@ian-pascoe/pi-minimal-subagents 0.15.0 → 0.16.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/README.md
CHANGED
|
@@ -276,10 +276,10 @@ creation; reloading does not silently broaden them. The default maximum depth
|
|
|
276
276
|
is two levels beneath the interactive Root Agent.
|
|
277
277
|
|
|
278
278
|
The extension registers six coordinator tools for the Root Agent and fanout
|
|
279
|
-
children: `subagent`, `agent_message`, `subagent_wait`, `subagent_status`,
|
|
280
|
-
`subagent_cancel`, and `subagent_delete`.
|
|
281
|
-
|
|
282
|
-
|
|
279
|
+
children below the depth cap: `subagent`, `agent_message`, `subagent_wait`, `subagent_status`,
|
|
280
|
+
`subagent_cancel`, and `subagent_delete`. Children that cannot spawn (delegation
|
|
281
|
+
`none`, or fanout at the depth cap) have no children to wait on or inspect, so they
|
|
282
|
+
receive only `agent_message`.
|
|
283
283
|
|
|
284
284
|
A running child's `latest_activity_at` advances with the timestamps of its latest
|
|
285
285
|
messages and tool results. Targeted `subagent_status` includes `recent_activity`, a bounded tail of message
|
|
@@ -288,7 +288,9 @@ assistant message but omits image data. Timeout Wait Events carry only a compact
|
|
|
288
288
|
progress snapshot. Children target only direct children; the Root Agent
|
|
289
289
|
may inspect any descendant. Model-facing status reports a `child_count` but no
|
|
290
290
|
nested `children` summaries. Reported `usage` always includes `cacheWrite1h`
|
|
291
|
-
and `reasoning`, as `0` when the provider reports none.
|
|
291
|
+
and `reasoning`, as `0` when the provider reports none. Tool-result text and
|
|
292
|
+
`structuredContent` round every `usage.cost` field to six decimal places of USD;
|
|
293
|
+
exact values stay in session data. `subagent_cancel`
|
|
292
294
|
lists in `affected_agent_ids` only agents whose active turns it cancelled.
|
|
293
295
|
|
|
294
296
|
`session_context` defaults to `omit`: the child starts with only its system
|
package/package.json
CHANGED
|
@@ -353,7 +353,7 @@ export function buildSubagentSystemPrompt(
|
|
|
353
353
|
): string {
|
|
354
354
|
const coordinatorBoundary = options.canSpawn
|
|
355
355
|
? "Coordinator tools support subagent, agent_message, subagent_wait, subagent_status, subagent_cancel, and subagent_delete. Wait, status, cancel, and delete target direct children only; recursive cancel and delete may affect a child's subtree."
|
|
356
|
-
: "Coordinator tools support agent_message
|
|
356
|
+
: "Coordinator tools support only agent_message; you have no children to wait on or inspect.";
|
|
357
357
|
const delegationBoundary = options.canSpawn
|
|
358
358
|
? [
|
|
359
359
|
"You have explicit fanout responsibility for this assigned task.",
|
|
@@ -272,7 +272,10 @@ const CoordinatorWaitSourceOutputSchema = {
|
|
|
272
272
|
source_turn_id: Type.String(),
|
|
273
273
|
};
|
|
274
274
|
|
|
275
|
-
/**
|
|
275
|
+
/**
|
|
276
|
+
* Final details schemas exposed to CodeMode for the six coordinator tools. `structuredContent`
|
|
277
|
+
* matches them with every `usage.cost` field rounded for presentation.
|
|
278
|
+
*/
|
|
276
279
|
export const CoordinatorToolOutputSchemas = {
|
|
277
280
|
subagent: Type.Object({
|
|
278
281
|
agent_id: Type.String(),
|
|
@@ -13,6 +13,7 @@ import type { TUI } from "@earendil-works/pi-tui";
|
|
|
13
13
|
import type { MinimalSubagentsCoordinator } from "./minimal-subagents-coordinator.js";
|
|
14
14
|
import { withTroubleshootingHint } from "./troubleshooting-skill.js";
|
|
15
15
|
import type { MinimalSubagentsModelRole } from "./minimal-subagents-config.js";
|
|
16
|
+
import { roundMinimalSubagentsUsageCosts } from "./minimal-subagents-usage.js";
|
|
16
17
|
import {
|
|
17
18
|
renderCoordinatorToolCall,
|
|
18
19
|
renderCoordinatorToolResult,
|
|
@@ -42,11 +43,8 @@ import type {
|
|
|
42
43
|
WaitResult,
|
|
43
44
|
} from "./minimal-subagents-types.js";
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"subagent_wait",
|
|
48
|
-
"subagent_status",
|
|
49
|
-
]);
|
|
46
|
+
/** A child that cannot spawn can never have children, so only adjacent messaging is useful. */
|
|
47
|
+
const NON_SPAWNING_CHILD_COORDINATOR_TOOL_NAMES = new Set(["agent_message"]);
|
|
50
48
|
|
|
51
49
|
/** Coordinator operations consumed by the six public coordinator tool definitions. */
|
|
52
50
|
export type CoordinatorToolOperations = Pick<
|
|
@@ -183,10 +181,28 @@ function createCoordinatorToolRendering(
|
|
|
183
181
|
};
|
|
184
182
|
}
|
|
185
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Serialize a tool result with every nested `usage` cost rounded for presentation. Exact values
|
|
186
|
+
* stay in `details`, the Registry, and session data, which never pass through here.
|
|
187
|
+
*/
|
|
188
|
+
function stringifyWithRoundedUsageCosts(
|
|
189
|
+
result: CoordinatorToolResultDetails,
|
|
190
|
+
space?: number,
|
|
191
|
+
): string {
|
|
192
|
+
// `JSON.stringify` types replacer values as `any`; a usage is recognized by key and `cost` object.
|
|
193
|
+
return JSON.stringify(
|
|
194
|
+
result,
|
|
195
|
+
(key, value) =>
|
|
196
|
+
key === "usage" && value?.cost ? roundMinimalSubagentsUsageCosts(value) : value,
|
|
197
|
+
space,
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
186
201
|
function structuredToolResult<TDetails extends CoordinatorToolResultDetails>(
|
|
187
202
|
result: TDetails,
|
|
188
203
|
): AgentToolResult<TDetails> {
|
|
189
|
-
|
|
204
|
+
// Presentation only: `details` keeps the exact values the session persists.
|
|
205
|
+
const json = stringifyWithRoundedUsageCosts(result, 2);
|
|
190
206
|
const truncated = truncateHead(json, {
|
|
191
207
|
maxBytes: DEFAULT_MAX_BYTES,
|
|
192
208
|
maxLines: DEFAULT_MAX_LINES,
|
|
@@ -380,7 +396,7 @@ export function createCoordinatorToolDefinitions(
|
|
|
380
396
|
? alreadyDeliveredContent(result)
|
|
381
397
|
: structuredToolResult(result).content,
|
|
382
398
|
details,
|
|
383
|
-
structuredContent: JSON.parse(
|
|
399
|
+
structuredContent: JSON.parse(stringifyWithRoundedUsageCosts(details)),
|
|
384
400
|
};
|
|
385
401
|
});
|
|
386
402
|
} finally {
|
|
@@ -483,5 +499,5 @@ export function createCoordinatorToolDefinitions(
|
|
|
483
499
|
const allowFanoutTools = options.allowFanoutTools ?? options.callerId === "root";
|
|
484
500
|
return allowFanoutTools
|
|
485
501
|
? coordinatorTools
|
|
486
|
-
: coordinatorTools.filter((tool) =>
|
|
502
|
+
: coordinatorTools.filter((tool) => NON_SPAWNING_CHILD_COORDINATOR_TOOL_NAMES.has(tool.name));
|
|
487
503
|
}
|
|
@@ -33,3 +33,33 @@ export function addMinimalSubagentsUsage(
|
|
|
33
33
|
},
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* USD decimal places kept in model-visible and structured usage costs. Six places is one
|
|
39
|
+
* millionth of a dollar: finer than any single turn's cost is worth reading, yet coarse enough to
|
|
40
|
+
* drop the binary-float tails that summing many per-message costs produces.
|
|
41
|
+
*/
|
|
42
|
+
export const MINIMAL_SUBAGENTS_COST_DECIMALS = 6;
|
|
43
|
+
|
|
44
|
+
const COST_SCALE = 10 ** MINIMAL_SUBAGENTS_COST_DECIMALS;
|
|
45
|
+
|
|
46
|
+
function roundCost(value: number): number {
|
|
47
|
+
return Number.isFinite(value) ? Math.round(value * COST_SCALE) / COST_SCALE : value;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Return a clone whose cost fields are rounded for presentation. Each field rounds independently
|
|
52
|
+
* from its exact value, so `total` stays within half a unit per summed field of the rounded sum.
|
|
53
|
+
*/
|
|
54
|
+
export function roundMinimalSubagentsUsageCosts(usage: Usage): Usage {
|
|
55
|
+
return {
|
|
56
|
+
...usage,
|
|
57
|
+
cost: {
|
|
58
|
+
input: roundCost(usage.cost.input),
|
|
59
|
+
output: roundCost(usage.cost.output),
|
|
60
|
+
cacheRead: roundCost(usage.cost.cacheRead),
|
|
61
|
+
cacheWrite: roundCost(usage.cost.cacheWrite),
|
|
62
|
+
total: roundCost(usage.cost.total),
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|