mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-07-16 12:40:18 +00:00
3682d237d7
CI Tests job (run 28525484615) failed one test per shard: - Stubs for _resolve_compatible_session_model_state lacked profile_config (wakeup wiring spy, start_session_turn runtime adapter fixture). - #1855 structural test used 6k char slice; resolver helper outgrew window. Co-authored-by: b3nw <b3nw@users.noreply.github.com>
131 lines
4.8 KiB
Python
131 lines
4.8 KiB
Python
"""start_session_turn honors runtime_adapter_enabled() via the shared
|
|
_start_run helper — Q-2979-A2 / Copilot discussion_r3305864087/r3305864173.
|
|
|
|
Before this fix start_session_turn (Option Z drain-thread wakeup entrypoint)
|
|
called _start_chat_stream_for_session directly, bypassing the runtime-adapter
|
|
selection block that /api/chat/start (_handle_chat_start) already ran. As a
|
|
result a process-wakeup turn skipped the adapter that a human-typed turn
|
|
would have hit when ``HERMES_RUNTIME_ADAPTER=legacy-journal`` was set.
|
|
|
|
The refactor factors a shared ``_start_run`` helper used by both entrypoints,
|
|
so flipping the env to ``legacy-journal`` now routes process-wakeup turns
|
|
through the same LegacyJournalRuntimeAdapter as the browser path.
|
|
|
|
These tests exercise that contract directly without spinning up a real HTTP
|
|
server (precedent: tests/test_wakeup_defer_race.py — monkeypatch the heavy
|
|
deps, call the function under test, assert on adapter selection).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import types
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
def _stub_routes(monkeypatch):
|
|
"""Patch the heavy deps inside start_session_turn so the call collapses
|
|
to one observable: did it go through the runtime adapter or not."""
|
|
from api import routes as routes_mod
|
|
|
|
# 1. Fake session lookup — returns a minimal object with the attributes
|
|
# _start_run touches via the s.* attribute names.
|
|
s = types.SimpleNamespace(
|
|
session_id="sess-test",
|
|
model="opus",
|
|
model_provider="anthropic",
|
|
profile="developer-general",
|
|
workspace="/tmp/ws-test",
|
|
)
|
|
monkeypatch.setattr(routes_mod, "get_session", lambda _sid: s)
|
|
|
|
# 2. Workspace resolution — short-circuit to the persisted workspace.
|
|
monkeypatch.setattr(
|
|
routes_mod,
|
|
"_resolve_chat_workspace_with_recovery",
|
|
lambda _s, _req: "/tmp/ws-test",
|
|
)
|
|
|
|
# 3. Model resolution — pass through.
|
|
monkeypatch.setattr(
|
|
routes_mod,
|
|
"_resolve_compatible_session_model_state",
|
|
lambda model, provider, **kwargs: (model, provider, model),
|
|
)
|
|
|
|
# 4. Block the per-session live-view fan-out (it pokes a real registry).
|
|
monkeypatch.setattr(
|
|
routes_mod,
|
|
"_start_chat_stream_for_session",
|
|
lambda *a, **kw: {"_status": 200, "stream_id": "stream-direct", "session_id": "sess-test"},
|
|
)
|
|
|
|
# 5. Silence the channel emit.
|
|
import api.background_process as bp_mod
|
|
|
|
monkeypatch.setattr(bp_mod, "get_session_channel", lambda _sid: None)
|
|
|
|
return routes_mod
|
|
|
|
|
|
def test_start_session_turn_uses_direct_path_by_default(_stub_routes, monkeypatch):
|
|
"""With HERMES_WEBUI_RUNTIME_ADAPTER unset (legacy-direct default), the helper
|
|
must NOT go through the adapter — it falls through to the direct
|
|
_start_chat_stream_for_session call, same as before."""
|
|
monkeypatch.delenv("HERMES_WEBUI_RUNTIME_ADAPTER", raising=False)
|
|
|
|
calls = {"adapter": 0}
|
|
from api import runtime_adapter as ra_mod
|
|
|
|
real_build = ra_mod.build_runtime_adapter
|
|
|
|
def _track(*a, **kw):
|
|
calls["adapter"] += 1
|
|
return real_build(*a, **kw)
|
|
|
|
monkeypatch.setattr(ra_mod, "build_runtime_adapter", _track)
|
|
|
|
resp = _stub_routes.start_session_turn("sess-test", "wakeup msg")
|
|
assert resp["_status"] == 200
|
|
assert calls["adapter"] == 0, "default mode must not build a runtime adapter"
|
|
|
|
|
|
def test_start_session_turn_routes_through_adapter_when_enabled(
|
|
_stub_routes, monkeypatch
|
|
):
|
|
"""With HERMES_WEBUI_RUNTIME_ADAPTER=legacy-journal, start_session_turn must
|
|
construct + invoke the LegacyJournalRuntimeAdapter — same path
|
|
_handle_chat_start exercises. This is the regression that Q-2979-A2 fixes:
|
|
before the _start_run refactor, this env flip had no effect on the
|
|
process-wakeup path."""
|
|
monkeypatch.setenv("HERMES_WEBUI_RUNTIME_ADAPTER", "legacy-journal")
|
|
|
|
from api import runtime_adapter as ra_mod
|
|
|
|
invoked = {"adapter": 0, "start_run": 0}
|
|
|
|
class _SpyAdapter:
|
|
def start_run(self, request):
|
|
invoked["start_run"] += 1
|
|
assert request.session_id == "sess-test"
|
|
assert request.message == "wakeup msg"
|
|
assert request.source == "process_wakeup"
|
|
assert request.metadata == {"route": "start_session_turn"}
|
|
return ra_mod.RunStartResult(
|
|
run_id="run-test",
|
|
stream_id="stream-via-adapter",
|
|
session_id=request.session_id,
|
|
payload={"_status": 200, "stream_id": "stream-via-adapter"},
|
|
)
|
|
|
|
def _fake_build(**kw):
|
|
invoked["adapter"] += 1
|
|
return _SpyAdapter()
|
|
|
|
monkeypatch.setattr(ra_mod, "build_runtime_adapter", _fake_build)
|
|
|
|
resp = _stub_routes.start_session_turn("sess-test", "wakeup msg")
|
|
assert resp["_status"] == 200
|
|
assert resp["stream_id"] == "stream-via-adapter"
|
|
assert invoked == {"adapter": 1, "start_run": 1}
|