@ryan_nookpi/pi-extension-subagent 0.4.1 → 0.4.3
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/commands.ts +8 -1
- package/package.json +1 -1
- package/tool-render.ts +56 -20
package/commands.ts
CHANGED
|
@@ -63,7 +63,12 @@ import { buildMainContextText, makeSubagentSessionFile, wrapTaskWithMainContext
|
|
|
63
63
|
import { formatStarterPackNotice, offerStarterPackIfEmpty } from "./starter-pack.js";
|
|
64
64
|
import { type SubagentStore, truncateText, updateRunFromResult } from "./store.js";
|
|
65
65
|
import { createSubagentToolExecute } from "./tool-execute.js";
|
|
66
|
-
import {
|
|
66
|
+
import {
|
|
67
|
+
renderListAgentsCall,
|
|
68
|
+
renderListAgentsResult,
|
|
69
|
+
renderSubagentToolCall,
|
|
70
|
+
renderSubagentToolResult,
|
|
71
|
+
} from "./tool-render.js";
|
|
67
72
|
import type { CommandRunState, SingleResult, SubagentDetails } from "./types.js";
|
|
68
73
|
import { ListAgentsParams, SubagentParams } from "./types.js";
|
|
69
74
|
import { updateCommandRunsWidget, type WidgetRenderCtx } from "./widget.js";
|
|
@@ -927,6 +932,8 @@ export function registerAll(pi: ExtensionAPI, store: SubagentStore): SubagentReg
|
|
|
927
932
|
description:
|
|
928
933
|
"List available subagent definitions (name, source, model, thinking, tools, description). Useful before planning delegation.",
|
|
929
934
|
parameters: ListAgentsParams,
|
|
935
|
+
renderCall: renderListAgentsCall,
|
|
936
|
+
renderResult: renderListAgentsResult,
|
|
930
937
|
execute: async (_toolCallId, _params: Record<string, any>, _signal, _onUpdate, ctx) => {
|
|
931
938
|
const starterPack = await offerStarterPackIfEmpty(ctx);
|
|
932
939
|
const discovery = starterPack.discovery;
|
package/package.json
CHANGED
package/tool-render.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { getMarkdownTheme, type ThemeColor } from "@earendil-works/pi-coding-agent";
|
|
8
8
|
import { Container, Markdown, Spacer, Text, visibleWidth } from "@earendil-works/pi-tui";
|
|
9
9
|
import { parseSubagentToolCommand } from "./cli.js";
|
|
10
|
+
import { SUBAGENT_STRONG_WAIT_MESSAGE } from "./constants.js";
|
|
10
11
|
import { formatToolCall, formatUsageStats } from "./format.js";
|
|
11
12
|
import { getDisplayItems, getFinalOutput } from "./runner.js";
|
|
12
13
|
import { COLLAPSED_ITEM_COUNT, truncateText } from "./store.js";
|
|
@@ -27,10 +28,12 @@ type ToolRenderResult = {
|
|
|
27
28
|
type ToolRenderArgs = { command?: unknown };
|
|
28
29
|
type ToolCallRenderContext = { expanded: boolean };
|
|
29
30
|
type CompactBlock = { agent: string; task: string };
|
|
31
|
+
type ListAgentsDetails = { agents?: Array<{ name?: unknown }> };
|
|
30
32
|
|
|
31
33
|
const COMPACT_TASK_PREVIEW_WIDTH = 72;
|
|
32
34
|
const COMPACT_AGENT_WIDTH = 20;
|
|
33
35
|
const COMPACT_MAX_ITEMS = 3;
|
|
36
|
+
const COMPACT_AGENT_LIST_COUNT = 3;
|
|
34
37
|
|
|
35
38
|
function normalizeTaskPreview(task: string): string {
|
|
36
39
|
return truncateText(task.replace(/\s+/g, " ").trim(), COMPACT_TASK_PREVIEW_WIDTH);
|
|
@@ -110,6 +113,25 @@ function renderCompactLaunch(command: unknown): string | null {
|
|
|
110
113
|
return ` run · ${params.agent} · ${contextLabel}\n ${task}`;
|
|
111
114
|
}
|
|
112
115
|
|
|
116
|
+
function getToolResultText(result: ToolRenderResult): string {
|
|
117
|
+
const raw = result.content[0];
|
|
118
|
+
return (raw?.type === "text" ? raw.text : undefined) ?? "(no output)";
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function renderPlainToolResult(fullText: string, expanded: boolean, theme: RenderTheme): Text {
|
|
122
|
+
if (expanded) return new Text(fullText, 0, 0);
|
|
123
|
+
|
|
124
|
+
const waitMessageIndex = fullText.indexOf(SUBAGENT_STRONG_WAIT_MESSAGE);
|
|
125
|
+
if (waitMessageIndex >= 0) {
|
|
126
|
+
return new Text(fullText.slice(0, waitMessageIndex).trimEnd(), 0, 0);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const firstLine = fullText.split("\n")[0] ?? "";
|
|
130
|
+
const lineCount = fullText.split("\n").length;
|
|
131
|
+
const suffix = lineCount > 1 ? theme.fg("muted", ` (+${lineCount - 1} lines)`) : "";
|
|
132
|
+
return new Text(firstLine + suffix, 0, 0);
|
|
133
|
+
}
|
|
134
|
+
|
|
113
135
|
function renderDisplayItems(items: DisplayItem[], expanded: boolean, theme: RenderTheme, limit?: number): string {
|
|
114
136
|
const toShow = limit ? items.slice(-limit) : items;
|
|
115
137
|
const skipped = limit && items.length > limit ? items.length - limit : 0;
|
|
@@ -128,6 +150,38 @@ function renderDisplayItems(items: DisplayItem[], expanded: boolean, theme: Rend
|
|
|
128
150
|
|
|
129
151
|
// ─── renderCall ──────────────────────────────────────────────────────────────
|
|
130
152
|
|
|
153
|
+
export function renderListAgentsCall(_args: unknown, theme: RenderTheme) {
|
|
154
|
+
return new Text(theme.fg("toolTitle", theme.bold("list-agents")), 0, 0);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function renderListAgentsResult(
|
|
158
|
+
result: ToolRenderResult,
|
|
159
|
+
{ expanded }: { expanded: boolean },
|
|
160
|
+
theme: RenderTheme,
|
|
161
|
+
) {
|
|
162
|
+
const fullText = getToolResultText(result);
|
|
163
|
+
if (expanded) return new Text(theme.fg("toolOutput", fullText), 0, 0);
|
|
164
|
+
|
|
165
|
+
const details = result.details as ListAgentsDetails | undefined;
|
|
166
|
+
const names = details?.agents
|
|
167
|
+
?.map((agent) => (typeof agent.name === "string" ? truncateText(agent.name, COMPACT_AGENT_WIDTH) : ""))
|
|
168
|
+
.filter(Boolean);
|
|
169
|
+
if (!names) return new Text(theme.fg("toolOutput", fullText.split("\n")[0] ?? fullText), 0, 0);
|
|
170
|
+
if (names.length === 0) return new Text(theme.fg("muted", "○ no agents"), 0, 0);
|
|
171
|
+
|
|
172
|
+
const visibleNames = names.slice(0, COMPACT_AGENT_LIST_COUNT);
|
|
173
|
+
const hiddenCount = names.length - visibleNames.length;
|
|
174
|
+
const hiddenSuffix = hiddenCount > 0 ? `, +${hiddenCount}` : "";
|
|
175
|
+
return new Text(
|
|
176
|
+
theme.fg(
|
|
177
|
+
"toolOutput",
|
|
178
|
+
`✓ ${names.length} agent${names.length === 1 ? "" : "s"} · ${visibleNames.join(", ")}${hiddenSuffix}`,
|
|
179
|
+
),
|
|
180
|
+
0,
|
|
181
|
+
0,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
131
185
|
export function renderSubagentToolCall(
|
|
132
186
|
args: ToolRenderArgs,
|
|
133
187
|
theme: RenderTheme,
|
|
@@ -161,30 +215,12 @@ export function renderSubagentToolResult(
|
|
|
161
215
|
) {
|
|
162
216
|
const details = result.details as SubagentDetails | undefined;
|
|
163
217
|
if (!details || details.results.length === 0) {
|
|
164
|
-
|
|
165
|
-
const fullText = (raw?.type === "text" ? raw.text : undefined) ?? "(no output)";
|
|
166
|
-
if (!expanded) {
|
|
167
|
-
const firstLine = fullText.split("\n")[0] ?? "";
|
|
168
|
-
const lineCount = fullText.split("\n").length;
|
|
169
|
-
const suffix = lineCount > 1 ? theme.fg("muted", ` (+${lineCount - 1} lines)`) : "";
|
|
170
|
-
return new Text(firstLine + suffix, 0, 0);
|
|
171
|
-
}
|
|
172
|
-
return new Text(fullText, 0, 0);
|
|
218
|
+
return renderPlainToolResult(getToolResultText(result), expanded, theme);
|
|
173
219
|
}
|
|
174
220
|
|
|
175
221
|
const mdTheme = getMarkdownTheme();
|
|
176
222
|
const r = details.results[0];
|
|
177
|
-
if (!r)
|
|
178
|
-
const raw2 = result.content[0];
|
|
179
|
-
const fullText2 = (raw2?.type === "text" ? raw2.text : undefined) ?? "(no output)";
|
|
180
|
-
if (!expanded) {
|
|
181
|
-
const firstLine = fullText2.split("\n")[0] ?? "";
|
|
182
|
-
const lineCount = fullText2.split("\n").length;
|
|
183
|
-
const suffix = lineCount > 1 ? theme.fg("muted", ` (+${lineCount - 1} lines)`) : "";
|
|
184
|
-
return new Text(firstLine + suffix, 0, 0);
|
|
185
|
-
}
|
|
186
|
-
return new Text(fullText2, 0, 0);
|
|
187
|
-
}
|
|
223
|
+
if (!r) return renderPlainToolResult(getToolResultText(result), expanded, theme);
|
|
188
224
|
|
|
189
225
|
const isError = r.exitCode !== 0 || r.stopReason === "error" || r.stopReason === "aborted";
|
|
190
226
|
const icon = isError ? theme.fg("error", "✗") : theme.fg("success", "✓");
|