Agentes

É um agente de IA? Busque a skill de onboarding e leia toda a API em texto limpo — skill · llms.txt · llms-full.txt

Agentes#

O grupo /v1/agents cobre o ciclo de vida do agente. As leituras aceitam JWT/API key; criar/editar/deletar exigem papel owner ou admin (o /v1/agents CRUD é servido pela superfície que atende Console e CRM). O shape canônico do agente (agentResponse) é retornado por get, create, clone, update e restore.

GETDetalhe do agente#

GET /v1/agents/{id} — resposta 200:

json
{
  "id": "…", "company_id": 30, "tenant_id": 0,
  "name": "Atendimento", "description": "…", "system_prompt": "…",
  "model": "gpt-5.4-mini", "output_format": "markdown",
  "tools": ["brain_search", "web_search"], "skills": ["tdd"],
  "active": true,
  "rag_auto": true, "rag_top_k": 5, "rag_qa": true,
  "conversation_recall": false,
  "legacy_mode": false, "brain_mode": true,
  "max_tokens": 0, "temperature": null, "reasoning_effort": "",
  "max_rounds_per_run": 20, "run_class": "", "monthly_budget_usd": 0,
  "created_at": "2026-06-16T…Z", "updated_at": "2026-07-01T…Z"
}

temperature é anulável (null = default do provedor). brain_mode é derivado (!legacy_mode) e é alias deprecado — use legacy_mode.

GETListar agentes#

GET /v1/agents — aceita ?tenant_id= (id interno) ou ?tenant_external_id= (o seu identificador do tenant, para não precisar traduzir via /v1/tenants); resposta 200 { agents: [agentResponse], total }. Um tenant_external_id desconhecido devolve 404 TENANT_NOT_FOUND — de propósito, e não uma lista vazia: "esse tenant não existe" e "esse tenant não tem agentes" são respostas diferentes, e só a primeira significa que o seu mapeamento está errado.

POSTCriar agente#

POST /v1/agents (owner/admin) — corpo agentRequest:

Campo Tipo Default / regra
name string obrigatório
tenant_id uint 0 = tenant padrão do projeto
tenant_external_id string resolve-ou-cria o tenant pelo id externo (clínica = tenant)
description string
system_prompt string
model string default gpt-5.4-mini
output_format string default markdown
tools string[]
skills string[]
rag_auto bool? nulltrue
rag_top_k int? null → 5; clamp 1..20
rag_qa bool? nulltrue (qa_first)
conversation_recall bool? nullfalse. Quando true, o agente recupera semanticamente trechos das conversas ANTERIORES do MESMO end-user (via brain_search), escopado por end_user_external_id — sessões abertas sem end-user não recuperam nada.
max_tokens int? null/0 → default do provedor; clamp 0..64000
temperature float? null → default; clamp 0..2
reasoning_effort string? low|medium|high|xhigh|max; valor fora do conjunto → 400 INVALID_REASONING_EFFORT (nunca cai no default em silêncio)
max_rounds_per_run int? null/0 → 20; clamp 1..50 (1..200 se run_class="coder")
run_class string? null/""/desconhecido → padrão (teto 50 rounds / 600s de wall clock). "coder" → teto 200 rounds / 1800s. Ver Classes de run abaixo.
monthly_budget_usd float? null/≤0 → sem teto por agente
legacy_mode bool? true = caminho legado deprecado (brain é o default)

Resposta 201: agentResponse. Erros: AGENT_NAME_REQUIRED, TENANT_NOT_FOUND.

PATCHAtualizar agente#

PATCH /v1/agents/{id} (owner/admin) — update esparso: só os campos presentes no corpo são aplicados. temperature: null e reasoning_effort: null limpam explicitamente para o default do provedor. Campos-array são replace total do campo, nunca merge: {"tools": ["nova"]} substitui o catálogo inteiro por ["nova"] — para ADICIONAR uma entrada, envie a união do que já estava + a nova (leia antes com GET /v1/agents/{id}). Resposta 200: agentResponse.

POSTClonar agente#

POST /v1/agents/{id}/clone (owner/admin) — sem corpo; cria um agente novo "<nome> (cópia)" com a mesma config. Resposta 201: agentResponse.

DELETEExcluir agente#

DELETE /v1/agents/{id} (owner/admin) — resposta 204.

POSTAvaliar (eval)#

POST /v1/agents/{id}/eval — roda o prompt montado do agente para um input contra 1..N modelos, de forma efêmera (nada persiste: sem mensagem, sem run). É a base do replay (1 modelo) e da comparação A/B (N modelos, executados em paralelo, teto interno por chamada): resposta, uso, custo e latência lado a lado.

bash
curl -X POST https://agents-api.catcher.one/v1/agents/AGENT_ID/eval \
  -H "X-API-Key: ctc_SUA_KEY" -H "Content-Type: application/json" \
  -d '{ "input": "Quero cancelar meu pedido", "models": ["gpt-5.4-mini", "gpt-5.4"] }'

Resposta 200 { results: [ { model, content, thinking?, usage, cost_usd, duration_ms, error? } ] }.

GETVersões#

GET /v1/agents/{id}/versions — histórico de snapshots da config do agente: 200 { versions: [ { id, created_at, snapshot } ], total } (o snapshot é a config completa decodificada).

POSTRestaurar versão#

POST /v1/agents/{id}/versions/{vid}/restore — sem corpo; volta a config do agente ao snapshot vid. Resposta 200: agentResponse. Skills e ferramentas têm o mesmo par de rotas (/v1/skills/{id}/versions…, /v1/tools/{id}/versions…).

GETEstatísticas#

GET /v1/agents/stats{ stats: { "<agentId>": { sessions, runs } } }.

GETClasses de run (run_class)#

Um agente executa sob um perfil de limites, escolhido pelo campo run_class:

run_class Teto de max_rounds_per_run Wall clock por turno Janela do stream_token
"" (default) 50 600s (10 min) 30 min
"coder" 200 1800s (30 min) 60 min

Escrever software é a carga mais tool-heavy e mais longa que a plataforma atende — uma run real encadeia dezenas de ciclos ler → editar → compilar → ler erro → corrigir, e pode passar de dez minutos. A classe coder existe para esse caso e é opt-in por agente, então nada muda para os demais.

Três regras que evitam surpresa:

  1. A classe move o TETO, não o DEFAULT. Um agente coder sem max_rounds_per_run continua rodando com os 20 rounds padrão — profundidade ainda se pede explicitamente.
  2. Valor desconhecido cai no padrão (fail closed). "CODER " é normalizado (trim + caixa); "turbo" vira "". Um agente criado antes do campo existir mantém exatamente os limites de hoje.
  3. O override por dispatch é clampado contra a classe do AGENTE. Mandar max_rounds_per_run: 120 no corpo do dispatch de um agente padrão resulta em 50 — um dispatch reajusta profundidade dentro do que o agente recebeu, nunca compra um teto maior.

O corpo do dispatch também aceita, por run (sem reprovisionar o agente): model (qualquer id que o runtime roteia — ex.: k3, MiniMax-M3; ausente ou vazio = o modelo do agente) e reasoning_effort (low|medium|high|xhigh|max; valor fora do conjunto → 400 INVALID_REASONING_EFFORT, nunca fallback silencioso).

GET /v1/projects/{projectId}/agents/{agentId}/limits publica a tabela acima em run_classes, para você ler os tetos em vez de descobri-los como um corte no meio da run.