pi-subagents 0.13.4 → 0.14.1
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 +23 -4
- package/README.md +35 -14
- package/agent-management.ts +15 -6
- package/agent-manager-detail.ts +13 -3
- package/agent-manager-edit.ts +75 -23
- package/agent-manager-list.ts +12 -5
- package/agent-manager.ts +199 -11
- package/agents.ts +315 -20
- package/artifacts.ts +11 -5
- package/async-execution.ts +92 -73
- package/chain-clarify.ts +49 -160
- package/chain-execution.ts +38 -76
- package/execution.ts +53 -48
- package/index.ts +1 -1
- package/install.mjs +3 -3
- package/model-fallback.ts +8 -2
- package/package.json +1 -1
- package/parallel-utils.ts +5 -5
- package/prompt-template-bridge.ts +19 -8
- package/render.ts +23 -50
- package/schemas.ts +1 -1
- package/settings.ts +6 -4
- package/single-output.ts +2 -2
- package/skills.ts +165 -75
- package/subagent-executor.ts +52 -18
- package/subagent-runner.ts +171 -54
- package/types.ts +65 -14
- package/utils.ts +52 -21
package/async-execution.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { injectSingleOutputInstruction, resolveSingleOutputPath } from "./single
|
|
|
15
15
|
import { isParallelStep, resolveStepBehavior, type ChainStep, type SequentialStep, type StepOverrides } from "./settings.ts";
|
|
16
16
|
import type { RunnerStep } from "./parallel-utils.ts";
|
|
17
17
|
import { resolvePiPackageRoot } from "./pi-spawn.ts";
|
|
18
|
-
import { buildSkillInjection, normalizeSkillInput,
|
|
18
|
+
import { buildSkillInjection, normalizeSkillInput, resolveSkillsWithFallback } from "./skills.ts";
|
|
19
19
|
import { buildModelCandidates, resolveModelCandidate, type AvailableModelInfo } from "./model-fallback.ts";
|
|
20
20
|
import {
|
|
21
21
|
type ArtifactConfig,
|
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
type MaxOutputConfig,
|
|
24
24
|
ASYNC_DIR,
|
|
25
25
|
RESULTS_DIR,
|
|
26
|
+
TEMP_ROOT_DIR,
|
|
27
|
+
getAsyncConfigPath,
|
|
26
28
|
resolveChildMaxSubagentDepth,
|
|
27
29
|
} from "./types.ts";
|
|
28
30
|
|
|
@@ -53,6 +55,7 @@ export interface AsyncExecutionContext {
|
|
|
53
55
|
pi: ExtensionAPI;
|
|
54
56
|
cwd: string;
|
|
55
57
|
currentSessionId: string;
|
|
58
|
+
currentModelProvider?: string;
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
export interface AsyncChainParams {
|
|
@@ -113,7 +116,8 @@ export function isAsyncAvailable(): boolean {
|
|
|
113
116
|
function spawnRunner(cfg: object, suffix: string, cwd: string): number | undefined {
|
|
114
117
|
if (!jitiCliPath) return undefined;
|
|
115
118
|
|
|
116
|
-
|
|
119
|
+
fs.mkdirSync(TEMP_ROOT_DIR, { recursive: true });
|
|
120
|
+
const cfgPath = getAsyncConfigPath(suffix);
|
|
117
121
|
fs.writeFileSync(cfgPath, JSON.stringify(cfg));
|
|
118
122
|
const runner = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-runner.ts");
|
|
119
123
|
|
|
@@ -127,6 +131,14 @@ function spawnRunner(cfg: object, suffix: string, cwd: string): number | undefin
|
|
|
127
131
|
return proc.pid;
|
|
128
132
|
}
|
|
129
133
|
|
|
134
|
+
function formatAsyncStartError(mode: "single" | "chain", message: string): AsyncExecutionResult {
|
|
135
|
+
return {
|
|
136
|
+
content: [{ type: "text", text: message }],
|
|
137
|
+
isError: true,
|
|
138
|
+
details: { mode, results: [] },
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
130
142
|
/**
|
|
131
143
|
* Execute a chain asynchronously
|
|
132
144
|
*/
|
|
@@ -152,7 +164,6 @@ export function executeAsyncChain(
|
|
|
152
164
|
const chainSkills = params.chainSkills ?? [];
|
|
153
165
|
const availableModels = params.availableModels;
|
|
154
166
|
|
|
155
|
-
// Validate all agents exist before building steps
|
|
156
167
|
for (const s of chain) {
|
|
157
168
|
const stepAgents = isParallelStep(s)
|
|
158
169
|
? s.parallel.map((t) => t.agent)
|
|
@@ -180,14 +191,14 @@ export function executeAsyncChain(
|
|
|
180
191
|
};
|
|
181
192
|
}
|
|
182
193
|
|
|
183
|
-
/** Build a resolved runner step from a SequentialStep */
|
|
184
194
|
const buildSeqStep = (s: SequentialStep, sessionFile?: string) => {
|
|
185
195
|
const a = agents.find((x) => x.name === s.agent)!;
|
|
186
196
|
const stepSkillInput = normalizeSkillInput(s.skill);
|
|
187
197
|
const stepOverrides: StepOverrides = { skills: stepSkillInput };
|
|
188
198
|
const behavior = resolveStepBehavior(a, stepOverrides, chainSkills);
|
|
189
199
|
const skillNames = behavior.skills === false ? [] : behavior.skills;
|
|
190
|
-
const
|
|
200
|
+
const skillCwd = s.cwd ?? cwd ?? ctx.cwd;
|
|
201
|
+
const { resolved: resolvedSkills } = resolveSkillsWithFallback(skillNames, skillCwd, ctx.cwd);
|
|
191
202
|
|
|
192
203
|
let systemPrompt = a.systemPrompt?.trim() || null;
|
|
193
204
|
if (resolvedSkills.length > 0) {
|
|
@@ -195,18 +206,16 @@ export function executeAsyncChain(
|
|
|
195
206
|
systemPrompt = systemPrompt ? `${systemPrompt}\n\n${injection}` : injection;
|
|
196
207
|
}
|
|
197
208
|
|
|
198
|
-
// Resolve output path and inject instruction into task
|
|
199
|
-
// Use step's cwd if specified, otherwise fall back to chain-level cwd
|
|
200
209
|
const outputPath = resolveSingleOutputPath(s.output, ctx.cwd, s.cwd ?? cwd);
|
|
201
210
|
const task = injectSingleOutputInstruction(s.task ?? "{previous}", outputPath);
|
|
202
211
|
|
|
203
|
-
const primaryModel = resolveModelCandidate(s.model ?? a.model, availableModels);
|
|
212
|
+
const primaryModel = resolveModelCandidate(s.model ?? a.model, availableModels, ctx.currentModelProvider);
|
|
204
213
|
return {
|
|
205
214
|
agent: s.agent,
|
|
206
215
|
task,
|
|
207
216
|
cwd: s.cwd,
|
|
208
217
|
model: applyThinkingSuffix(primaryModel, a.thinking),
|
|
209
|
-
modelCandidates: buildModelCandidates(s.model ?? a.model, a.fallbackModels, availableModels).map((candidate) =>
|
|
218
|
+
modelCandidates: buildModelCandidates(s.model ?? a.model, a.fallbackModels, availableModels, ctx.currentModelProvider).map((candidate) =>
|
|
210
219
|
applyThinkingSuffix(candidate, a.thinking),
|
|
211
220
|
),
|
|
212
221
|
tools: a.tools,
|
|
@@ -227,8 +236,6 @@ export function executeAsyncChain(
|
|
|
227
236
|
return sessionFile;
|
|
228
237
|
};
|
|
229
238
|
|
|
230
|
-
// Build runner steps — sequential steps become flat objects,
|
|
231
|
-
// parallel steps become { parallel: [...], concurrency?, failFast? }
|
|
232
239
|
const steps: RunnerStep[] = chain.map((s) => {
|
|
233
240
|
if (isParallelStep(s)) {
|
|
234
241
|
return {
|
|
@@ -249,28 +256,34 @@ export function executeAsyncChain(
|
|
|
249
256
|
});
|
|
250
257
|
|
|
251
258
|
const runnerCwd = cwd ?? ctx.cwd;
|
|
252
|
-
|
|
253
|
-
|
|
259
|
+
let pid: number | undefined;
|
|
260
|
+
try {
|
|
261
|
+
pid = spawnRunner(
|
|
262
|
+
{
|
|
263
|
+
id,
|
|
264
|
+
steps,
|
|
265
|
+
resultPath: path.join(RESULTS_DIR, `${id}.json`),
|
|
266
|
+
cwd: runnerCwd,
|
|
267
|
+
placeholder: "{previous}",
|
|
268
|
+
maxOutput,
|
|
269
|
+
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
270
|
+
artifactConfig,
|
|
271
|
+
share: shareEnabled,
|
|
272
|
+
sessionDir: sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined,
|
|
273
|
+
asyncDir,
|
|
274
|
+
sessionId: ctx.currentSessionId,
|
|
275
|
+
piPackageRoot,
|
|
276
|
+
piArgv1: process.argv[1],
|
|
277
|
+
worktreeSetupHook,
|
|
278
|
+
worktreeSetupHookTimeoutMs,
|
|
279
|
+
},
|
|
254
280
|
id,
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
artifactConfig,
|
|
262
|
-
share: shareEnabled,
|
|
263
|
-
sessionDir: sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined,
|
|
264
|
-
asyncDir,
|
|
265
|
-
sessionId: ctx.currentSessionId,
|
|
266
|
-
piPackageRoot,
|
|
267
|
-
piArgv1: process.argv[1],
|
|
268
|
-
worktreeSetupHook,
|
|
269
|
-
worktreeSetupHookTimeoutMs,
|
|
270
|
-
},
|
|
271
|
-
id,
|
|
272
|
-
runnerCwd,
|
|
273
|
-
);
|
|
281
|
+
runnerCwd,
|
|
282
|
+
);
|
|
283
|
+
} catch (error) {
|
|
284
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
285
|
+
return formatAsyncStartError("chain", `Failed to start async chain '${id}': ${message}`);
|
|
286
|
+
}
|
|
274
287
|
|
|
275
288
|
if (pid) {
|
|
276
289
|
const firstStep = chain[0];
|
|
@@ -292,7 +305,6 @@ export function executeAsyncChain(
|
|
|
292
305
|
});
|
|
293
306
|
}
|
|
294
307
|
|
|
295
|
-
// Build chain description with parallel groups shown as [agent1+agent2]
|
|
296
308
|
const chainDesc = chain
|
|
297
309
|
.map((s) =>
|
|
298
310
|
isParallelStep(s) ? `[${s.parallel.map((t) => t.agent).join("+")}]` : (s as SequentialStep).agent,
|
|
@@ -330,7 +342,8 @@ export function executeAsyncSingle(
|
|
|
330
342
|
} = params;
|
|
331
343
|
const skillNames = params.skills ?? agentConfig.skills ?? [];
|
|
332
344
|
const availableModels = params.availableModels;
|
|
333
|
-
const
|
|
345
|
+
const skillCwd = cwd ?? ctx.cwd;
|
|
346
|
+
const { resolved: resolvedSkills } = resolveSkillsWithFallback(skillNames, skillCwd, ctx.cwd);
|
|
334
347
|
let systemPrompt = agentConfig.systemPrompt?.trim() || null;
|
|
335
348
|
if (resolvedSkills.length > 0) {
|
|
336
349
|
const injection = buildSkillInjection(resolvedSkills);
|
|
@@ -352,46 +365,52 @@ export function executeAsyncSingle(
|
|
|
352
365
|
const runnerCwd = cwd ?? ctx.cwd;
|
|
353
366
|
const outputPath = resolveSingleOutputPath(params.output, ctx.cwd, cwd);
|
|
354
367
|
const taskWithOutputInstruction = injectSingleOutputInstruction(task, outputPath);
|
|
355
|
-
|
|
356
|
-
|
|
368
|
+
let pid: number | undefined;
|
|
369
|
+
try {
|
|
370
|
+
pid = spawnRunner(
|
|
371
|
+
{
|
|
372
|
+
id,
|
|
373
|
+
steps: [
|
|
374
|
+
{
|
|
375
|
+
agent,
|
|
376
|
+
task: taskWithOutputInstruction,
|
|
377
|
+
cwd,
|
|
378
|
+
model: applyThinkingSuffix(resolveModelCandidate(params.modelOverride ?? agentConfig.model, availableModels, ctx.currentModelProvider), agentConfig.thinking),
|
|
379
|
+
modelCandidates: buildModelCandidates(params.modelOverride ?? agentConfig.model, agentConfig.fallbackModels, availableModels, ctx.currentModelProvider).map((candidate) =>
|
|
380
|
+
applyThinkingSuffix(candidate, agentConfig.thinking),
|
|
381
|
+
),
|
|
382
|
+
tools: agentConfig.tools,
|
|
383
|
+
extensions: agentConfig.extensions,
|
|
384
|
+
mcpDirectTools: agentConfig.mcpDirectTools,
|
|
385
|
+
systemPrompt,
|
|
386
|
+
skills: resolvedSkills.map((r) => r.name),
|
|
387
|
+
outputPath,
|
|
388
|
+
sessionFile,
|
|
389
|
+
maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, agentConfig.maxSubagentDepth),
|
|
390
|
+
},
|
|
391
|
+
],
|
|
392
|
+
resultPath: path.join(RESULTS_DIR, `${id}.json`),
|
|
393
|
+
cwd: runnerCwd,
|
|
394
|
+
placeholder: "{previous}",
|
|
395
|
+
maxOutput,
|
|
396
|
+
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
397
|
+
artifactConfig,
|
|
398
|
+
share: shareEnabled,
|
|
399
|
+
sessionDir: sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined,
|
|
400
|
+
asyncDir,
|
|
401
|
+
sessionId: ctx.currentSessionId,
|
|
402
|
+
piPackageRoot,
|
|
403
|
+
piArgv1: process.argv[1],
|
|
404
|
+
worktreeSetupHook,
|
|
405
|
+
worktreeSetupHookTimeoutMs,
|
|
406
|
+
},
|
|
357
407
|
id,
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
modelCandidates: buildModelCandidates(params.modelOverride ?? agentConfig.model, agentConfig.fallbackModels, availableModels).map((candidate) =>
|
|
365
|
-
applyThinkingSuffix(candidate, agentConfig.thinking),
|
|
366
|
-
),
|
|
367
|
-
tools: agentConfig.tools,
|
|
368
|
-
extensions: agentConfig.extensions,
|
|
369
|
-
mcpDirectTools: agentConfig.mcpDirectTools,
|
|
370
|
-
systemPrompt,
|
|
371
|
-
skills: resolvedSkills.map((r) => r.name),
|
|
372
|
-
outputPath,
|
|
373
|
-
sessionFile,
|
|
374
|
-
maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, agentConfig.maxSubagentDepth),
|
|
375
|
-
},
|
|
376
|
-
],
|
|
377
|
-
resultPath: path.join(RESULTS_DIR, `${id}.json`),
|
|
378
|
-
cwd: runnerCwd,
|
|
379
|
-
placeholder: "{previous}",
|
|
380
|
-
maxOutput,
|
|
381
|
-
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
382
|
-
artifactConfig,
|
|
383
|
-
share: shareEnabled,
|
|
384
|
-
sessionDir: sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined,
|
|
385
|
-
asyncDir,
|
|
386
|
-
sessionId: ctx.currentSessionId,
|
|
387
|
-
piPackageRoot,
|
|
388
|
-
piArgv1: process.argv[1],
|
|
389
|
-
worktreeSetupHook,
|
|
390
|
-
worktreeSetupHookTimeoutMs,
|
|
391
|
-
},
|
|
392
|
-
id,
|
|
393
|
-
runnerCwd,
|
|
394
|
-
);
|
|
408
|
+
runnerCwd,
|
|
409
|
+
);
|
|
410
|
+
} catch (error) {
|
|
411
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
412
|
+
return formatAsyncStartError("single", `Failed to start async run '${id}': ${message}`);
|
|
413
|
+
}
|
|
395
414
|
|
|
396
415
|
if (pid) {
|
|
397
416
|
ctx.pi.events.emit("subagent:started", {
|