pi-subagents 0.21.5 → 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 +15 -0
- package/README.md +9 -10
- 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 +1 -1
- 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/intercom/intercom-bridge.ts +10 -8
- package/src/manager-ui/agent-manager-edit.ts +43 -19
- package/src/manager-ui/agent-manager.ts +5 -2
- package/src/runs/background/subagent-runner.ts +7 -0
- 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 +12 -26
- 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/types.ts +1 -0
- package/src/slash/slash-commands.ts +3 -6
|
@@ -4,30 +4,31 @@ import { buildRuntimeName, defaultSystemPromptMode, frontmatterNameForConfig, pa
|
|
|
4
4
|
import { createEditorState, ensureCursorVisible, getCursorDisplayPos, handleEditorInput, renderEditor, wrapText } from "../tui/text-editor.ts";
|
|
5
5
|
import type { TextEditorState } from "../tui/text-editor.ts";
|
|
6
6
|
import { pad, row, renderHeader, renderFooter, formatScrollInfo } from "../tui/render-helpers.ts";
|
|
7
|
+
import { findModelInfo, getSupportedThinkingLevels, type ModelInfo, type ThinkingLevel } from "../shared/model-info.ts";
|
|
7
8
|
|
|
8
|
-
export
|
|
9
|
+
export type { ModelInfo };
|
|
9
10
|
export interface SkillInfo { name: string; source: string; description?: string; }
|
|
10
11
|
export type EditScreen = "edit" | "edit-field" | "edit-prompt";
|
|
11
12
|
export type EditField = typeof FIELD_ORDER[number];
|
|
12
13
|
|
|
13
14
|
export interface EditState {
|
|
14
15
|
draft: AgentConfig; isNew: boolean; fieldIndex: number; fieldMode: "text" | "model" | "thinking" | "skills" | null;
|
|
15
|
-
fieldEditor: TextEditorState; promptEditor: TextEditorState; modelSearchQuery: string; modelCursor: number; filteredModels: ModelInfo[];
|
|
16
|
+
fieldEditor: TextEditorState; promptEditor: TextEditorState; modelSearchQuery: string; modelCursor: number; models: ModelInfo[]; filteredModels: ModelInfo[];
|
|
16
17
|
thinkingCursor: number; skillSearchQuery: string; skillCursor: number; filteredSkills: SkillInfo[]; skillSelected: Set<string>; error?: string;
|
|
17
18
|
fields: EditField[];
|
|
18
19
|
title?: string;
|
|
19
20
|
overrideBase?: BuiltinAgentOverrideBase;
|
|
21
|
+
preferredProvider?: string;
|
|
20
22
|
}
|
|
21
23
|
interface EditInputResult { action?: "save" | "discard" | "delete"; nextScreen?: EditScreen; }
|
|
22
24
|
interface CreateEditStateOptions {
|
|
23
25
|
fields?: EditField[];
|
|
24
26
|
title?: string;
|
|
25
27
|
overrideBase?: BuiltinAgentOverrideBase;
|
|
28
|
+
preferredProvider?: string;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const;
|
|
29
31
|
const FIELD_ORDER = ["name", "package", "description", "model", "fallbackModels", "thinking", "systemPromptMode", "inheritProjectContext", "inheritSkills", "defaultContext", "tools", "extensions", "skills", "output", "reads", "progress", "interactive", "prompt"] as const;
|
|
30
|
-
type ThinkingLevel = typeof THINKING_LEVELS[number];
|
|
31
32
|
const PROMPT_VIEWPORT_HEIGHT = 16;
|
|
32
33
|
const MODEL_SELECTOR_HEIGHT = 10;
|
|
33
34
|
const SKILL_SELECTOR_HEIGHT = 10;
|
|
@@ -86,8 +87,8 @@ export function createEditState(draft: AgentConfig, isNew: boolean, models: Mode
|
|
|
86
87
|
return {
|
|
87
88
|
draft: { ...draft, tools: draft.tools ? [...draft.tools] : undefined, mcpDirectTools: draft.mcpDirectTools ? [...draft.mcpDirectTools] : undefined, skills: draft.skills ? [...draft.skills] : undefined, fallbackModels: draft.fallbackModels ? [...draft.fallbackModels] : undefined, extensions: draft.extensions ? [...draft.extensions] : draft.extensions, defaultReads: draft.defaultReads ? [...draft.defaultReads] : undefined, extraFields: draft.extraFields ? { ...draft.extraFields } : undefined },
|
|
88
89
|
isNew, fieldIndex: 0, fieldMode: null, fieldEditor: createEditorState(), promptEditor: createEditorState(draft.systemPrompt ?? ""),
|
|
89
|
-
modelSearchQuery: "", modelCursor: 0, filteredModels: [...models], thinkingCursor: 0, skillSearchQuery: "", skillCursor: 0, filteredSkills: [...skills], skillSelected: new Set(draft.skills ?? []),
|
|
90
|
-
fields: options.fields ?? [...FIELD_ORDER], title: options.title, overrideBase: options.overrideBase,
|
|
90
|
+
modelSearchQuery: "", modelCursor: 0, models: [...models], filteredModels: [...models], thinkingCursor: 0, skillSearchQuery: "", skillCursor: 0, filteredSkills: [...skills], skillSelected: new Set(draft.skills ?? []),
|
|
91
|
+
fields: options.fields ?? [...FIELD_ORDER], title: options.title, overrideBase: options.overrideBase, preferredProvider: options.preferredProvider,
|
|
91
92
|
};
|
|
92
93
|
}
|
|
93
94
|
|
|
@@ -180,9 +181,16 @@ function openModelPicker(state: EditState, models: ModelInfo[]): void {
|
|
|
180
181
|
state.fieldIndex = state.fields.indexOf("model"); state.fieldMode = "model"; state.modelSearchQuery = ""; state.filteredModels = [...models];
|
|
181
182
|
const idx = state.filteredModels.findIndex((m) => m.fullId === state.draft.model || m.id === state.draft.model); state.modelCursor = idx >= 0 ? idx : 0;
|
|
182
183
|
}
|
|
184
|
+
function getDraftThinkingLevels(state: EditState): ThinkingLevel[] {
|
|
185
|
+
return getSupportedThinkingLevels(findModelInfo(state.draft.model, state.models, state.preferredProvider));
|
|
186
|
+
}
|
|
187
|
+
|
|
183
188
|
function openThinkingPicker(state: EditState): void {
|
|
184
189
|
state.fieldIndex = state.fields.indexOf("thinking"); state.fieldMode = "thinking";
|
|
185
|
-
const
|
|
190
|
+
const levels = getDraftThinkingLevels(state);
|
|
191
|
+
const currentLevel = state.draft.thinking ?? "off";
|
|
192
|
+
const idx = levels.findIndex((level) => level === currentLevel);
|
|
193
|
+
state.thinkingCursor = idx >= 0 ? idx : Math.max(0, levels.indexOf("off"));
|
|
186
194
|
}
|
|
187
195
|
function openSkillPicker(state: EditState, skills: SkillInfo[]): void {
|
|
188
196
|
state.fieldIndex = state.fields.indexOf("skills"); state.fieldMode = "skills"; state.skillSearchQuery = ""; state.filteredSkills = [...skills]; state.skillSelected = new Set(state.draft.skills ?? []); state.skillCursor = 0;
|
|
@@ -230,16 +238,22 @@ function renderThinkingPicker(state: EditState, width: number, theme: Theme): st
|
|
|
230
238
|
high: "Deep reasoning",
|
|
231
239
|
xhigh: "Maximum reasoning (ultrathink)",
|
|
232
240
|
};
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
241
|
+
const levels = getDraftThinkingLevels(state);
|
|
242
|
+
if (levels.length === 0) {
|
|
243
|
+
lines.push(row(` ${theme.fg("dim", "No supported thinking levels")}`, width, theme));
|
|
244
|
+
} else {
|
|
245
|
+
for (let i = 0; i < levels.length; i++) {
|
|
246
|
+
const level = levels[i]!;
|
|
247
|
+
const isSelected = i === state.thinkingCursor;
|
|
248
|
+
const prefix = isSelected ? theme.fg("accent", "→ ") : " ";
|
|
249
|
+
const levelText = isSelected ? theme.fg("accent", level) : level;
|
|
250
|
+
const desc = theme.fg("dim", ` - ${descriptions[level]}`);
|
|
251
|
+
lines.push(row(` ${prefix}${levelText}${desc}`, width, theme));
|
|
252
|
+
}
|
|
240
253
|
}
|
|
241
254
|
while (lines.length < 19) lines.push(row("", width, theme));
|
|
242
|
-
|
|
255
|
+
const footer = levels.length === 0 ? " [esc] cancel " : " [enter] select [esc] cancel [↑↓] navigate ";
|
|
256
|
+
lines.push(renderFooter(footer, width, theme));
|
|
243
257
|
return lines;
|
|
244
258
|
}
|
|
245
259
|
|
|
@@ -323,7 +337,15 @@ export function handleEditInput(screen: EditScreen, state: EditState, data: stri
|
|
|
323
337
|
if (screen === "edit-field") {
|
|
324
338
|
if (state.fieldMode === "model") {
|
|
325
339
|
if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) { state.fieldMode = null; return { nextScreen: "edit" }; }
|
|
326
|
-
if (matchesKey(data, "return")) {
|
|
340
|
+
if (matchesKey(data, "return")) {
|
|
341
|
+
const selected = state.filteredModels[state.modelCursor];
|
|
342
|
+
if (selected) {
|
|
343
|
+
state.draft.model = selected.fullId;
|
|
344
|
+
if (state.draft.thinking && !getDraftThinkingLevels(state).some((level) => level === state.draft.thinking)) state.draft.thinking = undefined;
|
|
345
|
+
}
|
|
346
|
+
state.fieldMode = null;
|
|
347
|
+
return { nextScreen: "edit" };
|
|
348
|
+
}
|
|
327
349
|
if (matchesKey(data, "up")) { if (state.filteredModels.length > 0) state.modelCursor = state.modelCursor === 0 ? state.filteredModels.length - 1 : state.modelCursor - 1; return; }
|
|
328
350
|
if (matchesKey(data, "down")) { if (state.filteredModels.length > 0) state.modelCursor = state.modelCursor === state.filteredModels.length - 1 ? 0 : state.modelCursor + 1; return; }
|
|
329
351
|
if (matchesKey(data, "backspace")) { if (state.modelSearchQuery.length > 0) state.modelSearchQuery = state.modelSearchQuery.slice(0, -1); }
|
|
@@ -334,10 +356,12 @@ export function handleEditInput(screen: EditScreen, state: EditState, data: stri
|
|
|
334
356
|
return;
|
|
335
357
|
}
|
|
336
358
|
if (state.fieldMode === "thinking") {
|
|
359
|
+
const levels = getDraftThinkingLevels(state);
|
|
337
360
|
if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) { state.fieldMode = null; return { nextScreen: "edit" }; }
|
|
338
|
-
if (
|
|
339
|
-
if (matchesKey(data, "
|
|
340
|
-
if (matchesKey(data, "
|
|
361
|
+
if (levels.length === 0) return;
|
|
362
|
+
if (matchesKey(data, "return")) { const selected = levels[state.thinkingCursor] ?? "off"; state.draft.thinking = selected === "off" ? undefined : selected; state.fieldMode = null; return { nextScreen: "edit" }; }
|
|
363
|
+
if (matchesKey(data, "up")) { state.thinkingCursor = state.thinkingCursor === 0 ? levels.length - 1 : state.thinkingCursor - 1; return; }
|
|
364
|
+
if (matchesKey(data, "down")) { state.thinkingCursor = state.thinkingCursor === levels.length - 1 ? 0 : state.thinkingCursor + 1; return; }
|
|
341
365
|
return;
|
|
342
366
|
}
|
|
343
367
|
if (state.fieldMode === "skills") {
|
|
@@ -45,7 +45,7 @@ interface ChainEntry { id: string; kind: "chain"; config: ChainConfig; }
|
|
|
45
45
|
interface NameInputState { mode: "new-agent" | "clone-agent" | "clone-chain" | "new-chain"; editor: TextEditorState; scope: "user" | "project"; allowProject: boolean; sourceId?: string; template?: AgentTemplate; error?: string; }
|
|
46
46
|
interface StatusMessage { text: string; type: "error" | "info"; }
|
|
47
47
|
interface OverrideScopeState { selectedScope: "user" | "project"; allowProject: boolean; }
|
|
48
|
-
export interface AgentManagerOptions { newShortcut?: string; }
|
|
48
|
+
export interface AgentManagerOptions { newShortcut?: string; preferredModelProvider?: string; }
|
|
49
49
|
|
|
50
50
|
const BUILTIN_OVERRIDE_FIELDS: EditField[] = ["model", "fallbackModels", "thinking", "systemPromptMode", "inheritProjectContext", "inheritSkills", "defaultContext", "disabled", "tools", "skills", "prompt"];
|
|
51
51
|
|
|
@@ -135,6 +135,7 @@ export class AgentManagerComponent implements Component {
|
|
|
135
135
|
private skills: SkillInfo[];
|
|
136
136
|
private done: (result: ManagerResult) => void;
|
|
137
137
|
private shortcuts: ListShortcuts;
|
|
138
|
+
private preferredModelProvider: string | undefined;
|
|
138
139
|
|
|
139
140
|
constructor(tui: TUI, theme: Theme, agentData: AgentData, models: ModelInfo[], skills: SkillInfo[], done: (result: ManagerResult) => void, options: AgentManagerOptions = {}) {
|
|
140
141
|
this.tui = tui;
|
|
@@ -144,6 +145,7 @@ export class AgentManagerComponent implements Component {
|
|
|
144
145
|
this.skills = skills;
|
|
145
146
|
this.done = done;
|
|
146
147
|
this.shortcuts = { newShortcut: options.newShortcut?.trim() || DEFAULT_AGENT_MANAGER_NEW_SHORTCUT };
|
|
148
|
+
this.preferredModelProvider = options.preferredModelProvider;
|
|
147
149
|
this.loadEntries();
|
|
148
150
|
}
|
|
149
151
|
|
|
@@ -196,7 +198,7 @@ export class AgentManagerComponent implements Component {
|
|
|
196
198
|
|
|
197
199
|
private enterDetail(entry: AgentEntry): void { this.currentAgentId = entry.id; this.detailState = { resolved: true, scrollOffset: 0, recentRuns: loadRunsForAgent(entry.config.name).slice(0, 5) }; this.screen = "detail"; }
|
|
198
200
|
private enterChainDetail(entry: ChainEntry): void { this.currentChainId = entry.id; this.chainDetailState = { scrollOffset: 0 }; this.screen = "chain-detail"; }
|
|
199
|
-
private enterEdit(entry: AgentEntry): void { this.currentAgentId = entry.id; this.builtinOverrideScope = null; this.editState = createEditState(entry.config, entry.isNew, this.models, this.skills); this.screen = "edit"; }
|
|
201
|
+
private enterEdit(entry: AgentEntry): void { this.currentAgentId = entry.id; this.builtinOverrideScope = null; this.editState = createEditState(entry.config, entry.isNew, this.models, this.skills, { preferredProvider: this.preferredModelProvider }); this.screen = "edit"; }
|
|
200
202
|
private enterBuiltinOverrideScope(entry: AgentEntry): void {
|
|
201
203
|
this.currentAgentId = entry.id;
|
|
202
204
|
this.overrideScopeState = { selectedScope: this.agentData.projectSettingsPath ? "project" : "user", allowProject: Boolean(this.agentData.projectSettingsPath) };
|
|
@@ -209,6 +211,7 @@ export class AgentManagerComponent implements Component {
|
|
|
209
211
|
fields: BUILTIN_OVERRIDE_FIELDS,
|
|
210
212
|
title: `Builtin Override: ${entry.config.name} [${scope}]`,
|
|
211
213
|
overrideBase: this.resolveBuiltinOverrideBase(entry),
|
|
214
|
+
preferredProvider: this.preferredModelProvider,
|
|
212
215
|
});
|
|
213
216
|
this.screen = "edit";
|
|
214
217
|
}
|
|
@@ -538,6 +538,7 @@ interface SingleStepContext {
|
|
|
538
538
|
piArgv1?: string;
|
|
539
539
|
registerInterrupt?: (interrupt: (() => void) | undefined) => void;
|
|
540
540
|
childIntercomTarget?: string;
|
|
541
|
+
orchestratorIntercomTarget?: string;
|
|
541
542
|
onChildEvent?: (event: ChildEvent) => void;
|
|
542
543
|
}
|
|
543
544
|
|
|
@@ -604,6 +605,10 @@ async function runSingleStep(
|
|
|
604
605
|
mcpDirectTools: step.mcpDirectTools,
|
|
605
606
|
promptFileStem: step.agent,
|
|
606
607
|
intercomSessionName: ctx.childIntercomTarget,
|
|
608
|
+
orchestratorIntercomTarget: ctx.orchestratorIntercomTarget,
|
|
609
|
+
runId: ctx.id,
|
|
610
|
+
childAgentName: step.agent,
|
|
611
|
+
childIndex: ctx.flatIndex,
|
|
607
612
|
});
|
|
608
613
|
const run = await runPiStreaming(
|
|
609
614
|
args,
|
|
@@ -1299,6 +1304,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1299
1304
|
piPackageRoot: config.piPackageRoot,
|
|
1300
1305
|
piArgv1: config.piArgv1,
|
|
1301
1306
|
childIntercomTarget: config.childIntercomTargets?.[fi],
|
|
1307
|
+
orchestratorIntercomTarget: config.controlIntercomTarget,
|
|
1302
1308
|
registerInterrupt: (interrupt) => {
|
|
1303
1309
|
activeChildInterrupt = interrupt;
|
|
1304
1310
|
},
|
|
@@ -1439,6 +1445,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1439
1445
|
piPackageRoot: config.piPackageRoot,
|
|
1440
1446
|
piArgv1: config.piArgv1,
|
|
1441
1447
|
childIntercomTarget: config.childIntercomTargets?.[flatIndex],
|
|
1448
|
+
orchestratorIntercomTarget: config.controlIntercomTarget,
|
|
1442
1449
|
registerInterrupt: (interrupt) => {
|
|
1443
1450
|
activeChildInterrupt = interrupt;
|
|
1444
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";
|
|
@@ -358,11 +359,7 @@ async function resumeAsyncRun(input: {
|
|
|
358
359
|
|
|
359
360
|
const runId = randomUUID().slice(0, 8);
|
|
360
361
|
const artifactConfig: ArtifactConfig = { ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts !== false };
|
|
361
|
-
const availableModels = input.ctx.modelRegistry.getAvailable().map(
|
|
362
|
-
provider: m.provider,
|
|
363
|
-
id: m.id,
|
|
364
|
-
fullId: `${m.provider}/${m.id}`,
|
|
365
|
-
}));
|
|
362
|
+
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
366
363
|
const result = executeAsyncSingle(runId, {
|
|
367
364
|
agent: target.agent,
|
|
368
365
|
task: buildRevivedAsyncTask(target, followUp),
|
|
@@ -782,11 +779,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
782
779
|
currentSessionId: deps.state.currentSessionId!,
|
|
783
780
|
currentModelProvider: ctx.model?.provider,
|
|
784
781
|
};
|
|
785
|
-
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(
|
|
786
|
-
provider: m.provider,
|
|
787
|
-
id: m.id,
|
|
788
|
-
fullId: `${m.provider}/${m.id}`,
|
|
789
|
-
}));
|
|
782
|
+
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
790
783
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
|
|
791
784
|
const currentProvider = ctx.model?.provider;
|
|
792
785
|
const controlIntercomTarget = intercomBridge.active ? intercomBridge.orchestratorTarget : undefined;
|
|
@@ -951,6 +944,7 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
951
944
|
onControlEvent,
|
|
952
945
|
controlConfig,
|
|
953
946
|
childIntercomTarget: childIntercomTarget ? (agent, index) => childIntercomTarget(runId, agent, index) : undefined,
|
|
947
|
+
orchestratorIntercomTarget: data.intercomBridge.active ? data.intercomBridge.orchestratorTarget : undefined,
|
|
954
948
|
foregroundControl,
|
|
955
949
|
chainSkills,
|
|
956
950
|
chainDir: params.chainDir,
|
|
@@ -979,11 +973,7 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
979
973
|
chain: asyncChain,
|
|
980
974
|
agents,
|
|
981
975
|
ctx: asyncCtx,
|
|
982
|
-
availableModels: ctx.modelRegistry.getAvailable().map(
|
|
983
|
-
provider: m.provider,
|
|
984
|
-
id: m.id,
|
|
985
|
-
fullId: `${m.provider}/${m.id}`,
|
|
986
|
-
})),
|
|
976
|
+
availableModels: ctx.modelRegistry.getAvailable().map(toModelInfo),
|
|
987
977
|
cwd: effectiveCwd,
|
|
988
978
|
maxOutput: params.maxOutput,
|
|
989
979
|
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
@@ -1045,6 +1035,7 @@ interface ForegroundParallelRunInput {
|
|
|
1045
1035
|
controlConfig: ResolvedControlConfig;
|
|
1046
1036
|
onControlEvent?: (event: ControlEvent) => void;
|
|
1047
1037
|
childIntercomTarget?: (agent: string, index: number) => string | undefined;
|
|
1038
|
+
orchestratorIntercomTarget?: string;
|
|
1048
1039
|
foregroundControl?: SubagentState["foregroundControls"] extends Map<string, infer T> ? T : never;
|
|
1049
1040
|
concurrencyLimit: number;
|
|
1050
1041
|
liveResults: (SingleResult | undefined)[];
|
|
@@ -1203,6 +1194,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
1203
1194
|
controlConfig: input.controlConfig,
|
|
1204
1195
|
onControlEvent: input.onControlEvent,
|
|
1205
1196
|
intercomSessionName: input.childIntercomTarget?.(task.agent, index),
|
|
1197
|
+
orchestratorIntercomTarget: input.orchestratorIntercomTarget,
|
|
1206
1198
|
modelOverride: input.modelOverrides[index],
|
|
1207
1199
|
availableModels: input.availableModels,
|
|
1208
1200
|
preferredModelProvider: input.ctx.model?.provider,
|
|
@@ -1307,11 +1299,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1307
1299
|
}
|
|
1308
1300
|
|
|
1309
1301
|
const currentProvider = ctx.model?.provider;
|
|
1310
|
-
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(
|
|
1311
|
-
provider: m.provider,
|
|
1312
|
-
id: m.id,
|
|
1313
|
-
fullId: `${m.provider}/${m.id}`,
|
|
1314
|
-
}));
|
|
1302
|
+
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
1315
1303
|
let taskTexts = tasks.map((t) => t.task);
|
|
1316
1304
|
const skillOverrides: (string[] | false | undefined)[] = tasks.map((t) =>
|
|
1317
1305
|
normalizeSkillInput(t.skill),
|
|
@@ -1484,6 +1472,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1484
1472
|
controlConfig,
|
|
1485
1473
|
onControlEvent,
|
|
1486
1474
|
childIntercomTarget: childIntercomTarget ? (agent, index) => childIntercomTarget(runId, agent, index) : undefined,
|
|
1475
|
+
orchestratorIntercomTarget: data.intercomBridge.active ? data.intercomBridge.orchestratorTarget : undefined,
|
|
1487
1476
|
foregroundControl,
|
|
1488
1477
|
concurrencyLimit: parallelConcurrency,
|
|
1489
1478
|
maxSubagentDepths,
|
|
@@ -1588,11 +1577,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1588
1577
|
}
|
|
1589
1578
|
|
|
1590
1579
|
const currentProvider = ctx.model?.provider;
|
|
1591
|
-
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(
|
|
1592
|
-
provider: m.provider,
|
|
1593
|
-
id: m.id,
|
|
1594
|
-
fullId: `${m.provider}/${m.id}`,
|
|
1595
|
-
}));
|
|
1580
|
+
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
1596
1581
|
let task = params.task ?? "";
|
|
1597
1582
|
let modelOverride: string | undefined = resolveModelCandidate(
|
|
1598
1583
|
(params.model as string | undefined) ?? agentConfig.model,
|
|
@@ -1753,6 +1738,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1753
1738
|
controlConfig,
|
|
1754
1739
|
onControlEvent,
|
|
1755
1740
|
intercomSessionName: childIntercomTarget,
|
|
1741
|
+
orchestratorIntercomTarget: data.intercomBridge.active ? data.intercomBridge.orchestratorTarget : undefined,
|
|
1756
1742
|
index: 0,
|
|
1757
1743
|
modelOverride,
|
|
1758
1744
|
availableModels,
|
|
@@ -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 {
|