feat(FN-4367): add structured JSON verdict output for prompt-mode workflow steps
- Add verdict (PASS/FAIL) field to core WorkflowStepResult type - Add parseWorkflowStepOutput() engine helper for json-workflow-verdict blocks - Update executeWorkflowStep to extract structured verdict/notes from output - Persist verdict and notes in runWorkflowSteps result entries - Update agent prompt Feedback Format to require JSON verdict block - Update WS-006 (Frontend UX Design) template prompt with structured fast-bail - Add WorkflowResultsTab verdict badge and notes rendering with CSS - Add 11 engine tests for verdict parsing edge cases - Add 6 dashboard tests for verdict/notes rendering - Create replace-ws006-prompt.mjs migration script for existing DBs - Add changeset for @runfusion/fusion patch Fusion-Task-Id: FN-4367 Fusion-Task-Lineage: adbfac60-5cfe-4ae9-9706-1094dfe7d676
This commit is contained in:
@@ -6575,6 +6575,50 @@ ${failureFeedback}
|
||||
return { output: trimmed, malformed: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse structured JSON verdict from workflow step output.
|
||||
*
|
||||
* Looks for a trailing JSON block of the form:
|
||||
* ```json-workflow-verdict
|
||||
* {"verdict":"PASS"|"FAIL","notes":"..."}
|
||||
* ```
|
||||
*
|
||||
* If found, extracts verdict/notes and returns the prose before the block
|
||||
* as `output`.
|
||||
*
|
||||
* Falls back to prose-only parsing (REQUEST REVISION) for backward compat.
|
||||
*/
|
||||
private parseWorkflowStepOutput(rawOutput: string): {
|
||||
output: string;
|
||||
verdict?: "PASS" | "FAIL";
|
||||
notes?: string;
|
||||
} {
|
||||
const trimmed = rawOutput.trim();
|
||||
|
||||
// Try structured JSON block first
|
||||
const jsonBlockMatch = trimmed.match(
|
||||
/```json-workflow-verdict\s*\n([\s\S]*?)\n\s*```/,
|
||||
);
|
||||
if (jsonBlockMatch) {
|
||||
try {
|
||||
const parsed = JSON.parse(jsonBlockMatch[1].trim());
|
||||
if (parsed.verdict === "PASS" || parsed.verdict === "FAIL") {
|
||||
const proseBefore = trimmed.slice(0, trimmed.indexOf(jsonBlockMatch[0])).trim();
|
||||
return {
|
||||
output: proseBefore || parsed.notes || "",
|
||||
verdict: parsed.verdict,
|
||||
notes: parsed.notes,
|
||||
};
|
||||
}
|
||||
} catch {
|
||||
// Malformed JSON — fall through to prose parsing
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: no structured block found, return raw output
|
||||
return { output: trimmed };
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a single workflow step by spawning an agent with the step's prompt.
|
||||
* Returns structured outcome with support for revision requests.
|
||||
|
||||
Reference in New Issue
Block a user