@narumitw/pi-subagents 0.52.0 → 0.54.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/README.md +154 -12
- package/package.json +1 -1
- package/src/agents/built-ins.ts +124 -0
- package/src/agents/catalog.ts +224 -0
- package/src/agents/discovery.ts +249 -0
- package/src/agents/types.ts +98 -0
- package/src/agents.ts +47 -665
- package/src/auto-transport.ts +2 -1
- package/src/automation-contract.ts +709 -0
- package/src/automation-planner.ts +65 -0
- package/src/automation.ts +585 -0
- package/src/capability-router.ts +1 -1
- package/src/completion-delivery.ts +2 -3
- package/src/config-status.ts +2 -2
- package/src/config-ui.ts +8 -8
- package/src/consult-resources.ts +1 -1
- package/src/consult.ts +9 -7
- package/src/create-stateful-transport.ts +2 -1
- package/src/cwd-policy.ts +1 -1
- package/src/execution/budget.ts +56 -0
- package/src/execution/runtime-policy.ts +19 -0
- package/src/execution-plan.ts +2 -2
- package/src/execution-profiles.ts +1 -1
- package/src/execution-ui.ts +1 -1
- package/src/execution.ts +269 -100
- package/src/in-process-transport.ts +3 -2
- package/src/inspect.ts +35 -8
- package/src/limits.ts +1 -0
- package/src/orchestration-metrics.ts +12 -5
- package/src/panel-execution.ts +1 -1
- package/src/panel-planning.ts +1 -1
- package/src/params.ts +3 -1
- package/src/persistence.ts +1 -1
- package/src/registry-types.ts +1 -1
- package/src/registry.ts +1 -1
- package/src/render.ts +1 -1
- package/src/retained-semantic-state.ts +1 -1
- package/src/rpc-transport-metadata.ts +1 -1
- package/src/rpc-transport.ts +2 -1
- package/src/runner.ts +6 -1
- package/src/settings/inspection.ts +275 -0
- package/src/settings/schema.ts +186 -0
- package/src/settings.ts +72 -420
- package/src/spawn-idempotency.ts +1 -1
- package/src/stateful-agent-view.ts +87 -0
- package/src/stateful-config.ts +1 -1
- package/src/stateful-guidance.ts +1 -1
- package/src/stateful-limits.ts +1 -1
- package/src/stateful-prompt.ts +2 -2
- package/src/stateful-safety.ts +2 -1
- package/src/stateful.ts +23 -103
- package/src/subagents.ts +10 -9
- package/src/subprocess-transport.ts +2 -6
- package/src/transport-types.ts +1 -1
- package/src/transport-ui.ts +1 -1
- package/src/verification-harness.ts +516 -0
- package/src/verification-receipt.ts +275 -0
- package/src/verified-execution-benchmark.ts +86 -0
- package/src/verified-execution-contract.ts +219 -0
- package/src/work-item-ledger.ts +510 -37
- package/src/work-item-persistence.ts +31 -0
- package/src/workflow-completion-controller.ts +397 -0
- package/src/workflow-plan-compiler.ts +618 -0
- package/src/workflow-plan-patch.ts +636 -0
- package/src/workflow-planning-benchmark.ts +95 -0
- package/src/workflow-planning.ts +11 -1
- package/src/workflow-ui.ts +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@narumitw/pi-subagents) [](https://pi.dev) [](./LICENSE)
|
|
4
4
|
|
|
5
|
-
`@narumitw/pi-subagents` is a native [Pi coding agent](https://pi.dev) extension for delegating work to specialized agents. By default, it exposes
|
|
5
|
+
`@narumitw/pi-subagents` is a native [Pi coding agent](https://pi.dev) extension for delegating work to specialized agents. By default, it exposes eight capability-specific tools: blocking batches, explicit autonomous workflow planning, four detached lifecycle tools, side-effect-free inspection, and synchronous read-only consultation. Users can keep every delegation method, choose async-only delegation, retain only blocking delegation, or disable delegation while keeping inspection available.
|
|
6
6
|
|
|
7
7
|
Use it to split independent research, planning, implementation, and review work across focused workers. Under the default next-turn delivery policy, background delegation is for work the current response does not depend on. Opt-in auto-resume also supports final-answer-dependent background work by requesting a synthesis turn after completion.
|
|
8
8
|
|
|
@@ -11,6 +11,7 @@ Use it to split independent research, planning, implementation, and review work
|
|
|
11
11
|
- Offers all delegation methods by default, with goal-oriented presets for async-only, blocking-only, or disabled delegation.
|
|
12
12
|
- Adds `subagent_inspect` for bounded metadata without child launch, mailbox-content access, acknowledgement, or mutation.
|
|
13
13
|
- Adds `subagent_consult` for one synchronous ephemeral child constrained to built-in `read`, `grep`, `find`, and `ls` tools (or a narrower agent allow-list).
|
|
14
|
+
- Adds explicit `subagent_auto` requests that use one bounded read-only planning turn and a deterministic compiler to select the smallest justified existing workflow without changing omitted-field behavior.
|
|
14
15
|
- Keeps batch workers isolated in `pi --mode json -p --no-session` subprocesses.
|
|
15
16
|
- Lets users set a blocking parallel call's maximum worker count from 1 through 64 while keeping four-at-a-time execution.
|
|
16
17
|
- Registers detached stateful lifecycle tools by default; completion can stay queued for the next turn or opt into an idle root synthesis turn.
|
|
@@ -22,7 +23,7 @@ Use it to split independent research, planning, implementation, and review work
|
|
|
22
23
|
- Optionally loads project agents from `.pi/agents/*.md` with confirmation.
|
|
23
24
|
- Provides a current-session-first `/subagents` manager, direct `settings|status|help` routes, and compatibility aliases for agent tools and retained agents.
|
|
24
25
|
- Supports trust-aware per-task `cwd` policies, task-selected work, workflow, idle, turn, and tool-call budgets, deterministic timeout checkpoints, bounded abort-then-summary recovery, progress telemetry, and explicit Fast, Balanced, or Deep thinking profiles.
|
|
25
|
-
-
|
|
26
|
+
- Uses Pi-native tool rows throughout; blocking and consultation calls add bounded custom live activity.
|
|
26
27
|
- Bounds JSON lines, captured messages, stderr, final output, chain substitution, and fan-in context.
|
|
27
28
|
- Enforces a recursion-depth guard and deterministic process-group termination.
|
|
28
29
|
- Provides addressable stateful agents with follow-up, consolidated mailbox/management actions, idempotent spawn retries, context selection and preview, versioned structured outcomes, and persistence.
|
|
@@ -54,13 +55,13 @@ pi -e ./packages/pi-subagents
|
|
|
54
55
|
|
|
55
56
|
## 🛠️ Pi tool
|
|
56
57
|
|
|
57
|
-
`pi-subagents` registers
|
|
58
|
+
`pi-subagents` registers eight tools by default. Run `/subagents`, choose **Change delegation**, review the concrete tool changes, then select **Save and reload** to apply one of these workflows:
|
|
58
59
|
|
|
59
60
|
| Workflow | Registered tools |
|
|
60
61
|
| --- | --- |
|
|
61
|
-
| **All delegation methods** (default) | Existing five delegation/lifecycle tools, `subagent_inspect`, and `subagent_consult` |
|
|
62
|
+
| **All delegation methods** (default) | Existing five delegation/lifecycle tools, `subagent_auto`, `subagent_inspect`, and `subagent_consult` |
|
|
62
63
|
| **Async only** | Four detached lifecycle tools plus `subagent_inspect`; blocking `subagent` and `subagent_consult` are omitted |
|
|
63
|
-
| **Blocking only** | `subagent`, `subagent_consult`, and `subagent_inspect` |
|
|
64
|
+
| **Blocking only** | `subagent`, `subagent_auto`, `subagent_consult`, and `subagent_inspect` |
|
|
64
65
|
| **Disabled** | `subagent_inspect` only; delegation is disabled |
|
|
65
66
|
|
|
66
67
|
The preview compares the selection with the tools registered in the current session, even when a manual settings edit is pending, and remains read-only until confirmation. Escape or **Cancel** leaves settings unchanged. Tool removal requires an extension reload because Pi does not expose extension tool unregistration. To avoid aborting work or removing isolated worktrees during `session_shutdown`, workflow changes are blocked while detached agents are retained; finish or clear them through **Current agents** first. Pi owns reload-error reporting and does not return a success result to extensions, so the save notification also tells users to run `/reload` if the tool surface does not refresh.
|
|
@@ -68,6 +69,7 @@ The preview compares the selection with the tools registered in the current sess
|
|
|
68
69
|
The available tools are:
|
|
69
70
|
|
|
70
71
|
- `subagent` — delegate blocking single, parallel, fan-in, chained, panel-review, or explicit dependency-workflow tasks. The main agent cannot process queued steering until the call returns.
|
|
72
|
+
- `subagent_auto` — explicitly request one read-only planning turn followed by deterministic compilation and, only when admitted, execution through the existing blocking workflow engine.
|
|
71
73
|
- `subagent_spawn` and related lifecycle tools — when enabled, start reusable detached work, return immediately, and receive bounded completion messages automatically.
|
|
72
74
|
- `subagent_inspect` — inspect agent/model/run/runtime metadata without launching work or changing state.
|
|
73
75
|
- `subagent_consult` — run one ephemeral read-only consultation and wait for its answer.
|
|
@@ -96,6 +98,7 @@ Choose the API by lifecycle:
|
|
|
96
98
|
|
|
97
99
|
| Need | Use |
|
|
98
100
|
| --- | --- |
|
|
101
|
+
| The caller explicitly wants a high-level objective decomposed under an authority ceiling and aggregate budget | `subagent_auto`, when blocking delegation is enabled |
|
|
99
102
|
| A delegated result is required before the root's next action under default next-turn delivery | Use one blocking `subagent` call when registered. In **Async only**, complete the critical-path work directly or switch workflows before delegating it |
|
|
100
103
|
| Broad research/review the current response does not depend on | Prefer one `subagent_spawn` covering related branches, when lifecycle tools are enabled |
|
|
101
104
|
| Final-answer-dependent broad work with `completionDelivery: "auto-resume"` | Prefer one `subagent_spawn`; completion requests a synthesis turn |
|
|
@@ -224,6 +227,70 @@ A blocking fan-out is reserved for output that must be synthesized before the ro
|
|
|
224
227
|
}
|
|
225
228
|
```
|
|
226
229
|
|
|
230
|
+
## 🧠 Explicit autonomous workflow planning
|
|
231
|
+
|
|
232
|
+
`subagent_auto` is an opt-in surface separate from the large multi-mode `subagent` schema.
|
|
233
|
+
It never intercepts ordinary prompts and does not change existing calls when omitted.
|
|
234
|
+
The caller supplies one versioned objective, non-goals, required inputs, acceptance criteria, required evidence, an authority ceiling, an aggregate budget, and deterministic constraints.
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"request": {
|
|
239
|
+
"version": "pi-subagents:automation-request:v1",
|
|
240
|
+
"objective": "Implement and verify the package change",
|
|
241
|
+
"nonGoals": ["Do not publish or release"],
|
|
242
|
+
"requiredInputs": ["current trusted repository"],
|
|
243
|
+
"acceptanceCriteria": ["Focused and root checks pass"],
|
|
244
|
+
"requiredEvidence": ["test output", "final diff review"],
|
|
245
|
+
"authorityCeiling": {
|
|
246
|
+
"capabilities": ["implementation", "code-review"],
|
|
247
|
+
"tools": ["read", "bash", "edit", "write"],
|
|
248
|
+
"readPaths": ["packages/pi-subagents"],
|
|
249
|
+
"writePaths": ["packages/pi-subagents"],
|
|
250
|
+
"network": "unspecified",
|
|
251
|
+
"secrets": "unspecified",
|
|
252
|
+
"sideEffectPolicy": "mutating"
|
|
253
|
+
},
|
|
254
|
+
"aggregateBudget": {
|
|
255
|
+
"timeoutMs": 180000,
|
|
256
|
+
"maxTurns": 30,
|
|
257
|
+
"maxToolCalls": 60,
|
|
258
|
+
"maxTasks": 4,
|
|
259
|
+
"maxRevisions": 1
|
|
260
|
+
},
|
|
261
|
+
"constraints": {
|
|
262
|
+
"contextPressure": "high",
|
|
263
|
+
"maxMutatingWidth": 2,
|
|
264
|
+
"requireVerification": true,
|
|
265
|
+
"workspaceMode": "shared"
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The planner always uses the built-in `planner` with only `read`, `grep`, `find`, and `ls`, disabled extensions and session persistence, trust-aware prompt resources, a maximum 60-second planning deadline, and bounded turn/tool-call counts.
|
|
272
|
+
The planner returns only `pi-subagents:workflow-plan:v1` JSON and cannot choose agents, grant authority, create descendants, or forge executor identities.
|
|
273
|
+
The executor reserves at most one quarter of the aggregate timeout, turns, and tool calls for planning before compiling execution work.
|
|
274
|
+
It rejects before planning when that reservation leaves no positive execution budget, and it narrows the request task ceiling to the configured blocking-task limit before compilation or persistence.
|
|
275
|
+
|
|
276
|
+
The compiler validates strict unknown-field and UTF-8 bounds, relative scopes, cycles, artifacts, ownership, capability routes, aggregate budgets, task generations, integration ownership, and the two-mutating-worker limit before execution.
|
|
277
|
+
Caller-level acceptance criteria and required evidence are merged into the authoritative terminal, integration-owner, and verifier contracts without exceeding contract item limits.
|
|
278
|
+
Path ceilings are compiler and conflict-scheduling constraints, not operating-system filesystem isolation; use a container or sandbox when host-level containment is required.
|
|
279
|
+
Network and secrets guarantees other than `"unspecified"` fail closed because the current executor cannot enforce them.
|
|
280
|
+
It can narrow or reject a proposal and can add one verifier only within the caller's remaining authority and budget.
|
|
281
|
+
Parent-owned, needs-input, planner-failed, and compiler-rejected outcomes launch no execution workers.
|
|
282
|
+
Every admitted mutating workflow has one authoritative integration owner and one distinct `structured-v2` verifier before any mutating worker starts.
|
|
283
|
+
Project-local agents are not selected by this first surface, workflow grandchildren are rejected, and `workspaceMode: "worktree"` fails closed until blocking workflow worktree execution is supported.
|
|
284
|
+
|
|
285
|
+
Pending, needs-input, verification-rework, stale, or invalidated work can be revised through the internal `pi-subagents:workflow-plan-patch:v1` contract.
|
|
286
|
+
Each accepted patch must match the current plan identity and workflow generation, rotates both identity and task generations, preserves accepted history/artifacts/receipts, and stops after the caller's revision limit.
|
|
287
|
+
The initial tool surface does not expose free-form public graph editing.
|
|
288
|
+
|
|
289
|
+
For compatibility or exact task control, use caller-authored `subagent.workflow`.
|
|
290
|
+
Before downgrading, use that explicit workflow fallback and let active automation calls finish.
|
|
291
|
+
Older releases do not register `subagent_auto` and ignore the separate versioned automation records under `~/.pi/agent/pi-subagents-workflows/`; no settings migration is required.
|
|
292
|
+
No benchmark result in this release changes the default delegation policy or makes a production-quality claim.
|
|
293
|
+
|
|
227
294
|
## 🔎 Read-only inspection
|
|
228
295
|
|
|
229
296
|
`subagent_inspect` is registered in every workflow, including disabled delegation. It never starts a child, sends or acknowledges mailbox messages, interrupts or closes a run, changes settings, refreshes providers, resolves credentials, or modifies files.
|
|
@@ -413,7 +480,55 @@ Run an explicit dependency workflow:
|
|
|
413
480
|
}
|
|
414
481
|
```
|
|
415
482
|
|
|
416
|
-
|
|
483
|
+
Managed verified execution is an explicit per-workflow contract.
|
|
484
|
+
The executor infers the final mutating integration owner when none is declared, synthesizes one distinct read-only verifier, runs declared deterministic checks in a disposable Git worktree overlaid with the submitted state, and accepts only the exact unchanged submitted state.
|
|
485
|
+
Every deterministic check has a stable evidence ID, a direct executable with argument-array invocation, and an optional relative `cwd` and timeout.
|
|
486
|
+
Only `git`, `node`, `npm`, and `npx` are accepted; shell command strings fail before child allocation.
|
|
487
|
+
The integration owner must request `structured-v2`, declare a non-empty `writePaths` scope, and name current required evidence through its delegation contract.
|
|
488
|
+
Every required evidence ID must match a currently passed executor-owned check; worker-authored artifact metadata never satisfies that binding.
|
|
489
|
+
|
|
490
|
+
```json
|
|
491
|
+
{
|
|
492
|
+
"workflow": {
|
|
493
|
+
"verifiedExecution": {
|
|
494
|
+
"verifierAgent": "reviewer",
|
|
495
|
+
"maxReworkCycles": 1,
|
|
496
|
+
"checks": [
|
|
497
|
+
{
|
|
498
|
+
"id": "focused-test",
|
|
499
|
+
"command": "npm",
|
|
500
|
+
"args": ["test", "--", "feature"],
|
|
501
|
+
"timeoutMs": 120000
|
|
502
|
+
}
|
|
503
|
+
]
|
|
504
|
+
},
|
|
505
|
+
"tasks": [
|
|
506
|
+
{
|
|
507
|
+
"id": "implementation",
|
|
508
|
+
"agent": "worker",
|
|
509
|
+
"task": "Implement the contracted change.",
|
|
510
|
+
"writePaths": ["src", "test"],
|
|
511
|
+
"acceptanceCriteria": ["The focused regression test passes"],
|
|
512
|
+
"resultFormat": "structured-v2",
|
|
513
|
+
"contract": {
|
|
514
|
+
"version": "pi-subagents:delegation:v2",
|
|
515
|
+
"level": "full",
|
|
516
|
+
"taskId": "implementation",
|
|
517
|
+
"objective": "Implement the contracted change",
|
|
518
|
+
"requiredEvidence": ["focused-test"],
|
|
519
|
+
"sideEffectPolicy": "mutating"
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
]
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
An advanced caller may provide the verifier task instead of letting the executor synthesize it.
|
|
528
|
+
That task must directly and only depend on the integration owner, use `structured-v2`, select the configured distinct verifier agent, and declare an enforced read-only contract without shell or custom tools.
|
|
529
|
+
The executor narrows accepted verifier authority to `read` even when the selected agent normally has broader tools, and disables verifier extensions, skills, prompt templates, and inherited context files.
|
|
530
|
+
|
|
531
|
+
The older explicit verifier contract remains available as a compatibility gate without managed integration:
|
|
417
532
|
|
|
418
533
|
```json
|
|
419
534
|
{
|
|
@@ -461,10 +576,26 @@ A task that explicitly requires independent verification must have exactly one d
|
|
|
461
576
|
The producer stops in `awaiting-verification`, its own passing verification claims remain untrusted, and ordinary downstream tasks stay blocked until the executor records an accepted verifier receipt.
|
|
462
577
|
The verifier runs alone in a fresh subprocess context against one bounded Git-visible tree identity and must encode `verification-accepted`, `verification-rework`, or `verification-rejected` through the documented `structured-v2` status and reason fields.
|
|
463
578
|
Dirty-tree identity covers at most 1 MiB across separately framed staged and unstaged binary diffs plus bounded non-ignored untracked paths and bytes; submodules, unsupported states, and changing trees fail closed.
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
579
|
+
The compatibility gate preserves bounded rework or rejection evidence but does not replay the producer automatically.
|
|
580
|
+
|
|
581
|
+
With `verifiedExecution`, execution completion and acceptance are separate `pi-subagents:work-acceptance:v1` states.
|
|
582
|
+
A worker's own verification, confidence, prose, consensus, or exit status cannot move `pending` acceptance to `accepted`.
|
|
583
|
+
The executor-owned `pi-subagents:verification-receipt:v1` binds both tree captures, patch digest, changed paths, accepted scope, target and verifier generations and `ExecutionPlan` IDs, verifier identity, acceptance criteria, required current evidence, and bounded deterministic check receipts.
|
|
584
|
+
Each receipt is capped at 12 KiB, each stored check stream at 2 KiB, and oversized acceptance evidence fails closed rather than expanding tool details.
|
|
585
|
+
The verifier receives the original objective, current artifact metadata, immutable tree identity, and executor-owned check output rather than the worker narrative.
|
|
586
|
+
Verifier mutation, a stale or replaced generation, a failed or unsafe check, missing evidence, wrong scope, patch, plan, tree, or identity, cancellation, timeout, and unsupported Git state all produce non-success.
|
|
587
|
+
One verifier `rework` decision may rotate the worker and verifier generations when `maxReworkCycles` is `1`; prior grants are revoked, prior evidence remains history, only current requirements and findings are added, and a second rejection is terminal.
|
|
588
|
+
Crashes, timeouts, cancellation, ambiguous settlement, and drift are never replayed.
|
|
589
|
+
The disposable check worktree includes bounded tracked and non-ignored untracked files and is removed after checks.
|
|
590
|
+
When the repository has a local `node_modules` directory, the worktree is nested beneath it so normal Node and npm resolution can read the installed dependency tree without copying it.
|
|
591
|
+
The worktree isolates repository build output, but it does not make the installed dependency tree read-only and is not an operating-system sandbox for processes, network, secrets, absolute paths, or host credentials.
|
|
592
|
+
The accepted state remains the selected shared workspace; no general patch merge or conflict resolver is added.
|
|
593
|
+
|
|
594
|
+
Omitting `verifiedExecution` preserves prior workflow behavior, including the older explicit verifier gate above.
|
|
595
|
+
To downgrade, finish active workflows, remove `verifiedExecution`, and either use the explicit `verifierFor` compatibility form or perform verification in the parent.
|
|
596
|
+
Older package versions reject the unknown managed contract rather than silently providing its guarantees.
|
|
597
|
+
Explicit workflow transitions are atomically persisted as mode-0600, private-text-redacted snapshots for current-session `list_workflows` and `get_workflow` inspection; in-flight execution or acceptance restores as interrupted non-success, and no prior side effect is automatically resumed.
|
|
598
|
+
Legacy v1 and v2 records without acceptance fields retain their prior completed terminal meaning, while v1 self-reported verification flags and artifact trust remain untrusted.
|
|
468
599
|
|
|
469
600
|
## 🔁 Stateful agents
|
|
470
601
|
|
|
@@ -918,6 +1049,12 @@ packages/pi-subagents/
|
|
|
918
1049
|
├── src/
|
|
919
1050
|
│ ├── index.ts # Pi package entrypoint
|
|
920
1051
|
│ ├── subagents.ts # Extension registration and blocking tool schema
|
|
1052
|
+
│ ├── automation.ts # Explicit autonomous planning tool and lifecycle owner
|
|
1053
|
+
│ ├── automation-contract.ts # Strict request, proposal, and graph-patch contracts
|
|
1054
|
+
│ ├── automation-planner.ts # Bounded read-only planner prompt and resource policy
|
|
1055
|
+
│ ├── workflow-plan-compiler.ts # Deterministic admission, routing, and workflow compilation
|
|
1056
|
+
│ ├── workflow-plan-patch.ts # Generation-safe revisions and atomic plan persistence
|
|
1057
|
+
│ ├── workflow-planning-benchmark.ts # Frozen matched offline evaluation protocol
|
|
921
1058
|
│ ├── inspect.ts # Side-effect-free metadata inspection tool
|
|
922
1059
|
│ ├── consult.ts # Synchronous read-only consultation tool
|
|
923
1060
|
│ ├── consult-policy.ts # Enforced read-only tool intersection
|
|
@@ -937,7 +1074,12 @@ packages/pi-subagents/
|
|
|
937
1074
|
│ ├── execution-plan.ts # Executor-owned authority and resource resolution
|
|
938
1075
|
│ ├── work-item-ledger.ts # Persistent dependency and artifact state machine
|
|
939
1076
|
│ ├── work-item-persistence.ts # Atomic redacted workflow state and inspection
|
|
940
|
-
│ ├── workflow-verification.ts #
|
|
1077
|
+
│ ├── workflow-verification.ts # Compatibility independent-verifier receipts
|
|
1078
|
+
│ ├── verified-execution-contract.ts # Explicit managed-verification request boundary
|
|
1079
|
+
│ ├── workflow-completion-controller.ts # Sole opted-in terminal acceptance owner
|
|
1080
|
+
│ ├── verification-harness.ts # Disposable deterministic check execution
|
|
1081
|
+
│ ├── verification-receipt.ts # Strict executor-owned managed receipts
|
|
1082
|
+
│ ├── verified-execution-benchmark.ts # Matched offline acceptance/cost fixture
|
|
941
1083
|
│ ├── workflow-tree-identity.ts # Bounded exact Git-visible tree identities
|
|
942
1084
|
│ ├── integration-controller.ts # Fail-closed canonical integration admission
|
|
943
1085
|
│ ├── adaptive-scheduler.ts # Dependency, capacity, budget, and conflict scheduling
|
|
@@ -972,7 +1114,7 @@ packages/pi-subagents/
|
|
|
972
1114
|
```
|
|
973
1115
|
|
|
974
1116
|
`index.ts` is the Pi entrypoint and forwards to `subagents.ts`; the other source modules are internal.
|
|
975
|
-
Workflow settings remain backward compatible: older files without `blocking.enabled` receive the
|
|
1117
|
+
Workflow settings remain backward compatible: older files without `blocking.enabled` receive the eight-tool default, and an absent `blocking.maxParallelTasks` keeps the previous eight-worker limit.
|
|
976
1118
|
Existing `stateful.enabled: false` files expose blocking delegation plus inspection/consultation.
|
|
977
1119
|
Older package releases ignore and preserve the optional `blocking.maxParallelTasks`, `consult`, and `cwdPolicy` fields.
|
|
978
1120
|
The package exposes its Pi extension through `package.json`:
|
package/package.json
CHANGED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in agent definitions and prompt construction.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { type AgentCapabilityManifest, CAPABILITY_MANIFEST_VERSION } from "../capabilities.js";
|
|
6
|
+
import type { AgentConfig } from "./types.js";
|
|
7
|
+
|
|
8
|
+
export const BUILT_IN_AGENTS: AgentConfig[] = [
|
|
9
|
+
{
|
|
10
|
+
name: "scout",
|
|
11
|
+
description:
|
|
12
|
+
"Read-only codebase reconnaissance; returns concise findings with paths and evidence.",
|
|
13
|
+
tools: ["read", "grep", "find", "ls", "bash"],
|
|
14
|
+
capabilityManifest: builtInManifest(["repository-search", "code-evidence"], "read", [
|
|
15
|
+
"evidence-gathering",
|
|
16
|
+
]),
|
|
17
|
+
source: "built-in",
|
|
18
|
+
filePath: "built-in:scout",
|
|
19
|
+
systemPrompt: [
|
|
20
|
+
"You are a scout subagent. Explore the codebase quickly and report grounded findings.",
|
|
21
|
+
"Do not edit files. Prefer read, grep, find, ls, and safe bash inspection commands.",
|
|
22
|
+
"Return concise bullets with exact file paths, symbols, and open questions.",
|
|
23
|
+
].join("\n"),
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "planner",
|
|
27
|
+
description: "Turns reconnaissance into a lean implementation or migration plan.",
|
|
28
|
+
tools: ["read", "grep", "find", "ls"],
|
|
29
|
+
capabilityManifest: builtInManifest(
|
|
30
|
+
["task-decomposition", "implementation-planning", "migration-planning"],
|
|
31
|
+
"read",
|
|
32
|
+
),
|
|
33
|
+
source: "built-in",
|
|
34
|
+
filePath: "built-in:planner",
|
|
35
|
+
systemPrompt: [
|
|
36
|
+
"You are a planner subagent. Produce executable, verifiable plans only.",
|
|
37
|
+
"Do not modify files. Ground the plan in the repository's actual structure.",
|
|
38
|
+
"Call out assumptions, risks, sequencing, and verification commands.",
|
|
39
|
+
].join("\n"),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "reviewer",
|
|
43
|
+
description: "Independent code review agent that inspects existing verification evidence.",
|
|
44
|
+
tools: ["read", "grep", "find", "ls", "bash"],
|
|
45
|
+
capabilityManifest: builtInManifest(
|
|
46
|
+
["code-review", "evidence-review", "security-baseline"],
|
|
47
|
+
"read",
|
|
48
|
+
["independent-review"],
|
|
49
|
+
),
|
|
50
|
+
source: "built-in",
|
|
51
|
+
filePath: "built-in:reviewer",
|
|
52
|
+
systemPrompt: [
|
|
53
|
+
"You are a reviewer subagent. Review changes adversarially and assess claims against the code and existing evidence.",
|
|
54
|
+
"Do not edit files or run tests, builds, benchmarks, formatters, or other long-running verification commands.",
|
|
55
|
+
"Inspect code, diffs, test definitions, and existing verification evidence. Recommend any additional commands for the main agent to run.",
|
|
56
|
+
"Report PASS, FAIL, or PARTIAL with evidence, commands inspected, and specific follow-ups.",
|
|
57
|
+
].join("\n"),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "worker",
|
|
61
|
+
description: "General-purpose implementation worker with the default Pi tool set.",
|
|
62
|
+
capabilityManifest: builtInManifest(
|
|
63
|
+
["implementation", "command-execution", "repository-modification"],
|
|
64
|
+
"write",
|
|
65
|
+
),
|
|
66
|
+
source: "built-in",
|
|
67
|
+
filePath: "built-in:worker",
|
|
68
|
+
systemPrompt: workerSystemPrompt(),
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "general",
|
|
72
|
+
description: "Alias for worker; kept for model-generated subagent names.",
|
|
73
|
+
capabilityManifest: builtInManifest(
|
|
74
|
+
["implementation", "command-execution", "repository-modification"],
|
|
75
|
+
"write",
|
|
76
|
+
),
|
|
77
|
+
source: "built-in",
|
|
78
|
+
filePath: "built-in:general",
|
|
79
|
+
systemPrompt: workerSystemPrompt(),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "general-purpose",
|
|
83
|
+
description: "Alias for worker; compatible with common subagent naming conventions.",
|
|
84
|
+
capabilityManifest: builtInManifest(
|
|
85
|
+
["implementation", "command-execution", "repository-modification"],
|
|
86
|
+
"write",
|
|
87
|
+
),
|
|
88
|
+
source: "built-in",
|
|
89
|
+
filePath: "built-in:general-purpose",
|
|
90
|
+
systemPrompt: workerSystemPrompt(),
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
export function getBuiltInAgent(name: string): AgentConfig | undefined {
|
|
95
|
+
const agent = BUILT_IN_AGENTS.find((candidate) => candidate.name === name);
|
|
96
|
+
return agent ? structuredClone(agent) : undefined;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function builtInManifest(
|
|
100
|
+
capabilities: string[],
|
|
101
|
+
filesystem: "read" | "write",
|
|
102
|
+
verificationRoles: string[] = [],
|
|
103
|
+
): AgentCapabilityManifest {
|
|
104
|
+
return {
|
|
105
|
+
version: CAPABILITY_MANIFEST_VERSION,
|
|
106
|
+
capabilities,
|
|
107
|
+
modalities: ["text"],
|
|
108
|
+
resultFormats: ["text", "structured-v1", "structured-v2"],
|
|
109
|
+
authority: { filesystem },
|
|
110
|
+
verificationRoles,
|
|
111
|
+
contextStrengths: ["repository"],
|
|
112
|
+
costHint: filesystem === "read" ? "low" : "medium",
|
|
113
|
+
latencyHint: filesystem === "read" ? "low" : "medium",
|
|
114
|
+
limitations: [],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function workerSystemPrompt(): string {
|
|
119
|
+
return [
|
|
120
|
+
"You are a focused worker subagent running in an isolated Pi process.",
|
|
121
|
+
"Complete the delegated task directly. Keep scope tight and avoid unrelated changes.",
|
|
122
|
+
"When done, summarize files changed, commands run, and any remaining risks.",
|
|
123
|
+
].join("\n");
|
|
124
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded, sanitized model-facing agent catalog formatting.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { BUILT_IN_AGENTS } from "./built-ins.js";
|
|
6
|
+
import {
|
|
7
|
+
type AgentDiscoveryOptions,
|
|
8
|
+
type AgentDiscoveryResult,
|
|
9
|
+
discoverAgents,
|
|
10
|
+
} from "./discovery.js";
|
|
11
|
+
import type { AgentConfig, SubagentSettings } from "./types.js";
|
|
12
|
+
|
|
13
|
+
export function formatAgentList(
|
|
14
|
+
agents: AgentConfig[],
|
|
15
|
+
maxItems: number,
|
|
16
|
+
): { text: string; remaining: number } {
|
|
17
|
+
if (agents.length === 0) return { text: "none", remaining: 0 };
|
|
18
|
+
const listed = agents.slice(0, maxItems);
|
|
19
|
+
const remaining = agents.length - listed.length;
|
|
20
|
+
return {
|
|
21
|
+
text: listed.map((a) => `${a.name} (${a.source}): ${a.description}`).join("; "),
|
|
22
|
+
remaining,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface AgentCatalog {
|
|
27
|
+
/** The effective catalog for the default invocation scope. */
|
|
28
|
+
user: AgentDiscoveryResult;
|
|
29
|
+
/** The project-scope catalog; custom project definitions are loaded only after project trust. */
|
|
30
|
+
project?: AgentDiscoveryResult;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface AgentCatalogFormatOptions {
|
|
34
|
+
maxItems?: number;
|
|
35
|
+
maxDescriptionLength?: number;
|
|
36
|
+
maxCharacters?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface AgentCatalogFormatResult {
|
|
40
|
+
text: string;
|
|
41
|
+
omitted: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const DEFAULT_AGENT_CATALOG_MAX_ITEMS = 32;
|
|
45
|
+
export const DEFAULT_AGENT_CATALOG_MAX_DESCRIPTION_LENGTH = 240;
|
|
46
|
+
export const DEFAULT_AGENT_CATALOG_MAX_CHARACTERS = 6_000;
|
|
47
|
+
export const DEFAULT_AGENT_CATALOG_MAX_FILES_PER_SCOPE = 128;
|
|
48
|
+
export const DEFAULT_AGENT_CATALOG_MAX_FILE_BYTES = 64 * 1024;
|
|
49
|
+
export const DEFAULT_AGENT_CATALOG_MAX_TOTAL_BYTES_PER_SCOPE = 2 * 1024 * 1024;
|
|
50
|
+
|
|
51
|
+
const BUILT_IN_AGENT_ORDER = new Map(BUILT_IN_AGENTS.map((agent, index) => [agent.name, index]));
|
|
52
|
+
|
|
53
|
+
function compareCatalogAgents(left: AgentConfig, right: AgentConfig): number {
|
|
54
|
+
const leftBuiltInOrder = BUILT_IN_AGENT_ORDER.get(left.name);
|
|
55
|
+
const rightBuiltInOrder = BUILT_IN_AGENT_ORDER.get(right.name);
|
|
56
|
+
if (leftBuiltInOrder !== undefined || rightBuiltInOrder !== undefined) {
|
|
57
|
+
if (leftBuiltInOrder === undefined) return 1;
|
|
58
|
+
if (rightBuiltInOrder === undefined) return -1;
|
|
59
|
+
return leftBuiltInOrder - rightBuiltInOrder;
|
|
60
|
+
}
|
|
61
|
+
return left.name.localeCompare(right.name);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function normalizeCatalogDescription(description: string, maxLength: number): string {
|
|
65
|
+
const normalized = description.replace(/\s+/gu, " ").trim();
|
|
66
|
+
if (normalized.length <= maxLength) return normalized;
|
|
67
|
+
const suffix = "…";
|
|
68
|
+
return `${normalized.slice(0, Math.max(0, maxLength - suffix.length)).trimEnd()}${suffix}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
type CatalogScope = "user" | "project" | "project-fallback";
|
|
72
|
+
|
|
73
|
+
function catalogAgentLine(
|
|
74
|
+
agent: AgentConfig,
|
|
75
|
+
scope: CatalogScope,
|
|
76
|
+
userNames: ReadonlySet<string>,
|
|
77
|
+
maxDescriptionLength: number,
|
|
78
|
+
): string {
|
|
79
|
+
const scopeLabel =
|
|
80
|
+
scope === "user"
|
|
81
|
+
? 'agentScope: "user"'
|
|
82
|
+
: scope === "project"
|
|
83
|
+
? 'requires agentScope: "project" or "both"'
|
|
84
|
+
: 'requires agentScope: "project" ("both" selects the user definition)';
|
|
85
|
+
const collision =
|
|
86
|
+
scope !== "user" && userNames.has(agent.name)
|
|
87
|
+
? scope === "project"
|
|
88
|
+
? "; overrides the default user definition for project/both"
|
|
89
|
+
: "; scope-specific fallback for the default user override"
|
|
90
|
+
: "";
|
|
91
|
+
return `- ${agent.name} [source: ${agent.source}; ${scopeLabel}${collision}] — ${normalizeCatalogDescription(agent.description, maxDescriptionLength)}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Format the effective agent variants that the parent model can invoke.
|
|
96
|
+
*
|
|
97
|
+
* User-authored descriptions are prompt text, so this formatter deliberately normalizes and bounds
|
|
98
|
+
* them. Project definitions are supplied separately by the caller so an untrusted project is never
|
|
99
|
+
* read merely to build model-facing metadata.
|
|
100
|
+
*/
|
|
101
|
+
export function formatAgentCatalog(
|
|
102
|
+
catalog: AgentCatalog,
|
|
103
|
+
options: AgentCatalogFormatOptions = {},
|
|
104
|
+
): AgentCatalogFormatResult {
|
|
105
|
+
const maxItems = Math.max(0, options.maxItems ?? DEFAULT_AGENT_CATALOG_MAX_ITEMS);
|
|
106
|
+
const maxDescriptionLength = Math.max(
|
|
107
|
+
1,
|
|
108
|
+
options.maxDescriptionLength ?? DEFAULT_AGENT_CATALOG_MAX_DESCRIPTION_LENGTH,
|
|
109
|
+
);
|
|
110
|
+
const maxCharacters = Math.max(1, options.maxCharacters ?? DEFAULT_AGENT_CATALOG_MAX_CHARACTERS);
|
|
111
|
+
const userDiscoveryIncomplete =
|
|
112
|
+
(catalog.user.omittedAgentDefinitions ?? 0) > 0 ||
|
|
113
|
+
catalog.user.metadataDiscoveryIncomplete === true;
|
|
114
|
+
const projectDiscoveryIncomplete =
|
|
115
|
+
(catalog.project?.omittedAgentDefinitions ?? 0) > 0 ||
|
|
116
|
+
catalog.project?.metadataDiscoveryIncomplete === true;
|
|
117
|
+
const discoveredUserAgents = [...catalog.user.agents].sort(compareCatalogAgents);
|
|
118
|
+
const discoveredProjectScopeAgents = [...(catalog.project?.agents ?? [])].sort(
|
|
119
|
+
compareCatalogAgents,
|
|
120
|
+
);
|
|
121
|
+
const userAgents = userDiscoveryIncomplete ? [] : discoveredUserAgents;
|
|
122
|
+
const projectScopeAgents = projectDiscoveryIncomplete ? [] : discoveredProjectScopeAgents;
|
|
123
|
+
const projectAgents = projectScopeAgents.filter((agent) => agent.source === "project");
|
|
124
|
+
const discoveredUserByName = new Map(discoveredUserAgents.map((agent) => [agent.name, agent]));
|
|
125
|
+
const userByName = new Map(userAgents.map((agent) => [agent.name, agent]));
|
|
126
|
+
const userNames = new Set(userByName.keys());
|
|
127
|
+
const potentialProjectFallbackAgents = discoveredProjectScopeAgents.filter(
|
|
128
|
+
(agent) =>
|
|
129
|
+
agent.source === "built-in" && discoveredUserByName.get(agent.name)?.source === "user",
|
|
130
|
+
);
|
|
131
|
+
const projectFallbackAgents =
|
|
132
|
+
userDiscoveryIncomplete || projectDiscoveryIncomplete ? [] : potentialProjectFallbackAgents;
|
|
133
|
+
const allEntries = [
|
|
134
|
+
...userAgents.map((agent) => ({ agent, scope: "user" as const })),
|
|
135
|
+
...projectAgents.map((agent) => ({ agent, scope: "project" as const })),
|
|
136
|
+
...projectFallbackAgents.map((agent) => ({ agent, scope: "project-fallback" as const })),
|
|
137
|
+
];
|
|
138
|
+
const boundedEntries = allEntries.slice(0, maxItems);
|
|
139
|
+
const suppressedMetadataEntries =
|
|
140
|
+
(userDiscoveryIncomplete ? discoveredUserAgents.length : 0) +
|
|
141
|
+
(projectDiscoveryIncomplete
|
|
142
|
+
? discoveredProjectScopeAgents.filter((agent) => agent.source === "project").length +
|
|
143
|
+
potentialProjectFallbackAgents.length
|
|
144
|
+
: 0);
|
|
145
|
+
const discoveryOmissions =
|
|
146
|
+
(catalog.user.omittedAgentDefinitions ?? 0) +
|
|
147
|
+
(catalog.project?.omittedAgentDefinitions ?? 0) +
|
|
148
|
+
suppressedMetadataEntries;
|
|
149
|
+
const discoveryIncomplete =
|
|
150
|
+
catalog.user.metadataDiscoveryIncomplete === true ||
|
|
151
|
+
catalog.project?.metadataDiscoveryIncomplete === true;
|
|
152
|
+
|
|
153
|
+
const render = (entries: typeof allEntries, omitted: number): string => {
|
|
154
|
+
const lines = [
|
|
155
|
+
"Available agent definitions (metadata only; runtime validation and trust remain authoritative).",
|
|
156
|
+
];
|
|
157
|
+
const userLines = entries
|
|
158
|
+
.filter((entry) => entry.scope === "user")
|
|
159
|
+
.map((entry) => catalogAgentLine(entry.agent, entry.scope, userNames, maxDescriptionLength));
|
|
160
|
+
if (userLines.length > 0) {
|
|
161
|
+
lines.push('Default scope (agentScope: "user"):');
|
|
162
|
+
lines.push(...userLines);
|
|
163
|
+
}
|
|
164
|
+
const projectLines = entries
|
|
165
|
+
.filter((entry) => entry.scope !== "user")
|
|
166
|
+
.map((entry) => catalogAgentLine(entry.agent, entry.scope, userNames, maxDescriptionLength));
|
|
167
|
+
if (projectLines.length > 0) {
|
|
168
|
+
lines.push("Trusted project/scope variants (use the required agentScope shown):");
|
|
169
|
+
lines.push(...projectLines);
|
|
170
|
+
}
|
|
171
|
+
const collisionNames = entries
|
|
172
|
+
.filter((entry) => entry.scope !== "user" && userNames.has(entry.agent.name))
|
|
173
|
+
.map((entry) => entry.agent.name);
|
|
174
|
+
if (collisionNames.length > 0 && projectLines.length > 0) {
|
|
175
|
+
const precedence = entries
|
|
176
|
+
.filter((entry) => entry.scope !== "user" && userNames.has(entry.agent.name))
|
|
177
|
+
.map((entry) =>
|
|
178
|
+
entry.scope === "project"
|
|
179
|
+
? `${entry.agent.name}: user with "user", project with "project"/"both"`
|
|
180
|
+
: `${entry.agent.name}: user with "user"/"both", built-in with "project"`,
|
|
181
|
+
);
|
|
182
|
+
lines.push(`Same-name precedence: ${precedence.join("; ")}.`);
|
|
183
|
+
}
|
|
184
|
+
if (omitted > 0) {
|
|
185
|
+
lines.push(
|
|
186
|
+
`[${omitted} additional agent definition${omitted === 1 ? "" : "s"} omitted due to metadata bounds or incomplete discovery.]`,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
if (discoveryIncomplete) {
|
|
190
|
+
lines.push("[Agent metadata discovery was incomplete; some definitions may be unavailable.]");
|
|
191
|
+
}
|
|
192
|
+
return lines.join("\n");
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
let listedCount = boundedEntries.length;
|
|
196
|
+
let text = render(
|
|
197
|
+
boundedEntries.slice(0, listedCount),
|
|
198
|
+
allEntries.length - listedCount + discoveryOmissions,
|
|
199
|
+
);
|
|
200
|
+
while (text.length > maxCharacters && listedCount > 0) {
|
|
201
|
+
listedCount -= 1;
|
|
202
|
+
text = render(
|
|
203
|
+
boundedEntries.slice(0, listedCount),
|
|
204
|
+
allEntries.length - listedCount + discoveryOmissions,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
return { text, omitted: allEntries.length - listedCount + discoveryOmissions };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function discoverAgentCatalog(
|
|
211
|
+
cwd: string,
|
|
212
|
+
projectTrusted: boolean,
|
|
213
|
+
config?: SubagentSettings,
|
|
214
|
+
): AgentCatalog {
|
|
215
|
+
const options: AgentDiscoveryOptions = {
|
|
216
|
+
maxFiles: DEFAULT_AGENT_CATALOG_MAX_FILES_PER_SCOPE,
|
|
217
|
+
maxFileBytes: DEFAULT_AGENT_CATALOG_MAX_FILE_BYTES,
|
|
218
|
+
maxTotalBytes: DEFAULT_AGENT_CATALOG_MAX_TOTAL_BYTES_PER_SCOPE,
|
|
219
|
+
};
|
|
220
|
+
return {
|
|
221
|
+
user: discoverAgents(cwd, "user", config, options),
|
|
222
|
+
project: projectTrusted ? discoverAgents(cwd, "project", config, options) : undefined,
|
|
223
|
+
};
|
|
224
|
+
}
|