pingdotgg / pingdotgg/t3code

[Bug]: Claude 200k context window selection is a no-op; sessions always run at 1M

Open Beginner friendly
#8,405 1 comment 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
23k
Forks
5.9k
Avg merge
11h 14m
Merged PRs (30d)
357

Description

Before submitting
  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.
Area

apps/server

Steps to reproduce
  1. Pick Claude Opus 5 (or Fable 5 / Sonnet 5) in the composer.
  2. Set Context Window → 200k.
  3. Send a turn.
  4. Inspect what the provider actually ran — e.g. read modelUsage[<model>].contextWindow off the SDK result, or look at the maxTokens values T3 persists in orchestration_events.

The session runs at 1,000,000 tokens, not 200,000. The 200k selection has no effect on the request.

Expected behavior

Selecting 200k should make Claude Code run the 200k context window.

Actual behavior

The 200k selection is a no-op. resolveClaudeApiModelId (apps/server/src/provider/Layers/ClaudeProvider.ts:458) encodes the choice purely in the model slug:

export function resolveClaudeApiModelId(modelSelection: ModelSelection): string {
  switch (resolveClaudeContextWindow(modelSelection)) {
    case "1m":  return `${modelSelection.model}[1m]`;
    default:    return modelSelection.model;   // assumed to mean 200k
  }
}

The bare slug does not mean 200k. Claude Code auto-enables the 1M window for these models unless the process env sets CLAUDE_CODE_DISABLE_1M_CONTEXT=1. So T3 spawns --model claude-opus-5, and the session runs at 1M anyway.

Three runs, same SDK (@anthropic-ai/claude-agent-sdk 0.3.170) and same binary (Claude Code 2.1.247), reading modelUsage[].contextWindow off the result message:

model passed env actual context window
claude-opus-5 default 1,000,000
claude-opus-5[1m] default 1,000,000
claude-opus-5 CLAUDE_CODE_DISABLE_1M_CONTEXT=1 200,000

Same via the bare CLI, no SDK involved:

$ claude --model claude-opus-5 --output-format json -p "hi" | jq '.modelUsage | map_values(.contextWindow)'
{ "claude-opus-5": 1000000 }

Confirmed for all three models that expose the Context Window trait: claude-opus-5, claude-fable-5, claude-sonnet-5 all report 1,000,000 when passed as a bare slug.

Not environment-specific — reproduces identically on a local server and on a desktop-managed SSH remote. In both cases the selection reaches the server intact (projection_threads.model_selection_json contains {"id":"contextWindow","value":"200k"}) and the spawned process has a clean env and --model claude-opus-5.

Impact

Major degradation or frequent failure

Version or commit

0.0.36-nightly.20260827.1205

Environment

macOS 26.6.2 + Linux SSH remote; Claude Code 2.1.247; @anthropic-ai/claude-agent-sdk 0.3.170; Claude Max OAuth

Logs or stack traces
# T3 persists Claude Code's own report of the live window.
# A thread whose stored selection is 200k:
#   projection_threads.model_selection_json
#     {"instanceId":"claudeAgent","model":"claude-opus-5",
#      "options":[{"id":"effort","value":"xhigh"},{"id":"contextWindow","value":"200k"}]}
#   orchestration_events payloads for that thread:
#     {"maxTokens": 1000000} x60
Workaround

None from the UI. Selecting 1M vs 200k makes no difference to the request; both run at 1M.

Suggested fix

Set the env var alongside the slug, at the single queryOptions site in apps/server/src/provider/Layers/ClaudeAdapter.ts:4331:

env: {
  ...claudeEnvironment,
  ...(resolveClaudeContextWindow(modelSelection) === "200k"
    ? { CLAUDE_CODE_DISABLE_1M_CONTEXT: "1" }
    : {}),
},

One caveat for whoever picks this up: env is only read at spawn, so the query.setModel() path in sendTurn (ClaudeAdapter.ts:4531) can't flip the window on a live thread — switching 200k↔1M mid-thread would need a session restart to take effect.

Related
  • #5286 — same root cause, but filed as a cosmetic meter bug. It's the reverse: the meter is the accurate part. selectedClaudeContextWindow seeds it at 200k, then Claude Code's honest report of 1,000,000 overwrites it at ClaudeAdapter.ts:2153.
  • #2733 — same report, closed as a duplicate of #2394. Its one comment already named CLAUDE_CODE_DISABLE_1M_CONTEXT, but the linked PR's fork was deleted.
  • #2394 — closed in a maintenance sweep with "a new report would need provider request diagnostics". This report provides them.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with resolveClaudeApiModelId in apps/server/src/provider/Layers/ClaudeProvider.ts and the queryOptions env construction at apps/server/src/provider/Layers/ClaudeAdapter.ts:4331. Verify how the 200k selection reaches the spawned process, then confirm the resulting SDK contextWindow or persisted maxTokens reports 200k while 1M remains unchanged. Note that changing the selection through sendTurn cannot affect an already-running session because env is read at spawn.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.