Skip to content

Patterns

The four documented patterns, each with its questions written and its thresholds in one module.

The thresholds these tools branch on live in strands_jev/questions.py, one file, so a change of policy is a constant under review. Defaults at this commit: confidence floor 0.6, noul threshold 0.5, complexity escalates above 1.0 or under a confidence of 0.5.

fan_out

Ask every question you might need in one request, then keep only the applicable answers.

Ports the speculative fan-out pattern (docs.typesafe.ai/patterns/fan-out). Questions are answered in parallel against the same state and cannot see each other, so a follow-up question ("how severe is the bug?") is asked up front alongside the question that decides whether it matters ("is this a bug report?"). A premise ties the follow-up to that deciding answer; answers whose premise does not hold are returned under skipped rather than dropped, so nothing is hidden. Adding questions to one request costs tokens but little latency.

parameter type default description
state str | dict | list required What Jev reads: text or a JSON object with meaningful field names.
questions dict | str required The same map of question specs as jev_ask (type noul, choice or score, with instructions and criteria). A JSON string is accepted.
premises dict | str | None None Which questions are speculative and when they apply. A map of question key to {"question": "<other key>", "equals": <choice or true/false>} or {"question": "<other key>", "at_least": <number>} for a noul probability or a score. Questions without a premise always apply. A JSON string is accepted.
context str None Optional text folded in next to the state.

Returns JSON with answers (the applicable ones, same shape as jev_ask), skipped (key to the premise that failed and the answer anyway), model, latency_ms, input_tokens; plus a one-line summary.

Ports patterns/fan-out

Measured 2026-09-29, jev-1.13.0: Jev 10/12, baseline 8/12, 12 calls, 5,506 input tokens, $0.000231, mean 159 ms. Details.

route

Classify a request's intent and decide who handles it: code, a specialist, or a person.

Ports intent routing (docs.typesafe.ai/patterns/intent-routing) with confidence-gated routing folded in (docs.typesafe.ai/patterns/confidence-routing). One request carries a Choice over your intents plus none_of_these and a 3-level complexity Score. The decision is gated twice: the intent's confidence must clear min_confidence (or the intent's own entry in thresholds, for the risky ones), and for the intents named in complex_intents a complexity score above 1 or a complexity confidence under 0.5 escalates to a person. The pattern applies that second gate to one intent (complaints), not to lookups; measured on 2026-09-29, gating every intent sent two clear lookups to a person because a 3-level score spread its probability. The thresholds are the pattern's own; tune them on your data.

parameter type default description
message str | dict required The request, as text or a JSON object.
intents dict | list[str] | str required Intent name to a one-sentence description of when it applies. A list of names works, read by name alone. A JSON string is accepted.
handlers dict | str | None None Intent name to the handler label your code dispatches on (for example "code", "product_llm", "human"). Missing intents default to their own name; anything undecided or escalated routes to "human".
min_confidence float 0.6 Confidence floor for acting on the intent, 0..1.
thresholds dict | str | None None Per-intent floors that override min_confidence for riskier intents, for example {"approve_transfer": 0.85}. Values 0..1.
assess_complexity bool True Also score complexity, 3 levels from "a lookup answers it" to "it needs a person". Set false when only the intent matters.
complex_intents list[str] | str | None None The intents whose handler depends on complexity, for example ["complaint"]. Omitted: every intent is gated. Ignored when complexity is not assessed.
context str None Optional text folded in next to the message.

Returns JSON with intent, confidence, decided, handler, escalate (bool), reason, probabilities, runner_up, complexity (score, confidence, legend) when assessed, threshold_used; plus a one-line summary.

Ports patterns/intent-routing, patterns/confidence-routing

Measured 2026-09-29, jev-1.13.0: Jev 14/14, baseline 11/14, 14 calls, 6,886 input tokens, $0.000289, mean 179 ms. Details.

composite_score

Score one thing, or rank many, on several dimensions with weights you control in code.

Ports composite scoring (docs.typesafe.ai/patterns/composite-scoring). Each dimension is an atomic Score question; every dimension is asked in one request per item. Scores are normalised to 0..1 by dividing by the top level index, then combined under each weight profile in code. The raw normalised scores are returned so you can reweight without asking again. The default rubric has five generic levels; describe your own levels when the dimension has concrete stages (the docs ask that levels describe situations).

parameter type default description
dimensions dict | str required Dimension name to the rating instruction ("How deep is the Python experience?"), or to {"instructions": ..., "levels": [...]} for a dimension with its own ordered levels (2 to 10). A JSON string is accepted.
state str | dict | list | None None The one thing to score. Give this or items.
items list | str | None None Several things to score and rank, one request each (at most 500).
weights dict | str | None None One profile {"python": 0.4, "leadership": 0.1, ...} or several {"senior_ic": {...}, "manager": {...}}. Non-negative, normalised to sum to 1. Omitted: equal weights.
levels list[str] | str | None None Shared ordered level descriptions for dimensions that give none.
context str None Optional text folded in next to each item, such as the job description.

Returns JSON with dimensions (name to instruction), profiles (normalised weights), results (per item: scores 0..1 per dimension with raw score, confidence and legend; composite per profile), ranking (per profile, best first, when items was given); plus a one-line summary.

Ports patterns/composite-scoring

Measured 2026-09-29, jev-1.13.0: Jev 27/30, baseline 20/30, 6 calls, 3,313 input tokens, $0.000139, mean 213 ms. Details.

function_call

Turn a natural-language request into a function name and closed-set arguments, with confidence.

Ports the function-calling cookbook (docs.typesafe.ai/cookbooks/function_calling). One request carries a Choice over the functions (plus a no-match option), and for every function every argument: a Choice for a single value from a fixed list, a Noul per member for a set argument, a Noul for a flag, and an optional "stated" Noul that decides whether the argument was mentioned at all (when not, it is left out so the function's default applies). Only the chosen function's answers are read. The call's confidence is the least certain judgement behind it. Free text, numbers and dates are not filled: keep them as defaults or ask the user. Write each question about the idea, not the parameter name.

parameter type default description
request str required What the user said.
functions dict | str required Function name to {"description": "...", "arguments": {arg: {"question": "...", "options": {value: meaning, ...}, "kind": "choice" \| "set" \| "flag", "stated": "Does the user say anything about ...?"}}}. kind defaults to choice when options are given, flag otherwise; stated is optional; a set question may hold {} where the member name goes. A bare string is a description with no arguments. A JSON string is accepted.
min_confidence float 0.6 Floor on the call's confidence to report decided, 0..1.
context str None Optional text folded in next to the request.

Returns JSON with function (or none_of_these), arguments (value per filled argument), confidence (the minimum), function_confidence, decided, per_argument (each judgement with its probability or confidence, and whether it was stated), probabilities over functions; plus a one-line summary.

Ports cookbooks/function_calling

Measured 2026-09-29, jev-1.13.0: Jev 14/16, baseline 10/16, 16 calls, 29,830 input tokens, $0.001253, mean 172 ms. Details.

Edit page