agent-relay-server 0.10.13 → 0.10.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-server",
3
- "version": "0.10.13",
3
+ "version": "0.10.15",
4
4
  "description": "Lightweight HTTP message relay for inter-agent communication across machines",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",
package/src/bus.ts CHANGED
@@ -234,6 +234,7 @@ function handleRegister(ws: BusWebSocket, frame: RegisterFrame): void {
234
234
  getLifecycleManager().onAgentRegistered(agent.id, {
235
235
  policyName: stringMeta(payload.meta, "policyName"),
236
236
  spawnRequestId: stringMeta(payload.meta, "spawnRequestId"),
237
+ tmuxSession: stringMeta(payload.meta, "tmuxSession"),
237
238
  });
238
239
  emitAgentStatusEvent(agent.id);
239
240
  }
@@ -359,6 +360,7 @@ function messageMatchesAgent(msg: Message, agentId: string): boolean {
359
360
  const agent = getAgent(agentId);
360
361
  if (!agent) return false;
361
362
  if (msg.claimable && msg.claimedBy && msg.claimedBy !== agentId) return false;
363
+ if (msg.resolvedToAgent === agentId) return true;
362
364
  if (msg.to === agentId || msg.from === agentId) return true;
363
365
  return targetMatchesAgent(msg.to, agentId, agent);
364
366
  }
@@ -7,7 +7,7 @@ import {
7
7
  upsertManagedAgentState,
8
8
  } from "./config-store";
9
9
  import { emitRelayEvent } from "./events";
10
- import type { Command, ManagedAgentState, SpawnPolicy } from "./types";
10
+ import type { Command, ManagedAgent, ManagedAgentState, SpawnPolicy } from "./types";
11
11
 
12
12
  const DEFAULT_TICK_MS = 10_000;
13
13
  const DAY_MS = 24 * 60 * 60 * 1000;
@@ -58,13 +58,14 @@ export class LifecycleManager {
58
58
  this.spawnAgent(policy, "message-trigger");
59
59
  }
60
60
 
