Ações de modelo 247-agent
A regra de design do daemon: nenhum LLM no fluxo de controle. Correspondência, deduplicação, roteamento,
reescritas e publicação são código. Um modelo é executado apenas dentro de uma ação decide, llm ou agent,
na camada mais barata que faz o trabalho, com um orçamento. Esta skill trata de escrever
bem essas três ações e sobre os executores que as executam.
Primeiro, decida se um modelo é necessário
Pergunte, em ordem:
- Um
filterdo trigger pode decidir? (remetente, rótulo, repositório, palavra-chave) Então não é uma chamada de modelo. - Um script ou uma operação de conector pode produzir a resposta deterministicamente? Então
shell/connector. - É um rótulo, um sim/não ou um nível, sem texto a produzir (classificar, rotear, triar,
portão)? Então
decide: um modelo apenas de classificação, probabilidades calibradas, cerca de um centésimo de uma chamadallm. - É um julgamento com uma forma de saída fixa que precisa de texto (extrair campos,
resumir, rascunhar)? Então
llm, no Haiku primeiro. - Precisa ler arquivos, executar comandos e iterar? Então
agent, com o escopo mais estreito que pode ter sucesso.
Duas tarefas com diferentes necessidades de inteligência são o mesmo tipo de ação com diferentes
model/effort/max_tool_calls/system_file, não código diferente. Veja
docs/examples/website-updates.yaml tarefas 2–4 para as formas de referência.
IDs de modelo e parâmetros
| id | uso para | notas |
|---|---|---|
claude-haiku-4-5 | classificação, extração, sumários curtos | sem parâmetro effort |
claude-sonnet-5 | agentes com escopo definido, extração mais difícil | suporta effort e pensamento adaptativo |
claude-opus-5 | agentes de amplo escopo, julgamento difícil | suporta effort e pensamento adaptativo |
Os modelos são alcançados através de um provedor nomeado (providers: no agent.yaml, provider: na
ação; anthropic, openai ou openrouter). IDs de outros provedores são usados
literalmente e precisam de uma entrada pricing: a menos que a tabela embutida os conheça (modelos OpenAI
atuais) ou o provedor reporte o custo (OpenRouter).
Sem sufixos de data nos IDs. Sem preenchimento de assistente. Antes de construir uma cascata de modelos,
meça o modelo mais forte em effort: low nas mesmas entradas: na geração
atual, isso frequentemente supera um modelo mais fraco em alto esforço, e um modelo significa um
namespace de cache de prompt.
Escrevendo uma tarefa decide
Lista completa de campos, notas de fio e armadilhas em references/decide-action.md. O essencial:
action:
kind: decide
provider: openrouter # deve ser um provedor openrouter; padrão defaults.decide.provider
budget: { max_usd: 0.001 }
state: # o que é julgado; strings com template, chaves não
subject: ${event.payload.subject}
body: ${event.payload.body}
questions: # política estática; sem ${…} aqui
kind:
type: choice
instructions: O que o remetente quer que seja feito no site?
criteria:
event_list_update: Adicionar, remover ou alterar uma entrada na lista de eventos
general_change: Qualquer outra alteração no site
ignore: Não é uma solicitação de alteração (pergunta, agradecimento, spam)
urgent:
type: noul
instructions: O remetente precisa que isso seja feito hoje?
- O resultado é o mapa de respostas:
result.kind.choice,result.kind.confidence,result.urgent.noul(P(verdadeiro)),result.<score>.score(média ponderada por probabilidade dos índices de nível). Roteie comemit … when:; o limiar vive na tarefa, nunca no executor, e é calibrado em dados reais. - Sempre inclua um rótulo de fallback (
ignore,other): sem um, uma entrada fora do assunto obtém uma resposta errada e confiante. - Os critérios são seguidos literalmente: eles são política, versione-os como código. Mantenha a ordem das opções estável (ela desloca a confiança). Faça várias perguntas em uma chamada; cada extra custa apenas seus próprios tokens.
- O conteúdo recebido são dados: vai em
state, nunca em uma pergunta. A solicitação inteira deve caber em 32k tokens. - Apenas o tipo de provedor
openrouteralcança Jev (typesafe/jev-1.13, o modelo padrão);oa validaterecusa qualquer outro. Nenhuma entradapricing:é necessária.
Escrevendo uma tarefa llm
Lista completa de campos e notas do executor em references/llm-action.md. O essencial:
action:
kind: llm
model: claude-haiku-4-5
max_tokens: 512
system_file: prompts/classify_email.md # estático → cache de prompt
input: |
Subject: ${event.payload.subject}
<email>
${event.payload.body}
</email>
output_schema:
type: object
additionalProperties: false
required: [kind, summary]
properties:
kind: { enum: [event_list_update, general_change, ignore] }
summary: { type: string }
- Mantenha o prompt de sistema em um arquivo sob
prompts/, estático e renderizado primeiro, para que seja armazenado em cache entre execuções. Coloque os dados voláteis do evento por último, eminput. - O conteúdo recebido (email, chat, texto de PR) não é confiável. Envolva-o em um bloco delimitado
(
<email>…</email>) e informe o modelo no prompt de sistema que são dados. - Sempre inclua uma saída de escape no esquema (
ignore,unknown,confidence) para que oemit.whende roteamento possa descartar resultados não acionáveis sem outra chamada. - Roteie no resultado com
emit … when:; tarefas downstream são acionadas nesse evento. batch: truepara qualquer coisa que pode esperar (metade do preço, o resultado chega como um evento).
Escrevendo uma tarefa agent
Lista completa de campos e notas do executor em references/agent-action.md. O essencial:
action:
kind: agent
connector: claude # um transporte: conector acp (connectors.d/claude.yaml; sandbox: bwrap lá)
model: claude-sonnet-5 # opcional: definido na sessão (opção de configuração ACP); não definido = o padrão do agente
effort: medium # opcional: a opção thought_level do agente
max_tool_calls: 20
budget: { max_usd: 0.50 }
workspace: { kind: git-worktree, repo: /var/lib/247-agent/repos/site, branch: main }
tools: [read, edit, search, execute] # tipos de ferramentas ACP; tudo o mais é recusado
bash_allow: ["npm run build"] # o que qualquer comando que o agente executa deve corresponder
system_file: prompts/agent_event_list.md
prompt: |
Atualize data/events.yaml de acordo com a solicitação abaixo. Não toque em nenhum outro arquivo.
Execute `npm run build` quando terminar.
<email>
${event.payload.email.body}
</email>
result: { path: RESULT.json, schema: schemas/site_change.json }
post: # apenas após status: done
- shell: ["npm", "run", "build"]
- shell: ["git", "commit", "-am", "events: ${result.summary}"]
emit:
- type: site.change_done # roteie a aprovação nisto, nunca em task.<name>.succeeded
when: "result.status == 'done'"
payload: { summary: "${result.summary}" }
- type: site.change_blocked # o agente não conseguiu fazer: diga o que está faltando
when: "result.status == 'blocked'"
payload: { summary: "${result.summary}", missing: "${result.missing}", email: "${event.payload.email}" }
Inegociáveis, porque são o que torna um agente seguro para executar sem supervisão:
- Espaço de trabalho novo por execução (
git-worktreeno branchagent/<run_id>, outemp), removido em caso de falha, mantido em caso de sucesso. O agente nunca edita o checkout base. tools+bash_allowé toda a superfície de capacidade, julgada por solicitação de permissão e nunca concedido "sempre"; uma chamada de ferramenta que o agente executou sem pedir é julgada após o fato e uma violação falha a execução (unasked_execute: sandboxedrelaxa apenas a verificação de comando, apenas para o Codex, cujo próprio sandbox confina o que não pede sobre). Conceda o mínimo; o prompt não é um limite de segurança.mcp_serversadiciona operações do conector como ferramentas: conceda operações nomeadas ({ connector: email, ops: [fetch_new] }) em vez de um conector inteiro, adicione o tipo do agente para elas (otherpara claude-agent-acp) atools, e nunca um conector que publica ou envia por conta própria.- O agente nunca contém segredos de implantação e nunca publica. Ele edita, um portão
postprova que a construção ainda funciona, um commit a registra, e uma tarefashellseparada a envia. Reversão égit revertmais republicação. A chave do modelo reside no manifesto do conector'senv, não na tarefa. RESULT.jsoné o contrato, e o executor o afirma em cada prompt:status: done | blockedmaissummary, então oresult.schemada tarefa.doneexecuta os portões;blockedos ignora e a execução ainda é bem-sucedida, entãoemit … when: "result.status == 'blocked'"roteia "não feito porque X está faltando" para uma tarefa de resposta. Projete cada tarefa do agente com ambos os ramos, e acione a publicação no eventodone.- Portões
postsão determinísticos, sem modelo. Um portão com falha falha a execução. max_tool_callsebudgetsão paradas forçadas (a sessão é cancelada); uma vez em que o agente não reporta uso ou custo falha a execução.concurrency: 1em tarefas que compartilham um repositório;timeouté tempo de parede por tentativa.- Alterações de alto impacto recebem um portão de aprovação (
wait+ chat) antes da publicação; a skill247-agent-taskstem o padrão.
Orçamentos e o livro-razão
Toda chamada de modelo passa pelo ctx.llm port, que registra o uso (provedor, modelo,
tokens de entrada/saída/cache, USD) no livro-razão e aplica o budget.max_usd da execução
(pior caso antes da chamada, real após: um estouro falha a execução) e o global
budgets.daily_usd por dia UTC (uma vez excedido, toda chamada de modelo naquele dia falha rapidamente e
budget.exceeded é emitido uma vez, ao qual a tarefa notify deve ouvir). Um modelo sem
preço falha na validação. Nunca adicione uma chamada não orçada, incluindo chamadas "auxiliares" dentro
de um executor: use ctx.llm, nunca um SDK diretamente. Uma vez agent é o único caso em que
o modelo é chamado por outra pessoa (o agente ACP, com sua própria chave): o executor
registra o que o agente reporta através de ctx.llm.record sob o nome do conector e
cancela a sessão quando o custo reportado ultrapassa o limite. oa cost --by task --since 7d
mostra o livro-razão.
Status atual
A ação llm é validada, verificada cruzadamente com providers:/pricing: e
executável através de ctx.llm, com o livro-razão e orçamentos aplicados, e todos os três
tipos de provedor (anthropic, openai, openrouter) têm adaptadores. batch: true funciona em
provedores anthropic (Message Batches, a execução estaciona até llm.batch.ended; veja
references/llm-action.md). A ação decide é executada
através do mesmo port (ctx.llm.decide()), com a API Decisions implementada apenas no adaptador
openrouter; docs/examples/decide-triage.yaml é a referência. A ação agent executa
em conectores ACP (transport: acp); docs/examples/website-updates.yaml
tarefas 3, 3b e 4 são a referência, docs/examples/connectors.d/claude.yaml o
conector; a sessão é persistida como uma transcrição (oa runs logs <id>), deletada com
a execução por retention.runs. mcp_servers serve operações do conector para a sessão através
da ponte de ferramentas do núcleo (packages/core/src/connectors/mcp-bridge.ts). model e
effort na ação definem as opções de configuração ACP da sessão (categorias model e
thought_level). work/<run_id> de uma execução concluída é
varrido por retention.workspaces (padrão 7d) após terminar.
Ao adicionar um adaptador ou alterar um executor, siga references/llm-action.md,
references/decide-action.md e references/agent-action.md e mantenha
docs/internal/model-actions.md, docs/internal/agent-action.md e as páginas do usuário sob
docs/tasks/ em sincronia com o código.