jeo-code 0.8.7 → 0.8.8
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 +10 -0
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/package.json +1 -1
- package/src/ai/providers/anthropic.ts +52 -40
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
The README mirrors the latest 5 entries — regenerate with `bun run changelog:sync`.
|
|
8
8
|
|
|
9
|
+
## [0.8.8] - 2026-07-08
|
|
10
|
+
_"실동작검증을 통해서 유효성 평가하고 개선해줘" — live-verified the v0.8.5 fallback mechanism using active Claude Code OAuth credentials on this machine (confirmed 200 OK for both Fable 5 and Opus 4.8 via the proxy). Identified two critical improvement vectors during verification: (1) server-side fallback was previously scoped strictly to API-key credentials, leaving OAuth users (who also hit `reasoning_extraction` refusals) with today's reactive-only recovery; (2) the sequential `postAnthropic` retry ladder could throw immediately on a combination of different error types (e.g. temperature error first, then fallback error, then success)._
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **OAuth support for server-side fallback** (`src/ai/providers/anthropic.ts`) — removed the `credential.kind !== "api_key"` constraint. The Claude Code OAuth proxy has been verified to fully support both the `fallbacks` parameter and the `server-side-fallback-2026-06-01` beta header. `headersFor` now dynamically injects the fallback beta header into the OAuth request headers when applicable, extending the refusal-avoidance benefit to all subscription users.
|
|
14
|
+
- **Loop-based unified retry handling** (`src/ai/providers/anthropic.ts`) — refactored the sequential `if (isXError)` retry lines into a clean, unified `for` loop. The loop dynamically flips state flags (`includeTemperature`, `stripArtifacts`, `disableFallback`) and retries up to 4 times, allowing successful recovery from any combination of errors.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- **Combination retry test** (`test/anthropic-fallback.test.ts`) — added a robust regression test verifying that `postAnthropic` recovers successfully when multiple orthogonal errors occur in sequence (temperature error first, then fallback error, then success) and yields the correct final payload.
|
|
18
|
+
|
|
9
19
|
## [0.8.7] - 2026-07-08
|
|
10
20
|
_Fix-forward for a CI-caught release failure in v0.8.6 (this same session): `test/launch-prompt-routing.test.ts` shipped with a dropped closing brace (a git 3-way merge misaligned on a duplicate `});` line during this session's own working-tree isolation, then a subsequent `git stash push --keep-index` silently reset the working tree to the pre-fix staged content — the fix was applied once, verified once, then invisibly reverted before the commit that actually shipped). The v0.8.6 GitHub Actions release workflow correctly caught the syntax error at `bun test` and failed BEFORE the npm publish step ran; `npm view jeo-code version` confirmed 0.8.5 remained latest throughout — nothing broken ever reached the registry. Per this repo's established pattern for a same-day CI-caught regression (v0.8.0 → v0.8.1), shipping forward rather than retargeting the already-publicly-failed v0.8.6 tag._
|
|
11
21
|
|
package/README.ja.md
CHANGED
|
@@ -262,11 +262,11 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
|
|
|
262
262
|
## 変更履歴 (Changelog)
|
|
263
263
|
|
|
264
264
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
265
|
+
- **[0.8.8]** (2026-07-08) — "실동작검증을 통해서 유효성 평가하고 개선해줘" — live-verified the v0.8.5 fallback mechanism using active Claude Code OAuth credentials on this machine (confirmed 200 OK for both Fable 5 and Opus 4.8 via the proxy). Identified two critical improvement vectors during verification: (1) server-side fallback was previously scoped strictly to API-key credentials, leaving OAuth users (who also hit `reasoning_extraction` refusals) with today's reactive-only recovery; (2) the sequential `postAnthropic` retry ladder could throw immediately on a combination of different error types (e.g. temperature error first, then fallback error, then success).
|
|
265
266
|
- **[0.8.7]** (2026-07-08) — Fix-forward for a CI-caught release failure in v0.8.6 (this same session): `test/launch-prompt-routing.test.ts` shipped with a dropped closing brace (a git 3-way merge misaligned on a duplicate `});` line during this session's own working-tree isolation, then a subsequent `git stash push --keep-index` silently reset the working tree to the pre-fix staged content — the fix was applied once, verified once, then invisibly reverted before the commit that actually shipped). The v0.8.6 GitHub Actions release workflow correctly caught the syntax error at `bun test` and failed BEFORE the npm publish step ran; `npm view jeo-code version` confirmed 0.8.5 remained latest throughout — nothing broken ever reached the registry. Per this repo's established pattern for a same-day CI-caught regression (v0.8.0 → v0.8.1), shipping forward rather than retargeting the already-publicly-failed v0.8.6 tag.
|
|
266
267
|
- **[0.8.6]** (2026-07-08) — Explicit `/model` pin always winning over PromptRouter was correct but opaque: `/route status` showed "routing: on" even while a session pin blocked routing from ever evaluating a prompt, and there was no way back to routed mode short of restarting the session. Also closed a related escalation gap: `routing.enabled` with `roles.smol` unset made ambiguous-prompt LLM escalation silently skip every turn, even when a cheaper credentialed model existed to run the classifier.
|
|
267
268
|
- **[0.8.5]** (2026-07-08) — "딥리서치 다음과같이 페이블5 모델이 응답하게 되는경우를 피하기 위해" — a claude-fable-5 turn hit `Error: Refusal (reasoning_extraction): This request was blocked as it seems to violate Anthropic's Terms of Service.` jeo already had a full reactive recovery ladder (context reset → thinking-artifact strip → guidance strip → fail-fast on a category-shaped refusal), but every rung still resends to the SAME model — a deterministic classifier trip re-refuses identically no matter how much context gets stripped. Deep-researched Anthropic's current docs and found the actual fix: a documented, dedicated **server-side fallback** beta released alongside Fable 5 that retries a safety-classifier decline against a different model inside the SAME request, before the caller ever sees an error.
|
|
268
269
|
- **[0.8.4]** (2026-07-08) — Follow-up to the 0.8.3 `jeo --tmux` E2E verification, which surfaced two real bugs: (1) the fake `test-anthropic-key` fixture found sitting in the user's REAL `~/.jeo/config.json` turned out to be reproducible — jeo's own test suite could silently write to the real config with no guard, and a prior session's routing tests had done exactly that; (2) the E2E run's TUI showed `'antigravity/gemini-pro-agent' is not in the live antigravity catalog` for a model that WAS live — traced to the note firing on a FAILED provider discovery (timeout/expired OAuth) rather than a genuinely absent model.
|
|
269
|
-
- **[0.8.3]** (2026-07-08) — "잘못된 모델 설정하는 경우가 있는데" — the static Antigravity catalog had drifted badly from the LIVE Cloud Code Assist agent backend, and several current wire ids actively LIE about their tier: `gemini-3-flash-agent` is really "Gemini 3.5 Flash (High)" (the flagship agent model, which the name-suffix heuristic filed under the SMALL flash tier), `gemini-pro-agent` is really "Gemini 3.1 Pro (High)" (the code-agent model), and `gemini-3.1-pro-high` is DEPRECATED by the backend in favor of `gemini-pro-agent`. Probed the real `fetchAvailableModels` response (displayNames + agentModelSorts + deprecatedModelIds) and made it the single source of truth.
|
|
270
270
|
|
|
271
271
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
272
272
|
<!-- CHANGELOG:END -->
|
package/README.ko.md
CHANGED
|
@@ -263,11 +263,11 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
|
|
|
263
263
|
## 변경 이력 (Changelog)
|
|
264
264
|
|
|
265
265
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
266
|
+
- **[0.8.8]** (2026-07-08) — "실동작검증을 통해서 유효성 평가하고 개선해줘" — live-verified the v0.8.5 fallback mechanism using active Claude Code OAuth credentials on this machine (confirmed 200 OK for both Fable 5 and Opus 4.8 via the proxy). Identified two critical improvement vectors during verification: (1) server-side fallback was previously scoped strictly to API-key credentials, leaving OAuth users (who also hit `reasoning_extraction` refusals) with today's reactive-only recovery; (2) the sequential `postAnthropic` retry ladder could throw immediately on a combination of different error types (e.g. temperature error first, then fallback error, then success).
|
|
266
267
|
- **[0.8.7]** (2026-07-08) — Fix-forward for a CI-caught release failure in v0.8.6 (this same session): `test/launch-prompt-routing.test.ts` shipped with a dropped closing brace (a git 3-way merge misaligned on a duplicate `});` line during this session's own working-tree isolation, then a subsequent `git stash push --keep-index` silently reset the working tree to the pre-fix staged content — the fix was applied once, verified once, then invisibly reverted before the commit that actually shipped). The v0.8.6 GitHub Actions release workflow correctly caught the syntax error at `bun test` and failed BEFORE the npm publish step ran; `npm view jeo-code version` confirmed 0.8.5 remained latest throughout — nothing broken ever reached the registry. Per this repo's established pattern for a same-day CI-caught regression (v0.8.0 → v0.8.1), shipping forward rather than retargeting the already-publicly-failed v0.8.6 tag.
|
|
267
268
|
- **[0.8.6]** (2026-07-08) — Explicit `/model` pin always winning over PromptRouter was correct but opaque: `/route status` showed "routing: on" even while a session pin blocked routing from ever evaluating a prompt, and there was no way back to routed mode short of restarting the session. Also closed a related escalation gap: `routing.enabled` with `roles.smol` unset made ambiguous-prompt LLM escalation silently skip every turn, even when a cheaper credentialed model existed to run the classifier.
|
|
268
269
|
- **[0.8.5]** (2026-07-08) — "딥리서치 다음과같이 페이블5 모델이 응답하게 되는경우를 피하기 위해" — a claude-fable-5 turn hit `Error: Refusal (reasoning_extraction): This request was blocked as it seems to violate Anthropic's Terms of Service.` jeo already had a full reactive recovery ladder (context reset → thinking-artifact strip → guidance strip → fail-fast on a category-shaped refusal), but every rung still resends to the SAME model — a deterministic classifier trip re-refuses identically no matter how much context gets stripped. Deep-researched Anthropic's current docs and found the actual fix: a documented, dedicated **server-side fallback** beta released alongside Fable 5 that retries a safety-classifier decline against a different model inside the SAME request, before the caller ever sees an error.
|
|
269
270
|
- **[0.8.4]** (2026-07-08) — Follow-up to the 0.8.3 `jeo --tmux` E2E verification, which surfaced two real bugs: (1) the fake `test-anthropic-key` fixture found sitting in the user's REAL `~/.jeo/config.json` turned out to be reproducible — jeo's own test suite could silently write to the real config with no guard, and a prior session's routing tests had done exactly that; (2) the E2E run's TUI showed `'antigravity/gemini-pro-agent' is not in the live antigravity catalog` for a model that WAS live — traced to the note firing on a FAILED provider discovery (timeout/expired OAuth) rather than a genuinely absent model.
|
|
270
|
-
- **[0.8.3]** (2026-07-08) — "잘못된 모델 설정하는 경우가 있는데" — the static Antigravity catalog had drifted badly from the LIVE Cloud Code Assist agent backend, and several current wire ids actively LIE about their tier: `gemini-3-flash-agent` is really "Gemini 3.5 Flash (High)" (the flagship agent model, which the name-suffix heuristic filed under the SMALL flash tier), `gemini-pro-agent` is really "Gemini 3.1 Pro (High)" (the code-agent model), and `gemini-3.1-pro-high` is DEPRECATED by the backend in favor of `gemini-pro-agent`. Probed the real `fetchAvailableModels` response (displayNames + agentModelSorts + deprecatedModelIds) and made it the single source of truth.
|
|
271
271
|
|
|
272
272
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
273
273
|
<!-- CHANGELOG:END -->
|
package/README.md
CHANGED
|
@@ -265,11 +265,11 @@ Huge thanks to [gajae-code](https://github.com/Yeachan-Heo/gajae-code) for the i
|
|
|
265
265
|
## Changelog
|
|
266
266
|
|
|
267
267
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
268
|
+
- **[0.8.8]** (2026-07-08) — "실동작검증을 통해서 유효성 평가하고 개선해줘" — live-verified the v0.8.5 fallback mechanism using active Claude Code OAuth credentials on this machine (confirmed 200 OK for both Fable 5 and Opus 4.8 via the proxy). Identified two critical improvement vectors during verification: (1) server-side fallback was previously scoped strictly to API-key credentials, leaving OAuth users (who also hit `reasoning_extraction` refusals) with today's reactive-only recovery; (2) the sequential `postAnthropic` retry ladder could throw immediately on a combination of different error types (e.g. temperature error first, then fallback error, then success).
|
|
268
269
|
- **[0.8.7]** (2026-07-08) — Fix-forward for a CI-caught release failure in v0.8.6 (this same session): `test/launch-prompt-routing.test.ts` shipped with a dropped closing brace (a git 3-way merge misaligned on a duplicate `});` line during this session's own working-tree isolation, then a subsequent `git stash push --keep-index` silently reset the working tree to the pre-fix staged content — the fix was applied once, verified once, then invisibly reverted before the commit that actually shipped). The v0.8.6 GitHub Actions release workflow correctly caught the syntax error at `bun test` and failed BEFORE the npm publish step ran; `npm view jeo-code version` confirmed 0.8.5 remained latest throughout — nothing broken ever reached the registry. Per this repo's established pattern for a same-day CI-caught regression (v0.8.0 → v0.8.1), shipping forward rather than retargeting the already-publicly-failed v0.8.6 tag.
|
|
269
270
|
- **[0.8.6]** (2026-07-08) — Explicit `/model` pin always winning over PromptRouter was correct but opaque: `/route status` showed "routing: on" even while a session pin blocked routing from ever evaluating a prompt, and there was no way back to routed mode short of restarting the session. Also closed a related escalation gap: `routing.enabled` with `roles.smol` unset made ambiguous-prompt LLM escalation silently skip every turn, even when a cheaper credentialed model existed to run the classifier.
|
|
270
271
|
- **[0.8.5]** (2026-07-08) — "딥리서치 다음과같이 페이블5 모델이 응답하게 되는경우를 피하기 위해" — a claude-fable-5 turn hit `Error: Refusal (reasoning_extraction): This request was blocked as it seems to violate Anthropic's Terms of Service.` jeo already had a full reactive recovery ladder (context reset → thinking-artifact strip → guidance strip → fail-fast on a category-shaped refusal), but every rung still resends to the SAME model — a deterministic classifier trip re-refuses identically no matter how much context gets stripped. Deep-researched Anthropic's current docs and found the actual fix: a documented, dedicated **server-side fallback** beta released alongside Fable 5 that retries a safety-classifier decline against a different model inside the SAME request, before the caller ever sees an error.
|
|
271
272
|
- **[0.8.4]** (2026-07-08) — Follow-up to the 0.8.3 `jeo --tmux` E2E verification, which surfaced two real bugs: (1) the fake `test-anthropic-key` fixture found sitting in the user's REAL `~/.jeo/config.json` turned out to be reproducible — jeo's own test suite could silently write to the real config with no guard, and a prior session's routing tests had done exactly that; (2) the E2E run's TUI showed `'antigravity/gemini-pro-agent' is not in the live antigravity catalog` for a model that WAS live — traced to the note firing on a FAILED provider discovery (timeout/expired OAuth) rather than a genuinely absent model.
|
|
272
|
-
- **[0.8.3]** (2026-07-08) — "잘못된 모델 설정하는 경우가 있는데" — the static Antigravity catalog had drifted badly from the LIVE Cloud Code Assist agent backend, and several current wire ids actively LIE about their tier: `gemini-3-flash-agent` is really "Gemini 3.5 Flash (High)" (the flagship agent model, which the name-suffix heuristic filed under the SMALL flash tier), `gemini-pro-agent` is really "Gemini 3.1 Pro (High)" (the code-agent model), and `gemini-3.1-pro-high` is DEPRECATED by the backend in favor of `gemini-pro-agent`. Probed the real `fetchAvailableModels` response (displayNames + agentModelSorts + deprecatedModelIds) and made it the single source of truth.
|
|
273
273
|
|
|
274
274
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
275
275
|
<!-- CHANGELOG:END -->
|
package/README.zh.md
CHANGED
|
@@ -262,11 +262,11 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
|
|
|
262
262
|
## 更新日志 (Changelog)
|
|
263
263
|
|
|
264
264
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
265
|
+
- **[0.8.8]** (2026-07-08) — "실동작검증을 통해서 유효성 평가하고 개선해줘" — live-verified the v0.8.5 fallback mechanism using active Claude Code OAuth credentials on this machine (confirmed 200 OK for both Fable 5 and Opus 4.8 via the proxy). Identified two critical improvement vectors during verification: (1) server-side fallback was previously scoped strictly to API-key credentials, leaving OAuth users (who also hit `reasoning_extraction` refusals) with today's reactive-only recovery; (2) the sequential `postAnthropic` retry ladder could throw immediately on a combination of different error types (e.g. temperature error first, then fallback error, then success).
|
|
265
266
|
- **[0.8.7]** (2026-07-08) — Fix-forward for a CI-caught release failure in v0.8.6 (this same session): `test/launch-prompt-routing.test.ts` shipped with a dropped closing brace (a git 3-way merge misaligned on a duplicate `});` line during this session's own working-tree isolation, then a subsequent `git stash push --keep-index` silently reset the working tree to the pre-fix staged content — the fix was applied once, verified once, then invisibly reverted before the commit that actually shipped). The v0.8.6 GitHub Actions release workflow correctly caught the syntax error at `bun test` and failed BEFORE the npm publish step ran; `npm view jeo-code version` confirmed 0.8.5 remained latest throughout — nothing broken ever reached the registry. Per this repo's established pattern for a same-day CI-caught regression (v0.8.0 → v0.8.1), shipping forward rather than retargeting the already-publicly-failed v0.8.6 tag.
|
|
266
267
|
- **[0.8.6]** (2026-07-08) — Explicit `/model` pin always winning over PromptRouter was correct but opaque: `/route status` showed "routing: on" even while a session pin blocked routing from ever evaluating a prompt, and there was no way back to routed mode short of restarting the session. Also closed a related escalation gap: `routing.enabled` with `roles.smol` unset made ambiguous-prompt LLM escalation silently skip every turn, even when a cheaper credentialed model existed to run the classifier.
|
|
267
268
|
- **[0.8.5]** (2026-07-08) — "딥리서치 다음과같이 페이블5 모델이 응답하게 되는경우를 피하기 위해" — a claude-fable-5 turn hit `Error: Refusal (reasoning_extraction): This request was blocked as it seems to violate Anthropic's Terms of Service.` jeo already had a full reactive recovery ladder (context reset → thinking-artifact strip → guidance strip → fail-fast on a category-shaped refusal), but every rung still resends to the SAME model — a deterministic classifier trip re-refuses identically no matter how much context gets stripped. Deep-researched Anthropic's current docs and found the actual fix: a documented, dedicated **server-side fallback** beta released alongside Fable 5 that retries a safety-classifier decline against a different model inside the SAME request, before the caller ever sees an error.
|
|
268
269
|
- **[0.8.4]** (2026-07-08) — Follow-up to the 0.8.3 `jeo --tmux` E2E verification, which surfaced two real bugs: (1) the fake `test-anthropic-key` fixture found sitting in the user's REAL `~/.jeo/config.json` turned out to be reproducible — jeo's own test suite could silently write to the real config with no guard, and a prior session's routing tests had done exactly that; (2) the E2E run's TUI showed `'antigravity/gemini-pro-agent' is not in the live antigravity catalog` for a model that WAS live — traced to the note firing on a FAILED provider discovery (timeout/expired OAuth) rather than a genuinely absent model.
|
|
269
|
-
- **[0.8.3]** (2026-07-08) — "잘못된 모델 설정하는 경우가 있는데" — the static Antigravity catalog had drifted badly from the LIVE Cloud Code Assist agent backend, and several current wire ids actively LIE about their tier: `gemini-3-flash-agent` is really "Gemini 3.5 Flash (High)" (the flagship agent model, which the name-suffix heuristic filed under the SMALL flash tier), `gemini-pro-agent` is really "Gemini 3.1 Pro (High)" (the code-agent model), and `gemini-3.1-pro-high` is DEPRECATED by the backend in favor of `gemini-pro-agent`. Probed the real `fetchAvailableModels` response (displayNames + agentModelSorts + deprecatedModelIds) and made it the single source of truth.
|
|
270
270
|
|
|
271
271
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
272
272
|
<!-- CHANGELOG:END -->
|
package/package.json
CHANGED
|
@@ -137,14 +137,14 @@ function parseAnthropicVersion(model: string): { kind: "opus" | "sonnet" | "haik
|
|
|
137
137
|
* artifact strip, guidance strip) because every rung resent the SAME model. Scoped to
|
|
138
138
|
* `claude-fable-5` (the model this beta's docs are written against — Mythos-5's
|
|
139
139
|
* invite-only status makes its fallback support unconfirmed) on a DIRECT api.anthropic.com
|
|
140
|
-
* API-key call
|
|
141
|
-
*
|
|
142
|
-
*
|
|
140
|
+
* API-key or Claude-Code OAuth call: the beta's request/response shape is undocumented for
|
|
141
|
+
* a custom baseUrl (Anthropic-compatible third-party hosts), so those paths keep today's
|
|
142
|
+
* reactive (post-refusal) recovery unchanged.
|
|
143
143
|
* `JEO_ANTHROPIC_FALLBACK=0` opts out entirely. */
|
|
144
144
|
const FALLBACK_BETA = "server-side-fallback-2026-06-01";
|
|
145
145
|
function anthropicFallbackModels(model: string, credential: Credential, baseUrl: string | undefined): string[] {
|
|
146
146
|
if (jeoEnv("ANTHROPIC_FALLBACK") === "0") return [];
|
|
147
|
-
if (
|
|
147
|
+
if (baseUrl) return [];
|
|
148
148
|
const v = parseAnthropicVersion(model);
|
|
149
149
|
if (!v || v.kind !== "fable") return [];
|
|
150
150
|
return ["claude-opus-4-8"];
|
|
@@ -397,44 +397,48 @@ async function postAnthropic(
|
|
|
397
397
|
credential: Credential,
|
|
398
398
|
stream: boolean,
|
|
399
399
|
): Promise<Response> {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
400
|
+
let includeTemperature = true;
|
|
401
|
+
let stripArtifacts = false;
|
|
402
|
+
let disableFallback = false;
|
|
403
|
+
|
|
404
|
+
for (let attempt = 1; attempt <= 4; attempt++) {
|
|
405
|
+
const { url, headers, body } = anthropicRequest(
|
|
406
|
+
messages,
|
|
407
|
+
options,
|
|
408
|
+
credential,
|
|
409
|
+
stream,
|
|
410
|
+
includeTemperature,
|
|
411
|
+
stripArtifacts,
|
|
412
|
+
disableFallback,
|
|
413
|
+
);
|
|
414
|
+
const response = await fetch(url, { method: "POST", headers, body, signal: options.signal });
|
|
415
|
+
if (response.ok) return response;
|
|
404
416
|
|
|
405
|
-
|
|
406
|
-
|
|
417
|
+
const detail = await response.text().catch(() => "");
|
|
418
|
+
if (isDeprecatedTemperatureError(response.status, detail) && includeTemperature) {
|
|
419
|
+
includeTemperature = false;
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
if (isReasoningArtifactError(response.status, detail) && !stripArtifacts) {
|
|
423
|
+
stripArtifacts = true;
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
if (isFallbackUnsupportedError(response.status, detail) && !disableFallback) {
|
|
427
|
+
disableFallback = true;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
407
430
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (response.ok) return response;
|
|
418
|
-
throw await providerHttpError("Anthropic", response, stream ? "(stream)" : undefined);
|
|
419
|
-
}
|
|
420
|
-
// Fail-safe: the account/endpoint doesn't support server-side fallback (or the
|
|
421
|
-
// named fallback model rejected THIS request's shape) → retry once without it.
|
|
422
|
-
if (isFallbackUnsupportedError(response.status, detail)) {
|
|
423
|
-
response = await send(true, false, true);
|
|
424
|
-
if (response.ok) return response;
|
|
425
|
-
throw await providerHttpError("Anthropic", response, stream ? "(stream)" : undefined);
|
|
431
|
+
// Unrecoverable error, or all retries for the active error type spent
|
|
432
|
+
const enrichedDetail = response.status === 429 ? `${detail}${anthropicRateLimitEvidence(response.headers)}` : detail;
|
|
433
|
+
throw new ProviderHttpError(
|
|
434
|
+
"Anthropic",
|
|
435
|
+
response.status,
|
|
436
|
+
enrichedDetail,
|
|
437
|
+
stream ? "(stream)" : undefined,
|
|
438
|
+
parseRetryAfter(response.headers.get("retry-after")) ?? parseRetryFromBody(detail),
|
|
439
|
+
);
|
|
426
440
|
}
|
|
427
|
-
|
|
428
|
-
// 429s carry their rate-limit headers in the DETAIL so isUsageLimitError /
|
|
429
|
-
// friendlyProviderError can classify on the full evidence (gjc parity).
|
|
430
|
-
const enrichedDetail = response.status === 429 ? `${detail}${anthropicRateLimitEvidence(response.headers)}` : detail;
|
|
431
|
-
throw new ProviderHttpError(
|
|
432
|
-
"Anthropic",
|
|
433
|
-
response.status,
|
|
434
|
-
enrichedDetail,
|
|
435
|
-
stream ? "(stream)" : undefined,
|
|
436
|
-
parseRetryAfter(response.headers.get("retry-after")) ?? parseRetryFromBody(detail),
|
|
437
|
-
);
|
|
441
|
+
throw new Error("Anthropic request failed: maximum retries reached without response");
|
|
438
442
|
}
|
|
439
443
|
|
|
440
444
|
/** Anthropic usage: with prompt caching the input splits into uncached + cache read +
|
|
@@ -665,12 +669,20 @@ function headersFor(credential: Credential, stream: boolean, model: string, base
|
|
|
665
669
|
"anthropic-version": "2023-06-01",
|
|
666
670
|
};
|
|
667
671
|
}
|
|
668
|
-
|
|
672
|
+
const headers: Record<string, string> = {
|
|
669
673
|
"content-type": "application/json",
|
|
670
674
|
authorization: `Bearer ${credential.token}`,
|
|
671
675
|
"anthropic-version": "2023-06-01",
|
|
672
676
|
...claudeCodeOAuthHeaders(stream, model),
|
|
673
677
|
};
|
|
678
|
+
if (!disableFallback && anthropicFallbackModels(model, credential, baseUrl).length) {
|
|
679
|
+
const betas = headers["anthropic-beta"] ? headers["anthropic-beta"].split(",") : [];
|
|
680
|
+
if (!betas.includes(FALLBACK_BETA)) {
|
|
681
|
+
betas.push(FALLBACK_BETA);
|
|
682
|
+
headers["anthropic-beta"] = betas.join(",");
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return headers;
|
|
674
686
|
}
|
|
675
687
|
if (credential.kind === "api_key") {
|
|
676
688
|
const betas = ANTHROPIC_API_KEY_BETA.slice();
|