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
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Lightweight client for agent-to-agent communication via Agent Relay daemon.
|
|
6
6
|
*/
|
|
7
|
-
import { type Envelope, type SendPayload, type SendMeta, type AckPayload, type PayloadKind, type SpeakOnTrigger, type EntityType, type ChannelMessagePayload, type MessageAttachment } from './protocol/types.js';
|
|
7
|
+
import { type Envelope, type SendPayload, type SendMeta, type AckPayload, type PayloadKind, type SpeakOnTrigger, type EntityType, type ChannelMessagePayload, type MessageAttachment, type SpawnResultPayload, type ReleaseResultPayload, type StatusResponsePayload, type InboxMessage, type AgentInfo, type HealthResponsePayload, type MetricsResponsePayload, type CreateProposalOptions, type VoteOptions } from './protocol/types.js';
|
|
8
8
|
export type ClientState = 'DISCONNECTED' | 'CONNECTING' | 'HANDSHAKING' | 'READY' | 'BACKOFF';
|
|
9
9
|
export interface SyncOptions {
|
|
10
10
|
timeoutMs?: number;
|
|
@@ -62,6 +62,9 @@ export declare class RelayClient {
|
|
|
62
62
|
private writeQueue;
|
|
63
63
|
private writeScheduled;
|
|
64
64
|
private pendingSyncAcks;
|
|
65
|
+
private pendingSpawns;
|
|
66
|
+
private pendingReleases;
|
|
67
|
+
private pendingQueries;
|
|
65
68
|
onMessage?: (from: string, payload: SendPayload, messageId: string, meta?: SendMeta, originalTo?: string) => void;
|
|
66
69
|
/**
|
|
67
70
|
* Callback for channel messages.
|
|
@@ -125,6 +128,35 @@ export declare class RelayClient {
|
|
|
125
128
|
* Send log output to the daemon for dashboard streaming.
|
|
126
129
|
*/
|
|
127
130
|
sendLog(data: string): boolean;
|
|
131
|
+
/**
|
|
132
|
+
* Spawn a new agent via the relay daemon.
|
|
133
|
+
* @param options - Spawn options
|
|
134
|
+
* @param options.name - Name for the new agent
|
|
135
|
+
* @param options.cli - CLI to use (claude, codex, gemini, etc.)
|
|
136
|
+
* @param options.task - Task description
|
|
137
|
+
* @param options.cwd - Working directory
|
|
138
|
+
* @param options.team - Team name
|
|
139
|
+
* @param options.interactive - Interactive mode
|
|
140
|
+
* @param options.shadowOf - Spawn as shadow of this agent
|
|
141
|
+
* @param options.shadowSpeakOn - Shadow speak-on triggers
|
|
142
|
+
* @param timeoutMs - Timeout for spawn operation (default: 30000ms)
|
|
143
|
+
*/
|
|
144
|
+
spawn(options: {
|
|
145
|
+
name: string;
|
|
146
|
+
cli: string;
|
|
147
|
+
task?: string;
|
|
148
|
+
cwd?: string;
|
|
149
|
+
team?: string;
|
|
150
|
+
interactive?: boolean;
|
|
151
|
+
shadowOf?: string;
|
|
152
|
+
shadowSpeakOn?: SpeakOnTrigger[];
|
|
153
|
+
}, timeoutMs?: number): Promise<SpawnResultPayload>;
|
|
154
|
+
/**
|
|
155
|
+
* Release (terminate) an agent via the relay daemon.
|
|
156
|
+
* @param name - Agent name to release
|
|
157
|
+
* @param timeoutMs - Timeout for release operation (default: 10000ms)
|
|
158
|
+
*/
|
|
159
|
+
release(name: string, timeoutMs?: number): Promise<ReleaseResultPayload>;
|
|
128
160
|
/**
|
|
129
161
|
* Join a channel.
|
|
130
162
|
* @param channel - Channel name (e.g., '#general', 'dm:alice:bob')
|
|
@@ -161,6 +193,102 @@ export declare class RelayClient {
|
|
|
161
193
|
attachments?: MessageAttachment[];
|
|
162
194
|
data?: Record<string, unknown>;
|
|
163
195
|
}): boolean;
|
|
196
|
+
/**
|
|
197
|
+
* Create a consensus proposal.
|
|
198
|
+
*
|
|
199
|
+
* The proposal will be broadcast to all participants. They can vote using
|
|
200
|
+
* the `vote()` method. Results are delivered via `onMessage` callback.
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* client.createProposal({
|
|
205
|
+
* title: 'Approve API design',
|
|
206
|
+
* description: 'Should we proceed with the REST API design?',
|
|
207
|
+
* participants: ['Developer', 'Reviewer', 'Lead'],
|
|
208
|
+
* consensusType: 'majority',
|
|
209
|
+
* });
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @param options - Proposal options
|
|
213
|
+
* @returns true if the message was sent
|
|
214
|
+
*/
|
|
215
|
+
createProposal(options: CreateProposalOptions): boolean;
|
|
216
|
+
/**
|
|
217
|
+
* Vote on a consensus proposal.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```typescript
|
|
221
|
+
* // Approve with a reason
|
|
222
|
+
* client.vote({
|
|
223
|
+
* proposalId: 'prop_123',
|
|
224
|
+
* value: 'approve',
|
|
225
|
+
* reason: 'Looks good to me',
|
|
226
|
+
* });
|
|
227
|
+
*
|
|
228
|
+
* // Reject without reason
|
|
229
|
+
* client.vote({ proposalId: 'prop_123', value: 'reject' });
|
|
230
|
+
* ```
|
|
231
|
+
*
|
|
232
|
+
* @param options - Vote options
|
|
233
|
+
* @returns true if the message was sent
|
|
234
|
+
*/
|
|
235
|
+
vote(options: VoteOptions): boolean;
|
|
236
|
+
/**
|
|
237
|
+
* Send a query to the daemon and wait for a response.
|
|
238
|
+
* @internal
|
|
239
|
+
*/
|
|
240
|
+
private query;
|
|
241
|
+
/**
|
|
242
|
+
* Get daemon status information.
|
|
243
|
+
* @returns Daemon status including version, uptime, and counts
|
|
244
|
+
*/
|
|
245
|
+
getStatus(): Promise<StatusResponsePayload>;
|
|
246
|
+
/**
|
|
247
|
+
* Get messages from the inbox.
|
|
248
|
+
* @param options - Filter options
|
|
249
|
+
* @param options.limit - Maximum number of messages to return
|
|
250
|
+
* @param options.unreadOnly - Only return unread messages
|
|
251
|
+
* @param options.from - Filter by sender
|
|
252
|
+
* @param options.channel - Filter by channel
|
|
253
|
+
* @returns Array of inbox messages
|
|
254
|
+
*/
|
|
255
|
+
getInbox(options?: {
|
|
256
|
+
limit?: number;
|
|
257
|
+
unreadOnly?: boolean;
|
|
258
|
+
from?: string;
|
|
259
|
+
channel?: string;
|
|
260
|
+
}): Promise<InboxMessage[]>;
|
|
261
|
+
/**
|
|
262
|
+
* List online agents.
|
|
263
|
+
* @param options - Filter options
|
|
264
|
+
* @param options.includeIdle - Include idle agents (default: true)
|
|
265
|
+
* @param options.project - Filter by project
|
|
266
|
+
* @returns Array of agent info
|
|
267
|
+
*/
|
|
268
|
+
listAgents(options?: {
|
|
269
|
+
includeIdle?: boolean;
|
|
270
|
+
project?: string;
|
|
271
|
+
}): Promise<AgentInfo[]>;
|
|
272
|
+
/**
|
|
273
|
+
* Get system health information.
|
|
274
|
+
* @param options - Include options
|
|
275
|
+
* @param options.includeCrashes - Include crash history (default: true)
|
|
276
|
+
* @param options.includeAlerts - Include alerts (default: true)
|
|
277
|
+
* @returns Health information including score, issues, and recommendations
|
|
278
|
+
*/
|
|
279
|
+
getHealth(options?: {
|
|
280
|
+
includeCrashes?: boolean;
|
|
281
|
+
includeAlerts?: boolean;
|
|
282
|
+
}): Promise<HealthResponsePayload>;
|
|
283
|
+
/**
|
|
284
|
+
* Get resource metrics for agents.
|
|
285
|
+
* @param options - Filter options
|
|
286
|
+
* @param options.agent - Filter to a specific agent
|
|
287
|
+
* @returns Metrics including memory, CPU, and system info
|
|
288
|
+
*/
|
|
289
|
+
getMetrics(options?: {
|
|
290
|
+
agent?: string;
|
|
291
|
+
}): Promise<MetricsResponsePayload>;
|
|
164
292
|
private setState;
|
|
165
293
|
private sendHello;
|
|
166
294
|
private send;
|
|
@@ -171,11 +299,17 @@ export declare class RelayClient {
|
|
|
171
299
|
private handleDeliver;
|
|
172
300
|
private handleChannelMessage;
|
|
173
301
|
private handleAck;
|
|
302
|
+
private handleSpawnResult;
|
|
303
|
+
private handleReleaseResult;
|
|
304
|
+
private handleQueryResponse;
|
|
174
305
|
private handlePing;
|
|
175
306
|
private handleErrorFrame;
|
|
176
307
|
private handleDisconnect;
|
|
177
308
|
private handleError;
|
|
178
309
|
private rejectPendingSyncAcks;
|
|
310
|
+
private rejectPendingSpawns;
|
|
311
|
+
private rejectPendingReleases;
|
|
312
|
+
private rejectPendingQueries;
|
|
179
313
|
private scheduleReconnect;
|
|
180
314
|
}
|
|
181
315
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -73,6 +73,9 @@ export class RelayClient {
|
|
|
73
73
|
writeQueue = [];
|
|
74
74
|
writeScheduled = false;
|
|
75
75
|
pendingSyncAcks = new Map();
|
|
76
|
+
pendingSpawns = new Map();
|
|
77
|
+
pendingReleases = new Map();
|
|
78
|
+
pendingQueries = new Map();
|
|
76
79
|
// Event handlers
|
|
77
80
|
onMessage;
|
|
78
81
|
/**
|
|
@@ -350,6 +353,91 @@ export class RelayClient {
|
|
|
350
353
|
return this.send(envelope);
|
|
351
354
|
}
|
|
352
355
|
// =============================================================================
|
|
356
|
+
// Spawn/Release Operations
|
|
357
|
+
// =============================================================================
|
|
358
|
+
/**
|
|
359
|
+
* Spawn a new agent via the relay daemon.
|
|
360
|
+
* @param options - Spawn options
|
|
361
|
+
* @param options.name - Name for the new agent
|
|
362
|
+
* @param options.cli - CLI to use (claude, codex, gemini, etc.)
|
|
363
|
+
* @param options.task - Task description
|
|
364
|
+
* @param options.cwd - Working directory
|
|
365
|
+
* @param options.team - Team name
|
|
366
|
+
* @param options.interactive - Interactive mode
|
|
367
|
+
* @param options.shadowOf - Spawn as shadow of this agent
|
|
368
|
+
* @param options.shadowSpeakOn - Shadow speak-on triggers
|
|
369
|
+
* @param timeoutMs - Timeout for spawn operation (default: 30000ms)
|
|
370
|
+
*/
|
|
371
|
+
async spawn(options, timeoutMs = 30000) {
|
|
372
|
+
if (this._state !== 'READY') {
|
|
373
|
+
throw new Error('Client not ready');
|
|
374
|
+
}
|
|
375
|
+
const envelopeId = generateId();
|
|
376
|
+
return new Promise((resolve, reject) => {
|
|
377
|
+
const timeoutHandle = setTimeout(() => {
|
|
378
|
+
this.pendingSpawns.delete(envelopeId);
|
|
379
|
+
reject(new Error(`Spawn timeout after ${timeoutMs}ms`));
|
|
380
|
+
}, timeoutMs);
|
|
381
|
+
this.pendingSpawns.set(envelopeId, { resolve, reject, timeoutHandle });
|
|
382
|
+
const envelope = {
|
|
383
|
+
v: PROTOCOL_VERSION,
|
|
384
|
+
type: 'SPAWN',
|
|
385
|
+
id: envelopeId,
|
|
386
|
+
ts: Date.now(),
|
|
387
|
+
payload: {
|
|
388
|
+
name: options.name,
|
|
389
|
+
cli: options.cli,
|
|
390
|
+
task: options.task || '',
|
|
391
|
+
cwd: options.cwd,
|
|
392
|
+
team: options.team,
|
|
393
|
+
interactive: options.interactive,
|
|
394
|
+
shadowOf: options.shadowOf,
|
|
395
|
+
shadowSpeakOn: options.shadowSpeakOn,
|
|
396
|
+
spawnerName: this.config.agentName,
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
const sent = this.send(envelope);
|
|
400
|
+
if (!sent) {
|
|
401
|
+
clearTimeout(timeoutHandle);
|
|
402
|
+
this.pendingSpawns.delete(envelopeId);
|
|
403
|
+
reject(new Error('Failed to send spawn message'));
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Release (terminate) an agent via the relay daemon.
|
|
409
|
+
* @param name - Agent name to release
|
|
410
|
+
* @param timeoutMs - Timeout for release operation (default: 10000ms)
|
|
411
|
+
*/
|
|
412
|
+
async release(name, timeoutMs = 10000) {
|
|
413
|
+
if (this._state !== 'READY') {
|
|
414
|
+
throw new Error('Client not ready');
|
|
415
|
+
}
|
|
416
|
+
const envelopeId = generateId();
|
|
417
|
+
return new Promise((resolve, reject) => {
|
|
418
|
+
const timeoutHandle = setTimeout(() => {
|
|
419
|
+
this.pendingReleases.delete(envelopeId);
|
|
420
|
+
reject(new Error(`Release timeout after ${timeoutMs}ms`));
|
|
421
|
+
}, timeoutMs);
|
|
422
|
+
this.pendingReleases.set(envelopeId, { resolve, reject, timeoutHandle });
|
|
423
|
+
const envelope = {
|
|
424
|
+
v: PROTOCOL_VERSION,
|
|
425
|
+
type: 'RELEASE',
|
|
426
|
+
id: envelopeId,
|
|
427
|
+
ts: Date.now(),
|
|
428
|
+
payload: {
|
|
429
|
+
name,
|
|
430
|
+
},
|
|
431
|
+
};
|
|
432
|
+
const sent = this.send(envelope);
|
|
433
|
+
if (!sent) {
|
|
434
|
+
clearTimeout(timeoutHandle);
|
|
435
|
+
this.pendingReleases.delete(envelopeId);
|
|
436
|
+
reject(new Error('Failed to send release message'));
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
// =============================================================================
|
|
353
441
|
// Channel Operations
|
|
354
442
|
// =============================================================================
|
|
355
443
|
/**
|
|
@@ -461,6 +549,188 @@ export class RelayClient {
|
|
|
461
549
|
};
|
|
462
550
|
return this.send(envelope);
|
|
463
551
|
}
|
|
552
|
+
// =============================================================================
|
|
553
|
+
// Consensus Operations
|
|
554
|
+
// =============================================================================
|
|
555
|
+
/**
|
|
556
|
+
* Create a consensus proposal.
|
|
557
|
+
*
|
|
558
|
+
* The proposal will be broadcast to all participants. They can vote using
|
|
559
|
+
* the `vote()` method. Results are delivered via `onMessage` callback.
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```typescript
|
|
563
|
+
* client.createProposal({
|
|
564
|
+
* title: 'Approve API design',
|
|
565
|
+
* description: 'Should we proceed with the REST API design?',
|
|
566
|
+
* participants: ['Developer', 'Reviewer', 'Lead'],
|
|
567
|
+
* consensusType: 'majority',
|
|
568
|
+
* });
|
|
569
|
+
* ```
|
|
570
|
+
*
|
|
571
|
+
* @param options - Proposal options
|
|
572
|
+
* @returns true if the message was sent
|
|
573
|
+
*/
|
|
574
|
+
createProposal(options) {
|
|
575
|
+
if (this._state !== 'READY') {
|
|
576
|
+
return false;
|
|
577
|
+
}
|
|
578
|
+
// Build the PROPOSE command message
|
|
579
|
+
const lines = [
|
|
580
|
+
`PROPOSE: ${options.title}`,
|
|
581
|
+
`TYPE: ${options.consensusType ?? 'majority'}`,
|
|
582
|
+
`PARTICIPANTS: ${options.participants.join(', ')}`,
|
|
583
|
+
`DESCRIPTION: ${options.description}`,
|
|
584
|
+
];
|
|
585
|
+
if (options.timeoutMs !== undefined) {
|
|
586
|
+
lines.push(`TIMEOUT: ${options.timeoutMs}`);
|
|
587
|
+
}
|
|
588
|
+
if (options.quorum !== undefined) {
|
|
589
|
+
lines.push(`QUORUM: ${options.quorum}`);
|
|
590
|
+
}
|
|
591
|
+
if (options.threshold !== undefined) {
|
|
592
|
+
lines.push(`THRESHOLD: ${options.threshold}`);
|
|
593
|
+
}
|
|
594
|
+
const body = lines.join('\n');
|
|
595
|
+
// Send to the special _consensus recipient
|
|
596
|
+
return this.sendMessage('_consensus', body, 'action');
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Vote on a consensus proposal.
|
|
600
|
+
*
|
|
601
|
+
* @example
|
|
602
|
+
* ```typescript
|
|
603
|
+
* // Approve with a reason
|
|
604
|
+
* client.vote({
|
|
605
|
+
* proposalId: 'prop_123',
|
|
606
|
+
* value: 'approve',
|
|
607
|
+
* reason: 'Looks good to me',
|
|
608
|
+
* });
|
|
609
|
+
*
|
|
610
|
+
* // Reject without reason
|
|
611
|
+
* client.vote({ proposalId: 'prop_123', value: 'reject' });
|
|
612
|
+
* ```
|
|
613
|
+
*
|
|
614
|
+
* @param options - Vote options
|
|
615
|
+
* @returns true if the message was sent
|
|
616
|
+
*/
|
|
617
|
+
vote(options) {
|
|
618
|
+
if (this._state !== 'READY') {
|
|
619
|
+
return false;
|
|
620
|
+
}
|
|
621
|
+
// Build the VOTE command
|
|
622
|
+
let body = `VOTE ${options.proposalId} ${options.value}`;
|
|
623
|
+
if (options.reason) {
|
|
624
|
+
body += ` ${options.reason}`;
|
|
625
|
+
}
|
|
626
|
+
// Send to the special _consensus recipient
|
|
627
|
+
return this.sendMessage('_consensus', body, 'action');
|
|
628
|
+
}
|
|
629
|
+
// =============================================================================
|
|
630
|
+
// Query Operations
|
|
631
|
+
// =============================================================================
|
|
632
|
+
/**
|
|
633
|
+
* Send a query to the daemon and wait for a response.
|
|
634
|
+
* @internal
|
|
635
|
+
*/
|
|
636
|
+
async query(type, payload, timeoutMs = 5000) {
|
|
637
|
+
if (this._state !== 'READY') {
|
|
638
|
+
throw new Error('Client not ready');
|
|
639
|
+
}
|
|
640
|
+
const envelopeId = generateId();
|
|
641
|
+
return new Promise((resolve, reject) => {
|
|
642
|
+
const timeoutHandle = setTimeout(() => {
|
|
643
|
+
this.pendingQueries.delete(envelopeId);
|
|
644
|
+
reject(new Error(`Query timeout after ${timeoutMs}ms`));
|
|
645
|
+
}, timeoutMs);
|
|
646
|
+
this.pendingQueries.set(envelopeId, {
|
|
647
|
+
resolve: resolve,
|
|
648
|
+
reject,
|
|
649
|
+
timeoutHandle,
|
|
650
|
+
});
|
|
651
|
+
const envelope = {
|
|
652
|
+
v: PROTOCOL_VERSION,
|
|
653
|
+
type: type,
|
|
654
|
+
id: envelopeId,
|
|
655
|
+
ts: Date.now(),
|
|
656
|
+
payload,
|
|
657
|
+
};
|
|
658
|
+
const sent = this.send(envelope);
|
|
659
|
+
if (!sent) {
|
|
660
|
+
clearTimeout(timeoutHandle);
|
|
661
|
+
this.pendingQueries.delete(envelopeId);
|
|
662
|
+
reject(new Error(`Failed to send ${type} query`));
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Get daemon status information.
|
|
668
|
+
* @returns Daemon status including version, uptime, and counts
|
|
669
|
+
*/
|
|
670
|
+
async getStatus() {
|
|
671
|
+
return this.query('STATUS', {});
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Get messages from the inbox.
|
|
675
|
+
* @param options - Filter options
|
|
676
|
+
* @param options.limit - Maximum number of messages to return
|
|
677
|
+
* @param options.unreadOnly - Only return unread messages
|
|
678
|
+
* @param options.from - Filter by sender
|
|
679
|
+
* @param options.channel - Filter by channel
|
|
680
|
+
* @returns Array of inbox messages
|
|
681
|
+
*/
|
|
682
|
+
async getInbox(options = {}) {
|
|
683
|
+
const payload = {
|
|
684
|
+
agent: this.config.agentName,
|
|
685
|
+
limit: options.limit,
|
|
686
|
+
unreadOnly: options.unreadOnly,
|
|
687
|
+
from: options.from,
|
|
688
|
+
channel: options.channel,
|
|
689
|
+
};
|
|
690
|
+
const response = await this.query('INBOX', payload);
|
|
691
|
+
return response.messages || [];
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* List online agents.
|
|
695
|
+
* @param options - Filter options
|
|
696
|
+
* @param options.includeIdle - Include idle agents (default: true)
|
|
697
|
+
* @param options.project - Filter by project
|
|
698
|
+
* @returns Array of agent info
|
|
699
|
+
*/
|
|
700
|
+
async listAgents(options = {}) {
|
|
701
|
+
const payload = {
|
|
702
|
+
includeIdle: options.includeIdle ?? true,
|
|
703
|
+
project: options.project,
|
|
704
|
+
};
|
|
705
|
+
const response = await this.query('LIST_AGENTS', payload);
|
|
706
|
+
return response.agents || [];
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Get system health information.
|
|
710
|
+
* @param options - Include options
|
|
711
|
+
* @param options.includeCrashes - Include crash history (default: true)
|
|
712
|
+
* @param options.includeAlerts - Include alerts (default: true)
|
|
713
|
+
* @returns Health information including score, issues, and recommendations
|
|
714
|
+
*/
|
|
715
|
+
async getHealth(options = {}) {
|
|
716
|
+
const payload = {
|
|
717
|
+
includeCrashes: options.includeCrashes ?? true,
|
|
718
|
+
includeAlerts: options.includeAlerts ?? true,
|
|
719
|
+
};
|
|
720
|
+
return this.query('HEALTH', payload);
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Get resource metrics for agents.
|
|
724
|
+
* @param options - Filter options
|
|
725
|
+
* @param options.agent - Filter to a specific agent
|
|
726
|
+
* @returns Metrics including memory, CPU, and system info
|
|
727
|
+
*/
|
|
728
|
+
async getMetrics(options = {}) {
|
|
729
|
+
const payload = {
|
|
730
|
+
agent: options.agent,
|
|
731
|
+
};
|
|
732
|
+
return this.query('METRICS', payload);
|
|
733
|
+
}
|
|
464
734
|
// Private methods
|
|
465
735
|
setState(state) {
|
|
466
736
|
this._state = state;
|
|
@@ -552,6 +822,12 @@ export class RelayClient {
|
|
|
552
822
|
case 'ACK':
|
|
553
823
|
this.handleAck(envelope);
|
|
554
824
|
break;
|
|
825
|
+
case 'SPAWN_RESULT':
|
|
826
|
+
this.handleSpawnResult(envelope);
|
|
827
|
+
break;
|
|
828
|
+
case 'RELEASE_RESULT':
|
|
829
|
+
this.handleReleaseResult(envelope);
|
|
830
|
+
break;
|
|
555
831
|
case 'ERROR':
|
|
556
832
|
this.handleErrorFrame(envelope);
|
|
557
833
|
break;
|
|
@@ -560,6 +836,13 @@ export class RelayClient {
|
|
|
560
836
|
console.warn('[sdk] Server busy, backing off');
|
|
561
837
|
}
|
|
562
838
|
break;
|
|
839
|
+
case 'STATUS_RESPONSE':
|
|
840
|
+
case 'INBOX_RESPONSE':
|
|
841
|
+
case 'LIST_AGENTS_RESPONSE':
|
|
842
|
+
case 'HEALTH_RESPONSE':
|
|
843
|
+
case 'METRICS_RESPONSE':
|
|
844
|
+
this.handleQueryResponse(envelope);
|
|
845
|
+
break;
|
|
563
846
|
}
|
|
564
847
|
}
|
|
565
848
|
handleWelcome(envelope) {
|
|
@@ -627,6 +910,37 @@ export class RelayClient {
|
|
|
627
910
|
this.pendingSyncAcks.delete(correlationId);
|
|
628
911
|
pending.resolve(envelope.payload);
|
|
629
912
|
}
|
|
913
|
+
handleSpawnResult(envelope) {
|
|
914
|
+
const replyTo = envelope.payload.replyTo;
|
|
915
|
+
if (!replyTo)
|
|
916
|
+
return;
|
|
917
|
+
const pending = this.pendingSpawns.get(replyTo);
|
|
918
|
+
if (!pending)
|
|
919
|
+
return;
|
|
920
|
+
clearTimeout(pending.timeoutHandle);
|
|
921
|
+
this.pendingSpawns.delete(replyTo);
|
|
922
|
+
pending.resolve(envelope.payload);
|
|
923
|
+
}
|
|
924
|
+
handleReleaseResult(envelope) {
|
|
925
|
+
const replyTo = envelope.payload.replyTo;
|
|
926
|
+
if (!replyTo)
|
|
927
|
+
return;
|
|
928
|
+
const pending = this.pendingReleases.get(replyTo);
|
|
929
|
+
if (!pending)
|
|
930
|
+
return;
|
|
931
|
+
clearTimeout(pending.timeoutHandle);
|
|
932
|
+
this.pendingReleases.delete(replyTo);
|
|
933
|
+
pending.resolve(envelope.payload);
|
|
934
|
+
}
|
|
935
|
+
handleQueryResponse(envelope) {
|
|
936
|
+
// Query responses use the envelope id to match requests
|
|
937
|
+
const pending = this.pendingQueries.get(envelope.id);
|
|
938
|
+
if (!pending)
|
|
939
|
+
return;
|
|
940
|
+
clearTimeout(pending.timeoutHandle);
|
|
941
|
+
this.pendingQueries.delete(envelope.id);
|
|
942
|
+
pending.resolve(envelope.payload);
|
|
943
|
+
}
|
|
630
944
|
handlePing(envelope) {
|
|
631
945
|
this.send({
|
|
632
946
|
v: PROTOCOL_VERSION,
|
|
@@ -656,6 +970,9 @@ export class RelayClient {
|
|
|
656
970
|
this.parser.reset();
|
|
657
971
|
this.socket = undefined;
|
|
658
972
|
this.rejectPendingSyncAcks(new Error('Disconnected while awaiting ACK'));
|
|
973
|
+
this.rejectPendingSpawns(new Error('Disconnected while awaiting spawn result'));
|
|
974
|
+
this.rejectPendingReleases(new Error('Disconnected while awaiting release result'));
|
|
975
|
+
this.rejectPendingQueries(new Error('Disconnected while awaiting query response'));
|
|
659
976
|
if (this._destroyed) {
|
|
660
977
|
this.setState('DISCONNECTED');
|
|
661
978
|
return;
|
|
@@ -685,6 +1002,27 @@ export class RelayClient {
|
|
|
685
1002
|
this.pendingSyncAcks.delete(correlationId);
|
|
686
1003
|
}
|
|
687
1004
|
}
|
|
1005
|
+
rejectPendingSpawns(error) {
|
|
1006
|
+
for (const [id, pending] of this.pendingSpawns.entries()) {
|
|
1007
|
+
clearTimeout(pending.timeoutHandle);
|
|
1008
|
+
pending.reject(error);
|
|
1009
|
+
this.pendingSpawns.delete(id);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
rejectPendingReleases(error) {
|
|
1013
|
+
for (const [id, pending] of this.pendingReleases.entries()) {
|
|
1014
|
+
clearTimeout(pending.timeoutHandle);
|
|
1015
|
+
pending.reject(error);
|
|
1016
|
+
this.pendingReleases.delete(id);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
rejectPendingQueries(error) {
|
|
1020
|
+
for (const [id, pending] of this.pendingQueries.entries()) {
|
|
1021
|
+
clearTimeout(pending.timeoutHandle);
|
|
1022
|
+
pending.reject(error);
|
|
1023
|
+
this.pendingQueries.delete(id);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
688
1026
|
scheduleReconnect() {
|
|
689
1027
|
this.setState('BACKOFF');
|
|
690
1028
|
this.reconnectAttempts++;
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
*/
|
|
28
28
|
export { RelayClient, type ClientState, type ClientConfig, type SyncOptions, } from './client.js';
|
|
29
29
|
export { createRelay, createPair, type Relay, type RelayConfig, } from './standalone.js';
|
|
30
|
-
export { PROTOCOL_VERSION, type MessageType, type PayloadKind, type Envelope, type EntityType, type SendPayload, type SendMeta, type SyncMeta, type DeliveryInfo, type AckPayload, type ErrorCode, type ErrorPayload, type SpeakOnTrigger, type ShadowConfig, type SpawnPayload, type SpawnResultPayload, type ReleasePayload, type ReleaseResultPayload, type ChannelMessagePayload, type ChannelJoinPayload, type ChannelLeavePayload, } from './protocol/index.js';
|
|
30
|
+
export { PROTOCOL_VERSION, type MessageType, type PayloadKind, type Envelope, type EntityType, type SendPayload, type SendMeta, type SyncMeta, type DeliveryInfo, type AckPayload, type ErrorCode, type ErrorPayload, type SpeakOnTrigger, type ShadowConfig, type SpawnPayload, type SpawnResultPayload, type ReleasePayload, type ReleaseResultPayload, type ChannelMessagePayload, type ChannelJoinPayload, type ChannelLeavePayload, type MessageAttachment, type StatusResponsePayload, type InboxMessage, type AgentInfo, type HealthResponsePayload, type CrashRecord, type AlertRecord, type MetricsResponsePayload, type AgentMetrics, type ConsensusType, type VoteValue, type ProposalStatus, type CreateProposalOptions, type VoteOptions, } from './protocol/index.js';
|
|
31
31
|
export { encodeFrame, encodeFrameLegacy, FrameParser, MAX_FRAME_BYTES, } from './protocol/index.js';
|
|
32
|
+
export { getLogs, listLoggedAgents, type GetLogsOptions, type LogsResult, } from './logs.js';
|
|
32
33
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -33,4 +33,6 @@ export { createRelay, createPair, } from './standalone.js';
|
|
|
33
33
|
export { PROTOCOL_VERSION, } from './protocol/index.js';
|
|
34
34
|
// Framing utilities
|
|
35
35
|
export { encodeFrame, encodeFrameLegacy, FrameParser, MAX_FRAME_BYTES, } from './protocol/index.js';
|
|
36
|
+
// Log utilities (file-based, doesn't require connection)
|
|
37
|
+
export { getLogs, listLoggedAgents, } from './logs.js';
|
|
36
38
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log reading utilities for Agent Relay SDK.
|
|
3
|
+
*
|
|
4
|
+
* These utilities read agent logs from the local filesystem.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Options for reading agent logs.
|
|
8
|
+
*/
|
|
9
|
+
export interface GetLogsOptions {
|
|
10
|
+
/** Directory containing worker logs. Defaults to `.agent-relay/worker-logs` in cwd. */
|
|
11
|
+
logsDir?: string;
|
|
12
|
+
/** Number of lines to return from the end. Default: 50 */
|
|
13
|
+
lines?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Result of a logs query.
|
|
17
|
+
*/
|
|
18
|
+
export interface LogsResult {
|
|
19
|
+
/** Agent name */
|
|
20
|
+
agent: string;
|
|
21
|
+
/** Log content */
|
|
22
|
+
content: string;
|
|
23
|
+
/** Whether log file exists */
|
|
24
|
+
found: boolean;
|
|
25
|
+
/** Number of lines returned */
|
|
26
|
+
lineCount: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get logs for a specific agent.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { getLogs } from '@agent-relay/sdk';
|
|
34
|
+
*
|
|
35
|
+
* const result = await getLogs('Worker1', { lines: 100 });
|
|
36
|
+
* if (result.found) {
|
|
37
|
+
* console.log(result.content);
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @param agent - Agent name
|
|
42
|
+
* @param options - Options for reading logs
|
|
43
|
+
* @returns Log content and metadata
|
|
44
|
+
*/
|
|
45
|
+
export declare function getLogs(agent: string, options?: GetLogsOptions): Promise<LogsResult>;
|
|
46
|
+
/**
|
|
47
|
+
* List all agents that have log files.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import { listLoggedAgents } from '@agent-relay/sdk';
|
|
52
|
+
*
|
|
53
|
+
* const agents = await listLoggedAgents();
|
|
54
|
+
* console.log('Agents with logs:', agents);
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @param logsDir - Directory containing worker logs
|
|
58
|
+
* @returns Array of agent names
|
|
59
|
+
*/
|
|
60
|
+
export declare function listLoggedAgents(logsDir?: string): Promise<string[]>;
|
|
61
|
+
//# sourceMappingURL=logs.d.ts.map
|