Files
agent_platform_oci/docs/A2A_IMPLEMENTACAO.md
2026-10-21 08:23:55 -03:00

6.3 KiB

Integração A2A no Agent Framework OCI

Decisão de arquitetura

O Agent Gateway existente passa a ter uma fachada A2A opcional. Não é necessário manter um segundo roteador, duplicar o supervisor ou migrar os agentes atuais.

Consumidor atual ── /gateway/message ─┐
                                    ├─ Agent Gateway / supervisor ─┬─ backend native
Consumidor A2A ──── /a2a ─────────────┘                             └─ backend a2a

O backend nativo continua recebendo {channel, payload, agent_id, tenant_id}. A ausência de protocol no catálogo mantém native. A2A fica desativado por padrão; o SDK só é importado ao habilitar a fachada ou selecionar um backend A2A. Não foi alterado o runtime dos agentes, os workflows, os canais ou os MCPs.

A entrada usa A2A 1.0 / JSON-RPC, SDK oficial a2a-sdk==1.2.2, com adaptação 0.3 disponibilizada pelo próprio SDK. Agentes externos podem ser registrados com a2a_version: '1.0' ou '0.3'; não há detecção heurística de versão.

Ativação local

Na raiz do framework:

python -m pip install -e 'libs/agent_framework[a2a]' -r apps/agent_gateway/requirements.txt
export ENABLE_A2A=true
export A2A_PUBLIC_URL=https://meu-gateway.example
export BACKENDS_CONFIG_PATH="$PWD/apps/agent_gateway/config/backends.a2a.example.yaml"
python -m uvicorn app.main:app --app-dir apps/agent_gateway --port 8010

Edite primeiro as URLs do catálogo de exemplo. Para agentes externos, informe o endpoint JSON-RPC anunciado no Agent Card como url + a2a_rpc_path. Credenciais ficam em variáveis de ambiente referenciadas por a2a_headers_env. Os valores não são publicados em /backends.

A imagem opcional pode ser construída a partir da raiz:

docker build -f apps/agent_gateway/Dockerfile.a2a -t agent-gateway-a2a .

Defina A2A_PUBLIC_URL no ambiente do container e monte o catálogo de backends. A imagem e os comandos anteriores de implantação continuam disponíveis.

Descoberta e chamada

O Agent Card fica em GET /.well-known/agent-card.json; as skills são derivadas dos backends habilitados. As mensagens chegam em POST /a2a.

Exemplo A2A 1.0, com cabeçalho A2A-Version: 1.0:

{
  "jsonrpc": "2.0",
  "id": "request-1",
  "method": "SendMessage",
  "params": {
    "message": {
      "messageId": "message-1",
      "contextId": "conversation-123",
      "role": "ROLE_USER",
      "parts": [
        {"text": "Quero consultar minha fatura"},
        {"data": {"customer_id": "123"}}
      ],
      "metadata": {"tenant_id": "default"}
    }
  }
}

No modo de tarefas (padrão), a resposta fica em result.task. O resultado de negócio está em artifacts[].parts, com texto e uma parte data contendo a resposta do framework. Com A2A_TASK_MODE=false, permanece em result.message. Reutilize contextId nos próximos turnos. No modo 0.3, use o cabeçalho A2A-Version: 0.3, método message/send, role user e os campos kind da especificação 0.3; o resultado é uma Task diretamente (ou Message com A2A_TASK_MODE=false).

Partes data devem conter objetos e são incorporadas ao payload de negócio. A identidade da sessão e o texto do protocolo prevalecem sobre esses dados. Arquivos recebidos pela fachada são rejeitados explicitamente.

Conversas, tarefas e limites

  • A fachada cria Tasks A2A e permite envio imediato, consulta, cancelamento e streaming SSE. A2A_TASK_MODE=false mantém o modo anterior de Messages. Consulte A2A assíncrono para os exemplos completos.
  • O adaptador de saída aceita Message ou Task; consulta GetTask/tasks/get enquanto o agente está trabalhando, dentro de um prazo total configurável por BACKEND_TIMEOUT_SECONDS. Não repete automaticamente operações de envio.
  • Tarefas que pedem input/autenticação preservam estado e identidade para o próximo turno. Tarefas concluídas não são reutilizadas.
  • A continuidade remota é guardada no processo, por tenant/backend/sessão, com validade de uma hora e limite de 10 mil entradas. Em múltiplas réplicas, use afinidade de sessão ou implemente armazenamento compartilhado antes de depender dessa continuidade. Reiniciar o processo limpa esse cache.
  • metadata.a2a_result preserva o resultado remoto, incluindo dados/artefatos; a2a_context_id, a2a_task_id e a2a_state permitem inspeção e continuidade explícita no payload quando necessário.
  • Streaming SSE está disponível no modo de tarefas. Push notifications e gRPC não são oferecidos. O proxy de eventos nativo não é utilizado para agentes A2A: use SendStreamingMessage/SubscribeToTask e seus equivalentes 0.3.
  • O template templates/agent_template_backend também expõe A2A diretamente quando ENABLE_A2A=true, sem passar pelo gateway global.

Autenticação

As rotas A2A compartilham o middleware de autenticação já instalado no gateway (AGENT_GATEWAY_AUTH_*). Habilitar A2A não habilita autenticação automaticamente. O tenant em metadata mantém a semântica atual do framework: é dado do pedido, não uma autorização concedida pelo protocolo. Políticas de acesso a tenants continuam sendo responsabilidade da configuração de autenticação/autorização.

Quando houver autenticação, declare-a também no Agent Card, por exemplo:

export A2A_SECURITY_SCHEMES='{"gatewayBearer":{"httpAuthSecurityScheme":{"scheme":"bearer"}}}'
export A2A_SECURITY='[{"gatewayBearer":[]}]'

Essas declarações documentam o mecanismo; quem verifica as credenciais é o middleware. Se desejar descoberta pública, adicione somente o caminho do Agent Card à configuração de caminhos públicos; /a2a permanece protegido.

Validação

Testes em tests/test_a2a_interoperability.py cobrem os dois formatos de entrada, o contrato nativo, os dois formatos de saída, polling, erros JSON-RPC, continuidade de tarefas, separação entre tenants e limite de tempo.

PYTHONPATH=libs/agent_framework/src pytest tests/test_a2a_interoperability.py -q

Validação com transportes HTTP simulados e aplicação FastAPI local; não substitui um teste de integração com os serviços OCI e agentes externos da implantação.

Referências oficiais: