@bastani/atomic 0.9.15 → 0.9.16-alpha.2
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 +19 -0
- package/dist/builtin/intercom/CHANGELOG.md +10 -0
- package/dist/builtin/intercom/README.md +8 -8
- package/dist/builtin/intercom/contact-supervisor-tool.ts +68 -32
- package/dist/builtin/intercom/index-heavy.ts +1 -0
- package/dist/builtin/intercom/index.ts +21 -15
- package/dist/builtin/intercom/intercom-tool.ts +66 -10
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/parent-ask-handoff.ts +72 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +26 -0
- package/dist/builtin/subagents/README.md +37 -114
- package/dist/builtin/subagents/agents/worker.md +2 -2
- package/dist/builtin/subagents/package.json +1 -5
- package/dist/builtin/subagents/skills/subagent/SKILL.md +26 -103
- package/dist/builtin/subagents/src/extension/index.ts +5 -30
- package/dist/builtin/subagents/src/extension/notification-content.ts +1 -1
- package/dist/builtin/subagents/src/extension/schemas.ts +2 -14
- package/dist/builtin/subagents/src/extension/tool-description.ts +1 -4
- package/dist/builtin/subagents/src/extension/tool-rendering.ts +53 -0
- package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +1 -54
- package/dist/builtin/subagents/src/intercom/result-intercom.ts +4 -4
- package/dist/builtin/subagents/src/runs/foreground/execution-parent-ask-handoff.ts +78 -0
- package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +7 -5
- package/dist/builtin/subagents/src/runs/foreground/notify.ts +5 -6
- package/dist/builtin/subagents/src/runs/foreground/parent-ask-output.ts +48 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-burst-display.ts +46 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-burst.ts +403 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +48 -9
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts +3 -1
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-live-update.ts +11 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +164 -93
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +36 -29
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parent-ask-projection.ts +11 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +42 -17
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +3 -121
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +7 -2
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +30 -257
- package/dist/builtin/subagents/src/runs/inprocess/control-status.ts +0 -34
- package/dist/builtin/subagents/src/runs/inprocess/index.ts +0 -12
- package/dist/builtin/subagents/src/runs/inprocess/prompt-behavior.ts +1 -1
- package/dist/builtin/subagents/src/runs/inprocess/runner.ts +2 -141
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +8 -0
- package/dist/builtin/subagents/src/shared/status-format.ts +3 -3
- package/dist/builtin/subagents/src/shared/types-config.ts +41 -0
- package/dist/builtin/subagents/src/shared/types-foreground-state.ts +7 -15
- package/dist/builtin/subagents/src/shared/types-results.ts +3 -1
- package/dist/builtin/subagents/src/shared/types-runtime.ts +1 -11
- package/dist/builtin/subagents/src/slash/slash-commands.ts +4 -468
- package/dist/builtin/subagents/src/tui/render-progress.ts +2 -2
- package/dist/builtin/subagents/src/tui/render-result-compact.ts +2 -2
- package/dist/builtin/subagents/src/tui/render-result.ts +38 -14
- package/dist/builtin/subagents/src/tui/render-status-progress.ts +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +16 -0
- package/dist/builtin/workflows/README.md +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/bro/LICENSE.txt +21 -0
- package/dist/builtin/workflows/skills/bro/SKILL.md +14 -0
- package/dist/builtin/workflows/skills/how/LICENSE.txt +21 -0
- package/dist/builtin/workflows/skills/how/SKILL.md +162 -0
- package/dist/builtin/workflows/skills/how/references/critic-prompt.md +59 -0
- package/dist/builtin/workflows/skills/how/references/critique-rubric.md +58 -0
- package/dist/builtin/workflows/skills/how/references/explainer-prompt.md +55 -0
- package/dist/builtin/workflows/skills/how/references/explorer-prompt.md +52 -0
- package/dist/builtin/workflows/skills/teach/LICENSE.txt +21 -0
- package/dist/builtin/workflows/skills/teach/SKILL.md +28 -0
- package/dist/builtin/workflows/skills/unslop/LICENSE.txt +21 -0
- package/dist/builtin/workflows/skills/unslop/SKILL.md +87 -0
- package/dist/builtin/workflows/skills/why/LICENSE.txt +21 -0
- package/dist/builtin/workflows/skills/why/SKILL.md +267 -0
- package/dist/builtin/workflows/skills/why/references/epistemics.md +144 -0
- package/dist/builtin/workflows/skills/why/references/investigator-prompt.md +103 -0
- package/dist/builtin/workflows/skills/why/references/source-playbook.md +17 -0
- package/dist/builtin/workflows/skills/why/references/sources/code-archaeology.md +88 -0
- package/dist/builtin/workflows/skills/why/references/sources/databricks.md +70 -0
- package/dist/builtin/workflows/skills/why/references/sources/datadog.md +99 -0
- package/dist/builtin/workflows/skills/why/references/sources/incident-postmortem.md +15 -0
- package/dist/builtin/workflows/skills/why/references/sources/linear.md +48 -0
- package/dist/builtin/workflows/skills/why/references/sources/notion.md +55 -0
- package/dist/builtin/workflows/skills/why/references/sources/sentry.md +100 -0
- package/dist/builtin/workflows/skills/why/references/sources/slack.md +54 -0
- package/dist/builtin/workflows/skills/why/references/synthesizer-prompt.md +135 -0
- package/dist/builtin/workflows/src/durable/dbos-embedded-postgres-root.ts +548 -39
- package/dist/builtin/workflows/src/durable/dbos-embedded-postgres.ts +529 -65
- package/dist/builtin/workflows/src/durable/dbos-lifecycle.ts +30 -8
- package/dist/builtin/workflows/src/durable/dbos-local-postgres.ts +36 -3
- package/dist/builtin/workflows/src/durable/local-command.ts +68 -10
- package/dist/builtin/workflows/src/extension/companions.ts +1 -1
- package/dist/builtin/workflows/src/extension/dispatcher.ts +7 -1
- package/dist/builtin/workflows/src/extension/extension-factory.ts +2 -2
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1094 -298
- package/dist/builtin/workflows/src/extension/public-types.ts +2 -2
- package/dist/builtin/workflows/src/extension/render-result.ts +16 -2
- package/dist/builtin/workflows/src/extension/runtime.ts +8 -1
- package/dist/builtin/workflows/src/extension/workflow-request-abort.ts +15 -0
- package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +4 -3
- package/dist/builtin/workflows/src/extension/workflow-tool-registration.ts +107 -13
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +22 -12
- package/dist/builtin/workflows/src/tui/widget.ts +25 -6
- package/dist/core/agent-session-auto-compaction.js +10 -10
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +11 -13
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +1 -1
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-models.d.ts.map +1 -1
- package/dist/core/agent-session-models.js +5 -7
- package/dist/core/agent-session-models.js.map +1 -1
- package/dist/core/agent-session-prompt.js +4 -4
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-retry.d.ts +4 -4
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-retry.js +8 -34
- package/dist/core/agent-session-retry.js.map +1 -1
- package/dist/core/agent-session-tool-hooks.js +4 -4
- package/dist/core/agent-session-tool-hooks.js.map +1 -1
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.js +3 -10
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js +19 -3
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +0 -3
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +0 -12
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/modes/interactive-engine/remote-command-catalog.d.ts +1 -1
- package/dist/modes/interactive-engine/remote-command-catalog.js +1 -1
- package/dist/modes/interactive-engine/remote-command-catalog.js.map +1 -1
- package/docs/intercom.md +29 -27
- package/docs/settings.md +2 -2
- package/docs/subagents.md +18 -15
- package/docs/usage.md +0 -9
- package/docs/workflows.md +27 -10
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
- package/dist/builtin/subagents/prompts/gather-context-and-clarify.md +0 -27
- package/dist/builtin/subagents/prompts/parallel-cleanup.md +0 -61
- package/dist/builtin/subagents/prompts/parallel-context-build.md +0 -43
- package/dist/builtin/subagents/prompts/parallel-handoff-plan.md +0 -47
- package/dist/builtin/subagents/prompts/parallel-research.md +0 -34
- package/dist/builtin/subagents/prompts/parallel-review.md +0 -47
- package/dist/builtin/subagents/prompts/review-loop.md +0 -39
- package/dist/builtin/subagents/src/extension/doctor.ts +0 -188
- package/dist/builtin/subagents/src/runs/inprocess/attempt-handles.ts +0 -104
- /package/dist/builtin/subagents/src/runs/foreground/{subagent-executor-resume.ts → subagent-executor-cwd.ts} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@bastani/atomic";
|
|
2
2
|
import type { AgentConfig } from "../../agents/agents.js";
|
|
3
3
|
import { INTERCOM_BRIDGE_MARKER } from "../../intercom/intercom-bridge.js";
|
|
4
|
+
import { requestSupervisorAuthorization } from "../../intercom/supervisor-authorization.js";
|
|
4
5
|
import type { ModelInfo } from "../../shared/model-info.js";
|
|
5
6
|
import type { CandidateModelResolver } from "../../shared/model-resolution.js";
|
|
6
7
|
import { buildTaskInstructions, type ResolvedStepBehavior } from "../../shared/settings.js";
|
|
@@ -8,8 +9,10 @@ import type {
|
|
|
8
9
|
AgentProgress,
|
|
9
10
|
ArtifactConfig,
|
|
10
11
|
ControlEvent,
|
|
12
|
+
ForegroundParentAskHandoff,
|
|
11
13
|
IntercomEventBus,
|
|
12
14
|
MaxOutputConfig,
|
|
15
|
+
RunSyncOptions,
|
|
13
16
|
SingleResult,
|
|
14
17
|
SubagentState,
|
|
15
18
|
SubagentToolResult,
|
|
@@ -20,6 +23,7 @@ import { inheritedIntercomGroup, resolveChildIntercomGroup } from "../shared/int
|
|
|
20
23
|
import { currentModelFullId } from "../shared/model-fallback.js";
|
|
21
24
|
import { injectSingleOutputInstruction, resolveSingleOutputPath } from "../shared/single-output.js";
|
|
22
25
|
import type { WorktreeSetup } from "../shared/worktree.js";
|
|
26
|
+
import { markLiveResultIndices } from "./subagent-executor-live-update.js";
|
|
23
27
|
import type { SubagentExecutorRuntimeDeps, TaskParam } from "./subagent-executor-types.js";
|
|
24
28
|
import { resolveParallelTaskCwd } from "./subagent-executor-worktree.js";
|
|
25
29
|
|
|
@@ -27,6 +31,7 @@ interface ForegroundParallelRunInput {
|
|
|
27
31
|
tasks: TaskParam[];
|
|
28
32
|
taskTexts: string[];
|
|
29
33
|
agents: AgentConfig[];
|
|
34
|
+
agentConfigs?: AgentConfig[];
|
|
30
35
|
ctx: ExtensionContext;
|
|
31
36
|
intercomEvents: IntercomEventBus;
|
|
32
37
|
signal: AbortSignal;
|
|
@@ -57,23 +62,39 @@ interface ForegroundParallelRunInput {
|
|
|
57
62
|
liveResults: (SingleResult | undefined)[];
|
|
58
63
|
liveProgress: (AgentProgress | undefined)[];
|
|
59
64
|
onUpdate?: (r: SubagentToolResult) => void;
|
|
65
|
+
onParentAskHandoff?: (handoff: ForegroundParentAskHandoff) => void;
|
|
60
66
|
onDetachedExit?: (index: number, result: SingleResult) => void;
|
|
67
|
+
onExecution?: (index: number, runtimeCwd: string, options: RunSyncOptions) => void;
|
|
61
68
|
worktreeSetup?: WorktreeSetup;
|
|
62
69
|
runtime: Pick<SubagentExecutorRuntimeDeps, "runSync">;
|
|
63
70
|
}
|
|
64
71
|
|
|
72
|
+
function skippedParallelResult(task: TaskParam, taskText: string, error: string): SingleResult {
|
|
73
|
+
return {
|
|
74
|
+
agent: task.agent,
|
|
75
|
+
task: taskText,
|
|
76
|
+
status: "skipped",
|
|
77
|
+
messages: [],
|
|
78
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 },
|
|
79
|
+
error,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
65
83
|
export async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Promise<SingleResult[]> {
|
|
66
84
|
const intercomDetachController = new AbortController();
|
|
85
|
+
const parentAskController = new AbortController();
|
|
86
|
+
const startedIndices = new Set<number>();
|
|
87
|
+
const activeIndices = new Set<number>();
|
|
67
88
|
return mapConcurrent(input.tasks, input.concurrencyLimit, async (task, index) => {
|
|
89
|
+
if (parentAskController.signal.aborted) {
|
|
90
|
+
return skippedParallelResult(task, input.taskTexts[index] ?? task.task, "Skipped after parent ask handoff");
|
|
91
|
+
}
|
|
68
92
|
if (intercomDetachController.signal.aborted) {
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 },
|
|
75
|
-
error: "Skipped after foreground group detached for intercom coordination",
|
|
76
|
-
};
|
|
93
|
+
return skippedParallelResult(
|
|
94
|
+
task,
|
|
95
|
+
input.taskTexts[index] ?? task.task,
|
|
96
|
+
"Skipped after foreground group detached for intercom coordination",
|
|
97
|
+
);
|
|
77
98
|
}
|
|
78
99
|
const behavior = input.behaviors[index];
|
|
79
100
|
const effectiveSkills = behavior?.skills;
|
|
@@ -93,7 +114,24 @@ export async function runForegroundParallelTasks(input: ForegroundParallelRunInp
|
|
|
93
114
|
`${readInstructions.prefix}${input.taskTexts[index]!}${progressInstructions.suffix}`,
|
|
94
115
|
outputPath,
|
|
95
116
|
);
|
|
117
|
+
const childIntercomTarget = input.childIntercomTarget?.(task.agent, index);
|
|
118
|
+
const supervisorAuthorization = await requestSupervisorAuthorization(input.intercomEvents, childIntercomTarget);
|
|
119
|
+
if (parentAskController.signal.aborted) {
|
|
120
|
+
return skippedParallelResult(task, input.taskTexts[index] ?? task.task, "Skipped after parent ask handoff");
|
|
121
|
+
}
|
|
122
|
+
if (intercomDetachController.signal.aborted) {
|
|
123
|
+
return skippedParallelResult(
|
|
124
|
+
task,
|
|
125
|
+
input.taskTexts[index] ?? task.task,
|
|
126
|
+
"Skipped after foreground group detached for intercom coordination",
|
|
127
|
+
);
|
|
128
|
+
}
|
|
96
129
|
const interruptController = new AbortController();
|
|
130
|
+
const interruptForParentAsk = () => interruptController.abort();
|
|
131
|
+
parentAskController.signal.addEventListener("abort", interruptForParentAsk, { once: true });
|
|
132
|
+
if (parentAskController.signal.aborted) interruptController.abort();
|
|
133
|
+
startedIndices.add(index);
|
|
134
|
+
activeIndices.add(index);
|
|
97
135
|
if (input.foregroundControl) {
|
|
98
136
|
input.foregroundControl.currentAgent = task.agent;
|
|
99
137
|
input.foregroundControl.currentIndex = index;
|
|
@@ -107,91 +145,124 @@ export async function runForegroundParallelTasks(input: ForegroundParallelRunInp
|
|
|
107
145
|
return true;
|
|
108
146
|
};
|
|
109
147
|
}
|
|
110
|
-
const agentConfig = input.agents.find((agent) => agent.name === task.agent);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
input.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
totalSteps: input.tasks.length,
|
|
185
|
-
},
|
|
186
|
-
});
|
|
148
|
+
const agentConfig = input.agentConfigs?.[index] ?? input.agents.find((agent) => agent.name === task.agent);
|
|
149
|
+
const taskAgents = input.agentConfigs && agentConfig ? [agentConfig] : input.agents;
|
|
150
|
+
const runOptions: RunSyncOptions = {
|
|
151
|
+
cwd: taskCwd,
|
|
152
|
+
signal: input.signal,
|
|
153
|
+
interruptSignal: interruptController.signal,
|
|
154
|
+
allowIntercomDetach: agentConfig?.systemPrompt?.includes(INTERCOM_BRIDGE_MARKER) === true,
|
|
155
|
+
intercomEvents: input.intercomEvents,
|
|
156
|
+
runId: input.runId,
|
|
157
|
+
index,
|
|
158
|
+
sessionDir: input.sessionDirForIndex(index),
|
|
159
|
+
sessionFile: input.sessionFileForIndex(index),
|
|
160
|
+
share: input.shareEnabled,
|
|
161
|
+
artifactsDir: input.artifactConfig.enabled ? input.artifactsDir : undefined,
|
|
162
|
+
artifactConfig: input.artifactConfig,
|
|
163
|
+
maxOutput: input.maxOutput,
|
|
164
|
+
outputPath,
|
|
165
|
+
outputMode: behavior?.outputMode,
|
|
166
|
+
parentDepth: input.parentDepth,
|
|
167
|
+
workflowStageSubagentGuard: input.workflowStageSubagentGuard,
|
|
168
|
+
workflowSessionMetadata: workflowSessionMetadataFromContext(input.ctx),
|
|
169
|
+
controlConfig: input.controlConfig,
|
|
170
|
+
onControlEvent: input.onControlEvent,
|
|
171
|
+
intercomSessionName: childIntercomTarget,
|
|
172
|
+
supervisorAuthorization,
|
|
173
|
+
orchestratorIntercomTarget: input.orchestratorIntercomTarget,
|
|
174
|
+
intercomGroup: resolveChildIntercomGroup(
|
|
175
|
+
task.group ?? input.setIntercomGroup,
|
|
176
|
+
inheritedIntercomGroup(input.ctx),
|
|
177
|
+
input.sharedAutoIntercomGroup,
|
|
178
|
+
),
|
|
179
|
+
onDetachedExit: (result) => input.onDetachedExit?.(index, result),
|
|
180
|
+
intercomDetachSignal: intercomDetachController.signal,
|
|
181
|
+
onIntercomDetachCommit: () => intercomDetachController.abort(),
|
|
182
|
+
onParentAskHandoff: input.onParentAskHandoff
|
|
183
|
+
? (request) => {
|
|
184
|
+
if (parentAskController.signal.aborted) return;
|
|
185
|
+
request.taskContext = input.tasks[request.index]?.task ?? "";
|
|
186
|
+
input.onParentAskHandoff?.({
|
|
187
|
+
askingChildIndex: request.index,
|
|
188
|
+
releasedChildIndices: [...activeIndices].sort((left, right) => left - right),
|
|
189
|
+
unlaunchedChildIndices: input.tasks
|
|
190
|
+
.map((_, taskIndex) => taskIndex)
|
|
191
|
+
.filter((taskIndex) => !startedIndices.has(taskIndex)),
|
|
192
|
+
request,
|
|
193
|
+
});
|
|
194
|
+
parentAskController.abort();
|
|
195
|
+
}
|
|
196
|
+
: undefined,
|
|
197
|
+
modelOverride: input.modelOverrides[index],
|
|
198
|
+
availableModels: input.availableModels,
|
|
199
|
+
knownModelProviders: input.knownModelProviders,
|
|
200
|
+
resolveCandidateModel: input.resolveCandidateModel,
|
|
201
|
+
preferredModelProvider: input.ctx.model?.provider,
|
|
202
|
+
currentModel: currentModelFullId(input.ctx.model),
|
|
203
|
+
currentThinkingLevel: input.ctx.thinkingLevel,
|
|
204
|
+
skills: effectiveSkills === false ? [] : effectiveSkills,
|
|
205
|
+
onUpdate: input.onUpdate
|
|
206
|
+
? (progressUpdate) => {
|
|
207
|
+
const stepResults = progressUpdate.details?.results || [];
|
|
208
|
+
const stepProgress = progressUpdate.details?.progress || [];
|
|
209
|
+
if (input.foregroundControl && stepProgress.length > 0) {
|
|
210
|
+
const current = stepProgress[0];
|
|
211
|
+
input.foregroundControl.currentAgent = task.agent;
|
|
212
|
+
input.foregroundControl.currentIndex = index;
|
|
213
|
+
input.foregroundControl.currentActivityState = current?.activityState;
|
|
214
|
+
input.foregroundControl.lastActivityAt = current?.lastActivityAt;
|
|
215
|
+
input.foregroundControl.currentTool = current?.currentTool;
|
|
216
|
+
input.foregroundControl.currentToolStartedAt = current?.currentToolStartedAt;
|
|
217
|
+
input.foregroundControl.currentPath = current?.currentPath;
|
|
218
|
+
input.foregroundControl.turnCount = current?.turnCount;
|
|
219
|
+
input.foregroundControl.tokens = current?.tokens;
|
|
220
|
+
input.foregroundControl.toolCount = current?.toolCount;
|
|
221
|
+
input.foregroundControl.updatedAt = Date.now();
|
|
187
222
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
223
|
+
if (stepResults.length > 0) input.liveResults[index] = stepResults[0];
|
|
224
|
+
if (stepProgress.length > 0) input.liveProgress[index] = stepProgress[0];
|
|
225
|
+
const indexedResults = input.liveResults.flatMap((result, resultIndex) =>
|
|
226
|
+
result === undefined ? [] : [{ result, index: resultIndex }],
|
|
227
|
+
);
|
|
228
|
+
const mergedResults = indexedResults.map(({ result }) => result);
|
|
229
|
+
const mergedProgress = input.liveProgress.filter(
|
|
230
|
+
(progress): progress is AgentProgress => progress !== undefined,
|
|
231
|
+
);
|
|
232
|
+
const controlEvents = progressUpdate.details?.controlEvents?.map((event) => ({ ...event, index }));
|
|
233
|
+
const artifactDir = progressUpdate.details?.artifacts?.dir;
|
|
234
|
+
const artifactFiles = mergedResults.flatMap((result) =>
|
|
235
|
+
result.artifactPaths ? [result.artifactPaths] : [],
|
|
236
|
+
);
|
|
237
|
+
const aggregateUpdate: SubagentToolResult = {
|
|
238
|
+
content: progressUpdate.content,
|
|
239
|
+
details: {
|
|
240
|
+
mode: "parallel",
|
|
241
|
+
results: mergedResults,
|
|
242
|
+
progress: mergedProgress,
|
|
243
|
+
...(controlEvents?.length ? { controlEvents } : {}),
|
|
244
|
+
totalSteps: input.tasks.length,
|
|
245
|
+
...(artifactDir && artifactFiles.length
|
|
246
|
+
? { artifacts: { dir: artifactDir, files: artifactFiles } }
|
|
247
|
+
: {}),
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
markLiveResultIndices(
|
|
251
|
+
aggregateUpdate,
|
|
252
|
+
indexedResults.map(({ index: resultIndex }) => resultIndex),
|
|
253
|
+
);
|
|
254
|
+
input.onUpdate?.(aggregateUpdate);
|
|
255
|
+
}
|
|
256
|
+
: undefined,
|
|
257
|
+
};
|
|
258
|
+
input.onExecution?.(index, input.ctx.cwd, runOptions);
|
|
259
|
+
return input.runtime.runSync(input.ctx.cwd, taskAgents, task.agent, taskText, runOptions).finally(() => {
|
|
260
|
+
activeIndices.delete(index);
|
|
261
|
+
parentAskController.signal.removeEventListener("abort", interruptForParentAsk);
|
|
262
|
+
if (input.foregroundControl?.currentIndex === index) {
|
|
263
|
+
input.foregroundControl.interrupt = undefined;
|
|
264
|
+
input.foregroundControl.updatedAt = Date.now();
|
|
265
|
+
}
|
|
266
|
+
});
|
|
196
267
|
});
|
|
197
268
|
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
type AgentProgress,
|
|
14
14
|
type ArtifactPaths,
|
|
15
|
+
type ForegroundParentAskHandoff,
|
|
15
16
|
isWorkflowStageOrchestrationContext,
|
|
16
17
|
resolveTopLevelParallelConcurrency,
|
|
17
18
|
resolveTopLevelParallelMaxTasks,
|
|
@@ -22,18 +23,18 @@ import {
|
|
|
22
23
|
import { compactForegroundDetails, getSingleResultOutput } from "../../shared/utils.js";
|
|
23
24
|
import { sharedAutoGroupForSet } from "../shared/intercom-group.js";
|
|
24
25
|
import { resolveModelCandidate } from "../shared/model-fallback.js";
|
|
25
|
-
import {
|
|
26
|
+
import { formatParallelResultContent } from "../shared/parallel-utils.js";
|
|
26
27
|
import { recordRun } from "../shared/run-history.js";
|
|
27
28
|
import { resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.js";
|
|
28
29
|
import { cleanupWorktrees, type WorktreeSetup } from "../shared/worktree.js";
|
|
29
30
|
import { createDetachedCleanupBarrier } from "./detached-cleanup-barrier.js";
|
|
31
|
+
import { formatParentAskHandoffOutput } from "./parent-ask-output.js";
|
|
30
32
|
import { runForegroundParallelTasks } from "./subagent-executor-parallel-task.js";
|
|
33
|
+
import { markParentAskHandoff } from "./subagent-executor-parent-ask-projection.js";
|
|
31
34
|
import {
|
|
32
35
|
createForegroundControlNotifier,
|
|
33
36
|
maybeBuildForegroundIntercomReceipt,
|
|
34
37
|
notifyDetachedForegroundChildExit,
|
|
35
|
-
rememberForegroundRun,
|
|
36
|
-
replaceForegroundRunChild,
|
|
37
38
|
} from "./subagent-executor-status.js";
|
|
38
39
|
import type { ExecutionContextData, ResolvedExecutorDeps, TaskParam } from "./subagent-executor-types.js";
|
|
39
40
|
import {
|
|
@@ -82,17 +83,19 @@ export async function runParallelPath(
|
|
|
82
83
|
details: { mode: "parallel" as const, results: [] },
|
|
83
84
|
};
|
|
84
85
|
|
|
85
|
-
const agentConfigs: AgentConfig[] = [];
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
const agentConfigs: AgentConfig[] = data.parallelAgentConfigs ? [...data.parallelAgentConfigs] : [];
|
|
87
|
+
if (!data.parallelAgentConfigs) {
|
|
88
|
+
for (const task of tasks) {
|
|
89
|
+
const config = agents.find((agent) => agent.name === task.agent);
|
|
90
|
+
if (!config) {
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text", text: `Unknown agent: ${task.agent}` }],
|
|
93
|
+
isError: true,
|
|
94
|
+
details: { mode: "parallel" as const, results: [] },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
agentConfigs.push(config);
|
|
94
98
|
}
|
|
95
|
-
agentConfigs.push(config);
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
const workflowStageSubagentGuard = isWorkflowStageOrchestrationContext(ctx);
|
|
@@ -143,6 +146,7 @@ export async function runParallelPath(
|
|
|
143
146
|
cleanupWorktrees(worktreeSetup);
|
|
144
147
|
});
|
|
145
148
|
if (errorResult) return errorResult;
|
|
149
|
+
let parentAsk: ForegroundParentAskHandoff | undefined;
|
|
146
150
|
|
|
147
151
|
try {
|
|
148
152
|
const duplicateOutputError = findDuplicateParallelOutputPath({
|
|
@@ -176,7 +180,6 @@ export async function runParallelPath(
|
|
|
176
180
|
const results = await runForegroundParallelTasks({
|
|
177
181
|
onDetachedExit: (index, result) => {
|
|
178
182
|
try {
|
|
179
|
-
replaceForegroundRunChild(deps.state, runId, index, result);
|
|
180
183
|
notifyDetachedForegroundChildExit({
|
|
181
184
|
pi: deps.pi,
|
|
182
185
|
runId,
|
|
@@ -189,9 +192,13 @@ export async function runParallelPath(
|
|
|
189
192
|
detachedCleanup.recover(index);
|
|
190
193
|
}
|
|
191
194
|
},
|
|
195
|
+
onParentAskHandoff: (handoff) => {
|
|
196
|
+
if (!parentAsk) parentAsk = handoff;
|
|
197
|
+
},
|
|
192
198
|
tasks,
|
|
193
199
|
taskTexts,
|
|
194
200
|
agents,
|
|
201
|
+
...(data.parallelAgentConfigs ? { agentConfigs } : {}),
|
|
195
202
|
ctx,
|
|
196
203
|
intercomEvents: deps.pi.events,
|
|
197
204
|
signal,
|
|
@@ -242,21 +249,26 @@ export async function runParallelPath(
|
|
|
242
249
|
mode: "parallel",
|
|
243
250
|
runId,
|
|
244
251
|
results,
|
|
252
|
+
parentAskYielded: parentAsk !== undefined,
|
|
245
253
|
progress: params.includeProgress ? allProgress : undefined,
|
|
246
254
|
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
247
255
|
});
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
256
|
+
if (parentAsk) {
|
|
257
|
+
const worktreeSuffix = buildParallelWorktreeSuffix(worktreeSetup, artifactsDir, tasks as TaskParam[]);
|
|
258
|
+
const handoffText = formatParentAskHandoffOutput(parentAsk);
|
|
259
|
+
const yieldedResult: SubagentToolResult = {
|
|
260
|
+
content: [{ type: "text", text: worktreeSuffix ? `${handoffText}\n\n${worktreeSuffix}` : handoffText }],
|
|
261
|
+
details,
|
|
262
|
+
};
|
|
263
|
+
markParentAskHandoff(yieldedResult, parentAsk);
|
|
264
|
+
return yieldedResult;
|
|
265
|
+
}
|
|
254
266
|
if (interrupted) {
|
|
255
267
|
return {
|
|
256
268
|
content: [
|
|
257
269
|
{
|
|
258
270
|
type: "text",
|
|
259
|
-
text: `Parallel run
|
|
271
|
+
text: `Parallel run ended after interrupt (${interrupted.agent}). Launch fresh subagents for any follow-up.`,
|
|
260
272
|
},
|
|
261
273
|
],
|
|
262
274
|
details,
|
|
@@ -272,7 +284,7 @@ export async function runParallelPath(
|
|
|
272
284
|
content: [
|
|
273
285
|
{
|
|
274
286
|
type: "text",
|
|
275
|
-
text: `Parallel run detached for intercom coordination (${detached.agent}). Reply to the supervisor request first. After the child exits,
|
|
287
|
+
text: `Parallel run detached for intercom coordination (${detached.agent}). Reply to the supervisor request first. After the child exits, launch fresh follow-up work if needed.`,
|
|
276
288
|
},
|
|
277
289
|
],
|
|
278
290
|
details,
|
|
@@ -294,8 +306,7 @@ export async function runParallelPath(
|
|
|
294
306
|
}
|
|
295
307
|
|
|
296
308
|
const worktreeSuffix = buildParallelWorktreeSuffix(worktreeSetup, artifactsDir, tasks as TaskParam[]);
|
|
297
|
-
const
|
|
298
|
-
const aggregatedOutput = aggregateParallelOutputs(
|
|
309
|
+
const childContent = formatParallelResultContent(
|
|
299
310
|
results.map((result) => ({
|
|
300
311
|
agent: result.agent,
|
|
301
312
|
output: result.truncation?.text || getSingleResultOutput(result),
|
|
@@ -304,11 +315,7 @@ export async function runParallelPath(
|
|
|
304
315
|
})),
|
|
305
316
|
(i, agent) => `=== Task ${i + 1}: ${agent} ===`,
|
|
306
317
|
);
|
|
307
|
-
|
|
308
|
-
const summary = `${ok}/${results.length} succeeded`;
|
|
309
|
-
const fullContent = worktreeSuffix
|
|
310
|
-
? `${summary}\n\n${aggregatedOutput}\n\n${worktreeSuffix}`
|
|
311
|
-
: `${summary}\n\n${aggregatedOutput}`;
|
|
318
|
+
const fullContent = worktreeSuffix ? `${childContent}\n\n${worktreeSuffix}` : childContent;
|
|
312
319
|
|
|
313
320
|
return {
|
|
314
321
|
content: [{ type: "text", text: fullContent }],
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ForegroundParentAskHandoff, SubagentToolResult } from "../../shared/types.js";
|
|
2
|
+
|
|
3
|
+
const parentAskHandoffs = new WeakMap<SubagentToolResult, ForegroundParentAskHandoff>();
|
|
4
|
+
|
|
5
|
+
export function markParentAskHandoff(result: SubagentToolResult, handoff: ForegroundParentAskHandoff): void {
|
|
6
|
+
parentAskHandoffs.set(result, handoff);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getParentAskHandoff(result: SubagentToolResult): ForegroundParentAskHandoff | undefined {
|
|
10
|
+
return parentAskHandoffs.get(result);
|
|
11
|
+
}
|
|
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { normalizeSkillInput } from "../../agents/skills.js";
|
|
4
4
|
import { INTERCOM_BRIDGE_MARKER, resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.js";
|
|
5
|
+
import { requestSupervisorAuthorization } from "../../intercom/supervisor-authorization.js";
|
|
5
6
|
import { collectKnownModelProviders, type ModelInfo, toModelInfo } from "../../shared/model-info.js";
|
|
6
7
|
import { createCandidateModelResolver } from "../../shared/model-resolution.js";
|
|
7
8
|
import {
|
|
@@ -13,6 +14,8 @@ import {
|
|
|
13
14
|
type AgentProgress,
|
|
14
15
|
type ArtifactPaths,
|
|
15
16
|
isWorkflowStageOrchestrationContext,
|
|
17
|
+
type ParentAskHandoffRequest,
|
|
18
|
+
type RunSyncOptions,
|
|
16
19
|
type SingleResult,
|
|
17
20
|
type SubagentToolResult,
|
|
18
21
|
workflowSessionMetadataFromContext,
|
|
@@ -29,12 +32,11 @@ import {
|
|
|
29
32
|
resolveSingleOutputPath,
|
|
30
33
|
validateFileOnlyOutputMode,
|
|
31
34
|
} from "../shared/single-output.js";
|
|
35
|
+
import { formatParentAskHandoffOutput } from "./parent-ask-output.js";
|
|
32
36
|
import {
|
|
33
37
|
createForegroundControlNotifier,
|
|
34
38
|
maybeBuildForegroundIntercomReceipt,
|
|
35
39
|
notifyDetachedForegroundChildExit,
|
|
36
|
-
rememberForegroundRun,
|
|
37
|
-
replaceForegroundRunChild,
|
|
38
40
|
} from "./subagent-executor-status.js";
|
|
39
41
|
import type { ExecutionContextData, ForegroundControl, ResolvedExecutorDeps } from "./subagent-executor-types.js";
|
|
40
42
|
|
|
@@ -123,7 +125,8 @@ export async function runSinglePath(
|
|
|
123
125
|
const currentProvider = ctx.model?.provider;
|
|
124
126
|
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
125
127
|
const knownModelProviders = collectKnownModelProviders(ctx.modelRegistry);
|
|
126
|
-
|
|
128
|
+
const handoffTaskContext = params.task ?? "";
|
|
129
|
+
let task = handoffTaskContext;
|
|
127
130
|
const modelOverride: string | undefined = resolveModelCandidate(
|
|
128
131
|
(params.model as string | undefined) ?? agentConfig.model,
|
|
129
132
|
availableModels,
|
|
@@ -165,6 +168,7 @@ export async function runSinglePath(
|
|
|
165
168
|
effectiveSkills = skillOverride;
|
|
166
169
|
}
|
|
167
170
|
const interruptController = new AbortController();
|
|
171
|
+
let parentAsk: ParentAskHandoffRequest | undefined;
|
|
168
172
|
const foregroundControl = deps.state.foregroundControls.get(runId);
|
|
169
173
|
if (foregroundControl) {
|
|
170
174
|
foregroundControl.currentAgent = params.agent;
|
|
@@ -184,7 +188,8 @@ export async function runSinglePath(
|
|
|
184
188
|
|
|
185
189
|
let r: SingleResult;
|
|
186
190
|
try {
|
|
187
|
-
|
|
191
|
+
const supervisorAuthorization = await requestSupervisorAuthorization(deps.pi.events, childIntercomTarget);
|
|
192
|
+
const runOptions: RunSyncOptions = {
|
|
188
193
|
cwd: effectiveCwd,
|
|
189
194
|
signal,
|
|
190
195
|
interruptSignal: interruptController.signal,
|
|
@@ -206,14 +211,18 @@ export async function runSinglePath(
|
|
|
206
211
|
controlConfig,
|
|
207
212
|
onControlEvent,
|
|
208
213
|
intercomSessionName: childIntercomTarget,
|
|
214
|
+
supervisorAuthorization,
|
|
209
215
|
orchestratorIntercomTarget: data.intercomBridge.active ? data.intercomBridge.orchestratorTarget : undefined,
|
|
210
216
|
intercomGroup: resolveChildIntercomGroup(params.group, inheritedIntercomGroup(ctx), undefined),
|
|
217
|
+
onParentAskHandoff: (request) => {
|
|
218
|
+
if (parentAsk) return;
|
|
219
|
+
request.taskContext = handoffTaskContext;
|
|
220
|
+
parentAsk = request;
|
|
221
|
+
interruptController.abort();
|
|
222
|
+
},
|
|
211
223
|
onDetachedExit: (result) => {
|
|
212
224
|
cleanupTransientProgress(progressDir, artifactConfig.enabled);
|
|
213
|
-
if (result) {
|
|
214
|
-
replaceForegroundRunChild(deps.state, runId, 0, result);
|
|
215
|
-
notifyDetachedForegroundChildExit({ pi: deps.pi, runId, mode: "single", index: 0, result });
|
|
216
|
-
}
|
|
225
|
+
if (result) notifyDetachedForegroundChildExit({ pi: deps.pi, runId, mode: "single", index: 0, result });
|
|
217
226
|
},
|
|
218
227
|
index: 0,
|
|
219
228
|
modelOverride,
|
|
@@ -224,7 +233,8 @@ export async function runSinglePath(
|
|
|
224
233
|
currentModel: currentModelFullId(ctx.model),
|
|
225
234
|
currentThinkingLevel: ctx.thinkingLevel,
|
|
226
235
|
skills: effectiveSkills,
|
|
227
|
-
}
|
|
236
|
+
};
|
|
237
|
+
r = await deps.runtime.runSync(ctx.cwd, agents, params.agent!, task, runOptions);
|
|
228
238
|
} catch (error) {
|
|
229
239
|
cleanupTransientProgress(progressDir, artifactConfig.enabled);
|
|
230
240
|
throw error;
|
|
@@ -263,16 +273,11 @@ export async function runSinglePath(
|
|
|
263
273
|
mode: "single",
|
|
264
274
|
runId,
|
|
265
275
|
results: [r],
|
|
276
|
+
parentAskYielded: parentAsk !== undefined && r.interrupted,
|
|
266
277
|
progress: params.includeProgress ? allProgress : undefined,
|
|
267
278
|
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
268
279
|
truncation: r.truncation,
|
|
269
280
|
});
|
|
270
|
-
rememberForegroundRun(deps.state, {
|
|
271
|
-
runId,
|
|
272
|
-
mode: "single",
|
|
273
|
-
cwd: effectiveCwd,
|
|
274
|
-
results: details.results,
|
|
275
|
-
});
|
|
276
281
|
|
|
277
282
|
if (!r.detached && !r.interrupted) {
|
|
278
283
|
const intercomReceipt = await maybeBuildForegroundIntercomReceipt({
|
|
@@ -296,7 +301,24 @@ export async function runSinglePath(
|
|
|
296
301
|
content: [
|
|
297
302
|
{
|
|
298
303
|
type: "text",
|
|
299
|
-
text: `Detached for intercom coordination: ${params.agent}. Reply to the supervisor request first. After the child exits,
|
|
304
|
+
text: `Detached for intercom coordination: ${params.agent}. Reply to the supervisor request first. After the child exits, launch a fresh follow-up if needed.`,
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
details,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (parentAsk && r.interrupted) {
|
|
312
|
+
return {
|
|
313
|
+
content: [
|
|
314
|
+
{
|
|
315
|
+
type: "text",
|
|
316
|
+
text: formatParentAskHandoffOutput({
|
|
317
|
+
askingChildIndex: 0,
|
|
318
|
+
releasedChildIndices: [0],
|
|
319
|
+
unlaunchedChildIndices: [],
|
|
320
|
+
request: parentAsk,
|
|
321
|
+
}),
|
|
300
322
|
},
|
|
301
323
|
],
|
|
302
324
|
details,
|
|
@@ -306,7 +328,10 @@ export async function runSinglePath(
|
|
|
306
328
|
if (r.interrupted) {
|
|
307
329
|
return {
|
|
308
330
|
content: [
|
|
309
|
-
{
|
|
331
|
+
{
|
|
332
|
+
type: "text",
|
|
333
|
+
text: `Run ended after interrupt (${params.agent}). Launch a fresh subagent for any follow-up.`,
|
|
334
|
+
},
|
|
310
335
|
],
|
|
311
336
|
details,
|
|
312
337
|
};
|