@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.
- package/dist/context-persistence.d.ts +140 -0
- package/dist/context-persistence.d.ts.map +1 -0
- package/dist/context-persistence.js +397 -0
- package/dist/context-persistence.js.map +1 -0
- package/dist/crash-insights.d.ts +156 -0
- package/dist/crash-insights.d.ts.map +1 -0
- package/dist/crash-insights.js +492 -0
- package/dist/crash-insights.js.map +1 -0
- package/dist/gossip-health.d.ts +137 -0
- package/dist/gossip-health.d.ts.map +1 -0
- package/dist/gossip-health.js +241 -0
- package/dist/gossip-health.js.map +1 -0
- package/dist/health-monitor.d.ts +97 -0
- package/dist/health-monitor.d.ts.map +1 -0
- package/dist/health-monitor.js +291 -0
- package/dist/health-monitor.js.map +1 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -0
- package/dist/leader-watchdog.d.ts +109 -0
- package/dist/leader-watchdog.d.ts.map +1 -0
- package/dist/leader-watchdog.js +189 -0
- package/dist/leader-watchdog.js.map +1 -0
- package/dist/logger.d.ts +114 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +250 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory-monitor.d.ts +172 -0
- package/dist/memory-monitor.d.ts.map +1 -0
- package/dist/memory-monitor.js +599 -0
- package/dist/memory-monitor.js.map +1 -0
- package/dist/metrics.d.ts +115 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +239 -0
- package/dist/metrics.js.map +1 -0
- package/dist/provider-context.d.ts +100 -0
- package/dist/provider-context.d.ts.map +1 -0
- package/dist/provider-context.js +362 -0
- package/dist/provider-context.js.map +1 -0
- package/dist/stateless-lead.d.ts +149 -0
- package/dist/stateless-lead.d.ts.map +1 -0
- package/dist/stateless-lead.js +308 -0
- package/dist/stateless-lead.js.map +1 -0
- package/dist/supervisor.d.ts +147 -0
- package/dist/supervisor.d.ts.map +1 -0
- package/dist/supervisor.js +459 -0
- package/dist/supervisor.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-Specific Context Injection
|
|
3
|
+
*
|
|
4
|
+
* Handles context persistence differently based on the AI provider:
|
|
5
|
+
* - Claude: Uses hooks (PreToolUse, PostToolUse, Stop) to inject/save context
|
|
6
|
+
* - Codex: Uses config settings for periodic context refresh
|
|
7
|
+
* - Gemini: Uses system instruction updates
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import { createLogger } from './logger.js';
|
|
12
|
+
import { getContextPersistence } from './context-persistence.js';
|
|
13
|
+
const logger = createLogger('provider-context');
|
|
14
|
+
/**
|
|
15
|
+
* Base class for provider-specific context handling
|
|
16
|
+
*/
|
|
17
|
+
class ProviderContextHandler {
|
|
18
|
+
persistence;
|
|
19
|
+
config;
|
|
20
|
+
constructor(config) {
|
|
21
|
+
this.config = config;
|
|
22
|
+
this.persistence = getContextPersistence(path.join(config.workingDir, '.agent-relay', 'context'));
|
|
23
|
+
}
|
|
24
|
+
getState() {
|
|
25
|
+
return this.persistence.getState(this.config.agentName);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Claude Context Handler using Hooks
|
|
30
|
+
*
|
|
31
|
+
* Creates hooks that:
|
|
32
|
+
* - Pre-tool: Inject resumption context before critical operations
|
|
33
|
+
* - Stop: Save state to ledger on session end
|
|
34
|
+
*/
|
|
35
|
+
export class ClaudeContextHandler extends ProviderContextHandler {
|
|
36
|
+
hooksConfig;
|
|
37
|
+
constructor(config, hooksConfig) {
|
|
38
|
+
super(config);
|
|
39
|
+
this.hooksConfig = {
|
|
40
|
+
hooksDir: path.join(config.workingDir, '.claude', 'hooks'),
|
|
41
|
+
onPreToolUse: true,
|
|
42
|
+
onStop: true,
|
|
43
|
+
contextFile: path.join(config.workingDir, 'CLAUDE.md'),
|
|
44
|
+
...hooksConfig,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async setup() {
|
|
48
|
+
// Ensure hooks directory exists
|
|
49
|
+
if (!fs.existsSync(this.hooksConfig.hooksDir)) {
|
|
50
|
+
fs.mkdirSync(this.hooksConfig.hooksDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
// Create or update settings.json with hook configuration
|
|
53
|
+
const settingsPath = path.join(this.config.workingDir, '.claude', 'settings.json');
|
|
54
|
+
let settings = {};
|
|
55
|
+
if (fs.existsSync(settingsPath)) {
|
|
56
|
+
try {
|
|
57
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Start fresh if invalid
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Configure hooks
|
|
64
|
+
const hooks = settings.hooks || {};
|
|
65
|
+
if (this.hooksConfig.onStop) {
|
|
66
|
+
// Stop hook to save context
|
|
67
|
+
const stopHookScript = this.createStopHookScript();
|
|
68
|
+
const stopHookPath = path.join(this.hooksConfig.hooksDir, 'save-context.sh');
|
|
69
|
+
fs.writeFileSync(stopHookPath, stopHookScript, { mode: 0o755 });
|
|
70
|
+
hooks.Stop = hooks.Stop || [];
|
|
71
|
+
const stopHookEntry = {
|
|
72
|
+
matcher: '',
|
|
73
|
+
hooks: [{ type: 'command', command: stopHookPath }],
|
|
74
|
+
};
|
|
75
|
+
// Only add if not already present
|
|
76
|
+
if (!hooks.Stop.some((h) => {
|
|
77
|
+
const entry = h;
|
|
78
|
+
return entry.hooks?.[0]?.command === stopHookPath;
|
|
79
|
+
})) {
|
|
80
|
+
hooks.Stop.push(stopHookEntry);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
settings.hooks = hooks;
|
|
84
|
+
// Write updated settings
|
|
85
|
+
const settingsDir = path.dirname(settingsPath);
|
|
86
|
+
if (!fs.existsSync(settingsDir)) {
|
|
87
|
+
fs.mkdirSync(settingsDir, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
90
|
+
logger.info('Claude hooks configured', {
|
|
91
|
+
hooksDir: this.hooksConfig.hooksDir,
|
|
92
|
+
onStop: this.hooksConfig.onStop,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async injectContext(handoff) {
|
|
96
|
+
if (!this.hooksConfig.contextFile)
|
|
97
|
+
return;
|
|
98
|
+
// Read existing CLAUDE.md
|
|
99
|
+
let existingContent = '';
|
|
100
|
+
if (fs.existsSync(this.hooksConfig.contextFile)) {
|
|
101
|
+
existingContent = fs.readFileSync(this.hooksConfig.contextFile, 'utf8');
|
|
102
|
+
}
|
|
103
|
+
// Generate resumption context
|
|
104
|
+
const resumptionContext = this.persistence.generateResumptionContext(this.config.agentName);
|
|
105
|
+
if (!resumptionContext)
|
|
106
|
+
return;
|
|
107
|
+
// Check if we already have resumption context
|
|
108
|
+
const marker = '<!-- AGENT_RESUMPTION_CONTEXT -->';
|
|
109
|
+
const endMarker = '<!-- END_AGENT_RESUMPTION_CONTEXT -->';
|
|
110
|
+
let newContent;
|
|
111
|
+
if (existingContent.includes(marker)) {
|
|
112
|
+
// Replace existing context
|
|
113
|
+
const regex = new RegExp(`${marker}[\\s\\S]*?${endMarker}`, 'g');
|
|
114
|
+
newContent = existingContent.replace(regex, `${marker}\n${resumptionContext}\n${endMarker}`);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// Prepend context
|
|
118
|
+
newContent = `${marker}\n${resumptionContext}\n${endMarker}\n\n${existingContent}`;
|
|
119
|
+
}
|
|
120
|
+
fs.writeFileSync(this.hooksConfig.contextFile, newContent);
|
|
121
|
+
logger.info('Injected resumption context into CLAUDE.md', {
|
|
122
|
+
agent: this.config.agentName,
|
|
123
|
+
handoffId: handoff.fromAgent,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async saveContext() {
|
|
127
|
+
this.persistence.checkpoint(this.config.agentName);
|
|
128
|
+
logger.info('Saved Claude context checkpoint', { agent: this.config.agentName });
|
|
129
|
+
}
|
|
130
|
+
async cleanup() {
|
|
131
|
+
// Optionally remove the resumption context from CLAUDE.md
|
|
132
|
+
if (this.hooksConfig.contextFile && fs.existsSync(this.hooksConfig.contextFile)) {
|
|
133
|
+
const content = fs.readFileSync(this.hooksConfig.contextFile, 'utf8');
|
|
134
|
+
const marker = '<!-- AGENT_RESUMPTION_CONTEXT -->';
|
|
135
|
+
const endMarker = '<!-- END_AGENT_RESUMPTION_CONTEXT -->';
|
|
136
|
+
const regex = new RegExp(`${marker}[\\s\\S]*?${endMarker}\\n*`, 'g');
|
|
137
|
+
const cleaned = content.replace(regex, '');
|
|
138
|
+
fs.writeFileSync(this.hooksConfig.contextFile, cleaned);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
createStopHookScript() {
|
|
142
|
+
const contextDir = path.join(this.config.workingDir, '.agent-relay', 'context');
|
|
143
|
+
return `#!/bin/bash
|
|
144
|
+
# Claude Code Stop Hook - Save agent context
|
|
145
|
+
# Generated by agent-relay
|
|
146
|
+
|
|
147
|
+
AGENT_NAME="${this.config.agentName}"
|
|
148
|
+
CONTEXT_DIR="${contextDir}"
|
|
149
|
+
|
|
150
|
+
# Read hook input from stdin
|
|
151
|
+
read -r INPUT
|
|
152
|
+
|
|
153
|
+
# Save checkpoint marker
|
|
154
|
+
mkdir -p "$CONTEXT_DIR/ledgers"
|
|
155
|
+
echo '{"event":"stop","timestamp":"'$(date -Iseconds)'","agent":"'$AGENT_NAME'"}' >> "$CONTEXT_DIR/ledgers/events.jsonl"
|
|
156
|
+
|
|
157
|
+
# Exit successfully (don't block stop)
|
|
158
|
+
exit 0
|
|
159
|
+
`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Codex Context Handler using Config
|
|
164
|
+
*
|
|
165
|
+
* Uses Codex's configuration for:
|
|
166
|
+
* - Periodic context refresh via system prompt updates
|
|
167
|
+
* - History file for context continuity
|
|
168
|
+
*/
|
|
169
|
+
export class CodexContextHandler extends ProviderContextHandler {
|
|
170
|
+
codexConfig;
|
|
171
|
+
refreshInterval;
|
|
172
|
+
constructor(config, codexConfig) {
|
|
173
|
+
super(config);
|
|
174
|
+
this.codexConfig = {
|
|
175
|
+
configPath: path.join(config.workingDir, '.codex', 'config.json'),
|
|
176
|
+
contextRefreshInterval: 60000, // 1 minute default
|
|
177
|
+
systemPromptPath: path.join(config.workingDir, '.codex', 'system-prompt.md'),
|
|
178
|
+
...codexConfig,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
async setup() {
|
|
182
|
+
const configDir = path.dirname(this.codexConfig.configPath);
|
|
183
|
+
if (!fs.existsSync(configDir)) {
|
|
184
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
185
|
+
}
|
|
186
|
+
// Read or create config
|
|
187
|
+
let config = {};
|
|
188
|
+
if (fs.existsSync(this.codexConfig.configPath)) {
|
|
189
|
+
try {
|
|
190
|
+
config = JSON.parse(fs.readFileSync(this.codexConfig.configPath, 'utf8'));
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// Start fresh
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Set up context-aware configuration
|
|
197
|
+
config.history = config.history || {};
|
|
198
|
+
config.history.save_history = true;
|
|
199
|
+
config.history.max_history_size = 1000;
|
|
200
|
+
// Disable Codex auto-update checks to keep container-stable version
|
|
201
|
+
config.check_for_updates = false;
|
|
202
|
+
// Point to our system prompt if using custom context
|
|
203
|
+
if (this.codexConfig.systemPromptPath) {
|
|
204
|
+
config.system_prompt_file = this.codexConfig.systemPromptPath;
|
|
205
|
+
}
|
|
206
|
+
fs.writeFileSync(this.codexConfig.configPath, JSON.stringify(config, null, 2));
|
|
207
|
+
logger.info('Codex config configured', {
|
|
208
|
+
configPath: this.codexConfig.configPath,
|
|
209
|
+
refreshInterval: this.codexConfig.contextRefreshInterval,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async injectContext(_handoff) {
|
|
213
|
+
if (!this.codexConfig.systemPromptPath)
|
|
214
|
+
return;
|
|
215
|
+
// Generate resumption context
|
|
216
|
+
const resumptionContext = this.persistence.generateResumptionContext(this.config.agentName);
|
|
217
|
+
if (!resumptionContext)
|
|
218
|
+
return;
|
|
219
|
+
// Read existing system prompt
|
|
220
|
+
let existingPrompt = '';
|
|
221
|
+
if (fs.existsSync(this.codexConfig.systemPromptPath)) {
|
|
222
|
+
existingPrompt = fs.readFileSync(this.codexConfig.systemPromptPath, 'utf8');
|
|
223
|
+
}
|
|
224
|
+
// Add/update resumption context
|
|
225
|
+
const marker = '<!-- AGENT_RESUMPTION_CONTEXT -->';
|
|
226
|
+
const endMarker = '<!-- END_AGENT_RESUMPTION_CONTEXT -->';
|
|
227
|
+
let newPrompt;
|
|
228
|
+
if (existingPrompt.includes(marker)) {
|
|
229
|
+
const regex = new RegExp(`${marker}[\\s\\S]*?${endMarker}`, 'g');
|
|
230
|
+
newPrompt = existingPrompt.replace(regex, `${marker}\n${resumptionContext}\n${endMarker}`);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
newPrompt = `${marker}\n${resumptionContext}\n${endMarker}\n\n${existingPrompt}`;
|
|
234
|
+
}
|
|
235
|
+
fs.writeFileSync(this.codexConfig.systemPromptPath, newPrompt);
|
|
236
|
+
logger.info('Injected resumption context into Codex system prompt', {
|
|
237
|
+
agent: this.config.agentName,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
async saveContext() {
|
|
241
|
+
this.persistence.checkpoint(this.config.agentName);
|
|
242
|
+
logger.info('Saved Codex context checkpoint', { agent: this.config.agentName });
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Start periodic context refresh
|
|
246
|
+
*/
|
|
247
|
+
startPeriodicRefresh() {
|
|
248
|
+
if (this.refreshInterval)
|
|
249
|
+
return;
|
|
250
|
+
this.refreshInterval = setInterval(async () => {
|
|
251
|
+
const handoff = this.persistence.createHandoff(this.config.agentName);
|
|
252
|
+
await this.injectContext(handoff);
|
|
253
|
+
}, this.codexConfig.contextRefreshInterval);
|
|
254
|
+
logger.info('Started periodic context refresh for Codex', {
|
|
255
|
+
interval: this.codexConfig.contextRefreshInterval,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
stopPeriodicRefresh() {
|
|
259
|
+
if (this.refreshInterval) {
|
|
260
|
+
clearInterval(this.refreshInterval);
|
|
261
|
+
this.refreshInterval = undefined;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
async cleanup() {
|
|
265
|
+
this.stopPeriodicRefresh();
|
|
266
|
+
if (this.codexConfig.systemPromptPath && fs.existsSync(this.codexConfig.systemPromptPath)) {
|
|
267
|
+
const content = fs.readFileSync(this.codexConfig.systemPromptPath, 'utf8');
|
|
268
|
+
const marker = '<!-- AGENT_RESUMPTION_CONTEXT -->';
|
|
269
|
+
const endMarker = '<!-- END_AGENT_RESUMPTION_CONTEXT -->';
|
|
270
|
+
const regex = new RegExp(`${marker}[\\s\\S]*?${endMarker}\\n*`, 'g');
|
|
271
|
+
const cleaned = content.replace(regex, '');
|
|
272
|
+
fs.writeFileSync(this.codexConfig.systemPromptPath, cleaned);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Gemini Context Handler
|
|
278
|
+
*
|
|
279
|
+
* Uses system instruction file for context injection
|
|
280
|
+
*/
|
|
281
|
+
export class GeminiContextHandler extends ProviderContextHandler {
|
|
282
|
+
systemInstructionPath;
|
|
283
|
+
constructor(config) {
|
|
284
|
+
super(config);
|
|
285
|
+
this.systemInstructionPath = path.join(config.workingDir, '.gemini', 'system-instruction.md');
|
|
286
|
+
}
|
|
287
|
+
async setup() {
|
|
288
|
+
const dir = path.dirname(this.systemInstructionPath);
|
|
289
|
+
if (!fs.existsSync(dir)) {
|
|
290
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
291
|
+
}
|
|
292
|
+
logger.info('Gemini context handler configured', {
|
|
293
|
+
systemInstructionPath: this.systemInstructionPath,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
async injectContext(_handoff) {
|
|
297
|
+
const resumptionContext = this.persistence.generateResumptionContext(this.config.agentName);
|
|
298
|
+
if (!resumptionContext)
|
|
299
|
+
return;
|
|
300
|
+
let existingContent = '';
|
|
301
|
+
if (fs.existsSync(this.systemInstructionPath)) {
|
|
302
|
+
existingContent = fs.readFileSync(this.systemInstructionPath, 'utf8');
|
|
303
|
+
}
|
|
304
|
+
const marker = '<!-- AGENT_RESUMPTION_CONTEXT -->';
|
|
305
|
+
const endMarker = '<!-- END_AGENT_RESUMPTION_CONTEXT -->';
|
|
306
|
+
let newContent;
|
|
307
|
+
if (existingContent.includes(marker)) {
|
|
308
|
+
const regex = new RegExp(`${marker}[\\s\\S]*?${endMarker}`, 'g');
|
|
309
|
+
newContent = existingContent.replace(regex, `${marker}\n${resumptionContext}\n${endMarker}`);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
newContent = `${marker}\n${resumptionContext}\n${endMarker}\n\n${existingContent}`;
|
|
313
|
+
}
|
|
314
|
+
fs.writeFileSync(this.systemInstructionPath, newContent);
|
|
315
|
+
logger.info('Injected resumption context for Gemini', { agent: this.config.agentName });
|
|
316
|
+
}
|
|
317
|
+
async saveContext() {
|
|
318
|
+
this.persistence.checkpoint(this.config.agentName);
|
|
319
|
+
}
|
|
320
|
+
async cleanup() {
|
|
321
|
+
if (fs.existsSync(this.systemInstructionPath)) {
|
|
322
|
+
const content = fs.readFileSync(this.systemInstructionPath, 'utf8');
|
|
323
|
+
const marker = '<!-- AGENT_RESUMPTION_CONTEXT -->';
|
|
324
|
+
const endMarker = '<!-- END_AGENT_RESUMPTION_CONTEXT -->';
|
|
325
|
+
const regex = new RegExp(`${marker}[\\s\\S]*?${endMarker}\\n*`, 'g');
|
|
326
|
+
const cleaned = content.replace(regex, '');
|
|
327
|
+
fs.writeFileSync(this.systemInstructionPath, cleaned);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Factory function to create the appropriate context handler
|
|
333
|
+
*/
|
|
334
|
+
export function createContextHandler(config, providerOptions) {
|
|
335
|
+
switch (config.provider) {
|
|
336
|
+
case 'claude':
|
|
337
|
+
return new ClaudeContextHandler(config, providerOptions);
|
|
338
|
+
case 'codex':
|
|
339
|
+
return new CodexContextHandler(config, providerOptions);
|
|
340
|
+
case 'gemini':
|
|
341
|
+
return new GeminiContextHandler(config);
|
|
342
|
+
default:
|
|
343
|
+
// Generic handler - use Claude-style CLAUDE.md injection
|
|
344
|
+
return new ClaudeContextHandler(config, {
|
|
345
|
+
contextFile: path.join(config.workingDir, 'AGENT_CONTEXT.md'),
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Detect provider from CLI command
|
|
351
|
+
*/
|
|
352
|
+
export function detectProvider(cli) {
|
|
353
|
+
const cmd = cli.toLowerCase();
|
|
354
|
+
if (cmd.includes('claude'))
|
|
355
|
+
return 'claude';
|
|
356
|
+
if (cmd.includes('codex'))
|
|
357
|
+
return 'codex';
|
|
358
|
+
if (cmd.includes('gemini'))
|
|
359
|
+
return 'gemini';
|
|
360
|
+
return 'generic';
|
|
361
|
+
}
|
|
362
|
+
//# sourceMappingURL=provider-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-context.js","sourceRoot":"","sources":["../src/provider-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
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 { EventEmitter } from 'events';
|
|
14
|
+
/**
|
|
15
|
+
* Task from Beads
|
|
16
|
+
*/
|
|
17
|
+
export interface BeadsTask {
|
|
18
|
+
id: string;
|
|
19
|
+
title: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
status: 'open' | 'in_progress' | 'blocked' | 'closed';
|
|
22
|
+
priority: number;
|
|
23
|
+
assignee?: string;
|
|
24
|
+
leaseExpires?: number;
|
|
25
|
+
tags?: string[];
|
|
26
|
+
created_at: string;
|
|
27
|
+
updated_at: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Lead heartbeat (P2)
|
|
31
|
+
*/
|
|
32
|
+
export interface LeadHeartbeat {
|
|
33
|
+
leadName: string;
|
|
34
|
+
leadId: string;
|
|
35
|
+
timestamp: number;
|
|
36
|
+
activeTaskCount: number;
|
|
37
|
+
assignedAgents: string[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Configuration for stateless lead
|
|
41
|
+
*/
|
|
42
|
+
export interface StatelessLeadConfig {
|
|
43
|
+
/** Path to .beads directory */
|
|
44
|
+
beadsDir: string;
|
|
45
|
+
/** Agent name for this lead */
|
|
46
|
+
agentName: string;
|
|
47
|
+
/** Unique agent ID */
|
|
48
|
+
agentId: string;
|
|
49
|
+
/** How often to poll Beads for ready tasks (ms) */
|
|
50
|
+
pollIntervalMs: number;
|
|
51
|
+
/** Heartbeat interval (ms) */
|
|
52
|
+
heartbeatIntervalMs: number;
|
|
53
|
+
/** Lease duration for assigned tasks (ms) - P1 */
|
|
54
|
+
leaseDurationMs: number;
|
|
55
|
+
/** Callback to send relay messages */
|
|
56
|
+
sendRelay: (to: string, message: string) => Promise<void>;
|
|
57
|
+
/** Callback to get available workers */
|
|
58
|
+
getAvailableWorkers: () => Promise<string[]>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Stateless Lead Coordinator
|
|
62
|
+
*
|
|
63
|
+
* Reads tasks from Beads JSONL, assigns to workers, tracks via Beads updates.
|
|
64
|
+
* No in-memory task queue - all state persisted to Beads.
|
|
65
|
+
*/
|
|
66
|
+
export declare class StatelessLeadCoordinator extends EventEmitter {
|
|
67
|
+
private config;
|
|
68
|
+
private issuesPath;
|
|
69
|
+
private heartbeatPath;
|
|
70
|
+
private pollInterval?;
|
|
71
|
+
private heartbeatInterval?;
|
|
72
|
+
private isRunning;
|
|
73
|
+
constructor(config: StatelessLeadConfig);
|
|
74
|
+
/**
|
|
75
|
+
* Start the lead coordinator loop
|
|
76
|
+
*/
|
|
77
|
+
start(): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Stop the lead coordinator
|
|
80
|
+
*/
|
|
81
|
+
stop(): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Read all tasks from Beads JSONL
|
|
84
|
+
*/
|
|
85
|
+
private readTasks;
|
|
86
|
+
/**
|
|
87
|
+
* Update a task in Beads JSONL
|
|
88
|
+
*/
|
|
89
|
+
private updateTask;
|
|
90
|
+
/**
|
|
91
|
+
* Get tasks that are ready to be assigned
|
|
92
|
+
* Ready = open status, not assigned, not blocked, sorted by priority
|
|
93
|
+
*/
|
|
94
|
+
private getReadyTasks;
|
|
95
|
+
/**
|
|
96
|
+
* Get tasks currently assigned to agents
|
|
97
|
+
*/
|
|
98
|
+
private getAssignedTasks;
|
|
99
|
+
/**
|
|
100
|
+
* Poll for ready tasks and assign to available workers
|
|
101
|
+
*/
|
|
102
|
+
private pollAndAssign;
|
|
103
|
+
/**
|
|
104
|
+
* Assign a task to a worker
|
|
105
|
+
*/
|
|
106
|
+
private assignTask;
|
|
107
|
+
/**
|
|
108
|
+
* Handle task completion from worker
|
|
109
|
+
*/
|
|
110
|
+
completeTask(taskId: string, worker: string, reason?: string): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Handle task blocked by worker
|
|
113
|
+
*/
|
|
114
|
+
blockTask(taskId: string, worker: string, reason: string): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Renew lease for a task (worker signals still working)
|
|
117
|
+
*/
|
|
118
|
+
renewLease(taskId: string, worker: string): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* Write leader heartbeat to file (P2)
|
|
121
|
+
*/
|
|
122
|
+
private writeHeartbeat;
|
|
123
|
+
/**
|
|
124
|
+
* Read current leader heartbeat (for watchdog - P3)
|
|
125
|
+
*/
|
|
126
|
+
static readHeartbeat(beadsDir: string): Promise<LeadHeartbeat | null>;
|
|
127
|
+
/**
|
|
128
|
+
* Check if leader is stale (for watchdog - P3)
|
|
129
|
+
*/
|
|
130
|
+
static isLeaderStale(beadsDir: string, staleThresholdMs?: number): Promise<boolean>;
|
|
131
|
+
/**
|
|
132
|
+
* Get current status
|
|
133
|
+
*/
|
|
134
|
+
getStatus(): Promise<{
|
|
135
|
+
isRunning: boolean;
|
|
136
|
+
leadName: string;
|
|
137
|
+
readyTasks: number;
|
|
138
|
+
assignedTasks: number;
|
|
139
|
+
lastHeartbeat: number | null;
|
|
140
|
+
}>;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Create a stateless lead coordinator with defaults
|
|
144
|
+
*/
|
|
145
|
+
export declare function createStatelessLead(beadsDir: string, agentName: string, agentId: string, callbacks: {
|
|
146
|
+
sendRelay: (to: string, message: string) => Promise<void>;
|
|
147
|
+
getAvailableWorkers: () => Promise<string[]>;
|
|
148
|
+
}): StatelessLeadCoordinator;
|
|
149
|
+
//# sourceMappingURL=stateless-lead.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateless-lead.d.ts","sourceRoot":"","sources":["../src/stateless-lead.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,GAAG,QAAQ,CAAC;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,8BAA8B;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kDAAkD;IAClD,eAAe,EAAE,MAAM,CAAC;IACxB,sCAAsC;IACtC,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,wCAAwC;IACxC,mBAAmB,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC9C;AAQD;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,YAAY;IACxD,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAC,CAAiC;IACtD,OAAO,CAAC,iBAAiB,CAAC,CAAiC;IAC3D,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,mBAAmB;IAOvC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkC5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B;;OAEG;YACW,SAAS;IAoBvB;;OAEG;YACW,UAAU;IAiBxB;;;OAGG;YACW,aAAa;IAsB3B;;OAEG;YACW,gBAAgB;IAa9B;;OAEG;YACW,aAAa;IAmB3B;;OAEG;YACW,UAAU;IAkBxB;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlF;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU9E;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D;;OAEG;YACW,cAAc;IAe5B;;OAEG;WACU,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAe3E;;OAEG;WACU,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,gBAAgB,SAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAOxF;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC;QACzB,SAAS,EAAE,OAAO,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC9B,CAAC;CAaH;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE;IACT,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,mBAAmB,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC9C,GACA,wBAAwB,CAU1B"}
|