agent-relay 2.0.19 → 2.0.21

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 (142) hide show
  1. package/CHANGELOG.md +217 -24
  2. package/bin/relay-pty-darwin-arm64 +0 -0
  3. package/bin/relay-pty-darwin-x64 +0 -0
  4. package/bin/relay-pty-linux-x64 +0 -0
  5. package/dist/dashboard/out/404.html +1 -1
  6. package/dist/dashboard/out/app/onboarding.html +1 -1
  7. package/dist/dashboard/out/app/onboarding.txt +1 -1
  8. package/dist/dashboard/out/app.html +1 -1
  9. package/dist/dashboard/out/app.txt +1 -1
  10. package/dist/dashboard/out/cloud/link.html +1 -1
  11. package/dist/dashboard/out/cloud/link.txt +1 -1
  12. package/dist/dashboard/out/complete-profile.html +1 -1
  13. package/dist/dashboard/out/complete-profile.txt +1 -1
  14. package/dist/dashboard/out/connect-repos.html +1 -1
  15. package/dist/dashboard/out/connect-repos.txt +1 -1
  16. package/dist/dashboard/out/history.html +1 -1
  17. package/dist/dashboard/out/history.txt +1 -1
  18. package/dist/dashboard/out/index.html +1 -1
  19. package/dist/dashboard/out/index.txt +1 -1
  20. package/dist/dashboard/out/login.html +1 -1
  21. package/dist/dashboard/out/login.txt +1 -1
  22. package/dist/dashboard/out/metrics.html +1 -1
  23. package/dist/dashboard/out/metrics.txt +1 -1
  24. package/dist/dashboard/out/pricing.html +1 -1
  25. package/dist/dashboard/out/pricing.txt +1 -1
  26. package/dist/dashboard/out/providers/setup/claude.html +1 -1
  27. package/dist/dashboard/out/providers/setup/claude.txt +1 -1
  28. package/dist/dashboard/out/providers/setup/codex.html +1 -1
  29. package/dist/dashboard/out/providers/setup/codex.txt +1 -1
  30. package/dist/dashboard/out/providers/setup/cursor.html +1 -1
  31. package/dist/dashboard/out/providers/setup/cursor.txt +1 -1
  32. package/dist/dashboard/out/providers.html +1 -1
  33. package/dist/dashboard/out/providers.txt +1 -1
  34. package/dist/dashboard/out/signup.html +1 -1
  35. package/dist/dashboard/out/signup.txt +1 -1
  36. package/package.json +23 -17
  37. package/packages/api-types/package.json +2 -2
  38. package/packages/bridge/dist/spawner.d.ts +2 -0
  39. package/packages/bridge/dist/spawner.js +76 -24
  40. package/packages/bridge/package.json +8 -8
  41. package/packages/cli-tester/README.md +277 -0
  42. package/packages/cli-tester/dist/index.d.ts +21 -0
  43. package/packages/cli-tester/dist/index.js +21 -0
  44. package/packages/cli-tester/dist/utils/credential-check.d.ts +56 -0
  45. package/packages/cli-tester/dist/utils/credential-check.js +230 -0
  46. package/packages/cli-tester/dist/utils/socket-client.d.ts +76 -0
  47. package/packages/cli-tester/dist/utils/socket-client.js +153 -0
  48. package/packages/cli-tester/docker/entrypoint.sh +58 -0
  49. package/packages/cli-tester/package.json +32 -0
  50. package/packages/cli-tester/scripts/clear-auth.sh +101 -0
  51. package/packages/cli-tester/scripts/inject-message.sh +42 -0
  52. package/packages/cli-tester/scripts/start.sh +71 -0
  53. package/packages/cli-tester/scripts/test-cli.sh +56 -0
  54. package/packages/cli-tester/scripts/test-full-spawn.sh +238 -0
  55. package/packages/cli-tester/scripts/test-registration.sh +182 -0
  56. package/packages/cli-tester/scripts/test-setup-flow.sh +202 -0
  57. package/packages/cli-tester/scripts/test-spawn.sh +140 -0
  58. package/packages/cli-tester/scripts/test-with-daemon.sh +247 -0
  59. package/packages/cli-tester/scripts/verify-auth.sh +112 -0
  60. package/packages/cloud/package.json +6 -6
  61. package/packages/config/dist/cli-auth-config.js +65 -0
  62. package/packages/config/package.json +2 -2
  63. package/packages/continuity/package.json +1 -1
  64. package/packages/daemon/dist/router.js +4 -4
  65. package/packages/daemon/dist/server.js +38 -19
  66. package/packages/daemon/dist/spawn-manager.d.ts +4 -0
  67. package/packages/daemon/dist/spawn-manager.js +2 -0
  68. package/packages/daemon/package.json +12 -12
  69. package/packages/dashboard/dist/server.js +4 -0
  70. package/packages/dashboard/package.json +14 -14
  71. package/packages/dashboard/ui-dist/404.html +1 -1
  72. package/packages/dashboard/ui-dist/app/onboarding.html +1 -1
  73. package/packages/dashboard/ui-dist/app/onboarding.txt +1 -1
  74. package/packages/dashboard/ui-dist/app.html +1 -1
  75. package/packages/dashboard/ui-dist/app.txt +1 -1
  76. package/packages/dashboard/ui-dist/cloud/link.html +1 -1
  77. package/packages/dashboard/ui-dist/cloud/link.txt +1 -1
  78. package/packages/dashboard/ui-dist/complete-profile.html +1 -1
  79. package/packages/dashboard/ui-dist/complete-profile.txt +1 -1
  80. package/packages/dashboard/ui-dist/connect-repos.html +1 -1
  81. package/packages/dashboard/ui-dist/connect-repos.txt +1 -1
  82. package/packages/dashboard/ui-dist/history.html +1 -1
  83. package/packages/dashboard/ui-dist/history.txt +1 -1
  84. package/packages/dashboard/ui-dist/index.html +1 -1
  85. package/packages/dashboard/ui-dist/index.txt +1 -1
  86. package/packages/dashboard/ui-dist/login.html +1 -1
  87. package/packages/dashboard/ui-dist/login.txt +1 -1
  88. package/packages/dashboard/ui-dist/metrics.html +1 -1
  89. package/packages/dashboard/ui-dist/metrics.txt +1 -1
  90. package/packages/dashboard/ui-dist/pricing.html +1 -1
  91. package/packages/dashboard/ui-dist/pricing.txt +1 -1
  92. package/packages/dashboard/ui-dist/providers/setup/claude.html +1 -1
  93. package/packages/dashboard/ui-dist/providers/setup/claude.txt +1 -1
  94. package/packages/dashboard/ui-dist/providers/setup/codex.html +1 -1
  95. package/packages/dashboard/ui-dist/providers/setup/codex.txt +1 -1
  96. package/packages/dashboard/ui-dist/providers/setup/cursor.html +1 -1
  97. package/packages/dashboard/ui-dist/providers/setup/cursor.txt +1 -1
  98. package/packages/dashboard/ui-dist/providers.html +1 -1
  99. package/packages/dashboard/ui-dist/providers.txt +1 -1
  100. package/packages/dashboard/ui-dist/signup.html +1 -1
  101. package/packages/dashboard/ui-dist/signup.txt +1 -1
  102. package/packages/dashboard-server/dist/server.js +4 -0
  103. package/packages/dashboard-server/package.json +12 -12
  104. package/packages/hooks/package.json +4 -4
  105. package/packages/mcp/package.json +2 -2
  106. package/packages/memory/package.json +2 -2
  107. package/packages/policy/package.json +2 -2
  108. package/packages/protocol/package.json +1 -1
  109. package/packages/resiliency/package.json +1 -1
  110. package/packages/sdk/README.md +512 -58
  111. package/packages/sdk/dist/client.d.ts +135 -1
  112. package/packages/sdk/dist/client.js +338 -0
  113. package/packages/sdk/dist/index.d.ts +2 -1
  114. package/packages/sdk/dist/index.js +2 -0
  115. package/packages/sdk/dist/logs.d.ts +61 -0
  116. package/packages/sdk/dist/logs.js +95 -0
  117. package/packages/sdk/dist/protocol/index.d.ts +1 -1
  118. package/packages/sdk/dist/protocol/types.d.ts +186 -1
  119. package/packages/sdk/package.json +3 -3
  120. package/packages/spawner/package.json +2 -2
  121. package/packages/state/package.json +1 -1
  122. package/packages/storage/dist/sqlite-adapter.js +2 -0
  123. package/packages/storage/package.json +2 -2
  124. package/packages/telemetry/package.json +1 -1
  125. package/packages/trajectory/package.json +2 -2
  126. package/packages/user-directory/package.json +2 -2
  127. package/packages/utils/package.json +1 -1
  128. package/packages/wrapper/dist/base-wrapper.js +27 -10
  129. package/packages/wrapper/dist/relay-pty-orchestrator.js +16 -16
  130. package/packages/wrapper/dist/tmux-wrapper.js +16 -0
  131. package/packages/wrapper/package.json +7 -7
  132. package/scripts/hooks/install.sh +16 -0
  133. package/scripts/hooks/pre-commit +60 -0
  134. package/specs/PRIMITIVES_ROADMAP.md +2154 -0
  135. /package/dist/dashboard/out/_next/static/{cREcLZyPb-5NyVZje0Qfe → 7MZPqYkVGw3EGzVBkVmY9}/_buildManifest.js +0 -0
  136. /package/dist/dashboard/out/_next/static/{cREcLZyPb-5NyVZje0Qfe → 7MZPqYkVGw3EGzVBkVmY9}/_ssgManifest.js +0 -0
  137. /package/packages/dashboard/ui-dist/_next/static/{N3ajGnJqRESKyCjDvyU52 → 7MZPqYkVGw3EGzVBkVmY9}/_buildManifest.js +0 -0
  138. /package/packages/dashboard/ui-dist/_next/static/{N3ajGnJqRESKyCjDvyU52 → 7MZPqYkVGw3EGzVBkVmY9}/_ssgManifest.js +0 -0
  139. /package/packages/dashboard/ui-dist/_next/static/{UQiyWwBxIP-9it3GYVBDL → iJ3Uiz3IrqUJL7IxKZHiV}/_buildManifest.js +0 -0
  140. /package/packages/dashboard/ui-dist/_next/static/{UQiyWwBxIP-9it3GYVBDL → iJ3Uiz3IrqUJL7IxKZHiV}/_ssgManifest.js +0 -0
  141. /package/packages/dashboard/ui-dist/_next/static/{cREcLZyPb-5NyVZje0Qfe → l-jd878zUJ_IlraqEWMZc}/_buildManifest.js +0 -0
  142. /package/packages/dashboard/ui-dist/_next/static/{cREcLZyPb-5NyVZje0Qfe → l-jd878zUJ_IlraqEWMZc}/_ssgManifest.js +0 -0
