@humain/terminal 0.0.16 → 0.0.18
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 +12 -0
- package/dist/bundle/chunks/{chunk-Z4RA2T5Q.js → chunk-QLVZGOBY.js} +131 -128
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/tools/subagent-worktree.d.ts +25 -0
- package/dist/core/tools/subagent-worktree.d.ts.map +1 -0
- package/dist/core/tools/subagent-worktree.js +267 -0
- package/dist/core/tools/subagent-worktree.js.map +1 -0
- package/dist/core/tools/subagent.d.ts +8 -0
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +116 -20
- package/dist/core/tools/subagent.js.map +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagent.d.ts","sourceRoot":"","sources":["../../../src/core/tools/subagent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAO,OAAO,EAAS,MAAM,uBAAuB,CAAC;AAGjE,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI/B,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"subagent.d.ts","sourceRoot":"","sources":["../../../src/core/tools/subagent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAO,OAAO,EAAS,MAAM,uBAAuB,CAAC;AAGjE,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI/B,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG/E,OAAO,EAGN,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAEzB,MAAM,wBAAwB,CAAC;AAQhC,4FAA4F;AAC5F,eAAO,MAAM,kBAAkB,mCAAmC,CAAC;AAUnE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAyED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,oBAAoB,CAmBnF;AAoGD,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,kBAAkB,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,iBAAiB,CAAC;IAC7B,uBAAuB,CAAC,EAAE,gBAAgB,CAAC;IAC3C,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;IACtC,UAAU,EAAE,UAAU,CAAC;IACvB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,oBAAoB,EAAE,CAAC;CAChC;AA0YD,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;EAqBlB,CAAC;AAEH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAC,OAAO,cAAc,EAAE,eAAe,CAAC,CAopBhH;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,2EAE7C"}
|
|
@@ -23,6 +23,7 @@ import { getMarkdownTheme } from "../../modes/interactive/theme/theme.js";
|
|
|
23
23
|
import { parseFrontmatter } from "../../utils/frontmatter.js";
|
|
24
24
|
import { withFileMutationQueue } from "./file-mutation-queue.js";
|
|
25
25
|
import { shortenPath } from "./render-utils.js";
|
|
26
|
+
import { createSubagentWorktree, isGitWorkTree, } from "./subagent-worktree.js";
|
|
26
27
|
import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
27
28
|
const MAX_PARALLEL_TASKS = 8;
|
|
28
29
|
const MAX_CONCURRENCY = 4;
|
|
@@ -223,7 +224,10 @@ function getFinalOutput(messages) {
|
|
|
223
224
|
return "";
|
|
224
225
|
}
|
|
225
226
|
function isFailedResult(result) {
|
|
226
|
-
return result.
|
|
227
|
+
return (Boolean(result.errorMessage) ||
|
|
228
|
+
result.exitCode !== 0 ||
|
|
229
|
+
result.stopReason === "error" ||
|
|
230
|
+
result.stopReason === "aborted");
|
|
227
231
|
}
|
|
228
232
|
function getResultOutput(result) {
|
|
229
233
|
if (isFailedResult(result)) {
|
|
@@ -255,7 +259,7 @@ function getDisplayItems(messages) {
|
|
|
255
259
|
}
|
|
256
260
|
return items;
|
|
257
261
|
}
|
|
258
|
-
async function mapWithConcurrencyLimit(items, concurrency, fn, signal) {
|
|
262
|
+
async function mapWithConcurrencyLimit(items, concurrency, fn, signal, onAbort) {
|
|
259
263
|
if (items.length === 0)
|
|
260
264
|
return [];
|
|
261
265
|
const limit = Math.max(1, Math.min(concurrency, items.length));
|
|
@@ -263,12 +267,14 @@ async function mapWithConcurrencyLimit(items, concurrency, fn, signal) {
|
|
|
263
267
|
let nextIndex = 0;
|
|
264
268
|
const workers = new Array(limit).fill(null).map(async () => {
|
|
265
269
|
while (true) {
|
|
266
|
-
// Don't spawn doomed children for tasks still queued after an abort.
|
|
267
|
-
if (signal?.aborted)
|
|
268
|
-
throw new Error("Subagent was aborted");
|
|
269
270
|
const current = nextIndex++;
|
|
270
271
|
if (current >= items.length)
|
|
271
272
|
return;
|
|
273
|
+
if (signal?.aborted) {
|
|
274
|
+
if (onAbort)
|
|
275
|
+
results[current] = await onAbort(items[current], current);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
272
278
|
results[current] = await fn(items[current], current);
|
|
273
279
|
}
|
|
274
280
|
});
|
|
@@ -297,7 +303,7 @@ function getCliInvocation(args) {
|
|
|
297
303
|
}
|
|
298
304
|
return { command: "humain-terminal", args };
|
|
299
305
|
}
|
|
300
|
-
async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, model, parentModel, signal, onUpdate, makeDetails) {
|
|
306
|
+
async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, isolation, step, model, parentModel, signal, onUpdate, makeDetails, toolCallId, childIndex) {
|
|
301
307
|
const agent = agents.find((a) => a.name === agentName);
|
|
302
308
|
if (!agent) {
|
|
303
309
|
const available = agents.map((a) => `"${a.name}"`).join(", ") || "none";
|
|
@@ -310,8 +316,13 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
310
316
|
stderr: `Unknown agent: "${agentName}". Available agents: ${available}.`,
|
|
311
317
|
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
|
|
312
318
|
step,
|
|
319
|
+
isolation: "shared",
|
|
313
320
|
};
|
|
314
321
|
}
|
|
322
|
+
let worktree = null;
|
|
323
|
+
let isolationDegradedReason;
|
|
324
|
+
const parentCwd = cwd ?? defaultCwd;
|
|
325
|
+
let childCwd = parentCwd;
|
|
315
326
|
const args = ["--mode", "json", "-p", "--no-session"];
|
|
316
327
|
if (model) {
|
|
317
328
|
// Canonical "provider/modelId" handle: split on the FIRST slash so
|
|
@@ -343,6 +354,7 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
343
354
|
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
|
|
344
355
|
model: model ?? `${parentModel.provider}/${parentModel.id}`,
|
|
345
356
|
step,
|
|
357
|
+
isolation: "shared",
|
|
346
358
|
};
|
|
347
359
|
const emitUpdate = () => {
|
|
348
360
|
if (onUpdate) {
|
|
@@ -352,7 +364,22 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
352
364
|
});
|
|
353
365
|
}
|
|
354
366
|
};
|
|
367
|
+
let wasAborted = false;
|
|
355
368
|
try {
|
|
369
|
+
if (isolation === "worktree") {
|
|
370
|
+
if (await isGitWorkTree(parentCwd)) {
|
|
371
|
+
worktree = await createSubagentWorktree({ parentCwd, label: `${toolCallId}-${childIndex}` });
|
|
372
|
+
childCwd = worktree.cwd;
|
|
373
|
+
currentResult.isolation = "worktree";
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
isolationDegradedReason = "not-a-git-repo";
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (isolationDegradedReason)
|
|
380
|
+
currentResult.isolationDegradedReason = isolationDegradedReason;
|
|
381
|
+
if (signal?.aborted)
|
|
382
|
+
throw new Error("Subagent was aborted");
|
|
356
383
|
if (agent.systemPrompt.trim()) {
|
|
357
384
|
const tmp = await writePromptToTempFile(agent.name, agent.systemPrompt);
|
|
358
385
|
tmpPromptDir = tmp.dir;
|
|
@@ -360,16 +387,16 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
360
387
|
args.push("--append-system-prompt", tmpPromptPath);
|
|
361
388
|
}
|
|
362
389
|
args.push(`Task: ${task}`);
|
|
363
|
-
let wasAborted = false;
|
|
364
390
|
const exitCode = await new Promise((resolve) => {
|
|
365
391
|
const invocation = getCliInvocation(args);
|
|
366
392
|
const proc = spawn(invocation.command, invocation.args, {
|
|
367
|
-
cwd:
|
|
393
|
+
cwd: childCwd,
|
|
368
394
|
shell: false,
|
|
369
395
|
stdio: ["ignore", "pipe", "pipe"],
|
|
370
396
|
env: { ...process.env, [SUBAGENT_DEPTH_ENV]: String(currentSubagentDepth() + 1) },
|
|
371
397
|
});
|
|
372
398
|
let buffer = "";
|
|
399
|
+
let settled = false;
|
|
373
400
|
const processLine = (line) => {
|
|
374
401
|
if (!line.trim())
|
|
375
402
|
return;
|
|
@@ -418,23 +445,39 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
418
445
|
proc.stderr.on("data", (data) => {
|
|
419
446
|
currentResult.stderr += data.toString();
|
|
420
447
|
});
|
|
448
|
+
let abortListener;
|
|
449
|
+
let killTimer;
|
|
450
|
+
const cleanupAbort = () => {
|
|
451
|
+
if (signal && abortListener)
|
|
452
|
+
signal.removeEventListener("abort", abortListener);
|
|
453
|
+
if (killTimer)
|
|
454
|
+
clearTimeout(killTimer);
|
|
455
|
+
};
|
|
421
456
|
proc.on("close", (code) => {
|
|
457
|
+
settled = true;
|
|
458
|
+
cleanupAbort();
|
|
422
459
|
if (buffer.trim())
|
|
423
460
|
processLine(buffer);
|
|
424
461
|
resolve(code ?? 0);
|
|
425
462
|
});
|
|
426
463
|
proc.on("error", () => {
|
|
464
|
+
settled = true;
|
|
465
|
+
cleanupAbort();
|
|
427
466
|
resolve(1);
|
|
428
467
|
});
|
|
429
468
|
if (signal) {
|
|
430
469
|
const killProc = () => {
|
|
470
|
+
if (settled)
|
|
471
|
+
return;
|
|
431
472
|
wasAborted = true;
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
if (!proc.killed)
|
|
473
|
+
killTimer = setTimeout(() => {
|
|
474
|
+
if (!settled)
|
|
435
475
|
proc.kill("SIGKILL");
|
|
436
476
|
}, 5000);
|
|
477
|
+
killTimer.unref?.();
|
|
478
|
+
proc.kill("SIGTERM");
|
|
437
479
|
};
|
|
480
|
+
abortListener = killProc;
|
|
438
481
|
if (signal.aborted)
|
|
439
482
|
killProc();
|
|
440
483
|
else
|
|
@@ -442,11 +485,53 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
442
485
|
}
|
|
443
486
|
});
|
|
444
487
|
currentResult.exitCode = exitCode;
|
|
445
|
-
if (wasAborted)
|
|
446
|
-
|
|
447
|
-
|
|
488
|
+
if (wasAborted || signal?.aborted) {
|
|
489
|
+
currentResult.exitCode = 1;
|
|
490
|
+
currentResult.stopReason = "aborted";
|
|
491
|
+
currentResult.errorMessage = "Subagent was aborted";
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
currentResult.exitCode = 1;
|
|
496
|
+
currentResult.errorMessage = error instanceof Error ? error.message : String(error);
|
|
497
|
+
if (wasAborted || signal?.aborted)
|
|
498
|
+
currentResult.stopReason = "aborted";
|
|
448
499
|
}
|
|
449
500
|
finally {
|
|
501
|
+
if (worktree) {
|
|
502
|
+
try {
|
|
503
|
+
if (isFailedResult(currentResult) || signal?.aborted) {
|
|
504
|
+
currentResult.mergeOutcome = "skipped";
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
const merged = await worktree.mergeBack();
|
|
508
|
+
currentResult.mergeOutcome = merged.outcome;
|
|
509
|
+
currentResult.changedFiles = merged.changedFiles;
|
|
510
|
+
if (merged.patchPath)
|
|
511
|
+
currentResult.patchPath = merged.patchPath;
|
|
512
|
+
if (merged.outcome === "conflict") {
|
|
513
|
+
currentResult.errorMessage = `subagent merge conflict: ${merged.changedFiles.join(", ")} could not be applied to the parent workspace; patch kept at ${merged.patchPath}`;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
catch (error) {
|
|
518
|
+
currentResult.exitCode = 1;
|
|
519
|
+
currentResult.mergeOutcome = "skipped";
|
|
520
|
+
currentResult.errorMessage = `subagent merge failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
521
|
+
}
|
|
522
|
+
finally {
|
|
523
|
+
try {
|
|
524
|
+
await worktree.dispose();
|
|
525
|
+
}
|
|
526
|
+
catch (error) {
|
|
527
|
+
currentResult.exitCode = 1;
|
|
528
|
+
const cleanupError = `subagent worktree cleanup failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
529
|
+
const primaryOutput = getResultOutput(currentResult);
|
|
530
|
+
currentResult.errorMessage =
|
|
531
|
+
primaryOutput === "(no output)" ? cleanupError : `${primaryOutput}\n${cleanupError}`;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
450
535
|
if (tmpPromptPath)
|
|
451
536
|
try {
|
|
452
537
|
fs.unlinkSync(tmpPromptPath);
|
|
@@ -462,6 +547,7 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
462
547
|
/* ignore */
|
|
463
548
|
}
|
|
464
549
|
}
|
|
550
|
+
return currentResult;
|
|
465
551
|
}
|
|
466
552
|
const TaskItem = Type.Object({
|
|
467
553
|
agent: Type.String({ description: "Name of the agent to invoke" }),
|
|
@@ -470,6 +556,9 @@ const TaskItem = Type.Object({
|
|
|
470
556
|
description: "Optional canonical provider/model for this child. Defaults to the parent provider/model.",
|
|
471
557
|
})),
|
|
472
558
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
|
|
559
|
+
isolation: Type.Optional(StringEnum(["shared", "worktree"], {
|
|
560
|
+
description: "Filesystem isolation for this child. 'worktree' runs it in a disposable git worktree and merges its changes back; the caller's policy sets this, not the model.",
|
|
561
|
+
})),
|
|
473
562
|
});
|
|
474
563
|
const ChainItem = Type.Object({
|
|
475
564
|
agent: Type.String({ description: "Name of the agent to invoke" }),
|
|
@@ -494,6 +583,9 @@ const SubagentParams = Type.Object({
|
|
|
494
583
|
agentScope: Type.Optional(AgentScopeSchema),
|
|
495
584
|
confirmProjectAgents: Type.Optional(Type.Boolean({ description: "Prompt before running project-local agents. Default: true.", default: true })),
|
|
496
585
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process (single mode)" })),
|
|
586
|
+
isolation: Type.Optional(StringEnum(["shared", "worktree"], {
|
|
587
|
+
description: "Filesystem isolation for this child. 'worktree' runs it in a disposable git worktree and merges its changes back; the caller's policy sets this, not the model.",
|
|
588
|
+
})),
|
|
497
589
|
});
|
|
498
590
|
export function createSubagentToolDefinition(cwd) {
|
|
499
591
|
return {
|
|
@@ -502,6 +594,7 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
502
594
|
description: [
|
|
503
595
|
"Delegate tasks to specialized subagents with isolated context.",
|
|
504
596
|
"Modes: single (agent + task), parallel (tasks array), chain (sequential with {previous} placeholder).",
|
|
597
|
+
"The optional isolation field is policy-set for each child.",
|
|
505
598
|
`Default agent scope is "user" (from ${path.join(getAgentDir(), "agents")}).`,
|
|
506
599
|
`To enable project-local agents in ${CONFIG_DIR_NAME}/agents, set agentScope: "both" (or "project").`,
|
|
507
600
|
].join(" "),
|
|
@@ -510,7 +603,7 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
510
603
|
"Use subagent to fan out independent work in parallel (tasks array) or run multi-step pipelines (chain). Subagents run with isolated context and cannot delegate further.",
|
|
511
604
|
],
|
|
512
605
|
parameters: SubagentParams,
|
|
513
|
-
async execute(
|
|
606
|
+
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
514
607
|
const agentScope = params.agentScope ?? "user";
|
|
515
608
|
const defaultCwd = ctx?.cwd ?? cwd;
|
|
516
609
|
const parentModel = ctx?.model;
|
|
@@ -539,6 +632,7 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
539
632
|
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
|
|
540
633
|
errorMessage,
|
|
541
634
|
step: child.step,
|
|
635
|
+
isolation: "shared",
|
|
542
636
|
});
|
|
543
637
|
const stubAllChildren = (errorMessage) => requestedChildren().map((child) => stubResult(child, errorMessage));
|
|
544
638
|
const makeDetails = (mode) => (results) => ({
|
|
@@ -631,7 +725,7 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
631
725
|
}
|
|
632
726
|
}
|
|
633
727
|
: undefined;
|
|
634
|
-
const result = await runSingleAgent(defaultCwd, agents, step.agent, taskWithContext, step.cwd, i + 1, step.model, parentModel, signal, chainUpdate, makeDetails("chain"));
|
|
728
|
+
const result = await runSingleAgent(defaultCwd, agents, step.agent, taskWithContext, step.cwd, undefined, i + 1, step.model, parentModel, signal, chainUpdate, makeDetails("chain"), toolCallId, i);
|
|
635
729
|
results.push(result);
|
|
636
730
|
const isError = isFailedResult(result);
|
|
637
731
|
if (isError) {
|
|
@@ -676,6 +770,7 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
676
770
|
messages: [],
|
|
677
771
|
stderr: "",
|
|
678
772
|
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
|
|
773
|
+
isolation: "shared",
|
|
679
774
|
};
|
|
680
775
|
}
|
|
681
776
|
const emitParallelUpdate = () => {
|
|
@@ -691,18 +786,18 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
691
786
|
}
|
|
692
787
|
};
|
|
693
788
|
const results = await mapWithConcurrencyLimit(params.tasks, MAX_CONCURRENCY, async (t, index) => {
|
|
694
|
-
const result = await runSingleAgent(defaultCwd, agents, t.agent, t.task, t.cwd, undefined, t.model, parentModel, signal,
|
|
789
|
+
const result = await runSingleAgent(defaultCwd, agents, t.agent, t.task, t.cwd, t.isolation, undefined, t.model, parentModel, signal,
|
|
695
790
|
// Per-task update callback
|
|
696
791
|
(partial) => {
|
|
697
792
|
if (partial.details?.results[0]) {
|
|
698
793
|
allResults[index] = partial.details.results[0];
|
|
699
794
|
emitParallelUpdate();
|
|
700
795
|
}
|
|
701
|
-
}, makeDetails("parallel"));
|
|
796
|
+
}, makeDetails("parallel"), toolCallId, index);
|
|
702
797
|
allResults[index] = result;
|
|
703
798
|
emitParallelUpdate();
|
|
704
799
|
return result;
|
|
705
|
-
}, signal);
|
|
800
|
+
}, signal, (t) => stubResult({ agent: t.agent, task: t.task }, "not run: subagent was aborted"));
|
|
706
801
|
const successCount = results.filter((r) => !isFailedResult(r)).length;
|
|
707
802
|
const summaries = results.map((r) => {
|
|
708
803
|
const output = truncateParallelOutput(getResultOutput(r));
|
|
@@ -719,10 +814,11 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
719
814
|
},
|
|
720
815
|
],
|
|
721
816
|
details: makeDetails("parallel")(results),
|
|
817
|
+
isError: successCount !== results.length,
|
|
722
818
|
};
|
|
723
819
|
}
|
|
724
820
|
if (params.agent && params.task) {
|
|
725
|
-
const result = await runSingleAgent(defaultCwd, agents, params.agent, params.task, params.cwd, undefined, params.model, parentModel, signal, onUpdate, makeDetails("single"));
|
|
821
|
+
const result = await runSingleAgent(defaultCwd, agents, params.agent, params.task, params.cwd, params.isolation, undefined, params.model, parentModel, signal, onUpdate, makeDetails("single"), toolCallId, 0);
|
|
726
822
|
const isError = isFailedResult(result);
|
|
727
823
|
if (isError) {
|
|
728
824
|
const errorMsg = getResultOutput(result);
|