agent-inbox 0.0.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/CLAUDE.md +113 -0
  2. package/README.md +195 -1
  3. package/dist/federation/address.d.ts +24 -0
  4. package/dist/federation/address.d.ts.map +1 -0
  5. package/dist/federation/address.js +54 -0
  6. package/dist/federation/address.js.map +1 -0
  7. package/dist/federation/connection-manager.d.ts +118 -0
  8. package/dist/federation/connection-manager.d.ts.map +1 -0
  9. package/dist/federation/connection-manager.js +369 -0
  10. package/dist/federation/connection-manager.js.map +1 -0
  11. package/dist/federation/delivery-queue.d.ts +66 -0
  12. package/dist/federation/delivery-queue.d.ts.map +1 -0
  13. package/dist/federation/delivery-queue.js +199 -0
  14. package/dist/federation/delivery-queue.js.map +1 -0
  15. package/dist/federation/index.d.ts +7 -0
  16. package/dist/federation/index.d.ts.map +1 -0
  17. package/dist/federation/index.js +6 -0
  18. package/dist/federation/index.js.map +1 -0
  19. package/dist/federation/routing-engine.d.ts +74 -0
  20. package/dist/federation/routing-engine.d.ts.map +1 -0
  21. package/dist/federation/routing-engine.js +158 -0
  22. package/dist/federation/routing-engine.js.map +1 -0
  23. package/dist/federation/trust.d.ts +39 -0
  24. package/dist/federation/trust.d.ts.map +1 -0
  25. package/dist/federation/trust.js +64 -0
  26. package/dist/federation/trust.js.map +1 -0
  27. package/dist/index.d.ts +60 -2
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +217 -18
  30. package/dist/index.js.map +1 -1
  31. package/dist/ipc/ipc-server.d.ts +21 -0
  32. package/dist/ipc/ipc-server.d.ts.map +1 -0
  33. package/dist/ipc/ipc-server.js +173 -0
  34. package/dist/ipc/ipc-server.js.map +1 -0
  35. package/dist/jsonrpc/mail-server.d.ts +45 -0
  36. package/dist/jsonrpc/mail-server.d.ts.map +1 -0
  37. package/dist/jsonrpc/mail-server.js +284 -0
  38. package/dist/jsonrpc/mail-server.js.map +1 -0
  39. package/dist/map/map-client.d.ts +91 -0
  40. package/dist/map/map-client.d.ts.map +1 -0
  41. package/dist/map/map-client.js +202 -0
  42. package/dist/map/map-client.js.map +1 -0
  43. package/dist/mcp/mcp-server.d.ts +23 -0
  44. package/dist/mcp/mcp-server.d.ts.map +1 -0
  45. package/dist/mcp/mcp-server.js +226 -0
  46. package/dist/mcp/mcp-server.js.map +1 -0
  47. package/dist/push/notifier.d.ts +49 -0
  48. package/dist/push/notifier.d.ts.map +1 -0
  49. package/dist/push/notifier.js +150 -0
  50. package/dist/push/notifier.js.map +1 -0
  51. package/dist/registry/warm-registry.d.ts +63 -0
  52. package/dist/registry/warm-registry.d.ts.map +1 -0
  53. package/dist/registry/warm-registry.js +173 -0
  54. package/dist/registry/warm-registry.js.map +1 -0
  55. package/dist/router/message-router.d.ts +44 -0
  56. package/dist/router/message-router.d.ts.map +1 -0
  57. package/dist/router/message-router.js +137 -0
  58. package/dist/router/message-router.js.map +1 -0
  59. package/dist/storage/interface.d.ts +31 -0
  60. package/dist/storage/interface.d.ts.map +1 -0
  61. package/dist/storage/interface.js +2 -0
  62. package/dist/storage/interface.js.map +1 -0
  63. package/dist/storage/memory.d.ts +28 -0
  64. package/dist/storage/memory.d.ts.map +1 -0
  65. package/dist/storage/memory.js +118 -0
  66. package/dist/storage/memory.js.map +1 -0
  67. package/dist/storage/sqlite.d.ts +35 -0
  68. package/dist/storage/sqlite.d.ts.map +1 -0
  69. package/dist/storage/sqlite.js +445 -0
  70. package/dist/storage/sqlite.js.map +1 -0
  71. package/dist/traceability/traceability.d.ts +29 -0
  72. package/dist/traceability/traceability.d.ts.map +1 -0
  73. package/dist/traceability/traceability.js +150 -0
  74. package/dist/traceability/traceability.js.map +1 -0
  75. package/dist/types.d.ts +261 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +3 -0
  78. package/dist/types.js.map +1 -0
  79. package/docs/DESIGN.md +1156 -0
  80. package/docs/PLAN.md +545 -0
  81. package/hooks/inbox-hook.mjs +119 -0
  82. package/hooks/register-hook.mjs +69 -0
  83. package/package.json +33 -25
  84. package/rules/agent-inbox.md +78 -0
  85. package/src/federation/address.ts +61 -0
  86. package/src/federation/connection-manager.ts +458 -0
  87. package/src/federation/delivery-queue.ts +222 -0
  88. package/src/federation/index.ts +6 -0
  89. package/src/federation/routing-engine.ts +188 -0
  90. package/src/federation/trust.ts +71 -0
  91. package/src/index.ts +299 -0
  92. package/src/ipc/ipc-server.ts +207 -0
  93. package/src/jsonrpc/mail-server.ts +356 -0
  94. package/src/map/map-client.ts +260 -0
  95. package/src/mcp/mcp-server.ts +272 -0
  96. package/src/push/notifier.ts +192 -0
  97. package/src/registry/warm-registry.ts +210 -0
  98. package/src/router/message-router.ts +175 -0
  99. package/src/storage/interface.ts +48 -0
  100. package/src/storage/memory.ts +145 -0
  101. package/src/storage/sqlite.ts +645 -0
  102. package/src/traceability/traceability.ts +183 -0
  103. package/src/types.ts +297 -0
  104. package/test/federation/address.test.ts +101 -0
  105. package/test/federation/connection-manager.test.ts +546 -0
  106. package/test/federation/delivery-queue.test.ts +159 -0
  107. package/test/federation/integration.test.ts +823 -0
  108. package/test/federation/routing-engine.test.ts +117 -0
  109. package/test/federation/sdk-integration.test.ts +748 -0
  110. package/test/federation/trust.test.ts +89 -0
  111. package/test/ipc-jsonrpc.test.ts +113 -0
  112. package/test/ipc-server.test.ts +197 -0
  113. package/test/mail-server.test.ts +208 -0
  114. package/test/map-client.test.ts +408 -0
  115. package/test/message-router.test.ts +184 -0
  116. package/test/push-notifier.test.ts +139 -0
  117. package/test/registry/warm-registry.test.ts +171 -0
  118. package/test/sqlite-storage.test.ts +243 -0
  119. package/test/storage.test.ts +196 -0
  120. package/test/traceability.test.ts +123 -0
  121. package/tsconfig.json +20 -0
  122. package/tsup.config.ts +10 -0
  123. package/vitest.config.ts +8 -0
  124. package/dist/index.d.mts +0 -2
  125. package/dist/index.mjs +0 -1
  126. package/dist/index.mjs.map +0 -1