@@ -1,15 +1,45 @@
1
1
  # @agent-relay/sdk
2
2
 
3
- Dead simple agent-to-agent communication.
3
+ **Primitives for building powerful multi-agent swarms.**
4
+
5
+ Unlike frameworks that impose specific orchestration patterns, Agent Relay provides flexible communication primitives that let you build any swarm architecture. Whether you want hierarchical coordination, parallel fan-out, consensus-based decisions, or self-organizing agents—the SDK gives you the building blocks.
6
+
7
+ ## Why Agent Relay for Swarms?
8
+
9
+ | Framework | Approach | Limitation |
10
+ |-----------|----------|------------|
11
+ | OpenAI Agents | Handoff-based routing | Prescriptive flow control |
12
+ | Swarms.ai | Pre-built swarm types | Configuration-heavy |
13
+ | Strands | Self-organizing swarms | AWS ecosystem lock-in |
14
+ | **Agent Relay** | **Communication primitives** | **You design the orchestration** |
15
+
16
+ ### What You Can Build
17
+
18
+ - **Hierarchical swarms** - Lead + specialist workers with task delegation
19
+ - **Parallel execution** - Fan-out to workers, fan-in results
20
+ - **Pipeline workflows** - Sequential processing across agents
21
+ - **Consensus decisions** - Group voting on critical choices
22
+ - **Self-organizing teams** - Dynamic task claiming via channels
23
+ - **Supervised agents** - Shadow monitoring for QA and oversight
24
+
25
+ See [examples/SWARM_PATTERNS.md](./examples/SWARM_PATTERNS.md) for detailed patterns and [examples/SWARM_CAPABILITIES.md](./examples/SWARM_CAPABILITIES.md) for how primitives map to swarm capabilities.
4
26
 
