feat(workflow): carry skillName through the WorkflowStep round-trip (U1)
Add skillName to WorkflowStep and WorkflowStepInput, and round-trip it through nodeToStepInput / stepInputToNode so a skill-executor node's skill is available to the step session. Honors the compiler INVERSION CONTRACT (parity test). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -626,6 +626,11 @@ export interface WorkflowStep {
|
||||
prompt: string;
|
||||
/** Tool set available to prompt-mode workflow agents. Defaults to readonly. */
|
||||
toolMode?: WorkflowStepToolMode;
|
||||
/** Name of a skill to load into this step's session (e.g.
|
||||
* "compound-engineering:ce-work"). When set, the step session loads the named
|
||||
* skill (discovery + selection) and the engine injects the Fusion workflow-step
|
||||
* conventions preamble. Only meaningful for skill-executor graph nodes. */
|
||||
skillName?: string;
|
||||
/** Name of a script from project settings `scripts` map to execute (required when mode is "script") */
|
||||
scriptName?: string;
|
||||
/** Whether this step is available for selection on new tasks */
|
||||
@@ -746,6 +751,9 @@ export interface WorkflowStepInput {
|
||||
prompt?: string;
|
||||
/** Tool set available to prompt-mode workflow agents. Defaults to readonly. */
|
||||
toolMode?: WorkflowStepToolMode;
|
||||
/** Name of a skill to load into this step's session (e.g.
|
||||
* "compound-engineering:ce-work"). See `WorkflowStep.skillName`. */
|
||||
skillName?: string;
|
||||
/** Script name from project settings (required when mode is "script").
|
||||
* Must reference a named script in `settings.scripts` — no raw commands. */
|
||||
scriptName?: string;
|
||||
|
||||
@@ -231,8 +231,9 @@ function defaultGateMode(node: WorkflowIrNode, mode: "prompt" | "script"): Workf
|
||||
* its exact inverse is `stepInputToNode` in `workflow-steps-to-ir.ts`. Parity is
|
||||
* pinned by `__tests__/workflow-steps-to-ir.test.ts` over exactly the
|
||||
* compiler-visible fields: name / mode / phase / gateMode / prompt / scriptName /
|
||||
* toolMode / modelProvider / modelId. `enabled` / `defaultOn` / `templateId` are
|
||||
* NOT compiler-visible and are handled by migration policy, not the converter.
|
||||
* toolMode / skillName / modelProvider / modelId. `enabled` / `defaultOn` /
|
||||
* `templateId` are NOT compiler-visible and are handled by migration policy, not
|
||||
* the converter.
|
||||
*
|
||||
* INVERSION CONTRACT: when you add a field here, extend `stepInputToNode` (and
|
||||
* the parity test) in `workflow-steps-to-ir.ts` to keep the round-trip exact.
|
||||
@@ -255,6 +256,10 @@ function nodeToStepInput(node: WorkflowIrNode, phase: "pre-merge" | "post-merge"
|
||||
} else {
|
||||
input.prompt = configString(node, "prompt") ?? "";
|
||||
input.toolMode = node.config?.toolMode === "coding" ? "coding" : "readonly";
|
||||
// Carry the node's skill name so the step session can load it (U1). Only
|
||||
// present on skill-executor nodes; omitted otherwise to keep round-trip exact.
|
||||
const skillName = configString(node, "skillName");
|
||||
if (skillName) input.skillName = skillName;
|
||||
const provider = configString(node, "modelProvider");
|
||||
const modelId = configString(node, "modelId");
|
||||
if (provider && modelId) {
|
||||
|
||||
@@ -12,10 +12,10 @@ import { parseWorkflowIr } from "./workflow-ir.js";
|
||||
* compileWorkflowToSteps(stepsToWorkflowIr(steps, name)) ≡ steps
|
||||
*
|
||||
* over exactly the compiler-visible fields: name / mode / phase / gateMode /
|
||||
* prompt / scriptName / toolMode / modelProvider / modelId. `enabled` /
|
||||
* `defaultOn` / `templateId` / `migratedFragmentId` are NOT compiler-visible and
|
||||
* are handled by migration policy (KTD-3), not by this converter. Parity is
|
||||
* pinned by `__tests__/workflow-steps-to-ir.test.ts`.
|
||||
* prompt / scriptName / toolMode / skillName / modelProvider / modelId.
|
||||
* `enabled` / `defaultOn` / `templateId` / `migratedFragmentId` are NOT
|
||||
* compiler-visible and are handled by migration policy (KTD-3), not by this
|
||||
* converter. Parity is pinned by `__tests__/workflow-steps-to-ir.test.ts`.
|
||||
*
|
||||
* INVERSION CONTRACT: when a compiler-visible field is added to `nodeToStepInput`
|
||||
* (see the contract comment there), extend `stepInputToNode` below and the parity
|
||||
@@ -68,6 +68,9 @@ function stepInputToNode(step: WorkflowStep, id: string): WorkflowIrNode {
|
||||
// prompt mode
|
||||
config.prompt = step.prompt ?? "";
|
||||
config.toolMode = step.toolMode === "coding" ? "coding" : "readonly";
|
||||
// Skill name round-trips when set (U1). The compiler reads it back via
|
||||
// configString(node, "skillName"), so this keeps the inverse exact.
|
||||
if (step.skillName) config.skillName = step.skillName;
|
||||
// Model overrides only round-trip when BOTH are present (compiler requirement).
|
||||
if (step.modelProvider && step.modelId) {
|
||||
config.modelProvider = step.modelProvider;
|
||||
|
||||
Reference in New Issue
Block a user