ai-sdk-provider-claude-code 3.4.4 → 3.5.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/README.md +312 -51
- package/dist/index.cjs +1589 -175
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +481 -31
- package/dist/index.d.ts +481 -31
- package/dist/index.js +1593 -177
- package/dist/index.js.map +1 -1
- package/docs/ai-sdk-v4/GUIDE.md +2 -0
- package/docs/ai-sdk-v4/README.md +7 -0
- package/docs/ai-sdk-v5/GUIDE.md +2 -0
- package/docs/ai-sdk-v5/README.md +10 -0
- package/docs/sessions.md +117 -0
- package/package.json +9 -2
package/dist/index.cjs
CHANGED
|
@@ -20,17 +20,34 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
AbortError: () => import_claude_agent_sdk3.AbortError,
|
|
23
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,
|
|
24
28
|
claudeCode: () => claudeCode,
|
|
25
29
|
createAPICallError: () => createAPICallError,
|
|
30
|
+
createAiSdkMcpServer: () => createAiSdkMcpServer,
|
|
26
31
|
createAuthenticationError: () => createAuthenticationError,
|
|
27
32
|
createClaudeCode: () => createClaudeCode,
|
|
28
33
|
createCustomMcpServer: () => createCustomMcpServer,
|
|
29
34
|
createSdkMcpServer: () => import_claude_agent_sdk3.createSdkMcpServer,
|
|
30
35
|
createTimeoutError: () => createTimeoutError,
|
|
36
|
+
deleteSession: () => import_claude_agent_sdk4.deleteSession,
|
|
37
|
+
foldSessionSummary: () => import_claude_agent_sdk4.foldSessionSummary,
|
|
38
|
+
forkSession: () => import_claude_agent_sdk4.forkSession,
|
|
31
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,
|
|
32
44
|
isAuthenticationError: () => isAuthenticationError,
|
|
33
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,
|
|
34
51
|
tool: () => import_claude_agent_sdk3.tool
|
|
35
52
|
});
|
|
36
53
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -45,6 +62,23 @@ var import_provider_utils = require("@ai-sdk/provider-utils");
|
|
|
45
62
|
// src/convert-to-claude-code-messages.ts
|
|
46
63
|
var IMAGE_URL_WARNING = "Image URLs are not supported by this provider; supply base64/data URLs.";
|
|
47
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
|
+
}
|
|
48
82
|
function normalizeBase64(base64) {
|
|
49
83
|
return base64.replace(/\s+/g, "");
|
|
50
84
|
}
|
|
@@ -227,8 +261,9 @@ function convertToClaudeCodeMessages(prompt) {
|
|
|
227
261
|
}
|
|
228
262
|
const toolCalls = message.content.filter((part) => part.type === "tool-call");
|
|
229
263
|
if (toolCalls.length > 0) {
|
|
230
|
-
|
|
231
|
-
|
|
264
|
+
const serializedCalls = toolCalls.map((call) => `[Tool call: ${call.toolName}(${serializeToolCallInput(call.input)})]`).join("\n");
|
|
265
|
+
assistantContent += assistantContent ? `
|
|
266
|
+
${serializedCalls}` : serializedCalls;
|
|
232
267
|
}
|
|
233
268
|
}
|
|
234
269
|
const formattedAssistant = `Assistant: ${assistantContent}`;
|
|
@@ -437,6 +472,9 @@ function mapClaudeCodeFinishReason(subtype, stopReason) {
|
|
|
437
472
|
// src/validation.ts
|
|
438
473
|
var import_zod = require("zod");
|
|
439
474
|
var import_fs = require("fs");
|
|
475
|
+
function isBlankResume(value) {
|
|
476
|
+
return typeof value === "string" && value.trim() === "";
|
|
477
|
+
}
|
|
440
478
|
var loggerFunctionSchema = import_zod.z.object({
|
|
441
479
|
debug: import_zod.z.any().refine((val) => typeof val === "function", {
|
|
442
480
|
message: "debug must be a function"
|
|
@@ -457,23 +495,29 @@ var claudeCodeSettingsSchema = import_zod.z.object({
|
|
|
457
495
|
appendSystemPrompt: import_zod.z.string().optional(),
|
|
458
496
|
systemPrompt: import_zod.z.union([
|
|
459
497
|
import_zod.z.string(),
|
|
498
|
+
import_zod.z.array(import_zod.z.string()),
|
|
460
499
|
import_zod.z.object({
|
|
461
500
|
type: import_zod.z.literal("preset"),
|
|
462
501
|
preset: import_zod.z.literal("claude_code"),
|
|
463
|
-
append: import_zod.z.string().optional()
|
|
502
|
+
append: import_zod.z.string().optional(),
|
|
503
|
+
excludeDynamicSections: import_zod.z.boolean().optional()
|
|
464
504
|
})
|
|
465
505
|
]).optional(),
|
|
466
506
|
maxTurns: import_zod.z.number().int().min(1).max(100).optional(),
|
|
467
507
|
maxThinkingTokens: import_zod.z.number().int().positive().max(1e5).optional(),
|
|
468
508
|
thinking: import_zod.z.union([
|
|
469
|
-
import_zod.z.object({
|
|
509
|
+
import_zod.z.object({
|
|
510
|
+
type: import_zod.z.literal("adaptive"),
|
|
511
|
+
display: import_zod.z.enum(["summarized", "omitted"]).optional()
|
|
512
|
+
}).strict(),
|
|
470
513
|
import_zod.z.object({
|
|
471
514
|
type: import_zod.z.literal("enabled"),
|
|
472
|
-
budgetTokens: import_zod.z.number().int().positive().optional()
|
|
515
|
+
budgetTokens: import_zod.z.number().int().positive().optional(),
|
|
516
|
+
display: import_zod.z.enum(["summarized", "omitted"]).optional()
|
|
473
517
|
}).strict(),
|
|
474
518
|
import_zod.z.object({ type: import_zod.z.literal("disabled") }).strict()
|
|
475
519
|
]).optional(),
|
|
476
|
-
effort: import_zod.z.enum(["low", "medium", "high", "max"]).optional(),
|
|
520
|
+
effort: import_zod.z.enum(["low", "medium", "high", "xhigh", "max"]).optional(),
|
|
477
521
|
promptSuggestions: import_zod.z.boolean().optional(),
|
|
478
522
|
cwd: import_zod.z.string().refine(
|
|
479
523
|
(val) => {
|
|
@@ -486,11 +530,19 @@ var claudeCodeSettingsSchema = import_zod.z.object({
|
|
|
486
530
|
).optional(),
|
|
487
531
|
executable: import_zod.z.enum(["bun", "deno", "node"]).optional(),
|
|
488
532
|
executableArgs: import_zod.z.array(import_zod.z.string()).optional(),
|
|
489
|
-
|
|
533
|
+
// Mirrors the SDK 0.3.x PermissionMode union ('auto' and 'dontAsk' were
|
|
534
|
+
// added in 0.3.x; 'delegate' was dropped AND is rejected by the CLI's
|
|
535
|
+
// --permission-mode flag parser, so it is rejected here too).
|
|
536
|
+
permissionMode: import_zod.z.enum(["default", "acceptEdits", "bypassPermissions", "plan", "dontAsk", "auto"]).optional(),
|
|
490
537
|
permissionPromptToolName: import_zod.z.string().optional(),
|
|
491
538
|
continue: import_zod.z.boolean().optional(),
|
|
492
539
|
resume: import_zod.z.string().optional(),
|
|
493
|
-
|
|
540
|
+
// The CLI rejects --session-id values that are not valid UUIDs, so
|
|
541
|
+
// enforce the UUID shape here instead of failing at query time.
|
|
542
|
+
sessionId: import_zod.z.string().refine(
|
|
543
|
+
(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),
|
|
544
|
+
{ message: "sessionId must be a valid UUID (the CLI rejects non-UUID session IDs)" }
|
|
545
|
+
).optional(),
|
|
494
546
|
allowedTools: import_zod.z.array(import_zod.z.string()).optional(),
|
|
495
547
|
disallowedTools: import_zod.z.array(import_zod.z.string()).optional(),
|
|
496
548
|
betas: import_zod.z.array(import_zod.z.string()).optional(),
|
|
@@ -499,7 +551,9 @@ var claudeCodeSettingsSchema = import_zod.z.object({
|
|
|
499
551
|
maxBudgetUsd: import_zod.z.number().min(0).optional(),
|
|
500
552
|
plugins: import_zod.z.array(
|
|
501
553
|
import_zod.z.object({
|
|
502
|
-
|
|
554
|
+
// SDK SdkPluginConfig: only 'local' is supported; the SDK throws
|
|
555
|
+
// 'Unsupported plugin type' at query time for anything else.
|
|
556
|
+
type: import_zod.z.literal("local"),
|
|
503
557
|
path: import_zod.z.string()
|
|
504
558
|
}).passthrough()
|
|
505
559
|
).optional(),
|
|
@@ -514,12 +568,41 @@ var claudeCodeSettingsSchema = import_zod.z.object({
|
|
|
514
568
|
preset: import_zod.z.literal("claude_code")
|
|
515
569
|
})
|
|
516
570
|
]).optional(),
|
|
571
|
+
skills: import_zod.z.union([import_zod.z.array(import_zod.z.string()), import_zod.z.literal("all")]).optional(),
|
|
572
|
+
settings: import_zod.z.union([
|
|
573
|
+
import_zod.z.string(),
|
|
574
|
+
import_zod.z.record(import_zod.z.string(), import_zod.z.any())
|
|
575
|
+
// inline Settings object
|
|
576
|
+
]).optional(),
|
|
577
|
+
managedSettings: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional(),
|
|
578
|
+
toolAliases: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
579
|
+
toolConfig: import_zod.z.object({
|
|
580
|
+
askUserQuestion: import_zod.z.object({
|
|
581
|
+
previewFormat: import_zod.z.enum(["markdown", "html"]).optional()
|
|
582
|
+
}).passthrough().optional()
|
|
583
|
+
}).passthrough().optional(),
|
|
584
|
+
planModeInstructions: import_zod.z.string().optional(),
|
|
585
|
+
title: import_zod.z.string().optional(),
|
|
586
|
+
forwardSubagentText: import_zod.z.boolean().optional(),
|
|
587
|
+
agentProgressSummaries: import_zod.z.boolean().optional(),
|
|
588
|
+
includeHookEvents: import_zod.z.boolean().optional(),
|
|
589
|
+
taskBudget: import_zod.z.object({ total: import_zod.z.number().positive() }).strict().optional(),
|
|
590
|
+
sessionStore: import_zod.z.any().refine(
|
|
591
|
+
(val) => val === void 0 || typeof val === "object" && val !== null && typeof val.append === "function" && typeof val.load === "function",
|
|
592
|
+
{ message: "sessionStore must be an object with append() and load() functions" }
|
|
593
|
+
).optional(),
|
|
594
|
+
sessionStoreFlush: import_zod.z.enum(["batched", "eager"]).optional(),
|
|
595
|
+
loadTimeoutMs: import_zod.z.number().int().positive().optional(),
|
|
517
596
|
settingSources: import_zod.z.array(import_zod.z.enum(["user", "project", "local"])).optional(),
|
|
518
597
|
streamingInput: import_zod.z.enum(["auto", "always", "off"]).optional(),
|
|
519
598
|
// Hooks and tool-permission callback (permissive validation of shapes)
|
|
520
599
|
canUseTool: import_zod.z.any().refine((v) => v === void 0 || typeof v === "function", {
|
|
521
600
|
message: "canUseTool must be a function"
|
|
522
601
|
}).optional(),
|
|
602
|
+
onUserDialog: import_zod.z.any().refine((v) => v === void 0 || typeof v === "function", {
|
|
603
|
+
message: "onUserDialog must be a function"
|
|
604
|
+
}).optional(),
|
|
605
|
+
supportedDialogKinds: import_zod.z.array(import_zod.z.string()).optional(),
|
|
523
606
|
hooks: import_zod.z.record(
|
|
524
607
|
import_zod.z.string(),
|
|
525
608
|
import_zod.z.array(
|
|
@@ -572,7 +655,8 @@ var claudeCodeSettingsSchema = import_zod.z.object({
|
|
|
572
655
|
tools: import_zod.z.array(import_zod.z.string()).optional(),
|
|
573
656
|
disallowedTools: import_zod.z.array(import_zod.z.string()).optional(),
|
|
574
657
|
prompt: import_zod.z.string(),
|
|
575
|
-
|
|
658
|
+
// SDK 0.3.x AgentDefinition accepts any model alias or full model ID
|
|
659
|
+
model: import_zod.z.string().optional(),
|
|
576
660
|
mcpServers: import_zod.z.array(
|
|
577
661
|
import_zod.z.union([
|
|
578
662
|
import_zod.z.string(),
|
|
@@ -603,10 +687,14 @@ var claudeCodeSettingsSchema = import_zod.z.object({
|
|
|
603
687
|
}).optional(),
|
|
604
688
|
onStreamStart: import_zod.z.any().refine((val) => val === void 0 || typeof val === "function", {
|
|
605
689
|
message: "onStreamStart must be a function"
|
|
690
|
+
}).optional(),
|
|
691
|
+
// Callback invoked with the predicted next user prompt (active unless promptSuggestions: false)
|
|
692
|
+
onPromptSuggestion: import_zod.z.any().refine((val) => val === void 0 || typeof val === "function", {
|
|
693
|
+
message: "onPromptSuggestion must be a function"
|
|
606
694
|
}).optional()
|
|
607
695
|
}).strict();
|
|
608
696
|
function validateModelId(modelId) {
|
|
609
|
-
const knownModels = ["opus", "sonnet", "haiku"];
|
|
697
|
+
const knownModels = ["opus", "sonnet", "haiku", "fable"];
|
|
610
698
|
if (!modelId || modelId.trim() === "") {
|
|
611
699
|
throw new Error("Model ID cannot be empty");
|
|
612
700
|
}
|
|
@@ -630,6 +718,51 @@ function validateSettings(settings) {
|
|
|
630
718
|
return { valid: false, warnings, errors };
|
|
631
719
|
}
|
|
632
720
|
const validSettings = result.data;
|
|
721
|
+
const sdkOptionsRecord = validSettings.sdkOptions;
|
|
722
|
+
const effective = (key) => {
|
|
723
|
+
const override = sdkOptionsRecord?.[key];
|
|
724
|
+
return override !== void 0 ? override : validSettings[key];
|
|
725
|
+
};
|
|
726
|
+
const effSessionStore = effective("sessionStore");
|
|
727
|
+
const effectiveResumeId = () => {
|
|
728
|
+
for (const candidate of [sdkOptionsRecord?.resume, validSettings.resume]) {
|
|
729
|
+
if (typeof candidate === "string" && !isBlankResume(candidate)) {
|
|
730
|
+
return candidate;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
return void 0;
|
|
734
|
+
};
|
|
735
|
+
if (effSessionStore !== void 0 && effective("persistSession") === false) {
|
|
736
|
+
errors.push(
|
|
737
|
+
"sessionStore cannot be combined with persistSession: false. Transcript mirroring requires local session writes; remove persistSession: false or drop sessionStore."
|
|
738
|
+
);
|
|
739
|
+
return { valid: false, warnings, errors };
|
|
740
|
+
}
|
|
741
|
+
if (effSessionStore !== void 0 && effective("enableFileCheckpointing") === true) {
|
|
742
|
+
errors.push(
|
|
743
|
+
"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."
|
|
744
|
+
);
|
|
745
|
+
return { valid: false, warnings, errors };
|
|
746
|
+
}
|
|
747
|
+
if (effective("continue") === true && effSessionStore !== void 0 && effectiveResumeId() === void 0 && typeof effSessionStore.listSessions !== "function") {
|
|
748
|
+
errors.push(
|
|
749
|
+
"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."
|
|
750
|
+
);
|
|
751
|
+
return { valid: false, warnings, errors };
|
|
752
|
+
}
|
|
753
|
+
const effSettingsOption = effective("settings");
|
|
754
|
+
if (effective("sandbox") !== void 0 && typeof effSettingsOption === "string" && !(effSettingsOption.trim().startsWith("{") && effSettingsOption.trim().endsWith("}"))) {
|
|
755
|
+
errors.push(
|
|
756
|
+
"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."
|
|
757
|
+
);
|
|
758
|
+
return { valid: false, warnings, errors };
|
|
759
|
+
}
|
|
760
|
+
if (effective("sessionId") !== void 0 && effective("forkSession") !== true && (effective("continue") === true || effectiveResumeId() !== void 0)) {
|
|
761
|
+
errors.push(
|
|
762
|
+
"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."
|
|
763
|
+
);
|
|
764
|
+
return { valid: false, warnings, errors };
|
|
765
|
+
}
|
|
633
766
|
if (validSettings.maxTurns && validSettings.maxTurns > 20) {
|
|
634
767
|
warnings.push(
|
|
635
768
|
`High maxTurns value (${validSettings.maxTurns}) may lead to long-running conversations`
|
|
@@ -658,11 +791,30 @@ function validateSettings(settings) {
|
|
|
658
791
|
if (validSettings.disallowedTools) {
|
|
659
792
|
validateToolNames(validSettings.disallowedTools, "disallowed");
|
|
660
793
|
}
|
|
661
|
-
|
|
794
|
+
const effDialogKinds = effective("supportedDialogKinds");
|
|
795
|
+
if (Array.isArray(effDialogKinds) && effDialogKinds.length > 0 && effective("onUserDialog") == null) {
|
|
796
|
+
errors.push(
|
|
797
|
+
"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."
|
|
798
|
+
);
|
|
799
|
+
return { valid: false, warnings, errors };
|
|
800
|
+
}
|
|
801
|
+
const effAllowedTools = effective("allowedTools");
|
|
802
|
+
if (Array.isArray(effAllowedTools) && effAllowedTools.includes("Skill") && !effective("settingSources")) {
|
|
662
803
|
warnings.push(
|
|
663
804
|
"allowedTools includes 'Skill' but settingSources is not set. Skills require settingSources (e.g., ['user', 'project']) to load skill definitions."
|
|
664
805
|
);
|
|
665
806
|
}
|
|
807
|
+
if (validSettings.agents) {
|
|
808
|
+
const knownAgentModelAliases = ["sonnet", "opus", "haiku", "fable", "inherit"];
|
|
809
|
+
for (const [agentName, agent] of Object.entries(validSettings.agents)) {
|
|
810
|
+
const agentModel = agent.model;
|
|
811
|
+
if (agentModel !== void 0 && !knownAgentModelAliases.includes(agentModel) && !agentModel.includes("-")) {
|
|
812
|
+
warnings.push(
|
|
813
|
+
`Unknown model alias '${agentModel}' for agent '${agentName}'. Known aliases are: ${knownAgentModelAliases.join(", ")}; full model IDs (e.g. 'claude-sonnet-4-5') are also accepted.`
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
666
818
|
return { valid: true, warnings, errors };
|
|
667
819
|
} catch (error) {
|
|
668
820
|
errors.push(`Validation error: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -683,6 +835,137 @@ function validateSessionId(sessionId) {
|
|
|
683
835
|
return void 0;
|
|
684
836
|
}
|
|
685
837
|
|
|
838
|
+
// src/sanitize-json-schema.ts
|
|
839
|
+
var SUBSCHEMA_MAP_KEYWORDS = [
|
|
840
|
+
"properties",
|
|
841
|
+
"patternProperties",
|
|
842
|
+
"$defs",
|
|
843
|
+
"definitions",
|
|
844
|
+
"dependentSchemas",
|
|
845
|
+
// draft-07 `dependencies` values are either subschemas (schema form) or
|
|
846
|
+
// arrays of property-name strings (array form); sanitizeNode passes
|
|
847
|
+
// string arrays through untouched, so walking both forms is safe.
|
|
848
|
+
"dependencies"
|
|
849
|
+
];
|
|
850
|
+
var SUBSCHEMA_KEYWORDS = [
|
|
851
|
+
"items",
|
|
852
|
+
// may also be an array of subschemas (draft-07 tuple form)
|
|
853
|
+
"additionalItems",
|
|
854
|
+
"additionalProperties",
|
|
855
|
+
"unevaluatedItems",
|
|
856
|
+
"unevaluatedProperties",
|
|
857
|
+
"not",
|
|
858
|
+
"contains",
|
|
859
|
+
"propertyNames",
|
|
860
|
+
"contentSchema",
|
|
861
|
+
"if",
|
|
862
|
+
"then",
|
|
863
|
+
"else"
|
|
864
|
+
];
|
|
865
|
+
var SUBSCHEMA_LIST_KEYWORDS = ["prefixItems", "anyOf", "oneOf", "allOf"];
|
|
866
|
+
function sanitizeJsonSchemaForOutputFormat(schema) {
|
|
867
|
+
const strippedFormatPaths = [];
|
|
868
|
+
const sanitized = sanitizeNode(schema, "#", /* @__PURE__ */ new WeakSet(), strippedFormatPaths);
|
|
869
|
+
return {
|
|
870
|
+
schema: sanitized ?? schema,
|
|
871
|
+
strippedFormatPaths
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
function sanitizeNode(node, path, visiting, strippedFormatPaths) {
|
|
875
|
+
if (typeof node !== "object" || node === null) {
|
|
876
|
+
return node;
|
|
877
|
+
}
|
|
878
|
+
if (visiting.has(node)) {
|
|
879
|
+
return node;
|
|
880
|
+
}
|
|
881
|
+
visiting.add(node);
|
|
882
|
+
try {
|
|
883
|
+
if (Array.isArray(node)) {
|
|
884
|
+
return sanitizeList(node, path, visiting, strippedFormatPaths);
|
|
885
|
+
}
|
|
886
|
+
const record = node;
|
|
887
|
+
let result = record;
|
|
888
|
+
const setKey = (key, value) => {
|
|
889
|
+
if (result === record) {
|
|
890
|
+
result = { ...record };
|
|
891
|
+
}
|
|
892
|
+
result[key] = value;
|
|
893
|
+
};
|
|
894
|
+
if (typeof record.format === "string") {
|
|
895
|
+
const format = record.format;
|
|
896
|
+
const existingDescription = record.description;
|
|
897
|
+
result = { ...record };
|
|
898
|
+
delete result.format;
|
|
899
|
+
if (typeof existingDescription === "string" && existingDescription.length > 0) {
|
|
900
|
+
result.description = `${existingDescription} (expected format: ${format})`;
|
|
901
|
+
} else if (existingDescription === void 0 || existingDescription === "") {
|
|
902
|
+
result.description = `Expected format: ${format}`;
|
|
903
|
+
}
|
|
904
|
+
strippedFormatPaths.push(path);
|
|
905
|
+
}
|
|
906
|
+
for (const keyword of SUBSCHEMA_MAP_KEYWORDS) {
|
|
907
|
+
const map = record[keyword];
|
|
908
|
+
if (typeof map !== "object" || map === null || Array.isArray(map)) continue;
|
|
909
|
+
const mapRecord = map;
|
|
910
|
+
let newMap = mapRecord;
|
|
911
|
+
for (const [name, child] of Object.entries(mapRecord)) {
|
|
912
|
+
const sanitizedChild = sanitizeNode(
|
|
913
|
+
child,
|
|
914
|
+
`${path}/${keyword}/${name}`,
|
|
915
|
+
visiting,
|
|
916
|
+
strippedFormatPaths
|
|
917
|
+
);
|
|
918
|
+
if (sanitizedChild !== child) {
|
|
919
|
+
if (newMap === mapRecord) {
|
|
920
|
+
newMap = { ...mapRecord };
|
|
921
|
+
}
|
|
922
|
+
newMap[name] = sanitizedChild;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
if (newMap !== mapRecord) {
|
|
926
|
+
setKey(keyword, newMap);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
for (const keyword of SUBSCHEMA_KEYWORDS) {
|
|
930
|
+
const child = record[keyword];
|
|
931
|
+
if (typeof child !== "object" || child === null) continue;
|
|
932
|
+
const sanitizedChild = sanitizeNode(
|
|
933
|
+
child,
|
|
934
|
+
`${path}/${keyword}`,
|
|
935
|
+
visiting,
|
|
936
|
+
strippedFormatPaths
|
|
937
|
+
);
|
|
938
|
+
if (sanitizedChild !== child) {
|
|
939
|
+
setKey(keyword, sanitizedChild);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
for (const keyword of SUBSCHEMA_LIST_KEYWORDS) {
|
|
943
|
+
const list = record[keyword];
|
|
944
|
+
if (!Array.isArray(list)) continue;
|
|
945
|
+
const sanitizedList = sanitizeList(list, `${path}/${keyword}`, visiting, strippedFormatPaths);
|
|
946
|
+
if (sanitizedList !== list) {
|
|
947
|
+
setKey(keyword, sanitizedList);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return result;
|
|
951
|
+
} finally {
|
|
952
|
+
visiting.delete(node);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
function sanitizeList(list, path, visiting, strippedFormatPaths) {
|
|
956
|
+
let result = list;
|
|
957
|
+
for (let i = 0; i < list.length; i++) {
|
|
958
|
+
const sanitizedChild = sanitizeNode(list[i], `${path}/${i}`, visiting, strippedFormatPaths);
|
|
959
|
+
if (sanitizedChild !== list[i]) {
|
|
960
|
+
if (result === list) {
|
|
961
|
+
result = [...list];
|
|
962
|
+
}
|
|
963
|
+
result[i] = sanitizedChild;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
return result;
|
|
967
|
+
}
|
|
968
|
+
|
|
686
969
|
// src/logger.ts
|
|
687
970
|
var defaultLogger = {
|
|
688
971
|
// eslint-disable-next-line no-console
|
|
@@ -729,6 +1012,8 @@ function createVerboseLogger(logger, verbose = false) {
|
|
|
729
1012
|
|
|
730
1013
|
// src/claude-code-language-model.ts
|
|
731
1014
|
var import_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
|
|
1015
|
+
var PROVIDER_VERSION = "3.5.0";
|
|
1016
|
+
var DEFAULT_CLIENT_APP = `ai-sdk-provider-claude-code/${PROVIDER_VERSION}`;
|
|
732
1017
|
var CLAUDE_CODE_TRUNCATION_WARNING = "Claude Code SDK output ended unexpectedly; returning truncated response from buffered text. Await upstream fix to avoid data loss.";
|
|
733
1018
|
var MIN_TRUNCATION_LENGTH = 512;
|
|
734
1019
|
function isClaudeCodeTruncationError(error, bufferedText) {
|
|
@@ -760,6 +1045,34 @@ function isClaudeCodeTruncationError(error, bufferedText) {
|
|
|
760
1045
|
}
|
|
761
1046
|
return true;
|
|
762
1047
|
}
|
|
1048
|
+
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.";
|
|
1049
|
+
function extractJsonObjectText(text) {
|
|
1050
|
+
const trimmed = text.trim();
|
|
1051
|
+
if (!trimmed) {
|
|
1052
|
+
return void 0;
|
|
1053
|
+
}
|
|
1054
|
+
const candidates = [trimmed];
|
|
1055
|
+
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);
|
|
1056
|
+
candidates.push(...fencedBlocks.reverse());
|
|
1057
|
+
for (const candidate of candidates) {
|
|
1058
|
+
if (!candidate) continue;
|
|
1059
|
+
try {
|
|
1060
|
+
const parsed = JSON.parse(candidate);
|
|
1061
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
1062
|
+
return candidate;
|
|
1063
|
+
}
|
|
1064
|
+
} catch {
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
return void 0;
|
|
1068
|
+
}
|
|
1069
|
+
function getStructuredErrorKind(error) {
|
|
1070
|
+
if (typeof error === "object" && error !== null && "errorKind" in error) {
|
|
1071
|
+
const kind = error.errorKind;
|
|
1072
|
+
if (typeof kind === "string") return kind;
|
|
1073
|
+
}
|
|
1074
|
+
return void 0;
|
|
1075
|
+
}
|
|
763
1076
|
function isAbortError(err) {
|
|
764
1077
|
if (err && typeof err === "object") {
|
|
765
1078
|
const e = err;
|
|
@@ -770,6 +1083,7 @@ function isAbortError(err) {
|
|
|
770
1083
|
}
|
|
771
1084
|
var DEFAULT_INHERITED_ENV_VARS = process.platform === "win32" ? [
|
|
772
1085
|
"APPDATA",
|
|
1086
|
+
"COMSPEC",
|
|
773
1087
|
"HOMEDRIVE",
|
|
774
1088
|
"HOMEPATH",
|
|
775
1089
|
"LOCALAPPDATA",
|
|
@@ -784,23 +1098,89 @@ var DEFAULT_INHERITED_ENV_VARS = process.platform === "win32" ? [
|
|
|
784
1098
|
"WINDIR"
|
|
785
1099
|
] : ["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER", "LANG", "LC_ALL", "TMPDIR"];
|
|
786
1100
|
var CLAUDE_ENV_VARS = ["CLAUDE_CONFIG_DIR"];
|
|
1101
|
+
var NETWORK_ENV_VARS = [
|
|
1102
|
+
"HTTP_PROXY",
|
|
1103
|
+
"HTTPS_PROXY",
|
|
1104
|
+
"NO_PROXY",
|
|
1105
|
+
"http_proxy",
|
|
1106
|
+
"https_proxy",
|
|
1107
|
+
"no_proxy",
|
|
1108
|
+
"NODE_EXTRA_CA_CERTS",
|
|
1109
|
+
"SSL_CERT_FILE",
|
|
1110
|
+
"SSL_CERT_DIR"
|
|
1111
|
+
];
|
|
1112
|
+
var CLOUD_ENV_VARS = ["GCLOUD_PROJECT", "CLOUD_ML_REGION"];
|
|
1113
|
+
var INHERITED_ENV_PREFIXES = ["ANTHROPIC_", "CLAUDE_", "AWS_", "GOOGLE_"];
|
|
787
1114
|
function getBaseProcessEnv() {
|
|
788
1115
|
const env = {};
|
|
789
|
-
const allowedKeys = /* @__PURE__ */ new Set([
|
|
790
|
-
|
|
1116
|
+
const allowedKeys = /* @__PURE__ */ new Set([
|
|
1117
|
+
...DEFAULT_INHERITED_ENV_VARS,
|
|
1118
|
+
...CLAUDE_ENV_VARS,
|
|
1119
|
+
...NETWORK_ENV_VARS,
|
|
1120
|
+
...CLOUD_ENV_VARS
|
|
1121
|
+
]);
|
|
1122
|
+
const addIfSafe = (key) => {
|
|
791
1123
|
const value = process.env[key];
|
|
792
1124
|
if (typeof value !== "string") {
|
|
793
|
-
|
|
1125
|
+
return;
|
|
794
1126
|
}
|
|
795
1127
|
if (value.startsWith("()")) {
|
|
796
|
-
|
|
1128
|
+
return;
|
|
797
1129
|
}
|
|
798
1130
|
env[key] = value;
|
|
1131
|
+
};
|
|
1132
|
+
for (const key of allowedKeys) {
|
|
1133
|
+
addIfSafe(key);
|
|
1134
|
+
}
|
|
1135
|
+
for (const key of Object.keys(process.env)) {
|
|
1136
|
+
if (INHERITED_ENV_PREFIXES.some((prefix) => key.startsWith(prefix))) {
|
|
1137
|
+
addIfSafe(key);
|
|
1138
|
+
}
|
|
799
1139
|
}
|
|
800
1140
|
return env;
|
|
801
1141
|
}
|
|
802
1142
|
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).";
|
|
803
1143
|
var SDK_OPTIONS_BLOCKLIST = /* @__PURE__ */ new Set(["model", "abortController", "prompt", "outputFormat"]);
|
|
1144
|
+
var SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
|
|
1145
|
+
function isSubagentToolName(name) {
|
|
1146
|
+
return SUBAGENT_TOOL_NAMES.has(name);
|
|
1147
|
+
}
|
|
1148
|
+
function resolveToolParentId(messageLevel, blockLevel, inferFallback) {
|
|
1149
|
+
if (messageLevel !== void 0) return messageLevel;
|
|
1150
|
+
if (typeof blockLevel === "string") return blockLevel;
|
|
1151
|
+
return inferFallback();
|
|
1152
|
+
}
|
|
1153
|
+
function computeRetractedToolCallIds(retracted, descriptors) {
|
|
1154
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1155
|
+
for (const { toolCallId, uuid } of descriptors) {
|
|
1156
|
+
if (uuid !== void 0 && retracted.has(uuid)) {
|
|
1157
|
+
ids.add(toolCallId);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
return ids;
|
|
1161
|
+
}
|
|
1162
|
+
function applySupersede(message, evict, logger, guard = "array") {
|
|
1163
|
+
const supersedes = message.supersedes;
|
|
1164
|
+
const triggered = guard === "truthy" ? Boolean(supersedes && supersedes.length > 0) : Array.isArray(supersedes) && supersedes.length > 0;
|
|
1165
|
+
if (!triggered) {
|
|
1166
|
+
return false;
|
|
1167
|
+
}
|
|
1168
|
+
logger.debug(`[claude-code] Assistant message supersedes ${supersedes.length} prior message(s)`);
|
|
1169
|
+
evict(new Set(supersedes));
|
|
1170
|
+
return true;
|
|
1171
|
+
}
|
|
1172
|
+
function buildRetractionEvictor(evict) {
|
|
1173
|
+
return (uuids) => evict(new Set(uuids));
|
|
1174
|
+
}
|
|
1175
|
+
var INFORMATIONAL_SYSTEM_SUBTYPES = /* @__PURE__ */ new Set([
|
|
1176
|
+
"notification",
|
|
1177
|
+
"status",
|
|
1178
|
+
"task_updated",
|
|
1179
|
+
"session_state_changed",
|
|
1180
|
+
"commands_changed",
|
|
1181
|
+
"memory_recall",
|
|
1182
|
+
"plugin_install"
|
|
1183
|
+
]);
|
|
804
1184
|
function isContentBlock(item) {
|
|
805
1185
|
return typeof item === "object" && item !== null && "type" in item;
|
|
806
1186
|
}
|
|
@@ -1023,6 +1403,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1023
1403
|
// 100KB warning threshold
|
|
1024
1404
|
static MAX_DELTA_CALC_SIZE = 1e4;
|
|
1025
1405
|
// 10KB delta computation threshold
|
|
1406
|
+
// Upper bound for draining post-result messages (prompt_suggestion) so a
|
|
1407
|
+
// lingering CLI subprocess cannot be held open indefinitely after finish.
|
|
1408
|
+
static PROMPT_SUGGESTION_DRAIN_TIMEOUT_MS = 1e4;
|
|
1026
1409
|
modelId;
|
|
1027
1410
|
settings;
|
|
1028
1411
|
sessionId;
|
|
@@ -1070,27 +1453,71 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1070
1453
|
return sanitized;
|
|
1071
1454
|
}
|
|
1072
1455
|
getEffectiveResume(sdkOptions) {
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
if (!Array.isArray(content)) return { text: "", thinking: [] };
|
|
1077
|
-
let text = "";
|
|
1078
|
-
const thinking = [];
|
|
1079
|
-
for (const part of content) {
|
|
1080
|
-
if (!isContentBlock(part)) continue;
|
|
1081
|
-
if (part.type === "text" && typeof part.text === "string") {
|
|
1082
|
-
text += part.text;
|
|
1083
|
-
} else if (part.type === "thinking" && typeof part.thinking === "string") {
|
|
1084
|
-
thinking.push(part.thinking);
|
|
1456
|
+
for (const candidate of [sdkOptions?.resume, this.settings.resume, this.sessionId]) {
|
|
1457
|
+
if (typeof candidate === "string" && !isBlankResume(candidate)) {
|
|
1458
|
+
return candidate;
|
|
1085
1459
|
}
|
|
1086
1460
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1461
|
+
return void 0;
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Single source of truth for the CLI's `--session-id` exclusivity rule.
|
|
1465
|
+
*
|
|
1466
|
+
* The CLI rejects `--session-id` together with `--resume`/`--continue`
|
|
1467
|
+
* unless `--fork-session` is also set (forkSession then names the forked
|
|
1468
|
+
* session's own ID). This predicate captures "there IS a resume/continue
|
|
1469
|
+
* target AND we are not forking", i.e. the case where a session id must NOT
|
|
1470
|
+
* coexist. It is referenced by both:
|
|
1471
|
+
* - the pre-merge forwarding guard (via its inverse), which decides whether
|
|
1472
|
+
* to forward `settings.sessionId` onto the base options, and
|
|
1473
|
+
* - the post-merge exclusivity drop, which removes any session id that the
|
|
1474
|
+
* generic sdkOptions overlay (or the auto-resume turn) re-introduced.
|
|
1475
|
+
*
|
|
1476
|
+
* Keeping one definition guarantees both sites agree on what "conflicts with
|
|
1477
|
+
* a session id" means. The mirror in validation.ts (construction-time)
|
|
1478
|
+
* intentionally stays separate: it reads settings+sdkOptions, not a built
|
|
1479
|
+
* opts object.
|
|
1480
|
+
*/
|
|
1481
|
+
static sessionIdConflictsWithResumeOrContinue(args) {
|
|
1482
|
+
return (args.resumePresent || args.continue) && !args.forkSession;
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Owns ALL session-id / resume cross-option resolution on the FINAL merged
|
|
1486
|
+
* options, in the single correct order. Called once, immediately after the
|
|
1487
|
+
* generic sdkOptions overlay in createQueryOptions.
|
|
1488
|
+
*
|
|
1489
|
+
* Two concerns, in this exact order (order matters: step 1 can change whether
|
|
1490
|
+
* step 2 sees a resume target):
|
|
1491
|
+
*
|
|
1492
|
+
* 1. Blank-resume restoration. The overlay copies the raw `sdkOptions.resume`
|
|
1493
|
+
* verbatim, which can re-introduce a blank/whitespace value over the
|
|
1494
|
+
* base `resume` that getEffectiveResume already normalized. The SDK treats
|
|
1495
|
+
* a blank resume as absent, so a blank must NOT clobber the computed
|
|
1496
|
+
* fallback — restore `effectiveResume` (already blank-stripped; may itself
|
|
1497
|
+
* be undefined for a genuinely new session) rather than leaving '' or
|
|
1498
|
+
* forcing undefined, which would erase a real settings.resume / captured
|
|
1499
|
+
* session id.
|
|
1500
|
+
*
|
|
1501
|
+
* 2. Session-id exclusivity. Drop `opts.sessionId` whenever it conflicts with
|
|
1502
|
+
* a resume/continue target (see sessionIdConflictsWithResumeOrContinue).
|
|
1503
|
+
* This runs on the merged opts so it catches a sessionId re-added by the
|
|
1504
|
+
* sdkOptions overlay AND the auto-resumed second turn (where resume was
|
|
1505
|
+
* populated from the captured session id). It complements — does not
|
|
1506
|
+
* replace — the pre-merge forwarding guard, which governs whether
|
|
1507
|
+
* settings.sessionId was forwarded BEFORE the overlay could mutate
|
|
1508
|
+
* forkSession/continue/resume.
|
|
1509
|
+
*/
|
|
1510
|
+
applySessionResolution(opts, effectiveResume) {
|
|
1511
|
+
if (isBlankResume(opts.resume)) {
|
|
1512
|
+
opts.resume = effectiveResume;
|
|
1513
|
+
}
|
|
1514
|
+
if (opts.sessionId !== void 0 && _ClaudeCodeLanguageModel.sessionIdConflictsWithResumeOrContinue({
|
|
1515
|
+
resumePresent: opts.resume !== void 0,
|
|
1516
|
+
continue: opts.continue === true,
|
|
1517
|
+
forkSession: opts.forkSession === true
|
|
1518
|
+
})) {
|
|
1519
|
+
opts.sessionId = void 0;
|
|
1092
1520
|
}
|
|
1093
|
-
return { text, thinking };
|
|
1094
1521
|
}
|
|
1095
1522
|
extractToolUses(content) {
|
|
1096
1523
|
return filterContentBlocks(content, "tool_use").map((block) => {
|
|
@@ -1184,6 +1611,153 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1184
1611
|
}
|
|
1185
1612
|
return result;
|
|
1186
1613
|
}
|
|
1614
|
+
/**
|
|
1615
|
+
* Builds a provider-executed `tool-call` part from an assistant `tool_use`
|
|
1616
|
+
* block. Shared by doGenerate (content part) and doStream (stream part) so
|
|
1617
|
+
* the two paths cannot drift in field shape.
|
|
1618
|
+
*/
|
|
1619
|
+
buildToolCallPart(toolCallId, toolName, input, parentToolCallId) {
|
|
1620
|
+
return {
|
|
1621
|
+
type: "tool-call",
|
|
1622
|
+
toolCallId,
|
|
1623
|
+
toolName,
|
|
1624
|
+
input,
|
|
1625
|
+
providerExecuted: true,
|
|
1626
|
+
dynamic: true,
|
|
1627
|
+
// V3 field: indicates tool is provider-defined (not in user's tools map)
|
|
1628
|
+
providerMetadata: {
|
|
1629
|
+
"claude-code": {
|
|
1630
|
+
// rawInput preserves the original serialized format before AI SDK normalization.
|
|
1631
|
+
// Use this if you need the exact string sent to the Claude CLI, which may differ
|
|
1632
|
+
// from the `input` field after AI SDK processing.
|
|
1633
|
+
rawInput: input,
|
|
1634
|
+
parentToolCallId: parentToolCallId ?? null
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* Builds a provider-executed `tool-result` part from a user-message
|
|
1641
|
+
* `tool_result` block, applying normalization and `maxToolResultSize`
|
|
1642
|
+
* truncation. Shared by doGenerate and doStream.
|
|
1643
|
+
*/
|
|
1644
|
+
buildToolResultPart(toolCallId, toolName, result, isError, parentToolCallId) {
|
|
1645
|
+
const normalizedResult = this.normalizeToolResult(result);
|
|
1646
|
+
const rawResult = typeof result === "string" ? result : result === void 0 ? (
|
|
1647
|
+
// tool_result blocks may omit `content` entirely; '' keeps both
|
|
1648
|
+
// `result` (NonNullable<JSONValue>) and rawResult (JSONValue) valid.
|
|
1649
|
+
""
|
|
1650
|
+
) : (() => {
|
|
1651
|
+
try {
|
|
1652
|
+
return JSON.stringify(result) ?? String(result);
|
|
1653
|
+
} catch {
|
|
1654
|
+
return String(result);
|
|
1655
|
+
}
|
|
1656
|
+
})();
|
|
1657
|
+
const maxToolResultSize = this.settings.maxToolResultSize;
|
|
1658
|
+
const truncatedResult = truncateToolResultForStream(normalizedResult, maxToolResultSize);
|
|
1659
|
+
const truncatedRawResult = truncateToolResultForStream(rawResult, maxToolResultSize);
|
|
1660
|
+
const rawResultTruncated = truncatedRawResult !== rawResult;
|
|
1661
|
+
return {
|
|
1662
|
+
type: "tool-result",
|
|
1663
|
+
toolCallId,
|
|
1664
|
+
toolName,
|
|
1665
|
+
// `?? ''`: absent `content` (undefined) and string results that
|
|
1666
|
+
// normalize to JSON null (e.g. the string "null") must not violate the
|
|
1667
|
+
// NonNullable<JSONValue> contract of LanguageModelV3ToolResult.result.
|
|
1668
|
+
result: truncatedResult ?? "",
|
|
1669
|
+
isError,
|
|
1670
|
+
providerExecuted: true,
|
|
1671
|
+
dynamic: true,
|
|
1672
|
+
// V3 field: indicates tool is provider-defined
|
|
1673
|
+
providerMetadata: {
|
|
1674
|
+
"claude-code": {
|
|
1675
|
+
// rawResult preserves the original CLI output string before JSON parsing.
|
|
1676
|
+
// Use this when you need the exact string returned by the tool, especially
|
|
1677
|
+
// if the `result` field has been parsed/normalized and you need the original format.
|
|
1678
|
+
rawResult: truncatedRawResult,
|
|
1679
|
+
rawResultTruncated,
|
|
1680
|
+
parentToolCallId: parentToolCallId ?? null
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
serializeToolError(error) {
|
|
1686
|
+
return typeof error === "string" ? error : typeof error === "object" && error !== null ? (() => {
|
|
1687
|
+
try {
|
|
1688
|
+
return JSON.stringify(error) ?? String(error);
|
|
1689
|
+
} catch {
|
|
1690
|
+
return String(error);
|
|
1691
|
+
}
|
|
1692
|
+
})() : String(error);
|
|
1693
|
+
}
|
|
1694
|
+
/**
|
|
1695
|
+
* Builds a provider-executed `tool-error` STREAM part from a user-message
|
|
1696
|
+
* `tool_error` block (doStream only; AI SDK core handles tool-error stream
|
|
1697
|
+
* parts natively).
|
|
1698
|
+
*/
|
|
1699
|
+
buildToolErrorPart(toolCallId, toolName, error, parentToolCallId) {
|
|
1700
|
+
const rawError = this.serializeToolError(error);
|
|
1701
|
+
return {
|
|
1702
|
+
type: "tool-error",
|
|
1703
|
+
toolCallId,
|
|
1704
|
+
toolName,
|
|
1705
|
+
error: rawError,
|
|
1706
|
+
providerExecuted: true,
|
|
1707
|
+
dynamic: true,
|
|
1708
|
+
// V3 field: indicates tool is provider-defined
|
|
1709
|
+
providerMetadata: {
|
|
1710
|
+
"claude-code": {
|
|
1711
|
+
rawError,
|
|
1712
|
+
parentToolCallId: parentToolCallId ?? null
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
/**
|
|
1718
|
+
* Builds a V3 `tool-result` CONTENT part with `isError: true` from a
|
|
1719
|
+
* user-message `tool_error` block (doGenerate only). The V3 content union
|
|
1720
|
+
* has no `tool-error` member and AI SDK core's asContent() silently drops
|
|
1721
|
+
* unknown content part types, so an extension tool-error part would never
|
|
1722
|
+
* reach `generateText` users — an isError tool-result, by contrast,
|
|
1723
|
+
* round-trips into a proper tool-error part in steps content.
|
|
1724
|
+
*/
|
|
1725
|
+
buildToolErrorResultPart(toolCallId, toolName, error, parentToolCallId) {
|
|
1726
|
+
const rawError = this.serializeToolError(error);
|
|
1727
|
+
return {
|
|
1728
|
+
type: "tool-result",
|
|
1729
|
+
toolCallId,
|
|
1730
|
+
toolName,
|
|
1731
|
+
result: rawError,
|
|
1732
|
+
isError: true,
|
|
1733
|
+
providerExecuted: true,
|
|
1734
|
+
dynamic: true,
|
|
1735
|
+
// V3 field: indicates tool is provider-defined
|
|
1736
|
+
providerMetadata: {
|
|
1737
|
+
"claude-code": {
|
|
1738
|
+
rawError,
|
|
1739
|
+
parentToolCallId: parentToolCallId ?? null
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
/**
|
|
1745
|
+
* Policy (P3): late-frame drop guard, shared by all four tool_result/tool_error
|
|
1746
|
+
* sites (doGenerate result+error, doStream result+error). When a frame's tool
|
|
1747
|
+
* id is tombstoned (its tool-call was retracted by a supersede/refusal-fallback
|
|
1748
|
+
* signal), the frame must be DROPPED rather than re-synthesized into an orphan
|
|
1749
|
+
* tool-call. Centralizing the predicate + debug message keeps the four sites in
|
|
1750
|
+
* lockstep so a future tombstone change can't be applied to only some of them.
|
|
1751
|
+
*/
|
|
1752
|
+
isRetractedToolFrame(id, tombstone, frameKind) {
|
|
1753
|
+
if (!tombstone.has(id)) {
|
|
1754
|
+
return false;
|
|
1755
|
+
}
|
|
1756
|
+
this.logger.debug(
|
|
1757
|
+
`[claude-code] Dropping tool ${frameKind} for retracted (superseded) tool ID: ${id}`
|
|
1758
|
+
);
|
|
1759
|
+
return true;
|
|
1760
|
+
}
|
|
1187
1761
|
generateAllWarnings(options, prompt) {
|
|
1188
1762
|
const warnings = [];
|
|
1189
1763
|
const unsupportedParams = [];
|
|
@@ -1204,6 +1778,27 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1204
1778
|
});
|
|
1205
1779
|
}
|
|
1206
1780
|
}
|
|
1781
|
+
if (options.tools !== void 0 && options.tools.length > 0) {
|
|
1782
|
+
warnings.push({
|
|
1783
|
+
type: "unsupported",
|
|
1784
|
+
feature: "tools",
|
|
1785
|
+
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)."
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
if (options.toolChoice !== void 0 && options.toolChoice.type !== "auto") {
|
|
1789
|
+
warnings.push({
|
|
1790
|
+
type: "unsupported",
|
|
1791
|
+
feature: "toolChoice",
|
|
1792
|
+
details: `Claude Code CLI does not support toolChoice '${options.toolChoice.type}'. Only automatic tool selection is available; the toolChoice parameter will be ignored.`
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
if (options.maxOutputTokens !== void 0) {
|
|
1796
|
+
warnings.push({
|
|
1797
|
+
type: "unsupported",
|
|
1798
|
+
feature: "maxOutputTokens",
|
|
1799
|
+
details: "Claude Code CLI does not accept an output token cap. The maxOutputTokens parameter will be ignored."
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1207
1802
|
if (this.modelValidationWarning) {
|
|
1208
1803
|
warnings.push({
|
|
1209
1804
|
type: "other",
|
|
@@ -1236,7 +1831,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1236
1831
|
const opts = {
|
|
1237
1832
|
model: this.getModel(),
|
|
1238
1833
|
abortController,
|
|
1239
|
-
resume: effectiveResume
|
|
1834
|
+
resume: effectiveResume,
|
|
1240
1835
|
pathToClaudeCodeExecutable: this.settings.pathToClaudeCodeExecutable,
|
|
1241
1836
|
maxTurns: this.settings.maxTurns,
|
|
1242
1837
|
maxThinkingTokens: this.settings.maxThinkingTokens,
|
|
@@ -1262,6 +1857,12 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1262
1857
|
mcpServers: this.settings.mcpServers,
|
|
1263
1858
|
canUseTool: this.settings.canUseTool
|
|
1264
1859
|
};
|
|
1860
|
+
if (this.settings.onUserDialog !== void 0) {
|
|
1861
|
+
opts.onUserDialog = this.settings.onUserDialog;
|
|
1862
|
+
}
|
|
1863
|
+
if (this.settings.supportedDialogKinds !== void 0) {
|
|
1864
|
+
opts.supportedDialogKinds = this.settings.supportedDialogKinds;
|
|
1865
|
+
}
|
|
1265
1866
|
if (this.settings.systemPrompt !== void 0) {
|
|
1266
1867
|
opts.systemPrompt = this.settings.systemPrompt;
|
|
1267
1868
|
} else if (this.settings.customSystemPrompt !== void 0) {
|
|
@@ -1281,6 +1882,8 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1281
1882
|
}
|
|
1282
1883
|
if (this.settings.settingSources !== void 0) {
|
|
1283
1884
|
opts.settingSources = this.settings.settingSources;
|
|
1885
|
+
} else {
|
|
1886
|
+
opts.settingSources = [];
|
|
1284
1887
|
}
|
|
1285
1888
|
if (this.settings.additionalDirectories !== void 0) {
|
|
1286
1889
|
opts.additionalDirectories = this.settings.additionalDirectories;
|
|
@@ -1288,6 +1891,48 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1288
1891
|
if (this.settings.agents !== void 0) {
|
|
1289
1892
|
opts.agents = this.settings.agents;
|
|
1290
1893
|
}
|
|
1894
|
+
if (this.settings.skills !== void 0) {
|
|
1895
|
+
opts.skills = this.settings.skills;
|
|
1896
|
+
}
|
|
1897
|
+
if (this.settings.settings !== void 0) {
|
|
1898
|
+
opts.settings = this.settings.settings;
|
|
1899
|
+
}
|
|
1900
|
+
if (this.settings.managedSettings !== void 0) {
|
|
1901
|
+
opts.managedSettings = this.settings.managedSettings;
|
|
1902
|
+
}
|
|
1903
|
+
if (this.settings.toolAliases !== void 0) {
|
|
1904
|
+
opts.toolAliases = this.settings.toolAliases;
|
|
1905
|
+
}
|
|
1906
|
+
if (this.settings.toolConfig !== void 0) {
|
|
1907
|
+
opts.toolConfig = this.settings.toolConfig;
|
|
1908
|
+
}
|
|
1909
|
+
if (this.settings.planModeInstructions !== void 0) {
|
|
1910
|
+
opts.planModeInstructions = this.settings.planModeInstructions;
|
|
1911
|
+
}
|
|
1912
|
+
if (this.settings.title !== void 0) {
|
|
1913
|
+
opts.title = this.settings.title;
|
|
1914
|
+
}
|
|
1915
|
+
if (this.settings.forwardSubagentText !== void 0) {
|
|
1916
|
+
opts.forwardSubagentText = this.settings.forwardSubagentText;
|
|
1917
|
+
}
|
|
1918
|
+
if (this.settings.agentProgressSummaries !== void 0) {
|
|
1919
|
+
opts.agentProgressSummaries = this.settings.agentProgressSummaries;
|
|
1920
|
+
}
|
|
1921
|
+
if (this.settings.includeHookEvents !== void 0) {
|
|
1922
|
+
opts.includeHookEvents = this.settings.includeHookEvents;
|
|
1923
|
+
}
|
|
1924
|
+
if (this.settings.taskBudget !== void 0) {
|
|
1925
|
+
opts.taskBudget = this.settings.taskBudget;
|
|
1926
|
+
}
|
|
1927
|
+
if (this.settings.sessionStore !== void 0) {
|
|
1928
|
+
opts.sessionStore = this.settings.sessionStore;
|
|
1929
|
+
}
|
|
1930
|
+
if (this.settings.sessionStoreFlush !== void 0) {
|
|
1931
|
+
opts.sessionStoreFlush = this.settings.sessionStoreFlush;
|
|
1932
|
+
}
|
|
1933
|
+
if (this.settings.loadTimeoutMs !== void 0) {
|
|
1934
|
+
opts.loadTimeoutMs = this.settings.loadTimeoutMs;
|
|
1935
|
+
}
|
|
1291
1936
|
if (this.settings.includePartialMessages !== void 0) {
|
|
1292
1937
|
opts.includePartialMessages = this.settings.includePartialMessages;
|
|
1293
1938
|
}
|
|
@@ -1312,7 +1957,13 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1312
1957
|
if (this.settings.hooks) {
|
|
1313
1958
|
opts.hooks = this.settings.hooks;
|
|
1314
1959
|
}
|
|
1315
|
-
|
|
1960
|
+
const effectiveForkSession = sdkOptions?.forkSession ?? this.settings.forkSession;
|
|
1961
|
+
const effectiveContinue = sdkOptions?.continue ?? this.settings.continue;
|
|
1962
|
+
if (this.settings.sessionId !== void 0 && !_ClaudeCodeLanguageModel.sessionIdConflictsWithResumeOrContinue({
|
|
1963
|
+
resumePresent: opts.resume !== void 0,
|
|
1964
|
+
continue: effectiveContinue === true,
|
|
1965
|
+
forkSession: effectiveForkSession === true
|
|
1966
|
+
})) {
|
|
1316
1967
|
opts.sessionId = this.settings.sessionId;
|
|
1317
1968
|
}
|
|
1318
1969
|
if (this.settings.debug !== void 0) {
|
|
@@ -1328,7 +1979,17 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1328
1979
|
const rest = { ...sdkOverrides };
|
|
1329
1980
|
delete rest.env;
|
|
1330
1981
|
delete rest.stderr;
|
|
1331
|
-
Object.
|
|
1982
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
1983
|
+
if (value !== void 0) {
|
|
1984
|
+
opts[key] = value;
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
this.applySessionResolution(opts, effectiveResume);
|
|
1989
|
+
if (typeof opts.fallbackModel === "string" && opts.fallbackModel === opts.model) {
|
|
1990
|
+
throw new Error(
|
|
1991
|
+
`fallbackModel cannot be the same as the model ('${String(opts.model)}'). Specify a different model for fallbackModel, or remove it.`
|
|
1992
|
+
);
|
|
1332
1993
|
}
|
|
1333
1994
|
const userStderrCallback = sdkStderr ?? this.settings.stderr;
|
|
1334
1995
|
if (stderrCollector || userStderrCallback) {
|
|
@@ -1337,14 +1998,27 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1337
1998
|
if (userStderrCallback) userStderrCallback(data);
|
|
1338
1999
|
};
|
|
1339
2000
|
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
2001
|
+
const mergedEnv = {
|
|
2002
|
+
...getBaseProcessEnv(),
|
|
2003
|
+
...this.settings.env,
|
|
2004
|
+
...sdkEnv
|
|
2005
|
+
};
|
|
2006
|
+
if (!("CLAUDE_AGENT_SDK_CLIENT_APP" in mergedEnv)) {
|
|
2007
|
+
mergedEnv.CLAUDE_AGENT_SDK_CLIENT_APP = DEFAULT_CLIENT_APP;
|
|
1343
2008
|
}
|
|
2009
|
+
opts.env = mergedEnv;
|
|
1344
2010
|
if (responseFormat?.type === "json" && responseFormat.schema) {
|
|
2011
|
+
const { schema: sanitizedSchema, strippedFormatPaths } = sanitizeJsonSchemaForOutputFormat(
|
|
2012
|
+
responseFormat.schema
|
|
2013
|
+
);
|
|
2014
|
+
if (strippedFormatPaths.length > 0) {
|
|
2015
|
+
this.logger.debug(
|
|
2016
|
+
`[claude-code] Stripped unsupported 'format' keywords from outputFormat schema (hints folded into descriptions; client-side Zod validation still enforces them) at: ${strippedFormatPaths.join(", ")}`
|
|
2017
|
+
);
|
|
2018
|
+
}
|
|
1345
2019
|
opts.outputFormat = {
|
|
1346
2020
|
type: "json_schema",
|
|
1347
|
-
schema:
|
|
2021
|
+
schema: sanitizedSchema
|
|
1348
2022
|
};
|
|
1349
2023
|
}
|
|
1350
2024
|
return opts;
|
|
@@ -1353,6 +2027,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1353
2027
|
if (isAbortError(error)) {
|
|
1354
2028
|
throw error;
|
|
1355
2029
|
}
|
|
2030
|
+
if (error instanceof import_provider2.APICallError || error instanceof import_provider2.LoadAPIKeyError) {
|
|
2031
|
+
return error;
|
|
2032
|
+
}
|
|
1356
2033
|
const isErrorWithMessage = (err) => {
|
|
1357
2034
|
return typeof err === "object" && err !== null && "message" in err;
|
|
1358
2035
|
};
|
|
@@ -1369,11 +2046,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1369
2046
|
"claude auth login",
|
|
1370
2047
|
"/login",
|
|
1371
2048
|
// CLI returns "Please run /login"
|
|
1372
|
-
"invalid api key"
|
|
2049
|
+
"invalid api key",
|
|
2050
|
+
"oauth_org_not_allowed"
|
|
2051
|
+
// SDK 0.3.x assistant error kind: OAuth org not permitted
|
|
1373
2052
|
];
|
|
1374
2053
|
const errorMessage = isErrorWithMessage(error) && error.message ? error.message.toLowerCase() : "";
|
|
2054
|
+
const errorKind = getStructuredErrorKind(error);
|
|
1375
2055
|
const exitCode = isErrorWithCode(error) && typeof error.exitCode === "number" ? error.exitCode : void 0;
|
|
1376
|
-
const isAuthError = authErrorPatterns.some((pattern) => errorMessage.includes(pattern)) || exitCode === 401;
|
|
2056
|
+
const isAuthError = errorKind === "authentication_failed" || errorKind === "oauth_org_not_allowed" || authErrorPatterns.some((pattern) => errorMessage.includes(pattern)) || exitCode === 401;
|
|
1377
2057
|
if (isAuthError) {
|
|
1378
2058
|
return createAuthenticationError({
|
|
1379
2059
|
message: isErrorWithMessage(error) && error.message ? error.message : "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
|
|
@@ -1388,9 +2068,30 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1388
2068
|
// It's controlled by the consumer via AbortSignal
|
|
1389
2069
|
});
|
|
1390
2070
|
}
|
|
1391
|
-
const isRetryable = errorCode === "ENOENT" || errorCode === "ECONNREFUSED" || errorCode === "ETIMEDOUT" || errorCode === "ECONNRESET";
|
|
1392
2071
|
const stderrFromError = isErrorWithCode(error) && typeof error.stderr === "string" ? error.stderr : void 0;
|
|
1393
2072
|
const stderr = stderrFromError || collectedStderr || void 0;
|
|
2073
|
+
if (errorKind === "overloaded" || errorKind === "rate_limit" || errorMessage.includes("overloaded")) {
|
|
2074
|
+
return createAPICallError({
|
|
2075
|
+
message: isErrorWithMessage(error) && error.message ? error.message : "Anthropic API is overloaded. Please retry.",
|
|
2076
|
+
code: errorCode || void 0,
|
|
2077
|
+
exitCode,
|
|
2078
|
+
stderr,
|
|
2079
|
+
promptExcerpt: messagesPrompt.substring(0, 200),
|
|
2080
|
+
isRetryable: true
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2083
|
+
if (errorKind === "model_not_found" || errorMessage.includes("model_not_found") || errorMessage.includes("no such model")) {
|
|
2084
|
+
const originalMessage = isErrorWithMessage(error) && error.message ? error.message : "Model not found";
|
|
2085
|
+
return createAPICallError({
|
|
2086
|
+
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.`,
|
|
2087
|
+
code: errorCode || void 0,
|
|
2088
|
+
exitCode,
|
|
2089
|
+
stderr,
|
|
2090
|
+
promptExcerpt: messagesPrompt.substring(0, 200),
|
|
2091
|
+
isRetryable: false
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
const isRetryable = errorCode === "ENOENT" || errorCode === "ECONNREFUSED" || errorCode === "ETIMEDOUT" || errorCode === "ECONNRESET";
|
|
1394
2095
|
return createAPICallError({
|
|
1395
2096
|
message: isErrorWithMessage(error) && error.message ? error.message : "Claude Code SDK error",
|
|
1396
2097
|
code: errorCode || void 0,
|
|
@@ -1426,6 +2127,152 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1426
2127
|
}).join(", ");
|
|
1427
2128
|
this.logger.warn(`[claude-code] MCP servers not connected: ${details}`);
|
|
1428
2129
|
}
|
|
2130
|
+
/**
|
|
2131
|
+
* Handles SDK 0.3.x system messages other than 'init', shared by doGenerate
|
|
2132
|
+
* and doStream:
|
|
2133
|
+
* - 'api_retry' is counted into providerMetadata (`apiRetries`) and debug-logged.
|
|
2134
|
+
* - 'permission_denied' is warn-logged and recorded into providerMetadata
|
|
2135
|
+
* (`permissionDenials`); without this a denial is invisible until the
|
|
2136
|
+
* model talks about it.
|
|
2137
|
+
* - 'model_refusal_fallback' is debug-logged (the superseding assistant
|
|
2138
|
+
* message is handled by the text-dedup guard in the message loops).
|
|
2139
|
+
* - 'thinking_tokens' deltas are accumulated into providerMetadata
|
|
2140
|
+
* (`estimatedThinkingTokens`); the estimate is explicitly not the
|
|
2141
|
+
* authoritative billed output tokens, so it is surfaced as metadata
|
|
2142
|
+
* instead of feeding `usage.outputTokens.reasoning`.
|
|
2143
|
+
* - The subtypes in {@link INFORMATIONAL_SYSTEM_SUBTYPES} are intentionally
|
|
2144
|
+
* informational and only debug-logged.
|
|
2145
|
+
*/
|
|
2146
|
+
handleSystemMessage(message, tracking, onRetractedUuids) {
|
|
2147
|
+
switch (message.subtype) {
|
|
2148
|
+
case "api_retry":
|
|
2149
|
+
tracking.apiRetries += 1;
|
|
2150
|
+
this.logger.debug(
|
|
2151
|
+
`[claude-code] API retry ${message.attempt}/${message.max_retries} in ${message.retry_delay_ms}ms - Status: ${message.error_status ?? "unknown"}, Error: ${message.error}`
|
|
2152
|
+
);
|
|
2153
|
+
break;
|
|
2154
|
+
case "permission_denied": {
|
|
2155
|
+
const reason = message.decision_reason ?? message.message;
|
|
2156
|
+
tracking.permissionDenials.push({
|
|
2157
|
+
toolName: message.tool_name,
|
|
2158
|
+
toolUseId: message.tool_use_id,
|
|
2159
|
+
...reason !== void 0 && { reason }
|
|
2160
|
+
});
|
|
2161
|
+
this.logger.warn(
|
|
2162
|
+
`[claude-code] Permission denied - Tool: ${message.tool_name}${reason ? `, Reason: ${reason}` : ""}`
|
|
2163
|
+
);
|
|
2164
|
+
break;
|
|
2165
|
+
}
|
|
2166
|
+
case "mirror_error": {
|
|
2167
|
+
const mirrorError = message.error ?? "unknown error";
|
|
2168
|
+
const mirrorSessionId = message.key?.sessionId ?? message.session_id ?? "unknown";
|
|
2169
|
+
tracking.mirrorErrors.push({ error: mirrorError, sessionId: mirrorSessionId });
|
|
2170
|
+
this.logger.warn(
|
|
2171
|
+
`[claude-code] SessionStore mirror error (transcript batch dropped) - Session: ${mirrorSessionId}, Error: ${mirrorError}`
|
|
2172
|
+
);
|
|
2173
|
+
break;
|
|
2174
|
+
}
|
|
2175
|
+
case "model_refusal_fallback": {
|
|
2176
|
+
this.logger.debug(
|
|
2177
|
+
`[claude-code] Model refusal fallback - ${message.original_model} -> ${message.fallback_model} (direction: ${message.direction})`
|
|
2178
|
+
);
|
|
2179
|
+
const retractedUuids = message.retracted_message_uuids;
|
|
2180
|
+
if (onRetractedUuids && retractedUuids && retractedUuids.length > 0) {
|
|
2181
|
+
this.logger.debug(
|
|
2182
|
+
`[claude-code] Refusal fallback retracts ${retractedUuids.length} message uuid(s)`
|
|
2183
|
+
);
|
|
2184
|
+
onRetractedUuids(retractedUuids);
|
|
2185
|
+
}
|
|
2186
|
+
break;
|
|
2187
|
+
}
|
|
2188
|
+
case "thinking_tokens":
|
|
2189
|
+
tracking.estimatedThinkingTokens += message.estimated_tokens_delta;
|
|
2190
|
+
this.logger.debug(
|
|
2191
|
+
`[claude-code] Thinking tokens estimate - block total: ${message.estimated_tokens}, delta: ${message.estimated_tokens_delta}, accumulated: ${tracking.estimatedThinkingTokens}`
|
|
2192
|
+
);
|
|
2193
|
+
break;
|
|
2194
|
+
default:
|
|
2195
|
+
if (INFORMATIONAL_SYSTEM_SUBTYPES.has(message.subtype)) {
|
|
2196
|
+
this.logger.debug(
|
|
2197
|
+
`[claude-code] Ignoring informational system message: ${message.subtype}`
|
|
2198
|
+
);
|
|
2199
|
+
} else {
|
|
2200
|
+
this.logger.debug(`[claude-code] Unhandled system message subtype: ${message.subtype}`);
|
|
2201
|
+
}
|
|
2202
|
+
break;
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
/**
|
|
2206
|
+
* Merges the result message's `permission_denials` list into the tracked
|
|
2207
|
+
* denials. PreToolUse-hook denies bypass canUseTool and emit no
|
|
2208
|
+
* `permission_denied` system event (per the SDK docs on
|
|
2209
|
+
* SDKPermissionDeniedMessage), so the result list is the only place they
|
|
2210
|
+
* surface. Entries already recorded from stream-time events are deduped by
|
|
2211
|
+
* `tool_use_id`.
|
|
2212
|
+
*/
|
|
2213
|
+
mergeResultPermissionDenials(message, tracking) {
|
|
2214
|
+
for (const denial of message.permission_denials ?? []) {
|
|
2215
|
+
const alreadyTracked = tracking.permissionDenials.some(
|
|
2216
|
+
(d) => d.toolUseId !== void 0 && d.toolUseId === denial.tool_use_id
|
|
2217
|
+
);
|
|
2218
|
+
if (!alreadyTracked) {
|
|
2219
|
+
tracking.permissionDenials.push({
|
|
2220
|
+
toolName: denial.tool_name,
|
|
2221
|
+
toolUseId: denial.tool_use_id
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
/**
|
|
2227
|
+
* Bounded post-result drain for the `prompt_suggestion` message
|
|
2228
|
+
* (promptSuggestions: true), shared by doGenerate and doStream. The
|
|
2229
|
+
* suggestion arrives AFTER the result message; the SDK emits at most one
|
|
2230
|
+
* per turn, so stop once it is delivered, and a timeout closes the
|
|
2231
|
+
* iterator (tearing down the subprocess) if the CLI lingers after the
|
|
2232
|
+
* result without emitting one. Advances the response's own generator, so
|
|
2233
|
+
* the caller's surrounding loop resumes to a finished iterator.
|
|
2234
|
+
*/
|
|
2235
|
+
async drainPromptSuggestion(response, onPromptSuggestion) {
|
|
2236
|
+
const iterator = response[Symbol.asyncIterator]();
|
|
2237
|
+
let drainTimer;
|
|
2238
|
+
const drainTimeout = new Promise((resolve) => {
|
|
2239
|
+
drainTimer = setTimeout(
|
|
2240
|
+
() => resolve("timeout"),
|
|
2241
|
+
_ClaudeCodeLanguageModel.PROMPT_SUGGESTION_DRAIN_TIMEOUT_MS
|
|
2242
|
+
);
|
|
2243
|
+
drainTimer.unref?.();
|
|
2244
|
+
});
|
|
2245
|
+
try {
|
|
2246
|
+
while (true) {
|
|
2247
|
+
const winner = await Promise.race([iterator.next(), drainTimeout]);
|
|
2248
|
+
if (winner === "timeout") {
|
|
2249
|
+
this.logger.debug("[claude-code] Post-result drain timed out; closing SDK iterator");
|
|
2250
|
+
void iterator.return?.().catch(() => {
|
|
2251
|
+
});
|
|
2252
|
+
break;
|
|
2253
|
+
}
|
|
2254
|
+
if (winner.done) {
|
|
2255
|
+
break;
|
|
2256
|
+
}
|
|
2257
|
+
const trailingMessage = winner.value;
|
|
2258
|
+
this.logger.debug(`[claude-code] Post-result message type: ${trailingMessage.type}`);
|
|
2259
|
+
if (trailingMessage.type === "prompt_suggestion") {
|
|
2260
|
+
onPromptSuggestion(trailingMessage.suggestion);
|
|
2261
|
+
void iterator.return?.().catch(() => {
|
|
2262
|
+
});
|
|
2263
|
+
break;
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
} catch (drainError) {
|
|
2267
|
+
this.logger.debug(
|
|
2268
|
+
`[claude-code] Error draining post-result messages: ${drainError instanceof Error ? drainError.message : String(drainError)}`
|
|
2269
|
+
);
|
|
2270
|
+
} finally {
|
|
2271
|
+
if (drainTimer !== void 0) {
|
|
2272
|
+
clearTimeout(drainTimer);
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
1429
2276
|
async doGenerate(options) {
|
|
1430
2277
|
this.logger.debug(`[claude-code] Starting doGenerate request with model: ${this.modelId}`);
|
|
1431
2278
|
this.logger.debug(`[claude-code] Response format: ${options.responseFormat?.type ?? "none"}`);
|
|
@@ -1442,9 +2289,6 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1442
2289
|
let abortListener;
|
|
1443
2290
|
if (options.abortSignal?.aborted) {
|
|
1444
2291
|
abortController.abort(options.abortSignal.reason);
|
|
1445
|
-
} else if (options.abortSignal) {
|
|
1446
|
-
abortListener = () => abortController.abort(options.abortSignal?.reason);
|
|
1447
|
-
options.abortSignal.addEventListener("abort", abortListener, { once: true });
|
|
1448
2292
|
}
|
|
1449
2293
|
let collectedStderr = "";
|
|
1450
2294
|
const stderrCollector = (data) => {
|
|
@@ -1459,15 +2303,77 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1459
2303
|
sdkOptions,
|
|
1460
2304
|
effectiveResume
|
|
1461
2305
|
);
|
|
2306
|
+
if (options.abortSignal && !options.abortSignal.aborted) {
|
|
2307
|
+
abortListener = () => abortController.abort(options.abortSignal?.reason);
|
|
2308
|
+
options.abortSignal.addEventListener("abort", abortListener, { once: true });
|
|
2309
|
+
}
|
|
1462
2310
|
let text = "";
|
|
1463
|
-
const
|
|
2311
|
+
const contentSegments = [];
|
|
2312
|
+
const joinTextSegments = () => contentSegments.filter((segment) => segment.kind === "text").map((segment) => segment.text).join("");
|
|
2313
|
+
const joinFinalTurnTextSegments = () => {
|
|
2314
|
+
let start = 0;
|
|
2315
|
+
for (let i = 0; i < contentSegments.length; i++) {
|
|
2316
|
+
const kind = contentSegments[i]?.kind;
|
|
2317
|
+
if (kind === "tool-result" || kind === "tool-error") {
|
|
2318
|
+
start = i + 1;
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
return contentSegments.slice(start).filter((segment) => segment.kind === "text").map((segment) => segment.text).join("");
|
|
2322
|
+
};
|
|
2323
|
+
const knownTools = /* @__PURE__ */ new Map();
|
|
2324
|
+
const retractedToolIds = /* @__PURE__ */ new Set();
|
|
2325
|
+
const evictBuffered = (retracted) => {
|
|
2326
|
+
if (retracted.size === 0) return;
|
|
2327
|
+
const retractedToolCallIds = computeRetractedToolCallIds(
|
|
2328
|
+
retracted,
|
|
2329
|
+
contentSegments.filter(
|
|
2330
|
+
(segment) => segment.kind === "tool-call" || segment.kind === "tool-result" || segment.kind === "tool-error"
|
|
2331
|
+
).map((segment) => ({
|
|
2332
|
+
toolCallId: segment.toolCallId,
|
|
2333
|
+
uuid: segment.uuid
|
|
2334
|
+
}))
|
|
2335
|
+
);
|
|
2336
|
+
for (const toolCallId of retractedToolCallIds) {
|
|
2337
|
+
retractedToolIds.add(toolCallId);
|
|
2338
|
+
knownTools.delete(toolCallId);
|
|
2339
|
+
activeTaskTools.delete(toolCallId);
|
|
2340
|
+
}
|
|
2341
|
+
for (let i = contentSegments.length - 1; i >= 0; i--) {
|
|
2342
|
+
const segment = contentSegments[i];
|
|
2343
|
+
if (segment === void 0) continue;
|
|
2344
|
+
const segmentUuid = "uuid" in segment ? segment.uuid : void 0;
|
|
2345
|
+
const retractsSegment = segmentUuid !== void 0 && retracted.has(segmentUuid) || (segment.kind === "tool-result" || segment.kind === "tool-error") && retractedToolCallIds.has(segment.toolCallId);
|
|
2346
|
+
if (retractsSegment) {
|
|
2347
|
+
contentSegments.splice(i, 1);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
};
|
|
2351
|
+
const activeTaskTools = /* @__PURE__ */ new Map();
|
|
2352
|
+
const getFallbackParentId = () => {
|
|
2353
|
+
if (activeTaskTools.size === 1) {
|
|
2354
|
+
return activeTaskTools.keys().next().value ?? null;
|
|
2355
|
+
}
|
|
2356
|
+
return null;
|
|
2357
|
+
};
|
|
1464
2358
|
let structuredOutput;
|
|
2359
|
+
let receivedResultMessage = false;
|
|
1465
2360
|
let usage = createEmptyUsage();
|
|
1466
2361
|
let finishReason = { unified: "stop", raw: void 0 };
|
|
1467
2362
|
let wasTruncated = false;
|
|
1468
2363
|
let costUsd;
|
|
1469
2364
|
let durationMs;
|
|
1470
2365
|
let modelUsage;
|
|
2366
|
+
let ttftMs;
|
|
2367
|
+
let ttftStreamMs;
|
|
2368
|
+
let timeToRequestMs;
|
|
2369
|
+
let warmSpareClaimed;
|
|
2370
|
+
let terminalReason;
|
|
2371
|
+
const metadataTracking = {
|
|
2372
|
+
apiRetries: 0,
|
|
2373
|
+
permissionDenials: [],
|
|
2374
|
+
mirrorErrors: [],
|
|
2375
|
+
estimatedThinkingTokens: 0
|
|
2376
|
+
};
|
|
1471
2377
|
const warnings = this.generateAllWarnings(options, messagesPrompt);
|
|
1472
2378
|
if (messageWarnings) {
|
|
1473
2379
|
messageWarnings.forEach((warning) => {
|
|
@@ -1513,23 +2419,195 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1513
2419
|
options: queryOptions
|
|
1514
2420
|
});
|
|
1515
2421
|
this.settings.onQueryCreated?.(response);
|
|
1516
|
-
|
|
2422
|
+
let lastAssistantErrorKind;
|
|
2423
|
+
const sdkIterator = response[Symbol.asyncIterator]();
|
|
2424
|
+
const detachableResponse = {
|
|
2425
|
+
[Symbol.asyncIterator]: () => ({
|
|
2426
|
+
next: () => sdkIterator.next(),
|
|
2427
|
+
return: () => {
|
|
2428
|
+
void sdkIterator.return?.().catch(() => {
|
|
2429
|
+
});
|
|
2430
|
+
return Promise.resolve({ done: true, value: void 0 });
|
|
2431
|
+
}
|
|
2432
|
+
})
|
|
2433
|
+
};
|
|
2434
|
+
for await (const message of detachableResponse) {
|
|
1517
2435
|
this.logger.debug(`[claude-code] Received message type: ${message.type}`);
|
|
1518
2436
|
if (message.type === "assistant") {
|
|
1519
|
-
|
|
1520
|
-
message.
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
2437
|
+
if (typeof message.error === "string") {
|
|
2438
|
+
lastAssistantErrorKind = message.error;
|
|
2439
|
+
}
|
|
2440
|
+
applySupersede(message, evictBuffered, this.logger, "truthy");
|
|
2441
|
+
const messageUuid = typeof message.uuid === "string" ? message.uuid : void 0;
|
|
2442
|
+
const sdkParentToolUseId = message.parent_tool_use_id;
|
|
2443
|
+
const content = message.message.content;
|
|
2444
|
+
if (Array.isArray(content)) {
|
|
2445
|
+
for (const block of content) {
|
|
2446
|
+
if (!isContentBlock(block)) continue;
|
|
2447
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
2448
|
+
if (block.text.length > 0) {
|
|
2449
|
+
contentSegments.push({
|
|
2450
|
+
kind: "text",
|
|
2451
|
+
...messageUuid !== void 0 && { uuid: messageUuid },
|
|
2452
|
+
text: block.text
|
|
2453
|
+
});
|
|
2454
|
+
}
|
|
2455
|
+
} else if (block.type === "thinking" && typeof block.thinking === "string") {
|
|
2456
|
+
contentSegments.push({
|
|
2457
|
+
kind: "reasoning",
|
|
2458
|
+
...messageUuid !== void 0 && { uuid: messageUuid },
|
|
2459
|
+
text: block.thinking
|
|
2460
|
+
});
|
|
2461
|
+
} else if (block.type === "tool_use") {
|
|
2462
|
+
const [tool3] = this.extractToolUses([block]);
|
|
2463
|
+
if (!tool3) continue;
|
|
2464
|
+
const parentToolCallId = isSubagentToolName(tool3.name) ? null : resolveToolParentId(
|
|
2465
|
+
sdkParentToolUseId,
|
|
2466
|
+
tool3.parentToolUseId,
|
|
2467
|
+
getFallbackParentId
|
|
2468
|
+
);
|
|
2469
|
+
this.logger.debug(
|
|
2470
|
+
`[claude-code] Tool use detected - Tool: ${tool3.name}, ID: ${tool3.id}, SDK parent: ${sdkParentToolUseId}, resolved parent: ${parentToolCallId}`
|
|
2471
|
+
);
|
|
2472
|
+
knownTools.set(tool3.id, { name: tool3.name, parentToolCallId });
|
|
2473
|
+
if (isSubagentToolName(tool3.name)) {
|
|
2474
|
+
activeTaskTools.set(tool3.id, { startTime: Date.now() });
|
|
2475
|
+
}
|
|
2476
|
+
contentSegments.push({
|
|
2477
|
+
kind: "tool-call",
|
|
2478
|
+
...messageUuid !== void 0 && { uuid: messageUuid },
|
|
2479
|
+
toolCallId: tool3.id,
|
|
2480
|
+
part: this.buildToolCallPart(
|
|
2481
|
+
tool3.id,
|
|
2482
|
+
tool3.name,
|
|
2483
|
+
this.serializeToolInput(tool3.input),
|
|
2484
|
+
parentToolCallId
|
|
2485
|
+
)
|
|
2486
|
+
});
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
text = joinTextSegments();
|
|
2491
|
+
} else if (message.type === "user") {
|
|
2492
|
+
if (!message.message?.content) {
|
|
2493
|
+
this.logger.warn(
|
|
2494
|
+
`[claude-code] Unexpected user message structure: missing content field. Message type: ${message.type}. This may indicate an SDK protocol violation.`
|
|
2495
|
+
);
|
|
2496
|
+
continue;
|
|
2497
|
+
}
|
|
2498
|
+
const sdkParentToolUseIdForResults = message.parent_tool_use_id;
|
|
2499
|
+
const resultMessageUuid = typeof message.uuid === "string" ? message.uuid : void 0;
|
|
2500
|
+
const content = message.message.content;
|
|
2501
|
+
for (const result of this.extractToolResults(content)) {
|
|
2502
|
+
if (this.isRetractedToolFrame(result.id, retractedToolIds, "result")) {
|
|
2503
|
+
continue;
|
|
2504
|
+
}
|
|
2505
|
+
const known = knownTools.get(result.id);
|
|
2506
|
+
const toolName = result.name ?? known?.name ?? _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
|
|
2507
|
+
this.logger.debug(
|
|
2508
|
+
`[claude-code] Tool result received - Tool: ${toolName}, ID: ${result.id}`
|
|
2509
|
+
);
|
|
2510
|
+
let parentToolCallId;
|
|
2511
|
+
if (known) {
|
|
2512
|
+
known.name = toolName;
|
|
2513
|
+
parentToolCallId = known.parentToolCallId;
|
|
2514
|
+
} else {
|
|
2515
|
+
this.logger.warn(
|
|
2516
|
+
`[claude-code] Received tool result for unknown tool ID: ${result.id}`
|
|
2517
|
+
);
|
|
2518
|
+
parentToolCallId = isSubagentToolName(toolName) ? null : resolveToolParentId(sdkParentToolUseIdForResults, void 0, getFallbackParentId);
|
|
2519
|
+
knownTools.set(result.id, { name: toolName, parentToolCallId });
|
|
2520
|
+
contentSegments.push({
|
|
2521
|
+
kind: "tool-call",
|
|
2522
|
+
toolCallId: result.id,
|
|
2523
|
+
part: this.buildToolCallPart(result.id, toolName, "", parentToolCallId)
|
|
2524
|
+
});
|
|
2525
|
+
}
|
|
2526
|
+
if (isSubagentToolName(toolName)) {
|
|
2527
|
+
activeTaskTools.delete(result.id);
|
|
2528
|
+
}
|
|
2529
|
+
contentSegments.push({
|
|
2530
|
+
kind: "tool-result",
|
|
2531
|
+
...resultMessageUuid !== void 0 && { uuid: resultMessageUuid },
|
|
2532
|
+
toolCallId: result.id,
|
|
2533
|
+
part: this.buildToolResultPart(
|
|
2534
|
+
result.id,
|
|
2535
|
+
toolName,
|
|
2536
|
+
result.result,
|
|
2537
|
+
result.isError,
|
|
2538
|
+
parentToolCallId
|
|
2539
|
+
)
|
|
2540
|
+
});
|
|
2541
|
+
}
|
|
2542
|
+
for (const error of this.extractToolErrors(content)) {
|
|
2543
|
+
if (this.isRetractedToolFrame(error.id, retractedToolIds, "error")) {
|
|
2544
|
+
continue;
|
|
2545
|
+
}
|
|
2546
|
+
const known = knownTools.get(error.id);
|
|
2547
|
+
const toolName = error.name ?? known?.name ?? _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
|
|
2548
|
+
this.logger.debug(
|
|
2549
|
+
`[claude-code] Tool error received - Tool: ${toolName}, ID: ${error.id}`
|
|
2550
|
+
);
|
|
2551
|
+
let parentToolCallId;
|
|
2552
|
+
if (known) {
|
|
2553
|
+
known.name = toolName;
|
|
2554
|
+
parentToolCallId = known.parentToolCallId;
|
|
2555
|
+
} else {
|
|
2556
|
+
this.logger.warn(
|
|
2557
|
+
`[claude-code] Received tool error for unknown tool ID: ${error.id}`
|
|
2558
|
+
);
|
|
2559
|
+
parentToolCallId = isSubagentToolName(toolName) ? null : resolveToolParentId(sdkParentToolUseIdForResults, void 0, getFallbackParentId);
|
|
2560
|
+
knownTools.set(error.id, { name: toolName, parentToolCallId });
|
|
2561
|
+
contentSegments.push({
|
|
2562
|
+
kind: "tool-call",
|
|
2563
|
+
toolCallId: error.id,
|
|
2564
|
+
part: this.buildToolCallPart(error.id, toolName, "", parentToolCallId)
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
if (isSubagentToolName(toolName)) {
|
|
2568
|
+
activeTaskTools.delete(error.id);
|
|
2569
|
+
}
|
|
2570
|
+
contentSegments.push({
|
|
2571
|
+
kind: "tool-error",
|
|
2572
|
+
...resultMessageUuid !== void 0 && { uuid: resultMessageUuid },
|
|
2573
|
+
toolCallId: error.id,
|
|
2574
|
+
part: this.buildToolErrorResultPart(
|
|
2575
|
+
error.id,
|
|
2576
|
+
toolName,
|
|
2577
|
+
error.error,
|
|
2578
|
+
parentToolCallId
|
|
2579
|
+
)
|
|
2580
|
+
});
|
|
2581
|
+
}
|
|
1524
2582
|
} else if (message.type === "result") {
|
|
1525
2583
|
done();
|
|
2584
|
+
receivedResultMessage = true;
|
|
1526
2585
|
this.setSessionId(message.session_id);
|
|
1527
2586
|
costUsd = message.total_cost_usd;
|
|
1528
2587
|
durationMs = message.duration_ms;
|
|
1529
2588
|
modelUsage = message.modelUsage;
|
|
2589
|
+
if ("ttft_ms" in message) {
|
|
2590
|
+
ttftMs = message.ttft_ms;
|
|
2591
|
+
}
|
|
2592
|
+
if ("ttft_stream_ms" in message) {
|
|
2593
|
+
ttftStreamMs = message.ttft_stream_ms;
|
|
2594
|
+
}
|
|
2595
|
+
if ("time_to_request_ms" in message) {
|
|
2596
|
+
timeToRequestMs = message.time_to_request_ms;
|
|
2597
|
+
}
|
|
2598
|
+
if ("warm_spare_claimed" in message) {
|
|
2599
|
+
warmSpareClaimed = message.warm_spare_claimed;
|
|
2600
|
+
}
|
|
2601
|
+
terminalReason = message.terminal_reason;
|
|
2602
|
+
this.mergeResultPermissionDenials(message, metadataTracking);
|
|
1530
2603
|
if ("is_error" in message && message.is_error === true) {
|
|
1531
|
-
const
|
|
1532
|
-
|
|
2604
|
+
const resultText = "result" in message && typeof message.result === "string" ? message.result : void 0;
|
|
2605
|
+
const errorsText = "errors" in message && Array.isArray(message.errors) ? message.errors.filter((e) => typeof e === "string").join("; ") : "";
|
|
2606
|
+
const errorMessage = resultText ?? (errorsText || "Claude Code CLI returned an error");
|
|
2607
|
+
throw Object.assign(new Error(errorMessage), {
|
|
2608
|
+
exitCode: 1,
|
|
2609
|
+
errorKind: lastAssistantErrorKind
|
|
2610
|
+
});
|
|
1533
2611
|
}
|
|
1534
2612
|
if (message.subtype === "error_max_structured_output_retries") {
|
|
1535
2613
|
throw new Error(
|
|
@@ -1552,10 +2630,21 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1552
2630
|
const stopReason = "stop_reason" in message ? message.stop_reason : void 0;
|
|
1553
2631
|
finishReason = mapClaudeCodeFinishReason(message.subtype, stopReason);
|
|
1554
2632
|
this.logger.debug(`[claude-code] Finish reason: ${finishReason.unified}`);
|
|
2633
|
+
const effectivePromptSuggestions = sdkOptions?.promptSuggestions ?? this.settings.promptSuggestions;
|
|
2634
|
+
if (this.settings.onPromptSuggestion && effectivePromptSuggestions !== false) {
|
|
2635
|
+
await this.drainPromptSuggestion(response, this.settings.onPromptSuggestion);
|
|
2636
|
+
}
|
|
2637
|
+
break;
|
|
1555
2638
|
} else if (message.type === "system" && message.subtype === "init") {
|
|
1556
2639
|
this.logMcpConnectionIssues(message.mcp_servers);
|
|
1557
2640
|
this.setSessionId(message.session_id);
|
|
1558
2641
|
this.logger.info(`[claude-code] Session initialized: ${message.session_id}`);
|
|
2642
|
+
} else if (message.type === "system") {
|
|
2643
|
+
this.handleSystemMessage(
|
|
2644
|
+
message,
|
|
2645
|
+
metadataTracking,
|
|
2646
|
+
buildRetractionEvictor(evictBuffered)
|
|
2647
|
+
);
|
|
1559
2648
|
}
|
|
1560
2649
|
}
|
|
1561
2650
|
} catch (error) {
|
|
@@ -1585,15 +2674,45 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1585
2674
|
options.abortSignal.removeEventListener("abort", abortListener);
|
|
1586
2675
|
}
|
|
1587
2676
|
}
|
|
1588
|
-
|
|
2677
|
+
if (options.responseFormat?.type === "json" && options.responseFormat.schema !== void 0 && receivedResultMessage && structuredOutput === void 0 && !wasTruncated && finishReason.unified === "stop") {
|
|
2678
|
+
const recoveredJsonText = extractJsonObjectText(joinFinalTurnTextSegments()) ?? extractJsonObjectText(joinTextSegments());
|
|
2679
|
+
if (recoveredJsonText !== void 0) {
|
|
2680
|
+
this.logger.warn(
|
|
2681
|
+
"[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."
|
|
2682
|
+
);
|
|
2683
|
+
structuredOutput = JSON.parse(recoveredJsonText);
|
|
2684
|
+
} else {
|
|
2685
|
+
throw createAPICallError({
|
|
2686
|
+
message: MISSING_STRUCTURED_OUTPUT_ERROR_MESSAGE,
|
|
2687
|
+
promptExcerpt: messagesPrompt.substring(0, 200),
|
|
2688
|
+
isRetryable: false
|
|
2689
|
+
});
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
const thinkingTraces = contentSegments.filter((segment) => segment.kind === "reasoning").map((segment) => segment.text);
|
|
2693
|
+
const contentParts = [];
|
|
2694
|
+
for (const segment of contentSegments) {
|
|
2695
|
+
if (segment.kind === "reasoning") {
|
|
2696
|
+
contentParts.push({ type: "reasoning", text: segment.text });
|
|
2697
|
+
} else if (segment.kind === "text") {
|
|
2698
|
+
if (structuredOutput !== void 0) continue;
|
|
2699
|
+
const last = contentParts[contentParts.length - 1];
|
|
2700
|
+
if (last !== void 0 && last.type === "text") {
|
|
2701
|
+
last.text += segment.text;
|
|
2702
|
+
} else {
|
|
2703
|
+
contentParts.push({ type: "text", text: segment.text });
|
|
2704
|
+
}
|
|
2705
|
+
} else {
|
|
2706
|
+
contentParts.push(segment.part);
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
if (structuredOutput !== void 0) {
|
|
2710
|
+
contentParts.push({ type: "text", text: JSON.stringify(structuredOutput) });
|
|
2711
|
+
} else if (!contentParts.some((part) => part.type === "text")) {
|
|
2712
|
+
contentParts.push({ type: "text", text: "" });
|
|
2713
|
+
}
|
|
1589
2714
|
return {
|
|
1590
|
-
content:
|
|
1591
|
-
...thinkingTraces.map((trace) => ({
|
|
1592
|
-
type: "reasoning",
|
|
1593
|
-
text: trace
|
|
1594
|
-
})),
|
|
1595
|
-
{ type: "text", text: finalText }
|
|
1596
|
-
],
|
|
2715
|
+
content: contentParts,
|
|
1597
2716
|
usage,
|
|
1598
2717
|
finishReason,
|
|
1599
2718
|
warnings,
|
|
@@ -1611,6 +2730,21 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1611
2730
|
...costUsd !== void 0 && { costUsd },
|
|
1612
2731
|
...durationMs !== void 0 && { durationMs },
|
|
1613
2732
|
...modelUsage !== void 0 && { modelUsage },
|
|
2733
|
+
...ttftMs !== void 0 && { ttftMs },
|
|
2734
|
+
...ttftStreamMs !== void 0 && { ttftStreamMs },
|
|
2735
|
+
...timeToRequestMs !== void 0 && { timeToRequestMs },
|
|
2736
|
+
...warmSpareClaimed !== void 0 && { warmSpareClaimed },
|
|
2737
|
+
...terminalReason !== void 0 && { terminalReason },
|
|
2738
|
+
...metadataTracking.apiRetries > 0 && { apiRetries: metadataTracking.apiRetries },
|
|
2739
|
+
...metadataTracking.permissionDenials.length > 0 && {
|
|
2740
|
+
permissionDenials: metadataTracking.permissionDenials
|
|
2741
|
+
},
|
|
2742
|
+
...metadataTracking.mirrorErrors.length > 0 && {
|
|
2743
|
+
mirrorErrors: metadataTracking.mirrorErrors
|
|
2744
|
+
},
|
|
2745
|
+
...metadataTracking.estimatedThinkingTokens > 0 && {
|
|
2746
|
+
estimatedThinkingTokens: metadataTracking.estimatedThinkingTokens
|
|
2747
|
+
},
|
|
1614
2748
|
...wasTruncated && { truncated: true },
|
|
1615
2749
|
...thinkingTraces.length > 0 && { thinkingTraces }
|
|
1616
2750
|
}
|
|
@@ -1633,9 +2767,6 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1633
2767
|
let abortListener;
|
|
1634
2768
|
if (options.abortSignal?.aborted) {
|
|
1635
2769
|
abortController.abort(options.abortSignal.reason);
|
|
1636
|
-
} else if (options.abortSignal) {
|
|
1637
|
-
abortListener = () => abortController.abort(options.abortSignal?.reason);
|
|
1638
|
-
options.abortSignal.addEventListener("abort", abortListener, { once: true });
|
|
1639
2770
|
}
|
|
1640
2771
|
let collectedStderr = "";
|
|
1641
2772
|
const stderrCollector = (data) => {
|
|
@@ -1650,6 +2781,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1650
2781
|
sdkOptions,
|
|
1651
2782
|
effectiveResume
|
|
1652
2783
|
);
|
|
2784
|
+
if (options.abortSignal && !options.abortSignal.aborted) {
|
|
2785
|
+
abortListener = () => abortController.abort(options.abortSignal?.reason);
|
|
2786
|
+
options.abortSignal.addEventListener("abort", abortListener, { once: true });
|
|
2787
|
+
}
|
|
1653
2788
|
if (queryOptions.includePartialMessages === void 0) {
|
|
1654
2789
|
queryOptions.includePartialMessages = true;
|
|
1655
2790
|
}
|
|
@@ -1680,6 +2815,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1680
2815
|
done = () => resolve(void 0);
|
|
1681
2816
|
});
|
|
1682
2817
|
const toolStates = /* @__PURE__ */ new Map();
|
|
2818
|
+
const retractedStreamToolIds = /* @__PURE__ */ new Set();
|
|
1683
2819
|
const activeTaskTools = /* @__PURE__ */ new Map();
|
|
1684
2820
|
const getFallbackParentId = () => {
|
|
1685
2821
|
if (activeTaskTools.size === 1) {
|
|
@@ -1702,24 +2838,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1702
2838
|
return;
|
|
1703
2839
|
}
|
|
1704
2840
|
closeToolInput(toolId, state);
|
|
1705
|
-
controller.enqueue(
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
providerMetadata: {
|
|
1714
|
-
"claude-code": {
|
|
1715
|
-
// rawInput preserves the original serialized format before AI SDK normalization.
|
|
1716
|
-
// Use this if you need the exact string sent to the Claude CLI, which may differ
|
|
1717
|
-
// from the `input` field after AI SDK processing.
|
|
1718
|
-
rawInput: state.lastSerializedInput ?? "",
|
|
1719
|
-
parentToolCallId: state.parentToolCallId ?? null
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
});
|
|
2841
|
+
controller.enqueue(
|
|
2842
|
+
this.buildToolCallPart(
|
|
2843
|
+
toolId,
|
|
2844
|
+
state.name,
|
|
2845
|
+
state.lastSerializedInput ?? "",
|
|
2846
|
+
state.parentToolCallId
|
|
2847
|
+
)
|
|
2848
|
+
);
|
|
1723
2849
|
state.callEmitted = true;
|
|
1724
2850
|
};
|
|
1725
2851
|
const finalizeToolCalls = () => {
|
|
@@ -1730,16 +2856,61 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1730
2856
|
};
|
|
1731
2857
|
let usage = createEmptyUsage();
|
|
1732
2858
|
let accumulatedText = "";
|
|
2859
|
+
const textSegments = [];
|
|
1733
2860
|
let textPartId;
|
|
1734
2861
|
let streamedTextLength = 0;
|
|
2862
|
+
let emittedTextSinceLastAssistant = "";
|
|
1735
2863
|
let hasReceivedStreamEvents = false;
|
|
1736
2864
|
let hasStreamedJson = false;
|
|
2865
|
+
let lastAssistantErrorKind;
|
|
2866
|
+
const metadataTracking = {
|
|
2867
|
+
apiRetries: 0,
|
|
2868
|
+
permissionDenials: [],
|
|
2869
|
+
mirrorErrors: [],
|
|
2870
|
+
estimatedThinkingTokens: 0
|
|
2871
|
+
};
|
|
1737
2872
|
const toolBlocksByIndex = /* @__PURE__ */ new Map();
|
|
1738
2873
|
const toolInputAccumulators = /* @__PURE__ */ new Map();
|
|
1739
2874
|
const textBlocksByIndex = /* @__PURE__ */ new Map();
|
|
1740
2875
|
let textStreamedViaContentBlock = false;
|
|
1741
2876
|
const reasoningBlocksByIndex = /* @__PURE__ */ new Map();
|
|
1742
2877
|
let currentReasoningPartId;
|
|
2878
|
+
const evictLive = (retracted) => {
|
|
2879
|
+
if (retracted.size === 0) return;
|
|
2880
|
+
for (let i = textSegments.length - 1; i >= 0; i--) {
|
|
2881
|
+
const segmentUuid = textSegments[i]?.uuid;
|
|
2882
|
+
if (segmentUuid !== void 0 && retracted.has(segmentUuid)) {
|
|
2883
|
+
textSegments.splice(i, 1);
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
accumulatedText = textSegments.map((segment) => segment.text).join("");
|
|
2887
|
+
const retractedToolCallIds = computeRetractedToolCallIds(
|
|
2888
|
+
retracted,
|
|
2889
|
+
[...toolStates].map(([toolId, state]) => ({
|
|
2890
|
+
toolCallId: toolId,
|
|
2891
|
+
uuid: state.messageUuid
|
|
2892
|
+
}))
|
|
2893
|
+
);
|
|
2894
|
+
for (const toolId of retractedToolCallIds) {
|
|
2895
|
+
const state = toolStates.get(toolId);
|
|
2896
|
+
if (!state) continue;
|
|
2897
|
+
activeTaskTools.delete(toolId);
|
|
2898
|
+
if (!state.callEmitted) {
|
|
2899
|
+
closeToolInput(toolId, state);
|
|
2900
|
+
toolStates.delete(toolId);
|
|
2901
|
+
retractedStreamToolIds.add(toolId);
|
|
2902
|
+
toolInputAccumulators.delete(toolId);
|
|
2903
|
+
for (const [blockIndex, mappedId] of toolBlocksByIndex) {
|
|
2904
|
+
if (mappedId === toolId) {
|
|
2905
|
+
toolBlocksByIndex.delete(blockIndex);
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
this.logger.debug(
|
|
2909
|
+
`[claude-code] Retracted pending tool call from superseded message - ID: ${toolId}`
|
|
2910
|
+
);
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
};
|
|
1743
2914
|
try {
|
|
1744
2915
|
controller.enqueue({ type: "stream-start", warnings });
|
|
1745
2916
|
if (effectiveCanUseTool && effectivePermissionPromptToolName) {
|
|
@@ -1789,6 +2960,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1789
2960
|
});
|
|
1790
2961
|
accumulatedText += deltaText;
|
|
1791
2962
|
streamedTextLength += deltaText.length;
|
|
2963
|
+
emittedTextSinceLastAssistant += deltaText;
|
|
1792
2964
|
}
|
|
1793
2965
|
if (event.type === "content_block_delta" && event.delta.type === "input_json_delta" && "partial_json" in event.delta && event.delta.partial_json) {
|
|
1794
2966
|
const jsonDelta = event.delta.partial_json;
|
|
@@ -1848,13 +3020,16 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1848
3020
|
toolInputAccumulators.set(toolId, "");
|
|
1849
3021
|
let state = toolStates.get(toolId);
|
|
1850
3022
|
if (!state) {
|
|
1851
|
-
const
|
|
3023
|
+
const partialParentId = message.parent_tool_use_id;
|
|
3024
|
+
const currentParentId = isSubagentToolName(toolName) ? null : resolveToolParentId(partialParentId, void 0, getFallbackParentId);
|
|
3025
|
+
const envelopeUuid = message.uuid;
|
|
1852
3026
|
state = {
|
|
1853
3027
|
name: toolName,
|
|
1854
3028
|
inputStarted: false,
|
|
1855
3029
|
inputClosed: false,
|
|
1856
3030
|
callEmitted: false,
|
|
1857
|
-
parentToolCallId: currentParentId
|
|
3031
|
+
parentToolCallId: currentParentId,
|
|
3032
|
+
...typeof envelopeUuid === "string" && { messageUuid: envelopeUuid }
|
|
1858
3033
|
};
|
|
1859
3034
|
toolStates.set(toolId, state);
|
|
1860
3035
|
}
|
|
@@ -1874,7 +3049,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1874
3049
|
}
|
|
1875
3050
|
}
|
|
1876
3051
|
});
|
|
1877
|
-
if (toolName
|
|
3052
|
+
if (isSubagentToolName(toolName)) {
|
|
1878
3053
|
activeTaskTools.set(toolId, { startTime: Date.now() });
|
|
1879
3054
|
}
|
|
1880
3055
|
state.inputStarted = true;
|
|
@@ -1958,20 +3133,14 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
1958
3133
|
const effectiveInput = accumulatedInput || state.lastSerializedInput || "";
|
|
1959
3134
|
state.lastSerializedInput = effectiveInput;
|
|
1960
3135
|
if (!state.callEmitted) {
|
|
1961
|
-
controller.enqueue(
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
"claude-code": {
|
|
1970
|
-
rawInput: effectiveInput,
|
|
1971
|
-
parentToolCallId: state.parentToolCallId ?? null
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
});
|
|
3136
|
+
controller.enqueue(
|
|
3137
|
+
this.buildToolCallPart(
|
|
3138
|
+
toolId,
|
|
3139
|
+
state.name,
|
|
3140
|
+
effectiveInput,
|
|
3141
|
+
state.parentToolCallId
|
|
3142
|
+
)
|
|
3143
|
+
);
|
|
1975
3144
|
state.callEmitted = true;
|
|
1976
3145
|
}
|
|
1977
3146
|
}
|
|
@@ -2013,6 +3182,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2013
3182
|
continue;
|
|
2014
3183
|
}
|
|
2015
3184
|
if (message.type === "assistant") {
|
|
3185
|
+
if (typeof message.error === "string") {
|
|
3186
|
+
lastAssistantErrorKind = message.error;
|
|
3187
|
+
}
|
|
3188
|
+
const supersedesPriorMessages = applySupersede(message, evictLive, this.logger);
|
|
2016
3189
|
if (!message.message?.content) {
|
|
2017
3190
|
this.logger.warn(
|
|
2018
3191
|
`[claude-code] Unexpected assistant message structure: missing content field. Message type: ${message.type}. This may indicate an SDK protocol violation.`
|
|
@@ -2040,19 +3213,24 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2040
3213
|
const toolId = tool3.id;
|
|
2041
3214
|
let state = toolStates.get(toolId);
|
|
2042
3215
|
if (!state) {
|
|
2043
|
-
const currentParentId = tool3.name
|
|
3216
|
+
const currentParentId = isSubagentToolName(tool3.name) ? null : resolveToolParentId(
|
|
3217
|
+
sdkParentToolUseId,
|
|
3218
|
+
tool3.parentToolUseId,
|
|
3219
|
+
getFallbackParentId
|
|
3220
|
+
);
|
|
2044
3221
|
state = {
|
|
2045
3222
|
name: tool3.name,
|
|
2046
3223
|
inputStarted: false,
|
|
2047
3224
|
inputClosed: false,
|
|
2048
3225
|
callEmitted: false,
|
|
2049
|
-
parentToolCallId: currentParentId
|
|
3226
|
+
parentToolCallId: currentParentId,
|
|
3227
|
+
...typeof message.uuid === "string" && { messageUuid: message.uuid }
|
|
2050
3228
|
};
|
|
2051
3229
|
toolStates.set(toolId, state);
|
|
2052
3230
|
this.logger.debug(
|
|
2053
3231
|
`[claude-code] New tool use detected - Tool: ${tool3.name}, ID: ${toolId}, SDK parent: ${sdkParentToolUseId}, resolved parent: ${currentParentId}`
|
|
2054
3232
|
);
|
|
2055
|
-
} else if (!state.parentToolCallId && sdkParentToolUseId && tool3.name
|
|
3233
|
+
} else if (!state.parentToolCallId && sdkParentToolUseId && !isSubagentToolName(tool3.name)) {
|
|
2056
3234
|
state.parentToolCallId = sdkParentToolUseId;
|
|
2057
3235
|
this.logger.debug(
|
|
2058
3236
|
`[claude-code] Retroactive parent context - Tool: ${tool3.name}, ID: ${toolId}, parent: ${sdkParentToolUseId}`
|
|
@@ -2076,7 +3254,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2076
3254
|
}
|
|
2077
3255
|
}
|
|
2078
3256
|
});
|
|
2079
|
-
if (tool3.name
|
|
3257
|
+
if (isSubagentToolName(tool3.name)) {
|
|
2080
3258
|
activeTaskTools.set(toolId, { startTime: Date.now() });
|
|
2081
3259
|
}
|
|
2082
3260
|
state.inputStarted = true;
|
|
@@ -2105,10 +3283,76 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2105
3283
|
}
|
|
2106
3284
|
const text = content.map((c) => c.type === "text" ? c.text : "").join("");
|
|
2107
3285
|
if (text) {
|
|
2108
|
-
if (
|
|
3286
|
+
if (supersedesPriorMessages) {
|
|
3287
|
+
textSegments.push({
|
|
3288
|
+
...typeof message.uuid === "string" && { uuid: message.uuid },
|
|
3289
|
+
text
|
|
3290
|
+
});
|
|
3291
|
+
accumulatedText = textSegments.map((segment) => segment.text).join("");
|
|
3292
|
+
if (emittedTextSinceLastAssistant === text) {
|
|
3293
|
+
streamedTextLength = Math.max(streamedTextLength, text.length);
|
|
3294
|
+
this.logger.debug(
|
|
3295
|
+
"[claude-code] Skipping text emission for superseding assistant message (replacement already streamed)"
|
|
3296
|
+
);
|
|
3297
|
+
} else if (emittedTextSinceLastAssistant.length > 0 && text.startsWith(emittedTextSinceLastAssistant)) {
|
|
3298
|
+
if (options.responseFormat?.type !== "json") {
|
|
3299
|
+
const suffix = text.slice(emittedTextSinceLastAssistant.length);
|
|
3300
|
+
if (suffix) {
|
|
3301
|
+
if (!textPartId) {
|
|
3302
|
+
textPartId = (0, import_provider_utils.generateId)();
|
|
3303
|
+
controller.enqueue({ type: "text-start", id: textPartId });
|
|
3304
|
+
}
|
|
3305
|
+
controller.enqueue({
|
|
3306
|
+
type: "text-delta",
|
|
3307
|
+
id: textPartId,
|
|
3308
|
+
delta: suffix
|
|
3309
|
+
});
|
|
3310
|
+
emittedTextSinceLastAssistant = text;
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
streamedTextLength = Math.max(streamedTextLength, text.length);
|
|
3314
|
+
this.logger.debug(
|
|
3315
|
+
"[claude-code] Emitted unstreamed suffix of superseding assistant message"
|
|
3316
|
+
);
|
|
3317
|
+
} else if (options.responseFormat?.type !== "json") {
|
|
3318
|
+
if (textPartId) {
|
|
3319
|
+
const closedTextId = textPartId;
|
|
3320
|
+
controller.enqueue({
|
|
3321
|
+
type: "text-end",
|
|
3322
|
+
id: closedTextId
|
|
3323
|
+
});
|
|
3324
|
+
textPartId = void 0;
|
|
3325
|
+
for (const [idx, blockTextId] of textBlocksByIndex) {
|
|
3326
|
+
if (blockTextId === closedTextId) {
|
|
3327
|
+
textBlocksByIndex.delete(idx);
|
|
3328
|
+
break;
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
textPartId = (0, import_provider_utils.generateId)();
|
|
3333
|
+
controller.enqueue({
|
|
3334
|
+
type: "text-start",
|
|
3335
|
+
id: textPartId
|
|
3336
|
+
});
|
|
3337
|
+
controller.enqueue({
|
|
3338
|
+
type: "text-delta",
|
|
3339
|
+
id: textPartId,
|
|
3340
|
+
delta: text
|
|
3341
|
+
});
|
|
3342
|
+
streamedTextLength = Math.max(streamedTextLength, text.length);
|
|
3343
|
+
this.logger.debug(
|
|
3344
|
+
"[claude-code] Emitted superseding assistant message as a new text part (canonical replacement)"
|
|
3345
|
+
);
|
|
3346
|
+
}
|
|
3347
|
+
} else if (hasReceivedStreamEvents) {
|
|
2109
3348
|
const newTextStart = streamedTextLength;
|
|
2110
3349
|
const deltaText = text.length > newTextStart ? text.slice(newTextStart) : "";
|
|
2111
3350
|
accumulatedText = text;
|
|
3351
|
+
textSegments.length = 0;
|
|
3352
|
+
textSegments.push({
|
|
3353
|
+
...typeof message.uuid === "string" && { uuid: message.uuid },
|
|
3354
|
+
text
|
|
3355
|
+
});
|
|
2112
3356
|
if (options.responseFormat?.type !== "json" && deltaText) {
|
|
2113
3357
|
if (!textPartId) {
|
|
2114
3358
|
textPartId = (0, import_provider_utils.generateId)();
|
|
@@ -2126,6 +3370,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2126
3370
|
streamedTextLength = text.length;
|
|
2127
3371
|
} else {
|
|
2128
3372
|
accumulatedText += text;
|
|
3373
|
+
textSegments.push({
|
|
3374
|
+
...typeof message.uuid === "string" && { uuid: message.uuid },
|
|
3375
|
+
text
|
|
3376
|
+
});
|
|
2129
3377
|
if (options.responseFormat?.type !== "json") {
|
|
2130
3378
|
if (!textPartId) {
|
|
2131
3379
|
textPartId = (0, import_provider_utils.generateId)();
|
|
@@ -2142,6 +3390,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2142
3390
|
}
|
|
2143
3391
|
}
|
|
2144
3392
|
}
|
|
3393
|
+
emittedTextSinceLastAssistant = "";
|
|
2145
3394
|
} else if (message.type === "user") {
|
|
2146
3395
|
if (!message.message?.content) {
|
|
2147
3396
|
this.logger.warn(
|
|
@@ -2162,13 +3411,18 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2162
3411
|
break;
|
|
2163
3412
|
}
|
|
2164
3413
|
}
|
|
2165
|
-
accumulatedText = "";
|
|
2166
|
-
streamedTextLength = 0;
|
|
2167
3414
|
this.logger.debug("[claude-code] Closed text part due to user message");
|
|
2168
3415
|
}
|
|
3416
|
+
accumulatedText = "";
|
|
3417
|
+
textSegments.length = 0;
|
|
3418
|
+
streamedTextLength = 0;
|
|
3419
|
+
emittedTextSinceLastAssistant = "";
|
|
2169
3420
|
const sdkParentToolUseIdForResults = message.parent_tool_use_id;
|
|
2170
3421
|
const content = message.message.content;
|
|
2171
3422
|
for (const result of this.extractToolResults(content)) {
|
|
3423
|
+
if (this.isRetractedToolFrame(result.id, retractedStreamToolIds, "result")) {
|
|
3424
|
+
continue;
|
|
3425
|
+
}
|
|
2172
3426
|
let state = toolStates.get(result.id);
|
|
2173
3427
|
const toolName = result.name ?? state?.name ?? _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
|
|
2174
3428
|
this.logger.debug(
|
|
@@ -2178,7 +3432,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2178
3432
|
this.logger.warn(
|
|
2179
3433
|
`[claude-code] Received tool result for unknown tool ID: ${result.id}`
|
|
2180
3434
|
);
|
|
2181
|
-
const resolvedParentId = toolName
|
|
3435
|
+
const resolvedParentId = isSubagentToolName(toolName) ? null : resolveToolParentId(
|
|
3436
|
+
sdkParentToolUseIdForResults,
|
|
3437
|
+
void 0,
|
|
3438
|
+
getFallbackParentId
|
|
3439
|
+
);
|
|
2182
3440
|
state = {
|
|
2183
3441
|
name: toolName,
|
|
2184
3442
|
inputStarted: false,
|
|
@@ -2212,50 +3470,24 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2212
3470
|
}
|
|
2213
3471
|
}
|
|
2214
3472
|
state.name = toolName;
|
|
2215
|
-
const normalizedResult = this.normalizeToolResult(result.result);
|
|
2216
|
-
const rawResult = typeof result.result === "string" ? result.result : (() => {
|
|
2217
|
-
try {
|
|
2218
|
-
return JSON.stringify(result.result);
|
|
2219
|
-
} catch {
|
|
2220
|
-
return String(result.result);
|
|
2221
|
-
}
|
|
2222
|
-
})();
|
|
2223
|
-
const maxToolResultSize = this.settings.maxToolResultSize;
|
|
2224
|
-
const truncatedResult = truncateToolResultForStream(
|
|
2225
|
-
normalizedResult,
|
|
2226
|
-
maxToolResultSize
|
|
2227
|
-
);
|
|
2228
|
-
const truncatedRawResult = truncateToolResultForStream(
|
|
2229
|
-
rawResult,
|
|
2230
|
-
maxToolResultSize
|
|
2231
|
-
);
|
|
2232
|
-
const rawResultTruncated = truncatedRawResult !== rawResult;
|
|
2233
3473
|
emitToolCall(result.id, state);
|
|
2234
|
-
if (toolName
|
|
3474
|
+
if (isSubagentToolName(toolName)) {
|
|
2235
3475
|
activeTaskTools.delete(result.id);
|
|
2236
3476
|
}
|
|
2237
|
-
controller.enqueue(
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
providerMetadata: {
|
|
2247
|
-
"claude-code": {
|
|
2248
|
-
// rawResult preserves the original CLI output string before JSON parsing.
|
|
2249
|
-
// Use this when you need the exact string returned by the tool, especially
|
|
2250
|
-
// if the `result` field has been parsed/normalized and you need the original format.
|
|
2251
|
-
rawResult: truncatedRawResult,
|
|
2252
|
-
rawResultTruncated,
|
|
2253
|
-
parentToolCallId: state.parentToolCallId ?? null
|
|
2254
|
-
}
|
|
2255
|
-
}
|
|
2256
|
-
});
|
|
3477
|
+
controller.enqueue(
|
|
3478
|
+
this.buildToolResultPart(
|
|
3479
|
+
result.id,
|
|
3480
|
+
toolName,
|
|
3481
|
+
result.result,
|
|
3482
|
+
result.isError,
|
|
3483
|
+
state.parentToolCallId
|
|
3484
|
+
)
|
|
3485
|
+
);
|
|
2257
3486
|
}
|
|
2258
3487
|
for (const error of this.extractToolErrors(content)) {
|
|
3488
|
+
if (this.isRetractedToolFrame(error.id, retractedStreamToolIds, "error")) {
|
|
3489
|
+
continue;
|
|
3490
|
+
}
|
|
2259
3491
|
let state = toolStates.get(error.id);
|
|
2260
3492
|
const toolName = error.name ?? state?.name ?? _ClaudeCodeLanguageModel.UNKNOWN_TOOL_NAME;
|
|
2261
3493
|
this.logger.debug(
|
|
@@ -2265,7 +3497,11 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2265
3497
|
this.logger.warn(
|
|
2266
3498
|
`[claude-code] Received tool error for unknown tool ID: ${error.id}`
|
|
2267
3499
|
);
|
|
2268
|
-
const errorResolvedParentId = toolName
|
|
3500
|
+
const errorResolvedParentId = isSubagentToolName(toolName) ? null : resolveToolParentId(
|
|
3501
|
+
sdkParentToolUseIdForResults,
|
|
3502
|
+
void 0,
|
|
3503
|
+
getFallbackParentId
|
|
3504
|
+
);
|
|
2269
3505
|
state = {
|
|
2270
3506
|
name: toolName,
|
|
2271
3507
|
inputStarted: true,
|
|
@@ -2276,37 +3512,24 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2276
3512
|
toolStates.set(error.id, state);
|
|
2277
3513
|
}
|
|
2278
3514
|
emitToolCall(error.id, state);
|
|
2279
|
-
if (toolName
|
|
3515
|
+
if (isSubagentToolName(toolName)) {
|
|
2280
3516
|
activeTaskTools.delete(error.id);
|
|
2281
3517
|
}
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
} catch {
|
|
2286
|
-
return String(error.error);
|
|
2287
|
-
}
|
|
2288
|
-
})() : String(error.error);
|
|
2289
|
-
controller.enqueue({
|
|
2290
|
-
type: "tool-error",
|
|
2291
|
-
toolCallId: error.id,
|
|
2292
|
-
toolName,
|
|
2293
|
-
error: rawError,
|
|
2294
|
-
providerExecuted: true,
|
|
2295
|
-
dynamic: true,
|
|
2296
|
-
// V3 field: indicates tool is provider-defined
|
|
2297
|
-
providerMetadata: {
|
|
2298
|
-
"claude-code": {
|
|
2299
|
-
rawError,
|
|
2300
|
-
parentToolCallId: state.parentToolCallId ?? null
|
|
2301
|
-
}
|
|
2302
|
-
}
|
|
2303
|
-
});
|
|
3518
|
+
controller.enqueue(
|
|
3519
|
+
this.buildToolErrorPart(error.id, toolName, error.error, state.parentToolCallId)
|
|
3520
|
+
);
|
|
2304
3521
|
}
|
|
2305
3522
|
} else if (message.type === "result") {
|
|
2306
3523
|
done();
|
|
3524
|
+
this.mergeResultPermissionDenials(message, metadataTracking);
|
|
2307
3525
|
if ("is_error" in message && message.is_error === true) {
|
|
2308
|
-
const
|
|
2309
|
-
|
|
3526
|
+
const resultText = "result" in message && typeof message.result === "string" ? message.result : void 0;
|
|
3527
|
+
const errorsText = "errors" in message && Array.isArray(message.errors) ? message.errors.filter((e) => typeof e === "string").join("; ") : "";
|
|
3528
|
+
const errorMessage = resultText ?? (errorsText || "Claude Code CLI returned an error");
|
|
3529
|
+
throw Object.assign(new Error(errorMessage), {
|
|
3530
|
+
exitCode: 1,
|
|
3531
|
+
errorKind: lastAssistantErrorKind
|
|
3532
|
+
});
|
|
2310
3533
|
}
|
|
2311
3534
|
if (message.subtype === "error_max_structured_output_retries") {
|
|
2312
3535
|
throw new Error(
|
|
@@ -2354,6 +3577,38 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2354
3577
|
type: "text-end",
|
|
2355
3578
|
id: jsonTextId
|
|
2356
3579
|
});
|
|
3580
|
+
} else if (options.responseFormat?.type === "json" && options.responseFormat.schema !== void 0 && finishReason.unified === "stop") {
|
|
3581
|
+
const recoveredJsonText = extractJsonObjectText(accumulatedText);
|
|
3582
|
+
if (recoveredJsonText === void 0) {
|
|
3583
|
+
throw createAPICallError({
|
|
3584
|
+
message: MISSING_STRUCTURED_OUTPUT_ERROR_MESSAGE,
|
|
3585
|
+
promptExcerpt: messagesPrompt.substring(0, 200),
|
|
3586
|
+
isRetryable: false
|
|
3587
|
+
});
|
|
3588
|
+
}
|
|
3589
|
+
this.logger.warn(
|
|
3590
|
+
"[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."
|
|
3591
|
+
);
|
|
3592
|
+
if (textPartId) {
|
|
3593
|
+
controller.enqueue({
|
|
3594
|
+
type: "text-end",
|
|
3595
|
+
id: textPartId
|
|
3596
|
+
});
|
|
3597
|
+
}
|
|
3598
|
+
const recoveredTextId = (0, import_provider_utils.generateId)();
|
|
3599
|
+
controller.enqueue({
|
|
3600
|
+
type: "text-start",
|
|
3601
|
+
id: recoveredTextId
|
|
3602
|
+
});
|
|
3603
|
+
controller.enqueue({
|
|
3604
|
+
type: "text-delta",
|
|
3605
|
+
id: recoveredTextId,
|
|
3606
|
+
delta: recoveredJsonText
|
|
3607
|
+
});
|
|
3608
|
+
controller.enqueue({
|
|
3609
|
+
type: "text-end",
|
|
3610
|
+
id: recoveredTextId
|
|
3611
|
+
});
|
|
2357
3612
|
} else if (textPartId) {
|
|
2358
3613
|
controller.enqueue({
|
|
2359
3614
|
type: "text-end",
|
|
@@ -2391,6 +3646,32 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2391
3646
|
...message.modelUsage !== void 0 && {
|
|
2392
3647
|
modelUsage: message.modelUsage
|
|
2393
3648
|
},
|
|
3649
|
+
// SDK 0.3.x timing metadata (ttft_* only present on SDKResultSuccess)
|
|
3650
|
+
..."ttft_ms" in message && message.ttft_ms !== void 0 && { ttftMs: message.ttft_ms },
|
|
3651
|
+
..."ttft_stream_ms" in message && message.ttft_stream_ms !== void 0 && {
|
|
3652
|
+
ttftStreamMs: message.ttft_stream_ms
|
|
3653
|
+
},
|
|
3654
|
+
..."time_to_request_ms" in message && message.time_to_request_ms !== void 0 && {
|
|
3655
|
+
timeToRequestMs: message.time_to_request_ms
|
|
3656
|
+
},
|
|
3657
|
+
..."warm_spare_claimed" in message && message.warm_spare_claimed !== void 0 && {
|
|
3658
|
+
warmSpareClaimed: message.warm_spare_claimed
|
|
3659
|
+
},
|
|
3660
|
+
...message.terminal_reason !== void 0 && {
|
|
3661
|
+
terminalReason: message.terminal_reason
|
|
3662
|
+
},
|
|
3663
|
+
...metadataTracking.apiRetries > 0 && {
|
|
3664
|
+
apiRetries: metadataTracking.apiRetries
|
|
3665
|
+
},
|
|
3666
|
+
...metadataTracking.permissionDenials.length > 0 && {
|
|
3667
|
+
permissionDenials: metadataTracking.permissionDenials
|
|
3668
|
+
},
|
|
3669
|
+
...metadataTracking.mirrorErrors.length > 0 && {
|
|
3670
|
+
mirrorErrors: metadataTracking.mirrorErrors
|
|
3671
|
+
},
|
|
3672
|
+
...metadataTracking.estimatedThinkingTokens > 0 && {
|
|
3673
|
+
estimatedThinkingTokens: metadataTracking.estimatedThinkingTokens
|
|
3674
|
+
},
|
|
2394
3675
|
// JSON validation warnings are collected during streaming and included
|
|
2395
3676
|
// in providerMetadata since the AI SDK's finish event doesn't support
|
|
2396
3677
|
// a top-level warnings field (unlike stream-start which was already emitted)
|
|
@@ -2401,6 +3682,10 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2401
3682
|
}
|
|
2402
3683
|
});
|
|
2403
3684
|
controller.close();
|
|
3685
|
+
const effectivePromptSuggestions = sdkOptions?.promptSuggestions ?? this.settings.promptSuggestions;
|
|
3686
|
+
if (this.settings.onPromptSuggestion && effectivePromptSuggestions !== false) {
|
|
3687
|
+
await this.drainPromptSuggestion(response, this.settings.onPromptSuggestion);
|
|
3688
|
+
}
|
|
2404
3689
|
return;
|
|
2405
3690
|
} else if (message.type === "system" && message.subtype === "init") {
|
|
2406
3691
|
this.logMcpConnectionIssues(message.mcp_servers);
|
|
@@ -2412,6 +3697,15 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2412
3697
|
timestamp: /* @__PURE__ */ new Date(),
|
|
2413
3698
|
modelId: this.modelId
|
|
2414
3699
|
});
|
|
3700
|
+
} else if (message.type === "system") {
|
|
3701
|
+
this.handleSystemMessage(
|
|
3702
|
+
message,
|
|
3703
|
+
metadataTracking,
|
|
3704
|
+
buildRetractionEvictor(evictLive)
|
|
3705
|
+
);
|
|
3706
|
+
} else if (message.type === "prompt_suggestion") {
|
|
3707
|
+
this.logger.debug("[claude-code] Received prompt suggestion");
|
|
3708
|
+
this.settings.onPromptSuggestion?.(message.suggestion);
|
|
2415
3709
|
}
|
|
2416
3710
|
}
|
|
2417
3711
|
finalizeToolCalls();
|
|
@@ -2462,6 +3756,18 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
|
|
|
2462
3756
|
"claude-code": {
|
|
2463
3757
|
...this.sessionId !== void 0 && { sessionId: this.sessionId },
|
|
2464
3758
|
truncated: true,
|
|
3759
|
+
...metadataTracking.apiRetries > 0 && {
|
|
3760
|
+
apiRetries: metadataTracking.apiRetries
|
|
3761
|
+
},
|
|
3762
|
+
...metadataTracking.permissionDenials.length > 0 && {
|
|
3763
|
+
permissionDenials: metadataTracking.permissionDenials
|
|
3764
|
+
},
|
|
3765
|
+
...metadataTracking.mirrorErrors.length > 0 && {
|
|
3766
|
+
mirrorErrors: metadataTracking.mirrorErrors
|
|
3767
|
+
},
|
|
3768
|
+
...metadataTracking.estimatedThinkingTokens > 0 && {
|
|
3769
|
+
estimatedThinkingTokens: metadataTracking.estimatedThinkingTokens
|
|
3770
|
+
},
|
|
2465
3771
|
...streamWarnings.length > 0 && {
|
|
2466
3772
|
warnings: warningsJson
|
|
2467
3773
|
}
|
|
@@ -2577,10 +3883,40 @@ var claudeCode = createClaudeCode();
|
|
|
2577
3883
|
|
|
2578
3884
|
// src/index.ts
|
|
2579
3885
|
var import_claude_agent_sdk3 = require("@anthropic-ai/claude-agent-sdk");
|
|
3886
|
+
var import_claude_agent_sdk4 = require("@anthropic-ai/claude-agent-sdk");
|
|
3887
|
+
var import_claude_agent_sdk5 = require("@anthropic-ai/claude-agent-sdk");
|
|
2580
3888
|
|
|
2581
3889
|
// src/mcp-helpers.ts
|
|
2582
3890
|
var import_claude_agent_sdk2 = require("@anthropic-ai/claude-agent-sdk");
|
|
2583
3891
|
var import_zod2 = require("zod");
|
|
3892
|
+
function buildIsErrorResult(text) {
|
|
3893
|
+
return {
|
|
3894
|
+
isError: true,
|
|
3895
|
+
content: [{ type: "text", text }]
|
|
3896
|
+
};
|
|
3897
|
+
}
|
|
3898
|
+
async function normalizeToolResultToText(toolName, result) {
|
|
3899
|
+
if (result != null && typeof result[Symbol.asyncIterator] === "function") {
|
|
3900
|
+
let last;
|
|
3901
|
+
for await (const chunk of result) {
|
|
3902
|
+
last = chunk;
|
|
3903
|
+
}
|
|
3904
|
+
result = last;
|
|
3905
|
+
}
|
|
3906
|
+
if (typeof result === "string") {
|
|
3907
|
+
return { text: result };
|
|
3908
|
+
}
|
|
3909
|
+
try {
|
|
3910
|
+
return { text: JSON.stringify(result) ?? "undefined" };
|
|
3911
|
+
} catch (serializationError) {
|
|
3912
|
+
const reason = serializationError instanceof Error ? serializationError.message : String(serializationError);
|
|
3913
|
+
return {
|
|
3914
|
+
isError: buildIsErrorResult(
|
|
3915
|
+
`Tool "${toolName}" succeeded but its result could not be serialized to JSON: ${reason}`
|
|
3916
|
+
)
|
|
3917
|
+
};
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
2584
3920
|
function createCustomMcpServer(config) {
|
|
2585
3921
|
const defs = Object.entries(config.tools).map(
|
|
2586
3922
|
([name, def]) => (0, import_claude_agent_sdk2.tool)(
|
|
@@ -2593,19 +3929,97 @@ function createCustomMcpServer(config) {
|
|
|
2593
3929
|
);
|
|
2594
3930
|
return (0, import_claude_agent_sdk2.createSdkMcpServer)({ name: config.name, version: config.version, tools: defs });
|
|
2595
3931
|
}
|
|
3932
|
+
var AI_SDK_SCHEMA_SYMBOL = Symbol.for("vercel.ai.schema");
|
|
3933
|
+
function isAiSdkJsonSchema(schema) {
|
|
3934
|
+
return typeof schema === "object" && schema !== null && AI_SDK_SCHEMA_SYMBOL in schema;
|
|
3935
|
+
}
|
|
3936
|
+
function isZodObjectSchema(schema) {
|
|
3937
|
+
if (typeof schema !== "object" || schema === null) {
|
|
3938
|
+
return false;
|
|
3939
|
+
}
|
|
3940
|
+
const candidate = schema;
|
|
3941
|
+
if (!("_zod" in candidate) && !("_def" in candidate)) {
|
|
3942
|
+
return false;
|
|
3943
|
+
}
|
|
3944
|
+
const typeTag = candidate._zod?.def?.type ?? candidate._def?.typeName;
|
|
3945
|
+
if (typeTag !== "object" && typeTag !== "ZodObject") {
|
|
3946
|
+
return false;
|
|
3947
|
+
}
|
|
3948
|
+
return typeof candidate.shape === "object" && candidate.shape !== null;
|
|
3949
|
+
}
|
|
3950
|
+
function createAiSdkMcpServer(name, tools) {
|
|
3951
|
+
const defs = Object.entries(tools).map(([toolName, def]) => {
|
|
3952
|
+
const execute = def.execute;
|
|
3953
|
+
if (typeof execute !== "function") {
|
|
3954
|
+
throw new Error(
|
|
3955
|
+
`createAiSdkMcpServer: tool "${toolName}" has no execute function. Only tools that execute locally can be bridged to the Claude Code CLI.`
|
|
3956
|
+
);
|
|
3957
|
+
}
|
|
3958
|
+
if (isAiSdkJsonSchema(def.inputSchema)) {
|
|
3959
|
+
throw new Error(
|
|
3960
|
+
`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.`
|
|
3961
|
+
);
|
|
3962
|
+
}
|
|
3963
|
+
if (!isZodObjectSchema(def.inputSchema)) {
|
|
3964
|
+
throw new Error(
|
|
3965
|
+
`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.`
|
|
3966
|
+
);
|
|
3967
|
+
}
|
|
3968
|
+
const zodSchema = def.inputSchema;
|
|
3969
|
+
return (0, import_claude_agent_sdk2.tool)(
|
|
3970
|
+
toolName,
|
|
3971
|
+
def.description ?? "",
|
|
3972
|
+
zodSchema.shape,
|
|
3973
|
+
async (args, extra) => {
|
|
3974
|
+
try {
|
|
3975
|
+
const extraInfo = extra ?? {};
|
|
3976
|
+
const result = await execute.call(def, args, {
|
|
3977
|
+
toolCallId: extraInfo.requestId !== void 0 ? String(extraInfo.requestId) : void 0,
|
|
3978
|
+
abortSignal: extraInfo.signal
|
|
3979
|
+
});
|
|
3980
|
+
const normalized = await normalizeToolResultToText(toolName, result);
|
|
3981
|
+
if ("isError" in normalized) {
|
|
3982
|
+
return normalized.isError;
|
|
3983
|
+
}
|
|
3984
|
+
return { content: [{ type: "text", text: normalized.text }] };
|
|
3985
|
+
} catch (error) {
|
|
3986
|
+
return buildIsErrorResult(error instanceof Error ? error.message : String(error));
|
|
3987
|
+
}
|
|
3988
|
+
}
|
|
3989
|
+
);
|
|
3990
|
+
});
|
|
3991
|
+
return (0, import_claude_agent_sdk2.createSdkMcpServer)({ name, tools: defs });
|
|
3992
|
+
}
|
|
2596
3993
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2597
3994
|
0 && (module.exports = {
|
|
3995
|
+
AbortError,
|
|
2598
3996
|
ClaudeCodeLanguageModel,
|
|
3997
|
+
HOOK_EVENTS,
|
|
3998
|
+
InMemorySessionStore,
|
|
3999
|
+
SYSTEM_PROMPT_DYNAMIC_BOUNDARY,
|
|
2599
4000
|
claudeCode,
|
|
2600
4001
|
createAPICallError,
|
|
4002
|
+
createAiSdkMcpServer,
|
|
2601
4003
|
createAuthenticationError,
|
|
2602
4004
|
createClaudeCode,
|
|
2603
4005
|
createCustomMcpServer,
|
|
2604
4006
|
createSdkMcpServer,
|
|
2605
4007
|
createTimeoutError,
|
|
4008
|
+
deleteSession,
|
|
4009
|
+
foldSessionSummary,
|
|
4010
|
+
forkSession,
|
|
2606
4011
|
getErrorMetadata,
|
|
4012
|
+
getSessionInfo,
|
|
4013
|
+
getSessionMessages,
|
|
4014
|
+
getSubagentMessages,
|
|
4015
|
+
importSessionToStore,
|
|
2607
4016
|
isAuthenticationError,
|
|
2608
4017
|
isTimeoutError,
|
|
4018
|
+
listSessions,
|
|
4019
|
+
listSubagents,
|
|
4020
|
+
renameSession,
|
|
4021
|
+
startup,
|
|
4022
|
+
tagSession,
|
|
2609
4023
|
tool
|
|
2610
4024
|
});
|
|
2611
4025
|
//# sourceMappingURL=index.cjs.map
|