/** * LLM output formatter. * * Converts an ImhotepResult into a compact JSON string designed for * consumption by large language models in automated repair loops. * Failing clauses include diagnostic codes, messages, fix hints, and metrics. * When there are no clause results (parse/preflight failures), synthetic * failing clauses are emitted from diagnostics so repair loops still work. */ import type { ImhotepResult } from 'imhotep-core' export function formatAsLLM(result: ImhotepResult): string { const failingClauses = result.clauseResults .filter((cr) => cr.status === 'fail' || cr.status === 'error') .map((cr) => { let diag = result.diagnostics.find((d) => d.clauseId === cr.clauseId) if (!diag) { const code = cr.diagnostics.find((c) => c !== '') if (code) { diag = result.diagnostics.find((d) => d.code === code) } } const failingClause: Record = {} failingClause.clauseLabel = cr.clauseLabel ?? diag?.clauseLabel ?? cr.clauseId failingClause.sourceRef = cr.sourceRef ?? diag?.sourceRef ?? {} failingClause.diagnosticCode = diag?.code ?? cr.diagnostics[0] ?? 'IMH_UNKNOWN_FAILURE' failingClause.message = diag?.message ?? `Clause ${cr.clauseId} failed` failingClause.suggestedFix = diag?.suggestedFix ?? diag?.fixHints ?? [] failingClause.metrics = { ...(diag?.metrics ?? {}), ...(cr.metrics ?? {}) } return failingClause }) if (failingClauses.length === 0 && result.diagnostics.length > 0) { for (const d of result.diagnostics) { const failingClause: Record = {} failingClause.clauseLabel = d.clauseLabel ?? 'diagnostic' failingClause.sourceRef = d.sourceRef ?? {} failingClause.diagnosticCode = d.code failingClause.message = d.message failingClause.suggestedFix = d.suggestedFix ?? d.fixHints ?? [] failingClause.metrics = d.metrics ?? {} failingClauses.push(failingClause) } } const llmOutput: Record = {} llmOutput.passed = result.passed llmOutput.failingClauses = failingClauses llmOutput.summary = result.summary return JSON.stringify(llmOutput) }