fc86edd94c
- .claude/CLAUDE.md - .claude/rules/create_agent.md - agents/_specials/father-bot/prompts/system.md - agents/_template/config.yaml - agents/_template_robot/config.yaml - cmd/agentctl/autoavatar.go - cmd/launcher/sqlite.go - dev-scripts/_common.sh - dev-scripts/agent/create-full.sh - dev-scripts/agent/delete-full.sh - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
362 lines
16 KiB
Bash
Executable File
362 lines
16 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# create-full.sh — pipeline completo para crear un agente o robot funcional
|
|
#
|
|
# Pipeline de 7+1 pasos:
|
|
# 1. SCAFFOLD → crear archivos base desde template
|
|
# 2. BUILD → go build -tags goolm ./...
|
|
# 3. REGISTER → crear usuario Matrix + token
|
|
# 4. VERIFY E2EE → cross-signing + recovery key
|
|
# 5. CONVERT (robot) → eliminar LLM/prompts si type=robot
|
|
# 6. AUTO-AVATAR → generar y aplicar foto de perfil
|
|
# 7. DISPLAY NAME → configurar nombre visible en Matrix
|
|
# 8. PERSONALIZE → (automatico si se pasan --description / --system-prompt)
|
|
#
|
|
# Pasos posteriores:
|
|
# 9. REBUILD → recompilar tras personalizacion
|
|
# 10. START/RESTART → arrancar el launcher con el bot
|
|
# 11. HEALTH CHECK → ./dev-scripts/agent/health-check.sh <id>
|
|
# 12. SELF-INTRODUCE → ./dev-scripts/agent/notify-developer.sh <id>
|
|
#
|
|
# Uso básico:
|
|
# ./dev-scripts/agent/create-full.sh <agent-id> "Display Name"
|
|
# ./dev-scripts/agent/create-full.sh <agent-id> "Display Name" --type robot
|
|
#
|
|
# Uso con personalización automática (Paso 8 incluido):
|
|
# ./dev-scripts/agent/create-full.sh weather-bot "Weather Bot" \
|
|
# --description "Consulta el tiempo actual y predicciones" \
|
|
# --provider anthropic \
|
|
# --system-prompt "Eres Weather Bot, especialista en meteorología."
|
|
#
|
|
# Flags de personalización (opcionales, activan el Paso 8 automático):
|
|
# --description "<texto>" descripcion del agente
|
|
# --provider <claude-code|openai|anthropic> proveedor LLM (default: claude-code)
|
|
# REGLA PROYECTO: usar claude-code SIEMPRE salvo razon explicita
|
|
# --model <modelo> modelo LLM (default: segun provider)
|
|
# --tone <friendly|professional|...> tono (default: friendly)
|
|
# --prefix "<emoji>" emoji prefix (default: 🤖)
|
|
# --system-prompt "<texto>" system prompt inline
|
|
# --system-prompt-file <path> system prompt desde archivo
|
|
# --tool-use habilitar tool_use en config
|
|
# --language <es|en> idioma (default: es)
|
|
# --avatar <URL_o_ruta> imagen para el avatar (default: generador random)
|
|
# ej: https://example/pikachu.png o ./avatars/poke.png
|
|
#
|
|
# Requisitos en .env:
|
|
# MATRIX_ADMIN_TOKEN, MATRIX_HOMESERVER, MATRIX_SERVER_NAME
|
|
# DEVELOPER_MATRIX_USERS (opcional, para notificación al developer)
|
|
|
|
source "$(dirname "$0")/../_common.sh"
|
|
load_env
|
|
|
|
need_arg "${1:-}"
|
|
|
|
ID="$1"
|
|
DISPLAYNAME="${2:-$ID}"
|
|
TYPE="agent"
|
|
NORM="$(normalize_id "$ID")"
|
|
SCRIPT_DIR="$(dirname "$0")"
|
|
|
|
# Flags de personalización (Paso 8)
|
|
PERSONALIZE_DESCRIPTION=""
|
|
PERSONALIZE_PROVIDER=""
|
|
PERSONALIZE_MODEL=""
|
|
PERSONALIZE_TONE="friendly"
|
|
PERSONALIZE_PREFIX="🤖"
|
|
PERSONALIZE_SYSTEM_PROMPT=""
|
|
PERSONALIZE_SYSTEM_PROMPT_FILE=""
|
|
PERSONALIZE_TOOL_USE=false
|
|
PERSONALIZE_LANGUAGE="es"
|
|
DO_PERSONALIZE=false
|
|
|
|
# Parse flags
|
|
shift 2 2>/dev/null || shift 1 2>/dev/null || true
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--type) TYPE="${2:-agent}"; shift 2 ;;
|
|
--type=*) TYPE="${1#--type=}"; shift ;;
|
|
--description) PERSONALIZE_DESCRIPTION="${2:-}"; DO_PERSONALIZE=true; shift 2 ;;
|
|
--description=*) PERSONALIZE_DESCRIPTION="${1#--description=}"; DO_PERSONALIZE=true; shift ;;
|
|
--provider) PERSONALIZE_PROVIDER="${2:-}"; DO_PERSONALIZE=true; shift 2 ;;
|
|
--provider=*) PERSONALIZE_PROVIDER="${1#--provider=}"; DO_PERSONALIZE=true; shift ;;
|
|
--model) PERSONALIZE_MODEL="${2:-}"; DO_PERSONALIZE=true; shift 2 ;;
|
|
--model=*) PERSONALIZE_MODEL="${1#--model=}"; DO_PERSONALIZE=true; shift ;;
|
|
--tone) PERSONALIZE_TONE="${2:-friendly}"; DO_PERSONALIZE=true; shift 2 ;;
|
|
--tone=*) PERSONALIZE_TONE="${1#--tone=}"; DO_PERSONALIZE=true; shift ;;
|
|
--prefix) PERSONALIZE_PREFIX="${2:-🤖}"; DO_PERSONALIZE=true; shift 2 ;;
|
|
--prefix=*) PERSONALIZE_PREFIX="${1#--prefix=}"; DO_PERSONALIZE=true; shift ;;
|
|
--system-prompt) PERSONALIZE_SYSTEM_PROMPT="${2:-}"; DO_PERSONALIZE=true; shift 2 ;;
|
|
--system-prompt=*) PERSONALIZE_SYSTEM_PROMPT="${1#--system-prompt=}"; DO_PERSONALIZE=true; shift ;;
|
|
--system-prompt-file) PERSONALIZE_SYSTEM_PROMPT_FILE="${2:-}"; DO_PERSONALIZE=true; shift 2 ;;
|
|
--system-prompt-file=*) PERSONALIZE_SYSTEM_PROMPT_FILE="${1#--system-prompt-file=}"; DO_PERSONALIZE=true; shift ;;
|
|
--tool-use) PERSONALIZE_TOOL_USE=true; DO_PERSONALIZE=true; shift ;;
|
|
--language) PERSONALIZE_LANGUAGE="${2:-es}"; DO_PERSONALIZE=true; shift 2 ;;
|
|
--language=*) PERSONALIZE_LANGUAGE="${1#--language=}"; DO_PERSONALIZE=true; shift ;;
|
|
--avatar) AVATAR_SOURCE="${2:-}"; shift 2 ;;
|
|
--avatar=*) AVATAR_SOURCE="${1#--avatar=}"; shift ;;
|
|
*) shift ;;
|
|
esac
|
|
done
|
|
|
|
# AVATAR_SOURCE puede ser URL (http/https) o ruta local. Vacio = generador random.
|
|
: "${AVATAR_SOURCE:=}"
|
|
|
|
if [[ "$TYPE" == "robot" ]]; then
|
|
TYPE_LABEL="robot"
|
|
TYPE_EMOJI="🤖"
|
|
else
|
|
TYPE_LABEL="agente"
|
|
TYPE_EMOJI="🧠"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${BLU}═══════════════════════════════════════════════════════${RST}"
|
|
echo -e "${BLU} Creando ${TYPE_LABEL}: ${GRN}$ID${BLU} ($DISPLAYNAME) ${TYPE_EMOJI}${RST}"
|
|
echo -e "${BLU}═══════════════════════════════════════════════════════${RST}"
|
|
echo ""
|
|
|
|
# ── Paso 1: Scaffold ─────────────────────────────────────────────────────
|
|
TOTAL_STEPS=7
|
|
[[ "$TYPE" == "robot" ]] && TOTAL_STEPS=8
|
|
|
|
info "Paso 1/${TOTAL_STEPS} — Scaffold (agent.go, config.yaml, prompts, launcher)"
|
|
echo ""
|
|
|
|
"$SCRIPT_DIR/new-agent.sh" "$ID" "$DISPLAYNAME"
|
|
|
|
echo ""
|
|
|
|
# ── Paso 2: Verificar compilación ─────────────────────────────────────────
|
|
info "Paso 2/${TOTAL_STEPS} — Verificando compilación..."
|
|
|
|
if "$GO" build -tags goolm ./... 2>&1; then
|
|
ok "Compilación exitosa"
|
|
else
|
|
fail "Error de compilación — revisa agents/$ID/agent.go y cmd/launcher/main.go"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# ── Paso 3: Registrar en Matrix ──────────────────────────────────────────
|
|
info "Paso 3/${TOTAL_STEPS} — Registrando en Matrix..."
|
|
echo ""
|
|
|
|
# Reload .env in case new-agent.sh or previous steps changed it
|
|
load_env
|
|
|
|
"$SCRIPT_DIR/register.sh" "$ID" "$DISPLAYNAME"
|
|
|
|
echo ""
|
|
|
|
# ── Paso 4: Verificar E2EE ───────────────────────────────────────────────
|
|
info "Paso 4/${TOTAL_STEPS} — Verificación E2EE (cross-signing + recovery key)..."
|
|
echo ""
|
|
|
|
# Reload .env to pick up token, password, pickle key from register.sh
|
|
load_env
|
|
|
|
"$SCRIPT_DIR/verify.sh" "$ID"
|
|
|
|
echo ""
|
|
|
|
# ── Paso 5 (robots): Convertir a robot ───────────────────────────────────
|
|
if [[ "$TYPE" == "robot" ]]; then
|
|
info "Paso 5/${TOTAL_STEPS} — Convirtiendo a robot..."
|
|
echo ""
|
|
|
|
"$SCRIPT_DIR/convert-to-robot.sh" "$ID" "$DISPLAYNAME"
|
|
|
|
# Rebuild after conversion
|
|
info "Recompilando tras conversión..."
|
|
"$GO" build -tags goolm ./... 2>&1 || fail "Error de compilación tras conversión a robot"
|
|
ok "Recompilación exitosa"
|
|
|
|
echo ""
|
|
fi
|
|
|
|
# ── Paso auto-avatar: Generar/aplicar avatar ────────────────────────────
|
|
AVATAR_STEP=$((TOTAL_STEPS - 2))
|
|
info "Paso ${AVATAR_STEP}/${TOTAL_STEPS} — Configurando avatar del bot..."
|
|
echo ""
|
|
|
|
# Resuelve el binario de agentctl como array (preserva split por espacios)
|
|
if [[ -f "$REPO_ROOT/bin/agentctl" ]]; then
|
|
CTL_ARR=("$REPO_ROOT/bin/agentctl")
|
|
else
|
|
CTL_ARR=("$GO" run -tags goolm ./cmd/agentctl)
|
|
fi
|
|
|
|
# Si el usuario pasa --avatar, usa la URL/ruta indicada en vez del generador random.
|
|
AVATAR_CMD=("${CTL_ARR[@]}" auto-avatar "$ID")
|
|
if [[ -n "$AVATAR_SOURCE" ]]; then
|
|
if [[ "$AVATAR_SOURCE" =~ ^https?:// ]]; then
|
|
AVATAR_CMD+=(--from-url "$AVATAR_SOURCE")
|
|
info "Usando avatar personalizado desde URL: $AVATAR_SOURCE"
|
|
else
|
|
AVATAR_CMD+=(--from-file "$AVATAR_SOURCE")
|
|
info "Usando avatar personalizado desde archivo: $AVATAR_SOURCE"
|
|
fi
|
|
fi
|
|
|
|
if "${AVATAR_CMD[@]}" 2>&1; then
|
|
ok "Avatar configurado y aplicado"
|
|
else
|
|
warn "No se pudo configurar avatar (se puede hacer despues con: agentctl auto-avatar $ID [--from-url <url> | --from-file <path>])"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# ── Paso display name: Configurar nombre visible en Matrix ──────────────
|
|
DISPLAYNAME_STEP=$((TOTAL_STEPS - 1))
|
|
info "Paso ${DISPLAYNAME_STEP}/${TOTAL_STEPS} — Configurando display name en Matrix..."
|
|
echo ""
|
|
|
|
# Reload .env to pick up token from register.sh
|
|
load_env
|
|
|
|
TOKEN_VAR="MATRIX_TOKEN_${NORM}"
|
|
BOT_TOKEN="${!TOKEN_VAR:-}"
|
|
|
|
if [[ -n "$BOT_TOKEN" ]]; then
|
|
USER_ID="@${ID}:${MATRIX_SERVER_NAME}"
|
|
if curl -sf -X PUT \
|
|
"${MATRIX_HOMESERVER}/_matrix/client/v3/profile/${USER_ID}/displayname" \
|
|
-H "Authorization: Bearer $BOT_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"displayname\": \"${DISPLAYNAME}\"}" >/dev/null 2>&1; then
|
|
ok "Display name configurado: $DISPLAYNAME"
|
|
else
|
|
warn "No se pudo configurar display name (se puede hacer despues manualmente)"
|
|
fi
|
|
else
|
|
warn "Token del bot no encontrado — display name no configurado"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# ── Paso 8a (robots): aplicar --description al config.yaml ──────────────
|
|
# Los robots no tienen prompts/system.md ni agent.go (no LLM), pero su
|
|
# config.yaml SI tiene un campo `description:` que personalize.sh ignora.
|
|
# Para evitar que el robot quede con la descripcion del template literal,
|
|
# parcheamos la linea aqui.
|
|
if [[ "$TYPE" == "robot" ]] && [[ -n "$PERSONALIZE_DESCRIPTION" ]]; then
|
|
CFG_FILE="agents/$ID/config.yaml"
|
|
if [[ -f "$CFG_FILE" ]]; then
|
|
# Escapar caracteres especiales del valor para sed
|
|
ESCAPED_DESC="$(printf '%s' "$PERSONALIZE_DESCRIPTION" | sed -e 's/[\/&|]/\\&/g')"
|
|
sed -i "0,/^ description:.*/s|| description: \"$ESCAPED_DESC\"|" "$CFG_FILE"
|
|
ok "Descripcion del robot aplicada al config.yaml"
|
|
fi
|
|
fi
|
|
|
|
# ── Paso 8 (automático, solo agents): Personalizar archivos ─────────────
|
|
PERSONALIZE_DONE=false
|
|
if $DO_PERSONALIZE && [[ "$TYPE" != "robot" ]]; then
|
|
PERSONALIZE_EXTRA_STEP=$((TOTAL_STEPS + 1))
|
|
info "Paso ${PERSONALIZE_EXTRA_STEP} — Personalizando archivos del agente (automático)..."
|
|
echo ""
|
|
|
|
# Construir args para personalize.sh
|
|
PERSONALIZE_ARGS=()
|
|
[[ -n "$PERSONALIZE_DESCRIPTION" ]] && PERSONALIZE_ARGS+=(--description "$PERSONALIZE_DESCRIPTION")
|
|
[[ -n "$PERSONALIZE_PROVIDER" ]] && PERSONALIZE_ARGS+=(--provider "$PERSONALIZE_PROVIDER")
|
|
[[ -n "$PERSONALIZE_MODEL" ]] && PERSONALIZE_ARGS+=(--model "$PERSONALIZE_MODEL")
|
|
[[ "$PERSONALIZE_TONE" != "friendly" ]] && PERSONALIZE_ARGS+=(--tone "$PERSONALIZE_TONE")
|
|
[[ "$PERSONALIZE_PREFIX" != "🤖" ]] && PERSONALIZE_ARGS+=(--prefix "$PERSONALIZE_PREFIX")
|
|
[[ -n "$PERSONALIZE_SYSTEM_PROMPT" ]] && PERSONALIZE_ARGS+=(--system-prompt "$PERSONALIZE_SYSTEM_PROMPT")
|
|
[[ -n "$PERSONALIZE_SYSTEM_PROMPT_FILE" ]] && PERSONALIZE_ARGS+=(--system-prompt-file "$PERSONALIZE_SYSTEM_PROMPT_FILE")
|
|
$PERSONALIZE_TOOL_USE && PERSONALIZE_ARGS+=(--tool-use)
|
|
[[ "$PERSONALIZE_LANGUAGE" != "es" ]] && PERSONALIZE_ARGS+=(--language "$PERSONALIZE_LANGUAGE")
|
|
|
|
if "$SCRIPT_DIR/personalize.sh" "$ID" "${PERSONALIZE_ARGS[@]}"; then
|
|
ok "Personalización completada"
|
|
PERSONALIZE_DONE=true
|
|
|
|
# Recompilar tras personalización
|
|
info "Recompilando tras personalización..."
|
|
if "$GO" build -tags goolm ./... 2>&1; then
|
|
ok "Recompilación exitosa"
|
|
else
|
|
fail "Error de compilación tras personalización — revisa agents/$ID/agent.go"
|
|
fi
|
|
else
|
|
warn "Personalización falló — revisa los flags o edita los archivos manualmente"
|
|
fi
|
|
|
|
echo ""
|
|
fi
|
|
|
|
# ── Paso final: Notificar al developer ───────────────────────────────────
|
|
NOTIFY_STEP=$TOTAL_STEPS
|
|
info "Paso ${NOTIFY_STEP}+ — Notificando a desarrolladores..."
|
|
echo ""
|
|
|
|
"$SCRIPT_DIR/notify-developer.sh" "$ID" "$TYPE" "$DISPLAYNAME" || true
|
|
|
|
echo ""
|
|
|
|
# ── Resumen ──────────────────────────────────────────────────────────────
|
|
echo -e "${GRN}═══════════════════════════════════════════════════════${RST}"
|
|
echo -e "${GRN} ✓ ${TYPE_LABEL^} $ID creado exitosamente ${TYPE_EMOJI}${RST}"
|
|
echo -e "${GRN}═══════════════════════════════════════════════════════${RST}"
|
|
echo ""
|
|
echo -e " ${BLU}Archivos creados:${RST}"
|
|
echo -e " agents/$ID/agent.go"
|
|
echo -e " agents/$ID/config.yaml"
|
|
if [[ "$TYPE" != "robot" ]]; then
|
|
echo -e " agents/$ID/prompts/system.md"
|
|
fi
|
|
echo ""
|
|
echo -e " ${BLU}Variables en .env:${RST}"
|
|
echo -e " MATRIX_TOKEN_${NORM}"
|
|
echo -e " MATRIX_PASSWORD_${NORM}"
|
|
echo -e " PICKLE_KEY_${NORM}"
|
|
echo -e " SSSS_RECOVERY_KEY_${NORM}"
|
|
echo ""
|
|
echo -e " ${BLU}Launcher actualizado:${RST}"
|
|
echo -e " cmd/launcher/main.go (import)"
|
|
echo ""
|
|
if $PERSONALIZE_DONE; then
|
|
echo -e "${GRN}Paso 8 completado automáticamente ✓${RST}"
|
|
echo -e " ${DIM}config.yaml, agent.go y prompts/system.md personalizados${RST}"
|
|
echo ""
|
|
echo -e "${YLW}Siguientes pasos (9-12 del pipeline):${RST}"
|
|
echo ""
|
|
echo -e " ${BLU}9. REBUILD${RST}:"
|
|
echo -e " ${DIM}go build -tags goolm ./...${RST}"
|
|
echo ""
|
|
echo -e " ${BLU}10. START${RST}:"
|
|
echo -e " ${DIM}./dev-scripts/server/start.sh${RST}"
|
|
echo ""
|
|
echo -e " ${BLU}11. HEALTH CHECK${RST}:"
|
|
echo -e " ${DIM}./dev-scripts/agent/health-check.sh $ID${RST}"
|
|
echo ""
|
|
echo -e " ${BLU}12. SELF-INTRODUCE${RST} (tras health check ok):"
|
|
echo -e " ${DIM}./dev-scripts/agent/notify-developer.sh $ID $TYPE \"$DISPLAYNAME\"${RST}"
|
|
else
|
|
echo -e "${YLW}Siguientes pasos (8-12 del pipeline):${RST}"
|
|
echo ""
|
|
if [[ "$TYPE" == "robot" ]]; then
|
|
echo -e " ${BLU}8. PERSONALIZE${RST} — añadir comandos custom:"
|
|
echo -e " ${DIM}agents/$ID/commands.go${RST}"
|
|
echo -e " ${DIM}cmd/launcher/main.go${RST} (registrar comandos)"
|
|
else
|
|
echo -e " ${BLU}8. PERSONALIZE${RST} — personalizar los archivos del agente:"
|
|
echo -e " ${DIM}agents/$ID/agent.go${RST} — reglas de decisión"
|
|
echo -e " ${DIM}agents/$ID/config.yaml${RST} — LLM, tools, personalidad"
|
|
echo -e " ${DIM}agents/$ID/prompts/system.md${RST} — system prompt"
|
|
fi
|
|
echo ""
|
|
echo -e " ${BLU}9. REBUILD${RST}:"
|
|
echo -e " ${DIM}go build -tags goolm ./...${RST}"
|
|
echo ""
|
|
echo -e " ${BLU}10. START${RST}:"
|
|
echo -e " ${DIM}./dev-scripts/server/start.sh${RST}"
|
|
echo ""
|
|
echo -e " ${BLU}11. HEALTH CHECK${RST}:"
|
|
echo -e " ${DIM}./dev-scripts/agent/health-check.sh $ID${RST}"
|
|
echo ""
|
|
echo -e " ${BLU}12. SELF-INTRODUCE${RST} (tras health check ok):"
|
|
echo -e " ${DIM}./dev-scripts/agent/notify-developer.sh $ID $TYPE \"$DISPLAYNAME\"${RST}"
|
|
echo ""
|
|
fi # end $PERSONALIZE_DONE else
|