pi-subagents 0.63.0 → 0.65.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 +57 -1
- package/README.md +2 -2
- package/agents/reviewer.md +1 -1
- package/agents/scout.md +1 -1
- package/docs/agents.md +18 -16
- package/docs/configuration.md +7 -15
- package/docs/extension-api.md +15 -6
- package/docs/missions.md +2 -0
- package/docs/observability.md +10 -12
- package/docs/tool-reference.md +7 -6
- package/docs/watchdog.md +92 -114
- package/docs/workflows.md +5 -3
- package/package.json +3 -4
- package/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
- package/skills/pi-subagents/references/execution-controls.md +6 -5
- package/src/agents/agent-management.ts +47 -15
- package/src/api/capability-ceiling.ts +0 -1
- package/src/api/{pi-args.ts → child-tool-plan.ts} +1 -1
- package/src/api/preflight.ts +2 -3
- package/src/extension/doctor.ts +2 -10
- package/src/extension/fanout-child.ts +9 -11
- package/src/extension/index.ts +27 -5
- package/src/extension/public-execution.ts +14 -0
- package/src/extension/rpc.ts +3 -2
- package/src/extension/schemas.ts +2 -1
- package/src/extension/tool-description.ts +9 -8
- package/src/intercom/native-supervisor-channel.ts +138 -60
- package/src/intercom/supervisor-ui.ts +243 -0
- package/src/runs/background/async-execution.ts +46 -24
- package/src/runs/background/async-job-tracker.ts +11 -0
- package/src/runs/background/async-resume.ts +11 -2
- package/src/runs/background/control-channel.ts +2 -204
- package/src/runs/background/notify.ts +41 -2
- package/src/runs/background/process-terminal.ts +1 -1
- package/src/runs/background/run-child-session.ts +613 -0
- package/src/runs/background/run-status.ts +0 -1
- package/src/runs/background/runner-aliases.ts +125 -0
- package/src/runs/background/runner-child-sessions.ts +31 -0
- package/src/runs/background/scheduled-runs.ts +18 -4
- package/src/runs/background/subagent-runner.ts +203 -898
- package/src/runs/foreground/async-steering-action.ts +1 -17
- package/src/runs/foreground/execution.ts +196 -378
- package/src/runs/foreground/foreground-control.ts +4 -0
- package/src/runs/foreground/subagent-executor.ts +121 -58
- package/src/runs/foreground/workflow-foreground-steering.ts +24 -98
- package/src/runs/shared/abort-recovery.ts +3 -3
- package/src/runs/shared/acceptance.ts +10 -0
- package/src/runs/shared/async-status-projection.ts +11 -43
- package/src/runs/shared/capability-ceiling.ts +1 -2
- package/src/runs/shared/child-hooks.ts +25 -0
- package/src/runs/shared/child-identity.ts +13 -2
- package/src/runs/shared/child-launch.ts +314 -0
- package/src/runs/shared/child-lifecycle.ts +25 -0
- package/src/runs/shared/child-runtime-config.ts +126 -0
- package/src/runs/shared/child-session.ts +342 -0
- package/src/runs/shared/child-tool-plan.ts +530 -0
- package/src/runs/shared/claude-code-adapter.ts +5 -1
- package/src/runs/shared/completion-guard.ts +1 -1
- package/src/runs/shared/external-cli-preflight.ts +16 -0
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +5 -4
- package/src/runs/shared/model-exclusions.ts +82 -14
- package/src/runs/shared/model-fallback.ts +47 -4
- package/src/runs/shared/nested-events.ts +29 -45
- package/src/runs/shared/nested-path.ts +0 -14
- package/src/runs/shared/orca-progress-tabs.ts +12 -7
- package/src/runs/shared/parallel-utils.ts +0 -2
- package/src/runs/shared/permissions.ts +0 -13
- package/src/runs/shared/process-signal.ts +4 -1
- package/src/runs/shared/run-fanout-budget.ts +0 -13
- package/src/runs/shared/runtime-acknowledged-extensions.ts +0 -27
- package/src/runs/shared/structured-output.ts +17 -4
- package/src/runs/shared/subagent-control.ts +6 -2
- package/src/runs/shared/subagent-prompt-runtime.ts +87 -384
- package/src/runs/shared/tool-availability.ts +18 -62
- package/src/runs/shared/tool-budget.ts +0 -14
- package/src/runs/shared/worktree-cleanup-plan.ts +25 -6
- package/src/runs/shared/worktree.ts +117 -30
- package/src/shared/child-session-name.ts +1 -1
- package/src/shared/jsonl-writer.ts +11 -0
- package/src/shared/thinking-ceiling.ts +0 -6
- package/src/shared/types.ts +64 -30
- package/src/shared/utils.ts +3 -4
- package/src/slash/slash-commands.ts +0 -6
- package/src/tui/fleet.ts +0 -1
- package/src/tui/render.ts +238 -31
- package/src/watchdog/child-status.ts +54 -34
- package/src/watchdog/diff-tool.ts +77 -0
- package/src/watchdog/emission-guard.ts +5 -3
- package/src/watchdog/guidance.ts +20 -0
- package/src/watchdog/register-child.ts +28 -25
- package/src/watchdog/register-main.ts +10 -9
- package/src/watchdog/render.ts +4 -5
- package/src/watchdog/review.ts +15 -4
- package/src/watchdog/rules.ts +70 -0
- package/src/watchdog/runtime.ts +75 -92
- package/src/watchdog/scope.ts +0 -11
- package/src/watchdog/settings.ts +48 -104
- package/src/watchdog/types.ts +18 -32
- package/src/watchdog/warning-format.ts +0 -1
- package/src/workflows/chat-progress.ts +3 -2
- package/src/workflows/scripted-workflow.ts +48 -1
- package/src/workflows/workflow-checklist.ts +10 -12
- package/src/workflows/workflow-preflight.ts +28 -1
- package/src/runs/shared/child-protocol.ts +0 -415
- package/src/runs/shared/pi-args.ts +0 -1062
- package/src/runs/shared/subagent-startup-retry.ts +0 -116
- package/src/shared/post-exit-stdio-guard.ts +0 -85
package/docs/watchdog.md
CHANGED
|
@@ -1,145 +1,142 @@
|
|
|
1
1
|
# Watchdog and child permissions
|
|
2
2
|
|
|
3
|
-
The watchdog is an opt-in
|
|
3
|
+
The watchdog is an opt-in second model that reviews what the agent just did and pushes findings back into the transcript. It looks for missed constraints, correctness risks, test gaps, unsafe changes, loop risks, and scope drift, and says nothing when the turn is clean. It is not the `reviewer` subagent; `subagents.defaultModel` and `agentOverrides.reviewer` do not configure it.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## When it runs
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
| Timing | Trigger | Gate | Delivery |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| Boundary review | `agent_end` of every main or child turn | Repo changed | Steered into the transcript; the agent gets one continuation, then that turn is reviewed again |
|
|
10
|
+
| Cadence review | Every `cadence.everyNTools` tool results, minimum 5 | Opt-in | Steered after the current tool, before the next step |
|
|
11
|
+
| LSP pre-pass | Before boundary review | Changed TypeScript/JavaScript files | Diagnostics become watchdog findings without a model call |
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
Boundary reviews coalesce a turn's edits into one final-state review. Unchanged or reverted diffs are skipped, as are `.pi/subagents/` and `tmp/` artifacts. In orchestrated runs, each writing child reviews its own worktree and the parent reviews the aggregate diff after child changes land. There is no timer or "every turn regardless of edits" mode; the closest is a low cadence such as `everyNTools: 5`. Cadence monitoring is inspired by [Scopey](https://github.com/ArchAstro/scopey).
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
- Multiple edits in one turn are coalesced into one review of the final changed state.
|
|
13
|
-
- Unchanged/reverted diffs are skipped.
|
|
14
|
-
- Generated `.pi/subagents/` or `tmp/` artifacts do not trigger review.
|
|
15
|
-
- In orchestrated runs, each writing child can review its own edited worktree, and the parent can still review the aggregate repo diff after child changes are applied.
|
|
15
|
+
Children get the same boundary, cadence, and LSP behavior. Child cadence resolves from `children.overrides.<agent>.cadence`, then `children.cadence`, then top-level `cadence`:
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"subagents": {
|
|
20
|
+
"watchdog": {
|
|
21
|
+
"enabled": true,
|
|
22
|
+
"cadence": { "everyNTools": 10 },
|
|
23
|
+
"children": {
|
|
24
|
+
"enabled": true,
|
|
25
|
+
"cadence": { "everyNTools": 20 },
|
|
26
|
+
"overrides": {
|
|
27
|
+
"worker": { "cadence": { "everyNTools": 5 } },
|
|
28
|
+
"reviewer": { "enabled": false }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
18
35
|
|
|
19
|
-
|
|
36
|
+
That means: main every 10 tools, worker every 5, other children every 20, reviewer never.
|
|
20
37
|
|
|
21
|
-
|
|
38
|
+
## What you see
|
|
22
39
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
40
|
+
Every finding is an ordinary transcript message: expandable, scrollable, and persisted in session JSONL. A clean review shows nothing.
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
you ─▶ agent turn ─▶ edits repo ─▶ agent_end ─▶ watchdog review
|
|
44
|
+
├─ clean: turn ends
|
|
45
|
+
└─ warning: steered in; agent continues once
|
|
27
46
|
```
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
Collapsed warnings show the title and evidence line. Expanded warnings show evidence, recommended action, category, and source:
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
```
|
|
51
|
+
● Subagent watchdog Blocker (displayed): Claims tests passed without running them
|
|
52
|
+
Evidence: The transcript claims `npm test` passed but no test command appears in the tool log.
|
|
53
|
+
Recommended action: Run the focused test before finishing.
|
|
54
|
+
Category: Test Gap · Source: main
|
|
55
|
+
```
|
|
33
56
|
|
|
34
|
-
|
|
57
|
+
When consecutive boundary reviews raise the same warning, the agent is not making progress. After `stalemateRepeats` identical warnings in a row (default 3), the warning is shown as `stalemate`, no continuation is triggered, and the turn ends. Your next prompt resets the count.
|
|
35
58
|
|
|
36
|
-
|
|
37
|
-
/subagents-watchdog model anthropic/claude-opus-4-8:high
|
|
38
|
-
/subagents-watchdog model openai-codex/gpt-5.5:high
|
|
39
|
-
/subagents-watchdog model inherit
|
|
40
|
-
/subagents-watchdog check
|
|
41
|
-
```
|
|
59
|
+
Child watchdog findings are lifted into the parent in three ways:
|
|
42
60
|
|
|
43
|
-
|
|
61
|
+
- The result envelope contains `watchdog.warnings` with severity, category, summary, evidence, recommended action, `addressed`, and `stalemate`, bounded to the last 20.
|
|
62
|
+
- The acceptance runtime check `watchdog-blocker` fails on blockers that are unaddressed or stalemate.
|
|
63
|
+
- Completion notices include `Watchdog blockers:` lines, and Fleet/status views show `wd:<n>` plus `resolve watchdog blockers`.
|
|
44
64
|
|
|
45
|
-
-
|
|
46
|
-
- If `main.model` is set without a thinking suffix or `main.thinking`, it runs with thinking off. Prefer `:high` or `"thinking": "high"` for the strong-watchdog pairing.
|
|
65
|
+
`/subagents-watchdog status` shows setting sources, enabled state, runtime state, review trigger, scope, cadence, LSP status, selected model/thinking, child overrides, timeout, stalemate count, launch-rule count, review backend, last warning, changed paths, and config errors when present.
|
|
47
66
|
|
|
48
|
-
|
|
67
|
+
## What the reviewer is given
|
|
49
68
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"main": {
|
|
56
|
-
"model": "anthropic/claude-opus-4-8",
|
|
57
|
-
"thinking": "high"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
```
|
|
69
|
+
- **Turn delta** with changed repo paths. Over-long input keeps the first 6,000 characters and the tail.
|
|
70
|
+
- **Current scope** (`scope.enabled`, default on): bounded real user prompts, with newer prompts superseding older ones.
|
|
71
|
+
- **`watchdog_diff`** when inside git: diff since the session-start commit, including later commits, plus untracked paths to inspect with `read`; accepts `path` and `stat:true`.
|
|
72
|
+
- **`WATCHDOG.md`** standing instructions, read fresh on every review: `<project>/.pi/WATCHDOG.md` first, then `~/.pi/agent/WATCHDOG.md`, capped at 8,000 characters. Set `guidance.watchdogMd: false` to ignore them.
|
|
73
|
+
- **LSP diagnostics** from `typescript-language-server`, auto-detected in `node_modules/.bin` or `PATH`; it is never installed and never run over the whole workspace. Errors become blockers, warnings concerns, and info/hints stay in status.
|
|
63
74
|
|
|
64
|
-
##
|
|
75
|
+
## Choosing a model
|
|
65
76
|
|
|
66
|
-
|
|
77
|
+
One model setting serves both boundary and cadence reviews per endpoint. Use a strong complementary model for rare adversarial boundary reviews, or a cheap one for frequent cadence monitoring.
|
|
67
78
|
|
|
68
|
-
|
|
79
|
+
```text
|
|
80
|
+
/subagents-watchdog recommend-model
|
|
81
|
+
/subagents-watchdog session model recommended
|
|
82
|
+
/subagents-watchdog model recommended
|
|
83
|
+
/subagents-watchdog model anthropic/claude-opus-4-8:high
|
|
84
|
+
/subagents-watchdog model openai-codex/gpt-5.5:high
|
|
85
|
+
/subagents-watchdog model inherit
|
|
86
|
+
/subagents-watchdog check
|
|
87
|
+
/subagents-watchdog on
|
|
88
|
+
```
|
|
69
89
|
|
|
70
|
-
|
|
90
|
+
The recommendation is Opus 4.8 or GPT 5.5 at thinking high, whichever your main session is not using and is authenticated. Saving a model does not enable the watchdog; use `on` separately.
|
|
71
91
|
|
|
72
92
|
```json
|
|
73
93
|
{
|
|
74
94
|
"subagents": {
|
|
75
95
|
"watchdog": {
|
|
76
96
|
"enabled": true,
|
|
77
|
-
"main": {
|
|
78
|
-
"model": "anthropic/claude-haiku-4-5",
|
|
79
|
-
"thinking": "medium"
|
|
80
|
-
},
|
|
97
|
+
"main": { "model": "anthropic/claude-opus-4-8", "thinking": "high" },
|
|
81
98
|
"scope": { "enabled": true },
|
|
82
99
|
"cadence": { "everyNTools": 10 },
|
|
83
|
-
"
|
|
84
|
-
"blockers": true,
|
|
85
|
-
"maxAttempts": 3,
|
|
86
|
-
"stalemateRepeats": 3
|
|
87
|
-
}
|
|
100
|
+
"stalemateRepeats": 3
|
|
88
101
|
}
|
|
89
102
|
}
|
|
90
103
|
}
|
|
91
104
|
```
|
|
92
105
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
When the watchdog displays a blocker at `agent_end`, the `subagents.watchdog.autoFollow` policy can queue a visible follow-up user message asking the agent to address it. Auto-follow only runs while the watchdog is enabled, respects `maxAttempts`, and stops on repeated identical blockers using `stalemateRepeats`.
|
|
96
|
-
|
|
97
|
-
## LSP diagnostics
|
|
98
|
-
|
|
99
|
-
When the watchdog is enabled, it also checks changed TypeScript and JavaScript files for fresh language-server diagnostics before the model review.
|
|
106
|
+
Omit `main.model` to inherit the session model and thinking level. A `main.model` without a thinking suffix or `main.thinking` runs with thinking off, so prefer `:high` for the strong pairing.
|
|
100
107
|
|
|
101
|
-
|
|
102
|
-
- LSP errors surface as watchdog blockers, warnings as concerns, and info/hints stay in status details.
|
|
103
|
-
- Slow or missing servers are reported in `/subagents-watchdog status` without blocking the turn or emitting late mid-turn warnings.
|
|
104
|
-
- Configure the bounds with `subagents.watchdog.lsp.enabled`, `timeoutMs`, `maxFiles`, and `maxDiagnostics`.
|
|
108
|
+
Agents can call `subagent({ action: "watchdog.recommend-model" })` and `subagent({ action: "watchdog.configure", model: "recommended", scope: "session" | "user" | "project" })`. They should use `scope: "session"` unless you ask for a lasting default.
|
|
105
109
|
|
|
106
110
|
## Child watchdogs
|
|
107
111
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Child watchdogs are opt-in and follow the same edit-gated rule: read-only children do not trigger watchdog reviews, while writer children are reviewed at their own `agent_end` if their worktree changed.
|
|
111
|
-
|
|
112
|
-
## Agent-driven configuration
|
|
113
|
-
|
|
114
|
-
Agents can configure the same values through the tool when you ask them to set up the watchdog:
|
|
115
|
-
|
|
116
|
-
```ts
|
|
117
|
-
subagent({ action: "watchdog.recommend-model" })
|
|
118
|
-
subagent({ action: "watchdog.configure", model: "recommended", scope: "session" })
|
|
119
|
-
subagent({ action: "watchdog.configure", model: "recommended", scope: "project" })
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Persistent scopes (`user` or `project`) should only be used when you ask for a lasting default. Otherwise the agent should use `scope: "session"`.
|
|
112
|
+
Opt in under `subagents.watchdog.children`. `model` and `thinking` set the default child watchdog; `overrides.<agent>` can set `model`, `thinking`, `enabled`, or `cadence` per role.
|
|
123
113
|
|
|
124
|
-
##
|
|
114
|
+
## Launch rules
|
|
125
115
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
Configure explicit non-bash rules globally in `~/.pi/agent/extensions/subagent/config.json`:
|
|
116
|
+
`subagents.watchdog.rules` pins which models each role may run on. It runs before a child starts, needs no model call, and applies even when model review is off.
|
|
129
117
|
|
|
130
118
|
```json
|
|
131
119
|
{
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
|
|
136
|
-
|
|
120
|
+
"subagents": {
|
|
121
|
+
"watchdog": {
|
|
122
|
+
"rules": {
|
|
123
|
+
"action": "warn",
|
|
124
|
+
"roleModels": {
|
|
125
|
+
"scout": { "allow": ["openai-codex/gpt-5.6-luna:max"] },
|
|
126
|
+
"oracle": { "deny": ["*"], "note": "oracle is for hard questions only; ask before launching" },
|
|
127
|
+
"worker": { "deny": ["openai-codex/gpt-5.6-sol:high"] }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
137
130
|
}
|
|
138
131
|
}
|
|
139
132
|
}
|
|
140
133
|
```
|
|
141
134
|
|
|
142
|
-
|
|
135
|
+
`action: "warn"` steers a concern into the orchestrator transcript and lets the launch proceed. `action: "block"` returns a tool error and starts nothing. `allow` and `deny` are anchored, case-sensitive globs (`*`, `?`) matched against `provider/id[:thinking]` and bare `provider/id`; `deny` wins. Rules apply to direct launches, workflow children, and chain/parallel steps using settings visible at the launch cwd.
|
|
136
|
+
|
|
137
|
+
## Native child tool permissions
|
|
138
|
+
|
|
139
|
+
Opt-in, Pi child runtimes only. With no rules, every tool call passes through. Global non-bash rules live in `~/.pi/agent/extensions/subagent/config.json`; agents override matching rules in `permission:` or `permissions:` frontmatter:
|
|
143
140
|
|
|
144
141
|
```yaml
|
|
145
142
|
---
|
|
@@ -150,27 +147,8 @@ permission:
|
|
|
150
147
|
---
|
|
151
148
|
```
|
|
152
149
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
- Agent rules override matching global rules.
|
|
156
|
-
- Omitted and unknown tools default to `allow`.
|
|
157
|
-
- Explicit `allow` removes an inherited restriction.
|
|
158
|
-
- The gate is not registered when the resolved policy has no `ask` or `deny` rules.
|
|
159
|
-
|
|
160
|
-
### How `ask` works
|
|
161
|
-
|
|
162
|
-
An explicit `ask` pauses that exact tool call and sends a bounded, redacted preview to a one-call permission arbiter owned by the built-in child watchdog. The arbiter uses the configured child-watchdog model and returns only `approve` or `deny`; it does not notify the parent agent.
|
|
163
|
-
|
|
164
|
-
Enable and configure `subagents.watchdog.children` before using `ask` rules. A disabled watchdog, missing model/auth, timeout, malformed response, or runtime error denies the call with a clear error.
|
|
165
|
-
|
|
166
|
-
Asked requests and decisions are written to bounded audit JSONL, including `decisionSource: "watchdog"` and bounded failure reasons. Ordinary direction and clarification through `contact_supervisor` or the optional `pi-intercom` extension remain separate and are never permission-gated.
|
|
167
|
-
|
|
168
|
-
### Bash is out of scope
|
|
169
|
-
|
|
170
|
-
`bash` is always passed through by pi-subagents. Bash rules are rejected rather than parsed, gated, denied, or audited. Install and configure `pi-guard` when command-level bash policy is needed.
|
|
171
|
-
|
|
172
|
-
A pi-subagents child is headless, so a pi-guard rule that resolves to `ask` cannot request approval from the parent Pi UI. Native permissions do not forward pi-guard decisions; they only apply to the separate non-bash child permission gate. For child-specific policy, use `PI_GUARD` through a `PI_SUBAGENT_PI_BINARY` wrapper or an equivalent launch wrapper, and configure explicit `allow` or `deny` rules. An `allow` rule grants execution; it is not approval forwarding, so retain explicit denies for commands the child must not run.
|
|
150
|
+
Values are `allow`, `ask`, and `deny`. Agent rules override global ones, omitted and unknown tools default to `allow`, an explicit `allow` removes an inherited restriction, and the gate is not registered when the resolved policy has no `ask` or `deny`.
|
|
173
151
|
|
|
174
|
-
|
|
152
|
+
`ask` pauses that exact tool call and sends a bounded, redacted preview to a one-call arbiter owned by the child watchdog, using the configured child-watchdog model. The arbiter returns only `approve` or `deny` and does not notify the parent. A disabled watchdog, missing model/auth, timeout, malformed response, or runtime error denies the call with a clear error. Requests and decisions are written to bounded audit JSONL. `contact_supervisor` and the optional `pi-intercom` extension are never permission-gated.
|
|
175
153
|
|
|
176
|
-
External CLI profiles are opaque processes, so native permissions cannot intercept their tools
|
|
154
|
+
Bash is always passed through; bash rules are rejected. Use `pi-guard` for command-level policy. Children are pi sessions inside the parent process (foreground) or the detached runner process (background), not separate `pi` binaries, so there is no per-child command wrapper; load `pi-guard` into a child through the agent's `extensions` or `subagentOnlyExtensions`, and background children also pick it up as an ambient extension. External CLI profiles are opaque processes, so native permissions cannot intercept their tools; launches with effective `ask` or `deny` rules are rejected for external CLI agents.
|
package/docs/workflows.md
CHANGED
|
@@ -14,7 +14,7 @@ Packaged `worker`, `oracle`, and `advisor` default to forked context when a laun
|
|
|
14
14
|
|
|
15
15
|
Child-safety boundaries are enforced at runtime:
|
|
16
16
|
|
|
17
|
-
-
|
|
17
|
+
- Child sessions do not receive the bundled `pi-subagents` skill.
|
|
18
18
|
- Forked child context filtering removes parent-only subagent artifacts (including old hidden orchestration-instruction messages, slash/status/control messages, and prior parent `subagent` tool-call/tool-result history) while preserving ordinary prose and unrelated tool calls/results.
|
|
19
19
|
- By default, children do not register the `subagent` tool and receive boundary instructions that they are not the parent orchestrator and must not propose or run subagents.
|
|
20
20
|
- The explicit exception is an agent whose resolved builtin `tools` includes `subagent`; that child gets a child-safe `subagent` tool for the fanout work the parent assigned, still bounded by `maxSubagentDepth`.
|
|
@@ -369,7 +369,9 @@ Each child uses the existing worktree lifecycle: it branches from clean HEAD, jo
|
|
|
369
369
|
|
|
370
370
|
A top-level `{ workflowScript, worktree: true }` makes isolation the default for every workflow child. An individual child can override that default with `worktree: false`. Keep one writer when parallel writes are not intentionally isolated.
|
|
371
371
|
|
|
372
|
-
|
|
372
|
+
Use `baseRef` to branch managed worktrees from a named commit or branch instead of the default `HEAD`. For example, `{ workflowScript, worktree: true, baseRef: "refs/heads/release" }` applies the release ref to children unless a child supplies its own `baseRef`. The source checkout must still be clean, and the ref must resolve to a commit before any worktree is allocated.
|
|
373
|
+
|
|
374
|
+
Configure the worktree provider, native path layout, base directory, and setup hook in [configuration.md](configuration.md).
|
|
373
375
|
|
|
374
376
|
### Lane metadata lifecycle
|
|
375
377
|
|
|
@@ -446,7 +448,7 @@ export PI_SUBAGENT_MAX_DEPTH=1
|
|
|
446
448
|
export PI_SUBAGENT_MAX_DEPTH=0
|
|
447
449
|
```
|
|
448
450
|
|
|
449
|
-
`
|
|
451
|
+
`PI_SUBAGENT_MAX_DEPTH` applies to the top-level parent; children inherit their limit through their runtime config, and their own depth is tracked there too.
|
|
450
452
|
|
|
451
453
|
## Prompt-template integration
|
|
452
454
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-subagents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.65.0",
|
|
4
4
|
"description": "Pi extension for single-agent delegation and scripted multi-agent workflows",
|
|
5
5
|
"author": "Nico Bailon",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"./preflight": "./src/api/preflight.ts",
|
|
17
17
|
"./control-channel": "./src/api/control-channel.ts",
|
|
18
18
|
"./intercom-bridge": "./src/api/intercom-bridge.ts",
|
|
19
|
-
"./
|
|
19
|
+
"./child-tool-plan": "./src/api/child-tool-plan.ts",
|
|
20
20
|
"./shared-types": "./src/api/shared-types.ts",
|
|
21
21
|
"./project-panes": "./src/api/project-panes.ts"
|
|
22
22
|
},
|
|
@@ -56,8 +56,7 @@
|
|
|
56
56
|
"test": "npm run test:unit",
|
|
57
57
|
"test:unit": "node --experimental-strip-types --import ./test/support/isolated-temp-root.mjs --test test/unit/*.test.ts",
|
|
58
58
|
"test:integration": "node --experimental-strip-types --import ./test/support/register-loader.mjs --test test/integration/*.test.ts",
|
|
59
|
-
"test:
|
|
60
|
-
"test:all": "npm run test:unit && npm run test:integration && npm run test:e2e"
|
|
59
|
+
"test:all": "npm run test:unit && npm run test:integration"
|
|
61
60
|
},
|
|
62
61
|
"pi": {
|
|
63
62
|
"extensions": [
|
|
@@ -21,7 +21,7 @@ This file is a detailed reference loaded from `skills/pi-subagents/SKILL.md`.
|
|
|
21
21
|
become second decision-makers.
|
|
22
22
|
- **Respect the fixed authority policy.** `authorityPolicy` is a small `auto` / `confirm` / `forbid` map for supported operational actions. Worktree discard, destructive cleanup, and spawn-budget grants default to confirmation; stop, steer, and schedule creation remain automatic. Use `worktree.discard` with the durable `handoffPath`; confirm-required actions refuse safely without an interactive UI and retained paths include manual Git recovery commands.
|
|
23
23
|
|
|
24
|
-
Runtime config can change orchestration behavior. `intercomBridge.resultDelivery: false` disables only external acknowledged grouped-result delivery when native parent notifications own completion; supervisor asks/progress stay active, and enabled transport failures are still reported. `asyncByDefault` and `forceTopLevelAsync` affect whether launches detach; `waitTool` can make direct `bg_wait()` calls return immediately while headless auto-drain remains active, and its effective value is propagated to child runtimes; `globalConcurrencyLimit` bounds concurrent fanout, while a positive `maxSubagentSpawnsPerSession` optionally caps cumulative launches (`0` or unset is unlimited). Status and doctor report the budget; static work preflights declared capacity; only the settled root interactive parent can use `grant-spawn-budget` after native confirmation, with total grants bounded by the original cap. Compaction does not reset usage or grants; `singleRunOutputBaseDir` and `worktreeBaseDir` route outputs and worktrees; `completionBatch` groups async notifications. `artifactDir` is `session` (default), `project`, or `temp` and chooses where subagent artifacts are stored. Set `asyncWidget: false` to hide the above-editor background-run widget when a companion footer or dashboard owns that space (fleet inspector remains available). Per-run `artifacts: false` disables artifact capture for that launch. Async status and result artifacts include `lifecycleArtifactVersion` and fields such as `workflowGraph`, `steps`, `results`, `totalTokens`, `totalCost`, `turnCount`, `toolCount`, and nested `children`.
|
|
24
|
+
Runtime config can change orchestration behavior. `intercomBridge.resultDelivery: false` disables only external acknowledged grouped-result delivery when native parent notifications own completion; supervisor asks/progress stay active, and enabled transport failures are still reported. `asyncByDefault` and `forceTopLevelAsync` affect whether launches detach; `waitTool` can make direct `bg_wait()` calls return immediately while headless auto-drain remains active, and its effective value is propagated to child runtimes; `globalConcurrencyLimit` bounds concurrent fanout, while a positive `maxSubagentSpawnsPerSession` optionally caps cumulative launches (`0` or unset is unlimited). Status and doctor report the budget; static work preflights declared capacity; only the settled root interactive parent can use `grant-spawn-budget` after native confirmation, with total grants bounded by the original cap. Compaction does not reset usage or grants; `singleRunOutputBaseDir` and `worktreeBaseDir` route outputs and worktrees; `completionBatch` groups async notifications. `artifactDir` is `session` (default), `project`, or `temp` and chooses where subagent artifacts are stored. Set `asyncWidget: false` to hide the above-editor background-run widget when a companion footer or dashboard owns that space (fleet inspector remains available). Per-run `artifacts: false` disables artifact capture for that launch. Async status and result artifacts include `lifecycleArtifactVersion` and fields such as `workflowGraph`, `steps`, `results`, `totalTokens`, `totalCost`, `turnCount`, `toolCount`, and nested `children`. Prefer these artifacts and `status` views over scraping terminal output.
|
|
25
25
|
|
|
26
26
|
### Keep report artifacts out of the repository root
|
|
27
27
|
|
|
@@ -236,8 +236,8 @@ Resume behavior:
|
|
|
236
236
|
- Multi-child async runs require `index` unless only one running child is selectable.
|
|
237
237
|
- Completed foreground single, parallel, and chain runs can also be revived by `index` while their run metadata remains in extension state.
|
|
238
238
|
- Nested runs can be resumed by nested id when a live route or persisted nested session metadata is available.
|
|
239
|
-
- Revive starts a new child
|
|
240
|
-
- Direct revival holds an exclusive cross-process lease on the canonical child session file until the new child finishes. Concurrent attempts fail before
|
|
239
|
+
- Revive starts a new child session from the old session context; it does not resume the original child session.
|
|
240
|
+
- Direct revival holds an exclusive cross-process lease on the canonical child session file until the new child finishes. Concurrent attempts fail before the child session starts and identify the owning revived run; stale ownership is reclaimed only when the recorded process is demonstrably gone or reused.
|
|
241
241
|
- If the chosen child has no persisted `.jsonl` session file, resume fails and reports that directly.
|
|
242
242
|
|
|
243
243
|
Use diagnostics when setup or child startup looks wrong:
|
|
@@ -337,9 +337,10 @@ child changes land. Enabled watchdogs also run changed-file TypeScript/JavaScrip
|
|
|
337
337
|
LSP diagnostics before the model pass when `typescript-language-server` is available.
|
|
338
338
|
They keep bounded current-scope context from real user prompts (`watchdog.scope.enabled`)
|
|
339
339
|
and can optionally run non-blocking Scopey-style cadence reviews every N tool results
|
|
340
|
-
(`watchdog.cadence.everyNTools`). Cadence corrections and
|
|
341
|
-
|
|
342
|
-
|
|
340
|
+
(`watchdog.cadence.everyNTools`). Cadence corrections and boundary warnings are always
|
|
341
|
+
transcript-visible; a boundary warning continues the run so the agent can act on it, and
|
|
342
|
+
repeated identical warnings stop after `watchdog.stalemateRepeats`. Choose the watchdog
|
|
343
|
+
model that matches the desired cheap-monitor vs strong-reviewer policy.
|
|
343
344
|
|
|
344
345
|
Prefer a strong complementary model (for example Opus 4.8 high paired against a
|
|
345
346
|
GPT 5.5 main session, or the reverse). Recommendation and configuration:
|
|
@@ -32,6 +32,7 @@ import { resolveSubagentModelOverride, type ParentModel } from "../runs/shared/m
|
|
|
32
32
|
import { validateToolBudgetConfig } from "../runs/shared/tool-budget.ts";
|
|
33
33
|
import { 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
|
+
import { resolveExternalCliBinaryAvailability, type ExternalCliBinaryAvailability } from "../runs/shared/external-cli-preflight.ts";
|
|
35
36
|
import type { AcceptanceInput, AgentCapabilitiesSnapshot, AgentCapabilityRow, Details, ExtensionConfig, ToolBudgetConfig } from "../shared/types.ts";
|
|
36
37
|
import { getProjectConfigDir } from "../shared/utils.ts";
|
|
37
38
|
import { previewDisplayText } from "../shared/display-text.ts";
|
|
@@ -704,17 +705,34 @@ function externalJobProviderSuffix(provider: string, names: Set<string> | undefi
|
|
|
704
705
|
return names.has(provider) ? "✓" : "missing";
|
|
705
706
|
}
|
|
706
707
|
|
|
707
|
-
|
|
708
|
+
type ExternalCliAvailabilityByCommand = ReadonlyMap<string, ExternalCliBinaryAvailability>;
|
|
709
|
+
|
|
710
|
+
function externalCliAvailabilityForAgents(agents: readonly AgentConfig[]): ExternalCliAvailabilityByCommand {
|
|
711
|
+
const availability = new Map<string, ExternalCliBinaryAvailability>();
|
|
712
|
+
for (const agent of agents) {
|
|
713
|
+
const runner = agent.runner;
|
|
714
|
+
if (runner?.type === "external-cli" && !availability.has(runner.command)) {
|
|
715
|
+
availability.set(runner.command, resolveExternalCliBinaryAvailability(runner.command, process.env));
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return availability;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
function runnerListBadge(agent: AgentConfig, providerNames: Set<string> | undefined, externalCliAvailability?: ExternalCliAvailabilityByCommand): string | undefined {
|
|
708
722
|
if (agent.runner?.type === "external-job") return `external-job:${agent.runner.provider} ${externalJobProviderSuffix(agent.runner.provider, providerNames)}`;
|
|
709
|
-
if (agent.runner?.type === "external-cli")
|
|
723
|
+
if (agent.runner?.type === "external-cli") {
|
|
724
|
+
const availability = externalCliAvailability?.get(agent.runner.command);
|
|
725
|
+
if (!availability) return "external-cli";
|
|
726
|
+
return `external-cli:${agent.runner.command} ${availability.available ? "✓" : "missing"}`;
|
|
727
|
+
}
|
|
710
728
|
return undefined;
|
|
711
729
|
}
|
|
712
730
|
|
|
713
|
-
function agentListMetadata(agent: AgentConfig, providerNames: Set<string> | undefined): string {
|
|
731
|
+
function agentListMetadata(agent: AgentConfig, providerNames: Set<string> | undefined, externalCliAvailability?: ExternalCliAvailabilityByCommand): string {
|
|
714
732
|
const source = agent.source === "package" ? packageSourceLabel(agent) : agent.source;
|
|
715
733
|
return [
|
|
716
734
|
source,
|
|
717
|
-
runnerListBadge(agent, providerNames),
|
|
735
|
+
runnerListBadge(agent, providerNames, externalCliAvailability),
|
|
718
736
|
agent.defaultContext ? `context: ${agent.defaultContext}` : undefined,
|
|
719
737
|
agent.aliases?.length ? `aliases: ${agent.aliases.join(", ")}` : undefined,
|
|
720
738
|
].filter((part): part is string => Boolean(part)).join(", ");
|
|
@@ -724,7 +742,7 @@ function formatAgentListLine(agent: AgentConfig, providerNames: Set<string> | un
|
|
|
724
742
|
return `- ${agent.name} (${agentListMetadata(agent, providerNames)}): ${agent.description}`;
|
|
725
743
|
}
|
|
726
744
|
|
|
727
|
-
function formatAgentCapabilitiesLine(agent: AgentConfig, providerNames: Set<string> | undefined): string {
|
|
745
|
+
function formatAgentCapabilitiesLine(agent: AgentConfig, providerNames: Set<string> | undefined, externalCliAvailability?: ExternalCliAvailabilityByCommand): string {
|
|
728
746
|
const declaredTools = [
|
|
729
747
|
...(agent.tools ?? []),
|
|
730
748
|
...(agent.mcpDirectTools ?? []).map((tool) => `mcp:${tool}`),
|
|
@@ -742,7 +760,7 @@ function formatAgentCapabilitiesLine(agent: AgentConfig, providerNames: Set<stri
|
|
|
742
760
|
if (agent.modelProvider && !agent.model.includes("/")) model = `${agent.modelProvider}/${agent.model}`;
|
|
743
761
|
}
|
|
744
762
|
const thinking = agent.thinking === false ? "off" : agent.thinking ?? "default";
|
|
745
|
-
return `- ${agent.name} (${agentListMetadata(agent, providerNames)}): Description: ${previewDisplayText(agent.description, 240)}; Tools: ${tools}; Model: ${model}; Thinking: ${thinking}`;
|
|
763
|
+
return `- ${agent.name} (${agentListMetadata(agent, providerNames, externalCliAvailability)}): Description: ${previewDisplayText(agent.description, 240)}; Tools: ${tools}; Model: ${model}; Thinking: ${thinking}`;
|
|
746
764
|
}
|
|
747
765
|
|
|
748
766
|
const EXTERNAL_JOB_CAPABILITIES = { stop: false, steer: false, resume: false, structuredOutput: false, toolEvents: false } as const;
|
|
@@ -752,10 +770,19 @@ function listOrEmpty<T>(values: T[] | undefined): T[] {
|
|
|
752
770
|
return values ?? [];
|
|
753
771
|
}
|
|
754
772
|
|
|
755
|
-
function agentCapabilityRunner(agent: AgentConfig, providerNames: Set<string> | undefined): AgentCapabilityRow["runner"] {
|
|
773
|
+
function agentCapabilityRunner(agent: AgentConfig, providerNames: Set<string> | undefined, externalCliAvailability: ExternalCliAvailabilityByCommand): AgentCapabilityRow["runner"] {
|
|
756
774
|
const runner = agent.runner;
|
|
757
775
|
if (!runner || runner.type === "pi") return PI_AGENT_RUNNER;
|
|
758
|
-
if (runner.type === "external-cli")
|
|
776
|
+
if (runner.type === "external-cli") {
|
|
777
|
+
const availability = externalCliAvailability.get(runner.command)!;
|
|
778
|
+
return {
|
|
779
|
+
type: "external-cli",
|
|
780
|
+
adapter: runner.adapter,
|
|
781
|
+
command: runner.command,
|
|
782
|
+
...availability,
|
|
783
|
+
capabilities: resolveExternalCliRunnerStatus(runner).capabilities,
|
|
784
|
+
};
|
|
785
|
+
}
|
|
759
786
|
return { type: "external-job", provider: runner.provider, available: providerNames?.has(runner.provider), capabilities: EXTERNAL_JOB_CAPABILITIES };
|
|
760
787
|
}
|
|
761
788
|
|
|
@@ -769,7 +796,7 @@ function agentCapabilityTools(agent: AgentConfig): AgentCapabilityRow["tools"] {
|
|
|
769
796
|
};
|
|
770
797
|
}
|
|
771
798
|
|
|
772
|
-
function agentCapabilityRow(agent: AgentConfig, options: { executable: boolean; providerNames?: Set<string>; restrictionSources?: string[] }): AgentCapabilityRow {
|
|
799
|
+
function agentCapabilityRow(agent: AgentConfig, options: { executable: boolean; providerNames?: Set<string>; externalCliAvailability: ExternalCliAvailabilityByCommand; restrictionSources?: string[] }): AgentCapabilityRow {
|
|
773
800
|
return {
|
|
774
801
|
name: agent.name,
|
|
775
802
|
description: previewDisplayText(agent.description, 1000),
|
|
@@ -777,7 +804,7 @@ function agentCapabilityRow(agent: AgentConfig, options: { executable: boolean;
|
|
|
777
804
|
executable: options.executable,
|
|
778
805
|
restrictionSources: options.executable ? undefined : options.restrictionSources ?? [],
|
|
779
806
|
aliases: agent.aliases ? [...agent.aliases] : undefined,
|
|
780
|
-
runner: agentCapabilityRunner(agent, options.providerNames),
|
|
807
|
+
runner: agentCapabilityRunner(agent, options.providerNames, options.externalCliAvailability),
|
|
781
808
|
tools: agentCapabilityTools(agent),
|
|
782
809
|
model: presentDetails({ value: agent.model, fallbackModels: agent.fallbackModels, thinking: agent.thinking }),
|
|
783
810
|
execution: presentDetails({ defaultAsync: agent.defaultAsync, timeoutMs: agent.defaultTimeoutMs }),
|
|
@@ -786,11 +813,11 @@ function agentCapabilityRow(agent: AgentConfig, options: { executable: boolean;
|
|
|
786
813
|
};
|
|
787
814
|
}
|
|
788
815
|
|
|
789
|
-
function agentCapabilitiesSnapshot(input: { agents: AgentConfig[]; restrictedAgents: AgentConfig[]; providerNames?: Set<string>; restrictedSources?: string[] }): AgentCapabilitiesSnapshot {
|
|
816
|
+
function agentCapabilitiesSnapshot(input: { agents: AgentConfig[]; restrictedAgents: AgentConfig[]; providerNames?: Set<string>; externalCliAvailability: ExternalCliAvailabilityByCommand; restrictedSources?: string[] }): AgentCapabilitiesSnapshot {
|
|
790
817
|
return {
|
|
791
818
|
agents: [
|
|
792
|
-
...input.agents.map((agent) => agentCapabilityRow(agent, { executable: true, providerNames: input.providerNames })),
|
|
793
|
-
...input.restrictedAgents.map((agent) => agentCapabilityRow(agent, { executable: false, providerNames: input.providerNames, restrictionSources: input.restrictedSources })),
|
|
819
|
+
...input.agents.map((agent) => agentCapabilityRow(agent, { executable: true, providerNames: input.providerNames, externalCliAvailability: input.externalCliAvailability })),
|
|
820
|
+
...input.restrictedAgents.map((agent) => agentCapabilityRow(agent, { executable: false, providerNames: input.providerNames, externalCliAvailability: input.externalCliAvailability, restrictionSources: input.restrictedSources })),
|
|
794
821
|
],
|
|
795
822
|
restrictedCount: input.restrictedAgents.length,
|
|
796
823
|
...(input.restrictedSources?.length ? { capabilityCeilingSources: [...input.restrictedSources] } : {}),
|
|
@@ -824,13 +851,14 @@ function appendAgentDiagnosticLines(lines: string[], diagnostics: AgentDiscovery
|
|
|
824
851
|
);
|
|
825
852
|
}
|
|
826
853
|
|
|
827
|
-
function agentCapabilityDetails(input: { capabilityMode: boolean; agents: AgentConfig[]; restrictedAgents: AgentConfig[]; providerNames?: Set<string>; restrictedSources?: string[] }): Partial<Details> | undefined {
|
|
854
|
+
function agentCapabilityDetails(input: { capabilityMode: boolean; agents: AgentConfig[]; restrictedAgents: AgentConfig[]; providerNames?: Set<string>; externalCliAvailability: ExternalCliAvailabilityByCommand; restrictedSources?: string[] }): Partial<Details> | undefined {
|
|
828
855
|
if (!input.capabilityMode) return undefined;
|
|
829
856
|
return {
|
|
830
857
|
agentCapabilities: jsonDetails(agentCapabilitiesSnapshot({
|
|
831
858
|
agents: input.agents,
|
|
832
859
|
restrictedAgents: input.restrictedAgents,
|
|
833
860
|
providerNames: input.providerNames,
|
|
861
|
+
externalCliAvailability: input.externalCliAvailability,
|
|
834
862
|
restrictedSources: input.restrictedSources,
|
|
835
863
|
})),
|
|
836
864
|
};
|
|
@@ -936,7 +964,10 @@ export function handleList(params: ManagementParams, ctx: ManagementContext): Ag
|
|
|
936
964
|
const providerStatus = registeredExternalJobProviderStatus();
|
|
937
965
|
const providerNameSet = providerNames(providerStatus);
|
|
938
966
|
const capabilityMode = params.capabilities === true;
|
|
939
|
-
const
|
|
967
|
+
const externalCliAvailability = capabilityMode ? externalCliAvailabilityForAgents([...agents, ...restrictedAgents]) : undefined;
|
|
968
|
+
const formatLine = capabilityMode
|
|
969
|
+
? (agent: AgentConfig, names: Set<string> | undefined) => formatAgentCapabilitiesLine(agent, names, externalCliAvailability)
|
|
970
|
+
: formatAgentListLine;
|
|
940
971
|
const lines = [
|
|
941
972
|
capabilityMode ? "Executable agents (capabilities):" : "Executable agents:",
|
|
942
973
|
...formatAgentListSections(agents, providerNameSet, formatLine),
|
|
@@ -950,6 +981,7 @@ export function handleList(params: ManagementParams, ctx: ManagementContext): Ag
|
|
|
950
981
|
agents,
|
|
951
982
|
restrictedAgents,
|
|
952
983
|
providerNames: providerNameSet,
|
|
984
|
+
externalCliAvailability: externalCliAvailability ?? new Map(),
|
|
953
985
|
restrictedSources,
|
|
954
986
|
}));
|
|
955
987
|
}
|
package/src/api/preflight.ts
CHANGED
|
@@ -7,11 +7,11 @@ import { buildSkillInjection, normalizeSkillInput, resolveSkillsWithFallback } f
|
|
|
7
7
|
import { buildAgentMemoryInjection } from "../agents/agent-memory.ts";
|
|
8
8
|
import { buildModelCandidates, inheritsParentModel, resolveEffectiveSubagentModel, resolveModelOrigin, type AvailableModelInfo, type ParentModel } from "../runs/shared/model-fallback.ts";
|
|
9
9
|
import { resolveModelScopesForAgent } from "../runs/shared/model-scope.ts";
|
|
10
|
-
import { applyThinkingSuffix, resolvePiLaunchToolPlan, type PiLaunchToolPlan } from "../runs/shared/
|
|
10
|
+
import { applyThinkingSuffix, resolvePiLaunchToolPlan, type PiLaunchToolPlan } from "../runs/shared/child-tool-plan.ts";
|
|
11
11
|
import { injectOutputPathSystemPrompt, normalizeSingleOutputOverride, resolveSingleOutputPath } from "../runs/shared/single-output.ts";
|
|
12
12
|
import { getArtifactPaths, getArtifactsDir } from "../shared/artifacts.ts";
|
|
13
13
|
import { resolveEffectiveThinking } from "../shared/model-info.ts";
|
|
14
|
-
import { assertThinkingWithinCeiling,
|
|
14
|
+
import { assertThinkingWithinCeiling, intersectThinkingCeilings, type ThinkingLevel } from "../shared/thinking-ceiling.ts";
|
|
15
15
|
import { SUBAGENT_LIFECYCLE_ARTIFACT_VERSION, type ArtifactDirPreference, type ArtifactPaths, type JsonSchemaObject, type OutputMode } from "../shared/types.ts";
|
|
16
16
|
import { capabilityCeilingAgentRestrictionMessage, intersectSubagentCapabilityCeilings, type ResolvedSubagentCapabilityCeiling, type SubagentCapabilityAudit } from "../runs/shared/capability-ceiling.ts";
|
|
17
17
|
import { resolvePermissionRules } from "../runs/shared/permissions.ts";
|
|
@@ -330,7 +330,6 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
|
|
|
330
330
|
discovered.maxThinking,
|
|
331
331
|
input.thinkingCeiling,
|
|
332
332
|
input.inheritedThinkingCeiling,
|
|
333
|
-
decodeThinkingCeiling(process.env[SUBAGENT_THINKING_CEILING_ENV]),
|
|
334
333
|
);
|
|
335
334
|
const model = externalRunner ? undefined : applyThinkingSuffix(primaryModel, effectiveThinkingConfig, input.thinking !== undefined);
|
|
336
335
|
const modelCandidates = externalRunner
|
package/src/extension/doctor.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { discoverAgentsAll, type AgentSource } from "../agents/agents.ts";
|
|
|
4
4
|
import { isAsyncAvailable } from "../runs/background/async-execution.ts";
|
|
5
5
|
import { formatSpawnBudgetSummary, getSpawnBudgetSnapshot } from "../runs/shared/spawn-budget.ts";
|
|
6
6
|
import { getActiveAsyncCapacitySnapshot, resolveAbandonedSlotReleaseAfterMs, resolveMaxActiveAsyncRunsPerSession } from "../runs/background/active-async-capacity.ts";
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
import { diagnoseIntercomBridge, type IntercomBridgeDiagnostic } from "../intercom/intercom-bridge.ts";
|
|
9
9
|
import { discoverAvailableSkills, type SkillSource } from "../agents/skills.ts";
|
|
10
10
|
import {
|
|
@@ -178,14 +178,6 @@ function formatSpawnBudgetSection(input: DoctorReportInput): string[] {
|
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
function formatRunFanoutSection(input: DoctorReportInput): string[] {
|
|
181
|
-
try {
|
|
182
|
-
const inherited = decodeRunFanoutBudgetDescriptor(process.env[RUN_FANOUT_BUDGET_ENV]);
|
|
183
|
-
if (inherited) {
|
|
184
|
-
return [`- usage: ${formatRunFanoutBudget(getRunFanoutBudgetSnapshot(inherited)).replace(/^Run fan-out: /, "")}`, `- root run: ${inherited.rootRunId}`, "- reset boundary: cumulative claims are never released; a new top-level run creates a new budget"];
|
|
185
|
-
}
|
|
186
|
-
} catch (error) {
|
|
187
|
-
return [`- inherited budget: invalid — ${errorText(error)}`];
|
|
188
|
-
}
|
|
189
181
|
const configured = resolveMaxSubagentSpawnsPerRun(input.config.maxSubagentSpawnsPerRun);
|
|
190
182
|
const source = normalizeMaxSubagentSpawnsPerRun(process.env.PI_SUBAGENT_MAX_SPAWNS_PER_RUN) !== undefined
|
|
191
183
|
? "environment"
|
|
@@ -214,7 +206,7 @@ function formatPermissionSystemSection(): string[] {
|
|
|
214
206
|
if (trimmed) {
|
|
215
207
|
lines.push(`- parent session: set (${trimmed})`);
|
|
216
208
|
} else {
|
|
217
|
-
lines.push("- parent session: not set — ask forwarding from
|
|
209
|
+
lines.push("- parent session: not set — ask forwarding from background children will not reach a parent UI");
|
|
218
210
|
}
|
|
219
211
|
const isChild = process.env["PI_SUBAGENT_CHILD"] === "1";
|
|
220
212
|
lines.push(`- subagent process: ${isChild ? "yes (PI_SUBAGENT_CHILD=1)" : "no"}`);
|