@openclaw/ai 0.0.0 → 2026.7.1-2
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/LICENSE +21 -0
- package/README.md +27 -3
- package/dist/anthropic-B5gZQM5X.mjs +1383 -0
- package/dist/api-registry-BXYnCOIR.d.mts +33 -0
- package/dist/azure-openai-responses-DNoSk8Uy.mjs +141 -0
- package/dist/azure-openai-responses-client-compat-a_O_GVQV.mjs +41 -0
- package/dist/diagnostics-BaTA9eVl.d.mts +25 -0
- package/dist/diagnostics-COpOtRwq.mjs +36 -0
- package/dist/diagnostics.d.mts +2 -0
- package/dist/diagnostics.mjs +2 -0
- package/dist/env-api-keys-CtMlqaQ4.mjs +171 -0
- package/dist/event-stream-0nZeBKl2.d.mts +26 -0
- package/dist/event-stream-ReMmOTzX.mjs +65 -0
- package/dist/event-stream.d.mts +2 -0
- package/dist/event-stream.mjs +2 -0
- package/dist/github-copilot-headers-BsH5cqGj.mjs +48 -0
- package/dist/google-D6sIQ1bL.mjs +55 -0
- package/dist/google-shared-ZPSl2qTi.mjs +548 -0
- package/dist/google-vertex-rDGwkoZK.mjs +111 -0
- package/dist/hash-CHgqbJmD.mjs +16 -0
- package/dist/headers-B_e4-1J0.mjs +9 -0
- package/dist/host-4t713IeR.mjs +37 -0
- package/dist/index-BoTnz8cv.d.mts +74 -0
- package/dist/index.d.mts +69 -0
- package/dist/index.mjs +7 -0
- package/dist/internal/anthropic.d.mts +234 -0
- package/dist/internal/anthropic.mjs +4 -0
- package/dist/internal/openai.d.mts +244 -0
- package/dist/internal/openai.mjs +7 -0
- package/dist/internal/runtime.d.mts +245 -0
- package/dist/internal/runtime.mjs +176 -0
- package/dist/internal/shared.d.mts +48 -0
- package/dist/internal/shared.mjs +3 -0
- package/dist/json-parse-DzNSIQBq.mjs +134 -0
- package/dist/llm-request-activity-CehVkZP-.mjs +35 -0
- package/dist/mistral-CePVNdws.mjs +563 -0
- package/dist/model-utils-DgmOla96.mjs +69 -0
- package/dist/openai-chatgpt-jwt-DhAAzLkj.mjs +39 -0
- package/dist/openai-chatgpt-responses-DVC4Bk_A.mjs +1068 -0
- package/dist/openai-completions-B9QLIq2U.mjs +844 -0
- package/dist/openai-responses-B6LylGxM.mjs +136 -0
- package/dist/openai-responses-shared-sj2YUPYc.mjs +1944 -0
- package/dist/openai-tool-projection-BknoV11q.mjs +195 -0
- package/dist/providers.d.mts +11 -0
- package/dist/providers.mjs +109 -0
- package/dist/reasoning-tag-text-partitioner-axhAdUwg.mjs +394 -0
- package/dist/sanitize-unicode-BZiVbGwK.d.mts +24 -0
- package/dist/sanitize-unicode-DT5o51ur.mjs +26 -0
- package/dist/src-CZ503MYJ.mjs +99 -0
- package/dist/stream-CREqxHgU.mjs +74 -0
- package/dist/stream-first-event-timeout-RjWszj8c.mjs +106 -0
- package/dist/streaming-byte-guard-BrbkbwUu.mjs +46 -0
- package/dist/tool-schema-json-projection-BXtBc_mD.mjs +74 -0
- package/dist/transform-messages-BhGF_fF4.mjs +507 -0
- package/dist/types-BVVgDSdq.d.mts +1 -0
- package/dist/types-DRgdPqaZ.d.mts +587 -0
- package/dist/types.d.mts +6 -0
- package/dist/types.mjs +5 -0
- package/dist/validation-BDMWOr8d.d.mts +9 -0
- package/dist/validation-FrchoOlv.mjs +199 -0
- package/dist/validation.d.mts +2 -0
- package/dist/validation.mjs +2 -0
- package/npm-shrinkwrap.json +645 -0
- package/package.json +74 -2
|
@@ -0,0 +1,1383 @@
|
|
|
1
|
+
import { n as getEnvApiKey, r as __exportAll } from "./env-api-keys-CtMlqaQ4.mjs";
|
|
2
|
+
import { c as resolveClaudeNativeThinkingLevelMap, d as supportsClaudeNativeMaxEffort, f as supportsClaudeNativeXhighEffort, l as resolveClaudeSonnet5ModelIdentity, u as supportsClaudeAdaptiveThinking } from "./src-CZ503MYJ.mjs";
|
|
3
|
+
import { t as AssistantMessageEventStream } from "./event-stream-ReMmOTzX.mjs";
|
|
4
|
+
import { n as getAiTransportHost, r as resolveAiTransportHeaderSentinels } from "./host-4t713IeR.mjs";
|
|
5
|
+
import { n as calculateCost, r as clampThinkingLevel } from "./model-utils-DgmOla96.mjs";
|
|
6
|
+
import { r as createDeferredEventBuffer, t as notifyLlmRequestActivity } from "./llm-request-activity-CehVkZP-.mjs";
|
|
7
|
+
import { t as headersToRecord } from "./headers-B_e4-1J0.mjs";
|
|
8
|
+
import { n as parseStreamingJson, t as parseJsonWithRepair } from "./json-parse-DzNSIQBq.mjs";
|
|
9
|
+
import { t as sanitizeSurrogates } from "./sanitize-unicode-DT5o51ur.mjs";
|
|
10
|
+
import { a as adjustMaxTokensForThinking, b as stripSystemPromptCacheBoundary, c as isRecord, d as prepareClaudeSonnet5RequestContext, f as requiresClaudeAdaptiveThinking, h as usesClaudeStreamingRefusalContract, i as extractToolResultText, l as applyClaudeRequestContract, m as usesClaudeFable5MessagesContract, n as describeToolResultMediaPlaceholder, o as buildBaseOptions, r as extractToolResultBlockText, t as transformMessages, y as splitSystemPromptCacheBoundary } from "./transform-messages-BhGF_fF4.mjs";
|
|
11
|
+
import { t as projectRuntimeToolInputSchema } from "./tool-schema-json-projection-BXtBc_mD.mjs";
|
|
12
|
+
import { a as resolveCacheRetention, i as resolveCloudflareBaseUrl, n as hasCopilotVisionInput, t as buildCopilotDynamicHeaders } from "./github-copilot-headers-BsH5cqGj.mjs";
|
|
13
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
14
|
+
//#region packages/ai/src/providers/anthropic-auth-headers.ts
|
|
15
|
+
function usesFoundryBearerAuth(model) {
|
|
16
|
+
return model.provider === "microsoft-foundry" && (model.authHeader === true || hasBearerAuthorizationHeader(model.headers));
|
|
17
|
+
}
|
|
18
|
+
function hasBearerAuthorizationHeader(headers) {
|
|
19
|
+
if (!headers) return false;
|
|
20
|
+
return Object.entries(headers).some(([key, value]) => key.toLowerCase() === "authorization" && /^bearer\s+\S+/i.test(value.trim()));
|
|
21
|
+
}
|
|
22
|
+
function omitFoundryBearerCredentialHeaders(headers) {
|
|
23
|
+
if (!headers) return;
|
|
24
|
+
const next = {};
|
|
25
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
26
|
+
const lower = key.toLowerCase();
|
|
27
|
+
if (lower === "authorization" || lower === "x-api-key" || lower === "api-key") continue;
|
|
28
|
+
next[key] = value;
|
|
29
|
+
}
|
|
30
|
+
return Object.keys(next).length > 0 ? next : void 0;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region packages/ai/src/providers/anthropic-refusal.ts
|
|
34
|
+
function readNullableString(value) {
|
|
35
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
36
|
+
}
|
|
37
|
+
function readAnthropicRefusalDetails(value) {
|
|
38
|
+
if (!value || typeof value !== "object") return {
|
|
39
|
+
category: null,
|
|
40
|
+
explanation: null
|
|
41
|
+
};
|
|
42
|
+
const details = value;
|
|
43
|
+
return {
|
|
44
|
+
category: readNullableString(details.category),
|
|
45
|
+
explanation: readNullableString(details.explanation)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function formatAnthropicRefusalMessage(details) {
|
|
49
|
+
return `Anthropic refusal${details.category ? ` (category: ${details.category})` : ""}${details.explanation ? `: ${details.explanation}` : "."}`;
|
|
50
|
+
}
|
|
51
|
+
function applyAnthropicRefusal(output, stopDetails, provider) {
|
|
52
|
+
const details = readAnthropicRefusalDetails(stopDetails);
|
|
53
|
+
output.stopReason = "error";
|
|
54
|
+
output.errorMessage = formatAnthropicRefusalMessage(details);
|
|
55
|
+
output.diagnostics = [...output.diagnostics ?? [], {
|
|
56
|
+
type: "provider_refusal",
|
|
57
|
+
timestamp: Date.now(),
|
|
58
|
+
details: {
|
|
59
|
+
provider,
|
|
60
|
+
category: details.category,
|
|
61
|
+
explanation: details.explanation
|
|
62
|
+
}
|
|
63
|
+
}];
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region packages/ai/src/providers/anthropic-server-fallback.ts
|
|
67
|
+
/** Anthropic beta that re-serves safety refusals on an allowed fallback model. */
|
|
68
|
+
const ANTHROPIC_SERVER_SIDE_FALLBACK_BETA = "server-side-fallback-2026-06-01";
|
|
69
|
+
const CLAUDE_FABLE_5_FALLBACK_MODEL = "claude-opus-4-8";
|
|
70
|
+
const CLAUDE_FABLE_5_FALLBACK_MODEL_COST = {
|
|
71
|
+
input: 5,
|
|
72
|
+
output: 25,
|
|
73
|
+
cacheRead: .5,
|
|
74
|
+
cacheWrite: 6.25
|
|
75
|
+
};
|
|
76
|
+
function buildAnthropicServerSideFallbacks() {
|
|
77
|
+
return [{ model: CLAUDE_FABLE_5_FALLBACK_MODEL }];
|
|
78
|
+
}
|
|
79
|
+
function readBoundaryModel(value) {
|
|
80
|
+
if (!value || typeof value !== "object") return null;
|
|
81
|
+
const model = value.model;
|
|
82
|
+
return typeof model === "string" && model.trim() ? model : null;
|
|
83
|
+
}
|
|
84
|
+
/** Reads a `fallback` content block marking where one model's output gives way to the next. */
|
|
85
|
+
function readAnthropicFallbackBoundary(block) {
|
|
86
|
+
if (!block || typeof block !== "object") return null;
|
|
87
|
+
const record = block;
|
|
88
|
+
if (record.type !== "fallback") return null;
|
|
89
|
+
return {
|
|
90
|
+
fromModel: readBoundaryModel(record.from),
|
|
91
|
+
toModel: readBoundaryModel(record.to)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Drops pre-fallback thinking/tool calls while preserving the text prefix that
|
|
96
|
+
* the serving model continued. Dropped tool calls must never execute or replay.
|
|
97
|
+
*/
|
|
98
|
+
function applyAnthropicFallbackBoundary(params) {
|
|
99
|
+
const { output, boundary } = params;
|
|
100
|
+
const survivors = output.content.filter((block) => block.type === "text");
|
|
101
|
+
for (const survivor of survivors) delete survivor.textSignature;
|
|
102
|
+
output.content.splice(0, output.content.length, ...survivors);
|
|
103
|
+
if (boundary.toModel) output.responseModel = boundary.toModel;
|
|
104
|
+
output.diagnostics = [...output.diagnostics ?? [], {
|
|
105
|
+
type: "provider_fallback",
|
|
106
|
+
timestamp: Date.now(),
|
|
107
|
+
details: {
|
|
108
|
+
provider: params.provider,
|
|
109
|
+
fromModel: boundary.fromModel,
|
|
110
|
+
toModel: boundary.toModel
|
|
111
|
+
}
|
|
112
|
+
}];
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region packages/ai/src/providers/anthropic-thinking-replay.ts
|
|
116
|
+
const ANTHROPIC_OMITTED_REASONING_TEXT = "[assistant reasoning omitted]";
|
|
117
|
+
function asReplayMessage(value) {
|
|
118
|
+
return value && typeof value === "object" ? value : void 0;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Anthropic tool results continue the preceding assistant turn. Preserve that
|
|
122
|
+
* turn's signed thinking even when the next request disables new thinking.
|
|
123
|
+
*/
|
|
124
|
+
function findActiveAnthropicToolTurnAssistantIndex(messages) {
|
|
125
|
+
const toolResultIds = /* @__PURE__ */ new Set();
|
|
126
|
+
let index = messages.length - 1;
|
|
127
|
+
while (index >= 0) {
|
|
128
|
+
const message = asReplayMessage(messages[index]);
|
|
129
|
+
if (message?.role !== "toolResult") break;
|
|
130
|
+
if (typeof message.toolCallId === "string") toolResultIds.add(message.toolCallId);
|
|
131
|
+
index -= 1;
|
|
132
|
+
}
|
|
133
|
+
if (toolResultIds.size === 0) return -1;
|
|
134
|
+
const assistant = asReplayMessage(messages[index]);
|
|
135
|
+
if (assistant?.role !== "assistant" || !Array.isArray(assistant.content)) return -1;
|
|
136
|
+
const toolCallIds = /* @__PURE__ */ new Set();
|
|
137
|
+
for (const block of assistant.content) {
|
|
138
|
+
if (!block || typeof block !== "object") continue;
|
|
139
|
+
const record = block;
|
|
140
|
+
if ((record.type === "toolCall" || record.type === "tool_use" || record.type === "function_call") && typeof record.id === "string") toolCallIds.add(record.id);
|
|
141
|
+
}
|
|
142
|
+
return [...toolResultIds].every((toolCallId) => toolCallIds.has(toolCallId)) ? index : -1;
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
//#region packages/ai/src/providers/anthropic-tool-projection.ts
|
|
146
|
+
function isProviderSupportedViolation(violation) {
|
|
147
|
+
return violation.endsWith(".$dynamicRef") || violation.endsWith(".$dynamicAnchor");
|
|
148
|
+
}
|
|
149
|
+
const schemaValueKeywords = /* @__PURE__ */ new Set([
|
|
150
|
+
"additionalProperties",
|
|
151
|
+
"contains",
|
|
152
|
+
"contentSchema",
|
|
153
|
+
"else",
|
|
154
|
+
"if",
|
|
155
|
+
"items",
|
|
156
|
+
"not",
|
|
157
|
+
"propertyNames",
|
|
158
|
+
"then",
|
|
159
|
+
"unevaluatedItems",
|
|
160
|
+
"unevaluatedProperties"
|
|
161
|
+
]);
|
|
162
|
+
const schemaArrayKeywords = /* @__PURE__ */ new Set([
|
|
163
|
+
"allOf",
|
|
164
|
+
"anyOf",
|
|
165
|
+
"oneOf",
|
|
166
|
+
"prefixItems"
|
|
167
|
+
]);
|
|
168
|
+
const schemaMapKeywords = /* @__PURE__ */ new Set([
|
|
169
|
+
"$defs",
|
|
170
|
+
"definitions",
|
|
171
|
+
"dependencies",
|
|
172
|
+
"dependentSchemas",
|
|
173
|
+
"patternProperties",
|
|
174
|
+
"properties"
|
|
175
|
+
]);
|
|
176
|
+
function normalizeAnthropicJsonSchema(schema) {
|
|
177
|
+
if (!isRecord(schema)) return schema;
|
|
178
|
+
let changed = false;
|
|
179
|
+
const normalized = { ...schema };
|
|
180
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
181
|
+
if (schemaValueKeywords.has(key) && !Array.isArray(value)) {
|
|
182
|
+
const next = normalizeAnthropicJsonSchema(value);
|
|
183
|
+
normalized[key] = next;
|
|
184
|
+
changed ||= next !== value;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (schemaArrayKeywords.has(key) && Array.isArray(value)) {
|
|
188
|
+
const next = value.map(normalizeAnthropicJsonSchema);
|
|
189
|
+
normalized[key] = next;
|
|
190
|
+
changed ||= next.some((entry, index) => entry !== value[index]);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (schemaMapKeywords.has(key) && isRecord(value)) {
|
|
194
|
+
const next = Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [entryKey, normalizeAnthropicJsonSchema(entryValue)]));
|
|
195
|
+
normalized[key] = next;
|
|
196
|
+
changed ||= Object.entries(value).some(([entryKey, entryValue]) => next[entryKey] !== entryValue);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (Array.isArray(schema.items)) {
|
|
200
|
+
normalized.prefixItems = schema.items.map(normalizeAnthropicJsonSchema);
|
|
201
|
+
const additionalItems = schema.additionalItems;
|
|
202
|
+
if (typeof additionalItems === "boolean" || isRecord(additionalItems)) normalized.items = normalizeAnthropicJsonSchema(additionalItems);
|
|
203
|
+
else delete normalized.items;
|
|
204
|
+
delete normalized.additionalItems;
|
|
205
|
+
changed = true;
|
|
206
|
+
}
|
|
207
|
+
return changed ? normalized : schema;
|
|
208
|
+
}
|
|
209
|
+
/** Snapshots direct/custom tool descriptors before Anthropic payload construction. */
|
|
210
|
+
function projectAnthropicTools(tools, toWireName) {
|
|
211
|
+
const projectedTools = [];
|
|
212
|
+
const unavailableOriginalNames = /* @__PURE__ */ new Set();
|
|
213
|
+
for (const tool of tools) {
|
|
214
|
+
let projectedTool;
|
|
215
|
+
let originalName;
|
|
216
|
+
try {
|
|
217
|
+
const name = tool.name;
|
|
218
|
+
originalName = name;
|
|
219
|
+
if (!name) continue;
|
|
220
|
+
const schemaProjection = projectRuntimeToolInputSchema(tool.parameters, `${name}.parameters`);
|
|
221
|
+
if (!isRecord(schemaProjection.schema) || schemaProjection.violations.some((violation) => !isProviderSupportedViolation(violation))) {
|
|
222
|
+
unavailableOriginalNames.add(name);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
const anthropicSchema = normalizeAnthropicJsonSchema(schemaProjection.schema);
|
|
226
|
+
if (!isRecord(anthropicSchema)) {
|
|
227
|
+
unavailableOriginalNames.add(name);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const properties = anthropicSchema.properties;
|
|
231
|
+
const required = anthropicSchema.required;
|
|
232
|
+
if (properties !== void 0 && properties !== null && !isRecord(properties) || required !== void 0 && required !== null && (!Array.isArray(required) || required.some((entry) => typeof entry !== "string"))) {
|
|
233
|
+
unavailableOriginalNames.add(name);
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
let description;
|
|
237
|
+
try {
|
|
238
|
+
description = typeof tool.description === "string" ? tool.description : void 0;
|
|
239
|
+
} catch {}
|
|
240
|
+
projectedTool = {
|
|
241
|
+
originalName: name,
|
|
242
|
+
wireName: toWireName(name),
|
|
243
|
+
...description ? { description } : {},
|
|
244
|
+
inputSchema: {
|
|
245
|
+
type: "object",
|
|
246
|
+
properties: properties ?? {},
|
|
247
|
+
required: required ?? []
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
} catch {
|
|
251
|
+
if (originalName) unavailableOriginalNames.add(originalName);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
const conflictingTool = projectedTools.find((entry) => entry.wireName === projectedTool.wireName);
|
|
255
|
+
if (conflictingTool && conflictingTool.originalName !== projectedTool.originalName) throw new Error(`Anthropic tool names "${conflictingTool.originalName}" and "${projectedTool.originalName}" both map to "${projectedTool.wireName}"`);
|
|
256
|
+
projectedTools.push(projectedTool);
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
inputToolCount: tools.length,
|
|
260
|
+
unavailableOriginalNames,
|
|
261
|
+
tools: projectedTools
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/** Keeps forced Anthropic tool choices aligned with the projected wire names. */
|
|
265
|
+
function reconcileAnthropicToolChoice(choice, projection) {
|
|
266
|
+
if (projection.inputToolCount === 0) return choice;
|
|
267
|
+
if (choice.type === "tool") {
|
|
268
|
+
const requestedName = choice.name;
|
|
269
|
+
const originalMatch = projection.tools.find((tool) => tool.originalName === requestedName);
|
|
270
|
+
if (originalMatch) return {
|
|
271
|
+
...choice,
|
|
272
|
+
name: originalMatch.wireName
|
|
273
|
+
};
|
|
274
|
+
if (projection.unavailableOriginalNames.has(requestedName)) throw new Error(`Anthropic tool_choice requested unavailable tool "${requestedName}" after schema conversion`);
|
|
275
|
+
const matchedTool = projection.tools.find((tool) => tool.wireName === requestedName);
|
|
276
|
+
if (!matchedTool) throw new Error(`Anthropic tool_choice requested unavailable tool "${requestedName}" after schema conversion`);
|
|
277
|
+
return {
|
|
278
|
+
...choice,
|
|
279
|
+
name: matchedTool.wireName
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
if (projection.tools.length === 0) {
|
|
283
|
+
if (choice.type === "auto") return;
|
|
284
|
+
if (choice.type === "any") throw new Error("Anthropic tool_choice requires a tool, but no tools survived schema conversion");
|
|
285
|
+
}
|
|
286
|
+
return choice;
|
|
287
|
+
}
|
|
288
|
+
/** Maps Claude Code wire names without trusting every direct/custom descriptor. */
|
|
289
|
+
function resolveOriginalAnthropicToolName(name, projection) {
|
|
290
|
+
return projection?.tools.find((tool) => tool.wireName === name)?.originalName ?? name;
|
|
291
|
+
}
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region packages/ai/src/providers/anthropic-usage.ts
|
|
294
|
+
function readAnthropicUsageTokenCount(value) {
|
|
295
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
296
|
+
}
|
|
297
|
+
function readAnthropicPromptUsageSnapshot(usage) {
|
|
298
|
+
const input = readAnthropicUsageTokenCount(usage.input_tokens);
|
|
299
|
+
const cacheRead = usage.cache_read_input_tokens == null ? 0 : readAnthropicUsageTokenCount(usage.cache_read_input_tokens);
|
|
300
|
+
const cacheWrite = usage.cache_creation_input_tokens == null ? 0 : readAnthropicUsageTokenCount(usage.cache_creation_input_tokens);
|
|
301
|
+
if (input === void 0 || cacheRead === void 0 || cacheWrite === void 0) return;
|
|
302
|
+
return {
|
|
303
|
+
input,
|
|
304
|
+
cacheRead,
|
|
305
|
+
cacheWrite
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function readLastAnthropicIterationUsage(usage) {
|
|
309
|
+
if (usage.iterations == null) return { state: "absent" };
|
|
310
|
+
if (!Array.isArray(usage.iterations) || usage.iterations.length === 0) return { state: "invalid" };
|
|
311
|
+
const iteration = usage.iterations.at(-1);
|
|
312
|
+
if (!iteration || typeof iteration !== "object" || Array.isArray(iteration)) return { state: "invalid" };
|
|
313
|
+
const record = iteration;
|
|
314
|
+
const input = readAnthropicUsageTokenCount(record.input_tokens);
|
|
315
|
+
const cacheRead = readAnthropicUsageTokenCount(record.cache_read_input_tokens);
|
|
316
|
+
const cacheWrite = readAnthropicUsageTokenCount(record.cache_creation_input_tokens);
|
|
317
|
+
const outputTokens = readAnthropicUsageTokenCount(record.output_tokens);
|
|
318
|
+
if (input === void 0 || cacheRead === void 0 || cacheWrite === void 0 || outputTokens === void 0) return { state: "invalid" };
|
|
319
|
+
const contextPromptTokens = input + cacheRead + cacheWrite;
|
|
320
|
+
return {
|
|
321
|
+
state: "valid",
|
|
322
|
+
usage: {
|
|
323
|
+
contextPromptTokens,
|
|
324
|
+
totalTokens: contextPromptTokens + outputTokens
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region packages/ai/src/providers/anthropic.ts
|
|
330
|
+
var anthropic_exports = /* @__PURE__ */ __exportAll({
|
|
331
|
+
streamAnthropic: () => streamAnthropic,
|
|
332
|
+
streamSimpleAnthropic: () => streamSimpleAnthropic
|
|
333
|
+
});
|
|
334
|
+
const ANTHROPIC_CACHE_CONTROL_LIMIT = 4;
|
|
335
|
+
const EMPTY_ERROR_TOOL_RESULT_TEXT = "[tool error with no output]";
|
|
336
|
+
function getCacheControl(model, cacheRetention) {
|
|
337
|
+
const retention = resolveCacheRetention(cacheRetention);
|
|
338
|
+
if (retention === "none") return { retention };
|
|
339
|
+
const ttl = retention === "long" && getAnthropicCompat(model).supportsLongCacheRetention ? "1h" : void 0;
|
|
340
|
+
return {
|
|
341
|
+
retention,
|
|
342
|
+
cacheControl: {
|
|
343
|
+
type: "ephemeral",
|
|
344
|
+
...ttl && { ttl }
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
const claudeCodeVersion = "2.1.75";
|
|
349
|
+
const claudeCodeBillingSystemBlock = `x-anthropic-billing-header: cc_version=${claudeCodeVersion}; cc_entrypoint=sdk-cli;`;
|
|
350
|
+
const ccToolLookup = new Map([
|
|
351
|
+
"Read",
|
|
352
|
+
"Write",
|
|
353
|
+
"Edit",
|
|
354
|
+
"Bash",
|
|
355
|
+
"Grep",
|
|
356
|
+
"Glob",
|
|
357
|
+
"AskUserQuestion",
|
|
358
|
+
"EnterPlanMode",
|
|
359
|
+
"ExitPlanMode",
|
|
360
|
+
"KillShell",
|
|
361
|
+
"NotebookEdit",
|
|
362
|
+
"Skill",
|
|
363
|
+
"Task",
|
|
364
|
+
"TaskOutput",
|
|
365
|
+
"TodoWrite",
|
|
366
|
+
"WebFetch",
|
|
367
|
+
"WebSearch"
|
|
368
|
+
].map((t) => [t.toLowerCase(), t]));
|
|
369
|
+
const toClaudeCodeName = (name) => ccToolLookup.get(name.toLowerCase()) ?? name;
|
|
370
|
+
/**
|
|
371
|
+
* Convert content blocks to Anthropic API format
|
|
372
|
+
*/
|
|
373
|
+
function convertContentBlocks(content, isError) {
|
|
374
|
+
const text = extractToolResultText(content);
|
|
375
|
+
const mediaPlaceholder = describeToolResultMediaPlaceholder(content);
|
|
376
|
+
if (!(Array.isArray(content) && content.some((item) => item && typeof item === "object" && item.type === "image"))) {
|
|
377
|
+
const sanitized = sanitizeSurrogates(text);
|
|
378
|
+
return sanitized.trim().length > 0 ? sanitized : mediaPlaceholder ?? (isError ? EMPTY_ERROR_TOOL_RESULT_TEXT : "");
|
|
379
|
+
}
|
|
380
|
+
const blocks = [];
|
|
381
|
+
let hasTextBlock = false;
|
|
382
|
+
for (const block of Array.isArray(content) ? content : []) {
|
|
383
|
+
if (!block || typeof block !== "object") continue;
|
|
384
|
+
const record = block;
|
|
385
|
+
const blockText = extractToolResultBlockText(block);
|
|
386
|
+
if (blockText) {
|
|
387
|
+
blocks.push({
|
|
388
|
+
type: "text",
|
|
389
|
+
text: sanitizeSurrogates(blockText)
|
|
390
|
+
});
|
|
391
|
+
hasTextBlock = true;
|
|
392
|
+
}
|
|
393
|
+
if (record.type !== "image") continue;
|
|
394
|
+
blocks.push({
|
|
395
|
+
type: "image",
|
|
396
|
+
source: {
|
|
397
|
+
type: "base64",
|
|
398
|
+
media_type: typeof record.mimeType === "string" ? record.mimeType : "image/jpeg",
|
|
399
|
+
data: typeof record.data === "string" ? record.data : ""
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
if (!hasTextBlock) blocks.unshift({
|
|
404
|
+
type: "text",
|
|
405
|
+
text: mediaPlaceholder ?? "(see attached image)"
|
|
406
|
+
});
|
|
407
|
+
return blocks;
|
|
408
|
+
}
|
|
409
|
+
const FINE_GRAINED_TOOL_STREAMING_BETA = "fine-grained-tool-streaming-2025-05-14";
|
|
410
|
+
const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
|
|
411
|
+
const ANTHROPIC_MIN_THINKING_BUDGET_TOKENS = 1024;
|
|
412
|
+
function getAnthropicCompat(model) {
|
|
413
|
+
const isFireworks = model.provider === "fireworks";
|
|
414
|
+
const isCloudflareAiGatewayAnthropic = model.provider === "cloudflare-ai-gateway" && model.baseUrl.includes("anthropic");
|
|
415
|
+
return {
|
|
416
|
+
supportsEagerToolInputStreaming: model.compat?.supportsEagerToolInputStreaming ?? !isFireworks,
|
|
417
|
+
supportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? !isFireworks,
|
|
418
|
+
sendSessionAffinityHeaders: model.compat?.sendSessionAffinityHeaders ?? (isFireworks || isCloudflareAiGatewayAnthropic),
|
|
419
|
+
supportsCacheControlOnTools: model.compat?.supportsCacheControlOnTools ?? !isFireworks
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function mergeHeaders(...headerSources) {
|
|
423
|
+
const merged = {};
|
|
424
|
+
for (const headers of headerSources) if (headers) Object.assign(merged, headers);
|
|
425
|
+
return merged;
|
|
426
|
+
}
|
|
427
|
+
const ANTHROPIC_MESSAGE_EVENTS = /* @__PURE__ */ new Set([
|
|
428
|
+
"message_start",
|
|
429
|
+
"message_delta",
|
|
430
|
+
"message_stop",
|
|
431
|
+
"content_block_start",
|
|
432
|
+
"content_block_delta",
|
|
433
|
+
"content_block_stop"
|
|
434
|
+
]);
|
|
435
|
+
function flushSseEvent(state) {
|
|
436
|
+
if (!state.event && state.data.length === 0) return null;
|
|
437
|
+
const event = {
|
|
438
|
+
event: state.event,
|
|
439
|
+
data: state.data.join("\n"),
|
|
440
|
+
raw: [...state.raw]
|
|
441
|
+
};
|
|
442
|
+
state.event = null;
|
|
443
|
+
state.data = [];
|
|
444
|
+
state.raw = [];
|
|
445
|
+
return event;
|
|
446
|
+
}
|
|
447
|
+
function decodeSseLine(line, state) {
|
|
448
|
+
if (line === "") return flushSseEvent(state);
|
|
449
|
+
state.raw.push(line);
|
|
450
|
+
if (line.startsWith(":")) return null;
|
|
451
|
+
const delimiterIndex = line.indexOf(":");
|
|
452
|
+
const fieldName = delimiterIndex === -1 ? line : line.slice(0, delimiterIndex);
|
|
453
|
+
let value = delimiterIndex === -1 ? "" : line.slice(delimiterIndex + 1);
|
|
454
|
+
if (value.startsWith(" ")) value = value.slice(1);
|
|
455
|
+
if (fieldName === "event") state.event = value;
|
|
456
|
+
else if (fieldName === "data") state.data.push(value);
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
function nextLineBreakIndex(text) {
|
|
460
|
+
const carriageReturnIndex = text.indexOf("\r");
|
|
461
|
+
const newlineIndex = text.indexOf("\n");
|
|
462
|
+
if (carriageReturnIndex === -1) return newlineIndex;
|
|
463
|
+
if (newlineIndex === -1) return carriageReturnIndex;
|
|
464
|
+
return Math.min(carriageReturnIndex, newlineIndex);
|
|
465
|
+
}
|
|
466
|
+
function consumeLine(text) {
|
|
467
|
+
const lineBreakIndex = nextLineBreakIndex(text);
|
|
468
|
+
if (lineBreakIndex === -1) return null;
|
|
469
|
+
let nextIndex = lineBreakIndex + 1;
|
|
470
|
+
if (text[lineBreakIndex] === "\r" && text[nextIndex] === "\n") nextIndex += 1;
|
|
471
|
+
return {
|
|
472
|
+
line: text.slice(0, lineBreakIndex),
|
|
473
|
+
rest: text.slice(nextIndex)
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
async function* iterateSseMessages(body, signal) {
|
|
477
|
+
const reader = body.getReader();
|
|
478
|
+
const decoder = new TextDecoder();
|
|
479
|
+
const state = {
|
|
480
|
+
event: null,
|
|
481
|
+
data: [],
|
|
482
|
+
raw: []
|
|
483
|
+
};
|
|
484
|
+
let buffer = "";
|
|
485
|
+
try {
|
|
486
|
+
while (true) {
|
|
487
|
+
if (signal?.aborted) throw new Error("Request was aborted");
|
|
488
|
+
const { value, done } = await reader.read();
|
|
489
|
+
if (done) break;
|
|
490
|
+
buffer += decoder.decode(value, { stream: true });
|
|
491
|
+
let consumed = consumeLine(buffer);
|
|
492
|
+
while (consumed) {
|
|
493
|
+
buffer = consumed.rest;
|
|
494
|
+
const event = decodeSseLine(consumed.line, state);
|
|
495
|
+
if (event) yield event;
|
|
496
|
+
consumed = consumeLine(buffer);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
buffer += decoder.decode();
|
|
500
|
+
let consumed = consumeLine(buffer);
|
|
501
|
+
while (consumed) {
|
|
502
|
+
buffer = consumed.rest;
|
|
503
|
+
const event = decodeSseLine(consumed.line, state);
|
|
504
|
+
if (event) yield event;
|
|
505
|
+
consumed = consumeLine(buffer);
|
|
506
|
+
}
|
|
507
|
+
if (buffer.length > 0) {
|
|
508
|
+
const event = decodeSseLine(buffer, state);
|
|
509
|
+
if (event) yield event;
|
|
510
|
+
}
|
|
511
|
+
const trailingEvent = flushSseEvent(state);
|
|
512
|
+
if (trailingEvent) yield trailingEvent;
|
|
513
|
+
} finally {
|
|
514
|
+
reader.releaseLock();
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
async function* iterateAnthropicEvents(response, signal, requireMessageStop = false) {
|
|
518
|
+
if (!response.body) throw new Error("Attempted to iterate over an Anthropic response with no body");
|
|
519
|
+
let sawMessageStart = false;
|
|
520
|
+
let sawMessageEnd = false;
|
|
521
|
+
for await (const sse of iterateSseMessages(response.body, signal)) {
|
|
522
|
+
if (sse.event === "error") throw new Error(sse.data);
|
|
523
|
+
if (!ANTHROPIC_MESSAGE_EVENTS.has(sse.event ?? "")) continue;
|
|
524
|
+
try {
|
|
525
|
+
const event = parseJsonWithRepair(sse.data);
|
|
526
|
+
if (event.type === "message_start") sawMessageStart = true;
|
|
527
|
+
else if (event.type === "message_stop") sawMessageEnd = true;
|
|
528
|
+
yield event;
|
|
529
|
+
} catch (error) {
|
|
530
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
531
|
+
throw new Error(`Could not parse Anthropic SSE event ${sse.event}: ${message}; data=${sse.data}; raw=${sse.raw.join("\\n")}`, { cause: error });
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if ((sawMessageStart || requireMessageStop) && !sawMessageEnd) throw new Error("Anthropic stream ended before message_stop");
|
|
535
|
+
}
|
|
536
|
+
const streamAnthropic = (model, context, options) => {
|
|
537
|
+
const stream = new AssistantMessageEventStream();
|
|
538
|
+
const requestContext = prepareClaudeSonnet5RequestContext(model, context);
|
|
539
|
+
const requestOptions = normalizeAnthropicThinkingOptions(model, options);
|
|
540
|
+
(async () => {
|
|
541
|
+
const output = {
|
|
542
|
+
role: "assistant",
|
|
543
|
+
content: [],
|
|
544
|
+
api: model.api,
|
|
545
|
+
provider: model.provider,
|
|
546
|
+
model: model.id,
|
|
547
|
+
usage: {
|
|
548
|
+
input: 0,
|
|
549
|
+
output: 0,
|
|
550
|
+
cacheRead: 0,
|
|
551
|
+
cacheWrite: 0,
|
|
552
|
+
totalTokens: 0,
|
|
553
|
+
cost: {
|
|
554
|
+
input: 0,
|
|
555
|
+
output: 0,
|
|
556
|
+
cacheRead: 0,
|
|
557
|
+
cacheWrite: 0,
|
|
558
|
+
total: 0
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
stopReason: "stop",
|
|
562
|
+
timestamp: Date.now()
|
|
563
|
+
};
|
|
564
|
+
const refusalBuffer = usesClaudeStreamingRefusalContract(model) ? createDeferredEventBuffer(stream, () => notifyLlmRequestActivity(requestOptions?.signal)) : void 0;
|
|
565
|
+
const eventSink = refusalBuffer ?? stream;
|
|
566
|
+
let costModel = model;
|
|
567
|
+
let messageStartPromptUsage;
|
|
568
|
+
try {
|
|
569
|
+
let client;
|
|
570
|
+
let isOAuth;
|
|
571
|
+
let serverSideFallback = false;
|
|
572
|
+
if (requestOptions?.client) {
|
|
573
|
+
client = requestOptions.client;
|
|
574
|
+
isOAuth = false;
|
|
575
|
+
} else {
|
|
576
|
+
const apiKey = requestOptions?.apiKey ?? getEnvApiKey(model.provider) ?? "";
|
|
577
|
+
let copilotDynamicHeaders;
|
|
578
|
+
if (model.provider === "github-copilot") {
|
|
579
|
+
const hasImages = hasCopilotVisionInput(requestContext.messages);
|
|
580
|
+
copilotDynamicHeaders = buildCopilotDynamicHeaders({
|
|
581
|
+
messages: requestContext.messages,
|
|
582
|
+
hasImages
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
const cacheSessionId = (requestOptions?.cacheRetention ?? resolveCacheRetention()) === "none" ? void 0 : requestOptions?.sessionId;
|
|
586
|
+
const created = createClient(model, apiKey, requestOptions?.thinkingEnabled === true, requestOptions?.interleavedThinking ?? true, shouldUseFineGrainedToolStreamingBeta(model, requestContext), requestOptions?.headers, copilotDynamicHeaders, cacheSessionId);
|
|
587
|
+
client = created.client;
|
|
588
|
+
isOAuth = created.isOAuthToken;
|
|
589
|
+
serverSideFallback = created.serverSideFallback;
|
|
590
|
+
}
|
|
591
|
+
const builtParams = buildParams(model, requestContext, isOAuth, requestOptions, serverSideFallback);
|
|
592
|
+
let params = builtParams.params;
|
|
593
|
+
const toolProjection = builtParams.toolProjection;
|
|
594
|
+
const nextParams = await requestOptions?.onPayload?.(params, model);
|
|
595
|
+
if (nextParams !== void 0) params = nextParams;
|
|
596
|
+
applyClaudeRequestContract(params, model);
|
|
597
|
+
const sdkRequestOptions = {
|
|
598
|
+
...requestOptions?.signal ? { signal: requestOptions.signal } : {},
|
|
599
|
+
...requestOptions?.timeoutMs !== void 0 ? { timeout: requestOptions.timeoutMs } : {},
|
|
600
|
+
...requestOptions?.maxRetries !== void 0 ? { maxRetries: requestOptions.maxRetries } : {}
|
|
601
|
+
};
|
|
602
|
+
const response = await client.messages.create({
|
|
603
|
+
...params,
|
|
604
|
+
stream: true
|
|
605
|
+
}, sdkRequestOptions).asResponse();
|
|
606
|
+
await requestOptions?.onResponse?.({
|
|
607
|
+
status: response.status,
|
|
608
|
+
headers: headersToRecord(response.headers)
|
|
609
|
+
}, model);
|
|
610
|
+
const blocks = output.content;
|
|
611
|
+
const blockIndexes = /* @__PURE__ */ new Map();
|
|
612
|
+
for await (const event of iterateAnthropicEvents(response, requestOptions?.signal, refusalBuffer !== void 0)) if (event.type === "message_start") {
|
|
613
|
+
output.responseId = event.message.id;
|
|
614
|
+
output.responseModel = event.message.model;
|
|
615
|
+
const promptUsage = readAnthropicPromptUsageSnapshot(event.message.usage);
|
|
616
|
+
const messageStartPromptTokens = promptUsage ? promptUsage.input + promptUsage.cacheRead + promptUsage.cacheWrite : 0;
|
|
617
|
+
messageStartPromptUsage = messageStartPromptTokens > 0 ? promptUsage : void 0;
|
|
618
|
+
const inputTokens = readAnthropicUsageTokenCount(event.message.usage.input_tokens);
|
|
619
|
+
if (inputTokens !== void 0) output.usage.input = inputTokens;
|
|
620
|
+
const outputTokens = readAnthropicUsageTokenCount(event.message.usage.output_tokens);
|
|
621
|
+
if (outputTokens !== void 0) output.usage.output = outputTokens;
|
|
622
|
+
const cacheReadTokens = event.message.usage.cache_read_input_tokens == null ? 0 : readAnthropicUsageTokenCount(event.message.usage.cache_read_input_tokens);
|
|
623
|
+
if (cacheReadTokens !== void 0) output.usage.cacheRead = cacheReadTokens;
|
|
624
|
+
const cacheWriteTokens = event.message.usage.cache_creation_input_tokens == null ? 0 : readAnthropicUsageTokenCount(event.message.usage.cache_creation_input_tokens);
|
|
625
|
+
if (cacheWriteTokens !== void 0) output.usage.cacheWrite = cacheWriteTokens;
|
|
626
|
+
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
627
|
+
if (messageStartPromptUsage && outputTokens !== void 0) output.usage.contextUsage = {
|
|
628
|
+
state: "available",
|
|
629
|
+
promptTokens: messageStartPromptTokens,
|
|
630
|
+
totalTokens: messageStartPromptTokens + output.usage.output
|
|
631
|
+
};
|
|
632
|
+
calculateCost(costModel, output.usage);
|
|
633
|
+
eventSink.push({
|
|
634
|
+
type: "start",
|
|
635
|
+
partial: output
|
|
636
|
+
});
|
|
637
|
+
} else if (event.type === "content_block_start") {
|
|
638
|
+
const fallbackBoundary = refusalBuffer ? readAnthropicFallbackBoundary(event.content_block) : null;
|
|
639
|
+
if (fallbackBoundary) {
|
|
640
|
+
refusalBuffer?.discard();
|
|
641
|
+
blockIndexes.clear();
|
|
642
|
+
applyAnthropicFallbackBoundary({
|
|
643
|
+
output,
|
|
644
|
+
boundary: fallbackBoundary,
|
|
645
|
+
provider: model.provider
|
|
646
|
+
});
|
|
647
|
+
costModel = {
|
|
648
|
+
...model,
|
|
649
|
+
cost: CLAUDE_FABLE_5_FALLBACK_MODEL_COST
|
|
650
|
+
};
|
|
651
|
+
calculateCost(costModel, output.usage);
|
|
652
|
+
eventSink.push({
|
|
653
|
+
type: "start",
|
|
654
|
+
partial: output
|
|
655
|
+
});
|
|
656
|
+
for (let i = 0; i < blocks.length; i += 1) {
|
|
657
|
+
const block = blocks[i];
|
|
658
|
+
if (block.type !== "text") continue;
|
|
659
|
+
delete block.index;
|
|
660
|
+
eventSink.push({
|
|
661
|
+
type: "text_start",
|
|
662
|
+
contentIndex: i,
|
|
663
|
+
partial: output
|
|
664
|
+
});
|
|
665
|
+
if (block.text) eventSink.push({
|
|
666
|
+
type: "text_delta",
|
|
667
|
+
contentIndex: i,
|
|
668
|
+
delta: block.text,
|
|
669
|
+
partial: output
|
|
670
|
+
});
|
|
671
|
+
eventSink.push({
|
|
672
|
+
type: "text_end",
|
|
673
|
+
contentIndex: i,
|
|
674
|
+
content: block.text,
|
|
675
|
+
partial: output
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
} else if (event.content_block.type === "text") {
|
|
679
|
+
const block = {
|
|
680
|
+
type: "text",
|
|
681
|
+
text: "",
|
|
682
|
+
index: event.index
|
|
683
|
+
};
|
|
684
|
+
output.content.push(block);
|
|
685
|
+
blockIndexes.set(event.index, output.content.length - 1);
|
|
686
|
+
eventSink.push({
|
|
687
|
+
type: "text_start",
|
|
688
|
+
contentIndex: output.content.length - 1,
|
|
689
|
+
partial: output
|
|
690
|
+
});
|
|
691
|
+
} else if (event.content_block.type === "thinking") {
|
|
692
|
+
const block = {
|
|
693
|
+
type: "thinking",
|
|
694
|
+
thinking: "",
|
|
695
|
+
thinkingSignature: "",
|
|
696
|
+
index: event.index
|
|
697
|
+
};
|
|
698
|
+
output.content.push(block);
|
|
699
|
+
blockIndexes.set(event.index, output.content.length - 1);
|
|
700
|
+
eventSink.push({
|
|
701
|
+
type: "thinking_start",
|
|
702
|
+
contentIndex: output.content.length - 1,
|
|
703
|
+
partial: output
|
|
704
|
+
});
|
|
705
|
+
} else if (event.content_block.type === "redacted_thinking") {
|
|
706
|
+
const block = {
|
|
707
|
+
type: "thinking",
|
|
708
|
+
thinking: "[Reasoning redacted]",
|
|
709
|
+
thinkingSignature: event.content_block.data,
|
|
710
|
+
redacted: true,
|
|
711
|
+
index: event.index
|
|
712
|
+
};
|
|
713
|
+
output.content.push(block);
|
|
714
|
+
blockIndexes.set(event.index, output.content.length - 1);
|
|
715
|
+
eventSink.push({
|
|
716
|
+
type: "thinking_start",
|
|
717
|
+
contentIndex: output.content.length - 1,
|
|
718
|
+
partial: output
|
|
719
|
+
});
|
|
720
|
+
} else if (event.content_block.type === "tool_use") {
|
|
721
|
+
const block = {
|
|
722
|
+
type: "toolCall",
|
|
723
|
+
id: event.content_block.id,
|
|
724
|
+
name: isOAuth ? resolveOriginalAnthropicToolName(event.content_block.name, toolProjection) : event.content_block.name,
|
|
725
|
+
arguments: event.content_block.input ?? {},
|
|
726
|
+
partialJson: "",
|
|
727
|
+
index: event.index
|
|
728
|
+
};
|
|
729
|
+
output.content.push(block);
|
|
730
|
+
blockIndexes.set(event.index, output.content.length - 1);
|
|
731
|
+
eventSink.push({
|
|
732
|
+
type: "toolcall_start",
|
|
733
|
+
contentIndex: output.content.length - 1,
|
|
734
|
+
partial: output
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
} else if (event.type === "content_block_delta") {
|
|
738
|
+
if (event.delta.type === "text_delta") {
|
|
739
|
+
const index = blockIndexes.get(event.index);
|
|
740
|
+
const block = index === void 0 ? void 0 : blocks[index];
|
|
741
|
+
if (index !== void 0 && block?.type === "text") {
|
|
742
|
+
block.text += event.delta.text;
|
|
743
|
+
eventSink.push({
|
|
744
|
+
type: "text_delta",
|
|
745
|
+
contentIndex: index,
|
|
746
|
+
delta: event.delta.text,
|
|
747
|
+
partial: output
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
} else if (event.delta.type === "thinking_delta") {
|
|
751
|
+
const index = blockIndexes.get(event.index);
|
|
752
|
+
const block = index === void 0 ? void 0 : blocks[index];
|
|
753
|
+
if (index !== void 0 && block?.type === "thinking") {
|
|
754
|
+
block.thinking += event.delta.thinking;
|
|
755
|
+
eventSink.push({
|
|
756
|
+
type: "thinking_delta",
|
|
757
|
+
contentIndex: index,
|
|
758
|
+
delta: event.delta.thinking,
|
|
759
|
+
partial: output
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
} else if (event.delta.type === "input_json_delta") {
|
|
763
|
+
const index = blockIndexes.get(event.index);
|
|
764
|
+
const block = index === void 0 ? void 0 : blocks[index];
|
|
765
|
+
if (index !== void 0 && block?.type === "toolCall") {
|
|
766
|
+
block.partialJson += event.delta.partial_json;
|
|
767
|
+
block.arguments = parseStreamingJson(block.partialJson);
|
|
768
|
+
eventSink.push({
|
|
769
|
+
type: "toolcall_delta",
|
|
770
|
+
contentIndex: index,
|
|
771
|
+
delta: event.delta.partial_json,
|
|
772
|
+
partial: output
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
} else if (event.delta.type === "signature_delta") {
|
|
776
|
+
const index = blockIndexes.get(event.index);
|
|
777
|
+
const block = index === void 0 ? void 0 : blocks[index];
|
|
778
|
+
if (index !== void 0 && block?.type === "thinking") {
|
|
779
|
+
block.thinkingSignature = block.thinkingSignature || "";
|
|
780
|
+
block.thinkingSignature += event.delta.signature;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
} else if (event.type === "content_block_stop") {
|
|
784
|
+
const index = blockIndexes.get(event.index);
|
|
785
|
+
const block = index === void 0 ? void 0 : blocks[index];
|
|
786
|
+
if (index !== void 0 && block) {
|
|
787
|
+
blockIndexes.delete(event.index);
|
|
788
|
+
delete block.index;
|
|
789
|
+
if (block.type === "text") eventSink.push({
|
|
790
|
+
type: "text_end",
|
|
791
|
+
contentIndex: index,
|
|
792
|
+
content: block.text,
|
|
793
|
+
partial: output
|
|
794
|
+
});
|
|
795
|
+
else if (block.type === "thinking") eventSink.push({
|
|
796
|
+
type: "thinking_end",
|
|
797
|
+
contentIndex: index,
|
|
798
|
+
content: block.thinking,
|
|
799
|
+
partial: output
|
|
800
|
+
});
|
|
801
|
+
else if (block.type === "toolCall") {
|
|
802
|
+
block.arguments = parseStreamingJson(block.partialJson);
|
|
803
|
+
delete block.partialJson;
|
|
804
|
+
eventSink.push({
|
|
805
|
+
type: "toolcall_end",
|
|
806
|
+
contentIndex: index,
|
|
807
|
+
toolCall: block,
|
|
808
|
+
partial: output
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
} else if (event.type === "message_delta") {
|
|
813
|
+
if (event.delta.stop_reason) if (event.delta.stop_reason === "refusal") applyAnthropicRefusal(output, event.delta.stop_details, model.provider);
|
|
814
|
+
else output.stopReason = mapStopReason(event.delta.stop_reason);
|
|
815
|
+
const inputTokens = readAnthropicUsageTokenCount(event.usage.input_tokens);
|
|
816
|
+
if (inputTokens !== void 0) output.usage.input = inputTokens;
|
|
817
|
+
const outputTokens = readAnthropicUsageTokenCount(event.usage.output_tokens);
|
|
818
|
+
if (outputTokens !== void 0) output.usage.output = outputTokens;
|
|
819
|
+
const cacheReadTokens = readAnthropicUsageTokenCount(event.usage.cache_read_input_tokens);
|
|
820
|
+
if (cacheReadTokens !== void 0) output.usage.cacheRead = cacheReadTokens;
|
|
821
|
+
const cacheWriteTokens = readAnthropicUsageTokenCount(event.usage.cache_creation_input_tokens);
|
|
822
|
+
if (cacheWriteTokens !== void 0) output.usage.cacheWrite = cacheWriteTokens;
|
|
823
|
+
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
824
|
+
const iterationUsage = readLastAnthropicIterationUsage(event.usage);
|
|
825
|
+
if (iterationUsage.state === "valid") output.usage.contextUsage = {
|
|
826
|
+
state: "available",
|
|
827
|
+
promptTokens: iterationUsage.usage.contextPromptTokens,
|
|
828
|
+
totalTokens: iterationUsage.usage.totalTokens
|
|
829
|
+
};
|
|
830
|
+
else if (iterationUsage.state === "invalid") output.usage.contextUsage = { state: "unavailable" };
|
|
831
|
+
else if (outputTokens !== void 0 && (messageStartPromptUsage !== void 0 || inputTokens !== void 0 && cacheReadTokens !== void 0 && cacheWriteTokens !== void 0)) {
|
|
832
|
+
const promptTokens = output.usage.input + output.usage.cacheRead + output.usage.cacheWrite;
|
|
833
|
+
output.usage.contextUsage = {
|
|
834
|
+
state: "available",
|
|
835
|
+
promptTokens,
|
|
836
|
+
totalTokens: promptTokens + output.usage.output
|
|
837
|
+
};
|
|
838
|
+
} else output.usage.contextUsage = { state: "unavailable" };
|
|
839
|
+
calculateCost(costModel, output.usage);
|
|
840
|
+
}
|
|
841
|
+
if (requestOptions?.signal?.aborted) throw new Error("Request was aborted");
|
|
842
|
+
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
843
|
+
refusalBuffer?.flush();
|
|
844
|
+
stream.push({
|
|
845
|
+
type: "done",
|
|
846
|
+
reason: output.stopReason,
|
|
847
|
+
message: output
|
|
848
|
+
});
|
|
849
|
+
stream.end();
|
|
850
|
+
} catch (error) {
|
|
851
|
+
for (const block of output.content) {
|
|
852
|
+
delete block.index;
|
|
853
|
+
delete block.partialJson;
|
|
854
|
+
}
|
|
855
|
+
if (refusalBuffer) {
|
|
856
|
+
refusalBuffer.discard();
|
|
857
|
+
output.content = [];
|
|
858
|
+
}
|
|
859
|
+
output.stopReason = requestOptions?.signal?.aborted ? "aborted" : "error";
|
|
860
|
+
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
|
861
|
+
stream.push({
|
|
862
|
+
type: "error",
|
|
863
|
+
reason: output.stopReason,
|
|
864
|
+
error: output
|
|
865
|
+
});
|
|
866
|
+
stream.end();
|
|
867
|
+
}
|
|
868
|
+
})();
|
|
869
|
+
return stream;
|
|
870
|
+
};
|
|
871
|
+
function normalizeAnthropicToolChoice(thinkingEnabled, toolChoice) {
|
|
872
|
+
if (thinkingEnabled && (toolChoice === "any" || typeof toolChoice === "object" && toolChoice.type === "tool")) return { type: "auto" };
|
|
873
|
+
return typeof toolChoice === "string" ? { type: toolChoice } : toolChoice;
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Check if a model supports adaptive thinking (Fable 5, Opus 4.6+, Sonnet 4.6).
|
|
877
|
+
*/
|
|
878
|
+
function supportsAdaptiveThinking(model) {
|
|
879
|
+
return supportsClaudeAdaptiveThinking(model);
|
|
880
|
+
}
|
|
881
|
+
function normalizeAnthropicThinkingOptions(model, options) {
|
|
882
|
+
if (options?.thinkingEnabled !== true || supportsAdaptiveThinking(model)) return options;
|
|
883
|
+
const budgetTokens = options.thinkingBudgetTokens ?? ANTHROPIC_MIN_THINKING_BUDGET_TOKENS;
|
|
884
|
+
const maxTokens = options.maxTokens ?? model.maxTokens;
|
|
885
|
+
if (budgetTokens >= ANTHROPIC_MIN_THINKING_BUDGET_TOKENS && budgetTokens < maxTokens) return options;
|
|
886
|
+
return {
|
|
887
|
+
...options,
|
|
888
|
+
thinkingEnabled: false,
|
|
889
|
+
thinkingBudgetTokens: void 0
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
function supportsNativeXhighEffort(model) {
|
|
893
|
+
return supportsClaudeNativeXhighEffort(model);
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Map ThinkingLevel to Anthropic effort levels for adaptive thinking.
|
|
897
|
+
* Model metadata owns the provider-specific extended effort mapping.
|
|
898
|
+
*/
|
|
899
|
+
function mapThinkingLevelToEffort(model, level) {
|
|
900
|
+
const requestedLevel = level;
|
|
901
|
+
const hasCanonicalAlias = typeof model.params?.canonicalModelId === "string";
|
|
902
|
+
const thinkingLevelMap = resolveClaudeNativeThinkingLevelMap(model);
|
|
903
|
+
const clampModel = {
|
|
904
|
+
...model,
|
|
905
|
+
...hasCanonicalAlias ? { reasoning: true } : {},
|
|
906
|
+
...thinkingLevelMap ? { thinkingLevelMap } : {}
|
|
907
|
+
};
|
|
908
|
+
const clampedLevel = requestedLevel ? clampThinkingLevel(clampModel, requestedLevel) : requestedLevel;
|
|
909
|
+
const mapped = clampedLevel ? thinkingLevelMap?.[clampedLevel] : void 0;
|
|
910
|
+
if (typeof mapped === "string") return mapped;
|
|
911
|
+
switch (clampedLevel) {
|
|
912
|
+
case "off":
|
|
913
|
+
case "minimal":
|
|
914
|
+
case "low": return "low";
|
|
915
|
+
case "medium": return "medium";
|
|
916
|
+
case "high": return "high";
|
|
917
|
+
case "xhigh": return supportsNativeXhighEffort(model) ? "xhigh" : "high";
|
|
918
|
+
case "max": return supportsClaudeNativeMaxEffort(model) ? "max" : "high";
|
|
919
|
+
default: return "high";
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
const streamSimpleAnthropic = (model, context, options) => {
|
|
923
|
+
const apiKey = options?.apiKey || getEnvApiKey(model.provider);
|
|
924
|
+
if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
|
|
925
|
+
const base = {
|
|
926
|
+
...buildBaseOptions(model, options, apiKey),
|
|
927
|
+
toolChoice: options?.toolChoice
|
|
928
|
+
};
|
|
929
|
+
const mandatoryAdaptiveThinking = requiresClaudeAdaptiveThinking(model);
|
|
930
|
+
if (options?.reasoning === "off" && !mandatoryAdaptiveThinking) return streamAnthropic(model, context, {
|
|
931
|
+
...base,
|
|
932
|
+
thinkingEnabled: false
|
|
933
|
+
});
|
|
934
|
+
const reasoning = options?.reasoning === "off" ? mandatoryAdaptiveThinking ? "low" : "high" : options?.reasoning;
|
|
935
|
+
if (resolveClaudeSonnet5ModelIdentity(model)) return streamAnthropic(model, context, {
|
|
936
|
+
...base,
|
|
937
|
+
thinkingEnabled: true,
|
|
938
|
+
effort: mapThinkingLevelToEffort(model, reasoning ?? "high")
|
|
939
|
+
});
|
|
940
|
+
if (!reasoning) return streamAnthropic(model, context, {
|
|
941
|
+
...base,
|
|
942
|
+
thinkingEnabled: mandatoryAdaptiveThinking,
|
|
943
|
+
...mandatoryAdaptiveThinking ? { effort: "high" } : {}
|
|
944
|
+
});
|
|
945
|
+
if (supportsAdaptiveThinking(model)) {
|
|
946
|
+
const effort = mapThinkingLevelToEffort(model, reasoning);
|
|
947
|
+
return streamAnthropic(model, context, {
|
|
948
|
+
...base,
|
|
949
|
+
thinkingEnabled: true,
|
|
950
|
+
effort
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
const adjusted = adjustMaxTokensForThinking(base.maxTokens, model.maxTokens, reasoning, options?.thinkingBudgets);
|
|
954
|
+
const thinkingEnabled = adjusted.thinkingBudget >= 1024;
|
|
955
|
+
return streamAnthropic(model, context, {
|
|
956
|
+
...base,
|
|
957
|
+
maxTokens: adjusted.maxTokens,
|
|
958
|
+
thinkingEnabled,
|
|
959
|
+
thinkingBudgetTokens: thinkingEnabled ? adjusted.thinkingBudget : void 0
|
|
960
|
+
});
|
|
961
|
+
};
|
|
962
|
+
function isOAuthToken(apiKey) {
|
|
963
|
+
return getAiTransportHost().resolveSecretSentinel(apiKey).includes("sk-ant-oat");
|
|
964
|
+
}
|
|
965
|
+
function isAnthropicPublicEndpoint(baseUrl) {
|
|
966
|
+
if (!baseUrl) return true;
|
|
967
|
+
try {
|
|
968
|
+
return new URL(baseUrl).hostname.toLowerCase() === "api.anthropic.com";
|
|
969
|
+
} catch {
|
|
970
|
+
return false;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Server-side refusal fallback is a first-party Claude API beta: proxies and
|
|
975
|
+
* Bedrock/Vertex/Foundry reject the `fallbacks` param, and OAuth (Claude Code
|
|
976
|
+
* identity) requests are excluded until the beta is verified there.
|
|
977
|
+
*/
|
|
978
|
+
function supportsAnthropicServerSideFallback(model) {
|
|
979
|
+
if (!usesClaudeFable5MessagesContract(model) || model.provider !== "anthropic") return false;
|
|
980
|
+
return isAnthropicPublicEndpoint(model.baseUrl);
|
|
981
|
+
}
|
|
982
|
+
function createClient(model, apiKey, thinkingEnabled, interleavedThinking, useFineGrainedToolStreamingBeta, optionsHeaders, dynamicHeaders, sessionId) {
|
|
983
|
+
const needsInterleavedBeta = interleavedThinking && !supportsAdaptiveThinking(model);
|
|
984
|
+
const betaFeatures = [];
|
|
985
|
+
if (useFineGrainedToolStreamingBeta) betaFeatures.push(FINE_GRAINED_TOOL_STREAMING_BETA);
|
|
986
|
+
if (needsInterleavedBeta) betaFeatures.push(INTERLEAVED_THINKING_BETA);
|
|
987
|
+
const fetchOptions = /^kimi(?:-|$)/.test(model.provider) && thinkingEnabled ? { sanitizeSse: false } : void 0;
|
|
988
|
+
const fetch = getAiTransportHost().buildModelFetch(model, void 0, fetchOptions);
|
|
989
|
+
if (model.provider === "cloudflare-ai-gateway") return {
|
|
990
|
+
client: new Anthropic({
|
|
991
|
+
apiKey,
|
|
992
|
+
authToken: null,
|
|
993
|
+
baseURL: resolveCloudflareBaseUrl(model),
|
|
994
|
+
dangerouslyAllowBrowser: true,
|
|
995
|
+
defaultHeaders: mergeHeaders({
|
|
996
|
+
accept: "application/json",
|
|
997
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
998
|
+
Authorization: null,
|
|
999
|
+
...betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}
|
|
1000
|
+
}, model.headers, optionsHeaders),
|
|
1001
|
+
fetch
|
|
1002
|
+
}),
|
|
1003
|
+
isOAuthToken: false,
|
|
1004
|
+
serverSideFallback: false
|
|
1005
|
+
};
|
|
1006
|
+
if (model.provider === "github-copilot") return {
|
|
1007
|
+
client: new Anthropic({
|
|
1008
|
+
apiKey: null,
|
|
1009
|
+
authToken: apiKey,
|
|
1010
|
+
baseURL: model.baseUrl,
|
|
1011
|
+
dangerouslyAllowBrowser: true,
|
|
1012
|
+
defaultHeaders: mergeHeaders({
|
|
1013
|
+
accept: "application/json",
|
|
1014
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
1015
|
+
...betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}
|
|
1016
|
+
}, model.headers, dynamicHeaders, optionsHeaders),
|
|
1017
|
+
fetch
|
|
1018
|
+
}),
|
|
1019
|
+
isOAuthToken: false,
|
|
1020
|
+
serverSideFallback: false
|
|
1021
|
+
};
|
|
1022
|
+
if (usesFoundryBearerAuth({
|
|
1023
|
+
...model,
|
|
1024
|
+
headers: resolveAiTransportHeaderSentinels(model.headers)
|
|
1025
|
+
})) return {
|
|
1026
|
+
client: new Anthropic({
|
|
1027
|
+
apiKey: null,
|
|
1028
|
+
authToken: apiKey,
|
|
1029
|
+
baseURL: model.baseUrl,
|
|
1030
|
+
dangerouslyAllowBrowser: true,
|
|
1031
|
+
defaultHeaders: mergeHeaders({
|
|
1032
|
+
accept: "application/json",
|
|
1033
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
1034
|
+
...betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}
|
|
1035
|
+
}, omitFoundryBearerCredentialHeaders(model.headers), dynamicHeaders, optionsHeaders),
|
|
1036
|
+
fetch
|
|
1037
|
+
}),
|
|
1038
|
+
isOAuthToken: false,
|
|
1039
|
+
serverSideFallback: false
|
|
1040
|
+
};
|
|
1041
|
+
if (isOAuthToken(apiKey)) return {
|
|
1042
|
+
client: new Anthropic({
|
|
1043
|
+
apiKey: null,
|
|
1044
|
+
authToken: apiKey,
|
|
1045
|
+
baseURL: model.baseUrl,
|
|
1046
|
+
dangerouslyAllowBrowser: true,
|
|
1047
|
+
defaultHeaders: mergeHeaders({
|
|
1048
|
+
accept: "application/json",
|
|
1049
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
1050
|
+
"anthropic-beta": [
|
|
1051
|
+
"claude-code-20250219",
|
|
1052
|
+
"oauth-2025-04-20",
|
|
1053
|
+
...betaFeatures
|
|
1054
|
+
].join(","),
|
|
1055
|
+
"user-agent": `claude-cli/${claudeCodeVersion}`,
|
|
1056
|
+
"x-app": "cli"
|
|
1057
|
+
}, model.headers, optionsHeaders),
|
|
1058
|
+
fetch
|
|
1059
|
+
}),
|
|
1060
|
+
isOAuthToken: true,
|
|
1061
|
+
serverSideFallback: false
|
|
1062
|
+
};
|
|
1063
|
+
const serverSideFallback = supportsAnthropicServerSideFallback(model);
|
|
1064
|
+
if (serverSideFallback) betaFeatures.push(ANTHROPIC_SERVER_SIDE_FALLBACK_BETA);
|
|
1065
|
+
const sessionAffinityHeaders = sessionId && getAnthropicCompat(model).sendSessionAffinityHeaders ? { "x-session-affinity": sessionId } : {};
|
|
1066
|
+
return {
|
|
1067
|
+
client: new Anthropic({
|
|
1068
|
+
apiKey,
|
|
1069
|
+
authToken: null,
|
|
1070
|
+
baseURL: model.baseUrl,
|
|
1071
|
+
dangerouslyAllowBrowser: true,
|
|
1072
|
+
defaultHeaders: mergeHeaders({
|
|
1073
|
+
accept: "application/json",
|
|
1074
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
1075
|
+
...betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}
|
|
1076
|
+
}, sessionAffinityHeaders, model.headers, optionsHeaders),
|
|
1077
|
+
fetch
|
|
1078
|
+
}),
|
|
1079
|
+
isOAuthToken: false,
|
|
1080
|
+
serverSideFallback
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
function buildParams(model, context, isOAuthTokenResult, options, serverSideFallback = false) {
|
|
1084
|
+
const mandatoryAdaptiveThinking = requiresClaudeAdaptiveThinking(model);
|
|
1085
|
+
const replayThinkingEnabled = mandatoryAdaptiveThinking || options?.thinkingEnabled === true;
|
|
1086
|
+
const { cacheControl } = getCacheControl(model, options?.cacheRetention);
|
|
1087
|
+
const system = buildAnthropicSystemBlocks(context.systemPrompt, isOAuthTokenResult, cacheControl);
|
|
1088
|
+
const compat = context.tools ? getAnthropicCompat(model) : void 0;
|
|
1089
|
+
const convertedTools = context.tools && compat ? convertTools(context.tools, isOAuthTokenResult, compat.supportsEagerToolInputStreaming, compat.supportsCacheControlOnTools ? cacheControl : void 0) : void 0;
|
|
1090
|
+
const tools = convertedTools?.tools;
|
|
1091
|
+
const toolProjection = convertedTools?.projection;
|
|
1092
|
+
const systemCacheControlCount = countNativeCacheControlMarkers(system);
|
|
1093
|
+
const toolCacheControlCount = countNativeCacheControlMarkers(tools);
|
|
1094
|
+
const messageCacheControlLimit = Math.max(0, ANTHROPIC_CACHE_CONTROL_LIMIT - systemCacheControlCount - toolCacheControlCount);
|
|
1095
|
+
const params = {
|
|
1096
|
+
model: model.id,
|
|
1097
|
+
messages: convertMessages(context.messages, model, isOAuthTokenResult, cacheControl, messageCacheControlLimit, replayThinkingEnabled),
|
|
1098
|
+
max_tokens: options?.maxTokens ?? model.maxTokens,
|
|
1099
|
+
stream: true
|
|
1100
|
+
};
|
|
1101
|
+
if (system) params.system = system;
|
|
1102
|
+
if (serverSideFallback) params.fallbacks = buildAnthropicServerSideFallbacks();
|
|
1103
|
+
if (options?.temperature !== void 0 && !options?.thinkingEnabled && !supportsNativeXhighEffort(model)) params.temperature = options.temperature;
|
|
1104
|
+
if (options?.stop !== void 0 && options.stop.length > 0) params.stop_sequences = options.stop;
|
|
1105
|
+
if (tools && tools.length > 0) params.tools = tools;
|
|
1106
|
+
if (mandatoryAdaptiveThinking || model.reasoning || supportsAdaptiveThinking(model)) {
|
|
1107
|
+
if (mandatoryAdaptiveThinking || options?.thinkingEnabled) {
|
|
1108
|
+
const display = options?.thinkingDisplay ?? "summarized";
|
|
1109
|
+
if (supportsAdaptiveThinking(model)) {
|
|
1110
|
+
params.thinking = {
|
|
1111
|
+
type: "adaptive",
|
|
1112
|
+
display
|
|
1113
|
+
};
|
|
1114
|
+
const effort = options?.effort ?? (mandatoryAdaptiveThinking ? "high" : void 0);
|
|
1115
|
+
if (effort) params.output_config = effort === "xhigh" ? { effort } : { effort };
|
|
1116
|
+
} else params.thinking = {
|
|
1117
|
+
type: "enabled",
|
|
1118
|
+
budget_tokens: options?.thinkingBudgetTokens ?? ANTHROPIC_MIN_THINKING_BUDGET_TOKENS,
|
|
1119
|
+
display
|
|
1120
|
+
};
|
|
1121
|
+
} else if (options?.thinkingEnabled === false) params.thinking = { type: "disabled" };
|
|
1122
|
+
}
|
|
1123
|
+
if (options?.metadata) {
|
|
1124
|
+
const userId = options.metadata.user_id;
|
|
1125
|
+
if (typeof userId === "string") params.metadata = { user_id: userId };
|
|
1126
|
+
}
|
|
1127
|
+
if (options?.toolChoice) {
|
|
1128
|
+
const normalizedToolChoice = normalizeAnthropicToolChoice(replayThinkingEnabled, options.toolChoice);
|
|
1129
|
+
const projectedToolChoice = toolProjection ? reconcileAnthropicToolChoice(normalizedToolChoice, toolProjection) : normalizedToolChoice;
|
|
1130
|
+
if (projectedToolChoice) params.tool_choice = projectedToolChoice;
|
|
1131
|
+
}
|
|
1132
|
+
return {
|
|
1133
|
+
params,
|
|
1134
|
+
toolProjection
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
function normalizeToolCallId(id) {
|
|
1138
|
+
return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
|
|
1139
|
+
}
|
|
1140
|
+
function convertMessages(messages, model, isOAuthTokenValue, cacheControl, messageCacheControlLimit = 4, replayThinkingEnabled = true) {
|
|
1141
|
+
const params = [];
|
|
1142
|
+
const cacheBreakpointOptOutParamIndexes = /* @__PURE__ */ new Set();
|
|
1143
|
+
const transformedMessages = transformMessages(messages, model, normalizeToolCallId);
|
|
1144
|
+
const activeToolTurnAssistantIndex = replayThinkingEnabled ? -1 : findActiveAnthropicToolTurnAssistantIndex(transformedMessages);
|
|
1145
|
+
for (let i = 0; i < transformedMessages.length; i++) {
|
|
1146
|
+
const msg = transformedMessages[i];
|
|
1147
|
+
if (msg.role === "user") {
|
|
1148
|
+
const isRuntimeContextCarrier = msg.runtimeContextCarrier === true;
|
|
1149
|
+
if (typeof msg.content === "string") {
|
|
1150
|
+
if (msg.content.trim().length > 0) {
|
|
1151
|
+
if (isRuntimeContextCarrier) cacheBreakpointOptOutParamIndexes.add(params.length);
|
|
1152
|
+
params.push({
|
|
1153
|
+
role: "user",
|
|
1154
|
+
content: sanitizeSurrogates(msg.content)
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
} else {
|
|
1158
|
+
const filteredBlocks = msg.content.map((item) => {
|
|
1159
|
+
if (item.type === "text") return {
|
|
1160
|
+
type: "text",
|
|
1161
|
+
text: sanitizeSurrogates(item.text)
|
|
1162
|
+
};
|
|
1163
|
+
return {
|
|
1164
|
+
type: "image",
|
|
1165
|
+
source: {
|
|
1166
|
+
type: "base64",
|
|
1167
|
+
media_type: item.mimeType,
|
|
1168
|
+
data: item.data
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
}).filter((b) => {
|
|
1172
|
+
if (b.type === "text") return b.text.trim().length > 0;
|
|
1173
|
+
return true;
|
|
1174
|
+
});
|
|
1175
|
+
if (filteredBlocks.length === 0) continue;
|
|
1176
|
+
if (isRuntimeContextCarrier) cacheBreakpointOptOutParamIndexes.add(params.length);
|
|
1177
|
+
params.push({
|
|
1178
|
+
role: "user",
|
|
1179
|
+
content: filteredBlocks
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
} else if (msg.role === "assistant") {
|
|
1183
|
+
const blocks = [];
|
|
1184
|
+
let omittedThinking = false;
|
|
1185
|
+
for (const block of msg.content) if (block.type === "text") {
|
|
1186
|
+
if (block.text.trim().length === 0) continue;
|
|
1187
|
+
blocks.push({
|
|
1188
|
+
type: "text",
|
|
1189
|
+
text: sanitizeSurrogates(block.text)
|
|
1190
|
+
});
|
|
1191
|
+
} else if (block.type === "thinking") {
|
|
1192
|
+
if (!replayThinkingEnabled && i !== activeToolTurnAssistantIndex) {
|
|
1193
|
+
omittedThinking = true;
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
if (block.redacted) {
|
|
1197
|
+
blocks.push({
|
|
1198
|
+
type: "redacted_thinking",
|
|
1199
|
+
data: block.thinkingSignature
|
|
1200
|
+
});
|
|
1201
|
+
continue;
|
|
1202
|
+
}
|
|
1203
|
+
const thinkingSignature = block.thinkingSignature?.trim();
|
|
1204
|
+
const hasNativeThinkingSignature = Boolean(thinkingSignature) && thinkingSignature !== "reasoning_content";
|
|
1205
|
+
if (block.thinking.trim().length === 0 && !hasNativeThinkingSignature) continue;
|
|
1206
|
+
if (!thinkingSignature) blocks.push({
|
|
1207
|
+
type: "text",
|
|
1208
|
+
text: sanitizeSurrogates(block.thinking)
|
|
1209
|
+
});
|
|
1210
|
+
else {
|
|
1211
|
+
if (thinkingSignature === "reasoning_content") continue;
|
|
1212
|
+
blocks.push({
|
|
1213
|
+
type: "thinking",
|
|
1214
|
+
thinking: block.thinking,
|
|
1215
|
+
signature: thinkingSignature
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
} else if (block.type === "toolCall") blocks.push({
|
|
1219
|
+
type: "tool_use",
|
|
1220
|
+
id: block.id,
|
|
1221
|
+
name: isOAuthTokenValue ? toClaudeCodeName(block.name) : block.name,
|
|
1222
|
+
input: block.arguments ?? {}
|
|
1223
|
+
});
|
|
1224
|
+
if (blocks.length === 0 && omittedThinking) blocks.push({
|
|
1225
|
+
type: "text",
|
|
1226
|
+
text: ANTHROPIC_OMITTED_REASONING_TEXT
|
|
1227
|
+
});
|
|
1228
|
+
if (blocks.length === 0) continue;
|
|
1229
|
+
params.push({
|
|
1230
|
+
role: "assistant",
|
|
1231
|
+
content: blocks
|
|
1232
|
+
});
|
|
1233
|
+
} else if (msg.role === "toolResult") {
|
|
1234
|
+
const toolResults = [];
|
|
1235
|
+
toolResults.push({
|
|
1236
|
+
type: "tool_result",
|
|
1237
|
+
tool_use_id: msg.toolCallId,
|
|
1238
|
+
content: convertContentBlocks(msg.content, msg.isError),
|
|
1239
|
+
is_error: msg.isError
|
|
1240
|
+
});
|
|
1241
|
+
let j = i + 1;
|
|
1242
|
+
while (j < transformedMessages.length && transformedMessages[j].role === "toolResult") {
|
|
1243
|
+
const nextMsg = transformedMessages[j];
|
|
1244
|
+
toolResults.push({
|
|
1245
|
+
type: "tool_result",
|
|
1246
|
+
tool_use_id: nextMsg.toolCallId,
|
|
1247
|
+
content: convertContentBlocks(nextMsg.content, nextMsg.isError),
|
|
1248
|
+
is_error: nextMsg.isError
|
|
1249
|
+
});
|
|
1250
|
+
j++;
|
|
1251
|
+
}
|
|
1252
|
+
i = j - 1;
|
|
1253
|
+
params.push({
|
|
1254
|
+
role: "user",
|
|
1255
|
+
content: toolResults
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
if (cacheControl && params.length > 0 && messageCacheControlLimit > 0) {
|
|
1260
|
+
let fallbackToolResult;
|
|
1261
|
+
for (let i = params.length - 1; i >= 0; i--) {
|
|
1262
|
+
const message = params[i];
|
|
1263
|
+
if (message.role !== "user" || cacheBreakpointOptOutParamIndexes.has(i)) continue;
|
|
1264
|
+
if (Array.isArray(message.content)) {
|
|
1265
|
+
for (let j = message.content.length - 1; j >= 0; j--) {
|
|
1266
|
+
const block = message.content[j];
|
|
1267
|
+
if (block.type === "text" || block.type === "image") {
|
|
1268
|
+
if (fallbackToolResult && messageCacheControlLimit === 1) {
|
|
1269
|
+
applyContentBlockCacheControl(fallbackToolResult, cacheControl);
|
|
1270
|
+
return params;
|
|
1271
|
+
}
|
|
1272
|
+
applyContentBlockCacheControl(block, cacheControl);
|
|
1273
|
+
if (fallbackToolResult && messageCacheControlLimit > 1) applyContentBlockCacheControl(fallbackToolResult, cacheControl);
|
|
1274
|
+
return params;
|
|
1275
|
+
}
|
|
1276
|
+
if (block.type === "tool_result" && fallbackToolResult === void 0) fallbackToolResult = block;
|
|
1277
|
+
}
|
|
1278
|
+
continue;
|
|
1279
|
+
}
|
|
1280
|
+
if (typeof message.content === "string") {
|
|
1281
|
+
if (fallbackToolResult && messageCacheControlLimit === 1) {
|
|
1282
|
+
applyContentBlockCacheControl(fallbackToolResult, cacheControl);
|
|
1283
|
+
return params;
|
|
1284
|
+
}
|
|
1285
|
+
message.content = [{
|
|
1286
|
+
type: "text",
|
|
1287
|
+
text: message.content,
|
|
1288
|
+
cache_control: cacheControl
|
|
1289
|
+
}];
|
|
1290
|
+
if (fallbackToolResult && messageCacheControlLimit > 1) applyContentBlockCacheControl(fallbackToolResult, cacheControl);
|
|
1291
|
+
return params;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
if (fallbackToolResult) applyContentBlockCacheControl(fallbackToolResult, cacheControl);
|
|
1295
|
+
}
|
|
1296
|
+
return params;
|
|
1297
|
+
}
|
|
1298
|
+
function applyContentBlockCacheControl(block, cacheControl) {
|
|
1299
|
+
block.cache_control = cacheControl;
|
|
1300
|
+
}
|
|
1301
|
+
function buildAnthropicSystemBlocks(systemPrompt, isOAuthTokenResult, cacheControl) {
|
|
1302
|
+
const blocks = [];
|
|
1303
|
+
if (isOAuthTokenResult) {
|
|
1304
|
+
blocks.push({
|
|
1305
|
+
type: "text",
|
|
1306
|
+
text: claudeCodeBillingSystemBlock
|
|
1307
|
+
});
|
|
1308
|
+
blocks.push({
|
|
1309
|
+
type: "text",
|
|
1310
|
+
text: "You are Claude Code, Anthropic's official CLI for Claude.",
|
|
1311
|
+
...cacheControl ? { cache_control: cacheControl } : {}
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
if (systemPrompt) blocks.push(...buildSystemPromptBlocks(systemPrompt, cacheControl));
|
|
1315
|
+
return blocks.length > 0 ? blocks : void 0;
|
|
1316
|
+
}
|
|
1317
|
+
function buildSystemPromptBlocks(systemPrompt, cacheControl) {
|
|
1318
|
+
if (!cacheControl) return [{
|
|
1319
|
+
type: "text",
|
|
1320
|
+
text: sanitizeSurrogates(stripSystemPromptCacheBoundary(systemPrompt))
|
|
1321
|
+
}];
|
|
1322
|
+
const split = splitSystemPromptCacheBoundary(systemPrompt);
|
|
1323
|
+
if (!split) return [{
|
|
1324
|
+
type: "text",
|
|
1325
|
+
text: sanitizeSurrogates(systemPrompt),
|
|
1326
|
+
cache_control: cacheControl
|
|
1327
|
+
}];
|
|
1328
|
+
const blocks = [];
|
|
1329
|
+
if (split.stablePrefix) blocks.push({
|
|
1330
|
+
type: "text",
|
|
1331
|
+
text: sanitizeSurrogates(split.stablePrefix),
|
|
1332
|
+
cache_control: cacheControl
|
|
1333
|
+
});
|
|
1334
|
+
if (split.dynamicSuffix) blocks.push({
|
|
1335
|
+
type: "text",
|
|
1336
|
+
text: sanitizeSurrogates(split.dynamicSuffix)
|
|
1337
|
+
});
|
|
1338
|
+
return blocks.length > 0 ? blocks : [{
|
|
1339
|
+
type: "text",
|
|
1340
|
+
text: ""
|
|
1341
|
+
}];
|
|
1342
|
+
}
|
|
1343
|
+
function countNativeCacheControlMarkers(blocks) {
|
|
1344
|
+
if (!Array.isArray(blocks)) return 0;
|
|
1345
|
+
let count = 0;
|
|
1346
|
+
for (const block of blocks) if (block && typeof block === "object" && "cache_control" in block) count += 1;
|
|
1347
|
+
return count;
|
|
1348
|
+
}
|
|
1349
|
+
function shouldUseFineGrainedToolStreamingBeta(model, context) {
|
|
1350
|
+
return Boolean(context.tools?.length) && !getAnthropicCompat(model).supportsEagerToolInputStreaming;
|
|
1351
|
+
}
|
|
1352
|
+
function convertTools(tools, isOAuthTokenLocal, supportsEagerToolInputStreaming, cacheControl) {
|
|
1353
|
+
const projection = projectAnthropicTools(tools, (name) => isOAuthTokenLocal ? toClaudeCodeName(name) : name);
|
|
1354
|
+
const convertedTools = [];
|
|
1355
|
+
for (const [index, tool] of projection.tools.entries()) {
|
|
1356
|
+
const convertedTool = {
|
|
1357
|
+
name: tool.wireName,
|
|
1358
|
+
description: tool.description,
|
|
1359
|
+
input_schema: tool.inputSchema
|
|
1360
|
+
};
|
|
1361
|
+
if (supportsEagerToolInputStreaming) convertedTool.eager_input_streaming = true;
|
|
1362
|
+
if (cacheControl && index === projection.tools.length - 1) convertedTool.cache_control = cacheControl;
|
|
1363
|
+
convertedTools.push(convertedTool);
|
|
1364
|
+
}
|
|
1365
|
+
return {
|
|
1366
|
+
projection,
|
|
1367
|
+
tools: convertedTools
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
function mapStopReason(reason) {
|
|
1371
|
+
switch (reason) {
|
|
1372
|
+
case "end_turn": return "stop";
|
|
1373
|
+
case "max_tokens": return "length";
|
|
1374
|
+
case "tool_use": return "toolUse";
|
|
1375
|
+
case "refusal": return "error";
|
|
1376
|
+
case "pause_turn": return "stop";
|
|
1377
|
+
case "stop_sequence": return "stop";
|
|
1378
|
+
case "sensitive": return "error";
|
|
1379
|
+
default: throw new Error(`Unhandled stop reason: ${reason}`);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
//#endregion
|
|
1383
|
+
export { readAnthropicFallbackBoundary as _, readAnthropicUsageTokenCount as a, usesFoundryBearerAuth as b, reconcileAnthropicToolChoice as c, findActiveAnthropicToolTurnAssistantIndex as d, ANTHROPIC_SERVER_SIDE_FALLBACK_BETA as f, buildAnthropicServerSideFallbacks as g, applyAnthropicFallbackBoundary as h, readAnthropicPromptUsageSnapshot as i, resolveOriginalAnthropicToolName as l, CLAUDE_FABLE_5_FALLBACK_MODEL_COST as m, streamAnthropic as n, readLastAnthropicIterationUsage as o, CLAUDE_FABLE_5_FALLBACK_MODEL as p, streamSimpleAnthropic as r, projectAnthropicTools as s, anthropic_exports as t, ANTHROPIC_OMITTED_REASONING_TEXT as u, applyAnthropicRefusal as v, omitFoundryBearerCredentialHeaders as y };
|