ai-sdk-provider-claude-code 3.5.2 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -120
- package/dist/index.d.ts +236 -51
- package/dist/index.js +951 -223
- package/dist/index.js.map +1 -1
- package/docs/sessions.md +4 -4
- package/package.json +12 -14
- package/dist/index.cjs +0 -4025
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -1329
package/README.md
CHANGED
|
@@ -3,33 +3,34 @@
|
|
|
3
3
|
<a href="https://www.npmjs.com/package/ai-sdk-provider-claude-code"><img src="https://img.shields.io/npm/v/ai-sdk-provider-claude-code?color=00A79E" alt="npm version" /></a>
|
|
4
4
|
<a href="https://www.npmjs.com/package/ai-sdk-provider-claude-code"><img src="https://img.shields.io/npm/unpacked-size/ai-sdk-provider-claude-code?color=00A79E" alt="install size" /></a>
|
|
5
5
|
<a href="https://www.npmjs.com/package/ai-sdk-provider-claude-code"><img src="https://img.shields.io/npm/dy/ai-sdk-provider-claude-code.svg?color=00A79E" alt="npm downloads" /></a>
|
|
6
|
-
<a href="https://nodejs.org/en/about/releases/"><img src="https://img.shields.io/badge/node-%3E%
|
|
6
|
+
<a href="https://nodejs.org/en/about/releases/"><img src="https://img.shields.io/badge/node-%3E%3D22-00A79E" alt="Node.js ≥ 22" /></a>
|
|
7
7
|
<a href="https://www.npmjs.com/package/ai-sdk-provider-claude-code"><img src="https://img.shields.io/npm/l/ai-sdk-provider-claude-code?color=00A79E" alt="License: MIT" /></a>
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
10
|
# AI SDK Provider for Claude Agent SDK
|
|
11
11
|
|
|
12
|
-
> **Latest Release**: Version
|
|
12
|
+
> **Latest Release**: Version 4.x supports AI SDK v7 stable with the Claude Agent SDK. Version 3.x moves to maintenance for AI SDK v6 under the `ai-sdk-v6` tag.
|
|
13
13
|
|
|
14
14
|
**ai-sdk-provider-claude-code** lets you use Claude via the [Vercel AI SDK](https://sdk.vercel.ai/docs) through the official `@anthropic-ai/claude-agent-sdk` and the Claude Code CLI.
|
|
15
15
|
|
|
16
16
|
## Version Compatibility
|
|
17
17
|
|
|
18
|
-
| Provider Version | AI SDK Version | Underlying SDK
|
|
19
|
-
| ---------------- | -------------- |
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
23
|
-
|
|
|
18
|
+
| Provider Version | AI SDK Version | Underlying SDK | NPM Tag | Status | Branch |
|
|
19
|
+
| ---------------- | -------------- | -------------------------------- | -------------------- | ----------- | ----------- |
|
|
20
|
+
| 4.x.x | v7 | `@anthropic-ai/claude-agent-sdk` | `latest` | Stable | `main` |
|
|
21
|
+
| 3.x.x | v6 | `@anthropic-ai/claude-agent-sdk` | `ai-sdk-v6` | Maintenance | `ai-sdk-v6` |
|
|
22
|
+
| 2.x.x | v5 | `@anthropic-ai/claude-agent-sdk` | `ai-sdk-v5` | Legacy | `ai-sdk-v5` |
|
|
23
|
+
| 1.x.x | v5 | `@anthropic-ai/claude-code` | `v1-claude-code-sdk` | Legacy | `v1` |
|
|
24
|
+
| 0.x.x | v4 | `@anthropic-ai/claude-code` | `ai-sdk-v4` | Legacy | `ai-sdk-v4` |
|
|
24
25
|
|
|
25
26
|
Install commands for each line are listed under [Installation](#installation) below.
|
|
26
27
|
|
|
27
28
|
## Zod Compatibility
|
|
28
29
|
|
|
29
|
-
**
|
|
30
|
+
**The 4.x line requires Zod `^4.1.8`.** Version 3.x remains available for AI SDK v6 under the `ai-sdk-v6` tag.
|
|
30
31
|
|
|
31
32
|
```bash
|
|
32
|
-
npm install ai-sdk-provider-claude-code ai zod@^4.
|
|
33
|
+
npm install ai-sdk-provider-claude-code ai zod@^4.1.8
|
|
33
34
|
```
|
|
34
35
|
|
|
35
36
|
> **Note:** Zod 3 support was dropped in v3.2.0 due to the underlying `@anthropic-ai/claude-agent-sdk@0.2.x` requiring Zod 4. If you need Zod 3 support, use `ai-sdk-provider-claude-code@3.1.x`.
|
|
@@ -48,9 +49,11 @@ claude auth login
|
|
|
48
49
|
### 2. Add the provider
|
|
49
50
|
|
|
50
51
|
```bash
|
|
51
|
-
# For AI SDK
|
|
52
|
-
npm install ai-sdk-provider-claude-code ai
|
|
53
|
-
|
|
52
|
+
# For AI SDK v7 (4.x; current latest tag)
|
|
53
|
+
npm install ai-sdk-provider-claude-code ai
|
|
54
|
+
|
|
55
|
+
# For AI SDK v6 maintenance (3.x)
|
|
56
|
+
npm install ai-sdk-provider-claude-code@ai-sdk-v6 ai@^6.0.0
|
|
54
57
|
|
|
55
58
|
# For AI SDK v5
|
|
56
59
|
npm install ai-sdk-provider-claude-code@ai-sdk-v5 ai@^5.0.0
|
|
@@ -72,9 +75,26 @@ Please ensure you have appropriate permissions and comply with all applicable te
|
|
|
72
75
|
|
|
73
76
|
## Quick Start
|
|
74
77
|
|
|
75
|
-
### AI SDK
|
|
78
|
+
### AI SDK v7 (`latest`)
|
|
76
79
|
|
|
77
80
|
```typescript
|
|
81
|
+
// npm install ai-sdk-provider-claude-code ai
|
|
82
|
+
import { streamText } from 'ai';
|
|
83
|
+
import { claudeCode } from 'ai-sdk-provider-claude-code';
|
|
84
|
+
|
|
85
|
+
const result = streamText({
|
|
86
|
+
model: claudeCode('haiku'),
|
|
87
|
+
prompt: 'Hello, Claude!',
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const text = await result.text;
|
|
91
|
+
console.log(text);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### AI SDK v6 (maintenance)
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// npm install ai-sdk-provider-claude-code@ai-sdk-v6 ai@^6.0.0
|
|
78
98
|
import { streamText } from 'ai';
|
|
79
99
|
import { claudeCode } from 'ai-sdk-provider-claude-code';
|
|
80
100
|
|
|
@@ -105,6 +125,24 @@ console.log(text);
|
|
|
105
125
|
|
|
106
126
|
## Breaking Changes
|
|
107
127
|
|
|
128
|
+
### Version 4.0.0 (AI SDK v7)
|
|
129
|
+
|
|
130
|
+
This release ports the provider to AI SDK v7 / `LanguageModelV4`, adds first-class Claude Agent SDK callback, query-controller, MCP, and image support, and keeps the v7 support boundaries explicit:
|
|
131
|
+
|
|
132
|
+
- Requires Node.js ≥ 22 and Zod `^4.1.8`
|
|
133
|
+
- ESM-only package output; CommonJS `require()` is no longer available
|
|
134
|
+
- Tool failures now use spec `tool-result` parts/events with `isError: true` instead of the provider-specific `tool-error` stream extension
|
|
135
|
+
|
|
136
|
+
### Optional AI SDK v7 surfaces not implemented
|
|
137
|
+
|
|
138
|
+
Version 4.0.0 intentionally keeps optional provider surfaces absent unless the Claude Agent SDK has a durable provider-reference mapping:
|
|
139
|
+
|
|
140
|
+
- `ProviderV4.files()` is not implemented yet. The AI SDK interface uploads `{ type: 'data' }` or `{ type: 'text' }` bytes and returns a reusable provider reference, but Claude Agent SDK `0.3.205` exposes no direct upload/reuse API for that contract. This provider forwards inline **image** file parts in prompts; non-image inline files (for example PDFs) emit an unsupported-file call warning and are not forwarded. It does not upload files into durable provider references.
|
|
141
|
+
- Canonical V4 tool-result file parts are replayed into conversation history as text markers like `[File <name>: <mediaType>]`; raw file bytes are not re-sent on replay. Richer tool-result file replay, such as re-sending actual image/file bytes for tool-result file parts, is deferred.
|
|
142
|
+
- `ProviderV4.skills()` is not implemented yet. Claude Code skills are loaded from configured user/project/local skill directories with the existing `skills` setting below; there is no Agent SDK API that uploads a skill bundle and returns an AI SDK provider reference.
|
|
143
|
+
- Workflow serialization is deferred. `@ai-sdk/provider-utils@5.0.5` exposes `WORKFLOW_SERIALIZE`, `WORKFLOW_DESERIALIZE`, and `serializeModelOptions()` for provider model classes in the AI SDK v7 stack, but this provider has not added a serialization contract for provider instances or settings. Callback/function settings such as `canUseTool`, hooks, `logger`, `spawnClaudeCodeProcess`, and `SessionStore` methods are not JSON-serializable and must be recreated by the application.
|
|
144
|
+
- V4 `custom` and `reasoning-file` parts are not emitted as provider output yet. Claude Agent SDK `0.3.205` has no durable reasoning-file artifact output that maps to AI SDK `reasoning-file`; assistant-history `custom` and `reasoning-file` parts have no Claude Code replay representation and are skipped (unknown unsupported content variants still warn).
|
|
145
|
+
|
|
108
146
|
### Version 3.0.0 (AI SDK v6 Stable)
|
|
109
147
|
|
|
110
148
|
This version upgrades to AI SDK v6 stable with updated provider types:
|
|
@@ -133,11 +171,12 @@ Key changes:
|
|
|
133
171
|
|
|
134
172
|
## Models
|
|
135
173
|
|
|
136
|
-
- **`
|
|
174
|
+
- **`fable`** - Claude Fable (most capable)
|
|
175
|
+
- **`opus`** - Claude Opus (highly capable)
|
|
137
176
|
- **`sonnet`** - Claude Sonnet (balanced performance)
|
|
138
177
|
- **`haiku`** - Claude Haiku (fastest, most cost-effective)
|
|
139
178
|
|
|
140
|
-
You can also use full model identifiers directly (e.g., `claude-sonnet-4-6`, `claude-opus-4-8`).
|
|
179
|
+
You can also use full model identifiers directly (e.g., `claude-fable-5`, `claude-sonnet-4-6`, `claude-opus-4-8`).
|
|
141
180
|
|
|
142
181
|
## Documentation
|
|
143
182
|
|
|
@@ -193,7 +232,7 @@ claude auth login
|
|
|
193
232
|
|
|
194
233
|
If you're upgrading from version 1.x:
|
|
195
234
|
|
|
196
|
-
1. **Update the package**: `npm install ai-sdk-provider-claude-code@
|
|
235
|
+
1. **Update the package**: `npm install ai-sdk-provider-claude-code@ai-sdk-v5`
|
|
197
236
|
2. **If you relied on default system prompt or CLAUDE.md**, add explicit configuration:
|
|
198
237
|
```ts
|
|
199
238
|
const model = claudeCode('sonnet', {
|
|
@@ -212,37 +251,41 @@ If you're upgrading from version 1.x:
|
|
|
212
251
|
|
|
213
252
|
## Structured Outputs
|
|
214
253
|
|
|
215
|
-
This provider supports **native structured outputs** via
|
|
254
|
+
This provider supports **native structured outputs** via Claude Agent SDK constrained decoding. On the 4.x line (AI SDK v7), use `generateText()` with an `output` specification such as `Output.object({ schema })`, then destructure `output` from the result. For streaming structured output, use `streamText()` with the same `output` setting and read `partialOutputStream` as partial objects arrive.
|
|
216
255
|
|
|
217
256
|
```typescript
|
|
218
|
-
import {
|
|
257
|
+
import { generateText, Output } from 'ai';
|
|
219
258
|
import { claudeCode } from 'ai-sdk-provider-claude-code';
|
|
220
259
|
import { z } from 'zod';
|
|
221
260
|
|
|
222
|
-
const
|
|
261
|
+
const UserProfileSchema = z.object({
|
|
262
|
+
name: z.string(),
|
|
263
|
+
age: z.number(),
|
|
264
|
+
email: z.string().describe('Email address (validate client-side)'),
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
const { output } = await generateText({
|
|
223
268
|
model: claudeCode('sonnet'),
|
|
224
|
-
|
|
225
|
-
name: z.string(),
|
|
226
|
-
age: z.number(),
|
|
227
|
-
email: z.string().describe('Email address (validate client-side)'),
|
|
228
|
-
}),
|
|
269
|
+
output: Output.object({ schema: UserProfileSchema }),
|
|
229
270
|
prompt: 'Generate a user profile for a software developer',
|
|
230
271
|
});
|
|
231
272
|
|
|
232
|
-
console.log(
|
|
273
|
+
console.log(output); // Matches the schema above
|
|
233
274
|
// { name: "Alex Chen", age: 28, email: "alex@example.com" }
|
|
234
275
|
```
|
|
235
276
|
|
|
236
277
|
**Benefits:**
|
|
237
278
|
|
|
238
279
|
- ✅ **Schema compliance (supported features)** - Constrained decoding ensures valid output
|
|
239
|
-
- ✅ **No JSON parsing errors** - SDK handles
|
|
280
|
+
- ✅ **No JSON parsing errors** - AI SDK handles validation against your schema
|
|
240
281
|
- ✅ **No prompt engineering** - Schema enforcement is native to the SDK
|
|
241
282
|
- ✅ **Better performance** - No retry/extraction logic needed
|
|
242
283
|
|
|
243
|
-
> **Note:**
|
|
284
|
+
> **Note:** Schema-less JSON output (AI SDK v7 `Output.json()`) is not supported by Claude Code; use `Output.object()` / `Output.array()` / `Output.choice()` with a schema or choices. The provider emits a V4 `unsupported` warning with `feature: 'responseFormat'` and treats the call as plain text.
|
|
285
|
+
>
|
|
286
|
+
> **Current CLI limitation:** Some JSON Schema features can cause the Claude Code CLI to silently fall back to prose (no `structured_output`). The provider mitigates the most common case: `format` keywords (`date-time`, `email`, `uri`, `uuid`, ... — produced by Zod's `.datetime()`, `.email()`, `.url()`, `.uuid()`) are stripped client-side before the schema is sent, with the hint folded into the field's `description` (e.g., `(expected format: email)`). Server-side enforcement of `format` still does not exist in the CLI, but the AI SDK validates `output` against your original Zod schema client-side, so nothing is lost. Complex regex `pattern`s (lookaheads/backreferences) remain unmitigated — `pattern` is passed through untouched because the CLI genuinely rejects some patterns. Keep generation schemas simple and enforce stricter invariants after generation.
|
|
244
287
|
>
|
|
245
|
-
>
|
|
288
|
+
> If you are staying on the 3.x (AI SDK v6) line, its legacy structured-output examples may still use `generateObject()` / `streamObject()`; new 4.x code should use `generateText()` / `streamText()` with `Output`.
|
|
246
289
|
|
|
247
290
|
## Core Features
|
|
248
291
|
|
|
@@ -252,44 +295,56 @@ console.log(result.object); // Matches the schema above
|
|
|
252
295
|
- 🎯 Native structured outputs with schema compliance for supported features
|
|
253
296
|
- 🛑 AbortSignal support
|
|
254
297
|
- 🔧 Tool management (MCP servers, permissions)
|
|
255
|
-
- 🧩 Callbacks (
|
|
298
|
+
- 🧩 Callbacks (`onSdkMessage`, task/hook/MCP status events, `canUseTool`, `onElicitation`)
|
|
299
|
+
- 🎛️ Query controller access for safe live-session controls
|
|
300
|
+
|
|
301
|
+
## AI SDK v7 app-level features
|
|
302
|
+
|
|
303
|
+
DevTools and OpenTelemetry/OTel telemetry registration are app-level `ai` package features. This provider exposes standard AI SDK v7 metadata and stream parts for them, but adds no runtime dependencies for DevTools or OTel.
|
|
256
304
|
|
|
257
305
|
## Agent SDK Options (Advanced)
|
|
258
306
|
|
|
259
307
|
This provider exposes Agent SDK options directly. Key options include:
|
|
260
308
|
|
|
261
|
-
| Option | Description
|
|
262
|
-
| --------------------------------- |
|
|
263
|
-
| `betas` | Enable beta features (e.g., `['context-1m-2025-08-07']`)
|
|
264
|
-
| `sandbox` | Configure sandbox behavior (`{ enabled: true }`). Cannot be combined with a `settings` file path (inline `settings` objects are fine)
|
|
265
|
-
| `plugins` | Load custom plugins from local paths
|
|
266
|
-
| `resumeSessionAt` | Resume session at a specific message UUID
|
|
267
|
-
| `enableFileCheckpointing` | Enable file rewind support
|
|
268
|
-
| `maxBudgetUsd` | Maximum budget in USD for the query
|
|
269
|
-
| `tools` | Tool configuration (array of names or preset)
|
|
270
|
-
| `allowDangerouslySkipPermissions` | Allow bypassing permissions
|
|
271
|
-
| `persistSession` | When `false`, disables session persistence to disk (v3.2.0+)
|
|
272
|
-
| `spawnClaudeCodeProcess` | Custom process spawner for VMs/containers (v3.2.0+)
|
|
273
|
-
| `permissionMode` | Permission mode: `'default'`, `'acceptEdits'`, `'bypassPermissions'`, `'plan'`, `'dontAsk'`, `'auto'` (`'auto'` and `'dontAsk'` added in SDK 0.3.x; `'delegate'` was removed in SDK 0.3.x and the CLI rejects it, so the provider rejects it at validation time)
|
|
274
|
-
| `sessionId` | Use a specific session ID for deterministic tracking and correlation (v3.4.0+). Must be a valid UUID; cannot be combined with `continue`/`resume` unless `forkSession` is also set
|
|
275
|
-
| `debug` | Enable programmatic debug logging from the SDK (v3.4.0+)
|
|
276
|
-
| `debugFile` | Path to a file for SDK debug log output (v3.4.0+)
|
|
277
|
-
| `effort` | Effort level: `'low'`, `'medium'`, `'high'`, `'xhigh'`, or `'max'`
|
|
278
|
-
| `thinking` | Thinking config: `{ type: 'adaptive' }`, `{ type: 'enabled', budgetTokens?: number }`, or `{ type: 'disabled' }`
|
|
279
|
-
| `promptSuggestions` | Enable prompt suggestions (`boolean`)
|
|
280
|
-
| `skills` | Enable skills for the session: `'all'` or an array of skill names (v3.5.0+)
|
|
281
|
-
| `settings` | Inline `Settings` object or path to a settings JSON file (v3.5.0+)
|
|
282
|
-
| `managedSettings` | Restrictive policy-tier settings enforced on the subprocess (v3.5.0+)
|
|
283
|
-
| `toolAliases` | Map built-in tool names to replacement tools, e.g. `{ Bash: 'mcp__workspace__bash' }` (v3.5.0+)
|
|
284
|
-
| `toolConfig` | Per-tool configuration for built-in tools, e.g. `{ askUserQuestion: { previewFormat: 'html' } }` (v3.5.0+)
|
|
285
|
-
| `planModeInstructions` | Custom workflow instructions for plan mode (v3.5.0+)
|
|
286
|
-
| `title` | Custom title for a new session (v3.5.0+)
|
|
287
|
-
| `forwardSubagentText` | Forward subagent text/thinking blocks for nested transcripts (v3.5.0+)
|
|
288
|
-
| `agentProgressSummaries` | Periodic AI-generated progress summaries for running subagents (v3.5.0+)
|
|
289
|
-
| `includeHookEvents` | Include hook lifecycle events in the output stream (v3.5.0+)
|
|
290
|
-
| `fallbackModel` | Fallback model(s) if the primary is overloaded — accepts a comma-separated list to try in order. Must differ from the main model
|
|
291
|
-
| `onUserDialog` | Callback rendering blocking CLI dialogs (`request_user_dialog`); see **User dialogs** below
|
|
292
|
-
| `supportedDialogKinds` | Dialog kinds your `onUserDialog` can render; required for dialogs to be emitted at all
|
|
309
|
+
| Option | Description |
|
|
310
|
+
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
311
|
+
| `betas` | Enable beta features (e.g., `['context-1m-2025-08-07']`) |
|
|
312
|
+
| `sandbox` | Configure sandbox behavior (`{ enabled: true }`). Cannot be combined with a `settings` file path (inline `settings` objects are fine) |
|
|
313
|
+
| `plugins` | Load custom plugins from local paths |
|
|
314
|
+
| `resumeSessionAt` | Resume session at a specific message UUID |
|
|
315
|
+
| `enableFileCheckpointing` | Enable file rewind support |
|
|
316
|
+
| `maxBudgetUsd` | Maximum budget in USD for the query |
|
|
317
|
+
| `tools` | Tool configuration (array of names or preset) |
|
|
318
|
+
| `allowDangerouslySkipPermissions` | Allow bypassing permissions |
|
|
319
|
+
| `persistSession` | When `false`, disables session persistence to disk (v3.2.0+) |
|
|
320
|
+
| `spawnClaudeCodeProcess` | Custom process spawner for VMs/containers (v3.2.0+) |
|
|
321
|
+
| `permissionMode` | Permission mode: `'default'`, `'acceptEdits'`, `'bypassPermissions'`, `'plan'`, `'dontAsk'`, `'auto'` (`'auto'` and `'dontAsk'` added in SDK 0.3.x; `'delegate'` was removed in SDK 0.3.x and the CLI rejects it, so the provider rejects it at validation time) |
|
|
322
|
+
| `sessionId` | Use a specific session ID for deterministic tracking and correlation (v3.4.0+). Must be a valid UUID; cannot be combined with `continue`/`resume` unless `forkSession` is also set |
|
|
323
|
+
| `debug` | Enable programmatic debug logging from the SDK (v3.4.0+) |
|
|
324
|
+
| `debugFile` | Path to a file for SDK debug log output (v3.4.0+) |
|
|
325
|
+
| `effort` | Effort level: `'low'`, `'medium'`, `'high'`, `'xhigh'`, or `'max'` |
|
|
326
|
+
| `thinking` | Thinking config: `{ type: 'adaptive' }`, `{ type: 'enabled', budgetTokens?: number }`, or `{ type: 'disabled' }` |
|
|
327
|
+
| `promptSuggestions` | Enable prompt suggestions (`boolean`) |
|
|
328
|
+
| `skills` | Enable skills for the session: `'all'` or an array of skill names (v3.5.0+) |
|
|
329
|
+
| `settings` | Inline `Settings` object or path to a settings JSON file (v3.5.0+) |
|
|
330
|
+
| `managedSettings` | Restrictive policy-tier settings enforced on the subprocess (v3.5.0+) |
|
|
331
|
+
| `toolAliases` | Map built-in tool names to replacement tools, e.g. `{ Bash: 'mcp__workspace__bash' }` (v3.5.0+) |
|
|
332
|
+
| `toolConfig` | Per-tool configuration for built-in tools, e.g. `{ askUserQuestion: { previewFormat: 'html' } }` (v3.5.0+) |
|
|
333
|
+
| `planModeInstructions` | Custom workflow instructions for plan mode (v3.5.0+) |
|
|
334
|
+
| `title` | Custom title for a new session (v3.5.0+) |
|
|
335
|
+
| `forwardSubagentText` | Forward subagent text/thinking blocks for nested transcripts (v3.5.0+) |
|
|
336
|
+
| `agentProgressSummaries` | Periodic AI-generated progress summaries for running subagents (v3.5.0+) |
|
|
337
|
+
| `includeHookEvents` | Include hook lifecycle events in the output stream (v3.5.0+) |
|
|
338
|
+
| `fallbackModel` | Fallback model(s) if the primary is overloaded — accepts a comma-separated list to try in order. Must differ from the main model |
|
|
339
|
+
| `onUserDialog` | Callback rendering blocking CLI dialogs (`request_user_dialog`); see **User dialogs** below |
|
|
340
|
+
| `supportedDialogKinds` | Dialog kinds your `onUserDialog` can render; required for dialogs to be emitted at all |
|
|
341
|
+
| `onSdkMessage` | Raw callback for every observed Agent SDK `SDKMessage`; useful for future SDK message types and custom telemetry |
|
|
342
|
+
| `onTaskEvent` | Callback for task/subagent lifecycle events (`ClaudeCodeTaskEvent`); also accumulated in `providerMetadata['claude-code'].taskEvents` when present |
|
|
343
|
+
| `onHookEvent` | Callback for hook lifecycle events (`ClaudeCodeHookEvent`); set `includeHookEvents: true` when you want the SDK to emit hook started/progress/response messages |
|
|
344
|
+
| `onMcpStatusChange` | Callback for the initial MCP status snapshot observed from the SDK init message (`ClaudeCodeMcpStatusEvent`); the same request-time snapshot is surfaced in `providerMetadata['claude-code'].mcpServers` when available. For live status after runtime MCP changes, use `controller.mcpServerStatus()` while the query is live and SDK streaming input/output is active |
|
|
345
|
+
| `onElicitation` | First-class Agent SDK `OnElicitation` callback for MCP elicitation requests (form fields, URL auth, or other server-requested input) |
|
|
346
|
+
| `agent` | Select a named Claude Code agent persona for the main thread. Use intentionally: a configured agent can carry its own prompt/tool/model policy, separate from the AI SDK call's prompt/model surface |
|
|
347
|
+
| `onQueryControllerCreated` | Callback receiving a `ClaudeCodeQueryController` for safe live-query controls. Control-protocol methods require a live SDK `Query`, and most require SDK streaming input/output; `controller.rawQuery` remains available when you need the raw SDK `Query` |
|
|
293
348
|
|
|
294
349
|
**System prompt** (`systemPrompt`) accepts a string, a string array, or the Claude Code preset object (v3.5.0+ for the array form). In the array form, include the re-exported `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` marker as a standalone element to split the static (cross-session cacheable) prefix from the dynamic suffix. The preset object additionally accepts `excludeDynamicSections: true` to strip per-user dynamic sections (working directory, git status) so the prompt caches across users.
|
|
295
350
|
|
|
@@ -301,6 +356,8 @@ This provider exposes Agent SDK options directly. Key options include:
|
|
|
301
356
|
|
|
302
357
|
**Alpha options** (v3.5.0+, marked `@alpha` upstream and subject to change): `taskBudget` (`{ total: number }` API-side token budget), `sessionStore` (mirror session transcripts to a custom storage adapter; the provider rejects combining it with `persistSession: false` or `enableFileCheckpointing: true`, and `continue: true` without a `resume` ID requires the store to implement `listSessions()`), `sessionStoreFlush` (`'batched'` or `'eager'`), and `loadTimeoutMs` (resume-load timeout). The SDK's `InMemorySessionStore` reference implementation and the `SessionStore`/`SessionStoreFlush` types are re-exported.
|
|
303
358
|
|
|
359
|
+
The package also re-exports SDK helper functions/types used by advanced hosts: `resolveSettings`, `filterEscalatingDefaultMode`, `SandboxCredentialsConfig`, and `SDKFilesPersistedEvent` in addition to the session, hook, MCP, permission, and warm-start exports documented below.
|
|
360
|
+
|
|
304
361
|
### User dialogs (`onUserDialog` / `supportedDialogKinds`)
|
|
305
362
|
|
|
306
363
|
Some CLI flows ask the host to render a blocking dialog (a `request_user_dialog` control request) — for example `'refusal_fallback_prompt'`, which asks whether to retry a refused request differently. The SDK **fails closed** here: a dialog kind not declared in `supportedDialogKinds` is never emitted, and the flow behind it degrades to its no-dialog behavior (for `'refusal_fallback_prompt'`, the classic refusal error ends the turn). Providing `onUserDialog` alone does NOT opt you in — both options are required, and passing a non-empty `supportedDialogKinds` without the callback throws at SDK option intake, so the provider **rejects** that combination at validation time (`createClaudeCode`/model construction throws `Invalid settings`).
|
|
@@ -323,9 +380,11 @@ const model = claudeCode('sonnet', {
|
|
|
323
380
|
|
|
324
381
|
The `OnUserDialog`, `UserDialogRequest`, and `UserDialogResult` types are re-exported. Note that `UserDialogResult.result` is typed `unknown` — the CLI validates it against the dialog kind's own result schema at runtime, and a result that doesn't match (e.g. the wrong shape or an unknown string) is **silently** replaced by the dialog's default (for `'refusal_fallback_prompt'`, `'cancelled'`), so double-check the result values for each kind you handle.
|
|
325
382
|
|
|
326
|
-
### Permission decisions (`canUseTool`
|
|
383
|
+
### Permission decisions (`canUseTool`, `permissionMode`, and AI SDK `toolApproval`)
|
|
327
384
|
|
|
328
|
-
SDK 0.3.x enriched the `canUseTool` callback (no provider change needed — these arrive on the existing `options` argument):
|
|
385
|
+
SDK 0.3.x enriched the Claude Agent SDK `canUseTool` callback (no provider change needed — these arrive on the existing `options` argument):
|
|
386
|
+
|
|
387
|
+
AI SDK v7 `toolApproval` is **not** bridged to Claude Code's internal tool permission system. Use Claude Agent SDK `canUseTool` / `permissionMode` for Claude Code built-in and MCP tools; call-level `toolApproval` on `generateText`/`streamText` applies to app-level AI SDK tools handled by the `ai` package.
|
|
329
388
|
|
|
330
389
|
- `title` — full permission prompt sentence (e.g. "Claude wants to read foo.txt"); prefer it over reconstructing from `toolName` + input
|
|
331
390
|
- `displayName` — short noun phrase for the tool action (e.g. "Read file"), suitable for button labels
|
|
@@ -352,7 +411,39 @@ const model = claudeCode('sonnet', {
|
|
|
352
411
|
> **Upstream CLI caveats (verified on CLI 2.1.172):**
|
|
353
412
|
>
|
|
354
413
|
> - A `PreToolUse` hook returning `permissionDecision: 'defer'` combined with a `canUseTool` callback fails the tool call **before** `canUseTool` is ever consulted. When `canUseTool` should handle the call, have the hook return no decision (or `'allow'`) instead of `'defer'`.
|
|
355
|
-
> - The `PermissionDenied` hook only fires for CLI-internal auto-mode classifier denials (e.g. `permissionMode: 'auto'`). Denials issued by `canUseTool` do **not** trigger it — they surface via the result message's `permission_denials`, which the provider merges into `providerMetadata['claude-code'].permissionDenials`.
|
|
414
|
+
> - The `PermissionDenied` hook only fires for CLI-internal auto-mode classifier denials (e.g. `permissionMode: 'auto'`). Denials issued by `canUseTool` do **not** trigger it — they surface via the result message's `permission_denials`, which the provider merges into `finalStep.providerMetadata['claude-code'].permissionDenials`.
|
|
415
|
+
|
|
416
|
+
### Agent SDK event callbacks (`onSdkMessage`, task/hook/MCP status, elicitation)
|
|
417
|
+
|
|
418
|
+
Use these callbacks when you need Agent SDK observability without parsing AI SDK stream parts yourself:
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
const model = claudeCode('sonnet', {
|
|
422
|
+
onSdkMessage: (message) => {
|
|
423
|
+
console.debug('raw SDK message:', message.type);
|
|
424
|
+
},
|
|
425
|
+
onTaskEvent: (event) => {
|
|
426
|
+
console.debug('task event:', event.subtype);
|
|
427
|
+
},
|
|
428
|
+
includeHookEvents: true,
|
|
429
|
+
onHookEvent: (event) => {
|
|
430
|
+
console.debug('hook event:', event.subtype);
|
|
431
|
+
},
|
|
432
|
+
onMcpStatusChange: (status) => {
|
|
433
|
+
console.debug('MCP init status snapshot:', status);
|
|
434
|
+
},
|
|
435
|
+
onElicitation: async (request) => {
|
|
436
|
+
return renderMcpElicitation(request);
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
- `onSdkMessage` receives the raw `SDKMessage` objects the provider observes. Prefer this when you want to preserve new or rare SDK messages without waiting for provider-specific metadata.
|
|
442
|
+
- `onTaskEvent` receives normalized task/subagent events and the same objects are collected into `providerMetadata['claude-code'].taskEvents` when any fire during the request.
|
|
443
|
+
- `onHookEvent` receives normalized hook lifecycle events; because the underlying SDK only emits hook lifecycle messages when requested, pair it with `includeHookEvents: true`.
|
|
444
|
+
- `onMcpStatusChange` receives the initial MCP server status snapshot observed during the request; final metadata includes that same request-time `mcpServers` snapshot when available. For live status after `reconnectMcpServer()`, `toggleMcpServer()`, or `setMcpServers()`, call `controller.mcpServerStatus()` while the query is live and SDK streaming input/output is active.
|
|
445
|
+
- `onElicitation` is the first-class Agent SDK `OnElicitation` hook. It is for MCP-server-requested input; if you do not provide it, unhandled elicitation requests follow the SDK's default decline/cancel behavior.
|
|
446
|
+
- `agent` selects a named Claude Code agent for the main thread. This is different from `agents` (which defines subagents). Use it only when you want the named agent's configured prompt/tools/model behavior to participate in the main request.
|
|
356
447
|
|
|
357
448
|
See [`ClaudeCodeSettings`](https://github.com/ben-vargas/ai-sdk-provider-claude-code/blob/main/src/types.ts) for the full list of supported options (e.g., `allowedTools`, `disallowedTools`, `hooks`, `canUseTool`, `env`, `settingSources`).
|
|
358
449
|
|
|
@@ -373,22 +464,17 @@ const model = claudeCode('sonnet', {
|
|
|
373
464
|
});
|
|
374
465
|
```
|
|
375
466
|
|
|
376
|
-
###
|
|
377
|
-
|
|
378
|
-
A few Agent SDK surfaces are deliberately not wrapped by this provider. A compile-time drift guard (`src/options-coverage.test.ts`) keeps this list exhaustive: every SDK `Options` field is either mapped, provider-managed, or consciously listed below.
|
|
467
|
+
### SDK boundaries
|
|
379
468
|
|
|
380
|
-
|
|
469
|
+
**Provider-managed fields** are set internally and ignored if passed via `sdkOptions`: `model`, `abortController`, `prompt`, and `outputFormat`.
|
|
381
470
|
|
|
382
|
-
|
|
383
|
-
- `onElicitation` — an interactive host-UI callback for MCP elicitation requests (form fields, URL auth). Headless AI SDK usage has no dialog surface, and the SDK safely auto-declines unhandled requests.
|
|
384
|
-
|
|
385
|
-
**Provider-managed fields** that are set internally and ignored if passed via `sdkOptions`: `model`, `abortController`, `prompt`, and `outputFormat`.
|
|
471
|
+
`agent` and `onElicitation` are first-class `ClaudeCodeSettings` fields on the 4.x line. Older 3.x docs described them as `sdkOptions` escape hatches; use the direct settings names in new code.
|
|
386
472
|
|
|
387
473
|
**Alternate SDK entry points** — the Agent SDK also ships `/browser` (WebSocket browser transport), `/bridge` (remote-control session transport), and `/assistant` (worker/daemon harness) entry points. These are alpha surfaces with their own versioning cadence and are aimed at embedding hosts rather than AI SDK consumers, so this provider does not re-export them. Import them directly from `@anthropic-ai/claude-agent-sdk/<entry>` if you need them, with the usual alpha-stability caveats.
|
|
388
474
|
|
|
389
475
|
## Claude Agent SDK 0.3.x Notes
|
|
390
476
|
|
|
391
|
-
This provider depends on `@anthropic-ai/claude-agent-sdk
|
|
477
|
+
This provider depends on `@anthropic-ai/claude-agent-sdk@0.3.205` (exact pin). The pin is exact rather than a caret because upstream releases have shipped broken `sdk.d.ts` declarations before (0.3.198–0.3.202 collapsed `SDKMessage` to `any`, fixed in 0.3.203); the weekly canary gates each pin move. The 0.3.x line introduces a few changes worth knowing about:
|
|
392
478
|
|
|
393
479
|
### New peer dependencies
|
|
394
480
|
|
|
@@ -450,7 +536,7 @@ for await (const chunk of result.textStream) {
|
|
|
450
536
|
|
|
451
537
|
**Requirements:**
|
|
452
538
|
|
|
453
|
-
- `streamingInput: 'always'` or `'auto'` with `canUseTool` set
|
|
539
|
+
- `streamingInput: 'always'` or `'auto'` with `canUseTool` set; image parts also auto-enable SDK streaming input under `'auto'`
|
|
454
540
|
- Messages injected via `inject(content)` are delivered to the agent mid-turn
|
|
455
541
|
|
|
456
542
|
**Important:** Injection works between tool calls, not during continuous text generation. Use tasks that involve tool usage (file operations, bash commands, etc.) for effective mid-turn interruption.
|
|
@@ -480,14 +566,14 @@ injector.inject('STOP!', (delivered) => {
|
|
|
480
566
|
|
|
481
567
|
See [examples/message-injection.ts](examples/message-injection.ts) for complete examples including conditional injection and supervisor approval patterns.
|
|
482
568
|
|
|
483
|
-
## Image Inputs
|
|
569
|
+
## Image Inputs
|
|
484
570
|
|
|
485
|
-
-
|
|
486
|
-
- Supported payloads
|
|
571
|
+
- With `streamingInput: 'auto'` (the default), supported image prompts automatically enable the Agent SDK streaming-input path for that request; you no longer need to set `streamingInput: 'always'` just to send images.
|
|
572
|
+
- Supported payloads include data URLs (`data:image/png;base64,...`), strings prefixed with `base64:<mediaType>,<data>`, or AI SDK v7 file parts such as `{ type: 'file', data: { type: 'data', data: '<base64>' }, mediaType: 'image/png' }` (use `mediaType`, not `mimeType`).
|
|
487
573
|
- Remote HTTP(S) image URLs are ignored with the warning "Image URLs are not supported by this provider; supply base64/data URLs." (`supportsImageUrls` remains `false`).
|
|
488
|
-
-
|
|
574
|
+
- `streamingInput: 'off'` remains an explicit opt-out: image prompts skip the streaming-input path, image parts are omitted, and the provider emits a generic `type: 'other'` image streaming-input warning.
|
|
489
575
|
- Use realistic image payloads—very small placeholders may result in the model asking for a different image.
|
|
490
|
-
- `examples/images.ts` accepts a local image path
|
|
576
|
+
- `examples/images.ts` accepts a local image path, reads its bytes, and builds an AI SDK v7 file part: `npx tsx examples/images.ts /absolute/path/to/image.png`.
|
|
491
577
|
|
|
492
578
|
## Skills Support
|
|
493
579
|
|
|
@@ -536,7 +622,7 @@ See [examples/skills-management.ts](examples/skills-management.ts) for more exam
|
|
|
536
622
|
|
|
537
623
|
## Using AI SDK Tools
|
|
538
624
|
|
|
539
|
-
The Claude Code CLI executes its own tools, so AI SDK tools passed to `generateText`/`streamText` via the `tools` option are ignored (with an `unsupported` warning). Automatic bridging is impossible by design: at the `
|
|
625
|
+
The Claude Code CLI executes its own tools, so AI SDK tools passed to `generateText`/`streamText` via the `tools` option are ignored (with an `unsupported` warning). Automatic bridging is impossible by design: at the `LanguageModelV4` layer the provider only receives tool _declarations_ (name, description, JSON schema) — the `execute` functions live in the `ai` package layer and never reach any provider.
|
|
540
626
|
|
|
541
627
|
Instead, bridge your tools explicitly with the `createAiSdkMcpServer` helper, which turns a map of AI SDK tools into an in-process MCP server that the CLI can call:
|
|
542
628
|
|
|
@@ -567,6 +653,7 @@ Notes:
|
|
|
567
653
|
|
|
568
654
|
- Each tool's `execute` runs in your process; string results pass through as MCP text content, everything else is `JSON.stringify`'d, and thrown errors become `isError` tool results instead of crashing the CLI session. Results that cannot be serialized to JSON (e.g. circular objects) also become `isError` results with a serialization message.
|
|
569
655
|
- Tool calls/results surface to the AI SDK as **provider-executed dynamic tool parts** (`tool-call`/`tool-result` with `mcp__<serverName>__<toolName>` names), not as executions of your local `tools` option.
|
|
656
|
+
- AI SDK v7 `toolApproval` is call-level approval for app-level AI SDK tools. Once a tool is exposed to Claude Code as MCP, approve or deny it with Claude Agent SDK controls (`canUseTool`, `permissionMode`, `allowedTools`, `disallowedTools`).
|
|
570
657
|
- Only **Zod object schemas** are supported (`z.object({...})`, the same schema you pass to the AI SDK `tool()` helper). Tools defined with the AI SDK's `jsonSchema()` helper are rejected at creation time because the Agent SDK's `tool()` requires a Zod shape.
|
|
571
658
|
- **Validation scope:** the Agent SDK's `tool()` takes only the schema _shape_ and validates incoming args field-by-field (running field-level validation and transforms, and stripping unknown keys) before `execute` runs. Object-level constructs — `.refine()`/`.superRefine()` (cross-field invariants) and `.strict()`/`.passthrough()`/`.catchall()` (unknown-key modes) — are **not** enforced by the bridge: re-parsing on top of the SDK's output would re-run transforms and reject valid transform schemas (e.g. `z.string().transform(v => v.length)`). Perform cross-field and unknown-key checks inside `execute`.
|
|
572
659
|
- Tools without an `execute` function (client-executed tools) are rejected at creation time.
|
|
@@ -576,7 +663,7 @@ See [examples/ai-sdk-tools.ts](examples/ai-sdk-tools.ts) for a runnable example
|
|
|
576
663
|
|
|
577
664
|
## Session Management
|
|
578
665
|
|
|
579
|
-
Every request runs as a Claude Code session, persisted under `~/.claude/projects/` by default
|
|
666
|
+
Every request runs as a Claude Code session, persisted under `~/.claude/projects/` by default. In AI SDK v7, read the session ID from `finalStep.providerMetadata['claude-code'].sessionId` (`result.finalStep` for `generateText`, or `await stream.finalStep` for `streamText`). Sessions can be resumed (`resume`), forked (`forkSession`), pinned to a deterministic ID (`sessionId`), titled (`title`), or kept ephemeral (`persistSession: false`). The provider also re-exports the SDK's session lifecycle helpers — `listSessions()`, `getSessionMessages()`, `forkSession()`, `getSessionInfo()`, `renameSession()`, `tagSession()`, `deleteSession()`, `listSubagents()`, `getSubagentMessages()`, `importSessionToStore()`, and `foldSessionSummary()` — for managing stored sessions outside of a query.
|
|
580
667
|
|
|
581
668
|
See [docs/sessions.md](docs/sessions.md) for the full guide (settings vs helpers, disk storage vs custom `SessionStore`, `title` vs `renameSession()`), and [examples/session-management.ts](examples/session-management.ts) for a runnable walkthrough (`npm run example:sessions`).
|
|
582
669
|
|
|
@@ -605,22 +692,25 @@ for await (const message of warm.query('Summarize the latest deploy log.')) {
|
|
|
605
692
|
// await using warm = ... // WarmQuery is AsyncDisposable
|
|
606
693
|
```
|
|
607
694
|
|
|
608
|
-
All requests made through this provider report timing in `providerMetadata['claude-code']` (`ttftMs`, `ttftStreamMs`, `timeToRequestMs`), plus `warmSpareClaimed` when the SDK reports whether the query was served from a pre-warmed spare process (surfaced as `true` or `false` whenever reported) — use these to measure whether warm-start plumbing is worth it for your workload.
|
|
695
|
+
All requests made through this provider report timing in `finalStep.providerMetadata['claude-code']` (`ttftMs`, `ttftStreamMs`, `timeToRequestMs`), plus `warmSpareClaimed` when the SDK reports whether the query was served from a pre-warmed spare process (surfaced as `true` or `false` whenever reported; use `await stream.finalStep` after `streamText`) — use these to measure whether warm-start plumbing is worth it for your workload.
|
|
609
696
|
|
|
610
697
|
## Limitations
|
|
611
698
|
|
|
612
|
-
- Requires Node.js ≥
|
|
613
|
-
-
|
|
699
|
+
- Requires Node.js ≥ 22
|
|
700
|
+
- With `streamingInput: 'auto'`, image inputs auto-enable streaming input for supported base64/data/file-part payloads, but remote image URLs are still not fetched by this provider
|
|
701
|
+
- `ProviderV4.files()` / FilesV4 upload is not implemented: inline file/image data is supported where Claude Code can represent it, but the provider does not create durable AI SDK provider-reference uploads
|
|
702
|
+
- `ProviderV4.skills()` / SkillsV4 upload is not implemented: Claude Code skills still come from configured user/project/local skill directories via the `skills` / `settingSources` options
|
|
703
|
+
- Workflow serialization remains deferred; callback/function settings such as `canUseTool`, hooks, `onSdkMessage`, `onElicitation`, `logger`, `spawnClaudeCodeProcess`, and `SessionStore` methods must be reconstructed by the application
|
|
614
704
|
- Some AI SDK parameters are unsupported and ignored with an `unsupported` warning: `temperature`, `topP`, `topK`, `presencePenalty`, `frequencyPenalty`, `stopSequences`, `seed`, and `maxOutputTokens` (the CLI does not accept an output token cap)
|
|
615
|
-
- AI SDK `tools
|
|
705
|
+
- AI SDK `tools`, `toolChoice` (other than `'auto'`), and call-level `toolApproval` do not approve Claude Code internal built-in/MCP tools. To expose custom tools to the CLI, bridge them with the `createAiSdkMcpServer` helper and pass the result via the `mcpServers` setting (plus `allowedTools`); approve or deny Claude Code tools with `canUseTool`, `permissionMode`, `allowedTools`, and `disallowedTools`
|
|
616
706
|
- When replaying conversation history through the prompt, assistant tool calls are serialized as text lines — `[Tool call: Read({"file_path":"/x"})]` (inputs truncated at 1000 characters) — paired with `Tool Result (Read): ...` lines for tool messages
|
|
617
|
-
- `canUseTool` requires streaming input at the SDK level (AsyncIterable prompt). This provider supports it via `streamingInput`: use `'auto'` (
|
|
707
|
+
- `canUseTool` requires streaming input at the SDK level (AsyncIterable prompt), and image prompts use the same path. This provider supports it via `streamingInput`: use `'auto'` (streams when `canUseTool` is set or image parts are present), `'always'`, or `'off'` (`'off'` disables streaming image input, emits a generic `type: 'other'` image streaming-input warning, and omits image parts). See GUIDE for details.
|
|
618
708
|
|
|
619
709
|
## Tool Error Parity (Streaming)
|
|
620
710
|
|
|
621
|
-
-
|
|
622
|
-
-
|
|
623
|
-
- See
|
|
711
|
+
- AI SDK v7 represents failed tool executions with the standard `tool-result` stream event/part and `isError: true`.
|
|
712
|
+
- The former provider-specific `tool-error` stream extension is not emitted on the 4.x line; inspect `providerMetadata['claude-code']` (e.g., `rawError`) on the `tool-result` when you need Claude Code details.
|
|
713
|
+
- See **Content Block Streaming** below for the current streaming event overview; the Tool Streaming Support doc is historical v5-era reference material.
|
|
624
714
|
|
|
625
715
|
## Content Block Streaming
|
|
626
716
|
|
|
@@ -637,7 +727,7 @@ For subagent parent/child tracking, see **Subagent Hierarchy Tracking** in this
|
|
|
637
727
|
When Claude Code spawns subagents via the `Task` tool, this provider exposes parent-child relationships through `providerMetadata`:
|
|
638
728
|
|
|
639
729
|
```ts
|
|
640
|
-
// Available on tool-input-start, tool-call,
|
|
730
|
+
// Available on tool-input-start, tool-call, and tool-result events
|
|
641
731
|
providerMetadata['claude-code'].parentToolCallId: string | null;
|
|
642
732
|
```
|
|
643
733
|
|
|
@@ -649,35 +739,38 @@ This enables UIs to build hierarchical views of nested agent execution.
|
|
|
649
739
|
|
|
650
740
|
## Provider Metadata
|
|
651
741
|
|
|
652
|
-
Each response exposes Claude Code metadata under `providerMetadata['claude-code']` (
|
|
653
|
-
|
|
654
|
-
| Field | Type | Description
|
|
655
|
-
| ------------------------- | --------- |
|
|
656
|
-
| `sessionId` | `string` | Session ID for multi-turn conversations
|
|
657
|
-
| `costUsd` | `number` | Cost of the request in USD
|
|
658
|
-
| `durationMs` | `number` | Total request duration in milliseconds
|
|
659
|
-
| `modelUsage` | `object` | Per-model token usage breakdown
|
|
660
|
-
| `ttftMs` | `number` | Time to first token in milliseconds (when reported by the SDK)
|
|
661
|
-
| `ttftStreamMs` | `number` | Time to first streamed token in milliseconds (when reported)
|
|
662
|
-
| `timeToRequestMs` | `number` | Time until the API request was issued in milliseconds (when reported)
|
|
663
|
-
| `warmSpareClaimed` | `boolean` | Whether the query was served from a pre-warmed spare CLI process (when reported); see **Reducing time-to-first-token (warm start)**
|
|
664
|
-
| `terminalReason` | `string` | Why the turn loop terminated (SDK `TerminalReason`, e.g. `'completed'`, `'max_turns'`; re-exported type)
|
|
665
|
-
| `apiRetries` | `number` | Number of API retry attempts observed during the request (only present when > 0)
|
|
666
|
-
| `permissionDenials` | `array` | Denied tool calls: `{ toolName, toolUseId?, reason? }`
|
|
667
|
-
| `
|
|
668
|
-
| `
|
|
669
|
-
| `
|
|
670
|
-
| `
|
|
742
|
+
Each response exposes Claude Code metadata under the final step's `providerMetadata['claude-code']` (AI SDK v7: `result.finalStep.providerMetadata`, or `await stream.finalStep` for `streamText`; internally this comes from the provider `doGenerate` result or `finish` stream event):
|
|
743
|
+
|
|
744
|
+
| Field | Type | Description |
|
|
745
|
+
| ------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
746
|
+
| `sessionId` | `string` | Session ID for multi-turn conversations |
|
|
747
|
+
| `costUsd` | `number` | Cost of the request in USD |
|
|
748
|
+
| `durationMs` | `number` | Total request duration in milliseconds |
|
|
749
|
+
| `modelUsage` | `object` | Per-model token usage breakdown |
|
|
750
|
+
| `ttftMs` | `number` | Time to first token in milliseconds (when reported by the SDK) |
|
|
751
|
+
| `ttftStreamMs` | `number` | Time to first streamed token in milliseconds (when reported) |
|
|
752
|
+
| `timeToRequestMs` | `number` | Time until the API request was issued in milliseconds (when reported) |
|
|
753
|
+
| `warmSpareClaimed` | `boolean` | Whether the query was served from a pre-warmed spare CLI process (when reported); see **Reducing time-to-first-token (warm start)** |
|
|
754
|
+
| `terminalReason` | `string` | Why the turn loop terminated (SDK `TerminalReason`, e.g. `'completed'`, `'max_turns'`; re-exported type) |
|
|
755
|
+
| `apiRetries` | `number` | Number of API retry attempts observed during the request (only present when > 0) |
|
|
756
|
+
| `permissionDenials` | `array` | Denied tool calls: `{ toolName, toolUseId?, reason?, agentId?, decisionReasonType?, raw? }` when available. Stream-time auto-denials are warn-logged; PreToolUse-hook denials are merged from the result message |
|
|
757
|
+
| `taskEvents` | `array` | `ClaudeCodeTaskEvent[]` task/subagent lifecycle events observed during the request (only present when non-empty) |
|
|
758
|
+
| `hookEvents` | `array` | `ClaudeCodeHookEvent[]` hook lifecycle events observed during the request (only present when non-empty; requires SDK hook event emission, e.g. `includeHookEvents: true`) |
|
|
759
|
+
| `mcpServers` | `array` | Initial MCP server status snapshot observed from the SDK init message during the request, matching the data delivered to `onMcpStatusChange` when available. Use `controller.mcpServerStatus()` for live status after runtime MCP changes only while the query is live and SDK streaming input/output is active |
|
|
760
|
+
| `mirrorErrors` | `array` | SessionStore transcript-mirror append failures: `{ error, sessionId }` (only present when non-empty). Each is a transcript batch the SDK DROPPED after retries — also warn-logged — so `sessionStore` consumers can detect a silently-incomplete mirror |
|
|
761
|
+
| `estimatedThinkingTokens` | `number` | Accumulated live thinking-token estimate from the redacted-thinking phase (only present when > 0); approximate, not the authoritative billed output tokens |
|
|
762
|
+
| `truncated` | `true` | Present when the response was recovered from a truncated SDK stream |
|
|
763
|
+
| `thinkingTraces` | `array` | Thinking blocks extracted in non-streaming mode (`doGenerate` only) |
|
|
671
764
|
|
|
672
765
|
```ts
|
|
673
|
-
const {
|
|
674
|
-
const meta = providerMetadata?.['claude-code'];
|
|
766
|
+
const { finalStep } = await generateText({ model, prompt: 'Hello' });
|
|
767
|
+
const meta = finalStep.providerMetadata?.['claude-code'];
|
|
675
768
|
console.log(meta?.costUsd, meta?.ttftMs, meta?.terminalReason);
|
|
676
769
|
```
|
|
677
770
|
|
|
678
771
|
### Prompt suggestions (`onPromptSuggestion`)
|
|
679
772
|
|
|
680
|
-
|
|
773
|
+
Set `promptSuggestions: true` to receive predicted next prompts. When the option is unset or `false`, the CLI does not emit `prompt_suggestion` messages and `onPromptSuggestion` never fires. Delivery is still subject to CLI heuristics (suppressed on the first turn, after API errors, in plan mode, or via `CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false`), so it may not fire on every enabled turn. The SDK delivers the suggestion AFTER the `result` message — i.e. after the AI SDK response has already finished — so it cannot be part of `providerMetadata`. Register a callback instead. (In streaming mode the provider briefly drains post-result messages to deliver the suggestion; the drain stops after the first suggestion and is capped at 10 seconds so a lingering CLI process is never held open indefinitely.)
|
|
681
774
|
|
|
682
775
|
```ts
|
|
683
776
|
const model = claudeCode('sonnet', {
|
|
@@ -688,25 +781,31 @@ const model = claudeCode('sonnet', {
|
|
|
688
781
|
});
|
|
689
782
|
```
|
|
690
783
|
|
|
691
|
-
###
|
|
784
|
+
### Query controller (`onQueryControllerCreated` / `createClaudeCodeQueryController`)
|
|
785
|
+
|
|
786
|
+
`onQueryCreated` still exposes the raw Agent SDK `Query` for advanced consumers. The provider also offers a safer controller surface for the wrapped live-query operations listed below and exports the same wrapper as `createClaudeCodeQueryController(query)`. The controller's `rawQuery` property remains available when you intentionally need the underlying SDK object.
|
|
787
|
+
|
|
788
|
+
`onQueryControllerCreated` only applies to the live SDK `Query` created for that request. Controller methods that send Agent SDK control requests require that query to still be running, and most control requests are supported by the SDK only when streaming input/output is active. In this provider, set `streamingInput: 'always'` for controller-control recipes (or use `'auto'` only when another feature already triggers streaming input, such as `canUseTool` or image parts).
|
|
692
789
|
|
|
693
|
-
|
|
790
|
+
Use `onQueryControllerCreated` when you want to call wrapped controls—`interrupt()`, `setPermissionMode()`, `setMcpPermissionModeOverride()`, `setModel()`, `setMaxThinkingTokens()`, `applyFlagSettings()`, `mcpServerStatus()`, `reconnectMcpServer()`, `toggleMcpServer()`, `setMcpServers()`, `getContextUsage()`, `rewindFiles()`, `stopTask()`, `backgroundTasks()`, and optional `streamInput()`—without passing the entire raw query through your UI layer:
|
|
694
791
|
|
|
695
792
|
```ts
|
|
696
|
-
import type {
|
|
793
|
+
import type { ClaudeCodeQueryController } from 'ai-sdk-provider-claude-code';
|
|
697
794
|
|
|
698
|
-
let
|
|
795
|
+
let activeController: ClaudeCodeQueryController | undefined;
|
|
699
796
|
let contextUsage: unknown;
|
|
797
|
+
|
|
700
798
|
const model = claudeCode('sonnet', {
|
|
701
|
-
|
|
702
|
-
|
|
799
|
+
streamingInput: 'always', // Required for Agent SDK control requests.
|
|
800
|
+
onQueryControllerCreated: (controller) => {
|
|
801
|
+
activeController = controller;
|
|
703
802
|
},
|
|
704
803
|
hooks: {
|
|
705
804
|
Stop: [
|
|
706
805
|
{
|
|
707
806
|
hooks: [
|
|
708
807
|
async () => {
|
|
709
|
-
contextUsage = await
|
|
808
|
+
contextUsage = await activeController?.getContextUsage();
|
|
710
809
|
return { continue: true };
|
|
711
810
|
},
|
|
712
811
|
],
|
|
@@ -719,6 +818,10 @@ const result = await generateText({ model, prompt: 'Hello' });
|
|
|
719
818
|
console.log(contextUsage); // tokens used / remaining in the session context window
|
|
720
819
|
```
|
|
721
820
|
|
|
821
|
+
The controller does not extend the SDK query lifetime. Controller calls that talk to the CLI subprocess must happen before `generateText`/`streamText` resolves; after the subprocess exits, the underlying SDK call rejects with `ProcessTransport is not ready for writing`.
|
|
822
|
+
|
|
823
|
+
For MCP, `onMcpStatusChange` and `providerMetadata['claude-code'].mcpServers` record the request's initial SDK init snapshot; after `reconnectMcpServer()`, `toggleMcpServer()`, or `setMcpServers()`, call `controller.mcpServerStatus()` only while the query is live and SDK streaming input/output is active.
|
|
824
|
+
|
|
722
825
|
## Contributing
|
|
723
826
|
|
|
724
827
|
We welcome contributions, especially:
|