Commit Graph
50 Commits
Author SHA1 Message Date
enne2 7097c4002b perf(qmem): skill qmem in inglese conciso — description sempre-on 70→42 token, corpo on-demand 1817→1028 token (totale -43%), procedure preservate 2026-08-28 16:38:33 +02:00
enne2 ca89679b3c perf(qmem): A2 schemi tool in inglese compatto — testo model-visible 2242→462 token (-79%) col tokenizer Qwen3.8; nomi/parametri/enum/default invariati, promptGuidelines duplicate rimosse (già in QMEM_RULES) 2026-08-28 16:27:49 +02:00
enne2 6c1c4f526f fix(qmem): frontmatter skill quotato (YAML ': ') + A1 regole iniettate compatte (procedure → skill qmem) 2026-08-28 16:02:35 +02:00
enne2 86ac1996fb feat(private): memorie riservate escluse dalle ricerche standard
- gateway: campo private (bool) in MemoryIn; filtro must_not private=true
  di default in search_filter; include_private in SearchIn per ricerche
  esplicite; campo private esposto in format_results
- estensione: parametro private in qmem_store, include_private in qmem_search
  (con descrizioni e avvertenze sui prompt dei modelli)
- testato su brain: record private invisibile alla ricerca standard,
  visibile solo con include_private=true; topic esplicito da solo non sblocca
- deploy: /opt/memory/gateway ricostruito (container memory-gateway)
2026-08-25 20:14:28 +02:00
enne2 5a5081e5d9 feat(prompt): regola vincolante identificazione macchina nei record qmem (hostname auto-rilevato, layout modulare) + bump v1.8.0 2026-08-24 22:55:51 +02:00
Matteo Benedetto 4776b4b496 refactor: split gateway and pi-qmem extension into modules
- gateway: separate config, models, state, audit, guardrail, embeddings,
  store, metrics, cleanup and routes; keep main.py as FastAPI bootstrap
- extension: split client/config, six tools, config command and rules;
  preserve jiti entrypoint and registrations
- Dockerfile copies the complete gateway module set
- tests: update monkeypatch boundaries for modular config/state
2026-08-24 16:19:19 +02:00
Matteo Benedetto e68fca3388 feat(reparenting): supersede di un record ri-parenta automaticamente i figli attivi
- gateway: nel blocco supersede, i figli attivi (parent_id == vecchio UUID,
  superseded_by vuoto) vengono ri-parentati al nuovo UUID; audit action
  'reparent'; risposta con campo 'reparented'. Un solo livello: i nipoti
  puntano agli UUID dei figli, invariati. I figli superseduti restano
  storici ancorati alla vecchia lineage.
- estensione: qmem_tree con fallback lineage (cerca figli anche per
  supersedes_id del root) per gli orfani pre-fix; qmem_correct riporta
  il numero di figli ri-parentati.
- test: 2 nuovi (ri-parenta figli attivi; ri-parenta solo attivi con
  figlio già superseduto). 34 pass.
- deploy su brain (10.8.0.3): main.py aggiornato, container ricreato,
  smoke test end-to-end OK (reparented=1).
2026-08-24 15:43:33 +02:00
Matteo Benedetto 0283d3964e feat(hierarchy): aggiunti tool qmem_tree e regole operative per gestione gerarchica L1/L2 2026-08-23 13:16:13 +02:00
Matteo Benedetto 369a2c2d9e feat(hierarchy): supporto metadati strutturati e gerarchici su Qdrant (parent_id, level, topic, links) 2026-08-23 13:07:16 +02:00
Matteo Benedetto fc11f878f6 feat(prompt): blocco Riflessione in QMEM_RULES (loop Reflexion-style) + bump v1.7.1
Regola auto-miglioramento: lezioni strutturate TRIGGER→CAUSA→AZIONE→VERIFICA
dopo fallimenti/successi sorprendenti; promozione a fact procedurale per
operazioni ricorrenti; consolidamento periodico. Vietate lezioni vaghe e
promozioni senza evidenza (anti-drift). Solo prompt: nessun cambiamento
server/API.
2026-08-22 16:10:17 +02:00
Matteo Benedetto a448241ba2 fix(monitoring): migliora leggibilità dashboard qmem 2026-08-20 15:13:08 +02:00
Matteo Benedetto 94e9bb44b1 docs: sez. 11.11 istanza frigate (embedding llama.cpp) + bump v2.7.0 2026-08-18 22:48:50 +02:00
Matteo Benedetto 2626649e5a feat: backend embedding configurabile — EMBED_API=ollama|llamacpp
- llama.cpp: /v1/embeddings OpenAI-compatible con Bearer key (EMBED_API_KEY)
- ollama (default): /api/embed invariato
- EMBED_URL sostituisce OLLAMA_URL (alias retrocompatibile)
2026-08-18 22:46:26 +02:00
Matteo Benedetto b7809fc92d feat(version): endpoint /v1/version + git_commit nel build Docker
- GET /v1/version (pubblico): espone version, git_commit, guardrail_version,
  guardrail_enabled, soglie, embedding_model
