Projeto do Agent Contas ORACLE

This commit is contained in:
2026-08-19 09:35:50 -03:00
commit 950a2bcd33
1366 changed files with 177217 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
# Sample guideline, please follow similar structure for guideline with code samples
# 1. Suggest using streams instead of simple loops for better readability.
# <example>
# *Comment:
# Category: Minor
# Issue: Use streams instead of a loop for better readability.
# Code Block:
#
# ```java
# // Calculate squares of numbers
# List<Integer> squares = new ArrayList<>();
# for (int number : numbers) {
# squares.add(number * number);
# }
# ```
# Recommendation:
#
# ```java
# // Calculate squares of numbers
# List<Integer> squares = Arrays.stream(numbers)
# .map(n -> n * n) // Map each number to its square
# .toList();
# ```
# </example>

View File

@@ -0,0 +1,37 @@
# Correção: deadlock/espera cross-loop na geração de sequence
## Problema
A API síncrona `agent_framework.observer.event()` podia ser chamada em uma worker thread sem event loop ativo. Nesse caso, a implementação anterior executava `asyncio.run(aevent(...))`, criando um novo event loop temporário. Ao mesmo tempo, `analytics/tim_sequence.py` compartilhava instâncias globais de `asyncio.Lock` (`_mongo_index_lock` e `_memory_lock`) entre chamadas que podiam vir de event loops diferentes.
Na primeira operação Mongo, `_ensure_mongo_ttl_index_once()` mantinha `_mongo_index_lock` durante a criação do índice TTL. A contenção por outro loop podia deixar a segunda chamada aguardando indefinidamente.
## Alterações aplicadas
1. `observer.py`
- removido `asyncio.run()` do caminho síncrono de `event()`;
- adicionado um event loop dedicado e reutilizável para chamadas síncronas;
- submissão cross-thread feita com `asyncio.run_coroutine_threadsafe()`;
- encerramento best-effort do loop no shutdown do processo.
2. `analytics/tim_sequence.py`
- `_mongo_index_lock`: `asyncio.Lock` -> `threading.Lock`;
- `_memory_lock`: `asyncio.Lock` -> `threading.Lock`;
- inicialização do índice TTL movida para uma função síncrona protegida por lock de thread e chamada via `asyncio.to_thread()`;
- o contador de fallback em memória usa uma seção crítica curta e thread-safe.
3. Testes
- `tests/test_observer_cross_loop_deadlock_fix.py` valida:
- múltiplas worker threads usando `event()` compartilham o mesmo loop síncrono do observer;
- sequence em memória permanece monotônica entre event loops independentes;
- criação do índice TTL ocorre apenas uma vez sob contenção cross-loop.
## Validação executada
```bash
PYTHONPATH=libs/agent_framework/src pytest -q tests/test_observer_cross_loop_deadlock_fix.py
```
Resultado: `3 passed`.
A suíte completa do repositório possui falhas preexistentes/independentes desta alteração, incluindo conflitos de coleta de arquivos `test_long_term_memory.py`, caminhos estáticos de template e testes de checkpoint/workflow. Esses itens não foram alterados por esta correção.

View File

@@ -0,0 +1,133 @@
# Inventário — Agent Gateway + MCP Gateway Overlay
Este inventário lista os arquivos incluídos no overlay `agent_platform_agent_gateway_mcp_gateway_overlay.zip`, indicando a área, o tipo de alteração e a finalidade de cada arquivo.
## Resumo
| Área | Quantidade |
|---|---:|
| Documentação | 1 |
| Agent Gateway | 10 |
| MCP Gateway | 5 |
| Agent Framework | 4 |
| Template Backend | 2 |
| MCP Server Mock | 2 |
| Deploy | 2 |
## Arquivos por área
### Documentação
| Arquivo | Tipo | Finalidade |
|---|---|---|
| `README_AGENT_GATEWAY_AND_MCP_GATEWAY_EVOLUTION.md` | Novo / overlay | Documento principal do overlay. Explica a nova arquitetura sem AI Gateway separado, com Agent Gateway governando políticas/modelos e MCP Gateway separado para tools. |
### Agent Gateway
| Arquivo | Tipo | Finalidade |
|---|---|---|
| `apps/agent_gateway/app/config/governance_loader.py` | Novo / overlay | Carrega o arquivo YAML de governança do Agent Gateway a partir de AGENT_GATEWAY_GOVERNANCE_CONFIG. |
| `apps/agent_gateway/app/governance/__init__.py` | Novo / overlay | Inicializa o pacote Python de governança do Agent Gateway. |
| `apps/agent_gateway/app/governance/audit.py` | Novo / overlay | Centraliza logging/auditoria das decisões de governança do Agent Gateway, com proteção simples para não logar mensagem completa. |
| `apps/agent_gateway/app/governance/evaluation_hooks.py` | Novo / overlay | Hooks antes e depois da chamada ao backend/runtime. Serve para amostragem, evaluator, scoring ou integração futura com Langfuse. |
| `apps/agent_gateway/app/governance/model_policies.py` | Novo / overlay | Resolve políticas de modelo/profile no Agent Gateway. Define qual provider/model/profile deve ser usado por operação, tenant e agente. |
| `apps/agent_gateway/app/governance/rate_limit.py` | Novo / overlay | Implementa rate limit em memória por tenant, agente e canal antes de encaminhar a requisição ao backend/runtime. |
| `apps/agent_gateway/app/governance/usage.py` | Novo / overlay | Hook para registrar uso de gateway, políticas aplicadas e respostas do backend. Pronto para plugar métricas, banco, Langfuse ou OTEL. |
| `apps/agent_gateway/app/governance_middleware.py` | Novo / overlay | Componente principal de governança do Agent Gateway. Aplica rate limit, resolve model_policy, gera headers/metadados e executa hooks antes/depois do backend. |
| `apps/agent_gateway/app/routes/governed_proxy_example.py` | Novo / overlay | Exemplo de rota governada para demonstrar como aplicar governança antes de encaminhar para o Agent Backend/Runtime. |
| `apps/agent_gateway/config/gateway_governance.yaml` | Novo / overlay | Configuração de governança do Agent Gateway: profiles, operation_profiles, providers permitidos, rate limits, headers propagados e evaluation hooks. |
### MCP Gateway
| Arquivo | Tipo | Finalidade |
|---|---|---|
| `apps/mcp_gateway/Dockerfile` | Novo / overlay | Imagem Docker do MCP Gateway. |
| `apps/mcp_gateway/app/__init__.py` | Novo / overlay | Inicializa o pacote Python da aplicação MCP Gateway. |
| `apps/mcp_gateway/app/main.py` | Novo / overlay | Aplicação FastAPI do MCP Gateway. Expõe health, ready, catálogo de tools e endpoint de invoke com auth, autorização, mapping, cache, timeout e retry. |
| `apps/mcp_gateway/config/mcp_gateway.yaml` | Novo / overlay | Configuração central do MCP Gateway: MCP servers, tools, versões, cache, timeout, retry, autorização por agente/canal e mapping BusinessContext → parâmetros. |
| `apps/mcp_gateway/requirements.txt` | Novo / overlay | Dependências Python do MCP Gateway. |
### Agent Framework
| Arquivo | Tipo | Finalidade |
|---|---|---|
| `libs/agent_framework/src/agent_framework/gateway_policy_context.py` | Novo / overlay | Helper no framework para o Runtime ler a política de modelo enviada pelo Agent Gateway em state['metadata']['model_policy']. |
| `libs/agent_framework/src/agent_framework/gateways/__init__.py` | Novo / overlay | Inicializa o pacote de clients de gateways no framework, exportando MCPGatewayClient. |
| `libs/agent_framework/src/agent_framework/gateways/mcp_gateway_client.py` | Novo / overlay | Client assíncrono do framework para chamar o MCP Gateway: listar tools e executar tools. |
| `libs/agent_framework/src/agent_framework/runtime_mcp_gateway_adapter.py` | Novo / overlay | Mixin opcional para agentes/runtime chamarem tools via MCP Gateway e anexarem resultados em state['mcp_results']. |
### Template Backend
| Arquivo | Tipo | Finalidade |
|---|---|---|
| `templates/agent_template_backend/app/mcp_gateway_client_factory.py` | Novo / overlay | Factory no template backend para construir MCPGatewayClient a partir de variáveis de ambiente. |
### MCP Server Mock
| Arquivo | Tipo | Finalidade |
|---|---|---|
| `mcp/servers/mock_telecom_mcp/app.py` | Novo / overlay | Mock MCP Server com tools consultar_fatura e consultar_pagamentos para validar o MCP Gateway localmente. |
| `mcp/servers/mock_telecom_mcp/requirements.txt` | Novo / overlay | Dependências do mock MCP Server de telecom usado para testes locais. |
### Deploy
| Arquivo | Tipo | Finalidade |
|---|---|---|
| `deploy/docker/docker-compose.mcp-gateway.yml` | Novo / overlay | Docker Compose para subir MCP Gateway e mock_telecom_mcp localmente. |
| `deploy/k8s/mcp-gateway.yaml` | Novo / overlay | Manifest Kubernetes de Deployment e Service do MCP Gateway. |
## Observações de integração
### Agent Gateway
Os arquivos em `apps/agent_gateway` não criam um novo serviço. Eles evoluem o Agent Gateway existente para atuar como gateway dedicado da plataforma, centralizando:
- políticas de modelo/profile;
- rate limit;
- auditoria;
- hooks de avaliação;
- propagação de metadados de governança para o Runtime.
A rota `governed_proxy_example.py` é um exemplo de integração. O handler real do `POST /gateway/message` deve aplicar:
```python
governed_body, headers = governance.prepare_backend_request(body)
```
antes de chamar o backend/runtime, e:
```python
return governance.process_backend_response(data)
```
após receber a resposta.
### MCP Gateway
O MCP Gateway é um serviço separado. Ele centraliza:
- catálogo de tools;
- autorização por agente/canal;
- versionamento de tools;
- mapping de BusinessContext para parâmetros;
- cache;
- timeout;
- retry;
- auditoria simples.
### Runtime / Backend
O Runtime continua responsável por:
- LangGraph;
- estado;
- memória;
- checkpoints;
- fluxo;
- providers LLM existentes.
O Runtime passa a chamar tools via MCP Gateway usando `MCPGatewayClient` e/ou `MCPGatewayRuntimeMixin`.
### AI Gateway
Este overlay não cria `apps/ai_gateway`. A governança de modelo fica no Agent Gateway, e a execução LLM continua no Runtime/backend usando os providers já existentes.

View File

