ai-sdk-provider-claude-code 3.0.1 → 3.2.1

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
@@ -46,17 +46,13 @@ npm install ai-sdk-provider-claude-code@ai-sdk-v4 ai@^4.3.16
46
46
 
47
47
  ## Zod Compatibility
48
48
 
49
- This package is **fully compatible with both Zod 3 and Zod 4**.
49
+ **Starting from v3.2.0, this package requires Zod 4.**
50
50
 
51
51
  ```bash
52
- # With Zod 3
53
- npm install ai-sdk-provider-claude-code ai zod@^3.0.0
54
-
55
- # With Zod 4
56
52
  npm install ai-sdk-provider-claude-code ai zod@^4.0.0
57
53
  ```
58
54
 
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"`).
55
+ > **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`.
60
56
 
61
57
  ## Installation
62
58
 
@@ -269,6 +265,49 @@ console.log(result.object); // Guaranteed to match schema
269
265
  - 🔧 Tool management (MCP servers, permissions)
270
266
  - 🧩 Callbacks (hooks, canUseTool)
271
267
 
268
+ ## Agent SDK Options (Advanced)
269
+
270
+ This provider exposes Agent SDK options directly. Key options include:
271
+
272
+ | Option | Description |
273
+ | --------------------------------- | --------------------------------------------------------------------------------------------------------- |
274
+ | `betas` | Enable beta features (e.g., `['context-1m-2025-08-07']`) |
275
+ | `sandbox` | Configure sandbox behavior (`{ enabled: true }`) |
276
+ | `plugins` | Load custom plugins from local paths |
277
+ | `resumeSessionAt` | Resume session at a specific message UUID |
278
+ | `enableFileCheckpointing` | Enable file rewind support |
279
+ | `maxBudgetUsd` | Maximum budget in USD for the query |
280
+ | `tools` | Tool configuration (array of names or preset) |
281
+ | `allowDangerouslySkipPermissions` | Allow bypassing permissions |
282
+ | `persistSession` | When `false`, disables session persistence to disk (v3.2.0+) |
283
+ | `spawnClaudeCodeProcess` | Custom process spawner for VMs/containers (v3.2.0+) |
284
+ | `permissionMode` | Permission mode: `'default'`, `'acceptEdits'`, `'bypassPermissions'`, `'plan'`, `'delegate'`, `'dontAsk'` |
285
+
286
+ **Agent definitions** (`agents`) now support additional fields (v3.2.0+):
287
+
288
+ - `disallowedTools` - Tools to explicitly disallow for the agent
289
+ - `mcpServers` - MCP servers available to the agent
290
+ - `criticalSystemReminder_EXPERIMENTAL` - Experimental critical reminder
291
+
292
+ 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`).
293
+
294
+ For options not explicitly exposed, use the `sdkOptions` escape hatch. It **overrides** explicit settings,
295
+ but provider-managed fields are ignored (`model`, `abortController`, `prompt`, `outputFormat`).
296
+ If you set `sdkOptions.resume`, it also drives the streaming prompt `session_id` so the SDK
297
+ and prompt target the same session.
298
+
299
+ ```ts
300
+ const model = claudeCode('sonnet', {
301
+ betas: ['context-1m-2025-08-07'],
302
+ sandbox: { enabled: true },
303
+ persistSession: false, // Don't persist session to disk
304
+ sdkOptions: {
305
+ maxBudgetUsd: 1,
306
+ resume: 'session-abc',
307
+ },
308
+ });
309
+ ```
310
+
272
311
  ## Image Inputs (Streaming Only)
273
312
 
274
313
  - Enable streaming input (`streamingInput: 'always'` or provide `canUseTool`) before sending images.
