@ferris1225/pi-subagents 3.0.0 → 4.0.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/src/monitor.ts CHANGED
@@ -165,7 +165,7 @@ function tailGraphemes(segments: string[], maxWidth: number): string {
165
165
  * One-line task preview, capped by `maxWidth` display columns (default 80).
166
166
  * `keysOnly` (default): extracted key fragments (paths, quoted phrases,
167
167
  * symbols) are shown bare — the agent name is already displayed next to the
168
- * task line, so templated prose ("explore: trace how ...") adds nothing.
168
+ * task line, so templated prose ("explorer: trace how ...") adds nothing.
169
169
  * `keysOnly: false` keeps the prose as `head…tail` (used for completion
170
170
  * messages, where the Task line is the reader's only context).
171
171
  * Grapheme-safe — CJK, ZWJ emoji and combining sequences are never split.
package/src/prompt.ts CHANGED
@@ -1,80 +1,97 @@
1
1
  /**
2
- * Builds the delegation directive injected into the parent model's system prompt
3
- * via the `before_agent_start` hook. This is the lever that makes the main model
4
- * actually USE the subagent tool proactively (pi never shows it the per-agent
5
- * descriptions otherwise).
6
- *
7
- * The directive is a self-contained replacement for the "Sub-agent Dispatch" and
8
- * "Review, Verification & Commit" sections users otherwise keep in a global
9
- * AGENTS.md — so installing this extension lets them delete those sections without
10
- * losing the behavior. (Other AGENTS.md sections — Behavior, Git & Security,
11
- * platform/language rules — are unrelated and stay put.)
2
+ * Builds the authoritative delegation directive injected into the parent model's
3
+ * system prompt via `before_agent_start`. Tool metadata stays intentionally
4
+ * minimal so role/process guidance is not paid for twice.
12
5
  */
13
6
 
14
7
  import type { AgentConfig } from "./agents.ts";
15
8
  import { formatCatalogEntry } from "./agents.ts";
16
9
 
17
- /** Compact role routing hints, emitted only for roles that are enabled. */
18
- const ROLE_ROUTING: Record<string, string> = {
19
- explore: "explore — codebase reconnaissance: broad/open-ended search, multi-file lookups, mapping unfamiliar code, tracing symbols/dependencies (read-only, competent fast model); NOT for one-line lookups.",
20
- worker: "worker — implement/fix/refactor/test a self-contained task worth a separate context (full tools; plans internally).",
21
- cleaner: "cleaner — evidence-first cleanup for explicit cleanup intent in any language (for example dead code, redundancy, simplification, or over-engineering) or a requested periodic cleanup pass; audit/find/inspect/report is read-only, while explicit remove/clean/simplify/refactor wording permits verified edits; never PR-count or pre-commit driven (reviewer remains the gate).",
22
- reviewer: "reviewer — adversarial pre-commit review of a diff (read-only; independent context).",
23
- };
10
+ function bullets(lines: readonly string[]): string {
11
+ return lines.map((line) => `- ${line}`).join("\n");
12
+ }
24
13
 
25
14
  export function buildDelegationDirective(agents: AgentConfig[]): string {
26
15
  if (agents.length === 0) return "";
27
16
 
28
17
  const catalog = agents.map(formatCatalogEntry).join("\n");
29
- const routing = agents
30
- .map((a) => ROLE_ROUTING[a.name])
31
- .filter((line): line is string => Boolean(line))
32
- .map((line) => `- ${line}`)
33
- .join("\n");
34
- const hasExplore = agents.some((a) => a.name === "explore");
35
- const hasCleaner = agents.some((a) => a.name === "cleaner");
36
- const hasReviewer = agents.some((a) => a.name === "reviewer");
18
+ const hasExplorer = agents.some((agent) => agent.name === "explorer");
19
+ const hasWorker = agents.some((agent) => agent.name === "worker");
20
+ const hasCleaner = agents.some((agent) => agent.name === "cleaner");
21
+ const hasReviewer = agents.some((agent) => agent.name === "reviewer");
37
22
  const hasMultiple = agents.length > 1;
23
+ const worktreeTargets = hasWorker && hasCleaner
24
+ ? "worker, cleaner, or another"
25
+ : hasWorker
26
+ ? "worker or another"
27
+ : hasCleaner
28
+ ? "cleaner or another"
29
+ : "a";
30
+
31
+ const dispatchRules = [
32
+ "Handle simple work inline with direct tools: one-line lookups, known-target reads/edits, and quick questions do not justify a child process.",
33
+ ...(hasExplorer
34
+ ? [
35
+ "Use `explorer` proactively when reconnaissance becomes broad or crosses files: mapping unfamiliar code, tracing symbols/dependencies, or answering multi-file location/reference questions. Treat its output only as a retrieval index; re-read load-bearing files before edits or decisions about deletion, security, compatibility, persistence, or dynamic reachability. Use a stronger model/specialist for complex dynamic, concurrent, migration, or security-sensitive analysis.",
36
+ ]
37
+ : []),
38
+ ...(hasWorker
39
+ ? ["Use `worker` for a self-contained implementation, fix, refactor, or test task whose separate context pays for itself."]
40
+ : []),
41
+ ...(hasCleaner
42
+ ? [
43
+ `Use \`cleaner\` only when the user explicitly authorizes cleanup/removal/simplification edits, including a requested maintenance pass. It gathers evidence, then applies every safe proven in-scope cut; zero edits is valid. Generic or read-only audit, inspect, report, review, code-health, plan, proposed-solution, or cleanup-candidate assessment goes to ${hasReviewer ? "`reviewer`" : "direct main-context inspection because `reviewer` is disabled"}. Never dispatch cleaner by PR count or as the pre-commit gate.`,
44
+ ]
45
+ : []),
46
+ ...(hasReviewer
47
+ ? [
48
+ `Use \`reviewer\` for generic/read-only assessments and as the fresh independent pre-commit gate for non-trivial diffs${hasCleaner ? ", including cleaner edits" : ""}. Advisory findings do not authorize follow-up edits; only gate verdicts can enter auto-fix.`,
49
+ ]
50
+ : []),
51
+ "Brief every child with the complete goal, exact paths, constraints, and expected output. It has no memory of this conversation.",
52
+ "Children are leaf processes without delegation tools. Do not ask them to spawn sub-agents; use `subagent_control fork` on a parked/settled retained thread for an independent continuation.",
53
+ ...(hasMultiple
54
+ ? [
55
+ "Dispatch independent work in one `tasks` array and let the resumed main agent start dependent work only after prerequisites finish.",
56
+ ]
57
+ : []),
58
+ `Filesystem isolation: single tasks default to shared${hasWorker ? "; parallel worker tasks default to detached Git worktrees" : ""}${hasCleaner ? "; cleaner defaults to shared" : ""}. Request \`isolation: "worktree"\` only for ${worktreeTargets} write-capable agent in a Git repository with committed HEAD. Read-only agents reject it, and setup/integration failure never falls back silently to shared.`,
59
+ "A configured child model/provider failure automatically continues the same retained session on the current main model; do not redispatch. Ordinary tool/task failures stay on the selected model.",
60
+ "Trust but verify: inspect actual changes/results before reporting completion.",
61
+ ];
62
+
63
+ const handoffRules = [
64
+ "Dispatch returns immediately and ends this turn. Never sleep, poll, or call `subagent_wait` to hold the turn; results arrive as messages that automatically resume the main agent, even mid-turn.",
65
+ "Use `subagent_wait` with explicit `timeoutMs` only when the user specifically asks you to remain in-turn and wait. Its default lookup is non-blocking.",
66
+ "A result is already shown to the user. Do not restate, paraphrase, or re-summarize it; add only your conclusion or next action, often one line.",
67
+ "A delivered result does not mean siblings are finished. Before declaring the overall task done, use `subagent_status` to confirm that no runs remain active.",
68
+ ];
69
+
70
+ const verificationRules = [
71
+ "Never report an unrun check as passed; identify unavailable checks and pre-existing failures honestly.",
72
+ ...(hasReviewer
73
+ ? [
74
+ "Send every non-trivial diff through one fresh read-only `reviewer` gate before reporting done. Resolve every finding; do not bypass the configured auto-fix/re-review cap.",
75
+ "Use multi-model cross-review only when explicitly requested or for genuinely high-risk security, unsafe/FFI, persistence-migration, or concurrency changes.",
76
+ ]
77
+ : []),
78
+ "Commit or push only when explicitly requested, applicable checks pass, and no review finding remains unresolved.",
79
+ ];
38
80
 
39
81
  return `
40
82
  ## Sub-agent delegation (pi-subagents)
41
83
 
42
- You have a \`subagent\` tool that starts specialized agents in ISOLATED background processes.
43
- It immediately ends the current main-agent turn so the user can keep working. When a child
44
- finishes, its result is sent back as a message that automatically resumes the main agent;
45
- if the main agent is busy, the result waits as a follow-up.
46
-
47
- NEVER run sleep, wait, or polling commands (e.g. Start-Sleep, sleep, timeout), and do NOT
48
- call subagent_wait to hold the turn — dispatching already ended it, and results arrive as
49
- messages that resume the main agent automatically (even mid-turn). Ending your turn is the
50
- default and the only correct way to wait; subagent_wait blocks the turn so the user cannot
51
- give you other work meanwhile. It is non-blocking by default: settled results return
52
- immediately, active runs return a "still running — end your turn" note. Pass an explicit
53
- timeoutMs only when you must stay in the turn (e.g. the user asked you to wait).
84
+ The \`subagent\` tool starts specialized leaf agents in isolated Pi child processes and context windows. It returns immediately; completion messages automatically resume the main agent.
54
85
 
55
86
  Available agents:
56
87
  ${catalog}
57
88
 
58
- ${routing ? `Routing:\n${routing}\n` : ""}Dispatch discipline:
59
- - Handle SIMPLE work INLINE with direct tools: a one-line lookup, single edit, or quick question is a grep/read/edit in the main context — never a sub-agent. Sub-agents cost startup time, tokens, and a context switch.
60
- - Use \`explore\` PROACTIVELY for codebase reconnaissance: mapping an unfamiliar area, multi-file lookups, tracing symbols across modules, or any "where is X / which files reference Y" question that would take several greps or reading multiple files. It should run on a competent fast code model and returns compressed findings, saving main-context space.
61
- - Delegate only when isolation genuinely pays: a self-contained implementation/fix with its own validation (worker)${hasCleaner ? ", explicit evidence-first cleanup (cleaner)" : ""}, or a fresh-context review gate (reviewer).
62
- ${hasCleaner ? "- Route explicit cleanup intent in any language to `cleaner` (for example dead code, redundancy, simplification, or over-engineering), including a requested periodic maintenance pass. Audit/find/inspect/report wording means read-only evidence; apply only for explicit remove/clean/simplify/refactor wording. Generic code review without cleanup intent goes to `reviewer`. Never dispatch cleaner by PR count or automatically as the pre-commit gate; `reviewer` separately reviews cleaner edits.\n" : ""}- When in doubt, start with a direct tool call in the main context; escalate to \`explore\` as soon as the search turns broad or crosses multiple files.
63
- - For an already-known or trivial target, use a direct search/read tool (e.g. grep/find/read) — do not over-delegate a one-line lookup.
64
- ${hasMultiple ? `- Run INDEPENDENT tasks in parallel: one subagent call with a \`tasks\` array, and track them with your todo list. Parallel worker items default to detached Git worktree isolation; pass \`isolation: "shared"\` only when a worker intentionally needs the caller's live uncommitted tree.${hasCleaner ? " Cleaner is also write-capable and may use explicit worktree isolation." : ""} Let the automatically resumed main agent launch dependent work only after its prerequisite result arrives (e.g. explore, then ${hasCleaner ? "worker/cleaner" : "worker"}, then reviewer).\n` : ""}- Single dispatch stays in the shared working tree by default. Use \`isolation: "worktree"\` only for ${hasCleaner ? "worker, cleaner, or another" : "worker or another"} write-capable agent in a Git repository; never request it for explore/reviewer, and never silently retry shared after setup fails.
65
- - Brief each sub-agent as self-contained: goal, exact paths, constraints, expected output. It has NO memory of this conversation.
66
- - Treat delegated agents as leaf workers: do not ask a sub-agent to dispatch another sub-agent; child processes do not have this tool. Use \`subagent_control fork\` on a parked/settled retained thread when you need an independent continuation with preserved context and a new run id.
67
- - Trust but verify: a sub-agent's summary describes intent, not outcome. Check the actual changes/results before reporting work done.
68
- ${hasExplore ? "- Treat `explore` findings as a retrieval index, never as sole proof for edits, deletion, security, compatibility, persistence, or dynamic reachability. Re-read load-bearing files before acting. An underpowered model can be false economy on complex dynamic, concurrent, migration, or security-sensitive code; use a stronger model or specialist there.\n" : ""}
69
- Result handoff (do not re-state):
70
- - A sub-agent's result arrives as a message that is already shown to the user. Do NOT restate, paraphrase, or re-summarize its findings in your reply — that just burns tokens duplicating what is already visible. The user can read the result above.
71
- - Reply only with what you ADD: your own conclusion, the next action you are taking, or a one-line acknowledgement. When the result already answers the user, a single sentence is enough — then end your turn or proceed.
72
- - Read the result and act on it (verify, continue, commit). Keep your own output short.
73
- - A result arriving does NOT mean all work is finished: sub-agents run in the background and siblings may still be active (a delivery names any still-running runs). Do not report the overall task complete until no runs are active — call subagent_status to confirm before saying Done.
89
+ Dispatch:
90
+ ${bullets(dispatchRules)}
91
+
92
+ Result handoff:
93
+ ${bullets(handoffRules)}
74
94
 
75
- Review & verification:
76
- - Never report an unrun check as passed; report it as unavailable or as a pre-existing failure.
77
- ${hasReviewer ? `- For non-trivial diffs${hasCleaner ? " (including cleaner edits)" : ""}, run one fresh read-only \`reviewer\` sub-agent before reporting done. Fix every finding the reviewer reports and re-review at most once.
78
- - Use multi-model cross-review only when explicitly requested or for genuinely high-risk changes (security, unsafe/FFI, persistence-migration, concurrency). Reviewers are read-only; only the main agent edits.
79
- ` : ""}- Commit or push only when explicitly requested, applicable checks pass, and no unresolved review findings remain.`;
95
+ Review and verification:
96
+ ${bullets(verificationRules)}`;
80
97
  }