@@ -0,0 +1,520 @@
### Long-Term Memory Implementation Guide
### Concept
Long-Term Memory (LTM) is the `agent_framework` capability that stores and retrieves durable facts beyond the lifetime of a conversation session.
Unlike message history, which is normally associated with a `session_id`, Long-Term Memory is associated with the business identity of the user or customer. In the current implementation, this identity consists of:
```text
tenant_id
agent_id
customer_key
```
This allows an agent to retrieve preferences, identity information, projects and constraints even when a new session is created.
### Purpose
Long-Term Memory is used to:
- maintain continuity across sessions;
- personalize responses;
- prevent users from repeating previously supplied information;
- reduce the need to send the full conversation history to the model;
- store preferences, current projects, preferred names and constraints;
- isolate memory across tenants, agents and customers.
Example:
```text
Session A:
"Call me Cris. My preferred language is Python."
Session B, with another session_id and the same customer_key:
"What do you remember about me?"
Expected response:
"Your preferred name is Cris and your preferred language is Python."
```
### Memory type differences
#### Conversation Memory
Stores messages from the current conversation and is normally associated with the `session_id`.
#### Summary Memory
Stores a summary of the conversation to reduce the context size sent to the model.
#### Long-Term Memory
Stores durable facts across sessions and is associated with the business identity, primarily the `customer_key`.
### Components
#### LongTermMemoryManager
Coordinates:
- memory loading;
- identity-based retrieval;
- context rendering;
- durable fact extraction;
- fact persistence;
- deduplication and updates.
#### LongTermMemoryStore
Persistence interface used by the manager.
#### SQLiteLongTermMemoryStore
Reference implementation based on SQLite.
It is suitable for:
- local development;
- testing;
- demonstrations;
- low-scale environments.
#### InMemoryLongTermMemoryStore
In-memory implementation used for quick tests.
Its content is lost when the backend process stops.
#### LongTermMemoryExtractor
Identifies durable facts in messages.
Examples:
```text
preferred_name = Cris
preferred_language = Python
current_project = Atlas
```
#### LongTermMemoryItem
Data model representing a persisted item, including identity, key, value, category, confidence and metadata.
#### AgentRuntime
Loads memory before agent execution and injects the rendered context into the prompt.
#### persist_long_term_memory node
LangGraph node responsible for persisting facts after the final response has been generated and validated.
### File structure
```text
libs/
└── agent_framework/
└── src/
└── agent_framework/
└── memory/
├── __init__.py
├── long_term_extractor.py
├── long_term_memory.py
├── long_term_models.py
└── long_term_store.py
```
### Execution flow
```text
User message
AgentRuntime.prepare_memory_context()
├── Conversation Memory
├── Summary Memory
└── Long-Term Memory
long_term_memory_context
Agent prompt
Agent
Guardrails / Judges / Supervisor
persist_long_term_memory
LongTermMemoryExtractor
LongTermMemoryStore
```
### Framework configuration
### New modules
Copy:
```text
libs/agent_framework/src/agent_framework/memory/long_term_extractor.py
libs/agent_framework/src/agent_framework/memory/long_term_memory.py
libs/agent_framework/src/agent_framework/memory/long_term_models.py
libs/agent_framework/src/agent_framework/memory/long_term_store.py
```
### Update memory/__init__.py
Export the Long-Term Memory components:
```python
from agent_framework.memory.long_term_memory import (
LongTermMemoryManager,
create_long_term_memory_manager,
)
from agent_framework.memory.long_term_models import LongTermMemoryItem
from agent_framework.memory.long_term_store import (
InMemoryLongTermMemoryStore,
LongTermMemoryStore,
SQLiteLongTermMemoryStore,
create_long_term_memory_store,
)
```
### Update settings.py
Add:
```python
ENABLE_LONG_TERM_MEMORY: bool = False
LONG_TERM_MEMORY_PROVIDER: str = "sqlite"
LONG_TERM_MEMORY_SQLITE_PATH: str = "./data/agent_framework.db"
LONG_TERM_MEMORY_TABLE: str = "agentfw_long_term_memory"
LONG_TERM_MEMORY_MAX_CONTEXT_ITEMS: int = 20
LONG_TERM_MEMORY_MIN_CONFIDENCE: float = 0.70
LONG_TERM_MEMORY_AUTO_EXTRACT: bool = True
LONG_TERM_MEMORY_INJECT_CONTEXT: bool = True
```
### AgentRuntime integration
The runtime must:
1. verify that the feature is enabled;
2. create the manager when needed;
3. retrieve facts using the identity;
4. populate the workflow state;
5. inject the rendered context into the prompt.
State fields:
```python
long_term_memories: list[dict]
long_term_memory_context: str
long_term_memory_write_result: dict
```
### AgentWorkflow initialization
Create the manager in `AgentWorkflow`:
```python
self.long_term_memory_manager = create_long_term_memory_manager(
settings,
telemetry=telemetry,
)
```
### Correct agent initialization
Do not pass `long_term_memory_manager` through `agent_kwargs` when the constructors of `BillingAgent`, `ProductAgent`, `OrdersAgent` and `SupportAgent` do not declare that parameter.
This initialization causes an error:
```python
agent_kwargs = {
"telemetry": telemetry,
"settings": settings,
"memory": memory,
"summary_memory": summary_memory,
"long_term_memory_manager": self.long_term_memory_manager,
}
self.billing = BillingAgent(llm, **agent_kwargs)
```
Resulting error:
```text
TypeError: BillingAgent.__init__() got an unexpected keyword argument
'long_term_memory_manager'
```
The recommended approach is to create agents using their existing signatures and inject the manager as an attribute after initialization:
```python
agent_kwargs = {
"telemetry": telemetry,
"tool_router": getattr(self, "tool_router", None),
"rag_service": self.rag_service,
"cache": self.cache,
"settings": settings,
"observer": self.observer,
"memory": memory,
"summary_memory": summary_memory,
}
self.billing = BillingAgent(llm, **agent_kwargs)
self.product = ProductAgent(llm, **agent_kwargs)
self.orders = OrdersAgent(llm, **agent_kwargs)
self.support = SupportAgent(llm, **agent_kwargs)
for agent in (
self.billing,
self.product,
self.orders,
self.support,
):
agent.long_term_memory_manager = self.long_term_memory_manager
```
This approach avoids changing every agent constructor and keeps the feature encapsulated in the framework.
### LangGraph configuration
Register the node:
```python
builder.add_node(
"persist_long_term_memory",
self._node(
"persist_long_term_memory",
self.persist_long_term_memory,
),
)
```
Update the edges:
```python
builder.add_edge(
"supervisor_review",
"persist_long_term_memory",
)
builder.add_edge(
"persist_long_term_memory",
"persist",
)
```
Implement:
```python
async def persist_long_term_memory(
self,
state: AgentState,
) -> dict[str, object]:
result = await self.long_term_memory_manager.persist_turn(state)
return {
"long_term_memory_write_result": result,
}
```
Final flow:
```text
supervisor_review
persist_long_term_memory
persist
```
### Environment variables
```env
ENABLE_LONG_TERM_MEMORY=true
LONG_TERM_MEMORY_PROVIDER=sqlite
LONG_TERM_MEMORY_SQLITE_PATH=./data/agent_framework.db
LONG_TERM_MEMORY_TABLE=agentfw_long_term_memory
LONG_TERM_MEMORY_MAX_CONTEXT_ITEMS=20
LONG_TERM_MEMORY_MIN_CONFIDENCE=0.70
LONG_TERM_MEMORY_AUTO_EXTRACT=true
LONG_TERM_MEMORY_INJECT_CONTEXT=true
```
### SQLite database path
A relative path is resolved from the directory in which the backend is started.
To prevent different databases from being created accidentally, prefer an absolute path in development environments:
```env
LONG_TERM_MEMORY_SQLITE_PATH=/mnt/c/Asus_Projects/agent_platform_oci_long_term_memory/data/agent_framework.db
```
Create the directory before starting:
```bash
mkdir -p data
```
### Testing
### Test 1 — Persistence
Send:
```json
{
"session_id": "default:telecom_contas:memory-session-a",
"customer_key": "11999999999",
"message": "Call me Cris. My preferred language is Python and my current project is Atlas."
}
```
### Test 2 — Retrieval in another session
Use another `session_id` while keeping the same `customer_key`:
```json
{
"session_id": "default:telecom_contas:memory-session-b",
"customer_key": "11999999999",
"message": "What do you remember about me, my preferences and my project?"
}
```
Expected result:
```text
Your preferred name is Cris.
Your preferred language is Python.
Your current project is Atlas.
```
### Test 3 — Isolation
Use another customer:
```json
{
"session_id": "default:telecom_contas:memory-session-c",
"customer_key": "another-customer",
"message": "What is my preferred name and current project?"
}
```
The data associated with `11999999999` must not be returned.
### Test 4 — Frontend reset
Restart or reset the frontend and verify that it still sends the same `customer_key`.
Memory must survive a `session_id` change. Resetting the frontend does not delete the SQLite database.
### Test 5 — Backend restart
Restart Uvicorn and repeat the query.
With:
```env
LONG_TERM_MEMORY_PROVIDER=sqlite
```
memory must remain available.
With:
```env
LONG_TERM_MEMORY_PROVIDER=memory
```
memory is lost when the process stops.
### Direct SQLite verification
Find the database:
```bash
find . -name "agent_framework.db" -type f
```
Open it:
```bash
sqlite3 ./data/agent_framework.db
```
Query:
```sql
SELECT
tenant_id,
agent_id,
customer_key,
memory_type,
memory_key,
memory_value,
confidence,
created_at,
updated_at
FROM agentfw_long_term_memory
ORDER BY updated_at DESC;
```
### Success criteria
The implementation is working when:
- memory is retrieved with another `session_id`;
- the same `customer_key` retrieves previous facts;
- another `customer_key` cannot access those facts;
- restarting the frontend does not erase memory;
- restarting the backend does not erase memory when using SQLite;
- the `persist_long_term_memory` node runs;
- the prompt receives `long_term_memory_context`.
### Best practices
- Persist only durable facts.
- Do not store the complete conversation as Long-Term Memory.
- Isolate data by `tenant_id`, `agent_id` and `customer_key`.
- Do not use `session_id` as the permanent user identity.
- Persist only after final validations.
- Avoid persisting temporary tool results.
- Record telemetry for reads, writes, updates and failures.
- Define retention and deletion policies.
- Use an absolute SQLite path in environments with multiple working directories.
- Move to an enterprise database for production and high-availability environments.
### Reference implementation limitations
The current implementation uses rule-based extraction and SQLite as the reference provider.
Recommended future enhancements:
- LLM-based fact extraction;
- vector-based semantic memory;
- episodic memory;
- expiration and versioning;
- semantic deduplication;
- consent policies;
- query and deletion APIs;
- Oracle Autonomous Database provider;
- encryption and sensitive-data classification.

View File

@@ -0,0 +1,272 @@
# Agent Platform OCI — Manual Oficial de Agent Gateway e MCP Gateway
## Objetivo
Este documento consolida:
- Arquitetura oficial
- Inventário dos componentes
- Procedimento completo de execução local
- MCP Gateway
- Agent Gateway
- Backend Runtime
- Frontend
- Testes E2E
- Troubleshooting
- Decisões arquiteturais
---
# Arquitetura Oficial
Frontend (5173)
Agent Gateway (9000)
Agent Template Backend / Runtime (8000)
MCP Gateway (8300)
Telecom MCP Server (8100)
Retail MCP Server (8200)
---
# Portas Oficiais
| Componente | Porta |
|------------|--------|
| Frontend | 5173 |
| Agent Gateway | 9000 |
| Backend Runtime | 8000 |
| MCP Gateway | 8300 |
| Telecom MCP Server | 8100 |
| Retail MCP Server | 8200 |
---
# Variáveis Oficiais
## Agent Template Backend
ENABLE_MCP_TOOLS=true
MCP_GATEWAY_ENABLED=true
MCP_GATEWAY_URL=http://localhost:8300
MCP_GATEWAY_TIMEOUT_SECONDS=60
MCP_GATEWAY_AGENT_ID=telecom_contas
MCP_GATEWAY_TENANT_ID=default
## Agent Gateway
DEFAULT_AGENT_BACKEND_URL=http://localhost:8000
AGENT_GATEWAY_GOVERNANCE_CONFIG=config/gateway_governance.yaml
## MCP Gateway
MCP_GATEWAY_CONFIG_PATH=config/mcp_gateway.yaml
---
# Ordem de Inicialização
1. Telecom MCP Server
2. Retail MCP Server
3. MCP Gateway
4. Agent Template Backend
5. Agent Gateway
6. Frontend
---
# Terminal 1 — Telecom MCP Server
cd mcp/servers/telecom_mcp_server
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python -m uvicorn main:app --host 0.0.0.0 --port 8100 --reload
Validação:
curl http://localhost:8100/health
---
# Terminal 2 — Retail MCP Server
cd mcp/servers/retail_mcp_server
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python -m uvicorn main:app --host 0.0.0.0 --port 8200 --reload
Validação:
curl http://localhost:8200/health
---
# Terminal 3 — MCP Gateway
cd apps/mcp_gateway
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
export MCP_GATEWAY_CONFIG_PATH=config/mcp_gateway.yaml
python -m uvicorn app.main:app --host 0.0.0.0 --port 8300 --reload
Validações:
curl http://localhost:8300/health
curl http://localhost:8300/ready
curl http://localhost:8300/v1/tools
Teste:
curl -X POST http://localhost:8300/v1/tools/consultar_fatura/invoke
---
# Terminal 4 — Agent Template Backend
cd templates/agent_template_backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
Validações:
curl http://localhost:8000/health
curl http://localhost:8000/agents
---
# Terminal 5 — Agent Gateway
cd apps/agent_gateway
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
export DEFAULT_AGENT_BACKEND_URL=http://localhost:8000
export AGENT_GATEWAY_GOVERNANCE_CONFIG=config/gateway_governance.yaml
python -m uvicorn app.main:app --host 0.0.0.0 --port 9000 --reload
Validações:
curl http://localhost:9000/health
Teste:
curl -X POST http://localhost:9000/gateway/message
---
# Terminal 6 — Frontend
cd agent_frontend
npm install
npm run dev -- --host 0.0.0.0 --port 5173
Abrir:
http://localhost:5173
Backend URL:
http://localhost:9000
---
# Fluxo de Tools
Agent
MCPToolRouter
MCPGatewayClient
MCP Gateway
MCP Server
---
# Teste Integrado E2E
Frontend
Agent Gateway
Backend Runtime
MCP Gateway
Telecom MCP Server
Resultado esperado:
- Agent Gateway recebe requisição
- Runtime executa LangGraph
- MCP Gateway resolve tool
- MCP Server responde
- Usuário recebe resposta
---
# Troubleshooting
## Backend chamando MCP Server direto
Confirmar:
MCP_GATEWAY_ENABLED=true
MCP_GATEWAY_URL=http://localhost:8300
## Porta incorreta
A porta oficial do MCP Gateway é:
8300
## Agent Gateway não encontra Backend
Validar:
curl http://localhost:8000/health
## MCP Gateway não encontra MCP Server
Validar:
curl http://localhost:8100/health
curl http://localhost:8200/health
---
# Decisões Arquiteturais Oficiais
- Agent Gateway centraliza governança
- Runtime executa LangGraph
- Runtime executa LLM
- MCP Gateway centraliza tools
- MCP Servers executam tools
- Backend usa MCP Gateway
- gateway_runtime.env.example foi removido
- MCP_GATEWAY_* fica no .env do backend
- Porta oficial MCP Gateway = 8300

View File

