mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-25 19:20:16 +00:00
+4
-1
@@ -3,12 +3,15 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- **PR #2744** by @Michaelyklam — #1925 RuntimeAdapter RFC follow-up: marks the `runner-local` selection seam shipped in v0.51.105 and defines the next Slice 4d supervised runner route gate before live chat can move onto a runner backend. The gate keeps runner routing default-off, preserves legacy fallback and public response shapes, and carries the Runtime API gap matrix forward so active-run discovery, session→run lookup, command metadata, artifacts, and provider/tool routing do not become private WebUI runtime replicas.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Sanitize git fetch diagnostics before returning update-check errors to the browser, preserving useful failure context while redacting credentialed remote URLs, GitHub token shapes, and secret-looking query parameters.
|
||||
- **Fixed: per-turn SQLite connection leak in handoff-summary path (#2233)** (Isla Liu, fork prototype). Two functions on the `/api/session/handoff-summary` hot path were opening `sqlite3.connect(...)` inside a bare `with` statement, which commits the transaction at scope exit but does NOT close the connection. Per-turn invocations accumulated `state.db`/`state.db-wal` file descriptors and CPython heap pages on long-lived worker threads, surfacing as the multi-GB VmRSS / 6× duplicated state.db fds observed on PID 434. Wrapped both call sites with `contextlib.closing(...)` (already imported and used at 7 other sites in the same files) so the connection is closed deterministically: `api/models.py::count_conversation_rounds` and `api/routes.py::_persist_handoff_summary_to_state_db`. Regression test `tests/test_issue2233_sqlite_connection_leak.py` loops both functions 20× against a tmp `state.db` and asserts `/proc/<pid>/fd` count does not grow more than 2. Live soak against a freshly-built worktree server confirmed fd growth = 0 and VmRSS growth = 0 KB across 20 POSTs to `/api/session/handoff-summary` — well below the leaked-curve baseline (cold 134 MB → pre-restart 1.27 GB on the unpatched instance). Rollback: single `git revert` reverts both edits.
|
||||
|
||||
|
||||
## [v0.51.107] — 2026-05-21 — Release CE (stage-400 — 8-PR batch — pinned-sessions-limit getter rename + uploaded-file user-turn dedupe + active-run repair guard + incremental KaTeX streaming + profile default model on fresh boot + French locale completion + update-check error surfacing + release-update apply path)
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
- **Author:** @Michaelyklam
|
||||
- **Updated by:** @franksong2702
|
||||
- **Created:** 2026-05-11
|
||||
- **Revised:** 2026-05-17
|
||||
- **Revised:** 2026-05-21
|
||||
- **Tracking issue:** [#1925](https://github.com/nesquena/hermes-webui/issues/1925)
|
||||
|
||||
## Credit and Scope
|
||||
@@ -52,7 +52,7 @@ The immediate goal is not to build a sidecar. The immediate goal is to define th
|
||||
browser contract, classify current runtime state, and gate the first reversible
|
||||
journal slice.
|
||||
|
||||
## Current Gate State — 2026-05-19
|
||||
## Current Gate State — 2026-05-21
|
||||
|
||||
Slice 1 is now past the first active validation gate:
|
||||
|
||||
@@ -99,11 +99,16 @@ adapter-seam work:
|
||||
facade normalizes an injected runner client's start / observe / status /
|
||||
control responses without owning `AIAgent`, streams, cancellation flags,
|
||||
approval queues, clarify queues, goal state, or cached-agent tables.
|
||||
- The next implementation gate is a feature-flagged runner backend plus
|
||||
restart/reattach harness. It must stay default-off, keep legacy fallback
|
||||
intact, pass explicit profile/workspace/model payloads instead of mutating
|
||||
WebUI process globals, and avoid recreating `STREAMS` / `CANCEL_FLAGS` /
|
||||
approval queues / clarify queues under new names.
|
||||
- #2627 shipped the Slice 4c runner-backend harness gate in v0.51.96.
|
||||
- #2696 shipped the first Slice 4c implementation in v0.51.105: the default-off
|
||||
`runner-local` adapter selection point and `build_runtime_adapter(...)`
|
||||
factory wiring around an injected runner client. Live browser chat routes still
|
||||
stay on the legacy backend, and no supervised runner process exists yet.
|
||||
- The next implementation gate is a supervised/local runner backend proposal and
|
||||
route-selection harness. It must stay default-off, keep legacy fallback intact,
|
||||
pass explicit profile/workspace/model payloads instead of mutating WebUI
|
||||
process globals, and avoid recreating `STREAMS` / `CANCEL_FLAGS` / approval
|
||||
queues / clarify queues under new names.
|
||||
|
||||
The next gate is runner-backend plumbing, not queue implementation
|
||||
by default. Queue / continue routing should only move before Slice 4 if a future
|
||||
@@ -780,11 +785,11 @@ client/backend and explicit route selection.
|
||||
|
||||
#### Slice 4c: Feature-flagged runner backend and restart/reattach harness
|
||||
|
||||
Status as of PR #2696: implementation proposed. The code adds a default-off
|
||||
`runner-local` adapter selection point plus factory wiring for an injected runner
|
||||
client, while keeping live browser chat routes on the legacy backend. The
|
||||
restart/reattach harness remains synthetic/fake-runner based until a later slice
|
||||
introduces a supervised runner process.
|
||||
Status as of 2026-05-21: shipped in v0.51.105 via #2696. The code adds a
|
||||
default-off `runner-local` adapter selection point plus factory wiring for an
|
||||
injected runner client, while keeping live browser chat routes on the legacy
|
||||
backend. The restart/reattach harness remains synthetic/fake-runner based until a
|
||||
later slice introduces a supervised runner process.
|
||||
|
||||
After the facade exists, the next narrow implementation slice should add a real
|
||||
runner-client/backend selection point and a synthetic restart/reattach harness,
|
||||
@@ -836,6 +841,61 @@ Non-goals for Slice 4c:
|
||||
harness is reviewed;
|
||||
- no server-side queue endpoint or queue scheduler just for adapter symmetry.
|
||||
|
||||
#### Slice 4d: Supervised runner backend route gate
|
||||
|
||||
After `runner-local` selection exists, the next reviewable gate should define the
|
||||
first supervised/local runner backend and the route-selection harness before live
|
||||
browser chat can use it. This is still a contract/test slice first: no default-on
|
||||
runner mode, no removal of `legacy-direct` or `legacy-journal`, and no claim that
|
||||
production WebUI turns survive restart until the harness demonstrates it.
|
||||
|
||||
Scope:
|
||||
|
||||
- define the runner process/client lifecycle: how a run is spawned, supervised,
|
||||
observed, and terminated without placing new active-run maps in the main WebUI
|
||||
request process;
|
||||
- define the route-selection point for `/api/chat/start` without changing the
|
||||
public response shape while the default remains legacy-backed;
|
||||
- specify how runner-owned events become WebUI journal events with stable
|
||||
cursors, terminal state, and replay ordering;
|
||||
- specify cancellation, approval, clarify, goal, and staged queue behavior as
|
||||
runner-client `ControlResult` responses, with unsupported controls bounded and
|
||||
visible rather than silently falling back to legacy process-local callbacks;
|
||||
- carry the runtime API gap matrix forward: missing Hermes-owned capabilities
|
||||
such as active-run discovery, session-to-run lookup, command capability
|
||||
metadata, artifact events, and provider/tool routing should remain explicit
|
||||
gaps or temporary adapter state, not private WebUI runtime replicas.
|
||||
|
||||
Acceptance tests for Slice 4d:
|
||||
|
||||
1. **Route remains default-off.** Unset `HERMES_WEBUI_RUNTIME_ADAPTER` and
|
||||
`legacy-direct` keep `/api/chat/start` on the existing path; `runner-local`
|
||||
is the only mode allowed to select the runner route.
|
||||
2. **Restart/reattach harness proves ownership moved.** A fake or local runner
|
||||
starts a run, the first WebUI server/adapter instance is discarded, a new
|
||||
adapter instance discovers the same active or terminal run, replay catches up
|
||||
from cursor, and cancel remains available if the run is still active.
|
||||
3. **No public response-shape drift.** Chat start and control responses remain
|
||||
stable while adapter-only fields stay internal or explicitly documented as a
|
||||
new contract revision.
|
||||
4. **No runtime-surrogate globals.** The main WebUI server does not gain new
|
||||
module-level maps for runner-owned streams, cancel flags, approval/clarify
|
||||
callbacks, cached agents, goal state, or queue schedulers.
|
||||
5. **Explicit context payloads.** Runner startup carries session, profile,
|
||||
workspace, attachments, provider/model, toolsets, source, and metadata as
|
||||
payload fields rather than depending on process-global environment mutation in
|
||||
the WebUI server.
|
||||
|
||||
Non-goals for Slice 4d:
|
||||
|
||||
- no default-on runner backend;
|
||||
- no removal of the legacy in-process backends;
|
||||
- no server-side queue endpoint or scheduler just for adapter symmetry;
|
||||
- no permanent WebUI-owned active-run discovery cache when the missing capability
|
||||
belongs in a runner or future Hermes Runtime API;
|
||||
- no broad UI/product surface migration; WebUI remains the rich workbench while
|
||||
only execution ownership moves.
|
||||
|
||||
## First Meaningful Success Criteria
|
||||
|
||||
The first meaningful milestones are deliberately split.
|
||||
|
||||
@@ -470,6 +470,7 @@ def test_rfc_defines_slice4c_runner_backend_harness_gate():
|
||||
rfc = (routes.Path(__file__).parent.parent / "docs" / "rfcs" / "hermes-run-adapter-contract.md").read_text(encoding="utf-8")
|
||||
|
||||
assert "#### Slice 4c: Feature-flagged runner backend and restart/reattach harness" in rfc
|
||||
assert "Status as of 2026-05-21: shipped in v0.51.105 via #2696" in rfc
|
||||
assert "`HERMES_WEBUI_RUNTIME_ADAPTER=runner-local`" in rfc
|
||||
assert "`legacy-direct` remains the default" in rfc
|
||||
assert "No route-shape drift" in rfc
|
||||
@@ -479,6 +480,22 @@ def test_rfc_defines_slice4c_runner_backend_harness_gate():
|
||||
assert "no live chat route switch to the runner backend before the restart/reattach" in rfc
|
||||
|
||||
|
||||
def test_rfc_defines_slice4d_supervised_runner_route_gate():
|
||||
routes = importlib.import_module("api.routes")
|
||||
rfc = (routes.Path(__file__).parent.parent / "docs" / "rfcs" / "hermes-run-adapter-contract.md").read_text(encoding="utf-8")
|
||||
|
||||
assert "#### Slice 4d: Supervised runner backend route gate" in rfc
|
||||
assert "After `runner-local` selection exists" in rfc
|
||||
assert "route-selection harness before live\nbrowser chat can use it" in rfc
|
||||
assert "Route remains default-off" in rfc
|
||||
assert "Restart/reattach harness proves ownership moved" in rfc
|
||||
assert "No public response-shape drift" in rfc
|
||||
assert "No runtime-surrogate globals" in rfc
|
||||
assert "Explicit context payloads" in rfc
|
||||
assert "active-run discovery, session-to-run lookup, command capability\n metadata, artifact events, and provider/tool routing" in rfc
|
||||
assert "WebUI remains the rich workbench while\n only execution ownership moves" in rfc
|
||||
|
||||
|
||||
def test_runner_runtime_adapter_passes_explicit_start_payload_without_env_mutation(monkeypatch):
|
||||
runtime = importlib.import_module("api.runtime_adapter")
|
||||
captured = []
|
||||
|
||||
Reference in New Issue
Block a user