@pi-archimedes/subagent 2.2.0 → 2.4.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/package.json +6 -2
- package/src/agent-manager.ts +12 -1676
- package/src/agent-panel.ts +1442 -0
- package/src/agent-store.ts +309 -0
- package/src/compact.test.ts +19 -8
- package/src/compact.ts +141 -161
- package/src/expanded.ts +16 -26
- package/src/index.ts +8 -38
- package/src/stream.test.ts +267 -3
- package/src/stream.ts +35 -8
- package/src/tool-schema.ts +33 -0
package/src/compact.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Text } from "@earendil-works/pi-tui";
|
|
2
2
|
import type { SubagentDetails, SubagentProgress, SubagentResult, SubagentToolCall, SubagentToolResult } from "./types.js";
|
|
3
|
-
import {
|
|
3
|
+
import { formatDuration, truncLine, buildStatsLine, buildAgentLabel } from "./format.js";
|
|
4
|
+
import { renderToolCallLine } from "@pi-archimedes/core/tool-render";
|
|
4
5
|
|
|
5
6
|
type Theme = { fg: (token: string, text: string) => string; bold: (text: string) => string };
|
|
6
7
|
type RenderContext = { state: Record<string, unknown>; invalidate: () => void };
|
|
@@ -35,52 +36,43 @@ export function buildActivityLine(
|
|
|
35
36
|
return theme.fg("error", "✗ Failed");
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
// Running: show the current tool with
|
|
39
|
+
// Running: show the current tool with the running glyph ▸ + live duration.
|
|
39
40
|
if (data.currentTool) {
|
|
40
|
-
const arrow = theme.fg("muted", "↳ ");
|
|
41
41
|
const argsPreview = data.currentToolArgs
|
|
42
42
|
? truncLine(data.currentToolArgs, 60)
|
|
43
43
|
: "";
|
|
44
44
|
const durationPart = data.currentToolStartedAt
|
|
45
45
|
? " | " + formatDuration(Date.now() - data.currentToolStartedAt)
|
|
46
46
|
: "";
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
line += theme.fg("dim", ": " + argsPreview);
|
|
50
|
-
}
|
|
51
|
-
if (durationPart) {
|
|
52
|
-
line += theme.fg("dim", durationPart);
|
|
53
|
-
}
|
|
54
|
-
return arrow + line;
|
|
47
|
+
const suffix = (argsPreview ? ": " + argsPreview : "") + durationPart;
|
|
48
|
+
return renderToolCallLine("running", data.currentTool, suffix, theme);
|
|
55
49
|
}
|
|
56
50
|
|
|
57
|
-
// Running, no active tool: show the most recently completed tool call
|
|
58
|
-
//
|
|
51
|
+
// Running, no active tool: show the most recently completed tool call with
|
|
52
|
+
// its status glyph (✓ ok / ✗ error) and matching name colour.
|
|
59
53
|
if (data.toolCalls && data.toolCalls.length > 0) {
|
|
60
54
|
const lastCall = data.toolCalls[data.toolCalls.length - 1];
|
|
61
55
|
if (lastCall) {
|
|
62
56
|
if (typeof lastCall === "string") {
|
|
63
|
-
return
|
|
57
|
+
return renderToolCallLine("success", truncLine(lastCall, 60), "", theme);
|
|
64
58
|
}
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
const argsPart = lastCall.argsPreview
|
|
69
|
-
? theme.fg("dim", ": " + truncLine(lastCall.argsPreview, 60))
|
|
59
|
+
const status = lastCall.error ? "error" : "success";
|
|
60
|
+
const suffix = lastCall.argsPreview
|
|
61
|
+
? ": " + truncLine(lastCall.argsPreview, 60)
|
|
70
62
|
: "";
|
|
71
|
-
return
|
|
63
|
+
return renderToolCallLine(status, lastCall.name, suffix, theme);
|
|
72
64
|
}
|
|
73
65
|
}
|
|
74
66
|
|
|
75
|
-
// Running, no tool history: show first line of streamed output
|
|
67
|
+
// Running, no tool history: show first line of streamed output (▸, muted).
|
|
76
68
|
if (data.finalOutput) {
|
|
77
69
|
const firstLine = data.finalOutput.split("\n")[0] ?? "";
|
|
78
|
-
return
|
|
70
|
+
return renderToolCallLine("running", truncLine(firstLine, 80), "", theme);
|
|
79
71
|
}
|
|
80
72
|
|
|
81
73
|
// Running, no info yet
|
|
82
74
|
if (data.status === "running") {
|
|
83
|
-
return
|
|
75
|
+
return renderToolCallLine("running", "Starting...", "", theme);
|
|
84
76
|
}
|
|
85
77
|
|
|
86
78
|
return "";
|
|
@@ -88,13 +80,37 @@ export function buildActivityLine(
|
|
|
88
80
|
|
|
89
81
|
// ── Status glyph ────────────────────────────────────────────────────────────
|
|
90
82
|
|
|
91
|
-
function statusGlyph(isRunning: boolean, status: string): string {
|
|
92
|
-
if (isRunning) return "↳";
|
|
93
|
-
return status === "completed" ? "✓" : "✗";
|
|
94
|
-
}
|
|
95
83
|
|
|
96
84
|
// ── Compact single agent ────────────────────────────────────────────────────
|
|
97
85
|
|
|
86
|
+
type AgentBlockData = {
|
|
87
|
+
agentName: string;
|
|
88
|
+
task: string | undefined;
|
|
89
|
+
model: string | undefined;
|
|
90
|
+
statsData: Parameters<typeof buildStatsLine>[0];
|
|
91
|
+
activity: ActivityData;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Shared 3-line agent block used by both the single and parallel compact
|
|
95
|
+
// views so they render identically:
|
|
96
|
+
// <agent>: <task>
|
|
97
|
+
// <model> · <stats>
|
|
98
|
+
// <activity> (status lives here — "✓ Done" / "✗ Failed" / ▸ tool)
|
|
99
|
+
function buildAgentBlock(data: AgentBlockData, theme: Theme): string {
|
|
100
|
+
const statsLine = buildStatsLine(data.statsData, theme);
|
|
101
|
+
const modelLabel = data.model ? theme.fg("accent", data.model) : "";
|
|
102
|
+
const activityLine = buildActivityLine(data.activity, theme);
|
|
103
|
+
const label = buildAgentLabel(data.agentName, data.task, theme);
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
label +
|
|
107
|
+
"\n" +
|
|
108
|
+
[modelLabel, statsLine].filter(Boolean).join(" ") +
|
|
109
|
+
"\n" +
|
|
110
|
+
activityLine
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
98
114
|
export function renderCompactSingle(
|
|
99
115
|
text: Text,
|
|
100
116
|
result: SubagentResult,
|
|
@@ -119,36 +135,30 @@ export function renderCompactSingle(
|
|
|
119
135
|
? Date.now() - (context.state[timeKey] as number)
|
|
120
136
|
: summary.durationMs;
|
|
121
137
|
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
? theme.fg("accent", modelName)
|
|
147
|
-
: "";
|
|
148
|
-
const expandHint = theme.fg("muted", "(ctrl+o)");
|
|
149
|
-
const agentLabel = buildAgentLabel(agentName, result.task, theme);
|
|
150
|
-
let output = agentLabel + "\n" + [modelLabel, statsPart, expandHint].filter(Boolean).join(" ");
|
|
151
|
-
output += "\n" + activityLine;
|
|
138
|
+
const output = buildAgentBlock(
|
|
139
|
+
{
|
|
140
|
+
agentName,
|
|
141
|
+
task: result.task,
|
|
142
|
+
model: progress?.model ?? result.model,
|
|
143
|
+
statsData: {
|
|
144
|
+
turns: result.usage.turns ?? 0,
|
|
145
|
+
toolCount: summary.toolCount,
|
|
146
|
+
tokens: summary.tokens,
|
|
147
|
+
durationMs: liveDuration,
|
|
148
|
+
cost: result.usage.cost ?? 0,
|
|
149
|
+
},
|
|
150
|
+
activity: {
|
|
151
|
+
currentTool: progress?.currentTool,
|
|
152
|
+
currentToolArgs: progress?.currentToolArgs,
|
|
153
|
+
currentToolStartedAt: progress?.currentToolStartedAt,
|
|
154
|
+
finalOutput: result.finalOutput,
|
|
155
|
+
status: isRunning ? "running" : status,
|
|
156
|
+
error: result.error,
|
|
157
|
+
toolCalls: progress?.toolCalls,
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
theme,
|
|
161
|
+
);
|
|
152
162
|
|
|
153
163
|
text.setText(output);
|
|
154
164
|
return text;
|
|
@@ -175,39 +185,30 @@ export function renderCompactParallel(
|
|
|
175
185
|
? "running"
|
|
176
186
|
: result.exitCode === 0 ? "completed" : "failed";
|
|
177
187
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
:
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
toolCalls: progress?.toolCalls,
|
|
203
|
-
};
|
|
204
|
-
const activityLine = buildActivityLine(activityData, theme);
|
|
205
|
-
|
|
206
|
-
let line = `${glyphColored} ${buildAgentLabel(agentName, result.task, theme)}${statsPart}`;
|
|
207
|
-
if (activityLine) {
|
|
208
|
-
line += "\n" + activityLine;
|
|
209
|
-
}
|
|
210
|
-
return line;
|
|
188
|
+
return buildAgentBlock(
|
|
189
|
+
{
|
|
190
|
+
agentName,
|
|
191
|
+
task: result.task,
|
|
192
|
+
model: progress?.model ?? result.model,
|
|
193
|
+
statsData: {
|
|
194
|
+
turns: result.usage.turns ?? 0,
|
|
195
|
+
toolCount: summary.toolCount,
|
|
196
|
+
tokens: summary.tokens,
|
|
197
|
+
durationMs: summary.durationMs,
|
|
198
|
+
cost: result.usage.cost ?? 0,
|
|
199
|
+
},
|
|
200
|
+
activity: {
|
|
201
|
+
currentTool: progress?.currentTool,
|
|
202
|
+
currentToolArgs: progress?.currentToolArgs,
|
|
203
|
+
currentToolStartedAt: progress?.currentToolStartedAt,
|
|
204
|
+
finalOutput: result.finalOutput,
|
|
205
|
+
status,
|
|
206
|
+
error: result.error,
|
|
207
|
+
toolCalls: progress?.toolCalls,
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
theme,
|
|
211
|
+
);
|
|
211
212
|
});
|
|
212
213
|
|
|
213
214
|
text.setText(lines.join("\n"));
|
|
@@ -227,13 +228,6 @@ export function renderCompactProgress(
|
|
|
227
228
|
const status = progress.status;
|
|
228
229
|
const isRunning = status === "running";
|
|
229
230
|
|
|
230
|
-
const glyph = statusGlyph(isRunning, status);
|
|
231
|
-
const glyphColored = status === "completed"
|
|
232
|
-
? theme.fg("success", glyph)
|
|
233
|
-
: status === "failed"
|
|
234
|
-
? theme.fg("error", glyph)
|
|
235
|
-
: theme.fg("muted", glyph);
|
|
236
|
-
|
|
237
231
|
// Track start time for live duration
|
|
238
232
|
const timeKey = "_subagentStartTime_" + agentName;
|
|
239
233
|
if (isRunning && context.state[timeKey] === undefined) {
|
|
@@ -243,34 +237,30 @@ export function renderCompactProgress(
|
|
|
243
237
|
? Date.now() - (context.state[timeKey] as number)
|
|
244
238
|
: progress.durationMs;
|
|
245
239
|
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const expandHint = theme.fg("muted", "(ctrl+o)");
|
|
271
|
-
const agentLabel = buildAgentLabel(agentName, progress.task, theme);
|
|
272
|
-
let output = agentLabel + "\n" + [modelLabel, statsPart, expandHint].filter(Boolean).join(" ");
|
|
273
|
-
output += "\n" + activityLine;
|
|
240
|
+
const output = buildAgentBlock(
|
|
241
|
+
{
|
|
242
|
+
agentName,
|
|
243
|
+
task: progress.task,
|
|
244
|
+
model: progress.model,
|
|
245
|
+
statsData: {
|
|
246
|
+
turns: 0,
|
|
247
|
+
toolCount: progress.toolCount,
|
|
248
|
+
tokens: progress.tokens,
|
|
249
|
+
durationMs: liveDuration,
|
|
250
|
+
cost: progress.cost,
|
|
251
|
+
},
|
|
252
|
+
activity: {
|
|
253
|
+
currentTool: progress.currentTool,
|
|
254
|
+
currentToolArgs: progress.currentToolArgs,
|
|
255
|
+
currentToolStartedAt: progress.currentToolStartedAt,
|
|
256
|
+
finalOutput: undefined,
|
|
257
|
+
status,
|
|
258
|
+
error: progress.error,
|
|
259
|
+
toolCalls: progress.toolCalls,
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
theme,
|
|
263
|
+
);
|
|
274
264
|
|
|
275
265
|
text.setText(output);
|
|
276
266
|
return text;
|
|
@@ -284,44 +274,34 @@ export function renderCompactParallelProgress(
|
|
|
284
274
|
theme: Theme,
|
|
285
275
|
context: RenderContext,
|
|
286
276
|
): Text {
|
|
287
|
-
const lines = (details.progress ?? []).map((progress
|
|
277
|
+
const lines = (details.progress ?? []).map((progress) => {
|
|
288
278
|
const agentName = progress.agent ?? "subagent";
|
|
289
279
|
const status = progress.status;
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
error: progress.error,
|
|
316
|
-
toolCalls: progress.toolCalls,
|
|
317
|
-
};
|
|
318
|
-
const activityLine = buildActivityLine(activityData, theme);
|
|
319
|
-
|
|
320
|
-
let line = `${glyphColored} ${buildAgentLabel(agentName, progress.task, theme)}${statsPart}`;
|
|
321
|
-
if (activityLine) {
|
|
322
|
-
line += "\n" + activityLine;
|
|
323
|
-
}
|
|
324
|
-
return line;
|
|
280
|
+
|
|
281
|
+
return buildAgentBlock(
|
|
282
|
+
{
|
|
283
|
+
agentName,
|
|
284
|
+
task: progress.task,
|
|
285
|
+
model: progress.model,
|
|
286
|
+
statsData: {
|
|
287
|
+
turns: 0,
|
|
288
|
+
toolCount: progress.toolCount,
|
|
289
|
+
tokens: progress.tokens,
|
|
290
|
+
durationMs: progress.durationMs,
|
|
291
|
+
cost: progress.cost,
|
|
292
|
+
},
|
|
293
|
+
activity: {
|
|
294
|
+
currentTool: progress.currentTool,
|
|
295
|
+
currentToolArgs: progress.currentToolArgs,
|
|
296
|
+
currentToolStartedAt: progress.currentToolStartedAt,
|
|
297
|
+
finalOutput: undefined,
|
|
298
|
+
status,
|
|
299
|
+
error: progress.error,
|
|
300
|
+
toolCalls: progress.toolCalls,
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
theme,
|
|
304
|
+
);
|
|
325
305
|
});
|
|
326
306
|
|
|
327
307
|
text.setText(lines.join("\n"));
|
package/src/expanded.ts
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { Text } from "@earendil-works/pi-tui";
|
|
2
2
|
import type { SubagentDetails, SubagentProgress, SubagentResult, SubagentToolCall } from "./types.js";
|
|
3
|
-
import {
|
|
3
|
+
import { formatDuration, truncLine, buildStatsLine, buildAgentLabel } from "./format.js";
|
|
4
|
+
import { renderToolCallLine } from "@pi-archimedes/core/tool-render";
|
|
4
5
|
|
|
5
6
|
type Theme = { fg: (token: string, text: string) => string; bold: (text: string) => string };
|
|
6
7
|
|
|
7
8
|
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
8
9
|
|
|
10
|
+
// A completed tool call renders with a status glyph (✓ ok / ✗ error) and its
|
|
11
|
+
// name coloured to match. Legacy string-form calls (old persisted sessions)
|
|
12
|
+
// carry no status, so they render as a neutral success line.
|
|
9
13
|
function formatToolCall(call: SubagentToolCall | string, theme: Theme): string {
|
|
10
|
-
// Backward compat: old persisted sessions may have toolCalls as string[]
|
|
11
14
|
if (typeof call === "string") {
|
|
12
|
-
return
|
|
13
|
-
}
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
const argsPart = call.argsPreview
|
|
18
|
-
? theme.fg("dim", ": " + call.argsPreview)
|
|
19
|
-
: "";
|
|
20
|
-
return arrow + name + argsPart;
|
|
15
|
+
return renderToolCallLine("success", call, "", theme);
|
|
16
|
+
}
|
|
17
|
+
const status = call.error ? "error" : "success";
|
|
18
|
+
const suffix = call.argsPreview ? ": " + call.argsPreview : "";
|
|
19
|
+
return renderToolCallLine(status, call.name, suffix, theme);
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
// ── Expanded completed result ───────────────────────────────────────────────
|
|
@@ -42,8 +41,7 @@ export function buildExpandedText(
|
|
|
42
41
|
durationMs: result.progressSummary?.durationMs,
|
|
43
42
|
cost: result.usage.cost,
|
|
44
43
|
}, theme);
|
|
45
|
-
const
|
|
46
|
-
const statsParts = [modelLabel, statsLine, expandHint].filter(Boolean);
|
|
44
|
+
const statsParts = [modelLabel, statsLine].filter(Boolean);
|
|
47
45
|
if (statsParts.length > 0) {
|
|
48
46
|
lines.push(statsParts.join(" "));
|
|
49
47
|
}
|
|
@@ -116,8 +114,7 @@ export function renderProgressExpanded(
|
|
|
116
114
|
durationMs: progress.durationMs,
|
|
117
115
|
cost: progress.cost,
|
|
118
116
|
}, theme);
|
|
119
|
-
const
|
|
120
|
-
const statsParts = [modelLabel, statsLine, expandHint].filter(Boolean);
|
|
117
|
+
const statsParts = [modelLabel, statsLine].filter(Boolean);
|
|
121
118
|
if (statsParts.length > 0) {
|
|
122
119
|
lines.push(statsParts.join(" "));
|
|
123
120
|
}
|
|
@@ -136,7 +133,7 @@ export function renderProgressExpanded(
|
|
|
136
133
|
}
|
|
137
134
|
}
|
|
138
135
|
|
|
139
|
-
// Activity (current tool with
|
|
136
|
+
// Activity (current tool, marked with the running glyph ▸)
|
|
140
137
|
if (progress.currentTool) {
|
|
141
138
|
lines.push("");
|
|
142
139
|
const argsPreview = progress.currentToolArgs
|
|
@@ -145,14 +142,8 @@ export function renderProgressExpanded(
|
|
|
145
142
|
const durationPart = progress.currentToolStartedAt
|
|
146
143
|
? " | " + formatDuration(Date.now() - progress.currentToolStartedAt)
|
|
147
144
|
: "";
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
line += theme.fg("dim", ": " + argsPreview);
|
|
151
|
-
}
|
|
152
|
-
if (durationPart) {
|
|
153
|
-
line += theme.fg("dim", durationPart);
|
|
154
|
-
}
|
|
155
|
-
lines.push(line);
|
|
145
|
+
const suffix = (argsPreview ? ": " + argsPreview : "") + durationPart;
|
|
146
|
+
lines.push(renderToolCallLine("running", progress.currentTool, suffix, theme));
|
|
156
147
|
}
|
|
157
148
|
|
|
158
149
|
// Status at bottom
|
|
@@ -192,8 +183,7 @@ export function buildProgressExpandedText(
|
|
|
192
183
|
durationMs: progress.durationMs,
|
|
193
184
|
cost: progress.cost,
|
|
194
185
|
}, theme);
|
|
195
|
-
const
|
|
196
|
-
const statsParts = [modelLabel, statsLine, expandHint].filter(Boolean);
|
|
186
|
+
const statsParts = [modelLabel, statsLine].filter(Boolean);
|
|
197
187
|
if (statsParts.length > 0) {
|
|
198
188
|
lines.push(statsParts.join(" "));
|
|
199
189
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { Text, TUI } from "@earendil-works/pi-tui";
|
|
2
|
+
import { Text, type TUI } from "@earendil-works/pi-tui";
|
|
3
3
|
import { Type } from "typebox";
|
|
4
|
+
import { SUBAGENT_PARAMS_SCHEMA } from "./tool-schema.js";
|
|
4
5
|
import { executeSubagent, executeParallel } from "./execute.js";
|
|
5
6
|
// agent-manager.js lazy-loaded below to keep subagent tool registration fast
|
|
6
7
|
import { renderSubagentResult } from "./render.js";
|
|
7
8
|
import { OVERLAY_CHROME } from "@pi-archimedes/core/overlay";
|
|
9
|
+
import { renderToolHeader } from "@pi-archimedes/core/tool-render";
|
|
8
10
|
import { discoverAgents, discoverAgentsAll, findAgent, formatAgentList } from "./agents.js";
|
|
9
11
|
import { validateModel, firstError } from "./model-validation.js";
|
|
10
12
|
import type {
|
|
@@ -14,38 +16,6 @@ import type {
|
|
|
14
16
|
SubagentToolResult,
|
|
15
17
|
} from "./types.js";
|
|
16
18
|
|
|
17
|
-
// ── JSON Schema for tool parameters (TypeBox) ──────────────────────────────
|
|
18
|
-
|
|
19
|
-
const TaskItem = Type.Object({
|
|
20
|
-
agent: Type.Optional(Type.String({
|
|
21
|
-
description: "Agent name for this task (optional). If omitted, runs config-less.",
|
|
22
|
-
})),
|
|
23
|
-
task: Type.String(),
|
|
24
|
-
model: Type.Optional(Type.String()),
|
|
25
|
-
cwd: Type.Optional(Type.String()),
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
const SUBAGENT_PARAMS_SCHEMA = Type.Object({
|
|
29
|
-
agent: Type.Optional(Type.String({
|
|
30
|
-
description: "Agent name (optional). If omitted, the subagent runs config-less — parent's current model, all tools, no system-prompt override. Call list_agents to see available agents.",
|
|
31
|
-
})),
|
|
32
|
-
task: Type.Optional(Type.String({
|
|
33
|
-
description: "Task description for the subagent. Required when not using 'tasks' array.",
|
|
34
|
-
})),
|
|
35
|
-
tasks: Type.Optional(Type.Array(TaskItem, {
|
|
36
|
-
description: "Multiple tasks for parallel execution. Required when not using 'task'.",
|
|
37
|
-
})),
|
|
38
|
-
model: Type.Optional(Type.String({
|
|
39
|
-
description: "Model override for the subagent",
|
|
40
|
-
})),
|
|
41
|
-
async: Type.Optional(Type.Boolean({
|
|
42
|
-
description: "Run asynchronously (fire-and-forget)",
|
|
43
|
-
})),
|
|
44
|
-
cwd: Type.Optional(Type.String({
|
|
45
|
-
description: "Working directory for the subagent",
|
|
46
|
-
})),
|
|
47
|
-
});
|
|
48
|
-
|
|
49
19
|
// ── Theme helper type for render functions ──────────────────────────────────
|
|
50
20
|
|
|
51
21
|
interface RenderTheme {
|
|
@@ -236,13 +206,13 @@ export function registerSubagent(pi: ExtensionAPI): void {
|
|
|
236
206
|
(ctx as Record<string, unknown>).lastComponent = text;
|
|
237
207
|
|
|
238
208
|
if (tasks && tasks.length > 0) {
|
|
239
|
-
|
|
240
|
-
|
|
209
|
+
text.setText(
|
|
210
|
+
renderToolHeader("subagent", `${tasks.length} tasks`, theme),
|
|
211
|
+
);
|
|
241
212
|
} else if (agent) {
|
|
242
|
-
|
|
243
|
-
text.setText(label);
|
|
213
|
+
text.setText(renderToolHeader("subagent", agent, theme));
|
|
244
214
|
} else {
|
|
245
|
-
text.setText(
|
|
215
|
+
text.setText(renderToolHeader("subagent", undefined, theme));
|
|
246
216
|
}
|
|
247
217
|
|
|
248
218
|
return text;
|