5
27
  ## Install
6
28
 
7
29
  ```bash
8
- npm install @agent-relay/sdk @agent-relay/daemon
30
+ npm install @agent-relay/sdk
31
+ ```
32
+
33
+ For standalone mode (in-process daemon), also install:
34
+
35
+ ```bash
36
+ npm install @agent-relay/daemon
9
37
  ```
10
38
 
11
39
  ## Quick Start
12
40
 
41
+ ### Standalone Mode (Zero Config)
42
+
13
43
  ```typescript
14
44
  import { createRelay } from '@agent-relay/sdk';
15
45
 
@@ -32,9 +62,7 @@ alice.sendMessage('Bob', 'Hello!');
32
62
  await relay.stop();
33
63
  ```
34
64
 
35
- That's it. No daemon to start, no config files, no setup.
36
-
37
- ## Even Simpler: Two Agents
65
+ ### Even Simpler: Two Agents
38
66
 
39
67
  ```typescript
40
68
  import { createPair } from '@agent-relay/sdk';
@@ -47,125 +75,551 @@ alice.sendMessage('bob', 'Hey!');
47
75
  await stop();
48
76
  ```
49
77
 
78
+ ### External Daemon Mode
79
+
80
+ If you're running `agent-relay up` separately:
81
+
82
+ ```typescript
83
+ import { RelayClient } from '@agent-relay/sdk';
84
+
85
+ const client = new RelayClient({
86
+ agentName: 'MyAgent',
87
+ socketPath: '/tmp/agent-relay.sock', // optional, this is the default
88
+ });
89
+
90
+ await client.connect();
91
+ client.sendMessage('OtherAgent', 'Hello!');
92
+ ```
93
+
50
94
  ## Features
