agent-relay 3.0.1 → 3.0.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.
- package/README.md +32 -247
- package/bin/agent-relay-broker-darwin-arm64 +0 -0
- package/bin/agent-relay-broker-darwin-x64 +0 -0
- package/bin/agent-relay-broker-linux-arm64 +0 -0
- package/bin/agent-relay-broker-linux-x64 +0 -0
- package/dist/index.cjs +74 -9
- package/package.json +9 -8
- package/packages/acp-bridge/package.json +2 -2
- package/packages/config/package.json +1 -1
- package/packages/hooks/package.json +4 -4
- package/packages/memory/package.json +2 -2
- package/packages/policy/package.json +2 -2
- package/packages/sdk/dist/__tests__/facade.test.js +48 -0
- package/packages/sdk/dist/__tests__/facade.test.js.map +1 -1
- package/packages/sdk/dist/__tests__/integration.test.js +6 -1
- package/packages/sdk/dist/__tests__/integration.test.js.map +1 -1
- package/packages/sdk/dist/__tests__/unit.test.js +36 -0
- package/packages/sdk/dist/__tests__/unit.test.js.map +1 -1
- package/packages/sdk/dist/client.d.ts +2 -0
- package/packages/sdk/dist/client.d.ts.map +1 -1
- package/packages/sdk/dist/client.js +27 -4
- package/packages/sdk/dist/client.js.map +1 -1
- package/packages/sdk/dist/relay.d.ts +27 -0
- package/packages/sdk/dist/relay.d.ts.map +1 -1
- package/packages/sdk/dist/relay.js +61 -4
- package/packages/sdk/dist/relay.js.map +1 -1
- package/packages/sdk/package.json +2 -2
- package/packages/sdk/src/__tests__/facade.test.ts +68 -0
- package/packages/sdk/src/__tests__/integration.test.ts +6 -1
- package/packages/sdk/src/__tests__/unit.test.ts +44 -0
- package/packages/sdk/src/client.ts +30 -6
- package/packages/sdk/src/relay.ts +75 -4
- package/packages/sdk-py/pyproject.toml +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 +2 -2
- package/scripts/postinstall.js +35 -162
- package/packages/sdk/bin/agent-relay-broker +0 -0
package/README.md
CHANGED
|
@@ -1,275 +1,60 @@
|
|
|
1
1
|
# agent-relay
|
|
2
2
|
|
|
3
|
-
> Real-time messaging between AI agents.
|
|
3
|
+
> Real-time messaging between AI agents.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@agent-relay/sdk)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
|
-
```bash
|
|
13
|
-
curl -fsSL https://raw.githubusercontent.com/AgentWorkforce/relay/main/install.sh | bash
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Or via npm (requires Node.js 18+):
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npm install -g agent-relay
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Quick Start
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
agent-relay up --dashboard
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Open **http://localhost:3888** to spawn agents, view real-time status, and stream logs.
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## CLI Reference
|
|
33
|
-
|
|
34
|
-
| Command | Description |
|
|
35
|
-
| --------------------------------------- | ------------------------ |
|
|
36
|
-
| `agent-relay up` | Start broker + dashboard |
|
|
37
|
-
| `agent-relay down` | Stop broker |
|
|
38
|
-
| `agent-relay spawn <name> <cli> "task"` | Spawn a worker agent |
|
|
39
|
-
| `agent-relay status` | Check broker status |
|
|
40
|
-
| `agent-relay run workflow.yaml` | Run a YAML workflow |
|
|
41
|
-
| `agent-relay run --template feature-dev`| Run a built-in template |
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## Workflows
|
|
46
|
-
|
|
47
|
-
Define multi-agent workflows in YAML, TypeScript, or Python. Run locally or queue to the cloud for 24/7 execution:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
# Run locally
|
|
51
|
-
agent-relay run workflow.yaml --task "Add OAuth2 support"
|
|
52
|
-
|
|
53
|
-
# Queue to cloud — durable, scalable, runs in sandboxes
|
|
54
|
-
agent-relay run workflow.yaml --cloud --task "Add OAuth2 support"
|
|
55
|
-
|
|
56
|
-
# Use built-in templates
|
|
57
|
-
agent-relay run --template feature-dev --task "Add user dashboard"
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### relay.yaml
|
|
61
|
-
|
|
62
|
-
Blueprint-style workflows combine **agent steps** (LLM-powered) with **deterministic steps** (shell commands) for faster, cheaper, more reliable execution:
|
|
63
|
-
|
|
64
|
-
```yaml
|
|
65
|
-
version: "1.0"
|
|
66
|
-
name: ship-feature
|
|
67
|
-
|
|
68
|
-
agents:
|
|
69
|
-
- name: planner
|
|
70
|
-
cli: claude
|
|
71
|
-
model: opus
|
|
72
|
-
- name: developer
|
|
73
|
-
cli: codex
|
|
74
|
-
|
|
75
|
-
workflows:
|
|
76
|
-
- name: default
|
|
77
|
-
preflight:
|
|
78
|
-
- command: git status --porcelain
|
|
79
|
-
failIf: non-empty
|
|
80
|
-
steps:
|
|
81
|
-
- name: plan
|
|
82
|
-
agent: planner
|
|
83
|
-
task: "Create implementation plan for: {{task}}"
|
|
84
|
-
- name: create-branch
|
|
85
|
-
type: deterministic
|
|
86
|
-
command: git checkout -b feature/{{branch-name}}
|
|
87
|
-
dependsOn: [plan]
|
|
88
|
-
- name: implement
|
|
89
|
-
agent: developer
|
|
90
|
-
task: "Implement: {{steps.plan.output}}"
|
|
91
|
-
dependsOn: [create-branch]
|
|
92
|
-
- name: test
|
|
93
|
-
type: deterministic
|
|
94
|
-
command: npm test
|
|
95
|
-
dependsOn: [implement]
|
|
96
|
-
- name: commit
|
|
97
|
-
type: deterministic
|
|
98
|
-
command: git add -A && git commit -m "feat: {{task}}"
|
|
99
|
-
dependsOn: [test]
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
**Benefits:** Deterministic steps run instantly ($0 LLM cost), catch issues early with preflight checks, and git commands can't hallucinate.
|
|
103
|
-
|
|
104
|
-
Also available as fluent builders in [TypeScript SDK](https://www.npmjs.com/package/@agent-relay/sdk) and [Python SDK](https://pypi.org/project/agent-relay/).
|
|
105
|
-
|
|
106
|
-
### Built-in Templates
|
|
107
|
-
|
|
108
|
-
All templates use blueprint-style hybrid workflows with deterministic quality gates.
|
|
109
|
-
|
|
110
|
-
| Template | Pattern | Description |
|
|
111
|
-
| ---------------- | ------------ | ------------------------------------------------ |
|
|
112
|
-
| `feature-dev` | hub-spoke | Plan, implement, review, and finalize a feature |
|
|
113
|
-
| `bug-fix` | hub-spoke | Investigate, patch, validate, and document |
|
|
114
|
-
| `code-review` | fan-out | Parallel multi-reviewer assessment |
|
|
115
|
-
| `security-audit` | pipeline | Scan, triage, remediate, and verify |
|
|
116
|
-
| `refactor` | hierarchical | Analyze, plan, execute, and validate |
|
|
117
|
-
| `documentation` | handoff | Research, draft, review, and publish |
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## SDK Usage
|
|
122
|
-
|
|
123
12
|
```bash
|
|
124
13
|
npm install @agent-relay/sdk
|
|
125
14
|
```
|
|
126
15
|
|
|
127
|
-
|
|
16
|
+
## Usage
|
|
128
17
|
|
|
129
18
|
```typescript
|
|
130
|
-
import { AgentRelay, Models } from
|
|
19
|
+
import { AgentRelay, Models } from "@agent-relay/sdk";
|
|
131
20
|
|
|
132
21
|
const relay = new AgentRelay();
|
|
133
22
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
});
|
|
23
|
+
relay.onMessageReceived = (msg) =>
|
|
24
|
+
console.log(`[${msg.from} → ${msg.to}]: ${msg.text}`);
|
|
25
|
+
|
|
26
|
+
const channel = ["tic-tac-toe"];
|
|
139
27
|
|
|
140
|
-
const
|
|
141
|
-
name:
|
|
142
|
-
model: Models.
|
|
28
|
+
const x = await relay.claude.spawn({
|
|
29
|
+
name: "PlayerX",
|
|
30
|
+
model: Models.Claude.SONNET,
|
|
31
|
+
channels: channel,
|
|
32
|
+
task: "Play tic-tac-toe as X against PlayerO. You go first.",
|
|
33
|
+
});
|
|
34
|
+
const o = await relay.codex.spawn({
|
|
35
|
+
name: "PlayerO",
|
|
36
|
+
model: Models.Codex.GPT_5_3_CODEX_SPARK,
|
|
37
|
+
channels: channel,
|
|
38
|
+
task: "Play tic-tac-toe as O against PlayerX.",
|
|
143
39
|
});
|
|
144
40
|
|
|
145
|
-
|
|
146
|
-
await
|
|
41
|
+
console.log("Waiting for agents to be ready...");
|
|
42
|
+
await Promise.all([
|
|
43
|
+
relay.waitForAgentReady("PlayerX"),
|
|
44
|
+
relay.waitForAgentReady("PlayerO"),
|
|
45
|
+
]);
|
|
46
|
+
console.log("Both ready. Starting game.");
|
|
147
47
|
|
|
148
|
-
|
|
149
|
-
relay.onMessageReceived = (msg) => {
|
|
150
|
-
console.log(`${msg.from} → ${msg.to}: ${msg.text}`);
|
|
151
|
-
};
|
|
48
|
+
relay.system().sendMessage({ to: "PlayerX", text: "Start." });
|
|
152
49
|
|
|
50
|
+
const FIVE_MINUTES = 5 * 60 * 1000;
|
|
51
|
+
await AgentRelay.waitForAny([x, o], FIVE_MINUTES);
|
|
153
52
|
await relay.shutdown();
|
|
154
53
|
```
|
|
155
54
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
import { workflow, Models, SwarmPatterns } from '@agent-relay/sdk/workflows';
|
|
162
|
-
|
|
163
|
-
// Hub-spoke: Lead coordinates workers
|
|
164
|
-
const result = await workflow('feature-build')
|
|
165
|
-
.pattern(SwarmPatterns.HUB_SPOKE)
|
|
166
|
-
.agent('lead', { cli: 'claude', model: Models.Claude.OPUS, role: 'Coordinator' })
|
|
167
|
-
.agent('dev1', { cli: 'codex', model: Models.Codex.CODEX_5_3, role: 'Developer' })
|
|
168
|
-
.agent('dev2', { cli: 'cursor', model: Models.Cursor.CLAUDE_SONNET, role: 'Developer' })
|
|
169
|
-
.step('plan', { agent: 'lead', task: 'Break down the feature into tasks' })
|
|
170
|
-
.step('impl1', { agent: 'dev1', task: 'Implement backend', dependsOn: ['plan'] })
|
|
171
|
-
.step('impl2', { agent: 'dev2', task: 'Implement frontend', dependsOn: ['plan'] })
|
|
172
|
-
.step('review', { agent: 'lead', task: 'Review and merge', dependsOn: ['impl1', 'impl2'] })
|
|
173
|
-
.run();
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**Swarm Patterns:**
|
|
177
|
-
|
|
178
|
-
| Category | Patterns |
|
|
179
|
-
| --------------- | ----------------------------------------------------------- |
|
|
180
|
-
| **Core** | `dag`, `fan-out`, `pipeline`, `hub-spoke`, `consensus`, `mesh` |
|
|
181
|
-
| **Data** | `map-reduce`, `scatter-gather` |
|
|
182
|
-
| **Quality** | `supervisor`, `reflection`, `verifier` |
|
|
183
|
-
| **Adversarial** | `red-team`, `auction` |
|
|
184
|
-
| **Resilience** | `escalation`, `saga`, `circuit-breaker` |
|
|
185
|
-
|
|
186
|
-
Auto-pattern selection: define agents with roles like `mapper`, `reducer`, `tier-1`, `attacker`, `defender` and the pattern is auto-selected.
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
## Cloud
|
|
191
|
-
|
|
192
|
-
Scale to teams and automate with [Agent Relay Cloud](https://agent-relay.com):
|
|
193
|
-
|
|
194
|
-
```bash
|
|
195
|
-
agent-relay cloud link # Link your machine
|
|
196
|
-
agent-relay cloud agents # List agents across machines
|
|
197
|
-
agent-relay cloud send AgentName "Your message"
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Multi-Agent Orchestration
|
|
201
|
-
|
|
202
|
-
Spawn agent teams in the cloud — each agent runs in its own isolated sandbox but can communicate with teammates:
|
|
203
|
-
|
|
204
|
-
- **Isolated Sandboxes**: Each agent gets a secure container with full dev environment
|
|
205
|
-
- **Cross-Sandbox Messaging**: Agents collaborate via relay channels despite isolation
|
|
206
|
-
- **24/7 Durable Workflows**: Queue workflows to run continuously, survive restarts
|
|
207
|
-
- **Auto-Scaling**: Workspaces scale up/down based on agent load
|
|
208
|
-
|
|
209
|
-
```bash
|
|
210
|
-
# Queue a workflow to run in the cloud
|
|
211
|
-
agent-relay run workflow.yaml --cloud --task "Refactor auth module"
|
|
212
|
-
|
|
213
|
-
# Workflows persist, scale, and run even when you're offline
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Integrations
|
|
217
|
-
|
|
218
|
-
| Integration | Capabilities |
|
|
219
|
-
| ----------- | ------------ |
|
|
220
|
-
| **GitHub** | CI auto-fix, @mentions in PRs, issue assignment triggers |
|
|
221
|
-
| **Linear** | Issue assignment spawns agents, status sync |
|
|
222
|
-
| **Slack** | Chat with agents, trigger workflows from Slack commands |
|
|
223
|
-
|
|
224
|
-
### CI Auto-Fix
|
|
225
|
-
|
|
226
|
-
Install the [Agent Relay GitHub App](https://github.com/apps/agent-relay):
|
|
227
|
-
|
|
228
|
-
```
|
|
229
|
-
1. CI fails on PR #123
|
|
230
|
-
2. Agent Relay: "🔴 CI Failure Detected, spawning @ci-fix agent..."
|
|
231
|
-
3. Agent analyzes logs, fixes issue, pushes commit
|
|
232
|
-
4. Agent Relay: "✅ CI Fix Applied — please re-run checks"
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
## Architecture
|
|
238
|
-
|
|
239
|
-
Agent Relay is built from modular components that work together:
|
|
240
|
-
|
|
241
|
-
```
|
|
242
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
243
|
-
│ Your Application │
|
|
244
|
-
├─────────────────────────────────────────────────────────────────┤
|
|
245
|
-
│ agent-relay CLI │ @agent-relay/sdk │ relay.yaml │
|
|
246
|
-
├─────────────────────────────────────────────────────────────────┤
|
|
247
|
-
│ Relay Broker │
|
|
248
|
-
│ • Agent lifecycle • Message routing • PTY management │
|
|
249
|
-
├─────────────────────────────────────────────────────────────────┤
|
|
250
|
-
│ Relaycast │
|
|
251
|
-
│ • REST API • WebSocket events • Channels & threads │
|
|
252
|
-
├─────────────────────────────────────────────────────────────────┤
|
|
253
|
-
│ Claude │ Codex │ Gemini │ Cursor │ Aider │ Goose │
|
|
254
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
### Components
|
|
258
|
-
|
|
259
|
-
| Component | Description |
|
|
260
|
-
| --------- | ----------- |
|
|
261
|
-
| **Relay Broker** | Core message router with sub-5ms latency. Manages agent lifecycle, PTY sessions, and message delivery. |
|
|
262
|
-
| **Relaycast** | Communication layer with REST API and WebSocket. Provides channels, threads, reactions, and file attachments. Framework-agnostic — works with CrewAI, LangGraph, AutoGen, or raw API calls. |
|
|
263
|
-
| **Relay Dashboard** | Real-time monitoring UI. View agent status, stream logs, and manage workflows from the browser. |
|
|
264
|
-
| **Relay Cloud** | Multi-tenant cloud platform with auto-scaling, billing, and webhook integrations for GitHub/Linear/Slack. |
|
|
265
|
-
| **Trajectories** | Decision capture system. Records the "why" behind code changes — decisions, challenges, and confidence scores — as searchable institutional memory. |
|
|
266
|
-
|
|
267
|
-
### How It Works
|
|
268
|
-
|
|
269
|
-
1. **Zero modification**: Agents run unmodified CLI tools (Claude Code, Codex, etc.) in PTY sessions
|
|
270
|
-
2. **MCP protocol**: Agents communicate via standard MCP tools — no custom SDK required inside agents
|
|
271
|
-
3. **Mix AI providers**: Combine Claude, GPT, and Gemini agents in a single workflow — each using their strengths
|
|
272
|
-
4. **Workflow engine**: YAML workflows parsed and executed with dependency resolution, retries, and verification
|
|
55
|
+
## Supported CLI’s
|
|
56
|
+
- Claude
|
|
57
|
+
- Codex
|
|
273
58
|
|
|
274
59
|
---
|
|
275
60
|
|
|
@@ -279,4 +64,4 @@ Apache-2.0 — Copyright 2026 Agent Workforce Incorporated
|
|
|
279
64
|
|
|
280
65
|
---
|
|
281
66
|
|
|
282
|
-
**Links:** [Documentation](https://docs.agent-relay.com/) · [Issues](https://github.com/AgentWorkforce/relay/issues) · [
|
|
67
|
+
**Links:** [Documentation](https://docs.agent-relay.com/) · [Issues](https://github.com/AgentWorkforce/relay/issues) · [Discord](https://discord.gg/6E6CTxM8um)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/index.cjs
CHANGED
|
@@ -8989,6 +8989,8 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
8989
8989
|
eventBuffer = [];
|
|
8990
8990
|
maxBufferSize = 1e3;
|
|
8991
8991
|
exitPromise;
|
|
8992
|
+
/** The workspace key returned by the broker in its hello_ack response. */
|
|
8993
|
+
workspaceKey;
|
|
8992
8994
|
constructor(options = {}) {
|
|
8993
8995
|
this.options = {
|
|
8994
8996
|
binaryPath: options.binaryPath ?? resolveDefaultBinaryPath(),
|
|
@@ -9250,8 +9252,11 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
9250
9252
|
resolve3();
|
|
9251
9253
|
});
|
|
9252
9254
|
});
|
|
9253
|
-
await this.requestHello();
|
|
9255
|
+
const helloAck = await this.requestHello();
|
|
9254
9256
|
console.log("[broker] Broker ready (hello handshake complete)");
|
|
9257
|
+
if (helloAck.workspace_key) {
|
|
9258
|
+
this.workspaceKey = helloAck.workspace_key;
|
|
9259
|
+
}
|
|
9255
9260
|
}
|
|
9256
9261
|
disposeProcessHandles() {
|
|
9257
9262
|
this.stdoutRl?.close();
|
|
@@ -9367,12 +9372,16 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
9367
9372
|
}
|
|
9368
9373
|
};
|
|
9369
9374
|
var CLI_MODEL_FLAG_CLIS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "goose", "aider"]);
|
|
9375
|
+
var CLI_DEFAULT_ARGS = {
|
|
9376
|
+
codex: ["-c", "check_for_update_on_startup=false"]
|
|
9377
|
+
};
|
|
9370
9378
|
function buildPtyArgsWithModel(cli, args, model) {
|
|
9371
|
-
const
|
|
9379
|
+
const cliName = cli.split(":")[0].trim().toLowerCase();
|
|
9380
|
+
const defaultArgs = CLI_DEFAULT_ARGS[cliName] ?? [];
|
|
9381
|
+
const baseArgs = [...defaultArgs, ...args];
|
|
9372
9382
|
if (!model) {
|
|
9373
9383
|
return baseArgs;
|
|
9374
9384
|
}
|
|
9375
|
-
const cliName = cli.split(":")[0].trim().toLowerCase();
|
|
9376
9385
|
if (!CLI_MODEL_FLAG_CLIS.has(cliName)) {
|
|
9377
9386
|
return baseArgs;
|
|
9378
9387
|
}
|
|
@@ -9410,7 +9419,19 @@ function resolveDefaultBinaryPath() {
|
|
|
9410
9419
|
if (import_node_fs.default.existsSync(workspaceRelease)) {
|
|
9411
9420
|
return workspaceRelease;
|
|
9412
9421
|
}
|
|
9413
|
-
const
|
|
9422
|
+
const binDir = import_node_path.default.resolve(moduleDir, "..", "bin");
|
|
9423
|
+
const platformMap = {
|
|
9424
|
+
darwin: { arm64: "darwin-arm64", x64: "darwin-x64" },
|
|
9425
|
+
linux: { arm64: "linux-arm64", x64: "linux-x64" }
|
|
9426
|
+
};
|
|
9427
|
+
const suffix = platformMap[process.platform]?.[process.arch];
|
|
9428
|
+
if (suffix) {
|
|
9429
|
+
const platformBinary = import_node_path.default.join(binDir, `agent-relay-broker-${suffix}`);
|
|
9430
|
+
if (import_node_fs.default.existsSync(platformBinary)) {
|
|
9431
|
+
return platformBinary;
|
|
9432
|
+
}
|
|
9433
|
+
}
|
|
9434
|
+
const bundled = import_node_path.default.join(binDir, brokerExe);
|
|
9414
9435
|
if (import_node_fs.default.existsSync(bundled)) {
|
|
9415
9436
|
return bundled;
|
|
9416
9437
|
}
|
|
@@ -15176,7 +15197,7 @@ var DefaultModels = {
|
|
|
15176
15197
|
};
|
|
15177
15198
|
|
|
15178
15199
|
// node_modules/@relaycast/sdk/dist/version.js
|
|
15179
|
-
var SDK_VERSION = "0.4.
|
|
15200
|
+
var SDK_VERSION = "0.4.2";
|
|
15180
15201
|
|
|
15181
15202
|
// node_modules/@relaycast/types/node_modules/zod/v4/classic/external.js
|
|
15182
15203
|
var external_exports2 = {};
|
|
@@ -45021,12 +45042,26 @@ var AgentRelay = class {
|
|
|
45021
45042
|
onDeliveryUpdate = null;
|
|
45022
45043
|
onAgentExitRequested = null;
|
|
45023
45044
|
onAgentIdle = null;
|
|
45045
|
+
// ── Public accessors ────────────────────────────────────────────────────
|
|
45046
|
+
/** The resolved Relaycast workspace API key (available after first spawn). */
|
|
45047
|
+
get workspaceKey() {
|
|
45048
|
+
return this.relayApiKey;
|
|
45049
|
+
}
|
|
45050
|
+
/** Observer URL for the auto-created workspace (available after first spawn). */
|
|
45051
|
+
get observerUrl() {
|
|
45052
|
+
if (!this.relayApiKey)
|
|
45053
|
+
return void 0;
|
|
45054
|
+
return `https://observer.relaycast.dev/?key=${this.relayApiKey}`;
|
|
45055
|
+
}
|
|
45024
45056
|
// Shorthand spawners
|
|
45025
45057
|
codex;
|
|
45026
45058
|
claude;
|
|
45027
45059
|
gemini;
|
|
45028
45060
|
clientOptions;
|
|
45029
45061
|
defaultChannels;
|
|
45062
|
+
workspaceName;
|
|
45063
|
+
relaycastBaseUrl;
|
|
45064
|
+
relayApiKey;
|
|
45030
45065
|
client;
|
|
45031
45066
|
startPromise;
|
|
45032
45067
|
unsubEvent;
|
|
@@ -45043,6 +45078,8 @@ var AgentRelay = class {
|
|
|
45043
45078
|
idleResolverSeq = 0;
|
|
45044
45079
|
constructor(options = {}) {
|
|
45045
45080
|
this.defaultChannels = options.channels ?? ["general"];
|
|
45081
|
+
this.workspaceName = options.workspaceName;
|
|
45082
|
+
this.relaycastBaseUrl = options.relaycastBaseUrl;
|
|
45046
45083
|
this.clientOptions = {
|
|
45047
45084
|
binaryPath: options.binaryPath,
|
|
45048
45085
|
binaryArgs: options.binaryArgs,
|
|
@@ -45128,7 +45165,7 @@ var AgentRelay = class {
|
|
|
45128
45165
|
if (waitForMessage) {
|
|
45129
45166
|
return this.waitForAgentMessage(name, timeoutMs ?? 6e4);
|
|
45130
45167
|
}
|
|
45131
|
-
return this.waitForAgentReady(name, timeoutMs ??
|
|
45168
|
+
return this.waitForAgentReady(name, timeoutMs ?? 6e4);
|
|
45132
45169
|
}
|
|
45133
45170
|
// ── Human source ────────────────────────────────────────────────────────
|
|
45134
45171
|
human(opts) {
|
|
@@ -45318,7 +45355,7 @@ var AgentRelay = class {
|
|
|
45318
45355
|
* The agent's CLI may not yet be ready to receive messages.
|
|
45319
45356
|
* Use `waitForAgentMessage()` for full readiness.
|
|
45320
45357
|
*/
|
|
45321
|
-
async waitForAgentReady(name, timeoutMs =
|
|
45358
|
+
async waitForAgentReady(name, timeoutMs = 6e4) {
|
|
45322
45359
|
const client = await this.ensureStarted();
|
|
45323
45360
|
const existing = this.knownAgents.get(name);
|
|
45324
45361
|
if (existing && this.readyAgents.has(name)) {
|
|
@@ -45492,14 +45529,42 @@ var AgentRelay = class {
|
|
|
45492
45529
|
}
|
|
45493
45530
|
}
|
|
45494
45531
|
}
|
|
45532
|
+
/**
|
|
45533
|
+
* Ensure a Relaycast workspace API key is available.
|
|
45534
|
+
* Resolution order:
|
|
45535
|
+
* 1. Already resolved (cached from a previous call)
|
|
45536
|
+
* 2. RELAY_API_KEY in options.env
|
|
45537
|
+
* 3. RELAY_API_KEY in process.env
|
|
45538
|
+
* 4. Auto-create a fresh workspace via the Relaycast REST API
|
|
45539
|
+
*/
|
|
45540
|
+
async ensureRelaycastApiKey() {
|
|
45541
|
+
if (this.relayApiKey)
|
|
45542
|
+
return;
|
|
45543
|
+
const envKey = this.clientOptions.env?.RELAY_API_KEY ?? process.env.RELAY_API_KEY;
|
|
45544
|
+
if (envKey) {
|
|
45545
|
+
this.relayApiKey = envKey;
|
|
45546
|
+
if (!this.clientOptions.env) {
|
|
45547
|
+
this.clientOptions.env = { ...process.env, RELAY_API_KEY: envKey };
|
|
45548
|
+
} else if (!this.clientOptions.env.RELAY_API_KEY) {
|
|
45549
|
+
this.clientOptions.env.RELAY_API_KEY = envKey;
|
|
45550
|
+
}
|
|
45551
|
+
return;
|
|
45552
|
+
}
|
|
45553
|
+
if (!this.clientOptions.env) {
|
|
45554
|
+
this.clientOptions.env = { ...process.env };
|
|
45555
|
+
}
|
|
45556
|
+
}
|
|
45495
45557
|
async ensureStarted() {
|
|
45496
45558
|
if (this.client)
|
|
45497
45559
|
return this.client;
|
|
45498
45560
|
if (this.startPromise)
|
|
45499
45561
|
return this.startPromise;
|
|
45500
|
-
this.startPromise = AgentRelayClient.start(this.clientOptions).then((c) => {
|
|
45562
|
+
this.startPromise = this.ensureRelaycastApiKey().then(() => AgentRelayClient.start(this.clientOptions)).then((c) => {
|
|
45501
45563
|
this.client = c;
|
|
45502
45564
|
this.startPromise = void 0;
|
|
45565
|
+
if (c.workspaceKey) {
|
|
45566
|
+
this.relayApiKey = c.workspaceKey;
|
|
45567
|
+
}
|
|
45503
45568
|
this.wireEvents(c);
|
|
45504
45569
|
return c;
|
|
45505
45570
|
}).catch((err) => {
|
|
@@ -45648,7 +45713,7 @@ var AgentRelay = class {
|
|
|
45648
45713
|
const client = await relay.ensureStarted();
|
|
45649
45714
|
await client.release(name, reason);
|
|
45650
45715
|
},
|
|
45651
|
-
async waitForReady(timeoutMs =
|
|
45716
|
+
async waitForReady(timeoutMs = 6e4) {
|
|
45652
45717
|
await relay.waitForAgentReady(name, timeoutMs);
|
|
45653
45718
|
},
|
|
45654
45719
|
waitForExit(timeoutMs) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-relay",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Real-time agent-to-agent communication system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -103,6 +103,7 @@
|
|
|
103
103
|
"postbuild": "chmod +x dist/src/cli/bootstrap.js dist/src/cli/index.js && npm run build:cjs",
|
|
104
104
|
"prepack": "if [ -d node_modules ]; then npm run build; else echo '⚠ node_modules not found, skipping prepack build'; fi",
|
|
105
105
|
"dev:watch": "tsc -w",
|
|
106
|
+
"docs": "cd ./docs && npx mintlify dev",
|
|
106
107
|
"watch:start": "npm run build && concurrently -k \"npm run dev:watch\" \"node --watch dist/src/cli/bootstrap.js start dashboard.js claude\"",
|
|
107
108
|
"watch:start:cli-tools": "npm run build && bash ./scripts/watch-cli-tools.sh",
|
|
108
109
|
"watch:start:claude": "npm run watch:start:cli-tools -- --tool=claude",
|
|
@@ -173,13 +174,13 @@
|
|
|
173
174
|
},
|
|
174
175
|
"homepage": "https://github.com/AgentWorkforce/relay#readme",
|
|
175
176
|
"dependencies": {
|
|
176
|
-
"@agent-relay/config": "3.0.
|
|
177
|
-
"@agent-relay/hooks": "3.0.
|
|
178
|
-
"@agent-relay/sdk": "3.0.
|
|
179
|
-
"@agent-relay/telemetry": "3.0.
|
|
180
|
-
"@agent-relay/trajectory": "3.0.
|
|
181
|
-
"@agent-relay/user-directory": "3.0.
|
|
182
|
-
"@agent-relay/utils": "3.0.
|
|
177
|
+
"@agent-relay/config": "3.0.2",
|
|
178
|
+
"@agent-relay/hooks": "3.0.2",
|
|
179
|
+
"@agent-relay/sdk": "3.0.2",
|
|
180
|
+
"@agent-relay/telemetry": "3.0.2",
|
|
181
|
+
"@agent-relay/trajectory": "3.0.2",
|
|
182
|
+
"@agent-relay/user-directory": "3.0.2",
|
|
183
|
+
"@agent-relay/utils": "3.0.2",
|
|
183
184
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
184
185
|
"@relaycast/sdk": "^0.4.0",
|
|
185
186
|
"chokidar": "^5.0.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-relay/acp-bridge",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "ACP (Agent Client Protocol) bridge for Agent Relay - expose relay agents to ACP-compatible editors like Zed",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@agent-relay/sdk": "3.0.
|
|
49
|
+
"@agent-relay/sdk": "3.0.2",
|
|
50
50
|
"@agentclientprotocol/sdk": "^0.12.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-relay/hooks",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Hook emitter, registry, and trajectory hooks for Agent Relay",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
"test:watch": "vitest"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@agent-relay/config": "3.0.
|
|
41
|
-
"@agent-relay/trajectory": "3.0.
|
|
42
|
-
"@agent-relay/sdk": "3.0.
|
|
40
|
+
"@agent-relay/config": "3.0.2",
|
|
41
|
+
"@agent-relay/trajectory": "3.0.2",
|
|
42
|
+
"@agent-relay/sdk": "3.0.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "^22.19.3",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-relay/memory",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Semantic memory storage and retrieval system for agent-relay with multiple backend support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"test:watch": "vitest"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@agent-relay/hooks": "3.0.
|
|
25
|
+
"@agent-relay/hooks": "3.0.2"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^22.19.3",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-relay/policy",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Agent policy management with multi-level fallback (repo, local PRPM, cloud workspace)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"test:watch": "vitest"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@agent-relay/config": "3.0.
|
|
25
|
+
"@agent-relay/config": "3.0.2"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^22.19.3",
|
|
@@ -254,4 +254,52 @@ test("facade: listLoggedAgents returns array", async (t) => {
|
|
|
254
254
|
await relay.shutdown();
|
|
255
255
|
}
|
|
256
256
|
});
|
|
257
|
+
// ── workspaceKey / observerUrl from hello_ack ────────────────────────────────
|
|
258
|
+
test("facade: workspaceKey is populated from broker hello_ack after startup", async (t) => {
|
|
259
|
+
const bin = requireBinary(t);
|
|
260
|
+
if (!bin)
|
|
261
|
+
return;
|
|
262
|
+
// Create relay WITHOUT passing RELAY_API_KEY in env — broker creates its own
|
|
263
|
+
// workspace and returns the key via hello_ack. This tests the fix for the
|
|
264
|
+
// "dual workspace" bug where SDK and broker used different workspace keys.
|
|
265
|
+
const envWithoutKey = { ...process.env };
|
|
266
|
+
delete envWithoutKey.RELAY_API_KEY;
|
|
267
|
+
const relay = new AgentRelay({
|
|
268
|
+
binaryPath: bin,
|
|
269
|
+
requestTimeoutMs: 15_000,
|
|
270
|
+
env: envWithoutKey,
|
|
271
|
+
});
|
|
272
|
+
try {
|
|
273
|
+
await relay.getStatus();
|
|
274
|
+
// After startup, workspaceKey MUST be set from the broker's hello_ack.
|
|
275
|
+
assert.ok(relay.workspaceKey, "workspaceKey must be set after broker startup (read from hello_ack workspace_key field)");
|
|
276
|
+
assert.match(relay.workspaceKey, /^rk_live_/, "workspaceKey must be a valid workspace key (rk_live_ prefix)");
|
|
277
|
+
// observerUrl must be correctly formatted.
|
|
278
|
+
assert.ok(relay.observerUrl, "observerUrl must be defined when workspaceKey is set");
|
|
279
|
+
assert.ok(relay.observerUrl.includes(relay.workspaceKey), "observerUrl must contain the workspace key");
|
|
280
|
+
}
|
|
281
|
+
finally {
|
|
282
|
+
await relay.shutdown();
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
test("facade: workspaceKey from env matches broker hello_ack when valid", async (t) => {
|
|
286
|
+
if (!requireRelaycast(t))
|
|
287
|
+
return;
|
|
288
|
+
const bin = requireBinary(t);
|
|
289
|
+
if (!bin)
|
|
290
|
+
return;
|
|
291
|
+
// When RELAY_API_KEY is valid, the broker uses it and returns the same key
|
|
292
|
+
// in hello_ack. SDK and broker must be on the same workspace.
|
|
293
|
+
const relay = makeRelay(bin);
|
|
294
|
+
try {
|
|
295
|
+
await relay.getStatus();
|
|
296
|
+
assert.ok(relay.workspaceKey, "workspaceKey must be set after startup");
|
|
297
|
+
// The workspace key returned by broker must match what we passed in.
|
|
298
|
+
assert.equal(relay.workspaceKey, process.env.RELAY_API_KEY, "broker hello_ack workspace_key must match the RELAY_API_KEY we passed — " +
|
|
299
|
+
"a mismatch means broker and SDK are on different workspaces, breaking MCP auth");
|
|
300
|
+
}
|
|
301
|
+
finally {
|
|
302
|
+
await relay.shutdown();
|
|
303
|
+
}
|
|
304
|
+
});
|
|
257
305
|
//# sourceMappingURL=facade.test.js.map
|