Try it
Copy the code ↓- Data source
- Decision schema
- Model inference
- Structured result
2 Decision schema 3 typed questions
recoverychoiceretry_onceswitch_toolask_usertransientscorelowmediumhighneeds_usernoulprobability 0–1
3 Model inference typesafe/jev-1.13
Waiting for a run.
4 Structured result
Raw JSON
Run the demo to see the JSON answers, the highlighted pick and the final action.
FLATKEY_API_KEY and run.curl -sS https://router.flatkey.ai/api/alpha/decisions \
-H "Authorization: Bearer $FLATKEY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "typesafe/jev-1.13",
"state": "Failed step (attempt 1 of 2):\n tool: http_fetch\n args: GET https://api.vendor.example/v2/invoices?since=2026-10-01\n error: 401 Unauthorized — \"API token expired. Generate a new token in Settings → API.\"\n\nAlternative tools: browser_open (no saved login), read_cache (last sync 9 days ago)\nGoal: list October invoices for the monthly close report.\n\nTask: recovery (retry_once / switch_tool / ask_user), transient, needs_user.",
"questions": {
"recovery": {
"type": "choice",
"instructions": "An agent step just failed. Given the tool, its arguments, the error, the attempt count, and the alternative tools listed, what should the harness do next? Prefer retry_once only for errors that look transient; switch_tool when a listed alternative can reach the same goal; ask_user when the failure needs information, permission, or a decision only the user has.",
"criteria": {
"retry_once": "The error looks transient (timeout, rate limit, flaky network, lock contention) and the same call with the same arguments is likely to succeed",
"switch_tool": "The same call will keep failing, but one of the alternative tools listed can reach the same goal",
"ask_user": "The failure needs credentials, permission, a missing input, or a judgment call from the user, or every remaining option is risky"
}
},
"transient": {
"type": "score",
"instructions": "How likely is it that this exact error clears if the identical call is repeated, based only on the error text and context provided.",
"criteria": [
"low",
"medium",
"high"
]
},
"needs_user": {
"type": "noul",
"instructions": "The failure can only be resolved with something the user has to provide or approve—credentials, a missing value, a scope decision, or consent to a destructive fallback."
}
}
}'// Node.js 18+ (built-in fetch). Run: FLATKEY_API_KEY=... node jev.mjs
const body = {
"model": "typesafe/jev-1.13",
"state": "Failed step (attempt 1 of 2):\n tool: http_fetch\n args: GET https://api.vendor.example/v2/invoices?since=2026-10-01\n error: 401 Unauthorized — \"API token expired. Generate a new token in Settings → API.\"\n\nAlternative tools: browser_open (no saved login), read_cache (last sync 9 days ago)\nGoal: list October invoices for the monthly close report.\n\nTask: recovery (retry_once / switch_tool / ask_user), transient, needs_user.",
"questions": {
"recovery": {
"type": "choice",
"instructions": "An agent step just failed. Given the tool, its arguments, the error, the attempt count, and the alternative tools listed, what should the harness do next? Prefer retry_once only for errors that look transient; switch_tool when a listed alternative can reach the same goal; ask_user when the failure needs information, permission, or a decision only the user has.",
"criteria": {
"retry_once": "The error looks transient (timeout, rate limit, flaky network, lock contention) and the same call with the same arguments is likely to succeed",
"switch_tool": "The same call will keep failing, but one of the alternative tools listed can reach the same goal",
"ask_user": "The failure needs credentials, permission, a missing input, or a judgment call from the user, or every remaining option is risky"
}
},
"transient": {
"type": "score",
"instructions": "How likely is it that this exact error clears if the identical call is repeated, based only on the error text and context provided.",
"criteria": [
"low",
"medium",
"high"
]
},
"needs_user": {
"type": "noul",
"instructions": "The failure can only be resolved with something the user has to provide or approve—credentials, a missing value, a scope decision, or consent to a destructive fallback."
}
}
};
const res = await fetch("https://router.flatkey.ai/api/alpha/decisions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.FLATKEY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`Jev request failed: ${res.status} ${await res.text()}`);
const { answers, usage } = await res.json();
console.log(JSON.stringify(answers, null, 2), usage);# Python 3.8+ (pip install requests). Run: FLATKEY_API_KEY=... python jev.py
import json, os, requests
body = json.loads(r"""{
"model": "typesafe/jev-1.13",
"state": "Failed step (attempt 1 of 2):\n tool: http_fetch\n args: GET https://api.vendor.example/v2/invoices?since=2026-10-01\n error: 401 Unauthorized — \"API token expired. Generate a new token in Settings → API.\"\n\nAlternative tools: browser_open (no saved login), read_cache (last sync 9 days ago)\nGoal: list October invoices for the monthly close report.\n\nTask: recovery (retry_once / switch_tool / ask_user), transient, needs_user.",
"questions": {
"recovery": {
"type": "choice",
"instructions": "An agent step just failed. Given the tool, its arguments, the error, the attempt count, and the alternative tools listed, what should the harness do next? Prefer retry_once only for errors that look transient; switch_tool when a listed alternative can reach the same goal; ask_user when the failure needs information, permission, or a decision only the user has.",
"criteria": {
"retry_once": "The error looks transient (timeout, rate limit, flaky network, lock contention) and the same call with the same arguments is likely to succeed",
"switch_tool": "The same call will keep failing, but one of the alternative tools listed can reach the same goal",
"ask_user": "The failure needs credentials, permission, a missing input, or a judgment call from the user, or every remaining option is risky"
}
},
"transient": {
"type": "score",
"instructions": "How likely is it that this exact error clears if the identical call is repeated, based only on the error text and context provided.",
"criteria": [
"low",
"medium",
"high"
]
},
"needs_user": {
"type": "noul",
"instructions": "The failure can only be resolved with something the user has to provide or approve—credentials, a missing value, a scope decision, or consent to a destructive fallback."
}
}
}""")
res = requests.post(
"https://router.flatkey.ai/api/alpha/decisions",
headers={"Authorization": f"Bearer {os.environ['FLATKEY_API_KEY']}"},
json=body,
timeout=60,
)
res.raise_for_status()
data = res.json()
print(json.dumps(data["answers"], indent=2), data.get("usage"))
No Flatkey key yet? Get one for Jev 1.13 →
About this use case

Who / when
Audience
- agent harness builders whose tool calls fail on timeouts, rate limits, and bad inputs
- coding-agent teams tired of blind retry loops that burn budget
- teams that keep a big planner model for planning and want a small model for recovery calls
Triggers
- a shell command, API call, browser step, or patch returns an error mid-run
- some errors are transient and clear on one retry; others will fail the same way forever
- another tool in the option list could reach the same goal a different way
- missing credentials, ambiguous goals, or destructive fallbacks need the user, not another attempt
The workflow
- 01Failed stepTool, args, error, attemptsInput
- 02Recoveryretry / switch / askJev
- 03Transient?Score + needs_user flagJev
- 04Code gateRetry, reroute, or pauseYour code
Question shape
{
"recovery": {
"type": "choice",
"instructions": "An agent step just failed. Given the tool, its arguments, the error, the attempt count, and the alternative tools listed, what should the harness do next? Prefer retry_once only for errors that look transient; switch_tool when a listed alternative can reach the same goal; ask_user when the failure needs information, permission, or a decision only the user has.",
"criteria": {
"retry_once": "The error looks transient (timeout, rate limit, flaky network, lock contention) and the same call with the same arguments is likely to succeed",
"switch_tool": "The same call will keep failing, but one of the alternative tools listed can reach the same goal",
"ask_user": "The failure needs credentials, permission, a missing input, or a judgment call from the user, or every remaining option is risky"
}
},
"transient": {
"type": "score",
"instructions": "How likely is it that this exact error clears if the identical call is repeated, based only on the error text and context provided.",
"criteria": [
"low",
"medium",
"high"
]
},
"needs_user": {
"type": "noul",
"instructions": "The failure can only be resolved with something the user has to provide or approve—credentials, a missing value, a scope decision, or consent to a destructive fallback."
}
}Gate policy
≥ 0.90
Honor recovery: retry once if the attempt budget allows, switch to the named alternative tool, or pause and ask. Never retry when needs_user is true.
0.65–0.90
Retry only when transient is high and this is the first attempt; otherwise switch when an alternative is listed, else ask the user.
< 0.65
Stop and ask the user with the error attached (no blind loops), and log the probabilities to tune the recovery policy.
Failure modes
Pre-launch checks before you trust auto-routing:
- Retrying an expired-token 401 three times, burning budget and tripping the vendor's lockout;
- Asking the user about every timeout that would have cleared on one more attempt;
- Switching to a stale cache and quietly reporting nine-day-old numbers as current;
- Spending a full planner-model turn writing a post-mortem just to pick the next move;
- Letting Jev raise retry limits or grant permissions—recovery choice only; budgets and approvals stay in the harness;
FAQ
Why not just retry every failure a few times with backoff?
Backoff is right for transient errors, and your harness should keep it. But an expired token, a missing file, or a permission error fails the same way every time, so blind retries only waste budget and can trigger lockouts. Jev reads the error text and tells the harness which kind of failure it is looking at.
Why not ask the planner model what to do after a failure?
It adds a full chat turn of latency and cost to every failed step, and the answer is free text you still have to parse. Jev returns a calibrated choice over the three moves your harness already supports, plus a transient score and a needs_user flag you can threshold in code.
What does the Flatkey call look like?
POST https://router.flatkey.ai/api/alpha/decisions with Authorization: Bearer …, Content-Type: application/json, and a body of state, model (typesafe/jev-1.13), and questions (choice / score / noul). This is not an OpenAI-compatible /v1 chat endpoint.
Can I bring my own API key?
Yes. Try the free demo above without signing in. To run it live on your own text, sign in with Google and connect a Flatkey or OpenRouter key (a quick test call runs when you save it). Manage or delete it anytime under Dashboard → BYOK. Keys are stored encrypted on the server, used only for runs you trigger, and never sent back to the browser. Need a Flatkey key? Get one for Jev 1.13 on Flatkey.
Is this the official TypeSafe Jev product page?
No. jev-llm.com is an independent research and practice site. Verify pricing, models and terms at the original TypeSafe sources.
Sources
what to do after a failure: retry once, switch tools, or stop and ask
— @DarkFactorr View the post on X →
Wire this gate with your own key
Bring your own key through Flatkey / OpenRouter. Keep exact checks in code.