package/dist/index.cjs CHANGED
@@ -461,12 +461,33 @@ var claudeCodeSettingsSchema = import_zod.z.object({
461
461
  ).optional(),
462
462
  executable: import_zod.z.enum(["bun", "deno", "node"]).optional(),
463
463
  executableArgs: import_zod.z.array(import_zod.z.string()).optional(),
464
- permissionMode: import_zod.z.enum(["default", "acceptEdits", "bypassPermissions", "plan"]).optional(),
464
+ permissionMode: import_zod.z.enum(["default", "acceptEdits", "bypassPermissions", "plan", "delegate", "dontAsk"]).optional(),
465
465
  permissionPromptToolName: import_zod.z.string().optional(),
466
466
  continue: import_zod.z.boolean().optional(),
467
467
  resume: import_zod.z.string().optional(),
468
468
  allowedTools: import_zod.z.array(import_zod.z.string()).optional(),
469
469
  disallowedTools: import_zod.z.array(import_zod.z.string()).optional(),
470
+ betas: import_zod.z.array(import_zod.z.string()).optional(),
471
+ allowDangerouslySkipPermissions: import_zod.z.boolean().optional(),
472
+ enableFileCheckpointing: import_zod.z.boolean().optional(),
473
+ maxBudgetUsd: import_zod.z.number().min(0).optional(),
474
+ plugins: import_zod.z.array(
475
+ import_zod.z.object({
476
+ type: import_zod.z.string(),
477
+ path: import_zod.z.string()
478
+ }).passthrough()
479
+ ).optional(),
480
+ resumeSessionAt: import_zod.z.string().optional(),
481
+ sandbox: import_zod.z.any().refine((val) => val === void 0 || typeof val === "object", {
482
+ message: "sandbox must be an object"
483
+ }).optional(),
484
+ tools: import_zod.z.union([
485
+ import_zod.z.array(import_zod.z.string()),
486
+ import_zod.z.object({
487
+ type: import_zod.z.literal("preset"),
488
+ preset: import_zod.z.literal("claude_code")
489
+ })
490
+ ]).optional(),
470
491
  settingSources: import_zod.z.array(import_zod.z.enum(["user", "project", "local"])).optional(),
471
492
  streamingInput: import_zod.z.enum(["auto", "always", "off"]).optional(),
472
493
  // Hooks and tool-permission callback (permissive validation of shapes)
@@ -521,9 +542,18 @@ var claudeCodeSettingsSchema = import_zod.z.object({
521
542
  import_zod.z.object({
522
543
  description: import_zod.z.string(),
523
544
  tools: import_zod.z.array(import_zod.z.string()).optional(),
545
+ disallowedTools: import_zod.z.array(import_zod.z.string()).optional(),
524
546
  prompt: import_zod.z.string(),
525
- model: import_zod.z.enum(["sonnet", "opus", "haiku", "inherit"]).optional()
526
- })
547
+ model: import_zod.z.enum(["sonnet", "opus", "haiku", "inherit"]).optional(),
548
+ mcpServers: import_zod.z.array(
549
+ import_zod.z.union([
550
+ import_zod.z.string(),
551
+ import_zod.z.record(import_zod.z.string(), import_zod.z.any())
552
+ // McpServerConfigForProcessTransport
553
+ ])
554
+ ).optional(),
555
+ criticalSystemReminder_EXPERIMENTAL: import_zod.z.string().optional()
556
+ }).passthrough()
527
557
  ).optional(),
528
558
  includePartialMessages: import_zod.z.boolean().optional(),
529
559
  fallbackModel: import_zod.z.string().optional(),
@@ -532,7 +562,12 @@ var claudeCodeSettingsSchema = import_zod.z.object({
532
562
  message: "stderr must be a function"
533
563
  }).optional(),
534
564
  strictMcpConfig: import_zod.z.boolean().optional(),
