First commit

This commit is contained in:
2026-10-30 22:04:44 -03:00
commit 645ecdfb07
2794 changed files with 282545 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
# Atualização do Template Backend — Analytics, Observer, NOC/GRL e OutputSupervisor
Esta versão do `agent_template_backend` foi atualizada para consumir as novidades transportadas para o `agent_framework`.
## 1. Analytics e Pub/Sub
O backend não chama mais diretamente apenas o publisher antigo de eventos. Agora ele cria um `AnalyticsPublisher`:
```python
from agent_framework.analytics.factory import create_analytics_publisher
from agent_framework.observability.observer import AgentObserver
analytics = create_analytics_publisher(settings)
observer = AgentObserver(analytics=analytics)
```
Com isso, o mesmo backend pode publicar em:
- OCI Streaming
- GCP Pub/Sub
- CompositePublisher, quando `ANALYTICS_PROVIDERS=oci_streaming,pubsub`
- Noop, quando analytics estiver desligado
## 2. Configuração mínima
```env
ENABLE_ANALYTICS=true
ANALYTICS_PROVIDERS=pubsub
GCP_PUBSUB_TOPIC_PATH=projects/<project-id>/topics/<topic-name>
GOOGLE_APPLICATION_CREDENTIALS=/secrets/gcp-service-account.json
```
Para publicar simultaneamente em OCI Streaming e GCP Pub/Sub:
```env
ENABLE_ANALYTICS=true
ANALYTICS_PROVIDERS=oci_streaming,pubsub
ENABLE_OCI_STREAMING=true
OCI_STREAM_ENDPOINT=<endpoint>
OCI_STREAM_OCID=<stream-ocid>
GCP_PUBSUB_TOPIC_PATH=projects/<project-id>/topics/<topic-name>
```
## 3. Observer corporativo
O workflow recebeu emissão automática dos principais eventos corporativos:
- `NOC.001`: início do workflow
- `NOC.005`: exceção fatal no workflow
- `NOC.006`: fim do workflow antes da resposta final
- `IC.AGENT_COMPLETED`: evento informacional de conclusão
- `GRL.001` a `GRL.009`: emitidos pelo `OutputSupervisor`
## 4. OutputSupervisor
Foi inserido um novo nó LangGraph:
```text
agent -> output_supervisor -> output_guardrails -> judge -> supervisor_review -> persist
```
O `OutputSupervisor` não substitui o supervisor de roteamento. Ele valida a saída candidata do agente usando o contrato corporativo:
- `allow`
- `sanitize`
- `retry`
- `block`
- `handover`
- `observe`
Para compatibilidade com os guardrails já existentes, o template inclui o adapter `LegacyOutputGuardrailRail`, que converte decisões antigas `allowed=True/False` para `RailAction`.
## 5. Campos adicionados ao AgentState
```python
supervisor_action: str
supervisor_guidance: str
supervisor_attempt: int
supervisor_handover_reason: str
output_supervisor_results: list[dict]
output_guardrails_already_applied: bool
```
## 6. Arquivos alterados
- `agent_template_backend/app/main.py`
- `agent_template_backend/app/workflows/agent_graph.py`
- `agent_template_backend/app/state.py`
- `agent_template_backend/.env`
- `agent_template_backend/requirements.txt`
- `agent_framework/src/agent_framework/config/settings.py`
## 7. Observação importante
O `OutputSupervisor` roda os guardrails de saída por meio do adapter legado e marca `output_guardrails_already_applied=True`. Assim o nó `output_guardrails` permanece no grafo para compatibilidade, mas evita reexecutar a mesma validação quando o supervisor já aplicou os rails.

View File

@@ -0,0 +1,45 @@
# Como usar IC, NOC e GRL no Template Backend
## IC — Item de Controle
Use IC para registrar eventos de negócio relevantes.
```python
await observer.emit_ic(
"IC.FATURA_CONSULTADA",
{"session_id": session_id, "invoice_id": invoice_id},
component="billing_agent",
)
```
## NOC — Evento operacional
Use NOC para saúde técnica, latência, erros e checkpoints operacionais.
```python
await observer.emit_noc(
"003",
{"session_id": session_id, "resourceName": "ADB", "latencyMs": 120},
component="repository",
)
```
## GRL — Evento de guardrail
Normalmente o framework emite GRL automaticamente. Use manualmente apenas para
rails customizados dentro do agente.
```python
await observer.emit_grl(
"OBSERVE",
{"session_id": session_id, "rail_code": "CUSTOM_POLICY"},
component="custom_rail",
)
```
## Onde já existe no template
- `app/workflows/agent_graph.py` emite IC/NOC no ciclo do workflow.
- `app/agents/runtime.py` emite IC para MCP/tools.
- `app/agents/*_agent.py` contém exemplos dentro do método `run()`.
- `app/examples/` contém exemplos isolados.

