pi-subagents 0.14.1 → 0.15.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 +18 -0
- package/README.md +85 -4
- package/agent-management.ts +28 -7
- package/agent-manager-detail.ts +4 -1
- package/agent-manager-edit.ts +46 -6
- package/agent-manager.ts +28 -2
- package/agent-serializer.ts +6 -0
- package/agents/context-builder.md +24 -26
- package/agents/delegate.md +4 -1
- package/agents/planner.md +21 -15
- package/agents/researcher.md +23 -25
- package/agents/reviewer.md +22 -14
- package/agents/scout.md +24 -19
- package/agents/worker.md +20 -8
- package/agents.ts +121 -13
- package/async-execution.ts +18 -12
- package/async-job-tracker.ts +3 -3
- package/async-status.ts +3 -3
- package/chain-execution.ts +5 -5
- package/execution.ts +3 -3
- package/formatters.ts +14 -12
- package/index.ts +1 -1
- package/package.json +1 -1
- package/parallel-utils.ts +4 -15
- package/pi-args.ts +13 -6
- package/schemas.ts +1 -1
- package/settings.ts +2 -2
- package/slash-commands.ts +8 -8
- package/subagent-executor.ts +32 -19
- package/subagent-prompt-runtime.ts +67 -0
- package/subagent-runner.ts +3 -8
- package/utils.ts +6 -1
- package/worktree.ts +2 -1
package/agents/researcher.md
CHANGED
|
@@ -3,35 +3,33 @@ name: researcher
|
|
|
3
3
|
description: Autonomous web researcher — searches, evaluates, and synthesizes a focused research brief
|
|
4
4
|
tools: read, write, web_search, fetch_content, get_search_content
|
|
5
5
|
model: anthropic/claude-sonnet-4-6
|
|
6
|
+
systemPromptMode: replace
|
|
7
|
+
inheritProjectContext: true
|
|
8
|
+
inheritSkills: false
|
|
6
9
|
output: research.md
|
|
7
10
|
defaultProgress: true
|
|
8
11
|
---
|
|
9
12
|
|
|
10
|
-
You are a research
|
|
13
|
+
You are a research subagent.
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
1. Break the question into 2-4 searchable facets
|
|
14
|
-
2. Search with `web_search` using `queries` (parallel, varied angles) and `curate: false`
|
|
15
|
-
3. Read the answers. Identify what's well-covered, what has gaps, what's noise.
|
|
16
|
-
4. For the 2-3 most promising source URLs, use `fetch_content` to get full page content
|
|
17
|
-
5. Synthesize everything into a brief that directly answers the question
|
|
15
|
+
Given a question or topic, run focused web research and produce a concise, well-sourced brief that answers the question directly.
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
17
|
+
Working rules:
|
|
18
|
+
- Break the problem into 2-4 distinct research angles.
|
|
19
|
+
- Use `web_search` with `queries` so the search covers multiple angles instead of one generic query.
|
|
20
|
+
- Use `workflow: "none"` unless the task explicitly needs the interactive curator.
|
|
21
|
+
- Read the search results first. Then fetch full content only for the most promising source URLs.
|
|
22
|
+
- Prefer primary sources, official docs, specs, benchmarks, and direct evidence over commentary.
|
|
23
|
+
- Drop stale, redundant, or SEO-heavy sources.
|
|
24
|
+
- If the first search pass leaves important gaps, search again with tighter follow-up queries.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
- Drop: SEO filler, outdated info, beginner tutorials (unless that's the audience)
|
|
26
|
+
Search strategy:
|
|
27
|
+
- direct answer query
|
|
28
|
+
- authoritative source query
|
|
29
|
+
- practical experience or benchmark query
|
|
30
|
+
- recent developments query when the topic is time-sensitive
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Output format (research.md):
|
|
32
|
+
Output format (`research.md`):
|
|
35
33
|
|
|
36
34
|
# Research: [topic]
|
|
37
35
|
|
|
@@ -39,13 +37,13 @@ Output format (research.md):
|
|
|
39
37
|
2-3 sentence direct answer.
|
|
40
38
|
|
|
41
39
|
## Findings
|
|
42
|
-
Numbered findings with inline source citations
|
|
40
|
+
Numbered findings with inline source citations.
|
|
43
41
|
1. **Finding** — explanation. [Source](url)
|
|
44
42
|
2. **Finding** — explanation. [Source](url)
|
|
45
43
|
|
|
46
44
|
## Sources
|
|
47
|
-
- Kept: Source Title (url) — why
|
|
48
|
-
- Dropped: Source Title — why excluded
|
|
45
|
+
- Kept: Source Title (url) — why it matters
|
|
46
|
+
- Dropped: Source Title — why it was excluded
|
|
49
47
|
|
|
50
48
|
## Gaps
|
|
51
|
-
What
|
|
49
|
+
What could not be answered confidently. Suggested next steps.
|
package/agents/reviewer.md
CHANGED
|
@@ -1,30 +1,38 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: reviewer
|
|
3
3
|
description: Code review specialist that validates implementation and fixes issues
|
|
4
|
-
tools: read, grep, find, ls, bash
|
|
4
|
+
tools: read, grep, find, ls, bash, edit, write
|
|
5
5
|
model: openai-codex/gpt-5.3-codex
|
|
6
6
|
thinking: high
|
|
7
|
+
systemPromptMode: replace
|
|
8
|
+
inheritProjectContext: true
|
|
9
|
+
inheritSkills: false
|
|
7
10
|
defaultReads: plan.md, progress.md
|
|
8
11
|
defaultProgress: true
|
|
9
12
|
---
|
|
10
13
|
|
|
11
|
-
You are a
|
|
14
|
+
You are a review-and-fix subagent.
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
Review the implementation against the plan, inspect the actual code, and fix any real problems you find.
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
Working rules:
|
|
19
|
+
- Read the plan and current progress first when they are provided.
|
|
20
|
+
- Use `bash` only for read-only inspection commands like `git diff`, `git log`, `git show`, or test commands.
|
|
21
|
+
- Do not invent issues. Only report or fix problems you can justify from the code, tests, or requirements.
|
|
22
|
+
- Prefer small corrective edits over broad rewrites.
|
|
23
|
+
- If everything looks good, say so plainly and leave the code unchanged.
|
|
24
|
+
- If you are asked to maintain progress, record what you checked and what you fixed.
|
|
16
25
|
|
|
17
26
|
Review checklist:
|
|
18
|
-
1. Implementation matches plan requirements
|
|
19
|
-
2. Code
|
|
20
|
-
3.
|
|
21
|
-
4.
|
|
27
|
+
1. Implementation matches the plan and task requirements.
|
|
28
|
+
2. Code is correct and coherent.
|
|
29
|
+
3. Important edge cases are handled.
|
|
30
|
+
4. Tests and validation still make sense.
|
|
31
|
+
5. The final code is readable and minimal.
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Update progress.md with:
|
|
33
|
+
When updating `progress.md`, add a review section like this:
|
|
26
34
|
|
|
27
35
|
## Review
|
|
28
|
-
-
|
|
29
|
-
- Fixed:
|
|
30
|
-
- Note:
|
|
36
|
+
- Correct: what is already good
|
|
37
|
+
- Fixed: issue and resolution
|
|
38
|
+
- Note: observations or follow-up items
|
package/agents/scout.md
CHANGED
|
@@ -3,40 +3,45 @@ name: scout
|
|
|
3
3
|
description: Fast codebase recon that returns compressed context for handoff
|
|
4
4
|
tools: read, grep, find, ls, bash, write
|
|
5
5
|
model: anthropic/claude-haiku-4-5
|
|
6
|
+
systemPromptMode: replace
|
|
7
|
+
inheritProjectContext: true
|
|
8
|
+
inheritSkills: false
|
|
6
9
|
output: context.md
|
|
7
10
|
defaultProgress: true
|
|
8
11
|
---
|
|
9
12
|
|
|
10
|
-
You are a
|
|
13
|
+
You are a scouting subagent running inside pi.
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
When running solo, write to the provided output path and summarize what you found.
|
|
15
|
+
Use the provided tools directly. Move fast, but do not guess. Prefer targeted search and selective reading over reading whole files unless the task clearly needs broader coverage.
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
17
|
+
Focus on the minimum context another agent needs in order to act:
|
|
18
|
+
- relevant entry points
|
|
19
|
+
- key types, interfaces, and functions
|
|
20
|
+
- data flow and dependencies
|
|
21
|
+
- files that are likely to need changes
|
|
22
|
+
- constraints, risks, and open questions
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
Working rules:
|
|
25
|
+
- Use `grep`, `find`, `ls`, and `read` to map the area before diving deeper.
|
|
26
|
+
- Use `bash` only for non-interactive inspection commands.
|
|
27
|
+
- When you cite code, use exact file paths and line ranges.
|
|
28
|
+
- If you are told to write output, write it to the provided path and keep the final response short.
|
|
29
|
+
- When running solo, summarize what you found after writing the output.
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
Output format (`context.md`):
|
|
27
32
|
|
|
28
33
|
# Code Context
|
|
29
34
|
|
|
30
35
|
## Files Retrieved
|
|
31
|
-
List
|
|
32
|
-
1. `path/to/file.ts` (lines 10-50) -
|
|
33
|
-
2. `path/to/other.ts` (lines 100-150) -
|
|
36
|
+
List exact files and line ranges.
|
|
37
|
+
1. `path/to/file.ts` (lines 10-50) - why it matters
|
|
38
|
+
2. `path/to/other.ts` (lines 100-150) - why it matters
|
|
34
39
|
|
|
35
40
|
## Key Code
|
|
36
|
-
|
|
41
|
+
Include the critical types, interfaces, functions, and small code snippets that matter.
|
|
37
42
|
|
|
38
43
|
## Architecture
|
|
39
|
-
|
|
44
|
+
Explain how the pieces connect.
|
|
40
45
|
|
|
41
46
|
## Start Here
|
|
42
|
-
|
|
47
|
+
Name the first file another agent should open and why.
|
package/agents/worker.md
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: worker
|
|
3
|
-
description: General-purpose subagent with full capabilities
|
|
3
|
+
description: General-purpose subagent with full capabilities
|
|
4
4
|
model: claude-sonnet-4-6
|
|
5
|
+
systemPromptMode: replace
|
|
6
|
+
inheritProjectContext: true
|
|
7
|
+
inheritSkills: false
|
|
5
8
|
defaultReads: context.md, plan.md
|
|
6
9
|
defaultProgress: true
|
|
7
10
|
---
|
|
8
11
|
|
|
9
|
-
You are
|
|
12
|
+
You are an implementation subagent.
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
- Which files to read (context from previous steps)
|
|
13
|
-
- Where to maintain progress tracking
|
|
14
|
+
Use the provided tools directly to complete the task. Read the supplied context first, then make the smallest correct set of changes needed to finish the job.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
Working rules:
|
|
17
|
+
- Follow existing patterns in the codebase.
|
|
18
|
+
- Prefer simple changes over clever ones.
|
|
19
|
+
- Do not leave speculative scaffolding, placeholder code, or TODOs unless the task explicitly requires them.
|
|
20
|
+
- Run relevant tests or validation commands when you can.
|
|
21
|
+
- If you are asked to maintain progress, keep it accurate and up to date.
|
|
22
|
+
- When you finish, summarize what changed, what you verified, and anything still unresolved.
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
When running in a chain, expect instructions about:
|
|
25
|
+
- which files to read first
|
|
26
|
+
- where to maintain progress tracking
|
|
27
|
+
- where to write output if a file target is provided
|
|
28
|
+
|
|
29
|
+
Suggested `progress.md` structure when asked to maintain it:
|
|
18
30
|
|
|
19
31
|
# Progress
|
|
20
32
|
|
|
@@ -29,4 +41,4 @@ Progress.md format:
|
|
|
29
41
|
- `path/to/file.ts` - what changed
|
|
30
42
|
|
|
31
43
|
## Notes
|
|
32
|
-
|
|
44
|
+
Key decisions, blockers, or follow-up items.
|
package/agents.ts
CHANGED
|
@@ -14,11 +14,27 @@ import { parseFrontmatter } from "./frontmatter.ts";
|
|
|
14
14
|
export type AgentScope = "user" | "project" | "both";
|
|
15
15
|
|
|
16
16
|
export type AgentSource = "builtin" | "user" | "project";
|
|
17
|
+
export type SystemPromptMode = "append" | "replace";
|
|
18
|
+
|
|
19
|
+
export function defaultSystemPromptMode(name: string): SystemPromptMode {
|
|
20
|
+
return name === "delegate" ? "append" : "replace";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function defaultInheritProjectContext(name: string): boolean {
|
|
24
|
+
return name === "delegate";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function defaultInheritSkills(): boolean {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
17
30
|
|
|
18
31
|
export interface BuiltinAgentOverrideBase {
|
|
19
32
|
model?: string;
|
|
20
33
|
fallbackModels?: string[];
|
|
21
34
|
thinking?: string;
|
|
35
|
+
systemPromptMode: SystemPromptMode;
|
|
36
|
+
inheritProjectContext: boolean;
|
|
37
|
+
inheritSkills: boolean;
|
|
22
38
|
systemPrompt: string;
|
|
23
39
|
skills?: string[];
|
|
24
40
|
tools?: string[];
|
|
@@ -29,6 +45,9 @@ export interface BuiltinAgentOverrideConfig {
|
|
|
29
45
|
model?: string | false;
|
|
30
46
|
fallbackModels?: string[] | false;
|
|
31
47
|
thinking?: string | false;
|
|
48
|
+
systemPromptMode?: SystemPromptMode;
|
|
49
|
+
inheritProjectContext?: boolean;
|
|
50
|
+
inheritSkills?: boolean;
|
|
32
51
|
systemPrompt?: string;
|
|
33
52
|
skills?: string[] | false;
|
|
34
53
|
tools?: string[] | false;
|
|
@@ -48,6 +67,9 @@ export interface AgentConfig {
|
|
|
48
67
|
model?: string;
|
|
49
68
|
fallbackModels?: string[];
|
|
50
69
|
thinking?: string;
|
|
70
|
+
systemPromptMode: SystemPromptMode;
|
|
71
|
+
inheritProjectContext: boolean;
|
|
72
|
+
inheritSkills: boolean;
|
|
51
73
|
systemPrompt: string;
|
|
52
74
|
source: AgentSource;
|
|
53
75
|
filePath: string;
|
|
@@ -125,6 +147,9 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
|
|
|
125
147
|
model: agent.model,
|
|
126
148
|
fallbackModels: agent.fallbackModels ? [...agent.fallbackModels] : undefined,
|
|
127
149
|
thinking: agent.thinking,
|
|
150
|
+
systemPromptMode: agent.systemPromptMode,
|
|
151
|
+
inheritProjectContext: agent.inheritProjectContext,
|
|
152
|
+
inheritSkills: agent.inheritSkills,
|
|
128
153
|
systemPrompt: agent.systemPrompt,
|
|
129
154
|
skills: agent.skills ? [...agent.skills] : undefined,
|
|
130
155
|
tools: agent.tools ? [...agent.tools] : undefined,
|
|
@@ -139,6 +164,9 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
|
|
|
139
164
|
? { fallbackModels: override.fallbackModels === false ? false : [...override.fallbackModels] }
|
|
140
165
|
: {}),
|
|
141
166
|
...(override.thinking !== undefined ? { thinking: override.thinking } : {}),
|
|
167
|
+
...(override.systemPromptMode !== undefined ? { systemPromptMode: override.systemPromptMode } : {}),
|
|
168
|
+
...(override.inheritProjectContext !== undefined ? { inheritProjectContext: override.inheritProjectContext } : {}),
|
|
169
|
+
...(override.inheritSkills !== undefined ? { inheritSkills: override.inheritSkills } : {}),
|
|
142
170
|
...(override.systemPrompt !== undefined ? { systemPrompt: override.systemPrompt } : {}),
|
|
143
171
|
...(override.skills !== undefined ? { skills: override.skills === false ? false : [...override.skills] } : {}),
|
|
144
172
|
...(override.tools !== undefined ? { tools: override.tools === false ? false : [...override.tools] } : {}),
|
|
@@ -187,29 +215,85 @@ function writeSettingsFile(filePath: string, settings: Record<string, unknown>):
|
|
|
187
215
|
fs.writeFileSync(filePath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
188
216
|
}
|
|
189
217
|
|
|
190
|
-
function
|
|
218
|
+
function parseOverrideStringArrayOrFalse(
|
|
219
|
+
value: unknown,
|
|
220
|
+
meta: { filePath: string; name: string; field: string },
|
|
221
|
+
): string[] | false | undefined {
|
|
222
|
+
if (value === undefined) return undefined;
|
|
191
223
|
if (value === false) return false;
|
|
192
|
-
if (!Array.isArray(value))
|
|
193
|
-
|
|
224
|
+
if (!Array.isArray(value)) {
|
|
225
|
+
throw new Error(`Builtin override '${meta.name}' in '${meta.filePath}' has invalid '${meta.field}'; expected an array of strings or false.`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const items: string[] = [];
|
|
229
|
+
for (const item of value) {
|
|
230
|
+
if (typeof item !== "string") {
|
|
231
|
+
throw new Error(`Builtin override '${meta.name}' in '${meta.filePath}' has invalid '${meta.field}'; expected an array of strings or false.`);
|
|
232
|
+
}
|
|
233
|
+
const trimmed = item.trim();
|
|
234
|
+
if (trimmed) items.push(trimmed);
|
|
235
|
+
}
|
|
194
236
|
return items;
|
|
195
237
|
}
|
|
196
238
|
|
|
197
|
-
function parseBuiltinOverrideEntry(
|
|
198
|
-
|
|
239
|
+
function parseBuiltinOverrideEntry(
|
|
240
|
+
name: string,
|
|
241
|
+
value: unknown,
|
|
242
|
+
filePath: string,
|
|
243
|
+
): BuiltinAgentOverrideConfig | undefined {
|
|
244
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
245
|
+
throw new Error(`Builtin override '${name}' in '${filePath}' must be an object.`);
|
|
246
|
+
}
|
|
247
|
+
|
|
199
248
|
const input = value as Record<string, unknown>;
|
|
200
249
|
const override: BuiltinAgentOverrideConfig = {};
|
|
201
250
|
|
|
202
|
-
if (
|
|
203
|
-
|
|
204
|
-
|
|
251
|
+
if ("model" in input) {
|
|
252
|
+
if (typeof input.model === "string" || input.model === false) override.model = input.model;
|
|
253
|
+
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'model'; expected a string or false.`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if ("thinking" in input) {
|
|
257
|
+
if (typeof input.thinking === "string" || input.thinking === false) override.thinking = input.thinking;
|
|
258
|
+
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'thinking'; expected a string or false.`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if ("systemPromptMode" in input) {
|
|
262
|
+
if (input.systemPromptMode === "append" || input.systemPromptMode === "replace") {
|
|
263
|
+
override.systemPromptMode = input.systemPromptMode;
|
|
264
|
+
} else {
|
|
265
|
+
throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'systemPromptMode'; expected 'append' or 'replace'.`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if ("inheritProjectContext" in input) {
|
|
270
|
+
if (typeof input.inheritProjectContext === "boolean") {
|
|
271
|
+
override.inheritProjectContext = input.inheritProjectContext;
|
|
272
|
+
} else {
|
|
273
|
+
throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'inheritProjectContext'; expected a boolean.`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if ("inheritSkills" in input) {
|
|
278
|
+
if (typeof input.inheritSkills === "boolean") {
|
|
279
|
+
override.inheritSkills = input.inheritSkills;
|
|
280
|
+
} else {
|
|
281
|
+
throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'inheritSkills'; expected a boolean.`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if ("systemPrompt" in input) {
|
|
286
|
+
if (typeof input.systemPrompt === "string") override.systemPrompt = input.systemPrompt;
|
|
287
|
+
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'systemPrompt'; expected a string.`);
|
|
288
|
+
}
|
|
205
289
|
|
|
206
|
-
const fallbackModels =
|
|
290
|
+
const fallbackModels = parseOverrideStringArrayOrFalse(input.fallbackModels, { filePath, name, field: "fallbackModels" });
|
|
207
291
|
if (fallbackModels !== undefined) override.fallbackModels = fallbackModels;
|
|
208
292
|
|
|
209
|
-
const skills =
|
|
293
|
+
const skills = parseOverrideStringArrayOrFalse(input.skills, { filePath, name, field: "skills" });
|
|
210
294
|
if (skills !== undefined) override.skills = skills;
|
|
211
295
|
|
|
212
|
-
const tools =
|
|
296
|
+
const tools = parseOverrideStringArrayOrFalse(input.tools, { filePath, name, field: "tools" });
|
|
213
297
|
if (tools !== undefined) override.tools = tools;
|
|
214
298
|
|
|
215
299
|
return Object.keys(override).length > 0 ? override : undefined;
|
|
@@ -225,7 +309,7 @@ function readBuiltinOverrides(filePath: string | null): Record<string, BuiltinAg
|
|
|
225
309
|
|
|
226
310
|
const parsed: Record<string, BuiltinAgentOverrideConfig> = {};
|
|
227
311
|
for (const [name, value] of Object.entries(agentOverrides)) {
|
|
228
|
-
const override = parseBuiltinOverrideEntry(value);
|
|
312
|
+
const override = parseBuiltinOverrideEntry(name, value, filePath);
|
|
229
313
|
if (override) parsed[name] = override;
|
|
230
314
|
}
|
|
231
315
|
return parsed;
|
|
@@ -246,6 +330,9 @@ function applyBuiltinOverride(
|
|
|
246
330
|
next.fallbackModels = override.fallbackModels === false ? undefined : [...override.fallbackModels];
|
|
247
331
|
}
|
|
248
332
|
if (override.thinking !== undefined) next.thinking = override.thinking === false ? undefined : override.thinking;
|
|
333
|
+
if (override.systemPromptMode !== undefined) next.systemPromptMode = override.systemPromptMode;
|
|
334
|
+
if (override.inheritProjectContext !== undefined) next.inheritProjectContext = override.inheritProjectContext;
|
|
335
|
+
if (override.inheritSkills !== undefined) next.inheritSkills = override.inheritSkills;
|
|
249
336
|
if (override.systemPrompt !== undefined) next.systemPrompt = override.systemPrompt;
|
|
250
337
|
if (override.skills !== undefined) next.skills = override.skills === false ? undefined : [...override.skills];
|
|
251
338
|
if (override.tools !== undefined) {
|
|
@@ -281,13 +368,16 @@ function applyBuiltinOverrides(
|
|
|
281
368
|
|
|
282
369
|
export function buildBuiltinOverrideConfig(
|
|
283
370
|
base: BuiltinAgentOverrideBase,
|
|
284
|
-
draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools">,
|
|
371
|
+
draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools">,
|
|
285
372
|
): BuiltinAgentOverrideConfig | undefined {
|
|
286
373
|
const override: BuiltinAgentOverrideConfig = {};
|
|
287
374
|
|
|
288
375
|
if (draft.model !== base.model) override.model = draft.model ?? false;
|
|
289
376
|
if (!arraysEqual(draft.fallbackModels, base.fallbackModels)) override.fallbackModels = draft.fallbackModels ? [...draft.fallbackModels] : false;
|
|
290
377
|
if (draft.thinking !== base.thinking) override.thinking = draft.thinking ?? false;
|
|
378
|
+
if (draft.systemPromptMode !== base.systemPromptMode) override.systemPromptMode = draft.systemPromptMode;
|
|
379
|
+
if (draft.inheritProjectContext !== base.inheritProjectContext) override.inheritProjectContext = draft.inheritProjectContext;
|
|
380
|
+
if (draft.inheritSkills !== base.inheritSkills) override.inheritSkills = draft.inheritSkills;
|
|
291
381
|
if (draft.systemPrompt !== base.systemPrompt) override.systemPrompt = draft.systemPrompt;
|
|
292
382
|
if (!arraysEqual(draft.skills, base.skills)) override.skills = draft.skills ? [...draft.skills] : false;
|
|
293
383
|
|
|
@@ -410,6 +500,21 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
|
|
|
410
500
|
?.split(",")
|
|
411
501
|
.map((model) => model.trim())
|
|
412
502
|
.filter(Boolean);
|
|
503
|
+
const systemPromptMode = frontmatter.systemPromptMode === "replace"
|
|
504
|
+
? "replace"
|
|
505
|
+
: frontmatter.systemPromptMode === "append"
|
|
506
|
+
? "append"
|
|
507
|
+
: defaultSystemPromptMode(frontmatter.name);
|
|
508
|
+
const inheritProjectContext = frontmatter.inheritProjectContext === "true"
|
|
509
|
+
? true
|
|
510
|
+
: frontmatter.inheritProjectContext === "false"
|
|
511
|
+
? false
|
|
512
|
+
: defaultInheritProjectContext(frontmatter.name);
|
|
513
|
+
const inheritSkills = frontmatter.inheritSkills === "true"
|
|
514
|
+
? true
|
|
515
|
+
: frontmatter.inheritSkills === "false"
|
|
516
|
+
? false
|
|
517
|
+
: defaultInheritSkills();
|
|
413
518
|
|
|
414
519
|
let extensions: string[] | undefined;
|
|
415
520
|
if (frontmatter.extensions !== undefined) {
|
|
@@ -434,6 +539,9 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
|
|
|
434
539
|
model: frontmatter.model,
|
|
435
540
|
fallbackModels: fallbackModels && fallbackModels.length > 0 ? fallbackModels : undefined,
|
|
436
541
|
thinking: frontmatter.thinking,
|
|
542
|
+
systemPromptMode,
|
|
543
|
+
inheritProjectContext,
|
|
544
|
+
inheritSkills,
|
|
437
545
|
systemPrompt: body,
|
|
438
546
|
source,
|
|
439
547
|
filePath,
|
package/async-execution.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { isParallelStep, resolveStepBehavior, type ChainStep, type SequentialSte
|
|
|
16
16
|
import type { RunnerStep } from "./parallel-utils.ts";
|
|
17
17
|
import { resolvePiPackageRoot } from "./pi-spawn.ts";
|
|
18
18
|
import { buildSkillInjection, normalizeSkillInput, resolveSkillsWithFallback } from "./skills.ts";
|
|
19
|
+
import { resolveChildCwd } from "./utils.ts";
|
|
19
20
|
import { buildModelCandidates, resolveModelCandidate, type AvailableModelInfo } from "./model-fallback.ts";
|
|
20
21
|
import {
|
|
21
22
|
type ArtifactConfig,
|
|
@@ -163,6 +164,7 @@ export function executeAsyncChain(
|
|
|
163
164
|
} = params;
|
|
164
165
|
const chainSkills = params.chainSkills ?? [];
|
|
165
166
|
const availableModels = params.availableModels;
|
|
167
|
+
const runnerCwd = resolveChildCwd(ctx.cwd, cwd);
|
|
166
168
|
|
|
167
169
|
for (const s of chain) {
|
|
168
170
|
const stepAgents = isParallelStep(s)
|
|
@@ -193,27 +195,27 @@ export function executeAsyncChain(
|
|
|
193
195
|
|
|
194
196
|
const buildSeqStep = (s: SequentialStep, sessionFile?: string) => {
|
|
195
197
|
const a = agents.find((x) => x.name === s.agent)!;
|
|
198
|
+
const stepCwd = resolveChildCwd(runnerCwd, s.cwd);
|
|
196
199
|
const stepSkillInput = normalizeSkillInput(s.skill);
|
|
197
200
|
const stepOverrides: StepOverrides = { skills: stepSkillInput };
|
|
198
201
|
const behavior = resolveStepBehavior(a, stepOverrides, chainSkills);
|
|
199
202
|
const skillNames = behavior.skills === false ? [] : behavior.skills;
|
|
200
|
-
const
|
|
201
|
-
const { resolved: resolvedSkills } = resolveSkillsWithFallback(skillNames, skillCwd, ctx.cwd);
|
|
203
|
+
const { resolved: resolvedSkills } = resolveSkillsWithFallback(skillNames, stepCwd, ctx.cwd);
|
|
202
204
|
|
|
203
|
-
let systemPrompt = a.systemPrompt?.trim()
|
|
205
|
+
let systemPrompt = a.systemPrompt?.trim() ?? "";
|
|
204
206
|
if (resolvedSkills.length > 0) {
|
|
205
207
|
const injection = buildSkillInjection(resolvedSkills);
|
|
206
208
|
systemPrompt = systemPrompt ? `${systemPrompt}\n\n${injection}` : injection;
|
|
207
209
|
}
|
|
208
210
|
|
|
209
|
-
const outputPath = resolveSingleOutputPath(s.output, ctx.cwd,
|
|
211
|
+
const outputPath = resolveSingleOutputPath(s.output, ctx.cwd, stepCwd);
|
|
210
212
|
const task = injectSingleOutputInstruction(s.task ?? "{previous}", outputPath);
|
|
211
213
|
|
|
212
214
|
const primaryModel = resolveModelCandidate(s.model ?? a.model, availableModels, ctx.currentModelProvider);
|
|
213
215
|
return {
|
|
214
216
|
agent: s.agent,
|
|
215
217
|
task,
|
|
216
|
-
cwd:
|
|
218
|
+
cwd: stepCwd,
|
|
217
219
|
model: applyThinkingSuffix(primaryModel, a.thinking),
|
|
218
220
|
modelCandidates: buildModelCandidates(s.model ?? a.model, a.fallbackModels, availableModels, ctx.currentModelProvider).map((candidate) =>
|
|
219
221
|
applyThinkingSuffix(candidate, a.thinking),
|
|
@@ -222,6 +224,9 @@ export function executeAsyncChain(
|
|
|
222
224
|
extensions: a.extensions,
|
|
223
225
|
mcpDirectTools: a.mcpDirectTools,
|
|
224
226
|
systemPrompt,
|
|
227
|
+
systemPromptMode: a.systemPromptMode,
|
|
228
|
+
inheritProjectContext: a.inheritProjectContext,
|
|
229
|
+
inheritSkills: a.inheritSkills,
|
|
225
230
|
skills: resolvedSkills.map((r) => r.name),
|
|
226
231
|
outputPath,
|
|
227
232
|
sessionFile,
|
|
@@ -255,7 +260,6 @@ export function executeAsyncChain(
|
|
|
255
260
|
return buildSeqStep(s as SequentialStep, nextSessionFile());
|
|
256
261
|
});
|
|
257
262
|
|
|
258
|
-
const runnerCwd = cwd ?? ctx.cwd;
|
|
259
263
|
let pid: number | undefined;
|
|
260
264
|
try {
|
|
261
265
|
pid = spawnRunner(
|
|
@@ -340,11 +344,11 @@ export function executeAsyncSingle(
|
|
|
340
344
|
worktreeSetupHook,
|
|
341
345
|
worktreeSetupHookTimeoutMs,
|
|
342
346
|
} = params;
|
|
347
|
+
const runnerCwd = resolveChildCwd(ctx.cwd, cwd);
|
|
343
348
|
const skillNames = params.skills ?? agentConfig.skills ?? [];
|
|
344
349
|
const availableModels = params.availableModels;
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
let systemPrompt = agentConfig.systemPrompt?.trim() || null;
|
|
350
|
+
const { resolved: resolvedSkills } = resolveSkillsWithFallback(skillNames, runnerCwd, ctx.cwd);
|
|
351
|
+
let systemPrompt = agentConfig.systemPrompt?.trim() ?? "";
|
|
348
352
|
if (resolvedSkills.length > 0) {
|
|
349
353
|
const injection = buildSkillInjection(resolvedSkills);
|
|
350
354
|
systemPrompt = systemPrompt ? `${systemPrompt}\n\n${injection}` : injection;
|
|
@@ -362,8 +366,7 @@ export function executeAsyncSingle(
|
|
|
362
366
|
};
|
|
363
367
|
}
|
|
364
368
|
|
|
365
|
-
const
|
|
366
|
-
const outputPath = resolveSingleOutputPath(params.output, ctx.cwd, cwd);
|
|
369
|
+
const outputPath = resolveSingleOutputPath(params.output, ctx.cwd, runnerCwd);
|
|
367
370
|
const taskWithOutputInstruction = injectSingleOutputInstruction(task, outputPath);
|
|
368
371
|
let pid: number | undefined;
|
|
369
372
|
try {
|
|
@@ -374,7 +377,7 @@ export function executeAsyncSingle(
|
|
|
374
377
|
{
|
|
375
378
|
agent,
|
|
376
379
|
task: taskWithOutputInstruction,
|
|
377
|
-
cwd,
|
|
380
|
+
cwd: runnerCwd,
|
|
378
381
|
model: applyThinkingSuffix(resolveModelCandidate(params.modelOverride ?? agentConfig.model, availableModels, ctx.currentModelProvider), agentConfig.thinking),
|
|
379
382
|
modelCandidates: buildModelCandidates(params.modelOverride ?? agentConfig.model, agentConfig.fallbackModels, availableModels, ctx.currentModelProvider).map((candidate) =>
|
|
380
383
|
applyThinkingSuffix(candidate, agentConfig.thinking),
|
|
@@ -383,6 +386,9 @@ export function executeAsyncSingle(
|
|
|
383
386
|
extensions: agentConfig.extensions,
|
|
384
387
|
mcpDirectTools: agentConfig.mcpDirectTools,
|
|
385
388
|
systemPrompt,
|
|
389
|
+
systemPromptMode: agentConfig.systemPromptMode,
|
|
390
|
+
inheritProjectContext: agentConfig.inheritProjectContext,
|
|
391
|
+
inheritSkills: agentConfig.inheritSkills,
|
|
386
392
|
skills: resolvedSkills.map((r) => r.name),
|
|
387
393
|
outputPath,
|
|
388
394
|
sessionFile,
|
package/async-job-tracker.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { renderWidget } from "./render.
|
|
3
|
+
import { renderWidget } from "./render.ts";
|
|
4
4
|
import {
|
|
5
5
|
type SubagentState,
|
|
6
6
|
POLL_INTERVAL_MS,
|
|
7
|
-
} from "./types.
|
|
8
|
-
import { readStatus } from "./utils.
|
|
7
|
+
} from "./types.ts";
|
|
8
|
+
import { readStatus } from "./utils.ts";
|
|
9
9
|
|
|
10
10
|
export function createAsyncJobTracker(state: SubagentState, asyncDirRoot: string): {
|
|
11
11
|
ensurePoller: () => void;
|
package/async-status.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { formatDuration, formatTokens, shortenPath } from "./formatters.
|
|
4
|
-
import { type AsyncStatus, type TokenUsage } from "./types.
|
|
5
|
-
import { readStatus } from "./utils.
|
|
3
|
+
import { formatDuration, formatTokens, shortenPath } from "./formatters.ts";
|
|
4
|
+
import { type AsyncStatus, type TokenUsage } from "./types.ts";
|
|
5
|
+
import { readStatus } from "./utils.ts";
|
|
6
6
|
|
|
7
7
|
export interface AsyncRunStepSummary {
|
|
8
8
|
index: number;
|
package/chain-execution.ts
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
import { discoverAvailableSkills, normalizeSkillInput } from "./skills.ts";
|
|
29
29
|
import { runSync } from "./execution.ts";
|
|
30
30
|
import { buildChainSummary } from "./formatters.ts";
|
|
31
|
-
import { compactForegroundDetails, getSingleResultOutput, mapConcurrent } from "./utils.ts";
|
|
31
|
+
import { compactForegroundDetails, getSingleResultOutput, mapConcurrent, resolveChildCwd } from "./utils.ts";
|
|
32
32
|
import { recordRun } from "./run-history.ts";
|
|
33
33
|
import {
|
|
34
34
|
cleanupWorktrees,
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
formatWorktreeDiffSummary,
|
|
39
39
|
formatWorktreeTaskCwdConflict,
|
|
40
40
|
type WorktreeSetup,
|
|
41
|
-
} from "./worktree.
|
|
41
|
+
} from "./worktree.ts";
|
|
42
42
|
import {
|
|
43
43
|
type AgentProgress,
|
|
44
44
|
type ArtifactConfig,
|
|
@@ -181,7 +181,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
181
181
|
|
|
182
182
|
const taskCwd = input.worktreeSetup
|
|
183
183
|
? input.worktreeSetup.worktrees[taskIndex]!.agentCwd
|
|
184
|
-
: (
|
|
184
|
+
: resolveChildCwd(input.cwd ?? input.ctx.cwd, task.cwd);
|
|
185
185
|
|
|
186
186
|
const outputPath = typeof behavior.output === "string"
|
|
187
187
|
? (path.isAbsolute(behavior.output) ? behavior.output : path.join(input.chainDir, behavior.output))
|
|
@@ -412,7 +412,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
412
412
|
|
|
413
413
|
if (isParallelStep(step)) {
|
|
414
414
|
const parallelTemplates = stepTemplates as string[];
|
|
415
|
-
const parallelCwd =
|
|
415
|
+
const parallelCwd = resolveChildCwd(cwd ?? ctx.cwd, step.cwd);
|
|
416
416
|
let worktreeSetup: WorktreeSetup | undefined;
|
|
417
417
|
if (step.worktree) {
|
|
418
418
|
const worktreeTaskCwdConflict = findWorktreeTaskCwdConflict(step.parallel, parallelCwd);
|
|
@@ -605,7 +605,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
605
605
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(params.maxSubagentDepth, agentConfig.maxSubagentDepth);
|
|
606
606
|
|
|
607
607
|
const r = await runSync(ctx.cwd, agents, seqStep.agent, stepTask, {
|
|
608
|
-
cwd:
|
|
608
|
+
cwd: resolveChildCwd(cwd ?? ctx.cwd, seqStep.cwd),
|
|
609
609
|
signal,
|
|
610
610
|
runId,
|
|
611
611
|
index: globalTaskIndex,
|