Compare commits

..

13 Commits

1238 changed files with 58110 additions and 2955 deletions

View File

@@ -212,3 +212,25 @@ LONG_TERM_MEMORY_INJECT_CONTEXT=true
# Keep disabled in the generic framework; agents may enable their own YAML mapping. # Keep disabled in the generic framework; agents may enable their own YAML mapping.
OBSERVABILITY_CODE_MAPPING_ENABLED=false OBSERVABILITY_CODE_MAPPING_ENABLED=false
OBSERVABILITY_CODE_MAPPING_PATH= OBSERVABILITY_CODE_MAPPING_PATH=
###############################################################################
# RAG provider selection (mutually exclusive at runtime)
###############################################################################
# standard = RAG original do agent_framework_oci (default, backward compatible)
# kbdb = KBDB enterprise via PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE
RAG_PROVIDER=standard
# Somente usados quando RAG_PROVIDER=kbdb. Se vazios, credenciais caem para ADB_*.
KBDB_DB_USER=
KBDB_DB_PASSWORD=
KBDB_DB_DSN=
KBDB_DB_WALLET_LOCATION=
KBDB_DB_WALLET_PASSWORD=
KBDB_SEARCH_TYPE=hybrid
KBDB_NODE_EXPANSION=true
KBDB_NODE_MAX_RELATED=8
KBDB_GRAPH_CROSS_REF=false
KBDB_MAX_CROSS_REF_HOPS=1
KBDB_DOCUMENT_TYPE=customer_safe
KBDB_METADATA_JSON=
KBDB_MIN_SCORE=

14
.idea/workspace.xml generated
View File

@@ -4,7 +4,9 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="30a0e1d8-9d7d-469b-b241-f300911cee8a" name="Changes" comment="Ajustes na documentação e remanejamento dos folders" /> <list default="true" id="30a0e1d8-9d7d-469b-b241-f300911cee8a" name="Changes" comment="Ajustes na documentação e remanejamento dos folders">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -50,12 +52,13 @@
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true", "ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
"ModuleVcsDetector.initialDetectionPerformed": "true", "ModuleVcsDetector.initialDetectionPerformed": "true",
"RunOnceActivity.ShowReadmeOnStart": "true", "RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
"RunOnceActivity.git.unshallow": "true", "RunOnceActivity.git.unshallow": "true",
"RunOnceActivity.typescript.service.memoryLimit.init": "true", "RunOnceActivity.typescript.service.memoryLimit.init": "true",
"SHARE_PROJECT_CONFIGURATION_FILES": "true", "SHARE_PROJECT_CONFIGURATION_FILES": "true",
"git-widget-placeholder": "master", "git-widget-placeholder": "main",
"kotlin-language-version-configured": "true", "kotlin-language-version-configured": "true",
"last_opened_file_path": "D:/Dropbox/ORACLE/TIM/FY27/Wave_2/Ajuste para manter o agente atual ou voltar ao roteamento/agent_framework_oci", "last_opened_file_path": "D:/Dropbox/ORACLE/TIM/FY27/Commits/agent_platform_oci",
"node.js.detected.package.eslint": "true", "node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true", "node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)", "node.js.selected.package.eslint": "(autodetect)",
@@ -68,8 +71,8 @@
<component name="SharedIndexes"> <component name="SharedIndexes">
<attachedChunks> <attachedChunks>
<set> <set>
<option value="bundled-jdk-9823dce3aa75-fbdcb00ec9e3-intellij.indexing.shared.core-IU-251.29188.36" /> <option value="bundled-jdk-30f59d01ecdd-cffe25b9f5b3-intellij.indexing.shared.core-IU-253.28294.334" />
<option value="bundled-js-predefined-d6986cc7102b-09060db00ec0-JavaScript-IU-251.29188.36" /> <option value="bundled-js-predefined-d6986cc7102b-c7e53b3be11b-JavaScript-IU-253.28294.334" />
</set> </set>
</attachedChunks> </attachedChunks>
</component> </component>
@@ -92,6 +95,7 @@
<workItem from="1785414225783" duration="148000" /> <workItem from="1785414225783" duration="148000" />
<workItem from="1785414447653" duration="704000" /> <workItem from="1785414447653" duration="704000" />
<workItem from="1785630146329" duration="316000" /> <workItem from="1785630146329" duration="316000" />
<workItem from="1787832640995" duration="4662000" />
</task> </task>
<task id="LOCAL-00001" summary="Ajustes na documentação e remanejamento dos folders"> <task id="LOCAL-00001" summary="Ajustes na documentação e remanejamento dos folders">
<option name="closed" value="true" /> <option name="closed" value="true" />

212
README.md
View File

@@ -18,6 +18,27 @@ O objetivo é que cada novo agente implemente apenas sua lógica de domínio —
>**Note: Se deseja ir direto e testar a DEMO, vá até a Seção 17 e 18.** >**Note: Se deseja ir direto e testar a DEMO, vá até a Seção 17 e 18.**
## Índice de Desenvolvimento — Agent Framework OCI
### Outros idiomas
- [Developer documentation in English](README_en.md)
- [Índice técnico detalhado em Português](docs/developer/pt/INDEX_DEVELOPER_GUIDE.md)
- [Detailed technical index in English](docs/developer/en/INDEX_DEVELOPER_GUIDE.md)
### Como usar esta documentação
A documentação possui três níveis:
1. **Tutorial principal:** este [`README.md`](README.md) — criação, configuração, execução e teste de um agente do início ao fim.
2. **Arquitetura:** [01 — Arquitetura e Conceitos](docs/developer/pt/01_architecture_and_concepts.md) — componentes, responsabilidades e onde implementar cada coisa.
3. **Referências especializadas:** manuais `02` a `12` — implementação profunda e troubleshooting por capacidade.
Se você está começando um novo agente, siga este `README.md` desde o início. Para aprofundamento ou troubleshooting, use os links abaixo.
Se algo não está funcionando ou se deseja entender melhor funcionalidades da arquitetura do Agent Framework OCI, vá até [34. Funcionalidades Avançadas](#34-funcionalidades-avançadas). Você vai encontrar detalhamento sobre funcionalidades avançadas, como conceitos, exemplos e manuais de utilização.
## SPECs / SDDs da Agent Platform OCI ## SPECs / SDDs da Agent Platform OCI
@@ -2150,71 +2171,30 @@ trace_id
#### 5.1.1.21.3. Instrumentação automática do cliente OpenAI pelo Langfuse #### 5.1.1.21.3. Instrumentação automática do cliente OpenAI pelo Langfuse
O padrão oficial do framework é:
```python ```env
ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=true
```
habilita a instrumentação automática do cliente OpenAI pelo Langfuse.
Quando habilitada, todas as chamadas realizadas através do cliente OpenAI instrumentado passam a gerar automaticamente spans e generations detalhadas no Langfuse.
Benefícios
Com a instrumentação automática ativada, o Langfuse passa a registrar informações como:
* OpenAI-generation
* Prompt enviado ao modelo
* Resposta retornada pelo modelo
* Modelo utilizado
* Quantidade de tokens
* Custos estimados
* Latência da chamada
* Erros de execução
Essas informações ficam associadas ao trace principal da conversa, facilitando análise, troubleshooting e auditoria.
Comportamento quando desabilitado
Quando:
```python
ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=false ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=false
``` ```
ou a variável não está definida: O framework já instrumenta as chamadas LLM por meio de `Telemetry.generation(...)`, preservando `trace_id`, `session_id`, `user_id`, metadados, tokens, custos, latência e o relacionamento pai/filho dentro do trace de negócio. Por esse motivo, a auto-instrumentação do cliente OpenAI não é necessária no fluxo normal do framework.
* As chamadas LLM continuam funcionando normalmente. Quando `false`:
* Os spans customizados do framework continuam sendo emitidos.
* O Langfuse deixa de criar automaticamente as entradas OpenAI-generation.
* Menos detalhes ficam disponíveis para análise das chamadas ao modelo.
Quando utilizar * as chamadas LLM continuam funcionando normalmente;
* prompts, respostas, modelo, tokens, custos e latência continuam disponíveis pela telemetria explícita do framework;
* as generations permanecem correlacionadas ao trace principal da requisição;
* evita-se dupla instrumentação e `OpenAI-generation` como trace raiz separado.
Recomenda-se habilitar em: A opção `true` existe apenas para compatibilidade ou diagnóstico de código que chama diretamente o SDK OpenAI/OpenAI-compatible fora da camada de `Telemetry` do framework. Nesses casos, o wrapper `langfuse.openai` pode capturar automaticamente essas chamadas. Entretanto, em uma aplicação que já usa a instrumentação nativa do framework, mantê-la habilitada pode gerar duplicidade de observations, contagem duplicada de tokens/custos ou traces independentes quando não houver um parent Langfuse ativo.
* Ambientes de desenvolvimento. ```env
* Ambientes de homologação. # Padrão recomendado para todos os templates e ambientes do framework
* Ambientes de produção que necessitem observabilidade detalhada das chamadas LLM. ENABLE_LANGFUSE=true
* Cenários de troubleshooting, tuning de prompts e análise de custos. ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=false
```
Observação Todos os arquivos `.env.example` distribuídos pelo projeto mantêm essa opção explicitamente em `false`. Se um componente externo precisar de captura automática, habilite-a somente naquele deployment e valide a árvore de traces no Langfuse.
Esta configuração afeta apenas a telemetria automática do Langfuse.
Ela não altera:
* O comportamento dos agentes.
* O roteamento do Supervisor.
* Guardrails.
* Judges.
* MCP Tool Router.
* Fluxos LangGraph.
Seu único objetivo é enriquecer a observabilidade das chamadas realizadas ao modelo de linguagem.
---
### 5.1.1.22. Recomendações de arquitetura
#### 5.1.1.22.1. Para demos e desenvolvimento #### 5.1.1.22.1. Para demos e desenvolvimento
@@ -11176,3 +11156,123 @@ A adoção das funcionalidades do `Tuning-Performance` pode proporcionar:
* comportamento consistente entre diferentes agentes e projetos. * comportamento consistente entre diferentes agentes e projetos.
O conteúdo desta pasta deve ser tratado como uma extensão adicional do framework. Sua utilização requer implementação, configuração, testes funcionais e validação das regras de negócio antes da implantação em produção. O conteúdo desta pasta deve ser tratado como uma extensão adicional do framework. Sua utilização requer implementação, configuração, testes funcionais e validação das regras de negócio antes da implantação em produção.
### Buscar pelo problema
| Problema / dúvida | O que normalmente está envolvido | Onde procurar |
|---|---|---|
| O framework não encontra o agente/intenção correta | routing, intents, threshold, modo determinístico/LLM | [Routing e Stickiness](docs/developer/pt/02_routing_stickiness_and_intent_shift.md) |
| O agente fica preso no mesmo assunto e não troca de intent | route stickiness, intent shift, handoff | [Routing e Stickiness](docs/developer/pt/02_routing_stickiness_and_intent_shift.md) |
| Uma resposta que deveria preencher parâmetro é interpretada como novo intent | precedência transacional, parameter extraction | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) |
| A transação fica pedindo o mesmo parâmetro | estado transacional, extractor, schema | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) e [MCP/Tools](docs/developer/pt/04_mcp_integration_tools_and_policies.md) |
| A confirmação “sim/não” não continua o fluxo | confirmation state, transaction state | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) |
| Uma fala inválida durante um `expected_input` vira `CONTINUAR` em vez de pedir esclarecimento | `semantic_classifier.unmatched_value`, `reprompt`, `contextual_reentry`, COER delegado | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) e [Feedback de Guardrails de Entrada](docs/developer/pt/12_input_guardrail_feedback_and_blocked_turns.md) |
| Uma transação encerrada reaparece | checkpoint antigo versus estado transacional ativo | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) e [LTM/Checkpoint](docs/developer/pt/08_long_term_memory_and_checkpoint.md) |
| O sistema diz que executou algo, mas não existe evidência | MCP result, estado `COMPLETED`, judges transacionais | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) e [Guardrails/Judges](docs/developer/pt/06_guardrails_judges_and_transaction_evaluation.md) |
| Uma tool não aparece ou não é encontrada | `tools.yaml`, catálogo MCP, discovery | [MCP/Tools](docs/developer/pt/04_mcp_integration_tools_and_policies.md) |
| MCP Server não aparece no catálogo | registration, manifest/discovery, MCP Gateway | [MCP/Tools](docs/developer/pt/04_mcp_integration_tools_and_policies.md) e [Gateways](docs/developer/pt/05_agent_gateway_mcp_gateway_and_auth.md) |
| Parâmetros enviados à tool estão errados | schema, mapping, BusinessContext, extractor | [MCP/Tools](docs/developer/pt/04_mcp_integration_tools_and_policies.md) |
| Uma operação transacional executa sem confirmação | tool policy, `require_confirmation` | [MCP/Tools](docs/developer/pt/04_mcp_integration_tools_and_policies.md) |
| Uma busca por nome exige correspondência exata demais | extração/mapeamento de parâmetros e lógica do agente | [MCP/Tools](docs/developer/pt/04_mcp_integration_tools_and_policies.md) |
| Recebo 401 entre gateway/backend/MCP | Basic Auth, credenciais por hop | [Gateways e Auth](docs/developer/pt/05_agent_gateway_mcp_gateway_and_auth.md) |
| Preciso decidir se algo pertence ao framework ou ao agente | boundary core/agente | [Arquitetura e Conceitos](docs/developer/pt/01_architecture_and_concepts.md) |
| Guardrail específico de um agente está quebrando outro | extensibilidade, imports de domínio no core | [Guardrails e Judges](docs/developer/pt/06_guardrails_judges_and_transaction_evaluation.md) |
| Uma frase incompleta recebe mensagem genérica de “regra de segurança” | feedback de input guardrail, `COER`, blocked-turn state | [Feedback de Guardrails de Entrada](docs/developer/pt/12_input_guardrail_feedback_and_blocked_turns.md) |
| `route=blocked` aparece junto com tools/resultados de outro turno | limpeza de estado do turno bloqueado | [Feedback de Guardrails de Entrada](docs/developer/pt/12_input_guardrail_feedback_and_blocked_turns.md) |
| Workflow conclui e gera protocolo, mas a resposta final vira mensagem de segurança | `expected_protocols`, `CMP`, `DLEX_OUT`, ordem de `output_guardrails` | [Guardrails e Judges](docs/developer/pt/06_guardrails_judges_and_transaction_evaluation.md) |
| Judge não roda em uma transação | sampling, `always_run_for_transactional`, sinais transacionais | [Guardrails e Judges](docs/developer/pt/06_guardrails_judges_and_transaction_evaluation.md) |
| Groundedness está avaliando sem contexto correto | RAG context, MCP evidence, judge inputs | [RAG/Grounding](docs/developer/pt/07_rag_business_context_and_grounding.md) |
| RAG não encontra conteúdo | provider, ingestão, embeddings, configuração | [RAG/Grounding](docs/developer/pt/07_rag_business_context_and_grounding.md) |
| Não sei se usar RAG, memória ou tool | separação de responsabilidades | [Arquitetura e Conceitos](docs/developer/pt/01_architecture_and_concepts.md) e [RAG/Grounding](docs/developer/pt/07_rag_business_context_and_grounding.md) |
| Memória desaparece ao trocar de sessão | LTM versus conversation memory | [LTM e Checkpoint](docs/developer/pt/08_long_term_memory_and_checkpoint.md) |
| Memória de um cliente/agente aparece em outro | identity key, tenant/agent/customer isolation | [LTM e Checkpoint](docs/developer/pt/08_long_term_memory_and_checkpoint.md) |
| Preciso recuperar `reasoning_content` | `ainvoke_response()` | [LLM Rich Response](docs/developer/pt/09_llm_rich_response_reasoning.md) |
| `reasoning_content` vem `None` | provider/model não expõe o campo | [LLM Rich Response](docs/developer/pt/09_llm_rich_response_reasoning.md) |
| Há chamadas LLM desnecessárias | routing determinístico, concorrência, cache | [Performance](docs/developer/pt/10_performance_cache_and_async_runtime.md) |
| Há deadlock ou espera entre event loops | cross-loop sequence/runtime | [Performance](docs/developer/pt/10_performance_cache_and_async_runtime.md) |
| Logs/traces não correlacionam o mesmo agente | labels, IDs e mapeamento de observabilidade | [Observabilidade](docs/developer/pt/11_observability_persistence_and_operational_readiness.md) |
| Sequence está interferindo no processamento | implementação assíncrona de sequência | [Observabilidade](docs/developer/pt/11_observability_persistence_and_operational_readiness.md) e [Performance](docs/developer/pt/10_performance_cache_and_async_runtime.md) |
| Um exemplo antigo não compila | documentação histórica versus API atual | [Validação README x Código](docs/developer/pt/VALIDATION_README_ALIGNMENT.md) |
| Preciso criar um agente novo do zero | fluxo completo | [`README.md`](README.md) |
| Preciso saber onde colocar uma nova feature | arquitetura e boundaries | [Arquitetura e Conceitos](docs/developer/pt/01_architecture_and_concepts.md) |
### 34. Funcionalidades Avançadas
### [01 — Arquitetura e Conceitos](docs/developer/pt/01_architecture_and_concepts.md)
**O que é:** visão dos componentes, contratos e limites de responsabilidade.
**Use quando:** precisar entender a plataforma, decidir onde implementar algo ou evitar acoplamento entre core e agente.
### [02 — Routing, Route Stickiness e Intent Shift](docs/developer/pt/02_routing_stickiness_and_intent_shift.md)
**O que é:** referência completa de descoberta de agente/intent, stickiness, handoff e mudança de intenção.
**Use quando:** a mensagem cai no agente errado, não troca de intent ou perde continuidade.
### [03 — Workflows Transacionais e Estado](docs/developer/pt/03_transaction_workflows_and_state.md)
**O que é:** ciclo transacional multi-turno, estados, confirmação, pausa/retomada, `expected_input`, `semantic_classifier`, `unmatched_value`/`reprompt` e evidência operacional.
**Use quando:** há loops, confirmações incorretas, retomadas erradas, `CONTINUAR`/`contextual_reentry` indevido, `reprompt` ausente ou operações críticas.
### [04 — MCP, Tools, Policies e Extração de Parâmetros](docs/developer/pt/04_mcp_integration_tools_and_policies.md)
**O que é:** referência de tools, MCP Servers, mappings, policies e parameter extraction.
**Use quando:** integração/execução de tool está incorreta ou precisa ser criada.
### [05 — Agent Gateway, MCP Gateway e Autenticação](docs/developer/pt/05_agent_gateway_mcp_gateway_and_auth.md)
**O que é:** responsabilidades dos gateways, governança e autenticação entre componentes.
**Use quando:** houver problema de entrada, catálogo, autorização, 401 ou deployment dos gateways.
### [06 — Guardrails, Judges e Avaliação Transacional](docs/developer/pt/06_guardrails_judges_and_transaction_evaluation.md)
**O que é:** validações nativas/externas, judges, grounding e regras para turnos transacionais.
**Use quando:** uma validação bloqueia, não roda ou produz avaliação incorreta.
### [07 — RAG, BusinessContext e Grounding](docs/developer/pt/07_rag_business_context_and_grounding.md)
**O que é:** providers de RAG, contexto recuperado, BusinessContext e grounding.
**Use quando:** conhecimento recuperado não chega corretamente ao agente/judge.
### [08 — Long-Term Memory e Checkpoint](docs/developer/pt/08_long_term_memory_and_checkpoint.md)
**O que é:** memória durável, memória conversacional, identidade e snapshots de estado.
**Use quando:** contexto some, vaza ou workflow retoma do lugar errado.
### [09 — LLM Rich Response e reasoning_content](docs/developer/pt/09_llm_rich_response_reasoning.md)
**O que é:** resposta estruturada de inferência além do `str` retornado por `ainvoke()`.
**Use quando:** consumidores precisam de metadados, usage ou reasoning disponibilizado pelo provider.
### [10 — Performance, Cache e Runtime Assíncrono](docs/developer/pt/10_performance_cache_and_async_runtime.md)
**O que é:** otimizações de concorrência, cache, LLM e event loops.
**Use quando:** houver latência evitável, processamento serial ou deadlock.
### [11 — Observabilidade, Persistência e Prontidão Operacional](docs/developer/pt/11_observability_persistence_and_operational_readiness.md)
**O que é:** correlação, eventos, labels, sequence, persistência e diagnóstico.
**Use quando:** for necessário provar o caminho executado ou diagnosticar produção.
### [12 — Feedback de Guardrails de Entrada e Turnos Bloqueados](docs/developer/pt/12_input_guardrail_feedback_and_blocked_turns.md)
**O que é:** semântica de mensagens públicas para bloqueios de input, limpeza do estado do turno e passagem da resposta pelos guardrails de saída.
**Use quando:** um `COER`/guardrail de entrada gera mensagem genérica, `route=blocked` carrega resultados antigos ou há dúvida sobre a precedência entre input guardrails, routing e tools.
### Tutorial principal
[`README.md`](README.md) continua sendo a referência para o passo a passo completo:
`arquitetura → configuração → criação do agente → registro → estado → routing → tools → MCP → identidade → execução → testes → gateways → memória → RAG`.

View File

@@ -18,6 +18,28 @@ The goal is for each new agent to implement only its domain logic — prompts, b
>**Note: If you want to test the DEMO, go to the Section 17 and 18.** >**Note: If you want to test the DEMO, go to the Section 17 and 18.**
## Developer Index — Agent Framework OCI
### Other languages
- [Documentação de desenvolvimento em Português](README.md)
- [Detailed technical index in English](docs/developer/en/INDEX_DEVELOPER_GUIDE.md)
- [Índice técnico detalhado em Português](docs/developer/pt/INDEX_DEVELOPER_GUIDE.md)
### How to use this documentation
The documentation has three clear levels:
1. **Main tutorial:** this [`README_en.md`](README_en.md) — build, configure, run and test an agent end to end.
2. **Architecture:** [01 — Architecture and Concepts](docs/developer/en/01_architecture_and_concepts.md) — components, boundaries and implementation placement.
3. **Specialized references:** manuals `02` through `12` — deep implementation and troubleshooting by capability.
If you are creating a new agent, follow this `README_en.md` from the beginning. For deeper implementation details or troubleshooting, use the links below.
If something is not working or if you want to understand the features of the Agent Framework OCI architecture, go to [34. Advanced Features](#34-advanced-features)
## SPECs / SDDs of the Agent Platform OCI ## SPECs / SDDs of the Agent Platform OCI
The Agent Platform OCI documentation is organized into numbered SPECs/SDDs, each covering an architectural, operational, or governance area of the platform. The objective is to standardize the construction, evolution, operation, and certification of enterprise agents based on the Agent Framework OCI. The Agent Platform OCI documentation is organized into numbered SPECs/SDDs, each covering an architectural, operational, or governance area of the platform. The objective is to standardize the construction, evolution, operation, and certification of enterprise agents based on the Agent Framework OCI.
@@ -2145,71 +2167,30 @@ trace_id
#### 5.1.1.21.3. Automatic Langfuse instrumentation for the OpenAI client #### 5.1.1.21.3. Automatic Langfuse instrumentation for the OpenAI client
```python The framework's official default is:
ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=true
```
enables automatic Langfuse instrumentation for the OpenAI client. ```env
When enabled, every request executed through the Langfuse-instrumented OpenAI client automatically generates detailed spans and generations within Langfuse.
Benefits
With automatic instrumentation enabled, Langfuse can automatically capture and display information such as:
* OpenAI-generation
* Prompt sent to the model
* Model response
* Model name used
* Token consumption
* Estimated costs
* Request latency
* Execution errors
All of this information is linked to the main conversation trace, making troubleshooting, auditing, and performance analysis significantly easier.
Behavior When Disabled
When:
```python
ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=false ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=false
``` ```
or when the variable is not defined: The framework already instruments LLM calls through `Telemetry.generation(...)`, preserving `trace_id`, `session_id`, `user_id`, metadata, token usage, cost, latency, and the parent/child relationship inside the business trace. Therefore, OpenAI client auto-instrumentation is not required in the normal framework path.
* LLM calls continue to function normally. When set to `false`:
* Custom framework spans are still emitted.
* Langfuse no longer automatically creates OpenAI-generation entries.
* Less detailed information is available for analyzing model interactions.
Recommended Usage * LLM calls continue to work normally;
* prompts, responses, model, tokens, costs, and latency remain available through the framework's explicit telemetry;
* generations remain correlated with the main request trace;
* duplicate instrumentation and standalone `OpenAI-generation` root traces are avoided.
It is recommended to enable this setting in: The `true` option exists only for compatibility or diagnostics for code that calls the OpenAI/OpenAI-compatible SDK directly outside the framework `Telemetry` layer. In such cases, the `langfuse.openai` wrapper can automatically capture those calls. In an application already using the framework's native instrumentation, keeping it enabled may create duplicate observations, duplicate token/cost accounting, or independent traces when no active Langfuse parent exists.
* Development environments ```env
* Testing and staging environments # Recommended default for every framework template and environment
* Production environments that require detailed LLM observability ENABLE_LANGFUSE=true
* Prompt engineering, troubleshooting, and cost analysis scenarios ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=false
```
Important Note Every `.env.example` distributed with the project explicitly keeps this option set to `false`. If an external component requires automatic capture, enable it only for that deployment and validate the trace tree in Langfuse.
This setting only affects Langfuse automatic telemetry and observability.
It does not change:
* Agent behavior
* Supervisor routing
* Guardrails
* Judges
* MCP Tool Router
* LangGraph workflows
Its sole purpose is to enrich the observability of language model interactions and provide more detailed execution insights within Langfuse.
---
### 5.1.1.22. Architecture recommendations
#### 5.1.1.22.1. For demos and development #### 5.1.1.22.1. For demos and development
@@ -11082,3 +11063,116 @@ Adopting the `Tuning-Performance` capabilities can provide:
* consistent behavior across agents and projects. * consistent behavior across agents and projects.
The content of this folder should be treated as an additional framework extension. Its use requires implementation, configuration, functional testing, and business-rule validation before production deployment. The content of this folder should be treated as an additional framework extension. Its use requires implementation, configuration, functional testing, and business-rule validation before production deployment.
### Search by problem
| Problem / question | Usually involves | Go to |
|---|---|---|
| Framework selects the wrong agent/intent | routing, intents, thresholds, deterministic/LLM mode | [Routing and Stickiness](docs/developer/en/02_routing_stickiness_and_intent_shift.md) |
| Agent stays stuck on the same subject | route stickiness, intent shift, handoff | [Routing and Stickiness](docs/developer/en/02_routing_stickiness_and_intent_shift.md) |
| A parameter answer is mistaken for a new intent | transaction precedence, parameter extraction | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) |
| Transaction keeps asking for the same parameter | transaction state, extractor, schema | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [MCP/Tools](docs/developer/en/04_mcp_integration_tools_and_policies.md) |
| “yes/no” confirmation does not continue the flow | confirmation state | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) |
| Invalid input during `expected_input` becomes `CONTINUAR` instead of asking for clarification | `semantic_classifier.unmatched_value`, `reprompt`, `contextual_reentry`, delegated COER | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [Input Guardrail Feedback](docs/developer/en/12_input_guardrail_feedback_and_blocked_turns.md) |
| A closed transaction reappears | old checkpoint vs active transaction | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [LTM/Checkpoint](docs/developer/en/08_long_term_memory_and_checkpoint.md) |
| System claims an operation ran but there is no evidence | MCP results, `COMPLETED`, transaction judges | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [Guardrails/Judges](docs/developer/en/06_guardrails_judges_and_transaction_evaluation.md) |
| A tool is missing | tools config, MCP catalog/discovery | [MCP/Tools](docs/developer/en/04_mcp_integration_tools_and_policies.md) |
| MCP Server is missing from catalog | registration, manifest/discovery, MCP Gateway | [MCP/Tools](docs/developer/en/04_mcp_integration_tools_and_policies.md) and [Gateways](docs/developer/en/05_agent_gateway_mcp_gateway_and_auth.md) |
| Tool parameters are wrong | schema, mapping, BusinessContext, extraction | [MCP/Tools](docs/developer/en/04_mcp_integration_tools_and_policies.md) |
| Transactional tool executes without confirmation | policy, `require_confirmation` | [MCP/Tools](docs/developer/en/04_mcp_integration_tools_and_policies.md) |
| 401 between gateway/backend/MCP | Basic Auth, hop credentials | [Gateways and Auth](docs/developer/en/05_agent_gateway_mcp_gateway_and_auth.md) |
| Need to decide framework vs agent ownership | core/agent boundary | [Architecture and Concepts](docs/developer/en/01_architecture_and_concepts.md) |
| Agent-specific guardrail breaks another agent | extension model, domain imports | [Guardrails and Judges](docs/developer/en/06_guardrails_judges_and_transaction_evaluation.md) |
| Judge does not run for a transaction | sampling, transaction signals | [Guardrails and Judges](docs/developer/en/06_guardrails_judges_and_transaction_evaluation.md) |
| Groundedness gets the wrong context | RAG context, MCP evidence, judge inputs | [RAG/Grounding](docs/developer/en/07_rag_business_context_and_grounding.md) |
| RAG returns no useful content | provider, ingestion, embeddings | [RAG/Grounding](docs/developer/en/07_rag_business_context_and_grounding.md) |
| Unsure whether to use RAG, memory or a tool | responsibility separation | [Architecture and Concepts](docs/developer/en/01_architecture_and_concepts.md) |
| Memory disappears across sessions | LTM vs conversation memory | [LTM and Checkpoint](docs/developer/en/08_long_term_memory_and_checkpoint.md) |
| Memory leaks across customer/agent | identity isolation | [LTM and Checkpoint](docs/developer/en/08_long_term_memory_and_checkpoint.md) |
| Need `reasoning_content` | `ainvoke_response()` | [LLM Rich Response](docs/developer/en/09_llm_rich_response_reasoning.md) |
| `reasoning_content` is `None` | provider/model does not expose it | [LLM Rich Response](docs/developer/en/09_llm_rich_response_reasoning.md) |
| Too many LLM calls | deterministic routing, concurrency, cache | [Performance](docs/developer/en/10_performance_cache_and_async_runtime.md) |
| Deadlock across event loops | cross-loop runtime/sequence | [Performance](docs/developer/en/10_performance_cache_and_async_runtime.md) |
| Logs/traces do not correlate the same agent | labels, IDs, observability mapping | [Observability](docs/developer/en/11_observability_persistence_and_operational_readiness.md) |
| Historical example no longer compiles | stale docs vs current API | [README Alignment Validation](docs/developer/en/VALIDATION_README_ALIGNMENT.md) |
| Need to create a new agent from scratch | complete flow | [`README_en.md`](README_en.md) |
### 34. Advanced Features
### [01 — Architecture and Concepts](docs/developer/en/01_architecture_and_concepts.md)
**What it is:** component, contract and responsibility-boundary reference.
**Use it when:** understanding the platform or deciding where a feature belongs.
### [02 — Routing, Route Stickiness and Intent Shift](docs/developer/en/02_routing_stickiness_and_intent_shift.md)
**What it is:** agent/intent discovery, stickiness, handoff and intent-shift reference.
**Use it when:** routing is wrong or session continuity behaves incorrectly.
### [03 — Transactional Workflows and State](docs/developer/en/03_transaction_workflows_and_state.md)
**What it is:** multi-turn transaction lifecycle, states, confirmation, resume and execution evidence.
**Use it when:** transactions loop, resume incorrectly or perform critical operations.
### [04 — MCP, Tools, Policies and Parameter Extraction](docs/developer/en/04_mcp_integration_tools_and_policies.md)
**What it is:** tools, MCP Servers, mappings, policies and extraction reference.
**Use it when:** building or troubleshooting tool integration.
### [05 — Agent Gateway, MCP Gateway and Authentication](docs/developer/en/05_agent_gateway_mcp_gateway_and_auth.md)
**What it is:** gateway responsibilities, governance and component authentication.
**Use it when:** troubleshooting ingress, catalog, authorization or gateway deployment.
### [06 — Guardrails, Judges and Transaction Evaluation](docs/developer/en/06_guardrails_judges_and_transaction_evaluation.md)
**What it is:** native/external validation, judges, grounding and transaction evaluation.
**Use it when:** validation blocks, skips or evaluates incorrectly.
### [07 — RAG, BusinessContext and Grounding](docs/developer/en/07_rag_business_context_and_grounding.md)
**What it is:** RAG providers, retrieved context, BusinessContext and grounding.
**Use it when:** retrieved knowledge does not reach the runtime/judge correctly.
### [08 — Long-Term Memory and Checkpoint](docs/developer/en/08_long_term_memory_and_checkpoint.md)
**What it is:** durable memory, conversational memory, identity and state snapshots.
**Use it when:** context disappears, leaks or resumes incorrectly.
### [09 — LLM Rich Response and reasoning_content](docs/developer/en/09_llm_rich_response_reasoning.md)
**What it is:** structured inference output beyond the `str` returned by `ainvoke()`.
**Use it when:** consumers require provider metadata, usage or reasoning exposed by the provider.
### [10 — Performance, Cache and Async Runtime](docs/developer/en/10_performance_cache_and_async_runtime.md)
**What it is:** concurrency, caching, LLM and event-loop optimization reference.
**Use it when:** reducing avoidable latency or diagnosing deadlocks.
### [11 — Observability, Persistence and Operational Readiness](docs/developer/en/11_observability_persistence_and_operational_readiness.md)
**What it is:** correlation, events, labels, sequencing, persistence and production diagnostics.
**Use it when:** proving execution paths or diagnosing production behavior.
### [12 — Input Guardrail Feedback and Blocked-Turn Semantics](docs/developer/en/12_input_guardrail_feedback_and_blocked_turns.md)
**What it is:** user-facing semantics for input blocks, blocked-turn state cleanup, and output-guardrail validation of the generated feedback.
**Use it when:** `COER`/input guardrails generate generic messages, `route=blocked` carries stale results, or you need to reason about precedence between input guardrails, routing, and tools.
### Main tutorial
[`README_en.md`](README_en.md) remains the complete step-by-step guide.
| Workflow completes and generates a protocol, but the final response becomes a safety message | `expected_protocols`, `CMP`, `DLEX_OUT`, `output_guardrails` ordering | [Guardrails and Judges](docs/developer/en/06_guardrails_judges_and_transaction_evaluation.md) |

View File

@@ -160,7 +160,7 @@ class AgentWorkflow:
builder.add_conditional_edges( builder.add_conditional_edges(
"input_guardrails", "input_guardrails",
self._after_input_guardrails, self._after_input_guardrails,
{"blocked": "persist", "continue": "load_long_term_memory"}, {"blocked": "output_guardrails", "continue": "load_long_term_memory"},
) )
builder.add_edge("load_long_term_memory", "routing_decision") builder.add_edge("load_long_term_memory", "routing_decision")
builder.add_conditional_edges( builder.add_conditional_edges(
@@ -197,6 +197,31 @@ class AgentWorkflow:
def _after_input_guardrails(self, state): def _after_input_guardrails(self, state):
return "blocked" if state.get("blocked") else "continue" return "blocked" if state.get("blocked") else "continue"
@staticmethod
def _input_guardrail_user_message(decisions, state, sanitized_text):
# Keep the technical guardrail reason in telemetry, but expose only a
# safe, actionable message to the end user. The message is intentionally
# routed through output_guardrails before persistence/delivery.
blocked = [d for d in decisions if not getattr(d, "allowed", True)]
first = blocked[0] if blocked else None
code = str(getattr(first, "code", "") or "").upper()
if code == "COER":
return (
"Não consegui entender sua última mensagem porque ela parece "
"incompleta ou ambígua. Pode reformular ou completar o que você quis dizer?"
)
if code == "INPUT_SIZE":
return "Sua mensagem ficou muito longa para eu processar de uma vez. Pode resumir ou dividir em partes?"
if code == "DLEX_IN":
return "Não posso usar essa informação da forma solicitada. Reformule o pedido sem incluir dados ou conteúdo restrito."
if code == "PINJ":
return "Não posso seguir instruções que tentem alterar as regras do atendimento. Posso continuar ajudando com a sua solicitação."
if code == "TOX":
return "Não consegui prosseguir com essa mensagem. Pode reformular o pedido para continuarmos o atendimento?"
if code == "CMP":
return "Não posso prosseguir com essa solicitação dessa forma. Posso ajudar com uma alternativa permitida."
return "Não consegui processar essa mensagem. Pode reformular para eu continuar o atendimento?"
async def input_guardrails(self, state): async def input_guardrails(self, state):
if state.get("session_ended") is True: if state.get("session_ended") is True:
answer = str(getattr( answer = str(getattr(
@@ -281,12 +306,33 @@ class AgentWorkflow:
component="workflow.input_guardrails.final", component="workflow.input_guardrails.final",
) )
if any(not d.allowed for d in decisions): if any(not d.allowed for d in decisions):
# A blocking input guardrail stops the turn before routing/tools.
# Clear turn-local routing/tool state so stale data from a prior
# turn cannot appear as if it was executed after the block.
user_message = self._input_guardrail_user_message(decisions, state, sanitized)
return { return {
"sanitized_input": sanitized, "sanitized_input": sanitized,
"answer": "Não consegui seguir com essa mensagem por regra de segurança.", "answer": user_message,
"final_answer": "Não consegui seguir com essa mensagem por regra de segurança.", "final_answer": None,
"guardrail_decisions": [d.model_dump() for d in decisions], "guardrail_decisions": [d.model_dump() for d in decisions],
"route": "blocked", "route": "blocked",
"intent": "input_guardrail_blocked",
"route_decision": {
"route": "blocked",
"agent": None,
"intent": "input_guardrail_blocked",
"confidence": 1.0,
"reason": "Entrada interrompida por guardrail antes do roteamento.",
"method": "guardrail",
"next_state": state.get("next_state"),
"handoff": False,
"metadata": {},
"domain": state.get("domain"),
"mcp_tools": [],
},
"mcp_tools": [],
"mcp_results": [],
"judge_results": [],
"blocked": True, "blocked": True,
} }
return { return {

View File

@@ -7,6 +7,35 @@ router:
confidence_threshold: 0.65 confidence_threshold: 0.65
allow_handoff: true allow_handoff: true
transaction_confirmation:
# Explicit yes/no stays deterministic. Only inconclusive replies use this LLM fallback.
semantic_fallback:
enabled: true
allowed_values: [SIM, NAO, CONTINUAR]
confirm_values: [SIM]
reject_values: [NAO]
continue_values: [CONTINUAR]
include_relevant_context: true
profile_name: router
prompt: |
Você classifica a resposta do cliente a uma confirmação transacional pendente.
Considere a pergunta pendente, somente o histórico recente relacionado ao mesmo tema e a fala atual.
Não execute a ação e não invente fatos.
Classes permitidas: {{ allowed_values }}
- SIM: confirmação/aceite inequívoco, inclusive equivalentes como "isso mesmo", "pode confirmar", "é isso" quando o contexto tornar o aceite claro.
- NAO: recusa/cancelamento inequívoco da ação pendente.
- CONTINUAR: qualquer resposta que não confirme nem rejeite inequivocamente, incluindo pergunta adicional, correção, novo dado, ambiguidade ou possível mudança de assunto.
Pergunta pendente:
{{ pending_prompt }}
Histórico relevante:
{{ relevant_conversation_context }}
Resposta atual do cliente:
{{ user_input }}
state_policies: state_policies:
- state: WAITING_BILLING_CONFIRMATION - state: WAITING_BILLING_CONFIRMATION
agent: billing_agent agent: billing_agent

View File

@@ -4,8 +4,16 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
invoice_id: string type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
invoice_id:
type: string
label: o identificador da fatura
description: Identificador da fatura que o cliente deseja consultar.
user_prompt: Informe o identificador da fatura que deseja consultar.
selection_keywords: selection_keywords:
- fatura - fatura
- conta - conta
@@ -18,7 +26,11 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
selection_keywords: selection_keywords:
- pagamento - pagamento
- pagamentos - pagamentos
@@ -27,8 +39,16 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
asset_id: string type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
asset_id:
type: string
label: o identificador do plano ou ativo
description: Identificador do plano ou ativo comercial associado ao cliente.
user_prompt: Informe o identificador do plano ou ativo que deseja consultar.
selection_keywords: selection_keywords:
- plano - plano
response: response:
@@ -39,7 +59,11 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
selection_keywords: selection_keywords:
- serviços - serviços
- servicos - servicos
@@ -49,8 +73,16 @@ tools:
mcp_server: retail mcp_server: retail
enabled: true enabled: true
args_schema: args_schema:
order_id: string order_id:
customer_id: string type: string
label: o número do pedido
description: Identificador do pedido que o cliente deseja consultar.
user_prompt: Informe o número do pedido que deseja consultar.
customer_id:
type: string
label: a identificação do cliente
description: Identificador do cliente associado ao pedido de varejo.
user_prompt: Informe a identificação do cliente.
selection_keywords: selection_keywords:
- consultar pedido - consultar pedido
- status do pedido - status do pedido
@@ -63,7 +95,11 @@ tools:
mcp_server: retail mcp_server: retail
enabled: true enabled: true
args_schema: args_schema:
order_id: string order_id:
type: string
label: o número do pedido
description: Identificador do pedido cuja entrega ou rastreamento será consultado.
user_prompt: Informe o número do pedido que deseja rastrear.
selection_keywords: selection_keywords:
- entrega - entrega
- rastreio - rastreio
@@ -82,7 +118,11 @@ tools:
- order_id - order_id
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
type: string
label: o número do pedido
description: Identificador do pedido que o cliente deseja cancelar.
user_prompt: Informe o número do pedido que deseja cancelar.
selection_keywords: selection_keywords:
- cancelar pedido - cancelar pedido
- cancelamento do pedido - cancelamento do pedido
@@ -100,8 +140,16 @@ tools:
- reason - reason
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
reason: string type: string
label: o número do pedido
description: Identificador do pedido para o qual o cliente deseja solicitar troca.
user_prompt: Informe o número do pedido que deseja trocar.
reason:
type: string
label: o motivo da troca
description: Motivo informado pelo cliente para solicitar a troca do pedido.
user_prompt: Qual é o motivo da troca?
selection_keywords: selection_keywords:
- solicitar troca - solicitar troca
- trocar - trocar
@@ -118,8 +166,16 @@ tools:
- reason - reason
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
reason: string type: string
label: o número do pedido
description: Identificador do pedido para o qual o cliente deseja solicitar devolução.
user_prompt: Informe o número do pedido que deseja devolver.
reason:
type: string
label: o motivo da devolução
description: Motivo informado pelo cliente para solicitar a devolução do pedido.
user_prompt: Qual é o motivo da devolução?
selection_keywords: selection_keywords:
- solicitar devolução - solicitar devolução
- solicitar devolucao - solicitar devolucao

View File

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

View File

@@ -1,211 +0,0 @@
###############################################################################
# AI AGENT PLATFORM - CONFIGURAÇÃO ÚNICA
# Este arquivo é lido por Pydantic Settings no framework e no backend template.
###############################################################################
APP_NAME=ai-agent-template
APP_ENV=local
LOG_LEVEL=INFO
API_HOST=0.0.0.0
API_PORT=8000
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
###############################################################################
# LLM - OCI Generative AI como provider principal
###############################################################################
# Opções: mock, oci_openai, oci_sdk, openai_compatible
LLM_PROVIDER=oci_sdk
LLM_TEMPERATURE=0.2
LLM_MAX_TOKENS=2048
LLM_TIMEOUT_SECONDS=120
# OCI OpenAI-compatible endpoint
OCI_GENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com
OCI_GENAI_MODEL=openai.gpt-4.1
OCI_GENAI_API_KEY=sk-ph3FgX6iP3fxAQCXb9IpPIDTadkeeYAWntUWhzcWysIM6zsS
OCI_GENAI_PROJECT_OCID=
#OCI_GENAI_BASE_URL=https://pegruagntaiatenddev.pe.inference.generativeai.sa-saopaulo-1.oci.oraclecloud.com
#OCI_GENAI_MODEL=openai.gpt-4.1
#OCI_GENAI_API_KEY=
#OCI_GENAI_PROJECT_OCID=
# OCI_AUTH_MODE=config_file|instance_principal|resource_principal
OCI_AUTH_MODE=config_file
# OCI SDK / signer / profiles
OCI_CONFIG_FILE=~/.oci/config
OCI_PROFILE=LATINOAMERICA-Chicago
OCI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaexpiw4a7dio64mkfv2t273s2hgdl6mgfvvyv7tycalnjlvpvfl3q
OCI_REGION=us-chicago-1
###############################################################################
# Persistência
###############################################################################
# Opções: memory, autonomous, mongodb
SESSION_REPOSITORY_PROVIDER=autonomous
MEMORY_REPOSITORY_PROVIDER=autonomous
CHECKPOINT_REPOSITORY_PROVIDER=autonomous
# Autonomous Database
ADB_USER=admin
ADB_PASSWORD=Moniquinha19721972
ADB_DSN=oradb23ai_high
ADB_WALLET_LOCATION=/mnt/d/Dropbox/ORACLE/LatinoAmerica/Wallet_ORADB23ai
ADB_WALLET_PASSWORD=Moniquinha1972
ADB_TABLE_PREFIX=AGENTFW
# MongoDB - também pode representar Autonomous usando API compatível com Mongo, se habilitada no ambiente
MONGODB_URI=mongodb://mongo:mongopassword@localhost:27017
MONGODB_DATABASE=agent_platform
# Redis
REDIS_URL=redis://localhost:6379/0
ENABLE_REDIS_CACHE=false
###############################################################################
# RAG / Vector / Graph
###############################################################################
VECTOR_STORE_PROVIDER=autonomous
GRAPH_STORE_PROVIDER=autonomous
RAG_TOP_K=5
EMBEDDING_PROVIDER=oci
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
###############################################################################
# Observabilidade
###############################################################################
ENABLE_LANGFUSE=true
# Opcional: verbose, compact
LANGFUSE_TRACE_MODE=compact
# Nome customizado do trace pai, ex.: backoffice.checklist.workflow ou backoffice.emulador.workflow
LANGFUSE_COMPACT_VISIBLE_EVENT_PREFIXES=AGA.,NOC., IC.
LANGFUSE_COMPACT_SUPPRESSED_PREFIXES=llm.chat_completion
LANGFUSE_IGNORE_HEALTHCHECKS=true
LANGFUSE_IGNORED_PATHS=/health,/ready,/metrics
LANGFUSE_PUBLIC_KEY=pk-lf-4a1e3921-5158-4fd3-a16d-7a77549fb312
LANGFUSE_SECRET_KEY=sk-lf-efc6fd59-c5ec-4858-b6ec-4aa129734915
LANGFUSE_HOST=http://localhost:3005
ENABLE_OTEL=false
OTEL_EXPORTER_OTLP_ENDPOINT=
OTEL_SERVICE_NAME=ai-agent-template
ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=true
ENABLE_LANGFUSE_ANALYTICS_PUBLISHER=false
###############################################################################
# Analytics / Observer corporativo
###############################################################################
# Quando true, AgentObserver publica eventos IC.*, NOC.* e GRL.* nos providers abaixo.
ENABLE_ANALYTICS=false
# Providers aceitos: oci_streaming,pubsub,noop
ANALYTICS_PROVIDERS=oci_streaming
# Compatibilidade FIRST/TIM: pode informar AGENT_PUBSUB_TOPIC diretamente.
AGENT_PUBSUB_TOPIC=
GCP_PUBSUB_TOPIC_PATH=
GCP_PROJECT_ID=
GCP_PUBSUB_TOPIC=
GCP_PUBSUB_TIMEOUT_SECONDS=30
# Credencial GCP segue padrão Google:
# GOOGLE_APPLICATION_CREDENTIALS=/secrets/gcp-service-account.json
###############################################################################
# OCI Streaming
###############################################################################
ENABLE_OCI_STREAMING=false
OCI_STREAM_ENDPOINT=
OCI_STREAM_OCID=
OCI_STREAM_PARTITION_KEY=agent-events
###############################################################################
# Guardrails, Judges, Supervisor
###############################################################################
ENABLE_INPUT_GUARDRAILS=true
ENABLE_OUTPUT_GUARDRAILS=true
ENABLE_JUDGES=true
ENABLE_SUPERVISOR=true
ENABLE_OUTPUT_SUPERVISOR=true
ENABLE_PARALLEL_GUARDRAILS=true
GUARDRAILS_FAIL_FAST=true
OUTPUT_SUPERVISOR_MAX_RETRIES=3
GUARDRAILS_CONFIG_PATH=./config/guardrails.yaml
JUDGES_CONFIG_PATH=./config/judges.yaml
PROMPT_POLICY_PATH=./config/prompt_policy.yaml
###############################################################################
# Gateway de canais
###############################################################################
DEFAULT_CHANNEL=web
# embedded = backend may parse simple/native channel payloads.
# external = backend only accepts GatewayRequest normalized by an external Channel Gateway.
FRAMEWORK_CHANNEL_INPUT_MODE=embedded
ENABLE_VOICE_ADAPTER=true
ENABLE_WHATSAPP_ADAPTER=true
ENABLE_TEXT_ADAPTER=true
#################################################
# ENTERPRISE ROUTING
#################################################
# Arquivo YAML com intents, keywords, políticas de estado e fallback.
ROUTING_CONFIG_PATH=./config/routing.yaml
# true = usa LLM para classificar quando keywords/estado não resolverem.
# Em produção, costuma ser útil; em desenvolvimento, false evita custo e latência.
ENABLE_LLM_ROUTER=true
# Semantic route stickiness (optional).
# Uses a lightweight LLM profile to decide only CONTINUE vs ROUTE.
# There are no regexes or deterministic language rules.
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_TRANSACTIONAL_WORKFLOWS=true
WORKFLOWS_PATH=./workflows
###############################################################################
# MCP / Tools
###############################################################################
ENABLE_MCP_TOOLS=true
MCP_SERVERS_CONFIG_PATH=./config/mcp_servers.yaml
TOOLS_CONFIG_PATH=./config/tools.yaml
MCP_TOOL_TIMEOUT_SECONDS=30
# router = EnterpriseRouter seleciona um agente; supervisor = pode acionar múltiplos agentes
ROUTING_MODE=router
# Usage/cost accounting
USAGE_REPOSITORY_PROVIDER=autonomous
IDENTITY_CONFIG_PATH=./config/identity.yaml
MCP_PARAMETER_MAPPING_PATH=./config/mcp_parameter_mapping.yaml
# -----------------------------------------------------------------------------
# ConversationSummaryMemory / compressão de contexto conversacional
# -----------------------------------------------------------------------------
ENABLE_CONVERSATION_SUMMARY_MEMORY=true
MEMORY_CONTEXT_STRATEGY=summary
MEMORY_HISTORY_LIMIT=80
MEMORY_RECENT_MESSAGES_LIMIT=8
MEMORY_SUMMARY_TRIGGER_MESSAGES=20
MEMORY_MAX_SUMMARY_CHARS=6000
MEMORY_SUMMARY_USE_LLM=true
MEMORY_INJECT_RECENT_MESSAGES=true
MEMORY_INJECT_SUMMARY=true
###############################################################################
# LONG-TERM MEMORY
###############################################################################
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
# For Autonomous/Oracle, defaults to ${ADB_TABLE_PREFIX}_LONG_TERM_MEMORY
# LONG_TERM_MEMORY_ORACLE_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
ENABLE_TRANSACTIONAL_WORKFLOWS=true
WORKFLOWS_PATH=./workflows

View File

@@ -160,7 +160,7 @@ class AgentWorkflow:
builder.add_conditional_edges( builder.add_conditional_edges(
"input_guardrails", "input_guardrails",
self._after_input_guardrails, self._after_input_guardrails,
{"blocked": "persist", "continue": "load_long_term_memory"}, {"blocked": "output_guardrails", "continue": "load_long_term_memory"},
) )
builder.add_edge("load_long_term_memory", "routing_decision") builder.add_edge("load_long_term_memory", "routing_decision")
builder.add_conditional_edges( builder.add_conditional_edges(
@@ -197,6 +197,31 @@ class AgentWorkflow:
def _after_input_guardrails(self, state): def _after_input_guardrails(self, state):
return "blocked" if state.get("blocked") else "continue" return "blocked" if state.get("blocked") else "continue"
@staticmethod
def _input_guardrail_user_message(decisions, state, sanitized_text):
# Keep the technical guardrail reason in telemetry, but expose only a
# safe, actionable message to the end user. The message is intentionally
# routed through output_guardrails before persistence/delivery.
blocked = [d for d in decisions if not getattr(d, "allowed", True)]
first = blocked[0] if blocked else None
code = str(getattr(first, "code", "") or "").upper()
if code == "COER":
return (
"Não consegui entender sua última mensagem porque ela parece "
"incompleta ou ambígua. Pode reformular ou completar o que você quis dizer?"
)
if code == "INPUT_SIZE":
return "Sua mensagem ficou muito longa para eu processar de uma vez. Pode resumir ou dividir em partes?"
if code == "DLEX_IN":
return "Não posso usar essa informação da forma solicitada. Reformule o pedido sem incluir dados ou conteúdo restrito."
if code == "PINJ":
return "Não posso seguir instruções que tentem alterar as regras do atendimento. Posso continuar ajudando com a sua solicitação."
if code == "TOX":
return "Não consegui prosseguir com essa mensagem. Pode reformular o pedido para continuarmos o atendimento?"
if code == "CMP":
return "Não posso prosseguir com essa solicitação dessa forma. Posso ajudar com uma alternativa permitida."
return "Não consegui processar essa mensagem. Pode reformular para eu continuar o atendimento?"
async def input_guardrails(self, state): async def input_guardrails(self, state):
if state.get("session_ended") is True: if state.get("session_ended") is True:
answer = str(getattr( answer = str(getattr(
@@ -281,12 +306,33 @@ class AgentWorkflow:
component="workflow.input_guardrails.final", component="workflow.input_guardrails.final",
) )
if any(not d.allowed for d in decisions): if any(not d.allowed for d in decisions):
# A blocking input guardrail stops the turn before routing/tools.
# Clear turn-local routing/tool state so stale data from a prior
# turn cannot appear as if it was executed after the block.
user_message = self._input_guardrail_user_message(decisions, state, sanitized)
return { return {
"sanitized_input": sanitized, "sanitized_input": sanitized,
"answer": "Não consegui seguir com essa mensagem por regra de segurança.", "answer": user_message,
"final_answer": "Não consegui seguir com essa mensagem por regra de segurança.", "final_answer": None,
"guardrail_decisions": [d.model_dump() for d in decisions], "guardrail_decisions": [d.model_dump() for d in decisions],
"route": "blocked", "route": "blocked",
"intent": "input_guardrail_blocked",
"route_decision": {
"route": "blocked",
"agent": None,
"intent": "input_guardrail_blocked",
"confidence": 1.0,
"reason": "Entrada interrompida por guardrail antes do roteamento.",
"method": "guardrail",
"next_state": state.get("next_state"),
"handoff": False,
"metadata": {},
"domain": state.get("domain"),
"mcp_tools": [],
},
"mcp_tools": [],
"mcp_results": [],
"judge_results": [],
"blocked": True, "blocked": True,
} }
return { return {

View File

@@ -7,6 +7,35 @@ router:
confidence_threshold: 0.65 confidence_threshold: 0.65
allow_handoff: true allow_handoff: true
transaction_confirmation:
# Explicit yes/no stays deterministic. Only inconclusive replies use this LLM fallback.
semantic_fallback:
enabled: true
allowed_values: [SIM, NAO, CONTINUAR]
confirm_values: [SIM]
reject_values: [NAO]
continue_values: [CONTINUAR]
include_relevant_context: true
profile_name: router
prompt: |
Você classifica a resposta do cliente a uma confirmação transacional pendente.
Considere a pergunta pendente, somente o histórico recente relacionado ao mesmo tema e a fala atual.
Não execute a ação e não invente fatos.
Classes permitidas: {{ allowed_values }}
- SIM: confirmação/aceite inequívoco, inclusive equivalentes como "isso mesmo", "pode confirmar", "é isso" quando o contexto tornar o aceite claro.
- NAO: recusa/cancelamento inequívoco da ação pendente.
- CONTINUAR: qualquer resposta que não confirme nem rejeite inequivocamente, incluindo pergunta adicional, correção, novo dado, ambiguidade ou possível mudança de assunto.
Pergunta pendente:
{{ pending_prompt }}
Histórico relevante:
{{ relevant_conversation_context }}
Resposta atual do cliente:
{{ user_input }}
state_policies: state_policies:
- state: WAITING_BILLING_CONFIRMATION - state: WAITING_BILLING_CONFIRMATION
agent: billing_agent agent: billing_agent

View File

@@ -4,8 +4,16 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
invoice_id: string type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
invoice_id:
type: string
label: o identificador da fatura
description: Identificador da fatura que o cliente deseja consultar.
user_prompt: Informe o identificador da fatura que deseja consultar.
selection_keywords: selection_keywords:
- fatura - fatura
- conta - conta
@@ -18,7 +26,11 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
selection_keywords: selection_keywords:
- pagamento - pagamento
- pagamentos - pagamentos
@@ -27,8 +39,16 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
asset_id: string type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
asset_id:
type: string
label: o identificador do plano ou ativo
description: Identificador do plano ou ativo comercial associado ao cliente.
user_prompt: Informe o identificador do plano ou ativo que deseja consultar.
selection_keywords: selection_keywords:
- plano - plano
response: response:
@@ -39,7 +59,11 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
selection_keywords: selection_keywords:
- serviços - serviços
- servicos - servicos
@@ -49,8 +73,16 @@ tools:
mcp_server: retail mcp_server: retail
enabled: true enabled: true
args_schema: args_schema:
order_id: string order_id:
customer_id: string type: string
label: o número do pedido
description: Identificador do pedido que o cliente deseja consultar.
user_prompt: Informe o número do pedido que deseja consultar.
customer_id:
type: string
label: a identificação do cliente
description: Identificador do cliente associado ao pedido de varejo.
user_prompt: Informe a identificação do cliente.
selection_keywords: selection_keywords:
- consultar pedido - consultar pedido
- status do pedido - status do pedido
@@ -63,7 +95,11 @@ tools:
mcp_server: retail mcp_server: retail
enabled: true enabled: true
args_schema: args_schema:
order_id: string order_id:
type: string
label: o número do pedido
description: Identificador do pedido cuja entrega ou rastreamento será consultado.
user_prompt: Informe o número do pedido que deseja rastrear.
selection_keywords: selection_keywords:
- entrega - entrega
- rastreio - rastreio
@@ -82,7 +118,11 @@ tools:
- order_id - order_id
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
type: string
label: o número do pedido
description: Identificador do pedido que o cliente deseja cancelar.
user_prompt: Informe o número do pedido que deseja cancelar.
selection_keywords: selection_keywords:
- cancelar pedido - cancelar pedido
- cancelamento do pedido - cancelamento do pedido
@@ -100,8 +140,16 @@ tools:
- reason - reason
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
reason: string type: string
label: o número do pedido
description: Identificador do pedido para o qual o cliente deseja solicitar troca.
user_prompt: Informe o número do pedido que deseja trocar.
reason:
type: string
label: o motivo da troca
description: Motivo informado pelo cliente para solicitar a troca do pedido.
user_prompt: Qual é o motivo da troca?
selection_keywords: selection_keywords:
- solicitar troca - solicitar troca
- trocar - trocar
@@ -118,8 +166,16 @@ tools:
- reason - reason
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
reason: string type: string
label: o número do pedido
description: Identificador do pedido para o qual o cliente deseja solicitar devolução.
user_prompt: Informe o número do pedido que deseja devolver.
reason:
type: string
label: o motivo da devolução
description: Motivo informado pelo cliente para solicitar a devolução do pedido.
user_prompt: Qual é o motivo da devolução?
selection_keywords: selection_keywords:
- solicitar devolução - solicitar devolução
- solicitar devolucao - solicitar devolucao

View File

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

View File

@@ -1,195 +0,0 @@
###############################################################################
# AI AGENT PLATFORM - CONFIGURAÇÃO ÚNICA
# Este arquivo é lido por Pydantic Settings no framework e no backend template.
###############################################################################
APP_NAME=ai-agent-template
APP_ENV=local
LOG_LEVEL=INFO
API_HOST=0.0.0.0
API_PORT=8000
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
###############################################################################
# LLM - OCI Generative AI como provider principal
###############################################################################
# Opções: mock, oci_openai, oci_sdk, openai_compatible
LLM_PROVIDER=oci_openai
LLM_TEMPERATURE=0.2
LLM_MAX_TOKENS=2048
LLM_TIMEOUT_SECONDS=120
# OCI OpenAI-compatible endpoint
OCI_GENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/openai/v1
OCI_GENAI_MODEL=openai.gpt-4.1
OCI_GENAI_API_KEY=sk-ph3FgX6ph3FgX6ph3FgX6ph3FgX6ph3FgX6ph3FgX6
OCI_GENAI_PROJECT_OCID=
# OCI SDK / signer / profiles
OCI_CONFIG_FILE=~/.oci/config
OCI_PROFILE=DEFAULT
OCI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
OCI_REGION=us-chicago-1
###############################################################################
# Persistência
###############################################################################
# Opções: memory, autonomous, mongodb
SESSION_REPOSITORY_PROVIDER=sqlite
MEMORY_REPOSITORY_PROVIDER=sqlite
CHECKPOINT_REPOSITORY_PROVIDER=sqlite
SQLITE_DB_PATH=./data/agent_framework.db
# Autonomous Database
ADB_USER=admin
ADB_PASSWORD=fjhsdf04954hf
ADB_DSN=oradb23aidev_high
ADB_WALLET_LOCATION=/ORACLE/DEFAULT/Wallet_ORADB23aiDev
ADB_WALLET_PASSWORD=fjhsdf04954hf
ADB_TABLE_PREFIX=AGENTFW
# MongoDB - também pode representar Autonomous usando API compatível com Mongo, se habilitada no ambiente
MONGODB_URI=mongodb://mongo:mongopassword@localhost:27017
MONGODB_DATABASE=agent_platform
# Redis
REDIS_URL=redis://localhost:6379/0
ENABLE_REDIS_CACHE=false
###############################################################################
# RAG / Vector / Graph
###############################################################################
VECTOR_STORE_PROVIDER=sqlite
GRAPH_STORE_PROVIDER=sqlite
RAG_TOP_K=5
EMBEDDING_PROVIDER=mock
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
###############################################################################
# Observabilidade
###############################################################################
ENABLE_LANGFUSE=true
LANGFUSE_TRACE_MODE=compact # Opcional: verbose, compact
LANGFUSE_PUBLIC_KEY=pk-lf-2f9da109-5b0f-4c78-b61d-9598ed787eba
LANGFUSE_SECRET_KEY=sk-lf-a4cb0cdd-f2ea-4468-9911-cebeb91ba944
LANGFUSE_HOST=http://localhost:3005
ENABLE_OTEL=false
OTEL_EXPORTER_OTLP_ENDPOINT=
OTEL_SERVICE_NAME=ai-agent-template
ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=true
###############################################################################
# Analytics / Observer corporativo
###############################################################################
# Quando true, AgentObserver publica eventos IC.*, NOC.* e GRL.* nos providers abaixo.
ENABLE_ANALYTICS=false
# Providers aceitos: oci_streaming,pubsub,noop
ANALYTICS_PROVIDERS=pubsub
# Compatibilidade FIRST/TIM: pode informar AGENT_PUBSUB_TOPIC diretamente.
AGENT_PUBSUB_TOPIC=
GCP_PUBSUB_TOPIC_PATH=
GCP_PROJECT_ID=
GCP_PUBSUB_TOPIC=
GCP_PUBSUB_TIMEOUT_SECONDS=30
# Credencial GCP segue padrão Google:
# GOOGLE_APPLICATION_CREDENTIALS=/secrets/gcp-service-account.json
###############################################################################
# OCI Streaming
###############################################################################
ENABLE_OCI_STREAMING=false
OCI_STREAM_ENDPOINT=
OCI_STREAM_OCID=
OCI_STREAM_PARTITION_KEY=agent-events
###############################################################################
# Guardrails, Judges, Supervisor
###############################################################################
ENABLE_INPUT_GUARDRAILS=true
ENABLE_OUTPUT_GUARDRAILS=true
ENABLE_JUDGES=true
ENABLE_SUPERVISOR=true
ENABLE_OUTPUT_SUPERVISOR=true
ENABLE_PARALLEL_GUARDRAILS=true
GUARDRAILS_FAIL_FAST=true
OUTPUT_SUPERVISOR_MAX_RETRIES=3
GUARDRAILS_CONFIG_PATH=./config/guardrails.yaml
JUDGES_CONFIG_PATH=./config/judges.yaml
PROMPT_POLICY_PATH=./config/prompt_policy.yaml
###############################################################################
# Gateway de canais
###############################################################################
DEFAULT_CHANNEL=web
# embedded = backend may parse simple/native channel payloads.
# external = backend only accepts GatewayRequest normalized by an external Channel Gateway.
FRAMEWORK_CHANNEL_INPUT_MODE=embedded
ENABLE_VOICE_ADAPTER=true
ENABLE_WHATSAPP_ADAPTER=true
ENABLE_TEXT_ADAPTER=true
#################################################
# ENTERPRISE ROUTING
#################################################
# Arquivo YAML com intents, keywords, políticas de estado e fallback.
ROUTING_CONFIG_PATH=./config/routing.yaml
# true = usa LLM para classificar quando keywords/estado não resolverem.
# Em produção, costuma ser útil; em desenvolvimento, false evita custo e latência.
ENABLE_LLM_ROUTER=true
###############################################################################
# MCP / Tools
###############################################################################
ENABLE_MCP_TOOLS=true
MCP_SERVERS_CONFIG_PATH=./config/mcp_servers.yaml
TOOLS_CONFIG_PATH=./config/tools.yaml
TOOL_POLICIES_PATH=./config/tool_policies.yaml
MCP_TOOL_TIMEOUT_SECONDS=30
# router = EnterpriseRouter seleciona um agente; supervisor = pode acionar múltiplos agentes
ROUTING_MODE=router
# Usage/cost accounting
USAGE_REPOSITORY_PROVIDER=sqlite
IDENTITY_CONFIG_PATH=./config/identity.yaml
MCP_PARAMETER_MAPPING_PATH=./config/mcp_parameter_mapping.yaml
# -----------------------------------------------------------------------------
# ConversationSummaryMemory / compressão de contexto conversacional
# -----------------------------------------------------------------------------
ENABLE_CONVERSATION_SUMMARY_MEMORY=true
MEMORY_CONTEXT_STRATEGY=summary
MEMORY_HISTORY_LIMIT=80
MEMORY_RECENT_MESSAGES_LIMIT=8
MEMORY_SUMMARY_TRIGGER_MESSAGES=20
MEMORY_MAX_SUMMARY_CHARS=6000
MEMORY_SUMMARY_USE_LLM=true
MEMORY_INJECT_RECENT_MESSAGES=true
MEMORY_INJECT_SUMMARY=true
###############################################################################
# MCP Gateway
###############################################################################
# true = framework routes tool calls to the dedicated MCP Gateway.
# false = framework calls MCP servers directly from mcp_servers.yaml.
MCP_GATEWAY_ENABLED=true
MCP_GATEWAY_URL=http://localhost:8300
MCP_GATEWAY_TIMEOUT_SECONDS=60
# MCP_GATEWAY_TOKEN=
MCP_GATEWAY_AGENT_ID=telecom_contas
MCP_GATEWAY_TENANT_ID=default
###############################################################################
# LONG-TERM MEMORY
###############################################################################
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
# For Autonomous/Oracle, defaults to ${ADB_TABLE_PREFIX}_LONG_TERM_MEMORY
# LONG_TERM_MEMORY_ORACLE_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

View File

@@ -159,7 +159,7 @@ class AgentWorkflow:
builder.add_conditional_edges( builder.add_conditional_edges(
"input_guardrails", "input_guardrails",
self._after_input_guardrails, self._after_input_guardrails,
{"blocked": "persist", "continue": "routing_decision"}, {"blocked": "output_guardrails", "continue": "routing_decision"},
) )
builder.add_conditional_edges( builder.add_conditional_edges(
"routing_decision", "routing_decision",
@@ -195,6 +195,31 @@ class AgentWorkflow:
def _after_input_guardrails(self, state): def _after_input_guardrails(self, state):
return "blocked" if state.get("blocked") else "continue" return "blocked" if state.get("blocked") else "continue"
@staticmethod
def _input_guardrail_user_message(decisions, state, sanitized_text):
# Keep the technical guardrail reason in telemetry, but expose only a
# safe, actionable message to the end user. The message is intentionally
# routed through output_guardrails before persistence/delivery.
blocked = [d for d in decisions if not getattr(d, "allowed", True)]
first = blocked[0] if blocked else None
code = str(getattr(first, "code", "") or "").upper()
if code == "COER":
return (
"Não consegui entender sua última mensagem porque ela parece "
"incompleta ou ambígua. Pode reformular ou completar o que você quis dizer?"
)
if code == "INPUT_SIZE":
return "Sua mensagem ficou muito longa para eu processar de uma vez. Pode resumir ou dividir em partes?"
if code == "DLEX_IN":
return "Não posso usar essa informação da forma solicitada. Reformule o pedido sem incluir dados ou conteúdo restrito."
if code == "PINJ":
return "Não posso seguir instruções que tentem alterar as regras do atendimento. Posso continuar ajudando com a sua solicitação."
if code == "TOX":
return "Não consegui prosseguir com essa mensagem. Pode reformular o pedido para continuarmos o atendimento?"
if code == "CMP":
return "Não posso prosseguir com essa solicitação dessa forma. Posso ajudar com uma alternativa permitida."
return "Não consegui processar essa mensagem. Pode reformular para eu continuar o atendimento?"
async def input_guardrails(self, state): async def input_guardrails(self, state):
if state.get("session_ended") is True: if state.get("session_ended") is True:
answer = str(getattr( answer = str(getattr(
@@ -279,12 +304,33 @@ class AgentWorkflow:
component="workflow.input_guardrails.final", component="workflow.input_guardrails.final",
) )
if any(not d.allowed for d in decisions): if any(not d.allowed for d in decisions):
# A blocking input guardrail stops the turn before routing/tools.
# Clear turn-local routing/tool state so stale data from a prior
# turn cannot appear as if it was executed after the block.
user_message = self._input_guardrail_user_message(decisions, state, sanitized)
return { return {
"sanitized_input": sanitized, "sanitized_input": sanitized,
"answer": "Não consegui seguir com essa mensagem por regra de segurança.", "answer": user_message,
"final_answer": "Não consegui seguir com essa mensagem por regra de segurança.", "final_answer": None,
"guardrail_decisions": [d.model_dump() for d in decisions], "guardrail_decisions": [d.model_dump() for d in decisions],
"route": "blocked", "route": "blocked",
"intent": "input_guardrail_blocked",
"route_decision": {
"route": "blocked",
"agent": None,
"intent": "input_guardrail_blocked",
"confidence": 1.0,
"reason": "Entrada interrompida por guardrail antes do roteamento.",
"method": "guardrail",
"next_state": state.get("next_state"),
"handoff": False,
"metadata": {},
"domain": state.get("domain"),
"mcp_tools": [],
},
"mcp_tools": [],
"mcp_results": [],
"judge_results": [],
"blocked": True, "blocked": True,
} }
return { return {

View File

@@ -7,6 +7,35 @@ router:
confidence_threshold: 0.65 confidence_threshold: 0.65
allow_handoff: true allow_handoff: true
transaction_confirmation:
# Explicit yes/no stays deterministic. Only inconclusive replies use this LLM fallback.
semantic_fallback:
enabled: true
allowed_values: [SIM, NAO, CONTINUAR]
confirm_values: [SIM]
reject_values: [NAO]
continue_values: [CONTINUAR]
include_relevant_context: true
profile_name: router
prompt: |
Você classifica a resposta do cliente a uma confirmação transacional pendente.
Considere a pergunta pendente, somente o histórico recente relacionado ao mesmo tema e a fala atual.
Não execute a ação e não invente fatos.
Classes permitidas: {{ allowed_values }}
- SIM: confirmação/aceite inequívoco, inclusive equivalentes como "isso mesmo", "pode confirmar", "é isso" quando o contexto tornar o aceite claro.
- NAO: recusa/cancelamento inequívoco da ação pendente.
- CONTINUAR: qualquer resposta que não confirme nem rejeite inequivocamente, incluindo pergunta adicional, correção, novo dado, ambiguidade ou possível mudança de assunto.
Pergunta pendente:
{{ pending_prompt }}
Histórico relevante:
{{ relevant_conversation_context }}
Resposta atual do cliente:
{{ user_input }}
state_policies: state_policies:
- state: WAITING_BILLING_CONFIRMATION - state: WAITING_BILLING_CONFIRMATION
agent: billing_agent agent: billing_agent

View File

@@ -4,8 +4,16 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
invoice_id: string type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
invoice_id:
type: string
label: o identificador da fatura
description: Identificador da fatura que o cliente deseja consultar.
user_prompt: Informe o identificador da fatura que deseja consultar.
selection_keywords: selection_keywords:
- fatura - fatura
- conta - conta
@@ -18,7 +26,11 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
selection_keywords: selection_keywords:
- pagamento - pagamento
- pagamentos - pagamentos
@@ -27,8 +39,16 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
asset_id: string type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
asset_id:
type: string
label: o identificador do plano ou ativo
description: Identificador do plano ou ativo comercial associado ao cliente.
user_prompt: Informe o identificador do plano ou ativo que deseja consultar.
selection_keywords: selection_keywords:
- plano - plano
response: response:
@@ -39,7 +59,11 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
selection_keywords: selection_keywords:
- serviços - serviços
- servicos - servicos
@@ -49,8 +73,16 @@ tools:
mcp_server: retail mcp_server: retail
enabled: true enabled: true
args_schema: args_schema:
order_id: string order_id:
customer_id: string type: string
label: o número do pedido
description: Identificador do pedido que o cliente deseja consultar.
user_prompt: Informe o número do pedido que deseja consultar.
customer_id:
type: string
label: a identificação do cliente
description: Identificador do cliente associado ao pedido de varejo.
user_prompt: Informe a identificação do cliente.
selection_keywords: selection_keywords:
- consultar pedido - consultar pedido
- status do pedido - status do pedido
@@ -63,7 +95,11 @@ tools:
mcp_server: retail mcp_server: retail
enabled: true enabled: true
args_schema: args_schema:
order_id: string order_id:
type: string
label: o número do pedido
description: Identificador do pedido cuja entrega ou rastreamento será consultado.
user_prompt: Informe o número do pedido que deseja rastrear.
selection_keywords: selection_keywords:
- entrega - entrega
- rastreio - rastreio
@@ -82,7 +118,11 @@ tools:
- order_id - order_id
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
type: string
label: o número do pedido
description: Identificador do pedido que o cliente deseja cancelar.
user_prompt: Informe o número do pedido que deseja cancelar.
selection_keywords: selection_keywords:
- cancelar pedido - cancelar pedido
- cancelamento do pedido - cancelamento do pedido
@@ -100,8 +140,16 @@ tools:
- reason - reason
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
reason: string type: string
label: o número do pedido
description: Identificador do pedido para o qual o cliente deseja solicitar troca.
user_prompt: Informe o número do pedido que deseja trocar.
reason:
type: string
label: o motivo da troca
description: Motivo informado pelo cliente para solicitar a troca do pedido.
user_prompt: Qual é o motivo da troca?
selection_keywords: selection_keywords:
- solicitar troca - solicitar troca
- trocar - trocar
@@ -118,8 +166,16 @@ tools:
- reason - reason
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
reason: string type: string
label: o número do pedido
description: Identificador do pedido para o qual o cliente deseja solicitar devolução.
user_prompt: Informe o número do pedido que deseja devolver.
reason:
type: string
label: o motivo da devolução
description: Motivo informado pelo cliente para solicitar a devolução do pedido.
user_prompt: Qual é o motivo da devolução?
selection_keywords: selection_keywords:
- solicitar devolução - solicitar devolução
- solicitar devolucao - solicitar devolucao

View File

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

View File

@@ -1,207 +0,0 @@
###############################################################################
# AI AGENT PLATFORM - CONFIGURAÇÃO ÚNICA
# Este arquivo é lido por Pydantic Settings no framework e no backend template.
###############################################################################
APP_NAME=ai-agent-template
APP_ENV=local
LOG_LEVEL=INFO
API_HOST=0.0.0.0
API_PORT=8000
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
###############################################################################
# LLM - OCI Generative AI como provider principal
###############################################################################
# Opções: mock, oci_openai, oci_sdk, openai_compatible
LLM_PROVIDER=oci_sdk
LLM_TEMPERATURE=0.2
LLM_MAX_TOKENS=2048
LLM_TIMEOUT_SECONDS=120
# OCI OpenAI-compatible endpoint
OCI_GENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com
OCI_GENAI_MODEL=openai.gpt-4.1
OCI_GENAI_API_KEY=sk-ph3FgX6iP3fxAQCXb9IpPIDTadkeeYAWntUWhzcWysIM6zsS
OCI_GENAI_PROJECT_OCID=
#OCI_GENAI_BASE_URL=https://pegruagntaiatenddev.pe.inference.generativeai.sa-saopaulo-1.oci.oraclecloud.com
#OCI_GENAI_MODEL=openai.gpt-4.1
#OCI_GENAI_API_KEY=
#OCI_GENAI_PROJECT_OCID=
# OCI_AUTH_MODE=config_file|instance_principal|resource_principal
OCI_AUTH_MODE=config_file
# OCI SDK / signer / profiles
OCI_CONFIG_FILE=~/.oci/config
OCI_PROFILE=LATINOAMERICA-Chicago
OCI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaexpiw4a7dio64mkfv2t273s2hgdl6mgfvvyv7tycalnjlvpvfl3q
OCI_REGION=us-chicago-1
###############################################################################
# Persistência
###############################################################################
# Opções: memory, autonomous, mongodb
SESSION_REPOSITORY_PROVIDER=autonomous
MEMORY_REPOSITORY_PROVIDER=autonomous
CHECKPOINT_REPOSITORY_PROVIDER=autonomous
# Autonomous Database
ADB_USER=admin
ADB_PASSWORD=Moniquinha19721972
ADB_DSN=oradb23ai_high
ADB_WALLET_LOCATION=/mnt/d/Dropbox/ORACLE/LatinoAmerica/Wallet_ORADB23ai
ADB_WALLET_PASSWORD=Moniquinha1972
ADB_TABLE_PREFIX=AGENTFW
# MongoDB - também pode representar Autonomous usando API compatível com Mongo, se habilitada no ambiente
MONGODB_URI=mongodb://mongo:mongopassword@localhost:27017
MONGODB_DATABASE=agent_platform
# Redis
REDIS_URL=redis://localhost:6379/0
ENABLE_REDIS_CACHE=false
###############################################################################
# RAG / Vector / Graph
###############################################################################
VECTOR_STORE_PROVIDER=autonomous
GRAPH_STORE_PROVIDER=autonomous
RAG_TOP_K=5
EMBEDDING_PROVIDER=oci
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
###############################################################################
# Observabilidade
###############################################################################
ENABLE_LANGFUSE=true
# Opcional: verbose, compact
LANGFUSE_TRACE_MODE=compact
# Nome customizado do trace pai, ex.: backoffice.checklist.workflow ou backoffice.emulador.workflow
LANGFUSE_COMPACT_VISIBLE_EVENT_PREFIXES=AGA.,NOC., IC.
LANGFUSE_COMPACT_SUPPRESSED_PREFIXES=llm.chat_completion
LANGFUSE_IGNORE_HEALTHCHECKS=true
LANGFUSE_IGNORED_PATHS=/health,/ready,/metrics
LANGFUSE_PUBLIC_KEY=pk-lf-4a1e3921-5158-4fd3-a16d-7a77549fb312
LANGFUSE_SECRET_KEY=sk-lf-efc6fd59-c5ec-4858-b6ec-4aa129734915
LANGFUSE_HOST=http://localhost:3005
ENABLE_OTEL=false
OTEL_EXPORTER_OTLP_ENDPOINT=
OTEL_SERVICE_NAME=ai-agent-template
ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=true
ENABLE_LANGFUSE_ANALYTICS_PUBLISHER=false
###############################################################################
# Analytics / Observer corporativo
###############################################################################
# Quando true, AgentObserver publica eventos IC.*, NOC.* e GRL.* nos providers abaixo.
ENABLE_ANALYTICS=false
# Providers aceitos: oci_streaming,pubsub,noop
ANALYTICS_PROVIDERS=oci_streaming
# Compatibilidade FIRST/TIM: pode informar AGENT_PUBSUB_TOPIC diretamente.
AGENT_PUBSUB_TOPIC=
GCP_PUBSUB_TOPIC_PATH=
GCP_PROJECT_ID=
GCP_PUBSUB_TOPIC=
GCP_PUBSUB_TIMEOUT_SECONDS=30
# Credencial GCP segue padrão Google:
# GOOGLE_APPLICATION_CREDENTIALS=/secrets/gcp-service-account.json
###############################################################################
# OCI Streaming
###############################################################################
ENABLE_OCI_STREAMING=false
OCI_STREAM_ENDPOINT=
OCI_STREAM_OCID=
OCI_STREAM_PARTITION_KEY=agent-events
###############################################################################
# Guardrails, Judges, Supervisor
###############################################################################
ENABLE_INPUT_GUARDRAILS=true
ENABLE_OUTPUT_GUARDRAILS=true
ENABLE_JUDGES=true
ENABLE_SUPERVISOR=true
ENABLE_OUTPUT_SUPERVISOR=true
ENABLE_PARALLEL_GUARDRAILS=true
GUARDRAILS_FAIL_FAST=true
OUTPUT_SUPERVISOR_MAX_RETRIES=3
GUARDRAILS_CONFIG_PATH=./config/guardrails.yaml
JUDGES_CONFIG_PATH=./config/judges.yaml
PROMPT_POLICY_PATH=./config/prompt_policy.yaml
###############################################################################
# Gateway de canais
###############################################################################
DEFAULT_CHANNEL=web
# embedded = backend may parse simple/native channel payloads.
# external = backend only accepts GatewayRequest normalized by an external Channel Gateway.
FRAMEWORK_CHANNEL_INPUT_MODE=embedded
ENABLE_VOICE_ADAPTER=true
ENABLE_WHATSAPP_ADAPTER=true
ENABLE_TEXT_ADAPTER=true
#################################################
# ENTERPRISE ROUTING
#################################################
# Arquivo YAML com intents, keywords, políticas de estado e fallback.
ROUTING_CONFIG_PATH=./config/routing.yaml
# true = usa LLM para classificar quando keywords/estado não resolverem.
# Em produção, costuma ser útil; em desenvolvimento, false evita custo e latência.
ENABLE_LLM_ROUTER=true
# Semantic route stickiness (optional).
# Uses a lightweight LLM profile to decide only CONTINUE vs ROUTE.
# There are no regexes or deterministic language rules.
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.
###############################################################################
# MCP / Tools
###############################################################################
ENABLE_MCP_TOOLS=true
MCP_SERVERS_CONFIG_PATH=./config/mcp_servers.yaml
TOOLS_CONFIG_PATH=./config/tools.yaml
MCP_TOOL_TIMEOUT_SECONDS=30
# router = EnterpriseRouter seleciona um agente; supervisor = pode acionar múltiplos agentes
ROUTING_MODE=router
# Usage/cost accounting
USAGE_REPOSITORY_PROVIDER=autonomous
IDENTITY_CONFIG_PATH=./config/identity.yaml
MCP_PARAMETER_MAPPING_PATH=./config/mcp_parameter_mapping.yaml
# -----------------------------------------------------------------------------
# ConversationSummaryMemory / compressão de contexto conversacional
# -----------------------------------------------------------------------------
ENABLE_CONVERSATION_SUMMARY_MEMORY=true
MEMORY_CONTEXT_STRATEGY=summary
MEMORY_HISTORY_LIMIT=80
MEMORY_RECENT_MESSAGES_LIMIT=8
MEMORY_SUMMARY_TRIGGER_MESSAGES=20
MEMORY_MAX_SUMMARY_CHARS=6000
MEMORY_SUMMARY_USE_LLM=true
MEMORY_INJECT_RECENT_MESSAGES=true
MEMORY_INJECT_SUMMARY=true
###############################################################################
# LONG-TERM MEMORY
###############################################################################
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
# For Autonomous/Oracle, defaults to ${ADB_TABLE_PREFIX}_LONG_TERM_MEMORY
# LONG_TERM_MEMORY_ORACLE_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

View File

@@ -160,7 +160,7 @@ class AgentWorkflow:
builder.add_conditional_edges( builder.add_conditional_edges(
"input_guardrails", "input_guardrails",
self._after_input_guardrails, self._after_input_guardrails,
{"blocked": "persist", "continue": "load_long_term_memory"}, {"blocked": "output_guardrails", "continue": "load_long_term_memory"},
) )
builder.add_edge("load_long_term_memory", "routing_decision") builder.add_edge("load_long_term_memory", "routing_decision")
builder.add_conditional_edges( builder.add_conditional_edges(
@@ -197,6 +197,31 @@ class AgentWorkflow:
def _after_input_guardrails(self, state): def _after_input_guardrails(self, state):
return "blocked" if state.get("blocked") else "continue" return "blocked" if state.get("blocked") else "continue"
@staticmethod
def _input_guardrail_user_message(decisions, state, sanitized_text):
# Keep the technical guardrail reason in telemetry, but expose only a
# safe, actionable message to the end user. The message is intentionally
# routed through output_guardrails before persistence/delivery.
blocked = [d for d in decisions if not getattr(d, "allowed", True)]
first = blocked[0] if blocked else None
code = str(getattr(first, "code", "") or "").upper()
if code == "COER":
return (
"Não consegui entender sua última mensagem porque ela parece "
"incompleta ou ambígua. Pode reformular ou completar o que você quis dizer?"
)
if code == "INPUT_SIZE":
return "Sua mensagem ficou muito longa para eu processar de uma vez. Pode resumir ou dividir em partes?"
if code == "DLEX_IN":
return "Não posso usar essa informação da forma solicitada. Reformule o pedido sem incluir dados ou conteúdo restrito."
if code == "PINJ":
return "Não posso seguir instruções que tentem alterar as regras do atendimento. Posso continuar ajudando com a sua solicitação."
if code == "TOX":
return "Não consegui prosseguir com essa mensagem. Pode reformular o pedido para continuarmos o atendimento?"
if code == "CMP":
return "Não posso prosseguir com essa solicitação dessa forma. Posso ajudar com uma alternativa permitida."
return "Não consegui processar essa mensagem. Pode reformular para eu continuar o atendimento?"
async def input_guardrails(self, state): async def input_guardrails(self, state):
if state.get("session_ended") is True: if state.get("session_ended") is True:
answer = str(getattr( answer = str(getattr(
@@ -281,12 +306,33 @@ class AgentWorkflow:
component="workflow.input_guardrails.final", component="workflow.input_guardrails.final",
) )
if any(not d.allowed for d in decisions): if any(not d.allowed for d in decisions):
# A blocking input guardrail stops the turn before routing/tools.
# Clear turn-local routing/tool state so stale data from a prior
# turn cannot appear as if it was executed after the block.
user_message = self._input_guardrail_user_message(decisions, state, sanitized)
return { return {
"sanitized_input": sanitized, "sanitized_input": sanitized,
"answer": "Não consegui seguir com essa mensagem por regra de segurança.", "answer": user_message,
"final_answer": "Não consegui seguir com essa mensagem por regra de segurança.", "final_answer": None,
"guardrail_decisions": [d.model_dump() for d in decisions], "guardrail_decisions": [d.model_dump() for d in decisions],
"route": "blocked", "route": "blocked",
"intent": "input_guardrail_blocked",
"route_decision": {
"route": "blocked",
"agent": None,
"intent": "input_guardrail_blocked",
"confidence": 1.0,
"reason": "Entrada interrompida por guardrail antes do roteamento.",
"method": "guardrail",
"next_state": state.get("next_state"),
"handoff": False,
"metadata": {},
"domain": state.get("domain"),
"mcp_tools": [],
},
"mcp_tools": [],
"mcp_results": [],
"judge_results": [],
"blocked": True, "blocked": True,
} }
return { return {

View File

@@ -7,6 +7,35 @@ router:
confidence_threshold: 0.65 confidence_threshold: 0.65
allow_handoff: true allow_handoff: true
transaction_confirmation:
# Explicit yes/no stays deterministic. Only inconclusive replies use this LLM fallback.
semantic_fallback:
enabled: true
allowed_values: [SIM, NAO, CONTINUAR]
confirm_values: [SIM]
reject_values: [NAO]
continue_values: [CONTINUAR]
include_relevant_context: true
profile_name: router
prompt: |
Você classifica a resposta do cliente a uma confirmação transacional pendente.
Considere a pergunta pendente, somente o histórico recente relacionado ao mesmo tema e a fala atual.
Não execute a ação e não invente fatos.
Classes permitidas: {{ allowed_values }}
- SIM: confirmação/aceite inequívoco, inclusive equivalentes como "isso mesmo", "pode confirmar", "é isso" quando o contexto tornar o aceite claro.
- NAO: recusa/cancelamento inequívoco da ação pendente.
- CONTINUAR: qualquer resposta que não confirme nem rejeite inequivocamente, incluindo pergunta adicional, correção, novo dado, ambiguidade ou possível mudança de assunto.
Pergunta pendente:
{{ pending_prompt }}
Histórico relevante:
{{ relevant_conversation_context }}
Resposta atual do cliente:
{{ user_input }}
state_policies: state_policies:
- state: WAITING_BILLING_CONFIRMATION - state: WAITING_BILLING_CONFIRMATION
agent: billing_agent agent: billing_agent

View File

@@ -4,8 +4,16 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
invoice_id: string type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
invoice_id:
type: string
label: o identificador da fatura
description: Identificador da fatura que o cliente deseja consultar.
user_prompt: Informe o identificador da fatura que deseja consultar.
selection_keywords: selection_keywords:
- fatura - fatura
- conta - conta
@@ -18,7 +26,11 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
selection_keywords: selection_keywords:
- pagamento - pagamento
- pagamentos - pagamentos
@@ -27,8 +39,16 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
asset_id: string type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
asset_id:
type: string
label: o identificador do plano ou ativo
description: Identificador do plano ou ativo comercial associado ao cliente.
user_prompt: Informe o identificador do plano ou ativo que deseja consultar.
selection_keywords: selection_keywords:
- plano - plano
response: response:
@@ -39,7 +59,11 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
selection_keywords: selection_keywords:
- serviços - serviços
- servicos - servicos
@@ -49,8 +73,16 @@ tools:
mcp_server: retail mcp_server: retail
enabled: true enabled: true
args_schema: args_schema:
order_id: string order_id:
customer_id: string type: string
label: o número do pedido
description: Identificador do pedido que o cliente deseja consultar.
user_prompt: Informe o número do pedido que deseja consultar.
customer_id:
type: string
label: a identificação do cliente
description: Identificador do cliente associado ao pedido de varejo.
user_prompt: Informe a identificação do cliente.
selection_keywords: selection_keywords:
- consultar pedido - consultar pedido
- status do pedido - status do pedido
@@ -63,7 +95,11 @@ tools:
mcp_server: retail mcp_server: retail
enabled: true enabled: true
args_schema: args_schema:
order_id: string order_id:
type: string
label: o número do pedido
description: Identificador do pedido cuja entrega ou rastreamento será consultado.
user_prompt: Informe o número do pedido que deseja rastrear.
selection_keywords: selection_keywords:
- entrega - entrega
- rastreio - rastreio
@@ -82,7 +118,11 @@ tools:
- order_id - order_id
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
type: string
label: o número do pedido
description: Identificador do pedido que o cliente deseja cancelar.
user_prompt: Informe o número do pedido que deseja cancelar.
selection_keywords: selection_keywords:
- cancelar pedido - cancelar pedido
- cancelamento do pedido - cancelamento do pedido
@@ -100,8 +140,16 @@ tools:
- reason - reason
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
reason: string type: string
label: o número do pedido
description: Identificador do pedido para o qual o cliente deseja solicitar troca.
user_prompt: Informe o número do pedido que deseja trocar.
reason:
type: string
label: o motivo da troca
description: Motivo informado pelo cliente para solicitar a troca do pedido.
user_prompt: Qual é o motivo da troca?
selection_keywords: selection_keywords:
- solicitar troca - solicitar troca
- trocar - trocar
@@ -118,8 +166,16 @@ tools:
- reason - reason
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
reason: string type: string
label: o número do pedido
description: Identificador do pedido para o qual o cliente deseja solicitar devolução.
user_prompt: Informe o número do pedido que deseja devolver.
reason:
type: string
label: o motivo da devolução
description: Motivo informado pelo cliente para solicitar a devolução do pedido.
user_prompt: Qual é o motivo da devolução?
selection_keywords: selection_keywords:
- solicitar devolução - solicitar devolução
- solicitar devolucao - solicitar devolucao

View File

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

View File

@@ -1,195 +0,0 @@
###############################################################################
# AI AGENT PLATFORM - CONFIGURAÇÃO ÚNICA
# Este arquivo é lido por Pydantic Settings no framework e no backend template.
###############################################################################
APP_NAME=ai-agent-template
APP_ENV=local
LOG_LEVEL=INFO
API_HOST=0.0.0.0
API_PORT=8000
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
###############################################################################
# LLM - OCI Generative AI como provider principal
###############################################################################
# Opções: mock, oci_openai, oci_sdk, openai_compatible
LLM_PROVIDER=oci_openai
LLM_TEMPERATURE=0.2
LLM_MAX_TOKENS=2048
LLM_TIMEOUT_SECONDS=120
# OCI OpenAI-compatible endpoint
OCI_GENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/openai/v1
OCI_GENAI_MODEL=openai.gpt-4.1
OCI_GENAI_API_KEY=sk-ph3FgX6ph3FgX6ph3FgX6ph3FgX6ph3FgX6ph3FgX6
OCI_GENAI_PROJECT_OCID=
# OCI SDK / signer / profiles
OCI_CONFIG_FILE=~/.oci/config
OCI_PROFILE=DEFAULT
OCI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
OCI_REGION=us-chicago-1
###############################################################################
# Persistência
###############################################################################
# Opções: memory, autonomous, mongodb
SESSION_REPOSITORY_PROVIDER=sqlite
MEMORY_REPOSITORY_PROVIDER=sqlite
CHECKPOINT_REPOSITORY_PROVIDER=sqlite
SQLITE_DB_PATH=./data/agent_framework.db
# Autonomous Database
ADB_USER=admin
ADB_PASSWORD=fjhsdf04954hf
ADB_DSN=oradb23aidev_high
ADB_WALLET_LOCATION=/ORACLE/DEFAULT/Wallet_ORADB23aiDev
ADB_WALLET_PASSWORD=fjhsdf04954hf
ADB_TABLE_PREFIX=AGENTFW
# MongoDB - também pode representar Autonomous usando API compatível com Mongo, se habilitada no ambiente
MONGODB_URI=mongodb://mongo:mongopassword@localhost:27017
MONGODB_DATABASE=agent_platform
# Redis
REDIS_URL=redis://localhost:6379/0
ENABLE_REDIS_CACHE=false
###############################################################################
# RAG / Vector / Graph
###############################################################################
VECTOR_STORE_PROVIDER=sqlite
GRAPH_STORE_PROVIDER=sqlite
RAG_TOP_K=5
EMBEDDING_PROVIDER=mock
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
###############################################################################
# Observabilidade
###############################################################################
ENABLE_LANGFUSE=true
LANGFUSE_TRACE_MODE=compact # Opcional: verbose, compact
LANGFUSE_PUBLIC_KEY=pk-lf-2f9da109-5b0f-4c78-b61d-9598ed787eba
LANGFUSE_SECRET_KEY=sk-lf-a4cb0cdd-f2ea-4468-9911-cebeb91ba944
LANGFUSE_HOST=http://localhost:3005
ENABLE_OTEL=false
OTEL_EXPORTER_OTLP_ENDPOINT=
OTEL_SERVICE_NAME=ai-agent-template
ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=true
###############################################################################
# Analytics / Observer corporativo
###############################################################################
# Quando true, AgentObserver publica eventos IC.*, NOC.* e GRL.* nos providers abaixo.
ENABLE_ANALYTICS=false
# Providers aceitos: oci_streaming,pubsub,noop
ANALYTICS_PROVIDERS=pubsub
# Compatibilidade FIRST/TIM: pode informar AGENT_PUBSUB_TOPIC diretamente.
AGENT_PUBSUB_TOPIC=
GCP_PUBSUB_TOPIC_PATH=
GCP_PROJECT_ID=
GCP_PUBSUB_TOPIC=
GCP_PUBSUB_TIMEOUT_SECONDS=30
# Credencial GCP segue padrão Google:
# GOOGLE_APPLICATION_CREDENTIALS=/secrets/gcp-service-account.json
###############################################################################
# OCI Streaming
###############################################################################
ENABLE_OCI_STREAMING=false
OCI_STREAM_ENDPOINT=
OCI_STREAM_OCID=
OCI_STREAM_PARTITION_KEY=agent-events
###############################################################################
# Guardrails, Judges, Supervisor
###############################################################################
ENABLE_INPUT_GUARDRAILS=true
ENABLE_OUTPUT_GUARDRAILS=true
ENABLE_JUDGES=true
ENABLE_SUPERVISOR=true
ENABLE_OUTPUT_SUPERVISOR=true
ENABLE_PARALLEL_GUARDRAILS=true
GUARDRAILS_FAIL_FAST=true
OUTPUT_SUPERVISOR_MAX_RETRIES=3
GUARDRAILS_CONFIG_PATH=./config/guardrails.yaml
JUDGES_CONFIG_PATH=./config/judges.yaml
PROMPT_POLICY_PATH=./config/prompt_policy.yaml
###############################################################################
# Gateway de canais
###############################################################################
DEFAULT_CHANNEL=web
# embedded = backend may parse simple/native channel payloads.
# external = backend only accepts GatewayRequest normalized by an external Channel Gateway.
FRAMEWORK_CHANNEL_INPUT_MODE=embedded
ENABLE_VOICE_ADAPTER=true
ENABLE_WHATSAPP_ADAPTER=true
ENABLE_TEXT_ADAPTER=true
#################################################
# ENTERPRISE ROUTING
#################################################
# Arquivo YAML com intents, keywords, políticas de estado e fallback.
ROUTING_CONFIG_PATH=./config/routing.yaml
# true = usa LLM para classificar quando keywords/estado não resolverem.
# Em produção, costuma ser útil; em desenvolvimento, false evita custo e latência.
ENABLE_LLM_ROUTER=true
###############################################################################
# MCP / Tools
###############################################################################
ENABLE_MCP_TOOLS=true
MCP_SERVERS_CONFIG_PATH=./config/mcp_servers.yaml
TOOLS_CONFIG_PATH=./config/tools.yaml
TOOL_POLICIES_PATH=./config/tool_policies.yaml
MCP_TOOL_TIMEOUT_SECONDS=30
# router = EnterpriseRouter seleciona um agente; supervisor = pode acionar múltiplos agentes
ROUTING_MODE=router
# Usage/cost accounting
USAGE_REPOSITORY_PROVIDER=sqlite
IDENTITY_CONFIG_PATH=./config/identity.yaml
MCP_PARAMETER_MAPPING_PATH=./config/mcp_parameter_mapping.yaml
# -----------------------------------------------------------------------------
# ConversationSummaryMemory / compressão de contexto conversacional
# -----------------------------------------------------------------------------
ENABLE_CONVERSATION_SUMMARY_MEMORY=true
MEMORY_CONTEXT_STRATEGY=summary
MEMORY_HISTORY_LIMIT=80
MEMORY_RECENT_MESSAGES_LIMIT=8
MEMORY_SUMMARY_TRIGGER_MESSAGES=20
MEMORY_MAX_SUMMARY_CHARS=6000
MEMORY_SUMMARY_USE_LLM=true
MEMORY_INJECT_RECENT_MESSAGES=true
MEMORY_INJECT_SUMMARY=true
###############################################################################
# MCP Gateway
###############################################################################
# true = framework routes tool calls to the dedicated MCP Gateway.
# false = framework calls MCP servers directly from mcp_servers.yaml.
MCP_GATEWAY_ENABLED=true
MCP_GATEWAY_URL=http://localhost:8300
MCP_GATEWAY_TIMEOUT_SECONDS=60
# MCP_GATEWAY_TOKEN=
MCP_GATEWAY_AGENT_ID=telecom_contas
MCP_GATEWAY_TENANT_ID=default
###############################################################################
# LONG-TERM MEMORY
###############################################################################
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
# For Autonomous/Oracle, defaults to ${ADB_TABLE_PREFIX}_LONG_TERM_MEMORY
# LONG_TERM_MEMORY_ORACLE_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

View File

@@ -159,7 +159,7 @@ class AgentWorkflow:
builder.add_conditional_edges( builder.add_conditional_edges(
"input_guardrails", "input_guardrails",
self._after_input_guardrails, self._after_input_guardrails,
{"blocked": "persist", "continue": "routing_decision"}, {"blocked": "output_guardrails", "continue": "routing_decision"},
) )
builder.add_conditional_edges( builder.add_conditional_edges(
"routing_decision", "routing_decision",
@@ -195,6 +195,31 @@ class AgentWorkflow:
def _after_input_guardrails(self, state): def _after_input_guardrails(self, state):
return "blocked" if state.get("blocked") else "continue" return "blocked" if state.get("blocked") else "continue"
@staticmethod
def _input_guardrail_user_message(decisions, state, sanitized_text):
# Keep the technical guardrail reason in telemetry, but expose only a
# safe, actionable message to the end user. The message is intentionally
# routed through output_guardrails before persistence/delivery.
blocked = [d for d in decisions if not getattr(d, "allowed", True)]
first = blocked[0] if blocked else None
code = str(getattr(first, "code", "") or "").upper()
if code == "COER":
return (
"Não consegui entender sua última mensagem porque ela parece "
"incompleta ou ambígua. Pode reformular ou completar o que você quis dizer?"
)
if code == "INPUT_SIZE":
return "Sua mensagem ficou muito longa para eu processar de uma vez. Pode resumir ou dividir em partes?"
if code == "DLEX_IN":
return "Não posso usar essa informação da forma solicitada. Reformule o pedido sem incluir dados ou conteúdo restrito."
if code == "PINJ":
return "Não posso seguir instruções que tentem alterar as regras do atendimento. Posso continuar ajudando com a sua solicitação."
if code == "TOX":
return "Não consegui prosseguir com essa mensagem. Pode reformular o pedido para continuarmos o atendimento?"
if code == "CMP":
return "Não posso prosseguir com essa solicitação dessa forma. Posso ajudar com uma alternativa permitida."
return "Não consegui processar essa mensagem. Pode reformular para eu continuar o atendimento?"
async def input_guardrails(self, state): async def input_guardrails(self, state):
if state.get("session_ended") is True: if state.get("session_ended") is True:
answer = str(getattr( answer = str(getattr(
@@ -279,12 +304,33 @@ class AgentWorkflow:
component="workflow.input_guardrails.final", component="workflow.input_guardrails.final",
) )
if any(not d.allowed for d in decisions): if any(not d.allowed for d in decisions):
# A blocking input guardrail stops the turn before routing/tools.
# Clear turn-local routing/tool state so stale data from a prior
# turn cannot appear as if it was executed after the block.
user_message = self._input_guardrail_user_message(decisions, state, sanitized)
return { return {
"sanitized_input": sanitized, "sanitized_input": sanitized,
"answer": "Não consegui seguir com essa mensagem por regra de segurança.", "answer": user_message,
"final_answer": "Não consegui seguir com essa mensagem por regra de segurança.", "final_answer": None,
"guardrail_decisions": [d.model_dump() for d in decisions], "guardrail_decisions": [d.model_dump() for d in decisions],
"route": "blocked", "route": "blocked",
"intent": "input_guardrail_blocked",
"route_decision": {
"route": "blocked",
"agent": None,
"intent": "input_guardrail_blocked",
"confidence": 1.0,
"reason": "Entrada interrompida por guardrail antes do roteamento.",
"method": "guardrail",
"next_state": state.get("next_state"),
"handoff": False,
"metadata": {},
"domain": state.get("domain"),
"mcp_tools": [],
},
"mcp_tools": [],
"mcp_results": [],
"judge_results": [],
"blocked": True, "blocked": True,
} }
return { return {

View File

@@ -7,6 +7,35 @@ router:
confidence_threshold: 0.65 confidence_threshold: 0.65
allow_handoff: true allow_handoff: true
transaction_confirmation:
# Explicit yes/no stays deterministic. Only inconclusive replies use this LLM fallback.
semantic_fallback:
enabled: true
allowed_values: [SIM, NAO, CONTINUAR]
confirm_values: [SIM]
reject_values: [NAO]
continue_values: [CONTINUAR]
include_relevant_context: true
profile_name: router
prompt: |
Você classifica a resposta do cliente a uma confirmação transacional pendente.
Considere a pergunta pendente, somente o histórico recente relacionado ao mesmo tema e a fala atual.
Não execute a ação e não invente fatos.
Classes permitidas: {{ allowed_values }}
- SIM: confirmação/aceite inequívoco, inclusive equivalentes como "isso mesmo", "pode confirmar", "é isso" quando o contexto tornar o aceite claro.
- NAO: recusa/cancelamento inequívoco da ação pendente.
- CONTINUAR: qualquer resposta que não confirme nem rejeite inequivocamente, incluindo pergunta adicional, correção, novo dado, ambiguidade ou possível mudança de assunto.
Pergunta pendente:
{{ pending_prompt }}
Histórico relevante:
{{ relevant_conversation_context }}
Resposta atual do cliente:
{{ user_input }}
state_policies: state_policies:
- state: WAITING_BILLING_CONFIRMATION - state: WAITING_BILLING_CONFIRMATION
agent: billing_agent agent: billing_agent

View File

@@ -4,8 +4,16 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
invoice_id: string type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
invoice_id:
type: string
label: o identificador da fatura
description: Identificador da fatura que o cliente deseja consultar.
user_prompt: Informe o identificador da fatura que deseja consultar.
selection_keywords: selection_keywords:
- fatura - fatura
- conta - conta
@@ -18,7 +26,11 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
selection_keywords: selection_keywords:
- pagamento - pagamento
- pagamentos - pagamentos
@@ -27,8 +39,16 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
asset_id: string type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
asset_id:
type: string
label: o identificador do plano ou ativo
description: Identificador do plano ou ativo comercial associado ao cliente.
user_prompt: Informe o identificador do plano ou ativo que deseja consultar.
selection_keywords: selection_keywords:
- plano - plano
response: response:
@@ -39,7 +59,11 @@ tools:
mcp_server: telecom mcp_server: telecom
enabled: true enabled: true
args_schema: args_schema:
msisdn: string msisdn:
type: string
label: o número da linha
description: Número da linha do cliente (MSISDN) usado para consultar informações de telecom.
user_prompt: Informe o número da linha que deseja consultar.
selection_keywords: selection_keywords:
- serviços - serviços
- servicos - servicos
@@ -49,8 +73,16 @@ tools:
mcp_server: retail mcp_server: retail
enabled: true enabled: true
args_schema: args_schema:
order_id: string order_id:
customer_id: string type: string
label: o número do pedido
description: Identificador do pedido que o cliente deseja consultar.
user_prompt: Informe o número do pedido que deseja consultar.
customer_id:
type: string
label: a identificação do cliente
description: Identificador do cliente associado ao pedido de varejo.
user_prompt: Informe a identificação do cliente.
selection_keywords: selection_keywords:
- consultar pedido - consultar pedido
- status do pedido - status do pedido
@@ -63,7 +95,11 @@ tools:
mcp_server: retail mcp_server: retail
enabled: true enabled: true
args_schema: args_schema:
order_id: string order_id:
type: string
label: o número do pedido
description: Identificador do pedido cuja entrega ou rastreamento será consultado.
user_prompt: Informe o número do pedido que deseja rastrear.
selection_keywords: selection_keywords:
- entrega - entrega
- rastreio - rastreio
@@ -82,7 +118,11 @@ tools:
- order_id - order_id
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
type: string
label: o número do pedido
description: Identificador do pedido que o cliente deseja cancelar.
user_prompt: Informe o número do pedido que deseja cancelar.
selection_keywords: selection_keywords:
- cancelar pedido - cancelar pedido
- cancelamento do pedido - cancelamento do pedido
@@ -100,8 +140,16 @@ tools:
- reason - reason
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
reason: string type: string
label: o número do pedido
description: Identificador do pedido para o qual o cliente deseja solicitar troca.
user_prompt: Informe o número do pedido que deseja trocar.
reason:
type: string
label: o motivo da troca
description: Motivo informado pelo cliente para solicitar a troca do pedido.
user_prompt: Qual é o motivo da troca?
selection_keywords: selection_keywords:
- solicitar troca - solicitar troca
- trocar - trocar
@@ -118,8 +166,16 @@ tools:
- reason - reason
confirmation_required: true confirmation_required: true
args_schema: args_schema:
order_id: string order_id:
reason: string type: string
label: o número do pedido
description: Identificador do pedido para o qual o cliente deseja solicitar devolução.
user_prompt: Informe o número do pedido que deseja devolver.
reason:
type: string
label: o motivo da devolução
description: Motivo informado pelo cliente para solicitar a devolução do pedido.
user_prompt: Qual é o motivo da devolução?
selection_keywords: selection_keywords:
- solicitar devolução - solicitar devolução
- solicitar devolucao - solicitar devolucao

View File

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

View File

@@ -1,192 +0,0 @@
###############################################################################
# AI AGENT PLATFORM - CONFIGURAÇÃO ÚNICA
# Este arquivo é lido por Pydantic Settings no framework e no backend template.
###############################################################################
APP_NAME=ai-agent-template
APP_ENV=local
LOG_LEVEL=INFO
API_HOST=0.0.0.0
API_PORT=8000
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
###############################################################################
# LLM - OCI Generative AI como provider principal
###############################################################################
# Opções: mock, oci_openai, oci_sdk, openai_compatible
LLM_PROVIDER=oci_openai
LLM_TEMPERATURE=0.2
LLM_MAX_TOKENS=2048
LLM_TIMEOUT_SECONDS=120
# OCI OpenAI-compatible endpoint
OCI_GENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/openai/v1
OCI_GENAI_MODEL=openai.gpt-4.1
OCI_GENAI_API_KEY=sk-ph3FgX6ph3FgX6ph3FgX6ph3FgX6ph3FgX6ph3FgX6
OCI_GENAI_PROJECT_OCID=
# OCI SDK / signer / profiles
OCI_CONFIG_FILE=~/.oci/config
OCI_PROFILE=DEFAULT
OCI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
OCI_REGION=us-chicago-1
###############################################################################
# Persistência
###############################################################################
# Opções: memory, autonomous, mongodb
SESSION_REPOSITORY_PROVIDER=sqlite
MEMORY_REPOSITORY_PROVIDER=sqlite
CHECKPOINT_REPOSITORY_PROVIDER=sqlite
SQLITE_DB_PATH=./data/agent_framework.db
# Autonomous Database
ADB_USER=admin
ADB_PASSWORD=fjhsdf04954hf
ADB_DSN=oradb23aidev_high
ADB_WALLET_LOCATION=/ORACLE/DEFAULT/Wallet_ORADB23aiDev
ADB_WALLET_PASSWORD=fjhsdf04954hf
ADB_TABLE_PREFIX=AGENTFW
# MongoDB - também pode representar Autonomous usando API compatível com Mongo, se habilitada no ambiente
MONGODB_URI=mongodb://mongo:mongopassword@localhost:27017
MONGODB_DATABASE=agent_platform
# Redis
REDIS_URL=redis://localhost:6379/0
ENABLE_REDIS_CACHE=false
###############################################################################
# RAG / Vector / Graph
###############################################################################
VECTOR_STORE_PROVIDER=sqlite
GRAPH_STORE_PROVIDER=sqlite
RAG_TOP_K=5
EMBEDDING_PROVIDER=mock
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
###############################################################################
# Observabilidade
###############################################################################
ENABLE_LANGFUSE=true
LANGFUSE_TRACE_MODE=compact # Opcional: verbose, compact
LANGFUSE_PUBLIC_KEY=pk-lf-2f9da109-5b0f-4c78-b61d-9598ed787eba
LANGFUSE_SECRET_KEY=sk-lf-a4cb0cdd-f2ea-4468-9911-cebeb91ba944
LANGFUSE_HOST=http://localhost:3005
ENABLE_OTEL=false
OTEL_EXPORTER_OTLP_ENDPOINT=
OTEL_SERVICE_NAME=ai-agent-template
ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=true
###############################################################################
# Analytics / Observer corporativo
###############################################################################
# Quando true, AgentObserver publica eventos IC.*, NOC.* e GRL.* nos providers abaixo.
ENABLE_ANALYTICS=false
# Providers aceitos: oci_streaming,pubsub,noop
ANALYTICS_PROVIDERS=pubsub
# Compatibilidade FIRST/TIM: pode informar AGENT_PUBSUB_TOPIC diretamente.
AGENT_PUBSUB_TOPIC=
GCP_PUBSUB_TOPIC_PATH=
GCP_PROJECT_ID=
GCP_PUBSUB_TOPIC=
GCP_PUBSUB_TIMEOUT_SECONDS=30
# Credencial GCP segue padrão Google:
# GOOGLE_APPLICATION_CREDENTIALS=/secrets/gcp-service-account.json
###############################################################################
# OCI Streaming
###############################################################################
ENABLE_OCI_STREAMING=false
OCI_STREAM_ENDPOINT=
OCI_STREAM_OCID=
OCI_STREAM_PARTITION_KEY=agent-events
###############################################################################
# Guardrails, Judges, Supervisor
###############################################################################
ENABLE_INPUT_GUARDRAILS=true
ENABLE_OUTPUT_GUARDRAILS=true
ENABLE_JUDGES=true
ENABLE_SUPERVISOR=true
ENABLE_OUTPUT_SUPERVISOR=true
ENABLE_PARALLEL_GUARDRAILS=true
GUARDRAILS_FAIL_FAST=true
OUTPUT_SUPERVISOR_MAX_RETRIES=3
GUARDRAILS_CONFIG_PATH=./config/guardrails.yaml
JUDGES_CONFIG_PATH=./config/judges.yaml
PROMPT_POLICY_PATH=./config/prompt_policy.yaml
###############################################################################
# Gateway de canais
###############################################################################
DEFAULT_CHANNEL=web
ENABLE_VOICE_ADAPTER=true
ENABLE_WHATSAPP_ADAPTER=true
ENABLE_TEXT_ADAPTER=true
#################################################
# ENTERPRISE ROUTING
#################################################
# Arquivo YAML com intents, keywords, políticas de estado e fallback.
ROUTING_CONFIG_PATH=./config/routing.yaml
# true = usa LLM para classificar quando keywords/estado não resolverem.
# Em produção, costuma ser útil; em desenvolvimento, false evita custo e latência.
ENABLE_LLM_ROUTER=true
###############################################################################
# MCP / Tools
###############################################################################
ENABLE_MCP_TOOLS=true
MCP_SERVERS_CONFIG_PATH=./config/mcp_servers.yaml
TOOLS_CONFIG_PATH=./config/tools.yaml
TOOL_POLICIES_PATH=./config/tool_policies.yaml
MCP_TOOL_TIMEOUT_SECONDS=30
# router = EnterpriseRouter seleciona um agente; supervisor = pode acionar múltiplos agentes
ROUTING_MODE=router
# Usage/cost accounting
USAGE_REPOSITORY_PROVIDER=sqlite
IDENTITY_CONFIG_PATH=./config/identity.yaml
MCP_PARAMETER_MAPPING_PATH=./config/mcp_parameter_mapping.yaml
# -----------------------------------------------------------------------------
# ConversationSummaryMemory / compressão de contexto conversacional
# -----------------------------------------------------------------------------
ENABLE_CONVERSATION_SUMMARY_MEMORY=true
MEMORY_CONTEXT_STRATEGY=summary
MEMORY_HISTORY_LIMIT=80
MEMORY_RECENT_MESSAGES_LIMIT=8
MEMORY_SUMMARY_TRIGGER_MESSAGES=20
MEMORY_MAX_SUMMARY_CHARS=6000
MEMORY_SUMMARY_USE_LLM=true
MEMORY_INJECT_RECENT_MESSAGES=true
MEMORY_INJECT_SUMMARY=true
###############################################################################
# MCP Gateway
###############################################################################
# true = framework routes tool calls to the dedicated MCP Gateway.
# false = framework calls MCP servers directly from mcp_servers.yaml.
MCP_GATEWAY_ENABLED=true
MCP_GATEWAY_URL=http://localhost:8300
MCP_GATEWAY_TIMEOUT_SECONDS=60
# MCP_GATEWAY_TOKEN=
MCP_GATEWAY_AGENT_ID=telecom_contas
MCP_GATEWAY_TENANT_ID=default
###############################################################################
# LONG-TERM MEMORY
###############################################################################
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
# For Autonomous/Oracle, defaults to ${ADB_TABLE_PREFIX}_LONG_TERM_MEMORY
# LONG_TERM_MEMORY_ORACLE_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

Some files were not shown because too many files have changed in this diff Show More