> ## 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.

# Sessions

> A single, directly-controlled run of an agent.

A session is one run of an [agent](https://vetta.sh/docs/concepts/agents.md). You control it directly: send input, stream [events](https://vetta.sh/docs/concepts/events-and-streaming.md), interrupt it, adjust its budget, and read the files it produced. State is durable — a session can run for hours, survive restarts, and sit idle for days at storage cost only.

## Lifecycle

Sessions progress through these statuses:

| Status | Description |
| - | - |
| `queued` | Created and accepted; the first turn has not started yet. |
| `running` | The agent is actively executing a turn. |
| `idle` | The turn yielded control and the session is **resumable** — waiting for input, a tool confirmation, or its next scheduled fire. Carries a `stop_reason`. |
| `completed` | The agent declared the task done. Non-`running`, like `idle`. |
| `failed` | An unrecoverable error ended the run. |
| `cancelled` | The run was canceled with `cancel`. Terminal. |

> [!NOTE]
>
> There is no mandatory "deliver" step. When a turn yields control the session goes **`idle`** with a `stop_reason` and stays resumable — you can send more input for days. It reaches **`completed`** only when the agent declares the task done. Anything worth keeping is written to [Files](https://vetta.sh/docs/capabilities/files.md) via `publish_file`; scratch work stays in the session's sandbox.

## Create a session

A session inherits its agent's configuration. The simplest create is empty and starts `idle`, then you send it work. To start a session **`running` in a single call**, pass an initial `message` — it is enqueued as the first input and the agent begins its first turn immediately.

```bash CLI theme={"system"}
# One call: create and start running
vetta session create --agent agt_01j8rf6tq2m4vz9xkp3n7c5hwd --message "Refund order #4821"
```

```typescript TypeScript theme={"system"}
const session = await vetta.sessions.create({
  agent: agent.id,
  message: "Refund order #4821",
});
```

```bash cURL theme={"system"}
curl -fsSL https://api.vetta.sh/v1/sessions \
  -H "authorization: Bearer $VETTA_API_KEY" \
  -H "content-type: application/json" \
  -d '{ "agent_id": "agt_7Q...", "message": "Refund order #4821" }'
```

You can still create a session without input and drive it in two steps — useful when you want to attach resources or start streaming before the first turn:

```bash CLI theme={"system"}
vetta session create --agent agt_01j8rf6tq2m4vz9xkp3n7c5hwd --window immediate --budget-usd 2.00
# ... then, when ready ...
vetta session send --session $SID --message "Refund order #4821"
```

```typescript TypeScript theme={"system"}
const session = await vetta.sessions.create({
  agent: agent.id,
  window: "immediate",
  budgetMicroUsd: "2000000", // $2.00 — whole micro-USD; never a bare number
});
await session.send("Refund order #4821");
```

Both forms accept the same creation options — completion window (`immediate` / `priority` / `loose`), a session budget, agent overrides, and the attachable resources below.

### Attach resources at create

Beyond the agent's own configuration, a create call can bind extra resources to the session:

| Field | What it does |
| - | - |
| `computer` | *(coming soon)* Reuse an existing [computer](https://vetta.sh/docs/capabilities/computer.md) (`cmp_...`) instead of provisioning a fresh sandbox. |
| `skills` | *(coming soon)* [Skills](https://vetta.sh/docs/capabilities/skills.md) to mount for this run, on top of the agent's — today skills are set on the agent. |
| `vault_ids` | *(coming soon)* [Vaults](https://vetta.sh/docs/identity/overview.md) whose secrets the session may read. Today a session reaches vault credentials through the [MCP connector](https://vetta.sh/docs/capabilities/tools.md#mcp-connector); a session-level grant is not yet accepted. |
| `outcome` | *(Phase 4)* An outcome (`out_...`) to grade the run against a rubric. |
| `metadata` | Arbitrary key-value pairs stored on the session and echoed on its events. |

```typescript TypeScript theme={"system"}
const session = await vetta.sessions.create({
  agent: agent.id,
  message: "Draft the Q3 refund report",
  computer: "cmp_3f...",
  skills: ["pdf-forms"],
  outcome: "out_9k...",            // Phase 4
  metadata: { ticket: "OPS-4821" },
});
```

### Override agent configuration for a session

*(Coming soon.)* Session-local `overrides` for the agent's `model`, `system`, `skills`, `tools`, or `computer` are not yet accepted on create — today you pin behavior with `agent_version` or create a new agent version. When overrides land they will be **session-local** and never propagate back to the agent or its [versions](https://vetta.sh/docs/concepts/agents.md#versioning).

```typescript TypeScript theme={"system"}
const session = await vetta.sessions.create({
  agent: agent.id,
  overrides: { model: "z-ai/glm-5.3-flash", system: "Escalate anything ambiguous." },
});
```

Override semantics:

* **Arrays replace in full — they are not merged.** Passing `skills` or `tools` in `overrides` swaps the agent's list wholesale rather than unioning with it.
* **`model` cannot be cleared.** You may point a session at a different model, but every session has one; passing an empty value is rejected.
* **Nothing flows back.** When the session ends, the agent definition is exactly as it was before.

## Send work and stream

```typescript TypeScript theme={"system"}
await session.send("Refund order #4821");

for await (const e of session.stream()) {
  if (e.type === "message.delta") process.stdout.write(e.text);
  if (e.type === "tool.completed") console.log(`\n[tool] ${e.name}`);
  if (e.type === "session.idle") break;
}
```

The stream is resumable by **sequence**: reconnect with `session.stream({ fromSeq })` to replay everything after a `seq` you already handled — no gaps, no duplicates. See [Events & streaming](https://vetta.sh/docs/concepts/events-and-streaming.md).

## Session budgets

A session can carry its own cap, independent of the agent's period budget. When the running total reaches the cap, the session **pauses**: it goes `idle` with `stop_reason: "budget_paused"` and stops pricing new calls. Raising the cap — or removing it entirely — **auto-resumes** the paused session from exactly where it stopped, with no need to re-send the last message. See [Budgets](https://vetta.sh/docs/concepts/budgets.md).

```bash CLI theme={"system"}
vetta session budget --session $SID --usd 5.00   # raise → auto-resumes
```

## Stop reasons

Every time a session goes `idle`, the `session.idle` [event](https://vetta.sh/docs/concepts/events-and-streaming.md) and the session record carry a `stop_reason` — a string describing why the turn ended:

| `stop_reason` | Meaning |
| - | - |
| `end_turn` | The agent finished the turn and has nothing left to do. The normal, healthy resting state. |
| `awaiting_input` | The turn ended with nothing left to do and the session is waiting for whatever you send next. Nothing specific is owed — when the agent needs a particular answer it reports `awaiting_answer` instead. |
| `awaiting_approval` | The agent called a tool gated by an [`ask` policy](https://vetta.sh/docs/concepts/policies) and is waiting on your confirmation. Reply with an allow/deny to resume — see [Awaiting-approval loop](https://vetta.sh/docs/concepts/session-operations.md#awaiting-approval-loop). |
| `budget_paused` | A [session or agent budget](https://vetta.sh/docs/concepts/budgets.md) cap was reached, or the prepaid balance ran out. Raise or remove the cap to auto-resume; a top-up resumes a session the balance stopped. |
| `interrupted` | You [interrupted](https://vetta.sh/docs/concepts/session-operations.md#interrupting) the turn; it stopped at the next commit boundary. |
| `max_iterations` | The turn hit its step/iteration cap for a single slice. Send another message to continue. |
| `context_exhausted` | The turn produced neither a message nor a tool call. Reported honestly rather than as `end_turn`, which would claim the task was finished. |
| `awaiting_delegation` | A [coordinator](https://vetta.sh/docs/team/coordinator.md) yielded because every thread it [delegated](https://vetta.sh/docs/team/delegation.md) to is still running. Nobody is being asked for anything, so no reply unblocks it — the children finishing does. |
| `awaiting_answer` | The agent asked you a question and cannot continue without the answer. What is being asked is a `pending_actions` entry with `kind: "question"`, carrying the prompt and one to three fields — see [Awaiting-answer loop](https://vetta.sh/docs/concepts/session-operations.md#awaiting-answer-loop). Reported only when *every* parked row is a question; a session parked on both reports `awaiting_approval` and still carries the questions. |
| `error` | An unrecoverable error ended the turn. |

## Retrieving results after idle

When a session goes `idle`, its durable outputs are the [files it published](https://vetta.sh/docs/capabilities/files.md), its [event history](https://vetta.sh/docs/concepts/events-and-streaming.md), and — when an [output schema](#structured-results) is set — a typed `structured_output`. Scratch work stays in the session's sandbox and is not returned — the agent promotes anything worth keeping with `publish_file`.

```bash CLI theme={"system"}
vetta file list --session $SID            # artifacts this session published
vetta session events --session $SID        # replay the full transcript (resumable --from-seq)
```

```typescript TypeScript theme={"system"}
const s = await vetta.sessions.get(session.id);
if (s.status === "idle") {
  const files = await vetta.files.list({ sessionId: s.id });
  for (const f of files) console.log(f.id, f.name);   // fil_...
}
```

## Structured results

By default an agent's durable output is the files it published plus its event history. When you also want a machine-readable result, set an **`output_schema`** (a JSON Schema) — on the agent as a default, or per session as an override. When the session goes `idle` having satisfied the schema, the session object carries a typed **`structured_output`** object alongside its files and events, so a caller can read the result directly instead of parsing the transcript.

```typescript TypeScript theme={"system"}
const session = await vetta.sessions.create({
  agent: agent.id,
  message: "Refund order #4821 and report the outcome.",
  outputSchema: {
    type: "object",
    properties: {
      refunded: { type: "boolean" },
      amount_micro_usd: { type: "integer" },
    },
    required: ["refunded"],
  },
});

const s = await vetta.sessions.get(session.id);
if (s.status === "idle" && s.structured_output) {
  console.log(s.structured_output.refunded, s.structured_output.amount_micro_usd);
}
```

The same typed `structured_output` is included on the [`session.idle` deployment payload](https://vetta.sh/docs/capabilities/deployments), so an unattended fire returns a structured result without a transcript replay.

## Cost and usage

Every session object carries its running cost and token usage, so you never have to reconstruct spend from the transcript. `consumed_micro_usd` is the cumulative cost in integer [micro-USD](https://vetta.sh/docs/concepts/budgets.md), and `token_usage` breaks the model tokens into the five metered tiers — `input`, `cache_write`, `cache_read`, `output`, and `reasoning`. A `session.usage` [event](https://vetta.sh/docs/concepts/events-and-streaming.md) is emitted before every idle or terminal transition, and the fuller export path is described in [Observability](https://vetta.sh/docs/capabilities/observability.md).

```json theme={"system"}
{
  "id": "ses_4a...",
  "status": "idle",
  "stop_reason": "end_turn",
  "consumed_micro_usd": 12530000,
  "token_usage": { "input": 41230, "cache_write": 2048, "cache_read": 18900, "output": 3120, "reasoning": 900 },
  "last_seq": 128
}
```

## Update the agent mid-session

*(Coming soon.)* Session-local updates to `tools` and `mcp_servers` while a session is `idle` are not yet served — today, changing tools means a new agent version (or a new session). When this lands, updates will be a full replacement of the provided array and session-local.

## Create parameters

**agent** `string` *required*

The [agent](https://vetta.sh/docs/concepts/agents.md) to run. Accepts a name or an `agt_` id.

**message** `string`

Initial input. When present, the session starts `running` instead of `idle`.

**window** `string` (default: agent default)

Override the [completion window](https://vetta.sh/docs/concepts/completion-window.md): `immediate`, `priority`, or `loose`.

**budget\_usd** `number`

A session-local spend cap. On the wire this is sent as integer micro-USD (`budget_micro_usd`); the CLI `--budget-usd` and SDK helpers convert dollars client-side. Reaching it pauses the session with `stop_reason: "budget_paused"`.

**output\_schema** `object`

A JSON Schema for a [structured result](#structured-results). Overrides the agent's default. When set, the idle session carries a typed `structured_output`.

**overrides** `object`

*(coming soon)* Session-local replacements for the agent's `model`, `system`, `skills`, `tools`, or `computer`. Arrays replace in full; `model` cannot be cleared.

**computer** `string`

*(coming soon)* An existing computer (`cmp_...`) to attach instead of a fresh sandbox.

**skills** `string[]`

*(coming soon)* Skills to mount for this run.

**vault\_ids** `string[]`

*(coming soon)* Vaults the session may read secrets from — not yet accepted on create.

**outcome** `string`

*(Phase 4)* An outcome (`out_...`) to grade the run against a rubric.

**metadata** `object`

Arbitrary key-value pairs stored on the session and echoed on its events.

> [card] [Next: session operations](https://vetta.sh/docs/concepts/session-operations.md)
>
> Retrieve, list, interrupt, archive, and delete sessions.


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