@agwab/pi-workflow 0.2.0 → 0.2.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/README.md +2 -0
- package/dist/compiler.d.ts +4 -6
- package/dist/compiler.js +64 -31
- package/dist/dynamic-generated-task-runtime.d.ts +2 -0
- package/dist/dynamic-generated-task-runtime.js +21 -8
- package/dist/engine.d.ts +5 -6
- package/dist/engine.js +36 -52
- package/dist/extension.js +11 -9
- package/dist/store.d.ts +3 -1
- package/dist/store.js +134 -38
- package/dist/subagent-backend.d.ts +4 -0
- package/dist/subagent-backend.js +128 -4
- package/dist/types.d.ts +3 -1
- package/dist/workflow-runtime.d.ts +2 -0
- package/dist/workflow-runtime.js +30 -0
- package/docs/usage.md +11 -0
- package/package.json +1 -1
- package/src/compiler.ts +113 -57
- package/src/dynamic-generated-task-runtime.ts +47 -12
- package/src/engine.ts +49 -85
- package/src/extension.ts +18 -14
- package/src/store.ts +179 -44
- package/src/subagent-backend.ts +170 -6
- package/src/types.ts +7 -1
- package/src/workflow-runtime.ts +35 -0
package/README.md
CHANGED
|
@@ -64,6 +64,8 @@ If you want deterministic manual control, use the slash command form:
|
|
|
64
64
|
/workflow run deep-research "Research this repository and summarize the architecture tradeoffs."
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
For opt-in lower-latency runs, add `--thinking low`; defaults remain conservative pending holdout evidence. See [`docs/usage.md`](./docs/usage.md).
|
|
68
|
+
|
|
67
69
|
For a one-off adaptive workflow that should plan, fan out, and synthesize without choosing a saved workflow, use:
|
|
68
70
|
|
|
69
71
|
```text
|
package/dist/compiler.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type ArtifactGraphWorkflowSpec
|
|
2
|
-
import { type WorkflowModelInfo } from "./workflow-runtime.js";
|
|
1
|
+
import { type ArtifactGraphWorkflowSpec } from "./types.js";
|
|
2
|
+
import { type WorkflowModelInfo, type WorkflowRuntimeDefaults } from "./workflow-runtime.js";
|
|
3
3
|
interface CompileOptions {
|
|
4
4
|
cwd: string;
|
|
5
5
|
specPath?: string;
|
|
@@ -7,9 +7,7 @@ interface CompileOptions {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function compileWorkflow(spec: ArtifactGraphWorkflowSpec, options: CompileOptions & {
|
|
9
9
|
task?: string;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
thinking?: ThinkingLevel;
|
|
13
|
-
};
|
|
10
|
+
runtimeOverrides?: WorkflowRuntimeDefaults;
|
|
11
|
+
runtimeDefaults?: WorkflowRuntimeDefaults;
|
|
14
12
|
}): Promise<any>;
|
|
15
13
|
export {};
|
package/dist/compiler.js
CHANGED
|
@@ -4,7 +4,7 @@ import { loadAgentByName } from "./agents.js";
|
|
|
4
4
|
import { DYNAMIC_OUTPUT_PROFILES } from "./dynamic-profiles.js";
|
|
5
5
|
import { classifyToolCapability, effectiveToolClassification, providersForSelectedTools, resolveToolSelection, TOOL_NAME_PATTERN, toolAllowedByAuthorityCeiling, toolNameForSpec, } from "./tool-metadata.js";
|
|
6
6
|
import { WorkflowValidationError, WORKFLOW_RUN_TYPE, } from "./types.js";
|
|
7
|
-
import { resolveWorkflowRuntime, } from "./workflow-runtime.js";
|
|
7
|
+
import { resolveWorkflowRuntime, selectWorkflowRuntime, } from "./workflow-runtime.js";
|
|
8
8
|
const DELEGATION_TOOLS = new Set([
|
|
9
9
|
"skill_test_subagent",
|
|
10
10
|
"workflow",
|
|
@@ -413,6 +413,17 @@ async function collectForeachPathWarnings(stages, specDir) {
|
|
|
413
413
|
}
|
|
414
414
|
return warnings;
|
|
415
415
|
}
|
|
416
|
+
function runtimeSettings(value) {
|
|
417
|
+
if (!isPlainRecord(value))
|
|
418
|
+
return undefined;
|
|
419
|
+
const model = typeof value.model === "string" && value.model.trim()
|
|
420
|
+
? value.model.trim()
|
|
421
|
+
: undefined;
|
|
422
|
+
const thinking = typeof value.thinking === "string" && value.thinking.trim()
|
|
423
|
+
? value.thinking.trim()
|
|
424
|
+
: undefined;
|
|
425
|
+
return model || thinking ? { model, thinking } : undefined;
|
|
426
|
+
}
|
|
416
427
|
async function compileArtifactGraphPlan(spec, options) {
|
|
417
428
|
const stages = spec.stages;
|
|
418
429
|
if (!Array.isArray(stages)) {
|
|
@@ -450,8 +461,9 @@ async function compileArtifactGraphPlan(spec, options) {
|
|
|
450
461
|
Object.keys(workflowInput).length > 0
|
|
451
462
|
? `# Workflow Input\n\n${JSON.stringify(workflowInput, null, 2)}`
|
|
452
463
|
: "";
|
|
453
|
-
const
|
|
454
|
-
const
|
|
464
|
+
const runtimeOverrides = options.runtimeOverrides;
|
|
465
|
+
const runtimeDefaults = options.runtimeDefaults;
|
|
466
|
+
const specRuntimeDefaults = runtimeSettings(spec.defaults);
|
|
455
467
|
const tasks = [];
|
|
456
468
|
const stageRecords = [];
|
|
457
469
|
const issues = [];
|
|
@@ -475,17 +487,26 @@ async function compileArtifactGraphPlan(spec, options) {
|
|
|
475
487
|
: `$.artifactGraph.stages.${jsonKey(stage.id)}.dynamic`;
|
|
476
488
|
validateDelegationBoundary(rawDynamicToolSelection.tools, issues, dynamicToolPath);
|
|
477
489
|
const dynamicToolSelection = filterToolSelection(rawDynamicToolSelection);
|
|
478
|
-
const
|
|
479
|
-
const resolvedDynamicRuntime = await resolveWorkflowRuntime(
|
|
490
|
+
const requestedRuntime = selectWorkflowRuntime(runtimeOverrides, runtimeSettings(stage), runtimeDefaults, specRuntimeDefaults);
|
|
491
|
+
const resolvedDynamicRuntime = await resolveWorkflowRuntime(requestedRuntime, {
|
|
480
492
|
taskKey: key,
|
|
481
493
|
stageId: stage.id,
|
|
482
494
|
taskId,
|
|
483
495
|
agent: "dynamic",
|
|
484
496
|
}, { availableModels: options.availableModels });
|
|
497
|
+
const dynamicTask = buildDynamicTask(stage, taskId, key, prompt, dependencyKeys, options.cwd, specDir, workflowInputText, options.task, resolvedDynamicRuntime, {
|
|
498
|
+
runtimeOverrides,
|
|
499
|
+
runtimeDefaults,
|
|
500
|
+
specRuntimeDefaults,
|
|
501
|
+
stageRuntime: runtimeSettings(stage),
|
|
502
|
+
}, overrides);
|
|
485
503
|
dynamicTask.runtime = {
|
|
486
504
|
...dynamicTask.runtime,
|
|
487
505
|
...resolvedDynamicRuntime,
|
|
488
506
|
};
|
|
507
|
+
if (options.availableModels?.length) {
|
|
508
|
+
dynamicTask.dynamic.availableModels = options.availableModels;
|
|
509
|
+
}
|
|
489
510
|
if (dynamicToolSelection.tools || dynamicToolSelection.toolProviders) {
|
|
490
511
|
dynamicTask.runtime = {
|
|
491
512
|
...dynamicTask.runtime,
|
|
@@ -539,13 +560,7 @@ async function compileArtifactGraphPlan(spec, options) {
|
|
|
539
560
|
validateToolSubset(toolSelection.tools, stageAgent, issues, toolPath);
|
|
540
561
|
validateDelegationBoundary(toolSelection.tools, issues, toolPath);
|
|
541
562
|
const filteredToolSelection = filterToolSelection(toolSelection);
|
|
542
|
-
|
|
543
|
-
const requestedRuntime = {
|
|
544
|
-
model: options.runtimeDefaults?.model ?? stage.model ?? spec.defaults?.model,
|
|
545
|
-
thinking: options.runtimeDefaults?.thinking ??
|
|
546
|
-
stage.thinking ??
|
|
547
|
-
spec.defaults?.thinking,
|
|
548
|
-
};
|
|
563
|
+
const requestedRuntime = selectWorkflowRuntime(runtimeOverrides, runtimeSettings(stage), runtimeDefaults, specRuntimeDefaults);
|
|
549
564
|
const resolvedRuntime = await resolveWorkflowRuntime(requestedRuntime, {
|
|
550
565
|
taskKey: key,
|
|
551
566
|
stageId: stage.id,
|
|
@@ -825,11 +840,33 @@ async function compileArtifactGraphPlan(spec, options) {
|
|
|
825
840
|
tasks,
|
|
826
841
|
warnings,
|
|
827
842
|
budget: {
|
|
828
|
-
models:
|
|
843
|
+
models: budgetModelRows(tasks),
|
|
829
844
|
unratedModels: [],
|
|
830
845
|
},
|
|
831
846
|
};
|
|
832
847
|
}
|
|
848
|
+
function budgetModelRows(tasks) {
|
|
849
|
+
const models = new Set();
|
|
850
|
+
for (const task of tasks) {
|
|
851
|
+
if (typeof task?.runtime?.model === "string" && task.runtime.model.trim()) {
|
|
852
|
+
models.add(task.runtime.model.trim());
|
|
853
|
+
}
|
|
854
|
+
const loop = task?.dynamic?.decisionLoop;
|
|
855
|
+
if (!loop || typeof loop !== "object")
|
|
856
|
+
continue;
|
|
857
|
+
for (const profile of [
|
|
858
|
+
loop.planner,
|
|
859
|
+
loop.workerDefaults,
|
|
860
|
+
loop.verifier,
|
|
861
|
+
loop.synthesis,
|
|
862
|
+
]) {
|
|
863
|
+
if (typeof profile?.model === "string" && profile.model.trim()) {
|
|
864
|
+
models.add(profile.model.trim());
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
return [...models].sort().map((model) => ({ model }));
|
|
869
|
+
}
|
|
833
870
|
function isSupportStage(stage) {
|
|
834
871
|
return stage?.support !== undefined && stage?.type === undefined;
|
|
835
872
|
}
|
|
@@ -889,7 +926,7 @@ function buildSupportTask(stage, taskId, key, prompt, dependencyKeys, cwd, workf
|
|
|
889
926
|
...overrides,
|
|
890
927
|
};
|
|
891
928
|
}
|
|
892
|
-
function buildDynamicTask(stage, taskId, key, prompt, dependencyKeys, cwd, specDir, workflowInputText, runtimeTask,
|
|
929
|
+
function buildDynamicTask(stage, taskId, key, prompt, dependencyKeys, cwd, specDir, workflowInputText, runtimeTask, controllerRuntime, runtimePriority, overrides) {
|
|
893
930
|
const dynamic = stage.dynamic ?? {};
|
|
894
931
|
const uses = String(dynamic.uses);
|
|
895
932
|
const normalizedPrompt = String(prompt ?? "").replace(/\$\{item\}/g, "the relevant item from the dependency context");
|
|
@@ -942,7 +979,7 @@ function buildDynamicTask(stage, taskId, key, prompt, dependencyKeys, cwd, specD
|
|
|
942
979
|
usesPath: resolve(specDir, String(workflow.uses)),
|
|
943
980
|
};
|
|
944
981
|
}
|
|
945
|
-
const decisionLoop = compileDynamicDecisionLoop(dynamic.decisionLoop,
|
|
982
|
+
const decisionLoop = compileDynamicDecisionLoop(dynamic.decisionLoop, runtimePriority);
|
|
946
983
|
return {
|
|
947
984
|
key,
|
|
948
985
|
id: key,
|
|
@@ -960,8 +997,7 @@ function buildDynamicTask(stage, taskId, key, prompt, dependencyKeys, cwd, specD
|
|
|
960
997
|
explicitWorktreePolicy: false,
|
|
961
998
|
runtime: {
|
|
962
999
|
approvalMode: "non-interactive",
|
|
963
|
-
|
|
964
|
-
thinking: defaultThinking,
|
|
1000
|
+
...controllerRuntime,
|
|
965
1001
|
maxRuntimeMs: dynamic.budget?.maxRuntimeMs ?? DEFAULT_DYNAMIC_MAX_RUNTIME_MS,
|
|
966
1002
|
},
|
|
967
1003
|
safety: {
|
|
@@ -999,21 +1035,24 @@ function buildDynamicTask(stage, taskId, key, prompt, dependencyKeys, cwd, specD
|
|
|
999
1035
|
helpers,
|
|
1000
1036
|
workflows,
|
|
1001
1037
|
...(decisionLoop ? { decisionLoop } : {}),
|
|
1038
|
+
...(runtimePriority.runtimeOverrides
|
|
1039
|
+
? { runtimeOverrides: runtimePriority.runtimeOverrides }
|
|
1040
|
+
: {}),
|
|
1002
1041
|
},
|
|
1003
1042
|
...overrides,
|
|
1004
1043
|
};
|
|
1005
1044
|
}
|
|
1006
|
-
function compileDynamicDecisionLoop(value,
|
|
1045
|
+
function compileDynamicDecisionLoop(value, runtimePriority) {
|
|
1007
1046
|
if (!isPlainRecord(value))
|
|
1008
1047
|
return undefined;
|
|
1009
1048
|
const allowedToolSelection = filterToolSelection(resolveToolSelection([Array.isArray(value.allowedTools) ? value.allowedTools : undefined], undefined));
|
|
1010
1049
|
const maxFindings = positiveInteger(recordValue(value.stateIndex, "maxFindings"));
|
|
1011
1050
|
const deprecatedRequiredFindingIds = stringArray(recordValue(value.stateIndex, "requiredFindingIds"));
|
|
1012
1051
|
return {
|
|
1013
|
-
planner: compileDynamicDecisionLoopProfile(value.planner,
|
|
1014
|
-
workerDefaults: compileDynamicDecisionLoopProfile(value.workerDefaults,
|
|
1015
|
-
verifier: compileDynamicDecisionLoopProfile(value.verifier,
|
|
1016
|
-
synthesis: compileDynamicDecisionLoopProfile(value.synthesis,
|
|
1052
|
+
planner: compileDynamicDecisionLoopProfile(value.planner, runtimePriority),
|
|
1053
|
+
workerDefaults: compileDynamicDecisionLoopProfile(value.workerDefaults, runtimePriority),
|
|
1054
|
+
verifier: compileDynamicDecisionLoopProfile(value.verifier, runtimePriority),
|
|
1055
|
+
synthesis: compileDynamicDecisionLoopProfile(value.synthesis, runtimePriority),
|
|
1017
1056
|
allowedAgents: stringArray(value.allowedAgents),
|
|
1018
1057
|
...(allowedToolSelection.tools
|
|
1019
1058
|
? { allowedTools: allowedToolSelection.tools }
|
|
@@ -1054,22 +1093,16 @@ function compileDynamicDecisionLoop(value, defaultModel, defaultThinking) {
|
|
|
1054
1093
|
},
|
|
1055
1094
|
};
|
|
1056
1095
|
}
|
|
1057
|
-
function compileDynamicDecisionLoopProfile(value,
|
|
1096
|
+
function compileDynamicDecisionLoopProfile(value, runtimePriority) {
|
|
1058
1097
|
if (!isPlainRecord(value))
|
|
1059
1098
|
return undefined;
|
|
1060
1099
|
const toolSelection = filterToolSelection(resolveToolSelection([Array.isArray(value.tools) ? value.tools : undefined], undefined));
|
|
1061
|
-
const
|
|
1062
|
-
? value.model.trim()
|
|
1063
|
-
: defaultModel;
|
|
1064
|
-
const thinking = typeof value.thinking === "string" && value.thinking.trim()
|
|
1065
|
-
? value.thinking.trim()
|
|
1066
|
-
: defaultThinking;
|
|
1100
|
+
const runtime = selectWorkflowRuntime(runtimePriority.runtimeOverrides, runtimeSettings(value), runtimePriority.stageRuntime, runtimePriority.runtimeDefaults, runtimePriority.specRuntimeDefaults);
|
|
1067
1101
|
return {
|
|
1068
1102
|
...(typeof value.agent === "string" && value.agent.trim()
|
|
1069
1103
|
? { agent: value.agent.trim() }
|
|
1070
1104
|
: {}),
|
|
1071
|
-
...
|
|
1072
|
-
...(thinking ? { thinking } : {}),
|
|
1105
|
+
...runtime,
|
|
1073
1106
|
...(toolSelection.tools ? { tools: toolSelection.tools } : {}),
|
|
1074
1107
|
...(toolSelection.toolProviders
|
|
1075
1108
|
? { toolProviders: toolSelection.toolProviders }
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CompiledDynamicWorkflowTask, CompiledTask, CompiledWorkflow, ThinkingLevel, WorkflowRunRecord, WorkflowTaskRunRecord } from "./types.js";
|
|
2
|
+
import { type WorkflowModelInfo } from "./workflow-runtime.js";
|
|
2
3
|
export interface DynamicArtifactInput {
|
|
3
4
|
kind: "workflow-artifact-ref";
|
|
4
5
|
name: string;
|
|
@@ -41,6 +42,7 @@ export declare function buildDynamicGeneratedCompiledTask(input: {
|
|
|
41
42
|
branchId?: string;
|
|
42
43
|
request: DynamicAgentRequest;
|
|
43
44
|
dynamic: CompiledDynamicWorkflowTask;
|
|
45
|
+
availableModels?: WorkflowModelInfo[];
|
|
44
46
|
}): Promise<CompiledTask>;
|
|
45
47
|
export declare function isDynamicCompiledTaskPayload(value: unknown): value is CompiledTask;
|
|
46
48
|
export declare function assertDynamicGeneratedMetadataMatches(compiledTask: CompiledTask, expected: {
|
|
@@ -6,6 +6,7 @@ import { readOrRebuildDynamicState } from "./dynamic-state.js";
|
|
|
6
6
|
import { sanitizeTaskId } from "./engine-run-graph.js";
|
|
7
7
|
import { fromProjectPath, isTerminalTaskStatus, readJson } from "./store.js";
|
|
8
8
|
import { classifyToolCapability, effectiveToolClassification, providersForSelectedTools, toolAllowedByAuthorityCeiling, } from "./tool-metadata.js";
|
|
9
|
+
import { resolveWorkflowRuntime, selectWorkflowRuntime, } from "./workflow-runtime.js";
|
|
9
10
|
const DYNAMIC_OUTPUT_MAX_DIGEST_CHARS = 1000;
|
|
10
11
|
const DYNAMIC_DELEGATION_TOOLS = new Set([
|
|
11
12
|
"skill_test_subagent",
|
|
@@ -69,6 +70,13 @@ export async function buildDynamicGeneratedCompiledTask(input) {
|
|
|
69
70
|
}
|
|
70
71
|
const toolProviders = executionProfile?.toolProviders ??
|
|
71
72
|
providersForSelectedTools(tools, new Map(Object.entries(input.controllerCompiledTask.runtime.toolProviders ?? {})));
|
|
73
|
+
const selectedRuntime = selectWorkflowRuntime(input.dynamic.runtimeOverrides, runtimeSettings(input.request), runtimeSettings(executionProfile), runtimeSettings(input.controllerCompiledTask.runtime), runtimeSettings(agentDefinition));
|
|
74
|
+
const resolvedRuntime = await resolveWorkflowRuntime(selectedRuntime, {
|
|
75
|
+
taskKey: input.generatedSpecId,
|
|
76
|
+
stageId: input.controllerStageId,
|
|
77
|
+
taskId: input.request.id,
|
|
78
|
+
agent: requestedAgent,
|
|
79
|
+
}, { availableModels: input.availableModels ?? input.dynamic.availableModels });
|
|
72
80
|
const unknownTools = (tools ?? []).filter((tool) => effectiveToolClassification(tool, toolProviders) === undefined);
|
|
73
81
|
if (unknownTools.length > 0) {
|
|
74
82
|
throw new Error(`dynamic agent requested tools without trusted classification metadata: ${unknownTools.join(", ")}`);
|
|
@@ -135,14 +143,7 @@ export async function buildDynamicGeneratedCompiledTask(input) {
|
|
|
135
143
|
explicitWorktreePolicy: requiresWorktree,
|
|
136
144
|
runtime: {
|
|
137
145
|
approvalMode: "non-interactive",
|
|
138
|
-
|
|
139
|
-
executionProfile?.model ??
|
|
140
|
-
input.controllerCompiledTask.runtime.model ??
|
|
141
|
-
agentDefinition.model,
|
|
142
|
-
thinking: input.request.thinking ??
|
|
143
|
-
executionProfile?.thinking ??
|
|
144
|
-
input.controllerCompiledTask.runtime.thinking ??
|
|
145
|
-
agentDefinition.thinking,
|
|
146
|
+
...resolvedRuntime,
|
|
146
147
|
tools,
|
|
147
148
|
...(toolProviders ? { toolProviders } : {}),
|
|
148
149
|
maxRuntimeMs: input.request.maxRuntimeMs ??
|
|
@@ -461,6 +462,18 @@ function requiredDynamicString(value, field, api = "ctx.agent()") {
|
|
|
461
462
|
}
|
|
462
463
|
return value.trim();
|
|
463
464
|
}
|
|
465
|
+
function runtimeSettings(value) {
|
|
466
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
467
|
+
return undefined;
|
|
468
|
+
const record = value;
|
|
469
|
+
const model = typeof record.model === "string" && record.model.trim()
|
|
470
|
+
? record.model.trim()
|
|
471
|
+
: undefined;
|
|
472
|
+
const thinking = typeof record.thinking === "string" && record.thinking.trim()
|
|
473
|
+
? record.thinking.trim()
|
|
474
|
+
: undefined;
|
|
475
|
+
return model || thinking ? { model, thinking } : undefined;
|
|
476
|
+
}
|
|
464
477
|
function optionalDynamicString(value, field) {
|
|
465
478
|
if (value === undefined)
|
|
466
479
|
return undefined;
|
package/dist/engine.d.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import { type WorkflowModelInfo } from "./workflow-runtime.js";
|
|
1
|
+
import { type WorkflowModelInfo, type WorkflowRuntimeDefaults } from "./workflow-runtime.js";
|
|
2
2
|
import { type DynamicWorkflowUi } from "./dynamic-controller-policy.js";
|
|
3
|
-
import { type CompiledWorkflow, type
|
|
3
|
+
import { type CompiledWorkflow, type WorkflowRunRecord } from "./types.js";
|
|
4
4
|
export { buildRunSourceContext } from "./workflow-source-context-runtime.js";
|
|
5
5
|
export { evaluateLoopUntilCondition } from "./loop-runtime.js";
|
|
6
6
|
export type { DynamicWorkflowUi } from "./dynamic-controller-policy.js";
|
|
7
7
|
export interface WorkflowRunOptions {
|
|
8
8
|
task?: string;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
thinking?: ThinkingLevel;
|
|
12
|
-
};
|
|
9
|
+
runtimeOverrides?: WorkflowRuntimeDefaults;
|
|
10
|
+
runtimeDefaults?: WorkflowRuntimeDefaults;
|
|
13
11
|
availableModels?: WorkflowModelInfo[];
|
|
14
12
|
dynamicUi?: DynamicWorkflowUi;
|
|
15
13
|
runId?: string;
|
|
@@ -17,6 +15,7 @@ export interface WorkflowRunOptions {
|
|
|
17
15
|
}
|
|
18
16
|
interface WorkflowScheduleOptions {
|
|
19
17
|
dynamicUi?: DynamicWorkflowUi;
|
|
18
|
+
availableModels?: WorkflowModelInfo[];
|
|
20
19
|
}
|
|
21
20
|
export declare function runWorkflowSpec(specPath: string, cwd: string, options?: WorkflowRunOptions): Promise<WorkflowRunRecord>;
|
|
22
21
|
export declare function runDynamicTask(cwd: string, options?: WorkflowRunOptions): Promise<WorkflowRunRecord>;
|
package/dist/engine.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
1
|
+
import { appendFile, mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, extname, join, resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
4
|
import { Worker } from "node:worker_threads";
|
|
5
5
|
import { compileWorkflow } from "./compiler.js";
|
|
6
6
|
import { loadWorkflowSpec } from "./schema.js";
|
|
7
|
-
import { createRunRecord, createTaskRunRecord, compiledWorkflowPath, fromProjectPath, indexSupervisorErrorPath, isTerminalWorkflowStatus, isTerminalTaskStatus, listRunRecords, readIndex, readJson, readRunRecord, resetTaskForResume, setTaskTerminal, supervisorPath, toProjectPath, updateIndex, withRunLease, writeJsonAtomic, writeRunRecord, writeCompiledRunArtifact, writeStaticRunArtifacts, } from "./store.js";
|
|
7
|
+
import { createRunRecord, createTaskRunRecord, compiledWorkflowPath, fromProjectPath, indexSupervisorErrorPath, isTerminalWorkflowStatus, isTerminalTaskStatus, listRunRecords, readIndex, readJson, readRunRecord, resetTaskForResume, setTaskTerminal, supervisorPath, toProjectPath, updateIndex, withRunLease, workflowRunPath, writeJsonAtomic, writeRunRecord, writeCompiledRunArtifact, writeStaticRunArtifacts, } from "./store.js";
|
|
8
8
|
import { resolveWorkflowBackend } from "./backend.js";
|
|
9
9
|
import { ensureManagedWorktree } from "./worktree.js";
|
|
10
10
|
import { resolveWorkflowHelperRef } from "./workflow-helpers.js";
|
|
@@ -21,7 +21,6 @@ import { normalizeDynamicFanoutPlanRequest, runDynamicDecisionLoopStatusPersistC
|
|
|
21
21
|
import { assertRunTaskPositionalAlignment, buildForeachGeneratedTasks, dependenciesReady, markDagDependentsSkipped, nextTaskRecordIndex, reconcileDynamicGeneratedRunRecords, recoverStaleRunningDynamicControllers, replaceDependencyList, sourceStageIdsForFrom, stageSourcePolicy, updateDownstreamDependencies, } from "./engine-run-graph.js";
|
|
22
22
|
import { reconcileLoopTaskMaterialization, scheduleLoop, } from "./loop-runtime.js";
|
|
23
23
|
import { executeSupportTask, normalizeDynamicControllerOutput, prepareArtifactGraphRetryTask, prepareDagTask, readArtifactGraphControl, readArtifactGraphSupportSources, readSupportSources, writeArtifactGraphDynamicResult, } from "./artifact-graph-runtime.js";
|
|
24
|
-
import { isDynamicOutputProfile, } from "./dynamic-profiles.js";
|
|
25
24
|
import { DIRECT_DYNAMIC_RUNTIME_VERSION, ensureDirectDynamicRuntimeBundle, } from "./dynamic-runtime-bundle.js";
|
|
26
25
|
import { WORKFLOW_RUN_TYPE, } from "./types.js";
|
|
27
26
|
export { buildRunSourceContext } from "./workflow-source-context-runtime.js";
|
|
@@ -37,6 +36,7 @@ const DYNAMIC_CONTROLLER_ENGINE_CAPABILITIES = Object.freeze({
|
|
|
37
36
|
});
|
|
38
37
|
const DYNAMIC_CONTROLLER_ENGINE_INTEGRITY_ERROR_MESSAGE = "incompatible or stale pi-workflow engine: dynamic controller context is missing runDecisionLoop (rebuild dist / reload workflow engine)";
|
|
39
38
|
const supervisorTimers = new Map();
|
|
39
|
+
const supervisorRunMtimes = new Map();
|
|
40
40
|
export async function runWorkflowSpec(specPath, cwd, options = {}) {
|
|
41
41
|
const loaded = await loadWorkflowSpec(specPath, cwd);
|
|
42
42
|
return runLoadedWorkflowSpec(cwd, loaded.specPath, loaded.spec, options);
|
|
@@ -62,6 +62,7 @@ async function runLoadedWorkflowSpec(cwd, specPath, spec, options, provenance) {
|
|
|
62
62
|
cwd,
|
|
63
63
|
specPath,
|
|
64
64
|
task: options.task,
|
|
65
|
+
runtimeOverrides: options.runtimeOverrides,
|
|
65
66
|
runtimeDefaults: options.runtimeDefaults,
|
|
66
67
|
availableModels: options.availableModels,
|
|
67
68
|
});
|
|
@@ -76,11 +77,14 @@ async function runLoadedWorkflowSpec(cwd, specPath, spec, options, provenance) {
|
|
|
76
77
|
await writeStaticRunArtifacts(cwd, run, compiled, spec);
|
|
77
78
|
await writeRunRecord(cwd, run);
|
|
78
79
|
});
|
|
79
|
-
const
|
|
80
|
+
const scheduleOptions = {
|
|
80
81
|
dynamicUi: options.dynamicUi,
|
|
81
|
-
|
|
82
|
+
availableModels: options.availableModels,
|
|
83
|
+
};
|
|
84
|
+
const scheduled = (await scheduleRun(cwd, run.runId, compiled, scheduleOptions)) ??
|
|
85
|
+
(await readRunRecord(cwd, run.runId));
|
|
82
86
|
if (scheduled.status === "running")
|
|
83
|
-
watchRun(cwd, scheduled.runId,
|
|
87
|
+
watchRun(cwd, scheduled.runId, scheduleOptions);
|
|
84
88
|
return scheduled;
|
|
85
89
|
}
|
|
86
90
|
export async function refreshRun(cwd, runIdOrPrefix) {
|
|
@@ -168,15 +172,26 @@ export function watchRun(cwd, runId, options = {}) {
|
|
|
168
172
|
return;
|
|
169
173
|
const timer = setInterval(() => {
|
|
170
174
|
void (async () => {
|
|
175
|
+
const previousMtime = supervisorRunMtimes.get(key);
|
|
176
|
+
const beforeMtime = await readRunMtimeMs(cwd, runId);
|
|
171
177
|
const refreshed = await refreshRun(cwd, runId);
|
|
178
|
+
const afterMtime = await readRunMtimeMs(cwd, runId);
|
|
179
|
+
const currentMtime = afterMtime ?? beforeMtime;
|
|
180
|
+
if (currentMtime !== undefined)
|
|
181
|
+
supervisorRunMtimes.set(key, currentMtime);
|
|
172
182
|
if (refreshed.status === "running") {
|
|
173
|
-
|
|
183
|
+
const unchanged = previousMtime !== undefined &&
|
|
184
|
+
currentMtime !== undefined &&
|
|
185
|
+
currentMtime <= previousMtime;
|
|
186
|
+
if (!unchanged)
|
|
187
|
+
await scheduleRun(cwd, runId, undefined, options);
|
|
174
188
|
return;
|
|
175
189
|
}
|
|
176
190
|
const existing = supervisorTimers.get(key);
|
|
177
191
|
if (existing)
|
|
178
192
|
clearInterval(existing);
|
|
179
193
|
supervisorTimers.delete(key);
|
|
194
|
+
supervisorRunMtimes.delete(key);
|
|
180
195
|
})().catch((error) => {
|
|
181
196
|
void recordSupervisorError(cwd, runId, error);
|
|
182
197
|
});
|
|
@@ -184,6 +199,16 @@ export function watchRun(cwd, runId, options = {}) {
|
|
|
184
199
|
timer.unref?.();
|
|
185
200
|
supervisorTimers.set(key, timer);
|
|
186
201
|
}
|
|
202
|
+
async function readRunMtimeMs(cwd, runId) {
|
|
203
|
+
try {
|
|
204
|
+
return (await stat(workflowRunPath(cwd, runId))).mtimeMs;
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
if (error.code === "ENOENT")
|
|
208
|
+
return undefined;
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
187
212
|
export async function scheduleRun(cwd, runId, compiled, options = {}) {
|
|
188
213
|
return withRunLease(cwd, runId, async () => {
|
|
189
214
|
let run = await readRunRecord(cwd, runId);
|
|
@@ -630,6 +655,7 @@ async function executeDynamicControllerTask(cwd, run, compiledFlow, controllerIn
|
|
|
630
655
|
sources,
|
|
631
656
|
dynamic: compiledTask.dynamic,
|
|
632
657
|
dynamicUi: options.dynamicUi,
|
|
658
|
+
availableModels: options.availableModels,
|
|
633
659
|
});
|
|
634
660
|
await assertDynamicGeneratedTasksSettled({
|
|
635
661
|
cwd,
|
|
@@ -639,6 +665,7 @@ async function executeDynamicControllerTask(cwd, run, compiledFlow, controllerIn
|
|
|
639
665
|
controllerTask: task,
|
|
640
666
|
controllerCompiledTask: compiledTask,
|
|
641
667
|
dynamic: compiledTask.dynamic,
|
|
668
|
+
availableModels: options.availableModels,
|
|
642
669
|
});
|
|
643
670
|
await recordActiveRuntime();
|
|
644
671
|
const unrunBranchBlockers = await dynamicUnrunBranchBlockers(cwd, run.runId, task.specId);
|
|
@@ -1171,57 +1198,12 @@ function requiredDynamicString(value, field, api = "ctx.agent()") {
|
|
|
1171
1198
|
}
|
|
1172
1199
|
return value.trim();
|
|
1173
1200
|
}
|
|
1174
|
-
function optionalDynamicString(value, field) {
|
|
1175
|
-
if (value === undefined)
|
|
1176
|
-
return undefined;
|
|
1177
|
-
return requiredDynamicString(value, field);
|
|
1178
|
-
}
|
|
1179
|
-
function optionalDynamicStringArray(value, field) {
|
|
1180
|
-
if (value === undefined)
|
|
1181
|
-
return undefined;
|
|
1182
|
-
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
1183
|
-
throw new Error(`ctx.agent() ${field} must be an array of strings`);
|
|
1184
|
-
}
|
|
1185
|
-
return value.map((item) => item.trim()).filter(Boolean);
|
|
1186
|
-
}
|
|
1187
|
-
function isPlainDynamicRecord(value) {
|
|
1188
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1189
|
-
}
|
|
1190
|
-
function optionalDynamicPositiveInteger(value, field) {
|
|
1191
|
-
if (value === undefined)
|
|
1192
|
-
return undefined;
|
|
1193
|
-
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
1194
|
-
throw new Error(`ctx.agent() ${field} must be a positive integer`);
|
|
1195
|
-
}
|
|
1196
|
-
return value;
|
|
1197
|
-
}
|
|
1198
|
-
function requiredDynamicOutputProfile(value, field, api) {
|
|
1199
|
-
const profile = requiredDynamicString(value, field, api);
|
|
1200
|
-
if (!isDynamicOutputProfile(profile)) {
|
|
1201
|
-
throw new Error(`${api} ${field} has an unsupported output profile`);
|
|
1202
|
-
}
|
|
1203
|
-
return profile;
|
|
1204
|
-
}
|
|
1205
|
-
function requiredDynamicNonNegativeInteger(value, field, api) {
|
|
1206
|
-
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
1207
|
-
throw new Error(`${api} ${field} must be a non-negative integer`);
|
|
1208
|
-
}
|
|
1209
|
-
return value;
|
|
1210
|
-
}
|
|
1211
1201
|
function requiredDynamicPositiveInteger(value, field, api) {
|
|
1212
1202
|
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
1213
1203
|
throw new Error(`${api} ${field} must be a positive integer`);
|
|
1214
1204
|
}
|
|
1215
1205
|
return value;
|
|
1216
1206
|
}
|
|
1217
|
-
function optionalDynamicStringField(value) {
|
|
1218
|
-
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
1219
|
-
}
|
|
1220
|
-
function optionalDynamicOutputProfile(value) {
|
|
1221
|
-
if (value === undefined)
|
|
1222
|
-
return undefined;
|
|
1223
|
-
return requiredDynamicOutputProfile(value, "outputProfile", "ctx.agent()");
|
|
1224
|
-
}
|
|
1225
1207
|
async function currentDynamicBudgetRemaining(input) {
|
|
1226
1208
|
const state = await readOrRebuildDynamicState(input.cwd, input.run.runId);
|
|
1227
1209
|
const run = await readRunRecord(input.cwd, input.run.runId).catch(() => input.run);
|
|
@@ -1540,6 +1522,7 @@ async function repairMissingDynamicGeneratedTask(input, specId) {
|
|
|
1540
1522
|
branchId: optionalEventString(event.payload.branchId),
|
|
1541
1523
|
request,
|
|
1542
1524
|
dynamic: input.dynamic,
|
|
1525
|
+
availableModels: input.availableModels,
|
|
1543
1526
|
});
|
|
1544
1527
|
assertDynamicGeneratedMetadataMatches(compiledTask, {
|
|
1545
1528
|
controllerSpecId: input.controllerTask.specId,
|
|
@@ -1635,6 +1618,7 @@ async function runDynamicAgentRequest(input) {
|
|
|
1635
1618
|
branchId: generationBranchId,
|
|
1636
1619
|
request: generationRequest,
|
|
1637
1620
|
dynamic: input.dynamic,
|
|
1621
|
+
availableModels: input.availableModels,
|
|
1638
1622
|
});
|
|
1639
1623
|
assertDynamicGeneratedMetadataMatches(compiledTask, {
|
|
1640
1624
|
controllerSpecId: input.controllerTask.specId,
|
package/dist/extension.js
CHANGED
|
@@ -13,7 +13,7 @@ import { fromProjectPath, readIndex, readRunRecord } from "./store.js";
|
|
|
13
13
|
import { loadWorkflowSpec } from "./schema.js";
|
|
14
14
|
import { listWorkflows, resolveWorkflowRef } from "./workflow-specs.js";
|
|
15
15
|
import { WorkflowValidationError, } from "./types.js";
|
|
16
|
-
import { toWorkflowModelInfo } from "./workflow-runtime.js";
|
|
16
|
+
import { toWorkflowModelInfo, } from "./workflow-runtime.js";
|
|
17
17
|
const UNFINISHED_RUN_NOTICE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
18
18
|
const UNFINISHED_RUN_NOTICE_MAX_RUNS = 5;
|
|
19
19
|
const UNFINISHED_RUN_NOTICE_DEDUPE_MS = 6 * 60 * 60 * 1000;
|
|
@@ -442,8 +442,8 @@ function parseWorkflowDynamicToolParams(params) {
|
|
|
442
442
|
const model = optionalStringParam(params, "model", "workflow_dynamic")?.trim();
|
|
443
443
|
const rawThinking = optionalStringParam(params, "thinking", "workflow_dynamic")?.trim();
|
|
444
444
|
const thinking = rawThinking ? parseThinkingLevel(rawThinking) : undefined;
|
|
445
|
-
const
|
|
446
|
-
return { task, detach: detachValue === true,
|
|
445
|
+
const runtimeOverrides = model || thinking ? { model: model || undefined, thinking } : undefined;
|
|
446
|
+
return { task, detach: detachValue === true, runtimeOverrides };
|
|
447
447
|
}
|
|
448
448
|
function stringParam(params, key, toolName) {
|
|
449
449
|
const value = params[key];
|
|
@@ -521,7 +521,8 @@ async function startWorkflowRunFromRequest(request, ctx, api) {
|
|
|
521
521
|
throw new Error('This workflow needs a task. Usage: /workflow run <workflow-name-or-path> "<task>"');
|
|
522
522
|
const run = await runWorkflowSpec(workflow, ctx.cwd, {
|
|
523
523
|
task,
|
|
524
|
-
|
|
524
|
+
runtimeOverrides: request.runtimeOverrides,
|
|
525
|
+
runtimeDefaults: currentRuntimeDefaults(ctx, api),
|
|
525
526
|
availableModels: availableWorkflowModels(ctx),
|
|
526
527
|
dynamicUi: dynamicUiFromContext(ctx),
|
|
527
528
|
});
|
|
@@ -544,7 +545,8 @@ async function startDynamicRunFromRequest(request, ctx, api) {
|
|
|
544
545
|
throw new Error('This dynamic workflow needs a task. Usage: /workflow dynamic "<task>"');
|
|
545
546
|
const run = await runDynamicTask(ctx.cwd, {
|
|
546
547
|
task,
|
|
547
|
-
|
|
548
|
+
runtimeOverrides: request.runtimeOverrides,
|
|
549
|
+
runtimeDefaults: currentRuntimeDefaults(ctx, api),
|
|
548
550
|
availableModels: availableWorkflowModels(ctx),
|
|
549
551
|
dynamicUi: dynamicUiFromContext(ctx),
|
|
550
552
|
});
|
|
@@ -763,27 +765,27 @@ async function handleWorkflowCommand(args, ctx, api) {
|
|
|
763
765
|
const parsed = parseWorkflowRunArgs(args);
|
|
764
766
|
const specPath = parsed.specPath ||
|
|
765
767
|
requireArg(tokens, 1, '/workflow run <workflow-name-or-path> "<task>"');
|
|
766
|
-
const
|
|
768
|
+
const runtimeOverrides = parsed.model || parsed.thinking
|
|
767
769
|
? { model: parsed.model, thinking: parsed.thinking }
|
|
768
770
|
: undefined;
|
|
769
771
|
const result = await startWorkflowRunFromRequest({
|
|
770
772
|
workflow: specPath,
|
|
771
773
|
task: parsed.task,
|
|
772
774
|
detach: parsed.detach,
|
|
773
|
-
|
|
775
|
+
runtimeOverrides,
|
|
774
776
|
}, ctx, api);
|
|
775
777
|
emitRunStartResult(ctx, result.run.status, result.text);
|
|
776
778
|
return;
|
|
777
779
|
}
|
|
778
780
|
if (action === "dynamic") {
|
|
779
781
|
const parsed = parseWorkflowDynamicArgs(args);
|
|
780
|
-
const
|
|
782
|
+
const runtimeOverrides = parsed.model || parsed.thinking
|
|
781
783
|
? { model: parsed.model, thinking: parsed.thinking }
|
|
782
784
|
: undefined;
|
|
783
785
|
const result = await startDynamicRunFromRequest({
|
|
784
786
|
task: parsed.task,
|
|
785
787
|
detach: parsed.detach,
|
|
786
|
-
|
|
788
|
+
runtimeOverrides,
|
|
787
789
|
}, ctx, api);
|
|
788
790
|
emitRunStartResult(ctx, result.run.status, result.text);
|
|
789
791
|
return;
|
package/dist/store.d.ts
CHANGED
|
@@ -25,13 +25,15 @@ export declare function createRunRecord(cwd: string, compiled: CompiledWorkflow,
|
|
|
25
25
|
runDir: string;
|
|
26
26
|
}>;
|
|
27
27
|
export declare function writeRunRecord(cwd: string, run: WorkflowRunRecord): Promise<void>;
|
|
28
|
+
export declare function flushPendingIndexUpdatesForTests(): Promise<void>;
|
|
29
|
+
export declare function setIndexUpdateDebounceMsForTests(value?: number): void;
|
|
28
30
|
export declare function writeCompiledRunArtifact(cwd: string, runId: string, compiled: CompiledWorkflow): Promise<void>;
|
|
29
31
|
export declare function writeStaticRunArtifacts(cwd: string, run: WorkflowRunRecord, compiled: CompiledWorkflow, originalSpec: unknown): Promise<void>;
|
|
30
32
|
export declare function findRunRecordPath(cwd: string, runIdOrPrefix: string): Promise<string | undefined>;
|
|
31
33
|
export declare function readRunRecord(cwd: string, runIdOrPrefix: string): Promise<WorkflowRunRecord>;
|
|
32
34
|
export declare function readIndex(cwd: string): Promise<WorkflowIndexRecord | undefined>;
|
|
33
35
|
export declare function listRunRecords(cwd: string): Promise<WorkflowRunRecord[]>;
|
|
34
|
-
export declare function updateIndex(cwd: string): Promise<WorkflowIndexRecord>;
|
|
36
|
+
export declare function updateIndex(cwd: string, changedRunId?: string): Promise<WorkflowIndexRecord>;
|
|
35
37
|
export declare function deriveRunStatus(run: WorkflowRunRecord): WorkflowRunRecord;
|
|
36
38
|
export declare function summarizeTasks(tasks: WorkflowTaskRunRecord[]): TaskSummary;
|
|
37
39
|
export declare function deriveWorkflowStatus(summary: TaskSummary): WorkflowRunStatus;
|