ai-sdk-provider-claude-code 3.5.3 → 4.0.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/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/");
68
+ }
69
+ function isConcreteImageMimeType(mediaType) {
70
+ const normalized = normalizeMediaType(mediaType);
71
+ return normalized.startsWith("image/") && !normalized.endsWith("/*");
30
72
  }
31
- function isImageMimeType(mimeType) {
32
- return typeof mimeType === "string" && mimeType.trim().toLowerCase().startsWith("image/");
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");
@@ -561,6 +727,18 @@ var claudeCodeSettingsSchema = z.object({
561
727
  forwardSubagentText: z.boolean().optional(),
562
728
  agentProgressSummaries: z.boolean().optional(),
563
729
  includeHookEvents: z.boolean().optional(),
730
+ onSdkMessage: z.any().refine((v) => v === void 0 || typeof v === "function", {
731
+ message: "onSdkMessage must be a function"
732
+ }).optional(),
733
+ onTaskEvent: z.any().refine((v) => v === void 0 || typeof v === "function", {
734
+ message: "onTaskEvent must be a function"
735
+ }).optional(),
736
+ onHookEvent: z.any().refine((v) => v === void 0 || typeof v === "function", {
737
+ message: "onHookEvent must be a function"
738
+ }).optional(),
739
+ onMcpStatusChange: z.any().refine((v) => v === void 0 || typeof v === "function", {
740
+ message: "onMcpStatusChange must be a function"
741
+ }).optional(),
564
742
  taskBudget: z.object({ total: z.number().positive() }).strict().optional(),
565
743
  sessionStore: z.any().refine(
566
744
  (val) => val === void 0 || typeof val === "object" && val !== null && typeof val.append === "function" && typeof val.load === "function",
@@ -577,6 +755,9 @@ var claudeCodeSettingsSchema = z.object({
577
755
  onUserDialog: z.any().refine((v) => v === void 0 || typeof v === "function", {
578
756
  message: "onUserDialog must be a function"
579
757
  }).optional(),
758
+ onElicitation: z.any().refine((v) => v === void 0 || typeof v === "function", {
759
+ message: "onElicitation must be a function"
760
+ }).optional(),
580
761
  supportedDialogKinds: z.array(z.string()).optional(),
581
762
  hooks: z.record(
582
763
  z.string(),
@@ -623,6 +804,7 @@ var claudeCodeSettingsSchema = z.object({
623
804
  logger: z.union([z.literal(false), loggerFunctionSchema]).optional(),
624
805
  env: z.record(z.string(), z.string().optional()).optional(),
625
806
  additionalDirectories: z.array(z.string()).optional(),
807
+ agent: z.string().optional(),
626
808
  agents: z.record(
627
809
  z.string(),
628
810
  z.object({
@@ -660,10 +842,13 @@ var claudeCodeSettingsSchema = z.object({
660
842
  onQueryCreated: z.any().refine((val) => val === void 0 || typeof val === "function", {
661
843
  message: "onQueryCreated must be a function"
662
844
  }).optional(),
845
+ onQueryControllerCreated: z.any().refine((val) => val === void 0 || typeof val === "function", {
846
+ message: "onQueryControllerCreated must be a function"
847
+ }).optional(),
663
848
  onStreamStart: z.any().refine((val) => val === void 0 || typeof val === "function", {
664
849
  message: "onStreamStart must be a function"
665
850
  }).optional(),
666
- // Callback invoked with the predicted next user prompt (active unless promptSuggestions: false)
851
+ // Callback invoked with the predicted next user prompt (requires promptSuggestions: true)
667
852
  onPromptSuggestion: z.any().refine((val) => val === void 0 || typeof val === "function", {
668
853
  message: "onPromptSuggestion must be a function"
669
854
  }).optional()
@@ -748,6 +933,11 @@ function validateSettings(settings) {
748
933
  `Very high maxThinkingTokens (${validSettings.maxThinkingTokens}) may increase response time`
749
934
  );
750
935
  }
936
+ if (validSettings.onPromptSuggestion !== void 0 && effective("promptSuggestions") !== true) {
937
+ warnings.push(
938
+ "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."
939
+ );
940
+ }
751
941
  if (validSettings.allowedTools && validSettings.disallowedTools) {
752
942
  warnings.push(
753
943
  "Both allowedTools and disallowedTools are specified. Only allowedTools will be used."
@@ -985,9 +1175,38 @@ function createVerboseLogger(logger, verbose = false) {
985
1175
  };
986
1176
  }
987
1177
 
1178
+ // src/query-controller.ts
1179
+ function createClaudeCodeQueryController(query2) {
1180
+ const controller = {
1181
+ rawQuery: query2,
1182
+ // SDK 0.3.205 returns the control-protocol response; the public contract stays Promise<void>.
1183
+ interrupt: async () => {
1184
+ await query2.interrupt();
1185
+ },
1186
+ setPermissionMode: (mode) => query2.setPermissionMode(mode),
1187
+ setMcpPermissionModeOverride: (serverName, mode) => query2.setMcpPermissionModeOverride(serverName, mode),
1188
+ setModel: (model) => query2.setModel(model),
1189
+ setMaxThinkingTokens: (maxThinkingTokens, thinkingDisplay) => query2.setMaxThinkingTokens(maxThinkingTokens, thinkingDisplay),
1190
+ applyFlagSettings: (settings) => query2.applyFlagSettings(settings),
1191
+ mcpServerStatus: () => query2.mcpServerStatus(),
1192
+ reconnectMcpServer: (serverName) => query2.reconnectMcpServer(serverName),
1193
+ toggleMcpServer: (serverName, enabled) => query2.toggleMcpServer(serverName, enabled),
1194
+ setMcpServers: (servers) => query2.setMcpServers(servers),
1195
+ getContextUsage: () => query2.getContextUsage(),
1196
+ rewindFiles: (userMessageId, options) => query2.rewindFiles(userMessageId, options),
1197
+ stopTask: (taskId) => query2.stopTask(taskId),
1198
+ backgroundTasks: (toolUseId) => toolUseId === void 0 ? query2.backgroundTasks() : query2.backgroundTasks(toolUseId)
1199
+ };
1200
+ const streamInput = query2.streamInput;
1201
+ if (typeof streamInput === "function") {
1202
+ controller.streamInput = (stream) => streamInput.call(query2, stream);
1203
+ }
1204
+ return controller;
1205
+ }
1206
+
988
1207
  // src/claude-code-language-model.ts
989
1208
  import { query } from "@anthropic-ai/claude-agent-sdk";
990
- var PROVIDER_VERSION = "3.5.3";
1209
+ var PROVIDER_VERSION = "4.0.1";
991
1210
  var DEFAULT_CLIENT_APP = `ai-sdk-provider-claude-code/${PROVIDER_VERSION}`;
992
1211
  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
1212
  var MIN_TRUNCATION_LENGTH = 512;
@@ -1027,6 +1246,13 @@ function isClaudeCodeTruncationError(error, bufferedText) {
1027
1246
  return true;
1028
1247
  }
1029
1248
  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.";
1249
+ var INTERNAL_STRUCTURED_OUTPUT_TOOL_NAME = "StructuredOutput";
1250
+ function isInternalStructuredOutputTool(toolName, options) {
1251
+ return options.responseFormat?.type === "json" && toolName === INTERNAL_STRUCTURED_OUTPUT_TOOL_NAME;
1252
+ }
1253
+ function isNonTextToolUseContentBlockType(type) {
1254
+ return type === "server_tool_use" || type === "mcp_tool_use";
1255
+ }
1030
1256
  function extractJsonObjectText(text) {
1031
1257
  const trimmed = text.trim();
1032
1258
  if (!trimmed) {
@@ -1120,7 +1346,7 @@ function getBaseProcessEnv() {
1120
1346
  }
1121
1347
  return env;
1122
1348
  }
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).";
1349
+ 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
1350
  var SDK_OPTIONS_BLOCKLIST = /* @__PURE__ */ new Set(["model", "abortController", "prompt", "outputFormat"]);
1125
1351
  var SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
1126
1352
  function isSubagentToolName(name) {
@@ -1143,7 +1369,7 @@ function computeRetractedToolCallIds(retracted, descriptors) {
1143
1369
  function applySupersede(message, evict, logger, guard = "array") {
1144
1370
  const supersedes = message.supersedes;
1145
1371
  const triggered = guard === "truthy" ? Boolean(supersedes && supersedes.length > 0) : Array.isArray(supersedes) && supersedes.length > 0;
1146
- if (!triggered) {
1372
+ if (!triggered || supersedes === void 0) {
1147
1373
  return false;
1148
1374
  }
1149
1375
  logger.debug(`[claude-code] Assistant message supersedes ${supersedes.length} prior message(s)`);
@@ -1156,12 +1382,126 @@ function buildRetractionEvictor(evict) {
1156
1382
  var INFORMATIONAL_SYSTEM_SUBTYPES = /* @__PURE__ */ new Set([
1157
1383
  "notification",
1158
1384
  "status",
1159
- "task_updated",
1160
1385
  "session_state_changed",
1161
1386
  "commands_changed",
1162
1387
  "memory_recall",
1163
- "plugin_install"
1388
+ "plugin_install",
1389
+ "informational"
1164
1390
  ]);
1391
+ var CLAUDE_REASONING_EFFORT_MAP = {
1392
+ minimal: "low",
1393
+ low: "low",
1394
+ medium: "medium",
1395
+ high: "high",
1396
+ xhigh: "xhigh"
1397
+ };
1398
+ var CLAUDE_EFFORT_LEVELS = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh", "max"]);
1399
+ function isObjectRecord(value) {
1400
+ return typeof value === "object" && value !== null;
1401
+ }
1402
+ function toJsonSafeValue(value) {
1403
+ if (value === void 0) {
1404
+ return void 0;
1405
+ }
1406
+ try {
1407
+ const serialized = JSON.stringify(value);
1408
+ return serialized === void 0 ? void 0 : JSON.parse(serialized);
1409
+ } catch {
1410
+ return String(value);
1411
+ }
1412
+ }
1413
+ function deepFreezeJsonValue(value) {
1414
+ if (Array.isArray(value)) {
1415
+ for (const nested of value) {
1416
+ deepFreezeJsonValue(nested);
1417
+ }
1418
+ return Object.freeze(value);
1419
+ }
1420
+ if (!isObjectRecord(value)) {
1421
+ return value;
1422
+ }
1423
+ const objectValue = value;
1424
+ for (const nested of Object.values(objectValue)) {
1425
+ if (nested !== void 0) {
1426
+ deepFreezeJsonValue(nested);
1427
+ }
1428
+ }
1429
+ return Object.freeze(objectValue);
1430
+ }
1431
+ function toJsonSafeClone(value) {
1432
+ const clone = toJsonSafeValue(value);
1433
+ if (clone === void 0) {
1434
+ return void 0;
1435
+ }
1436
+ return clone;
1437
+ }
1438
+ function toImmutableJsonSafeClone(value) {
1439
+ const clone = toJsonSafeValue(value);
1440
+ if (clone === void 0) {
1441
+ return void 0;
1442
+ }
1443
+ return deepFreezeJsonValue(clone);
1444
+ }
1445
+ function hasValidThinkingDisplay(value) {
1446
+ return value === void 0 || value === "summarized" || value === "omitted";
1447
+ }
1448
+ function isClaudeEffortLevel(value) {
1449
+ return typeof value === "string" && CLAUDE_EFFORT_LEVELS.has(value);
1450
+ }
1451
+ function isClaudeThinkingConfig(value) {
1452
+ if (!isObjectRecord(value)) {
1453
+ return false;
1454
+ }
1455
+ if (value.type === "disabled") {
1456
+ return true;
1457
+ }
1458
+ if (value.type === "adaptive") {
1459
+ return hasValidThinkingDisplay(value.display);
1460
+ }
1461
+ if (value.type === "enabled") {
1462
+ const budgetTokens = value.budgetTokens;
1463
+ return (budgetTokens === void 0 || typeof budgetTokens === "number") && hasValidThinkingDisplay(value.display);
1464
+ }
1465
+ return false;
1466
+ }
1467
+ function addInvalidClaudeReasoningProviderOptionWarning(warnings, key) {
1468
+ warnings?.push({
1469
+ type: "other",
1470
+ message: `Invalid providerOptions['claude-code'].${key} value was ignored.`
1471
+ });
1472
+ }
1473
+ function extractClaudeReasoningProviderOptions(providerOptions, warnings) {
1474
+ const options = providerOptions?.["claude-code"];
1475
+ if (options === void 0) {
1476
+ return { hasClaudeReasoningSettings: false };
1477
+ }
1478
+ const result = { hasClaudeReasoningSettings: false };
1479
+ if (options.thinking !== void 0) {
1480
+ if (isClaudeThinkingConfig(options.thinking)) {
1481
+ result.thinking = options.thinking;
1482
+ result.hasClaudeReasoningSettings = true;
1483
+ } else {
1484
+ addInvalidClaudeReasoningProviderOptionWarning(warnings, "thinking");
1485
+ }
1486
+ }
1487
+ if (options.effort !== void 0) {
1488
+ if (isClaudeEffortLevel(options.effort)) {
1489
+ result.effort = options.effort;
1490
+ result.hasClaudeReasoningSettings = true;
1491
+ } else {
1492
+ addInvalidClaudeReasoningProviderOptionWarning(warnings, "effort");
1493
+ }
1494
+ }
1495
+ if (options.maxThinkingTokens !== void 0) {
1496
+ if (typeof options.maxThinkingTokens === "number") {
1497
+ result.maxThinkingTokens = options.maxThinkingTokens;
1498
+ result.hasClaudeReasoningSettings = true;
1499
+ } else {
1500
+ addInvalidClaudeReasoningProviderOptionWarning(warnings, "maxThinkingTokens");
1501
+ }
1502
+ }
1503
+ return result;
1504
+ }
1165
1505
  function isContentBlock(item) {
1166
1506
  return typeof item === "object" && item !== null && "type" in item;
1167
1507
  }
@@ -1322,6 +1662,7 @@ function toAsyncIterablePrompt(messagesPrompt, outputStreamEnded, sessionId, con
1322
1662
  };
1323
1663
  }
1324
1664
  var modelMap = {
1665
+ fable: "fable",
1325
1666
  opus: "opus",
1326
1667
  sonnet: "sonnet",
1327
1668
  haiku: "haiku"
@@ -1370,7 +1711,7 @@ function truncateToolResultForStream(result, maxSize = MAX_TOOL_RESULT_SIZE) {
1370
1711
  return result;
1371
1712
  }
1372
1713
  var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1373
- specificationVersion = "v3";
1714
+ specificationVersion = "v4";
1374
1715
  defaultObjectGenerationMode = "json";
1375
1716
  supportsImageUrls = false;
1376
1717
  supportedUrls = {};
@@ -1441,6 +1782,81 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1441
1782
  }
1442
1783
  return void 0;
1443
1784
  }
1785
+ invokeObservabilityCallback(callbackName, callback, value) {
1786
+ if (!callback) {
1787
+ return;
1788
+ }
1789
+ const logError = (error) => {
1790
+ const message = error instanceof Error ? error.message : String(error);
1791
+ this.logger.warn(`[claude-code] ${callbackName} callback failed; ignoring error: ${message}`);
1792
+ if (error instanceof Error && error.stack) {
1793
+ this.logger.debug(`[claude-code] ${callbackName} callback stack: ${error.stack}`);
1794
+ }
1795
+ };
1796
+ try {
1797
+ const result = callback(value);
1798
+ if (result && typeof result.then === "function") {
1799
+ void Promise.resolve(result).catch(logError);
1800
+ }
1801
+ } catch (error) {
1802
+ logError(error);
1803
+ }
1804
+ }
1805
+ invokeSdkMessageCallback(message) {
1806
+ const onSdkMessage = this.settings.onSdkMessage;
1807
+ if (onSdkMessage === void 0) {
1808
+ return;
1809
+ }
1810
+ this.invokeObservabilityCallback(
1811
+ "onSdkMessage",
1812
+ onSdkMessage,
1813
+ toImmutableJsonSafeClone(message)
1814
+ );
1815
+ }
1816
+ notifyQueryCreated(response) {
1817
+ this.settings.onQueryCreated?.(response);
1818
+ const onQueryControllerCreated = this.settings.onQueryControllerCreated;
1819
+ if (onQueryControllerCreated !== void 0) {
1820
+ this.invokeObservabilityCallback(
1821
+ "onQueryControllerCreated",
1822
+ onQueryControllerCreated,
1823
+ createClaudeCodeQueryController(response)
1824
+ );
1825
+ }
1826
+ }
1827
+ trackTaskEvent(event, tracking) {
1828
+ tracking.taskEvents.push(toJsonSafeClone(event));
1829
+ const onTaskEvent = this.settings.onTaskEvent;
1830
+ if (onTaskEvent !== void 0) {
1831
+ this.invokeObservabilityCallback("onTaskEvent", onTaskEvent, toImmutableJsonSafeClone(event));
1832
+ }
1833
+ }
1834
+ trackHookEvent(event, tracking) {
1835
+ tracking.hookEvents.push(toJsonSafeClone(event));
1836
+ const onHookEvent = this.settings.onHookEvent;
1837
+ if (onHookEvent !== void 0) {
1838
+ this.invokeObservabilityCallback("onHookEvent", onHookEvent, toImmutableJsonSafeClone(event));
1839
+ }
1840
+ }
1841
+ trackMcpStatusFromInit(message, tracking) {
1842
+ const servers = message.mcp_servers;
1843
+ tracking.mcpServers = toJsonSafeClone(servers);
1844
+ const statusEvent = {
1845
+ subtype: "init",
1846
+ sessionId: message.session_id,
1847
+ uuid: message.uuid,
1848
+ servers,
1849
+ raw: message
1850
+ };
1851
+ const onMcpStatusChange = this.settings.onMcpStatusChange;
1852
+ if (onMcpStatusChange !== void 0) {
1853
+ this.invokeObservabilityCallback(
1854
+ "onMcpStatusChange",
1855
+ onMcpStatusChange,
1856
+ toImmutableJsonSafeClone(statusEvent)
1857
+ );
1858
+ }
1859
+ }
1444
1860
  /**
1445
1861
  * Single source of truth for the CLI's `--session-id` exclusivity rule.
1446
1862
  *
@@ -1605,7 +2021,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1605
2021
  input,
1606
2022
  providerExecuted: true,
1607
2023
  dynamic: true,
1608
- // V3 field: indicates tool is provider-defined (not in user's tools map)
2024
+ // V4 field: indicates tool is provider-defined (not in user's tools map)
1609
2025
  providerMetadata: {
1610
2026
  "claude-code": {
1611
2027
  // rawInput preserves the original serialized format before AI SDK normalization.
@@ -1645,12 +2061,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1645
2061
  toolName,
1646
2062
  // `?? ''`: absent `content` (undefined) and string results that
1647
2063
  // normalize to JSON null (e.g. the string "null") must not violate the
1648
- // NonNullable<JSONValue> contract of LanguageModelV3ToolResult.result.
2064
+ // NonNullable<JSONValue> contract of LanguageModelV4ToolResult.result.
1649
2065
  result: truncatedResult ?? "",
1650
2066
  isError,
1651
- providerExecuted: true,
1652
2067
  dynamic: true,
1653
- // V3 field: indicates tool is provider-defined
2068
+ // V4 field: indicates tool is provider-defined
1654
2069
  providerMetadata: {
1655
2070
  "claude-code": {
1656
2071
  // rawResult preserves the original CLI output string before JSON parsing.
@@ -1673,37 +2088,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1673
2088
  })() : String(error);
1674
2089
  }
1675
2090
  /**
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).
2091
+ * Builds a V4 provider `tool-result` part with `isError: true` from a
2092
+ * user-message `tool_error` block. V4 has no provider-level `tool-error`
2093
+ * content or stream part; AI SDK core derives user-facing tool-error
2094
+ * semantics from this result while preserving providerMetadata.
1679
2095
  */
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) {
2096
+ buildErroredToolResultPart(toolCallId, toolName, error, parentToolCallId) {
1707
2097
  const rawError = this.serializeToolError(error);
1708
2098
  return {
1709
2099
  type: "tool-result",
@@ -1711,9 +2101,8 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1711
2101
  toolName,
1712
2102
  result: rawError,
1713
2103
  isError: true,
1714
- providerExecuted: true,
1715
2104
  dynamic: true,
1716
- // V3 field: indicates tool is provider-defined
2105
+ // V4 field: indicates tool is provider-defined
1717
2106
  providerMetadata: {
1718
2107
  "claude-code": {
1719
2108
  rawError,
@@ -1739,7 +2128,33 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1739
2128
  );
1740
2129
  return true;
1741
2130
  }
1742
- generateAllWarnings(options, prompt) {
2131
+ resolvePortableReasoningOptions(options, sdkOptions, claudeProviderOptions, warnings) {
2132
+ 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;
2133
+ if (hasClaudeSpecificReasoning || !isCustomReasoning(options.reasoning)) {
2134
+ return {};
2135
+ }
2136
+ if (options.reasoning === "none") {
2137
+ return { thinking: { type: "disabled" } };
2138
+ }
2139
+ const effort = mapReasoningToProviderEffort({
2140
+ reasoning: options.reasoning,
2141
+ effortMap: CLAUDE_REASONING_EFFORT_MAP,
2142
+ warnings: warnings ?? []
2143
+ });
2144
+ return effort === void 0 ? {} : { effort };
2145
+ }
2146
+ applyClaudeReasoningProviderOptions(opts, claudeProviderOptions) {
2147
+ if (claudeProviderOptions.thinking !== void 0) {
2148
+ opts.thinking = claudeProviderOptions.thinking;
2149
+ }
2150
+ if (claudeProviderOptions.effort !== void 0) {
2151
+ opts.effort = claudeProviderOptions.effort;
2152
+ }
2153
+ if (claudeProviderOptions.maxThinkingTokens !== void 0) {
2154
+ opts.maxThinkingTokens = claudeProviderOptions.maxThinkingTokens;
2155
+ }
2156
+ }
2157
+ generateAllWarnings(options, prompt, sdkOptions) {
1743
2158
  const warnings = [];
1744
2159
  const unsupportedParams = [];
1745
2160
  if (options.temperature !== void 0) unsupportedParams.push("temperature");
@@ -1806,9 +2221,18 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1806
2221
  message: promptWarning
1807
2222
  });
1808
2223
  }
2224
+ this.resolvePortableReasoningOptions(
2225
+ options,
2226
+ sdkOptions,
2227
+ extractClaudeReasoningProviderOptions(options.providerOptions, warnings),
2228
+ warnings
2229
+ );
1809
2230
  return warnings;
1810
2231
  }
1811
- createQueryOptions(abortController, responseFormat, stderrCollector, sdkOptions, effectiveResume) {
2232
+ createQueryOptions(abortController, options, stderrCollector, sdkOptions, effectiveResume) {
2233
+ const claudeReasoningProviderOptions = extractClaudeReasoningProviderOptions(
2234
+ options.providerOptions
2235
+ );
1812
2236
  const opts = {
1813
2237
  model: this.getModel(),
1814
2238
  abortController,
@@ -1836,8 +2260,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1836
2260
  sandbox: this.settings.sandbox,
1837
2261
  tools: this.settings.tools,
1838
2262
  mcpServers: this.settings.mcpServers,
1839
- canUseTool: this.settings.canUseTool
2263
+ canUseTool: this.settings.canUseTool,
2264
+ onElicitation: this.settings.onElicitation,
2265
+ agent: this.settings.agent
1840
2266
  };
2267
+ Object.assign(
2268
+ opts,
2269
+ this.resolvePortableReasoningOptions(options, sdkOptions, claudeReasoningProviderOptions)
2270
+ );
1841
2271
  if (this.settings.onUserDialog !== void 0) {
1842
2272
  opts.onUserDialog = this.settings.onUserDialog;
1843
2273
  }
@@ -1966,6 +2396,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1966
2396
  }
1967
2397
  }
1968
2398
  }
2399
+ this.applyClaudeReasoningProviderOptions(opts, claudeReasoningProviderOptions);
1969
2400
  this.applySessionResolution(opts, effectiveResume);
1970
2401
  if (typeof opts.fallbackModel === "string" && opts.fallbackModel === opts.model) {
1971
2402
  throw new Error(
@@ -1988,9 +2419,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1988
2419
  mergedEnv.CLAUDE_AGENT_SDK_CLIENT_APP = DEFAULT_CLIENT_APP;
1989
2420
  }
1990
2421
  opts.env = mergedEnv;
1991
- if (responseFormat?.type === "json" && responseFormat.schema) {
2422
+ if (options.responseFormat?.type === "json" && options.responseFormat.schema) {
1992
2423
  const { schema: sanitizedSchema, strippedFormatPaths } = sanitizeJsonSchemaForOutputFormat(
1993
- responseFormat.schema
2424
+ options.responseFormat.schema
1994
2425
  );
1995
2426
  if (strippedFormatPaths.length > 0) {
1996
2427
  this.logger.debug(
@@ -2087,7 +2518,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2087
2518
  if (errorKind === "model_not_found" || errorMessage.includes("model_not_found") || errorMessage.includes("no such model")) {
2088
2519
  const originalMessage = isErrorWithMessage(error) && error.message ? error.message : "Model not found";
2089
2520
  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.`,
2521
+ 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
2522
  code: errorCode || void 0,
2092
2523
  exitCode,
2093
2524
  stderr,
@@ -2157,16 +2588,159 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2157
2588
  break;
2158
2589
  case "permission_denied": {
2159
2590
  const reason = message.decision_reason ?? message.message;
2591
+ const raw = toJsonSafeValue(message);
2160
2592
  tracking.permissionDenials.push({
2161
2593
  toolName: message.tool_name,
2162
2594
  toolUseId: message.tool_use_id,
2163
- ...reason !== void 0 && { reason }
2595
+ ...message.agent_id !== void 0 && { agentId: message.agent_id },
2596
+ ...message.decision_reason_type !== void 0 && {
2597
+ decisionReasonType: message.decision_reason_type
2598
+ },
2599
+ ...reason !== void 0 && { reason },
2600
+ ...raw !== void 0 && { raw }
2164
2601
  });
2165
2602
  this.logger.warn(
2166
2603
  `[claude-code] Permission denied - Tool: ${message.tool_name}${reason ? `, Reason: ${reason}` : ""}`
2167
2604
  );
2168
2605
  break;
2169
2606
  }
2607
+ case "task_started":
2608
+ this.trackTaskEvent(
2609
+ {
2610
+ subtype: "task_started",
2611
+ taskId: message.task_id,
2612
+ ...message.tool_use_id !== void 0 && { toolUseId: message.tool_use_id },
2613
+ description: message.description,
2614
+ ...message.subagent_type !== void 0 && { subagentType: message.subagent_type },
2615
+ ...message.task_type !== void 0 && { taskType: message.task_type },
2616
+ ...message.workflow_name !== void 0 && { workflowName: message.workflow_name },
2617
+ ...message.prompt !== void 0 && { prompt: message.prompt },
2618
+ ...message.skip_transcript !== void 0 && {
2619
+ skipTranscript: message.skip_transcript
2620
+ },
2621
+ uuid: message.uuid,
2622
+ sessionId: message.session_id,
2623
+ raw: message
2624
+ },
2625
+ tracking
2626
+ );
2627
+ this.logger.debug(`[claude-code] Task started - ID: ${message.task_id}`);
2628
+ break;
2629
+ case "task_progress":
2630
+ this.trackTaskEvent(
2631
+ {
2632
+ subtype: "task_progress",
2633
+ taskId: message.task_id,
2634
+ ...message.tool_use_id !== void 0 && { toolUseId: message.tool_use_id },
2635
+ description: message.description,
2636
+ ...message.subagent_type !== void 0 && { subagentType: message.subagent_type },
2637
+ usage: message.usage,
2638
+ ...message.last_tool_name !== void 0 && { lastToolName: message.last_tool_name },
2639
+ ...message.summary !== void 0 && { summary: message.summary },
2640
+ uuid: message.uuid,
2641
+ sessionId: message.session_id,
2642
+ raw: message
2643
+ },
2644
+ tracking
2645
+ );
2646
+ this.logger.debug(`[claude-code] Task progress - ID: ${message.task_id}`);
2647
+ break;
2648
+ case "task_updated":
2649
+ this.trackTaskEvent(
2650
+ {
2651
+ subtype: "task_updated",
2652
+ taskId: message.task_id,
2653
+ patch: message.patch,
2654
+ uuid: message.uuid,
2655
+ sessionId: message.session_id,
2656
+ raw: message
2657
+ },
2658
+ tracking
2659
+ );
2660
+ this.logger.debug(`[claude-code] Task updated - ID: ${message.task_id}`);
2661
+ break;
2662
+ case "task_notification":
2663
+ this.trackTaskEvent(
2664
+ {
2665
+ subtype: "task_notification",
2666
+ taskId: message.task_id,
2667
+ ...message.tool_use_id !== void 0 && { toolUseId: message.tool_use_id },
2668
+ status: message.status,
2669
+ outputFile: message.output_file,
2670
+ summary: message.summary,
2671
+ ...message.usage !== void 0 && { usage: message.usage },
2672
+ ...message.skip_transcript !== void 0 && {
2673
+ skipTranscript: message.skip_transcript
2674
+ },
2675
+ uuid: message.uuid,
2676
+ sessionId: message.session_id,
2677
+ raw: message
2678
+ },
2679
+ tracking
2680
+ );
2681
+ this.logger.debug(
2682
+ `[claude-code] Task notification - ID: ${message.task_id}, Status: ${message.status}`
2683
+ );
2684
+ break;
2685
+ case "hook_started":
2686
+ this.trackHookEvent(
2687
+ {
2688
+ subtype: "hook_started",
2689
+ hookId: message.hook_id,
2690
+ hookName: message.hook_name,
2691
+ hookEvent: message.hook_event,
2692
+ uuid: message.uuid,
2693
+ sessionId: message.session_id,
2694
+ raw: message
2695
+ },
2696
+ tracking
2697
+ );
2698
+ this.logger.debug(
2699
+ `[claude-code] Hook started - ID: ${message.hook_id}, Event: ${message.hook_event}`
2700
+ );
2701
+ break;
2702
+ case "hook_progress":
2703
+ this.trackHookEvent(
2704
+ {
2705
+ subtype: "hook_progress",
2706
+ hookId: message.hook_id,
2707
+ hookName: message.hook_name,
2708
+ hookEvent: message.hook_event,
2709
+ stdout: message.stdout,
2710
+ stderr: message.stderr,
2711
+ output: message.output,
2712
+ uuid: message.uuid,
2713
+ sessionId: message.session_id,
2714
+ raw: message
2715
+ },
2716
+ tracking
2717
+ );
2718
+ this.logger.debug(
2719
+ `[claude-code] Hook progress - ID: ${message.hook_id}, Event: ${message.hook_event}`
2720
+ );
2721
+ break;
2722
+ case "hook_response":
2723
+ this.trackHookEvent(
2724
+ {
2725
+ subtype: "hook_response",
2726
+ hookId: message.hook_id,
2727
+ hookName: message.hook_name,
2728
+ hookEvent: message.hook_event,
2729
+ output: message.output,
2730
+ stdout: message.stdout,
2731
+ stderr: message.stderr,
2732
+ ...message.exit_code !== void 0 && { exitCode: message.exit_code },
2733
+ outcome: message.outcome,
2734
+ uuid: message.uuid,
2735
+ sessionId: message.session_id,
2736
+ raw: message
2737
+ },
2738
+ tracking
2739
+ );
2740
+ this.logger.debug(
2741
+ `[claude-code] Hook response - ID: ${message.hook_id}, Outcome: ${message.outcome}`
2742
+ );
2743
+ break;
2170
2744
  case "mirror_error": {
2171
2745
  const mirrorError = message.error ?? "unknown error";
2172
2746
  const mirrorSessionId = message.key?.sessionId ?? message.session_id ?? "unknown";
@@ -2219,12 +2793,21 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2219
2793
  const alreadyTracked = tracking.permissionDenials.some(
2220
2794
  (d) => d.toolUseId !== void 0 && d.toolUseId === denial.tool_use_id
2221
2795
  );
2222
- if (!alreadyTracked) {
2223
- tracking.permissionDenials.push({
2224
- toolName: denial.tool_name,
2225
- toolUseId: denial.tool_use_id
2226
- });
2796
+ if (alreadyTracked) {
2797
+ continue;
2227
2798
  }
2799
+ const agentId = typeof denial.agent_id === "string" ? denial.agent_id : typeof denial.agentId === "string" ? denial.agentId : void 0;
2800
+ const decisionReasonType = typeof denial.decision_reason_type === "string" ? denial.decision_reason_type : typeof denial.decisionReasonType === "string" ? denial.decisionReasonType : void 0;
2801
+ const reason = typeof denial.decision_reason === "string" ? denial.decision_reason : typeof denial.reason === "string" ? denial.reason : typeof denial.message === "string" ? denial.message : void 0;
2802
+ const raw = toJsonSafeValue(denial);
2803
+ tracking.permissionDenials.push({
2804
+ toolName: denial.tool_name,
2805
+ toolUseId: denial.tool_use_id,
2806
+ ...agentId !== void 0 && { agentId },
2807
+ ...decisionReasonType !== void 0 && { decisionReasonType },
2808
+ ...reason !== void 0 && { reason },
2809
+ ...raw !== void 0 && { raw }
2810
+ });
2228
2811
  }
2229
2812
  }
2230
2813
  /**
@@ -2233,11 +2816,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2233
2816
  * suggestion arrives AFTER the result message; the SDK emits at most one
2234
2817
  * per turn, so stop once it is delivered, and a timeout closes the
2235
2818
  * 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.
2819
+ * result without emitting one. Drained messages still pass through the
2820
+ * generic raw SDK callback before prompt-specific handling.
2238
2821
  */
2239
- async drainPromptSuggestion(response, onPromptSuggestion) {
2240
- const iterator = response[Symbol.asyncIterator]();
2822
+ async drainPromptSuggestion(iterator, onPromptSuggestion) {
2241
2823
  let drainTimer;
2242
2824
  const drainTimeout = new Promise((resolve) => {
2243
2825
  drainTimer = setTimeout(
@@ -2260,8 +2842,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2260
2842
  }
2261
2843
  const trailingMessage = winner.value;
2262
2844
  this.logger.debug(`[claude-code] Post-result message type: ${trailingMessage.type}`);
2845
+ this.invokeSdkMessageCallback(trailingMessage);
2263
2846
  if (trailingMessage.type === "prompt_suggestion") {
2264
- onPromptSuggestion(trailingMessage.suggestion);
2847
+ onPromptSuggestion?.(trailingMessage.suggestion);
2265
2848
  void iterator.return?.().catch(() => {
2266
2849
  });
2267
2850
  break;
@@ -2303,7 +2886,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2303
2886
  const effectiveResume = this.getEffectiveResume(sdkOptions);
2304
2887
  const queryOptions = this.createQueryOptions(
2305
2888
  abortController,
2306
- options.responseFormat,
2889
+ options,
2307
2890
  stderrCollector,
2308
2891
  sdkOptions,
2309
2892
  effectiveResume
@@ -2377,9 +2960,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2377
2960
  apiRetries: 0,
2378
2961
  permissionDenials: [],
2379
2962
  mirrorErrors: [],
2380
- estimatedThinkingTokens: 0
2963
+ estimatedThinkingTokens: 0,
2964
+ taskEvents: [],
2965
+ hookEvents: []
2381
2966
  };
2382
- const warnings = this.generateAllWarnings(options, messagesPrompt);
2967
+ const warnings = this.generateAllWarnings(
2968
+ options,
2969
+ messagesPrompt,
2970
+ sdkOptions
2971
+ );
2383
2972
  if (messageWarnings) {
2384
2973
  messageWarnings.forEach((warning) => {
2385
2974
  warnings.push({
@@ -2391,7 +2980,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2391
2980
  const modeSetting = this.settings.streamingInput ?? "auto";
2392
2981
  const effectiveCanUseTool = sdkOptions?.canUseTool ?? this.settings.canUseTool;
2393
2982
  const effectivePermissionPromptToolName = sdkOptions?.permissionPromptToolName ?? this.settings.permissionPromptToolName;
2394
- const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!effectiveCanUseTool;
2983
+ const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && (!!effectiveCanUseTool || hasImageParts);
2395
2984
  if (!wantsStreamInput && hasImageParts) {
2396
2985
  warnings.push({
2397
2986
  type: "other",
@@ -2423,7 +3012,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2423
3012
  prompt: sdkPrompt,
2424
3013
  options: queryOptions
2425
3014
  });
2426
- this.settings.onQueryCreated?.(response);
3015
+ this.notifyQueryCreated(response);
2427
3016
  let lastAssistantErrorKind;
2428
3017
  const sdkIterator = response[Symbol.asyncIterator]();
2429
3018
  const detachableResponse = {
@@ -2438,6 +3027,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2438
3027
  };
2439
3028
  for await (const message of detachableResponse) {
2440
3029
  this.logger.debug(`[claude-code] Received message type: ${message.type}`);
3030
+ this.invokeSdkMessageCallback(message);
2441
3031
  if (message.type === "assistant") {
2442
3032
  if (typeof message.error === "string") {
2443
3033
  lastAssistantErrorKind = message.error;
@@ -2466,6 +3056,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2466
3056
  } else if (block.type === "tool_use") {
2467
3057
  const [tool3] = this.extractToolUses([block]);
2468
3058
  if (!tool3) continue;
3059
+ if (isInternalStructuredOutputTool(tool3.name, options)) continue;
2469
3060
  const parentToolCallId = isSubagentToolName(tool3.name) ? null : resolveToolParentId(
2470
3061
  sdkParentToolUseId,
2471
3062
  tool3.parentToolUseId,
@@ -2576,7 +3167,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2576
3167
  kind: "tool-error",
2577
3168
  ...resultMessageUuid !== void 0 && { uuid: resultMessageUuid },
2578
3169
  toolCallId: error.id,
2579
- part: this.buildToolErrorResultPart(
3170
+ part: this.buildErroredToolResultPart(
2580
3171
  error.id,
2581
3172
  toolName,
2582
3173
  error.error,
@@ -2634,14 +3225,19 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2634
3225
  }
2635
3226
  const stopReason = "stop_reason" in message ? message.stop_reason : void 0;
2636
3227
  finishReason = mapClaudeCodeFinishReason(message.subtype, stopReason);
3228
+ if (structuredOutput !== void 0 && finishReason.unified === "tool-calls") {
3229
+ finishReason = { unified: "stop", raw: finishReason.raw };
3230
+ }
2637
3231
  this.logger.debug(`[claude-code] Finish reason: ${finishReason.unified}`);
2638
3232
  const effectivePromptSuggestions = sdkOptions?.promptSuggestions ?? this.settings.promptSuggestions;
2639
- if (this.settings.onPromptSuggestion && effectivePromptSuggestions !== false) {
2640
- await this.drainPromptSuggestion(response, this.settings.onPromptSuggestion);
3233
+ const shouldDrainPromptSuggestion = effectivePromptSuggestions !== false && (this.settings.onPromptSuggestion !== void 0 || this.settings.onSdkMessage !== void 0);
3234
+ if (shouldDrainPromptSuggestion) {
3235
+ await this.drainPromptSuggestion(sdkIterator, this.settings.onPromptSuggestion);
2641
3236
  }
2642
3237
  break;
2643
3238
  } else if (message.type === "system" && message.subtype === "init") {
2644
3239
  this.logMcpConnectionIssues(message.mcp_servers);
3240
+ this.trackMcpStatusFromInit(message, metadataTracking);
2645
3241
  this.setSessionId(message.session_id);
2646
3242
  this.logger.info(`[claude-code] Session initialized: ${message.session_id}`);
2647
3243
  } else if (message.type === "system") {
@@ -2744,6 +3340,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2744
3340
  ...metadataTracking.permissionDenials.length > 0 && {
2745
3341
  permissionDenials: metadataTracking.permissionDenials
2746
3342
  },
3343
+ ...metadataTracking.taskEvents.length > 0 && {
3344
+ taskEvents: metadataTracking.taskEvents
3345
+ },
3346
+ ...metadataTracking.hookEvents.length > 0 && {
3347
+ hookEvents: metadataTracking.hookEvents
3348
+ },
3349
+ ...metadataTracking.mcpServers !== void 0 && {
3350
+ mcpServers: metadataTracking.mcpServers
3351
+ },
2747
3352
  ...metadataTracking.mirrorErrors.length > 0 && {
2748
3353
  mirrorErrors: metadataTracking.mirrorErrors
2749
3354
  },
@@ -2782,7 +3387,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2782
3387
  const effectiveResume = this.getEffectiveResume(sdkOptions);
2783
3388
  const queryOptions = this.createQueryOptions(
2784
3389
  abortController,
2785
- options.responseFormat,
3390
+ options,
2786
3391
  stderrCollector,
2787
3392
  sdkOptions,
2788
3393
  effectiveResume
@@ -2794,7 +3399,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2794
3399
  if (queryOptions.includePartialMessages === void 0) {
2795
3400
  queryOptions.includePartialMessages = true;
2796
3401
  }
2797
- const warnings = this.generateAllWarnings(options, messagesPrompt);
3402
+ const warnings = this.generateAllWarnings(
3403
+ options,
3404
+ messagesPrompt,
3405
+ sdkOptions
3406
+ );
2798
3407
  if (messageWarnings) {
2799
3408
  messageWarnings.forEach((warning) => {
2800
3409
  warnings.push({
@@ -2806,7 +3415,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2806
3415
  const modeSetting = this.settings.streamingInput ?? "auto";
2807
3416
  const effectiveCanUseTool = sdkOptions?.canUseTool ?? this.settings.canUseTool;
2808
3417
  const effectivePermissionPromptToolName = sdkOptions?.permissionPromptToolName ?? this.settings.permissionPromptToolName;
2809
- const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!effectiveCanUseTool;
3418
+ const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && (!!effectiveCanUseTool || hasImageParts);
2810
3419
  if (!wantsStreamInput && hasImageParts) {
2811
3420
  warnings.push({
2812
3421
  type: "other",
@@ -2873,9 +3482,13 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2873
3482
  apiRetries: 0,
2874
3483
  permissionDenials: [],
2875
3484
  mirrorErrors: [],
2876
- estimatedThinkingTokens: 0
3485
+ estimatedThinkingTokens: 0,
3486
+ taskEvents: [],
3487
+ hookEvents: []
2877
3488
  };
2878
3489
  const toolBlocksByIndex = /* @__PURE__ */ new Map();
3490
+ const structuredOutputBlockIndexes = /* @__PURE__ */ new Set();
3491
+ const nonTextToolBlockIndexes = /* @__PURE__ */ new Set();
2879
3492
  const toolInputAccumulators = /* @__PURE__ */ new Map();
2880
3493
  const textBlocksByIndex = /* @__PURE__ */ new Map();
2881
3494
  let textStreamedViaContentBlock = false;
@@ -2938,9 +3551,24 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2938
3551
  prompt: sdkPrompt,
2939
3552
  options: queryOptions
2940
3553
  });
2941
- this.settings.onQueryCreated?.(response);
2942
- for await (const message of response) {
3554
+ this.notifyQueryCreated(response);
3555
+ const sdkIterator = response[Symbol.asyncIterator]();
3556
+ const detachableResponse = {
3557
+ [Symbol.asyncIterator]: () => ({
3558
+ next: () => sdkIterator.next(),
3559
+ return: () => {
3560
+ void sdkIterator.return?.().catch(() => {
3561
+ });
3562
+ return Promise.resolve({ done: true, value: void 0 });
3563
+ }
3564
+ })
3565
+ };
3566
+ for await (const message of detachableResponse) {
2943
3567
  this.logger.debug(`[claude-code] Stream received message type: ${message.type}`);
3568
+ this.invokeSdkMessageCallback(message);
3569
+ if (options.includeRawChunks) {
3570
+ controller.enqueue({ type: "raw", rawValue: message });
3571
+ }
2944
3572
  if (message.type === "stream_event") {
2945
3573
  const streamEvent = message;
2946
3574
  const event = streamEvent.event;
@@ -2972,7 +3600,8 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2972
3600
  const jsonDelta = event.delta.partial_json;
2973
3601
  hasReceivedStreamEvents = true;
2974
3602
  const blockIndex = "index" in event ? event.index : -1;
2975
- if (options.responseFormat?.type === "json") {
3603
+ const isStructuredOutputDelta = structuredOutputBlockIndexes.has(blockIndex) || !toolBlocksByIndex.has(blockIndex) && !nonTextToolBlockIndexes.has(blockIndex);
3604
+ if (options.responseFormat?.type === "json" && isStructuredOutputDelta) {
2976
3605
  if (!textPartId) {
2977
3606
  textPartId = generateId();
2978
3607
  controller.enqueue({
@@ -3002,12 +3631,25 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3002
3631
  continue;
3003
3632
  }
3004
3633
  }
3634
+ if (event.type === "content_block_start" && "content_block" in event && isNonTextToolUseContentBlockType(event.content_block?.type)) {
3635
+ const blockIndex = "index" in event ? event.index : -1;
3636
+ hasReceivedStreamEvents = true;
3637
+ nonTextToolBlockIndexes.add(blockIndex);
3638
+ structuredOutputBlockIndexes.delete(blockIndex);
3639
+ continue;
3640
+ }
3005
3641
  if (event.type === "content_block_start" && "content_block" in event && event.content_block?.type === "tool_use") {
3006
3642
  const blockIndex = "index" in event ? event.index : -1;
3007
3643
  const toolBlock = event.content_block;
3008
3644
  const toolId = typeof toolBlock.id === "string" && toolBlock.id.length > 0 ? toolBlock.id : generateId();
3009
3645
  const toolName = typeof toolBlock.name === "string" && toolBlock.name.length > 0 ? toolBlock.name : _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
3010
3646
  hasReceivedStreamEvents = true;
3647
+ nonTextToolBlockIndexes.delete(blockIndex);
3648
+ if (isInternalStructuredOutputTool(toolName, options)) {
3649
+ structuredOutputBlockIndexes.add(blockIndex);
3650
+ continue;
3651
+ }
3652
+ structuredOutputBlockIndexes.delete(blockIndex);
3011
3653
  if (textPartId) {
3012
3654
  const closedTextId = textPartId;
3013
3655
  controller.enqueue({
@@ -3154,6 +3796,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3154
3796
  toolInputAccumulators.delete(toolId);
3155
3797
  continue;
3156
3798
  }
3799
+ if (structuredOutputBlockIndexes.delete(blockIndex)) {
3800
+ continue;
3801
+ }
3802
+ if (nonTextToolBlockIndexes.delete(blockIndex)) {
3803
+ continue;
3804
+ }
3157
3805
  const textId = textBlocksByIndex.get(blockIndex);
3158
3806
  if (textId) {
3159
3807
  this.logger.debug(
@@ -3200,7 +3848,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3200
3848
  }
3201
3849
  const sdkParentToolUseId = message.parent_tool_use_id;
3202
3850
  const content = message.message.content;
3203
- const tools = this.extractToolUses(content);
3851
+ const tools = this.extractToolUses(content).filter(
3852
+ (tool3) => !isInternalStructuredOutputTool(tool3.name, options)
3853
+ );
3204
3854
  if (textPartId && tools.length > 0) {
3205
3855
  const closedTextId = textPartId;
3206
3856
  controller.enqueue({
@@ -3253,7 +3903,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3253
3903
  toolName: tool3.name,
3254
3904
  providerExecuted: true,
3255
3905
  dynamic: true,
3256
- // V3 field: indicates tool is provider-defined
3906
+ // V4 field: indicates tool is provider-defined
3257
3907
  providerMetadata: {
3258
3908
  "claude-code": {
3259
3909
  parentToolCallId: state.parentToolCallId ?? null
@@ -3458,7 +4108,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3458
4108
  toolName,
3459
4109
  providerExecuted: true,
3460
4110
  dynamic: true,
3461
- // V3 field: indicates tool is provider-defined
4111
+ // V4 field: indicates tool is provider-defined
3462
4112
  providerMetadata: {
3463
4113
  "claude-code": {
3464
4114
  parentToolCallId: state.parentToolCallId ?? null
@@ -3510,19 +4160,47 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3510
4160
  );
3511
4161
  state = {
3512
4162
  name: toolName,
3513
- inputStarted: true,
3514
- inputClosed: true,
4163
+ inputStarted: false,
4164
+ inputClosed: false,
3515
4165
  callEmitted: false,
3516
4166
  parentToolCallId: errorResolvedParentId
3517
4167
  };
3518
4168
  toolStates.set(error.id, state);
4169
+ if (!state.inputStarted) {
4170
+ controller.enqueue({
4171
+ type: "tool-input-start",
4172
+ id: error.id,
4173
+ toolName,
4174
+ providerExecuted: true,
4175
+ dynamic: true,
4176
+ // V4 field: indicates tool is provider-defined
4177
+ providerMetadata: {
4178
+ "claude-code": {
4179
+ parentToolCallId: state.parentToolCallId ?? null
4180
+ }
4181
+ }
4182
+ });
4183
+ state.inputStarted = true;
4184
+ }
4185
+ if (!state.inputClosed) {
4186
+ controller.enqueue({
4187
+ type: "tool-input-end",
4188
+ id: error.id
4189
+ });
4190
+ state.inputClosed = true;
4191
+ }
3519
4192
  }
3520
4193
  emitToolCall(error.id, state);
3521
4194
  if (isSubagentToolName(toolName)) {
3522
4195
  activeTaskTools.delete(error.id);
3523
4196
  }
3524
4197
  controller.enqueue(
3525
- this.buildToolErrorPart(error.id, toolName, error.error, state.parentToolCallId)
4198
+ this.buildErroredToolResultPart(
4199
+ error.id,
4200
+ toolName,
4201
+ error.error,
4202
+ state.parentToolCallId
4203
+ )
3526
4204
  );
3527
4205
  }
3528
4206
  } else if (message.type === "result") {
@@ -3552,13 +4230,16 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3552
4230
  );
3553
4231
  }
3554
4232
  const stopReason = "stop_reason" in message ? message.stop_reason : void 0;
3555
- const finishReason = mapClaudeCodeFinishReason(
4233
+ let finishReason = mapClaudeCodeFinishReason(
3556
4234
  message.subtype,
3557
4235
  stopReason
3558
4236
  );
3559
- this.logger.debug(`[claude-code] Stream finish reason: ${finishReason.unified}`);
3560
4237
  this.setSessionId(message.session_id);
3561
4238
  const structuredOutput = "structured_output" in message ? message.structured_output : void 0;
4239
+ if (structuredOutput !== void 0 && finishReason.unified === "tool-calls") {
4240
+ finishReason = { unified: "stop", raw: finishReason.raw };
4241
+ }
4242
+ this.logger.debug(`[claude-code] Stream finish reason: ${finishReason.unified}`);
3562
4243
  const alreadyStreamedJson = hasStreamedJson && options.responseFormat?.type === "json" && hasReceivedStreamEvents;
3563
4244
  if (alreadyStreamedJson) {
3564
4245
  if (textPartId) {
@@ -3672,6 +4353,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3672
4353
  ...metadataTracking.permissionDenials.length > 0 && {
3673
4354
  permissionDenials: metadataTracking.permissionDenials
3674
4355
  },
4356
+ ...metadataTracking.taskEvents.length > 0 && {
4357
+ taskEvents: metadataTracking.taskEvents
4358
+ },
4359
+ ...metadataTracking.hookEvents.length > 0 && {
4360
+ hookEvents: metadataTracking.hookEvents
4361
+ },
4362
+ ...metadataTracking.mcpServers !== void 0 && {
4363
+ mcpServers: metadataTracking.mcpServers
4364
+ },
3675
4365
  ...metadataTracking.mirrorErrors.length > 0 && {
3676
4366
  mirrorErrors: metadataTracking.mirrorErrors
3677
4367
  },
@@ -3689,12 +4379,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3689
4379
  });
3690
4380
  controller.close();
3691
4381
  const effectivePromptSuggestions = sdkOptions?.promptSuggestions ?? this.settings.promptSuggestions;
3692
- if (this.settings.onPromptSuggestion && effectivePromptSuggestions !== false) {
3693
- await this.drainPromptSuggestion(response, this.settings.onPromptSuggestion);
4382
+ const shouldDrainPromptSuggestion = effectivePromptSuggestions !== false && (this.settings.onPromptSuggestion !== void 0 || this.settings.onSdkMessage !== void 0);
4383
+ if (shouldDrainPromptSuggestion) {
4384
+ await this.drainPromptSuggestion(sdkIterator, this.settings.onPromptSuggestion);
3694
4385
  }
3695
4386
  return;
3696
4387
  } else if (message.type === "system" && message.subtype === "init") {
3697
4388
  this.logMcpConnectionIssues(message.mcp_servers);
4389
+ this.trackMcpStatusFromInit(message, metadataTracking);
3698
4390
  this.setSessionId(message.session_id);
3699
4391
  this.logger.info(`[claude-code] Stream session initialized: ${message.session_id}`);
3700
4392
  controller.enqueue({
@@ -3768,6 +4460,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3768
4460
  ...metadataTracking.permissionDenials.length > 0 && {
3769
4461
  permissionDenials: metadataTracking.permissionDenials
3770
4462
  },
4463
+ ...metadataTracking.taskEvents.length > 0 && {
4464
+ taskEvents: metadataTracking.taskEvents
4465
+ },
4466
+ ...metadataTracking.hookEvents.length > 0 && {
4467
+ hookEvents: metadataTracking.hookEvents
4468
+ },
4469
+ ...metadataTracking.mcpServers !== void 0 && {
4470
+ mcpServers: metadataTracking.mcpServers
4471
+ },
3771
4472
  ...metadataTracking.mirrorErrors.length > 0 && {
3772
4473
  mirrorErrors: metadataTracking.mirrorErrors
3773
4474
  },
@@ -3815,19 +4516,23 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3815
4516
  };
3816
4517
  }
3817
4518
  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
- }
4519
+ const result = warnings.map((warning) => {
4520
+ const base = { type: warning.type };
4521
+ switch (warning.type) {
4522
+ case "unsupported":
4523
+ case "compatibility":
4524
+ base.feature = warning.feature;
4525
+ if (warning.details !== void 0) {
4526
+ base.details = warning.details;
4527
+ }
4528
+ break;
4529
+ case "deprecated":
4530
+ base.setting = warning.setting;
4531
+ base.message = warning.message;
4532
+ break;
4533
+ case "other":
4534
+ base.message = warning.message;
4535
+ break;
3831
4536
  }
3832
4537
  return base;
3833
4538
  });
@@ -3870,7 +4575,7 @@ function createClaudeCode(options = {}) {
3870
4575
  };
3871
4576
  provider.languageModel = createModel;
3872
4577
  provider.chat = createModel;
3873
- provider.specificationVersion = "v3";
4578
+ provider.specificationVersion = "v4";
3874
4579
  provider.embeddingModel = (modelId) => {
3875
4580
  throw new NoSuchModelError2({
3876
4581
  modelId,
@@ -3894,7 +4599,9 @@ import {
3894
4599
  SYSTEM_PROMPT_DYNAMIC_BOUNDARY,
3895
4600
  InMemorySessionStore,
3896
4601
  HOOK_EVENTS,
3897
- AbortError
4602
+ AbortError,
4603
+ resolveSettings,
4604
+ filterEscalatingDefaultMode
3898
4605
  } from "@anthropic-ai/claude-agent-sdk";
3899
4606
  import {
3900
4607
  listSessions,
@@ -3914,6 +4621,16 @@ import { startup } from "@anthropic-ai/claude-agent-sdk";
3914
4621
  // src/mcp-helpers.ts
3915
4622
  import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
3916
4623
  import "zod";
4624
+ var warnedDescriptionFunctionToolNames = /* @__PURE__ */ new Set();
4625
+ function warnDiscardedDescriptionFunction(toolName) {
4626
+ if (warnedDescriptionFunctionToolNames.has(toolName)) {
4627
+ return;
4628
+ }
4629
+ warnedDescriptionFunctionToolNames.add(toolName);
4630
+ console.warn(
4631
+ `[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.`
4632
+ );
4633
+ }
3917
4634
  function buildIsErrorResult(text) {
3918
4635
  return {
3919
4636
  isError: true,
@@ -3956,7 +4673,11 @@ function createCustomMcpServer(config) {
3956
4673
  }
3957
4674
  var AI_SDK_SCHEMA_SYMBOL = Symbol.for("vercel.ai.schema");
3958
4675
  function isAiSdkJsonSchema(schema) {
3959
- return typeof schema === "object" && schema !== null && AI_SDK_SCHEMA_SYMBOL in schema;
4676
+ if (typeof schema !== "object" || schema === null) {
4677
+ return false;
4678
+ }
4679
+ const candidate = schema;
4680
+ return candidate[AI_SDK_SCHEMA_SYMBOL] === true && "jsonSchema" in candidate && "validate" in candidate;
3960
4681
  }
3961
4682
  function isZodObjectSchema(schema) {
3962
4683
  if (typeof schema !== "object" || schema === null) {
@@ -3991,9 +4712,13 @@ function createAiSdkMcpServer(name, tools) {
3991
4712
  );
3992
4713
  }
3993
4714
  const zodSchema = def.inputSchema;
4715
+ const description = typeof def.description === "string" ? def.description : "";
4716
+ if (typeof def.description === "function") {
4717
+ warnDiscardedDescriptionFunction(toolName);
4718
+ }
3994
4719
  return tool(
3995
4720
  toolName,
3996
- def.description ?? "",
4721
+ description,
3997
4722
  zodSchema.shape,
3998
4723
  async (args, extra) => {
3999
4724
  try {
@@ -4026,10 +4751,12 @@ export {
4026
4751
  createAiSdkMcpServer,
4027
4752
  createAuthenticationError,
4028
4753
  createClaudeCode,
4754
+ createClaudeCodeQueryController,
4029
4755
  createCustomMcpServer,
4030
4756
  createSdkMcpServer2 as createSdkMcpServer,
4031
4757
  createTimeoutError,
4032
4758
  deleteSession,
4759
+ filterEscalatingDefaultMode,
4033
4760
  foldSessionSummary,
4034
4761
  forkSession,
4035
4762
  getErrorMetadata,
@@ -4042,6 +4769,7 @@ export {
4042
4769
  listSessions,
4043
4770
  listSubagents,
4044
4771
  renameSession,
4772
+ resolveSettings,
4045
4773
  startup,
4046
4774
  tagSession,
4047
4775
  tool2 as tool