Spaces:
Sleeping
Sleeping
| /** | |
| * 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" }; | |
| } | |