Saltar para o conteúdo

Documentação

Perguntar primeiro.Agir depois.

Os agentes perguntam. As pessoas decidem.

Fale connosco

O pedido

Envie a ação com a chave de ingestão. O mesmo idempotency_key do mesmo agente devolve o mesmo pedido (200 em vez de 201), por isso repetir nunca cria um segundo. Consulte o pedido até ser decidido.

POST /api/agent/v1/actions
Authorization: Bearer bfa_…

{
  "action": "payments.transfer",
  "summary": "Pay supplier invoice 42",
  "params": { "amount": 40000, "currency": "EUR" },
  "idempotency_key": "invoice-42",
  "expires_in_secs": 3600
}

→ 201 { "id": "…", "status": "pending", "required_approval": "user", "expires_at": "…" }
GET /api/agent/v1/actions/{id}   # until status is approved, rejected or expired

action

1 a 100 caracteres: letras, dígitos e . _ - :. As políticas de aprovação podem usá-lo.

summary

O que uma pessoa lê ao decidir, até 500 caracteres.

params

Um objeto JSON até 16 KiB. As pessoas veem-no por inteiro; o registo de auditoria guarda só os nomes dos campos.

expires_in_secs

60 a 604800, por omissão 86400. Um pedido que ninguém decidiu a tempo passa a expired.

Quem decide, e com que rigor

O rigor da verificação nunca é escolha do agente. Todo o pedido precisa de pelo menos uma aprovação de um administrador ou operador. As políticas de aprovação que protegem os passos dos fluxos podem elevá-lo a administrador, ou a duas pessoas diferentes com um administrador, por valor, classe de risco ou hora do dia. Fica fixado quando o pedido é feito.

Uma recusa, tal como uma aprovação, exige uma justificação escrita de pelo menos 5 caracteres. Cada passo fica auditado, e o agente só vê os seus pedidos e nunca as notas de outras pessoas.

As pessoas decidem na aplicação, em Gateway de ações, ou com um token de serviço de escrita: GET /api/gateway/actions?status=pending e depois POST /api/gateway/actions/{id}/approve ou /reject com uma nota.

Com os SDK

Em Python é um decorador, em TypeScript é withApproval.

from blue_falnoa import AgentClient

bf = AgentClient(url, "bfa_…")

@bf.requires_approval("payments.transfer", "Pay supplier invoice")
def pay(invoice, amount):
    ...  # runs only after people approve

pay(invoice="42", amount=40000)   # a refusal or expiry raises PermissionError

TypeScript

import { AgentClient } from "@blue-falnoa/sdk";

const bf = new AgentClient(url, "bfa_…");
await bf.withApproval(
  "payments.transfer",
  "Pay supplier invoice 42",
  { amount: 40000, currency: "EUR" },
  () => payInvoice("42"), // runs only after people approve
);

O que não faz

O gateway só controla os agentes que o chamam. Nada impede um agente de saltar a chamada. Os pedidos de agentes não aprovados no registo, incluindo depois de uma paragem de emergência, são recusados com 403.