# Pass state to AI SDK tools and agents with context

**Author:** Ben Sabic

---

Context lets you pass server-side state through a generation or agent loop without putting that state into the prompt. The AI SDK keeps shared runtime state separate from per-tool state, so an agent can track its own progress while each tool receives only the values it needs. Use context for tenant information, feature flags, session data, request IDs, API credentials, or access tokens, the kind of values that shape how your code runs but that the model shouldn't reason about. `runtimeContext` carries state for the whole loop, while `toolsContext` and `contextSchema` scope state to an individual tool.

## Overview

In this guide, you'll learn how to:

- Tell `runtimeContext` and `toolsContext` apart, and know when to reach for each
  
- Pass shared state through a generation or agent loop with `runtimeContext`
  
- Scope state to a single tool with `toolsContext` and a `contextSchema`
  
- Keep sensitive values out of telemetry with context filtering
  

## How context flows through a loop

The AI SDK splits context into two layers. `runtimeContext` is shared across the whole generation or agent loop, and `toolsContext` holds values scoped to individual tools. Each tool declares the shape of the context it expects, and the SDK validates and passes only that tool's context to it, so one tool can't read another tool's values.

| Concept          | Where you set it                                                   | Where you read it                                                                          | Use it for                                         |
| ---------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | -------------------------------------------------- |
| `runtimeContext` | `generateText`, `streamText`, or a `ToolLoopAgent` call            | `prepareStep`, lifecycle callbacks, step results, and telemetry                            | Shared generation or agent state                   |
| `toolsContext`   | `generateText`, `streamText`, or a `ToolLoopAgent` call            | `prepareStep`, approval callbacks, and tool context resolution                             | Map of per-tool context values, keyed by tool name |
| Tool `context`   | Each tool's `toolsContext` entry, validated by its `contextSchema` | The tool's `execute`, description function, `needsApproval`, and input lifecycle callbacks | Values needed by one tool                          |

Both layers start from the same `generateText`, `streamText`, or `ToolLoopAgent` call. Runtime context is the shared state for the loop, and you can read or update it in `prepareStep` between model calls. Tool context works differently. The SDK resolves it from `toolsContext` into each tool's own validated `context` before that tool runs, so a tool only ever sees the values meant for it. Telemetry receives a filtered copy of both, which you control with the filters covered below.

## How to pass shared state with runtime context

Pass `runtimeContext` when you need shared state for the whole generation or agent loop. The AI SDK doesn't add `runtimeContext` to the model prompt, so it's a safe place for values that should affect execution without reaching the model. Use it to configure step preparation, track server-side state, or correlate lifecycle events.

`import { generateText } from 'ai'; const result = await generateText({ model: 'openai/gpt-5.2', prompt: 'Help me plan a trip.', runtimeContext: { tenantId: 'tenant_123', plan: 'enterprise', requestId: 'req_abc', }, prepareStep: async ({ runtimeContext }) => { if (runtimeContext.plan === 'enterprise') { return { temperature: 0.2 }; } return {}; }, });`

`prepareStep` can return a new `runtimeContext`. The new value applies to the current step and every step after it, which makes `prepareStep` the right place to update agent state between turns of the loop.

## How to give a tool its own state with tool context

Use `toolsContext` for values that belong to a specific tool. Each tool declares the context it expects with `contextSchema`, and the AI SDK validates the matching `toolsContext` entry and passes it to the tool as `context`. A tool receives only its own context, not the full `toolsContext` map, so an untrusted or third-party tool can't read another tool's credentials.

