Visión General de la Arquitectura del Sistema¶
Este documento describe la arquitectura de alto nivel, los componentes en tiempo de ejecución, el esquema de la base de datos y el modelo de colas de Bruce.
1. Filosofía de Arquitectura¶
Bruce está diseñado en torno a cinco principios fundamentales:
- Binario Único Autónomo: Compilado como un único ejecutable Go independiente con todos los recursos del panel web integrados mediante
go:embed. No requiere runtime de Node.js, dependencias de Python ni servidor web estático externo. - Inyección Explícita de Dependencias: Sin marcos mágicos de reflexión, contenedores DI (como Uber FX) ni ORM pesados. Todos los componentes se instancian y configuran explícitamente en
cmd/bruce/main.go. - Soberanía de Datos Local-First: Todo el estado (sesiones, mensajes, tareas proactivas, resúmenes, configuraciones) reside en una base de datos local SQLite operando en modo Write-Ahead Logging (
WAL). - Desacoplamiento Asíncrono vía Redis: Los mensajes entrantes de todos los conectores se convierten en tareas serializables y se envían a Redis a través de Asynq. Los conectores nunca se bloquean esperando llamadas lentas a LLM, ejecuciones de herramientas o reintentos de API.
- Abstracción de IA Multiproveedor: El worker central interactúa con los LLM a través de interfaces estandarizadas (
LLMService), lo que permite alternar sin problemas entre Claude, Gemini y OpenAI.
2. Arquitectura de Ejecución en Alto Nivel¶
flowchart TD
subgraph Clients ["Plataformas de Clientes"]
WA[WhatsApp]
DC[Discord]
TG[Telegram]
WEB[Navegador Web]
end
subgraph Ingestion ["Capa de Ingesta y HTTP"]
C_WA[Conector WhatsApp\nwhatsmeow]
C_DC[Conector Discord\ndiscordgo]
C_TG[Conector Telegram\nLong Polling]
HTTP[Servidor HTTP :8080\nWeb UI & REST API]
end
subgraph QueueLayer ["Cola de Tareas y Sondeo"]
R[(Redis)]
POLLER[Sondeador del Programador\nIntervalo de 1 minuto]
end
subgraph WorkerCore ["Core Worker (Asynq)"]
PROC[Procesador Worker]
LOOP[Bucle del Agente Autónomo\nRunAgentLoop]
TREG[Registro de Herramientas]
end
subgraph AIProviders ["Servicios Externos de IA"]
CLAUDE[Anthropic Claude]
GEMINI[Google Gemini]
OPENAI[OpenAI GPT]
end
subgraph Persistence ["Capa de Persistencia"]
SQLITE[(Base de Datos SQLite\nModo WAL)]
FS[Almacenamiento en Disco\n./data/artifacts]
end
WA --> C_WA
DC --> C_DC
TG --> C_TG
WEB --> HTTP
C_WA & C_DC & C_TG & HTTP -->|Encolar message:process| R
POLLER -->|Encolar proactive:execute| R
R -->|Desencolar Tarea| PROC
PROC -->|Cargar historial y contexto| SQLITE
PROC --> LOOP
LOOP <--> TREG
LOOP <--> CLAUDE & GEMINI & OPENAI
TREG -->|Guardar Artefactos HTML| FS
PROC -->|Persistir mensajes y registros| SQLITE
PROC -->|Enviar respuesta| C_WA & C_DC & C_TG & HTTP
3. Cola de Tareas Asynq y Tipos de Trabajos¶
Bruce utiliza Asynq sobre Redis para garantizar una ejecución en segundo plano confiable, reintentos automáticos y resiliencia ante límites de frecuencia.
| Tipo de Tarea | Carga Útil de Cola | Tiempo Límite | Descripción |
|---|---|---|---|
message:process |
ProcessIncomingMessagePayload |
180s | Ingesta un mensaje de usuario desde Discord, WhatsApp, Telegram o Web Chat, ejecuta el bucle del agente y envía la respuesta. |
proactive:execute_report |
ExecuteScheduledReportPayload |
180s | Ejecuta una tarea programada vencida. Si mode: "message", envía directamente. Si mode: "agent", ejecuta el bucle con herramientas. |
proactive:evaluate_watch |
EvaluateWatchPayload |
45s | Evalúa una condición ambiental con herramientas específicas y comprueba cambios de hash. |
session:summarize |
SummarizeSessionPayload |
60s | Comprime periódicamente el historial antiguo de conversaciones largas en un resumen conciso en Markdown. |
4. Esquema de Base de Datos SQLite¶
Bruce utiliza SQLite con claves foráneas y modo WAL habilitado (_journal_mode=WAL&_busy_timeout=5000).
Tablas Principales:¶
┌──────────────────┐ ┌──────────────────────┐
│ sessions │◀─────┼│ messages │
├──────────────────┤ 1 N ├──────────────────────┤
│ id (PK) │ │ id (PK) │
│ connector_type │ │ session_id (FK) │
│ channel_id │ │ role (user/assistant)│
│ is_active │ │ content │
│ system_prompt │ │ timestamp │
└────────┬─────────┘ └──────────────────────┘
│
│ 1
│
▼ N
┌─────────────────────────┐ ┌──────────────────────┐
│ proactive_tasks │ │ session_summaries │
├─────────────────────────┤ ├──────────────────────┤
│ id (PK) │ │ session_id (PK, FK) │
│ session_id (FK) │ │ summary │
│ title │ │ last_summarized_msg │
│ task_type (cron/watch) │ │ message_count │
│ execution_mode (msg/agt)│ │ updated_at │
│ schedule_expr │ └──────────────────────┘
│ prompt_condition │
│ is_active │ ┌──────────────────────┐
│ next_run_at │ │ tool_executions │
└─────────────────────────┘ ├──────────────────────┤
│ id (PK) │
┌─────────────────────────┐ │ session_id │
│ config_entries │ │ tool_name │
├─────────────────────────┤ │ input_json │
│ key (PK) │ │ output_json │
│ value │ │ executed_at │
│ updated_at │ └──────────────────────┘
└─────────────────────────┘
sessions: Representa una conversación individual identificada por(connector_type, channel_id).messages: Registro cronológico de mensajes del usuario y respuestas del asistente.proactive_tasks: Programaciones y monitoreos de condiciones con modo de ejecución (messagevsagent).session_summaries: Resúmenes continuos de conversaciones pasadas para mantener el contexto más allá del límite de tokens.tool_executions: Registro de auditoría de cada ejecución de herramienta, entradas y resultados.config_entries: Modificaciones dinámicas de configuración administradas mediante la interfaz web y la API.oauth_tokens: Tokens de acceso y actualización cifrados para integraciones de Google Workspace.
5. Ciclos de Vida y Cierre Controlado (Graceful Shutdown)¶
Cuando Bruce recibe una señal de terminación (SIGINT o SIGTERM):
1. Servidor HTTP: Llama a server.Shutdown(ctx) con un tiempo límite de 10 segundos, rechazando nuevas conexiones mientras completa las solicitudes en curso.
2. Sondeador del Programador: Detiene el ticker de 1 minuto.
3. Procesamiento de Asynq: Llama a asynqServer.Shutdown(), esperando que los workers activos completen sus tareas sin pérdida de datos.
4. Conectores:
- Discord: Cierra la sesión WebSocket de la pasarela (discordgo.Close()).
- WhatsApp: Desconecta el cliente whatsmeow de forma segura.
- Telegram: Detiene el bucle de sondeo (long-polling).
5. Base de Datos: Cierra de forma segura el grupo de conexiones de SQLite, realizando el punto de control de los archivos WAL.