// ─── Retry engine ───────────────────────────────────────────────────────────── // Decides if and how to retry a failed/poor LLM response. // S-RETRY-WIRE: usa validateGate invece di validateOutput raw. // validateGate unifica normalize/sanitize/repair/quality/antiRewriteGuard // e produce un retryHint chirurgico quando referenceCode è fornito. import { validateGate } from "./validationGate"; export interface RetryDecision { shouldRetry: boolean; reason: string; augmentedPrompt?: string; priority: "immediate" | "deferred" | "skip"; } export interface RetryContext { task: string; output: string; iter: number; maxIter: number; toolResults?: string[]; /** * S-RETRY-WIRE: snapshot "noto buono" del codice per antiRewriteGuard. * Se fornito, validateGate rileva rewrite/incompletezza/import injection * e inietta il retryHint chirurgico nel prompt del retry. */ referenceCode?: string; } export function decideRetry(ctx: RetryContext): RetryDecision { // Never retry near the iteration ceiling if (ctx.iter >= ctx.maxIter - 2) { return { shouldRetry: false, reason: "limite iterazioni raggiunto", priority: "skip" }; } // S-RETRY-WIRE: validateGate sostituisce validateOutput. // referenceCode attiva auditOutput() → hint chirurgico anti-rewrite/incompletezza/injection. const gate = validateGate(ctx.output, { taskHint: ctx.task, referenceCode: ctx.referenceCode, }); // "accept" e "repaired" → nessun retry necessario if (gate.verdict === "accept" || gate.verdict === "repaired") { return { shouldRetry: false, reason: "output valido", priority: "skip" }; } const issueStr = gate.issues.join(", "); // S-RETRY-WIRE: retryHint del gate contiene già i constraint chirurgici // (NON riscrivere / Includi tutte le classi / Non introdurre deps esterne). // IMPORTANT: non menzionare mai "la risposta precedente" — istruzione interna pura. let augmentedPrompt = gate.retryHint ? gate.retryHint + " Rispondi in modo preciso e completo. Fornisci direttamente la risposta corretta senza meta-commenti." : "Rispondi alla domanda dell'utente in modo preciso e completo. Non commentare eventuali problemi precedenti."; if (ctx.toolResults && ctx.toolResults.length > 0) { const dataStr = ctx.toolResults.slice(0, 3).join("\n\n"); augmentedPrompt += ` Usa questi dati reali già disponibili:\n${dataStr}`; } else { augmentedPrompt += " Sii accurato, completo e in italiano."; } const shouldRetry = gate.verdict === "retry" || gate.verdict === "reject"; return { shouldRetry, reason: issueStr, augmentedPrompt, priority: gate.quality < 2 ? "immediate" : "deferred", }; } /** Quick check: should this output trigger a retry? */ export function shouldRetry(output: string, task?: string): boolean { const gate = validateGate(output, { taskHint: task }); return gate.verdict === "retry" || gate.verdict === "reject"; }