Skip to content

Visão geral dos agents

Ongrid é um sistema multi-agente ReAct. O usuário sempre fala com o coordinator — a persona de topo na superfície de chat. Quando uma tarefa cabe em um domínio especializado (investigação profunda de causa raiz, revisão de ação mutadora, deep dive de rede), o coordinator despacha para um sub-agente (um "worker") via AgentTool. Cada worker roda o mesmo graph kernel contra uma tool bag filtrada e retorna uma resposta final que o coordinator tece em sua resposta.

Esta página é o mapa. As páginas de cada persona explicam cada agent em detalhe.

Personas, não threads de chat

Uma persona é um arquivo em disco que descreve o que um agent faz. O layout canônico — mesmo formato do agent format do Claude Code com chaves snake_case:

yaml
---
name: specialist-disk
description: 文件系统 / 磁盘容量专家 — du / find / stat / inode / 挂载 / 大文件
when_to_use: |
  When the task is about disk / filesystem health:
    - Disk full / utilization climbing
    - Hunt for large files / large directories
    - inode exhaustion / mount point inspection
tools:
  - query_knowledge
  - host_find_large_files
  - host_du_summary
  - host_stat_file
  - host_bash
  - query_promql
  - get_host_load
permission_mode: read-only
max_turns: 15
---
[markdown body — this becomes the system prompt]

O corpo abaixo do frontmatter é o SystemPrompt. Dois arquivos de persona com o mesmo name colidem e o loader registra um warning. Veja referência de formato de persona para todo campo.

Personas vivem sob ./agents/ na imagem do manager (/app/agents/ dentro do container). O Ongrid distribui personas built-in na imagem e também lê personas escritas pelo usuário de um diretório montado — veja Agents customizados.

Coordinator vs worker

AspectoCoordinatorWorker
Quem fala com o usuárioSim (via superfície de chat ou IM)Nunca — a saída do worker vai ao coordinator
Tool bagAmpla: query_*, AgentTool, redirect stubsEstreita: whitelist tools: da persona
Nome da personadefault (ou override por org)specialist-*, incident-investigator, reviewer
Spawned porRuntime (uma por sessão de chat)AgentTool ou decorator review_gate
Pode dar spawn?Sim (em workers)Não (workers não podem aninhar por design)
SessãoLonga duração, persistidaNova sessão por spawn, escopada a um turno

A função do coordinator é dispatch + triage + síntese. Ferramentas de deep-dive vivem nos workers. O coordinator carrega slots de RedirectStub para tools que o LLM tende a alucinar (host_bash, get_host_load, …); chamar uma delas retorna uma mensagem de redirect que induz o modelo a reinvocar via AgentTool.

AgentTool

A primitiva de dispatch do coordinator. Wire name AgentTool (PascalCase para alinhar com o tool catalog do Claude Code). O schema visível ao LLM:

json
{
  "type": "object",
  "properties": {
    "description":   {"type": "string"},
    "subagent_type": {"type": "string"},
    "prompt":        {"type": "string"}
  },
  "required": ["description", "subagent_type", "prompt"]
}
  • description — resumo de 1 linha da tarefa usado no tile do SPA.
  • subagent_typename da persona. O catálogo injetado no system prompt do coordinator lista os valores válidos (o registry de personas, menos reviewer e default).
  • prompt — briefing completo da tarefa. O worker não vê o contexto do coordinator — empacote cada detalhe necessário (incident_id, device_id, redação exata).

A chamada é síncrona do ponto de vista do coordinator. Bloqueia até o worker atingir completed / failed / killed. Uma revisão anterior tinha uma flag async background: true; modelos fracos pegavam, respondiam ao usuário com o task_id pendente, e nunca seguiam. A flag não existe mais hoje (veja agent_tool.go para o comentário post-mortem). O único caminho async é o reviewer — e esse é dirigido pelo decorator, não pelo LLM.

Dedupe é embutido

Um LRU de 120s indexado por sha256(subagent_type + canonical(prompt)) faz curto-circuito na segunda de duas chamadas idênticas de AgentTool. O LLM vê o resultado anterior com uma dica explícita "você já despachou isso". Reduz loop blowouts no coordinator (E2E eval D1 viu 122 chamadas de tool em 240s sem dedupe).

