@agent-relay/resiliency 0.1.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.
Files changed (49) hide show
  1. package/dist/context-persistence.d.ts +140 -0
  2. package/dist/context-persistence.d.ts.map +1 -0
  3. package/dist/context-persistence.js +397 -0
  4. package/dist/context-persistence.js.map +1 -0
  5. package/dist/crash-insights.d.ts +156 -0
  6. package/dist/crash-insights.d.ts.map +1 -0
  7. package/dist/crash-insights.js +492 -0
  8. package/dist/crash-insights.js.map +1 -0
  9. package/dist/gossip-health.d.ts +137 -0
  10. package/dist/gossip-health.d.ts.map +1 -0
  11. package/dist/gossip-health.js +241 -0
  12. package/dist/gossip-health.js.map +1 -0
  13. package/dist/health-monitor.d.ts +97 -0
  14. package/dist/health-monitor.d.ts.map +1 -0
  15. package/dist/health-monitor.js +291 -0
  16. package/dist/health-monitor.js.map +1 -0
  17. package/dist/index.d.ts +68 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +68 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/leader-watchdog.d.ts +109 -0
  22. package/dist/leader-watchdog.d.ts.map +1 -0
  23. package/dist/leader-watchdog.js +189 -0
  24. package/dist/leader-watchdog.js.map +1 -0
  25. package/dist/logger.d.ts +114 -0
  26. package/dist/logger.d.ts.map +1 -0
  27. package/dist/logger.js +250 -0
  28. package/dist/logger.js.map +1 -0
  29. package/dist/memory-monitor.d.ts +172 -0
  30. package/dist/memory-monitor.d.ts.map +1 -0
  31. package/dist/memory-monitor.js +599 -0
  32. package/dist/memory-monitor.js.map +1 -0
  33. package/dist/metrics.d.ts +115 -0
  34. package/dist/metrics.d.ts.map +1 -0
  35. package/dist/metrics.js +239 -0
  36. package/dist/metrics.js.map +1 -0
  37. package/dist/provider-context.d.ts +100 -0
  38. package/dist/provider-context.d.ts.map +1 -0
  39. package/dist/provider-context.js +362 -0
  40. package/dist/provider-context.js.map +1 -0
  41. package/dist/stateless-lead.d.ts +149 -0
  42. package/dist/stateless-lead.d.ts.map +1 -0
  43. package/dist/stateless-lead.js +308 -0
  44. package/dist/stateless-lead.js.map +1 -0
  45. package/dist/supervisor.d.ts +147 -0
  46. package/dist/supervisor.d.ts.map +1 -0
  47. package/dist/supervisor.js +459 -0
  48. package/dist/supervisor.js.map +1 -0
  49. package/package.json +28 -0
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Stateless Lead Coordinator
3
+ *
4
+ * Implements P0: Lead reads from Beads, no in-memory task queue.
5
+ * All task state lives in Beads. If lead crashes, new lead picks up.
6
+ *
7
+ * Key principles:
8
+ * - Lead is a coordinator, not a state holder
9
+ * - Beads is the single source of truth for task state
10
+ * - Any agent can become lead by reading from Beads
11
+ * - Tasks are assigned by updating Beads, not in-memory
12
+ */
13
+ import * as fs from 'fs';
14
+ import * as path from 'path';
15
+ import { EventEmitter } from 'events';
16
+ const DEFAULT_CONFIG = {
17
+ pollIntervalMs: 5000,
18
+ heartbeatIntervalMs: 10000,
19
+ leaseDurationMs: 300000, // 5 minutes
20
+ };
21
+ /**
22
+ * Stateless Lead Coordinator
23
+ *
24
+ * Reads tasks from Beads JSONL, assigns to workers, tracks via Beads updates.
25
+ * No in-memory task queue - all state persisted to Beads.
26
+ */
27
+ export class StatelessLeadCoordinator extends EventEmitter {
28
+ config;
29
+ issuesPath;
30
+ heartbeatPath;
31
+ pollInterval;
32
+ heartbeatInterval;
33
+ isRunning = false;
34
+ constructor(config) {
35
+ super();
36
+ this.config = { ...DEFAULT_CONFIG, ...config };
37
+ this.issuesPath = path.join(this.config.beadsDir, 'issues.jsonl');
38
+ this.heartbeatPath = path.join(this.config.beadsDir, 'leader-heartbeat.json');
39
+ }
40
+ /**
41
+ * Start the lead coordinator loop
42
+ */
43
+ async start() {
44
+ if (this.isRunning)
45
+ return;
46
+ this.isRunning = true;
47
+ console.log(`[stateless-lead] Starting lead coordinator: ${this.config.agentName}`);
48
+ // Write initial heartbeat
49
+ await this.writeHeartbeat();
50
+ // Start polling for ready tasks
51
+ this.pollInterval = setInterval(async () => {
52
+ try {
53
+ await this.pollAndAssign();
54
+ }
55
+ catch (err) {
56
+ console.error('[stateless-lead] Poll error:', err);
57
+ this.emit('error', err);
58
+ }
59
+ }, this.config.pollIntervalMs);
60
+ // Start heartbeat
61
+ this.heartbeatInterval = setInterval(async () => {
62
+ try {
63
+ await this.writeHeartbeat();
64
+ }
65
+ catch (err) {
66
+ console.error('[stateless-lead] Heartbeat error:', err);
67
+ }
68
+ }, this.config.heartbeatIntervalMs);
69
+ // Initial poll
70
+ await this.pollAndAssign();
71
+ this.emit('started', { leadName: this.config.agentName });
72
+ }
73
+ /**
74
+ * Stop the lead coordinator
75
+ */
76
+ async stop() {
77
+ if (!this.isRunning)
78
+ return;
79
+ this.isRunning = false;
80
+ if (this.pollInterval) {
81
+ clearInterval(this.pollInterval);
82
+ this.pollInterval = undefined;
83
+ }
84
+ if (this.heartbeatInterval) {
85
+ clearInterval(this.heartbeatInterval);
86
+ this.heartbeatInterval = undefined;
87
+ }
88
+ console.log(`[stateless-lead] Stopped lead coordinator: ${this.config.agentName}`);
89
+ this.emit('stopped', { leadName: this.config.agentName });
90
+ }
91
+ /**
92
+ * Read all tasks from Beads JSONL
93
+ */
94
+ async readTasks() {
95
+ if (!fs.existsSync(this.issuesPath)) {
96
+ return [];
97
+ }
98
+ const content = await fs.promises.readFile(this.issuesPath, 'utf-8');
99
+ const tasks = [];
100
+ for (const line of content.split('\n')) {
101
+ if (!line.trim())
102
+ continue;
103
+ try {
104
+ tasks.push(JSON.parse(line));
105
+ }
106
+ catch {
107
+ // Skip malformed lines
108
+ }
109
+ }
110
+ return tasks;
111
+ }
112
+ /**
113
+ * Update a task in Beads JSONL
114
+ */
115
+ async updateTask(taskId, updates) {
116
+ const tasks = await this.readTasks();
117
+ const updated = tasks.map((task) => {
118
+ if (task.id === taskId) {
119
+ return {
120
+ ...task,
121
+ ...updates,
122
+ updated_at: new Date().toISOString(),
123
+ };
124
+ }
125
+ return task;
126
+ });
127
+ const content = updated.map((t) => JSON.stringify(t)).join('\n') + '\n';
128
+ await fs.promises.writeFile(this.issuesPath, content, 'utf-8');
129
+ }
130
+ /**
131
+ * Get tasks that are ready to be assigned
132
+ * Ready = open status, not assigned, not blocked, sorted by priority
133
+ */
134
+ async getReadyTasks() {
135
+ const tasks = await this.readTasks();
136
+ const now = Date.now();
137
+ return tasks
138
+ .filter((task) => {
139
+ // Must be open
140
+ if (task.status !== 'open')
141
+ return false;
142
+ // Not assigned, or lease expired (P1)
143
+ if (task.assignee) {
144
+ if (task.leaseExpires && task.leaseExpires > now) {
145
+ return false; // Still leased
146
+ }
147
+ // Lease expired - task is available again
148
+ }
149
+ return true;
150
+ })
151
+ .sort((a, b) => a.priority - b.priority); // Lower priority number = higher priority
152
+ }
153
+ /**
154
+ * Get tasks currently assigned to agents
155
+ */
156
+ async getAssignedTasks() {
157
+ const tasks = await this.readTasks();
158
+ const now = Date.now();
159
+ return tasks.filter((task) => {
160
+ if (task.status !== 'in_progress')
161
+ return false;
162
+ if (!task.assignee)
163
+ return false;
164
+ // Check lease not expired
165
+ if (task.leaseExpires && task.leaseExpires <= now)
166
+ return false;
167
+ return true;
168
+ });
169
+ }
170
+ /**
171
+ * Poll for ready tasks and assign to available workers
172
+ */
173
+ async pollAndAssign() {
174
+ const readyTasks = await this.getReadyTasks();
175
+ if (readyTasks.length === 0)
176
+ return;
177
+ const workers = await this.config.getAvailableWorkers();
178
+ if (workers.length === 0) {
179
+ console.log('[stateless-lead] No available workers');
180
+ return;
181
+ }
182
+ // Assign one task per available worker
183
+ for (const worker of workers) {
184
+ const task = readyTasks.shift();
185
+ if (!task)
186
+ break;
187
+ await this.assignTask(task, worker);
188
+ }
189
+ }
190
+ /**
191
+ * Assign a task to a worker
192
+ */
193
+ async assignTask(task, worker) {
194
+ const leaseExpires = Date.now() + this.config.leaseDurationMs;
195
+ // Update Beads first (source of truth)
196
+ await this.updateTask(task.id, {
197
+ status: 'in_progress',
198
+ assignee: worker,
199
+ leaseExpires,
200
+ });
201
+ // Send task to worker via relay
202
+ const message = `TASK [${task.id}]: ${task.title}${task.description ? '\n\n' + task.description : ''}`;
203
+ await this.config.sendRelay(worker, message);
204
+ console.log(`[stateless-lead] Assigned ${task.id} to ${worker} (lease expires in ${this.config.leaseDurationMs / 1000}s)`);
205
+ this.emit('assigned', { taskId: task.id, worker, leaseExpires });
206
+ }
207
+ /**
208
+ * Handle task completion from worker
209
+ */
210
+ async completeTask(taskId, worker, reason) {
211
+ await this.updateTask(taskId, {
212
+ status: 'closed',
213
+ assignee: worker,
214
+ });
215
+ console.log(`[stateless-lead] Task ${taskId} completed by ${worker}${reason ? ': ' + reason : ''}`);
216
+ this.emit('completed', { taskId, worker, reason });
217
+ }
218
+ /**
219
+ * Handle task blocked by worker
220
+ */
221
+ async blockTask(taskId, worker, reason) {
222
+ await this.updateTask(taskId, {
223
+ status: 'blocked',
224
+ assignee: worker,
225
+ });
226
+ console.log(`[stateless-lead] Task ${taskId} blocked by ${worker}: ${reason}`);
227
+ this.emit('blocked', { taskId, worker, reason });
228
+ }
229
+ /**
230
+ * Renew lease for a task (worker signals still working)
231
+ */
232
+ async renewLease(taskId, worker) {
233
+ const leaseExpires = Date.now() + this.config.leaseDurationMs;
234
+ await this.updateTask(taskId, { leaseExpires });
235
+ console.log(`[stateless-lead] Renewed lease for ${taskId} (${worker})`);
236
+ this.emit('leaseRenewed', { taskId, worker, leaseExpires });
237
+ }
238
+ /**
239
+ * Write leader heartbeat to file (P2)
240
+ */
241
+ async writeHeartbeat() {
242
+ const assignedTasks = await this.getAssignedTasks();
243
+ const assignedAgents = [...new Set(assignedTasks.map((t) => t.assignee).filter(Boolean))];
244
+ const heartbeat = {
245
+ leadName: this.config.agentName,
246
+ leadId: this.config.agentId,
247
+ timestamp: Date.now(),
248
+ activeTaskCount: assignedTasks.length,
249
+ assignedAgents,
250
+ };
251
+ await fs.promises.writeFile(this.heartbeatPath, JSON.stringify(heartbeat, null, 2), 'utf-8');
252
+ }
253
+ /**
254
+ * Read current leader heartbeat (for watchdog - P3)
255
+ */
256
+ static async readHeartbeat(beadsDir) {
257
+ const heartbeatPath = path.join(beadsDir, 'leader-heartbeat.json');
258
+ if (!fs.existsSync(heartbeatPath)) {
259
+ return null;
260
+ }
261
+ try {
262
+ const content = await fs.promises.readFile(heartbeatPath, 'utf-8');
263
+ return JSON.parse(content);
264
+ }
265
+ catch {
266
+ return null;
267
+ }
268
+ }
269
+ /**
270
+ * Check if leader is stale (for watchdog - P3)
271
+ */
272
+ static async isLeaderStale(beadsDir, staleThresholdMs = 30000) {
273
+ const heartbeat = await StatelessLeadCoordinator.readHeartbeat(beadsDir);
274
+ if (!heartbeat)
275
+ return true;
276
+ return Date.now() - heartbeat.timestamp > staleThresholdMs;
277
+ }
278
+ /**
279
+ * Get current status
280
+ */
281
+ async getStatus() {
282
+ const readyTasks = await this.getReadyTasks();
283
+ const assignedTasks = await this.getAssignedTasks();
284
+ const heartbeat = await StatelessLeadCoordinator.readHeartbeat(this.config.beadsDir);
285
+ return {
286
+ isRunning: this.isRunning,
287
+ leadName: this.config.agentName,
288
+ readyTasks: readyTasks.length,
289
+ assignedTasks: assignedTasks.length,
290
+ lastHeartbeat: heartbeat?.timestamp ?? null,
291
+ };
292
+ }
293
+ }
294
+ /**
295
+ * Create a stateless lead coordinator with defaults
296
+ */
297
+ export function createStatelessLead(beadsDir, agentName, agentId, callbacks) {
298
+ return new StatelessLeadCoordinator({
299
+ beadsDir,
300
+ agentName,
301
+ agentId,
302
+ ...callbacks,
303
+ pollIntervalMs: 5000,
304
+ heartbeatIntervalMs: 10000,
305
+ leaseDurationMs: 300000,
306
+ });
307
+ }
308
+ //# sourceMappingURL=stateless-lead.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateless-lead.js","sourceRoot":"","sources":["../src/stateless-lead.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Agent Supervisor
3
+ *
4
+ * High-level supervisor that combines health monitoring, logging, and metrics
5
+ * to provide comprehensive agent resiliency.
6
+ */
7
+ import { EventEmitter } from 'events';
8
+ import { AgentHealthMonitor, HealthMonitorConfig } from './health-monitor.js';
9
+ import { LogLevel } from './logger.js';
10
+ import { metrics } from './metrics.js';
11
+ import { ProviderType } from './provider-context.js';
12
+ import { LeadHeartbeat } from './stateless-lead.js';
13
+ export interface SupervisedAgent {
14
+ name: string;
15
+ cli: string;
16
+ task?: string;
17
+ pid: number;
18
+ logFile?: string;
19
+ spawnedAt: Date;
20
+ workingDir?: string;
21
+ provider?: ProviderType;
22
+ }
23
+ export interface SupervisorConfig {
24
+ healthCheck: Partial<HealthMonitorConfig>;
25
+ logging: {
26
+ level: LogLevel;
27
+ file?: string;
28
+ };
29
+ autoRestart: boolean;
30
+ maxRestarts: number;
31
+ notifyOnCrash: boolean;
32
+ contextPersistence: {
33
+ enabled: boolean;
34
+ baseDir?: string;
35
+ autoInjectOnRestart: boolean;
36
+ };
37
+ /** Leader coordination (P0-P3) */
38
+ leaderCoordination?: {
39
+ enabled: boolean;
40
+ /** Path to .beads directory */
41
+ beadsDir: string;
42
+ /** Callback to send relay messages */
43
+ sendRelay?: (to: string, message: string) => Promise<void>;
44
+ };
45
+ }
46
+ export declare class AgentSupervisor extends EventEmitter {
47
+ private config;
48
+ private healthMonitor;
49
+ private logger;
50
+ private agents;
51
+ private restarters;
52
+ private contextPersistence?;
53
+ private contextHandlers;
54
+ private leaderWatchdog?;
55
+ private leadCoordinator?;
56
+ private supervisorAgentId;
57
+ constructor(config?: Partial<SupervisorConfig>);
58
+ /**
59
+ * Start supervising agents
60
+ */
61
+ start(): void;
62
+ /**
63
+ * Stop supervising agents
64
+ */
65
+ stop(): void;
66
+ /**
67
+ * Enable leader coordination with watchdog
68
+ * This allows this supervisor to participate in leader election and
69
+ * potentially become the lead coordinator for task distribution.
70
+ */
71
+ enableLeaderCoordination(beadsDir: string, sendRelay: (to: string, message: string) => Promise<void>): void;
72
+ /**
73
+ * Called when this supervisor wins leader election
74
+ */
75
+ private becomeLeader;
76
+ /**
77
+ * Get healthy agents for leader election
78
+ */
79
+ private getHealthyAgents;
80
+ /**
81
+ * Get available worker names (healthy agents not currently busy)
82
+ */
83
+ private getAvailableWorkerNames;
84
+ /**
85
+ * Check if this supervisor is currently the leader
86
+ */
87
+ isLeader(): boolean;
88
+ /**
89
+ * Get current leader info
90
+ */
91
+ getCurrentLeader(): LeadHeartbeat | null;
92
+ /**
93
+ * Add an agent to supervision
94
+ */
95
+ supervise(agent: SupervisedAgent, options: {
96
+ isAlive: () => boolean;
97
+ kill: (signal?: string) => void;
98
+ restart: () => Promise<void>;
99
+ sendHealthCheck?: () => Promise<boolean>;
100
+ }): void;
101
+ /**
102
+ * Remove an agent from supervision
103
+ */
104
+ unsupervise(name: string): void;
105
+ /**
106
+ * Update agent info (e.g., after restart)
107
+ */
108
+ updateAgent(name: string, updates: Partial<SupervisedAgent>): void;
109
+ /**
110
+ * Get all supervised agents
111
+ */
112
+ getAgents(): SupervisedAgent[];
113
+ /**
114
+ * Get agent status
115
+ */
116
+ getStatus(name: string): {
117
+ agent?: SupervisedAgent;
118
+ health?: ReturnType<AgentHealthMonitor['get']>;
119
+ metrics?: ReturnType<typeof metrics.getAgentMetrics>;
120
+ };
121
+ /**
122
+ * Get overall supervisor status
123
+ */
124
+ getOverallStatus(): {
125
+ agents: SupervisedAgent[];
126
+ health: ReturnType<AgentHealthMonitor['getAll']>;
127
+ systemMetrics: ReturnType<typeof metrics.getSystemMetrics>;
128
+ };
129
+ /**
130
+ * Force restart an agent
131
+ */
132
+ forceRestart(name: string): Promise<void>;
133
+ /**
134
+ * Setup event handlers for health monitor
135
+ */
136
+ private setupHealthMonitorEvents;
137
+ /**
138
+ * Send notification about agent crash
139
+ */
140
+ private notifyCrash;
141
+ /**
142
+ * Send notification about permanently dead agent
143
+ */
144
+ private notifyDead;
145
+ }
146
+ export declare function getSupervisor(config?: Partial<SupervisorConfig>): AgentSupervisor;
147
+ //# sourceMappingURL=supervisor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"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"}