View File

@@ -0,0 +1,48 @@
# Backends atualizados para ConversationSummaryMemory
Esta versão dos backends foi compatibilizada com a versão do framework que adiciona `ConversationSummaryMemory`.
## O que mudou
- `app/main.py` agora inicializa `create_conversation_summary_memory(...)` junto com `create_memory(...)`.
- `AgentWorkflow` recebe `summary_memory` e repassa para os agentes.
- Os agentes não montam mais prompts manuais para o LLM; agora usam `build_messages()` do framework.
- Antes da chamada ao LLM, os agentes executam `await self.prepare_memory_context(state)`.
- Quando habilitado por `.env`, o prompt passa a receber:
- resumo acumulado da conversa;
- últimas mensagens completas;
- mensagem atual;
- BusinessContext;
- MCP results;
- RAG context e metadata.
## Configuração
```env
ENABLE_CONVERSATION_SUMMARY_MEMORY=true
MEMORY_CONTEXT_STRATEGY=summary
MEMORY_HISTORY_LIMIT=80
MEMORY_RECENT_MESSAGES_LIMIT=8
MEMORY_SUMMARY_TRIGGER_MESSAGES=20
MEMORY_MAX_SUMMARY_CHARS=6000
MEMORY_SUMMARY_USE_LLM=true
MEMORY_INJECT_RECENT_MESSAGES=true
MEMORY_INJECT_SUMMARY=true
```
## Backends alterados
- `backoffice_convertido_framework`
- `agent_template_backend`
- `agent_template_backend_day_zero`
## Observação importante
Estes backends esperam que o pacote `agent_framework` instalado/conectado seja a versão com os módulos:
- `agent_framework.memory.summary_memory`
- `agent_framework.memory.summary_store`
- `AgentRuntimeMixin.prepare_memory_context()`
- `AgentRuntimeMixin.build_messages()` com injeção de memória
Use junto com o ZIP `agent_framework_conversation_summary_memory.zip`.

View File

@@ -0,0 +1,14 @@
# Exemplos implementados no template
Este projeto entrega as capacidades transversais habilitadas como referência:
- route stickiness semântica com o perfil `route_continuity`;
- decisões `CONTINUE`, `ROUTE`, `HUMAN_HANDOFF` e `END_SESSION`;
- nós globais `human_handoff` e `end_session`;
- persistência de `active_agent`, `route_bypassed`, `continuity_signal` e controle de sessão;
- rejeição de novas mensagens depois de `session_ended=true`;
- políticas MCP `read_only` e `transactional` no backend;
- exemplo `solicitar_devolucao` com `require_confirmation: true`.
Para confirmar a transação, envie `confirmed: true` ou `confirmation: true` como booleano. Handoff e encerramento não chamam agentes de domínio nem MCP.

View File

@@ -0,0 +1,84 @@
# FRAMEWORK_CHANNEL_INPUT_MODE
This backend setting controls what kind of channel input the Agent Framework backend accepts.
It replaces the ambiguous use of `CHANNEL_GATEWAY_MODE` inside the backend.
## Values
```env
FRAMEWORK_CHANNEL_INPUT_MODE=embedded
```
The backend may use internal channel adapters to interpret simple/native channel payloads. This is useful for demos, labs, local frontend, curl tests, and simple environments.
```env
FRAMEWORK_CHANNEL_INPUT_MODE=external
```
The backend accepts only a normalized `GatewayRequest` produced by an external Channel Gateway. It does not parse native WhatsApp, Voice, Teams, or other channel payloads.
## Recommended enterprise setup
In the external channel gateway service:
```env
CHANNEL_GATEWAY_RUNTIME_MODE=adapter
```
In this backend:
```env
FRAMEWORK_CHANNEL_INPUT_MODE=external
```
Flow:
```text
External channel / browser / customer adapter
↓
channel_gateway:7000
CHANNEL_GATEWAY_RUNTIME_MODE=adapter
↓ GatewayRequest
agent_template_backend:8000
FRAMEWORK_CHANNEL_INPUT_MODE=external
↓
LangGraph / Agents / MCP / Guardrails
```
## Valid direct request to backend in external mode
```bash
curl -s -X POST "http://localhost:8000/gateway/message" \
-H "Content-Type: application/json" \
-d '{
"channel": "web",
"tenant_id": "default",
"agent_id": "telecom_contas",
"payload": {
"message": "Quero consultar minha fatura",
"session_id": "backend-external-ok-001"
}
}' | jq
```
## Invalid direct request to backend in external mode
```bash
curl -i -s -X POST "http://localhost:8000/gateway/message" \
-H "Content-Type: application/json" \
-d '{
"message": "Quero consultar minha fatura",
"session_id": "raw-payload-error-001"
}'
```
Expected result: HTTP 422.
## Legacy compatibility
`CHANNEL_GATEWAY_MODE` is still present as a legacy alias for older environments, but new deployments should use:
```env
FRAMEWORK_CHANNEL_INPUT_MODE=embedded|external
```

View File

@@ -0,0 +1,127 @@
# Guardrails paralelos fail-fast e Observer IC
## O que foi implementado
### 1. ParallelRailExecutor
Arquivo principal:
```text
agent_framework/src/agent_framework/guardrails/parallel_executor.py
```
Também foi criado um alias de compatibilidade:
```text
agent_framework/src/agent_framework/guardrails/executor.py
```
Esse alias evita erro quando algum código antigo importar:
```python
from agent_framework.guardrails.executor import ParallelRailExecutor
```
### 2. Execução paralela no GuardrailPipeline
Arquivo alterado:
```text
agent_framework/src/agent_framework/guardrails/pipeline.py
```
O pipeline continua retornando o contrato antigo:
```python
(texto_final, list[RailDecision])
```
mas internamente pode executar rails em paralelo com fail-fast.
### 3. Execução paralela no OutputSupervisor
Arquivo alterado:
```text
agent_framework/src/agent_framework/guardrails/output_supervisor.py
```
O `OutputSupervisor` agora usa `ParallelRailExecutor` quando habilitado.
### 4. Configuração
Novas configurações:
```env
ENABLE_PARALLEL_GUARDRAILS=true
GUARDRAILS_FAIL_FAST=true
```
Também foram adicionadas em:
```text
agent_framework/src/agent_framework/config/settings.py
.env
.env.example
agent_template_backend/.env
agent_template_backend_day_zero/.env
```
### 5. Observer IC
O `AgentObserver` já tinha `emit_ic()`.
Foi complementada a API global compatível com FIRST/TIM:
```python
from agent_framework.observer import ic, aic, noc, anoc, grl, agrl
```
Exemplos:
```python
ic("AGENT_COMPLETED", data={"session_id": "..."})
await aic("MCP_TOOL_CALLED", data={"tool_name": "consultar_fatura"})
```
### 6. ICs automáticos no template backend
O backend emite agora:
```text
IC.AGENT_STARTED
IC.ROUTE_SELECTED
IC.MCP_TOOL_CALLED
IC.TOOL_CALLED
IC.AGENT_COMPLETED
```
Além dos eventos já existentes:
```text
NOC.001
NOC.005
NOC.006
GRL.001 ... GRL.009
```
## Validações executadas
Foram executadas validações locais com `PYTHONPATH=agent_framework/src`:
```bash
python3 -m compileall -q agent_framework/src/agent_framework agent_template_backend/app agent_template_backend_day_zero/app
```
Smoke tests executados:
```text
1. Import de ParallelRailExecutor via agent_framework.guardrails
2. Import de ParallelRailExecutor via agent_framework.guardrails.executor
3. Execução fail-fast: FastBlock cancela SlowAllow
4. GuardrailPipeline paralelo retorna RailDecision legado
5. OutputSupervisor paralelo retorna RailAction.BLOCK
6. API global observer.ic/noc/grl/aic/anoc/agrl
```
Observação: o import completo do `agent_template_backend.app.workflows.agent_graph` depende de `langgraph`, que não está instalado no sandbox de validação. O arquivo foi validado por `compileall`, e a dependência já consta em `agent_template_backend/requirements.txt`.

View File