@@ -0,0 +1,627 @@
# Manual de Execução Local
## Agent Gateway + MCP Gateway + Agent Template Backend + Frontend
## 1. Arquitetura de execução
A arquitetura local fica assim:
```text
Frontend
porta 5173
Agent Gateway
porta 9000
Agent Template Backend / Agent Runtime
porta 8000
MCP Gateway
porta 8300
MCP Server / Mock Telecom MCP
porta 8001
```
A governança de modelo, rate limit, auditoria e políticas ficam no **Agent Gateway**.
O **Agent Runtime / Agent Template Backend** continua responsável por:
- LangGraph;
- estado;
- memória;
- checkpoints;
- supervisor/router;
- guardrails;
- judges;
- chamada LLM via providers existentes;
- chamada de tools via MCP Gateway.
---
## 2. Portas
| Componente | Porta | URL |
|---|---:|---|
| Frontend | 5173 | `http://localhost:5173` |
| Agent Gateway | 9000 | `http://localhost:9000` |
| Agent Template Backend | 8000 | `http://localhost:8000` |
| MCP Gateway | 8300 | `http://localhost:8300` |
| MCP Server / Mock Telecom MCP | 8001 | `http://localhost:8001` |
---
## 3. Ordem recomendada para subir
Subir nesta ordem:
1. MCP Server / Mock Telecom MCP
2. MCP Gateway
3. Agent Template Backend
4. Agent Gateway
5. Frontend
---
# 4. Terminal 1 — MCP Server / Mock Telecom MCP
Se estiver usando o mock incluído no overlay:
```bash
cd agent_platform_oci/mcp/servers/mock_telecom_mcp
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app:app --host 0.0.0.0 --port 8001 --reload
```
Validar:
```bash
curl http://localhost:8001/health
```
Resultado esperado:
```json
{
"status": "ok",
"service": "mock_telecom_mcp"
}
```
---
# 5. Terminal 2 — MCP Gateway
```bash
cd agent_platform_oci/apps/mcp_gateway
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
export MCP_GATEWAY_CONFIG_PATH=config/mcp_gateway.yaml
uvicorn app.main:app --host 0.0.0.0 --port 8300 --reload
```
Validar health:
```bash
curl http://localhost:8300/health
```
Validar readiness:
```bash
curl http://localhost:8300/ready
```
Listar tools:
```bash
curl -s http://localhost:8300/v1/tools | jq
```
Executar tool:
```bash
curl -s -X POST http://localhost:8300/v1/tools/consultar_fatura/invoke \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "default",
"agent_id": "telecom_contas",
"channel": "web",
"tool_name": "consultar_fatura",
"business_context": {
"customer_key": "11999999999",
"contract_key": "INV-001",
"session_key": "session-001"
}
}' | jq
```
Resultado esperado:
```json
{
"tool_name": "consultar_fatura",
"version": "1.0.0",
"ok": true,
"data": {
"invoice_id": "INV-001",
"msisdn": "11999999999",
"valor_total": 249.9,
"vencimento": "2026-06-10",
"status": "ABERTA"
}
}
```
---
# 6. Terminal 3 — Agent Template Backend / Agent Runtime
```bash
cd agent_platform_oci/templates/agent_template_backend
```
ou, se o seu backend estiver em outra pasta:
```bash
cd agent_platform_oci/templates/agent_template_backend
```
Ativar ambiente:
```bash
source .venv/bin/activate
```
Se ainda não existir `.venv`:
```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
Configurar variáveis:
```bash
export MCP_GATEWAY_ENABLED=true
export MCP_GATEWAY_URL=http://localhost:8300
export MCP_GATEWAY_TIMEOUT_SECONDS=60
export AGENT_GATEWAY_GOVERNANCE_CONFIG=config/gateway_governance.yaml
```
Se estiver usando OCI/OpenAI-compatible, manter também as variáveis já existentes do backend:
```bash
export LLM_PROVIDER=oci_openai
export OCI_GENAI_API_KEY=<sua-chave>
```
ou, para mock:
```bash
export LLM_PROVIDER=mock
```
Subir backend:
```bash
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
```
Validar:
```bash
curl http://localhost:8000/health
```
Validar agentes:
```bash
curl http://localhost:8000/agents | jq
```
Testar backend direto:
```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": "session-001",
"user_id": "user-001",
"message_id": "msg-001",
"business_context": {
"customer_key": "11999999999",
"contract_key": "INV-001",
"session_key": "session-001"
}
}
}' | jq
```
---
# 7. Terminal 4 — Agent Gateway
```bash
cd agent_platform_oci/apps/agent_gateway
```
Ativar ambiente:
```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
Configurar variáveis:
```bash
export DEFAULT_AGENT_BACKEND_URL=http://localhost:8000
export AGENT_GATEWAY_GOVERNANCE_CONFIG=config/gateway_governance.yaml
```
Subir Agent Gateway:
```bash
python -m uvicorn app.main:app --host 0.0.0.0 --port 9000 --reload
```
Validar:
```bash
curl http://localhost:9000/health
```
Se a rota governada de exemplo estiver registrada no `app.main`, testar:
```bash
curl -s -X POST http://localhost:9000/gateway/message/governed \
-H "Content-Type: application/json" \
-d '{
"channel": "web",
"tenant_id": "default",
"agent_id": "telecom_contas",
"payload": {
"message": "Quero consultar minha fatura",
"session_id": "session-001",
"user_id": "user-001",
"message_id": "msg-001",
"metadata": {
"operation": "agent.final_answer"
},
"business_context": {
"customer_key": "11999999999",
"contract_key": "INV-001",
"session_key": "session-001"
}
}
}' | jq
```
Se a rota real for `/gateway/message`, testar:
```bash
curl -s -X POST http://localhost:9000/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": "session-001",
"user_id": "user-001",
"message_id": "msg-001",
"metadata": {
"operation": "agent.final_answer"
},
"business_context": {
"customer_key": "11999999999",
"contract_key": "INV-001",
"session_key": "session-001"
}
}
}' | jq
```
---
# 8. Terminal 5 — Frontend
```bash
cd agent_platform_oci/agent_frontend
```
ou a pasta onde estiver o frontend.
Instalar dependências:
```bash
npm install
```
Subir:
```bash
npm run dev -- --host 0.0.0.0 --port 5173
```
Abrir:
```text
http://localhost:5173
```
Configurar no frontend:
```text
Backend URL: http://localhost:9000
Agent: telecom_contas
Session ID: session-001
Customer Key: 11999999999
Contract Key: INV-001
```
O frontend deve chamar o **Agent Gateway** na porta 9000, não o MCP Gateway.
---
# 9. Fluxo final esperado
```text
Frontend 5173
Agent Gateway 9000
Agent Template Backend 8000
MCP Gateway 8300
Mock Telecom MCP 8001
```
---
# 10. Docker Compose para MCP Gateway + Mock MCP
Também é possível subir MCP Gateway + Mock MCP com Docker Compose:
```bash
cd agent_platform_oci
docker compose -f deploy/docker/docker-compose.mcp-gateway.yml up --build
```
Isso sobe:
```text
MCP Gateway http://localhost:8300
Mock Telecom MCP http://localhost:8001
```
Depois subir manualmente:
- Agent Template Backend na porta 8000;
- Agent Gateway na porta 9000;
- Frontend na porta 5173.
---
# 11. Checklist de validação
## MCP Server
```bash
curl http://localhost:8001/health
```
## MCP Gateway
```bash
curl http://localhost:8300/health
curl http://localhost:8300/v1/tools
```
## Backend Runtime
```bash
curl http://localhost:8000/health
curl http://localhost:8000/agents
```
## Agent Gateway
```bash
curl http://localhost:9000/health
```
## Frontend
```text
http://localhost:5173
```
---
# 12. Erros comuns
## 12.1. Frontend chamando porta errada
Errado:
```text
Frontend → http://localhost:8000
```
Correto:
```text
Frontend → http://localhost:9000
```
Se você quiser testar sem Agent Gateway, pode apontar temporariamente para 8000. Mas no modelo final, o frontend deve usar o Agent Gateway.
---
## 12.2. MCP Gateway sem MCP Server
Sintoma:
```text
MCP server unavailable
```
Correção:
```bash
curl http://localhost:8001/health
```
Se falhar, subir o mock MCP server.
---
## 12.3. Tool sem BusinessContext
Sintoma:
```json
{
"missing_business_keys": ["customer_key", "contract_key"]
}
```
Correção:
enviar:
```json
"business_context": {
"customer_key": "11999999999",
"contract_key": "INV-001",
"session_key": "session-001"
}
```
---
## 12.4. Agent Gateway não encontra backend
Sintoma:
```text
Connection refused http://localhost:8000
```
Correção:
validar:
```bash
curl http://localhost:8000/health
```
e configurar:
```bash
export DEFAULT_AGENT_BACKEND_URL=http://localhost:8000
```
---
## 12.5. Rota governada não registrada
Se `/gateway/message/governed` retornar 404, significa que o arquivo de exemplo ainda não foi incluído no `app.main`.
Nesse caso, use a rota real `/gateway/message` ou registre no `main.py`:
```python
from app.routes.governed_proxy_example import router as governed_router
app.include_router(governed_router)
```
---
# 13. Variáveis consolidadas
## Agent Gateway
```env
DEFAULT_AGENT_BACKEND_URL=http://localhost:8000
AGENT_GATEWAY_GOVERNANCE_CONFIG=config/gateway_governance.yaml
```
## Agent Template Backend
```env
MCP_GATEWAY_ENABLED=true
MCP_GATEWAY_URL=http://localhost:8300
MCP_GATEWAY_TIMEOUT_SECONDS=60
LLM_PROVIDER=mock
```
## MCP Gateway
```env
MCP_GATEWAY_CONFIG_PATH=config/mcp_gateway.yaml
```
---
# 14. Resumo rápido
Em cinco terminais:
```bash
# Terminal 1
cd mcp/servers/mock_telecom_mcp
source .venv/bin/activate
uvicorn app:app --host 0.0.0.0 --port 8001 --reload
# Terminal 2
cd apps/mcp_gateway
source .venv/bin/activate
export MCP_GATEWAY_CONFIG_PATH=config/mcp_gateway.yaml
uvicorn app.main:app --host 0.0.0.0 --port 8300 --reload
# Terminal 3
cd templates/agent_template_backend
source .venv/bin/activate
export MCP_GATEWAY_ENABLED=true
export MCP_GATEWAY_URL=http://localhost:8300
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
# Terminal 4
cd apps/agent_gateway
source .venv/bin/activate
export DEFAULT_AGENT_BACKEND_URL=http://localhost:8000
export AGENT_GATEWAY_GOVERNANCE_CONFIG=config/gateway_governance.yaml
uvicorn app.main:app --host 0.0.0.0 --port 9000 --reload
# Terminal 5
cd agent_frontend
npm install
npm run dev -- --host 0.0.0.0 --port 5173
```

View File

@@ -0,0 +1,93 @@
# MCP Gateway Runbook
## Arquitetura corrigida
O backend/agente não deve chamar diretamente os MCP servers finais. O fluxo correto é:
```text
agent_template_backend / agent_framework
-> MCP Gateway Client
-> apps/mcp_gateway
-> mcp/servers/telecom_mcp_server ou mcp/servers/retail_mcp_server
```
## Subir localmente
A partir da raiz do projeto:
### Terminal 1 - Telecom MCP Server
```bash
cd mcp/servers/telecom_mcp_server
python -m uvicorn main:app --host 0.0.0.0 --port 8100 --reload
```
### Terminal 2 - Retail MCP Server
```bash
cd mcp/servers/retail_mcp_server
python -m uvicorn main:app --host 0.0.0.0 --port 8200 --reload
```
### Terminal 3 - MCP Gateway
```bash
cd apps/mcp_gateway
export MCP_GATEWAY_CONFIG_PATH=config/mcp_gateway.yaml
python -m uvicorn app.main:app --host 0.0.0.0 --port 8300 --reload
```
### Terminal 4 - Backend/agente
No `.env` do backend/agente ou do runtime que usa o `agent_framework`, habilite:
```env
ENABLE_MCP_TOOLS=true
MCP_GATEWAY_ENABLED=true
MCP_GATEWAY_URL=http://localhost:8300
MCP_GATEWAY_AGENT_ID=telecom_contas
MCP_GATEWAY_TENANT_ID=default
```
## Testes rápidos
### Health do gateway
```bash
curl http://localhost:8300/health
```
### Lista de tools expostas pelo gateway
```bash
curl http://localhost:8300/v1/tools
```
### Chamada de tool via gateway
```bash
curl -X POST http://localhost:8300/v1/tools/consultar_fatura/invoke \
-H 'Content-Type: application/json' \
-d '{
"tenant_id": "default",
"agent_id": "telecom_contas",
"channel": "web",
"tool_name": "consultar_fatura",
"arguments": {
"msisdn": "11999999999",
"invoice_id": "INV-123"
},
"business_context": {},
"metadata": {"session_id": "local-test"}
}'
```
Resposta esperada: `ok: true`, `data.invoice_id`, `data.msisdn`, `metadata.server: telecom`.
## O que foi corrigido
- `apps/mcp_gateway/config/mcp_gateway.yaml` agora aponta para os MCP servers reais nas portas `8100` e `8200`.
- O MCP Gateway agora suporta o contrato legado dos MCP servers: `POST /mcp/tools/call` com `{tool_name, arguments}`.
- O `agent_framework` ganhou flags `MCP_GATEWAY_ENABLED`, `MCP_GATEWAY_URL`, `MCP_GATEWAY_TOKEN`, `MCP_GATEWAY_AGENT_ID` e `MCP_GATEWAY_TENANT_ID`.
- O `MCPToolRouter` passa a chamar o MCP Gateway quando `MCP_GATEWAY_ENABLED=true`.
- `libs/agent_framework/config/mcp_servers.yaml` foi mantido como registry lógico/fallback, não como caminho principal quando o gateway está ativo.

View File

@@ -0,0 +1,520 @@
### Manual de Implementação — Long-Term Memory
### Conceito
A Long-Term Memory (LTM) é a capacidade do `agent_framework` de armazenar e recuperar fatos duradouros além da duração de uma sessão de conversa.
Diferentemente do histórico de mensagens, que normalmente está associado a um `session_id`, a memória de longo prazo é associada à identidade de negócio do usuário ou cliente. Na implementação atual, essa identidade é composta por:
```text
tenant_id
agent_id
customer_key
```
Isso permite que um agente recupere preferências, informações de identidade, projetos e restrições mesmo quando uma nova sessão é criada.
### Para que serve
A Long-Term Memory serve para:
- manter continuidade entre sessões;
- personalizar respostas;
- evitar que o usuário repita informações já fornecidas;
- reduzir a necessidade de enviar todo o histórico ao modelo;
- armazenar preferências, projetos atuais, nomes preferidos e restrições;
- isolar a memória entre tenants, agentes e clientes.
Exemplo:
```text
Sessão A:
"Me chame de Cris. Minha linguagem preferida é Python."
Sessão B, com outro session_id e o mesmo customer_key:
"O que você lembra sobre mim?"
Resposta esperada:
"Seu nome preferido é Cris e sua linguagem preferida é Python."
```
### Diferença entre os tipos de memória
#### Conversation Memory
Mantém as mensagens da conversa atual e normalmente está associada ao `session_id`.
#### Summary Memory
Mantém um resumo da conversa para reduzir o tamanho do contexto enviado ao modelo.
#### Long-Term Memory
Mantém fatos duradouros entre sessões e é associada à identidade de negócio, principalmente ao `customer_key`.
### Componentes da funcionalidade
#### LongTermMemoryManager
Responsável por coordenar:
- carregamento das memórias;
- recuperação por identidade;
- renderização do contexto;
- extração de novos fatos;
- persistência dos fatos;
- deduplicação e atualização.
#### LongTermMemoryStore
Interface de persistência utilizada pelo manager.
#### SQLiteLongTermMemoryStore
Implementação de referência baseada em SQLite.
É apropriada para:
- desenvolvimento local;
- testes;
- demonstrações;
- ambientes de baixa escala.
#### InMemoryLongTermMemoryStore
Implementação em memória utilizada para testes rápidos.
O conteúdo é perdido quando o processo do backend é encerrado.
#### LongTermMemoryExtractor
Responsável por identificar fatos duradouros nas mensagens.
Exemplos de fatos:
```text
preferred_name = Cris
preferred_language = Python
current_project = Atlas
```
#### LongTermMemoryItem
Modelo que representa um item persistido, incluindo identidade, chave, valor, categoria, confiança e metadados.
#### AgentRuntime
Carrega a memória antes da execução do agente e injeta o contexto no prompt.
#### Nó persist_long_term_memory
Nó do LangGraph responsável por persistir os fatos após a geração e validação da resposta final.
### Estrutura dos arquivos
```text
libs/
└── agent_framework/
└── src/
└── agent_framework/
└── memory/
├── __init__.py
├── long_term_extractor.py
├── long_term_memory.py
├── long_term_models.py
└── long_term_store.py
```
### Fluxo de execução
```text
Mensagem do usuário
AgentRuntime.prepare_memory_context()
├── Conversation Memory
├── Summary Memory
└── Long-Term Memory
long_term_memory_context
Prompt do agente
Agente
Guardrails / Judges / Supervisor
persist_long_term_memory
LongTermMemoryExtractor
LongTermMemoryStore
```
### Configuração do framework
### Novos módulos
Copie os arquivos:
```text
libs/agent_framework/src/agent_framework/memory/long_term_extractor.py
libs/agent_framework/src/agent_framework/memory/long_term_memory.py
libs/agent_framework/src/agent_framework/memory/long_term_models.py
libs/agent_framework/src/agent_framework/memory/long_term_store.py
```
### Atualização de memory/__init__.py
Exporte os componentes da Long-Term Memory:
```python
from agent_framework.memory.long_term_memory import (
LongTermMemoryManager,
create_long_term_memory_manager,
)
from agent_framework.memory.long_term_models import LongTermMemoryItem
from agent_framework.memory.long_term_store import (
InMemoryLongTermMemoryStore,
LongTermMemoryStore,
SQLiteLongTermMemoryStore,
create_long_term_memory_store,
)
```
### Atualização de settings.py
Adicione as configurações:
```python
ENABLE_LONG_TERM_MEMORY: bool = False
LONG_TERM_MEMORY_PROVIDER: str = "sqlite"
LONG_TERM_MEMORY_SQLITE_PATH: str = "./data/agent_framework.db"
LONG_TERM_MEMORY_TABLE: str = "agentfw_long_term_memory"
LONG_TERM_MEMORY_MAX_CONTEXT_ITEMS: int = 20
LONG_TERM_MEMORY_MIN_CONFIDENCE: float = 0.70
LONG_TERM_MEMORY_AUTO_EXTRACT: bool = True
LONG_TERM_MEMORY_INJECT_CONTEXT: bool = True
```
### Integração com AgentRuntime
O runtime deve:
1. verificar se a funcionalidade está habilitada;
2. criar o manager quando necessário;
3. recuperar os fatos pela identidade;
4. preencher o estado;
5. injetar o contexto no prompt.
Campos adicionados ao estado:
```python
long_term_memories: list[dict]
long_term_memory_context: str
long_term_memory_write_result: dict
```
### Inicialização no AgentWorkflow
O manager deve ser criado no `AgentWorkflow`:
```python
self.long_term_memory_manager = create_long_term_memory_manager(
settings,
telemetry=telemetry,
)
```
### Inicialização correta dos agentes
O `long_term_memory_manager` não deve ser passado pelo `agent_kwargs` caso os construtores de `BillingAgent`, `ProductAgent`, `OrdersAgent` e `SupportAgent` não declarem esse parâmetro.
Esta inicialização causa erro:
```python
agent_kwargs = {
"telemetry": telemetry,
"settings": settings,
"memory": memory,
"summary_memory": summary_memory,
"long_term_memory_manager": self.long_term_memory_manager,
}
self.billing = BillingAgent(llm, **agent_kwargs)
```
Erro resultante:
```text
TypeError: BillingAgent.__init__() got an unexpected keyword argument
'long_term_memory_manager'
```
A forma recomendada é criar os agentes com a assinatura já existente e injetar o manager como atributo após a inicialização:
```python
agent_kwargs = {
"telemetry": telemetry,
"tool_router": getattr(self, "tool_router", None),
"rag_service": self.rag_service,
"cache": self.cache,
"settings": settings,
"observer": self.observer,
"memory": memory,
"summary_memory": summary_memory,
}
self.billing = BillingAgent(llm, **agent_kwargs)
self.product = ProductAgent(llm, **agent_kwargs)
self.orders = OrdersAgent(llm, **agent_kwargs)
self.support = SupportAgent(llm, **agent_kwargs)
for agent in (
self.billing,
self.product,
self.orders,
self.support,
):
agent.long_term_memory_manager = self.long_term_memory_manager
```
Essa abordagem evita alterar os construtores de todos os agentes e mantém a funcionalidade encapsulada no framework.
### Configuração do LangGraph
Registre o nó:
```python
builder.add_node(
"persist_long_term_memory",
self._node(
"persist_long_term_memory",
self.persist_long_term_memory,
),
)
```
Altere o fluxo:
```python
builder.add_edge(
"supervisor_review",
"persist_long_term_memory",
)
builder.add_edge(
"persist_long_term_memory",
"persist",
)
```
Implemente o método:
```python
async def persist_long_term_memory(
self,
state: AgentState,
) -> dict[str, object]:
result = await self.long_term_memory_manager.persist_turn(state)
return {
"long_term_memory_write_result": result,
}
```
Fluxo final:
```text
supervisor_review
persist_long_term_memory
persist
```
### Variáveis de ambiente
```env
ENABLE_LONG_TERM_MEMORY=true
LONG_TERM_MEMORY_PROVIDER=sqlite
LONG_TERM_MEMORY_SQLITE_PATH=./data/agent_framework.db
LONG_TERM_MEMORY_TABLE=agentfw_long_term_memory
LONG_TERM_MEMORY_MAX_CONTEXT_ITEMS=20
LONG_TERM_MEMORY_MIN_CONFIDENCE=0.70
LONG_TERM_MEMORY_AUTO_EXTRACT=true
LONG_TERM_MEMORY_INJECT_CONTEXT=true
```
### Caminho do banco SQLite
O caminho relativo é resolvido a partir do diretório em que o backend é iniciado.
Para evitar que bancos diferentes sejam criados acidentalmente, prefira um caminho absoluto em ambientes de desenvolvimento:
```env
LONG_TERM_MEMORY_SQLITE_PATH=/mnt/c/Asus_Projects/agent_platform_oci_long_term_memory/data/agent_framework.db
```
Crie a pasta antes de iniciar:
```bash
mkdir -p data
```
### Como testar
### Teste 1 — Gravação
Envie:
```json
{
"session_id": "default:telecom_contas:memory-session-a",
"customer_key": "11999999999",
"message": "Me chame de Cris. Minha linguagem preferida é Python e meu projeto atual se chama Atlas."
}
```
### Teste 2 — Recuperação em outra sessão
Utilize outro `session_id`, mantendo o mesmo `customer_key`:
```json
{
"session_id": "default:telecom_contas:memory-session-b",
"customer_key": "11999999999",
"message": "O que você lembra sobre mim, minhas preferências e meu projeto?"
}
```
Resultado esperado:
```text
Seu nome preferido é Cris.
Sua linguagem preferida é Python.
Seu projeto atual se chama Atlas.
```
### Teste 3 — Isolamento
Utilize outro cliente:
```json
{
"session_id": "default:telecom_contas:memory-session-c",
"customer_key": "outro-cliente",
"message": "Qual é meu nome preferido e qual é meu projeto atual?"
}
```
Os dados de `11999999999` não devem aparecer.
### Teste 4 — Reinicialização do frontend
Reinicie ou resete o frontend e confirme que ele continua enviando o mesmo `customer_key`.
A memória deve sobreviver à troca do `session_id`. O reset do frontend não apaga o SQLite.
### Teste 5 — Reinicialização do backend
Reinicie o Uvicorn e repita a consulta.
Com:
```env
LONG_TERM_MEMORY_PROVIDER=sqlite
```
a memória deve continuar disponível.
Com:
```env
LONG_TERM_MEMORY_PROVIDER=memory
```
a memória será perdida quando o processo for encerrado.
### Verificação direta no SQLite
Localize o banco:
```bash
find . -name "agent_framework.db" -type f
```
Abra:
```bash
sqlite3 ./data/agent_framework.db
```
Consulte:
```sql
SELECT
tenant_id,
agent_id,
customer_key,
memory_type,
memory_key,
memory_value,
confidence,
created_at,
updated_at
FROM agentfw_long_term_memory
ORDER BY updated_at DESC;
```
### Critérios de sucesso
A implementação está funcionando quando:
- a memória é recuperada com outro `session_id`;
- o mesmo `customer_key` recupera os fatos anteriores;
- outro `customer_key` não acessa esses fatos;
- reiniciar o frontend não apaga a memória;
- reiniciar o backend não apaga a memória quando o provider é SQLite;
- o nó `persist_long_term_memory` é executado;
- o prompt recebe `long_term_memory_context`.
### Boas práticas
- Persistir somente fatos duradouros.
- Não armazenar a conversa completa como Long-Term Memory.
- Isolar dados por `tenant_id`, `agent_id` e `customer_key`.
- Não utilizar `session_id` como identidade permanente do usuário.
- Persistir somente depois das validações finais.
- Evitar armazenar resultados temporários de ferramentas.
- Registrar telemetria de leitura, escrita, atualização e falha.
- Definir políticas de retenção e exclusão.
- Usar caminho absoluto para SQLite em ambientes com múltiplos diretórios de execução.
- Migrar para um banco corporativo em ambientes de produção e alta disponibilidade.
### Limitações da implementação de referência
A implementação atual utiliza extração baseada em regras e SQLite como provider de referência.
Evoluções recomendadas:
- extração de fatos com LLM;
- memória semântica com vetores;
- memória episódica;
- expiração e versionamento;
- deduplicação semântica;
- política de consentimento;
- API de consulta e exclusão;
- provider Oracle Autonomous Database;
- criptografia e classificação de dados sensíveis.

