feat: campo confidence (high/medium/low, default medium) nei record

- 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)
This commit is contained in:
Matteo Benedetto
2026-08-16 19:43:30 +02:00
parent 7abced1566
commit eba9c19179
2 changed files with 16 additions and 1 deletions
+13 -1
View File
@@ -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,
+3
View File
@@ -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"),