@@ -0,0 +1,42 @@
# Implementação IC/NOC/GRL preservando lógica existente
Esta versão mantém a lógica original dos agentes do `agent_template_backend` e adiciona observabilidade corporativa.
## IC adicionados nos agentes
Cada agente agora emite eventos de negócio sem alterar a resposta final:
- `IC.BILLING_AGENT_STARTED` / `IC.BILLING_AGENT_COMPLETED`
- `IC.ORDERS_AGENT_STARTED` / `IC.ORDERS_AGENT_COMPLETED`
- `IC.PRODUCT_AGENT_STARTED` / `IC.PRODUCT_AGENT_COMPLETED`
- `IC.SUPPORT_AGENT_STARTED` / `IC.SUPPORT_AGENT_COMPLETED`
- `IC.<AGENT>_MCP_CONTEXT_COLLECTED` quando houver dados MCP
- `IC.<AGENT>_RAG_CONTEXT_RETRIEVED` quando RAG estiver habilitado
O mixin `AgentRuntimeMixin` também emite:
- `IC.MCP_TOOL_CALLED` antes da chamada MCP
- `IC.TOOL_CALLED` após a chamada MCP
## NOC
O workflow já emite eventos operacionais principais:
- `NOC.001` no início da execução
- `NOC.005` em exceção fatal
- `NOC.006` na persistência/finalização
## GRL
O backend agora também exemplifica emissão GRL no workflow:
- `GRL.001` início do pipeline de guardrails
- `GRL.002` decisão allow
- `GRL.004` decisão block
- `GRL.009` decisão final agregada
Quando `OutputSupervisor` está habilitado, ele continua sendo o principal mecanismo corporativo de supervisão de saída.
## Garantia
A lógica original dos agentes não foi substituída por stubs. As chamadas LLM, MCP, RAG, cache e os retornos originais foram preservados.

View File

@@ -0,0 +1,5 @@
# Langfuse single trace observer fix
This backend now uses `TelemetryBackedAgentObserver` instead of publishing IC/NOC/GRL through `AgentObserver(analytics=...)`.
Why: when analytics includes the Langfuse provider, observer events such as `IC.AGENT_COMPLETED` and `NOC.006` may create a second root trace with little detail. Emitting those events through `Telemetry.event(...)` keeps them inside the active request/workflow trace.

View File