535
- extraArgs: import_zod.z.record(import_zod.z.string(), import_zod.z.union([import_zod.z.string(), import_zod.z.null()])).optional()
565
+ extraArgs: import_zod.z.record(import_zod.z.string(), import_zod.z.union([import_zod.z.string(), import_zod.z.null()])).optional(),
566
+ persistSession: import_zod.z.boolean().optional(),
567
+ spawnClaudeCodeProcess: import_zod.z.any().refine((val) => val === void 0 || typeof val === "function", {
568
+ message: "spawnClaudeCodeProcess must be a function"
569
+ }).optional(),
570
+ sdkOptions: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional()
536
571
  }).strict();
537
572
  function validateModelId(modelId) {
538
573
  const knownModels = ["opus", "sonnet", "haiku"];
@@ -614,7 +649,9 @@ function validateSessionId(sessionId) {
614
649
 
615
650
  // src/logger.ts
616
651
  var defaultLogger = {
652
+ // eslint-disable-next-line no-console
617
653
  debug: (message) => console.debug(`[DEBUG] ${message}`),
654
+ // eslint-disable-next-line no-console
618
655
  info: (message) => console.info(`[INFO] ${message}`),
619
656
  warn: (message) => console.warn(`[WARN] ${message}`),
620
657
  error: (message) => console.error(`[ERROR] ${message}`)
@@ -696,6 +733,7 @@ function isAbortError(err) {
696
733
  return false;
697
734
  }
698
735
  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).";
736
+ var SDK_OPTIONS_BLOCKLIST = /* @__PURE__ */ new Set(["model", "abortController", "prompt", "outputFormat"]);
699
737
  function createEmptyUsage() {
700
738
  return {
701
739
  inputTokens: {
@@ -800,6 +838,25 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
800
838
  const mapped = modelMap[this.modelId];
801
839
  return mapped ?? this.modelId;
802
840
  }
841
+ getSanitizedSdkOptions() {
842
+ if (!this.settings.sdkOptions || typeof this.settings.sdkOptions !== "object") {
843
+ return void 0;
844
+ }
845
+ const sanitized = { ...this.settings.sdkOptions };
846
+ const blockedKeys = Array.from(SDK_OPTIONS_BLOCKLIST).filter((key) => key in sanitized);
847
+ if (blockedKeys.length > 0) {
848
+ this.logger.warn(
849
+ `[claude-code] sdkOptions includes provider-managed fields (${blockedKeys.join(
850
+ ", "
851
+ )}); these will be ignored.`
852
+ );
853
+ blockedKeys.forEach((key) => delete sanitized[key]);
854
+ }
855
+ return sanitized;
856
+ }
857
+ getEffectiveResume(sdkOptions) {
858
+ return sdkOptions?.resume ?? this.settings.resume ?? this.sessionId;
859
+ }
803
860
  extractToolUses(content) {
804
861
  if (!Array.isArray(content)) {
805
862
  return [];
@@ -933,11 +990,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
933
990
  }
934
991
  return warnings;
935
992
  }
936
- createQueryOptions(abortController, responseFormat) {
993
+ createQueryOptions(abortController, responseFormat, stderrCollector, sdkOptions, effectiveResume) {
937
994
  const opts = {
938
995
  model: this.getModel(),
939
996
  abortController,
940
- resume: this.settings.resume ?? this.sessionId,
997
+ resume: effectiveResume ?? this.settings.resume ?? this.sessionId,
941
998
  pathToClaudeCodeExecutable: this.settings.pathToClaudeCodeExecutable,
942
999
  maxTurns: this.settings.maxTurns,
943
1000
  maxThinkingTokens: this.settings.maxThinkingTokens,
@@ -949,6 +1006,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
949
1006
  continue: this.settings.continue,
950
1007
  allowedTools: this.settings.allowedTools,
951
1008
  disallowedTools: this.settings.disallowedTools,
1009
+ betas: this.settings.betas,
1010
+ allowDangerouslySkipPermissions: this.settings.allowDangerouslySkipPermissions,
1011
+ enableFileCheckpointing: this.settings.enableFileCheckpointing,
1012
+ maxBudgetUsd: this.settings.maxBudgetUsd,
1013
+ plugins: this.settings.plugins,
1014
+ resumeSessionAt: this.settings.resumeSessionAt,
1015
+ sandbox: this.settings.sandbox,
1016
+ tools: this.settings.tools,
952
1017
  mcpServers: this.settings.mcpServers,
953
1018
  canUseTool: this.settings.canUseTool
954
1019
  };
@@ -987,20 +1052,39 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
987
1052
  if (this.settings.forkSession !== void 0) {
988
1053
  opts.forkSession = this.settings.forkSession;
989
1054
  }
990
- if (this.settings.stderr !== void 0) {
991
- opts.stderr = this.settings.stderr;
992
- }
993
1055
  if (this.settings.strictMcpConfig !== void 0) {
994
1056
  opts.strictMcpConfig = this.settings.strictMcpConfig;
995
1057
  }
996
1058
  if (this.settings.extraArgs !== void 0) {
997
1059
  opts.extraArgs = this.settings.extraArgs;
998
1060
  }
1061
+ if (this.settings.persistSession !== void 0) {
1062
+ opts.persistSession = this.settings.persistSession;
1063
+ }
1064
+ if (this.settings.spawnClaudeCodeProcess !== void 0) {
1065
+ opts.spawnClaudeCodeProcess = this.settings.spawnClaudeCodeProcess;
1066
+ }
999
1067
  if (this.settings.hooks) {
1000
1068
  opts.hooks = this.settings.hooks;
1001
1069
  }
1002
- if (this.settings.env !== void 0) {
1003
- opts.env = { ...process.env, ...this.settings.env };
1070
+ const sdkOverrides = sdkOptions ? sdkOptions : void 0;
1071
+ const sdkEnv = sdkOverrides && typeof sdkOverrides.env === "object" && sdkOverrides.env !== null ? sdkOverrides.env : void 0;
1072
+ const sdkStderr = sdkOverrides && typeof sdkOverrides.stderr === "function" ? sdkOverrides.stderr : void 0;
1073
+ if (sdkOverrides) {
1074
+ const rest = { ...sdkOverrides };
1075
+ delete rest.env;
1076
+ delete rest.stderr;
1077
+ Object.assign(opts, rest);
1078
+ }
1079
+ const userStderrCallback = sdkStderr ?? this.settings.stderr;
1080
+ if (stderrCollector || userStderrCallback) {
1081
+ opts.stderr = (data) => {
1082
+ if (stderrCollector) stderrCollector(data);
1083
+ if (userStderrCallback) userStderrCallback(data);
1084
+ };
1085
+ }
1086
+ if (this.settings.env !== void 0 || sdkEnv !== void 0) {
1087
+ opts.env = { ...process.env, ...this.settings.env, ...sdkEnv };
1004
1088
  }
1005
1089
  if (responseFormat?.type === "json" && responseFormat.schema) {
1006
1090
  opts.outputFormat = {
@@ -1010,7 +1094,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1010
1094
  }
1011
1095
  return opts;
1012
1096
  }
1013
- handleClaudeCodeError(error, messagesPrompt) {
1097
+ handleClaudeCodeError(error, messagesPrompt, collectedStderr) {
1014
1098
  if (isAbortError(error)) {
1015
1099
  throw error;
1016
1100
  }
@@ -1026,7 +1110,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1026
1110
  "unauthorized",
1027
1111
  "auth failed",
1028
1112
  "please login",
1029
- "claude login"
1113
+ "claude login",
1114
+ "/login",
1115
+ // CLI returns "Please run /login"
1116
+ "invalid api key"
1030
1117
  ];
1031
1118
  const errorMessage = isErrorWithMessage(error) && error.message ? error.message.toLowerCase() : "";
1032
1119
  const exitCode = isErrorWithCode(error) && typeof error.exitCode === "number" ? error.exitCode : void 0;
@@ -1046,11 +1133,13 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1046
1133
  });
1047
1134
  }
1048
1135
  const isRetryable = errorCode === "ENOENT" || errorCode === "ECONNREFUSED" || errorCode === "ETIMEDOUT" || errorCode === "ECONNRESET";
1136
+ const stderrFromError = isErrorWithCode(error) && typeof error.stderr === "string" ? error.stderr : void 0;
1137
+ const stderr = stderrFromError || collectedStderr || void 0;
1049
1138
  return createAPICallError({
1050
1139
  message: isErrorWithMessage(error) && error.message ? error.message : "Claude Code SDK error",
1051
1140
  code: errorCode || void 0,
1052
1141
  exitCode,
1053
- stderr: isErrorWithCode(error) && typeof error.stderr === "string" ? error.stderr : void 0,
1142
+ stderr,
1054
1143
  promptExcerpt: messagesPrompt.substring(0, 200),
1055
1144
  isRetryable
1056
1145
  });
@@ -1082,7 +1171,19 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1082
1171
  abortListener = () => abortController.abort(options.abortSignal?.reason);
1083
1172
  options.abortSignal.addEventListener("abort", abortListener, { once: true });
1084
1173
  }
1085
- const queryOptions = this.createQueryOptions(abortController, options.responseFormat);
1174
+ let collectedStderr = "";
1175
+ const stderrCollector = (data) => {
1176
+ collectedStderr += data;
1177
+ };
1178
+ const sdkOptions = this.getSanitizedSdkOptions();
1179
+ const effectiveResume = this.getEffectiveResume(sdkOptions);
1180
+ const queryOptions = this.createQueryOptions(
1181
+ abortController,
1182
+ options.responseFormat,
1183
+ stderrCollector,
1184
+ sdkOptions,
1185
+ effectiveResume
1186
+ );
1086
1187
  let text = "";
1087
1188
  let structuredOutput;
1088
1189
  let usage = createEmptyUsage();
@@ -1100,7 +1201,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1100
1201
  });
1101
1202
  }
1102
1203
  const modeSetting = this.settings.streamingInput ?? "auto";
1103
- const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!this.settings.canUseTool;
1204
+ const effectiveCanUseTool = sdkOptions?.canUseTool ?? this.settings.canUseTool;
1205
+ const effectivePermissionPromptToolName = sdkOptions?.permissionPromptToolName ?? this.settings.permissionPromptToolName;
1206
+ const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!effectiveCanUseTool;
1104
1207
  if (!wantsStreamInput && hasImageParts) {
1105
1208
  warnings.push({
1106
1209
  type: "other",
@@ -1113,7 +1216,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1113
1216
  done = () => resolve(void 0);
1114
1217
  });
1115
1218
  try {
1116
- if (this.settings.canUseTool && this.settings.permissionPromptToolName) {
1219
+ if (effectiveCanUseTool && effectivePermissionPromptToolName) {
1117
1220
  throw new Error(
1118
1221
  "canUseTool requires streamingInput mode ('auto' or 'always') and cannot be used with permissionPromptToolName (SDK constraint). Set streamingInput: 'auto' (or 'always') and remove permissionPromptToolName, or remove canUseTool."
1119
1222
  );
@@ -1121,11 +1224,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1121
1224
  const sdkPrompt = wantsStreamInput ? toAsyncIterablePrompt(
1122
1225
  messagesPrompt,
1123
1226
  outputStreamEnded,
1124
- this.settings.resume ?? this.sessionId,
1227
+ effectiveResume,
1125
1228
  streamingContentParts
1126
1229
  ) : messagesPrompt;
1127
1230
  this.logger.debug(
1128
- `[claude-code] Executing query with streamingInput: ${wantsStreamInput}, session: ${this.settings.resume ?? this.sessionId ?? "new"}`
1231
+ `[claude-code] Executing query with streamingInput: ${wantsStreamInput}, session: ${effectiveResume ?? "new"}`
1129
1232
  );
1130
1233
  const response = (0, import_claude_agent_sdk.query)({
1131
1234
  prompt: sdkPrompt,
@@ -1140,6 +1243,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1140
1243
  this.setSessionId(message.session_id);
1141
1244
  costUsd = message.total_cost_usd;
1142
1245
  durationMs = message.duration_ms;
1246
+ if ("is_error" in message && message.is_error === true) {
1247
+ const errorMessage = "result" in message && typeof message.result === "string" ? message.result : "Claude Code CLI returned an error";
1248
+ throw Object.assign(new Error(errorMessage), { exitCode: 1 });
1249
+ }
1143
1250
  if (message.subtype === "error_max_structured_output_retries") {
1144
1251
  throw new Error(
1145
1252
  "Failed to generate valid structured output after maximum retries. The model could not produce a response matching the required schema."
@@ -1185,7 +1292,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1185
1292
  message: CLAUDE_CODE_TRUNCATION_WARNING
1186
1293
  });
1187
1294
  } else {
1188
- throw this.handleClaudeCodeError(error, messagesPrompt);
1295
+ throw this.handleClaudeCodeError(error, messagesPrompt, collectedStderr);
1189
1296
  }
1190
1297
  } finally {
1191
1298
  if (options.abortSignal && abortListener) {
@@ -1236,7 +1343,19 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1236
1343
  abortListener = () => abortController.abort(options.abortSignal?.reason);
1237
1344
  options.abortSignal.addEventListener("abort", abortListener, { once: true });
1238
1345
  }
1239
- const queryOptions = this.createQueryOptions(abortController, options.responseFormat);
1346
+ let collectedStderr = "";
1347
+ const stderrCollector = (data) => {
1348
+ collectedStderr += data;
1349
+ };
1350
+ const sdkOptions = this.getSanitizedSdkOptions();
1351
+ const effectiveResume = this.getEffectiveResume(sdkOptions);
1352
+ const queryOptions = this.createQueryOptions(
1353
+ abortController,
1354
+ options.responseFormat,
1355
+ stderrCollector,
1356
+ sdkOptions,
1357
+ effectiveResume
1358
+ );
1240
1359
  if (queryOptions.includePartialMessages === void 0) {
1241
1360
  queryOptions.includePartialMessages = true;
1242
1361
  }
@@ -1250,7 +1369,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1250
1369
  });
1251
1370
  }
1252
1371
  const modeSetting = this.settings.streamingInput ?? "auto";
1253
- const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!this.settings.canUseTool;
1372
+ const effectiveCanUseTool = sdkOptions?.canUseTool ?? this.settings.canUseTool;
1373
+ const effectivePermissionPromptToolName = sdkOptions?.permissionPromptToolName ?? this.settings.permissionPromptToolName;
1374
+ const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!effectiveCanUseTool;
1254
1375
  if (!wantsStreamInput && hasImageParts) {
1255
1376
  warnings.push({
1256
1377
  type: "other",
@@ -1310,9 +1431,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1310
1431
  let textPartId;
1311
1432
  let streamedTextLength = 0;
1312
1433
  let hasReceivedStreamEvents = false;
1434
+ let hasStreamedJson = false;
1313
1435
  try {
1314
1436
  controller.enqueue({ type: "stream-start", warnings });
1315
- if (this.settings.canUseTool && this.settings.permissionPromptToolName) {
1437
+ if (effectiveCanUseTool && effectivePermissionPromptToolName) {
1316
1438
  throw new Error(
1317
1439
  "canUseTool requires streamingInput mode ('auto' or 'always') and cannot be used with permissionPromptToolName (SDK constraint). Set streamingInput: 'auto' (or 'always') and remove permissionPromptToolName, or remove canUseTool."
1318
1440
  );
@@ -1320,11 +1442,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1320
1442
  const sdkPrompt = wantsStreamInput ? toAsyncIterablePrompt(
1321
1443
  messagesPrompt,
1322
1444
  outputStreamEnded,
1323
- this.settings.resume ?? this.sessionId,
1445
+ effectiveResume,
1324
1446
  streamingContentParts
1325
1447
  ) : messagesPrompt;
1326
1448
  this.logger.debug(
1327
- `[claude-code] Starting stream query with streamingInput: ${wantsStreamInput}, session: ${this.settings.resume ?? this.sessionId ?? "new"}`
1449
+ `[claude-code] Starting stream query with streamingInput: ${wantsStreamInput}, session: ${effectiveResume ?? "new"}`
1328
1450
  );
1329
1451
  const response = (0, import_claude_agent_sdk.query)({
1330
1452
  prompt: sdkPrompt,
@@ -1376,6 +1498,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1376
1498
  });
1377
1499
  accumulatedText += jsonDelta;
1378
1500
  streamedTextLength += jsonDelta.length;
1501
+ hasStreamedJson = true;
1379
1502
  }
1380
1503
  }
1381
1504
  continue;
@@ -1388,7 +1511,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1388
1511
  continue;
1389
1512
  }
1390
1513
  const content = message.message.content;
1391
- for (const tool3 of this.extractToolUses(content)) {
1514
+ const tools = this.extractToolUses(content);
1515
+ if (textPartId && tools.length > 0) {
1516
+ controller.enqueue({
1517
+ type: "text-end",
1518
+ id: textPartId
1519
+ });
1520
+ textPartId = void 0;
1521
+ }
1522
+ for (const tool3 of tools) {
1392
1523
  const toolId = tool3.id;
1393
1524
  let state = toolStates.get(toolId);
1394
1525
  if (!state) {
@@ -1595,6 +1726,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1595
1726
  }
1596
1727
  } else if (message.type === "result") {
1597
1728
  done();
1729
+ if ("is_error" in message && message.is_error === true) {
1730
+ const errorMessage = "result" in message && typeof message.result === "string" ? message.result : "Claude Code CLI returned an error";
1731
+ throw Object.assign(new Error(errorMessage), { exitCode: 1 });
1732
+ }
1598
1733
  if (message.subtype === "error_max_structured_output_retries") {
1599
1734
  throw new Error(
1600
1735
  "Failed to generate valid structured output after maximum retries. The model could not produce a response matching the required schema."
@@ -1615,12 +1750,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1615
1750
  this.logger.debug(`[claude-code] Stream finish reason: ${finishReason.unified}`);
1616
1751
  this.setSessionId(message.session_id);
1617
1752
  const structuredOutput = "structured_output" in message ? message.structured_output : void 0;
1618
- const alreadyStreamedJson = textPartId && options.responseFormat?.type === "json" && hasReceivedStreamEvents;
1619
- if (alreadyStreamedJson && textPartId) {
1620
- controller.enqueue({
1621
- type: "text-end",
1622
- id: textPartId
1623
- });
1753
+ const alreadyStreamedJson = hasStreamedJson && options.responseFormat?.type === "json" && hasReceivedStreamEvents;
1754
+ if (alreadyStreamedJson) {
1755
+ if (textPartId) {
1756
+ controller.enqueue({
1757
+ type: "text-end",
1758
+ id: textPartId
1759
+ });
1760
+ }
1624
1761
  } else if (structuredOutput !== void 0) {
1625
1762
  const jsonTextId = (0, import_provider_utils.generateId)();
1626
1763
  const jsonText = JSON.stringify(structuredOutput);
@@ -1753,7 +1890,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1753
1890
  if (isAbortError(error)) {
1754
1891
  errorToEmit = options.abortSignal?.aborted ? options.abortSignal.reason : error;
1755
1892
  } else {
1756
- errorToEmit = this.handleClaudeCodeError(error, messagesPrompt);
1893
+ errorToEmit = this.handleClaudeCodeError(error, messagesPrompt, collectedStderr);
1757
1894
  }
1758
1895
  controller.enqueue({
1759
1896
  type: "error",