M1+M2: gateway core loop + agent transparency

M1 (gateway core loop / text round-trip):
- WS server (ws_server.py): bind, hello auth (constant-time), hello.ack, heartbeat, connection registry
- pairing.py: token generation, pairing store, QR payload
- adapter.py: send() -> message frame; inbound message.send -> MessageEvent -> handle_message
- app: Connect screen, GatewayClient (connect + reconnect), ChatScreen send/render, SecureStore (Android/Desktop)
- tests/ws_probe.py: probe harness driving a real turn

M2 (streaming + reasoning + tools + commentary):
- protocol.py: M2 frame types (message.start/update/stop, tool.start/progress/end, commentary)
- adapter.py: per-chat turn-state machine; classify outbound into frames; _split_reasoning; tool-line parsing
- reasoning in streaming: capture via on_stream_delta hook (kind=reasoning, gated by plugins.stream_reasoning_deltas) with a FIFO barrier, attach to message.stop
- app: live streaming bubble, ReasoningBlock (collapse + copy), ToolCard (Everything/Truncated/Nothing), dimmed commentary, typing
- docs/14-milestones.md: M1/M2 marked done; reasoning note corrected
This commit is contained in:
ARIA committed 2026-08-19 13:56:19 +02:00
1 parent 59acf66c89
commit 218c50d688
21 files changed
+3437 -129

No files matched your search

+28 -18
View File
@@ -7,15 +7,15 @@ has explicit **acceptance criteria**. Work top-to-bottom; don't skip M0/M1.
## M0 — Toolchain & scaffolding
**Goal:** everything builds; the plugin is discoverable; the repo is safe.
- [ ] Install JDK 17, Android SDK, set `ANDROID_HOME` (`12-toolchain.md`).
- [ ] `cd hermes-agent && uv sync` (hermes venv works).
- [ ] Create monorepo scaffold (`02-monorepo.md`): `gateway-plugin/`, `app/`
- [X] Install JDK 17, Android SDK, set `ANDROID_HOME` (`12-toolchain.md`).
- [X] `cd hermes-agent && uv sync` (hermes venv works).
- [X] Create monorepo scaffold (`02-monorepo.md`): `gateway-plugin/`, `app/`
(CMP: `shared`, `androidApp`, `desktopApp`), root `.gitignore`
(**excludes `hermes-agent/`**), root `README.md`.
- [ ] `git init` + a pre-commit/CI guard that fails if `hermes-agent/` is staged.
- [ ] CMP project builds empty: `./gradlew :androidApp:assembleDebug`,
- [X] `git init` + a pre-commit/CI guard that fails if `hermes-agent/` is staged.
- [X] CMP project builds empty: `./gradlew :androidApp:assembleDebug`,
`./gradlew :desktopApp:run` (blank window).
- [ ] Plugin skeleton: `plugin.yaml` + `adapter.py` with `register(ctx)` + a
- [X] Plugin skeleton: `plugin.yaml` + `adapter.py` with `register(ctx)` + a
no-op `AndroidAdapter` → `hermes gateway status` lists **android**.
- **Demo:** `hermes gateway status` shows `android`; `./gradlew
:androidApp:installDebug` installs a blank app on the MIX 2S.
@@ -25,31 +25,41 @@ has explicit **acceptance criteria**. Work top-to-bottom; don't skip M0/M1.
## M1 — Gateway core loop (text round-trip)
**Goal:** pair + send a text message + get a (non-streaming) reply.
- [ ] WS server (`ws_server.py`): bind, `hello` auth (constant-time),
- [X] WS server (`ws_server.py`): bind, `hello` auth (constant-time),
`hello.ack`, heartbeat, connection registry.
- [ ] `AndroidAdapter.send()` → `message` frame; inbound `message.send` →
- [X] `AndroidAdapter.send()` → `message` frame; inbound `message.send` →
`MessageEvent` → `handle_message`.
- [ ] Pairing store + `ANDROID_TOKEN`; QR payload in `interactive_setup`.
- [ ] App: Connect screen (URL+token, real `hello` test), `GatewayClient`
- [X] Pairing store + `ANDROID_TOKEN`; QR payload in `interactive_setup`.
- [X] App: Connect screen (URL+token, real `hello` test), `GatewayClient`
(connect + reconnect), ChatScreen sends + renders `message`.
- [ ] `ws_probe.py` harness drives a real turn.
- [X] `ws_probe.py` harness drives a real turn.
- **Demo (on-device):** pair the phone, send "hello", see the agent's reply.
- **Accept:** text round-trip works on-device; wrong token is rejected;
reconnect after gateway restart re-pairs.
## M2 — Streaming + reasoning + tools + commentary
**Goal:** the "agent transparency" features.
- [ ] Map consumer `send`/`edit_message` → `message.start/update/stop`.
- [ ] Reasoning: set `show_reasoning` for android; adapter splits prefix →
`reasoning` field. **Verify format with `ws_probe.py`.**
- [ ] Tool events: classify tool-progress `send()`s → structured
- [X] Map consumer `send`/`edit_message` → `message.start/update/stop`.
- [X] Reasoning: set `show_reasoning` for android; adapter splits prefix →
`reasoning` field. **Verify format with `ws_probe.py`.** (The model
returns a separate `reasoning_content` field. In the *streaming* case the
gateway drops it — the stream consumer only forwards `content` and the
final send is suppressed — so the adapter captures it via the
`on_stream_delta` plugin hook (`kind="reasoning"`, gated by
`plugins.stream_reasoning_deltas: true`) and attaches it to
`message.stop`. Non-streaming already carried it via the prefix split.)
- [X] Tool events: classify tool-progress `send()`s → structured
`tool.start/progress/end` (turn-state machine). **Verify with probe.**
- [ ] Commentary → `commentary` frames. Typing → `typing`.
- [ ] App: live bubble (coalesced updates), `ReasoningBlock` (collapse + copy),
- [X] Commentary → `commentary` frames. Typing → `typing`.
- [X] App: live bubble (coalesced updates), `ReasoningBlock` (collapse + copy),
`ToolCard` with **Everything/Truncated/Nothing** setting, dimmed
`commentary` bubble.
- **Demo (on-device):** a multi-step prompt streams, shows reasoning above the
answer, tool cards (toggle verbosity), and an intermediate beat.
(Verified on the MIX 2S: streaming, tool cards + verbosity toggle, and the
reasoning panel rendering above the answer. The commentary beat is
model/agent-dependent and did not fire with the current model, but the
rendering + frame handling are in place.)
- **Accept:** all four render correctly; tool verbosity setting changes
rendering; reasoning copy button works; frame shapes match `04-wire-protocol`.
@@ -135,4 +145,4 @@ has explicit **acceptance criteria**. Work top-to-bottom; don't skip M0/M1.
are stable so the shared module is settled.
- Parallelizable: plugin (Python) and app (Kotlin) can be worked on
concurrently once the protocol (`04-wire-protocol.md`) is agreed; the probe
harness is the integration seam.
harness is the integration seam.