ai-sdk-provider-claude-code 3.5.3 → 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/dist/index.js CHANGED
@@ -3,11 +3,21 @@ import { NoSuchModelError as NoSuchModelError2 } from "@ai-sdk/provider";
3
3
 
4
4
  // src/claude-code-language-model.ts
5
5
  import { NoSuchModelError, APICallError as APICallError2, LoadAPIKeyError as LoadAPIKeyError2 } from "@ai-sdk/provider";
6
- import { generateId } from "@ai-sdk/provider-utils";
6
+ import {
7
+ generateId,
8
+ isCustomReasoning,
9
+ mapReasoningToProviderEffort
10
+ } from "@ai-sdk/provider-utils";
7
11
 
8
12
  // src/convert-to-claude-code-messages.ts
13
+ import { detectMediaType } from "@ai-sdk/provider-utils";
9
14
  var IMAGE_URL_WARNING = "Image URLs are not supported by this provider; supply base64/data URLs.";
10
15
  var IMAGE_CONVERSION_WARNING = "Unable to convert image content; supply base64/data URLs.";
16
+ var FILE_REFERENCE_WARNING = "Provider file references are not supported by this provider; supply inline file data.";
17
+ function createUnsupportedFilePartWarning(mediaType) {
18
+ const mediaTypeLabel = mediaType && mediaType.trim() ? mediaType : "unknown";
19
+ return `Unsupported file part (${mediaTypeLabel}) was ignored; this provider forwards only image file parts inline.`;
20
+ }
11
21
  var MAX_TOOL_CALL_INPUT_LENGTH = 1e3;
12
22
  function serializeToolCallInput(input) {
13
23
  let serialized;
@@ -25,42 +35,75 @@ function serializeToolCallInput(input) {
25
35
  }
26
36
  return serialized;
27
37
  }
