merge: issue/0027-prune-config-schema — implementación paralela
# Conflicts: # dev/issues/README.md
This commit is contained in:
+79
-231
@@ -1,51 +1,48 @@
|
||||
# ============================================
|
||||
# AGENTE PLANTILLA
|
||||
# ============================================
|
||||
# Este archivo sirve como referencia canonica para la configuracion de todos los agentes.
|
||||
# NO se lanza (template: true). Copiar y adaptar para crear nuevos agentes.
|
||||
# Referencia canonica de configuracion. NO se lanza (template: true).
|
||||
# Copiar y adaptar para nuevos agentes. Solo incluye campos funcionales.
|
||||
|
||||
agent:
|
||||
id: "_template"
|
||||
name: "Template Agent"
|
||||
version: "0.0.0"
|
||||
enabled: true
|
||||
template: true # el launcher ignora este agente
|
||||
description: "Agente plantilla. No se lanza. Sirve como referencia para crear nuevos agentes."
|
||||
template: true # el launcher ignora este agente
|
||||
description: "Agente plantilla. No se lanza."
|
||||
tags: [template]
|
||||
|
||||
# ============================================
|
||||
# PERSONALIDAD Y COMPORTAMIENTO
|
||||
# ============================================
|
||||
personality:
|
||||
# --- Identidad narrativa ---
|
||||
role: "asistente general"
|
||||
backstory: "Un asistente amigable creado para ayudar con tareas cotidianas."
|
||||
expertise: [general]
|
||||
limitations: []
|
||||
|
||||
# --- Estilo basico ---
|
||||
tone: friendly # direct | friendly | formal | casual | technical
|
||||
verbosity: concise # minimal | concise | detailed | verbose
|
||||
tone: friendly # direct | friendly | formal | casual | technical
|
||||
verbosity: concise # minimal | concise | detailed | verbose
|
||||
language: es
|
||||
languages_supported: [es, en]
|
||||
emoji_style: minimal # none | minimal | moderate | heavy
|
||||
emoji_style: minimal # none | minimal | moderate | heavy
|
||||
prefix: ""
|
||||
error_style: helpful # terse | helpful | detailed
|
||||
error_style: helpful # terse | helpful | detailed
|
||||
|
||||
# --- Comunicacion avanzada ---
|
||||
# Identidad narrativa (opcional)
|
||||
role: ""
|
||||
backstory: ""
|
||||
expertise: []
|
||||
limitations: []
|
||||
|
||||
# Comunicacion avanzada (opcional)
|
||||
communication:
|
||||
formality: semiformal # formal | semiformal | casual | coloquial
|
||||
humor: none # none | subtle | moderate | frequent
|
||||
personality: pragmatic # analytical | creative | pragmatic | empathetic | assertive
|
||||
response_style: structured # structured | conversational | bullet_points | narrative
|
||||
quirks: [] # rasgos unicos del personaje
|
||||
avoid_topics: [] # temas a evitar
|
||||
catchphrases: [] # frases tipicas
|
||||
formality: semiformal # formal | semiformal | casual | coloquial
|
||||
humor: none # none | subtle | moderate | frequent
|
||||
personality: pragmatic # analytical | creative | pragmatic | empathetic | assertive
|
||||
response_style: structured # structured | conversational | bullet_points | narrative
|
||||
quirks: []
|
||||
avoid_topics: []
|
||||
catchphrases: []
|
||||
|
||||
# --- Directivas libres ---
|
||||
custom_directives: [] # instrucciones extra para el system prompt
|
||||
custom_directives: []
|
||||
|
||||
# --- Templates de respuesta ---
|
||||
templates:
|
||||
greeting: "Hola, soy {name}. En que puedo ayudarte?"
|
||||
unknown_command: "No entiendo ese comando. Usa !help."
|
||||
@@ -54,7 +51,6 @@ personality:
|
||||
success: "{{.Summary}}"
|
||||
busy: "Estoy procesando otra solicitud, un momento..."
|
||||
|
||||
# --- Comportamiento ---
|
||||
behavior:
|
||||
proactive: false
|
||||
ask_confirmation: false
|
||||
@@ -64,49 +60,45 @@ personality:
|
||||
acknowledge_receipt: false
|
||||
|
||||
# ============================================
|
||||
# LLM — CONEXION Y RAZONAMIENTO
|
||||
# LLM
|
||||
# ============================================
|
||||
llm:
|
||||
primary:
|
||||
provider: openai # openai | anthropic | claude-code
|
||||
provider: openai # openai | anthropic | claude-code
|
||||
model: "gpt-4o"
|
||||
api_key_env: OPENAI_API_KEY
|
||||
base_url: "" # opcional: custom endpoint
|
||||
base_url: ""
|
||||
max_tokens: 4096
|
||||
temperature: 0.7
|
||||
|
||||
# Claude Code: subproceso claude -p (solo si provider: claude-code)
|
||||
# Solo si provider: claude-code
|
||||
claude_code:
|
||||
binary: "claude"
|
||||
timeout: 3m
|
||||
disable_tools: false
|
||||
allowed_tools: [] # vacio = permitir todas
|
||||
allowed_tools: []
|
||||
disallowed_tools: []
|
||||
working_dir: "" # default: tmpdir aislado
|
||||
permission_mode: "default" # default | acceptEdits | bypassPermissions | plan
|
||||
model: "sonnet" # sonnet | opus | haiku | full model name
|
||||
working_dir: "" # IMPORTANTE: configurar fuera del repo
|
||||
permission_mode: "default"
|
||||
model: "sonnet"
|
||||
fallback_model: ""
|
||||
session_id: ""
|
||||
add_dirs: []
|
||||
|
||||
# Fallback LLM (opcional)
|
||||
fallback:
|
||||
provider: ""
|
||||
model: ""
|
||||
api_key_env: ""
|
||||
base_url: ""
|
||||
max_tokens: 0
|
||||
temperature: 0
|
||||
|
||||
reasoning:
|
||||
system_prompt_file: "prompts/system.md" # relativo a agents/<id>/
|
||||
system_prompt_file: "prompts/system.md"
|
||||
context_window: 16384
|
||||
memory_messages: 30 # mensajes previos a incluir en el contexto
|
||||
memory_messages: 30
|
||||
|
||||
tool_use:
|
||||
enabled: false # habilitar function calling
|
||||
max_iterations: 5 # ciclos tool-call → execute → feedback
|
||||
parallel_calls: false # permitir llamadas paralelas a tools
|
||||
enabled: false
|
||||
max_iterations: 5
|
||||
parallel_calls: false
|
||||
|
||||
rate_limit:
|
||||
requests_per_minute: 60
|
||||
@@ -114,89 +106,80 @@ llm:
|
||||
concurrent_requests: 5
|
||||
|
||||
# ============================================
|
||||
# TOOLS — HERRAMIENTAS DISPONIBLES
|
||||
# TOOLS
|
||||
# ============================================
|
||||
tools:
|
||||
ssh:
|
||||
enabled: false
|
||||
allowed_targets: [] # lista de targets definidos en ssh.targets
|
||||
allowed_commands: [] # allowlist: si no esta vacio, solo estos comandos
|
||||
forbidden_commands: [] # blocklist
|
||||
allowed_targets: []
|
||||
allowed_commands: []
|
||||
forbidden_commands: []
|
||||
timeout: 30s
|
||||
max_concurrent: 3
|
||||
require_confirmation: [] # comandos que necesitan confirmacion
|
||||
require_confirmation: []
|
||||
|
||||
http:
|
||||
enabled: false
|
||||
allowed_domains: [] # si no esta vacio, solo estos dominios
|
||||
allowed_domains: []
|
||||
timeout: 10s
|
||||
max_retries: 2
|
||||
|
||||
scripts:
|
||||
enabled: false
|
||||
scripts_dir: "./scripts"
|
||||
allowed: [] # si no esta vacio, solo estos scripts
|
||||
allowed: []
|
||||
timeout: 60s
|
||||
sandbox: false
|
||||
|
||||
file_ops:
|
||||
enabled: false
|
||||
allowed_paths: [] # si no esta vacio, solo estos paths
|
||||
allowed_paths: []
|
||||
read_only: true
|
||||
|
||||
matrix_send:
|
||||
allowed_rooms: [] # si no esta vacio, solo enviar a estos rooms
|
||||
allowed_rooms: []
|
||||
|
||||
mcp:
|
||||
enabled: false
|
||||
servers: [] # lista de servidores MCP externos
|
||||
# Ejemplo:
|
||||
# - name: "filesystem"
|
||||
# transport: stdio
|
||||
# command: "npx"
|
||||
# args: ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/data"]
|
||||
# env: {}
|
||||
# tools: [] # filtro: solo estas tools (vacio = todas)
|
||||
# prefix: "fs_" # prefijo para evitar colisiones
|
||||
# timeout: 30s
|
||||
servers: []
|
||||
expose:
|
||||
port: 0 # exponer las tools propias via MCP server
|
||||
tools: [] # tools a exponer (vacio = todas)
|
||||
port: 0
|
||||
tools: []
|
||||
|
||||
memory:
|
||||
enabled: false # tool para acceder a memoria del agente
|
||||
enabled: false
|
||||
|
||||
knowledge:
|
||||
enabled: false
|
||||
dir: "./knowledge" # knowledge privado del agente
|
||||
dir: "./knowledge"
|
||||
|
||||
shared_knowledge:
|
||||
enabled: false
|
||||
dir: "knowledges" # knowledge compartido entre agentes
|
||||
dir: "knowledges"
|
||||
db_path: "knowledges/data/knowledge.db"
|
||||
|
||||
skills:
|
||||
allowed_interpreters: ["bash", "sh"] # interpretes permitidos para skills
|
||||
allowed_interpreters: ["bash", "sh"]
|
||||
|
||||
# ============================================
|
||||
# SKILLS — SISTEMA DE SKILLS
|
||||
# SKILLS
|
||||
# ============================================
|
||||
skills:
|
||||
enabled: false
|
||||
path: "skills/" # ruta base de skills (relativa al proyecto)
|
||||
categories: [] # vacio = todas las categorias | ["devops", "system"] = filtradas
|
||||
timeout: 60s # timeout para ejecucion de scripts
|
||||
path: "skills/"
|
||||
categories: []
|
||||
timeout: 60s
|
||||
|
||||
# ============================================
|
||||
# MEMORIA — VENTANA DE CONVERSACION
|
||||
# MEMORIA
|
||||
# ============================================
|
||||
memory:
|
||||
enabled: false
|
||||
window_size: 20 # mensajes por room en ventana deslizante
|
||||
db_path: "" # default: agents/<id>/data/memory.db
|
||||
window_size: 20
|
||||
db_path: ""
|
||||
|
||||
# ============================================
|
||||
# MATRIX — CONEXION Y ROOMS
|
||||
# MATRIX
|
||||
# ============================================
|
||||
matrix:
|
||||
homeserver: "https://matrix.example.com"
|
||||
@@ -208,51 +191,29 @@ matrix:
|
||||
enabled: false
|
||||
store_path: "./agents/_template/data/crypto/"
|
||||
pickle_key_env: PICKLE_KEY_TEMPLATE
|
||||
trust_mode: tofu # tofu | cross-signing | manual
|
||||
recovery_key_env: "" # SSSS recovery key para cross-signing
|
||||
trust_mode: tofu
|
||||
recovery_key_env: ""
|
||||
|
||||
rooms:
|
||||
listen: [] # rooms donde escuchar sin responder
|
||||
respond: [] # rooms donde responder automaticamente
|
||||
admin: [] # rooms de admin (para comandos especiales)
|
||||
listen: []
|
||||
respond: []
|
||||
admin: []
|
||||
|
||||
filters:
|
||||
command_prefix: "!"
|
||||
mention_respond: true # responder a menciones
|
||||
dm_respond: true # responder a DMs
|
||||
mention_respond: true
|
||||
dm_respond: true
|
||||
ignore_bots: true
|
||||
ignore_users: []
|
||||
unauthorized_response: silent # silent | explicit
|
||||
unauthorized_response: silent
|
||||
min_power_level: 0
|
||||
|
||||
threads:
|
||||
enabled: true # responder en threads si el mensaje viene de un thread
|
||||
auto_thread: false # crear thread automatico por cada conversacion nueva
|
||||
enabled: true
|
||||
auto_thread: false
|
||||
|
||||
# ============================================
|
||||
# COMUNICACION INTER-AGENTES
|
||||
# ============================================
|
||||
agents:
|
||||
peers: []
|
||||
# Ejemplo:
|
||||
# - id: other-agent
|
||||
# capabilities: [devops, monitoring]
|
||||
# room: "!roomid:server.com"
|
||||
|
||||
delegation:
|
||||
enabled: false
|
||||
can_delegate_to: []
|
||||
can_receive_from: []
|
||||
max_delegation_depth: 1
|
||||
timeout: 30s
|
||||
|
||||
protocol:
|
||||
format: json # json | protobuf | msgpack
|
||||
channel: matrix # matrix | grpc | channel
|
||||
heartbeat_interval: 60s
|
||||
|
||||
# ============================================
|
||||
# SSH — INVENTARIO DE SERVIDORES
|
||||
# SSH INVENTORY
|
||||
# ============================================
|
||||
ssh:
|
||||
defaults:
|
||||
@@ -262,152 +223,39 @@ ssh:
|
||||
known_hosts: "~/.ssh/known_hosts"
|
||||
keepalive_interval: 30s
|
||||
timeout: 60s
|
||||
|
||||
targets: {}
|
||||
# Ejemplo:
|
||||
# prod-web:
|
||||
# hosts: ["web01.example.com", "web02.example.com"]
|
||||
# user: "deploy"
|
||||
# port: 22
|
||||
# key_file_env: SSH_KEY_PROD
|
||||
# bastion:
|
||||
# hosts: ["bastion.example.com"]
|
||||
# user: "admin"
|
||||
|
||||
# ============================================
|
||||
# PERMISOS Y SEGURIDAD
|
||||
# SEGURIDAD
|
||||
# ============================================
|
||||
security:
|
||||
# Nota: roles/audit/secrets aqui son legacy. Usar security/ centralizado.
|
||||
|
||||
audit:
|
||||
enabled: false
|
||||
log_file: "./agents/_template/data/audit.log"
|
||||
log_file: ""
|
||||
log_to_room: ""
|
||||
include: []
|
||||
|
||||
secrets:
|
||||
provider: env # env | vault | sops
|
||||
provider: env
|
||||
|
||||
# Sanitizacion de prompts (deteccion de injection)
|
||||
sanitize:
|
||||
enabled: false
|
||||
mode: warn # warn | strip | reject
|
||||
min_severity: medium # low | medium | high
|
||||
mode: warn
|
||||
min_severity: medium
|
||||
disabled_patterns: []
|
||||
|
||||
# Rate limiting de tools por room
|
||||
tool_rate_limit:
|
||||
enabled: false
|
||||
max_calls_per_min: 10
|
||||
cleanup_interval_s: 60
|
||||
|
||||
# ============================================
|
||||
# SCHEDULING — AUTOMATIZACIONES CRON
|
||||
# SCHEDULING
|
||||
# ============================================
|
||||
schedules: []
|
||||
# Ejemplo 1: enviar mensaje (send_message)
|
||||
# - name: "buenos-dias"
|
||||
# cron: "0 9 * * 1-5" # lunes a viernes a las 9am
|
||||
# action:
|
||||
# kind: send_message
|
||||
# message: "Buenos dias equipo!" # inline
|
||||
# # template: "prompts/daily.md" # o desde archivo
|
||||
# output_room: "!roomid:server.com"
|
||||
# on_failure:
|
||||
# notify_room: "!admin:server.com"
|
||||
# escalate_to: ""
|
||||
|
||||
# Ejemplo 2: ejecutar tool (run_tool)
|
||||
# - name: "check-disk"
|
||||
# cron: "0 */6 * * *" # cada 6 horas
|
||||
# action:
|
||||
# kind: run_tool
|
||||
# target: ssh_exec
|
||||
# command: "df -h"
|
||||
# output_room: "!ops:server.com"
|
||||
# on_failure:
|
||||
# notify_room: "!admin:server.com"
|
||||
|
||||
# Ejemplo 3: prompt LLM (llm_prompt)
|
||||
# - name: "resumen-logs"
|
||||
# cron: "0 18 * * *" # diario a las 6pm
|
||||
# action:
|
||||
# kind: llm_prompt
|
||||
# prompt: "Dame un resumen de los logs del dia."
|
||||
# output_room: "!ops:server.com"
|
||||
# on_failure:
|
||||
# notify_room: ""
|
||||
|
||||
# ============================================
|
||||
# OBSERVABILIDAD
|
||||
# ============================================
|
||||
observability:
|
||||
logging:
|
||||
level: info # debug | info | warn | error
|
||||
format: json # json | text
|
||||
output: stdout # stdout | file
|
||||
file: "./agents/_template/data/template.log"
|
||||
|
||||
metrics:
|
||||
enabled: false
|
||||
port: 9090
|
||||
path: /metrics
|
||||
export: prometheus # prometheus | datadog | ...
|
||||
|
||||
health:
|
||||
enabled: true
|
||||
port: 8080
|
||||
path: /healthz
|
||||
|
||||
tracing:
|
||||
enabled: false
|
||||
provider: "" # jaeger | zipkin | datadog
|
||||
endpoint: ""
|
||||
|
||||
# ============================================
|
||||
# RESILIENCIA
|
||||
# ============================================
|
||||
resilience:
|
||||
circuit_breaker:
|
||||
failure_threshold: 5 # abrir tras N fallos consecutivos
|
||||
timeout: 30s # tiempo en open antes de half-open
|
||||
half_open_max: 2 # intentos en half-open antes de cerrar
|
||||
|
||||
retry:
|
||||
max_attempts: 2
|
||||
backoff: exponential # fixed | exponential
|
||||
initial_delay: 1s
|
||||
max_delay: 10s
|
||||
|
||||
shutdown:
|
||||
timeout: 10s # tiempo maximo para graceful shutdown
|
||||
drain_messages: true # procesar mensajes pendientes
|
||||
save_state: false
|
||||
state_file: ""
|
||||
|
||||
queue:
|
||||
enabled: true
|
||||
max_size: 100
|
||||
priority_users: [] # usuarios con prioridad
|
||||
|
||||
# ============================================
|
||||
# ALMACENAMIENTO Y ESTADO
|
||||
# STORAGE
|
||||
# ============================================
|
||||
storage:
|
||||
base_path: "" # root para datos; default: $AGENTS_DATA_DIR/<id> o agents/<id>/data
|
||||
|
||||
state:
|
||||
backend: sqlite # sqlite | redis | file
|
||||
path: "./agents/_template/data/template.db"
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
backend: memory # memory | redis
|
||||
ttl: 5m
|
||||
max_entries: 200
|
||||
|
||||
history:
|
||||
backend: sqlite
|
||||
path: "./agents/_template/data/history.db"
|
||||
retention: 168h # 7 dias
|
||||
base_path: ""
|
||||
|
||||
@@ -175,27 +175,6 @@ matrix:
|
||||
enabled: true # responder en threads cuando el mensaje viene de un thread
|
||||
auto_thread: false # true para crear thread automático por cada conversación nueva
|
||||
|
||||
# ============================================
|
||||
# COMUNICACIÓN INTER-AGENTES
|
||||
# ============================================
|
||||
agents:
|
||||
peers:
|
||||
- id: assistant-bot
|
||||
capabilities: [general, llm]
|
||||
room: ""
|
||||
|
||||
delegation:
|
||||
enabled: false
|
||||
can_delegate_to: []
|
||||
can_receive_from: [assistant-bot]
|
||||
max_delegation_depth: 1
|
||||
timeout: 30s
|
||||
|
||||
protocol:
|
||||
format: json
|
||||
channel: matrix
|
||||
heartbeat_interval: 60s
|
||||
|
||||
# ============================================
|
||||
# SSH — no aplica para este bot
|
||||
# ============================================
|
||||
@@ -228,72 +207,7 @@ security:
|
||||
schedules: []
|
||||
|
||||
# ============================================
|
||||
# OBSERVABILIDAD
|
||||
# ============================================
|
||||
observability:
|
||||
logging:
|
||||
level: info
|
||||
format: json
|
||||
output: stdout
|
||||
file: "./agents/asistente-2/data/asistente-2.log"
|
||||
|
||||
metrics:
|
||||
enabled: false
|
||||
port: 9092
|
||||
path: /metrics
|
||||
export: prometheus
|
||||
|
||||
health:
|
||||
enabled: true
|
||||
port: 8082
|
||||
path: /healthz
|
||||
|
||||
tracing:
|
||||
enabled: false
|
||||
provider: ""
|
||||
endpoint: ""
|
||||
|
||||
# ============================================
|
||||
# RESILIENCIA
|
||||
# ============================================
|
||||
resilience:
|
||||
circuit_breaker:
|
||||
failure_threshold: 5
|
||||
timeout: 30s
|
||||
half_open_max: 2
|
||||
|
||||
retry:
|
||||
max_attempts: 2
|
||||
backoff: exponential
|
||||
initial_delay: 1s
|
||||
max_delay: 10s
|
||||
|
||||
shutdown:
|
||||
timeout: 10s
|
||||
drain_messages: true
|
||||
save_state: false
|
||||
state_file: ""
|
||||
|
||||
queue:
|
||||
enabled: true
|
||||
max_size: 100
|
||||
priority_users: ["@admin:matrix-af2f3d.organic-machine.com"]
|
||||
|
||||
# ============================================
|
||||
# ALMACENAMIENTO Y ESTADO
|
||||
# STORAGE
|
||||
# ============================================
|
||||
storage:
|
||||
state:
|
||||
backend: sqlite
|
||||
path: "./agents/asistente-2/data/asistente-2.db"
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
backend: memory
|
||||
ttl: 5m
|
||||
max_entries: 200
|
||||
|
||||
history:
|
||||
backend: sqlite
|
||||
path: "./agents/asistente-2/data/history.db"
|
||||
retention: 168h # 7 días
|
||||
base_path: ""
|
||||
|
||||
@@ -169,24 +169,6 @@ matrix:
|
||||
enabled: true # responder en threads cuando el mensaje viene de un thread
|
||||
auto_thread: false # true para crear thread automático por cada conversación nueva
|
||||
|
||||
# ============================================
|
||||
# COMUNICACIÓN INTER-AGENTES
|
||||
# ============================================
|
||||
agents:
|
||||
peers: []
|
||||
|
||||
delegation:
|
||||
enabled: false
|
||||
can_delegate_to: []
|
||||
can_receive_from: []
|
||||
max_delegation_depth: 1
|
||||
timeout: 30s
|
||||
|
||||
protocol:
|
||||
format: json
|
||||
channel: matrix
|
||||
heartbeat_interval: 60s
|
||||
|
||||
# ============================================
|
||||
# SSH — no aplica para este bot
|
||||
# ============================================
|
||||
@@ -219,72 +201,7 @@ security:
|
||||
schedules: []
|
||||
|
||||
# ============================================
|
||||
# OBSERVABILIDAD
|
||||
# ============================================
|
||||
observability:
|
||||
logging:
|
||||
level: info
|
||||
format: json
|
||||
output: stdout
|
||||
file: "./agents/assistant-bot/data/assistant.log"
|
||||
|
||||
metrics:
|
||||
enabled: false
|
||||
port: 9091
|
||||
path: /metrics
|
||||
export: prometheus
|
||||
|
||||
health:
|
||||
enabled: true
|
||||
port: 8081
|
||||
path: /healthz
|
||||
|
||||
tracing:
|
||||
enabled: false
|
||||
provider: ""
|
||||
endpoint: ""
|
||||
|
||||
# ============================================
|
||||
# RESILIENCIA
|
||||
# ============================================
|
||||
resilience:
|
||||
circuit_breaker:
|
||||
failure_threshold: 5
|
||||
timeout: 30s
|
||||
half_open_max: 2
|
||||
|
||||
retry:
|
||||
max_attempts: 2
|
||||
backoff: exponential
|
||||
initial_delay: 1s
|
||||
max_delay: 10s
|
||||
|
||||
shutdown:
|
||||
timeout: 10s
|
||||
drain_messages: true
|
||||
save_state: false
|
||||
state_file: ""
|
||||
|
||||
queue:
|
||||
enabled: true
|
||||
max_size: 100
|
||||
priority_users: ["@admin:matrix-af2f3d.organic-machine.com"]
|
||||
|
||||
# ============================================
|
||||
# ALMACENAMIENTO Y ESTADO
|
||||
# STORAGE
|
||||
# ============================================
|
||||
storage:
|
||||
state:
|
||||
backend: sqlite
|
||||
path: "./agents/assistant-bot/data/assistant.db"
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
backend: memory
|
||||
ttl: 5m
|
||||
max_entries: 200
|
||||
|
||||
history:
|
||||
backend: sqlite
|
||||
path: "./agents/assistant-bot/data/history.db"
|
||||
retention: 168h # 7 días
|
||||
base_path: ""
|
||||
|
||||
@@ -37,7 +37,7 @@ afectados y notas de implementacion.
|
||||
| 24c | Security integration + cleanup | [0024c-security-integration.md](completed/0024c-security-integration.md) | completado |
|
||||
| 25 | Catálogo cron + scaffolder | [0025-cron-scaffolder.md](completed/0025-cron-scaffolder.md) | completado |
|
||||
| 26 | Refactorizar runtime.go | [0026-split-runtime.md](0026-split-runtime.md) | pendiente |
|
||||
| 27 | Limpiar config schema | [0027-prune-config-schema.md](0027-prune-config-schema.md) | pendiente |
|
||||
| 27 | Limpiar config schema | [0027-prune-config-schema.md](completed/0027-prune-config-schema.md) | completado |
|
||||
| 28 | Desacoplar launcher | [0028-decouple-launcher.md](0028-decouple-launcher.md) | pendiente |
|
||||
| 29 | Tests para runtime y config | [0029-core-tests.md](0029-core-tests.md) | pendiente |
|
||||
| 30 | Separacion Robot vs Agente | [0030-robot-vs-agent.md](0030-robot-vs-agent.md) | pendiente |
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# 0027 — Limpiar config schema: eliminar codigo muerto
|
||||
|
||||
## Objetivo
|
||||
|
||||
Eliminar las secciones del config schema (`internal/config/schema.go`) que no estan implementadas ni referenciadas en el codebase. Reducir de 560 lineas / 61 structs a solo lo que realmente se usa.
|
||||
|
||||
## Contexto
|
||||
|
||||
- `internal/config/schema.go` tiene 560 lineas y 61 tipos struct
|
||||
- Secciones **nunca referenciadas** en ningun archivo `.go`:
|
||||
- `ObservabilityCfg` (metrics, tracing, health) — 0 usos
|
||||
- `ResilienceCfg` (circuit breaker, retry, queue) — 0 usos
|
||||
- `AgentsCfg` (peers, delegation, protocol) — 0 usos
|
||||
- `PersonalityCfg.Communication` (18 campos: humor, quirks, catchphrases) — 0 usos
|
||||
- El template `_template/config.yaml` tiene 414 lineas cuando un agente real necesita ~40
|
||||
- Esto complica el onboarding y crea confusion sobre que es funcional vs especulativo
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
internal/config/schema.go → eliminar structs muertos (~180 lineas)
|
||||
agents/_template/config.yaml → reducir a lo esencial (~60 lineas)
|
||||
```
|
||||
|
||||
### Patron pure core / impure shell
|
||||
|
||||
- `pkg/` — sin cambios
|
||||
- `shell/` — sin cambios
|
||||
- `agents/` — template simplificado
|
||||
- `internal/config/` — poda de tipos
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1: Auditar uso real
|
||||
|
||||
- [ ] **1.1** Grep cada struct/campo del schema contra todo el codebase para confirmar cuales tienen 0 referencias
|
||||
- [ ] **1.2** Documentar en este issue la lista final de tipos a eliminar
|
||||
|
||||
### Fase 2: Podar schema.go
|
||||
|
||||
- [ ] **2.1** Eliminar `ObservabilityCfg` y todos sus sub-structs (LoggingCfg, MetricsCfg, HealthCfg, TracingCfg)
|
||||
- [ ] **2.2** Eliminar `ResilienceCfg` y sub-structs (CircuitBreakerCfg, RetryCfg, ShutdownCfg, QueueCfg)
|
||||
- [ ] **2.3** Eliminar `AgentsCfg` y sub-structs (PeerCfg, DelegationCfg)
|
||||
- [ ] **2.4** Eliminar campos no usados de `PersonalityCfg` (Communication, Humor, Quirks, etc.)
|
||||
- [ ] **2.5** Verificar que los campos eliminados no rompen el parsing YAML (yaml.v3 ignora campos extra por defecto)
|
||||
|
||||
### Fase 3: Simplificar template
|
||||
|
||||
- [ ] **3.1** Reescribir `agents/_template/config.yaml` con solo los campos funcionales (~60 lineas)
|
||||
- [ ] **3.2** Añadir comentarios explicativos en el template para cada seccion
|
||||
|
||||
### Fase 4: Tests
|
||||
|
||||
- [ ] **4.1** Verificar que los configs existentes (`assistant-bot`, `asistente-2`, `meteorologo`) siguen parseando correctamente
|
||||
- [ ] **4.2** `go build -tags goolm ./...` compila
|
||||
- [ ] **4.3** `go test -tags goolm ./...` pasa
|
||||
|
||||
### Fase 5: Cleanup
|
||||
|
||||
- [ ] **5.1** Actualizar `CLAUDE.md` si se mencionan secciones eliminadas
|
||||
- [ ] **5.2** Si algun config YAML existente usa campos eliminados, limpiar esas lineas
|
||||
|
||||
---
|
||||
|
||||
## Ejemplo de uso
|
||||
|
||||
Antes (template 414 lineas):
|
||||
```yaml
|
||||
personality:
|
||||
tone: friendly
|
||||
communication:
|
||||
formality: informal # nunca se usa
|
||||
humor: light # nunca se usa
|
||||
quirks: ["dice 'vale'"] # nunca se usa
|
||||
observability: # nunca se usa
|
||||
logging: ...
|
||||
metrics: ...
|
||||
resilience: # nunca se usa
|
||||
circuit_breaker: ...
|
||||
```
|
||||
|
||||
Despues (template ~60 lineas):
|
||||
```yaml
|
||||
agent:
|
||||
id: mi-agente
|
||||
description: "Descripcion"
|
||||
personality:
|
||||
tone: friendly
|
||||
language: es
|
||||
llm:
|
||||
primary:
|
||||
provider: openai
|
||||
model: gpt-4o
|
||||
matrix:
|
||||
threads:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
## Decisiones de diseno
|
||||
|
||||
- **Eliminar, no comentar**: codigo muerto se borra, no se comenta con "// TODO: implement"
|
||||
- **Si se necesita en el futuro, se re-añade**: Git tiene historial. No mantener especulacion.
|
||||
- **yaml.v3 es tolerante**: campos extra en YAML no causan error, asi que eliminar structs no rompe configs existentes que tengan esos campos
|
||||
|
||||
## Prerequisitos
|
||||
|
||||
- Ninguno
|
||||
|
||||
## Riesgos
|
||||
|
||||
- **Falso negativo en grep**: algun campo podria usarse via reflection o string matching. Mitigacion: buscar tambien por nombre de campo en strings
|
||||
- **Configs de usuarios existentes**: si alguien tiene un config con `observability:`, no rompera (yaml.v3 ignora), pero el campo sera silenciosamente ignorado. Esto ya era el caso.
|
||||
@@ -10,12 +10,9 @@ type AgentConfig struct {
|
||||
LLM LLMCfg `yaml:"llm"`
|
||||
Tools ToolsCfg `yaml:"tools"`
|
||||
Matrix MatrixCfg `yaml:"matrix"`
|
||||
Agents AgentsCfg `yaml:"agents"`
|
||||
SSH SSHCfg `yaml:"ssh"`
|
||||
Security SecurityCfg `yaml:"security"`
|
||||
Schedules []ScheduleCfg `yaml:"schedules"`
|
||||
Observability ObservabilityCfg `yaml:"observability"`
|
||||
Resilience ResilienceCfg `yaml:"resilience"`
|
||||
Storage StorageCfg `yaml:"storage"`
|
||||
Memory MemoryCfg `yaml:"memory"`
|
||||
Skills SkillsCfg `yaml:"skills"`
|
||||
@@ -276,34 +273,6 @@ type FiltersCfg struct {
|
||||
MinPowerLevel int `yaml:"min_power_level"`
|
||||
}
|
||||
|
||||
// ── Inter-agent ───────────────────────────────────────────────────────────
|
||||
|
||||
type AgentsCfg struct {
|
||||
Peers []PeerCfg `yaml:"peers"`
|
||||
Delegation DelegationCfg `yaml:"delegation"`
|
||||
Protocol ProtocolCfg `yaml:"protocol"`
|
||||
}
|
||||
|
||||
type PeerCfg struct {
|
||||
ID string `yaml:"id"`
|
||||
Capabilities []string `yaml:"capabilities"`
|
||||
Room string `yaml:"room"`
|
||||
}
|
||||
|
||||
type DelegationCfg struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
CanDelegateTo []string `yaml:"can_delegate_to"`
|
||||
CanReceiveFrom []string `yaml:"can_receive_from"`
|
||||
MaxDepth int `yaml:"max_delegation_depth"`
|
||||
Timeout time.Duration `yaml:"timeout"`
|
||||
}
|
||||
|
||||
type ProtocolCfg struct {
|
||||
Format string `yaml:"format"` // json | protobuf | msgpack
|
||||
Channel string `yaml:"channel"` // matrix | grpc | channel
|
||||
HeartbeatInterval time.Duration `yaml:"heartbeat_interval"`
|
||||
}
|
||||
|
||||
// ── SSH Inventory ─────────────────────────────────────────────────────────
|
||||
|
||||
type SSHCfg struct {
|
||||
@@ -398,76 +367,6 @@ type FailureAction struct {
|
||||
EscalateTo string `yaml:"escalate_to"`
|
||||
}
|
||||
|
||||
// ── Observability ─────────────────────────────────────────────────────────
|
||||
|
||||
type ObservabilityCfg struct {
|
||||
Logging LoggingCfg `yaml:"logging"`
|
||||
Metrics MetricsCfg `yaml:"metrics"`
|
||||
Health HealthCfg `yaml:"health"`
|
||||
Tracing TracingCfg `yaml:"tracing"`
|
||||
}
|
||||
|
||||
type LoggingCfg struct {
|
||||
Level string `yaml:"level"`
|
||||
Format string `yaml:"format"` // json | text
|
||||
Output string `yaml:"output"` // stdout | file
|
||||
File string `yaml:"file"`
|
||||
}
|
||||
|
||||
type MetricsCfg struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Port int `yaml:"port"`
|
||||
Path string `yaml:"path"`
|
||||
Export string `yaml:"export"` // prometheus
|
||||
}
|
||||
|
||||
type HealthCfg struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Port int `yaml:"port"`
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
|
||||
type TracingCfg struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Provider string `yaml:"provider"`
|
||||
Endpoint string `yaml:"endpoint"`
|
||||
}
|
||||
|
||||
// ── Resilience ────────────────────────────────────────────────────────────
|
||||
|
||||
type ResilienceCfg struct {
|
||||
CircuitBreaker CircuitBreakerCfg `yaml:"circuit_breaker"`
|
||||
Retry RetryCfg `yaml:"retry"`
|
||||
Shutdown ShutdownCfg `yaml:"shutdown"`
|
||||
Queue QueueCfg `yaml:"queue"`
|
||||
}
|
||||
|
||||
type CircuitBreakerCfg struct {
|
||||
FailureThreshold int `yaml:"failure_threshold"`
|
||||
Timeout time.Duration `yaml:"timeout"`
|
||||
HalfOpenMax int `yaml:"half_open_max"`
|
||||
}
|
||||
|
||||
type RetryCfg struct {
|
||||
MaxAttempts int `yaml:"max_attempts"`
|
||||
Backoff string `yaml:"backoff"` // fixed | exponential
|
||||
InitialDelay time.Duration `yaml:"initial_delay"`
|
||||
MaxDelay time.Duration `yaml:"max_delay"`
|
||||
}
|
||||
|
||||
type ShutdownCfg struct {
|
||||
Timeout time.Duration `yaml:"timeout"`
|
||||
DrainMessages bool `yaml:"drain_messages"`
|
||||
SaveState bool `yaml:"save_state"`
|
||||
StateFile string `yaml:"state_file"`
|
||||
}
|
||||
|
||||
type QueueCfg struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
MaxSize int `yaml:"max_size"`
|
||||
PriorityUsers []string `yaml:"priority_users"`
|
||||
}
|
||||
|
||||
// ── Storage ───────────────────────────────────────────────────────────────
|
||||
|
||||
type StorageCfg struct {
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// TestAgentConfigParseMinimal verifies that a minimal config YAML (with only
|
||||
// required fields) parses into AgentConfig without error.
|
||||
func TestAgentConfigParseMinimal(t *testing.T) {
|
||||
const minimalYAML = `
|
||||
agent:
|
||||
id: test-bot
|
||||
name: Test Bot
|
||||
enabled: true
|
||||
matrix:
|
||||
homeserver: "https://matrix.example.com"
|
||||
user_id: "@test:matrix.example.com"
|
||||
llm:
|
||||
primary:
|
||||
provider: openai
|
||||
model: gpt-4o
|
||||
`
|
||||
var cfg AgentConfig
|
||||
if err := yaml.Unmarshal([]byte(minimalYAML), &cfg); err != nil {
|
||||
t.Fatalf("failed to parse minimal config: %v", err)
|
||||
}
|
||||
if cfg.Agent.ID != "test-bot" {
|
||||
t.Errorf("expected agent.id=test-bot, got %q", cfg.Agent.ID)
|
||||
}
|
||||
if cfg.Matrix.Homeserver != "https://matrix.example.com" {
|
||||
t.Errorf("expected homeserver, got %q", cfg.Matrix.Homeserver)
|
||||
}
|
||||
if cfg.LLM.Primary.Provider != "openai" {
|
||||
t.Errorf("expected provider=openai, got %q", cfg.LLM.Primary.Provider)
|
||||
}
|
||||
}
|
||||
|
||||
// TestAgentConfigIgnoresRemovedSections verifies that YAML containing the
|
||||
// removed sections (agents, observability, resilience) still parses without
|
||||
// error. yaml.v3 silently ignores unknown keys.
|
||||
func TestAgentConfigIgnoresRemovedSections(t *testing.T) {
|
||||
const yamlWithRemoved = `
|
||||
agent:
|
||||
id: legacy-bot
|
||||
name: Legacy Bot
|
||||
enabled: true
|
||||
matrix:
|
||||
homeserver: "https://matrix.example.com"
|
||||
user_id: "@legacy:matrix.example.com"
|
||||
llm:
|
||||
primary:
|
||||
provider: openai
|
||||
model: gpt-4o
|
||||
|
||||
# These sections were removed from the schema but may still exist in old YAMLs.
|
||||
agents:
|
||||
peers:
|
||||
- id: other-bot
|
||||
capabilities: [general]
|
||||
room: "!abc:server.com"
|
||||
delegation:
|
||||
enabled: false
|
||||
protocol:
|
||||
format: json
|
||||
channel: matrix
|
||||
|
||||
observability:
|
||||
logging:
|
||||
level: info
|
||||
format: json
|
||||
metrics:
|
||||
enabled: false
|
||||
health:
|
||||
enabled: true
|
||||
port: 8080
|
||||
tracing:
|
||||
enabled: false
|
||||
|
||||
resilience:
|
||||
circuit_breaker:
|
||||
failure_threshold: 5
|
||||
timeout: 30s
|
||||
retry:
|
||||
max_attempts: 2
|
||||
backoff: exponential
|
||||
shutdown:
|
||||
timeout: 10s
|
||||
queue:
|
||||
enabled: true
|
||||
max_size: 100
|
||||
`
|
||||
var cfg AgentConfig
|
||||
if err := yaml.Unmarshal([]byte(yamlWithRemoved), &cfg); err != nil {
|
||||
t.Fatalf("parsing config with removed sections should succeed, got: %v", err)
|
||||
}
|
||||
if cfg.Agent.ID != "legacy-bot" {
|
||||
t.Errorf("expected agent.id=legacy-bot, got %q", cfg.Agent.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// TestAgentConfigParseFull verifies that a config YAML with all active sections
|
||||
// parses correctly, including personality with communication.
|
||||
func TestAgentConfigParseFull(t *testing.T) {
|
||||
const fullYAML = `
|
||||
agent:
|
||||
id: full-bot
|
||||
name: Full Bot
|
||||
version: "1.0.0"
|
||||
enabled: true
|
||||
description: "A fully configured bot"
|
||||
tags: [test, full]
|
||||
|
||||
personality:
|
||||
tone: friendly
|
||||
verbosity: concise
|
||||
language: es
|
||||
role: "asistente general"
|
||||
communication:
|
||||
formality: semiformal
|
||||
humor: subtle
|
||||
personality: pragmatic
|
||||
response_style: structured
|
||||
quirks: ["usa analogias"]
|
||||
avoid_topics: ["politica"]
|
||||
catchphrases: ["interesante"]
|
||||
|
||||
llm:
|
||||
primary:
|
||||
provider: openai
|
||||
model: gpt-4o
|
||||
api_key_env: OPENAI_API_KEY
|
||||
max_tokens: 4096
|
||||
temperature: 0.7
|
||||
tool_use:
|
||||
enabled: true
|
||||
max_iterations: 5
|
||||
|
||||
matrix:
|
||||
homeserver: "https://matrix.example.com"
|
||||
user_id: "@full:matrix.example.com"
|
||||
access_token_env: MATRIX_TOKEN
|
||||
threads:
|
||||
enabled: true
|
||||
auto_thread: false
|
||||
|
||||
tools:
|
||||
ssh:
|
||||
enabled: false
|
||||
http:
|
||||
enabled: true
|
||||
allowed_domains: ["api.example.com"]
|
||||
timeout: 10s
|
||||
|
||||
security:
|
||||
sanitize:
|
||||
enabled: true
|
||||
mode: warn
|
||||
min_severity: medium
|
||||
tool_rate_limit:
|
||||
enabled: true
|
||||
max_calls_per_min: 10
|
||||
|
||||
storage:
|
||||
base_path: "/data/full-bot"
|
||||
|
||||
memory:
|
||||
enabled: true
|
||||
window_size: 30
|
||||
|
||||
skills:
|
||||
enabled: true
|
||||
path: "skills/"
|
||||
categories: ["devops"]
|
||||
timeout: 60s
|
||||
`
|
||||
var cfg AgentConfig
|
||||
if err := yaml.Unmarshal([]byte(fullYAML), &cfg); err != nil {
|
||||
t.Fatalf("failed to parse full config: %v", err)
|
||||
}
|
||||
|
||||
// Verify key fields
|
||||
if cfg.Agent.ID != "full-bot" {
|
||||
t.Errorf("agent.id: got %q", cfg.Agent.ID)
|
||||
}
|
||||
if cfg.Personality.Communication.Humor != "subtle" {
|
||||
t.Errorf("personality.communication.humor: got %q", cfg.Personality.Communication.Humor)
|
||||
}
|
||||
if len(cfg.Personality.Communication.Quirks) != 1 {
|
||||
t.Errorf("personality.communication.quirks: expected 1, got %d", len(cfg.Personality.Communication.Quirks))
|
||||
}
|
||||
if !cfg.LLM.ToolUse.Enabled {
|
||||
t.Error("llm.tool_use.enabled should be true")
|
||||
}
|
||||
if !cfg.Tools.HTTP.Enabled {
|
||||
t.Error("tools.http.enabled should be true")
|
||||
}
|
||||
if cfg.Storage.BasePath != "/data/full-bot" {
|
||||
t.Errorf("storage.base_path: got %q", cfg.Storage.BasePath)
|
||||
}
|
||||
if !cfg.Memory.Enabled {
|
||||
t.Error("memory.enabled should be true")
|
||||
}
|
||||
if !cfg.Skills.Enabled {
|
||||
t.Error("skills.enabled should be true")
|
||||
}
|
||||
if !cfg.Security.Sanitize.Enabled {
|
||||
t.Error("security.sanitize.enabled should be true")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user