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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs DELETED
@@ -1,4085 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- AbortError: () => import_claude_agent_sdk3.AbortError,
24
- ClaudeCodeLanguageModel: () => ClaudeCodeLanguageModel,
25
- HOOK_EVENTS: () => import_claude_agent_sdk3.HOOK_EVENTS,
26
- InMemorySessionStore: () => import_claude_agent_sdk3.InMemorySessionStore,
27
- SYSTEM_PROMPT_DYNAMIC_BOUNDARY: () => import_claude_agent_sdk3.SYSTEM_PROMPT_DYNAMIC_BOUNDARY,
28
- claudeCode: () => claudeCode,
29
- createAPICallError: () => createAPICallError,
30
- createAiSdkMcpServer: () => createAiSdkMcpServer,
31
- createAuthenticationError: () => createAuthenticationError,
32
- createClaudeCode: () => createClaudeCode,
33
- createCustomMcpServer: () => createCustomMcpServer,
34
- createSdkMcpServer: () => import_claude_agent_sdk3.createSdkMcpServer,
35
- createTimeoutError: () => createTimeoutError,
36
- deleteSession: () => import_claude_agent_sdk4.deleteSession,
37
- foldSessionSummary: () => import_claude_agent_sdk4.foldSessionSummary,
38
- forkSession: () => import_claude_agent_sdk4.forkSession,
39
- getErrorMetadata: () => getErrorMetadata,
40
- getSessionInfo: () => import_claude_agent_sdk4.getSessionInfo,
41
- getSessionMessages: () => import_claude_agent_sdk4.getSessionMessages,
42
- getSubagentMessages: () => import_claude_agent_sdk4.getSubagentMessages,
43
- importSessionToStore: () => import_claude_agent_sdk4.importSessionToStore,
44
- isAuthenticationError: () => isAuthenticationError,
45
- isTimeoutError: () => isTimeoutError,
46
- listSessions: () => import_claude_agent_sdk4.listSessions,
47
- listSubagents: () => import_claude_agent_sdk4.listSubagents,
48
- renameSession: () => import_claude_agent_sdk4.renameSession,
49
- startup: () => import_claude_agent_sdk5.startup,
50
- tagSession: () => import_claude_agent_sdk4.tagSession,
51
- tool: () => import_claude_agent_sdk3.tool
52
- });
53
- module.exports = __toCommonJS(index_exports);
54
-
55
- // src/claude-code-provider.ts
56
- var import_provider3 = require("@ai-sdk/provider");
57
-
58
- // src/claude-code-language-model.ts
59
- var import_provider2 = require("@ai-sdk/provider");
60
- var import_provider_utils = require("@ai-sdk/provider-utils");
61
-
62
- // src/convert-to-claude-code-messages.ts
63
- var IMAGE_URL_WARNING = "Image URLs are not supported by this provider; supply base64/data URLs.";
64
- var IMAGE_CONVERSION_WARNING = "Unable to convert image content; supply base64/data URLs.";
65
- var MAX_TOOL_CALL_INPUT_LENGTH = 1e3;
66
- function serializeToolCallInput(input) {
67
- let serialized;
68
- if (input === void 0) {
69
- serialized = "";
70
- } else {
71
- try {
72
- serialized = JSON.stringify(input) ?? String(input);
73
- } catch {
74
- serialized = String(input);
75
- }
76
- }
77
- if (serialized.length > MAX_TOOL_CALL_INPUT_LENGTH) {
78
- return `${serialized.slice(0, MAX_TOOL_CALL_INPUT_LENGTH)}...[truncated]`;
79
- }
80
- return serialized;
81
- }
82
- function normalizeBase64(base64) {
83
- return base64.replace(/\s+/g, "");
84
- }
85
- function isImageMimeType(mimeType) {
86
- return typeof mimeType === "string" && mimeType.trim().toLowerCase().startsWith("image/");
87
- }
88
- function createImageContent(mediaType, data) {
89
- const trimmedType = mediaType.trim();
90
- const trimmedData = normalizeBase64(data.trim());
91
- if (!trimmedType || !trimmedData) {
92
- return void 0;
93
- }
94
- return {
95
- type: "image",
96
- source: {
97
- type: "base64",
98
- media_type: trimmedType,
99
- data: trimmedData
100
- }
101
- };
102
- }
103
- function extractMimeType(candidate) {
104
- if (typeof candidate === "string" && candidate.trim()) {
105
- return candidate.trim();
106
- }
107
- return void 0;
108
- }
109
- function parseObjectImage(imageObj, fallbackMimeType) {
110
- const data = typeof imageObj.data === "string" ? imageObj.data : void 0;
111
- const mimeType = extractMimeType(
112
- imageObj.mimeType ?? imageObj.mediaType ?? imageObj.media_type ?? fallbackMimeType
113
- );
114
- if (!data || !mimeType) {
115
- return void 0;
116
- }
117
- return createImageContent(mimeType, data);
118
- }
119
- function parseStringImage(value, fallbackMimeType) {
120
- const trimmed = value.trim();
121
- if (/^https?:\/\//i.test(trimmed)) {
122
- return { warning: IMAGE_URL_WARNING };
123
- }
124
- const dataUrlMatch = trimmed.match(/^data:([^;]+);base64,(.+)$/i);
125
- if (dataUrlMatch) {
126
- const [, mediaType, data] = dataUrlMatch;
127
- const content = createImageContent(mediaType, data);
128
- return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
129
- }
130
- const base64Match = trimmed.match(/^base64:([^,]+),(.+)$/i);
131
- if (base64Match) {
132
- const [, explicitMimeType, data] = base64Match;
133
- const content = createImageContent(explicitMimeType, data);
134
- return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
135
- }
136
- if (fallbackMimeType) {
137
- const content = createImageContent(fallbackMimeType, trimmed);
138
- if (content) {
139
- return { content };
140
- }
141
- }
142
- return { warning: IMAGE_CONVERSION_WARNING };
143
- }
144
- function parseImagePart(part) {
145
- if (!part || typeof part !== "object") {
146
- return { warning: IMAGE_CONVERSION_WARNING };
147
- }
148
- const imageValue = part.image;
149
- const mimeType = extractMimeType(part.mimeType);
150
- if (typeof imageValue === "string") {
151
- return parseStringImage(imageValue, mimeType);
152
- }
153
- if (imageValue && typeof imageValue === "object") {
154
- const content = parseObjectImage(imageValue, mimeType);
155
- return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
156
- }
157
- return { warning: IMAGE_CONVERSION_WARNING };
158
- }
159
- function convertBinaryToBase64(data) {
160
- if (typeof Buffer !== "undefined") {
161
- const buffer = data instanceof Uint8Array ? Buffer.from(data) : Buffer.from(new Uint8Array(data));
162
- return buffer.toString("base64");
163
- }
164
- if (typeof btoa === "function") {
165
- const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
166
- let binary = "";
167
- const chunkSize = 32768;
168
- for (let i = 0; i < bytes.length; i += chunkSize) {
169
- const chunk = bytes.subarray(i, i + chunkSize);
170
- binary += String.fromCharCode(...chunk);
171
- }
172
- return btoa(binary);
173
- }
174
- return void 0;
175
- }
176
- function parseFilePart(part) {
177
- const mimeType = extractMimeType(part.mediaType ?? part.mimeType);
178
- if (!mimeType || !isImageMimeType(mimeType)) {
179
- return {};
180
- }
181
- const data = part.data;
182
- if (typeof data === "string") {
183
- const content = createImageContent(mimeType, data);
184
- return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
185
- }
186
- if (data instanceof Uint8Array || typeof ArrayBuffer !== "undefined" && data instanceof ArrayBuffer) {
187
- const base64 = convertBinaryToBase64(data);
188
- if (!base64) {
189
- return { warning: IMAGE_CONVERSION_WARNING };
190
- }
191
- const content = createImageContent(mimeType, base64);
192
- return content ? { content } : { warning: IMAGE_CONVERSION_WARNING };
193
- }
194
- return { warning: IMAGE_CONVERSION_WARNING };
195
- }
196
- function convertToClaudeCodeMessages(prompt) {
197
- const messages = [];
198
- const warnings = [];
199
- let systemPrompt;
200
- const streamingSegments = [];
201
- const imageMap = /* @__PURE__ */ new Map();
202
- let hasImageParts = false;
203
- const addSegment = (formatted) => {
204
- streamingSegments.push({ formatted });
205
- return streamingSegments.length - 1;
206
- };
207
- const addImageForSegment = (segmentIndex, content) => {
208
- hasImageParts = true;
209
- if (!imageMap.has(segmentIndex)) {
210
- imageMap.set(segmentIndex, []);
211
- }
212
- imageMap.get(segmentIndex)?.push(content);
213
- };
214
- for (const message of prompt) {
215
- switch (message.role) {
216
- case "system":
217
- systemPrompt = message.content;
218
- if (typeof message.content === "string" && message.content.trim().length > 0) {
219
- addSegment(message.content);
220
- } else {
221
- addSegment("");
222
- }
223
- break;
224
- case "user":
225
- if (typeof message.content === "string") {
226
- messages.push(message.content);
227
- addSegment(`Human: ${message.content}`);
228
- } else {
229
- const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
230
- const segmentIndex = addSegment(textParts ? `Human: ${textParts}` : "");
231
- if (textParts) {
232
- messages.push(textParts);
233
- }
234
- for (const part of message.content) {
235
- if (part.type === "image") {
236
- const { content, warning } = parseImagePart(part);
237
- if (content) {
238
- addImageForSegment(segmentIndex, content);
239
- } else if (warning) {
240
- warnings.push(warning);
241
- }
242
- } else if (part.type === "file") {
243
- const { content, warning } = parseFilePart(part);
244
- if (content) {
245
- addImageForSegment(segmentIndex, content);
246
- } else if (warning) {
247
- warnings.push(warning);
248
- }
249
- }
250
- }
251
- }
252
- break;
253
- case "assistant": {
254
- let assistantContent = "";
255
- if (typeof message.content === "string") {
256
- assistantContent = message.content;
257
- } else {
258
- const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
259
- if (textParts) {
260
- assistantContent = textParts;
261
- }
262
- const toolCalls = message.content.filter((part) => part.type === "tool-call");
263
- if (toolCalls.length > 0) {
264
- const serializedCalls = toolCalls.map((call) => `[Tool call: ${call.toolName}(${serializeToolCallInput(call.input)})]`).join("\n");
265
- assistantContent += assistantContent ? `
266
- ${serializedCalls}` : serializedCalls;
267
- }
268
- }
269
- const formattedAssistant = `Assistant: ${assistantContent}`;
270
- messages.push(formattedAssistant);
271
- addSegment(formattedAssistant);
272
- break;
273
- }
274
- case "tool":
275
- for (const tool3 of message.content) {
276
- if (tool3.type === "tool-approval-response") {
277
- continue;
278
- }
279
- let resultText;
280
- const output = tool3.output;
281
- if (output.type === "text" || output.type === "error-text") {
282
- resultText = output.value;
283
- } else if (output.type === "json" || output.type === "error-json") {
284
- resultText = JSON.stringify(output.value);
285
- } else if (output.type === "execution-denied") {
286
- resultText = `[Execution denied${output.reason ? `: ${output.reason}` : ""}]`;
287
- } else if (output.type === "content") {
288
- resultText = output.value.filter((part) => part.type === "text").map((part) => part.text).join("\n");
289
- } else {
290
- resultText = "[Unknown output type]";
291
- }
292
- const formattedToolResult = `Tool Result (${tool3.toolName}): ${resultText}`;
293
- messages.push(formattedToolResult);
294
- addSegment(formattedToolResult);
295
- }
296
- break;
297
- }
298
- }
299
- let finalPrompt = "";
300
- if (systemPrompt) {
301
- finalPrompt = systemPrompt;
302
- }
303
- if (messages.length > 0) {
304
- const formattedMessages = [];
305
- for (let i = 0; i < messages.length; i++) {
306
- const msg = messages[i];
307
- if (msg.startsWith("Assistant:") || msg.startsWith("Tool Result")) {
308
- formattedMessages.push(msg);
309
- } else {
310
- formattedMessages.push(`Human: ${msg}`);
311
- }
312
- }
313
- if (finalPrompt) {
314
- const joinedMessages = formattedMessages.join("\n\n");
315
- finalPrompt = joinedMessages ? `${finalPrompt}
316
-
317
- ${joinedMessages}` : finalPrompt;
318
- } else {
319
- finalPrompt = formattedMessages.join("\n\n");
320
- }
321
- }
322
- const streamingParts = [];
323
- const imagePartsInOrder = [];
324
- const appendImagesForIndex = (index) => {
325
- const images = imageMap.get(index);
326
- if (!images) {
327
- return;
328
- }
329
- images.forEach((image) => {
330
- streamingParts.push(image);
331
- imagePartsInOrder.push(image);
332
- });
333
- };
334
- if (streamingSegments.length > 0) {
335
- let accumulatedText = "";
336
- let emittedText = false;
337
- const flushText = () => {
338
- if (!accumulatedText) {
339
- return;
340
- }
341
- streamingParts.push({ type: "text", text: accumulatedText });
342
- accumulatedText = "";
343
- emittedText = true;
344
- };
345
- streamingSegments.forEach((segment, index) => {
346
- const segmentText = segment.formatted;
347
- if (segmentText) {
348
- if (!accumulatedText) {
349
- accumulatedText = emittedText ? `
350
-
351
- ${segmentText}` : segmentText;
352
- } else {
353
- accumulatedText += `
354
-
355
- ${segmentText}`;
356
- }
357
- }
358
- if (imageMap.has(index)) {
359
- flushText();
360
- appendImagesForIndex(index);
361
- }
362
- });
363
- flushText();
364
- }
365
- return {
366
- messagesPrompt: finalPrompt,
367
- systemPrompt,
368
- ...warnings.length > 0 && { warnings },
369
- streamingContentParts: streamingParts.length > 0 ? streamingParts : [
370
- { type: "text", text: finalPrompt },
371
- ...imagePartsInOrder
372
- ],
373
- hasImageParts
374
- };
375
- }
376
-
377
- // src/errors.ts
378
- var import_provider = require("@ai-sdk/provider");
379
- var STDERR_TAIL_MARKER = " | stderr (tail):";
380
- var ANSI_ESCAPE_SEQUENCE = (
381
- // eslint-disable-next-line no-control-regex
382
- /\x1b(?:\][^\x07\x1b]*(?:\x07|\x1b\\)|\[[0-?]*[ -/]*[@-~])/g
383
- );
384
- function stderrTail(raw) {
385
- const withoutAnsi = raw.replace(ANSI_ESCAPE_SEQUENCE, "");
386
- const withoutControlCharacters = Array.from(withoutAnsi).filter((character) => {
387
- const codePoint = character.codePointAt(0) ?? 0;
388
- return character === "\r" || character === "\n" || codePoint === 8232 || codePoint === 8233 || codePoint >= 32 && codePoint < 127 || codePoint > 159;
389
- }).join("");
390
- const tail = withoutControlCharacters.split(/\r\n|\r|\n|\u2028|\u2029/).map((line) => line.trim()).filter((line) => line.length > 0).slice(-5).join("; ");
391
- const codePoints = Array.from(tail);
392
- return codePoints.length > 600 ? `\u2026${codePoints.slice(-599).join("")}` : tail;
393
- }
394
- function createAPICallError({
395
- message,
396
- code,
397
- exitCode,
398
- stderr,
399
- promptExcerpt,
400
- isRetryable = false
401
- }) {
402
- const metadata = {
403
- code,
404
- exitCode,
405
- stderr,
406
- promptExcerpt
407
- };
408
- const tail = typeof stderr === "string" && stderr.length > 0 ? stderrTail(stderr) : "";
409
- const enrichedMessage = tail && !message.includes(STDERR_TAIL_MARKER) ? `${message}${STDERR_TAIL_MARKER} ${tail}` : message;
410
- return new import_provider.APICallError({
411
- message: enrichedMessage,
412
- isRetryable,
413
- url: "claude-code-cli://command",
414
- requestBodyValues: promptExcerpt ? { prompt: promptExcerpt } : void 0,
415
- data: metadata
416
- });
417
- }
418
- function createAuthenticationError({
419
- message,
420
- stderr
421
- }) {
422
- const error = new import_provider.LoadAPIKeyError({
423
- message: message || "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
424
- });
425
- if (stderr) {
426
- error.data = { stderr };
427
- }
428
- return error;
429
- }
430
- function createTimeoutError({
431
- message,
432
- stderr,
433
- promptExcerpt,
434
- timeoutMs
435
- }) {
436
- const metadata = {
437
- code: "TIMEOUT",
438
- stderr,
439
- promptExcerpt
440
- };
441
- return new import_provider.APICallError({
442
- message,
443
- isRetryable: true,
444
- url: "claude-code-cli://command",
445
- requestBodyValues: promptExcerpt ? { prompt: promptExcerpt } : void 0,
446
- data: timeoutMs !== void 0 ? { ...metadata, timeoutMs } : metadata
447
- });
448
- }
449
- function isAuthenticationError(error) {
450
- if (error instanceof import_provider.LoadAPIKeyError) return true;
451
- if (error instanceof import_provider.APICallError && error.data?.exitCode === 401)
452
- return true;
453
- return false;
454
- }
455
- function isTimeoutError(error) {
456
- if (error instanceof import_provider.APICallError && error.data?.code === "TIMEOUT")
457
- return true;
458
- return false;
459
- }
460
- function getErrorMetadata(error) {
461
- if (error instanceof import_provider.APICallError && error.data) {
462
- return error.data;
463
- }
464
- if (error instanceof import_provider.LoadAPIKeyError && error.data) {
465
- return error.data;
466
- }
467
- return void 0;
468
- }
469
-
470
- // src/map-claude-code-finish-reason.ts
471
- function mapClaudeCodeFinishReason(subtype, stopReason) {
472
- if (stopReason != null) {
473
- switch (stopReason) {
474
- case "end_turn":
475
- return { unified: "stop", raw: "end_turn" };
476
- case "max_tokens":
477
- return { unified: "length", raw: "max_tokens" };
478
- case "stop_sequence":
479
- return { unified: "stop", raw: "stop_sequence" };
480
- case "tool_use":
481
- return { unified: "tool-calls", raw: "tool_use" };
482
- default:
483
- break;
484
- }
485
- }
486
- const raw = stopReason ?? subtype;
487
- switch (subtype) {
488
- case "success":
489
- return { unified: "stop", raw };
490
- case "error_max_turns":
491
- return { unified: "length", raw };
492
- case "error_during_execution":
493
- return { unified: "error", raw };
494
- case void 0:
495
- return { unified: "stop", raw };
496
- default:
497
- return { unified: "other", raw };
498
- }
499
- }
500
-
501
- // src/validation.ts
502
- var import_zod = require("zod");
503
- var import_fs = require("fs");
504
- function isBlankResume(value) {
505
- return typeof value === "string" && value.trim() === "";
506
- }
507
- var loggerFunctionSchema = import_zod.z.object({
508
- debug: import_zod.z.any().refine((val) => typeof val === "function", {
509
- message: "debug must be a function"
510
- }),
511
- info: import_zod.z.any().refine((val) => typeof val === "function", {
512
- message: "info must be a function"
513
- }),
514
- warn: import_zod.z.any().refine((val) => typeof val === "function", {
515
- message: "warn must be a function"
516
- }),
517
- error: import_zod.z.any().refine((val) => typeof val === "function", {
518
- message: "error must be a function"
519
- })
520
- });
521
- var claudeCodeSettingsSchema = import_zod.z.object({
522
- pathToClaudeCodeExecutable: import_zod.z.string().optional(),
523
- customSystemPrompt: import_zod.z.string().optional(),
524
- appendSystemPrompt: import_zod.z.string().optional(),
525
- systemPrompt: import_zod.z.union([
526
- import_zod.z.string(),
527
- import_zod.z.array(import_zod.z.string()),
528
- import_zod.z.object({
529
- type: import_zod.z.literal("preset"),
530
- preset: import_zod.z.literal("claude_code"),
531
- append: import_zod.z.string().optional(),
532
- excludeDynamicSections: import_zod.z.boolean().optional()
533
- })
534
- ]).optional(),
535
- maxTurns: import_zod.z.number().int().min(1).max(100).optional(),
536
- maxThinkingTokens: import_zod.z.number().int().positive().max(1e5).optional(),
537
- thinking: import_zod.z.union([
538
- import_zod.z.object({
539
- type: import_zod.z.literal("adaptive"),
540
- display: import_zod.z.enum(["summarized", "omitted"]).optional()
541
- }).strict(),
542
- import_zod.z.object({
543
- type: import_zod.z.literal("enabled"),
544
- budgetTokens: import_zod.z.number().int().positive().optional(),
545
- display: import_zod.z.enum(["summarized", "omitted"]).optional()
546
- }).strict(),
547
- import_zod.z.object({ type: import_zod.z.literal("disabled") }).strict()
548
- ]).optional(),
549
- effort: import_zod.z.enum(["low", "medium", "high", "xhigh", "max"]).optional(),
550
- promptSuggestions: import_zod.z.boolean().optional(),
551
- cwd: import_zod.z.string().refine(
552
- (val) => {
553
- if (typeof process === "undefined" || !process.versions?.node) {
554
- return true;
555
- }
556
- return !val || (0, import_fs.existsSync)(val);
557
- },
558
- { message: "Working directory must exist" }
559
- ).optional(),
560
- executable: import_zod.z.enum(["bun", "deno", "node"]).optional(),
561
- executableArgs: import_zod.z.array(import_zod.z.string()).optional(),
562
- // Mirrors the SDK 0.3.x PermissionMode union ('auto' and 'dontAsk' were
563
- // added in 0.3.x; 'delegate' was dropped AND is rejected by the CLI's
564
- // --permission-mode flag parser, so it is rejected here too).
565
- permissionMode: import_zod.z.enum(["default", "acceptEdits", "bypassPermissions", "plan", "dontAsk", "auto"]).optional(),
566
- permissionPromptToolName: import_zod.z.string().optional(),
567
- continue: import_zod.z.boolean().optional(),
568
- resume: import_zod.z.string().optional(),
569
- // The CLI rejects --session-id values that are not valid UUIDs, so
570
- // enforce the UUID shape here instead of failing at query time.
571
- sessionId: import_zod.z.string().refine(
572
- (val) => /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(val),
573
- { message: "sessionId must be a valid UUID (the CLI rejects non-UUID session IDs)" }
574
- ).optional(),
575
- allowedTools: import_zod.z.array(import_zod.z.string()).optional(),
576
- disallowedTools: import_zod.z.array(import_zod.z.string()).optional(),
577
- betas: import_zod.z.array(import_zod.z.string()).optional(),
578
- allowDangerouslySkipPermissions: import_zod.z.boolean().optional(),
579
- enableFileCheckpointing: import_zod.z.boolean().optional(),
580
- maxBudgetUsd: import_zod.z.number().min(0).optional(),
581
- plugins: import_zod.z.array(
582
- import_zod.z.object({
583
- // SDK SdkPluginConfig: only 'local' is supported; the SDK throws
584
- // 'Unsupported plugin type' at query time for anything else.
585
- type: import_zod.z.literal("local"),
586
- path: import_zod.z.string()
587
- }).passthrough()
588
- ).optional(),
589
- resumeSessionAt: import_zod.z.string().optional(),
590
- sandbox: import_zod.z.any().refine((val) => val === void 0 || typeof val === "object", {
591
- message: "sandbox must be an object"
592
- }).optional(),
593
- tools: import_zod.z.union([
594
- import_zod.z.array(import_zod.z.string()),
595
- import_zod.z.object({
596
- type: import_zod.z.literal("preset"),
597
- preset: import_zod.z.literal("claude_code")
598
- })
599
- ]).optional(),
600
- skills: import_zod.z.union([import_zod.z.array(import_zod.z.string()), import_zod.z.literal("all")]).optional(),
601
- settings: import_zod.z.union([
602
- import_zod.z.string(),
603
- import_zod.z.record(import_zod.z.string(), import_zod.z.any())
604
- // inline Settings object
605
- ]).optional(),
606
- managedSettings: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional(),
607
- toolAliases: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
608
- toolConfig: import_zod.z.object({
609
- askUserQuestion: import_zod.z.object({
610
- previewFormat: import_zod.z.enum(["markdown", "html"]).optional()
611
- }).passthrough().optional()
612
- }).passthrough().optional(),
613
- planModeInstructions: import_zod.z.string().optional(),
614
- title: import_zod.z.string().optional(),
615
- forwardSubagentText: import_zod.z.boolean().optional(),
616
- agentProgressSummaries: import_zod.z.boolean().optional(),
617
- includeHookEvents: import_zod.z.boolean().optional(),
618
- taskBudget: import_zod.z.object({ total: import_zod.z.number().positive() }).strict().optional(),
619
- sessionStore: import_zod.z.any().refine(
620
- (val) => val === void 0 || typeof val === "object" && val !== null && typeof val.append === "function" && typeof val.load === "function",
621
- { message: "sessionStore must be an object with append() and load() functions" }
622
- ).optional(),
623
- sessionStoreFlush: import_zod.z.enum(["batched", "eager"]).optional(),
624
- loadTimeoutMs: import_zod.z.number().int().positive().optional(),
625
- settingSources: import_zod.z.array(import_zod.z.enum(["user", "project", "local"])).optional(),
626
- streamingInput: import_zod.z.enum(["auto", "always", "off"]).optional(),
627
- // Hooks and tool-permission callback (permissive validation of shapes)
628
- canUseTool: import_zod.z.any().refine((v) => v === void 0 || typeof v === "function", {
629
- message: "canUseTool must be a function"
630
- }).optional(),
631
- onUserDialog: import_zod.z.any().refine((v) => v === void 0 || typeof v === "function", {
632
- message: "onUserDialog must be a function"
633
- }).optional(),
634
- supportedDialogKinds: import_zod.z.array(import_zod.z.string()).optional(),
635
- hooks: import_zod.z.record(
636
- import_zod.z.string(),
637
- import_zod.z.array(
638
- import_zod.z.object({
639
- matcher: import_zod.z.string().optional(),
640
- hooks: import_zod.z.array(import_zod.z.any()).nonempty()
641
- })
642
- )
643
- ).optional(),
644
- mcpServers: import_zod.z.record(
645
- import_zod.z.string(),
646
- import_zod.z.union([
647
- // McpStdioServerConfig
648
- import_zod.z.object({
649
- type: import_zod.z.literal("stdio").optional(),
650
- command: import_zod.z.string(),
651
- args: import_zod.z.array(import_zod.z.string()).optional(),
652
- env: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional()
653
- }),
654
- // McpSSEServerConfig
655
- import_zod.z.object({
656
- type: import_zod.z.literal("sse"),
657
- url: import_zod.z.string(),
658
- headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional()
659
- }),
660
- // McpHttpServerConfig
661
- import_zod.z.object({
662
- type: import_zod.z.literal("http"),
663
- url: import_zod.z.string(),
664
- headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional()
665
- }),
666
- // McpSdkServerConfig (in-process custom tools)
667
- import_zod.z.object({
668
- type: import_zod.z.literal("sdk"),
669
- name: import_zod.z.string(),
670
- instance: import_zod.z.any()
671
- })
672
- ])
673
- ).optional(),
674
- verbose: import_zod.z.boolean().optional(),
675
- debug: import_zod.z.boolean().optional(),
676
- debugFile: import_zod.z.string().optional(),
677
- logger: import_zod.z.union([import_zod.z.literal(false), loggerFunctionSchema]).optional(),
678
- env: import_zod.z.record(import_zod.z.string(), import_zod.z.string().optional()).optional(),
679
- additionalDirectories: import_zod.z.array(import_zod.z.string()).optional(),
680
- agents: import_zod.z.record(
681
- import_zod.z.string(),
682
- import_zod.z.object({
683
- description: import_zod.z.string(),
684
- tools: import_zod.z.array(import_zod.z.string()).optional(),
685
- disallowedTools: import_zod.z.array(import_zod.z.string()).optional(),
686
- prompt: import_zod.z.string(),
687
- // SDK 0.3.x AgentDefinition accepts any model alias or full model ID
688
- model: import_zod.z.string().optional(),
689
- mcpServers: import_zod.z.array(
690
- import_zod.z.union([
691
- import_zod.z.string(),
692
- import_zod.z.record(import_zod.z.string(), import_zod.z.any())
693
- // McpServerConfigForProcessTransport
694
- ])
695
- ).optional(),
696
- criticalSystemReminder_EXPERIMENTAL: import_zod.z.string().optional()
697
- }).passthrough()
698
- ).optional(),
699
- includePartialMessages: import_zod.z.boolean().optional(),
700
- fallbackModel: import_zod.z.string().optional(),
701
- forkSession: import_zod.z.boolean().optional(),
702
- stderr: import_zod.z.any().refine((val) => val === void 0 || typeof val === "function", {
703
- message: "stderr must be a function"
704
- }).optional(),
705
- strictMcpConfig: import_zod.z.boolean().optional(),
706
- extraArgs: import_zod.z.record(import_zod.z.string(), import_zod.z.union([import_zod.z.string(), import_zod.z.null()])).optional(),
707
- persistSession: import_zod.z.boolean().optional(),
708
- spawnClaudeCodeProcess: import_zod.z.any().refine((val) => val === void 0 || typeof val === "function", {
709
- message: "spawnClaudeCodeProcess must be a function"
710
- }).optional(),
711
- sdkOptions: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional(),
712
- maxToolResultSize: import_zod.z.number().int().min(100).max(1e6).optional(),
713
- // Callback invoked when Query object is created - for mid-stream injection via streamInput()
714
- onQueryCreated: import_zod.z.any().refine((val) => val === void 0 || typeof val === "function", {
715
- message: "onQueryCreated must be a function"
716
- }).optional(),
717
- onStreamStart: import_zod.z.any().refine((val) => val === void 0 || typeof val === "function", {
718
- message: "onStreamStart must be a function"
719
- }).optional(),
720
- // Callback invoked with the predicted next user prompt (active unless promptSuggestions: false)
721
- onPromptSuggestion: import_zod.z.any().refine((val) => val === void 0 || typeof val === "function", {
722
- message: "onPromptSuggestion must be a function"
723
- }).optional()
724
- }).strict();
725
- function validateModelId(modelId) {
726
- const knownModels = ["opus", "sonnet", "haiku", "fable"];
727
- if (!modelId || modelId.trim() === "") {
728
- throw new Error("Model ID cannot be empty");
729
- }
730
- if (!knownModels.includes(modelId)) {
731
- return `Unknown model ID: '${modelId}'. Proceeding with custom model. Known models are: ${knownModels.join(", ")}`;
732
- }
733
- return void 0;
734
- }
735
- function validateSettings(settings) {
736
- const warnings = [];
737
- const errors = [];
738
- try {
739
- const result = claudeCodeSettingsSchema.safeParse(settings);
740
- if (!result.success) {
741
- const errorObject = result.error;
742
- const issues = errorObject.errors || errorObject.issues || [];
743
- issues.forEach((err) => {
744
- const path = err.path.join(".");
745
- errors.push(`${path ? `${path}: ` : ""}${err.message}`);
746
- });
747
- return { valid: false, warnings, errors };
748
- }
749
- const validSettings = result.data;
750
- const sdkOptionsRecord = validSettings.sdkOptions;
751
- const effective = (key) => {
752
- const override = sdkOptionsRecord?.[key];
753
- return override !== void 0 ? override : validSettings[key];
754
- };
755
- const effSessionStore = effective("sessionStore");
756
- const effectiveResumeId = () => {
757
- for (const candidate of [sdkOptionsRecord?.resume, validSettings.resume]) {
758
- if (typeof candidate === "string" && !isBlankResume(candidate)) {
759
- return candidate;
760
- }
761
- }
762
- return void 0;
763
- };
764
- if (effSessionStore !== void 0 && effective("persistSession") === false) {
765
- errors.push(
766
- "sessionStore cannot be combined with persistSession: false. Transcript mirroring requires local session writes; remove persistSession: false or drop sessionStore."
767
- );
768
- return { valid: false, warnings, errors };
769
- }
770
- if (effSessionStore !== void 0 && effective("enableFileCheckpointing") === true) {
771
- errors.push(
772
- "sessionStore cannot be combined with enableFileCheckpointing: true. Checkpoint backup blobs are not mirrored to the store (rewindFiles() fails after a store-backed resume); remove enableFileCheckpointing or drop sessionStore."
773
- );
774
- return { valid: false, warnings, errors };
775
- }
776
- if (effective("continue") === true && effSessionStore !== void 0 && effectiveResumeId() === void 0 && typeof effSessionStore.listSessions !== "function") {
777
- errors.push(
778
- "continue: true with sessionStore requires the store to implement listSessions() (used to discover the most recent session). Implement listSessions(), pass resume with an explicit session ID, or drop continue."
779
- );
780
- return { valid: false, warnings, errors };
781
- }
782
- const effSettingsOption = effective("settings");
783
- if (effective("sandbox") !== void 0 && typeof effSettingsOption === "string" && !(effSettingsOption.trim().startsWith("{") && effSettingsOption.trim().endsWith("}"))) {
784
- errors.push(
785
- "sandbox cannot be combined with a settings file path. Pass settings as an inline Settings object, or move the sandbox configuration into the settings file and drop the sandbox option."
786
- );
787
- return { valid: false, warnings, errors };
788
- }
789
- if (effective("sessionId") !== void 0 && effective("forkSession") !== true && (effective("continue") === true || effectiveResumeId() !== void 0)) {
790
- errors.push(
791
- "sessionId cannot be combined with continue or resume unless forkSession: true is also set (it then names the forked session's ID). Remove sessionId, remove continue/resume, or add forkSession: true."
792
- );
793
- return { valid: false, warnings, errors };
794
- }
795
- if (validSettings.maxTurns && validSettings.maxTurns > 20) {
796
- warnings.push(
797
- `High maxTurns value (${validSettings.maxTurns}) may lead to long-running conversations`
798
- );
799
- }
800
- if (validSettings.maxThinkingTokens && validSettings.maxThinkingTokens > 5e4) {
801
- warnings.push(
802
- `Very high maxThinkingTokens (${validSettings.maxThinkingTokens}) may increase response time`
803
- );
804
- }
805
- if (validSettings.allowedTools && validSettings.disallowedTools) {
806
- warnings.push(
807
- "Both allowedTools and disallowedTools are specified. Only allowedTools will be used."
808
- );
809
- }
810
- const validateToolNames = (tools, type) => {
811
- tools.forEach((tool3) => {
812
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*(\([^)]*\))?$/.test(tool3) && !tool3.startsWith("mcp__")) {
813
- warnings.push(`Unusual ${type} tool name format: '${tool3}'`);
814
- }
815
- });
816
- };
817
- if (validSettings.allowedTools) {
818
- validateToolNames(validSettings.allowedTools, "allowed");
819
- }
820
- if (validSettings.disallowedTools) {
821
- validateToolNames(validSettings.disallowedTools, "disallowed");
822
- }
823
- const effDialogKinds = effective("supportedDialogKinds");
824
- if (Array.isArray(effDialogKinds) && effDialogKinds.length > 0 && effective("onUserDialog") == null) {
825
- errors.push(
826
- "supportedDialogKinds is set without onUserDialog. The SDK requires the onUserDialog callback to render declared dialog kinds and throws when a non-empty list is passed without it; provide onUserDialog or remove supportedDialogKinds."
827
- );
828
- return { valid: false, warnings, errors };
829
- }
830
- const effAllowedTools = effective("allowedTools");
831
- if (Array.isArray(effAllowedTools) && effAllowedTools.includes("Skill") && !effective("settingSources")) {
832
- warnings.push(
833
- "allowedTools includes 'Skill' but settingSources is not set. Skills require settingSources (e.g., ['user', 'project']) to load skill definitions."
834
- );
835
- }
836
- if (validSettings.agents) {
837
- const knownAgentModelAliases = ["sonnet", "opus", "haiku", "fable", "inherit"];
838
- for (const [agentName, agent] of Object.entries(validSettings.agents)) {
839
- const agentModel = agent.model;
840
- if (agentModel !== void 0 && !knownAgentModelAliases.includes(agentModel) && !agentModel.includes("-")) {
841
- warnings.push(
842
- `Unknown model alias '${agentModel}' for agent '${agentName}'. Known aliases are: ${knownAgentModelAliases.join(", ")}; full model IDs (e.g. 'claude-sonnet-4-5') are also accepted.`
843
- );
844
- }
845
- }
846
- }
847
- return { valid: true, warnings, errors };
848
- } catch (error) {
849
- errors.push(`Validation error: ${error instanceof Error ? error.message : String(error)}`);
850
- return { valid: false, warnings, errors };
851
- }
852
- }
853
- function validatePrompt(prompt) {
854
- const MAX_PROMPT_LENGTH = 1e5;
855
- if (prompt.length > MAX_PROMPT_LENGTH) {
856
- return `Very long prompt (${prompt.length} characters) may cause performance issues or timeouts`;
857
- }
858
- return void 0;
859
- }
860
- function validateSessionId(sessionId) {
861
- if (sessionId && !/^[a-zA-Z0-9-_]+$/.test(sessionId)) {
862
- return `Unusual session ID format. This may cause issues with session resumption.`;
863
- }
864
- return void 0;
865
- }
866
-
867
- // src/sanitize-json-schema.ts
868
- var SUBSCHEMA_MAP_KEYWORDS = [
869
- "properties",
870
- "patternProperties",
871
- "$defs",
872
- "definitions",
873
- "dependentSchemas",
874
- // draft-07 `dependencies` values are either subschemas (schema form) or
875
- // arrays of property-name strings (array form); sanitizeNode passes
876
- // string arrays through untouched, so walking both forms is safe.
877
- "dependencies"
878
- ];
879
- var SUBSCHEMA_KEYWORDS = [
880
- "items",
881
- // may also be an array of subschemas (draft-07 tuple form)
882
- "additionalItems",
883
- "additionalProperties",
884
- "unevaluatedItems",
885
- "unevaluatedProperties",
886
- "not",
887
- "contains",
888
- "propertyNames",
889
- "contentSchema",
890
- "if",
891
- "then",
892
- "else"
893
- ];
894
- var SUBSCHEMA_LIST_KEYWORDS = ["prefixItems", "anyOf", "oneOf", "allOf"];
895
- function sanitizeJsonSchemaForOutputFormat(schema) {
896
- const strippedFormatPaths = [];
897
- const sanitized = sanitizeNode(schema, "#", /* @__PURE__ */ new WeakSet(), strippedFormatPaths);
898
- return {
899
- schema: sanitized ?? schema,
900
- strippedFormatPaths
901
- };
902
- }
903
- function sanitizeNode(node, path, visiting, strippedFormatPaths) {
904
- if (typeof node !== "object" || node === null) {
905
- return node;
906
- }
907
- if (visiting.has(node)) {
908
- return node;
909
- }
910
- visiting.add(node);
911
- try {
912
- if (Array.isArray(node)) {
913
- return sanitizeList(node, path, visiting, strippedFormatPaths);
914
- }
915
- const record = node;
916
- let result = record;
917
- const setKey = (key, value) => {
918
- if (result === record) {
919
- result = { ...record };
920
- }
921
- result[key] = value;
922
- };
923
- if (typeof record.format === "string") {
924
- const format = record.format;
925
- const existingDescription = record.description;
926
- result = { ...record };
927
- delete result.format;
928
- if (typeof existingDescription === "string" && existingDescription.length > 0) {
929
- result.description = `${existingDescription} (expected format: ${format})`;
930
- } else if (existingDescription === void 0 || existingDescription === "") {
931
- result.description = `Expected format: ${format}`;
932
- }
933
- strippedFormatPaths.push(path);
934
- }
935
- for (const keyword of SUBSCHEMA_MAP_KEYWORDS) {
936
- const map = record[keyword];
937
- if (typeof map !== "object" || map === null || Array.isArray(map)) continue;
938
- const mapRecord = map;
939
- let newMap = mapRecord;
940
- for (const [name, child] of Object.entries(mapRecord)) {
941
- const sanitizedChild = sanitizeNode(
942
- child,
943
- `${path}/${keyword}/${name}`,
944
- visiting,
945
- strippedFormatPaths
946
- );
947
- if (sanitizedChild !== child) {
948
- if (newMap === mapRecord) {
949
- newMap = { ...mapRecord };
950
- }
951
- newMap[name] = sanitizedChild;
952
- }
953
- }
954
- if (newMap !== mapRecord) {
955
- setKey(keyword, newMap);
956
- }
957
- }
958
- for (const keyword of SUBSCHEMA_KEYWORDS) {
959
- const child = record[keyword];
960
- if (typeof child !== "object" || child === null) continue;
961
- const sanitizedChild = sanitizeNode(
962
- child,
963
- `${path}/${keyword}`,
964
- visiting,
965
- strippedFormatPaths
966
- );
967
- if (sanitizedChild !== child) {
968
- setKey(keyword, sanitizedChild);
969
- }
970
- }
971
- for (const keyword of SUBSCHEMA_LIST_KEYWORDS) {
972
- const list = record[keyword];
973
- if (!Array.isArray(list)) continue;
974
- const sanitizedList = sanitizeList(list, `${path}/${keyword}`, visiting, strippedFormatPaths);
975
- if (sanitizedList !== list) {
976
- setKey(keyword, sanitizedList);
977
- }
978
- }
979
- return result;
980
- } finally {
981
- visiting.delete(node);
982
- }
983
- }
984
- function sanitizeList(list, path, visiting, strippedFormatPaths) {
985
- let result = list;
986
- for (let i = 0; i < list.length; i++) {
987
- const sanitizedChild = sanitizeNode(list[i], `${path}/${i}`, visiting, strippedFormatPaths);
988
- if (sanitizedChild !== list[i]) {
989
- if (result === list) {
990
- result = [...list];
991
- }
992
- result[i] = sanitizedChild;
993
- }
994
- }
995
- return result;
996
- }
997
-
998
- // src/logger.ts
999
- var defaultLogger = {
1000
- // eslint-disable-next-line no-console
1001
- debug: (message) => console.debug(`[DEBUG] ${message}`),
1002
- // eslint-disable-next-line no-console
1003
- info: (message) => console.info(`[INFO] ${message}`),
1004
- warn: (message) => console.warn(`[WARN] ${message}`),
1005
- error: (message) => console.error(`[ERROR] ${message}`)
1006
- };
1007
- var noopLogger = {
1008
- debug: () => {
1009
- },
1010
- info: () => {
1011
- },
1012
- warn: () => {
1013
- },
1014
- error: () => {
1015
- }
1016
- };
1017
- function getLogger(logger) {
1018
- if (logger === false) {
1019
- return noopLogger;
1020
- }
1021
- if (logger === void 0) {
1022
- return defaultLogger;
1023
- }
1024
- return logger;
1025
- }
1026
- function createVerboseLogger(logger, verbose = false) {
1027
- if (verbose) {
1028
- return logger;
1029
- }
1030
- return {
1031
- debug: () => {
1032
- },
1033
- // No-op when not verbose
1034
- info: () => {
1035
- },
1036
- // No-op when not verbose
1037
- warn: logger.warn.bind(logger),
1038
- error: logger.error.bind(logger)
1039
- };
1040
- }
1041
-
1042
- // src/claude-code-language-model.ts
1043
- var import_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
1044
- var PROVIDER_VERSION = "3.5.3";
1045
- var DEFAULT_CLIENT_APP = `ai-sdk-provider-claude-code/${PROVIDER_VERSION}`;
1046
- var CLAUDE_CODE_TRUNCATION_WARNING = "Claude Code SDK output ended unexpectedly; returning truncated response from buffered text. Await upstream fix to avoid data loss.";
1047
- var MIN_TRUNCATION_LENGTH = 512;
1048
- function capStderr(raw) {
1049
- if (raw.length <= 4e3) {
1050
- return raw;
1051
- }
1052
- return Array.from(raw).slice(-4e3).join("");
1053
- }
1054
- function isClaudeCodeTruncationError(error, bufferedText) {
1055
- const isSyntaxError = error instanceof SyntaxError || // eslint-disable-next-line @typescript-eslint/no-explicit-any
1056
- typeof error?.name === "string" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
1057
- error.name.toLowerCase() === "syntaxerror";
1058
- if (!isSyntaxError) {
1059
- return false;
1060
- }
1061
- if (!bufferedText) {
1062
- return false;
1063
- }
1064
- const rawMessage = typeof error?.message === "string" ? error.message : "";
1065
- const message = rawMessage.toLowerCase();
1066
- const truncationIndicators = [
1067
- "unexpected end of json input",
1068
- "unexpected end of input",
1069
- "unexpected end of string",
1070
- "unexpected eof",
1071
- "end of file",
1072
- "unterminated string",
1073
- "unterminated string constant"
1074
- ];
1075
- if (!truncationIndicators.some((indicator) => message.includes(indicator))) {
1076
- return false;
1077
- }
1078
- if (bufferedText.length < MIN_TRUNCATION_LENGTH) {
1079
- return false;
1080
- }
1081
- return true;
1082
- }
1083
- 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.";
1084
- function extractJsonObjectText(text) {
1085
- const trimmed = text.trim();
1086
- if (!trimmed) {
1087
- return void 0;
1088
- }
1089
- const candidates = [trimmed];
1090
- const fencedBlocks = Array.from(trimmed.matchAll(/```(?:json)?\s*\n?([\s\S]*?)```/gi)).map((match) => match[1]?.trim()).filter((block) => block !== void 0 && block.length > 0);
1091
- candidates.push(...fencedBlocks.reverse());
1092
- for (const candidate of candidates) {
1093
- if (!candidate) continue;
1094
- try {
1095
- const parsed = JSON.parse(candidate);
1096
- if (typeof parsed === "object" && parsed !== null) {
1097
- return candidate;
1098
- }
1099
- } catch {
1100
- }
1101
- }
1102
- return void 0;
1103
- }
1104
- function getStructuredErrorKind(error) {
1105
- if (typeof error === "object" && error !== null && "errorKind" in error) {
1106
- const kind = error.errorKind;
1107
- if (typeof kind === "string") return kind;
1108
- }
1109
- return void 0;
1110
- }
1111
- function isAbortError(err) {
1112
- if (err && typeof err === "object") {
1113
- const e = err;
1114
- if (typeof e.name === "string" && e.name === "AbortError") return true;
1115
- if (typeof e.code === "string" && e.code.toUpperCase() === "ABORT_ERR") return true;
1116
- }
1117
- return false;
1118
- }
1119
- var DEFAULT_INHERITED_ENV_VARS = process.platform === "win32" ? [
1120
- "APPDATA",
1121
- "COMSPEC",
1122
- "HOMEDRIVE",
1123
- "HOMEPATH",
1124
- "LOCALAPPDATA",
1125
- "PATH",
1126
- "PATHEXT",
1127
- "SYSTEMDRIVE",
1128
- "SYSTEMROOT",
1129
- "TEMP",
1130
- "TMP",
1131
- "USERNAME",
1132
- "USERPROFILE",
1133
- "WINDIR"
1134
- ] : ["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER", "LANG", "LC_ALL", "TMPDIR"];
1135
- var CLAUDE_ENV_VARS = ["CLAUDE_CONFIG_DIR"];
1136
- var NETWORK_ENV_VARS = [
1137
- "HTTP_PROXY",
1138
- "HTTPS_PROXY",
1139
- "NO_PROXY",
1140
- "http_proxy",
1141
- "https_proxy",
1142
- "no_proxy",
1143
- "NODE_EXTRA_CA_CERTS",
1144
- "SSL_CERT_FILE",
1145
- "SSL_CERT_DIR"
1146
- ];
1147
- var CLOUD_ENV_VARS = ["GCLOUD_PROJECT", "CLOUD_ML_REGION"];
1148
- var INHERITED_ENV_PREFIXES = ["ANTHROPIC_", "CLAUDE_", "AWS_", "GOOGLE_"];
1149
- function getBaseProcessEnv() {
1150
- const env = {};
1151
- const allowedKeys = /* @__PURE__ */ new Set([
1152
- ...DEFAULT_INHERITED_ENV_VARS,
1153
- ...CLAUDE_ENV_VARS,
1154
- ...NETWORK_ENV_VARS,
1155
- ...CLOUD_ENV_VARS
1156
- ]);
1157
- const addIfSafe = (key) => {
1158
- const value = process.env[key];
1159
- if (typeof value !== "string") {
1160
- return;
1161
- }
1162
- if (value.startsWith("()")) {
1163
- return;
1164
- }
1165
- env[key] = value;
1166
- };
1167
- for (const key of allowedKeys) {
1168
- addIfSafe(key);
1169
- }
1170
- for (const key of Object.keys(process.env)) {
1171
- if (INHERITED_ENV_PREFIXES.some((prefix) => key.startsWith(prefix))) {
1172
- addIfSafe(key);
1173
- }
1174
- }
1175
- return env;
1176
- }
1177
- 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).";
1178
- var SDK_OPTIONS_BLOCKLIST = /* @__PURE__ */ new Set(["model", "abortController", "prompt", "outputFormat"]);
1179
- var SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
1180
- function isSubagentToolName(name) {
1181
- return SUBAGENT_TOOL_NAMES.has(name);
1182
- }
1183
- function resolveToolParentId(messageLevel, blockLevel, inferFallback) {
1184
- if (messageLevel !== void 0) return messageLevel;
1185
- if (typeof blockLevel === "string") return blockLevel;
1186
- return inferFallback();
1187
- }
1188
- function computeRetractedToolCallIds(retracted, descriptors) {
1189
- const ids = /* @__PURE__ */ new Set();
1190
- for (const { toolCallId, uuid } of descriptors) {
1191
- if (uuid !== void 0 && retracted.has(uuid)) {
1192
- ids.add(toolCallId);
1193
- }
1194
- }
1195
- return ids;
1196
- }
1197
- function applySupersede(message, evict, logger, guard = "array") {
1198
- const supersedes = message.supersedes;
1199
- const triggered = guard === "truthy" ? Boolean(supersedes && supersedes.length > 0) : Array.isArray(supersedes) && supersedes.length > 0;
1200
- if (!triggered) {
1201
- return false;
1202
- }
1203
- logger.debug(`[claude-code] Assistant message supersedes ${supersedes.length} prior message(s)`);
1204
- evict(new Set(supersedes));
1205
- return true;
1206
- }
1207
- function buildRetractionEvictor(evict) {
1208
- return (uuids) => evict(new Set(uuids));
1209
- }
1210
- var INFORMATIONAL_SYSTEM_SUBTYPES = /* @__PURE__ */ new Set([
1211
- "notification",
1212
- "status",
1213
- "task_updated",
1214
- "session_state_changed",
1215
- "commands_changed",
1216
- "memory_recall",
1217
- "plugin_install"
1218
- ]);
1219
- function isContentBlock(item) {
1220
- return typeof item === "object" && item !== null && "type" in item;
1221
- }
1222
- function filterContentBlocks(content, type) {
1223
- if (!Array.isArray(content)) return [];
1224
- const blocks = content.filter(
1225
- (item) => isContentBlock(item) && item.type === type
1226
- );
1227
- const mismatch = blocks.find((b) => b.type !== type);
1228
- if (mismatch) {
1229
- throw new Error(
1230
- `filterContentBlocks: block type '${mismatch.type}' passed filter for '${type}'`
1231
- );
1232
- }
1233
- return blocks;
1234
- }
1235
- function createEmptyUsage() {
1236
- return {
1237
- inputTokens: {
1238
- total: 0,
1239
- noCache: 0,
1240
- cacheRead: 0,
1241
- cacheWrite: 0
1242
- },
1243
- outputTokens: {
1244
- total: 0,
1245
- text: void 0,
1246
- reasoning: void 0
1247
- },
1248
- raw: void 0
1249
- };
1250
- }
1251
- function convertClaudeCodeUsage(usage) {
1252
- const inputTokens = usage.input_tokens ?? 0;
1253
- const outputTokens = usage.output_tokens ?? 0;
1254
- const cacheWrite = usage.cache_creation_input_tokens ?? 0;
1255
- const cacheRead = usage.cache_read_input_tokens ?? 0;
1256
- return {
1257
- inputTokens: {
1258
- total: inputTokens + cacheWrite + cacheRead,
1259
- noCache: inputTokens,
1260
- cacheRead,
1261
- cacheWrite
1262
- },
1263
- outputTokens: {
1264
- total: outputTokens,
1265
- text: void 0,
1266
- reasoning: void 0
1267
- },
1268
- raw: usage
1269
- };
1270
- }
1271
- function createMessageInjector() {
1272
- const queue = [];
1273
- let closed = false;
1274
- let resolver = null;
1275
- const injector = {
1276
- inject(content, onResult) {
1277
- if (closed) {
1278
- onResult?.(false);
1279
- return;
1280
- }
1281
- const item = { content, onResult };
1282
- if (resolver) {
1283
- const r = resolver;
1284
- resolver = null;
1285
- r(item);
1286
- } else {
1287
- queue.push(item);
1288
- }
1289
- },
1290
- close() {
1291
- closed = true;
1292
- if (resolver && queue.length === 0) {
1293
- resolver(null);
1294
- resolver = null;
1295
- }
1296
- }
1297
- };
1298
- const getNextItem = () => {
1299
- if (queue.length > 0) {
1300
- const item = queue.shift();
1301
- if (!item) {
1302
- return Promise.resolve(null);
1303
- }
1304
- return Promise.resolve(item);
1305
- }
1306
- if (closed) {
1307
- return Promise.resolve(null);
1308
- }
1309
- return new Promise((resolve) => {
1310
- resolver = (item) => {
1311
- resolve(item);
1312
- };
1313
- });
1314
- };
1315
- const notifySessionEnded = () => {
1316
- for (const item of queue) {
1317
- item.onResult?.(false);
1318
- }
1319
- queue.length = 0;
1320
- closed = true;
1321
- if (resolver) {
1322
- resolver(null);
1323
- resolver = null;
1324
- }
1325
- };
1326
- return { injector, getNextItem, notifySessionEnded };
1327
- }
1328
- function toAsyncIterablePrompt(messagesPrompt, outputStreamEnded, sessionId, contentParts, onStreamStart) {
1329
- const content = contentParts && contentParts.length > 0 ? contentParts : [{ type: "text", text: messagesPrompt }];
1330
- const initialMsg = {
1331
- type: "user",
1332
- message: {
1333
- role: "user",
1334
- content
1335
- },
1336
- parent_tool_use_id: null,
1337
- session_id: sessionId ?? ""
1338
- };
1339
- if (!onStreamStart) {
1340
- return {
1341
- async *[Symbol.asyncIterator]() {
1342
- yield initialMsg;
1343
- await outputStreamEnded;
1344
- }
1345
- };
1346
- }
1347
- const { injector, getNextItem, notifySessionEnded } = createMessageInjector();
1348
- return {
1349
- async *[Symbol.asyncIterator]() {
1350
- yield initialMsg;
1351
- onStreamStart(injector);
1352
- let streamEnded = false;
1353
- void outputStreamEnded.then(() => {
1354
- streamEnded = true;
1355
- notifySessionEnded();
1356
- });
1357
- while (!streamEnded) {
1358
- const item = await Promise.race([getNextItem(), outputStreamEnded.then(() => null)]);
1359
- if (item === null) {
1360
- await outputStreamEnded;
1361
- break;
1362
- }
1363
- const sdkMsg = {
1364
- type: "user",
1365
- message: {
1366
- role: "user",
1367
- content: [{ type: "text", text: item.content }]
1368
- },
1369
- parent_tool_use_id: null,
1370
- session_id: sessionId ?? ""
1371
- };
1372
- yield sdkMsg;
1373
- item.onResult?.(true);
1374
- }
1375
- }
1376
- };
1377
- }
1378
- var modelMap = {
1379
- opus: "opus",
1380
- sonnet: "sonnet",
1381
- haiku: "haiku"
1382
- };
1383
- var MAX_TOOL_RESULT_SIZE = 1e4;
1384
- function truncateToolResultForStream(result, maxSize = MAX_TOOL_RESULT_SIZE) {
1385
- if (typeof result === "string") {
1386
- if (result.length <= maxSize) return result;
1387
- return result.slice(0, maxSize) + `
1388
- ...[truncated ${result.length - maxSize} chars]`;
1389
- }
1390
- if (typeof result !== "object" || result === null) return result;
1391
- if (Array.isArray(result)) {
1392
- let largestIndex = -1;
1393
- let largestSize2 = 0;
1394
- for (let i = 0; i < result.length; i++) {
1395
- const value = result[i];
1396
- if (typeof value === "string" && value.length > largestSize2) {
1397
- largestIndex = i;
1398
- largestSize2 = value.length;
1399
- }
1400
- }
1401
- if (largestIndex >= 0 && largestSize2 > maxSize) {
1402
- const truncatedValue = result[largestIndex].slice(0, maxSize) + `
1403
- ...[truncated ${largestSize2 - maxSize} chars]`;
1404
- const cloned = [...result];
1405
- cloned[largestIndex] = truncatedValue;
1406
- return cloned;
1407
- }
1408
- return result;
1409
- }
1410
- const obj = result;
1411
- let largestKey = null;
1412
- let largestSize = 0;
1413
- for (const [key, value] of Object.entries(obj)) {
1414
- if (typeof value === "string" && value.length > largestSize) {
1415
- largestKey = key;
1416
- largestSize = value.length;
1417
- }
1418
- }
1419
- if (largestKey && largestSize > maxSize) {
1420
- const truncatedValue = obj[largestKey].slice(0, maxSize) + `
1421
- ...[truncated ${largestSize - maxSize} chars]`;
1422
- return { ...obj, [largestKey]: truncatedValue };
1423
- }
1424
- return result;
1425
- }
1426
- var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1427
- specificationVersion = "v3";
1428
- defaultObjectGenerationMode = "json";
1429
- supportsImageUrls = false;
1430
- supportedUrls = {};
1431
- supportsStructuredOutputs = true;
1432
- // Fallback/magic string constants
1433
- static UNKNOWN_TOOL_NAME = "unknown-tool";
1434
- // Tool input safety limits
1435
- static MAX_TOOL_INPUT_SIZE = 1048576;
1436
- // 1MB hard limit
1437
- static MAX_TOOL_INPUT_WARN = 102400;
1438
- // 100KB warning threshold
1439
- static MAX_DELTA_CALC_SIZE = 1e4;
1440
- // 10KB delta computation threshold
1441
- // Upper bound for draining post-result messages (prompt_suggestion) so a
1442
- // lingering CLI subprocess cannot be held open indefinitely after finish.
1443
- static PROMPT_SUGGESTION_DRAIN_TIMEOUT_MS = 1e4;
1444
- modelId;
1445
- settings;
1446
- sessionId;
1447
- modelValidationWarning;
1448
- settingsValidationWarnings;
1449
- logger;
1450
- constructor(options) {
1451
- this.modelId = options.id;
1452
- this.settings = options.settings ?? {};
1453
- this.settingsValidationWarnings = options.settingsValidationWarnings ?? [];
1454
- const baseLogger = getLogger(this.settings.logger);
1455
- this.logger = createVerboseLogger(baseLogger, this.settings.verbose ?? false);
1456
- if (!this.modelId || typeof this.modelId !== "string" || this.modelId.trim() === "") {
1457
- throw new import_provider2.NoSuchModelError({
1458
- modelId: this.modelId,
1459
- modelType: "languageModel"
1460
- });
1461
- }
1462
- this.modelValidationWarning = validateModelId(this.modelId);
1463
- if (this.modelValidationWarning) {
1464
- this.logger.warn(`Claude Code Model: ${this.modelValidationWarning}`);
1465
- }
1466
- }
1467
- get provider() {
1468
- return "claude-code";
1469
- }
1470
- getModel() {
1471
- const mapped = modelMap[this.modelId];
1472
- return mapped ?? this.modelId;
1473
- }
1474
- getSanitizedSdkOptions() {
1475
- if (!this.settings.sdkOptions || typeof this.settings.sdkOptions !== "object") {
1476
- return void 0;
1477
- }
1478
- const sanitized = { ...this.settings.sdkOptions };
1479
- const blockedKeys = Array.from(SDK_OPTIONS_BLOCKLIST).filter((key) => key in sanitized);
1480
- if (blockedKeys.length > 0) {
1481
- this.logger.warn(
1482
- `[claude-code] sdkOptions includes provider-managed fields (${blockedKeys.join(
1483
- ", "
1484
- )}); these will be ignored.`
1485
- );
1486
- blockedKeys.forEach((key) => delete sanitized[key]);
1487
- }
1488
- return sanitized;
1489
- }
1490
- getEffectiveResume(sdkOptions) {
1491
- for (const candidate of [sdkOptions?.resume, this.settings.resume, this.sessionId]) {
1492
- if (typeof candidate === "string" && !isBlankResume(candidate)) {
1493
- return candidate;
1494
- }
1495
- }
1496
- return void 0;
1497
- }
1498
- /**
1499
- * Single source of truth for the CLI's `--session-id` exclusivity rule.
1500
- *
1501
- * The CLI rejects `--session-id` together with `--resume`/`--continue`
1502
- * unless `--fork-session` is also set (forkSession then names the forked
1503
- * session's own ID). This predicate captures "there IS a resume/continue
1504
- * target AND we are not forking", i.e. the case where a session id must NOT
1505
- * coexist. It is referenced by both:
1506
- * - the pre-merge forwarding guard (via its inverse), which decides whether
1507
- * to forward `settings.sessionId` onto the base options, and
1508
- * - the post-merge exclusivity drop, which removes any session id that the
1509
- * generic sdkOptions overlay (or the auto-resume turn) re-introduced.
1510
- *
1511
- * Keeping one definition guarantees both sites agree on what "conflicts with
1512
- * a session id" means. The mirror in validation.ts (construction-time)
1513
- * intentionally stays separate: it reads settings+sdkOptions, not a built
1514
- * opts object.
1515
- */
1516
- static sessionIdConflictsWithResumeOrContinue(args) {
1517
- return (args.resumePresent || args.continue) && !args.forkSession;
1518
- }
1519
- /**
1520
- * Owns ALL session-id / resume cross-option resolution on the FINAL merged
1521
- * options, in the single correct order. Called once, immediately after the
1522
- * generic sdkOptions overlay in createQueryOptions.
1523
- *
1524
- * Two concerns, in this exact order (order matters: step 1 can change whether
1525
- * step 2 sees a resume target):
1526
- *
1527
- * 1. Blank-resume restoration. The overlay copies the raw `sdkOptions.resume`
1528
- * verbatim, which can re-introduce a blank/whitespace value over the
1529
- * base `resume` that getEffectiveResume already normalized. The SDK treats
1530
- * a blank resume as absent, so a blank must NOT clobber the computed
1531
- * fallback — restore `effectiveResume` (already blank-stripped; may itself
1532
- * be undefined for a genuinely new session) rather than leaving '' or
1533
- * forcing undefined, which would erase a real settings.resume / captured
1534
- * session id.
1535
- *
1536
- * 2. Session-id exclusivity. Drop `opts.sessionId` whenever it conflicts with
1537
- * a resume/continue target (see sessionIdConflictsWithResumeOrContinue).
1538
- * This runs on the merged opts so it catches a sessionId re-added by the
1539
- * sdkOptions overlay AND the auto-resumed second turn (where resume was
1540
- * populated from the captured session id). It complements — does not
1541
- * replace — the pre-merge forwarding guard, which governs whether
1542
- * settings.sessionId was forwarded BEFORE the overlay could mutate
1543
- * forkSession/continue/resume.
1544
- */
1545
- applySessionResolution(opts, effectiveResume) {
1546
- if (isBlankResume(opts.resume)) {
1547
- opts.resume = effectiveResume;
1548
- }
1549
- if (opts.sessionId !== void 0 && _ClaudeCodeLanguageModel.sessionIdConflictsWithResumeOrContinue({
1550
- resumePresent: opts.resume !== void 0,
1551
- continue: opts.continue === true,
1552
- forkSession: opts.forkSession === true
1553
- })) {
1554
- opts.sessionId = void 0;
1555
- }
1556
- }
1557
- extractToolUses(content) {
1558
- return filterContentBlocks(content, "tool_use").map((block) => {
1559
- const { id, name, input, parent_tool_use_id } = block;
1560
- return {
1561
- id: typeof id === "string" && id.length > 0 ? id : (0, import_provider_utils.generateId)(),
1562
- name: typeof name === "string" && name.length > 0 ? name : _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME,
1563
- input,
1564
- parentToolUseId: typeof parent_tool_use_id === "string" ? parent_tool_use_id : null
1565
- };
1566
- });
1567
- }
1568
- extractToolResults(content) {
1569
- return filterContentBlocks(content, "tool_result").map((block) => {
1570
- const { tool_use_id, content: content2, is_error, name } = block;
1571
- return {
1572
- id: typeof tool_use_id === "string" && tool_use_id.length > 0 ? tool_use_id : (0, import_provider_utils.generateId)(),
1573
- name: typeof name === "string" && name.length > 0 ? name : void 0,
1574
- result: content2,
1575
- isError: Boolean(is_error)
1576
- };
1577
- });
1578
- }
1579
- extractToolErrors(content) {
1580
- return filterContentBlocks(content, "tool_error").map((block) => {
1581
- const { tool_use_id, error, name } = block;
1582
- return {
1583
- id: typeof tool_use_id === "string" && tool_use_id.length > 0 ? tool_use_id : (0, import_provider_utils.generateId)(),
1584
- name: typeof name === "string" && name.length > 0 ? name : void 0,
1585
- error
1586
- };
1587
- });
1588
- }
1589
- serializeToolInput(input) {
1590
- if (typeof input === "string") {
1591
- return this.checkInputSize(input);
1592
- }
1593
- if (input === void 0) {
1594
- return "";
1595
- }
1596
- try {
1597
- const serialized = JSON.stringify(input);
1598
- return this.checkInputSize(serialized);
1599
- } catch {
1600
- const fallback = String(input);
1601
- return this.checkInputSize(fallback);
1602
- }
1603
- }
1604
- checkInputSize(str) {
1605
- const length = str.length;
1606
- if (length > _ClaudeCodeLanguageModel.MAX_TOOL_INPUT_SIZE) {
1607
- throw new Error(
1608
- `Tool input exceeds maximum size of ${_ClaudeCodeLanguageModel.MAX_TOOL_INPUT_SIZE} bytes (got ${length} bytes). This may indicate a malformed request or an attempt to process excessively large data.`
1609
- );
1610
- }
1611
- if (length > _ClaudeCodeLanguageModel.MAX_TOOL_INPUT_WARN) {
1612
- this.logger.warn(
1613
- `[claude-code] Large tool input detected: ${length} bytes. Performance may be impacted. Consider chunking or reducing input size.`
1614
- );
1615
- }
1616
- return str;
1617
- }
1618
- normalizeToolResult(result) {
1619
- if (typeof result === "string") {
1620
- try {
1621
- return JSON.parse(result);
1622
- } catch {
1623
- return result;
1624
- }
1625
- }
1626
- if (Array.isArray(result) && result.length > 0) {
1627
- const textBlocks = result.filter(
1628
- (block) => block?.type === "text" && typeof block.text === "string"
1629
- ).map((block) => block.text);
1630
- if (textBlocks.length !== result.length) {
1631
- return result;
1632
- }
1633
- if (textBlocks.length === 1) {
1634
- try {
1635
- return JSON.parse(textBlocks[0]);
1636
- } catch {
1637
- return textBlocks[0];
1638
- }
1639
- }
1640
- const combined = textBlocks.join("\n");
1641
- try {
1642
- return JSON.parse(combined);
1643
- } catch {
1644
- return combined;
1645
- }
1646
- }
1647
- return result;
1648
- }
1649
- /**
1650
- * Builds a provider-executed `tool-call` part from an assistant `tool_use`
1651
- * block. Shared by doGenerate (content part) and doStream (stream part) so
1652
- * the two paths cannot drift in field shape.
1653
- */
1654
- buildToolCallPart(toolCallId, toolName, input, parentToolCallId) {
1655
- return {
1656
- type: "tool-call",
1657
- toolCallId,
1658
- toolName,
1659
- input,
1660
- providerExecuted: true,
1661
- dynamic: true,
1662
- // V3 field: indicates tool is provider-defined (not in user's tools map)
1663
- providerMetadata: {
1664
- "claude-code": {
1665
- // rawInput preserves the original serialized format before AI SDK normalization.
1666
- // Use this if you need the exact string sent to the Claude CLI, which may differ
1667
- // from the `input` field after AI SDK processing.
1668
- rawInput: input,
1669
- parentToolCallId: parentToolCallId ?? null
1670
- }
1671
- }
1672
- };
1673
- }
1674
- /**
1675
- * Builds a provider-executed `tool-result` part from a user-message
1676
- * `tool_result` block, applying normalization and `maxToolResultSize`
1677
- * truncation. Shared by doGenerate and doStream.
1678
- */
1679
- buildToolResultPart(toolCallId, toolName, result, isError, parentToolCallId) {
1680
- const normalizedResult = this.normalizeToolResult(result);
1681
- const rawResult = typeof result === "string" ? result : result === void 0 ? (
1682
- // tool_result blocks may omit `content` entirely; '' keeps both
1683
- // `result` (NonNullable<JSONValue>) and rawResult (JSONValue) valid.
1684
- ""
1685
- ) : (() => {
1686
- try {
1687
- return JSON.stringify(result) ?? String(result);
1688
- } catch {
1689
- return String(result);
1690
- }
1691
- })();
1692
- const maxToolResultSize = this.settings.maxToolResultSize;
1693
- const truncatedResult = truncateToolResultForStream(normalizedResult, maxToolResultSize);
1694
- const truncatedRawResult = truncateToolResultForStream(rawResult, maxToolResultSize);
1695
- const rawResultTruncated = truncatedRawResult !== rawResult;
1696
- return {
1697
- type: "tool-result",
1698
- toolCallId,
1699
- toolName,
1700
- // `?? ''`: absent `content` (undefined) and string results that
1701
- // normalize to JSON null (e.g. the string "null") must not violate the
1702
- // NonNullable<JSONValue> contract of LanguageModelV3ToolResult.result.
1703
- result: truncatedResult ?? "",
1704
- isError,
1705
- providerExecuted: true,
1706
- dynamic: true,
1707
- // V3 field: indicates tool is provider-defined
1708
- providerMetadata: {
1709
- "claude-code": {
1710
- // rawResult preserves the original CLI output string before JSON parsing.
1711
- // Use this when you need the exact string returned by the tool, especially
1712
- // if the `result` field has been parsed/normalized and you need the original format.
1713
- rawResult: truncatedRawResult,
1714
- rawResultTruncated,
1715
- parentToolCallId: parentToolCallId ?? null
1716
- }
1717
- }
1718
- };
1719
- }
1720
- serializeToolError(error) {
1721
- return typeof error === "string" ? error : typeof error === "object" && error !== null ? (() => {
1722
- try {
1723
- return JSON.stringify(error) ?? String(error);
1724
- } catch {
1725
- return String(error);
1726
- }
1727
- })() : String(error);
1728
- }
1729
- /**
1730
- * Builds a provider-executed `tool-error` STREAM part from a user-message
1731
- * `tool_error` block (doStream only; AI SDK core handles tool-error stream
1732
- * parts natively).
1733
- */
1734
- buildToolErrorPart(toolCallId, toolName, error, parentToolCallId) {
1735
- const rawError = this.serializeToolError(error);
1736
- return {
1737
- type: "tool-error",
1738
- toolCallId,
1739
- toolName,
1740
- error: rawError,
1741
- providerExecuted: true,
1742
- dynamic: true,
1743
- // V3 field: indicates tool is provider-defined
1744
- providerMetadata: {
1745
- "claude-code": {
1746
- rawError,
1747
- parentToolCallId: parentToolCallId ?? null
1748
- }
1749
- }
1750
- };
1751
- }
1752
- /**
1753
- * Builds a V3 `tool-result` CONTENT part with `isError: true` from a
1754
- * user-message `tool_error` block (doGenerate only). The V3 content union
1755
- * has no `tool-error` member and AI SDK core's asContent() silently drops
1756
- * unknown content part types, so an extension tool-error part would never
1757
- * reach `generateText` users — an isError tool-result, by contrast,
1758
- * round-trips into a proper tool-error part in steps content.
1759
- */
1760
- buildToolErrorResultPart(toolCallId, toolName, error, parentToolCallId) {
1761
- const rawError = this.serializeToolError(error);
1762
- return {
1763
- type: "tool-result",
1764
- toolCallId,
1765
- toolName,
1766
- result: rawError,
1767
- isError: true,
1768
- providerExecuted: true,
1769
- dynamic: true,
1770
- // V3 field: indicates tool is provider-defined
1771
- providerMetadata: {
1772
- "claude-code": {
1773
- rawError,
1774
- parentToolCallId: parentToolCallId ?? null
1775
- }
1776
- }
1777
- };
1778
- }
1779
- /**
1780
- * Policy (P3): late-frame drop guard, shared by all four tool_result/tool_error
1781
- * sites (doGenerate result+error, doStream result+error). When a frame's tool
1782
- * id is tombstoned (its tool-call was retracted by a supersede/refusal-fallback
1783
- * signal), the frame must be DROPPED rather than re-synthesized into an orphan
1784
- * tool-call. Centralizing the predicate + debug message keeps the four sites in
1785
- * lockstep so a future tombstone change can't be applied to only some of them.
1786
- */
1787
- isRetractedToolFrame(id, tombstone, frameKind) {
1788
- if (!tombstone.has(id)) {
1789
- return false;
1790
- }
1791
- this.logger.debug(
1792
- `[claude-code] Dropping tool ${frameKind} for retracted (superseded) tool ID: ${id}`
1793
- );
1794
- return true;
1795
- }
1796
- generateAllWarnings(options, prompt) {
1797
- const warnings = [];
1798
- const unsupportedParams = [];
1799
- if (options.temperature !== void 0) unsupportedParams.push("temperature");
1800
- if (options.topP !== void 0) unsupportedParams.push("topP");
1801
- if (options.topK !== void 0) unsupportedParams.push("topK");
1802
- if (options.presencePenalty !== void 0) unsupportedParams.push("presencePenalty");
1803
- if (options.frequencyPenalty !== void 0) unsupportedParams.push("frequencyPenalty");
1804
- if (options.stopSequences !== void 0 && options.stopSequences.length > 0)
1805
- unsupportedParams.push("stopSequences");
1806
- if (options.seed !== void 0) unsupportedParams.push("seed");
1807
- if (unsupportedParams.length > 0) {
1808
- for (const param of unsupportedParams) {
1809
- warnings.push({
1810
- type: "unsupported",
1811
- feature: param,
1812
- details: `Claude Code SDK does not support the ${param} parameter. It will be ignored.`
1813
- });
1814
- }
1815
- }
1816
- if (options.tools !== void 0 && options.tools.length > 0) {
1817
- warnings.push({
1818
- type: "unsupported",
1819
- feature: "tools",
1820
- details: "The Claude Code CLI executes its own tools; AI SDK tools cannot be auto-bridged at the provider layer and will be ignored. To expose custom tools to the CLI, build an in-process MCP server with the createAiSdkMcpServer helper (exported by this package) and pass it via the mcpServers setting (plus allowedTools)."
1821
- });
1822
- }
1823
- if (options.toolChoice !== void 0 && options.toolChoice.type !== "auto") {
1824
- warnings.push({
1825
- type: "unsupported",
1826
- feature: "toolChoice",
1827
- details: `Claude Code CLI does not support toolChoice '${options.toolChoice.type}'. Only automatic tool selection is available; the toolChoice parameter will be ignored.`
1828
- });
1829
- }
1830
- if (options.maxOutputTokens !== void 0) {
1831
- warnings.push({
1832
- type: "unsupported",
1833
- feature: "maxOutputTokens",
1834
- details: "Claude Code CLI does not accept an output token cap. The maxOutputTokens parameter will be ignored."
1835
- });
1836
- }
1837
- if (this.modelValidationWarning) {
1838
- warnings.push({
1839
- type: "other",
1840
- message: this.modelValidationWarning
1841
- });
1842
- }
1843
- this.settingsValidationWarnings.forEach((warning) => {
1844
- warnings.push({
1845
- type: "other",
1846
- message: warning
1847
- });
1848
- });
1849
- if (options.responseFormat?.type === "json" && !options.responseFormat.schema) {
1850
- warnings.push({
1851
- type: "unsupported",
1852
- feature: "responseFormat",
1853
- details: "JSON response format requires a schema for the Claude Code provider. The JSON responseFormat is ignored and the call is treated as plain text."
1854
- });
1855
- }
1856
- const promptWarning = validatePrompt(prompt);
1857
- if (promptWarning) {
1858
- warnings.push({
1859
- type: "other",
1860
- message: promptWarning
1861
- });
1862
- }
1863
- return warnings;
1864
- }
1865
- createQueryOptions(abortController, responseFormat, stderrCollector, sdkOptions, effectiveResume) {
1866
- const opts = {
1867
- model: this.getModel(),
1868
- abortController,
1869
- resume: effectiveResume,
1870
- pathToClaudeCodeExecutable: this.settings.pathToClaudeCodeExecutable,
1871
- maxTurns: this.settings.maxTurns,
1872
- maxThinkingTokens: this.settings.maxThinkingTokens,
1873
- thinking: this.settings.thinking,
1874
- effort: this.settings.effort,
1875
- promptSuggestions: this.settings.promptSuggestions,
1876
- cwd: this.settings.cwd,
1877
- executable: this.settings.executable,
1878
- executableArgs: this.settings.executableArgs,
1879
- permissionMode: this.settings.permissionMode,
1880
- permissionPromptToolName: this.settings.permissionPromptToolName,
1881
- continue: this.settings.continue,
1882
- allowedTools: this.settings.allowedTools,
1883
- disallowedTools: this.settings.disallowedTools,
1884
- betas: this.settings.betas,
1885
- allowDangerouslySkipPermissions: this.settings.allowDangerouslySkipPermissions,
1886
- enableFileCheckpointing: this.settings.enableFileCheckpointing,
1887
- maxBudgetUsd: this.settings.maxBudgetUsd,
1888
- plugins: this.settings.plugins,
1889
- resumeSessionAt: this.settings.resumeSessionAt,
1890
- sandbox: this.settings.sandbox,
1891
- tools: this.settings.tools,
1892
- mcpServers: this.settings.mcpServers,
1893
- canUseTool: this.settings.canUseTool
1894
- };
1895
- if (this.settings.onUserDialog !== void 0) {
1896
- opts.onUserDialog = this.settings.onUserDialog;
1897
- }
1898
- if (this.settings.supportedDialogKinds !== void 0) {
1899
- opts.supportedDialogKinds = this.settings.supportedDialogKinds;
1900
- }
1901
- if (this.settings.systemPrompt !== void 0) {
1902
- opts.systemPrompt = this.settings.systemPrompt;
1903
- } else if (this.settings.customSystemPrompt !== void 0) {
1904
- this.logger.warn(
1905
- "[claude-code] 'customSystemPrompt' is deprecated and will be removed in a future major release. Please use 'systemPrompt' instead (string or { type: 'preset', preset: 'claude_code', append? })."
1906
- );
1907
- opts.systemPrompt = this.settings.customSystemPrompt;
1908
- } else if (this.settings.appendSystemPrompt !== void 0) {
1909
- this.logger.warn(
1910
- "[claude-code] 'appendSystemPrompt' is deprecated and will be removed in a future major release. Please use 'systemPrompt: { type: 'preset', preset: 'claude_code', append: <text> }' instead."
1911
- );
1912
- opts.systemPrompt = {
1913
- type: "preset",
1914
- preset: "claude_code",
1915
- append: this.settings.appendSystemPrompt
1916
- };
1917
- }
1918
- if (this.settings.settingSources !== void 0) {
1919
- opts.settingSources = this.settings.settingSources;
1920
- } else {
1921
- opts.settingSources = [];
1922
- }
1923
- if (this.settings.additionalDirectories !== void 0) {
1924
- opts.additionalDirectories = this.settings.additionalDirectories;
1925
- }
1926
- if (this.settings.agents !== void 0) {
1927
- opts.agents = this.settings.agents;
1928
- }
1929
- if (this.settings.skills !== void 0) {
1930
- opts.skills = this.settings.skills;
1931
- }
1932
- if (this.settings.settings !== void 0) {
1933
- opts.settings = this.settings.settings;
1934
- }
1935
- if (this.settings.managedSettings !== void 0) {
1936
- opts.managedSettings = this.settings.managedSettings;
1937
- }
1938
- if (this.settings.toolAliases !== void 0) {
1939
- opts.toolAliases = this.settings.toolAliases;
1940
- }
1941
- if (this.settings.toolConfig !== void 0) {
1942
- opts.toolConfig = this.settings.toolConfig;
1943
- }
1944
- if (this.settings.planModeInstructions !== void 0) {
1945
- opts.planModeInstructions = this.settings.planModeInstructions;
1946
- }
1947
- if (this.settings.title !== void 0) {
1948
- opts.title = this.settings.title;
1949
- }
1950
- if (this.settings.forwardSubagentText !== void 0) {
1951
- opts.forwardSubagentText = this.settings.forwardSubagentText;
1952
- }
1953
- if (this.settings.agentProgressSummaries !== void 0) {
1954
- opts.agentProgressSummaries = this.settings.agentProgressSummaries;
1955
- }
1956
- if (this.settings.includeHookEvents !== void 0) {
1957
- opts.includeHookEvents = this.settings.includeHookEvents;
1958
- }
1959
- if (this.settings.taskBudget !== void 0) {
1960
- opts.taskBudget = this.settings.taskBudget;
1961
- }
1962
- if (this.settings.sessionStore !== void 0) {
1963
- opts.sessionStore = this.settings.sessionStore;
1964
- }
1965
- if (this.settings.sessionStoreFlush !== void 0) {
1966
- opts.sessionStoreFlush = this.settings.sessionStoreFlush;
1967
- }
1968
- if (this.settings.loadTimeoutMs !== void 0) {
1969
- opts.loadTimeoutMs = this.settings.loadTimeoutMs;
1970
- }
1971
- if (this.settings.includePartialMessages !== void 0) {
1972
- opts.includePartialMessages = this.settings.includePartialMessages;
1973
- }
1974
- if (this.settings.fallbackModel !== void 0) {
1975
- opts.fallbackModel = this.settings.fallbackModel;
1976
- }
1977
- if (this.settings.forkSession !== void 0) {
1978
- opts.forkSession = this.settings.forkSession;
1979
- }
1980
- if (this.settings.strictMcpConfig !== void 0) {
1981
- opts.strictMcpConfig = this.settings.strictMcpConfig;
1982
- }
1983
- if (this.settings.extraArgs !== void 0) {
1984
- opts.extraArgs = this.settings.extraArgs;
1985
- }
1986
- if (this.settings.persistSession !== void 0) {
1987
- opts.persistSession = this.settings.persistSession;
1988
- }
1989
- if (this.settings.spawnClaudeCodeProcess !== void 0) {
1990
- opts.spawnClaudeCodeProcess = this.settings.spawnClaudeCodeProcess;
1991
- }
1992
- if (this.settings.hooks) {
1993
- opts.hooks = this.settings.hooks;
1994
- }
1995
- const effectiveForkSession = sdkOptions?.forkSession ?? this.settings.forkSession;
1996
- const effectiveContinue = sdkOptions?.continue ?? this.settings.continue;
1997
- if (this.settings.sessionId !== void 0 && !_ClaudeCodeLanguageModel.sessionIdConflictsWithResumeOrContinue({
1998
- resumePresent: opts.resume !== void 0,
1999
- continue: effectiveContinue === true,
2000
- forkSession: effectiveForkSession === true
2001
- })) {
2002
- opts.sessionId = this.settings.sessionId;
2003
- }
2004
- if (this.settings.debug !== void 0) {
2005
- opts.debug = this.settings.debug;
2006
- }
2007
- if (this.settings.debugFile !== void 0) {
2008
- opts.debugFile = this.settings.debugFile;
2009
- }
2010
- const sdkOverrides = sdkOptions ? sdkOptions : void 0;
2011
- const sdkEnv = sdkOverrides && typeof sdkOverrides.env === "object" && sdkOverrides.env !== null ? sdkOverrides.env : void 0;
2012
- const sdkStderr = sdkOverrides && typeof sdkOverrides.stderr === "function" ? sdkOverrides.stderr : void 0;
2013
- if (sdkOverrides) {
2014
- const rest = { ...sdkOverrides };
2015
- delete rest.env;
2016
- delete rest.stderr;
2017
- for (const [key, value] of Object.entries(rest)) {
2018
- if (value !== void 0) {
2019
- opts[key] = value;
2020
- }
2021
- }
2022
- }
2023
- this.applySessionResolution(opts, effectiveResume);
2024
- if (typeof opts.fallbackModel === "string" && opts.fallbackModel === opts.model) {
2025
- throw new Error(
2026
- `fallbackModel cannot be the same as the model ('${String(opts.model)}'). Specify a different model for fallbackModel, or remove it.`
2027
- );
2028
- }
2029
- const userStderrCallback = sdkStderr ?? this.settings.stderr;
2030
- if (stderrCollector || userStderrCallback) {
2031
- opts.stderr = (data) => {
2032
- if (stderrCollector) stderrCollector(data);
2033
- if (userStderrCallback) userStderrCallback(data);
2034
- };
2035
- }
2036
- const mergedEnv = {
2037
- ...getBaseProcessEnv(),
2038
- ...this.settings.env,
2039
- ...sdkEnv
2040
- };
2041
- if (!("CLAUDE_AGENT_SDK_CLIENT_APP" in mergedEnv)) {
2042
- mergedEnv.CLAUDE_AGENT_SDK_CLIENT_APP = DEFAULT_CLIENT_APP;
2043
- }
2044
- opts.env = mergedEnv;
2045
- if (responseFormat?.type === "json" && responseFormat.schema) {
2046
- const { schema: sanitizedSchema, strippedFormatPaths } = sanitizeJsonSchemaForOutputFormat(
2047
- responseFormat.schema
2048
- );
2049
- if (strippedFormatPaths.length > 0) {
2050
- this.logger.debug(
2051
- `[claude-code] Stripped unsupported 'format' keywords from outputFormat schema (hints folded into descriptions; client-side Zod validation still enforces them) at: ${strippedFormatPaths.join(", ")}`
2052
- );
2053
- }
2054
- opts.outputFormat = {
2055
- type: "json_schema",
2056
- schema: sanitizedSchema
2057
- };
2058
- }
2059
- return opts;
2060
- }
2061
- handleClaudeCodeError(error, messagesPrompt, collectedStderr) {
2062
- if (error instanceof import_provider2.APICallError || error instanceof import_provider2.LoadAPIKeyError) {
2063
- return error;
2064
- }
2065
- const rawSdkStderr = typeof error === "object" && error !== null && "stderr" in error && typeof error.stderr === "string" ? error.stderr : void 0;
2066
- const cappedSdkStderr = rawSdkStderr !== void 0 ? capStderr(rawSdkStderr) : void 0;
2067
- const selectedStderr = cappedSdkStderr !== void 0 && stderrTail(cappedSdkStderr) ? cappedSdkStderr : collectedStderr ? capStderr(collectedStderr) : void 0;
2068
- const stderr = selectedStderr || void 0;
2069
- const tail = stderr ? stderrTail(stderr) : "";
2070
- const appendStderrTail = (message) => tail && !message.includes(STDERR_TAIL_MARKER) ? `${message}${STDERR_TAIL_MARKER} ${tail}` : message;
2071
- if (isAbortError(error)) {
2072
- throw error;
2073
- }
2074
- const isErrorWithMessage = (err) => {
2075
- return typeof err === "object" && err !== null && "message" in err;
2076
- };
2077
- const isErrorWithCode = (err) => {
2078
- return typeof err === "object" && err !== null;
2079
- };
2080
- const authErrorPatterns = [
2081
- "not logged in",
2082
- "authentication",
2083
- "unauthorized",
2084
- "auth failed",
2085
- "please login",
2086
- "claude login",
2087
- "claude auth login",
2088
- "/login",
2089
- // CLI returns "Please run /login"
2090
- "invalid api key",
2091
- "oauth_org_not_allowed"
2092
- // SDK 0.3.x assistant error kind: OAuth org not permitted
2093
- ];
2094
- const stderrAuthPatterns = [
2095
- "not logged in",
2096
- "not authenticated",
2097
- "auth failed",
2098
- "please login",
2099
- "please run /login",
2100
- "claude login",
2101
- "claude auth login",
2102
- "invalid api key",
2103
- "oauth token revoked",
2104
- "oauth_org_not_allowed"
2105
- ];
2106
- const errorMessage = isErrorWithMessage(error) && error.message ? error.message.toLowerCase() : "";
2107
- const stderrMessage = stderr?.toLowerCase() ?? "";
2108
- const errorKind = getStructuredErrorKind(error);
2109
- const exitCode = isErrorWithCode(error) && typeof error.exitCode === "number" ? error.exitCode : void 0;
2110
- const isAuthError = errorKind === "authentication_failed" || errorKind === "oauth_org_not_allowed" || authErrorPatterns.some((pattern) => errorMessage.includes(pattern)) || stderrAuthPatterns.some((pattern) => stderrMessage.includes(pattern)) || exitCode === 401;
2111
- if (isAuthError) {
2112
- return createAuthenticationError({
2113
- message: appendStderrTail(
2114
- isErrorWithMessage(error) && error.message ? error.message : "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
2115
- ),
2116
- stderr
2117
- });
2118
- }
2119
- const errorCode = isErrorWithCode(error) && typeof error.code === "string" ? error.code : "";
2120
- if (errorCode === "ETIMEDOUT" || errorMessage.includes("timeout") || /request timed out|etimedout/i.test(stderr ?? "")) {
2121
- return createTimeoutError({
2122
- message: appendStderrTail(
2123
- isErrorWithMessage(error) && error.message ? error.message : "Request timed out"
2124
- ),
2125
- stderr,
2126
- promptExcerpt: messagesPrompt.substring(0, 200)
2127
- // Don't specify timeoutMs since we don't know the actual timeout value
2128
- // It's controlled by the consumer via AbortSignal
2129
- });
2130
- }
2131
- if (errorKind === "overloaded" || errorKind === "rate_limit" || errorMessage.includes("overloaded")) {
2132
- return createAPICallError({
2133
- message: isErrorWithMessage(error) && error.message ? error.message : "Anthropic API is overloaded. Please retry.",
2134
- code: errorCode || void 0,
2135
- exitCode,
2136
- stderr,
2137
- promptExcerpt: messagesPrompt.substring(0, 200),
2138
- isRetryable: true
2139
- });
2140
- }
2141
- if (errorKind === "model_not_found" || errorMessage.includes("model_not_found") || errorMessage.includes("no such model")) {
2142
- const originalMessage = isErrorWithMessage(error) && error.message ? error.message : "Model not found";
2143
- return createAPICallError({
2144
- 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.`,
2145
- code: errorCode || void 0,
2146
- exitCode,
2147
- stderr,
2148
- promptExcerpt: messagesPrompt.substring(0, 200),
2149
- isRetryable: false
2150
- });
2151
- }
2152
- const isRetryable = errorCode === "ENOENT" || errorCode === "ECONNREFUSED" || errorCode === "ETIMEDOUT" || errorCode === "ECONNRESET";
2153
- return createAPICallError({
2154
- message: isErrorWithMessage(error) && error.message ? error.message : "Claude Code SDK error",
2155
- code: errorCode || void 0,
2156
- exitCode,
2157
- stderr,
2158
- promptExcerpt: messagesPrompt.substring(0, 200),
2159
- isRetryable
2160
- });
2161
- }
2162
- setSessionId(sessionId) {
2163
- this.sessionId = sessionId;
2164
- const warning = validateSessionId(sessionId);
2165
- if (warning) {
2166
- this.logger.warn(`Claude Code Session: ${warning}`);
2167
- }
2168
- }
2169
- logMcpConnectionIssues(mcpServers) {
2170
- if (!Array.isArray(mcpServers) || mcpServers.length === 0) {
2171
- return;
2172
- }
2173
- const serversNeedingAttention = mcpServers.filter((server) => {
2174
- const status = typeof server.status === "string" ? server.status.toLowerCase() : "";
2175
- return status === "failed" || status === "needs-auth";
2176
- });
2177
- if (serversNeedingAttention.length === 0) {
2178
- return;
2179
- }
2180
- const details = serversNeedingAttention.map((server) => {
2181
- const name = typeof server.name === "string" && server.name.trim().length > 0 ? server.name : "<unknown>";
2182
- const status = typeof server.status === "string" && server.status.trim().length > 0 ? server.status : "unknown";
2183
- const error = typeof server.error === "string" && server.error.trim().length > 0 ? ` (${server.error})` : "";
2184
- return `${name}:${status}${error}`;
2185
- }).join(", ");
2186
- this.logger.warn(`[claude-code] MCP servers not connected: ${details}`);
2187
- }
2188
- /**
2189
- * Handles SDK 0.3.x system messages other than 'init', shared by doGenerate
2190
- * and doStream:
2191
- * - 'api_retry' is counted into providerMetadata (`apiRetries`) and debug-logged.
2192
- * - 'permission_denied' is warn-logged and recorded into providerMetadata
2193
- * (`permissionDenials`); without this a denial is invisible until the
2194
- * model talks about it.
2195
- * - 'model_refusal_fallback' is debug-logged (the superseding assistant
2196
- * message is handled by the text-dedup guard in the message loops).
2197
- * - 'thinking_tokens' deltas are accumulated into providerMetadata
2198
- * (`estimatedThinkingTokens`); the estimate is explicitly not the
2199
- * authoritative billed output tokens, so it is surfaced as metadata
2200
- * instead of feeding `usage.outputTokens.reasoning`.
2201
- * - The subtypes in {@link INFORMATIONAL_SYSTEM_SUBTYPES} are intentionally
2202
- * informational and only debug-logged.
2203
- */
2204
- handleSystemMessage(message, tracking, onRetractedUuids) {
2205
- switch (message.subtype) {
2206
- case "api_retry":
2207
- tracking.apiRetries += 1;
2208
- this.logger.debug(
2209
- `[claude-code] API retry ${message.attempt}/${message.max_retries} in ${message.retry_delay_ms}ms - Status: ${message.error_status ?? "unknown"}, Error: ${message.error}`
2210
- );
2211
- break;
2212
- case "permission_denied": {
2213
- const reason = message.decision_reason ?? message.message;
2214
- tracking.permissionDenials.push({
2215
- toolName: message.tool_name,
2216
- toolUseId: message.tool_use_id,
2217
- ...reason !== void 0 && { reason }
2218
- });
2219
- this.logger.warn(
2220
- `[claude-code] Permission denied - Tool: ${message.tool_name}${reason ? `, Reason: ${reason}` : ""}`
2221
- );
2222
- break;
2223
- }
2224
- case "mirror_error": {
2225
- const mirrorError = message.error ?? "unknown error";
2226
- const mirrorSessionId = message.key?.sessionId ?? message.session_id ?? "unknown";
2227
- tracking.mirrorErrors.push({ error: mirrorError, sessionId: mirrorSessionId });
2228
- this.logger.warn(
2229
- `[claude-code] SessionStore mirror error (transcript batch dropped) - Session: ${mirrorSessionId}, Error: ${mirrorError}`
2230
- );
2231
- break;
2232
- }
2233
- case "model_refusal_fallback": {
2234
- this.logger.debug(
2235
- `[claude-code] Model refusal fallback - ${message.original_model} -> ${message.fallback_model} (direction: ${message.direction})`
2236
- );
2237
- const retractedUuids = message.retracted_message_uuids;
2238
- if (onRetractedUuids && retractedUuids && retractedUuids.length > 0) {
2239
- this.logger.debug(
2240
- `[claude-code] Refusal fallback retracts ${retractedUuids.length} message uuid(s)`
2241
- );
2242
- onRetractedUuids(retractedUuids);
2243
- }
2244
- break;
2245
- }
2246
- case "thinking_tokens":
2247
- tracking.estimatedThinkingTokens += message.estimated_tokens_delta;
2248
- this.logger.debug(
2249
- `[claude-code] Thinking tokens estimate - block total: ${message.estimated_tokens}, delta: ${message.estimated_tokens_delta}, accumulated: ${tracking.estimatedThinkingTokens}`
2250
- );
2251
- break;
2252
- default:
2253
- if (INFORMATIONAL_SYSTEM_SUBTYPES.has(message.subtype)) {
2254
- this.logger.debug(
2255
- `[claude-code] Ignoring informational system message: ${message.subtype}`
2256
- );
2257
- } else {
2258
- this.logger.debug(`[claude-code] Unhandled system message subtype: ${message.subtype}`);
2259
- }
2260
- break;
2261
- }
2262
- }
2263
- /**
2264
- * Merges the result message's `permission_denials` list into the tracked
2265
- * denials. PreToolUse-hook denies bypass canUseTool and emit no
2266
- * `permission_denied` system event (per the SDK docs on
2267
- * SDKPermissionDeniedMessage), so the result list is the only place they
2268
- * surface. Entries already recorded from stream-time events are deduped by
2269
- * `tool_use_id`.
2270
- */
2271
- mergeResultPermissionDenials(message, tracking) {
2272
- for (const denial of message.permission_denials ?? []) {
2273
- const alreadyTracked = tracking.permissionDenials.some(
2274
- (d) => d.toolUseId !== void 0 && d.toolUseId === denial.tool_use_id
2275
- );
2276
- if (!alreadyTracked) {
2277
- tracking.permissionDenials.push({
2278
- toolName: denial.tool_name,
2279
- toolUseId: denial.tool_use_id
2280
- });
2281
- }
2282
- }
2283
- }
2284
- /**
2285
- * Bounded post-result drain for the `prompt_suggestion` message
2286
- * (promptSuggestions: true), shared by doGenerate and doStream. The
2287
- * suggestion arrives AFTER the result message; the SDK emits at most one
2288
- * per turn, so stop once it is delivered, and a timeout closes the
2289
- * iterator (tearing down the subprocess) if the CLI lingers after the
2290
- * result without emitting one. Advances the response's own generator, so
2291
- * the caller's surrounding loop resumes to a finished iterator.
2292
- */
2293
- async drainPromptSuggestion(response, onPromptSuggestion) {
2294
- const iterator = response[Symbol.asyncIterator]();
2295
- let drainTimer;
2296
- const drainTimeout = new Promise((resolve) => {
2297
- drainTimer = setTimeout(
2298
- () => resolve("timeout"),
2299
- _ClaudeCodeLanguageModel.PROMPT_SUGGESTION_DRAIN_TIMEOUT_MS
2300
- );
2301
- drainTimer.unref?.();
2302
- });
2303
- try {
2304
- while (true) {
2305
- const winner = await Promise.race([iterator.next(), drainTimeout]);
2306
- if (winner === "timeout") {
2307
- this.logger.debug("[claude-code] Post-result drain timed out; closing SDK iterator");
2308
- void iterator.return?.().catch(() => {
2309
- });
2310
- break;
2311
- }
2312
- if (winner.done) {
2313
- break;
2314
- }
2315
- const trailingMessage = winner.value;
2316
- this.logger.debug(`[claude-code] Post-result message type: ${trailingMessage.type}`);
2317
- if (trailingMessage.type === "prompt_suggestion") {
2318
- onPromptSuggestion(trailingMessage.suggestion);
2319
- void iterator.return?.().catch(() => {
2320
- });
2321
- break;
2322
- }
2323
- }
2324
- } catch (drainError) {
2325
- this.logger.debug(
2326
- `[claude-code] Error draining post-result messages: ${drainError instanceof Error ? drainError.message : String(drainError)}`
2327
- );
2328
- } finally {
2329
- if (drainTimer !== void 0) {
2330
- clearTimeout(drainTimer);
2331
- }
2332
- }
2333
- }
2334
- async doGenerate(options) {
2335
- this.logger.debug(`[claude-code] Starting doGenerate request with model: ${this.modelId}`);
2336
- this.logger.debug(`[claude-code] Response format: ${options.responseFormat?.type ?? "none"}`);
2337
- const {
2338
- messagesPrompt,
2339
- warnings: messageWarnings,
2340
- streamingContentParts,
2341
- hasImageParts
2342
- } = convertToClaudeCodeMessages(options.prompt);
2343
- this.logger.debug(
2344
- `[claude-code] Converted ${options.prompt.length} messages, hasImageParts: ${hasImageParts}`
2345
- );
2346
- const abortController = new AbortController();
2347
- let abortListener;
2348
- if (options.abortSignal?.aborted) {
2349
- abortController.abort(options.abortSignal.reason);
2350
- }
2351
- let collectedStderr = "";
2352
- const stderrCollector = (data) => {
2353
- collectedStderr += data;
2354
- collectedStderr = capStderr(collectedStderr);
2355
- };
2356
- const sdkOptions = this.getSanitizedSdkOptions();
2357
- const effectiveResume = this.getEffectiveResume(sdkOptions);
2358
- const queryOptions = this.createQueryOptions(
2359
- abortController,
2360
- options.responseFormat,
2361
- stderrCollector,
2362
- sdkOptions,
2363
- effectiveResume
2364
- );
2365
- if (options.abortSignal && !options.abortSignal.aborted) {
2366
- abortListener = () => abortController.abort(options.abortSignal?.reason);
2367
- options.abortSignal.addEventListener("abort", abortListener, { once: true });
2368
- }
2369
- let text = "";
2370
- const contentSegments = [];
2371
- const joinTextSegments = () => contentSegments.filter((segment) => segment.kind === "text").map((segment) => segment.text).join("");
2372
- const joinFinalTurnTextSegments = () => {
2373
- let start = 0;
2374
- for (let i = 0; i < contentSegments.length; i++) {
2375
- const kind = contentSegments[i]?.kind;
2376
- if (kind === "tool-result" || kind === "tool-error") {
2377
- start = i + 1;
2378
- }
2379
- }
2380
- return contentSegments.slice(start).filter((segment) => segment.kind === "text").map((segment) => segment.text).join("");
2381
- };
2382
- const knownTools = /* @__PURE__ */ new Map();
2383
- const retractedToolIds = /* @__PURE__ */ new Set();
2384
- const evictBuffered = (retracted) => {
2385
- if (retracted.size === 0) return;
2386
- const retractedToolCallIds = computeRetractedToolCallIds(
2387
- retracted,
2388
- contentSegments.filter(
2389
- (segment) => segment.kind === "tool-call" || segment.kind === "tool-result" || segment.kind === "tool-error"
2390
- ).map((segment) => ({
2391
- toolCallId: segment.toolCallId,
2392
- uuid: segment.uuid
2393
- }))
2394
- );
2395
- for (const toolCallId of retractedToolCallIds) {
2396
- retractedToolIds.add(toolCallId);
2397
- knownTools.delete(toolCallId);
2398
- activeTaskTools.delete(toolCallId);
2399
- }
2400
- for (let i = contentSegments.length - 1; i >= 0; i--) {
2401
- const segment = contentSegments[i];
2402
- if (segment === void 0) continue;
2403
- const segmentUuid = "uuid" in segment ? segment.uuid : void 0;
2404
- const retractsSegment = segmentUuid !== void 0 && retracted.has(segmentUuid) || (segment.kind === "tool-result" || segment.kind === "tool-error") && retractedToolCallIds.has(segment.toolCallId);
2405
- if (retractsSegment) {
2406
- contentSegments.splice(i, 1);
2407
- }
2408
- }
2409
- };
2410
- const activeTaskTools = /* @__PURE__ */ new Map();
2411
- const getFallbackParentId = () => {
2412
- if (activeTaskTools.size === 1) {
2413
- return activeTaskTools.keys().next().value ?? null;
2414
- }
2415
- return null;
2416
- };
2417
- let structuredOutput;
2418
- let receivedResultMessage = false;
2419
- let usage = createEmptyUsage();
2420
- let finishReason = { unified: "stop", raw: void 0 };
2421
- let wasTruncated = false;
2422
- let costUsd;
2423
- let durationMs;
2424
- let modelUsage;
2425
- let ttftMs;
2426
- let ttftStreamMs;
2427
- let timeToRequestMs;
2428
- let warmSpareClaimed;
2429
- let terminalReason;
2430
- const metadataTracking = {
2431
- apiRetries: 0,
2432
- permissionDenials: [],
2433
- mirrorErrors: [],
2434
- estimatedThinkingTokens: 0
2435
- };
2436
- const warnings = this.generateAllWarnings(options, messagesPrompt);
2437
- if (messageWarnings) {
2438
- messageWarnings.forEach((warning) => {
2439
- warnings.push({
2440
- type: "other",
2441
- message: warning
2442
- });
2443
- });
2444
- }
2445
- const modeSetting = this.settings.streamingInput ?? "auto";
2446
- const effectiveCanUseTool = sdkOptions?.canUseTool ?? this.settings.canUseTool;
2447
- const effectivePermissionPromptToolName = sdkOptions?.permissionPromptToolName ?? this.settings.permissionPromptToolName;
2448
- const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!effectiveCanUseTool;
2449
- if (!wantsStreamInput && hasImageParts) {
2450
- warnings.push({
2451
- type: "other",
2452
- message: STREAMING_FEATURE_WARNING
2453
- });
2454
- }
2455
- let done = () => {
2456
- };
2457
- const outputStreamEnded = new Promise((resolve) => {
2458
- done = () => resolve(void 0);
2459
- });
2460
- try {
2461
- if (effectiveCanUseTool && effectivePermissionPromptToolName) {
2462
- throw new Error(
2463
- "canUseTool requires streamingInput mode ('auto' or 'always') and cannot be used with permissionPromptToolName (SDK constraint). Set streamingInput: 'auto' (or 'always') and remove permissionPromptToolName, or remove canUseTool."
2464
- );
2465
- }
2466
- const sdkPrompt = wantsStreamInput ? toAsyncIterablePrompt(
2467
- messagesPrompt,
2468
- outputStreamEnded,
2469
- effectiveResume,
2470
- streamingContentParts,
2471
- this.settings.onStreamStart
2472
- ) : messagesPrompt;
2473
- this.logger.debug(
2474
- `[claude-code] Executing query with streamingInput: ${wantsStreamInput}, session: ${effectiveResume ?? "new"}`
2475
- );
2476
- const response = (0, import_claude_agent_sdk.query)({
2477
- prompt: sdkPrompt,
2478
- options: queryOptions
2479
- });
2480
- this.settings.onQueryCreated?.(response);
2481
- let lastAssistantErrorKind;
2482
- const sdkIterator = response[Symbol.asyncIterator]();
2483
- const detachableResponse = {
2484
- [Symbol.asyncIterator]: () => ({
2485
- next: () => sdkIterator.next(),
2486
- return: () => {
2487
- void sdkIterator.return?.().catch(() => {
2488
- });
2489
- return Promise.resolve({ done: true, value: void 0 });
2490
- }
2491
- })
2492
- };
2493
- for await (const message of detachableResponse) {
2494
- this.logger.debug(`[claude-code] Received message type: ${message.type}`);
2495
- if (message.type === "assistant") {
2496
- if (typeof message.error === "string") {
2497
- lastAssistantErrorKind = message.error;
2498
- }
2499
- applySupersede(message, evictBuffered, this.logger, "truthy");
2500
- const messageUuid = typeof message.uuid === "string" ? message.uuid : void 0;
2501
- const sdkParentToolUseId = message.parent_tool_use_id;
2502
- const content = message.message.content;
2503
- if (Array.isArray(content)) {
2504
- for (const block of content) {
2505
- if (!isContentBlock(block)) continue;
2506
- if (block.type === "text" && typeof block.text === "string") {
2507
- if (block.text.length > 0) {
2508
- contentSegments.push({
2509
- kind: "text",
2510
- ...messageUuid !== void 0 && { uuid: messageUuid },
2511
- text: block.text
2512
- });
2513
- }
2514
- } else if (block.type === "thinking" && typeof block.thinking === "string") {
2515
- contentSegments.push({
2516
- kind: "reasoning",
2517
- ...messageUuid !== void 0 && { uuid: messageUuid },
2518
- text: block.thinking
2519
- });
2520
- } else if (block.type === "tool_use") {
2521
- const [tool3] = this.extractToolUses([block]);
2522
- if (!tool3) continue;
2523
- const parentToolCallId = isSubagentToolName(tool3.name) ? null : resolveToolParentId(
2524
- sdkParentToolUseId,
2525
- tool3.parentToolUseId,
2526
- getFallbackParentId
2527
- );
2528
- this.logger.debug(
2529
- `[claude-code] Tool use detected - Tool: ${tool3.name}, ID: ${tool3.id}, SDK parent: ${sdkParentToolUseId}, resolved parent: ${parentToolCallId}`
2530
- );
2531
- knownTools.set(tool3.id, { name: tool3.name, parentToolCallId });
2532
- if (isSubagentToolName(tool3.name)) {
2533
- activeTaskTools.set(tool3.id, { startTime: Date.now() });
2534
- }
2535
- contentSegments.push({
2536
- kind: "tool-call",
2537
- ...messageUuid !== void 0 && { uuid: messageUuid },
2538
- toolCallId: tool3.id,
2539
- part: this.buildToolCallPart(
2540
- tool3.id,
2541
- tool3.name,
2542
- this.serializeToolInput(tool3.input),
2543
- parentToolCallId
2544
- )
2545
- });
2546
- }
2547
- }
2548
- }
2549
- text = joinTextSegments();
2550
- } else if (message.type === "user") {
2551
- if (!message.message?.content) {
2552
- this.logger.warn(
2553
- `[claude-code] Unexpected user message structure: missing content field. Message type: ${message.type}. This may indicate an SDK protocol violation.`
2554
- );
2555
- continue;
2556
- }
2557
- const sdkParentToolUseIdForResults = message.parent_tool_use_id;
2558
- const resultMessageUuid = typeof message.uuid === "string" ? message.uuid : void 0;
2559
- const content = message.message.content;
2560
- for (const result of this.extractToolResults(content)) {
2561
- if (this.isRetractedToolFrame(result.id, retractedToolIds, "result")) {
2562
- continue;
2563
- }
2564
- const known = knownTools.get(result.id);
2565
- const toolName = result.name ?? known?.name ?? _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
2566
- this.logger.debug(
2567
- `[claude-code] Tool result received - Tool: ${toolName}, ID: ${result.id}`
2568
- );
2569
- let parentToolCallId;
2570
- if (known) {
2571
- known.name = toolName;
2572
- parentToolCallId = known.parentToolCallId;
2573
- } else {
2574
- this.logger.warn(
2575
- `[claude-code] Received tool result for unknown tool ID: ${result.id}`
2576
- );
2577
- parentToolCallId = isSubagentToolName(toolName) ? null : resolveToolParentId(sdkParentToolUseIdForResults, void 0, getFallbackParentId);
2578
- knownTools.set(result.id, { name: toolName, parentToolCallId });
2579
- contentSegments.push({
2580
- kind: "tool-call",
2581
- toolCallId: result.id,
2582
- part: this.buildToolCallPart(result.id, toolName, "", parentToolCallId)
2583
- });
2584
- }
2585
- if (isSubagentToolName(toolName)) {
2586
- activeTaskTools.delete(result.id);
2587
- }
2588
- contentSegments.push({
2589
- kind: "tool-result",
2590
- ...resultMessageUuid !== void 0 && { uuid: resultMessageUuid },
2591
- toolCallId: result.id,
2592
- part: this.buildToolResultPart(
2593
- result.id,
2594
- toolName,
2595
- result.result,
2596
- result.isError,
2597
- parentToolCallId
2598
- )
2599
- });
2600
- }
2601
- for (const error of this.extractToolErrors(content)) {
2602
- if (this.isRetractedToolFrame(error.id, retractedToolIds, "error")) {
2603
- continue;
2604
- }
2605
- const known = knownTools.get(error.id);
2606
- const toolName = error.name ?? known?.name ?? _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
2607
- this.logger.debug(
2608
- `[claude-code] Tool error received - Tool: ${toolName}, ID: ${error.id}`
2609
- );
2610
- let parentToolCallId;
2611
- if (known) {
2612
- known.name = toolName;
2613
- parentToolCallId = known.parentToolCallId;
2614
- } else {
2615
- this.logger.warn(
2616
- `[claude-code] Received tool error for unknown tool ID: ${error.id}`
2617
- );
2618
- parentToolCallId = isSubagentToolName(toolName) ? null : resolveToolParentId(sdkParentToolUseIdForResults, void 0, getFallbackParentId);
2619
- knownTools.set(error.id, { name: toolName, parentToolCallId });
2620
- contentSegments.push({
2621
- kind: "tool-call",
2622
- toolCallId: error.id,
2623
- part: this.buildToolCallPart(error.id, toolName, "", parentToolCallId)
2624
- });
2625
- }
2626
- if (isSubagentToolName(toolName)) {
2627
- activeTaskTools.delete(error.id);
2628
- }
2629
- contentSegments.push({
2630
- kind: "tool-error",
2631
- ...resultMessageUuid !== void 0 && { uuid: resultMessageUuid },
2632
- toolCallId: error.id,
2633
- part: this.buildToolErrorResultPart(
2634
- error.id,
2635
- toolName,
2636
- error.error,
2637
- parentToolCallId
2638
- )
2639
- });
2640
- }
2641
- } else if (message.type === "result") {
2642
- done();
2643
- receivedResultMessage = true;
2644
- this.setSessionId(message.session_id);
2645
- costUsd = message.total_cost_usd;
2646
- durationMs = message.duration_ms;
2647
- modelUsage = message.modelUsage;
2648
- if ("ttft_ms" in message) {
2649
- ttftMs = message.ttft_ms;
2650
- }
2651
- if ("ttft_stream_ms" in message) {
2652
- ttftStreamMs = message.ttft_stream_ms;
2653
- }
2654
- if ("time_to_request_ms" in message) {
2655
- timeToRequestMs = message.time_to_request_ms;
2656
- }
2657
- if ("warm_spare_claimed" in message) {
2658
- warmSpareClaimed = message.warm_spare_claimed;
2659
- }
2660
- terminalReason = message.terminal_reason;
2661
- this.mergeResultPermissionDenials(message, metadataTracking);
2662
- if ("is_error" in message && message.is_error === true) {
2663
- const resultText = "result" in message && typeof message.result === "string" ? message.result : void 0;
2664
- const errorsText = "errors" in message && Array.isArray(message.errors) ? message.errors.filter((e) => typeof e === "string").join("; ") : "";
2665
- const errorMessage = resultText ?? (errorsText || "Claude Code CLI returned an error");
2666
- throw Object.assign(new Error(errorMessage), {
2667
- exitCode: 1,
2668
- errorKind: lastAssistantErrorKind
2669
- });
2670
- }
2671
- if (message.subtype === "error_max_structured_output_retries") {
2672
- throw new Error(
2673
- "Failed to generate valid structured output after maximum retries. The model could not produce a response matching the required schema."
2674
- );
2675
- }
2676
- if ("structured_output" in message && message.structured_output !== void 0) {
2677
- structuredOutput = message.structured_output;
2678
- this.logger.debug("[claude-code] Received structured output from SDK");
2679
- }
2680
- this.logger.info(
2681
- `[claude-code] Request completed - Session: ${message.session_id}, Cost: $${costUsd?.toFixed(4) ?? "N/A"}, Duration: ${durationMs ?? "N/A"}ms`
2682
- );
2683
- if ("usage" in message) {
2684
- usage = convertClaudeCodeUsage(message.usage);
2685
- this.logger.debug(
2686
- `[claude-code] Token usage - Input: ${usage.inputTokens.total}, Output: ${usage.outputTokens.total}`
2687
- );
2688
- }
2689
- const stopReason = "stop_reason" in message ? message.stop_reason : void 0;
2690
- finishReason = mapClaudeCodeFinishReason(message.subtype, stopReason);
2691
- this.logger.debug(`[claude-code] Finish reason: ${finishReason.unified}`);
2692
- const effectivePromptSuggestions = sdkOptions?.promptSuggestions ?? this.settings.promptSuggestions;
2693
- if (this.settings.onPromptSuggestion && effectivePromptSuggestions !== false) {
2694
- await this.drainPromptSuggestion(response, this.settings.onPromptSuggestion);
2695
- }
2696
- break;
2697
- } else if (message.type === "system" && message.subtype === "init") {
2698
- this.logMcpConnectionIssues(message.mcp_servers);
2699
- this.setSessionId(message.session_id);
2700
- this.logger.info(`[claude-code] Session initialized: ${message.session_id}`);
2701
- } else if (message.type === "system") {
2702
- this.handleSystemMessage(
2703
- message,
2704
- metadataTracking,
2705
- buildRetractionEvictor(evictBuffered)
2706
- );
2707
- }
2708
- }
2709
- } catch (error) {
2710
- done();
2711
- this.logger.debug(
2712
- `[claude-code] Error during doGenerate: ${error instanceof Error ? error.message : String(error)}`
2713
- );
2714
- if (isAbortError(error)) {
2715
- this.logger.debug("[claude-code] Request aborted by user");
2716
- throw options.abortSignal?.aborted ? options.abortSignal.reason : error;
2717
- }
2718
- if (isClaudeCodeTruncationError(error, text)) {
2719
- this.logger.warn(
2720
- `[claude-code] Detected truncated response, returning ${text.length} characters of buffered text`
2721
- );
2722
- wasTruncated = true;
2723
- finishReason = { unified: "length", raw: "truncation" };
2724
- warnings.push({
2725
- type: "other",
2726
- message: CLAUDE_CODE_TRUNCATION_WARNING
2727
- });
2728
- } else {
2729
- throw this.handleClaudeCodeError(error, messagesPrompt, collectedStderr);
2730
- }
2731
- } finally {
2732
- if (options.abortSignal && abortListener) {
2733
- options.abortSignal.removeEventListener("abort", abortListener);
2734
- }
2735
- }
2736
- if (options.responseFormat?.type === "json" && options.responseFormat.schema !== void 0 && receivedResultMessage && structuredOutput === void 0 && !wasTruncated && finishReason.unified === "stop") {
2737
- const recoveredJsonText = extractJsonObjectText(joinFinalTurnTextSegments()) ?? extractJsonObjectText(joinTextSegments());
2738
- if (recoveredJsonText !== void 0) {
2739
- this.logger.warn(
2740
- "[claude-code] outputFormat was requested but the CLI returned no structured_output; recovered JSON by parsing the prose response. The schema likely contains constructs the CLI cannot enforce - see the README structured-output limitations."
2741
- );
2742
- structuredOutput = JSON.parse(recoveredJsonText);
2743
- } else {
2744
- throw createAPICallError({
2745
- message: MISSING_STRUCTURED_OUTPUT_ERROR_MESSAGE,
2746
- promptExcerpt: messagesPrompt.substring(0, 200),
2747
- isRetryable: false
2748
- });
2749
- }
2750
- }
2751
- const thinkingTraces = contentSegments.filter((segment) => segment.kind === "reasoning").map((segment) => segment.text);
2752
- const contentParts = [];
2753
- for (const segment of contentSegments) {
2754
- if (segment.kind === "reasoning") {
2755
- contentParts.push({ type: "reasoning", text: segment.text });
2756
- } else if (segment.kind === "text") {
2757
- if (structuredOutput !== void 0) continue;
2758
- const last = contentParts[contentParts.length - 1];
2759
- if (last !== void 0 && last.type === "text") {
2760
- last.text += segment.text;
2761
- } else {
2762
- contentParts.push({ type: "text", text: segment.text });
2763
- }
2764
- } else {
2765
- contentParts.push(segment.part);
2766
- }
2767
- }
2768
- if (structuredOutput !== void 0) {
2769
- contentParts.push({ type: "text", text: JSON.stringify(structuredOutput) });
2770
- } else if (!contentParts.some((part) => part.type === "text")) {
2771
- contentParts.push({ type: "text", text: "" });
2772
- }
2773
- return {
2774
- content: contentParts,
2775
- usage,
2776
- finishReason,
2777
- warnings,
2778
- response: {
2779
- id: (0, import_provider_utils.generateId)(),
2780
- timestamp: /* @__PURE__ */ new Date(),
2781
- modelId: this.modelId
2782
- },
2783
- request: {
2784
- body: messagesPrompt
2785
- },
2786
- providerMetadata: {
2787
- "claude-code": {
2788
- ...this.sessionId !== void 0 && { sessionId: this.sessionId },
2789
- ...costUsd !== void 0 && { costUsd },
2790
- ...durationMs !== void 0 && { durationMs },
2791
- ...modelUsage !== void 0 && { modelUsage },
2792
- ...ttftMs !== void 0 && { ttftMs },
2793
- ...ttftStreamMs !== void 0 && { ttftStreamMs },
2794
- ...timeToRequestMs !== void 0 && { timeToRequestMs },
2795
- ...warmSpareClaimed !== void 0 && { warmSpareClaimed },
2796
- ...terminalReason !== void 0 && { terminalReason },
2797
- ...metadataTracking.apiRetries > 0 && { apiRetries: metadataTracking.apiRetries },
2798
- ...metadataTracking.permissionDenials.length > 0 && {
2799
- permissionDenials: metadataTracking.permissionDenials
2800
- },
2801
- ...metadataTracking.mirrorErrors.length > 0 && {
2802
- mirrorErrors: metadataTracking.mirrorErrors
2803
- },
2804
- ...metadataTracking.estimatedThinkingTokens > 0 && {
2805
- estimatedThinkingTokens: metadataTracking.estimatedThinkingTokens
2806
- },
2807
- ...wasTruncated && { truncated: true },
2808
- ...thinkingTraces.length > 0 && { thinkingTraces }
2809
- }
2810
- }
2811
- };
2812
- }
2813
- async doStream(options) {
2814
- this.logger.debug(`[claude-code] Starting doStream request with model: ${this.modelId}`);
2815
- this.logger.debug(`[claude-code] Response format: ${options.responseFormat?.type ?? "none"}`);
2816
- const {
2817
- messagesPrompt,
2818
- warnings: messageWarnings,
2819
- streamingContentParts,
2820
- hasImageParts
2821
- } = convertToClaudeCodeMessages(options.prompt);
2822
- this.logger.debug(
2823
- `[claude-code] Converted ${options.prompt.length} messages for streaming, hasImageParts: ${hasImageParts}`
2824
- );
2825
- const abortController = new AbortController();
2826
- let abortListener;
2827
- if (options.abortSignal?.aborted) {
2828
- abortController.abort(options.abortSignal.reason);
2829
- }
2830
- let collectedStderr = "";
2831
- const stderrCollector = (data) => {
2832
- collectedStderr += data;
2833
- collectedStderr = capStderr(collectedStderr);
2834
- };
2835
- const sdkOptions = this.getSanitizedSdkOptions();
2836
- const effectiveResume = this.getEffectiveResume(sdkOptions);
2837
- const queryOptions = this.createQueryOptions(
2838
- abortController,
2839
- options.responseFormat,
2840
- stderrCollector,
2841
- sdkOptions,
2842
- effectiveResume
2843
- );
2844
- if (options.abortSignal && !options.abortSignal.aborted) {
2845
- abortListener = () => abortController.abort(options.abortSignal?.reason);
2846
- options.abortSignal.addEventListener("abort", abortListener, { once: true });
2847
- }
2848
- if (queryOptions.includePartialMessages === void 0) {
2849
- queryOptions.includePartialMessages = true;
2850
- }
2851
- const warnings = this.generateAllWarnings(options, messagesPrompt);
2852
- if (messageWarnings) {
2853
- messageWarnings.forEach((warning) => {
2854
- warnings.push({
2855
- type: "other",
2856
- message: warning
2857
- });
2858
- });
2859
- }
2860
- const modeSetting = this.settings.streamingInput ?? "auto";
2861
- const effectiveCanUseTool = sdkOptions?.canUseTool ?? this.settings.canUseTool;
2862
- const effectivePermissionPromptToolName = sdkOptions?.permissionPromptToolName ?? this.settings.permissionPromptToolName;
2863
- const wantsStreamInput = modeSetting === "always" || modeSetting === "auto" && !!effectiveCanUseTool;
2864
- if (!wantsStreamInput && hasImageParts) {
2865
- warnings.push({
2866
- type: "other",
2867
- message: STREAMING_FEATURE_WARNING
2868
- });
2869
- }
2870
- const stream = new ReadableStream({
2871
- start: async (controller) => {
2872
- let done = () => {
2873
- };
2874
- const outputStreamEnded = new Promise((resolve) => {
2875
- done = () => resolve(void 0);
2876
- });
2877
- const toolStates = /* @__PURE__ */ new Map();
2878
- const retractedStreamToolIds = /* @__PURE__ */ new Set();
2879
- const activeTaskTools = /* @__PURE__ */ new Map();
2880
- const getFallbackParentId = () => {
2881
- if (activeTaskTools.size === 1) {
2882
- return activeTaskTools.keys().next().value ?? null;
2883
- }
2884
- return null;
2885
- };
2886
- const streamWarnings = [];
2887
- const closeToolInput = (toolId, state) => {
2888
- if (!state.inputClosed && state.inputStarted) {
2889
- controller.enqueue({
2890
- type: "tool-input-end",
2891
- id: toolId
2892
- });
2893
- state.inputClosed = true;
2894
- }
2895
- };
2896
- const emitToolCall = (toolId, state) => {
2897
- if (state.callEmitted) {
2898
- return;
2899
- }
2900
- closeToolInput(toolId, state);
2901
- controller.enqueue(
2902
- this.buildToolCallPart(
2903
- toolId,
2904
- state.name,
2905
- state.lastSerializedInput ?? "",
2906
- state.parentToolCallId
2907
- )
2908
- );
2909
- state.callEmitted = true;
2910
- };
2911
- const finalizeToolCalls = () => {
2912
- for (const [toolId, state] of toolStates) {
2913
- emitToolCall(toolId, state);
2914
- }
2915
- toolStates.clear();
2916
- };
2917
- let usage = createEmptyUsage();
2918
- let accumulatedText = "";
2919
- const textSegments = [];
2920
- let textPartId;
2921
- let streamedTextLength = 0;
2922
- let emittedTextSinceLastAssistant = "";
2923
- let hasReceivedStreamEvents = false;
2924
- let hasStreamedJson = false;
2925
- let lastAssistantErrorKind;
2926
- const metadataTracking = {
2927
- apiRetries: 0,
2928
- permissionDenials: [],
2929
- mirrorErrors: [],
2930
- estimatedThinkingTokens: 0
2931
- };
2932
- const toolBlocksByIndex = /* @__PURE__ */ new Map();
2933
- const toolInputAccumulators = /* @__PURE__ */ new Map();
2934
- const textBlocksByIndex = /* @__PURE__ */ new Map();
2935
- let textStreamedViaContentBlock = false;
2936
- const reasoningBlocksByIndex = /* @__PURE__ */ new Map();
2937
- let currentReasoningPartId;
2938
- const evictLive = (retracted) => {
2939
- if (retracted.size === 0) return;
2940
- for (let i = textSegments.length - 1; i >= 0; i--) {
2941
- const segmentUuid = textSegments[i]?.uuid;
2942
- if (segmentUuid !== void 0 && retracted.has(segmentUuid)) {
2943
- textSegments.splice(i, 1);
2944
- }
2945
- }
2946
- accumulatedText = textSegments.map((segment) => segment.text).join("");
2947
- const retractedToolCallIds = computeRetractedToolCallIds(
2948
- retracted,
2949
- [...toolStates].map(([toolId, state]) => ({
2950
- toolCallId: toolId,
2951
- uuid: state.messageUuid
2952
- }))
2953
- );
2954
- for (const toolId of retractedToolCallIds) {
2955
- const state = toolStates.get(toolId);
2956
- if (!state) continue;
2957
- activeTaskTools.delete(toolId);
2958
- if (!state.callEmitted) {
2959
- closeToolInput(toolId, state);
2960
- toolStates.delete(toolId);
2961
- retractedStreamToolIds.add(toolId);
2962
- toolInputAccumulators.delete(toolId);
2963
- for (const [blockIndex, mappedId] of toolBlocksByIndex) {
2964
- if (mappedId === toolId) {
2965
- toolBlocksByIndex.delete(blockIndex);
2966
- }
2967
- }
2968
- this.logger.debug(
2969
- `[claude-code] Retracted pending tool call from superseded message - ID: ${toolId}`
2970
- );
2971
- }
2972
- }
2973
- };
2974
- try {
2975
- controller.enqueue({ type: "stream-start", warnings });
2976
- if (effectiveCanUseTool && effectivePermissionPromptToolName) {
2977
- throw new Error(
2978
- "canUseTool requires streamingInput mode ('auto' or 'always') and cannot be used with permissionPromptToolName (SDK constraint). Set streamingInput: 'auto' (or 'always') and remove permissionPromptToolName, or remove canUseTool."
2979
- );
2980
- }
2981
- const sdkPrompt = wantsStreamInput ? toAsyncIterablePrompt(
2982
- messagesPrompt,
2983
- outputStreamEnded,
2984
- effectiveResume,
2985
- streamingContentParts,
2986
- this.settings.onStreamStart
2987
- ) : messagesPrompt;
2988
- this.logger.debug(
2989
- `[claude-code] Starting stream query with streamingInput: ${wantsStreamInput}, session: ${effectiveResume ?? "new"}`
2990
- );
2991
- const response = (0, import_claude_agent_sdk.query)({
2992
- prompt: sdkPrompt,
2993
- options: queryOptions
2994
- });
2995
- this.settings.onQueryCreated?.(response);
2996
- for await (const message of response) {
2997
- this.logger.debug(`[claude-code] Stream received message type: ${message.type}`);
2998
- if (message.type === "stream_event") {
2999
- const streamEvent = message;
3000
- const event = streamEvent.event;
3001
- if (event.type === "content_block_delta" && event.delta.type === "text_delta" && "text" in event.delta && event.delta.text) {
3002
- const deltaText = event.delta.text;
3003
- hasReceivedStreamEvents = true;
3004
- if (options.responseFormat?.type === "json") {
3005
- accumulatedText += deltaText;
3006
- streamedTextLength += deltaText.length;
3007
- continue;
3008
- }
3009
- if (!textPartId) {
3010
- textPartId = (0, import_provider_utils.generateId)();
3011
- controller.enqueue({
3012
- type: "text-start",
3013
- id: textPartId
3014
- });
3015
- }
3016
- controller.enqueue({
3017
- type: "text-delta",
3018
- id: textPartId,
3019
- delta: deltaText
3020
- });
3021
- accumulatedText += deltaText;
3022
- streamedTextLength += deltaText.length;
3023
- emittedTextSinceLastAssistant += deltaText;
3024
- }
3025
- if (event.type === "content_block_delta" && event.delta.type === "input_json_delta" && "partial_json" in event.delta && event.delta.partial_json) {
3026
- const jsonDelta = event.delta.partial_json;
3027
- hasReceivedStreamEvents = true;
3028
- const blockIndex = "index" in event ? event.index : -1;
3029
- if (options.responseFormat?.type === "json") {
3030
- if (!textPartId) {
3031
- textPartId = (0, import_provider_utils.generateId)();
3032
- controller.enqueue({
3033
- type: "text-start",
3034
- id: textPartId
3035
- });
3036
- }
3037
- controller.enqueue({
3038
- type: "text-delta",
3039
- id: textPartId,
3040
- delta: jsonDelta
3041
- });
3042
- accumulatedText += jsonDelta;
3043
- streamedTextLength += jsonDelta.length;
3044
- hasStreamedJson = true;
3045
- continue;
3046
- }
3047
- const toolId = toolBlocksByIndex.get(blockIndex);
3048
- if (toolId) {
3049
- const accumulated = (toolInputAccumulators.get(toolId) ?? "") + jsonDelta;
3050
- toolInputAccumulators.set(toolId, accumulated);
3051
- controller.enqueue({
3052
- type: "tool-input-delta",
3053
- id: toolId,
3054
- delta: jsonDelta
3055
- });
3056
- continue;
3057
- }
3058
- }
3059
- if (event.type === "content_block_start" && "content_block" in event && event.content_block?.type === "tool_use") {
3060
- const blockIndex = "index" in event ? event.index : -1;
3061
- const toolBlock = event.content_block;
3062
- const toolId = typeof toolBlock.id === "string" && toolBlock.id.length > 0 ? toolBlock.id : (0, import_provider_utils.generateId)();
3063
- const toolName = typeof toolBlock.name === "string" && toolBlock.name.length > 0 ? toolBlock.name : _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
3064
- hasReceivedStreamEvents = true;
3065
- if (textPartId) {
3066
- const closedTextId = textPartId;
3067
- controller.enqueue({
3068
- type: "text-end",
3069
- id: closedTextId
3070
- });
3071
- textPartId = void 0;
3072
- for (const [idx, blockTextId] of textBlocksByIndex) {
3073
- if (blockTextId === closedTextId) {
3074
- textBlocksByIndex.delete(idx);
3075
- break;
3076
- }
3077
- }
3078
- }
3079
- toolBlocksByIndex.set(blockIndex, toolId);
3080
- toolInputAccumulators.set(toolId, "");
3081
- let state = toolStates.get(toolId);
3082
- if (!state) {
3083
- const partialParentId = message.parent_tool_use_id;
3084
- const currentParentId = isSubagentToolName(toolName) ? null : resolveToolParentId(partialParentId, void 0, getFallbackParentId);
3085
- const envelopeUuid = message.uuid;
3086
- state = {
3087
- name: toolName,
3088
- inputStarted: false,
3089
- inputClosed: false,
3090
- callEmitted: false,
3091
- parentToolCallId: currentParentId,
3092
- ...typeof envelopeUuid === "string" && { messageUuid: envelopeUuid }
3093
- };
3094
- toolStates.set(toolId, state);
3095
- }
3096
- if (!state.inputStarted) {
3097
- this.logger.debug(
3098
- `[claude-code] Tool input started (content_block) - Tool: ${toolName}, ID: ${toolId}, parent: ${state.parentToolCallId}`
3099
- );
3100
- controller.enqueue({
3101
- type: "tool-input-start",
3102
- id: toolId,
3103
- toolName,
3104
- providerExecuted: true,
3105
- dynamic: true,
3106
- providerMetadata: {
3107
- "claude-code": {
3108
- parentToolCallId: state.parentToolCallId ?? null
3109
- }
3110
- }
3111
- });
3112
- if (isSubagentToolName(toolName)) {
3113
- activeTaskTools.set(toolId, { startTime: Date.now() });
3114
- }
3115
- state.inputStarted = true;
3116
- }
3117
- continue;
3118
- }
3119
- if (event.type === "content_block_start" && "content_block" in event && event.content_block?.type === "text") {
3120
- const blockIndex = "index" in event ? event.index : -1;
3121
- hasReceivedStreamEvents = true;
3122
- const partId = (0, import_provider_utils.generateId)();
3123
- textBlocksByIndex.set(blockIndex, partId);
3124
- textPartId = partId;
3125
- this.logger.debug(
3126
- `[claude-code] Text content block started - Index: ${blockIndex}, ID: ${partId}`
3127
- );
3128
- controller.enqueue({
3129
- type: "text-start",
3130
- id: partId
3131
- });
3132
- textStreamedViaContentBlock = true;
3133
- continue;
3134
- }
3135
- if (event.type === "content_block_start" && "content_block" in event && event.content_block?.type === "thinking") {
3136
- const blockIndex = "index" in event ? event.index : -1;
3137
- hasReceivedStreamEvents = true;
3138
- if (textPartId) {
3139
- const closedTextId = textPartId;
3140
- controller.enqueue({
3141
- type: "text-end",
3142
- id: closedTextId
3143
- });
3144
- textPartId = void 0;
3145
- for (const [idx, blockTextId] of textBlocksByIndex) {
3146
- if (blockTextId === closedTextId) {
3147
- textBlocksByIndex.delete(idx);
3148
- break;
3149
- }
3150
- }
3151
- }
3152
- const reasoningPartId = (0, import_provider_utils.generateId)();
3153
- reasoningBlocksByIndex.set(blockIndex, reasoningPartId);
3154
- currentReasoningPartId = reasoningPartId;
3155
- this.logger.debug(
3156
- `[claude-code] Reasoning started (content_block) - ID: ${reasoningPartId}`
3157
- );
3158
- controller.enqueue({
3159
- type: "reasoning-start",
3160
- id: reasoningPartId
3161
- });
3162
- continue;
3163
- }
3164
- if (event.type === "content_block_delta" && event.delta.type === "thinking_delta" && "thinking" in event.delta && event.delta.thinking) {
3165
- const blockIndex = "index" in event ? event.index : -1;
3166
- const reasoningPartId = reasoningBlocksByIndex.get(blockIndex) ?? currentReasoningPartId;
3167
- hasReceivedStreamEvents = true;
3168
- if (reasoningPartId) {
3169
- controller.enqueue({
3170
- type: "reasoning-delta",
3171
- id: reasoningPartId,
3172
- delta: event.delta.thinking
3173
- });
3174
- }
3175
- continue;
3176
- }
3177
- if (event.type === "content_block_stop") {
3178
- const blockIndex = "index" in event ? event.index : -1;
3179
- hasReceivedStreamEvents = true;
3180
- const toolId = toolBlocksByIndex.get(blockIndex);
3181
- if (toolId) {
3182
- const state = toolStates.get(toolId);
3183
- if (state && !state.inputClosed) {
3184
- const accumulatedInput = toolInputAccumulators.get(toolId) ?? "";
3185
- this.logger.debug(
3186
- `[claude-code] Tool content block stopped - Index: ${blockIndex}, Tool: ${state.name}, ID: ${toolId}`
3187
- );
3188
- controller.enqueue({
3189
- type: "tool-input-end",
3190
- id: toolId
3191
- });
3192
- state.inputClosed = true;
3193
- const effectiveInput = accumulatedInput || state.lastSerializedInput || "";
3194
- state.lastSerializedInput = effectiveInput;
3195
- if (!state.callEmitted) {
3196
- controller.enqueue(
3197
- this.buildToolCallPart(
3198
- toolId,
3199
- state.name,
3200
- effectiveInput,
3201
- state.parentToolCallId
3202
- )
3203
- );
3204
- state.callEmitted = true;
3205
- }
3206
- }
3207
- toolBlocksByIndex.delete(blockIndex);
3208
- toolInputAccumulators.delete(toolId);
3209
- continue;
3210
- }
3211
- const textId = textBlocksByIndex.get(blockIndex);
3212
- if (textId) {
3213
- this.logger.debug(
3214
- `[claude-code] Text content block stopped - Index: ${blockIndex}, ID: ${textId}`
3215
- );
3216
- controller.enqueue({
3217
- type: "text-end",
3218
- id: textId
3219
- });
3220
- textBlocksByIndex.delete(blockIndex);
3221
- if (textPartId === textId) {
3222
- textPartId = void 0;
3223
- }
3224
- continue;
3225
- }
3226
- const reasoningPartId = reasoningBlocksByIndex.get(blockIndex);
3227
- if (reasoningPartId) {
3228
- this.logger.debug(
3229
- `[claude-code] Reasoning ended (content_block) - ID: ${reasoningPartId}`
3230
- );
3231
- controller.enqueue({
3232
- type: "reasoning-end",
3233
- id: reasoningPartId
3234
- });
3235
- reasoningBlocksByIndex.delete(blockIndex);
3236
- if (currentReasoningPartId === reasoningPartId) {
3237
- currentReasoningPartId = void 0;
3238
- }
3239
- continue;
3240
- }
3241
- }
3242
- continue;
3243
- }
3244
- if (message.type === "assistant") {
3245
- if (typeof message.error === "string") {
3246
- lastAssistantErrorKind = message.error;
3247
- }
3248
- const supersedesPriorMessages = applySupersede(message, evictLive, this.logger);
3249
- if (!message.message?.content) {
3250
- this.logger.warn(
3251
- `[claude-code] Unexpected assistant message structure: missing content field. Message type: ${message.type}. This may indicate an SDK protocol violation.`
3252
- );
3253
- continue;
3254
- }
3255
- const sdkParentToolUseId = message.parent_tool_use_id;
3256
- const content = message.message.content;
3257
- const tools = this.extractToolUses(content);
3258
- if (textPartId && tools.length > 0) {
3259
- const closedTextId = textPartId;
3260
- controller.enqueue({
3261
- type: "text-end",
3262
- id: closedTextId
3263
- });
3264
- textPartId = void 0;
3265
- for (const [idx, blockTextId] of textBlocksByIndex) {
3266
- if (blockTextId === closedTextId) {
3267
- textBlocksByIndex.delete(idx);
3268
- break;
3269
- }
3270
- }
3271
- }
3272
- for (const tool3 of tools) {
3273
- const toolId = tool3.id;
3274
- let state = toolStates.get(toolId);
3275
- if (!state) {
3276
- const currentParentId = isSubagentToolName(tool3.name) ? null : resolveToolParentId(
3277
- sdkParentToolUseId,
3278
- tool3.parentToolUseId,
3279
- getFallbackParentId
3280
- );
3281
- state = {
3282
- name: tool3.name,
3283
- inputStarted: false,
3284
- inputClosed: false,
3285
- callEmitted: false,
3286
- parentToolCallId: currentParentId,
3287
- ...typeof message.uuid === "string" && { messageUuid: message.uuid }
3288
- };
3289
- toolStates.set(toolId, state);
3290
- this.logger.debug(
3291
- `[claude-code] New tool use detected - Tool: ${tool3.name}, ID: ${toolId}, SDK parent: ${sdkParentToolUseId}, resolved parent: ${currentParentId}`
3292
- );
3293
- } else if (!state.parentToolCallId && sdkParentToolUseId && !isSubagentToolName(tool3.name)) {
3294
- state.parentToolCallId = sdkParentToolUseId;
3295
- this.logger.debug(
3296
- `[claude-code] Retroactive parent context - Tool: ${tool3.name}, ID: ${toolId}, parent: ${sdkParentToolUseId}`
3297
- );
3298
- }
3299
- state.name = tool3.name;
3300
- if (!state.inputStarted) {
3301
- this.logger.debug(
3302
- `[claude-code] Tool input started - Tool: ${tool3.name}, ID: ${toolId}`
3303
- );
3304
- controller.enqueue({
3305
- type: "tool-input-start",
3306
- id: toolId,
3307
- toolName: tool3.name,
3308
- providerExecuted: true,
3309
- dynamic: true,
3310
- // V3 field: indicates tool is provider-defined
3311
- providerMetadata: {
3312
- "claude-code": {
3313
- parentToolCallId: state.parentToolCallId ?? null
3314
- }
3315
- }
3316
- });
3317
- if (isSubagentToolName(tool3.name)) {
3318
- activeTaskTools.set(toolId, { startTime: Date.now() });
3319
- }
3320
- state.inputStarted = true;
3321
- }
3322
- const serializedInput = this.serializeToolInput(tool3.input);
3323
- if (serializedInput) {
3324
- let deltaPayload = "";
3325
- if (state.lastSerializedInput === void 0) {
3326
- if (serializedInput.length <= _ClaudeCodeLanguageModel.MAX_DELTA_CALC_SIZE) {
3327
- deltaPayload = serializedInput;
3328
- }
3329
- } else if (serializedInput.length <= _ClaudeCodeLanguageModel.MAX_DELTA_CALC_SIZE && state.lastSerializedInput.length <= _ClaudeCodeLanguageModel.MAX_DELTA_CALC_SIZE && serializedInput.startsWith(state.lastSerializedInput)) {
3330
- deltaPayload = serializedInput.slice(state.lastSerializedInput.length);
3331
- } else if (serializedInput !== state.lastSerializedInput) {
3332
- deltaPayload = "";
3333
- }
3334
- if (deltaPayload) {
3335
- controller.enqueue({
3336
- type: "tool-input-delta",
3337
- id: toolId,
3338
- delta: deltaPayload
3339
- });
3340
- }
3341
- state.lastSerializedInput = serializedInput;
3342
- }
3343
- }
3344
- const text = content.map((c) => c.type === "text" ? c.text : "").join("");
3345
- if (text) {
3346
- if (supersedesPriorMessages) {
3347
- textSegments.push({
3348
- ...typeof message.uuid === "string" && { uuid: message.uuid },
3349
- text
3350
- });
3351
- accumulatedText = textSegments.map((segment) => segment.text).join("");
3352
- if (emittedTextSinceLastAssistant === text) {
3353
- streamedTextLength = Math.max(streamedTextLength, text.length);
3354
- this.logger.debug(
3355
- "[claude-code] Skipping text emission for superseding assistant message (replacement already streamed)"
3356
- );
3357
- } else if (emittedTextSinceLastAssistant.length > 0 && text.startsWith(emittedTextSinceLastAssistant)) {
3358
- if (options.responseFormat?.type !== "json") {
3359
- const suffix = text.slice(emittedTextSinceLastAssistant.length);
3360
- if (suffix) {
3361
- if (!textPartId) {
3362
- textPartId = (0, import_provider_utils.generateId)();
3363
- controller.enqueue({ type: "text-start", id: textPartId });
3364
- }
3365
- controller.enqueue({
3366
- type: "text-delta",
3367
- id: textPartId,
3368
- delta: suffix
3369
- });
3370
- emittedTextSinceLastAssistant = text;
3371
- }
3372
- }
3373
- streamedTextLength = Math.max(streamedTextLength, text.length);
3374
- this.logger.debug(
3375
- "[claude-code] Emitted unstreamed suffix of superseding assistant message"
3376
- );
3377
- } else if (options.responseFormat?.type !== "json") {
3378
- if (textPartId) {
3379
- const closedTextId = textPartId;
3380
- controller.enqueue({
3381
- type: "text-end",
3382
- id: closedTextId
3383
- });
3384
- textPartId = void 0;
3385
- for (const [idx, blockTextId] of textBlocksByIndex) {
3386
- if (blockTextId === closedTextId) {
3387
- textBlocksByIndex.delete(idx);
3388
- break;
3389
- }
3390
- }
3391
- }
3392
- textPartId = (0, import_provider_utils.generateId)();
3393
- controller.enqueue({
3394
- type: "text-start",
3395
- id: textPartId
3396
- });
3397
- controller.enqueue({
3398
- type: "text-delta",
3399
- id: textPartId,
3400
- delta: text
3401
- });
3402
- streamedTextLength = Math.max(streamedTextLength, text.length);
3403
- this.logger.debug(
3404
- "[claude-code] Emitted superseding assistant message as a new text part (canonical replacement)"
3405
- );
3406
- }
3407
- } else if (hasReceivedStreamEvents) {
3408
- const newTextStart = streamedTextLength;
3409
- const deltaText = text.length > newTextStart ? text.slice(newTextStart) : "";
3410
- accumulatedText = text;
3411
- textSegments.length = 0;
3412
- textSegments.push({
3413
- ...typeof message.uuid === "string" && { uuid: message.uuid },
3414
- text
3415
- });
3416
- if (options.responseFormat?.type !== "json" && deltaText) {
3417
- if (!textPartId) {
3418
- textPartId = (0, import_provider_utils.generateId)();
3419
- controller.enqueue({
3420
- type: "text-start",
3421
- id: textPartId
3422
- });
3423
- }
3424
- controller.enqueue({
3425
- type: "text-delta",
3426
- id: textPartId,
3427
- delta: deltaText
3428
- });
3429
- }
3430
- streamedTextLength = text.length;
3431
- } else {
3432
- accumulatedText += text;
3433
- textSegments.push({
3434
- ...typeof message.uuid === "string" && { uuid: message.uuid },
3435
- text
3436
- });
3437
- if (options.responseFormat?.type !== "json") {
3438
- if (!textPartId) {
3439
- textPartId = (0, import_provider_utils.generateId)();
3440
- controller.enqueue({
3441
- type: "text-start",
3442
- id: textPartId
3443
- });
3444
- }
3445
- controller.enqueue({
3446
- type: "text-delta",
3447
- id: textPartId,
3448
- delta: text
3449
- });
3450
- }
3451
- }
3452
- }
3453
- emittedTextSinceLastAssistant = "";
3454
- } else if (message.type === "user") {
3455
- if (!message.message?.content) {
3456
- this.logger.warn(
3457
- `[claude-code] Unexpected user message structure: missing content field. Message type: ${message.type}. This may indicate an SDK protocol violation.`
3458
- );
3459
- continue;
3460
- }
3461
- if (textPartId) {
3462
- const closedTextId = textPartId;
3463
- controller.enqueue({
3464
- type: "text-end",
3465
- id: closedTextId
3466
- });
3467
- textPartId = void 0;
3468
- for (const [blockIndex, blockTextId] of textBlocksByIndex) {
3469
- if (blockTextId === closedTextId) {
3470
- textBlocksByIndex.delete(blockIndex);
3471
- break;
3472
- }
3473
- }
3474
- this.logger.debug("[claude-code] Closed text part due to user message");
3475
- }
3476
- accumulatedText = "";
3477
- textSegments.length = 0;
3478
- streamedTextLength = 0;
3479
- emittedTextSinceLastAssistant = "";
3480
- const sdkParentToolUseIdForResults = message.parent_tool_use_id;
3481
- const content = message.message.content;
3482
- for (const result of this.extractToolResults(content)) {
3483
- if (this.isRetractedToolFrame(result.id, retractedStreamToolIds, "result")) {
3484
- continue;
3485
- }
3486
- let state = toolStates.get(result.id);
3487
- const toolName = result.name ?? state?.name ?? _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
3488
- this.logger.debug(
3489
- `[claude-code] Tool result received - Tool: ${toolName}, ID: ${result.id}`
3490
- );
3491
- if (!state) {
3492
- this.logger.warn(
3493
- `[claude-code] Received tool result for unknown tool ID: ${result.id}`
3494
- );
3495
- const resolvedParentId = isSubagentToolName(toolName) ? null : resolveToolParentId(
3496
- sdkParentToolUseIdForResults,
3497
- void 0,
3498
- getFallbackParentId
3499
- );
3500
- state = {
3501
- name: toolName,
3502
- inputStarted: false,
3503
- inputClosed: false,
3504
- callEmitted: false,
3505
- parentToolCallId: resolvedParentId
3506
- };
3507
- toolStates.set(result.id, state);
3508
- if (!state.inputStarted) {
3509
- controller.enqueue({
3510
- type: "tool-input-start",
3511
- id: result.id,
3512
- toolName,
3513
- providerExecuted: true,
3514
- dynamic: true,
3515
- // V3 field: indicates tool is provider-defined
3516
- providerMetadata: {
3517
- "claude-code": {
3518
- parentToolCallId: state.parentToolCallId ?? null
3519
- }
3520
- }
3521
- });
3522
- state.inputStarted = true;
3523
- }
3524
- if (!state.inputClosed) {
3525
- controller.enqueue({
3526
- type: "tool-input-end",
3527
- id: result.id
3528
- });
3529
- state.inputClosed = true;
3530
- }
3531
- }
3532
- state.name = toolName;
3533
- emitToolCall(result.id, state);
3534
- if (isSubagentToolName(toolName)) {
3535
- activeTaskTools.delete(result.id);
3536
- }
3537
- controller.enqueue(
3538
- this.buildToolResultPart(
3539
- result.id,
3540
- toolName,
3541
- result.result,
3542
- result.isError,
3543
- state.parentToolCallId
3544
- )
3545
- );
3546
- }
3547
- for (const error of this.extractToolErrors(content)) {
3548
- if (this.isRetractedToolFrame(error.id, retractedStreamToolIds, "error")) {
3549
- continue;
3550
- }
3551
- let state = toolStates.get(error.id);
3552
- const toolName = error.name ?? state?.name ?? _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
3553
- this.logger.debug(
3554
- `[claude-code] Tool error received - Tool: ${toolName}, ID: ${error.id}`
3555
- );
3556
- if (!state) {
3557
- this.logger.warn(
3558
- `[claude-code] Received tool error for unknown tool ID: ${error.id}`
3559
- );
3560
- const errorResolvedParentId = isSubagentToolName(toolName) ? null : resolveToolParentId(
3561
- sdkParentToolUseIdForResults,
3562
- void 0,
3563
- getFallbackParentId
3564
- );
3565
- state = {
3566
- name: toolName,
3567
- inputStarted: true,
3568
- inputClosed: true,
3569
- callEmitted: false,
3570
- parentToolCallId: errorResolvedParentId
3571
- };
3572
- toolStates.set(error.id, state);
3573
- }
3574
- emitToolCall(error.id, state);
3575
- if (isSubagentToolName(toolName)) {
3576
- activeTaskTools.delete(error.id);
3577
- }
3578
- controller.enqueue(
3579
- this.buildToolErrorPart(error.id, toolName, error.error, state.parentToolCallId)
3580
- );
3581
- }
3582
- } else if (message.type === "result") {
3583
- done();
3584
- this.mergeResultPermissionDenials(message, metadataTracking);
3585
- if ("is_error" in message && message.is_error === true) {
3586
- const resultText = "result" in message && typeof message.result === "string" ? message.result : void 0;
3587
- const errorsText = "errors" in message && Array.isArray(message.errors) ? message.errors.filter((e) => typeof e === "string").join("; ") : "";
3588
- const errorMessage = resultText ?? (errorsText || "Claude Code CLI returned an error");
3589
- throw Object.assign(new Error(errorMessage), {
3590
- exitCode: 1,
3591
- errorKind: lastAssistantErrorKind
3592
- });
3593
- }
3594
- if (message.subtype === "error_max_structured_output_retries") {
3595
- throw new Error(
3596
- "Failed to generate valid structured output after maximum retries. The model could not produce a response matching the required schema."
3597
- );
3598
- }
3599
- this.logger.info(
3600
- `[claude-code] Stream completed - Session: ${message.session_id}, Cost: $${message.total_cost_usd?.toFixed(4) ?? "N/A"}, Duration: ${message.duration_ms ?? "N/A"}ms`
3601
- );
3602
- if ("usage" in message) {
3603
- usage = convertClaudeCodeUsage(message.usage);
3604
- this.logger.debug(
3605
- `[claude-code] Stream token usage - Input: ${usage.inputTokens.total}, Output: ${usage.outputTokens.total}`
3606
- );
3607
- }
3608
- const stopReason = "stop_reason" in message ? message.stop_reason : void 0;
3609
- const finishReason = mapClaudeCodeFinishReason(
3610
- message.subtype,
3611
- stopReason
3612
- );
3613
- this.logger.debug(`[claude-code] Stream finish reason: ${finishReason.unified}`);
3614
- this.setSessionId(message.session_id);
3615
- const structuredOutput = "structured_output" in message ? message.structured_output : void 0;
3616
- const alreadyStreamedJson = hasStreamedJson && options.responseFormat?.type === "json" && hasReceivedStreamEvents;
3617
- if (alreadyStreamedJson) {
3618
- if (textPartId) {
3619
- controller.enqueue({
3620
- type: "text-end",
3621
- id: textPartId
3622
- });
3623
- }
3624
- } else if (structuredOutput !== void 0) {
3625
- const jsonTextId = (0, import_provider_utils.generateId)();
3626
- const jsonText = JSON.stringify(structuredOutput);
3627
- controller.enqueue({
3628
- type: "text-start",
3629
- id: jsonTextId
3630
- });
3631
- controller.enqueue({
3632
- type: "text-delta",
3633
- id: jsonTextId,
3634
- delta: jsonText
3635
- });
3636
- controller.enqueue({
3637
- type: "text-end",
3638
- id: jsonTextId
3639
- });
3640
- } else if (options.responseFormat?.type === "json" && options.responseFormat.schema !== void 0 && finishReason.unified === "stop") {
3641
- const recoveredJsonText = extractJsonObjectText(accumulatedText);
3642
- if (recoveredJsonText === void 0) {
3643
- throw createAPICallError({
3644
- message: MISSING_STRUCTURED_OUTPUT_ERROR_MESSAGE,
3645
- promptExcerpt: messagesPrompt.substring(0, 200),
3646
- isRetryable: false
3647
- });
3648
- }
3649
- this.logger.warn(
3650
- "[claude-code] outputFormat was requested but the CLI returned no structured_output; recovered JSON by parsing the prose response. The schema likely contains constructs the CLI cannot enforce - see the README structured-output limitations."
3651
- );
3652
- if (textPartId) {
3653
- controller.enqueue({
3654
- type: "text-end",
3655
- id: textPartId
3656
- });
3657
- }
3658
- const recoveredTextId = (0, import_provider_utils.generateId)();
3659
- controller.enqueue({
3660
- type: "text-start",
3661
- id: recoveredTextId
3662
- });
3663
- controller.enqueue({
3664
- type: "text-delta",
3665
- id: recoveredTextId,
3666
- delta: recoveredJsonText
3667
- });
3668
- controller.enqueue({
3669
- type: "text-end",
3670
- id: recoveredTextId
3671
- });
3672
- } else if (textPartId) {
3673
- controller.enqueue({
3674
- type: "text-end",
3675
- id: textPartId
3676
- });
3677
- } else if (accumulatedText && !textStreamedViaContentBlock) {
3678
- const fallbackTextId = (0, import_provider_utils.generateId)();
3679
- controller.enqueue({
3680
- type: "text-start",
3681
- id: fallbackTextId
3682
- });
3683
- controller.enqueue({
3684
- type: "text-delta",
3685
- id: fallbackTextId,
3686
- delta: accumulatedText
3687
- });
3688
- controller.enqueue({
3689
- type: "text-end",
3690
- id: fallbackTextId
3691
- });
3692
- }
3693
- finalizeToolCalls();
3694
- const warningsJson = this.serializeWarningsForMetadata(streamWarnings);
3695
- controller.enqueue({
3696
- type: "finish",
3697
- finishReason,
3698
- usage,
3699
- providerMetadata: {
3700
- "claude-code": {
3701
- sessionId: message.session_id,
3702
- ...message.total_cost_usd !== void 0 && {
3703
- costUsd: message.total_cost_usd
3704
- },
3705
- ...message.duration_ms !== void 0 && { durationMs: message.duration_ms },
3706
- ...message.modelUsage !== void 0 && {
3707
- modelUsage: message.modelUsage
3708
- },
3709
- // SDK 0.3.x timing metadata (ttft_* only present on SDKResultSuccess)
3710
- ..."ttft_ms" in message && message.ttft_ms !== void 0 && { ttftMs: message.ttft_ms },
3711
- ..."ttft_stream_ms" in message && message.ttft_stream_ms !== void 0 && {
3712
- ttftStreamMs: message.ttft_stream_ms
3713
- },
3714
- ..."time_to_request_ms" in message && message.time_to_request_ms !== void 0 && {
3715
- timeToRequestMs: message.time_to_request_ms
3716
- },
3717
- ..."warm_spare_claimed" in message && message.warm_spare_claimed !== void 0 && {
3718
- warmSpareClaimed: message.warm_spare_claimed
3719
- },
3720
- ...message.terminal_reason !== void 0 && {
3721
- terminalReason: message.terminal_reason
3722
- },
3723
- ...metadataTracking.apiRetries > 0 && {
3724
- apiRetries: metadataTracking.apiRetries
3725
- },
3726
- ...metadataTracking.permissionDenials.length > 0 && {
3727
- permissionDenials: metadataTracking.permissionDenials
3728
- },
3729
- ...metadataTracking.mirrorErrors.length > 0 && {
3730
- mirrorErrors: metadataTracking.mirrorErrors
3731
- },
3732
- ...metadataTracking.estimatedThinkingTokens > 0 && {
3733
- estimatedThinkingTokens: metadataTracking.estimatedThinkingTokens
3734
- },
3735
- // JSON validation warnings are collected during streaming and included
3736
- // in providerMetadata since the AI SDK's finish event doesn't support
3737
- // a top-level warnings field (unlike stream-start which was already emitted)
3738
- ...streamWarnings.length > 0 && {
3739
- warnings: warningsJson
3740
- }
3741
- }
3742
- }
3743
- });
3744
- controller.close();
3745
- const effectivePromptSuggestions = sdkOptions?.promptSuggestions ?? this.settings.promptSuggestions;
3746
- if (this.settings.onPromptSuggestion && effectivePromptSuggestions !== false) {
3747
- await this.drainPromptSuggestion(response, this.settings.onPromptSuggestion);
3748
- }
3749
- return;
3750
- } else if (message.type === "system" && message.subtype === "init") {
3751
- this.logMcpConnectionIssues(message.mcp_servers);
3752
- this.setSessionId(message.session_id);
3753
- this.logger.info(`[claude-code] Stream session initialized: ${message.session_id}`);
3754
- controller.enqueue({
3755
- type: "response-metadata",
3756
- id: message.session_id,
3757
- timestamp: /* @__PURE__ */ new Date(),
3758
- modelId: this.modelId
3759
- });
3760
- } else if (message.type === "system") {
3761
- this.handleSystemMessage(
3762
- message,
3763
- metadataTracking,
3764
- buildRetractionEvictor(evictLive)
3765
- );
3766
- } else if (message.type === "prompt_suggestion") {
3767
- this.logger.debug("[claude-code] Received prompt suggestion");
3768
- this.settings.onPromptSuggestion?.(message.suggestion);
3769
- }
3770
- }
3771
- finalizeToolCalls();
3772
- this.logger.debug("[claude-code] Stream finalized, closing stream");
3773
- controller.close();
3774
- } catch (error) {
3775
- done();
3776
- this.logger.debug(
3777
- `[claude-code] Error during doStream: ${error instanceof Error ? error.message : String(error)}`
3778
- );
3779
- if (isClaudeCodeTruncationError(error, accumulatedText)) {
3780
- this.logger.warn(
3781
- `[claude-code] Detected truncated stream response, returning ${accumulatedText.length} characters of buffered text`
3782
- );
3783
- const truncationWarning = {
3784
- type: "other",
3785
- message: CLAUDE_CODE_TRUNCATION_WARNING
3786
- };
3787
- streamWarnings.push(truncationWarning);
3788
- if (textPartId) {
3789
- controller.enqueue({
3790
- type: "text-end",
3791
- id: textPartId
3792
- });
3793
- } else if (accumulatedText && !textStreamedViaContentBlock) {
3794
- const fallbackTextId = (0, import_provider_utils.generateId)();
3795
- controller.enqueue({
3796
- type: "text-start",
3797
- id: fallbackTextId
3798
- });
3799
- controller.enqueue({
3800
- type: "text-delta",
3801
- id: fallbackTextId,
3802
- delta: accumulatedText
3803
- });
3804
- controller.enqueue({
3805
- type: "text-end",
3806
- id: fallbackTextId
3807
- });
3808
- }
3809
- finalizeToolCalls();
3810
- const warningsJson = this.serializeWarningsForMetadata(streamWarnings);
3811
- controller.enqueue({
3812
- type: "finish",
3813
- finishReason: { unified: "length", raw: "truncation" },
3814
- usage,
3815
- providerMetadata: {
3816
- "claude-code": {
3817
- ...this.sessionId !== void 0 && { sessionId: this.sessionId },
3818
- truncated: true,
3819
- ...metadataTracking.apiRetries > 0 && {
3820
- apiRetries: metadataTracking.apiRetries
3821
- },
3822
- ...metadataTracking.permissionDenials.length > 0 && {
3823
- permissionDenials: metadataTracking.permissionDenials
3824
- },
3825
- ...metadataTracking.mirrorErrors.length > 0 && {
3826
- mirrorErrors: metadataTracking.mirrorErrors
3827
- },
3828
- ...metadataTracking.estimatedThinkingTokens > 0 && {
3829
- estimatedThinkingTokens: metadataTracking.estimatedThinkingTokens
3830
- },
3831
- ...streamWarnings.length > 0 && {
3832
- warnings: warningsJson
3833
- }
3834
- }
3835
- }
3836
- });
3837
- controller.close();
3838
- return;
3839
- }
3840
- finalizeToolCalls();
3841
- let errorToEmit;
3842
- if (isAbortError(error)) {
3843
- errorToEmit = options.abortSignal?.aborted ? options.abortSignal.reason : error;
3844
- } else {
3845
- errorToEmit = this.handleClaudeCodeError(error, messagesPrompt, collectedStderr);
3846
- }
3847
- controller.enqueue({
3848
- type: "error",
3849
- error: errorToEmit
3850
- });
3851
- controller.close();
3852
- } finally {
3853
- if (options.abortSignal && abortListener) {
3854
- options.abortSignal.removeEventListener("abort", abortListener);
3855
- }
3856
- }
3857
- },
3858
- cancel: () => {
3859
- if (options.abortSignal && abortListener) {
3860
- options.abortSignal.removeEventListener("abort", abortListener);
3861
- }
3862
- }
3863
- });
3864
- return {
3865
- stream,
3866
- request: {
3867
- body: messagesPrompt
3868
- }
3869
- };
3870
- }
3871
- serializeWarningsForMetadata(warnings) {
3872
- const result = warnings.map((w) => {
3873
- const base = { type: w.type };
3874
- if ("message" in w) {
3875
- const m = w.message;
3876
- if (m !== void 0) base.message = String(m);
3877
- }
3878
- if (w.type === "unsupported" || w.type === "compatibility") {
3879
- const feature = w.feature;
3880
- if (feature !== void 0) base.feature = String(feature);
3881
- if ("details" in w) {
3882
- const d = w.details;
3883
- if (d !== void 0) base.details = String(d);
3884
- }
3885
- }
3886
- return base;
3887
- });
3888
- return result;
3889
- }
3890
- };
3891
-
3892
- // src/claude-code-provider.ts
3893
- function createClaudeCode(options = {}) {
3894
- const logger = getLogger(options.defaultSettings?.logger);
3895
- if (options.defaultSettings) {
3896
- const validation = validateSettings(options.defaultSettings);
3897
- if (!validation.valid) {
3898
- throw new Error(`Invalid default settings: ${validation.errors.join(", ")}`);
3899
- }
3900
- if (validation.warnings.length > 0) {
3901
- validation.warnings.forEach((warning) => logger.warn(`Claude Code Provider: ${warning}`));
3902
- }
3903
- }
3904
- const createModel = (modelId, settings = {}) => {
3905
- const mergedSettings = {
3906
- ...options.defaultSettings,
3907
- ...settings
3908
- };
3909
- const validation = validateSettings(mergedSettings);
3910
- if (!validation.valid) {
3911
- throw new Error(`Invalid settings: ${validation.errors.join(", ")}`);
3912
- }
3913
- return new ClaudeCodeLanguageModel({
3914
- id: modelId,
3915
- settings: mergedSettings,
3916
- settingsValidationWarnings: validation.warnings
3917
- });
3918
- };
3919
- const provider = function(modelId, settings) {
3920
- if (new.target) {
3921
- throw new Error("The Claude Code model function cannot be called with the new keyword.");
3922
- }
3923
- return createModel(modelId, settings);
3924
- };
3925
- provider.languageModel = createModel;
3926
- provider.chat = createModel;
3927
- provider.specificationVersion = "v3";
3928
- provider.embeddingModel = (modelId) => {
3929
- throw new import_provider3.NoSuchModelError({
3930
- modelId,
3931
- modelType: "embeddingModel"
3932
- });
3933
- };
3934
- provider.imageModel = (modelId) => {
3935
- throw new import_provider3.NoSuchModelError({
3936
- modelId,
3937
- modelType: "imageModel"
3938
- });
3939
- };
3940
- return provider;
3941
- }
3942
- var claudeCode = createClaudeCode();
3943
-
3944
- // src/index.ts
3945
- var import_claude_agent_sdk3 = require("@anthropic-ai/claude-agent-sdk");
3946
- var import_claude_agent_sdk4 = require("@anthropic-ai/claude-agent-sdk");
3947
- var import_claude_agent_sdk5 = require("@anthropic-ai/claude-agent-sdk");
3948
-
3949
- // src/mcp-helpers.ts
3950
- var import_claude_agent_sdk2 = require("@anthropic-ai/claude-agent-sdk");
3951
- var import_zod2 = require("zod");
3952
- function buildIsErrorResult(text) {
3953
- return {
3954
- isError: true,
3955
- content: [{ type: "text", text }]
3956
- };
3957
- }
3958
- async function normalizeToolResultToText(toolName, result) {
3959
- if (result != null && typeof result[Symbol.asyncIterator] === "function") {
3960
- let last;
3961
- for await (const chunk of result) {
3962
- last = chunk;
3963
- }
3964
- result = last;
3965
- }
3966
- if (typeof result === "string") {
3967
- return { text: result };
3968
- }
3969
- try {
3970
- return { text: JSON.stringify(result) ?? "undefined" };
3971
- } catch (serializationError) {
3972
- const reason = serializationError instanceof Error ? serializationError.message : String(serializationError);
3973
- return {
3974
- isError: buildIsErrorResult(
3975
- `Tool "${toolName}" succeeded but its result could not be serialized to JSON: ${reason}`
3976
- )
3977
- };
3978
- }
3979
- }
3980
- function createCustomMcpServer(config) {
3981
- const defs = Object.entries(config.tools).map(
3982
- ([name, def]) => (0, import_claude_agent_sdk2.tool)(
3983
- name,
3984
- def.description,
3985
- def.inputSchema.shape,
3986
- (args, extra) => def.handler(args, extra),
3987
- def.annotations ? { annotations: def.annotations } : void 0
3988
- )
3989
- );
3990
- return (0, import_claude_agent_sdk2.createSdkMcpServer)({ name: config.name, version: config.version, tools: defs });
3991
- }
3992
- var AI_SDK_SCHEMA_SYMBOL = Symbol.for("vercel.ai.schema");
3993
- function isAiSdkJsonSchema(schema) {
3994
- return typeof schema === "object" && schema !== null && AI_SDK_SCHEMA_SYMBOL in schema;
3995
- }
3996
- function isZodObjectSchema(schema) {
3997
- if (typeof schema !== "object" || schema === null) {
3998
- return false;
3999
- }
4000
- const candidate = schema;
4001
- if (!("_zod" in candidate) && !("_def" in candidate)) {
4002
- return false;
4003
- }
4004
- const typeTag = candidate._zod?.def?.type ?? candidate._def?.typeName;
4005
- if (typeTag !== "object" && typeTag !== "ZodObject") {
4006
- return false;
4007
- }
4008
- return typeof candidate.shape === "object" && candidate.shape !== null;
4009
- }
4010
- function createAiSdkMcpServer(name, tools) {
4011
- const defs = Object.entries(tools).map(([toolName, def]) => {
4012
- const execute = def.execute;
4013
- if (typeof execute !== "function") {
4014
- throw new Error(
4015
- `createAiSdkMcpServer: tool "${toolName}" has no execute function. Only tools that execute locally can be bridged to the Claude Code CLI.`
4016
- );
4017
- }
4018
- if (isAiSdkJsonSchema(def.inputSchema)) {
4019
- throw new Error(
4020
- `createAiSdkMcpServer: tool "${toolName}" uses a JSON Schema-based inputSchema (e.g. the AI SDK's jsonSchema() helper). Only Zod object schemas are supported because the Agent SDK's tool() requires a Zod shape. Define inputSchema with z.object({...}) instead.`
4021
- );
4022
- }
4023
- if (!isZodObjectSchema(def.inputSchema)) {
4024
- throw new Error(
4025
- `createAiSdkMcpServer: tool "${toolName}" has an inputSchema that is not a Zod object schema. Pass the same z.object({...}) schema you would give to the AI SDK tool() helper.`
4026
- );
4027
- }
4028
- const zodSchema = def.inputSchema;
4029
- return (0, import_claude_agent_sdk2.tool)(
4030
- toolName,
4031
- def.description ?? "",
4032
- zodSchema.shape,
4033
- async (args, extra) => {
4034
- try {
4035
- const extraInfo = extra ?? {};
4036
- const result = await execute.call(def, args, {
4037
- toolCallId: extraInfo.requestId !== void 0 ? String(extraInfo.requestId) : void 0,
4038
- abortSignal: extraInfo.signal
4039
- });
4040
- const normalized = await normalizeToolResultToText(toolName, result);
4041
- if ("isError" in normalized) {
4042
- return normalized.isError;
4043
- }
4044
- return { content: [{ type: "text", text: normalized.text }] };
4045
- } catch (error) {
4046
- return buildIsErrorResult(error instanceof Error ? error.message : String(error));
4047
- }
4048
- }
4049
- );
4050
- });
4051
- return (0, import_claude_agent_sdk2.createSdkMcpServer)({ name, tools: defs });
4052
- }
4053
- // Annotate the CommonJS export names for ESM import in node:
4054
- 0 && (module.exports = {
4055
- AbortError,
4056
- ClaudeCodeLanguageModel,
4057
- HOOK_EVENTS,
4058
- InMemorySessionStore,
4059
- SYSTEM_PROMPT_DYNAMIC_BOUNDARY,
4060
- claudeCode,
4061
- createAPICallError,
4062
- createAiSdkMcpServer,
4063
- createAuthenticationError,
4064
- createClaudeCode,
4065
- createCustomMcpServer,
4066
- createSdkMcpServer,
4067
- createTimeoutError,
4068
- deleteSession,
4069
- foldSessionSummary,
4070
- forkSession,
4071
- getErrorMetadata,
4072
- getSessionInfo,
4073
- getSessionMessages,
4074
- getSubagentMessages,
4075
- importSessionToStore,
4076
- isAuthenticationError,
4077
- isTimeoutError,
4078
- listSessions,
4079
- listSubagents,
4080
- renameSession,
4081
- startup,
4082
- tagSession,
4083
- tool
4084
- });
4085
- //# sourceMappingURL=index.cjs.map