Skip to content

fix(auxiliary): keep auto model resolved from runtime pair - #61

Merged
Kyzcreig merged 1 commit into
mainfrom
fix/aux-auto-runtime-model
Jun 19, 2026
Merged

Kyzcreig merged 1 commit into
mainfrom
fix/aux-auto-runtime-model

Conversation

@Kyzcreig

Copy link
Copy Markdown
Collaborator

Summary

  • Fixes provider=auto auxiliary resolution so the auto branch keeps the live runtime provider/model pair.
  • Prevents stale main/config model state like claude-opus-4-8 from being crossed onto a fallback Codex client that should use gpt-5.5.
  • Adds a regression test for the outer resolve_provider_client("auto", model=None, main_runtime=...) path.

Root cause

resolve_provider_client() filled a missing model from _read_main_model() before entering the provider == "auto" branch. During mid-session fallback, _resolve_auto(main_runtime=...) correctly selected openai-codex / gpt-5.5, but the prefilled stale model claude-opus-4-8 won over the auto-resolved model. Codex then rejected the request with:

The 'claude-opus-4-8' model is not supported when using Codex with a ChatGPT account.

Test plan

  • RED proof before the fix:
    • tests/agent/test_auxiliary_main_first.py::TestResolveProviderClientAutoRuntimeModel::test_auto_provider_does_not_let_stale_config_model_override_runtime_model
    • failed with AssertionError: assert 'claude-opus-4-8' == 'gpt-5.5'
  • GREEN after the fix:
    • python -m pytest tests/agent/test_auxiliary_main_first.py::TestResolveProviderClientAutoRuntimeModel::test_auto_provider_does_not_let_stale_config_model_override_runtime_model tests/agent/test_auxiliary_main_first.py::TestResolveProviderClientAutoRuntimeModel::test_auto_provider_preserves_explicit_model_override -q -o addopts=''
    • 2 passed
  • Neighbor suites:
    • python -m pytest tests/agent/test_auxiliary_main_first.py tests/agent/test_auxiliary_client.py tests/agent/test_context_compressor.py -q -o addopts='' -p no:randomly
    • 338 passed, 1 warning
  • Synthetic production-path E2E:
    • call_llm(task="compression", main_runtime={"provider":"openai-codex","model":"gpt-5.5"}) with the network call intercepted after kwargs build.
    • Captured downstream model: gpt-5.5; BUG_PRESENT: False.

Local fleet status

  • Cherry-picked to the live editable checkout on disk as bf30244ae.
  • Aegis gateway restarted and verified on the fixed checkout.
  • Apollo gateway was not restarted; it will load the fix on Ace's chosen restart.

When provider=auto and the caller omits an explicit model, resolve_provider_client filled model from _read_main_model() before invoking _resolve_auto(). During a mid-session failover this can cross stale config/default model state (claude-opus-4-8) onto the live fallback provider client (openai-codex), producing the observed Codex 400.\n\nSkip the generic model fallback for provider=auto so _resolve_auto(main_runtime=...) supplies the matched provider/model pair. Explicit caller model overrides still win.\n\nRegression: tests/agent/test_auxiliary_main_first.py::TestResolveProviderClientAutoRuntimeModel::test_auto_provider_does_not_let_stale_config_model_override_runtime_model is RED before this fix (returns stale claude-opus-4-8) and GREEN after (returns gpt-5.5).
@github-actions

Copy link
Copy Markdown

🔎 Lint report: fix/aux-auto-runtime-model vs origin/main

ruff

Total: 4 on HEAD, 4 on base (➖ 0)

🆕 New issues (2):

Rule Count
PLW1514 2
First entries
scripts/lcm_qa_battery.py:144: [PLW1514] `pathlib.Path(...).write_text` without explicit `encoding` argument
scripts/lcm_arm_b_node_recovery.py:801: [PLW1514] `pathlib.Path(...).write_text` without explicit `encoding` argument

✅ Fixed issues (2):

Rule Count
PLW1514 2
First entries
../../../../../tmp/lint-base/scripts/lcm_qa_battery.py:144: [PLW1514] `pathlib.Path(...).write_text` without explicit `encoding` argument
../../../../../tmp/lint-base/scripts/lcm_arm_b_node_recovery.py:801: [PLW1514] `pathlib.Path(...).write_text` without explicit `encoding` argument

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 11193 on HEAD, 11192 on base (🆕 +1)

🆕 New issues (1):

Rule Count
invalid-argument-type 1
First entries
tests/agent/test_auxiliary_main_first.py:571: [invalid-argument-type] invalid-argument-type: Argument to function `resolve_provider_client` is incorrect: Expected `str`, found `None`

✅ Fixed issues: none

Unchanged: 5838 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a provider/model mismatch during mid-session fallback: resolve_provider_client() was unconditionally filling an empty model from _read_main_model() before entering the provider == "auto" branch, so a stale config model (e.g. claude-opus-4-8) could overwrite the correct runtime model (gpt-5.5) chosen by _resolve_auto.

  • Core fix (agent/auxiliary_client.py): Guards the model-fill block with provider != \"auto\", letting the auto branch delegate model selection entirely to _resolve_auto(main_runtime=...).
  • New tests (tests/agent/test_auxiliary_main_first.py): Adds TestResolveProviderClientAutoRuntimeModel with two cases — one proving the regression is gone (stale config model no longer wins), and one verifying explicit caller-supplied models still take precedence over the auto-resolved model.

Confidence Score: 4/5

Safe to merge; the production fix is a minimal, well-targeted guard that only affects the auto provider path and is backed by a clear regression test.