@@ -0,0 +1,452 @@
# MCP Multi-item — Guia do Desenvolvedor
## Objetivo
Use este guia quando uma única intenção do usuário precisa operar sobre **mais de um item do mesmo tipo** — por exemplo, cancelar vários VAS/produtos, devolver ou consultar vários pedidos, alterar vários ativos ou processar várias faturas/linhas/contratos.
O framework já possui suporte genérico para **resolução/canonicalização de múltiplos itens**, **confirmação transacional**, **execução MCP/workflow**, **preservação de evidência por item** e **normalização de `SUCCESS` / `PARTIAL_SUCCESS` / `FAILED`**. O desenvolvedor não deve criar um segundo motor de multi-item dentro do agente.
> **Regra central:** multi-item é uma característica da resolução, execução e resultado da operação. **Não é definido pelo tipo do parâmetro de entrada.** Uma tool pode receber `subject: string`, `id: string`, `items: array` ou outro contrato natural de domínio e ainda assim processar múltiplos itens.
## Regra principal
**Não faça loop de negócio no agente.** O agente seleciona a intenção/tool e usa o runtime. A expansão para múltiplos itens pode ocorrer no pre-validator, na própria tool MCP ou em um workflow de domínio.
Fluxo recomendado:
```text
Usuário cita N itens
-> Router/Agent seleciona a tool
-> Runtime coleta os parâmetros declarados pela tool
-> Entrada pode ser escalar ou coleção
-> (opcional) pre-validation resolve/expande/canonicaliza N itens
-> Runtime pede UMA confirmação coerente para o conjunto efetivo
-> MCP tool/workflow processa 1 ou N itens
-> Tool primária devolve results[] com success/ok por item
-> Framework normaliza SUCCESS / PARTIAL_SUCCESS / FAILED
-> Composição final relata sucessos e falhas individualmente
```
## 1. Declare o contrato natural da operação em `tools.yaml`
O framework **não exige `array/list`** para que uma operação seja multi-item.
Use o contrato que faz sentido para a tool e para o domínio:
- **parâmetro escalar** (`subject`, `id`, `query`, etc.) quando a operação recebe uma expressão que pode representar uma ou várias entidades;
- **`array/list`** quando a interface MCP é naturalmente batch e recebe explicitamente uma coleção.
### Padrão A — parâmetro escalar que pode representar vários itens
Este é o padrão usado pelo agente de Contas para cancelamento de VAS.
```yaml
tools:
cancelar_vas_avulso:
description: Cancela um ou mais serviços VAS.
mcp_server: contas
enabled: true
tool_type: action
args_schema:
subject:
type: string
label: o serviço ou os serviços
description: Serviço ou expressão com um ou mais serviços a cancelar.
```
Entrada possível:
```text
subject = "TIM Fashion, Aya Audiobooks, Neymar Jr"
```
O `subject` continua sendo uma `string`. O suporte multi-item aparece posteriormente quando o validator/tool resolve essa expressão em itens independentes.
### Padrão B — coleção explícita
Também é válido quando a API/tool é naturalmente batch:
```yaml
tools:
cancelar_produtos:
description: Cancela um ou mais produtos do cliente.
mcp_server: contas
enabled: true
tool_type: action
args_schema:
items:
type: array
label: os produtos
description: Lista de produtos que o cliente deseja cancelar.
```
Os dois padrões são suportados. **Não altere uma interface escalar existente para array apenas para “habilitar multi-item”.**
## 2. `tool_policies.yaml` não possui sintaxe especial de multi-item
`tool_policies.yaml` continua definindo tipo de operação, confirmação, parâmetros obrigatórios e pre-validation. Não é necessário criar `multi_item: true`, trocar `subject` por `items` ou introduzir outra configuração.
Exemplo realista do agente de Contas:
```yaml
version: 1
defaults:
operation_type: read_only
require_confirmation: false
tool_policies:
cancelar_vas_avulso:
operation_type: transactional
require_confirmation: true
requires:
- subject
pre_validation:
enabled: true
tool: validar_vas_subject
fail_open: false
```
`requires: [subject]` significa apenas que a operação precisa saber **o que** será processado. Esse `subject` pode representar um item ou vários.
## 3. Pre-validation pode transformar um parâmetro escalar em múltiplos itens
Quando necessário, o pre-validator resolve nomes, canonicaliza entidades e pode materializar uma lista estrutural em `transaction_decision.resolved_arguments`.
Exemplo:
```json
{
"eligible": true,
"subject": "TIM Fashion, Aya Audiobooks, Neymar Jr",
"resolved_subject": "TIM Fashion Mensal, Aya Audiobooks Premium, Neymar Jr",
"resolved_subjects": [
"TIM Fashion Mensal",
"Aya Audiobooks Premium",
"Neymar Jr"
],
"transaction_decision": {
"resolved_arguments": {
"subject": "TIM Fashion Mensal, Aya Audiobooks Premium, Neymar Jr",
"items": [
{"name": "TIM Fashion Mensal"},
{"name": "Aya Audiobooks Premium"},
{"name": "Neymar Jr"}
]
},
"target_tool": "cancelar_vas_avulso",
"confirmation_message": "Você confirma o cancelamento de TIM Fashion Mensal, Aya Audiobooks Premium e Neymar Jr?"
}
}
```
`resolved_arguments.items[]` é uma representação canônica útil para a execução, mas **não obriga** `tools.yaml` a declarar `items` como parâmetro de entrada.
### Validação parcial e `fail_open: false`
`eligible` é global. Com `fail_open: false`, retornar `eligible: false` encerra a transação inteira.
Portanto, quando alguns itens são válidos e outros não:
1. mantenha `eligible: true` se existe pelo menos um item acionável;
2. preserve o estado individual dos itens resolvidos/rejeitados;
3. deixe a tool primária produzir o resultado terminal por item em `results[]`.
Exemplo conceitual:
```json
{
"eligible": true,
"status": "PARTIALLY_ELIGIBLE",
"transaction_decision": {
"resolved_arguments": {
"items": [
{"name": "TIM Fashion Mensal", "eligible": true},
{"name": "Aya Audiobooks Premium", "eligible": false, "reason": "item_nao_encontrado"},
{"name": "Neymar Jr", "eligible": true}
]
}
}
}
```
Se nenhum item puder ser processado, `eligible: false` é apropriado.
## 4. Contrato de entrada do MCP: uma operação lógica, não necessariamente uma coleção explícita
Prefira **uma única operação lógica MCP para o agente**. Ela pode ser implementada de três formas:
1. receber um parâmetro escalar e expandi-lo no validator/workflow;
2. receber uma coleção explícita (`array/list`);
3. receber uma expressão/identificador e descobrir os itens dentro da própria tool/workflow.
O agente não deve fazer fan-out chamando a mesma tool repetidamente por conta própria.
### Exemplo — escalar expandido
```json
{
"tool_name": "cancelar_vas_avulso",
"arguments": {
"subject": "TIM Fashion Mensal, Aya Audiobooks Premium, Neymar Jr"
}
}
```
### Exemplo — batch explícito
```json
{
"tool_name": "cancelar_produtos",
"arguments": {
"items": [
{"name": "A", "id": "1001"},
{"name": "B", "id": "1002"}
]
}
}
```
Se o backend só possui API unitária, o fan-out deve ficar encapsulado no **MCP Server ou workflow de domínio**, preservando uma única operação lógica para o agente.
## 5. Contrato obrigatório de resultado por item
Para o framework reconhecer automaticamente o resultado como multi-item, a **tool primária solicitada** deve expor uma lista `results` com **dois ou mais itens**, e cada item deve possuir `success` ou `ok` booleano.
```json
{
"results": [
{"subject": "TIM Fashion Mensal", "success": true},
{"subject": "Aya Audiobooks Premium", "success": false, "reason": "not_found"},
{"subject": "Neymar Jr", "success": true}
]
}
```
Campos como `id`, `subject`, `name`, `reason`, `error`, `protocol` e outros são de domínio e opcionais. O sinal estrutural do normalizador é `success: true|false` ou `ok: true|false` por item.
### Workflow-backed tool
Se a tool é executada por workflow, o caminho preferencial e autoritativo é:
```text
workflow.output[tool_name].results
```
Uma falha auxiliar posterior não deve apagar itens já concluídos pela tool primária.
## 6. O que o framework produz automaticamente
Com `results[]` válido, o runtime classifica o agregado como:
| Situação | `multi_item_status` |
|---|---|
| todos os itens concluíram | `SUCCESS` |
| parte concluiu e parte falhou | `PARTIAL_SUCCESS` |
| todos falharam | `FAILED` |
Exemplo:
```json
{
"multi_item_status": "PARTIAL_SUCCESS",
"partial_success": true,
"metadata": {
"multi_item": {
"status": "PARTIAL_SUCCESS",
"items_count": 3,
"items_succeeded_count": 2,
"items_failed_count": 1,
"primary_tool": "cancelar_vas_avulso"
}
}
}
```
Se um wrapper/etapa posterior retornar erro depois de existirem resultados terminais válidos, o framework preserva os sucessos individuais e pode registrar o erro como secundário, em vez de converter tudo para falha total.
## 7. O que NÃO fazer
Não crie motor multi-item dentro do agente:
```python
# NÃO
for product in products:
await tool_router.call("cancelar_produto", {"product": product})
```
Não reduza resultado misto a um único booleano global sem evidência por item:
```json
{
"approved": false,
"error": "um item falhou"
}
```
Também não altere uma interface existente apenas para trocar:
```text
subject: string
```
por:
```text
items: array
```
quando o validator/workflow já consegue expandir corretamente o `subject`.
## 8. Exemplo completo — padrão escalar do Contas
### `tools.yaml`
```yaml
tools:
cancelar_vas_avulso:
description: Cancela um ou mais VAS.
mcp_server: contas
enabled: true
tool_type: action
args_schema:
subject:
type: string
```
### `tool_policies.yaml`
```yaml
tool_policies:
cancelar_vas_avulso:
operation_type: transactional
require_confirmation: true
requires:
- subject
pre_validation:
enabled: true
tool: validar_vas_subject
fail_open: false
```
### Validator
```json
{
"eligible": true,
"transaction_decision": {
"resolved_arguments": {
"subject": "TIM Fashion Mensal, Aya Audiobooks Premium, Neymar Jr",
"items": [
{"name": "TIM Fashion Mensal"},
{"name": "Aya Audiobooks Premium"},
{"name": "Neymar Jr"}
]
}
}
}
```
### Resultado MCP/workflow
```json
{
"results": [
{"subject": "TIM Fashion Mensal", "success": true},
{"subject": "Aya Audiobooks Premium", "success": false, "reason": "not_found"},
{"subject": "Neymar Jr", "success": true}
]
}
```
Resultado agregado: `PARTIAL_SUCCESS`.
## 9. Exemplo alternativo — API naturalmente batch
Quando o MCP já define coleção como contrato de entrada, `array/list` continua válido:
```yaml
args_schema:
order_ids:
type: array
```
```json
{
"results": [
{"order_id": "P-100", "success": true},
{"order_id": "P-101", "success": false, "reason": "already_shipped"},
{"order_id": "P-102", "success": true}
]
}
```
O ponto importante é: **array é uma opção de contrato, não o gatilho do mecanismo multi-item.**
## 10. Read-only, conversational e transactional podem ser multi-item
Multi-item é independente do `operation_type`.
É possível ter:
```text
read_only + multi-item
conversational + multi-item
transactional + multi-item
internal + multi-item
```
O que muda é a política de confirmação e execução, não a capacidade de representar vários itens.
## 11. Idempotência e protocolos
Em operações com efeito colateral:
- use chave de idempotência de requisição e, quando necessário, por item;
- devolva protocolo/operation id no próprio item;
- preserve itens já concluídos em retry;
- não dependa apenas de mensagem textual agregada.
A política específica de idempotência do sistema de destino continua pertencendo ao MCP/workflow de domínio.
## 12. Checklist do desenvolvedor
- [ ] O agente seleciona a operação e **não** implementa fan-out/loop MCP de negócio.
- [ ] `tools.yaml` declara o contrato natural da operação, que pode ser escalar ou coleção.
- [ ] Nenhuma chave especial `multi_item: true` foi criada ou é necessária.
- [ ] `tool_policies.yaml` usa os `requires` reais do domínio; não é necessário trocar `subject` por `items`.
- [ ] Se um escalar representar múltiplas entidades, validator/tool/workflow expande e canonicaliza os itens.
- [ ] A confirmação representa o conjunto efetivo resolvido.
- [ ] Com `fail_open: false`, um item inválido não força `eligible: false` global quando outros ainda são acionáveis.
- [ ] A tool primária retorna `results[]` com `success` ou `ok` por item quando há múltiplos resultados.
- [ ] Workflow usa `output[tool_name].results` como evidência terminal preferencial da tool primária.
- [ ] Resultado parcial não é reduzido a um único `approved=false` ou `success=false` global.
- [ ] Testes cobrem todos-sucesso, parcial, todos-falha e falha auxiliar posterior.
- [ ] A apresentação final menciona sucessos e falhas individualmente quando houver `PARTIAL_SUCCESS`.
## 13. Onde o comportamento existe no framework
```text
libs/agent_framework/src/agent_framework/runtime/transaction_parameters.py
- suporte existente a coerção de array/list quando esse for o contrato declarado
libs/agent_framework/src/agent_framework/runtime/agent_runtime.py
- pre-validation e resolved_arguments
- _primary_multi_item_outcomes()
- _normalize_multi_item_tool_result()
- instrução de composição multi-item para o LLM
tests/test_multi_item_result_normalization.py
- regressões de SUCCESS/PARTIAL_SUCCESS e proteção contra falha auxiliar
```
## 14. Resumo de responsabilidade
| Camada | Responsabilidade |
|---|---|
| Agente | selecionar intenção/tool e usar o runtime; não implementar motor multi-item |
| `tools.yaml` | declarar o contrato natural da operação; pode ser escalar ou coleção |
| `tool_policies.yaml` | confirmação, `requires` e pre-validation; sem sintaxe especial de multi-item |
| Pre-validator MCP | identificar, resolver, canonicalizar e, quando necessário, expandir 1 parâmetro em N itens |
| Tool MCP/workflow | executar 1 ou N itens e produzir resultado por item |
| Framework runtime | manter estado/confirmação, interpretar `results[]`, preservar evidência e calcular `SUCCESS` / `PARTIAL_SUCCESS` / `FAILED` |
| LLM/presentation | transformar evidências em resposta sem apagar sucesso/falha individual |

