AUDIT / src /lib /agentLoop /confidenceGateBlock.ts
Arypulka98's picture
feat(audit): deploy full backend cluster node (part 2)
cc11e77 verified
Raw
History Blame Contribute Delete
5.01 kB
/**
* confidenceGateBlock.ts — S511: extracted from agentLoop.ts
*
* Gestisce tre controlli pre-API per ogni iterazione del ReAct loop:
* 1. ReasoningCore.decide() — cervello decisionale (stop/fix/plan/continue)
* 2. Confidence short-circuit (S418-F2) — break se score ≥ 0.72 + step eseguiti
* 3. Borderline confidence retry (S501) — inietta hint web_search se score 0.4-0.6
*
* Ritorna:
* - { action: "break" } → il caller fa break dal for loop
* - { action: "continue" } → il caller fa continue (solo reasoning stop)
* - { action: "ok" } → prosegui normalmente
*
* Muta `loopMessages` per reference (reasoning fix/plan e borderline hint).
*
* @module confidenceGateBlock
*/
import type { ApiMsg } from "./networkTools";
import type { AgentStep } from "../storage";
import { evaluateBorderlineRetry } from "../confidenceGate";
import type { ConfidenceSession } from "../confidenceEngine";
import type { ReasoningCore } from "../reasoningCore";
// ─── Interfaces ────────────────────────────────────────────────────────────────
export interface ConfidenceGateCtx {
iter: number;
isDirectAnswer: boolean;
steps: AgentStep[];
loopMessages: ApiMsg[];
lastUserMsg: string;
signal: AbortSignal | undefined;
reasoning: Pick<ReasoningCore, "isExhausted" | "decide">;
confSession: Pick<ConfidenceSession, "shouldClose" | "getScore">;
onStatus: (msg: string) => void;
}
export type ConfidenceGateAction = "break" | "continue" | "ok";
export interface ConfidenceGateResult {
action: ConfidenceGateAction;
}
// ─── Main export ───────────────────────────────────────────────────────────────
/**
* Esegue i tre controlli di confidence pre-API:
* reasoning.decide() → confidence short-circuit → borderline retry.
*/
export async function runConfidenceGate(ctx: ConfidenceGateCtx): Promise<ConfidenceGateResult> {
const { iter, isDirectAnswer, steps, loopMessages, lastUserMsg, signal, reasoning, confSession, onStatus } = ctx;
// ── 1. ReasoningCore.decide() — P0a-fix ─────────────────────────────────
// DIRECT-FIX: disabilitato per task a risposta diretta (isDirectAnswer → _effectiveMaxIter=1)
if (iter > 0 && !reasoning.isExhausted() && !isDirectAnswer) {
try {
const _rDecision = await reasoning.decide(signal);
if (_rDecision.action === "stop") {
onStatus("Ci siamo ✓");
return { action: "break" };
}
if (_rDecision.action === "fix" && _rDecision.reason) {
onStatus(`✏️ Mi correggo: ${_rDecision.reason.slice(0, 80)}`);
loopMessages.push({ role: "user", content: `[REASONING CORE — FIX RICHIESTO]\n${_rDecision.reason}\nCorreggi l'approccio e riprova. Steps suggeriti: ${_rDecision.steps.slice(0, 3).join(", ") || "cambia strategia"}` } as ApiMsg);
}
if (_rDecision.action === "plan" && _rDecision.steps.length > 0) {
onStatus(`🔄 Cambio approccio: ${_rDecision.steps[0].slice(0, 60)}`);
loopMessages.push({ role: "user", content: `[REASONING CORE — NUOVO PIANO]\n${_rDecision.steps.map((s, i) => `${i + 1}. ${s}`).join("\n")}` } as ApiMsg);
}
// "continue" → nessuna azione aggiuntiva, il loop prosegue normalmente
} catch { /* non-blocking — reasoning.decide() non blocca il loop */ }
}
// ── 2. Confidence short-circuit (S418-F2) ────────────────────────────────
// DIRECT-FIX: shouldClose() applicato già a iter > 0 per task a risposta diretta
const _trivialCloseReady = isDirectAnswer ? iter > 0 : iter > 1;
if (_trivialCloseReady && steps.length >= 1 && confSession.shouldClose()) {
onStatus("Risposta pronta ✓");
return { action: "break" };
}
// ── 3. Borderline confidence retry (S501) ────────────────────────────────
// Attivato una sola volta per loop (iter===1) per evitare loop infiniti.
if (iter === 1 && !confSession.shouldClose()) {
const _brDecision = (() => {
try { return evaluateBorderlineRetry(lastUserMsg, confSession.getScore()); } catch { return null; }
})();
if (_brDecision?.needsWeb && _brDecision.suggestedQuery) {
onStatus("Verifico un'ultima cosa…");
const _brHint = `\n\n[BORDERLINE CONFIDENCE: score=${(confSession.getScore() * 100).toFixed(0)}%. ` +
`Esegui web_search con query: "${_brDecision.suggestedQuery}" per supportare la risposta con dati verificati prima di rispondere.]`;
loopMessages[0] = { ...loopMessages[0], content: String(loopMessages[0].content) + _brHint };
}
}
return { action: "ok" };
}