Files
agents_and_robots/docs/creating-agents.md
T

11 KiB

Guía completa: Crear un nuevo agente

Esta guía documenta todos los pasos para crear, registrar, configurar y poner en marcha un nuevo bot/agente en el sistema.

Requisitos previos

  • Go 1.23+ instalado (/usr/local/go/bin)
  • Acceso al homeserver Matrix (MATRIX_HOMESERVER y MATRIX_ADMIN_TOKEN en .env)
  • Variables de entorno cargadas (.env con todos los secretos)

Paso 1: Crear el scaffold del agente

Opción A: Script automático

./dev-scripts/new-agent.sh <agent-id> "Display Name"
# Ejemplo: ./dev-scripts/new-agent.sh mi-bot "Mi Bot"

Esto crea la estructura base en agents/<agent-id>/.

Opción B: Manual

Crear la estructura de directorios:

agents/<agent-id>/
├── agent.go                # Reglas puras de decisión
├── config.yaml             # Configuración completa del agente
├── prompts/
│   └── system.md           # System prompt para el LLM
└── data/                   # Runtime (auto-generado, en .gitignore)
    └── crypto/             # Store E2EE

1.1 Crear agents/<agent-id>/agent.go

Archivo de reglas puras. El package debe exportar una función Rules() []decision.Rule.

package mibot

import (
    "github.com/enmanuel/agents/pkg/decision"
)

// Rules returns the decision rules for this agent.
func Rules() []decision.Rule {
    return []decision.Rule{
        // !help — comando de ayuda explícito
        {
            Name:  "help",
            Match: decision.MatchCommand("help"),
            Actions: []decision.Action{{
                Kind: decision.ActionKindReply,
                Reply: &decision.ReplyAction{
                    Content: "Soy mi-bot. Escríbeme lo que necesitas.",
                },
            }},
        },

        // Catch-all: DMs y menciones → LLM
        {
            Name: "llm-all",
            Match: func(ctx decision.MessageContext) bool {
                return ctx.IsDirectMsg || ctx.IsMention
            },
            Actions: []decision.Action{{
                Kind: decision.ActionKindLLM,
                LLM:  &decision.LLMAction{},
            }},
        },
    }
}

Reglas importantes:

  • Este archivo es puro — sin imports de I/O, sin side effects
  • Solo usa types de pkg/decision
  • Las reglas se evalúan en orden; la primera que matchea gana

1.2 Crear agents/<agent-id>/config.yaml

Configuración completa del agente. Referencia: internal/config/schema.go.

Secciones principales:

Sección Descripción
agent Identidad: id, name, version, enabled, description, tags
personality Tono, verbosidad, idioma, templates, comportamiento
llm Provider (openai/anthropic), modelo, tokens, temperature, tool_use
tools SSH, HTTP, scripts, file_ops, MCP — cada uno con su enabled/config
matrix Homeserver, user_id, token, device_id, encryption, rooms, filters
agents Peers conocidos, delegación, protocolo inter-agente
ssh Configuración SSH (solo si aplica)
security Roles, audit, secrets provider
schedules Tareas programadas (cron)
observability Logging, metrics, health, tracing
resilience Circuit breaker, retry, shutdown, queue
storage State backend, cache, history

Campos críticos en matrix:

matrix:
  homeserver: "https://matrix-af2f3d.organic-machine.com"
  user_id: "@<agent-id>:matrix-af2f3d.organic-machine.com"
  access_token_env: MATRIX_TOKEN_<AGENT_UPPER>   # nombre de la env var
  device_id: "<se obtiene al registrar>"

  encryption:
    enabled: true
    store_path: "./agents/<agent-id>/data/crypto/"
    pickle_key_env: PICKLE_KEY_<AGENT_UPPER>
    trust_mode: tofu

Para habilitar tool-use:

llm:
  tool_use:
    enabled: true          # DEBE ser true
    max_iterations: 5
    parallel_calls: false

1.3 Crear agents/<agent-id>/prompts/system.md

System prompt que recibe el LLM. Debe incluir:

  • Identidad y rol del bot
  • Capacidades disponibles
  • Herramientas disponibles (si tool_use está habilitado)
  • Estilo de respuesta
  • Limitaciones

