Structured decisions
UsegenerateStructuredOutput() from @bastani/atomic, or the structured_output tool, when an integration needs one schema-validated semantic decision. Both use the same model contract. Neither starts a child agent, executes the caller’s other tools, or authorizes an action. Neither reads routerModel or changes the selected chat model.
Automatic workflow-stage and subagent model: "auto" selection uses routerModel separately; it does not change calls to generateStructuredOutput(). See Select the router.
Select the inference model
Pass an optional exactprovider/model string, not a model object and not auto:
modelis the primary. It may be a chat language model or a classifier registered in the current model registry.typesafe/jev-latestis one example classifier, not a separate request type.fallbackModelsis an ordered list of the same kind of exact IDs.- Omit
modelto use the current stage or chat model as the primary. - After the primary and every explicit fallback, Atomic tries the current chat model if it has not already been tried.
modelAttempts, and still tries the remaining candidates, including the current chat model, so a mistyped model or fallback does not fail the call. The call fails with the first ID’s error only when no candidate resolves. A classifier is never an execution auto candidate. A catalog entry does not prove that the provider can classify, that credentials work, or that quota remains. Setting routerModel does not change this selection.
A classifier can answer a finite Choice. Literal unions, enums, booleans, and flat objects whose required fields all use those types are Choice-compatible. Free-form text, unconstrained numbers, arrays, optional fields, and nested objects are not. Atomic compiles compatible schemas into generic choice questions and skips an incompatible classifier, recording the skip. A request whose entire chain is incompatible fails without inventing a decoder.
Pass the session modelRegistry. Classifier credentials come from that registry’s normal provider login, such as /login typesafe or TYPESAFE_API_KEY for TypeSafe Jev. Do not copy a resolved key into state.
value is the schema-validated decision, not the request arguments. model names the candidate that produced it. modelAttempts records skips and failed candidates when a chain was used. This decision API does not expose classifier billing usage: its classifier-produced usage is not a classifier bill. The lower-level classifier operation may report usage and cost separately. Chat usage is reported when a chat candidate supplies the accepted result. A valid shape is not proof that the judgment is correct. Validate current policy again before any later action.
The structured_output tool takes the same decision inputs from the calling model: required instructions and nonempty named state, plus optional model and fallbackModels. The registered schema is fixed by createStructuredOutputTool({ schema }). The tool resolves those IDs through the session registry and returns the inferred value. Omitting model uses the current stage or session chat model. The calling model cannot set a deadline; the tool’s own timeoutMs option does. See Structured output final results.
Select the router
For workflow stages and subagents withmodel: "auto", routerModel selects the decision provider: an explicit exact registered chat or classifier ID uses that model, while an unset or auto value uses the current chat model. Saved classifier credentials do not change this selection. An invalid explicit router selection fails instead of falling back. Set it through /settings; extensions can read the current value with ctx.getRouterModel().
Chat routing gets an initial attempt plus up to three corrective retries for malformed or schema-invalid output, all within one decision deadline. A failed explicit classifier routing attempt switches to the current chat model immediately when one exists, including missing credentials, an unsupported classify operation, a provider size or context rejection, and a refusal. Cancellation does not fall back. The result includes fallback: { from, to, reason } when that hop is used. Transient provider retries follow the selected provider’s operation and the request’s retry settings. General generateStructuredOutput() advances its own fallbackModels chain; it does not read routerModel.
For workflow-stage and subagent model: "auto", a complete routing-inference failure runs the stage or child on the current chat model with a recorded warning instead of failing, provided that model is available and satisfies every routing constraint.
Prepare a decision
Instructions describe the judgment. Namedstate fields contain the actual task, relevant conversation, explicit constraints, and reference text. Paths and URLs may identify a source, but do not replace its content. Exclude secrets from state and instructions.
A general structured-output request supplies instructions, state, and schema. Atomic derives choice questions from a compatible schema and skips a classifier for other schemas. Keep fixed numeric limits in code. Include a no-match outcome in the schema when abstention is valid.
Automatic routing builds its own finite Choice questions from eligible execution models. Call generateStructuredOutput() directly for other decisions; it derives questions from your result schema instead of reading routerModel.
Provider behavior and limits
Chat candidates receive one internal result tool whose parameters are the registered schema. Atomic uses provider-aware serialization, requests strict sampling where supported, and validates the returned arguments without coercing values or removing extra fields. UseadditionalProperties: false for closed objects. A prose-only response, extra tool call, truncated response, or invalid result fails that candidate and advances the chain. The public structured_output tool is separate: its parameters are instructions, state, and optional model selectors, and its result is the inferred value.
Use Type.Optional(...) for result fields that may be omitted. When a strict provider represents an omitted optional object property as null, Atomic removes that placeholder if the property’s schema rejects null, including declared properties inside nested objects and array items. If null is a meaningful result, explicitly allow it in the property schema; Atomic preserves those null values. Required properties and undeclared fields still follow the original schema.
Chat decisions use HTTP/SSE rather than WebSocket transport fallback and disable configured Anthropic server-side fallbacks for this request only. The chat decision layer retries transient failures according to the request’s retry settings. Classifier calls use the registered provider’s classify operation and forward the retry limit and cancellation signal; provider implementations own their transport retries.
A registered classifier receives shared state and choice questions through the generic classify operation. TypeSafe Jev is one such classifier. Router classification is one classify request. A provider that rejects the request size or context fails that candidate; routing then uses the current chat model when one exists.
The structured-decision path never trims supplied state. A general structured-output call skips an incompatible classifier candidate and continues with the next fallback. A provider size rejection advances the same way without repeating the rejected request. Supply concise context or select a chat model with enough capacity when needed.
Automatic subagent and workflow-stage model selection has a chat model read the task and sends a classifier only the resulting answers and candidate models; see automatic model selection.
Classifier response bodies are limited by the provider operation. Atomic validates that every question receives a known Choice option. Lower-level classify results may report usage and cost when the provider supplies them; this structured-decision API does not expose them as classifier billing usage. Reported model, probabilities, and confidence are advisory and never reject an otherwise valid decision.
Cancellation and failures
One wall-clock deadline covers the whole call: every repair attempt, transport retry, and model-candidate fallback together, not each generation alone.timeoutMs sets it as a positive integer number of milliseconds. Without it, the structured_output tool uses the session’s httpIdleTimeoutMs setting and every other call uses that setting’s default of 10 minutes. A disabled idle timeout (0 or "disabled") leaves only the largest timer delay, about 24.8 days. Raise the deadline for slow, reasoning-heavy models or large state.
When the deadline passes, Atomic stops the in-flight generation, which also ends a provider that ignores its signal, and rejects the call with Structured output decision exceeded its <n>ms deadline; no decision was accepted. That failure is final: it does not start another repair or advance to a fallback model. Unlike cancellation, it names the deadline. The message ends with how each attempt finished and how long it took, such as Attempts: 1) stopReason=stop 25m02s; 2) still generating 4m58s.. The error for exhausted repairs ends the same way, so a slow wedge reads differently from several failed generations. Provider transport, credential-preparation and enclosing tool-request limits remain independent of this deadline.
Pass an AbortSignal to cancel sooner, for example signal: AbortSignal.timeout(milliseconds). Cancellation rejects the whole call immediately, even if a provider ignores its signal. Output has no fixed token cap: a chat decision may use the selected model’s full output limit. Pass a positive integer maxTokens only when you want a smaller bound.
No result is returned for missing state, invalid configuration, unrepaired malformed output or an unrecovered provider failure. Keep action admission after the awaited result and check cancellation again at that boundary. Neither API runs recursive agents or provider probes.
Provider errors report a static reason without raw response bodies or credentials. A failed classifier request, including a refusal or an unrecognized or missing Choice answer, advances to the next configured model or current chat model. Chat provider errors also advance, including explicit refusals. Ordinary text without a valid result gets up to three repairs before advancing; Atomic does not inspect the wording to guess whether it is a refusal. Cancellation stops the chain.