diff --git a/src/agent_env/agents/agents/claude-code/claude_bridge.py b/src/agent_env/agents/agents/claude-code/claude_bridge.py index b3edc851..5e86f05d 100644 --- a/src/agent_env/agents/agents/claude-code/claude_bridge.py +++ b/src/agent_env/agents/agents/claude-code/claude_bridge.py @@ -560,6 +560,16 @@ async def feed_stdin() -> None: stderr_task.cancel() +# Behind a gateway the CLI gives a bare id of these a 200K window, and envs whose tool definitions alone pass that +# make it exit with "Autocompact is thrashing". Add a model only once the pinned CLI maps its [1m] form. +_NATIVE_1M_MODELS = frozenset({"claude-opus-5", "claude-opus-5-5", "claude-fable-5-1", "claude-opus-4-8", + "claude-opus-4-7"}) + + +def _with_1m_window(model: str) -> str: + return f"{model}[1m]" if model in _NATIVE_1M_MODELS else model + + def _command(session_id: str, resume: bool, *, model: str | None, allowed_tools: list[str] | None, mcp_servers: dict[str, dict] | None, system_prompt: str | None, output_format: dict | None, role: str | None, effort: str | None, max_turns: int | None) -> list[str]: @@ -568,7 +578,7 @@ def _command(session_id: str, resume: bool, *, model: str | None, allowed_tools: "--setting-sources", "user"] cmd += ["--resume", session_id] if resume else ["--session-id", session_id] if model: - cmd += ["--model", model] + cmd += ["--model", _with_1m_window(model)] if system_prompt: cmd += ["--system-prompt", system_prompt] if effort: diff --git a/tst/unit/agents/claude_code/test_claude_bridge_model.py b/tst/unit/agents/claude_code/test_claude_bridge_model.py new file mode 100644 index 00000000..702f2208 --- /dev/null +++ b/tst/unit/agents/claude_code/test_claude_bridge_model.py @@ -0,0 +1,27 @@ +"""The model the CLI is given: a native-1M model passed without [1m] gets its 1M window.""" + +import pytest + +from tst.unit.agents.claude_code.agent import claude_bridge + + +def _cli_model(model: str | None) -> str | None: + cmd = claude_bridge._command("sess-1", False, model=model, allowed_tools=None, mcp_servers=None, + system_prompt=None, output_format=None, role=None, effort=None, max_turns=None) + return cmd[cmd.index("--model") + 1] if "--model" in cmd else None + + +@pytest.mark.parametrize("model", ["claude-opus-5-5", "claude-opus-5", "claude-fable-5-1", "claude-opus-4-8", + "claude-opus-4-7"]) +def test_a_native_1m_model_gets_its_1m_window(model): + assert _cli_model(model) == f"{model}[1m]" + + +@pytest.mark.parametrize("model", ["claude-opus-5-5[1m]", "claude-opus-4-8[1m]", "claude-sonnet-4-6", "gpt-5.6-sol", + "gemini/gemini-3.1-pro-preview"]) +def test_other_models_pass_through_unchanged(model): + assert _cli_model(model) == model + + +def test_no_model_sends_no_model_flag(): + assert _cli_model(None) is None