@xiaoso/dsh-tool-plus 0.1.5 → 0.1.7-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/THIRD_PARTY_NOTICES.md +9 -3
- package/lib/{abort-Cwwm4Err.mjs → abort-Caqff3M6.mjs} +2 -2
- package/lib/alibaba-coding-plan-DTupMiAi.mjs +73 -0
- package/lib/alibaba-token-plan-CHGyWOfX.mjs +46 -0
- package/lib/alibaba-token-plan-Dj3OZhEE.mjs +82 -0
- package/lib/{amazon-bedrock-TVMpUTRG.mjs → amazon-bedrock-DbFSYXfJ.mjs} +117 -38
- package/lib/{anthropic-BL6LFDQS.mjs → anthropic-CTJ3IQVa.mjs} +675 -166
- package/lib/anthropic-CXfWlp-x.mjs +105 -0
- package/lib/{aws-credentials-B20dliS7.mjs → anthropic-wire-CKuhDwZ1.mjs} +74 -14
- package/lib/{api-key-login-CIDnXeYd.mjs → api-key-validation-CGCJFbFr.mjs} +27 -68
- package/lib/{azure-openai-responses-BkhsLmN3.mjs → azure-openai-responses-ChFbWaGj.mjs} +27 -16
- package/lib/{browser-render-CmgvSNte.mjs → browser-render-9o0Rknop.mjs} +4 -4
- package/lib/bun-shim.mjs +71 -2
- package/lib/{bundled-references-ChZSPDFw.mjs → bundled-references-DY3EJxZV.mjs} +6 -5
- package/lib/cline-pass-Bwg3esu9.mjs +44 -0
- package/lib/cloudflare-ai-gateway-BupNXyKK.mjs +35 -0
- package/lib/cloudflare-ai-gateway-EWo0VkP5.mjs +44 -0
- package/lib/collapse-DOR8sOGf.mjs +2304 -0
- package/lib/coreweave-C82HrLpb.mjs +31 -0
- package/lib/coreweave-Ct8cF-da.mjs +14 -0
- package/lib/{cursor-B6HcmplF.mjs → cursor-B95LzVWV.mjs} +11 -3
- package/lib/{cursor-CRpLpaZ3.mjs → cursor-DJV_dcgB.mjs} +887 -1784
- package/lib/{cursor-B8m6SqAH.mjs → cursor-LKGjucn2.mjs} +48 -38
- package/lib/cursor-proto-B8Wj8bv9.mjs +10513 -0
- package/lib/{deterministic-id-D-yIV_eI.mjs → deterministic-id-CUEIMSqR.mjs} +1 -1
- package/lib/devin-BMTdx_hx.mjs +316 -0
- package/lib/{devin-DUAfvBsW.mjs → devin-DSp0Rw_E.mjs} +172 -86
- package/lib/devin-ExGIghmx.mjs +69 -0
- package/lib/devin-proto-Br8fdyNl.mjs +2888 -0
- package/lib/{dom-CawWi8fa.mjs → dom-DG3sPESc.mjs} +8 -8
- package/lib/effort-BdtQMN-_.mjs +23 -0
- package/lib/{error-C-f_Wnw4.mjs → error-CORgGg5a.mjs} +275 -154
- package/lib/{event-stream-Dh2guZxS.mjs → event-stream-ulcDenZD.mjs} +20 -4
- package/lib/{gemini-headers-DKUShltF.mjs → gemini-headers-Co9cVvex.mjs} +2 -2
- package/lib/{github-copilot-suDymKrx.mjs → github-copilot-Dstq1D3s.mjs} +69 -29
- package/lib/github-copilot-headers-DOh1gt_w.mjs +312 -0
- package/lib/gitlab-duo-DSCMrU0m.mjs +11 -0
- package/lib/google-CtsKkOQK.mjs +38 -0
- package/lib/google-antigravity-z-5KsEci.mjs +252 -0
- package/lib/{google-auth-DYJLM792.mjs → google-auth-ieLBaneO.mjs} +4 -4
- package/lib/{google-gemini-cli-8BT513Ul.mjs → google-gemini-cli-C6NE5mWz.mjs} +28 -54
- package/lib/{google-gemini-cli-D6cSmfvB.mjs → google-gemini-cli-CAIPSl7e.mjs} +23 -29
- package/lib/google-oauth-shared-DhMllAkt.mjs +53 -0
- package/lib/{google-shared-CVbHK5vZ.mjs → google-shared-B0aNCYEH.mjs} +140 -44
- package/lib/{google-validation-Cgbn3tWJ.mjs → google-validation-BEkNs-Bx.mjs} +1 -1
- package/lib/{google-vertex-Bui-ypAe.mjs → google-vertex-Bbd1tYNc.mjs} +8 -8
- package/lib/hosts-00rjRzUD.mjs +203 -0
- package/lib/id-AL5obQzR.mjs +71 -0
- package/lib/{idle-iterator-CYAxUkSD.mjs → idle-iterator-DlUkEfzW.mjs} +3 -3
- package/lib/index.mjs +587 -5266
- package/lib/kilo-ChJL54wq.mjs +81 -0
- package/lib/kimi-C2c_Zq8A.mjs +67 -0
- package/lib/{launch-BmgEUycu.mjs → launch-DKDH71En.mjs} +1 -1
- package/lib/markit-CmRfm4E2.mjs +9885 -0
- package/lib/models-DnXMYGcJ.mjs +381604 -0
- package/lib/muse-code-Di1VZmB1.mjs +143 -0
- package/lib/{ollama-Df9ce-Cp.mjs → ollama-B8ic3sEp.mjs} +15 -30
- package/lib/{openai-codex-CAVI3Me-.mjs → openai-codex-DuJNC99x.mjs} +29 -99
- package/lib/{openai-codex-responses-BcnOotRB.mjs → openai-codex-responses-BL29nh9K.mjs} +204 -116
- package/lib/{openai-completions-Bq4WT47M.mjs → openai-completions-BK2f2dBv.mjs} +152 -82
- package/lib/openai-configuration-update-xMYUjaK_.mjs +150 -0
- package/lib/{openai-reasoning-fallback-DXsfiSXO.mjs → openai-reasoning-fallback-BdB3RCbj.mjs} +106 -12
- package/lib/{openai-responses-Mq_-PjvE.mjs → openai-responses-CGQPlIIy.mjs} +76 -82
- package/lib/{perplexity-XgLF73E7.mjs → perplexity-TBjz3VMB.mjs} +52 -9
- package/lib/{pkce-BlQikGPu.mjs → pkce-BYjmugmw.mjs} +1 -1
- package/lib/protobuf-aab1UGVn.mjs +717 -0
- package/lib/{provider-response-C6vcbQyO.mjs → provider-response-SqKSkkUc.mjs} +1 -1
- package/lib/{proxy-D9lm7ONA.mjs → proxy-5nWqRL1f.mjs} +45 -5
- package/lib/{readability-Cpm-ocau.mjs → readability-uGhqb4GC.mjs} +2 -2
- package/lib/reference-CtvM4zLU.mjs +114 -0
- package/lib/{request-debug-HJMoJncL.mjs → request-debug-NQN0BjHH.mjs} +1 -1
- package/lib/{sanitize-text-CfcXzw5X.mjs → sanitize-text-BCf5KmCf.mjs} +1 -1
- package/lib/{scrapers-CE_qK1yk.mjs → scrapers-D8oWspgW.mjs} +12 -12
- package/lib/{src-BcD0_rQR.mjs → src-BwW51vA5.mjs} +979 -388
- package/lib/{sse-debug-CYdjOC96.mjs → sse-debug-B-tkLCPW.mjs} +1 -1
- package/lib/{stream-Bjq8wjfr.mjs → stream-B_7qN-bA.mjs} +3802 -2623
- package/lib/stream-markup-healing-DKT1lnkW.mjs +267 -0
- package/lib/{strict-tool-validation-imVLUcbI.mjs → strict-tool-validation-CBTz1dAA.mjs} +2 -2
- package/lib/taxonomy-DSIM99rS.mjs +15392 -0
- package/lib/{stream-markup-healing-DZ6bVDxH.mjs → thinking-CiLa2LFB.mjs} +31 -186
- package/lib/{turndown-DN7ByzEI.mjs → turndown-DrX1M4WG.mjs} +4 -4
- package/lib/{type-guards-B9VVjRDK.mjs → type-guards-CttAANEx.mjs} +1 -1
- package/lib/{types-DX_bvuus.mjs → types-PVueGi9S.mjs} +2 -2
- package/lib/{utils-APrc-TBB.mjs → utils-CCfhUQen.mjs} +2364 -2676
- package/lib/{utils-Cp2Mxf_U.mjs → utils-CUPhpw9A.mjs} +413 -134
- package/lib/{utils-CQHPEQ3W.mjs → utils-DeWqNWV8.mjs} +2 -2
- package/lib/{vision-guard-mBmtAHx0.mjs → vision-guard-_XwsL1DF.mjs} +14 -29
- package/lib/xai-oauth-CXhnz0gO.mjs +210 -0
- package/lib/{xiaomi-7mE345KX.mjs → xiaomi-psoUItal.mjs} +8 -37
- package/lib/{zai-CeNpMV3W.mjs → zai-ApJ8HBgT.mjs} +8 -71
- package/lib/{zip-BK7UHCwX.mjs → zip-Kd602XNe.mjs} +1 -1
- package/package.json +43 -41
- package/presets/package.json +1 -1
- package/presets/tool-plus-ptc/agent.cordis.yml +13 -4
- package/presets/tool-plus-standard/agent.cordis.yml +11 -3
- package/lib/agent_pb-Rizyt9Zg.mjs +0 -805
- package/lib/anthropic-CDmj476p.mjs +0 -262
- package/lib/api_server_pb-CDZgLMta.mjs +0 -252
- package/lib/callback-server-CFJK-jvK.mjs +0 -398
- package/lib/codex-P1dGpX7G.mjs +0 -54
- package/lib/device-code-CuXTWYwY.mjs +0 -51
- package/lib/devin-BcQwht1W.mjs +0 -114
- package/lib/devin-BvMfGevz.mjs +0 -95
- package/lib/github-copilot-B3kQl0g0.mjs +0 -104
- package/lib/gitlab-duo-BriUTP8k.mjs +0 -155
- package/lib/gitlab-duo-workflow-wK5Ljzmc.mjs +0 -91
- package/lib/google-CE5tFDod.mjs +0 -30
- package/lib/google-antigravity-C1jgNljz.mjs +0 -198
- package/lib/google-oauth-shared-BLVTvokk.mjs +0 -147
- package/lib/grammar-D-NqNUxQ.mjs +0 -49
- package/lib/identity-HNO1Oe9B.mjs +0 -219
- package/lib/kimi-DgcUpPtK.mjs +0 -236
- package/lib/markit-DtGoRE6M.mjs +0 -1417
- package/lib/minimax-code-Y3h5li9N.mjs +0 -53
- package/lib/models-DRA2c_8U.mjs +0 -104660
- package/lib/opencode-BsVw9rCD.mjs +0 -38
- package/lib/to-binary-B1BEBIPC.mjs +0 -6002
- package/lib/wafer-BlhWLweO.mjs +0 -17
- package/lib/xai-oauth-5pORHUrg.mjs +0 -446
|
@@ -1,34 +1,29 @@
|
|
|
1
1
|
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
2
|
__installBunShim();
|
|
3
3
|
import { r as __exportAll } from "./fs-promises-shim-Bx0fpxuk.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { A as isTransientStreamParseError, D as isFastModeUnsupported,
|
|
6
|
-
import { A as
|
|
7
|
-
import { n as isRecord } from "./type-guards-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { t as
|
|
14
|
-
import { t as
|
|
15
|
-
import {
|
|
16
|
-
import { a as
|
|
17
|
-
import { t as
|
|
18
|
-
import {
|
|
4
|
+
import { $ as isEnoent, C as warn, N as $env, a as readSseEvents, b as debug, g as parseJsonWithRepair, q as getInstallId, v as parseStreamingJsonThrottled } from "./src-BwW51vA5.mjs";
|
|
5
|
+
import { A as isTransientStreamParseError, D as isFastModeUnsupported, F as AnthropicStreamEnvelopeError, M as AnthropicApiError, N as AnthropicConnectionError, O as isGrammarError, P as AnthropicConnectionTimeoutError, _ as AbortError, a as isTransientStatus, c as finalize, d as getRetryAfterMsFromHeaders, i as isProviderRetryableError, k as isStreamEnvelopeError, l as finalizeErrorMessage, n as StreamTimeoutError, r as ValidationError, s as ProviderResponseError, t as ConfigurationError, u as getHeadersFromError } from "./error-CORgGg5a.mjs";
|
|
6
|
+
import { A as toolWireSchema, B as spillToDescription, C as kStreamingLastParseLen, T as renderDemotedThinking, V as COMBINATOR_KEYS, b as kStreamingBlockIndex, c as resolveCacheRetention, g as clearStreamingPartialJson, h as transformMessages, j as NO_STRICT, n as getHeaderCaseInsensitive, o as normalizeSystemPrompts, s as normalizeToolCallId, w as kStreamingPartialJson } from "./utils-CUPhpw9A.mjs";
|
|
7
|
+
import { n as isRecord } from "./type-guards-CttAANEx.mjs";
|
|
8
|
+
import { At as withReplaySafeStreamRetry, Ct as applyInferenceHeaders, et as getOpenAIPromptCacheKey, f as isFoundryEnabled, n as getEnvApiKey, t as OUTPUT_FALLBACK_BUFFER, wt as isForcedToolChoice } from "./stream-B_7qN-bA.mjs";
|
|
9
|
+
import { r as isAnthropicOAuthToken } from "./utils-DeWqNWV8.mjs";
|
|
10
|
+
import { a as mapEffortToAnthropicAdaptiveEffort, n as isAnthropicServerToolHistoryBlock, r as parseAnthropicInputTransformations, t as THINKING_BINDING_CONTROLS_BETA } from "./anthropic-wire-CKuhDwZ1.mjs";
|
|
11
|
+
import { t as createAbortSourceTracker } from "./abort-Caqff3M6.mjs";
|
|
12
|
+
import { n as getBundledModel, t as calculateCost } from "./models-DnXMYGcJ.mjs";
|
|
13
|
+
import { a as resolveGitHubCopilotBaseUrl, b as parseGitHubCopilotApiKey, i as resolveCopilotRequestIdentity, n as hasCopilotVisionInput, o as wrapFetchForCopilotFallback, t as buildCopilotDynamicHeaders } from "./github-copilot-headers-DOh1gt_w.mjs";
|
|
14
|
+
import { t as NON_VISION_IMAGE_PLACEHOLDER } from "./vision-guard-_XwsL1DF.mjs";
|
|
15
|
+
import { t as AssistantMessageEventStream } from "./event-stream-ulcDenZD.mjs";
|
|
16
|
+
import { a as claudeCodeUserAgent, i as claudeCodeSystemInstruction, n as CLAUDE_CODE_MAX_OUTPUT_TOKENS, o as claudeCodeVersion, r as claudeCodeSdkVersion } from "./anthropic-CXfWlp-x.mjs";
|
|
17
|
+
import { n as isVertexRawPredictUrl, t as hostMatchesUrl } from "./hosts-00rjRzUD.mjs";
|
|
18
|
+
import { a as isOfficialAnthropicApiUrl, i as isAnthropicSigningProxyUrl } from "./collapse-DOR8sOGf.mjs";
|
|
19
|
+
import { a as getStreamIdleTimeoutMs, i as getStreamFirstEventTimeoutMs, o as iterateWithIdleTimeout } from "./idle-iterator-DlUkEfzW.mjs";
|
|
20
|
+
import { t as notifyProviderResponse } from "./provider-response-SqKSkkUc.mjs";
|
|
21
|
+
import { t as notifyRawSseEvent } from "./sse-debug-B-tkLCPW.mjs";
|
|
19
22
|
import * as fs from "node:fs";
|
|
20
23
|
import { scheduler } from "node:timers/promises";
|
|
21
24
|
import * as nodeCrypto from "node:crypto";
|
|
22
25
|
import * as tls from "node:tls";
|
|
23
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@
|
|
24
|
-
/** True when a block is complete Anthropic server-tool history omp can replay. */
|
|
25
|
-
function isAnthropicServerToolHistoryBlock(block) {
|
|
26
|
-
if (block.type === "server_tool_use") return (block.name === "web_search" || block.name === "tool_search_tool_regex" || block.name === "tool_search_tool_bm25") && typeof block.id === "string" && block.id.length > 0;
|
|
27
|
-
if (block.type === "web_search_tool_result" || block.type === "tool_search_tool_result") return typeof block.tool_use_id === "string" && block.tool_use_id.length > 0 && Object.hasOwn(block, "content");
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
//#endregion
|
|
31
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/utils/sdk-stream-timeout.ts
|
|
26
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.1.17/node_modules/@oh-my-pi/pi-ai/src/utils/sdk-stream-timeout.ts
|
|
32
27
|
/**
|
|
33
28
|
* Shared helpers for mapping `StreamOptions.streamFirstEventTimeoutMs` onto
|
|
34
29
|
* underlying SDK request-timeout options.
|
|
@@ -72,7 +67,7 @@ function createSdkStreamRequestOptions(signal, streamFirstEventTimeoutMs) {
|
|
|
72
67
|
};
|
|
73
68
|
}
|
|
74
69
|
//#endregion
|
|
75
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@
|
|
70
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.1.17/node_modules/@oh-my-pi/pi-ai/src/providers/anthropic-client.ts
|
|
76
71
|
/**
|
|
77
72
|
* Minimal HTTP client for the Anthropic Messages API.
|
|
78
73
|
*
|
|
@@ -236,7 +231,7 @@ var AnthropicMessagesClient = class {
|
|
|
236
231
|
callerSignal?.addEventListener("abort", onAbort, { once: true });
|
|
237
232
|
try {
|
|
238
233
|
return await fetchFn(url, {
|
|
239
|
-
...this.#options.fetchOptions
|
|
234
|
+
...this.#options.fetchOptions,
|
|
240
235
|
method: "POST",
|
|
241
236
|
headers,
|
|
242
237
|
body,
|
|
@@ -260,7 +255,7 @@ var AnthropicMessagesClient = class {
|
|
|
260
255
|
}
|
|
261
256
|
};
|
|
262
257
|
//#endregion
|
|
263
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@
|
|
258
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.1.17/node_modules/@oh-my-pi/pi-ai/src/providers/anthropic.ts
|
|
264
259
|
var anthropic_exports = /* @__PURE__ */ __exportAll({
|
|
265
260
|
CLAUDE_CODE_MAX_OUTPUT_TOKENS: () => CLAUDE_CODE_MAX_OUTPUT_TOKENS,
|
|
266
261
|
applyAnthropicUsageExtras: () => applyAnthropicUsageExtras,
|
|
@@ -269,17 +264,19 @@ var anthropic_exports = /* @__PURE__ */ __exportAll({
|
|
|
269
264
|
buildAnthropicHeaders: () => buildAnthropicHeaders,
|
|
270
265
|
buildAnthropicSystemBlocks: () => buildAnthropicSystemBlocks,
|
|
271
266
|
buildBetaHeader: () => buildBetaHeader,
|
|
267
|
+
claudeCodeHeaders: () => claudeCodeHeaders,
|
|
268
|
+
claudeCodeSdkVersion: () => claudeCodeSdkVersion,
|
|
272
269
|
claudeCodeSystemInstruction: () => claudeCodeSystemInstruction,
|
|
270
|
+
claudeCodeUserAgent: () => claudeCodeUserAgent,
|
|
273
271
|
claudeCodeVersion: () => claudeCodeVersion,
|
|
274
272
|
claudeToolPrefix: () => "_",
|
|
275
273
|
convertAnthropicMessages: () => convertAnthropicMessages,
|
|
276
|
-
coworkHeaders: () => coworkHeaders,
|
|
277
|
-
coworkUserAgent: () => coworkUserAgent,
|
|
278
274
|
deriveClaudeDeviceId: () => deriveClaudeDeviceId,
|
|
279
275
|
isClaudeCloakingUserId: () => isClaudeCloakingUserId,
|
|
280
276
|
isInvalidThinkingSignatureError: () => isInvalidThinkingSignatureError,
|
|
281
|
-
|
|
277
|
+
isThinkingPrefixBindingError: () => isThinkingPrefixBindingError,
|
|
282
278
|
mapStainlessArch: () => mapStainlessArch,
|
|
279
|
+
mapStainlessOs: () => mapStainlessOs,
|
|
283
280
|
maybeAddReplayUnsignedThinkingHint: () => maybeAddReplayUnsignedThinkingHint,
|
|
284
281
|
normalizeAnthropicBaseUrl: () => normalizeAnthropicBaseUrl,
|
|
285
282
|
normalizeAnthropicToolSchema: () => normalizeAnthropicToolSchema,
|
|
@@ -319,26 +316,31 @@ function mergeAnthropicBetaHeader(callerHeaders, beta) {
|
|
|
319
316
|
for (const key in callerHeaders) if (key.toLowerCase() === "anthropic-beta") return { [key]: buildBetaHeader(normalizeExtraBetas(callerHeaders[key]), [beta]) };
|
|
320
317
|
return { "anthropic-beta": beta };
|
|
321
318
|
}
|
|
319
|
+
const oauthAuthBeta = "oauth-2025-04-20";
|
|
322
320
|
const midConversationSystemBeta = "mid-conversation-system-2026-04-07";
|
|
321
|
+
const midConversationSystemClearAtBeta = "mid-conversation-system-clear-at-2026-08-21";
|
|
322
|
+
const midConversationToolChangesBeta = "mid-conversation-tool-changes-2026-07-01";
|
|
323
|
+
const midConversationOutputConfigBeta = "mid-conversation-output-config-2026-07-01";
|
|
323
324
|
const contextManagementBeta = "context-management-2025-06-27";
|
|
324
325
|
const structuredOutputsBeta = "structured-outputs-2025-12-15";
|
|
325
326
|
const thinkingTokenCountBeta = "thinking-token-count-2026-05-13";
|
|
326
327
|
const fallbackCreditBeta = "fallback-credit-2026-06-01";
|
|
327
|
-
const
|
|
328
|
+
const claudeCodeUtilityBetaDefaults = [
|
|
329
|
+
oauthAuthBeta,
|
|
328
330
|
"interleaved-thinking-2025-05-14",
|
|
329
331
|
thinkingTokenCountBeta,
|
|
330
332
|
contextManagementBeta,
|
|
331
333
|
"prompt-caching-scope-2026-01-05",
|
|
332
334
|
structuredOutputsBeta
|
|
333
335
|
];
|
|
334
|
-
const
|
|
336
|
+
const claudeCodeAgentBetaDefaults = [
|
|
335
337
|
"claude-code-20250219",
|
|
338
|
+
oauthAuthBeta,
|
|
336
339
|
"interleaved-thinking-2025-05-14",
|
|
337
340
|
thinkingTokenCountBeta,
|
|
338
341
|
contextManagementBeta,
|
|
339
342
|
"prompt-caching-scope-2026-01-05",
|
|
340
|
-
midConversationSystemBeta
|
|
341
|
-
"advanced-tool-use-2025-11-20"
|
|
343
|
+
midConversationSystemBeta
|
|
342
344
|
];
|
|
343
345
|
const extendedCacheTtlBeta = "extended-cache-ttl-2025-04-11";
|
|
344
346
|
const fineGrainedToolStreamingBeta = "fine-grained-tool-streaming-2025-05-14";
|
|
@@ -347,11 +349,20 @@ const fastModeBeta = "fast-mode-2026-02-01";
|
|
|
347
349
|
const taskBudgetBeta = "task-budgets-2026-03-13";
|
|
348
350
|
const effortBeta = "effort-2025-11-24";
|
|
349
351
|
const serverSideFallbackBeta = "server-side-fallback-2026-06-01";
|
|
350
|
-
function
|
|
351
|
-
|
|
352
|
+
function resolveAnthropicControlBetas(model, prefixMismatchBehavior) {
|
|
353
|
+
const betas = [];
|
|
354
|
+
if (prefixMismatchBehavior) betas.push(THINKING_BINDING_CONTROLS_BETA);
|
|
355
|
+
if (model.compat.supportsTurnScopedSystem) betas.push(midConversationSystemClearAtBeta);
|
|
356
|
+
if (model.compat.supportsMidConversationToolChanges) betas.push(midConversationToolChangesBeta);
|
|
357
|
+
if (model.compat.supportsPerMessageEffort) betas.push(midConversationOutputConfigBeta);
|
|
358
|
+
return betas;
|
|
359
|
+
}
|
|
360
|
+
function buildClaudeCodeBetas({ agentRequest, thinkingRequest, disableStrictTools = false, supportsContextManagement = true }) {
|
|
361
|
+
if (!agentRequest && !disableStrictTools && supportsContextManagement) return claudeCodeUtilityBetaDefaults;
|
|
352
362
|
const betas = [];
|
|
353
|
-
for (const beta of agentRequest ?
|
|
363
|
+
for (const beta of agentRequest ? claudeCodeAgentBetaDefaults : claudeCodeUtilityBetaDefaults) {
|
|
354
364
|
if (disableStrictTools && beta === structuredOutputsBeta) continue;
|
|
365
|
+
if (!supportsContextManagement && beta === contextManagementBeta) continue;
|
|
355
366
|
betas.push(beta);
|
|
356
367
|
}
|
|
357
368
|
if (!agentRequest) return betas;
|
|
@@ -359,11 +370,6 @@ function buildCoworkBetas(agentRequest, thinkingRequest, disableStrictTools = fa
|
|
|
359
370
|
betas.push(fallbackCreditBeta);
|
|
360
371
|
return betas;
|
|
361
372
|
}
|
|
362
|
-
function getHeaderCaseInsensitive(headers, headerName) {
|
|
363
|
-
if (!headers) return void 0;
|
|
364
|
-
const normalizedName = headerName.toLowerCase();
|
|
365
|
-
for (const [key, value] of Object.entries(headers)) if (key.toLowerCase() === normalizedName) return value;
|
|
366
|
-
}
|
|
367
373
|
function isClaudeCodeClientUserAgent(userAgent) {
|
|
368
374
|
if (!userAgent) return false;
|
|
369
375
|
return userAgent.toLowerCase().startsWith("claude-cli");
|
|
@@ -383,7 +389,10 @@ function buildAnthropicHeaders(options) {
|
|
|
383
389
|
const incomingUserAgent = getHeaderCaseInsensitive(options.modelHeaders, "User-Agent");
|
|
384
390
|
const incomingAuthorization = getHeaderCaseInsensitive(options.modelHeaders, "Authorization");
|
|
385
391
|
const incomingApiKey = getHeaderCaseInsensitive(options.modelHeaders, "X-Api-Key");
|
|
386
|
-
const betaHeader = buildBetaHeader(options.
|
|
392
|
+
const betaHeader = buildBetaHeader(options.claudeCodeBetas ?? (oauthToken ? buildClaudeCodeBetas({
|
|
393
|
+
agentRequest: true,
|
|
394
|
+
thinkingRequest: true
|
|
395
|
+
}) : []), extraBetas);
|
|
387
396
|
const acceptHeader = oauthToken ? "application/json" : stream ? "text/event-stream" : "application/json";
|
|
388
397
|
const isCloudflare = options.isCloudflareAiGateway ?? false;
|
|
389
398
|
const honorAuthorization = !oauthToken && !isCloudflare;
|
|
@@ -419,20 +428,19 @@ function buildAnthropicHeaders(options) {
|
|
|
419
428
|
"cf-aig-authorization": `Bearer ${options.apiKey}`
|
|
420
429
|
};
|
|
421
430
|
if (oauthToken) {
|
|
422
|
-
const userAgent = isClaudeCodeClientUserAgent(incomingUserAgent) ? incomingUserAgent :
|
|
431
|
+
const userAgent = isClaudeCodeClientUserAgent(incomingUserAgent) ? incomingUserAgent : claudeCodeUserAgent;
|
|
423
432
|
const headers = {
|
|
424
433
|
...modelHeaders,
|
|
425
434
|
Accept: acceptHeader,
|
|
426
435
|
"Content-Type": "application/json",
|
|
427
436
|
"User-Agent": userAgent,
|
|
428
437
|
...options.claudeCodeSessionId ? { "X-Claude-Code-Session-Id": options.claudeCodeSessionId } : {},
|
|
429
|
-
...
|
|
438
|
+
...claudeCodeHeaders,
|
|
430
439
|
...betaHeader ? { "anthropic-beta": betaHeader } : {},
|
|
431
440
|
"anthropic-dangerous-direct-browser-access": "true",
|
|
432
441
|
"anthropic-version": "2023-06-01",
|
|
433
442
|
Authorization: `Bearer ${options.apiKey}`,
|
|
434
443
|
"x-app": "cli",
|
|
435
|
-
"x-client-request-id": nodeCrypto.randomUUID(),
|
|
436
444
|
Connection: "keep-alive",
|
|
437
445
|
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
438
446
|
...incomingApiKey ? { "X-Api-Key": incomingApiKey } : {}
|
|
@@ -468,15 +476,31 @@ function cloneAnthropicCacheControl(cacheControl) {
|
|
|
468
476
|
const ANTHROPIC_STOP_SEQUENCES_MAX = 4;
|
|
469
477
|
let warnedStopSequencesTrim = false;
|
|
470
478
|
const ANTHROPIC_PROVIDER_SESSION_STATE_KEY = "anthropic-messages";
|
|
479
|
+
function createAnthropicControlState() {
|
|
480
|
+
return {
|
|
481
|
+
declaredTools: void 0,
|
|
482
|
+
activeToolNames: /* @__PURE__ */ new Set(),
|
|
483
|
+
stableSystemBlocks: void 0,
|
|
484
|
+
systemFingerprint: void 0,
|
|
485
|
+
controlTransitions: [],
|
|
486
|
+
baseEffort: void 0,
|
|
487
|
+
baseEffortWire: void 0,
|
|
488
|
+
currentEffort: void 0
|
|
489
|
+
};
|
|
490
|
+
}
|
|
471
491
|
function createAnthropicProviderSessionState() {
|
|
472
492
|
const state = {
|
|
473
493
|
strictToolsDisabled: false,
|
|
474
494
|
fastModeDisabled: false,
|
|
475
495
|
replayUnsignedThinkingDisabled: false,
|
|
496
|
+
prefixDroppedThinkingBlocks: /* @__PURE__ */ new Set(),
|
|
497
|
+
controlStates: /* @__PURE__ */ new Map(),
|
|
476
498
|
close: () => {
|
|
477
499
|
state.strictToolsDisabled = false;
|
|
478
500
|
state.fastModeDisabled = false;
|
|
479
501
|
state.replayUnsignedThinkingDisabled = false;
|
|
502
|
+
state.prefixDroppedThinkingBlocks.clear();
|
|
503
|
+
state.controlStates.clear();
|
|
480
504
|
}
|
|
481
505
|
};
|
|
482
506
|
return state;
|
|
@@ -496,7 +520,11 @@ function getAnthropicProviderSessionState(providerSessionState, baseUrl, modelId
|
|
|
496
520
|
if (!providerSessionState) return void 0;
|
|
497
521
|
const key = anthropicProviderSessionStateKey(baseUrl, modelId);
|
|
498
522
|
const existing = providerSessionState.get(key);
|
|
499
|
-
if (existing)
|
|
523
|
+
if (existing) {
|
|
524
|
+
existing.prefixDroppedThinkingBlocks ??= /* @__PURE__ */ new Set();
|
|
525
|
+
existing.controlStates ??= /* @__PURE__ */ new Map();
|
|
526
|
+
return existing;
|
|
527
|
+
}
|
|
500
528
|
const created = createAnthropicProviderSessionState();
|
|
501
529
|
providerSessionState.set(key, created);
|
|
502
530
|
return created;
|
|
@@ -523,6 +551,18 @@ function getCacheControl(model, cacheRetention) {
|
|
|
523
551
|
}
|
|
524
552
|
};
|
|
525
553
|
}
|
|
554
|
+
/** Maps Node's platform identifier to the Stainless wire value. */
|
|
555
|
+
function mapStainlessOs(platform) {
|
|
556
|
+
switch (platform.toLowerCase()) {
|
|
557
|
+
case "darwin": return "MacOS";
|
|
558
|
+
case "windows":
|
|
559
|
+
case "win32": return "Windows";
|
|
560
|
+
case "linux": return "Linux";
|
|
561
|
+
case "freebsd": return "FreeBSD";
|
|
562
|
+
default: return `Other::${platform.toLowerCase()}`;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
/** Maps Node's architecture identifier to the Stainless wire value. */
|
|
526
566
|
function mapStainlessArch(arch) {
|
|
527
567
|
switch (arch.toLowerCase()) {
|
|
528
568
|
case "amd64":
|
|
@@ -535,19 +575,19 @@ function mapStainlessArch(arch) {
|
|
|
535
575
|
default: return `other::${arch.toLowerCase()}`;
|
|
536
576
|
}
|
|
537
577
|
}
|
|
538
|
-
/** Static headers emitted by
|
|
539
|
-
const
|
|
578
|
+
/** Static headers emitted by Claude Code's CLI runtime. */
|
|
579
|
+
const claudeCodeHeaders = {
|
|
540
580
|
"X-Stainless-Arch": mapStainlessArch(process.arch),
|
|
541
581
|
"X-Stainless-Lang": "js",
|
|
542
|
-
"X-Stainless-OS":
|
|
543
|
-
"X-Stainless-Package-Version":
|
|
582
|
+
"X-Stainless-OS": mapStainlessOs(process.platform),
|
|
583
|
+
"X-Stainless-Package-Version": claudeCodeSdkVersion,
|
|
544
584
|
"X-Stainless-Retry-Count": "0",
|
|
545
585
|
"X-Stainless-Runtime": "node",
|
|
546
586
|
"X-Stainless-Runtime-Version": "v26.3.0",
|
|
547
587
|
"X-Stainless-Timeout": "600"
|
|
548
588
|
};
|
|
549
589
|
const enforcedHeaderKeys = new Set([
|
|
550
|
-
...Object.keys(
|
|
590
|
+
...Object.keys(claudeCodeHeaders),
|
|
551
591
|
"Accept",
|
|
552
592
|
"Accept-Encoding",
|
|
553
593
|
"Connection",
|
|
@@ -564,7 +604,7 @@ const enforcedHeaderKeys = new Set([
|
|
|
564
604
|
"cf-aig-authorization"
|
|
565
605
|
].map((key) => key.toLowerCase()));
|
|
566
606
|
const overridableAnthropicHeaderKeys = new Set([
|
|
567
|
-
...Object.keys(
|
|
607
|
+
...Object.keys(claudeCodeHeaders),
|
|
568
608
|
"anthropic-beta",
|
|
569
609
|
"User-Agent",
|
|
570
610
|
"x-app"
|
|
@@ -577,7 +617,7 @@ function createClaudeBillingHeader(firstUserMessageText) {
|
|
|
577
617
|
20
|
|
578
618
|
].map((i) => firstUserMessageText[i] ?? "0").join("");
|
|
579
619
|
const versionSuffix = nodeCrypto.createHash("sha256").update(`59cf53e54c78${k}${claudeCodeVersion}`).digest("hex").slice(0, 3);
|
|
580
|
-
return `${CLAUDE_BILLING_HEADER_PREFIX} cc_version=${claudeCodeVersion}.${versionSuffix}; cc_entrypoint=
|
|
620
|
+
return `${CLAUDE_BILLING_HEADER_PREFIX} cc_version=${claudeCodeVersion}.${versionSuffix}; cc_entrypoint=cli; ${CCH_PLACEHOLDER_STR};`;
|
|
581
621
|
}
|
|
582
622
|
const CCH_SEED = 5577024349156291176n;
|
|
583
623
|
const CCH_PLACEHOLDER_STR = "cch=00000";
|
|
@@ -816,7 +856,7 @@ async function resizeAnthropicManyImageBlock(block) {
|
|
|
816
856
|
async function resizeAnthropicManyImageContent(content, state, limit) {
|
|
817
857
|
let changed = false;
|
|
818
858
|
const next = await Promise.all(content.map(async (block) => {
|
|
819
|
-
if (block.type !== "image") return block;
|
|
859
|
+
if (block.type !== "image" || block.url || block.providerFile?.provider === "anthropic" && block.providerFile.id) return block;
|
|
820
860
|
let resized = anthropicManyImageResizeCache.get(block);
|
|
821
861
|
if (resized === void 0) {
|
|
822
862
|
resized = await limit(() => resizeAnthropicManyImageBlock(block));
|
|
@@ -896,22 +936,34 @@ function convertContentBlocks(content, supportsImages = true) {
|
|
|
896
936
|
});
|
|
897
937
|
continue;
|
|
898
938
|
}
|
|
899
|
-
|
|
900
|
-
if (
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
939
|
+
let source;
|
|
940
|
+
if (block.providerFile?.provider === "anthropic" && block.providerFile.id) source = {
|
|
941
|
+
type: "file",
|
|
942
|
+
file_id: block.providerFile.id
|
|
943
|
+
};
|
|
944
|
+
else if (block.url) source = {
|
|
945
|
+
type: "url",
|
|
946
|
+
url: block.url
|
|
947
|
+
};
|
|
948
|
+
else {
|
|
949
|
+
const mediaType = normalizeAnthropicImageMediaType(block.mimeType);
|
|
950
|
+
if (!mediaType) {
|
|
951
|
+
blocks.push({
|
|
952
|
+
type: "text",
|
|
953
|
+
text: `[unsupported image: ${block.mimeType}]`
|
|
954
|
+
});
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
source = {
|
|
958
|
+
type: "base64",
|
|
959
|
+
media_type: mediaType,
|
|
960
|
+
data: block.data
|
|
961
|
+
};
|
|
906
962
|
}
|
|
907
963
|
sawImage = true;
|
|
908
964
|
blocks.push({
|
|
909
965
|
type: "image",
|
|
910
|
-
source
|
|
911
|
-
type: "base64",
|
|
912
|
-
media_type: mediaType,
|
|
913
|
-
data: block.data
|
|
914
|
-
}
|
|
966
|
+
source
|
|
915
967
|
});
|
|
916
968
|
}
|
|
917
969
|
if (!supportsImages) return blocks.filter((block) => block.type === "text").map((block) => block.text).join("\n").toWellFormed();
|
|
@@ -921,7 +973,7 @@ function convertContentBlocks(content, supportsImages = true) {
|
|
|
921
973
|
});
|
|
922
974
|
return blocks;
|
|
923
975
|
}
|
|
924
|
-
const
|
|
976
|
+
const CLAUDE_CODE_TLS_CIPHERS = tls.DEFAULT_CIPHERS;
|
|
925
977
|
const foundryTlsOptionsCache = /* @__PURE__ */ new Map();
|
|
926
978
|
function foundryTlsCacheKeyComponent(value) {
|
|
927
979
|
if (!value) return null;
|
|
@@ -1025,7 +1077,7 @@ function resolveFoundryTlsOptions(model) {
|
|
|
1025
1077
|
foundryTlsOptionsCache.set(cacheKey, resolved);
|
|
1026
1078
|
return resolved;
|
|
1027
1079
|
}
|
|
1028
|
-
function
|
|
1080
|
+
function buildClaudeCodeTlsFetchOptions(model, baseUrl) {
|
|
1029
1081
|
if (model.provider !== "anthropic") return void 0;
|
|
1030
1082
|
if (!baseUrl) return void 0;
|
|
1031
1083
|
let serverName;
|
|
@@ -1039,8 +1091,8 @@ function buildCoworkTlsFetchOptions(model, baseUrl) {
|
|
|
1039
1091
|
return { tls: {
|
|
1040
1092
|
rejectUnauthorized: true,
|
|
1041
1093
|
serverName,
|
|
1042
|
-
...
|
|
1043
|
-
...foundryTlsOptions
|
|
1094
|
+
...CLAUDE_CODE_TLS_CIPHERS ? { ciphers: CLAUDE_CODE_TLS_CIPHERS } : {},
|
|
1095
|
+
...foundryTlsOptions
|
|
1044
1096
|
} };
|
|
1045
1097
|
}
|
|
1046
1098
|
function mergeHeaders(...headerSources) {
|
|
@@ -1155,12 +1207,6 @@ async function* observeDecodedAnthropicSdkEvents(events, observer) {
|
|
|
1155
1207
|
}
|
|
1156
1208
|
const PROVIDER_MAX_RETRIES = 10;
|
|
1157
1209
|
/**
|
|
1158
|
-
* Flat delay between attempts when Copilot 400s a model its own `/models`
|
|
1159
|
-
* catalog advertises. Part of the fleet carries the model and part doesn't, so
|
|
1160
|
-
* the retry is a reroll rather than a wait for capacity to free up.
|
|
1161
|
-
*/
|
|
1162
|
-
const COPILOT_MODEL_FLAP_RETRY_DELAY_MS = 400;
|
|
1163
|
-
/**
|
|
1164
1210
|
* How long `ping` keepalives may keep extending the idle deadline without any
|
|
1165
1211
|
* semantic stream progress, as a multiple of the idle timeout. Anthropic pings
|
|
1166
1212
|
* across legitimate generation gaps, so pings count as liveness — but a wedged
|
|
@@ -1184,18 +1230,6 @@ function shouldIgnoreAnthropicPreambleEvent(eventType) {
|
|
|
1184
1230
|
if (eventType === "ping") return true;
|
|
1185
1231
|
return !ANTHROPIC_MESSAGE_EVENTS.has(eventType);
|
|
1186
1232
|
}
|
|
1187
|
-
/**
|
|
1188
|
-
* Whether an Anthropic (or Copilot-over-Anthropic) stream error should be
|
|
1189
|
-
* retried. The classification lives in {@link AIError.isProviderRetryableError};
|
|
1190
|
-
* this wrapper injects the Copilot-specific model-availability transient check,
|
|
1191
|
-
* which the error module must not import directly.
|
|
1192
|
-
*/
|
|
1193
|
-
function isProviderRetryableError(error, provider) {
|
|
1194
|
-
return isProviderRetryableError$1(error, {
|
|
1195
|
-
provider,
|
|
1196
|
-
isProviderTransient: provider === "github-copilot" ? (err) => isCopilotTransientModelError(err) : void 0
|
|
1197
|
-
});
|
|
1198
|
-
}
|
|
1199
1233
|
const THINKING_ENVELOPE_OPEN = "<thinking>";
|
|
1200
1234
|
const THINKING_ENVELOPE_CLOSE = "</thinking>";
|
|
1201
1235
|
function unwrapAnthropicThinkingEnvelope(text) {
|
|
@@ -1320,7 +1354,7 @@ function resolveIterationModel(requestModel, iterationModelId) {
|
|
|
1320
1354
|
}
|
|
1321
1355
|
return requestModel;
|
|
1322
1356
|
}
|
|
1323
|
-
function calculateFallbackTurnCost(requestModel, usage, source) {
|
|
1357
|
+
function calculateFallbackTurnCost(requestModel, usage, source, timestamp) {
|
|
1324
1358
|
const iterations = source.iterations ?? [];
|
|
1325
1359
|
if (iterations.length === 0) return false;
|
|
1326
1360
|
const cost = {
|
|
@@ -1350,7 +1384,7 @@ function calculateFallbackTurnCost(requestModel, usage, source) {
|
|
|
1350
1384
|
iterationUsage.output = outputTokens;
|
|
1351
1385
|
iterationUsage.cacheWrite = cacheWriteTokens;
|
|
1352
1386
|
iterationUsage.totalTokens = iterationUsage.input + iterationUsage.output + iterationUsage.cacheRead + iterationUsage.cacheWrite;
|
|
1353
|
-
calculateCost(resolveIterationModel(requestModel, iteration.model), iterationUsage);
|
|
1387
|
+
calculateCost(resolveIterationModel(requestModel, iteration.model), iterationUsage, timestamp);
|
|
1354
1388
|
cost.input += iterationUsage.cost.input;
|
|
1355
1389
|
cost.output += iterationUsage.cost.output;
|
|
1356
1390
|
cost.cacheRead += iterationUsage.cost.cacheRead;
|
|
@@ -1363,24 +1397,112 @@ function calculateFallbackTurnCost(requestModel, usage, source) {
|
|
|
1363
1397
|
return true;
|
|
1364
1398
|
}
|
|
1365
1399
|
/**
|
|
1366
|
-
* Detects the
|
|
1367
|
-
*
|
|
1368
|
-
*
|
|
1400
|
+
* Detects the two shapes a signature-enforcing endpoint uses to reject a
|
|
1401
|
+
* replayed unsigned thinking block (sent as `signature: ""`):
|
|
1402
|
+
*
|
|
1403
|
+
* - Anthropic and Anthropic-fronting proxies: `400 Invalid `signature` in
|
|
1404
|
+
* `thinking` block`.
|
|
1405
|
+
* - Bedrock-backed proxies: the empty string fails schema validation before
|
|
1406
|
+
* signature checking, so it comes back as `ValidationException: The model
|
|
1407
|
+
* returned the following errors: messages.N.content.M.thinking.signature:
|
|
1408
|
+
* Field required`.
|
|
1409
|
+
*
|
|
1410
|
+
* Exported for the compat tests.
|
|
1369
1411
|
*/
|
|
1370
1412
|
const INVALID_THINKING_SIGNATURE_PATTERN = /invalid\s+`?signature`?\s+in\s+`?thinking`?(?:\s+block)?/i;
|
|
1413
|
+
const MISSING_THINKING_SIGNATURE_PATTERN = /thinking\.signature\b[^"\n]{0,32}\brequired\b/i;
|
|
1414
|
+
const THINKING_PREFIX_BINDING_PATTERN = /(?:bound to a different conversation|block_binding\.prefix_mismatch_behavior|prefix_mismatch_behavior)/i;
|
|
1415
|
+
/** Detects the preserved-thinking error caused by rewriting a signed block's conversation prefix. */
|
|
1416
|
+
function isThinkingPrefixBindingError(message) {
|
|
1417
|
+
return INVALID_THINKING_SIGNATURE_PATTERN.test(message) && THINKING_PREFIX_BINDING_PATTERN.test(message);
|
|
1418
|
+
}
|
|
1371
1419
|
function isInvalidThinkingSignatureError(message) {
|
|
1372
|
-
return INVALID_THINKING_SIGNATURE_PATTERN.test(message);
|
|
1420
|
+
return INVALID_THINKING_SIGNATURE_PATTERN.test(message) || MISSING_THINKING_SIGNATURE_PATTERN.test(message);
|
|
1421
|
+
}
|
|
1422
|
+
const INPUT_TRANSFORMATION_PATH_PATTERN = /^messages\.(\d+)\.content\.(\d+)$/;
|
|
1423
|
+
const PREFIX_BINDING_ERROR_PATH_PATTERN = /messages\.(\d+)\.content\.(\d+)/;
|
|
1424
|
+
function thinkingReplayKey(block) {
|
|
1425
|
+
if (block.type === "thinking") return block.signature ? `thinking:${block.signature}` : void 0;
|
|
1426
|
+
if (block.type === "redacted_thinking") return block.data ? `redacted:${block.data}` : void 0;
|
|
1427
|
+
}
|
|
1428
|
+
function rememberPrefixDroppedThinking(params, transformations, state) {
|
|
1429
|
+
if (!state) return;
|
|
1430
|
+
let firstMessageIndex;
|
|
1431
|
+
let firstBlockIndex;
|
|
1432
|
+
for (const transformation of transformations) {
|
|
1433
|
+
if (transformation.reason !== "prefix_binding_mismatch" || typeof transformation.path !== "string") continue;
|
|
1434
|
+
const match = INPUT_TRANSFORMATION_PATH_PATTERN.exec(transformation.path);
|
|
1435
|
+
if (!match) continue;
|
|
1436
|
+
const messageIndex = Number(match[1]);
|
|
1437
|
+
const blockIndex = Number(match[2]);
|
|
1438
|
+
if (firstMessageIndex === void 0 || messageIndex < firstMessageIndex || messageIndex === firstMessageIndex && blockIndex < (firstBlockIndex ?? Number.POSITIVE_INFINITY)) {
|
|
1439
|
+
firstMessageIndex = messageIndex;
|
|
1440
|
+
firstBlockIndex = blockIndex;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
if (firstMessageIndex === void 0 || firstBlockIndex === void 0) return;
|
|
1444
|
+
for (let messageIndex = firstMessageIndex; messageIndex < params.messages.length; messageIndex++) {
|
|
1445
|
+
const message = params.messages[messageIndex];
|
|
1446
|
+
if (!message || !Array.isArray(message.content)) continue;
|
|
1447
|
+
const blockStart = messageIndex === firstMessageIndex ? firstBlockIndex : 0;
|
|
1448
|
+
for (let blockIndex = blockStart; blockIndex < message.content.length; blockIndex++) {
|
|
1449
|
+
const key = thinkingReplayKey(message.content[blockIndex]);
|
|
1450
|
+
if (key) state.prefixDroppedThinkingBlocks.add(key);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
function rememberPrefixBindingFailure(params, message, state) {
|
|
1455
|
+
if (!state) return false;
|
|
1456
|
+
const match = PREFIX_BINDING_ERROR_PATH_PATTERN.exec(message);
|
|
1457
|
+
let path = match ? `messages.${match[1]}.content.${match[2]}` : void 0;
|
|
1458
|
+
if (!path) for (let messageIndex = 0; messageIndex < params.messages.length && !path; messageIndex++) {
|
|
1459
|
+
const candidate = params.messages[messageIndex];
|
|
1460
|
+
if (!candidate || !Array.isArray(candidate.content)) continue;
|
|
1461
|
+
const blockIndex = candidate.content.findIndex((block) => thinkingReplayKey(block) !== void 0);
|
|
1462
|
+
if (blockIndex >= 0) path = `messages.${messageIndex}.content.${blockIndex}`;
|
|
1463
|
+
}
|
|
1464
|
+
if (!path) return false;
|
|
1465
|
+
rememberPrefixDroppedThinking(params, [{
|
|
1466
|
+
type: "thinking_dropped",
|
|
1467
|
+
reason: "prefix_binding_mismatch",
|
|
1468
|
+
path
|
|
1469
|
+
}], state);
|
|
1470
|
+
return true;
|
|
1471
|
+
}
|
|
1472
|
+
function applyReportedInputTransformations(output, params, state, value, seen, replace = false) {
|
|
1473
|
+
if (value === void 0 || value === null) return;
|
|
1474
|
+
if (replace) {
|
|
1475
|
+
seen.clear();
|
|
1476
|
+
output.inputTransformations = [];
|
|
1477
|
+
}
|
|
1478
|
+
const fresh = [];
|
|
1479
|
+
for (const transformation of parseAnthropicInputTransformations(value)) {
|
|
1480
|
+
const key = JSON.stringify(transformation);
|
|
1481
|
+
if (seen.has(key)) continue;
|
|
1482
|
+
seen.add(key);
|
|
1483
|
+
fresh.push(transformation);
|
|
1484
|
+
}
|
|
1485
|
+
if (fresh.length === 0) return;
|
|
1486
|
+
output.inputTransformations = [...output.inputTransformations ?? [], ...fresh];
|
|
1487
|
+
rememberPrefixDroppedThinking(params, fresh, state);
|
|
1488
|
+
for (const transformation of fresh) {
|
|
1489
|
+
if (transformation.reason !== "prefix_binding_mismatch") continue;
|
|
1490
|
+
warn("anthropic: dropped thinking block after conversation prefix changed", {
|
|
1491
|
+
model: output.model,
|
|
1492
|
+
path: transformation.path
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1373
1495
|
}
|
|
1374
1496
|
/**
|
|
1375
|
-
* Prepend a pointed remediation to
|
|
1376
|
-
*
|
|
1497
|
+
* Prepend a pointed remediation to a thinking-signature rejection 400 when the
|
|
1498
|
+
* model looks like an unmarked custom signing proxy
|
|
1377
1499
|
* (opaque baseUrl, `spec.reasoning: true`, no explicit
|
|
1378
1500
|
* `compat.replayUnsignedThinking` override). The default is native replay for
|
|
1379
1501
|
* the 3p reasoning majority (#2005); this hint turns the misconfigured-proxy
|
|
1380
1502
|
* case into a one-line fix instead of a silent retry loop (#4297).
|
|
1381
1503
|
*/
|
|
1382
1504
|
function maybeAddReplayUnsignedThinkingHint(model, message) {
|
|
1383
|
-
if (!isInvalidThinkingSignatureError(message)) return message;
|
|
1505
|
+
if (!isInvalidThinkingSignatureError(message) || isThinkingPrefixBindingError(message)) return message;
|
|
1384
1506
|
if (model.compat.officialEndpoint) return message;
|
|
1385
1507
|
if (model.compatConfig?.replayUnsignedThinking !== void 0) return message;
|
|
1386
1508
|
return `${`Provider "${model.provider}" looks like an Anthropic-compatible signing proxy: it rejected a replayed unsigned thinking block. Set \`compat.replayUnsignedThinking: false\` under \`providers.${model.provider}\` in your models.yml and retry. See https://github.com/can1357/oh-my-pi/issues/4297.`}\n\n${message}`;
|
|
@@ -1410,9 +1532,10 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1410
1532
|
hasImages: hasCopilotVisionInput(context.messages),
|
|
1411
1533
|
premiumMultiplier: model.premiumMultiplier,
|
|
1412
1534
|
headers: {
|
|
1413
|
-
...model.headers
|
|
1414
|
-
...options?.headers
|
|
1535
|
+
...model.headers,
|
|
1536
|
+
...options?.headers
|
|
1415
1537
|
},
|
|
1538
|
+
integrationId: resolveCopilotRequestIdentity(options?.headers),
|
|
1416
1539
|
initiatorOverride: options?.initiatorOverride
|
|
1417
1540
|
}) : void 0;
|
|
1418
1541
|
if (copilotDynamicHeaders?.premiumRequests !== void 0) output.usage.premiumRequests = copilotDynamicHeaders.premiumRequests;
|
|
@@ -1423,10 +1546,14 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1423
1546
|
let disableStrictTools = (providerSessionState?.strictToolsDisabled ?? false) || (model.compat?.disableStrictTools ?? false);
|
|
1424
1547
|
let dropFastMode = providerSessionState?.fastModeDisabled ?? false;
|
|
1425
1548
|
let forceDemoteUnsignedThinking = providerSessionState?.replayUnsignedThinkingDisabled ?? false;
|
|
1549
|
+
let dropAllThinking = false;
|
|
1550
|
+
let prefixBindingRetryAttempted = false;
|
|
1551
|
+
let prefixMismatchBehavior = model.thinking?.prefixBinding && model.compat.supportsThinkingBindingControls ? options?.anthropicPrefixMismatchBehavior ?? "drop_block" : void 0;
|
|
1552
|
+
const controlBetas = resolveAnthropicControlBetas(model, prefixMismatchBehavior);
|
|
1426
1553
|
const mergedCallerHeaders = mergeHeaders(model.headers, options?.headers);
|
|
1427
1554
|
const umansGatewayWebSearchHeader = getUmansWebSearchHeader(model, mergedCallerHeaders);
|
|
1428
1555
|
let fallbacks = options?.fallbacks;
|
|
1429
|
-
if (model.
|
|
1556
|
+
if (!model.compat.supportsOutputEffort && fallbacks?.some((entry) => entry.output_config?.effort !== void 0)) fallbacks = fallbacks.map((entry) => {
|
|
1430
1557
|
const outputConfig = entry.output_config;
|
|
1431
1558
|
if (outputConfig?.effort === void 0) return entry;
|
|
1432
1559
|
return {
|
|
@@ -1445,9 +1572,11 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1445
1572
|
if (model.provider === "anthropic" && options?.serviceTier === "priority" && !dropFastMode && !extraBetas.includes(fastModeBeta)) extraBetas.push(fastModeBeta);
|
|
1446
1573
|
if (options?.taskBudget && !extraBetas.includes(taskBudgetBeta)) extraBetas.push(taskBudgetBeta);
|
|
1447
1574
|
const sendsAdaptiveEffortPin = isAdaptiveOnlyThinking(model) && (options?.thinkingEnabled === false || model.compat.supportsForcedToolChoice && isForcedToolChoice(options?.toolChoice));
|
|
1448
|
-
if (model.reasoning && model.
|
|
1449
|
-
if (
|
|
1450
|
-
|
|
1575
|
+
if (model.reasoning && model.compat.supportsOutputEffort && (options?.thinkingEnabled && options.effort !== "adaptive" || sendsAdaptiveEffortPin) && !extraBetas.includes(effortBeta)) extraBetas.push(effortBeta);
|
|
1576
|
+
if (!isVertexRawPredictUrl(baseUrl)) {
|
|
1577
|
+
for (const beta of controlBetas) if (!extraBetas.includes(beta)) extraBetas.push(beta);
|
|
1578
|
+
}
|
|
1579
|
+
if (model.reasoning && options?.thinkingEnabled && model.compat.supportsContextManagement !== false && !extraBetas.includes(contextManagementBeta)) extraBetas.push(contextManagementBeta);
|
|
1451
1580
|
if (!(options?.isOAuth ?? isAnthropicOAuthToken(apiKey)) && getCacheControl(model, options?.cacheRetention).cacheControl?.ttl === "1h" && !extraBetas.includes(extendedCacheTtlBeta)) extraBetas.push(extendedCacheTtlBeta);
|
|
1452
1581
|
if (fallbacks?.length) {
|
|
1453
1582
|
if (!extraBetas.includes(serverSideFallbackBeta)) extraBetas.push(serverSideFallbackBeta);
|
|
@@ -1471,7 +1600,7 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1471
1600
|
thinkingDisplay: options?.thinkingDisplay,
|
|
1472
1601
|
fetch: options?.fetch,
|
|
1473
1602
|
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
1474
|
-
|
|
1603
|
+
sessionId: options?.sessionId ?? extractClaudeMetadataSessionId(options?.metadata?.user_id) ?? options?.promptCacheKey,
|
|
1475
1604
|
disableStrictTools
|
|
1476
1605
|
});
|
|
1477
1606
|
client = created.client;
|
|
@@ -1484,6 +1613,10 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1484
1613
|
useUmansGatewayWebSearch: umansGatewayWebSearchHeader !== void 0,
|
|
1485
1614
|
forceDemoteUnsignedThinking,
|
|
1486
1615
|
supportsEagerToolInputStreaming,
|
|
1616
|
+
prefixMismatchBehavior,
|
|
1617
|
+
dropAllThinking,
|
|
1618
|
+
droppedThinkingBlocks: providerSessionState?.prefixDroppedThinkingBlocks,
|
|
1619
|
+
providerSessionState,
|
|
1487
1620
|
fallbacks
|
|
1488
1621
|
});
|
|
1489
1622
|
if (disableStrictTools) dropAnthropicStrictTools(nextParams);
|
|
@@ -1502,6 +1635,7 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1502
1635
|
return nextParams;
|
|
1503
1636
|
};
|
|
1504
1637
|
let params = await prepareParams();
|
|
1638
|
+
const seenInputTransformations = /* @__PURE__ */ new Set();
|
|
1505
1639
|
const idleTimeoutMs = options?.streamIdleTimeoutMs ?? getStreamIdleTimeoutMs(model.compat.streamIdleTimeoutMs);
|
|
1506
1640
|
const firstEventTimeoutMs = options?.streamFirstEventTimeoutMs ?? getStreamFirstEventTimeoutMs(idleTimeoutMs);
|
|
1507
1641
|
const requestTimeoutMs = firstEventTimeoutMs !== void 0 && firstEventTimeoutMs > 0 ? firstEventTimeoutMs : void 0;
|
|
@@ -1533,13 +1667,14 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1533
1667
|
const wireUsage = parseAnthropicWireUsage(body.usage);
|
|
1534
1668
|
if (!wireUsage) throw new AnthropicStreamEnvelopeError("Anthropic cache refresh response omitted usage");
|
|
1535
1669
|
if (typeof body.id === "string") output.responseId = body.id;
|
|
1670
|
+
applyReportedInputTransformations(output, params, providerSessionState, body.input_transformations, seenInputTransformations);
|
|
1536
1671
|
output.usage.input = wireUsage.input_tokens ?? 0;
|
|
1537
1672
|
output.usage.output = wireUsage.output_tokens ?? 0;
|
|
1538
1673
|
output.usage.cacheRead = wireUsage.cache_read_input_tokens ?? 0;
|
|
1539
1674
|
output.usage.cacheWrite = wireUsage.cache_creation_input_tokens ?? 0;
|
|
1540
1675
|
applyAnthropicUsageExtras(output.usage, wireUsage);
|
|
1541
1676
|
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
1542
|
-
calculateCost(model, output.usage);
|
|
1677
|
+
calculateCost(model, output.usage, output.timestamp);
|
|
1543
1678
|
output.duration = performance.now() - startTime;
|
|
1544
1679
|
stream.push({
|
|
1545
1680
|
type: "start",
|
|
@@ -1618,10 +1753,14 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1618
1753
|
while (true) {
|
|
1619
1754
|
activeAbortTracker = createAbortSourceTracker(options?.signal);
|
|
1620
1755
|
const { requestSignal } = activeAbortTracker;
|
|
1621
|
-
|
|
1622
|
-
|
|
1756
|
+
let injectedClientBetaHeaders;
|
|
1757
|
+
if (options?.client !== void 0 && !isVertexRawPredictUrl(baseUrl)) {
|
|
1758
|
+
for (const beta of controlBetas) injectedClientBetaHeaders = mergeAnthropicBetaHeader(injectedClientBetaHeaders ?? mergedCallerHeaders, beta);
|
|
1759
|
+
if (params.output_config?.effort !== void 0) injectedClientBetaHeaders = mergeAnthropicBetaHeader(injectedClientBetaHeaders ?? mergedCallerHeaders, effortBeta);
|
|
1760
|
+
}
|
|
1761
|
+
const perRequestHeaders = umansGatewayWebSearchHeader || injectedClientBetaHeaders ? {
|
|
1623
1762
|
...umansGatewayWebSearchHeader,
|
|
1624
|
-
...
|
|
1763
|
+
...injectedClientBetaHeaders
|
|
1625
1764
|
} : void 0;
|
|
1626
1765
|
const requestOptions = {
|
|
1627
1766
|
...createSdkStreamRequestOptions(requestSignal, requestTimeoutMs),
|
|
@@ -1693,6 +1832,7 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1693
1832
|
sawMessageStart = true;
|
|
1694
1833
|
const startMessage = event.message;
|
|
1695
1834
|
if (startMessage?.id) output.responseId = startMessage.id;
|
|
1835
|
+
applyReportedInputTransformations(output, params, providerSessionState, startMessage?.input_transformations, seenInputTransformations);
|
|
1696
1836
|
const startUsage = startMessage?.usage;
|
|
1697
1837
|
if (startUsage) {
|
|
1698
1838
|
applyAnthropicUsageExtras(output.usage, startUsage);
|
|
@@ -1704,8 +1844,8 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1704
1844
|
if (serverSideFallback) {
|
|
1705
1845
|
const served = fallbackServedModelFromUsage(startUsage);
|
|
1706
1846
|
if (served) output.model = served;
|
|
1707
|
-
if (!calculateFallbackTurnCost(model, output.usage, startUsage)) calculateCost(model, output.usage);
|
|
1708
|
-
} else calculateCost(model, output.usage);
|
|
1847
|
+
if (!calculateFallbackTurnCost(model, output.usage, startUsage, output.timestamp)) calculateCost(model, output.usage, output.timestamp);
|
|
1848
|
+
} else calculateCost(model, output.usage, output.timestamp);
|
|
1709
1849
|
} else reportAnthropicEnvelopeAnomaly("message_start missing usage");
|
|
1710
1850
|
continue;
|
|
1711
1851
|
}
|
|
@@ -1952,6 +2092,7 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1952
2092
|
continue;
|
|
1953
2093
|
}
|
|
1954
2094
|
const delta = event.delta;
|
|
2095
|
+
applyReportedInputTransformations(output, params, providerSessionState, event.input_transformations, seenInputTransformations, true);
|
|
1955
2096
|
const rawStopReason = delta?.stop_reason;
|
|
1956
2097
|
if (rawStopReason) {
|
|
1957
2098
|
output.stopReason = mapStopReason(rawStopReason);
|
|
@@ -1978,12 +2119,13 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
1978
2119
|
if (serverSideFallback) {
|
|
1979
2120
|
const served = fallbackServedModelFromUsage(deltaUsage);
|
|
1980
2121
|
if (served) output.model = served;
|
|
1981
|
-
if (!calculateFallbackTurnCost(model, output.usage, deltaUsage)) calculateCost(model, output.usage);
|
|
1982
|
-
} else calculateCost(model, output.usage);
|
|
2122
|
+
if (!calculateFallbackTurnCost(model, output.usage, deltaUsage, output.timestamp)) calculateCost(model, output.usage, output.timestamp);
|
|
2123
|
+
} else calculateCost(model, output.usage, output.timestamp);
|
|
1983
2124
|
}
|
|
1984
2125
|
} else if (event.type === "message_stop") {
|
|
1985
2126
|
sawTerminalEnvelope = true;
|
|
1986
2127
|
sawMessageStop = true;
|
|
2128
|
+
break;
|
|
1987
2129
|
}
|
|
1988
2130
|
}
|
|
1989
2131
|
const firstEventTimeoutError = activeAbortTracker.getLocalAbortReason();
|
|
@@ -2027,12 +2169,35 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
2027
2169
|
firstTokenTime = void 0;
|
|
2028
2170
|
continue;
|
|
2029
2171
|
}
|
|
2030
|
-
|
|
2031
|
-
|
|
2172
|
+
const streamFailureMessage = streamFailure instanceof Error ? streamFailure.message : String(streamFailure);
|
|
2173
|
+
if (!prefixBindingRetryAttempted && options?.anthropicPrefixMismatchBehavior !== "error" && firstTokenTime === void 0 && !streamedReplayUnsafeContent && isThinkingPrefixBindingError(streamFailureMessage)) {
|
|
2174
|
+
warn("anthropic: thinking prefix changed, stripping bound thinking and retrying", {
|
|
2175
|
+
provider: model.provider,
|
|
2176
|
+
model: model.id,
|
|
2177
|
+
baseUrl
|
|
2178
|
+
});
|
|
2179
|
+
prefixBindingRetryAttempted = true;
|
|
2180
|
+
prefixMismatchBehavior = void 0;
|
|
2181
|
+
dropAllThinking = !rememberPrefixBindingFailure(params, streamFailureMessage, providerSessionState);
|
|
2182
|
+
params = await prepareParams();
|
|
2183
|
+
providerRetryAttempt = 0;
|
|
2184
|
+
output.content.length = 0;
|
|
2185
|
+
output.model = model.id;
|
|
2186
|
+
output.responseId = void 0;
|
|
2187
|
+
output.errorMessage = void 0;
|
|
2188
|
+
output.inputTransformations = void 0;
|
|
2189
|
+
output.providerPayload = void 0;
|
|
2190
|
+
output.usage = createEmptyUsage(copilotDynamicHeaders?.premiumRequests);
|
|
2191
|
+
output.stopReason = "stop";
|
|
2192
|
+
firstTokenTime = void 0;
|
|
2193
|
+
continue;
|
|
2194
|
+
}
|
|
2195
|
+
if (!forceDemoteUnsignedThinking && firstTokenTime === void 0 && !streamedReplayUnsafeContent && !isThinkingPrefixBindingError(streamFailureMessage) && isInvalidThinkingSignatureError(streamFailureMessage)) {
|
|
2196
|
+
warn("anthropic: signing proxy detected (thinking signature rejected), demoting unsigned thinking and retrying", {
|
|
2032
2197
|
provider: model.provider,
|
|
2033
2198
|
model: model.id,
|
|
2034
2199
|
baseUrl,
|
|
2035
|
-
error:
|
|
2200
|
+
error: streamFailureMessage
|
|
2036
2201
|
});
|
|
2037
2202
|
if (providerSessionState) providerSessionState.replayUnsignedThinkingDisabled = true;
|
|
2038
2203
|
forceDemoteUnsignedThinking = true;
|
|
@@ -2070,10 +2235,10 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
2070
2235
|
const isTransientEnvelopeFailure = isTransientStreamParseError(streamFailure) || isStreamEnvelopeError(streamFailure);
|
|
2071
2236
|
const isLocalIdleTimeout = streamFailure === idleTimeoutAbortError || streamFailure instanceof Error && streamFailure.message === idleTimeoutAbortError.message;
|
|
2072
2237
|
const canRetryTransientEnvelopeFailure = isTransientEnvelopeFailure && !streamedReplayUnsafeContent;
|
|
2073
|
-
const canRetryProviderFailure = !isLocalIdleTimeout && firstTokenTime === void 0 && !streamedReplayUnsafeContent && isProviderRetryableError(streamFailure
|
|
2238
|
+
const canRetryProviderFailure = !isLocalIdleTimeout && firstTokenTime === void 0 && !streamedReplayUnsafeContent && isProviderRetryableError(streamFailure);
|
|
2074
2239
|
if (activeAbortTracker.wasCallerAbort() || providerRetryAttempt >= PROVIDER_MAX_RETRIES || !canRetryTransientEnvelopeFailure && !canRetryProviderFailure) throw streamFailure;
|
|
2075
2240
|
providerRetryAttempt++;
|
|
2076
|
-
const backoffDelayMs =
|
|
2241
|
+
const backoffDelayMs = calculateAnthropicRetryDelayMs(providerRetryAttempt - 1);
|
|
2077
2242
|
const headerDelayMs = getRetryAfterMsFromHeaders(getHeadersFromError(streamFailure));
|
|
2078
2243
|
const maxRetryDelayMs = options?.maxRetryDelayMs ?? 6e4;
|
|
2079
2244
|
if (headerDelayMs !== void 0 && maxRetryDelayMs > 0 && headerDelayMs > maxRetryDelayMs) throw streamFailure;
|
|
@@ -2126,15 +2291,12 @@ const streamAnthropicOnce = (model, context, options) => {
|
|
|
2126
2291
|
return stream;
|
|
2127
2292
|
};
|
|
2128
2293
|
/**
|
|
2129
|
-
* Public entry:
|
|
2130
|
-
*
|
|
2131
|
-
* stall the agent loop). The inner attempt keeps its own provider-failure retry
|
|
2132
|
-
* loop; this layer only re-issues a fresh request on an empty success. Shared
|
|
2133
|
-
* with the OpenAI-completions provider via `withEmptyCompletionRetry`.
|
|
2294
|
+
* Public entry: retry benign empty completions before they reach the agent
|
|
2295
|
+
* loop. The inner attempt owns Anthropic provider-failure retries.
|
|
2134
2296
|
*/
|
|
2135
|
-
const streamAnthropic = (model, context, options) =>
|
|
2297
|
+
const streamAnthropic = (model, context, options) => withReplaySafeStreamRetry(model, context, options, streamAnthropicOnce, { retryEmptyCompletion: true });
|
|
2136
2298
|
function buildAnthropicSystemBlocks(systemPrompt, options = {}) {
|
|
2137
|
-
const { includeClaudeCodeInstruction = false, extraInstructions = [], firstUserMessageText } = options;
|
|
2299
|
+
const { includeClaudeCodeInstruction = false, extraInstructions = [], firstUserMessageText, cacheControl } = options;
|
|
2138
2300
|
const sanitizedPrompts = normalizeSystemPrompts(systemPrompt);
|
|
2139
2301
|
const trimmedInstructions = extraInstructions.map((instruction) => instruction.trim()).filter(Boolean);
|
|
2140
2302
|
const hasBillingHeader = sanitizedPrompts.some((prompt) => prompt.startsWith(CLAUDE_BILLING_HEADER_PREFIX));
|
|
@@ -2144,7 +2306,8 @@ function buildAnthropicSystemBlocks(systemPrompt, options = {}) {
|
|
|
2144
2306
|
text: createClaudeBillingHeader(firstUserMessageText ?? "")
|
|
2145
2307
|
}, {
|
|
2146
2308
|
type: "text",
|
|
2147
|
-
text: claudeCodeSystemInstruction
|
|
2309
|
+
text: claudeCodeSystemInstruction,
|
|
2310
|
+
cache_control: cacheControl ? cloneAnthropicCacheControl(cacheControl) : { type: "ephemeral" }
|
|
2148
2311
|
}];
|
|
2149
2312
|
for (const instruction of trimmedInstructions) blocks.push({
|
|
2150
2313
|
type: "text",
|
|
@@ -2172,7 +2335,7 @@ function normalizeExtraBetas(betas) {
|
|
|
2172
2335
|
return (Array.isArray(betas) ? betas : betas.split(",")).map((beta) => beta.trim()).filter((beta) => beta.length > 0);
|
|
2173
2336
|
}
|
|
2174
2337
|
function buildAnthropicClientOptions(args) {
|
|
2175
|
-
const { model, apiKey, extraBetas = [], stream = true, interleavedThinking = true, headers, dynamicHeaders, hasTools = false, thinkingEnabled = false, isOAuth, maxRetryDelayMs,
|
|
2338
|
+
const { model, apiKey, extraBetas = [], stream = true, interleavedThinking = true, headers, dynamicHeaders, hasTools = false, thinkingEnabled = false, isOAuth, maxRetryDelayMs, sessionId, disableStrictTools: disableStrictToolsOverride } = args;
|
|
2176
2339
|
const compat = model.compat;
|
|
2177
2340
|
const disableStrictTools = disableStrictToolsOverride ?? compat.disableStrictTools;
|
|
2178
2341
|
const baseUrl = resolveAnthropicBaseUrl(model, apiKey);
|
|
@@ -2182,7 +2345,7 @@ function buildAnthropicClientOptions(args) {
|
|
|
2182
2345
|
const needsFineGrainedToolStreamingBeta = hasTools && isOfficialAnthropicApiUrl(baseUrl) && !supportsEagerToolInputStreaming;
|
|
2183
2346
|
const foundryCustomHeaders = resolveAnthropicCustomHeaders(model, baseUrl);
|
|
2184
2347
|
const fetchOptions = {
|
|
2185
|
-
...
|
|
2348
|
+
...buildClaudeCodeTlsFetchOptions(model, baseUrl),
|
|
2186
2349
|
timeout: false
|
|
2187
2350
|
};
|
|
2188
2351
|
const baseFetch = args.fetch ?? fetch;
|
|
@@ -2190,6 +2353,19 @@ function buildAnthropicClientOptions(args) {
|
|
|
2190
2353
|
if (model.provider === "github-copilot") {
|
|
2191
2354
|
const copilotApiKey = parseGitHubCopilotApiKey(apiKey).accessToken;
|
|
2192
2355
|
const betaFeatures = [...extraBetas];
|
|
2356
|
+
const defaultHeaders = mergeHeaders({
|
|
2357
|
+
Accept: stream ? "text/event-stream" : "application/json",
|
|
2358
|
+
"Content-Type": "application/json",
|
|
2359
|
+
"anthropic-version": "2023-06-01",
|
|
2360
|
+
"Anthropic-Dangerous-Direct-Browser-Access": "true",
|
|
2361
|
+
Authorization: `Bearer ${copilotApiKey}`,
|
|
2362
|
+
...betaFeatures.length > 0 ? { "anthropic-beta": buildBetaHeader([], betaFeatures) } : {}
|
|
2363
|
+
}, model.headers, dynamicHeaders, headers);
|
|
2364
|
+
applyInferenceHeaders(defaultHeaders, {
|
|
2365
|
+
provider: model.provider,
|
|
2366
|
+
protocol: "anthropic",
|
|
2367
|
+
sessionId
|
|
2368
|
+
});
|
|
2193
2369
|
return {
|
|
2194
2370
|
isOAuthToken: false,
|
|
2195
2371
|
apiKey: null,
|
|
@@ -2197,15 +2373,8 @@ function buildAnthropicClientOptions(args) {
|
|
|
2197
2373
|
baseURL: baseUrl,
|
|
2198
2374
|
maxRetries: 5,
|
|
2199
2375
|
maxRetryDelayMs,
|
|
2200
|
-
defaultHeaders
|
|
2201
|
-
|
|
2202
|
-
"Content-Type": "application/json",
|
|
2203
|
-
"anthropic-version": "2023-06-01",
|
|
2204
|
-
"Anthropic-Dangerous-Direct-Browser-Access": "true",
|
|
2205
|
-
Authorization: `Bearer ${copilotApiKey}`,
|
|
2206
|
-
...betaFeatures.length > 0 ? { "anthropic-beta": buildBetaHeader([], betaFeatures) } : {}
|
|
2207
|
-
}, model.headers, dynamicHeaders, headers),
|
|
2208
|
-
fetch: cchFetch,
|
|
2376
|
+
defaultHeaders,
|
|
2377
|
+
fetch: wrapFetchForCopilotFallback(cchFetch, true, resolveCopilotRequestIdentity(headers)),
|
|
2209
2378
|
fetchOptions
|
|
2210
2379
|
};
|
|
2211
2380
|
}
|
|
@@ -2221,8 +2390,18 @@ function buildAnthropicClientOptions(args) {
|
|
|
2221
2390
|
modelHeaders: mergeHeaders(model.headers, foundryCustomHeaders, getUmansWebSearchHeader(model, mergeHeaders(model.headers, headers)), headers, dynamicHeaders),
|
|
2222
2391
|
isCloudflareAiGateway: model.provider === "cloudflare-ai-gateway",
|
|
2223
2392
|
allowAnthropicHeaderOverrides: model.compat.allowAnthropicHeaderOverrides,
|
|
2224
|
-
claudeCodeSessionId,
|
|
2225
|
-
|
|
2393
|
+
claudeCodeSessionId: sessionId,
|
|
2394
|
+
claudeCodeBetas: oauthToken ? buildClaudeCodeBetas({
|
|
2395
|
+
agentRequest: hasTools || thinkingEnabled,
|
|
2396
|
+
thinkingRequest: thinkingEnabled,
|
|
2397
|
+
disableStrictTools,
|
|
2398
|
+
supportsContextManagement: model.compat.supportsContextManagement
|
|
2399
|
+
}) : []
|
|
2400
|
+
});
|
|
2401
|
+
applyInferenceHeaders(defaultHeaders, {
|
|
2402
|
+
provider: model.provider,
|
|
2403
|
+
protocol: "anthropic",
|
|
2404
|
+
sessionId
|
|
2226
2405
|
});
|
|
2227
2406
|
if (model.provider === "cloudflare-ai-gateway") return {
|
|
2228
2407
|
isOAuthToken: false,
|
|
@@ -2279,7 +2458,7 @@ function disableThinkingIfToolChoiceForced(params, model) {
|
|
|
2279
2458
|
if (toolChoice.type !== "any" && toolChoice.type !== "tool") return;
|
|
2280
2459
|
delete params.thinking;
|
|
2281
2460
|
delete params.context_management;
|
|
2282
|
-
if (isAdaptiveOnlyThinking(model) && model.
|
|
2461
|
+
if (isAdaptiveOnlyThinking(model) && model.compat.supportsOutputEffort) {
|
|
2283
2462
|
const outputConfig = params.output_config ?? {};
|
|
2284
2463
|
outputConfig.effort = "low";
|
|
2285
2464
|
params.output_config = outputConfig;
|
|
@@ -2306,7 +2485,7 @@ function ensureMaxTokensForThinking(params, maxAllowedTokens) {
|
|
|
2306
2485
|
function applyCacheControlToLastBlock(blocks, cacheControl) {
|
|
2307
2486
|
for (let index = blocks.length - 1; index >= 0; index--) {
|
|
2308
2487
|
const block = blocks[index];
|
|
2309
|
-
if (block.type === "thinking" || block.type === "redacted_thinking" || block.type === "fallback") continue;
|
|
2488
|
+
if (block.type === "thinking" || block.type === "redacted_thinking" || block.type === "fallback" || block.type === "tool_addition" || block.type === "tool_removal") continue;
|
|
2310
2489
|
if ("cache_control" in block && block.cache_control != null) return false;
|
|
2311
2490
|
blocks[index] = {
|
|
2312
2491
|
...block,
|
|
@@ -2321,10 +2500,11 @@ function applyPromptCaching(params, cacheControl) {
|
|
|
2321
2500
|
const trailingIndex = params.messages.length - 1;
|
|
2322
2501
|
const trailingMessage = params.messages[trailingIndex];
|
|
2323
2502
|
const messageEnd = trailingMessage?.role === "user" && trailingMessage.content === "Continue." && params.messages[trailingIndex - 1]?.role === "assistant" ? trailingIndex - 1 : trailingIndex;
|
|
2324
|
-
|
|
2325
|
-
for (let index = messageEnd; index >=
|
|
2503
|
+
let eligibleMessages = 0;
|
|
2504
|
+
for (let index = messageEnd; index >= 0 && eligibleMessages < 2; index--) {
|
|
2326
2505
|
const message = params.messages[index];
|
|
2327
|
-
if (!message) continue;
|
|
2506
|
+
if (!message || message.clear_at === "next_user_message") continue;
|
|
2507
|
+
eligibleMessages++;
|
|
2328
2508
|
if (typeof message.content === "string") message.content = [{
|
|
2329
2509
|
type: "text",
|
|
2330
2510
|
text: message.content,
|
|
@@ -2333,6 +2513,46 @@ function applyPromptCaching(params, cacheControl) {
|
|
|
2333
2513
|
else if (Array.isArray(message.content)) applyCacheControlToLastBlock(message.content, cacheControl);
|
|
2334
2514
|
}
|
|
2335
2515
|
}
|
|
2516
|
+
/**
|
|
2517
|
+
* Anchor cache_control on the stable request head — the last (non-deferred)
|
|
2518
|
+
* tool definition and the last system block. The canonical cache order is
|
|
2519
|
+
* tools → system → messages, so a breakpoint on the final system block caches
|
|
2520
|
+
* the entire tools+system prefix, and the extra tool breakpoint keeps the tool
|
|
2521
|
+
* definitions cached even when the system text changes. This guarantees the
|
|
2522
|
+
* large, unchanging head is a cache hit on every turn regardless of how the
|
|
2523
|
+
* message tail churns — the breakpoint placement first-party Anthropic clients
|
|
2524
|
+
* (Claude Code, Pi) use. Without it, the general API-key path anchors only the
|
|
2525
|
+
* moving message tail, so tail churn re-writes the whole head uncached.
|
|
2526
|
+
*
|
|
2527
|
+
* Anthropic allows at most 4 cache breakpoints per request. At most one is
|
|
2528
|
+
* spent on tools and one on system here, leaving two for the message tail in
|
|
2529
|
+
* `applyPromptCaching`. Head caching is skipped entirely when the head is
|
|
2530
|
+
* already anchored — the OAuth Claude Code path caches its own instruction
|
|
2531
|
+
* block at buildAnthropicSystemBlocks, and via the canonical tools → system
|
|
2532
|
+
* order that single system breakpoint already caches every preceding tool. Re-
|
|
2533
|
+
* anchoring there would be redundant, would change the OAuth wire, and could
|
|
2534
|
+
* push a tool-heavy request over the 4-breakpoint budget, so the general
|
|
2535
|
+
* API-key path (nothing cached upstream) is the only one decorated here.
|
|
2536
|
+
*
|
|
2537
|
+
* Runs after the byte-stability plane (planStableAnthropicSystem /
|
|
2538
|
+
* planStableAnthropicTools), which hands back fresh block/tool copies each turn
|
|
2539
|
+
* and keys tool identity off a fingerprint that excludes cache_control — so
|
|
2540
|
+
* decorating here is byte-stable across turns and never forces a re-baseline.
|
|
2541
|
+
*/
|
|
2542
|
+
function applyHeadCaching(systemBlocks, tools, cacheControl) {
|
|
2543
|
+
if (!cacheControl) return;
|
|
2544
|
+
if ((systemBlocks?.some((block) => block.cache_control != null) ?? false) || (tools?.some((tool) => tool.cache_control != null) ?? false)) return;
|
|
2545
|
+
if (tools && tools.length > 0) for (let index = tools.length - 1; index >= 0; index--) {
|
|
2546
|
+
const tool = tools[index];
|
|
2547
|
+
if (!tool || tool.defer_loading) continue;
|
|
2548
|
+
tool.cache_control = cloneAnthropicCacheControl(cacheControl);
|
|
2549
|
+
break;
|
|
2550
|
+
}
|
|
2551
|
+
if (systemBlocks && systemBlocks.length > 0) {
|
|
2552
|
+
const lastBlock = systemBlocks[systemBlocks.length - 1];
|
|
2553
|
+
if (lastBlock) lastBlock.cache_control = cloneAnthropicCacheControl(cacheControl);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2336
2556
|
function usesAdaptiveThinkingTagOnly(model) {
|
|
2337
2557
|
const thinking = model.thinking;
|
|
2338
2558
|
if (thinking?.mode !== "anthropic-adaptive") return false;
|
|
@@ -2369,8 +2589,227 @@ function extractClaudeCodeFirstUserMessageText(messages) {
|
|
|
2369
2589
|
}
|
|
2370
2590
|
return "";
|
|
2371
2591
|
}
|
|
2592
|
+
const MAX_ANTHROPIC_CONTROL_STATES = 16;
|
|
2593
|
+
function resetAnthropicControlState(state) {
|
|
2594
|
+
state.declaredTools = void 0;
|
|
2595
|
+
state.activeToolNames.clear();
|
|
2596
|
+
state.stableSystemBlocks = void 0;
|
|
2597
|
+
state.systemFingerprint = void 0;
|
|
2598
|
+
state.controlTransitions = [];
|
|
2599
|
+
state.baseEffort = void 0;
|
|
2600
|
+
state.baseEffortWire = void 0;
|
|
2601
|
+
state.currentEffort = void 0;
|
|
2602
|
+
}
|
|
2603
|
+
function anthropicControlMessageProjection(message) {
|
|
2604
|
+
if (message.role !== "assistant" || !Array.isArray(message.content)) return message;
|
|
2605
|
+
return {
|
|
2606
|
+
...message,
|
|
2607
|
+
content: message.content.filter((block) => block.type !== "thinking" && block.type !== "redacted_thinking")
|
|
2608
|
+
};
|
|
2609
|
+
}
|
|
2610
|
+
function getAnthropicControlState(state, sessionId, system, messages) {
|
|
2611
|
+
if (!state) return void 0;
|
|
2612
|
+
const root = messages[0];
|
|
2613
|
+
const fingerprint = String(Bun.hash(JSON.stringify([
|
|
2614
|
+
sessionId ?? "",
|
|
2615
|
+
system?.map((block) => block.text) ?? null,
|
|
2616
|
+
root ? anthropicControlMessageProjection(root) : null
|
|
2617
|
+
])));
|
|
2618
|
+
const existing = state.controlStates.get(fingerprint);
|
|
2619
|
+
if (existing) {
|
|
2620
|
+
state.controlStates.delete(fingerprint);
|
|
2621
|
+
state.controlStates.set(fingerprint, existing);
|
|
2622
|
+
return existing;
|
|
2623
|
+
}
|
|
2624
|
+
const created = createAnthropicControlState();
|
|
2625
|
+
state.controlStates.set(fingerprint, created);
|
|
2626
|
+
if (state.controlStates.size > MAX_ANTHROPIC_CONTROL_STATES) {
|
|
2627
|
+
const oldest = state.controlStates.keys().next().value;
|
|
2628
|
+
if (oldest !== void 0) state.controlStates.delete(oldest);
|
|
2629
|
+
}
|
|
2630
|
+
return created;
|
|
2631
|
+
}
|
|
2632
|
+
/** Fingerprint of the wire message a control transition is attached after. */
|
|
2633
|
+
function anthropicControlAnchor(messages, messageCount) {
|
|
2634
|
+
if (messageCount === 0) return "";
|
|
2635
|
+
const message = messages[messageCount - 1];
|
|
2636
|
+
return message ? String(Bun.hash(JSON.stringify(anthropicControlMessageProjection(message)))) : "";
|
|
2637
|
+
}
|
|
2638
|
+
/**
|
|
2639
|
+
* Discard the control baseline when the request no longer continues the
|
|
2640
|
+
* conversation it was captured for: a different model, or a wire history that
|
|
2641
|
+
* shrank or was rewritten under a recorded transition (compaction, branch
|
|
2642
|
+
* switch, `/clear`). The next request re-baselines from its own payload.
|
|
2643
|
+
*/
|
|
2644
|
+
function syncAnthropicControlState(state, messages) {
|
|
2645
|
+
for (const transition of state.controlTransitions) if (transition.messageCount > messages.length || transition.anchor !== anthropicControlAnchor(messages, transition.messageCount)) {
|
|
2646
|
+
resetAnthropicControlState(state);
|
|
2647
|
+
return;
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
/**
|
|
2651
|
+
* Keep the top-level `system` array byte-stable across a session. The blocks
|
|
2652
|
+
* captured on the first request are replayed verbatim (with the current
|
|
2653
|
+
* request's cache breakpoints) while their text is unchanged. A text change
|
|
2654
|
+
* re-baselines instead of duplicating the prompt as a mid-conversation
|
|
2655
|
+
* system message: omp's system prompt is one rendered segment that embeds
|
|
2656
|
+
* the tool roster, so replaying a second copy on every later request would
|
|
2657
|
+
* cost the full prompt again per change. The prefix rewrite is absorbed by
|
|
2658
|
+
* `prefix_mismatch_behavior: "drop_block"` and one cache miss.
|
|
2659
|
+
*/
|
|
2660
|
+
function planStableAnthropicSystem(current, state, enabled) {
|
|
2661
|
+
if (!state || !enabled) return current;
|
|
2662
|
+
const fingerprint = JSON.stringify(current?.map((block) => block.text) ?? null);
|
|
2663
|
+
if (state.systemFingerprint !== fingerprint) {
|
|
2664
|
+
resetAnthropicControlState(state);
|
|
2665
|
+
state.systemFingerprint = fingerprint;
|
|
2666
|
+
state.stableSystemBlocks = current?.map((block) => ({
|
|
2667
|
+
type: block.type,
|
|
2668
|
+
text: block.text
|
|
2669
|
+
}));
|
|
2670
|
+
}
|
|
2671
|
+
return state.stableSystemBlocks?.map((block, index) => {
|
|
2672
|
+
const cacheControl = current?.[index]?.cache_control;
|
|
2673
|
+
return cacheControl ? {
|
|
2674
|
+
...block,
|
|
2675
|
+
cache_control: cloneAnthropicCacheControl(cacheControl)
|
|
2676
|
+
} : { ...block };
|
|
2677
|
+
});
|
|
2678
|
+
}
|
|
2679
|
+
function anthropicToolDefinitionKey(tool) {
|
|
2680
|
+
const stable = { ...tool };
|
|
2681
|
+
delete stable.defer_loading;
|
|
2682
|
+
delete stable.description;
|
|
2683
|
+
return JSON.stringify(stable);
|
|
2684
|
+
}
|
|
2685
|
+
function cloneAnthropicTools(tools) {
|
|
2686
|
+
return tools.map((tool) => ({ ...tool }));
|
|
2687
|
+
}
|
|
2688
|
+
function recordAnthropicControlTransition(state, messages, messageCount, content, effort) {
|
|
2689
|
+
const existing = state.controlTransitions.findLast((transition) => transition.messageCount === messageCount);
|
|
2690
|
+
if (existing) {
|
|
2691
|
+
existing.content.push(...content);
|
|
2692
|
+
if (effort !== void 0) existing.effort = effort;
|
|
2693
|
+
return;
|
|
2694
|
+
}
|
|
2695
|
+
state.controlTransitions.push({
|
|
2696
|
+
messageCount,
|
|
2697
|
+
anchor: anthropicControlAnchor(messages, messageCount),
|
|
2698
|
+
content,
|
|
2699
|
+
effort
|
|
2700
|
+
});
|
|
2701
|
+
}
|
|
2702
|
+
/**
|
|
2703
|
+
* Keep the top-level `tools` array byte-stable across a session. Tools that
|
|
2704
|
+
* leave the active set are withdrawn with `tool_removal`; tools that join are
|
|
2705
|
+
* appended with `defer_loading: true` (not part of the checked prefix until
|
|
2706
|
+
* referenced) and offered with `tool_addition`. A changed definition for an
|
|
2707
|
+
* already-declared name cannot be expressed as a control and re-baselines.
|
|
2708
|
+
*/
|
|
2709
|
+
function planStableAnthropicTools(current, messages, state, enabled) {
|
|
2710
|
+
if (!state || !enabled || !current) return current;
|
|
2711
|
+
if (!state.declaredTools) {
|
|
2712
|
+
state.declaredTools = cloneAnthropicTools(current);
|
|
2713
|
+
state.activeToolNames = new Set(current.map((tool) => tool.name));
|
|
2714
|
+
return cloneAnthropicTools(state.declaredTools);
|
|
2715
|
+
}
|
|
2716
|
+
const declaredByName = new Map(state.declaredTools.map((tool) => [tool.name, tool]));
|
|
2717
|
+
for (const tool of current) {
|
|
2718
|
+
const declared = declaredByName.get(tool.name);
|
|
2719
|
+
if (declared && anthropicToolDefinitionKey(declared) !== anthropicToolDefinitionKey(tool)) {
|
|
2720
|
+
resetAnthropicControlState(state);
|
|
2721
|
+
state.declaredTools = cloneAnthropicTools(current);
|
|
2722
|
+
state.activeToolNames = new Set(current.map((candidate) => candidate.name));
|
|
2723
|
+
return cloneAnthropicTools(state.declaredTools);
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
const nextActive = new Set(current.map((tool) => tool.name));
|
|
2727
|
+
const changes = [];
|
|
2728
|
+
for (const activeName of state.activeToolNames) {
|
|
2729
|
+
if (nextActive.has(activeName)) continue;
|
|
2730
|
+
changes.push({
|
|
2731
|
+
type: "tool_removal",
|
|
2732
|
+
tool: {
|
|
2733
|
+
type: "tool_reference",
|
|
2734
|
+
name: activeName
|
|
2735
|
+
}
|
|
2736
|
+
});
|
|
2737
|
+
}
|
|
2738
|
+
for (const tool of current) {
|
|
2739
|
+
if (state.activeToolNames.has(tool.name)) continue;
|
|
2740
|
+
if (!declaredByName.has(tool.name)) {
|
|
2741
|
+
const deferred = {
|
|
2742
|
+
...tool,
|
|
2743
|
+
defer_loading: true
|
|
2744
|
+
};
|
|
2745
|
+
state.declaredTools.push(deferred);
|
|
2746
|
+
declaredByName.set(tool.name, deferred);
|
|
2747
|
+
}
|
|
2748
|
+
changes.push({
|
|
2749
|
+
type: "tool_addition",
|
|
2750
|
+
tool: {
|
|
2751
|
+
type: "tool_reference",
|
|
2752
|
+
name: tool.name
|
|
2753
|
+
}
|
|
2754
|
+
});
|
|
2755
|
+
}
|
|
2756
|
+
if (changes.length > 0) recordAnthropicControlTransition(state, messages, messages.length, changes);
|
|
2757
|
+
state.activeToolNames = nextActive;
|
|
2758
|
+
return cloneAnthropicTools(state.declaredTools);
|
|
2759
|
+
}
|
|
2760
|
+
/**
|
|
2761
|
+
* Keep top-level `output_config.effort` byte-stable across a session and carry
|
|
2762
|
+
* later changes as per-message effort. Anthropic applies a system message's
|
|
2763
|
+
* `output_config.effort` from the next `user` turn on, so the control is
|
|
2764
|
+
* anchored before the latest user message to take effect on this response.
|
|
2765
|
+
*/
|
|
2766
|
+
function planStableAnthropicEffort(current, messages, state, enabled) {
|
|
2767
|
+
if (!state || !enabled) return current;
|
|
2768
|
+
const effective = current ?? "high";
|
|
2769
|
+
if (state.baseEffort === void 0) {
|
|
2770
|
+
state.baseEffort = effective;
|
|
2771
|
+
state.baseEffortWire = current;
|
|
2772
|
+
state.currentEffort = effective;
|
|
2773
|
+
return current;
|
|
2774
|
+
}
|
|
2775
|
+
if (state.currentEffort !== effective) {
|
|
2776
|
+
const lastUserIndex = messages.findLastIndex((message) => message.role === "user");
|
|
2777
|
+
recordAnthropicControlTransition(state, messages, lastUserIndex >= 0 ? lastUserIndex : messages.length, [], effective);
|
|
2778
|
+
state.currentEffort = effective;
|
|
2779
|
+
}
|
|
2780
|
+
return state.baseEffortWire;
|
|
2781
|
+
}
|
|
2782
|
+
function materializeAnthropicControlTransitions(messages, state) {
|
|
2783
|
+
if (!state || state.controlTransitions.length === 0) return messages;
|
|
2784
|
+
const result = messages.slice();
|
|
2785
|
+
const ordered = state.controlTransitions.toSorted((a, b) => a.messageCount - b.messageCount);
|
|
2786
|
+
let offset = 0;
|
|
2787
|
+
for (const transition of ordered) {
|
|
2788
|
+
const index = Math.min(transition.messageCount + offset, result.length);
|
|
2789
|
+
const previous = result[index - 1];
|
|
2790
|
+
if (previous?.role === "system" && previous.clear_at === void 0) {
|
|
2791
|
+
const content = typeof previous.content === "string" ? [{
|
|
2792
|
+
type: "text",
|
|
2793
|
+
text: previous.content
|
|
2794
|
+
}, ...transition.content] : [...previous.content, ...transition.content];
|
|
2795
|
+
result[index - 1] = {
|
|
2796
|
+
...previous,
|
|
2797
|
+
content,
|
|
2798
|
+
...transition.effort === void 0 ? {} : { output_config: { effort: transition.effort } }
|
|
2799
|
+
};
|
|
2800
|
+
continue;
|
|
2801
|
+
}
|
|
2802
|
+
result.splice(index, 0, {
|
|
2803
|
+
role: "system",
|
|
2804
|
+
content: transition.content.map((block) => ({ ...block })),
|
|
2805
|
+
...transition.effort === void 0 ? {} : { output_config: { effort: transition.effort } }
|
|
2806
|
+
});
|
|
2807
|
+
offset++;
|
|
2808
|
+
}
|
|
2809
|
+
return result;
|
|
2810
|
+
}
|
|
2372
2811
|
function buildParams(model, context, isOAuthToken, options, buildOptions) {
|
|
2373
|
-
const { disableStrictTools, useUmansGatewayWebSearch, forceDemoteUnsignedThinking, supportsEagerToolInputStreaming, fallbacks = options?.fallbacks } = buildOptions;
|
|
2812
|
+
const { disableStrictTools, useUmansGatewayWebSearch, forceDemoteUnsignedThinking, supportsEagerToolInputStreaming, prefixMismatchBehavior, dropAllThinking, droppedThinkingBlocks, providerSessionState, fallbacks = options?.fallbacks } = buildOptions;
|
|
2374
2813
|
const effectiveModel = forceDemoteUnsignedThinking && model.compat.replayUnsignedThinking ? {
|
|
2375
2814
|
...model,
|
|
2376
2815
|
compat: {
|
|
@@ -2379,14 +2818,15 @@ function buildParams(model, context, isOAuthToken, options, buildOptions) {
|
|
|
2379
2818
|
}
|
|
2380
2819
|
} : model;
|
|
2381
2820
|
const { cacheControl } = getCacheControl(model, options?.cacheRetention);
|
|
2382
|
-
const shouldInjectClaudeCodeInstruction = isOAuthToken &&
|
|
2821
|
+
const shouldInjectClaudeCodeInstruction = isOAuthToken && model.compat.injectClaudeCodeInstruction !== false;
|
|
2383
2822
|
const firstUserMessageText = shouldInjectClaudeCodeInstruction ? extractClaudeCodeFirstUserMessageText(context.messages) : "";
|
|
2384
|
-
|
|
2823
|
+
let systemBlocks = buildAnthropicSystemBlocks(context.systemPrompt, {
|
|
2385
2824
|
includeClaudeCodeInstruction: shouldInjectClaudeCodeInstruction,
|
|
2386
|
-
firstUserMessageText
|
|
2825
|
+
firstUserMessageText,
|
|
2826
|
+
cacheControl
|
|
2387
2827
|
});
|
|
2388
2828
|
let tools;
|
|
2389
|
-
if (context.tools) tools = convertTools(context.tools, isOAuthToken, disableStrictTools
|
|
2829
|
+
if (context.tools) tools = convertTools(context.tools, isOAuthToken, disableStrictTools, supportsEagerToolInputStreaming, model.compat.escapeBuiltinToolNames, useUmansGatewayWebSearch);
|
|
2390
2830
|
else if (isOAuthToken) tools = [];
|
|
2391
2831
|
const metadataAccountId = readAnthropicMetadataAccountId(options?.metadata);
|
|
2392
2832
|
const metadataUserId = resolveAnthropicMetadataUserId(readMetadataString(options?.metadata, "user_id") ?? (model.provider === "kimi-code" ? getOpenAIPromptCacheKey(options) : void 0), isOAuthToken, options?.sessionId, metadataAccountId);
|
|
@@ -2417,19 +2857,36 @@ function buildParams(model, context, isOAuthToken, options, buildOptions) {
|
|
|
2417
2857
|
else thinking = { type: "disabled" };
|
|
2418
2858
|
}
|
|
2419
2859
|
}
|
|
2420
|
-
|
|
2860
|
+
if (prefixMismatchBehavior) {
|
|
2861
|
+
if (!thinking && model.thinking?.mode === "anthropic-adaptive") thinking = { type: "adaptive" };
|
|
2862
|
+
if (thinking?.type === "adaptive" || thinking?.type === "enabled") thinking.block_binding = { prefix_mismatch_behavior: prefixMismatchBehavior };
|
|
2863
|
+
}
|
|
2864
|
+
const contextManagement = !options?.client && model.compat.supportsContextManagement !== false && (thinking?.type === "adaptive" || thinking?.type === "enabled") ? { edits: [{
|
|
2421
2865
|
type: "clear_thinking_20251015",
|
|
2422
2866
|
keep: "all"
|
|
2423
2867
|
}] } : void 0;
|
|
2868
|
+
let wireMessages = convertAnthropicMessages(context.messages, effectiveModel, isOAuthToken, {
|
|
2869
|
+
serverSideFallbackEnabled: !!fallbacks?.length,
|
|
2870
|
+
dropAllThinking,
|
|
2871
|
+
droppedThinkingBlocks
|
|
2872
|
+
});
|
|
2873
|
+
const controlState = getAnthropicControlState(providerSessionState, options?.sessionId, systemBlocks, wireMessages);
|
|
2874
|
+
if (controlState) syncAnthropicControlState(controlState, wireMessages);
|
|
2875
|
+
systemBlocks = planStableAnthropicSystem(systemBlocks, controlState, model.compat.supportsMidConversationSystem);
|
|
2876
|
+
tools = planStableAnthropicTools(tools, wireMessages, controlState, model.compat.supportsMidConversationToolChanges);
|
|
2877
|
+
applyHeadCaching(systemBlocks, tools, cacheControl);
|
|
2878
|
+
const topLevelEffort = planStableAnthropicEffort(outputConfigEffort, wireMessages, controlState, model.compat.supportsPerMessageEffort);
|
|
2879
|
+
wireMessages = materializeAnthropicControlTransitions(wireMessages, controlState);
|
|
2424
2880
|
const outputConfigEntries = {};
|
|
2425
|
-
if (
|
|
2881
|
+
if (topLevelEffort && model.compat.supportsOutputEffort) outputConfigEntries.effort = topLevelEffort;
|
|
2426
2882
|
if (options?.taskBudget) outputConfigEntries.task_budget = options.taskBudget;
|
|
2427
2883
|
const outputConfig = Object.keys(outputConfigEntries).length ? outputConfigEntries : void 0;
|
|
2428
2884
|
const modelMaxTokens = model.maxTokens ?? 64e3;
|
|
2429
2885
|
const maxOutputTokens = isOAuthToken ? Math.min(CLAUDE_CODE_MAX_OUTPUT_TOKENS, modelMaxTokens) : modelMaxTokens;
|
|
2886
|
+
const vertexControlBetas = isVertexRawPredictUrl(model.baseUrl) ? resolveAnthropicControlBetas(model, prefixMismatchBehavior) : [];
|
|
2430
2887
|
const params = {
|
|
2431
2888
|
model: options?.requestModelId ?? model.requestModelId ?? model.id,
|
|
2432
|
-
messages:
|
|
2889
|
+
messages: wireMessages,
|
|
2433
2890
|
...systemBlocks && { system: systemBlocks },
|
|
2434
2891
|
...tools !== void 0 && { tools },
|
|
2435
2892
|
...metadata && { metadata },
|
|
@@ -2438,6 +2895,7 @@ function buildParams(model, context, isOAuthToken, options, buildOptions) {
|
|
|
2438
2895
|
...contextManagement && { context_management: contextManagement },
|
|
2439
2896
|
...outputConfig && { output_config: outputConfig },
|
|
2440
2897
|
...fallbacks?.length ? { fallbacks } : {},
|
|
2898
|
+
...vertexControlBetas.length > 0 ? { anthropic_beta: vertexControlBetas } : {},
|
|
2441
2899
|
stream: true
|
|
2442
2900
|
};
|
|
2443
2901
|
const thinkingType = params.thinking?.type;
|
|
@@ -2489,6 +2947,7 @@ function buildToolResultBlock(model, msg, hoistedImages) {
|
|
|
2489
2947
|
for (const block of content) if (block.type === "image") hoistedImages.push(block);
|
|
2490
2948
|
content = content.filter((block) => block.type === "text");
|
|
2491
2949
|
}
|
|
2950
|
+
if (Array.isArray(content) && content.length === 0) content = "";
|
|
2492
2951
|
content = ensureErrorToolResultWireContent(content, msg.isError);
|
|
2493
2952
|
const block = {
|
|
2494
2953
|
type: "tool_result",
|
|
@@ -2539,28 +2998,50 @@ function toWellFormedDeep(value) {
|
|
|
2539
2998
|
* that don't send the beta.
|
|
2540
2999
|
*/
|
|
2541
3000
|
function convertAnthropicMessages(messages, model, isOAuthToken, opts) {
|
|
2542
|
-
const
|
|
3001
|
+
const developerParams = [];
|
|
2543
3002
|
const params = [];
|
|
2544
3003
|
const transformedMessages = transformMessages(messages, model, normalizeToolCallId);
|
|
2545
3004
|
for (let i = 0; i < transformedMessages.length; i++) {
|
|
2546
3005
|
const msg = transformedMessages[i];
|
|
2547
3006
|
if (msg.role === "user" || msg.role === "developer") {
|
|
2548
|
-
|
|
3007
|
+
const payload = msg.role === "developer" && msg.providerPayload?.type === "anthropicMessage" ? msg.providerPayload : void 0;
|
|
3008
|
+
const hasProviderControls = payload?.clearAt !== void 0 || payload?.effort !== void 0 || payload?.toolChanges !== void 0 && payload.toolChanges.length > 0;
|
|
2549
3009
|
let content;
|
|
2550
3010
|
if (typeof msg.content === "string") {
|
|
2551
|
-
if (msg.content.trim().length === 0)
|
|
2552
|
-
|
|
3011
|
+
if (msg.content.trim().length === 0) {
|
|
3012
|
+
if (!hasProviderControls) continue;
|
|
3013
|
+
content = [];
|
|
3014
|
+
} else content = msg.content.toWellFormed();
|
|
2553
3015
|
} else {
|
|
2554
3016
|
const contentBlocks = convertContentBlocks(msg.content, model.input.includes("image"));
|
|
2555
3017
|
if (typeof contentBlocks === "string") {
|
|
2556
|
-
if (contentBlocks.trim().length === 0)
|
|
2557
|
-
|
|
3018
|
+
if (contentBlocks.trim().length === 0) {
|
|
3019
|
+
if (!hasProviderControls) continue;
|
|
3020
|
+
content = [];
|
|
3021
|
+
} else content = contentBlocks;
|
|
2558
3022
|
} else {
|
|
2559
|
-
if (contentBlocks.length === 0) continue;
|
|
3023
|
+
if (contentBlocks.length === 0 && !hasProviderControls) continue;
|
|
2560
3024
|
content = contentBlocks;
|
|
2561
3025
|
}
|
|
2562
3026
|
}
|
|
2563
|
-
if (
|
|
3027
|
+
if (payload?.toolChanges && model.compat.supportsMidConversationToolChanges) {
|
|
3028
|
+
const blocks = typeof content === "string" ? [{
|
|
3029
|
+
type: "text",
|
|
3030
|
+
text: content
|
|
3031
|
+
}] : content;
|
|
3032
|
+
for (const change of payload.toolChanges) blocks.push({
|
|
3033
|
+
type: change.type,
|
|
3034
|
+
tool: {
|
|
3035
|
+
type: "tool_reference",
|
|
3036
|
+
name: encodeAnthropicToolName(change.name, isOAuthToken, model.compat.escapeBuiltinToolNames)
|
|
3037
|
+
}
|
|
3038
|
+
});
|
|
3039
|
+
content = blocks;
|
|
3040
|
+
}
|
|
3041
|
+
if (msg.role === "developer") developerParams.push({
|
|
3042
|
+
index: params.length,
|
|
3043
|
+
payload
|
|
3044
|
+
});
|
|
2564
3045
|
params.push({
|
|
2565
3046
|
role: "user",
|
|
2566
3047
|
content
|
|
@@ -2575,6 +3056,7 @@ function convertAnthropicMessages(messages, model, isOAuthToken, opts) {
|
|
|
2575
3056
|
text: block.text.toWellFormed()
|
|
2576
3057
|
});
|
|
2577
3058
|
} else if (block.type === "thinking") {
|
|
3059
|
+
if (opts?.dropAllThinking || block.thinkingSignature && opts?.droppedThinkingBlocks?.has(`thinking:${block.thinkingSignature}`)) continue;
|
|
2578
3060
|
if (hasSignedThinking) {
|
|
2579
3061
|
if (!block.thinkingSignature || block.thinkingSignature.trim().length === 0) {
|
|
2580
3062
|
if (block.thinking.trim().length === 0) continue;
|
|
@@ -2608,6 +3090,7 @@ function convertAnthropicMessages(messages, model, isOAuthToken, opts) {
|
|
|
2608
3090
|
signature: block.thinkingSignature
|
|
2609
3091
|
});
|
|
2610
3092
|
} else if (block.type === "redactedThinking") {
|
|
3093
|
+
if (opts?.dropAllThinking || opts?.droppedThinkingBlocks?.has(`redacted:${block.data}`)) continue;
|
|
2611
3094
|
if (block.data.trim().length === 0) continue;
|
|
2612
3095
|
blocks.push({
|
|
2613
3096
|
type: "redacted_thinking",
|
|
@@ -2630,7 +3113,7 @@ function convertAnthropicMessages(messages, model, isOAuthToken, opts) {
|
|
|
2630
3113
|
let sawToolUse = false;
|
|
2631
3114
|
let needsPartition = false;
|
|
2632
3115
|
for (const block of blocks) if (block.type === "tool_use") sawToolUse = true;
|
|
2633
|
-
else if (sawToolUse) {
|
|
3116
|
+
else if (sawToolUse && block.type !== "thinking" && block.type !== "redacted_thinking") {
|
|
2634
3117
|
needsPartition = true;
|
|
2635
3118
|
break;
|
|
2636
3119
|
}
|
|
@@ -2668,15 +3151,40 @@ function convertAnthropicMessages(messages, model, isOAuthToken, opts) {
|
|
|
2668
3151
|
});
|
|
2669
3152
|
}
|
|
2670
3153
|
}
|
|
2671
|
-
if (
|
|
3154
|
+
if (developerParams.length > 0 && model.compat.supportsMidConversationSystem) for (const developer of developerParams.toReversed()) {
|
|
3155
|
+
const idx = developer.index;
|
|
2672
3156
|
const followsUser = idx > 0 && params[idx - 1]?.role === "user";
|
|
2673
3157
|
const next = params[idx + 1];
|
|
2674
3158
|
const lastOrBeforeAssistant = idx === params.length - 1 || next?.role === "assistant";
|
|
2675
3159
|
const content = params[idx].content;
|
|
2676
|
-
const
|
|
2677
|
-
|
|
3160
|
+
const systemCompatible = typeof content === "string" || content.every((block) => block.type === "text" || block.type === "tool_addition" || block.type === "tool_removal");
|
|
3161
|
+
const effortOnly = developer.payload?.effort !== void 0 && Array.isArray(content) && content.length === 0;
|
|
3162
|
+
if (!(followsUser && lastOrBeforeAssistant && systemCompatible || effortOnly)) continue;
|
|
3163
|
+
const turnScoped = developer.payload?.clearAt === "next_user_message" && model.compat.supportsTurnScopedSystem;
|
|
3164
|
+
const hasEffort = developer.payload?.effort !== void 0 && model.compat.supportsPerMessageEffort;
|
|
3165
|
+
const hasToolChanges = (developer.payload?.toolChanges?.length ?? 0) > 0;
|
|
3166
|
+
if (turnScoped && (hasEffort || hasToolChanges) && Array.isArray(content)) {
|
|
3167
|
+
const scopedContent = content.filter((block) => block.type === "text");
|
|
3168
|
+
const controlContent = content.filter((block) => block.type !== "text");
|
|
3169
|
+
if (scopedContent.length > 0) {
|
|
3170
|
+
params[idx] = {
|
|
3171
|
+
role: "system",
|
|
3172
|
+
content: scopedContent,
|
|
3173
|
+
clear_at: "next_user_message"
|
|
3174
|
+
};
|
|
3175
|
+
params.splice(idx + 1, 0, {
|
|
3176
|
+
role: "system",
|
|
3177
|
+
content: controlContent,
|
|
3178
|
+
...hasEffort ? { output_config: { effort: developer.payload?.effort } } : {}
|
|
3179
|
+
});
|
|
3180
|
+
continue;
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
params[idx] = {
|
|
2678
3184
|
role: "system",
|
|
2679
|
-
content
|
|
3185
|
+
content,
|
|
3186
|
+
...turnScoped && !hasEffort && !hasToolChanges ? { clear_at: "next_user_message" } : {},
|
|
3187
|
+
...hasEffort ? { output_config: { effort: developer.payload?.effort } } : {}
|
|
2680
3188
|
};
|
|
2681
3189
|
}
|
|
2682
3190
|
for (let i = params.length - 1; i > 0; i--) if (params[i].role === "assistant" && params[i - 1]?.role === "assistant") params.splice(i, 0, {
|
|
@@ -3092,7 +3600,8 @@ function convertTools(tools, isOAuthToken, disableStrictTools = false, supportsE
|
|
|
3092
3600
|
description: tool.description || "",
|
|
3093
3601
|
input_schema: plan.inputSchema,
|
|
3094
3602
|
...supportsEagerToolInputStreaming ? { eager_input_streaming: true } : {},
|
|
3095
|
-
...plan.strict ? { strict: true } : {}
|
|
3603
|
+
...plan.strict ? { strict: true } : {},
|
|
3604
|
+
...tool.deferLoading ? { defer_loading: true } : {}
|
|
3096
3605
|
};
|
|
3097
3606
|
});
|
|
3098
3607
|
}
|