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:
gsxdsm
2026-05-14 08:36:57 -07:00
parent e7348eac50
commit 6c19ec4cb8
2 changed files with 49 additions and 0 deletions

View File

@@ -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.