mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-24 16:54:43 +00:00
Extract the open_preview emitter into a shared tools/desktop_ui bridge (one gateway-injected sink, routed by HERMES_UI_SESSION_ID) and add a second desktop-gated tool on top of it: - focus_pane(chat|files|terminal|review|sessions) -> pane.reveal event. The desktop runs each pane's own reveal path (revealDesktopPane table) and only acts on the active window -- a background turn never moves the user's focus (desktop AGENTS.md: offer, don't hijack). open_preview now emits through the same bridge. Both tools are check_fn on HERMES_DESKTOP (zero footprint elsewhere), sitting beside read_terminal/close_terminal in _HERMES_CORE_TOOLS. Deliberately not adding run_slash: letting the agent fire slash commands mid-turn (/model, /new, /clear) fights prompt-cache + conversation invariants.
40 lines
1.4 KiB
Python
40 lines
1.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Bridge desktop-only tools to Hermes-desktop renderer events.
|
|
|
|
The preview pane, pane focus, and friends live in the desktop renderer, so
|
|
desktop-gated tools reach them through an emitter the desktop ``tui_gateway``
|
|
installs at session start via :func:`set_emitter`. Everywhere else it stays
|
|
``None`` and the tools report "desktop only". Routing keys off
|
|
``HERMES_UI_SESSION_ID`` so the event lands on the window that owns the turn
|
|
(``_emit``/``write_json`` is ``_stdout_lock``-guarded, so emitting from the
|
|
tool's thread is safe).
|
|
"""
|
|
|
|
from typing import Callable, Optional
|
|
|
|
from gateway.session_context import get_session_env
|
|
|
|
# (sid, event, payload) sink, installed by the desktop gateway.
|
|
_emit: Optional[Callable[[str, str, dict], None]] = None
|
|
|
|
|
|
def set_emitter(fn: Optional[Callable[[str, str, dict], None]]) -> None:
|
|
"""Install (or clear) the renderer-event sink. Called by the desktop gateway."""
|
|
global _emit
|
|
_emit = fn
|
|
|
|
|
|
def available() -> bool:
|
|
"""True when running under the desktop app (an emitter is wired)."""
|
|
return _emit is not None
|
|
|
|
|
|
def emit(event: str, payload: dict) -> bool:
|
|
"""Route ``event`` to the window that owns the current turn.
|
|
|
|
Returns ``False`` when no emitter is wired (i.e. not the desktop app)."""
|
|
fn = _emit
|
|
if fn is None:
|
|
return False
|
|
fn(get_session_env("HERMES_UI_SESSION_ID", ""), event, payload)
|
|
return True
|