pi-subagents 0.67.0 → 0.68.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/CHANGELOG.md +70 -0
- package/README.md +1 -1
- package/docs/agents.md +37 -12
- package/docs/configuration.md +61 -19
- package/docs/extension-api.md +5 -1
- package/docs/missions.md +2 -2
- package/docs/models.md +11 -79
- package/docs/observability.md +18 -8
- package/docs/standalone-background.md +13 -3
- package/docs/tool-reference.md +15 -12
- package/docs/watchdog.md +10 -12
- package/docs/workflows.md +11 -1
- package/index.ts +5 -2
- package/package.json +4 -2
- package/runner-peer-loader.mjs +24 -0
- package/runner-peer-preload.mjs +25 -11
- package/skills/pi-subagents/SKILL.md +18 -21
- package/skills/pi-subagents/references/constraints-and-recipes.md +3 -2
- package/skills/pi-subagents/references/execution-controls.md +4 -4
- package/skills/pi-subagents/references/management-authoring-rpc.md +0 -1
- package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +16 -12
- package/skills/pi-subagents/references/review-and-validation.md +3 -3
- package/src/agents/agent-management.ts +57 -58
- package/src/agents/agent-serializer.ts +4 -3
- package/src/agents/agents.ts +184 -71
- package/src/agents/chain-serializer.ts +5 -0
- package/src/agents/runtime-agent-registry.ts +7 -6
- package/src/api/preflight.ts +20 -16
- package/src/api/required-child-extensions.ts +6 -0
- package/src/extension/config.ts +10 -37
- package/src/extension/fanout-child.ts +3 -0
- package/src/extension/herdr-pi-bridge.ts +160 -0
- package/src/extension/index.ts +42 -31
- package/src/extension/public-execution.ts +3 -3
- package/src/extension/schemas.ts +16 -5
- package/src/extension/tool-description.ts +8 -7
- package/src/intercom/native-supervisor-channel.ts +22 -18
- package/src/policy/authority.ts +4 -0
- package/src/profiles/profiles.ts +12 -6
- package/src/runs/background/active-run-index.ts +17 -1
- package/src/runs/background/async-execution.ts +309 -126
- package/src/runs/background/async-job-tracker.ts +8 -6
- package/src/runs/background/async-resume.ts +13 -4
- package/src/runs/background/async-status.ts +15 -4
- package/src/runs/background/auto-drain.ts +20 -10
- package/src/runs/background/binary-bootstrap.ts +5 -0
- package/src/runs/background/chain-append.ts +1 -1
- package/src/runs/background/chain-root-attachment.ts +14 -33
- package/src/runs/background/notify.ts +74 -6
- package/src/runs/background/result-files.ts +8 -4
- package/src/runs/background/result-watcher.ts +19 -2
- package/src/runs/background/run-child-session.ts +20 -29
- package/src/runs/background/runner-aliases.ts +4 -33
- package/src/runs/background/runner-child-launch.ts +4 -1
- package/src/runs/background/runner-child-sessions.ts +2 -2
- package/src/runs/background/runner-http-dispatcher.ts +119 -0
- package/src/runs/background/scheduled-runs.ts +11 -5
- package/src/runs/background/stale-run-reconciler.ts +35 -11
- package/src/runs/background/subagent-runner.ts +396 -275
- package/src/runs/background/subagent-wait.ts +128 -23
- package/src/runs/background/wait-completions.ts +75 -27
- package/src/runs/background/wait-subscriptions.ts +9 -3
- package/src/runs/background/wait-tool.ts +4 -2
- package/src/runs/foreground/async-stop-action.ts +93 -3
- package/src/runs/foreground/execution.ts +91 -218
- package/src/runs/foreground/foreground-history.ts +2 -1
- package/src/runs/foreground/subagent-executor.ts +266 -80
- package/src/runs/shared/acceptance.ts +34 -10
- package/src/runs/shared/async-status-projection.ts +123 -33
- package/src/runs/shared/child-launch-plan.ts +15 -3
- package/src/runs/shared/child-launch.ts +19 -6
- package/src/runs/shared/child-runtime-config.ts +5 -0
- package/src/runs/shared/child-session.ts +94 -50
- package/src/runs/shared/child-tool-plan.ts +28 -16
- package/src/runs/shared/dynamic-fanout.ts +2 -2
- package/src/runs/shared/external-cli-contract.ts +11 -1
- package/src/runs/shared/external-cli-preflight.ts +6 -2
- package/src/runs/shared/herdr-connection.ts +134 -0
- package/src/runs/shared/herdr-external-adapters.ts +169 -0
- package/src/runs/shared/herdr-machine.ts +279 -0
- package/src/runs/shared/herdr-pi-protocol.ts +59 -0
- package/src/runs/shared/herdr-placed-run.ts +263 -0
- package/src/runs/shared/model-resolution-diagnostic.ts +76 -0
- package/src/runs/shared/{model-fallback.ts → model-resolution.ts} +22 -237
- package/src/runs/shared/model-scope.ts +1 -1
- package/src/runs/shared/nested-events.ts +11 -2
- package/src/runs/shared/parallel-utils.ts +7 -2
- package/src/runs/shared/pi-spawn.ts +1 -1
- package/src/runs/shared/subagent-prompt-runtime.ts +4 -2
- package/src/runs/shared/worktree-setup-command.ts +27 -4
- package/src/runs/shared/worktree.ts +3 -3
- package/src/shared/child-cache-retention.ts +43 -0
- package/src/shared/launch-contract.ts +6 -9
- package/src/shared/pruned-fork.ts +1 -1
- package/src/shared/required-child-extensions.ts +81 -0
- package/src/shared/settings.ts +5 -2
- package/src/shared/shortcuts.ts +0 -4
- package/src/shared/types.ts +70 -29
- package/src/slash/slash-commands.ts +0 -6
- package/src/slash/subagents-admin.ts +13 -9
- package/src/tui/render.ts +20 -10
- package/src/watchdog/child-status.ts +28 -36
- package/src/watchdog/lsp-diagnostics.ts +1 -1
- package/src/watchdog/model-selection.ts +1 -1
- package/src/watchdog/register-child.ts +10 -3
- package/src/watchdog/register-main.ts +20 -20
- package/src/watchdog/render.ts +1 -1
- package/src/watchdog/review.ts +14 -30
- package/src/watchdog/rules.ts +1 -1
- package/src/watchdog/runtime.ts +23 -12
- package/src/watchdog/settings.ts +3 -6
- package/src/watchdog/types.ts +3 -5
- package/src/watchdog/warning-format.ts +1 -1
- package/src/workflows/scripted-workflow.ts +42 -3
- package/src/workflows/workflow-receipt.ts +21 -3
- package/src/workflows/workflow-resources.ts +13 -2
- package/src/runs/shared/model-exclusions.ts +0 -374
- package/src/runs/shared/readonly-model-continuation.ts +0 -69
- package/src/runs/shared/readonly-session-evidence.ts +0 -307
package/runner-peer-preload.mjs
CHANGED
|
@@ -1,18 +1,32 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as nodeModule from "node:module";
|
|
2
2
|
import { pathToFileURL } from "node:url";
|
|
3
3
|
|
|
4
4
|
const aliases = JSON.parse(process.env.JITI_ALIAS ?? "{}");
|
|
5
|
+
const nativeRunner = process.env.PI_ASYNC_NATIVE_RUNNER === "1";
|
|
6
|
+
const compiledRunner = process.env.PI_ASYNC_COMPILED_RUNNER === "1";
|
|
7
|
+
// Pi's jiti loader owns aliases for external extensions; these hooks only supply peers to our compiled package.
|
|
8
|
+
const packageRootUrl = new URL("./", import.meta.url).href;
|
|
5
9
|
const redirected = new Set([
|
|
6
|
-
"@earendil-works/pi-server",
|
|
7
|
-
"@earendil-works/pi-server/unix",
|
|
8
10
|
"@earendil-works/pi-tui",
|
|
9
11
|
]);
|
|
10
12
|
|
|
11
|
-
registerHooks
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
if (typeof nodeModule.registerHooks === "function") {
|
|
14
|
+
nodeModule.registerHooks({
|
|
15
|
+
resolve(specifier, context, nextResolve) {
|
|
16
|
+
const packageImport = context.parentURL?.startsWith(packageRootUrl) === true;
|
|
17
|
+
if ((nativeRunner && (!compiledRunner || packageImport) ? aliases[specifier] : redirected.has(specifier) && aliases[specifier])) {
|
|
18
|
+
return nextResolve(pathToFileURL(aliases[specifier]).href, context);
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
return nextResolve(specifier, context);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (nativeRunner && specifier.endsWith(".js")) return nextResolve(`${specifier.slice(0, -3)}.ts`, context);
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
nodeModule.register(new URL("./runner-peer-loader.mjs", import.meta.url), {
|
|
30
|
+
data: { aliases, nativeRunner, compiledRunner, packageRootUrl },
|
|
31
|
+
});
|
|
32
|
+
}
|
|
@@ -1,28 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pi-subagents
|
|
3
3
|
description: |
|
|
4
|
-
|
|
5
|
-
review, scripted
|
|
6
|
-
|
|
7
|
-
supply focused context, planning, review, or execution.
|
|
4
|
+
Technical guidance for operator-requested delegation to builtin or custom
|
|
5
|
+
subagents: bounded handoffs, parallel review, scripted workflows, async work,
|
|
6
|
+
forked context, isolation, and coordinated execution.
|
|
8
7
|
---
|
|
9
8
|
|
|
10
9
|
# Pi Subagents
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- Direct parent edits during orchestrator mode should be intentional, small
|
|
25
|
-
interventions with a brief reason.
|
|
11
|
+
The parent works directly by default. Invoke subagents only when the operator
|
|
12
|
+
requested delegation in the current request or through applicable user/project
|
|
13
|
+
instructions. Task size, complexity, risk, tool-call count, recipe fit, or an
|
|
14
|
+
available specialist does not independently authorize delegation.
|
|
15
|
+
|
|
16
|
+
Once authorized, choose the smallest bounded shape that earns its token and
|
|
17
|
+
elapsed-time overhead through concrete evidence, independent review,
|
|
18
|
+
specialization, useful parallelism, or needed isolation. A single child is
|
|
19
|
+
valid; writer, challenge, and review stages must each earn their overhead rather
|
|
20
|
+
than becoming default ceremony. The parent keeps user intent, constraints,
|
|
21
|
+
routing, arbitration, decisions, final acceptance, and publication authority,
|
|
22
|
+
and may perform the work directly where it is the most efficient owner.
|
|
26
23
|
|
|
27
24
|
Children do not spawn subagents unless the parent explicitly delegated fanout
|
|
28
25
|
and their resolved `tools` allow `subagent`.
|
|
@@ -94,9 +91,9 @@ For exact API fields and worked examples, call `subagent({action:"guide",topic:"
|
|
|
94
91
|
| List, create, edit, disable, eject, or expose agents/RPC | `references/management-authoring-rpc.md` |
|
|
95
92
|
| Check safety constraints, recipes, or error handling | `references/constraints-and-recipes.md` |
|
|
96
93
|
|
|
97
|
-
For complex
|
|
98
|
-
|
|
99
|
-
review.
|
|
94
|
+
For an authorized complex delegated workflow, read `prompting-and-roles.md` and
|
|
95
|
+
`execution-controls.md`, then load `review-and-validation.md` and
|
|
96
|
+
`constraints-and-recipes.md` before launch or review.
|
|
100
97
|
|
|
101
98
|
## Operating rules
|
|
102
99
|
|
|
@@ -52,10 +52,11 @@ This reference keeps cross-cutting policy and failure handling. Load the matchin
|
|
|
52
52
|
| Independent lanes, repositories, worktrees, and handoffs | [`references/multi-lane-orchestration.md`](multi-lane-orchestration.md) |
|
|
53
53
|
| Agent management, file authoring, prompt integration, or RPC | [`references/management-authoring-rpc.md`](management-authoring-rpc.md) |
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
After delegation is operator-authorized, choose the smallest recipe that earns
|
|
56
|
+
its overhead. Recipes select a shape; they do not authorize delegation:
|
|
56
57
|
|
|
57
58
|
- **Recon → plan → implement:** run one focused `scout`, then one `worker` that consumes its findings.
|
|
58
|
-
- **
|
|
59
|
+
- **Implementation:** clarify scope and acceptance, record user-owned decisions and seam/validation contracts, and use a bounded scout, writer, or fresh reviewer only where the requested delegation benefits from that stage. Keep one writer, inspect direct evidence, and require every added stage to earn its overhead. Split large work into serial milestones instead of a writer swarm; do not stop at review without disposition.
|
|
59
60
|
- **Parallel analysis:** fan out only independent read/review/validation work, or isolate each writer in its own worktree. Never run concurrent writers in one checkout.
|
|
60
61
|
|
|
61
62
|
## Error Handling
|
|
@@ -24,7 +24,7 @@ Project settings resolve from the nearest parent directory containing `.pi` or `
|
|
|
24
24
|
|
|
25
25
|
An agent may set `runner.type: external-cli` with a non-empty `command`, optional string `args`, and `promptDelivery: stdin` (the default). The command runs with `shell: false`, inherits the resolved cwd and environment, and receives the combined agent instructions and task through stdin. It must already be installed; pi-subagents adds no CLI dependency.
|
|
26
26
|
|
|
27
|
-
External CLI profiles are async-only and one-shot. They support lifecycle artifacts, stdout/stderr logs, timeout, and stop. Full stdout and stderr are retained in their log files, while the final stdout response and stderr error kept in memory are each limited to their last 64 KiB. They do not support native Pi child options such as model override, structured output, acceptance/agent contract, tool budgets, fast mode, fork context, skills, or native Pi tools unless the runner explicitly implements them. Foreground/clarify, steer/resume/interrupt-as-pause, nested subagents,
|
|
27
|
+
External CLI profiles are async-only and one-shot. They support lifecycle artifacts, stdout/stderr logs, timeout, and stop. Full stdout and stderr are retained in their log files, while the final stdout response and stderr error kept in memory are each limited to their last 64 KiB. They do not support native Pi child options such as model override, structured output, acceptance/agent contract, tool budgets, fast mode, fork context, skills, or native Pi tools unless the runner explicitly implements them. Foreground/clarify, steer/resume/interrupt-as-pause, nested subagents, and sessions are also unsupported.
|
|
28
28
|
|
|
29
29
|
### External job profiles
|
|
30
30
|
|
|
@@ -32,7 +32,7 @@ An agent may set `runner.type: external-job` with a non-empty `provider` and opt
|
|
|
32
32
|
|
|
33
33
|
External job profiles are async-only. The provider owns the remote job and Pi owns the async run record. Status persists provider name, provider job id, prompt digest, provider options, handle/conversation URLs when supplied, result artifact path, last known state, and provider failure code/message. Recovery uses existing provider job metadata to call `reattach` and `result`; it refuses to redispatch a prompt when the persisted provider job does not match the prompt digest.
|
|
34
34
|
|
|
35
|
-
External job profiles do not support foreground/clarify, steer/resume, Pi models/tools/extensions/skills, tool budgets, structured output, native child permissions,
|
|
35
|
+
External job profiles do not support foreground/clarify, steer/resume, Pi models/tools/extensions/skills, tool budgets, structured output, native child permissions, or Pi child sessions. Capacity conflicts fail closed and include the blocking provider job id when the provider supplies it.
|
|
36
36
|
|
|
37
37
|
### Single agent
|
|
38
38
|
|
|
@@ -248,9 +248,9 @@ Use diagnostics when setup or child startup looks wrong:
|
|
|
248
248
|
subagent({ action: "doctor" })
|
|
249
249
|
```
|
|
250
250
|
|
|
251
|
-
### Failed lane recovery and execution-mode
|
|
251
|
+
### Failed lane recovery and execution-mode changes
|
|
252
252
|
|
|
253
|
-
A failure in the subagent workflow, child launch, prompt runtime, extension loading, or child tooling setup is a lane infrastructure blocker, not permission to silently change execution mode. Stop and report the exact failure, run/status, and repo/cwd/worktree/branch/ref state. Retry or fix the `subagent` path only through a clear same-protocol retry; before retrying or asking the owner, verify the worktree is clean or capture the partial diff. For backlog lanes and other subagent-governed workflows, switching to `interactive_shell`, `pi -ne`, Codex/Claude/Cursor CLI, a foreground agent, or another external mode requires explicit owner approval. Pi core may print a generic `pi -ne` extension-load hint; that hint is outside this package and is not protocol-approved
|
|
253
|
+
A failure in the subagent workflow, child launch, prompt runtime, extension loading, or child tooling setup is a lane infrastructure blocker, not permission to silently change execution mode. Stop and report the exact failure, run/status, and repo/cwd/worktree/branch/ref state. Retry or fix the `subagent` path only through a clear same-protocol retry; before retrying or asking the owner, verify the worktree is clean or capture the partial diff. For backlog lanes and other subagent-governed workflows, switching to `interactive_shell`, `pi -ne`, Codex/Claude/Cursor CLI, a foreground agent, or another external mode requires explicit owner approval. Pi core may print a generic `pi -ne` extension-load hint; that hint is outside this package and is not protocol-approved. A verified compaction abort may continue the retained child session once on the same resolved model; provider failures never select another model automatically.
|
|
254
254
|
|
|
255
255
|
### External terminal work
|
|
256
256
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use this reference when several independent tasks need coordinated workers, worktrees, or repositories. It defines lane ownership; use the other pi-subagents references for run controls, prompts, and mission details. The parent remains the final decision-maker.
|
|
4
4
|
|
|
5
|
-
Create lanes only
|
|
5
|
+
Create lanes only after delegation is operator-authorized and each lane materially improves evidence, independent review, specialization, useful parallelism, or isolated execution. Do not manufacture parallelism: keep dependent work serial, and only split work when each lane has a distinct decision and useful output.
|
|
6
6
|
|
|
7
7
|
## Lane board and authority
|
|
8
8
|
|
|
@@ -8,12 +8,17 @@ Parent extensions may register a session-scoped, out-of-band ceiling through `pi
|
|
|
8
8
|
|
|
9
9
|
## When to Use
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
All launch guidance below assumes delegation was requested by the operator in
|
|
12
|
+
the current request or applicable user/project instructions. Complexity,
|
|
13
|
+
workflow fit, and potential quality gains help choose a shape after that gate;
|
|
14
|
+
they do not authorize a launch.
|
|
15
|
+
|
|
16
|
+
- **Complex work orchestration**: after delegation is authorized, keep the parent on its ordinary strong default model and launch only when a bounded child materially improves evidence, independent review, specialization, useful parallelism, or isolated execution. For hard orchestration or root-cause questions, use a top-reasoning model only as a bounded read-only critic/oracle escalation, never as an autonomous root. Lightweight one-off delegation can stay lightweight.
|
|
12
17
|
- **Advisory review**: use fresh-context `reviewer` agents for adversarial code review; fork to `oracle` only for rare escalation where inherited decisions, drift, model routing, root cause, or hard tradeoffs matter
|
|
13
18
|
- **Implementation handoff**: have `oracle` advise, then `worker` implement only after an approved direction
|
|
14
19
|
- **Recon and planning**: use `scout`, then write a plan when needed
|
|
15
20
|
- **Parallel exploration**: run multiple non-conflicting tasks concurrently
|
|
16
|
-
- **Regular skill specialists**: when
|
|
21
|
+
- **Regular skill specialists**: when authorized delegation names or benefits from a relevant specialization, discovery suggestions may help select a small fresh-context fanout
|
|
17
22
|
- **Long-running work**: launch async/background runs and inspect them later. For mutation-capable work, bound the delivery slice and elapsed runtime, then request checkpoints after active tool work returns. Reserve hard tool-call caps for explicitly read-only children.
|
|
18
23
|
- **Subagent control**: watch needs-attention signals and soft-interrupt only when a delegated run is genuinely blocked
|
|
19
24
|
- **Agent authoring**: create, update, or override project agents. Treat saved chain records as legacy inspection or migration inputs, not as a current authoring target.
|
|
@@ -29,7 +34,7 @@ Agents use the `subagent(...)` tool for execution, management, status, and contr
|
|
|
29
34
|
- `/subagents-detach [run-id]` — detach an active foreground single-subagent run without terminating its child
|
|
30
35
|
- `/subagents-steer <run-id> [--child <child-id>] <message>` — steer a live async run (or one child of it) from non-TUI sessions and RPC hosts
|
|
31
36
|
- `/subagent-cost` — show parent plus child token usage and cost for the session
|
|
32
|
-
- `/subagents-fleet` — open the live fleet inspector with per-child controls;
|
|
37
|
+
- `/subagents-fleet` — open the live fleet inspector with per-child controls; `↑↓`/`jk` selects children, `PgUp`/`PgDn` scrolls transcript detail, `s` steers the selected live async child, and `D` stops its top-level async run after confirmation
|
|
33
38
|
- `/subagents-watchdog` — inspect or configure the opt-in adversarial change watchdog (model, on/off, recommend-model, check)
|
|
34
39
|
- `/subagents-doctor` — diagnose setup, discovery, async paths, and intercom bridge state
|
|
35
40
|
- `/subagents-models [agent]` — show the live runtime-loaded builtin model mapping
|
|
@@ -39,7 +44,7 @@ Agents use the `subagent(...)` tool for execution, management, status, and contr
|
|
|
39
44
|
Prefer the tool when you are writing agent logic. Prefer the slash commands when
|
|
40
45
|
you are guiding a human through an interactive flow.
|
|
41
46
|
|
|
42
|
-
Packaged prompt shortcuts are also available for repeatable workflows. Treat them as reusable orchestration recipes, not just human slash commands. When the user asks for one of these shapes,
|
|
47
|
+
Packaged prompt shortcuts are also available for repeatable workflows. Treat them as reusable orchestration recipes, not just human slash commands. When the user asks for one of these shapes, apply the same pattern directly with `subagent(...)` and other tools:
|
|
43
48
|
- `/parallel-review` — fresh-context reviewers with distinct review angles, then synthesis
|
|
44
49
|
- `/review-loop` — parent-orchestrated worker, fresh-reviewer, and fix-worker cycles until clean or capped
|
|
45
50
|
- `/parallel-research` — combine `researcher` and `scout` for external evidence plus local code context
|
|
@@ -53,7 +58,7 @@ The prompt templates in `prompts/` encode workflows the parent agent can run on
|
|
|
53
58
|
|
|
54
59
|
### Commission-risk and cold-start packets
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
After the operator-authority gate above, delegate only when the child materially improves evidence, independent review, specialization, useful parallelism, or isolated execution; do not manufacture parallelism. Every child packet must be cold-start complete: state the goal, exact target/cwd/ref, authority and edit boundary, relevant context/evidence, success criteria, validation, output, and stop/escalation rules. For an orchestration audit by the critic tier, make the child read-only and request at most three omissions, each cited to a file, line, or decision; high thinking is an explicit escalation, not a default.
|
|
57
62
|
|
|
58
63
|
### Council Mode technique
|
|
59
64
|
|
|
@@ -67,7 +72,7 @@ Use this when the user wants adversarial review of a diff, plan, issue, file, or
|
|
|
67
72
|
|
|
68
73
|
### Proactive skill-specialist technique
|
|
69
74
|
|
|
70
|
-
Use this when `{ action: "list" }` reports
|
|
75
|
+
Use this only within operator-authorized delegation when `{ action: "list" }` reports skill subagent suggestions relevant to the requested handoff. Availability is a selection hint, not authority or a command to fan out.
|
|
71
76
|
|
|
72
77
|
Default guardrails:
|
|
73
78
|
- Keep the fanout small: usually one or two skill-specialist children, never more than the listed recommendations or configured cap.
|
|
@@ -105,11 +110,11 @@ Use this when the question needs both external evidence and local implications.
|
|
|
105
110
|
|
|
106
111
|
### Gather-context-and-clarify technique
|
|
107
112
|
|
|
108
|
-
Use this
|
|
113
|
+
Use this when the operator requests delegated context gathering. Launch `scout` for local context and `researcher` only when external docs, recent sources, ecosystem context, or primary evidence would materially improve understanding. Ask children for concise findings plus remaining clarification questions. Then synthesize what is known and use `interview` to ask the unresolved questions needed for shared understanding before planning or implementing.
|
|
109
114
|
|
|
110
115
|
### Parallel cleanup technique
|
|
111
116
|
|
|
112
|
-
Use this after implementation when the user
|
|
117
|
+
Use this after implementation when the user or applicable instructions request delegated cleanup review. Launch two fresh-context `reviewer` tasks with `output: false` and `progress: false`: one deslop pass and one verbosity pass. If the `deslop` or `verbosity-cleaner` skills are available, pass the relevant skill to that reviewer; otherwise inline the criteria. Both reviewers are review-only and should flag concrete issues with severity, file/line references, and smallest safe fixes. Phrase the constraint as “Do not modify project/source files; returning findings through the configured output artifact is allowed” when you use `output` or `outputMode: "file-only"`. The parent decides what to apply and asks before making changes unless cleanup was already authorized.
|
|
113
118
|
|
|
114
119
|
### Staged fix orchestration technique
|
|
115
120
|
|
|
@@ -203,7 +208,7 @@ For one run, use inline config:
|
|
|
203
208
|
|
|
204
209
|
For persistent tweaks, edit `subagents.agentOverrides` in user or project settings. User overrides apply everywhere. Project overrides apply only in that repo and win over user overrides. Use `/subagents-models` or `subagent({ action: "models" })` to inspect the live mapping after settings and overrides load.
|
|
205
210
|
|
|
206
|
-
Provider-scoped entries can layer on top of the default override for the active parent session provider. The provider is selected once from the parent model
|
|
211
|
+
Provider-scoped entries can layer on top of the default override for the active parent session provider. The provider is selected once from the parent model. Within each settings file, the provider entry wins per field; project settings still win over user settings.
|
|
207
212
|
|
|
208
213
|
```json
|
|
209
214
|
{
|
|
@@ -261,7 +266,6 @@ Direct settings example:
|
|
|
261
266
|
"reviewer": {
|
|
262
267
|
"model": "provider/strong-review-model",
|
|
263
268
|
"thinking": "high",
|
|
264
|
-
"fallbackModels": ["backup-provider/strong-review-model"],
|
|
265
269
|
"acceptanceRole": "read-only"
|
|
266
270
|
}
|
|
267
271
|
}
|
|
@@ -269,7 +273,7 @@ Direct settings example:
|
|
|
269
273
|
}
|
|
270
274
|
```
|
|
271
275
|
|
|
272
|
-
Useful override fields: `description`, `model`, `
|
|
276
|
+
Useful override fields: `description`, `model`, `thinking`,
|
|
273
277
|
`systemPromptMode`, `inheritProjectContext`, `inheritGlobalContext`, `inheritSkills`, `defaultContext`,
|
|
274
278
|
`acceptanceRole`, `disabled`, `skills`, `tools`, `extensions`, and `systemPrompt`.
|
|
275
279
|
`description` replaces the discovered description for builtin and custom agents
|
|
@@ -283,7 +287,7 @@ Keep the parent/orchestrator on the ordinary strong default model because omissi
|
|
|
283
287
|
|
|
284
288
|
Examples are illustrative, not requirements. Map these tiers to concrete models in user/project settings or a profile. A non-OpenAI setup should choose comparable available models by capability.
|
|
285
289
|
|
|
286
|
-
|
|
290
|
+
Each child launch uses one resolved model exactly once. If quota or availability fails, surface that failure and let the parent or operator explicitly launch a later attempt with another model. Forked children keep their requested thinking level even when provider-specific reasoning blocks are stripped from the inherited transcript.
|
|
287
291
|
|
|
288
292
|
If a provider rejects model IDs with thinking suffixes, use
|
|
289
293
|
`subagents.disableThinking: true` in user or project settings to clear bundled
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pi Subagents: Review And Validation
|
|
2
2
|
|
|
3
|
-
Generic review and delivery guidance for delegated work. This file does not encode private backlog, merge, or release policy.
|
|
3
|
+
Generic review and delivery guidance for operator-authorized delegated work. This file does not encode private backlog, merge, or release policy.
|
|
4
4
|
|
|
5
5
|
## Delivery loop
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ Use the smallest loop that proves the change:
|
|
|
9
9
|
1. Inspect the source, diff, issue, or plan directly.
|
|
10
10
|
2. Keep one writer for each cwd or worktree.
|
|
11
11
|
3. Run focused validation that can fail for the changed behavior.
|
|
12
|
-
4.
|
|
12
|
+
4. When the operator/project delegation contract calls for independent review, use a fresh-context read-only reviewer; otherwise parent inspection is valid.
|
|
13
13
|
5. Apply only accepted findings inside the same writer boundary.
|
|
14
14
|
6. Re-run affected validation and review only the changed blast radius.
|
|
15
15
|
7. Inspect the final diff and evidence before parent acceptance.
|
|
@@ -61,7 +61,7 @@ Before reporting delegated work as done, verify the relevant subset:
|
|
|
61
61
|
|
|
62
62
|
- final diff contains only intended files
|
|
63
63
|
- focused validation covers changed behavior
|
|
64
|
-
-
|
|
64
|
+
- required independent review has fresh-review evidence
|
|
65
65
|
- accepted findings are fixed and revalidated
|
|
66
66
|
- publication authority exists before push, comment, close, merge, deploy, or release
|
|
67
67
|
- external checks are exact-head when used as evidence
|
|
@@ -28,9 +28,9 @@ import {
|
|
|
28
28
|
} from "./proactive-skills.ts";
|
|
29
29
|
import { parseFrontmatter, parseFrontmatterList } from "./frontmatter.ts";
|
|
30
30
|
import { resolveEffectiveThinking, toModelInfo } from "../shared/model-info.ts";
|
|
31
|
-
import { resolveSubagentModelOverride, type ParentModel } from "../runs/shared/model-
|
|
31
|
+
import { resolveSubagentModelOverride, type ParentModel } from "../runs/shared/model-resolution.ts";
|
|
32
32
|
import { validateToolBudgetConfig } from "../runs/shared/tool-budget.ts";
|
|
33
|
-
import { validateAcceptanceInput } from "../runs/shared/acceptance.ts";
|
|
33
|
+
import { formatReviewGateLabel, validateAcceptanceInput } from "../runs/shared/acceptance.ts";
|
|
34
34
|
import { CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL, isCodeOwnedExternalCliAdapterId, resolveExternalCliRunnerStatus, validateCodeOwnedProfileRunner } from "../runs/shared/external-cli-contract.ts";
|
|
35
35
|
import { resolveExternalCliBinaryAvailability, type ExternalCliBinaryAvailability } from "../runs/shared/external-cli-preflight.ts";
|
|
36
36
|
import type { AcceptanceInput, AgentCapabilitiesSnapshot, AgentCapabilityRow, Details, ExtensionConfig, ToolBudgetConfig } from "../shared/types.ts";
|
|
@@ -218,13 +218,6 @@ function modelWarning(ctx: ManagementContext, model: string | undefined): string
|
|
|
218
218
|
return `Warning: model '${model}' is not in the current model registry. Run subagent({ action: "models" }) to list valid provider/id selectors, then use the exact provider/id form (bare ids resolve only when unique).`;
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
function fallbackModelsWarning(ctx: ManagementContext, fallbackModels: string[] | undefined): string | undefined {
|
|
222
|
-
if (!fallbackModels || fallbackModels.length === 0) return undefined;
|
|
223
|
-
const available = new Set(ctx.modelRegistry.getAvailable().flatMap((m) => [`${m.provider}/${m.id}`, m.id]));
|
|
224
|
-
const missing = fallbackModels.filter((model) => !available.has(model));
|
|
225
|
-
return missing.length ? `Warning: fallback models not in the current model registry: ${missing.join(", ")}.` : undefined;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
221
|
function skillsWarning(cwd: string, agent: Pick<AgentConfig, "skills" | "skillPath" | "filePath">): string | undefined {
|
|
229
222
|
if (!agent.skills?.length) return undefined;
|
|
230
223
|
const { missing } = resolveSkills(
|
|
@@ -268,7 +261,6 @@ export function editableAgentConfig(agent: AgentConfig): AgentConfig {
|
|
|
268
261
|
outputMode: _outputMode,
|
|
269
262
|
defaultReads: _defaultReads,
|
|
270
263
|
model: _model,
|
|
271
|
-
fallbackModels: _fallbackModels,
|
|
272
264
|
fast: _fast,
|
|
273
265
|
thinking: _thinking,
|
|
274
266
|
systemPromptMode: _systemPromptMode,
|
|
@@ -305,7 +297,6 @@ export function editableAgentConfig(agent: AgentConfig): AgentConfig {
|
|
|
305
297
|
...(base.outputMode !== undefined ? { outputMode: base.outputMode } : {}),
|
|
306
298
|
...(base.defaultReads !== undefined ? { defaultReads: [...base.defaultReads] } : {}),
|
|
307
299
|
...(base.model !== undefined && hasDeclaredField("model") ? { model: base.model } : {}),
|
|
308
|
-
...(base.fallbackModels !== undefined ? { fallbackModels: [...base.fallbackModels] } : {}),
|
|
309
300
|
...(base.fast !== undefined ? { fast: base.fast } : {}),
|
|
310
301
|
...(base.thinking !== undefined && hasDeclaredField("thinking") ? { thinking: base.thinking } : {}),
|
|
311
302
|
systemPromptMode: base.systemPromptMode,
|
|
@@ -353,7 +344,6 @@ export function preservedAgentFrontmatterFields(agent: AgentConfig, cfg: Record<
|
|
|
353
344
|
if (hasKey(cfg, "systemPrompt")) changed("systemPrompt");
|
|
354
345
|
if (hasKey(cfg, "runner")) changed("runner");
|
|
355
346
|
if (hasKey(cfg, "model")) changed("model");
|
|
356
|
-
if (hasKey(cfg, "fallbackModels")) changed("fallbackModels");
|
|
357
347
|
if (hasKey(cfg, "tools")) changed("tools");
|
|
358
348
|
if (hasKey(cfg, "excludeTools")) changed("excludeTools");
|
|
359
349
|
if (hasKey(cfg, "skills")) changed("skill", "skills");
|
|
@@ -466,21 +456,7 @@ function applyAgentConfig(target: AgentConfig, cfg: Record<string, unknown>): st
|
|
|
466
456
|
else delete target.model;
|
|
467
457
|
} else return "config.model must be a string or false when provided.";
|
|
468
458
|
}
|
|
469
|
-
if (hasKey(cfg, "fallbackModels"))
|
|
470
|
-
if (cfg.fallbackModels === false || cfg.fallbackModels === "") delete target.fallbackModels;
|
|
471
|
-
else if (typeof cfg.fallbackModels === "string") {
|
|
472
|
-
const models = parseCsv(cfg.fallbackModels);
|
|
473
|
-
if (models.length) target.fallbackModels = models;
|
|
474
|
-
else delete target.fallbackModels;
|
|
475
|
-
} else if (Array.isArray(cfg.fallbackModels)) {
|
|
476
|
-
const models = cfg.fallbackModels
|
|
477
|
-
.filter((value): value is string => typeof value === "string")
|
|
478
|
-
.map((value) => value.trim())
|
|
479
|
-
.filter(Boolean);
|
|
480
|
-
if (models.length) target.fallbackModels = [...new Set(models)];
|
|
481
|
-
else delete target.fallbackModels;
|
|
482
|
-
} else return "config.fallbackModels must be a comma-separated string, string array, or false when provided.";
|
|
483
|
-
}
|
|
459
|
+
if (hasKey(cfg, "fallbackModels")) return "config.fallbackModels was removed; configure one model instead.";
|
|
484
460
|
if (hasKey(cfg, "tools")) {
|
|
485
461
|
if (cfg.tools === false || cfg.tools === "") { delete target.tools; delete target.mcpDirectTools; }
|
|
486
462
|
else if (typeof cfg.tools === "string") {
|
|
@@ -637,7 +613,6 @@ function applyAgentConfig(target: AgentConfig, cfg: Record<string, unknown>): st
|
|
|
637
613
|
target.tools?.length || target.mcpDirectTools?.length ? "tools" : undefined,
|
|
638
614
|
target.excludeTools?.length ? "excludeTools" : undefined,
|
|
639
615
|
target.model ? "model" : undefined,
|
|
640
|
-
target.fallbackModels?.length ? "fallbackModels" : undefined,
|
|
641
616
|
target.thinking ? "thinking" : undefined,
|
|
642
617
|
target.extensions?.length ? "extensions" : undefined,
|
|
643
618
|
target.subagentOnlyExtensions?.length ? "subagentOnlyExtensions" : undefined,
|
|
@@ -713,13 +688,19 @@ function externalJobProviderSuffix(provider: string, names: Set<string> | undefi
|
|
|
713
688
|
|
|
714
689
|
type ExternalCliAvailabilityByCommand = ReadonlyMap<string, ExternalCliBinaryAvailability>;
|
|
715
690
|
|
|
691
|
+
/** A placed agent checks only local ssh; machine catalog and remote CLI validation happen at launch. */
|
|
692
|
+
function externalCliAvailabilityKey(command: string, machine: string | undefined): string {
|
|
693
|
+
return machine ? `ssh@${machine}` : command;
|
|
694
|
+
}
|
|
695
|
+
|
|
716
696
|
function externalCliAvailabilityForAgents(agents: readonly AgentConfig[]): ExternalCliAvailabilityByCommand {
|
|
717
697
|
const availability = new Map<string, ExternalCliBinaryAvailability>();
|
|
718
698
|
for (const agent of agents) {
|
|
719
699
|
const runner = agent.runner;
|
|
720
|
-
if (runner?.type
|
|
721
|
-
|
|
722
|
-
|
|
700
|
+
if (runner?.type !== "external-cli") continue;
|
|
701
|
+
const key = externalCliAvailabilityKey(runner.command, agent.machine);
|
|
702
|
+
if (availability.has(key)) continue;
|
|
703
|
+
availability.set(key, resolveExternalCliBinaryAvailability(agent.machine ? "ssh" : runner.command, process.env));
|
|
723
704
|
}
|
|
724
705
|
return availability;
|
|
725
706
|
}
|
|
@@ -727,10 +708,13 @@ function externalCliAvailabilityForAgents(agents: readonly AgentConfig[]): Exter
|
|
|
727
708
|
function runnerListBadge(agent: AgentConfig, providerNames: Set<string> | undefined, externalCliAvailability?: ExternalCliAvailabilityByCommand): string | undefined {
|
|
728
709
|
if (agent.runner?.type === "external-job") return `external-job:${agent.runner.provider} ${externalJobProviderSuffix(agent.runner.provider, providerNames)}`;
|
|
729
710
|
if (agent.runner?.type === "external-cli") {
|
|
730
|
-
const
|
|
731
|
-
|
|
732
|
-
return `external-cli:${
|
|
711
|
+
const placed = agent.machine ? `${agent.runner.command} @ ${agent.machine}` : agent.runner.command;
|
|
712
|
+
const availability = externalCliAvailability?.get(externalCliAvailabilityKey(agent.runner.command, agent.machine));
|
|
713
|
+
if (!availability) return `external-cli:${placed}`;
|
|
714
|
+
if (agent.machine) return `external-cli:${placed} saved Herdr placement; transport ${availability.available ? "✓" : "missing"}; machine not preflighted`;
|
|
715
|
+
return `external-cli:${placed} ${availability.available ? "✓" : "missing"}`;
|
|
733
716
|
}
|
|
717
|
+
if (agent.machine) return `machine: ${agent.machine} (saved Herdr placement)`;
|
|
734
718
|
return undefined;
|
|
735
719
|
}
|
|
736
720
|
|
|
@@ -766,7 +750,39 @@ function formatAgentCapabilitiesLine(agent: AgentConfig, providerNames: Set<stri
|
|
|
766
750
|
if (agent.modelProvider && !agent.model.includes("/")) model = `${agent.modelProvider}/${agent.model}`;
|
|
767
751
|
}
|
|
768
752
|
const thinking = agent.thinking === false ? "off" : agent.thinking ?? "default";
|
|
769
|
-
|
|
753
|
+
const machine = agent.machine ? `; Machine: ${agent.machine} (saved Herdr placement)` : "";
|
|
754
|
+
const acceptance = formatAcceptanceSummary(agent);
|
|
755
|
+
return `- ${agent.name} (${agentListMetadata(agent, providerNames, externalCliAvailability)}): Description: ${previewDisplayText(agent.description, 240)}; Tools: ${tools}; Model: ${model}; Thinking: ${thinking}${machine}${acceptance ? `; ${acceptance}` : ""}`;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function formatAcceptanceSummary(agent: AgentConfig): string | undefined {
|
|
759
|
+
const policy = agent.defaultAcceptance;
|
|
760
|
+
const summary: string[] = [];
|
|
761
|
+
if (policy === false) summary.push("Acceptance: disabled");
|
|
762
|
+
else if (typeof policy === "string") summary.push(`Acceptance: ${policy}`);
|
|
763
|
+
else if (policy) {
|
|
764
|
+
const modifiers = [
|
|
765
|
+
...(policy.evidence ?? []),
|
|
766
|
+
...(policy.verify ?? []).map((command) => `verify: ${formatAcceptanceDisplayLabel(command.id)}`),
|
|
767
|
+
...(policy.criteria?.length ? [`criteria: ${policy.criteria.length}`] : []),
|
|
768
|
+
...(policy.stopRules?.length ? [`stopRules: ${policy.stopRules.length}`] : []),
|
|
769
|
+
];
|
|
770
|
+
if (policy.review === false) modifiers.push("review: off");
|
|
771
|
+
else if (policy.review) {
|
|
772
|
+
const displayReview = policy.review.agent
|
|
773
|
+
? { ...policy.review, agent: formatAcceptanceDisplayLabel(policy.review.agent) }
|
|
774
|
+
: policy.review;
|
|
775
|
+
modifiers.push(`review: ${formatReviewGateLabel(displayReview)}`);
|
|
776
|
+
}
|
|
777
|
+
if (policy.report) modifiers.push(`report: ${policy.report}`);
|
|
778
|
+
summary.push(`Acceptance: ${policy.level ?? "auto"}${modifiers.length > 0 ? ` (${modifiers.join(", ")})` : ""}`);
|
|
779
|
+
}
|
|
780
|
+
if (agent.acceptanceRole) summary.push(`Acceptance role: ${agent.acceptanceRole}`);
|
|
781
|
+
return summary.length > 0 ? summary.join("; ") : undefined;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function formatAcceptanceDisplayLabel(value: string): string {
|
|
785
|
+
return JSON.stringify(previewDisplayText(value, 80));
|
|
770
786
|
}
|
|
771
787
|
|
|
772
788
|
const EXTERNAL_JOB_CAPABILITIES = { stop: false, steer: false, resume: false, structuredOutput: false, toolEvents: false } as const;
|
|
@@ -780,11 +796,12 @@ function agentCapabilityRunner(agent: AgentConfig, providerNames: Set<string> |
|
|
|
780
796
|
const runner = agent.runner;
|
|
781
797
|
if (!runner || runner.type === "pi") return PI_AGENT_RUNNER;
|
|
782
798
|
if (runner.type === "external-cli") {
|
|
783
|
-
const availability = externalCliAvailability.get(runner.command)!;
|
|
799
|
+
const availability = externalCliAvailability.get(externalCliAvailabilityKey(runner.command, agent.machine))!;
|
|
784
800
|
return {
|
|
785
801
|
type: "external-cli",
|
|
786
802
|
adapter: runner.adapter,
|
|
787
803
|
command: runner.command,
|
|
804
|
+
...(agent.machine ? { machine: agent.machine } : {}),
|
|
788
805
|
...availability,
|
|
789
806
|
capabilities: resolveExternalCliRunnerStatus(runner).capabilities,
|
|
790
807
|
};
|
|
@@ -812,8 +829,9 @@ function agentCapabilityRow(agent: AgentConfig, options: { executable: boolean;
|
|
|
812
829
|
aliases: agent.aliases ? [...agent.aliases] : undefined,
|
|
813
830
|
runner: agentCapabilityRunner(agent, options.providerNames, options.externalCliAvailability),
|
|
814
831
|
tools: agentCapabilityTools(agent),
|
|
815
|
-
model: presentDetails({ value: agent.model,
|
|
832
|
+
model: presentDetails({ value: agent.model, thinking: agent.thinking }),
|
|
816
833
|
execution: presentDetails({ defaultAsync: agent.defaultAsync, timeoutMs: agent.defaultTimeoutMs }),
|
|
834
|
+
acceptance: presentDetails({ policy: agent.defaultAcceptance, role: agent.acceptanceRole }),
|
|
817
835
|
output: presentDetails({ path: agent.output, mode: agent.outputMode }),
|
|
818
836
|
extensions: presentDetails({ names: agent.extensions, subagentOnly: agent.subagentOnlyExtensions, skills: agent.skills }),
|
|
819
837
|
};
|
|
@@ -914,7 +932,6 @@ function formatAgentDetail(agent: AgentConfig): string {
|
|
|
914
932
|
}
|
|
915
933
|
if (agent.aliases?.length) lines.push(`Aliases: ${agent.aliases.join(", ")}`);
|
|
916
934
|
if (agent.model) lines.push(`Model: ${agent.model}`);
|
|
917
|
-
if (agent.fallbackModels?.length) lines.push(`Fallback models: ${agent.fallbackModels.join(", ")}`);
|
|
918
935
|
if (tools.length) lines.push(`Tools: ${tools.join(", ")}`);
|
|
919
936
|
if (agent.excludeTools?.length) lines.push(`Excluded tools: ${agent.excludeTools.join(", ")}`);
|
|
920
937
|
if (agent.skills?.length) lines.push(`Skills: ${agent.skills.join(", ")}`);
|
|
@@ -1057,12 +1074,6 @@ function handleModels(params: ManagementParams, ctx: ManagementContext): AgentTo
|
|
|
1057
1074
|
lines.push(` ${resolvedModel ?? "(unresolved)"}`);
|
|
1058
1075
|
lines.push(`Source: ${source}`);
|
|
1059
1076
|
lines.push(`Thinking: ${effectiveThinking ?? "default"}`);
|
|
1060
|
-
if (agent.fallbackModels?.length) {
|
|
1061
|
-
lines.push("Fallback models:");
|
|
1062
|
-
for (const fallback of agent.fallbackModels) {
|
|
1063
|
-
lines.push(` ${resolveSubagentModelOverride(fallback, currentModel, availableModels, agent.modelProvider ?? preferredProvider) ?? fallback}`);
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
1077
|
if (agent.override) {
|
|
1067
1078
|
lines.push("Override file:");
|
|
1068
1079
|
lines.push(` ${agent.override.path}`);
|
|
@@ -1082,12 +1093,6 @@ function handleModels(params: ManagementParams, ctx: ManagementContext): AgentTo
|
|
|
1082
1093
|
lines.push(` ${resolvedModel ?? "(unresolved)"}`);
|
|
1083
1094
|
lines.push(` source: ${source}`);
|
|
1084
1095
|
lines.push(` thinking: ${effectiveThinking ?? "default"}`);
|
|
1085
|
-
if (agent.fallbackModels?.length) {
|
|
1086
|
-
lines.push(" fallback models:");
|
|
1087
|
-
for (const fallback of agent.fallbackModels) {
|
|
1088
|
-
lines.push(` ${resolveSubagentModelOverride(fallback, currentModel, availableModels, agent.modelProvider ?? preferredProvider) ?? fallback}`);
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
1096
|
if (agent.override) {
|
|
1092
1097
|
lines.push(" override file:");
|
|
1093
1098
|
lines.push(` ${agent.override.path}`);
|
|
@@ -1177,8 +1182,6 @@ export function handleCreate(params: ManagementParams, ctx: ManagementContext):
|
|
|
1177
1182
|
if (profileError) return result(profileError, true);
|
|
1178
1183
|
const mw = modelWarning(ctx, agent.model);
|
|
1179
1184
|
if (mw) warnings.push(mw);
|
|
1180
|
-
const fmw = fallbackModelsWarning(ctx, agent.fallbackModels);
|
|
1181
|
-
if (fmw) warnings.push(fmw);
|
|
1182
1185
|
const sw = skillsWarning(ctx.cwd, agent);
|
|
1183
1186
|
if (sw) warnings.push(sw);
|
|
1184
1187
|
fs.writeFileSync(targetPath, serializeAgent(agent), "utf-8");
|
|
@@ -1234,10 +1237,6 @@ export function handleUpdate(params: ManagementParams, ctx: ManagementContext):
|
|
|
1234
1237
|
const mw = modelWarning(ctx, updated.model);
|
|
1235
1238
|
if (mw) warnings.push(mw);
|
|
1236
1239
|
}
|
|
1237
|
-
if (hasKey(cfg, "fallbackModels")) {
|
|
1238
|
-
const fmw = fallbackModelsWarning(ctx, updated.fallbackModels);
|
|
1239
|
-
if (fmw) warnings.push(fmw);
|
|
1240
|
-
}
|
|
1241
1240
|
if (hasKey(cfg, "skills") || hasKey(cfg, "skillPath")) {
|
|
1242
1241
|
const sw = skillsWarning(ctx.cwd, updated);
|
|
1243
1242
|
if (sw) warnings.push(sw);
|
|
@@ -1385,8 +1384,8 @@ function handleReset(params: ManagementParams, ctx: ManagementContext): AgentToo
|
|
|
1385
1384
|
fs.unlinkSync(custom.filePath);
|
|
1386
1385
|
lines.push(`Deleted custom ${scope} agent file at ${custom.filePath}.`);
|
|
1387
1386
|
}
|
|
1388
|
-
const overrideRemoval = removeBuiltinAgentOverride(ctx.cwd, runtimeName, scope);
|
|
1389
|
-
if (overrideRemoval.removed) lines.push(
|
|
1387
|
+
const overrideRemoval = removeBuiltinAgentOverride(ctx.cwd, runtimeName, scope, { preserveMachine: true });
|
|
1388
|
+
if (overrideRemoval.removed) lines.push(`${overrideRemoval.machinePreserved ? "Cleared customization in" : "Removed"} ${scope} settings override at ${overrideRemoval.path}.${overrideRemoval.machinePreserved ? " Retained machine placement." : ""}`);
|
|
1390
1389
|
if (lines.length === 0) {
|
|
1391
1390
|
const otherScope = scope === "user" ? "project" : "user";
|
|
1392
1391
|
const otherCustom = (otherScope === "user" ? d.user : d.project).find((a) => a.name === raw || a.name === sanitized);
|
|
@@ -13,7 +13,6 @@ export const KNOWN_FIELDS = new Set([
|
|
|
13
13
|
"excludeTools",
|
|
14
14
|
"allowNestedSubagents",
|
|
15
15
|
"model",
|
|
16
|
-
"fallbackModels",
|
|
17
16
|
"fast",
|
|
18
17
|
"thinking",
|
|
19
18
|
"systemPromptMode",
|
|
@@ -32,8 +31,10 @@ export const KNOWN_FIELDS = new Set([
|
|
|
32
31
|
"extensions",
|
|
33
32
|
"subagentOnlyExtensions",
|
|
34
33
|
"mutationTools",
|
|
34
|
+
"machine",
|
|
35
35
|
"output",
|
|
36
36
|
"outputMode",
|
|
37
|
+
"outputSchema",
|
|
37
38
|
"defaultReads",
|
|
38
39
|
"defaultProgress",
|
|
39
40
|
"interactive",
|
|
@@ -80,8 +81,6 @@ export function serializeAgent(config: AgentConfig, options: SerializeAgentOptio
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
if (config.model || preserve("model")) lines.push(`model: ${config.model ?? ""}`);
|
|
83
|
-
const fallbackModelsValue = joinComma(config.fallbackModels);
|
|
84
|
-
if (fallbackModelsValue || preserve("fallbackModels")) lines.push(`fallbackModels: ${fallbackModelsValue ?? ""}`);
|
|
85
84
|
if (config.fast === true || preserve("fast")) lines.push(`fast: ${config.fast === undefined ? "" : config.fast ? "true" : "false"}`);
|
|
86
85
|
if ((config.thinking && (config.thinking !== "off" || preserve("thinking"))) || (!config.thinking && preserve("thinking"))) {
|
|
87
86
|
lines.push(`thinking: ${config.thinking ?? ""}`);
|
|
@@ -127,8 +126,10 @@ export function serializeAgent(config: AgentConfig, options: SerializeAgentOptio
|
|
|
127
126
|
const mutationToolsValue = joinComma(config.mutationTools);
|
|
128
127
|
if (mutationToolsValue || preserve("mutationTools")) lines.push(`mutationTools: ${mutationToolsValue ?? ""}`);
|
|
129
128
|
|
|
129
|
+
if (config.machine || preserve("machine")) lines.push(`machine: ${config.machine ?? ""}`);
|
|
130
130
|
if (config.output || preserve("output")) lines.push(`output: ${config.output ?? ""}`);
|
|
131
131
|
if (config.outputMode || preserve("outputMode")) lines.push(`outputMode: ${config.outputMode ?? ""}`);
|
|
132
|
+
if (config.outputSchema || preserve("outputSchema")) lines.push(`outputSchema: ${config.outputSchema ? JSON.stringify(config.outputSchema) : ""}`);
|
|
132
133
|
|
|
133
134
|
const readsValue = joinComma(config.defaultReads);
|
|
134
135
|
if (readsValue || preserve("defaultReads")) lines.push(`defaultReads: ${readsValue ?? ""}`);
|