@llblab/pi-actors 0.43.0 → 0.43.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/AGENTS.md +12 -6
- package/BACKLOG.md +189 -1
- package/CHANGELOG.md +180 -301
- package/README.md +9 -7
- package/dist/index.js +1 -1
- package/dist/lib/async-runs.d.ts +2 -1
- package/dist/lib/async-runs.js +16 -4
- package/dist/lib/automatic-review-runtime.d.ts +1 -1
- package/dist/lib/automatic-review-runtime.js +5 -5
- package/dist/lib/command-templates.d.ts +2 -0
- package/dist/lib/command-templates.js +38 -4
- package/dist/lib/control-projection.d.ts +20 -0
- package/dist/lib/control-projection.js +66 -0
- package/dist/lib/control.d.ts +3 -0
- package/dist/lib/control.js +27 -14
- package/dist/lib/draft-sleep.js +3 -3
- package/dist/lib/file-state.d.ts +1 -0
- package/dist/lib/file-state.js +98 -42
- package/dist/lib/inspector-overlay.d.ts +2 -0
- package/dist/lib/inspector-overlay.js +92 -53
- package/dist/lib/limits.d.ts +5 -3
- package/dist/lib/limits.js +5 -3
- package/dist/lib/prompts.d.ts +1 -1
- package/dist/lib/prompts.js +1 -1
- package/dist/lib/recipe-control.js +6 -2
- package/dist/lib/review-control.d.ts +1 -1
- package/dist/lib/review-control.js +4 -5
- package/dist/lib/runs-control-delivery.d.ts +8 -1
- package/dist/lib/runs-control-delivery.js +38 -15
- package/dist/lib/runs-controls.d.ts +2 -0
- package/dist/lib/runs-controls.js +5 -3
- package/dist/lib/runs-trace.d.ts +2 -2
- package/dist/lib/runs-trace.js +24 -20
- package/dist/lib/runtime-identity.d.ts +7 -0
- package/dist/lib/runtime-identity.js +35 -0
- package/dist/lib/runtime-triage.d.ts +29 -0
- package/dist/lib/runtime-triage.js +76 -0
- package/dist/lib/tool-review-scheduler.js +7 -7
- package/dist/lib/tools-inspect.js +53 -14
- package/dist/lib/tools-message.d.ts +1 -2
- package/dist/lib/tools-message.js +6 -6
- package/dist/lib/tools-response.d.ts +0 -1
- package/dist/lib/tools-response.js +0 -9
- package/dist/lib/tools.d.ts +1 -1
- package/dist/lib/tools.js +1 -1
- package/dist/lib/trace-projection.js +30 -10
- package/dist/scripts/locker.mjs +9 -16
- package/dist/scripts/music-player.mjs +7 -13
- package/dist/scripts/release-gates.mjs +33 -2
- package/dist/scripts/validate-recipe.mjs +5 -4
- package/dist/skills/actors/SKILL.md +12 -7
- package/dist/skills/swarm/SKILL.md +0 -2
- package/docs/0.43-baseline.md +18 -23
- package/docs/README.md +2 -4
- package/docs/actor-inspector.md +5 -5
- package/docs/async-runs.md +2 -2
- package/docs/command-templates.md +6 -116
- package/docs/recipe-library.md +2 -4
- package/docs/releasing.md +28 -0
- package/docs/template-recipes.md +1 -1
- package/docs/tool-registry.md +2 -2
- package/index.ts +1 -1
- package/lib/async-runs.ts +18 -5
- package/lib/automatic-review-runtime.ts +7 -7
- package/lib/command-templates.ts +44 -4
- package/lib/control-projection.ts +105 -0
- package/lib/control.ts +33 -18
- package/lib/draft-sleep.ts +3 -3
- package/lib/file-state.ts +68 -61
- package/lib/inspector-overlay.ts +93 -58
- package/lib/limits.ts +5 -3
- package/lib/prompts.ts +1 -1
- package/lib/recipe-control.ts +9 -2
- package/lib/review-control.ts +4 -5
- package/lib/runs-control-delivery.ts +45 -17
- package/lib/runs-controls.ts +12 -3
- package/lib/runs-trace.ts +23 -19
- package/lib/runtime-identity.ts +39 -0
- package/lib/runtime-triage.ts +120 -0
- package/lib/tool-review-scheduler.ts +7 -7
- package/lib/tools-inspect.ts +60 -16
- package/lib/tools-message.ts +7 -8
- package/lib/tools-response.ts +0 -12
- package/lib/tools.ts +4 -4
- package/lib/trace-projection.ts +33 -10
- package/package.json +1 -1
- package/scripts/locker.mjs +9 -16
- package/scripts/music-player.mjs +7 -13
- package/scripts/release-gates.mjs +33 -2
- package/scripts/validate-recipe.mjs +5 -4
- package/skills/actors/SKILL.md +12 -7
- package/skills/swarm/SKILL.md +0 -2
- package/docs/actors-deep-reference.md +0 -108
- package/docs/component-recipes.md +0 -45
- package/docs/task-first-recipes.md +0 -261
|
@@ -41,6 +41,7 @@ export declare class ActorInspectorOverlay {
|
|
|
41
41
|
private killDialogChoice;
|
|
42
42
|
private rowIndex;
|
|
43
43
|
private runCache?;
|
|
44
|
+
private selectedTraceId?;
|
|
44
45
|
private runIndex;
|
|
45
46
|
private selectorIndex;
|
|
46
47
|
private selectorMode?;
|
|
@@ -81,6 +82,7 @@ export declare class ActorInspectorOverlay {
|
|
|
81
82
|
private readRunMeta;
|
|
82
83
|
private documentProjection;
|
|
83
84
|
private inlineDocumentValue;
|
|
85
|
+
private labeledDocumentLines;
|
|
84
86
|
private labeledScalarLines;
|
|
85
87
|
private document;
|
|
86
88
|
private wrapDocument;
|
|
@@ -7,6 +7,7 @@ import { readFileSync } from "node:fs";
|
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import { matchesKey, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
|
|
9
9
|
import * as ActorInspector from "./inspector.js";
|
|
10
|
+
import * as ControlProjection from "./control-projection.js";
|
|
10
11
|
import * as RunsControls from "./runs-controls.js";
|
|
11
12
|
import * as RunControlDelivery from "./runs-control-delivery.js";
|
|
12
13
|
import * as TraceProjection from "./trace-projection.js";
|
|
@@ -20,6 +21,9 @@ const TRACE_SOURCES = [
|
|
|
20
21
|
"artifact",
|
|
21
22
|
"runtime",
|
|
22
23
|
];
|
|
24
|
+
function newestTraceItems(items) {
|
|
25
|
+
return [...items].sort((left, right) => right.ts.localeCompare(left.ts) || right.id.localeCompare(left.id));
|
|
26
|
+
}
|
|
23
27
|
export class ActorInspectorOverlay {
|
|
24
28
|
done;
|
|
25
29
|
killRun;
|
|
@@ -39,6 +43,7 @@ export class ActorInspectorOverlay {
|
|
|
39
43
|
killDialogChoice = "cancel";
|
|
40
44
|
rowIndex = 0;
|
|
41
45
|
runCache;
|
|
46
|
+
selectedTraceId;
|
|
42
47
|
runIndex = 0;
|
|
43
48
|
selectorIndex = 0;
|
|
44
49
|
selectorMode;
|
|
@@ -56,9 +61,7 @@ export class ActorInspectorOverlay {
|
|
|
56
61
|
this.theme = options.theme;
|
|
57
62
|
this.tui = options.tui;
|
|
58
63
|
this.refreshTimer = setInterval(() => {
|
|
59
|
-
this.
|
|
60
|
-
if (this.focus !== "list" && this.focus !== "detail")
|
|
61
|
-
this.traceCache = undefined;
|
|
64
|
+
this.invalidate();
|
|
62
65
|
this.tui.requestRender();
|
|
63
66
|
}, 1_000);
|
|
64
67
|
this.refreshTimer.unref?.();
|
|
@@ -66,7 +69,10 @@ export class ActorInspectorOverlay {
|
|
|
66
69
|
dispose() {
|
|
67
70
|
clearInterval(this.refreshTimer);
|
|
68
71
|
}
|
|
69
|
-
invalidate() {
|
|
72
|
+
invalidate() {
|
|
73
|
+
this.runCache = undefined;
|
|
74
|
+
this.traceCache = undefined;
|
|
75
|
+
}
|
|
70
76
|
handleInput(data) {
|
|
71
77
|
const runs = this.runs();
|
|
72
78
|
this.runIndex = Math.min(this.runIndex, Math.max(0, runs.length - 1));
|
|
@@ -90,11 +96,14 @@ export class ActorInspectorOverlay {
|
|
|
90
96
|
this.focus = this.tab === "trace" ? "tabs" : "runs";
|
|
91
97
|
}
|
|
92
98
|
else if (this.focus === "detail") {
|
|
99
|
+
this.selectedTraceId = this.traceDetail?.id;
|
|
93
100
|
this.traceDetail = undefined;
|
|
94
101
|
this.detailScroll = 0;
|
|
95
102
|
this.focus = "list";
|
|
96
103
|
}
|
|
97
104
|
else if (this.focus === "document" || this.focus === "list") {
|
|
105
|
+
if (this.focus === "list")
|
|
106
|
+
this.selectedTraceId = undefined;
|
|
98
107
|
this.focus = "tabs";
|
|
99
108
|
}
|
|
100
109
|
else {
|
|
@@ -146,9 +155,12 @@ export class ActorInspectorOverlay {
|
|
|
146
155
|
this.focus = "runs";
|
|
147
156
|
}
|
|
148
157
|
else if (matchesKey(data, "down")) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
158
|
+
const items = this.tab === "trace" ? this.traceItems(runs[this.runIndex]) : [];
|
|
159
|
+
this.focus = items.length > 0 ? "list" : "document";
|
|
160
|
+
if (this.focus === "list") {
|
|
161
|
+
this.rowIndex = 0;
|
|
162
|
+
this.selectedTraceId = items[0]?.id;
|
|
163
|
+
}
|
|
152
164
|
}
|
|
153
165
|
else if (matchesKey(data, "return")) {
|
|
154
166
|
if (this.tab === "trace")
|
|
@@ -158,12 +170,17 @@ export class ActorInspectorOverlay {
|
|
|
158
170
|
}
|
|
159
171
|
}
|
|
160
172
|
else if (this.focus === "list") {
|
|
161
|
-
const
|
|
162
|
-
|
|
173
|
+
const items = this.traceItems(runs[this.runIndex]);
|
|
174
|
+
const count = items.length;
|
|
175
|
+
if (matchesKey(data, "left")) {
|
|
176
|
+
this.selectedTraceId = undefined;
|
|
163
177
|
this.focus = "tabs";
|
|
178
|
+
}
|
|
164
179
|
else if (matchesKey(data, "up")) {
|
|
165
|
-
if (this.rowIndex === 0)
|
|
180
|
+
if (this.rowIndex === 0) {
|
|
181
|
+
this.selectedTraceId = undefined;
|
|
166
182
|
this.focus = "tabs";
|
|
183
|
+
}
|
|
167
184
|
else
|
|
168
185
|
this.rowIndex -= 1;
|
|
169
186
|
}
|
|
@@ -177,13 +194,15 @@ export class ActorInspectorOverlay {
|
|
|
177
194
|
this.rowIndex = Math.min(Math.max(0, count - 1), this.rowIndex + this.contentViewportRows());
|
|
178
195
|
}
|
|
179
196
|
else if (matchesKey(data, "return") || matchesKey(data, "right")) {
|
|
180
|
-
const item =
|
|
197
|
+
const item = items[this.rowIndex];
|
|
181
198
|
if (item) {
|
|
182
199
|
this.traceDetail = item;
|
|
183
200
|
this.detailScroll = 0;
|
|
184
201
|
this.focus = "detail";
|
|
185
202
|
}
|
|
186
203
|
}
|
|
204
|
+
if (this.focus === "list")
|
|
205
|
+
this.selectedTraceId = items[this.rowIndex]?.id;
|
|
187
206
|
}
|
|
188
207
|
if (data.toLowerCase() === "f" && this.tab === "trace") {
|
|
189
208
|
this.cycleTraceSource(runs[this.runIndex]);
|
|
@@ -239,6 +258,7 @@ export class ActorInspectorOverlay {
|
|
|
239
258
|
this.documentScroll = 0;
|
|
240
259
|
this.detailScroll = 0;
|
|
241
260
|
this.rowIndex = 0;
|
|
261
|
+
this.selectedTraceId = undefined;
|
|
242
262
|
this.traceDetail = undefined;
|
|
243
263
|
}
|
|
244
264
|
cycleRun(runs, direction) {
|
|
@@ -260,6 +280,7 @@ export class ActorInspectorOverlay {
|
|
|
260
280
|
this[key] += this.contentViewportRows();
|
|
261
281
|
}
|
|
262
282
|
else if (matchesKey(data, "left") && target === "detail") {
|
|
283
|
+
this.selectedTraceId = this.traceDetail?.id;
|
|
263
284
|
this.traceDetail = undefined;
|
|
264
285
|
this.detailScroll = 0;
|
|
265
286
|
this.focus = "list";
|
|
@@ -361,7 +382,10 @@ export class ActorInspectorOverlay {
|
|
|
361
382
|
if (!confirmation || !this.killRun)
|
|
362
383
|
return;
|
|
363
384
|
try {
|
|
364
|
-
|
|
385
|
+
const result = this.killRun(confirmation.run, confirmation.runInstanceId);
|
|
386
|
+
this.feedback = result.ok ? undefined : result;
|
|
387
|
+
if (result.ok)
|
|
388
|
+
this.invalidate();
|
|
365
389
|
}
|
|
366
390
|
catch (error) {
|
|
367
391
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -387,7 +411,6 @@ export class ActorInspectorOverlay {
|
|
|
387
411
|
`${this.theme.fg("muted", "Current status:")} ${this.theme.fg("warning", confirmation.status)}`,
|
|
388
412
|
"",
|
|
389
413
|
this.theme.fg("text", "This sends canonical kill Control."),
|
|
390
|
-
this.theme.fg("error", "The action is destructive and cannot be undone."),
|
|
391
414
|
"",
|
|
392
415
|
`${cancel} ${kill}`,
|
|
393
416
|
"",
|
|
@@ -480,7 +503,17 @@ export class ActorInspectorOverlay {
|
|
|
480
503
|
const items = this.traceItems(run);
|
|
481
504
|
if (items.length === 0)
|
|
482
505
|
return [this.theme.fg("muted", " No Trace evidence")];
|
|
506
|
+
if (this.selectedTraceId) {
|
|
507
|
+
const selectedIndex = items.findIndex((item) => item.id === this.selectedTraceId);
|
|
508
|
+
if (selectedIndex >= 0)
|
|
509
|
+
this.rowIndex = selectedIndex;
|
|
510
|
+
else
|
|
511
|
+
this.selectedTraceId = undefined;
|
|
512
|
+
}
|
|
483
513
|
this.rowIndex = Math.min(this.rowIndex, items.length - 1);
|
|
514
|
+
if (this.focus === "list" && !this.selectedTraceId) {
|
|
515
|
+
this.selectedTraceId = items[this.rowIndex]?.id;
|
|
516
|
+
}
|
|
484
517
|
const viewportRows = this.contentViewportRows();
|
|
485
518
|
const maxStart = Math.max(0, items.length - viewportRows);
|
|
486
519
|
const start = Math.max(0, Math.min(this.rowIndex - Math.floor(viewportRows / 2), maxStart));
|
|
@@ -495,12 +528,12 @@ export class ActorInspectorOverlay {
|
|
|
495
528
|
const marker = item.level === "error"
|
|
496
529
|
? this.theme.fg("error", "!")
|
|
497
530
|
: detail.attention
|
|
498
|
-
? this.theme.fg("warning", "
|
|
499
|
-
:
|
|
531
|
+
? this.theme.fg("warning", "A")
|
|
532
|
+
: " ";
|
|
500
533
|
const prefix = this.focus === "list" && index === this.rowIndex
|
|
501
534
|
? this.theme.fg("accent", " ▶ ")
|
|
502
535
|
: " ";
|
|
503
|
-
const row = `${prefix}${this.theme.fg("text", `#${
|
|
536
|
+
const row = `${prefix}${this.theme.fg("text", `#${items.length - index}`)} ${marker} ${this.theme.fg("muted", item.source)}/${this.theme.fg(item.level === "error" ? "error" : "accent", item.kind)} ${this.theme.fg("text", item.summary)}`;
|
|
504
537
|
return this.focus === "list" && index === this.rowIndex
|
|
505
538
|
? this.theme.fg("accent", row)
|
|
506
539
|
: row;
|
|
@@ -526,7 +559,10 @@ export class ActorInspectorOverlay {
|
|
|
526
559
|
actor_actions: Array.isArray(meta.control) ? meta.control : [],
|
|
527
560
|
runtime_actions: run.status === "running" ? ["kill"] : ["archive", "prune"],
|
|
528
561
|
endpoint,
|
|
529
|
-
recent_controls: RunsControls.readRunControlsFromStateDir(stateDir)
|
|
562
|
+
recent_controls: RunsControls.readRunControlsFromStateDir(stateDir)
|
|
563
|
+
.slice(-20)
|
|
564
|
+
.reverse()
|
|
565
|
+
.map(ControlProjection.projectRunControl),
|
|
530
566
|
};
|
|
531
567
|
}
|
|
532
568
|
allTraceItems(run) {
|
|
@@ -536,10 +572,10 @@ export class ActorInspectorOverlay {
|
|
|
536
572
|
this.traceCache.runInstanceId === run.runInstanceId) {
|
|
537
573
|
return this.traceCache.items;
|
|
538
574
|
}
|
|
539
|
-
const items = this.readTrace(path.join(this.stateRoot, run.run), {
|
|
575
|
+
const items = newestTraceItems(this.readTrace(path.join(this.stateRoot, run.run), {
|
|
540
576
|
limit: 100,
|
|
541
577
|
source: "all",
|
|
542
|
-
});
|
|
578
|
+
}));
|
|
543
579
|
this.traceCache = { run: run.run, runInstanceId: run.runInstanceId, items };
|
|
544
580
|
return items;
|
|
545
581
|
}
|
|
@@ -567,14 +603,7 @@ export class ActorInspectorOverlay {
|
|
|
567
603
|
}
|
|
568
604
|
documentProjection(value, width) {
|
|
569
605
|
const sections = value && typeof value === "object" && !Array.isArray(value)
|
|
570
|
-
? Object.entries(value).map(([key, item]) =>
|
|
571
|
-
const inline = this.inlineDocumentValue(item);
|
|
572
|
-
return inline !== undefined
|
|
573
|
-
? [`${key}: ${inline}`]
|
|
574
|
-
: item && typeof item === "object"
|
|
575
|
-
? [`${key}:`, ...this.document(item, 1)]
|
|
576
|
-
: this.labeledScalarLines(key, item);
|
|
577
|
-
})
|
|
606
|
+
? Object.entries(value).map(([key, item]) => this.labeledDocumentLines(key, item))
|
|
578
607
|
: [this.document(value)];
|
|
579
608
|
const lines = [];
|
|
580
609
|
const stripes = [];
|
|
@@ -596,19 +625,22 @@ export class ActorInspectorOverlay {
|
|
|
596
625
|
return undefined;
|
|
597
626
|
}
|
|
598
627
|
if (value && typeof value === "object") {
|
|
599
|
-
|
|
600
|
-
if (entries.length === 0)
|
|
628
|
+
if (Object.keys(value).length === 0)
|
|
601
629
|
return "{}";
|
|
602
|
-
if (entries.length <= 3 &&
|
|
603
|
-
entries.every(([, item]) => (item === null || typeof item !== "object") &&
|
|
604
|
-
!(typeof item === "string" && /[\r\n]/u.test(item)))) {
|
|
605
|
-
return `{ ${entries
|
|
606
|
-
.map(([key, item]) => `${key}: ${String(item ?? "none")}`)
|
|
607
|
-
.join(", ")} }`;
|
|
608
|
-
}
|
|
609
630
|
}
|
|
610
631
|
return undefined;
|
|
611
632
|
}
|
|
633
|
+
labeledDocumentLines(key, value, depth = 0) {
|
|
634
|
+
const inline = this.inlineDocumentValue(value);
|
|
635
|
+
if (inline !== undefined)
|
|
636
|
+
return [`${" ".repeat(depth)}${key}: ${inline}`];
|
|
637
|
+
if (value && typeof value === "object") {
|
|
638
|
+
const indent = " ".repeat(depth);
|
|
639
|
+
const nested = this.document(value, depth);
|
|
640
|
+
return [`${indent}${key}: ${nested[0].slice(indent.length)}`, ...nested.slice(1)];
|
|
641
|
+
}
|
|
642
|
+
return this.labeledScalarLines(key, value, depth);
|
|
643
|
+
}
|
|
612
644
|
labeledScalarLines(key, value, depth = 0) {
|
|
613
645
|
const indent = " ".repeat(depth);
|
|
614
646
|
const [first = "", ...rest] = String(value ?? "none").split(/\r?\n/u);
|
|
@@ -624,25 +656,32 @@ export class ActorInspectorOverlay {
|
|
|
624
656
|
if (inline !== undefined)
|
|
625
657
|
return [`${" ".repeat(depth)}${inline}`];
|
|
626
658
|
if (Array.isArray(value)) {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
659
|
+
const indent = " ".repeat(depth);
|
|
660
|
+
return [
|
|
661
|
+
`${indent}[`,
|
|
662
|
+
...value.flatMap((item, index) => {
|
|
663
|
+
const marker = `${indent} - #${index + 1}`;
|
|
664
|
+
const itemInline = this.inlineDocumentValue(item);
|
|
665
|
+
return itemInline !== undefined
|
|
666
|
+
? [`${marker}: ${itemInline}`]
|
|
667
|
+
: [marker, ...this.document(item, depth + 2)];
|
|
668
|
+
}),
|
|
669
|
+
`${indent}]`,
|
|
670
|
+
];
|
|
634
671
|
}
|
|
635
672
|
if (typeof value === "object") {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
673
|
+
const indent = " ".repeat(depth);
|
|
674
|
+
const entries = Object.entries(value);
|
|
675
|
+
return [
|
|
676
|
+
`${indent}{`,
|
|
677
|
+
...entries.flatMap(([key, item], index) => {
|
|
678
|
+
const lines = this.labeledDocumentLines(key, item, depth + 1);
|
|
679
|
+
if (index < entries.length - 1)
|
|
680
|
+
lines[lines.length - 1] += ",";
|
|
681
|
+
return lines;
|
|
682
|
+
}),
|
|
683
|
+
`${indent}}`,
|
|
684
|
+
];
|
|
646
685
|
}
|
|
647
686
|
return String(value)
|
|
648
687
|
.split(/\r?\n/u)
|
package/dist/lib/limits.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared output and
|
|
3
|
-
* Zones: output governance, Trace previews,
|
|
2
|
+
* Shared output, preview, and Control envelope limits.
|
|
3
|
+
* Zones: output governance, Trace previews, Inspect defaults, Control portability
|
|
4
4
|
*/
|
|
5
5
|
export declare const DEFAULT_INSPECT_LINES = 40;
|
|
6
6
|
export declare const TOOL_OUTPUT_MAX_BYTES: number;
|
|
7
7
|
export declare const TOOL_OUTPUT_MAX_LINES = 2000;
|
|
8
8
|
export declare const COMPACT_PREVIEW_CHARS = 160;
|
|
9
|
-
export declare const
|
|
9
|
+
export declare const CONTROL_ACTION_MAX_LENGTH = 64;
|
|
10
|
+
export declare const CONTROL_INPUT_MAX_BYTES = 380;
|
|
11
|
+
export declare const CONTROL_WIRE_MAX_BYTES = 512;
|
|
10
12
|
export declare const INSPECTOR_BODY_PREVIEW_CHARS = 320;
|
|
11
13
|
export declare const DOCTOR_ACTION_PREVIEW_CHARS = 72;
|
|
12
14
|
export declare const SESSION_EVIDENCE_MAX_TURNS = 100;
|
package/dist/lib/limits.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared output and
|
|
3
|
-
* Zones: output governance, Trace previews,
|
|
2
|
+
* Shared output, preview, and Control envelope limits.
|
|
3
|
+
* Zones: output governance, Trace previews, Inspect defaults, Control portability
|
|
4
4
|
*/
|
|
5
5
|
export const DEFAULT_INSPECT_LINES = 40;
|
|
6
6
|
export const TOOL_OUTPUT_MAX_BYTES = 50 * 1024;
|
|
7
7
|
export const TOOL_OUTPUT_MAX_LINES = 2_000;
|
|
8
8
|
export const COMPACT_PREVIEW_CHARS = 160;
|
|
9
|
-
export const
|
|
9
|
+
export const CONTROL_ACTION_MAX_LENGTH = 64;
|
|
10
|
+
export const CONTROL_INPUT_MAX_BYTES = 380;
|
|
11
|
+
export const CONTROL_WIRE_MAX_BYTES = 512;
|
|
10
12
|
export const INSPECTOR_BODY_PREVIEW_CHARS = 320;
|
|
11
13
|
export const DOCTOR_ACTION_PREVIEW_CHARS = 72;
|
|
12
14
|
export const SESSION_EVIDENCE_MAX_TURNS = 100;
|
package/dist/lib/prompts.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
export declare const REGISTER_TOOL_DESCRIPTION: string;
|
|
7
7
|
export declare const REGISTER_TOOL_PROMPT_SNIPPET = "Register persistent command templates as agent-callable tools";
|
|
8
8
|
export declare const REGISTER_TOOL_GUIDELINES: string[];
|
|
9
|
-
export declare const ONBOARDING_SYSTEM_PROMPT = "pi-actors quick model:\n- Local-first actor memory: persist trusted local capabilities instead of rebuilding shell recipes.\n- Layers: task -> command template -> recipe/tool -> spawn -> run:<id>; tool:<name> wraps registered capabilities.\n- Command templates stay sync and shell-free: string leaves split into executable + argv,
|
|
9
|
+
export declare const ONBOARDING_SYSTEM_PROMPT = "pi-actors quick model:\n- Local-first actor memory: persist trusted local capabilities instead of rebuilding shell recipes.\n- Layers: task -> command template -> recipe/tool -> spawn -> run:<id>; tool:<name> wraps registered capabilities.\n- Command templates stay sync and shell-free: string leaves split into executable + argv, infer .js/.mjs through node\u2192bun\u2192deno run and .sh through bash, and treat operators such as && as literal arguments; use template arrays for sequencing or an explicit trusted shell/script when shell semantics are required. Flags include args/defaults, parallel, concurrency, min_successful, when, timeout, delay, retry, failure, recover, repeat, accept_output, output.\n- Placeholders support typed/default args plus {value??fallback} and {flag?yes:no}.\n- ~/.pi/agent/recipes/*.json is actor muscle memory: every recipe there is auto-registered as an agent tool across sessions; register_tool writes there.\n- Recipes own template directly and may declare metadata/defaults/imports/control/artifacts; files >1 MiB or import depth >32 fail closed.\n- Recipe imports are local variables; imported recipes are definitions, not nested async runs; parent async:true creates one run.\n- Actor-mode trigger: if work may outlive this turn, need steering/follow-up/artifacts, run as a service, fan out, or be resumed/inspected later, use spawn -> message -> inspect instead of ad hoc shell backgrounding.\n- Use spawn/message/inspect for actor-level start/send/observe; short foreground checks can stay ordinary tools/templates; avoid internal transport vocabulary in public guidance.\n- Run state lives under ~/.pi/agent/tmp/pi-actors/runs. Inspect intentionally and avoid busy-polling. Terminal and coordinator-bound notifications queue as Pi follow-ups so concurrently completed actors can reach the coordinator after current work instead of steering between tool calls. Terminal follow-up content stays minimal: run, status, one base path, and relative artifact names only; semantic output stays in non-LLM details and run state. When a deferred actor result gates the next step, wait for its terminal follow-up; do not schedule continuation loops, repeatedly inspect, or mutate its reviewed scope while it runs. Inspect early only for an operator request, a meaningful actor event, or diagnosis of an overdue/stuck run.\n- Maintain ~/.pi/agent/recipes like MEMORY.md for capabilities: keep useful tools, curate stale ones, and fix/remove/disable invalid recipes flagged by registry warnings; packaged/ad hoc recipes are lower-priority components; offer to save successful recurring patterns only after confirmation.\n- Prefer maintained packaged recipes/pipelines with spawn file=<recipe> before ad hoc scripts/wrappers; review swarms inherit current model/thinking, preflight before fanout, and expose quorum/concurrency/TTL knobs unless explicit args are passed.\n- For any non-trivial actor use or pi-actors change, read the bundled actors skill first. Before launching multiple actors/subagents for parallel implementation, independent artifact generation, delegated audit, or review, also read the bundled swarm skill; the coordinator owns decomposition, disjoint scopes, launch correctness, integration, and final validation. For deeper guidance, inspect installed extension sources/docs/recipes because README/docs are not automatically in context.";
|
|
10
10
|
export declare const REGISTER_TOOL_PARAM_DESCRIPTIONS: {
|
|
11
11
|
readonly name: "Tool name in snake_case (e.g., 'transcribe')";
|
|
12
12
|
readonly description: "Describe what the tool does for the LLM. Required unless deleting; omitted updates keep the old description.";
|
package/dist/lib/prompts.js
CHANGED
|
@@ -16,7 +16,7 @@ export const REGISTER_TOOL_GUIDELINES = [
|
|
|
16
16
|
export const ONBOARDING_SYSTEM_PROMPT = `pi-actors quick model:
|
|
17
17
|
- Local-first actor memory: persist trusted local capabilities instead of rebuilding shell recipes.
|
|
18
18
|
- Layers: task -> command template -> recipe/tool -> spawn -> run:<id>; tool:<name> wraps registered capabilities.
|
|
19
|
-
- Command templates stay sync and shell-free: string leaves split into executable + argv,
|
|
19
|
+
- Command templates stay sync and shell-free: string leaves split into executable + argv, infer .js/.mjs through node→bun→deno run and .sh through bash, and treat operators such as && as literal arguments; use template arrays for sequencing or an explicit trusted shell/script when shell semantics are required. Flags include args/defaults, parallel, concurrency, min_successful, when, timeout, delay, retry, failure, recover, repeat, accept_output, output.
|
|
20
20
|
- Placeholders support typed/default args plus {value??fallback} and {flag?yes:no}.
|
|
21
21
|
- ~/.pi/agent/recipes/*.json is actor muscle memory: every recipe there is auto-registered as an agent tool across sessions; register_tool writes there.
|
|
22
22
|
- Recipes own template directly and may declare metadata/defaults/imports/control/artifacts; files >1 MiB or import depth >32 fail closed.
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* Zones: actor-local action declarations, normalization, reserved-action fencing
|
|
4
4
|
* Owns pure Recipe control validation; Recipe loading and Run capture stay in recipe/run domains.
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
import * as Control from "./control.js";
|
|
7
|
+
import * as Limits from "./limits.js";
|
|
7
8
|
const RUNTIME_RUN_ACTIONS = new Set(["archive", "kill", "prune"]);
|
|
8
9
|
export function normalizeRecipeControl(value) {
|
|
9
10
|
if (value === undefined)
|
|
@@ -18,9 +19,12 @@ export function normalizeRecipeControl(value) {
|
|
|
18
19
|
throw new Error("recipe.control actions must be non-empty strings");
|
|
19
20
|
}
|
|
20
21
|
const action = raw.trim();
|
|
21
|
-
if (!
|
|
22
|
+
if (!Control.isControlAction(action)) {
|
|
22
23
|
throw new Error(`invalid recipe.control action: ${action}`);
|
|
23
24
|
}
|
|
25
|
+
if (action.length > Limits.CONTROL_ACTION_MAX_LENGTH) {
|
|
26
|
+
throw new Error(`recipe.control action exceeds ${Limits.CONTROL_ACTION_MAX_LENGTH} ASCII characters: ${action}`);
|
|
27
|
+
}
|
|
24
28
|
if (RUNTIME_RUN_ACTIONS.has(action)) {
|
|
25
29
|
throw new Error(`recipe.control action is runtime-reserved and must not be declared: ${action}`);
|
|
26
30
|
}
|
|
@@ -11,4 +11,4 @@ export interface AutomaticReviewControlOptions {
|
|
|
11
11
|
toolStatePath?: string;
|
|
12
12
|
}
|
|
13
13
|
export declare function controlAutomaticReview(action: AutomaticReviewControlAction, scope: AutomaticReviewScope, options?: AutomaticReviewControlOptions): Record<string, unknown>;
|
|
14
|
-
export declare function parseAutomaticReviewScope(
|
|
14
|
+
export declare function parseAutomaticReviewScope(input: unknown): AutomaticReviewScope;
|
|
@@ -98,14 +98,13 @@ export function controlAutomaticReview(action, scope, options = {}) {
|
|
|
98
98
|
return {
|
|
99
99
|
...result,
|
|
100
100
|
next_actions: nextActions,
|
|
101
|
-
sent: result.changed === true,
|
|
102
101
|
};
|
|
103
102
|
}
|
|
104
|
-
export function parseAutomaticReviewScope(
|
|
105
|
-
const record =
|
|
106
|
-
?
|
|
103
|
+
export function parseAutomaticReviewScope(input) {
|
|
104
|
+
const record = input && typeof input === "object" && !Array.isArray(input)
|
|
105
|
+
? input
|
|
107
106
|
: {};
|
|
108
107
|
if (record.scope === "draft" || record.scope === "tool")
|
|
109
108
|
return record.scope;
|
|
110
|
-
throw new Error("review
|
|
109
|
+
throw new Error("review Control requires input.scope=draft or input.scope=tool.");
|
|
111
110
|
}
|
|
@@ -16,6 +16,13 @@ export interface DeliverRunControlRequest {
|
|
|
16
16
|
input?: unknown;
|
|
17
17
|
run_instance_id: string;
|
|
18
18
|
}
|
|
19
|
-
export declare
|
|
19
|
+
export declare function encodeRunControlWire(wire: {
|
|
20
|
+
action: string;
|
|
21
|
+
id: string;
|
|
22
|
+
input?: unknown;
|
|
23
|
+
}): {
|
|
24
|
+
bytes: number;
|
|
25
|
+
payload: string;
|
|
26
|
+
};
|
|
20
27
|
export declare function readRunControlEndpoint(stateDir: string, runInstanceId: string): RunControlEndpoint | undefined;
|
|
21
28
|
export declare function deliverRunControl(run: string, stateDir: string, request: DeliverRunControlRequest, options?: DeliverRunControlOptions): Promise<Record<string, unknown>>;
|
|
@@ -6,9 +6,23 @@
|
|
|
6
6
|
import { closeSync, constants, existsSync, openSync, statSync, writeSync, } from "node:fs";
|
|
7
7
|
import { createConnection } from "node:net";
|
|
8
8
|
import { join } from "node:path";
|
|
9
|
+
import * as Control from "./control.js";
|
|
10
|
+
import * as Limits from "./limits.js";
|
|
9
11
|
import { appendRunControlInStateDir, updateRunControlStatusInStateDir, } from "./runs-controls.js";
|
|
10
12
|
import { readJsonFileResilient } from "./state-readers.js";
|
|
11
|
-
|
|
13
|
+
const PREFLIGHT_CONTROL_ID = "00000000-0000-4000-8000-000000000000";
|
|
14
|
+
export function encodeRunControlWire(wire) {
|
|
15
|
+
const payload = `${JSON.stringify({
|
|
16
|
+
id: wire.id,
|
|
17
|
+
action: wire.action,
|
|
18
|
+
...(wire.input !== undefined ? { input: wire.input } : {}),
|
|
19
|
+
})}\n`;
|
|
20
|
+
const bytes = Buffer.byteLength(payload);
|
|
21
|
+
if (bytes > Limits.CONTROL_WIRE_MAX_BYTES) {
|
|
22
|
+
throw new Error(`Run Control wire record exceeds the ${Limits.CONTROL_WIRE_MAX_BYTES}-byte portable bound`);
|
|
23
|
+
}
|
|
24
|
+
return { bytes, payload };
|
|
25
|
+
}
|
|
12
26
|
export function readRunControlEndpoint(stateDir, runInstanceId) {
|
|
13
27
|
const endpoint = readJsonFileResilient(join(stateDir, "control-endpoint.json"), {}).value;
|
|
14
28
|
if (endpoint.run_instance_id !== runInstanceId)
|
|
@@ -65,34 +79,43 @@ function sendToNamedPipe(endpoint, payload, send) {
|
|
|
65
79
|
});
|
|
66
80
|
}
|
|
67
81
|
export async function deliverRunControl(run, stateDir, request, options = {}) {
|
|
68
|
-
const
|
|
82
|
+
const action = Control.normalizeControlAction(request.action);
|
|
83
|
+
const input = request.input === undefined
|
|
84
|
+
? undefined
|
|
85
|
+
: Control.normalizeControlInput(request.input);
|
|
86
|
+
const normalizedRequest = {
|
|
87
|
+
action,
|
|
88
|
+
...(input !== undefined ? { input } : {}),
|
|
89
|
+
run_instance_id: request.run_instance_id,
|
|
90
|
+
};
|
|
91
|
+
encodeRunControlWire({
|
|
92
|
+
id: PREFLIGHT_CONTROL_ID,
|
|
93
|
+
action,
|
|
94
|
+
...(input !== undefined ? { input } : {}),
|
|
95
|
+
});
|
|
96
|
+
const control = appendRunControlInStateDir(stateDir, normalizedRequest);
|
|
69
97
|
const endpoint = readRunControlEndpoint(stateDir, request.run_instance_id);
|
|
70
98
|
if (!endpoint) {
|
|
71
99
|
updateRunControlStatusInStateDir(stateDir, control.id, "failed", { error: "control endpoint is not ready for this Run generation" }, ["queued", "delivered"]);
|
|
72
100
|
throw Object.assign(new Error("Run Control endpoint is not ready."), {
|
|
73
|
-
action
|
|
101
|
+
action,
|
|
74
102
|
control_id: control.id,
|
|
75
103
|
reason: "endpoint_not_ready",
|
|
76
104
|
run,
|
|
77
105
|
run_instance_id: request.run_instance_id,
|
|
78
106
|
});
|
|
79
107
|
}
|
|
80
|
-
const wire = {
|
|
81
|
-
id: control.id,
|
|
82
|
-
action: request.action,
|
|
83
|
-
...(request.input !== undefined ? { input: request.input } : {}),
|
|
84
|
-
};
|
|
85
|
-
const payload = `${JSON.stringify(wire)}\n`;
|
|
86
|
-
const bytes = Buffer.byteLength(payload);
|
|
87
108
|
try {
|
|
109
|
+
const { bytes, payload } = encodeRunControlWire({
|
|
110
|
+
id: control.id,
|
|
111
|
+
action,
|
|
112
|
+
...(input !== undefined ? { input } : {}),
|
|
113
|
+
});
|
|
88
114
|
let written;
|
|
89
115
|
if (endpoint.type === "fifo") {
|
|
90
116
|
if ((options.platform ?? process.platform) === "win32") {
|
|
91
117
|
throw new Error("FIFO Control delivery is unsupported on native Windows");
|
|
92
118
|
}
|
|
93
|
-
if (bytes > FIFO_ATOMIC_CONTROL_MAX_BYTES) {
|
|
94
|
-
throw new Error(`FIFO Control payload exceeds the ${FIFO_ATOMIC_CONTROL_MAX_BYTES}-byte portable atomic-write bound`);
|
|
95
|
-
}
|
|
96
119
|
written = sendToFifo(endpoint, payload);
|
|
97
120
|
}
|
|
98
121
|
else {
|
|
@@ -103,7 +126,7 @@ export async function deliverRunControl(run, stateDir, request, options = {}) {
|
|
|
103
126
|
}
|
|
104
127
|
updateRunControlStatusInStateDir(stateDir, control.id, "delivered");
|
|
105
128
|
return {
|
|
106
|
-
action
|
|
129
|
+
action,
|
|
107
130
|
bytes,
|
|
108
131
|
control_id: control.id,
|
|
109
132
|
delivery: "delivered",
|
|
@@ -116,7 +139,7 @@ export async function deliverRunControl(run, stateDir, request, options = {}) {
|
|
|
116
139
|
const reason = error instanceof Error ? error.message : String(error);
|
|
117
140
|
updateRunControlStatusInStateDir(stateDir, control.id, "failed", { error: reason }, ["queued", "delivered"]);
|
|
118
141
|
throw Object.assign(new Error(`Run Control delivery failed: ${reason}`), {
|
|
119
|
-
action
|
|
142
|
+
action,
|
|
120
143
|
control_id: control.id,
|
|
121
144
|
endpoint_type: endpoint.type,
|
|
122
145
|
reason: "delivery_failed",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Zones: durable Control records, claim locks, status transitions, bounded compaction
|
|
4
4
|
* Owns Run-local Control persistence; owner/generation authorization and transport delivery stay in lifecycle adapters.
|
|
5
5
|
*/
|
|
6
|
+
import { type JsonlReadResult } from "./state-readers.ts";
|
|
6
7
|
export declare const RUN_CONTROL_TERMINAL_LIMIT = 128;
|
|
7
8
|
export type RunControlStatus = "queued" | "delivered" | "claimed" | "handled" | "failed";
|
|
8
9
|
export interface RunControlRecord {
|
|
@@ -24,6 +25,7 @@ export interface ProcessRunControlsResult {
|
|
|
24
25
|
handled: number;
|
|
25
26
|
}
|
|
26
27
|
export declare function runControlsFile(stateDir: string): string;
|
|
28
|
+
export declare function readRunControlJournalFromStateDir(stateDir: string): JsonlReadResult<unknown>;
|
|
27
29
|
export declare function readRunControlsFromStateDir(stateDir: string): RunControlRecord[];
|
|
28
30
|
export declare function appendRunControlInStateDir(stateDir: string, request: {
|
|
29
31
|
run_instance_id: string;
|
|
@@ -7,15 +7,17 @@ import { randomUUID } from "node:crypto";
|
|
|
7
7
|
import { writeFileSync } from "node:fs";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
import { acquireFileMutationLock, writeTextAtomic } from "./file-state.js";
|
|
10
|
-
import { readJsonlFileResilient } from "./state-readers.js";
|
|
10
|
+
import { readJsonlFileResilient, } from "./state-readers.js";
|
|
11
11
|
export const RUN_CONTROL_TERMINAL_LIMIT = 128;
|
|
12
12
|
const TERMINAL_STATUSES = new Set(["handled", "failed"]);
|
|
13
13
|
export function runControlsFile(stateDir) {
|
|
14
14
|
return join(stateDir, "controls.jsonl");
|
|
15
15
|
}
|
|
16
|
+
export function readRunControlJournalFromStateDir(stateDir) {
|
|
17
|
+
return readJsonlFileResilient(runControlsFile(stateDir));
|
|
18
|
+
}
|
|
16
19
|
export function readRunControlsFromStateDir(stateDir) {
|
|
17
|
-
return
|
|
18
|
-
.records;
|
|
20
|
+
return readRunControlJournalFromStateDir(stateDir).records;
|
|
19
21
|
}
|
|
20
22
|
function acquireRunControlsLock(stateDir) {
|
|
21
23
|
return acquireFileMutationLock(runControlsFile(stateDir));
|
package/dist/lib/runs-trace.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Run Trace event journal.
|
|
3
|
-
* Zones: structured event validation,
|
|
4
|
-
* Owns Run-local
|
|
3
|
+
* Zones: structured event validation, token-locked append-only writes, resilient bounded reads
|
|
4
|
+
* Owns canonical Run-local Trace persistence; lifecycle projection and owner attention delivery stay in adapters.
|
|
5
5
|
*/
|
|
6
6
|
export interface TraceEvent {
|
|
7
7
|
id: string;
|