@trim21/personal-pi-extensions 0.0.165 → 0.0.167
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 +1 -1
- package/src/spawn-agent.ts +60 -45
package/package.json
CHANGED
package/src/spawn-agent.ts
CHANGED
|
@@ -24,9 +24,9 @@ import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
|
24
24
|
import { tmpdir } from "node:os";
|
|
25
25
|
import { basename, dirname, join } from "node:path";
|
|
26
26
|
|
|
27
|
-
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
28
|
-
import type { Message } from "@earendil-works/pi-ai";
|
|
27
|
+
import type { AgentMessage, AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
29
28
|
import {
|
|
29
|
+
type AgentSessionEvent,
|
|
30
30
|
type ExtensionAPI,
|
|
31
31
|
getMarkdownTheme,
|
|
32
32
|
truncateTail,
|
|
@@ -72,7 +72,7 @@ interface SubagentDetails {
|
|
|
72
72
|
agent: string;
|
|
73
73
|
task: string;
|
|
74
74
|
exitCode: number;
|
|
75
|
-
messages:
|
|
75
|
+
messages: AgentMessage[];
|
|
76
76
|
stderr: string;
|
|
77
77
|
usage: UsageStats;
|
|
78
78
|
model?: string;
|
|
@@ -82,7 +82,7 @@ interface SubagentDetails {
|
|
|
82
82
|
|
|
83
83
|
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
84
84
|
|
|
85
|
-
function getFinalOutput(messages:
|
|
85
|
+
function getFinalOutput(messages: AgentMessage[]): string {
|
|
86
86
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
87
87
|
const msg = messages[i];
|
|
88
88
|
if (msg.role === "assistant") {
|
|
@@ -234,42 +234,47 @@ export async function runAgent(
|
|
|
234
234
|
|
|
235
235
|
const processLine = (line: string) => {
|
|
236
236
|
if (!line.trim()) return;
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
237
|
+
const event = parseJsonEvent(line);
|
|
238
|
+
if (!event) return;
|
|
239
|
+
|
|
240
|
+
switch (event.type) {
|
|
241
|
+
case "message_update": {
|
|
242
|
+
// A completed text block (text_end carries the full content) becomes a
|
|
243
|
+
// `text:` log line. Deltas/thinking are intentionally not logged.
|
|
244
|
+
const delta = event.assistantMessageEvent;
|
|
245
|
+
if (delta.type === "text_end") {
|
|
246
|
+
pushLogLine(`text: ${delta.content}`);
|
|
247
|
+
emitUpdate();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
case "tool_execution_start": {
|
|
253
|
+
pushLogLine(`tool: ${event.toolName}`);
|
|
251
254
|
emitUpdate();
|
|
255
|
+
|
|
256
|
+
break;
|
|
252
257
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
258
|
+
case "message_end": {
|
|
259
|
+
const msg = event.message;
|
|
260
|
+
result.messages.push(msg);
|
|
261
|
+
if (msg.role === "assistant") {
|
|
262
|
+
result.usage.turns++;
|
|
263
|
+
result.usage.input += msg.usage.input;
|
|
264
|
+
result.usage.output += msg.usage.output;
|
|
265
|
+
result.usage.cacheRead += msg.usage.cacheRead;
|
|
266
|
+
result.usage.cacheWrite += msg.usage.cacheWrite;
|
|
267
|
+
result.usage.cost += msg.usage.cost.total;
|
|
268
|
+
result.usage.contextTokens = msg.usage.totalTokens;
|
|
269
|
+
if (!result.model) result.model = msg.model;
|
|
270
|
+
result.stopReason = msg.stopReason;
|
|
271
|
+
if (msg.errorMessage) result.errorMessage = msg.errorMessage;
|
|
272
|
+
}
|
|
273
|
+
emitUpdate();
|
|
274
|
+
|
|
275
|
+
break;
|
|
271
276
|
}
|
|
272
|
-
|
|
277
|
+
// No default
|
|
273
278
|
}
|
|
274
279
|
};
|
|
275
280
|
|
|
@@ -317,12 +322,22 @@ export async function runAgent(
|
|
|
317
322
|
}
|
|
318
323
|
}
|
|
319
324
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
325
|
+
/**
|
|
326
|
+
* Parse one line of the subagent's `--mode json` event stream into a typed
|
|
327
|
+
* event. Non-JSON lines and non-event records (e.g. the session header) are
|
|
328
|
+
* rejected. The cast here is the single trust boundary: downstream branches
|
|
329
|
+
* are fully type-narrowed via the `AgentSessionEvent` discriminated union.
|
|
330
|
+
*/
|
|
331
|
+
function parseJsonEvent(line: string): AgentSessionEvent | null {
|
|
332
|
+
let raw: unknown;
|
|
333
|
+
try {
|
|
334
|
+
raw = JSON.parse(line);
|
|
335
|
+
} catch {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
339
|
+
if (typeof (raw as Record<string, unknown>).type !== "string") return null;
|
|
340
|
+
return raw as AgentSessionEvent;
|
|
326
341
|
}
|
|
327
342
|
|
|
328
343
|
/** Session entry customType used to mark the injected subagent list. */
|
|
@@ -357,8 +372,8 @@ export default function spawnAgent(pi: ExtensionAPI) {
|
|
|
357
372
|
}
|
|
358
373
|
|
|
359
374
|
pi.registerTool<typeof spawnAgentSchema, SubagentDetails>({
|
|
360
|
-
name: "
|
|
361
|
-
label: "
|
|
375
|
+
name: "spawn-agent",
|
|
376
|
+
label: "spawn-agent",
|
|
362
377
|
description: [
|
|
363
378
|
"Delegate a task to a subagent running in a separate pi process with an isolated context window.",
|
|
364
379
|
"The `agent` parameter must be one of the available subagent types listed in the system prompt.",
|