From 7d406eb358ba13d00460cedc37b0dfed43a98d6c Mon Sep 17 00:00:00 2001 From: Flood Sung Date: Thu, 14 May 2026 06:17:28 +0000 Subject: [PATCH] fix(claude): only enable 1M context beta when model has [1m] suffix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both executors unconditionally set: queryOptions.betas = ['context-1m-2025-08-07']; The comment acknowledged this was a no-op on OAuth / Pro-Max (where betas are ignored and the `[1m]` suffix is the actual lever), but on API-key auth the SDK honors the beta header — so every API-key user got 1M context for *every* model, including plain `opus-4-7`. Visible symptom: `/model claude-opus-4-7` showed a 1000k context window in the card footer (and billed at 2× the rate) instead of the expected 200k. The user only intended 1M on the explicit `claude-opus-4-7[1m]` form. Fix: only emit the beta flag when the model name contains `[1m]`. That makes the suffix the single canonical signal for both auth paths — SDK parses it directly, and we re-send the matching beta as belt-and-braces for any auth mode that needs the explicit header. Both `executor.ts` and `persistent-executor.ts` had the same unconditional line; both fixed. Comment notes they must stay in sync. No new tests — the SDK's beta dispatch is mocked away in vitest, and the change is one conditional. All 291 existing tests still pass. Co-Authored-By: Claude Opus 4.7 --- src/engines/claude/executor.ts | 17 ++++++++++++++--- src/engines/claude/persistent-executor.ts | 17 +++++++++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/engines/claude/executor.ts b/src/engines/claude/executor.ts index 5d413d3e..8839f43c 100644 --- a/src/engines/claude/executor.ts +++ b/src/engines/claude/executor.ts @@ -365,9 +365,20 @@ export class ClaudeExecutor { queryOptions.resume = sessionId; } - // Beta flags are ignored by the SDK on OAuth/Pro-Max auth. For 1M context, - // use the model-name suffix `[1m]` (e.g. `claude-opus-4-7[1m]`) instead. - queryOptions.betas = ['context-1m-2025-08-07']; + // 1M context window is opt-in via the `[1m]` model-name suffix + // (`claude-opus-4-7[1m]`). The suffix is the canonical signal — the SDK + // parses it directly on both OAuth and API-key auth paths. + // + // We *also* set the matching `betas` flag when the suffix is present, + // belt-and-braces: harmless when the SDK already inferred it, and a + // safety net if a future SDK rev only honors the explicit beta header + // for some auth modes. Without the suffix, leave `betas` unset — + // setting it unconditionally on API-key auth had the side-effect of + // forcing every model (e.g. plain `opus-4-7`) into 1M context at 2× + // the price, which the user never asked for. + if (this.config.claude.model?.includes('[1m]')) { + queryOptions.betas = ['context-1m-2025-08-07']; + } return queryOptions; } diff --git a/src/engines/claude/persistent-executor.ts b/src/engines/claude/persistent-executor.ts index 774f593e..35515dce 100644 --- a/src/engines/claude/persistent-executor.ts +++ b/src/engines/claude/persistent-executor.ts @@ -365,8 +365,21 @@ export class PersistentClaudeExecutor extends EventEmitter { append: '\n\n' + appendSections.join('\n\n'), }; } - // Beta flags (parity with legacy executor) - queryOptions.betas = ['context-1m-2025-08-07']; + // 1M context window is opt-in via the `[1m]` model-name suffix + // (`claude-opus-4-7[1m]`). The suffix is the canonical signal — the SDK + // parses it directly on both OAuth and API-key auth paths. + // + // We *also* set the matching `betas` flag when the suffix is present, + // belt-and-braces: harmless when the SDK already inferred it, and a + // safety net if a future SDK rev only honors the explicit beta header + // for some auth modes. Without the suffix, leave `betas` unset — + // setting it unconditionally on API-key auth had the side-effect of + // forcing every model (e.g. plain `opus-4-7`) into 1M context at 2× + // the price, which the user never asked for. (Parity with legacy + // executor; both spots must stay in sync.) + if (this.options.model?.includes('[1m]')) { + queryOptions.betas = ['context-1m-2025-08-07']; + } // Hooks: AskUserQuestion (mirrored from legacy executor — required so // that questions can be answered by users via Feishu cards) + Agent