feat: add assistant bot with LLM integration and configuration
- Implemented the assistant bot with basic command handling and LLM routing. - Created configuration file for the assistant bot with personality, behavior, and LLM settings. - Added system prompt for the assistant bot to define its capabilities and limitations. - Developed registration script for creating Matrix bot users via Synapse admin API. - Introduced common development scripts for agent management (start, stop, list, logs). - Scaffolded new agent creation script to streamline the addition of new agents. - Implemented agent removal script to disable agents without deleting data.
This commit is contained in:
Executable
+358
@@ -0,0 +1,358 @@
|
||||
#!/usr/bin/env bash
|
||||
# new-agent.sh — genera el scaffold de un nuevo agente
|
||||
#
|
||||
# Uso:
|
||||
# ./dev-scripts/new-agent.sh <agent-id> [displayname]
|
||||
#
|
||||
# Ejemplo:
|
||||
# ./dev-scripts/new-agent.sh monitor-bot "Monitor Agent"
|
||||
#
|
||||
# Crea:
|
||||
# agents/<agent-id>/config.yaml (basado en el assistant como plantilla)
|
||||
# agents/<agent-id>/agent.go (reglas puras vacías, listo para extender)
|
||||
# agents/<agent-id>/prompts/ (directorio para system prompt)
|
||||
# agents/<agent-id>/data/ (directorio de datos, en .gitignore)
|
||||
#
|
||||
# También te recuerda los dos pasos manuales que quedan.
|
||||
|
||||
source "$(dirname "$0")/_common.sh"
|
||||
load_env
|
||||
|
||||
need_arg "${1:-}"
|
||||
|
||||
ID="$1"
|
||||
DISPLAYNAME="${2:-$ID}"
|
||||
PACKAGE="$(echo "$ID" | tr '-' '_' | sed 's/_bot//')" # "monitor-bot" → "monitor"
|
||||
DIR="agents/$ID"
|
||||
|
||||
[[ -d "$DIR" ]] && fail "Ya existe agents/$ID — ¿ya fue creado?"
|
||||
|
||||
info "Creando scaffold para $ID..."
|
||||
|
||||
mkdir -p "$DIR/prompts" "$DIR/data"
|
||||
|
||||
# ── config.yaml ────────────────────────────────────────────────────────────
|
||||
cat > "$DIR/config.yaml" <<YAML
|
||||
# ============================================
|
||||
# IDENTIDAD
|
||||
# ============================================
|
||||
agent:
|
||||
id: $ID
|
||||
name: "$DISPLAYNAME"
|
||||
version: "1.0.0"
|
||||
enabled: true
|
||||
description: "Descripción del agente $DISPLAYNAME"
|
||||
tags: [$(echo "$ID" | tr '-' ',')]
|
||||
|
||||
# ============================================
|
||||
# PERSONALIDAD Y COMPORTAMIENTO
|
||||
# ============================================
|
||||
personality:
|
||||
tone: friendly
|
||||
verbosity: concise
|
||||
language: es
|
||||
languages_supported: [es, en]
|
||||
emoji_style: minimal
|
||||
prefix: "🤖"
|
||||
error_style: helpful
|
||||
|
||||
templates:
|
||||
greeting: "Hola, soy $DISPLAYNAME. ¿En qué puedo ayudarte?"
|
||||
unknown_command: "No reconozco ese comando. Escríbeme directamente."
|
||||
permission_denied: "No tengo permiso para hacer eso."
|
||||
error: "Algo salió mal: {{.Error}}"
|
||||
success: "{{.Summary}}"
|
||||
busy: "Procesando, dame un momento..."
|
||||
|
||||
behavior:
|
||||
proactive: false
|
||||
ask_confirmation: false
|
||||
show_reasoning: false
|
||||
thread_replies: true
|
||||
typing_indicator: true
|
||||
acknowledge_receipt: false
|
||||
|
||||
# ============================================
|
||||
# LLM
|
||||
# ============================================
|
||||
llm:
|
||||
primary:
|
||||
provider: openai
|
||||
model: gpt-4o
|
||||
api_key_env: OPENAI_API_KEY
|
||||
base_url: ""
|
||||
max_tokens: 4096
|
||||
temperature: 0.7
|
||||
|
||||
fallback:
|
||||
provider: ""
|
||||
model: ""
|
||||
api_key_env: ""
|
||||
base_url: ""
|
||||
max_tokens: 0
|
||||
temperature: 0
|
||||
|
||||
reasoning:
|
||||
system_prompt_file: "prompts/system.md"
|
||||
context_window: 16384
|
||||
memory_messages: 20
|
||||
|
||||
tool_use:
|
||||
enabled: false
|
||||
max_iterations: 3
|
||||
parallel_calls: false
|
||||
|
||||
rate_limit:
|
||||
requests_per_minute: 30
|
||||
tokens_per_minute: 100000
|
||||
concurrent_requests: 3
|
||||
|
||||
# ============================================
|
||||
# TOOLS — ajustar según necesidades del agente
|
||||
# ============================================
|
||||
tools:
|
||||
ssh:
|
||||
enabled: false
|
||||
allowed_targets: []
|
||||
forbidden_commands: []
|
||||
timeout: 0s
|
||||
max_concurrent: 0
|
||||
require_confirmation: []
|
||||
http:
|
||||
enabled: false
|
||||
allowed_domains: []
|
||||
timeout: 0s
|
||||
max_retries: 0
|
||||
scripts:
|
||||
enabled: false
|
||||
scripts_dir: ""
|
||||
allowed: []
|
||||
timeout: 0s
|
||||
sandbox: false
|
||||
file_ops:
|
||||
enabled: false
|
||||
allowed_paths: []
|
||||
read_only: true
|
||||
mcp:
|
||||
enabled: false
|
||||
servers: []
|
||||
expose:
|
||||
port: 0
|
||||
tools: []
|
||||
|
||||
# ============================================
|
||||
# MATRIX
|
||||
# ============================================
|
||||
matrix:
|
||||
homeserver: "${MATRIX_HOMESERVER}"
|
||||
user_id: "@$ID:${MATRIX_SERVER_NAME}"
|
||||
access_token_env: MATRIX_TOKEN_$(echo "$ID" | tr '[:lower:]-' '[:upper:]_')
|
||||
device_id: "$(echo "$ID" | tr '[:lower:]-' '[:upper:]_')01"
|
||||
|
||||
encryption:
|
||||
enabled: false
|
||||
store_path: "./data/crypto/"
|
||||
trust_mode: tofu
|
||||
|
||||
rooms:
|
||||
listen: []
|
||||
respond: []
|
||||
admin: []
|
||||
|
||||
filters:
|
||||
command_prefix: "!"
|
||||
mention_respond: true
|
||||
dm_respond: true
|
||||
ignore_bots: true
|
||||
ignore_users: []
|
||||
min_power_level: 0
|
||||
|
||||
# ============================================
|
||||
# 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
|
||||
# ============================================
|
||||
ssh:
|
||||
defaults:
|
||||
user: ""
|
||||
port: 22
|
||||
key_file_env: ""
|
||||
known_hosts: ""
|
||||
keepalive_interval: 0s
|
||||
timeout: 0s
|
||||
targets: {}
|
||||
|
||||
# ============================================
|
||||
# SEGURIDAD
|
||||
# ============================================
|
||||
security:
|
||||
roles:
|
||||
admin:
|
||||
users: ["@admin:\${MATRIX_SERVER_NAME}"]
|
||||
actions: ["*"]
|
||||
user:
|
||||
users: ["*"]
|
||||
actions: ["help"]
|
||||
audit:
|
||||
enabled: false
|
||||
log_file: "./data/audit.log"
|
||||
log_to_room: ""
|
||||
include: []
|
||||
secrets:
|
||||
provider: env
|
||||
|
||||
# ============================================
|
||||
# SCHEDULING
|
||||
# ============================================
|
||||
schedules: []
|
||||
|
||||
# ============================================
|
||||
# OBSERVABILIDAD
|
||||
# ============================================
|
||||
observability:
|
||||
logging:
|
||||
level: info
|
||||
format: json
|
||||
output: stdout
|
||||
file: "./data/$ID.log"
|
||||
metrics:
|
||||
enabled: false
|
||||
port: 0
|
||||
path: /metrics
|
||||
export: prometheus
|
||||
health:
|
||||
enabled: true
|
||||
port: 0
|
||||
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: 50
|
||||
priority_users: ["@admin:\${MATRIX_SERVER_NAME}"]
|
||||
|
||||
# ============================================
|
||||
# ALMACENAMIENTO
|
||||
# ============================================
|
||||
storage:
|
||||
state:
|
||||
backend: sqlite
|
||||
path: "./data/$ID.db"
|
||||
cache:
|
||||
enabled: true
|
||||
backend: memory
|
||||
ttl: 5m
|
||||
max_entries: 200
|
||||
history:
|
||||
backend: sqlite
|
||||
path: "./data/history.db"
|
||||
retention: 168h
|
||||
YAML
|
||||
|
||||
# ── agent.go ───────────────────────────────────────────────────────────────
|
||||
cat > "$DIR/agent.go" <<GO
|
||||
// Package $PACKAGE defines the pure rules for the $DISPLAYNAME.
|
||||
package $PACKAGE
|
||||
|
||||
import "github.com/enmanuel/agents/pkg/decision"
|
||||
|
||||
// Rules returns the decision rules for the $ID.
|
||||
func Rules() []decision.Rule {
|
||||
return []decision.Rule{
|
||||
{
|
||||
Name: "help",
|
||||
Match: decision.MatchCommand("help"),
|
||||
Actions: []decision.Action{{
|
||||
Kind: decision.ActionKindReply,
|
||||
Reply: &decision.ReplyAction{
|
||||
Content: "Soy $DISPLAYNAME. Escríbeme lo que necesitas.",
|
||||
},
|
||||
}},
|
||||
},
|
||||
// Catch-all: DMs y menciones van al LLM
|
||||
{
|
||||
Name: "llm-fallback",
|
||||
Match: func(ctx decision.MessageContext) bool {
|
||||
return ctx.IsDirectMsg || ctx.IsMention
|
||||
},
|
||||
Actions: []decision.Action{{
|
||||
Kind: decision.ActionKindLLM,
|
||||
LLM: &decision.LLMAction{},
|
||||
}},
|
||||
},
|
||||
}
|
||||
}
|
||||
GO
|
||||
|
||||
# ── system prompt ──────────────────────────────────────────────────────────
|
||||
cat > "$DIR/prompts/system.md" <<MD
|
||||
# $DISPLAYNAME — System Prompt
|
||||
|
||||
Eres $DISPLAYNAME. Describe aquí el rol, capacidades y restricciones del agente.
|
||||
|
||||
## Rol
|
||||
...
|
||||
|
||||
## Capacidades
|
||||
...
|
||||
|
||||
## Restricciones
|
||||
...
|
||||
MD
|
||||
|
||||
ok "Scaffold creado en $DIR/"
|
||||
echo ""
|
||||
|
||||
# ── Pasos siguientes ──────────────────────────────────────────────────────
|
||||
echo -e "${YLW}Quedan 2 pasos manuales:${RST}"
|
||||
echo ""
|
||||
echo -e " ${BLU}1.${RST} Añade una línea en ${BLU}cmd/launcher/main.go${RST}:"
|
||||
echo ""
|
||||
echo -e ' import ('
|
||||
echo -e " ${GRN}${PACKAGE}agent \"github.com/enmanuel/agents/agents/$ID\"${RST}"
|
||||
echo -e ' )'
|
||||
echo ""
|
||||
echo -e ' var rulesRegistry = map[string]func() []decision.Rule{'
|
||||
echo -e " ${GRN}\"$ID\": ${PACKAGE}agent.Rules,${RST}"
|
||||
echo -e ' ...'
|
||||
echo -e ' }'
|
||||
echo ""
|
||||
echo -e " ${BLU}2.${RST} Registra el bot en Matrix y añade el token a .env:"
|
||||
echo ""
|
||||
echo -e " ${DIM}./dev-scripts/register.sh $ID \"$DISPLAYNAME\"${RST}"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user