# 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.