@llblab/pi-actors 0.25.0 → 0.26.1
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/BACKLOG.md +4 -8
- package/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/dist/lib/actor-worker.d.ts +3 -0
- package/dist/lib/actor-worker.js +54 -6
- package/dist/lib/coordinator.js +31 -4
- package/dist/recipes/actor-worker.json +10 -6
- package/dist/recipes/lens-swarm.json +0 -2
- package/dist/recipes/pipeline-architect-coordinator.json +0 -2
- package/dist/recipes/pipeline-artifact-bundle.json +0 -2
- package/dist/recipes/pipeline-artifact-report.json +0 -2
- package/dist/recipes/pipeline-artifact-write.json +0 -2
- package/dist/recipes/pipeline-async-run-ops.json +0 -2
- package/dist/recipes/pipeline-checkpoint-continuation.json +0 -2
- package/dist/recipes/pipeline-development-tasking.json +0 -2
- package/dist/recipes/pipeline-docs-maintenance.json +0 -2
- package/dist/recipes/pipeline-media-library.json +0 -2
- package/dist/recipes/pipeline-quorum-review.json +0 -2
- package/dist/recipes/pipeline-release-readiness.json +0 -2
- package/dist/recipes/pipeline-release-summary.json +0 -2
- package/dist/recipes/pipeline-repo-health.json +0 -2
- package/dist/recipes/pipeline-research-synthesis.json +0 -2
- package/dist/recipes/pipeline-review-readiness.json +0 -2
- package/dist/recipes/pipeline-room-swarm.json +0 -2
- package/dist/recipes/subagent-artifact.json +0 -2
- package/dist/recipes/subagent-checkpoint.json +0 -2
- package/dist/recipes/subagent-conflict-report.json +0 -2
- package/dist/recipes/subagent-contradiction-map.json +0 -2
- package/dist/recipes/subagent-critic.json +0 -2
- package/dist/recipes/subagent-evidence-map.json +0 -2
- package/dist/recipes/subagent-followup.json +0 -2
- package/dist/recipes/subagent-judge.json +0 -2
- package/dist/recipes/subagent-merge.json +0 -2
- package/dist/recipes/subagent-message.json +0 -2
- package/dist/recipes/subagent-normalize.json +0 -2
- package/dist/recipes/subagent-plan.json +0 -2
- package/dist/recipes/subagent-prompt.json +0 -2
- package/dist/recipes/subagent-quorum.json +0 -2
- package/dist/recipes/subagent-review-coordinator.json +0 -2
- package/dist/recipes/subagent-review.json +0 -2
- package/dist/recipes/subagent-task-card.json +0 -2
- package/dist/recipes/subagent-tools.json +0 -2
- package/dist/recipes/subagent-verify.json +0 -2
- package/dist/recipes/subagents-prompts.json +0 -2
- package/dist/skills/actors/SKILL.md +2 -2
- package/dist/skills/swarm/SKILL.md +1 -1
- package/docs/actor-messages.md +1 -1
- package/docs/template-recipes.md +2 -2
- package/lib/actor-worker.ts +62 -6
- package/lib/coordinator.ts +33 -4
- package/package.json +1 -1
- package/recipes/actor-worker.json +10 -6
- package/recipes/lens-swarm.json +0 -2
- package/recipes/pipeline-architect-coordinator.json +0 -2
- package/recipes/pipeline-artifact-bundle.json +0 -2
- package/recipes/pipeline-artifact-report.json +0 -2
- package/recipes/pipeline-artifact-write.json +0 -2
- package/recipes/pipeline-async-run-ops.json +0 -2
- package/recipes/pipeline-checkpoint-continuation.json +0 -2
- package/recipes/pipeline-development-tasking.json +0 -2
- package/recipes/pipeline-docs-maintenance.json +0 -2
- package/recipes/pipeline-media-library.json +0 -2
- package/recipes/pipeline-quorum-review.json +0 -2
- package/recipes/pipeline-release-readiness.json +0 -2
- package/recipes/pipeline-release-summary.json +0 -2
- package/recipes/pipeline-repo-health.json +0 -2
- package/recipes/pipeline-research-synthesis.json +0 -2
- package/recipes/pipeline-review-readiness.json +0 -2
- package/recipes/pipeline-room-swarm.json +0 -2
- package/recipes/subagent-artifact.json +0 -2
- package/recipes/subagent-checkpoint.json +0 -2
- package/recipes/subagent-conflict-report.json +0 -2
- package/recipes/subagent-contradiction-map.json +0 -2
- package/recipes/subagent-critic.json +0 -2
- package/recipes/subagent-evidence-map.json +0 -2
- package/recipes/subagent-followup.json +0 -2
- package/recipes/subagent-judge.json +0 -2
- package/recipes/subagent-merge.json +0 -2
- package/recipes/subagent-message.json +0 -2
- package/recipes/subagent-normalize.json +0 -2
- package/recipes/subagent-plan.json +0 -2
- package/recipes/subagent-prompt.json +0 -2
- package/recipes/subagent-quorum.json +0 -2
- package/recipes/subagent-review-coordinator.json +0 -2
- package/recipes/subagent-review.json +0 -2
- package/recipes/subagent-task-card.json +0 -2
- package/recipes/subagent-tools.json +0 -2
- package/recipes/subagent-verify.json +0 -2
- package/recipes/subagents-prompts.json +0 -2
- package/skills/actors/SKILL.md +2 -2
- package/skills/swarm/SKILL.md +1 -1
package/BACKLOG.md
CHANGED
|
@@ -180,7 +180,7 @@ The backlog is intentionally pruned to the 20% of work most likely to deliver 80
|
|
|
180
180
|
### M-09 Actor Worker v2
|
|
181
181
|
|
|
182
182
|
- Priority: High.
|
|
183
|
-
- Status:
|
|
183
|
+
- Status: Done.
|
|
184
184
|
- Goal: Promote `actor-worker` from a minimal demo into the canonical standard-worker reference pattern.
|
|
185
185
|
- Why now: Mailbox-loop semantics are now stable enough to show artifact production, compact status, and stale-claim recovery without adding a scheduler or broker.
|
|
186
186
|
- Direction:
|
|
@@ -196,7 +196,7 @@ The backlog is intentionally pruned to the 20% of work most likely to deliver 80
|
|
|
196
196
|
### M-10 Dist Package Contract Hardening
|
|
197
197
|
|
|
198
198
|
- Priority: Medium.
|
|
199
|
-
- Status:
|
|
199
|
+
- Status: Done.
|
|
200
200
|
- Goal: Make the dist-first package contract difficult to regress after the 0.24 packaging shift.
|
|
201
201
|
- Why now: `dist/` is now the default JS-only runtime surface and carries mirrored scripts, recipes, fixtures, and skills.
|
|
202
202
|
- Direction:
|
|
@@ -211,7 +211,7 @@ The backlog is intentionally pruned to the 20% of work most likely to deliver 80
|
|
|
211
211
|
### M-11 Actor Termination Semantics
|
|
212
212
|
|
|
213
213
|
- Priority: Medium.
|
|
214
|
-
- Status:
|
|
214
|
+
- Status: Done.
|
|
215
215
|
- Goal: Make `control.kill` the canonical parent-to-actor termination action while keeping `control.stop` and `control.cancel` as actor-domain messages whose meaning depends on the actor protocol.
|
|
216
216
|
- Why now: Mailbox workers need a clearer lifecycle boundary before v2 patterns harden. Treating `stop`, `cancel`, and `kill` as equivalent stop messages blurs actor termination with domain-specific task or playback control.
|
|
217
217
|
- Remaining direction:
|
|
@@ -240,9 +240,5 @@ These are valid ideas but not current focus. Reintroduce only with concrete evid
|
|
|
240
240
|
## Suggested Milestone Order
|
|
241
241
|
|
|
242
242
|
```text
|
|
243
|
-
|
|
244
|
-
M-09
|
|
245
|
-
|
|
246
|
-
0.26 — Package contract hardening and lifecycle semantics:
|
|
247
|
-
M-10, M-11
|
|
243
|
+
Next milestone: choose from deferred items only after concrete actor workflow evidence appears.
|
|
248
244
|
```
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.26.1: Coordinator Empty-Synthesis Hotfix
|
|
6
|
+
|
|
7
|
+
- `[Coordinator]` Treat all-failed participant rounds and empty synthesis as a failed coordinator run instead of a clean success, preserving operator trust when swarm branches all exit non-zero.
|
|
8
|
+
- `[Artifacts]` Write compact diagnostics into empty synthesis artifacts, including participant attempt/success/failure counts and transcript size, so failed swarms leave actionable evidence instead of only `No synthesis output`.
|
|
9
|
+
|
|
10
|
+
## 0.26.0: Actor Worker v2 and Package Contract Hardening
|
|
11
|
+
|
|
12
|
+
- `[Actor Worker]` Promoted the packaged `actor-worker` into a v2 reference pattern with compact `worker-status.json`, optional per-task result artifacts under `worker-artifacts/`, stale-claim surfacing through status, and artifact metadata on `task.result` room messages.
|
|
13
|
+
- `[Recipes]` Audited packaged async recipe mailbox contracts so `control.stop` and `control.cancel` remain declared only for actor-domain handlers such as locker/coordinator/music control, while generic async recipes expose `control.kill` for runtime termination.
|
|
14
|
+
- `[Packaging]` Hardened dist package regressions with mirrored asset checks for `dist/scripts`, `dist/recipes`, `dist/fixtures`, and `dist/skills`, plus negative checks for stale dist files and source-only runtime imports in built script shims.
|
|
15
|
+
- `[Skills]` Updated the actors skill recipe navigator to document the v2 worker pattern and its `control.kill` termination contract.
|
|
16
|
+
|
|
5
17
|
## 0.25.0: Recipe Doctor Remediation UX
|
|
6
18
|
|
|
7
19
|
- `[Recipe Doctor]` Added prioritized advisory remediations to recipe doctor output, including a compact top action, structured verbose remediation entries, blocked lower-priority candidates for invalid/disabled overrides, and ordered coverage for invalid, disabled, shadowed, and risky shell-boundary recipes.
|
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ cat > ~/.pi/agent/recipes/docs_review.json <<'JSON'
|
|
|
89
89
|
"async": true,
|
|
90
90
|
"args": ["scope:path", "model:string"],
|
|
91
91
|
"mailbox": {
|
|
92
|
-
"accepts": ["control.
|
|
92
|
+
"accepts": ["control.kill", "control.continue"],
|
|
93
93
|
"emits": ["review.completed", "run.failed"]
|
|
94
94
|
},
|
|
95
95
|
"template": "pi -p --model {model} --no-tools \"Review {scope} for unclear actor-runtime onboarding. Return concise findings.\""
|
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
* Zones: worker demo, mailbox loop recipe runtime
|
|
4
4
|
*/
|
|
5
5
|
interface ActorWorkerArgs {
|
|
6
|
+
artifact_dir?: string;
|
|
6
7
|
branch?: string;
|
|
7
8
|
poll_ms?: string | number;
|
|
8
9
|
run?: string;
|
|
10
|
+
stale_claim_ms?: string | number;
|
|
9
11
|
state_dir?: string;
|
|
12
|
+
write_artifacts?: string | boolean;
|
|
10
13
|
}
|
|
11
14
|
export declare function parseActorWorkerArgs(argv: string[]): ActorWorkerArgs;
|
|
12
15
|
export declare function runActorWorker(argv?: string[]): Promise<void>;
|
package/dist/lib/actor-worker.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Canonical mailbox-backed actor worker entrypoint logic.
|
|
3
3
|
* Zones: worker demo, mailbox loop recipe runtime
|
|
4
4
|
*/
|
|
5
|
-
import { appendFileSync } from "node:fs";
|
|
5
|
+
import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
|
-
import { appendRoomMessage, ensureRoomMember } from "./actor-rooms.js";
|
|
7
|
+
import { appendRoomMessage, ensureRoomMember, readBranchInboxMessages } from "./actor-rooms.js";
|
|
8
8
|
import { handleMailboxLoopOnce, isMailboxLoopStopMessage } from "./mailbox-loop.js";
|
|
9
9
|
export function parseActorWorkerArgs(argv) {
|
|
10
10
|
const args = {};
|
|
@@ -29,21 +29,54 @@ function sleep(ms) {
|
|
|
29
29
|
function text(value) {
|
|
30
30
|
return typeof value === "string" ? value : JSON.stringify(value);
|
|
31
31
|
}
|
|
32
|
+
function enabled(value) {
|
|
33
|
+
return value !== false && value !== "false" && value !== "0";
|
|
34
|
+
}
|
|
35
|
+
function safeName(value) {
|
|
36
|
+
return String(value ?? "unknown").replaceAll(/[^A-Za-z0-9_.-]+/g, "_");
|
|
37
|
+
}
|
|
32
38
|
export async function runActorWorker(argv = process.argv.slice(2)) {
|
|
33
39
|
const args = parseActorWorkerArgs(argv);
|
|
34
40
|
const stateDir = String(args.state_dir ?? "");
|
|
35
41
|
const run = String(args.run ?? "");
|
|
36
42
|
const branch = String(args.branch ?? "worker");
|
|
37
43
|
const pollMs = Math.max(50, Number(args.poll_ms ?? 1000));
|
|
44
|
+
const staleClaimMs = Math.max(0, Number(args.stale_claim_ms ?? 0));
|
|
45
|
+
const artifactDir = String(args.artifact_dir ?? join(stateDir, "worker-artifacts"));
|
|
46
|
+
const writeArtifacts = enabled(args.write_artifacts ?? true);
|
|
38
47
|
if (!stateDir || !run) {
|
|
39
48
|
throw new Error("usage: actor-worker.mjs --state-dir <dir> --run <id> [--branch worker] [--poll-ms 1000]");
|
|
40
49
|
}
|
|
41
50
|
const branchAddress = `branch:${run}/${branch}`;
|
|
42
51
|
const roomAddress = `room:${run}`;
|
|
43
52
|
const journalPath = join(stateDir, "worker-events.jsonl");
|
|
53
|
+
const statusPath = join(stateDir, "worker-status.json");
|
|
54
|
+
if (writeArtifacts)
|
|
55
|
+
mkdirSync(artifactDir, { recursive: true });
|
|
44
56
|
function journal(event, data = {}) {
|
|
45
57
|
appendFileSync(journalPath, `${JSON.stringify({ event, ts: new Date().toISOString(), ...data })}\n`);
|
|
46
58
|
}
|
|
59
|
+
function staleClaims() {
|
|
60
|
+
if (staleClaimMs <= 0)
|
|
61
|
+
return 0;
|
|
62
|
+
const cutoff = Date.now() - staleClaimMs;
|
|
63
|
+
return readBranchInboxMessages(stateDir, run, branchAddress).filter((record) => {
|
|
64
|
+
if (record.status !== "claimed" || !record.claimed_at)
|
|
65
|
+
return false;
|
|
66
|
+
const claimedAt = Date.parse(record.claimed_at);
|
|
67
|
+
return Number.isFinite(claimedAt) && claimedAt < cutoff;
|
|
68
|
+
}).length;
|
|
69
|
+
}
|
|
70
|
+
function status(state, data = {}) {
|
|
71
|
+
writeFileSync(statusPath, `${JSON.stringify({ artifact_dir: artifactDir, branch, run, stale_claims: staleClaims(), state, ts: new Date().toISOString(), ...data }, null, 2)}\n`);
|
|
72
|
+
}
|
|
73
|
+
function writeResultArtifact(id, result) {
|
|
74
|
+
if (!writeArtifacts)
|
|
75
|
+
return undefined;
|
|
76
|
+
const path = join(artifactDir, `${safeName(id)}.txt`);
|
|
77
|
+
writeFileSync(path, `${result}\n`);
|
|
78
|
+
return path;
|
|
79
|
+
}
|
|
47
80
|
function room(type, summary, body = {}) {
|
|
48
81
|
appendRoomMessage(stateDir, "main", {
|
|
49
82
|
body,
|
|
@@ -55,7 +88,9 @@ export async function runActorWorker(argv = process.argv.slice(2)) {
|
|
|
55
88
|
}
|
|
56
89
|
ensureRoomMember(stateDir, run, "main", branchAddress, { display: branch, role: "worker", status: "present" }, `${branch} joined as mailbox worker`);
|
|
57
90
|
room("awaiting_assignment", `${branch} awaiting assignment`, { branch });
|
|
58
|
-
journal("worker.started", { branch, run });
|
|
91
|
+
journal("worker.started", { artifact_dir: artifactDir, branch, run, stale_claim_ms: staleClaimMs });
|
|
92
|
+
status("awaiting_assignment", { handled: 0, stale_claim_ms: staleClaimMs });
|
|
93
|
+
let handled = 0;
|
|
59
94
|
let stopping = false;
|
|
60
95
|
while (!stopping) {
|
|
61
96
|
const result = await handleMailboxLoopOnce({ address: branchAddress, kind: "branch", run, stateDir }, (message) => {
|
|
@@ -63,6 +98,7 @@ export async function runActorWorker(argv = process.argv.slice(2)) {
|
|
|
63
98
|
stopping = true;
|
|
64
99
|
room("actor.leave", `${branch} stopping`, { branch, reason: message.type });
|
|
65
100
|
journal("worker.stopping", { id: message.id, type: message.type });
|
|
101
|
+
status("stopping", { handled, reason: message.type });
|
|
66
102
|
return;
|
|
67
103
|
}
|
|
68
104
|
room("task.claim", `${branch} claimed ${message.type}`, {
|
|
@@ -70,17 +106,29 @@ export async function runActorWorker(argv = process.argv.slice(2)) {
|
|
|
70
106
|
id: message.id,
|
|
71
107
|
type: message.type,
|
|
72
108
|
});
|
|
109
|
+
const result = text(message.body);
|
|
110
|
+
const artifact = writeResultArtifact(message.id, result);
|
|
111
|
+
handled += 1;
|
|
73
112
|
room("task.result", `${branch} handled ${message.type}`, {
|
|
113
|
+
artifact,
|
|
74
114
|
branch,
|
|
75
115
|
id: message.id,
|
|
76
|
-
result
|
|
116
|
+
result,
|
|
77
117
|
type: message.type,
|
|
78
118
|
});
|
|
79
119
|
room("awaiting_assignment", `${branch} awaiting assignment`, { branch });
|
|
80
|
-
journal("task.handled", { id: message.id, type: message.type });
|
|
120
|
+
journal("task.handled", { artifact, id: message.id, type: message.type });
|
|
121
|
+
status("awaiting_assignment", {
|
|
122
|
+
handled,
|
|
123
|
+
last_artifact: artifact,
|
|
124
|
+
last_id: message.id,
|
|
125
|
+
last_type: message.type,
|
|
126
|
+
stale_claim_ms: staleClaimMs,
|
|
127
|
+
});
|
|
81
128
|
}, { owner: branchAddress });
|
|
82
129
|
if (!result.handled)
|
|
83
130
|
await sleep(pollMs);
|
|
84
131
|
}
|
|
85
|
-
journal("worker.done", { branch, run });
|
|
132
|
+
journal("worker.done", { branch, handled, run });
|
|
133
|
+
status("done", { handled });
|
|
86
134
|
}
|
package/dist/lib/coordinator.js
CHANGED
|
@@ -259,7 +259,7 @@ async function readRoomTranscript(config) {
|
|
|
259
259
|
}
|
|
260
260
|
async function synthesize(config, locker) {
|
|
261
261
|
if (!config.artifactPath)
|
|
262
|
-
return;
|
|
262
|
+
return { code: 0, empty: false };
|
|
263
263
|
if (locker) {
|
|
264
264
|
await writeLockerMessage(locker, {
|
|
265
265
|
type: "lock.claim",
|
|
@@ -269,9 +269,13 @@ async function synthesize(config, locker) {
|
|
|
269
269
|
const transcript = await readRoomTranscript(config);
|
|
270
270
|
const prompt = `Synthesize this transcript into a concise Markdown artifact. Mission: ${config.mission}. Include: Title, Consensus, Roles, Protocol, Final Artifact Shape, Next Actions, Open Questions. Use only the transcript evidence below.\n\nTRANSCRIPT:\n${transcript.slice(-24000)}`;
|
|
271
271
|
const result = await runPi(prompt, config.model, config.thinking);
|
|
272
|
-
|
|
272
|
+
const output = result.stdout.trim();
|
|
273
|
+
const diagnostics = config.stats
|
|
274
|
+
? `\n\n## Diagnostics\n\nparticipant_attempts=${config.stats.participantAttempts}\nparticipant_success=${config.stats.participantSuccess}\nparticipant_failures=${config.stats.participantFailures}\nsynthesis_code=${result.code}\ntranscript_messages=${transcript.trim() ? transcript.split("\n").length : 0}\n`
|
|
275
|
+
: "";
|
|
276
|
+
await writeFile(config.artifactPath, output
|
|
273
277
|
? result.stdout
|
|
274
|
-
:
|
|
278
|
+
: `# Synthesis Artifact\n\nNo synthesis output.${diagnostics}\n`, "utf8");
|
|
275
279
|
if (locker) {
|
|
276
280
|
await writeLockerMessage(locker, {
|
|
277
281
|
type: "lock.complete",
|
|
@@ -284,6 +288,7 @@ async function synthesize(config, locker) {
|
|
|
284
288
|
});
|
|
285
289
|
}
|
|
286
290
|
process.stdout.write(`artifact=${config.artifactPath}\n`);
|
|
291
|
+
return { code: result.code, empty: !output };
|
|
287
292
|
}
|
|
288
293
|
async function readInboxLines(inboxPath) {
|
|
289
294
|
if (!existsSync(inboxPath))
|
|
@@ -378,9 +383,17 @@ async function participantRound(role, round, config) {
|
|
|
378
383
|
const address = `branch:${config.runId}/${role.name}`;
|
|
379
384
|
const prompt = `You are ${displayName} (${address}), ${role.persona}. Mission: ${config.mission}. Round ${round}/${config.rounds}. First call inspect target=${config.room} view=previews lines=30 and inspect target=${config.room} view=contacts. Then call message once to ${config.room} from ${address} type=chat.message. Body: 2-4 sentences that react to a named participant, propose the next coordination step, and refine the shared artifact. Use contacts for peer names and addresses. End stdout with summary <=160 chars.`;
|
|
380
385
|
const result = await executeParticipantPrompt(role, prompt, config);
|
|
386
|
+
if (config.stats) {
|
|
387
|
+
config.stats.participantAttempts += 1;
|
|
388
|
+
if (result.code === 0)
|
|
389
|
+
config.stats.participantSuccess += 1;
|
|
390
|
+
else
|
|
391
|
+
config.stats.participantFailures += 1;
|
|
392
|
+
}
|
|
381
393
|
process.stdout.write(`[${role.name} round ${round}] code=${result.code}\n${result.stdout}\n`);
|
|
382
394
|
if (result.stderr.trim())
|
|
383
395
|
process.stderr.write(`[${role.name} round ${round}] ${result.stderr}\n`);
|
|
396
|
+
return result;
|
|
384
397
|
}
|
|
385
398
|
async function participantJoin(role, config) {
|
|
386
399
|
const displayName = role.name;
|
|
@@ -546,6 +559,11 @@ export async function runCoordinator(argv = process.argv.slice(2)) {
|
|
|
546
559
|
artifactPath: arg("artifact-path", ""),
|
|
547
560
|
locker: boolArg("locker", false),
|
|
548
561
|
lockerLeaseMs: numberArg("locker-lease-ms", 600000),
|
|
562
|
+
stats: {
|
|
563
|
+
participantAttempts: 0,
|
|
564
|
+
participantSuccess: 0,
|
|
565
|
+
participantFailures: 0,
|
|
566
|
+
},
|
|
549
567
|
};
|
|
550
568
|
if (!config.model) {
|
|
551
569
|
console.error("--model is required");
|
|
@@ -559,7 +577,16 @@ export async function runCoordinator(argv = process.argv.slice(2)) {
|
|
|
559
577
|
if (!runMode)
|
|
560
578
|
throw new Error(`Unknown coordinator mode: ${config.mode}`);
|
|
561
579
|
await runMode(config, locker);
|
|
562
|
-
await synthesize(config, locker);
|
|
580
|
+
const synthesis = await synthesize(config, locker);
|
|
581
|
+
if (config.stats.participantAttempts > 0 && config.stats.participantSuccess === 0) {
|
|
582
|
+
failures.push(`All participant rounds failed: attempts=${config.stats.participantAttempts}`);
|
|
583
|
+
}
|
|
584
|
+
if (synthesis?.empty && config.stats.participantFailures > 0) {
|
|
585
|
+
failures.push(`Synthesis output was empty after participant failures: failures=${config.stats.participantFailures}`);
|
|
586
|
+
}
|
|
587
|
+
if (synthesis && synthesis.code !== 0) {
|
|
588
|
+
failures.push(`Synthesis command failed: code=${synthesis.code}`);
|
|
589
|
+
}
|
|
563
590
|
}
|
|
564
591
|
catch (globalError) {
|
|
565
592
|
failures.push(`Global coordinator error: ${globalError.message}`);
|
|
@@ -4,18 +4,20 @@
|
|
|
4
4
|
"args": [
|
|
5
5
|
"repo:path",
|
|
6
6
|
"branch:string",
|
|
7
|
-
"poll_ms:int"
|
|
7
|
+
"poll_ms:int",
|
|
8
|
+
"stale_claim_ms:int",
|
|
9
|
+
"write_artifacts:bool"
|
|
8
10
|
],
|
|
9
11
|
"defaults": {
|
|
10
12
|
"repo": "~/.pi/agent/extensions/pi-actors",
|
|
11
13
|
"branch": "worker",
|
|
12
|
-
"poll_ms": "1000"
|
|
14
|
+
"poll_ms": "1000",
|
|
15
|
+
"stale_claim_ms": "0",
|
|
16
|
+
"write_artifacts": "true"
|
|
13
17
|
},
|
|
14
18
|
"mailbox": {
|
|
15
19
|
"accepts": [
|
|
16
20
|
"task.assign",
|
|
17
|
-
"control.stop",
|
|
18
|
-
"control.cancel",
|
|
19
21
|
"control.kill"
|
|
20
22
|
],
|
|
21
23
|
"emits": [
|
|
@@ -29,7 +31,9 @@
|
|
|
29
31
|
]
|
|
30
32
|
},
|
|
31
33
|
"artifacts": {
|
|
32
|
-
"journal": "{state_dir}/worker-events.jsonl"
|
|
34
|
+
"journal": "{state_dir}/worker-events.jsonl",
|
|
35
|
+
"status": "{state_dir}/worker-status.json",
|
|
36
|
+
"results": "{state_dir}/worker-artifacts"
|
|
33
37
|
},
|
|
34
|
-
"template": "{repo}/scripts/actor-worker.mjs --state-dir {state_dir} --run {run_id} --branch {branch} --poll-ms {poll_ms}"
|
|
38
|
+
"template": "{repo}/scripts/actor-worker.mjs --state-dir {state_dir} --run {run_id} --branch {branch} --poll-ms {poll_ms} --stale-claim-ms {stale_claim_ms} --write-artifacts {write_artifacts}"
|
|
35
39
|
}
|