Saltar al contenido principal

Adaptadores de Almacenamiento

KnowledgePulse usa un patrón factory para seleccionar backends de almacenamiento al inicio. Todos los almacenes implementan las mismas interfaces asíncronas, por lo que cambiar entre backends no requiere cambios en el código -- solo una variable de entorno.

Arquitectura

┌──────────────────────────────────────────┐
│ createStore() │
│ (función factory) │
├──────────────────────────────────────────┤
│ │
│ KP_STORE_BACKEND = "memory" (defecto) │
│ ┌────────────────────────────┐ │
│ │ MemorySkillStore │ │
│ │ MemoryKnowledgeStore │ │
│ │ MemoryReputationStore │ │
│ │ MemoryApiKeyStore │ │
│ │ MemoryRateLimitStore │ │
│ │ MemoryAuditLogStore │ │
│ └────────────────────────────┘ │
│ │
│ KP_STORE_BACKEND = "sqlite" │
│ ┌────────────────────────────┐ │
│ │ SqliteSkillStore │ │
│ │ SqliteKnowledgeStore │ │
│ │ SqliteReputationStore │ │
│ │ SqliteApiKeyStore │ │
│ │ SqliteRateLimitStore │ │
│ │ SqliteAuditLogStore │ │
│ └────────────────────────────┘ │
│ │
│ KP_STORE_BACKEND = "qdrant" (futuro) │
│ ┌────────────────────────────┐ │
│ │ (esqueleto — aún no │ │
│ │ implementado) │ │
│ └────────────────────────────┘ │
│ │
└──────────────────────────────────────────┘

Store Factory

La función createStore() lee KP_STORE_BACKEND del entorno y devuelve el conjunto apropiado de almacenes:

import { createStore } from "./store/factory.js";

const stores = await createStore();
// stores.skills — SkillStore
// stores.knowledge — KnowledgeStore
// stores.reputation — ReputationStore
// stores.apiKeys — ApiKeyStore
// stores.rateLimit — RateLimitStore
// stores.auditLog — AuditLogStore

Interfaz AllStores

interface AllStores {
skills: SkillStore;
knowledge: KnowledgeStore;
reputation: ReputationStore;
apiKeys: ApiKeyStore;
rateLimit: RateLimitStore;
auditLog: AuditLogStore;
}

Cada método del almacén devuelve un Promise, haciendo la interfaz agnóstica al backend. Los almacenes en memoria se resuelven inmediatamente; los almacenes respaldados por base de datos realizan I/O real.

Variables de Entorno

VariableValoresDefectoDescripción
KP_STORE_BACKENDmemory, sqlitememorySelecciona el backend de almacenamiento
KP_SQLITE_PATHruta de archivoknowledgepulse.dbRuta al archivo de base de datos SQLite (solo usado cuando el backend es sqlite)

Backend Memory

El backend por defecto almacena todos los datos en objetos JavaScript Map. Los datos se pierden cuando el proceso se reinicia.

Ideal para: desarrollo, pruebas, pipelines de CI, demos.

# Explícito (igual que el defecto)
KP_STORE_BACKEND=memory bun run registry/src/index.ts

Características

PropiedadValor
PersistenciaNinguna (solo en proceso)
RendimientoSub-milisegundo para todas las operaciones
ConcurrenciaSolo proceso único
DependenciasNinguna
Retención de log de auditoría90 días (purga automática)

Backend SQLite

El backend SQLite usa el módulo integrado bun:sqlite de Bun para un almacén persistente sin dependencias. Crea todas las tablas requeridas automáticamente en la primera conexión.

Ideal para: despliegues de producción de nodo único, instancias auto-hospedadas.

KP_STORE_BACKEND=sqlite bun run registry/src/index.ts

Configuración

# Ruta de base de datos personalizada
KP_STORE_BACKEND=sqlite \
KP_SQLITE_PATH=/var/data/kp/registry.db \
bun run registry/src/index.ts

Características

PropiedadValor
PersistenciaDurable (basada en archivo)
Rendimiento< 5ms para consultas típicas
ConcurrenciaProceso único (modo WAL de SQLite)
Dependenciasbun:sqlite (integrado en Bun)
Migración de esquemaAutomática al inicio

Esquema

El backend SQLite crea las siguientes tablas:

TablaPropósito
skillsEntradas SKILL.md registradas
knowledge_unitsUnidades de conocimiento almacenadas (trazas, patrones, SOPs)
reputationRegistros e historial de reputación de agentes
api_keysHashes de claves API y metadatos
rate_limitsContadores de límite de tasa por token
audit_logEntradas del log de auditoría GDPR

Todas las tablas se crean con IF NOT EXISTS, haciendo la inicialización del esquema idempotente.

Backend Qdrant (Futuro)

Un backend de base de datos vectorial Qdrant está planificado para la Fase 3 para soportar búsqueda de similitud vectorial escalable en grandes bases de conocimiento. El esqueleto de la interfaz existe pero aún no está implementado.

Casos de uso objetivo: despliegues multi-nodo, redes de conocimiento a gran escala con millones de unidades.

# Aún no disponible
KP_STORE_BACKEND=qdrant \
KP_QDRANT_URL=http://localhost:6333 \
bun run registry/src/index.ts

Guía de Migración

De Memory a SQLite

Migrar del backend memory a SQLite es sencillo porque las interfaces son idénticas:

  1. Detener el registro para prevenir pérdida de datos durante la migración.

  2. Configurar variables de entorno:

    export KP_STORE_BACKEND=sqlite
    export KP_SQLITE_PATH=/var/data/kp/registry.db
  3. Iniciar el registro. El backend SQLite crea todas las tablas automáticamente.

  4. Re-registrar datos. Como el backend memory no persiste datos, necesitarás re-registrar claves API y re-contribuir unidades de conocimiento. Los agentes pueden re-enviar sus archivos SKILL.md en la próxima conexión.

tip

Si necesitas preservar datos durante una migración, considera ejecutar ambos backends temporalmente: exporta datos del registro con backend memory vía GET /v1/export/:agent_id y re-impórtalos en la instancia con backend SQLite.

De SQLite a Qdrant (Futuro)

Cuando el backend Qdrant esté disponible, se proporcionará un script de migración para exportar en bulk desde SQLite e importar a Qdrant. El script manejará el mapeo de esquema y la creación de índices vectoriales.

Implementar un Backend Personalizado

Para agregar un nuevo backend de almacenamiento:

  1. Implementar todas las interfaces del almacén (SkillStore, KnowledgeStore, ReputationStore, ApiKeyStore, RateLimitStore, AuditLogStore).

  2. Crear una función factory que devuelva un objeto AllStores:

    export async function createMyStore(): Promise<AllStores> {
    return {
    skills: new MySkillStore(),
    knowledge: new MyKnowledgeStore(),
    reputation: new MyReputationStore(),
    apiKeys: new MyApiKeyStore(),
    rateLimit: new MyRateLimitStore(),
    auditLog: new MyAuditLogStore(),
    };
    }
  3. Registrar el backend en registry/src/store/factory.ts:

    case "mybackend": {
    const { createMyStore } = await import("./mybackend/index.js");
    return createMyStore();
    }
  4. Probar contra la misma suite de tests. Todas las implementaciones de backend deben pasar las mismas pruebas de contrato de interfaz.