@fosterg4/pi-subagent 1.0.2 → 1.0.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/index.ts +36 -10
- package/package.json +1 -1
- package/utils.ts +37 -0
package/index.ts
CHANGED
|
@@ -35,12 +35,15 @@ import {
|
|
|
35
35
|
formatAgentList,
|
|
36
36
|
} from "./agents.ts";
|
|
37
37
|
import { type ValidationResult, validateSchema } from "./validate.ts";
|
|
38
|
+
import { fmt, usageLine, sumUsage } from "./utils.ts";
|
|
38
39
|
|
|
39
40
|
const MAX_PARALLEL_TASKS = 8;
|
|
40
41
|
const MAX_CONCURRENCY = 4;
|
|
41
42
|
const PER_TASK_OUTPUT_CAP = 50 * 1024;
|
|
42
43
|
|
|
44
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
43
45
|
|
|
46
|
+
interface UsageStats {
|
|
44
47
|
input: number;
|
|
45
48
|
output: number;
|
|
46
49
|
cacheRead: number;
|
|
@@ -954,11 +957,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
954
957
|
return theme.fg("error", "\u2717");
|
|
955
958
|
};
|
|
956
959
|
|
|
957
|
-
|
|
960
|
+
// --- Single mode ---
|
|
958
961
|
if (details.mode === "single" && details.results.length === 1) {
|
|
959
962
|
const r = details.results[0];
|
|
960
963
|
const status = getStatusText(r);
|
|
961
964
|
const finalOutput = getFinalOutputText(r.messages);
|
|
965
|
+
const usage = usageLine(r.usage);
|
|
966
|
+
const usg = usage ? theme.fg("dim", usage) : "";
|
|
962
967
|
|
|
963
968
|
if (expanded) {
|
|
964
969
|
const container = new Container();
|
|
@@ -969,6 +974,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
969
974
|
container.addChild(new Spacer(1));
|
|
970
975
|
container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
|
|
971
976
|
}
|
|
977
|
+
if (usg) {
|
|
978
|
+
container.addChild(new Spacer(1));
|
|
979
|
+
container.addChild(new Text(usg, 0, 0));
|
|
980
|
+
}
|
|
972
981
|
return container;
|
|
973
982
|
}
|
|
974
983
|
|
|
@@ -981,6 +990,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
981
990
|
} else {
|
|
982
991
|
text += `\n${theme.fg("muted", "(no output)")}`;
|
|
983
992
|
}
|
|
993
|
+
if (usg) text += `\n${usg}`;
|
|
984
994
|
return new Text(text, 0, 0);
|
|
985
995
|
}
|
|
986
996
|
|
|
@@ -991,6 +1001,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
991
1001
|
const allOk = details.results.every((r) => r.exitCode === 0);
|
|
992
1002
|
const icon = allOk ? theme.fg("success", "\u2713") : theme.fg("error", "\u2717");
|
|
993
1003
|
const steps = details.results.map((r) => r.agent).join(" \u2192 ");
|
|
1004
|
+
const total = sumUsage(details.results);
|
|
1005
|
+
const totalUsg = usageLine(total);
|
|
994
1006
|
|
|
995
1007
|
if (expanded) {
|
|
996
1008
|
const container = new Container();
|
|
@@ -999,18 +1011,19 @@ export default function (pi: ExtensionAPI) {
|
|
|
999
1011
|
);
|
|
1000
1012
|
for (const r of details.results) {
|
|
1001
1013
|
const out = getFinalOutputText(r.messages);
|
|
1014
|
+
const stepUsage = usageLine(r.usage);
|
|
1015
|
+
const stepUsg = stepUsage ? theme.fg("dim", stepUsage) : "";
|
|
1016
|
+
const label = `${getStatusText(r)} ${theme.fg("accent", r.agent)}${r.model ? theme.fg("muted", ` \u00B7 ${r.model}`) : ""}${stepUsg ? " " + stepUsg : ""}`;
|
|
1002
1017
|
if (out) {
|
|
1003
1018
|
container.addChild(new Spacer(1));
|
|
1004
|
-
container.addChild(
|
|
1005
|
-
new Text(
|
|
1006
|
-
`${getStatusText(r)} ${theme.fg("accent", r.agent)}${r.model ? theme.fg("muted", ` \u00B7 ${r.model}`) : ""}`,
|
|
1007
|
-
0,
|
|
1008
|
-
0,
|
|
1009
|
-
),
|
|
1010
|
-
);
|
|
1019
|
+
container.addChild(new Text(label, 0, 0));
|
|
1011
1020
|
container.addChild(new Markdown(out.trim(), 0, 0, mdTheme));
|
|
1012
1021
|
}
|
|
1013
1022
|
}
|
|
1023
|
+
if (totalUsg && details.results.length > 1) {
|
|
1024
|
+
container.addChild(new Spacer(1));
|
|
1025
|
+
container.addChild(new Text(totalUsg, 0, 0));
|
|
1026
|
+
}
|
|
1014
1027
|
return container;
|
|
1015
1028
|
}
|
|
1016
1029
|
|
|
@@ -1023,6 +1036,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1023
1036
|
} else {
|
|
1024
1037
|
text += `\n${theme.fg("muted", "(no output)")}`;
|
|
1025
1038
|
}
|
|
1039
|
+
if (totalUsg) text += `\n${totalUsg}`;
|
|
1026
1040
|
return new Text(text, 0, 0);
|
|
1027
1041
|
}
|
|
1028
1042
|
|
|
@@ -1039,6 +1053,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
1039
1053
|
|
|
1040
1054
|
if (expanded && running === 0) {
|
|
1041
1055
|
const container = new Container();
|
|
1056
|
+
const total = sumUsage(details.results);
|
|
1057
|
+
const totalUsg = usageLine(total);
|
|
1042
1058
|
container.addChild(
|
|
1043
1059
|
new Text(
|
|
1044
1060
|
`${icon} ${theme.fg("accent", `${done} tasks`)}`,
|
|
@@ -1048,11 +1064,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
1048
1064
|
);
|
|
1049
1065
|
for (const r of details.results) {
|
|
1050
1066
|
const out = getFinalOutputText(r.messages);
|
|
1067
|
+
const stepUsage = usageLine(r.usage);
|
|
1068
|
+
const stepUsg = stepUsage ? theme.fg("dim", stepUsage) : "";
|
|
1051
1069
|
if (out) {
|
|
1052
1070
|
container.addChild(new Spacer(1));
|
|
1053
1071
|
container.addChild(
|
|
1054
1072
|
new Text(
|
|
1055
|
-
`${getStatusText(r)} ${theme.fg("accent", r.agent)}`,
|
|
1073
|
+
`${getStatusText(r)} ${theme.fg("accent", r.agent)}${stepUsg ? " " + stepUsg : ""}`,
|
|
1056
1074
|
0,
|
|
1057
1075
|
0,
|
|
1058
1076
|
),
|
|
@@ -1060,11 +1078,19 @@ export default function (pi: ExtensionAPI) {
|
|
|
1060
1078
|
container.addChild(new Markdown(out.trim(), 0, 0, mdTheme));
|
|
1061
1079
|
}
|
|
1062
1080
|
}
|
|
1081
|
+
if (totalUsg && details.results.length > 1) {
|
|
1082
|
+
container.addChild(new Spacer(1));
|
|
1083
|
+
container.addChild(new Text(totalUsg, 0, 0));
|
|
1084
|
+
}
|
|
1063
1085
|
return container;
|
|
1064
1086
|
}
|
|
1065
1087
|
|
|
1088
|
+
const usg = usageLine(sumUsage(details.results));
|
|
1066
1089
|
let text = `${icon} ${theme.fg("accent", `${done}/${details.results.length} tasks`)}`;
|
|
1067
|
-
if (running === 0
|
|
1090
|
+
if (running === 0) {
|
|
1091
|
+
if (usg) text += `\n${usg}`;
|
|
1092
|
+
if (!expanded) text += theme.fg("muted", " (Ctrl+O to expand)");
|
|
1093
|
+
}
|
|
1068
1094
|
return new Text(text, 0, 0);
|
|
1069
1095
|
}
|
|
1070
1096
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fosterg4/pi-subagent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Delegate tasks to specialized subagents with isolated context windows, structured JSON handoff, contract schemas, and live TUI streaming",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
package/utils.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared formatting helpers — testable without pi runtime deps
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { UsageStats } from "./index.ts";
|
|
6
|
+
|
|
7
|
+
export function fmt(n: number): string {
|
|
8
|
+
if (n < 1000) return n.toString();
|
|
9
|
+
if (n < 10000) return (n / 1000).toFixed(1) + "k";
|
|
10
|
+
if (n < 1000000) return Math.round(n / 1000) + "k";
|
|
11
|
+
return (n / 1000000).toFixed(1) + "M";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function usageLine(u: UsageStats): string {
|
|
15
|
+
const parts: string[] = [];
|
|
16
|
+
if (u.input) parts.push("\u2191" + fmt(u.input));
|
|
17
|
+
if (u.output) parts.push("\u2193" + fmt(u.output));
|
|
18
|
+
if (u.cacheRead) {
|
|
19
|
+
parts.push("R" + fmt(u.cacheRead));
|
|
20
|
+
const total = u.input + u.cacheRead;
|
|
21
|
+
if (total > 0) parts.push("CH" + ((u.cacheRead / total) * 100).toFixed(1) + "%");
|
|
22
|
+
}
|
|
23
|
+
if (u.cost) parts.push("$" + u.cost.toFixed(4));
|
|
24
|
+
return parts.join(" ");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function sumUsage(results: ReadonlyArray<{ usage: UsageStats }>): UsageStats {
|
|
28
|
+
const u: UsageStats = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 };
|
|
29
|
+
for (const r of results) {
|
|
30
|
+
u.input += r.usage.input;
|
|
31
|
+
u.output += r.usage.output;
|
|
32
|
+
u.cacheRead += r.usage.cacheRead;
|
|
33
|
+
u.cacheWrite += r.usage.cacheWrite;
|
|
34
|
+
u.cost += r.usage.cost;
|
|
35
|
+
}
|
|
36
|
+
return u;
|
|
37
|
+
}
|