Usar como referencia: agents/assistant/prompts/assistant-system.md o agents/asistente2/prompts/system.md.

Paso 2: Registrar el agente en el launcher

Editar cmd/launcher/main.go:

  1. Añadir import del package del agente:
mibotAgent "github.com/enmanuel/agents/agents/mibot"
  1. Añadir entrada en rulesRegistry:
var rulesRegistry = map[string]func() []decision.Rule{
    "assistant-bot": assistantagent.Rules,
    "mi-bot":        mibotAgent.Rules,    // ← nuevo
    "devops-bot":    devopsagent.Rules,
}

Nota: El ID aquí debe coincidir exactamente con agent.id en el config.yaml.

Paso 3: Registrar en Matrix

./dev-scripts/register.sh <agent-id> "Display Name"

Este comando:

  1. Crea el usuario en Synapse via admin API
  2. Genera una contraseña aleatoria
  3. Hace login para obtener un access token
  4. Guarda MATRIX_TOKEN_<AGENT> en .env

Guardar la contraseña manualmente — se necesita para la verificación E2EE:

# Añadir al .env manualmente si no se guardó:
MATRIX_PASSWORD_<AGENT>=<password_generada>

Importante: El script register.sh imprime la password en la salida. Copiarla y guardarla.

Actualizar device_id en config.yaml

El registro crea un device_id nuevo. Actualizarlo en agents/<agent-id>/config.yaml:

matrix:
  device_id: "<DEVICE_ID del output de register>"

Paso 4: Configurar avatar y display name

Colocar la imagen del bot en static/:

# Subir avatar y sincronizar displayname desde el config
./dev-scripts/avatar.sh <agent-id> static/<imagen>.jpg

