From 0883e0a78327048959317b59641891eb3b1289de Mon Sep 17 00:00:00 2001 From: Epinephrine <27862058+luvs01@users.noreply.github.com> Date: Tue, 13 Oct 2026 04:24:26 +0000 Subject: [PATCH 1/3] fix(runtime): bound overflow parsing and batch replay scrubs Limit overflow normalization to a bounded prefix and collect rejected native reasoning blobs before scrubbing raw and parsed replay history once. Preserve existing route and credential provenance checks. Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- src/claude/outbound.ts | 10 ++-- src/server/responses/core-replay.ts | 11 ++-- structure/runtime.md | 2 +- structure/transports/responses.md | 2 +- ...claude-native-reasoning-provenance.test.ts | 54 +++++++++++++++++++ .../claude-prompt-too-long.test.ts | 22 ++++++++ 6 files changed, 92 insertions(+), 9 deletions(-) diff --git a/src/claude/outbound.ts b/src/claude/outbound.ts index 60924c92def..10a19ae26ed 100644 --- a/src/claude/outbound.ts +++ b/src/claude/outbound.ts @@ -81,12 +81,16 @@ export function anthropicErrorType(status: number): string { * (devlog/_plan/261009_claude_1m_default/010). */ const CLAUDE_PROMPT_TOO_LONG_RE = /prompt is too long|input is too long for requested model/i; -const STATED_CONTEXT_COUNTS_RE = /maximum context length is (\d+) tokens[\s\S]*?(?:resulted in|you requested) (\d+) tokens/i; +const MAX_OVERFLOW_MESSAGE_CHARS = 64 * 1024; +const STATED_CONTEXT_LIMIT_RE = /maximum context length is (\d+) tokens/i; +const STATED_REQUEST_COUNT_RE = /(?:resulted in|you requested) (\d+) tokens/i; export function claudePromptTooLongMessage(message: string): string { + message = message.slice(0, MAX_OVERFLOW_MESSAGE_CHARS); if (CLAUDE_PROMPT_TOO_LONG_RE.test(message)) return message; - const counts = STATED_CONTEXT_COUNTS_RE.exec(message); - if (counts) return `prompt is too long: ${counts[2]} tokens > ${counts[1]} maximum`; + const limit = STATED_CONTEXT_LIMIT_RE.exec(message); + const requested = limit && STATED_REQUEST_COUNT_RE.exec(message.slice(limit.index + limit[0].length)); + if (limit && requested) return `prompt is too long: ${requested[1]} tokens > ${limit[1]} maximum`; return `prompt is too long: ${message}`; } diff --git a/src/server/responses/core-replay.ts b/src/server/responses/core-replay.ts index d842deefb51..66fdfa819ed 100644 --- a/src/server/responses/core-replay.ts +++ b/src/server/responses/core-replay.ts @@ -125,11 +125,13 @@ export function bindRouteReasoningReplayScope(args: { if (owner) parsed._nativeReasoningBoundOwner = owner; else delete parsed._nativeReasoningBoundOwner; if (parsed._nativeReasoningReplay?.size) { + const rejected = new Set(); for (const [blob, tag] of parsed._nativeReasoningReplay) { if (!nativeReasoningTagMatches(nativeReasoningTag(owner, blob), tag)) { - stripNativeReasoningBlob(parsed, blob); + rejected.add(blob); } } + if (rejected.size) stripNativeReasoningBlobs(parsed, rejected); } const continuationDestinationIdentity = providerContinuationDestinationIdentity(parsed, provider); const continuationOwner = providerContinuationOwnerFromReplayIdentity( @@ -169,11 +171,11 @@ export function bindRouteReasoningReplayScope(args: { bindProviderContinuationForRoute(parsed, continuationOwner); } -function stripNativeReasoningBlob(parsed: OcxParsedRequest, blob: string): void { +function stripNativeReasoningBlobs(parsed: OcxParsedRequest, rejected: ReadonlySet): void { const input = (parsed._rawBody as { input?: unknown } | undefined)?.input; if (Array.isArray(input)) { for (const item of input) { - if (item && typeof item === "object" && item.type === "reasoning" && item.encrypted_content === blob) { + if (item && typeof item === "object" && item.type === "reasoning" && rejected.has(item.encrypted_content)) { delete item.encrypted_content; delete item.id; } @@ -187,7 +189,8 @@ function stripNativeReasoningBlob(parsed: OcxParsedRequest, blob: string): void const item: unknown = JSON.parse(part.signature); if (!item || typeof item !== "object" || Array.isArray(item)) continue; const reasoning = item as Record; - if (reasoning.type !== "reasoning" || reasoning.encrypted_content !== blob) continue; + if (reasoning.type !== "reasoning" || typeof reasoning.encrypted_content !== "string" + || !rejected.has(reasoning.encrypted_content)) continue; delete reasoning.encrypted_content; delete reasoning.id; part.signature = JSON.stringify(reasoning); diff --git a/structure/runtime.md b/structure/runtime.md index d49f43597b9..6901666ba6d 100644 --- a/structure/runtime.md +++ b/structure/runtime.md @@ -1,6 +1,6 @@ # Runtime -The minute sweep checks persisted activation deadlines locally; only missing deadlines trigger metadata discovery. See the [quota activation contract](providers/openai-tiers.md#public-provider-contract). Codex control-plane ids are defined in the dependency-free `src/codex/control-plane-models.ts`; `src/router.ts` routes these exact ids unchanged to canonical OpenAI, retaining the existing error when no OpenAI provider is enabled. They do not widen the public native roster. Catalog requests and scheduled source refreshes follow the [nonblocking catalog observation contract](catalog.md#shared-catalog). Async runtime persistence rejects observed selection/epoch changes and returns detached frozen results; bounded exec rejects promptly and releases output readers on deadline or abort, independently awaits actual child exit, and escalates SIGTERM to SIGKILL after the shared 2-second grace (Windows termination is forceful). +The minute sweep checks persisted activation deadlines locally; only missing deadlines trigger metadata discovery. See the [quota activation contract](providers/openai-tiers.md#public-provider-contract). Codex control-plane ids are defined in the dependency-free `src/codex/control-plane-models.ts`; `src/router.ts` routes these exact ids unchanged to canonical OpenAI, retaining the existing error when no OpenAI provider is enabled. They do not widen the public native roster. Catalog requests and scheduled source refreshes follow the [nonblocking catalog observation contract](catalog.md#shared-catalog). Async runtime persistence rejects observed selection/epoch changes and returns detached frozen results; bounded exec rejects promptly and releases output readers on deadline or abort, independently awaits actual child exit, and escalates SIGTERM to SIGKILL after the shared 2-second grace (Windows termination is forceful). Claude overflow normalization examines at most 64 Ki characters, extracts stated context/request counts in separate forward scans, retains the bounded rewritten prefix, and leaves other error classifications intact; the managed native Messages SSE route follows the same contract (`tests/claude-integration/claude-prompt-too-long.test.ts`). ## Bun runtime and test runner diff --git a/structure/transports/responses.md b/structure/transports/responses.md index 723d5173da7..56dce4d12f0 100644 --- a/structure/transports/responses.md +++ b/structure/transports/responses.md @@ -334,7 +334,7 @@ again held its entry for the life of the process. A replayed compaction item carries an `encrypted_content` blob only its minting backend can decode, and the client replays it on every later turn. The proxy's own `ocx1:` envelopes are transparent base64, so they always lower to plain user messages. A native blob is relayed only when there is no known serving-identity mismatch and the destination is known to decode native blobs — the canonical ChatGPT forward surface, the official OpenAI API, or a provider with the explicit `decodesNativeCompactionBlobs` capability. The destination gate alone is insufficient because more than one backend, including OpenAI and xAI, mints native blobs: a destination can decode its own blob without being able to decode the previous backend's. -The same serving-identity mismatch signal therefore strips reasoning `encrypted_content` and degrades native compaction blobs through the existing opaque-note path. Claude-native reasoning adds a per-blob tag check at every route binding: only the +The same serving-identity mismatch signal therefore strips reasoning `encrypted_content` and degrades native compaction blobs through the existing opaque-note path. Claude-native reasoning batches rejected blob tags into one scrub pass: only the matching durable endpoint and generation-bearing credential retain raw and parsed carriers. Without recorded thread identity, the destination gate remains. Noncanonical forward providers receive no caller credentials and may point at any backend. On any other routed destination the blob also degrades to the same opaque note the bridged parser uses, because forwarding it there fails the turn and the item outlives the failure in the client transcript, repeating on every later turn including the compaction turn the proxy itself drives. With `store: false`, request sanitization strips ids from every input item, including compact-wire items, matching codex-rs (`core/src/client.rs:918-925`). Compact-wire items remain exempt from response-side field backfill. diff --git a/tests/claude-integration/claude-native-reasoning-provenance.test.ts b/tests/claude-integration/claude-native-reasoning-provenance.test.ts index 659624ed2f2..66568cb4edc 100644 --- a/tests/claude-integration/claude-native-reasoning-provenance.test.ts +++ b/tests/claude-integration/claude-native-reasoning-provenance.test.ts @@ -137,6 +137,60 @@ describe("Claude native reasoning provenance", () => { expect(nativeReasoningOwnerForRoute({ provider: oauth, oauthCredentialSnapshot: { accountId: "slot" } })).toBeUndefined(); }); + test("rejects many distinct blobs in one history pass and preserves valid replay until a route switch", () => { + const selected = provider(); + const owner = nativeReasoningOwnerForRoute({ provider: selected }); + const payload = turn(); + for (let i = 0; i < 128; i++) { + const blob = `ciphertext-${i}`; + payload.messages.push({ role: "assistant", content: [ + { type: "thinking", thinking: "Visible plan.", signature: encodeReasoningEnvelope({ nat: { + enc: blob, model: MODEL, id: `rs_${i}`, tag: i === 0 ? nativeReasoningTag(owner, blob)! : "invalid", + } }) }, + { type: "text", text: "Done." }, + ] } as typeof payload.messages[number]); + } + const translated = anthropicToResponsesTranslation(payload); + const parsed = parseRequest(translated.body); + parsed._nativeReasoningReplay = translated.nativeReasoningReplay; + expect(parsed._nativeReasoningReplay?.size).toBe(128); + let signatureReads = 0; + let carriers = 0; + for (const message of parsed.context.messages) { + if (message.role !== "assistant" || !Array.isArray(message.content)) continue; + for (const part of message.content) { + if (part.type !== "thinking" || typeof part.signature !== "string") continue; + carriers++; + let value = part.signature; + Object.defineProperty(part, "signature", { + enumerable: true, configurable: true, + get() { signatureReads++; return value; }, + set(next: string) { value = next; }, + }); + } + } + expect(carriers).toBe(128); + const bind = (target: OcxProviderConfig) => { + signatureReads = 0; + bindRouteReasoningReplayScope({ parsed, providerName: "a", provider: target, adapterName: "openai-responses" }); + expect(signatureReads).toBeLessThanOrEqual(2 * carriers); + }; + bind(selected); + for (const history of [parsed._rawBody, parsed.context]) { + const encoded = JSON.stringify(history); + expect(encoded).toContain("ciphertext-0"); + expect(encoded).not.toContain("ciphertext-1"); + } + bind(provider(undefined, "key-b")); + bind(selected); + for (const history of [parsed._rawBody, parsed.context]) { + const encoded = JSON.stringify(history); + expect(encoded).not.toContain("ciphertext-"); + expect(encoded).not.toContain("rs_127"); + expect(encoded).toContain("Visible plan."); + } + }); + test("OAuth generation changes strip both replay carriers while the same generation keeps them", () => { const oauth = { ...provider(), authMode: "oauth" } as OcxProviderConfig; const minted = nativeReasoningOwnerForRoute({ provider: oauth, oauthCredentialSnapshot: { accountId: "slot", generation: 1 } })!; diff --git a/tests/claude-integration/claude-prompt-too-long.test.ts b/tests/claude-integration/claude-prompt-too-long.test.ts index 9c093f6bba7..8cc6cb5f655 100644 --- a/tests/claude-integration/claude-prompt-too-long.test.ts +++ b/tests/claude-integration/claude-prompt-too-long.test.ts @@ -58,6 +58,15 @@ describe("claudePromptTooLongMessage", () => { expect(CLAUDE_CODE_GAP_RE.test(message)).toBe(false); }); + test("bounds repeated context prefixes and scans a request count only after the first limit", () => { + const repeated = "maximum context length is 1 tokens; ".repeat(4_000); + expect(claudePromptTooLongMessage(repeated)).toBe(`prompt is too long: ${repeated.slice(0, 64 * 1024)}`); + expect(claudePromptTooLongMessage("you requested 99 tokens; maximum context length is 10 tokens")) + .not.toContain("99 tokens > 10 maximum"); + expect(claudePromptTooLongMessage("maximum context length is 10 tokens; maximum context length is 20 tokens; you requested 30 tokens")) + .toBe("prompt is too long: 30 tokens > 10 maximum"); + }); + test("leaves Anthropic wording unchanged", () => { for (const text of ["prompt is too long: 1000 tokens > 900 maximum", "Input is too long for requested model."]) { expect(claudePromptTooLongMessage(text)).toBe(text); @@ -223,6 +232,19 @@ describe("native Messages lane", () => { expect(data.error.message).toBe("prompt is too long: Your request exceeded model token limit: 262144"); }); + test("bounds oversized overflow messages on the managed native SSE route", async () => { + const message = "maximum context length is 1 tokens; ".repeat(4_000); + const frame = `event: error\ndata: ${JSON.stringify({ type: "error", error: { + type: "invalid_request_error", message, + } })}\n\n`; + const { response, text } = await send(nativeConfig(() => new Response(frame, { + headers: { "content-type": "text/event-stream" }, + })), true); + expect(response.status).toBe(200); + const data = JSON.parse(text.split("\n").find(line => line.startsWith("data:"))!.slice(5)); + expect(data.error.message).toBe(`prompt is too long: ${message.slice(0, 64 * 1024)}`); + }); + test("stall detection still times raw upstream bytes, not whole rewritten frames", async () => { // One large delta frame arrives in fragments over ~1.6s with a 1s stall limit. Each fragment // must reset the deadline; a frame-buffering rewrite placed before the tap would not. From ede44be85740676c606eb61e25bfa0b5e3153704 Mon Sep 17 00:00:00 2001 From: Epinephrine <27862058+luvs01@users.noreply.github.com> Date: Tue, 13 Oct 2026 09:49:51 +0000 Subject: [PATCH 2/3] docs(claude): explain bounded overflow error messages --- .../src/content/docs/fr/guides/claude-code.md | 4 ++++ .../src/content/docs/guides/claude-code.md | 23 +++++++++++++++---- .../src/content/docs/ja/guides/claude-code.md | 4 ++++ .../src/content/docs/ko/guides/claude-code.md | 4 ++++ .../src/content/docs/ru/guides/claude-code.md | 4 ++++ .../src/content/docs/tr/guides/claude-code.md | 4 ++++ .../content/docs/zh-cn/guides/claude-code.md | 4 ++++ .../content/docs/zh-tw/guides/claude-code.md | 4 ++++ 8 files changed, 47 insertions(+), 4 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/claude-code.md b/docs-site/src/content/docs/fr/guides/claude-code.md index 374ea9949eb..f8b1796bdac 100644 --- a/docs-site/src/content/docs/fr/guides/claude-code.md +++ b/docs-site/src/content/docs/fr/guides/claude-code.md @@ -486,6 +486,10 @@ Trois états de configuration : La valeur de compactage est réglable dans **Connexion → Claude**. **Avertissement :** une valeur supérieure à la fenêtre réelle d'un modèle rend ce modèle inutilisable : les tours échouent avant que le résumé puisse se déclencher. +La normalisation des erreurs de dépassement de contexte utilise uniquement les 65 536 premières unités de code UTF-16 du message du fournisseur. +Les diagnostics ou nombres de jetons situés après cette limite peuvent disparaître sans marqueur de troncature. +Consultez le [guide anglais](/guides/claude-code/#auto-context-big-context-models-without-the-200k-ceiling) pour les limites exactes et les conditions de reprise des nombres de jetons. + Les modèles Anthropic natifs dont le contexte est inférieur à 1M ne sont jamais marqués automatiquement. Une fenêtre de compactage que vous exportez vous-même reste prioritaire pour le marquage des variables de lancement ; le proxy s'appuie sur votre valeur pour déterminer les modèles qui peuvent recevoir le marqueur sans risque. Les lignes de découverte ignorent cet export et conservent le plancher fixe. diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index d780ece5c1a..e879501e26a 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -675,11 +675,26 @@ window breaks that model — the chat errors out before the summary can fire. A model's advertised context window does not guarantee that a tool-heavy request fits the upstream input limit. A classified input-limit rejection reaches Claude Code as `invalid_request_error` with `context_length_exceeded`, worded the way Anthropic words it -(`prompt is too long: …`, with token counts when the provider states them), so Claude Code +(`prompt is too long: …`), so Claude Code compacts the conversation and retries on its own; a non-streaming response uses HTTP 400 instead -of a retryable 502. Providers on the native Messages lane get the same wording. A throughput -limit that only mentions tokens (for example "too many tokens per minute") keeps its text and is -not treated as an overflow. If compaction itself still exceeds the limit, preserve the original +of a retryable 502. Providers on the native Messages lane get the same wording. + +Overflow normalization uses only the first **65,536 UTF-16 code units** of the provider's error +message, including messages that already use Anthropic's wording. This is a string-length limit, +not a byte or token limit. Text beyond it is discarded without an ellipsis or truncation marker, +so diagnostic details and token counts near the end may be absent from the error Claude Code +receives. The added `prompt is too long: ` prefix can make the final message longer than this +retained portion. + +Within that portion, recognized Anthropic wording is kept; otherwise OpenCodex emits +`prompt is too long: tokens > maximum` only when it finds +`maximum context length is tokens` followed by `resulted in tokens` or +`you requested tokens`. It uses the first stated limit and the first matching request +count after it. If that pair is missing, reversed, or cut off, it prefixes the retained text with +`prompt is too long: ` without inventing counts. A throughput limit that only mentions tokens +(for example "too many tokens per minute") keeps its text and is not treated as an overflow. + +If compaction itself still exceeds the limit, preserve the original history and try compacting a fork with fewer enabled tool or MCP schemas, if your client supports that workflow. A `[1m]` marker or larger client accounting setting does not raise the upstream limit, and OpenCodex does not silently remove history or tools to make it fit. diff --git a/docs-site/src/content/docs/ja/guides/claude-code.md b/docs-site/src/content/docs/ja/guides/claude-code.md index 07899bcfb0b..bd35bc626dc 100644 --- a/docs-site/src/content/docs/ja/guides/claude-code.md +++ b/docs-site/src/content/docs/ja/guides/claude-code.md @@ -338,6 +338,10 @@ Claude Code は未知モデルのコンテキストを 200k トークンとし **接続 → Claude** で圧縮値を調整できます。**警告:** モデルの実際のコンテキストウィンドウより大きく上げると 要約を開始する前にチャットエラーが発生します。 +コンテキスト超過エラーの正規化では、プロバイダーのエラーメッセージの先頭 65,536 UTF-16 コード単位だけを使います。 +末尾の診断情報やトークン数は、省略を示す印なしで失われることがあります。 +詳しい制限とトークン数の扱いは[英語ガイド](/guides/claude-code/#auto-context-big-context-models-without-the-200k-ceiling)を参照してください。 + 1M 未満のネイティブ Anthropic モデルには自動で標識を付けません。自分で export した圧縮値は起動スロットの標識に優先し、プロキシは**ユーザーが指定した**値を基準にどのモデルに安全に標識を付けるか決定します。ディスカバリー行はその export を無視し、固定の下限を保ちます。 直接編集した設定値が不正な場合は 829,800 に戻ります。 diff --git a/docs-site/src/content/docs/ko/guides/claude-code.md b/docs-site/src/content/docs/ko/guides/claude-code.md index f5ee8cf4068..58bd79779d6 100644 --- a/docs-site/src/content/docs/ko/guides/claude-code.md +++ b/docs-site/src/content/docs/ko/guides/claude-code.md @@ -370,6 +370,10 @@ Claude Code는 알 수 없는 모델의 컨텍스트를 200k 토큰으로 계산 **연결 → Claude**에서 압축 값을 조절할 수 있어요. **경고:** 모델의 실제 컨텍스트 창보다 크게 올리면 요약을 시작하기 전에 채팅 오류가 발생해요. +컨텍스트 초과 오류를 정규화할 때는 제공자 오류 메시지의 첫 65,536 UTF-16 코드 단위만 사용해요. +뒤쪽 진단 내용이나 토큰 수는 별도 잘림 표시 없이 빠질 수 있어요. +자세한 제한과 토큰 수 처리 조건은 [영문 가이드](/guides/claude-code/#auto-context-big-context-models-without-the-200k-ceiling)를 참고하세요. + 1M 미만인 네이티브 Anthropic 모델에는 자동으로 표식을 붙이지 않아요. 직접 내보낸 압축 값은 실행 슬롯 표식에서 항상 우선하며, 프록시는 **사용자가 지정한** 값을 기준으로 어떤 모델에 안전하게 표식을 붙일지 결정해요. 디스커버리 행은 그 값을 무시하고 고정 하한을 유지해요. diff --git a/docs-site/src/content/docs/ru/guides/claude-code.md b/docs-site/src/content/docs/ru/guides/claude-code.md index 972f5f7e7d7..018dd5db1da 100644 --- a/docs-site/src/content/docs/ru/guides/claude-code.md +++ b/docs-site/src/content/docs/ru/guides/claude-code.md @@ -359,6 +359,10 @@ Anthropic сохраняют канонические id в обоих инте реального окна модели, эта модель ломается — чат завершится ошибкой раньше, чем успеет сработать резюмирование. +При нормализации ошибок переполнения контекста используются только первые 65 536 единиц кода UTF-16 сообщения провайдера. +Диагностические сведения и числа токенов за этой границей могут исчезнуть без отметки об усечении. +Точные ограничения и условия переноса чисел токенов описаны в [английском руководстве](/guides/claude-code/#auto-context-big-context-models-without-the-200k-ceiling). + Нативные модели Anthropic с окном меньше 1M никогда не помечаются автоматически. Экспортированное вами окно сжатия имеет приоритет при пометке слотов запуска (прокси использует ВАШЕ значение, чтобы решить, какие модели можно безопасно пометить). Строки обнаружения игнорируют этот экспорт и сохраняют фиксированный пол. Некорректные значения, внесённые в конфигурацию вручную, откатываются diff --git a/docs-site/src/content/docs/tr/guides/claude-code.md b/docs-site/src/content/docs/tr/guides/claude-code.md index cd60138f3fc..ce2e074d9a7 100644 --- a/docs-site/src/content/docs/tr/guides/claude-code.md +++ b/docs-site/src/content/docs/tr/guides/claude-code.md @@ -546,6 +546,10 @@ Sıkıştırma değeri Claude sayfasında ayarlanabilir. **Uyarı:** bir modelin penceresinin üzerine çıkarmak o modeli bozar — sohbet özetleme tetiklenmeden önce hata verir. +Bağlam taşması hataları normalleştirilirken sağlayıcının hata mesajının yalnızca ilk 65.536 UTF-16 kod birimi kullanılır. +Bu sınırdan sonraki tanılama ayrıntıları veya token sayıları, kesilme işareti eklenmeden kaybolabilir. +Kesin sınırlar ve token sayılarının aktarılma koşulları için [İngilizce kılavuza](/guides/claude-code/#auto-context-big-context-models-without-the-200k-ceiling) bakın. + 1M altı yerel Anthropic modelleri hiçbir zaman otomatik olarak işaretlenmez. Kendi dışa aktardığınız sıkıştırma penceresi, başlatma yuvası işaretlemesinde her zaman kazanır (proxy hangi modellerin işaretlenmesinin güvenli olduğuna karar vermek için SİZİN değerinizi kullanır). diff --git a/docs-site/src/content/docs/zh-cn/guides/claude-code.md b/docs-site/src/content/docs/zh-cn/guides/claude-code.md index 6b0c397f80a..8d298836870 100644 --- a/docs-site/src/content/docs/zh-cn/guides/claude-code.md +++ b/docs-site/src/content/docs/zh-cn/guides/claude-code.md @@ -318,6 +318,10 @@ v1 别名按字面解码(历史上 model ID 中包含的两字符序列 `~s` / 可以在 Claude 页面调整压缩值。**警告:**如果将其提高到超过模型的实际窗口,该模型将无法正常 工作——聊天会在触发摘要之前报错。 +规范化上下文超限错误时,只使用提供方错误消息的前 65,536 个 UTF-16 代码单元。 +后面的诊断信息或 token 数可能被丢弃,且不会添加截断标记。 +详细限制和 token 数处理条件见[英文指南](/guides/claude-code/#auto-context-big-context-models-without-the-200k-ceiling)。 + 低于 1M 的原生 Anthropic 模型绝不会被自动标记。你自行导出的压缩值在启动槽位标记上始终优先(代理会使用**你的** 值来判断哪些模型可以安全标记)。发现列表忽略该导出值并保持固定下限。手动编辑配置时填入的无效值会回退到 829,800。 diff --git a/docs-site/src/content/docs/zh-tw/guides/claude-code.md b/docs-site/src/content/docs/zh-tw/guides/claude-code.md index 33395a06123..6d4e9d955c7 100644 --- a/docs-site/src/content/docs/zh-tw/guides/claude-code.md +++ b/docs-site/src/content/docs/zh-tw/guides/claude-code.md @@ -394,6 +394,10 @@ v1 別名按字面解碼(歷史上 model ID 中包含的兩字元序列 `~s` / 可以在 Claude 頁面調整壓縮值。**警告:**如果將其提高到超過模型的實際視窗,該模型將無法正常 工作——聊天會在觸發摘要之前報錯。 +正規化上下文超限錯誤時,只使用提供方錯誤訊息的前 65,536 個 UTF-16 程式碼單元。 +後面的診斷資訊或 token 數可能被捨棄,且不會新增截斷標記。 +詳細限制和 token 數處理條件請參閱[英文指南](/guides/claude-code/#auto-context-big-context-models-without-the-200k-ceiling)。 + 低於 1M 的原生 Anthropic 模型絕不會被自動標記。你自行匯出的壓縮值在啟動槽位標記上始終優先(代理會使用**你的** 值來判斷哪些模型可以安全標記)。探索列表忽略該匯出值並保持固定下限。手動編輯設定時填入的無效值會回退到 829,800。 From f7d271cf93d911325d7030370c376e11cc944da7 Mon Sep 17 00:00:00 2001 From: Epinephrine <27862058+luvs01@users.noreply.github.com> Date: Tue, 13 Oct 2026 10:07:37 +0000 Subject: [PATCH 3/3] docs(claude): describe overflow prefix spacing in prose --- docs-site/src/content/docs/guides/claude-code.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index e879501e26a..92ea65980a5 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -683,15 +683,15 @@ Overflow normalization uses only the first **65,536 UTF-16 code units** of the p message, including messages that already use Anthropic's wording. This is a string-length limit, not a byte or token limit. Text beyond it is discarded without an ellipsis or truncation marker, so diagnostic details and token counts near the end may be absent from the error Claude Code -receives. The added `prompt is too long: ` prefix can make the final message longer than this -retained portion. +receives. The added `prompt is too long:` prefix, followed by a space, can make the final message +longer than this retained portion. Within that portion, recognized Anthropic wording is kept; otherwise OpenCodex emits `prompt is too long: tokens > maximum` only when it finds `maximum context length is tokens` followed by `resulted in tokens` or `you requested tokens`. It uses the first stated limit and the first matching request count after it. If that pair is missing, reversed, or cut off, it prefixes the retained text with -`prompt is too long: ` without inventing counts. A throughput limit that only mentions tokens +`prompt is too long:` followed by a space, without inventing counts. A throughput limit that only mentions tokens (for example "too many tokens per minute") keeps its text and is not treated as an overflow. If compaction itself still exceeds the limit, preserve the original