Jev · Score
ivy.node.jev-score · v0.1.0
ivyx✓
Asks TypeSafe Jev where a text or JSON state sits on an ordered scale of 2 to 10 described levels and returns a score from 0 to the top level with the nearest level, its description and the confidence. Use it to rate or grade urgency, severity, sentiment, quality or correctness. Levels go from low to high; the score is probability-weighted, so it can land between two levels. 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 | What to rate, in words; the model never sees anything else about it. |
| levelsrequired | array | Two to ten level descriptions, from the low end of the scale to the high end. |
| 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 |
|---|---|---|
| scorerequired | number | 0 to the top level number; can fall between levels. |
| levelrequired | integer | The nearest level number, 0 for the first. |
| level_textrequired | string | The nearest level's description. |
| is | object | For each level, as lowercase words joined by _, whether it is the nearest one; a branch reads is.<level>. |
| normalizedrequired | number | The score scaled to 0–1. |
| confidencerequired | number | 0–1, how peaked the probabilities are. |
| probabilities | object | Each level's probability, keyed by level number. |
| 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")
levels = [str(l) for l in (inp.get("levels") or []) if str(l).strip()]
if not 2 <= len(levels) <= 10:
raise ValueError("levels needs between 2 and 10 descriptions, lowest first.")
answer, model = ask({"type": "score", "criteria": levels})
score = float(answer.get("score"))
level = max(0, min(len(levels) - 1, int(round(score))))
out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out["score"] = score
out["level"] = level
out["level_text"] = levels[level]
out["is"] = {slug(t): i == level for i, t in enumerate(levels)}
out["normalized"] = round(score / (len(levels) - 1), 4)
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
- severe
Two exclamation marks land on the top of a three-level scale.
- calm
A calm message is level 0 on a five-level scale.
- row
A row as the state comes back beside its score, and the node's own fields win.
- one-level
A single level is refused before any call.
- empty-state
An empty state is refused before any call.