feat: add local-first gateway routing

This commit is contained in:
Hermes Agent
2026-07-24 11:26:52 +00:00
parent 25a83e0b6f
commit e5cc27ebc7
12 changed files with 720 additions and 402 deletions
+25 -2
View File
@@ -57,9 +57,32 @@ Android contracts may model these needs, but implementation must keep them capab
- The transport/domain model exposes direct gateway capabilities first. `legacyCompanionAdapter` exists only to identify old adapters during migration.
- Backend behavior belongs upstream in Hermes Agent. Hermes Mobile may add client adapters and mappers, not server-side replacements.
## Local-first gateway routing
A server profile can contain two URLs for the **same Hermes gateway identity**:
- **Local URL** — preferred when the phone can safely reach the gateway on the home/LAN (for example, `https://hermes.home.arpa`).
- **Remote URL** — fallback when local reachability is unavailable (for example, a configured public HTTPS hostname).
The client must choose automatically per connection attempt:
1. If a local URL is configured, probe its documented `GET /health` endpoint using a short, bounded timeout.
2. Use the local URL when the probe succeeds and the gateway identity/auth contract is compatible.
3. Otherwise immediately use the configured remote URL; never leave chat blocked waiting for LAN discovery.
4. Re-evaluate on app foreground, explicit reconnect, connectivity changes, and after a failed active request. Do not switch a request mid-stream.
5. Show the active route (`Local` or `Remote`) in connection diagnostics, but do not expose bearer tokens or internal host details in message content/logs.
Security and reliability rules:
- Local and remote URLs are explicit user configuration, not guessed IP ranges or silently discovered devices in the MVP.
- Both routes must use HTTPS by default and must be treated as the same intended gateway only after an authenticated compatibility check. The app must not silently send a bearer token to an arbitrary captive portal or unrelated LAN host.
- Remote is a fallback, not a duplicate profile. User preferences, selected session state, and credentials stay associated with one logical gateway profile.
- A later milestone may add opt-in mDNS/QR setup, certificate pinning/identity binding, and richer connectivity observation only after direct-gateway basics are verified.
- The current upstream identity-binding limitation and the stronger contract needed are tracked in `docs/BLOCKERS.md`.
## Android Contract Milestones
1. Auth and connection: validate URL, store bearer tokens securely, probe `GET /health`, and use `GET /v1/models` as the first authenticated check.
1. Auth and connection: validate local + remote URLs, store bearer tokens securely, probe `GET /health`, use `GET /v1/models` as the first authenticated check, and make local-first fallback observable/retryable.
2. Sessions: keep repository interfaces for list/create/select/continue, but mark route mapping provisional until upstream session docs are verified.
3. Streaming: support final response and token delta reduction now; gate structured tool/artifact/session events behind server capabilities.
3. Streaming: support final response and token delta reduction now; gate structured tool/artifact/session events behind server capabilities. Keep each stream bound to its selected local or remote route.
4. Companion removal: after direct gateway chat/session/streaming works end to end, remove legacy companion UI routes and then deprecate install/docs around `apps/companion`.