From eba9c19179100779d68497a1d3ca052686964369 Mon Sep 17 00:00:00 2001 From: Matteo Benedetto Date: Sun, 16 Aug 2026 19:43:30 +0200 Subject: [PATCH] feat: campo confidence (high/medium/low, default medium) nei record MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - gateway: MemoryIn + payload + risultati search; 422 su valore invalido - estensione: confidence in qmem_store e qmem_correct (eredita dal superseduto), mostrato nei risultati - backward compatible: record esistenti → confidence null - verificato sul server: high/medium/default, 422 su invalida (istanza di test) --- extensions/index.ts | 14 +++++++++++++- gateway/main.py | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/extensions/index.ts b/extensions/index.ts index c5e95a7..a314d6a 100644 --- a/extensions/index.ts +++ b/extensions/index.ts @@ -189,6 +189,11 @@ export default function qmemExtension(pi: ExtensionAPI) { description: "Scope organizzativo (default: agent).", }), ), + confidence: Type.Optional( + Type.Union([Type.Literal("high"), Type.Literal("medium"), Type.Literal("low")], { + description: "Affidabilità del record: high = verificato (fonte autorevole/conferma), medium = probabile, low = osservazione non confermata (default: medium).", + }), + ), source: Type.Optional(Type.String({ description: "Origine del record (es. conversazione, file, ticket)." })), expires_at: Type.Optional(Type.String({ description: "Scadenza ISO 8601 (es. 2026-09-01T00:00:00Z) per memoria volatile." })), supersedes_id: Type.Optional(Type.String({ description: "UUID del record da supersedere (correzione): il nuovo record diventa la versione attiva, il vecchio resta in archivio marcato superseded." })), @@ -217,6 +222,7 @@ export default function qmemExtension(pi: ExtensionAPI) { project_id: p.project_id, scope: p.scope ?? "agent", source: p.source, + confidence: p.confidence ?? "medium", expires_at: p.expires_at, supersedes_id: p.supersedes_id, supersede_reason: p.supersede_reason, @@ -334,7 +340,7 @@ export default function qmemExtension(pi: ExtensionAPI) { } const lines = results.map( (r: any, i: number) => - `${i + 1}. [${r.kind}/${r.scope} score=${r.score}${r.score < 0.6 ? " ⚠️" : ""}] ${r.text}\n (id: ${r.memory_id}, agente: ${r.agent_id ?? "?"}, creato: ${r.created_at ?? "?"}${r.source ? `, fonte: ${r.source}` : ""}${r.supersedes_id ? `, supersede ${r.supersedes_id}` : ""}${r.superseded_by ? `, ⚠️ superseduto da ${r.superseded_by}` : ""})`, + `${i + 1}. [${r.kind}/${r.scope} score=${r.score}${r.score < 0.6 ? " ⚠️" : ""}${r.confidence ? ` conf=${r.confidence}` : ""}] ${r.text}\n (id: ${r.memory_id}, agente: ${r.agent_id ?? "?"}, creato: ${r.created_at ?? "?"}${r.source ? `, fonte: ${r.source}` : ""}${r.supersedes_id ? `, supersede ${r.supersedes_id}` : ""}${r.superseded_by ? `, ⚠️ superseduto da ${r.superseded_by}` : ""})`, ); return { content: [{ type: "text", text: lines.join("\n") }], @@ -373,6 +379,11 @@ export default function qmemExtension(pi: ExtensionAPI) { ), ), project_id: Type.Optional(Type.String({ description: "Progetto del nuovo record (default: eredita dal record superseduto)." })), + confidence: Type.Optional( + Type.Union([Type.Literal("high"), Type.Literal("medium"), Type.Literal("low")], { + description: "Affidabilità del nuovo record (default: eredita dal record superseduto).", + }), + ), agent_id: Type.Optional(Type.String({ description: "Nome dell'agente che corregge (solo provenienza)." })), }), async execute(toolCallId, params, signal, onUpdate, ctx) { @@ -456,6 +467,7 @@ export default function qmemExtension(pi: ExtensionAPI) { agent_id: p.agent_id, project_id: p.project_id ?? orig.project_id, scope: orig.scope ?? "agent", + confidence: p.confidence ?? orig.confidence ?? "medium", source: "qmem_correct", supersedes_id: memoryId, supersede_reason: p.reason, diff --git a/gateway/main.py b/gateway/main.py index be245cc..c67c80b 100644 --- a/gateway/main.py +++ b/gateway/main.py @@ -180,6 +180,7 @@ class MemoryIn(BaseModel): project_id: str = Field(min_length=1, max_length=64, description="OBBLIGATORIO: progetto/dominio di appartenenza (kebab-case)") scope: Literal["agent", "project", "org"] = "agent" source: Optional[str] = Field(default=None, max_length=256) + confidence: Literal["high", "medium", "low"] = Field(default="medium", description="Affidabilità del record: high = verificato, medium = probabile, low = osservazione non confermata") expires_at: Optional[str] = None # ISO 8601 supersedes_id: Optional[str] = None supersede_reason: Optional[str] = Field(default=None, max_length=512) @@ -369,6 +370,7 @@ async def add_memory( "project_id": body.project_id, "scope": body.scope, "source": body.source, + "confidence": body.confidence, "created_at": _now_iso(), "expires_at": _parse_ts(body.expires_at), "supersedes_id": superseded_id, @@ -463,6 +465,7 @@ async def search_memories(body: SearchIn, key: str = Depends(require_auth)) -> d "agent_id": h.payload.get("agent_id"), "scope": h.payload.get("scope"), "project_id": h.payload.get("project_id"), + "confidence": h.payload.get("confidence"), "created_at": h.payload.get("created_at"), "source": h.payload.get("source"), "supersedes_id": h.payload.get("supersedes_id"),