pi-subagents 0.11.7 → 0.11.8

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 CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.11.8] - 2026-03-21
6
+
7
+ ### Added
8
+ - Prompt-template delegation bridge now supports parallel task execution: accepts `tasks` array payloads, emits per-task `parallelResults` with individual error/success states, and streams per-task progress updates with `taskProgress` entries.
9
+
5
10
  ## [0.11.7] - 2026-03-20
6
11
 
7
12
  ### Changed
package/index.ts CHANGED
@@ -142,8 +142,23 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
142
142
  const promptTemplateBridge = registerPromptTemplateDelegationBridge({
143
143
  events: pi.events,
144
144
  getContext: () => state.lastUiContext,
145
- execute: async (requestId, request, signal, ctx, onUpdate) =>
146
- executor.execute(
145
+ execute: async (requestId, request, signal, ctx, onUpdate) => {
146
+ if (request.tasks && request.tasks.length > 0) {
147
+ return executor.execute(
148
+ requestId,
149
+ {
150
+ tasks: request.tasks,
151
+ context: request.context,
152
+ cwd: request.cwd,
153
+ async: false,
154
+ clarify: false,
155
+ },
156
+ signal,
157
+ onUpdate,
158
+ ctx,
159
+ );
160
+ }
161
+ return executor.execute(
147
162
  requestId,
148
163
  {
149
164
  agent: request.agent,
@@ -157,7 +172,8 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
157
172
  signal,
158
173
  onUpdate,
159
174
  ctx,
160
- ),
175
+ );
176
+ },
161
177
  });
162
178
 
163
179
  const tool: ToolDefinition<typeof SubagentParams, Details> = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-subagents",
3
- "version": "0.11.7",
3
+ "version": "0.11.8",
4
4
  "description": "Pi extension for delegating tasks to subagents with chains, parallel execution, and TUI clarification",
5
5
  "author": "Nico Bailon",
6
6
  "license": "MIT",
@@ -4,10 +4,24 @@ export const PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT = "prompt-template:subagent
4
4
  export const PROMPT_TEMPLATE_SUBAGENT_UPDATE_EVENT = "prompt-template:subagent:update";
5
5
  export const PROMPT_TEMPLATE_SUBAGENT_CANCEL_EVENT = "prompt-template:subagent:cancel";
6
6
 
7
+ export interface PromptTemplateDelegationTask {
8
+ agent: string;
9
+ task: string;
10
+ model?: string;
11
+ }
12
+
13
+ export interface PromptTemplateDelegationParallelResult {
14
+ agent: string;
15
+ messages: unknown[];
16
+ isError: boolean;
17
+ errorText?: string;
18
+ }
19
+
7
20
  export interface PromptTemplateDelegationRequest {
8
21
  requestId: string;
9
22
  agent: string;
10
23
  task: string;
24
+ tasks?: PromptTemplateDelegationTask[];
11
25
  context: "fresh" | "fork";
12
26
  model: string;
13
27
  cwd: string;
@@ -15,10 +29,23 @@ export interface PromptTemplateDelegationRequest {
15
29
 
16
30
  export interface PromptTemplateDelegationResponse extends PromptTemplateDelegationRequest {
17
31
  messages: unknown[];
32
+ parallelResults?: PromptTemplateDelegationParallelResult[];
18
33
  isError: boolean;
19
34
  errorText?: string;
20
35
  }
21
36
 
37
+ export interface PromptTemplateDelegationTaskProgress {
38
+ index?: number;
39
+ agent: string;
40
+ status?: string;
41
+ currentTool?: string;
42
+ currentToolArgs?: string;
43
+ recentOutput?: string;
44
+ toolCount?: number;
45
+ durationMs?: number;
46
+ tokens?: number;
47
+ }
48
+
22
49
  export interface PromptTemplateDelegationUpdate {
23
50
  requestId: string;
24
51
  currentTool?: string;
@@ -27,6 +54,7 @@ export interface PromptTemplateDelegationUpdate {
27
54
  toolCount?: number;
28
55
  durationMs?: number;
29
56
  tokens?: number;
57
+ taskProgress?: PromptTemplateDelegationTaskProgress[];
30
58
  }
31
59
 
32
60
  export interface PromptTemplateBridgeEvents {
@@ -39,13 +67,21 @@ interface PromptTemplateBridgeResult {
39
67
  content?: unknown;
40
68
  details?: {
41
69
  results?: Array<{
70
+ agent?: string;
42
71
  messages?: unknown[];
72
+ exitCode?: number;
73
+ error?: string;
43
74
  }>;
44
75
  progress?: Array<{
76
+ index?: number;
77
+ agent?: string;
78
+ status?: string;
45
79
  currentTool?: string;
46
80
  currentToolArgs?: string;
47
81
  recentOutput?: string[];
48
82
  toolCount?: number;
83
+ durationMs?: number;
84
+ tokens?: number;
49
85
  }>;
50
86
  };
51
87
  }
@@ -62,15 +98,45 @@ export interface PromptTemplateBridgeOptions<Ctx extends { cwd?: string }> {
62
98
  ) => Promise<PromptTemplateBridgeResult>;
63
99
  }
64
100
 
101
+ function parseDelegationTasks(tasks: unknown): PromptTemplateDelegationTask[] {
102
+ if (!Array.isArray(tasks)) return [];
103
+ const parsed: PromptTemplateDelegationTask[] = [];
104
+ for (const item of tasks) {
105
+ if (!item || typeof item !== "object") return [];
106
+ const value = item as Partial<PromptTemplateDelegationTask>;
107
+ if (typeof value.agent !== "string" || !value.agent.trim()) return [];
108
+ if (typeof value.task !== "string" || !value.task.trim()) return [];
109
+ const model = typeof value.model === "string" && value.model.trim().length > 0 ? value.model : undefined;
110
+ parsed.push({
111
+ agent: value.agent,
112
+ task: value.task,
113
+ ...(model ? { model } : {}),
114
+ });
115
+ }
116
+ return parsed;
117
+ }
118
+
65
119
  export function parsePromptTemplateRequest(data: unknown): PromptTemplateDelegationRequest | undefined {
66
120
  if (!data || typeof data !== "object") return undefined;
67
- const value = data as Partial<PromptTemplateDelegationRequest>;
68
- if (!value.requestId || !value.agent || !value.task || !value.model || !value.cwd) return undefined;
121
+ const value = data as Partial<PromptTemplateDelegationRequest> & { tasks?: unknown };
122
+ if (typeof value.requestId !== "string" || !value.requestId) return undefined;
123
+ if (typeof value.model !== "string" || !value.model) return undefined;
124
+ if (typeof value.cwd !== "string" || !value.cwd) return undefined;
69
125
  if (value.context !== "fresh" && value.context !== "fork") return undefined;
126
+ const tasks = parseDelegationTasks(value.tasks);
127
+ const hasSingle =
128
+ typeof value.agent === "string" &&
129
+ value.agent.length > 0 &&
130
+ typeof value.task === "string" &&
131
+ value.task.length > 0;
132
+ if (!hasSingle && tasks.length === 0) return undefined;
133
+
134
+ const fallbackTask = tasks[0];
70
135
  return {
71
136
  requestId: value.requestId,
72
- agent: value.agent,
73
- task: value.task,
137
+ agent: hasSingle ? value.agent : fallbackTask!.agent,
138
+ task: hasSingle ? value.task : fallbackTask!.task,
139
+ ...(tasks.length > 0 ? { tasks } : {}),
74
140
  context: value.context,
75
141
  model: value.model,
76
142
  cwd: value.cwd,
@@ -90,16 +156,31 @@ export function firstTextContent(content: unknown): string | undefined {
90
156
 
91
157
  function toDelegationUpdate(requestId: string, update: PromptTemplateBridgeResult): PromptTemplateDelegationUpdate | undefined {
92
158
  const progress = update.details?.progress?.[0];
93
- if (!progress) return undefined;
94
- const lastOutput = progress.recentOutput?.[progress.recentOutput.length - 1];
159
+ const taskProgress = update.details?.progress?.map((entry) => {
160
+ const lastOutput = entry.recentOutput?.[entry.recentOutput.length - 1];
161
+ return {
162
+ index: entry.index,
163
+ agent: entry.agent ?? "delegate",
164
+ status: entry.status,
165
+ currentTool: entry.currentTool,
166
+ currentToolArgs: entry.currentToolArgs,
167
+ recentOutput: lastOutput && lastOutput !== "(running...)" ? lastOutput : undefined,
168
+ toolCount: entry.toolCount,
169
+ durationMs: entry.durationMs,
170
+ tokens: entry.tokens,
171
+ };
172
+ });
173
+ if (!progress && (!taskProgress || taskProgress.length === 0)) return undefined;
174
+ const lastOutput = progress?.recentOutput?.[progress.recentOutput.length - 1];
95
175
  return {
96
176
  requestId,
97
- currentTool: progress.currentTool,
98
- currentToolArgs: progress.currentToolArgs,
177
+ currentTool: progress?.currentTool,
178
+ currentToolArgs: progress?.currentToolArgs,
99
179
  recentOutput: lastOutput && lastOutput !== "(running...)" ? lastOutput : undefined,
100
- toolCount: progress.toolCount,
101
- durationMs: (progress as { durationMs?: number }).durationMs,
102
- tokens: (progress as { tokens?: number }).tokens,
180
+ toolCount: progress?.toolCount,
181
+ durationMs: progress?.durationMs,
182
+ tokens: progress?.tokens,
183
+ taskProgress,
103
184
  };
104
185
  }
105
186
 
@@ -177,9 +258,31 @@ export function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: strin
177
258
  },
178
259
  );
179
260
  const messages = result.details?.results?.[0]?.messages ?? [];
261
+ const parallelResults = request.tasks
262
+ ? request.tasks.map<PromptTemplateDelegationParallelResult>((task, index) => {
263
+ const step = result.details?.results?.[index];
264
+ if (!step) {
265
+ return {
266
+ agent: task.agent,
267
+ messages: [],
268
+ isError: true,
269
+ errorText: "Missing result for delegated parallel task.",
270
+ };
271
+ }
272
+ const exitCode = typeof step.exitCode === "number" ? step.exitCode : undefined;
273
+ const errorText = step.error;
274
+ return {
275
+ agent: step.agent ?? task.agent,
276
+ messages: step.messages ?? [],
277
+ isError: (exitCode !== undefined && exitCode !== 0) || !!errorText,
278
+ errorText: errorText || undefined,
279
+ };
280
+ })
281
+ : undefined;
180
282
  const response: PromptTemplateDelegationResponse = {
181
283
  ...request,
182
284
  messages,
285
+ ...(parallelResults ? { parallelResults } : {}),
183
286
  isError: result.isError === true,
184
287
  errorText: result.isError ? firstTextContent(result.content) : undefined,
185
288
  };