Conversation
|
This change is part of the following stack: Change managed by git-spice. |
- Add memory_service_url and communicate_service_url fields to UiConfig
- Load AGENTD_MEMORY_SERVICE_URL (default http://localhost:7008) and
AGENTD_COMMUNICATE_SERVICE_URL (default http://localhost:7010) from env
- Add memory_url and communicate_url fields to ProxyState
- Add proxy_memory and proxy_communicate handler functions
- Register /api/memory/{*path} and /api/communicate/{*path} routes
- Update React frontend serviceConfig to use relative proxy paths
- Fix base.ts buildUrl and openWebSocket to handle relative /api/... URLs
via window.location.origin (fixes 'Invalid URL' error)
- Fix inline WS URL helpers in hooks/components for relative base URLs
- Add memory and communicate dev proxy entries to vite.config.ts
geoffjay
left a comment
There was a problem hiding this comment.
Review: fix(ui): add memory and communicate service proxy routes
The core goal is correct and the implementation approach is sound, but there are two issues to address before merge.
Blocker 1: Branch needs restack
The diff context reveals this branch was created before the index_url proxy support landed on main. The current main branch has index_url: String in ProxyState (proxy.rs), index_service_url: String in UiConfig (config.rs), and the matching proxy_index route wired in lib.rs — none of which appear in this PR's diff context. Merging as-is would produce a conflict or silently drop the index service proxy.
Fix: run git-spice upstack restack to pull in the index service changes, then re-push.
Blocker 2: Rust proxy does not support WebSocket upgrades
config.ts is changed to route all service URLs through the proxy — including the orchestrator and communicate services, both of which have WebSocket endpoints:
AgentTerminal.tsxopensws://<host>/api/orchestrator/terminal/<id>useAgentStream.ts/useAllAgentsStream.tsopenws://<host>/api/orchestrator/stream/<id>useCommunicateSocket.tsopensws://<host>/api/communicate/...
The Rust proxy in proxy_request uses reqwest::Client, which is an HTTP client and does not implement the WebSocket upgrade handshake (HTTP 101 / Upgrade: websocket). When the browser initiates a WebSocket connection through /api/orchestrator or /api/communicate, the proxy will forward the upgrade request to the upstream but then call .bytes().await on the response — which will either hang waiting for the stream to complete or return a malformed response, breaking the WebSocket connection.
The Vite dev proxy handles this correctly with ws: true, but that only applies in local development. The production Rust proxy has no equivalent.
Before this PR: WebSocket connections used direct http://localhost:17006 URLs (baked in at build time), bypassing the proxy entirely. After this PR: they are routed through the Rust proxy and will fail.
Options to fix:
- Lowest-risk / recommended for this PR's scope: Keep WebSocket-bearing services on absolute URLs and only route REST-only services (memory, ask, notify) through the proxy. You could split the orchestrator config into separate REST and WS URL keys, or leave orchestrator/communicate on direct URLs for now.
- Replace
reqwest-based proxying with a crate that supports HTTP upgrade tunneling (e.g.hyper-reverse-proxywith upgrade support). - Add dedicated WebSocket tunnel handlers alongside the HTTP proxy handlers for services that need it.
Option 1 unblocks the memories fix without regressing agent streaming or communicate.
Minor: ws: true on memory proxy is unnecessary
"/api/memory": {
target: memoryServiceUrl,
ws: true, // memory is REST-only — this flag is misleadingThe memory service appears to be HTTP/REST only. ws: true is harmless but misleading. Worth removing for clarity. (Separately, the existing /api/orchestrator Vite entry is missing ws: true, which is the actual gap for agent streaming in dev — but that's a pre-existing issue outside this PR's scope.)
What's good
- The Rust-side additions (
config.rs,lib.rs,proxy.rs) are clean and follow the existing proxy pattern exactly — naming, error handling, doc comments are all consistent. - The
base.tsrelative-path guard (startsWith("/") ? window.location.origin + ...) is correct and handles both absolute and relative base URLs properly. - The same guard is applied consistently across all four hook/component files that construct WebSocket URLs.
- The vite dev proxy entries for the new services are structured correctly, and
ws: trueon communicate is appropriate for that service. - The PR description accurately describes the problem (17008 vs 7008 port mismatch) and the intended solution.
Add proxy routes for the memory and communicate services to the UI server, and update the React frontend to use relative proxy paths instead of direct localhost URLs. This fixes the /memories page silently failing due to port mismatch (17008 vs 7008).
Closes #929