feat: gateway forwarding between the local mesh and the hub - #175
Merged
Merged
Conversation
AgentRegistry.getAgent only checked the local agents map, so a device known solely through gossip (never registered or state-synced locally) was unresolvable even though listAgents already merged it into its own returned array. Extend getAgent to fall back to the same listDiscoverableAgents merge listAgents uses, via a shared synthesiseDiscoveredAgent helper. RoomMessaging.sendDm checked recipient existence via a direct agents.get lookup, which can never see a gossip-only device. Route it through a new resolveAgent dependency (wired to AgentRegistry.getAgent) instead, so a DM to a gossip-discovered recipient is no longer rejected as AGENT_NOT_FOUND before ever reaching the transport layer. This is a prerequisite for cross-machine DMs (agent-comms#155), where a remote agent learned via the hub's gossip will never exist as a locally registered record.
… mesh and the hub The gateway (agent-comms#154) held a hub connection but did nothing with it: no local agent was ever advertised onto it, nothing learned from it was merged back, and a room-domain request addressed to a device this side had no local session for simply failed as not_connected. This wires the actual forwarding, both directions. Outbound: whenever a local peer session's own gossiped directory changes, forward every agent/self-bearing entry (by construction only ever a visible agent, since MeshStore's selfAgentAdvert getter never gossips that key for a hidden or ghost one) onto the hub's own raw connection as a gossip frame, keyed by each device's own device-id. sendGossipUpdate can only ever advertise a session's own single device, so this rides HubSession's own tracked raw Connection instead. connectHub also pushes an immediate catch-up of every already-known local device, so a coordinator handover doesn't wait for each local peer's own next periodic gossip tick to re-advertise. Remote directory merge: HubSession now surfaces every remote directory entry the hub's gossip and catch-up carry, merged into the transport's own mesh-wide knownDevices via the same mergeKnownDevices helper a local peer session's directory already uses -- a hub-learned agent therefore surfaces in listAgents/getAgent with no separate lookup path. Routing: WireMeshTransport.sendRoomRequest falls back to routing through the hub's relay-connect/relay-data pairing when its target isn't a local peer session, bounded by a timeout since the hub silently drops a relay-connect to an unknown target-device with no error frame. HubSession's own inbound dispatch now sends a real room-domain verb (room.send, room.join, room.notify, ...) to the same roomVerbHandlers a local peer session already uses, with a per-request ConnectionHandle keyed by request.fromDevice -- the same "attribute to the true sender, never the hub" discipline already applied to the legacy opaque-frame path, extended to this one. A legacy state_sync or state_update carried this way is still dropped before it ever reaches onMessage, unchanged: it has no per-request capability token to verify it against, unlike a real room-domain verb. reportPresenceAdvert and the outbound-forwarding/routing helpers move out to gossip-directory.ts and a new hub-forwarding.ts respectively to keep wire-mesh-transport.ts under this repo's max-lines cap.
wireTestTransport never wired WireMeshTransport's getSelfAgentAdvert parameter, unlike bridge-mesh.ts's own production wiring -- every test built on it therefore never gossiped the agent/self extension at all, regardless of registerAgent being called, which silently made listKnownDevices/listAgents' own gossip-discovery merge untestable through the standard helper. Wire it the same way production does. Add integration coverage for agent-comms#155 using two independent local meshes, each its own coordinator dialling a shared real relay hub, never directly connected to each other: a non-gateway local peer on one machine is discovered by the other machine's gateway purely via hub gossip; a hidden or ghost agent is never advertised across it; and a DM to a remote gateway's own agent, including its two-round consent handshake, routes correctly through the hub's relay pairing. Document the one confirmed limitation this surfaced: wire-mesh-core's own session layer tracks at most one active relay pairing per remote device, so an inbound hub-relayed room-domain request is dispatched as addressed to this gateway's own agent unconditionally -- there is no target-device disambiguation available yet to route it on to a different local peer this same gateway also advertises.
Mearman
force-pushed
the
feat/gateway-forwarding
branch
from
September 17, 2026 17:07
33488e5 to
18eee5f
Compare
Mearman
marked this pull request as ready for review
September 17, 2026 17:13
|
🎉 This PR is included in version 3.10.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
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.
Implements the core forwarding leg of the cross-machine mesh epic (#153): the coordinator's gateway (#154) starts actually forwarding between the local mesh and the hub, in both directions.
visibleagents onto the hub via gossip, keyed by device-id, so remote gateways can address them.list_agentsand are resolvable for DMs.Closes #155
Work in progress -- pushing incrementally.