pi-subagents 0.21.4 → 0.22.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 +23 -0
- package/README.md +12 -11
- package/agents/context-builder.md +4 -5
- package/agents/delegate.md +2 -1
- package/agents/oracle.md +5 -8
- package/agents/planner.md +2 -3
- package/agents/researcher.md +2 -3
- package/agents/reviewer.md +4 -21
- package/agents/scout.md +2 -3
- package/agents/worker.md +7 -7
- package/package.json +3 -2
- package/prompts/parallel-context-build.md +1 -1
- package/prompts/parallel-handoff-plan.md +2 -2
- package/skills/pi-subagents/SKILL.md +30 -27
- package/src/extension/index.ts +4 -1
- package/src/intercom/intercom-bridge.ts +10 -8
- package/src/intercom/result-intercom.ts +4 -3
- package/src/manager-ui/agent-manager-edit.ts +43 -19
- package/src/manager-ui/agent-manager.ts +5 -2
- package/src/runs/background/async-execution.ts +16 -10
- package/src/runs/background/async-job-tracker.ts +12 -19
- package/src/runs/background/async-resume.ts +1 -0
- package/src/runs/background/async-status.ts +35 -49
- package/src/runs/background/parallel-groups.ts +45 -0
- package/src/runs/background/result-watcher.ts +2 -2
- package/src/runs/background/run-status.ts +26 -7
- package/src/runs/background/stale-run-reconciler.ts +15 -2
- package/src/runs/background/subagent-runner.ts +12 -3
- package/src/runs/foreground/chain-clarify.ts +35 -30
- package/src/runs/foreground/chain-execution.ts +9 -6
- package/src/runs/foreground/execution.ts +4 -0
- package/src/runs/foreground/subagent-executor.ts +18 -30
- package/src/runs/shared/model-fallback.ts +2 -5
- package/src/runs/shared/pi-args.ts +20 -0
- package/src/shared/model-info.ts +68 -0
- package/src/shared/session-identity.ts +10 -0
- package/src/shared/types.ts +14 -5
- package/src/slash/slash-commands.ts +8 -7
- package/src/tui/render.ts +67 -2
- package/src/tui/subagents-status.ts +129 -15
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
|
4
|
-
import { formatAsyncRunList, listAsyncRuns } from "./async-status.ts";
|
|
5
|
-
import { ASYNC_DIR, RESULTS_DIR, type Details } from "../../shared/types.ts";
|
|
4
|
+
import { formatAsyncRunList, formatAsyncRunProgressLabel, listAsyncRuns } from "./async-status.ts";
|
|
5
|
+
import { ASYNC_DIR, RESULTS_DIR, type AsyncStatus, type Details } from "../../shared/types.ts";
|
|
6
6
|
import { resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.ts";
|
|
7
7
|
import { resolveAsyncRunLocation } from "./async-resume.ts";
|
|
8
|
+
import { flatToLogicalStepIndex, normalizeParallelGroups } from "./parallel-groups.ts";
|
|
8
9
|
import { reconcileAsyncRun } from "./stale-run-reconciler.ts";
|
|
9
10
|
|
|
10
11
|
interface RunStatusParams {
|
|
@@ -31,6 +32,19 @@ function canShowRevive(stepCount: number, sessionFile: unknown): sessionFile is
|
|
|
31
32
|
return stepCount === 1 && typeof sessionFile === "string" && fs.existsSync(sessionFile);
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
function stepLineLabel(status: AsyncStatus, index: number): string {
|
|
36
|
+
const steps = status.steps ?? [];
|
|
37
|
+
if (status.mode === "parallel") return `Agent ${index + 1}/${steps.length || 1}`;
|
|
38
|
+
if (status.mode === "chain") {
|
|
39
|
+
const chainStepCount = status.chainStepCount ?? (steps.length || 1);
|
|
40
|
+
const groups = normalizeParallelGroups(status.parallelGroups, steps.length, chainStepCount);
|
|
41
|
+
const group = groups.find((candidate) => index >= candidate.start && index < candidate.start + candidate.count);
|
|
42
|
+
if (group) return `Step ${group.stepIndex + 1}/${chainStepCount} Agent ${index - group.start + 1}/${group.count}`;
|
|
43
|
+
return `Step ${flatToLogicalStepIndex(index, chainStepCount, groups) + 1}/${chainStepCount}`;
|
|
44
|
+
}
|
|
45
|
+
return `Step ${index + 1}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDeps = {}): AgentToolResult<Details> {
|
|
35
49
|
const asyncDirRoot = deps.asyncDirRoot ?? ASYNC_DIR;
|
|
36
50
|
const resultsDir = deps.resultsDir ?? RESULTS_DIR;
|
|
@@ -89,9 +103,14 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
89
103
|
const logPath = path.join(asyncDir, `subagent-log-${effectiveRunId}.md`);
|
|
90
104
|
const eventsPath = path.join(asyncDir, "events.jsonl");
|
|
91
105
|
if (status) {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
106
|
+
const progressLabel = formatAsyncRunProgressLabel({
|
|
107
|
+
mode: status.mode,
|
|
108
|
+
state: status.state,
|
|
109
|
+
currentStep: status.currentStep,
|
|
110
|
+
chainStepCount: status.chainStepCount,
|
|
111
|
+
parallelGroups: status.parallelGroups,
|
|
112
|
+
steps: (status.steps ?? []).map((step, index) => ({ index, agent: step.agent, status: step.status })),
|
|
113
|
+
});
|
|
95
114
|
const started = new Date(status.startedAt).toISOString();
|
|
96
115
|
const updated = status.lastUpdate ? new Date(status.lastUpdate).toISOString() : "n/a";
|
|
97
116
|
const statusActivityText = status.state === "running" ? activityText(status.activityState, status.lastActivityAt) : undefined;
|
|
@@ -101,7 +120,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
101
120
|
`State: ${status.state}`,
|
|
102
121
|
statusActivityText ? `Activity: ${statusActivityText}` : undefined,
|
|
103
122
|
`Mode: ${status.mode}`,
|
|
104
|
-
|
|
123
|
+
`Progress: ${progressLabel}`,
|
|
105
124
|
`Started: ${started}`,
|
|
106
125
|
`Updated: ${updated}`,
|
|
107
126
|
`Dir: ${asyncDir}`,
|
|
@@ -111,7 +130,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
|
|
|
111
130
|
for (const [index, step] of (status.steps ?? []).entries()) {
|
|
112
131
|
const stepActivityText = step.status === "running" ? activityText(step.activityState, step.lastActivityAt) : undefined;
|
|
113
132
|
const errorText = step.error ? `, error: ${step.error}` : "";
|
|
114
|
-
lines.push(
|
|
133
|
+
lines.push(`${stepLineLabel(status, index)}: ${step.agent} ${step.status}${stepActivityText ? `, ${stepActivityText}` : ""}${errorText}`);
|
|
115
134
|
if (step.status === "running") {
|
|
116
135
|
lines.push(` Intercom target: ${resolveSubagentIntercomTarget(status.runId, step.agent, index)} (if registered)`);
|
|
117
136
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { writeAtomicJson } from "../../shared/atomic-json.ts";
|
|
4
|
-
import { RESULTS_DIR, type AsyncStatus } from "../../shared/types.ts";
|
|
4
|
+
import { RESULTS_DIR, type AsyncParallelGroupStatus, type AsyncStatus, type SubagentRunMode } from "../../shared/types.ts";
|
|
5
|
+
import { normalizeParallelGroups } from "./parallel-groups.ts";
|
|
5
6
|
|
|
6
7
|
export type PidLiveness = "alive" | "dead" | "unknown";
|
|
7
8
|
|
|
@@ -10,8 +11,11 @@ type KillFn = (pid: number, signal?: NodeJS.Signals | 0) => boolean;
|
|
|
10
11
|
interface StartedRunMetadata {
|
|
11
12
|
runId: string;
|
|
12
13
|
pid?: number;
|
|
13
|
-
|
|
14
|
+
sessionId?: string;
|
|
15
|
+
mode?: SubagentRunMode;
|
|
14
16
|
agents?: string[];
|
|
17
|
+
chainStepCount?: number;
|
|
18
|
+
parallelGroups?: AsyncParallelGroupStatus[];
|
|
15
19
|
startedAt?: number;
|
|
16
20
|
sessionFile?: string;
|
|
17
21
|
}
|
|
@@ -133,13 +137,21 @@ function terminalStatusFromResult(status: AsyncStatus, resultPath: string, now:
|
|
|
133
137
|
function buildStartedStatus(asyncDir: string, startedRun: StartedRunMetadata, now: number): AsyncStatus {
|
|
134
138
|
const startedAt = startedRun.startedAt ?? now;
|
|
135
139
|
const agents = startedRun.agents?.length ? startedRun.agents : ["subagent"];
|
|
140
|
+
const chainStepCount = startedRun.chainStepCount;
|
|
141
|
+
const parallelGroups = chainStepCount !== undefined
|
|
142
|
+
? normalizeParallelGroups(startedRun.parallelGroups, agents.length, chainStepCount)
|
|
143
|
+
: [];
|
|
136
144
|
return {
|
|
137
145
|
runId: startedRun.runId || path.basename(asyncDir),
|
|
146
|
+
...(startedRun.sessionId ? { sessionId: startedRun.sessionId } : {}),
|
|
138
147
|
mode: startedRun.mode ?? "single",
|
|
139
148
|
state: "running",
|
|
140
149
|
pid: startedRun.pid,
|
|
141
150
|
startedAt,
|
|
142
151
|
lastUpdate: now,
|
|
152
|
+
currentStep: 0,
|
|
153
|
+
...(chainStepCount !== undefined ? { chainStepCount } : {}),
|
|
154
|
+
...(parallelGroups.length ? { parallelGroups } : {}),
|
|
143
155
|
steps: agents.map((agent) => ({
|
|
144
156
|
agent,
|
|
145
157
|
status: "running" as const,
|
|
@@ -197,6 +209,7 @@ function buildFailedRepair(status: AsyncStatus, asyncDir: string, now: number, r
|
|
|
197
209
|
timestamp: now,
|
|
198
210
|
durationMs: Math.max(0, now - status.startedAt),
|
|
199
211
|
asyncDir,
|
|
212
|
+
sessionId: status.sessionId,
|
|
200
213
|
sessionFile: status.sessionFile,
|
|
201
214
|
},
|
|
202
215
|
};
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
type AsyncStatus,
|
|
17
17
|
type ModelAttempt,
|
|
18
18
|
type ResolvedControlConfig,
|
|
19
|
+
type SubagentRunMode,
|
|
19
20
|
type Usage,
|
|
20
21
|
DEFAULT_MAX_OUTPUT,
|
|
21
22
|
type MaxOutputConfig,
|
|
@@ -90,7 +91,7 @@ interface SubagentRunConfig {
|
|
|
90
91
|
controlConfig?: ResolvedControlConfig;
|
|
91
92
|
controlIntercomTarget?: string;
|
|
92
93
|
childIntercomTargets?: Array<string | undefined>;
|
|
93
|
-
resultMode?:
|
|
94
|
+
resultMode?: SubagentRunMode;
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
interface StepResult {
|
|
@@ -472,7 +473,7 @@ function writeRunLog(
|
|
|
472
473
|
logPath: string,
|
|
473
474
|
input: {
|
|
474
475
|
id: string;
|
|
475
|
-
mode:
|
|
476
|
+
mode: SubagentRunMode;
|
|
476
477
|
cwd: string;
|
|
477
478
|
startedAt: number;
|
|
478
479
|
endedAt: number;
|
|
@@ -537,6 +538,7 @@ interface SingleStepContext {
|
|
|
537
538
|
piArgv1?: string;
|
|
538
539
|
registerInterrupt?: (interrupt: (() => void) | undefined) => void;
|
|
539
540
|
childIntercomTarget?: string;
|
|
541
|
+
orchestratorIntercomTarget?: string;
|
|
540
542
|
onChildEvent?: (event: ChildEvent) => void;
|
|
541
543
|
}
|
|
542
544
|
|
|
@@ -603,6 +605,10 @@ async function runSingleStep(
|
|
|
603
605
|
mcpDirectTools: step.mcpDirectTools,
|
|
604
606
|
promptFileStem: step.agent,
|
|
605
607
|
intercomSessionName: ctx.childIntercomTarget,
|
|
608
|
+
orchestratorIntercomTarget: ctx.orchestratorIntercomTarget,
|
|
609
|
+
runId: ctx.id,
|
|
610
|
+
childAgentName: step.agent,
|
|
611
|
+
childIndex: ctx.flatIndex,
|
|
606
612
|
});
|
|
607
613
|
const run = await runPiStreaming(
|
|
608
614
|
args,
|
|
@@ -877,7 +883,8 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
877
883
|
|| flatSteps.some((step) => Boolean(step.sessionFile));
|
|
878
884
|
const statusPayload: RunnerStatusPayload = {
|
|
879
885
|
runId: id,
|
|
880
|
-
|
|
886
|
+
...(config.sessionId ? { sessionId: config.sessionId } : {}),
|
|
887
|
+
mode: config.resultMode ?? (flatSteps.length > 1 ? "chain" : "single"),
|
|
881
888
|
state: "running",
|
|
882
889
|
lastActivityAt: overallStartTime,
|
|
883
890
|
startedAt: overallStartTime,
|
|
@@ -1297,6 +1304,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1297
1304
|
piPackageRoot: config.piPackageRoot,
|
|
1298
1305
|
piArgv1: config.piArgv1,
|
|
1299
1306
|
childIntercomTarget: config.childIntercomTargets?.[fi],
|
|
1307
|
+
orchestratorIntercomTarget: config.controlIntercomTarget,
|
|
1300
1308
|
registerInterrupt: (interrupt) => {
|
|
1301
1309
|
activeChildInterrupt = interrupt;
|
|
1302
1310
|
},
|
|
@@ -1437,6 +1445,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1437
1445
|
piPackageRoot: config.piPackageRoot,
|
|
1438
1446
|
piArgv1: config.piArgv1,
|
|
1439
1447
|
childIntercomTarget: config.childIntercomTargets?.[flatIndex],
|
|
1448
|
+
orchestratorIntercomTarget: config.controlIntercomTarget,
|
|
1440
1449
|
registerInterrupt: (interrupt) => {
|
|
1441
1450
|
activeChildInterrupt = interrupt;
|
|
1442
1451
|
},
|
|
@@ -18,15 +18,10 @@ import { createEditorState, ensureCursorVisible, getCursorDisplayPos, handleEdit
|
|
|
18
18
|
import { updateFrontmatterField } from "../../agents/agent-serializer.ts";
|
|
19
19
|
import { serializeChain } from "../../agents/chain-serializer.ts";
|
|
20
20
|
import { resolveModelCandidate, splitThinkingSuffix } from "../shared/model-fallback.ts";
|
|
21
|
+
import { findModelInfo, getSupportedThinkingLevels, type ModelInfo, type ThinkingLevel } from "../../shared/model-info.ts";
|
|
21
22
|
|
|
22
23
|
type ClarifyMode = 'single' | 'parallel' | 'chain';
|
|
23
24
|
|
|
24
|
-
export interface ModelInfo {
|
|
25
|
-
provider: string;
|
|
26
|
-
id: string;
|
|
27
|
-
fullId: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
25
|
export interface BehaviorOverride {
|
|
31
26
|
output?: string | false;
|
|
32
27
|
reads?: string[] | false;
|
|
@@ -44,9 +39,6 @@ export interface ChainClarifyResult {
|
|
|
44
39
|
|
|
45
40
|
type EditMode = "template" | "output" | "reads" | "model" | "thinking" | "skills";
|
|
46
41
|
|
|
47
|
-
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const;
|
|
48
|
-
type ThinkingLevel = typeof THINKING_LEVELS[number];
|
|
49
|
-
|
|
50
42
|
/**
|
|
51
43
|
* TUI component for chain clarification.
|
|
52
44
|
* Factory signature matches ctx.ui.custom: (tui, theme, kb, done) => Component
|
|
@@ -602,7 +594,10 @@ export class ChainClarifyComponent implements Component {
|
|
|
602
594
|
const selected = this.filteredModels[this.modelSelectedIndex];
|
|
603
595
|
if (selected) {
|
|
604
596
|
const { thinkingSuffix } = splitThinkingSuffix(this.getEffectiveModel(this.editingStep!));
|
|
605
|
-
|
|
597
|
+
const requestedLevel = thinkingSuffix.slice(1);
|
|
598
|
+
const selectedModel = findModelInfo(selected.fullId, this.availableModels, this.preferredProvider);
|
|
599
|
+
const suffix = getSupportedThinkingLevels(selectedModel).some((level) => level === requestedLevel) ? thinkingSuffix : "";
|
|
600
|
+
this.updateBehavior(this.editingStep!, "model", `${selected.fullId}${suffix}`);
|
|
606
601
|
}
|
|
607
602
|
this.exitEditMode();
|
|
608
603
|
return;
|
|
@@ -645,6 +640,10 @@ export class ChainClarifyComponent implements Component {
|
|
|
645
640
|
}
|
|
646
641
|
}
|
|
647
642
|
|
|
643
|
+
private getAvailableThinkingLevels(stepIndex: number): ThinkingLevel[] {
|
|
644
|
+
return getSupportedThinkingLevels(findModelInfo(this.getEffectiveModel(stepIndex), this.availableModels, this.preferredProvider));
|
|
645
|
+
}
|
|
646
|
+
|
|
648
647
|
/** Enter thinking level selector mode */
|
|
649
648
|
private enterThinkingSelector(): void {
|
|
650
649
|
if (!this.getEffectiveBehavior(this.selectedStep).model) {
|
|
@@ -654,15 +653,11 @@ export class ChainClarifyComponent implements Component {
|
|
|
654
653
|
this.editingStep = this.selectedStep;
|
|
655
654
|
this.editMode = "thinking";
|
|
656
655
|
|
|
657
|
-
const
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
this.thinkingSelectedIndex = levelIdx >= 0 ? levelIdx : 0;
|
|
663
|
-
} else {
|
|
664
|
-
this.thinkingSelectedIndex = 0;
|
|
665
|
-
}
|
|
656
|
+
const levels = this.getAvailableThinkingLevels(this.selectedStep);
|
|
657
|
+
const { thinkingSuffix } = splitThinkingSuffix(this.getEffectiveModel(this.selectedStep));
|
|
658
|
+
const suffix = thinkingSuffix.slice(1);
|
|
659
|
+
const levelIdx = levels.findIndex((level) => level === suffix);
|
|
660
|
+
this.thinkingSelectedIndex = levelIdx >= 0 ? levelIdx : Math.max(0, levels.indexOf("off"));
|
|
666
661
|
|
|
667
662
|
this.tui.requestRender();
|
|
668
663
|
}
|
|
@@ -673,8 +668,11 @@ export class ChainClarifyComponent implements Component {
|
|
|
673
668
|
return;
|
|
674
669
|
}
|
|
675
670
|
|
|
671
|
+
const levels = this.getAvailableThinkingLevels(this.editingStep!);
|
|
672
|
+
if (levels.length === 0) return;
|
|
673
|
+
|
|
676
674
|
if (matchesKey(data, "return")) {
|
|
677
|
-
const selectedLevel =
|
|
675
|
+
const selectedLevel = levels[this.thinkingSelectedIndex] ?? "off";
|
|
678
676
|
this.applyThinkingLevel(selectedLevel);
|
|
679
677
|
this.exitEditMode();
|
|
680
678
|
return;
|
|
@@ -682,14 +680,14 @@ export class ChainClarifyComponent implements Component {
|
|
|
682
680
|
|
|
683
681
|
if (matchesKey(data, "up")) {
|
|
684
682
|
this.thinkingSelectedIndex = this.thinkingSelectedIndex === 0
|
|
685
|
-
?
|
|
683
|
+
? levels.length - 1
|
|
686
684
|
: this.thinkingSelectedIndex - 1;
|
|
687
685
|
this.tui.requestRender();
|
|
688
686
|
return;
|
|
689
687
|
}
|
|
690
688
|
|
|
691
689
|
if (matchesKey(data, "down")) {
|
|
692
|
-
this.thinkingSelectedIndex = this.thinkingSelectedIndex ===
|
|
690
|
+
this.thinkingSelectedIndex = this.thinkingSelectedIndex === levels.length - 1
|
|
693
691
|
? 0
|
|
694
692
|
: this.thinkingSelectedIndex + 1;
|
|
695
693
|
this.tui.requestRender();
|
|
@@ -1044,13 +1042,18 @@ export class ChainClarifyComponent implements Component {
|
|
|
1044
1042
|
"xhigh": "Maximum reasoning (ultrathink)",
|
|
1045
1043
|
};
|
|
1046
1044
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1045
|
+
const levels = this.getAvailableThinkingLevels(this.editingStep!);
|
|
1046
|
+
if (levels.length === 0) {
|
|
1047
|
+
lines.push(this.row(` ${th.fg("dim", "No supported thinking levels")}`));
|
|
1048
|
+
} else {
|
|
1049
|
+
for (let i = 0; i < levels.length; i++) {
|
|
1050
|
+
const level = levels[i]!;
|
|
1051
|
+
const isSelected = i === this.thinkingSelectedIndex;
|
|
1052
|
+
const prefix = isSelected ? th.fg("accent", "→ ") : " ";
|
|
1053
|
+
const levelText = isSelected ? th.fg("accent", level) : level;
|
|
1054
|
+
const desc = th.fg("dim", ` - ${levelDescriptions[level]}`);
|
|
1055
|
+
lines.push(this.row(` ${prefix}${levelText}${desc}`));
|
|
1056
|
+
}
|
|
1054
1057
|
}
|
|
1055
1058
|
|
|
1056
1059
|
const contentLines = lines.length;
|
|
@@ -1059,7 +1062,9 @@ export class ChainClarifyComponent implements Component {
|
|
|
1059
1062
|
lines.push(this.row(""));
|
|
1060
1063
|
}
|
|
1061
1064
|
|
|
1062
|
-
const footerText =
|
|
1065
|
+
const footerText = levels.length === 0
|
|
1066
|
+
? " [Esc] Cancel "
|
|
1067
|
+
: " [Enter] Select • [Esc] Cancel • ↑↓ Navigate ";
|
|
1063
1068
|
lines.push(this.renderFooter(footerText));
|
|
1064
1069
|
|
|
1065
1070
|
return lines;
|
|
@@ -7,7 +7,8 @@ import * as path from "node:path";
|
|
|
7
7
|
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
|
8
8
|
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
9
9
|
import type { AgentConfig } from "../../agents/agents.ts";
|
|
10
|
-
import { ChainClarifyComponent, type ChainClarifyResult, type BehaviorOverride
|
|
10
|
+
import { ChainClarifyComponent, type ChainClarifyResult, type BehaviorOverride } from "./chain-clarify.ts";
|
|
11
|
+
import { toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
|
|
11
12
|
import {
|
|
12
13
|
resolveChainTemplates,
|
|
13
14
|
createChainDir,
|
|
@@ -93,6 +94,7 @@ interface ParallelChainRunInput {
|
|
|
93
94
|
onControlEvent?: (event: ControlEvent) => void;
|
|
94
95
|
controlConfig: ResolvedControlConfig;
|
|
95
96
|
childIntercomTarget?: (agent: string, index: number) => string | undefined;
|
|
97
|
+
orchestratorIntercomTarget?: string;
|
|
96
98
|
foregroundControl?: {
|
|
97
99
|
updatedAt: number;
|
|
98
100
|
currentAgent?: string;
|
|
@@ -240,6 +242,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
240
242
|
controlConfig: input.controlConfig,
|
|
241
243
|
onControlEvent: input.onControlEvent,
|
|
242
244
|
intercomSessionName: input.childIntercomTarget?.(task.agent, input.globalTaskIndex + taskIndex),
|
|
245
|
+
orchestratorIntercomTarget: input.orchestratorIntercomTarget,
|
|
243
246
|
modelOverride: effectiveModel,
|
|
244
247
|
availableModels: input.availableModels,
|
|
245
248
|
preferredModelProvider: input.ctx.model?.provider,
|
|
@@ -313,6 +316,7 @@ interface ChainExecutionParams {
|
|
|
313
316
|
onControlEvent?: (event: ControlEvent) => void;
|
|
314
317
|
controlConfig: ResolvedControlConfig;
|
|
315
318
|
childIntercomTarget?: (agent: string, index: number) => string | undefined;
|
|
319
|
+
orchestratorIntercomTarget?: string;
|
|
316
320
|
foregroundControl?: {
|
|
317
321
|
updatedAt: number;
|
|
318
322
|
currentAgent?: string;
|
|
@@ -363,6 +367,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
363
367
|
onControlEvent,
|
|
364
368
|
controlConfig,
|
|
365
369
|
childIntercomTarget,
|
|
370
|
+
orchestratorIntercomTarget,
|
|
366
371
|
foregroundControl,
|
|
367
372
|
intercomEvents,
|
|
368
373
|
chainSkills: chainSkillsParam,
|
|
@@ -389,11 +394,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
389
394
|
let templates: ResolvedTemplates = resolveChainTemplates(chainSteps);
|
|
390
395
|
const shouldClarify = clarify !== false && ctx.hasUI && !hasParallelSteps;
|
|
391
396
|
let tuiBehaviorOverrides: (BehaviorOverride | undefined)[] | undefined;
|
|
392
|
-
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(
|
|
393
|
-
provider: m.provider,
|
|
394
|
-
id: m.id,
|
|
395
|
-
fullId: `${m.provider}/${m.id}`,
|
|
396
|
-
}));
|
|
397
|
+
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
397
398
|
const availableSkills = discoverAvailableSkills(cwd ?? ctx.cwd);
|
|
398
399
|
|
|
399
400
|
if (shouldClarify) {
|
|
@@ -586,6 +587,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
586
587
|
controlConfig,
|
|
587
588
|
onControlEvent,
|
|
588
589
|
childIntercomTarget,
|
|
590
|
+
orchestratorIntercomTarget,
|
|
589
591
|
foregroundControl,
|
|
590
592
|
worktreeSetup,
|
|
591
593
|
maxSubagentDepth: params.maxSubagentDepth,
|
|
@@ -771,6 +773,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
771
773
|
controlConfig,
|
|
772
774
|
onControlEvent,
|
|
773
775
|
intercomSessionName: childIntercomTarget?.(seqStep.agent, globalTaskIndex),
|
|
776
|
+
orchestratorIntercomTarget,
|
|
774
777
|
modelOverride: effectiveModel,
|
|
775
778
|
availableModels,
|
|
776
779
|
preferredModelProvider: ctx.model?.provider,
|
|
@@ -153,6 +153,10 @@ async function runSingleAttempt(
|
|
|
153
153
|
mcpDirectTools: agent.mcpDirectTools,
|
|
154
154
|
promptFileStem: agent.name,
|
|
155
155
|
intercomSessionName: options.intercomSessionName,
|
|
156
|
+
orchestratorIntercomTarget: options.orchestratorIntercomTarget,
|
|
157
|
+
runId: options.runId,
|
|
158
|
+
childAgentName: agent.name,
|
|
159
|
+
childIndex: options.index ?? 0,
|
|
156
160
|
});
|
|
157
161
|
|
|
158
162
|
const result: SingleResult = {
|
|
@@ -5,7 +5,8 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
|
|
5
5
|
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
6
6
|
import { type AgentConfig, type AgentScope } from "../../agents/agents.ts";
|
|
7
7
|
import { getArtifactsDir } from "../../shared/artifacts.ts";
|
|
8
|
-
import { ChainClarifyComponent, type ChainClarifyResult
|
|
8
|
+
import { ChainClarifyComponent, type ChainClarifyResult } from "./chain-clarify.ts";
|
|
9
|
+
import { toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
|
|
9
10
|
import { executeChain } from "./chain-execution.ts";
|
|
10
11
|
import { resolveExecutionAgentScope } from "../../agents/agent-scope.ts";
|
|
11
12
|
import { handleManagementAction } from "../../agents/agent-management.ts";
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
import { discoverAvailableSkills, normalizeSkillInput } from "../../agents/skills.ts";
|
|
30
31
|
import { executeAsyncChain, executeAsyncSingle, isAsyncAvailable } from "../background/async-execution.ts";
|
|
31
32
|
import { createForkContextResolver } from "../../shared/fork-context.ts";
|
|
33
|
+
import { resolveCurrentSessionId } from "../../shared/session-identity.ts";
|
|
32
34
|
import { applyIntercomBridgeToAgent, INTERCOM_BRIDGE_MARKER, resolveIntercomBridge, resolveIntercomSessionTarget, resolveSubagentIntercomTarget, type IntercomBridgeState } from "../../intercom/intercom-bridge.ts";
|
|
33
35
|
import { formatControlIntercomMessage, formatControlNoticeMessage, resolveControlConfig, shouldNotifyControlEvent } from "../shared/subagent-control.ts";
|
|
34
36
|
import { finalizeSingleOutput, injectSingleOutputInstruction, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
@@ -65,6 +67,7 @@ import {
|
|
|
65
67
|
type MaxOutputConfig,
|
|
66
68
|
type ResolvedControlConfig,
|
|
67
69
|
type SingleResult,
|
|
70
|
+
type SubagentRunMode,
|
|
68
71
|
type SubagentState,
|
|
69
72
|
DEFAULT_ARTIFACT_CONFIG,
|
|
70
73
|
SUBAGENT_ACTIONS,
|
|
@@ -332,7 +335,7 @@ async function resumeAsyncRun(input: {
|
|
|
332
335
|
}
|
|
333
336
|
|
|
334
337
|
const parentSessionFile = input.ctx.sessionManager.getSessionFile() ?? null;
|
|
335
|
-
input.deps.state.currentSessionId =
|
|
338
|
+
input.deps.state.currentSessionId = resolveCurrentSessionId(input.ctx.sessionManager);
|
|
336
339
|
const effectiveCwd = target.cwd ?? input.requestCwd;
|
|
337
340
|
const scope: AgentScope = resolveExecutionAgentScope(input.params.agentScope);
|
|
338
341
|
const discoveredAgents = input.deps.discoverAgents(effectiveCwd, scope).agents;
|
|
@@ -356,11 +359,7 @@ async function resumeAsyncRun(input: {
|
|
|
356
359
|
|
|
357
360
|
const runId = randomUUID().slice(0, 8);
|
|
358
361
|
const artifactConfig: ArtifactConfig = { ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts !== false };
|
|
359
|
-
const availableModels = input.ctx.modelRegistry.getAvailable().map(
|
|
360
|
-
provider: m.provider,
|
|
361
|
-
id: m.id,
|
|
362
|
-
fullId: `${m.provider}/${m.id}`,
|
|
363
|
-
}));
|
|
362
|
+
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
364
363
|
const result = executeAsyncSingle(runId, {
|
|
365
364
|
agent: target.agent,
|
|
366
365
|
task: buildRevivedAsyncTask(target, followUp),
|
|
@@ -423,7 +422,7 @@ async function emitForegroundResultIntercom(input: {
|
|
|
423
422
|
pi: ExtensionAPI;
|
|
424
423
|
intercomBridge: IntercomBridgeState;
|
|
425
424
|
runId: string;
|
|
426
|
-
mode:
|
|
425
|
+
mode: SubagentRunMode;
|
|
427
426
|
results: SingleResult[];
|
|
428
427
|
chainSteps?: number;
|
|
429
428
|
}): Promise<ReturnType<typeof buildSubagentResultIntercomPayload> | null> {
|
|
@@ -459,7 +458,7 @@ async function maybeBuildForegroundIntercomReceipt(input: {
|
|
|
459
458
|
pi: ExtensionAPI;
|
|
460
459
|
intercomBridge: IntercomBridgeState;
|
|
461
460
|
runId: string;
|
|
462
|
-
mode:
|
|
461
|
+
mode: SubagentRunMode;
|
|
463
462
|
details: Details;
|
|
464
463
|
}): Promise<{ text: string; details: Details } | null> {
|
|
465
464
|
const payload = await emitForegroundResultIntercom({
|
|
@@ -780,11 +779,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
780
779
|
currentSessionId: deps.state.currentSessionId!,
|
|
781
780
|
currentModelProvider: ctx.model?.provider,
|
|
782
781
|
};
|
|
783
|
-
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(
|
|
784
|
-
provider: m.provider,
|
|
785
|
-
id: m.id,
|
|
786
|
-
fullId: `${m.provider}/${m.id}`,
|
|
787
|
-
}));
|
|
782
|
+
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
788
783
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
|
|
789
784
|
const currentProvider = ctx.model?.provider;
|
|
790
785
|
const controlIntercomTarget = intercomBridge.active ? intercomBridge.orchestratorTarget : undefined;
|
|
@@ -949,6 +944,7 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
949
944
|
onControlEvent,
|
|
950
945
|
controlConfig,
|
|
951
946
|
childIntercomTarget: childIntercomTarget ? (agent, index) => childIntercomTarget(runId, agent, index) : undefined,
|
|
947
|
+
orchestratorIntercomTarget: data.intercomBridge.active ? data.intercomBridge.orchestratorTarget : undefined,
|
|
952
948
|
foregroundControl,
|
|
953
949
|
chainSkills,
|
|
954
950
|
chainDir: params.chainDir,
|
|
@@ -977,11 +973,7 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
977
973
|
chain: asyncChain,
|
|
978
974
|
agents,
|
|
979
975
|
ctx: asyncCtx,
|
|
980
|
-
availableModels: ctx.modelRegistry.getAvailable().map(
|
|
981
|
-
provider: m.provider,
|
|
982
|
-
id: m.id,
|
|
983
|
-
fullId: `${m.provider}/${m.id}`,
|
|
984
|
-
})),
|
|
976
|
+
availableModels: ctx.modelRegistry.getAvailable().map(toModelInfo),
|
|
985
977
|
cwd: effectiveCwd,
|
|
986
978
|
maxOutput: params.maxOutput,
|
|
987
979
|
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
@@ -1043,6 +1035,7 @@ interface ForegroundParallelRunInput {
|
|
|
1043
1035
|
controlConfig: ResolvedControlConfig;
|
|
1044
1036
|
onControlEvent?: (event: ControlEvent) => void;
|
|
1045
1037
|
childIntercomTarget?: (agent: string, index: number) => string | undefined;
|
|
1038
|
+
orchestratorIntercomTarget?: string;
|
|
1046
1039
|
foregroundControl?: SubagentState["foregroundControls"] extends Map<string, infer T> ? T : never;
|
|
1047
1040
|
concurrencyLimit: number;
|
|
1048
1041
|
liveResults: (SingleResult | undefined)[];
|
|
@@ -1201,6 +1194,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
1201
1194
|
controlConfig: input.controlConfig,
|
|
1202
1195
|
onControlEvent: input.onControlEvent,
|
|
1203
1196
|
intercomSessionName: input.childIntercomTarget?.(task.agent, index),
|
|
1197
|
+
orchestratorIntercomTarget: input.orchestratorIntercomTarget,
|
|
1204
1198
|
modelOverride: input.modelOverrides[index],
|
|
1205
1199
|
availableModels: input.availableModels,
|
|
1206
1200
|
preferredModelProvider: input.ctx.model?.provider,
|
|
@@ -1305,11 +1299,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1305
1299
|
}
|
|
1306
1300
|
|
|
1307
1301
|
const currentProvider = ctx.model?.provider;
|
|
1308
|
-
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(
|
|
1309
|
-
provider: m.provider,
|
|
1310
|
-
id: m.id,
|
|
1311
|
-
fullId: `${m.provider}/${m.id}`,
|
|
1312
|
-
}));
|
|
1302
|
+
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
1313
1303
|
let taskTexts = tasks.map((t) => t.task);
|
|
1314
1304
|
const skillOverrides: (string[] | false | undefined)[] = tasks.map((t) =>
|
|
1315
1305
|
normalizeSkillInput(t.skill),
|
|
@@ -1482,6 +1472,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1482
1472
|
controlConfig,
|
|
1483
1473
|
onControlEvent,
|
|
1484
1474
|
childIntercomTarget: childIntercomTarget ? (agent, index) => childIntercomTarget(runId, agent, index) : undefined,
|
|
1475
|
+
orchestratorIntercomTarget: data.intercomBridge.active ? data.intercomBridge.orchestratorTarget : undefined,
|
|
1485
1476
|
foregroundControl,
|
|
1486
1477
|
concurrencyLimit: parallelConcurrency,
|
|
1487
1478
|
maxSubagentDepths,
|
|
@@ -1586,11 +1577,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1586
1577
|
}
|
|
1587
1578
|
|
|
1588
1579
|
const currentProvider = ctx.model?.provider;
|
|
1589
|
-
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(
|
|
1590
|
-
provider: m.provider,
|
|
1591
|
-
id: m.id,
|
|
1592
|
-
fullId: `${m.provider}/${m.id}`,
|
|
1593
|
-
}));
|
|
1580
|
+
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
1594
1581
|
let task = params.task ?? "";
|
|
1595
1582
|
let modelOverride: string | undefined = resolveModelCandidate(
|
|
1596
1583
|
(params.model as string | undefined) ?? agentConfig.model,
|
|
@@ -1751,6 +1738,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1751
1738
|
controlConfig,
|
|
1752
1739
|
onControlEvent,
|
|
1753
1740
|
intercomSessionName: childIntercomTarget,
|
|
1741
|
+
orchestratorIntercomTarget: data.intercomBridge.active ? data.intercomBridge.orchestratorTarget : undefined,
|
|
1754
1742
|
index: 0,
|
|
1755
1743
|
modelOverride,
|
|
1756
1744
|
availableModels,
|
|
@@ -1966,7 +1954,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
1966
1954
|
const scope: AgentScope = resolveExecutionAgentScope(effectiveParams.agentScope);
|
|
1967
1955
|
const effectiveCwd = effectiveParams.cwd ?? ctx.cwd;
|
|
1968
1956
|
const parentSessionFile = ctx.sessionManager.getSessionFile() ?? null;
|
|
1969
|
-
deps.state.currentSessionId =
|
|
1957
|
+
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
1970
1958
|
const discoveredAgents = deps.discoverAgents(effectiveCwd, scope).agents;
|
|
1971
1959
|
effectiveParams = applyAgentDefaultContext(effectiveParams, discoveredAgents);
|
|
1972
1960
|
const sessionName = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
+
import type { ModelInfo as AvailableModelInfo } from "../../shared/model-info.ts";
|
|
1
2
|
import type { Usage } from "../../shared/types.ts";
|
|
2
3
|
|
|
3
|
-
export
|
|
4
|
-
provider: string;
|
|
5
|
-
id: string;
|
|
6
|
-
fullId: string;
|
|
7
|
-
}
|
|
4
|
+
export type { AvailableModelInfo };
|
|
8
5
|
|
|
9
6
|
interface ModelAttemptSummary {
|
|
10
7
|
model: string;
|
|
@@ -7,6 +7,10 @@ const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
|
7
7
|
const TASK_ARG_LIMIT = 8000;
|
|
8
8
|
const PROMPT_RUNTIME_EXTENSION_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-prompt-runtime.ts");
|
|
9
9
|
export const SUBAGENT_CHILD_ENV = "PI_SUBAGENT_CHILD";
|
|
10
|
+
export const SUBAGENT_ORCHESTRATOR_TARGET_ENV = "PI_SUBAGENT_ORCHESTRATOR_TARGET";
|
|
11
|
+
export const SUBAGENT_RUN_ID_ENV = "PI_SUBAGENT_RUN_ID";
|
|
12
|
+
export const SUBAGENT_CHILD_AGENT_ENV = "PI_SUBAGENT_CHILD_AGENT";
|
|
13
|
+
export const SUBAGENT_CHILD_INDEX_ENV = "PI_SUBAGENT_CHILD_INDEX";
|
|
10
14
|
|
|
11
15
|
interface BuildPiArgsInput {
|
|
12
16
|
baseArgs: string[];
|
|
@@ -25,6 +29,10 @@ interface BuildPiArgsInput {
|
|
|
25
29
|
mcpDirectTools?: string[];
|
|
26
30
|
promptFileStem?: string;
|
|
27
31
|
intercomSessionName?: string;
|
|
32
|
+
orchestratorIntercomTarget?: string;
|
|
33
|
+
runId?: string;
|
|
34
|
+
childAgentName?: string;
|
|
35
|
+
childIndex?: number;
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
interface BuildPiArgsResult {
|
|
@@ -119,6 +127,18 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
119
127
|
if (input.intercomSessionName) {
|
|
120
128
|
env.PI_SUBAGENT_INTERCOM_SESSION_NAME = input.intercomSessionName;
|
|
121
129
|
}
|
|
130
|
+
if (input.orchestratorIntercomTarget) {
|
|
131
|
+
env[SUBAGENT_ORCHESTRATOR_TARGET_ENV] = input.orchestratorIntercomTarget;
|
|
132
|
+
}
|
|
133
|
+
if (input.runId) {
|
|
134
|
+
env[SUBAGENT_RUN_ID_ENV] = input.runId;
|
|
135
|
+
}
|
|
136
|
+
if (input.childAgentName) {
|
|
137
|
+
env[SUBAGENT_CHILD_AGENT_ENV] = input.childAgentName;
|
|
138
|
+
}
|
|
139
|
+
if (input.childIndex !== undefined) {
|
|
140
|
+
env[SUBAGENT_CHILD_INDEX_ENV] = String(input.childIndex);
|
|
141
|
+
}
|
|
122
142
|
if (input.mcpDirectTools?.length) {
|
|
123
143
|
env.MCP_DIRECT_TOOLS = input.mcpDirectTools.join(",");
|
|
124
144
|
} else {
|