pi-subagents 0.19.0 → 0.19.2
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 +16 -0
- package/README.md +596 -846
- package/doctor.ts +198 -0
- package/index.ts +4 -1
- package/intercom-bridge.ts +58 -6
- package/package.json +1 -1
- package/prompts/gather-context-and-clarify.md +13 -0
- package/prompts/oracle-executor.md +9 -0
- package/prompts/parallel-research.md +50 -0
- package/prompts/parallel-review.md +32 -2
- package/schemas.ts +1 -1
- package/skills/pi-subagents/SKILL.md +124 -20
- package/slash-commands.ts +83 -29
- package/slash-live-state.ts +3 -3
- package/subagent-executor.ts +35 -1
- package/subagents-status.ts +13 -7
|
@@ -15,8 +15,8 @@ agents into a workflow, or create/edit agents and chains on demand.
|
|
|
15
15
|
|
|
16
16
|
## When to Use
|
|
17
17
|
|
|
18
|
-
- **Advisory review**:
|
|
19
|
-
- **Implementation handoff**: have `oracle` advise, then `oracle-executor` or `worker` implement
|
|
18
|
+
- **Advisory review**: use fresh-context `reviewer` agents for adversarial code review, or fork to `oracle` when inherited decisions and drift matter
|
|
19
|
+
- **Implementation handoff**: have `oracle` advise, then `oracle-executor` or `worker` implement only after an approved direction
|
|
20
20
|
- **Recon and planning**: use `scout` or `context-builder`, then `planner`
|
|
21
21
|
- **Parallel exploration**: run multiple non-conflicting tasks concurrently
|
|
22
22
|
- **Long-running work**: launch async/background runs and inspect them later
|
|
@@ -32,11 +32,19 @@ Humans often use the slash-command layer instead:
|
|
|
32
32
|
- `/chain` — launch a chain of steps
|
|
33
33
|
- `/parallel` — launch top-level parallel tasks
|
|
34
34
|
- `/agents` — open the agents manager TUI
|
|
35
|
+
- `/run-chain` — launch a saved `.chain.md` workflow
|
|
35
36
|
- `/subagents-status` — inspect active/recent async runs
|
|
37
|
+
- `/subagents-doctor` — diagnose setup, discovery, async paths, and intercom bridge state
|
|
36
38
|
|
|
37
39
|
Prefer the tool when you are writing agent logic. Prefer the slash commands when
|
|
38
40
|
you are guiding a human through an interactive flow.
|
|
39
41
|
|
|
42
|
+
Packaged prompt shortcuts are also available for repeatable workflows:
|
|
43
|
+
- `/parallel-review` — fresh-context reviewers with distinct review angles, then synthesis
|
|
44
|
+
- `/parallel-research` — combine `researcher` and `scout` for external evidence plus local code context
|
|
45
|
+
- `/gather-context-and-clarify` — scout/research first, then ask the user clarifying questions with `interview`
|
|
46
|
+
- `/oracle-executor` — send an explicitly approved implementation task to `oracle-executor`
|
|
47
|
+
|
|
40
48
|
## Builtin Agents
|
|
41
49
|
|
|
42
50
|
Builtin agents load at the lowest priority. Project agents override user agents,
|
|
@@ -54,16 +62,40 @@ and user/project agents override builtins with the same name.
|
|
|
54
62
|
| `oracle` | Decision-consistency advisory review | `openai-codex/gpt-5.5` | Advisory review, intercom coordination |
|
|
55
63
|
| `oracle-executor` | Implementation after approval | `openai-codex/gpt-5.5` | Single-writer implementation after approval |
|
|
56
64
|
|
|
57
|
-
Override builtin defaults
|
|
58
|
-
|
|
65
|
+
Override builtin defaults before copying full agent files when a small tweak is enough.
|
|
66
|
+
|
|
67
|
+
For one run, use inline config:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
/run reviewer[model=anthropic/claude-sonnet-4] "Review this diff"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For persistent tweaks, prefer `/agents`: choose the builtin, press `e`, change the model or other fields, then save a user or project override. User overrides apply everywhere. Project overrides apply only in that repo and win over user overrides.
|
|
59
74
|
|
|
60
75
|
Settings locations:
|
|
61
76
|
- User scope: `~/.pi/agent/settings.json`
|
|
62
77
|
- Project scope: `.pi/settings.json`
|
|
63
78
|
|
|
79
|
+
Direct settings example:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"subagents": {
|
|
84
|
+
"agentOverrides": {
|
|
85
|
+
"reviewer": {
|
|
86
|
+
"model": "anthropic/claude-sonnet-4",
|
|
87
|
+
"thinking": "high",
|
|
88
|
+
"fallbackModels": ["openai/gpt-5-mini"]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
64
95
|
Useful override fields: `model`, `fallbackModels`, `thinking`,
|
|
65
96
|
`systemPromptMode`, `inheritProjectContext`, `inheritSkills`, `disabled`,
|
|
66
|
-
`skills`, `tools`, and `systemPrompt`.
|
|
97
|
+
`skills`, `tools`, and `systemPrompt`. Create a user or project agent with the
|
|
98
|
+
same name only when you want a substantially different agent.
|
|
67
99
|
|
|
68
100
|
## Discovery and Scope Rules
|
|
69
101
|
|
|
@@ -119,6 +151,21 @@ subagent({
|
|
|
119
151
|
})
|
|
120
152
|
```
|
|
121
153
|
|
|
154
|
+
Top-level parallel tasks can override per-task behavior:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
subagent({
|
|
158
|
+
tasks: [
|
|
159
|
+
{ agent: "scout", task: "Map auth", output: "auth-context.md", progress: true },
|
|
160
|
+
{ agent: "researcher", task: "Research OAuth best practices", output: "oauth-research.md" },
|
|
161
|
+
{ agent: "reviewer", task: "Review auth tests", model: "anthropic/claude-sonnet-4" }
|
|
162
|
+
],
|
|
163
|
+
concurrency: 3
|
|
164
|
+
})
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Avoid duplicate output paths in parallel tasks. Concurrent children should not write to the same file.
|
|
168
|
+
|
|
122
169
|
### Chain execution
|
|
123
170
|
|
|
124
171
|
```typescript
|
|
@@ -147,6 +194,14 @@ subagent({
|
|
|
147
194
|
|
|
148
195
|
Inspect async runs with `subagent({ action: "status", id: "..." })`, `subagent({ action: "status" })` for active runs, or the `/subagents-status` slash command.
|
|
149
196
|
|
|
197
|
+
Use diagnostics when setup or child startup looks wrong:
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
subagent({ action: "doctor" })
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Humans can use `/subagents-doctor` for the same read-only report. It checks runtime paths, discovery counts, async support, current session context, and intercom bridge state.
|
|
204
|
+
|
|
150
205
|
### Subagent control
|
|
151
206
|
|
|
152
207
|
Subagent control is the runtime visibility and intervention layer for delegated runs. It is separate from lifecycle status. Lifecycle status says whether a child is `queued`, `running`, `paused`, `complete`, or `failed`. Activity reporting is factual: it tracks the last observed activity time and the current tool when known. It does not pretend to know that a child is truly stuck.
|
|
@@ -198,6 +253,8 @@ subagent({
|
|
|
198
253
|
Chains default to clarify mode unless you explicitly set `clarify: false`.
|
|
199
254
|
For programmatic background launches, use `clarify: false, async: true`.
|
|
200
255
|
|
|
256
|
+
The `/agents` manager also has launch toggles for forked context, background execution, and worktree-isolated parallel runs. Use it when guiding a human who wants to inspect or edit the launch before starting.
|
|
257
|
+
|
|
201
258
|
## Worktree Isolation
|
|
202
259
|
|
|
203
260
|
When multiple agents might write concurrently, use worktrees instead of letting
|
|
@@ -249,35 +306,44 @@ history as a baseline contract.
|
|
|
249
306
|
|
|
250
307
|
## Subagent + Intercom Coordination
|
|
251
308
|
|
|
252
|
-
When `pi-intercom` is installed and enabled,
|
|
253
|
-
the orchestrator through the intercom bridge.
|
|
309
|
+
`pi-subagents` works without `pi-intercom`. When `pi-intercom` is installed and enabled, the intercom bridge can automatically give child agents a private coordination channel back to the parent session.
|
|
254
310
|
|
|
255
|
-
|
|
311
|
+
Most agents should not call `intercom` directly unless bridge instructions provide a target. Do not invent a target. Use the target from the injected bridge instructions or from a visible needs-attention notice.
|
|
312
|
+
|
|
313
|
+
Use `intercom` when:
|
|
314
|
+
- a subagent is blocked on a decision
|
|
315
|
+
- a child needs clarification instead of guessing
|
|
316
|
+
- a detached or async child needs to coordinate without waiting for normal tool return flow
|
|
317
|
+
- an advisory agent was explicitly asked to send a concise progress update
|
|
318
|
+
|
|
319
|
+
Message conventions:
|
|
320
|
+
- `ask` means the child needs a decision or clarification from the parent session.
|
|
321
|
+
- `send` means a short blocked/progress update, only when blocked or explicitly asked.
|
|
322
|
+
- Routine completion does not go through intercom. The normal subagent result still returns through `pi-subagents`.
|
|
323
|
+
|
|
324
|
+
If a bridge target is available, a child can ask:
|
|
256
325
|
|
|
257
326
|
```typescript
|
|
258
327
|
intercom({
|
|
259
328
|
action: "ask",
|
|
260
|
-
to: "
|
|
329
|
+
to: "<bridge-provided-target>",
|
|
261
330
|
message: "Should I optimize for readability or performance here?"
|
|
262
331
|
})
|
|
263
332
|
```
|
|
264
333
|
|
|
265
|
-
|
|
334
|
+
The parent replies with:
|
|
266
335
|
|
|
267
336
|
```typescript
|
|
268
337
|
intercom({ action: "reply", message: "Optimize for readability." })
|
|
269
338
|
```
|
|
270
339
|
|
|
271
|
-
Or
|
|
340
|
+
Or inspects unresolved asks first:
|
|
272
341
|
|
|
273
342
|
```typescript
|
|
274
343
|
intercom({ action: "pending" })
|
|
275
344
|
```
|
|
276
345
|
|
|
277
|
-
|
|
278
|
-
- a subagent is blocked on a decision
|
|
279
|
-
- an advisory agent wants to send a concise handoff mid-flight
|
|
280
|
-
- a detached or async child needs to coordinate without waiting for normal tool return flow
|
|
346
|
+
If intercom messages do not show up, run `subagent({ action: "doctor" })` or `/subagents-doctor`.
|
|
281
347
|
|
|
282
348
|
## Management Mode
|
|
283
349
|
|
|
@@ -326,6 +392,8 @@ subagent({ action: "delete", agent: "my-agent" })
|
|
|
326
392
|
Use management actions when the system needs to create or edit subagents on
|
|
327
393
|
demand without dropping into raw file editing.
|
|
328
394
|
|
|
395
|
+
Management actions create or update user/project agent files. For small builtin changes such as a model swap, prefer `/agents` builtin overrides or `subagents.agentOverrides` in settings.
|
|
396
|
+
|
|
329
397
|
## Creating and Editing Agents by File
|
|
330
398
|
|
|
331
399
|
A minimal agent file looks like this:
|
|
@@ -357,7 +425,12 @@ copying a full builtin file.
|
|
|
357
425
|
|
|
358
426
|
## Prompt Template Integration
|
|
359
427
|
|
|
360
|
-
|
|
428
|
+
The package includes prompt shortcuts for common workflows: `/parallel-review`,
|
|
429
|
+
`/parallel-research`, `/gather-context-and-clarify`, and `/oracle-executor`.
|
|
430
|
+
Use them when the user wants repeatable review, research, clarification, or
|
|
431
|
+
approved execution patterns.
|
|
432
|
+
|
|
433
|
+
If `pi-prompt-template-model` is installed, additional user prompt templates can delegate into
|
|
361
434
|
`pi-subagents`. This is useful when a slash command should always run through a
|
|
362
435
|
particular agent or with forked context.
|
|
363
436
|
|
|
@@ -366,7 +439,7 @@ particular agent or with forked context.
|
|
|
366
439
|
- **Forking requires a persisted parent session.** If the current session does not
|
|
367
440
|
have a persisted session file, forked runs fail.
|
|
368
441
|
- **Forked runs inherit parent history.** They are branched threads, not fresh
|
|
369
|
-
filtered contexts.
|
|
442
|
+
filtered contexts. Use fresh context for adversarial reviewers unless the user explicitly asks for forked context.
|
|
370
443
|
- **Default subagent nesting depth is 2.** Deeper recursive delegation is blocked
|
|
371
444
|
unless configured otherwise.
|
|
372
445
|
- **Attention signals are not lifecycle state.** `needs_attention` means no activity has been observed past the configured threshold. `paused` means the child turn was intentionally interrupted or is awaiting direction; it is not the same as `failed`.
|
|
@@ -386,7 +459,10 @@ for the actual write path.
|
|
|
386
459
|
### Use fork for branched advisory or execution threads
|
|
387
460
|
|
|
388
461
|
Forked runs are useful when the child should reason in a separate thread while
|
|
389
|
-
still inheriting the parent’s accumulated context.
|
|
462
|
+
still inheriting the parent’s accumulated context. They are especially useful for
|
|
463
|
+
`oracle`, which audits inherited decisions and drift. For adversarial code review,
|
|
464
|
+
prefer fresh-context reviewers that inspect the repo and diff directly unless the
|
|
465
|
+
user explicitly requests forked context.
|
|
390
466
|
|
|
391
467
|
### Prefer narrow tasks
|
|
392
468
|
|
|
@@ -426,8 +502,7 @@ subagent({
|
|
|
426
502
|
subagent({ agent: "worker", task: "Add retry logic to the API client." })
|
|
427
503
|
subagent({
|
|
428
504
|
agent: "reviewer",
|
|
429
|
-
task: "Review the retry logic implementation. Look for edge cases and race conditions."
|
|
430
|
-
context: "fork"
|
|
505
|
+
task: "Review the retry logic implementation. Inspect the repo and current diff directly. Look for edge cases and race conditions."
|
|
431
506
|
})
|
|
432
507
|
```
|
|
433
508
|
|
|
@@ -442,6 +517,14 @@ subagent({
|
|
|
442
517
|
})
|
|
443
518
|
```
|
|
444
519
|
|
|
520
|
+
### Saved chain
|
|
521
|
+
|
|
522
|
+
```text
|
|
523
|
+
/run-chain review-chain -- review this branch
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Use saved `.chain.md` workflows when the user wants a repeatable multi-agent flow without rewriting the chain each time.
|
|
527
|
+
|
|
445
528
|
## Error Handling
|
|
446
529
|
|
|
447
530
|
**"Unknown agent"**
|
|
@@ -450,6 +533,12 @@ subagent({ action: "list" })
|
|
|
450
533
|
// Check available agents and chains, then confirm scope/precedence.
|
|
451
534
|
```
|
|
452
535
|
|
|
536
|
+
**Setup, discovery, or intercom confusion**
|
|
537
|
+
```typescript
|
|
538
|
+
subagent({ action: "doctor" })
|
|
539
|
+
// Check runtime paths, async support, discovery counts, current session, and intercom bridge state.
|
|
540
|
+
```
|
|
541
|
+
|
|
453
542
|
**"Max subagent depth exceeded"**
|
|
454
543
|
```typescript
|
|
455
544
|
// Flatten the workflow or raise maxSubagentDepth in config.
|
|
@@ -464,3 +553,18 @@ subagent({ action: "list" })
|
|
|
464
553
|
```typescript
|
|
465
554
|
// Resolve the current outbound ask before starting another one.
|
|
466
555
|
```
|
|
556
|
+
|
|
557
|
+
**Parallel output-path conflict**
|
|
558
|
+
```typescript
|
|
559
|
+
// Give each parallel task a distinct output path, or disable output for tasks that do not need it.
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
**Worktree launch fails**
|
|
563
|
+
```typescript
|
|
564
|
+
// Ensure the git working tree is clean and task cwd overrides match the shared cwd.
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Child fails before starting**
|
|
568
|
+
```typescript
|
|
569
|
+
// Inspect /subagents-status detail, artifact metadata/output logs, and run doctor. Extension loader errors usually appear in child output logs.
|
|
570
|
+
```
|
package/slash-commands.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
5
5
|
import { Key, matchesKey } from "@mariozechner/pi-tui";
|
|
6
|
-
import { discoverAgents, discoverAgentsAll } from "./agents.ts";
|
|
6
|
+
import { discoverAgents, discoverAgentsAll, type ChainConfig } from "./agents.ts";
|
|
7
7
|
import { AgentManagerComponent, type ManagerResult } from "./agent-manager.ts";
|
|
8
8
|
import { SubagentsStatusComponent } from "./subagents-status.ts";
|
|
9
9
|
import { discoverAvailableSkills } from "./skills.ts";
|
|
@@ -108,6 +108,36 @@ const makeAgentCompletions = (state: SubagentState, multiAgent: boolean) => (pre
|
|
|
108
108
|
return agents.filter((a) => a.name.startsWith(lastWord)).map((a) => ({ value: `${beforeLastWord}${a.name}`, label: a.name }));
|
|
109
109
|
};
|
|
110
110
|
|
|
111
|
+
const discoverSavedChains = (cwd: string): ChainConfig[] => {
|
|
112
|
+
const chainsByName = new Map<string, ChainConfig>();
|
|
113
|
+
for (const chain of discoverAgentsAll(cwd).chains) {
|
|
114
|
+
chainsByName.set(chain.name, chain);
|
|
115
|
+
}
|
|
116
|
+
return Array.from(chainsByName.values());
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const makeChainCompletions = (state: SubagentState) => (prefix: string) => {
|
|
120
|
+
if (prefix.includes(" ")) return null;
|
|
121
|
+
return discoverSavedChains(state.baseCwd)
|
|
122
|
+
.filter((chain) => chain.name.startsWith(prefix))
|
|
123
|
+
.map((chain) => ({ value: chain.name, label: chain.name }));
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const mapSavedChainSteps = (chain: ChainConfig, worktree = false): ChainStep[] => {
|
|
127
|
+
return (chain.steps as Array<ChainStep & { skills?: string[] | false }>).map((step) => {
|
|
128
|
+
if (isParallelStep(step)) return worktree ? { ...step, worktree: true } : { ...step };
|
|
129
|
+
return {
|
|
130
|
+
agent: step.agent,
|
|
131
|
+
task: step.task || undefined,
|
|
132
|
+
output: step.output,
|
|
133
|
+
reads: step.reads,
|
|
134
|
+
progress: step.progress,
|
|
135
|
+
skill: step.skill ?? step.skills,
|
|
136
|
+
model: step.model,
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
|
|
111
141
|
async function requestSlashRun(
|
|
112
142
|
pi: ExtensionAPI,
|
|
113
143
|
ctx: ExtensionContext,
|
|
@@ -328,19 +358,7 @@ async function openAgentManager(
|
|
|
328
358
|
if (result.action === "launch") {
|
|
329
359
|
await runSlashSubagent(pi, ctx, { agent: result.agent, task: result.task, ...launchOptions });
|
|
330
360
|
} else if (result.action === "launch-chain") {
|
|
331
|
-
|
|
332
|
-
if (isParallelStep(step)) return result.worktree ? { ...step, worktree: true } : { ...step };
|
|
333
|
-
return {
|
|
334
|
-
agent: step.agent,
|
|
335
|
-
task: step.task || undefined,
|
|
336
|
-
output: step.output,
|
|
337
|
-
reads: step.reads,
|
|
338
|
-
progress: step.progress,
|
|
339
|
-
skill: step.skill ?? (step as typeof step & { skills?: string[] | false }).skills,
|
|
340
|
-
model: step.model,
|
|
341
|
-
};
|
|
342
|
-
});
|
|
343
|
-
await runSlashSubagent(pi, ctx, { chain: chainParam, task: result.task, ...launchOptions });
|
|
361
|
+
await runSlashSubagent(pi, ctx, { chain: mapSavedChainSteps(result.chain, result.worktree), task: result.task, ...launchOptions });
|
|
344
362
|
} else if (result.action === "parallel") {
|
|
345
363
|
await runSlashSubagent(pi, ctx, {
|
|
346
364
|
tasks: result.tasks,
|
|
@@ -489,24 +507,53 @@ export function registerSlashCommands(
|
|
|
489
507
|
},
|
|
490
508
|
});
|
|
491
509
|
|
|
510
|
+
pi.registerCommand("run-chain", {
|
|
511
|
+
description: "Run a saved chain: /run-chain chainName -- task [--bg] [--fork]",
|
|
512
|
+
getArgumentCompletions: makeChainCompletions(state),
|
|
513
|
+
handler: async (args, ctx) => {
|
|
514
|
+
const { args: cleanedArgs, bg, fork } = extractExecutionFlags(args);
|
|
515
|
+
const delimiterIndex = cleanedArgs.indexOf(" -- ");
|
|
516
|
+
const usage = "Usage: /run-chain <chainName> -- <task> [--bg] [--fork]";
|
|
517
|
+
if (delimiterIndex === -1) {
|
|
518
|
+
ctx.ui.notify(usage, "error");
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const chainName = cleanedArgs.slice(0, delimiterIndex).trim();
|
|
522
|
+
const task = cleanedArgs.slice(delimiterIndex + 4).trim();
|
|
523
|
+
if (!chainName || !task) {
|
|
524
|
+
ctx.ui.notify(usage, "error");
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
const chain = discoverSavedChains(state.baseCwd).find((candidate) => candidate.name === chainName);
|
|
528
|
+
if (!chain) {
|
|
529
|
+
ctx.ui.notify(`Unknown chain: ${chainName}`, "error");
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
const params: SubagentParamsLike = { chain: mapSavedChainSteps(chain), task, clarify: false, agentScope: "both" };
|
|
533
|
+
if (bg) params.async = true;
|
|
534
|
+
if (fork) params.context = "fork";
|
|
535
|
+
await runSlashSubagent(pi, ctx, params);
|
|
536
|
+
},
|
|
537
|
+
});
|
|
538
|
+
|
|
492
539
|
pi.registerCommand("parallel", {
|
|
493
540
|
description: "Run agents in parallel: /parallel scout \"task1\" -> reviewer \"task2\" [--bg] [--fork]",
|
|
494
541
|
getArgumentCompletions: makeAgentCompletions(state, true),
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
542
|
+
handler: async (args, ctx) => {
|
|
543
|
+
const { args: cleanedArgs, bg, fork } = extractExecutionFlags(args);
|
|
544
|
+
const parsed = parseAgentArgs(state, cleanedArgs, "parallel", ctx);
|
|
545
|
+
if (!parsed) return;
|
|
546
|
+
const tasks = parsed.steps.map(({ name, config, task: stepTask }) => ({
|
|
547
|
+
agent: name,
|
|
548
|
+
task: stepTask ?? parsed.task,
|
|
549
|
+
...(config.output !== undefined ? { output: config.output } : {}),
|
|
550
|
+
...(config.reads !== undefined ? { reads: config.reads } : {}),
|
|
551
|
+
...(config.model ? { model: config.model } : {}),
|
|
552
|
+
...(config.skill !== undefined ? { skill: config.skill } : {}),
|
|
553
|
+
...(config.progress !== undefined ? { progress: config.progress } : {}),
|
|
554
|
+
}));
|
|
555
|
+
const params: SubagentParamsLike = { tasks, clarify: false, agentScope: "both" };
|
|
556
|
+
if (bg) params.async = true;
|
|
510
557
|
if (fork) params.context = "fork";
|
|
511
558
|
await runSlashSubagent(pi, ctx, params);
|
|
512
559
|
},
|
|
@@ -522,6 +569,13 @@ export function registerSlashCommands(
|
|
|
522
569
|
},
|
|
523
570
|
});
|
|
524
571
|
|
|
572
|
+
pi.registerCommand("subagents-doctor", {
|
|
573
|
+
description: "Show subagent diagnostics",
|
|
574
|
+
handler: async (_args, ctx) => {
|
|
575
|
+
await runSlashSubagent(pi, ctx, { action: "doctor" });
|
|
576
|
+
},
|
|
577
|
+
});
|
|
578
|
+
|
|
525
579
|
pi.registerShortcut("ctrl+shift+a", {
|
|
526
580
|
handler: async (ctx) => {
|
|
527
581
|
await openAgentManager(pi, ctx);
|
package/slash-live-state.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
|
2
2
|
import type { Message } from "@mariozechner/pi-ai";
|
|
3
|
-
import type { SubagentParamsLike } from "./subagent-executor.
|
|
4
|
-
import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.
|
|
5
|
-
import { type Details, type SingleResult, type Usage, SLASH_RESULT_TYPE } from "./types.
|
|
3
|
+
import type { SubagentParamsLike } from "./subagent-executor.ts";
|
|
4
|
+
import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.ts";
|
|
5
|
+
import { type Details, type SingleResult, type Usage, SLASH_RESULT_TYPE } from "./types.ts";
|
|
6
6
|
|
|
7
7
|
export interface SlashMessageDetails {
|
|
8
8
|
requestId: string;
|
package/subagent-executor.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { ChainClarifyComponent, type ChainClarifyResult, type ModelInfo } from "
|
|
|
9
9
|
import { executeChain } from "./chain-execution.ts";
|
|
10
10
|
import { resolveExecutionAgentScope } from "./agent-scope.ts";
|
|
11
11
|
import { handleManagementAction } from "./agent-management.ts";
|
|
12
|
+
import { buildDoctorReport } from "./doctor.ts";
|
|
12
13
|
import { runSync } from "./execution.ts";
|
|
13
14
|
import { resolveModelCandidate } from "./model-fallback.ts";
|
|
14
15
|
import { aggregateParallelOutputs } from "./parallel-utils.ts";
|
|
@@ -1544,6 +1545,39 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
1544
1545
|
const requestCwd = resolveRequestedCwd(ctx.cwd, params.cwd);
|
|
1545
1546
|
const paramsWithResolvedCwd = params.cwd === undefined ? params : { ...params, cwd: requestCwd };
|
|
1546
1547
|
if (params.action) {
|
|
1548
|
+
if (params.action === "doctor") {
|
|
1549
|
+
let currentSessionFile: string | null = null;
|
|
1550
|
+
let currentSessionId = deps.state.currentSessionId;
|
|
1551
|
+
let sessionError: string | undefined;
|
|
1552
|
+
try {
|
|
1553
|
+
currentSessionFile = ctx.sessionManager.getSessionFile() ?? null;
|
|
1554
|
+
currentSessionId = ctx.sessionManager.getSessionId();
|
|
1555
|
+
} catch (error) {
|
|
1556
|
+
sessionError = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
1557
|
+
}
|
|
1558
|
+
let orchestratorTarget: string | undefined;
|
|
1559
|
+
try {
|
|
1560
|
+
orchestratorTarget = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
1561
|
+
} catch {}
|
|
1562
|
+
return {
|
|
1563
|
+
content: [{
|
|
1564
|
+
type: "text",
|
|
1565
|
+
text: buildDoctorReport({
|
|
1566
|
+
cwd: requestCwd,
|
|
1567
|
+
config: deps.config,
|
|
1568
|
+
state: deps.state,
|
|
1569
|
+
context: paramsWithResolvedCwd.context,
|
|
1570
|
+
requestedSessionDir: paramsWithResolvedCwd.sessionDir,
|
|
1571
|
+
currentSessionFile,
|
|
1572
|
+
currentSessionId,
|
|
1573
|
+
orchestratorTarget,
|
|
1574
|
+
sessionError,
|
|
1575
|
+
expandTilde: deps.expandTilde,
|
|
1576
|
+
}),
|
|
1577
|
+
}],
|
|
1578
|
+
details: { mode: "management", results: [] },
|
|
1579
|
+
};
|
|
1580
|
+
}
|
|
1547
1581
|
if (params.action === "status") {
|
|
1548
1582
|
const foreground = getForegroundControl(deps.state, paramsWithResolvedCwd.id ?? paramsWithResolvedCwd.runId);
|
|
1549
1583
|
if (foreground) return foregroundStatusResult(foreground);
|
|
@@ -1576,7 +1610,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
1576
1610
|
details: { mode: "management", results: [] },
|
|
1577
1611
|
};
|
|
1578
1612
|
}
|
|
1579
|
-
const validActions = ["list", "get", "create", "update", "delete", "status", "interrupt"];
|
|
1613
|
+
const validActions = ["list", "get", "create", "update", "delete", "status", "interrupt", "doctor"];
|
|
1580
1614
|
if (!validActions.includes(params.action)) {
|
|
1581
1615
|
return {
|
|
1582
1616
|
content: [{ type: "text", text: `Unknown action: ${params.action}. Valid: ${validActions.join(", ")}` }],
|
package/subagents-status.ts
CHANGED
|
@@ -3,10 +3,10 @@ import * as path from "node:path";
|
|
|
3
3
|
import type { Theme } from "@mariozechner/pi-coding-agent";
|
|
4
4
|
import type { Component, TUI } from "@mariozechner/pi-tui";
|
|
5
5
|
import { matchesKey, truncateToWidth } from "@mariozechner/pi-tui";
|
|
6
|
-
import { type AsyncRunOverlayData, type AsyncRunSummary, listAsyncRunsForOverlay } from "./async-status.
|
|
7
|
-
import { ASYNC_DIR } from "./types.
|
|
8
|
-
import { formatDuration, formatTokens, shortenPath } from "./formatters.
|
|
9
|
-
import { formatScrollInfo, renderFooter, renderHeader, row } from "./render-helpers.
|
|
6
|
+
import { type AsyncRunOverlayData, type AsyncRunSummary, listAsyncRunsForOverlay } from "./async-status.ts";
|
|
7
|
+
import { ASYNC_DIR } from "./types.ts";
|
|
8
|
+
import { formatDuration, formatTokens, shortenPath } from "./formatters.ts";
|
|
9
|
+
import { formatScrollInfo, renderFooter, renderHeader, row } from "./render-helpers.ts";
|
|
10
10
|
|
|
11
11
|
const AUTO_REFRESH_MS = 2000;
|
|
12
12
|
const DETAIL_EVENT_LIMIT = 8;
|
|
@@ -178,13 +178,19 @@ export class SubagentsStatusComponent implements Component {
|
|
|
178
178
|
private recent: AsyncRunSummary[] = [];
|
|
179
179
|
private rows: StatusRow[] = [];
|
|
180
180
|
private errorMessage?: string;
|
|
181
|
+
private tui: TUI;
|
|
182
|
+
private theme: Theme;
|
|
183
|
+
private done: () => void;
|
|
181
184
|
|
|
182
185
|
constructor(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
tui: TUI,
|
|
187
|
+
theme: Theme,
|
|
188
|
+
done: () => void,
|
|
186
189
|
deps: StatusOverlayDeps = {},
|
|
187
190
|
) {
|
|
191
|
+
this.tui = tui;
|
|
192
|
+
this.theme = theme;
|
|
193
|
+
this.done = done;
|
|
188
194
|
this.listRunsForOverlay = deps.listRunsForOverlay ?? listAsyncRunsForOverlay;
|
|
189
195
|
const refreshMs = deps.refreshMs ?? AUTO_REFRESH_MS;
|
|
190
196
|
this.reload();
|