mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-24 18:50:15 +00:00
@@ -94,11 +94,16 @@ adapter-seam work:
|
||||
`queue_message(...)` as a staged protocol method only; `/queue` remains
|
||||
browser-side queue/drain behavior, and no server-side queue endpoint or queue
|
||||
scheduler should be added merely for adapter symmetry.
|
||||
- #2575 shipped the Slice 4a runner/sidecar contract gate in v0.51.93. The next
|
||||
implementation step can add runner-backend adapter plumbing, but 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.
|
||||
- #2575 shipped the Slice 4a runner/sidecar contract gate in v0.51.93.
|
||||
- #2599 shipped the Slice 4b `RunnerRuntimeAdapter` facade in v0.51.94. The
|
||||
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.
|
||||
|
||||
The next gate is runner-backend plumbing, not queue implementation
|
||||
by default. Queue / continue routing should only move before Slice 4 if a future
|
||||
@@ -753,6 +758,8 @@ Non-goals for Slice 4a:
|
||||
|
||||
#### Slice 4b: Runner adapter client facade
|
||||
|
||||
Status as of 2026-05-20: shipped in v0.51.94 via #2599.
|
||||
|
||||
The first code slice after the Slice 4a contract should be a small
|
||||
`RunnerRuntimeAdapter` facade that delegates to an injected runner client. This
|
||||
is still not the runner process itself. Its job is to pin the adapter-facing
|
||||
@@ -771,6 +778,58 @@ normalization rules before route wiring or process supervision lands:
|
||||
The implementation remains default-off until a later slice adds an actual runner
|
||||
client/backend and explicit route selection.
|
||||
|
||||
#### Slice 4c: Feature-flagged runner backend and restart/reattach harness
|
||||
|
||||
After the facade exists, the next narrow implementation slice should add a real
|
||||
runner-client/backend selection point and a synthetic restart/reattach harness,
|
||||
without routing normal browser chat to that backend yet.
|
||||
|
||||
Scope:
|
||||
|
||||
- add a concrete runner-client factory behind an explicit mode such as
|
||||
`HERMES_WEBUI_RUNTIME_ADAPTER=runner-local`, while preserving `legacy-direct`
|
||||
and `legacy-journal` as the default/revert paths;
|
||||
- validate that `StartRunRequest` carries explicit session, profile, workspace,
|
||||
attachments, provider/model, toolset, source, and metadata fields into the
|
||||
runner boundary without relying on WebUI process-global environment mutation;
|
||||
- prove a recreated WebUI adapter can rediscover runner-owned status and replay
|
||||
ordered events from the runner/journal surface after process-local state is
|
||||
discarded;
|
||||
- keep controls bounded through `ControlResult` values, with unsupported controls
|
||||
returning `unsupported` / `not-active` rather than falling back to stale legacy
|
||||
`STREAMS` or callback queues;
|
||||
- keep the live `/api/chat/start` path on the legacy backend until the runner
|
||||
backend has a passing restart/reattach harness and maintainer approval to wire
|
||||
route selection.
|
||||
|
||||
Acceptance tests for Slice 4c:
|
||||
|
||||
1. **Default-off selection.** `legacy-direct` remains the default; `runner-local`
|
||||
or any later runner mode is selected only by an explicit feature flag.
|
||||
2. **No route-shape drift.** Adding the runner backend does not expand public
|
||||
`/api/chat/start`, cancel, approval, clarify, goal, or status response shapes
|
||||
while the route remains legacy-backed.
|
||||
3. **Restart/reattach harness.** A fake or local runner fixture can start a run,
|
||||
discard the first WebUI adapter instance, recreate the adapter, and still
|
||||
observe ordered events plus terminal/live status from durable runner-owned
|
||||
state.
|
||||
4. **Control bounds.** Cancel / approval / clarify / queue / goal controls route
|
||||
through the runner client only when the runner backend is selected, and
|
||||
unsupported controls return bounded `ControlResult` values without consulting
|
||||
legacy process-local state.
|
||||
5. **No runtime-surrogate globals.** The main WebUI server must not gain new
|
||||
module-level maps for runner-owned streams, cancellation flags, pending
|
||||
approval/clarify callbacks, cached agents, or goal/queue schedulers.
|
||||
|
||||
Non-goals for Slice 4c:
|
||||
|
||||
- no default-on runner backend;
|
||||
- no removal of the legacy in-process backend;
|
||||
- no public response-shape expansion;
|
||||
- no live chat route switch to the runner backend before the restart/reattach
|
||||
harness is reviewed;
|
||||
- no server-side queue endpoint or queue scheduler just for adapter symmetry.
|
||||
|
||||
## First Meaningful Success Criteria
|
||||
|
||||
The first meaningful milestones are deliberately split.
|
||||
|
||||
@@ -404,10 +404,25 @@ def test_rfc_defines_slice4_runner_contract_before_runner_code():
|
||||
assert "no removal of the legacy in-process backend" in rfc
|
||||
assert "no default-on runner mode" in rfc
|
||||
assert "#### Slice 4b: Runner adapter client facade" in rfc
|
||||
assert "Status as of 2026-05-20: shipped in v0.51.94 via #2599" in rfc
|
||||
assert "delegates to an injected runner client" in rfc
|
||||
assert "without relying on process-local `STREAMS`" in rfc
|
||||
|
||||
|
||||
def test_rfc_defines_slice4c_runner_backend_harness_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 4c: Feature-flagged runner backend and restart/reattach harness" 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
|
||||
assert "Restart/reattach harness" in rfc
|
||||
assert "discard the first WebUI adapter instance" in rfc
|
||||
assert "No runtime-surrogate globals" in rfc
|
||||
assert "no live chat route switch to the runner backend before the restart/reattach" 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