agent-relay-server 0.4.39 → 0.6.0

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/src/security.ts CHANGED
@@ -95,7 +95,8 @@ export function requiredScopeFor(method: string, pathname: string): string | nul
95
95
  if (pathname === "/api/stats") return "stats:read";
96
96
  if (pathname === "/api/health") return "health:read";
97
97
  if (pathname === "/api/events") return "events:read";
98
- if (pathname === "/api/channels") return "channels:read";
98
+ if (pathname === "/api/connectors" || pathname.startsWith("/api/connectors/")) return method === "GET" ? "connectors:read" : "system:write";
99
+ if (pathname.startsWith("/api/channels") || pathname.startsWith("/api/channel-bindings")) return method === "GET" ? "channels:read" : "channels:write";
99
100
  if (pathname === "/api/integrations" || pathname.startsWith("/api/integrations/")) return method === "GET" ? "integrations:read" : "integrations:write";
100
101
  if (pathname.startsWith("/api/agents")) return method === "GET" ? "agents:read" : "agents:write";
101
102
  if (pathname.startsWith("/api/activity")) return method === "GET" ? "activity:read" : "activity:write";
package/src/sse.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { getAgent } from "./db";
1
+ import { getAgent, getOrchestrator } from "./db";
2
2
  import type { Message, Task } from "./types";
3
3
 
4
4
  interface Connection {
@@ -122,6 +122,12 @@ export function emitTaskChanged(task: Task, eventType = "task.updated") {
122
122
  }
123
123
  }
124
124
 
125
+ export function emitChannelActivity(activity: Record<string, unknown>) {
126
+ for (const conn of connections.values()) {
127
+ send(conn, "channel.activity", activity);
128
+ }
129
+ }
130
+
125
131
  export function getConnectionCount(): number {
126
132
  return connections.size;
127
133
  }
@@ -135,3 +141,17 @@ function targetMatchesAgent(target: string, agentId: string): boolean {
135
141
  if (target.startsWith("label:") && agent.label === target.slice(6)) return true;
136
142
  return false;
137
143
  }
