pi-subagents 0.13.3 → 0.14.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 +21 -0
- package/README.md +35 -12
- package/agent-management.ts +15 -6
- package/agent-manager-detail.ts +12 -2
- package/agent-manager-edit.ts +75 -23
- package/agent-manager-list.ts +9 -2
- package/agent-manager.ts +199 -11
- package/agents.ts +315 -20
- package/artifacts.ts +11 -5
- package/async-execution.ts +92 -71
- package/chain-clarify.ts +45 -156
- package/chain-execution.ts +23 -63
- package/execution.ts +54 -49
- package/index.ts +1 -1
- package/intercom-bridge.ts +8 -0
- package/model-fallback.ts +8 -2
- package/package.json +1 -1
- package/schemas.ts +1 -1
- package/settings.ts +6 -4
- package/skills.ts +259 -77
- package/subagent-executor.ts +45 -15
- package/subagent-runner.ts +176 -51
- package/types.ts +64 -13
- package/utils.ts +5 -10
- package/worktree.ts +27 -9
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,27 +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
|
-
worktreeSetupHook,
|
|
268
|
-
worktreeSetupHookTimeoutMs,
|
|
269
|
-
},
|
|
270
|
-
id,
|
|
271
|
-
runnerCwd,
|
|
272
|
-
);
|
|
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
|
+
}
|
|
273
287
|
|
|
274
288
|
if (pid) {
|
|
275
289
|
const firstStep = chain[0];
|
|
@@ -291,7 +305,6 @@ export function executeAsyncChain(
|
|
|
291
305
|
});
|
|
292
306
|
}
|
|
293
307
|
|
|
294
|
-
// Build chain description with parallel groups shown as [agent1+agent2]
|
|
295
308
|
const chainDesc = chain
|
|
296
309
|
.map((s) =>
|
|
297
310
|
isParallelStep(s) ? `[${s.parallel.map((t) => t.agent).join("+")}]` : (s as SequentialStep).agent,
|
|
@@ -329,7 +342,8 @@ export function executeAsyncSingle(
|
|
|
329
342
|
} = params;
|
|
330
343
|
const skillNames = params.skills ?? agentConfig.skills ?? [];
|
|
331
344
|
const availableModels = params.availableModels;
|
|
332
|
-
const
|
|
345
|
+
const skillCwd = cwd ?? ctx.cwd;
|
|
346
|
+
const { resolved: resolvedSkills } = resolveSkillsWithFallback(skillNames, skillCwd, ctx.cwd);
|
|
333
347
|
let systemPrompt = agentConfig.systemPrompt?.trim() || null;
|
|
334
348
|
if (resolvedSkills.length > 0) {
|
|
335
349
|
const injection = buildSkillInjection(resolvedSkills);
|
|
@@ -351,45 +365,52 @@ export function executeAsyncSingle(
|
|
|
351
365
|
const runnerCwd = cwd ?? ctx.cwd;
|
|
352
366
|
const outputPath = resolveSingleOutputPath(params.output, ctx.cwd, cwd);
|
|
353
367
|
const taskWithOutputInstruction = injectSingleOutputInstruction(task, outputPath);
|
|
354
|
-
|
|
355
|
-
|
|
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
|
+
},
|
|
356
407
|
id,
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
modelCandidates: buildModelCandidates(params.modelOverride ?? agentConfig.model, agentConfig.fallbackModels, availableModels).map((candidate) =>
|
|
364
|
-
applyThinkingSuffix(candidate, agentConfig.thinking),
|
|
365
|
-
),
|
|
366
|
-
tools: agentConfig.tools,
|
|
367
|
-
extensions: agentConfig.extensions,
|
|
368
|
-
mcpDirectTools: agentConfig.mcpDirectTools,
|
|
369
|
-
systemPrompt,
|
|
370
|
-
skills: resolvedSkills.map((r) => r.name),
|
|
371
|
-
outputPath,
|
|
372
|
-
sessionFile,
|
|
373
|
-
maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, agentConfig.maxSubagentDepth),
|
|
374
|
-
},
|
|
375
|
-
],
|
|
376
|
-
resultPath: path.join(RESULTS_DIR, `${id}.json`),
|
|
377
|
-
cwd: runnerCwd,
|
|
378
|
-
placeholder: "{previous}",
|
|
379
|
-
maxOutput,
|
|
380
|
-
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
381
|
-
artifactConfig,
|
|
382
|
-
share: shareEnabled,
|
|
383
|
-
sessionDir: sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined,
|
|
384
|
-
asyncDir,
|
|
385
|
-
sessionId: ctx.currentSessionId,
|
|
386
|
-
piPackageRoot,
|
|
387
|
-
worktreeSetupHook,
|
|
388
|
-
worktreeSetupHookTimeoutMs,
|
|
389
|
-
},
|
|
390
|
-
id,
|
|
391
|
-
runnerCwd,
|
|
392
|
-
);
|
|
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
|
+
}
|
|
393
414
|
|
|
394
415
|
if (pid) {
|
|
395
416
|
ctx.pi.events.emit("subagent:started", {
|