View File

@@ -0,0 +1,82 @@
# Teste e diagnóstico de Long-Term Memory
## O que foi corrigido
1. A LTM agora é carregada explicitamente antes do roteamento.
2. O estado recebe uma chave estável em `long_term_memory_subject_key`, baseada em `business_context.customer_key` e, como fallback, `user_id`.
3. O resultado de carga e persistência aparece em `metadata.long_term_memory` da resposta.
4. `/health` informa a configuração efetiva de LTM carregada pelo processo.
5. Falhas de leitura e gravação geram eventos `long_term_memory.load.failed` e `long_term_memory.persist.failed`.
## Teste
Primeira sessão:
```bash
curl -s http://localhost:8000/gateway/message \
-H 'Content-Type: application/json' \
-d '{
"channel":"web",
"payload":{
"text":"Meu nome preferido é Cris e minha linguagem preferida é Python.",
"session_id":"ltm-session-001",
"user_id":"ltm-user-001",
"customer_id":"ltm-customer-001"
}
}'
```
Verifique na resposta:
```json
"long_term_memory": {
"subject_key": "ltm-customer-001",
"write_result": {
"saved": 2
}
}
```
Nova sessão, mesma identidade:
```bash
curl -s http://localhost:8000/gateway/message \
-H 'Content-Type: application/json' \
-d '{
"channel":"web",
"payload":{
"text":"Qual é meu nome preferido e qual linguagem eu prefiro?",
"session_id":"ltm-session-002",
"user_id":"ltm-user-001",
"customer_id":"ltm-customer-001"
}
}'
```
Na segunda resposta, confira:
- `metadata.long_term_memory.subject_key` igual à primeira chamada;
- `metadata.long_term_memory.loaded` com registros;
- `metadata.long_term_memory.context` preenchido;
- ausência de `load_error`.
## Diagnóstico rápido
```bash
curl -s http://localhost:8000/health
```
A seção `long_term_memory` deve mostrar:
```json
{
"enabled": true,
"provider": "sqlite",
"sqlite_path": "./data/agent_framework.db",
"table": "agentfw_long_term_memory",
"auto_extract": true,
"inject_context": true
}
```
Execute o backend com o diretório do projeto como diretório de trabalho. Como o caminho SQLite é relativo, iniciar a aplicação em outro diretório pode criar ou consultar outro arquivo `./data/agent_framework.db`.

