docs(runtime): define runner client backend gate#2972
Conversation
a679d5c to
1b05d60
Compare
SummaryDocs-only RFC advance for the #1925 RuntimeAdapter ladder. Marks Slice 4e as shipped via #2794 (v0.51.129), adds a new Slice 4f gate that constrains what a future supervised local runner client backend may and may not do, and pins both the status update and the new gate text via static regression assertions in Code referenceSlice 4e status banner sits where the slice header already lives ( The new gate (Slice 4f, lines 957-1015 in the PR HEAD) restates the five acceptance tests and six scope items. The most consequential one is the no-globals guardrail: And the pin test at Diagnosis / RecommendationThe doc evolution is consistent with the chain of #2416 → #2424 → #2599 → #2744 → #2794 already recorded at One observation, not a blocker: this lands while #2959 (the contract-routing review-gate issue) is still open. #2959 is asking for PRs that change contract semantics to declare a The static regression test approach (substring assertions over the RFC body) is the same approach already used for 4c/4d/4e, so consistency wins out over fragility concerns. If a reviewer later wants to reword the scope bullets, they'll have to update the test in the same PR, which is the intended forcing function. Two minor doc nits worth a pass:
Test plan
|
a6c65de
# Conflicts: # CHANGELOG.md
…➔ 0.51.145) (#668) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/nesquena/hermes-webui](https://github.com/nesquena/hermes-webui) | patch | `0.51.134` → `0.51.145` | --- >⚠️ **Warning** > > Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/567) for more information. --- ### Release Notes <details> <summary>nesquena/hermes-webui (ghcr.io/nesquena/hermes-webui)</summary> ### [`v0.51.145`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051145--2026-05-26--Release-DQ-stage-batch27--sidebar-running-state-preservation) [Compare Source](nesquena/hermes-webui@v0.51.144...v0.51.145) ##### Fixed - Sidebar session rows now preserve the server-reported running state when merging stale optimistic first-turn cache entries, so active background sessions keep their spinner and can later transition to unread correctly. ([#​2999](nesquena/hermes-webui#2999), [#​3001](nesquena/hermes-webui#3001)) ### [`v0.51.144`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051144--2026-05-26--Release-DP-stage-batch26--single-PR-terminal-supervisor-hardening) [Compare Source](nesquena/hermes-webui@v0.51.143...v0.51.144) ##### Fixed - Embedded workspace terminals now use a dedicated supervisor thread for shell spawning to eliminate timeout-vs-spawn race conditions. If a `start_terminal()` call times out (5s) but the supervisor's `subprocess.Popen` completes later, the late-arriving process is now reaped via `_reap_abandoned_spawn()` (SIGHUP → wait → SIGKILL escalation) instead of being orphaned. Adds 8 Linux-only concurrency regression tests covering concurrent spawns, Popen-failure recovery, repeated-failure-survival, and the timeout-race late-commit path. ([#​2880](nesquena/hermes-webui#2880)) ### [`v0.51.143`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051143--2026-05-26--Release-DO-stage-batch25--single-PR-workspace-markdown-scheme) [Compare Source](nesquena/hermes-webui@v0.51.142...v0.51.143) ##### Added - Chat markdown links using `workspace://path/to/file` now open the target in the workspace preview pane instead of navigating away from the WebUI. Renderable via both the settled `renderMd()` and live `streaming-markdown` paths. Workspace path existence is verified via `/api/list` before opening; missing files surface a `file_open_failed` status toast. ([#​2881](nesquena/hermes-webui#2881), [#​2938](nesquena/hermes-webui#2938)) ### [`v0.51.142`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051142--2026-05-26--Release-DN-stage-batch24--4-PR-fresh-today-batch) [Compare Source](nesquena/hermes-webui@v0.51.141...v0.51.142) ##### Added - New `GET /api/crons/delivery-options` endpoint surfaces the agent's full delivery-platform registry. The cron-create UI now reads delivery options dynamically (including telegram, discord, slack, feishu, wecom, signal, etc.) instead of a 4-option hardcoded select, and the deliver field is editable for existing jobs. ([#​2996](nesquena/hermes-webui#2996)) ##### Fixed - Browser chat fallback now merges `fallback_providers` with the legacy `fallback_model` in Hermes CLI/gateway order, so WebUI can continue to a later non-Codex fallback when the primary Codex provider path fails. Duplicate provider/model/base\_url routes are de-duplicated. ([#​2993](nesquena/hermes-webui#2993)) - WebUI streaming sessions created under a non-default profile now attach `session_search` to that profile's `state.db` instead of the server's default profile database. ([#​2965](nesquena/hermes-webui#2965), [#​2995](nesquena/hermes-webui#2995)) - `client_secret` deny-list entry in the models-cache auth.json fingerprint now carries an inline rationale comment, and the `_write_auth` test helper docstring matches its actual contract. Follow-up to [#​2964](nesquena/hermes-webui#2964) review nits. ([#​2994](nesquena/hermes-webui#2994)) ### [`v0.51.141`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051141--2026-05-26--Release-DM-stage-batch23--4-PR-second-hold-bucket-pass) [Compare Source](nesquena/hermes-webui@v0.51.140...v0.51.141) ##### Added - WebUI can now opt into a `webui_prefill_messages_script` / `HERMES_WEBUI_PREFILL_MESSAGES_SCRIPT` hook for dynamic browser-turn prefill context from local notes or recall systems. The script output is capped at 256 KiB, normalized to ephemeral prefill messages, and browser status still hides message bodies while redacting script errors. - Added a read-only WebUI/CLI session source switch in the chat sidebar when agent session sync is enabled. WebUI conversations stay in the default list, while imported CLI/agent sessions are surfaced under a separate `CLI sessions` tab with counts so large CLI histories do not clutter the normal conversation list. (Refs [#​2351](nesquena/hermes-webui#2351)) ##### Fixed - Compact tool activity now keeps visible interim assistant progress in the live Session timeline instead of making that progress effectively collapsed-only inside Activity details. The interim assistant stream path creates and flushes a visible assistant segment before resetting for later tool/compression activity. ### [`v0.51.140`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051140--2026-05-26--Release-DL-stage-batch22--5-PR-hold-bucket-reassessment) [Compare Source](nesquena/hermes-webui@v0.51.139...v0.51.140) ##### Fixed - Live streamed assistant Markdown now treats underscores in ordinary text and identifiers literally, matching the settled message renderer while preserving asterisk-based emphasis. - Models cache no longer churns every \~14 minutes when the auth.json credential pool refreshes. The auth.json fingerprint now hashes provider-identity fields (active\_provider, credential\_pool ids, base\_url, auth\_type) and excludes pure credential-rotation fields (access\_token, refresh\_token, expires\_at, last\_status, request\_count, updated\_at). Real provider/model-set changes still invalidate the cache. (RCA t\_16551f61) - Paginated `/api/session?msg_limit=N` windows now anchor on the newest renderable transcript row instead of the raw message-array tail. Long sessions whose newest rows are only hidden tool-result entries no longer open to an empty visible transcript with non-empty `S.messages`. - `_loadOlderMessages()` now requests a larger cumulative tail window (`msg_limit=current+30`) rather than a separate `msg_before` page. Suffix-continuity check guards against races and falls back to the legacy index-page request when the loaded transcript is no longer the suffix of the new server response. ##### Performance - `renderMessages()` now caches `renderMd()` / `_renderUserFencedBlocks()` output keyed on message text, caches the visible-message scan across renders, scopes the question→assistant lookup to the visible window, and Prism-highlights only newly-mounted code blocks. Long sessions with many messages no longer freeze the browser tab on every render. ### [`v0.51.139`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051139--2026-05-25--Release-DK-stage-batch21--5-PR-tier-2-batch) [Compare Source](nesquena/hermes-webui@v0.51.138...v0.51.139) ##### Added - Image lightbox now supports prev/next navigation when multiple images are present in the same message. Click `‹` / `›` buttons or use `←` / `→` keyboard arrows to browse; an image counter (`1 / 5`) is shown at the bottom. ([#​2967](nesquena/hermes-webui#2967)) ##### Fixed - Session switching now keeps the initial metadata fetch on `/api/session?messages=0&resolve_model=0` and defers stale model/provider repair until after the new session is assigned, so first paint does not block on cold model catalog hydration. - Metadata-only session loads now use a cheap state summary instead of full transcript reconciliation, while still detecting real external state.db growth and ignoring restamped replay rows that would otherwise retrigger refresh polling. - Session transcript reconciliation now precomputes visible-duplicate lookup state instead of recomputing loose-content normalization for every state.db row, reducing long-session tail-load latency without changing the append-only merge contract. - Vendored KaTeX CSS, JavaScript, and fonts locally so math rendering no longer triggers CSP font reports for `cdn.jsdelivr.net` font files. - Vendored `js-yaml` locally so YAML tree-view loading no longer triggers CSP script reports for `cdnjs.cloudflare.com`. - Session delete now prunes the deleted row from `_index.json` in place instead of discarding the whole index, and composer draft saves skip the sidebar index entirely. Both reduce churn on new-session sends after a delete or while typing. ##### Changed - Sidebar chat search now highlights matching title text and shows a subtle content preview for body-only matches. ### [`v0.51.138`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051138--2026-05-25--Release-DJ-stage-batch20--7-PR-ultra-safe-batch) [Compare Source](nesquena/hermes-webui@v0.51.137...v0.51.138) ##### Added - **PR [#​2972](nesquena/hermes-webui#2972 by [@​Michaelyklam](https://github.com/Michaelyklam) (refs [#​1925](nesquena/hermes-webui#1925)) — Advance the runtime-adapter RFC after the Slice 4e route-selection harness shipped in v0.51.129. The RFC now defines the Slice 4f supervised local runner client backend gate: replace the bounded `runner-local` 501 only when explicitly configured, prove restart/reattach from durable runner/journal state, preserve the public chat-start field whitelist, require cancel as the first live runner-owned control, and keep active-run discovery/supervision out of new WebUI process-local runtime-surrogate globals. ##### Changed - Contributor guidance now requires explicit `Contract Routing` for contract-affecting PRs and `Contract Change` when a PR intentionally changes an existing product, runtime, or review contract. Contract tests must move with the corresponding docs instead of silently redefining behavior by themselves, with the current static coverage documented as advisory rather than a GitHub policy gate. - Removing a provider key now surfaces the server's specific CSRF rejection reason ("Session expired - reload the page", "Cross-origin mismatch - check reverse proxy headers", or the fallback "Cross-origin request rejected") when the underlying POST is rejected with 403, instead of swallowing all three into one generic toast. (Refs [#​2572](nesquena/hermes-webui#2572)) - Tool cards in the transcript now use a slightly stronger border and a 2px left edge so tool output stays visually distinct from final assistant prose without requiring hover. ([#​2867](nesquena/hermes-webui#2867)) - Tasks panel "Gateway not configured" banner now includes a direct link to the new `docs/docker.md#scheduled-jobs-and-the-gateway-daemon` section that walks through running the gateway container so scheduled cron jobs actually tick. (Refs [#​2785](nesquena/hermes-webui#2785)) - WebUI structured request logs now include `remote` (client IP) and an optional `forwarded_for` field when an `X-Forwarded-For` header is present, making failed-login and unauthorized-access logs usable by downstream security tooling like fail2ban behind a reverse proxy. ##### Internal - Test cleanup in `tests/test_issue1894_provider_overlap.py`: canonicalize the `opencode-go` base URL to `opencode.ai/zen/go/v1` (matching `hermes_cli/auth.py` and `api/config.py`), drop a vestigial `# noqa: N801`, and convert section banner comments to per-test docstrings. ### [`v0.51.137`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051137--2026-05-25--Release-DI-stage-batch19--6-PR-medium-risk-batch) [Compare Source](nesquena/hermes-webui@v0.51.136...v0.51.137) ##### Added - Operators can now set `HERMES_WEBUI_CSP_CONNECT_EXTRA` to append validated extra origins to the report-only CSP `connect-src` directive for reverse-proxy or tunnel deployments. ##### Fixed - Trim session-level tool call payloads to the returned message window for paginated `/api/session` loads, so long tool-heavy sessions do not send historical tool call summaries during ordinary session switching. - Sidebar compression lineage collapse now prefers the current continuation tip over a preserved parent snapshot when both rows share the same backend segment count. This keeps reloads after context compression from reopening the older parent transcript and making the active conversation appear to disappear. - Reloading a stale `/session/<parent>` compression URL now resolves to the visible continuation tip from the sidebar payload instead of reopening the archived parent snapshot. - Undo, retry, and explicit session truncation now persist a sidecar truncation watermark, preventing older `state.db` rows from reappearing after the WebUI transcript was intentionally shortened. - Chat uploads with the same filename in one session now keep distinct attachment files instead of overwriting the earlier upload. - Compression reference card no longer disappears behind the "Load earlier messages" cutoff after subsequent turns. The post-compression anchor is now calculated from the position of the last `[CONTEXT COMPACTION]` marker in the transcript instead of pointing at the visible tail, so the anchor stays at the compression boundary regardless of how many turns have been added since. ### [`v0.51.136`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051136--2026-05-25--Release-DH-stage-batch18--5-PR-streaming--session-index-batch) [Compare Source](nesquena/hermes-webui@v0.51.135...v0.51.136) ##### Fixed - When the session index is missing, WebUI now starts a background rebuild while preserving the first sidebar full-scan result, so the index is primed for later requests without temporarily hiding existing sessions. - Live token-usage hints now cap the cumulative in-flight tool-result prompt estimate per assistant turn, preventing many large tool callbacks from temporarily inflating the context ring before exact provider accounting arrives. - Streaming checkpoint saves now run under the session's profile environment, so periodic background checkpoints no longer risk falling back to the process-global profile when a WebUI tab is using a non-default profile. - Chat streaming now keeps a single live EventSource registered per session/stream, preventing reconnect or context-compaction paths from stacking subscribers and rendering one assistant token stream multiple times. - Streaming visible-progress text emitted simultaneously through token, reasoning, and interim-assistant callbacks now renders once in the chat transcript instead of duplicating inside Thinking cards. ### [`v0.51.135`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051135--2026-05-25--Release-DG-stage-batch17--9-PR-small-fix-batch) [Compare Source](nesquena/hermes-webui@v0.51.134...v0.51.135) ##### Added - Added a proposed canonical session resolution RFC covering URL routes, query parameters, localStorage, sidebar rows, and compression-lineage IDs so future session-routing fixes have one review contract. ##### Fixed - Browser session links that use the API-style `?session_id=<id>` query parameter now open the requested conversation instead of falling back to the last locally stored session. - Gateway status now treats existing messaging-session metadata as configured when `gateway.status` is unavailable, avoiding a misleading "Gateway not configured" warning for multi-container deployments with active gateway sessions. - Session sidebar Archive/Delete menu actions now repaint from local sidebar state immediately after the server confirms the mutation, instead of waiting for the full `/api/sessions` refresh before the row disappears. - Clarification dialogs now reserve transcript space while open or collapsed, so the question prompt no longer covers the assistant text needed to answer it. - Chat uploads now send the absolute server-side path for image attachments in the agent text context, restoring immediate tool access (e.g. `vision_analyze`) to files uploaded in the current turn. - Pending uploaded-file user turns no longer double-render when both the optimistic bubble and the server's pending-message hydration produce the same `[Attached files: ...]` suffix. </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19--> Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/668
Thinking Path
runner-localselection, and the default-off/api/chat/startroute-selection harness.runner-localnow fails closed with a bounded not-configured response rather than silently falling back to WebUI-owned execution.What Changed
docs/rfcs/hermes-run-adapter-contract.md.Why It Matters
This keeps the #1925 ladder moving without jumping straight from route-selection plumbing to a runner implementation. The key guardrail stays intact: WebUI should be thin in execution ownership, not thin in product scope, and the runner boundary should not recreate
STREAMS,CANCEL_FLAGS, cachedAIAgent, approval/clarify callback queues, or active-run discovery caches under new names.Refs #1925.
Verification
env -u HERMES_CONFIG_PATH -u HERMES_WEBUI_HOST /home/michael/.hermes/hermes-agent/venv/bin/python -m pytest tests/test_runtime_adapter_seam.py -q→30 passedenv -u HERMES_CONFIG_PATH -u HERMES_WEBUI_HOST /home/michael/.hermes/hermes-agent/venv/bin/python -m pytest tests/ -q→6587 passed, 6 skipped, 3 xpassed, 8 subtests passedgit diff --check→ cleanRisks / Follow-ups
runner-localbounded 501 path only when a supervised runner client is explicitly configured.Model Used
OpenAI Codex / GPT-5.5 via Hermes Agent, with terminal/file tools and repository tests.