@oh-my-pi/pi-coding-agent 3.13.1337 → 3.15.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 +88 -0
- package/docs/theme.md +38 -5
- package/examples/sdk/11-sessions.ts +2 -2
- package/package.json +7 -4
- package/src/cli/file-processor.ts +51 -2
- package/src/cli/plugin-cli.ts +25 -19
- package/src/cli/update-cli.ts +4 -3
- package/src/core/agent-session.ts +31 -4
- package/src/core/compaction/branch-summarization.ts +4 -32
- package/src/core/compaction/compaction.ts +6 -84
- package/src/core/compaction/utils.ts +2 -3
- package/src/core/custom-tools/types.ts +2 -0
- package/src/core/export-html/index.ts +1 -1
- package/src/core/hooks/index.ts +1 -1
- package/src/core/hooks/tool-wrapper.ts +0 -1
- package/src/core/hooks/types.ts +2 -2
- package/src/core/plugins/doctor.ts +9 -1
- package/src/core/sdk.ts +2 -1
- package/src/core/session-manager.ts +552 -41
- package/src/core/settings-manager.ts +174 -0
- package/src/core/system-prompt.ts +9 -14
- package/src/core/title-generator.ts +2 -8
- package/src/core/tools/ask.ts +19 -37
- package/src/core/tools/bash.ts +2 -37
- package/src/core/tools/edit.ts +2 -9
- package/src/core/tools/exa/render.ts +52 -48
- package/src/core/tools/find.ts +10 -8
- package/src/core/tools/grep.ts +45 -17
- package/src/core/tools/ls.ts +22 -2
- package/src/core/tools/lsp/clients/biome-client.ts +207 -0
- package/src/core/tools/lsp/clients/index.ts +49 -0
- package/src/core/tools/lsp/clients/lsp-linter-client.ts +98 -0
- package/src/core/tools/lsp/config.ts +3 -0
- package/src/core/tools/lsp/index.ts +107 -55
- package/src/core/tools/lsp/render.ts +192 -79
- package/src/core/tools/lsp/types.ts +27 -0
- package/src/core/tools/lsp/utils.ts +62 -22
- package/src/core/tools/notebook.ts +9 -1
- package/src/core/tools/output.ts +37 -14
- package/src/core/tools/read.ts +349 -34
- package/src/core/tools/renderers.ts +290 -89
- package/src/core/tools/review.ts +12 -5
- package/src/core/tools/task/agents.ts +5 -5
- package/src/core/tools/task/commands.ts +3 -3
- package/src/core/tools/task/executor.ts +33 -1
- package/src/core/tools/task/index.ts +93 -6
- package/src/core/tools/task/render.ts +147 -66
- package/src/core/tools/task/types.ts +14 -9
- package/src/core/tools/web-fetch.ts +242 -103
- package/src/core/tools/web-search/index.ts +64 -20
- package/src/core/tools/web-search/providers/exa.ts +68 -172
- package/src/core/tools/web-search/render.ts +264 -74
- package/src/core/tools/write.ts +2 -8
- package/src/main.ts +10 -6
- package/src/modes/cleanup.ts +23 -0
- package/src/modes/index.ts +9 -4
- package/src/modes/interactive/components/bash-execution.ts +6 -3
- package/src/modes/interactive/components/branch-summary-message.ts +1 -1
- package/src/modes/interactive/components/compaction-summary-message.ts +1 -1
- package/src/modes/interactive/components/dynamic-border.ts +1 -1
- package/src/modes/interactive/components/extensions/extension-dashboard.ts +4 -5
- package/src/modes/interactive/components/extensions/extension-list.ts +18 -16
- package/src/modes/interactive/components/extensions/inspector-panel.ts +8 -8
- package/src/modes/interactive/components/hook-message.ts +2 -2
- package/src/modes/interactive/components/hook-selector.ts +1 -1
- package/src/modes/interactive/components/model-selector.ts +22 -9
- package/src/modes/interactive/components/oauth-selector.ts +20 -4
- package/src/modes/interactive/components/plugin-settings.ts +4 -2
- package/src/modes/interactive/components/session-selector.ts +9 -6
- package/src/modes/interactive/components/settings-defs.ts +285 -1
- package/src/modes/interactive/components/settings-selector.ts +176 -3
- package/src/modes/interactive/components/status-line/index.ts +4 -0
- package/src/modes/interactive/components/status-line/presets.ts +94 -0
- package/src/modes/interactive/components/status-line/segments.ts +350 -0
- package/src/modes/interactive/components/status-line/separators.ts +55 -0
- package/src/modes/interactive/components/status-line/types.ts +81 -0
- package/src/modes/interactive/components/status-line-segment-editor.ts +357 -0
- package/src/modes/interactive/components/status-line.ts +169 -233
- package/src/modes/interactive/components/tool-execution.ts +446 -211
- package/src/modes/interactive/components/tree-selector.ts +17 -6
- package/src/modes/interactive/components/ttsr-notification.ts +4 -4
- package/src/modes/interactive/components/welcome.ts +27 -19
- package/src/modes/interactive/interactive-mode.ts +98 -13
- package/src/modes/interactive/theme/dark.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-arctic.json +111 -0
- package/src/modes/interactive/theme/defaults/dark-catppuccin.json +106 -0
- package/src/modes/interactive/theme/defaults/dark-cyberpunk.json +109 -0
- package/src/modes/interactive/theme/defaults/dark-dracula.json +105 -0
- package/src/modes/interactive/theme/defaults/dark-forest.json +103 -0
- package/src/modes/interactive/theme/defaults/dark-github.json +112 -0
- package/src/modes/interactive/theme/defaults/dark-gruvbox.json +119 -0
- package/src/modes/interactive/theme/defaults/dark-monochrome.json +101 -0
- package/src/modes/interactive/theme/defaults/dark-monokai.json +105 -0
- package/src/modes/interactive/theme/defaults/dark-nord.json +104 -0
- package/src/modes/interactive/theme/defaults/dark-ocean.json +108 -0
- package/src/modes/interactive/theme/defaults/dark-one.json +107 -0
- package/src/modes/interactive/theme/defaults/dark-retro.json +99 -0
- package/src/modes/interactive/theme/defaults/dark-rose-pine.json +95 -0
- package/src/modes/interactive/theme/defaults/dark-solarized.json +96 -0
- package/src/modes/interactive/theme/defaults/dark-sunset.json +106 -0
- package/src/modes/interactive/theme/defaults/dark-synthwave.json +102 -0
- package/src/modes/interactive/theme/defaults/dark-tokyo-night.json +108 -0
- package/src/modes/interactive/theme/defaults/index.ts +67 -0
- package/src/modes/interactive/theme/defaults/light-arctic.json +106 -0
- package/src/modes/interactive/theme/defaults/light-catppuccin.json +105 -0
- package/src/modes/interactive/theme/defaults/light-cyberpunk.json +103 -0
- package/src/modes/interactive/theme/defaults/light-forest.json +107 -0
- package/src/modes/interactive/theme/defaults/light-github.json +114 -0
- package/src/modes/interactive/theme/defaults/light-gruvbox.json +115 -0
- package/src/modes/interactive/theme/defaults/light-monochrome.json +100 -0
- package/src/modes/interactive/theme/defaults/light-ocean.json +106 -0
- package/src/modes/interactive/theme/defaults/light-one.json +105 -0
- package/src/modes/interactive/theme/defaults/light-retro.json +105 -0
- package/src/modes/interactive/theme/defaults/light-solarized.json +101 -0
- package/src/modes/interactive/theme/defaults/light-sunset.json +106 -0
- package/src/modes/interactive/theme/defaults/light-synthwave.json +105 -0
- package/src/modes/interactive/theme/defaults/light-tokyo-night.json +118 -0
- package/src/modes/interactive/theme/light.json +3 -2
- package/src/modes/interactive/theme/theme-schema.json +120 -4
- package/src/modes/interactive/theme/theme.ts +1228 -14
- package/src/prompts/branch-summary-preamble.md +3 -0
- package/src/prompts/branch-summary.md +28 -0
- package/src/prompts/compaction-summary.md +34 -0
- package/src/prompts/compaction-turn-prefix.md +16 -0
- package/src/prompts/compaction-update-summary.md +41 -0
- package/src/prompts/init.md +30 -0
- package/src/{core/tools/task/bundled-agents → prompts}/reviewer.md +6 -0
- package/src/prompts/summarization-system.md +3 -0
- package/src/prompts/system-prompt.md +27 -0
- package/src/{core/tools/task/bundled-agents → prompts}/task.md +2 -0
- package/src/prompts/title-system.md +8 -0
- package/src/prompts/tools/ask.md +24 -0
- package/src/prompts/tools/bash.md +23 -0
- package/src/prompts/tools/edit.md +9 -0
- package/src/prompts/tools/find.md +6 -0
- package/src/prompts/tools/grep.md +12 -0
- package/src/prompts/tools/lsp.md +14 -0
- package/src/prompts/tools/output.md +23 -0
- package/src/prompts/tools/read.md +25 -0
- package/src/prompts/tools/web-fetch.md +8 -0
- package/src/prompts/tools/web-search.md +10 -0
- package/src/prompts/tools/write.md +10 -0
- package/src/commands/init.md +0 -20
- /package/src/{core/tools/task/bundled-commands → prompts}/architect-plan.md +0 -0
- /package/src/{core/tools/task/bundled-agents → prompts}/browser.md +0 -0
- /package/src/{core/tools/task/bundled-agents → prompts}/explore.md +0 -0
- /package/src/{core/tools/task/bundled-commands → prompts}/implement-with-critic.md +0 -0
- /package/src/{core/tools/task/bundled-commands → prompts}/implement.md +0 -0
- /package/src/{core/tools/task/bundled-agents → prompts}/plan.md +0 -0
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
// Embed agent markdown files at build time
|
|
8
|
-
import browserMd from "
|
|
9
|
-
import exploreMd from "
|
|
10
|
-
import planMd from "
|
|
11
|
-
import reviewerMd from "
|
|
12
|
-
import taskMd from "
|
|
8
|
+
import browserMd from "../../../prompts/browser.md" with { type: "text" };
|
|
9
|
+
import exploreMd from "../../../prompts/explore.md" with { type: "text" };
|
|
10
|
+
import planMd from "../../../prompts/plan.md" with { type: "text" };
|
|
11
|
+
import reviewerMd from "../../../prompts/reviewer.md" with { type: "text" };
|
|
12
|
+
import taskMd from "../../../prompts/task.md" with { type: "text" };
|
|
13
13
|
import type { AgentDefinition, AgentSource } from "./types";
|
|
14
14
|
|
|
15
15
|
const EMBEDDED_AGENTS: { name: string; content: string }[] = [
|
|
@@ -9,9 +9,9 @@ import { type SlashCommand, slashCommandCapability } from "../../../capability/s
|
|
|
9
9
|
import { loadSync } from "../../../discovery";
|
|
10
10
|
|
|
11
11
|
// Embed command markdown files at build time
|
|
12
|
-
import architectPlanMd from "
|
|
13
|
-
import implementMd from "
|
|
14
|
-
import implementWithCriticMd from "
|
|
12
|
+
import architectPlanMd from "../../../prompts/architect-plan.md" with { type: "text" };
|
|
13
|
+
import implementMd from "../../../prompts/implement.md" with { type: "text" };
|
|
14
|
+
import implementWithCriticMd from "../../../prompts/implement-with-critic.md" with { type: "text" };
|
|
15
15
|
|
|
16
16
|
const EMBEDDED_COMMANDS: { name: string; content: string }[] = [
|
|
17
17
|
{ name: "architect-plan.md", content: architectPlanMd },
|
|
@@ -100,6 +100,38 @@ function extractToolArgsPreview(args: Record<string, unknown>): string {
|
|
|
100
100
|
return "";
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
function getNumberField(record: Record<string, unknown>, key: string): number | undefined {
|
|
104
|
+
if (!Object.hasOwn(record, key)) return undefined;
|
|
105
|
+
const value = record[key];
|
|
106
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function firstNumberField(record: Record<string, unknown>, keys: string[]): number | undefined {
|
|
110
|
+
for (const key of keys) {
|
|
111
|
+
const value = getNumberField(record, key);
|
|
112
|
+
if (value !== undefined) return value;
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Normalize usage objects from different event formats.
|
|
119
|
+
*/
|
|
120
|
+
function getUsageTokens(usage: unknown): number {
|
|
121
|
+
if (!usage || typeof usage !== "object") return 0;
|
|
122
|
+
const record = usage as Record<string, unknown>;
|
|
123
|
+
|
|
124
|
+
const totalTokens = firstNumberField(record, ["totalTokens", "total_tokens"]);
|
|
125
|
+
if (totalTokens !== undefined && totalTokens > 0) return totalTokens;
|
|
126
|
+
|
|
127
|
+
const input = firstNumberField(record, ["input", "input_tokens", "inputTokens"]) ?? 0;
|
|
128
|
+
const output = firstNumberField(record, ["output", "output_tokens", "outputTokens"]) ?? 0;
|
|
129
|
+
const cacheRead = firstNumberField(record, ["cacheRead", "cache_read", "cacheReadTokens"]) ?? 0;
|
|
130
|
+
const cacheWrite = firstNumberField(record, ["cacheWrite", "cache_write", "cacheWriteTokens"]) ?? 0;
|
|
131
|
+
|
|
132
|
+
return input + output + cacheRead + cacheWrite;
|
|
133
|
+
}
|
|
134
|
+
|
|
103
135
|
/**
|
|
104
136
|
* Run a single agent as a subprocess.
|
|
105
137
|
*/
|
|
@@ -369,7 +401,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
369
401
|
const messageUsage = event.message?.usage || event.usage;
|
|
370
402
|
if (messageUsage) {
|
|
371
403
|
// Accumulate tokens across messages (not overwrite)
|
|
372
|
-
progress.tokens += (messageUsage
|
|
404
|
+
progress.tokens += getUsageTokens(messageUsage);
|
|
373
405
|
}
|
|
374
406
|
// If pending termination, now we have tokens - terminate
|
|
375
407
|
if (pendingTermination && !resolved) {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
17
|
+
import type { Usage } from "@oh-my-pi/pi-ai";
|
|
17
18
|
import type { Theme } from "../../../modes/interactive/theme/theme";
|
|
18
19
|
import { cleanupTempDir, createTempArtifactsDir, getArtifactsDir } from "./artifacts";
|
|
19
20
|
import { discoverAgents, getAgent } from "./discovery";
|
|
@@ -42,6 +43,79 @@ function formatBytes(bytes: number): string {
|
|
|
42
43
|
return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
function createUsageTotals(): Usage {
|
|
47
|
+
return {
|
|
48
|
+
input: 0,
|
|
49
|
+
output: 0,
|
|
50
|
+
cacheRead: 0,
|
|
51
|
+
cacheWrite: 0,
|
|
52
|
+
totalTokens: 0,
|
|
53
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function addUsageTotals(target: Usage, usage: Partial<Usage>): void {
|
|
58
|
+
const input = usage.input ?? 0;
|
|
59
|
+
const output = usage.output ?? 0;
|
|
60
|
+
const cacheRead = usage.cacheRead ?? 0;
|
|
61
|
+
const cacheWrite = usage.cacheWrite ?? 0;
|
|
62
|
+
const totalTokens = usage.totalTokens ?? input + output + cacheRead + cacheWrite;
|
|
63
|
+
const cost =
|
|
64
|
+
usage.cost ??
|
|
65
|
+
({
|
|
66
|
+
input: 0,
|
|
67
|
+
output: 0,
|
|
68
|
+
cacheRead: 0,
|
|
69
|
+
cacheWrite: 0,
|
|
70
|
+
total: 0,
|
|
71
|
+
} satisfies Usage["cost"]);
|
|
72
|
+
|
|
73
|
+
target.input += input;
|
|
74
|
+
target.output += output;
|
|
75
|
+
target.cacheRead += cacheRead;
|
|
76
|
+
target.cacheWrite += cacheWrite;
|
|
77
|
+
target.totalTokens += totalTokens;
|
|
78
|
+
target.cost.input += cost.input;
|
|
79
|
+
target.cost.output += cost.output;
|
|
80
|
+
target.cost.cacheRead += cost.cacheRead;
|
|
81
|
+
target.cost.cacheWrite += cost.cacheWrite;
|
|
82
|
+
target.cost.total += cost.total;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function parseSubagentUsage(events: string[] | undefined): Usage | undefined {
|
|
86
|
+
if (!events || events.length === 0) return undefined;
|
|
87
|
+
|
|
88
|
+
const totals = createUsageTotals();
|
|
89
|
+
let hasUsage = false;
|
|
90
|
+
|
|
91
|
+
for (const line of events) {
|
|
92
|
+
let event: unknown;
|
|
93
|
+
try {
|
|
94
|
+
event = JSON.parse(line);
|
|
95
|
+
} catch {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!event || typeof event !== "object") continue;
|
|
100
|
+
const record = event as Record<string, unknown>;
|
|
101
|
+
if (record.type !== "message_end") continue;
|
|
102
|
+
|
|
103
|
+
const message = record.message;
|
|
104
|
+
if (!message || typeof message !== "object") continue;
|
|
105
|
+
const msgRecord = message as Record<string, unknown>;
|
|
106
|
+
if (msgRecord.role !== "assistant") continue;
|
|
107
|
+
if (msgRecord.stopReason === "aborted" || msgRecord.stopReason === "error") continue;
|
|
108
|
+
|
|
109
|
+
const usage = msgRecord.usage;
|
|
110
|
+
if (!usage || typeof usage !== "object") continue;
|
|
111
|
+
|
|
112
|
+
addUsageTotals(totals, usage as Partial<Usage>);
|
|
113
|
+
hasUsage = true;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return hasUsage ? totals : undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
45
119
|
/** Session context interface */
|
|
46
120
|
interface SessionContext {
|
|
47
121
|
getSessionFile: () => string | null;
|
|
@@ -393,19 +467,31 @@ export function createTaskTool(
|
|
|
393
467
|
});
|
|
394
468
|
});
|
|
395
469
|
|
|
470
|
+
const aggregatedUsage = createUsageTotals();
|
|
471
|
+
let hasAggregatedUsage = false;
|
|
472
|
+
const resultsWithUsage = results.map((result) => {
|
|
473
|
+
const usage = parseSubagentUsage(result.jsonlEvents);
|
|
474
|
+
if (usage) {
|
|
475
|
+
addUsageTotals(aggregatedUsage, usage);
|
|
476
|
+
hasAggregatedUsage = true;
|
|
477
|
+
return { ...result, usage };
|
|
478
|
+
}
|
|
479
|
+
return result;
|
|
480
|
+
});
|
|
481
|
+
|
|
396
482
|
// Collect output paths (artifacts already written by executor in real-time)
|
|
397
483
|
const outputPaths: string[] = [];
|
|
398
|
-
for (const result of
|
|
484
|
+
for (const result of resultsWithUsage) {
|
|
399
485
|
if (result.artifactPaths) {
|
|
400
486
|
outputPaths.push(result.artifactPaths.outputPath);
|
|
401
487
|
}
|
|
402
488
|
}
|
|
403
489
|
|
|
404
490
|
// Build final output - match plugin format
|
|
405
|
-
const successCount =
|
|
491
|
+
const successCount = resultsWithUsage.filter((r) => r.exitCode === 0).length;
|
|
406
492
|
const totalDuration = Date.now() - startTime;
|
|
407
493
|
|
|
408
|
-
const summaries =
|
|
494
|
+
const summaries = resultsWithUsage.map((r) => {
|
|
409
495
|
const status = r.exitCode === 0 ? "completed" : `failed (exit ${r.exitCode})`;
|
|
410
496
|
const output = r.output.trim() || r.stderr.trim() || "(no output)";
|
|
411
497
|
const preview = output.split("\n").slice(0, 5).join("\n");
|
|
@@ -415,14 +501,14 @@ export function createTaskTool(
|
|
|
415
501
|
? ` [${r.outputMeta.lineCount} lines, ${formatBytes(r.outputMeta.charCount)}]`
|
|
416
502
|
: "";
|
|
417
503
|
const pathInfo = !hasOutputTool && r.artifactPaths?.outputPath ? ` (${r.artifactPaths.outputPath})` : "";
|
|
418
|
-
return `[${r.agent}] ${status}${meta}
|
|
504
|
+
return `[${r.agent}] ${status}${meta} ${outputId}${pathInfo}\n${preview}`;
|
|
419
505
|
});
|
|
420
506
|
|
|
421
507
|
const skippedNote =
|
|
422
508
|
skippedSelfRecursion > 0
|
|
423
509
|
? ` (${skippedSelfRecursion} ${blockedAgent} task${skippedSelfRecursion > 1 ? "s" : ""} skipped - self-recursion blocked)`
|
|
424
510
|
: "";
|
|
425
|
-
const summary = `${successCount}/${
|
|
511
|
+
const summary = `${successCount}/${resultsWithUsage.length} succeeded${skippedNote} [${formatDuration(totalDuration)}]\n\n${summaries.join("\n\n---\n\n")}`;
|
|
426
512
|
|
|
427
513
|
// Cleanup temp directory if used
|
|
428
514
|
if (tempArtifactsDir) {
|
|
@@ -433,8 +519,9 @@ export function createTaskTool(
|
|
|
433
519
|
content: [{ type: "text", text: summary }],
|
|
434
520
|
details: {
|
|
435
521
|
projectAgentsDir,
|
|
436
|
-
results,
|
|
522
|
+
results: resultsWithUsage,
|
|
437
523
|
totalDurationMs: totalDuration,
|
|
524
|
+
usage: hasAggregatedUsage ? aggregatedUsage : undefined,
|
|
438
525
|
outputPaths,
|
|
439
526
|
},
|
|
440
527
|
};
|
|
@@ -44,29 +44,91 @@ export function formatDuration(ms: number): string {
|
|
|
44
44
|
/**
|
|
45
45
|
* Truncate text to max length with ellipsis.
|
|
46
46
|
*/
|
|
47
|
-
function truncate(text: string, maxLen: number): string {
|
|
47
|
+
function truncate(text: string, maxLen: number, ellipsis: string): string {
|
|
48
48
|
if (text.length <= maxLen) return text;
|
|
49
|
-
|
|
49
|
+
const sliceLen = Math.max(0, maxLen - ellipsis.length);
|
|
50
|
+
return `${text.slice(0, sliceLen)}${ellipsis}`;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
/**
|
|
53
54
|
* Get status icon for agent state.
|
|
55
|
+
* For running status, uses animated spinner if spinnerFrame is provided.
|
|
54
56
|
*/
|
|
55
|
-
function getStatusIcon(status: AgentProgress["status"]): string {
|
|
57
|
+
function getStatusIcon(status: AgentProgress["status"], theme: Theme, spinnerFrame?: number): string {
|
|
56
58
|
switch (status) {
|
|
57
59
|
case "pending":
|
|
58
|
-
return
|
|
59
|
-
case "running":
|
|
60
|
-
|
|
60
|
+
return theme.status.pending;
|
|
61
|
+
case "running": {
|
|
62
|
+
// Use animated spinner if frame is provided, otherwise static icon
|
|
63
|
+
if (spinnerFrame === undefined) return theme.status.running;
|
|
64
|
+
const frames = theme.spinnerFrames;
|
|
65
|
+
return frames[spinnerFrame % frames.length];
|
|
66
|
+
}
|
|
61
67
|
case "completed":
|
|
62
|
-
return
|
|
68
|
+
return theme.status.success;
|
|
63
69
|
case "failed":
|
|
64
|
-
return
|
|
70
|
+
return theme.status.error;
|
|
65
71
|
case "aborted":
|
|
66
|
-
return
|
|
72
|
+
return theme.status.aborted;
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
|
|
76
|
+
function formatBadge(label: string, color: "success" | "error" | "warning" | "accent" | "muted", theme: Theme): string {
|
|
77
|
+
const left = theme.format.bracketLeft;
|
|
78
|
+
const right = theme.format.bracketRight;
|
|
79
|
+
return theme.fg(color, `${left}${label}${right}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function formatFindingSummary(findings: ReportFindingDetails[], theme: Theme): string {
|
|
83
|
+
if (findings.length === 0) return theme.fg("dim", "Findings: none");
|
|
84
|
+
|
|
85
|
+
const counts = new Map<number, number>();
|
|
86
|
+
for (const finding of findings) {
|
|
87
|
+
counts.set(finding.priority, (counts.get(finding.priority) ?? 0) + 1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const parts: string[] = [];
|
|
91
|
+
for (const priority of [0, 1, 2, 3]) {
|
|
92
|
+
const label = PRIORITY_LABELS[priority] ?? "P?";
|
|
93
|
+
const color = priority === 0 ? "error" : priority === 1 ? "warning" : "muted";
|
|
94
|
+
const count = counts.get(priority) ?? 0;
|
|
95
|
+
parts.push(theme.fg(color, `${label}:${count}`));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return `${theme.fg("dim", "Findings:")} ${parts.join(theme.sep.dot)}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function renderOutputSection(
|
|
102
|
+
output: string,
|
|
103
|
+
continuePrefix: string,
|
|
104
|
+
expanded: boolean,
|
|
105
|
+
theme: Theme,
|
|
106
|
+
maxCollapsed = 3,
|
|
107
|
+
maxExpanded = 10,
|
|
108
|
+
): string[] {
|
|
109
|
+
const lines: string[] = [];
|
|
110
|
+
const outputLines = output.split("\n").filter((line) => line.trim());
|
|
111
|
+
if (outputLines.length === 0) return lines;
|
|
112
|
+
|
|
113
|
+
lines.push(`${continuePrefix}${theme.fg("dim", "Output")}`);
|
|
114
|
+
|
|
115
|
+
const previewCount = expanded ? maxExpanded : maxCollapsed;
|
|
116
|
+
for (const line of outputLines.slice(0, previewCount)) {
|
|
117
|
+
lines.push(`${continuePrefix} ${theme.fg("dim", truncate(line, 70, theme.format.ellipsis))}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (outputLines.length > previewCount) {
|
|
121
|
+
lines.push(
|
|
122
|
+
`${continuePrefix} ${theme.fg(
|
|
123
|
+
"dim",
|
|
124
|
+
`${theme.format.ellipsis} ${outputLines.length - previewCount} more lines`,
|
|
125
|
+
)}`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return lines;
|
|
130
|
+
}
|
|
131
|
+
|
|
70
132
|
/**
|
|
71
133
|
* Render the tool call arguments.
|
|
72
134
|
*/
|
|
@@ -76,24 +138,36 @@ export function renderCall(args: TaskParams, theme: Theme): Component {
|
|
|
76
138
|
if (args.tasks.length === 1) {
|
|
77
139
|
// Single task - show agent and task preview
|
|
78
140
|
const task = args.tasks[0];
|
|
79
|
-
const taskPreview = truncate(task.task, 60);
|
|
141
|
+
const taskPreview = truncate(task.task, 60, theme.format.ellipsis);
|
|
80
142
|
return new Text(`${label} ${theme.fg("accent", task.agent)}: ${theme.fg("muted", taskPreview)}`, 0, 0);
|
|
81
143
|
}
|
|
82
144
|
|
|
83
145
|
// Multiple tasks - show count and agent names
|
|
84
146
|
const agents = args.tasks.map((t) => t.agent).join(", ");
|
|
85
|
-
return new Text(
|
|
147
|
+
return new Text(
|
|
148
|
+
`${label} ${theme.fg("muted", `${args.tasks.length} agents: ${truncate(agents, 50, theme.format.ellipsis)}`)}`,
|
|
149
|
+
0,
|
|
150
|
+
0,
|
|
151
|
+
);
|
|
86
152
|
}
|
|
87
153
|
|
|
88
154
|
/**
|
|
89
155
|
* Render streaming progress for a single agent.
|
|
90
156
|
*/
|
|
91
|
-
function renderAgentProgress(
|
|
157
|
+
function renderAgentProgress(
|
|
158
|
+
progress: AgentProgress,
|
|
159
|
+
isLast: boolean,
|
|
160
|
+
expanded: boolean,
|
|
161
|
+
theme: Theme,
|
|
162
|
+
spinnerFrame?: number,
|
|
163
|
+
): string[] {
|
|
92
164
|
const lines: string[] = [];
|
|
93
|
-
const prefix = isLast
|
|
94
|
-
|
|
165
|
+
const prefix = isLast
|
|
166
|
+
? `${theme.boxSharp.bottomLeft}${theme.boxSharp.horizontal}`
|
|
167
|
+
: `${theme.boxSharp.teeRight}${theme.boxSharp.horizontal}`;
|
|
168
|
+
const continuePrefix = isLast ? " " : `${theme.boxSharp.vertical} `;
|
|
95
169
|
|
|
96
|
-
const icon = getStatusIcon(progress.status);
|
|
170
|
+
const icon = getStatusIcon(progress.status, theme, spinnerFrame);
|
|
97
171
|
const iconColor =
|
|
98
172
|
progress.status === "completed"
|
|
99
173
|
? "success"
|
|
@@ -105,35 +179,43 @@ function renderAgentProgress(progress: AgentProgress, isLast: boolean, expanded:
|
|
|
105
179
|
const agentId = `${progress.agent}(${progress.index})`;
|
|
106
180
|
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", agentId)}`;
|
|
107
181
|
|
|
182
|
+
// Only show badge for non-running states (spinner already indicates running)
|
|
183
|
+
if (progress.status !== "running") {
|
|
184
|
+
const statusLabel =
|
|
185
|
+
progress.status === "completed"
|
|
186
|
+
? "done"
|
|
187
|
+
: progress.status === "failed"
|
|
188
|
+
? "failed"
|
|
189
|
+
: progress.status === "aborted"
|
|
190
|
+
? "aborted"
|
|
191
|
+
: "pending";
|
|
192
|
+
statusLine += ` ${formatBadge(statusLabel, iconColor, theme)}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
108
195
|
if (progress.status === "running") {
|
|
109
|
-
const taskPreview = truncate(progress.task, 40);
|
|
110
|
-
statusLine +=
|
|
111
|
-
statusLine +=
|
|
196
|
+
const taskPreview = truncate(progress.task, 40, theme.format.ellipsis);
|
|
197
|
+
statusLine += ` ${theme.fg("muted", taskPreview)}`;
|
|
198
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", `${progress.toolCount} tools`)}`;
|
|
112
199
|
if (progress.tokens > 0) {
|
|
113
|
-
statusLine +=
|
|
200
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", `${formatTokens(progress.tokens)} tokens`)}`;
|
|
114
201
|
}
|
|
115
202
|
} else if (progress.status === "completed") {
|
|
116
|
-
statusLine +=
|
|
117
|
-
statusLine +=
|
|
118
|
-
statusLine += ` · ${theme.fg("dim", `${formatTokens(progress.tokens)} tokens`)}`;
|
|
119
|
-
} else if (progress.status === "aborted") {
|
|
120
|
-
statusLine += `: ${theme.fg("error", "aborted")}`;
|
|
121
|
-
} else if (progress.status === "failed") {
|
|
122
|
-
statusLine += `: ${theme.fg("error", "failed")}`;
|
|
203
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", `${progress.toolCount} tools`)}`;
|
|
204
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", `${formatTokens(progress.tokens)} tokens`)}`;
|
|
123
205
|
}
|
|
124
206
|
|
|
125
207
|
lines.push(statusLine);
|
|
126
208
|
|
|
127
209
|
// Current tool (if running)
|
|
128
210
|
if (progress.status === "running" && progress.currentTool) {
|
|
129
|
-
let toolLine = `${continuePrefix}
|
|
211
|
+
let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("muted", progress.currentTool)}`;
|
|
130
212
|
if (progress.currentToolArgs) {
|
|
131
|
-
toolLine += `: ${theme.fg("dim", truncate(progress.currentToolArgs, 40))}`;
|
|
213
|
+
toolLine += `: ${theme.fg("dim", truncate(progress.currentToolArgs, 40, theme.format.ellipsis))}`;
|
|
132
214
|
}
|
|
133
215
|
if (progress.currentToolStartMs) {
|
|
134
216
|
const elapsed = Date.now() - progress.currentToolStartMs;
|
|
135
217
|
if (elapsed > 5000) {
|
|
136
|
-
toolLine +=
|
|
218
|
+
toolLine += `${theme.sep.dot}${theme.fg("warning", formatDuration(elapsed))}`;
|
|
137
219
|
}
|
|
138
220
|
}
|
|
139
221
|
lines.push(toolLine);
|
|
@@ -153,7 +235,9 @@ function renderAgentProgress(progress: AgentProgress, isLast: boolean, expanded:
|
|
|
153
235
|
}
|
|
154
236
|
}
|
|
155
237
|
if (dataArray.length > 3) {
|
|
156
|
-
lines.push(
|
|
238
|
+
lines.push(
|
|
239
|
+
`${continuePrefix}${theme.fg("dim", `${theme.format.ellipsis} ${dataArray.length - 3} more`)}`,
|
|
240
|
+
);
|
|
157
241
|
}
|
|
158
242
|
}
|
|
159
243
|
}
|
|
@@ -161,10 +245,8 @@ function renderAgentProgress(progress: AgentProgress, isLast: boolean, expanded:
|
|
|
161
245
|
|
|
162
246
|
// Expanded view: recent output and tools
|
|
163
247
|
if (expanded && progress.status === "running") {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
lines.push(`${continuePrefix} ${theme.fg("dim", truncate(line, 60))}`);
|
|
167
|
-
}
|
|
248
|
+
const output = progress.recentOutput.join("\n");
|
|
249
|
+
lines.push(...renderOutputSection(output, continuePrefix, true, theme, 2, 6));
|
|
168
250
|
}
|
|
169
251
|
|
|
170
252
|
return lines;
|
|
@@ -184,7 +266,7 @@ function renderReviewResult(
|
|
|
184
266
|
|
|
185
267
|
// Verdict line
|
|
186
268
|
const verdictColor = summary.overall_correctness === "correct" ? "success" : "error";
|
|
187
|
-
const verdictIcon = summary.overall_correctness === "correct" ?
|
|
269
|
+
const verdictIcon = summary.overall_correctness === "correct" ? theme.status.success : theme.status.error;
|
|
188
270
|
lines.push(
|
|
189
271
|
`${continuePrefix}${theme.fg(verdictColor, verdictIcon)} Patch is ${theme.fg(verdictColor, summary.overall_correctness)} ${theme.fg("dim", `(${(summary.confidence * 100).toFixed(0)}% confidence)`)}`,
|
|
190
272
|
);
|
|
@@ -192,19 +274,21 @@ function renderReviewResult(
|
|
|
192
274
|
// Explanation preview (first ~80 chars when collapsed, full when expanded)
|
|
193
275
|
if (summary.explanation) {
|
|
194
276
|
if (expanded) {
|
|
195
|
-
|
|
277
|
+
lines.push(`${continuePrefix}${theme.fg("dim", "Summary")}`);
|
|
196
278
|
const explanationLines = summary.explanation.split("\n");
|
|
197
279
|
for (const line of explanationLines) {
|
|
198
|
-
lines.push(`${continuePrefix}${theme.fg("dim", line)}`);
|
|
280
|
+
lines.push(`${continuePrefix} ${theme.fg("dim", line)}`);
|
|
199
281
|
}
|
|
200
282
|
} else {
|
|
201
283
|
// Preview: first sentence or ~100 chars
|
|
202
|
-
const preview = truncate(`${summary.explanation.split(/[.!?]/)[0]}.`, 100);
|
|
203
|
-
lines.push(`${continuePrefix}${theme.fg("dim", preview)}`);
|
|
284
|
+
const preview = truncate(`${summary.explanation.split(/[.!?]/)[0]}.`, 100, theme.format.ellipsis);
|
|
285
|
+
lines.push(`${continuePrefix}${theme.fg("dim", `Summary: ${preview}`)}`);
|
|
204
286
|
}
|
|
205
287
|
}
|
|
206
288
|
|
|
207
|
-
// Findings
|
|
289
|
+
// Findings summary + list
|
|
290
|
+
lines.push(`${continuePrefix}${formatFindingSummary(findings, theme)}`);
|
|
291
|
+
|
|
208
292
|
if (findings.length > 0) {
|
|
209
293
|
lines.push(`${continuePrefix}`); // Spacing
|
|
210
294
|
lines.push(...renderFindings(findings, continuePrefix, expanded, theme));
|
|
@@ -228,8 +312,10 @@ function renderFindings(
|
|
|
228
312
|
for (let i = 0; i < displayCount; i++) {
|
|
229
313
|
const finding = findings[i];
|
|
230
314
|
const isLastFinding = i === displayCount - 1 && (expanded || findings.length <= 3);
|
|
231
|
-
const findingPrefix = isLastFinding
|
|
232
|
-
|
|
315
|
+
const findingPrefix = isLastFinding
|
|
316
|
+
? `${theme.boxSharp.bottomLeft}${theme.boxSharp.horizontal}`
|
|
317
|
+
: `${theme.boxSharp.teeRight}${theme.boxSharp.horizontal}`;
|
|
318
|
+
const findingContinue = isLastFinding ? " " : `${theme.boxSharp.vertical} `;
|
|
233
319
|
|
|
234
320
|
const priority = PRIORITY_LABELS[finding.priority] ?? "P?";
|
|
235
321
|
const color = finding.priority === 0 ? "error" : finding.priority === 1 ? "warning" : "muted";
|
|
@@ -251,7 +337,9 @@ function renderFindings(
|
|
|
251
337
|
}
|
|
252
338
|
|
|
253
339
|
if (!expanded && findings.length > 3) {
|
|
254
|
-
lines.push(
|
|
340
|
+
lines.push(
|
|
341
|
+
`${continuePrefix}${theme.fg("dim", `${theme.format.ellipsis} ${findings.length - 3} more findings`)}`,
|
|
342
|
+
);
|
|
255
343
|
}
|
|
256
344
|
|
|
257
345
|
return lines;
|
|
@@ -262,23 +350,24 @@ function renderFindings(
|
|
|
262
350
|
*/
|
|
263
351
|
function renderAgentResult(result: SingleResult, isLast: boolean, expanded: boolean, theme: Theme): string[] {
|
|
264
352
|
const lines: string[] = [];
|
|
265
|
-
const prefix = isLast
|
|
266
|
-
|
|
353
|
+
const prefix = isLast
|
|
354
|
+
? `${theme.boxSharp.bottomLeft}${theme.boxSharp.horizontal}`
|
|
355
|
+
: `${theme.boxSharp.teeRight}${theme.boxSharp.horizontal}`;
|
|
356
|
+
const continuePrefix = isLast ? " " : `${theme.boxSharp.vertical} `;
|
|
267
357
|
|
|
268
358
|
const aborted = result.aborted ?? false;
|
|
269
359
|
const success = !aborted && result.exitCode === 0;
|
|
270
|
-
const icon = aborted ?
|
|
360
|
+
const icon = aborted ? theme.status.aborted : success ? theme.status.success : theme.status.error;
|
|
271
361
|
const iconColor = success ? "success" : "error";
|
|
272
362
|
const statusText = aborted ? "aborted" : success ? "done" : "failed";
|
|
273
363
|
|
|
274
364
|
// Main status line - include index for Output tool ID derivation
|
|
275
365
|
const agentId = `${result.agent}(${result.index})`;
|
|
276
|
-
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", agentId)}`;
|
|
277
|
-
statusLine += `: ${theme.fg(iconColor, statusText)}`;
|
|
366
|
+
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", agentId)} ${formatBadge(statusText, iconColor, theme)}`;
|
|
278
367
|
if (result.tokens > 0) {
|
|
279
|
-
statusLine +=
|
|
368
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", `${formatTokens(result.tokens)} tokens`)}`;
|
|
280
369
|
}
|
|
281
|
-
statusLine +=
|
|
370
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", formatDuration(result.durationMs))}`;
|
|
282
371
|
|
|
283
372
|
if (result.truncated) {
|
|
284
373
|
statusLine += ` ${theme.fg("warning", "[truncated]")}`;
|
|
@@ -299,8 +388,9 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
|
|
|
299
388
|
}
|
|
300
389
|
if (reportFindingData && reportFindingData.length > 0) {
|
|
301
390
|
lines.push(
|
|
302
|
-
`${continuePrefix}${theme.fg("warning",
|
|
391
|
+
`${continuePrefix}${theme.fg("warning", theme.status.warning)} ${theme.fg("dim", "Review summary missing (submit_review not called)")}`,
|
|
303
392
|
);
|
|
393
|
+
lines.push(`${continuePrefix}${formatFindingSummary(reportFindingData, theme)}`);
|
|
304
394
|
lines.push(`${continuePrefix}`); // Spacing
|
|
305
395
|
lines.push(...renderFindings(reportFindingData, continuePrefix, expanded, theme));
|
|
306
396
|
return lines;
|
|
@@ -339,21 +429,12 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
|
|
|
339
429
|
|
|
340
430
|
// Fallback to output preview if no custom rendering
|
|
341
431
|
if (!hasCustomRendering) {
|
|
342
|
-
|
|
343
|
-
const previewCount = expanded ? 8 : 3;
|
|
344
|
-
|
|
345
|
-
for (const line of outputLines.slice(0, previewCount)) {
|
|
346
|
-
lines.push(`${continuePrefix}${theme.fg("dim", truncate(line, 70))}`);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if (outputLines.length > previewCount) {
|
|
350
|
-
lines.push(`${continuePrefix}${theme.fg("dim", `... ${outputLines.length - previewCount} more lines`)}`);
|
|
351
|
-
}
|
|
432
|
+
lines.push(...renderOutputSection(result.output, continuePrefix, expanded, theme, 3, 12));
|
|
352
433
|
}
|
|
353
434
|
|
|
354
435
|
// Error message
|
|
355
436
|
if (result.error && !success) {
|
|
356
|
-
lines.push(`${continuePrefix}${theme.fg("error", truncate(result.error, 70))}`);
|
|
437
|
+
lines.push(`${continuePrefix}${theme.fg("error", truncate(result.error, 70, theme.format.ellipsis))}`);
|
|
357
438
|
}
|
|
358
439
|
|
|
359
440
|
return lines;
|
|
@@ -367,13 +448,13 @@ export function renderResult(
|
|
|
367
448
|
options: RenderResultOptions,
|
|
368
449
|
theme: Theme,
|
|
369
450
|
): Component {
|
|
370
|
-
const { expanded, isPartial } = options;
|
|
451
|
+
const { expanded, isPartial, spinnerFrame } = options;
|
|
371
452
|
const details = result.details;
|
|
372
453
|
|
|
373
454
|
if (!details) {
|
|
374
455
|
// Fallback to simple text
|
|
375
456
|
const text = result.content.find((c) => c.type === "text")?.text || "";
|
|
376
|
-
return new Text(theme.fg("dim", truncate(text, 100)), 0, 0);
|
|
457
|
+
return new Text(theme.fg("dim", truncate(text, 100, theme.format.ellipsis)), 0, 0);
|
|
377
458
|
}
|
|
378
459
|
|
|
379
460
|
const lines: string[] = [];
|
|
@@ -382,7 +463,7 @@ export function renderResult(
|
|
|
382
463
|
// Streaming progress view
|
|
383
464
|
details.progress.forEach((progress, i) => {
|
|
384
465
|
const isLast = i === details.progress!.length - 1;
|
|
385
|
-
lines.push(...renderAgentProgress(progress, isLast, expanded, theme));
|
|
466
|
+
lines.push(...renderAgentProgress(progress, isLast, expanded, theme, spinnerFrame));
|
|
386
467
|
});
|
|
387
468
|
} else if (details.results.length > 0) {
|
|
388
469
|
// Final results view
|
|
@@ -407,7 +488,7 @@ export function renderResult(
|
|
|
407
488
|
if (failCount > 0) {
|
|
408
489
|
summary += theme.fg("error", `${failCount} failed`);
|
|
409
490
|
}
|
|
410
|
-
summary +=
|
|
491
|
+
summary += `${theme.sep.dot}${theme.fg("dim", formatDuration(details.totalDurationMs))}`;
|
|
411
492
|
lines.push(summary);
|
|
412
493
|
|
|
413
494
|
// Artifacts suppressed from user view - available via session file
|
|
@@ -1,17 +1,9 @@
|
|
|
1
|
+
import type { Usage } from "@oh-my-pi/pi-ai";
|
|
1
2
|
import { type Static, Type } from "@sinclair/typebox";
|
|
2
3
|
|
|
3
4
|
/** Source of an agent definition */
|
|
4
5
|
export type AgentSource = "bundled" | "user" | "project";
|
|
5
6
|
|
|
6
|
-
/** Single task item for parallel execution */
|
|
7
|
-
export const taskItemSchema = Type.Object({
|
|
8
|
-
agent: Type.String({ description: "Agent name" }),
|
|
9
|
-
task: Type.String({ description: "Task description for the agent" }),
|
|
10
|
-
model: Type.Optional(Type.String({ description: "Model override for this task" })),
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
export type TaskItem = Static<typeof taskItemSchema>;
|
|
14
|
-
|
|
15
7
|
/** Maximum tasks per call */
|
|
16
8
|
export const MAX_PARALLEL_TASKS = 32;
|
|
17
9
|
|
|
@@ -36,6 +28,15 @@ export const OMP_BLOCKED_AGENT_ENV = "OMP_BLOCKED_AGENT";
|
|
|
36
28
|
/** Environment variable containing allowed spawn list (propagated to subprocesses) */
|
|
37
29
|
export const OMP_SPAWNS_ENV = "OMP_SPAWNS";
|
|
38
30
|
|
|
31
|
+
/** Single task item for parallel execution */
|
|
32
|
+
export const taskItemSchema = Type.Object({
|
|
33
|
+
agent: Type.String({ description: "Agent name" }),
|
|
34
|
+
task: Type.String({ description: "Task description for the agent" }),
|
|
35
|
+
model: Type.Optional(Type.String({ description: "Model override for this task" })),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export type TaskItem = Static<typeof taskItemSchema>;
|
|
39
|
+
|
|
39
40
|
/** Task tool parameters */
|
|
40
41
|
export const taskSchema = Type.Object({
|
|
41
42
|
context: Type.Optional(Type.String({ description: "Shared context prepended to all task prompts" })),
|
|
@@ -121,6 +122,8 @@ export interface SingleResult {
|
|
|
121
122
|
aborted?: boolean;
|
|
122
123
|
jsonlEvents?: string[];
|
|
123
124
|
artifactPaths?: { inputPath: string; outputPath: string; jsonlPath?: string };
|
|
125
|
+
/** Aggregated usage from the subprocess, if available. */
|
|
126
|
+
usage?: Usage;
|
|
124
127
|
/** Data extracted by registered subprocess tool handlers (keyed by tool name) */
|
|
125
128
|
extractedToolData?: Record<string, unknown[]>;
|
|
126
129
|
/** Output metadata for Output tool integration */
|
|
@@ -132,6 +135,8 @@ export interface TaskToolDetails {
|
|
|
132
135
|
projectAgentsDir: string | null;
|
|
133
136
|
results: SingleResult[];
|
|
134
137
|
totalDurationMs: number;
|
|
138
|
+
/** Aggregated usage across all subagents. */
|
|
139
|
+
usage?: Usage;
|
|
135
140
|
outputPaths?: string[];
|
|
136
141
|
progress?: AgentProgress[];
|
|
137
142
|
}
|