144
+
145
+ export function emitOrchestratorStatus(orchestratorId: string) {
146
+ const orch = getOrchestrator(orchestratorId);
147
+ const data = orch ?? { id: orchestratorId, status: "offline" };
148
+ for (const conn of connections.values()) {
149
+ send(conn, "orchestrator.status", data);
150
+ }
151
+ }
152
+
153
+ export function emitOrchestratorRemoved(orchestratorId: string) {
154
+ for (const conn of connections.values()) {
155
+ send(conn, "orchestrator.removed", { id: orchestratorId });
156
+ }
157
+ }
package/src/types.ts CHANGED
@@ -1,6 +1,9 @@
1
+ export type AgentKind = "provider" | "channel" | "orchestrator" | "system" | "user";
2
+
1
3
  export interface AgentCard {
2
4
  id: string;
3
5
  name: string;
6
+ kind: AgentKind;
4
7
  label?: string; // human-friendly alias; acts as a fan-out target ("label:foo")
5
8
  tags: string[];
6
9
  machine?: string;
@@ -15,13 +18,19 @@ export interface AgentCard {
15
18
  createdAt: number;
16
19
  }
17
20
 
18
- export type MessageType = "message" | "system";
21
+ export type MessageKind =
22
+ | "chat"
23
+ | "channel.event"
24
+ | "task"
25
+ | "pair"
26
+ | "control"
27
+ | "system";
19
28
 
20
29
  export interface Message {
21
30
  id: number;
22
31
  from: string;
23
32
  to: string; // agent-id | "tag:<name>" | "broadcast" | "cap:<name>"
24
- type: MessageType;
33
+ kind: MessageKind;
25
34
  channel?: string;
26
35
  subject?: string;
27
36
  body: string;
@@ -32,6 +41,7 @@ export interface Message {
32
41
  claimedAt?: number;
33
42
  claimExpiresAt?: number;
34
43
  idempotencyKey?: string;
44
+ payload: Record<string, unknown>;
35
45
  meta?: Record<string, unknown>;
36
46
  readBy: string[];
37
47
  createdAt: number;
@@ -40,16 +50,71 @@ export interface Message {
40
50
  export interface SendMessageInput {
41
51
  from: string;
42
52
  to: string;
43
- type?: MessageType;
53
+ kind?: MessageKind;
44
54
  channel?: string;
45
55
  subject?: string;
46
56
  body: string;
47
57
  replyTo?: number;
48
58
  claimable?: boolean;
49
59
  idempotencyKey?: string;
60
+ payload?: Record<string, unknown>;
50
61
  meta?: Record<string, unknown>;
51
62
  }
52
63
 
64
+ export type ConnectorKind = "channel" | "event" | "provider" | "orchestrator";
65
+ export type ConnectorAction = "install" | "uninstall" | "enable" | "disable" | "start" | "stop" | "restart" | "status" | "doctor";
66
+
67
+ export interface ConnectorManifest {
68
+ schema: "agent-relay.connector.v1";
69
+ id: string;
70
+ kind: ConnectorKind;
71
+ packageName?: string;
72
+ binary: string;
73
+ displayName: string;
74
+ description?: string;
75
+ version: string;
76
+ capabilities: string[];
77
+ commands: Partial<Record<ConnectorAction, string[]>>;
78
+ configSchema?: Record<string, unknown>;
79
+ }
80
+
81
+ interface ConnectorRuntime {
82
+ installed: boolean;
83
+ enabled?: boolean;
84
+ running?: boolean;
85
+ status?: "ok" | "warn" | "error" | "unknown";
86
+ detail?: string;
87
+ updatedAt?: string;
88
+ raw?: unknown;
89
+ }
90
+
91
+ export interface ConnectorSummary {
92
+ id: string;
93
+ kind: ConnectorKind;
94
+ displayName: string;
95
+ description?: string;
96
+ version: string;
97
+ packageName?: string;
98
+ binary: string;
99
+ capabilities: string[];
100
+ registryPath: string;
101
+ manifest: ConnectorManifest;
102
+ config?: Record<string, unknown>;
103
+ state?: Record<string, unknown>;
104
+ runtime: ConnectorRuntime;
105
+ }
106
+
107
+ export interface ConnectorActionResult {
108
+ connectorId: string;
109
+ action: ConnectorAction;
110
+ command?: string[];
111
+ ok: boolean;
112
+ exitCode?: number | null;
113
+ stdout?: string;
114
+ stderr?: string;
115
+ parsed?: unknown;
116
+ }
117
+
53
118
  export type PairStatus = "pending" | "active" | "ended" | "rejected" | "expired";
54
119
 
55
120
  export interface PairSession {
@@ -99,6 +164,7 @@ export interface PollQuery {
99
164
  export interface RegisterAgentInput {
100
165
  id: string;
101
166
  name: string;
167
+ kind?: AgentKind;
102
168
  label?: string | null;
103
169
  tags?: string[];
104
170
  machine?: string;
@@ -203,16 +269,39 @@ export interface IntegrationSummary {
203
269
 
204
270
  export type ChannelDirection = "inbound" | "outbound" | "bidirectional";
205
271
 
272
+ export type ChannelRouteTarget =
273
+ | { type: "agent"; id: string }
274
+ | { type: "label"; id: string }
275
+ | { type: "tag"; id: string }
276
+ | { type: "capability"; id: string }
277
+ | { type: "broadcast" }
278
+ | { type: "orchestrator"; id: string };
279
+
280
+ export type ChannelBindingMode = "exclusive" | "claimable" | "broadcast";
281
+
282
+ export interface ChannelBinding {
283
+ id: string;
284
+ channelId: string;
285
+ conversationId?: string;
286
+ target: ChannelRouteTarget;
287
+ mode: ChannelBindingMode;
288
+ priority: number;
289
+ createdAt: number;
290
+ updatedAt: number;
291
+ }
292
+
206
293
  export interface ChannelSummary {
207
294
  id: string;
208
295
  name: string;
209
296
  type: string;
210
297
  transport: string;
211
298
  agentId: string;
299
+ accountId: string;
212
300
  status: AgentCard["status"];
213
301
  ready: boolean;
214
302
  direction: ChannelDirection;
215
303
  target?: string;
304
+ binding?: ChannelBinding;
216
305
  topicChannels: string[];
217
306
  capabilities: string[];
218
307
  tags: string[];
@@ -291,6 +380,66 @@ export interface ActivityEventInput {
291
380
  metadata?: Record<string, unknown>;
292
381
  }
293
382
 
383
+ // --- Orchestrators ---
384
+
385
+ export type OrchestratorStatus = "online" | "offline";
386
+ export type SpawnProvider = "claude" | "codex";
387
+ export type SpawnApprovalMode = "open" | "guarded" | "read-only";
388
+
389
+ export interface Orchestrator {
390
+ id: string;
391
+ hostname: string;
392
+ status: OrchestratorStatus;
393
+ agentId: string; // relay agent id for messaging
394
+ providers: SpawnProvider[];
395
+ baseDir: string;
396
+ envKeys: string[]; // names only, never values
397
+ meta: Record<string, unknown>;
398
+ managedAgents: ManagedAgent[];
399
+ lastSeen: number;
400
+ createdAt: number;
401
+ }
402
+
403
+ export interface ManagedAgent {
404
+ agentId: string;
405
+ provider: SpawnProvider;
406
+ tmuxSession: string;
407
+ cwd: string;
408
+ label?: string;
409
+ approvalMode: SpawnApprovalMode;
410
+ pid?: number;
411
+ startedAt: number;
412
+ }
413
+
414
+ export interface RegisterOrchestratorInput {
415
+ id: string;
416
+ hostname: string;
417
+ providers: SpawnProvider[];
418
+ baseDir: string;
419
+ envKeys?: string[];
420
+ meta?: Record<string, unknown>;
421
+ }
422
+
423
+ export interface OrchestratorSpawnInput {
424
+ provider: SpawnProvider;
425
+ cwd?: string;
426
+ label?: string;
427
+ approvalMode?: SpawnApprovalMode;
428
+ prompt?: string;
429
+ env?: Record<string, string>;
430
+ }
431
+
432
+ export interface OrchestratorSpawnResult {
433
+ orchestratorId: string;
434
+ provider: SpawnProvider;
435
+ tmuxSession: string;
436
+ cwd: string;
437
+ label?: string;
438
+ approvalMode: SpawnApprovalMode;
439
+ pid?: number;
440
+ startedAt: number;
441
+ }
442
+
294
443
  export interface HealthCheck {
295
444
  name: string;
296
445
  status: "ok" | "warn" | "error";