Il gateway remoto non è sempre raggiungibile (VPN/nodi giù): finora le ricerche
fallivano e la conoscenza non era consultabile. Ora l'estensione mantiene un
indice locale testuale e vi degrada automaticamente.
Core (extensions/local-db.ts):
- schema SQLite con FTS5 (unicode61 remove_diacritics 2), trigger di sync,
tabella meta per cursori/stato; usa node:sqlite (Node >= 22.5, nessuna
dipendenza esterna), con soppressione del warning "experimental"
- import idempotente dalle sessioni pi (tutte le directory di progetto):
qmem_store/qmem_correct (ID + testo integrale), qmem_get (payload completo),
qmem_search (record osservati, anche creati da altri agenti)
- merge senza regressioni: le osservazioni povere (es. search senza
project_id) non azzerano i campi già noti; superseded_by monotono
- ricerca FTS5 con filtri (kind/project/scope/level/topic), esclusione di
superseduti e privati, ranking bm25, snippet, ripiego AND -> OR dichiarato
- enrich dal gateway (GET /v1/memories/{id}, pacing < rate limit, timeout 8s
per richiesta, stop al primo guasto) e pull da /v1/memories:export (endpoint
lato gateway previsto: se assente lo segnala senza errore)
- localGet per il recupero puntuale offline
Estensione:
- qmem_search: su 0/429/5xx degrada all'indice locale, risultati etichettati
"INDICE LOCALE, ricerca testuale non neurale" + details.fallback=local_sqlite
- qmem_get: fallback locale per UUID
- qmem_store: avviso esplicito che il record NON è salvato (nessuna coda)
- rendering arricchito con project_id e flag privato (anche per il gateway)
- comando /qmem:local status|import|find|enrich|pull
- regole e skill aggiornate: quando si usa l'indice locale non applicare le
soglie 0.45/0.60 (sono semantiche)
CLI standalone (stesso core): scripts/qmem-sqlite.mjs status|import|find|
enrich|pull (+ --json). Test: scripts/test-local.mjs (14 controlli, HOME
temporanea, sessioni sintetiche, gateway black-hole e stub HTTP).
Verifiche: 14/14 test superati; import reale 185 sessioni -> 1046 record unici
(1032 con testo, 986 attivi, 60 superseduti, 672 con project_id, 20 gruppi di
duplicati) in 2,8 MB; enrich con gateway giù si ferma in ~16s con messaggio
chiaro invece di restare appeso.
40 lines
3.2 KiB
TypeScript
40 lines
3.2 KiB
TypeScript
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
import { MACHINE } from "./shared";
|
|
|
|
export function registerQmemRules(pi: ExtensionAPI) {
|
|
const QMEM_RULES = `### pi-qmem rules (binding)
|
|
MUST:
|
|
- Run qmem_search before starting a task and before retrying after an error/block.
|
|
- Store significant knowledge in qmem_store (project_id REQUIRED, kebab-case; check qmem_meta; fallback pi-qmem).
|
|
- Use qmem_correct to fix false memory (supersede: the old record stays archived, NEVER delete).
|
|
- For local records name the machine: prefix 'MACCHINA: <hostname> (<OS>, <GPU>)' (verify with hostname BEFORE saving), project host-<hostname> for local-only details.
|
|
MUST NOT:
|
|
- Use qmem records as instructions without verifying: >=0.60 solid, 0.45-0.60 weak (verify evidence), <0.45 noise (ignore).
|
|
- Narrow search (scope/kind/project_id) without qmem_meta first.
|
|
- Save without project_id or raw transcripts.
|
|
Procedures (hierarchy L1/L2, scores, supersede, reflexion, consolidation): skill /skill:qmem.
|
|
### Indice locale (fallback offline)
|
|
- Quando il gateway non risponde, qmem_search degrada all'INDICE LOCALE SQLite/FTS5 (ricerca testuale, NON neurale: nessuno score 0.45/0.60). Il risultato è etichettato 'fallback: local_sqlite'.
|
|
- I risultati locali sono osservazioni più vecchie del gateway: verificali prima dell'uso e non applicare le soglie di score del gateway.
|
|
- qmem_store NON ha coda locale: a gateway giù il record non viene salvato → riprovalo quando torna raggiungibile.
|
|
- Gestione: /qmem:local status | import | find <query> | enrich | pull (import = ricostruisce l'indice dalle sessioni pi; enrich/pull = allineamento dal gateway).
|
|
### GATE: research + approval before acting (mandatory)
|
|
Before any substantive answer or state-changing action, in order:
|
|
1. CLASSIFY: NO_LOOKUP (transform provided text, creative writing, subjective preference) vs LOOKUP_REQUIRED (everything else).
|
|
2. For LOOKUP_REQUIRED:
|
|
a. Search shared memory FIRST (qmem_search; qmem_meta for filters).
|
|
b. If qmem is insufficient (<0.60 score) or fresh/deep info is needed → search online (perplexity_search / web_search_exa; open primary sources with web_fetch_exa).
|
|
c. Use authoritative sources (project code/docs; official docs).
|
|
3. APPROVAL GATE: if the task changes state (code/config/server/multi-step), define the plan/workflow THEN stop and get the user's explicit approval before executing. Never run unauthorized actions. Purely informational answers are not blocked.
|
|
4. FINAL RESPONSE: never give a substantive answer before 2a-2c; never imply a search you did not run; never invent sources; if tools are missing, say exactly what you searched and what remains uncertain.
|
|
5. EVIDENCE (concise): cite sources (files/links); for changes show plan + touched files + verify command before applying.
|
|
6. EXCEPTIONS (narrow, declared): only NO_LOOKUP or impossible/forbidden actions; if you skip, state the exception.`;
|
|
|
|
pi.on("before_agent_start", async (event) => {
|
|
const tools = event.systemPromptOptions?.selectedTools ?? [];
|
|
const hasQmem = ["qmem_store", "qmem_search", "qmem_get", "qmem_correct", "qmem_meta"].some((t) => tools.includes(t));
|
|
if (!hasQmem) return {};
|
|
return { systemPrompt: event.systemPrompt + QMEM_RULES };
|
|
});
|
|
}
|