28
- function normalizeBase64(base64) {
29
- return base64.replace(/\s+/g, "");
38
+ function getVariantName(value, discriminator) {
39
+ if (typeof value === "object" && value !== null) {
40
+ const candidate = value[discriminator];
41
+ if (typeof candidate === "string" && candidate) {
42
+ return candidate;
43
+ }
44
+ }
45
+ return String(value);
46
+ }
47
+ function createUnknownPromptVariantWarning(value, context, discriminator = "type") {
48
+ return `Unsupported ${context} ${discriminator} '${getVariantName(
49
+ value,
50
+ discriminator
51
+ )}' was skipped.`;
52
+ }
53
+ function extractMimeType(candidate) {
54
+ if (typeof candidate === "string" && candidate.trim()) {
55
+ return candidate.trim();
56
+ }
57
+ return void 0;
58
+ }
59
+ function normalizeMediaType(mediaType) {
60
+ return mediaType.trim().toLowerCase();
61
+ }
62
+ function isImageMimeType(mediaType) {
63
+ if (!mediaType) {
64
+ return false;
65
+ }
66
+ const normalized = normalizeMediaType(mediaType);
67
+ return normalized === "image" || normalized === "image/*" || normalized.startsWith("image/");
30
68
  }
31
- function isImageMimeType(mimeType) {
32
- return typeof mimeType === "string" && mimeType.trim().toLowerCase().startsWith("image/");
69
+ function isConcreteImageMimeType(mediaType) {
70
+ const normalized = normalizeMediaType(mediaType);
71
+ return normalized.startsWith("image/") && !normalized.endsWith("/*");
72
+ }
73
+ function resolveImageMediaType(mediaType, data) {
74
+ const normalizedMediaType = normalizeMediaType(mediaType);
75
+ if (isConcreteImageMimeType(normalizedMediaType)) {
76
+ return normalizedMediaType;
77
+ }
78
+ if ((normalizedMediaType === "image" || normalizedMediaType === "image/*") && data) {
79
+ try {
80
+ const detectedMediaType = detectMediaType({ data, topLevelType: "image" });
81
+ if (detectedMediaType && isConcreteImageMimeType(detectedMediaType)) {
82
+ return detectedMediaType;
83
+ }
84
+ } catch {
85
+ return void 0;
86
+ }
87
+ }
88
+ return void 0;
33
89
  }
34
90
  function createImageContent(mediaType, data) {
35
- const trimmedType = mediaType.trim();
36
- const trimmedData = normalizeBase64(data.trim());
37
- if (!trimmedType || !trimmedData) {
91
+ const normalizedType = normalizeMediaType(mediaType);
92
+ const trimmedData = data.trim().replace(/\s+/g, "");
93
+ if (!isConcreteImageMimeType(normalizedType) || !trimmedData) {
38
94
  return void 0;
39
95
  }
40
96
  return {
41
97
  type: "image",
42
98
  source: {
43
99
  type: "base64",
44
- media_type: trimmedType,
100
+ media_type: normalizedType,
45
101
  data: trimmedData
46
102
  }
47
103
  };
48
104
  }
49
- function extractMimeType(candidate) {
50
- if (typeof candidate === "string" && candidate.trim()) {
51
- return candidate.trim();
52
- }
53
- return void 0;
54
- }
55
- function parseObjectImage(imageObj, fallbackMimeType) {
56
- const data = typeof imageObj.data === "string" ? imageObj.data : void 0;
57
- const mimeType = extractMimeType(
58
- imageObj.mimeType ?? imageObj.mediaType ?? imageObj.media_type ?? fallbackMimeType
59
- );
60
- if (!data || !mimeType) {
61
- return void 0;
62
- }
63
- return createImageContent(mimeType, data);
105
+ function resolveStringImageMediaType(mediaType, data, fallbackMimeType) {
106
+ return resolveImageMediaType(mediaType, data) ?? (fallbackMimeType ? resolveImageMediaType(fallbackMimeType, data) : void 0);
64
107
  }
65
108
  function parseStringImage(value, fallbackMimeType) {
66
109
  const trimmed = value.trim();
@@ -70,41 +113,31 @@ function parseStringImage(value, fallbackMimeType) {
70
113
  const dataUrlMatch = trimmed.match(/^data:([^;]+);base64,(.+)$/i);
71
114
  if (dataUrlMatch) {
72
115
  const [, mediaType, data] = dataUrlMatch;
73
- const content = createImageContent(mediaType, data);
116
+ const resolvedMediaType = resolveStringImageMediaType(mediaType, data, fallbackMimeType);
117
+ const content = resolvedMediaType ? createImageContent(resolvedMediaType, data) : void 0;
74
118
  return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
75
119
  }
76
120
  const base64Match = trimmed.match(/^base64:([^,]+),(.+)$/i);
77
121
  if (base64Match) {
78
122
  const [, explicitMimeType, data] = base64Match;
79
- const content = createImageContent(explicitMimeType, data);
123
+ const resolvedMediaType = resolveStringImageMediaType(explicitMimeType, data, fallbackMimeType);
124
+ const content = resolvedMediaType ? createImageContent(resolvedMediaType, data) : void 0;
80
125
  return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
81
126
  }
82
127
  if (fallbackMimeType) {
83
- const content = createImageContent(fallbackMimeType, trimmed);
84
- if (content) {
85
- return { content };
128
+ const resolvedMediaType = resolveImageMediaType(fallbackMimeType, trimmed);
129
+ if (resolvedMediaType) {
130
+ const content = createImageContent(resolvedMediaType, trimmed);
131
+ if (content) {
132
+ return { content };
133
+ }
86
134
  }
87
135
  }
88
136
  return { warning: IMAGE_CONVERSION_WARNING };
89
137
  }
90
- function parseImagePart(part) {
91
- if (!part || typeof part !== "object") {
92
- return { warning: IMAGE_CONVERSION_WARNING };
93
- }
94
- const imageValue = part.image;
95
- const mimeType = extractMimeType(part.mimeType);
96
- if (typeof imageValue === "string") {
97
- return parseStringImage(imageValue, mimeType);
98
- }
99
- if (imageValue && typeof imageValue === "object") {
100
- const content = parseObjectImage(imageValue, mimeType);
101
- return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
102
- }
103
- return { warning: IMAGE_CONVERSION_WARNING };
104
- }
105
138
  function convertBinaryToBase64(data) {
106
139
  if (typeof Buffer !== "undefined") {
107
- const buffer = data instanceof Uint8Array ? Buffer.from(data) : Buffer.from(new Uint8Array(data));
140
+ const buffer = data instanceof Uint8Array ? Buffer.from(data.buffer, data.byteOffset, data.byteLength) : Buffer.from(data);
108
141
  return buffer.toString("base64");
109
142
  }
110
143
  if (typeof btoa === "function") {
@@ -120,24 +153,102 @@ function convertBinaryToBase64(data) {
120
153
  return void 0;
121
154
  }
122
155
  function parseFilePart(part) {
123
- const mimeType = extractMimeType(part.mediaType ?? part.mimeType);
124
- if (!mimeType || !isImageMimeType(mimeType)) {
125
- return {};
156
+ const mediaType = extractMimeType(part.mediaType);
157
+ const fileData = part.data;
158
+ switch (fileData.type) {
159
+ case "data": {
160
+ if (!mediaType || !isImageMimeType(mediaType)) {
161
+ return { warning: createUnsupportedFilePartWarning(mediaType) };
162
+ }
163
+ if (typeof fileData.data === "string") {
164
+ return parseStringImage(fileData.data, mediaType);
165
+ }
166
+ const resolvedMediaType = resolveImageMediaType(mediaType, fileData.data);
167
+ if (!resolvedMediaType) {
168
+ return { warning: IMAGE_CONVERSION_WARNING };
169
+ }
170
+ const base64 = convertBinaryToBase64(fileData.data);
171
+ if (!base64) {
172
+ return { warning: IMAGE_CONVERSION_WARNING };
173
+ }
174
+ const content = createImageContent(resolvedMediaType, base64);
175
+ return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
176
+ }
177
+ case "url": {
178
+ if (!mediaType || !isImageMimeType(mediaType)) {
179
+ return { warning: createUnsupportedFilePartWarning(mediaType) };
180
+ }
181
+ const url = fileData.url.toString();
182
+ if (!/^data:/i.test(url.trim())) {
183
+ return { warning: IMAGE_URL_WARNING };
184
+ }
185
+ return parseStringImage(url, mediaType);
186
+ }
187
+ case "text":
188
+ return fileData.text ? { text: fileData.text } : {};
189
+ case "reference":
190
+ return { warning: FILE_REFERENCE_WARNING };
191
+ default: {
192
+ const unknownFileData = fileData;
193
+ return {
194
+ warning: createUnknownPromptVariantWarning(unknownFileData, "prompt file data")
195
+ };
196
+ }
126
197
  }
127
- const data = part.data;
128
- if (typeof data === "string") {
129
- const content = createImageContent(mimeType, data);
130
- return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
198
+ }
199
+ function serializeToolResultFilePart(part, warnings) {
200
+ const fileData = part.data;
201
+ const fileLabel = part.filename ? `File ${part.filename}` : "File";
202
+ switch (fileData.type) {
203
+ case "data":
204
+ return `[${fileLabel}: ${part.mediaType}]`;
205
+ case "url":
206
+ return `[${fileLabel}: ${part.mediaType}: ${fileData.url.toString()}]`;
207
+ case "text":
208
+ return fileData.text;
209
+ case "reference":
210
+ warnings.push(FILE_REFERENCE_WARNING);
211
+ return void 0;
212
+ default: {
213
+ const unknownFileData = fileData;
214
+ warnings.push(createUnknownPromptVariantWarning(unknownFileData, "tool result file data"));
215
+ return void 0;
216
+ }
131
217
  }
132
- if (data instanceof Uint8Array || typeof ArrayBuffer !== "undefined" && data instanceof ArrayBuffer) {
133
- const base64 = convertBinaryToBase64(data);
134
- if (!base64) {
135
- return { warning: IMAGE_CONVERSION_WARNING };
218
+ }
219
+ function serializeToolResultContentPart(part, warnings) {
220
+ switch (part.type) {
221
+ case "text":
222
+ return part.text;
223
+ case "file":
224
+ return serializeToolResultFilePart(part, warnings);
225
+ case "custom":
226
+ return void 0;
227
+ default: {
228
+ const unknownPart = part;
229
+ warnings.push(createUnknownPromptVariantWarning(unknownPart, "tool result content part"));
230
+ return void 0;
231
+ }
232
+ }
233
+ }
234
+ function serializeToolResultOutput(output, warnings) {
235
+ switch (output.type) {
236
+ case "text":
237
+ case "error-text":
238
+ return output.value;
239
+ case "json":
240
+ case "error-json":
241
+ return JSON.stringify(output.value) ?? String(output.value);
242
+ case "execution-denied":
243
+ return `[Execution denied${output.reason ? `: ${output.reason}` : ""}]`;
244
+ case "content":
245
+ return output.value.map((part) => serializeToolResultContentPart(part, warnings)).filter((text) => typeof text === "string" && text.length > 0).join("\n");
246
+ default: {
247
+ const unknownOutput = output;
248
+ warnings.push(createUnknownPromptVariantWarning(unknownOutput, "tool result output"));
249
+ return void 0;
136
250
  }
137
- const content = createImageContent(mimeType, base64);
138
- return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
139
251
  }
140
- return { warning: IMAGE_CONVERSION_WARNING };
141
252
  }
142
253
  function convertToClaudeCodeMessages(prompt) {
143
254
  const messages = [];
@@ -157,89 +268,149 @@ function convertToClaudeCodeMessages(prompt) {
157
268
  }
158
269
  imageMap.get(segmentIndex)?.push(content);
159
270
  };
271
+ const addWarning = (warning) => {
272
+ if (warning) {
273
+ warnings.push(warning);
274
+ }
275
+ };
160
276
  for (const message of prompt) {
161
277
  switch (message.role) {
162
278
  case "system":
163
- systemPrompt = message.content;
164
- if (typeof message.content === "string" && message.content.trim().length > 0) {
279
+ systemPrompt = systemPrompt === void 0 ? message.content : `${systemPrompt}
280
+
281
+ ${message.content}`;
282
+ if (message.content.trim().length > 0) {
165
283
  addSegment(message.content);
166
284
  } else {
167
285
  addSegment("");
168
286
  }
169
287
  break;
170
- case "user":
171
- if (typeof message.content === "string") {
172
- messages.push(message.content);
173
- addSegment(`Human: ${message.content}`);
174
- } else {
175
- const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
176
- const segmentIndex = addSegment(textParts ? `Human: ${textParts}` : "");
177
- if (textParts) {
178
- messages.push(textParts);
179
- }
180
- for (const part of message.content) {
181
- if (part.type === "image") {
182
- const { content, warning } = parseImagePart(part);
183
- if (content) {
184
- addImageForSegment(segmentIndex, content);
185
- } else if (warning) {
186
- warnings.push(warning);
288
+ case "user": {
289
+ const textParts = [];
290
+ const imageParts = [];
291
+ for (const part of message.content) {
292
+ switch (part.type) {
293
+ case "text":
294
+ if (typeof part.text === "string") {
295
+ textParts.push(part.text);
296
+ }
297
+ break;
298
+ case "file": {
299
+ const { content, text, warning } = parseFilePart(part);
300
+ if (typeof text === "string") {
301
+ textParts.push(text);
187
302
  }
188
- } else if (part.type === "file") {
189
- const { content, warning } = parseFilePart(part);
190
303
  if (content) {
191
- addImageForSegment(segmentIndex, content);
192
- } else if (warning) {
193
- warnings.push(warning);
304
+ imageParts.push(content);
194
305
  }
306
+ addWarning(warning);
307
+ break;
308
+ }
309
+ default: {
310
+ const unknownPart = part;
311
+ addWarning(
312
+ createUnknownPromptVariantWarning(unknownPart, "prompt user content part")
313
+ );
314
+ break;
195
315
  }
196
316
  }
197
317
  }
318
+ const textContent = textParts.join("\n");
319
+ const segmentIndex = addSegment(textContent ? `Human: ${textContent}` : "");
320
+ if (textContent) {
321
+ messages.push(`Human: ${textContent}`);
322
+ }
323
+ for (const imagePart of imageParts) {
324
+ addImageForSegment(segmentIndex, imagePart);
325
+ }
198
326
  break;
327
+ }
199
328
  case "assistant": {
200
- let assistantContent = "";
201
- if (typeof message.content === "string") {
202
- assistantContent = message.content;
203
- } else {
204
- const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
205
- if (textParts) {
206
- assistantContent = textParts;
207
- }
208
- const toolCalls = message.content.filter((part) => part.type === "tool-call");
209
- if (toolCalls.length > 0) {
210
- const serializedCalls = toolCalls.map((call) => `[Tool call: ${call.toolName}(${serializeToolCallInput(call.input)})]`).join("\n");
211
- assistantContent += assistantContent ? `
212
- ${serializedCalls}` : serializedCalls;
329
+ const assistantParts = [];
330
+ const imageParts = [];
331
+ for (const part of message.content) {
332
+ switch (part.type) {
333
+ case "text":
334
+ if (typeof part.text === "string") {
335
+ assistantParts.push(part.text);
336
+ }
337
+ break;
338
+ case "tool-call":
339
+ assistantParts.push(
340
+ `[Tool call: ${part.toolName}(${serializeToolCallInput(part.input)})]`
341
+ );
342
+ break;
343
+ case "tool-result": {
344
+ const output = serializeToolResultOutput(part.output, warnings);
345
+ if (output !== void 0) {
346
+ assistantParts.push(`Tool Result (${part.toolName}): ${output}`);
347
+ }
348
+ break;
349
+ }
350
+ case "file": {
351
+ const { content, text, warning } = parseFilePart(part);
352
+ if (typeof text === "string") {
353
+ assistantParts.push(text);
354
+ }
355
+ if (content) {
356
+ imageParts.push(content);
357
+ }
358
+ addWarning(warning);
359
+ break;
360
+ }
361
+ case "reasoning":
362
+ break;
363
+ case "reasoning-file":
364
+ break;
365
+ case "custom":
366
+ break;
367
+ default: {
368
+ const unknownPart = part;
369
+ addWarning(
370
+ createUnknownPromptVariantWarning(unknownPart, "prompt assistant content part")
371
+ );
372
+ break;
373
+ }
213
374
  }
214
375
  }
376
+ const assistantContent = assistantParts.join("\n");
215
377
  const formattedAssistant = `Assistant: ${assistantContent}`;
216
378
  messages.push(formattedAssistant);
217
- addSegment(formattedAssistant);
379
+ const segmentIndex = addSegment(formattedAssistant);
380
+ for (const imagePart of imageParts) {
381
+ addImageForSegment(segmentIndex, imagePart);
382
+ }
218
383
  break;
219
384
  }
220
385
  case "tool":
221
386
  for (const tool3 of message.content) {
222
- if (tool3.type === "tool-approval-response") {
223
- continue;
224
- }
225
- let resultText;
226
- const output = tool3.output;
227
- if (output.type === "text" || output.type === "error-text") {
228
- resultText = output.value;
229
- } else if (output.type === "json" || output.type === "error-json") {
230
- resultText = JSON.stringify(output.value);
231
- } else if (output.type === "execution-denied") {
232
- resultText = `[Execution denied${output.reason ? `: ${output.reason}` : ""}]`;
233
- } else if (output.type === "content") {
234
- resultText = output.value.filter((part) => part.type === "text").map((part) => part.text).join("\n");
235
- } else {
236
- resultText = "[Unknown output type]";
387
+ switch (tool3.type) {
388
+ case "tool-result": {
389
+ const output = serializeToolResultOutput(tool3.output, warnings);
390
+ if (output !== void 0) {
391
+ const formattedToolResult = `Tool Result (${tool3.toolName}): ${output}`;
392
+ messages.push(formattedToolResult);
393
+ addSegment(formattedToolResult);
394
+ }
395
+ break;
396
+ }
397
+ case "tool-approval-response":
398
+ break;
399
+ default: {
400
+ const unknownPart = tool3;
401
+ addWarning(
402
+ createUnknownPromptVariantWarning(unknownPart, "prompt tool content part")
403
+ );
404
+ break;
405
+ }
237
406
  }
238
- const formattedToolResult = `Tool Result (${tool3.toolName}): ${resultText}`;
239
- messages.push(formattedToolResult);
240
- addSegment(formattedToolResult);
241
407
  }
242
408
  break;
409
+ default: {
410
+ const unknownMessage = message;
411
+ addWarning(createUnknownPromptVariantWarning(unknownMessage, "prompt message", "role"));
412
+ break;
413
+ }
243
414
  }
244
415
  }
245
416
  let finalPrompt = "";
@@ -249,12 +420,7 @@ ${serializedCalls}` : serializedCalls;
249
420
  if (messages.length > 0) {
250
421
  const formattedMessages = [];
251
422
  for (let i = 0; i < messages.length; i++) {
252
- const msg = messages[i];
253
- if (msg.startsWith("Assistant:") || msg.startsWith("Tool Result")) {
254
- formattedMessages.push(msg);
255
- } else {
256
- formattedMessages.push(`Human: ${msg}`);
257
- }
423
+ formattedMessages.push(messages[i]);
258
424
  }
259
425
  if (finalPrompt) {
260
426
  const joinedMessages = formattedMessages.join("\n\n");
@@ -322,21 +488,6 @@ ${segmentText}`;
322
488
 
323
489
  // src/errors.ts
324
490
  import { APICallError, LoadAPIKeyError } from "@ai-sdk/provider";
325
- var STDERR_TAIL_MARKER = " | stderr (tail):";
326
- var ANSI_ESCAPE_SEQUENCE = (
327
- // eslint-disable-next-line no-control-regex
328
- /\x1b(?:\][^\x07\x1b]*(?:\x07|\x1b\\)|\[[0-?]*[ -/]*[@-~])/g
329
- );
330
- function stderrTail(raw) {
331
- const withoutAnsi = raw.replace(ANSI_ESCAPE_SEQUENCE, "");
332
- const withoutControlCharacters = Array.from(withoutAnsi).filter((character) => {
333
- const codePoint = character.codePointAt(0) ?? 0;
334
- return character === "\r" || character === "\n" || codePoint === 8232 || codePoint === 8233 || codePoint >= 32 && codePoint < 127 || codePoint > 159;
335
- }).join("");
336
- const tail = withoutControlCharacters.split(/\r\n|\r|\n|\u2028|\u2029/).map((line) => line.trim()).filter((line) => line.length > 0).slice(-5).join("; ");
337
- const codePoints = Array.from(tail);
338
- return codePoints.length > 600 ? `\u2026${codePoints.slice(-599).join("")}` : tail;
339
- }
340
491
  function createAPICallError({
341
492
  message,
342
493
  code,
@@ -351,37 +502,26 @@ function createAPICallError({
351
502
  stderr,
352
503
  promptExcerpt
353
504
  };
354
- const tail = typeof stderr === "string" && stderr.length > 0 ? stderrTail(stderr) : "";
355
- const enrichedMessage = tail && !message.includes(STDERR_TAIL_MARKER) ? `${message}${STDERR_TAIL_MARKER} ${tail}` : message;
356
505
  return new APICallError({
357
- message: enrichedMessage,
506
+ message,
358
507
  isRetryable,
359
508
  url: "claude-code-cli://command",
360
509
  requestBodyValues: promptExcerpt ? { prompt: promptExcerpt } : void 0,
361
510
  data: metadata
362
511
  });
363
512
  }
364
- function createAuthenticationError({
365
- message,
366
- stderr
367
- }) {
368
- const error = new LoadAPIKeyError({
513
+ function createAuthenticationError({ message }) {
514
+ return new LoadAPIKeyError({
369
515
  message: message || "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
370
516
  });
371
- if (stderr) {
372
- error.data = { stderr };
373
- }
374
- return error;
375
517
  }
376
518
  function createTimeoutError({
377
519
  message,
378
- stderr,
379
520
  promptExcerpt,
380
521
  timeoutMs
381
522
  }) {
382
523
  const metadata = {
383
524
  code: "TIMEOUT",
384
- stderr,
385
525
  promptExcerpt
386
526
  };
387
527
  return new APICallError({
@@ -407,9 +547,6 @@ function getErrorMetadata(error) {
407
547
  if (error instanceof APICallError && error.data) {
408
548
  return error.data;
409
549
  }
410
- if (error instanceof LoadAPIKeyError && error.data) {
411
- return error.data;
412
- }
413
550
  return void 0;
414
551
  }
415
552
 
@@ -561,6 +698,18 @@ var claudeCodeSettingsSchema = z.object({
561
698
  forwardSubagentText: z.boolean().optional(),
562
699
  agentProgressSummaries: z.boolean().optional(),
563
700
  includeHookEvents: z.boolean().optional(),
701
+ onSdkMessage: z.any().refine((v) => v === void 0 || typeof v === "function", {
702
+ message: "onSdkMessage must be a function"
703
+ }).optional(),
704
+ onTaskEvent: z.any().refine((v) => v === void 0 || typeof v === "function", {
705
+ message: "onTaskEvent must be a function"
706
+ }).optional(),
707
+ onHookEvent: z.any().refine((v) => v === void 0 || typeof v === "function", {
708
+ message: "onHookEvent must be a function"
709
+ }).optional(),
710
+ onMcpStatusChange: z.any().refine((v) => v === void 0 || typeof v === "function", {
711
+ message: "onMcpStatusChange must be a function"
712
+ }).optional(),
564
713
  taskBudget: z.object({ total: z.number().positive() }).strict().optional(),
565
714
  sessionStore: z.any().refine(
566
715
  (val) => val === void 0 || typeof val === "object" && val !== null && typeof val.append === "function" && typeof val.load === "function",
@@ -577,6 +726,9 @@ var claudeCodeSettingsSchema = z.object({
577
726
  onUserDialog: z.any().refine((v) => v === void 0 || typeof v === "function", {
578
727
  message: "onUserDialog must be a function"
579
728
  }).optional(),
729
+ onElicitation: z.any().refine((v) => v === void 0 || typeof v === "function", {
730
+ message: "onElicitation must be a function"
731
+ }).optional(),
580
732
  supportedDialogKinds: z.array(z.string()).optional(),
581
733
  hooks: z.record(
582
734
  z.string(),
@@ -623,6 +775,7 @@ var claudeCodeSettingsSchema = z.object({
623
775
  logger: z.union([z.literal(false), loggerFunctionSchema]).optional(),
624
776
  env: z.record(z.string(), z.string().optional()).optional(),
625
777
  additionalDirectories: z.array(z.string()).optional(),
778
+ agent: z.string().optional(),
626
779
  agents: z.record(
627
780
  z.string(),
628
781
  z.object({
@@ -660,10 +813,13 @@ var claudeCodeSettingsSchema = z.object({
660
813
  onQueryCreated: z.any().refine((val) => val === void 0 || typeof val === "function", {
661
814
  message: "onQueryCreated must be a function"
662
815
  }).optional(),
816
+ onQueryControllerCreated: z.any().refine((val) => val === void 0 || typeof val === "function", {
817
+ message: "onQueryControllerCreated must be a function"
818
+ }).optional(),
663
819
  onStreamStart: z.any().refine((val) => val === void 0 || typeof val === "function", {
664
820
  message: "onStreamStart must be a function"
665
821
  }).optional(),
666
- // Callback invoked with the predicted next user prompt (active unless promptSuggestions: false)
822
+ // Callback invoked with the predicted next user prompt (requires promptSuggestions: true)
667
823
  onPromptSuggestion: z.any().refine((val) => val === void 0 || typeof val === "function", {
668
824
  message: "onPromptSuggestion must be a function"
669
825
  }).optional()
@@ -748,6 +904,11 @@ function validateSettings(settings) {
748
904
  `Very high maxThinkingTokens (${validSettings.maxThinkingTokens}) may increase response time`
749
905
  );
750
906
  }
907
+ if (validSettings.onPromptSuggestion !== void 0 && effective("promptSuggestions") !== true) {
908
+ warnings.push(
909
+ "onPromptSuggestion is registered but promptSuggestions is not enabled. The CLI only emits prompt_suggestion messages when promptSuggestions is true, so the callback will never fire. Set promptSuggestions: true."
910
+ );
911
+ }
751
912
  if (validSettings.allowedTools && validSettings.disallowedTools) {
752
913
  warnings.push(
753
914
  "Both allowedTools and disallowedTools are specified. Only allowedTools will be used."
@@ -985,18 +1146,41 @@ function createVerboseLogger(logger, verbose = false) {
985
1146
  };
986
1147
  }
987
1148
 
1149
+ // src/query-controller.ts
1150
+ function createClaudeCodeQueryController(query2) {
1151
+ const controller = {
1152
+ rawQuery: query2,
1153
+ // SDK 0.3.205 returns the control-protocol response; the public contract stays Promise<void>.
1154
+ interrupt: async () => {
1155
+ await query2.interrupt();
1156
+ },
1157
+ setPermissionMode: (mode) => query2.setPermissionMode(mode),
1158
+ setMcpPermissionModeOverride: (serverName, mode) => query2.setMcpPermissionModeOverride(serverName, mode),
1159
+ setModel: (model) => query2.setModel(model),
1160
+ setMaxThinkingTokens: (maxThinkingTokens, thinkingDisplay) => query2.setMaxThinkingTokens(maxThinkingTokens, thinkingDisplay),
1161
+ applyFlagSettings: (settings) => query2.applyFlagSettings(settings),
1162
+ mcpServerStatus: () => query2.mcpServerStatus(),
1163
+ reconnectMcpServer: (serverName) => query2.reconnectMcpServer(serverName),
1164
+ toggleMcpServer: (serverName, enabled) => query2.toggleMcpServer(serverName, enabled),
1165
+ setMcpServers: (servers) => query2.setMcpServers(servers),
1166
+ getContextUsage: () => query2.getContextUsage(),
1167
+ rewindFiles: (userMessageId, options) => query2.rewindFiles(userMessageId, options),
1168
+ stopTask: (taskId) => query2.stopTask(taskId),
1169
+ backgroundTasks: (toolUseId) => toolUseId === void 0 ? query2.backgroundTasks() : query2.backgroundTasks(toolUseId)
1170
+ };
1171
+ const streamInput = query2.streamInput;
1172
+ if (typeof streamInput === "function") {
1173
+ controller.streamInput = (stream) => streamInput.call(query2, stream);
1174
+ }
1175
+ return controller;
1176
+ }
1177
+
988
1178
  // src/claude-code-language-model.ts
989
1179
  import { query } from "@anthropic-ai/claude-agent-sdk";
990
- var PROVIDER_VERSION = "3.5.3";
1180
+ var PROVIDER_VERSION = "4.0.0";
991
1181
  var DEFAULT_CLIENT_APP = `ai-sdk-provider-claude-code/${PROVIDER_VERSION}`;
992
1182
  var CLAUDE_CODE_TRUNCATION_WARNING = "Claude Code SDK output ended unexpectedly; returning truncated response from buffered text. Await upstream fix to avoid data loss.";
993
1183
  var MIN_TRUNCATION_LENGTH = 512;
994
- function capStderr(raw) {
995
- if (raw.length <= 4e3) {
996
- return raw;
997
- }
998
- return Array.from(raw).slice(-4e3).join("");
999
- }
1000
1184
  function isClaudeCodeTruncationError(error, bufferedText) {
1001
1185
  const isSyntaxError = error instanceof SyntaxError || // eslint-disable-next-line @typescript-eslint/no-explicit-any
1002
1186
  typeof error?.name === "string" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1027,6 +1211,13 @@ function isClaudeCodeTruncationError(error, bufferedText) {
1027
1211
  return true;
1028
1212
  }
1029
1213
  var MISSING_STRUCTURED_OUTPUT_ERROR_MESSAGE = "Structured output was requested (responseFormat with a JSON schema) but the Claude Code CLI returned no structured_output, and the prose response could not be parsed as JSON. This usually means the schema contains constructs the CLI cannot enforce (e.g. complex regex patterns with lookaheads/backreferences), causing it to silently fall back to prose. Simplify the generation schema and validate strictly client-side. See the 'Structured Outputs' section of the ai-sdk-provider-claude-code README for the list of known limitations.";
1214
+ var INTERNAL_STRUCTURED_OUTPUT_TOOL_NAME = "StructuredOutput";
1215
+ function isInternalStructuredOutputTool(toolName, options) {
1216
+ return options.responseFormat?.type === "json" && toolName === INTERNAL_STRUCTURED_OUTPUT_TOOL_NAME;
1217
+ }
1218
+ function isNonTextToolUseContentBlockType(type) {
1219
+ return type === "server_tool_use" || type === "mcp_tool_use";
1220
+ }
1030
1221
  function extractJsonObjectText(text) {
1031
1222
  const trimmed = text.trim();
1032
1223
  if (!trimmed) {
@@ -1120,7 +1311,7 @@ function getBaseProcessEnv() {
1120
1311
  }
1121
1312
  return env;
1122
1313
  }
1123
- 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).";
1314
+ var STREAMING_FEATURE_WARNING = "Claude Agent SDK image input requires streaming input. Set `streamingInput: 'auto'` or `streamingInput: 'always'`; `streamingInput: 'off'` disables streaming image input.";
1124
1315
  var SDK_OPTIONS_BLOCKLIST = /* @__PURE__ */ new Set(["model", "abortController", "prompt", "outputFormat"]);
1125
1316
  var SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
1126
1317
  function isSubagentToolName(name) {
@@ -1143,7 +1334,7 @@ function computeRetractedToolCallIds(retracted, descriptors) {
1143
1334
  function applySupersede(message, evict, logger, guard = "array") {
1144
1335
  const supersedes = message.supersedes;
1145
1336
  const triggered = guard === "truthy" ? Boolean(supersedes && supersedes.length > 0) : Array.isArray(supersedes) && supersedes.length > 0;
1146
- if (!triggered) {
1337
+ if (!triggered || supersedes === void 0) {
1147
1338
  return false;
1148
1339
  }
1149
1340
  logger.debug(`[claude-code] Assistant message supersedes ${supersedes.length} prior message(s)`);
@@ -1156,12 +1347,126 @@ function buildRetractionEvictor(evict) {
1156
1347
  var INFORMATIONAL_SYSTEM_SUBTYPES = /* @__PURE__ */ new Set([
1157
1348
  "notification",
1158
1349
  "status",
1159
- "task_updated",
1160
1350
  "session_state_changed",
1161
1351
  "commands_changed",
1162
1352
  "memory_recall",
1163
- "plugin_install"
1353
+ "plugin_install",
1354
+ "informational"
1164
1355
  ]);
1356
+ var CLAUDE_REASONING_EFFORT_MAP = {
1357
+ minimal: "low",
1358
+ low: "low",
1359
+ medium: "medium",
1360
+ high: "high",
1361
+ xhigh: "xhigh"
1362
+ };
1363
+ var CLAUDE_EFFORT_LEVELS = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh", "max"]);
1364
+ function isObjectRecord(value) {
1365
+ return typeof value === "object" && value !== null;
1366
+ }
1367
+ function toJsonSafeValue(value) {
1368
+ if (value === void 0) {
1369
+ return void 0;
1370
+ }
1371
+ try {
1372
+ const serialized = JSON.stringify(value);
1373
+ return serialized === void 0 ? void 0 : JSON.parse(serialized);
1374
+ } catch {
1375
+ return String(value);
1376
+ }
1377
+ }
1378
+ function deepFreezeJsonValue(value) {
1379
+ if (Array.isArray(value)) {
1380
+ for (const nested of value) {
1381
+ deepFreezeJsonValue(nested);
1382
+ }
1383
+ return Object.freeze(value);
1384
+ }
1385
+ if (!isObjectRecord(value)) {
1386
+ return value;
1387
+ }
1388
+ const objectValue = value;
1389
+ for (const nested of Object.values(objectValue)) {
1390
+ if (nested !== void 0) {
1391
+ deepFreezeJsonValue(nested);
1392
+ }
1393
+ }
1394
+ return Object.freeze(objectValue);
1395
+ }
1396
+ function toJsonSafeClone(value) {
1397
+ const clone = toJsonSafeValue(value);
1398
+ if (clone === void 0) {
1399
+ return void 0;
1400
+ }
1401
+ return clone;
1402
+ }
1403
+ function toImmutableJsonSafeClone(value) {
1404
+ const clone = toJsonSafeValue(value);
1405
+ if (clone === void 0) {
1406
+ return void 0;
1407
+ }
1408
+ return deepFreezeJsonValue(clone);
1409
+ }
1410
+ function hasValidThinkingDisplay(value) {
1411
+ return value === void 0 || value === "summarized" || value === "omitted";
1412
+ }
1413
+ function isClaudeEffortLevel(value) {
1414
+ return typeof value === "string" && CLAUDE_EFFORT_LEVELS.has(value);
1415
+ }
1416
+ function isClaudeThinkingConfig(value) {
1417
+ if (!isObjectRecord(value)) {
1418
+ return false;
1419
+ }
1420
+ if (value.type === "disabled") {
1421
+ return true;
1422
+ }
1423
+ if (value.type === "adaptive") {
1424
+ return hasValidThinkingDisplay(value.display);
1425
+ }
1426
+ if (value.type === "enabled") {
1427
+ const budgetTokens = value.budgetTokens;
1428
+ return (budgetTokens === void 0 || typeof budgetTokens === "number") && hasValidThinkingDisplay(value.display);
1429
+ }
1430
+ return false;
1431
+ }
1432
+ function addInvalidClaudeReasoningProviderOptionWarning(warnings, key) {
1433
+ warnings?.push({
1434
+ type: "other",
1435
+ message: `Invalid providerOptions['claude-code'].${key} value was ignored.`
1436
+ });
1437
+ }
1438
+ function extractClaudeReasoningProviderOptions(providerOptions, warnings) {
1439
+ const options = providerOptions?.["claude-code"];
1440
+ if (options === void 0) {
1441
+ return { hasClaudeReasoningSettings: false };
1442
+ }
1443
+ const result = { hasClaudeReasoningSettings: false };
1444
+ if (options.thinking !== void 0) {
1445
+ if (isClaudeThinkingConfig(options.thinking)) {
1446
+ result.thinking = options.thinking;
1447
+ result.hasClaudeReasoningSettings = true;
1448
+ } else {
1449
+ addInvalidClaudeReasoningProviderOptionWarning(warnings, "thinking");
1450
+ }
1451
+ }
1452
+ if (options.effort !== void 0) {
1453
+ if (isClaudeEffortLevel(options.effort)) {
1454
+ result.effort = options.effort;
1455
+ result.hasClaudeReasoningSettings = true;
1456
+ } else {
1457
+ addInvalidClaudeReasoningProviderOptionWarning(warnings, "effort");
1458
+ }
1459
+ }
1460
+ if (options.maxThinkingTokens !== void 0) {
1461
+ if (typeof options.maxThinkingTokens === "number") {
1462
+ result.maxThinkingTokens = options.maxThinkingTokens;
1463
+ result.hasClaudeReasoningSettings = true;
1464
+ } else {
1465
+ addInvalidClaudeReasoningProviderOptionWarning(warnings, "maxThinkingTokens");
1466
+ }
1467
+ }
1468
+ return result;
1469
+ }
1165
1470
  function isContentBlock(item) {
1166
1471
  return typeof item === "object" && item !== null && "type" in item;
1167
1472
  }
@@ -1322,6 +1627,7 @@ function toAsyncIterablePrompt(messagesPrompt, outputStreamEnded, sessionId, con
1322
1627
  };
1323
1628
  }
1324
1629
  var modelMap = {
1630
+ fable: "fable",
1325
1631
  opus: "opus",
1326
1632
  sonnet: "sonnet",
1327
1633
  haiku: "haiku"
@@ -1370,7 +1676,7 @@ function truncateToolResultForStream(result, maxSize = MAX_TOOL_RESULT_SIZE) {
1370
1676
  return result;
1371
1677
  }
1372
1678
  var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1373
- specificationVersion = "v3";
1679
+ specificationVersion = "v4";
1374
1680
  defaultObjectGenerationMode = "json";
1375
1681
  supportsImageUrls = false;
1376
1682
  supportedUrls = {};
@@ -1441,6 +1747,81 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1441
1747
  }
1442
1748
  return void 0;
1443
1749
  }
1750
+ invokeObservabilityCallback(callbackName, callback, value) {
1751
+ if (!callback) {
1752
+ return;
1753
+ }
1754
+ const logError = (error) => {
1755
+ const message = error instanceof Error ? error.message : String(error);
1756
+ this.logger.warn(`[claude-code] ${callbackName} callback failed; ignoring error: ${message}`);
1757
+ if (error instanceof Error && error.stack) {
1758
+ this.logger.debug(`[claude-code] ${callbackName} callback stack: ${error.stack}`);
1759
+ }
1760
+ };
1761
+ try {
1762
+ const result = callback(value);
1763
+ if (result && typeof result.then === "function") {
1764
+ void Promise.resolve(result).catch(logError);
1765
+ }
1766
+ } catch (error) {
1767
+ logError(error);
1768
+ }
1769
+ }
1770
+ invokeSdkMessageCallback(message) {
1771
+ const onSdkMessage = this.settings.onSdkMessage;
1772
+ if (onSdkMessage === void 0) {
1773
+ return;
1774
+ }
1775
+ this.invokeObservabilityCallback(
1776
+ "onSdkMessage",
1777
+ onSdkMessage,
1778
+ toImmutableJsonSafeClone(message)
1779
+ );
1780
+ }
1781
+ notifyQueryCreated(response) {
1782
+ this.settings.onQueryCreated?.(response);
1783
+ const onQueryControllerCreated = this.settings.onQueryControllerCreated;
1784
+ if (onQueryControllerCreated !== void 0) {
1785
+ this.invokeObservabilityCallback(
1786
+ "onQueryControllerCreated",
1787
+ onQueryControllerCreated,
1788
+ createClaudeCodeQueryController(response)
1789
+ );
1790
+ }
1791
+ }
1792
+ trackTaskEvent(event, tracking) {
1793
+ tracking.taskEvents.push(toJsonSafeClone(event));
1794
+ const onTaskEvent = this.settings.onTaskEvent;
1795
+ if (onTaskEvent !== void 0) {
1796
+ this.invokeObservabilityCallback("onTaskEvent", onTaskEvent, toImmutableJsonSafeClone(event));
1797
+ }
1798
+ }
1799
+ trackHookEvent(event, tracking) {
1800
+ tracking.hookEvents.push(toJsonSafeClone(event));
1801
+ const onHookEvent = this.settings.onHookEvent;
1802
+ if (onHookEvent !== void 0) {
1803
+ this.invokeObservabilityCallback("onHookEvent", onHookEvent, toImmutableJsonSafeClone(event));
1804
+ }
1805
+ }
1806
+ trackMcpStatusFromInit(message, tracking) {
1807
+ const servers = message.mcp_servers;
1808
+ tracking.mcpServers = toJsonSafeClone(servers);
1809
+ const statusEvent = {
1810
+ subtype: "init",
1811
+ sessionId: message.session_id,
1812
+ uuid: message.uuid,
1813
+ servers,
1814
+ raw: message
1815
+ };
1816
+ const onMcpStatusChange = this.settings.onMcpStatusChange;
1817
+ if (onMcpStatusChange !== void 0) {
1818
+ this.invokeObservabilityCallback(
1819
+ "onMcpStatusChange",
1820
+ onMcpStatusChange,
1821
+ toImmutableJsonSafeClone(statusEvent)
1822
+ );
1823
+ }
1824
+ }
1444
1825
  /**
1445
1826
  * Single source of truth for the CLI's `--session-id` exclusivity rule.
1446
1827
  *
@@ -1605,7 +1986,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1605
1986
  input,
1606
1987
  providerExecuted: true,
1607
1988
  dynamic: true,
1608
- // V3 field: indicates tool is provider-defined (not in user's tools map)
1989
+ // V4 field: indicates tool is provider-defined (not in user's tools map)
1609
1990
  providerMetadata: {
1610
1991
  "claude-code": {
1611
1992
  // rawInput preserves the original serialized format before AI SDK normalization.
@@ -1645,12 +2026,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1645
2026
  toolName,
1646
2027
  // `?? ''`: absent `content` (undefined) and string results that
1647
2028
  // normalize to JSON null (e.g. the string "null") must not violate the
1648
- // NonNullable<JSONValue> contract of LanguageModelV3ToolResult.result.
2029
+ // NonNullable<JSONValue> contract of LanguageModelV4ToolResult.result.
1649
2030
  result: truncatedResult ?? "",
1650
2031
  isError,
1651
- providerExecuted: true,
1652
2032
  dynamic: true,
1653
- // V3 field: indicates tool is provider-defined
2033
+ // V4 field: indicates tool is provider-defined
1654
2034
  providerMetadata: {
1655
2035
  "claude-code": {
1656
2036
  // rawResult preserves the original CLI output string before JSON parsing.
@@ -1673,37 +2053,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1673
2053
  })() : String(error);
1674
2054
  }
1675
2055
  /**
1676
- * Builds a provider-executed `tool-error` STREAM part from a user-message
1677
- * `tool_error` block (doStream only; AI SDK core handles tool-error stream
1678
- * parts natively).
2056
+ * Builds a V4 provider `tool-result` part with `isError: true` from a
2057
+ * user-message `tool_error` block. V4 has no provider-level `tool-error`
2058
+ * content or stream part; AI SDK core derives user-facing tool-error
2059
+ * semantics from this result while preserving providerMetadata.
1679
2060
  */
1680
- buildToolErrorPart(toolCallId, toolName, error, parentToolCallId) {
1681
- const rawError = this.serializeToolError(error);
1682
- return {
1683
- type: "tool-error",
1684
- toolCallId,
1685
- toolName,
1686
- error: rawError,
1687
- providerExecuted: true,
1688
- dynamic: true,
1689
- // V3 field: indicates tool is provider-defined
1690
- providerMetadata: {
1691
- "claude-code": {
1692
- rawError,
1693
- parentToolCallId: parentToolCallId ?? null
1694
- }
1695
- }
1696
- };
1697
- }
1698
- /**
1699
- * Builds a V3 `tool-result` CONTENT part with `isError: true` from a
1700
- * user-message `tool_error` block (doGenerate only). The V3 content union
1701
- * has no `tool-error` member and AI SDK core's asContent() silently drops
1702
- * unknown content part types, so an extension tool-error part would never
1703
- * reach `generateText` users — an isError tool-result, by contrast,
1704
- * round-trips into a proper tool-error part in steps content.
1705
- */
1706
- buildToolErrorResultPart(toolCallId, toolName, error, parentToolCallId) {
2061
+ buildErroredToolResultPart(toolCallId, toolName, error, parentToolCallId) {
1707
2062
  const rawError = this.serializeToolError(error);
1708
2063
  return {
1709
2064
  type: "tool-result",
@@ -1711,9 +2066,8 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1711
2066
  toolName,
1712
2067
  result: rawError,
1713
2068
  isError: true,
1714
- providerExecuted: true,
1715
2069
  dynamic: true,
1716
- // V3 field: indicates tool is provider-defined
2070
+ // V4 field: indicates tool is provider-defined
1717
2071
  providerMetadata: {
1718
2072
  "claude-code": {
1719
2073
  rawError,
@@ -1739,7 +2093,33 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1739
2093
  );
1740
2094
  return true;
1741
2095
  }
1742
- generateAllWarnings(options, prompt) {
2096
+ resolvePortableReasoningOptions(options, sdkOptions, claudeProviderOptions, warnings) {
2097
+ const hasClaudeSpecificReasoning = this.settings.thinking !== void 0 || this.settings.effort !== void 0 || this.settings.maxThinkingTokens !== void 0 || sdkOptions?.thinking !== void 0 || sdkOptions?.effort !== void 0 || sdkOptions?.maxThinkingTokens !== void 0 || claudeProviderOptions.hasClaudeReasoningSettings;
2098
+ if (hasClaudeSpecificReasoning || !isCustomReasoning(options.reasoning)) {
2099
+ return {};
2100
+ }
2101
+ if (options.reasoning === "none") {
2102
+ return { thinking: { type: "disabled" } };
2103
+ }
2104
+ const effort = mapReasoningToProviderEffort({
2105
+ reasoning: options.reasoning,
2106
+ effortMap: CLAUDE_REASONING_EFFORT_MAP,
2107
+ warnings: warnings ?? []
2108
+ });
2109
+ return effort === void 0 ? {} : { effort };
2110
+ }
2111
+ applyClaudeReasoningProviderOptions(opts, claudeProviderOptions) {
2112
+ if (claudeProviderOptions.thinking !== void 0) {
2113
+ opts.thinking = claudeProviderOptions.thinking;
2114
+ }
2115
+ if (claudeProviderOptions.effort !== void 0) {
2116
+ opts.effort = claudeProviderOptions.effort;
2117
+ }
2118
+ if (claudeProviderOptions.maxThinkingTokens !== void 0) {
2119
+ opts.maxThinkingTokens = claudeProviderOptions.maxThinkingTokens;
2120
+ }
2121
+ }
2122
+ generateAllWarnings(options, prompt, sdkOptions) {
1743
2123
  const warnings = [];
1744
2124
  const unsupportedParams = [];
1745
2125
  if (options.temperature !== void 0) unsupportedParams.push("temperature");
@@ -1806,9 +2186,18 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1806
2186
  message: promptWarning
1807
2187
  });
1808
2188
  }
2189
+ this.resolvePortableReasoningOptions(
2190
+ options,
2191
+ sdkOptions,
2192
+ extractClaudeReasoningProviderOptions(options.providerOptions, warnings),
2193
+ warnings
2194
+ );
1809
2195
  return warnings;
1810
2196
  }
1811
- createQueryOptions(abortController, responseFormat, stderrCollector, sdkOptions, effectiveResume) {
2197
+ createQueryOptions(abortController, options, stderrCollector, sdkOptions, effectiveResume) {
2198
+ const claudeReasoningProviderOptions = extractClaudeReasoningProviderOptions(
2199
+ options.providerOptions
2200
+ );
1812
2201
  const opts = {
1813
2202
  model: this.getModel(),
1814
2203
  abortController,
@@ -1836,8 +2225,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1836
2225
  sandbox: this.settings.sandbox,
1837
2226
  tools: this.settings.tools,
1838
2227
  mcpServers: this.settings.mcpServers,
1839
- canUseTool: this.settings.canUseTool
2228
+ canUseTool: this.settings.canUseTool,
2229
+ onElicitation: this.settings.onElicitation,
2230
+ agent: this.settings.agent
1840
2231
  };
2232
+ Object.assign(
2233
+ opts,
2234
+ this.resolvePortableReasoningOptions(options, sdkOptions, claudeReasoningProviderOptions)
2235
+ );
1841
2236
  if (this.settings.onUserDialog !== void 0) {
1842
2237
  opts.onUserDialog = this.settings.onUserDialog;
1843
2238
  }
@@ -1966,6 +2361,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1966
2361
  }
1967
2362
  }
1968
2363
  }
2364
+ this.applyClaudeReasoningProviderOptions(opts, claudeReasoningProviderOptions);
1969
2365
  this.applySessionResolution(opts, effectiveResume);
1970
2366
  if (typeof opts.fallbackModel === "string" && opts.fallbackModel === opts.model) {
1971
2367
  throw new Error(
@@ -1988,9 +2384,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1988
2384
  mergedEnv.CLAUDE_AGENT_SDK_CLIENT_APP = DEFAULT_CLIENT_APP;
1989
2385
  }
1990
2386
  opts.env = mergedEnv;
1991
- if (responseFormat?.type === "json" && responseFormat.schema) {
2387
+ if (options.responseFormat?.type === "json" && options.responseFormat.schema) {
1992
2388
  const { schema: sanitizedSchema, strippedFormatPaths } = sanitizeJsonSchemaForOutputFormat(
1993
- responseFormat.schema
2389
+ options.responseFormat.schema
1994
2390
  );
1995
2391
  if (strippedFormatPaths.length > 0) {
1996
2392
  this.logger.debug(
@@ -2005,18 +2401,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2005
2401
  return opts;
2006
2402
  }
2007
2403
  handleClaudeCodeError(error, messagesPrompt, collectedStderr) {
2008
- if (error instanceof APICallError2 || error instanceof LoadAPIKeyError2) {
2009
- return error;
2010
- }
2011
- const rawSdkStderr = typeof error === "object" && error !== null && "stderr" in error && typeof error.stderr === "string" ? error.stderr : void 0;
2012
- const cappedSdkStderr = rawSdkStderr !== void 0 ? capStderr(rawSdkStderr) : void 0;
2013
- const selectedStderr = cappedSdkStderr !== void 0 && stderrTail(cappedSdkStderr) ? cappedSdkStderr : collectedStderr ? capStderr(collectedStderr) : void 0;
2014
- const stderr = selectedStderr || void 0;
2015
- const tail = stderr ? stderrTail(stderr) : "";
2016
- const appendStderrTail = (message) => tail && !message.includes(STDERR_TAIL_MARKER) ? `${message}${STDERR_TAIL_MARKER} ${tail}` : message;
2017
2404
  if (isAbortError(error)) {
2018
2405
  throw error;
2019
2406
  }
2407
+ if (error instanceof APICallError2 || error instanceof LoadAPIKeyError2) {
2408
+ return error;
2409
+ }
2020
2410
  const isErrorWithMessage = (err) => {
2021
2411
  return typeof err === "object" && err !== null && "message" in err;
2022
2412
  };
@@ -2037,43 +2427,26 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2037
2427
  "oauth_org_not_allowed"
2038
2428
  // SDK 0.3.x assistant error kind: OAuth org not permitted
2039
2429
  ];
2040
- const stderrAuthPatterns = [
2041
- "not logged in",
2042
- "not authenticated",
2043
- "auth failed",
2044
- "please login",
2045
- "please run /login",
2046
- "claude login",
2047
- "claude auth login",
2048
- "invalid api key",
2049
- "oauth token revoked",
2050
- "oauth_org_not_allowed"
2051
- ];
2052
2430
  const errorMessage = isErrorWithMessage(error) && error.message ? error.message.toLowerCase() : "";
2053
- const stderrMessage = stderr?.toLowerCase() ?? "";
2054
2431
  const errorKind = getStructuredErrorKind(error);
2055
2432
  const exitCode = isErrorWithCode(error) && typeof error.exitCode === "number" ? error.exitCode : void 0;
2056
- const isAuthError = errorKind === "authentication_failed" || errorKind === "oauth_org_not_allowed" || authErrorPatterns.some((pattern) => errorMessage.includes(pattern)) || stderrAuthPatterns.some((pattern) => stderrMessage.includes(pattern)) || exitCode === 401;
2433
+ const isAuthError = errorKind === "authentication_failed" || errorKind === "oauth_org_not_allowed" || authErrorPatterns.some((pattern) => errorMessage.includes(pattern)) || exitCode === 401;
2057
2434
  if (isAuthError) {
2058
2435
  return createAuthenticationError({
2059
- message: appendStderrTail(
2060
- isErrorWithMessage(error) && error.message ? error.message : "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
2061
- ),
2062
- stderr
2436
+ message: isErrorWithMessage(error) && error.message ? error.message : "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
2063
2437
  });
2064
2438
  }
2065
2439
  const errorCode = isErrorWithCode(error) && typeof error.code === "string" ? error.code : "";
2066
- if (errorCode === "ETIMEDOUT" || errorMessage.includes("timeout") || /request timed out|etimedout/i.test(stderr ?? "")) {
2440
+ if (errorCode === "ETIMEDOUT" || errorMessage.includes("timeout")) {
2067
2441
  return createTimeoutError({
2068
- message: appendStderrTail(
2069
- isErrorWithMessage(error) && error.message ? error.message : "Request timed out"
2070
- ),
2071
- stderr,
2442
+ message: isErrorWithMessage(error) && error.message ? error.message : "Request timed out",
2072
2443
  promptExcerpt: messagesPrompt.substring(0, 200)
2073
2444
  // Don't specify timeoutMs since we don't know the actual timeout value
2074
2445
  // It's controlled by the consumer via AbortSignal
2075
2446
  });
2076
2447
  }
2448
+ const stderrFromError = isErrorWithCode(error) && typeof error.stderr === "string" ? error.stderr : void 0;
2449
+ const stderr = stderrFromError || collectedStderr || void 0;
2077
2450
  if (errorKind === "overloaded" || errorKind === "rate_limit" || errorMessage.includes("overloaded")) {
2078
2451
  return createAPICallError({
2079
2452
  message: isErrorWithMessage(error) && error.message ? error.message : "Anthropic API is overloaded. Please retry.",
@@ -2087,7 +2460,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2087
2460
  if (errorKind === "model_not_found" || errorMessage.includes("model_not_found") || errorMessage.includes("no such model")) {
2088
2461
  const originalMessage = isErrorWithMessage(error) && error.message ? error.message : "Model not found";
2089
2462
  return createAPICallError({
2090
- message: `${originalMessage}. The requested model was not found. Verify the model id passed to the provider (e.g. 'opus', 'sonnet', 'haiku', or a full model name) and that your account has access to it.`,
2463
+ message: `${originalMessage}. The requested model was not found. Verify the model id passed to the provider (e.g. 'fable', 'opus', 'sonnet', 'haiku', or a full model name) and that your account has access to it.`,
2091
2464
  code: errorCode || void 0,
2092
2465
  exitCode,
2093
2466
  stderr,
@@ -2157,16 +2530,159 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2157
2530
  break;
2158
2531
  case "permission_denied": {
2159
2532
  const reason = message.decision_reason ?? message.message;
2533
+ const raw = toJsonSafeValue(message);
2160
2534
  tracking.permissionDenials.push({
2161
2535
  toolName: message.tool_name,
2162
2536
  toolUseId: message.tool_use_id,
2163
- ...reason !== void 0 && { reason }
2537
+ ...message.agent_id !== void 0 && { agentId: message.agent_id },
2538
+ ...message.decision_reason_type !== void 0 && {
2539
+ decisionReasonType: message.decision_reason_type
2540
+ },
2541
+ ...reason !== void 0 && { reason },
2542
+ ...raw !== void 0 && { raw }
2164
2543
  });
2165
2544
  this.logger.warn(
2166
2545
  `[claude-code] Permission denied - Tool: ${message.tool_name}${reason ? `, Reason: ${reason}` : ""}`
2167
2546
  );
2168
2547
  break;
2169
2548
  }
2549
+ case "task_started":
2550
+ this.trackTaskEvent(
2551
+ {
2552
+ subtype: "task_started",
2553
+ taskId: message.task_id,
2554
+ ...message.tool_use_id !== void 0 && { toolUseId: message.tool_use_id },
2555
+ description: message.description,
2556
+ ...message.subagent_type !== void 0 && { subagentType: message.subagent_type },
2557
+ ...message.task_type !== void 0 && { taskType: message.task_type },
2558
+ ...message.workflow_name !== void 0 && { workflowName: message.workflow_name },
2559
+ ...message.prompt !== void 0 && { prompt: message.prompt },
2560
+ ...message.skip_transcript !== void 0 && {
2561
+ skipTranscript: message.skip_transcript
2562
+ },
2563
+ uuid: message.uuid,
2564
+ sessionId: message.session_id,
2565
+ raw: message
2566
+ },
2567
+ tracking
2568
+ );
2569
+ this.logger.debug(`[claude-code] Task started - ID: ${message.task_id}`);
2570
+ break;
2571
+ case "task_progress":
2572
+ this.trackTaskEvent(
2573
+ {
2574
+ subtype: "task_progress",
2575
+ taskId: message.task_id,
2576
+ ...message.tool_use_id !== void 0 && { toolUseId: message.tool_use_id },
2577
+ description: message.description,
2578
+ ...message.subagent_type !== void 0 && { subagentType: message.subagent_type },
2579
+ usage: message.usage,
2580
+ ...message.last_tool_name !== void 0 && { lastToolName: message.last_tool_name },
2581
+ ...message.summary !== void 0 && { summary: message.summary },
2582
+ uuid: message.uuid,
2583
+ sessionId: message.session_id,
2584
+ raw: message
2585
+ },
2586
+ tracking
2587
+ );
2588
+ this.logger.debug(`[claude-code] Task progress - ID: ${message.task_id}`);
2589
+ break;
2590
+ case "task_updated":
2591
+ this.trackTaskEvent(
2592
+ {
2593
+ subtype: "task_updated",
2594
+ taskId: message.task_id,
2595
+ patch: message.patch,
2596
+ uuid: message.uuid,
2597
+ sessionId: message.session_id,
2598
+ raw: message
2599
+ },
2600
+ tracking
2601
+ );
2602
+ this.logger.debug(`[claude-code] Task updated - ID: ${message.task_id}`);
2603
+ break;
2604
+ case "task_notification":
2605
+ this.trackTaskEvent(
2606
+ {
2607
+ subtype: "task_notification",
2608
+ taskId: message.task_id,
2609
+ ...message.tool_use_id !== void 0 && { toolUseId: message.tool_use_id },
2610
+ status: message.status,
2611
+ outputFile: message.output_file,
2612
+ summary: message.summary,
2613
+ ...message.usage !== void 0 && { usage: message.usage },
2614
+ ...message.skip_transcript !== void 0 && {
2615
+ skipTranscript: message.skip_transcript
2616
+ },
2617
+ uuid: message.uuid,
2618
+ sessionId: message.session_id,
2619
+ raw: message
2620
+ },
2621
+ tracking
2622
+ );
2623
+ this.logger.debug(
2624
+ `[claude-code] Task notification - ID: ${message.task_id}, Status: ${message.status}`
2625
+ );
2626
+ break;
2627
+ case "hook_started":
2628
+ this.trackHookEvent(
2629
+ {
2630
+ subtype: "hook_started",
2631
+ hookId: message.hook_id,
2632
+ hookName: message.hook_name,
2633
+ hookEvent: message.hook_event,
2634
+ uuid: message.uuid,
2635
+ sessionId: message.session_id,
2636
+ raw: message
2637
+ },
2638
+ tracking
2639
+ );
2640
+ this.logger.debug(
2641
+ `[claude-code] Hook started - ID: ${message.hook_id}, Event: ${message.hook_event}`
2642
+ );
2643
+ break;
2644
+ case "hook_progress":
2645
+ this.trackHookEvent(
2646
+ {
2647
+ subtype: "hook_progress",
2648
+ hookId: message.hook_id,
2649
+ hookName: message.hook_name,
2650
+ hookEvent: message.hook_event,
2651
+ stdout: message.stdout,
2652
+ stderr: message.stderr,
2653
+ output: message.output,
2654
+ uuid: message.uuid,
2655
+ sessionId: message.session_id,
2656
+ raw: message
2657
+ },
2658
+ tracking
2659
+ );
2660
+ this.logger.debug(
2661
+ `[claude-code] Hook progress - ID: ${message.hook_id}, Event: ${message.hook_event}`
2662
+ );
2663
+ break;
2664
+ case "hook_response":
2665
+ this.trackHookEvent(
2666
+ {
2667
+ subtype: "hook_response",
2668
+ hookId: message.hook_id,
2669
+ hookName: message.hook_name,
2670
+ hookEvent: message.hook_event,
2671
+ output: message.output,
2672
+ stdout: message.stdout,
2673
+ stderr: message.stderr,
2674
+ ...message.exit_code !== void 0 && { exitCode: message.exit_code },
2675
+ outcome: message.outcome,
2676
+ uuid: message.uuid,
2677
+ sessionId: message.session_id,
2678
+ raw: message
2679
+ },
2680
+ tracking
2681
+ );
2682
+ this.logger.debug(
2683
+ `[claude-code] Hook response - ID: ${message.hook_id}, Outcome: ${message.outcome}`
2684
+ );
2685
+ break;
2170
2686
  case "mirror_error": {
2171
2687
  const mirrorError = message.error ?? "unknown error";
2172
2688
  const mirrorSessionId = message.key?.sessionId ?? message.session_id ?? "unknown";
@@ -2219,12 +2735,21 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2219
2735
  const alreadyTracked = tracking.permissionDenials.some(
2220
2736
  (d) => d.toolUseId !== void 0 && d.toolUseId === denial.tool_use_id
2221
2737
  );
2222
- if (!alreadyTracked) {
2223
- tracking.permissionDenials.push({
2224
- toolName: denial.tool_name,
2225
- toolUseId: denial.tool_use_id
2226
- });
2738
+ if (alreadyTracked) {
2739
+ continue;
2227
2740
  }
2741
+ const agentId = typeof denial.agent_id === "string" ? denial.agent_id : typeof denial.agentId === "string" ? denial.agentId : void 0;
2742
+ const decisionReasonType = typeof denial.decision_reason_type === "string" ? denial.decision_reason_type : typeof denial.decisionReasonType === "string" ? denial.decisionReasonType : void 0;
2743
+ const reason = typeof denial.decision_reason === "string" ? denial.decision_reason : typeof denial.reason === "string" ? denial.reason : typeof denial.message === "string" ? denial.message : void 0;
2744
+ const raw = toJsonSafeValue(denial);
2745
+ tracking.permissionDenials.push({
2746
+ toolName: denial.tool_name,
2747
+ toolUseId: denial.tool_use_id,
2748
+ ...agentId !== void 0 && { agentId },
2749
+ ...decisionReasonType !== void 0 && { decisionReasonType },
2750
+ ...reason !== void 0 && { reason },
2751
+ ...raw !== void 0 && { raw }
2752
+ });
2228
2753
  }
2229
2754
  }
2230
2755
  /**
@@ -2233,11 +2758,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2233
2758
  * suggestion arrives AFTER the result message; the SDK emits at most one
2234
2759
  * per turn, so stop once it is delivered, and a timeout closes the
2235
2760
  * iterator (tearing down the subprocess) if the CLI lingers after the
2236
- * result without emitting one. Advances the response's own generator, so
2237
- * the caller's surrounding loop resumes to a finished iterator.
2761
+ * result without emitting one. Drained messages still pass through the
2762
+ * generic raw SDK callback before prompt-specific handling.
2238
2763
  */
2239
- async drainPromptSuggestion(response, onPromptSuggestion) {
2240
- const iterator = response[Symbol.asyncIterator]();
2764
+ async drainPromptSuggestion(iterator, onPromptSuggestion) {
2241
2765
  let drainTimer;
2242
2766
  const drainTimeout = new Promise((resolve) => {
2243
2767
  drainTimer = setTimeout(
@@ -2260,8 +2784,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2260
2784
  }
2261
2785
  const trailingMessage = winner.value;
2262
2786
  this.logger.debug(`[claude-code] Post-result message type: ${trailingMessage.type}`);
2787
+ this.invokeSdkMessageCallback(trailingMessage);
2263
2788
  if (trailingMessage.type === "prompt_suggestion") {
2264
- onPromptSuggestion(trailingMessage.suggestion);
2789
+ onPromptSuggestion?.(trailingMessage.suggestion);
2265
2790
  void iterator.return?.().catch(() => {
2266
2791
  });
2267
2792
  break;
@@ -2297,13 +2822,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2297
2822
  let collectedStderr = "";
2298
2823
  const stderrCollector = (data) => {
2299
2824
  collectedStderr += data;
2300
- collectedStderr = capStderr(collectedStderr);
2301
2825
  };
2302
2826
  const sdkOptions = this.getSanitizedSdkOptions();
2303
2827
  const effectiveResume = this.getEffectiveResume(sdkOptions);
2304
2828
  const queryOptions = this.createQueryOptions(
2305
2829
  abortController,
2306
- options.responseFormat,
2830
+ options,
2307
2831
  stderrCollector,
2308
2832
  sdkOptions,
2309
2833
  effectiveResume
@@ -2377,9 +2901,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2377
2901
  apiRetries: 0,
2378
2902
  permissionDenials: [],
2379
2903
  mirrorErrors: [],
2380
- estimatedThinkingTokens: 0
2904
+ estimatedThinkingTokens: 0,
2905
+ taskEvents: [],
2906
+ hookEvents: []
2381
2907
  };
2382
- const warnings = this.generateAllWarnings(options, messagesPrompt);
2908
+ const warnings = this.generateAllWarnings(
2909
+ options,
2910
+ messagesPrompt,
2911
+ sdkOptions
2912
+ );
2383
2913
  if (messageWarnings) {
2384
2914
  messageWarnings.forEach((warning) => {
2385
2915
  warnings.push({
@@ -2391,7 +2921,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2391
2921
  const modeSetting = this.settings.streamingInput ?? "auto";
2392
2922
  const effectiveCanUseTool = sdkOptions?.canUseTool ?? this.settings.canUseTool;
2393
2923
  const effectivePermissionPromptToolName = sdkOptions?.permissionPromptToolName ?? this.settings.permissionPromptToolName;
2394
- const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!effectiveCanUseTool;
2924
+ const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && (!!effectiveCanUseTool || hasImageParts);
2395
2925
  if (!wantsStreamInput && hasImageParts) {
2396
2926
  warnings.push({
2397
2927
  type: "other",
@@ -2423,7 +2953,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2423
2953
  prompt: sdkPrompt,
2424
2954
  options: queryOptions
2425
2955
  });
2426
- this.settings.onQueryCreated?.(response);
2956
+ this.notifyQueryCreated(response);
2427
2957
  let lastAssistantErrorKind;
2428
2958
  const sdkIterator = response[Symbol.asyncIterator]();
2429
2959
  const detachableResponse = {
@@ -2438,6 +2968,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2438
2968
  };
2439
2969
  for await (const message of detachableResponse) {
2440
2970
  this.logger.debug(`[claude-code] Received message type: ${message.type}`);
2971
+ this.invokeSdkMessageCallback(message);
2441
2972
  if (message.type === "assistant") {
2442
2973
  if (typeof message.error === "string") {
2443
2974
  lastAssistantErrorKind = message.error;
@@ -2466,6 +2997,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2466
2997
  } else if (block.type === "tool_use") {
2467
2998
  const [tool3] = this.extractToolUses([block]);
2468
2999
  if (!tool3) continue;
3000
+ if (isInternalStructuredOutputTool(tool3.name, options)) continue;
2469
3001
  const parentToolCallId = isSubagentToolName(tool3.name) ? null : resolveToolParentId(
2470
3002
  sdkParentToolUseId,
2471
3003
  tool3.parentToolUseId,
@@ -2576,7 +3108,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2576
3108
  kind: "tool-error",
2577
3109
  ...resultMessageUuid !== void 0 && { uuid: resultMessageUuid },
2578
3110
  toolCallId: error.id,
2579
- part: this.buildToolErrorResultPart(
3111
+ part: this.buildErroredToolResultPart(
2580
3112
  error.id,
2581
3113
  toolName,
2582
3114
  error.error,
@@ -2634,14 +3166,19 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2634
3166
  }
2635
3167
  const stopReason = "stop_reason" in message ? message.stop_reason : void 0;
2636
3168
  finishReason = mapClaudeCodeFinishReason(message.subtype, stopReason);
3169
+ if (structuredOutput !== void 0 && finishReason.unified === "tool-calls") {
3170
+ finishReason = { unified: "stop", raw: finishReason.raw };
3171
+ }
2637
3172
  this.logger.debug(`[claude-code] Finish reason: ${finishReason.unified}`);
2638
3173
  const effectivePromptSuggestions = sdkOptions?.promptSuggestions ?? this.settings.promptSuggestions;
2639
- if (this.settings.onPromptSuggestion && effectivePromptSuggestions !== false) {
2640
- await this.drainPromptSuggestion(response, this.settings.onPromptSuggestion);
3174
+ const shouldDrainPromptSuggestion = effectivePromptSuggestions !== false && (this.settings.onPromptSuggestion !== void 0 || this.settings.onSdkMessage !== void 0);
3175
+ if (shouldDrainPromptSuggestion) {
3176
+ await this.drainPromptSuggestion(sdkIterator, this.settings.onPromptSuggestion);
2641
3177
  }
2642
3178
  break;
2643
3179
  } else if (message.type === "system" && message.subtype === "init") {
2644
3180
  this.logMcpConnectionIssues(message.mcp_servers);
3181
+ this.trackMcpStatusFromInit(message, metadataTracking);
2645
3182
  this.setSessionId(message.session_id);
2646
3183
  this.logger.info(`[claude-code] Session initialized: ${message.session_id}`);
2647
3184
  } else if (message.type === "system") {
@@ -2744,6 +3281,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2744
3281
  ...metadataTracking.permissionDenials.length > 0 && {
2745
3282
  permissionDenials: metadataTracking.permissionDenials
2746
3283
  },
3284
+ ...metadataTracking.taskEvents.length > 0 && {
3285
+ taskEvents: metadataTracking.taskEvents
3286
+ },
3287
+ ...metadataTracking.hookEvents.length > 0 && {
3288
+ hookEvents: metadataTracking.hookEvents
3289
+ },
3290
+ ...metadataTracking.mcpServers !== void 0 && {
3291
+ mcpServers: metadataTracking.mcpServers
3292
+ },
2747
3293
  ...metadataTracking.mirrorErrors.length > 0 && {
2748
3294
  mirrorErrors: metadataTracking.mirrorErrors
2749
3295
  },
@@ -2776,13 +3322,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2776
3322
  let collectedStderr = "";
2777
3323
  const stderrCollector = (data) => {
2778
3324
  collectedStderr += data;
2779
- collectedStderr = capStderr(collectedStderr);
2780
3325
  };
2781
3326
  const sdkOptions = this.getSanitizedSdkOptions();
2782
3327
  const effectiveResume = this.getEffectiveResume(sdkOptions);
2783
3328
  const queryOptions = this.createQueryOptions(
2784
3329
  abortController,
2785
- options.responseFormat,
3330
+ options,
2786
3331
  stderrCollector,
2787
3332
  sdkOptions,
2788
3333
  effectiveResume
@@ -2794,7 +3339,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2794
3339
  if (queryOptions.includePartialMessages === void 0) {
2795
3340
  queryOptions.includePartialMessages = true;
2796
3341
  }
2797
- const warnings = this.generateAllWarnings(options, messagesPrompt);
3342
+ const warnings = this.generateAllWarnings(
3343
+ options,
3344
+ messagesPrompt,
3345
+ sdkOptions
3346
+ );
2798
3347
  if (messageWarnings) {
2799
3348
  messageWarnings.forEach((warning) => {
2800
3349
  warnings.push({
@@ -2806,7 +3355,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2806
3355
  const modeSetting = this.settings.streamingInput ?? "auto";
2807
3356
  const effectiveCanUseTool = sdkOptions?.canUseTool ?? this.settings.canUseTool;
2808
3357
  const effectivePermissionPromptToolName = sdkOptions?.permissionPromptToolName ?? this.settings.permissionPromptToolName;
2809
- const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!effectiveCanUseTool;
3358
+ const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && (!!effectiveCanUseTool || hasImageParts);
2810
3359
  if (!wantsStreamInput && hasImageParts) {
2811
3360
  warnings.push({
2812
3361
  type: "other",
@@ -2873,9 +3422,13 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2873
3422
  apiRetries: 0,
2874
3423
  permissionDenials: [],
2875
3424
  mirrorErrors: [],
2876
- estimatedThinkingTokens: 0
3425
+ estimatedThinkingTokens: 0,
3426
+ taskEvents: [],
3427
+ hookEvents: []
2877
3428
  };
2878
3429
  const toolBlocksByIndex = /* @__PURE__ */ new Map();
3430
+ const structuredOutputBlockIndexes = /* @__PURE__ */ new Set();
3431
+ const nonTextToolBlockIndexes = /* @__PURE__ */ new Set();
2879
3432
  const toolInputAccumulators = /* @__PURE__ */ new Map();
2880
3433
  const textBlocksByIndex = /* @__PURE__ */ new Map();
2881
3434
  let textStreamedViaContentBlock = false;
@@ -2938,9 +3491,24 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2938
3491
  prompt: sdkPrompt,
2939
3492
  options: queryOptions
2940
3493
  });
2941
- this.settings.onQueryCreated?.(response);
2942
- for await (const message of response) {
3494
+ this.notifyQueryCreated(response);
3495
+ const sdkIterator = response[Symbol.asyncIterator]();
3496
+ const detachableResponse = {
3497
+ [Symbol.asyncIterator]: () => ({
3498
+ next: () => sdkIterator.next(),
3499
+ return: () => {
3500
+ void sdkIterator.return?.().catch(() => {
3501
+ });
3502
+ return Promise.resolve({ done: true, value: void 0 });
3503
+ }
3504
+ })
3505
+ };
3506
+ for await (const message of detachableResponse) {
2943
3507
  this.logger.debug(`[claude-code] Stream received message type: ${message.type}`);
3508
+ this.invokeSdkMessageCallback(message);
3509
+ if (options.includeRawChunks) {
3510
+ controller.enqueue({ type: "raw", rawValue: message });
3511
+ }
2944
3512
  if (message.type === "stream_event") {
2945
3513
  const streamEvent = message;
2946
3514
  const event = streamEvent.event;
@@ -2972,7 +3540,8 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2972
3540
  const jsonDelta = event.delta.partial_json;
2973
3541
  hasReceivedStreamEvents = true;
2974
3542
  const blockIndex = "index" in event ? event.index : -1;
2975
- if (options.responseFormat?.type === "json") {
3543
+ const isStructuredOutputDelta = structuredOutputBlockIndexes.has(blockIndex) || !toolBlocksByIndex.has(blockIndex) && !nonTextToolBlockIndexes.has(blockIndex);
3544
+ if (options.responseFormat?.type === "json" && isStructuredOutputDelta) {
2976
3545
  if (!textPartId) {
2977
3546
  textPartId = generateId();
2978
3547
  controller.enqueue({
@@ -3002,12 +3571,25 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3002
3571
  continue;
3003
3572
  }
3004
3573
  }
3574
+ if (event.type === "content_block_start" && "content_block" in event && isNonTextToolUseContentBlockType(event.content_block?.type)) {
3575
+ const blockIndex = "index" in event ? event.index : -1;
3576
+ hasReceivedStreamEvents = true;
3577
+ nonTextToolBlockIndexes.add(blockIndex);
3578
+ structuredOutputBlockIndexes.delete(blockIndex);
3579
+ continue;
3580
+ }
3005
3581
  if (event.type === "content_block_start" && "content_block" in event && event.content_block?.type === "tool_use") {
3006
3582
  const blockIndex = "index" in event ? event.index : -1;
3007
3583
  const toolBlock = event.content_block;
3008
3584
  const toolId = typeof toolBlock.id === "string" && toolBlock.id.length > 0 ? toolBlock.id : generateId();
3009
3585
  const toolName = typeof toolBlock.name === "string" && toolBlock.name.length > 0 ? toolBlock.name : _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
3010
3586
  hasReceivedStreamEvents = true;
3587
+ nonTextToolBlockIndexes.delete(blockIndex);
3588
+ if (isInternalStructuredOutputTool(toolName, options)) {
3589
+ structuredOutputBlockIndexes.add(blockIndex);
3590
+ continue;
3591
+ }
3592
+ structuredOutputBlockIndexes.delete(blockIndex);
3011
3593
  if (textPartId) {
3012
3594
  const closedTextId = textPartId;
3013
3595
  controller.enqueue({
@@ -3154,6 +3736,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3154
3736
  toolInputAccumulators.delete(toolId);
3155
3737
  continue;
3156
3738
  }
3739
+ if (structuredOutputBlockIndexes.delete(blockIndex)) {
3740
+ continue;
3741
+ }
3742
+ if (nonTextToolBlockIndexes.delete(blockIndex)) {
3743
+ continue;
3744
+ }
3157
3745
  const textId = textBlocksByIndex.get(blockIndex);
3158
3746
  if (textId) {
3159
3747
  this.logger.debug(
@@ -3200,7 +3788,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3200
3788
  }
3201
3789
  const sdkParentToolUseId = message.parent_tool_use_id;
3202
3790
  const content = message.message.content;
3203
- const tools = this.extractToolUses(content);
3791
+ const tools = this.extractToolUses(content).filter(
3792
+ (tool3) => !isInternalStructuredOutputTool(tool3.name, options)
3793
+ );
3204
3794
  if (textPartId && tools.length > 0) {
3205
3795
  const closedTextId = textPartId;
3206
3796
  controller.enqueue({
@@ -3253,7 +3843,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3253
3843
  toolName: tool3.name,
3254
3844
  providerExecuted: true,
3255
3845
  dynamic: true,
3256
- // V3 field: indicates tool is provider-defined
3846
+ // V4 field: indicates tool is provider-defined
3257
3847
  providerMetadata: {
3258
3848
  "claude-code": {
3259
3849
  parentToolCallId: state.parentToolCallId ?? null
@@ -3458,7 +4048,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3458
4048
  toolName,
3459
4049
  providerExecuted: true,
3460
4050
  dynamic: true,
3461
- // V3 field: indicates tool is provider-defined
4051
+ // V4 field: indicates tool is provider-defined
3462
4052
  providerMetadata: {
3463
4053
  "claude-code": {
3464
4054
  parentToolCallId: state.parentToolCallId ?? null
@@ -3510,19 +4100,47 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3510
4100
  );
3511
4101
  state = {
3512
4102
  name: toolName,
3513
- inputStarted: true,
3514
- inputClosed: true,
4103
+ inputStarted: false,
4104
+ inputClosed: false,
3515
4105
  callEmitted: false,
3516
4106
  parentToolCallId: errorResolvedParentId
3517
4107
  };
3518
4108
  toolStates.set(error.id, state);
4109
+ if (!state.inputStarted) {
4110
+ controller.enqueue({
4111
+ type: "tool-input-start",
4112
+ id: error.id,
4113
+ toolName,
4114
+ providerExecuted: true,
4115
+ dynamic: true,
4116
+ // V4 field: indicates tool is provider-defined
4117
+ providerMetadata: {
4118
+ "claude-code": {
4119
+ parentToolCallId: state.parentToolCallId ?? null
4120
+ }
4121
+ }
4122
+ });
4123
+ state.inputStarted = true;
4124
+ }
4125
+ if (!state.inputClosed) {
4126
+ controller.enqueue({
4127
+ type: "tool-input-end",
4128
+ id: error.id
4129
+ });
4130
+ state.inputClosed = true;
4131
+ }
3519
4132
  }
3520
4133
  emitToolCall(error.id, state);
3521
4134
  if (isSubagentToolName(toolName)) {
3522
4135
  activeTaskTools.delete(error.id);
3523
4136
  }
3524
4137
  controller.enqueue(
3525
- this.buildToolErrorPart(error.id, toolName, error.error, state.parentToolCallId)
4138
+ this.buildErroredToolResultPart(
4139
+ error.id,
4140
+ toolName,
4141
+ error.error,
4142
+ state.parentToolCallId
4143
+ )
3526
4144
  );
3527
4145
  }
3528
4146
  } else if (message.type === "result") {
@@ -3552,13 +4170,16 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3552
4170
  );
3553
4171
  }
3554
4172
  const stopReason = "stop_reason" in message ? message.stop_reason : void 0;
3555
- const finishReason = mapClaudeCodeFinishReason(
4173
+ let finishReason = mapClaudeCodeFinishReason(
3556
4174
  message.subtype,
3557
4175
  stopReason
3558
4176
  );
3559
- this.logger.debug(`[claude-code] Stream finish reason: ${finishReason.unified}`);
3560
4177
  this.setSessionId(message.session_id);
3561
4178
  const structuredOutput = "structured_output" in message ? message.structured_output : void 0;
4179
+ if (structuredOutput !== void 0 && finishReason.unified === "tool-calls") {
4180
+ finishReason = { unified: "stop", raw: finishReason.raw };
4181
+ }
4182
+ this.logger.debug(`[claude-code] Stream finish reason: ${finishReason.unified}`);
3562
4183
  const alreadyStreamedJson = hasStreamedJson && options.responseFormat?.type === "json" && hasReceivedStreamEvents;
3563
4184
  if (alreadyStreamedJson) {
3564
4185
  if (textPartId) {
@@ -3672,6 +4293,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3672
4293
  ...metadataTracking.permissionDenials.length > 0 && {
3673
4294
  permissionDenials: metadataTracking.permissionDenials
3674
4295
  },
4296
+ ...metadataTracking.taskEvents.length > 0 && {
4297
+ taskEvents: metadataTracking.taskEvents
4298
+ },
4299
+ ...metadataTracking.hookEvents.length > 0 && {
4300
+ hookEvents: metadataTracking.hookEvents
4301
+ },
4302
+ ...metadataTracking.mcpServers !== void 0 && {
4303
+ mcpServers: metadataTracking.mcpServers
4304
+ },
3675
4305
  ...metadataTracking.mirrorErrors.length > 0 && {
3676
4306
  mirrorErrors: metadataTracking.mirrorErrors
3677
4307
  },
@@ -3689,12 +4319,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3689
4319
  });
3690
4320
  controller.close();
3691
4321
  const effectivePromptSuggestions = sdkOptions?.promptSuggestions ?? this.settings.promptSuggestions;
3692
- if (this.settings.onPromptSuggestion && effectivePromptSuggestions !== false) {
3693
- await this.drainPromptSuggestion(response, this.settings.onPromptSuggestion);
4322
+ const shouldDrainPromptSuggestion = effectivePromptSuggestions !== false && (this.settings.onPromptSuggestion !== void 0 || this.settings.onSdkMessage !== void 0);
4323
+ if (shouldDrainPromptSuggestion) {
4324
+ await this.drainPromptSuggestion(sdkIterator, this.settings.onPromptSuggestion);
3694
4325
  }
3695
4326
  return;
3696
4327
  } else if (message.type === "system" && message.subtype === "init") {
3697
4328
  this.logMcpConnectionIssues(message.mcp_servers);
4329
+ this.trackMcpStatusFromInit(message, metadataTracking);
3698
4330
  this.setSessionId(message.session_id);
3699
4331
  this.logger.info(`[claude-code] Stream session initialized: ${message.session_id}`);
3700
4332
  controller.enqueue({
@@ -3768,6 +4400,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3768
4400
  ...metadataTracking.permissionDenials.length > 0 && {
3769
4401
  permissionDenials: metadataTracking.permissionDenials
3770
4402
  },
4403
+ ...metadataTracking.taskEvents.length > 0 && {
4404
+ taskEvents: metadataTracking.taskEvents
4405
+ },
4406
+ ...metadataTracking.hookEvents.length > 0 && {
4407
+ hookEvents: metadataTracking.hookEvents
4408
+ },
4409
+ ...metadataTracking.mcpServers !== void 0 && {
4410
+ mcpServers: metadataTracking.mcpServers
4411
+ },
3771
4412
  ...metadataTracking.mirrorErrors.length > 0 && {
3772
4413
  mirrorErrors: metadataTracking.mirrorErrors
3773
4414
  },
@@ -3815,19 +4456,23 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3815
4456
  };
3816
4457
  }
3817
4458
  serializeWarningsForMetadata(warnings) {
3818
- const result = warnings.map((w) => {
3819
- const base = { type: w.type };
3820
- if ("message" in w) {
3821
- const m = w.message;
3822
- if (m !== void 0) base.message = String(m);
3823
- }
3824
- if (w.type === "unsupported" || w.type === "compatibility") {
3825
- const feature = w.feature;
3826
- if (feature !== void 0) base.feature = String(feature);
3827
- if ("details" in w) {
3828
- const d = w.details;
3829
- if (d !== void 0) base.details = String(d);
3830
- }
4459
+ const result = warnings.map((warning) => {
4460
+ const base = { type: warning.type };
4461
+ switch (warning.type) {
4462
+ case "unsupported":
4463
+ case "compatibility":
4464
+ base.feature = warning.feature;
4465
+ if (warning.details !== void 0) {
4466
+ base.details = warning.details;
4467
+ }
4468
+ break;
4469
+ case "deprecated":
4470
+ base.setting = warning.setting;
4471
+ base.message = warning.message;
4472
+ break;
4473
+ case "other":
4474
+ base.message = warning.message;
4475
+ break;
3831
4476
  }
3832
4477
  return base;
3833
4478
  });
@@ -3870,7 +4515,7 @@ function createClaudeCode(options = {}) {
3870
4515
  };
3871
4516
  provider.languageModel = createModel;
3872
4517
  provider.chat = createModel;
3873
- provider.specificationVersion = "v3";
4518
+ provider.specificationVersion = "v4";
3874
4519
  provider.embeddingModel = (modelId) => {
3875
4520
  throw new NoSuchModelError2({
3876
4521
  modelId,
@@ -3894,7 +4539,9 @@ import {
3894
4539
  SYSTEM_PROMPT_DYNAMIC_BOUNDARY,
3895
4540
  InMemorySessionStore,
3896
4541
  HOOK_EVENTS,
3897
- AbortError
4542
+ AbortError,
4543
+ resolveSettings,
4544
+ filterEscalatingDefaultMode
3898
4545
  } from "@anthropic-ai/claude-agent-sdk";
3899
4546
  import {
3900
4547
  listSessions,
@@ -3914,6 +4561,16 @@ import { startup } from "@anthropic-ai/claude-agent-sdk";
3914
4561
  // src/mcp-helpers.ts
3915
4562
  import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
3916
4563
  import "zod";
4564
+ var warnedDescriptionFunctionToolNames = /* @__PURE__ */ new Set();
4565
+ function warnDiscardedDescriptionFunction(toolName) {
4566
+ if (warnedDescriptionFunctionToolNames.has(toolName)) {
4567
+ return;
4568
+ }
4569
+ warnedDescriptionFunctionToolNames.add(toolName);
4570
+ console.warn(
4571
+ `[claude-code] AI SDK tool "${toolName}" has a function-valued description; createAiSdkMcpServer cannot evaluate it during MCP bridging, so the bridged tool description was omitted.`
4572
+ );
4573
+ }
3917
4574
  function buildIsErrorResult(text) {
3918
4575
  return {
3919
4576
  isError: true,
@@ -3956,7 +4613,11 @@ function createCustomMcpServer(config) {
3956
4613
  }
3957
4614
  var AI_SDK_SCHEMA_SYMBOL = Symbol.for("vercel.ai.schema");
3958
4615
  function isAiSdkJsonSchema(schema) {
3959
- return typeof schema === "object" && schema !== null && AI_SDK_SCHEMA_SYMBOL in schema;
4616
+ if (typeof schema !== "object" || schema === null) {
4617
+ return false;
4618
+ }
4619
+ const candidate = schema;
4620
+ return candidate[AI_SDK_SCHEMA_SYMBOL] === true && "jsonSchema" in candidate && "validate" in candidate;
3960
4621
  }
3961
4622
  function isZodObjectSchema(schema) {
3962
4623
  if (typeof schema !== "object" || schema === null) {
@@ -3991,9 +4652,13 @@ function createAiSdkMcpServer(name, tools) {
3991
4652
  );
3992
4653
  }
3993
4654
  const zodSchema = def.inputSchema;
4655
+ const description = typeof def.description === "string" ? def.description : "";
4656
+ if (typeof def.description === "function") {
4657
+ warnDiscardedDescriptionFunction(toolName);
4658
+ }
3994
4659
  return tool(
3995
4660
  toolName,
3996
- def.description ?? "",
4661
+ description,
3997
4662
  zodSchema.shape,
3998
4663
  async (args, extra) => {
3999
4664
  try {
@@ -4026,10 +4691,12 @@ export {
4026
4691
  createAiSdkMcpServer,
4027
4692
  createAuthenticationError,
4028
4693
  createClaudeCode,
4694
+ createClaudeCodeQueryController,
4029
4695
  createCustomMcpServer,
4030
4696
  createSdkMcpServer2 as createSdkMcpServer,
4031
4697
  createTimeoutError,
4032
4698
  deleteSession,
4699
+ filterEscalatingDefaultMode,
4033
4700
  foldSessionSummary,
4034
4701
  forkSession,
4035
4702
  getErrorMetadata,
@@ -4042,6 +4709,7 @@ export {
4042
4709
  listSessions,
4043
4710
  listSubagents,
4044
4711
  renameSession,
4712
+ resolveSettings,
4045
4713
  startup,
4046
4714
  tagSession,
4047
4715
  tool2 as tool