@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.
Files changed (120) hide show
  1. package/README.md +1 -1
  2. package/THIRD_PARTY_NOTICES.md +9 -3
  3. package/lib/{abort-Cwwm4Err.mjs → abort-Caqff3M6.mjs} +2 -2
  4. package/lib/alibaba-coding-plan-DTupMiAi.mjs +73 -0
  5. package/lib/alibaba-token-plan-CHGyWOfX.mjs +46 -0
  6. package/lib/alibaba-token-plan-Dj3OZhEE.mjs +82 -0
  7. package/lib/{amazon-bedrock-TVMpUTRG.mjs → amazon-bedrock-DbFSYXfJ.mjs} +117 -38
  8. package/lib/{anthropic-BL6LFDQS.mjs → anthropic-CTJ3IQVa.mjs} +675 -166
  9. package/lib/anthropic-CXfWlp-x.mjs +105 -0
  10. package/lib/{aws-credentials-B20dliS7.mjs → anthropic-wire-CKuhDwZ1.mjs} +74 -14
  11. package/lib/{api-key-login-CIDnXeYd.mjs → api-key-validation-CGCJFbFr.mjs} +27 -68
  12. package/lib/{azure-openai-responses-BkhsLmN3.mjs → azure-openai-responses-ChFbWaGj.mjs} +27 -16
  13. package/lib/{browser-render-CmgvSNte.mjs → browser-render-9o0Rknop.mjs} +4 -4
  14. package/lib/bun-shim.mjs +71 -2
  15. package/lib/{bundled-references-ChZSPDFw.mjs → bundled-references-DY3EJxZV.mjs} +6 -5
  16. package/lib/cline-pass-Bwg3esu9.mjs +44 -0
  17. package/lib/cloudflare-ai-gateway-BupNXyKK.mjs +35 -0
  18. package/lib/cloudflare-ai-gateway-EWo0VkP5.mjs +44 -0
  19. package/lib/collapse-DOR8sOGf.mjs +2304 -0
  20. package/lib/coreweave-C82HrLpb.mjs +31 -0
  21. package/lib/coreweave-Ct8cF-da.mjs +14 -0
  22. package/lib/{cursor-B6HcmplF.mjs → cursor-B95LzVWV.mjs} +11 -3
  23. package/lib/{cursor-CRpLpaZ3.mjs → cursor-DJV_dcgB.mjs} +887 -1784
  24. package/lib/{cursor-B8m6SqAH.mjs → cursor-LKGjucn2.mjs} +48 -38
  25. package/lib/cursor-proto-B8Wj8bv9.mjs +10513 -0
  26. package/lib/{deterministic-id-D-yIV_eI.mjs → deterministic-id-CUEIMSqR.mjs} +1 -1
  27. package/lib/devin-BMTdx_hx.mjs +316 -0
  28. package/lib/{devin-DUAfvBsW.mjs → devin-DSp0Rw_E.mjs} +172 -86
  29. package/lib/devin-ExGIghmx.mjs +69 -0
  30. package/lib/devin-proto-Br8fdyNl.mjs +2888 -0
  31. package/lib/{dom-CawWi8fa.mjs → dom-DG3sPESc.mjs} +8 -8
  32. package/lib/effort-BdtQMN-_.mjs +23 -0
  33. package/lib/{error-C-f_Wnw4.mjs → error-CORgGg5a.mjs} +275 -154
  34. package/lib/{event-stream-Dh2guZxS.mjs → event-stream-ulcDenZD.mjs} +20 -4
  35. package/lib/{gemini-headers-DKUShltF.mjs → gemini-headers-Co9cVvex.mjs} +2 -2
  36. package/lib/{github-copilot-suDymKrx.mjs → github-copilot-Dstq1D3s.mjs} +69 -29
  37. package/lib/github-copilot-headers-DOh1gt_w.mjs +312 -0
  38. package/lib/gitlab-duo-DSCMrU0m.mjs +11 -0
  39. package/lib/google-CtsKkOQK.mjs +38 -0
  40. package/lib/google-antigravity-z-5KsEci.mjs +252 -0
  41. package/lib/{google-auth-DYJLM792.mjs → google-auth-ieLBaneO.mjs} +4 -4
  42. package/lib/{google-gemini-cli-8BT513Ul.mjs → google-gemini-cli-C6NE5mWz.mjs} +28 -54
  43. package/lib/{google-gemini-cli-D6cSmfvB.mjs → google-gemini-cli-CAIPSl7e.mjs} +23 -29
  44. package/lib/google-oauth-shared-DhMllAkt.mjs +53 -0
  45. package/lib/{google-shared-CVbHK5vZ.mjs → google-shared-B0aNCYEH.mjs} +140 -44
  46. package/lib/{google-validation-Cgbn3tWJ.mjs → google-validation-BEkNs-Bx.mjs} +1 -1
  47. package/lib/{google-vertex-Bui-ypAe.mjs → google-vertex-Bbd1tYNc.mjs} +8 -8
  48. package/lib/hosts-00rjRzUD.mjs +203 -0
  49. package/lib/id-AL5obQzR.mjs +71 -0
  50. package/lib/{idle-iterator-CYAxUkSD.mjs → idle-iterator-DlUkEfzW.mjs} +3 -3
  51. package/lib/index.mjs +587 -5266
  52. package/lib/kilo-ChJL54wq.mjs +81 -0
  53. package/lib/kimi-C2c_Zq8A.mjs +67 -0
  54. package/lib/{launch-BmgEUycu.mjs → launch-DKDH71En.mjs} +1 -1
  55. package/lib/markit-CmRfm4E2.mjs +9885 -0
  56. package/lib/models-DnXMYGcJ.mjs +381604 -0
  57. package/lib/muse-code-Di1VZmB1.mjs +143 -0
  58. package/lib/{ollama-Df9ce-Cp.mjs → ollama-B8ic3sEp.mjs} +15 -30
  59. package/lib/{openai-codex-CAVI3Me-.mjs → openai-codex-DuJNC99x.mjs} +29 -99
  60. package/lib/{openai-codex-responses-BcnOotRB.mjs → openai-codex-responses-BL29nh9K.mjs} +204 -116
  61. package/lib/{openai-completions-Bq4WT47M.mjs → openai-completions-BK2f2dBv.mjs} +152 -82
  62. package/lib/openai-configuration-update-xMYUjaK_.mjs +150 -0
  63. package/lib/{openai-reasoning-fallback-DXsfiSXO.mjs → openai-reasoning-fallback-BdB3RCbj.mjs} +106 -12
  64. package/lib/{openai-responses-Mq_-PjvE.mjs → openai-responses-CGQPlIIy.mjs} +76 -82
  65. package/lib/{perplexity-XgLF73E7.mjs → perplexity-TBjz3VMB.mjs} +52 -9
  66. package/lib/{pkce-BlQikGPu.mjs → pkce-BYjmugmw.mjs} +1 -1
  67. package/lib/protobuf-aab1UGVn.mjs +717 -0
  68. package/lib/{provider-response-C6vcbQyO.mjs → provider-response-SqKSkkUc.mjs} +1 -1
  69. package/lib/{proxy-D9lm7ONA.mjs → proxy-5nWqRL1f.mjs} +45 -5
  70. package/lib/{readability-Cpm-ocau.mjs → readability-uGhqb4GC.mjs} +2 -2
  71. package/lib/reference-CtvM4zLU.mjs +114 -0
  72. package/lib/{request-debug-HJMoJncL.mjs → request-debug-NQN0BjHH.mjs} +1 -1
  73. package/lib/{sanitize-text-CfcXzw5X.mjs → sanitize-text-BCf5KmCf.mjs} +1 -1
  74. package/lib/{scrapers-CE_qK1yk.mjs → scrapers-D8oWspgW.mjs} +12 -12
  75. package/lib/{src-BcD0_rQR.mjs → src-BwW51vA5.mjs} +979 -388
  76. package/lib/{sse-debug-CYdjOC96.mjs → sse-debug-B-tkLCPW.mjs} +1 -1
  77. package/lib/{stream-Bjq8wjfr.mjs → stream-B_7qN-bA.mjs} +3802 -2623
  78. package/lib/stream-markup-healing-DKT1lnkW.mjs +267 -0
  79. package/lib/{strict-tool-validation-imVLUcbI.mjs → strict-tool-validation-CBTz1dAA.mjs} +2 -2
  80. package/lib/taxonomy-DSIM99rS.mjs +15392 -0
  81. package/lib/{stream-markup-healing-DZ6bVDxH.mjs → thinking-CiLa2LFB.mjs} +31 -186
  82. package/lib/{turndown-DN7ByzEI.mjs → turndown-DrX1M4WG.mjs} +4 -4
  83. package/lib/{type-guards-B9VVjRDK.mjs → type-guards-CttAANEx.mjs} +1 -1
  84. package/lib/{types-DX_bvuus.mjs → types-PVueGi9S.mjs} +2 -2
  85. package/lib/{utils-APrc-TBB.mjs → utils-CCfhUQen.mjs} +2364 -2676
  86. package/lib/{utils-Cp2Mxf_U.mjs → utils-CUPhpw9A.mjs} +413 -134
  87. package/lib/{utils-CQHPEQ3W.mjs → utils-DeWqNWV8.mjs} +2 -2
  88. package/lib/{vision-guard-mBmtAHx0.mjs → vision-guard-_XwsL1DF.mjs} +14 -29
  89. package/lib/xai-oauth-CXhnz0gO.mjs +210 -0
  90. package/lib/{xiaomi-7mE345KX.mjs → xiaomi-psoUItal.mjs} +8 -37
  91. package/lib/{zai-CeNpMV3W.mjs → zai-ApJ8HBgT.mjs} +8 -71
  92. package/lib/{zip-BK7UHCwX.mjs → zip-Kd602XNe.mjs} +1 -1
  93. package/package.json +43 -41
  94. package/presets/package.json +1 -1
  95. package/presets/tool-plus-ptc/agent.cordis.yml +13 -4
  96. package/presets/tool-plus-standard/agent.cordis.yml +11 -3
  97. package/lib/agent_pb-Rizyt9Zg.mjs +0 -805
  98. package/lib/anthropic-CDmj476p.mjs +0 -262
  99. package/lib/api_server_pb-CDZgLMta.mjs +0 -252
  100. package/lib/callback-server-CFJK-jvK.mjs +0 -398
  101. package/lib/codex-P1dGpX7G.mjs +0 -54
  102. package/lib/device-code-CuXTWYwY.mjs +0 -51
  103. package/lib/devin-BcQwht1W.mjs +0 -114
  104. package/lib/devin-BvMfGevz.mjs +0 -95
  105. package/lib/github-copilot-B3kQl0g0.mjs +0 -104
  106. package/lib/gitlab-duo-BriUTP8k.mjs +0 -155
  107. package/lib/gitlab-duo-workflow-wK5Ljzmc.mjs +0 -91
  108. package/lib/google-CE5tFDod.mjs +0 -30
  109. package/lib/google-antigravity-C1jgNljz.mjs +0 -198
  110. package/lib/google-oauth-shared-BLVTvokk.mjs +0 -147
  111. package/lib/grammar-D-NqNUxQ.mjs +0 -49
  112. package/lib/identity-HNO1Oe9B.mjs +0 -219
  113. package/lib/kimi-DgcUpPtK.mjs +0 -236
  114. package/lib/markit-DtGoRE6M.mjs +0 -1417
  115. package/lib/minimax-code-Y3h5li9N.mjs +0 -53
  116. package/lib/models-DRA2c_8U.mjs +0 -104660
  117. package/lib/opencode-BsVw9rCD.mjs +0 -38
  118. package/lib/to-binary-B1BEBIPC.mjs +0 -6002
  119. package/lib/wafer-BlhWLweO.mjs +0 -17
  120. 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 { P as $env, S as debug, T as warn, _ as parseStreamingJsonThrottled, a as readSseEvents, h as parseJsonWithRepair, q as getInstallId, y as isEnoent } from "./src-BcD0_rQR.mjs";
