Skip to content

Reasoning function format

A reasoning function is a definition of the type reasoning. Its document names a model, the input and output contracts, the settings and a prompt template. A run renders the prompt from its input, calls the model and records the model's answer. Build your first playbook walks through one with an agent.

A function document

The source is Markdown: YAML front matter, then a Liquid prompt template. This example reviews a campaign brief. Replace the model reference with a concrete id from list_models, or with one your workspace administrator confirms.

markdown
---
description: Reviews a campaign brief against the team's criteria
model: anthropic/claude-sonnet-4-5
config:
  max_output_tokens: 800
input:
  schema:
    type: object
    properties:
      brief: { type: string }
      criteria: { type: string }
    required: [brief, criteria]
---

{% system %}Review the brief using the supplied criteria. Identify missing evidence. Do not invent facts.{% endsystem %}
Brief: {{ input.brief }}
Criteria: {{ input.criteria }}

To save it, call create_definition with type: "reasoning", a function name and the document as source. To run it, call run_definition with the same type and name, and with brief and criteria in the input object. Both operations also need the playbook id, unless the MCP connection is scoped to that playbook.

A function document contains instructions, never model credentials. Each change to the document creates a version. A run uses the latest active version and records it as definition_version; a run cannot select an older version.

Fields

FieldRequiredValue
descriptionNoText of 1 to 1,000 characters. list_definitions, get_definition and the overview show it
modelYesA model reference in provider/model form, such as anthropic/claude-sonnet-4-5
config.max_output_tokensNoA whole number from 1 to 64,000; 1,024 when left out. The most tokens the answer may use
config.temperatureNoA finite number: the sampling temperature. Each provider accepts its own range
config.top_pNoA finite number: nucleus sampling
config.seedNoA whole number of 0 or more, for providers that accept a seed
config.stop_sequencesNoA list of strings. The answer stops where the model writes one
config.reasoningNoThe reasoning effort, for models that reason: none, minimal, low, medium, high or xhigh
input.schemaNoA JSON Schema whose root is "type": "object". Without it, any JSON object is accepted
input.defaultNoDefaults for top-level input fields, as a JSON object. The supplied input's fields override them before validation
output.formatNotext, the default, or json
output.schemaWith jsonA JSON Schema the answer must match; see Answers that are JSON. Not allowed with text
output.shapeNoThe name of an output shape, series, categories, table or text: the answer is JSON of that shape. Not allowed beside output.schema or with text
provider_optionsNoOptions for one provider, under its namespace; see Provider options
toolsNoThe tools a run may call, each server/tool or server/*; see Tools

Any other key, at any level, is rejected.

How a document is checked

create_definition and update_definition check the whole document, and every run checks it again. A document with problems is rejected with every problem listed under /source:

  • Each problem names its line and, where there is one, a JSON pointer into the front matter, such as Line 4, /config/temperature: Expected number.
  • A problem found twice is reported once. A rejection lists at most 20 problems in line order, then one line that counts the rest, such as Line 23: 5881 more issues are not shown.
  • The front matter is YAML 1.2 with the core schema, so yes and 2026-10-01 stay strings. Anchors, aliases and tags are rejected. A key may appear only once in a mapping, and numbers must be finite. Nesting is limited to 72 levels.
  • input.default must match the input schema for the fields it names. Required fields may be left for the input to supply.
  • A setting in config is checked only against the type and range in the table above. Whether the provider accepts the value becomes clear when a run calls it.
  • Saving calls no model. Whether the provider is configured, and whether it offers the model, becomes clear only when the function runs; see How a run ends.

How a run works

A run takes these steps:

  1. It applies input.default: each top-level field the supplied input leaves out takes its default. It checks the result against input.schema. The input may be at most 256 KiB as JSON and 512 levels deep. A run without input gets {}.
  2. It renders the template. The system block becomes the system instructions, and everything else becomes one user message.
  3. It calls the model. A function with tools lets the model call them before it answers; see Tools.
  4. It checks a JSON answer against output.schema, or against the shape output.shape names.
  5. It records the output and a record of the call.

An external agent can pass evidence it collected through its own connections as input. The function itself cannot reach that agent's tools.

Supply a run_id to read a run later or to retry it. The same id and input return a recorded success or invalid_input without calling the model again. After unavailable, conflict or a failure, they run the definition again. A run that called tools is the exception; see When a tool-calling run cannot finish. Retrying under a run id gives every case. The HTTP reference gives the other rules of the run operations.

The template

The template is Liquid. It reads three variables and nothing else:

VariableValue
inputThe run's input, a JSON object, after input.default is applied and the result checked
todayThe date when the run starts, YYYY-MM-DD, in UTC
nowThe time when the run starts, in ISO 8601, in UTC

Rules for reading values:

  • The template may also read names it creates itself with assign, for, increment or cycle. Any other name is rejected when the document is saved.
  • When the input schema lists its properties and sets additionalProperties: false, input.<field> must be one of them.
  • A field the input does not have stops the run with invalid_input, naming the field and the line.
  • Two places may read a missing field without stopping the run: a condition of if, elsif or unless, and the default filter. So a template can test a field that may be absent: {% if input.vip %}…{% endif %}, {{ input.nickname | default: "friend" }}.
  • Only the input's own fields can be read: input.constructor is a missing field.
  • A list renders as its items with no separators, and an object renders as [object Object]. Use {{ input.account | json }} to render JSON.

The system block

liquid
{% system %}You review expenses against the policy of {{ input.company }}.{% endsystem %}
Review this expense: {{ input.expense | json }}
  • The text between {% system %} and {% endsystem %} is sent as the system instructions. Everything outside it is the message, sent as one user message.
  • A template has at most one system block. The block must sit at the top level, outside every other tag, and its tags take no arguments.
  • The template must render some text outside the block.
  • An input that contains {% system %} or {% endsystem %} renders as those literal characters. It never opens or closes the instructions.
  • The template renders in document order, so a value assigned in the block is available after it.

Tags

Available: assign, if with elsif and else, unless, case with when, for with break and continue, cycle, increment, decrement, echo, liquid, raw, comment, # and tablerow.

Not available: include, render, layout and block, since a function is a single document. capture is not available either; use assign with append instead.

Filters

Liquid's standard data and string filters are available: abs, append, array_to_sentence_string, at_least, at_most, base64_decode, base64_encode, capitalize, ceil, compact, concat, default, divided_by, downcase, escape, escape_once, find, find_index, first, floor, group_by, has, join, json, last, lstrip, map, minus, modulo, newline_to_br, normalize_whitespace, number_of_words, plus, pop, prepend, push, raw, reject, remove, remove_first, remove_last, replace, replace_first, replace_last, reverse, round, rstrip, shift, size, slice, slugify, sort, sort_natural, split, squish, strip, strip_newlines, sum, times, to_integer, truncate, truncatewords, uniq, unshift, upcase, where and xml_escape.

The runtime adds three filters:

FilterWhat it doesExample
moneyFormats a number, or a string holding a decimal number, as US dollars with thousands separators: no cents for a whole amount, two decimals otherwise. Any other value stops the render{{ 364028 | money }} is $364,028; 1234.5 is $1,234.50
clipCuts text to a number of characters, 400 by default, and appends an ellipsis (…) when it cuts. Characters are counted as Unicode code points{{ input.notes | clip: 200 }}
wordsCounts the words in a string, where a word is a run of characters between whitespace{% assign n = input.notes | words %}

Not available:

  • The date filters. They read the server's clock and time zone, so the same function would render differently on another server. Use today and now instead.
  • sample, which is random.
  • The digest filters, strip_html and the URL encoders.
  • The filters that evaluate an expression given as text, such as where_exp.
  • inspect and jsonify, which duplicate json.

Limits

LimitValueWhen it is reached
Length of the template65,536 charactersRefused when saved
Names in tags and outputs1,000Refused when saved
Time to render200 msThe run ends as invalid_input
Memory that filters and ranges may charge5,000,000 characters or itemsThe run ends as invalid_input
Rendered instructions, and rendered message200,000 characters eachThe run ends as invalid_input

Names are counted in the text inside {{ }} and {% %}: every variable, property, filter and keyword. A template that nests tags or parentheses more deeply than the engine can parse (about 2,000 levels of tags) is refused when saved. A render limit ends the run as invalid_input because the input is what makes the render grow.

Answers that are JSON

With output.format: json, the answer must match output.schema. With output.shape, it must match the shape's schema and the rules the shape adds, such as the order of a series' points; Output shapes gives them, and the shape's schema is sent to the provider as output.schema would be. The runtime validates the answer against the schema as written, whatever the provider enforced. A schema is a JSON Schema document in draft 2020-12. It is read as draft-07 when $schema says so, or when the document uses definitions without $defs.

These rules apply to output.schema and input.schema alike, and a schema that breaks one is refused when saved:

  • At most 65,536 bytes as JSON, at most 64 nested levels of objects and lists, and at most 1,000 values in one enum.
  • No pattern or patternProperties, because a hostile regular expression can stall validation.
  • No if, then, else, contains, minContains, maxContains, dependentRequired, dependentSchemas, dependencies, unevaluatedItems, unevaluatedProperties or additionalItems.
  • No $anchor, $dynamicRef, $dynamicAnchor, $recursiveRef or $recursiveAnchor.
  • $ref may point only to #/$defs/<name> or #/definitions/<name>. not may only be {}. enum and const may contain only strings, numbers, booleans and null. additionalProperties may not be a schema when properties is present.
  • No definition that loops through $ref, allOf, anyOf or oneOf with no property or item in between, such as "a": {"$ref": "#/$defs/a"}. A definition may refer to itself through properties or items, as a tree does.

An answer may nest at most 128 levels deep. When an input or an answer does not match, the rejection reports each distinct issue once. It lists at most 20, then one line that counts the rest.

Some providers reject or do not enforce parts of a schema. Such a schema is still saved, and the definition carries warnings that name the line and the providers concerned. The warnings also name what is sent to the provider but not checked by the runtime, such as format and keywords it does not know. A definition shows at most 100 warnings. create_definition, get_definition, list_definitions and update_definition show them. For example: Line 8, /output/schema/properties/total/minimum: minimum is not enforced while Anthropic models write the answer; an answer outside it fails as output_invalid (anthropic, bedrock, bedrock-anthropic, vertex-anthropic). To write a schema every provider accepts:

  • Make the root "type": "object". OpenAI and Azure strict structured outputs accept only an object, and so do providers that return JSON through a tool call.
  • Give every object "additionalProperties": false and list every property in required. Write an optional property as nullable, such as "type": ["string", "null"]. OpenAI and Azure reject anything else.
  • Expect Anthropic models not to receive numeric, length and count bounds (minimum, maxLength, minItems, uniqueItems and the like). The runtime still checks them, so an answer outside them fails. The same holds for oneOf, which Anthropic models receive as anyOf.
  • Use only the formats Anthropic models accept: date-time, time, date, duration, email, hostname, uri, ipv4, ipv6 and uuid.
  • Keep schemas small: Google notes that very large or deeply nested schemas may be rejected.

Tools

tools lists the tools a run may call, from the tool servers the operator configured for the playbook and the connections people added to its org. Write each as server/tool, or server/* for every tool of a server that the operator allows; a connection is named the same way, by its name:

yaml
tools: [graph/search, graph/query, notes/*]

server/* gives every tool the server lists that the server's allowed setting names. When the operator left allowed out, it gives every tool the server lists. A tool written in another form, or listed twice, is refused when the document is saved.

Find the tool names

Do not guess tool names. Ask the runtime:

  1. Call search (MCP, or GET /v1/orgs/{org}/playbooks/{playbook}/tool-servers/search). It returns the servers set up for the playbook and the tools the operator allows on each. It asks each server for its tools, as a run does. When the servers offer many tools, pass a few words describing what the function should do as terms. See Tool servers.
  2. Call introspect to read one tool in full, with the schema of its arguments.
  3. Call the tool with execute to see what it returns before you name it. execute calls the tool once, as a run would, and returns what the run's model would see. The call is recorded in the playbook's history. dry_run reports beforehand what the call would check. See Calling a tool by hand.

Before the model is called

A run checks its tools after it confirms that its model is offered, and before it calls the model. A run whose model is not offered contacts no tool server. A tool that cannot be used ends the run as unavailable, and the model is never called:

KindbecauseWhen
tool_not_offeredtool_server_not_configuredThe server is not configured for the playbook
tool_not_offeredtool_not_allowedThe tool is outside the server's allowed
tool_not_offeredtool_not_listedThe server does not list the tool
tool_not_offeredconnection_pendingThe server is a connection nobody has approved yet
tool_not_offeredconnection_brokenThe server is a connection whose credential cannot be read; remove it and add it again
tool_not_offeredconnection_not_allowedThe server is a connection a rule of the operator no longer allows
tool_server_failedunreachableThe server cannot be reached, or does not respond in time
tool_server_failedfailingThe server fails, or refuses to list its tools
tool_server_failedrate_limitedThe server asks the run to slow down
tool_server_failedkey_refusedThe server did not accept the key the runtime gives it; check that key, do not retry

What the model sees

  • Each tool reaches the model under a unique name made from server__tool, for an MCP server and an HTTP API alike. Characters other than letters, digits and underscores become underscores. A name longer than 64 characters, or one that clashes with another after that change, gets an 8-character hash. A numeric suffix resolves any clash that remains.
  • The tool's description is cut to 4 KiB. Its input schema is sent unchanged.
  • Parts of a tool's input schema that the provider may refuse or not enforce are added to the run's warnings, such as graph__search inputSchema#/properties/query/maxLength. Tools are not sent as strict structured outputs, so the rules for JSON output schemas do not apply to them.
  • The model keeps the function's output format. It may call several tools in one step, and call tools over several steps, before it answers.
  • Each call carries the run id in the request's metadata, under auto.on/run_id.
  • A tool's text content reaches the model as text. Structured content reaches it only when there is no text. Other content reaches it as a one-line placeholder.
  • A result the server marks isError, such as a policy denial, reaches the model as a tool error it may recover from.
  • A server's own instructions never reach the model. Error text is scrubbed of the server's secrets and of minted tokens.

Limits on calls

The runtime checks each call before it sends it:

  • A run makes at most 25 calls; any further call is refused.
  • A call that sends more than 16 KiB of arguments is refused.
  • A third call of the same tool with the same arguments is refused, and the model is pointed to the result of the earlier call.

A refused call is not sent and not recorded, and the model is told why.

The model reads each tool result in full. A result is cut, with a note of how much was left out, only when it would not fit in the room left for the step that called it:

  • The room starts as the smaller of two figures: the model's context window, as the server's model catalog gives it, and what is left of the run's budget. The step's input and output are taken off it, and the step's calls share the rest equally.
  • Room is counted in the provider's tokens for that step, and converted to bytes at the step's ratio of bytes sent to input tokens counted.
  • A cut result stays valid JSON, with a note asking for fewer rows, fields or depth.
  • When the catalog does not know the window, or the provider reports no token counts, each result is read in full.

A run's model calls use at most the input tokens the operator sets with REASONING_MAX_INPUT_TOKENS, 2,000,000 by default. Before each step, the runtime estimates that step's input from the step before. When the remaining budget would not cover another step after it, that step is the last, and it is made without tools.

Once the run has used all its calls, or the budget would run out, the model answers from what it has, without tools. That last step gives the model the calls so far as text, so every provider accepts it. The tool results sit in a block fenced by a random marker and labelled as the results of the tools the model called. The label tells the model they are data to answer from, not instructions and not the user's words.

A run that calls tools costs more. Every step resends the conversation so far, so a run that uses its whole budget sends on the order of a million tokens. Ask a tool for one page of its data when the whole would be more than the model should read.

Limits on time and failures

BoundValueWhen it is reached
One call30 secondsA tool error that counts as a server failure
A 429 from a tool serverWaited out when Retry-After asks for at most 10 secondsOtherwise a server failure
Server failures in one run5The run ends with because: "server_failed"
One model call60 seconds plus 25 ms for every token of max_output_tokensThe run ends with because: "model_unavailable"
The whole run10 minutes, or one model call's limit when that is longerThe run ends with because: "run_bound"
A tool call in the last step, made without toolsNone allowedThe run ends with because: "no_answer"

Once the run has called a tool, each of these ends it as tools_unfinished or effect_unknown; see When a tool-calling run cannot finish. Before its first call, the run ends as plain unavailable.

A provider may signal that the request is too long: HTTP 413, or the error code or type context_length_exceeded or request_too_large. The run then ends as conflict with the kind unworkable. Its detail names the signal, how many bytes the tools returned, and the input tokens the provider counted for the last step.

The run's history

Each call adds two events to the run's history, appended as they happen:

  1. tool_call_started, recorded before the call is sent. It has the call's number, the id the model gave it, the server, the tool and the size of its arguments. It has read_only: true when the server marks the tool read-only, and the SHA-256 digest of the arguments when they are kept.
  2. Then one of:
    • tool_call_answered, when the tool answered: is_error, the size of the result and its digest when it is kept, shown_bytes when the model read less than all of it, the duration and the JSON-RPC id.
    • tool_call_failed, when it did not: because (arguments_refused, server_failure, timed_out, too_large for a result larger than the transport reads, or cancelled), the failure message, the duration and the JSON-RPC id.

Either event carries the server's own request id when the server's request_id setting says where to find it. The arguments and the result are kept in full, scrubbed of secrets, unless the operator sets record_content: false for the server. A run's history, from list_playbook_events given its run_id, shows each one when it is at most 2 KiB, and its size otherwise. get_event reads them in full.

When a tool-calling run cannot finish

A tool may change something outside the playbook. So a run that called tools and then could not finish ends in one of two ways, depending on what it called:

It calledEndingStatusWhat may follow
Only tools their servers mark read-only (readOnlyHint)unavailable, kind tools_unfinished503A new run, or a workflow's retry on status 503, may do the work again
Any tool its server does not mark read-onlyconflict, kind effect_unknown409No retry on status 503 matches it, since that tool may already have changed an external system

Both endings name, in words, the tools the run called. They keep the because field of the bound or failure that stopped the run.

The same run id never runs that work again. Retrying under a run id gives the rule for every run; for a tool-calling run:

  • run_definition with the run_id of a tool-calling run that did not succeed returns conflict with the kind tools_called. When the run has ended and every tool it called only reads, the rejection also has because: "only_read", and its words say nothing was changed.
  • A run of a function with tools that is still started also cannot restart under its id, even before its first recorded call, since it may still be in progress. It also returns tools_called.

A caller that disconnects before the run returns interrupts the run, which is recorded as failed. Tool calls in flight are cancelled and may already have had external effects.

Inspect its history and any external effects before deliberately starting a new run with a new id. Retrying a successful run returns its recorded result without calling tools again.

Setting up tools

Tool access works in every runtime, whether started with npx or Docker, once the operator configures tool_servers. The operator binds each server to an org, and optionally to some of its playbooks. Its allowed setting narrows the server's tools; see the Configuration reference. Connecting an external agent does not give the function that agent's tools, credentials or accounts; see Tool access inside a reasoning function.

How a run ends

Every rejection is a problem document, and is recorded on the run.

What happenedRejectionHTTP
The input is not a JSON object, or does not match the input schemainvalid_input, with the issues under /input422
The template reads a missing field outside a conditioninvalid_input at /input/<field>, with the line422
A filter rejects an input value, a render limit is reached, or the message renders emptyinvalid_input, with the line422
The model refuses the content under its policyinvalid_input422
The provider rejects the model, the schema or a settingconflict, kind unworkable409
A provider option its gateway does not allow, or a namespace nothing readsconflict, kind unworkable; nothing is called409
A JSON answer is cut off at max_output_tokensconflict, kind unworkable: raise config.max_output_tokens409
The answer is too large for the 1 MiB a run recordsconflict, kind unworkable: lower config.max_output_tokens409
The provider signals the request is too longconflict, kind unworkable409
The model is outside the operator's allowed modelsunavailable, kind model_not_offered, because: "model_not_allowed"503
The provider is not configured, or its certificate is not trustedunavailable503
The provider rejects the credentialsunavailable, with the HTTP status503
The provider limits the rate of requestsunavailable, with the seconds to wait when it said503
The provider cannot be reached or cannot serve now, or does not respond in timeunavailable: try again later503
A JSON answer does not match the schemaunavailable, with the first issues: try again503
A tool cannot be used before the model is calledunavailable, kind tool_not_offered or tool_server_failed503
A run that called tools cannot finishunavailable, kind tools_unfinished, or conflict, kind effect_unknown503 or 409
The caller disconnects before the run returnsThe run is interrupted and recorded as failed499

What the rejections say:

  • A provider's rejection names the provider, the HTTP status and what it means. It quotes the provider's own words only where Provider messages allow them.
  • A rejection for a provider that is not configured names that provider, with the configured providers and the aliases. A rejection for an untrusted certificate says that the operator must act. Neither names a setting. When other providers are configured but not this one, the kind is model_not_offered and because is provider_not_configured.
  • Nothing is sent to a model outside the allowed models.
  • A request that is too long is explained under Limits on time and failures. The tool endings are explained under Before the model is called and When a tool-calling run cannot finish.

More rules:

  • A text answer cut off at max_output_tokens succeeds, with finish_reason: "length" in the record.
  • A model call may take 60 seconds plus 25 ms for every token of max_output_tokens: 85.6 seconds at the default 1,024. That time includes up to two retries of a call that failed with HTTP 408, 409, 429 or 5xx, or could not connect.
  • When a provider ignores or changes a setting, the record's warnings say so.
  • The definition operations add their own rejections: not_found for a definition the playbook does not have, and conflict for a retired definition or one whose document no longer parses.

What a run records

get_run returns the output of a succeeded run with its record:

FieldWhat it holds
modelThe model as requested, as resolved through the aliases, and as the provider answered
settingsThe settings sent, with the default max_output_tokens filled in
output_formattext or json
finish_reason, raw_finish_reasonWhy the answer ended: stop, length, content_filter, tool_calls, error or other; and the provider's own word for it
usageInput tokens (uncached, cache read, cache write), output tokens (text, reasoning) and the total; null where unknown
response_idThe provider's id of the response; for Bedrock, its request id
warningsWhat the provider said it ignored or changed, and the parts of a tool's input schema that are not portable to it; at most 20
duration_msHow long the call took
promptThe rendered instructions and message, and truncated
  • The output and the record may be at most 1 MiB together; see Runs and results. When the prompt does not fit beside the answer, the record keeps the start of the instructions and of the message, and sets truncated: true.
  • The record contains no credentials. It also leaves out the provider options, which the definition already contains.
  • A run rejected after its model answered keeps a record with only usage and duration_ms, and the playbook's analytics count its tokens. That happens when:
    • the answer does not match the schema, or is cut off;
    • the model refused the content;
    • the model kept calling tools in the last step;
    • the answer is too large for the 1 MiB.
  • A rejection that comes before the model answers records no usage, since none is known. Neither does a call stopped by its deadline, by the run's bound or by failing tool servers.

The overview

get_definition returns a saved function with its overview: a plain-words description for a person who does not read Liquid or YAML. Auto Studio shows it before the document. The overview says, in order:

  1. The description, or that the function has none yet.
  2. What the function needs: each field of input.schema, with its type, its bounds and the value input.default gives it.
  3. What it produces: text, each field of output.schema, or the shape output.shape names, in a sentence.
  4. The model, and each tool it may call. When the function names any tools, a diagram draws the function, its model and those tools.
  5. What the model is told: the instructions and the message, as a person reads them.
  6. Used by: the active definitions of the playbook that use this function, read each time it is returned, and left out when there are none.

In the instructions and the message:

  • Each value the template reads, such as {{ input.brief }}, appears as its name in bold, brief, without its filters.
  • A condition or a loop that ends on a later line than it opens reads as lines. {% if input.vip %} becomes an italic line, When input.vip:. {% unless %} becomes Unless …:, {% elsif %} Or when …: and {% else %} Otherwise:. {% for item in input.items %} becomes For each item of input.items:.
  • A condition or a loop that opens and ends within one line reads as a phrase of that line. {% if input.vip %}Dear {% else %}Hello {% endif %} reads as Dear when input.vip, otherwise Hello. {% for item in input.items %}{{ item.name }}{% unless forloop.last %}, {% endunless %}{% endfor %} reads as each item of input.items as name, separated by commas.
  • Comments are left out, a raw block keeps its text, and any other tag stays as it is written.
  • The instructions and the message are each cut past 8,192 characters, with the line of the document where they continue.

The overview is written from the document when it is saved, so it says only what the document says. Write the description for the person who will read it. Give each field of the schemas a description, and put each field's default value in input.default, so the overview can show it. A function without them still has an overview, with only the types.

Provider options

provider_options passes options to one provider, under the namespace that provider reads. Only options that shape how the model reasons or writes its answer are offered:

yaml
provider_options:
  anthropic:
    thinking: { type: enabled, budgetTokens: 2000 }
NamespaceRead for models ofOffered
anthropicanthropic, bedrock-anthropic, vertex-anthropicthinking, with only type, budgetTokens and display
openaiopenai, and azure when there are no azure optionstextVerbosity, reasoningMode, logitBias
azureazuretextVerbosity, reasoningMode, logitBias
googlegoogle, and vertex when there are no googleVertex or vertex optionsthinkingConfig, safetySettings, threshold
vertexvertexthinkingConfig, safetySettings, threshold
googleVertexvertex, vertex-anthropicthinkingConfig, safetySettings, threshold, and thinking as for anthropic
amazonBedrockbedrockreasoningConfig
bedrockbedrock when there are no amazonBedrock options, and bedrock-anthropicreasoningConfig

An option is offered only when this table lists it; an option a provider adds is not offered until it is reviewed and listed. Put the options of Anthropic models on Bedrock under anthropic, since Bedrock passes anything under bedrock through unchanged. The runtime checks the option names, including the names inside thinking; the provider checks the values when the run calls it.

These are never offered, for any provider:

  • Anything the front matter sets, such as the effort level (config.reasoning), the token limit or how a JSON schema is sent (output).
  • Credentials, and attribution such as user, metadata or labels.
  • Anything stored or reused on the operator's account: store, previousResponseId, conversation, container, cacheControl, cachedContent, and prompt cache keys and retention.
  • Routing, fallbacks, capacity and service tiers.
  • Request headers and betas, such as anthropicBeta.
  • Tools and servers, such as mcpServers.
  • Raw request fields, such as additionalModelRequestFields or prediction.
  • Options for provider-managed conversation state, since the runtime manages the run's conversation.
  • Output the runtime does not read, such as logprobs or reasoningSummary.
  • Options that change how the runtime sends the prompt, such as systemMessageMode or forceReasoning.

An option that is not offered is refused when the document is saved. The problem names the option and says it is not offered, with the reason, such as effort is not offered: the front matter sets it. A namespace that is neither a provider's nor shaped like a gateway's name (a lowercase letter, then up to 31 letters, digits and hyphens) is refused the same way. Do not copy a provider's full API request into this field; write the options the table offers and read the validation feedback.

Options for a gateway

A gateway is an endpoint the operator configures under its own name. Every field under the gateway's name, or its camel-case form (my-gateway and myGateway), goes into the request body unchanged. user is read from openaiCompatible. A gateway gives meaning to body fields its operator may not want a function to set: attribution and budgets, routing and fallbacks, mock answers, endpoints and credentials. So under any of these namespaces, a function may set only the top-level fields the operator lists in the gateway's allowed_provider_options. By default that list is empty. The operator cannot allow a field the runtime sets, such as temperature.

Saving does not know which gateways are configured, so these checks happen when the function runs:

  • A field outside the list rejects the run as conflict with the kind unworkable, naming the field and saying the gateway does not allow it. The gateway is not called.
  • A namespace shaped like a gateway's name that no configured provider or gateway reads rejects the run the same way, before any provider is called.

The repository's engineering reference explains, for contributors, why each option and each left-out filter is withheld.