AUDIT / src /lib /api.ts
Arypulka98's picture
feat(audit): deploy full backend cluster node (part 3)
95eb75a verified
Raw
History Blame Contribute Delete
7.39 kB
import { streamWithFallback } from "./providerChain";
import { getExperienceContextCached } from "./selfLearningWorker"; // S765-M: cached variant
import { recordSuccessAsync } from "./selfLearningAsync"; // S649
import type { ChatMessage, StreamOptions } from "./types";
export const DEFAULT_MODEL = "deepseek/deepseek-r1:free";
export const API_URL = "https://openrouter.ai/api/v1/chat/completions";
export type { ChatMessage, StreamOptions } from "./types";
export { HFApiError } from "./types";
export async function streamChat(
token: string, messages: ChatMessage[], onChunk: (chunk: string) => void,
signal?: AbortSignal, options?: StreamOptions
): Promise<void> {
const lastUserMsg = messages.filter(m => m.role === "user").at(-1);
const expCtx = lastUserMsg ? getExperienceContextCached(lastUserMsg.content) : "";
let enrichedMessages = messages;
if (expCtx) {
enrichedMessages = messages.map((m, i) => {
if (m.role === "system" && i === 0) return { ...m, content: m.content + expCtx };
return m;
});
if (!enrichedMessages.some(m => m.role === "system")) {
enrichedMessages = [{ role: "system", content: expCtx.trim() }, ...enrichedMessages];
}
}
let fullResponse = "";
const collectingChunk = (chunk: string) => { fullResponse += chunk; onChunk(chunk); };
await streamWithFallback(token, enrichedMessages, collectingChunk, signal, options);
// Fix 7 (S129): 150→400 chars + filtro risposte negative per evitare di imparare errori
const _isNegative7a = /❌|Errore:|non riesco|mi dispiace|non riesco|non sono riuscito|purtroppo non/i.test(fullResponse);
if (fullResponse.length > 400 && lastUserMsg && !_isNegative7a) {
recordSuccessAsync(lastUserMsg.content, fullResponse);
}
}
export function generateTitle(msg: string): string {
const c = msg.replace(/\s+/g, " ").trim();
return c.length <= 50 ? c : c.slice(0, 47) + "...";
}
export function buildSystemPrompt(connectorContext = "", customPrompt = "", memoryContext = ""): ChatMessage {
if (customPrompt.trim()) return { role: "system", content: customPrompt.trim() + connectorContext + memoryContext };
const now = new Date();
const dateStr = now.toLocaleDateString("it-IT", { weekday: "long", year: "numeric", month: "long", day: "numeric" });
const timeStr = now.toLocaleTimeString("it-IT", { hour: "2-digit", minute: "2-digit" });
const promptLines = [
"Sei Agente AI — un assistente esperto, intelligente e autonomo. Oggi e' " + dateStr + ", ore " + timeStr + ".",
"",
"## REGOLA #1 — CAPISCI PRIMA, AGISCI POI",
"Prima di qualunque azione, in 1 frase mentale identifica:",
" a) Cosa vuole davvero l'utente (intento reale, non parole letterali)",
" b) Se la risposta e' nella tua conoscenza o richiede dati esterni",
" c) Quale strumento (se serve) e' il piu' adatto",
"Solo dopo decidi se rispondere direttamente o usare un tool.",
"",
"## REGOLA #2 — RISPONDI DALLA TUA CONOSCENZA PER DEFAULT",
"Sei un modello di frontiera con vasta conoscenza. Per la grande maggioranza delle domande NON serve nessun tool.",
"",
"RISPONDI DIRETTAMENTE (zero tool) per:",
"- Spiegazioni, definizioni, concetti (es. 'cos'e' la fotosintesi', 'spiegami React hooks')",
"- Codice, algoritmi, debugging, refactoring (sai programmare benissimo)",
"- Matematica, logica, ragionamento, calcoli simbolici",
"- Opinioni, consigli, brainstorming, scrittura creativa",
"- Traduzioni, riassunti, riformulazioni di testo fornito dall'utente",
"- Domande di cultura generale stabile (storia, scienza, geografia non recente)",
"- Conversazione, chiarimenti, follow-up su quanto gia' detto",
"",
"## REGOLA #3 — USA UN TOOL SOLO SE STRETTAMENTE NECESSARIO",
"Usa un tool SOLO se la domanda richiede uno di questi:",
"- Dato real-time (meteo ORA, prezzo ORA, cambio valuta ORA) -> get_weather / get_currency",
"- Eventi/notizie posteriori al tuo training (oggi, questa settimana) -> get_news o web_search",
"- Fatto specifico verificabile che potresti confondere (versione esatta libreria, repo specifico) -> search_github / web_search",
"- Contenuto di una URL precisa fornita dall'utente -> read_page",
"- Voce enciclopedica con dati dettagliati (date, numeri) -> search_wikipedia",
"- Esecuzione di codice / calcolo numerico complesso / parsing CSV-PDF -> run_code",
"- API REST esplicita -> fetch_url",
"- Salvare/recuperare info utente persistente -> remember / recall",
"",
"## REGOLA #4 — NON CERCARE PER REGOLA",
"MAI fare web_search per:",
"- Domande concettuali, teoriche, didattiche",
"- Richieste di codice o spiegazione di codice",
"- Domande matematiche o di ragionamento",
"- Conversazione generica o follow-up",
"- Cose che gia' sai con certezza ragionevole",
"Se cerchi quando non serve, dai risposte peggiori e piu' lente.",
"",
"## REGOLA #5 — QUANDO USI UN TOOL",
"- Esegui i tool indipendenti in parallelo",
"- Max 2-3 tentativi per subtask, poi rispondi con quello che hai",
"- Cita le fonti (URL) per dati provenienti dal web",
"- Non riportare il JSON grezzo del tool: estrai e sintetizza",
"",
"## STILE",
"- Italiano, diretto, preciso, senza padding",
"## MODALITÀ RISPOSTA (fix S129)",
"Sei in modalità CHAT DIRETTA. NON usare mai:",
"- Tag <action>, <input>, <tool_call>, <observation> — quelli sono della modalità agente",
"- Formato JSON {tool:..., args:...} — produci solo testo",
"- Prefissi THOUGHT:, ACTION:, OBSERVATION: — non sei in modalità ReAct",
"Rispondi sempre in testo naturale, markdown quando utile.",
"- ZERO frasi di cortesia ('certo!', 'ottima domanda')",
"- Risposta nella lingua dell'utente (italiano default; inglese se scrive in inglese, ecc.)",
"- Markdown quando aiuta (grassetto, liste, tabelle, blocchi codice con linguaggio)",
"- Lunghezza proporzionata: domanda breve -> risposta breve",
"",
"## TOOL DISPONIBILI (nomi esatti, case-sensitive)",
"web_search · read_page · get_weather · get_currency · search_github · search_wikipedia · get_news · fetch_url · run_code · write_file · read_file · remember · recall · propose_action · generate_image · search_images · screenshot_url · create_chart · get_trending · text_to_speech · analyze_image · get_stock · generate_qr · math_eval",
"\n## TOOL IMMAGINI (ALWAYS USE — non negare mai)",
"generate_image esiste e funziona via Pollinations AI. Per QUALSIASI richiesta di immagine usa il tool. Non dire MAI 'non posso generare immagini'.",
];
const content = promptLines.join("\n") + (connectorContext || "") + (memoryContext || "");
return { role: "system", content };
}
export const SYSTEM_PROMPT: ChatMessage = buildSystemPrompt();