AUDIT / src /lib /__tests__ /agentLoopS42.test.ts
Arypulka98's picture
feat(audit): deploy full backend cluster node (part 2)
cc11e77 verified
Raw
History Blame Contribute Delete
9.29 kB
/**
* agentLoopS42.test.ts — Integration tests S42: CapabilityRouter + TaskClassifier wire-in
*
* Copertura (12 test):
* 1. classifyTask + route: task semplice → light tier → groq (velocità)
* 2. classifyTask + route: task premium → high reasoning → gemini o openai
* 3. classifyTask + route: code_generation → code=true → provider con code_score alto
* 4. classifyTask + route: search_and_report → requires_tools=true → provider con tools=true
* 5. route: prefer_free=true → esclude provider non free se disponibili free
* 6. _setRouterDeps: isAvailable filtra provider senza token
* 7. _setRouterDeps: solo groq disponibile → route ritorna groq
* 8. route con tutti i provider unavailable → null (no crash)
* 9. classifyTask: debug → modelTier standard, code=true nel capReq
* 10. classifyTask: full_app → premium, needsPlan=true
* 11. preferredModel map: groq → llama-3.3-70b-versatile
* 12. preferredModel map: gemini → gemini-2.5-flash
*
* DI: _setTestDeps / _resetDeps + _setTestMatcher / _resetMatcher
* Zero vi.mock su moduli ESM — pattern DI puro
* SESSIONE: S42 — CapabilityRouter + TaskClassifier wire-in agentLoop
*/
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import {
classifyTask,
_setTestMatcher,
_resetMatcher,
} from "@/lib/taskClassifier";
import {
route,
scoreProfile,
CAPABILITY_PROFILES,
_setTestDeps,
_resetDeps,
} from "@/lib/capabilityRouter";
import type { CapabilityRequest } from "@/lib/capabilityRouter";
// ─── Helpers ──────────────────────────────────────────────────────────────────
/** Costruisce un CapabilityRequest dal TaskClassification (rispecchia la logica wire-in) */
function buildCapReq(msg: string): CapabilityRequest {
const cls = classifyTask(msg);
return {
reasoning_depth: (
cls.modelTier === "premium" ? "high" :
cls.modelTier === "standard" ? "medium" : "low"
) as "low" | "medium" | "high",
code: cls.type === "code_generation" || cls.type === "code_fix" || cls.type === "refactor" || cls.type === "debug",
requires_tools: cls.type === "search_and_report" || cls.type === "debug",
prefer_free: true,
speed: cls.complexity <= 3,
};
}
/** Mappa provider → modello hint (rispecchia la logica wire-in) */
function mapPreferredModel(provider: string): string | undefined {
switch (provider) {
case "groq": return "llama-3.3-70b-versatile";
case "gemini": return "gemini-2.5-flash"; // gemini-2.0-flash deprecato marzo 2026
case "openai": return "gpt-4o-mini";
case "openrouter": return "moonshotai/kimi-k2.6:free"; // S306: deepseek-v4-flash non più free
default: return undefined;
}
}
// ─── Setup / Teardown ─────────────────────────────────────────────────────────
beforeEach(() => {
_setTestDeps({ isAvailable: () => true });
});
afterEach(() => {
_resetDeps();
_resetMatcher();
});
// ─── Test suite ───────────────────────────────────────────────────────────────
describe("S42: TaskClassifier + CapabilityRouter integration", () => {
it("1. task semplice → light tier → provider veloce scelto (speed=true)", () => {
const cls = classifyTask("ciao");
expect(cls.modelTier).toBe("light");
expect(cls.complexity).toBeLessThanOrEqual(3);
const req = buildCapReq("ciao");
expect(req.speed).toBe(true);
expect(req.reasoning_depth).toBe("low");
const result = route(req);
expect(result).not.toBeNull();
// Con speed=true groq ha lo score più alto (speed_score=10)
expect(result!.provider).toBe("groq");
});
it("2. task premium (full_app) → reasoning high → provider con reasoning_score>=9", () => {
const cls = classifyTask("crea un'app completa da zero con dashboard e autenticazione");
expect(cls.modelTier).toBe("premium");
const req = buildCapReq("crea un'app completa da zero con dashboard e autenticazione");
expect(req.reasoning_depth).toBe("high");
const result = route(req);
expect(result).not.toBeNull();
expect(result!.profile.reasoning_score).toBeGreaterThanOrEqual(9);
expect(["gemini", "openai"]).toContain(result!.provider);
});
it("3. code_generation → code=true nel capReq → provider con code_score alto", () => {
const cls = classifyTask("scrivi una funzione TypeScript per validare email");
expect(cls.type).toBe("code_generation");
const req = buildCapReq("scrivi una funzione TypeScript per validare email");
expect(req.code).toBe(true);
const result = route(req);
expect(result).not.toBeNull();
// I provider con code_score alto (openai=9, gemini=8, openrouter=8) devono essere preferiti
expect(result!.profile.code_score).toBeGreaterThanOrEqual(6);
});
it("4. search_and_report → requires_tools=true → provider con tools=true", () => {
const cls = classifyTask("cerca informazioni su TypeScript 5.9");
expect(cls.type).toBe("search_and_report");
const req = buildCapReq("cerca informazioni su TypeScript 5.9");
expect(req.requires_tools).toBe(true);
const result = route(req);
expect(result).not.toBeNull();
// Deve scegliere un provider con tools=true
expect(result!.profile.tools).toBe(true);
});
it("5. prefer_free=true → esclude provider non free se ci sono free disponibili", () => {
// Rende disponibili solo free + together (non free)
_setTestDeps({ isAvailable: (id) => ["gemini", "groq", "together"].includes(id) });
const result = route({ prefer_free: true, speed: true });
expect(result).not.toBeNull();
// Deve preferire groq (free + speed 10/10) su together (non free)
expect(result!.profile.free).toBe(true);
});
it("6. _setRouterDeps: filtra provider senza token (solo gemini disponibile)", () => {
_setTestDeps({ isAvailable: (id) => id === "gemini" });
const result = route({ reasoning_depth: "high" });
expect(result).not.toBeNull();
expect(result!.provider).toBe("gemini");
});
it("7. _setRouterDeps: solo groq disponibile → ritorna groq", () => {
_setTestDeps({ isAvailable: (id) => id === "groq" });
const result = route({ speed: true });
expect(result).not.toBeNull();
expect(result!.provider).toBe("groq");
});
it("8. tutti i provider unavailable → route ritorna null (no crash)", () => {
_setTestDeps({ isAvailable: () => false });
const result = route({ reasoning_depth: "high" });
expect(result).toBeNull();
});
it("9. debug task → modelTier standard, code=true, requires_tools=true nel capReq", () => {
// "non funziona" matcha il pattern debug
const msg = "la funzione non funziona e restituisce undefined";
const cls = classifyTask(msg);
expect(cls.type).toBe("debug");
expect(cls.modelTier).toBe("standard");
const req = buildCapReq(msg);
expect(req.code).toBe(true);
expect(req.requires_tools).toBe(true);
expect(req.reasoning_depth).toBe("medium");
});
it("10. full_app → premium, needsPlan=true, multiFile=true", () => {
const cls = classifyTask("build a complete app from scratch with auth and dashboard");
expect(cls.modelTier).toBe("premium");
expect(cls.needsPlan).toBe(true);
expect(cls.multiFile).toBe(true);
});
it("11. mapPreferredModel: groq → llama-3.3-70b-versatile", () => {
expect(mapPreferredModel("groq")).toBe("llama-3.3-70b-versatile");
});
it("12. mapPreferredModel: gemini → gemini-2.5-flash, openai → gpt-4o-mini, sconosciuto → undefined", () => {
expect(mapPreferredModel("gemini")).toBe("gemini-2.5-flash");
expect(mapPreferredModel("openai")).toBe("gpt-4o-mini");
expect(mapPreferredModel("openrouter")).toBe("moonshotai/kimi-k2.6:free"); // S306
expect(mapPreferredModel("huggingface")).toBeUndefined();
});
});
// ─── scoreProfile sanity checks per wire-in ──────────────────────────────────
describe("S42: scoreProfile sanity per wire-in", () => {
it("browser-llm con requires_tools=true ha score molto negativo (bloccato dal router)", () => {
const profile = CAPABILITY_PROFILES["browser-llm"];
const score = scoreProfile(profile, { requires_tools: true });
expect(score).toBeLessThan(-50);
});
it("gemini ha score positivo per reasoning_depth=high", () => {
const profile = CAPABILITY_PROFILES["gemini"];
const score = scoreProfile(profile, { reasoning_depth: "high" });
expect(score).toBeGreaterThan(0);
});
it("groq ha score più alto di gemini per speed=true (speed_score 10 vs 7)", () => {
const groqScore = scoreProfile(CAPABILITY_PROFILES["groq"], { speed: true });
const geminiScore = scoreProfile(CAPABILITY_PROFILES["gemini"], { speed: true });
expect(groqScore).toBeGreaterThan(geminiScore);
});
});