Core types
Request-side controls
Provider adapters compile the normalized schema before extraction. Strictness
is a provider-lowering request; local JSON Schema validation still runs before
Meerkat accepts the result.
Schema visibility
Whenoutput_schema is set, every request of the run (main turns and
extraction turns) carries this section, appended to the leading system prompt
after a blank line, or as the system prompt when the session has none:
additionalProperties: false on every
object). For Anthropic the section also keeps keywords the native
output_config.format slot cannot take, such as minimum and maximum: only
the slot copy on the extraction request is lowered, and validate-first and
extraction both validate against the full compiled schema. The optional schema name is not shown. The section is a pure
function of the compiled schema, so it is byte-identical across the requests
of a run and prompt caching is unaffected. It is added to requests only and
never written into the session transcript. Requests that reference Gemini
cached content (cached_content_name) are left unchanged, because the cached
content owns their system instruction. Provider-authored cache breakpoints
over a request carrying the section describe a system prompt the transcript
does not contain, so they are not recorded as durable cache evidence.
Validate-first
When the agentic loop ends, the final reply is validated first, with the same code-fence stripping and named-wrapper unwrapping extraction applies. A reply that validates becomesRunResult.structured_output and no extraction request
is sent. Anything else (prose, invalid JSON, a schema mismatch, or a validator
fault) runs the extraction phase exactly as described below: the same prompt,
temperature 0.0, no tools, the provider’s native schema slot, and the same
retry accounting.
The extraction_succeeded event of a validate-first success carries
"origin": "final_reply" and no request_usage, so consumers that count
provider requests (the ATIF exporter, usage summaries) do not count an
extraction request that never ran. origin is omitted when an extraction
request produced the value, which is also how events written before the field
existed read.
Validate-first also asserts known JSON Schema format keywords (for example
date-time, email, uri, uuid); unknown formats are ignored. Providers
that decode natively against the schema enforce these formats on the
extraction request, so a final reply that has the right shape but breaks a
declared format runs extraction instead of being accepted. The extraction
phase’s own validation treats format as an annotation, as before.
The section shows the schema as the active provider compiles it. When a
sticky model fallback switches providers mid-request, the retried request
shows the fallback provider’s compiled schema, which is also the one used
for validation from then on.
Known limits
- Changing the schema between turns of one session invalidates the cached
prompt prefix. The section is part of the leading system prompt, so a turn
that sets, clears, or swaps
output_schemasends a different prompt prefix than the turns before it, and the provider’s prompt cache misses for that prefix once. Only callers that change the schema from turn to turn are affected: a session with a stable schema (or none) sends a byte-identical prefix on every request, and caching works as usual. - OpenAI Responses
store=truecontinuation keeps the section of the stored chain. With the explicitstore=trueopt-in, follow-up requests continue the conversation the provider stored instead of resending it, so the model still sees the section the earlier requests carried, the same way a stored chain keeps an earlier system prompt. If the schema changed since, the visible reply may follow the old schema.structured_outputstays correct: validate-first checks the reply against the current schema, a reply shaped by the old one fails, and the extraction request runs with the current schema in the native slot.
Result-side fields
Provider schema compilation happens before the main output is saved into the
result. A compilation failure can therefore return the typed extraction failure
with an empty
RunResult.text; output retention applies to failures after
schema compilation succeeds.
Event ordering
After provider schema compilation succeeds, a schema-bearing run has two terminal observability stages:- The normal agentic turn completes and emits
run_completedwithextraction_required: true.resultis the main assistant output. - Extraction emits exactly one follow-up terminal event:
extraction_succeededwithstructured_outputand optionalschema_warnings, orextraction_failedwithlast_output,attempts, andreason. When validate-first accepts the final reply,extraction_succeededfollowsrun_completeddirectly.
turn_completed events. Both
outcome events carry request_usage: one per-call usage row for each answered
extraction request, including attempts that failed validation. Extraction
failure does not emit run_failed; the main run already completed, and the
returned RunResult carries extraction_error.
Provider schema compilation happens before these success-shaped boundaries. A
compile failure emits extraction_failed directly and emits neither
turn_completed nor run_completed first.
Validation note
Schema validation depends on thejsonschema feature. A build without that
feature fails closed with typed InvalidOutputSchema when an output schema is
configured. Meerkat never marks merely parsed, unvalidated JSON as structured
output.
Each extraction attempt runs with no tools. Core requests temperature 0.0;
provider lowering may omit it when the provider/model does not support the
parameter. This is not a deterministic-output guarantee. Markdown code
fences are stripped before parsing. A provider may wrap a named root object in
the schema name; Meerkat unwraps that envelope only when the inner object is a
clearly better match and the wrapper key is not itself declared by the schema.
