"""System-prompt assembly for the desktop chat surface. Pins the second half of the fix: the new ``PLATFORM_HINTS["desktop"]`` entry, the deletion of the standalone desktop-hint block from ``build_environment_hints()``, and the lookup-site extension that appends the embedded-terminal-pane clarifier to the ``tui`` platform hint when ``HERMES_DESKTOP_TERMINAL=1``. These tests run against the real prompt builders (no mocks) because cache-stability and byte-for-byte text contracts are what we are verifying — mocking the resolver would hide exactly the class of bug this test covers. """ from types import SimpleNamespace from unittest.mock import patch import pytest from agent.prompt_builder import PLATFORM_HINTS, build_environment_hints from agent.system_prompt import ( _tui_embedded_pane_clarifier, build_system_prompt_parts, ) def _stable_prompt(agent): with ( patch("run_agent.load_soul_md", return_value=""), patch("run_agent.build_nous_subscription_prompt", return_value=""), patch("run_agent.build_environment_hints", return_value=""), patch("run_agent.build_context_files_prompt", return_value=""), ): return build_system_prompt_parts(agent)["stable"] def _make_agent(platform="", **overrides): base = dict( load_soul_identity=False, skip_context_files=False, valid_tool_names=[], _task_completion_guidance=False, _tool_use_enforcement=False, _environment_probe=False, _kanban_worker_guidance="", _memory_store=None, _memory_manager=None, _platform_hint_overrides={}, model="", provider="", pass_session_id=False, session_id="", ) base["platform"] = platform base.update(overrides) return SimpleNamespace(**base) class TestDesktopHintEntry: def test_desktop_key_exists(self): """The map must carry a "desktop" entry — without it the platform hint lookup falls through to an empty string and the agent gets no surface framing at all on the desktop chat surface.""" assert "desktop" in PLATFORM_HINTS def test_desktop_hint_advertises_markdown(self): """The desktop renderer supports full GFM (verified via the Streamdown pipeline in apps/desktop). The hint must steer the agent toward markdown, not away from it like the cli/tui hints do.""" hint = PLATFORM_HINTS["desktop"] assert "markdown" in hint.lower() class TestDesktopHintBlockRemoved: """The standalone desktop-hint block that used to live in ``build_environment_hints()`` (lines ~1130-1144) was a band-aid for the missing ``PLATFORM_HINTS["desktop"]`` entry. Once that entry exists, the block is dead code that competes with the platform hint's claim of what surface the agent is on. It must be gone.""" def test_build_environment_hints_has_no_runtime_surface_line(self, monkeypatch): monkeypatch.setenv("HERMES_DESKTOP", "1") monkeypatch.delenv("HERMES_DESKTOP_TERMINAL", raising=False) from agent.prompt_builder import _clear_backend_probe_cache _clear_backend_probe_cache() hints = build_environment_hints() assert "Runtime surface:" not in hints assert "desktop GUI app" not in hints def test_build_environment_hints_has_no_embedded_pane_clarifier(self, monkeypatch): """The ⌥-drag / ⌘+L embedded-pane clarifier moves to the platform-hint resolution site (system_prompt.py), not build_environment_hints().""" monkeypatch.setenv("HERMES_DESKTOP", "1") monkeypatch.setenv("HERMES_DESKTOP_TERMINAL", "1") from agent.prompt_builder import _clear_backend_probe_cache _clear_backend_probe_cache() hints = build_environment_hints() assert "embedded terminal pane" not in hints assert "Shift-drag" not in hints class TestPlatformHintResolutionInStablePrompt: """End-to-end through ``build_system_prompt_parts`` — the platform tag on the agent drives BOTH which PLATFORM_HINTS entry gets appended AND whether the embedded-pane clarifier follows it. The desktop-hint block that used to live in ``build_environment_hints()`` is gone.""" def test_desktop_platform_yields_desktop_hint_no_tui_framing(self, monkeypatch): monkeypatch.setenv("HERMES_DESKTOP", "1") monkeypatch.delenv("HERMES_DESKTOP_TERMINAL", raising=False) stable = _stable_prompt(_make_agent(platform="desktop")) assert PLATFORM_HINTS["desktop"] in stable assert "terminal UI" not in stable assert "Runtime surface:" not in stable assert "embedded terminal pane" not in stable def test_embedded_tui_yields_tui_hint_with_clarifier(self, monkeypatch): monkeypatch.setenv("HERMES_DESKTOP", "1") monkeypatch.setenv("HERMES_DESKTOP_TERMINAL", "1") stable = _stable_prompt(_make_agent(platform="tui")) assert PLATFORM_HINTS["tui"] in stable assert "embedded terminal pane" in stable assert "Shift-drag" in stable or "Option-drag" in stable or "⌥" in stable class TestEmbeddedTuiPaneClarifier: """When ``HERMES_DESKTOP_TERMINAL=1``, a standalone ``hermes --tui`` is running inside the desktop's embedded terminal pane. The user can ⌥-drag-select its output and ⌘/Ctrl+L to send it to the chat composer. That clarifier must be appended to the ``tui`` platform hint at the resolution site, NOT baked into the static ``PLATFORM_HINTS["tui"]`` string (which is shared with every standalone TUI session and must stay byte-stable).""" def test_embedded_pane_clarifier_appended_when_env_set(self, monkeypatch): monkeypatch.setenv("HERMES_DESKTOP_TERMINAL", "1") out = _tui_embedded_pane_clarifier(PLATFORM_HINTS["tui"]) assert out.startswith(PLATFORM_HINTS["tui"]) assert "embedded terminal pane" in out assert "Shift-drag" in out or "Option-drag" in out or "⌥" in out @pytest.mark.parametrize("val", ["0", "false", "no", "", "0", "False"]) def test_falsy_env_does_not_trigger_clarifier(self, monkeypatch, val): monkeypatch.setenv("HERMES_DESKTOP_TERMINAL", val) out = _tui_embedded_pane_clarifier(PLATFORM_HINTS["tui"]) assert out == PLATFORM_HINTS["tui"], ( f"HERMES_DESKTOP_TERMINAL={val!r} should not trigger clarifier" ) class TestContradictionGone: """The original contradiction: a single assembled system prompt contained both ``You are running in the Hermes terminal UI (TUI).`` and ``Runtime surface: you're running inside the Hermes desktop GUI app.``. After the fix, no single session's prompt can carry both.""" def test_desktop_chat_session_has_no_tui_framing(self, monkeypatch): monkeypatch.setenv("HERMES_DESKTOP", "1") monkeypatch.delenv("HERMES_DESKTOP_TERMINAL", raising=False) assert "tui" in PLATFORM_HINTS assert "desktop" in PLATFORM_HINTS desktop_hint = PLATFORM_HINTS["desktop"] tui_hint = PLATFORM_HINTS["tui"] assert "terminal UI" not in desktop_hint assert "terminal UI" in tui_hint def test_tui_hint_does_not_carry_desktop_marker(self): tui_hint = PLATFORM_HINTS["tui"] assert "desktop GUI app" not in tui_hint assert "Runtime surface:" not in tui_hint