# Detailed Rule Manual for `agent_template_backend`
## Technical Preface — how the `agent_template_backend` decision engine works
`agent_template_backend` is a **corporate reference template** for building agents on the Agent Framework OCI. Decision logic is not concentrated in one `if`, prompt, or router. Final behavior results from cooperation among declarative configuration, LangGraph state, transactional runtime, MCP Tool Router, RAG, memory, guardrails, judges, Output Supervisor, workflows, and persistence.
A message may:
- be sanitized/blocked before routing;
- belong to an already-open transaction;
- fill a pending parameter;
- confirm/reject an action;
- interrupt the previous operation through intent shift;
- continue with the current agent through route stickiness;
- contain multiple independent intents;
- resume a paused workflow;
- select one or more candidate tools;
- go through pre-validation;
- change its execution path because of policy;
- execute a tool directly or a deterministic workflow;
- use MCP as operational evidence;
- use RAG as documentary knowledge;
- use summarized/long-term memory as context;
- be reviewed by Output Supervisor, guardrails, and judges;
- persist state/evidence for the next turn.
When diagnosing the template, the right question is not only “which intent was found?” but:
> **What state was the session in, which mechanism had precedence, which intent/route won, which tool was selected, which parameters were resolved, which policy/pre-validation applied, what execution occurred, and which evidence supported the final response?**
## P.1. Engine overview
```mermaid
flowchart TD
U["Message / GatewayRequest"] --> IGR["Input Guardrails"]
IGR --> LTM["Load Long-Term Memory"]
LTM --> RT["EnterpriseRouter / Supervisor"]
RT --> CP["Conversation policy / state precedence"]
CP --> AG["Domain agent"]
AG --> TP["Tool policy + parameters"]
TP --> PV["Pre-validation when configured"]
PV --> CF["Confirmation when transactional"]
CF --> EX["Direct MCP or Workflow"]
EX --> RAG["RAG when needed"]
RAG --> CMP["Response composition"]
CMP --> OS["Output Supervisor"]
OS --> OGR["Output Guardrails"]
OGR --> J["Judges"]
J --> SR["Supervisor Review"]
SR --> MEM["Persistence / memory / checkpoint"]
MEM --> F["Response"]
```
Not every turn traverses every layer. A tracking query may finish quickly with MCP + renderer; a return may require collection, confirmation, and workflow execution.
## P.2. Actual corporate graph in the template
`app/workflows/agent_graph.py` builds a `FrameworkStateGraph(AgentState)` with the main nodes:
```text
START
↓
input_guardrails
↓
load_long_term_memory
↓
routing_decision
↓
billing_agent | product_agent | orders_agent | support_agent
| handoff | human_handoff | end_session | supervisor_agent
↓
output_supervisor
↓
output_guardrails
↓
judge
↓
supervisor_review
↓
persist_long_term_memory
↓
persist
↓
END
```
The graph is the backbone; domain rules live in YAML, agents, MCP, and workflows.
## P.3. Three state families
### P.3.1. States declared in `routing.yaml`
| State | Owning agent |
|---|---|
| `WAITING_BILLING_CONFIRMATION` | `billing_agent` |
| `WAITING_PRODUCT_CONFIRMATION` | `product_agent` |
| `WAITING_ORDER_CONFIRMATION` | `orders_agent` |
| `WAITING_SUPPORT_CONFIRMATION` | `support_agent` |
| `COLLECTING_BILLING_PARAMETERS` | `billing_agent` |
| `COLLECTING_PRODUCT_PARAMETERS` | `product_agent` |
| `COLLECTING_ORDER_PARAMETERS` | `orders_agent` |
| `COLLECTING_SUPPORT_PARAMETERS` | `support_agent` |
They keep the next turn with the owning agent while parameters or confirmation are pending.
### P.3.2. Canonical transactional runtime states
The runtime uses states such as:
```text
COLLECTING_PARAMETERS
AWAITING_CONFIRMATION
CONFIRMED
EXECUTING
WORKFLOW_PAUSED
TOOL_RESULT_CLARIFICATION
COMPLETED
FAILED
CANCELLED
BLOCKED
OUT_OF_SCOPE
```
These control parameters, confirmation, execution, and transaction termination.
### P.3.3. Workflow-engine states
A workflow has an independent execution identified by `execution_id`, with results such as:
```text
PAUSED / WAITING_INPUT
COMPLETED
FAILED
```
The three groups are related, but they must not be treated as a single enum.
## P.4. Conceptual transactional state machine
```mermaid
stateDiagram-v2
[*] --> COLLECTING_PARAMETERS: required fields missing
COLLECTING_PARAMETERS --> AWAITING_CONFIRMATION: complete parameters + validations OK
COLLECTING_PARAMETERS --> CANCELLED: intent shift / abandonment
AWAITING_CONFIRMATION --> EXECUTING: positive confirmation
AWAITING_CONFIRMATION --> CANCELLED: negative confirmation
AWAITING_CONFIRMATION --> AWAITING_CONFIRMATION: inconclusive response
EXECUTING --> COMPLETED: tool/workflow completed
EXECUTING --> WORKFLOW_PAUSED: workflow requests input
EXECUTING --> FAILED: technical error
EXECUTING --> BLOCKED: policy/guardrail
EXECUTING --> OUT_OF_SCOPE: domain rule rejects
WORKFLOW_PAUSED --> EXECUTING: valid resume
WORKFLOW_PAUSED --> COMPLETED: workflow ends
```
## P.5. Routing
`config/routing.yaml` is the declarative source for intents, priorities, agents, tools, keywords, and examples.
The main `EnterpriseRouter` sequence is:
```text
active state/transaction
→ deterministic matching
→ LLM router when enabled
→ fallback
```
Deterministic matching favors the best priority/specificity combination; **lower numeric `priority` values take precedence**.
When `ENABLE_LLM_ROUTER=true`, the LLM receives the allowed catalog and classifies within it. The LLM must not invent new tools or agents.
## P.6. Route stickiness
`ENABLE_ROUTE_STICKINESS` enables a lightweight classifier that decides semantic continuity among:
```text
CONTINUE
ROUTE
HUMAN_HANDOFF
END_SESSION
```
Relevant configuration:
```text
ROUTE_STICKINESS_LLM_PROFILE
ROUTE_STICKINESS_CONFIDENCE_THRESHOLD
ROUTE_STICKINESS_HISTORY_TURNS
ROUTE_STICKINESS_MAX_TOKENS
```
`CONTINUE` keeps the active agent; `ROUTE` goes back to EnterpriseRouter. Stickiness does not authorize transactions and does not replace tool policy.
## P.7. Intent shift
During `COLLECTING_PARAMETERS` or `AWAITING_CONFIRMATION`, the framework protects the current transaction from accidental topic changes. An explicit change of subject may, however, cancel/clear the transactional latch and return the turn to normal routing.
The current utterance also has precedence when filling pending fields. A response such as `PED-1001` while collecting `order_id` must not be reinterpreted as a new intent.
## P.8. Parameter collection
Parameter requirements are produced by the combination:
```text
tools.yaml args_schema
+ tool_policies.yaml requires
+ mcp_parameter_mapping.yaml
+ canonical state data
```
Example:
```text
cancelar_pedido
requires: [order_id]
```
Without `order_id`, the runtime enters `COLLECTING_PARAMETERS`, uses the tool schema/user prompt to request the field, and preserves agent ownership.
## P.9. Temporal reconciliation
The framework contains a temporal reconciler in `runtime/transaction_parameters.py`. It is used **after** the normal current-turn extraction attempt when required fields are still missing.
Principles:
- the current utterance is the newest source and has precedence;
- history resolves references but does not invent operational facts;
- fields may be preserved, resolved, cleared, or remain unresolved;
- ambiguity must remain unresolved;
- candidate results still pass domain validations/pre-validation.
This allows coherent cross-turn relationships without converting conversational history into backend evidence.
## P.10. Contextual reentry
`EnterpriseRouter` and the runtime support `contextual_reentry`: a short turn may reenter a rule when the immediately preceding context constrains its meaning.
The runtime keeps the current utterance separate from `relevant_conversation_context`; that context is interpretive and does not replace tools/MCP as operational authority.
## P.11. Multi-intent and `pending_topics`
`MultiIntentPlanner` can split independent goals:
```text
"track the order and then cancel it"
```
into distinct topics without decomposing internal parameters of one action.
When one action must finish before the next, remaining goals may be persisted in `pending_topics`. `drain_pending_topics()` appears directly in the template graph.
## P.12. Tool policies
`tools.yaml` describes capabilities. `tool_policies.yaml` describes **how** a sensitive capability may execute.
In the base template:
- `cancelar_pedido`: transactional + confirmation + `order_id` + pre-validation;
- `solicitar_troca`: transactional + confirmation;
- `solicitar_devolucao`: transactional + confirmation + `order_id/reason` + workflow.
This prevents sensitive execution rules from being hardcoded inside agents.
## P.13. Pre-validation
Pre-validation occurs after required parameters are complete and before confirmation.
Flow:
```text
complete parameters
→ side-effect-free MCP validator
→ eligible?
├─ false: OUT_OF_SCOPE / terminate latch
└─ true: AWAITING_CONFIRMATION
```
In the template, `cancelar_pedido` uses `validar_cancelamento_pedido` with `fail_open=false`.
## P.14. Transaction confirmation
Tools with `require_confirmation=true` do not execute automatically.
The framework first attempts to interpret explicit confirmations deterministically and can use semantic fallback when necessary. A positive response promotes the transaction to execution; a negative one cancels it; an inconclusive response keeps the transaction active.
## P.15. Transactional workflow
A policy may define:
```yaml
execution:
mode: workflow
workflow: devolucao_pedido
version: active
```
After confirmation, the logical tool is executed by `WorkflowToolExecutor`, which loads the versioned YAML and executes the deterministic graph. The domain declares nodes/actions; the framework owns runtime, checkpointing, and tracing.
## P.16. Pause/Resume
The workflow engine supports pause nodes, `expected_input`, `resume_from`, and resume by `execution_id`. The base return workflow does not pause; the capability is demonstrated separately in `Tuning-Performance/Pause_Resume_Workflow`.
An important rule is that pause compilation must not automatically rerun a side-effecting action when the user answers.
## P.17. Guardrails
In the global template:
**Input**
- `MSK`
- `VLOOP`
**Output**
- `REVPREC`
- `PINJ`
- `DLEX_OUT`
Pipelines can be enabled/disabled through `.env`. Guardrails evaluate permission/safety/operational coherence; they must not replace routing or domain rules.
## P.18. Output Supervisor
Output Supervisor sits between the agent and output guardrails. It may review the candidate response, apply retry/sanitize/block/handover policies, and prevent premature claims about effects that are not supported by operational results.
`OUTPUT_SUPERVISOR_MAX_RETRIES` controls the regeneration limit.
## P.19. Judges
`config/judges.yaml` enables:
| Judge | Threshold/policy |
|---|---|
| `response_quality` | `0.7` |
| `groundedness` | `0.6` |
| `sentiment` | does not fail on negative |
| `tone` | `fail_closed=true` |
Global configuration:
```text
enabled=true
fail_closed=true
sample_rate=0.25
always_run_for_transactional=true
```
Transactional responses are therefore evaluated even when the general sampling rate would skip them.
## P.20. MCP, operational evidence, and renderers
The template separates three responsibilities:
```text
routing → which capabilities belong to the intent
tool runtime → which capability should actually execute
MCP server → operational fact / integration
```
Some tools use `response.mode: renderer`, such as `telecom.invoice`, `telecom.plan`, `retail.order`, and `retail.delivery`. In those cases, MCP results may be presented deterministically without requiring LLM composition.
## P.21. RAG
`AgentRuntimeMixin._retrieve_rag_context()` uses the framework's official RAG path. RAG is for documentary knowledge; MCP is for operational state.
The runtime also supports **Domain-Requested RAG**: a tool may return `requires_rag=true` and `rag_queries`, forcing retrieval even when MCP would normally be considered sufficient.
## P.22. Domain-requested LLM composition
A tool/workflow may return:
```json
{
"requires_llm_composition": true,
"response_instruction": "Explain using only workflow evidence."
}
```
The domain does not create its own LLM gateway. AgentRuntime uses the official provider, preserving tracing, cost controls, profiles, and guardrails.
## P.23. Memory
The template provides:
- ConversationSummaryMemory;
- recent memory;
- optional Long-Term Memory;
- operational checkpoint/persistence.
Memory helps interpret context, preferences, and continuity. **It does not replace Transaction Evidence or MCP** for asserting that an operation occurred.
## P.24. Transaction Evidence
Completed transaction results can be persisted as structured operational evidence and correlated with future turns. This prevents later responses from mentioning a previous protocol/cancellation without providing the same evidence to judges/groundedness.
## P.25. Idempotency
Transactional state, checkpointing, and `execution_id` also protect against retry/replay/reexecution. A repeated confirmation must not create two transactions just because the channel resent a message.
## P.26. Voice interruption and replay
The framework contains channel short-circuits for idle nudges, non-interruptible speech, post-finalization, and barge-in. In several cases it simply replays the last utterance without reopening LangGraph, tools, or guardrails; where needed it uses the `processing_interruption_classifier` profile.
## P.27. Workflow error and recovery
`WorkflowRuntime` preserves the last valid snapshot and exposes `error`, partial trace, and `error_details` when the provider supplies `status_code`, `body`, and `attempts`. The domain can distinguish technical failure from business-rule rejection without coupling the framework to the provider.
## P.28. Observability
The template emits telemetry to:
- Langfuse;
- OpenTelemetry;
- corporate analytics/observer;
- IC events;
- NOC;
- GRL;
- workflow;
- guardrails;
- judges.
Telemetry should allow reconstruction of:
```text
input → route → agent → tool → policy → workflow → output controls → persistence
```
## P.29. `agents.yaml`: logical application/agent isolation
`config/agents.yaml` registers two reference `agent_id` values:
- `telecom_contas`;
- `retail_orders`.
Each can point to prompt policy, routing, guardrails, judges, MCP servers, and tools, plus `metadata.system_prefix`. The goal is to prevent policies, memory/checkpoints, or decisions from leaking across logical identities.
## P.30. Troubleshooting golden rule
Always investigate in this order:
```text
1. Which agent_id is active?
2. What was the state/checkpoint?
3. Was there an active transaction or paused workflow?
4. Which route/stickiness decision occurred?
5. Which intent won and why?
6. Which mcp_tools did the intent authorize?
7. Which tool was actually selected?
8. Which parameters were resolved?
9. Did temporal reconciliation occur?
10. Did pre-validation occur?
11. Was confirmation required?
12. Direct tool or workflow?
13. Which MCP/workflow result was produced?
14. Did the response use renderer, RAG, or LLM?
15. Did Output Supervisor/guardrails change anything?
16. Did judges approve it?
17. Was state/evidence persisted?
```
This is the engine on which the template's five rules are built.
## 1. How to read this manual
This manual follows the same model as the Accounts Agent manual. Each rule is explained at six levels:
1. **Rule/intent** — what it means and its boundary.
2. **Routing** — `routing.yaml` attribute by attribute and how the intent is discovered.
3. **Tools** — operation, arguments, aliases, extraction, policy, confirmation, pre-validation, and return.
4. **Workflow** — when present, nodes, actions, conditions, and termination.
5. **Binding** — Python/YAML/`.env` files involved.
6. **Diagnostics** — why a specific decision occurs.
A separate section then covers `Tuning-Performance`.
## 2. Agent catalog and `agent_id` isolation
| agent_id | Name | Domain | Specific configuration |
|---|---|---|---|
| `telecom_contas` | Agente Telecom Contas | `telecom` | prompt `./config/agents/telecom_contas/prompt_policy.yaml`; guardrails `./config/agents/telecom_contas/guardrails.yaml`; judges `./config/agents/telecom_contas/judges.yaml` |
| `retail_orders` | Agente Retail Pedidos | `retail` | prompt `./config/agents/retail_orders/prompt_policy.yaml`; guardrails `./config/agents/retail_orders/guardrails.yaml`; judges `./config/agents/retail_orders/judges.yaml` |
The `default_agent_id` is `telecom_contas`. Each entry's `system_prefix` guides the runtime so that policies, memory/checkpoints, or decisions from another `agent_id` are not mixed.
## 3. Component binding
```mermaid
flowchart LR
U["GatewayRequest / message"] --> G["app/main.py"]
G --> WF["app/workflows/agent_graph.py"]
WF --> R["config/routing.yaml"]
R --> A["app/agents/*_agent.py"]
A --> RT["AgentRuntimeMixin"]
RT --> T["config/tools.yaml"]
T --> P["config/tool_policies.yaml"]
T --> M["config/mcp_parameter_mapping.yaml"]
P --> MCP["MCP Tool Router / Gateway"]
M --> MCP
MCP --> S["mcp/servers/telecom or retail"]
P --> DW["workflows/*.yaml when execution=workflow"]
DW --> WA["app/workflow_actions/*.py"]
A --> RAG["RAG / memory / LLM"]
A --> OS["Output Supervisor"]
OS --> GR["Guardrails"]
GR --> J["Judges"]
J --> PS["Persistence / checkpoint / evidence"]
```
## 4. Rule inventory
| Intent | Rule | Agent | Priority | Tools |
|---|---|---|---:|---|
| `billing_invoice_explanation` | Billing / Invoice Explanation | `billing_agent` | 10 | `consultar_fatura`, `consultar_pagamentos` |
| `product_services_information` | Products, Plan, Services, and VAS | `product_agent` | 20 | `consultar_plano`, `listar_servicos` |
| `retail_order_cancel` | Order Cancellation | `orders_agent` | 20 | `consultar_pedido`, `cancelar_pedido` |
| `retail_order_tracking` | Order Query and Tracking | `orders_agent` | 30 | `consultar_pedido`, `consultar_entrega` |
| `retail_support_exchange_return` | Exchange, Return, Warranty, and Retail Support | `support_agent` | 25 | `consultar_pedido`, `solicitar_troca`, `solicitar_devolucao` |
# 5. Rule — Billing / Invoice Explanation
**Intent:** `billing_invoice_explanation`
**Domain:** `telecom`
**Agent:** `billing_agent`
**Priority:** `10`
## What this rule means
Questions about invoices, billing, due dates, duplicate copies, disputes, and amounts.
### Rule boundary
This is an informational/operational billing rule. It queries evidence; by itself it does not authorize a transactional financial action.
## `routing.yaml` attribute by attribute
| Attribute | Value in this rule | Role in the engine |
|---|---|---|
| `name` | billing_invoice_explanation | Stable intent identifier. It is stored in routing/telemetry state and links the decision to declared capabilities. |
| `domain` | telecom | Logical domain. It helps constrain context, agents, and catalog interpretation. |
| `agent` | billing_agent | Agent that receives the turn when this intent wins. |
| `description` | Questions about invoices, billing, due dates, duplicate copies, disputes, and amounts. | Semantic definition used by maintainers and by the LLM fallback. |
| `priority` | 10 | Tie-breaker among competing intents. In EnterpriseRouter, lower numeric values take precedence. |
| `mcp_tools` | consultar_fatura
consultar_pagamentos | Capabilities initially authorized/expected for this intent. |
| `keywords` | fatura
conta
cobrança
boleto
vencimento
segunda via
contestar
valor alto
invoice | Deterministic triggers evaluated before semantic fallback. |
| `examples` | Minha fatura veio alta.
Quero entender uma cobrança.
Preciso da segunda via da conta. | Examples offered to the LLM classifier; they are neither regexes nor executable rules. |
## How this intent is found
1. EnterpriseRouter checks active state/transaction before treating the utterance as a new request.
2. In deterministic matching, this intent offers keywords such as `fatura`, `conta`, `cobrança`, `boleto`, `vencimento`, `segunda via`, `contestar`, `valor alto`, `invoice`.
3. In collisions, `priority=10` participates in tie-breaking; lower values take precedence.
4. If LLM fallback is used, the description and examples such as `Minha fatura veio alta.`, `Quero entender uma cobrança.`, `Preciso da segunda via da conta.` help classification.
5. When the intent wins, state receives the route/agent and initial tool set `['consultar_fatura', 'consultar_pagamentos']`.
## Owning agent and Python behavior
File: `app/agents/billing_agent.py`.
Its `run()` follows a common pattern: emit start IC, collect MCP context, check transactional clarification/confirmation messages, try a direct MCP/renderer answer, retrieve RAG when necessary, prepare memory, assemble `messages`, call the LLM, and return a state patch.
This pattern comes from `app/agents/runtime.py::AgentRuntimeMixin`, preventing each agent from reimplementing MCP, RAG, cache, memory, IC, and transactional logic.
## Tools in this rule
### Tool `consultar_fatura`
**What it does:** Queries summarized invoice data by msisdn/invoice_id.
| Property | Value |
|---|---|
| MCP server | `telecom` |
| enabled | `True` |
| type/operation | `read_only` |
| confirmation required | `false` |
| requires | — |
| selection_keywords | `fatura`, `conta`, `boleto` |
| presentation | `mode=renderer`; renderer `telecom.invoice` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `msisdn` | `string` | canonical context `customer_key` | Número da linha do cliente (MSISDN) usado para consultar informações de telecom. |
| `invoice_id` | `string` | canonical context `contract_key` | Identificador da fatura que o cliente deseja consultar. |
**MCP aliases:** `customer_key → msisdn`, `contract_key → invoice_id`, `interaction_key → ura_call_id`, `session_key → session_id`.
**Conversational extraction:**
- `mes_referencia`: strategy `month_name_pt`; Extrair mês citado na mensagem. janeiro=1, fevereiro=2, março=3, abril=4, maio=5, junho=6, julho=7, agosto=8, setembro=9, outubro=10, novembro=11, dezembro=12.
**What it returns:** In the sample MCP it returns `invoice_id`, `msisdn`, `valor_total`, `vencimento`, `status`, and an `itens` list; the final envelope is `{ok, result, metadata}`.
### Tool `consultar_pagamentos`
**What it does:** Queries the customer's payment history.
| Property | Value |
|---|---|
| MCP server | `telecom` |
| enabled | `True` |
| type/operation | `read_only` |
| confirmation required | `false` |
| requires | — |
| selection_keywords | `pagamento`, `pagamentos` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `msisdn` | `string` | canonical context `customer_key` | Número da linha do cliente (MSISDN) usado para consultar informações de telecom. |
**MCP aliases:** `customer_key → msisdn`, `interaction_key → ura_call_id`, `session_key → session_id`.
**What it returns:** Returns `msisdn` and `pagamentos[]`, with date, amount, and payment status from the mock.
## Workflow
This rule does not require a dedicated declarative workflow in the base template. Execution occurs through MCP/the standard runtime; transactional states may still exist for parameter collection and confirmation.
## Binding between YAML and Python
- `config/routing.yaml` → finds `billing_invoice_explanation` and selects `billing_agent`.
- `config/tools.yaml` → describes arguments, MCP server, selection keywords, and renderer.
- `config/tool_policies.yaml` → defines read-only/transactional behavior, confirmation, pre-validation, and/or workflow.
- `config/mcp_parameter_mapping.yaml` → maps canonical keys and extracts fields from the message.
- `app/agents/billing_agent.py` → uses `AgentRuntimeMixin` to execute capabilities without duplicating infrastructure.
- `app/workflows/agent_graph.py` → connects the agent to the corporate graph and output controls.
- `mcp/servers/telecom_mcp_server/main.py` → mock/contract implementation for tool `consultar_fatura`.
- `mcp/servers/telecom_mcp_server/main.py` → mock/contract implementation for tool `consultar_pagamentos`.
### Relevant `.env` and configuration
- `ROUTING_CONFIG_PATH=./config/routing.yaml` and `ENABLE_LLM_ROUTER` control the routing catalog/semantic fallback.
- `ENABLE_ROUTE_STICKINESS`, `ROUTE_STICKINESS_*`, `HUMAN_HANDOFF_MESSAGE`, and `END_SESSION_MESSAGE` control continuity/session behavior.
- `ENABLE_MCP_TOOLS`, `MCP_SERVERS_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, and `MCP_TOOL_TIMEOUT_SECONDS` control tools.
- `MCP_GATEWAY_ENABLED` chooses between a dedicated MCP Gateway and direct access to configured MCP servers.
- Logical server `telecom` is resolved by `config/mcp_servers.yaml`; in the base template it points to `http://localhost:8100/mcp` using the legacy HTTP contract.
- `ENABLE_INPUT_GUARDRAILS`, `ENABLE_OUTPUT_GUARDRAILS`, `ENABLE_JUDGES`, and `ENABLE_OUTPUT_SUPERVISOR` affect the cycle before/after the agent.
- `ENABLE_CONVERSATION_SUMMARY_MEMORY` and `ENABLE_LONG_TERM_MEMORY` may enrich prompt/context without replacing MCP evidence.
- `RAG_PROVIDER`, `VECTOR_STORE_PROVIDER`, `GRAPH_STORE_PROVIDER`, `RAG_TOP_K`, and `KBDB_*` control documentary retrieval when used.
### Special diagnostic — why two tools appear under the same intent
The billing intent authorizes `consultar_fatura` and `consultar_pagamentos` because billing questions may require invoice evidence or payment-history evidence. This **does not mean both tools must run on every turn**.
`tools.yaml.selection_keywords`, current text, available arguments, and runtime state help select the appropriate capability. “I need a duplicate invoice / what is my invoice amount?” should favor `consultar_fatura`; a specific payment question should favor `consultar_pagamentos`.
# 6. Rule — Products, Plan, Services, and VAS
**Intent:** `product_services_information`
**Domain:** `telecom`
**Agent:** `product_agent`
**Priority:** `20`
## What this rule means
Questions about plans, packages, products, services, VAS, internet, roaming, and benefits.
### Rule boundary
It is used to discover plans/services/VAS and explain attributes. A product question must not be converted into a proactive offer or a transactional action.
## `routing.yaml` attribute by attribute
| Attribute | Value in this rule | Role in the engine |
|---|---|---|
| `name` | product_services_information | Stable intent identifier. It is stored in routing/telemetry state and links the decision to declared capabilities. |
| `domain` | telecom | Logical domain. It helps constrain context, agents, and catalog interpretation. |
| `agent` | product_agent | Agent that receives the turn when this intent wins. |
| `description` | Questions about plans, packages, products, services, VAS, internet, roaming, and benefits. | Semantic definition used by maintainers and by the LLM fallback. |
| `priority` | 20 | Tie-breaker among competing intents. In EnterpriseRouter, lower numeric values take precedence. |
| `mcp_tools` | consultar_plano
listar_servicos | Capabilities initially authorized/expected for this intent. |
| `keywords` | plano
serviço
pacote
internet
roaming
vas
benefício
assinatura | Deterministic triggers evaluated before semantic fallback. |
| `examples` | Quais serviços estão ativos no meu plano?
Quero saber sobre meu pacote de internet.
Tenho roaming internacional? | Examples offered to the LLM classifier; they are neither regexes nor executable rules. |
## How this intent is found
1. EnterpriseRouter checks active state/transaction before treating the utterance as a new request.
2. In deterministic matching, this intent offers keywords such as `plano`, `serviço`, `pacote`, `internet`, `roaming`, `vas`, `benefício`, `assinatura`.
3. In collisions, `priority=20` participates in tie-breaking; lower values take precedence.
4. If LLM fallback is used, the description and examples such as `Quais serviços estão ativos no meu plano?`, `Quero saber sobre meu pacote de internet.`, `Tenho roaming internacional?` help classification.
5. When the intent wins, state receives the route/agent and initial tool set `['consultar_plano', 'listar_servicos']`.
## Owning agent and Python behavior
File: `app/agents/product_agent.py`.
Its `run()` follows a common pattern: emit start IC, collect MCP context, check transactional clarification/confirmation messages, try a direct MCP/renderer answer, retrieve RAG when necessary, prepare memory, assemble `messages`, call the LLM, and return a state patch.
This pattern comes from `app/agents/runtime.py::AgentRuntimeMixin`, preventing each agent from reimplementing MCP, RAG, cache, memory, IC, and transactional logic.
## Tools in this rule
### Tool `consultar_plano`
**What it does:** Queries the active plan and commercial attributes.
| Property | Value |
|---|---|
| MCP server | `telecom` |
| enabled | `True` |
| type/operation | `read_only` |
| confirmation required | `false` |
| requires | — |
| selection_keywords | `plano` |
| presentation | `mode=renderer`; renderer `telecom.plan` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `msisdn` | `string` | canonical context `customer_key` | Número da linha do cliente (MSISDN) usado para consultar informações de telecom. |
| `asset_id` | `string` | canonical context `resource_key`; canonical context `contract_key` | Identificador do plano ou ativo comercial associado ao cliente. |
**MCP aliases:** `customer_key → msisdn`, `resource_key → asset_id`, `contract_key → asset_id`, `session_key → session_id`.
**What it returns:** Returns `msisdn`, `asset_id`, plan name, internet allowance, roaming attribute, and status.
### Tool `listar_servicos`
**What it does:** Lists active services and additional VAS.
| Property | Value |
|---|---|
| MCP server | `telecom` |
| enabled | `True` |
| type/operation | `read_only` |
| confirmation required | `false` |
| requires | — |
| selection_keywords | `serviços`, `servicos`, `vas` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `msisdn` | `string` | canonical context `customer_key` | Número da linha do cliente (MSISDN) usado para consultar informações de telecom. |
**MCP aliases:** `customer_key → msisdn`, `session_key → session_id`.
**What it returns:** Returns `msisdn` and `servicos[]` containing name, status, and amount.
## Workflow
This rule does not require a dedicated declarative workflow in the base template. Execution occurs through MCP/the standard runtime; transactional states may still exist for parameter collection and confirmation.
## Binding between YAML and Python
- `config/routing.yaml` → finds `product_services_information` and selects `product_agent`.
- `config/tools.yaml` → describes arguments, MCP server, selection keywords, and renderer.
- `config/tool_policies.yaml` → defines read-only/transactional behavior, confirmation, pre-validation, and/or workflow.
- `config/mcp_parameter_mapping.yaml` → maps canonical keys and extracts fields from the message.
- `app/agents/product_agent.py` → uses `AgentRuntimeMixin` to execute capabilities without duplicating infrastructure.
- `app/workflows/agent_graph.py` → connects the agent to the corporate graph and output controls.
- `mcp/servers/telecom_mcp_server/main.py` → mock/contract implementation for tool `consultar_plano`.
- `mcp/servers/telecom_mcp_server/main.py` → mock/contract implementation for tool `listar_servicos`.
### Relevant `.env` and configuration
- `ROUTING_CONFIG_PATH=./config/routing.yaml` and `ENABLE_LLM_ROUTER` control the routing catalog/semantic fallback.
- `ENABLE_ROUTE_STICKINESS`, `ROUTE_STICKINESS_*`, `HUMAN_HANDOFF_MESSAGE`, and `END_SESSION_MESSAGE` control continuity/session behavior.
- `ENABLE_MCP_TOOLS`, `MCP_SERVERS_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, and `MCP_TOOL_TIMEOUT_SECONDS` control tools.
- `MCP_GATEWAY_ENABLED` chooses between a dedicated MCP Gateway and direct access to configured MCP servers.
- Logical server `telecom` is resolved by `config/mcp_servers.yaml`; in the base template it points to `http://localhost:8100/mcp` using the legacy HTTP contract.
- `ENABLE_INPUT_GUARDRAILS`, `ENABLE_OUTPUT_GUARDRAILS`, `ENABLE_JUDGES`, and `ENABLE_OUTPUT_SUPERVISOR` affect the cycle before/after the agent.
- `ENABLE_CONVERSATION_SUMMARY_MEMORY` and `ENABLE_LONG_TERM_MEMORY` may enrich prompt/context without replacing MCP evidence.
- `RAG_PROVIDER`, `VECTOR_STORE_PROVIDER`, `GRAPH_STORE_PROVIDER`, `RAG_TOP_K`, and `KBDB_*` control documentary retrieval when used.
# 7. Rule — Order Cancellation
**Intent:** `retail_order_cancel`
**Domain:** `retail`
**Agent:** `orders_agent`
**Priority:** `20`
## What this rule means
Explicit cancellation of an order or purchase.
### Rule boundary
The intent represents the customer's desire to cancel. Execution still depends on `order_id`, pre-validation, and confirmation; an ineligible order is blocked before confirmation.
## `routing.yaml` attribute by attribute
| Attribute | Value in this rule | Role in the engine |
|---|---|---|
| `name` | retail_order_cancel | Stable intent identifier. It is stored in routing/telemetry state and links the decision to declared capabilities. |
| `domain` | retail | Logical domain. It helps constrain context, agents, and catalog interpretation. |
| `agent` | orders_agent | Agent that receives the turn when this intent wins. |
| `description` | Explicit cancellation of an order or purchase. | Semantic definition used by maintainers and by the LLM fallback. |
| `priority` | 20 | Tie-breaker among competing intents. In EnterpriseRouter, lower numeric values take precedence. |
| `mcp_tools` | consultar_pedido
cancelar_pedido | Capabilities initially authorized/expected for this intent. |
| `keywords` | cancelar pedido
cancelamento do pedido
cancelar a compra
cancelar compra | Deterministic triggers evaluated before semantic fallback. |
| `examples` | Quero cancelar meu pedido.
Cancele o pedido.
Quero cancelar a compra. | Examples offered to the LLM classifier; they are neither regexes nor executable rules. |
## How this intent is found
1. EnterpriseRouter checks active state/transaction before treating the utterance as a new request.
2. In deterministic matching, this intent offers keywords such as `cancelar pedido`, `cancelamento do pedido`, `cancelar a compra`, `cancelar compra`.
3. In collisions, `priority=20` participates in tie-breaking; lower values take precedence.
4. If LLM fallback is used, the description and examples such as `Quero cancelar meu pedido.`, `Cancele o pedido.`, `Quero cancelar a compra.` help classification.
5. When the intent wins, state receives the route/agent and initial tool set `['consultar_pedido', 'cancelar_pedido']`.
## Owning agent and Python behavior
File: `app/agents/orders_agent.py`.
Its `run()` follows a common pattern: emit start IC, collect MCP context, check transactional clarification/confirmation messages, try a direct MCP/renderer answer, retrieve RAG when necessary, prepare memory, assemble `messages`, call the LLM, and return a state patch.
This pattern comes from `app/agents/runtime.py::AgentRuntimeMixin`, preventing each agent from reimplementing MCP, RAG, cache, memory, IC, and transactional logic.
## Tools in this rule
### Tool `consultar_pedido`
**What it does:** Queries a retail order by order_id/customer_id.
| Property | Value |
|---|---|
| MCP server | `retail` |
| enabled | `True` |
| type/operation | `read_only` |
| confirmation required | `false` |
| requires | — |
| selection_keywords | `consultar pedido`, `status do pedido`, `pedido` |
| presentation | `mode=renderer`; renderer `retail.order` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `order_id` | `string` | `hybrid` extraction from `message` | Identificador do pedido que o cliente deseja consultar. |
| `customer_id` | `string` | canonical context `customer_key` | Identificador do cliente associado ao pedido de varejo. |
**MCP aliases:** `customer_key → customer_id`, `session_key → session_id`.
**Conversational extraction:**
- `order_id`: strategy `hybrid`; Extraia somente o identificador do pedido informado explicitamente pelo usuário. Retorne null quando não houver identificador de pedido na mensagem.
**What it returns:** Returns `order_id`, `customer_id`, `status`, `valor_total`, and `itens[]`. In the mock, `123` and `PED-ENTREGUE` are `ENTREGUE`; other orders are `EM_TRANSPORTE`.
### Tool `cancelar_pedido`
**What it does:** Simulates cancellation of a retail order.
| Property | Value |
|---|---|
| MCP server | `retail` |
| enabled | `True` |
| type/operation | `transactional` |
| confirmation required | `true` |
| requires | `order_id` |
| selection_keywords | `cancelar pedido`, `cancelamento do pedido`, `cancelar compra`, `cancelar a compra` |
| pre-validation | `validar_cancelamento_pedido`; `fail_open=false` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `order_id` | `string` | `hybrid` extraction from `message` | Identificador do pedido que o cliente deseja cancelar. |
**MCP aliases:** `session_key → session_id`.
**Conversational extraction:**
- `order_id`: strategy `hybrid`; Extraia somente o identificador do pedido informado explicitamente pelo usuário. Retorne null quando não houver identificador de pedido na mensagem.
**What it returns:** Returns a protocol, `order_id`, `CANCELAMENTO_SOLICITADO` status, and guidance. Because it is transactional, it must only execute after parameters, pre-validation, and confirmation.
### Internal tool used by the policy
### Tool `validar_cancelamento_pedido`
**What it does:** Pre-validates order cancellation without executing transactional side effects.
| Property | Value |
|---|---|
| MCP server | `retail` |
| enabled | `True` |
| type/operation | `internal` |
| confirmation required | `false` |
| requires | `order_id` |
| selection_keywords | — |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `order_id` | `string` | canonical context `resource_key` | Identificador do pedido a ser pre-validado para cancelamento. |
| `target_tool` | `string` | state/context, parameter collection, or explicit call | Nome interno da operação transacional que será pre-validada; normalmente preenchido pelo runtime e não solicitado ao usuário. |
**MCP aliases:** `resource_key → order_id`.
**What it returns:** Returns `eligible`, `status`, `order_id`, a `reason` when blocked, and `side_effect_free` metadata. It is an internal/read-only tool used before confirmation.
## Workflow
This rule does not require a dedicated declarative workflow in the base template. Execution occurs through MCP/the standard runtime; transactional states may still exist for parameter collection and confirmation.
## Binding between YAML and Python
- `config/routing.yaml` → finds `retail_order_cancel` and selects `orders_agent`.
- `config/tools.yaml` → describes arguments, MCP server, selection keywords, and renderer.
- `config/tool_policies.yaml` → defines read-only/transactional behavior, confirmation, pre-validation, and/or workflow.
- `config/mcp_parameter_mapping.yaml` → maps canonical keys and extracts fields from the message.
- `app/agents/orders_agent.py` → uses `AgentRuntimeMixin` to execute capabilities without duplicating infrastructure.
- `app/workflows/agent_graph.py` → connects the agent to the corporate graph and output controls.
- `mcp/servers/retail_mcp_server/main.py` → mock/contract implementation for tool `consultar_pedido`.
- `mcp/servers/retail_mcp_server/main.py` → mock/contract implementation for tool `cancelar_pedido`.
### Relevant `.env` and configuration
- `ROUTING_CONFIG_PATH=./config/routing.yaml` and `ENABLE_LLM_ROUTER` control the routing catalog/semantic fallback.
- `ENABLE_ROUTE_STICKINESS`, `ROUTE_STICKINESS_*`, `HUMAN_HANDOFF_MESSAGE`, and `END_SESSION_MESSAGE` control continuity/session behavior.
- `ENABLE_MCP_TOOLS`, `MCP_SERVERS_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, and `MCP_TOOL_TIMEOUT_SECONDS` control tools.
- `MCP_GATEWAY_ENABLED` chooses between a dedicated MCP Gateway and direct access to configured MCP servers.
- Logical server `retail` is resolved by `config/mcp_servers.yaml`; in the base template it points to `http://localhost:8200/mcp` using the legacy HTTP contract.
- `ENABLE_INPUT_GUARDRAILS`, `ENABLE_OUTPUT_GUARDRAILS`, `ENABLE_JUDGES`, and `ENABLE_OUTPUT_SUPERVISOR` affect the cycle before/after the agent.
- `ENABLE_CONVERSATION_SUMMARY_MEMORY` and `ENABLE_LONG_TERM_MEMORY` may enrich prompt/context without replacing MCP evidence.
- `RAG_PROVIDER`, `VECTOR_STORE_PROVIDER`, `GRAPH_STORE_PROVIDER`, `RAG_TOP_K`, and `KBDB_*` control documentary retrieval when used.
### Special diagnostic — why `PED-ENTREGUE` never reaches confirmation
Intent `retail_order_cancel` represents the **customer's objective**: cancel an order. After routing, the `cancelar_pedido` policy requires `order_id`, calls pre-validation tool `validar_cancelamento_pedido`, and only allows `AWAITING_CONFIRMATION` when the validator returns `eligible=true`.
In the sample MCP:
```text
PED-1001
→ validar_cancelamento_pedido
→ eligible=true
→ AWAITING_CONFIRMATION
→ "yes"
→ cancelar_pedido
→ protocol CANCEL-2026-001
```
For:
```text
PED-ENTREGUE
→ validar_cancelamento_pedido
→ eligible=false / NOT_ELIGIBLE
→ OUT_OF_SCOPE
→ no confirmation question
→ cancelar_pedido does not execute
```
This illustrates the architectural rule: **intent is not operational authorization**. Intent expresses what the customer wants; domain pre-validation determines whether the operation may proceed.
# 8. Rule — Order Query and Tracking
**Intent:** `retail_order_tracking`
**Domain:** `retail`
**Agent:** `orders_agent`
**Priority:** `30`
## What this rule means
Order, delivery, tracking, delay, and purchase-status queries.
### Rule boundary
This is read-only: it queries order/delivery state and must not modify the order.
## `routing.yaml` attribute by attribute
| Attribute | Value in this rule | Role in the engine |
|---|---|---|
| `name` | retail_order_tracking | Stable intent identifier. It is stored in routing/telemetry state and links the decision to declared capabilities. |
| `domain` | retail | Logical domain. It helps constrain context, agents, and catalog interpretation. |
| `agent` | orders_agent | Agent that receives the turn when this intent wins. |
| `description` | Order, delivery, tracking, delay, and purchase-status queries. | Semantic definition used by maintainers and by the LLM fallback. |
| `priority` | 30 | Tie-breaker among competing intents. In EnterpriseRouter, lower numeric values take precedence. |
| `mcp_tools` | consultar_pedido
consultar_entrega | Capabilities initially authorized/expected for this intent. |
| `keywords` | pedido
entrega
rastreio
rastreamento
encomenda
compra
atraso
correios | Deterministic triggers evaluated before semantic fallback. |
| `examples` | Meu pedido não chegou.
Quero rastrear minha entrega.
Qual é o status da minha compra? | Examples offered to the LLM classifier; they are neither regexes nor executable rules. |
## How this intent is found
1. EnterpriseRouter checks active state/transaction before treating the utterance as a new request.
2. In deterministic matching, this intent offers keywords such as `pedido`, `entrega`, `rastreio`, `rastreamento`, `encomenda`, `compra`, `atraso`, `correios`.
3. In collisions, `priority=30` participates in tie-breaking; lower values take precedence.
4. If LLM fallback is used, the description and examples such as `Meu pedido não chegou.`, `Quero rastrear minha entrega.`, `Qual é o status da minha compra?` help classification.
5. When the intent wins, state receives the route/agent and initial tool set `['consultar_pedido', 'consultar_entrega']`.
## Owning agent and Python behavior
File: `app/agents/orders_agent.py`.
Its `run()` follows a common pattern: emit start IC, collect MCP context, check transactional clarification/confirmation messages, try a direct MCP/renderer answer, retrieve RAG when necessary, prepare memory, assemble `messages`, call the LLM, and return a state patch.
This pattern comes from `app/agents/runtime.py::AgentRuntimeMixin`, preventing each agent from reimplementing MCP, RAG, cache, memory, IC, and transactional logic.
## Tools in this rule
### Tool `consultar_pedido`
**What it does:** Queries a retail order by order_id/customer_id.
| Property | Value |
|---|---|
| MCP server | `retail` |
| enabled | `True` |
| type/operation | `read_only` |
| confirmation required | `false` |
| requires | — |
| selection_keywords | `consultar pedido`, `status do pedido`, `pedido` |
| presentation | `mode=renderer`; renderer `retail.order` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `order_id` | `string` | `hybrid` extraction from `message` | Identificador do pedido que o cliente deseja consultar. |
| `customer_id` | `string` | canonical context `customer_key` | Identificador do cliente associado ao pedido de varejo. |
**MCP aliases:** `customer_key → customer_id`, `session_key → session_id`.
**Conversational extraction:**
- `order_id`: strategy `hybrid`; Extraia somente o identificador do pedido informado explicitamente pelo usuário. Retorne null quando não houver identificador de pedido na mensagem.
**What it returns:** Returns `order_id`, `customer_id`, `status`, `valor_total`, and `itens[]`. In the mock, `123` and `PED-ENTREGUE` are `ENTREGUE`; other orders are `EM_TRANSPORTE`.
### Tool `consultar_entrega`
**What it does:** Queries delivery and tracking data for an order.
| Property | Value |
|---|---|
| MCP server | `retail` |
| enabled | `True` |
| type/operation | `read_only` |
| confirmation required | `false` |
| requires | — |
| selection_keywords | `entrega`, `rastreio`, `rastreamento`, `transportadora`, `previsão` |
| presentation | `mode=renderer`; renderer `retail.delivery` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `order_id` | `string` | `hybrid` extraction from `message` | Identificador do pedido cuja entrega ou rastreamento será consultado. |
**MCP aliases:** `session_key → session_id`.
**Conversational extraction:**
- `order_id`: strategy `hybrid`; Extraia somente o identificador do pedido informado explicitamente pelo usuário. Retorne null quando não houver identificador de pedido na mensagem.
**What it returns:** Returns `order_id`, carrier, tracking code, forecast, and movement events.
## Workflow
This rule does not require a dedicated declarative workflow in the base template. Execution occurs through MCP/the standard runtime; transactional states may still exist for parameter collection and confirmation.
## Binding between YAML and Python
- `config/routing.yaml` → finds `retail_order_tracking` and selects `orders_agent`.
- `config/tools.yaml` → describes arguments, MCP server, selection keywords, and renderer.
- `config/tool_policies.yaml` → defines read-only/transactional behavior, confirmation, pre-validation, and/or workflow.
- `config/mcp_parameter_mapping.yaml` → maps canonical keys and extracts fields from the message.
- `app/agents/orders_agent.py` → uses `AgentRuntimeMixin` to execute capabilities without duplicating infrastructure.
- `app/workflows/agent_graph.py` → connects the agent to the corporate graph and output controls.
- `mcp/servers/retail_mcp_server/main.py` → mock/contract implementation for tool `consultar_pedido`.
- `mcp/servers/retail_mcp_server/main.py` → mock/contract implementation for tool `consultar_entrega`.
### Relevant `.env` and configuration
- `ROUTING_CONFIG_PATH=./config/routing.yaml` and `ENABLE_LLM_ROUTER` control the routing catalog/semantic fallback.
- `ENABLE_ROUTE_STICKINESS`, `ROUTE_STICKINESS_*`, `HUMAN_HANDOFF_MESSAGE`, and `END_SESSION_MESSAGE` control continuity/session behavior.
- `ENABLE_MCP_TOOLS`, `MCP_SERVERS_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, and `MCP_TOOL_TIMEOUT_SECONDS` control tools.
- `MCP_GATEWAY_ENABLED` chooses between a dedicated MCP Gateway and direct access to configured MCP servers.
- Logical server `retail` is resolved by `config/mcp_servers.yaml`; in the base template it points to `http://localhost:8200/mcp` using the legacy HTTP contract.
- `ENABLE_INPUT_GUARDRAILS`, `ENABLE_OUTPUT_GUARDRAILS`, `ENABLE_JUDGES`, and `ENABLE_OUTPUT_SUPERVISOR` affect the cycle before/after the agent.
- `ENABLE_CONVERSATION_SUMMARY_MEMORY` and `ENABLE_LONG_TERM_MEMORY` may enrich prompt/context without replacing MCP evidence.
- `RAG_PROVIDER`, `VECTOR_STORE_PROVIDER`, `GRAPH_STORE_PROVIDER`, `RAG_TOP_K`, and `KBDB_*` control documentary retrieval when used.
# 9. Rule — Exchange, Return, Warranty, and Retail Support
**Intent:** `retail_support_exchange_return`
**Domain:** `retail`
**Agent:** `support_agent`
**Priority:** `25`
## What this rule means
Support, exchange, return, warranty, and product-problem requests.
### Rule boundary
It groups post-sale support. The intent may select exchange or return as the specific tool; transactional actions still require confirmation.
## `routing.yaml` attribute by attribute
| Attribute | Value in this rule | Role in the engine |
|---|---|---|
| `name` | retail_support_exchange_return | Stable intent identifier. It is stored in routing/telemetry state and links the decision to declared capabilities. |
| `domain` | retail | Logical domain. It helps constrain context, agents, and catalog interpretation. |
| `agent` | support_agent | Agent that receives the turn when this intent wins. |
| `description` | Support, exchange, return, warranty, and product-problem requests. | Semantic definition used by maintainers and by the LLM fallback. |
| `priority` | 25 | Tie-breaker among competing intents. In EnterpriseRouter, lower numeric values take precedence. |
| `mcp_tools` | consultar_pedido
solicitar_troca
solicitar_devolucao | Capabilities initially authorized/expected for this intent. |
| `keywords` | solicitar devolução
devolver pedido
solicitar troca
troca
devolução
devolver
garantia
defeito
produto quebrado
suporte
arrependimento | Deterministic triggers evaluated before semantic fallback. |
| `examples` | Quero trocar um produto.
Meu produto veio com defeito.
Como faço uma devolução? | Examples offered to the LLM classifier; they are neither regexes nor executable rules. |
## How this intent is found
1. EnterpriseRouter checks active state/transaction before treating the utterance as a new request.
2. In deterministic matching, this intent offers keywords such as `solicitar devolução`, `devolver pedido`, `solicitar troca`, `troca`, `devolução`, `devolver`, `garantia`, `defeito`, `produto quebrado`, `suporte`.
3. In collisions, `priority=25` participates in tie-breaking; lower values take precedence.
4. If LLM fallback is used, the description and examples such as `Quero trocar um produto.`, `Meu produto veio com defeito.`, `Como faço uma devolução?` help classification.
5. When the intent wins, state receives the route/agent and initial tool set `['consultar_pedido', 'solicitar_troca', 'solicitar_devolucao']`.
## Owning agent and Python behavior
File: `app/agents/support_agent.py`.
Its `run()` follows a common pattern: emit start IC, collect MCP context, check transactional clarification/confirmation messages, try a direct MCP/renderer answer, retrieve RAG when necessary, prepare memory, assemble `messages`, call the LLM, and return a state patch.
This pattern comes from `app/agents/runtime.py::AgentRuntimeMixin`, preventing each agent from reimplementing MCP, RAG, cache, memory, IC, and transactional logic.
## Tools in this rule
### Tool `consultar_pedido`
**What it does:** Queries a retail order by order_id/customer_id.
| Property | Value |
|---|---|
| MCP server | `retail` |
| enabled | `True` |
| type/operation | `read_only` |
| confirmation required | `false` |
| requires | — |
| selection_keywords | `consultar pedido`, `status do pedido`, `pedido` |
| presentation | `mode=renderer`; renderer `retail.order` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `order_id` | `string` | `hybrid` extraction from `message` | Identificador do pedido que o cliente deseja consultar. |
| `customer_id` | `string` | canonical context `customer_key` | Identificador do cliente associado ao pedido de varejo. |
**MCP aliases:** `customer_key → customer_id`, `session_key → session_id`.
**Conversational extraction:**
- `order_id`: strategy `hybrid`; Extraia somente o identificador do pedido informado explicitamente pelo usuário. Retorne null quando não houver identificador de pedido na mensagem.
**What it returns:** Returns `order_id`, `customer_id`, `status`, `valor_total`, and `itens[]`. In the mock, `123` and `PED-ENTREGUE` are `ENTREGUE`; other orders are `EM_TRANSPORTE`.
### Tool `solicitar_troca`
**What it does:** Simulates opening an exchange request.
| Property | Value |
|---|---|
| MCP server | `retail` |
| enabled | `True` |
| type/operation | `transactional` |
| confirmation required | `true` |
| requires | `order_id`, `reason` |
| selection_keywords | `solicitar troca`, `trocar`, `troca`, `defeito`, `quebrado` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `order_id` | `string` | `hybrid` extraction from `message` | Identificador do pedido para o qual o cliente deseja solicitar troca. |
| `reason` | `string` | default `Solicitação aberta pelo atendimento conversacional.` | Motivo informado pelo cliente para solicitar a troca do pedido. |
**MCP aliases:** `session_key → session_id`.
**Conversational extraction:**
- `order_id`: strategy `hybrid`; Extraia somente o identificador do pedido informado explicitamente pelo usuário. Retorne null quando não houver identificador de pedido na mensagem.
**What it returns:** Returns a protocol, `order_id`, `ABERTO` status, and guidance for shipment/continuation of the exchange.
### Tool `solicitar_devolucao`
**What it does:** Simulates opening a return request.
| Property | Value |
|---|---|
| MCP server | `retail` |
| enabled | `True` |
| type/operation | `transactional` |
| confirmation required | `true` |
| requires | `order_id`, `reason` |
| selection_keywords | `solicitar devolução`, `solicitar devolucao`, `devolver pedido`, `devolver`, `devolução`, `devolucao`, `arrependimento` |
| execution | `mode=workflow`; workflow `devolucao_pedido`; version `active` |
**Required data and origin**
| Field | Type | How it is obtained | Use |
|---|---|---|---|
| `order_id` | `string` | `hybrid` extraction from `message` | Identificador do pedido para o qual o cliente deseja solicitar devolução. |
| `reason` | `string` | default `Solicitação aberta pelo atendimento conversacional.` | Motivo informado pelo cliente para solicitar a devolução do pedido. |
**MCP aliases:** `session_key → session_id`.
**Conversational extraction:**
- `order_id`: strategy `hybrid`; Extraia somente o identificador do pedido informado explicitamente pelo usuário. Retorne null quando não houver identificador de pedido na mensagem.
**What it returns:** In direct MCP mode it returns protocol/status/guidance; in the normal template the policy selects `execution.mode: workflow`, so final execution goes through the deterministic `devolucao_pedido` workflow.
**Special execution:** this tool is bound to a deterministic workflow by policy; see the workflow section below.
## Workflow(s) involved
### Workflow `devolucao_pedido.v1.yaml`
**Contract:** `name=devolucao_pedido`, `version=1`, `start=validar_pedido`.
**Why it is built this way:** a return is a transactional multi-step action. The template separates the conversational decision from deterministic execution: it first validates the order and only registers the return when validation produces `valid=true`. This prevents the LLM from freely choosing the sequence of side effects.
#### Nodes
| Node | Action | Input | Role |
|---|---|---|---|
| `validar_pedido` | `validar_pedido` | `order_id=$.input.order_id` | Initial validation point. |
| `registrar_devolucao` | `registrar_devolucao` | `order_id=$.input.order_id`, `reason=$.input.reason` | Executes the return effect/registration. Uses `retry=1`. |
#### Conditions and termination
| From | To | Condition | Consequence |
|---|---|---|---|
| `validar_pedido` | `registrar_devolucao` | `{"path": "$.nodes.validar_pedido.valid", "equals": true}` | Advances to `registrar_devolucao`. |
| `validar_pedido` | `END` | `{"path": "$.nodes.validar_pedido.valid", "equals": false}` | Terminates the workflow. |
| `registrar_devolucao` | `END` | always | Terminates the workflow. |
#### Python actions
- `app/workflow_actions/devolucao.py::validar_pedido`: validates `order_id` and returns a contract containing `valid`.
- `app/workflow_actions/devolucao.py::registrar_devolucao`: deterministically records the return result and produces `protocol`, `order_id`, `status`, and the data required for the response.
#### Pause/Resume
This base workflow **does not contain a pause node**. Collection of `order_id`/`reason` and confirmation happen earlier in the transactional runtime. Pause/resume examples are demonstrated separately in `Tuning-Performance/Pause_Resume_Workflow`.
## Binding between YAML and Python
- `config/routing.yaml` → finds `retail_support_exchange_return` and selects `support_agent`.
- `config/tools.yaml` → describes arguments, MCP server, selection keywords, and renderer.
- `config/tool_policies.yaml` → defines read-only/transactional behavior, confirmation, pre-validation, and/or workflow.
- `config/mcp_parameter_mapping.yaml` → maps canonical keys and extracts fields from the message.
- `app/agents/support_agent.py` → uses `AgentRuntimeMixin` to execute capabilities without duplicating infrastructure.
- `app/workflows/agent_graph.py` → connects the agent to the corporate graph and output controls.
- `mcp/servers/retail_mcp_server/main.py` → mock/contract implementation for tool `consultar_pedido`.
- `mcp/servers/retail_mcp_server/main.py` → mock/contract implementation for tool `solicitar_troca`.
- `mcp/servers/retail_mcp_server/main.py` → mock/contract implementation for tool `solicitar_devolucao`.
### Relevant `.env` and configuration
- `ROUTING_CONFIG_PATH=./config/routing.yaml` and `ENABLE_LLM_ROUTER` control the routing catalog/semantic fallback.
- `ENABLE_ROUTE_STICKINESS`, `ROUTE_STICKINESS_*`, `HUMAN_HANDOFF_MESSAGE`, and `END_SESSION_MESSAGE` control continuity/session behavior.
- `ENABLE_MCP_TOOLS`, `MCP_SERVERS_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, and `MCP_TOOL_TIMEOUT_SECONDS` control tools.
- `MCP_GATEWAY_ENABLED` chooses between a dedicated MCP Gateway and direct access to configured MCP servers.
- Logical server `retail` is resolved by `config/mcp_servers.yaml`; in the base template it points to `http://localhost:8200/mcp` using the legacy HTTP contract.
- `ENABLE_INPUT_GUARDRAILS`, `ENABLE_OUTPUT_GUARDRAILS`, `ENABLE_JUDGES`, and `ENABLE_OUTPUT_SUPERVISOR` affect the cycle before/after the agent.
- `ENABLE_CONVERSATION_SUMMARY_MEMORY` and `ENABLE_LONG_TERM_MEMORY` may enrich prompt/context without replacing MCP evidence.
- `RAG_PROVIDER`, `VECTOR_STORE_PROVIDER`, `GRAPH_STORE_PROVIDER`, `RAG_TOP_K`, and `KBDB_*` control documentary retrieval when used.
### Special diagnostic — exchange and return share an intent, but not the same execution
`retail_support_exchange_return` groups post-sale support because the phrases have strong semantic overlap. **Tool** selection occurs inside the allowed set:
- “trocar”, “troca”, “defeito”, “quebrado” → `solicitar_troca`;
- “devolver”, “devolução”, “arrependimento” → `solicitar_devolucao`;
- `consultar_pedido` may be used to obtain resource context.
Both actions are transactional and require confirmation. The main difference is that `solicitar_devolucao` has this policy in `tool_policies.yaml`:
```yaml
execution:
mode: workflow
workflow: devolucao_pedido
version: active
```
Therefore, after confirmation, a return is not merely a direct call: it enters the deterministic workflow. Exchange follows the standard transactional tool execution path.
# Cross-cutting template rules and mechanisms
## Tool selection within one intent
`routing.yaml.mcp_tools` defines the set compatible with the intent. `tools.yaml.selection_keywords`, available arguments, transactional state, and policies help determine which capability should execute. Two tools belonging to the same intent does not mean both must run.
## Direct MCP response versus LLM
Agents call `build_direct_mcp_answer()`. When the result contains a sufficient deterministic renderer/contract, the runtime may respond directly and mark RAG as `skipped: direct_mcp_answer`.
When a direct answer is insufficient, the agent may retrieve RAG, prepare memory, and use the LLM.
## `prompt_policy.yaml`
Defines tone and preferred vocabulary; it also registers intents/agents for prompt composition. It does not replace `routing.yaml`.
## Configuration by `agent_id`
`config/agents//prompt_policy.yaml`, `guardrails.yaml`, and `judges.yaml` allow each logical identity to be specialized. The registry lives in `config/agents.yaml`.
## MCP transport
`config/mcp_servers.yaml` documents three styles:
- `http`: framework legacy contract;
- `fastmcp`: official MCP Streamable HTTP;
- `sse`: official MCP SSE.
In the base template, `telecom` and `retail` use local `http`, but the registry can change without rewriting agents.
## MCP Gateway
With `MCP_GATEWAY_ENABLED=true`, the backend delegates calls to the dedicated MCP Gateway (`MCP_GATEWAY_URL`). With `false`, it uses registry endpoints directly.
## Summarized memory
`ENABLE_CONVERSATION_SUMMARY_MEMORY=true` allows summary + recent messages to be prepared before assembling `messages`. The goal is to reduce context while preserving continuity.
## RAG
The template may use memory/vector/graph stores and KBDB. RAG does not replace an operational tool. `ProductAgent` emits detailed IC even when retrieval was attempted but produced no context.
## Observability
The runtime can publish events to Langfuse, OTEL, and analytics. `AgentObserver` standardizes IC/NOC/GRL. The template's `TelemetryObserver` connects workflow events to observability infrastructure.
## Presentation
`app/presentation/tool_renderers.py` decouples MCP payload from textual/visual response. Renderers are useful when deterministic presentation should avoid LLM cost/latency.
## Workflow actions
`app/workflow_actions/` contains domain effects/actions referenced by YAML. Workflow defines order/conditions; the action implements the operation.
## Diagnosing an unexpected decision
1. Check `agent_id`.
2. Inspect `transaction_status`, `next_state`, paused workflow, and checkpoint.
3. Inspect `routing_decision` and method (`state`, keyword, LLM, stickiness).
4. Confirm intent, route, and `mcp_tools`.
5. See which tool was actually selected.
6. Compare `requires` with `resolved_arguments`/`missing_parameters`.
7. Look for temporal reconciliation/contextual reentry.
8. Inspect `transaction_pre_validation`.
9. Confirm whether `AWAITING_CONFIRMATION` occurred.
10. Identify direct execution versus workflow.
11. Inspect `mcp_results`, `transaction_evidence`, RAG, and renderer.
12. Check Output Supervisor, guardrails, and judges.
13. Confirm persistence/pending topics at the end of the turn.
# Part II — `Tuning-Performance`
`Tuning-Performance` should not be read merely as “speed optimization.” The folder acts as a catalog of **isolated framework-capability scenarios**, useful for benchmarking, regression, and architectural understanding.
The base template already incorporates several of these capabilities. Some directories contain a modified executable copy; others contain documentation only; `Normal` and `Long_Term_Memory` are empty in this package and therefore do not represent an additional executable variant in this version.
## `Tuning-Performance` inventory
| Scenario | Content in this package | Objective |
|---|---|---|
| `Authentication` | README + executable template variant | Cross-cutting authentication through providers/middleware and route policies. |
| `Deterministic_Transactional_Workflow` | README + executable template variant | Deterministic multi-step execution after confirmation. |
| `Domain_Requested_LLM_Composition` | documentation/example | Domain requests composition through the official LLM without creating a private LLM gateway. |
| `Domain_Requested_RAG` | documentation/example | Domain requests framework RAG when MCP is insufficient. |
| `External_Guardrails_Judges` | README + executable template variant | External guardrail/judge extensions and overhead measurement. |
| `Long_Term_Memory` | documentation/example | Reserved directory; the capability exists in framework/template, with no local variant in this package. |
| `Normal` | documentation/example | Reserved baseline; empty directory in this package. |
| `Offline_Workflow_Regression` | documentation/example | Opt-in deterministic fallback for offline workflow-DSL regression tests. |
| `Pause_Resume_Workflow` | README + executable template variant | Pause/resume by execution_id and expected_input. |
| `Route_Stickness` | documentation/example | Semantic continuity, handoff, session ending, and MCP policies. |
| `Transaction_Evidence` | README + executable template variant | Persistence/correlation of transactional operational evidence. |
| `Transaction_Pre_Validation` | README + executable template variant | Side-effect-free MCP validator before confirmation. |
| `Voice_Interruption_Replay` | documentation/example | Voice short-circuit/replay without incorrectly reexecuting the graph. |
| `Workflow_Error_Recovery` | documentation/example | Partial snapshot and structured error_details on workflow failure. |
# T1. Tuning — `Authentication`
**Objective:** Cross-cutting authentication through providers/middleware and route policies.
## What this scenario demonstrates
Demonstrates authentication as a cross-cutting HTTP concern, installed before conversational processing, with provider-specific configuration and public/protected route policies.
## Delta from the base template
Analyzed variant: `Tuning-Performance/Authentication/agent_template_backend_authentication`.
**Changed files:** `requirements.txt`, `README.md`, `.env.example`, `app/main.py`, `app/state.py`, `docs/TRANSACTION_SEMANTIC_CONFIRMATION.md`, `config/mcp_parameter_mapping.yaml`, `config/tools.yaml`, `config/tool_policies.yaml`, `app/agents/product_agent.py`, `app/workflows/agent_graph.py`.
**Added files:** `docs/MANUAL_AUTENTICACAO.md`, `config/authentication.example.yaml`, `scripts/generate_secret_hash.py`.
## Engine and configuration
The variant uses `install_authentication()`/providers from `libs/agent_framework/security` and adds `config/authentication.example.yaml`. `.env.example` demonstrates:
```text
AGENT_AUTH_MODE=basic|api_key|bearer_static|jwt|oauth2_introspection|trusted_proxy
AGENT_AUTH_PUBLIC_PATHS
AGENT_AUTH_PUBLIC_PREFIXES
```
In the Basic example, the credential is stored as a hash (`AGENT_AUTH_BASIC_SECRET_HASH`) and `scripts/generate_secret_hash.py` helps generate it.
Authentication is **cross-cutting**: it occurs at the HTTP edge/middleware before the conversational engine. It must not become a routing keyword or an agent rule.
## What to validate
- truly public routes;
- fail-closed behavior on protected routes;
- secret storage/rotation;
- claims/roles/scopes per provider;
- blocking direct pod access when using `trusted_proxy`;
- observability without logging secrets/tokens.
The documentation itself marks this as a reference implementation requiring security review before production.
# T2. Tuning — `Deterministic_Transactional_Workflow`
**Objective:** Deterministic multi-step execution after confirmation.
## What this scenario demonstrates
Demonstrates how a confirmed transactional capability can be delegated to a deterministic workflow so the LLM does not choose the side-effect sequence.
## Delta from the base template
Analyzed variant: `Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend`.
**Changed files:** `.env.example`, `app/main.py`, `app/state.py`, `docs/TRANSACTION_SEMANTIC_CONFIRMATION.md`, `config/mcp_parameter_mapping.yaml`, `config/tools.yaml`, `config/tool_policies.yaml`, `app/agents/product_agent.py`, `app/agents/runtime.py`, `app/workflows/agent_graph.py`.
**Added files:** `tests/test_transactional_workflow_template.py`.
## Flow
```text
router
→ support_agent
→ collect order_id + reason
→ AWAITING_CONFIRMATION
→ explicit confirmation
→ policy execution.mode=workflow
→ WorkflowToolExecutor
→ devolucao_pedido.active.yaml
→ devolucao_pedido.v1.yaml
→ validar_pedido
→ registrar_devolucao
→ protocol + workflow_execution_id
```
The main gain is not simply “having confirmation” — that already exists. The differentiator is **removing post-confirmation sequence choice from the LLM**.
## What to measure
- collection/confirmation time;
- workflow latency;
- action retries;
- idempotency/reexecution;
- `workflow_execution_id` consistency;
- response when `validar_pedido.valid=false`.
# T3. Tuning — `Domain_Requested_LLM_Composition`
**Objective:** Domain requests composition through the official LLM without creating a private LLM gateway.
## What this scenario demonstrates
Demonstrates a domain result explicitly requesting answer composition by the framework's official LLM path.
## Contract
A tool/workflow may return:
```json
{
"requires_llm_composition": true,
"response_instruction": "Explain using only workflow evidence."
}
```
or `response_instructions` as a list.
`AgentRuntimeMixin` detects the flag recursively. When active, `build_direct_mcp_answer()` does not end the turn; MCP output becomes evidence for composition through the official LLM.
## Architectural rule
The domain may request **wording/composition**, but it must not use this mechanism to decide whether a transaction occurs, invent amounts/protocols, or create a private LLM provider. Provider, profile, tracing, credentials, and costs remain framework responsibilities.
# T4. Tuning — `Domain_Requested_RAG`
**Objective:** Domain requests framework RAG when MCP is insufficient.
## What this scenario demonstrates
Demonstrates a domain result explicitly requesting framework RAG, including one or more retrieval queries.
## Contract
```json
{
"requires_rag": true,
"rag_queries": [
"Documentary question 1",
"Documentary question 2"
]
}
```
Flow:
```text
tool/workflow
→ requires_rag
→ AgentRuntimeMixin
→ framework RagService
→ vector/graph store
→ LLM with MCP evidence + RAG evidence
```
The flag may override `SKIP_RAG_WHEN_MCP_SUFFICIENT`. The domain does not instantiate embeddings/vector stores; it only declares the need and queries.
# T5. Tuning — `External_Guardrails_Judges`
**Objective:** External guardrail/judge extensions and overhead measurement.
## What this scenario demonstrates
Demonstrates external guardrail/judge extensions and the latency/behavioral overhead they introduce.
## Delta from the base template
Analyzed variant: `Tuning-Performance/External_Guardrails_Judges/agent_template_backend`.
**Changed files:** `README.md`, `llm_profiles.yaml`, `.env.example`, `app/main.py`, `app/state.py`, `docs/TRANSACTION_SEMANTIC_CONFIRMATION.md`, `config/judges.yaml`, `config/mcp_parameter_mapping.yaml`, `config/tools.yaml`, `config/tool_policies.yaml`, `config/guardrails.yaml`, `app/agents/product_agent.py`, `app/workflows/agent_graph.py`.
**Added files:** `app/extensions/example_judges.py`, `app/extensions/__init__.py`, `app/extensions/example_guardrails.py`.
## What changes
The variant adds extensions in `app/extensions/example_guardrails.py` and `app/extensions/example_judges.py` and changes configuration to demonstrate `type: external`.
## Correct benchmark
Compare with the extension disabled and separate:
- p50/p95/p99;
- allow/deny/sanitize;
- timeout/error;
- LLM-judge cost;
- fail-open/fail-closed behavior;
- transactional cases, because `always_run_for_transactional` may bypass sampling.
Synchronous implementations may use a worker thread; `async` uses the event loop. Tuning should observe provider/pool contention and must not log prompts/PII/financial payloads.
# T6. Tuning — `Long_Term_Memory`
**Objective:** Reserved directory; the capability exists in framework/template, with no local variant in this package.
## What this scenario demonstrates
The directory is empty in this package; the capability is documented from the base template itself.
## How it works in the base template
The graph calls `load_long_term_memory` before routing and `persist_long_term_memory` near the end. The manager is created by `create_long_term_memory_manager(settings, telemetry=telemetry)` and injected into agents.
Main variables:
```text
ENABLE_LONG_TERM_MEMORY
LONG_TERM_MEMORY_PROVIDER
LONG_TERM_MEMORY_SQLITE_PATH
LONG_TERM_MEMORY_TABLE
LONG_TERM_MEMORY_MAX_CONTEXT_ITEMS
LONG_TERM_MEMORY_MIN_CONFIDENCE
LONG_TERM_MEMORY_AUTO_EXTRACT
LONG_TERM_MEMORY_INJECT_CONTEXT
```
**Do not confuse it with Transaction Evidence:** LTM is semantic/durable memory; transaction evidence is structured operational fact tied to an execution/resource.
# T7. Tuning — `Normal`
**Objective:** Reserved baseline; empty directory in this package.
## What this scenario demonstrates
The directory is empty; the effective baseline is `templates/agent_template_backend`.
## Baseline used in this manual
The baseline is `templates/agent_template_backend`. When evaluating any tuning scenario, compare against the exact same:
- LLM/provider;
- persistence;
- MCP transport;
- guardrails/judges;
- RAG;
- load;
- test data.
Without a controlled baseline, latency differences cannot be attributed to the capability being studied.
# T8. Tuning — `Offline_Workflow_Regression`
**Objective:** Opt-in deterministic fallback for offline workflow-DSL regression tests.
## What this scenario demonstrates
Demonstrates an opt-in deterministic fallback used only for offline regression of workflow DSL behavior.
## Behavior
Production still requires LangGraph. Deterministic fallback exists only when `allow_deterministic_fallback=True`, for builders/offline tests.
It exercises the DSL:
- actions;
- edges;
- conditions;
- pause/resume;
- trace.
It must not be automatically selected in production, because that would hide missing/misconfigured LangGraph infrastructure.
# T9. Tuning — `Pause_Resume_Workflow`
**Objective:** Pause/resume by execution_id and expected_input.
## What this scenario demonstrates
Demonstrates pausing a workflow for user input and resuming the exact execution by `execution_id`.
## Delta from the base template
Analyzed variant: `Tuning-Performance/Pause_Resume_Workflow/agent_template_backend`.
**Changed files:** `README.md`, `docs/TRANSACTION_SEMANTIC_CONFIRMATION.md`.
**Added files:** `app/demo.py`, `tests/test_pause_resume.py`, `workflows/confirmacao.active.yaml`, `workflows/confirmacao.v1.yaml`.
## Structure
The variant adds `workflows/confirmacao.v1.yaml`, `confirmacao.active.yaml`, `app/demo.py`, and tests.
`WorkflowRuntime.arun()` starts the execution; when a node declares pause, it returns `PAUSED`. `aresume(name, execution_id, value)` resumes the same execution.
The YAML demonstrates:
- `expected_input`;
- normalization;
- allowed values;
- `resume_from`;
- reprompt;
- `semantic_classifier`;
- contextual reentry by option.
Pause is separated from the previous action so resuming does not repeat a side effect.
# T10. Tuning — `Route_Stickness`
**Objective:** Semantic continuity, handoff, session ending, and MCP policies.
## What this scenario demonstrates
Demonstrates route continuity, rerouting, human handoff, and session termination without allowing stickiness to authorize tools.
## Decision order
```text
session ended? → reject/replay according to channel
route stickiness enabled?
→ CONTINUE → active agent
→ ROUTE/low confidence/error → EnterpriseRouter
→ HUMAN_HANDOFF → global node
→ END_SESSION → global node
```
Documented variables:
```text
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=...
END_SESSION_MESSAGE=...
```
Stickiness does not authorize tools. Even under `CONTINUE`, MCP calls still pass through read-only/transactional policies.
# T11. Tuning — `Transaction_Evidence`
**Objective:** Persistence/correlation of transactional operational evidence.
## What this scenario demonstrates
Demonstrates persistence of completed transactional evidence so later turns and judges can ground references to prior operations.
## Delta from the base template
Analyzed variant: `Tuning-Performance/Transaction_Evidence/agent_template_backend`.
**Changed files:** `.env.example`, `app/main.py`, `app/state.py`, `docs/TRANSACTION_SEMANTIC_CONFIRMATION.md`, `config/mcp_parameter_mapping.yaml`, `config/tools.yaml`, `config/tool_policies.yaml`, `app/agents/product_agent.py`, `app/workflows/agent_graph.py`.
**Added files:** none.
## Problem solved
A transaction may occur in one turn and be referenced later. Without persisted evidence, groundedness may consider a prior cancellation/protocol unsupported.
The runtime writes `transaction_evidence` and correlates relevant items into `relevant_transaction_evidence`.
Example:
```text
cancelar_pedido(PED-1001)
→ COMPLETED
→ protocol
→ transaction_evidence
...
"show me my order"
→ consultar_pedido
→ relevant_transaction_evidence from cancellation
→ response + judges receive the same evidence
```
Transaction Evidence is operational, not semantic memory.
# T12. Tuning — `Transaction_Pre_Validation`
**Objective:** Side-effect-free MCP validator before confirmation.
## What this scenario demonstrates
Demonstrates side-effect-free validation before the user is asked to confirm a sensitive transaction.
## Delta from the base template
Analyzed variant: `Tuning-Performance/Transaction_Pre_Validation/agent_template_backend`.
**Changed files:** `.env.example`, `docs/TRANSACTION_SEMANTIC_CONFIRMATION.md`, `app/agents/product_agent.py`, `app/workflows/agent_graph.py`.
**Added files:** none.
## Flow
```text
complete parameters
→ validar_cancelamento_pedido
→ eligible?
├─ false → OUT_OF_SCOPE / terminal / clear latch
└─ true → AWAITING_CONFIRMATION
↓
yes
↓
cancelar_pedido
```
`fail_open=false` is appropriate for a sensitive operation. Rejection does not become `transaction_evidence`, because the business operation did not occur.
Expected events include:
```text
IC.TRANSACTION_PREVALIDATION_REQUESTED
IC.TRANSACTION_PREVALIDATION_PASSED
IC.TRANSACTION_PREVALIDATION_REJECTED
IC.TRANSACTION_CONFIRMATION_REQUIRED
```
# T13. Tuning — `Voice_Interruption_Replay`
**Objective:** Voice short-circuit/replay without incorrectly reexecuting the graph.
## What this scenario demonstrates
Demonstrates voice replay/short-circuit decisions that avoid unnecessary graph and tool execution.
## Framework-native order
1. ended session → terminal replay;
2. idle nudge → replay last real utterance;
3. non-interruptible speech → literal replay;
4. interruptible speech with context → `processing_interruption_classifier`;
5. insufficient context → normal processing.
On short-circuit, metadata reports `replay=true`, `framework_short_circuit=true` and avoids LangGraph/tools/guardrails. In classifier cases, only the lightweight classification LLM may be called.
# T14. Tuning — `Workflow_Error_Recovery`
**Objective:** Partial snapshot and structured error_details on workflow failure.
## What this scenario demonstrates
Demonstrates preserving partial output/trace and structured provider error details when a workflow fails.
## Failure contract
`WorkflowRunResult` preserves:
- `output`: nodes completed before failure;
- `trace`: partial path;
- `error`: message;
- `error_details`: when available, `status_code`, `body`, `attempts`.
This keeps the framework generic while allowing the domain to interpret provider details without coupling the workflow engine to a specific integration.
# Part III — maintenance file map
## Base template
| Area | File |
|---|---|
| API / session / SSE / entry | `templates/agent_template_backend/app/main.py` |
| State | `app/state.py` |
| Graph | `app/workflows/agent_graph.py` |
| Common agent runtime | `app/agents/runtime.py` |
| Billing | `app/agents/billing_agent.py` |
| Products | `app/agents/product_agent.py` |
| Orders | `app/agents/orders_agent.py` |
| Support | `app/agents/support_agent.py` |
| Routing | `config/routing.yaml` |
| Agents registry | `config/agents.yaml` |
| Tools | `config/tools.yaml` |
| Policies | `config/tool_policies.yaml` |
| MCP parameters | `config/mcp_parameter_mapping.yaml` |
| MCP servers | `config/mcp_servers.yaml` |
| Guardrails | `config/guardrails.yaml` |
| Judges | `config/judges.yaml` |
| Prompt policy | `config/prompt_policy.yaml` |
| Return workflow | `workflows/devolucao_pedido.v1.yaml` |
| Workflow active pointer | `workflows/devolucao_pedido.active.yaml` |
| Return actions | `app/workflow_actions/devolucao.py` |
| Renderers | `app/presentation/tool_renderers.py` |
| Observability | `app/observability/telemetry_observer.py` |
| Framework runtime | `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` |
| Router | `libs/agent_framework/src/agent_framework/routing/enterprise_router.py` |
| Multi-intent | `libs/agent_framework/src/agent_framework/routing/multi_intent.py` |
| Pending topics | `libs/agent_framework/src/agent_framework/routing/pending_topics.py` |
| Parameters/reconciliation | `libs/agent_framework/src/agent_framework/runtime/transaction_parameters.py` |
| Workflow runtime | `libs/agent_framework/src/agent_framework/workflows/` |
## How to create a new rule without hardcoding the core
1. Define the intent in `config/routing.yaml`.
2. Point it to an existing agent or create one under `app/agents/`.
3. Register the agent in the graph only if it is new.
4. Declare capabilities in `config/tools.yaml`.
5. Declare confirmation/pre-validation/workflow in `config/tool_policies.yaml`.
6. Configure aliases/extract/defaults in `config/mcp_parameter_mapping.yaml`.
7. Implement the tool in the MCP Server, not in the router.
8. For multi-step orchestration, create workflow YAML and Python actions.
9. Add guardrails/judges only for cross-cutting/quality concerns; do not use guardrails as routers.
10. Test state, collection, confirmation, intent shift, retry, idempotency, and groundedness.
11. If the capability needs advanced behavior, consult the `Tuning-Performance` scenarios before duplicating infrastructure in the agent.