package/CLAUDE.md ADDED
@@ -0,0 +1,113 @@
1
+ # CLAUDE.md — Agent Guide for agent-inbox
2
+
3
+ ## What this repo is
4
+
5
+ Agent Inbox is a MAP-native message router for multi-agent systems. It provides structured inbox/outbox semantics, threading, delivery tracking, and cross-system federation on top of MAP (Multi-Agent Protocol) transport.
6
+
7
+ ## Build and test
8
+
9
+ ```bash
10
+ npm install # Install dependencies
11
+ npm run build # TypeScript compile (tsc)
12
+ npm test # Run all tests (vitest)
13
+ npm run test:watch # Watch mode
14
+ ```
15
+
16
+ All tests use vitest. Run the full suite before committing — there are 210+ tests across 16 files. Tests run fast (<2s total).
17
+
18
+ ## Project layout
19
+
20
+ ```
21
+ src/
22
+ index.ts Entry point — wires storage, router, federation, IPC, MCP, MAP
23
+ types.ts All type definitions (Message, Agent, Federation types, etc.)
24
+ storage/interface.ts Storage interface (getAgent, putMessage, getInbox, etc.)
25
+ storage/memory.ts InMemoryStorage — Map-based, used in all tests
26
+ storage/sqlite.ts SQLiteStorage — persistent with FTS5 search
27
+ router/message-router.ts Core routing: resolveRecipients, normalizeContent, routeMessage
28
+ federation/
29
+ connection-manager.ts Manages MAP connections + federation peer links + queue flush
30
+ routing-engine.ts Table/broadcast/hierarchical routing strategies
31
+ delivery-queue.ts Offline message queue with TTL, retry, overflow policies
32
+ address.ts Parse "agent@system" addresses (parseAddress, isRemoteAddress)
33
+ trust.ts Allow-list federation trust (canConnect, canRoute stubs)
34
+ registry/warm-registry.ts Agent lifecycle: active → away → expired with TTL timers
35
+ traceability/traceability.ts Auto-create conversations/turns/threads from message events
36
+ ipc/ipc-server.ts UNIX socket server (NDJSON protocol)
37
+ map/map-client.ts MAP SDK wrapper (dynamic import, optional peer dependency)
38
+ mcp/mcp-server.ts MCP tool server (send_message, check_inbox, read_thread, list_agents)
39
+ jsonrpc/mail-server.ts MAP JSON-RPC mail methods
40
+ push/notifier.ts Push notification support
41
+
42
+ test/
43
+ federation/ Federation tests (connection-manager, routing, queue, address, trust, integration, sdk-integration)
44
+ registry/ Warm registry tests
45
+ *.test.ts Core tests (storage, router, traceability, IPC, mail-server, push)
46
+ ```
47
+
48
+ ## Key architecture concepts
49
+
50
+ ### Message flow
51
+
52
+ 1. Message comes in via IPC socket, MCP tool, or MAP connection
53
+ 2. `MessageRouter.routeMessage()` resolves recipients, normalizes content, stores the message
54
+ 3. Local recipients: message stored in their inbox via storage
55
+ 4. Remote recipients (`agent@system`): delegated to `ConnectionManager.route()`
56
+ 5. Federation sends via MAP SDK transport (or queues if peer is offline)
57
+ 6. Traceability layer auto-creates conversations/threads from events
58
+
59
+ ### Federation addressing
60
+
61
+ - `"bob"` — local agent
62
+ - `"bob@system-2"` — agent on a federated system
63
+ - `"@system-2"` — broadcast to system
64
+
65
+ Parsed by `parseAddress()` in `src/federation/address.ts`.
66
+
67
+ ### Storage interface
68
+
69
+ All storage operations go through `Storage` interface (`src/storage/interface.ts`). Two implementations: `InMemoryStorage` (tests + ephemeral) and `SQLiteStorage` (persistent). Tests always use `InMemoryStorage`.
70
+
71
+ ### MAP SDK is optional
72
+
73
+ The `@multi-agent-protocol/sdk` is a peer dependency loaded dynamically in `src/map/map-client.ts`. Agent Inbox works without it (IPC + MCP only, no MAP transport). The SDK class is injected into `ConnectionManager` when available.
74
+
75
+ ### Event-driven internals
76
+
77
+ Components communicate via `EventEmitter`. Key events:
78
+ - `message.created` — emitted by router, consumed by traceability
79
+ - `federation.route` — emitted when no transport, for testing
80
+ - `federation.message.received` — incoming federation message
81
+ - `federation.broadcast` — broadcast strategy fired
82
+ - `routing.updated` — routing table changed
83
+
84
+ ## Conventions
85
+
86
+ - **TypeScript strict mode**, ESM output
87
+ - **vitest** for all tests — no jest
88
+ - **No mocking frameworks** — tests use hand-rolled mocks and the `InMemoryStorage` directly
89
+ - IDs generated with `ulid` or `crypto.randomUUID()`
90
+ - Content normalization: string payloads auto-wrapped to `{ type: "text", text: "..." }`
91
+ - Federation tests use `MockMapServer` (in-process broker) in `test/federation/sdk-integration.test.ts`
92
+
93
+ ## Known design gaps
94
+
95
+ - **Broadcast/hierarchical routing strategies** are unreachable through `ConnectionManager.route()` for system-qualified addresses (`bob@system-2`). `resolveRoute()` always returns `addr.system` directly, never falling through to `handleUnknownRoute()`. Agent-only addresses that would trigger it are filtered by `isRemoteAddress()`. Documented in `test/federation/integration.test.ts` and `test/federation/sdk-integration.test.ts`.
96
+
97
+ ## Common tasks
98
+
99
+ ### Adding a new MCP tool
100
+ 1. Add tool definition in `src/mcp/mcp-server.ts`
101
+ 2. Implement handler that delegates to router/storage
102
+ 3. Add test in `test/` (currently no dedicated mcp test file — tools tested through integration)
103
+
104
+ ### Adding a new federation feature
105
+ 1. Types go in `src/types.ts`
106
+ 2. Logic in `src/federation/` (connection-manager, routing-engine, etc.)
107
+ 3. Unit test in `test/federation/`
108
+ 4. Integration test in `test/federation/integration.test.ts` or `test/federation/sdk-integration.test.ts`
109
+
110
+ ### Adding a new storage method
111
+ 1. Add to interface in `src/storage/interface.ts`
112
+ 2. Implement in both `memory.ts` and `sqlite.ts`
113
+ 3. Test in `test/storage.test.ts` and `test/sqlite-storage.test.ts`
package/README.md CHANGED
@@ -1 +1,195 @@
1
- # agent-inbox
1
+ # Agent Inbox
2
+
3
+ A MAP-native message router for multi-agent systems. Provides structured inbox/outbox semantics, message threading, delivery tracking, and cross-system federation on top of the [Multi-Agent Protocol](https://github.com/anthropics/multi-agent-protocol) transport layer.
4
+
5
+ Built to work with [claude-code-swarm](https://github.com/alexngai/claude-code-swarm) and any MAP-compatible agent framework.
6
+
7
+ ## What it does
8
+
9
+ - **Message routing** — Send messages between agents with `to`, `cc`, `bcc` semantics. Messages are stored in per-agent inboxes with delivery and read tracking.
10
+ - **Threading** — Messages can be grouped by `thread_tag` and linked via `in_reply_to` for conversation threading.
11
+ - **Traceability** — Auto-creates conversations, turns, and threads from messaging events following MAP's mail conventions.
12
+ - **Federation** — Route messages across independent systems via MAP federation. Supports configurable routing strategies (table, broadcast, hierarchical).
13
+ - **Multiple interfaces** — IPC (UNIX socket), MCP tools (stdio), MAP JSON-RPC, and push notifications.
14
+
15
+ ## Architecture
16
+
17
+ ```
18
+ Claude Code Session
19
+ |
20
+ Plugin (map-hook.mjs)
21
+ |
22
+ +-- spawn/done/trajectory --> MAP Sidecar (lifecycle)
23
+ |
24
+ +-- send/emit (messaging) --> Agent Inbox (routing + storage)
25
+ |
26
+ +-- Local delivery (same system)
27
+ +-- Federation (cross-system via MAP)
28
+ ```
29
+
30
+ Agent Inbox runs as an independent service alongside the MAP sidecar. The plugin dispatches messaging commands to Agent Inbox and lifecycle commands to the sidecar.
31
+
32
+ ## Quick start
33
+
34
+ ```bash
35
+ npm install
36
+ npm run build
37
+ npm start
38
+ ```
39
+
40
+ ### Environment variables
41
+
42
+ | Variable | Default | Description |
43
+ |----------|---------|-------------|
44
+ | `INBOX_SOCKET_PATH` | `~/.claude/agent-inbox/inbox.sock` | IPC socket path |
45
+ | `INBOX_SCOPE` | `default` | Default message scope |
46
+ | `INBOX_SYSTEM_ID` | auto-generated | System identity for federation |
47
+ | `MAP_SERVER_URL` | — | MAP server URL (optional) |
48
+ | `MAP_AGENT_NAME` | `agent-inbox` | Agent name for MAP connection |
49
+
50
+ ### As an MCP tool server
51
+
52
+ Agent Inbox exposes 4 MCP tools that agents can call directly:
53
+
54
+ | Tool | Description |
55
+ |------|-------------|
56
+ | `send_message` | Send a message to one or more agents (supports replies via `inReplyTo`) |
57
+ | `check_inbox` | Check an agent's inbox for unread messages (auto-registers the agent) |
58
+ | `read_thread` | Read all messages in a thread by `threadTag` |
59
+ | `list_agents` | List registered agents (local and optionally federated) |
60
+
61
+ ### IPC protocol
62
+
63
+ NDJSON over UNIX socket. Commands:
64
+
65
+ ```json
66
+ {"action": "send", "from": "alice", "to": "bob", "payload": "Hello"}
67
+ {"action": "notify", "event": {"type": "agent.spawn", "agent": {...}}}
68
+ {"action": "ping"}
69
+ ```
70
+
71
+ ### MAP JSON-RPC
72
+
73
+ When connected to a MAP server, Agent Inbox registers JSON-RPC methods:
74
+
75
+ - `mail/send` — Send a message
76
+ - `mail/inbox` — Check inbox
77
+ - `mail/thread` — Read a thread
78
+ - `mail/ack` — Acknowledge a message
79
+ - `mail/search` — Full-text search (requires SQLite storage)
80
+
81
+ ## Federation
82
+
83
+ Agents on different systems can message each other using `agent@system` addressing:
84
+
85
+ ```
86
+ alice@system-1 --> bob@system-2
87
+ ```
88
+
89
+ ### Configuration
90
+
91
+ Federation peers are configured explicitly:
92
+
93
+ ```typescript
94
+ await inbox.federate({
95
+ systemId: "partner-system",
96
+ url: "ws://partner.example.com:3001",
97
+ exposure: { agents: "all" },
98
+ });
99
+ ```
100
+
101
+ ### Routing strategies
102
+
103
+ | Strategy | Behavior |
104
+ |----------|----------|
105
+ | `table` (default) | In-memory routing table populated from peer exposure data. TTL-based expiry. |
106
+ | `broadcast` | Forward to all connected peers. First responder wins. |
107
+ | `hierarchical` | Local table first, then delegate to upstream hubs. |
108
+
109
+ ### Trust
110
+
111
+ Federation connections are gated by an allow-list. Only systems in `allowedServers` can establish federation links.
112
+
113
+ ### Delivery queue
114
+
115
+ Messages to offline peers are queued with configurable TTL, overflow policy, and retry strategy. Queues flush automatically on reconnect.
116
+
117
+ ## Storage
118
+
119
+ Two storage backends:
120
+
121
+ - **InMemoryStorage** — Default. Fast, no dependencies. Data lost on restart.
122
+ - **SQLiteStorage** — Persistent storage with FTS5 full-text search. Requires `better-sqlite3`.
123
+
124
+ ## Project structure
125
+
126
+ ```
127
+ src/
128
+ index.ts Entry point — wires all components
129
+ types.ts Core type definitions
130
+ storage/
131
+ interface.ts Storage interface
132
+ memory.ts In-memory implementation
133
+ sqlite.ts SQLite implementation (persistent + FTS5)
134
+ router/
135
+ message-router.ts Message routing: resolve recipients, local vs remote
136
+ federation/
137
+ connection-manager.ts MAP connections + federation peer management
138
+ routing-engine.ts Configurable routing (table/broadcast/hierarchical)
139
+ delivery-queue.ts Offline message queue with TTL + retry
140
+ address.ts Parse/resolve agent@system addresses
141
+ trust.ts Federation trust policies (allow-list)
142
+ registry/
143
+ warm-registry.ts Agent lifecycle: active/away/expired + TTL
144
+ traceability/
145
+ traceability.ts Auto-create conversations/turns/threads
146
+ ipc/
147
+ ipc-server.ts UNIX socket server (NDJSON protocol)
148
+ map/
149
+ map-client.ts MAP SDK connection wrapper
150
+ mcp/
151
+ mcp-server.ts MCP tool server (stdio transport)
152
+ jsonrpc/
153
+ mail-server.ts MAP JSON-RPC mail methods
154
+ push/
155
+ notifier.ts Push notification support
156
+ ```
157
+
158
+ ## Testing
159
+
160
+ ```bash
161
+ npm test # Run all tests
162
+ npm run test:watch # Watch mode
163
+ ```
164
+
165
+ 210 tests across 16 test files covering:
166
+
167
+ - Storage (in-memory + SQLite)
168
+ - Message routing and content normalization
169
+ - Traceability (auto-conversation/thread creation)
170
+ - IPC server (NDJSON protocol, concurrent clients)
171
+ - Federation (connection manager, routing engine, delivery queue, address parsing, trust)
172
+ - Federation integration (end-to-end multi-system scenarios)
173
+ - SDK integration (two-system tests with in-process mock MAP server)
174
+ - MAP JSON-RPC mail methods
175
+ - Warm agent registry lifecycle
176
+ - Push notifications
177
+
178
+ ## Development
179
+
180
+ ```bash
181
+ npm run dev # TypeScript watch mode
182
+ npm test # Run tests
183
+ npm run build # Production build
184
+ ```
185
+
186
+ Requires Node.js >= 18.
187
+
188
+ ## Further reading
189
+
190
+ - [docs/DESIGN.md](docs/DESIGN.md) — Detailed architecture and design decisions
191
+ - [docs/PLAN.md](docs/PLAN.md) — Implementation plan and phasing
192
+
193
+ ## License
194
+
195
+ MIT
@@ -0,0 +1,24 @@
1
+ import type { FederatedAddress } from "../types.js";
2
+ /**
3
+ * Parse a federated address string into its components.
4
+ *
5
+ * Formats:
6
+ * "agent-id" → { agent: "agent-id" } (local)
7
+ * "agent-id@system-id" → { agent: "agent-id", system: "system-id" } (federated)
8
+ * "@system-id" → { system: "system-id" } (broadcast to system)
9
+ * "agent-id@system/scope" → { agent: "agent-id", system: "system", scope: "scope" }
10
+ */
11
+ export declare function parseAddress(address: string): FederatedAddress;
12
+ /**
13
+ * Serialize a FederatedAddress back to string form.
14
+ */
15
+ export declare function formatAddress(addr: FederatedAddress): string;
16
+ /**
17
+ * Check if an address targets a remote system.
18
+ */
19
+ export declare function isRemoteAddress(addr: FederatedAddress): boolean;
20
+ /**
21
+ * Check if an address is a broadcast (no specific agent).
22
+ */
23
+ export declare function isBroadcastAddress(addr: FederatedAddress): boolean;
24
+ //# sourceMappingURL=address.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../../src/federation/address.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAqB9D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAS5D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAE/D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAElE"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Parse a federated address string into its components.
3
+ *
4
+ * Formats:
5
+ * "agent-id" → { agent: "agent-id" } (local)
6
+ * "agent-id@system-id" → { agent: "agent-id", system: "system-id" } (federated)
7
+ * "@system-id" → { system: "system-id" } (broadcast to system)
8
+ * "agent-id@system/scope" → { agent: "agent-id", system: "system", scope: "scope" }
9
+ */
10
+ export function parseAddress(address) {
11
+ const atIdx = address.indexOf("@");
12
+ if (atIdx === -1) {
13
+ // No @ — local address
14
+ return { agent: address };
15
+ }
16
+ const agent = atIdx > 0 ? address.slice(0, atIdx) : undefined;
17
+ const rest = address.slice(atIdx + 1);
18
+ // Check for scope separator (/)
19
+ const slashIdx = rest.indexOf("/");
20
+ if (slashIdx === -1) {
21
+ return { agent, system: rest };
22
+ }
23
+ return {
24
+ agent,
25
+ system: rest.slice(0, slashIdx),
26
+ scope: rest.slice(slashIdx + 1),
27
+ };
28
+ }
29
+ /**
30
+ * Serialize a FederatedAddress back to string form.
31
+ */
32
+ export function formatAddress(addr) {
33
+ let result = addr.agent ?? "";
34
+ if (addr.system) {
35
+ result += `@${addr.system}`;
36
+ if (addr.scope) {
37
+ result += `/${addr.scope}`;
38
+ }
39
+ }
40
+ return result;
41
+ }
42
+ /**
43
+ * Check if an address targets a remote system.
44
+ */
45
+ export function isRemoteAddress(addr) {
46
+ return addr.system !== undefined;
47
+ }
48
+ /**
49
+ * Check if an address is a broadcast (no specific agent).
50
+ */
51
+ export function isBroadcastAddress(addr) {
52
+ return addr.system !== undefined && addr.agent === undefined;
53
+ }
54
+ //# sourceMappingURL=address.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address.js","sourceRoot":"","sources":["../../src/federation/address.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,uBAAuB;QACvB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAC5B,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9D,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAEtC,gCAAgC;IAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACjC,CAAC;IAED,OAAO;QACL,KAAK;QACL,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;QAC/B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;KAChC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,IAAsB;IAClD,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC9B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAsB;IACpD,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAsB;IACvD,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,118 @@
1
+ import { EventEmitter } from "node:events";
2
+ import type { FederationConfig, FederationLink, FederationPeerConfig, Message, SystemId } from "../types.js";
3
+ import type { MapAgentConnectionClass } from "../map/map-client.js";
4
+ import { RoutingEngine } from "./routing-engine.js";
5
+ import { DeliveryQueue } from "./delivery-queue.js";
6
+ import { TrustManager } from "./trust.js";
7
+ export interface DeliveryResult {
8
+ delivered: boolean;
9
+ peerId?: string;
10
+ queued?: boolean;
11
+ error?: string;
12
+ }
13
+ /**
14
+ * Callback for handling incoming federation messages.
15
+ * Wired to router.routeMessage() by index.ts.
16
+ */
17
+ export type IncomingMessageHandler = (incoming: {
18
+ from: string;
19
+ peerId: string;
20
+ payload: unknown;
21
+ meta?: Record<string, unknown>;
22
+ }) => void;
23
+ /**
24
+ * Manages MAP connections and federation peer links.
25
+ *
26
+ * Coordinates routing, delivery queuing, and trust enforcement
27
+ * for cross-system messaging. When an SDK connect function is provided,
28
+ * opens real MAP connections to federation peers for actual message transport.
29
+ */
30
+ export declare class ConnectionManager {
31
+ private events;
32
+ private config;
33
+ private peers;
34
+ private connections;
35
+ private systemId;
36
+ private sdkClass;
37
+ private onIncoming;
38
+ readonly routing: RoutingEngine;
39
+ readonly queue: DeliveryQueue;
40
+ readonly trust: TrustManager;
41
+ constructor(events: EventEmitter, config?: FederationConfig, opts?: {
42
+ sdkClass?: MapAgentConnectionClass;
43
+ onIncomingMessage?: IncomingMessageHandler;
44
+ });
45
+ /**
46
+ * Get the resolved system ID for this Agent Inbox instance.
47
+ */
48
+ getSystemId(): SystemId;
49
+ /**
50
+ * Establish federation with a peer. Uses MAP federation/connect protocol.
51
+ * If an SDK class was injected, opens a real MAP connection to the peer.
52
+ * Returns the federation link, or throws if trust check fails.
53
+ */
54
+ federate(peer: FederationPeerConfig): Promise<FederationLink>;
55
+ /**
56
+ * Disconnect from a federation peer.
57
+ * Closes the real MAP connection if one exists.
58
+ */
59
+ disconnect(peerId: string): Promise<void>;
60
+ /**
61
+ * Route a message to the correct federation peer.
62
+ * Resolves the address, checks trust, and delivers or queues.
63
+ * If a real connection exists, sends via conn.send(); otherwise emits event.
64
+ */
65
+ route(message: Message): Promise<DeliveryResult>;
66
+ /**
67
+ * Send a message to a peer via real connection or event emission.
68
+ * Returns true if send succeeded (or event was emitted).
69
+ */
70
+ private sendToPeer;
71
+ /**
72
+ * Handle an incoming message from a federation peer connection.
73
+ * Delegates to the injected message handler (wired to router.routeMessage).
74
+ */
75
+ private handlePeerMessage;
76
+ /**
77
+ * Handle routing to an unknown agent. Behavior depends on strategy.
78
+ */
79
+ private handleUnknownRoute;
80
+ /**
81
+ * Get all federation peer links.
82
+ */
83
+ getPeers(): FederationLink[];
84
+ /**
85
+ * Get only connected peers.
86
+ */
87
+ getConnectedPeers(): FederationLink[];
88
+ /**
89
+ * Get a specific peer link.
90
+ */
91
+ getPeer(peerId: string): FederationLink | undefined;
92
+ /**
93
+ * Check if a peer is connected.
94
+ */
95
+ isConnected(peerId: string): boolean;
96
+ /**
97
+ * Check if a real MAP SDK connection exists for a peer.
98
+ */
99
+ hasTransport(peerId: string): boolean;
100
+ /**
101
+ * Clean up all state. Call on shutdown.
102
+ */
103
+ destroy(): Promise<void>;
104
+ /**
105
+ * Resolve the system ID using tiered precedence:
106
+ * 1. Explicit config (INBOX_SYSTEM_ID)
107
+ * 2. Auto-generated (persisted to file for stability across restarts)
108
+ *
109
+ * Note: Tier 2 (MAP systemInfo) is handled after MAP connection is established.
110
+ */
111
+ private resolveSystemId;
112
+ /**
113
+ * Update system ID from MAP server's systemInfo (Tier 2).
114
+ * Only used if no explicit config was set.
115
+ */
116
+ updateSystemIdFromMap(mapSystemName: string): void;
117
+ }
118
+ //# sourceMappingURL=connection-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-manager.d.ts","sourceRoot":"","sources":["../../src/federation/connection-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,OAAO,KAAK,EAEV,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,OAAO,EACP,QAAQ,EACT,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAEV,uBAAuB,EAExB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1C,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,QAAQ,EAAE;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,KAAK,IAAI,CAAC;AAEX;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAW1B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IAXhB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,WAAW,CAAoC;IACvD,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,UAAU,CAAgC;IAClD,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;gBAGnB,MAAM,EAAE,YAAY,EACpB,MAAM,GAAE,gBAAqB,EACrC,IAAI,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,uBAAuB,CAAC;QACnC,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;KAC5C;IA6BH;;OAEG;IACH,WAAW,IAAI,QAAQ;IAIvB;;;;OAIG;IACG,QAAQ,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAyDnE;;;OAGG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB/C;;;;OAIG;IACG,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IA6CtD;;;OAGG;YACW,UAAU;IAkCxB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAazB;;OAEG;YACW,kBAAkB;IA0DhC;;OAEG;IACH,QAAQ,IAAI,cAAc,EAAE;IAI5B;;OAEG;IACH,iBAAiB,IAAI,cAAc,EAAE;IAMrC;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAInD;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIpC;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIrC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB9B;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAgCvB;;;OAGG;IACH,qBAAqB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;CAKnD"}