Esto hace:

  1. Sube la imagen al homeserver Matrix (obtiene una URL mxc://)
  2. Establece el avatar del usuario bot
  3. Sincroniza el displayname desde agent.name del config.yaml

Formatos soportados: JPG, PNG. Recomendado: cuadrado, 256x256 o superior.

Paso 5: Verificación E2EE (cross-signing)

Sin este paso, los mensajes del bot mostrarán: "Encrypted by a device not verified by its owner".

./bin/verify \
  --homeserver "$MATRIX_HOMESERVER" \
  --username "<agent-id>" \
  --password "$MATRIX_PASSWORD_<AGENT>" \
  --token "$MATRIX_TOKEN_<AGENT>" \
  --store "./agents/<agent-id>/data/crypto/" \
  --pickle-key "$PICKLE_KEY_<AGENT>"

Qué hace:

  1. Inicializa el crypto helper de mautrix (usando el mismo store y pickle key que el agente)
  2. Genera claves de cross-signing (master + self-signing + user-signing)
  3. Las sube al homeserver usando UIA con la password del bot
  4. Las almacena cifradas en SSSS (Server-Side Secret Storage) en el servidor
  5. Imprime un recovery key (base58) que permite recuperar las claves privadas

5.1 Guardar el recovery key

El comando imprime algo como:

─── IMPORTANT: Save the recovery key ───
SSSS_RECOVERY_KEY_MI_BOT=EsXX YYYY ZZZZ ...

Añadir al .env (con comillas, el recovery key tiene espacios):

SSSS_RECOVERY_KEY_MI_BOT="EsXX YYYY ZZZZ ..."

5.2 Configurar recovery_key_env en config.yaml

encryption:
  enabled: true
  store_path: "./agents/<agent-id>/data/crypto/"
  pickle_key_env: PICKLE_KEY_<AGENT>
  trust_mode: tofu
  recovery_key_env: SSSS_RECOVERY_KEY_<AGENT>   # ← NUEVO

Esto permite que el agente recupere automáticamente las cross-signing private keys desde SSSS cada vez que arranca. Sin esto, las keys solo existen en memoria durante la sesión de verify.

Logs esperados al arrancar con recovery key configurado:

INFO cross-signing private keys fetched from SSSS
INFO e2ee ready

5.3 Si se cambia la password del bot

Cambiar la password (admin API) invalida el token anterior. Hay que:

  1. Re-login para obtener nuevo token
  2. Actualizar MATRIX_TOKEN_<AGENT> y MATRIX_PASSWORD_<AGENT> en .env
  3. Actualizar device_id en config.yaml
  4. Borrar el crypto store viejo (agents/<id>/data/crypto/crypto.db)
  5. Re-ejecutar cmd/verify → obtener nuevo recovery key
  6. Actualizar SSSS_RECOVERY_KEY_<AGENT> en .env

Nota: El pickle key (PICKLE_KEY_<AGENT>) NO cambia al rotar el token. Solo se regenera si se pierde.

Paso 6: Arrancar el agente

./dev-scripts/start.sh <agent-id>

Verificar que arrancó correctamente:

# Ver logs
tail -f run/<agent-id>.log

# Verificar proceso
./dev-scripts/ps.sh <agent-id>

# Estado general
./dev-scripts/list.sh

Logs esperados al arrancar correctamente:

{"level":"INFO","msg":"initializing e2ee","store":"agents/<id>/data/crypto/crypto.db"}
{"level":"INFO","msg":"e2ee ready"}
{"level":"INFO","msg":"agent starting","id":"<agent-id>","tools":["current_time","matrix_send"]}
{"level":"INFO","msg":"starting matrix sync"}

Paso 7: Verificar funcionamiento

  1. Abrir Element u otro cliente Matrix
  2. Enviar un DM al bot: @<agent-id>:matrix-af2f3d.organic-machine.com
  3. Verificar que responde
  4. Verificar que no aparece el warning de "device not verified"
  5. Si tiene tools, probar que las usa (e.g., preguntar la hora)

Resumen de comandos (en orden)

# 1. Crear scaffold
./dev-scripts/new-agent.sh <id> "Nombre"

# 2. Editar reglas, config, prompt
#    agents/<id>/agent.go
#    agents/<id>/config.yaml
#    agents/<id>/prompts/system.md

# 3. Registrar en launcher
#    Editar cmd/launcher/main.go → import + rulesRegistry

# 4. Registrar en Matrix
./dev-scripts/register.sh <id> "Nombre"

# 5. Avatar y displayname
./dev-scripts/avatar.sh <id> static/<imagen>.jpg

# 6. Generar pickle key (si no existe)
openssl rand -hex 32  # → guardar como PICKLE_KEY_<AGENT> en .env

# 7. Verificación E2EE + recovery key
./bin/verify \
  --homeserver "$MATRIX_HOMESERVER" \
  --username "<id>" \
  --password "$MATRIX_PASSWORD_<AGENT>" \
  --token "$MATRIX_TOKEN_<AGENT>" \
  --store "./agents/<id>/data/crypto/" \
  --pickle-key "$PICKLE_KEY_<AGENT>"
# → Guardar SSSS_RECOVERY_KEY_<AGENT> en .env (con comillas)
# → Añadir recovery_key_env al config.yaml

# 8. Arrancar
./dev-scripts/start.sh <id>

# 9. Verificar
tail -f run/<id>.log

Troubleshooting

Problema Causa Solución
env var ... is not set La regex del .env loader no matchea Verificar que el nombre de la var solo usa [A-Z0-9_]
M_UNKNOWN_TOKEN Token invalidado (password cambiada) Re-login, actualizar .env
mismatching device ID Crypto store con device viejo Borrar agents/<id>/data/crypto/crypto.db, actualizar device_id en config
olm account not marked as shared Crypto store inconsistente Auto-recovery lo resuelve al reiniciar. Si persiste: borrar crypto.db
"Encrypted by device not verified" Falta cross-signing Ejecutar cmd/verify con --store y --pickle-key del agente, guardar recovery key en .env
cross-signing private keys not available Recovery key no configurada Ejecutar cmd/verify, guardar recovery key, configurar recovery_key_env
verify recovery key: invalid Recovery key incorrecta Re-ejecutar cmd/verify para generar nueva recovery key
Bot no responde Reglas no matchean Verificar que hay regla catch-all para DMs/mentions
no rules registered for agent ID no está en rulesRegistry Añadir en cmd/launcher/main.go
Bot muere al arrancar Revisar logs tail -f run/<id>.log

Compilación

Siempre usar la tag goolm para soporte E2EE puro (sin CGO):

go build -tags goolm ./cmd/launcher
go build -tags goolm ./cmd/verify
go run -tags goolm ./cmd/verify --help