5
- import { A as isTransientStreamParseError, D as isFastModeUnsupported, E as isCopilotTransientModelError, F as AnthropicStreamEnvelopeError, M as AnthropicApiError, N as AnthropicConnectionError, O as isGrammarError, P as AnthropicConnectionTimeoutError, a as isTransientStatus, f as getHeadersFromError, i as isProviderRetryableError$1, k as isStreamEnvelopeError, l as finalize, n as StreamTimeoutError, p as getRetryAfterMsFromHeaders, r as ValidationError, s as ProviderResponseError, t as ConfigurationError, u as finalizeErrorMessage, v as AbortError } from "./error-C-f_Wnw4.mjs";
6
- import { A as NO_STRICT, C as kStreamingPartialJson, R as spillToDescription, S as kStreamingLastParseLen, a as normalizeSystemPrompts, h as clearStreamingPartialJson, k as toolWireSchema, m as transformMessages, o as normalizeToolCallId, s as resolveCacheRetention, w as renderDemotedThinking, y as kStreamingBlockIndex, z as COMBINATOR_KEYS } from "./utils-Cp2Mxf_U.mjs";
7
- import { n as isRecord } from "./type-guards-B9VVjRDK.mjs";
8
- import { Ct as withEmptyCompletionRetry, K as getOpenAIPromptCacheKey, _t as isForcedToolChoice, gt as resolveGitHubCopilotBaseUrl, ht as hasCopilotVisionInput, mt as buildCopilotDynamicHeaders, n as getEnvApiKey, t as OUTPUT_FALLBACK_BUFFER, wt as isFoundryEnabled } from "./stream-Bjq8wjfr.mjs";
9
- import { t as createAbortSourceTracker } from "./abort-Cwwm4Err.mjs";
10
- import { N as isVertexRawPredictUrl, f as isAnthropicSigningProxyUrl, j as hostMatchesUrl, n as getBundledModel, o as mapEffortToAnthropicAdaptiveEffort, p as isOfficialAnthropicApiUrl, t as calculateCost } from "./models-DRA2c_8U.mjs";
11
- import { r as isAnthropicOAuthToken } from "./utils-CQHPEQ3W.mjs";
12
- import { u as parseGitHubCopilotApiKey } from "./github-copilot-B3kQl0g0.mjs";
13
- import { t as NON_VISION_IMAGE_PLACEHOLDER } from "./vision-guard-mBmtAHx0.mjs";
14
- import { t as AssistantMessageEventStream } from "./event-stream-Dh2guZxS.mjs";
15
- import { a as coworkUserAgent, i as claudeCodeVersion, n as CLAUDE_CODE_MAX_OUTPUT_TOKENS, r as claudeCodeSystemInstruction } from "./anthropic-CDmj476p.mjs";
16
- import { a as getStreamIdleTimeoutMs, i as getStreamFirstEventTimeoutMs, o as iterateWithIdleTimeout } from "./idle-iterator-CYAxUkSD.mjs";
17
- import { t as notifyProviderResponse } from "./provider-response-C6vcbQyO.mjs";
18
- import { t as notifyRawSseEvent } from "./sse-debug-CYdjOC96.mjs";
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@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/anthropic-wire.ts
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@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/anthropic-client.ts
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@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/anthropic.ts
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
- isProviderRetryableError: () => isProviderRetryableError,
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 coworkUtilityBetaDefaults = [
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 coworkAgentBetaDefaults = [
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 buildCoworkBetas(agentRequest, thinkingRequest, disableStrictTools = false) {
351
- if (!agentRequest && !disableStrictTools) return coworkUtilityBetaDefaults;
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 ? coworkAgentBetaDefaults : coworkUtilityBetaDefaults) {
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.coworkBetas ?? (oauthToken ? buildCoworkBetas(true, true) : []), extraBetas);
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 : coworkUserAgent;
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
- ...coworkHeaders,
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) return 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 Cowork's Linux Claude runtime. */
539
- const coworkHeaders = {
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": "Linux",
543
- "X-Stainless-Package-Version": "0.94.0",
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(coworkHeaders),
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(coworkHeaders),
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=claude-desktop; ${CCH_PLACEHOLDER_STR};`;
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
- const mediaType = normalizeAnthropicImageMediaType(block.mimeType);
900
- if (!mediaType) {
901
- blocks.push({
902
- type: "text",
903
- text: `[unsupported image: ${block.mimeType}]`
904
- });
905
- continue;
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 COWORK_TLS_CIPHERS = tls.DEFAULT_CIPHERS;
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 buildCoworkTlsFetchOptions(model, baseUrl) {
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
- ...COWORK_TLS_CIPHERS ? { ciphers: COWORK_TLS_CIPHERS } : {},
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 Anthropic `400 Invalid `signature` in `thinking` block` failure
1367
- * a signing proxy returns when a stripped/unsigned prior thinking block is
1368
- * replayed as `signature: ""`. Exported for the compat tests.
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 Anthropic's `Invalid signature in thinking
1376
- * block` 400 when the model looks like an unmarked custom signing proxy
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.provider === "google-vertex" && fallbacks?.some((entry) => entry.output_config?.effort !== void 0)) fallbacks = fallbacks.map((entry) => {
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.provider !== "google-vertex" && (options?.thinkingEnabled && options.effort !== "adaptive" || sendsAdaptiveEffortPin) && !extraBetas.includes(effortBeta)) extraBetas.push(effortBeta);
1449
- if (model.compat.supportsMidConversationSystem && !extraBetas.includes(midConversationSystemBeta)) extraBetas.push(midConversationSystemBeta);
1450
- if (model.reasoning && options?.thinkingEnabled && model.provider !== "github-copilot" && model.provider !== "google-vertex" && model.provider !== "opencode-zen" && !extraBetas.includes(contextManagementBeta)) extraBetas.push(contextManagementBeta);
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
- claudeCodeSessionId: options?.sessionId ?? extractClaudeMetadataSessionId(options?.metadata?.user_id),
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
- const injectedClientEffortHeaders = options?.client !== void 0 && params.output_config?.effort !== void 0 ? mergeAnthropicBetaHeader(mergedCallerHeaders, effortBeta) : void 0;
1622
- const perRequestHeaders = umansGatewayWebSearchHeader || injectedClientEffortHeaders ? {
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
- ...injectedClientEffortHeaders
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
- if (!forceDemoteUnsignedThinking && firstTokenTime === void 0 && !streamedReplayUnsafeContent && isInvalidThinkingSignatureError(streamFailure instanceof Error ? streamFailure.message : String(streamFailure))) {
2031
- warn("anthropic: signing proxy detected (Invalid signature in thinking block), demoting unsigned thinking and retrying", {
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: streamFailure instanceof Error ? streamFailure.message : String(streamFailure)
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, model.provider);
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 = isCopilotTransientModelError(streamFailure) ? COPILOT_MODEL_FLAP_RETRY_DELAY_MS : calculateAnthropicRetryDelayMs(providerRetryAttempt - 1);
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: wrap the single-attempt streamer with bounded empty-completion
2130
- * retries (a benign terminal stop carrying no content/usage would otherwise
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) => withEmptyCompletionRetry(model, context, options, streamAnthropicOnce);
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, claudeCodeSessionId, disableStrictTools: disableStrictToolsOverride } = args;
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
- ...buildCoworkTlsFetchOptions(model, baseUrl) ?? {},
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: mergeHeaders({
2201
- Accept: stream ? "text/event-stream" : "application/json",
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
- coworkBetas: oauthToken ? buildCoworkBetas(hasTools || thinkingEnabled, thinkingEnabled, disableStrictTools) : []
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.provider !== "google-vertex") {
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
- const start = Math.max(0, messageEnd - 1);
2325
- for (let index = messageEnd; index >= start; 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 && !model.id.startsWith("claude-3-5-haiku");
2821
+ const shouldInjectClaudeCodeInstruction = isOAuthToken && model.compat.injectClaudeCodeInstruction !== false;
2383
2822
  const firstUserMessageText = shouldInjectClaudeCodeInstruction ? extractClaudeCodeFirstUserMessageText(context.messages) : "";
2384
- const systemBlocks = buildAnthropicSystemBlocks(context.systemPrompt, {
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 || model.provider === "github-copilot", supportsEagerToolInputStreaming, model.compat.escapeBuiltinToolNames, useUmansGatewayWebSearch);
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
- const contextManagement = !options?.client && model.provider !== "github-copilot" && model.provider !== "google-vertex" && model.provider !== "opencode-zen" && (thinking?.type === "adaptive" || thinking?.type === "enabled") ? { edits: [{
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 (outputConfigEffort && model.provider !== "google-vertex") outputConfigEntries.effort = outputConfigEffort;
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: convertAnthropicMessages(context.messages, effectiveModel, isOAuthToken, { serverSideFallbackEnabled: !!fallbacks?.length }),
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 developerParamIndices = [];
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
- if (!msg.content) continue;
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) continue;
2552
- content = msg.content.toWellFormed();
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) continue;
2557
- content = contentBlocks;
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 (msg.role === "developer") developerParamIndices.push(params.length);
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 (developerParamIndices.length > 0 && model.compat.supportsMidConversationSystem) for (const idx of developerParamIndices) {
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 textOnly = typeof content === "string" || content.every((block) => block.type === "text");
2677
- if (followsUser && lastOrBeforeAssistant && textOnly) params[idx] = {
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
  }