feat(Fase2): euristica webSearch=auto rifinita — filtri, trigger e anti-ridondanza
- webSearch=auto: euristica robusta con filtri negativi (immagini, analisi locale, task di codice, comandi) e trigger positivi (recency, versioni, confronti, definizioni, news). - webSearch non si attiva per mode image/analyze. - Cache anti-ridondanza: evita ricerche ripetute dello stesso topic entro 60s. - Test: 10/10 casi passano.
This commit is contained in:
+54
-10
@@ -428,14 +428,51 @@ async function webSearchGemini(query: string, signal?: AbortSignal): Promise<str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function needsWebSearch(prompt: string): boolean {
|
// Cache anti-ridondanza: evita ricerche web ripetute sullo stesso topic in una
|
||||||
const mode = getConfig("webSearch") ?? "auto";
|
// finestra breve (il multi-step reasoning lancia prompt simili in sequenza).
|
||||||
if (mode === "off") return false;
|
let lastSearch = { topic: "", time: 0 };
|
||||||
if (mode === "on") return true;
|
|
||||||
// auto: domande informative/tecniche che beneficiano di dati aggiornati
|
// Euristica per webSearch=auto. Determina se il prompt beneficia di dati
|
||||||
return /cerca|ricerca|latest|ultim|aggiorna|versione|documentaz|news|novit|differenza|confronta|quanto |come funzion|quando|perché|cos'è|chi è|release|prezzo|alternativ/i.test(
|
// aggiornati dalla ricerca web. Filtri negativi (immagini, codice locale,
|
||||||
prompt,
|
// comandi) per non sprecare chiamate API/token su task che non servono.
|
||||||
);
|
function needsWebSearch(prompt: string, mode?: string): boolean {
|
||||||
|
if (mode === "image" || mode === "analyze") return false;
|
||||||
|
const ws = getConfig("webSearch") ?? "auto";
|
||||||
|
if (ws === "on") return true;
|
||||||
|
if (ws === "off") return false;
|
||||||
|
|
||||||
|
const p = prompt.trim().toLowerCase();
|
||||||
|
if (!p || p.length < 14) return false;
|
||||||
|
|
||||||
|
// --- Filtri negativi: task che NON beneficiano della ricerca web ---
|
||||||
|
// generazione / editing immagini
|
||||||
|
if (/(genera|crea|disegna|produrr|dipin|realizz).{0,30}(immagine|logo|icona|poster|banner|ritratto|illustraz|foto|meme|sfondo)/i.test(p))
|
||||||
|
return false;
|
||||||
|
// analisi locale / OCR / trascrizione / traduzione / voce
|
||||||
|
if (/(analizza questo|analizza il|\bocr\b|trascri|leggi il file|traduci|riassumi il file)/.test(p)) return false;
|
||||||
|
// task di codice puramente locale
|
||||||
|
if (/^(scrivi|rifattorizza|correggi|implementa|aggiungi|rimuovi|crea|modifica|fix|refactor|aggiorna il file|genera il codice)/.test(p))
|
||||||
|
return false;
|
||||||
|
// comandi / gestione conversazione
|
||||||
|
if (/^(continua|ricordati|ignora|vai avanti|mostra|riassumi la conversazione|non)/.test(p)) return false;
|
||||||
|
|
||||||
|
// --- Trigger positivi ---
|
||||||
|
// segnali di recency / tempo corrente
|
||||||
|
if (/(oggi|stamattina|adesso|al momento|quest'anno|del 20\d\d|nel 20\d\d|recent|ultim|appena|di recente|attuale|latest)/i.test(p))
|
||||||
|
return true;
|
||||||
|
// versioni / package / tech aggiornati
|
||||||
|
if (/(versione|version|release|changelog|release notes|npm|package|dipendenz|compatibil|lts|stabile|beta|deprecat|\beol\b|end of life|release date)/i.test(p))
|
||||||
|
return true;
|
||||||
|
// confronti / alternative / raccomandazioni
|
||||||
|
if (/(differenza|confronta|\bvs\b|alternativ|migliore|best|top|consigli|oppure)/i.test(p)) return true;
|
||||||
|
// domande informative / definizioni
|
||||||
|
if (/(cos'?è|che cos|chi è|quanto|quando|dove|perché|come funzion|cosa significa|definizion|significat|prezzo|costo|storia di)/i.test(p))
|
||||||
|
return true;
|
||||||
|
// news / novità / fatti correnti
|
||||||
|
if (/(news|notizie|novità|novita|ultime notizie|accadut|succes|eventi|mercato|azienda|lancio|annunci)/i.test(p))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const estTokens = (s: string) => Math.ceil(s.length / 4);
|
const estTokens = (s: string) => Math.ceil(s.length / 4);
|
||||||
@@ -450,6 +487,7 @@ async function buildContextBlock(
|
|||||||
ctx: any,
|
ctx: any,
|
||||||
prompt: string,
|
prompt: string,
|
||||||
signal?: AbortSignal,
|
signal?: AbortSignal,
|
||||||
|
mode?: string,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
if (getConfig("contextInject") === "off") return "";
|
if (getConfig("contextInject") === "off") return "";
|
||||||
const budget = Number(getConfig("contextTokens") ?? 1500) || 1500;
|
const budget = Number(getConfig("contextTokens") ?? 1500) || 1500;
|
||||||
@@ -491,10 +529,16 @@ async function buildContextBlock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- <web_context> (Strada A) ---
|
// --- <web_context> (Strada A) ---
|
||||||
if (needsWebSearch(prompt)) {
|
if (needsWebSearch(prompt, mode)) {
|
||||||
|
// anti-ridondanza: non ricercare lo stesso topic entro 60s
|
||||||
|
const topic = prompt.trim().toLowerCase().slice(0, 60);
|
||||||
|
const now = Date.now();
|
||||||
|
if (topic !== lastSearch.topic || now - lastSearch.time > 60_000) {
|
||||||
|
lastSearch = { topic, time: now };
|
||||||
const web = await webSearchGemini(prompt.slice(0, 300), signal);
|
const web = await webSearchGemini(prompt.slice(0, 300), signal);
|
||||||
if (web) parts.push({ label: "web", xml: "web_context", body: web });
|
if (web) parts.push({ label: "web", xml: "web_context", body: web });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Token cap: budget totale ~1500. Assegna in modo proporzionale.
|
// Token cap: budget totale ~1500. Assegna in modo proporzionale.
|
||||||
const blocks: string[] = [];
|
const blocks: string[] = [];
|
||||||
@@ -1126,7 +1170,7 @@ export default function agyExtension(pi: ExtensionAPI) {
|
|||||||
const wantInject = p.injectContext ?? true;
|
const wantInject = p.injectContext ?? true;
|
||||||
const prevWs = getConfig("webSearch");
|
const prevWs = getConfig("webSearch");
|
||||||
if (typeof p.webSearch === "boolean") setConfig("webSearch", p.webSearch ? "on" : "off");
|
if (typeof p.webSearch === "boolean") setConfig("webSearch", p.webSearch ? "on" : "off");
|
||||||
const contextBlock = wantInject ? await buildContextBlock(ctx, p.prompt, signal) : "";
|
const contextBlock = wantInject ? await buildContextBlock(ctx, p.prompt, signal, p.mode) : "";
|
||||||
if (typeof p.webSearch === "boolean" && prevWs) setConfig("webSearch", prevWs);
|
if (typeof p.webSearch === "boolean" && prevWs) setConfig("webSearch", prevWs);
|
||||||
const res = await executeAgy({
|
const res = await executeAgy({
|
||||||
prompt: p.prompt,
|
prompt: p.prompt,
|
||||||
|
|||||||
Reference in New Issue
Block a user