51
95
 
52
96
  | Feature | Description |
53
97
  |---------|-------------|
54
- | **Zero config** | Just import and go |
98
+ | **Zero config** | Just import and go with standalone mode |
55
99
  | **Auto-reconnect** | Handles disconnections automatically |
56
100
  | **Message deduplication** | No duplicate deliveries |
57
- | **Sync messaging** | Wait for acknowledgment |
101
+ | **Sync messaging** | Wait for acknowledgment with `sendAndWait()` |
58
102
  | **Broadcast** | Send to all agents with `*` |
59
103
  | **Channels** | Group messaging with `#channel` |
104
+ | **Pub/Sub** | Topic-based subscriptions |
105
+ | **Agent spawning** | Spawn and release worker agents |
106
+ | **Shadow agents** | Monitor another agent's communication |
107
+ | **Consensus** | Distributed decision-making (external daemon only) |
108
+ | **Monitoring** | Health, metrics, agent discovery |
60
109
 
61
110
  ## API Reference
62
111
 
63
- ### createRelay(config?)
112
+ ### Core Messaging
64
113
 
65
- Creates a standalone relay with an in-process daemon.
114
+ #### sendMessage(to, body, kind?, data?, thread?)
115
+
116
+ Send a message to another agent.
66
117
 
67
118
  ```typescript
68
- const relay = await createRelay({
69
- socketPath: '/tmp/my-relay.sock', // Optional custom socket
70
- quiet: true, // Suppress logs (default: true)
71
- });
119
+ // Simple message
120
+ client.sendMessage('Bob', 'Hello!');
72
121
 
73
- // Create clients
74
- const agent = await relay.client('MyAgent');
122
+ // With message kind and data
123
+ client.sendMessage('Bob', 'Task complete', 'action', { taskId: 123 });
75
124
 
76
- // Stop everything
77
- await relay.stop();
125
+ // In a thread
126
+ client.sendMessage('Bob', 'Follow-up', 'message', undefined, 'thread-123');
78
127
  ```
79
128
 
80
- ### createPair(name1, name2, config?)
129
+ #### sendAndWait(to, body, options?)
81
130
 
82
- Shortcut to create two connected agents.
131
+ Send and wait for acknowledgment. Useful for ensuring delivery.
83
132
 
84
133
  ```typescript
85
- const { alice, bob, stop } = await createPair('alice', 'bob');
134
+ const ack = await client.sendAndWait('Bob', 'Important message', {
135
+ timeoutMs: 5000, // default: 30000
136
+ });
137
+ console.log('Acknowledged:', ack);
86
138
  ```
87
139
 
88
- ### RelayClient
140
+ #### broadcast(body, kind?, data?)
89
141
 
90
- The client for agent communication.
142
+ Send to all connected agents.
91
143
 
92
144
  ```typescript
93
- // Send messages
94
- client.sendMessage('OtherAgent', 'Hello!');
95
- client.sendMessage('#general', 'Channel message');
96
- client.sendMessage('*', 'Broadcast to everyone');
145
+ client.broadcast('System notice to everyone');
146
+ ```
147
+
148
+ #### onMessage
97
149
 
98
- // Wait for acknowledgment
99
- const ack = await client.sendAndWait('OtherAgent', 'Important message');
150
+ Callback for incoming messages.
100
151
 