View File

@@ -0,0 +1,11 @@
# Confirmação Transacional Semântica
Este template suporta confirmação transacional em duas camadas: primeiro um parser determinístico para `sim`/`não` e equivalentes explícitos; somente quando ele não consegue decidir, o framework usa um classificador semântico configurado em `config/routing.yaml`.
A configuração `router.transaction_confirmation.semantic_fallback` usa três classes: `SIM`, `NAO` e `CONTINUAR`. O prompt pode usar `{{ pending_prompt }}`, `{{ relevant_conversation_context }}`, `{{ user_input }}` e `{{ allowed_values }}`. O histórico injetado é apenas contexto de interpretação; não substitui validação de negócio ou evidência MCP.
Exemplo: após `Você confirma o cancelamento do serviço adicional selecionado?`, a frase `isso mesmo, pode confirmar` pode ser classificada como `SIM`. Já `mas qual é o valor?` deve ser `CONTINUAR`, portanto não executa a ação por confirmação.
Entradas explícitas já suportadas continuam no caminho determinístico e não geram custo adicional de LLM. Em observabilidade, o fallback usa `transaction.confirmation.semantic_classifier` e o `route_decision.metadata` informa `transaction_confirmation_source: semantic`.
Consulte `docs/developer/pt/03_transaction_workflows_and_state.md` do framework para o contrato completo e exemplos.

