fix(desktop): keep model runtime state per session (#43702)

* fix(desktop): keep model runtime state per session

(cherry picked from commit f72ee87d99ee38cb7b5badeb9a8af869bb92073a)

* fix(desktop): keep footer model state scoped to active session

(cherry picked from commit d91942ebd4671ff857b5c8526dbf133f04782ecb)

* fix(desktop): restore stored runtime when resuming sessions

(cherry picked from commit 32b3793418257617b8da57e26151f079c2620d00)

* fix(desktop): persist live runtime changes for resume

(cherry picked from commit c58467779436dcef44a80ad55b52664752dc0837)

* fix(desktop): persist resumed endpoint runtime

* chore(attribution): map pinguarmy's commit email in AUTHOR_MAP

The salvaged commits on this branch preserve @pinguarmy's authorship
(郝鹏宇 / peterhao@Peters-MacBook-Air.local). Add the mapping so the
check-attribution CI gate resolves the email to the GitHub username.

---------

Co-authored-by: 郝鹏宇 <peterhao@Peters-MacBook-Air.local>
This commit is contained in:
brooklyn! 2026-06-10 13:16:50 -05:00 committed by GitHub
parent 07ac185904
commit 6de3963e37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 474 additions and 32 deletions

View file

@ -878,6 +878,97 @@ def test_session_resume_uses_parent_lineage_for_display(monkeypatch):
assert captured["history_calls"] == [("tip", False), ("tip", True)]
def test_session_resume_passes_stored_runtime_to_agent(monkeypatch):
captured = {}
class FakeDB:
def get_session(self, target):
return {
"id": target,
"model": "gpt-5.4",
"billing_provider": "openai-codex",
"model_config": '{"reasoning_config":{"enabled":true,"effort":"high"},"service_tier":"priority","base_url":"https://custom.example/v1","api_mode":"chat_completions"}',
}
def reopen_session(self, target):
pass
def get_messages_as_conversation(self, target, include_ancestors=False):
return [{"role": "user", "content": "hello"}]
def fake_make_agent(sid, key, session_id=None, session_db=None, **kwargs):
captured.update(kwargs)
return types.SimpleNamespace(model="gpt-5.4", provider="openai-codex")
monkeypatch.setattr(server, "_get_db", lambda: FakeDB())
monkeypatch.setattr(server, "_enable_gateway_prompts", lambda: None)
monkeypatch.setattr(server, "_set_session_context", lambda target: [])
monkeypatch.setattr(server, "_clear_session_context", lambda tokens: None)
monkeypatch.setattr(server, "_make_agent", fake_make_agent)
monkeypatch.setattr(server, "_session_info", lambda agent, *a: {"model": agent.model, "provider": agent.provider})
def fake_init_session(sid, key, agent, history, cols=80):
server._sessions[sid] = {"agent": agent, "session_key": key}
monkeypatch.setattr(server, "_init_session", fake_init_session)
resp = server.handle_request(
{"id": "1", "method": "session.resume", "params": {"session_id": "stored-session"}}
)
assert resp["result"]["info"] == {"model": "gpt-5.4", "provider": "openai-codex"}
assert captured["model_override"] == {
"model": "gpt-5.4",
"provider": "openai-codex",
"base_url": "https://custom.example/v1",
"api_mode": "chat_completions",
}
assert captured["provider_override"] == "openai-codex"
assert captured["reasoning_config_override"] == {"enabled": True, "effort": "high"}
assert captured["service_tier_override"] == "priority"
runtime_sid = resp["result"]["session_id"]
assert server._sessions[runtime_sid]["model_override"] == captured["model_override"]
def test_persist_live_session_runtime_preserves_resume_metadata(monkeypatch):
updates = {}
class FakeDB:
def get_session(self, session_id):
assert session_id == "stored-session"
return {"model_config": '{"_branched_from":"root"}'}
def update_session_meta(self, session_id, model_config_json, model=None):
updates["meta"] = (session_id, json.loads(model_config_json), model)
agent = types.SimpleNamespace(
model="gpt-5.4",
provider="openai-codex",
base_url="https://custom.example/v1",
api_mode="chat_completions",
reasoning_config={"enabled": True, "effort": "high"},
service_tier="priority",
_session_db=FakeDB(),
)
server._persist_live_session_runtime({"agent": agent, "session_key": "stored-session"})
assert "model" not in updates
assert updates["meta"] == (
"stored-session",
{
"_branched_from": "root",
"model": "gpt-5.4",
"provider": "openai-codex",
"base_url": "https://custom.example/v1",
"api_mode": "chat_completions",
"reasoning_config": {"enabled": True, "effort": "high"},
"service_tier": "priority",
},
"gpt-5.4",
)
def test_status_callback_emits_kind_and_text():
with patch("tui_gateway.server._emit") as emit:
cb = server._agent_cbs("sid")["status_callback"]
@ -3593,8 +3684,9 @@ def test_session_info_includes_mcp_servers(monkeypatch):
fake_mod.get_mcp_status = lambda: fake_status
monkeypatch.setitem(sys.modules, "tools.mcp_tool", fake_mod)
info = server._session_info(types.SimpleNamespace(tools=[], model=""))
info = server._session_info(types.SimpleNamespace(tools=[], model="", provider="openai-codex"))
assert info["provider"] == "openai-codex"
assert info["mcp_servers"] == fake_status
@ -5983,6 +6075,45 @@ def test_make_agent_defaults_to_90(monkeypatch):
assert mock_agent.call_args.kwargs["max_iterations"] == 90
def test_make_agent_uses_session_runtime_overrides(monkeypatch):
_setup_make_agent_mocks(monkeypatch, {})
resolved = {}
def fake_resolve_runtime_provider(requested=None, target_model=None):
resolved["requested"] = requested
resolved["target_model"] = target_model
return {
"provider": requested,
"base_url": None,
"api_key": None,
"api_mode": None,
"command": None,
"args": None,
"credential_pool": None,
}
monkeypatch.setattr(
"hermes_cli.runtime_provider.resolve_runtime_provider",
fake_resolve_runtime_provider,
)
with patch("run_agent.AIAgent") as mock_agent:
server._make_agent(
"sid1",
"key1",
model_override="gpt-5.4",
provider_override="openai-codex",
reasoning_config_override={"enabled": True, "effort": "high"},
service_tier_override="priority",
)
assert resolved == {"requested": "openai-codex", "target_model": "gpt-5.4"}
assert mock_agent.call_args.kwargs["model"] == "gpt-5.4"
assert mock_agent.call_args.kwargs["provider"] == "openai-codex"
assert mock_agent.call_args.kwargs["reasoning_config"] == {"enabled": True, "effort": "high"}
assert mock_agent.call_args.kwargs["service_tier"] == "priority"
def test_make_agent_handles_null_agent_config(monkeypatch):
_setup_make_agent_mocks(monkeypatch, {"agent": None, "max_turns": 80})