Skip to content

Commit 99bb2e8

Browse files
saucamclaude
andauthored
fix: size the 1M context window for the bracket alias form (opus[1m]) (#302)
`contextWindowForModel` matched only the `-1m` suffix, so the bracket form Claude Code actually emits — `opus[1m]`, `claude-opus-5[1m]` — fell through to the conservative 200k default. Asking EXPLICITLY for the 1M variant therefore sized the window WORSE than the bare `opus` alias, which resolves to 1M. Observed on a live session pinned to `opus[1m]`: codeoid computed a 200k window against ~999k of real usage. Affected consumers: - the percent-of-window figure on SessionInfo (session.ts) — reads ~500% - the fork / provider-switch seed budget (seedBudgetChars via targetContextWindow) — 5x too small, so history seeds over-truncate Auto-rotate is NOT affected: decideRotation is passed the static `Session.CONTEXT_WINDOW` (1M), not this per-model resolution. This also did NOT cause the "prompt is too long" overflow seen on that session — that has a separate cause (compaction firing reactively after the API error rather than proactively). This is an independent defect surfaced while investigating it. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 3028190 commit 99bb2e8

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

src/daemon/context-windows.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,23 @@ describe("contextWindowForModel", () => {
3535
expect(contextWindowForModel("claude-sonnet-4-5-1m")).toBe(ONE_MILLION_CONTEXT);
3636
});
3737

38+
test("bracket [1m] form -> 1M (the form Claude Code actually emits)", () => {
39+
// Regression: these resolved to 200k, so asking EXPLICITLY for the 1M
40+
// variant sized the window WORSE than the bare `opus` alias — observed on
41+
// a live session running `opus[1m]`, which reported ~500% occupancy and a
42+
// 5x-too-small fork seed budget.
43+
expect(contextWindowForModel("opus[1m]")).toBe(ONE_MILLION_CONTEXT);
44+
expect(contextWindowForModel("sonnet[1m]")).toBe(ONE_MILLION_CONTEXT);
45+
expect(contextWindowForModel("claude-opus-5[1m]")).toBe(ONE_MILLION_CONTEXT);
46+
// Case-insensitive, like every other branch.
47+
expect(contextWindowForModel("OPUS[1M]")).toBe(ONE_MILLION_CONTEXT);
48+
});
49+
50+
test("haiku stays 200k in bracket form too", () => {
51+
// haiku has no 1M variant; a bracket suffix must not manufacture one.
52+
expect(contextWindowForModel("haiku")).toBe(DEFAULT_CONTEXT_WINDOW);
53+
});
54+
3855
test("unknown claude model -> conservative 200k miss", () => {
3956
expect(contextWindowForModel("claude-sonnet-4-0")).toBe(DEFAULT_CONTEXT_WINDOW);
4057
expect(contextWindowForModel("custom-model")).toBe(DEFAULT_CONTEXT_WINDOW);

src/daemon/context-windows.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,14 @@ export function contextWindowForModel(modelId: string | undefined | null): numbe
5151
for (const family of ONE_MILLION_FAMILIES) {
5252
if (m.includes(family)) return ONE_MILLION_CONTEXT;
5353
}
54-
if (m.includes("-1m")) return ONE_MILLION_CONTEXT;
54+
// The 1M variant appears in two forms: the suffix on a full model id
55+
// (`claude-opus-4-5-1m`) and the BRACKET form Claude Code uses on aliases
56+
// and ids alike (`opus[1m]`, `claude-opus-5[1m]`). Matching only the former
57+
// meant an EXPLICIT 1M request resolved to 200k while the bare `opus` alias
58+
// correctly resolved to 1M — inverting the caller's intent, and under-sizing
59+
// the window that drives the percent-of-window display, the fork seed budget
60+
// (seedBudgetChars), and auto-rotate occupancy.
61+
if (m.includes("-1m") || m.includes("[1m]")) return ONE_MILLION_CONTEXT;
5562

5663
// Aliases (matching the daemon's model resolver: opus → Opus 4.8,
5764
// sonnet → Sonnet 5 — both 1M; haiku → Haiku 4.5 at 200k).

0 commit comments

Comments
 (0)