ai-sdk-provider-claude-code 3.5.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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");
@@ -532,6 +698,18 @@ var claudeCodeSettingsSchema = z.object({
532
698
  forwardSubagentText: z.boolean().optional(),
533
699
  agentProgressSummaries: z.boolean().optional(),
534
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(),
535
713
  taskBudget: z.object({ total: z.number().positive() }).strict().optional(),
536
714
  sessionStore: z.any().refine(
537
715
  (val) => val === void 0 || typeof val === "object" && val !== null && typeof val.append === "function" && typeof val.load === "function",
@@ -548,6 +726,9 @@ var claudeCodeSettingsSchema = z.object({
548
726
  onUserDialog: z.any().refine((v) => v === void 0 || typeof v === "function", {
549
727
  message: "onUserDialog must be a function"
550
728
  }).optional(),
729
+ onElicitation: z.any().refine((v) => v === void 0 || typeof v === "function", {
730
+ message: "onElicitation must be a function"
731
+ }).optional(),
551
732
  supportedDialogKinds: z.array(z.string()).optional(),
552
733
  hooks: z.record(
553
734
  z.string(),
@@ -594,6 +775,7 @@ var claudeCodeSettingsSchema = z.object({
594
775
  logger: z.union([z.literal(false), loggerFunctionSchema]).optional(),
595
776
  env: z.record(z.string(), z.string().optional()).optional(),
596
777
  additionalDirectories: z.array(z.string()).optional(),
778
+ agent: z.string().optional(),
597
779
  agents: z.record(
598
780
  z.string(),
599
781
  z.object({
@@ -631,10 +813,13 @@ var claudeCodeSettingsSchema = z.object({
631
813
  onQueryCreated: z.any().refine((val) => val === void 0 || typeof val === "function", {
632
814
  message: "onQueryCreated must be a function"
633
815
  }).optional(),
816
+ onQueryControllerCreated: z.any().refine((val) => val === void 0 || typeof val === "function", {
817
+ message: "onQueryControllerCreated must be a function"
818
+ }).optional(),
634
819
  onStreamStart: z.any().refine((val) => val === void 0 || typeof val === "function", {
635
820
  message: "onStreamStart must be a function"
636
821
  }).optional(),
637
- // Callback invoked with the predicted next user prompt (active unless promptSuggestions: false)
822
+ // Callback invoked with the predicted next user prompt (requires promptSuggestions: true)
638
823
  onPromptSuggestion: z.any().refine((val) => val === void 0 || typeof val === "function", {
639
824
  message: "onPromptSuggestion must be a function"
640
825
  }).optional()
@@ -719,6 +904,11 @@ function validateSettings(settings) {
719
904
  `Very high maxThinkingTokens (${validSettings.maxThinkingTokens}) may increase response time`
720
905
  );
721
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
+ }
722
912
  if (validSettings.allowedTools && validSettings.disallowedTools) {
723
913
  warnings.push(
724
914
  "Both allowedTools and disallowedTools are specified. Only allowedTools will be used."
@@ -956,9 +1146,38 @@ function createVerboseLogger(logger, verbose = false) {
956
1146
  };
957
1147
  }
958
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
+
959
1178
  // src/claude-code-language-model.ts
960
1179
  import { query } from "@anthropic-ai/claude-agent-sdk";
961
- var PROVIDER_VERSION = "3.5.2";
1180
+ var PROVIDER_VERSION = "4.0.0";
962
1181
  var DEFAULT_CLIENT_APP = `ai-sdk-provider-claude-code/${PROVIDER_VERSION}`;
963
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.";
964
1183
  var MIN_TRUNCATION_LENGTH = 512;
@@ -992,6 +1211,13 @@ function isClaudeCodeTruncationError(error, bufferedText) {
992
1211
  return true;
993
1212
  }
994
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
+ }
995
1221
  function extractJsonObjectText(text) {
996
1222
  const trimmed = text.trim();
997
1223
  if (!trimmed) {
@@ -1085,7 +1311,7 @@ function getBaseProcessEnv() {
1085
1311
  }
1086
1312
  return env;
1087
1313
  }
1088
- 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.";
1089
1315
  var SDK_OPTIONS_BLOCKLIST = /* @__PURE__ */ new Set(["model", "abortController", "prompt", "outputFormat"]);
1090
1316
  var SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
1091
1317
  function isSubagentToolName(name) {
@@ -1108,7 +1334,7 @@ function computeRetractedToolCallIds(retracted, descriptors) {
1108
1334
  function applySupersede(message, evict, logger, guard = "array") {
1109
1335
  const supersedes = message.supersedes;
1110
1336
  const triggered = guard === "truthy" ? Boolean(supersedes && supersedes.length > 0) : Array.isArray(supersedes) && supersedes.length > 0;
1111
- if (!triggered) {
1337
+ if (!triggered || supersedes === void 0) {
1112
1338
  return false;
1113
1339
  }
1114
1340
  logger.debug(`[claude-code] Assistant message supersedes ${supersedes.length} prior message(s)`);
@@ -1121,12 +1347,126 @@ function buildRetractionEvictor(evict) {
1121
1347
  var INFORMATIONAL_SYSTEM_SUBTYPES = /* @__PURE__ */ new Set([
1122
1348
  "notification",
1123
1349
  "status",
1124
- "task_updated",
1125
1350
  "session_state_changed",
1126
1351
  "commands_changed",
1127
1352
  "memory_recall",
1128
- "plugin_install"
1353
+ "plugin_install",
1354
+ "informational"
1129
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
+ }
1130
1470
  function isContentBlock(item) {
1131
1471
  return typeof item === "object" && item !== null && "type" in item;
1132
1472
  }
@@ -1287,6 +1627,7 @@ function toAsyncIterablePrompt(messagesPrompt, outputStreamEnded, sessionId, con
1287
1627
  };
1288
1628
  }
1289
1629
  var modelMap = {
1630
+ fable: "fable",
1290
1631
  opus: "opus",
1291
1632
  sonnet: "sonnet",
1292
1633
  haiku: "haiku"
@@ -1335,7 +1676,7 @@ function truncateToolResultForStream(result, maxSize = MAX_TOOL_RESULT_SIZE) {
1335
1676
  return result;
1336
1677
  }
1337
1678
  var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1338
- specificationVersion = "v3";
1679
+ specificationVersion = "v4";
1339
1680
  defaultObjectGenerationMode = "json";
1340
1681
  supportsImageUrls = false;
1341
1682
  supportedUrls = {};
@@ -1406,6 +1747,81 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1406
1747
  }
1407
1748
  return void 0;
1408
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
+ }
1409
1825
  /**
1410
1826
  * Single source of truth for the CLI's `--session-id` exclusivity rule.
1411
1827
  *
@@ -1570,7 +1986,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1570
1986
  input,
1571
1987
  providerExecuted: true,
1572
1988
  dynamic: true,
1573
- // 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)
1574
1990
  providerMetadata: {
1575
1991
  "claude-code": {
1576
1992
  // rawInput preserves the original serialized format before AI SDK normalization.
@@ -1610,12 +2026,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1610
2026
  toolName,
1611
2027
  // `?? ''`: absent `content` (undefined) and string results that
1612
2028
  // normalize to JSON null (e.g. the string "null") must not violate the
1613
- // NonNullable<JSONValue> contract of LanguageModelV3ToolResult.result.
2029
+ // NonNullable<JSONValue> contract of LanguageModelV4ToolResult.result.
1614
2030
  result: truncatedResult ?? "",
1615
2031
  isError,
1616
- providerExecuted: true,
1617
2032
  dynamic: true,
1618
- // V3 field: indicates tool is provider-defined
2033
+ // V4 field: indicates tool is provider-defined
1619
2034
  providerMetadata: {
1620
2035
  "claude-code": {
1621
2036
  // rawResult preserves the original CLI output string before JSON parsing.
@@ -1638,37 +2053,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1638
2053
  })() : String(error);
1639
2054
  }
1640
2055
  /**
1641
- * Builds a provider-executed `tool-error` STREAM part from a user-message
1642
- * `tool_error` block (doStream only; AI SDK core handles tool-error stream
1643
- * 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.
1644
2060
  */
1645
- buildToolErrorPart(toolCallId, toolName, error, parentToolCallId) {
1646
- const rawError = this.serializeToolError(error);
1647
- return {
1648
- type: "tool-error",
1649
- toolCallId,
1650
- toolName,
1651
- error: rawError,
1652
- providerExecuted: true,
1653
- dynamic: true,
1654
- // V3 field: indicates tool is provider-defined
1655
- providerMetadata: {
1656
- "claude-code": {
1657
- rawError,
1658
- parentToolCallId: parentToolCallId ?? null
1659
- }
1660
- }
1661
- };
1662
- }
1663
- /**
1664
- * Builds a V3 `tool-result` CONTENT part with `isError: true` from a
1665
- * user-message `tool_error` block (doGenerate only). The V3 content union
1666
- * has no `tool-error` member and AI SDK core's asContent() silently drops
1667
- * unknown content part types, so an extension tool-error part would never
1668
- * reach `generateText` users — an isError tool-result, by contrast,
1669
- * round-trips into a proper tool-error part in steps content.
1670
- */
1671
- buildToolErrorResultPart(toolCallId, toolName, error, parentToolCallId) {
2061
+ buildErroredToolResultPart(toolCallId, toolName, error, parentToolCallId) {
1672
2062
  const rawError = this.serializeToolError(error);
1673
2063
  return {
1674
2064
  type: "tool-result",
@@ -1676,9 +2066,8 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1676
2066
  toolName,
1677
2067
  result: rawError,
1678
2068
  isError: true,
1679
- providerExecuted: true,
1680
2069
  dynamic: true,
1681
- // V3 field: indicates tool is provider-defined
2070
+ // V4 field: indicates tool is provider-defined
1682
2071
  providerMetadata: {
1683
2072
  "claude-code": {
1684
2073
  rawError,
@@ -1704,7 +2093,33 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1704
2093
  );
1705
2094
  return true;
1706
2095
  }
1707
- 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) {
1708
2123
  const warnings = [];
1709
2124
  const unsupportedParams = [];
1710
2125
  if (options.temperature !== void 0) unsupportedParams.push("temperature");
@@ -1771,9 +2186,18 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1771
2186
  message: promptWarning
1772
2187
  });
1773
2188
  }
2189
+ this.resolvePortableReasoningOptions(
2190
+ options,
2191
+ sdkOptions,
2192
+ extractClaudeReasoningProviderOptions(options.providerOptions, warnings),
2193
+ warnings
2194
+ );
1774
2195
  return warnings;
1775
2196
  }
1776
- createQueryOptions(abortController, responseFormat, stderrCollector, sdkOptions, effectiveResume) {
2197
+ createQueryOptions(abortController, options, stderrCollector, sdkOptions, effectiveResume) {
2198
+ const claudeReasoningProviderOptions = extractClaudeReasoningProviderOptions(
2199
+ options.providerOptions
2200
+ );
1777
2201
  const opts = {
1778
2202
  model: this.getModel(),
1779
2203
  abortController,
@@ -1801,8 +2225,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1801
2225
  sandbox: this.settings.sandbox,
1802
2226
  tools: this.settings.tools,
1803
2227
  mcpServers: this.settings.mcpServers,
1804
- canUseTool: this.settings.canUseTool
2228
+ canUseTool: this.settings.canUseTool,
2229
+ onElicitation: this.settings.onElicitation,
2230
+ agent: this.settings.agent
1805
2231
  };
2232
+ Object.assign(
2233
+ opts,
2234
+ this.resolvePortableReasoningOptions(options, sdkOptions, claudeReasoningProviderOptions)
2235
+ );
1806
2236
  if (this.settings.onUserDialog !== void 0) {
1807
2237
  opts.onUserDialog = this.settings.onUserDialog;
1808
2238
  }
@@ -1931,6 +2361,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1931
2361
  }
1932
2362
  }
1933
2363
  }
2364
+ this.applyClaudeReasoningProviderOptions(opts, claudeReasoningProviderOptions);
1934
2365
  this.applySessionResolution(opts, effectiveResume);
1935
2366
  if (typeof opts.fallbackModel === "string" && opts.fallbackModel === opts.model) {
1936
2367
  throw new Error(
@@ -1953,9 +2384,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1953
2384
  mergedEnv.CLAUDE_AGENT_SDK_CLIENT_APP = DEFAULT_CLIENT_APP;
1954
2385
  }
1955
2386
  opts.env = mergedEnv;
1956
- if (responseFormat?.type === "json" && responseFormat.schema) {
2387
+ if (options.responseFormat?.type === "json" && options.responseFormat.schema) {
1957
2388
  const { schema: sanitizedSchema, strippedFormatPaths } = sanitizeJsonSchemaForOutputFormat(
1958
- responseFormat.schema
2389
+ options.responseFormat.schema
1959
2390
  );
1960
2391
  if (strippedFormatPaths.length > 0) {
1961
2392
  this.logger.debug(
@@ -2029,7 +2460,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2029
2460
  if (errorKind === "model_not_found" || errorMessage.includes("model_not_found") || errorMessage.includes("no such model")) {
2030
2461
  const originalMessage = isErrorWithMessage(error) && error.message ? error.message : "Model not found";
2031
2462
  return createAPICallError({
2032
- 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.`,
2033
2464
  code: errorCode || void 0,
2034
2465
  exitCode,
2035
2466
  stderr,
@@ -2099,16 +2530,159 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2099
2530
  break;
2100
2531
  case "permission_denied": {
2101
2532
  const reason = message.decision_reason ?? message.message;
2533
+ const raw = toJsonSafeValue(message);
2102
2534
  tracking.permissionDenials.push({
2103
2535
  toolName: message.tool_name,
2104
2536
  toolUseId: message.tool_use_id,
2105
- ...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 }
2106
2543
  });
2107
2544
  this.logger.warn(
2108
2545
  `[claude-code] Permission denied - Tool: ${message.tool_name}${reason ? `, Reason: ${reason}` : ""}`
2109
2546
  );
2110
2547
  break;
2111
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;
2112
2686
  case "mirror_error": {
2113
2687
  const mirrorError = message.error ?? "unknown error";
2114
2688
  const mirrorSessionId = message.key?.sessionId ?? message.session_id ?? "unknown";
@@ -2161,12 +2735,21 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2161
2735
  const alreadyTracked = tracking.permissionDenials.some(
2162
2736
  (d) => d.toolUseId !== void 0 && d.toolUseId === denial.tool_use_id
2163
2737
  );
2164
- if (!alreadyTracked) {
2165
- tracking.permissionDenials.push({
2166
- toolName: denial.tool_name,
2167
- toolUseId: denial.tool_use_id
2168
- });
2738
+ if (alreadyTracked) {
2739
+ continue;
2169
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
+ });
2170
2753
  }
2171
2754
  }
2172
2755
  /**
@@ -2175,11 +2758,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2175
2758
  * suggestion arrives AFTER the result message; the SDK emits at most one
2176
2759
  * per turn, so stop once it is delivered, and a timeout closes the
2177
2760
  * iterator (tearing down the subprocess) if the CLI lingers after the
2178
- * result without emitting one. Advances the response's own generator, so
2179
- * 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.
2180
2763
  */
2181
- async drainPromptSuggestion(response, onPromptSuggestion) {
2182
- const iterator = response[Symbol.asyncIterator]();
2764
+ async drainPromptSuggestion(iterator, onPromptSuggestion) {
2183
2765
  let drainTimer;
2184
2766
  const drainTimeout = new Promise((resolve) => {
2185
2767
  drainTimer = setTimeout(
@@ -2202,8 +2784,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2202
2784
  }
2203
2785
  const trailingMessage = winner.value;
2204
2786
  this.logger.debug(`[claude-code] Post-result message type: ${trailingMessage.type}`);
2787
+ this.invokeSdkMessageCallback(trailingMessage);
2205
2788
  if (trailingMessage.type === "prompt_suggestion") {
2206
- onPromptSuggestion(trailingMessage.suggestion);
2789
+ onPromptSuggestion?.(trailingMessage.suggestion);
2207
2790
  void iterator.return?.().catch(() => {
2208
2791
  });
2209
2792
  break;
@@ -2244,7 +2827,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2244
2827
  const effectiveResume = this.getEffectiveResume(sdkOptions);
2245
2828
  const queryOptions = this.createQueryOptions(
2246
2829
  abortController,
2247
- options.responseFormat,
2830
+ options,
2248
2831
  stderrCollector,
2249
2832
  sdkOptions,
2250
2833
  effectiveResume
@@ -2318,9 +2901,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2318
2901
  apiRetries: 0,
2319
2902
  permissionDenials: [],
2320
2903
  mirrorErrors: [],
2321
- estimatedThinkingTokens: 0
2904
+ estimatedThinkingTokens: 0,
2905
+ taskEvents: [],
2906
+ hookEvents: []
2322
2907
  };
2323
- const warnings = this.generateAllWarnings(options, messagesPrompt);
2908
+ const warnings = this.generateAllWarnings(
2909
+ options,
2910
+ messagesPrompt,
2911
+ sdkOptions
2912
+ );
2324
2913
  if (messageWarnings) {
2325
2914
  messageWarnings.forEach((warning) => {
2326
2915
  warnings.push({
@@ -2332,7 +2921,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2332
2921
  const modeSetting = this.settings.streamingInput ?? "auto";
2333
2922
  const effectiveCanUseTool = sdkOptions?.canUseTool ?? this.settings.canUseTool;
2334
2923
  const effectivePermissionPromptToolName = sdkOptions?.permissionPromptToolName ?? this.settings.permissionPromptToolName;
2335
- const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!effectiveCanUseTool;
2924
+ const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && (!!effectiveCanUseTool || hasImageParts);
2336
2925
  if (!wantsStreamInput && hasImageParts) {
2337
2926
  warnings.push({
2338
2927
  type: "other",
@@ -2364,7 +2953,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2364
2953
  prompt: sdkPrompt,
2365
2954
  options: queryOptions
2366
2955
  });
2367
- this.settings.onQueryCreated?.(response);
2956
+ this.notifyQueryCreated(response);
2368
2957
  let lastAssistantErrorKind;
2369
2958
  const sdkIterator = response[Symbol.asyncIterator]();
2370
2959
  const detachableResponse = {
@@ -2379,6 +2968,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2379
2968
  };
2380
2969
  for await (const message of detachableResponse) {
2381
2970
  this.logger.debug(`[claude-code] Received message type: ${message.type}`);
2971
+ this.invokeSdkMessageCallback(message);
2382
2972
  if (message.type === "assistant") {
2383
2973
  if (typeof message.error === "string") {
2384
2974
  lastAssistantErrorKind = message.error;
@@ -2407,6 +2997,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2407
2997
  } else if (block.type === "tool_use") {
2408
2998
  const [tool3] = this.extractToolUses([block]);
2409
2999
  if (!tool3) continue;
3000
+ if (isInternalStructuredOutputTool(tool3.name, options)) continue;
2410
3001
  const parentToolCallId = isSubagentToolName(tool3.name) ? null : resolveToolParentId(
2411
3002
  sdkParentToolUseId,
2412
3003
  tool3.parentToolUseId,
@@ -2517,7 +3108,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2517
3108
  kind: "tool-error",
2518
3109
  ...resultMessageUuid !== void 0 && { uuid: resultMessageUuid },
2519
3110
  toolCallId: error.id,
2520
- part: this.buildToolErrorResultPart(
3111
+ part: this.buildErroredToolResultPart(
2521
3112
  error.id,
2522
3113
  toolName,
2523
3114
  error.error,
@@ -2575,14 +3166,19 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2575
3166
  }
2576
3167
  const stopReason = "stop_reason" in message ? message.stop_reason : void 0;
2577
3168
  finishReason = mapClaudeCodeFinishReason(message.subtype, stopReason);
3169
+ if (structuredOutput !== void 0 && finishReason.unified === "tool-calls") {
3170
+ finishReason = { unified: "stop", raw: finishReason.raw };
3171
+ }
2578
3172
  this.logger.debug(`[claude-code] Finish reason: ${finishReason.unified}`);
2579
3173
  const effectivePromptSuggestions = sdkOptions?.promptSuggestions ?? this.settings.promptSuggestions;
2580
- if (this.settings.onPromptSuggestion && effectivePromptSuggestions !== false) {
2581
- 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);
2582
3177
  }
2583
3178
  break;
2584
3179
  } else if (message.type === "system" && message.subtype === "init") {
2585
3180
  this.logMcpConnectionIssues(message.mcp_servers);
3181
+ this.trackMcpStatusFromInit(message, metadataTracking);
2586
3182
  this.setSessionId(message.session_id);
2587
3183
  this.logger.info(`[claude-code] Session initialized: ${message.session_id}`);
2588
3184
  } else if (message.type === "system") {
@@ -2685,6 +3281,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2685
3281
  ...metadataTracking.permissionDenials.length > 0 && {
2686
3282
  permissionDenials: metadataTracking.permissionDenials
2687
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
+ },
2688
3293
  ...metadataTracking.mirrorErrors.length > 0 && {
2689
3294
  mirrorErrors: metadataTracking.mirrorErrors
2690
3295
  },
@@ -2722,7 +3327,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2722
3327
  const effectiveResume = this.getEffectiveResume(sdkOptions);
2723
3328
  const queryOptions = this.createQueryOptions(
2724
3329
  abortController,
2725
- options.responseFormat,
3330
+ options,
2726
3331
  stderrCollector,
2727
3332
  sdkOptions,
2728
3333
  effectiveResume
@@ -2734,7 +3339,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2734
3339
  if (queryOptions.includePartialMessages === void 0) {
2735
3340
  queryOptions.includePartialMessages = true;
2736
3341
  }
2737
- const warnings = this.generateAllWarnings(options, messagesPrompt);
3342
+ const warnings = this.generateAllWarnings(
3343
+ options,
3344
+ messagesPrompt,
3345
+ sdkOptions
3346
+ );
2738
3347
  if (messageWarnings) {
2739
3348
  messageWarnings.forEach((warning) => {
2740
3349
  warnings.push({
@@ -2746,7 +3355,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2746
3355
  const modeSetting = this.settings.streamingInput ?? "auto";
2747
3356
  const effectiveCanUseTool = sdkOptions?.canUseTool ?? this.settings.canUseTool;
2748
3357
  const effectivePermissionPromptToolName = sdkOptions?.permissionPromptToolName ?? this.settings.permissionPromptToolName;
2749
- const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!effectiveCanUseTool;
3358
+ const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && (!!effectiveCanUseTool || hasImageParts);
2750
3359
  if (!wantsStreamInput && hasImageParts) {
2751
3360
  warnings.push({
2752
3361
  type: "other",
@@ -2813,9 +3422,13 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2813
3422
  apiRetries: 0,
2814
3423
  permissionDenials: [],
2815
3424
  mirrorErrors: [],
2816
- estimatedThinkingTokens: 0
3425
+ estimatedThinkingTokens: 0,
3426
+ taskEvents: [],
3427
+ hookEvents: []
2817
3428
  };
2818
3429
  const toolBlocksByIndex = /* @__PURE__ */ new Map();
3430
+ const structuredOutputBlockIndexes = /* @__PURE__ */ new Set();
3431
+ const nonTextToolBlockIndexes = /* @__PURE__ */ new Set();
2819
3432
  const toolInputAccumulators = /* @__PURE__ */ new Map();
2820
3433
  const textBlocksByIndex = /* @__PURE__ */ new Map();
2821
3434
  let textStreamedViaContentBlock = false;
@@ -2878,9 +3491,24 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2878
3491
  prompt: sdkPrompt,
2879
3492
  options: queryOptions
2880
3493
  });
2881
- this.settings.onQueryCreated?.(response);
2882
- 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) {
2883
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
+ }
2884
3512
  if (message.type === "stream_event") {
2885
3513
  const streamEvent = message;
2886
3514
  const event = streamEvent.event;
@@ -2912,7 +3540,8 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2912
3540
  const jsonDelta = event.delta.partial_json;
2913
3541
  hasReceivedStreamEvents = true;
2914
3542
  const blockIndex = "index" in event ? event.index : -1;
2915
- if (options.responseFormat?.type === "json") {
3543
+ const isStructuredOutputDelta = structuredOutputBlockIndexes.has(blockIndex) || !toolBlocksByIndex.has(blockIndex) && !nonTextToolBlockIndexes.has(blockIndex);
3544
+ if (options.responseFormat?.type === "json" && isStructuredOutputDelta) {
2916
3545
  if (!textPartId) {
2917
3546
  textPartId = generateId();
2918
3547
  controller.enqueue({
@@ -2942,12 +3571,25 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2942
3571
  continue;
2943
3572
  }
2944
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
+ }
2945
3581
  if (event.type === "content_block_start" && "content_block" in event && event.content_block?.type === "tool_use") {
2946
3582
  const blockIndex = "index" in event ? event.index : -1;
2947
3583
  const toolBlock = event.content_block;
2948
3584
  const toolId = typeof toolBlock.id === "string" && toolBlock.id.length > 0 ? toolBlock.id : generateId();
2949
3585
  const toolName = typeof toolBlock.name === "string" && toolBlock.name.length > 0 ? toolBlock.name : _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
2950
3586
  hasReceivedStreamEvents = true;
3587
+ nonTextToolBlockIndexes.delete(blockIndex);
3588
+ if (isInternalStructuredOutputTool(toolName, options)) {
3589
+ structuredOutputBlockIndexes.add(blockIndex);
3590
+ continue;
3591
+ }
3592
+ structuredOutputBlockIndexes.delete(blockIndex);
2951
3593
  if (textPartId) {
2952
3594
  const closedTextId = textPartId;
2953
3595
  controller.enqueue({
@@ -3094,6 +3736,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3094
3736
  toolInputAccumulators.delete(toolId);
3095
3737
  continue;
3096
3738
  }
3739
+ if (structuredOutputBlockIndexes.delete(blockIndex)) {
3740
+ continue;
3741
+ }
3742
+ if (nonTextToolBlockIndexes.delete(blockIndex)) {
3743
+ continue;
3744
+ }
3097
3745
  const textId = textBlocksByIndex.get(blockIndex);
3098
3746
  if (textId) {
3099
3747
  this.logger.debug(
@@ -3140,7 +3788,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3140
3788
  }
3141
3789
  const sdkParentToolUseId = message.parent_tool_use_id;
3142
3790
  const content = message.message.content;
3143
- const tools = this.extractToolUses(content);
3791
+ const tools = this.extractToolUses(content).filter(
3792
+ (tool3) => !isInternalStructuredOutputTool(tool3.name, options)
3793
+ );
3144
3794
  if (textPartId && tools.length > 0) {
3145
3795
  const closedTextId = textPartId;
3146
3796
  controller.enqueue({
@@ -3193,7 +3843,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3193
3843
  toolName: tool3.name,
3194
3844
  providerExecuted: true,
3195
3845
  dynamic: true,
3196
- // V3 field: indicates tool is provider-defined
3846
+ // V4 field: indicates tool is provider-defined
3197
3847
  providerMetadata: {
3198
3848
  "claude-code": {
3199
3849
  parentToolCallId: state.parentToolCallId ?? null
@@ -3398,7 +4048,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3398
4048
  toolName,
3399
4049
  providerExecuted: true,
3400
4050
  dynamic: true,
3401
- // V3 field: indicates tool is provider-defined
4051
+ // V4 field: indicates tool is provider-defined
3402
4052
  providerMetadata: {
3403
4053
  "claude-code": {
3404
4054
  parentToolCallId: state.parentToolCallId ?? null
@@ -3450,19 +4100,47 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3450
4100
  );
3451
4101
  state = {
3452
4102
  name: toolName,
3453
- inputStarted: true,
3454
- inputClosed: true,
4103
+ inputStarted: false,
4104
+ inputClosed: false,
3455
4105
  callEmitted: false,
3456
4106
  parentToolCallId: errorResolvedParentId
3457
4107
  };
3458
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
+ }
3459
4132
  }
3460
4133
  emitToolCall(error.id, state);
3461
4134
  if (isSubagentToolName(toolName)) {
3462
4135
  activeTaskTools.delete(error.id);
3463
4136
  }
3464
4137
  controller.enqueue(
3465
- this.buildToolErrorPart(error.id, toolName, error.error, state.parentToolCallId)
4138
+ this.buildErroredToolResultPart(
4139
+ error.id,
4140
+ toolName,
4141
+ error.error,
4142
+ state.parentToolCallId
4143
+ )
3466
4144
  );
3467
4145
  }
3468
4146
  } else if (message.type === "result") {
@@ -3492,13 +4170,16 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3492
4170
  );
3493
4171
  }
3494
4172
  const stopReason = "stop_reason" in message ? message.stop_reason : void 0;
3495
- const finishReason = mapClaudeCodeFinishReason(
4173
+ let finishReason = mapClaudeCodeFinishReason(
3496
4174
  message.subtype,
3497
4175
  stopReason
3498
4176
  );
3499
- this.logger.debug(`[claude-code] Stream finish reason: ${finishReason.unified}`);
3500
4177
  this.setSessionId(message.session_id);
3501
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}`);
3502
4183
  const alreadyStreamedJson = hasStreamedJson && options.responseFormat?.type === "json" && hasReceivedStreamEvents;
3503
4184
  if (alreadyStreamedJson) {
3504
4185
  if (textPartId) {
@@ -3612,6 +4293,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3612
4293
  ...metadataTracking.permissionDenials.length > 0 && {
3613
4294
  permissionDenials: metadataTracking.permissionDenials
3614
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
+ },
3615
4305
  ...metadataTracking.mirrorErrors.length > 0 && {
3616
4306
  mirrorErrors: metadataTracking.mirrorErrors
3617
4307
  },
@@ -3629,12 +4319,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3629
4319
  });
3630
4320
  controller.close();
3631
4321
  const effectivePromptSuggestions = sdkOptions?.promptSuggestions ?? this.settings.promptSuggestions;
3632
- if (this.settings.onPromptSuggestion && effectivePromptSuggestions !== false) {
3633
- 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);
3634
4325
  }
3635
4326
  return;
3636
4327
  } else if (message.type === "system" && message.subtype === "init") {
3637
4328
  this.logMcpConnectionIssues(message.mcp_servers);
4329
+ this.trackMcpStatusFromInit(message, metadataTracking);
3638
4330
  this.setSessionId(message.session_id);
3639
4331
  this.logger.info(`[claude-code] Stream session initialized: ${message.session_id}`);
3640
4332
  controller.enqueue({
@@ -3708,6 +4400,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3708
4400
  ...metadataTracking.permissionDenials.length > 0 && {
3709
4401
  permissionDenials: metadataTracking.permissionDenials
3710
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
+ },
3711
4412
  ...metadataTracking.mirrorErrors.length > 0 && {
3712
4413
  mirrorErrors: metadataTracking.mirrorErrors
3713
4414
  },
@@ -3755,19 +4456,23 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3755
4456
  };
3756
4457
  }
3757
4458
  serializeWarningsForMetadata(warnings) {
3758
- const result = warnings.map((w) => {
3759
- const base = { type: w.type };
3760
- if ("message" in w) {
3761
- const m = w.message;
3762
- if (m !== void 0) base.message = String(m);
3763
- }
3764
- if (w.type === "unsupported" || w.type === "compatibility") {
3765
- const feature = w.feature;
3766
- if (feature !== void 0) base.feature = String(feature);
3767
- if ("details" in w) {
3768
- const d = w.details;
3769
- if (d !== void 0) base.details = String(d);
3770
- }
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;
3771
4476
  }
3772
4477
  return base;
3773
4478
  });
@@ -3810,7 +4515,7 @@ function createClaudeCode(options = {}) {
3810
4515
  };
3811
4516
  provider.languageModel = createModel;
3812
4517
  provider.chat = createModel;
3813
- provider.specificationVersion = "v3";
4518
+ provider.specificationVersion = "v4";
3814
4519
  provider.embeddingModel = (modelId) => {
3815
4520
  throw new NoSuchModelError2({
3816
4521
  modelId,
@@ -3834,7 +4539,9 @@ import {
3834
4539
  SYSTEM_PROMPT_DYNAMIC_BOUNDARY,
3835
4540
  InMemorySessionStore,
3836
4541
  HOOK_EVENTS,
3837
- AbortError
4542
+ AbortError,
4543
+ resolveSettings,
4544
+ filterEscalatingDefaultMode
3838
4545
  } from "@anthropic-ai/claude-agent-sdk";
3839
4546
  import {
3840
4547
  listSessions,
@@ -3854,6 +4561,16 @@ import { startup } from "@anthropic-ai/claude-agent-sdk";
3854
4561
  // src/mcp-helpers.ts
3855
4562
  import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
3856
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
+ }
3857
4574
  function buildIsErrorResult(text) {
3858
4575
  return {
3859
4576
  isError: true,
@@ -3896,7 +4613,11 @@ function createCustomMcpServer(config) {
3896
4613
  }
3897
4614
  var AI_SDK_SCHEMA_SYMBOL = Symbol.for("vercel.ai.schema");
3898
4615
  function isAiSdkJsonSchema(schema) {
3899
- 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;
3900
4621
  }
3901
4622
  function isZodObjectSchema(schema) {
3902
4623
  if (typeof schema !== "object" || schema === null) {
@@ -3931,9 +4652,13 @@ function createAiSdkMcpServer(name, tools) {
3931
4652
  );
3932
4653
  }
3933
4654
  const zodSchema = def.inputSchema;
4655
+ const description = typeof def.description === "string" ? def.description : "";
4656
+ if (typeof def.description === "function") {
4657
+ warnDiscardedDescriptionFunction(toolName);
4658
+ }
3934
4659
  return tool(
3935
4660
  toolName,
3936
- def.description ?? "",
4661
+ description,
3937
4662
  zodSchema.shape,
3938
4663
  async (args, extra) => {
3939
4664
  try {
@@ -3966,10 +4691,12 @@ export {
3966
4691
  createAiSdkMcpServer,
3967
4692
  createAuthenticationError,
3968
4693
  createClaudeCode,
4694
+ createClaudeCodeQueryController,
3969
4695
  createCustomMcpServer,
3970
4696
  createSdkMcpServer2 as createSdkMcpServer,
3971
4697
  createTimeoutError,
3972
4698
  deleteSession,
4699
+ filterEscalatingDefaultMode,
3973
4700
  foldSessionSummary,
3974
4701
  forkSession,
3975
4702
  getErrorMetadata,
@@ -3982,6 +4709,7 @@ export {
3982
4709
  listSessions,
3983
4710
  listSubagents,
3984
4711
  renameSession,
4712
+ resolveSettings,
3985
4713
  startup,
3986
4714
  tagSession,
3987
4715
  tool2 as tool