pi-subagents 0.9.2 → 0.10.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/CHANGELOG.md +24 -0
- package/README.md +41 -4
- package/async-execution.ts +64 -30
- package/chain-execution.ts +1 -1
- package/execution.ts +16 -1
- package/index.ts +90 -13
- package/package.json +11 -2
- package/parallel-utils.ts +93 -0
- package/render.ts +78 -8
- package/schemas.ts +1 -1
- package/settings.ts +16 -14
- package/skills.ts +25 -1
- package/subagent-runner.ts +360 -176
- package/utils.ts +23 -7
package/utils.ts
CHANGED
|
@@ -186,18 +186,29 @@ export function getDisplayItems(messages: Message[]): DisplayItem[] {
|
|
|
186
186
|
* Detect errors in subagent execution from messages (only errors with no subsequent success)
|
|
187
187
|
*/
|
|
188
188
|
export function detectSubagentError(messages: Message[]): ErrorInfo {
|
|
189
|
-
|
|
189
|
+
// Step 1: Find the last assistant message with text content.
|
|
190
|
+
// If the agent produced a text response after encountering errors,
|
|
191
|
+
// it had a chance to recover — only errors AFTER this point matter.
|
|
192
|
+
let lastAssistantTextIndex = -1;
|
|
190
193
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
191
194
|
const msg = messages[i];
|
|
192
|
-
if (msg.role === "
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
if (msg.role === "assistant") {
|
|
196
|
+
const hasText = Array.isArray(msg.content) && msg.content.some(
|
|
197
|
+
(c) => c.type === "text" && "text" in c && (c.text as string).trim().length > 0,
|
|
198
|
+
);
|
|
199
|
+
if (hasText) {
|
|
200
|
+
lastAssistantTextIndex = i;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
195
203
|
}
|
|
196
204
|
}
|
|
197
205
|
|
|
198
|
-
|
|
199
|
-
|
|
206
|
+
// Step 2: Only scan tool results AFTER the last assistant text message.
|
|
207
|
+
// Errors before the agent's final response are implicitly recovered.
|
|
208
|
+
const scanStart = lastAssistantTextIndex >= 0 ? lastAssistantTextIndex + 1 : 0;
|
|
200
209
|
|
|
210
|
+
// Step 3: Check tool results in the post-response window
|
|
211
|
+
for (let i = messages.length - 1; i >= scanStart; i--) {
|
|
201
212
|
const msg = messages[i];
|
|
202
213
|
if (msg.role !== "toolResult") continue;
|
|
203
214
|
|
|
@@ -228,6 +239,9 @@ export function detectSubagentError(messages: Message[]): ErrorInfo {
|
|
|
228
239
|
}
|
|
229
240
|
}
|
|
230
241
|
|
|
242
|
+
// NOTE: These patterns can match legitimate output (grep results, logs,
|
|
243
|
+
// testing). With the assistant-message check above, most false positives
|
|
244
|
+
// are mitigated since the agent will have responded after routine errors.
|
|
231
245
|
const fatalPatterns = [
|
|
232
246
|
/command not found/i,
|
|
233
247
|
/permission denied/i,
|
|
@@ -319,6 +333,8 @@ export async function mapConcurrent<T, R>(
|
|
|
319
333
|
limit: number,
|
|
320
334
|
fn: (item: T, i: number) => Promise<R>,
|
|
321
335
|
): Promise<R[]> {
|
|
336
|
+
// Clamp to at least 1; NaN/undefined/0/negative all become 1
|
|
337
|
+
const safeLimit = Math.max(1, Math.floor(limit) || 1);
|
|
322
338
|
const results: R[] = new Array(items.length);
|
|
323
339
|
let next = 0;
|
|
324
340
|
|
|
@@ -329,7 +345,7 @@ export async function mapConcurrent<T, R>(
|
|
|
329
345
|
}
|
|
330
346
|
}
|
|
331
347
|
|
|
332
|
-
const workers = Array.from({ length: Math.min(
|
|
348
|
+
const workers = Array.from({ length: Math.min(safeLimit, items.length) }, () => worker());
|
|
333
349
|
await Promise.all(workers);
|
|
334
350
|
return results;
|
|
335
351
|
}
|