View File

@@ -0,0 +1,129 @@
# Agent Platform OCI — Agent Gateway + MCP Gateway Evolution
Este overlay remove o conceito de `AI Gateway` separado.
## Arquitetura
```text
Frontend
Agent Gateway
├── governance
├── model policies
├── rate limit
├── audit
└── evaluation hooks
Agent Backend / Runtime
├── LangGraph
├── state
├── memory
├── checkpoints
└── LLM providers via profiles existentes
MCP Gateway
MCP Servers
```
## O que entra no Agent Gateway
```text
apps/agent_gateway/app/governance/
apps/agent_gateway/app/governance_middleware.py
apps/agent_gateway/app/routes/governed_proxy_example.py
apps/agent_gateway/config/gateway_governance.yaml
```
## O que entra no MCP Gateway
```text
apps/mcp_gateway/
libs/agent_framework/src/agent_framework/gateways/mcp_gateway_client.py
libs/agent_framework/src/agent_framework/runtime_mcp_gateway_adapter.py
```
## Aplicar overlay
```bash
unzip agent_platform_agent_gateway_mcp_gateway_overlay.zip -d /tmp/overlay
rsync -av /tmp/overlay/ ./
```
## Subir MCP Gateway local
```bash
docker compose -f deploy/docker/docker-compose.mcp-gateway.yml up --build
```
Serviços:
```text
MCP Gateway http://localhost:8300
Mock Telecom MCP http://localhost:8001
```
## Testar MCP Gateway
```bash
curl http://localhost:8300/health
curl http://localhost:8300/v1/tools
```
Executar tool:
```bash
curl -s -X POST http://localhost:8300/v1/tools/consultar_fatura/invoke \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "default",
"agent_id": "telecom_contas",
"channel": "web",
"tool_name": "consultar_fatura",
"business_context": {
"customer_key": "11999999999",
"contract_key": "INV-001",
"session_key": "session-001"
}
}' | jq
```
## Como plugar no Agent Gateway
No handler real do `POST /gateway/message`, antes de encaminhar ao backend/runtime:
```python
governed_body, headers = governance.prepare_backend_request(body)
```
Ao receber resposta do backend:
```python
return governance.process_backend_response(data)
```
O arquivo abaixo mostra um exemplo completo:
```text
apps/agent_gateway/app/routes/governed_proxy_example.py
```
## Variáveis do Runtime
```env
MCP_GATEWAY_ENABLED=true
MCP_GATEWAY_URL=http://localhost:8300
MCP_GATEWAY_TIMEOUT_SECONDS=60
```
## Importante
Não existe `apps/ai_gateway`.
A governança de modelo fica no Agent Gateway como policy/metadados.
O Runtime continua usando os LLM providers existentes, podendo ler a política enviada pelo Gateway em:
```python
state["metadata"]["model_policy"]
```

View File

@@ -0,0 +1,68 @@
# Checkpoint Enterprise no Agent Framework OCI
Esta versão adiciona quatro capacidades ao checkpointer do LangGraph usado pelo framework:
1. **Checkpoint Integrity**: cada checkpoint é salvo dentro de um envelope com `schema_version`, `checkpoint_id`, `payload_hash` SHA-256 e `created_at`. Na leitura, o hash é recalculado. Se o payload foi truncado, alterado ou corrompido, o checkpoint é ignorado no recovery.
2. **Checkpoint Compaction**: checkpoints antigos são removidos automaticamente conforme a configuração `CHECKPOINT_COMPACT_EVERY` e `CHECKPOINT_KEEP_LAST`. Isso evita crescimento infinito da tabela `workflow_checkpoints`.
3. **Resilient Checkpointer**: gravações e leituras usam retry com backoff e jitter. A camada resiliente funciona sobre memory, SQLite e Oracle/Autonomous Database.
4. **Checkpoint Recovery**: ao recuperar o estado, o framework varre os últimos checkpoints e retorna o mais recente válido, pulando checkpoints corrompidos.
## Configuração
No `.env`:
```env
CHECKPOINT_REPOSITORY_PROVIDER=sqlite
ENABLE_RESILIENT_CHECKPOINTER=true
ENABLE_CHECKPOINT_INTEGRITY=true
ENABLE_CHECKPOINT_COMPACTION=true
CHECKPOINT_COMPACT_EVERY=50
CHECKPOINT_KEEP_LAST=20
CHECKPOINT_RECOVERY_SCAN_LIMIT=25
CHECKPOINT_RETRY_MAX_ATTEMPTS=3
CHECKPOINT_RETRY_BASE_DELAY_SECONDS=0.05
CHECKPOINT_RETRY_MAX_DELAY_SECONDS=1.0
CHECKPOINT_RETRY_JITTER_SECONDS=0.05
```
Para produção com múltiplos pods, prefira:
```env
CHECKPOINT_REPOSITORY_PROVIDER=autonomous
ADB_USER=...
ADB_PASSWORD=...
ADB_DSN=...
ADB_WALLET_LOCATION=...
ADB_TABLE_PREFIX=AGENTFW
```
## Uso no LangGraph
```python
from agent_framework.checkpoints import create_langgraph_checkpointer
checkpointer = create_langgraph_checkpointer(settings)
graph = builder.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": session_id}}
result = graph.invoke(input_state, config=config)
```
O `thread_id` continua sendo a chave de recuperação da conversa. Em ambiente com Load Balancer, qualquer pod consegue retomar a execução se usar o mesmo repositório persistente.
## Arquivos alterados
- `agent_framework/src/agent_framework/checkpoints/checkpoint_repository.py`
- `agent_framework/src/agent_framework/checkpoints/langgraph_saver.py`
- `agent_framework/src/agent_framework/checkpoints/__init__.py`
- `agent_framework/src/agent_framework/config/settings.py`
- `tests/unit/test_resilient_checkpointer.py`
## Observação importante
O provider `memory` agora também usa o `RepositoryCheckpointSaver` quando `ENABLE_RESILIENT_CHECKPOINTER=true`. Para voltar ao `MemorySaver` puro do LangGraph em testes locais, configure:
```env
ENABLE_RESILIENT_CHECKPOINTER=false
CHECKPOINT_REPOSITORY_PROVIDER=memory
```

View File

@@ -0,0 +1,114 @@
# AI Agent Platform — Enterprise Routing Edition
Esta versão inclui o projeto completo com:
- `agent_framework`: framework reutilizável.
- `agent_template_backend`: backend FastAPI com LangGraph, OCI Generative AI, Langfuse, guardrails, judges, supervisor e roteamento enterprise.
- `agent_frontend`: frontend web independente.
- `templates/template_telecom_billing_product`: template de exemplo para telecom com agentes de Fatura e Produto.
- `templates/template_retail_orders_support`: template de exemplo para e-commerce com agentes de Pedido e Suporte.
## Roteamento enterprise
O roteamento fica em:
```text
agent_framework/src/agent_framework/routing/
```
Componentes principais:
- `models.py`: modelos `IntentDefinition`, `RouterStatePolicy`, `RouteDecision`.
- `config_loader.py`: carrega o YAML de intents e políticas.
- `enterprise_router.py`: decide o agente de destino por estado, keyword, LLM ou fallback.
O template usa:
```text
agent_template_backend/config/routing.yaml
```
## Ordem de decisão
1. Estado conversacional (`state_policies`).
2. Keywords/intents configuráveis.
3. LLM Router opcional (`ENABLE_LLM_ROUTER=true`).
4. Fallback (`router.fallback_agent`).
## Como testar roteamento sem chamar o agente final
```bash
curl -X POST http://localhost:8000/debug/route \
-H 'Content-Type: application/json' \
-d '{
"channel": "web",
"payload": {
"text": "Minha fatura veio alta",
"user_id": "u1",
"channel_id": "browser-1",
"context": {"msisdn": "5511999999999"}
}
}'
```
Resposta esperada:
```json
{
"route": "billing_agent",
"agent": "billing_agent",
"intent": "billing_invoice_explanation",
"method": "keyword"
}
```
## Como habilitar roteamento por LLM
No `.env` do backend:
```env
LLM_PROVIDER=oci_openai
OCI_GENAI_API_KEY=...
OCI_GENAI_BASE_URL=https://inference.generativeai.sa-saopaulo-1.oci.oraclecloud.com/openai/v1
OCI_GENAI_MODEL=openai.gpt-4.1
ENABLE_LLM_ROUTER=true
ROUTING_CONFIG_PATH=./config/routing.yaml
```
## Como adicionar novo agente
1. Criar classe do agente em `agent_template_backend/app/agents/`.
2. Instanciar o agente em `AgentWorkflow.__init__`.
3. Adicionar node no LangGraph.
4. Adicionar a rota no `add_conditional_edges`.
5. Criar intent no `config/routing.yaml` apontando `agent: nome_do_agente`.
## Templates incluídos
### Template 1 — Telecom
Diretório:
```text
templates/template_telecom_billing_product
```
Agentes:
- BillingAgent
- ProductAgent
### Template 2 — Retail/E-commerce
Diretório:
```text
templates/template_retail_orders_support
```
Agentes:
- OrdersAgent
- SupportAgent
Este segundo template mostra como reutilizar a mesma arquitetura para outro domínio de negócio.

View File

@@ -0,0 +1,23 @@
# Delta Implementado para Padrão FIRST
Esta versão corrige as prioridades levantadas na comparação com o FIRST:
1. Oracle Session Repository real
2. Oracle Message History real
3. Oracle LangGraph Checkpoint Repository real
4. LangGraph Deep Telemetry
5. Token Accounting
6. Cost Accounting
7. Session Lock SSE
8. Replay Buffer SSE
9. KeepAlive SSE
10. Recovery por Last-Event-ID
11. Redis Provider e Distributed Cache
12. Oracle Vector Provider
13. Oracle Graph Provider
14. RAG Telemetry
15. Langfuse Generation Tracking
16. OpenTelemetry/Event Bus compatível
17. OCI Streaming Exporter preservado
A lógica de domínio continua genérica; o framework não copia regras específicas de cobrança do FIRST.

View File

