From 5c7ff9c70e2c29f6f48264c422aedc5de5036f1a Mon Sep 17 00:00:00 2001 From: Rod Boev Date: Wed, 1 Jul 2026 15:42:57 -0400 Subject: [PATCH] fix(#4251): preserve raced picker ownership through profile repair --- api/streaming.py | 4 ++- ...test_issue4251_wakeup_model_picker_race.py | 35 ++++++++++++++++--- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/api/streaming.py b/api/streaming.py index 7c0c9f2e..8a3d756a 100644 --- a/api/streaming.py +++ b/api/streaming.py @@ -6695,6 +6695,7 @@ def _run_agent_streaming( update_active_run(stream_id, phase="running", session_id=session_id) s.workspace = str(Path(workspace).expanduser().resolve()) _last_persisted_model = getattr(s, "model", None) + _turn_owns_persisted_model = False provider_context = ( str(model_provider).strip().lower() if model_provider is not None @@ -6707,6 +6708,7 @@ def _run_agent_streaming( s.model = model s.model_provider = provider_context or None _last_persisted_model = model + _turn_owns_persisted_model = True _agent_lock = _get_session_agent_lock(session_id) # TD1: set thread-local env context so concurrent sessions don't clobber globals @@ -6750,7 +6752,7 @@ def _run_agent_streaming( ) # #4251: only apply the profile-repair persistence if this turn still # owns the session model value it last wrote. - if getattr(s, "model", None) == _last_persisted_model: + if _turn_owns_persisted_model and getattr(s, "model", None) == _last_persisted_model: s.model_provider = provider_context if _repaired and model != (s.model or ""): s.model = model diff --git a/tests/test_issue4251_wakeup_model_picker_race.py b/tests/test_issue4251_wakeup_model_picker_race.py index 2f2ba5e7..dfb1385f 100644 --- a/tests/test_issue4251_wakeup_model_picker_race.py +++ b/tests/test_issue4251_wakeup_model_picker_race.py @@ -134,7 +134,14 @@ def _install_streaming_harness(monkeypatch, fake_session): monkeypatch.setitem(sys.modules, "hermes_state", fake_hermes_state) -def _run_streaming_turn(monkeypatch, fake_session, *, stream_id): +def _run_streaming_turn( + monkeypatch, + fake_session, + *, + stream_id, + dispatch_model="haiku-4-5", + dispatch_provider="anthropic", +): _install_streaming_harness(monkeypatch, fake_session) fake_session.active_stream_id = stream_id fake_queue = queue.Queue() @@ -143,8 +150,8 @@ def _run_streaming_turn(monkeypatch, fake_session, *, stream_id): streaming._run_agent_streaming( session_id=fake_session.session_id, msg_text="background wakeup turn", - model="haiku-4-5", - model_provider="anthropic", + model=dispatch_model, + model_provider=dispatch_provider, workspace="/tmp", stream_id=stream_id, ) @@ -154,7 +161,7 @@ def _run_streaming_turn(monkeypatch, fake_session, *, stream_id): def test_dispatch_stamp_does_not_clobber_newer_picker_model(monkeypatch): - fake_session = FakeSession(model="opus-4-8", model_provider="anthropic") + fake_session = FakeSession(model="opus-4-8", model_provider="openrouter") _run_streaming_turn( monkeypatch, @@ -163,6 +170,7 @@ def test_dispatch_stamp_does_not_clobber_newer_picker_model(monkeypatch): ) assert fake_session.model == "opus-4-8" + assert fake_session.model_provider == "openrouter" def test_dispatch_stamp_persists_resolved_model_when_no_race(monkeypatch): @@ -189,3 +197,22 @@ def test_dispatch_stamp_persists_when_session_model_was_empty(monkeypatch): assert fake_session.model == "haiku-4-5" assert fake_session.model_provider == "anthropic" + + +def test_profile_repair_skips_persistence_when_newer_picker_choice_already_won(monkeypatch): + fake_session = FakeSession(model="opus-4-8", model_provider="openrouter") + fake_session.profile = "worker-profile" + monkeypatch.setattr( + streaming, + "_apply_profile_home_context_to_streaming_model", + lambda **_kwargs: ("claude-profile-default", "anthropic", True), + ) + + _run_streaming_turn( + monkeypatch, + fake_session, + stream_id="stream-4251-profile-race", + ) + + assert fake_session.model == "opus-4-8" + assert fake_session.model_provider == "openrouter"