stageflow 0.13.0 → 0.16.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/dist/agent/activity.d.ts +3 -0
- package/dist/agent/claudeAdapter.js +84 -7
- package/dist/agent/claudeSession.d.ts +3 -0
- package/dist/agent/piAdapter.d.ts +2 -0
- package/dist/agent/piAdapter.js +34 -7
- package/dist/agent/port.d.ts +5 -2
- package/dist/cli/initTemplates.d.ts +1 -1
- package/dist/cli/initTemplates.js +1 -1
- package/dist/cli/migrateYamlCommand.d.ts +18 -0
- package/dist/cli/migrateYamlCommand.js +180 -0
- package/dist/cli/runOutput.js +58 -26
- package/dist/cli/validateCommand.d.ts +1 -0
- package/dist/cli/validateCommand.js +2 -0
- package/dist/cli.js +15 -1
- package/dist/config/browseCatalog.js +1 -1
- package/dist/config/createPipeline.d.ts +1 -1
- package/dist/config/createPipeline.js +23 -11
- package/dist/config/createStage.d.ts +1 -1
- package/dist/config/createStage.js +10 -5
- package/dist/config/legacyYaml.d.ts +28 -0
- package/dist/config/legacyYaml.js +98 -0
- package/dist/config/loadOutcome.d.ts +2 -1
- package/dist/config/loadOutcome.js +4 -1
- package/dist/config/loadPipeline.d.ts +2 -0
- package/dist/config/loadPipeline.js +150 -8
- package/dist/config/loadStage.d.ts +8 -1
- package/dist/config/loadStage.js +138 -29
- package/dist/config/loadStageflowManifest.js +10 -0
- package/dist/config/loadTask.js +14 -0
- package/dist/config/materializeStageModels.d.ts +7 -0
- package/dist/config/materializeStageModels.js +35 -0
- package/dist/config/mergePipelineIncludes.d.ts +5 -1
- package/dist/config/mergePipelineIncludes.js +82 -4
- package/dist/config/migrateYaml.d.ts +19 -0
- package/dist/config/migrateYaml.js +627 -0
- package/dist/config/modelField.d.ts +13 -0
- package/dist/config/modelField.js +16 -0
- package/dist/config/normalizePipelineStageEntry.js +41 -2
- package/dist/config/parseCompletionContract.d.ts +5 -2
- package/dist/config/parseCompletionContract.js +16 -3
- package/dist/config/parsePreEmitChecks.js +4 -0
- package/dist/config/pipelineNeeds.js +3 -3
- package/dist/config/pipelineStageKeys.d.ts +11 -0
- package/dist/config/pipelineStageKeys.js +14 -0
- package/dist/config/printTargetYaml.d.ts +28 -0
- package/dist/config/printTargetYaml.js +243 -0
- package/dist/config/resolveModel.d.ts +20 -0
- package/dist/config/resolveModel.js +35 -0
- package/dist/config/validateCatalog.d.ts +5 -1
- package/dist/config/validateCatalog.js +36 -6
- package/dist/config/validateCompletionContract.js +5 -0
- package/dist/config/yamlDialect.d.ts +29 -0
- package/dist/config/yamlDialect.js +327 -0
- package/dist/envelope/payloadSchema.d.ts +37 -5
- package/dist/envelope/payloadSchema.js +272 -22
- package/dist/mcp/catalogTools.js +1 -0
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/runstore/pipelineDagSnapshot.js +2 -0
- package/dist/runstore/port.d.ts +11 -0
- package/dist/runstore/runProjection.js +9 -0
- package/dist/runstore/sqlite/SqliteRunStore.js +27 -4
- package/dist/runstore/sqlite/schema.d.ts +1 -1
- package/dist/runstore/sqlite/schema.js +2 -0
- package/dist/runstore/stageExecution.d.ts +3 -0
- package/dist/runstore/stageExecution.js +6 -2
- package/dist/runstore/stageSnapshot.js +11 -0
- package/dist/runtime/completionCheckRunner.d.ts +3 -2
- package/dist/runtime/completionCheckRunner.js +3 -2
- package/dist/runtime/envelopeRouting.d.ts +2 -2
- package/dist/runtime/pipelineRunner.d.ts +3 -0
- package/dist/runtime/pipelineRunner.js +23 -3
- package/dist/runtime/runManager.js +3 -2
- package/dist/runtime/stageAttemptBootstrap.d.ts +2 -2
- package/dist/runtime/stageRunner.d.ts +2 -2
- package/dist/runtime/stageRunner.js +2 -2
- package/dist/runtime/taskInput.d.ts +7 -0
- package/dist/runtime/taskInput.js +60 -0
- package/dist/runtime/verifiedStageExecution.js +3 -0
- package/dist/types/completion.d.ts +6 -0
- package/dist/types/pipeline.d.ts +21 -2
- package/dist/types/preEmitCheck.d.ts +4 -6
- package/dist/types/stage.d.ts +22 -3
- package/dist/types/stageflowManifest.d.ts +2 -0
- package/dist/types/task.d.ts +1 -0
- package/dist/types/usage.d.ts +16 -0
- package/dist/types/usage.js +24 -0
- package/dist/ui/assets/{index-uVHiae8s.css → index-D2Wt8hwH.css} +1 -1
- package/dist/ui/assets/index-XWJovnp7.js +118 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/skills/stageflow-author/SKILL.md +7 -7
- package/skills/stageflow-author/assets/examples/branch-decision/hotfix.yaml +9 -1
- package/skills/stageflow-author/assets/examples/branch-decision/release-gate.pipeline.yaml +6 -2
- package/skills/stageflow-author/assets/examples/branch-decision/run-tests.yaml +9 -1
- package/skills/stageflow-author/assets/examples/branch-decision/ship.yaml +16 -1
- package/skills/stageflow-author/assets/examples/linear-review/draft.yaml +12 -2
- package/skills/stageflow-author/assets/examples/linear-review/publish.yaml +16 -1
- package/skills/stageflow-author/assets/examples/linear-review/review-loop.pipeline.yaml +11 -2
- package/skills/stageflow-author/assets/examples/linear-review/review.yaml +19 -1
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/gather.yaml +9 -1
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/research-digest.pipeline.yaml +6 -2
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/send.yaml +16 -1
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/summarize.yaml +9 -1
- package/skills/stageflow-author/references/catalog-mapping.md +30 -28
- package/skills/stageflow-author/references/catalog-write-conventions.md +2 -2
- package/skills/stageflow-author/references/stage-prompt-template.md +5 -5
- package/skills/stageflow-session-capture/SKILL.md +1 -1
- package/skills/stageflow-session-capture/assets/example-pipeline/example.pipeline.yaml +2 -1
- package/skills/stageflow-session-capture/assets/example-pipeline/implement.yaml +13 -2
- package/skills/stageflow-session-capture/assets/example-pipeline/research.yaml +18 -2
- package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -2
- package/dist/ui/assets/index-Yzh42vhf.js +0 -118
|
@@ -131,7 +131,8 @@ export type CompletionVerificationResult = {
|
|
|
131
131
|
/** Default Node implementation; callers may substitute a sandboxed executor. */
|
|
132
132
|
export declare const nodeCommandExecutor: CommandExecutor;
|
|
133
133
|
/**
|
|
134
|
-
* Run every
|
|
135
|
-
* or prevents later checks from producing their own
|
|
134
|
+
* Run every after-phase IR check in declaration order. YAML: `verify` when after.
|
|
135
|
+
* A failed check never throws or prevents later checks from producing their own
|
|
136
|
+
* repair evidence.
|
|
136
137
|
*/
|
|
137
138
|
export declare function runCompletionContract(input: CompletionCheckRunnerInput): Promise<CompletionVerificationResult>;
|
|
@@ -343,8 +343,9 @@ async function runCheck(check, input) {
|
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
/**
|
|
346
|
-
* Run every
|
|
347
|
-
* or prevents later checks from producing their own
|
|
346
|
+
* Run every after-phase IR check in declaration order. YAML: `verify` when after.
|
|
347
|
+
* A failed check never throws or prevents later checks from producing their own
|
|
348
|
+
* repair evidence.
|
|
348
349
|
*/
|
|
349
350
|
export async function runCompletionContract(input) {
|
|
350
351
|
const checks = [];
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { RunStore, StageSnapshot } from "../runstore/port.js";
|
|
2
2
|
import type { StageEnvelope, TerminalEnvelope } from "../types/envelope.js";
|
|
3
3
|
import type { LoadedPipeline, ResolvedPipelineDag } from "../types/pipeline.js";
|
|
4
|
-
import type {
|
|
4
|
+
import type { LoadedStageConfig } from "../types/stage.js";
|
|
5
5
|
export declare function buildCompletedEnvelopesFromRun(store: RunStore, runId: string, stages?: StageSnapshot[], dag?: ResolvedPipelineDag): Promise<Map<string, StageEnvelope>>;
|
|
6
|
-
export declare function buildStageConfigById(loaded: LoadedPipeline): Map<string,
|
|
6
|
+
export declare function buildStageConfigById(loaded: LoadedPipeline): Map<string, LoadedStageConfig>;
|
|
7
7
|
export type ResolvePriorEnvelopeResult = {
|
|
8
8
|
ok: true;
|
|
9
9
|
prior: StageEnvelope | null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentPort } from "../agent/port.js";
|
|
2
|
+
import { type ValidationFinding } from "../config/validateCatalog.js";
|
|
2
3
|
import type { RunStore } from "../runstore/port.js";
|
|
3
4
|
import type { StageEnvelope } from "../types/envelope.js";
|
|
4
5
|
import type { StageHitlController } from "./stageHitl.js";
|
|
@@ -15,6 +16,7 @@ export type PipelineRunResult = {
|
|
|
15
16
|
runDir: string;
|
|
16
17
|
runId: string;
|
|
17
18
|
reason?: string;
|
|
19
|
+
findings?: ValidationFinding[];
|
|
18
20
|
};
|
|
19
21
|
export type StartedPipeline = {
|
|
20
22
|
runId: string;
|
|
@@ -38,6 +40,7 @@ export type PreparedPipeline = {
|
|
|
38
40
|
stageProcessLauncher?: StageProcessLauncher;
|
|
39
41
|
operatorCatalog?: OperatorCatalog;
|
|
40
42
|
skipGates?: boolean;
|
|
43
|
+
findings?: ValidationFinding[];
|
|
41
44
|
};
|
|
42
45
|
export type ExecuteStagesOptions = {
|
|
43
46
|
maxActiveStagesPerRun?: number;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { loadPipelineValidated } from "../config/validateCatalog.js";
|
|
3
|
+
import { buildValidationResult, loadPipelineValidated, } from "../config/validateCatalog.js";
|
|
4
4
|
import { loadTaskFromYaml } from "../config/loadTask.js";
|
|
5
|
-
import { buildValidationResult } from "../config/validateCatalog.js";
|
|
6
5
|
import { resolveAndValidateCheckout } from "./stageRoots.js";
|
|
7
6
|
import { buildPipelineDagSnapshotFromLoaded } from "../runstore/pipelineDagSnapshot.js";
|
|
8
7
|
import { normalizeCatalogPath } from "../runstore/normalizeCatalogPath.js";
|
|
@@ -10,6 +9,7 @@ import { runPipelineDag } from "./pipelineScheduler.js";
|
|
|
10
9
|
import { readMaxActiveStagesPerRun, readStageExecutionMode, } from "./stageConcurrency.js";
|
|
11
10
|
import { StageProcessLauncher } from "./stageProcessLauncher.js";
|
|
12
11
|
import { PipelineValidationError } from "./pipelineValidationError.js";
|
|
12
|
+
import { checkTaskEntryInput } from "./taskInput.js";
|
|
13
13
|
export { PipelineValidationError } from "./pipelineValidationError.js";
|
|
14
14
|
let defaultStageProcessLauncher;
|
|
15
15
|
function resolveStageProcessLauncher(executionMode, override) {
|
|
@@ -27,6 +27,7 @@ function resolveStageProcessLauncher(executionMode, override) {
|
|
|
27
27
|
async function preparePipeline(options) {
|
|
28
28
|
const loadResult = await loadPipelineValidated(options.pipeline, {
|
|
29
29
|
cwd: options.cwd,
|
|
30
|
+
projectRoot: options.projectRoot ?? options.cwd,
|
|
30
31
|
validateStages: true,
|
|
31
32
|
});
|
|
32
33
|
if (!loadResult.ok) {
|
|
@@ -41,6 +42,20 @@ async function preparePipeline(options) {
|
|
|
41
42
|
})());
|
|
42
43
|
const label = options.taskPath ?? "task.yaml";
|
|
43
44
|
const task = loadTaskFromYaml(taskYaml, `task file ${label}`);
|
|
45
|
+
const pairing = checkTaskEntryInput(task, loaded, {
|
|
46
|
+
cwd: options.cwd,
|
|
47
|
+
taskPath: options.taskPath,
|
|
48
|
+
});
|
|
49
|
+
if (pairing.some((finding) => finding.severity === "error")) {
|
|
50
|
+
throw new PipelineValidationError(buildValidationResult("pipeline", pairing, false));
|
|
51
|
+
}
|
|
52
|
+
const warningFindings = [
|
|
53
|
+
...loadResult.findings.filter((finding) => finding.severity === "warning"),
|
|
54
|
+
...pairing.filter((finding) => finding.severity === "warning"),
|
|
55
|
+
];
|
|
56
|
+
for (const finding of warningFindings) {
|
|
57
|
+
console.error(`${finding.code}: ${finding.message}`);
|
|
58
|
+
}
|
|
44
59
|
const checkoutRoot = await resolveAndValidateCheckout(task, options.checkoutOverride, options.cwd);
|
|
45
60
|
const pipelinePath = normalizeCatalogPath(loaded.pipelinePath);
|
|
46
61
|
const taskPath = options.taskPath
|
|
@@ -76,6 +91,7 @@ async function preparePipeline(options) {
|
|
|
76
91
|
stageProcessLauncher,
|
|
77
92
|
operatorCatalog: options.operatorCatalog,
|
|
78
93
|
skipGates: options.skipGates,
|
|
94
|
+
...(warningFindings.length > 0 ? { findings: warningFindings } : {}),
|
|
79
95
|
};
|
|
80
96
|
}
|
|
81
97
|
export async function executeStages(prepared, options) {
|
|
@@ -84,7 +100,7 @@ export async function executeStages(prepared, options) {
|
|
|
84
100
|
prepared.executionMode ??
|
|
85
101
|
readStageExecutionMode(process.env);
|
|
86
102
|
const stageProcessLauncher = resolveStageProcessLauncher(executionMode, options?.stageProcessLauncher ?? prepared.stageProcessLauncher);
|
|
87
|
-
|
|
103
|
+
const result = await runPipelineDag({
|
|
88
104
|
prepared,
|
|
89
105
|
maxActiveStagesPerRun,
|
|
90
106
|
resumeFromStageId: options?.resumeFromStageId,
|
|
@@ -93,6 +109,10 @@ export async function executeStages(prepared, options) {
|
|
|
93
109
|
executionMode,
|
|
94
110
|
stageProcessLauncher,
|
|
95
111
|
});
|
|
112
|
+
if (prepared.findings !== undefined && prepared.findings.length > 0) {
|
|
113
|
+
return { ...result, findings: prepared.findings };
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
96
116
|
}
|
|
97
117
|
export async function runPipeline(options) {
|
|
98
118
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -383,7 +383,7 @@ export class RunManager {
|
|
|
383
383
|
gitSha: input.gitSha,
|
|
384
384
|
ciPrUrl: input.ciPrUrl,
|
|
385
385
|
ciJobUrl: input.ciJobUrl,
|
|
386
|
-
});
|
|
386
|
+
}, undefined, resolved.kind === "path" ? resolved.taskPath : undefined);
|
|
387
387
|
}
|
|
388
388
|
async rerun(runId) {
|
|
389
389
|
const cwd = this.options.cwd ?? process.cwd();
|
|
@@ -1061,7 +1061,7 @@ export class RunManager {
|
|
|
1061
1061
|
this.attachedWaiting.delete(`${runId}\0${stageId}`);
|
|
1062
1062
|
}
|
|
1063
1063
|
}
|
|
1064
|
-
async reserveAndStartPipeline(taskYaml, pipeline, taskLabel, cwd, checkoutOverride, skipGates, ciIdentity, projectRoot) {
|
|
1064
|
+
async reserveAndStartPipeline(taskYaml, pipeline, taskLabel, cwd, checkoutOverride, skipGates, ciIdentity, projectRoot, taskPath) {
|
|
1065
1065
|
let checkoutKey;
|
|
1066
1066
|
try {
|
|
1067
1067
|
const task = loadTaskFromYaml(taskYaml, taskLabel);
|
|
@@ -1086,6 +1086,7 @@ export class RunManager {
|
|
|
1086
1086
|
agent: this.options.agent,
|
|
1087
1087
|
store: this.options.store,
|
|
1088
1088
|
taskYaml,
|
|
1089
|
+
taskPath,
|
|
1089
1090
|
pipeline,
|
|
1090
1091
|
cwd,
|
|
1091
1092
|
projectRoot: projectRoot ?? this.projectRoot,
|
|
@@ -2,7 +2,7 @@ import type { AgentPort, FeedbackLoopContext, StageHandle, StageRunInput, StageS
|
|
|
2
2
|
import type { RunStore } from "../runstore/port.js";
|
|
3
3
|
import type { StageEnvelope } from "../types/envelope.js";
|
|
4
4
|
import type { ResolvedPipelineDag } from "../types/pipeline.js";
|
|
5
|
-
import type {
|
|
5
|
+
import type { LoadedStageConfig } from "../types/stage.js";
|
|
6
6
|
import type { TaskFile } from "../types/task.js";
|
|
7
7
|
import { type StageAttemptContext } from "./stageAttemptContext.js";
|
|
8
8
|
import { type StageRoots } from "./stageRoots.js";
|
|
@@ -14,7 +14,7 @@ export type StageAttemptOpenInput = {
|
|
|
14
14
|
agent: Pick<AgentPort, "openStage">;
|
|
15
15
|
store: RunStore;
|
|
16
16
|
runId: string;
|
|
17
|
-
stage:
|
|
17
|
+
stage: LoadedStageConfig;
|
|
18
18
|
task: TaskFile;
|
|
19
19
|
dag: ResolvedPipelineDag;
|
|
20
20
|
checkoutRoot?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentPort, FeedbackLoopContext, StageHandle, StageRunResult, StageSessionMode } from "../agent/port.js";
|
|
2
2
|
import type { StageEnvelope } from "../types/envelope.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { LoadedStageConfig } from "../types/stage.js";
|
|
4
4
|
import type { TaskFile } from "../types/task.js";
|
|
5
5
|
import type { RunStore } from "../runstore/port.js";
|
|
6
6
|
import type { ResolvedPipelineDag } from "../types/pipeline.js";
|
|
@@ -21,7 +21,7 @@ export type RunStageOptions = {
|
|
|
21
21
|
agent: AgentPort;
|
|
22
22
|
store: RunStore;
|
|
23
23
|
runId: string;
|
|
24
|
-
stage:
|
|
24
|
+
stage: LoadedStageConfig;
|
|
25
25
|
task: TaskFile;
|
|
26
26
|
dag?: ResolvedPipelineDag;
|
|
27
27
|
priorEnvelope?: StageEnvelope | null;
|
|
@@ -54,7 +54,7 @@ async function finalizeStageResult(options) {
|
|
|
54
54
|
store,
|
|
55
55
|
runId,
|
|
56
56
|
stageId,
|
|
57
|
-
event: { event: "failed", reason: result.reason },
|
|
57
|
+
event: { event: "failed", reason: result.reason, usage: result.usage },
|
|
58
58
|
attemptCtx,
|
|
59
59
|
});
|
|
60
60
|
console.error(`Stage ${stageId} failed: ${result.reason}`);
|
|
@@ -64,7 +64,7 @@ async function finalizeStageResult(options) {
|
|
|
64
64
|
store,
|
|
65
65
|
runId,
|
|
66
66
|
stageId,
|
|
67
|
-
event: { event: "succeeded" },
|
|
67
|
+
event: { event: "succeeded", usage: result.usage },
|
|
68
68
|
attemptCtx,
|
|
69
69
|
});
|
|
70
70
|
console.error(`Stage ${stageId} succeeded.`);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type ValidationFinding } from "../config/validateCatalog.js";
|
|
2
|
+
import type { LoadedPipeline } from "../types/pipeline.js";
|
|
1
3
|
import type { TaskFile } from "../types/task.js";
|
|
2
4
|
export type StartTaskInput = {
|
|
3
5
|
task?: string | TaskFile;
|
|
@@ -12,4 +14,9 @@ export type ResolvedTaskInput = {
|
|
|
12
14
|
};
|
|
13
15
|
export declare function isTaskFile(value: unknown): value is TaskFile;
|
|
14
16
|
export declare function taskFileToYaml(task: TaskFile): string;
|
|
17
|
+
/** Validate optional `task.input` against entry-stage IR `clone_input_schema` (YAML: `io.input.schema`). */
|
|
18
|
+
export declare function checkTaskEntryInput(task: TaskFile, loaded: LoadedPipeline, options: {
|
|
19
|
+
cwd: string;
|
|
20
|
+
taskPath?: string;
|
|
21
|
+
}): ValidationFinding[];
|
|
15
22
|
export declare function resolveStartTaskInput(input: StartTaskInput, cwd: string): ResolvedTaskInput;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { stringify as stringifyYaml } from "yaml";
|
|
2
3
|
import { parseTaskFile } from "../config/loadTask.js";
|
|
4
|
+
import { relPath } from "../config/validateCatalog.js";
|
|
5
|
+
import { payloadInstanceMismatch } from "../envelope/payloadSchema.js";
|
|
3
6
|
import { resolveTaskPath } from "./pipelineRunner.js";
|
|
4
7
|
export function isTaskFile(value) {
|
|
5
8
|
return parseTaskFile(value, "task").ok;
|
|
@@ -15,8 +18,65 @@ export function taskFileToYaml(task) {
|
|
|
15
18
|
doc.constraints = task.constraints;
|
|
16
19
|
if (task.checkout !== undefined)
|
|
17
20
|
doc.checkout = task.checkout;
|
|
21
|
+
if (task.input !== undefined)
|
|
22
|
+
doc.input = task.input;
|
|
18
23
|
return stringifyYaml(doc);
|
|
19
24
|
}
|
|
25
|
+
/** Validate optional `task.input` against entry-stage IR `clone_input_schema` (YAML: `io.input.schema`). */
|
|
26
|
+
export function checkTaskEntryInput(task, loaded, options) {
|
|
27
|
+
const absPath = options.taskPath
|
|
28
|
+
? path.resolve(options.cwd, options.taskPath)
|
|
29
|
+
: path.resolve(options.cwd, "task.yaml");
|
|
30
|
+
const findingPath = relPath(options.cwd, absPath);
|
|
31
|
+
const stageById = new Map(loaded.stages.map((stage) => [stage.id, stage]));
|
|
32
|
+
const findings = [];
|
|
33
|
+
for (const rootId of loaded.dag.roots) {
|
|
34
|
+
const stage = stageById.get(rootId);
|
|
35
|
+
if (stage?.clone_input_schema === undefined)
|
|
36
|
+
continue;
|
|
37
|
+
if (task.input === undefined) {
|
|
38
|
+
findings.push({
|
|
39
|
+
severity: "warning",
|
|
40
|
+
code: "task.entry_input_unmet",
|
|
41
|
+
path: findingPath,
|
|
42
|
+
message: `Task has no input; entry stage "${rootId}" requires io.input`,
|
|
43
|
+
category: "task",
|
|
44
|
+
pipelineId: loaded.pipeline.id,
|
|
45
|
+
stageId: rootId,
|
|
46
|
+
});
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
let details;
|
|
50
|
+
try {
|
|
51
|
+
details = payloadInstanceMismatch(task.input, stage.clone_input_schema);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
55
|
+
findings.push({
|
|
56
|
+
severity: "error",
|
|
57
|
+
code: "task.invalid_shape",
|
|
58
|
+
path: findingPath,
|
|
59
|
+
message: `Task input does not match entry stage "${rootId}" io.input: ${message}`,
|
|
60
|
+
category: "task",
|
|
61
|
+
pipelineId: loaded.pipeline.id,
|
|
62
|
+
stageId: rootId,
|
|
63
|
+
});
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (details !== undefined) {
|
|
67
|
+
findings.push({
|
|
68
|
+
severity: "error",
|
|
69
|
+
code: "task.invalid_shape",
|
|
70
|
+
path: findingPath,
|
|
71
|
+
message: `Task input does not match entry stage "${rootId}" io.input: ${details}`,
|
|
72
|
+
category: "task",
|
|
73
|
+
pipelineId: loaded.pipeline.id,
|
|
74
|
+
stageId: rootId,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return findings;
|
|
79
|
+
}
|
|
20
80
|
export function resolveStartTaskInput(input, cwd) {
|
|
21
81
|
if (typeof input.taskYaml === "string") {
|
|
22
82
|
if (input.taskYaml.trim().length === 0) {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { StageGateKind } from "./stage.js";
|
|
2
2
|
export declare const COMPLETION_VERIFICATION_FAILURE_PREFIX = "Completion verification failed:";
|
|
3
|
+
/**
|
|
4
|
+
* After-phase check IR (`DAG node.completion`). YAML: `verify` items whose
|
|
5
|
+
* `when` includes `after`. `type: payload_schema` here is a check kind (re-check
|
|
6
|
+
* the success payload after emit), not the old YAML authoring key.
|
|
7
|
+
*/
|
|
3
8
|
export type CompletionCheck = {
|
|
4
9
|
id: string;
|
|
5
10
|
type: "command";
|
|
@@ -31,6 +36,7 @@ export type CompletionContract = {
|
|
|
31
36
|
mode: "all";
|
|
32
37
|
checks: CompletionCheck[];
|
|
33
38
|
};
|
|
39
|
+
/** IR recovery on the DAG node. YAML: `on_verify_fail`. */
|
|
34
40
|
export type RecoveryPolicy = {
|
|
35
41
|
mode: "repair";
|
|
36
42
|
max_attempts: number;
|
package/dist/types/pipeline.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { CloneAction } from "./forkChoice.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { LoadedStageConfig, StageGateKind, StageIoYaml } from "./stage.js";
|
|
3
3
|
import type { CompletionContract, RecoveryPolicy } from "./completion.js";
|
|
4
4
|
export type PipelineConfig = {
|
|
5
5
|
id: string;
|
|
6
6
|
stages: string[];
|
|
7
7
|
/** Selects the AgentPort backend for every stage in this pipeline; overrides the global default. */
|
|
8
8
|
agent?: string;
|
|
9
|
+
/** Default LLM model id for every stage in this pipeline; overrides the global default. */
|
|
10
|
+
model?: string;
|
|
11
|
+
/** Pipeline-file `$ref` root (`#/schemas/<name>`). */
|
|
12
|
+
schemas?: Record<string, unknown>;
|
|
9
13
|
};
|
|
10
14
|
export type PipelineForkConfig = {
|
|
11
15
|
select: "one" | "subset";
|
|
@@ -37,12 +41,20 @@ export type PipelineStageRef = {
|
|
|
37
41
|
};
|
|
38
42
|
clonable?: boolean;
|
|
39
43
|
clone_cap?: number;
|
|
44
|
+
/** IR: after-phase checks. YAML: `verify` items whose `when` includes `after`. */
|
|
40
45
|
completion?: CompletionContract;
|
|
46
|
+
/** IR: after-phase failure policy. YAML: `on_verify_fail`. */
|
|
41
47
|
recovery?: RecoveryPolicy;
|
|
42
48
|
feedback_loop?: FeedbackLoopConfig;
|
|
43
49
|
/** Omitted means this stage is safe to include in a feedback replay. */
|
|
44
50
|
replay_safe?: boolean;
|
|
45
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Pipeline YAML stage entry (both dialects). Target authoring is `io` / `verify`
|
|
54
|
+
* / `on_verify_fail`. The payload_schema / pre_emit_checks / completion /
|
|
55
|
+
* recovery keys are the legacy YAML dialect (and also the IR names after compile).
|
|
56
|
+
* New catalog fields: add target YAML keys here and compile them in yamlDialect.ts.
|
|
57
|
+
*/
|
|
46
58
|
export type PipelineStageYamlEntry = PipelineStageRef & {
|
|
47
59
|
uses?: string;
|
|
48
60
|
system_prompt?: string;
|
|
@@ -53,6 +65,10 @@ export type PipelineStageYamlEntry = PipelineStageRef & {
|
|
|
53
65
|
clone_actions?: CloneAction[];
|
|
54
66
|
skill?: string;
|
|
55
67
|
mcp?: string[];
|
|
68
|
+
io?: StageIoYaml;
|
|
69
|
+
verify?: unknown;
|
|
70
|
+
on_verify_fail?: RecoveryPolicy;
|
|
71
|
+
pre_emit_checks?: unknown;
|
|
56
72
|
};
|
|
57
73
|
export type PipelineIncludeEntry = {
|
|
58
74
|
local: string;
|
|
@@ -70,6 +86,7 @@ export type NormalizedPipelineStageEntry = {
|
|
|
70
86
|
};
|
|
71
87
|
clonable?: boolean;
|
|
72
88
|
clone_cap?: number;
|
|
89
|
+
/** IR after compile. YAML `verify` after-phase / `on_verify_fail`. */
|
|
73
90
|
completion?: CompletionContract;
|
|
74
91
|
recovery?: RecoveryPolicy;
|
|
75
92
|
feedback_loop?: FeedbackLoopConfig;
|
|
@@ -102,7 +119,9 @@ export type ResolvedPipelineStageNode = {
|
|
|
102
119
|
clonable?: boolean;
|
|
103
120
|
clone_cap?: number;
|
|
104
121
|
definition_id?: string;
|
|
122
|
+
/** Persisted on pipeline_dag. YAML `verify` after-phase. */
|
|
105
123
|
completion?: CompletionContract;
|
|
124
|
+
/** Persisted on pipeline_dag. YAML `on_verify_fail`. */
|
|
106
125
|
recovery?: RecoveryPolicy;
|
|
107
126
|
feedback_loop?: FeedbackLoopConfig;
|
|
108
127
|
replay_safe?: boolean;
|
|
@@ -114,7 +133,7 @@ export type ResolvedPipelineDag = {
|
|
|
114
133
|
};
|
|
115
134
|
export type LoadedPipeline = {
|
|
116
135
|
pipeline: PipelineConfig;
|
|
117
|
-
stages:
|
|
136
|
+
stages: LoadedStageConfig[];
|
|
118
137
|
dag: ResolvedPipelineDag;
|
|
119
138
|
pipelinePath: string;
|
|
120
139
|
stageSources?: Record<string, PipelineStageSource>;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { StageGateKind } from "./stage.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* (`src/types/completion.ts`)
|
|
6
|
-
*
|
|
7
|
-
* `PreEmitCheck` runs synchronously inside the agent's own `emit_stage_envelope`
|
|
8
|
-
* tool call, driven by the stage-body `pre_emit_checks` field.
|
|
3
|
+
* Emit-phase check IR (`StageConfig.pre_emit_checks`). YAML: `verify` items
|
|
4
|
+
* whose `when` includes `emit`. Distinct from after-phase `CompletionCheck`
|
|
5
|
+
* (`src/types/completion.ts`), which runs after a candidate envelope is captured.
|
|
6
|
+
* This runs inside `emit_stage_envelope` before success is accepted.
|
|
9
7
|
*/
|
|
10
8
|
export type PreEmitCheck = {
|
|
11
9
|
id: string;
|
package/dist/types/stage.d.ts
CHANGED
|
@@ -2,16 +2,32 @@ import type { PreEmitCheck } from "./preEmitCheck.js";
|
|
|
2
2
|
import type { CloneAction } from "./forkChoice.js";
|
|
3
3
|
export declare const STAGE_GATE_KINDS: readonly ["free_text", "confirm", "multi_question", "artifact_backed"];
|
|
4
4
|
export type StageGateKind = (typeof STAGE_GATE_KINDS)[number];
|
|
5
|
+
/** Target YAML `io:` block. Compiles onto StageConfig.payload_schema / clone_input_schema. */
|
|
6
|
+
export type StageIoYaml = {
|
|
7
|
+
input?: {
|
|
8
|
+
schema?: unknown;
|
|
9
|
+
};
|
|
10
|
+
output?: {
|
|
11
|
+
schema?: unknown;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Loaded stage IR. Field names are the runtime contract (emit, VSE, snapshots),
|
|
16
|
+
* not the catalog YAML spelling. Target YAML `io` / `verify` compile onto these
|
|
17
|
+
* in `src/config/yamlDialect.ts`. Do not add new catalog keys here — add them on
|
|
18
|
+
* the YAML dialect and map them in compileTargetContract.
|
|
19
|
+
*/
|
|
5
20
|
export type StageConfig = {
|
|
6
21
|
id: string;
|
|
7
22
|
system_prompt: string;
|
|
8
|
-
model
|
|
9
|
-
/**
|
|
23
|
+
model?: string;
|
|
24
|
+
/** IR: success envelope.payload schema. YAML: `io.output.schema`. */
|
|
10
25
|
payload_schema?: unknown;
|
|
11
26
|
/** Declared ask_operator kinds this stage is expected to stop on. */
|
|
12
27
|
gate_kinds?: StageGateKind[];
|
|
13
|
-
/**
|
|
28
|
+
/** IR: emit-phase checks. YAML: `verify` items whose `when` includes `emit`. */
|
|
14
29
|
pre_emit_checks?: PreEmitCheck[];
|
|
30
|
+
/** IR: clone/fan-out assignment schema. YAML: `io.input.schema`. */
|
|
15
31
|
clone_input_schema?: unknown;
|
|
16
32
|
clone_actions?: CloneAction[];
|
|
17
33
|
/** Optional stage wall-clock timeout in milliseconds (default 60 minutes). */
|
|
@@ -24,3 +40,6 @@ export type StageConfig = {
|
|
|
24
40
|
*/
|
|
25
41
|
agent?: string;
|
|
26
42
|
};
|
|
43
|
+
export type LoadedStageConfig = StageConfig & {
|
|
44
|
+
model: string;
|
|
45
|
+
};
|
|
@@ -13,6 +13,8 @@ export type StageflowManifest = {
|
|
|
13
13
|
catalog: StageflowManifestCatalog;
|
|
14
14
|
/** Default AgentPort backend for every pipeline/stage that doesn't override it. */
|
|
15
15
|
agent?: string;
|
|
16
|
+
/** Default LLM model id for every stage that doesn't override it at pipeline or stage level. */
|
|
17
|
+
model?: string;
|
|
16
18
|
};
|
|
17
19
|
export type LoadedManifest = {
|
|
18
20
|
path: string;
|
package/dist/types/task.d.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Per-model token/cost breakdown, as computed by the backend SDK itself. */
|
|
2
|
+
export type ModelUsageBreakdown = {
|
|
3
|
+
inputTokens: number;
|
|
4
|
+
outputTokens: number;
|
|
5
|
+
cacheReadInputTokens: number;
|
|
6
|
+
cacheCreationInputTokens: number;
|
|
7
|
+
costUsd: number;
|
|
8
|
+
};
|
|
9
|
+
/** Accumulated LLM usage/cost for one stage attempt, across every turn/call it made. */
|
|
10
|
+
export type StageUsage = {
|
|
11
|
+
costUsd: number;
|
|
12
|
+
models: Record<string, ModelUsageBreakdown>;
|
|
13
|
+
};
|
|
14
|
+
/** Merge one model's usage from a single call into an accumulator, in place. */
|
|
15
|
+
export declare function addModelUsage(usage: StageUsage, model: string, delta: Partial<ModelUsageBreakdown>): void;
|
|
16
|
+
export declare function emptyStageUsage(): StageUsage;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
function emptyBreakdown() {
|
|
2
|
+
return {
|
|
3
|
+
inputTokens: 0,
|
|
4
|
+
outputTokens: 0,
|
|
5
|
+
cacheReadInputTokens: 0,
|
|
6
|
+
cacheCreationInputTokens: 0,
|
|
7
|
+
costUsd: 0,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/** Merge one model's usage from a single call into an accumulator, in place. */
|
|
11
|
+
export function addModelUsage(usage, model, delta) {
|
|
12
|
+
const current = usage.models[model] ?? emptyBreakdown();
|
|
13
|
+
usage.models[model] = {
|
|
14
|
+
inputTokens: current.inputTokens + (delta.inputTokens ?? 0),
|
|
15
|
+
outputTokens: current.outputTokens + (delta.outputTokens ?? 0),
|
|
16
|
+
cacheReadInputTokens: current.cacheReadInputTokens + (delta.cacheReadInputTokens ?? 0),
|
|
17
|
+
cacheCreationInputTokens: current.cacheCreationInputTokens + (delta.cacheCreationInputTokens ?? 0),
|
|
18
|
+
costUsd: current.costUsd + (delta.costUsd ?? 0),
|
|
19
|
+
};
|
|
20
|
+
usage.costUsd += delta.costUsd ?? 0;
|
|
21
|
+
}
|
|
22
|
+
export function emptyStageUsage() {
|
|
23
|
+
return { costUsd: 0, models: {} };
|
|
24
|
+
}
|