@@ -0,0 +1,45 @@
# Agent Framework FIRST Enterprise Plus
Esta versão evolui o framework nos quatro blocos solicitados:
1. **Langfuse Enterprise completo**
- `Telemetry.span()` com trace/session/user/metadata/tags.
- `Telemetry.generation()` com `usage`, token/cost metadata e compatibilidade Langfuse v2/v3.
- `Telemetry.score()` para judges/avaliações.
- Eventos arbitrários são registrados como spans seguros para evitar `Unknown observation type` no Langfuse.
2. **Token/Cost Accounting completo**
- `TokenUsageCollector` suporta `prompt_tokens`, `completion_tokens`, `cached_tokens`, `reasoning_tokens` e `total_tokens`.
- Tabela de preços por modelo via `MODEL_PRICES_JSON`.
- Conversão USD→BRL via `USD_BRL_RATE`.
- Persistência em `UsageRepository` e endpoint `/debug/usage`.
3. **Redis distribuído**
- `DistributedCache`: L1 memória + L2 Redis/SQLite/Oracle.
- `RedisCache` com `redis.asyncio` quando disponível e fallback sync.
- Namespace por `CACHE_KEY_PREFIX`.
- Telemetria de cache hit/miss/set/delete.
4. **Oracle Vector + PGQL reais**
- `OracleVectorStore` usa `VECTOR_DISTANCE(..., COSINE)` e `TO_VECTOR()` no Oracle 23ai.
- Tentativa automática de criar vector index quando suportado.
- `OracleGraphStore` usa tabelas `GRAPH_NODE` e `GRAPH_EDGE`.
- Suporte a criação de Property Graph e consulta por `GRAPH_TABLE`/PGQL, com fallback SQL.
Também foi corrigido o problema de duplicação SSE por replay + fila live usando controle de `max_replayed_id` no `SSEHub.subscribe()`.
## Testes
```bash
PYTHONPATH=agent_framework/src pytest -q tests/unit
```
Resultado validado nesta geração:
```text
17 passed
```
## Segurança
Os arquivos `.env` foram higienizados para não conter chaves reais. Configure suas credenciais localmente antes de usar OCI/Langfuse.

View File

@@ -0,0 +1,105 @@
# Ajustes operacionais finais — padrão FIRST
Esta versão corrige os gaps identificados na comparação contra o FIRST.
## Correções aplicadas
### 1. Checkpoint LangGraph operacional
O workflow não compila mais com `MemorySaver()` diretamente. Foi criado o adaptador:
```text
agent_framework/checkpoints/langgraph_saver.py
```
Ele conecta o LangGraph ao repository configurado do framework:
- `memory`
- `sqlite`
- `oracle` / `autonomous`
No workflow:
```python
builder.compile(checkpointer=create_langgraph_checkpointer(self.settings))
```
### 2. Telemetria LangGraph envolvendo a execução real
Foi adicionado wrapper de nó no workflow:
```python
self._node("billing_agent", self.billing_agent)
```
Assim o span/evento `langgraph.node.*` envolve a execução real do nó, não apenas um bloco vazio.
Eventos emitidos:
- `langgraph.node.started`
- `langgraph.node.completed`
- `langgraph.node.failed`
- `langgraph.edge.selected`
### 3. RAG integrado aos agentes
Os agentes agora recebem `RagService` e usam o contexto recuperado no prompt:
- BillingAgent
- ProductAgent
- OrdersAgent
- SupportAgent
O RAG usa:
- `VECTOR_STORE_PROVIDER=memory|sqlite|oracle|autonomous`
- `GRAPH_STORE_PROVIDER=memory|oracle|autonomous`
- `RAG_TOP_K`
### 4. Cache integrado ao runtime dos agentes
Criado mixin:
```text
agent_template_backend/app/agents/runtime.py
```
Ele adiciona:
- busca RAG padronizada;
- chave de cache para chamada LLM;
- hit/miss com telemetria;
- cache distribuído via `create_cache(settings)`.
### 5. Testes unitários
Criada pasta:
```text
tests/unit
```
Cobertura inicial:
- cache;
- SSE;
- RAG;
- checkpoint saver;
- telemetria LangGraph;
- runtime dos agentes;
- verificação estática do workflow;
- imports principais.
Validação local executada:
```text
12 passed
```
## Como testar
```bash
cd projeto_agent_framework_first_ready
pip install -r agent_template_backend/requirements.txt
pytest -q tests/unit
```

View File

@@ -0,0 +1,379 @@
# Projeto Agent Framework FIRST-ready
Esta versão mantém a arquitetura do `meu_projeto_agent_framework` e adiciona os padrões operacionais encontrados no projeto FIRST.
## Recursos adicionados
1. **SSE no padrão FIRST**
- `GET /gateway/events/{session_id}` para stream `text/event-stream`.
- `POST /gateway/message/sse` para processar mensagem emitindo eventos SSE.
- Eventos: `connected`, `flow.start`, `session.upserted`, `message.received`, `workflow.started`, `workflow.completed`, `message.responded`, `flow.end`.
- Keepalive configurável por `SSE_KEEPALIVE_SECONDS`.
- Lock por sessão para evitar concorrência dentro da mesma conversa.
- Replay de eventos via `Last-Event-ID` ou query param `last_event_id`.
2. **Persistência de sessão e mensagens**
- Implementado provider `sqlite`, executável localmente.
- `SESSION_REPOSITORY_PROVIDER=sqlite`.
- `MEMORY_REPOSITORY_PROVIDER=sqlite`.
- Tabelas locais: `agent_sessions`, `agent_messages`.
- Idempotência por `message_id`.
3. **Checkpoint persistente**
- Implementado provider `sqlite` para checkpoint final do workflow.
- `CHECKPOINT_REPOSITORY_PROVIDER=sqlite`.
- Endpoint de leitura: `GET /sessions/{session_id}/checkpoint`.
4. **Histórico de mensagens**
- Endpoint: `GET /sessions/{session_id}/messages`.
- Histórico usado como memória conversacional antes de chamar o LangGraph.
5. **Cache**
- Novo módulo `agent_framework.cache.cache`.
- Suporta cache local em memória e Redis se `ENABLE_REDIS_CACHE=true`.
6. **RAG / Vector Store**
- `agent_framework.rag.vector_store` agora possui `InMemoryVectorStore`, `SQLiteVectorStore` e contrato `AutonomousVectorStore`.
- A versão SQLite usa busca lexical local para desenvolvimento.
- O contrato permite trocar por Oracle Vector Search sem alterar a camada de aplicação.
7. **Observabilidade**
- Mantém Langfuse existente.
- Acrescenta eventos de gateway/SSE/workflow com `session_id`, `agent_id`, `tenant_id`, `message_id`, rota e intenção.
## Arquitetura resultante
```text
Browser
|-- POST /gateway/message/sse
|-- GET /gateway/events/{session_id}
|
FastAPI Template Backend
|
ChannelGateway
|
SessionRepository + MessageHistory + CheckpointRepository
|
LangGraph AgentWorkflow
|
Guardrails -> Router/Supervisor -> Agent -> Output Guardrails -> Judges
|
Telemetry / Langfuse / OCI Streaming
```
## Como rodar localmente
```bash
cd agent_template_backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -e ../agent_framework
uvicorn app.main:app --host 0.0.0.0 --port 8000
```
Frontend:
```bash
cd agent_frontend
python -m http.server 3000
```
Abra:
```text
http://localhost:3000
```
## Variáveis principais
```env
SESSION_REPOSITORY_PROVIDER=sqlite
MEMORY_REPOSITORY_PROVIDER=sqlite
CHECKPOINT_REPOSITORY_PROVIDER=sqlite
VECTOR_STORE_PROVIDER=sqlite
SQLITE_DB_PATH=./data/agent_framework.db
ENABLE_SSE=true
SSE_KEEPALIVE_SECONDS=15
ENABLE_MESSAGE_IDEMPOTENCY=true
```
## Teste via curl
Mensagem normal:
```bash
curl -X POST http://localhost:8000/gateway/message \
-H 'Content-Type: application/json' \
-d '{"channel":"web","payload":{"text":"teste","message":"teste","session_id":"s1","user_id":"u1","message_id":"m1"}}'
```
Mensagem com SSE:
```bash
curl -N http://localhost:8000/gateway/events/s1
```
Em outro terminal:
```bash
curl -X POST http://localhost:8000/gateway/message/sse \
-H 'Content-Type: application/json' \
-d '{"channel":"web","payload":{"text":"teste","message":"teste","session_id":"s1","user_id":"u1","message_id":"m2"}}'
```
Histórico:
```bash
curl http://localhost:8000/sessions/s1/messages
```
Checkpoint:
```bash
curl http://localhost:8000/sessions/s1/checkpoint
```
## Observação importante
A versão adicionada é executável localmente com SQLite. As classes `AutonomousSessionRepository`, `DatabaseMessageHistory`, `AutonomousCheckpointRepository` e `AutonomousVectorStore` mantêm o contrato para Oracle Autonomous Database, mas nesta entrega usam SQLite como backend local para permitir rodar e testar sem infraestrutura Oracle.
## Evolução de Observabilidade no padrão FIRST
Esta versão adiciona uma camada corporativa de observabilidade ao framework, mantendo os componentes reutilizáveis dentro de `agent_framework`.
### Componentes adicionados
```text
agent_framework/observability/
├── context.py # ContextVar: request_id, session_id, user_id, tenant_id, agent_id, channel, ura_call_id, workflow_id, message_id
├── telemetry.py # Facade central: span, event, generation, rag_event, cache_event, checkpoint_event
├── event_bus.py # Event bus interno para plugar logs, SSE, OCI Streaming, Elastic, Phoenix etc.
├── otel.py # OpenTelemetry opcional via OTLP
├── workflow_events.py # workflow.started, node.started, node.completed, edge.selected, workflow.failed
├── guardrail_events.py # guardrail.<CODE>.evaluated e guardrail.<CODE>.blocked
├── judge_events.py # judge.<NAME>.evaluated
├── streaming_events.py # sse.connected, sse.keepalive, sse.event.emitted
└── decorators.py # decorator @traced para classes do framework
```
### Correlação ponta-a-ponta
Cada chamada HTTP cria ou propaga `x-request-id` e o fluxo de mensagem vincula:
```text
request_id → tenant_id → agent_id → session_id → user_id → channel → message_id → workflow_id
```
O contexto usa `ContextVar`, portanto funciona em chamadas assíncronas, FastAPI, LangGraph e providers LLM.
### Langfuse
Ative no `.env`:
```env
ENABLE_LANGFUSE=true
LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=http://localhost:3000
```
O framework registra:
```text
Trace de conversa
├── http.request
├── agent.gateway_message
├── workflow.langgraph.ainvoke
├── workflow.input_guardrails
│ └── guardrail.<CODE>.evaluated / blocked
├── workflow.routing_decision
├── workflow.agent.<agent>
│ └── generation.<model>
├── workflow.output_guardrails
├── workflow.judge
│ └── judge.<NAME>.evaluated
├── workflow.supervisor_review
├── workflow.persist
└── sse.event.emitted / sse.keepalive
```
### OpenTelemetry
Ative no `.env`:
```env
ENABLE_OTEL=true
OTEL_SERVICE_NAME=agent-framework-template
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318/v1/traces
```
Com isso, os mesmos spans são exportados via OTLP para Elastic, Grafana Tempo, Jaeger, Collector ou outro backend compatível.
### SSE observável
O `SSEHub` agora registra eventos de:
- conexão aberta;
- replay de eventos;
- evento emitido;
- keepalive;
- lock por sessão no processamento de mensagem.
### Guardrails e Judges
Além dos eventos agregados (`guardrails.input.completed`, `judges.completed`), cada decisão individual gera telemetria própria:
```text
guardrail.MSK.evaluated
guardrail.OOS.blocked
judge.response_quality.evaluated
judge.groundedness.evaluated
```
### Extensão para outros backends
A classe `Telemetry.event_bus` permite plugar novos handlers sem alterar o workflow. Exemplo:
```python
async def enviar_para_elastic(event):
...
telemetry.event_bus.subscribe(enviar_para_elastic)
```
---
## Evolução FIRST Enterprise Completa
Esta versão recebeu os componentes que faltavam para aproximar o framework do padrão operacional do projeto FIRST:
### Persistência Oracle Autonomous Database
Foram adicionados providers reais Oracle:
- `OracleSessionRepository`
- `OracleMessageHistory`
- `OracleCheckpointRepository`
- `OracleCache`
- `OracleVectorStore`
- `OracleGraphStore`
- `OracleStore`
Tabelas criadas automaticamente com prefixo configurável `ADB_TABLE_PREFIX`:
- `<PREFIX>_AGENT_SESSION`
- `<PREFIX>_AGENT_MESSAGE`
- `<PREFIX>_WORKFLOW_CHECKPOINT`
- `<PREFIX>_WORKFLOW_CHECKPOINT_WRITE`
- `<PREFIX>_WORKFLOW_CHECKPOINT_BLOB`
- `<PREFIX>_SSE_EVENT`
- `<PREFIX>_CACHE_ENTRY`
- `<PREFIX>_RAG_DOCUMENT`
- `<PREFIX>_GRAPH_EDGE`
### Configuração Oracle
```env
SESSION_REPOSITORY_PROVIDER=oracle
MEMORY_REPOSITORY_PROVIDER=oracle
CHECKPOINT_REPOSITORY_PROVIDER=oracle
CACHE_BACKEND_PROVIDER=oracle
VECTOR_STORE_PROVIDER=oracle
GRAPH_STORE_PROVIDER=oracle
SSE_STORE_PROVIDER=oracle
ADB_USER=ADMIN
ADB_PASSWORD=***
ADB_DSN=meu_adb_high
ADB_WALLET_LOCATION=/path/wallet
ADB_WALLET_PASSWORD=***
ADB_TABLE_PREFIX=AGENTFW
```
### SSE Enterprise
O SSE agora possui:
- lock por sessão (`SessionLockManager`)
- keepalive configurável
- replay por `Last-Event-ID`
- persistência de eventos em SQLite ou Oracle
- telemetria de conexão, replay, keepalive e desconexão
Endpoint:
```text
GET /gateway/events/{session_id}?last_event_id=123
```
### LangGraph Deep Telemetry
Foi adicionado `LangGraphDeepTelemetry` com eventos:
- `langgraph.node.started`
- `langgraph.node.completed`
- `langgraph.node.failed`
- `langgraph.edge.selected`
Esses eventos são enviados para o Event Bus, Langfuse e OpenTelemetry quando habilitados.
### Token e Cost Accounting
Foi adicionado:
- `TokenUsageCollector`
- `CostTracker`
- cálculo de `prompt_tokens`, `completion_tokens`, `cached_tokens`, `total_tokens`
- cálculo de `cost_usd` e `cost_brl`
Configuração opcional:
```env
USD_BRL_RATE=5.0
MODEL_PRICES_JSON={"openai.gpt-4.1":{"input_per_1m":"2.00","output_per_1m":"8.00"}}
```
### Cache Enterprise
O cache agora é em cascata:
```text
L1: InMemory
L2: Redis, SQLite ou Oracle
```
Configuração:
```env
ENABLE_REDIS_CACHE=true
REDIS_URL=redis://localhost:6379/0
```
ou:
```env
CACHE_BACKEND_PROVIDER=oracle
```
### RAG Oracle 23ai
Foi adicionado `OracleVectorStore`, com suporte a coluna `VECTOR` e `VECTOR_DISTANCE()` quando um embedding provider for conectado.
Sem embedding provider, mantém fallback lexical para desenvolvimento local.
Também foi adicionado `OracleGraphStore` com tabela de arestas, pronto para evoluir para PGQL/Property Graph.
### Langfuse
Cada chamada LLM agora gera `generation` com:
- input
- output
- model
- provider
- token usage
- cost metadata
Além disso, spans de workflow, guardrails, judges, RAG, cache, checkpoint, SSE e LangGraph são publicados pelo mesmo Event Bus.

View File

