@bastani/atomic 0.9.26 → 0.9.27-alpha.1
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 +18 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/index.bundle.mjs +21 -6
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +8 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +693 -642
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +8 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +71 -20
- package/dist/builtin/workflows/src/index.js +31 -10
- package/dist/codemode-worker.js +3309 -0
- package/dist/config.d.ts +7 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +38 -12
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
- package/dist/core/agent-session-custom-message-commit.js +6 -0
- package/dist/core/agent-session-custom-message-commit.js.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.js +22 -6
- package/dist/core/agent-session-extension-bindings.js.map +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +3 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-tasks.js +9 -4
- package/dist/core/agent-session-tasks.js.map +1 -1
- package/dist/core/auth-storage-backends.d.ts +3 -0
- package/dist/core/auth-storage-backends.d.ts.map +1 -1
- package/dist/core/auth-storage-backends.js +45 -1
- package/dist/core/auth-storage-backends.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +14 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/extensions/provider-types.d.ts +3 -2
- package/dist/core/extensions/provider-types.d.ts.map +1 -1
- package/dist/core/extensions/provider-types.js.map +1 -1
- package/dist/core/extensions/runner-events.d.ts.map +1 -1
- package/dist/core/extensions/runner-events.js +10 -1
- package/dist/core/extensions/runner-events.js.map +1 -1
- package/dist/extensions/codemode/execute.d.ts.map +1 -1
- package/dist/extensions/codemode/execute.js +40 -6
- package/dist/extensions/codemode/execute.js.map +1 -1
- package/dist/extensions/codemode/tool.d.ts.map +1 -1
- package/dist/extensions/codemode/tool.js +1 -0
- package/dist/extensions/codemode/tool.js.map +1 -1
- package/dist/extensions/mcp/tools.d.ts.map +1 -1
- package/dist/extensions/mcp/tools.js +4 -9
- package/dist/extensions/mcp/tools.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.js +21 -0
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +1 -0
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-helpers.js +1 -1
- package/dist/modes/interactive/interactive-mode-helpers.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-process-lifecycle.js +7 -4
- package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -1
- package/dist/utils/output-files.d.ts +7 -0
- package/dist/utils/output-files.d.ts.map +1 -0
- package/dist/utils/output-files.js +20 -0
- package/dist/utils/output-files.js.map +1 -0
- package/docs/codemode.md +3 -3
- package/docs/extensions/api-reference.md +3 -1
- package/docs/extensions.md +2 -0
- package/docs/sdk.md +2 -0
- package/docs/settings.md +2 -0
- package/docs/subagents.md +4 -0
- package/docs/workflows/api-reference.md +6 -2
- package/docs/workflows/operations.md +10 -10
- package/npm-shrinkwrap.json +32 -32
- package/package.json +6 -6
|
@@ -8001,6 +8001,25 @@ function presentCancelledStatus(status, cause) {
|
|
|
8001
8001
|
}
|
|
8002
8002
|
|
|
8003
8003
|
// dist/builtin/subagents/src/runs/shared/parallel-utils.ts
|
|
8004
|
+
function createExecutionScheduler(limit) {
|
|
8005
|
+
let active = 0;
|
|
8006
|
+
const queued = [];
|
|
8007
|
+
const pump = () => {
|
|
8008
|
+
while (active < limit && queued.length > 0) {
|
|
8009
|
+
const dispatch = queued.shift();
|
|
8010
|
+
active++;
|
|
8011
|
+
const release = () => {
|
|
8012
|
+
active--;
|
|
8013
|
+
pump();
|
|
8014
|
+
};
|
|
8015
|
+
dispatch().then(release, release);
|
|
8016
|
+
}
|
|
8017
|
+
};
|
|
8018
|
+
return (dispatch) => {
|
|
8019
|
+
queued.push(dispatch);
|
|
8020
|
+
pump();
|
|
8021
|
+
};
|
|
8022
|
+
}
|
|
8004
8023
|
async function mapConcurrent(items, limit, fn) {
|
|
8005
8024
|
const safeLimit = Math.max(1, Math.floor(limit) || 1);
|
|
8006
8025
|
const results = new Array(items.length);
|
|
@@ -11703,6 +11722,119 @@ function resolveRequestedCwd(runtimeCwd, requestedCwd) {
|
|
|
11703
11722
|
return requestedCwd ? path11.resolve(runtimeCwd, requestedCwd) : runtimeCwd;
|
|
11704
11723
|
}
|
|
11705
11724
|
|
|
11725
|
+
// dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts
|
|
11726
|
+
function validateExecutionInput(params, agents, hasTasks, hasSingle, parallelAgentConfigs) {
|
|
11727
|
+
if (Number(hasTasks) + Number(hasSingle) !== 1) {
|
|
11728
|
+
return {
|
|
11729
|
+
content: [
|
|
11730
|
+
{
|
|
11731
|
+
type: "text",
|
|
11732
|
+
text: `Provide exactly one mode. Agents: ${agents.map((a) => a.name).join(", ") || "none"}`
|
|
11733
|
+
}
|
|
11734
|
+
],
|
|
11735
|
+
isError: true,
|
|
11736
|
+
details: { mode: "single", results: [] }
|
|
11737
|
+
};
|
|
11738
|
+
}
|
|
11739
|
+
if (hasSingle) {
|
|
11740
|
+
const reads = params.reads;
|
|
11741
|
+
if (reads !== undefined && reads !== false && (!Array.isArray(reads) || reads.some((entry) => typeof entry !== "string"))) {
|
|
11742
|
+
return {
|
|
11743
|
+
content: [{ type: "text", text: "reads must be an array of file path strings or false" }],
|
|
11744
|
+
isError: true,
|
|
11745
|
+
details: { mode: "single", results: [] }
|
|
11746
|
+
};
|
|
11747
|
+
}
|
|
11748
|
+
}
|
|
11749
|
+
if (hasSingle && params.agent && !agents.find((agent) => agent.name === params.agent)) {
|
|
11750
|
+
return {
|
|
11751
|
+
content: [{ type: "text", text: `Unknown agent: ${params.agent}` }],
|
|
11752
|
+
isError: true,
|
|
11753
|
+
details: { mode: "single", results: [] }
|
|
11754
|
+
};
|
|
11755
|
+
}
|
|
11756
|
+
if (hasTasks && params.tasks) {
|
|
11757
|
+
for (let i = 0;i < params.tasks.length; i++) {
|
|
11758
|
+
const task = params.tasks[i];
|
|
11759
|
+
const agent = parallelAgentConfigs?.[i] ?? agents.find((candidate) => candidate.name === task.agent);
|
|
11760
|
+
if (!agent || agent.name !== task.agent) {
|
|
11761
|
+
return {
|
|
11762
|
+
content: [{ type: "text", text: `Unknown agent: ${task.agent} (task ${i + 1})` }],
|
|
11763
|
+
isError: true,
|
|
11764
|
+
details: { mode: "parallel", results: [] }
|
|
11765
|
+
};
|
|
11766
|
+
}
|
|
11767
|
+
}
|
|
11768
|
+
}
|
|
11769
|
+
return null;
|
|
11770
|
+
}
|
|
11771
|
+
function getRequestedModeLabel(params) {
|
|
11772
|
+
if ((params.tasks?.length ?? 0) > 0)
|
|
11773
|
+
return "parallel";
|
|
11774
|
+
if (params.agent)
|
|
11775
|
+
return "single";
|
|
11776
|
+
return "single";
|
|
11777
|
+
}
|
|
11778
|
+
function applyAgentDefaultContext(params, agents) {
|
|
11779
|
+
if (params.context !== undefined)
|
|
11780
|
+
return params;
|
|
11781
|
+
const byName = new Map(agents.map((agent) => [agent.name, agent]));
|
|
11782
|
+
const names = [];
|
|
11783
|
+
if (params.agent)
|
|
11784
|
+
names.push(params.agent);
|
|
11785
|
+
for (const task of params.tasks ?? [])
|
|
11786
|
+
names.push(task.agent);
|
|
11787
|
+
return names.some((name) => byName.get(name)?.defaultContext === "fork") ? { ...params, context: "fork" } : params;
|
|
11788
|
+
}
|
|
11789
|
+
function buildRequestedModeError(params, message) {
|
|
11790
|
+
return withForkContext({
|
|
11791
|
+
content: [{ type: "text", text: message }],
|
|
11792
|
+
isError: true,
|
|
11793
|
+
details: { mode: getRequestedModeLabel(params), results: [] }
|
|
11794
|
+
}, params.context);
|
|
11795
|
+
}
|
|
11796
|
+
function expandTopLevelTaskCounts(tasks) {
|
|
11797
|
+
const expanded = [];
|
|
11798
|
+
for (let taskIndex = 0;taskIndex < tasks.length; taskIndex++) {
|
|
11799
|
+
const task = tasks[taskIndex];
|
|
11800
|
+
const rawCount = task.count;
|
|
11801
|
+
if (rawCount !== undefined && (typeof rawCount !== "number" || !Number.isInteger(rawCount) || rawCount < 1)) {
|
|
11802
|
+
return { error: `tasks[${taskIndex}].count must be an integer >= 1` };
|
|
11803
|
+
}
|
|
11804
|
+
const { count: _count, ...concreteTask } = task;
|
|
11805
|
+
for (let repeat = 0;repeat < (rawCount ?? 1); repeat++)
|
|
11806
|
+
expanded.push({ ...concreteTask });
|
|
11807
|
+
}
|
|
11808
|
+
return { tasks: expanded };
|
|
11809
|
+
}
|
|
11810
|
+
function normalizeRepeatedParallelCounts(params) {
|
|
11811
|
+
if (!params.tasks)
|
|
11812
|
+
return { params };
|
|
11813
|
+
const expandedTasks = expandTopLevelTaskCounts(params.tasks);
|
|
11814
|
+
if (expandedTasks.error)
|
|
11815
|
+
return { error: buildRequestedModeError(params, expandedTasks.error) };
|
|
11816
|
+
return { params: { ...params, tasks: expandedTasks.tasks } };
|
|
11817
|
+
}
|
|
11818
|
+
function withForkContext(result, context) {
|
|
11819
|
+
if (context !== "fork" || !result.details)
|
|
11820
|
+
return result;
|
|
11821
|
+
return {
|
|
11822
|
+
...result,
|
|
11823
|
+
details: {
|
|
11824
|
+
...result.details,
|
|
11825
|
+
context: "fork"
|
|
11826
|
+
}
|
|
11827
|
+
};
|
|
11828
|
+
}
|
|
11829
|
+
function toExecutionErrorResult(params, error) {
|
|
11830
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11831
|
+
return withForkContext({
|
|
11832
|
+
content: [{ type: "text", text: message }],
|
|
11833
|
+
isError: true,
|
|
11834
|
+
details: { mode: getRequestedModeLabel(params), results: [] }
|
|
11835
|
+
}, params.context);
|
|
11836
|
+
}
|
|
11837
|
+
|
|
11706
11838
|
// dist/builtin/subagents/src/runs/foreground/subagent-executor-live-update.ts
|
|
11707
11839
|
var liveResultIndices = new WeakMap;
|
|
11708
11840
|
function markLiveResultIndices(result, indices) {
|
|
@@ -11720,95 +11852,410 @@ function getParentAskHandoff(result) {
|
|
|
11720
11852
|
|
|
11721
11853
|
// dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts
|
|
11722
11854
|
var BURST_TASK_DISCOVERY_CWD = Symbol("burstTaskDiscoveryCwd");
|
|
11855
|
+
var BURST_EXECUTION_SCHEDULE = Symbol("burstExecutionSchedule");
|
|
11723
11856
|
function isManagementActionsRestricted(deps) {
|
|
11724
11857
|
return deps.childPolicy ? deps.childPolicy.managementActions === "restricted" : deps.allowMutatingManagementActions === false;
|
|
11725
11858
|
}
|
|
11726
11859
|
|
|
11727
|
-
// dist/builtin/subagents/src/runs/foreground/
|
|
11728
|
-
|
|
11729
|
-
|
|
11730
|
-
|
|
11731
|
-
|
|
11732
|
-
|
|
11733
|
-
|
|
11734
|
-
|
|
11735
|
-
|
|
11736
|
-
|
|
11737
|
-
"includeProgress",
|
|
11738
|
-
"agentScope"
|
|
11739
|
-
];
|
|
11740
|
-
function incompatibleField(items) {
|
|
11741
|
-
const first = items[0].params;
|
|
11742
|
-
for (const field of SHARED_FIELDS) {
|
|
11743
|
-
for (let index = 1;index < items.length; index++) {
|
|
11744
|
-
if (!isDeepStrictEqual(first[field], items[index].params[field]))
|
|
11745
|
-
return field;
|
|
11746
|
-
}
|
|
11747
|
-
}
|
|
11748
|
-
return;
|
|
11749
|
-
}
|
|
11750
|
-
function incompatibleFieldResult(field) {
|
|
11751
|
-
return {
|
|
11752
|
-
content: [
|
|
11753
|
-
{
|
|
11754
|
-
type: "text",
|
|
11755
|
-
text: `Cannot coalesce sibling subagent calls: incompatible top-level field '${field}'.`
|
|
11756
|
-
}
|
|
11757
|
-
],
|
|
11758
|
-
isError: true,
|
|
11759
|
-
details: { mode: "parallel", results: [] }
|
|
11760
|
-
};
|
|
11860
|
+
// dist/builtin/subagents/src/runs/foreground/task-output-retention.ts
|
|
11861
|
+
import { mkdtempSync, readFileSync as readFileSync8, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
11862
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
11863
|
+
import { join as join11 } from "node:path";
|
|
11864
|
+
var INLINE_TASK_OUTPUT_MAX_BYTES = 16 * 1024;
|
|
11865
|
+
var MAX_RETAINED_TASK_OUTPUTS = 256;
|
|
11866
|
+
var retained = new Map;
|
|
11867
|
+
var copyRoot;
|
|
11868
|
+
function retentionKey(ownerId, taskId) {
|
|
11869
|
+
return `${ownerId}\x00${taskId}`;
|
|
11761
11870
|
}
|
|
11762
|
-
function
|
|
11763
|
-
return
|
|
11764
|
-
content: [
|
|
11765
|
-
{
|
|
11766
|
-
type: "text",
|
|
11767
|
-
text: "Cannot coalesce sibling subagent calls: incompatible top-level field 'cwd' for worktree."
|
|
11768
|
-
}
|
|
11769
|
-
],
|
|
11770
|
-
isError: true,
|
|
11771
|
-
details: { mode: "parallel", results: [] }
|
|
11772
|
-
};
|
|
11871
|
+
function fileSafe(value) {
|
|
11872
|
+
return value.replace(/[^A-Za-z0-9._-]+/g, "_");
|
|
11773
11873
|
}
|
|
11774
|
-
function
|
|
11775
|
-
|
|
11776
|
-
|
|
11874
|
+
function privateCopyRoot() {
|
|
11875
|
+
if (copyRoot)
|
|
11876
|
+
return copyRoot;
|
|
11877
|
+
const root = mkdtempSync(join11(tmpdir2(), "atomic-subagent-output-"));
|
|
11878
|
+
copyRoot = root;
|
|
11879
|
+
process.once("exit", () => rmSync2(root, { recursive: true, force: true }));
|
|
11880
|
+
return root;
|
|
11777
11881
|
}
|
|
11778
|
-
function
|
|
11779
|
-
|
|
11882
|
+
function removeCopy(entry) {
|
|
11883
|
+
if (entry?.path)
|
|
11884
|
+
rmSync2(entry.path, { force: true });
|
|
11780
11885
|
}
|
|
11781
|
-
function
|
|
11782
|
-
|
|
11886
|
+
function fullOutputText(child, text) {
|
|
11887
|
+
if (child.outputMode !== "file-only" || !child.outputReference)
|
|
11888
|
+
return text;
|
|
11889
|
+
try {
|
|
11890
|
+
return readFileSync8(child.outputReference.path, "utf-8");
|
|
11891
|
+
} catch {
|
|
11892
|
+
return text;
|
|
11893
|
+
}
|
|
11783
11894
|
}
|
|
11784
|
-
function
|
|
11785
|
-
|
|
11895
|
+
function writePrivateCopy(ownerId, taskId, text) {
|
|
11896
|
+
try {
|
|
11897
|
+
const path = join11(privateCopyRoot(), `${fileSafe(ownerId)}-${fileSafe(taskId)}.md`);
|
|
11898
|
+
writeFileSync4(path, text, { encoding: "utf-8", mode: 384 });
|
|
11899
|
+
return path;
|
|
11900
|
+
} catch {
|
|
11786
11901
|
return;
|
|
11787
|
-
|
|
11788
|
-
return {
|
|
11789
|
-
agent: item.params.agent,
|
|
11790
|
-
task: item.params.task ?? "",
|
|
11791
|
-
cwd: originatingTaskCwd(callCwd, undefined),
|
|
11792
|
-
[BURST_TASK_DISCOVERY_CWD]: callCwd,
|
|
11793
|
-
...item.params.output !== undefined ? { output: item.params.output } : {},
|
|
11794
|
-
...item.params.outputMode !== undefined ? { outputMode: item.params.outputMode } : {},
|
|
11795
|
-
...item.params.reads !== undefined ? { reads: item.params.reads } : {},
|
|
11796
|
-
...item.params.progress !== undefined ? { progress: item.params.progress } : {},
|
|
11797
|
-
...item.params.model !== undefined ? { model: item.params.model } : {},
|
|
11798
|
-
...item.params.modelConstraints !== undefined ? { modelConstraints: item.params.modelConstraints } : {},
|
|
11799
|
-
...item.params.taskNeeds !== undefined ? { taskNeeds: item.params.taskNeeds } : {},
|
|
11800
|
-
...item.params.skill !== undefined ? { skill: item.params.skill } : {},
|
|
11801
|
-
...item.params.group !== undefined ? { group: item.params.group } : {}
|
|
11802
|
-
};
|
|
11902
|
+
}
|
|
11803
11903
|
}
|
|
11804
|
-
function
|
|
11805
|
-
const
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11904
|
+
function retainTaskOutput(child, text, ref) {
|
|
11905
|
+
const bytes = Buffer.from(text);
|
|
11906
|
+
const path = writePrivateCopy(ref.ownerId, ref.taskId, fullOutputText(child, text));
|
|
11907
|
+
const key = retentionKey(ref.ownerId, ref.taskId);
|
|
11908
|
+
removeCopy(retained.get(key));
|
|
11909
|
+
retained.delete(key);
|
|
11910
|
+
retained.set(key, {
|
|
11911
|
+
...path ? { path } : {},
|
|
11912
|
+
...child.outputReference ? { requestedPath: child.outputReference.path } : {},
|
|
11913
|
+
...child.outputSaveError ? { saveError: child.outputSaveError } : {},
|
|
11914
|
+
head: new TextDecoder().decode(bytes.subarray(0, INLINE_TASK_OUTPUT_MAX_BYTES)),
|
|
11915
|
+
totalBytes: bytes.byteLength
|
|
11916
|
+
});
|
|
11917
|
+
while (retained.size > MAX_RETAINED_TASK_OUTPUTS) {
|
|
11918
|
+
const oldest = retained.keys().next().value;
|
|
11919
|
+
if (oldest === undefined)
|
|
11920
|
+
break;
|
|
11921
|
+
removeCopy(retained.get(oldest));
|
|
11922
|
+
retained.delete(oldest);
|
|
11923
|
+
}
|
|
11924
|
+
}
|
|
11925
|
+
function retainedTaskOutput(ownerId, taskId) {
|
|
11926
|
+
return retained.get(retentionKey(ownerId, taskId));
|
|
11927
|
+
}
|
|
11928
|
+
|
|
11929
|
+
// dist/builtin/subagents/src/runs/foreground/task-execution.ts
|
|
11930
|
+
function subagentTaskResultLabel(result) {
|
|
11931
|
+
return result.kind === "cancelled" && result.cause === "user" ? "killed (non-resumable)" : result.kind;
|
|
11932
|
+
}
|
|
11933
|
+
function subagentTaskResponseText(response) {
|
|
11934
|
+
const outcomes = response.kind === "parallel" ? response.slots.map((slot) => slot.outcome) : [response];
|
|
11935
|
+
const killed = outcomes.filter((outcome) => outcome.kind === "admitted" && outcome.observation.kind === "settled" && subagentTaskResultLabel(outcome.observation.result) === "killed (non-resumable)");
|
|
11936
|
+
return `${killed.length ? `${killed.length} killed. These children cannot be resumed. Underlying host response:
|
|
11937
|
+
` : ""}${JSON.stringify(response)}`;
|
|
11938
|
+
}
|
|
11939
|
+
function settledOutputsFromResponse(response) {
|
|
11940
|
+
const outcomes = response.kind === "parallel" ? response.slots.map((slot) => slot.outcome) : [response];
|
|
11941
|
+
return outcomes.flatMap((outcome) => outcome.kind === "admitted" && outcome.observation.kind === "settled" ? [{ taskId: outcome.observation.taskId, result: outcome.observation.result }] : []);
|
|
11942
|
+
}
|
|
11943
|
+
function settledOutputsFromRecords(records) {
|
|
11944
|
+
return records.flatMap((record) => record.execution.kind === "settled" ? [{ taskId: record.ref.taskId, result: record.execution.result }] : []);
|
|
11945
|
+
}
|
|
11946
|
+
function settledOutputSection(taskId, label, output) {
|
|
11947
|
+
const truncated = output.shown < output.total ? `, first ${output.shown} shown${output.path ? "; read the full output file for the rest" : ""}` : "";
|
|
11948
|
+
const lines = [`Output of ${taskId} (${label}, ${output.total} bytes${truncated}):`];
|
|
11949
|
+
if (output.requestedPath)
|
|
11950
|
+
lines.push(`Requested output: ${output.requestedPath}`);
|
|
11951
|
+
if (output.saveError)
|
|
11952
|
+
lines.push(`Output file error: ${output.saveError}`);
|
|
11953
|
+
if (output.path)
|
|
11954
|
+
lines.push(`Full output: ${output.path}`);
|
|
11955
|
+
lines.push(output.head);
|
|
11956
|
+
return lines.join(`
|
|
11957
|
+
`);
|
|
11958
|
+
}
|
|
11959
|
+
async function readSettledOutput(host, settled) {
|
|
11960
|
+
const output = settled.result.output;
|
|
11961
|
+
if (!output)
|
|
11962
|
+
return;
|
|
11963
|
+
const label = subagentTaskResultLabel(settled.result);
|
|
11964
|
+
const kept = retainedTaskOutput(output.ownerId, output.taskId);
|
|
11965
|
+
if (kept) {
|
|
11966
|
+
return settledOutputSection(settled.taskId, label, {
|
|
11967
|
+
...kept,
|
|
11968
|
+
shown: Math.min(kept.totalBytes, INLINE_TASK_OUTPUT_MAX_BYTES),
|
|
11969
|
+
total: kept.totalBytes
|
|
11970
|
+
});
|
|
11971
|
+
}
|
|
11972
|
+
const unavailable = (reason) => `Output of ${settled.taskId} (${label}) is unavailable: ${reason}`;
|
|
11973
|
+
const lease = host.resolveTask(settled.taskId);
|
|
11974
|
+
if (!lease.ok)
|
|
11975
|
+
return unavailable(lease.error.message);
|
|
11976
|
+
try {
|
|
11977
|
+
const page = await host.ownerBinding.supervisor.readTaskOutput(lease.value, {
|
|
11978
|
+
start: "0",
|
|
11979
|
+
maximumBytes: INLINE_TASK_OUTPUT_MAX_BYTES
|
|
11980
|
+
});
|
|
11981
|
+
if (!page.ok)
|
|
11982
|
+
return unavailable(page.error.message);
|
|
11983
|
+
const decoder = new TextDecoder;
|
|
11984
|
+
const head = page.value.chunks.map((chunk) => decoder.decode(chunk.bytes, { stream: true })).join("") + decoder.decode();
|
|
11985
|
+
const shown = page.value.chunks.reduce((sum, chunk) => sum + chunk.bytes.byteLength, 0);
|
|
11986
|
+
return settledOutputSection(settled.taskId, label, { head, shown, total: Number(output.byteCount) });
|
|
11987
|
+
} catch (error) {
|
|
11988
|
+
return unavailable(error instanceof Error ? error.message : String(error));
|
|
11989
|
+
}
|
|
11990
|
+
}
|
|
11991
|
+
async function settledTaskOutputText(host, settled) {
|
|
11992
|
+
if (!host || settled.length === 0)
|
|
11993
|
+
return "";
|
|
11994
|
+
const sections = await Promise.all(settled.map((entry) => readSettledOutput(host, entry)));
|
|
11995
|
+
const present = sections.filter((section) => section !== undefined);
|
|
11996
|
+
return present.length ? `
|
|
11997
|
+
|
|
11998
|
+
${present.join(`
|
|
11999
|
+
|
|
12000
|
+
`)}` : "";
|
|
12001
|
+
}
|
|
12002
|
+
function taskToolResult(response, host) {
|
|
12003
|
+
return {
|
|
12004
|
+
content: [{ type: "text", text: subagentTaskResponseText(response) }],
|
|
12005
|
+
details: {
|
|
12006
|
+
mode: "single",
|
|
12007
|
+
results: [],
|
|
12008
|
+
taskResponse: response,
|
|
12009
|
+
taskRecords: taskResponseRecords(response, host)
|
|
12010
|
+
},
|
|
12011
|
+
...response.kind === "unstarted" ? { isError: true } : {}
|
|
12012
|
+
};
|
|
12013
|
+
}
|
|
12014
|
+
async function taskToolResultWithOutput(response, host) {
|
|
12015
|
+
const result = taskToolResult(response, host);
|
|
12016
|
+
const outputText = await settledTaskOutputText(host, settledOutputsFromResponse(response));
|
|
12017
|
+
if (!outputText)
|
|
12018
|
+
return result;
|
|
12019
|
+
return {
|
|
12020
|
+
...result,
|
|
12021
|
+
content: [{ type: "text", text: `${subagentTaskResponseText(response)}${outputText}` }]
|
|
12022
|
+
};
|
|
12023
|
+
}
|
|
12024
|
+
async function parallelTaskToolResultWithOutput(response, host) {
|
|
12025
|
+
return {
|
|
12026
|
+
content: [
|
|
12027
|
+
{
|
|
12028
|
+
type: "text",
|
|
12029
|
+
text: `${subagentTaskResponseText(response)}${await settledTaskOutputText(host, settledOutputsFromResponse(response))}`
|
|
12030
|
+
}
|
|
12031
|
+
],
|
|
12032
|
+
details: {
|
|
12033
|
+
mode: "parallel",
|
|
12034
|
+
results: [],
|
|
12035
|
+
taskResponse: response,
|
|
12036
|
+
taskRecords: taskResponseRecords(response, host)
|
|
12037
|
+
}
|
|
12038
|
+
};
|
|
12039
|
+
}
|
|
12040
|
+
function taskResponseRecords(response, host) {
|
|
12041
|
+
const outcomes = response.kind === "parallel" ? response.slots.map((slot) => slot.outcome) : [response];
|
|
12042
|
+
const ids = new Set(outcomes.flatMap((outcome) => outcome.kind === "admitted" ? [outcome.observation.taskId] : []));
|
|
12043
|
+
const watched = host?.watchOwnerTasks();
|
|
12044
|
+
if (!watched?.ok)
|
|
12045
|
+
return [];
|
|
12046
|
+
try {
|
|
12047
|
+
return watched.value.snapshot.tasks.filter((task) => ids.has(task.ref.taskId));
|
|
12048
|
+
} finally {
|
|
12049
|
+
watched.value.dispose();
|
|
12050
|
+
}
|
|
12051
|
+
}
|
|
12052
|
+
async function runAgentTask(input) {
|
|
12053
|
+
let yieldWait;
|
|
12054
|
+
let pendingYield = false;
|
|
12055
|
+
let parentObserving = input.wait?.kind === "foreground";
|
|
12056
|
+
const registered = Promise.withResolvers();
|
|
12057
|
+
input.options.modelRoute?.assertCurrent();
|
|
12058
|
+
const started = await input.host.startAgentTask({
|
|
12059
|
+
kind: "agent",
|
|
12060
|
+
agent: input.agent,
|
|
12061
|
+
task: input.intentTask ?? input.task,
|
|
12062
|
+
cwd: input.options.cwd ?? input.cwd,
|
|
12063
|
+
...input.options.modelRoute ? { routerSelection: input.options.modelRoute.routerSelection } : {}
|
|
12064
|
+
}, `${input.options.runId}:${input.options.index ?? 0}`, (context) => {
|
|
12065
|
+
const cleaned = Promise.withResolvers();
|
|
12066
|
+
let executionBound = false;
|
|
12067
|
+
const result = registered.promise.then(async () => {
|
|
12068
|
+
try {
|
|
12069
|
+
input.options.modelRoute?.assertCurrent();
|
|
12070
|
+
const child = await input.runtime.runSync(input.cwd, input.agents, input.agent, input.task, {
|
|
12071
|
+
...input.options,
|
|
12072
|
+
signal: context.signal,
|
|
12073
|
+
taskExecution: {
|
|
12074
|
+
signal: context.signal,
|
|
12075
|
+
reportActivity: context.reportActivity,
|
|
12076
|
+
bindTranscript: (session) => context.bindTranscript({
|
|
12077
|
+
getSessionId: () => session.getSessionId(),
|
|
12078
|
+
getEntries: () => session.getEntries(),
|
|
12079
|
+
...session.subscribe ? { subscribe: session.subscribe.bind(session) } : {},
|
|
12080
|
+
...session.getStreamingMessage ? { getStreamingMessage: session.getStreamingMessage.bind(session) } : {},
|
|
12081
|
+
...input.options.intercomSessionName ? {
|
|
12082
|
+
completionSource: {
|
|
12083
|
+
runId: input.options.runId,
|
|
12084
|
+
intercomTarget: input.options.intercomSessionName
|
|
12085
|
+
}
|
|
12086
|
+
} : {}
|
|
12087
|
+
}),
|
|
12088
|
+
onExecution: (execution) => {
|
|
12089
|
+
executionBound = true;
|
|
12090
|
+
execution.cleanup.then(cleaned.resolve, (error) => cleaned.resolve({
|
|
12091
|
+
kind: "failed",
|
|
12092
|
+
resources: [{ resource: "agent-session", code: "CleanupFailed", message: String(error) }]
|
|
12093
|
+
}));
|
|
12094
|
+
},
|
|
12095
|
+
yieldTaskWait: () => {
|
|
12096
|
+
parentObserving = false;
|
|
12097
|
+
if (yieldWait)
|
|
12098
|
+
yieldWait("intercom-coordination");
|
|
12099
|
+
else
|
|
12100
|
+
pendingYield = true;
|
|
12101
|
+
},
|
|
12102
|
+
isParentObserving: () => parentObserving
|
|
12103
|
+
}
|
|
12104
|
+
});
|
|
12105
|
+
if (child.model !== undefined || child.thinking !== undefined)
|
|
12106
|
+
context.reportActivity({
|
|
12107
|
+
reportId: "terminal-model",
|
|
12108
|
+
change: { kind: "model", model: child.model, thinking: child.thinking }
|
|
12109
|
+
});
|
|
12110
|
+
input.onTerminal?.(child);
|
|
12111
|
+
const text = input.outputText?.(child) ?? getSingleResultOutput(child);
|
|
12112
|
+
retainTaskOutput(child, text, context.ref);
|
|
12113
|
+
const bytes = Buffer.from(text);
|
|
12114
|
+
context.reportActivity({
|
|
12115
|
+
reportId: "terminal-output",
|
|
12116
|
+
change: { kind: "output", offset: "0", bytesBase64: bytes.toString("base64") }
|
|
12117
|
+
});
|
|
12118
|
+
const output = {
|
|
12119
|
+
ownerId: context.ref.ownerId,
|
|
12120
|
+
taskId: context.ref.taskId,
|
|
12121
|
+
artifactId: `output:${context.ref.taskId}`,
|
|
12122
|
+
byteCount: String(bytes.length),
|
|
12123
|
+
omittedRanges: []
|
|
12124
|
+
};
|
|
12125
|
+
if (child.status === "killed")
|
|
12126
|
+
return { kind: "cancelled", cause: "user", output };
|
|
12127
|
+
if (child.interrupted)
|
|
12128
|
+
return {
|
|
12129
|
+
kind: "cancelled",
|
|
12130
|
+
cause: input.options.interruptSignal?.aborted ? "parent-handoff" : "owner-close",
|
|
12131
|
+
output
|
|
12132
|
+
};
|
|
12133
|
+
return child.status === "ok" ? { kind: "completed", output } : {
|
|
12134
|
+
kind: "failed",
|
|
12135
|
+
code: "AgentFailed",
|
|
12136
|
+
message: child.error ?? child.envelope ?? "Agent failed",
|
|
12137
|
+
output
|
|
12138
|
+
};
|
|
12139
|
+
} finally {
|
|
12140
|
+
if (!executionBound)
|
|
12141
|
+
cleaned.resolve({ kind: "reaped" });
|
|
12142
|
+
}
|
|
12143
|
+
});
|
|
12144
|
+
return { result, cleanup: cleaned.promise };
|
|
12145
|
+
}, input.schedule);
|
|
12146
|
+
if (!started.ok)
|
|
12147
|
+
return { kind: "unstarted", reason: { kind: "rejected", error: started.error } };
|
|
12148
|
+
const yieldForIntercom = () => {
|
|
12149
|
+
parentObserving = false;
|
|
12150
|
+
if (yieldWait)
|
|
12151
|
+
yieldWait("intercom-coordination");
|
|
12152
|
+
else
|
|
12153
|
+
pendingYield = true;
|
|
12154
|
+
};
|
|
12155
|
+
input.options.intercomDetachSignal?.addEventListener("abort", yieldForIntercom, { once: true });
|
|
12156
|
+
if (input.options.intercomDetachSignal?.aborted)
|
|
12157
|
+
yieldForIntercom();
|
|
12158
|
+
const observation = input.host.observeAgentLaunch(started.value.taskId, input.wait, (yieldRegistered) => {
|
|
12159
|
+
yieldWait = yieldRegistered;
|
|
12160
|
+
if (pendingYield)
|
|
12161
|
+
yieldRegistered("intercom-coordination");
|
|
12162
|
+
registered.resolve();
|
|
12163
|
+
});
|
|
12164
|
+
registered.resolve();
|
|
12165
|
+
const observed = await observation.finally(() => {
|
|
12166
|
+
parentObserving = false;
|
|
12167
|
+
input.options.intercomDetachSignal?.removeEventListener("abort", yieldForIntercom);
|
|
12168
|
+
});
|
|
12169
|
+
if (!observed.ok)
|
|
12170
|
+
throw new Error(`${observed.error.code}: ${observed.error.message}`);
|
|
12171
|
+
return { kind: "admitted", observation: observed.value };
|
|
12172
|
+
}
|
|
12173
|
+
|
|
12174
|
+
// dist/builtin/subagents/src/runs/foreground/subagent-executor-burst.ts
|
|
12175
|
+
var SHARED_FIELDS = [
|
|
12176
|
+
"concurrency",
|
|
12177
|
+
"worktree",
|
|
12178
|
+
"context",
|
|
12179
|
+
"share",
|
|
12180
|
+
"control",
|
|
12181
|
+
"sessionDir",
|
|
12182
|
+
"maxOutput",
|
|
12183
|
+
"artifacts",
|
|
12184
|
+
"includeProgress",
|
|
12185
|
+
"agentScope"
|
|
12186
|
+
];
|
|
12187
|
+
function incompatibleField(items) {
|
|
12188
|
+
const first = items[0].params;
|
|
12189
|
+
for (const field of SHARED_FIELDS) {
|
|
12190
|
+
for (let index = 1;index < items.length; index++) {
|
|
12191
|
+
if (!isDeepStrictEqual(first[field], items[index].params[field]))
|
|
12192
|
+
return field;
|
|
12193
|
+
}
|
|
12194
|
+
}
|
|
12195
|
+
return;
|
|
12196
|
+
}
|
|
12197
|
+
function incompatibleFieldResult(field) {
|
|
12198
|
+
return {
|
|
12199
|
+
content: [
|
|
12200
|
+
{
|
|
12201
|
+
type: "text",
|
|
12202
|
+
text: `Cannot coalesce sibling subagent calls: incompatible top-level field '${field}'.`
|
|
12203
|
+
}
|
|
12204
|
+
],
|
|
12205
|
+
isError: true,
|
|
12206
|
+
details: { mode: "parallel", results: [] }
|
|
12207
|
+
};
|
|
12208
|
+
}
|
|
12209
|
+
function incompatibleWorktreeCwdResult() {
|
|
12210
|
+
return {
|
|
12211
|
+
content: [
|
|
12212
|
+
{
|
|
12213
|
+
type: "text",
|
|
12214
|
+
text: "Cannot coalesce sibling subagent calls: incompatible top-level field 'cwd' for worktree."
|
|
12215
|
+
}
|
|
12216
|
+
],
|
|
12217
|
+
isError: true,
|
|
12218
|
+
details: { mode: "parallel", results: [] }
|
|
12219
|
+
};
|
|
12220
|
+
}
|
|
12221
|
+
function taskExpandedLength(task) {
|
|
12222
|
+
const count = task.count;
|
|
12223
|
+
return typeof count === "number" && Number.isInteger(count) && count >= 1 ? count : 1;
|
|
12224
|
+
}
|
|
12225
|
+
function originatingCallCwd(item) {
|
|
12226
|
+
return resolveRequestedCwd(item.ctx.cwd, item.params.cwd);
|
|
12227
|
+
}
|
|
12228
|
+
function originatingTaskCwd(callCwd, taskCwd) {
|
|
12229
|
+
return resolveRequestedCwd(callCwd, taskCwd);
|
|
12230
|
+
}
|
|
12231
|
+
function topLevelSingleTask(item) {
|
|
12232
|
+
if (!item.params.agent)
|
|
12233
|
+
return;
|
|
12234
|
+
const callCwd = originatingCallCwd(item);
|
|
12235
|
+
return {
|
|
12236
|
+
agent: item.params.agent,
|
|
12237
|
+
task: item.params.task ?? "",
|
|
12238
|
+
cwd: originatingTaskCwd(callCwd, undefined),
|
|
12239
|
+
[BURST_TASK_DISCOVERY_CWD]: callCwd,
|
|
12240
|
+
...item.params.output !== undefined ? { output: item.params.output } : {},
|
|
12241
|
+
...item.params.outputMode !== undefined ? { outputMode: item.params.outputMode } : {},
|
|
12242
|
+
...item.params.reads !== undefined ? { reads: item.params.reads } : {},
|
|
12243
|
+
...item.params.progress !== undefined ? { progress: item.params.progress } : {},
|
|
12244
|
+
...item.params.model !== undefined ? { model: item.params.model } : {},
|
|
12245
|
+
...item.params.modelConstraints !== undefined ? { modelConstraints: item.params.modelConstraints } : {},
|
|
12246
|
+
...item.params.taskNeeds !== undefined ? { taskNeeds: item.params.taskNeeds } : {},
|
|
12247
|
+
...item.params.skill !== undefined ? { skill: item.params.skill } : {},
|
|
12248
|
+
...item.params.group !== undefined ? { group: item.params.group } : {}
|
|
12249
|
+
};
|
|
12250
|
+
}
|
|
12251
|
+
function existingParallelTask(item, task) {
|
|
12252
|
+
const callCwd = originatingCallCwd(item);
|
|
12253
|
+
return {
|
|
12254
|
+
...task,
|
|
12255
|
+
cwd: originatingTaskCwd(callCwd, task.cwd),
|
|
12256
|
+
[BURST_TASK_DISCOVERY_CWD]: callCwd,
|
|
12257
|
+
...task.group === undefined && item.params.group !== undefined ? { group: item.params.group } : {}
|
|
12258
|
+
};
|
|
11812
12259
|
}
|
|
11813
12260
|
function mergeBurst(items) {
|
|
11814
12261
|
const field = incompatibleField(items);
|
|
@@ -11835,6 +12282,7 @@ function mergeBurst(items) {
|
|
|
11835
12282
|
params: {
|
|
11836
12283
|
...commonCwd ? { cwd: commonCwd } : {},
|
|
11837
12284
|
tasks,
|
|
12285
|
+
wait: first.wait,
|
|
11838
12286
|
concurrency: first.concurrency,
|
|
11839
12287
|
worktree: first.worktree,
|
|
11840
12288
|
context: first.context,
|
|
@@ -11930,6 +12378,19 @@ function projectResult(result, route, live = false) {
|
|
|
11930
12378
|
}
|
|
11931
12379
|
};
|
|
11932
12380
|
}
|
|
12381
|
+
function isSingleResponse(outcome) {
|
|
12382
|
+
return outcome.kind === "admitted" || outcome.reason.kind === "rejected";
|
|
12383
|
+
}
|
|
12384
|
+
async function projectOwnerResult(result, route, item, ctx) {
|
|
12385
|
+
const response = result.details?.taskResponse;
|
|
12386
|
+
if (response?.kind !== "parallel")
|
|
12387
|
+
return;
|
|
12388
|
+
const slots = response.slots.slice(route.start, route.start + route.length).map((slot, ordinal) => ({ ...slot, ordinal }));
|
|
12389
|
+
const host = ctx.getAgentTaskHost?.();
|
|
12390
|
+
const own = slots.length === 1 ? slots[0].outcome : undefined;
|
|
12391
|
+
const projected = item.params.agent !== undefined && own !== undefined && isSingleResponse(own) ? await taskToolResultWithOutput(own, host) : await parallelTaskToolResultWithOutput({ kind: "parallel", slots }, host);
|
|
12392
|
+
return withForkContext(projected, item.params.context ?? result.details?.context);
|
|
12393
|
+
}
|
|
11933
12394
|
function resolveItem(item, result) {
|
|
11934
12395
|
if (item.settled)
|
|
11935
12396
|
return;
|
|
@@ -11965,19 +12426,30 @@ function observeLaterAbort(item) {
|
|
|
11965
12426
|
}
|
|
11966
12427
|
return cleanup;
|
|
11967
12428
|
}
|
|
12429
|
+
function groupByWait(items) {
|
|
12430
|
+
const groups = [];
|
|
12431
|
+
for (const item of items) {
|
|
12432
|
+
const group = groups.find((candidate) => isDeepStrictEqual(candidate[0].params.wait, item.params.wait));
|
|
12433
|
+
if (group)
|
|
12434
|
+
group.push(item);
|
|
12435
|
+
else
|
|
12436
|
+
groups.push([item]);
|
|
12437
|
+
}
|
|
12438
|
+
return groups;
|
|
12439
|
+
}
|
|
11968
12440
|
function createExecutionBurstDispatcher(input) {
|
|
11969
12441
|
let queue = [];
|
|
11970
12442
|
let flushScheduled = false;
|
|
11971
|
-
const run = async (items) => {
|
|
12443
|
+
const run = async (items, finish, schedule) => {
|
|
11972
12444
|
if (items.length === 1) {
|
|
11973
12445
|
const item = items[0];
|
|
11974
|
-
|
|
12446
|
+
const params = schedule ? { ...item.params, [BURST_EXECUTION_SCHEDULE]: schedule } : item.params;
|
|
11975
12447
|
try {
|
|
11976
|
-
item.resolve(await input.execute(item.id,
|
|
12448
|
+
item.resolve(await input.execute(item.id, params, item.signal, item.onUpdate, item.ctx));
|
|
11977
12449
|
} catch (error) {
|
|
11978
12450
|
item.reject(error instanceof Error ? error : new Error(String(error)));
|
|
11979
12451
|
} finally {
|
|
11980
|
-
|
|
12452
|
+
finish();
|
|
11981
12453
|
}
|
|
11982
12454
|
return;
|
|
11983
12455
|
}
|
|
@@ -11991,8 +12463,11 @@ function createExecutionBurstDispatcher(input) {
|
|
|
11991
12463
|
for (const item of items)
|
|
11992
12464
|
resolveItem(item, merged.error);
|
|
11993
12465
|
cleanupLaterAborts();
|
|
12466
|
+
finish();
|
|
11994
12467
|
return;
|
|
11995
12468
|
}
|
|
12469
|
+
if (schedule)
|
|
12470
|
+
merged.params[BURST_EXECUTION_SCHEDULE] = schedule;
|
|
11996
12471
|
const first = items[0];
|
|
11997
12472
|
const display = registerBurstDisplay(items.map((item) => item.id), merged.routes.reduce((total, route) => total + route.length, 0));
|
|
11998
12473
|
const onUpdate = (update) => {
|
|
@@ -12003,27 +12478,38 @@ function createExecutionBurstDispatcher(input) {
|
|
|
12003
12478
|
item.onUpdate?.(projectResult(update, merged.routes[index], true));
|
|
12004
12479
|
}
|
|
12005
12480
|
};
|
|
12006
|
-
input.setActive(true);
|
|
12007
12481
|
try {
|
|
12008
12482
|
const result = await input.execute(first.id, merged.params, first.signal, onUpdate, first.ctx);
|
|
12009
12483
|
updateBurstDisplay(display, result);
|
|
12010
|
-
|
|
12011
|
-
|
|
12012
|
-
|
|
12484
|
+
const projections = await Promise.all(items.map(async (item, index) => await projectOwnerResult(result, merged.routes[index], item, first.ctx) ?? projectResult(result, merged.routes[index])));
|
|
12485
|
+
for (let index = 0;index < items.length; index++)
|
|
12486
|
+
resolveItem(items[index], projections[index]);
|
|
12013
12487
|
} catch (error) {
|
|
12014
12488
|
const rejection = error instanceof Error ? error : new Error(String(error));
|
|
12015
12489
|
for (const item of items)
|
|
12016
12490
|
rejectItem(item, rejection);
|
|
12017
12491
|
} finally {
|
|
12018
|
-
input.setActive(false);
|
|
12019
12492
|
cleanupLaterAborts();
|
|
12493
|
+
finish();
|
|
12020
12494
|
}
|
|
12021
12495
|
};
|
|
12496
|
+
const runBurst = (items) => {
|
|
12497
|
+
const groups = groupByWait(items);
|
|
12498
|
+
const schedule = groups.length > 1 ? createExecutionScheduler(Math.min(...items.map((item) => resolveTopLevelParallelConcurrency(item.params.concurrency, input.concurrencyLimit)))) : undefined;
|
|
12499
|
+
let remaining = groups.length;
|
|
12500
|
+
input.setActive(true);
|
|
12501
|
+
const finish = () => {
|
|
12502
|
+
if (--remaining === 0)
|
|
12503
|
+
input.setActive(false);
|
|
12504
|
+
};
|
|
12505
|
+
for (const group of groups)
|
|
12506
|
+
run(group, finish, schedule);
|
|
12507
|
+
};
|
|
12022
12508
|
const flush = () => {
|
|
12023
12509
|
flushScheduled = false;
|
|
12024
12510
|
const items = queue;
|
|
12025
12511
|
queue = [];
|
|
12026
|
-
|
|
12512
|
+
runBurst(items);
|
|
12027
12513
|
};
|
|
12028
12514
|
return (id, params, signal, onUpdate, ctx) => {
|
|
12029
12515
|
if (input.isActive())
|
|
@@ -12162,144 +12648,31 @@ Create and maintain progress at: ${path12.join(progressDir, "progress.md")}`;
|
|
|
12162
12648
|
}
|
|
12163
12649
|
function buildTaskInstructions(behavior, cwd, isFirstProgressAgent) {
|
|
12164
12650
|
const prefixParts = [];
|
|
12165
|
-
const suffixParts = [];
|
|
12166
|
-
const readInstruction = buildReadInstruction(behavior.reads, cwd);
|
|
12167
|
-
if (readInstruction)
|
|
12168
|
-
prefixParts.push(readInstruction);
|
|
12169
|
-
if (behavior.output) {
|
|
12170
|
-
const outputPath = path12.isAbsolute(behavior.output) ? behavior.output : path12.join(cwd, behavior.output);
|
|
12171
|
-
prefixParts.push(`[Write to: ${outputPath}]`);
|
|
12172
|
-
}
|
|
12173
|
-
if (behavior.progress) {
|
|
12174
|
-
const progressPath = path12.join(cwd, "progress.md");
|
|
12175
|
-
if (isFirstProgressAgent)
|
|
12176
|
-
suffixParts.push(`Create and maintain progress at: ${progressPath}`);
|
|
12177
|
-
else
|
|
12178
|
-
suffixParts.push(`Update progress at: ${progressPath}`);
|
|
12179
|
-
}
|
|
12180
|
-
const prefix = prefixParts.length > 0 ? `${prefixParts.join(`
|
|
12181
|
-
`)}
|
|
12182
|
-
|
|
12183
|
-
` : "";
|
|
12184
|
-
const suffix = suffixParts.length > 0 ? `
|
|
12185
|
-
|
|
12186
|
-
---
|
|
12187
|
-
${suffixParts.join(`
|
|
12188
|
-
`)}` : "";
|
|
12189
|
-
return { prefix, suffix };
|
|
12190
|
-
}
|
|
12191
|
-
|
|
12192
|
-
// dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts
|
|
12193
|
-
function validateExecutionInput(params, agents, hasTasks, hasSingle, parallelAgentConfigs) {
|
|
12194
|
-
if (Number(hasTasks) + Number(hasSingle) !== 1) {
|
|
12195
|
-
return {
|
|
12196
|
-
content: [
|
|
12197
|
-
{
|
|
12198
|
-
type: "text",
|
|
12199
|
-
text: `Provide exactly one mode. Agents: ${agents.map((a) => a.name).join(", ") || "none"}`
|
|
12200
|
-
}
|
|
12201
|
-
],
|
|
12202
|
-
isError: true,
|
|
12203
|
-
details: { mode: "single", results: [] }
|
|
12204
|
-
};
|
|
12205
|
-
}
|
|
12206
|
-
if (hasSingle) {
|
|
12207
|
-
const reads = params.reads;
|
|
12208
|
-
if (reads !== undefined && reads !== false && (!Array.isArray(reads) || reads.some((entry) => typeof entry !== "string"))) {
|
|
12209
|
-
return {
|
|
12210
|
-
content: [{ type: "text", text: "reads must be an array of file path strings or false" }],
|
|
12211
|
-
isError: true,
|
|
12212
|
-
details: { mode: "single", results: [] }
|
|
12213
|
-
};
|
|
12214
|
-
}
|
|
12215
|
-
}
|
|
12216
|
-
if (hasSingle && params.agent && !agents.find((agent) => agent.name === params.agent)) {
|
|
12217
|
-
return {
|
|
12218
|
-
content: [{ type: "text", text: `Unknown agent: ${params.agent}` }],
|
|
12219
|
-
isError: true,
|
|
12220
|
-
details: { mode: "single", results: [] }
|
|
12221
|
-
};
|
|
12222
|
-
}
|
|
12223
|
-
if (hasTasks && params.tasks) {
|
|
12224
|
-
for (let i = 0;i < params.tasks.length; i++) {
|
|
12225
|
-
const task = params.tasks[i];
|
|
12226
|
-
const agent = parallelAgentConfigs?.[i] ?? agents.find((candidate) => candidate.name === task.agent);
|
|
12227
|
-
if (!agent || agent.name !== task.agent) {
|
|
12228
|
-
return {
|
|
12229
|
-
content: [{ type: "text", text: `Unknown agent: ${task.agent} (task ${i + 1})` }],
|
|
12230
|
-
isError: true,
|
|
12231
|
-
details: { mode: "parallel", results: [] }
|
|
12232
|
-
};
|
|
12233
|
-
}
|
|
12234
|
-
}
|
|
12235
|
-
}
|
|
12236
|
-
return null;
|
|
12237
|
-
}
|
|
12238
|
-
function getRequestedModeLabel(params) {
|
|
12239
|
-
if ((params.tasks?.length ?? 0) > 0)
|
|
12240
|
-
return "parallel";
|
|
12241
|
-
if (params.agent)
|
|
12242
|
-
return "single";
|
|
12243
|
-
return "single";
|
|
12244
|
-
}
|
|
12245
|
-
function applyAgentDefaultContext(params, agents) {
|
|
12246
|
-
if (params.context !== undefined)
|
|
12247
|
-
return params;
|
|
12248
|
-
const byName = new Map(agents.map((agent) => [agent.name, agent]));
|
|
12249
|
-
const names = [];
|
|
12250
|
-
if (params.agent)
|
|
12251
|
-
names.push(params.agent);
|
|
12252
|
-
for (const task of params.tasks ?? [])
|
|
12253
|
-
names.push(task.agent);
|
|
12254
|
-
return names.some((name) => byName.get(name)?.defaultContext === "fork") ? { ...params, context: "fork" } : params;
|
|
12255
|
-
}
|
|
12256
|
-
function buildRequestedModeError(params, message) {
|
|
12257
|
-
return withForkContext({
|
|
12258
|
-
content: [{ type: "text", text: message }],
|
|
12259
|
-
isError: true,
|
|
12260
|
-
details: { mode: getRequestedModeLabel(params), results: [] }
|
|
12261
|
-
}, params.context);
|
|
12262
|
-
}
|
|
12263
|
-
function expandTopLevelTaskCounts(tasks) {
|
|
12264
|
-
const expanded = [];
|
|
12265
|
-
for (let taskIndex = 0;taskIndex < tasks.length; taskIndex++) {
|
|
12266
|
-
const task = tasks[taskIndex];
|
|
12267
|
-
const rawCount = task.count;
|
|
12268
|
-
if (rawCount !== undefined && (typeof rawCount !== "number" || !Number.isInteger(rawCount) || rawCount < 1)) {
|
|
12269
|
-
return { error: `tasks[${taskIndex}].count must be an integer >= 1` };
|
|
12270
|
-
}
|
|
12271
|
-
const { count: _count, ...concreteTask } = task;
|
|
12272
|
-
for (let repeat = 0;repeat < (rawCount ?? 1); repeat++)
|
|
12273
|
-
expanded.push({ ...concreteTask });
|
|
12274
|
-
}
|
|
12275
|
-
return { tasks: expanded };
|
|
12276
|
-
}
|
|
12277
|
-
function normalizeRepeatedParallelCounts(params) {
|
|
12278
|
-
if (!params.tasks)
|
|
12279
|
-
return { params };
|
|
12280
|
-
const expandedTasks = expandTopLevelTaskCounts(params.tasks);
|
|
12281
|
-
if (expandedTasks.error)
|
|
12282
|
-
return { error: buildRequestedModeError(params, expandedTasks.error) };
|
|
12283
|
-
return { params: { ...params, tasks: expandedTasks.tasks } };
|
|
12284
|
-
}
|
|
12285
|
-
function withForkContext(result, context) {
|
|
12286
|
-
if (context !== "fork" || !result.details)
|
|
12287
|
-
return result;
|
|
12288
|
-
return {
|
|
12289
|
-
...result,
|
|
12290
|
-
details: {
|
|
12291
|
-
...result.details,
|
|
12292
|
-
context: "fork"
|
|
12293
|
-
}
|
|
12294
|
-
};
|
|
12295
|
-
}
|
|
12296
|
-
function toExecutionErrorResult(params, error) {
|
|
12297
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
12298
|
-
return withForkContext({
|
|
12299
|
-
content: [{ type: "text", text: message }],
|
|
12300
|
-
isError: true,
|
|
12301
|
-
details: { mode: getRequestedModeLabel(params), results: [] }
|
|
12302
|
-
}, params.context);
|
|
12651
|
+
const suffixParts = [];
|
|
12652
|
+
const readInstruction = buildReadInstruction(behavior.reads, cwd);
|
|
12653
|
+
if (readInstruction)
|
|
12654
|
+
prefixParts.push(readInstruction);
|
|
12655
|
+
if (behavior.output) {
|
|
12656
|
+
const outputPath = path12.isAbsolute(behavior.output) ? behavior.output : path12.join(cwd, behavior.output);
|
|
12657
|
+
prefixParts.push(`[Write to: ${outputPath}]`);
|
|
12658
|
+
}
|
|
12659
|
+
if (behavior.progress) {
|
|
12660
|
+
const progressPath = path12.join(cwd, "progress.md");
|
|
12661
|
+
if (isFirstProgressAgent)
|
|
12662
|
+
suffixParts.push(`Create and maintain progress at: ${progressPath}`);
|
|
12663
|
+
else
|
|
12664
|
+
suffixParts.push(`Update progress at: ${progressPath}`);
|
|
12665
|
+
}
|
|
12666
|
+
const prefix = prefixParts.length > 0 ? `${prefixParts.join(`
|
|
12667
|
+
`)}
|
|
12668
|
+
|
|
12669
|
+
` : "";
|
|
12670
|
+
const suffix = suffixParts.length > 0 ? `
|
|
12671
|
+
|
|
12672
|
+
---
|
|
12673
|
+
${suffixParts.join(`
|
|
12674
|
+
`)}` : "";
|
|
12675
|
+
return { prefix, suffix };
|
|
12303
12676
|
}
|
|
12304
12677
|
|
|
12305
12678
|
// dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts
|
|
@@ -13374,400 +13747,102 @@ function formatWorktreeDiffSummary(diffs) {
|
|
|
13374
13747
|
lines.push(diff.diffStat);
|
|
13375
13748
|
}
|
|
13376
13749
|
lines.push("");
|
|
13377
|
-
}
|
|
13378
|
-
const patchesDir = path18.dirname(changed[0].patchPath);
|
|
13379
|
-
lines.push(`Full patches: ${patchesDir}`);
|
|
13380
|
-
return lines.join(`
|
|
13381
|
-
`).trimEnd();
|
|
13382
|
-
}
|
|
13383
|
-
|
|
13384
|
-
// dist/builtin/subagents/src/runs/foreground/detached-cleanup-barrier.ts
|
|
13385
|
-
function createDetachedCleanupBarrier(onReady) {
|
|
13386
|
-
const recovered = new Set;
|
|
13387
|
-
let expected;
|
|
13388
|
-
let cleaned = false;
|
|
13389
|
-
const finishIfReady = () => {
|
|
13390
|
-
if (cleaned || !expected || ![...expected].every((index) => recovered.has(index)))
|
|
13391
|
-
return;
|
|
13392
|
-
cleaned = true;
|
|
13393
|
-
onReady();
|
|
13394
|
-
};
|
|
13395
|
-
return {
|
|
13396
|
-
recover(index) {
|
|
13397
|
-
recovered.add(index);
|
|
13398
|
-
finishIfReady();
|
|
13399
|
-
},
|
|
13400
|
-
defer(indices) {
|
|
13401
|
-
if (indices.length === 0)
|
|
13402
|
-
return false;
|
|
13403
|
-
expected = new Set(indices);
|
|
13404
|
-
finishIfReady();
|
|
13405
|
-
return true;
|
|
13406
|
-
}
|
|
13407
|
-
};
|
|
13408
|
-
}
|
|
13409
|
-
|
|
13410
|
-
// dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts
|
|
13411
|
-
import { join as join19 } from "node:path";
|
|
13412
|
-
|
|
13413
|
-
// dist/builtin/subagents/src/runs/foreground/subagent-executor-worktree.ts
|
|
13414
|
-
import * as path19 from "node:path";
|
|
13415
|
-
function buildParallelModeError(message) {
|
|
13416
|
-
return {
|
|
13417
|
-
content: [{ type: "text", text: message }],
|
|
13418
|
-
isError: true,
|
|
13419
|
-
details: { mode: "parallel", results: [] }
|
|
13420
|
-
};
|
|
13421
|
-
}
|
|
13422
|
-
function createParallelWorktreeSetup(enabled, cwd, runId, tasks, setupHook, setupHookTimeoutMs) {
|
|
13423
|
-
if (!enabled)
|
|
13424
|
-
return {};
|
|
13425
|
-
try {
|
|
13426
|
-
return {
|
|
13427
|
-
setup: createWorktrees(cwd, runId, tasks.length, {
|
|
13428
|
-
agents: tasks.map((task) => task.agent),
|
|
13429
|
-
setupHook: setupHook ? { hookPath: setupHook, timeoutMs: setupHookTimeoutMs } : undefined
|
|
13430
|
-
})
|
|
13431
|
-
};
|
|
13432
|
-
} catch (error) {
|
|
13433
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
13434
|
-
return { errorResult: buildParallelModeError(message) };
|
|
13435
|
-
}
|
|
13436
|
-
}
|
|
13437
|
-
function buildParallelWorktreeTaskCwdError(tasks, sharedCwd) {
|
|
13438
|
-
const conflict = findWorktreeTaskCwdConflict(tasks, sharedCwd);
|
|
13439
|
-
if (!conflict)
|
|
13440
|
-
return;
|
|
13441
|
-
return formatWorktreeTaskCwdConflict(conflict, sharedCwd);
|
|
13442
|
-
}
|
|
13443
|
-
function resolveParallelTaskCwd(task, paramsCwd, worktreeSetup, index) {
|
|
13444
|
-
if (worktreeSetup)
|
|
13445
|
-
return worktreeSetup.worktrees[index].agentCwd;
|
|
13446
|
-
return resolveChildCwd(paramsCwd, task.cwd);
|
|
13447
|
-
}
|
|
13448
|
-
function buildParallelWorktreeSuffix(worktreeSetup, artifactsDir, tasks) {
|
|
13449
|
-
if (!worktreeSetup)
|
|
13450
|
-
return "";
|
|
13451
|
-
const diffsDir = path19.join(artifactsDir, "worktree-diffs");
|
|
13452
|
-
const diffs = diffWorktrees(worktreeSetup, tasks.map((task) => task.agent), diffsDir);
|
|
13453
|
-
return formatWorktreeDiffSummary(diffs);
|
|
13454
|
-
}
|
|
13455
|
-
function findDuplicateParallelOutputPath(input) {
|
|
13456
|
-
const seen = new Map;
|
|
13457
|
-
for (let index = 0;index < input.tasks.length; index++) {
|
|
13458
|
-
const behavior = input.behaviors[index];
|
|
13459
|
-
if (!behavior?.output)
|
|
13460
|
-
continue;
|
|
13461
|
-
const task = input.tasks[index];
|
|
13462
|
-
const taskCwd = resolveParallelTaskCwd(task, input.paramsCwd, input.worktreeSetup, index);
|
|
13463
|
-
const outputPath = resolveSingleOutputPath(behavior.output, input.ctxCwd, taskCwd);
|
|
13464
|
-
if (!outputPath)
|
|
13465
|
-
continue;
|
|
13466
|
-
const previous = seen.get(outputPath);
|
|
13467
|
-
if (previous) {
|
|
13468
|
-
return `Parallel tasks ${previous.index + 1} (${previous.agent}) and ${index + 1} (${task.agent}) resolve output to the same path: ${outputPath}. Use distinct output paths.`;
|
|
13469
|
-
}
|
|
13470
|
-
seen.set(outputPath, { index, agent: task.agent });
|
|
13471
|
-
}
|
|
13472
|
-
return;
|
|
13473
|
-
}
|
|
13474
|
-
|
|
13475
|
-
// dist/builtin/subagents/src/runs/foreground/task-output-retention.ts
|
|
13476
|
-
import { mkdtempSync, readFileSync as readFileSync11, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
13477
|
-
import { tmpdir as tmpdir2 } from "node:os";
|
|
13478
|
-
import { join as join18 } from "node:path";
|
|
13479
|
-
var INLINE_TASK_OUTPUT_MAX_BYTES = 16 * 1024;
|
|
13480
|
-
var MAX_RETAINED_TASK_OUTPUTS = 256;
|
|
13481
|
-
var retained = new Map;
|
|
13482
|
-
var copyRoot;
|
|
13483
|
-
function retentionKey(ownerId, taskId) {
|
|
13484
|
-
return `${ownerId}\x00${taskId}`;
|
|
13485
|
-
}
|
|
13486
|
-
function fileSafe(value) {
|
|
13487
|
-
return value.replace(/[^A-Za-z0-9._-]+/g, "_");
|
|
13488
|
-
}
|
|
13489
|
-
function privateCopyRoot() {
|
|
13490
|
-
if (copyRoot)
|
|
13491
|
-
return copyRoot;
|
|
13492
|
-
const root = mkdtempSync(join18(tmpdir2(), "atomic-subagent-output-"));
|
|
13493
|
-
copyRoot = root;
|
|
13494
|
-
process.once("exit", () => rmSync3(root, { recursive: true, force: true }));
|
|
13495
|
-
return root;
|
|
13496
|
-
}
|
|
13497
|
-
function removeCopy(entry) {
|
|
13498
|
-
if (entry?.path)
|
|
13499
|
-
rmSync3(entry.path, { force: true });
|
|
13500
|
-
}
|
|
13501
|
-
function fullOutputText(child, text) {
|
|
13502
|
-
if (child.outputMode !== "file-only" || !child.outputReference)
|
|
13503
|
-
return text;
|
|
13504
|
-
try {
|
|
13505
|
-
return readFileSync11(child.outputReference.path, "utf-8");
|
|
13506
|
-
} catch {
|
|
13507
|
-
return text;
|
|
13508
|
-
}
|
|
13509
|
-
}
|
|
13510
|
-
function writePrivateCopy(ownerId, taskId, text) {
|
|
13511
|
-
try {
|
|
13512
|
-
const path = join18(privateCopyRoot(), `${fileSafe(ownerId)}-${fileSafe(taskId)}.md`);
|
|
13513
|
-
writeFileSync8(path, text, { encoding: "utf-8", mode: 384 });
|
|
13514
|
-
return path;
|
|
13515
|
-
} catch {
|
|
13516
|
-
return;
|
|
13517
|
-
}
|
|
13518
|
-
}
|
|
13519
|
-
function retainTaskOutput(child, text, ref) {
|
|
13520
|
-
const bytes = Buffer.from(text);
|
|
13521
|
-
const path = writePrivateCopy(ref.ownerId, ref.taskId, fullOutputText(child, text));
|
|
13522
|
-
const key = retentionKey(ref.ownerId, ref.taskId);
|
|
13523
|
-
removeCopy(retained.get(key));
|
|
13524
|
-
retained.delete(key);
|
|
13525
|
-
retained.set(key, {
|
|
13526
|
-
...path ? { path } : {},
|
|
13527
|
-
...child.outputReference ? { requestedPath: child.outputReference.path } : {},
|
|
13528
|
-
...child.outputSaveError ? { saveError: child.outputSaveError } : {},
|
|
13529
|
-
head: new TextDecoder().decode(bytes.subarray(0, INLINE_TASK_OUTPUT_MAX_BYTES)),
|
|
13530
|
-
totalBytes: bytes.byteLength
|
|
13531
|
-
});
|
|
13532
|
-
while (retained.size > MAX_RETAINED_TASK_OUTPUTS) {
|
|
13533
|
-
const oldest = retained.keys().next().value;
|
|
13534
|
-
if (oldest === undefined)
|
|
13535
|
-
break;
|
|
13536
|
-
removeCopy(retained.get(oldest));
|
|
13537
|
-
retained.delete(oldest);
|
|
13538
|
-
}
|
|
13539
|
-
}
|
|
13540
|
-
function retainedTaskOutput(ownerId, taskId) {
|
|
13541
|
-
return retained.get(retentionKey(ownerId, taskId));
|
|
13542
|
-
}
|
|
13543
|
-
|
|
13544
|
-
// dist/builtin/subagents/src/runs/foreground/task-execution.ts
|
|
13545
|
-
function subagentTaskResultLabel(result) {
|
|
13546
|
-
return result.kind === "cancelled" && result.cause === "user" ? "killed (non-resumable)" : result.kind;
|
|
13547
|
-
}
|
|
13548
|
-
function subagentTaskResponseText(response) {
|
|
13549
|
-
const outcomes = response.kind === "parallel" ? response.slots.map((slot) => slot.outcome) : [response];
|
|
13550
|
-
const killed = outcomes.filter((outcome) => outcome.kind === "admitted" && outcome.observation.kind === "settled" && subagentTaskResultLabel(outcome.observation.result) === "killed (non-resumable)");
|
|
13551
|
-
return `${killed.length ? `${killed.length} killed. These children cannot be resumed. Underlying host response:
|
|
13552
|
-
` : ""}${JSON.stringify(response)}`;
|
|
13553
|
-
}
|
|
13554
|
-
function settledOutputsFromResponse(response) {
|
|
13555
|
-
const outcomes = response.kind === "parallel" ? response.slots.map((slot) => slot.outcome) : [response];
|
|
13556
|
-
return outcomes.flatMap((outcome) => outcome.kind === "admitted" && outcome.observation.kind === "settled" ? [{ taskId: outcome.observation.taskId, result: outcome.observation.result }] : []);
|
|
13557
|
-
}
|
|
13558
|
-
function settledOutputsFromRecords(records) {
|
|
13559
|
-
return records.flatMap((record) => record.execution.kind === "settled" ? [{ taskId: record.ref.taskId, result: record.execution.result }] : []);
|
|
13560
|
-
}
|
|
13561
|
-
function settledOutputSection(taskId, label, output) {
|
|
13562
|
-
const truncated = output.shown < output.total ? `, first ${output.shown} shown${output.path ? "; read the full output file for the rest" : ""}` : "";
|
|
13563
|
-
const lines = [`Output of ${taskId} (${label}, ${output.total} bytes${truncated}):`];
|
|
13564
|
-
if (output.requestedPath)
|
|
13565
|
-
lines.push(`Requested output: ${output.requestedPath}`);
|
|
13566
|
-
if (output.saveError)
|
|
13567
|
-
lines.push(`Output file error: ${output.saveError}`);
|
|
13568
|
-
if (output.path)
|
|
13569
|
-
lines.push(`Full output: ${output.path}`);
|
|
13570
|
-
lines.push(output.head);
|
|
13571
|
-
return lines.join(`
|
|
13572
|
-
`);
|
|
13573
|
-
}
|
|
13574
|
-
async function readSettledOutput(host, settled) {
|
|
13575
|
-
const output = settled.result.output;
|
|
13576
|
-
if (!output)
|
|
13577
|
-
return;
|
|
13578
|
-
const label = subagentTaskResultLabel(settled.result);
|
|
13579
|
-
const kept = retainedTaskOutput(output.ownerId, output.taskId);
|
|
13580
|
-
if (kept) {
|
|
13581
|
-
return settledOutputSection(settled.taskId, label, {
|
|
13582
|
-
...kept,
|
|
13583
|
-
shown: Math.min(kept.totalBytes, INLINE_TASK_OUTPUT_MAX_BYTES),
|
|
13584
|
-
total: kept.totalBytes
|
|
13585
|
-
});
|
|
13586
|
-
}
|
|
13587
|
-
const unavailable = (reason) => `Output of ${settled.taskId} (${label}) is unavailable: ${reason}`;
|
|
13588
|
-
const lease = host.resolveTask(settled.taskId);
|
|
13589
|
-
if (!lease.ok)
|
|
13590
|
-
return unavailable(lease.error.message);
|
|
13591
|
-
try {
|
|
13592
|
-
const page = await host.ownerBinding.supervisor.readTaskOutput(lease.value, {
|
|
13593
|
-
start: "0",
|
|
13594
|
-
maximumBytes: INLINE_TASK_OUTPUT_MAX_BYTES
|
|
13595
|
-
});
|
|
13596
|
-
if (!page.ok)
|
|
13597
|
-
return unavailable(page.error.message);
|
|
13598
|
-
const decoder = new TextDecoder;
|
|
13599
|
-
const head = page.value.chunks.map((chunk) => decoder.decode(chunk.bytes, { stream: true })).join("") + decoder.decode();
|
|
13600
|
-
const shown = page.value.chunks.reduce((sum, chunk) => sum + chunk.bytes.byteLength, 0);
|
|
13601
|
-
return settledOutputSection(settled.taskId, label, { head, shown, total: Number(output.byteCount) });
|
|
13602
|
-
} catch (error) {
|
|
13603
|
-
return unavailable(error instanceof Error ? error.message : String(error));
|
|
13604
|
-
}
|
|
13605
|
-
}
|
|
13606
|
-
async function settledTaskOutputText(host, settled) {
|
|
13607
|
-
if (!host || settled.length === 0)
|
|
13608
|
-
return "";
|
|
13609
|
-
const sections = await Promise.all(settled.map((entry) => readSettledOutput(host, entry)));
|
|
13610
|
-
const present = sections.filter((section) => section !== undefined);
|
|
13611
|
-
return present.length ? `
|
|
13612
|
-
|
|
13613
|
-
${present.join(`
|
|
13614
|
-
|
|
13615
|
-
`)}` : "";
|
|
13750
|
+
}
|
|
13751
|
+
const patchesDir = path18.dirname(changed[0].patchPath);
|
|
13752
|
+
lines.push(`Full patches: ${patchesDir}`);
|
|
13753
|
+
return lines.join(`
|
|
13754
|
+
`).trimEnd();
|
|
13616
13755
|
}
|
|
13617
|
-
|
|
13756
|
+
|
|
13757
|
+
// dist/builtin/subagents/src/runs/foreground/detached-cleanup-barrier.ts
|
|
13758
|
+
function createDetachedCleanupBarrier(onReady) {
|
|
13759
|
+
const recovered = new Set;
|
|
13760
|
+
let expected;
|
|
13761
|
+
let cleaned = false;
|
|
13762
|
+
const finishIfReady = () => {
|
|
13763
|
+
if (cleaned || !expected || ![...expected].every((index) => recovered.has(index)))
|
|
13764
|
+
return;
|
|
13765
|
+
cleaned = true;
|
|
13766
|
+
onReady();
|
|
13767
|
+
};
|
|
13618
13768
|
return {
|
|
13619
|
-
|
|
13620
|
-
|
|
13621
|
-
|
|
13622
|
-
results: [],
|
|
13623
|
-
taskResponse: response,
|
|
13624
|
-
taskRecords: taskResponseRecords(response, host)
|
|
13769
|
+
recover(index) {
|
|
13770
|
+
recovered.add(index);
|
|
13771
|
+
finishIfReady();
|
|
13625
13772
|
},
|
|
13626
|
-
|
|
13773
|
+
defer(indices) {
|
|
13774
|
+
if (indices.length === 0)
|
|
13775
|
+
return false;
|
|
13776
|
+
expected = new Set(indices);
|
|
13777
|
+
finishIfReady();
|
|
13778
|
+
return true;
|
|
13779
|
+
}
|
|
13627
13780
|
};
|
|
13628
13781
|
}
|
|
13629
|
-
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
13782
|
+
|
|
13783
|
+
// dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts
|
|
13784
|
+
import { join as join19 } from "node:path";
|
|
13785
|
+
|
|
13786
|
+
// dist/builtin/subagents/src/runs/foreground/subagent-executor-worktree.ts
|
|
13787
|
+
import * as path19 from "node:path";
|
|
13788
|
+
function buildParallelModeError(message) {
|
|
13634
13789
|
return {
|
|
13635
|
-
|
|
13636
|
-
|
|
13790
|
+
content: [{ type: "text", text: message }],
|
|
13791
|
+
isError: true,
|
|
13792
|
+
details: { mode: "parallel", results: [] }
|
|
13637
13793
|
};
|
|
13638
13794
|
}
|
|
13639
|
-
function
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
const watched = host?.watchOwnerTasks();
|
|
13643
|
-
if (!watched?.ok)
|
|
13644
|
-
return [];
|
|
13795
|
+
function createParallelWorktreeSetup(enabled, cwd, runId, tasks, setupHook, setupHookTimeoutMs) {
|
|
13796
|
+
if (!enabled)
|
|
13797
|
+
return {};
|
|
13645
13798
|
try {
|
|
13646
|
-
return
|
|
13647
|
-
|
|
13648
|
-
|
|
13799
|
+
return {
|
|
13800
|
+
setup: createWorktrees(cwd, runId, tasks.length, {
|
|
13801
|
+
agents: tasks.map((task) => task.agent),
|
|
13802
|
+
setupHook: setupHook ? { hookPath: setupHook, timeoutMs: setupHookTimeoutMs } : undefined
|
|
13803
|
+
})
|
|
13804
|
+
};
|
|
13805
|
+
} catch (error) {
|
|
13806
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13807
|
+
return { errorResult: buildParallelModeError(message) };
|
|
13649
13808
|
}
|
|
13650
13809
|
}
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
onExecution: (execution) => {
|
|
13688
|
-
executionBound = true;
|
|
13689
|
-
execution.cleanup.then(cleaned.resolve, (error) => cleaned.resolve({
|
|
13690
|
-
kind: "failed",
|
|
13691
|
-
resources: [{ resource: "agent-session", code: "CleanupFailed", message: String(error) }]
|
|
13692
|
-
}));
|
|
13693
|
-
},
|
|
13694
|
-
yieldTaskWait: () => {
|
|
13695
|
-
parentObserving = false;
|
|
13696
|
-
if (yieldWait)
|
|
13697
|
-
yieldWait("intercom-coordination");
|
|
13698
|
-
else
|
|
13699
|
-
pendingYield = true;
|
|
13700
|
-
},
|
|
13701
|
-
isParentObserving: () => parentObserving
|
|
13702
|
-
}
|
|
13703
|
-
});
|
|
13704
|
-
if (child.model !== undefined || child.thinking !== undefined)
|
|
13705
|
-
context.reportActivity({
|
|
13706
|
-
reportId: "terminal-model",
|
|
13707
|
-
change: { kind: "model", model: child.model, thinking: child.thinking }
|
|
13708
|
-
});
|
|
13709
|
-
input.onTerminal?.(child);
|
|
13710
|
-
const text = input.outputText?.(child) ?? getSingleResultOutput(child);
|
|
13711
|
-
retainTaskOutput(child, text, context.ref);
|
|
13712
|
-
const bytes = Buffer.from(text);
|
|
13713
|
-
context.reportActivity({
|
|
13714
|
-
reportId: "terminal-output",
|
|
13715
|
-
change: { kind: "output", offset: "0", bytesBase64: bytes.toString("base64") }
|
|
13716
|
-
});
|
|
13717
|
-
const output = {
|
|
13718
|
-
ownerId: context.ref.ownerId,
|
|
13719
|
-
taskId: context.ref.taskId,
|
|
13720
|
-
artifactId: `output:${context.ref.taskId}`,
|
|
13721
|
-
byteCount: String(bytes.length),
|
|
13722
|
-
omittedRanges: []
|
|
13723
|
-
};
|
|
13724
|
-
if (child.status === "killed")
|
|
13725
|
-
return { kind: "cancelled", cause: "user", output };
|
|
13726
|
-
if (child.interrupted)
|
|
13727
|
-
return {
|
|
13728
|
-
kind: "cancelled",
|
|
13729
|
-
cause: input.options.interruptSignal?.aborted ? "parent-handoff" : "owner-close",
|
|
13730
|
-
output
|
|
13731
|
-
};
|
|
13732
|
-
return child.status === "ok" ? { kind: "completed", output } : {
|
|
13733
|
-
kind: "failed",
|
|
13734
|
-
code: "AgentFailed",
|
|
13735
|
-
message: child.error ?? child.envelope ?? "Agent failed",
|
|
13736
|
-
output
|
|
13737
|
-
};
|
|
13738
|
-
} finally {
|
|
13739
|
-
if (!executionBound)
|
|
13740
|
-
cleaned.resolve({ kind: "reaped" });
|
|
13741
|
-
}
|
|
13742
|
-
});
|
|
13743
|
-
return { result, cleanup: cleaned.promise };
|
|
13744
|
-
}, input.schedule);
|
|
13745
|
-
if (!started.ok)
|
|
13746
|
-
return { kind: "unstarted", reason: { kind: "rejected", error: started.error } };
|
|
13747
|
-
const yieldForIntercom = () => {
|
|
13748
|
-
parentObserving = false;
|
|
13749
|
-
if (yieldWait)
|
|
13750
|
-
yieldWait("intercom-coordination");
|
|
13751
|
-
else
|
|
13752
|
-
pendingYield = true;
|
|
13753
|
-
};
|
|
13754
|
-
input.options.intercomDetachSignal?.addEventListener("abort", yieldForIntercom, { once: true });
|
|
13755
|
-
if (input.options.intercomDetachSignal?.aborted)
|
|
13756
|
-
yieldForIntercom();
|
|
13757
|
-
const observation = input.host.observeAgentLaunch(started.value.taskId, input.wait, (yieldRegistered) => {
|
|
13758
|
-
yieldWait = yieldRegistered;
|
|
13759
|
-
if (pendingYield)
|
|
13760
|
-
yieldRegistered("intercom-coordination");
|
|
13761
|
-
registered.resolve();
|
|
13762
|
-
});
|
|
13763
|
-
registered.resolve();
|
|
13764
|
-
const observed = await observation.finally(() => {
|
|
13765
|
-
parentObserving = false;
|
|
13766
|
-
input.options.intercomDetachSignal?.removeEventListener("abort", yieldForIntercom);
|
|
13767
|
-
});
|
|
13768
|
-
if (!observed.ok)
|
|
13769
|
-
throw new Error(`${observed.error.code}: ${observed.error.message}`);
|
|
13770
|
-
return { kind: "admitted", observation: observed.value };
|
|
13810
|
+
function buildParallelWorktreeTaskCwdError(tasks, sharedCwd) {
|
|
13811
|
+
const conflict = findWorktreeTaskCwdConflict(tasks, sharedCwd);
|
|
13812
|
+
if (!conflict)
|
|
13813
|
+
return;
|
|
13814
|
+
return formatWorktreeTaskCwdConflict(conflict, sharedCwd);
|
|
13815
|
+
}
|
|
13816
|
+
function resolveParallelTaskCwd(task, paramsCwd, worktreeSetup, index) {
|
|
13817
|
+
if (worktreeSetup)
|
|
13818
|
+
return worktreeSetup.worktrees[index].agentCwd;
|
|
13819
|
+
return resolveChildCwd(paramsCwd, task.cwd);
|
|
13820
|
+
}
|
|
13821
|
+
function buildParallelWorktreeSuffix(worktreeSetup, artifactsDir, tasks) {
|
|
13822
|
+
if (!worktreeSetup)
|
|
13823
|
+
return "";
|
|
13824
|
+
const diffsDir = path19.join(artifactsDir, "worktree-diffs");
|
|
13825
|
+
const diffs = diffWorktrees(worktreeSetup, tasks.map((task) => task.agent), diffsDir);
|
|
13826
|
+
return formatWorktreeDiffSummary(diffs);
|
|
13827
|
+
}
|
|
13828
|
+
function findDuplicateParallelOutputPath(input) {
|
|
13829
|
+
const seen = new Map;
|
|
13830
|
+
for (let index = 0;index < input.tasks.length; index++) {
|
|
13831
|
+
const behavior = input.behaviors[index];
|
|
13832
|
+
if (!behavior?.output)
|
|
13833
|
+
continue;
|
|
13834
|
+
const task = input.tasks[index];
|
|
13835
|
+
const taskCwd = resolveParallelTaskCwd(task, input.paramsCwd, input.worktreeSetup, index);
|
|
13836
|
+
const outputPath = resolveSingleOutputPath(behavior.output, input.ctxCwd, taskCwd);
|
|
13837
|
+
if (!outputPath)
|
|
13838
|
+
continue;
|
|
13839
|
+
const previous = seen.get(outputPath);
|
|
13840
|
+
if (previous) {
|
|
13841
|
+
return `Parallel tasks ${previous.index + 1} (${previous.agent}) and ${index + 1} (${task.agent}) resolve output to the same path: ${outputPath}. Use distinct output paths.`;
|
|
13842
|
+
}
|
|
13843
|
+
seen.set(outputPath, { index, agent: task.agent });
|
|
13844
|
+
}
|
|
13845
|
+
return;
|
|
13771
13846
|
}
|
|
13772
13847
|
|
|
13773
13848
|
// dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts
|
|
@@ -13822,23 +13897,7 @@ function runUnboundParallelTask(options, agent, task, schedule, run) {
|
|
|
13822
13897
|
async function runForegroundParallelTasks(input) {
|
|
13823
13898
|
const intercomDetachController = new AbortController;
|
|
13824
13899
|
const host = input.ctx.getAgentTaskHost?.();
|
|
13825
|
-
|
|
13826
|
-
const queued = [];
|
|
13827
|
-
const pump = () => {
|
|
13828
|
-
while (active < input.concurrencyLimit && queued.length > 0) {
|
|
13829
|
-
const dispatch = queued.shift();
|
|
13830
|
-
active++;
|
|
13831
|
-
const release = () => {
|
|
13832
|
-
active--;
|
|
13833
|
-
pump();
|
|
13834
|
-
};
|
|
13835
|
-
dispatch().then(release, release);
|
|
13836
|
-
}
|
|
13837
|
-
};
|
|
13838
|
-
const schedule = (dispatch) => {
|
|
13839
|
-
queued.push(dispatch);
|
|
13840
|
-
pump();
|
|
13841
|
-
};
|
|
13900
|
+
const schedule = input.schedule ?? createExecutionScheduler(input.concurrencyLimit);
|
|
13842
13901
|
return mapConcurrent(input.tasks, input.tasks.length, async (task, index) => {
|
|
13843
13902
|
const behavior = input.behaviors[index];
|
|
13844
13903
|
const effectiveSkills = behavior?.skills;
|
|
@@ -14578,6 +14637,7 @@ async function runParallelPath(data, deps) {
|
|
|
14578
14637
|
}
|
|
14579
14638
|
const results = await runForegroundParallelTasks({
|
|
14580
14639
|
wait: params.wait,
|
|
14640
|
+
schedule: params[BURST_EXECUTION_SCHEDULE],
|
|
14581
14641
|
onTaskTerminal: (index) => detachedCleanup.recover(index),
|
|
14582
14642
|
onDetachedExit: (index, result) => {
|
|
14583
14643
|
try {
|
|
@@ -14646,20 +14706,7 @@ async function runParallelPath(data, deps) {
|
|
|
14646
14706
|
}))
|
|
14647
14707
|
};
|
|
14648
14708
|
worktreeCleanupDeferred = detachedCleanup.defer(response.slots.flatMap(({ ordinal, outcome }) => outcome.kind === "admitted" && outcome.observation.kind === "yielded" ? [ordinal] : []));
|
|
14649
|
-
return
|
|
14650
|
-
content: [
|
|
14651
|
-
{
|
|
14652
|
-
type: "text",
|
|
14653
|
-
text: `${subagentTaskResponseText(response)}${await settledTaskOutputText(ctx.getAgentTaskHost(), settledOutputsFromResponse(response))}`
|
|
14654
|
-
}
|
|
14655
|
-
],
|
|
14656
|
-
details: {
|
|
14657
|
-
mode: "parallel",
|
|
14658
|
-
results: [],
|
|
14659
|
-
taskResponse: response,
|
|
14660
|
-
taskRecords: taskResponseRecords(response, ctx.getAgentTaskHost())
|
|
14661
|
-
}
|
|
14662
|
-
};
|
|
14709
|
+
return parallelTaskToolResultWithOutput(response, ctx.getAgentTaskHost());
|
|
14663
14710
|
}
|
|
14664
14711
|
for (let i = 0;i < results.length; i++) {
|
|
14665
14712
|
const run = results[i];
|
|
@@ -15557,6 +15604,7 @@ async function runSinglePath(data, deps) {
|
|
|
15557
15604
|
intentTask: handoffTaskContext,
|
|
15558
15605
|
options: runOptions,
|
|
15559
15606
|
wait: params.wait,
|
|
15607
|
+
schedule: params[BURST_EXECUTION_SCHEDULE],
|
|
15560
15608
|
runtime: deps.runtime,
|
|
15561
15609
|
onTerminal: (child) => {
|
|
15562
15610
|
settledChild = child;
|
|
@@ -15572,8 +15620,10 @@ async function runSinglePath(data, deps) {
|
|
|
15572
15620
|
if (!parentAsk || !settledChild?.interrupted)
|
|
15573
15621
|
return await taskToolResultWithOutput(response, ctx.getAgentTaskHost());
|
|
15574
15622
|
r = settledChild;
|
|
15575
|
-
} else
|
|
15576
|
-
|
|
15623
|
+
} else {
|
|
15624
|
+
const schedule = params[BURST_EXECUTION_SCHEDULE];
|
|
15625
|
+
r = schedule ? await runUnboundParallelTask(runOptions, params.agent, task, schedule, (options) => deps.runtime.runSync(ctx.cwd, agents, params.agent, task, options)) : await deps.runtime.runSync(ctx.cwd, agents, params.agent, task, runOptions);
|
|
15626
|
+
}
|
|
15577
15627
|
} catch (error) {
|
|
15578
15628
|
cleanupTransientProgress(progressDir, artifactConfig.enabled);
|
|
15579
15629
|
throw error;
|
|
@@ -15911,6 +15961,7 @@ function createSubagentExecutor(rawDeps) {
|
|
|
15911
15961
|
};
|
|
15912
15962
|
const executeWithBurstCollection = createExecutionBurstDispatcher({
|
|
15913
15963
|
execute,
|
|
15964
|
+
concurrencyLimit: deps.config.parallel?.concurrency,
|
|
15914
15965
|
isActive: () => deps.state.subagentInProgress === true,
|
|
15915
15966
|
setActive: (active) => {
|
|
15916
15967
|
deps.state.subagentInProgress = active;
|