- /v1/status include version, git_commit, guardrail_version
- Dockerfile: ARG GIT_COMMIT / ENV GIT_COMMIT (default unknown)
- GATEWAY_VERSION 2.7.0, GIT_COMMIT da env
- Test: 2 nuovi (version endpoint, status git_commit) — 30/30 passano
2026-08-18 16:19:36 +02:00
Matteo Benedetto eccb2cb870 feat(guardrail): similarità pre-scrittura su POST /v1/memories
Guardrail deterministico FUORI dall'LLM (stessa architettura di egeos-copilot):
- Strato 1: text_hash SHA-256 normalizzato -> BLOCK 409 (EXACT_DUPLICATE)
- Strato 2: similarità semantica top-3 BGE-M3 cosine -> BLOCK/WARN/ALLOW
  (soglie configurabili: GUARDRAIL_BLOCK_THRESHOLD 0.85, WARN 0.70)
- Supersede esplicito bypassa il guardrail (correzione intenzionale)
- text_hash e flag guardrail nel payload; audit create_blocked
- Indice payload su text_hash
- Test: 6 nuovi (duplicato esatto, similarità alta/moderata, nessun candidato,
  supersede bypass, disabilitato, text_hash) — 28/28 passano
2026-08-18 12:58:28 +02:00
Matteo Benedetto 91ec4c82d7 feat: tool qmem_get per recupero deterministico record per UUID
Aggiunge qmem_get (GET /v1/memories/{id}) per recuperare un record
esatto per memory_id: usato quando un puntatore/playbook cita un ID.
La ricerca semantica (qmem_search) non garantisce di trovare record
lunghi con query generiche; qmem_get lo risolve in modo deterministico.
Restituisce anche record superseduti (lineage/audit).
2026-08-17 18:07:42 +02:00
enne2 24634f62fe chore: url di default del gateway = https://qmem.enne2.net (era http://10.8.0.3:8082) 2026-08-17 01:51:21 +02:00
Matteo Benedetto 6b4924d0db docs: sez. 11.10 incidente backfill (upsert→update_vectors) + lezioni apprese 2026-08-16 20:41:01 +02:00
Matteo Benedetto c4bfa1d5bf fix CRITICO: backfill usa update_vectors (non upsert) — preserva payload e vettore denso
INCIDENTE 2026-08-16: l'upsert parziale in Qdrant sostituisce l'intero punto,
cancellando payload e vettori densi di tutti i record. update_vectors aggiorna
solo il vettore specificato. Recovery: 278/330 record ricostruiti dalle sessioni
pi (qmem_store/qmem_correct con memory_id), 52 persi (agenti su altre macchine).
2026-08-16 20:39:12 +02:00
Matteo Benedetto 35be152be5 docs: permanenza esplicita — expires_at omesso = memoria permanente, mai cancellata dal cleanup
- descrizione parametro expires_at in qmem_store: chiarisce che il default è permanente
- skill qmem: sezione Igiene dei record con la garanzia di permanenza
- comportamento verificato sul server: record senza expires_at non selezionato dal filtro cleanup
2026-08-16 19:58:54 +02:00
Matteo Benedetto aed962cfcd chore: bump versioni (gateway 2.6.0, estensione 1.7.0) 2026-08-16 19:56:09 +02:00
Matteo Benedetto 027ba15817 docs: sez. 11.8 reranker rimandato (criteri futuri) + 11.9 hybrid retrieval 2026-08-16 19:56:00 +02:00
Matteo Benedetto 70f3699396 test: suite pytest per il gateway (21 test) + script di verifica pre-push
- conftest: FakeQdrant in-memory + mock embed (nessuna dipendenza da Qdrant/Ollama)
- test: validazione (project_id, kind, expires_at, confidence, lunghezza), auth (422/401/429), idempotency (replay/409/key diverse), supersede (404/409/lineage), filtri search, meta, status, metrics
- scripts/check.sh: esbuild (estensione) + pytest (gateway)
- requirements-dev.txt: pytest
2026-08-16 19:53:45 +02:00
Matteo Benedetto faa4e84611 feat: metriche gateway con push a VictoriaMetrics + dashboard Grafana
- raccolta in-memory: richieste per endpoint, latenza (sum/count), errori per status, search queries/hits, punti
- push periodico (30s) a VM via /api/v1/import/prometheus (pattern energy engine, timestamp ms)
- VM_PUSH_URL/VM_PUSH_INTERVAL/METRICS_ENABLED configurabili; default host.docker.internal:8428
- endpoint /v1/metrics (auth) per verifica manuale
- dashboard Grafana versionata in monitoring/qmem-dashboard.json (provisioning: /home/enne2/domotics/grafana/dashboards/)
- verificato sul server: /v1/metrics OK, 6 serie qmem_* in VM
2026-08-16 19:51:08 +02:00
Matteo Benedetto 6c2417eab7 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
2026-08-16 19:45:18 +02:00
Matteo Benedetto eba9c19179 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)
2026-08-16 19:43:30 +02:00
Matteo Benedetto 7abced1566 feat: hybrid retrieval (BM25 + vettoriale, RRF) opt-in via hybrid=true
- sparse vector bm25 (modifier IDF) + indice TEXT su text
- migrazione automatica: create_vector_name su collection esistente + backfill dei punti privi di sparse
- write: sparse vector a ogni upsert (fastembed Qdrant/bm25)
- search: hybrid=true → prefetch denso (min_score anti-rumore) + sparso, fusione RRF; default invariato (punteggi cosine)
- qdrant-client 1.13.0 → 1.19.0 (create_vector_name, query_points; search rimosso in 1.19)
- fastembed 0.5.1 + pre-download modello BM25 nel Dockerfile (appuser)
- estensione: parametro hybrid in qmem_search
- verificato sul server: migrazione + backfill OK, termine esatto trovato con RRF 1.0 (istanza di test)
2026-08-16 19:41:42 +02:00
Matteo Benedetto 2d354bfde6 feat: X-Request-ID per richiesta (header risposta + audit log)
- middleware: genera o accetta X-Request-ID, lo restituisce in header
- contextvar letto da _audit: correlazione richieste nei log
- verificato sul server: header + audit correlati (istanza di test)
2026-08-16 19:32:29 +02:00
Matteo Benedetto a2bb659e31 docs: sez. 11.7 accesso condiviso — rischio e criteri per chiavi per-scope future 2026-08-16 19:29:22 +02:00
Matteo Benedetto 3f7c3cee51 security: hash SHA-256 della query nell'audit log (niente contenuto in chiaro)
- query_hash (16 char) al posto di query[:80]
- verificato sul server: audit con query_hash, nessuna query in chiaro
2026-08-16 19:28:01 +02:00
Matteo Benedetto f30966a77c feat: rate limit leggero (30/min per IP) su /v1/status pubblico
- endpoint pubblico per healthcheck, protetto da abusi
- verificato sul server: 36 richieste → 30x200 + 6x429 (istanza di test)
2026-08-16 19:22:18 +02:00
Matteo Benedetto 87d59ccb5c feat: validazione expires_at ISO 8601 (422 con messaggio chiaro, niente fallback silenzioso)
- field_validator Pydantic su MemoryIn.expires_at
- verificato sul server: valida OK, invalida → 422 (istanza di test)
2026-08-16 19:21:01 +02:00
Matteo Benedetto 748356d769 perf: client httpx riusato per gli embedding (lazy, chiuso a shutdown)
- _get_http(): creazione lazy, keep-alive riusato tra le chiamate
- lifespan shutdown: aclose del client
- verificato sul server: status + search OK (istanza di test)
2026-08-16 19:18:41 +02:00
Matteo Benedetto ec0fdb972a refactor: lifespan al posto di @app.on_event (deprecato) + bump v2.5.0
- startup (collection+indici) e cleanup task nel context manager lifespan
- shutdown: cancel del cleanup task
- verificato sul server: startup OK, scrittura OK (istanza di test)
2026-08-16 19:17:19 +02:00
Matteo Benedetto 25ccb13f5b security: utente non-root (appuser, uid 10001) nel Dockerfile del gateway
- verificato sul server: whoami=appuser, status OK, scrittura OK (istanza di test)
2026-08-16 19:14:54 +02:00
Matteo Benedetto 625e569389 feat: soglia di sicurezza in qmem_correct con query (correctMinScore default 0.60)
- rifiuta il supersede se lo score del top-1 è sotto soglia (evidenza debole/rumorosa)
- messaggio guida: verifica con qmem_search e riprova con memory_id esplicito
- soglia configurabile in ~/.config/pi-qmem/config.json
2026-08-16 19:13:38 +02:00
Matteo Benedetto bb182dc370 feat: retry con backoff su errori transitori + timeoutMs applicato
- gatewayRequest: max 3 retry su 429/5xx/timeout/errore rete, backoff esponenziale + jitter, rispetta Retry-After (cap 10s)
- AbortError (annullamento utente) propagato, mai ritentato
- timeoutMs dalla config usato come fallback quando pi non fornisce signal
- testato: 503→200, sempre-503 (4 tentativi), 429+Retry-After, rete giù, abort
2026-08-16 19:12:12 +02:00
Matteo Benedetto 66e898f8b5 docs: sez. 11.6 idempotency nel playbook 2026-08-16 19:10:51 +02:00
Matteo Benedetto a7d4bbb4a8 feat: idempotency su POST /v1/memories (Idempotency-Key, replay → stessa risposta, payload diverso → 409)
- gateway: tabella in-memory con TTL 24h, hash canonico del payload, scoped per API key
- estensione: crypto.randomUUID() per operazione (store e correct), riusata su retry
- from __future__ import annotations (forward-reference _payload_hash)
2026-08-16 19:10:32 +02:00
Matteo Benedetto 9cb3008f4d docs: aggiungi gateway/README.md con istruzioni di deploy (referenziato dal README principale) 2026-08-16 19:01:49 +02:00
Matteo Benedetto 13d12b59b9 feat: regole QMEM_RULES imperative con trigger (MUST/MUST NOT + sequenza errore) 2026-08-13 18:58:44 +02:00
enne2 9925c37ea0 fix: virgole orfane dopo promptGuidelines (parse error) 2026-08-13 13:37:00 +02:00
enne2 c7088d4338 feat: regole comportamentali autocontenute nell'estensione (v1.5.0)
- promptGuidelines sui 4 tool (qmem_store/search/correct/meta): bullets nel Guidelines del system prompt, solo quando i tool sono attivi
- before_agent_start: blocco 'Regole pi-qmem' iniettato nel system prompt a ogni turno (solo se i tool qmem sono attivi) — regole vincolanti versionate con l'estensione
- skills/qmem/SKILL.md: procedura completa (punteggi, project_id, supersede, discovery) standard agentskills.io, distribuita via pi.skills nel manifest
- AGENTS.md ridotto a puntatore (riepilogo essenziale + rinvio a skill/tool)
- README aggiornato
2026-08-13 13:35:53 +02:00
enne2 72ebb949c8 feat: project_id obbligatorio (gateway v2.4.0 + estensione v1.4.0)
- gateway: MemoryIn.project_id required (min_length=1) → POST senza project_id = 422
- estensione: qmem_store project_id Type.String (non più Optional), descrizione con obbligo e rinvio a qmem_meta; qmem_correct resta opzionale (eredita dal superseduto)
- README/playbook sez. 11.5 aggiornati
2026-08-13 13:24:22 +02:00
enne2 334f9c6b44 fix(gateway): with_vectors (plurale) in qdrant.scroll per /v1/meta/overview 2026-08-13 13:09:10 +02:00
enne2 4b1f13c118 feat: discovery endpoint GET /v1/meta/overview + tool qmem_meta
- gateway v2.3.0: /v1/meta/overview (auth) con scope×kind, progetti, agenti, superseduti; scroll aggregato su soli campi metadata + cache TTL 60s invalidata su POST/DELETE/cleanup; audit action 'meta'
- estensione v1.3.0: tool qmem_meta (nessun parametro) che guida la ricerca settorializzata
- README/playbook (sez. 11.4)/AGENTS.md aggiornati
2026-08-13 13:06:10 +02:00
enne2 f6d9c5872d feat: min_score anti-rumore nella ricerca + igiene metadata
- gateway v2.2.0: SearchIn.min_score → score_threshold a livello Qdrant (filtra sotto soglia), audit e risposta con min_score
- estensione v1.2.0: qmem_search con min_score default 0.45 (guida punteggi in descrizione), marker ⚠️ per score<0.60, messaggio dedicato quando 0 risultati rilevanti
- dati: eliminato record rumore ('valuta preferita EUR'), assegnati project_id mancanti via supersede (domotics, pi-qmem x2, agy-pi)
- AGENTS.md: sezione interpretazione punteggi
2026-08-13 13:02:37 +02:00
enne2 1891f22a5e fix(qmem_correct): eredita kind/scope/project_id anche quando memory_id è passato direttamente (GET del record prima del supersede) 2026-08-13 12:42:58 +02:00
enne2 1713e68b82 feat: supersede di memorie false (qmem_correct, include_superseded, playbook sez. 11)
- gateway: supersedes_id validato (404/409), backlink superseded_by+superseded_at+supersede_reason sul vecchio record, indici keyword, search esclude i superseduti di default (include_superseded per lineage), risposta con lineage
- estensione: tool qmem_correct (memory_id o query), qmem_store con supersedes_id/supersede_reason, qmem_search con include_superseded
- README/playbook aggiornati, versione 1.1.0
2026-08-13 12:41:14 +02:00
enne2 eadd2a756b pi-qmem: memoria centralizzata condivisa per agenti AI (estensione pi + gateway) 2026-08-11 23:14:40 +02:00