101
- // Receive messages
152
+ ```typescript
102
153
  client.onMessage = (from, payload, messageId, meta, originalTo) => {
103
154
  console.log(`${from}: ${payload.body}`);
104
155
 
105
- // Check if broadcast
156
+ // payload.kind: 'message' | 'action' | 'state' | 'thinking'
157
+ // payload.data: optional structured data
158
+ // payload.thread: optional thread ID
159
+
160
+ // Check if it was a broadcast
106
161
  if (originalTo === '*') {
107
162
  console.log('This was a broadcast');
108
163
  }
109
164
  };
165
+ ```
110
166
 
111
- // Connection state changes
112
- client.onStateChange = (state) => {
113
- // 'DISCONNECTED' | 'CONNECTING' | 'HANDSHAKING' | 'READY' | 'BACKOFF'
114
- };
167
+ ### Channels
115
168
 
116
- // Disconnect
117
- client.disconnect();
169
+ #### joinChannel(channel, displayName?)
170
+
171
+ ```typescript
172
+ client.joinChannel('#general');
173
+ client.joinChannel('#team', 'Alice (Lead)'); // with display name
118
174
  ```
119
175
 
120
- ## Using with External Daemon
176
+ #### leaveChannel(channel, reason?)
121
177
 
122
- If you're running `agent-relay up` separately (e.g., for the dashboard), use the client directly:
178
+ ```typescript
179
+ client.leaveChannel('#general');
180
+ client.leaveChannel('#team', 'Signing off');
181
+ ```
182
+
183
+ #### sendChannelMessage(channel, body, options?)
123
184
 
124
185
  ```typescript
125
- import { RelayClient } from '@agent-relay/sdk';
186
+ // Simple message
187
+ client.sendChannelMessage('#general', 'Hello team!');
126
188
 
127
- const client = new RelayClient({
128
- agentName: 'MyAgent',
129
- socketPath: '/tmp/agent-relay.sock',
189
+ // With mentions and thread
190
+ client.sendChannelMessage('#general', 'Check this out', {
191
+ thread: 'discussion-123',
192
+ mentions: ['Bob', 'Charlie'],
193
+ attachments: [{ type: 'file', name: 'report.pdf', url: '...' }],
130
194
  });
195
+ ```
131
196
 
132
- await client.connect();
133
- client.sendMessage('OtherAgent', 'Hello!');
197
+ #### onChannelMessage
198
+
199
+ ```typescript
200
+ client.onChannelMessage = (from, channel, body, envelope) => {
201
+ console.log(`[${channel}] ${from}: ${body}`);
202
+ // envelope contains full message details (thread, mentions, etc.)
203
+ };
134
204
  ```
135
205
 
136
- ## Advanced: Channels
206
+ #### Admin Channel Operations
137
207
 
138
208
  ```typescript
139
- // Join a channel
140
- client.joinChannel('#general');
209
+ // Add a member to a channel (they don't need to be connected)
210
+ client.adminJoinChannel('#team', 'NewMember');
141
211
 
142
- // Send to channel
143
- client.sendChannelMessage('#general', 'Hello team!');
212
+ // Remove a member from a channel
213
+ client.adminRemoveMember('#team', 'FormerMember');
214
+ ```
144
215
 
