@arhen/pi-core-subagent 1.3.53 → 1.3.54

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arhen/pi-core-subagent",
3
- "version": "1.3.53",
3
+ "version": "1.3.54",
4
4
  "type": "module",
5
5
  "description": "pi extension: fast in-process subagents with a dependency-graph scheduler (needs edges gate tasks and carry upstream output into dependent prompts), plus background runs, intercom and agent-to-agent mailbox. Leader defines agents inline.",
6
6
  "license": "MIT",
package/src/format.ts CHANGED
@@ -114,7 +114,8 @@ export function compactLines(run: RunSnapshot): string[] {
114
114
  if (run.tasks.length > MAX_TASKS) lines.push(`… +${run.tasks.length - MAX_TASKS} more`);
115
115
  return lines;
116
116
  }
117
- const WIDGET_MAX_LINES = 10;
117
+ // header + 4 task rows; live tasks are ordered first, so the cap only ever hides finished work
118
+ const WIDGET_MAX_LINES = 5;
118
119
 
119
120
  export class SubagentsWidget implements Component {
120
121
  constructor(
@@ -139,17 +140,21 @@ export class SubagentsWidget implements Component {
139
140
  ),
140
141
  ];
141
142
  const budget = WIDGET_MAX_LINES - 1;
143
+ // live tasks first so the budget never hides work in progress
144
+ const all = runs.flatMap((run) => run.tasks);
145
+ const ordered = [
146
+ ...all.filter((t) => !TERMINAL.includes(t.status)),
147
+ ...all.filter((t) => TERMINAL.includes(t.status)),
148
+ ];
142
149
  let shown = 0;
143
- outer: for (const run of runs) {
144
- for (const task of run.tasks) {
145
- if (shown >= budget) break outer;
146
- shown += 1;
147
- const activity = task.lastActivity ? `${this.theme.fg("dim", `→ ${task.lastActivity}`)} · ` : "";
150
+ for (const task of ordered) {
151
+ if (shown >= budget) break;
152
+ shown += 1;
153
+ const activity = task.lastActivity ? `${this.theme.fg("dim", `→ ${task.lastActivity}`)} · ` : "";
148
154
 
149
- lines.push(
150
- truncateToWidth(`${this.theme.fg("dim", "├─")} ${themedTaskLine(task, this.theme, activity)}`, width, "…"),
151
- );
152
- }
155
+ lines.push(
156
+ truncateToWidth(`${this.theme.fg("dim", "├─")} ${themedTaskLine(task, this.theme, activity)}`, width, "…"),
157
+ );
153
158
  }
154
159
  const hidden = total - shown;
155
160
  if (hidden > 0) {
package/src/index.ts CHANGED
@@ -140,6 +140,7 @@ export default function (pi: ExtensionAPI) {
140
140
  "Define each agent inline: invented name, focused system prompt, read-only by default (write:true to edit). A matched agent file takes over (see description); matching is by description, not name — name the agent whatever fits the goal.",
141
141
  "Right after spawning, call subagent_status(runId) ONCE before any other work — a child that died on spawn (or never started) is invisible until far later otherwise. If it shows a task failed/never started, fix or respawn immediately.",
142
142
  "Never block with nothing to do: if you have no work left after spawning, end your turn — completion notifies you and wakes a fresh turn with the results. await_subagent/autoAwait while idle only burns time and tokens.",
143
+ "A failed task interrupts you immediately as a steering message — handle it in the same turn (resume, swap model, re-dispatch) instead of finishing the plan on a broken intermediate result. Completes and aborts queue as follow-ups.",
143
144
  "autoAwait:true only when this SAME turn must consume the result immediately. await_subagent is for syncing with your own parallel work — not the default follow-up to a spawn.",
144
145
  "A task that failed mid-work (provider error, rate limit, timeout) keeps its session file and branch: resume_subagent(runId, taskId, model?) revives it with full context — prefer that over respawning. Respawn only when it never started (no session file).",
145
146
  ],
package/src/manager.ts CHANGED
@@ -437,7 +437,9 @@ export class SubagentManager {
437
437
  }
438
438
 
439
439
  private deliverMode(kind: string, task: TaskSnapshot): "steer" | "followUp" {
440
- return isStartupFailure(task, kind) ? "steer" : "followUp";
440
+ // failures interrupt the leader's turn: it must decide immediately (resume, swap model, respawn)
441
+ // instead of finding out after its own turn ended. Aborts are user-initiated, so they queue.
442
+ return kind === "failed" || isStartupFailure(task, kind) ? "steer" : "followUp";
441
443
  }
442
444
 
443
445
  private notifyTask(run: RunSnapshot, task: TaskSnapshot, kind: "completed" | "failed" | "aborted"): void {
@@ -470,7 +472,7 @@ export class SubagentManager {
470
472
  ? `A subagent is asking you a question (task ${extra?.taskId}): ${extra?.question ?? ""}\nReply with reply_subagent(runId: "${run.id}", taskId: "${extra?.taskId}", message: ...).`
471
473
  : makeNotice(run, kind);
472
474
  try {
473
- this.pi.sendUserMessage(body, { deliverAs: "followUp" });
475
+ this.pi.sendUserMessage(body, { deliverAs: kind === "failed" ? "steer" : "followUp" });
474
476
  } catch {}
475
477
  this.emit("subagent:notification", { runId: run.id, kind, body });
476
478
  }