`import { generateText, tool } from 'ai'; import { z } from 'zod'; const weatherTool = tool({ description: 'Get the weather in a location', inputSchema: z.object({ location: z.string(), }), contextSchema: z.object({ weatherApiKey: z.string(), defaultUnit: z.enum(['celsius', 'fahrenheit']), }), execute: async ({ location }, { context }) => { return fetchWeather({ location, apiKey: context.weatherApiKey, unit: context.defaultUnit, }); }, }); const result = await generateText({ model: 'openai/gpt-5.2', tools: { weather: weatherTool }, toolsContext: { weather: { weatherApiKey: process.env.WEATHER_API_KEY!, defaultUnit: 'fahrenheit', }, }, prompt: 'What is the weather in San Francisco?', });` When at least one tool declares a `contextSchema`, `toolsContext` becomes required for the tools that need it. Tool description functions receive the same typed `context` before each model call, so a tool's description can change with its current context. Treat tool context as immutable inside a tool. To change it between steps, inspect the previous step in `prepareStep` and return an updated `toolsContext`. ## How to keep context out of telemetry Context often contains values that are useful within your application but shouldn't be sent to telemetry providers. Use `telemetry.includeRuntimeContext` to send selected top-level runtime context properties, and `telemetry.includeToolsContext` to send selected top-level tool context properties per tool. `import { ToolLoopAgent, tool } from 'ai'; import { z } from 'zod'; const customerLookup = tool({ description: 'Look up customer account details', inputSchema: z.object({ customerId: z.string(), }), contextSchema: z.object({ apiKey: z.string(), region: z.string(), }), execute: async ({ customerId }, { context }) => { return lookupCustomer({ customerId, apiKey: context.apiKey, region: context.region, }); }, }); const agent = new ToolLoopAgent({ model: 'openai/gpt-5.2', tools: { customerLookup }, }); const result = await agent.generate({ prompt: 'Check whether customer cust_123 is eligible for priority support.', runtimeContext: { requestId: 'req_abc', tenantId: 'tenant_123', userId: 'user_123', }, telemetry: { includeRuntimeContext: { requestId: true, }, includeToolsContext: { customerLookup: { region: true, }, }, }, toolsContext: { customerLookup: { apiKey: process.env.CUSTOMER_API_KEY!, region: 'us', }, }, });` With this configuration, telemetry receives the `customerLookup` context with only `region`, and the runtime context with only `requestId`. The `apiKey`, `tenantId`, and `userId` values never leave your application. > **Note:** Context filters only affect telemetry integrations, including OpenTelemetry. Tool execution, lifecycle callbacks, and returned results still receive the full context values. Filtering is shallow and applies only to top-level properties. When you omit `telemetry.includeRuntimeContext`, the SDK sends no runtime context properties; when you set it, the SDK sends only the properties you mark `true`. The same rule applies to `telemetry.includeToolsContext`. Use these filters to reduce telemetry exposure, not as a general security boundary. ## When to use runtime context, tool context, or the prompt Match each kind of state to where it's read: - **Runtime context**: Use `runtimeContext` for state shared by the whole generation or agent loop, such as request metadata, tenant settings, feature flags, or agent progress.    - **Tool context**: Use `toolsContext` and `contextSchema` for values a single tool needs, such as API keys, scoped clients, user permissions, or default tool settings.    - **Prompt messages**: Put information the model should reason about or mention in its answer into the prompt, not into context.    - **Telemetry filters**: Use `telemetry.includeRuntimeContext` and `telemetry.includeToolsContext` to control what context reaches your telemetry provider.    ## Where you can read each kind of context Use this table to find where each kind of context is available as you build: | Location                                 | `runtimeContext`                              | `toolsContext`                              | Tool `context`                              | | ---------------------------------------- | --------------------------------------------- | ------------------------------------------- | ------------------------------------------- | | `prepareStep`                            | Read and update                               | Read and update                             | Not directly                                | | Tool `execute` and description functions | Not passed directly                           | Not passed directly                         | Read the tool's validated `context`         | | Tool approval callbacks                  | Read                                          | Read in generic callbacks                   | Read as `toolContext` in per-tool callbacks | | Step results and finish callbacks        | Read per-step or final state                  | Read per-step or final state                | Available through `toolsContext` entries    | | Telemetry                                | Filtered by `telemetry.includeRuntimeContext` | Filtered by `telemetry.includeToolsContext` | Filtered by `telemetry.includeToolsContext` | ## Next steps - Read [Tools and tool calling](https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling) to define tools, input schemas, and multi-step tool calls.
  
- See [Building agents](https://ai-sdk.dev/docs/agents/building-agents) to use `ToolLoopAgent` and `prepareStep` for managing context across steps.
  
- Explore [Lifecycle callbacks](https://ai-sdk.dev/v7/docs/ai-sdk-core/lifecycle-callbacks) to hook into each step where runtime context is available.
  
- Check the [Telemetry](https://ai-sdk.dev/docs/ai-sdk-core/telemetry) guide to configure tracing and control what context is recorded.

---

[View full KB sitemap](/kb/sitemap.md)