145
- // Receive channel messages
146
- client.onChannelMessage = (from, channel, body, envelope) => {
147
- console.log(`[${channel}] ${from}: ${body}`);
216
+ ### Pub/Sub
217
+
218
+ Subscribe to topics for filtered message delivery.
219
+
220
+ ```typescript
221
+ // Subscribe to a topic
222
+ client.subscribe('builds');
223
+ client.subscribe('deployments');
224
+
225
+ // Messages to that topic will be delivered via onMessage
226
+ client.onMessage = (from, payload) => {
227
+ if (payload.data?.topic === 'builds') {
228
+ console.log('Build notification:', payload.body);
229
+ }
148
230
  };
149
231
 
150
- // Leave channel
151
- client.leaveChannel('#general');
232
+ // Unsubscribe
233
+ client.unsubscribe('builds');
234
+ ```
235
+
236
+ ### Agent Spawning
237
+
238
+ Spawn and manage worker agents programmatically.
239
+
240
+ ```typescript
241
+ // Spawn a new agent
242
+ const result = await client.spawn({
243
+ name: 'Worker1',
244
+ cli: 'claude', // claude, codex, gemini, etc.
245
+ task: 'Process the data files',
246
+ cwd: '/path/to/workdir', // optional
247
+ });
248
+
249
+ if (result.success) {
250
+ console.log('Worker spawned!');
251
+ }
252
+
253
+ // Release (terminate) an agent
254
+ const releaseResult = await client.release('Worker1');
152
255
  ```
153
256
 
154
- ## Advanced: Shadow Agents
257
+ #### Spawn as Shadow
258
+
259
+ ```typescript
260
+ // Spawn an agent that shadows another
261
+ await client.spawn({
262
+ name: 'Reviewer',
263
+ cli: 'claude',
264
+ task: 'Review code changes',
265
+ shadowOf: 'Developer',
266
+ shadowSpeakOn: ['error', 'complete'],
267
+ });
268
+ ```
155
269
 
156
- Monitor another agent's communication:
270
+ ### Shadow Agents
271
+
272
+ Monitor another agent's communication without them knowing.
157
273
 
158
274
  ```typescript
159
275
  // Bind as shadow to see all messages to/from PrimaryAgent
160
276
  client.bindAsShadow('PrimaryAgent', {
161
- receiveIncoming: true,
162
- receiveOutgoing: true,
277
+ receiveIncoming: true, // see messages sent TO the primary
278
+ receiveOutgoing: true, // see messages sent BY the primary
279
+ speakOn: ['error'], // triggers that allow shadow to speak
163
280
  });
164
281
 
165
282
  // Unbind
166
283
  client.unbindAsShadow('PrimaryAgent');
167
284
  ```
168
285
 
286
+ ### Logging
287
+
288
+ Stream logs to the daemon (for dashboard display).
289
+
290
+ ```typescript
291
+ // Send log output
292
+ client.sendLog('Starting task...');
293
+ client.sendLog('Processing file 1 of 10');
294
+ client.sendLog('Error: File not found');
295
+ ```
296
+
297
+ ### Consensus (External Daemon Only)
298
+
299
+ Distributed decision-making across agents. **Note:** Consensus requires an external daemon - it's disabled in standalone mode.
300
+
301
+ #### Consensus Types
302
+
303
+ | Type | Description |
304
+ |------|-------------|
305
+ | `majority` | >50% agreement (default) |
306
+ | `supermajority` | >=2/3 agreement (configurable) |
307
+ | `unanimous` | 100% agreement required |
308
+ | `weighted` | Votes weighted by role/expertise |
309
+ | `quorum` | Minimum participation + majority |
310
+
311
+ #### Create a Proposal
312
+
313
+ ```typescript
314
+ client.createProposal({
315
+ title: 'Approve API design',
316
+ description: 'Should we proceed with the REST API design?',
317
+ participants: ['Developer', 'Reviewer', 'Lead'],
318
+ consensusType: 'majority',
319
+ timeoutMs: 300000, // 5 minutes, optional
320
+ threshold: 0.67, // for supermajority, optional
321
+ quorum: 2, // minimum votes, optional
322
+ });
323
+ ```
324
+
325
+ #### Vote on a Proposal
326
+
327
+ ```typescript
328
+ client.vote({
329
+ proposalId: 'prop_123_abc',
330
+ value: 'approve', // or 'reject', 'abstain'
331
+ reason: 'Looks good to me', // optional
332
+ });
333
+ ```
334
+
335
+ #### Receiving Proposals and Results
336
+
337
+ ```typescript
338
+ client.onMessage = (from, payload) => {
339
+ if (payload.data?._isConsensusMessage) {
340
+ console.log('Consensus message:', payload.body);
341
+ }
342
+ };
343
+ ```
344
+
345
+ ### Monitoring & Discovery
346
+
347
+ #### List Online Agents
348
+
349
+ ```typescript
350
+ const agents = await client.listAgents();
351
+ for (const agent of agents) {
352
+ console.log(`${agent.name} (${agent.cli}) - ${agent.idle ? 'idle' : 'active'}`);
353
+ }
354
+
355
+ // Filter options
356
+ const activeOnly = await client.listAgents({ includeIdle: false });
357
+ const projectAgents = await client.listAgents({ project: 'myproject' });
358
+ ```
359
+
360
+ #### Get System Health
361
+
362
+ ```typescript
363
+ const health = await client.getHealth();
364
+ console.log(`Health score: ${health.healthScore}/100`);
365
+ console.log(`Issues: ${health.issues.length}`);
366
+ console.log(`Recommendations:`, health.recommendations);
367
+
368
+ // Options
369
+ const health = await client.getHealth({
370
+ includeCrashes: true, // include crash history
371
+ includeAlerts: true, // include alerts
372
+ });
373
+ ```
374
+
375
+ #### Get Resource Metrics
376
+
377
+ ```typescript
378
+ const metrics = await client.getMetrics();
379
+
380
+ // System overview
381
+ console.log(`Heap used: ${metrics.system.heapUsed}`);
382
+ console.log(`Free memory: ${metrics.system.freeMemory}`);
383
+
384
+ // Per-agent metrics
385
+ for (const agent of metrics.agents) {
386
+ console.log(`${agent.name}: ${agent.rssBytes} bytes, ${agent.cpuPercent}% CPU`);
387
+ }
388
+
389
+ // Filter to specific agent
390
+ const workerMetrics = await client.getMetrics({ agent: 'Worker1' });
391
+ ```
392
+
393
+ #### Get Daemon Status
394
+
395
+ ```typescript
396
+ const status = await client.getStatus();
397
+ console.log(`Version: ${status.version}`);
398
+ console.log(`Uptime: ${status.uptime}ms`);
399
+ console.log(`Agents: ${status.agentCount}`);
400
+ ```
401
+
402
+ #### Get Inbox Messages
403
+
404
+ ```typescript
405
+ const messages = await client.getInbox({ limit: 10 });
406
+ for (const msg of messages) {
407
+ console.log(`From ${msg.from}: ${msg.body}`);
408
+ }
409
+
410
+ // Filter options
411
+ const unread = await client.getInbox({ unreadOnly: true });
412
+ const fromAlice = await client.getInbox({ from: 'Alice' });
413
+ const channelMsgs = await client.getInbox({ channel: '#general' });
414
+ ```
415
+
416
+ #### Read Agent Logs (File-based)
417
+
418
+ Logs are stored locally and can be read without a connection:
419
+
420
+ ```typescript
421
+ import { getLogs, listLoggedAgents } from '@agent-relay/sdk';
422
+
423
+ // List agents with logs
424
+ const agents = await listLoggedAgents();
425
+
426
+ // Get last 100 lines of a specific agent's logs
427
+ const result = await getLogs('Worker1', { lines: 100 });
428
+ if (result.found) {
429
+ console.log(result.content);
430
+ }
431
+ ```
432
+
433
+ ### Connection Management
434
+
435
+ #### State Changes
436
+
437
+ ```typescript
438
+ client.onStateChange = (state) => {
439
+ // 'DISCONNECTED' | 'CONNECTING' | 'HANDSHAKING' | 'READY' | 'BACKOFF'
440
+ console.log('State:', state);
441
+ };
442
+ ```
443
+
444
+ #### Error Handling
445
+
446
+ ```typescript
447
+ client.onError = (error) => {
448
+ console.error('Client error:', error.message);
449
+ };
450
+ ```
451
+
452
+ #### Manual Connection Control
453
+
454
+ ```typescript
455
+ // Disconnect gracefully
456
+ client.disconnect();
457
+
458
+ // Permanently destroy (prevents reconnection)
459
+ client.destroy();
460
+
461
+ // Check current state
462
+ console.log(client.state); // 'READY', 'DISCONNECTED', etc.
463
+ console.log(client.agentName);
464
+ console.log(client.currentSessionId);
465
+ ```
466
+
467
+ ## Standalone vs External Daemon
468
+
469
+ | Feature | Standalone | External Daemon |
470
+ |---------|------------|-----------------|
471
+ | Setup required | None | Run `agent-relay up` |
472
+ | Consensus | No | Yes |
473
+ | Cloud sync | No | Yes |
474
+ | Dashboard | No | Yes |
475
+ | Best for | Testing, simple scripts | Production, multi-machine |
476
+
477
+ ## Configuration Reference
478
+
479
+ ### RelayClient Options
480
+
481
+ ```typescript
482
+ const client = new RelayClient({
483
+ // Required
484
+ agentName: 'MyAgent',
485
+
486
+ // Optional
487
+ socketPath: '/tmp/agent-relay.sock', // default
488
+ entityType: 'agent', // 'agent' or 'user'
489
+ cli: 'claude', // CLI identifier
490
+ program: 'my-app', // program identifier
491
+ model: 'claude-3', // model identifier
492
+ task: 'My task', // task description
493
+ workingDirectory: '/path/to/work',
494
+ displayName: 'Alice', // for human users
495
+ avatarUrl: 'https://...',
496
+ quiet: false, // suppress console logs
497
+ reconnect: true, // auto-reconnect
498
+ maxReconnectAttempts: 10,
499
+ reconnectDelayMs: 1000,
500
+ reconnectMaxDelayMs: 30000,
501
+ });
502
+ ```
503
+
504
+ ### createRelay Options
505
+
506
+ ```typescript
507
+ const relay = await createRelay({
508
+ socketPath: '/tmp/my-relay.sock', // optional
509
+ quiet: true, // suppress logs (default: true)
510
+ });
511
+ ```
512
+
513
+ ## TypeScript Types
514
+
515
+ All types are exported for TypeScript users:
516
+
517
+ ```typescript
518
+ import type {
519
+ // Client
520
+ ClientState,
521
+ ClientConfig,
522
+ SyncOptions,
523
+
524
+ // Messages
525
+ SendPayload,
526
+ PayloadKind,
527
+ AckPayload,
528
+
529
+ // Channels
530
+ ChannelMessagePayload,
531
+ MessageAttachment,
532
+
533
+ // Spawning
534
+ SpawnPayload,
535
+ SpawnResultPayload,
536
+ ReleaseResultPayload,
537
+
538
+ // Monitoring
539
+ AgentInfo,
540
+ AgentMetrics,
541
+ HealthResponsePayload,
542
+ MetricsResponsePayload,
543
+ InboxMessage,
544
+
545
+ // Consensus
546
+ ConsensusType,
547
+ VoteValue,
548
+ CreateProposalOptions,
549
+ VoteOptions,
550
+ } from '@agent-relay/sdk';
551
+ ```
552
+
553
+ ## Building Swarms
554
+
555
+ The SDK provides primitives that map directly to swarm capabilities:
556
+
557
+ | SDK Primitive | Swarm Capability |
558
+ |---------------|------------------|
559
+ | `sendMessage()` | **Handoffs** - Transfer tasks between agents |
560
+ | `sendAndWait()` | **Synchronous handoffs** - Wait for task completion |
561
+ | `getInbox()` + session resume | **Continuity** - Recover state across disconnections |
562
+ | `createProposal()` / `vote()` | **Consensus** - Group decision-making |
563
+ | `channels` + state payloads | **Shared memory** - Distributed state |
564
+ | `listAgents()` | **Discovery** - Find available workers |
565
+ | `getMetrics()` / `getHealth()` | **Monitoring** - Auto-scaling decisions |
566
+ | `bindAsShadow()` | **Observation** - QA and oversight |
567
+ | `spawn()` / `release()` | **Dynamic teams** - Scale workers on demand |
568
+
569
+ ### Example: Hierarchical Swarm
570
+
571
+ ```typescript
572
+ const lead = new RelayClient({ agentName: 'Lead' });
573
+ await lead.connect();
574
+
575
+ // Spawn specialized workers
576
+ for (const role of ['Frontend', 'Backend', 'Tests']) {
577
+ await lead.spawn({
578
+ name: `${role}Worker`,
579
+ cli: 'claude',
580
+ task: `You are a ${role} specialist. Wait for tasks from Lead.`,
581
+ });
582
+ }
583
+
584
+ // Delegate work
585
+ lead.sendMessage('FrontendWorker', 'Build the login page UI');
586
+ lead.sendMessage('BackendWorker', 'Create the /auth API endpoint');
587
+ lead.sendMessage('TestsWorker', 'Write integration tests for auth');
588
+
589
+ // Collect results
590
+ const results = new Map();
591
+ lead.onMessage = (from, { body }) => {
592
+ results.set(from, body);
593
+ if (results.size === 3) console.log('All workers complete!');
594
+ };
595
+ ```
596
+
597
+ ### Example: Consensus Decision
598
+
599
+ ```typescript
600
+ // Create a proposal for group decision
601
+ client.createProposal({
602
+ title: 'API Design Choice',
603
+ description: 'Should we use GraphQL or REST?',
604
+ participants: ['Architect', 'FrontendLead', 'BackendLead'],
605
+ consensusType: 'majority',
606
+ timeoutMs: 300000,
607
+ });
608
+
609
+ // Participants vote
610
+ client.vote({
611
+ proposalId: 'prop_123',
612
+ value: 'approve',
613
+ reason: 'GraphQL fits our needs better',
614
+ });
615
+ ```
616
+
617
+ ### Learn More
618
+
619
+ - **[Swarm Patterns](./examples/SWARM_PATTERNS.md)** - 8 detailed patterns with code
620
+ - **[Swarm Capabilities](./examples/SWARM_CAPABILITIES.md)** - How primitives enable swarm features
621
+ - **[AgentSwarm](https://github.com/AgentWorkforce/agentswarm)** - Production orchestrator built on Agent Relay
622
+
169
623
  ## License
170
624
 
171
625
  MIT