pi-fast-subagent 0.9.0 → 0.9.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/README.md +1 -0
- package/index.ts +5 -1
- package/package.json +1 -1
- package/render.ts +111 -0
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ Runs subagents with `createAgentSession()` in same process instead of spawning `
|
|
|
14
14
|
- User + project agent discovery
|
|
15
15
|
- Project agents override user agents
|
|
16
16
|
- Max nesting depth guard
|
|
17
|
+
- Streamed prompt preview while the parent LLM is writing the subagent task
|
|
17
18
|
- Chronological expanded view (Ctrl+O): subagent tool calls and response text interleaved in execution order
|
|
18
19
|
- Collapsed view shows response + trailing tool calls as an indented tree
|
|
19
20
|
|
package/index.ts
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
summarizeTask,
|
|
27
27
|
} from "./format.js";
|
|
28
28
|
import { defaultLoaderPool } from "./loader-pool.js";
|
|
29
|
-
import { renderSubagentResult } from "./render.js";
|
|
29
|
+
import { renderSubagentCall, renderSubagentResult } from "./render.js";
|
|
30
30
|
import { getCurrentDepth, mapConcurrent, runAgent } from "./runner.js";
|
|
31
31
|
import { SubagentParams } from "./schemas.js";
|
|
32
32
|
import type { AgentRowStatus, OnUpdate, RunResult, SubagentDetails, ToolCallEntry } from "./types.js";
|
|
@@ -317,6 +317,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
317
317
|
].join(" "),
|
|
318
318
|
parameters: SubagentParams,
|
|
319
319
|
|
|
320
|
+
renderCall(args, theme, context) {
|
|
321
|
+
return renderSubagentCall(args, theme, context);
|
|
322
|
+
},
|
|
323
|
+
|
|
320
324
|
renderResult(result: AgentToolResult<unknown>, opts: ToolRenderResultOptions, theme: Theme) {
|
|
321
325
|
return renderSubagentResult(result, opts, theme);
|
|
322
326
|
},
|
package/package.json
CHANGED
package/render.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { join } from "node:path";
|
|
|
8
8
|
import { getAgentDir, Theme, truncateToVisualLines, keyHint } from "@mariozechner/pi-coding-agent";
|
|
9
9
|
import type { AgentToolResult, ToolRenderResultOptions } from "@mariozechner/pi-coding-agent";
|
|
10
10
|
import { truncateToWidth, wrapTextWithAnsi } from "@mariozechner/pi-tui";
|
|
11
|
+
import type { Component } from "@mariozechner/pi-tui";
|
|
11
12
|
|
|
12
13
|
import { formatDuration, formatUsage } from "./format.js";
|
|
13
14
|
import type { SubagentDetails, ToolCallEntry } from "./types.js";
|
|
@@ -73,6 +74,116 @@ function readPreviewSettings(): { previewLines: number; promptPreviewLines: numb
|
|
|
73
74
|
return _settingsCache;
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
interface SubagentCallArgs {
|
|
78
|
+
agent?: unknown;
|
|
79
|
+
task?: unknown;
|
|
80
|
+
tasks?: unknown;
|
|
81
|
+
action?: unknown;
|
|
82
|
+
background?: unknown;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface SubagentRenderCallContext {
|
|
86
|
+
state: Record<string, unknown>;
|
|
87
|
+
executionStarted: boolean;
|
|
88
|
+
argsComplete: boolean;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function asString(v: unknown): string | undefined {
|
|
92
|
+
return typeof v === "string" ? v : undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function taskPreviewLines(task: string, width: number, maxLines: number): { lines: string[]; skipped: number } {
|
|
96
|
+
const innerWidth = Math.max(1, width - 2);
|
|
97
|
+
const visual: string[] = [];
|
|
98
|
+
for (const raw of task.split("\n")) {
|
|
99
|
+
try {
|
|
100
|
+
for (const w of wrapTextWithAnsi(raw, innerWidth)) visual.push(w);
|
|
101
|
+
} catch {
|
|
102
|
+
visual.push(truncateToWidth(raw, innerWidth, "..."));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const lines = visual.slice(0, maxLines).map((line) => truncateToWidth(` ${line}`, width, "..."));
|
|
106
|
+
return { lines, skipped: Math.max(0, visual.length - lines.length) };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Render tool-call args while provider is still streaming them. This makes long
|
|
111
|
+
* subagent prompt generation visible before execute() can start.
|
|
112
|
+
*/
|
|
113
|
+
export function renderSubagentCall(
|
|
114
|
+
args: SubagentCallArgs,
|
|
115
|
+
theme: Theme,
|
|
116
|
+
context: SubagentRenderCallContext,
|
|
117
|
+
): Component {
|
|
118
|
+
const cache = context.state as {
|
|
119
|
+
callWidth?: number;
|
|
120
|
+
callLines?: string[];
|
|
121
|
+
callKey?: string;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
invalidate() {
|
|
126
|
+
cache.callWidth = undefined;
|
|
127
|
+
cache.callLines = undefined;
|
|
128
|
+
cache.callKey = undefined;
|
|
129
|
+
},
|
|
130
|
+
render(width: number): string[] {
|
|
131
|
+
const key = JSON.stringify({ args, executionStarted: context.executionStarted, argsComplete: context.argsComplete, width });
|
|
132
|
+
if (cache.callWidth === width && cache.callKey === key && cache.callLines) return cache.callLines;
|
|
133
|
+
|
|
134
|
+
const out: string[] = [];
|
|
135
|
+
const agent = asString(args.agent);
|
|
136
|
+
const action = asString(args.action);
|
|
137
|
+
const task = asString(args.task);
|
|
138
|
+
const tasks = Array.isArray(args.tasks) ? args.tasks as Array<Record<string, unknown>> : undefined;
|
|
139
|
+
const isParallel = !!tasks?.length;
|
|
140
|
+
const status = context.executionStarted
|
|
141
|
+
? "running"
|
|
142
|
+
: context.argsComplete
|
|
143
|
+
? "starting"
|
|
144
|
+
: task || isParallel
|
|
145
|
+
? "writing prompt"
|
|
146
|
+
: "waiting for prompt";
|
|
147
|
+
const mode = isParallel ? `Parallel (${tasks!.length})` : "Subagent";
|
|
148
|
+
const bg = args.background === true ? " · background" : "";
|
|
149
|
+
const target = agent ? ` ${agent}` : action ? ` ${action}` : "";
|
|
150
|
+
out.push(truncateToWidth(`${theme.fg("toolTitle", mode)}${target}${bg} · ${theme.fg("dim", status)}`, width, "..."));
|
|
151
|
+
|
|
152
|
+
// Once execution starts, result renderer owns prompt display. Keep call row compact.
|
|
153
|
+
if (context.executionStarted) {
|
|
154
|
+
cache.callWidth = width;
|
|
155
|
+
cache.callKey = key;
|
|
156
|
+
cache.callLines = out;
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const maxLines = readPreviewSettings().promptPreviewLines;
|
|
161
|
+
if (task) {
|
|
162
|
+
out.push(truncateToWidth("Prompt:", width, "..."));
|
|
163
|
+
const preview = taskPreviewLines(task, width, maxLines);
|
|
164
|
+
out.push(...preview.lines);
|
|
165
|
+
if (preview.skipped > 0) out.push(truncateToWidth(theme.fg("muted", ` … (${preview.skipped} more lines)`), width, "..."));
|
|
166
|
+
} else if (tasks?.length) {
|
|
167
|
+
const maxRows = Math.max(1, Math.min(maxLines, tasks.length));
|
|
168
|
+
for (let i = 0; i < maxRows; i++) {
|
|
169
|
+
const t = tasks[i]!;
|
|
170
|
+
const rowAgent = asString(t.agent) ?? "?";
|
|
171
|
+
const rowTask = asString(t.task) ?? "";
|
|
172
|
+
out.push(truncateToWidth(` [${rowAgent}] ${rowTask || theme.fg("dim", "writing prompt...")}`, width, "..."));
|
|
173
|
+
}
|
|
174
|
+
if (tasks.length > maxRows) out.push(truncateToWidth(theme.fg("muted", ` … (${tasks.length - maxRows} more task${tasks.length - maxRows === 1 ? "" : "s"})`), width, "..."));
|
|
175
|
+
} else {
|
|
176
|
+
out.push(truncateToWidth(theme.fg("dim", " waiting for streamed tool arguments..."), width, "..."));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
cache.callWidth = width;
|
|
180
|
+
cache.callKey = key;
|
|
181
|
+
cache.callLines = out;
|
|
182
|
+
return out;
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
76
187
|
export function renderSubagentResult(
|
|
77
188
|
result: AgentToolResult<unknown>,
|
|
78
189
|
{ isPartial, expanded }: ToolRenderResultOptions,
|