feat: add term-llm Hub and delegation#801
Open
sam-saffron-jarvis wants to merge 9 commits into
Open
Conversation
Adds 'term-llm serve hub', a launcher/control plane fronting many term-llm serves (nodes), as a more ambitious successor to the serve-gateway prototype. internal/hub (new): Node abstraction + resolvers - Node: identity, URL/base path, bearer token, source - Registry over pluggable resolvers with precedence dedupe and soft failures - Static config resolver (YAML/JSON, --config), contain workspace resolver (via new contain.ReadWebConfig), local JSON store (0600) for UI-added nodes - Concurrent health prober: reachability, latency, agent/version/capabilities serve hub command: - Polished dashboard (embedded template/CSS): node cards with status dot, latency, source badge, capabilities, Open action, Add Node modal with Test connection, remove for local nodes; term-llm Hub branding - /node/<id>/* reverse proxy: injects node token server-side, strips client Authorization/Cookie/X-Api-Key and forwarding headers, no env proxy on the backend transport, SSE-safe timeouts, rebases <base>/TERM_LLM_UI_PREFIX onto the mount, rejects encoded separators and dot-dot traversal - Loopback-only bind until hub auth exists (documented TODOs: auth, self-registration, mTLS, host-based routing) Hub integration in serve web: - Proxy injects window.TERM_LLM_HUB into node HTML; the web UI sidebar now renders a Back to Hub link just below the Widgets entry when present - Native flags --hub-url/--hub-node-id/--hub-node-name for direct hub awareness without the proxy - healthz reports agent/version/capabilities to bearer-authenticated callers so the hub dashboard can display them contain: new env helpers (EnvPath, ReadEnvFile, ReadWebConfig) Tests: hub resolvers/registry/store/prober, contain env parsing, proxy token injection + credential stripping, HTML rebase + hub context injection, node API token non-leakage, add/test/remove flow, JS sidebar back-to-hub tests. Docs: new Hub guide.
70f7033 to
1119fba
Compare
8038e2e to
04a121c
Compare
04a121c to
64ff3d8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds term-llm Hub as a single dashboard/proxy over multiple term-llm web nodes, plus opt-in cross-node delegation.
Hub v1 includes:
term-llm serve hub--auth bearer,--token,TERM_LLM_HUB_TOKEN) with--auth nonerestricted to loopback/node/<id>/...node UI proxy with server-side bearer-token injectionhub_delegateandhub_check_delegationtoolsDelegation from jarvis-homeSafety model
Delegation is default-off and opt-in per node:
Without
delegation.enabled: true, a node can neither originate nor accept delegated work.Accepting delegated work still requires a target workdir:
Existing narrowing knobs remain available:
toaccept_fromallowed_agentsallowed_modelsmax_in_flightBut the user-facing safety story is the simple switch: delegation participation is off until the operator enables it.
Hub auth
Hub now has first-party bearer auth:
--auth beareris the default.--auth noneis allowed only on loopback./api/connectremains node-authenticated so reverse nodes can connect with their node token.X-Term-LLM-Node-ID+ node bearer token), not the operator Hub token.This keeps Hub auth simple: one operator token now; no users/RBAC/OAuth in this PR.
Reverse/private nodes
Adds reverse connection mode for private nodes where the Hub has a public address but cannot reach the node directly.
Hub config:
Private node:
The node dials
GET /api/connectas a websocket using its node id + bearer token. Hub requests then use the same node record and policy path as direct nodes; only the transport changes. Both ends send websocket pings every 20s, require pong/read activity within 60s, and use write deadlines so silent half-open sockets are detected and the node reconnects instead of sitting stale.Reverse transport now streams responses in bounded chunks over the websocket, with cancellation propagation. Direct-node streams still use the normal reverse proxy path.
This keeps the architecture simple:
/node/<id>/...proxyDashboard diagnostics
Node cards now surface token-safe diagnostics for common bad setups:
The point is to show the rake before someone steps on it.
Delegation recovery hardening
Partial target failures are now more recoverable:
Still no offline queue. Offline nodes fail fast; reconnect lets subsequent refresh/cancel paths recover known work.
Node-anywhere docs
Docs cover both modes:
Demo
Standalone isolated demo video, using two clean node homes/session stores rather than Sam's real Jarvis setup:
Delegation from jarvis-homeVideo artifact:
/chat/files/term-llm-hub-standalone-demo.mp4Tests
Live smoke: