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.
- package/CHANGELOG.md +217 -24
- package/bin/relay-pty-darwin-arm64 +0 -0
- package/bin/relay-pty-darwin-x64 +0 -0
- package/bin/relay-pty-linux-x64 +0 -0
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/app/onboarding.html +1 -1
- package/dist/dashboard/out/app/onboarding.txt +1 -1
- package/dist/dashboard/out/app.html +1 -1
- package/dist/dashboard/out/app.txt +1 -1
- package/dist/dashboard/out/cloud/link.html +1 -1
- package/dist/dashboard/out/cloud/link.txt +1 -1
- package/dist/dashboard/out/complete-profile.html +1 -1
- package/dist/dashboard/out/complete-profile.txt +1 -1
- package/dist/dashboard/out/connect-repos.html +1 -1
- package/dist/dashboard/out/connect-repos.txt +1 -1
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +1 -1
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +1 -1
- package/dist/dashboard/out/login.html +1 -1
- package/dist/dashboard/out/login.txt +1 -1
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +1 -1
- package/dist/dashboard/out/pricing.html +1 -1
- package/dist/dashboard/out/pricing.txt +1 -1
- package/dist/dashboard/out/providers/setup/claude.html +1 -1
- package/dist/dashboard/out/providers/setup/claude.txt +1 -1
- package/dist/dashboard/out/providers/setup/codex.html +1 -1
- package/dist/dashboard/out/providers/setup/codex.txt +1 -1
- package/dist/dashboard/out/providers/setup/cursor.html +1 -1
- package/dist/dashboard/out/providers/setup/cursor.txt +1 -1
- package/dist/dashboard/out/providers.html +1 -1
- package/dist/dashboard/out/providers.txt +1 -1
- package/dist/dashboard/out/signup.html +1 -1
- package/dist/dashboard/out/signup.txt +1 -1
- package/package.json +23 -17
- package/packages/api-types/package.json +2 -2
- package/packages/bridge/dist/spawner.d.ts +2 -0
- package/packages/bridge/dist/spawner.js +76 -24
- package/packages/bridge/package.json +8 -8
- package/packages/cli-tester/README.md +277 -0
- package/packages/cli-tester/dist/index.d.ts +21 -0
- package/packages/cli-tester/dist/index.js +21 -0
- package/packages/cli-tester/dist/utils/credential-check.d.ts +56 -0
- package/packages/cli-tester/dist/utils/credential-check.js +230 -0
- package/packages/cli-tester/dist/utils/socket-client.d.ts +76 -0
- package/packages/cli-tester/dist/utils/socket-client.js +153 -0
- package/packages/cli-tester/docker/entrypoint.sh +58 -0
- package/packages/cli-tester/package.json +32 -0
- package/packages/cli-tester/scripts/clear-auth.sh +101 -0
- package/packages/cli-tester/scripts/inject-message.sh +42 -0
- package/packages/cli-tester/scripts/start.sh +71 -0
- package/packages/cli-tester/scripts/test-cli.sh +56 -0
- package/packages/cli-tester/scripts/test-full-spawn.sh +238 -0
- package/packages/cli-tester/scripts/test-registration.sh +182 -0
- package/packages/cli-tester/scripts/test-setup-flow.sh +202 -0
- package/packages/cli-tester/scripts/test-spawn.sh +140 -0
- package/packages/cli-tester/scripts/test-with-daemon.sh +247 -0
- package/packages/cli-tester/scripts/verify-auth.sh +112 -0
- package/packages/cloud/package.json +6 -6
- package/packages/config/dist/cli-auth-config.js +65 -0
- package/packages/config/package.json +2 -2
- package/packages/continuity/package.json +1 -1
- package/packages/daemon/dist/router.js +4 -4
- package/packages/daemon/dist/server.js +38 -19
- package/packages/daemon/dist/spawn-manager.d.ts +4 -0
- package/packages/daemon/dist/spawn-manager.js +2 -0
- package/packages/daemon/package.json +12 -12
- package/packages/dashboard/dist/server.js +4 -0
- package/packages/dashboard/package.json +14 -14
- package/packages/dashboard/ui-dist/404.html +1 -1
- package/packages/dashboard/ui-dist/app/onboarding.html +1 -1
- package/packages/dashboard/ui-dist/app/onboarding.txt +1 -1
- package/packages/dashboard/ui-dist/app.html +1 -1
- package/packages/dashboard/ui-dist/app.txt +1 -1
- package/packages/dashboard/ui-dist/cloud/link.html +1 -1
- package/packages/dashboard/ui-dist/cloud/link.txt +1 -1
- package/packages/dashboard/ui-dist/complete-profile.html +1 -1
- package/packages/dashboard/ui-dist/complete-profile.txt +1 -1
- package/packages/dashboard/ui-dist/connect-repos.html +1 -1
- package/packages/dashboard/ui-dist/connect-repos.txt +1 -1
- package/packages/dashboard/ui-dist/history.html +1 -1
- package/packages/dashboard/ui-dist/history.txt +1 -1
- package/packages/dashboard/ui-dist/index.html +1 -1
- package/packages/dashboard/ui-dist/index.txt +1 -1
- package/packages/dashboard/ui-dist/login.html +1 -1
- package/packages/dashboard/ui-dist/login.txt +1 -1
- package/packages/dashboard/ui-dist/metrics.html +1 -1
- package/packages/dashboard/ui-dist/metrics.txt +1 -1
- package/packages/dashboard/ui-dist/pricing.html +1 -1
- package/packages/dashboard/ui-dist/pricing.txt +1 -1
- package/packages/dashboard/ui-dist/providers/setup/claude.html +1 -1
- package/packages/dashboard/ui-dist/providers/setup/claude.txt +1 -1
- package/packages/dashboard/ui-dist/providers/setup/codex.html +1 -1
- package/packages/dashboard/ui-dist/providers/setup/codex.txt +1 -1
- package/packages/dashboard/ui-dist/providers/setup/cursor.html +1 -1
- package/packages/dashboard/ui-dist/providers/setup/cursor.txt +1 -1
- package/packages/dashboard/ui-dist/providers.html +1 -1
- package/packages/dashboard/ui-dist/providers.txt +1 -1
- package/packages/dashboard/ui-dist/signup.html +1 -1
- package/packages/dashboard/ui-dist/signup.txt +1 -1
- package/packages/dashboard-server/dist/server.js +4 -0
- package/packages/dashboard-server/package.json +12 -12
- package/packages/hooks/package.json +4 -4
- package/packages/mcp/package.json +2 -2
- package/packages/memory/package.json +2 -2
- package/packages/policy/package.json +2 -2
- package/packages/protocol/package.json +1 -1
- package/packages/resiliency/package.json +1 -1
- package/packages/sdk/README.md +512 -58
- package/packages/sdk/dist/client.d.ts +135 -1
- package/packages/sdk/dist/client.js +338 -0
- package/packages/sdk/dist/index.d.ts +2 -1
- package/packages/sdk/dist/index.js +2 -0
- package/packages/sdk/dist/logs.d.ts +61 -0
- package/packages/sdk/dist/logs.js +95 -0
- package/packages/sdk/dist/protocol/index.d.ts +1 -1
- package/packages/sdk/dist/protocol/types.d.ts +186 -1
- package/packages/sdk/package.json +3 -3
- package/packages/spawner/package.json +2 -2
- package/packages/state/package.json +1 -1
- package/packages/storage/dist/sqlite-adapter.js +2 -0
- package/packages/storage/package.json +2 -2
- package/packages/telemetry/package.json +1 -1
- package/packages/trajectory/package.json +2 -2
- package/packages/user-directory/package.json +2 -2
- package/packages/utils/package.json +1 -1
- package/packages/wrapper/dist/base-wrapper.js +27 -10
- package/packages/wrapper/dist/relay-pty-orchestrator.js +16 -16
- package/packages/wrapper/dist/tmux-wrapper.js +16 -0
- package/packages/wrapper/package.json +7 -7
- package/scripts/hooks/install.sh +16 -0
- package/scripts/hooks/pre-commit +60 -0
- package/specs/PRIMITIVES_ROADMAP.md +2154 -0
- /package/dist/dashboard/out/_next/static/{cREcLZyPb-5NyVZje0Qfe → 7MZPqYkVGw3EGzVBkVmY9}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/{cREcLZyPb-5NyVZje0Qfe → 7MZPqYkVGw3EGzVBkVmY9}/_ssgManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{N3ajGnJqRESKyCjDvyU52 → 7MZPqYkVGw3EGzVBkVmY9}/_buildManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{N3ajGnJqRESKyCjDvyU52 → 7MZPqYkVGw3EGzVBkVmY9}/_ssgManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{UQiyWwBxIP-9it3GYVBDL → iJ3Uiz3IrqUJL7IxKZHiV}/_buildManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{UQiyWwBxIP-9it3GYVBDL → iJ3Uiz3IrqUJL7IxKZHiV}/_ssgManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{cREcLZyPb-5NyVZje0Qfe → l-jd878zUJ_IlraqEWMZc}/_buildManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{cREcLZyPb-5NyVZje0Qfe → l-jd878zUJ_IlraqEWMZc}/_ssgManifest.js +0 -0
package/packages/sdk/README.md
CHANGED
|
@@ -1,15 +1,45 @@
|
|
|
1
1
|
# @agent-relay/sdk
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
###
|
|
112
|
+
### Core Messaging
|
|
64
113
|
|
|
65
|
-
|
|
114
|
+
#### sendMessage(to, body, kind?, data?, thread?)
|
|
115
|
+
|
|
116
|
+
Send a message to another agent.
|
|
66
117
|
|
|
67
118
|
```typescript
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
quiet: true, // Suppress logs (default: true)
|
|
71
|
-
});
|
|
119
|
+
// Simple message
|
|
120
|
+
client.sendMessage('Bob', 'Hello!');
|
|
72
121
|
|
|
73
|
-
//
|
|
74
|
-
|
|
122
|
+
// With message kind and data
|
|
123
|
+
client.sendMessage('Bob', 'Task complete', 'action', { taskId: 123 });
|
|
75
124
|
|
|
76
|
-
//
|
|
77
|
-
|
|
125
|
+
// In a thread
|
|
126
|
+
client.sendMessage('Bob', 'Follow-up', 'message', undefined, 'thread-123');
|
|
78
127
|
```
|
|
79
128
|
|
|
80
|
-
|
|
129
|
+
#### sendAndWait(to, body, options?)
|
|
81
130
|
|
|
82
|
-
|
|
131
|
+
Send and wait for acknowledgment. Useful for ensuring delivery.
|
|
83
132
|
|
|
84
133
|
```typescript
|
|
85
|
-
const
|
|
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
|
-
|
|
140
|
+
#### broadcast(body, kind?, data?)
|
|
89
141
|
|
|
90
|
-
|
|
142
|
+
Send to all connected agents.
|
|
91
143
|
|
|
92
144
|
```typescript
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
145
|
+
client.broadcast('System notice to everyone');
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### onMessage
|
|
97
149
|
|
|
98
|
-
|
|
99
|
-
const ack = await client.sendAndWait('OtherAgent', 'Important message');
|
|
150
|
+
Callback for incoming messages.
|
|
100
151
|
|
|
101
|
-
|
|
152
|
+
```typescript
|
|
102
153
|
client.onMessage = (from, payload, messageId, meta, originalTo) => {
|
|
103
154
|
console.log(`${from}: ${payload.body}`);
|
|
104
155
|
|
|
105
|
-
//
|
|
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
|
-
|
|
112
|
-
client.onStateChange = (state) => {
|
|
113
|
-
// 'DISCONNECTED' | 'CONNECTING' | 'HANDSHAKING' | 'READY' | 'BACKOFF'
|
|
114
|
-
};
|
|
167
|
+
### Channels
|
|
115
168
|
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
176
|
+
#### leaveChannel(channel, reason?)
|
|
121
177
|
|
|
122
|
-
|
|
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
|
-
|
|
186
|
+
// Simple message
|
|
187
|
+
client.sendChannelMessage('#general', 'Hello team!');
|
|
126
188
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
|
|
133
|
-
|
|
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
|
-
|
|
206
|
+
#### Admin Channel Operations
|
|
137
207
|
|
|
138
208
|
```typescript
|
|
139
|
-
//
|
|
140
|
-
client.
|
|
209
|
+
// Add a member to a channel (they don't need to be connected)
|
|
210
|
+
client.adminJoinChannel('#team', 'NewMember');
|
|
141
211
|
|
|
142
|
-
//
|
|
143
|
-
client.
|
|
212
|
+
// Remove a member from a channel
|
|
213
|
+
client.adminRemoveMember('#team', 'FormerMember');
|
|
214
|
+
```
|
|
144
215
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
//
|
|
151
|
-
client.
|
|
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
|
-
|
|
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
|
-
|
|
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
|