> For the complete documentation index, see [llms.txt](/llms.txt).
> A full single-fetch corpus is available at [llms-full.txt](/llms-full.txt).
---
last_verified: 2026-10-09
title: Context API
description: The Context object every TypeScript handler receives — run details, steps, state, waits, signals, logging, and progress
category: TypeScript SDK
hideRightSidebar: true
---

Every function, workflow, and tool handler receives a `Context` as its first argument. It describes the current run and gives the handler access to durable steps, state, waits, and logging.

```typescript
import { fn } from '@agnt5/sdk';
import type { Context } from '@agnt5/sdk';

export const audit = fn('audit').run(async (ctx: Context, input: { orderId: string }) => {
  ctx.logger.info('Auditing order', { orderId: input.orderId, attempt: ctx.attempt });
  return { runId: ctx.runId };
});
```

## Run details

| Property | Type | Description |
|---|---|---|
| `runId` | `string` | The ID of the current run. |
| `invocationId` | `string` | The ID of this invocation. |
| `attempt` | `number` | Which try this is, starting at `0`. |
| `serviceName` | `string` | The worker's service name. |
| `activation` | `ActivationExecution \| undefined` | Inside a durable step on a deployed worker: `activationId`, `attempt`, and `idempotencyKey`. Send `idempotencyKey` to downstream systems so a re-run step doesn't repeat an effect. |
| `runtime` | `RuntimeContext` | Model overrides for this run: `runtime.llm` and `runtime.prompts`. See [Prompts](/docs/build/prompts.md#override-runtime-settings). |
| `caller` | `Caller \| undefined` | Set when the run was started by an MCP client: `server`, `tool`, `subject`, and `authMethod`. |
| `sandbox` | `Sandbox \| undefined` | The [sandbox](/docs/build/sandboxes.md) attached to the agent running this tool. |
| `metadata` | `Record<string, string> \| undefined` | Platform metadata for the run. |

## Steps and sleep

| Method | Description |
|---|---|
| `ctx.step(name, fn, options?)` | Run `fn` and checkpoint its result. Options: `key`, `input`. See [Workflows](/sdk/typescript/workflows.md#steps). |
| `ctx.sleep(ms, name?)` | Pause durably for `ms` milliseconds. |

## State

Run-scoped state that survives replay. All methods are async.

| Method | Description |
|---|---|
| `ctx.set(key, value)` | Store a JSON-serializable value. |
| `ctx.get<T>(key, defaultValue?)` | Read a value, or `defaultValue` when the key is not set. |
| `ctx.delete(key)` | Remove a key. Resolves to `true` when it existed. |

## Wait for a person

`ctx.waitForUser(question, options?)` pauses the workflow until someone answers, and resolves to the answer as a string, or `null` for a skipped question.

```typescript
const decision = await ctx.waitForUser('Approve this refund?', {
  inputType: 'approval',
  options: [
    { id: 'approve', label: 'Approve' },
    { id: 'reject', label: 'Reject' },
  ],
});
```

| Option | Description |
|---|---|
| `inputType` | `'text'` (default), `'approval'`, `'select'`, or `'multiselect'`. |
| `options` | Choices for `approval`, `select`, and `multiselect`: `{ id, label }`. |
| `allowCustom` | Adds a free-text choice to `select` and `multiselect`. |
| `skippable` | Lets the person skip; the answer is then `null`. |

People answer in Studio or with the [resume API](/docs/api-reference/runs-and-traces/resume-a-workflow.md). See [Human-in-the-loop](/docs/build/human-in-the-loop.md) for every input type.

## Wait for a signal

`ctx.waitForSignal<T>(signalName, name?)` pauses the workflow until another system sends a signal with that name, and resolves to the signal's payload.

```typescript
import { workflow } from '@agnt5/sdk';

export const shipment = workflow('shipment', async (ctx: Context, input: { orderId: string }) => {
  const delivery = await ctx.waitForSignal<{ deliveredAt: string }>('delivered', 'wait_delivery');
  return { orderId: input.orderId, deliveredAt: delivery.deliveredAt };
});
```

While it waits, the run's status is `paused`. Send the signal to the gateway with a [service key](/docs/build/local-development.md#create-a-service-key); the body's `payload` becomes the resolved value:

```bash
curl -X POST "https://gw.agnt5.com/v1/runs/<run-id>/signals/delivered" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: agnt5_sk_..." \
  -H "X-DEPLOYMENT-ID: <deployment-id>" \
  -d '{"payload": {"deliveredAt": "2026-10-09T18:00:00Z"}}'
```

## Logging, progress, and custom events

| Method | Description |
|---|---|
| `ctx.logger.info(message, meta?)` | Structured log line; also `debug`, `warn`, and `error`. `meta` is an object of extra fields. Logs appear in the run's logs and in `agnt5 inspect logs`. |
| `ctx.progress(value, { total?, message? })` | Report progress for a long-running handler, for example `ctx.progress(3, { total: 10, message: 'Indexed 3 of 10' })`. |
| `ctx.emit({ eventType, data })` | Record a custom event in the run's journal, for example `{ eventType: 'order.flagged', data: { reason } }`. |

## Next steps

* [Workflows](/sdk/typescript/workflows.md): steps, child workflows, and concurrency helpers.
* [Functions](/sdk/typescript/functions.md): the handlers that receive this context.
* [Human-in-the-loop](/docs/build/human-in-the-loop.md): every way to pause for a person.
