/** * agentLoopDirectResponse.test.ts — S478 DIRECT_RESPONSE_MODE: integration tests * * Verifica che il flag isDirectAnswer propagato da taskClassifier: * 1. Blocchi detectIntent (nessun tool pre-exec per domande definitorie) * 2. Imponga _effectiveMaxIter=1 tramite P1-GATE * 3. Non inietti ReasoningCore completo (stub leggero) * 4. Blocchi retry engine * 5. Blocchi belief restore * * Pattern: DI puro — usa _setTestMatcher da taskClassifier per controllare * isDirectAnswer in modo deterministico, senza mock di moduli ESM. * * SESSIONE: S478 — DIRECT_RESPONSE_MODE */ import { describe, it, expect, afterEach } from "vitest"; import { classifyTask, _setTestMatcher, _resetMatcher } from "@/lib/taskClassifier"; import { detectIntent } from "@/lib/agentLoop/intentParser"; afterEach(() => { _resetMatcher(); }); // ─── Gruppo A: classifyTask → isDirectAnswer propagato correttamente ────────── describe("S478: classifyTask → isDirectAnswer propagato (wire-in check)", () => { it("A-1. query definitoria breve → isDirectAnswer=true", () => { const cls = classifyTask("cos'è il DNA?"); expect(cls.isDirectAnswer).toBe(true); expect(cls.modelTier).not.toBe("premium"); // no heavy model per direct }); it("A-2. full_app → isDirectAnswer=false", () => { const cls = classifyTask("Crea un'app completa da zero con auth e dashboard"); expect(cls.isDirectAnswer).toBe(false); }); it("A-3. math_calculation → isDirectAnswer=true senza live signal", () => { const cls = classifyTask("quanto fa 12 * 12?"); expect(cls.type).toBe("math_calculation"); expect(cls.isDirectAnswer).toBe(true); }); it("A-4. simple_question → isDirectAnswer=true", () => { const cls = classifyTask("ciao!"); expect(cls.type).toBe("simple_question"); expect(cls.isDirectAnswer).toBe(true); }); it("A-5. explanation con live signal → isDirectAnswer=false", () => { // "oggi" è live signal → non direct anche se è una spiegazione const cls = classifyTask("spiegami le ultime notizie di oggi"); expect(cls.isDirectAnswer).toBe(false); }); it("A-6. search_and_report breve senza live → isDirectAnswer=true", () => { const cls = classifyTask("cerca cos'è TypeScript"); expect(cls.isDirectAnswer).toBe(true); }); it("A-7. search_and_report >100 chars → isDirectAnswer=false (troppo lungo)", () => { const longMsg = "cerca online e analizza in dettaglio tutti i trend recenti del mercato aziendale italiano per il 2026 e dimmi cosa dicono gli esperti"; expect(longMsg.length).toBeGreaterThan(100); const cls = classifyTask(longMsg); expect(cls.isDirectAnswer).toBe(false); }); it("A-8. DI: _setTestMatcher con isDirectAnswer=true esplicito → propagato", () => { _setTestMatcher((_msg, rules) => { const r = rules.find(r => r.type === "simple_question"); return r ?? null; }); const cls = classifyTask("anything"); expect(cls.isDirectAnswer).toBe(true); // simple_question senza live → direct }); }); // ─── Gruppo B: detectIntent → null per domande definitorie (S478 intentParser fix) ── describe("S478: detectIntent → null per domande definitorie (gate confermato)", () => { const DEFINITIONAL = [ "chi è Einstein?", "chi era Galileo Galilei?", "cos'è il DNA?", "cosa è il quantum computing?", "cosa sono i neutrini?", "what is TypeScript?", "what are design patterns?", "who is Alan Turing?", "who was Ada Lovelace?", "dimmi chi è Darwin", "sai chi è Platone?", "mi spieghi chi è Socrate?", ]; for (const query of DEFINITIONAL) { it(`→ null per: "${query}"`, () => { const result = detectIntent(query); expect(result).toBeNull(); }); } }); // ─── Gruppo C: detectIntent → NON null per query live ──────────────────────── describe("S478: detectIntent → tool corretto per query live (non bloccato)", () => { it("C-1. meteo → get_weather", () => { expect(detectIntent("che tempo fa a Roma?")?.tool).toBe("get_weather"); }); it("C-2. notizie → get_news", () => { expect(detectIntent("ultime notizie")?.tool).toBe("get_news"); }); it("C-3. 'chi è il presidente adesso?' → web_search (live, non bloccato)", () => { expect(detectIntent("chi è il presidente adesso?")?.tool).toBe("web_search"); }); it("C-4. 'chi ha vinto la partita ieri?' → web_search (live: risultato)", () => { expect(detectIntent("chi ha vinto la partita ieri?")?.tool).toBe("web_search"); }); it("C-5. immagine → generate_image", () => { expect(detectIntent("disegna un gatto su uno skateboard")?.tool).toBe("generate_image"); }); it("C-6. math eval → math_eval", () => { expect(detectIntent("calcola 2^10")?.tool).toBe("math_eval"); }); }); // ─── Gruppo D: isDirectAnswer via DI — verifica coerenza con getTopInterpretations ── describe("S478: getTopInterpretations → isDirectAnswer propagato", () => { // Import getTopInterpretations solo se esportato it("D-1. classifyTask ritorna isDirectAnswer booleano sempre definito", () => { const queries = [ "ciao", "cos'è il DNA?", "scrivi una funzione sort in TypeScript", "crea un'app completa con React", "xyzzy plugh frobozz", ]; for (const q of queries) { const cls = classifyTask(q); expect(typeof cls.isDirectAnswer).toBe("boolean"); } }); it("D-2. task code_generation → isDirectAnswer=false (mai direct)", () => { const cls = classifyTask("scrivi una funzione TypeScript per validare email con regex"); expect(cls.type).toBe("code_generation"); expect(cls.isDirectAnswer).toBe(false); }); it("D-3. task debug → isDirectAnswer=false (mai direct)", () => { const cls = classifyTask("il componente crasha su mobile, non funziona nulla"); expect(cls.type).toBe("debug"); expect(cls.isDirectAnswer).toBe(false); }); it("D-4. task architecture → isDirectAnswer=false (mai direct)", () => { const cls = classifyTask("come strutturare il progetto con microservizi e event bus?"); expect(cls.isDirectAnswer).toBe(false); }); });