@bastani/atomic 0.8.4 → 0.8.5-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +24 -23
- package/dist/builtin/intercom/README.md +5 -5
- package/dist/builtin/intercom/index.ts +1 -1
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/ui/compose.ts +19 -1
- package/dist/builtin/intercom/ui/session-list.ts +19 -1
- package/dist/builtin/mcp/README.md +3 -3
- package/dist/builtin/mcp/commands.ts +1 -1
- package/dist/builtin/mcp/host-html-template.ts +1 -1
- package/dist/builtin/mcp/mcp-panel.ts +14 -14
- package/dist/builtin/mcp/mcp-setup-panel.ts +4 -4
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/mcp/tool-result-renderer.ts +1 -1
- package/dist/builtin/subagents/README.md +3 -3
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/tui/render.ts +1844 -1062
- package/dist/builtin/web-access/README.md +1 -1
- package/dist/builtin/web-access/curator-page.ts +2 -2
- package/dist/builtin/web-access/index.ts +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/README.md +34 -7
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +23 -4
- package/dist/builtin/workflows/builtin/ralph.ts +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/workflow/SKILL.md +75 -16
- package/dist/builtin/workflows/skills/workflow/references/running-workflows.md +34 -11
- package/dist/builtin/workflows/skills/workflow/references/sdk-authoring.md +111 -20
- package/dist/builtin/workflows/src/extension/discovery.ts +32 -4
- package/dist/builtin/workflows/src/extension/index.ts +347 -63
- package/dist/builtin/workflows/src/extension/render-call.ts +3 -1
- package/dist/builtin/workflows/src/extension/render-result.ts +7 -0
- package/dist/builtin/workflows/src/extension/runtime.ts +4 -2
- package/dist/builtin/workflows/src/extension/wiring.ts +32 -8
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +36 -14
- package/dist/builtin/workflows/src/runs/background/runner.ts +2 -2
- package/dist/builtin/workflows/src/runs/background/status.ts +89 -0
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +338 -78
- package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +55 -7
- package/dist/builtin/workflows/src/runs/shared/workflow-runner.ts +146 -10
- package/dist/builtin/workflows/src/shared/store.ts +29 -0
- package/dist/builtin/workflows/src/shared/types.ts +25 -4
- package/dist/builtin/workflows/src/tui/graph-canvas.ts +69 -2
- package/dist/builtin/workflows/src/tui/graph-view.ts +97 -182
- package/dist/builtin/workflows/src/tui/header.ts +36 -20
- package/dist/builtin/workflows/src/tui/inline-form-card.ts +129 -46
- package/dist/builtin/workflows/src/tui/inline-form-editor.ts +111 -36
- package/dist/builtin/workflows/src/tui/inputs-picker.ts +311 -91
- package/dist/builtin/workflows/src/tui/layout.ts +1 -1
- package/dist/builtin/workflows/src/tui/node-card.ts +66 -37
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +20 -6
- package/dist/builtin/workflows/src/tui/prompt-card.ts +262 -85
- package/dist/builtin/workflows/src/tui/run-detail.ts +50 -31
- package/dist/builtin/workflows/src/tui/session-confirm.ts +21 -14
- package/dist/builtin/workflows/src/tui/session-picker.ts +35 -26
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +531 -960
- package/dist/builtin/workflows/src/tui/status-helpers.ts +6 -0
- package/dist/builtin/workflows/src/tui/status-list.ts +8 -4
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +7 -2
- package/dist/builtin/workflows/src/tui/switcher.ts +55 -25
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +33 -1
- package/dist/builtin/workflows/src/tui/workflow-list.ts +10 -6
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -6
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +3 -3
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +7 -7
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +2 -2
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +3 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +3 -2
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +24 -12
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +28 -17
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +65 -28
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +13 -5
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +3 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- 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 +5 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts +8 -8
- package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/dialog-builder.js +6 -6
- package/dist/core/tools/ask-user-question/view/dialog-builder.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +7 -4
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +3 -2
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +3 -2
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +2 -2
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +2 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/todos.d.ts.map +1 -1
- package/dist/core/tools/todos.js +1 -1
- package/dist/core/tools/todos.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts +4 -3
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +1 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +3 -3
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +3 -3
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +2 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +1 -1
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +3 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +13 -3
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +2 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +2 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +1 -0
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +47 -5
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +5 -5
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +3 -3
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +7 -7
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +8 -8
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +3 -3
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +2 -2
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +10 -12
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +3 -3
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/working-status.d.ts +25 -0
- package/dist/modes/interactive/components/working-status.d.ts.map +1 -0
- package/dist/modes/interactive/components/working-status.js +28 -0
- package/dist/modes/interactive/components/working-status.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +8 -7
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +8 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +5 -5
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/development.md +2 -2
- package/docs/extensions.md +7 -7
- package/docs/packages.md +11 -8
- package/docs/quickstart.md +2 -2
- package/docs/rpc.md +1 -1
- package/docs/sdk.md +14 -11
- package/docs/session-format.md +1 -1
- package/docs/sessions.md +10 -10
- package/docs/settings.md +1 -1
- package/docs/terminal-setup.md +9 -9
- package/docs/tmux.md +10 -10
- package/docs/tui.md +2 -2
- package/docs/usage.md +9 -9
- package/package.json +6 -1
|
@@ -13,12 +13,14 @@ import type {
|
|
|
13
13
|
WorkflowInputSchema,
|
|
14
14
|
StageContext,
|
|
15
15
|
StageOptions,
|
|
16
|
+
StagePromptOptions,
|
|
16
17
|
WorkflowTaskContextInput,
|
|
17
18
|
WorkflowTaskOptions,
|
|
18
19
|
WorkflowTaskResult,
|
|
19
20
|
WorkflowTaskStep,
|
|
20
21
|
WorkflowArtifact,
|
|
21
22
|
WorkflowMaxOutput,
|
|
23
|
+
WorkflowOutputMode,
|
|
22
24
|
WorkflowChainOptions,
|
|
23
25
|
WorkflowParallelOptions,
|
|
24
26
|
WorkflowDetails,
|
|
@@ -149,6 +151,18 @@ export function resolveInputs(
|
|
|
149
151
|
return resolved;
|
|
150
152
|
}
|
|
151
153
|
|
|
154
|
+
function resolveInputConcurrency(
|
|
155
|
+
schema: Readonly<Record<string, WorkflowInputSchema>>,
|
|
156
|
+
resolvedInputs: ResolvedInputs,
|
|
157
|
+
): number | undefined {
|
|
158
|
+
if (schema["max_concurrency"]?.type !== "number") return undefined;
|
|
159
|
+
|
|
160
|
+
const value = resolvedInputs["max_concurrency"];
|
|
161
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 1) return undefined;
|
|
162
|
+
|
|
163
|
+
return Math.floor(value);
|
|
164
|
+
}
|
|
165
|
+
|
|
152
166
|
// ---------------------------------------------------------------------------
|
|
153
167
|
// HIL unavailable fallback — rejects with precise per-primitive error
|
|
154
168
|
// ---------------------------------------------------------------------------
|
|
@@ -250,15 +264,52 @@ function taskPrevious(options: WorkflowTaskOptions): WorkflowTaskOptions["previo
|
|
|
250
264
|
return options.previous;
|
|
251
265
|
}
|
|
252
266
|
|
|
253
|
-
|
|
267
|
+
type WorkflowTaskExecutionOptions = WorkflowTaskOptions & { chainDir?: string };
|
|
268
|
+
|
|
269
|
+
function resolveWorkflowPath(filePath: string, baseDir: string | undefined): string {
|
|
270
|
+
if (isAbsolute(filePath)) return filePath;
|
|
271
|
+
return resolve(baseDir ?? process.cwd(), filePath);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function taskBaseDir(options: Pick<WorkflowTaskExecutionOptions, "chainDir" | "cwd">): string | undefined {
|
|
275
|
+
if (typeof options.chainDir === "string" && options.chainDir.length > 0) {
|
|
276
|
+
return resolveWorkflowPath(options.chainDir, process.cwd());
|
|
277
|
+
}
|
|
278
|
+
if (typeof options.cwd === "string" && options.cwd.length > 0) {
|
|
279
|
+
return resolveWorkflowPath(options.cwd, process.cwd());
|
|
280
|
+
}
|
|
281
|
+
return undefined;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function taskReadInstruction(options: WorkflowTaskExecutionOptions): string {
|
|
285
|
+
if (options.reads === false || options.reads === undefined || options.reads.length === 0) return "";
|
|
286
|
+
const baseDir = taskBaseDir(options);
|
|
287
|
+
const files = options.reads.map((file) => resolveWorkflowPath(file, baseDir));
|
|
288
|
+
return `[Read from: ${files.join(", ")}]\n\n`;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function taskPromptOptions(options: WorkflowTaskExecutionOptions): StagePromptOptions | undefined {
|
|
292
|
+
const baseDir = taskBaseDir(options);
|
|
293
|
+
const promptOptions: StagePromptOptions = {
|
|
294
|
+
...(options.output !== undefined ? { output: options.output } : {}),
|
|
295
|
+
...(options.outputMode !== undefined ? { outputMode: options.outputMode } : {}),
|
|
296
|
+
...(baseDir !== undefined ? { cwd: baseDir } : options.cwd !== undefined ? { cwd: options.cwd } : {}),
|
|
297
|
+
...(options.maxOutput !== undefined ? { maxOutput: options.maxOutput } : {}),
|
|
298
|
+
...(options.artifacts !== undefined ? { artifacts: options.artifacts } : {}),
|
|
299
|
+
...(options.sessionDir !== undefined ? { sessionDir: options.sessionDir } : {}),
|
|
300
|
+
};
|
|
301
|
+
return Object.keys(promptOptions).length === 0 ? undefined : promptOptions;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function taskStageOptions(options: WorkflowTaskExecutionOptions): StageOptions {
|
|
254
305
|
const {
|
|
255
306
|
prompt: _prompt,
|
|
256
307
|
task: _task,
|
|
257
308
|
previous: _previous,
|
|
309
|
+
chainDir: _chainDir,
|
|
258
310
|
output: _output,
|
|
259
311
|
outputMode: _outputMode,
|
|
260
312
|
reads: _reads,
|
|
261
|
-
progress: _progress,
|
|
262
313
|
worktree: _worktree,
|
|
263
314
|
maxOutput: _maxOutput,
|
|
264
315
|
artifacts: _artifacts,
|
|
@@ -273,16 +324,11 @@ function taskOptionsFromStep(step: WorkflowTaskStep, prompt: string, previous?:
|
|
|
273
324
|
prompt: _prompt,
|
|
274
325
|
task: _task,
|
|
275
326
|
previous: _previous,
|
|
276
|
-
|
|
277
|
-
outputMode: _outputMode,
|
|
278
|
-
reads: _reads,
|
|
279
|
-
progress: _progress,
|
|
280
|
-
worktree: _worktree,
|
|
281
|
-
...stageOptions
|
|
327
|
+
...stepOptions
|
|
282
328
|
} = step;
|
|
283
329
|
return previous === undefined
|
|
284
|
-
? { ...
|
|
285
|
-
: { ...
|
|
330
|
+
? { ...stepOptions, prompt }
|
|
331
|
+
: { ...stepOptions, prompt, previous };
|
|
286
332
|
}
|
|
287
333
|
|
|
288
334
|
function replaceTaskPlaceholder(prompt: string, task: string): string {
|
|
@@ -382,6 +428,28 @@ function withoutUndefinedProperties<T extends object>(value: T): Partial<T> {
|
|
|
382
428
|
) as Partial<T>;
|
|
383
429
|
}
|
|
384
430
|
|
|
431
|
+
function sharedTaskDefaultsFromOptions(
|
|
432
|
+
options: WorkflowChainOptions | WorkflowParallelOptions,
|
|
433
|
+
): Partial<WorkflowTaskExecutionOptions> {
|
|
434
|
+
const {
|
|
435
|
+
task: _task,
|
|
436
|
+
concurrency: _concurrency,
|
|
437
|
+
failFast: _failFast,
|
|
438
|
+
...taskDefaults
|
|
439
|
+
} = options as WorkflowParallelOptions;
|
|
440
|
+
return withoutUndefinedProperties(taskDefaults);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function taskWithSharedDefaults(
|
|
444
|
+
taskOptions: WorkflowTaskOptions,
|
|
445
|
+
options: WorkflowChainOptions | WorkflowParallelOptions,
|
|
446
|
+
): WorkflowTaskExecutionOptions {
|
|
447
|
+
return {
|
|
448
|
+
...sharedTaskDefaultsFromOptions(options),
|
|
449
|
+
...withoutUndefinedProperties(taskOptions),
|
|
450
|
+
} as WorkflowTaskExecutionOptions;
|
|
451
|
+
}
|
|
452
|
+
|
|
385
453
|
function directTaskWithDefaults(
|
|
386
454
|
item: WorkflowDirectTaskItem,
|
|
387
455
|
options: WorkflowDirectOptions,
|
|
@@ -392,9 +460,9 @@ function directTaskWithDefaults(
|
|
|
392
460
|
concurrency: _concurrency,
|
|
393
461
|
failFast: _failFast,
|
|
394
462
|
chainDir: _chainDir,
|
|
463
|
+
reads,
|
|
395
464
|
output,
|
|
396
465
|
outputMode,
|
|
397
|
-
progress,
|
|
398
466
|
worktree,
|
|
399
467
|
maxOutput,
|
|
400
468
|
artifacts,
|
|
@@ -409,9 +477,9 @@ function directTaskWithDefaults(
|
|
|
409
477
|
|
|
410
478
|
return {
|
|
411
479
|
...taskWithStageDefaults,
|
|
480
|
+
...(item.reads === undefined && reads !== undefined ? { reads } : {}),
|
|
412
481
|
...(item.output === undefined && output !== undefined ? { output } : {}),
|
|
413
482
|
...(item.outputMode === undefined && outputMode !== undefined ? { outputMode } : {}),
|
|
414
|
-
...(item.progress === undefined && progress !== undefined ? { progress } : {}),
|
|
415
483
|
...(item.worktree === undefined && worktree !== undefined ? { worktree } : {}),
|
|
416
484
|
...(item.maxOutput === undefined && maxOutput !== undefined ? { maxOutput } : {}),
|
|
417
485
|
...(item.artifacts === undefined && artifacts !== undefined ? { artifacts } : {}),
|
|
@@ -427,8 +495,6 @@ function directTaskToStep(
|
|
|
427
495
|
count: _count,
|
|
428
496
|
output: _output,
|
|
429
497
|
outputMode: _outputMode,
|
|
430
|
-
reads: _reads,
|
|
431
|
-
progress: _progress,
|
|
432
498
|
worktree: _worktree,
|
|
433
499
|
prompt,
|
|
434
500
|
task,
|
|
@@ -442,6 +508,54 @@ function directTaskToStep(
|
|
|
442
508
|
};
|
|
443
509
|
}
|
|
444
510
|
|
|
511
|
+
function positiveConcurrency(value: number | undefined): number | undefined {
|
|
512
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 1) return undefined;
|
|
513
|
+
return Math.floor(value);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async function mapParallelSteps<T>(
|
|
517
|
+
steps: readonly WorkflowTaskStep[],
|
|
518
|
+
concurrency: number | undefined,
|
|
519
|
+
failFast: boolean | undefined,
|
|
520
|
+
mapper: (step: WorkflowTaskStep) => Promise<T>,
|
|
521
|
+
): Promise<T[]> {
|
|
522
|
+
const limit = positiveConcurrency(concurrency) ?? steps.length;
|
|
523
|
+
const results = new Array<T>(steps.length);
|
|
524
|
+
const failures: Array<{ readonly index: number; readonly error: unknown }> = [];
|
|
525
|
+
let nextIndex = 0;
|
|
526
|
+
let firstFailure: unknown;
|
|
527
|
+
|
|
528
|
+
async function worker(): Promise<void> {
|
|
529
|
+
while (true) {
|
|
530
|
+
if (failFast !== false && firstFailure !== undefined) return;
|
|
531
|
+
const index = nextIndex;
|
|
532
|
+
nextIndex += 1;
|
|
533
|
+
const step = steps[index];
|
|
534
|
+
if (step === undefined) return;
|
|
535
|
+
try {
|
|
536
|
+
results[index] = await mapper(step);
|
|
537
|
+
} catch (err) {
|
|
538
|
+
failures.push({ index, error: err });
|
|
539
|
+
firstFailure ??= err;
|
|
540
|
+
if (failFast !== false) throw err;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
await Promise.all(
|
|
546
|
+
Array.from({ length: Math.min(limit, steps.length) }, () => worker()),
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
if (failures.length > 0) {
|
|
550
|
+
throw new AggregateError(
|
|
551
|
+
failures.map((failure) => failure.error),
|
|
552
|
+
`pi-workflows: ${failures.length} parallel ${failures.length === 1 ? "step" : "steps"} failed`,
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return results;
|
|
557
|
+
}
|
|
558
|
+
|
|
445
559
|
function expandedParallelTasks(tasks: readonly WorkflowDirectTaskItem[]): WorkflowDirectTaskItem[] {
|
|
446
560
|
const expanded: WorkflowDirectTaskItem[] = [];
|
|
447
561
|
for (const task of tasks) {
|
|
@@ -584,13 +698,14 @@ function isRunOpts(value: WorkflowDirectOptions | RunOpts | undefined): value is
|
|
|
584
698
|
}
|
|
585
699
|
|
|
586
700
|
async function writeDirectOutput(
|
|
587
|
-
item:
|
|
701
|
+
item: { readonly chainDir?: string; readonly cwd?: string; readonly output?: string | false; readonly outputMode?: WorkflowOutputMode },
|
|
588
702
|
result: WorkflowTaskResult,
|
|
589
703
|
): Promise<{ result: WorkflowTaskResult; artifact?: WorkflowArtifact }> {
|
|
590
704
|
if (typeof item.output !== "string") return { result };
|
|
591
705
|
|
|
592
|
-
|
|
593
|
-
await
|
|
706
|
+
const outputPath = resolveWorkflowPath(item.output, taskBaseDir(item));
|
|
707
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
708
|
+
await writeFile(outputPath, result.text, "utf8");
|
|
594
709
|
|
|
595
710
|
const visibleResult =
|
|
596
711
|
item.outputMode === "file-only"
|
|
@@ -601,7 +716,7 @@ async function writeDirectOutput(
|
|
|
601
716
|
result: visibleResult,
|
|
602
717
|
artifact: {
|
|
603
718
|
kind: "output",
|
|
604
|
-
path:
|
|
719
|
+
path: outputPath,
|
|
605
720
|
taskName: result.name,
|
|
606
721
|
},
|
|
607
722
|
};
|
|
@@ -746,7 +861,11 @@ export async function runParallel(
|
|
|
746
861
|
const direct = defineDirectWorkflow("direct-parallel", async (ctx) => {
|
|
747
862
|
try {
|
|
748
863
|
const steps = prepared.tasks.map((task) => directTaskToStep(task));
|
|
749
|
-
const rawResults = await ctx.parallel(steps, {
|
|
864
|
+
const rawResults = await ctx.parallel(steps, {
|
|
865
|
+
task: options.task,
|
|
866
|
+
concurrency: options.concurrency,
|
|
867
|
+
failFast: options.failFast,
|
|
868
|
+
});
|
|
750
869
|
const persisted = await Promise.all(
|
|
751
870
|
rawResults.map((result, index) => writeDirectOutput(prepared.tasks[index]!, result)),
|
|
752
871
|
);
|
|
@@ -788,9 +907,16 @@ async function runDirectChainStep(
|
|
|
788
907
|
const steps = prepared.tasks.map((item) =>
|
|
789
908
|
directTaskToStep(item, directTaskPrompt(item) ?? "{previous}", item.previous ?? prior),
|
|
790
909
|
);
|
|
791
|
-
const rawResults = await ctx.parallel(steps, {
|
|
910
|
+
const rawResults = await ctx.parallel(steps, {
|
|
911
|
+
task: rootTask,
|
|
912
|
+
concurrency: step.concurrency ?? options.concurrency,
|
|
913
|
+
failFast: step.failFast ?? options.failFast,
|
|
914
|
+
...(typeof options.chainDir === "string" ? { chainDir: options.chainDir } : {}),
|
|
915
|
+
} as WorkflowParallelOptions);
|
|
792
916
|
const persisted = await Promise.all(
|
|
793
|
-
rawResults.map((result, taskIndex) =>
|
|
917
|
+
rawResults.map((result, taskIndex) =>
|
|
918
|
+
writeDirectOutput({ ...prepared.tasks[taskIndex]!, chainDir: options.chainDir }, result),
|
|
919
|
+
),
|
|
794
920
|
);
|
|
795
921
|
const worktreeDiffs = collectWorktreeDiffs(prepared, stepOptions.artifacts !== false);
|
|
796
922
|
return {
|
|
@@ -811,9 +937,12 @@ async function runDirectChainStep(
|
|
|
811
937
|
try {
|
|
812
938
|
const rawResult = await ctx.task(
|
|
813
939
|
preparedStep.name,
|
|
814
|
-
|
|
940
|
+
{
|
|
941
|
+
...directTaskToStep(preparedStep, replaceTaskPlaceholder(prompt, rootTask), preparedStep.previous ?? prior),
|
|
942
|
+
...(typeof options.chainDir === "string" ? { chainDir: options.chainDir } : {}),
|
|
943
|
+
} as WorkflowTaskOptions,
|
|
815
944
|
);
|
|
816
|
-
const { result, artifact } = await writeDirectOutput(preparedStep, rawResult);
|
|
945
|
+
const { result, artifact } = await writeDirectOutput({ ...preparedStep, chainDir: options.chainDir }, rawResult);
|
|
817
946
|
const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
|
|
818
947
|
return {
|
|
819
948
|
results: [result],
|
|
@@ -924,8 +1053,8 @@ function nextEventLoopTurn(): Promise<void> {
|
|
|
924
1053
|
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
925
1054
|
}
|
|
926
1055
|
|
|
927
|
-
export async function run(
|
|
928
|
-
def: WorkflowDefinition
|
|
1056
|
+
export async function run<TInputs extends Record<string, unknown>>(
|
|
1057
|
+
def: WorkflowDefinition<TInputs>,
|
|
929
1058
|
inputs: Record<string, unknown>,
|
|
930
1059
|
opts: RunOpts = {},
|
|
931
1060
|
): Promise<RunResult> {
|
|
@@ -996,16 +1125,23 @@ export async function run(
|
|
|
996
1125
|
|
|
997
1126
|
// 4. Create GraphFrontierTracker and per-run ConcurrencyLimiter
|
|
998
1127
|
const tracker = new GraphFrontierTracker();
|
|
999
|
-
const
|
|
1128
|
+
const inputConcurrency = resolveInputConcurrency(def.inputs, resolvedInputs);
|
|
1129
|
+
const limiter = createRunLimiter(inputConcurrency ?? opts.config?.defaultConcurrency);
|
|
1000
1130
|
interface ReleaseBarrier {
|
|
1001
1131
|
readonly promise: Promise<void>;
|
|
1002
1132
|
readonly resolve: () => void;
|
|
1003
1133
|
readonly reject: (reason?: unknown) => void;
|
|
1004
1134
|
}
|
|
1005
1135
|
const releaseBarriers = new Map<string, ReleaseBarrier>();
|
|
1136
|
+
const cascadePauseOwners = new Map<string, Set<string>>();
|
|
1006
1137
|
|
|
1007
1138
|
const makeReleaseBarrier = (): ReleaseBarrier => {
|
|
1008
1139
|
const resolver = Promise.withResolvers<void>();
|
|
1140
|
+
// Abort rejects release barriers during kill/shutdown. Some barriers are
|
|
1141
|
+
// only state markers for a paused root/current stage and have no active
|
|
1142
|
+
// waiter, so mark expected cancellation as observed while preserving the
|
|
1143
|
+
// same promise for callers that do await it.
|
|
1144
|
+
void resolver.promise.catch(() => {});
|
|
1009
1145
|
return { promise: resolver.promise, resolve: resolver.resolve, reject: resolver.reject };
|
|
1010
1146
|
};
|
|
1011
1147
|
|
|
@@ -1059,6 +1195,23 @@ export async function run(
|
|
|
1059
1195
|
activeStore.recordStageBlocked(runId, stage.id, blockedBy);
|
|
1060
1196
|
};
|
|
1061
1197
|
|
|
1198
|
+
const markCascadePaused = (stageId: string, ownerStageId: string): void => {
|
|
1199
|
+
let owners = cascadePauseOwners.get(stageId);
|
|
1200
|
+
if (!owners) {
|
|
1201
|
+
owners = new Set<string>();
|
|
1202
|
+
cascadePauseOwners.set(stageId, owners);
|
|
1203
|
+
}
|
|
1204
|
+
owners.add(ownerStageId);
|
|
1205
|
+
};
|
|
1206
|
+
|
|
1207
|
+
const releaseCascadePauseOwner = (stageId: string, ownerStageId: string): boolean => {
|
|
1208
|
+
const owners = cascadePauseOwners.get(stageId);
|
|
1209
|
+
if (!owners) return false;
|
|
1210
|
+
const changed = owners.delete(ownerStageId);
|
|
1211
|
+
if (owners.size === 0) cascadePauseOwners.delete(stageId);
|
|
1212
|
+
return changed;
|
|
1213
|
+
};
|
|
1214
|
+
|
|
1062
1215
|
const releaseStageBarrier = (stageId: string): void => {
|
|
1063
1216
|
const barrier = releaseBarriers.get(stageId);
|
|
1064
1217
|
if (!barrier) return;
|
|
@@ -1067,12 +1220,14 @@ export async function run(
|
|
|
1067
1220
|
};
|
|
1068
1221
|
|
|
1069
1222
|
const cascadePauseFrom = async (pausedStageId: string): Promise<void> => {
|
|
1223
|
+
const stageRegistry = opts.stageControlRegistry ?? defaultStageControlRegistry;
|
|
1070
1224
|
for (const descendant of descendantsOf(pausedStageId)) {
|
|
1071
1225
|
if (isTerminalStage(descendant) || descendant.status === "paused" || descendant.status === "blocked") continue;
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
if (descendantHandle && descendantHandle.status === "running") {
|
|
1226
|
+
const descendantHandle = stageRegistry.get(runId, descendant.id);
|
|
1227
|
+
if (descendantHandle?.isStreaming || descendant.status === "running") {
|
|
1228
|
+
if (descendantHandle && (descendantHandle.status === "running" || descendantHandle.status === "pending")) {
|
|
1075
1229
|
await descendantHandle.pause();
|
|
1230
|
+
markCascadePaused(descendant.id, pausedStageId);
|
|
1076
1231
|
}
|
|
1077
1232
|
continue;
|
|
1078
1233
|
}
|
|
@@ -1080,17 +1235,32 @@ export async function run(
|
|
|
1080
1235
|
}
|
|
1081
1236
|
};
|
|
1082
1237
|
|
|
1083
|
-
const cascadeResumeFrom = (resumedStageId: string): void => {
|
|
1238
|
+
const cascadeResumeFrom = async (resumedStageId: string): Promise<void> => {
|
|
1239
|
+
const stageRegistry = opts.stageControlRegistry ?? defaultStageControlRegistry;
|
|
1084
1240
|
for (const descendant of descendantsOf(resumedStageId)) {
|
|
1085
|
-
if (isTerminalStage(descendant)
|
|
1086
|
-
if (
|
|
1087
|
-
|
|
1088
|
-
|
|
1241
|
+
if (isTerminalStage(descendant)) continue;
|
|
1242
|
+
if (descendant.status === "blocked") {
|
|
1243
|
+
if (blockingAncestorFor(descendant) !== undefined) continue;
|
|
1244
|
+
if (activeStore.recordStageUnblocked(runId, descendant.id)) {
|
|
1245
|
+
releaseStageBarrier(descendant.id);
|
|
1246
|
+
}
|
|
1247
|
+
continue;
|
|
1248
|
+
}
|
|
1249
|
+
if (descendant.status === "paused") {
|
|
1250
|
+
const ownedByResumedStage = releaseCascadePauseOwner(descendant.id, resumedStageId);
|
|
1251
|
+
if (!ownedByResumedStage) continue;
|
|
1252
|
+
if (cascadePauseOwners.has(descendant.id)) continue;
|
|
1253
|
+
if (blockingAncestorFor(descendant) !== undefined) continue;
|
|
1254
|
+
const descendantHandle = stageRegistry.get(runId, descendant.id);
|
|
1255
|
+
if (descendantHandle?.status === "paused") {
|
|
1256
|
+
await descendantHandle.resume();
|
|
1257
|
+
}
|
|
1089
1258
|
}
|
|
1090
1259
|
}
|
|
1091
1260
|
};
|
|
1092
1261
|
|
|
1093
1262
|
const rejectReleaseBarriers = (reason: unknown): void => {
|
|
1263
|
+
cascadePauseOwners.clear();
|
|
1094
1264
|
for (const [stageId, barrier] of releaseBarriers) {
|
|
1095
1265
|
releaseBarriers.delete(stageId);
|
|
1096
1266
|
activeStore.recordStageUnblocked(runId, stageId);
|
|
@@ -1105,8 +1275,8 @@ export async function run(
|
|
|
1105
1275
|
);
|
|
1106
1276
|
|
|
1107
1277
|
// 5. Build WorkflowRunContext
|
|
1108
|
-
const ctx: WorkflowRunContext = {
|
|
1109
|
-
inputs: resolvedInputs,
|
|
1278
|
+
const ctx: WorkflowRunContext<TInputs> = {
|
|
1279
|
+
inputs: resolvedInputs as TInputs,
|
|
1110
1280
|
ui: opts.ui ?? makeUnavailableUIContext(),
|
|
1111
1281
|
|
|
1112
1282
|
stage(name: string, options?: StageOptions) {
|
|
@@ -1168,6 +1338,15 @@ export async function run(
|
|
|
1168
1338
|
activeStore.recordStageAwaitingInput(runId, stageId, false);
|
|
1169
1339
|
await innerCtx.__dispose();
|
|
1170
1340
|
};
|
|
1341
|
+
let unregisterStageHandle = (): void => {};
|
|
1342
|
+
let liveHandleReleased = false;
|
|
1343
|
+
const releaseLiveHandle = async (): Promise<void> => {
|
|
1344
|
+
if (liveHandleReleased) return;
|
|
1345
|
+
liveHandleReleased = true;
|
|
1346
|
+
activeStore.recordStageAttachable(runId, stageId, false);
|
|
1347
|
+
unregisterStageHandle();
|
|
1348
|
+
await disposeInnerContext();
|
|
1349
|
+
};
|
|
1171
1350
|
|
|
1172
1351
|
// e. Register a live stage-control handle so attached panes can
|
|
1173
1352
|
// prompt/steer/pause/resume the underlying Pi session lazily.
|
|
@@ -1194,6 +1373,9 @@ export async function run(
|
|
|
1194
1373
|
get messages() {
|
|
1195
1374
|
return innerCtx.messages;
|
|
1196
1375
|
},
|
|
1376
|
+
get agentSession() {
|
|
1377
|
+
return innerCtx.__agentSession();
|
|
1378
|
+
},
|
|
1197
1379
|
async ensureAttached() {
|
|
1198
1380
|
await innerCtx.__ensureSession();
|
|
1199
1381
|
const meta = innerCtx.__sessionMeta();
|
|
@@ -1215,20 +1397,29 @@ export async function run(
|
|
|
1215
1397
|
await innerCtx.followUp(text);
|
|
1216
1398
|
},
|
|
1217
1399
|
async pause() {
|
|
1400
|
+
const statusBeforePause = stageSnapshot.status;
|
|
1218
1401
|
const changed = activeStore.recordStagePaused(runId, stageId);
|
|
1219
|
-
if (changed)
|
|
1220
|
-
|
|
1402
|
+
if (changed) {
|
|
1403
|
+
ensureReleaseBarrier(stageId);
|
|
1404
|
+
await cascadePauseFrom(stageId);
|
|
1405
|
+
}
|
|
1406
|
+
if (statusBeforePause === "pending" || statusBeforePause === "running" || innerCtx.isStreaming) {
|
|
1407
|
+
await innerCtx.__requestPause();
|
|
1408
|
+
}
|
|
1221
1409
|
},
|
|
1222
1410
|
async resume(message?: string) {
|
|
1223
1411
|
const changed = activeStore.recordStageResumed(runId, stageId);
|
|
1224
|
-
if (changed)
|
|
1412
|
+
if (changed) {
|
|
1413
|
+
releaseStageBarrier(stageId);
|
|
1414
|
+
await cascadeResumeFrom(stageId);
|
|
1415
|
+
}
|
|
1225
1416
|
await innerCtx.__resume(message);
|
|
1226
1417
|
},
|
|
1227
1418
|
subscribe(listener: AgentSessionEventListener) {
|
|
1228
1419
|
return innerCtx.subscribe(listener);
|
|
1229
1420
|
},
|
|
1230
1421
|
};
|
|
1231
|
-
|
|
1422
|
+
unregisterStageHandle = stageRegistry.register(handle);
|
|
1232
1423
|
|
|
1233
1424
|
// f. Record stage start in store (as pending), call onStageStart.
|
|
1234
1425
|
activeStore.recordStageStart(runId, stageSnapshot);
|
|
@@ -1239,9 +1430,10 @@ export async function run(
|
|
|
1239
1430
|
}
|
|
1240
1431
|
|
|
1241
1432
|
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
|
|
1433
|
+
const waitForStageRelease = async (): Promise<void> => {
|
|
1434
|
+
while (true) {
|
|
1435
|
+
const barrier = releaseBarriers.get(stageId);
|
|
1436
|
+
if (!barrier) return;
|
|
1245
1437
|
try {
|
|
1246
1438
|
await barrier.promise;
|
|
1247
1439
|
} catch (err) {
|
|
@@ -1251,10 +1443,21 @@ export async function run(
|
|
|
1251
1443
|
throw err;
|
|
1252
1444
|
}
|
|
1253
1445
|
}
|
|
1446
|
+
};
|
|
1447
|
+
|
|
1448
|
+
const runTrackedStageCall = async (call: () => Promise<string>): Promise<string> => {
|
|
1449
|
+
await waitForStageRelease();
|
|
1254
1450
|
|
|
1255
1451
|
// Block here until a concurrency slot is available for this run.
|
|
1256
1452
|
await limiter.acquire();
|
|
1257
1453
|
|
|
1454
|
+
try {
|
|
1455
|
+
await waitForStageRelease();
|
|
1456
|
+
} catch (err) {
|
|
1457
|
+
limiter.release();
|
|
1458
|
+
throw err;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1258
1461
|
stageSnapshot.status = "running";
|
|
1259
1462
|
stageSnapshot.startedAt = Date.now();
|
|
1260
1463
|
activeStore.recordStageStart(runId, stageSnapshot);
|
|
@@ -1310,8 +1513,10 @@ export async function run(
|
|
|
1310
1513
|
}
|
|
1311
1514
|
return result;
|
|
1312
1515
|
} catch (err) {
|
|
1313
|
-
|
|
1314
|
-
|
|
1516
|
+
if (!ownController.signal.aborted) {
|
|
1517
|
+
stageSnapshot.status = "failed";
|
|
1518
|
+
stageSnapshot.error = err instanceof Error ? err.message : String(err);
|
|
1519
|
+
}
|
|
1315
1520
|
throw err;
|
|
1316
1521
|
} finally {
|
|
1317
1522
|
stageSnapshot.endedAt = Date.now();
|
|
@@ -1343,12 +1548,39 @@ export async function run(
|
|
|
1343
1548
|
}
|
|
1344
1549
|
|
|
1345
1550
|
tracker.onSettle(stageId);
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1551
|
+
if (stageSnapshot.attached === true) {
|
|
1552
|
+
let unsubscribeDetach: (() => void) | undefined;
|
|
1553
|
+
let abortListener: (() => void) | undefined;
|
|
1554
|
+
const releaseWhenDetached = (force = false): void => {
|
|
1555
|
+
const currentRun = activeStore.runs().find((r) => r.id === runId);
|
|
1556
|
+
const currentStage = currentRun?.stages.find((s) => s.id === stageId);
|
|
1557
|
+
if (!force && currentStage?.attached === true) return;
|
|
1558
|
+
unsubscribeDetach?.();
|
|
1559
|
+
unsubscribeDetach = undefined;
|
|
1560
|
+
if (abortListener) {
|
|
1561
|
+
ownController.signal.removeEventListener("abort", abortListener);
|
|
1562
|
+
abortListener = undefined;
|
|
1563
|
+
}
|
|
1564
|
+
void releaseLiveHandle().catch(() => {});
|
|
1565
|
+
};
|
|
1566
|
+
unsubscribeDetach = activeStore.subscribe(() => releaseWhenDetached());
|
|
1567
|
+
abortListener = () => releaseWhenDetached(true);
|
|
1568
|
+
if (ownController.signal.aborted) releaseWhenDetached(true);
|
|
1569
|
+
else {
|
|
1570
|
+
ownController.signal.addEventListener(
|
|
1571
|
+
"abort",
|
|
1572
|
+
abortListener,
|
|
1573
|
+
{ once: true },
|
|
1574
|
+
);
|
|
1575
|
+
}
|
|
1576
|
+
releaseWhenDetached();
|
|
1351
1577
|
limiter.release();
|
|
1578
|
+
} else {
|
|
1579
|
+
try {
|
|
1580
|
+
await releaseLiveHandle();
|
|
1581
|
+
} finally {
|
|
1582
|
+
limiter.release();
|
|
1583
|
+
}
|
|
1352
1584
|
}
|
|
1353
1585
|
}
|
|
1354
1586
|
};
|
|
@@ -1438,28 +1670,52 @@ export async function run(
|
|
|
1438
1670
|
},
|
|
1439
1671
|
|
|
1440
1672
|
async task(name: string, options: WorkflowTaskOptions): Promise<WorkflowTaskResult> {
|
|
1441
|
-
const
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1673
|
+
const runTaskOnce = async (taskOptions: WorkflowTaskOptions): Promise<WorkflowTaskResult> => {
|
|
1674
|
+
const stage = ctx.stage(name, taskStageOptions(taskOptions));
|
|
1675
|
+
const rawText = await stage.prompt(
|
|
1676
|
+
applyTaskContext(`${taskReadInstruction(taskOptions)}${taskPrompt(taskOptions)}`, taskPrevious(taskOptions)),
|
|
1677
|
+
taskPromptOptions(taskOptions),
|
|
1678
|
+
);
|
|
1679
|
+
const text = truncateTaskOutput(rawText, taskOptions.maxOutput);
|
|
1680
|
+
const sessionId = (() => {
|
|
1681
|
+
try {
|
|
1682
|
+
return stage.sessionId;
|
|
1683
|
+
} catch {
|
|
1684
|
+
return undefined;
|
|
1685
|
+
}
|
|
1686
|
+
})();
|
|
1687
|
+
const stageMeta = (stage as InternalStageContext).__modelFallbackMeta?.() ?? {};
|
|
1688
|
+
return {
|
|
1689
|
+
name,
|
|
1690
|
+
stageName: name,
|
|
1691
|
+
text,
|
|
1692
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
1693
|
+
...(stage.sessionFile !== undefined ? { sessionFile: stage.sessionFile } : {}),
|
|
1694
|
+
...(stageMeta.model !== undefined ? { model: stageMeta.model } : {}),
|
|
1695
|
+
...(stageMeta.attemptedModels !== undefined ? { attemptedModels: stageMeta.attemptedModels } : {}),
|
|
1696
|
+
...(stageMeta.modelAttempts !== undefined ? { modelAttempts: stageMeta.modelAttempts } : {}),
|
|
1697
|
+
...(stageMeta.warnings !== undefined ? { warnings: stageMeta.warnings } : {}),
|
|
1698
|
+
};
|
|
1462
1699
|
};
|
|
1700
|
+
|
|
1701
|
+
if (options.worktree !== true) return runTaskOnce(options);
|
|
1702
|
+
|
|
1703
|
+
const prepared = prepareDirectWorktrees(
|
|
1704
|
+
[{ ...options, name }],
|
|
1705
|
+
{ ...options, worktree: true },
|
|
1706
|
+
`${runId}-${name}-${crypto.randomUUID()}`,
|
|
1707
|
+
name,
|
|
1708
|
+
);
|
|
1709
|
+
const preparedTask = prepared.tasks[0]!;
|
|
1710
|
+
try {
|
|
1711
|
+
const result = await runTaskOnce(preparedTask);
|
|
1712
|
+
const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
|
|
1713
|
+
return worktreeDiffs.artifacts.length === 0
|
|
1714
|
+
? result
|
|
1715
|
+
: { ...result, artifacts: [...(result.artifacts ?? []), ...worktreeDiffs.artifacts] };
|
|
1716
|
+
} finally {
|
|
1717
|
+
if (prepared.setup !== undefined) cleanupWorktrees(prepared.setup);
|
|
1718
|
+
}
|
|
1463
1719
|
},
|
|
1464
1720
|
|
|
1465
1721
|
async chain(steps: readonly WorkflowTaskStep[], options: WorkflowChainOptions = {}): Promise<WorkflowTaskResult[]> {
|
|
@@ -1469,19 +1725,23 @@ export async function run(
|
|
|
1469
1725
|
const explicitPrevious = taskPrevious(step);
|
|
1470
1726
|
const previous = explicitPrevious ?? (index > 0 ? results[index - 1] : undefined);
|
|
1471
1727
|
const prompt = replaceTaskPlaceholder(chainStepPrompt(step, index), options.task ?? "");
|
|
1472
|
-
results.push(await ctx.task(
|
|
1728
|
+
results.push(await ctx.task(
|
|
1729
|
+
step.name,
|
|
1730
|
+
taskWithSharedDefaults(taskOptionsFromStep(step, prompt, previous), options),
|
|
1731
|
+
));
|
|
1473
1732
|
}
|
|
1474
1733
|
return results;
|
|
1475
1734
|
},
|
|
1476
1735
|
|
|
1477
1736
|
async parallel(steps: readonly WorkflowTaskStep[], options: WorkflowParallelOptions = {}): Promise<WorkflowTaskResult[]> {
|
|
1478
1737
|
const fallback = parallelFallbackTask(steps, options);
|
|
1479
|
-
return
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1738
|
+
return mapParallelSteps(steps, options.concurrency, options.failFast, async (step) => {
|
|
1739
|
+
const prompt = replaceTaskPlaceholder(step.prompt ?? step.task ?? fallback, options.task ?? fallback);
|
|
1740
|
+
return ctx.task(
|
|
1741
|
+
step.name,
|
|
1742
|
+
taskWithSharedDefaults(taskOptionsFromStep(step, prompt, taskPrevious(step)), options),
|
|
1743
|
+
);
|
|
1744
|
+
});
|
|
1485
1745
|
},
|
|
1486
1746
|
};
|
|
1487
1747
|
|
|
@@ -50,6 +50,8 @@ export interface StageControlHandle {
|
|
|
50
50
|
readonly sessionFile: string | undefined;
|
|
51
51
|
readonly isStreaming: boolean;
|
|
52
52
|
readonly messages: AgentSession["messages"];
|
|
53
|
+
/** Live coding-agent session when available, used by embedded chat/footer UI. */
|
|
54
|
+
readonly agentSession?: AgentSession;
|
|
53
55
|
/** Ensure the SDK session exists. Cheap when already attached. */
|
|
54
56
|
ensureAttached(): Promise<void>;
|
|
55
57
|
/** Send a prompt. Use only when the stage is idle / not streaming. */
|