@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
package/lib/limits.ts
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared output and
|
|
3
|
-
* Zones: output governance,
|
|
2
|
+
* Shared output, preview, and Control envelope limits.
|
|
3
|
+
* Zones: output governance, Trace previews, Inspect defaults, Control portability
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export const DEFAULT_INSPECT_LINES = 40;
|
|
7
7
|
export const TOOL_OUTPUT_MAX_BYTES = 50 * 1024;
|
|
8
8
|
export const TOOL_OUTPUT_MAX_LINES = 2_000;
|
|
9
9
|
export const COMPACT_PREVIEW_CHARS = 160;
|
|
10
|
+
export const CONTROL_ACTION_MAX_LENGTH = 64;
|
|
11
|
+
export const CONTROL_INPUT_MAX_BYTES = 380;
|
|
12
|
+
export const CONTROL_WIRE_MAX_BYTES = 512;
|
|
10
13
|
export const INSPECTOR_BODY_PREVIEW_CHARS = 320;
|
|
11
|
-
export const ROOM_MESSAGE_PREVIEW_CHARS = 320;
|
|
12
14
|
export const DOCTOR_ACTION_PREVIEW_CHARS = 72;
|
|
13
15
|
export const SESSION_EVIDENCE_MAX_TURNS = 100;
|
|
14
16
|
export const SESSION_EVIDENCE_TEXT_CHARS = 4_000;
|
|
15
17
|
export const SESSION_EVIDENCE_MAX_TOOL_CALLS = 100;
|
|
18
|
+
export const TRACE_EVENT_MAX_BYTES = 64 * 1024;
|
|
19
|
+
export const TRACE_EVENT_MAX_READ = 200;
|
package/lib/observability.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Async run observability helpers
|
|
3
3
|
* Zones: async runtime, ambient UI, diagnostics
|
|
4
|
-
* Owns ambient summaries, terminal events, and
|
|
4
|
+
* Owns ambient summaries, terminal events, and Trace-attention delivery for detached Runs
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {
|
|
@@ -34,8 +34,8 @@ export type RunObservedStatus =
|
|
|
34
34
|
| "exited"
|
|
35
35
|
| "cancelled"
|
|
36
36
|
| "killed";
|
|
37
|
-
export type
|
|
38
|
-
export type
|
|
37
|
+
export type RunTraceAttention = "log" | "notify" | "followup";
|
|
38
|
+
export type RunTraceLevel = "info" | "warning" | "error";
|
|
39
39
|
|
|
40
40
|
export interface RunObservation {
|
|
41
41
|
activeSubagents?: number;
|
|
@@ -72,14 +72,14 @@ export interface RunSummary {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
export interface RunUiObservationState {
|
|
75
|
+
attentionEventIds: Map<string, Set<string>>;
|
|
75
76
|
eventLines: Map<string, number>;
|
|
76
77
|
frame: number;
|
|
77
78
|
observed: Map<string, RunObservedStatus>;
|
|
78
|
-
outboxEventIds: Map<string, Set<string>>;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export interface RunUiSnapshot {
|
|
82
|
-
|
|
82
|
+
attentionEvents: RunAttentionEvent[];
|
|
83
83
|
status: string | undefined;
|
|
84
84
|
summary: RunSummary;
|
|
85
85
|
transitions: RunTransition[];
|
|
@@ -97,28 +97,28 @@ export interface RunUiNotificationSink {
|
|
|
97
97
|
|
|
98
98
|
export function createRunUiObservationState(): RunUiObservationState {
|
|
99
99
|
return {
|
|
100
|
+
attentionEventIds: new Map<string, Set<string>>(),
|
|
100
101
|
eventLines: new Map<string, number>(),
|
|
101
102
|
frame: 0,
|
|
102
103
|
observed: new Map<string, RunObservedStatus>(),
|
|
103
|
-
outboxEventIds: new Map<string, Set<string>>(),
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
export function readRunUiSnapshot(
|
|
108
108
|
state: RunUiObservationState,
|
|
109
109
|
ownerId: string,
|
|
110
|
-
options: {
|
|
110
|
+
options: { includeAttention?: boolean; stateRoot?: string } = {},
|
|
111
111
|
): RunUiSnapshot {
|
|
112
112
|
const summary = summarizeRuns(options.stateRoot, ownerId);
|
|
113
113
|
const status = renderRunStatus(summary, state.frame++);
|
|
114
114
|
return {
|
|
115
|
-
|
|
116
|
-
options.
|
|
115
|
+
attentionEvents:
|
|
116
|
+
options.includeAttention === false
|
|
117
117
|
? []
|
|
118
|
-
:
|
|
118
|
+
: detectRunAttentionEvents(
|
|
119
119
|
state.eventLines,
|
|
120
120
|
summary,
|
|
121
|
-
state.
|
|
121
|
+
state.attentionEventIds,
|
|
122
122
|
),
|
|
123
123
|
status,
|
|
124
124
|
summary,
|
|
@@ -137,7 +137,7 @@ export function pruneRunUiObservationState(
|
|
|
137
137
|
snapshot.transitions.map(
|
|
138
138
|
(transition) => transition.stateDir ?? transition.run,
|
|
139
139
|
),
|
|
140
|
-
state.
|
|
140
|
+
state.attentionEventIds,
|
|
141
141
|
);
|
|
142
142
|
}
|
|
143
143
|
|
|
@@ -194,7 +194,7 @@ export function reconcileRunTerminalNotifications(input: {
|
|
|
194
194
|
stateRoot?: string;
|
|
195
195
|
}): RunUiSnapshot {
|
|
196
196
|
const snapshot = readRunUiSnapshot(input.state, input.ownerId, {
|
|
197
|
-
|
|
197
|
+
includeAttention: false,
|
|
198
198
|
stateRoot: input.stateRoot,
|
|
199
199
|
});
|
|
200
200
|
deliverRunTransitionNotifications(
|
|
@@ -206,17 +206,17 @@ export function reconcileRunTerminalNotifications(input: {
|
|
|
206
206
|
return snapshot;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
export function
|
|
210
|
-
events:
|
|
209
|
+
export function deliverRunAttentionNotifications(
|
|
210
|
+
events: RunAttentionEvent[],
|
|
211
211
|
sink: RunUiNotificationSink,
|
|
212
212
|
): void {
|
|
213
213
|
for (const event of events) {
|
|
214
|
-
if (!
|
|
215
|
-
const text =
|
|
216
|
-
sink.notify(text,
|
|
217
|
-
if (!
|
|
214
|
+
if (!shouldNotifyRunAttentionEvent(event)) continue;
|
|
215
|
+
const text = formatRunAttentionMessage(event);
|
|
216
|
+
sink.notify(text, getRunAttentionNotificationType(event));
|
|
217
|
+
if (!shouldSendRunAttentionFollowUp(event)) continue;
|
|
218
218
|
sink.sendFollowUp({
|
|
219
|
-
customType: "pi-actors-run-
|
|
219
|
+
customType: "pi-actors-run-trace",
|
|
220
220
|
content: text,
|
|
221
221
|
display: false,
|
|
222
222
|
details: event,
|
|
@@ -457,13 +457,13 @@ export interface RunTerminalSemanticResult {
|
|
|
457
457
|
type: string;
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
-
export interface
|
|
460
|
+
export interface RunAttentionEvent {
|
|
461
461
|
body?: unknown;
|
|
462
462
|
data?: unknown;
|
|
463
|
-
|
|
464
|
-
event: string;
|
|
463
|
+
attention: RunTraceAttention;
|
|
465
464
|
id: string;
|
|
466
|
-
|
|
465
|
+
kind: string;
|
|
466
|
+
level: RunTraceLevel;
|
|
467
467
|
metadata?: Record<string, unknown>;
|
|
468
468
|
run: string;
|
|
469
469
|
stateDir: string;
|
|
@@ -575,48 +575,7 @@ function terminalSemanticResult(
|
|
|
575
575
|
: typeof correlation.tool_call_id === "string"
|
|
576
576
|
? correlation.tool_call_id
|
|
577
577
|
: undefined;
|
|
578
|
-
const
|
|
579
|
-
typeof status.mailbox === "object" &&
|
|
580
|
-
!Array.isArray(status.mailbox)
|
|
581
|
-
? status.mailbox as Record<string, unknown>
|
|
582
|
-
: {};
|
|
583
|
-
const emits = Array.isArray(mailbox.emits)
|
|
584
|
-
? mailbox.emits.filter((item): item is string => typeof item === "string")
|
|
585
|
-
: [];
|
|
586
|
-
const outbox = readJsonlFileResilient<Record<string, unknown>>(
|
|
587
|
-
join(stateDir, "outbox.jsonl"),
|
|
588
|
-
).records;
|
|
589
|
-
const explicit = outbox.findLast((record) => {
|
|
590
|
-
const type = String(record.type ?? record.event ?? "");
|
|
591
|
-
return emits.includes(type) && !["command.done", "run.done", "run.failed"].includes(type);
|
|
592
|
-
});
|
|
593
|
-
if (explicit) {
|
|
594
|
-
const type = String(explicit.type ?? explicit.event);
|
|
595
|
-
return {
|
|
596
|
-
...(explicit.body === undefined
|
|
597
|
-
? {} : { body: formatSemanticBody(explicit.body) }),
|
|
598
|
-
...(typeof explicit.correlation_id === "string"
|
|
599
|
-
? { correlationId: explicit.correlation_id } : correlationId ? { correlationId } : {}),
|
|
600
|
-
metadata: {
|
|
601
|
-
...(explicit.metadata &&
|
|
602
|
-
typeof explicit.metadata === "object" &&
|
|
603
|
-
!Array.isArray(explicit.metadata)
|
|
604
|
-
? explicit.metadata as Record<string, unknown> : {}),
|
|
605
|
-
...(status.transport_context &&
|
|
606
|
-
typeof status.transport_context === "object" &&
|
|
607
|
-
!Array.isArray(status.transport_context)
|
|
608
|
-
? {
|
|
609
|
-
transport_context: status.transport_context as Record<string, unknown>,
|
|
610
|
-
} : {}),
|
|
611
|
-
run: String(status.run ?? ""),
|
|
612
|
-
status: observedStatus,
|
|
613
|
-
},
|
|
614
|
-
summary: String(explicit.summary ?? type),
|
|
615
|
-
synthesized: false,
|
|
616
|
-
type,
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
const reviewCompleted = observedStatus === "done" && emits.includes("review.completed");
|
|
578
|
+
const reviewCompleted = false;
|
|
620
579
|
const result = status.result &&
|
|
621
580
|
typeof status.result === "object" &&
|
|
622
581
|
!Array.isArray(status.result)
|
|
@@ -648,15 +607,6 @@ function terminalSemanticResult(
|
|
|
648
607
|
};
|
|
649
608
|
}
|
|
650
609
|
|
|
651
|
-
function formatSemanticBody(body: unknown): string {
|
|
652
|
-
const rendered = typeof body === "string" ? body : JSON.stringify(body);
|
|
653
|
-
const text = typeof rendered === "string" ? rendered : String(body);
|
|
654
|
-
const compact = text.trim();
|
|
655
|
-
return compact.length > TERMINAL_RESULT_CHARS
|
|
656
|
-
? `${compact.slice(0, TERMINAL_RESULT_CHARS - 1)}…`
|
|
657
|
-
: compact;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
610
|
function observeRun(stateDir: string): RunObservation | undefined {
|
|
661
611
|
try {
|
|
662
612
|
const status = AsyncRuns.getRunStatus(stateDir);
|
|
@@ -1110,24 +1060,26 @@ export function detectRunTransitions(
|
|
|
1110
1060
|
return transitions;
|
|
1111
1061
|
}
|
|
1112
1062
|
|
|
1113
|
-
function
|
|
1063
|
+
function normalizeTraceAttention(value: unknown): RunTraceAttention {
|
|
1114
1064
|
return value === "notify" || value === "followup" ? value : "log";
|
|
1115
1065
|
}
|
|
1116
1066
|
|
|
1117
|
-
function
|
|
1067
|
+
function normalizeTraceLevel(value: unknown): RunTraceLevel {
|
|
1118
1068
|
return value === "warning" || value === "error" ? value : "info";
|
|
1119
1069
|
}
|
|
1120
1070
|
|
|
1121
|
-
function
|
|
1071
|
+
function parseAttentionRecord(
|
|
1122
1072
|
raw: Record<string, unknown>,
|
|
1123
1073
|
run: RunObservation,
|
|
1124
1074
|
index: number,
|
|
1125
|
-
):
|
|
1075
|
+
): RunAttentionEvent | undefined {
|
|
1126
1076
|
if (!run.stateDir) return undefined;
|
|
1127
1077
|
const event =
|
|
1128
|
-
typeof raw.
|
|
1129
|
-
? raw.
|
|
1130
|
-
: "
|
|
1078
|
+
typeof raw.kind === "string" && raw.kind.trim()
|
|
1079
|
+
? raw.kind.trim()
|
|
1080
|
+
: typeof raw.event === "string" && raw.event.trim()
|
|
1081
|
+
? raw.event.trim()
|
|
1082
|
+
: "run.event";
|
|
1131
1083
|
const summary =
|
|
1132
1084
|
typeof raw.summary === "string" && raw.summary.trim()
|
|
1133
1085
|
? raw.summary.trim()
|
|
@@ -1143,10 +1095,13 @@ function parseOutboxRecord(
|
|
|
1143
1095
|
return {
|
|
1144
1096
|
...(raw.body !== undefined ? { body: raw.body } : {}),
|
|
1145
1097
|
...(raw.data !== undefined ? { data: raw.data } : {}),
|
|
1146
|
-
|
|
1147
|
-
|
|
1098
|
+
attention:
|
|
1099
|
+
raw.attention === "notify" || raw.attention === "followup"
|
|
1100
|
+
? raw.attention
|
|
1101
|
+
: normalizeTraceAttention(raw.delivery),
|
|
1148
1102
|
id,
|
|
1149
|
-
|
|
1103
|
+
kind: event,
|
|
1104
|
+
level: normalizeTraceLevel(raw.level),
|
|
1150
1105
|
...(raw.metadata &&
|
|
1151
1106
|
typeof raw.metadata === "object" &&
|
|
1152
1107
|
!Array.isArray(raw.metadata)
|
|
@@ -1159,8 +1114,12 @@ function parseOutboxRecord(
|
|
|
1159
1114
|
};
|
|
1160
1115
|
}
|
|
1161
1116
|
|
|
1162
|
-
function
|
|
1117
|
+
function readTraceAttentionRecords(run: RunObservation): Record<string, unknown>[] {
|
|
1163
1118
|
if (!run.stateDir) return [];
|
|
1119
|
+
const tracePath = join(run.stateDir, "trace.jsonl");
|
|
1120
|
+
if (existsSync(tracePath)) {
|
|
1121
|
+
return readJsonlFileResilient<Record<string, unknown>>(tracePath).records;
|
|
1122
|
+
}
|
|
1164
1123
|
return readJsonlFileResilient<Record<string, unknown>>(
|
|
1165
1124
|
join(run.stateDir, "outbox.jsonl"),
|
|
1166
1125
|
).records;
|
|
@@ -1199,15 +1158,15 @@ export function pruneRunObservationState(
|
|
|
1199
1158
|
}
|
|
1200
1159
|
}
|
|
1201
1160
|
|
|
1202
|
-
export function
|
|
1161
|
+
export function detectRunAttentionEvents(
|
|
1203
1162
|
previousLineCounts: Map<string, number>,
|
|
1204
1163
|
summary: RunSummary,
|
|
1205
1164
|
seenEventIds: Map<string, Set<string>> = new Map(),
|
|
1206
|
-
):
|
|
1207
|
-
const events:
|
|
1165
|
+
): RunAttentionEvent[] {
|
|
1166
|
+
const events: RunAttentionEvent[] = [];
|
|
1208
1167
|
for (const run of summary.runs) {
|
|
1209
1168
|
const key = run.stateDir ?? run.run;
|
|
1210
|
-
const records =
|
|
1169
|
+
const records = readTraceAttentionRecords(run);
|
|
1211
1170
|
const previousCount = previousLineCounts.get(key) ?? 0;
|
|
1212
1171
|
if (run.notificationPolicy === "silent") {
|
|
1213
1172
|
previousLineCounts.set(key, records.length);
|
|
@@ -1217,7 +1176,7 @@ export function detectRunOutboxEvents(
|
|
|
1217
1176
|
const start = Math.min(previousCount, records.length);
|
|
1218
1177
|
const seen = seenEventIds.get(key) ?? new Set<string>();
|
|
1219
1178
|
for (let index = start; index < records.length; index += 1) {
|
|
1220
|
-
const event =
|
|
1179
|
+
const event = parseAttentionRecord(records[index], run, index);
|
|
1221
1180
|
if (!event || seen.has(event.id)) continue;
|
|
1222
1181
|
events.push(event);
|
|
1223
1182
|
seen.add(event.id);
|
|
@@ -1228,18 +1187,18 @@ export function detectRunOutboxEvents(
|
|
|
1228
1187
|
return events;
|
|
1229
1188
|
}
|
|
1230
1189
|
|
|
1231
|
-
export function
|
|
1232
|
-
event:
|
|
1190
|
+
export function getRunAttentionNotificationType(
|
|
1191
|
+
event: RunAttentionEvent,
|
|
1233
1192
|
): RunTransitionNotificationType {
|
|
1234
1193
|
return event.level;
|
|
1235
1194
|
}
|
|
1236
1195
|
|
|
1237
|
-
export function
|
|
1238
|
-
return event.
|
|
1196
|
+
export function shouldNotifyRunAttentionEvent(event: RunAttentionEvent): boolean {
|
|
1197
|
+
return event.attention === "notify" || event.attention === "followup";
|
|
1239
1198
|
}
|
|
1240
1199
|
|
|
1241
|
-
export function
|
|
1242
|
-
return event.
|
|
1200
|
+
export function shouldSendRunAttentionFollowUp(event: RunAttentionEvent): boolean {
|
|
1201
|
+
return event.attention === "followup";
|
|
1243
1202
|
}
|
|
1244
1203
|
|
|
1245
1204
|
function commonDirectory(paths: string[]): string | undefined {
|
|
@@ -1297,7 +1256,7 @@ function formatNamedArtifacts(artifacts: unknown): string {
|
|
|
1297
1256
|
);
|
|
1298
1257
|
}
|
|
1299
1258
|
|
|
1300
|
-
function
|
|
1259
|
+
function getAttentionDataField(event: RunAttentionEvent, key: string): unknown {
|
|
1301
1260
|
return event.data &&
|
|
1302
1261
|
typeof event.data === "object" &&
|
|
1303
1262
|
!Array.isArray(event.data)
|
|
@@ -1313,10 +1272,10 @@ function formatBodyPreview(body: unknown): string {
|
|
|
1313
1272
|
return `\nBody: ${compact.length > 500 ? `${compact.slice(0, 500)}…` : compact}`;
|
|
1314
1273
|
}
|
|
1315
1274
|
|
|
1316
|
-
export function
|
|
1317
|
-
if (event.
|
|
1275
|
+
export function formatRunAttentionMessage(event: RunAttentionEvent): string {
|
|
1276
|
+
if (event.kind === "command.done")
|
|
1318
1277
|
return `Run ${event.run}: ${event.summary}`;
|
|
1319
|
-
return `Run ${event.run}: ${event.summary}${formatBodyPreview(event.body)}${formatNamedArtifacts(
|
|
1278
|
+
return `Run ${event.run}: ${event.summary}${formatBodyPreview(event.body)}${formatNamedArtifacts(getAttentionDataField(event, "artifacts"))}${formatRunFileList(getAttentionDataField(event, "run_files"))}`;
|
|
1320
1279
|
}
|
|
1321
1280
|
|
|
1322
1281
|
export function getRunTransitionNotificationType(
|
package/lib/prompts.ts
CHANGED
|
@@ -22,13 +22,13 @@ export const REGISTER_TOOL_GUIDELINES = [
|
|
|
22
22
|
export const ONBOARDING_SYSTEM_PROMPT = `pi-actors quick model:
|
|
23
23
|
- Local-first actor memory: persist trusted local capabilities instead of rebuilding shell recipes.
|
|
24
24
|
- Layers: task -> command template -> recipe/tool -> spawn -> run:<id>; tool:<name> wraps registered capabilities.
|
|
25
|
-
- Command templates stay sync and shell-free: string leaves split into executable + argv,
|
|
25
|
+
- 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.
|
|
26
26
|
- Placeholders support typed/default args plus {value??fallback} and {flag?yes:no}.
|
|
27
27
|
- ~/.pi/agent/recipes/*.json is actor muscle memory: every recipe there is auto-registered as an agent tool across sessions; register_tool writes there.
|
|
28
|
-
- Recipes own template directly and may declare metadata/defaults/imports/
|
|
28
|
+
- Recipes own template directly and may declare metadata/defaults/imports/control/artifacts; files >1 MiB or import depth >32 fail closed.
|
|
29
29
|
- Recipe imports are local variables; imported recipes are definitions, not nested async runs; parent async:true creates one run.
|
|
30
30
|
- 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.
|
|
31
|
-
- Use spawn/message/inspect for actor-level start/send/observe; short foreground checks can stay ordinary tools/templates; avoid
|
|
31
|
+
- 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.
|
|
32
32
|
- 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.
|
|
33
33
|
- 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.
|
|
34
34
|
- 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.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recipe Control contract.
|
|
3
|
+
* Zones: actor-local action declarations, normalization, reserved-action fencing
|
|
4
|
+
* Owns pure Recipe control validation; Recipe loading and Run capture stay in recipe/run domains.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as Control from "./control.ts";
|
|
8
|
+
import * as Limits from "./limits.ts";
|
|
9
|
+
|
|
10
|
+
const RUNTIME_RUN_ACTIONS = new Set(["archive", "kill", "prune"]);
|
|
11
|
+
|
|
12
|
+
export function normalizeRecipeControl(value: unknown): string[] | undefined {
|
|
13
|
+
if (value === undefined) return undefined;
|
|
14
|
+
if (!Array.isArray(value)) {
|
|
15
|
+
throw new Error("recipe.control must be an array of action strings");
|
|
16
|
+
}
|
|
17
|
+
const actions: string[] = [];
|
|
18
|
+
const seen = new Set<string>();
|
|
19
|
+
for (const raw of value) {
|
|
20
|
+
if (typeof raw !== "string" || !raw.trim()) {
|
|
21
|
+
throw new Error("recipe.control actions must be non-empty strings");
|
|
22
|
+
}
|
|
23
|
+
const action = raw.trim();
|
|
24
|
+
if (!Control.isControlAction(action)) {
|
|
25
|
+
throw new Error(`invalid recipe.control action: ${action}`);
|
|
26
|
+
}
|
|
27
|
+
if (action.length > Limits.CONTROL_ACTION_MAX_LENGTH) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`recipe.control action exceeds ${Limits.CONTROL_ACTION_MAX_LENGTH} ASCII characters: ${action}`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
if (RUNTIME_RUN_ACTIONS.has(action)) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`recipe.control action is runtime-reserved and must not be declared: ${action}`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
if (seen.has(action)) {
|
|
38
|
+
throw new Error(`duplicate recipe.control action: ${action}`);
|
|
39
|
+
}
|
|
40
|
+
seen.add(action);
|
|
41
|
+
actions.push(action);
|
|
42
|
+
}
|
|
43
|
+
return actions;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function assertRecipeHasNoMailbox(recipe: Record<string, unknown>): void {
|
|
47
|
+
if (Object.hasOwn(recipe, "mailbox")) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"recipe.mailbox was removed; replace it with control: [\"action\"] for actor-local inputs and emit Trace events for outputs",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
package/lib/recipes-discovery.ts
CHANGED
|
@@ -503,6 +503,8 @@ function diagnosticSuggestedAction(message: string): string {
|
|
|
503
503
|
if (/cyclic/i.test(message)) return "break the import cycle";
|
|
504
504
|
if (/exceeds.*size/i.test(message))
|
|
505
505
|
return "split large prompt or data into separate files";
|
|
506
|
+
if (/recipe\.mailbox was removed/i.test(message))
|
|
507
|
+
return "replace mailbox.accepts with control actions and route outputs to Trace events";
|
|
506
508
|
if (/repeat must/i.test(message))
|
|
507
509
|
return "use a positive repeat count or an array-typed repeat source";
|
|
508
510
|
if (/shadows/i.test(message))
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
} from "./command-templates.ts";
|
|
15
15
|
import * as CommandTemplates from "./command-templates.ts";
|
|
16
16
|
import * as Paths from "./paths.ts";
|
|
17
|
+
import * as RecipeControl from "./recipe-control.ts";
|
|
17
18
|
|
|
18
19
|
const MAX_RECIPE_FILE_BYTES = 1024 * 1024;
|
|
19
20
|
const MAX_RECIPE_IMPORT_DEPTH = 32;
|
|
@@ -26,23 +27,6 @@ export interface TemplateRecipeImportBinding {
|
|
|
26
27
|
|
|
27
28
|
export type TemplateRecipeImport = string | TemplateRecipeImportBinding;
|
|
28
29
|
|
|
29
|
-
export type TemplateRecipeMailboxEntry =
|
|
30
|
-
| string
|
|
31
|
-
| {
|
|
32
|
-
type: string;
|
|
33
|
-
body_schema?: unknown;
|
|
34
|
-
ack?: boolean | string;
|
|
35
|
-
idempotency?: string;
|
|
36
|
-
requires_response?: boolean;
|
|
37
|
-
level?: string;
|
|
38
|
-
summary?: string;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export interface TemplateRecipeMailbox {
|
|
42
|
-
accepts?: TemplateRecipeMailboxEntry[];
|
|
43
|
-
emits?: TemplateRecipeMailboxEntry[];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
30
|
export interface TemplateRecipeDefinition {
|
|
47
31
|
name?: string;
|
|
48
32
|
description?: string;
|
|
@@ -61,7 +45,7 @@ export interface TemplateRecipeDefinition {
|
|
|
61
45
|
accept_output?: "review_evidence";
|
|
62
46
|
output?: string;
|
|
63
47
|
artifacts?: Record<string, string>;
|
|
64
|
-
|
|
48
|
+
control?: string[];
|
|
65
49
|
retire_when?: "children_terminal";
|
|
66
50
|
retry?: number | string;
|
|
67
51
|
failure?: CommandTemplates.CommandTemplateFailureScope;
|
|
@@ -912,6 +896,7 @@ export function readResolvedRecipeConfig(
|
|
|
912
896
|
}
|
|
913
897
|
const raw = readRawRecipeConfig(path);
|
|
914
898
|
if (!raw || !Object.hasOwn(raw, "template")) return undefined;
|
|
899
|
+
RecipeControl.assertRecipeHasNoMailbox(raw);
|
|
915
900
|
const imports: Record<string, ImportedRecipe> = {};
|
|
916
901
|
for (const [alias, binding] of Object.entries(getRecipeImports(raw))) {
|
|
917
902
|
const importPath = resolveRecipeImportPath(
|
|
@@ -975,9 +960,11 @@ export function readResolvedRecipeConfig(
|
|
|
975
960
|
const artifactSource = isRecord(substituted.artifacts)
|
|
976
961
|
? substituted.artifacts
|
|
977
962
|
: delegated?.artifacts;
|
|
978
|
-
const
|
|
979
|
-
|
|
980
|
-
|
|
963
|
+
const control = RecipeControl.normalizeRecipeControl(
|
|
964
|
+
Object.hasOwn(substituted, "control")
|
|
965
|
+
? substituted.control
|
|
966
|
+
: delegated?.control,
|
|
967
|
+
);
|
|
981
968
|
return {
|
|
982
969
|
name: recipeName,
|
|
983
970
|
...(typeof substituted.description === "string" &&
|
|
@@ -1052,30 +1039,7 @@ export function readResolvedRecipeConfig(
|
|
|
1052
1039
|
),
|
|
1053
1040
|
}
|
|
1054
1041
|
: {}),
|
|
1055
|
-
...(
|
|
1056
|
-
? {
|
|
1057
|
-
mailbox: {
|
|
1058
|
-
...(Array.isArray(mailboxSource.accepts)
|
|
1059
|
-
? {
|
|
1060
|
-
accepts: mailboxSource.accepts.filter(
|
|
1061
|
-
(value): value is TemplateRecipeMailboxEntry =>
|
|
1062
|
-
typeof value === "string" ||
|
|
1063
|
-
(isRecord(value) && typeof value.type === "string"),
|
|
1064
|
-
),
|
|
1065
|
-
}
|
|
1066
|
-
: {}),
|
|
1067
|
-
...(Array.isArray(mailboxSource.emits)
|
|
1068
|
-
? {
|
|
1069
|
-
emits: mailboxSource.emits.filter(
|
|
1070
|
-
(value): value is TemplateRecipeMailboxEntry =>
|
|
1071
|
-
typeof value === "string" ||
|
|
1072
|
-
(isRecord(value) && typeof value.type === "string"),
|
|
1073
|
-
),
|
|
1074
|
-
}
|
|
1075
|
-
: {}),
|
|
1076
|
-
},
|
|
1077
|
-
}
|
|
1078
|
-
: {}),
|
|
1042
|
+
...(control !== undefined ? { control } : {}),
|
|
1079
1043
|
...(substituted.retire_when === "children_terminal" ||
|
|
1080
1044
|
delegated?.retire_when === "children_terminal"
|
|
1081
1045
|
? { retire_when: "children_terminal" as const }
|
package/lib/review-control.ts
CHANGED
|
@@ -124,14 +124,13 @@ export function controlAutomaticReview(
|
|
|
124
124
|
return {
|
|
125
125
|
...result,
|
|
126
126
|
next_actions: nextActions,
|
|
127
|
-
sent: result.changed === true,
|
|
128
127
|
};
|
|
129
128
|
}
|
|
130
129
|
|
|
131
|
-
export function parseAutomaticReviewScope(
|
|
132
|
-
const record =
|
|
133
|
-
?
|
|
130
|
+
export function parseAutomaticReviewScope(input: unknown): AutomaticReviewScope {
|
|
131
|
+
const record = input && typeof input === "object" && !Array.isArray(input)
|
|
132
|
+
? input as Record<string, unknown>
|
|
134
133
|
: {};
|
|
135
134
|
if (record.scope === "draft" || record.scope === "tool") return record.scope;
|
|
136
|
-
throw new Error("review
|
|
135
|
+
throw new Error("review Control requires input.scope=draft or input.scope=tool.");
|
|
137
136
|
}
|
package/lib/review-projection.ts
CHANGED
|
@@ -87,17 +87,13 @@ function templateShape(value: unknown): Record<string, unknown> {
|
|
|
87
87
|
|
|
88
88
|
function contractShape(recipe: Record<string, unknown> | undefined): Record<string, unknown> | undefined {
|
|
89
89
|
if (!recipe) return undefined;
|
|
90
|
-
const mailbox = recipe.mailbox && typeof recipe.mailbox === "object" && !Array.isArray(recipe.mailbox)
|
|
91
|
-
? recipe.mailbox as Record<string, unknown>
|
|
92
|
-
: {};
|
|
93
90
|
return {
|
|
94
91
|
argument_count: countArray(recipe.args),
|
|
95
92
|
artifact_count: countRecord(recipe.artifacts),
|
|
96
93
|
async: recipe.async === true,
|
|
97
94
|
default_count: countRecord(recipe.defaults),
|
|
98
95
|
import_count: countRecord(recipe.imports),
|
|
99
|
-
|
|
100
|
-
mailbox_emits_count: countArray(mailbox.emits),
|
|
96
|
+
control_action_count: countArray(recipe.control),
|
|
101
97
|
template_shape: templateShape(recipe.template),
|
|
102
98
|
};
|
|
103
99
|
}
|
package/lib/run-ui-runtime.ts
CHANGED
|
@@ -38,7 +38,7 @@ export function createRunUiRuntime(deps: RunUiRuntimeDeps): RunUiRuntime {
|
|
|
38
38
|
attempted: retirementAttempts,
|
|
39
39
|
cancelRun: (candidate) => AsyncRuns.cancelRun(candidate.stateDir),
|
|
40
40
|
notify: (message, level) => ctx.ui.notify(message, level),
|
|
41
|
-
sendStop: (candidate) => AsyncRuns.
|
|
41
|
+
sendStop: async (candidate) => AsyncRuns.cancelRun(candidate.stateDir),
|
|
42
42
|
});
|
|
43
43
|
};
|
|
44
44
|
const update = (
|
|
@@ -62,7 +62,7 @@ export function createRunUiRuntime(deps: RunUiRuntimeDeps): RunUiRuntime {
|
|
|
62
62
|
);
|
|
63
63
|
Observability.pruneRunUiObservationState(observation, snapshot);
|
|
64
64
|
if (!terminalOnly) {
|
|
65
|
-
Observability.
|
|
65
|
+
Observability.deliverRunAttentionNotifications(snapshot.attentionEvents, sink);
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
68
|
const reportDiagnostics = (ctx: Pi.ExtensionContext): void => {
|