The core change is a single conditional guard (provider != "auto") that is straightforward and consistent with how _resolve_auto already owns model selection for the auto branch. The regression test directly proves the broken behavior was fixed. The only noteworthy gap is that the second new test would have passed even without the fix, and it doesn't assert main_runtime forwarding — a minor improvement opportunity, not a defect.

No files require special attention beyond the minor assertion gap noted in the second new test.

Important Files Changed

Filename Overview
agent/auxiliary_client.py One-line guard change is minimal, correct, and consistent with how the auto branch already delegates fully to _resolve_auto; no other branches affected.
tests/agent/test_auxiliary_main_first.py Regression test correctly covers the fixed path; second test (explicit model override) actually passed before the fix too and does not assert that main_runtime is forwarded to _resolve_auto.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Caller
    participant resolve_provider_client
    participant _resolve_auto
    participant _read_main_model

    note over resolve_provider_client: provider="auto", model=None

    alt BEFORE fix (buggy)
        resolve_provider_client->>_read_main_model: _read_main_model()
        _read_main_model-->>resolve_provider_client: "claude-opus-4-8"
        note over resolve_provider_client: model = "claude-opus-4-8" (stale!)
        resolve_provider_client->>_resolve_auto: "_resolve_auto(main_runtime={...codex/gpt-5.5})"
        _resolve_auto-->>resolve_provider_client: (codex_client, "gpt-5.5")
        note over resolve_provider_client: final_model = "claude-opus-4-8" or "gpt-5.5" → "claude-opus-4-8"
        resolve_provider_client-->>Caller: (codex_client, "claude-opus-4-8") ❌ MISMATCH
    end

    alt AFTER fix (correct)
        note over resolve_provider_client: provider=="auto" → skip _read_main_model()
        resolve_provider_client->>_resolve_auto: "_resolve_auto(main_runtime={...codex/gpt-5.5})"
        _resolve_auto-->>resolve_provider_client: (codex_client, "gpt-5.5")
        note over resolve_provider_client: final_model = None or "gpt-5.5" → "gpt-5.5"
        resolve_provider_client-->>Caller: (codex_client, "gpt-5.5") ✅
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Caller
    participant resolve_provider_client
    participant _resolve_auto
    participant _read_main_model

    note over resolve_provider_client: provider="auto", model=None

    alt BEFORE fix (buggy)
        resolve_provider_client->>_read_main_model: _read_main_model()
        _read_main_model-->>resolve_provider_client: "claude-opus-4-8"
        note over resolve_provider_client: model = "claude-opus-4-8" (stale!)
        resolve_provider_client->>_resolve_auto: "_resolve_auto(main_runtime={...codex/gpt-5.5})"
        _resolve_auto-->>resolve_provider_client: (codex_client, "gpt-5.5")
        note over resolve_provider_client: final_model = "claude-opus-4-8" or "gpt-5.5" → "claude-opus-4-8"
        resolve_provider_client-->>Caller: (codex_client, "claude-opus-4-8") ❌ MISMATCH
    end

    alt AFTER fix (correct)
        note over resolve_provider_client: provider=="auto" → skip _read_main_model()
        resolve_provider_client->>_resolve_auto: "_resolve_auto(main_runtime={...codex/gpt-5.5})"
        _resolve_auto-->>resolve_provider_client: (codex_client, "gpt-5.5")
        note over resolve_provider_client: final_model = None or "gpt-5.5" → "gpt-5.5"
        resolve_provider_client-->>Caller: (codex_client, "gpt-5.5") ✅
    end
Loading

Reviews (1): Last reviewed commit: "fix(auxiliary): keep auto model resolved..." | Re-trigger Greptile

Comment on lines +583 to +600
def test_auto_provider_preserves_explicit_model_override(self):
"""A real caller-supplied model still wins over the auto-resolved model."""
codex_client = MagicMock()

with patch(
"agent.auxiliary_client._resolve_auto", return_value=(codex_client, "gpt-5.5"),
):
from agent.auxiliary_client import resolve_provider_client

client, model = resolve_provider_client(
"auto",
"gpt-5.4-mini",
False,
main_runtime={"provider": "openai-codex", "model": "gpt-5.5"},
)

assert client is codex_client
assert model == "gpt-5.4-mini"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Second test does not assert main_runtime forwarding to _resolve_auto

test_auto_provider_preserves_explicit_model_override verifies that a caller-supplied model wins over the auto-resolved one, which is correct. However, it doesn't assert that _resolve_auto was actually called with the right main_runtime. If a future refactor accidentally dropped main_runtime from the inner call, this test would still pass. The first test (test_auto_provider_does_not_let_stale_config_model_override_runtime_model) includes mock_resolve_auto.assert_called_once_with(main_runtime=...) — adding the same assertion here would close the gap.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@Kyzcreig
Kyzcreig merged commit 5ec895c into main Jun 19, 2026
36 of 37 checks passed
@Kyzcreig
Kyzcreig deleted the fix/aux-auto-runtime-model branch June 19, 2026 06:14
Kyzcreig added a commit that referenced this pull request Jun 19, 2026
Unblocks the fork-wide ruff enforcement gate (PLW1514) by adding explicit UTF-8 encodings to LCM report write_text calls.\n\nThis was already failing on clean fork/main and was inherited by PR #61; keep it as a separate hygiene fix rather than mixing it into the auxiliary resolver bugfix.

Co-authored-by: Apollo <apollo@daemonarchy.local>
@Kyzcreig
Kyzcreig restored the fix/aux-auto-runtime-model branch September 21, 2026 10:32
Kyzcreig pushed a commit that referenced this pull request Sep 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant