@mono-agent/agent-runtime 0.20.11 → 0.21.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/ARCHITECTURE.md +50 -11
- package/MIGRATION.md +288 -26
- package/README.md +352 -477
- package/package.json +13 -44
- package/src/agent/tool-bloat.js +145 -9
- package/src/agent/tools/agent-tool.js +108 -9
- package/src/agent/tools/bash.js +11 -26
- package/src/agent/tools/codex-subscription-search.js +123 -29
- package/src/agent/tools/exec.js +10 -2
- package/src/agent/tools/index.js +7 -0
- package/src/agent/tools/monitor.js +149 -0
- package/src/agent/tools/pi-bridge.js +123 -19
- package/src/agent/tools/shared/bash-environment.js +31 -0
- package/src/agent/tools/shared/monitors.js +293 -0
- package/src/agent/tools/shared/path-resolver.js +25 -6
- package/src/agent/tools/shared/process-jobs.js +6 -1
- package/src/agent/tools/shared/process-runner.js +26 -6
- package/src/agent/tools/shared/tool-context.js +8 -0
- package/src/agent/tools/web-access-interstitial.js +70 -0
- package/src/agent/tools/web-browser-render.js +83 -58
- package/src/agent/tools/web-controller.js +112 -21
- package/src/agent/tools/web-document-extractor.js +379 -0
- package/src/agent/tools/web-fetch.js +271 -243
- package/src/agent/tools/web-request.js +65 -0
- package/src/agent/tools/web-search-output.js +165 -0
- package/src/agent/tools/web-search-state.js +75 -0
- package/src/agent/tools/web-search.js +532 -71
- package/src/ai/cost.js +13 -68
- package/src/ai/failure.js +3 -3
- package/src/ai/index.js +5 -17
- package/src/ai/observer.js +8 -0
- package/src/ai/pi-interop.js +221 -1
- package/src/ai/pi-oauth-compat.js +1 -1
- package/src/ai/provider-check.js +131 -0
- package/src/ai/providers/codex/app-server-client.js +592 -0
- package/src/ai/providers/pi-models.js +18 -10
- package/src/ai/providers/pi-native/compaction-driver.js +94 -42
- package/src/ai/providers/pi-native/compaction-summary.js +140 -0
- package/src/ai/providers/pi-native/harness-adapter.js +376 -0
- package/src/ai/providers/pi-native/prompt-cache-diagnostics.js +103 -0
- package/src/ai/providers/pi-native/provider-attribution.js +102 -0
- package/src/ai/providers/pi-native/result-builder.js +38 -14
- package/src/ai/providers/pi-native/session-lifecycle.js +253 -55
- package/src/ai/providers/pi-native/stream-subscriber.js +52 -6
- package/src/ai/providers/pi-native/terminal-recovery.js +40 -0
- package/src/ai/providers/pi-native/turn-runner.js +279 -28
- package/src/ai/providers/pi-native.js +206 -61
- package/src/ai/runtime/capabilities.js +11 -56
- package/src/ai/runtime/live-input-events.js +250 -54
- package/src/ai/runtime/model-refs.js +118 -153
- package/src/ai/runtime/registry.js +22 -56
- package/src/ai/runtime/router.js +76 -417
- package/src/ai/runtime/session-liveness.js +3 -4
- package/src/ai/runtime/sessions.js +4 -5
- package/src/ai/runtime/tool-policy.js +0 -2
- package/src/ai/tool-lifecycle.js +32 -18
- package/src/ai/types.js +37 -112
- package/src/index.js +0 -6
- package/src/runtime.js +29 -16
- package/types/agent/tool-bloat.d.ts +1 -1
- package/types/agent/tools/agent-tool.d.ts +4 -2
- package/types/agent/tools/bash.d.ts +5 -3
- package/types/agent/tools/codex-subscription-search.d.ts +7 -3
- package/types/agent/tools/exec.d.ts +5 -3
- package/types/agent/tools/index.d.ts +1 -0
- package/types/agent/tools/monitor.d.ts +47 -0
- package/types/agent/tools/pi-bridge.d.ts +7 -4
- package/types/agent/tools/shared/bash-environment.d.ts +4 -0
- package/types/agent/tools/shared/monitors.d.ts +98 -0
- package/types/agent/tools/shared/process-jobs.d.ts +5 -1
- package/types/agent/tools/shared/process-runner.d.ts +14 -4
- package/types/agent/tools/shared/tool-context.d.ts +2 -0
- package/types/agent/tools/web-access-interstitial.d.ts +23 -0
- package/types/agent/tools/web-browser-render.d.ts +4 -1
- package/types/agent/tools/web-controller.d.ts +4 -2
- package/types/agent/tools/web-document-extractor.d.ts +27 -0
- package/types/agent/tools/web-fetch.d.ts +19 -24
- package/types/agent/tools/web-request.d.ts +20 -0
- package/types/agent/tools/web-search-output.d.ts +31 -0
- package/types/agent/tools/web-search-state.d.ts +21 -0
- package/types/agent/tools/web-search.d.ts +10 -45
- package/types/ai/cost.d.ts +1 -2
- package/types/ai/index.d.ts +2 -4
- package/types/ai/observer.d.ts +6 -0
- package/types/ai/pi-interop.d.ts +81 -0
- package/types/ai/provider-check.d.ts +53 -0
- package/types/ai/providers/codex/app-server-client.d.ts +37 -0
- package/types/ai/providers/pi-native/compaction-driver.d.ts +2 -1
- package/types/ai/providers/pi-native/compaction-summary.d.ts +19 -0
- package/types/ai/providers/pi-native/harness-adapter.d.ts +58 -0
- package/types/ai/providers/pi-native/prompt-cache-diagnostics.d.ts +3 -0
- package/types/ai/providers/pi-native/provider-attribution.d.ts +26 -0
- package/types/ai/providers/pi-native/result-builder.d.ts +14 -4
- package/types/ai/providers/pi-native/session-lifecycle.d.ts +25 -6
- package/types/ai/providers/pi-native/stream-subscriber.d.ts +2 -2
- package/types/ai/providers/pi-native/terminal-recovery.d.ts +2 -0
- package/types/ai/providers/pi-native/turn-runner.d.ts +68 -10
- package/types/ai/providers/pi-native.d.ts +21 -4
- package/types/ai/runtime/capabilities.d.ts +21 -70
- package/types/ai/runtime/live-input-events.d.ts +32 -8
- package/types/ai/runtime/model-refs.d.ts +0 -24
- package/types/ai/runtime/router.d.ts +3 -10
- package/types/ai/runtime/tool-policy.d.ts +0 -2
- package/types/ai/tool-lifecycle.d.ts +4 -3
- package/types/ai/types.d.ts +162 -256
- package/types/index.d.ts +0 -1
- package/src/ai/providers/acp-client.js +0 -1149
- package/src/ai/providers/acp-privacy.js +0 -124
- package/src/ai/providers/acp-public.js +0 -21
- package/src/ai/providers/acp-session-tokens.js +0 -282
- package/src/ai/providers/acp-transport.js +0 -356
- package/src/ai/providers/acp.js +0 -543
- package/src/ai/providers/claude-cli.js +0 -883
- package/src/ai/providers/claude-sandbox.js +0 -71
- package/src/ai/providers/claude-sdk-discovery-worker.js +0 -53
- package/src/ai/providers/claude-sdk-discovery.js +0 -352
- package/src/ai/providers/claude-sdk.js +0 -1127
- package/src/ai/providers/claude-subagent-activity.js +0 -719
- package/src/ai/providers/claude-subagents.js +0 -88
- package/src/ai/providers/codex-app.js +0 -2946
- package/src/ai/providers/opencode-app.js +0 -1109
- package/src/ai/providers/opencode-discovery.js +0 -39
- package/src/ai/providers/opencode-server.js +0 -508
- package/src/ai/runtime/context-windows.js +0 -46
- package/src/ai/runtime/fast-mode.js +0 -8
- package/src/ai/streaming/codex-events.js +0 -146
- package/src/ai/streaming/opencode-events.js +0 -59
- package/types/ai/providers/acp-client.d.ts +0 -227
- package/types/ai/providers/acp-privacy.d.ts +0 -25
- package/types/ai/providers/acp-public.d.ts +0 -7
- package/types/ai/providers/acp-session-tokens.d.ts +0 -41
- package/types/ai/providers/acp-transport.d.ts +0 -45
- package/types/ai/providers/acp.d.ts +0 -93
- package/types/ai/providers/claude-cli.d.ts +0 -305
- package/types/ai/providers/claude-sandbox.d.ts +0 -79
- package/types/ai/providers/claude-sdk-discovery-worker.d.ts +0 -1
- package/types/ai/providers/claude-sdk-discovery.d.ts +0 -97
- package/types/ai/providers/claude-sdk.d.ts +0 -138
- package/types/ai/providers/claude-subagent-activity.d.ts +0 -53
- package/types/ai/providers/claude-subagents.d.ts +0 -18
- package/types/ai/providers/codex-app.d.ts +0 -151
- package/types/ai/providers/opencode-app.d.ts +0 -96
- package/types/ai/providers/opencode-discovery.d.ts +0 -4
- package/types/ai/providers/opencode-server.d.ts +0 -20
- package/types/ai/runtime/context-windows.d.ts +0 -9
- package/types/ai/runtime/fast-mode.d.ts +0 -2
- package/types/ai/streaming/codex-events.d.ts +0 -40
- package/types/ai/streaming/opencode-events.d.ts +0 -42
|
@@ -1,1127 +0,0 @@
|
|
|
1
|
-
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
-
import { randomUUID } from "node:crypto";
|
|
3
|
-
import { formatLiveInputGuidance } from "../live-input-prompt.js";
|
|
4
|
-
import { estimateCost } from "../cost.js";
|
|
5
|
-
import { modelWithContextWindow } from "../runtime/context-windows.js";
|
|
6
|
-
import { runtimeCapabilities } from "../runtime/capabilities.js";
|
|
7
|
-
import { buildCapabilitiesUsed, toolCompactionAppliedFromWarnings } from "../runtime/capabilities-used.js";
|
|
8
|
-
import { MAX_TOOL_RESULT_BYTES, summarisePayload } from "../../agent/tool-bloat.js";
|
|
9
|
-
import { normalizeMcpToolParams } from "../../agent/tools/pi-bridge.js";
|
|
10
|
-
import { deprecatedSettingsWarning } from "../../agent/compaction.js";
|
|
11
|
-
import { readRuntimeBrand } from "../../agent/tools/shared/runtime-context.js";
|
|
12
|
-
import { createApprovalManager } from "../../agent/approval.js";
|
|
13
|
-
import {
|
|
14
|
-
claudeNativeAgentDefinitions,
|
|
15
|
-
resolveClaudeAllowedTools,
|
|
16
|
-
} from "./claude-subagents.js";
|
|
17
|
-
import {
|
|
18
|
-
claudeSandboxCapabilityMismatchResult,
|
|
19
|
-
claudeSandboxPolicyProblem,
|
|
20
|
-
} from "./claude-sandbox.js";
|
|
21
|
-
import { createClaudeSubagentActivityNormalizer } from "./claude-subagent-activity.js";
|
|
22
|
-
import { toolLifecycleMetadata } from "../tool-lifecycle.js";
|
|
23
|
-
|
|
24
|
-
const CLAUDE_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh", "max"]);
|
|
25
|
-
const CLAUDE_SETTING_SOURCES = new Set(["user", "project", "local"]);
|
|
26
|
-
const MAX_CLAUDE_ERROR_CHARS = 2_000;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Filesystem settings the Agent SDK may load for this run. The SDK's own default
|
|
30
|
-
* is "load nothing", and mono-agent keeps that default so a hosted run stays
|
|
31
|
-
* reproducible: no host CLAUDE.md, hooks, or plugins leak in unless the caller
|
|
32
|
-
* asks for them. A host that *wants* on-disk discovery — typically to reach
|
|
33
|
-
* `.claude/agents` so the native `Task` tool has profiles to deploy — opts in per
|
|
34
|
-
* run. Unrecognized entries are dropped rather than forwarded, so a typo cannot
|
|
35
|
-
* silently widen what the SDK reads off disk.
|
|
36
|
-
* @param {unknown} value
|
|
37
|
-
* @returns {Array<"user" | "project" | "local">}
|
|
38
|
-
*/
|
|
39
|
-
function normalizeClaudeSettingSources(value) {
|
|
40
|
-
if (!Array.isArray(value)) return [];
|
|
41
|
-
return Array.from(new Set(value.filter((entry) => CLAUDE_SETTING_SOURCES.has(entry))));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Preserve the provider default when effort is omitted. The current Agent SDK
|
|
46
|
-
* public effort contract accepts the five values below. Its shipped JavaScript
|
|
47
|
-
* currently forwards out-of-contract values to Claude Code, so mono-agent keeps
|
|
48
|
-
* this route inside the pinned public contract rather than relying on that
|
|
49
|
-
* untyped pass-through. Mono-agent must not infer thinking enablement/disablement
|
|
50
|
-
* from a requested effort level.
|
|
51
|
-
* @param {unknown} effort
|
|
52
|
-
* @returns {{effort?: "low" | "medium" | "high" | "xhigh" | "max"}}
|
|
53
|
-
*/
|
|
54
|
-
export function claudeEffortOptions(effort) {
|
|
55
|
-
if (effort == null || String(effort).trim() === "") return {};
|
|
56
|
-
const normalized = String(effort).trim();
|
|
57
|
-
if (normalized === "none") {
|
|
58
|
-
throw new Error(
|
|
59
|
-
'Mono-agent\'s Claude SDK route does not support effort "none": the pinned Claude Agent SDK public effort contract starts at "low". Omit effort to use the provider default, or choose low, medium, high, xhigh, or max.',
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
if (!CLAUDE_EFFORT_LEVELS.has(normalized)) {
|
|
63
|
-
throw new Error(
|
|
64
|
-
`Mono-agent's Claude SDK route does not support effort "${boundedText(normalized, 64)}": the pinned Claude Agent SDK public effort contract ends at "max". Choose low, medium, high, xhigh, or max, or omit effort.`,
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
return { effort: /** @type {"low" | "medium" | "high" | "xhigh" | "max"} */ (normalized) };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function boundedText(value, limit = MAX_CLAUDE_ERROR_CHARS) {
|
|
71
|
-
const text = String(value ?? "").replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
|
|
72
|
-
if (text.length <= limit) return text;
|
|
73
|
-
return `${text.slice(0, Math.max(0, limit - 16))}… [truncated]`;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function createClaudeSdkEnvironment(overrides, providerEnvironment) {
|
|
77
|
-
return {
|
|
78
|
-
...process.env,
|
|
79
|
-
...(overrides && typeof overrides === "object" ? overrides : {}),
|
|
80
|
-
...(providerEnvironment && typeof providerEnvironment === "object" ? providerEnvironment : {}),
|
|
81
|
-
MCP_CONNECTION_NONBLOCKING: "0",
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** @param {string} model @param {unknown} contextWindow */
|
|
86
|
-
export function claudeSdkModelForQuery(model, contextWindow) {
|
|
87
|
-
return modelWithContextWindow(model, contextWindow);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function extractText(event) {
|
|
91
|
-
if (event.type !== "assistant" || !event.message?.content) return "";
|
|
92
|
-
let out = "";
|
|
93
|
-
for (const block of event.message.content) {
|
|
94
|
-
if (block.type === "text") out += block.text;
|
|
95
|
-
}
|
|
96
|
-
return out;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function assistantToolNames(event) {
|
|
100
|
-
if (event.type !== "assistant" || !Array.isArray(event.message?.content)) return [];
|
|
101
|
-
return event.message.content
|
|
102
|
-
.filter((block) => block?.type === "tool_use" && block.name)
|
|
103
|
-
.map((block) => block.name);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function assistantThinkingObserved(event) {
|
|
107
|
-
return event?.type === "assistant"
|
|
108
|
-
&& Array.isArray(event.message?.content)
|
|
109
|
-
&& event.message.content.some((block) => block?.type === "thinking" || block?.type === "redacted_thinking");
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function extractResultText(event) {
|
|
113
|
-
if (event.type !== "result") return "";
|
|
114
|
-
if (typeof event.result === "string") return event.result;
|
|
115
|
-
if (event.result != null) return JSON.stringify(event.result);
|
|
116
|
-
if (typeof event.final_output === "string") return event.final_output;
|
|
117
|
-
if (event.final_output != null) return JSON.stringify(event.final_output);
|
|
118
|
-
return "";
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function stringifyError(value) {
|
|
122
|
-
if (!value) return "";
|
|
123
|
-
if (typeof value === "string") return value;
|
|
124
|
-
if (typeof value.message === "string") return value.message;
|
|
125
|
-
try { return JSON.stringify(value); } catch { return String(value); }
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function claudeAssistantFailure(code, requestId = null) {
|
|
129
|
-
const normalizedCode = boundedText(code || "unknown", 80);
|
|
130
|
-
const mapping = {
|
|
131
|
-
authentication_failed: {
|
|
132
|
-
message: "Claude authentication failed. Sign in again or provide a valid Claude credential.",
|
|
133
|
-
failureKind: "provider_auth",
|
|
134
|
-
category: "authentication",
|
|
135
|
-
retryable: false,
|
|
136
|
-
},
|
|
137
|
-
oauth_org_not_allowed: {
|
|
138
|
-
message: "Claude authentication succeeded, but this organization does not allow the OAuth session.",
|
|
139
|
-
failureKind: "provider_auth",
|
|
140
|
-
category: "authentication",
|
|
141
|
-
retryable: false,
|
|
142
|
-
},
|
|
143
|
-
rate_limit: {
|
|
144
|
-
message: "Claude usage or rate limit reached.",
|
|
145
|
-
failureKind: "usage_limit",
|
|
146
|
-
category: "usage_limit",
|
|
147
|
-
retryable: false,
|
|
148
|
-
},
|
|
149
|
-
max_output_tokens: {
|
|
150
|
-
message: "Claude reached the maximum output-token limit.",
|
|
151
|
-
failureKind: "usage_limit",
|
|
152
|
-
category: "usage_limit",
|
|
153
|
-
retryable: false,
|
|
154
|
-
},
|
|
155
|
-
overloaded: {
|
|
156
|
-
message: "Claude is temporarily overloaded.",
|
|
157
|
-
failureKind: "provider_unavailable",
|
|
158
|
-
category: "provider_unavailable",
|
|
159
|
-
retryable: true,
|
|
160
|
-
},
|
|
161
|
-
server_error: {
|
|
162
|
-
message: "Claude returned a temporary server error.",
|
|
163
|
-
failureKind: "provider_unavailable",
|
|
164
|
-
category: "provider_unavailable",
|
|
165
|
-
retryable: true,
|
|
166
|
-
},
|
|
167
|
-
billing_error: {
|
|
168
|
-
message: "Claude rejected the request because the account needs billing attention.",
|
|
169
|
-
failureKind: "provider_unavailable",
|
|
170
|
-
category: "nonretryable",
|
|
171
|
-
retryable: false,
|
|
172
|
-
},
|
|
173
|
-
invalid_request: {
|
|
174
|
-
message: "Claude rejected the request as invalid.",
|
|
175
|
-
failureKind: "provider_unavailable",
|
|
176
|
-
category: "nonretryable",
|
|
177
|
-
retryable: false,
|
|
178
|
-
},
|
|
179
|
-
model_not_found: {
|
|
180
|
-
message: "Claude could not find or access the requested model.",
|
|
181
|
-
failureKind: "provider_unavailable",
|
|
182
|
-
category: "nonretryable",
|
|
183
|
-
retryable: false,
|
|
184
|
-
},
|
|
185
|
-
unknown: {
|
|
186
|
-
message: "Claude reported an unknown provider error.",
|
|
187
|
-
failureKind: "provider_unavailable",
|
|
188
|
-
category: "unknown",
|
|
189
|
-
retryable: false,
|
|
190
|
-
},
|
|
191
|
-
};
|
|
192
|
-
const selected = mapping[normalizedCode] || mapping.unknown;
|
|
193
|
-
const safeRequestId = typeof requestId === "string" && requestId.trim()
|
|
194
|
-
? boundedText(requestId, 160)
|
|
195
|
-
: null;
|
|
196
|
-
return {
|
|
197
|
-
...selected,
|
|
198
|
-
code: normalizedCode,
|
|
199
|
-
requestId: safeRequestId,
|
|
200
|
-
message: `${selected.message}${safeRequestId ? ` Request ID: ${safeRequestId}.` : ""}`,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function resultFailureCategory(event, resultError) {
|
|
205
|
-
const text = `${resultError?.message || ""} ${Array.isArray(event?.errors) ? event.errors.join(" ") : ""}`;
|
|
206
|
-
if (/auth|oauth|api key|401|403|sign[ -]?in|log[ -]?in/i.test(text)) {
|
|
207
|
-
return claudeAssistantFailure("authentication_failed");
|
|
208
|
-
}
|
|
209
|
-
if (event?.subtype === "error_max_turns" || event?.subtype === "error_max_budget_usd") {
|
|
210
|
-
return {
|
|
211
|
-
message: boundedText(resultError?.message || "Claude usage limit reached."),
|
|
212
|
-
failureKind: "usage_limit",
|
|
213
|
-
category: "usage_limit",
|
|
214
|
-
retryable: false,
|
|
215
|
-
code: event.subtype,
|
|
216
|
-
requestId: null,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
if (/overload|temporar|server error|\b50[0234]\b/i.test(text)) {
|
|
220
|
-
return {
|
|
221
|
-
message: boundedText(resultError?.message || "Claude is temporarily unavailable."),
|
|
222
|
-
failureKind: "provider_unavailable",
|
|
223
|
-
category: "provider_unavailable",
|
|
224
|
-
retryable: true,
|
|
225
|
-
code: event?.subtype || "result_error",
|
|
226
|
-
requestId: null,
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
return {
|
|
230
|
-
message: boundedText(resultError?.message || "Claude request failed."),
|
|
231
|
-
failureKind: resultError?.failureKind || "provider_unavailable",
|
|
232
|
-
category: resultError?.failureKind === "invalid_result" ? "nonretryable" : "unknown",
|
|
233
|
-
retryable: false,
|
|
234
|
-
code: event?.subtype || "result_error",
|
|
235
|
-
requestId: null,
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function humanizeSubtype(subtype) {
|
|
240
|
-
return String(subtype || "").replace(/^error_/, "").replace(/_/g, " ").trim();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function resultEventError(event) {
|
|
244
|
-
if (event.type !== "result") return null;
|
|
245
|
-
const subtype = typeof event.subtype === "string" ? event.subtype : "";
|
|
246
|
-
const errors = Array.isArray(event.errors) ? event.errors.filter(Boolean) : [];
|
|
247
|
-
const explicit = stringifyError(event.error) || stringifyError(event.message);
|
|
248
|
-
if (!event.is_error && !subtype.startsWith("error_") && errors.length === 0 && !explicit) return null;
|
|
249
|
-
|
|
250
|
-
const detail = explicit || errors.map(stringifyError).filter(Boolean).join("; ");
|
|
251
|
-
const label = humanizeSubtype(subtype);
|
|
252
|
-
const message = subtype === "error_max_turns"
|
|
253
|
-
? "Claude stopped before final output: max turns reached"
|
|
254
|
-
: `Claude result error${label ? ` (${label})` : ""}${detail ? `: ${detail}` : ""}`;
|
|
255
|
-
return {
|
|
256
|
-
message: boundedText(message),
|
|
257
|
-
failureKind: subtype === "error_max_turns"
|
|
258
|
-
? "usage_limit"
|
|
259
|
-
: subtype === "error_max_structured_output_retries"
|
|
260
|
-
? "invalid_result"
|
|
261
|
-
: "provider_unavailable",
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function makeRuntimeWarning(message, warningKind = "claude_post_success_error") {
|
|
266
|
-
return {
|
|
267
|
-
warning_kind: warningKind,
|
|
268
|
-
message,
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function extractStructuredOutput(event) {
|
|
273
|
-
if (event?.type === "result" && Object.prototype.hasOwnProperty.call(event, "structured_output")) {
|
|
274
|
-
return event.structured_output;
|
|
275
|
-
}
|
|
276
|
-
return undefined;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
function structuredOutputEvent(value) {
|
|
280
|
-
return {
|
|
281
|
-
type: "structured_output",
|
|
282
|
-
source: "claude_sdk_output_format",
|
|
283
|
-
value,
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
function structuredOutputToolUses(event) {
|
|
288
|
-
if (event?.type !== "assistant" || !Array.isArray(event.message?.content)) return [];
|
|
289
|
-
return event.message.content
|
|
290
|
-
.filter((block) => (
|
|
291
|
-
block?.type === "tool_use"
|
|
292
|
-
&& block?.name === "StructuredOutput"
|
|
293
|
-
&& block.input !== undefined
|
|
294
|
-
&& (block.id || block.tool_use_id)
|
|
295
|
-
))
|
|
296
|
-
.map((block) => ({
|
|
297
|
-
id: block.id || block.tool_use_id,
|
|
298
|
-
input: block.input,
|
|
299
|
-
}));
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function acceptedStructuredOutputValues(event, pendingStructuredOutputById) {
|
|
303
|
-
if (event?.type !== "user" || !Array.isArray(event.message?.content)) return [];
|
|
304
|
-
const values = [];
|
|
305
|
-
for (const block of event.message.content) {
|
|
306
|
-
if (block?.type !== "tool_result") continue;
|
|
307
|
-
const id = block.tool_use_id || block.toolUseId;
|
|
308
|
-
if (!id || !pendingStructuredOutputById.has(id)) continue;
|
|
309
|
-
const value = pendingStructuredOutputById.get(id);
|
|
310
|
-
pendingStructuredOutputById.delete(id);
|
|
311
|
-
if (block.is_error === true) continue;
|
|
312
|
-
values.push(value);
|
|
313
|
-
}
|
|
314
|
-
return values;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function pickSessionId(...values) {
|
|
318
|
-
for (const value of values) {
|
|
319
|
-
if (typeof value === "string" && value.trim()) return value.trim();
|
|
320
|
-
}
|
|
321
|
-
return null;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
function sessionIdFromEvent(event) {
|
|
325
|
-
return pickSessionId(event?.session_id, event?.sessionId);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
function lastTextSnippet(texts, limit = 200) {
|
|
329
|
-
for (let i = texts.length - 1; i >= 0; i -= 1) {
|
|
330
|
-
const text = texts[i];
|
|
331
|
-
if (typeof text === "string" && text.trim()) {
|
|
332
|
-
const trimmed = text.trim();
|
|
333
|
-
return trimmed.length > limit ? trimmed.slice(-limit) : trimmed;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
return null;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
function buildClaudeErrorDetails({
|
|
340
|
-
event = null,
|
|
341
|
-
subtype = null,
|
|
342
|
-
providerSessionId = null,
|
|
343
|
-
assistantTexts = [],
|
|
344
|
-
lastToolName = null,
|
|
345
|
-
toolResultsSeen = 0,
|
|
346
|
-
numTurns = 0,
|
|
347
|
-
lastStructuredOutputRejection = null,
|
|
348
|
-
failureCode = null,
|
|
349
|
-
failureCategory = null,
|
|
350
|
-
retryable = null,
|
|
351
|
-
requestId = null,
|
|
352
|
-
}) {
|
|
353
|
-
const rawSubtype = subtype || event?.subtype || event?.type || null;
|
|
354
|
-
const resolvedSubtype = rawSubtype == null ? null : boundedText(rawSubtype, 160);
|
|
355
|
-
const turnCount = Number(event?.num_turns ?? numTurns) || 0;
|
|
356
|
-
const excerpt = lastTextSnippet(assistantTexts);
|
|
357
|
-
return {
|
|
358
|
-
claude_error_subtype: resolvedSubtype,
|
|
359
|
-
last_text_excerpt: excerpt,
|
|
360
|
-
last_tool_name: lastToolName ? boundedText(lastToolName, 160) : null,
|
|
361
|
-
had_partial_progress: !!(excerpt || lastToolName || toolResultsSeen > 0),
|
|
362
|
-
tool_results_seen: toolResultsSeen,
|
|
363
|
-
turn_count: turnCount,
|
|
364
|
-
max_turns_hit: resolvedSubtype === "error_max_turns",
|
|
365
|
-
structured_output_retry_exhausted: resolvedSubtype === "error_max_structured_output_retries",
|
|
366
|
-
last_structured_output_rejection: lastStructuredOutputRejection
|
|
367
|
-
? boundedText(lastStructuredOutputRejection, 500)
|
|
368
|
-
: null,
|
|
369
|
-
provider_session_id: providerSessionId ? boundedText(providerSessionId, 160) : null,
|
|
370
|
-
claude_error_code: failureCode ? boundedText(failureCode, 80) : null,
|
|
371
|
-
claude_error_category: failureCategory || null,
|
|
372
|
-
retryable: typeof retryable === "boolean" ? retryable : null,
|
|
373
|
-
request_id: requestId || null,
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
function toolResultText(block) {
|
|
378
|
-
const content = block?.content;
|
|
379
|
-
if (typeof content === "string") return content;
|
|
380
|
-
if (Array.isArray(content)) {
|
|
381
|
-
return content.map((item) => item?.text || item?.content || "").filter(Boolean).join("\n");
|
|
382
|
-
}
|
|
383
|
-
if (content == null) return "";
|
|
384
|
-
try { return JSON.stringify(content); } catch { return String(content); }
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function annotateClaudeToolLifecycles(event) {
|
|
388
|
-
if (event?.type !== "user" || !Array.isArray(event.message?.content)) return;
|
|
389
|
-
for (const block of event.message.content) {
|
|
390
|
-
if (!block || block.type !== "tool_result") continue;
|
|
391
|
-
block.tool_lifecycle = toolLifecycleMetadata(block.is_error === true
|
|
392
|
-
? { state: "error", failure_kind: "runtime_error", detail_code: "claude_sdk_tool_error" }
|
|
393
|
-
: { state: "success" });
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
function structuredOutputRejectionFromEvent(event) {
|
|
398
|
-
if (event?.type !== "user" || !Array.isArray(event.message?.content)) return null;
|
|
399
|
-
for (const block of event.message.content) {
|
|
400
|
-
if (block?.type === "tool_result" && block.is_error) {
|
|
401
|
-
const text = toolResultText(block);
|
|
402
|
-
if (/structured output|required schema|did not match schema|schema violation/i.test(text)) return text;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
const result = event.is_error === true ? stringifyError(event.tool_use_result) : null;
|
|
406
|
-
return /structured output|required schema|did not match schema|schema violation/i.test(result) ? result : null;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
function mergeHookMatchers(existing = {}, additions = {}) {
|
|
410
|
-
const merged = {};
|
|
411
|
-
for (const [name, groups] of Object.entries(existing || {})) {
|
|
412
|
-
if (Array.isArray(groups)) merged[name] = [...groups];
|
|
413
|
-
}
|
|
414
|
-
for (const [name, groups] of Object.entries(additions || {})) {
|
|
415
|
-
if (!Array.isArray(groups) || !groups.length) continue;
|
|
416
|
-
merged[name] = [...(merged[name] || []), ...groups];
|
|
417
|
-
}
|
|
418
|
-
return merged;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function objectInput(value) {
|
|
422
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
function parseMcpToolName(toolName) {
|
|
426
|
-
const name = String(toolName || "");
|
|
427
|
-
if (!name.startsWith("mcp__")) return null;
|
|
428
|
-
const rest = name.slice(5);
|
|
429
|
-
const sep = rest.indexOf("__");
|
|
430
|
-
if (sep <= 0) return null;
|
|
431
|
-
return {
|
|
432
|
-
serverName: rest.slice(0, sep),
|
|
433
|
-
toolName: rest.slice(sep + 2),
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
function normalizeClaudeMcpInput(input, qaOutputDir) {
|
|
438
|
-
const parsed = parseMcpToolName(input?.tool_name);
|
|
439
|
-
if (!parsed) return null;
|
|
440
|
-
const current = objectInput(input?.tool_input);
|
|
441
|
-
const normalized = normalizeMcpToolParams(parsed.serverName, parsed.toolName, current, { qaOutputDir });
|
|
442
|
-
if (normalized === current) return null;
|
|
443
|
-
try {
|
|
444
|
-
if (JSON.stringify(normalized) === JSON.stringify(current)) return null;
|
|
445
|
-
} catch {
|
|
446
|
-
// Non-serializable input is unexpected, but returning an SDK override is
|
|
447
|
-
// still safe when the normalizer produced a different object.
|
|
448
|
-
}
|
|
449
|
-
return normalized;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
function claudeToolResponseBlocks(toolResponse) {
|
|
453
|
-
if (toolResponse && typeof toolResponse === "object" && Array.isArray(toolResponse.content)) {
|
|
454
|
-
return toolResponse.content;
|
|
455
|
-
}
|
|
456
|
-
if (typeof toolResponse === "string") return [{ type: "text", text: toolResponse }];
|
|
457
|
-
if (toolResponse == null) return [];
|
|
458
|
-
try {
|
|
459
|
-
return [{ type: "text", text: JSON.stringify(toolResponse) }];
|
|
460
|
-
} catch {
|
|
461
|
-
return [{ type: "text", text: String(toolResponse) }];
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// Resolve the tool_result byte cap. Precedence is PER-GROUP (MIGRATION.md §8):
|
|
466
|
-
// explicit options.toolPayloadMaxBytes
|
|
467
|
-
// -> typed options.toolLimits — when this group is PRESENT it wins wholesale:
|
|
468
|
-
// its toolPayloadMaxBytes is used if valid, otherwise the default; the
|
|
469
|
-
// DEPRECATED settings fallback below is never consulted for this group,
|
|
470
|
-
// even if toolLimits.toolPayloadMaxBytes itself is absent/invalid.
|
|
471
|
-
// -> DEPRECATED options.settings.agent_tool_payload_max_bytes (usedSettings),
|
|
472
|
-
// only consulted when options.toolLimits is entirely absent.
|
|
473
|
-
// -> MAX_TOOL_RESULT_BYTES default.
|
|
474
|
-
// `usedSettings` lets the caller emit one deprecation warning per run when the
|
|
475
|
-
// legacy settings fallback was actually consumed.
|
|
476
|
-
export function toolPayloadLimit(options) {
|
|
477
|
-
const explicit = Number(options.toolPayloadMaxBytes);
|
|
478
|
-
if (Number.isFinite(explicit) && explicit > 0) return { bytes: Math.floor(explicit), usedSettings: false };
|
|
479
|
-
if (options.toolLimits) {
|
|
480
|
-
const typed = Number(options.toolLimits.toolPayloadMaxBytes);
|
|
481
|
-
if (Number.isFinite(typed) && typed > 0) return { bytes: Math.floor(typed), usedSettings: false };
|
|
482
|
-
return { bytes: MAX_TOOL_RESULT_BYTES, usedSettings: false };
|
|
483
|
-
}
|
|
484
|
-
const configured = Number(options.settings?.agent_tool_payload_max_bytes);
|
|
485
|
-
if (Number.isFinite(configured) && configured > 0) return { bytes: Math.floor(configured), usedSettings: true };
|
|
486
|
-
return { bytes: MAX_TOOL_RESULT_BYTES, usedSettings: false };
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
function createClaudeRuntimeHooks({
|
|
490
|
-
emitEvent,
|
|
491
|
-
persistArtifact,
|
|
492
|
-
qaOutputDir,
|
|
493
|
-
toolPayloadMaxBytes,
|
|
494
|
-
onToolUse,
|
|
495
|
-
onToolResult,
|
|
496
|
-
}) {
|
|
497
|
-
return {
|
|
498
|
-
PreToolUse: [{
|
|
499
|
-
matcher: "*",
|
|
500
|
-
hooks: [async (input) => {
|
|
501
|
-
onToolUse?.(input?.tool_name);
|
|
502
|
-
const updatedInput = normalizeClaudeMcpInput(input, qaOutputDir);
|
|
503
|
-
if (!updatedInput) return {};
|
|
504
|
-
return {
|
|
505
|
-
continue: true,
|
|
506
|
-
hookSpecificOutput: {
|
|
507
|
-
hookEventName: "PreToolUse",
|
|
508
|
-
updatedInput,
|
|
509
|
-
},
|
|
510
|
-
};
|
|
511
|
-
}],
|
|
512
|
-
}],
|
|
513
|
-
PostToolUse: [{
|
|
514
|
-
matcher: "*",
|
|
515
|
-
hooks: [async (input, toolUseID) => {
|
|
516
|
-
const toolName = input?.tool_name || "tool";
|
|
517
|
-
onToolUse?.(toolName);
|
|
518
|
-
onToolResult?.(toolName);
|
|
519
|
-
const blocks = claudeToolResponseBlocks(input?.tool_response);
|
|
520
|
-
if (!blocks.length) return {};
|
|
521
|
-
const summary = summarisePayload(toolName, blocks, persistArtifact, {
|
|
522
|
-
maxBytes: toolPayloadMaxBytes,
|
|
523
|
-
toolUseId: toolUseID || input?.tool_use_id || input?.toolUseID || null,
|
|
524
|
-
});
|
|
525
|
-
if (!summary.truncated) return {};
|
|
526
|
-
emitEvent({
|
|
527
|
-
type: "runtime_warning",
|
|
528
|
-
warning_kind: "tool_payload_truncated",
|
|
529
|
-
source: "tool_bloat_guard",
|
|
530
|
-
tool: toolName,
|
|
531
|
-
tool_use_id: toolUseID || input?.tool_use_id || input?.toolUseID || null,
|
|
532
|
-
original_bytes: summary.originalBytes,
|
|
533
|
-
max_bytes: toolPayloadMaxBytes,
|
|
534
|
-
saved_paths: summary.savedPaths,
|
|
535
|
-
});
|
|
536
|
-
return {
|
|
537
|
-
continue: true,
|
|
538
|
-
hookSpecificOutput: {
|
|
539
|
-
hookEventName: "PostToolUse",
|
|
540
|
-
updatedMCPToolOutput: summary.rewrittenBlocks,
|
|
541
|
-
},
|
|
542
|
-
};
|
|
543
|
-
}],
|
|
544
|
-
}],
|
|
545
|
-
PostToolUseFailure: [{
|
|
546
|
-
matcher: "*",
|
|
547
|
-
hooks: [async (input) => {
|
|
548
|
-
onToolUse?.(input?.tool_name);
|
|
549
|
-
return {};
|
|
550
|
-
}],
|
|
551
|
-
}],
|
|
552
|
-
};
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
function promptStringFromMessages(messages) {
|
|
556
|
-
return Array.isArray(messages)
|
|
557
|
-
? messages.filter(m => m.role === "user").map(m => typeof m.content === "string" ? m.content : JSON.stringify(m.content)).join("\n")
|
|
558
|
-
: String(messages || "");
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
function makeSdkUserMessage(body, sessionId, uuid = randomUUID()) {
|
|
562
|
-
return {
|
|
563
|
-
type: "user",
|
|
564
|
-
session_id: sessionId,
|
|
565
|
-
parent_tool_use_id: null,
|
|
566
|
-
uuid,
|
|
567
|
-
message: {
|
|
568
|
-
role: "user",
|
|
569
|
-
content: body,
|
|
570
|
-
},
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
function createClaudeCanUseTool(approvalManager, modelName) {
|
|
575
|
-
return async function canUseTool(toolName, input, context = {}) {
|
|
576
|
-
const decision = await approvalManager.request({
|
|
577
|
-
toolName,
|
|
578
|
-
input,
|
|
579
|
-
model: modelName,
|
|
580
|
-
toolUseId: context?.toolUseID || context?.toolUseId || context?.tool_use_id || null,
|
|
581
|
-
});
|
|
582
|
-
if (decision.decision === "deny") {
|
|
583
|
-
return {
|
|
584
|
-
behavior: "deny",
|
|
585
|
-
message: `Tool ${toolName} denied by host approval gate (${decision.reason || "no reason"})`,
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
return { behavior: "allow", updatedInput: input };
|
|
589
|
-
};
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
async function* livePromptMessages({ initialPrompt, liveInput, sessionId, prompts }) {
|
|
593
|
-
yield makeSdkUserMessage(initialPrompt, sessionId);
|
|
594
|
-
for await (const message of liveInput) {
|
|
595
|
-
try {
|
|
596
|
-
const sdkMessage = makeSdkUserMessage(
|
|
597
|
-
formatLiveInputGuidance(message.body, prompts),
|
|
598
|
-
sessionId,
|
|
599
|
-
message.id || randomUUID(),
|
|
600
|
-
);
|
|
601
|
-
message.acknowledge?.();
|
|
602
|
-
yield sdkMessage;
|
|
603
|
-
} catch (err) {
|
|
604
|
-
message.reject?.(err);
|
|
605
|
-
throw err;
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
export async function generateClaudeResponse(systemPrompt, options) {
|
|
611
|
-
const {
|
|
612
|
-
messages,
|
|
613
|
-
model,
|
|
614
|
-
effort,
|
|
615
|
-
cwd,
|
|
616
|
-
mcpServers,
|
|
617
|
-
allowedTools,
|
|
618
|
-
disallowedTools,
|
|
619
|
-
hooks,
|
|
620
|
-
permissionMode = "bypassPermissions",
|
|
621
|
-
maxTurns,
|
|
622
|
-
abortSignal,
|
|
623
|
-
onEvent = () => {},
|
|
624
|
-
} = options;
|
|
625
|
-
|
|
626
|
-
let effortOptions;
|
|
627
|
-
try {
|
|
628
|
-
effortOptions = claudeEffortOptions(effort);
|
|
629
|
-
} catch (error) {
|
|
630
|
-
const message = boundedText(error?.message || error);
|
|
631
|
-
return {
|
|
632
|
-
text: "",
|
|
633
|
-
structuredResult: undefined,
|
|
634
|
-
structuredResultSource: null,
|
|
635
|
-
events: [],
|
|
636
|
-
usage: {},
|
|
637
|
-
durationMs: 0,
|
|
638
|
-
numTurns: 0,
|
|
639
|
-
model: model.model,
|
|
640
|
-
effort: effort ?? null,
|
|
641
|
-
sdk: "claude",
|
|
642
|
-
cancelled: false,
|
|
643
|
-
error: message,
|
|
644
|
-
errorDetails: {
|
|
645
|
-
claude_error_code: "claude_effort_unsupported",
|
|
646
|
-
claude_error_category: "nonretryable",
|
|
647
|
-
retryable: false,
|
|
648
|
-
},
|
|
649
|
-
failureKind: "skipped_capability_mismatch",
|
|
650
|
-
providerSessionId: pickSessionId(options.sessionId, options.providerSessionId),
|
|
651
|
-
runtimeWarnings: [],
|
|
652
|
-
capabilitiesUsed: buildCapabilitiesUsed({ thinkingEnabled: null }),
|
|
653
|
-
};
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
if (claudeSandboxPolicyProblem(options)) {
|
|
657
|
-
return claudeSandboxCapabilityMismatchResult({
|
|
658
|
-
model: model.reference || `claude:${model.model}`,
|
|
659
|
-
effort,
|
|
660
|
-
sdk: "claude",
|
|
661
|
-
providerSessionId: pickSessionId(options.sessionId, options.providerSessionId),
|
|
662
|
-
outputSchema: options.outputSchema,
|
|
663
|
-
});
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
const promptString = promptStringFromMessages(messages);
|
|
667
|
-
const runtimeWarnings = [];
|
|
668
|
-
const capturedEvents = [];
|
|
669
|
-
const assistantTextFragments = [];
|
|
670
|
-
const reusableProviderSessionId = pickSessionId(options.sessionId, options.providerSessionId);
|
|
671
|
-
const persistArtifact = options.persistArtifact || null;
|
|
672
|
-
const qaOutputDir = options.qaOutputDir || options.runArtifactDir || null;
|
|
673
|
-
const { bytes: toolPayloadMaxBytes, usedSettings: toolPayloadFromSettings } = toolPayloadLimit(options);
|
|
674
|
-
let providerSessionId = reusableProviderSessionId;
|
|
675
|
-
let lastToolName = null;
|
|
676
|
-
let toolResultsSeen = 0;
|
|
677
|
-
|
|
678
|
-
function emitEvent(event) {
|
|
679
|
-
if (!event) return;
|
|
680
|
-
annotateClaudeToolLifecycles(event);
|
|
681
|
-
capturedEvents.push(event);
|
|
682
|
-
onEvent(event);
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
const subagentNormalizer = createClaudeSubagentActivityNormalizer();
|
|
686
|
-
function emitSubagentEvents(activityEvents) {
|
|
687
|
-
for (const activity of activityEvents) emitEvent(activity);
|
|
688
|
-
}
|
|
689
|
-
function drainSubagents(reason) {
|
|
690
|
-
emitSubagentEvents(subagentNormalizer.drain(reason));
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
// Deprecated `settings` fallback for the tool_result byte cap was consumed;
|
|
694
|
-
// surface the one-per-run deprecation warning (the typed `toolLimits` object
|
|
695
|
-
// is the supported path). mono-agent never passes `settings`, so this never
|
|
696
|
-
// fires there.
|
|
697
|
-
if (toolPayloadFromSettings) {
|
|
698
|
-
const warning = deprecatedSettingsWarning(["agent_tool_payload_max_bytes"]);
|
|
699
|
-
runtimeWarnings.push(warning);
|
|
700
|
-
emitEvent({ type: "runtime_warning", ...warning });
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
function noteToolUse(toolName) {
|
|
704
|
-
if (toolName) lastToolName = toolName;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
function noteToolResult(toolName) {
|
|
708
|
-
if (toolName) lastToolName = toolName;
|
|
709
|
-
toolResultsSeen += 1;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
const approvalManager = options.onToolApprovalRequest
|
|
713
|
-
? createApprovalManager({
|
|
714
|
-
onToolApprovalRequest: options.onToolApprovalRequest,
|
|
715
|
-
defaultRiskTier: options.approvalDefaultRiskTier,
|
|
716
|
-
timeoutMs: options.approvalTimeoutMs,
|
|
717
|
-
onEvent: emitEvent,
|
|
718
|
-
riskTiersByTool: options.toolRiskTiers,
|
|
719
|
-
alwaysAllowTools: options.approvalAlwaysAllowTools,
|
|
720
|
-
})
|
|
721
|
-
: null;
|
|
722
|
-
// The Claude SDK invokes `canUseTool` only when permissionMode opts out of
|
|
723
|
-
// bypass. When the host enabled approval gates, force the SDK out of
|
|
724
|
-
// bypass; otherwise the callback would be skipped silently.
|
|
725
|
-
const effectivePermissionMode = approvalManager && permissionMode === "bypassPermissions"
|
|
726
|
-
? "default"
|
|
727
|
-
: permissionMode;
|
|
728
|
-
const nativeAgents = claudeNativeAgentDefinitions(options.nativeSubagents);
|
|
729
|
-
// `"*"` allow-all → pass `allowedTools: undefined` so the SDK uses its default
|
|
730
|
-
// toolset (every tool, incl. Task — not double-added). disallowedTools still
|
|
731
|
-
// flows through, so deny-wins holds under allow-all.
|
|
732
|
-
const { allowAll: allowAllTools, tools: resolvedAllowedTools } = resolveClaudeAllowedTools(allowedTools, options.nativeSubagents);
|
|
733
|
-
const hasExplicitToolProjection = Array.isArray(allowedTools) && !allowAllTools;
|
|
734
|
-
const internalAbortController = new AbortController();
|
|
735
|
-
const disposableSession = options.persistSession === false
|
|
736
|
-
|| options.disposable === true
|
|
737
|
-
|| options.readinessProbe === true
|
|
738
|
-
|| options.sessionKeepAlive === false;
|
|
739
|
-
// Assembled incrementally, then handed across the SDK `query` boundary
|
|
740
|
-
// (outputFormat/resume/maxTurns are attached conditionally below).
|
|
741
|
-
/** @type {any} */
|
|
742
|
-
const queryOptions = {
|
|
743
|
-
systemPrompt,
|
|
744
|
-
model: claudeSdkModelForQuery(model.model, options.contextWindow),
|
|
745
|
-
cwd,
|
|
746
|
-
permissionMode: effectivePermissionMode,
|
|
747
|
-
...(effectivePermissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}),
|
|
748
|
-
// `tools` is the SDK's availability projection. In particular, [] must
|
|
749
|
-
// remain [] so a readiness/discovery call cannot silently regain defaults.
|
|
750
|
-
...(hasExplicitToolProjection ? { tools: resolvedAllowedTools } : {}),
|
|
751
|
-
// `allowedTools` only controls auto-approval. Never provide it alongside
|
|
752
|
-
// canUseTool, where it would bypass the host approval callback.
|
|
753
|
-
...(!approvalManager && hasExplicitToolProjection ? { allowedTools: resolvedAllowedTools } : {}),
|
|
754
|
-
disallowedTools,
|
|
755
|
-
mcpServers: mcpServers || {},
|
|
756
|
-
strictMcpConfig: true,
|
|
757
|
-
settingSources: normalizeClaudeSettingSources(options.settingSources),
|
|
758
|
-
// The SDK otherwise forwards child tool frames but suppresses child prose.
|
|
759
|
-
// Request it explicitly so the live normalizer can preserve the complete
|
|
760
|
-
// nested transcript without ever merging it into the parent answer.
|
|
761
|
-
forwardSubagentText: true,
|
|
762
|
-
env: createClaudeSdkEnvironment(options.env, options.providerEnv),
|
|
763
|
-
abortController: internalAbortController,
|
|
764
|
-
...(disposableSession ? { persistSession: false } : options.persistSession === true ? { persistSession: true } : {}),
|
|
765
|
-
...(approvalManager ? { canUseTool: createClaudeCanUseTool(approvalManager, model.model) } : {}),
|
|
766
|
-
...(nativeAgents ? { agents: nativeAgents } : {}),
|
|
767
|
-
hooks: mergeHookMatchers(hooks, createClaudeRuntimeHooks({
|
|
768
|
-
emitEvent,
|
|
769
|
-
persistArtifact,
|
|
770
|
-
qaOutputDir,
|
|
771
|
-
toolPayloadMaxBytes,
|
|
772
|
-
onToolUse: noteToolUse,
|
|
773
|
-
onToolResult: noteToolResult,
|
|
774
|
-
})),
|
|
775
|
-
...effortOptions,
|
|
776
|
-
};
|
|
777
|
-
if (options.outputSchema) {
|
|
778
|
-
queryOptions.outputFormat = {
|
|
779
|
-
type: "json_schema",
|
|
780
|
-
schema: options.outputSchema,
|
|
781
|
-
};
|
|
782
|
-
}
|
|
783
|
-
if (reusableProviderSessionId) {
|
|
784
|
-
queryOptions.resume = reusableProviderSessionId;
|
|
785
|
-
}
|
|
786
|
-
if (Number.isFinite(Number(maxTurns)) && Number(maxTurns) > 0) {
|
|
787
|
-
queryOptions.maxTurns = Number(maxTurns);
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
const prompt = options.liveInput
|
|
791
|
-
? livePromptMessages({ initialPrompt: promptString, liveInput: options.liveInput, sessionId: reusableProviderSessionId || randomUUID(), prompts: options.prompts })
|
|
792
|
-
: promptString;
|
|
793
|
-
const claudeAgentQuery = options.claudeAgentQuery ?? query;
|
|
794
|
-
const providerRequestStartedAt = Date.now();
|
|
795
|
-
emitEvent({
|
|
796
|
-
type: "provider_request_started",
|
|
797
|
-
sdk: "claude",
|
|
798
|
-
model: model.model,
|
|
799
|
-
runtime: "sdk",
|
|
800
|
-
timestamp: providerRequestStartedAt,
|
|
801
|
-
});
|
|
802
|
-
/** @type {ReturnType<typeof query> | null} */
|
|
803
|
-
let stream = null;
|
|
804
|
-
|
|
805
|
-
let text = "";
|
|
806
|
-
let usage = {};
|
|
807
|
-
let durationMs = 0;
|
|
808
|
-
let numTurns = 0;
|
|
809
|
-
let resultText = "";
|
|
810
|
-
let cancelled = false;
|
|
811
|
-
let errorMessage = null;
|
|
812
|
-
let failureKind = null;
|
|
813
|
-
let successfulResultSeen = false;
|
|
814
|
-
let postSuccessErrorSeen = false;
|
|
815
|
-
let structuredResultSource = null;
|
|
816
|
-
let structuredResult = undefined;
|
|
817
|
-
let errorDetails = null;
|
|
818
|
-
let lastStructuredOutputRejection = null;
|
|
819
|
-
let totalCostUsd = null;
|
|
820
|
-
let thinkingObserved = false;
|
|
821
|
-
let structuredTerminalFailure = null;
|
|
822
|
-
const pendingStructuredOutputById = new Map();
|
|
823
|
-
|
|
824
|
-
const rawFinalText = () => resultText || text;
|
|
825
|
-
|
|
826
|
-
function hasUsableFinalOutput() {
|
|
827
|
-
return structuredResult !== undefined || String(rawFinalText() || "").trim().length > 0;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
function hasPreservableFinalOutput() {
|
|
831
|
-
return successfulResultSeen ? hasUsableFinalOutput() : structuredResult !== undefined;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
function preservePostSuccessError(message) {
|
|
835
|
-
if (postSuccessErrorSeen) return;
|
|
836
|
-
postSuccessErrorSeen = true;
|
|
837
|
-
runtimeWarnings.push(makeRuntimeWarning(message));
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
const abortHandler = () => {
|
|
841
|
-
cancelled = true;
|
|
842
|
-
drainSubagents("subagent cancelled with the parent run");
|
|
843
|
-
internalAbortController.abort();
|
|
844
|
-
try { stream?.close?.(); } catch { /* best effort; finally closes again */ }
|
|
845
|
-
};
|
|
846
|
-
if (abortSignal) {
|
|
847
|
-
if (abortSignal.aborted) abortHandler();
|
|
848
|
-
else abortSignal.addEventListener("abort", abortHandler, { once: true });
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
try {
|
|
852
|
-
stream = claudeAgentQuery({ prompt: /** @type {any} */ (prompt), options: queryOptions });
|
|
853
|
-
for await (const rawEvent of stream) {
|
|
854
|
-
const nextSessionId = sessionIdFromEvent(rawEvent);
|
|
855
|
-
if (nextSessionId) providerSessionId = nextSessionId;
|
|
856
|
-
const observation = subagentNormalizer.observe(rawEvent);
|
|
857
|
-
emitSubagentEvents(observation.events);
|
|
858
|
-
// Child records are represented exclusively as subagent_activity. In
|
|
859
|
-
// particular, their text, errors, tools, usage, and structured output
|
|
860
|
-
// must never mutate the parent's result state below.
|
|
861
|
-
if (observation.consumed) {
|
|
862
|
-
if (cancelled) break;
|
|
863
|
-
continue;
|
|
864
|
-
}
|
|
865
|
-
// Preserve unrelated blocks when a root user message batches them with a
|
|
866
|
-
// background Agent launch acknowledgement.
|
|
867
|
-
const event = /** @type {any} */ (observation.forwarded ?? rawEvent);
|
|
868
|
-
emitEvent(event);
|
|
869
|
-
if (event?.type === "tool_progress" && event.tool_name) noteToolUse(event.tool_name);
|
|
870
|
-
for (const toolUse of structuredOutputToolUses(event)) {
|
|
871
|
-
pendingStructuredOutputById.set(toolUse.id, toolUse.input);
|
|
872
|
-
}
|
|
873
|
-
const structuredOutputRejection = structuredOutputRejectionFromEvent(event);
|
|
874
|
-
if (structuredOutputRejection) lastStructuredOutputRejection = structuredOutputRejection;
|
|
875
|
-
for (const acceptedStructuredOutput of acceptedStructuredOutputValues(event, pendingStructuredOutputById)) {
|
|
876
|
-
structuredResult = acceptedStructuredOutput;
|
|
877
|
-
structuredResultSource = "StructuredOutput";
|
|
878
|
-
emitEvent({
|
|
879
|
-
...structuredOutputEvent(acceptedStructuredOutput),
|
|
880
|
-
source: "StructuredOutput",
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
const eventStructuredOutput = extractStructuredOutput(event);
|
|
884
|
-
if (eventStructuredOutput !== undefined) {
|
|
885
|
-
structuredResult = eventStructuredOutput;
|
|
886
|
-
structuredResultSource = "structured_output";
|
|
887
|
-
emitEvent(structuredOutputEvent(eventStructuredOutput));
|
|
888
|
-
}
|
|
889
|
-
if (event.type === "assistant") {
|
|
890
|
-
thinkingObserved = thinkingObserved || assistantThinkingObserved(event);
|
|
891
|
-
if (event.error && !structuredTerminalFailure) {
|
|
892
|
-
const assistantFailure = claudeAssistantFailure(event.error, event.request_id);
|
|
893
|
-
structuredTerminalFailure = assistantFailure;
|
|
894
|
-
errorDetails = buildClaudeErrorDetails({
|
|
895
|
-
event,
|
|
896
|
-
subtype: event.error,
|
|
897
|
-
providerSessionId,
|
|
898
|
-
assistantTexts: assistantTextFragments,
|
|
899
|
-
lastToolName,
|
|
900
|
-
toolResultsSeen,
|
|
901
|
-
numTurns,
|
|
902
|
-
lastStructuredOutputRejection,
|
|
903
|
-
failureCode: assistantFailure.code,
|
|
904
|
-
failureCategory: assistantFailure.category,
|
|
905
|
-
retryable: assistantFailure.retryable,
|
|
906
|
-
requestId: assistantFailure.requestId,
|
|
907
|
-
});
|
|
908
|
-
}
|
|
909
|
-
const delta = extractText(event);
|
|
910
|
-
if (delta) assistantTextFragments.push(delta);
|
|
911
|
-
text += delta;
|
|
912
|
-
for (const toolName of assistantToolNames(event)) noteToolUse(toolName);
|
|
913
|
-
}
|
|
914
|
-
// The SDK's message union does not declare a runtime `error` event, but
|
|
915
|
-
// the runtime can emit one; keep this defensive branch and cast past the
|
|
916
|
-
// narrowed union.
|
|
917
|
-
else if (/** @type {any} */ (event).type === "error") {
|
|
918
|
-
const errorEvent = /** @type {any} */ (event);
|
|
919
|
-
const message = boundedText(errorEvent.error?.message || errorEvent.error || "sdk stream error");
|
|
920
|
-
if (structuredTerminalFailure) {
|
|
921
|
-
// A typed assistant error is authoritative. A later transport error
|
|
922
|
-
// cannot turn authentication/billing diagnostics into a generic
|
|
923
|
-
// provider failure.
|
|
924
|
-
} else if (hasPreservableFinalOutput()) {
|
|
925
|
-
preservePostSuccessError(`Claude SDK emitted an error after final output; preserved final result. ${message}`);
|
|
926
|
-
} else {
|
|
927
|
-
errorMessage = message;
|
|
928
|
-
failureKind = "provider_unavailable";
|
|
929
|
-
errorDetails = buildClaudeErrorDetails({
|
|
930
|
-
event,
|
|
931
|
-
subtype: "error",
|
|
932
|
-
providerSessionId,
|
|
933
|
-
assistantTexts: assistantTextFragments,
|
|
934
|
-
lastToolName,
|
|
935
|
-
toolResultsSeen,
|
|
936
|
-
numTurns,
|
|
937
|
-
lastStructuredOutputRejection,
|
|
938
|
-
});
|
|
939
|
-
}
|
|
940
|
-
break;
|
|
941
|
-
} else if (event.type === "result") {
|
|
942
|
-
if (Number.isFinite(Number(event.total_cost_usd))) totalCostUsd = Number(event.total_cost_usd);
|
|
943
|
-
const resultError = resultEventError(event);
|
|
944
|
-
if (resultError) {
|
|
945
|
-
if (!successfulResultSeen) {
|
|
946
|
-
usage = event.usage || usage;
|
|
947
|
-
durationMs = event.duration_ms || durationMs;
|
|
948
|
-
numTurns = event.num_turns || numTurns;
|
|
949
|
-
}
|
|
950
|
-
if (structuredTerminalFailure) {
|
|
951
|
-
// Retain the typed assistant error and request id. The result still
|
|
952
|
-
// contributes usage/duration/cost above.
|
|
953
|
-
} else if (hasPreservableFinalOutput()) {
|
|
954
|
-
preservePostSuccessError(`Claude SDK emitted an error after final output; preserved final result. ${resultError.message}`);
|
|
955
|
-
successfulResultSeen = true;
|
|
956
|
-
} else {
|
|
957
|
-
const categorized = resultFailureCategory(event, resultError);
|
|
958
|
-
usage = event.usage || usage;
|
|
959
|
-
durationMs = event.duration_ms || durationMs;
|
|
960
|
-
numTurns = event.num_turns || numTurns;
|
|
961
|
-
errorMessage = categorized.message;
|
|
962
|
-
failureKind = categorized.failureKind;
|
|
963
|
-
if (failureKind === "invalid_result") {
|
|
964
|
-
runtimeWarnings.push(makeRuntimeWarning(
|
|
965
|
-
resultError.message,
|
|
966
|
-
`${(options.toolContext?.runtimeBrand ?? readRuntimeBrand()).schemaPrefix}_result_validation`,
|
|
967
|
-
));
|
|
968
|
-
}
|
|
969
|
-
errorDetails = buildClaudeErrorDetails({
|
|
970
|
-
event,
|
|
971
|
-
subtype: event.subtype || "result_error",
|
|
972
|
-
providerSessionId,
|
|
973
|
-
assistantTexts: assistantTextFragments,
|
|
974
|
-
lastToolName,
|
|
975
|
-
toolResultsSeen,
|
|
976
|
-
numTurns,
|
|
977
|
-
lastStructuredOutputRejection,
|
|
978
|
-
failureCode: categorized.code,
|
|
979
|
-
failureCategory: categorized.category,
|
|
980
|
-
retryable: categorized.retryable,
|
|
981
|
-
requestId: categorized.requestId,
|
|
982
|
-
});
|
|
983
|
-
}
|
|
984
|
-
} else {
|
|
985
|
-
usage = event.usage || usage;
|
|
986
|
-
durationMs = event.duration_ms || durationMs;
|
|
987
|
-
numTurns = event.num_turns || numTurns;
|
|
988
|
-
resultText = extractResultText(event) || resultText;
|
|
989
|
-
successfulResultSeen = true;
|
|
990
|
-
}
|
|
991
|
-
if (options.liveInput) break;
|
|
992
|
-
}
|
|
993
|
-
if (cancelled) break;
|
|
994
|
-
}
|
|
995
|
-
} catch (err) {
|
|
996
|
-
if (!cancelled) {
|
|
997
|
-
const message = boundedText(err?.message || String(err));
|
|
998
|
-
if (structuredTerminalFailure) {
|
|
999
|
-
// Keep the earlier typed provider failure and its request id.
|
|
1000
|
-
} else if (successfulResultSeen && hasUsableFinalOutput()) {
|
|
1001
|
-
preservePostSuccessError(`Claude SDK stream failed after final output; preserved final result. ${message}`);
|
|
1002
|
-
} else {
|
|
1003
|
-
errorMessage = message;
|
|
1004
|
-
failureKind = "provider_unavailable";
|
|
1005
|
-
errorDetails = buildClaudeErrorDetails({
|
|
1006
|
-
subtype: "exception",
|
|
1007
|
-
providerSessionId,
|
|
1008
|
-
assistantTexts: assistantTextFragments,
|
|
1009
|
-
lastToolName,
|
|
1010
|
-
toolResultsSeen,
|
|
1011
|
-
numTurns,
|
|
1012
|
-
lastStructuredOutputRejection,
|
|
1013
|
-
failureCode: "exception",
|
|
1014
|
-
failureCategory: "unknown",
|
|
1015
|
-
retryable: false,
|
|
1016
|
-
});
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
} finally {
|
|
1020
|
-
drainSubagents(cancelled
|
|
1021
|
-
? "subagent cancelled with the parent run"
|
|
1022
|
-
: errorMessage || structuredTerminalFailure
|
|
1023
|
-
? "subagent stopped because the Claude SDK stream failed"
|
|
1024
|
-
: "subagent stream closed before completion");
|
|
1025
|
-
try { stream?.close?.(); } catch { /* best effort after every terminal path */ }
|
|
1026
|
-
if (abortSignal) abortSignal.removeEventListener?.("abort", abortHandler);
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
if (structuredTerminalFailure) {
|
|
1030
|
-
errorMessage = structuredTerminalFailure.message;
|
|
1031
|
-
failureKind = structuredTerminalFailure.failureKind;
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
const reference = model.reference || `claude:${model.model}`;
|
|
1035
|
-
const inputTokens = usage?.input_tokens ?? usage?.inputTokens ?? 0;
|
|
1036
|
-
const outputTokens = usage?.output_tokens ?? usage?.outputTokens ?? 0;
|
|
1037
|
-
const cachedTokens = usage?.cache_read_input_tokens ?? usage?.cache_read_tokens ?? 0;
|
|
1038
|
-
const cacheCreationTokens = usage?.cache_creation_input_tokens ?? usage?.cache_creation_tokens ?? 0;
|
|
1039
|
-
const costUsd = Number.isFinite(totalCostUsd)
|
|
1040
|
-
? totalCostUsd
|
|
1041
|
-
: estimateCost({
|
|
1042
|
-
resolveCustomPricing: options.resolveCustomPricing,
|
|
1043
|
-
model: reference,
|
|
1044
|
-
inputTokens,
|
|
1045
|
-
outputTokens,
|
|
1046
|
-
cachedTokens,
|
|
1047
|
-
cacheWriteTokens: cacheCreationTokens,
|
|
1048
|
-
});
|
|
1049
|
-
const enrichedUsage = {
|
|
1050
|
-
...usage,
|
|
1051
|
-
input_tokens: inputTokens || null,
|
|
1052
|
-
output_tokens: outputTokens || null,
|
|
1053
|
-
cache_read_tokens: cachedTokens || null,
|
|
1054
|
-
cache_creation_tokens: cacheCreationTokens || null,
|
|
1055
|
-
cost_usd: costUsd,
|
|
1056
|
-
};
|
|
1057
|
-
|
|
1058
|
-
emitEvent({
|
|
1059
|
-
type: "provider_request_completed",
|
|
1060
|
-
sdk: "claude",
|
|
1061
|
-
model: model.model,
|
|
1062
|
-
runtime: "sdk",
|
|
1063
|
-
timestamp: Date.now(),
|
|
1064
|
-
durationMs: Date.now() - providerRequestStartedAt,
|
|
1065
|
-
failureKind,
|
|
1066
|
-
cancelled,
|
|
1067
|
-
});
|
|
1068
|
-
if (cachedTokens > 0) {
|
|
1069
|
-
emitEvent({ type: "cache_hit", sdk: "claude", model: model.model, tokens: cachedTokens, source: "anthropic_prompt_cache" });
|
|
1070
|
-
}
|
|
1071
|
-
if (cacheCreationTokens > 0) {
|
|
1072
|
-
emitEvent({ type: "cache_miss", sdk: "claude", model: model.model, tokens: cacheCreationTokens, source: "anthropic_prompt_cache" });
|
|
1073
|
-
}
|
|
1074
|
-
emitEvent({
|
|
1075
|
-
type: "cost_accumulated",
|
|
1076
|
-
sdk: "claude",
|
|
1077
|
-
model: model.model,
|
|
1078
|
-
cumulativeUsd: costUsd ?? 0,
|
|
1079
|
-
tokens: {
|
|
1080
|
-
input: inputTokens,
|
|
1081
|
-
output: outputTokens,
|
|
1082
|
-
cacheReadTokens: cachedTokens,
|
|
1083
|
-
cacheCreationTokens,
|
|
1084
|
-
},
|
|
1085
|
-
});
|
|
1086
|
-
|
|
1087
|
-
const observedSubagents = subagentNormalizer.nativeSubagentsUsed();
|
|
1088
|
-
const capabilitiesUsed = buildCapabilitiesUsed({
|
|
1089
|
-
promptCacheActive: cachedTokens > 0 || cacheCreationTokens > 0,
|
|
1090
|
-
thinkingEnabled: thinkingObserved ? true : null,
|
|
1091
|
-
structuredOutputEnforced: !!options.outputSchema,
|
|
1092
|
-
subagentInvoked: subagentNormalizer.subagentInvoked(),
|
|
1093
|
-
mcpServersUsed: Object.keys(mcpServers || {}),
|
|
1094
|
-
nativeSubagentsUsed: observedSubagents,
|
|
1095
|
-
toolCompactionApplied: toolCompactionAppliedFromWarnings(runtimeWarnings),
|
|
1096
|
-
contextCompactionApplied: null, // Claude SDK doesn't use the runtime compaction layer
|
|
1097
|
-
});
|
|
1098
|
-
emitEvent({ type: "capabilities_resolved", sdk: "claude", model: model.model, capabilitiesUsed });
|
|
1099
|
-
|
|
1100
|
-
return {
|
|
1101
|
-
text: rawFinalText(),
|
|
1102
|
-
structuredResult,
|
|
1103
|
-
structuredResultSource,
|
|
1104
|
-
events: capturedEvents,
|
|
1105
|
-
usage: enrichedUsage,
|
|
1106
|
-
durationMs,
|
|
1107
|
-
numTurns,
|
|
1108
|
-
model: model.model,
|
|
1109
|
-
effort,
|
|
1110
|
-
sdk: "claude",
|
|
1111
|
-
cancelled,
|
|
1112
|
-
error: errorMessage,
|
|
1113
|
-
errorDetails,
|
|
1114
|
-
failureKind,
|
|
1115
|
-
providerSessionId,
|
|
1116
|
-
runtimeWarnings,
|
|
1117
|
-
capabilitiesUsed,
|
|
1118
|
-
};
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
export const claudeRuntimeBridge = {
|
|
1122
|
-
id: "claude",
|
|
1123
|
-
kind: "claude",
|
|
1124
|
-
capabilities: runtimeCapabilities("claude"),
|
|
1125
|
-
supports: (ref) => ref?.sdk === "claude",
|
|
1126
|
-
execute: generateClaudeResponse,
|
|
1127
|
-
};
|