@@ -0,0 +1,62 @@
# Guardrails implementados no framework
Esta versão adiciona uma camada pragmática de guardrails ao `agent_framework`, inspirada na separação de rails por estágio: input, output, retrieval e execução/tool.
## Rails de input
- `MSIZE` — bloqueia mensagens excessivamente grandes.
- `MSK` — mascara CPF, CNPJ, telefone, e-mail, cartão, CEP, RG, tokens e chaves.
- `TOX` — detecta toxicidade e registra severidade sem bloquear por padrão.
- `PINJ` — detecta prompt injection e registra score.
- `JBRK` — detecta jailbreak/roleplay de burla e registra score.
- `VLOOP` — bloqueia loop conversacional repetitivo.
## Rails de output
- `PII_OUT` — mascara PII na resposta do agente.
- `CMP` — suaviza promessas absolutas e linguagem de garantia excessiva.
- `REVPREC` — bloqueia verbalização de ação operacional sem confirmação de tool.
- `GND` — sinaliza groundedness/risco quando há resposta específica sem evidência.
- `ALUC_RISK` — marca risco de alucinação para telemetria e judges.
## Rails opcionais
- `RET_REL` — valida relevância de chunks de retrieval por score mínimo.
- `TOOL_VAL` — valida ferramenta MCP/tool, argumentos obrigatórios, valores negativos e allowlist.
## Arquivos alterados
- `agent_framework/src/agent_framework/guardrails/rails.py`
- `agent_framework/src/agent_framework/guardrails/pipeline.py`
- `agent_framework/src/agent_framework/guardrails/__init__.py`
## Uso rápido
```python
from agent_framework.guardrails.pipeline import GuardrailPipeline
pipeline = GuardrailPipeline()
sanitized_input, input_decisions = await pipeline.run_input(
user_text,
{"history_texts": history_texts},
)
final_answer, output_decisions = await pipeline.run_output(
answer,
context,
)
```
Para tools/MCP:
```python
_, decisions = await pipeline.run_tool(
"cancelar_produto",
{"produto": "VAS", "valor": 0},
{
"required_args": ["produto"],
"allowed_tools": ["cancelar_produto", "consultar_fatura"],
},
)
```

View File

@@ -0,0 +1,139 @@
# Projeto Agent Framework — FIRST Operational Max
Esta versão adiciona os ajustes operacionais que faltavam para aproximar o framework do padrão FIRST em produção.
## Ajustes incluídos nesta versão
### 1. Langfuse Enterprise Adapter
Novo módulo:
```text
agent_framework/observability/langfuse_enterprise.py
```
Inclui adaptador compatível com SDKs Langfuse v2/v3 para:
- atualização de trace;
- score/avaliação de trace;
- prompt registry quando suportado pelo SDK;
- isolamento das diferenças de API do Langfuse.
### 2. Token e Cost Accounting persistente
Novo pacote:
```text
agent_framework/billing/
```
Inclui:
- `UsageRecord`
- `SQLiteUsageRepository`
- `OracleUsageRepository`
- `create_usage_repository(settings)`
O provider LLM agora registra automaticamente:
- `prompt_tokens`
- `completion_tokens`
- `cached_tokens`
- `total_tokens`
- `cost_usd`
- `cost_brl`
- `tenant_id`
- `agent_id`
- `session_id`
- `message_id`
Novo endpoint:
```http
GET /debug/usage
GET /debug/usage?tenant_id=default
GET /debug/usage?session_id=<id>
```
### 3. RAG Service operacional
Novo módulo:
```text
agent_framework/rag/rag_service.py
```
Inclui:
- `RagService.add_documents()`
- `RagService.retrieve()`
- `RagResult.as_prompt_context()`
- telemetria de latência, quantidade de documentos, top scores e grafo.
### 4. Configuração nova
Variável adicionada:
```env
USAGE_REPOSITORY_PROVIDER=sqlite
```
Valores:
```text
sqlite
oracle
autonomous
```
### 5. Compatibilidade operacional local
Por padrão, a contabilização de uso usa SQLite mesmo que o restante esteja em memória. Assim é possível testar localmente sem Oracle.
## Teste rápido
```bash
cd agent_template_backend
uvicorn app.main:app --host 0.0.0.0 --port 8000
```
Teste uma mensagem:
```bash
curl -X POST http://localhost:8000/gateway/message \
-H 'Content-Type: application/json' \
-d '{"channel":"web","payload":{"text":"teste","user_id":"u1","session_id":"s1"}}'
```
Verifique uso/custo:
```bash
curl http://localhost:8000/debug/usage
```
## Para rodar com padrão mais próximo de produção
```env
SESSION_REPOSITORY_PROVIDER=sqlite
MEMORY_REPOSITORY_PROVIDER=sqlite
CHECKPOINT_REPOSITORY_PROVIDER=sqlite
USAGE_REPOSITORY_PROVIDER=sqlite
CACHE_BACKEND_PROVIDER=sqlite
VECTOR_STORE_PROVIDER=sqlite
ENABLE_LANGFUSE=true
LANGFUSE_HOST=http://localhost:3000
LANGFUSE_PUBLIC_KEY=...
LANGFUSE_SECRET_KEY=...
```
Para Autonomous Database:
```env
SESSION_REPOSITORY_PROVIDER=oracle
MEMORY_REPOSITORY_PROVIDER=oracle
CHECKPOINT_REPOSITORY_PROVIDER=oracle
USAGE_REPOSITORY_PROVIDER=oracle
CACHE_BACKEND_PROVIDER=oracle
VECTOR_STORE_PROVIDER=oracle
GRAPH_STORE_PROVIDER=oracle
ADB_USER=...
ADB_PASSWORD=...
ADB_DSN=...
ADB_WALLET_LOCATION=...
ADB_TABLE_PREFIX=AGENTFW
```

View File

@@ -0,0 +1,79 @@
# AI Agent Platform com MCP Tools
Esta versão adiciona uma camada MCP ao framework:
- `agent_framework.mcp.MCPToolRouter`
- `agent_template_backend/config/mcp_servers.yaml`
- `agent_template_backend/config/tools.yaml`
- `mcp_servers/telecom_mcp_server`
- `mcp_servers/retail_mcp_server`
## Subir localmente
Terminal 1:
```bash
bash ./scripts/run_mcp_servers.sh
```
Terminal 2:
```bash
cd agent_template_backend
python -m venv .venv
source .venv/bin/activate
pip install -e ../agent_framework
pip install -r requirements.txt
uvicorn app.main:app --reload --reload-dir app --reload-dir config --port 8000
```
Terminal 3:
```bash
cd agent_frontend
python -m http.server 5173
```
## Testes rápidos
Listar tools MCP carregadas pelo backend:
```bash
curl http://localhost:8000/debug/mcp/tools
```
Chamar tool diretamente via backend:
```bash
curl -X POST http://localhost:8000/debug/mcp/call/consultar_fatura \
-H 'Content-Type: application/json' \
-d '{"msisdn":"11999999999","invoice_id":"INV-001"}'
```
Roteamento Telecom + MCP:
```bash
curl -X POST http://localhost:8000/gateway/message \
-H 'Content-Type: application/json' \
-d '{"channel":"web","payload":{"session_id":"sess-tel-1","message":"Minha fatura veio alta","context":{"msisdn":"11999999999","invoice_id":"INV-001"}}}'
```
Roteamento Retail + MCP:
```bash
curl -X POST http://localhost:8000/gateway/message \
-H 'Content-Type: application/json' \
-d '{"channel":"web","payload":{"session_id":"sess-ret-1","message":"Meu pedido não chegou","context":{"order_id":"PED-1001","customer_id":"C-001"}}}'
```
## Docker Compose
```bash
docker compose up --build
```
No compose, o backend usa `config/mcp_servers.docker.yaml` para apontar para `telecom-mcp` e `retail-mcp`.
## Operações read-only e transacionais
Use `config/tool_policies.yaml` no backend para classificar somente as operações que precisam de tratamento adicional. A validação é aplicada no roteador central antes do MCP Gateway/Server. O arquivo é opcional e templates antigos continuam usando as políticas já presentes em `tools.yaml`. A configuração completa e o roteiro de migração estão em [README_TOOL_POLICIES.md](README_TOOL_POLICIES.md).

View File

@@ -0,0 +1,108 @@
# Multi-agent isolation
Esta versão permite subir mais de um `agent_template` no mesmo backend e chavear por `agent_id` sem misturar estado.
## O que ficou isolado
A chave lógica usada pelo backend é:
```text
tenant_id:agent_id:session_id
```
Com isso ficam isolados:
- memória conversacional;
- checkpoints do LangGraph (`thread_id`);
- telemetria/tags;
- prompts por perfil de agente;
- configuração de guardrails por agente;
- configuração de judges por agente;
- metadados de sessão.
## Arquivo principal
```text
agent_template_backend/config/agents.yaml
```
Exemplo:
```yaml
default_agent_id: telecom_contas
agents:
- agent_id: telecom_contas
prompt_policy_path: ./config/agents/telecom_contas/prompt_policy.yaml
guardrails_config_path: ./config/agents/telecom_contas/guardrails.yaml
judges_config_path: ./config/agents/telecom_contas/judges.yaml
- agent_id: retail_orders
prompt_policy_path: ./config/agents/retail_orders/prompt_policy.yaml
guardrails_config_path: ./config/agents/retail_orders/guardrails.yaml
judges_config_path: ./config/agents/retail_orders/judges.yaml
```
## Como escolher o agente na chamada
### Telecom
```bash
curl -X POST http://localhost:8000/gateway/message \
-H 'Content-Type: application/json' \
-d '{
"channel": "web",
"agent_id": "telecom_contas",
"tenant_id": "tim",
"payload": {
"session_id": "sessao-123",
"user_id": "cliente-1",
"message": "Quero entender minha fatura",
"context": {"invoice_id": "FAT-001"}
}
}'
```
### Retail
```bash
curl -X POST http://localhost:8000/gateway/message \
-H 'Content-Type: application/json' \
-d '{
"channel": "web",
"agent_id": "retail_orders",
"tenant_id": "loja",
"payload": {
"session_id": "sessao-123",
"user_id": "cliente-1",
"message": "Onde está meu pedido?",
"context": {"order_id": "PED-001"}
}
}'
```
Mesmo usando o mesmo `session_id`, as conversas ficam separadas porque as chaves finais serão:
```text
tim:telecom_contas:sessao-123
loja:retail_orders:sessao-123
```
## Endpoints úteis
```text
GET /agents
GET /health
POST /debug/route
POST /gateway/message
```
## Como adicionar um novo agent_template
1. Crie uma pasta em `agent_template_backend/config/agents/<novo_agent_id>/`.
2. Adicione `prompt_policy.yaml`, `guardrails.yaml` e `judges.yaml`.
3. Registre o agente em `config/agents.yaml`.
4. Chame `/gateway/message` usando `agent_id=<novo_agent_id>`.
## Observação arquitetural
O backend continua usando um único processo FastAPI e um único framework instalado, mas o estado persistido não usa mais `session_id` sozinho. Isso evita que dois agentes compartilhem memória, checkpoints ou decisões de governança acidentalmente.

View File

@@ -0,0 +1,244 @@
# Route Stickiness Semântica e Controle Global de Sessão no Agent Framework OCI
## Objetivo
A route stickiness semântica evita executar novamente o Enterprise Router quando uma nova mensagem continua claramente sob responsabilidade do agente ativo. A implementação usa um perfil LLM leve e não contém regexes, listas de frases, palavras específicas de idioma ou regras conversacionais por domínio.
A funcionalidade é opcional e preserva integralmente o comportamento anterior quando desabilitada, quando não existe agente ativo, quando a confiança é baixa ou quando ocorre erro na inferência.
## Decisão arquitetural
O classificador possui uma responsabilidade transversal e restrita:
- `CONTINUE`: a mensagem continua com o agente ativo;
- `ROUTE`: a mensagem deve seguir para o Enterprise Router normal;
- `HUMAN_HANDOFF`: o usuário solicitou atendimento humano;
- `END_SESSION`: o usuário solicitou ou confirmou o encerramento do atendimento.
Ele não responde ao usuário, não escolhe outro agente, não executa ferramentas e não interpreta regras de negócio. As duas ações globais são encaminhadas para nós próprios do grafo, evitando que cada agente implemente prompts ou regras de sessão.
Fluxo:
```text
Todos os turnos com a funcionalidade habilitada
-> classificador semântico leve
CONTINUE + agente ativo -> agente ativo
ROUTE/baixa confiança/erro -> Enterprise Router
HUMAN_HANDOFF -> nó global human_handoff
END_SESSION -> nó global end_session
No primeiro turno, CONTINUE é normalizado para ROUTE porque ainda não existe agente ativo. Handoff e encerramento podem ser reconhecidos mesmo no primeiro turno.
```
## Por que não há regras determinísticas
A interpretação de linguagem natural por regex exige manutenção contínua para novas construções, idiomas e domínios. Além disso, transfere aos times dos agentes a responsabilidade de manter flags e padrões de continuidade.
Esta implementação mantém no código apenas decisões técnicas inevitáveis:
- funcionalidade habilitada ou desabilitada;
- validação de que `CONTINUE` exige agente ativo;
- threshold de confiança;
- fallback em timeout, erro ou JSON inválido.
Não existem `DEFAULT_FOLLOWUP_PATTERNS`, regras de repetição, listas de pronomes ou keywords de continuidade.
## Configuração
### `.env`
```dotenv
ENABLE_ROUTE_STICKINESS=true
ROUTE_STICKINESS_LLM_PROFILE=route_continuity
ROUTE_STICKINESS_CONFIDENCE_THRESHOLD=0.90
ROUTE_STICKINESS_HISTORY_TURNS=2
ROUTE_STICKINESS_MAX_TOKENS=80
HUMAN_HANDOFF_MESSAGE=Vou encaminhar seu atendimento para uma pessoa.
END_SESSION_MESSAGE=Atendimento encerrado. Obrigado pelo contato.
```
- `ENABLE_ROUTE_STICKINESS`: ativa a capacidade.
- `ROUTE_STICKINESS_LLM_PROFILE`: perfil existente em `llm_profiles.yaml`.
- `ROUTE_STICKINESS_CONFIDENCE_THRESHOLD`: confiança mínima para bypass.
- `ROUTE_STICKINESS_HISTORY_TURNS`: quantidade de turnos recentes enviados ao classificador.
- `ROUTE_STICKINESS_MAX_TOKENS`: limite de saída do classificador.
- `HUMAN_HANDOFF_MESSAGE`: mensagem devolvida pelo nó global de transferência humana.
- `END_SESSION_MESSAGE`: mensagem devolvida pelo nó global de encerramento.
### Perfil leve
```yaml
profiles:
route_continuity:
provider: oci_openai
model: openai.gpt-4.1-mini
temperature: 0
max_tokens: 80
timeout_seconds: 5
```
O modelo acima é apenas um exemplo. Deve ser substituído pelo menor modelo aprovado e disponível no ambiente OCI. O framework reutiliza o mecanismo já existente de `LLM_PROFILES_PATH`; não há uma segunda configuração de provider/model específica para a funcionalidade.
## Contexto enviado ao modelo
O classificador recebe somente:
- agente ativo;
- descrições das capacidades dos agentes derivadas das intents já existentes;
- intent e domínio anteriores;
- histórico recente limitado;
- mensagem atual.
Não são enviados RAG completo, resultados MCP integrais, prompt do agente ou regras de negócio.
## Exemplos
### Continuidade
```text
Usuário: Qual é o meu plano?
Agente: Seu plano é Controle 50GB.
Usuário: O que está incluso?
```
Resultado esperado:
```json
{
"method": "continuity",
"route": "product_agent",
"route_bypassed": true
}
```
### Mudança de domínio
```text
Usuário: Qual é o meu plano?
Agente: Seu plano é Controle 50GB.
Usuário: Agora quero contestar uma cobrança.
```
O classificador retorna `ROUTE` e o Enterprise Router seleciona o agente apropriado.
### Baixa confiança ou falha
Qualquer resultado abaixo do threshold, timeout ou JSON inválido executa o Enterprise Router. A funcionalidade é fail-safe e nunca força continuidade em caso de dúvida.
## Telemetria
Evento `router.continuity`:
```json
{
"decision": "CONTINUE",
"confidence": 0.97,
"active_agent": "product_agent",
"route_bypassed": true,
"profile_name": "route_continuity"
}
```
Quando ocorre bypass, `route_decision.method` é `continuity` e o estado final contém:
- `active_agent`;
- `route_bypassed`;
- `continuity_signal`.
## Testes
```bash
pytest -q tests/unit/test_semantic_route_stickiness.py
```
Os testes validam:
- continuidade com bypass;
- mudança de assunto com fallback para o router;
- baixa confiança;
- saída inválida;
- primeiro turno sem chamada ao classificador.
## Benchmark recomendado
Executar a mesma conversação com a funcionalidade desabilitada e habilitada, registrando por turno:
- `route_bypassed`;
- `route_decision.method`;
- latência do `llm.route_continuity`;
- chamadas ao `llm.router`;
- tokens por perfil;
- latência total p50, p95 e p99.
A redução de tempo total somente deve ser atribuída à stickiness quando houver `route_bypassed=true` e ausência da geração `llm.router` no mesmo turno.
## Contratos globais
### Human handoff
Quando a decisão for `HUMAN_HANDOFF`, o router retorna:
```json
{
"route": "human_handoff",
"intent": "human_handoff",
"method": "continuity",
"handoff": true,
"metadata": {
"session_control": "HUMAN_HANDOFF",
"route_bypassed": true
}
}
```
O nó `human_handoff` produz os campos:
- `session_control=HUMAN_HANDOFF`;
- `human_handoff_requested=true`;
- `session_ended=false`;
- `next_state=HUMAN_HANDOFF_REQUESTED`.
O evento `session.human_handoff.requested` é emitido para que o Channel Gateway ou a integração do cliente encaminhe a conversa à plataforma humana. O framework não presume uma fila, fornecedor ou protocolo específico.
### Encerramento
Quando a decisão for `END_SESSION`, o router retorna:
```json
{
"route": "end_session",
"intent": "end_session",
"method": "continuity",
"metadata": {
"session_control": "END_SESSION",
"route_bypassed": true
}
}
```
O nó `end_session` produz:
- `session_control=END_SESSION`;
- `session_ended=true`;
- `human_handoff_requested=false`;
- `next_state=SESSION_ENDED`.
O evento `session.end.requested` é emitido antes da persistência. O backend continua responsável por aplicar a política concreta de expiração, fechamento ou limpeza da sessão em cada canal.
## Exemplos
| Mensagem | Contexto | Decisão esperada | Destino |
|---|---|---|---|
| `o que está incluso?` | `product_agent` ativo | `CONTINUE` | `product_agent` |
| `agora quero contestar uma cobrança` | `product_agent` ativo | `ROUTE` | Enterprise Router |
| `quero falar com uma pessoa` | com ou sem agente ativo | `HUMAN_HANDOFF` | nó `human_handoff` |
| `obrigado, pode encerrar` | com ou sem agente ativo | `END_SESSION` | nó `end_session` |
## Segurança e fallback
- Somente decisões acima do threshold são aceitas.
- `CONTINUE` sem agente ativo vira `ROUTE`.
- JSON inválido, timeout ou erro usa o Enterprise Router.
- Handoff e encerramento não executam agentes de domínio nem ferramentas MCP.
- O classificador não encerra fisicamente conexões nem seleciona filas humanas; ele emite um contrato global para integração.

