> ## Documentation Index
> Fetch the complete documentation index at: https://vetta.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured outputs

> Constrain a session's final result to a JSON Schema and read it back as typed data — no transcript scraping.

An agent's durable outputs are the [files](https://vetta.sh/docs/capabilities/files.md) it published and its [event history](https://vetta.sh/docs/concepts/events-and-streaming.md). That is everything a human needs, but a machine consumer wants one more thing: a **typed result** it can read without replaying a transcript. A **structured output** is exactly that — you attach a JSON Schema, and when the session goes [idle](https://vetta.sh/docs/concepts/sessions.md#lifecycle) the harness produces a `structured_output` object that conforms to it, sitting right on the session next to the files and events.

This is the contract that turns a deployment or a delegated sub-task from "read the transcript and hope" into a plain typed hand-off.

## Set an output schema

An `output_schema` is a standard [JSON Schema](https://json-schema.org). Set it on the **agent** to make it the default for every session, or on a **session** to override the default for one run. The session-level schema always wins.

```bash CLI theme={"system"}
vetta session create --agent agt_01j8rf6tq2m4vz9xkp3n7c5hwd \
  --message "Refund order #4821 if it qualifies." \
  --output-schema ./schemas/refund-decision.json
```

```typescript TypeScript theme={"system"}
const session = await vetta.sessions.create({
  agent: agent.id,
  message: "Refund order #4821 if it qualifies.",
  outputSchema: {
    type: "object",
    properties: {
      order_id: { type: "string" },
      refunded: { type: "boolean" },
      amount_micro_usd: { type: "integer" },
      reason: { type: "string" },
    },
    required: ["order_id", "refunded"],
  },
});
```

Set it once on the agent to bake the shape into every run:

```typescript TypeScript theme={"system"}
const agent = await vetta.agents.create({
  name: "Refunder",
  model: "z-ai/glm-5.3-flash",
  harness: "pi",
  budget: { capUsd: 50, maxTaskUsd: 5, period: "month" },
  outputSchema: refundDecisionSchema,   // agent-level default
});
```

## Reading the result

When a session with an `output_schema` reaches idle, its `structured_output` field is populated with an object that satisfies the schema. When no schema is set, `structured_output` is `null` and you fall back to files and events as before.

```bash CLI theme={"system"}
vetta session get $SID    # includes structured_output when a schema was set
```

```typescript TypeScript theme={"system"}
const s = await vetta.sessions.get(sessionId);
if (s.structured_output) {
  const { order_id, refunded, amount_micro_usd } = s.structured_output;
  await recordRefund(order_id, refunded, amount_micro_usd);
}
```

The same object rides on the `session.idle` [webhook](https://vetta.sh/docs/capabilities/webhooks.md) payload, so a push consumer never has to make a follow-up read:

```json theme={"system"}
{
  "id": "evt_7h...",
  "type": "session.idle",
  "created_at": "2026-08-20T09:00:12Z",
  "data": {
    "session_id": "ses_4a...",
    "stop_reason": "end_turn",
    "structured_output": {
      "order_id": "4821",
      "refunded": true,
      "amount_micro_usd": 4200000,
      "reason": "Within 30-day policy window."
    }
  }
}
```

## Requiring conformance

By default a schema is best-effort: if the agent finishes without producing a conforming object, the session still goes idle with `structured_output: null`. Set `structured_output_required: true` to make the schema a hard contract instead.

**structured\_output\_required** `boolean` (default: false)

When `true`, the session must produce a schema-conforming object to finish cleanly. If it cannot, the session goes idle with `stop_reason: "error"` and a typed failure describing what was missing, rather than silently returning `null`. Use this when a downstream system will break on a missing field.

> [!NOTE]
>
> The schema constrains only the **final** result. Intermediate turns, tool calls, and reasoning are unconstrained — the agent works however it needs to, and the harness enforces the shape only at the point the session yields control.

## How the agent submits it

Setting an `output_schema` gives the agent one extra tool, **`submit_output`**, whose parameters are
your schema. The agent calls it once with the finished result, and those arguments become the
session's `structured_output`. Two consequences worth knowing:

* **Conformance is checked at the call.** A call that does not match the schema is rejected and
  handed back to the agent with the reason, so it can correct and try again. A non-conforming object
  never reaches `structured_output`.
* **Per-tool [permissions](https://vetta.sh/docs/capabilities/tools.md) do not apply to it.** `submit_output` is how the
  answer comes back, not something the agent *does*, so it is offered even to an agent whose default
  tool permission is `ask` or `deny`.

You can watch it happen on the [event stream](https://vetta.sh/docs/concepts/events-and-streaming.md): a `tool.started` for
`submit_output` carrying the document as its arguments, then the `session.idle` event with the same
object under `structured_output`. When `structured_output_required` was not satisfied, that
`session.idle` also carries an `error` string saying so.

## Configuration reference

**output\_schema** `object`

A JSON Schema describing the session's final result. Settable on the agent (default for every session) or on the session (overrides the agent default). Omit it to leave `structured_output` as `null`.

**structured\_output\_required** `boolean` (default: false)

Require a conforming object; otherwise the session ends with `stop_reason: "error"`.

**structured\_output** `object | null`

Read-only on the session object. The schema-conforming result once the session is idle, or `null` if no schema was set or none was produced.

> [card] [Next: observability](https://vetta.sh/docs/capabilities/observability.md)
>
> Per-session cost, usage, and OpenTelemetry export.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.