Como um system prompt é composto

ComposeSystemPrompt monta o prompt que o LLM recebe, em ordem:

  1. basePrompt — o preâmbulo universal do runtime. Pode estar vazio.
  2. agentProfile.SystemPrompt — o corpo markdown da persona. Coordinator pode carregar um (a maioria carrega); workers sempre carregam.
  3. agentProfile.CriticalReminder — envolvido em <critical-reminder>...</critical-reminder>. É a constante a nível de persona; a camada de grafo também re-injeta por turno como <system-reminder> para sobreviver ao attention drift em sessões longas.
  4. Para cada skill ativa: um header [能力: <name>] + o PromptBody da skill.

Coordinator ganha um bloco extra antes da lista de skills: o catálogo de agents (buildAgentCatalog) — uma lista markdown de bullets com "specialists disponíveis" com a description e a primeira linha do when_to_use. O catálogo deliberadamente exclui reviewer (só o decorator ReviewGate pode dar spawn nele) e default (a persona virtual de topo — listá-la como sub-agent spawnable permitiria que o coordinator desse spawn em si mesmo recursivamente).

A agent registry

O AgentRegistry mantém personas parseadas em memória. Carrega uma vez no startup; Reload() sob um único swap de sync.RWMutex para que um turno de coordinator em andamento nunca observe um registry meio-carregado.

MétodoQuando
Load(root)Startup. Percorre <root>/**/*.md recursivamente.
Reload(root, ...)Instalação/desinstalação do marketplace. Swap atômico.
ByName(name)Lookup no spawn. Retorna (nil, false) em miss.
Replace(ag)Edição de user-agent. Upsert in place — live registry, sem restart.
Remove(name)Deleção de user-agent.

Erros de parse por arquivo viram warnings em vez de abortar a caminhada (mesma política do skill registry). Roots de agent inexistentes não são erro — você ganha um registry vazio, não uma falha de startup.

Reviewer e o review gate

O reviewer é especial: o coordinator não pode dar spawn nele. É gateado pelo decorator ReviewGate, que intercepta qualquer tool cuja Class seja "write" ou "destructive". O decorator:

  1. Monta um payload de proposta (action, target, reason, blast_radius, operator).
  2. Dá spawn no worker reviewer (sync do POV da tool interna) com seu próprio timeout de 60s, independente dos 15s da tool interna.
  3. Se o reviewer retornar Decision: approve, a chamada passa para a tool interna. Caso contrário o decorator retorna ErrReviewRejected envolvendo a razão do reviewer.

Por isso o catálogo de agents omite reviewer: só o decorator pode invocá-lo. Colocá-lo no catálogo permitiria que o coordinator despachasse "reviews" ad-hoc que não fazem gate de nada.

Veja Reviewer para a máquina de estados completa.

Ciclo de vida do worker

Máquina de estados Runtime.SpawnWorker:

text
pending  → running  → completed
                   ↘ failed
                   ↘ killed     (StopWorker called while running)
  • Uma linha em chat_sessions é criada antecipadamente para que queries de auditoria + árvore pai → worker resolvam mesmo enquanto o worker ainda está rodando.
  • Spawns em background derivam do contexto do runtime de longa duração para que uma requisição HTTP terminando não derrube o worker no meio do run; spawns síncronos herdam o ctx do caller.
  • A linha de sessão é fechada (closed_at setado) em todo caminho terminal, incluindo panics — sem isso, linhas órfãs acumulam (o test env chegou a 161 antes do fix entrar).

Workers não podem dar spawn em workers. SpawnWorker é exposto só no Runtime, e o filtro disabledForWorker remove AgentTool da tool bag de qualquer worker. Um coordinator, N workers paralelos, sem aninhamento mais profundo.

O que vem a seguir

  • Coordinator — a persona padrão, suas três control tools, e quando despachar vs responder direto.
  • Incident investigator — causa raiz até o "paciente zero", o budget de 18 ferramentas, e o eval F1.
  • Specialists — compute / disk / network / ops / sre, o que cada um detém, como o coordinator escolhe.
  • Reviewer — o gate de double-sign do SOP em tools mutadoras.
  • Agents customizados — escreva sua própria persona, hot-reload, debug.