agent-relay-server 0.10.12 → 0.10.14
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 +1 -1
- package/src/bus.ts +6 -0
- package/src/lifecycle-manager.ts +39 -2
- package/src/routes.ts +6 -0
package/package.json
CHANGED
package/src/bus.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { getAgent, getDb, heartbeat, markReady, orphanTasksForAgent, setStatus,
|
|
|
3
3
|
import { getOldestOutboxCursor, getOutboxCursor, replayEvents, type BusEvent } from "./bus-outbox";
|
|
4
4
|
import { emitRelayEvent, subscribeRelayEvents, type RelayEvent } from "./events";
|
|
5
5
|
import { createCommand, getCommand, updateCommand } from "./commands-db";
|
|
6
|
+
import { getLifecycleManager } from "./lifecycle-manager";
|
|
6
7
|
import { applyCommandToRecipe } from "./recipe-runner";
|
|
7
8
|
import {
|
|
8
9
|
BusProtocolError,
|
|
@@ -230,6 +231,11 @@ function handleRegister(ws: BusWebSocket, frame: RegisterFrame): void {
|
|
|
230
231
|
meta: payload.meta,
|
|
231
232
|
});
|
|
232
233
|
epoch = agent.epoch;
|
|
234
|
+
getLifecycleManager().onAgentRegistered(agent.id, {
|
|
235
|
+
policyName: stringMeta(payload.meta, "policyName"),
|
|
236
|
+
spawnRequestId: stringMeta(payload.meta, "spawnRequestId"),
|
|
237
|
+
tmuxSession: stringMeta(payload.meta, "tmuxSession"),
|
|
238
|
+
});
|
|
233
239
|
emitAgentStatusEvent(agent.id);
|
|
234
240
|
}
|
|
235
241
|
|
package/src/lifecycle-manager.ts
CHANGED
|
@@ -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) {
|