Jev · Choice
ivy.node.jev-choice · v0.1.0
ivyx✓
Asks TypeSafe Jev which of the given options fits a text or JSON state and returns the chosen option with its confidence and the probability of every option. Use it to pick a category, team, label, route or risk level. Options are a list of names or a map of name to description; add an "other" option when none may fit. Several hundred milliseconds, no text generated, and the answer is always one of the options. When the state is a JSON object its fields come back beside the answer, so a for-each over rows keeps each row.
Inputs
| Field | Type | Description |
|---|---|---|
| staterequired | Not declared | The text, or a JSON object or array, that Jev judges. |
| instructionsrequired | string | The question, in words; the model never sees anything else about it. |
| optionsrequired | Not declared | The options: a list of names, or a map of name to a description of when it applies. |
| jev_api_keyrequired | string | The TypeSafe API key; reference the stored secret jev-api-key, never the key itself. |
| base_url | string | The System One server. |
| model | string | The Jev model; pin a version such as jev-1.13.0 before tuning a threshold. |
Outputs
| Field | Type | Description |
|---|---|---|
| choicerequired | string | The option Jev chose. |
| is | object | For each option, as lowercase words joined by _, whether it is the one chosen; a branch reads is.<option>. |
| confidencerequired | number | 0–1, how peaked the probabilities are. |
| probabilitiesrequired | object | Each option's probability; they add up to 1. |
| model | string | The model version that answered. |
Source
python
inp = __ivy_ctx__["nodes"][__ivy_node_id__]["input"]
import json
import re
import requests
def slug(text):
"""The key a branch reads: "Needs action today" → "needs_action_today"."""
return re.sub(r"[^a-z0-9]+", "_", str(text).lower()).strip("_")
def ask(question):
state = inp.get("state")
if state is None or (isinstance(state, str) and not state.strip()) or state == {} or state == []:
raise ValueError("state is empty; give Jev the text or JSON to judge.")
instructions = str(inp.get("instructions") or "").strip()
if not instructions:
raise ValueError("instructions is empty; say what Jev should decide.")
key = inp.get("jev_api_key")
if not key:
raise ValueError("jev_api_key is missing; reference the stored secret jev-api-key.")
question["instructions"] = instructions
base = str(inp.get("base_url") or "https://api.typesafe.ai").rstrip("/")
response = requests.post(
base + "/v1/systemone",
headers={"Authorization": "Bearer " + str(key), "Content-Type": "application/json"},
json={"state": state, "model": inp.get("model") or "jev-latest", "questions": {"q": question}},
timeout=60,
)
if response.status_code in (401, 403):
raise PermissionError(f"Jev refused the API key (HTTP {response.status_code}).")
if response.status_code != 200:
raise RuntimeError(f"Jev answered HTTP {response.status_code}: {response.text[:300]}")
body = response.json()
answer = (body.get("answers") or {}).get("q")
if not isinstance(answer, dict):
raise RuntimeError("Jev's answer has no entry for the question.")
return answer, body.get("model")
options = inp.get("options")
if isinstance(options, list):
criteria = {str(o): None for o in options if str(o).strip()}
elif isinstance(options, dict):
criteria = {str(k): v for k, v in options.items()}
else:
criteria = {}
if len(criteria) < 2:
raise ValueError("options needs at least two choices.")
answer, model = ask({"type": "choice", "criteria": criteria})
choice = answer.get("choice")
if choice not in criteria:
raise RuntimeError(f"Jev chose {choice!r}, which is not one of the options.")
out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out["choice"] = choice
out["is"] = {slug(o): o == choice for o in criteria}
out["confidence"] = answer.get("confidence")
out["probabilities"] = answer.get("probabilities") or {}
out["model"] = model
# An object state's fields come back beside the answer, so a for-each over
# rows keeps each row (its date, its question) next to its score.
if isinstance(inp.get("state"), dict):
for _k, _v in inp["state"].items():
out.setdefault(_k, _v)Tests
Requires: python:3.9, requests
- billing
A charge complaint is routed to billing.
- described
Options given as a map with descriptions, the last one is the fallback.
- bad-key
A rejected key says so.
- one-option
A single option is refused before any call.