feat: avviso duplicati in qmem_store (search pre-salvataggio, soglia 0.92, non blocca)

- prima di salvare: ricerca top-3 con min_score 0.92 e stesso project_id
- se trovati: avviso nella risposta con id/score/testo dei candidati e suggerimento qmem_correct
- il salvataggio non viene bloccato
- verificato sul server: record quasi identici trovati con score 1.0/0.9908
This commit is contained in:
Matteo Benedetto
2026-08-16 19:45:18 +02:00
parent eba9c19179
commit 6c2417eab7
+18 -2
View File
@@ -209,6 +209,16 @@ export default function qmemExtension(pi: ExtensionAPI) {
} }
const p = params as any; const p = params as any;
onUpdate?.({ content: [{ type: "text", text: "qmem: salvataggio record..." }] }); onUpdate?.({ content: [{ type: "text", text: "qmem: salvataggio record..." }] });
// Rilevamento duplicati: cerca prima di salvare (soglia alta, non blocca)
let dupes: any[] = [];
const dupCheck = await gatewayRequest(
cfg,
"POST",
"/v1/memories:search",
{ query: p.text, project_id: p.project_id, top_k: 3, min_score: 0.92, include_superseded: false },
signal,
);
if (dupCheck.ok) dupes = dupCheck.data.results ?? [];
// Idempotency: stessa key per tutta l'operazione (e per eventuali retry) // Idempotency: stessa key per tutta l'operazione (e per eventuali retry)
const idemKey = crypto.randomUUID(); const idemKey = crypto.randomUUID();
const { ok, status, data } = await gatewayRequest( const { ok, status, data } = await gatewayRequest(
@@ -236,9 +246,15 @@ export default function qmemExtension(pi: ExtensionAPI) {
details: { error: "gateway_error", status }, details: { error: "gateway_error", status },
}; };
} }
const dupWarning =
dupes.length > 0
? "\n⚠️ Possibili duplicati (score >= 0.92, stesso project_id):\n" +
dupes.map((d: any) => ` - ${d.memory_id} (score ${d.score}): ${String(d.text).slice(0, 100)}`).join("\n") +
"\nValuta se il nuovo record è davvero necessario o se conviene qmem_correct sul duplicato."
: "";
return { return {
content: [{ type: "text", text: `Memoria salvata: ${data.memory_id} (${p.kind ?? "fact"}, scope ${p.scope ?? "agent"})${p.supersedes_id ? ` — supersede ${p.supersedes_id}` : ""}` }], content: [{ type: "text", text: `Memoria salvata: ${data.memory_id} (${p.kind ?? "fact"}, scope ${p.scope ?? "agent"})${p.supersedes_id ? ` — supersede ${p.supersedes_id}` : ""}${dupWarning}` }],
details: { memory_id: data.memory_id, created_at: data.created_at }, details: { memory_id: data.memory_id, created_at: data.created_at, duplicates: dupes.length },
}; };
}, },
}); });