import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { Type } from "typebox"; import { gatewayRequest, loadConfig } from "../shared.ts"; import { localDbPath, localGet } from "../local-db.ts"; export function registerQmemGet(pi: ExtensionAPI) { pi.registerTool({ name: "qmem_get", label: "Qmem memory get by ID", description: "Fetch one record exactly by UUID, including superseded records. Use qmem_search when the UUID is unknown.", parameters: Type.Object({ memory_id: Type.String({ description: "Record UUID." }), }), async execute(toolCallId, params, signal, onUpdate, ctx) { const cfg = loadConfig(); if (!cfg.apiKey) { return { content: [{ type: "text", text: "Config mancante: esegui /qmem:config per impostare url e apiKey." }], details: { error: "missing_config" }, }; } const p = params as any; onUpdate?.({ content: [{ type: "text", text: `qmem: recupero record ${p.memory_id}...` }] }); const { ok, status, data } = await gatewayRequest(cfg, "GET", `/v1/memories/${p.memory_id}`, undefined, signal); if (!ok) { const notFound = status === 404 || data?.detail === "Memoria non trovata"; if (!notFound) { // Gateway non raggiungibile: tentativo sull'indice locale (SQLite/FTS5) try { const local = await localGet(p.memory_id, { dbFile: localDbPath(cfg) }); if (local) { return { content: [ { type: "text", text: `⚠️ Gateway non raggiungibile (HTTP ${status}): record dall'INDICE LOCALE (osservazione più vecchia del gateway, può essere incompleta).\n` + `memory_id: ${local.memory_id}\n[${local.kind ?? "?"}/${local.scope ?? "?"}${local.project_id ? ` project=${local.project_id}` : ""}] agente: ${local.agent_id ?? "?"}, creato: ${local.created_at ?? "?"}${local.pending ? ", ⏳ creato offline: non ancora sul gateway" : ""}${local.superseded_by ? `, ⚠️ superseduto da ${local.superseded_by}` : ""}${local.remote_id ? `, sincronizzato come ${local.remote_id}` : ""}\n\n${local.text ?? "(nessun testo)"}`, }, ], details: { memory_id: local.memory_id, fallback: "local_sqlite", gateway_status: status }, }; } } catch { /* indice locale non disponibile: si prosegue con l'errore del gateway */ } } return { content: [ { type: "text", text: notFound ? `Record ${p.memory_id} non trovato (404). Verifica l'ID (qmem_search include_superseded=true per la lineage) oppure l'URL gateway.` : `Errore ${status}: ${JSON.stringify(data)}`, }, ], details: { error: notFound ? "not_found" : "gateway_error", status, memory_id: p.memory_id }, }; } const r = data ?? {}; const meta = [ `[${r.kind ?? "?"}/${r.scope ?? "?"}${r.level ? ` ${r.level}` : ""}${r.topic ? ` (${r.topic})` : ""}${r.confidence ? ` conf=${r.confidence}` : ""}]`, `project: ${r.project_id ?? "?"}`, `agente: ${r.agent_id ?? "?"}, creato: ${r.created_at ?? "?"}${r.source ? `, fonte: ${r.source}` : ""}`, ]; if (r.parent_id) meta.push(`parent: ${r.parent_id}`); if (r.links && r.links.length > 0) meta.push(`links: ${r.links.length}`); if (r.supersedes_id) meta.push(`supersede ${r.supersedes_id}`); if (r.superseded_by) meta.push(`⚠️ SUPERSEDUTO da ${r.superseded_by}`); if (r.expires_at) meta.push(`scade: ${r.expires_at}`); const lines = [`memory_id: ${r.memory_id ?? p.memory_id}`, meta.join(" | "), "", r.text ?? "(nessun testo)"]; return { content: [{ type: "text", text: lines.join("\n") }], details: { memory_id: r.memory_id ?? p.memory_id, kind: r.kind, scope: r.scope, project_id: r.project_id, parent_id: r.parent_id, level: r.level, topic: r.topic, superseded_by: r.superseded_by ?? null, }, }; }, }); }