Skip to main content

Decisions

jevlin decide asks a decision model typed questions about a state, where the router offers it. A router without decisions answers decisions_not_supported. The agents' skill does not teach it yet.

jevlin decide --stdin takes one JSON object and answers with one envelope carrying the same header as a search, with command set to decide. It sends POST /v1/decisions to the configured router with the same key, deadline, redirect policy and user agent as a search, and nothing about it is kept on this machine.

A decision is billed, and never sent twice. result.usage.cost_micros says what it cost, and it is one request the client never repeats.

The request​

Version 1:

fieldvalue
version1, required.
modelRequired: vendor/model, as jevlin decide --models lists it.
stateRequired and not null: what the questions are about, a string, object or array.
questionsRequired: a non-empty object of question name to question, each an object, such as {"type": "noul", "instructions": "…"}.
optionsAn object of the vendor's options.
sources1 to 5 entries, each exactly {"source_id": "s_…"}, a page's source_id from a search's result.merged.
max_chars1000 to 50000.

A malformed value, and any other field, answers fix_input before the router is called, with a code naming the field: unsupported_version, unknown_field, missing_model, invalid_model, missing_state, missing_questions, invalid_questions, invalid_options, invalid_sources or invalid_max_chars. A request over 1 MiB on stdin is input_too_large. Nothing else is checked here: the router judges the state, each question and the options, and the client sends them byte for byte, spacing and key order included. A router that does not take sources and max_chars yet refuses a request carrying them as malformed_json.

The answer​

On success, result has:

fieldmeaning
request_idThe router's id for this decision, also at the envelope's top level.
model, model_resolvedThe model as asked for, and what the vendor echoed, when it did.
answersOne entry per question name, the router's object for it: type is noul (with noul), choice (choice, probabilities), score (score, probabilities, legend) or refusal, and confidence when the vendor reports one. Only the whitespace between tokens is removed.
citationsThe sources the vendor reports for the whole request: url, title, excerpts. Empty when none.
sourcesThe pages the router read for a request carrying sources: source_id, url, title, chars, cached, cost_micros.
usageinput_tokens, output_tokens, grounded_calls, cost_micros, pages_cost_micros, cost_source (modeled, reported or free), byok and latency_ms.

A refusal is an answer, not a failure: ok stays true and the other answers stand. A 2xx with no answers is invalid_router_response, exit 4.

Listing the models​

jevlin decide --models sends GET /v1/decisions/models with the same key and reads nothing from stdin. result.models is the router's list, each with id (the value model takes), vendor, vendor_model, cost in millionths of a dollar (per_request_micros, per_prompt_ktok_micros, per_search_call_micros, a zero left out), free (requests_per_day, absent with no free tier), grounded and available (whether this account can call it). Listing spends nothing. --stdin and --models together are a usage error.

When it fails​

router answerexitcoderetryableaction
400 unknown_model3unknown_modelfalsefix_input: jevlin decide --models lists them
400 invalid_request, malformed_json3the router'sfalsefix_input
400 upstream_rejected3upstream_rejectedfalsefix_input: error.message is the vendor's
413 payload_too_large3payload_too_largefalsefix_input
403 decisions_unavailable3decisions_unavailablefalseconnect: this account cannot call this model, and error.message says why
404 or 4053decisions_not_supportedfalsereport: this router has no decisions
503 decisions_disabled3decisions_disabledfalsereport: this router has decisions switched off
503 model_unavailable4model_unavailablefalsereport: the platform holds no working key for this model
503 upstream_failed4upstream_failedthe body's retryableretry when true, with retry_after_ms if the router sent one; report otherwise
402 search_credit_only3search_credit_onlyfalsereport: the credit left this week is reserved for search; decisions resume at the weekly reset or after a top-up
any other statusas for a search

Exit codes are as for a search: 0 for a valid answer, 1 for transport, timeout or cancellation, 2 for usage, 3 for a 4xx, for no usable key, or for a router that has decisions switched off; 4 for any other 5xx or an answer the client could not use.

See also​