ai-sdk-provider-claude-code 3.0.0-beta.1 → 3.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 CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  # AI SDK Provider for Claude Code SDK
11
11
 
12
- > **Latest Release**: Version 2.x uses the Claude Agent SDK with native structured outputs support (v2.2.0+). For AI SDK v4 support, use the `ai-sdk-v4` tag or version 0.2.x.
12
+ > **Latest Release**: Version 3.x supports AI SDK v6 stable with the Claude Agent SDK. For AI SDK v5 support, use the `ai-sdk-v5` 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
 
@@ -17,23 +17,24 @@
17
17
 
18
18
  | Provider Version | AI SDK Version | Underlying SDK | NPM Tag | Status | Branch |
19
19
  | ---------------- | -------------- | ------------------------------------ | -------------------- | ------ | --------------------------------------------------------------------------------------- |
20
- | 2.x.x | v5 | `@anthropic-ai/claude-agent-sdk` | `latest` | Stable | `main` |
21
- | 1.x.x | v5 | `@anthropic-ai/claude-code` (legacy) | `v1-claude-code-sdk` | Stable | [`v1`](https://github.com/ben-vargas/ai-sdk-provider-claude-code/tree/v1) |
22
- | 0.x.x | v4 | `@anthropic-ai/claude-code` | `ai-sdk-v4` | Legacy | [`ai-sdk-v4`](https://github.com/ben-vargas/ai-sdk-provider-claude-code/tree/ai-sdk-v4) |
20
+ | 3.x.x | v6 | `@anthropic-ai/claude-agent-sdk` | `latest` | Stable | `main` |
21
+ | 2.x.x | v5 | `@anthropic-ai/claude-agent-sdk` | `ai-sdk-v5` | Stable | [`ai-sdk-v5`](https://github.com/ben-vargas/ai-sdk-provider-claude-code/tree/ai-sdk-v5) |
22
+ | 1.x.x | v5 | `@anthropic-ai/claude-code` (legacy) | `v1-claude-code-sdk` | Legacy | [`v1`](https://github.com/ben-vargas/ai-sdk-provider-claude-code/tree/v1) |
23
+ | 0.x.x | v4 | `@anthropic-ai/claude-code` (legacy) | `ai-sdk-v4` | Legacy | [`ai-sdk-v4`](https://github.com/ben-vargas/ai-sdk-provider-claude-code/tree/ai-sdk-v4) |
23
24
 
24
25
  ### Installing the Right Version
25
26
 
26
- **For AI SDK v5 with Claude Agent SDK (recommended):**
27
+ **For AI SDK v6 (recommended):**
27
28
 
28
29
  ```bash
29
- npm install ai-sdk-provider-claude-code ai
30
+ npm install ai-sdk-provider-claude-code ai@^6.0.0
30
31
  # or explicitly: npm install ai-sdk-provider-claude-code@latest
31
32
  ```
32
33
 
33
- **For AI SDK v5 with Claude Code SDK (legacy):**
34
+ **For AI SDK v5:**
34
35
 
35
36
  ```bash
36
- npm install ai-sdk-provider-claude-code@v1-claude-code-sdk ai
37
+ npm install ai-sdk-provider-claude-code@ai-sdk-v5 ai@^5.0.0
37
38
  ```
38
39
 
39
40
  **For AI SDK v4 (legacy):**
@@ -45,69 +46,17 @@ npm install ai-sdk-provider-claude-code@ai-sdk-v4 ai@^4.3.16
45
46
 
46
47
  ## Zod Compatibility
47
48
 
48
- This package is **tested and compatible with both Zod 3 and Zod 4**, but there's an important peer dependency consideration:
49
-
50
- ### Current Status
51
-
52
- - ✅ **Zod 3** (fully supported, no warnings)
53
- - ⚠️ **Zod 4** (functional, but requires `--legacy-peer-deps`)
54
-
55
- While this package declares support for both versions (`peerDependencies: "zod": "^3.0.0 || ^4.0.0"`), the underlying `@anthropic-ai/claude-agent-sdk` currently only declares support for Zod 3 (`peerDependencies: "zod": "^3.24.1"`).
56
-
57
- **All 302 tests pass with both Zod 3 and Zod 4.** See `examples/zod4-compatibility-test.ts` for comprehensive compatibility verification.
58
-
59
- ### Installation Instructions
60
-
61
- **With Zod 3 (recommended for now):**
49
+ This package is **fully compatible with both Zod 3 and Zod 4**.
62
50
 
63
51
  ```bash
52
+ # With Zod 3
64
53
  npm install ai-sdk-provider-claude-code ai zod@^3.0.0
65
- ```
66
-
67
- **With Zod 4 (requires package manager-specific flags):**
68
-
69
- For **npm**:
70
-
71
- ```bash
72
- npm install ai-sdk-provider-claude-code ai zod@^4.0.0 --legacy-peer-deps
73
- ```
74
-
75
- For **pnpm**:
76
-
77
- ```bash
78
- pnpm install ai-sdk-provider-claude-code ai zod@^4.0.0 --no-strict-peer-dependencies
79
- # Or configure it project-wide:
80
- pnpm config set strict-peer-dependencies false
81
- ```
82
-
83
- For **Yarn** (Berry/v2+):
84
-
85
- ```bash
86
- yarn add ai-sdk-provider-claude-code ai zod@^4.0.0
87
- # Yarn's peer resolution typically doesn't error here
88
- ```
89
-
90
- ### For Package Developers
91
-
92
- If you're developing with this package in your repository, add a configuration file to avoid needing the flag on every install:
93
-
94
- **For npm** (`.npmrc`):
95
54
 
96
- ```ini
97
- # .npmrc
98
- legacy-peer-deps=true
55
+ # With Zod 4
56
+ npm install ai-sdk-provider-claude-code ai zod@^4.0.0
99
57
  ```
100
58
 
101
- **For pnpm** (`.npmrc`):
102
-
103
- ```ini
104
- # .npmrc
105
- strict-peer-dependencies=false
106
- ```
107
-
108
- > **Note**: The `.npmrc` file in this repository is committed for CI/development consistency but is **not included in the published package** (it's excluded via the `files` field in `package.json`). End users will still need to use the appropriate flags when installing with Zod 4.
109
-
110
- > **Temporary Workaround**: This configuration is needed until `@anthropic-ai/claude-agent-sdk` adds official Zod 4 support to their peer dependencies. Track progress in the [claude-agent-sdk repository](https://github.com/anthropics/anthropic-sdk-typescript).
59
+ Both this package and the underlying `@anthropic-ai/claude-agent-sdk` declare support for both versions (`peerDependencies: "zod": "^3.24.1 || ^4.0.0"`).
111
60
 
112
61
  ## Installation
113
62
 
@@ -121,10 +70,13 @@ claude login
121
70
  ### 2. Add the provider
122
71
 
123
72
  ```bash
124
- # For v5 (recommended)
125
- npm install ai-sdk-provider-claude-code ai
73
+ # For AI SDK v6 (recommended)
74
+ npm install ai-sdk-provider-claude-code ai@^6.0.0
126
75
 
127
- # For v4 (legacy)
76
+ # For AI SDK v5
77
+ npm install ai-sdk-provider-claude-code@ai-sdk-v5 ai@^5.0.0
78
+
79
+ # For AI SDK v4 (legacy)
128
80
  npm install ai-sdk-provider-claude-code@ai-sdk-v4 ai@^4.3.16
129
81
  ```
130
82
 
@@ -140,7 +92,7 @@ Please ensure you have appropriate permissions and comply with all applicable te
140
92
 
141
93
  ## Quick Start
142
94
 
143
- ### AI SDK v5
95
+ ### AI SDK v6
144
96
 
145
97
  ```typescript
146
98
  import { streamText } from 'ai';
@@ -155,22 +107,31 @@ const text = await result.text;
155
107
  console.log(text);
156
108
  ```
157
109
 
158
- ### AI SDK v4
110
+ ### AI SDK v5
159
111
 
160
112
  ```typescript
161
- import { generateText } from 'ai';
113
+ // npm install ai-sdk-provider-claude-code@ai-sdk-v5 ai@^5.0.0
114
+ import { streamText } from 'ai';
162
115
  import { claudeCode } from 'ai-sdk-provider-claude-code';
163
116
 
164
- const { text } = await generateText({
117
+ const result = streamText({
165
118
  model: claudeCode('haiku'),
166
119
  prompt: 'Hello, Claude!',
167
120
  });
168
121
 
122
+ const text = await result.text;
169
123
  console.log(text);
170
124
  ```
171
125
 
172
126
  ## Breaking Changes
173
127
 
128
+ ### Version 3.0.0 (AI SDK v6 Stable)
129
+
130
+ This version upgrades to AI SDK v6 stable with updated provider types:
131
+
132
+ - **`usage.raw`** now contains raw provider usage (previously in `providerMetadata['claude-code'].rawUsage`)
133
+ - Internal type changes for `LanguageModelV3Usage` and `LanguageModelV3FinishReason` (transparent to most users)
134
+
174
135
  ### Version 2.0.0 (Claude Agent SDK Migration)
175
136
 
176
137
  This version migrates to `@anthropic-ai/claude-agent-sdk` with **new defaults for better control**:
package/dist/index.cjs CHANGED
@@ -407,13 +407,15 @@ function getErrorMetadata(error) {
407
407
  function mapClaudeCodeFinishReason(subtype) {
408
408
  switch (subtype) {
409
409
  case "success":
410
- return "stop";
410
+ return { unified: "stop", raw: subtype };
411
411
  case "error_max_turns":
412
- return "length";
412
+ return { unified: "length", raw: subtype };
413
413
  case "error_during_execution":
414
- return "error";
414
+ return { unified: "error", raw: subtype };
415
+ case void 0:
416
+ return { unified: "stop", raw: void 0 };
415
417
  default:
416
- return "stop";
418
+ return { unified: "other", raw: subtype };
417
419
  }
418
420
  }
419
421
 
@@ -689,6 +691,42 @@ function isAbortError(err) {
689
691
  return false;
690
692
  }
691
693
  var STREAMING_FEATURE_WARNING = "Claude Agent SDK features (hooks/MCP/images) require streaming input. Set `streamingInput: 'always'` or provide `canUseTool` (auto streams only when canUseTool is set).";
694
+ function createEmptyUsage() {
695
+ return {
696
+ inputTokens: {
697
+ total: 0,
698
+ noCache: 0,
699
+ cacheRead: 0,
700
+ cacheWrite: 0
701
+ },
702
+ outputTokens: {
703
+ total: 0,
704
+ text: void 0,
705
+ reasoning: void 0
706
+ },
707
+ raw: void 0
708
+ };
709
+ }
710
+ function convertClaudeCodeUsage(usage) {
711
+ const inputTokens = usage.input_tokens ?? 0;
712
+ const outputTokens = usage.output_tokens ?? 0;
713
+ const cacheWrite = usage.cache_creation_input_tokens ?? 0;
714
+ const cacheRead = usage.cache_read_input_tokens ?? 0;
715
+ return {
716
+ inputTokens: {
717
+ total: inputTokens + cacheWrite + cacheRead,
718
+ noCache: inputTokens,
719
+ cacheRead,
720
+ cacheWrite
721
+ },
722
+ outputTokens: {
723
+ total: outputTokens,
724
+ text: void 0,
725
+ reasoning: void 0
726
+ },
727
+ raw: usage
728
+ };
729
+ }
692
730
  function toAsyncIterablePrompt(messagesPrompt, outputStreamEnded, sessionId, contentParts) {
693
731
  const content = contentParts && contentParts.length > 0 ? contentParts : [{ type: "text", text: messagesPrompt }];
694
732
  const msg = {
@@ -1042,16 +1080,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1042
1080
  const queryOptions = this.createQueryOptions(abortController, options.responseFormat);
1043
1081
  let text = "";
1044
1082
  let structuredOutput;
1045
- let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
1046
- let finishReason = "stop";
1083
+ let usage = createEmptyUsage();
1084
+ let finishReason = { unified: "stop", raw: void 0 };
1047
1085
  let wasTruncated = false;
1048
1086
  let costUsd;
1049
1087
  let durationMs;
1050
- let rawUsage;
1051
- const warnings = this.generateAllWarnings(
1052
- options,
1053
- messagesPrompt
1054
- );
1088
+ const warnings = this.generateAllWarnings(options, messagesPrompt);
1055
1089
  if (messageWarnings) {
1056
1090
  messageWarnings.forEach((warning) => {
1057
1091
  warnings.push({
@@ -1114,18 +1148,13 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1114
1148
  `[claude-code] Request completed - Session: ${message.session_id}, Cost: $${costUsd?.toFixed(4) ?? "N/A"}, Duration: ${durationMs ?? "N/A"}ms`
1115
1149
  );
1116
1150
  if ("usage" in message) {
1117
- rawUsage = message.usage;
1118
- usage = {
1119
- inputTokens: (message.usage.cache_creation_input_tokens ?? 0) + (message.usage.cache_read_input_tokens ?? 0) + (message.usage.input_tokens ?? 0),
1120
- outputTokens: message.usage.output_tokens ?? 0,
1121
- totalTokens: (message.usage.cache_creation_input_tokens ?? 0) + (message.usage.cache_read_input_tokens ?? 0) + (message.usage.input_tokens ?? 0) + (message.usage.output_tokens ?? 0)
1122
- };
1151
+ usage = convertClaudeCodeUsage(message.usage);
1123
1152
  this.logger.debug(
1124
- `[claude-code] Token usage - Input: ${usage.inputTokens}, Output: ${usage.outputTokens}, Total: ${usage.totalTokens}`
1153
+ `[claude-code] Token usage - Input: ${usage.inputTokens.total}, Output: ${usage.outputTokens.total}`
1125
1154
  );
1126
1155
  }
1127
1156
  finishReason = mapClaudeCodeFinishReason(message.subtype);
1128
- this.logger.debug(`[claude-code] Finish reason: ${finishReason}`);
1157
+ this.logger.debug(`[claude-code] Finish reason: ${finishReason.unified}`);
1129
1158
  } else if (message.type === "system" && message.subtype === "init") {
1130
1159
  this.setSessionId(message.session_id);
1131
1160
  this.logger.info(`[claude-code] Session initialized: ${message.session_id}`);
@@ -1145,7 +1174,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1145
1174
  `[claude-code] Detected truncated response, returning ${text.length} characters of buffered text`
1146
1175
  );
1147
1176
  wasTruncated = true;
1148
- finishReason = "length";
1177
+ finishReason = { unified: "length", raw: "truncation" };
1149
1178
  warnings.push({
1150
1179
  type: "other",
1151
1180
  message: CLAUDE_CODE_TRUNCATION_WARNING
@@ -1177,7 +1206,6 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1177
1206
  ...this.sessionId !== void 0 && { sessionId: this.sessionId },
1178
1207
  ...costUsd !== void 0 && { costUsd },
1179
1208
  ...durationMs !== void 0 && { durationMs },
1180
- ...rawUsage !== void 0 && { rawUsage },
1181
1209
  ...wasTruncated && { truncated: true }
1182
1210
  }
1183
1211
  }
@@ -1207,10 +1235,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1207
1235
  if (queryOptions.includePartialMessages === void 0) {
1208
1236
  queryOptions.includePartialMessages = true;
1209
1237
  }
1210
- const warnings = this.generateAllWarnings(
1211
- options,
1212
- messagesPrompt
1213
- );
1238
+ const warnings = this.generateAllWarnings(options, messagesPrompt);
1214
1239
  if (messageWarnings) {
1215
1240
  messageWarnings.forEach((warning) => {
1216
1241
  warnings.push({
@@ -1275,7 +1300,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1275
1300
  }
1276
1301
  toolStates.clear();
1277
1302
  };
1278
- let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
1303
+ let usage = createEmptyUsage();
1279
1304
  let accumulatedText = "";
1280
1305
  let textPartId;
1281
1306
  let streamedTextLength = 0;
@@ -1573,22 +1598,16 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1573
1598
  this.logger.info(
1574
1599
  `[claude-code] Stream completed - Session: ${message.session_id}, Cost: $${message.total_cost_usd?.toFixed(4) ?? "N/A"}, Duration: ${message.duration_ms ?? "N/A"}ms`
1575
1600
  );
1576
- let rawUsage;
1577
1601
  if ("usage" in message) {
1578
- rawUsage = message.usage;
1579
- usage = {
1580
- inputTokens: (message.usage.cache_creation_input_tokens ?? 0) + (message.usage.cache_read_input_tokens ?? 0) + (message.usage.input_tokens ?? 0),
1581
- outputTokens: message.usage.output_tokens ?? 0,
1582
- totalTokens: (message.usage.cache_creation_input_tokens ?? 0) + (message.usage.cache_read_input_tokens ?? 0) + (message.usage.input_tokens ?? 0) + (message.usage.output_tokens ?? 0)
1583
- };
1602
+ usage = convertClaudeCodeUsage(message.usage);
1584
1603
  this.logger.debug(
1585
- `[claude-code] Stream token usage - Input: ${usage.inputTokens}, Output: ${usage.outputTokens}, Total: ${usage.totalTokens}`
1604
+ `[claude-code] Stream token usage - Input: ${usage.inputTokens.total}, Output: ${usage.outputTokens.total}`
1586
1605
  );
1587
1606
  }
1588
1607
  const finishReason = mapClaudeCodeFinishReason(
1589
1608
  message.subtype
1590
1609
  );
1591
- this.logger.debug(`[claude-code] Stream finish reason: ${finishReason}`);
1610
+ this.logger.debug(`[claude-code] Stream finish reason: ${finishReason.unified}`);
1592
1611
  this.setSessionId(message.session_id);
1593
1612
  const structuredOutput = "structured_output" in message ? message.structured_output : void 0;
1594
1613
  const alreadyStreamedJson = textPartId && options.responseFormat?.type === "json" && hasReceivedStreamEvents;
@@ -1647,7 +1666,6 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1647
1666
  costUsd: message.total_cost_usd
1648
1667
  },
1649
1668
  ...message.duration_ms !== void 0 && { durationMs: message.duration_ms },
1650
- ...rawUsage !== void 0 && { rawUsage },
1651
1669
  // JSON validation warnings are collected during streaming and included
1652
1670
  // in providerMetadata since the AI SDK's finish event doesn't support
1653
1671
  // a top-level warnings field (unlike stream-start which was already emitted)
@@ -1710,7 +1728,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1710
1728
  const warningsJson = this.serializeWarningsForMetadata(streamWarnings);
1711
1729
  controller.enqueue({
1712
1730
  type: "finish",
1713
- finishReason: "length",
1731
+ finishReason: { unified: "length", raw: "truncation" },
1714
1732
  usage,
1715
1733
  providerMetadata: {
1716
1734
  "claude-code": {