macOS: fold agent control into GatewayConnection
This commit is contained in:
24
docs/refactor/gateway-client.md
Normal file
24
docs/refactor/gateway-client.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Gateway Client Refactor (Dec 2025)
|
||||
|
||||
Goal: remove stringly-typed gateway calls from the macOS app, centralize routing/channel semantics, and improve error handling.
|
||||
|
||||
## Progress
|
||||
|
||||
- [x] Fold legacy “AgentRPC” into `GatewayConnection` (single layer; no separate client object).
|
||||
- [x] Typed gateway API: `GatewayConnection.Method` + `requestDecoded/requestVoid` + typed helpers (status/agent/chat/cron/etc).
|
||||
- [x] Centralize agent routing/channel semantics via `GatewayAgentChannel` + `GatewayAgentInvocation`.
|
||||
- [x] Improve gateway error model (structured `GatewayResponseError` + decoding errors include method).
|
||||
- [x] Migrate mac call sites to typed helpers (leave only intentionally dynamic forwarding paths).
|
||||
- [x] Convert remaining UI raw channel strings to `GatewayAgentChannel` (Cron editor).
|
||||
- [x] Cleanup naming: rename remaining tests/docs that still reference “RPC/AgentRPC”.
|
||||
|
||||
### Notes
|
||||
|
||||
- Intentionally string-based:
|
||||
- `BridgeServer` dynamic request forwarding (method is data-driven).
|
||||
- `ControlChannel` request wrapper (generic escape hatch).
|
||||
|
||||
## Notes / Non-goals
|
||||
|
||||
- No functional behavior changes intended (beyond better errors and removing “magic strings”).
|
||||
- Keep changes incremental: introduce typed APIs first, then migrate call sites, then remove old helpers.
|
||||
@@ -45,7 +45,7 @@ Goal: enforce the invariant **“one gateway websocket per app process (per effe
|
||||
|
||||
Key elements:
|
||||
- `GatewayConnection.shared` owns the one websocket and is the *only* supported entry point for app code that needs gateway RPC.
|
||||
- Consumers (e.g. Control UI, Agent RPC, SwiftUI WebChat) call `GatewayConnection.shared.request(...)` and do not create their own sockets.
|
||||
- Consumers (e.g. Control UI, agent invocations, SwiftUI WebChat) call `GatewayConnection.shared.request(...)` and do not create their own sockets.
|
||||
- If the effective connection config changes (local ↔ remote tunnel port, token change), `GatewayConnection` replaces the underlying connection.
|
||||
- The transport (`GatewayChannelActor`) is an internal detail and forwards push frames back into `GatewayConnection`.
|
||||
- Server-push frames are delivered via `GatewayConnection.shared.subscribe(...) -> AsyncStream<GatewayPush>` (in-process event bus).
|
||||
@@ -84,7 +84,7 @@ Minimum invariants:
|
||||
- Config changes (token / endpoint) cancel the old socket and reconnect once.
|
||||
|
||||
Nice-to-have integration coverage:
|
||||
- Multiple “consumers” (Control UI + Agent RPC + SwiftUI WebChat) all call through the shared connection and still produce only one websocket.
|
||||
- Multiple “consumers” (Control UI + agent invocations + SwiftUI WebChat) all call through the shared connection and still produce only one websocket.
|
||||
|
||||
Additional coverage added (macOS):
|
||||
- Subscribing after connect replays the latest snapshot.
|
||||
|
||||
@@ -105,7 +105,7 @@ Goal: replace legacy gateway/stdin/TCP control with a single WebSocket Gateway,
|
||||
- Add lightweight WS client helper for `status/health/send/agent` when Gateway is up. ✅ `gateway` subcommands use the Gateway over WS.
|
||||
- Consider a “local only” flag to avoid accidental remote connects. (optional; not needed with tunnel-first model.)
|
||||
- **WebChat backend**:
|
||||
- Single WS to Gateway; seed UI from snapshot; forward `presence/tick/agent` to browser. ✅ implemented via `GatewayClient` in `webchat/server.ts`.
|
||||
- Single WS to Gateway; seed UI from snapshot; forward `presence/tick/agent` to browser. ✅ implemented via the WebChat gateway client in `webchat/server.ts`.
|
||||
- Fail fast if handshake fails; no fallback transports. ✅ (webchat returns gateway unavailable)
|
||||
|
||||
## Phase 6 — Send/agent path hardening
|
||||
@@ -148,7 +148,7 @@ Goal: replace legacy gateway/stdin/TCP control with a single WebSocket Gateway,
|
||||
- Mac app smoke: presence/health render from snapshot; reconnect on tick loss. (Manual: open Instances tab, verify snapshot after connect, induce seq gap by toggling wifi, ensure UI refreshes.)
|
||||
- WebChat smoke: snapshot seed + event updates; tunnel scenario. ✅ Offline snapshot harness in `src/webchat/server.test.ts` (mock gateway) now passes; live tunnel still recommended for manual.
|
||||
- Idempotency tests: retry send/agent with same key after forced disconnect; expect deduped result. ✅ send + agent dedupe + reconnect retry covered in gateway tests.
|
||||
- Seq-gap handling: ✅ clients now detect seq gaps (GatewayClient + mac GatewayChannel) and refresh health/presence (webchat) or trigger UI refresh (mac). Load-test still optional.
|
||||
- Seq-gap handling: ✅ clients now detect seq gaps (WebChat gateway client + mac `GatewayConnection/GatewayChannel`) and refresh health/presence (webchat) or trigger UI refresh (mac). Load-test still optional.
|
||||
|
||||
## Phase 10 — Rollout
|
||||
- Version bump; release notes: breaking change to control plane (WS only).
|
||||
|
||||
Reference in New Issue
Block a user