@llblab/pi-actors 0.41.1 → 0.42.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/AGENTS.md +11 -6
- package/BACKLOG.md +2 -62
- package/CHANGELOG.md +15 -0
- package/README.md +22 -4
- package/dist/index.js +25 -121
- package/dist/lib/async-runs.d.ts +25 -5
- package/dist/lib/async-runs.js +136 -47
- package/dist/lib/automatic-review-runtime.d.ts +18 -0
- package/dist/lib/automatic-review-runtime.js +96 -0
- package/dist/lib/draft-consolidation-transaction.d.ts +65 -0
- package/dist/lib/draft-consolidation-transaction.js +610 -0
- package/dist/lib/draft-consolidation.d.ts +35 -0
- package/dist/lib/draft-consolidation.js +126 -0
- package/dist/lib/draft-review.d.ts +56 -0
- package/dist/lib/draft-review.js +254 -0
- package/dist/lib/draft-sleep.d.ts +65 -0
- package/dist/lib/draft-sleep.js +468 -0
- package/dist/lib/file-state.d.ts +8 -1
- package/dist/lib/file-state.js +115 -18
- package/dist/lib/inspector-actions.d.ts +16 -0
- package/dist/lib/inspector-actions.js +57 -0
- package/dist/lib/inspector-command.d.ts +7 -0
- package/dist/lib/inspector-command.js +37 -0
- package/dist/lib/inspector-overlay.d.ts +20 -3
- package/dist/lib/inspector-overlay.js +275 -74
- package/dist/lib/inspector.d.ts +9 -0
- package/dist/lib/inspector.js +48 -0
- package/dist/lib/observability.d.ts +1 -0
- package/dist/lib/observability.js +11 -1
- package/dist/lib/paths.d.ts +7 -0
- package/dist/lib/paths.js +28 -0
- package/dist/lib/recipes-discovery.js +32 -24
- package/dist/lib/recipes-usage.d.ts +18 -6
- package/dist/lib/recipes-usage.js +445 -34
- package/dist/lib/review-control.d.ts +14 -0
- package/dist/lib/review-control.js +111 -0
- package/dist/lib/review-diagnostics.d.ts +11 -0
- package/dist/lib/review-diagnostics.js +148 -0
- package/dist/lib/review-projection.d.ts +14 -0
- package/dist/lib/review-projection.js +170 -0
- package/dist/lib/run-ui-runtime.d.ts +18 -0
- package/dist/lib/run-ui-runtime.js +123 -0
- package/dist/lib/runs-artifacts.d.ts +1 -1
- package/dist/lib/runs-artifacts.js +1 -1
- package/dist/lib/runs-control.d.ts +8 -2
- package/dist/lib/runs-control.js +23 -6
- package/dist/lib/runs-identity.d.ts +1 -1
- package/dist/lib/runs-identity.js +1 -1
- package/dist/lib/runs-index.d.ts +11 -2
- package/dist/lib/runs-index.js +46 -23
- package/dist/lib/runs-mailbox.d.ts +1 -1
- package/dist/lib/runs-mailbox.js +1 -1
- package/dist/lib/runs-messages.d.ts +1 -1
- package/dist/lib/runs-messages.js +1 -1
- package/dist/lib/runs-outbox.d.ts +1 -1
- package/dist/lib/runs-outbox.js +1 -1
- package/dist/lib/runs-ownership.d.ts +1 -1
- package/dist/lib/runs-ownership.js +1 -1
- package/dist/lib/runs-parent-teardown.d.ts +51 -0
- package/dist/lib/runs-parent-teardown.js +172 -0
- package/dist/lib/runs-process.d.ts +1 -1
- package/dist/lib/runs-process.js +1 -1
- package/dist/lib/runs-retention.d.ts +1 -1
- package/dist/lib/runs-retention.js +1 -1
- package/dist/lib/runs-start.d.ts +5 -3
- package/dist/lib/runs-start.js +6 -48
- package/dist/lib/runs-status.d.ts +5 -3
- package/dist/lib/runs-status.js +4 -6
- package/dist/lib/runtime.d.ts +7 -1
- package/dist/lib/runtime.js +32 -18
- package/dist/lib/tool-review-lineage-transaction.d.ts +27 -0
- package/dist/lib/tool-review-lineage-transaction.js +597 -0
- package/dist/lib/tool-review-lineage.d.ts +24 -0
- package/dist/lib/tool-review-lineage.js +98 -0
- package/dist/lib/tool-review-scheduler.d.ts +80 -0
- package/dist/lib/tool-review-scheduler.js +494 -0
- package/dist/lib/tool-review-transaction.d.ts +50 -0
- package/dist/lib/tool-review-transaction.js +362 -0
- package/dist/lib/tool-review.d.ts +56 -0
- package/dist/lib/tool-review.js +197 -0
- package/dist/lib/tools-inspect.js +26 -3
- package/dist/lib/tools-local.js +4 -2
- package/dist/lib/tools-message.d.ts +1 -0
- package/dist/lib/tools-message.js +29 -17
- package/dist/lib/tools-spawn.js +4 -1
- package/dist/lib/tools.d.ts +1 -0
- package/dist/lib/tools.js +1 -0
- package/dist/recipes/draft-review.json +24 -0
- package/dist/recipes/tool-review.json +24 -0
- package/dist/scripts/release-gates.mjs +165 -0
- package/dist/skills/actors/SKILL.md +9 -8
- package/dist/skills/swarm/SKILL.md +1 -1
- package/docs/actor-inspector.md +20 -11
- package/docs/async-runs.md +9 -1
- package/docs/recipe-library.md +7 -3
- package/docs/template-recipes.md +4 -11
- package/docs/tool-registry.md +11 -4
- package/index.ts +27 -142
- package/lib/async-runs.ts +218 -62
- package/lib/automatic-review-runtime.ts +135 -0
- package/lib/draft-consolidation-transaction.ts +821 -0
- package/lib/draft-consolidation.ts +181 -0
- package/lib/draft-review.ts +325 -0
- package/lib/draft-sleep.ts +576 -0
- package/lib/file-state.ts +143 -19
- package/lib/inspector-actions.ts +79 -0
- package/lib/inspector-command.ts +54 -0
- package/lib/inspector-overlay.ts +325 -91
- package/lib/inspector.ts +72 -0
- package/lib/observability.ts +14 -1
- package/lib/paths.ts +43 -0
- package/lib/recipes-discovery.ts +34 -26
- package/lib/recipes-usage.ts +569 -40
- package/lib/review-control.ts +137 -0
- package/lib/review-diagnostics.ts +164 -0
- package/lib/review-projection.ts +200 -0
- package/lib/run-ui-runtime.ts +153 -0
- package/lib/runs-artifacts.ts +1 -1
- package/lib/runs-control.ts +49 -5
- package/lib/runs-identity.ts +1 -1
- package/lib/runs-index.ts +57 -21
- package/lib/runs-mailbox.ts +1 -1
- package/lib/runs-messages.ts +1 -1
- package/lib/runs-outbox.ts +1 -1
- package/lib/runs-ownership.ts +1 -1
- package/lib/runs-parent-teardown.ts +257 -0
- package/lib/runs-process.ts +1 -1
- package/lib/runs-retention.ts +1 -1
- package/lib/runs-start.ts +12 -68
- package/lib/runs-status.ts +12 -8
- package/lib/runtime.ts +34 -17
- package/lib/tool-review-lineage-transaction.ts +881 -0
- package/lib/tool-review-lineage.ts +145 -0
- package/lib/tool-review-scheduler.ts +635 -0
- package/lib/tool-review-transaction.ts +563 -0
- package/lib/tool-review.ts +270 -0
- package/lib/tools-inspect.ts +33 -3
- package/lib/tools-local.ts +8 -2
- package/lib/tools-message.ts +45 -30
- package/lib/tools-spawn.ts +8 -1
- package/lib/tools.ts +5 -0
- package/package.json +3 -2
- package/recipes/draft-review.json +24 -0
- package/recipes/tool-review.json +24 -0
- package/scripts/release-gates.mjs +165 -0
- package/skills/actors/SKILL.md +9 -8
- package/skills/swarm/SKILL.md +1 -1
package/lib/inspector-overlay.ts
CHANGED
|
@@ -12,21 +12,36 @@ import {
|
|
|
12
12
|
matchesKey,
|
|
13
13
|
truncateToWidth,
|
|
14
14
|
visibleWidth,
|
|
15
|
-
wrapTextWithAnsi,
|
|
16
15
|
type TUI,
|
|
17
16
|
} from "@earendil-works/pi-tui";
|
|
18
17
|
|
|
19
18
|
import * as Inspector from "./inspector.ts";
|
|
20
19
|
|
|
21
|
-
export type ActorInspectorOverlayTab = "communications" | "turns";
|
|
20
|
+
export type ActorInspectorOverlayTab = "recipe" | "communications" | "turns";
|
|
21
|
+
|
|
22
|
+
const INSPECTOR_TABS: ActorInspectorOverlayTab[] = [
|
|
23
|
+
"recipe",
|
|
24
|
+
"communications",
|
|
25
|
+
"turns",
|
|
26
|
+
];
|
|
22
27
|
|
|
23
28
|
type DetailLogicalLine = string | { sectionBreak: true };
|
|
24
29
|
|
|
25
30
|
const DETAIL_SECTION_BREAK: DetailLogicalLine = { sectionBreak: true };
|
|
26
31
|
|
|
32
|
+
export interface ActorInspectorOverlayActionResult {
|
|
33
|
+
ok: boolean;
|
|
34
|
+
message: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
export interface ActorInspectorOverlayOptions {
|
|
28
38
|
done: () => void;
|
|
39
|
+
killRun?: (
|
|
40
|
+
run: string,
|
|
41
|
+
runInstanceId: string,
|
|
42
|
+
) => ActorInspectorOverlayActionResult;
|
|
29
43
|
ownerId: string;
|
|
44
|
+
readTurns?: (stateDir: string) => Inspector.ActorInspectorTurnItem[];
|
|
30
45
|
stateRoot: string;
|
|
31
46
|
theme: Theme;
|
|
32
47
|
tui: TUI;
|
|
@@ -34,7 +49,12 @@ export interface ActorInspectorOverlayOptions {
|
|
|
34
49
|
|
|
35
50
|
export class ActorInspectorOverlay {
|
|
36
51
|
private readonly done: () => void;
|
|
52
|
+
private readonly killRun?: (
|
|
53
|
+
run: string,
|
|
54
|
+
runInstanceId: string,
|
|
55
|
+
) => ActorInspectorOverlayActionResult;
|
|
37
56
|
private readonly ownerId: string;
|
|
57
|
+
private readonly readTurns: (stateDir: string) => Inspector.ActorInspectorTurnItem[];
|
|
38
58
|
private readonly stateRoot: string;
|
|
39
59
|
private readonly theme: Theme;
|
|
40
60
|
private readonly tui: TUI;
|
|
@@ -48,24 +68,32 @@ export class ActorInspectorOverlay {
|
|
|
48
68
|
private detailOpen = false;
|
|
49
69
|
private detailScroll = 0;
|
|
50
70
|
private detailTurn?: Inspector.ActorInspectorTurnItem;
|
|
51
|
-
private
|
|
71
|
+
private feedback?: ActorInspectorOverlayActionResult;
|
|
72
|
+
private killConfirmation?: { run: string; runInstanceId: string };
|
|
52
73
|
private readonly readKeys = new Set<string>();
|
|
53
|
-
private focus: "runs" | "tabs" | "list" | "detail" | "select" = "tabs";
|
|
74
|
+
private focus: "runs" | "tabs" | "recipe" | "list" | "detail" | "select" = "tabs";
|
|
54
75
|
private filterControlIndex = 0;
|
|
55
76
|
private menuLevel: "run" | "filter" | "value" = "filter";
|
|
56
77
|
private selectorIndex = 0;
|
|
78
|
+
private recipeScroll = 0;
|
|
57
79
|
private rowIndex = 0;
|
|
58
80
|
private selectedRun?: string;
|
|
59
81
|
private subagentIndex = 0;
|
|
60
|
-
private tab: ActorInspectorOverlayTab = "
|
|
82
|
+
private tab: ActorInspectorOverlayTab = "recipe";
|
|
83
|
+
private turnCache?: { run: string; turns: Inspector.ActorInspectorTurnItem[] };
|
|
61
84
|
|
|
62
85
|
constructor(options: ActorInspectorOverlayOptions) {
|
|
63
86
|
this.done = options.done;
|
|
87
|
+
this.killRun = options.killRun;
|
|
64
88
|
this.ownerId = options.ownerId;
|
|
89
|
+
this.readTurns = options.readTurns ?? Inspector.readActorInspectorTurns;
|
|
65
90
|
this.stateRoot = options.stateRoot;
|
|
66
91
|
this.theme = options.theme;
|
|
67
92
|
this.tui = options.tui;
|
|
68
|
-
this.refreshTimer = setInterval(() =>
|
|
93
|
+
this.refreshTimer = setInterval(() => {
|
|
94
|
+
if (this.focus !== "list" && this.focus !== "detail") this.turnCache = undefined;
|
|
95
|
+
this.tui.requestRender();
|
|
96
|
+
}, 1000);
|
|
69
97
|
this.refreshTimer.unref?.();
|
|
70
98
|
}
|
|
71
99
|
|
|
@@ -76,6 +104,21 @@ export class ActorInspectorOverlay {
|
|
|
76
104
|
this.done();
|
|
77
105
|
return;
|
|
78
106
|
}
|
|
107
|
+
if (this.killConfirmation) {
|
|
108
|
+
if (matchesKey(data, "escape") || data.toLowerCase() === "n") {
|
|
109
|
+
this.feedback = { ok: false, message: "Kill cancelled." };
|
|
110
|
+
this.killConfirmation = undefined;
|
|
111
|
+
} else if (matchesKey(data, "return") || data.toLowerCase() === "y") {
|
|
112
|
+
this.confirmKill();
|
|
113
|
+
}
|
|
114
|
+
this.tui.requestRender();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (data.toLowerCase() === "k") {
|
|
118
|
+
this.requestKill(runs);
|
|
119
|
+
this.tui.requestRender();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
79
122
|
if (matchesKey(data, "escape")) {
|
|
80
123
|
if (this.focus === "select") {
|
|
81
124
|
if (this.menuLevel === "value") {
|
|
@@ -83,6 +126,7 @@ export class ActorInspectorOverlay {
|
|
|
83
126
|
this.selectorIndex = this.filterControlIndex;
|
|
84
127
|
} else this.focus = this.menuLevel === "run" ? "runs" : "tabs";
|
|
85
128
|
} else if (this.focus === "detail") this.backDetail();
|
|
129
|
+
else if (this.focus === "recipe") this.focus = "tabs";
|
|
86
130
|
else this.done();
|
|
87
131
|
this.tui.requestRender();
|
|
88
132
|
return;
|
|
@@ -102,18 +146,27 @@ export class ActorInspectorOverlay {
|
|
|
102
146
|
this.tui.requestRender();
|
|
103
147
|
return;
|
|
104
148
|
}
|
|
149
|
+
if (this.focus === "recipe") {
|
|
150
|
+
if (matchesKey(data, "up")) {
|
|
151
|
+
if (this.recipeScroll === 0) this.focus = "tabs";
|
|
152
|
+
else this.recipeScroll -= 1;
|
|
153
|
+
} else if (matchesKey(data, "down")) this.recipeScroll += 1;
|
|
154
|
+
else if (matchesKey(data, "pageUp"))
|
|
155
|
+
this.recipeScroll = Math.max(0, this.recipeScroll - this.contentViewportRows());
|
|
156
|
+
else if (matchesKey(data, "pageDown"))
|
|
157
|
+
this.recipeScroll += this.contentViewportRows();
|
|
158
|
+
else if (matchesKey(data, "left")) this.focus = "tabs";
|
|
159
|
+
this.tui.requestRender();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
105
162
|
if (this.focus === "detail") {
|
|
106
163
|
if (matchesKey(data, "up")) this.detailScroll = Math.max(0, this.detailScroll - 1);
|
|
107
164
|
else if (matchesKey(data, "down")) this.detailScroll += 1;
|
|
165
|
+
else if (matchesKey(data, "pageUp"))
|
|
166
|
+
this.detailScroll = Math.max(0, this.detailScroll - this.contentViewportRows());
|
|
167
|
+
else if (matchesKey(data, "pageDown"))
|
|
168
|
+
this.detailScroll += this.contentViewportRows();
|
|
108
169
|
else if (matchesKey(data, "left")) this.backDetail();
|
|
109
|
-
else if (
|
|
110
|
-
(matchesKey(data, "right") || matchesKey(data, "return")) &&
|
|
111
|
-
this.detailView === "evidence" &&
|
|
112
|
-
this.tab === "turns"
|
|
113
|
-
) {
|
|
114
|
-
this.detailView = "transcript";
|
|
115
|
-
this.detailScroll = 0;
|
|
116
|
-
}
|
|
117
170
|
this.tui.requestRender();
|
|
118
171
|
return;
|
|
119
172
|
}
|
|
@@ -124,16 +177,30 @@ export class ActorInspectorOverlay {
|
|
|
124
177
|
else if (matchesKey(data, "return") && runs.length > 0) this.openRunMenu();
|
|
125
178
|
} else if (this.focus === "tabs") {
|
|
126
179
|
if (matchesKey(data, "left") || matchesKey(data, "right")) {
|
|
127
|
-
|
|
180
|
+
const current = INSPECTOR_TABS.indexOf(this.tab);
|
|
181
|
+
const direction = matchesKey(data, "right") ? 1 : -1;
|
|
182
|
+
this.tab = INSPECTOR_TABS[
|
|
183
|
+
(current + direction + INSPECTOR_TABS.length) % INSPECTOR_TABS.length
|
|
184
|
+
]!;
|
|
128
185
|
this.filterControlIndex = 0;
|
|
186
|
+
this.recipeScroll = 0;
|
|
129
187
|
this.rowIndex = 0;
|
|
130
188
|
} else if (matchesKey(data, "up")) this.focus = "runs";
|
|
189
|
+
else if (
|
|
190
|
+
(matchesKey(data, "down") || matchesKey(data, "return")) &&
|
|
191
|
+
this.tab === "recipe"
|
|
192
|
+
) this.focus = "recipe";
|
|
131
193
|
else if (matchesKey(data, "down") && this.listItemCount() > 0)
|
|
132
194
|
this.focus = "list";
|
|
133
195
|
else if (matchesKey(data, "return")) this.openFilterMenu();
|
|
134
196
|
} else if (this.focus === "list") {
|
|
135
197
|
const count = this.tab === "communications" ? this.communicationPreviews().length : this.turnItems().length;
|
|
136
|
-
if (matchesKey(data, "
|
|
198
|
+
if (matchesKey(data, "left")) this.focus = "tabs";
|
|
199
|
+
else if (matchesKey(data, "pageUp"))
|
|
200
|
+
this.rowIndex = Math.max(0, this.rowIndex - this.contentViewportRows());
|
|
201
|
+
else if (matchesKey(data, "pageDown"))
|
|
202
|
+
this.rowIndex = Math.min(Math.max(0, count - 1), this.rowIndex + this.contentViewportRows());
|
|
203
|
+
else if (matchesKey(data, "up")) {
|
|
137
204
|
if (this.rowIndex === 0) this.focus = "tabs";
|
|
138
205
|
else this.rowIndex -= 1;
|
|
139
206
|
} else if (matchesKey(data, "down"))
|
|
@@ -194,11 +261,26 @@ export class ActorInspectorOverlay {
|
|
|
194
261
|
);
|
|
195
262
|
} else lines.push(this.border("├", "", "┤", innerWidth));
|
|
196
263
|
this.contentStripeIndices = [];
|
|
197
|
-
const
|
|
198
|
-
? this.
|
|
199
|
-
: this.
|
|
200
|
-
? this.
|
|
201
|
-
: this.
|
|
264
|
+
const baseContent = this.killConfirmation
|
|
265
|
+
? this.renderKillConfirmation()
|
|
266
|
+
: this.detailOpen
|
|
267
|
+
? this.renderDetail(innerWidth)
|
|
268
|
+
: this.selectedRun
|
|
269
|
+
? this.renderTimeline(innerWidth)
|
|
270
|
+
: this.renderRunSelector(innerWidth);
|
|
271
|
+
const content = this.feedback && !this.killConfirmation
|
|
272
|
+
? [
|
|
273
|
+
this.theme.fg(
|
|
274
|
+
this.feedback.ok
|
|
275
|
+
? "success"
|
|
276
|
+
: /^Kill (failed|rejected):/.test(this.feedback.message)
|
|
277
|
+
? "error"
|
|
278
|
+
: "warning",
|
|
279
|
+
` ${this.feedback.message}`,
|
|
280
|
+
),
|
|
281
|
+
...baseContent.slice(0, Math.max(0, this.contentViewportRows() - 1)),
|
|
282
|
+
]
|
|
283
|
+
: baseContent;
|
|
202
284
|
const contentViewportRows = this.contentViewportRows();
|
|
203
285
|
const selectorRows = selector.slice(1);
|
|
204
286
|
for (let index = 0; index < Math.max(content.length, contentViewportRows); index += 1) {
|
|
@@ -256,7 +338,9 @@ export class ActorInspectorOverlay {
|
|
|
256
338
|
|
|
257
339
|
private selectRun(run: string, index: number): void {
|
|
258
340
|
this.selectedRun = run;
|
|
341
|
+
this.turnCache = undefined;
|
|
259
342
|
this.runIndex = index;
|
|
343
|
+
this.recipeScroll = 0;
|
|
260
344
|
this.rowIndex = 0;
|
|
261
345
|
this.subagentIndex = 0;
|
|
262
346
|
this.communicationFrom = "all";
|
|
@@ -276,7 +360,74 @@ export class ActorInspectorOverlay {
|
|
|
276
360
|
if (next) this.selectRun(next.run, nextIndex);
|
|
277
361
|
}
|
|
278
362
|
|
|
363
|
+
private requestKill(runs: Inspector.ActorInspectorRunItem[]): void {
|
|
364
|
+
this.feedback = undefined;
|
|
365
|
+
if (this.focus !== "runs") {
|
|
366
|
+
this.feedback = { ok: false, message: "Focus Run before using Kill." };
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
const run = runs.find((item) => item.run === this.selectedRun);
|
|
370
|
+
if (!run) {
|
|
371
|
+
this.feedback = { ok: false, message: "Kill unavailable: no owned run." };
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (!this.killRun) {
|
|
375
|
+
this.feedback = { ok: false, message: "Kill unavailable in this Inspector." };
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (run.status !== "running") {
|
|
379
|
+
this.feedback = {
|
|
380
|
+
ok: false,
|
|
381
|
+
message: `Kill unavailable: run is ${run.status}.`,
|
|
382
|
+
};
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (!run.runInstanceId) {
|
|
386
|
+
this.feedback = {
|
|
387
|
+
ok: false,
|
|
388
|
+
message: "Kill unavailable: run generation unavailable.",
|
|
389
|
+
};
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
this.killConfirmation = {
|
|
393
|
+
run: run.run,
|
|
394
|
+
runInstanceId: run.runInstanceId,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private confirmKill(): void {
|
|
399
|
+
const confirmation = this.killConfirmation;
|
|
400
|
+
this.killConfirmation = undefined;
|
|
401
|
+
if (!confirmation || !this.killRun) {
|
|
402
|
+
this.feedback = { ok: false, message: "Kill unavailable in this Inspector." };
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
try {
|
|
406
|
+
this.feedback = this.killRun(
|
|
407
|
+
confirmation.run,
|
|
408
|
+
confirmation.runInstanceId,
|
|
409
|
+
);
|
|
410
|
+
} catch (error) {
|
|
411
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
412
|
+
this.feedback = {
|
|
413
|
+
ok: false,
|
|
414
|
+
message: `Kill failed: ${message.replaceAll(/\s+/g, " ").slice(0, 160)}.`,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
private renderKillConfirmation(): string[] {
|
|
420
|
+
return [
|
|
421
|
+
this.theme.fg(
|
|
422
|
+
"error",
|
|
423
|
+
` Kill running actor run:${this.killConfirmation?.run}?`,
|
|
424
|
+
),
|
|
425
|
+
this.theme.fg("muted", " This sends canonical control.kill and cannot be undone."),
|
|
426
|
+
];
|
|
427
|
+
}
|
|
428
|
+
|
|
279
429
|
private listItemCount(): number {
|
|
430
|
+
if (this.tab === "recipe") return 0;
|
|
280
431
|
return this.tab === "communications"
|
|
281
432
|
? this.communicationPreviews().length
|
|
282
433
|
: this.turnItems().length;
|
|
@@ -287,7 +438,11 @@ export class ActorInspectorOverlay {
|
|
|
287
438
|
const runControl = stripVTControlCharacters(this.renderRunControl());
|
|
288
439
|
return Math.max(0, runControl.indexOf("Run:") - 2);
|
|
289
440
|
}
|
|
290
|
-
const label = this.tab === "communications"
|
|
441
|
+
const label = this.tab === "communications"
|
|
442
|
+
? "Messages"
|
|
443
|
+
: this.tab === "turns"
|
|
444
|
+
? "Turns"
|
|
445
|
+
: "Recipe";
|
|
291
446
|
const tabs = stripVTControlCharacters(this.renderTabs());
|
|
292
447
|
return Math.max(0, tabs.indexOf(label) - 2);
|
|
293
448
|
}
|
|
@@ -295,18 +450,25 @@ export class ActorInspectorOverlay {
|
|
|
295
450
|
private renderKeyHints(): string {
|
|
296
451
|
const hint = (keys: string, description: string) =>
|
|
297
452
|
`${this.theme.fg("accent", keys)}${this.theme.fg("dim", ` ${description}`)}`;
|
|
453
|
+
if (this.killConfirmation)
|
|
454
|
+
return ` ${hint("y/enter", "confirm kill")} ${hint("n/esc", "cancel")}`;
|
|
298
455
|
if (this.focus === "select")
|
|
299
456
|
return this.menuLevel === "value"
|
|
300
457
|
? ` ${hint("↑↓", "option")} ${hint("enter", "apply")} ${hint("←/esc", "back")}`
|
|
301
458
|
: ` ${hint("↑↓", "option")} ${hint("→/enter", "open")} ${hint("←/esc", "back")}`;
|
|
459
|
+
if (this.focus === "recipe")
|
|
460
|
+
return ` ${hint("↑↓/pgup/pgdn", "scroll")} ${hint("↑ at top", "tabs")} ${hint("←/esc", "tabs")}`;
|
|
302
461
|
if (this.focus === "detail")
|
|
303
|
-
return
|
|
304
|
-
? ` ${hint("↑↓", "scroll")} ${hint("→/enter", "readable")} ${hint("←/esc", "back")}`
|
|
305
|
-
: ` ${hint("↑↓", "scroll")} ${hint("←/esc", this.detailView === "transcript" ? "evidence" : "back")}`;
|
|
462
|
+
return ` ${hint("↑↓/pgup/pgdn", "scroll")} ${hint("←/esc", "back")}`;
|
|
306
463
|
if (this.focus === "list")
|
|
307
|
-
return ` ${hint("
|
|
308
|
-
if (this.focus === "runs")
|
|
309
|
-
|
|
464
|
+
return ` ${hint("↑↓/pgup/pgdn", "row")} ${hint("→/enter", "open")} ${hint("←", "tabs")} ${hint("esc", "close")}`;
|
|
465
|
+
if (this.focus === "runs") {
|
|
466
|
+
const run = this.runs().find((item) => item.run === this.selectedRun);
|
|
467
|
+
const killHint = this.killRun && run?.status === "running" && run.runInstanceId
|
|
468
|
+
? ` ${hint("k", "kill")}`
|
|
469
|
+
: "";
|
|
470
|
+
return ` ${hint("←→", "run")} ${hint("↓", "tabs")} ${hint("enter", "list")}${killHint} ${hint("esc", "close")}`;
|
|
471
|
+
}
|
|
310
472
|
return ` ${hint("←→", "navigate")} ${hint("↑↓", "change row")} ${hint("enter", "select")} ${hint("esc", "close")}`;
|
|
311
473
|
}
|
|
312
474
|
|
|
@@ -359,7 +521,7 @@ export class ActorInspectorOverlay {
|
|
|
359
521
|
const subagent = this.subagents()[this.subagentIndex] ?? "all";
|
|
360
522
|
const messagesLabel = `Messages${messageFilters.length > 0 ? ` (${messageFilters.join(", ")})` : ""}`;
|
|
361
523
|
const turnsLabel = `Turns${subagent === "all" ? "" : ` (${subagent})`}`;
|
|
362
|
-
return `${tab("communications", messagesLabel)} ${tab("turns", turnsLabel)}`;
|
|
524
|
+
return `${tab("recipe", "Recipe")} ${tab("communications", messagesLabel)} ${tab("turns", turnsLabel)}`;
|
|
363
525
|
}
|
|
364
526
|
|
|
365
527
|
private renderRunSelector(width: number): string[] {
|
|
@@ -384,6 +546,7 @@ export class ActorInspectorOverlay {
|
|
|
384
546
|
this.selectedRun = undefined;
|
|
385
547
|
return [this.theme.fg("warning", " Selected run is no longer owned by this session")];
|
|
386
548
|
}
|
|
549
|
+
if (this.tab === "recipe") return this.renderRecipe(width);
|
|
387
550
|
const rows =
|
|
388
551
|
this.tab === "communications"
|
|
389
552
|
? this.communicationRows()
|
|
@@ -431,6 +594,51 @@ export class ActorInspectorOverlay {
|
|
|
431
594
|
});
|
|
432
595
|
}
|
|
433
596
|
|
|
597
|
+
private renderRecipe(width: number): string[] {
|
|
598
|
+
if (!this.selectedRun) return [];
|
|
599
|
+
const recipe = Inspector.readActorInspectorRecipe(
|
|
600
|
+
path.join(this.stateRoot, this.selectedRun),
|
|
601
|
+
);
|
|
602
|
+
const logicalLines: DetailLogicalLine[] = [
|
|
603
|
+
...this.detailSection(
|
|
604
|
+
"Identity",
|
|
605
|
+
this.readableValueLines(recipe.identity, " "),
|
|
606
|
+
),
|
|
607
|
+
...(recipe.definition
|
|
608
|
+
? this.detailSection(
|
|
609
|
+
"Recipe",
|
|
610
|
+
this.readableValueLines(recipe.definition, " "),
|
|
611
|
+
)
|
|
612
|
+
: []),
|
|
613
|
+
...this.detailSection(
|
|
614
|
+
"Launch",
|
|
615
|
+
this.readableValueLines(recipe.launch, " "),
|
|
616
|
+
),
|
|
617
|
+
...(recipe.composition.length > 0
|
|
618
|
+
? this.detailSection(
|
|
619
|
+
"Composition",
|
|
620
|
+
this.readableValueLines(recipe.composition, " "),
|
|
621
|
+
)
|
|
622
|
+
: []),
|
|
623
|
+
...this.detailSection("Diagnostics", recipe.diagnostics),
|
|
624
|
+
];
|
|
625
|
+
const wrapped = this.wrapDetailLines(
|
|
626
|
+
logicalLines.length > 0 ? logicalLines : [" No persisted recipe evidence"],
|
|
627
|
+
width,
|
|
628
|
+
);
|
|
629
|
+
const viewportRows = this.contentViewportRows();
|
|
630
|
+
const maxStart = Math.max(0, wrapped.lines.length - viewportRows);
|
|
631
|
+
this.recipeScroll = Math.min(this.recipeScroll, maxStart);
|
|
632
|
+
this.contentStripeIndices = wrapped.stripeIndices.slice(
|
|
633
|
+
this.recipeScroll,
|
|
634
|
+
this.recipeScroll + viewportRows,
|
|
635
|
+
);
|
|
636
|
+
return wrapped.lines.slice(
|
|
637
|
+
this.recipeScroll,
|
|
638
|
+
this.recipeScroll + viewportRows,
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
|
|
434
642
|
private communicationPreviews(): Inspector.ActorInspectorPreview[] {
|
|
435
643
|
if (!this.selectedRun) return [];
|
|
436
644
|
const channels =
|
|
@@ -496,7 +704,7 @@ export class ActorInspectorOverlay {
|
|
|
496
704
|
["inbox", preview.inbox_status],
|
|
497
705
|
["timestamp", preview.timestamp],
|
|
498
706
|
];
|
|
499
|
-
|
|
707
|
+
const lines = fields
|
|
500
708
|
.filter(([, value]) => value !== undefined)
|
|
501
709
|
.map(([label, value]) =>
|
|
502
710
|
truncateToWidth(
|
|
@@ -505,12 +713,14 @@ export class ActorInspectorOverlay {
|
|
|
505
713
|
"…",
|
|
506
714
|
),
|
|
507
715
|
);
|
|
716
|
+
const viewportRows = this.contentViewportRows();
|
|
717
|
+
const maxStart = Math.max(0, lines.length - viewportRows);
|
|
718
|
+
this.detailScroll = Math.min(this.detailScroll, maxStart);
|
|
719
|
+
return lines.slice(this.detailScroll, this.detailScroll + viewportRows);
|
|
508
720
|
}
|
|
509
721
|
const turn = this.detailTurn;
|
|
510
722
|
if (!turn) return [this.theme.fg("warning", " Turn row is no longer available")];
|
|
511
|
-
const logicalLines = this.
|
|
512
|
-
? this.turnTranscriptLines(turn)
|
|
513
|
-
: this.turnEvidenceLines(turn);
|
|
723
|
+
const logicalLines = this.turnEvidenceLines(turn);
|
|
514
724
|
const wrapped = this.wrapDetailLines(logicalLines, width);
|
|
515
725
|
const viewportRows = this.contentViewportRows();
|
|
516
726
|
const maxStart = Math.max(0, wrapped.lines.length - viewportRows);
|
|
@@ -543,11 +753,39 @@ export class ActorInspectorOverlay {
|
|
|
543
753
|
const leading = physicalLine.match(/^ */)?.[0] ?? "";
|
|
544
754
|
const content = physicalLine.slice(leading.length);
|
|
545
755
|
const contentWidth = Math.max(1, width - visibleWidth(leading));
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
756
|
+
const labeled = /^(\s*(?:-\s+)?[^:]+:\s+)(\S.*)$/u.exec(physicalLine);
|
|
757
|
+
let wrapped: string[];
|
|
758
|
+
if (
|
|
759
|
+
visibleWidth(physicalLine) > width &&
|
|
760
|
+
labeled &&
|
|
761
|
+
visibleWidth(labeled[1]) < width
|
|
762
|
+
) {
|
|
763
|
+
const prefix = labeled[1];
|
|
764
|
+
const value = labeled[2];
|
|
765
|
+
const firstWidth = Math.max(1, width - visibleWidth(prefix));
|
|
766
|
+
const first = this.wrapPreferred(value, firstWidth)[0] ??
|
|
767
|
+
this.takeVisiblePrefix(value, firstWidth);
|
|
768
|
+
const remainder = value.slice(first.length).trimStart();
|
|
769
|
+
const continuation = `${leading} `;
|
|
770
|
+
const continuationWidth = Math.max(
|
|
771
|
+
1,
|
|
772
|
+
width - visibleWidth(continuation),
|
|
773
|
+
);
|
|
774
|
+
wrapped = [
|
|
775
|
+
`${prefix}${first}`,
|
|
776
|
+
...(remainder
|
|
777
|
+
? this.wrapPreferred(remainder, continuationWidth).map(
|
|
778
|
+
(visualLine) => `${continuation}${visualLine}`,
|
|
779
|
+
)
|
|
780
|
+
: []),
|
|
781
|
+
];
|
|
782
|
+
} else {
|
|
783
|
+
wrapped = visibleWidth(physicalLine) <= width
|
|
784
|
+
? [physicalLine]
|
|
785
|
+
: this.wrapPreferred(content, contentWidth).map(
|
|
786
|
+
(visualLine) => `${leading}${visualLine}`,
|
|
787
|
+
);
|
|
788
|
+
}
|
|
551
789
|
for (const visualLine of wrapped) {
|
|
552
790
|
if (!visualLine.trim()) continue;
|
|
553
791
|
wrappedLines.push(visualLine);
|
|
@@ -558,6 +796,37 @@ export class ActorInspectorOverlay {
|
|
|
558
796
|
return { lines: wrappedLines, stripeIndices };
|
|
559
797
|
}
|
|
560
798
|
|
|
799
|
+
private wrapPreferred(content: string, width: number): string[] {
|
|
800
|
+
const lines: string[] = [];
|
|
801
|
+
let remaining = stripVTControlCharacters(content).trimEnd();
|
|
802
|
+
while (remaining && visibleWidth(remaining) > width) {
|
|
803
|
+
const candidate = this.takeVisiblePrefix(remaining, width);
|
|
804
|
+
let splitAt = -1;
|
|
805
|
+
let trimBoundary = false;
|
|
806
|
+
for (let index = 1; index < candidate.length; index += 1) {
|
|
807
|
+
if (/\s/u.test(candidate[index]!)) {
|
|
808
|
+
splitAt = index + 1;
|
|
809
|
+
trimBoundary = true;
|
|
810
|
+
} else if (/[-+=/_,.:]/u.test(candidate[index]!)) {
|
|
811
|
+
splitAt = index;
|
|
812
|
+
trimBoundary = false;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
if (splitAt <= 0) splitAt = candidate.length;
|
|
816
|
+
const head = remaining.slice(0, splitAt).trimEnd();
|
|
817
|
+
if (!head) {
|
|
818
|
+
lines.push(candidate);
|
|
819
|
+
remaining = remaining.slice(candidate.length);
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
lines.push(head);
|
|
823
|
+
remaining = remaining.slice(splitAt);
|
|
824
|
+
if (trimBoundary) remaining = remaining.trimStart();
|
|
825
|
+
}
|
|
826
|
+
if (remaining) lines.push(remaining);
|
|
827
|
+
return lines;
|
|
828
|
+
}
|
|
829
|
+
|
|
561
830
|
private detailSection(
|
|
562
831
|
title: string,
|
|
563
832
|
content: string[],
|
|
@@ -612,9 +881,14 @@ export class ActorInspectorOverlay {
|
|
|
612
881
|
}
|
|
613
882
|
if (!item || typeof item !== "object")
|
|
614
883
|
return [`${indent}- ${String(item)}`];
|
|
884
|
+
const [first = "", ...rest] = this.readableValueLines(
|
|
885
|
+
item,
|
|
886
|
+
`${indent} `,
|
|
887
|
+
depth + 1,
|
|
888
|
+
);
|
|
615
889
|
return [
|
|
616
|
-
`${indent}
|
|
617
|
-
...
|
|
890
|
+
`${indent}- ${first.trimStart()}`,
|
|
891
|
+
...rest,
|
|
618
892
|
];
|
|
619
893
|
});
|
|
620
894
|
}
|
|
@@ -650,7 +924,9 @@ export class ActorInspectorOverlay {
|
|
|
650
924
|
: "";
|
|
651
925
|
lines.push(` Subagent ${subagent}${stage}`, DETAIL_SECTION_BREAK);
|
|
652
926
|
if (turn.userText)
|
|
653
|
-
lines.push(
|
|
927
|
+
lines.push(
|
|
928
|
+
...this.detailSection("User", [this.readablePromptText(turn.userText)]),
|
|
929
|
+
);
|
|
654
930
|
if (turn.thinking)
|
|
655
931
|
lines.push(...this.detailSection("Thinking", [turn.thinking]));
|
|
656
932
|
if (turn.assistantText)
|
|
@@ -698,12 +974,6 @@ export class ActorInspectorOverlay {
|
|
|
698
974
|
` ${turn.promptFile}${turn.promptBytes ? ` (${turn.promptBytes} bytes)` : ""}`,
|
|
699
975
|
]
|
|
700
976
|
: []),
|
|
701
|
-
...(turn.recipeContext === undefined
|
|
702
|
-
? []
|
|
703
|
-
: [
|
|
704
|
-
"Recipe Context",
|
|
705
|
-
...this.readableValueLines(turn.recipeContext, " "),
|
|
706
|
-
]),
|
|
707
977
|
];
|
|
708
978
|
lines.push(...this.detailSection("Provenance", provenance));
|
|
709
979
|
return lines.length > 0 ? lines : [" No persisted turn evidence"];
|
|
@@ -714,44 +984,17 @@ export class ActorInspectorOverlay {
|
|
|
714
984
|
return wrapped?.[1]?.trim() || text;
|
|
715
985
|
}
|
|
716
986
|
|
|
717
|
-
private
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
const
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
...this.detailSection("User", [this.readablePromptText(turn.userText)]),
|
|
724
|
-
);
|
|
725
|
-
if (turn.thinking)
|
|
726
|
-
lines.push(...this.detailSection("Thinking", [turn.thinking]));
|
|
727
|
-
if (turn.assistantText)
|
|
728
|
-
lines.push(...this.detailSection("Assistant", [turn.assistantText]));
|
|
729
|
-
for (const tool of turn.toolCalls) {
|
|
730
|
-
const content = [
|
|
731
|
-
...(tool.arguments === undefined
|
|
732
|
-
? []
|
|
733
|
-
: ["Input", ...this.readableValueLines(tool.arguments, " ")]),
|
|
734
|
-
...(tool.result === undefined
|
|
735
|
-
? []
|
|
736
|
-
: ["Result", ...this.readableValueLines(tool.result, " ")]),
|
|
737
|
-
];
|
|
738
|
-
lines.push(
|
|
739
|
-
...this.detailSection(
|
|
740
|
-
`Tool (${tool.name}${tool.resultError ? ", Error" : ""})`,
|
|
741
|
-
content,
|
|
742
|
-
),
|
|
743
|
-
);
|
|
744
|
-
}
|
|
745
|
-
if (turn.error) lines.push(...this.detailSection("Error", [turn.error]));
|
|
746
|
-
return lines.length > 0 ? lines : [" No readable turn content"];
|
|
987
|
+
private allTurnItems(): Inspector.ActorInspectorTurnItem[] {
|
|
988
|
+
if (!this.selectedRun) return [];
|
|
989
|
+
if (this.turnCache?.run === this.selectedRun) return this.turnCache.turns;
|
|
990
|
+
const turns = this.readTurns(path.join(this.stateRoot, this.selectedRun));
|
|
991
|
+
this.turnCache = { run: this.selectedRun, turns };
|
|
992
|
+
return turns;
|
|
747
993
|
}
|
|
748
994
|
|
|
749
995
|
private turnItems(): Inspector.ActorInspectorTurnItem[] {
|
|
750
|
-
if (!this.selectedRun) return [];
|
|
751
996
|
const selectedSubagent = this.subagents()[this.subagentIndex];
|
|
752
|
-
return
|
|
753
|
-
path.join(this.stateRoot, this.selectedRun),
|
|
754
|
-
)
|
|
997
|
+
return this.allTurnItems()
|
|
755
998
|
.filter(
|
|
756
999
|
(turn) =>
|
|
757
1000
|
!selectedSubagent ||
|
|
@@ -793,9 +1036,7 @@ export class ActorInspectorOverlay {
|
|
|
793
1036
|
|
|
794
1037
|
private subagents(): string[] {
|
|
795
1038
|
if (!this.selectedRun || this.tab !== "turns") return ["all"];
|
|
796
|
-
const ids =
|
|
797
|
-
path.join(this.stateRoot, this.selectedRun),
|
|
798
|
-
).map((turn) => turn.commandId);
|
|
1039
|
+
const ids = this.allTurnItems().map((turn) => turn.commandId);
|
|
799
1040
|
return ["all", ...new Set(ids)];
|
|
800
1041
|
}
|
|
801
1042
|
|
|
@@ -982,17 +1223,11 @@ export class ActorInspectorOverlay {
|
|
|
982
1223
|
if (preview) this.readKeys.add(Inspector.inspectorPreviewReadKey(preview));
|
|
983
1224
|
} else this.detailTurn = this.turnItems()[this.rowIndex];
|
|
984
1225
|
this.detailScroll = 0;
|
|
985
|
-
this.detailView = "evidence";
|
|
986
1226
|
this.detailOpen = Boolean(this.detailCommunication || this.detailTurn);
|
|
987
1227
|
if (this.detailOpen) this.focus = "detail";
|
|
988
1228
|
}
|
|
989
1229
|
|
|
990
1230
|
private backDetail(): void {
|
|
991
|
-
if (this.detailView === "transcript") {
|
|
992
|
-
this.detailView = "evidence";
|
|
993
|
-
this.detailScroll = 0;
|
|
994
|
-
return;
|
|
995
|
-
}
|
|
996
1231
|
this.closeDetail();
|
|
997
1232
|
}
|
|
998
1233
|
|
|
@@ -1001,7 +1236,6 @@ export class ActorInspectorOverlay {
|
|
|
1001
1236
|
this.detailCommunication = undefined;
|
|
1002
1237
|
this.detailTurn = undefined;
|
|
1003
1238
|
this.detailScroll = 0;
|
|
1004
|
-
this.detailView = "evidence";
|
|
1005
1239
|
this.focus = "list";
|
|
1006
1240
|
}
|
|
1007
1241
|
|