agents-relay 1.0.101 → 1.0.102
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/reconciler-runtime.js +21 -0
- package/dist/reconciler.js +5 -0
- package/dist/workflow/definitions.js +12 -4
- package/package.json +2 -2
|
@@ -86,6 +86,27 @@ export class ReconcilerRuntimeBase {
|
|
|
86
86
|
}
|
|
87
87
|
async idle() { while (this.live.size > 0 || this.plannerLive.size > 0 || this.continuationLive.size > 0 || this.reconciling)
|
|
88
88
|
await new Promise(resolve => setTimeout(resolve, 25)); }
|
|
89
|
+
async close() {
|
|
90
|
+
for (const live of this.live.values()) {
|
|
91
|
+
live.controller.abort();
|
|
92
|
+
live.execution.cancel();
|
|
93
|
+
}
|
|
94
|
+
this.live.clear();
|
|
95
|
+
for (const timer of this.terminalTimers.values())
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
this.terminalTimers.clear();
|
|
98
|
+
for (const timer of this.terminalExitGraceTimers.values())
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
this.terminalExitGraceTimers.clear();
|
|
101
|
+
for (const planner of this.plannerLive.values()) {
|
|
102
|
+
clearTimeout(planner.timer);
|
|
103
|
+
planner.controller.abort();
|
|
104
|
+
}
|
|
105
|
+
this.plannerLive.clear();
|
|
106
|
+
for (const waiter of this.terminalWaiters.values())
|
|
107
|
+
waiter.resolve();
|
|
108
|
+
this.terminalWaiters.clear();
|
|
109
|
+
}
|
|
89
110
|
async wake(jobId) { return this.reconcile(jobId); }
|
|
90
111
|
async startAck(jobId, taskId, sourceId, launchBarrier, timeoutMs = this.options.startAckTimeoutMs ?? 60000) {
|
|
91
112
|
if (!this.options.eventBus)
|
package/dist/reconciler.js
CHANGED
|
@@ -146,8 +146,13 @@ export class Reconciler extends ReconcilerReviewBase {
|
|
|
146
146
|
this.plannerLive.get(task.id)?.controller.abort();
|
|
147
147
|
}
|
|
148
148
|
const beforeSchedule = await this.store.load(jobId);
|
|
149
|
+
const taskStatesBeforeSchedule = new Map(beforeSchedule.tasks.map(task => [task.id, task.state]));
|
|
149
150
|
const scheduleBefore = JSON.stringify(beforeSchedule.schedule ?? null);
|
|
150
151
|
let scheduled = schedule(beforeSchedule);
|
|
152
|
+
for (const task of scheduled.tasks) {
|
|
153
|
+
if (taskStatesBeforeSchedule.get(task.id) !== task.state)
|
|
154
|
+
await this.store.saveTask(task);
|
|
155
|
+
}
|
|
151
156
|
if (scheduled.state !== previousState || JSON.stringify(scheduled.schedule ?? null) !== scheduleBefore)
|
|
152
157
|
await this.store.saveJob(scheduled);
|
|
153
158
|
if (prState === 'OPEN') {
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { parseExecutableMermaid, WorkflowEngine } from './mermaid.js';
|
|
3
|
-
import { WORKFLOW_EFFECT_NAMES, WORKFLOW_EVENT_NAMES, WORKFLOW_MUTATION_NAMES } from './contracts.js';
|
|
3
|
+
import { WORKFLOW_EFFECT_NAMES, WORKFLOW_EVENT_NAMES, WORKFLOW_FACT_NAMES, WORKFLOW_MUTATION_NAMES, classifyWorkflowActions } from './contracts.js';
|
|
4
4
|
function declarativeActions() {
|
|
5
5
|
return Object.fromEntries([...WORKFLOW_MUTATION_NAMES, ...WORKFLOW_EFFECT_NAMES].map(name => [name, { declarative: true }]));
|
|
6
6
|
}
|
|
7
|
-
function
|
|
8
|
-
const url = new URL(`../../workflow/${name}.mmd`, import.meta.url);
|
|
9
|
-
const graph = parseExecutableMermaid(readFileSync(url, 'utf8'));
|
|
7
|
+
export function validateCanonicalWorkflowGraph(graph) {
|
|
10
8
|
const canonicalEvents = new Set(WORKFLOW_EVENT_NAMES);
|
|
9
|
+
const canonicalFacts = new Set(WORKFLOW_FACT_NAMES);
|
|
11
10
|
for (const transition of graph.transitions) {
|
|
12
11
|
if (!canonicalEvents.has(transition.event)) {
|
|
13
12
|
throw new Error(`Unknown canonical workflow event ${transition.event} referenced at line ${transition.line}`);
|
|
14
13
|
}
|
|
14
|
+
if (transition.guard && !canonicalFacts.has(transition.guard)) {
|
|
15
|
+
throw new Error(`Unknown canonical workflow fact ${transition.guard} referenced at line ${transition.line}`);
|
|
16
|
+
}
|
|
17
|
+
classifyWorkflowActions(transition.actions);
|
|
15
18
|
}
|
|
19
|
+
}
|
|
20
|
+
function load(name, guards = {}) {
|
|
21
|
+
const url = new URL(`../../workflow/${name}.mmd`, import.meta.url);
|
|
22
|
+
const graph = parseExecutableMermaid(readFileSync(url, 'utf8'));
|
|
23
|
+
validateCanonicalWorkflowGraph(graph);
|
|
16
24
|
return new WorkflowEngine(graph, guards, declarativeActions());
|
|
17
25
|
}
|
|
18
26
|
const booleanGuard = (name) => context => context[name] === true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents-relay",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.102",
|
|
4
4
|
"description": "Durable async agent jobs coordinated through GitHub pull requests",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc -p tsconfig.json && chmod +x dist/cli.js dist/relayd.js",
|
|
12
|
-
"test": "npm run build && node --test
|
|
12
|
+
"test": "npm run build && node --test test/*.test.js",
|
|
13
13
|
"test:chatgpt-temp-quality": "AGENTS_RELAY_RUN_CHATGPT_TEMP_QUALITY=1 AGENTS_RELAY_CHATGPT_BROWSER_WORKER_AGENT=/Users/chengli/Workspace/neo/skills/chatgpt-browser-worker/agents/browser-worker.agent.md sh -c \"npm run build && node test/quality/run-temporary-chat.mjs\"",
|
|
14
14
|
"dev": "tsx src/cli.ts"
|
|
15
15
|
},
|