61
- onAgentRegistered(agentId: string, meta: { policyName?: string; spawnRequestId?: string }): void {
61
+ onAgentRegistered(agentId: string, meta: { policyName?: string; spawnRequestId?: string; tmuxSession?: string | null }): void {
62
62
  if (!meta.policyName || !meta.spawnRequestId) return;
63
63
  const state = getManagedAgentState(meta.policyName);
64
64
  if (!state || state.spawnRequestId !== meta.spawnRequestId) return;
65
65
  const next = updateManagedAgentState(meta.policyName, {
66
66
  status: "running",
67
67
  agentId,
68
+ tmuxSession: meta.tmuxSession ?? state.tmuxSession,
68
69
  healthySince: this.now(),
69
70
  backoffUntil: undefined,
70
71
  lastError: undefined,
@@ -81,6 +82,42 @@ export class LifecycleManager {
81
82
  }
82
83
  }
83
84
 
85
+ onOrchestratorManagedAgentsReported(orchestratorId: string, agents: ManagedAgent[]): void {
86
+ for (const agent of agents) {
87
+ if (!agent.policyName || !agent.spawnRequestId) continue;
88
+ const state = getManagedAgentState(agent.policyName);
89
+ if (!state || state.spawnRequestId !== agent.spawnRequestId) continue;
90
+ const next = updateManagedAgentState(agent.policyName, {
91
+ agentId: agent.agentId || state.agentId,
92
+ tmuxSession: agent.tmuxSession,
93
+ });
94
+ if (next) this.emitState(next);
95
+ }
96
+
97
+ for (const policy of this.loadPolicies()) {
98
+ if (policy.orchestratorId !== orchestratorId) continue;
99
+ const state = getManagedAgentState(policy.name);
100
+ if (!state) continue;
101
+ const reported = agents.some((agent) => (
102
+ (state.spawnRequestId && agent.spawnRequestId === state.spawnRequestId) ||
103
+ (state.agentId && agent.agentId === state.agentId) ||
104
+ (state.tmuxSession && agent.tmuxSession === state.tmuxSession) ||
105
+ (agent.policyName === policy.name && (!state.spawnRequestId || agent.spawnRequestId === state.spawnRequestId))
106
+ ));
107
+ if (state.status === "running" && !reported) {
108
+ this.markBackoff(policy, state, "orchestrator session disappeared");
109
+ } else if (state.status === "stopping" && !reported) {
110
+ const next = updateManagedAgentState(policy.name, {
111
+ status: "stopped",
112
+ agentId: undefined,
113
+ tmuxSession: undefined,
114
+ lastStopAt: this.now(),
115
+ });
116
+ if (next) this.emitState(next);
117
+ }
118
+ }
119
+ }
120
+
84
121
  onAgentDisappeared(agentId: string): void {
85
122
  const policy = this.loadPolicies().find((item) => getManagedAgentState(item.name)?.agentId === agentId);
86
123
  if (!policy) return;
package/src/routes.ts CHANGED
@@ -81,6 +81,7 @@ import {
81
81
  updateManagedAgentState,
82
82
  } from "./config-store";
83
83
  import { createCommand, deleteCommand, expireCommands, getCommand, listCommands, updateCommand } from "./commands-db";
84
+ import { getLifecycleManager } from "./lifecycle-manager";
84
85
  import { getRecipe, listRecipes } from "./recipe-loader";
85
86
  import { applyCommandToRecipe, getRecipeInstance, listRecipeInstances, startRecipe, stopRecipe } from "./recipe-runner";
86
87
  import { createToken, getToken, listTokens, revokeToken } from "./token-db";
@@ -959,12 +960,14 @@ const postAgent: Handler = async (req) => {
959
960
  const agent = upsertAgent(input);
960
961
  const policyName = metaString(agent.meta, "policyName");
961
962
  const spawnRequestId = metaString(agent.meta, "spawnRequestId");
963
+ const tmuxSession = metaString(agent.meta, "tmuxSession");
962
964
  if (policyName && spawnRequestId) {
963
965
  const state = getManagedAgentState(policyName);
964
966
  if (state?.spawnRequestId === spawnRequestId) {
965
967
  const updatedState = updateManagedAgentState(policyName, {
966
968
  status: "running",
967
969
  agentId: agent.id,
970
+ tmuxSession: tmuxSession ?? state.tmuxSession,
968
971
  healthySince: Date.now(),
969
972
  lastError: undefined,
970
973
  });
@@ -1454,11 +1457,14 @@ const patchOrchestratorAgents: Handler = async (req, params) => {
1454
1457
  cwd: cleanString(a.cwd, "cwd", { required: true, max: 500 })!,
1455
1458
  label: cleanString(a.label, "label", { max: 120 }),
1456
1459
  approvalMode: (cleanEnum(a.approvalMode, "approvalMode", VALID_SPAWN_APPROVALS, "guarded") ?? "guarded") as SpawnApprovalMode,
1460
+ policyName: cleanString(a.policyName, "policyName", { max: 120 }),
1461
+ spawnRequestId: cleanString(a.spawnRequestId, "spawnRequestId", { max: 160 }),
1457
1462
  pid: typeof a.pid === "number" && Number.isSafeInteger(a.pid) ? a.pid : undefined,
1458
1463
  startedAt: typeof a.startedAt === "number" ? a.startedAt : Date.now(),
1459
1464
  };
1460
1465
  });
1461
1466
  const updated = updateManagedAgents(params.id!, cleaned);
1467
+ getLifecycleManager().onOrchestratorManagedAgentsReported(params.id!, cleaned);
1462
1468
  if (updated) emitOrchestratorStatus(params.id!);
1463
1469
  return json(updated);
1464
1470
  } catch (e) {