@llblab/pi-actors 0.41.1 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +11 -6
- package/BACKLOG.md +2 -62
- package/CHANGELOG.md +15 -0
- package/README.md +22 -4
- package/dist/index.js +25 -121
- package/dist/lib/async-runs.d.ts +25 -5
- package/dist/lib/async-runs.js +136 -47
- package/dist/lib/automatic-review-runtime.d.ts +18 -0
- package/dist/lib/automatic-review-runtime.js +96 -0
- package/dist/lib/draft-consolidation-transaction.d.ts +65 -0
- package/dist/lib/draft-consolidation-transaction.js +610 -0
- package/dist/lib/draft-consolidation.d.ts +35 -0
- package/dist/lib/draft-consolidation.js +126 -0
- package/dist/lib/draft-review.d.ts +56 -0
- package/dist/lib/draft-review.js +254 -0
- package/dist/lib/draft-sleep.d.ts +65 -0
- package/dist/lib/draft-sleep.js +468 -0
- package/dist/lib/file-state.d.ts +8 -1
- package/dist/lib/file-state.js +115 -18
- package/dist/lib/inspector-actions.d.ts +16 -0
- package/dist/lib/inspector-actions.js +57 -0
- package/dist/lib/inspector-command.d.ts +7 -0
- package/dist/lib/inspector-command.js +37 -0
- package/dist/lib/inspector-overlay.d.ts +20 -3
- package/dist/lib/inspector-overlay.js +275 -74
- package/dist/lib/inspector.d.ts +9 -0
- package/dist/lib/inspector.js +48 -0
- package/dist/lib/observability.d.ts +1 -0
- package/dist/lib/observability.js +11 -1
- package/dist/lib/paths.d.ts +7 -0
- package/dist/lib/paths.js +28 -0
- package/dist/lib/recipes-discovery.js +32 -24
- package/dist/lib/recipes-usage.d.ts +18 -6
- package/dist/lib/recipes-usage.js +445 -34
- package/dist/lib/review-control.d.ts +14 -0
- package/dist/lib/review-control.js +111 -0
- package/dist/lib/review-diagnostics.d.ts +11 -0
- package/dist/lib/review-diagnostics.js +148 -0
- package/dist/lib/review-projection.d.ts +14 -0
- package/dist/lib/review-projection.js +170 -0
- package/dist/lib/run-ui-runtime.d.ts +18 -0
- package/dist/lib/run-ui-runtime.js +123 -0
- package/dist/lib/runs-artifacts.d.ts +1 -1
- package/dist/lib/runs-artifacts.js +1 -1
- package/dist/lib/runs-control.d.ts +8 -2
- package/dist/lib/runs-control.js +23 -6
- package/dist/lib/runs-identity.d.ts +1 -1
- package/dist/lib/runs-identity.js +1 -1
- package/dist/lib/runs-index.d.ts +11 -2
- package/dist/lib/runs-index.js +46 -23
- package/dist/lib/runs-mailbox.d.ts +1 -1
- package/dist/lib/runs-mailbox.js +1 -1
- package/dist/lib/runs-messages.d.ts +1 -1
- package/dist/lib/runs-messages.js +1 -1
- package/dist/lib/runs-outbox.d.ts +1 -1
- package/dist/lib/runs-outbox.js +1 -1
- package/dist/lib/runs-ownership.d.ts +1 -1
- package/dist/lib/runs-ownership.js +1 -1
- package/dist/lib/runs-parent-teardown.d.ts +51 -0
- package/dist/lib/runs-parent-teardown.js +172 -0
- package/dist/lib/runs-process.d.ts +1 -1
- package/dist/lib/runs-process.js +1 -1
- package/dist/lib/runs-retention.d.ts +1 -1
- package/dist/lib/runs-retention.js +1 -1
- package/dist/lib/runs-start.d.ts +5 -3
- package/dist/lib/runs-start.js +6 -48
- package/dist/lib/runs-status.d.ts +5 -3
- package/dist/lib/runs-status.js +4 -6
- package/dist/lib/runtime.d.ts +7 -1
- package/dist/lib/runtime.js +32 -18
- package/dist/lib/tool-review-lineage-transaction.d.ts +27 -0
- package/dist/lib/tool-review-lineage-transaction.js +597 -0
- package/dist/lib/tool-review-lineage.d.ts +24 -0
- package/dist/lib/tool-review-lineage.js +98 -0
- package/dist/lib/tool-review-scheduler.d.ts +80 -0
- package/dist/lib/tool-review-scheduler.js +494 -0
- package/dist/lib/tool-review-transaction.d.ts +50 -0
- package/dist/lib/tool-review-transaction.js +362 -0
- package/dist/lib/tool-review.d.ts +56 -0
- package/dist/lib/tool-review.js +197 -0
- package/dist/lib/tools-inspect.js +26 -3
- package/dist/lib/tools-local.js +4 -2
- package/dist/lib/tools-message.d.ts +1 -0
- package/dist/lib/tools-message.js +29 -17
- package/dist/lib/tools-spawn.js +4 -1
- package/dist/lib/tools.d.ts +1 -0
- package/dist/lib/tools.js +1 -0
- package/dist/recipes/draft-review.json +24 -0
- package/dist/recipes/tool-review.json +24 -0
- package/dist/scripts/release-gates.mjs +165 -0
- package/dist/skills/actors/SKILL.md +9 -8
- package/dist/skills/swarm/SKILL.md +1 -1
- package/docs/actor-inspector.md +20 -11
- package/docs/async-runs.md +9 -1
- package/docs/recipe-library.md +7 -3
- package/docs/template-recipes.md +4 -11
- package/docs/tool-registry.md +11 -4
- package/index.ts +27 -142
- package/lib/async-runs.ts +218 -62
- package/lib/automatic-review-runtime.ts +135 -0
- package/lib/draft-consolidation-transaction.ts +821 -0
- package/lib/draft-consolidation.ts +181 -0
- package/lib/draft-review.ts +325 -0
- package/lib/draft-sleep.ts +576 -0
- package/lib/file-state.ts +143 -19
- package/lib/inspector-actions.ts +79 -0
- package/lib/inspector-command.ts +54 -0
- package/lib/inspector-overlay.ts +325 -91
- package/lib/inspector.ts +72 -0
- package/lib/observability.ts +14 -1
- package/lib/paths.ts +43 -0
- package/lib/recipes-discovery.ts +34 -26
- package/lib/recipes-usage.ts +569 -40
- package/lib/review-control.ts +137 -0
- package/lib/review-diagnostics.ts +164 -0
- package/lib/review-projection.ts +200 -0
- package/lib/run-ui-runtime.ts +153 -0
- package/lib/runs-artifacts.ts +1 -1
- package/lib/runs-control.ts +49 -5
- package/lib/runs-identity.ts +1 -1
- package/lib/runs-index.ts +57 -21
- package/lib/runs-mailbox.ts +1 -1
- package/lib/runs-messages.ts +1 -1
- package/lib/runs-outbox.ts +1 -1
- package/lib/runs-ownership.ts +1 -1
- package/lib/runs-parent-teardown.ts +257 -0
- package/lib/runs-process.ts +1 -1
- package/lib/runs-retention.ts +1 -1
- package/lib/runs-start.ts +12 -68
- package/lib/runs-status.ts +12 -8
- package/lib/runtime.ts +34 -17
- package/lib/tool-review-lineage-transaction.ts +881 -0
- package/lib/tool-review-lineage.ts +145 -0
- package/lib/tool-review-scheduler.ts +635 -0
- package/lib/tool-review-transaction.ts +563 -0
- package/lib/tool-review.ts +270 -0
- package/lib/tools-inspect.ts +33 -3
- package/lib/tools-local.ts +8 -2
- package/lib/tools-message.ts +45 -30
- package/lib/tools-spawn.ts +8 -1
- package/lib/tools.ts +5 -0
- package/package.json +3 -2
- package/recipes/draft-review.json +24 -0
- package/recipes/tool-review.json +24 -0
- package/scripts/release-gates.mjs +165 -0
- package/skills/actors/SKILL.md +9 -8
- package/skills/swarm/SKILL.md +1 -1
package/docs/recipe-library.md
CHANGED
|
@@ -13,14 +13,16 @@ Helper scripts that belong to library recipes live in root `scripts/`. The music
|
|
|
13
13
|
|
|
14
14
|
## Install Locally
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Select only the operator-facing recipe or wrapper you intend to own locally. For example:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
mkdir -p ~/.pi/agent/recipes
|
|
20
|
-
cp <repo>/recipes
|
|
20
|
+
cp <repo>/recipes/pipeline-review-readiness.json ~/.pi/agent/recipes/
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Do not bulk-copy `recipes/*.json`. The packaged library also contains internal composition stages, including `draft-review.json` and `tool-review.json`; the automatic-review runtime launches those selectors with fenced inputs and they must not become user-installed callable tools.
|
|
24
|
+
|
|
25
|
+
A registered tool can instead point at one selected recipe path when a durable operator-facing name is useful. Prefer a thin wrapper for public defaults or policy rather than copying the wrapper's internal imports.
|
|
24
26
|
|
|
25
27
|
## Async Subagent Components
|
|
26
28
|
|
|
@@ -32,6 +34,8 @@ Core subagent recipes:
|
|
|
32
34
|
- `recipes/subagent-preflight.json`: Tiny model/thinking/tool-policy smoke check before expensive fanout; failures surface `ACTOR_PREFLIGHT_FAILED` with stage, selected policy, provider error class, prompt file, and override args.
|
|
33
35
|
- Packaged reviewer, verifier, merger, judge, and normalizer stages use `accept_output: review_evidence` and require `ACTOR_REVIEW_RESULT` as the exact first non-whitespace output line. Marker prefixes, format acknowledgements, and input requests therefore remain rejected branch diagnostics rather than usable quorum evidence.
|
|
34
36
|
- `recipes/subagent-review.json`: Evidence-grounded review lens.
|
|
37
|
+
- `recipes/draft-review.json`: Internal no-tools selector for one immutable automatic draft batch. It receives an attached value-free structural projection with batch-local opaque occurrence/content-group identities, counts, risk labels, and usage—not canonical names, draft basenames, raw hashes, recipe bodies, template text, defaults, authored prose, or filesystem paths—then emits one terminal `DRAFT_REVIEW_RESULT` with quota-free promote/discard decisions. The executor derives any promotion from the separate trusted captured source.
|
|
38
|
+
- `recipes/tool-review.json`: Internal no-tools selector for one immutable 36-tool portfolio. It receives the same identity-opaque value-free structural projection and may recommend quota-free keep, unchanged-source rename (`evolve`), unchanged-source demote, or identical-source merge decisions. `replace`, `split`, and returned recipe content fail mechanically; deterministic executors alone read trusted captured recipes and own validated safe-boundary activation.
|
|
35
39
|
- `recipes/subagent-critic.json`: Assumption and failure-mode critique.
|
|
36
40
|
- `recipes/subagent-plan.json`: Bounded plan slices and validation gates.
|
|
37
41
|
- `recipes/subagent-evidence-map.json`: Evidence and confidence map.
|
package/docs/template-recipes.md
CHANGED
|
@@ -107,20 +107,13 @@ The high-priority user recipe directory is also the default tool set: recipes pl
|
|
|
107
107
|
|
|
108
108
|
Higher-priority files shadow lower-priority files with the same basename. Within one priority layer, same-id JSON shadows Markdown because JSON is the canonical precise format. A highest-priority invalid recipe is still visible and blocks fallback so operators do not accidentally run packaged behavior when a user override is broken. A highest-priority recipe with `disabled: true` also blocks fallback, is not launchable, and intentionally disables that id. Healthy overrides are silent; failed bare-name launches caused by invalid or disabled shadowing include compact `reason=shadowed_invalid` or `reason=shadowed_disabled` diagnostics with the active path, blocked candidate, and recipe-doctor hint.
|
|
109
109
|
|
|
110
|
-
## Usage Metadata
|
|
110
|
+
## Usage And Lineage Metadata
|
|
111
111
|
|
|
112
|
-
User-owned recipe launches
|
|
112
|
+
User-owned recipe launches update extension-maintained lineage ledgers under `.usage/recipes/<recipe-name>.json` plus a path index. Authored recipes remain untouched. The ledger keeps lifetime and revision-local launch counts, executable fingerprints, former names and paths, bounded revision ancestry, transition events, and review epochs.
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
{
|
|
116
|
-
"calls": 12,
|
|
117
|
-
"last_called": "2026-05-22T10:30:00.000Z"
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
The extension increments `calls` and updates `last_called` when it starts that concrete recipe, either through a recipe-backed tool call or a direct async recipe-file run. The sidecar also stores a content `fingerprint`; if authored recipe content changes, the next launch resets `calls` before counting the new launch and records `reset_at`. Keeping telemetry outside the recipe prevents usage writes from replacing concurrent operator edits; discovery merges sidecar usage into inspection. Agents should treat these fields as cleanup evidence, not as authored recipe contract. Packaged standard-library recipes do not receive usage metadata.
|
|
114
|
+
Lifetime usage survives rename, promotion, demotion, and executable revision. Revision-local counters restart when executable content changes, making the new fingerprint eligible for portfolio review without erasing prior evidence. Discovery merges current lineage evidence into inspection; packaged standard-library recipes receive no mutable usage ledger. The unreleased format stays intentionally unversioned until a public compatibility boundary exists.
|
|
122
115
|
|
|
123
|
-
There is intentionally no failure counter
|
|
116
|
+
There is intentionally no failure counter: a failed launch can reflect caller misuse, missing values, or environment state rather than recipe quality. Usage remains evidence, not an automatic usefulness verdict. Automatic review combines it with contract quality, portability, duplication, safety, and likely future value. `register_tool draft=...` is the preferred fenced single-draft override; a deliberate move/copy from `drafts/` into the recipe root also remains valid, though it may defer an already captured automatic batch.
|
|
124
117
|
|
|
125
118
|
For object form, keep `template` last. Recipe metadata comes first; executable content stays last.
|
|
126
119
|
|
package/docs/tool-registry.md
CHANGED
|
@@ -10,13 +10,15 @@ The registry source is location-discovered recipes, not a live tool-only JSON fi
|
|
|
10
10
|
|
|
11
11
|
- `~/.pi/agent/recipes/*.json` and `*.md` are the highest-priority user recipe root and the operator-managed tool set.
|
|
12
12
|
- Recipes in that root are tools by location.
|
|
13
|
-
- `~/.pi/agent/recipes/drafts/*.json` stores captured inline-spawn draft recipes, not registered tools. Promote one with `register_tool name=<tool_name> draft=<draft_path>` or
|
|
13
|
+
- `~/.pi/agent/recipes/drafts/*.json` stores captured inline-spawn draft recipes, not registered tools. Twelve drafts trigger one silent automatic exact-batch review after the foreground turn and active actors finish; the deterministic executor promotes or discards every reviewed source while preserving newer drafts for the next batch. Promote one earlier with the fenced `register_tool name=<tool_name> draft=<draft_path>` override or a deliberate move/copy into the recipe root. A direct filesystem promotion remains legitimate, but it can shrink or invalidate a captured batch and defer its automatic cleanup; lineage reattaches on the next launch when the move remains unambiguous. No manual batch-consolidation command exists. `inspect target=recipes view=summary` reports draft count, and verbose output lists paths, timestamps, fingerprints, validation state, source run when known, descriptions, and template previews.
|
|
14
14
|
- Packaged pi-actors recipes are the lower-priority standard library of declarative actor config components, not automatically registered tools.
|
|
15
15
|
- Ad hoc recipe files outside the user recipe root are components unless explicitly registered/copied into `~/.pi/agent/recipes`.
|
|
16
|
-
-
|
|
16
|
+
- The current tool name is the filename basename; `~/.pi/agent/recipes/docs_review.json` and `docs_review.md` both expose `docs_review`. A canonical name-and-priority lineage ledger preserves usage and revision history as draft/active location changes; controlled rename transfers that history to the new name and retains the former name.
|
|
17
|
+
- Set `PI_ACTORS_AUTOMATIC_REVIEW=off` (also accepts `false` or `0`) before starting Pi to disable draft/tool reviewer scheduling and safe-boundary portfolio activation; runtime status exposes the effective policy.
|
|
18
|
+
- Active user recipes receive zero-call lineage without fabricating launches. Once thirty-six non-sensitive current revisions lack a review fingerprint, pi-actors captures the oldest exact portfolio and silently attaches an identity-opaque value-free structural projection with batch-local equality-only content groups to the no-tools `tool-review` actor after a foreground turn and only while no other actor runs. A content revision resets revision-local usage and becomes eligible again while lifetime usage remains continuous. The reviewer may select only `keep`, unchanged-source rename (`evolve`), unchanged-source `demote`, or `merge` for canonically identical captured recipes; it never returns recipe content. `replace`, `split`, and executable contract changes require explicit operator authoring. Completed output becomes an immutable size-bounded approval plan only after exact result, source-hash, target-collision, and lineage-projection validation; approval itself never mutates active recipes. At the next `session_start`, filesystem commit persists `lineage_pending`, journaled lineage records roll forward, `completed` persists, and only then may quarantine be removed before runtime tool discovery.
|
|
17
19
|
- Same-id JSON shadows Markdown in the same priority layer.
|
|
18
20
|
|
|
19
|
-
Because the user recipe directory is sticky agent muscle memory, runtime launches update
|
|
21
|
+
Because the user recipe directory is sticky agent muscle memory, runtime launches update a stable lineage ledger under `.usage/recipes/<recipe-name>.json` plus a priority-compatible path index rather than rewriting authored recipe files. Launch accounting briefly shares the canonical recipe-root fence used by portfolio activation before taking index/ledger locks; activation therefore cannot quarantine a source between launch authorization and accounting. If activation already changed the loaded source, the stale invocation rejects with a reload-and-retry error instead of executing without usage evidence. `lifetime_calls` and the compatibility `calls` view survive rename, promotion, demotion, and content revision; `revision_calls` restarts only when the executable fingerprint changes. The bounded ledger retains former paths/names, revision ancestry, promotion/demotion events, and review epochs. An unambiguous external rename follows its prior lineage by fingerprint. Because automatic review has not shipped publicly, its inputs, results, admission state, plans, journals, evidence, lineage storage, and snapshots remain unversioned rather than carrying migration branches for discarded internal iterations. Discovery and file-watcher refresh merge ledger usage into inspect summaries. `inspect target=recipes view=summary verbose=true` includes usage metadata and operator-gated cleanup recommendations for invalid, shadowed, disabled, component-only, unused, or overriding recipes. The extension does not maintain a failure counter.
|
|
20
22
|
|
|
21
23
|
`register_tool` is the preferred agent-facing mutation API. It creates, updates, and deletes recipe files in `~/.pi/agent/recipes`; agents do not need to edit the files directly for normal registration. Extension-authored register, update, delete, draft-promotion, and usage-metadata mutations hold a cross-process lock keyed by filesystem-canonical recipe identity across the complete check/read/write/runtime-update window. Existing targets or the nearest existing parent are resolved through `realpath`, so real and symlink aliases serialize while unrelated recipes remain independent; stale locks are reclaimed only after their owner is proven dead. Direct file edits are still valid for operators and advanced agents. Runtime behavior is reactive: file creation, deletion, or edits in the user recipe root trigger validation and tool-set refresh, with invalid recipes surfaced as diagnostics rather than silently ignored. If the recipe root does not exist at session start, an advisory parent watcher detects its creation and switches to the normal root watcher; deletion or rename rearms the parent watcher without polling.
|
|
22
24
|
|
|
@@ -27,10 +29,15 @@ inspect target=tool:pi-actors view=status
|
|
|
27
29
|
inspect target=tool:pi-actors view=triage
|
|
28
30
|
inspect target=recipes view=status
|
|
29
31
|
inspect target=recipes view=doctor
|
|
32
|
+
inspect target=recipes view=reviews
|
|
30
33
|
inspect target=recipes view=summary verbose=true
|
|
31
34
|
```
|
|
32
35
|
|
|
33
|
-
`
|
|
36
|
+
`inspect target=recipes view=reviews` returns bounded read-only evidence for automatic draft/tool review phases, decision counts, garbage collection, lineage revisions, demotions, rollback provenance, retained revision snapshots, and bounded `failed_stage`/`last_error`/`next_action` fields. It never starts a review or generates a follow-up turn. Automatic reviewers receive only an attached value-free projection—counts, risk labels, bounded usage, and command-graph shape without recipe bodies, template/default values, authored prose, or filesystem paths—and no general filesystem or mutation tools. Internal snapshot rollback writes one CAS-authenticated journal before changing either recipe or lineage state; interruption after either write rolls forward on the next identical rollback request instead of returning a permanently split recipe/ledger state.
|
|
37
|
+
|
|
38
|
+
Explicit recovery stays inside the existing actor-message surface: send `review.retry` or `review.reset` to `tool:pi-actors` with `body={"scope":"draft"}` or `body={"scope":"tool"}`. Retry resets bounded launch/processing counters and reuses the immutable batch. If a draft transaction journal already exists, retry preserves the original reviewer run and resumes that authenticated journal plan; even changed reviewer stdout cannot redirect committed recipe or lineage targets. When a tool transaction already committed, retry preserves approval/transaction evidence and returns to the safe activation/lineage boundary rather than launching another reviewer. Reset removes only disposable failed/completed admission state and rejects tool cycles that still carry recovery evidence.
|
|
39
|
+
|
|
40
|
+
`tool:pi-actors` is a reserved runtime-status/control actor. `view=status` reports the loaded package version, package root, source/dist mode, entrypoint path, recipe roots, automatic-review policy, and git commit when available. Use it after reloads to confirm which extension code is actually live. `view=triage` adds a compact attention surface for active runs, other-session runs, invalid or blocking recipes, exposed tool recipes with non-lifecycle risk labels, drafts, stale claims, failed runs, attention messages, and next inspect actions without repairing anything. Packaged components and recipes whose only label is `risk.long_running` stay in recipe doctor/summary evidence rather than triage attention.
|
|
34
41
|
|
|
35
42
|
The recipe summary reports active, shadowed, invalid, disabled, and diagnostic entries so operators can answer why a tool is present, hidden, broken, or disabled. The doctor view keeps the same registry evidence but promotes an advisory action surface: compact output includes the highest-priority `top` remediation, risk-label counts, and ordered actions for invalid/blocking, disabled, risky shell-boundary, and shadowed recipes. Verbose inspection keeps per-recipe `risk_labels`, the structured `risk_summary`, `remediations`, `top_action`, diagnostic details, and blocked lower-priority fallback paths when a broken or disabled higher-priority recipe masks a fallback. Risk labels are deterministic review aids, not execution blockers or sandbox claims.
|
|
36
43
|
|
package/index.ts
CHANGED
|
@@ -5,118 +5,32 @@
|
|
|
5
5
|
* Wraps command templates as callable pi tools, stores durable user tools as recipe files, and exposes actor orchestration across reloads and sessions.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import * as
|
|
8
|
+
import * as AutomaticReviewRuntime from "./lib/automatic-review-runtime.ts";
|
|
9
9
|
import * as CommandTemplates from "./lib/command-templates.ts";
|
|
10
|
-
import * as
|
|
11
|
-
import * as Observability from "./lib/observability.ts";
|
|
10
|
+
import * as InspectorCommand from "./lib/inspector-command.ts";
|
|
12
11
|
import * as Paths from "./lib/paths.ts";
|
|
13
12
|
import * as Pi from "./lib/pi.ts";
|
|
14
13
|
import * as Prompts from "./lib/prompts.ts";
|
|
14
|
+
import * as RunUiRuntime from "./lib/run-ui-runtime.ts";
|
|
15
15
|
import * as Runtime from "./lib/runtime.ts";
|
|
16
16
|
import * as Temp from "./lib/temp.ts";
|
|
17
17
|
import * as Tools from "./lib/tools.ts";
|
|
18
18
|
import * as ToolsResponse from "./lib/tools-response.ts";
|
|
19
19
|
|
|
20
20
|
export default function toolRegistryExtension(pi: Pi.ExtensionAPI) {
|
|
21
|
-
let runsAnimationInterval: NodeJS.Timeout | undefined;
|
|
22
|
-
let runsNotifyTimeout: NodeJS.Timeout | undefined;
|
|
23
21
|
let activeRunContext: Pi.ExtensionContext | undefined;
|
|
24
|
-
let lastRunWatcherDiagnosticId = 0;
|
|
25
|
-
const runUi = Observability.createRunUiObservationState();
|
|
26
|
-
const retirementAttempts = new Set<string>();
|
|
27
|
-
const terminalNotificationsInFlight = new Set<string>();
|
|
28
22
|
const getRunOwnerId = Pi.getSessionId;
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
const updateRunUi = (
|
|
42
|
-
ctx: Pi.ExtensionContext,
|
|
43
|
-
notify = false,
|
|
44
|
-
terminalOnly = false,
|
|
45
|
-
): void => {
|
|
46
|
-
const ownerId = getRunOwnerId(ctx);
|
|
47
|
-
const snapshot = Observability.readRunUiSnapshot(runUi, ownerId);
|
|
48
|
-
ctx.ui.setStatus(
|
|
49
|
-
"zz-pi-actors-runs",
|
|
50
|
-
snapshot.status ? ctx.ui.theme.fg("dim", snapshot.status) : undefined,
|
|
51
|
-
);
|
|
52
|
-
if (!notify) return;
|
|
53
|
-
const notificationSink = Pi.createNotificationSink(pi, ctx);
|
|
54
|
-
retireCandidateRuns(ctx, snapshot.summary);
|
|
55
|
-
Observability.deliverRunTransitionNotifications(
|
|
56
|
-
snapshot.transitions,
|
|
57
|
-
notificationSink,
|
|
58
|
-
terminalNotificationsInFlight,
|
|
59
|
-
);
|
|
60
|
-
Observability.pruneRunUiObservationState(runUi, snapshot);
|
|
61
|
-
if (!terminalOnly) {
|
|
62
|
-
Observability.deliverRunOutboxNotifications(
|
|
63
|
-
snapshot.outboxEvents,
|
|
64
|
-
notificationSink,
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
const closeRunWatchers = (): void => {
|
|
69
|
-
runWatcher.close();
|
|
70
|
-
terminalReconciliation.close();
|
|
71
|
-
if (runsNotifyTimeout) clearTimeout(runsNotifyTimeout);
|
|
72
|
-
runsNotifyTimeout = undefined;
|
|
73
|
-
};
|
|
74
|
-
const reportRunWatcherDiagnostics = (ctx: Pi.ExtensionContext): void => {
|
|
75
|
-
for (const diagnostic of runWatcher.getDiagnostics()) {
|
|
76
|
-
if (diagnostic.id <= lastRunWatcherDiagnosticId) continue;
|
|
77
|
-
lastRunWatcherDiagnosticId = diagnostic.id;
|
|
78
|
-
ctx.ui.notify(
|
|
79
|
-
diagnostic.message,
|
|
80
|
-
diagnostic.code === "rearmed" ? "info" : "warning",
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
const scheduleRunEventUpdate = (): void => {
|
|
85
|
-
if (runsNotifyTimeout) clearTimeout(runsNotifyTimeout);
|
|
86
|
-
runsNotifyTimeout = setTimeout(() => {
|
|
87
|
-
const ctx = activeRunContext;
|
|
88
|
-
if (!ctx) return;
|
|
89
|
-
runWatcher.refresh();
|
|
90
|
-
updateRunUi(ctx, true);
|
|
91
|
-
reportRunWatcherDiagnostics(ctx);
|
|
92
|
-
}, 50);
|
|
93
|
-
runsNotifyTimeout.unref?.();
|
|
94
|
-
};
|
|
95
|
-
const runWatcher = Observability.createRunStateWatcher({
|
|
96
|
-
stateRoot: Paths.EXTENSION_RUNTIME_PATHS.runStateRoot,
|
|
97
|
-
onChange: scheduleRunEventUpdate,
|
|
23
|
+
const automaticReview = AutomaticReviewRuntime.createAutomaticReviewRuntime({
|
|
24
|
+
getActiveContext: () => activeRunContext,
|
|
25
|
+
getRunOwnerId,
|
|
26
|
+
getThinkingLevel: () => pi.getThinkingLevel(),
|
|
27
|
+
});
|
|
28
|
+
const runUiRuntime = RunUiRuntime.createRunUiRuntime({
|
|
29
|
+
getActiveContext: () => activeRunContext,
|
|
30
|
+
getRunOwnerId,
|
|
31
|
+
onRunEvent: automaticReview.schedule,
|
|
32
|
+
pi,
|
|
98
33
|
});
|
|
99
|
-
const terminalReconciliation =
|
|
100
|
-
Observability.createRunTerminalReconciliationLoop({
|
|
101
|
-
onError: (error) => {
|
|
102
|
-
const ctx = activeRunContext;
|
|
103
|
-
if (!ctx) return;
|
|
104
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
105
|
-
ctx.ui.notify(`Actor terminal reconciliation failed: ${message}`, "error");
|
|
106
|
-
},
|
|
107
|
-
reconcile: () => {
|
|
108
|
-
const ctx = activeRunContext;
|
|
109
|
-
if (!ctx) return;
|
|
110
|
-
Observability.reconcileRunTerminalNotifications({
|
|
111
|
-
inFlight: terminalNotificationsInFlight,
|
|
112
|
-
ownerId: getRunOwnerId(ctx),
|
|
113
|
-
sink: Pi.createNotificationSink(pi, ctx),
|
|
114
|
-
state: runUi,
|
|
115
|
-
});
|
|
116
|
-
reportRunWatcherDiagnostics(ctx);
|
|
117
|
-
},
|
|
118
|
-
refreshWatcher: () => runWatcher.refresh(),
|
|
119
|
-
});
|
|
120
34
|
const actorToolDefinitions = new Map<string, Tools.ActorToolDefinition>();
|
|
121
35
|
const withCurrentThinkingContext = <T extends Tools.ActorToolDefinition>(
|
|
122
36
|
definition: T,
|
|
@@ -164,54 +78,26 @@ export default function toolRegistryExtension(pi: Pi.ExtensionAPI) {
|
|
|
164
78
|
// Clear the pre-overlay widget after hot reloads from older pi-actors builds.
|
|
165
79
|
ctx.ui.setWidget("zz-pi-actors-comms", undefined);
|
|
166
80
|
activeRunContext = ctx;
|
|
167
|
-
|
|
81
|
+
runUiRuntime.close();
|
|
82
|
+
automaticReview.close();
|
|
168
83
|
recipeReload.close();
|
|
169
84
|
await Temp.prepareExtensionTempDir(Paths.EXTENSION_RUNTIME_PATHS.tempDir);
|
|
170
85
|
if (activeRunContext !== ctx) return;
|
|
86
|
+
automaticReview.start(ctx);
|
|
171
87
|
runtime.loadTools(ctx);
|
|
172
|
-
|
|
173
|
-
runWatcher.refresh();
|
|
174
|
-
terminalReconciliation.start();
|
|
88
|
+
runUiRuntime.start(ctx);
|
|
175
89
|
recipeReload.watch(ctx);
|
|
176
|
-
if (runsAnimationInterval) clearInterval(runsAnimationInterval);
|
|
177
|
-
runsAnimationInterval = setInterval(() => {
|
|
178
|
-
if (activeRunContext === ctx) updateRunUi(ctx, false);
|
|
179
|
-
}, 1000);
|
|
180
|
-
runsAnimationInterval.unref?.();
|
|
181
90
|
});
|
|
182
|
-
pi.on("
|
|
183
|
-
if (
|
|
184
|
-
|
|
91
|
+
pi.on("agent_end", async (_event, ctx) => {
|
|
92
|
+
if (activeRunContext === ctx) automaticReview.schedule();
|
|
93
|
+
});
|
|
94
|
+
pi.on("session_shutdown", async (event, ctx) => {
|
|
185
95
|
activeRunContext = undefined;
|
|
186
|
-
|
|
96
|
+
automaticReview.close();
|
|
187
97
|
recipeReload.close();
|
|
98
|
+
runUiRuntime.shutdown(event.reason, ctx);
|
|
188
99
|
});
|
|
189
|
-
|
|
190
|
-
description: "Open the keyboard-driven actor inspector overlay",
|
|
191
|
-
handler: async (_args, ctx) => {
|
|
192
|
-
ctx.ui.setWidget("zz-pi-actors-comms", undefined);
|
|
193
|
-
await ctx.ui.custom<void>(
|
|
194
|
-
(tui, theme, _keybindings, done) =>
|
|
195
|
-
new InspectorOverlay.ActorInspectorOverlay({
|
|
196
|
-
done,
|
|
197
|
-
ownerId: getRunOwnerId(ctx),
|
|
198
|
-
stateRoot: Paths.EXTENSION_RUNTIME_PATHS.runStateRoot,
|
|
199
|
-
theme,
|
|
200
|
-
tui,
|
|
201
|
-
}),
|
|
202
|
-
{
|
|
203
|
-
overlay: true,
|
|
204
|
-
overlayOptions: {
|
|
205
|
-
anchor: "center",
|
|
206
|
-
width: "94%",
|
|
207
|
-
minWidth: 72,
|
|
208
|
-
maxHeight: "94%",
|
|
209
|
-
margin: 1,
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
);
|
|
213
|
-
},
|
|
214
|
-
});
|
|
100
|
+
InspectorCommand.registerActorInspectorCommand(pi, getRunOwnerId);
|
|
215
101
|
pi.on("before_agent_start", async (event) => ({
|
|
216
102
|
systemPrompt: `${event.systemPrompt}\n\n${Prompts.ONBOARDING_SYSTEM_PROMPT}`,
|
|
217
103
|
}));
|
|
@@ -221,11 +107,10 @@ export default function toolRegistryExtension(pi: Pi.ExtensionAPI) {
|
|
|
221
107
|
configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
|
|
222
108
|
getActiveTools: () => pi.getActiveTools(),
|
|
223
109
|
getRuntimeTool: (name) =>
|
|
224
|
-
Tools.resolveActiveRuntimeTool(
|
|
225
|
-
|
|
226
|
-
runtime.getTools(),
|
|
227
|
-
(activeName) => actorToolDefinitions.get(activeName),
|
|
110
|
+
Tools.resolveActiveRuntimeTool(name, runtime.getTools(), (activeName) =>
|
|
111
|
+
actorToolDefinitions.get(activeName),
|
|
228
112
|
),
|
|
113
|
+
handleRuntimeMessage: automaticReview.handleMessage,
|
|
229
114
|
registryRuntime: runtime,
|
|
230
115
|
setActiveTools: (toolNames) => pi.setActiveTools(toolNames),
|
|
231
116
|
}).map(withCurrentThinkingContext),
|