feat(desktop): let the agent drive the shell — preview pane + pane focus - #69519
Merged
Conversation
Add a desktop-gated open_preview tool so 'open cnn.com in the preview pane' works. The tool (check_fn on HERMES_DESKTOP, zero footprint elsewhere) emits a preview.open event through a gateway-injected emitter, mirroring the close_terminal -> terminal.close bridge. The desktop handles it in usePreviewRouting, normalizing the target and opening the pane for the active session only -- a background turn never hijacks it. Bare domains and localhost are coaxed into fetchable URLs (www.cnn.com -> https://, localhost:3000 -> http://); file paths and schemes pass through to the renderer's normalizer.
Contributor
૮ >ﻌ< ა ci reviewrunning on 70ba3c4 CI timingsCI timings · View jobWall time 7m38s vs 8m29s (-10.0%). 3 job(s) slower, 15 faster, 2 unchanged.
|
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.
OutThisLife
enabled auto-merge
July 22, 2026 17:18
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…eview-open feat(desktop): let the agent drive the shell — preview pane + pane focus
33hodl
pushed a commit
to 33hodl/hermes-agent
that referenced
this pull request
Aug 12, 2026
…eview-open feat(desktop): let the agent drive the shell — preview pane + pane focus
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
On Hermes Desktop the agent could generate UI (TUI widgets, desktop plugins, HTML → preview webview) but couldn't drive the shell around it. The Preview pane only opened when the user clicked; the agent had no way to reveal panes on request. So "open cnn.com in the preview pane" or "show me the terminal" did nothing.
What
Two desktop-gated tools on a shared event bridge — same idiom as
read_terminal/close_terminal.tools/desktop_ui.py— one gateway-injected emitter both tools share. Routes byHERMES_UI_SESSION_IDso events land on the window that owns the turn.Noneoff-desktop → tools report "desktop only".open_preview(url[, label])→preview.open. Opens a URL / localhost / file in the preview pane. Bare domains + loopback are coaxed into fetchable URLs (www.cnn.com→https://…,localhost:3000→http://…); paths/schemes pass through to the renderer's normalizer. Handled inusePreviewRouting.focus_pane(chat|files|terminal|review|sessions)→pane.reveal. The desktop runs each pane's own reveal path (revealDesktopPanetable) — some are toggle-bound, so a revealed pane matches a user-driven open. Handled ingateway-event.ts.Both are
check_fnonHERMES_DESKTOP(zero model-tool footprint on CLI/messaging), listed in_HERMES_CORE_TOOLSbeside the other GUI affordances.Offer, don't hijack
Both open only for the active session — a background turn never moves the user's focus or pops a pane (desktop AGENTS.md). Legit here because it's an explicit user request the agent is fulfilling, not a background side effect.
Footprint / deliberate omissions
Highest rung on the ladder: service-gated tools, not always-on core tools, and one shared bridge rather than a per-tool sink.
Not adding
run_slash(agent firing slash commands):/model,/new,/clearmid-turn fight prompt-cache + conversation invariants.open_fileis subsumed byopen_preview(it takes a path).Tests
test_desktop_ui.py(routing/availability),test_open_preview_tool.py,test_focus_pane_tool.py— gating, validation, normalization, emit payloads, failure reporting.pane-focus.test.ts(each pane → its reveal path; unknown → no-op),use-preview-routing.test.tsx(active opens; background ignored).Python + vitest green; desktop
typecheck+ eslint clean; core-tool-list regression suites unchanged.