fix(FN-6035): model pre-merge workflow steps in builtin coding

This commit is contained in:
gsxdsm
2026-06-08 22:02:26 -07:00
parent b6800e8622
commit 8d3b869ec1
17 changed files with 283 additions and 46 deletions

View File

@@ -9,7 +9,14 @@ import {
type WorkflowRuntimePrimitives,
} from "./runtime-primitives.js";
export type WorkflowSeamName = "planning" | "execute" | "review" | "merge" | "schedule" | "step-execute";
export type WorkflowSeamName =
| "planning"
| "execute"
| "workflow-step"
| "review"
| "merge"
| "schedule"
| "step-execute";
export interface WorkflowLegacySeams {
/** Planning/spec stage. Built-in triage runs upstream of the interpreter
@@ -17,6 +24,7 @@ export interface WorkflowLegacySeams {
* custom planning behavior is expressed as a custom prompt node. */
planning: (task: TaskDetail, context: Record<string, unknown>) => Promise<WorkflowNodeResult>;
execute: (task: TaskDetail, context: Record<string, unknown>) => Promise<WorkflowNodeResult>;
workflowStep?: (task: TaskDetail, context: Record<string, unknown>) => Promise<WorkflowNodeResult>;
review: (task: TaskDetail, context: Record<string, unknown>) => Promise<WorkflowNodeResult>;
merge: (task: TaskDetail, context: Record<string, unknown>) => Promise<WorkflowNodeResult>;
schedule: (task: TaskDetail, context: Record<string, unknown>) => Promise<WorkflowNodeResult>;
@@ -195,6 +203,7 @@ export function resolveSeamName(node: { config?: Record<string, unknown> }): Wor
if (
seam === "planning" ||
seam === "execute" ||
seam === "workflow-step" ||
seam === "review" ||
seam === "merge" ||
seam === "schedule" ||
@@ -250,6 +259,11 @@ export function createPromptLikeHandler(
// IS the seam node, so its declared column drives the binding. (Other seams
// — planning/review/merge/schedule — stamp it too; only execute reads it.)
context.context[SEAM_GOVERNING_NODE_CONTEXT_KEY] = node.id;
if (seam === "workflow-step") {
return seams.workflowStep
? seams.workflowStep(context.task, context.context)
: { outcome: "success", value: "workflow-step-skipped" };
}
return seams[seam]!(context.task, context.context);
}
if (!runCustomNode) {
@@ -317,7 +331,24 @@ export function createPrimitivePromptLikeHandler(
...(result.contextPatch ?? {}),
}
: undefined;
return { outcome: result.outcome, value: result.value, contextPatch };
return {
outcome: result.outcome,
value: result.value,
contextPatch: {
...(contextPatch ?? {}),
"workflow:worktree-path": prepared.data.worktreePath,
},
};
}
if (seam === "workflow-step") {
const worktreePath = typeof context.context["workflow:worktree-path"] === "string"
? context.context["workflow:worktree-path"]
: undefined;
const result = await primitives.runWorkflowStep(primitiveCtx, context.task, {
phase: "pre-merge",
worktreePath,
});
return { outcome: result.outcome, value: result.value, contextPatch: result.contextPatch };
}
if (seam === "review") {
const result = await primitives.runReview(primitiveCtx, context.task, { type: "code" });
@@ -798,6 +829,7 @@ export function createNoopLegacySeams(): WorkflowLegacySeams {
return {
planning: success,
execute: success,
workflowStep: success,
review: success,
merge: success,
schedule: success,