Overview
Mode gives fine-grained control over which schema
fields are exposed to the LLM. It matters most for APIs where one resource is used by several operations
with different field sets — Gmail’s Message being the canonical case: send
accepts only raw, while reads return a structured payload tree.
It has a second job that is easy to miss and is arguably the more valuable one:
because the LLM view is computed from these declarations before any request is
made, Mode is also field-level data minimisation toward your model vendor —
a withheld field cannot reach a context window, by construction. See
egress control, including the audit artifact that renders
it.
Core concepts
The marker
mode_marker.py
Special modes
Always enforced, whatever mode the tool declares:response_only— the API returns it and never accepts it. Hidden from the LLM. IDs, timestamps, computed fields.request_only— input-only. Always shown.disabled— never exposed. Internal or deprecated fields.
Custom modes
Any other string. A custom mode narrows the view only when the tool declares a mode. With nomode= on the tool, custom-moded fields are all visible — setting
mode= is what makes create and update mutually exclusive.
Features
Multi-mode
Cascading
Child fields inherit the parent’s modes, so you mark the parent once:cascading_modes.py
response_only parent hides its whole subtree.
Mode + Format together
Processing order
- Mode filtering — fields are checked against the effective mode.
- Format transformation — only included fields are retyped.
- Metadata preservation — every marker survives onto the generated schema.
Declaring a mode on a tool
The builder’smode= parameter picks the
effective mode for that tool:
messages_send_tool.py
Worked example: Gmail
Problem.messages.send accepts only raw (RFC-822). Reads return a
structured payload MIME tree. One schema for both confuses the model into
sending fields the endpoint ignores.
Solution.
gmail_message_schema.py
mode="A"seesraw,thread_idmode="B"seespayload,thread_idmode=Nonesees everything exceptresponse_onlyanddisabled
Inspecting the result
Tool.llm_schema builds the filtered view —
what the model is actually handed:
Do’s and don’ts
Do- lean on cascading instead of marking every nested field
- say why a field has a mode, in the field description
- test each mode configuration
- use semantic mode names
- mark every nested field redundantly
- mix concerns into one name (
Mode("admin_read_v2")) - forget to set
mode=on the tool when the schema depends on it - use modes for authorization — they are a schema-visibility tool, not a permission system
Related
Mode— the marker, its values, and the cascade rulesFormat— the retyping that runs after mode filteringTool.llm_schema— the filtered schema the model sees- Egress control — the audit artifact these declarations produce