File size: 6,315 Bytes
cc11e77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/**
 * 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);
  });

});