@llblab/pi-actors 0.42.3 → 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 +127 -175
- package/BACKLOG.md +189 -1
- package/CHANGELOG.md +183 -292
- package/README.md +115 -276
- package/dist/fixtures/protocol/control-endpoint.json +6 -0
- package/dist/fixtures/protocol/control-record.json +9 -0
- package/dist/fixtures/protocol/recipe-summary.json +4 -12
- package/dist/fixtures/protocol/trace-event.json +9 -0
- package/dist/index.js +1 -1
- package/dist/lib/async-runs.d.ts +15 -38
- package/dist/lib/async-runs.js +173 -111
- 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 +15 -0
- package/dist/lib/control.js +97 -0
- package/dist/lib/draft-sleep.js +3 -3
- package/dist/lib/execution-sessions.d.ts +17 -0
- package/dist/lib/execution-sessions.js +85 -0
- package/dist/lib/file-state.d.ts +2 -0
- package/dist/lib/file-state.js +114 -46
- package/dist/lib/inspector-actions.d.ts +2 -2
- package/dist/lib/inspector-actions.js +2 -2
- package/dist/lib/inspector-command.js +3 -3
- package/dist/lib/inspector-overlay.d.ts +54 -70
- package/dist/lib/inspector-overlay.js +576 -910
- package/dist/lib/inspector.d.ts +3 -71
- package/dist/lib/inspector.js +19 -665
- package/dist/lib/limits.d.ts +7 -3
- package/dist/lib/limits.js +7 -3
- package/dist/lib/observability.d.ts +16 -16
- package/dist/lib/observability.js +43 -82
- package/dist/lib/prompts.d.ts +1 -1
- package/dist/lib/prompts.js +3 -3
- package/dist/lib/recipe-control.d.ts +7 -0
- package/dist/lib/recipe-control.js +43 -0
- package/dist/lib/recipes-discovery.js +2 -0
- package/dist/lib/recipes-references.d.ts +1 -14
- package/dist/lib/recipes-references.js +6 -21
- package/dist/lib/review-control.d.ts +1 -1
- package/dist/lib/review-control.js +4 -5
- package/dist/lib/review-projection.js +1 -5
- package/dist/lib/run-ui-runtime.js +2 -2
- package/dist/lib/runs-control-delivery.d.ts +28 -0
- package/dist/lib/runs-control-delivery.js +150 -0
- package/dist/lib/runs-controls.d.ts +37 -0
- package/dist/lib/runs-controls.js +146 -0
- package/dist/lib/runs-retention.d.ts +7 -0
- package/dist/lib/runs-retention.js +27 -3
- package/dist/lib/runs-start.js +4 -2
- package/dist/lib/runs-status.js +11 -6
- package/dist/lib/runs-trace.d.ts +24 -0
- package/dist/lib/runs-trace.js +102 -0
- package/dist/lib/runtime-identity.d.ts +7 -0
- package/dist/lib/runtime-identity.js +35 -0
- package/dist/lib/runtime-notifier.d.ts +1 -1
- package/dist/lib/runtime-notifier.js +1 -1
- 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.d.ts +3 -3
- package/dist/lib/tools-inspect.js +241 -707
- package/dist/lib/tools-local.js +2 -10
- package/dist/lib/tools-message.d.ts +6 -7
- package/dist/lib/tools-message.js +95 -396
- package/dist/lib/tools-response.d.ts +1 -5
- package/dist/lib/tools-response.js +5 -48
- package/dist/lib/tools-spawn.js +16 -28
- package/dist/lib/tools.d.ts +1 -1
- package/dist/lib/tools.js +2 -3
- package/dist/lib/trace-projection.d.ts +22 -0
- package/dist/lib/trace-projection.js +185 -0
- package/dist/recipes/draft-review.json +0 -10
- package/dist/recipes/lens-swarm.json +0 -14
- package/dist/recipes/music-player.json +10 -19
- package/dist/recipes/pipeline-architect-coordinator.json +0 -11
- package/dist/recipes/pipeline-artifact-bundle.json +1 -22
- package/dist/recipes/pipeline-artifact-report.json +1 -18
- package/dist/recipes/pipeline-artifact-write.json +1 -18
- package/dist/recipes/pipeline-async-run-ops.json +0 -12
- package/dist/recipes/pipeline-checkpoint-continuation.json +0 -14
- package/dist/recipes/pipeline-development-tasking.json +0 -12
- package/dist/recipes/pipeline-docs-maintenance.json +0 -12
- package/dist/recipes/pipeline-media-library.json +0 -12
- package/dist/recipes/pipeline-quorum-review.json +0 -12
- package/dist/recipes/pipeline-release-readiness.json +0 -12
- package/dist/recipes/pipeline-release-summary.json +0 -12
- package/dist/recipes/pipeline-repo-health.json +0 -12
- package/dist/recipes/pipeline-research-synthesis.json +0 -11
- package/dist/recipes/pipeline-review-readiness.json +0 -12
- package/dist/recipes/resource-locker.json +27 -0
- package/dist/recipes/subagent-artifact.json +0 -9
- package/dist/recipes/subagent-checkpoint.json +0 -10
- package/dist/recipes/subagent-conflict-report.json +0 -11
- package/dist/recipes/subagent-contradiction-map.json +0 -11
- package/dist/recipes/subagent-critic.json +0 -11
- package/dist/recipes/subagent-evidence-map.json +0 -11
- package/dist/recipes/subagent-followup.json +0 -10
- package/dist/recipes/subagent-judge.json +0 -11
- package/dist/recipes/subagent-merge.json +0 -11
- package/dist/recipes/subagent-normalize.json +0 -11
- package/dist/recipes/subagent-plan.json +0 -11
- package/dist/recipes/subagent-preflight.json +0 -11
- package/dist/recipes/subagent-prompt.json +0 -10
- package/dist/recipes/subagent-quorum.json +0 -10
- package/dist/recipes/subagent-review-coordinator.json +0 -14
- package/dist/recipes/subagent-review.json +0 -11
- package/dist/recipes/subagent-task-card.json +0 -11
- package/dist/recipes/subagent-tools.json +0 -10
- package/dist/recipes/subagent-verify.json +0 -11
- package/dist/recipes/subagents-prompts.json +0 -10
- package/dist/recipes/tool-review.json +0 -10
- package/dist/scripts/async-runner.mjs +25 -25
- package/dist/scripts/conformance.mjs +4 -2
- package/dist/scripts/locker.mjs +196 -69
- package/dist/scripts/music-player.mjs +162 -159
- package/dist/scripts/recipe-utils.mjs +6 -96
- package/dist/scripts/release-gates.mjs +91 -0
- package/dist/scripts/validate-recipe.mjs +8 -57
- package/dist/skills/actors/SKILL.md +57 -265
- package/dist/skills/swarm/SKILL.md +10 -34
- package/docs/0.43-baseline.md +39 -0
- package/docs/README.md +4 -6
- package/docs/actor-inspector.md +26 -64
- package/docs/async-runs.md +81 -328
- package/docs/command-templates.md +8 -118
- package/docs/recipe-library.md +55 -182
- package/docs/releasing.md +28 -0
- package/docs/template-recipes.md +76 -289
- package/docs/tool-registry.md +41 -161
- package/fixtures/protocol/control-endpoint.json +6 -0
- package/fixtures/protocol/control-record.json +9 -0
- package/fixtures/protocol/recipe-summary.json +4 -12
- package/fixtures/protocol/trace-event.json +9 -0
- package/index.ts +1 -1
- package/lib/async-runs.ts +218 -204
- 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 +117 -0
- package/lib/draft-sleep.ts +3 -3
- package/lib/execution-sessions.ts +111 -0
- package/lib/file-state.ts +84 -64
- package/lib/inspector-actions.ts +2 -2
- package/lib/inspector-command.ts +3 -3
- package/lib/inspector-overlay.ts +617 -1126
- package/lib/inspector.ts +46 -979
- package/lib/limits.ts +7 -3
- package/lib/observability.ts +60 -101
- package/lib/prompts.ts +3 -3
- package/lib/recipe-control.ts +52 -0
- package/lib/recipes-discovery.ts +2 -0
- package/lib/recipes-references.ts +9 -45
- package/lib/review-control.ts +4 -5
- package/lib/review-projection.ts +1 -5
- package/lib/run-ui-runtime.ts +2 -2
- package/lib/runs-control-delivery.ts +209 -0
- package/lib/runs-controls.ts +213 -0
- package/lib/runs-retention.ts +38 -3
- package/lib/runs-start.ts +4 -2
- package/lib/runs-status.ts +11 -6
- package/lib/runs-trace.ts +136 -0
- package/lib/runtime-identity.ts +39 -0
- package/lib/runtime-notifier.ts +1 -1
- package/lib/runtime-triage.ts +120 -0
- package/lib/tool-review-scheduler.ts +7 -7
- package/lib/tools-inspect.ts +283 -900
- package/lib/tools-local.ts +2 -12
- package/lib/tools-message.ts +112 -520
- package/lib/tools-response.ts +5 -64
- package/lib/tools-spawn.ts +16 -32
- package/lib/tools.ts +5 -6
- package/lib/trace-projection.ts +244 -0
- package/package.json +2 -1
- package/recipes/draft-review.json +0 -10
- package/recipes/lens-swarm.json +0 -14
- package/recipes/music-player.json +10 -19
- package/recipes/pipeline-architect-coordinator.json +0 -11
- package/recipes/pipeline-artifact-bundle.json +1 -22
- package/recipes/pipeline-artifact-report.json +1 -18
- package/recipes/pipeline-artifact-write.json +1 -18
- package/recipes/pipeline-async-run-ops.json +0 -12
- package/recipes/pipeline-checkpoint-continuation.json +0 -14
- package/recipes/pipeline-development-tasking.json +0 -12
- package/recipes/pipeline-docs-maintenance.json +0 -12
- package/recipes/pipeline-media-library.json +0 -12
- package/recipes/pipeline-quorum-review.json +0 -12
- package/recipes/pipeline-release-readiness.json +0 -12
- package/recipes/pipeline-release-summary.json +0 -12
- package/recipes/pipeline-repo-health.json +0 -12
- package/recipes/pipeline-research-synthesis.json +0 -11
- package/recipes/pipeline-review-readiness.json +0 -12
- package/recipes/resource-locker.json +27 -0
- package/recipes/subagent-artifact.json +0 -9
- package/recipes/subagent-checkpoint.json +0 -10
- package/recipes/subagent-conflict-report.json +0 -11
- package/recipes/subagent-contradiction-map.json +0 -11
- package/recipes/subagent-critic.json +0 -11
- package/recipes/subagent-evidence-map.json +0 -11
- package/recipes/subagent-followup.json +0 -10
- package/recipes/subagent-judge.json +0 -11
- package/recipes/subagent-merge.json +0 -11
- package/recipes/subagent-normalize.json +0 -11
- package/recipes/subagent-plan.json +0 -11
- package/recipes/subagent-preflight.json +0 -11
- package/recipes/subagent-prompt.json +0 -10
- package/recipes/subagent-quorum.json +0 -10
- package/recipes/subagent-review-coordinator.json +0 -14
- package/recipes/subagent-review.json +0 -11
- package/recipes/subagent-task-card.json +0 -11
- package/recipes/subagent-tools.json +0 -10
- package/recipes/subagent-verify.json +0 -11
- package/recipes/subagents-prompts.json +0 -10
- package/recipes/tool-review.json +0 -10
- package/scripts/async-runner.mjs +25 -25
- package/scripts/conformance.mjs +4 -2
- package/scripts/locker.mjs +196 -69
- package/scripts/music-player.mjs +162 -159
- package/scripts/recipe-utils.mjs +6 -96
- package/scripts/release-gates.mjs +91 -0
- package/scripts/validate-recipe.mjs +8 -57
- package/skills/actors/SKILL.md +57 -265
- package/skills/swarm/SKILL.md +10 -34
- package/dist/fixtures/protocol/actor-message-branch.json +0 -13
- package/dist/fixtures/protocol/mailbox-contract.json +0 -15
- package/dist/fixtures/protocol/room-message.json +0 -11
- package/dist/fixtures/protocol/room-roster.json +0 -11
- package/dist/fixtures/protocol/run-inbox-message.json +0 -9
- package/dist/fixtures/protocol/run-outbox-event.json +0 -9
- package/dist/lib/mailbox-loop.d.ts +0 -41
- package/dist/lib/mailbox-loop.js +0 -60
- package/dist/lib/messages.d.ts +0 -25
- package/dist/lib/messages.js +0 -122
- package/dist/lib/rooms.d.ts +0 -104
- package/dist/lib/rooms.js +0 -647
- package/dist/lib/runs-mailbox.d.ts +0 -25
- package/dist/lib/runs-mailbox.js +0 -146
- package/dist/lib/runs-messages.d.ts +0 -15
- package/dist/lib/runs-messages.js +0 -179
- package/dist/lib/runs-outbox.d.ts +0 -41
- package/dist/lib/runs-outbox.js +0 -87
- package/dist/lib/tools-mailbox.d.ts +0 -8
- package/dist/lib/tools-mailbox.js +0 -48
- package/dist/recipes/actor-worker.json +0 -39
- package/dist/recipes/coordinator-locker.json +0 -45
- package/dist/recipes/locker.json +0 -45
- package/dist/recipes/pipeline-room-swarm.json +0 -50
- package/dist/recipes/subagent-message.json +0 -32
- package/dist/recipes/utility-actor-message.json +0 -23
- package/dist/scripts/actor-worker.mjs +0 -214
- package/dist/scripts/coordinator.mjs +0 -799
- package/docs/actor-messages.md +0 -225
- package/docs/actors-deep-reference.md +0 -66
- package/docs/component-recipes.md +0 -148
- package/docs/task-first-recipes.md +0 -263
- package/fixtures/protocol/actor-message-branch.json +0 -13
- package/fixtures/protocol/mailbox-contract.json +0 -15
- package/fixtures/protocol/room-message.json +0 -11
- package/fixtures/protocol/room-roster.json +0 -11
- package/fixtures/protocol/run-inbox-message.json +0 -9
- package/fixtures/protocol/run-outbox-event.json +0 -9
- package/lib/mailbox-loop.ts +0 -144
- package/lib/messages.ts +0 -151
- package/lib/rooms.ts +0 -939
- package/lib/runs-mailbox.ts +0 -208
- package/lib/runs-messages.ts +0 -252
- package/lib/runs-outbox.ts +0 -144
- package/lib/tools-mailbox.ts +0 -56
- package/recipes/actor-worker.json +0 -39
- package/recipes/coordinator-locker.json +0 -45
- package/recipes/locker.json +0 -45
- package/recipes/pipeline-room-swarm.json +0 -50
- package/recipes/subagent-message.json +0 -32
- package/recipes/utility-actor-message.json +0 -23
- package/scripts/actor-worker.mjs +0 -214
- package/scripts/coordinator.mjs +0 -799
|
@@ -1,763 +1,297 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Public inspect tool behavior
|
|
3
|
-
* Zones:
|
|
4
|
-
* Owns
|
|
2
|
+
* Public inspect tool behavior.
|
|
3
|
+
* Zones: Run Recipe/Trace/Control views and runtime/recipe/tool diagnostics
|
|
4
|
+
* Owns exact inspect target/view dispatch; source projection stays in domain modules.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
-
import { dirname, join } from "node:path";
|
|
9
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { join } from "node:path";
|
|
10
7
|
import * as AsyncRuns from "./async-runs.js";
|
|
8
|
+
import * as ControlProjection from "./control-projection.js";
|
|
9
|
+
import * as Inspector from "./inspector.js";
|
|
11
10
|
import * as Limits from "./limits.js";
|
|
12
|
-
import * as Messages from "./messages.js";
|
|
13
11
|
import * as Paths from "./paths.js";
|
|
14
12
|
import * as RecipesDiscovery from "./recipes-discovery.js";
|
|
15
13
|
import * as ReviewDiagnostics from "./review-diagnostics.js";
|
|
16
|
-
import * as
|
|
14
|
+
import * as RunsControls from "./runs-controls.js";
|
|
15
|
+
import * as RunControlDelivery from "./runs-control-delivery.js";
|
|
16
|
+
import * as RunsTrace from "./runs-trace.js";
|
|
17
|
+
import * as RuntimeIdentity from "./runtime-identity.js";
|
|
18
|
+
import * as RuntimeTriage from "./runtime-triage.js";
|
|
17
19
|
import * as Schema from "./schema.js";
|
|
18
20
|
import * as ToolsAccess from "./tools-access.js";
|
|
19
|
-
import * as ToolsMailbox from "./tools-mailbox.js";
|
|
20
21
|
import * as ToolsResponse from "./tools-response.js";
|
|
22
|
+
import * as TraceProjection from "./trace-projection.js";
|
|
21
23
|
const asRecord = ToolsResponse.asRecord;
|
|
22
24
|
const maybeJsonText = ToolsResponse.maybeJsonText;
|
|
23
|
-
function
|
|
24
|
-
const draft = asRecord(diagnostics.draft_review);
|
|
25
|
-
const tool = asRecord(diagnostics.tool_review);
|
|
26
|
-
return [
|
|
27
|
-
`automatic_reviews draft=${String(draft.phase ?? "idle")} tool=${String(tool.phase ?? "idle")}`,
|
|
28
|
-
`lineages=${String(diagnostics.lineage_count ?? 0)} revision_snapshots=${String(diagnostics.revision_snapshots ?? 0)}`,
|
|
29
|
-
].join("\n");
|
|
30
|
-
}
|
|
31
|
-
function compactRunMessages(messages) {
|
|
32
|
-
if (messages.length === 0)
|
|
33
|
-
return "\n(no actor messages)";
|
|
34
|
-
return `\n${messages
|
|
35
|
-
.map((message) => [
|
|
36
|
-
`run=${message.run}`,
|
|
37
|
-
`type=${message.event}`,
|
|
38
|
-
`level=${message.level}`,
|
|
39
|
-
`summary=${message.summary.replaceAll(/\s+/g, "_")}`,
|
|
40
|
-
].join(" "))
|
|
41
|
-
.join("\n")}`;
|
|
42
|
-
}
|
|
43
|
-
function compactRoomPreviews(previews) {
|
|
44
|
-
if (previews.length === 0)
|
|
45
|
-
return "\n(no room message previews)";
|
|
46
|
-
return `\n${previews
|
|
47
|
-
.map((preview) => [
|
|
48
|
-
`ts=${preview.timestamp}`,
|
|
49
|
-
preview.from ? `from=${preview.from}` : "",
|
|
50
|
-
`to=${preview.to}`,
|
|
51
|
-
`type=${preview.type}`,
|
|
52
|
-
preview.summary
|
|
53
|
-
? `summary=${ToolsResponse.compactPreview(preview.summary)}`
|
|
54
|
-
: "",
|
|
55
|
-
preview.body_preview
|
|
56
|
-
? `body=${ToolsResponse.compactPreview(preview.body_preview)}`
|
|
57
|
-
: "",
|
|
58
|
-
]
|
|
59
|
-
.filter(Boolean)
|
|
60
|
-
.join(" "))
|
|
61
|
-
.join("\n")}`;
|
|
62
|
-
}
|
|
63
|
-
function compactRoomMessages(messages) {
|
|
64
|
-
if (messages.length === 0)
|
|
65
|
-
return "\n(no room messages)";
|
|
66
|
-
return `\n${messages
|
|
67
|
-
.map((message) => [
|
|
68
|
-
`ts=${message.received_at}`,
|
|
69
|
-
`from=${String(message.from ?? "<unknown>")}`,
|
|
70
|
-
`to=${message.to}`,
|
|
71
|
-
`type=${message.type}`,
|
|
72
|
-
`summary=${String(message.summary ?? "").replaceAll(/\s+/g, "_")}`,
|
|
73
|
-
ToolsResponse.compactPreview(message.body)
|
|
74
|
-
? `body=${ToolsResponse.compactPreview(message.body)}`
|
|
75
|
-
: "",
|
|
76
|
-
]
|
|
77
|
-
.filter(Boolean)
|
|
78
|
-
.join(" "))
|
|
79
|
-
.join("\n")}`;
|
|
80
|
-
}
|
|
81
|
-
function compactRoomContacts(contacts) {
|
|
82
|
-
if (contacts.length === 0)
|
|
83
|
-
return "\n(no room contacts)";
|
|
84
|
-
return `\n${contacts
|
|
85
|
-
.map((contact) => [
|
|
86
|
-
`address=${contact.address}`,
|
|
87
|
-
contact.role !== undefined ? `role=${String(contact.role)}` : "",
|
|
88
|
-
contact.parent !== undefined ? `parent=${String(contact.parent)}` : "",
|
|
89
|
-
contact.caps !== undefined
|
|
90
|
-
? `caps=${Array.isArray(contact.caps) ? contact.caps.join(",") : String(contact.caps)}`
|
|
91
|
-
: "",
|
|
92
|
-
contact.claim !== undefined
|
|
93
|
-
? `claim=${String(contact.claim).replaceAll(/\s+/g, "_")}`
|
|
94
|
-
: "",
|
|
95
|
-
contact.status !== undefined ? `status=${String(contact.status)}` : "",
|
|
96
|
-
]
|
|
97
|
-
.filter(Boolean)
|
|
98
|
-
.join(" "))
|
|
99
|
-
.join("\n")}`;
|
|
100
|
-
}
|
|
101
|
-
function compactRoomRoster(roster) {
|
|
102
|
-
const members = Object.values(roster);
|
|
103
|
-
if (members.length === 0)
|
|
104
|
-
return "\n(no room members)";
|
|
105
|
-
return `\n${members
|
|
106
|
-
.map((member) => [
|
|
107
|
-
`address=${member.address}`,
|
|
108
|
-
`role=${String(member.role ?? "")}`,
|
|
109
|
-
member.parent !== undefined ? `parent=${String(member.parent)}` : "",
|
|
110
|
-
member.caps !== undefined
|
|
111
|
-
? `caps=${Array.isArray(member.caps) ? member.caps.join(",") : String(member.caps)}`
|
|
112
|
-
: "",
|
|
113
|
-
member.claim !== undefined
|
|
114
|
-
? `claim=${String(member.claim).replaceAll(/\s+/g, "_")}`
|
|
115
|
-
: "",
|
|
116
|
-
`status=${String(member.status ?? "")}`,
|
|
117
|
-
`last_seen=${member.last_seen}`,
|
|
118
|
-
].join(" "))
|
|
119
|
-
.join("\n")}`;
|
|
120
|
-
}
|
|
121
|
-
function compactRoomStatus(status) {
|
|
122
|
-
return `\nroom=${status.room} messages=${status.message_count} roster=${status.roster_count}${status.diagnostics_count ? ` diagnostics=${status.diagnostics_count}` : ""}${status.last_message_at ? ` last_message_at=${status.last_message_at}` : ""}${status.last_message_from ? ` last_from=${status.last_message_from}` : ""}${status.last_message_type ? ` last_type=${status.last_message_type}` : ""}${status.last_message_summary ? ` last_summary=${ToolsResponse.compactPreview(status.last_message_summary)}` : ""}`;
|
|
123
|
-
}
|
|
124
|
-
function compactCommunicationSnapshot(snapshot) {
|
|
125
|
-
if (!snapshot)
|
|
126
|
-
return "\n(no communication snapshot)";
|
|
127
|
-
return `\nself=${snapshot.self} root=${snapshot.root} rooms=${snapshot.rooms.length} updated_at=${snapshot.updated_at}`;
|
|
128
|
-
}
|
|
129
|
-
function compactArtifactPath(value) {
|
|
130
|
-
if (typeof value === "string")
|
|
131
|
-
return value;
|
|
132
|
-
const record = asRecord(value);
|
|
133
|
-
return String(record.path ?? "<missing>");
|
|
134
|
-
}
|
|
135
|
-
function readBoundedReviewEvidence(status, limit) {
|
|
136
|
-
const evidenceFile = status.evidenceFile;
|
|
137
|
-
if (typeof evidenceFile !== "string" || !existsSync(evidenceFile))
|
|
138
|
-
return undefined;
|
|
139
|
-
try {
|
|
140
|
-
const manifest = asRecord(JSON.parse(readFileSync(evidenceFile, "utf8")));
|
|
141
|
-
const commands = Array.isArray(manifest.commands) ? manifest.commands : [];
|
|
142
|
-
const bounded = commands.slice(-Math.max(1, limit));
|
|
143
|
-
return {
|
|
144
|
-
...manifest,
|
|
145
|
-
commands: bounded,
|
|
146
|
-
commands_total: commands.length,
|
|
147
|
-
...(bounded.length < commands.length ? { commands_truncated: true } : {}),
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
catch {
|
|
151
|
-
return {
|
|
152
|
-
status: "invalid",
|
|
153
|
-
error: "review evidence manifest is unreadable",
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
function compactActorFiles(status) {
|
|
158
|
-
const run = String(status.run ?? "<unknown>");
|
|
159
|
-
const artifacts = asRecord(status.artifacts);
|
|
160
|
-
const files = [
|
|
161
|
-
status.stdoutLog,
|
|
162
|
-
status.stderrLog,
|
|
163
|
-
status.eventsFile,
|
|
164
|
-
status.outboxFile,
|
|
165
|
-
status.evidenceFile,
|
|
166
|
-
status.state_dir
|
|
167
|
-
? `${String(status.state_dir)}/communication.json`
|
|
168
|
-
: undefined,
|
|
169
|
-
status.state_dir ? `${String(status.state_dir)}/result.json` : undefined,
|
|
170
|
-
].filter((file) => typeof file === "string");
|
|
171
|
-
const artifactText = Object.keys(artifacts).length
|
|
172
|
-
? ` artifacts=${Object.entries(artifacts)
|
|
173
|
-
.map(([key, value]) => `${key}:${compactArtifactPath(value)}`)
|
|
174
|
-
.join(",")}`
|
|
175
|
-
: "";
|
|
176
|
-
const nextActions = ToolsResponse.artifactNextActions(run, artifacts);
|
|
177
|
-
const nextText = nextActions.length
|
|
178
|
-
? ` next=${nextActions.map((action) => action.replaceAll(/\s+/g, "_")).join("|")}`
|
|
179
|
-
: "";
|
|
180
|
-
return `\nrun=${run}${artifactText}${files.length ? ` files=${files.join(",")}` : ""}${nextText}`;
|
|
181
|
-
}
|
|
182
|
-
function summarizeOtherSessions(currentSession, allRuns) {
|
|
183
|
-
const otherRuns = allRuns.filter((run) => run.ownerId && run.ownerId !== currentSession);
|
|
25
|
+
function runtimeStatus() {
|
|
184
26
|
return {
|
|
185
|
-
|
|
186
|
-
|
|
27
|
+
automatic_review: process.env.PI_ACTORS_AUTOMATIC_REVIEW !== "off",
|
|
28
|
+
run_root: Paths.getRunStateRoot(),
|
|
29
|
+
state_schema: RuntimeIdentity.RUN_STATE_SCHEMA,
|
|
30
|
+
version: RuntimeIdentity.getPackageVersion(),
|
|
187
31
|
};
|
|
188
32
|
}
|
|
189
|
-
function
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
? `other_runs=${String(summary.other_runs)}`
|
|
196
|
-
: "",
|
|
197
|
-
]
|
|
198
|
-
.filter(Boolean)
|
|
199
|
-
.join(" ");
|
|
200
|
-
if (runs.length === 0)
|
|
201
|
-
return `\nsession=${session} runs=0${suffix ? ` ${suffix}` : ""}`;
|
|
202
|
-
return `\nsession=${session} runs=${runs.length}${suffix ? ` ${suffix}` : ""}\n${runs
|
|
33
|
+
function runtimeRuns(ctx, deps, status) {
|
|
34
|
+
const session = ToolsAccess.getContextSessionId(ctx);
|
|
35
|
+
const listed = deps.listRuns
|
|
36
|
+
? deps.listRuns()
|
|
37
|
+
: AsyncRuns.listRuns(undefined, status);
|
|
38
|
+
const runs = listed
|
|
203
39
|
.map((run) => {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return tokens.join(" ");
|
|
40
|
+
try {
|
|
41
|
+
return deps.getRunStatus
|
|
42
|
+
? deps.getRunStatus(String(run.state_dir ?? run.run))
|
|
43
|
+
: AsyncRuns.getRunStatus(String(run.state_dir ?? run.run));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return run;
|
|
47
|
+
}
|
|
213
48
|
})
|
|
214
|
-
.
|
|
49
|
+
.filter((run) => !session || !run.ownerId || run.ownerId === session);
|
|
50
|
+
return { ...(session ? { owner_session: session } : {}), runs };
|
|
215
51
|
}
|
|
216
|
-
function
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
try {
|
|
225
|
-
git_commit = execFileSync("git", ["-C", packageRoot, "rev-parse", "--short", "HEAD"], {
|
|
226
|
-
encoding: "utf8",
|
|
227
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
228
|
-
}).trim();
|
|
229
|
-
}
|
|
230
|
-
catch {
|
|
231
|
-
git_commit = undefined;
|
|
232
|
-
}
|
|
233
|
-
const entrypoint = fileURLToPath(import.meta.url);
|
|
234
|
-
return {
|
|
235
|
-
automatic_recipe_review: Paths.isAutomaticRecipeReviewEnabled(),
|
|
236
|
-
entrypoint,
|
|
237
|
-
git_commit,
|
|
238
|
-
mode: entrypoint.includes("/dist/") ? "dist" : "source",
|
|
239
|
-
package_name: packageJson.name ?? "@llblab/pi-actors",
|
|
240
|
-
package_root: packageRoot,
|
|
241
|
-
recipe_root: Paths.getRecipeRoot(),
|
|
242
|
-
packaged_recipe_root: packagedRecipeRoot,
|
|
243
|
-
version: packageJson.version ?? "unknown",
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
function compactPiActorsRuntimeStatus(status) {
|
|
247
|
-
return `\npi-actors version=${String(status.version)} mode=${String(status.mode)} automatic_review=${String(status.automatic_recipe_review)} path=${String(status.package_root)} entrypoint=${String(status.entrypoint)}${status.git_commit ? ` git=${String(status.git_commit)}` : ""}`;
|
|
248
|
-
}
|
|
249
|
-
function isStaleClaim(message, now) {
|
|
250
|
-
if (message.status !== "claimed")
|
|
251
|
-
return false;
|
|
252
|
-
const claimedAt = Date.parse(String(message.claimed_at ?? ""));
|
|
253
|
-
return Number.isFinite(claimedAt) && now - claimedAt > 5 * 60 * 1000;
|
|
254
|
-
}
|
|
255
|
-
function getRunTriageSignals(runs) {
|
|
256
|
-
const now = Date.now();
|
|
257
|
-
const staleClaims = [];
|
|
258
|
-
const attentionMessages = [];
|
|
52
|
+
function runtimeTriage(ctx, deps) {
|
|
53
|
+
const inventory = runtimeRuns(ctx, deps, undefined);
|
|
54
|
+
const runs = inventory.runs;
|
|
55
|
+
const failed = runs.filter((run) => run.status === "failed");
|
|
56
|
+
const pendingControls = [];
|
|
57
|
+
const staleControls = [];
|
|
58
|
+
const controlDiagnostics = [];
|
|
59
|
+
const nowMs = Date.now();
|
|
259
60
|
for (const run of runs) {
|
|
260
|
-
const stateDir =
|
|
261
|
-
const runId = String(run.run ?? "");
|
|
61
|
+
const stateDir = typeof run.state_dir === "string" ? run.state_dir : undefined;
|
|
262
62
|
if (!stateDir)
|
|
263
63
|
continue;
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
});
|
|
288
|
-
}
|
|
64
|
+
const runId = String(run.run ?? "unknown");
|
|
65
|
+
const journal = RunsControls.readRunControlJournalFromStateDir(stateDir);
|
|
66
|
+
controlDiagnostics.push(...journal.diagnostics.map((diagnostic) => ({
|
|
67
|
+
...(diagnostic.line === undefined ? {} : { line: diagnostic.line }),
|
|
68
|
+
reason: diagnostic.line === undefined
|
|
69
|
+
? "unreadable_control_journal"
|
|
70
|
+
: "invalid_control_json",
|
|
71
|
+
run: runId,
|
|
72
|
+
})));
|
|
73
|
+
for (const control of journal.records) {
|
|
74
|
+
const classified = RuntimeTriage.classifyRuntimeControl({
|
|
75
|
+
run: runId,
|
|
76
|
+
...(typeof run.run_instance_id === "string"
|
|
77
|
+
? { runInstanceId: run.run_instance_id }
|
|
78
|
+
: {}),
|
|
79
|
+
status: String(run.status ?? "unknown"),
|
|
80
|
+
}, control, nowMs);
|
|
81
|
+
if (classified.pending)
|
|
82
|
+
pendingControls.push(classified.pending);
|
|
83
|
+
if (classified.stale)
|
|
84
|
+
staleControls.push(classified.stale);
|
|
85
|
+
if (classified.diagnostic)
|
|
86
|
+
controlDiagnostics.push({ ...classified.diagnostic });
|
|
289
87
|
}
|
|
290
|
-
catch { }
|
|
291
88
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (recipe.tool !== true)
|
|
296
|
-
return false;
|
|
297
|
-
const labels = Array.isArray(recipe.risk_labels)
|
|
298
|
-
? recipe.risk_labels.map((label) => String(label))
|
|
299
|
-
: [];
|
|
300
|
-
return labels.some((label) => label !== "risk.long_running");
|
|
301
|
-
}
|
|
302
|
-
function getPiActorsTriage(ctx, deps) {
|
|
303
|
-
const runtime = getPiActorsRuntimeStatus();
|
|
304
|
-
const currentSession = ToolsAccess.getContextSessionId(ctx);
|
|
305
|
-
const listRuns = deps.listRuns ?? AsyncRuns.listRuns;
|
|
306
|
-
const getRunStatus = deps.getRunStatus ?? AsyncRuns.getRunStatus;
|
|
307
|
-
const allRuns = listRuns().flatMap((run) => {
|
|
308
|
-
try {
|
|
309
|
-
return [getRunStatus(String(run.state_dir))];
|
|
310
|
-
}
|
|
311
|
-
catch {
|
|
89
|
+
const attentionEvents = runs.flatMap((run) => {
|
|
90
|
+
const stateDir = typeof run.state_dir === "string" ? run.state_dir : undefined;
|
|
91
|
+
if (!stateDir)
|
|
312
92
|
return [];
|
|
313
|
-
|
|
93
|
+
return RunsTrace.readRunTraceEvents(stateDir)
|
|
94
|
+
.filter((event) => event.attention === "notify" || event.attention === "followup")
|
|
95
|
+
.map((event) => ({
|
|
96
|
+
run: run.run,
|
|
97
|
+
id: event.id,
|
|
98
|
+
kind: event.kind,
|
|
99
|
+
attention: event.attention,
|
|
100
|
+
summary: event.summary,
|
|
101
|
+
ts: event.ts,
|
|
102
|
+
}));
|
|
314
103
|
});
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
104
|
+
const boundedStaleControls = staleControls.slice(0, 40);
|
|
105
|
+
const staleKeys = new Set(boundedStaleControls.map((control) => `${control.run}\0${control.run_instance_id}\0${control.id}`));
|
|
106
|
+
const boundedPendingControls = [
|
|
107
|
+
...boundedStaleControls,
|
|
108
|
+
...pendingControls.filter((control) => !staleKeys.has(`${control.run}\0${control.run_instance_id}\0${control.id}`)),
|
|
109
|
+
].slice(0, 40);
|
|
110
|
+
return {
|
|
111
|
+
...inventory,
|
|
112
|
+
failed_runs: failed,
|
|
113
|
+
pending_control_count: pendingControls.length,
|
|
114
|
+
pending_controls: boundedPendingControls,
|
|
115
|
+
stale_control_count: staleControls.length,
|
|
116
|
+
stale_controls: boundedStaleControls,
|
|
117
|
+
control_diagnostic_count: controlDiagnostics.length,
|
|
118
|
+
control_diagnostics: controlDiagnostics.slice(0, 40),
|
|
119
|
+
attention_events: attentionEvents.slice(-40).reverse(),
|
|
120
|
+
next_actions: [
|
|
121
|
+
...(failed.length ? ["inspect target=runtime view=runs status=failed"] : []),
|
|
122
|
+
...staleControls.slice(0, 3).map((entry) => `inspect target=run:${entry.run} view=control`),
|
|
123
|
+
...(attentionEvents.length
|
|
124
|
+
? attentionEvents.slice(-3).map((entry) => `inspect target=run:${String(entry.run)} view=trace source=runtime`)
|
|
125
|
+
: []),
|
|
126
|
+
],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function compactRuntime(view, details) {
|
|
130
|
+
if (view === "runs") {
|
|
131
|
+
return `\nruntime runs=${details.runs?.length ?? 0}`;
|
|
132
|
+
}
|
|
133
|
+
if (view === "triage") {
|
|
134
|
+
return `\nruntime failed=${details.failed_runs?.length ?? 0} pending_controls=${Number(details.pending_control_count ?? 0)} stale_controls=${Number(details.stale_control_count ?? 0)} attention=${details.attention_events?.length ?? 0}`;
|
|
135
|
+
}
|
|
136
|
+
return `\nruntime version=${String(details.version)} state_schema=${String(details.state_schema)} automatic_review=${String(details.automatic_review)}`;
|
|
137
|
+
}
|
|
138
|
+
function inspectRuntime(view, input, ctx, deps) {
|
|
139
|
+
if (view === "status")
|
|
140
|
+
return runtimeStatus();
|
|
141
|
+
if (view === "runs") {
|
|
142
|
+
return runtimeRuns(ctx, deps, typeof input.status === "string" ? input.status : undefined);
|
|
143
|
+
}
|
|
144
|
+
if (view === "triage")
|
|
145
|
+
return runtimeTriage(ctx, deps);
|
|
146
|
+
throw new Error("inspect runtime supports view=status, view=runs, or view=triage.");
|
|
147
|
+
}
|
|
148
|
+
function inspectRecipes(view, deps) {
|
|
149
|
+
if (view !== "status" &&
|
|
150
|
+
view !== "summary" &&
|
|
151
|
+
view !== "doctor" &&
|
|
152
|
+
view !== "imports" &&
|
|
153
|
+
view !== "reviews") {
|
|
154
|
+
throw new Error("inspect recipes supports view=status, view=summary, view=doctor, view=imports, or view=reviews.");
|
|
155
|
+
}
|
|
323
156
|
const recipeRoot = deps.recipeRoot ?? Paths.getRecipeRoot();
|
|
157
|
+
if (view === "reviews") {
|
|
158
|
+
return ReviewDiagnostics.readAutomaticReviewDiagnostics({ recipeRoot });
|
|
159
|
+
}
|
|
324
160
|
const discovered = RecipesDiscovery.discoverRecipeSources([
|
|
325
161
|
{ root: recipeRoot, defaultTool: true, mutableUsage: true },
|
|
326
162
|
{ root: deps.packagedRecipeRoot ?? Paths.getPackagedRecipeRoot() },
|
|
327
163
|
]);
|
|
328
|
-
const
|
|
164
|
+
const summary = {
|
|
329
165
|
...RecipesDiscovery.summarizeDiscovery(discovered),
|
|
330
166
|
drafts: RecipesDiscovery.listDraftRecipes(join(recipeRoot, "drafts")),
|
|
331
167
|
};
|
|
332
|
-
const activeRecipes = Array.isArray(recipeSummary.active)
|
|
333
|
-
? recipeSummary.active
|
|
334
|
-
: [];
|
|
335
|
-
const highRiskRecipes = activeRecipes.filter(isTriageHighRiskRecipe);
|
|
336
|
-
const signals = getRunTriageSignals(visibleRuns);
|
|
337
|
-
const attentionMessages = signals.attention_messages;
|
|
338
|
-
const staleClaims = signals.stale_claims;
|
|
339
|
-
const invalidRecipes = Array.isArray(recipeSummary.invalid)
|
|
340
|
-
? recipeSummary.invalid
|
|
341
|
-
: [];
|
|
342
|
-
const remediations = Array.isArray(recipeSummary.remediations)
|
|
343
|
-
? recipeSummary.remediations
|
|
344
|
-
: [];
|
|
345
|
-
const drafts = Array.isArray(recipeSummary.drafts)
|
|
346
|
-
? recipeSummary.drafts
|
|
347
|
-
: [];
|
|
348
|
-
const nextActions = [
|
|
349
|
-
invalidRecipes.length || remediations.length
|
|
350
|
-
? "inspect target=recipes view=doctor"
|
|
351
|
-
: "",
|
|
352
|
-
drafts.length ? "inspect target=recipes view=summary verbose=true" : "",
|
|
353
|
-
failedRuns[0]?.run
|
|
354
|
-
? `inspect target=run:${String(failedRuns[0].run)} view=tail lines=80`
|
|
355
|
-
: "",
|
|
356
|
-
attentionMessages[0]?.run
|
|
357
|
-
? `inspect target=run:${String(attentionMessages[0].run)} view=messages`
|
|
358
|
-
: "",
|
|
359
|
-
activeRuns.length
|
|
360
|
-
? "inspect target=session:all view=runs status=active"
|
|
361
|
-
: "",
|
|
362
|
-
].filter(Boolean);
|
|
363
168
|
return {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
active_runs: activeRuns.map((run) => ({
|
|
367
|
-
run: run.run,
|
|
368
|
-
ownerId: run.ownerId,
|
|
369
|
-
recipe: run.recipe,
|
|
370
|
-
status: run.status,
|
|
371
|
-
})),
|
|
372
|
-
other_session_runs: otherRuns.length,
|
|
373
|
-
invalid_recipes: invalidRecipes,
|
|
374
|
-
blocking_recipes: remediations.filter((item) => String(item.kind ?? "").startsWith("blocking_")),
|
|
375
|
-
high_risk_recipes: highRiskRecipes.map((recipe) => ({
|
|
376
|
-
id: recipe.id,
|
|
377
|
-
path: recipe.path,
|
|
378
|
-
risk_labels: recipe.risk_labels,
|
|
379
|
-
})),
|
|
380
|
-
draft_recipes: drafts,
|
|
381
|
-
stale_claims: staleClaims,
|
|
382
|
-
recent_failed_runs: failedRuns.slice(0, 5).map((run) => ({
|
|
383
|
-
run: run.run,
|
|
384
|
-
recipe: run.recipe,
|
|
385
|
-
status: run.status,
|
|
386
|
-
})),
|
|
387
|
-
attention_messages: attentionMessages.slice(-10),
|
|
388
|
-
next_actions: [...new Set(nextActions)].slice(0, 5),
|
|
169
|
+
...summary,
|
|
170
|
+
next_actions: ToolsResponse.recipeRegistryNextActions(summary, view),
|
|
389
171
|
};
|
|
390
172
|
}
|
|
391
|
-
function
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const invalidRecipes = Array.isArray(summary.invalid_recipes)
|
|
397
|
-
? summary.invalid_recipes.length
|
|
398
|
-
: 0;
|
|
399
|
-
const blockingRecipes = Array.isArray(summary.blocking_recipes)
|
|
400
|
-
? summary.blocking_recipes.length
|
|
401
|
-
: 0;
|
|
402
|
-
const highRiskRecipes = Array.isArray(summary.high_risk_recipes)
|
|
403
|
-
? summary.high_risk_recipes.length
|
|
404
|
-
: 0;
|
|
405
|
-
const drafts = Array.isArray(summary.draft_recipes)
|
|
406
|
-
? summary.draft_recipes.length
|
|
407
|
-
: 0;
|
|
408
|
-
const staleClaims = Array.isArray(summary.stale_claims)
|
|
409
|
-
? summary.stale_claims.length
|
|
410
|
-
: 0;
|
|
411
|
-
const failedRuns = Array.isArray(summary.recent_failed_runs)
|
|
412
|
-
? summary.recent_failed_runs.length
|
|
413
|
-
: 0;
|
|
414
|
-
const attention = Array.isArray(summary.attention_messages)
|
|
415
|
-
? summary.attention_messages.length
|
|
416
|
-
: 0;
|
|
417
|
-
const nextActions = Array.isArray(summary.next_actions)
|
|
418
|
-
? summary.next_actions
|
|
419
|
-
: [];
|
|
420
|
-
return `\ntriage version=${String(runtime.version ?? "unknown")} mode=${String(runtime.mode ?? "unknown")} active_runs=${activeRuns} other_runs=${String(summary.other_session_runs ?? 0)} invalid_recipes=${invalidRecipes} blocking_recipes=${blockingRecipes} high_risk_recipes=${highRiskRecipes} drafts=${drafts} stale_claims=${staleClaims} failed_runs=${failedRuns} attention=${attention}${ToolsResponse.compactNextActions(nextActions)}`;
|
|
173
|
+
function parseRunTarget(target) {
|
|
174
|
+
if (!target.startsWith("run:"))
|
|
175
|
+
return undefined;
|
|
176
|
+
const run = target.slice(4);
|
|
177
|
+
return run && /^[A-Za-z0-9_.-]+$/.test(run) ? run : undefined;
|
|
421
178
|
}
|
|
422
|
-
function
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
179
|
+
function inspectRun(run, view, input, ctx, deps) {
|
|
180
|
+
if (view !== "recipe" && view !== "trace" && view !== "control") {
|
|
181
|
+
throw new Error("inspect run:<id> supports view=recipe, view=trace, or view=control.");
|
|
182
|
+
}
|
|
183
|
+
const status = deps.getRunStatus
|
|
184
|
+
? deps.getRunStatus(run)
|
|
185
|
+
: ToolsAccess.assertRunAccessibleToContext(run, ctx);
|
|
186
|
+
const stateDir = String(status.state_dir);
|
|
187
|
+
if (view === "recipe") {
|
|
188
|
+
return Inspector.readActorInspectorRecipe(stateDir);
|
|
189
|
+
}
|
|
190
|
+
if (view === "trace") {
|
|
191
|
+
const source = typeof input.source === "string" ? input.source : "all";
|
|
192
|
+
if (source !== "all" &&
|
|
193
|
+
source !== "lifecycle" &&
|
|
194
|
+
source !== "control" &&
|
|
195
|
+
source !== "process" &&
|
|
196
|
+
source !== "agent" &&
|
|
197
|
+
source !== "artifact" &&
|
|
198
|
+
source !== "runtime") {
|
|
199
|
+
throw new Error(`unsupported Trace source: ${source}`);
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
run,
|
|
203
|
+
source,
|
|
204
|
+
items: TraceProjection.projectRunTrace(stateDir, {
|
|
205
|
+
artifacts: status.artifacts,
|
|
206
|
+
limit: Number(input.lines || Limits.DEFAULT_INSPECT_LINES),
|
|
207
|
+
source,
|
|
208
|
+
}),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
const runInstanceId = String(status.run_instance_id ?? "");
|
|
212
|
+
return {
|
|
213
|
+
run,
|
|
214
|
+
run_instance_id: runInstanceId,
|
|
215
|
+
status: status.status,
|
|
216
|
+
actor_actions: Array.isArray(status.control) ? status.control : [],
|
|
217
|
+
runtime_actions: status.status === "running" ? ["kill"] : ["archive", "prune"],
|
|
218
|
+
endpoint: runInstanceId
|
|
219
|
+
? RunControlDelivery.readRunControlEndpoint(stateDir, runInstanceId)
|
|
220
|
+
: undefined,
|
|
221
|
+
recent_controls: RunsControls.readRunControlsFromStateDir(stateDir)
|
|
222
|
+
.slice(-Math.max(1, Number(input.lines || 20)))
|
|
223
|
+
.reverse()
|
|
224
|
+
.map(ControlProjection.projectRunControl),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function inspectTool(name, view, deps) {
|
|
228
|
+
if (!name || !/^[A-Za-z0-9_.-]+$/.test(name)) {
|
|
229
|
+
throw new Error(`invalid tool target: tool:${name}`);
|
|
230
|
+
}
|
|
231
|
+
if (view !== "status" && view !== "schema") {
|
|
232
|
+
throw new Error("inspect tool:<name> supports view=status or view=schema.");
|
|
233
|
+
}
|
|
234
|
+
const tool = deps.getTool?.(name);
|
|
235
|
+
if (!tool)
|
|
236
|
+
throw new Error(`registered tool not found: ${name}`);
|
|
237
|
+
return {
|
|
238
|
+
name,
|
|
239
|
+
description: tool.description,
|
|
240
|
+
parameters: tool.parameters,
|
|
241
|
+
promptSnippet: tool.promptSnippet,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function compactResult(target, view, details) {
|
|
245
|
+
if (target === "runtime")
|
|
246
|
+
return compactRuntime(view, details);
|
|
247
|
+
if (target === "recipes")
|
|
248
|
+
return ToolsResponse.compactRecipeRegistry(details);
|
|
249
|
+
if (target.startsWith("tool:"))
|
|
250
|
+
return `\ntool=${target.slice(5)} view=${view}`;
|
|
251
|
+
return `\nrun=${target.slice(4)} view=${view}`;
|
|
429
252
|
}
|
|
430
253
|
export function createInspectToolDefinition(deps = {}) {
|
|
431
254
|
return {
|
|
432
255
|
name: "inspect",
|
|
433
256
|
label: "Inspect",
|
|
434
|
-
description: "
|
|
257
|
+
description: "Inspect a Run's Recipe, Trace, or Control evidence, or runtime/recipe/tool diagnostics.",
|
|
435
258
|
parameters: Schema.objectSchema({
|
|
436
|
-
lines: Schema.stringSchema("
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
259
|
+
lines: Schema.stringSchema("Bounded item count for Trace or recent Controls."),
|
|
260
|
+
source: Schema.stringSchema("Optional Trace source: all, lifecycle, control, process, agent, artifact, or runtime."),
|
|
261
|
+
status: Schema.stringSchema("Optional runtime Run status filter."),
|
|
262
|
+
target: Schema.stringSchema("Target: run:<id>, runtime, recipes, or tool:<name>."),
|
|
263
|
+
verbose: Schema.booleanSchema("Return full JSON instead of compact text."),
|
|
264
|
+
view: Schema.stringSchema("Run view recipe|trace|control, or target-specific management view."),
|
|
441
265
|
}, ["target", "view"]),
|
|
442
266
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
443
267
|
const input = asRecord(params);
|
|
444
268
|
const target = String(input.target ?? "");
|
|
445
269
|
const view = String(input.view ?? "");
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
view !== "doctor" &&
|
|
450
|
-
view !== "imports" &&
|
|
451
|
-
view !== "reviews") {
|
|
452
|
-
throw new Error("inspect recipes supports view=status, view=summary, view=doctor, view=imports, or view=reviews.");
|
|
453
|
-
}
|
|
454
|
-
if (view === "reviews") {
|
|
455
|
-
const diagnostics = ReviewDiagnostics.readAutomaticReviewDiagnostics({
|
|
456
|
-
recipeRoot: deps.recipeRoot ?? Paths.getRecipeRoot(),
|
|
457
|
-
});
|
|
458
|
-
return {
|
|
459
|
-
content: [{
|
|
460
|
-
type: "text",
|
|
461
|
-
text: maybeJsonText(diagnostics, input.verbose === true, compactAutomaticReviewDiagnostics(diagnostics)),
|
|
462
|
-
}],
|
|
463
|
-
details: diagnostics,
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
const discovered = RecipesDiscovery.discoverRecipeSources([
|
|
467
|
-
{
|
|
468
|
-
root: deps.recipeRoot ?? Paths.getRecipeRoot(),
|
|
469
|
-
defaultTool: true,
|
|
470
|
-
mutableUsage: true,
|
|
471
|
-
},
|
|
472
|
-
{ root: deps.packagedRecipeRoot ?? Paths.getPackagedRecipeRoot() },
|
|
473
|
-
]);
|
|
474
|
-
const recipeRoot = deps.recipeRoot ?? Paths.getRecipeRoot();
|
|
475
|
-
const summaryBase = {
|
|
476
|
-
...RecipesDiscovery.summarizeDiscovery(discovered),
|
|
477
|
-
drafts: RecipesDiscovery.listDraftRecipes(join(recipeRoot, "drafts")),
|
|
478
|
-
};
|
|
479
|
-
const summary = {
|
|
480
|
-
...summaryBase,
|
|
481
|
-
next_actions: ToolsResponse.recipeRegistryNextActions(summaryBase, view),
|
|
482
|
-
};
|
|
483
|
-
return {
|
|
484
|
-
content: [
|
|
485
|
-
{
|
|
486
|
-
type: "text",
|
|
487
|
-
text: maybeJsonText(summary, input.verbose === true, view === "doctor"
|
|
488
|
-
? ToolsResponse.compactRecipeDoctor(summary)
|
|
489
|
-
: view === "imports"
|
|
490
|
-
? ToolsResponse.compactRecipeImports(summary)
|
|
491
|
-
: ToolsResponse.compactRecipeRegistry(summary)),
|
|
492
|
-
},
|
|
493
|
-
],
|
|
494
|
-
details: summary,
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
const address = Messages.parseActorAddress(target);
|
|
498
|
-
if (address.kind === "coordinator") {
|
|
499
|
-
if (view !== "status" && view !== "runs") {
|
|
500
|
-
throw new Error("inspect coordinator supports view=status or view=runs.");
|
|
501
|
-
}
|
|
502
|
-
const session = ToolsAccess.requireContextSessionId(ctx, "inspect coordinator");
|
|
503
|
-
const allRuns = AsyncRuns.listRuns(undefined, typeof input.status === "string" ? input.status : undefined).map((run) => AsyncRuns.getRunStatus(String(run.state_dir)));
|
|
504
|
-
const runs = allRuns.filter((run) => run.ownerId === session);
|
|
505
|
-
const sessionSummary = summarizeOtherSessions(session, allRuns);
|
|
506
|
-
return {
|
|
507
|
-
content: [
|
|
508
|
-
{
|
|
509
|
-
type: "text",
|
|
510
|
-
text: maybeJsonText({ session, runs, ...sessionSummary }, input.verbose === true, compactSessionRuns(session, runs, sessionSummary)),
|
|
511
|
-
},
|
|
512
|
-
],
|
|
513
|
-
details: { session, runs, ...sessionSummary },
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
if (address.kind === "session") {
|
|
517
|
-
if (view !== "status" && view !== "runs") {
|
|
518
|
-
throw new Error("inspect session:<id> supports view=status or view=runs.");
|
|
519
|
-
}
|
|
520
|
-
const allRuns = AsyncRuns.listRuns(undefined, typeof input.status === "string" ? input.status : undefined).map((run) => AsyncRuns.getRunStatus(String(run.state_dir)));
|
|
521
|
-
const runs = allRuns.filter((run) => address.value === "all" || run.ownerId === address.value);
|
|
522
|
-
const sessionSummary = address.value === "all"
|
|
523
|
-
? {}
|
|
524
|
-
: summarizeOtherSessions(address.value || "", allRuns);
|
|
525
|
-
return {
|
|
526
|
-
content: [
|
|
527
|
-
{
|
|
528
|
-
type: "text",
|
|
529
|
-
text: maybeJsonText({ session: address.value, runs, ...sessionSummary }, input.verbose === true, compactSessionRuns(address.value || "", runs, sessionSummary)),
|
|
530
|
-
},
|
|
531
|
-
],
|
|
532
|
-
details: { session: address.value, runs, ...sessionSummary },
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
if (address.kind === "tool" && address.value) {
|
|
536
|
-
if (address.value === "pi-actors") {
|
|
537
|
-
if (view !== "status" && view !== "triage") {
|
|
538
|
-
throw new Error("inspect tool:pi-actors supports view=status or view=triage.");
|
|
539
|
-
}
|
|
540
|
-
const details = view === "triage"
|
|
541
|
-
? getPiActorsTriage(ctx, deps)
|
|
542
|
-
: getPiActorsRuntimeStatus();
|
|
543
|
-
return {
|
|
544
|
-
content: [
|
|
545
|
-
{
|
|
546
|
-
type: "text",
|
|
547
|
-
text: maybeJsonText(details, input.verbose === true, view === "triage"
|
|
548
|
-
? compactPiActorsTriage(details)
|
|
549
|
-
: compactPiActorsRuntimeStatus(details)),
|
|
550
|
-
},
|
|
551
|
-
],
|
|
552
|
-
details,
|
|
553
|
-
};
|
|
554
|
-
}
|
|
555
|
-
if (view !== "status" && view !== "schema") {
|
|
556
|
-
throw new Error("inspect tool:<name> supports view=status or view=schema.");
|
|
557
|
-
}
|
|
558
|
-
const tool = deps.getTool?.(address.value);
|
|
559
|
-
if (!tool)
|
|
560
|
-
throw new Error(`tool actor not found: ${address.value}`);
|
|
561
|
-
const details = {
|
|
562
|
-
name: address.value,
|
|
563
|
-
description: tool.description,
|
|
564
|
-
parameters: tool.parameters,
|
|
565
|
-
promptSnippet: tool.promptSnippet,
|
|
566
|
-
};
|
|
567
|
-
return {
|
|
568
|
-
content: [
|
|
569
|
-
{
|
|
570
|
-
type: "text",
|
|
571
|
-
text: maybeJsonText(details, input.verbose === true || view === "schema", compactToolActor(address.value, details)),
|
|
572
|
-
},
|
|
573
|
-
],
|
|
574
|
-
details,
|
|
575
|
-
};
|
|
270
|
+
let details;
|
|
271
|
+
if (target === "runtime") {
|
|
272
|
+
details = inspectRuntime(view, input, ctx, deps);
|
|
576
273
|
}
|
|
577
|
-
if (
|
|
578
|
-
|
|
579
|
-
const stateDir = String(status.state_dir ?? "");
|
|
580
|
-
if (!stateDir)
|
|
581
|
-
throw new Error(`room:${address.value} has no run state directory.`);
|
|
582
|
-
if (view === "status") {
|
|
583
|
-
const status = Rooms.getRoomStatus(stateDir, address.room);
|
|
584
|
-
return {
|
|
585
|
-
content: [
|
|
586
|
-
{
|
|
587
|
-
type: "text",
|
|
588
|
-
text: maybeJsonText(status, input.verbose === true, compactRoomStatus(status)),
|
|
589
|
-
},
|
|
590
|
-
],
|
|
591
|
-
details: status,
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
if (view === "previews") {
|
|
595
|
-
const previews = Rooms.readRoomMessagePreviews(stateDir, address.room, Number(input.lines || Limits.DEFAULT_INSPECT_LINES));
|
|
596
|
-
return {
|
|
597
|
-
content: [
|
|
598
|
-
{
|
|
599
|
-
type: "text",
|
|
600
|
-
text: maybeJsonText(previews, input.verbose === true, compactRoomPreviews(previews)),
|
|
601
|
-
},
|
|
602
|
-
],
|
|
603
|
-
details: { previews },
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
if (view === "messages") {
|
|
607
|
-
const messages = Rooms.readRoomMessages(stateDir, address.room, Number(input.lines || Limits.DEFAULT_INSPECT_LINES));
|
|
608
|
-
return {
|
|
609
|
-
content: [
|
|
610
|
-
{
|
|
611
|
-
type: "text",
|
|
612
|
-
text: maybeJsonText(messages, input.verbose === true, compactRoomMessages(messages)),
|
|
613
|
-
},
|
|
614
|
-
],
|
|
615
|
-
details: { messages },
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
if (view === "contacts") {
|
|
619
|
-
const contacts = Rooms.readRoomContacts(stateDir, address.room);
|
|
620
|
-
return {
|
|
621
|
-
content: [
|
|
622
|
-
{
|
|
623
|
-
type: "text",
|
|
624
|
-
text: maybeJsonText(contacts, input.verbose === true, compactRoomContacts(contacts)),
|
|
625
|
-
},
|
|
626
|
-
],
|
|
627
|
-
details: { contacts },
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
if (view === "roster") {
|
|
631
|
-
const roster = Rooms.readRoomRoster(stateDir, address.room);
|
|
632
|
-
return {
|
|
633
|
-
content: [
|
|
634
|
-
{
|
|
635
|
-
type: "text",
|
|
636
|
-
text: maybeJsonText(roster, input.verbose === true, compactRoomRoster(roster)),
|
|
637
|
-
},
|
|
638
|
-
],
|
|
639
|
-
details: { roster },
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
throw new Error("inspect room:<run> supports view=status, view=messages, view=previews, view=roster, or view=contacts.");
|
|
274
|
+
else if (target === "recipes") {
|
|
275
|
+
details = inspectRecipes(view, deps);
|
|
643
276
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
if (view !== "mailbox")
|
|
651
|
-
throw new Error("inspect branch:<run>/<branch> supports view=mailbox.");
|
|
652
|
-
const status = ToolsAccess.assertRunAccessibleToContext(runId, ctx);
|
|
653
|
-
const branchInbox = Rooms.readBranchInboxDiagnostics(String(status.state_dir ?? ""), runId, target, Number(input.lines || Limits.DEFAULT_INSPECT_LINES));
|
|
654
|
-
const messages = branchInbox.messages;
|
|
655
|
-
return {
|
|
656
|
-
content: [
|
|
657
|
-
{
|
|
658
|
-
type: "text",
|
|
659
|
-
text: maybeJsonText(input.verbose === true ? branchInbox : messages, input.verbose === true, `${ToolsResponse.compactBranchInbox(messages.map((message) => ({ ...message })))}${branchInbox.corrupted > 0 ? `\ncorrupted=${branchInbox.corrupted}` : ""}`),
|
|
660
|
-
},
|
|
661
|
-
],
|
|
662
|
-
details: { corrupted: branchInbox.corrupted, messages },
|
|
663
|
-
};
|
|
664
|
-
}
|
|
665
|
-
switch (view) {
|
|
666
|
-
case "status": {
|
|
667
|
-
const status = ToolsAccess.assertRunAccessibleToContext(runId, ctx);
|
|
668
|
-
return {
|
|
669
|
-
content: [
|
|
670
|
-
{
|
|
671
|
-
type: "text",
|
|
672
|
-
text: maybeJsonText(status, input.verbose === true, ToolsResponse.compactAsyncRunStatus(status)),
|
|
673
|
-
},
|
|
674
|
-
],
|
|
675
|
-
details: status,
|
|
676
|
-
};
|
|
677
|
-
}
|
|
678
|
-
case "tail": {
|
|
679
|
-
ToolsAccess.assertRunAccessibleToContext(runId, ctx);
|
|
680
|
-
const text = AsyncRuns.tailRun(runId, Number(input.lines || Limits.DEFAULT_INSPECT_LINES));
|
|
681
|
-
return {
|
|
682
|
-
content: [{ type: "text", text: `\n${text}` }],
|
|
683
|
-
details: {},
|
|
684
|
-
};
|
|
685
|
-
}
|
|
686
|
-
case "messages": {
|
|
687
|
-
ToolsAccess.assertRunAccessibleToContext(runId, ctx);
|
|
688
|
-
const messages = AsyncRuns.readRunEvents(runId, Number(input.lines || Limits.DEFAULT_INSPECT_LINES));
|
|
689
|
-
return {
|
|
690
|
-
content: [
|
|
691
|
-
{
|
|
692
|
-
type: "text",
|
|
693
|
-
text: maybeJsonText(messages, input.verbose === true, compactRunMessages(messages)),
|
|
694
|
-
},
|
|
695
|
-
],
|
|
696
|
-
details: { messages },
|
|
697
|
-
};
|
|
698
|
-
}
|
|
699
|
-
case "artifacts":
|
|
700
|
-
case "files": {
|
|
701
|
-
const status = ToolsAccess.assertRunAccessibleToContext(runId, ctx);
|
|
702
|
-
const artifactManifest = AsyncRuns.resolveArtifactManifest(status.artifacts);
|
|
703
|
-
const reviewEvidence = readBoundedReviewEvidence(status, Number(input.lines || Limits.DEFAULT_INSPECT_LINES));
|
|
704
|
-
const details = artifactManifest
|
|
705
|
-
? {
|
|
706
|
-
...status,
|
|
707
|
-
...(reviewEvidence ? { review_evidence: reviewEvidence } : {}),
|
|
708
|
-
artifact_manifest: artifactManifest,
|
|
709
|
-
next_actions: ToolsResponse.artifactNextActions(status.run ?? runId, asRecord(status.artifacts)),
|
|
710
|
-
}
|
|
711
|
-
: {
|
|
712
|
-
...status,
|
|
713
|
-
...(reviewEvidence ? { review_evidence: reviewEvidence } : {}),
|
|
714
|
-
};
|
|
715
|
-
return {
|
|
716
|
-
content: [
|
|
717
|
-
{
|
|
718
|
-
type: "text",
|
|
719
|
-
text: maybeJsonText(details, input.verbose === true, compactActorFiles(status)),
|
|
720
|
-
},
|
|
721
|
-
],
|
|
722
|
-
details,
|
|
723
|
-
};
|
|
724
|
-
}
|
|
725
|
-
case "mailbox": {
|
|
726
|
-
const status = ToolsAccess.assertRunAccessibleToContext(runId, ctx);
|
|
727
|
-
const mailbox = asRecord(status.mailbox);
|
|
728
|
-
const normalizedMailbox = ToolsMailbox.normalizeMailboxContracts(mailbox);
|
|
729
|
-
const messages = AsyncRuns.readRunInboxMessages(runId, Number(input.lines || Limits.DEFAULT_INSPECT_LINES));
|
|
730
|
-
const details = {
|
|
731
|
-
mailbox,
|
|
732
|
-
normalized_mailbox: normalizedMailbox,
|
|
733
|
-
messages,
|
|
734
|
-
};
|
|
735
|
-
return {
|
|
736
|
-
content: [
|
|
737
|
-
{
|
|
738
|
-
type: "text",
|
|
739
|
-
text: maybeJsonText(details, input.verbose === true, ToolsResponse.compactRunMailbox(String(status.run ?? runId), mailbox, messages)),
|
|
740
|
-
},
|
|
741
|
-
],
|
|
742
|
-
details,
|
|
743
|
-
};
|
|
277
|
+
else {
|
|
278
|
+
const run = parseRunTarget(target);
|
|
279
|
+
if (run)
|
|
280
|
+
details = inspectRun(run, view, input, ctx, deps);
|
|
281
|
+
else if (target.startsWith("tool:")) {
|
|
282
|
+
details = inspectTool(target.slice(5), view, deps);
|
|
744
283
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
const snapshot = Rooms.readCommunicationSnapshot(String(status.state_dir ?? ""));
|
|
748
|
-
return {
|
|
749
|
-
content: [
|
|
750
|
-
{
|
|
751
|
-
type: "text",
|
|
752
|
-
text: maybeJsonText(snapshot ?? {}, input.verbose === true, compactCommunicationSnapshot(snapshot)),
|
|
753
|
-
},
|
|
754
|
-
],
|
|
755
|
-
details: { communication: snapshot },
|
|
756
|
-
};
|
|
284
|
+
else {
|
|
285
|
+
throw new Error(`unsupported inspect target: ${target}; use run:<id>, runtime, recipes, or tool:<name>`);
|
|
757
286
|
}
|
|
758
|
-
default:
|
|
759
|
-
throw new Error("inspect view must be one of: status, tail, messages, artifacts, files, mailbox, communication; branch targets support mailbox.");
|
|
760
287
|
}
|
|
288
|
+
return {
|
|
289
|
+
content: [{
|
|
290
|
+
type: "text",
|
|
291
|
+
text: maybeJsonText(details, input.verbose === true || (target.startsWith("tool:") && view === "schema"), compactResult(target, view, details)),
|
|
292
|
+
}],
|
|
293
|
+
details,
|
|
294
|
+
};
|
|
761
295
|
},
|
|
762
296
|
};
|
|
763
297
|
}
|