# Flujo del sistema de agentes — Diagrama de funciones ## 1. Arranque del sistema (Launcher) ```mermaid flowchart TD START["cmd/launcher/main()"] --> NEWLOGGER["newLogger(level)"] START --> GLOB["Glob: agents/*/config.yaml"] GLOB --> LOAD["config.Load(path)
→ os.ExpandEnv + validate()"] LOAD --> RULESFOR["rulesFor(agentID)
→ rulesRegistry[id]()"] RULESFOR --> AGENTNEW["agents.New(cfg, rules, logger)"] subgraph "agents.New() — Ensamblado" AGENTNEW --> MATRIXNEW["matrix.New(cfg.Matrix)
→ crea mautrix.Client"] MATRIXNEW --> CRYPTO{"encryption.enabled?"} CRYPTO -->|sí| INITCRYPTO["client.InitCrypto()
→ initCryptoCore()
→ initHelper()
→ resolvePickleKey()
→ logCryptoDiagnostics()"] INITCRYPTO --> FETCHKEYS{"recovery_key?"} FETCHKEYS -->|sí| CROSSSIGN["client.FetchCrossSigningKeys()
→ fetchCrossSigningKeysCore()"] FETCHKEYS -->|no| SSHEXEC CROSSSIGN --> SSHEXEC CRYPTO -->|no| SSHEXEC SSHEXEC["ssh.NewExecutor(cfg.SSH)"] SSHEXEC --> LLMFACTORY["llm.FromConfig(cfg.LLM.Primary)
→ NewAnthropicComplete() /
NewOpenAIComplete()"] LLMFACTORY --> FALLBACK{"fallback?"} FALLBACK -->|sí| WITHFALLBACK["llm.WithFallback(primary, fallback)"] FALLBACK -->|no| TOOLREG WITHFALLBACK --> TOOLREG TOOLREG["buildToolRegistry(cfg, ssh, matrix)
→ NewHTTPGet/Post()
→ NewSSHCommand()
→ NewReadFile()
→ NewCurrentTime()
→ NewMatrixSend()"] TOOLREG --> RUNNER["effects.NewRunner(matrix, ssh)"] RUNNER --> LISTENER["matrix.NewListener(client, cfg, handleEvent)"] end AGENTNEW --> RUN["agent.Run(ctx)
→ listener.Run(ctx)
→ mautrix.SyncWithContext()"] START --> SIGNAL["Espera SIGINT / SIGTERM
→ cancel ctx → shutdown"] ``` ## 2. Procesamiento de eventos (flujo principal) ```mermaid flowchart TD SYNC["mautrix SyncWithContext()"] --> EVENT["Evento Matrix recibido
EventMessage / StateMember"] EVENT --> AUTOJOIN{"StateMember
invite?"} AUTOJOIN -->|sí| JOIN["Auto-join room"] AUTOJOIN -->|no| SHOULD["listener.shouldHandle(evt)
→ filtra propios, bots, blocked, rooms"] SHOULD -->|rechazado| DROP["Descartado"] SHOULD -->|aceptado| ISDM["listener.checkIsDM(roomID)
→ cache de rooms con 2 miembros"] ISDM --> PARSE["message.Parse(body, sender, room, ...)
→ detecta mentions
→ parsea command + args
→ retorna MessageContext"] PARSE --> GOROUTINE["goroutine: agent.handleEvent()"] subgraph "handleEvent() — Decisión y ejecución" GOROUTINE --> TYPING["matrix.SendTyping(room, true)"] TYPING --> EVALUATE["decision.Evaluate(msgCtx, rules)
→ recorre reglas, Match() → []Action"] EVALUATE --> HASACTIONS{"¿acciones?"} HASACTIONS -->|sí| CHECKLLM{"¿contiene
ActionKindLLM?"} HASACTIONS -->|no| FALLBACKLLM{"¿es DM o
mención?"} FALLBACKLLM -->|sí| RUNLLM["agent.runLLM(ctx, msgCtx)"] FALLBACKLLM -->|no| NOOP["Sin acción"] CHECKLLM -->|sí| EXPANDLLM["Expande LLM actions:
runLLM() → ReplyAction"] CHECKLLM -->|no| EXECUTE EXPANDLLM --> EXECUTE RUNLLM --> EXECUTE["runner.Execute(ctx, roomID, actions)"] end ``` ## 3. Loop de herramientas del LLM (tool-use) ```mermaid flowchart TD RUNLLM["agent.runLLM()"] --> BUILD["Construir CompletionRequest
→ SystemPrompt desde archivo
→ Messages: historial + user
→ Tools: registry.ToLLMSpecs()"] BUILD --> CALL["CompleteFunc(ctx, request)
→ Anthropic API / OpenAI API"] subgraph "shell/llm — Proveedores" CALL --> ANTHROPIC["NewAnthropicComplete()
→ toAnthropicRequest()
→ HTTP POST /v1/messages
→ fromAnthropicResponse()"] CALL --> OPENAI["NewOpenAIComplete()
→ toOpenAIMessage()
→ toOpenAITools()
→ SDK CreateChatCompletion"] end ANTHROPIC --> RESPONSE["CompletionResponse
{Content, ToolCalls, Usage}"] OPENAI --> RESPONSE RESPONSE --> HASTOOLS{"¿ToolCalls
en respuesta?"} HASTOOLS -->|no| RETURN["Retorna Content como texto"] HASTOOLS -->|sí| EXECTOOLS["Por cada ToolCall:
registry.Execute(name, argsJSON)"] subgraph "tools/ — Ejecución de herramientas" EXECTOOLS --> TOOLSWITCH{"tool name"} TOOLSWITCH --> HTTP_GET["http_get
→ validateDomain()
→ GET request"] TOOLSWITCH --> HTTP_POST["http_post
→ validateDomain()
→ POST request"] TOOLSWITCH --> SSH_CMD["ssh_command
→ validateTarget()
→ validateCommand()
→ ssh.Executor.Execute()"] TOOLSWITCH --> READ_FILE["read_file
→ validatePath()
→ os.ReadFile()"] TOOLSWITCH --> MATRIX_SEND["matrix_send
→ client.SendText()"] TOOLSWITCH --> CURRENT_TIME["current_time
→ time.Now().Format()"] end EXECTOOLS --> APPEND["Append assistant msg + tool results
a Messages del request"] APPEND --> ITER{"iteración <
maxIter?"} ITER -->|sí| CALL ITER -->|no| RETURN ``` ## 4. Ejecución de efectos (Runner) ```mermaid flowchart TD EXECUTE["runner.Execute(ctx, roomID, actions)"] --> LOOP["Por cada Action en []Action"] LOOP --> EXECONE["runner.executeOne(ctx, roomID, action)"] EXECONE --> KIND{"action.Kind"} KIND -->|ActionKindReply| REPLY["matrix.SendText(ctx, roomID, content)
→ envío auto-encriptado si E2EE"] KIND -->|ActionKindSSH| SSHEXEC["ssh.Executor.Execute(ctx, spec)"] KIND -->|otro| UNHANDLED["Result{Err: unhandled}"] subgraph "shell/ssh — Ejecución SSH" SSHEXEC --> LOOKUP["Buscar target en config
→ resolver user/port/key"] LOOKUP --> LOADSIGNER["loadSigner(keyFileEnv)
→ leer clave privada"] LOADSIGNER --> DIAL["gossh.Dial(tcp, host:port)"] DIAL --> SESSION["client.NewSession()"] SESSION --> RUNCMD["session.CombinedOutput(cmd)"] RUNCMD --> SSHRESULT["Result{Stdout, Stderr, ExitCode}"] end REPLY --> RESULT["Result{Action, Output, Err}"] SSHRESULT --> RESULT UNHANDLED --> RESULT ``` ## 5. Motor de reglas puro (decision engine) ```mermaid flowchart TD EVAL["decision.Evaluate(ctx, rules)"] --> LOOP["Por cada Rule"] LOOP --> MATCH["rule.Match(ctx) → bool"] subgraph "MatchFuncs disponibles (pure)" MATCH --> CMD["MatchCommand(cmd)
ctx.Command == cmd"] MATCH --> PREFIX["MatchPrefix(prefix)
strings.HasPrefix(ctx.Content)"] MATCH --> ANY["MatchAny()
→ true siempre"] MATCH --> POWER["MatchMinPowerLevel(n)
ctx.PowerLevel >= n"] MATCH --> COMPOSE["And(...) / Or(...)
composición lógica"] end MATCH -->|true| COLLECT["Agregar rule.Actions a resultado"] MATCH -->|false| NEXT["Siguiente regla"] COLLECT --> NEXT NEXT --> LOOP LOOP -->|fin| ACTIONS["Retorna []Action acumuladas"] ``` ## 6. Gestión de procesos (agentctl / dev-scripts) ```mermaid flowchart TD CLI["cmd/agentctl/main()"] --> MGR["process.NewManager(runDir, glob, bin)"] MGR --> LISTCMD["listCmd → mgr.StatusAll()"] MGR --> STARTCMD["startCmd → mgr.Start(info)"] MGR --> STOPCMD["stopCmd → mgr.Stop(id)"] MGR --> REMOVECMD["removeCmd → mgr.Stop + setEnabled(false)"] subgraph "process.Manager — Ciclo de vida" LISTCMD --> SCAN["mgr.Scan()
→ glob configs
→ config.LoadMeta()"] SCAN --> STATUS["mgr.Status(info)
→ findProcessPIDs()
→ resolveRunningPID()"] STARTCMD --> STARTCHECK{"¿ya running?"} STARTCHECK -->|sí| REJECT["Error: already running"] STARTCHECK -->|no| LAUNCH["Abrir log file
→ buildEnv()
→ os/exec.Start()
→ escribir PID file"] STOPCMD --> SIGTERM["SIGTERM a todos los PIDs"] SIGTERM --> WAIT["Esperar 5s (polls cada 500ms)"] WAIT --> ALIVE{"¿todavía vivo?"} ALIVE -->|sí| SIGKILL["SIGKILL"] ALIVE -->|no| CLEAN["removePID()"] SIGKILL --> CLEAN end subgraph "Monitoreo" STATUS --> STATS["mgr.Stats(id)
→ statsForPID()
→ /proc/pid/stat (uptime)
→ /proc/pid/status (RSS)
→ ps -o pcpu (CPU)"] STATUS --> LOGS["mgr.LogTail(id, n)
→ últimas N líneas del log"] end ``` ## 7. Dashboard TUI (Bubbletea — pure core / impure shell) ```mermaid flowchart TD MAIN["cmd/dashboard/main()"] --> BRIDGE["newBridge(adapter)"] BRIDGE --> TEA["tea.NewProgram(bridge)"] subgraph "Pure Core — pkg/tui" INIT["bridge.Init()
→ IntentLoadAgents"] UPDATE["puretui.Update(model, msg)
→ (Model, []Intent)"] VIEW["puretui.View(model)
→ string renderizado"] UPDATE --> SCREENS{"Screen actual"} SCREENS --> MAIN_MENU["updateMainScreen()"] SCREENS --> AGENT_LIST["updateAgentList()"] SCREENS --> AGENT_ACTIONS["updateAgentActions()
→ executeAction()"] SCREENS --> LOGS_VIEW["updateLogs()"] SCREENS --> SERVER_VIEW["updateServerScreen()
→ executeServerAction()"] end subgraph "Impure Shell — shell/tui" ADAPTER["Adapter.RunIntent(intent)"] ADAPTER --> LOAD["loadAgents()
→ mgr.StatusAll() + Stats()"] ADAPTER --> START["startAgent(id)
→ mgr.Start()"] ADAPTER --> STOP["stopAgent(id)
→ mgr.Stop()"] ADAPTER --> KILL["killAgent(id)
→ mgr.Kill()"] ADAPTER --> RESTART["restartAgent(id)
→ Stop + Start"] ADAPTER --> STARTALL["startAll() / stopAll()
restartAll() / killAll()"] ADAPTER --> LOADLOGS["loadLogs(id)
→ mgr.LogTail()"] end TEA --> INIT INIT --> ADAPTER TEA --> UPDATE UPDATE -->|"[]Intent"| ADAPTER ADAPTER -->|"tea.Cmd → Msg"| UPDATE TEA --> VIEW ``` ## 8. Registro y verificación E2EE de bots ```mermaid flowchart TD subgraph "cmd/register — Registro en Matrix" REG["main()"] --> CREATE["createUser(homeserver, token, userID, name, pass)
→ PUT /_synapse/admin/v2/users/"] CREATE --> LOGIN["loginAs(homeserver, user, pass)
→ POST /_matrix/client/v3/login"] LOGIN --> TOKEN["Imprime access_token + device_id
→ exportar como MATRIX_TOKEN_BOT"] REG --> GENPASS["generatePassword()
→ 24 bytes /dev/urandom → hex"] end subgraph "cmd/verify — Cross-signing E2EE" VER["main()"] --> MAUTRIX["Crear mautrix.Client"] MAUTRIX --> INITCRYPTO["cryptohelper.Init()
→ mismo store que el agente"] INITCRYPTO --> GENKEYS["GenerateAndUploadCrossSigningKeys
WithPassword()"] GENKEYS --> RECOVERY["Imprime SSSS recovery key"] GENKEYS -->|"keys exist"| SIGNOWN["signOwnDevice()
→ mach.SignOwnDevice()"] end ``` ## 9. Flujo completo end-to-end ```mermaid flowchart LR USER["Usuario Matrix"] -->|"mensaje"| HOMESERVER["Matrix Homeserver"] HOMESERVER -->|"sync"| LISTENER["Listener.Run()
shouldHandle()
checkIsDM()"] LISTENER -->|"Parse()"| MSGCTX["MessageContext
(puro)"] MSGCTX -->|"handleEvent()"| DECIDE["Evaluate(rules)
(puro)"] DECIDE -->|"[]Action"| BRANCH{"¿tipo?"} BRANCH -->|"LLM"| LLM["runLLM()
→ tool-use loop"] LLM -->|"CompleteFunc"| API["Anthropic / OpenAI API"] API -->|"ToolCalls"| TOOLS["Registry.Execute()
http / ssh / file / time"] TOOLS -->|"results"| LLM LLM -->|"texto final"| REPLY BRANCH -->|"Reply"| REPLY["SendText() / SendMarkdown()"] BRANCH -->|"SSH"| SSH["Executor.Execute()"] SSH -->|"resultado"| REPLY REPLY -->|"respuesta"| HOMESERVER HOMESERVER -->|"mensaje"| USER ```