@oh-my-pi/pi-ai 18.10.0 → 18.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/THIRD-PARTY-NOTICES.txt +3 -3
- package/package.json +6 -6
- package/src/providers/anthropic.ts +167 -18
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.10.2] - 2026-10-12
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added support for `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS` on the `anthropic` provider: when set, requests omit pre-release fields (`context_management`, beta tool fields such as `strict` and `defer_loading`, task budgets, structured-output format, `thinking.block_binding`, and Anthropic server compaction) along with their beta headers, so `ANTHROPIC_BASE_URL` gateways that reject them keep working ([#15458](https://github.com/can1357/oh-my-pi/pull/15458) by [@H4vC](https://github.com/H4vC))
|
|
10
|
+
|
|
5
11
|
## [18.9.2] - 2026-10-11
|
|
6
12
|
|
|
7
13
|
### Breaking Changes
|
package/THIRD-PARTY-NOTICES.txt
CHANGED
|
@@ -79,9 +79,9 @@ uutils coreutils (https://github.com/uutils/coreutils), MIT
|
|
|
79
79
|
--------------------------------------------------------------------------------
|
|
80
80
|
Covers: base32, base64, basename, cat, cksum (shared checksum machinery),
|
|
81
81
|
b2sum, md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum, comm, cp,
|
|
82
|
-
cut, date, dirname, head, hostname, ln, ls, mkdir, mktemp, mv,
|
|
83
|
-
printenv, readlink, realpath, rm, seq, sort, stat, tac, tail, tee,
|
|
84
|
-
truncate, uname, uniq, wc, whoami, yes.
|
|
82
|
+
cut, date, dirname, head, hostname, ln, ls, mkdir, mktemp, mv, nl, nproc,
|
|
83
|
+
paste, printenv, readlink, realpath, rm, seq, sort, stat, tac, tail, tee,
|
|
84
|
+
touch, tr, truncate, uname, uniq, wc, whoami, yes.
|
|
85
85
|
|
|
86
86
|
Copyright (c) uutils developers
|
|
87
87
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-ai",
|
|
3
|
-
"version": "18.10.
|
|
3
|
+
"version": "18.10.2",
|
|
4
4
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -155,11 +155,11 @@
|
|
|
155
155
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
156
156
|
},
|
|
157
157
|
"dependencies": {
|
|
158
|
-
"@oh-my-pi/omptype": "18.10.
|
|
159
|
-
"@oh-my-pi/pi-catalog": "18.10.
|
|
160
|
-
"@oh-my-pi/pi-natives": "18.10.
|
|
161
|
-
"@oh-my-pi/pi-utils": "18.10.
|
|
162
|
-
"@oh-my-pi/pi-wire": "18.10.
|
|
158
|
+
"@oh-my-pi/omptype": "18.10.2",
|
|
159
|
+
"@oh-my-pi/pi-catalog": "18.10.2",
|
|
160
|
+
"@oh-my-pi/pi-natives": "18.10.2",
|
|
161
|
+
"@oh-my-pi/pi-utils": "18.10.2",
|
|
162
|
+
"@oh-my-pi/pi-wire": "18.10.2"
|
|
163
163
|
},
|
|
164
164
|
"devDependencies": {
|
|
165
165
|
"@types/bun": "^1.3.14"
|
|
@@ -9,6 +9,7 @@ import { isAnthropicOAuthToken } from "@oh-my-pi/pi-catalog/utils";
|
|
|
9
9
|
import { parseGitHubCopilotApiKey } from "@oh-my-pi/pi-catalog/wire/github-copilot";
|
|
10
10
|
import {
|
|
11
11
|
$env,
|
|
12
|
+
$flag,
|
|
12
13
|
isEnoent,
|
|
13
14
|
logger,
|
|
14
15
|
parseJsonWithRepair,
|
|
@@ -116,10 +117,12 @@ import {
|
|
|
116
117
|
type MessageCreateParams,
|
|
117
118
|
type MessageCreateParamsStreaming,
|
|
118
119
|
type MessageParam,
|
|
120
|
+
type OutputConfig,
|
|
119
121
|
parseAnthropicInputTransformations,
|
|
120
122
|
type RawMessageStreamEvent,
|
|
121
123
|
THINKING_BINDING_CONTROLS_BETA,
|
|
122
124
|
type TextBlockParam,
|
|
125
|
+
type ThinkingConfigParam,
|
|
123
126
|
} from "./anthropic-wire";
|
|
124
127
|
import {
|
|
125
128
|
claudeCodeSdkVersion,
|
|
@@ -273,24 +276,41 @@ const promptCacheBetas: Record<string, true> = {
|
|
|
273
276
|
};
|
|
274
277
|
|
|
275
278
|
/**
|
|
276
|
-
*
|
|
279
|
+
* Betas withheld under the kill switch: they gate the pre-release body fields
|
|
280
|
+
* it removes (Claude Code's gateway contract: context management, beta tool
|
|
281
|
+
* fields, structured-output format, task budgets, tool search), plus the
|
|
282
|
+
* thinking-binding and compaction controls omp also withholds.
|
|
283
|
+
*/
|
|
284
|
+
const killSwitchBetas: Record<string, true> = {
|
|
285
|
+
[THINKING_BINDING_CONTROLS_BETA]: true,
|
|
286
|
+
[contextManagementBeta]: true,
|
|
287
|
+
[COMPACTION_BETA]: true,
|
|
288
|
+
[LEGACY_COMPACTION_BETA]: true,
|
|
289
|
+
[structuredOutputsBeta]: true,
|
|
290
|
+
[taskBudgetBeta]: true,
|
|
291
|
+
[midConversationToolChangesBeta]: true,
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Remove the `dropped` betas from every `anthropic-beta` entry in a header
|
|
277
296
|
* record. Header names are case-insensitive and the value is a comma-separated
|
|
278
297
|
* list, so each matching key keeps its own casing and its remaining tokens;
|
|
279
298
|
* an entry left with no token is deleted rather than sent empty. The input is
|
|
280
|
-
* returned untouched when it advertises
|
|
299
|
+
* returned untouched when it advertises none of them.
|
|
281
300
|
*
|
|
282
301
|
* `model.headers` and `options.headers` are caller-controlled channels that
|
|
283
302
|
* reach the wire through `buildAnthropicHeaders` (as `modelHeaders`, which an
|
|
284
303
|
* override-enabled endpoint lets replace our own beta header outright), the
|
|
285
304
|
* GitHub Copilot default headers, and the per-request beta override built for
|
|
286
|
-
* injected clients — each of which must go through here once breakpoints drop
|
|
305
|
+
* injected clients — each of which must go through here once breakpoints drop
|
|
306
|
+
* or the experimental-beta kill switch is on.
|
|
287
307
|
*/
|
|
288
|
-
function
|
|
308
|
+
function stripHeaderBetas(headers: Record<string, string>, dropped: Record<string, true>): Record<string, string> {
|
|
289
309
|
let stripped: Record<string, string> | undefined;
|
|
290
310
|
for (const key in headers) {
|
|
291
311
|
if (key.toLowerCase() !== "anthropic-beta") continue;
|
|
292
312
|
const betas = normalizeExtraBetas(headers[key]);
|
|
293
|
-
const kept = betas.filter(beta =>
|
|
313
|
+
const kept = betas.filter(beta => dropped[beta] !== true);
|
|
294
314
|
if (kept.length === betas.length) continue;
|
|
295
315
|
stripped ??= { ...headers };
|
|
296
316
|
if (kept.length === 0) {
|
|
@@ -2406,6 +2426,9 @@ const streamAnthropicOnce = (
|
|
|
2406
2426
|
};
|
|
2407
2427
|
let dropAllThinking = droppedAllThinkingForSignature;
|
|
2408
2428
|
let prefixBindingRetryAttempted = false;
|
|
2429
|
+
// Claude Code's `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS`; the wrapper
|
|
2430
|
+
// already turned the gated compat off, this covers caller/frozen inputs.
|
|
2431
|
+
const killSwitchActive = experimentalBetasDisabled(model);
|
|
2409
2432
|
// A live fallback-credit redemption replays its frozen body.
|
|
2410
2433
|
const frozenRedemption =
|
|
2411
2434
|
options?.fallbackCreditRedemption &&
|
|
@@ -2413,6 +2436,24 @@ const streamAnthropicOnce = (
|
|
|
2413
2436
|
options.fallbackCreditRedemption.params
|
|
2414
2437
|
? options.fallbackCreditRedemption
|
|
2415
2438
|
: undefined;
|
|
2439
|
+
// A body frozen before the kill switch was set still carries the fields
|
|
2440
|
+
// it withholds; the credit token is bound to that body, so forfeit it
|
|
2441
|
+
// and build a fresh request. Server tools that already ran would re-run
|
|
2442
|
+
// and re-bill on a tokenless retry, so surface that case instead.
|
|
2443
|
+
const frozenBody = frozenRedemption?.params as MessageCreateParamsStreaming | undefined;
|
|
2444
|
+
// The redemption drops `fallbacks` before sending, so they cannot force a forfeit.
|
|
2445
|
+
const forfeitFrozenForKillSwitch =
|
|
2446
|
+
killSwitchActive &&
|
|
2447
|
+
frozenBody !== undefined &&
|
|
2448
|
+
carriesKillSwitchField({ ...frozenBody, fallbacks: undefined });
|
|
2449
|
+
if (
|
|
2450
|
+
forfeitFrozenForKillSwitch &&
|
|
2451
|
+
frozenRedemption?.refusedContent?.some(block => block.type === "anthropicServerTool")
|
|
2452
|
+
) {
|
|
2453
|
+
throw new AIError.ConfigurationError(
|
|
2454
|
+
"CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS was set after a refused turn that ran server tools; its fallback credit cannot be redeemed without the experimental fields the switch withholds.",
|
|
2455
|
+
);
|
|
2456
|
+
}
|
|
2416
2457
|
// Collected at most once, on first params build; a frozen redemption
|
|
2417
2458
|
// body never builds params.
|
|
2418
2459
|
let controlRecords: AnthropicControlRecord[] | undefined;
|
|
@@ -2431,12 +2472,16 @@ const streamAnthropicOnce = (
|
|
|
2431
2472
|
// `anthropic-beta` value, so once breakpoints are dropped an unstripped
|
|
2432
2473
|
// base would re-attach the very cache beta the replay abandoned. Both
|
|
2433
2474
|
// prompt-cache betas govern `ttl`/`scope`, so the options rung has to
|
|
2434
|
-
// strip them too.
|
|
2435
|
-
//
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2475
|
+
// strip them too. The kill switch's betas never ride, whatever the
|
|
2476
|
+
// caller's header says. Read through a closure because both cache
|
|
2477
|
+
// flags flip mid-turn.
|
|
2478
|
+
const callerBetaBaseHeaders = (): Record<string, string> => {
|
|
2479
|
+
const headers =
|
|
2480
|
+
dropCacheControl || dropCacheControlOptions
|
|
2481
|
+
? stripHeaderBetas(mergedCallerHeaders, promptCacheBetas)
|
|
2482
|
+
: mergedCallerHeaders;
|
|
2483
|
+
return killSwitchActive ? stripHeaderBetas(headers, killSwitchBetas) : headers;
|
|
2484
|
+
};
|
|
2440
2485
|
// Keep fallback payloads aligned with the top-level Vertex effort gate:
|
|
2441
2486
|
// no nested effort field means the fallback scan cannot re-add its beta.
|
|
2442
2487
|
let fallbacks = options?.fallbacks;
|
|
@@ -2565,7 +2610,9 @@ const streamAnthropicOnce = (
|
|
|
2565
2610
|
if (!isOAuth && isOfficialAnthropicApiUrl(baseUrl) && !extraBetas.includes(fallbackCreditBeta)) {
|
|
2566
2611
|
extraBetas.push(fallbackCreditBeta);
|
|
2567
2612
|
}
|
|
2568
|
-
|
|
2613
|
+
// A forfeited frozen body is rebuilt fresh, so it keeps the betas
|
|
2614
|
+
// computed above instead of the saved list describing the old body.
|
|
2615
|
+
if (options?.fallbackCreditRedemption && !forfeitFrozenForKillSwitch) {
|
|
2569
2616
|
const frozenBetas = (options.fallbackCreditRedemption.betas ?? []).filter(
|
|
2570
2617
|
b => !b.startsWith("server-side-fallback-"),
|
|
2571
2618
|
);
|
|
@@ -2598,6 +2645,8 @@ const streamAnthropicOnce = (
|
|
|
2598
2645
|
}
|
|
2599
2646
|
}
|
|
2600
2647
|
}
|
|
2648
|
+
// Caller betas and a frozen redemption's beta list bypass compat.
|
|
2649
|
+
if (killSwitchActive) extraBetas = extraBetas.filter(beta => killSwitchBetas[beta] !== true);
|
|
2601
2650
|
|
|
2602
2651
|
clientArgs = {
|
|
2603
2652
|
model,
|
|
@@ -2659,6 +2708,8 @@ const streamAnthropicOnce = (
|
|
|
2659
2708
|
if (replacementPayload !== undefined) {
|
|
2660
2709
|
nextParams = replacementPayload as typeof nextParams;
|
|
2661
2710
|
}
|
|
2711
|
+
// After `onPayload`, so a hook cannot restore a field the switch withholds.
|
|
2712
|
+
if (killSwitchActive) withholdKillSwitchFields(nextParams);
|
|
2662
2713
|
if (nextParams.compaction) stripCompactionIncompatibleParams(nextParams);
|
|
2663
2714
|
// After `onPayload`, so a hook cannot restore a field Bedrock rejects.
|
|
2664
2715
|
if (model.compat.bedrockMessagesApi) fitBedrockAnthropicPayload(nextParams);
|
|
@@ -2696,7 +2747,7 @@ const streamAnthropicOnce = (
|
|
|
2696
2747
|
let params: MessageCreateParamsStreaming;
|
|
2697
2748
|
// Recheck expiry here: preparation (image resizing) is async, and an
|
|
2698
2749
|
// expired token must fall back to a fresh request as before.
|
|
2699
|
-
if (frozenRedemption && Date.now() <= frozenRedemption.expiresAt) {
|
|
2750
|
+
if (frozenRedemption && !forfeitFrozenForKillSwitch && Date.now() <= frozenRedemption.expiresAt) {
|
|
2700
2751
|
const redemption = frozenRedemption;
|
|
2701
2752
|
usingFallbackCredit = true;
|
|
2702
2753
|
const frozenParams = structuredClone(redemption.params as MessageCreateParamsStreaming);
|
|
@@ -2925,7 +2976,12 @@ const streamAnthropicOnce = (
|
|
|
2925
2976
|
const rawBetas = options.fallbackCreditRedemption.betaHeader
|
|
2926
2977
|
.split(",")
|
|
2927
2978
|
.map(b => b.trim())
|
|
2928
|
-
.filter(
|
|
2979
|
+
.filter(
|
|
2980
|
+
b =>
|
|
2981
|
+
b &&
|
|
2982
|
+
!b.startsWith("server-side-fallback-") &&
|
|
2983
|
+
(!killSwitchActive || killSwitchBetas[b] !== true),
|
|
2984
|
+
);
|
|
2929
2985
|
if (!rawBetas.includes(fallbackCreditBeta) && !rawBetas.includes("fallback-credit-2026-06-01")) {
|
|
2930
2986
|
rawBetas.push(fallbackCreditBeta);
|
|
2931
2987
|
}
|
|
@@ -4003,10 +4059,97 @@ const streamAnthropicOnce = (
|
|
|
4003
4059
|
* loop. The inner attempt owns Anthropic provider-failure retries.
|
|
4004
4060
|
*/
|
|
4005
4061
|
export const streamAnthropic: StreamFunction<"anthropic-messages"> = (model, context, options) =>
|
|
4006
|
-
withReplaySafeStreamRetry(model, context, options, streamAnthropicOnce, {
|
|
4062
|
+
withReplaySafeStreamRetry(withoutDisabledExperimentalBetas(model), context, options, streamAnthropicOnce, {
|
|
4007
4063
|
retryEmptyCompletion: true,
|
|
4008
4064
|
});
|
|
4009
4065
|
|
|
4066
|
+
/** Whether Claude Code's `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS` applies to this model's provider. */
|
|
4067
|
+
function experimentalBetasDisabled(model: Model<"anthropic-messages">): boolean {
|
|
4068
|
+
return model.compat.honorsClaudeCodeBetaKillSwitch === true && $flag("CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS");
|
|
4069
|
+
}
|
|
4070
|
+
|
|
4071
|
+
/**
|
|
4072
|
+
* Whether a request body carries a field the kill switch withholds. A frozen
|
|
4073
|
+
* fallback-credit body that does cannot be redeemed under the switch. Defined
|
|
4074
|
+
* as "the sanitizer would change it" so detection and stripping cannot drift.
|
|
4075
|
+
*/
|
|
4076
|
+
function carriesKillSwitchField(params: MessageCreateParamsStreaming): boolean {
|
|
4077
|
+
const sanitized = structuredClone(params);
|
|
4078
|
+
withholdKillSwitchFields(sanitized);
|
|
4079
|
+
return !Bun.deepEquals(sanitized, params);
|
|
4080
|
+
}
|
|
4081
|
+
|
|
4082
|
+
/**
|
|
4083
|
+
* Remove every field the kill switch withholds from a final request body, for
|
|
4084
|
+
* payloads an `onPayload` hook replaced after compat already shaped them, and
|
|
4085
|
+
* for the switch's fields compat has no axis for (task budgets). Compaction
|
|
4086
|
+
* blocks keep their readable summary as text, the same form an endpoint
|
|
4087
|
+
* without compaction support receives.
|
|
4088
|
+
*/
|
|
4089
|
+
function withholdKillSwitchFields(params: MessageCreateParamsStreaming): void {
|
|
4090
|
+
withholdKillSwitchControls(params);
|
|
4091
|
+
delete params.context_management;
|
|
4092
|
+
delete params.compaction;
|
|
4093
|
+
// Server-side fallback entries carry their own per-attempt controls.
|
|
4094
|
+
for (const entry of params.fallbacks ?? []) withholdKillSwitchControls(entry);
|
|
4095
|
+
for (const tool of params.tools ?? []) {
|
|
4096
|
+
if ("strict" in tool) delete tool.strict;
|
|
4097
|
+
if ("defer_loading" in tool) delete tool.defer_loading;
|
|
4098
|
+
if ("eager_input_streaming" in tool) delete tool.eager_input_streaming;
|
|
4099
|
+
}
|
|
4100
|
+
for (const message of params.messages) {
|
|
4101
|
+
// Per-message `output_config` (mid-conversation effort) may carry the same controls.
|
|
4102
|
+
if ("output_config" in message && message.output_config) withholdKillSwitchControls(message);
|
|
4103
|
+
if (!Array.isArray(message.content)) continue;
|
|
4104
|
+
for (let i = 0; i < message.content.length; i++) {
|
|
4105
|
+
const block = message.content[i];
|
|
4106
|
+
if (block.type === "compaction") message.content[i] = { type: "text", text: block.content };
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
if (params.anthropic_beta) {
|
|
4110
|
+
params.anthropic_beta = params.anthropic_beta.filter(beta => killSwitchBetas[beta] !== true);
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
|
|
4114
|
+
/** Withhold the kill switch's thinking/output controls on a body, fallback entry, or message. */
|
|
4115
|
+
function withholdKillSwitchControls(holder: { thinking?: ThinkingConfigParam; output_config?: OutputConfig }): void {
|
|
4116
|
+
if (holder.thinking && "block_binding" in holder.thinking) delete holder.thinking.block_binding;
|
|
4117
|
+
if (!holder.output_config) return;
|
|
4118
|
+
delete holder.output_config.task_budget;
|
|
4119
|
+
delete holder.output_config.format;
|
|
4120
|
+
if (Object.keys(holder.output_config).length === 0) delete holder.output_config;
|
|
4121
|
+
}
|
|
4122
|
+
|
|
4123
|
+
/**
|
|
4124
|
+
* Honor Claude Code's `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS` kill switch on
|
|
4125
|
+
* providers whose compat opts in (`honors-claude-code-beta-kill-switch`).
|
|
4126
|
+
* Gateways behind `ANTHROPIC_BASE_URL` often reject pre-release body fields,
|
|
4127
|
+
* so the switch withholds what Claude Code's gateway contract lists — context
|
|
4128
|
+
* management, beta tool fields (`strict`, `defer_loading`,
|
|
4129
|
+
* `eager_input_streaming`), tool search (mid-conversation tool changes),
|
|
4130
|
+
* structured-output format, task budgets — plus `thinking.block_binding` and
|
|
4131
|
+
* server compaction (whose legacy replay needs a `context_management` edit),
|
|
4132
|
+
* together with their betas. Effort, adaptive thinking, interleaved thinking
|
|
4133
|
+
* and extended context stay, as in Claude Code. Applied through compat so every
|
|
4134
|
+
* request builder and retry rung sees one decision; {@link withholdKillSwitchFields}
|
|
4135
|
+
* and {@link killSwitchBetas} cover the rest where bodies and betas are finalized.
|
|
4136
|
+
*/
|
|
4137
|
+
function withoutDisabledExperimentalBetas(model: Model<"anthropic-messages">): Model<"anthropic-messages"> {
|
|
4138
|
+
if (!experimentalBetasDisabled(model)) return model;
|
|
4139
|
+
return {
|
|
4140
|
+
...model,
|
|
4141
|
+
compat: {
|
|
4142
|
+
...model.compat,
|
|
4143
|
+
supportsContextManagement: false,
|
|
4144
|
+
supportsThinkingBindingControls: false,
|
|
4145
|
+
supportsServerCompaction: false,
|
|
4146
|
+
disableStrictTools: true,
|
|
4147
|
+
supportsEagerToolInputStreaming: false,
|
|
4148
|
+
supportsMidConversationToolChanges: false,
|
|
4149
|
+
},
|
|
4150
|
+
};
|
|
4151
|
+
}
|
|
4152
|
+
|
|
4010
4153
|
export type AnthropicSystemBlock = {
|
|
4011
4154
|
type: "text";
|
|
4012
4155
|
text: string;
|
|
@@ -4163,7 +4306,9 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
|
|
|
4163
4306
|
// Unlike the generic builder below, this branch has no enforced-key
|
|
4164
4307
|
// filter: a caller-supplied `anthropic-beta` lands in the default
|
|
4165
4308
|
// headers verbatim, cache betas included.
|
|
4166
|
-
const defaultHeaders = dropPromptCacheBetas
|
|
4309
|
+
const defaultHeaders = dropPromptCacheBetas
|
|
4310
|
+
? stripHeaderBetas(mergedCopilotHeaders, promptCacheBetas)
|
|
4311
|
+
: mergedCopilotHeaders;
|
|
4167
4312
|
applyInferenceHeaders(defaultHeaders, {
|
|
4168
4313
|
provider: model.provider,
|
|
4169
4314
|
protocol: "anthropic",
|
|
@@ -4208,9 +4353,13 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
|
|
|
4208
4353
|
// value outright — but `allowAnthropicHeaderOverrides` lets it replace our
|
|
4209
4354
|
// built beta header wholesale, which would put a cache beta back on a
|
|
4210
4355
|
// breakpoint-free request.
|
|
4211
|
-
|
|
4212
|
-
|
|
4356
|
+
// The kill switch's betas are stripped on the same channel.
|
|
4357
|
+
const cacheStrippedHeaders = dropPromptCacheBetas
|
|
4358
|
+
? stripHeaderBetas(mergedRequestHeaders, promptCacheBetas)
|
|
4213
4359
|
: mergedRequestHeaders;
|
|
4360
|
+
const requestModelHeaders = experimentalBetasDisabled(model)
|
|
4361
|
+
? stripHeaderBetas(cacheStrippedHeaders, killSwitchBetas)
|
|
4362
|
+
: cacheStrippedHeaders;
|
|
4214
4363
|
const defaultHeaders = buildAnthropicHeaders({
|
|
4215
4364
|
apiKey,
|
|
4216
4365
|
baseUrl,
|