pi-better-subagents 0.1.26 → 0.1.28

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 CHANGED
@@ -127,6 +127,11 @@ const SUBAGENT_TOOLS = [
127
127
  "subagent_result",
128
128
  ];
129
129
 
130
+ const SUBAGENT_ORCHESTRATION_GUIDELINES = [
131
+ "When a structured plan is active, keep it as the parent-owned coordinator ledger: delegate bounded independent work, continue unblocked foreground work, and update the plan after integrating each result or failure.",
132
+ "Do not treat launching a subagent as completion of the parent milestone; relevant terminal results must be inspected and integrated before verification or completion.",
133
+ ];
134
+
130
135
  const GOAL_READY_EVENT = "pi-better-goal:ready";
131
136
  const GOAL_REGISTER_PROVIDER_EVENT = "pi-better-goal:register-provider";
132
137
  const goalReadySubscriptions = new WeakSet<ExtensionAPI>();
@@ -1267,7 +1272,8 @@ export default function (pi: ExtensionAPI) {
1267
1272
  promptGuidelines: [
1268
1273
  "Use subagent_spawn for independent work the user should not have to wait on. It returns at once with a run id; that return IS the deliverable — report the id to the user and continue.",
1269
1274
  "After subagent_spawn, do NOT call subagent_output or subagent_result in a loop to wait for the result, and do NOT sleep. The run completes on its own and reports back on the next turn.",
1270
- "Only call subagent_result / subagent_output when the user explicitly asks how a run is going or for its result.",
1275
+ "Call subagent_result after a completion or attention callback, or when the user explicitly asks for the result. Use subagent_output only when the user explicitly asks how a run is progressing; never use either tool to poll.",
1276
+ ...SUBAGENT_ORCHESTRATION_GUIDELINES,
1271
1277
  "The tools param is both the tool allowlist AND what determines which extensions load in the child (e.g. tools='read,bash,web_fetch' loads only the web-tools package). Ask for the tools the task needs and nothing more; clean:true gives a built-ins-only child. Pick a model with the model param (e.g. 'xai/grok-4.5@high'); providerless model patterns are resolved by Pi, while provider/model is deterministic and loads mapped provider extensions.",
1272
1278
  "By default the subagent is sandboxed (writes confined to its working dir, reads and network open) and triggers completion here on finish. Set callback:false to finish quietly — then read the result on demand via subagent_result.",
1273
1279
  "Use git_clone_workspace:true when the subagent will mutate Git in a sandbox. The parent prepares a disposable, self-contained clone with a real .git/ directory inside the sandbox root, so linked-worktree metadata outside the sandbox cannot stall the child.",
@@ -1336,6 +1342,7 @@ export default function (pi: ExtensionAPI) {
1336
1342
  "Use subagent_spawn_batch when you have several independent tasks to delegate. It returns immediately with a batch id and one run id per launched job.",
1337
1343
  "Each job is a normal subagent run; use subagent_result / subagent_output / subagent_stop with the individual run ids just like subagent_spawn.",
1338
1344
  "Do NOT poll for results. Each job reports back on its own when it finishes.",
1345
+ ...SUBAGENT_ORCHESTRATION_GUIDELINES,
1339
1346
  "By default the whole batch is rejected if there is not enough capacity. Set onCapacity to 'launch-available' to launch as many as fit and report the rest as skipped.",
1340
1347
  ],
1341
1348
  parameters: Type.Object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-better-subagents",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "description": "Pi extension for detached, sandboxed subagent runs that keep the foreground session free.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -918,7 +918,7 @@ function createOverlayComponent(
918
918
  width,
919
919
  deps.truncate,
920
920
  fg,
921
- { minRows: detailRows, bottomFooter: false, logTailRows },
921
+ { minRows: detailRows, maxRows: detailRows, bottomFooter: false, logTailRows },
922
922
  );
923
923
  } else {
924
924
  transcriptDetail = null;
@@ -1003,21 +1003,33 @@ function buildTranscriptDetailLines(
1003
1003
  width: number,
1004
1004
  truncate: (s: string, width: number) => string,
1005
1005
  fg: (color: string, value: string) => string,
1006
- options: { minRows?: number; bottomFooter?: boolean; logTailRows?: number } = {},
1006
+ options: { minRows?: number; maxRows?: number; bottomFooter?: boolean; logTailRows?: number } = {},
1007
1007
  ): string[] {
1008
1008
  const actions = [...(detail.footerActions ?? ["x close"]), "Esc close"].join(" · ");
1009
1009
  const tailRows = options.logTailRows ?? DEFAULT_LOG_TAIL_ROWS;
1010
- const shownTranscriptLines = transcriptLines.length ? transcriptLines.slice(-tailRows) : [" (no transcript yet)"];
1010
+ let shownTranscriptLines = transcriptLines.length ? transcriptLines.slice(-tailRows) : [" (no transcript yet)"];
1011
1011
  const lines: string[] = [
1012
1012
  fg("accent", rule(detail.title, width)),
1013
1013
  dim(` ← main · ${actions}`, fg),
1014
1014
  "",
1015
1015
  ` status ${fg(toneColor(detail.statusTone, detail.status), detail.status)}`,
1016
1016
  ];
1017
- if (detail.subtitle) lines.push(` summary ${detail.subtitle}`);
1018
- for (const item of detail.metadata) lines.push(` ${item.label.padEnd(8, " ").slice(0, 8)} ${item.value}`);
1019
- lines.push("", dim(section(`transcript · latest ${tailRows} rows`, width), fg));
1020
- if (detail.transcriptDiagnostic) lines.push(` ${dim(detail.transcriptDiagnostic, fg)}`);
1017
+ const optionalMetadata = [
1018
+ ...(detail.subtitle ? [` summary ${detail.subtitle}`] : []),
1019
+ ...detail.metadata.map((item) => ` ${item.label.padEnd(8, " ").slice(0, 8)} ${item.value}`),
1020
+ ];
1021
+ const transcriptHeader = ["", dim(section(`transcript · latest ${tailRows} rows`, width), fg)];
1022
+ if (detail.transcriptDiagnostic) transcriptHeader.push(` ${dim(detail.transcriptDiagnostic, fg)}`);
1023
+ if (options.maxRows !== undefined) {
1024
+ const fixedRows = lines.length + transcriptHeader.length + 1;
1025
+ const transcriptBudget = Math.max(1, options.maxRows - fixedRows);
1026
+ shownTranscriptLines = shownTranscriptLines.slice(-transcriptBudget);
1027
+ const metadataBudget = Math.max(0, options.maxRows - fixedRows - shownTranscriptLines.length);
1028
+ lines.push(...optionalMetadata.slice(0, metadataBudget));
1029
+ } else {
1030
+ lines.push(...optionalMetadata);
1031
+ }
1032
+ lines.push(...transcriptHeader);
1021
1033
  lines.push(...shownTranscriptLines);
1022
1034
  lines.push("");
1023
1035
  if (options.bottomFooter === false) return lines.map((line) => safeTruncate(line, width, truncate));