View File

@@ -0,0 +1,281 @@
# Modos de roteamento multi-agent: Enterprise Router e Supervisor
Este projeto suporta dois desenhos arquiteturais para roteamento entre agentes, sem precisar criar dois frameworks diferentes.
## Modos disponíveis
Configure por variável de ambiente:
```bash
ROUTING_MODE=router
```
ou:
```bash
ROUTING_MODE=supervisor
```
Também existe a chave documental em `agent_template_backend/config/routing.yaml`:
```yaml
router:
mode: router
```
A variável de ambiente `ROUTING_MODE` é a forma recomendada para ativar um modo em runtime, especialmente em Docker, Kubernetes ou OCI.
---
## Opção 1: Enterprise Router
Fluxo:
```text
Usuário
-> Input Guardrails
-> EnterpriseRouter
-> AgentRegistry
-> 1 agente especialista
-> Output Guardrails
-> Judges
-> Supervisor Review
-> Persistência/eventos
```
Uso recomendado quando cada mensagem deve ser atendida por um único agente especialista.
Exemplos:
- `Minha fatura veio alta` -> `billing_agent`
- `Onde está meu pedido?` -> `orders_agent`
- `Quero trocar um produto com defeito` -> `support_agent`
Vantagens:
- Menor latência.
- Menor custo de tokens.
- Debug mais simples.
- Mais fácil de operar em produção.
Limitação:
- Uma mensagem com múltiplos assuntos precisa ser roteada para um agente principal ou tratada por handoff.
---
## Opção 2: Supervisor
Fluxo:
```text
Usuário
-> Input Guardrails
-> Supervisor.route_plan
-> supervisor_agent
-> billing_agent opcional
-> orders_agent opcional
-> product_agent opcional
-> support_agent opcional
-> Consolidação
-> Output Guardrails
-> Judges
-> Supervisor Review
-> Persistência/eventos
```
Uso recomendado quando uma única mensagem pode envolver vários agentes.
Exemplo:
```text
Meu pedido não chegou e também fui cobrado duas vezes.
```
Neste caso, o supervisor pode acionar:
- `orders_agent`
- `billing_agent`
Vantagens:
- Suporta múltiplas intenções na mesma mensagem.
- Permite consolidação de respostas.
- Facilita cenários enterprise com vários domínios.
Custos:
- Maior latência.
- Maior consumo de tokens.
- Mais complexidade operacional.
---
## O que foi alterado no código
### 1. Configuração
Arquivo:
```text
agent_framework/src/agent_framework/config/settings.py
```
Foi adicionada a configuração:
```python
ROUTING_MODE: Literal['router','supervisor'] = 'router'
```
### 2. Workflow LangGraph
Arquivo:
```text
agent_template_backend/app/workflows/agent_graph.py
```
O nó `enterprise_route` foi substituído por um nó genérico:
```text
routing_decision
```
Esse nó decide o caminho com base em `ROUTING_MODE`:
- `router` usa `EnterpriseRouter`.
- `supervisor` usa `Supervisor.route_plan`.
Também foi adicionado o nó:
```text
supervisor_agent
```
Ele executa um ou mais agentes e consolida o resultado.
### 3. Supervisor
Arquivo:
```text
agent_framework/src/agent_framework/supervisor/supervisor.py
```
Foi adicionada a estrutura:
```python
SupervisorPlan
```
E o método:
```python
route_plan(state)
```
Esse método retorna uma lista de agentes a executar.
### 4. Debug
Endpoint:
```text
POST /debug/route
```
Agora respeita `ROUTING_MODE` e permite verificar rapidamente como uma mensagem será roteada.
---
## Como testar localmente
### Instalação
```bash
cd agent_template_backend
python -m venv .venv
source .venv/bin/activate
pip install -U pip setuptools wheel
pip install -e ../agent_framework
pip install -r requirements.txt
```
### Modo Router
```bash
export ROUTING_MODE=router
uvicorn app.main:app --reload --port 8000
```
Teste:
```bash
curl -X POST http://localhost:8000/debug/route \
-H 'Content-Type: application/json' \
-d '{"channel":"web","payload":{"text":"Onde está meu pedido?","session_id":"s1"}}'
```
Resultado esperado:
```json
{
"mode": "router",
"route": "orders_agent"
}
```
### Modo Supervisor
```bash
export ROUTING_MODE=supervisor
uvicorn app.main:app --reload --port 8000
```
Teste:
```bash
curl -X POST http://localhost:8000/debug/route \
-H 'Content-Type: application/json' \
-d '{"channel":"web","payload":{"text":"Meu pedido atrasou e minha fatura veio duplicada","session_id":"s2"}}'
```
Resultado esperado:
```json
{
"mode": "supervisor",
"route": "supervisor_agent",
"agents": ["billing_agent", "orders_agent"]
}
```
---
## Isolamento
A chave lógica de isolamento permanece:
```text
tenant_id:agent_id:session_id
```
Use essa chave para memória, sessão, checkpoint e telemetria. Em produção, recomenda-se padronizar `agent_id` por agente especialista ou por template, dependendo do nível de isolamento desejado.
---
## Recomendação
Comece em produção com:
```bash
ROUTING_MODE=router
```
Ative:
```bash
ROUTING_MODE=supervisor
```
quando houver necessidade real de múltiplos agentes na mesma mensagem.

View File

@@ -0,0 +1,86 @@
# Semantic Route Stickiness and Global Session Control in Agent Framework OCI
## Purpose
This optional capability uses a lightweight LLM profile and no regex, phrase lists, or domain-specific language rules. It classifies each turn as:
- `CONTINUE`: keep the active agent;
- `ROUTE`: run the regular Enterprise Router;
- `HUMAN_HANDOFF`: request human assistance;
- `END_SESSION`: finish the automated session.
The classifier does not answer the user, execute tools, or implement domain rules. Human handoff and session ending are handled by global graph nodes.
## Flow
```text
Incoming turn
-> lightweight semantic classifier
CONTINUE + active agent -> active agent
ROUTE / low confidence / error -> Enterprise Router
HUMAN_HANDOFF -> human_handoff node
END_SESSION -> end_session node
```
`CONTINUE` is converted to `ROUTE` when there is no active agent. Global session actions can be detected on the first turn.
## Configuration
```dotenv
ENABLE_ROUTE_STICKINESS=true
ROUTE_STICKINESS_LLM_PROFILE=route_continuity
ROUTE_STICKINESS_CONFIDENCE_THRESHOLD=0.90
ROUTE_STICKINESS_HISTORY_TURNS=2
ROUTE_STICKINESS_MAX_TOKENS=80
HUMAN_HANDOFF_MESSAGE=I will transfer your request to a person.
END_SESSION_MESSAGE=The session has ended. Thank you for contacting us.
```
```yaml
profiles:
route_continuity:
provider: oci_openai
model: openai.gpt-4.1-mini
temperature: 0
max_tokens: 80
timeout_seconds: 5
```
Use the smallest approved model available in the target OCI environment.
## Human handoff contract
The router returns route `human_handoff`, intent `human_handoff`, `handoff=true`, and metadata `session_control=HUMAN_HANDOFF`. The graph node sets:
- `human_handoff_requested=true`;
- `session_ended=false`;
- `next_state=HUMAN_HANDOFF_REQUESTED`.
It emits `session.human_handoff.requested`. The customer integration remains responsible for choosing the human queue and protocol.
## End-session contract
The router returns route `end_session`, intent `end_session`, and metadata `session_control=END_SESSION`. The graph node sets:
- `session_ended=true`;
- `human_handoff_requested=false`;
- `next_state=SESSION_ENDED`.
It emits `session.end.requested`. Channel-specific session expiration or connection closing remains an integration responsibility.
## Safety behavior
- Only decisions above the configured confidence threshold are accepted.
- Invalid JSON, timeout, low confidence, or errors fall back to the Enterprise Router.
- Human handoff and session ending do not execute domain agents or MCP tools.
- The classifier never selects a human queue and never physically closes a channel connection.
## Tests
Run:
```bash
PYTHONPATH=libs/agent_framework/src pytest -q tests/unit/test_semantic_route_stickiness.py
```
The suite covers CONTINUE, ROUTE, low confidence, invalid output, HUMAN_HANDOFF, END_SESSION, first-turn global actions, and CONTINUE without an active agent.

View File

@@ -0,0 +1,86 @@
# Template Backend/Frontend alinhado ao BusinessContext v2
Este pacote atualiza o `agent_template_backend` e o `agent_frontend` para refletir o framework novo, onde as chaves vindas do canal/front-end são resolvidas uma vez como chaves canônicas e propagadas pelas camadas até o MCP Server.
## Fluxo implementado
1. O front-end envia `tenant_id`, `agent_id`, `session_id` e `business_context`.
2. O backend normaliza a mensagem via `ChannelGateway` preservando todo o payload no `context`.
3. O backend usa `IdentityResolver` com `config/identity.yaml` para gerar `BusinessContext`:
- `customer_key`
- `contract_key`
- `interaction_key`
- `account_key`
- `resource_key`
- `session_key`
4. O workflow recebe `context.business_context`.
5. Os agentes de exemplo não montam mais argumentos específicos como `msisdn`, `invoice_id` ou `order_id` diretamente.
6. O `MCPToolRouter` usa `config/mcp_parameter_mapping.yaml` para converter chaves canônicas em parâmetros reais de cada tool MCP.
## Arquivos principais ajustados
- `agent_template_backend/app/main.py`
- carrega `IdentityResolver`;
- resolve `BusinessContext` por mensagem;
- persiste as chaves na sessão/memória/metadata/SSE;
- adiciona `/debug/identity`.
- `agent_template_backend/app/agents/runtime.py`
- adiciona `_collect_mcp_context()` centralizado;
- repassa `business_context` e `original_context` para o MCP Router.
- `agent_template_backend/app/agents/*_agent.py`
- agentes passam a usar `_collect_mcp_context()` em vez de montar argumentos específicos.
- `agent_template_backend/config/identity.yaml`
- define como campos do canal/front-end alimentam as chaves canônicas.
- `agent_template_backend/config/mcp_parameter_mapping.yaml`
- define como chaves canônicas viram parâmetros reais por tool MCP.
- `agent_frontend/index.html` e `agent_frontend/app.js`
- adicionam campos de `tenant`, `agent` e chaves canônicas;
- enviam `business_context` no payload;
- mantêm aliases de domínio para compatibilidade (`msisdn`, `invoice_id`, `order_id`, etc.).
## Teste rápido
Suba backend, frontend e MCP servers. Depois teste:
```bash
curl -s http://localhost:8000/health | jq
curl -s -X POST http://localhost:8000/debug/identity \
-H 'Content-Type: application/json' \
-d '{
"channel":"web",
"tenant_id":"default",
"agent_id":"telecom_contas",
"payload":{
"message":"Minha fatura veio alta",
"session_id":"teste-001",
"msisdn":"11999999999",
"invoice_id":"3000131180",
"ura_call_id":"URA-123",
"business_context":{
"customer_key":"11999999999",
"contract_key":"3000131180",
"interaction_key":"URA-123",
"session_key":"teste-001"
}
}
}' | jq
curl -s -X POST http://localhost:8000/debug/mcp/call/consultar_fatura \
-H 'Content-Type: application/json' \
-d '{
"business_context": {
"customer_key":"11999999999",
"contract_key":"3000131180",
"interaction_key":"URA-123",
"session_key":"teste-001"
}
}' | jq
```
No log do backend, procure por `mcp.tool.mapped`. Ele deve indicar as chaves mapeadas e `has_msisdn=true`, `has_invoice_id=true` para o domínio telecom.

View File

@@ -0,0 +1,28 @@
# Testes unitários do framework
Esta versão inclui uma pasta `tests/unit` cobrindo os componentes principais:
- cache local e distribuído;
- SSE com encode, persistência e replay;
- RAG com busca vetorial em memória;
- checkpoint saver compatível com LangGraph;
- telemetria profunda de LangGraph;
- runtime dos agentes com cache/RAG;
- verificação estática do workflow para garantir que não usa mais `MemorySaver()` diretamente.
## Como executar
```bash
cd projeto_agent_framework_first_ready
python -m venv .venv
source .venv/bin/activate
pip install -r agent_template_backend/requirements.txt
pip install pytest pytest-asyncio
pytest -q
```
Para rodar apenas os testes unitários:
```bash
pytest -q tests/unit
```