View File

@@ -0,0 +1,62 @@
# Validação da versão com IC/NOC/GRL
Validações executadas nesta geração:
1. `python -m compileall -q agent_template_backend/app`
- Resultado: OK.
2. Smoke test dos agentes com LLM fake e Observer fake:
- `BillingAgent`: preservou resposta gerada pelo LLM e emitiu IC de início/fim.
- `OrdersAgent`: preservou resposta gerada pelo LLM e emitiu IC de início/fim.
- `ProductAgent`: preservou resposta gerada pelo LLM e emitiu IC de início/fim.
- `SupportAgent`: preservou resposta gerada pelo LLM e emitiu IC de início/fim.
3. Verificação de regressão:
- Nenhum agente retorna `Template Enterprise ativo`.
- A lógica LLM/MCP/RAG/cache existente foi preservada.
## Eventos adicionados
### IC
Nos agentes:
- `IC.BILLING_AGENT_STARTED`
- `IC.BILLING_MCP_CONTEXT_COLLECTED`
- `IC.BILLING_RAG_CONTEXT_RETRIEVED`
- `IC.BILLING_AGENT_COMPLETED`
- `IC.ORDERS_AGENT_STARTED`
- `IC.ORDERS_MCP_CONTEXT_COLLECTED`
- `IC.ORDERS_RAG_CONTEXT_RETRIEVED`
- `IC.ORDERS_AGENT_COMPLETED`
- `IC.PRODUCT_AGENT_STARTED`
- `IC.PRODUCT_MCP_CONTEXT_COLLECTED`
- `IC.PRODUCT_RAG_CONTEXT_RETRIEVED`
- `IC.PRODUCT_AGENT_COMPLETED`
- `IC.SUPPORT_AGENT_STARTED`
- `IC.SUPPORT_MCP_CONTEXT_COLLECTED`
- `IC.SUPPORT_RAG_CONTEXT_RETRIEVED`
- `IC.SUPPORT_AGENT_COMPLETED`
No runtime MCP:
- `IC.MCP_TOOL_CALLED`
- `IC.TOOL_CALLED`
### NOC
Já integrados no workflow:
- `NOC.001` início da execução
- `NOC.005` erro fatal
- `NOC.006` finalização/persistência
### GRL
No workflow de guardrails:
- `GRL.001` início da avaliação
- `GRL.002` allow
- `GRL.004` block
- `GRL.009` decisão final

View File

@@ -0,0 +1,3 @@
compileall app: OK
Arquivos de exemplos IC/NOC/GRL adicionados.
Agentes preservam implementação original comentada.