View File

@@ -0,0 +1,90 @@
# Políticas mínimas para tools MCP read-only e transacionais
## Objetivo
O framework diferencia operações de consulta (`read_only`) e operações que alteram estado (`transactional`) imediatamente antes da chamada MCP. Essa classificação não substitui autorização, idempotência ou regras de negócio do servidor MCP; ela acrescenta somente a proteção conversacional mínima, especialmente confirmação explícita.
## Onde configurar
A parametrização pertence ao backend da aplicação:
```text
templates/agent_template_backend/config/tool_policies.yaml
```
A biblioteca compartilhada contém apenas o loader e a validação. O caminho é opcional:
```dotenv
TOOL_POLICIES_PATH=./config/tool_policies.yaml
```
## Exemplo
```yaml
version: 1
defaults:
operation_type: read_only
require_confirmation: false
tool_policies:
consultar_plano:
operation_type: read_only
alterar_plano:
operation_type: transactional
require_confirmation: true
requires: [new_plan_id]
```
Para executar `alterar_plano`, os argumentos precisam conter `new_plan_id` e um booleano literal de confirmação:
```json
{"new_plan_id": "CONTROLE_100", "confirmed": true}
```
Também é aceito `"confirmation": true`. Strings como `"true"` não são aceitas como confirmação.
## Compatibilidade
- Se `tool_policies.yaml` não existir, o framework continua usando `tool_type`, `requires`, `confirmation_required` e `execution_policy` de `tools.yaml`.
- Tools antigas sem política continuam executando como antes.
- Uma política explícita no arquivo novo prevalece para `operation_type` e confirmação daquela tool.
- O catálogo `tools.yaml` continua sendo a fonte de endpoint, schema, habilitação e cache.
- O novo arquivo não deve ser colocado em `libs/agent_framework`, pois as decisões variam por aplicação e domínio.
## Fluxo de execução
```text
agente -> MCPToolRouter -> validação da política -> mapeamento de parâmetros -> MCP Gateway/Server
```
Uma chamada bloqueada retorna `ok=false`, `metadata.blocked_by_policy=true`, o tipo da operação e a origem da política. O servidor MCP permanece a autoridade final para autenticação, autorização, validação, idempotência e transação de negócio.
## Migração recomendada
1. Atualize a biblioteca sem criar o arquivo: o comportamento permanece legado.
2. Crie `config/tool_policies.yaml` no backend.
3. Cadastre primeiro apenas operações transacionais que exigem confirmação.
4. Teste chamadas sem confirmação, com confirmação booleana e com campos obrigatórios ausentes.
5. Remova gradualmente duplicações de confirmação de `tools.yaml` quando todos os templates consumidores já usarem a nova configuração.
## Runtime transacional mínimo (correção de amarração)
A lista `mcp_tools` do roteamento é uma **allowlist**, não uma ordem para executar todas as ferramentas. O runtime agora:
1. executa automaticamente somente ferramentas `read_only`;
2. seleciona no máximo uma ação transacional compatível com o pedido do usuário;
3. quando `require_confirmation: true`, persiste `pending_tool_call` e `transaction_status: AWAITING_CONFIRMATION`;
4. no turno de confirmação, reutiliza a mesma chamada e executa com `confirmed: true`;
5. publica no estado `available_mcp_tools`, `selected_tool_call`, `tool_policy_result`, `confirmation_required` e `confirmation_received`.
Para o cenário de exemplo, o pedido `123` (ou `PED-ENTREGUE`) retorna `ENTREGUE` no MCP Retail. Use:
```text
Quero devolver o pedido 123 porque me arrependi da compra.
Sim, confirmo a devolução.
```
O contrato MCP foi padronizado para usar `reason` tanto no catálogo quanto no servidor FastMCP. `tool_policies.yaml` prevalece sobre os campos legados de `tools.yaml`; estes permanecem alinhados nos templates para compatibilidade.

View File

@@ -0,0 +1,113 @@
# AI Agent Platform — LangGraph + OCI
Monorepo com três projetos independentes:
- `agent_framework/`: biblioteca reutilizável para agentes escaláveis.
- `agent_template_backend/`: backend FastAPI usando o framework, com dois agentes, roteador, máquina de estados, sessão persistente e gateway de canais.
- `agent_frontend/`: frontend web simples e independente para conversar com o backend via gateway HTTP.
## Visão de arquitetura
```text
Frontend Web / WhatsApp / Voz / Texto
Channel Gateway + Adapters
SessionRepository persistente
Supervisor / Router Agent
LangGraph StateGraph
Agent A Agent B
↓ ↓
Guardrails → LLM OCI Generative AI → Output Guardrails → Judges
Memory / RAG / Vector / Graph / Telemetry / Streaming
```
![img_1.png](../img_1.png)
## Quickstart local
Suba a estrutura de Langfuse, MongoDB, REDIS para seu ambiente de desenvolvimento:
Vá até o folder ./agent_framework/Infrastructure_Langfuse/, onde existe o docker-compose.yml e execute:
```bash
docker compose up
```
O langfuse estará em:
```bash
http://localhost:3005
```
Crie sua Organização e seu projeto
![img.png](../img.png)
Será criado também um MongoDB e um REDIS, logo seu .env terá a configuração para apontar para estes recursos conteinerizados.
Você pode também apontar para um banco de dados Autonomous Oracle, basta configurar no arquivo .env.
Depois compile do Agent Framework dentro do agent_template_backend (agente template que se utiliza do Framework):
Obs: configure o arquivo .env.
Terminal 1:
```bash
cd agent_framework_oci
python -m venv .venv
source .venv/bin/activate
cd agent_template_backend
pip install -e ../agent_framework
pip install -r requirements.txt
uvicorn app.main:app --reload --reload-dir app --reload-dir config --port 8000
```
Terminal 2:
```bash
cd agent_framework_oci
bash ./scripts/run_mcp_servers.sh
```
Terminal 3:
```bash
cd agent_framework_oci
cd agent_frontend
python -m http.server 5173
```
Abra `http://localhost:5173`.
## OCI LLM
Configure no `.env`:
```env
LLM_PROVIDER=oci_openai
OCI_GENAI_BASE_URL=https://inference.generativeai.sa-saopaulo-1.oci.oraclecloud.com/openai/v1
OCI_GENAI_MODEL=openai.gpt-4.1
OCI_GENAI_API_KEY=...
```
Para rodar sem credenciais, use:
```env
LLM_PROVIDER=mock
```
## Estado do projeto
Este é um template de referência funcional/simulável. Conectores reais de Autonomous Database, MongoDB, Redis, Langfuse, OCI Streaming e OCI GenAI estão isolados por interfaces/adapters para facilitar evolução e deploy.
## Enterprise Routing Edition
Esta versão também possui `README_ENTERPRISE_ROUTING.md`, com detalhes sobre roteamento por estado, intents configuráveis, LLM Router opcional e dois templates de exemplo.
## Multi-agent isolation
Esta distribuição inclui suporte para múltiplos `agent_template` no mesmo backend.
Consulte `README_MULTI_AGENT_ISOLATION.md`.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
# Correção da extração de parâmetros MCP
## Problema corrigido
O bloco `extract` do `mcp_parameter_mapping.yaml` existia na configuração e na
documentação, mas não era executado pelo runtime. Além disso, valores do
Business Context podiam sobrescrever argumentos explícitos, fazendo
`contract_key` substituir o `order_id` informado pelo usuário.
## Correções
- implementação da extração genérica `strategy: llm` após a escolha da tool;
- suporte preservado para `strategy: month_name_pt`;
- profile dedicado `mcp_parameter_extraction`;
- telemetria `llm.mcp_parameter_extraction`;
- `extract` deixou de ser interpretado como mapeamento simples;
- argumentos explícitos/extraídos têm precedência sobre Business Context;
- remoção de `contract_key: order_id` dos templates;
- `order_id` configurado como `string`;
- atualização das variantes em `Tuning-Performance`.
## Resultado esperado
Para a mensagem `consultar pedido 123`, a chamada MCP deve receber
`order_id=123`, mesmo quando o Business Context contém outro `contract_key`.

View File

@@ -0,0 +1,21 @@
# Correção — mudança de consulta para ação transacional
## Problema
Após `consultar pedido 123`, a mensagem `Quero devolver o pedido 123` podia permanecer no `orders_agent` por route stickiness. Como a intent anterior só expunha tools de consulta, o runtime executava novamente `consultar_pedido` e a resposta direta repetia o status do pedido.
## Correções
- Keywords explícitas configuradas no `routing.yaml` podem preemptar a route stickiness quando apontam para outra intent/agente.
- `retail_support_exchange_return` passa a ter prioridade maior que `retail_order_tracking` para mensagens de troca/devolução.
- Tools transacionais declaram `selection_keywords` no `tools.yaml`.
- A resposta direta read-only é bloqueada quando a mensagem contém uma ação transacional registrada, mesmo que a intent anterior ainda esteja ativa.
- A seleção da action tool usa configuração, não aliases de domínio fixos no runtime.
## Fluxo esperado
1. `consultar pedido 123``orders_agent``consultar_pedido` → resposta direta.
2. `Quero devolver o pedido 123` → preempção da stickiness → `support_agent` / `retail_support_exchange_return`.
3. `consultar_pedido` valida o pedido.
4. `solicitar_devolucao` é selecionada e, com confirmação obrigatória, gera `AWAITING_CONFIRMATION`.
5. `Sim, confirmo` executa a action tool uma única vez.

View File

@@ -0,0 +1,36 @@
# Release notes - políticas read-only/transacionais
## Alterações
- Novo `ToolPolicyRegistry` opcional na biblioteca compartilhada.
- Validação central no `MCPToolRouter`, inclusive para chamadas diretas.
- Tipos mínimos `read_only` e `transactional`.
- Confirmação estrita por `confirmed: true` ou `confirmation: true`.
- Suporte opcional a campos obrigatórios por política.
- Fallback automático para `tool_type`, `requires`, `confirmation_required` e `execution_policy` de `tools.yaml`.
- `config/tool_policies.yaml` e variável `TOOL_POLICIES_PATH` nos templates principais, Day Zero e variantes de `Tuning-Performance/Normal` e `Tuning-Performance/Route_Stickness`.
- Testes unitários de política e compatibilidade adicionados em `tests/unit/test_tool_policies.py`.
## Verificações executadas
- Compilação de `libs`, `templates`, `Tuning-Performance` e `tests`: aprovada.
- Validação estrutural dos seis arquivos YAML: aprovada.
- Casos isolados do loader (política transacional, confirmação, ausência de arquivo e ausência de cadastro): aprovados.
- Renderização dos dois manuais Word atualizados: aprovada, sem cortes ou sobreposição nas páginas adicionadas.
## Limitação do ambiente de validação
A suíte `pytest` foi preparada, mas não pôde ser executada integralmente neste ambiente porque `pytest` e as dependências de runtime do projeto não estavam instalados e o acesso ao índice de pacotes expirou. Para reproduzir em um ambiente do projeto:
```bash
PYTHONPATH=libs/agent_framework/src:templates/agent_template_backend python -m pytest -q
```
## Correção de integração backend/MCP
- `mcp_tools` passou a ser tratado como allowlist.
- Ações não são mais executadas automaticamente junto com consultas.
- Confirmação transacional é persistida e retomada no turno seguinte.
- Corrigida incompatibilidade `reason`/`motivo` no MCP Retail.
- Adicionado pedido entregue determinístico para testes (`123`).
- Removida keyword genérica `produto` da intenção Telecom para evitar colisão com devoluções Retail.
- Templates Normal e Route_Stickness em `Tuning-Performance` foram sincronizados.

View File

@@ -0,0 +1,35 @@
# Test Results - Semantic Route Stickiness and Global Session Control
Date: 2026-07-31
## Command
```bash
PYTHONPATH=libs/agent_framework/src pytest -q tests/unit/test_semantic_route_stickiness.py
```
## Result
```text
9 passed
```
## Covered scenarios
1. `CONTINUE` bypasses the Enterprise Router.
2. `ROUTE` falls back to the Enterprise Router.
3. Low-confidence `CONTINUE` falls back safely.
4. Invalid model output falls back safely.
5. With no active agent, the lightweight classifier can still detect global session actions.
6. `HUMAN_HANDOFF` returns the global `human_handoff` route and session-control metadata.
7. `END_SESSION` returns the global `end_session` route and session-control metadata.
8. Global actions work on the first turn.
9. `CONTINUE` without an active agent is normalized to `ROUTE`.
## Additional validation
```bash
python -m compileall -q libs/agent_framework/src templates/agent_template_backend/app
```
Compilation completed successfully.

View File

@@ -0,0 +1,27 @@
# Validação — integração transacional Agent Template Backend / MCP
## Correções implementadas
- `mcp_tools` é tratado como allowlist, não como lista de execução automática.
- Tools `read_only` continuam disponíveis para enriquecimento de contexto.
- Somente uma tool transacional compatível com a solicitação é selecionada.
- `require_confirmation: true` cria `pending_tool_call` e `AWAITING_CONFIRMATION`.
- O turno de confirmação executa a chamada pendente com `confirmed: true`.
- O estado expõe `selected_tool_call`, `tool_policy_result`, `confirmation_required`, `confirmation_received` e `transaction_status`.
- `reason` foi padronizado entre catálogo, mapping e FastMCP Retail.
- Pedido `123` e `PED-ENTREGUE` retornam status `ENTREGUE` para testes positivos.
- A keyword genérica `produto` foi removida da intenção Telecom para não capturar devoluções Retail.
- Templates `Normal` e `Route_Stickness` em `Tuning-Performance` foram atualizados.
## Teste recomendado
1. `Quero devolver o pedido 123 porque me arrependi da compra.`
2. Esperado: `transaction_status=AWAITING_CONFIRMATION`, sem execução de `solicitar_devolucao`.
3. `Sim, confirmo a devolução.`
4. Esperado: `transaction_status=COMPLETED` e execução única de `solicitar_devolucao`.
## Resultado automatizado
```text
7 passed
```

View File

@@ -0,0 +1,38 @@
VALIDAÇÃO - GLOBAL SUPERVISOR
Alterações implementadas:
1. Framework
- agent_framework.global_supervisor.models
- agent_framework.global_supervisor.config
- agent_framework.global_supervisor.session_store
- agent_framework.global_supervisor.router
- agent_framework.global_supervisor.client
2. Novo serviço
- agent_gateway/app/main.py
- agent_gateway/app/settings.py
- agent_gateway/config/backends.yaml
- agent_gateway/README.md
- agent_gateway/Dockerfile
- agent_gateway/docs/ARQUITETURA_GLOBAL_SUPERVISOR.md
3. Docker Compose
- serviço agent-gateway adicionado na porta 8010.
Validações executadas:
- python3 -m compileall -q agent_framework/src/agent_framework/global_supervisor agent_gateway/app
Resultado: OK
- Smoke test do roteamento híbrido:
Entrada 1: "Minha fatura veio alta" -> contas
Entrada 2: "e esse valor?" na mesma session_id -> contas por active_backend
Resultado: OK
- Smoke test de import do app FastAPI:
from app.main import app, registry, router
Resultado: OK
Observação:
- O proxy SSE do gateway foi deixado como etapa futura. O endpoint /gateway/message/sse já roteia e encaminha como mensagem normal; para SSE fim-a-fim, pode-se implementar proxy de /gateway/events/{session_id} para o backend ativo.

View File

@@ -0,0 +1,5 @@
VALIDATION REPORT - guardrails parallel fail-fast + observer IC
Date: 2026-06-03
compileall: OK
smoke-tests: OK

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB