1757 lines
117 KiB
Markdown
1757 lines
117 KiB
Markdown
# Manual Detalhado de Regras do Agente de Contas
|
|
|
|
> Versão aprofundada gerada a partir do pacote `agent_contas_oci_template (9)(1).zip`. O objetivo é permitir entender **por que** o agente escolheu uma regra, como os componentes estão amarrados e onde diagnosticar decisões inesperadas.
|
|
|
|
## 1. Como ler este manual
|
|
|
|
Cada regra é documentada em seis níveis:
|
|
|
|
1. **Intenção de negócio** — o que a regra significa e o que ela não significa.
|
|
2. **Roteamento** — explicação atributo por atributo do bloco correspondente em `config/routing.yaml`.
|
|
3. **Descoberta da intent** — como o framework chega à intent: estado, keywords, LLM e fallback.
|
|
4. **Tools e parâmetros** — o que cada tool consulta/processa/executa, dados necessários, pre-validation, confirmação e retorno.
|
|
5. **Workflow** — nós, actions Python, condições, pause/resume e término.
|
|
6. **Diagnóstico** — exemplos que mostram por que duas frases parecidas podem produzir tratamentos diferentes.
|
|
|
|
A distinção mais importante é:
|
|
|
|
**intent != tool != workflow**
|
|
|
|
A intent descreve o objetivo conversacional. A tool representa uma capability. O workflow orquestra uma execução. E, em regras como VAS, o domínio ainda pode reclassificar a entidade e trocar a tool efetiva com base em evidência autoritativa.
|
|
|
|
## 2. Como o framework encontra uma intent
|
|
|
|
A ordem implementada no `EnterpriseRouter` é:
|
|
|
|
```text
|
|
1. state_policies
|
|
↓
|
|
2. keywords determinísticas
|
|
↓
|
|
3. LLM router, quando ENABLE_LLM_ROUTER=true
|
|
↓
|
|
4. fallback_agent
|
|
```
|
|
|
|
Antes de tratar uma fala isoladamente, o router verifica estados como `WAITING_*_CONFIRMATION` e `COLLECTING_*_PARAMETERS`. Isso impede que uma resposta curta como “sim” seja interpretada como uma nova solicitação.
|
|
|
|
No matching por keywords existem três estratégias:
|
|
|
|
- **exact**: termo único em token ou frase multi-token contida no texto;
|
|
- **ordered_tokens**: permite pequenos tokens entre as palavras da keyword, preservando ordem;
|
|
- **ordered_content_tokens**: tolera conectores curtos omitidos, como variações de “qual é o meu plano” / “qual o meu plano”.
|
|
|
|
Se mais de uma intent casar, a ordenação é:
|
|
|
|
```text
|
|
menor priority
|
|
→ estratégia mais estrita
|
|
→ keyword mais longa
|
|
```
|
|
|
|
Isto é importante: em `routing.yaml`, **priority 110 ganha de priority 145**, e não o contrário.
|
|
|
|
Se não houver keyword suficiente e o LLM router estiver habilitado, o classificador recebe `name`, `description` e alguns `examples` das intents permitidas. A resposta do LLM não inventa agente/tool: esses dados são recuperados do catálogo YAML.
|
|
|
|
Pedidos compostos podem ainda passar pelo `MultiIntentPlanner`, que separa objetivos independentes sem transformar parâmetros de uma única ação em intents artificiais.
|
|
|
|
## 3. Amarração entre os componentes
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
U["Mensagem do cliente"] --> R["routing.yaml"]
|
|
R --> ST["state_policies / intent"]
|
|
ST --> AG["Agente proprietário"]
|
|
AG --> TL["tools.yaml"]
|
|
TL --> TP["tool_policies.yaml"]
|
|
TL --> PM["mcp_parameter_mapping.yaml"]
|
|
TP --> PV["pre-validation"]
|
|
PM --> MCP["contas_mcp_server"]
|
|
PV --> MCP
|
|
MCP --> IR["classificação de domínio / invoice_resolver"]
|
|
IR --> WF["workflow YAML ou execução direta"]
|
|
WF --> WA["workflow_actions.py"]
|
|
WA --> DS["service.py"]
|
|
DS --> CL["client.py"]
|
|
CL --> ENV[".env + tim_integration_defaults.yaml"]
|
|
```
|
|
|
|
A seta `pre-validation → classificação de domínio` é especialmente importante. É nela que um pedido como “cancelar Paramount+” pode deixar de usar a operação de VAS avulso mesmo que a intent inicial tenha sido de cancelamento.
|
|
|
|
## 4. Inventário das regras
|
|
|
|
| Intent | Regra | Agente | Prioridade | Tools |
|
|
|---|---|---|---:|---|
|
|
| `contas_no_match` | No Match / Clarificação | `suporte_contas_agent` | 200 | — |
|
|
| `contas_plan_information` | Consulta de Plano | `faturas_agent` | 142 | `consultar_plano` |
|
|
| `contas_invoice_query` | Consulta / Segunda Via de Fatura | `faturas_agent` | 140 | `consultar_faturas` |
|
|
| `contas_invoice_explanation` | Explicação de Fatura | `faturas_agent` | 150 | `invoice_explanation` |
|
|
| `contas_contestation` | Contestação de Cobrança | `contestacao_agent` | 120 | `consultar_faturas`, `invoice_explanation`, `contestar_cobranca` |
|
|
| `contas_vas_cancel` | Cancelamento de VAS | `contestacao_agent` | 145 | `consultar_vas`, `cancelar_vas_avulso` |
|
|
| `contas_vas_strategic` | VAS Estratégico / Bundle | `contestacao_agent` | 125 | `consultar_vas`, `tratar_vas_estrategico` |
|
|
| `contas_vas_information` | Consulta de VAS | `vas_agent` | 110 | `consultar_vas` |
|
|
| `contas_vas_history` | Histórico de VAS | `vas_agent` | 105 | `consultar_historico_vas` |
|
|
| `contas_knowledge` | Conhecimento Geral de Contas | `suporte_contas_agent` | 120 | — |
|
|
| `contas_service_status` | Status de Solicitação | `suporte_contas_agent` | 90 | `consultar_status_solicitacao` |
|
|
| `contas_pro_rata` | Pró-rata | `faturas_agent` | 128 | `pro_rata` |
|
|
| `contas_termino_desconto` | Término de Desconto | `faturas_agent` | 127 | `termino_desconto` |
|
|
| `contas_valor_divergente` | Valor Divergente | `faturas_agent` | 126 | `valor_divergente` |
|
|
|
|
# 5. Regra — No Match / Clarificação
|
|
|
|
**Intent:** `contas_no_match`
|
|
**Agente:** `suporte_contas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `200`
|
|
|
|
## O que esta regra significa
|
|
|
|
Fala incompreensível, transcrição corrompida ou fragmento sem informação suficiente para determinar uma solicitação/objeto com segurança. Inclui enunciados que contêm uma palavra de domínio, mas deixam o objeto sem referente recuperável (por exemplo, verbo de cobrança seguido apenas de pronome/indefinido). Não use para assunto fora de escopo, reclamação, pedido de humano, jurídico/Anatel/Procon ou frase compreensível que apenas não corresponda a outra intent.
|
|
|
|
### Limite da regra
|
|
|
|
A regra deve permanecer dentro da descrição declarada; quando o objetivo muda, o roteamento/handoff deve mudar também.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_no_match | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | suporte_contas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 200 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Fala incompreensível, transcrição corrompida ou fragmento sem informação suficiente para determinar uma solicitação/objeto com segurança. Inclui enunciados que contêm uma palavra de domínio, mas deixam o objeto sem referente recuperável (por exemplo, verbo de cobrança seguido apenas de pronome/indefinido). Não use para assunto fora de escopo, reclamação, pedido de humano, jurídico/Anatel/Procon ou frase compreensível que apenas não corresponda a outra intent. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | — | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | — | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | asdkj qweoi zxcm<br>hã trrr blá qx<br>[fala sem conteúdo inteligível]<br>está cobrando um<br>veio uma aqui | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. Esta regra não possui keywords determinísticas; portanto depende de estado, classificador LLM/fallback ou lógica conversacional específica.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `asdkj qweoi zxcm`, `hã trrr blá qx`, `[fala sem conteúdo inteligível]` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=suporte_contas_agent` e `mcp_tools=[]`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
Esta intent não declara MCP tools. O tratamento é conversacional, de clarificação ou de conhecimento por mecanismos do agente/framework.
|
|
|
|
## Workflow
|
|
|
|
Não existe workflow dedicado para esta regra. A capability é executada diretamente ou a resposta é produzida pelo runtime/agente.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_no_match` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# 6. Regra — Consulta de Plano
|
|
|
|
**Intent:** `contas_plan_information`
|
|
**Agente:** `faturas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `142`
|
|
|
|
## O que esta regra significa
|
|
|
|
Consulta do plano principal ou dos planos efetivamente contratados na linha, incluindo nome, identificação, valor e dados contratuais do plano atual. Use somente quando a pergunta exigir dados do cliente. Não use para perguntas gerais sobre funcionamento, tarifação, regras, condições ou características de um plano/produto, ainda que o usuário cite o nome de um plano específico.
|
|
|
|
### Limite da regra
|
|
|
|
A regra deve permanecer dentro da descrição declarada; quando o objetivo muda, o roteamento/handoff deve mudar também.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_plan_information | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | faturas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 142 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Consulta do plano principal ou dos planos efetivamente contratados na linha, incluindo nome, identificação, valor e dados contratuais do plano atual. Use somente quando a pergunta exigir dados do cliente. Não use para perguntas gerais sobre funcionamento, tarifação, regras, condições ou características de um plano/produto, ainda que o usuário cite o nome de um plano específico. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | consultar_plano | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | qual é meu plano<br>qual e meu plano<br>qual é o meu plano<br>qual e o meu plano<br>meu plano contratado<br>plano contratado<br>nome do meu plano<br>que plano eu tenho<br>quais são meus planos<br>quais sao meus planos | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Qual é meu plano?<br>Qual é o meu plano contratado?<br>Que plano eu tenho?<br>Qual o nome do meu plano?<br>Quais são os planos da minha linha?<br>Quanto custa o meu plano atual? | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `qual é meu plano`, `qual e meu plano`, `qual é o meu plano`, `qual e o meu plano`, `meu plano contratado`, `plano contratado`, `nome do meu plano`, `que plano eu tenho`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `142` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Qual é meu plano?`, `Qual é o meu plano contratado?`, `Que plano eu tenho?` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=faturas_agent` e `mcp_tools=['consultar_plano']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `consultar_plano`
|
|
|
|
**O que faz:** Consulta exclusivamente o nome e valor do plano ou planos contratados a partir da evidência de billing analysis; não retorna VAS como plano.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna `{plans, count, source}`. Cada plano contém pelo menos `name`, `value`, `type` e `contestable`, extraído exclusivamente de `billing_analysis.currentInvoice`.
|
|
|
|
**Workflow:** não há workflow dedicado; a execução é direta no MCP/serviço ou é tratada pelo runtime do framework.
|
|
|
|
## Workflow
|
|
|
|
Não existe workflow dedicado para esta regra. A capability é executada diretamente ou a resposta é produzida pelo runtime/agente.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_plan_information` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
- `app/domain/contas/service.py`: regra de domínio e contrato de retorno.
|
|
- `app/domain/contas/client.py`: chamada concreta das integrações TIM.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- Billing/fatura: URLs e timeouts de fatura/PDF definidos no `.env` e complementados por `config/tim_integration_defaults.yaml`.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# 7. Regra — Consulta / Segunda Via de Fatura
|
|
|
|
**Intent:** `contas_invoice_query`
|
|
**Agente:** `faturas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `140`
|
|
|
|
## O que esta regra significa
|
|
|
|
Consulta, visualização, obtenção ou segunda via de fatura/conta sem pedido de explicação de cobrança.
|
|
|
|
### Limite da regra
|
|
|
|
A regra deve permanecer dentro da descrição declarada; quando o objetivo muda, o roteamento/handoff deve mudar também.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_invoice_query | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | faturas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 140 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Consulta, visualização, obtenção ou segunda via de fatura/conta sem pedido de explicação de cobrança. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | consultar_faturas | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | quero minha fatura<br>ver minha fatura<br>consultar fatura<br>consultar minha fatura<br>mostrar minha fatura<br>me mostra minha fatura<br>segunda via<br>segunda via da fatura<br>obter fatura<br>baixar fatura<br>minhas faturas<br>fatura atual<br>última fatura<br>ultima fatura<br>fatura em aberto<br>conta em aberto | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Quero minha fatura<br>Quero ver a minha conta<br>Pode consultar minha fatura atual?<br>Preciso da segunda via da fatura<br>Tenho alguma fatura em aberto? | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `quero minha fatura`, `ver minha fatura`, `consultar fatura`, `consultar minha fatura`, `mostrar minha fatura`, `me mostra minha fatura`, `segunda via`, `segunda via da fatura`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `140` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Quero minha fatura`, `Quero ver a minha conta`, `Pode consultar minha fatura atual?` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=faturas_agent` e `mcp_tools=['consultar_faturas']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `consultar_faturas`
|
|
|
|
**O que faz:** Consulta faturas atuais/anteriores, status, vencimento, valor e existência de fatura aberta sem iniciar o workflow de explicação.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna o payload de faturas e, quando disponível no contexto enriquecido, `invoice_amount`, `invoice_amount_open`, `invoice_period`, `invoice_emissao`, `invoice_id` e `customer_id`.
|
|
|
|
**Workflow:** não há workflow dedicado; a execução é direta no MCP/serviço ou é tratada pelo runtime do framework.
|
|
|
|
## Workflow
|
|
|
|
Não existe workflow dedicado para esta regra. A capability é executada diretamente ou a resposta é produzida pelo runtime/agente.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_invoice_query` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
- `app/domain/contas/service.py`: regra de domínio e contrato de retorno.
|
|
- `app/domain/contas/client.py`: chamada concreta das integrações TIM.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- Billing/fatura: URLs e timeouts de fatura/PDF definidos no `.env` e complementados por `config/tim_integration_defaults.yaml`.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# 8. Regra — Explicação de Fatura
|
|
|
|
**Intent:** `contas_invoice_explanation`
|
|
**Agente:** `faturas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `150`
|
|
|
|
## O que esta regra significa
|
|
|
|
Explicação, composição, diferença, aumento, variação, dúvida ou não reconhecimento informativo de valores/itens de uma fatura já conhecida. Use esta intent quando o cliente estiver tentando entender uma cobrança ou disser que não reconhece itens/valores, mas ainda não pedir explicitamente contestação, cancelamento, estorno, ajuste ou retirada. Não use para fragmentos que apenas mencionem cobrança sem um objeto/referente recuperável; nesses casos solicite clarificação via contas_no_match.
|
|
|
|
### Limite da regra
|
|
|
|
É informativa. Não deve executar contestação/cancelamento apenas porque o usuário disse que não reconhece algo.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_invoice_explanation | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | faturas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 150 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Explicação, composição, diferença, aumento, variação, dúvida ou não reconhecimento informativo de valores/itens de uma fatura já conhecida. Use esta intent quando o cliente estiver tentando entender uma cobrança ou disser que não reconhece itens/valores, mas ainda não pedir explicitamente contestação, cancelamento, estorno, ajuste ou retirada. Não use para fragmentos que apenas mencionem cobrança sem um objeto/referente recuperável; nesses casos solicite clarificação via contas_no_match. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | invoice_explanation | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | explicar fatura<br>explique minha fatura<br>entender minha fatura<br>entender minha conta<br>fatura veio alta<br>conta veio alta<br>veio mais cara<br>conta subiu<br>minha conta subiu<br>fatura subiu<br>minha fatura subiu<br>conta aumentou<br>minha conta aumentou<br>fatura aumentou<br>minha fatura aumentou<br>valor aumentou<br>diferença de valor<br>divergência na fatura<br>divergencia na fatura<br>não entendi a cobrança<br>nao entendi a cobranca<br>por que cobraram<br>por que veio esse valor<br>composição da fatura<br>composicao da fatura<br>detalhar cobrança<br>detalhar cobranca<br>não estou reconhecendo<br>nao estou reconhecendo<br>não reconheço esses itens<br>nao reconheco esses itens<br>itens que não reconheço<br>itens que nao reconheco<br>cobranças que não reconheço<br>cobrancas que nao reconheco | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Contratamos um plano, mas eu não estou reconhecendo esses itens eventuais.<br>Tem cobranças que eu não reconheço e quero entender de onde vieram.<br>Minha fatura veio mais alta e quero entender o que mudou.<br>Quero entender minha conta<br>Por que esse valor mudou?<br>Explique essas cobranças da minha fatura<br>Por que minha conta aumentou este mês? | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `explicar fatura`, `explique minha fatura`, `entender minha fatura`, `entender minha conta`, `fatura veio alta`, `conta veio alta`, `veio mais cara`, `conta subiu`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `150` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Contratamos um plano, mas eu não estou reconhecendo esses itens eventuais.`, `Tem cobranças que eu não reconheço e quero entender de onde vieram.`, `Minha fatura veio mais alta e quero entender o que mudou.` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=faturas_agent` e `mcp_tools=['invoice_explanation']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `invoice_explanation`
|
|
|
|
**O que faz:** Explica composição, diferença ou variação de valores de uma fatura; não deve ser usada apenas para consultar/obter a fatura.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna evidências (`complete_invoices`, `billing_analysis`, `invoice_detail`, período/valor/emissão) e uma instrução para o LLM explicar sem inventar cobranças.
|
|
|
|
**Workflow(s):** `workflows/invoice_explanation.v2.yaml`.
|
|
|
|
## Workflows envolvidos
|
|
|
|
### Workflow `invoice_explanation.v2.yaml`
|
|
|
|
**Nome lógico:** `invoice_explanation` · **versão:** `2` · **start:** `preparar`
|
|
|
|
**Por que existe dessa forma:** Foi construído como workflow conversacional porque a explicação não termina na primeira resposta: o agente apresenta a composição, pausa para saber se a explicação resolveu, pode registrar aceite, detectar nova intenção/variação VAS e preparar handoff para outra regra.
|
|
|
|
#### Nós
|
|
|
|
| Nó | Action Python | Papel | Pause/Resume |
|
|
|---|---|---|---|
|
|
| `preparar` | `preparar_invoice_explanation` | Executa `preparar_invoice_explanation`. É o ponto inicial. | não |
|
|
| `formatar` | `formatar_invoice_explanation` | Executa `formatar_invoice_explanation`. | sim; `return_from=$.output.mensagem`; resposta em `resposta_usuario`; permitidos=['SIM', 'NAO', 'CONTINUAR']; `resume_from=decisao` |
|
|
| `checar_tentativa` | `checar_tentativa_cvn` | Executa `checar_tentativa_cvn`. | não |
|
|
| `texto_intencao_invalida` | `montar_resposta_texto` | Executa `montar_resposta_texto`. | não |
|
|
| `fim_intencao_invalida` | `montar_resposta_texto` | Executa `montar_resposta_texto`. | não |
|
|
| `resposta_falha_servico` | `montar_resposta_texto` | Executa `montar_resposta_texto`. | não |
|
|
| `decisao` | `no_op` | Executa `no_op`. É nó de decisão/orquestração, sem efeito de domínio. | não |
|
|
| `registrar_sim` | `registrar_atendimento_invoice_explanation` | Executa `registrar_atendimento_invoice_explanation`. | não |
|
|
| `registrar_protocolo_aceite` | `registrar_protocolo_inicio` | Executa `registrar_protocolo_inicio`. | não |
|
|
| `registrar_nao` | `registrar_atendimento_invoice_explanation` | Executa `registrar_atendimento_invoice_explanation`. | não |
|
|
| `handoff_pos_explicacao_nao` | `preparar_handoff_invoice_explanation` | Executa `preparar_handoff_invoice_explanation`. | não |
|
|
| `checar_vas_variacao` | `checar_vas_variado` | Executa `checar_vas_variado`. | não |
|
|
| `finalizar_nao_resolvido` | `no_op` | Executa `no_op`. É nó de decisão/orquestração, sem efeito de domínio. | não |
|
|
|
|
#### Transições e condições
|
|
|
|
| De | Para | Prioridade | Condição | Interpretação |
|
|
|---|---|---:|---|---|
|
|
| `preparar` | `formatar` | 10 | `{"eq": ["$.vars.preparar.success", true]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `preparar` | `resposta_falha_servico` | 20 | `{"eq": ["$.vars.preparar.service_failed", true]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `preparar` | `checar_tentativa` | 30 | `{"eq": ["$.vars.preparar.success", false]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `checar_tentativa` | `fim_intencao_invalida` | 10 | `{"eq": ["$.vars.checar_tentativa.limite_excedido", true]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `checar_tentativa` | `texto_intencao_invalida` | 20 | sempre | Transição incondicional. |
|
|
| `formatar` | `decisao` | — | sempre | Transição incondicional. |
|
|
| `decisao` | `registrar_sim` | 10 | `{"eq": ["$.input.resposta_usuario", "SIM"]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `decisao` | `registrar_nao` | 20 | `{"eq": ["$.input.resposta_usuario", "NAO"]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `registrar_sim` | `registrar_protocolo_aceite` | — | sempre | Transição incondicional. |
|
|
| `registrar_protocolo_aceite` | `END` | — | sempre | Transição incondicional. |
|
|
| `registrar_nao` | `handoff_pos_explicacao_nao` | — | sempre | Transição incondicional. |
|
|
| `handoff_pos_explicacao_nao` | `END` | — | sempre | Transição incondicional. |
|
|
| `checar_vas_variacao` | `finalizar_nao_resolvido` | 10 | `{"eq": ["$.vars.checar_vas_variacao.tem_vas_variado", false]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `checar_vas_variacao` | `END` | 20 | sempre | Transição incondicional. |
|
|
| `finalizar_nao_resolvido` | `END` | — | sempre | Transição incondicional. |
|
|
| `texto_intencao_invalida` | `END` | — | sempre | Transição incondicional. |
|
|
| `fim_intencao_invalida` | `END` | — | sempre | Transição incondicional. |
|
|
| `resposta_falha_servico` | `END` | — | sempre | Transição incondicional. |
|
|
|
|
#### Como funciona a pausa e o resume
|
|
|
|
- Em `formatar`, a execução pausa quando `null` é verdadeira. A mensagem devolvida ao cliente vem de `$.output.mensagem`. O runtime persiste `workflow_name` e `execution_id`; a próxima fala é normalizada no campo `resposta_usuario` e a execução retorna em `decisao`. Valores esperados: `['SIM', 'NAO', 'CONTINUAR']`.
|
|
|
|
#### Término
|
|
|
|
- O fluxo termina após `registrar_protocolo_aceite` quando a transição final é alcançada.
|
|
- O fluxo termina após `handoff_pos_explicacao_nao` quando a transição final é alcançada.
|
|
- O fluxo termina após `checar_vas_variacao` quando a transição final é alcançada.
|
|
- O fluxo termina após `finalizar_nao_resolvido` quando a transição final é alcançada.
|
|
- O fluxo termina após `texto_intencao_invalida` quando a transição final é alcançada.
|
|
- O fluxo termina após `fim_intencao_invalida` quando a transição final é alcançada.
|
|
- O fluxo termina após `resposta_falha_servico` quando a transição final é alcançada.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_invoice_explanation` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
- `app/domain/contas/service.py`: regra de domínio e contrato de retorno.
|
|
- `app/domain/contas/client.py`: chamada concreta das integrações TIM.
|
|
- `app/domain/contas/invoice_resolver.py` e parsers: resolução canônica/classificação de itens de fatura.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- Billing/fatura: URLs e timeouts de fatura/PDF definidos no `.env` e complementados por `config/tim_integration_defaults.yaml`.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
|
|
### Diagnóstico especial — por que a explicação pode levar a outra regra
|
|
|
|
`invoice_explanation.v2` foi construído para não “engolir” a conversa depois de explicar a fatura. Após apresentar a evidência, ele pode pausar, receber a avaliação do cliente e preparar um handoff. Por isso uma frase posterior como “é a de R$ 14,99” pode deixar de ser uma simples explicação e fornecer o parâmetro que faltava para uma contestação; da mesma forma, a identificação de um VAS pode alimentar um fluxo de cancelamento/tratamento.
|
|
|
|
# 9. Regra — Contestação de Cobrança
|
|
|
|
**Intent:** `contas_contestation`
|
|
**Agente:** `contestacao_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `120`
|
|
|
|
## O que esta regra significa
|
|
|
|
Pedido transacional de contestação, estorno, ajuste, retirada ou correção de uma cobrança. Na primeira fala de não reconhecimento sem alvo concreto, use contas_invoice_explanation. Porém, numa reentrada contextual após a explicação, se o pedido original era não reconhecimento e o cliente identificar inequivocamente a cobrança/item/valor que continua questionando, trate a solicitação como contestação daquele alvo; a execução continua sujeita a validação e confirmação transacional.
|
|
|
|
### Limite da regra
|
|
|
|
É transacional. Precisa haver intenção de contestar/estornar/ajustar/retirar e um alvo suficientemente resolvido.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_contestation | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | contestacao_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 120 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Pedido transacional de contestação, estorno, ajuste, retirada ou correção de uma cobrança. Na primeira fala de não reconhecimento sem alvo concreto, use contas_invoice_explanation. Porém, numa reentrada contextual após a explicação, se o pedido original era não reconhecimento e o cliente identificar inequivocamente a cobrança/item/valor que continua questionando, trate a solicitação como contestação daquele alvo; a execução continua sujeita a validação e confirmação transacional. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | consultar_faturas<br>invoice_explanation<br>contestar_cobranca | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | quero contestar<br>quero contestação<br>quero contestacao<br>contestar essa cobrança<br>contestar essa cobranca<br>abrir contestação<br>abrir contestacao<br>quero estorno<br>pedir estorno<br>quero ajuste na fatura<br>ajustar essa cobrança<br>ajustar essa cobranca<br>retirar essa cobrança<br>retirar essa cobranca<br>tirar essa cobrança<br>tirar essa cobranca | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Contexto anterior: cliente não reconhece uma cobrança; após a explicação identifica 'é a de quatorze e noventa e nove'.<br>Após a explicação da fatura, o cliente identifica pelo nome ou valor qual cobrança continua não reconhecendo.<br>Quero contestar essa cobrança<br>Quero abrir uma contestação para esse valor<br>Quero um estorno dessa cobrança<br>Não reconheço essa cobrança e quero contestar<br>Esse valor está errado e quero um ajuste na fatura | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `quero contestar`, `quero contestação`, `quero contestacao`, `contestar essa cobrança`, `contestar essa cobranca`, `abrir contestação`, `abrir contestacao`, `quero estorno`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `120` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Contexto anterior: cliente não reconhece uma cobrança; após a explicação identifica 'é a de quatorze e noventa e nove'.`, `Após a explicação da fatura, o cliente identifica pelo nome ou valor qual cobrança continua não reconhecendo.`, `Quero contestar essa cobrança` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=contestacao_agent` e `mcp_tools=['consultar_faturas', 'invoice_explanation', 'contestar_cobranca']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `consultar_faturas`
|
|
|
|
**O que faz:** Consulta faturas atuais/anteriores, status, vencimento, valor e existência de fatura aberta sem iniciar o workflow de explicação.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna o payload de faturas e, quando disponível no contexto enriquecido, `invoice_amount`, `invoice_amount_open`, `invoice_period`, `invoice_emissao`, `invoice_id` e `customer_id`.
|
|
|
|
**Workflow:** não há workflow dedicado; a execução é direta no MCP/serviço ou é tratada pelo runtime do framework.
|
|
|
|
### Tool `invoice_explanation`
|
|
|
|
**O que faz:** Explica composição, diferença ou variação de valores de uma fatura; não deve ser usada apenas para consultar/obter a fatura.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna evidências (`complete_invoices`, `billing_analysis`, `invoice_detail`, período/valor/emissão) e uma instrução para o LLM explicar sem inventar cobranças.
|
|
|
|
**Workflow(s):** `workflows/invoice_explanation.v2.yaml`.
|
|
|
|
### Tool `contestar_cobranca`
|
|
|
|
**O que faz:** Executa contestação no novo domínio Contas após confirmação transacional do framework.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `action` |
|
|
| operation_type | `transactional` |
|
|
| require_confirmation | `True` |
|
|
| parâmetros obrigatórios pela policy | `subject`, `valor` |
|
|
| pre-validation | `validar_contestacao` (`fail_open=False`) |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `subject` | `string` | extraído de `message` via `llm` | Referência a um item concreto e identificável da fatura (serviço, produto, plano, cobrança específica ou benefício). Uma referência genérica ao documento ou à cobrança como um todo não identifica o subject; quando não houver entidade concreta suficiente para resolução contra a evidência da fatura, mantenha subject ausente/null. |
|
|
| `valor` | `number` | extraído de `message` via `llm` | Valor monetário explicitamente associado pelo cliente ao item, cobrança ou operação. Se não houver valor explícito ou houver dúvida razoável, manter ausente/null. |
|
|
| `motivo` | `string` | extraído de `message` via `llm` | Motivo informado pelo cliente para a solicitação ou contestação. Não inventar motivo quando não estiver explícito. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Extração conversacional:**
|
|
- `subject`: Extraia o nome do serviço/item cuja cobrança será contestada. Estratégia: `llm`.
|
|
- `valor`: Extraia o valor monetário explicitamente associado ao item. Retorne null se não houver valor. Estratégia: `llm`.
|
|
- `motivo`: Extraia o motivo da contestação em frase curta; null se não informado. Estratégia: `llm`.
|
|
|
|
**Retorno esperado:** Retorna `success`, protocolo, resultado da contestação, tracking e evidências auxiliares de fatura/contrato/perfil.
|
|
|
|
**Workflow(s):** `workflows/contestacao_tool.v2.yaml`.
|
|
|
|
## Workflows envolvidos
|
|
|
|
### Workflow `invoice_explanation.v2.yaml`
|
|
|
|
**Nome lógico:** `invoice_explanation` · **versão:** `2` · **start:** `preparar`
|
|
|
|
**Por que existe dessa forma:** Foi construído como workflow conversacional porque a explicação não termina na primeira resposta: o agente apresenta a composição, pausa para saber se a explicação resolveu, pode registrar aceite, detectar nova intenção/variação VAS e preparar handoff para outra regra.
|
|
|
|
#### Nós
|
|
|
|
| Nó | Action Python | Papel | Pause/Resume |
|
|
|---|---|---|---|
|
|
| `preparar` | `preparar_invoice_explanation` | Executa `preparar_invoice_explanation`. É o ponto inicial. | não |
|
|
| `formatar` | `formatar_invoice_explanation` | Executa `formatar_invoice_explanation`. | sim; `return_from=$.output.mensagem`; resposta em `resposta_usuario`; permitidos=['SIM', 'NAO', 'CONTINUAR']; `resume_from=decisao` |
|
|
| `checar_tentativa` | `checar_tentativa_cvn` | Executa `checar_tentativa_cvn`. | não |
|
|
| `texto_intencao_invalida` | `montar_resposta_texto` | Executa `montar_resposta_texto`. | não |
|
|
| `fim_intencao_invalida` | `montar_resposta_texto` | Executa `montar_resposta_texto`. | não |
|
|
| `resposta_falha_servico` | `montar_resposta_texto` | Executa `montar_resposta_texto`. | não |
|
|
| `decisao` | `no_op` | Executa `no_op`. É nó de decisão/orquestração, sem efeito de domínio. | não |
|
|
| `registrar_sim` | `registrar_atendimento_invoice_explanation` | Executa `registrar_atendimento_invoice_explanation`. | não |
|
|
| `registrar_protocolo_aceite` | `registrar_protocolo_inicio` | Executa `registrar_protocolo_inicio`. | não |
|
|
| `registrar_nao` | `registrar_atendimento_invoice_explanation` | Executa `registrar_atendimento_invoice_explanation`. | não |
|
|
| `handoff_pos_explicacao_nao` | `preparar_handoff_invoice_explanation` | Executa `preparar_handoff_invoice_explanation`. | não |
|
|
| `checar_vas_variacao` | `checar_vas_variado` | Executa `checar_vas_variado`. | não |
|
|
| `finalizar_nao_resolvido` | `no_op` | Executa `no_op`. É nó de decisão/orquestração, sem efeito de domínio. | não |
|
|
|
|
#### Transições e condições
|
|
|
|
| De | Para | Prioridade | Condição | Interpretação |
|
|
|---|---|---:|---|---|
|
|
| `preparar` | `formatar` | 10 | `{"eq": ["$.vars.preparar.success", true]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `preparar` | `resposta_falha_servico` | 20 | `{"eq": ["$.vars.preparar.service_failed", true]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `preparar` | `checar_tentativa` | 30 | `{"eq": ["$.vars.preparar.success", false]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `checar_tentativa` | `fim_intencao_invalida` | 10 | `{"eq": ["$.vars.checar_tentativa.limite_excedido", true]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `checar_tentativa` | `texto_intencao_invalida` | 20 | sempre | Transição incondicional. |
|
|
| `formatar` | `decisao` | — | sempre | Transição incondicional. |
|
|
| `decisao` | `registrar_sim` | 10 | `{"eq": ["$.input.resposta_usuario", "SIM"]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `decisao` | `registrar_nao` | 20 | `{"eq": ["$.input.resposta_usuario", "NAO"]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `registrar_sim` | `registrar_protocolo_aceite` | — | sempre | Transição incondicional. |
|
|
| `registrar_protocolo_aceite` | `END` | — | sempre | Transição incondicional. |
|
|
| `registrar_nao` | `handoff_pos_explicacao_nao` | — | sempre | Transição incondicional. |
|
|
| `handoff_pos_explicacao_nao` | `END` | — | sempre | Transição incondicional. |
|
|
| `checar_vas_variacao` | `finalizar_nao_resolvido` | 10 | `{"eq": ["$.vars.checar_vas_variacao.tem_vas_variado", false]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `checar_vas_variacao` | `END` | 20 | sempre | Transição incondicional. |
|
|
| `finalizar_nao_resolvido` | `END` | — | sempre | Transição incondicional. |
|
|
| `texto_intencao_invalida` | `END` | — | sempre | Transição incondicional. |
|
|
| `fim_intencao_invalida` | `END` | — | sempre | Transição incondicional. |
|
|
| `resposta_falha_servico` | `END` | — | sempre | Transição incondicional. |
|
|
|
|
#### Como funciona a pausa e o resume
|
|
|
|
- Em `formatar`, a execução pausa quando `null` é verdadeira. A mensagem devolvida ao cliente vem de `$.output.mensagem`. O runtime persiste `workflow_name` e `execution_id`; a próxima fala é normalizada no campo `resposta_usuario` e a execução retorna em `decisao`. Valores esperados: `['SIM', 'NAO', 'CONTINUAR']`.
|
|
|
|
#### Término
|
|
|
|
- O fluxo termina após `registrar_protocolo_aceite` quando a transição final é alcançada.
|
|
- O fluxo termina após `handoff_pos_explicacao_nao` quando a transição final é alcançada.
|
|
- O fluxo termina após `checar_vas_variacao` quando a transição final é alcançada.
|
|
- O fluxo termina após `finalizar_nao_resolvido` quando a transição final é alcançada.
|
|
- O fluxo termina após `texto_intencao_invalida` quando a transição final é alcançada.
|
|
- O fluxo termina após `fim_intencao_invalida` quando a transição final é alcançada.
|
|
- O fluxo termina após `resposta_falha_servico` quando a transição final é alcançada.
|
|
|
|
### Workflow `contestacao_tool.v2.yaml`
|
|
|
|
**Nome lógico:** `contestacao_tool` · **versão:** `2` · **start:** `registrar_protocolo`
|
|
|
|
**Por que existe dessa forma:** Foi separado da conversa porque contestação produz efeitos externos e exige uma sequência auditável: protocolo, validação de status, abertura da contestação, SMS/contrato/SR e atualização de status. A confirmação é feita antes pelo runtime; o workflow recebe uma operação já confirmada.
|
|
|
|
#### Nós
|
|
|
|
| Nó | Action Python | Papel | Pause/Resume |
|
|
|---|---|---|---|
|
|
| `registrar_protocolo` | `registrar_protocolo` | Executa `registrar_protocolo`. É o ponto inicial. | não |
|
|
| `enviar_sms` | `enviar_sms` | Executa `enviar_sms`. | não |
|
|
| `check_invoice_status` | `check_invoice_status` | Executa `check_invoice_status`. | não |
|
|
| `abrir_contestacao_cliente` | `abrir_contestacao_cliente` | Executa `abrir_contestacao_cliente`. | não |
|
|
| `consultar_contrato_corte` | `consultar_contrato_corte` | Executa `consultar_contrato_corte`. | não |
|
|
| `abrir_sr_conta_certa_manual` | `abrir_sr_conta_certa_manual` | Executa `abrir_sr_conta_certa_manual`. | não |
|
|
| `atualizar_status_sr` | `atualizar_status_sr` | Executa `atualizar_status_sr`. | não |
|
|
| `atualizar_status_sr_registro` | `atualizar_status_sr` | Executa `atualizar_status_sr`. | não |
|
|
|
|
#### Transições e condições
|
|
|
|
| De | Para | Prioridade | Condição | Interpretação |
|
|
|---|---|---:|---|---|
|
|
| `registrar_protocolo` | `check_invoice_status` | — | sempre | Transição incondicional. |
|
|
| `check_invoice_status` | `abrir_contestacao_cliente` | 10 | sempre | Transição incondicional. |
|
|
| `abrir_contestacao_cliente` | `END` | 1 | `{"eq": ["$.vars.abrir_contestacao_cliente.success", false]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `abrir_contestacao_cliente` | `enviar_sms` | 10 | `{"all": [{"exists": "$.vars.abrir_contestacao_cliente.barcode"}, {"neq": ["$.vars.abrir_contestacao_cliente.barcode", ""]}]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `abrir_contestacao_cliente` | `consultar_contrato_corte` | 99 | sempre | Transição incondicional. |
|
|
| `enviar_sms` | `consultar_contrato_corte` | — | sempre | Transição incondicional. |
|
|
| `consultar_contrato_corte` | `abrir_sr_conta_certa_manual` | 10 | `{"any": [{"all": [{"eq": ["$.vars.consultar_contrato_corte.apos_data_corte", true]}, {"eq": ["$.vars.consultar_contrato_corte.contestation_success", true]}, {"any": [{"eq": ["$.input.manual_conta_certa_indicator", true]}, {"eq": ["$.vars.abrir_contestacao_cliente.manual_conta_certa_indicator", true]}]}]}, {"all": [{"eq": ["$.vars.consultar_contrato_corte.dependent_invoice_item", true]}, {"eq": ["$.vars.consultar_contrato_corte.contestation_registered", true]}]}]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `consultar_contrato_corte` | `atualizar_status_sr` | 99 | sempre | Transição incondicional. |
|
|
| `abrir_sr_conta_certa_manual` | `atualizar_status_sr_registro` | 10 | sempre | Transição incondicional. |
|
|
| `atualizar_status_sr_registro` | `END` | — | sempre | Transição incondicional. |
|
|
| `atualizar_status_sr` | `END` | — | sempre | Transição incondicional. |
|
|
|
|
#### Término
|
|
|
|
- O fluxo termina após `abrir_contestacao_cliente` quando a condição `{"eq": ["$.vars.abrir_contestacao_cliente.success", false]}`.
|
|
- O fluxo termina após `atualizar_status_sr_registro` quando a transição final é alcançada.
|
|
- O fluxo termina após `atualizar_status_sr` quando a transição final é alcançada.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_contestation` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
- `app/domain/contas/service.py`: regra de domínio e contrato de retorno.
|
|
- `app/domain/contas/client.py`: chamada concreta das integrações TIM.
|
|
- `app/domain/contas/invoice_resolver.py` e parsers: resolução canônica/classificação de itens de fatura.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- Billing/fatura: URLs e timeouts de fatura/PDF definidos no `.env` e complementados por `config/tim_integration_defaults.yaml`.
|
|
- Contestação: `TIM_PROTOCOL_*`, `TIM_CUSTOMER_CONTESTATION_*`, `TIM_TRACKING_ACTIVITIES_*`, `TIM_SMS_*`, `TIM_CONTRATO_*`, `TIM_PROFILE_FULL_AUTH` e defaults de canal/client id.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
|
|
### Diagnóstico especial — “não reconheço” não é automaticamente contestação
|
|
|
|
O agente diferencia **entender** de **executar uma contestação**. Uma primeira fala como “não reconheço essa cobrança” pode cair em `contas_invoice_explanation`, pois ainda não existe pedido inequívoco de estorno/ajuste/contestação. Depois que a fatura é explicada, se o cliente identifica o alvo — por nome ou valor — e manifesta que continua questionando/quer contestar, o contexto pode reentrar em `contas_contestation`.
|
|
|
|
Essa separação existe para não disparar uma transação financeira a partir de uma dúvida informativa. `contestar_cobranca` exige `subject` e `valor`, passa por `validar_contestacao`, pede confirmação e só depois executa o workflow transacional.
|
|
|
|
# 10. Regra — Cancelamento de VAS
|
|
|
|
**Intent:** `contas_vas_cancel`
|
|
**Agente:** `contestacao_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `145`
|
|
|
|
## O que esta regra significa
|
|
|
|
Cancelamento ou retirada explicitamente solicitada de serviço/VAS. Não use para simples alegação de contratação ou cobrança não reconhecida sem pedido de ação; nesses casos use contas_invoice_explanation.
|
|
|
|
### Limite da regra
|
|
|
|
A intent significa que o cliente quer cancelar; **não garante** que o item seja tecnicamente cancelável como VAS avulso. A classe autoritativa do item é verificada depois.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_vas_cancel | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | contestacao_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 145 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Cancelamento ou retirada explicitamente solicitada de serviço/VAS. Não use para simples alegação de contratação ou cobrança não reconhecida sem pedido de ação; nesses casos use contas_invoice_explanation. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | consultar_vas<br>cancelar_vas_avulso | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | quero cancelar<br>cancelar meu<br>cancela o<br>cancele o<br>cancelar serviço<br>cancelar servico<br>cancelar assinatura<br>retirar serviço<br>retirar servico<br>desativar serviço<br>desativar servico<br>tirar esse vas | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Quero cancelar esse serviço<br>Quero retirar essa assinatura | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `quero cancelar`, `cancelar meu`, `cancela o`, `cancele o`, `cancelar serviço`, `cancelar servico`, `cancelar assinatura`, `retirar serviço`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `145` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Quero cancelar esse serviço`, `Quero retirar essa assinatura` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=contestacao_agent` e `mcp_tools=['consultar_vas', 'cancelar_vas_avulso']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `consultar_vas`
|
|
|
|
**O que faz:** Consulta serviços VAS ativos.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna o catálogo de VAS ativos fornecido pela integração TIM.
|
|
|
|
**Workflow:** não há workflow dedicado; a execução é direta no MCP/serviço ou é tratada pelo runtime do framework.
|
|
|
|
### Tool `cancelar_vas_avulso`
|
|
|
|
**O que faz:** Executa cancelamento de VAS avulso no novo domínio Contas; confirmação e estado são do framework.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `action` |
|
|
| operation_type | `transactional` |
|
|
| require_confirmation | `True` |
|
|
| parâmetros obrigatórios pela policy | `subject` |
|
|
| pre-validation | `validar_vas_subject` (`fail_open=False`) |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `subject` | `string` | extraído de `message` via `llm` | Referência a um ou mais serviços, produtos ou benefícios concretos e identificáveis nas evidências VAS/fatura do cliente. Preserve referências múltiplas e anafóricas quando o contexto imediato as resolver (por exemplo, "os dois", "ambos", "Netflix e HBO", "todos os VAS avulsos"). Categorias genéricas sem foco conversacional não identificam entidade; se o texto e o contexto não permitirem resolução segura para um item real nas evidências autorizadas, mantenha subject ausente/null. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Extração conversacional:**
|
|
- `subject`: Extraia somente o nome do serviço que o cliente quer cancelar. Retorne null se não estiver claro. Estratégia: `llm`.
|
|
|
|
**Retorno esperado:** Retorna `success`; serviço resolvido; evidência usada (`active`/`history`); resultado de bloqueio e cancelamento. Em falha retorna `reason` como `service_not_found`, `already_inactive_or_blocked`, `block_vas_failed` ou `cancel_vas_failed`.
|
|
|
|
**Workflow(s):** `workflows/cancelamento_vas_avulso.v1.yaml`.
|
|
|
|
## Workflows envolvidos
|
|
|
|
### Workflow `cancelamento_vas_avulso.v1.yaml`
|
|
|
|
**Nome lógico:** `cancelamento_vas_avulso` · **versão:** `1` · **start:** `cancelar_vas_avulso`
|
|
|
|
**Por que existe dessa forma:** É propositalmente curto: a complexidade de elegibilidade e confirmação fica antes da execução. Quando o workflow começa, os itens já devem estar canônicos e confirmados; a action batch executa bloqueio/cancelamento e tratamento composto por item.
|
|
|
|
#### Nós
|
|
|
|
| Nó | Action Python | Papel | Pause/Resume |
|
|
|---|---|---|---|
|
|
| `cancelar_vas_avulso` | `cancelamento_vas_avulso_batch` | Executa `cancelamento_vas_avulso_batch`. É o ponto inicial. | não |
|
|
|
|
#### Transições e condições
|
|
|
|
| De | Para | Prioridade | Condição | Interpretação |
|
|
|---|---|---:|---|---|
|
|
| `cancelar_vas_avulso` | `END` | — | sempre | Transição incondicional. |
|
|
|
|
#### Término
|
|
|
|
- O fluxo termina após `cancelar_vas_avulso` quando a transição final é alcançada.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_vas_cancel` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
- `app/domain/contas/service.py`: regra de domínio e contrato de retorno.
|
|
- `app/domain/contas/client.py`: chamada concreta das integrações TIM.
|
|
- `app/domain/contas/invoice_resolver.py` e parsers: resolução canônica/classificação de itens de fatura.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- VAS: endpoints/credenciais de consulta, histórico, bloqueio/cancelamento e defaults TIM; entre as variáveis presentes no cliente estão `TIM_VAS_HISTORY_URL`, `TIM_VAS_HISTORY_AUTH`, `TIM_VAS_HISTORY_TIMEOUT` e configuração de gateway.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
|
|
### Diagnóstico especial — por que `Tamboro` e `Paramount+` podem seguir caminhos diferentes
|
|
|
|
Esta é uma regra crítica do agente. A frase **“quero cancelar Tamboro e Paramount+”** pode inicialmente ser reconhecida como `contas_vas_cancel`, porque o objetivo do usuário é cancelar serviços. Isso **não significa** que todos os itens serão executados pela mesma tool.
|
|
|
|
A decisão ocorre em duas camadas:
|
|
|
|
1. **Roteamento conversacional**: `routing.yaml` decide que existe um pedido de cancelamento e entrega `consultar_vas` + `cancelar_vas_avulso`.
|
|
2. **Classificação autoritativa de cada entidade**: antes de executar, `validar_vas_subject`/`invoice_resolver` confronta o nome canônico com a fatura. O método `_classify()` dá precedência a `entry.estrategico`, `entry.classe` e depois à seção da fatura.
|
|
- `avulso` → `cancelar_vas_avulso`;
|
|
- `estrategico` ou `bundle` → `vas_estrategico` / `tratar_vas_estrategico`.
|
|
|
|
No código, `_build_item()` define `tool_category="vas_estrategico"` quando `item_type` é `bundle` ou `estrategico`. No pre-validator MCP, se a tool solicitada era `cancelar_vas_avulso` mas a entidade resolvida é estratégica, `effective_tool` muda para `tratar_vas_estrategico` e a decisão informa `action_changed`.
|
|
|
|
**Tamboro** normalmente permanece no caminho avulso quando a evidência da fatura o classifica assim. O workflow `cancelamento_vas_avulso.v1` então executa a action batch de cancelamento.
|
|
|
|
**Paramount+** pode aparecer em seção/registro classificado como estratégico. Nesse caso o domínio impede que ele seja cancelado como se fosse um VAS avulso e o direciona para `vas_estrategico.v3`, que é um fluxo de explicação/orientação e não um cancelamento técnico automático.
|
|
|
|
Há ainda um caso de **pedido misto** já coberto pelos testes: quando múltiplas entidades canônicas foram pré-validadas em `items[]`, o preflight não deve tentar resolver novamente a string agregada `"Tamboro Mensal, Paramount+"`. O snapshot preserva os itens. Na execução batch, cada resultado pode ser diferente — por exemplo, Tamboro com `success=true` e Paramount+ com `success=false/reason=service_not_found`; a resposta final deve preservar os dois resultados, sem afirmar que ambos foram cancelados.
|
|
|
|
**Onde olhar ao depurar este comportamento**
|
|
|
|
- `config/routing.yaml` → `contas_vas_cancel` e `contas_vas_strategic`;
|
|
- `config/tool_policies.yaml` → `cancelar_vas_avulso.pre_validation.tool=validar_vas_subject`;
|
|
- `config/mcp_parameter_mapping.yaml` → extração de `subject`;
|
|
- `app/domain/contas/parsers/bill_processor.py` → carimbo `estrategico`;
|
|
- `app/domain/contas/invoice_resolver.py` → `_classify()` e `_build_item()`;
|
|
- `contas_mcp/servers/contas_mcp_server/main.py` → `_validate_vas_subject()` e troca de `effective_tool`;
|
|
- `workflows/cancelamento_vas_avulso.v1.yaml`;
|
|
- `workflows/vas_estrategico.v3.yaml`;
|
|
- `tests/migration/test_subject_entity_resolution_all_domains.py`;
|
|
- `tests/migration/test_tim_aoferta_transaction_continuation.py`.
|
|
|
|
Esse mecanismo deve ser lido como **proteção de semântica de negócio**: a intent descreve o que o cliente quer; a classificação de domínio decide qual operação é legal/correta para cada item.
|
|
|
|
# 11. Regra — VAS Estratégico / Bundle
|
|
|
|
**Intent:** `contas_vas_strategic`
|
|
**Agente:** `contestacao_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `125`
|
|
|
|
## O que esta regra significa
|
|
|
|
Tratamento de serviço estratégico, parceiro ou benefício incluso com fluxo específico.
|
|
|
|
### Limite da regra
|
|
|
|
Representa tratamento específico de estratégico/bundle. Não é sinônimo de cancelamento técnico automático.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_vas_strategic | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | contestacao_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 125 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Tratamento de serviço estratégico, parceiro ou benefício incluso com fluxo específico. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | consultar_vas<br>tratar_vas_estrategico | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | apple music<br>deezer<br>disney<br>disney+<br>netflix<br>youtube premium<br>globoplay<br>amazon prime<br>prime video<br>serviço estratégico<br>servico estrategico<br>benefício incluso<br>beneficio incluso | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Não reconheço o Netflix<br>Quero tratar esse serviço estratégico<br>Meu plano inclui Deezer? | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `apple music`, `deezer`, `disney`, `disney+`, `netflix`, `youtube premium`, `globoplay`, `amazon prime`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `125` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Não reconheço o Netflix`, `Quero tratar esse serviço estratégico`, `Meu plano inclui Deezer?` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=contestacao_agent` e `mcp_tools=['consultar_vas', 'tratar_vas_estrategico']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `consultar_vas`
|
|
|
|
**O que faz:** Consulta serviços VAS ativos.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna o catálogo de VAS ativos fornecido pela integração TIM.
|
|
|
|
**Workflow:** não há workflow dedicado; a execução é direta no MCP/serviço ou é tratada pelo runtime do framework.
|
|
|
|
### Tool `tratar_vas_estrategico`
|
|
|
|
**O que faz:** Trata VAS estratégico/bundle no novo domínio Contas; diálogo e estado são do framework.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `conversational` |
|
|
| operation_type | `conversational` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | `subject` |
|
|
| pre-validation | `validar_vas_subject` (`fail_open=False`) |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `subject` | `string` | extraído de `message` via `llm` | Referência a um serviço, produto ou benefício concreto e identificável nas evidências VAS/fatura do cliente. Categorias ou referências genéricas não identificam uma entidade por si só; se o texto não permitir resolver univocamente para um item real, mantenha subject ausente/null. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Extração conversacional:**
|
|
- `subject`: Extraia somente o nome do serviço estratégico ou incluso citado pelo cliente. Estratégia: `llm`.
|
|
|
|
**Retorno esperado:** Retorna serviço estratégico encontrado, `accepted_explanation` e orientação de tratamento. Não executa cancelamento automático de VAS estratégico/bundle.
|
|
|
|
**Workflow(s):** `workflows/vas_estrategico.v3.yaml`.
|
|
|
|
## Workflows envolvidos
|
|
|
|
### Workflow `vas_estrategico.v3.yaml`
|
|
|
|
**Nome lógico:** `vas_estrategico` · **versão:** `3` · **start:** `preparar`
|
|
|
|
**Por que existe dessa forma:** Existe porque estratégico/bundle não é equivalente a VAS avulso. O fluxo primeiro explica/trata o serviço, pode pausar aguardando aceite e escolhe caminhos distintos para estratégico e bundle. Ele evita que uma solicitação genérica de 'cancelar' seja transformada automaticamente em cancelamento técnico.
|
|
|
|
#### Nós
|
|
|
|
| Nó | Action Python | Papel | Pause/Resume |
|
|
|---|---|---|---|
|
|
| `preparar` | `preparar_vas_estrategico` | Executa `preparar_vas_estrategico`. É o ponto inicial. | sim; `return_from=$.output.mensagem`; resposta em `resposta_usuario`; permitidos=['SIM', 'NAO', 'OUTRO']; `resume_from=decisao` |
|
|
| `resposta_bundle` | `montar_resposta_texto` | Executa `montar_resposta_texto`. | não |
|
|
| `decisao` | `no_op` | Executa `no_op`. É nó de decisão/orquestração, sem efeito de domínio. | não |
|
|
| `resposta_sim` | `montar_resposta_texto` | Executa `montar_resposta_texto`. | não |
|
|
| `explicar_cancelamento` | `montar_explicacao_cancelamento_vas_estrategico` | Executa `montar_explicacao_cancelamento_vas_estrategico`. | não |
|
|
| `registrar_sim` | `registrar_atendimento_vas_estrategico` | Executa `registrar_atendimento_vas_estrategico`. | não |
|
|
| `registrar_nao` | `registrar_atendimento_vas_estrategico` | Executa `registrar_atendimento_vas_estrategico`. | não |
|
|
| `registrar_bundle` | `registrar_atendimento_vas_estrategico` | Executa `registrar_atendimento_vas_estrategico`. | não |
|
|
| `registrar_outro` | `registrar_atendimento_vas_estrategico` | Executa `registrar_atendimento_vas_estrategico`. | não |
|
|
|
|
#### Transições e condições
|
|
|
|
| De | Para | Prioridade | Condição | Interpretação |
|
|
|---|---|---:|---|---|
|
|
| `preparar` | `decisao` | 10 | `{"eq": ["$.vars.preparar.await_user_input", true]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `preparar` | `resposta_bundle` | 20 | sempre | Transição incondicional. |
|
|
| `decisao` | `resposta_sim` | 10 | `{"eq": ["$.input.resposta_usuario", "SIM"]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `decisao` | `explicar_cancelamento` | 20 | `{"all": [{"eq": ["$.vars.preparar.has_estrategico_items", true]}, {"eq": ["$.input.resposta_usuario", "NAO"]}]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `decisao` | `resposta_bundle` | 30 | `{"eq": ["$.vars.preparar.has_estrategico_items", false]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `decisao` | `registrar_outro` | 99 | sempre | Transição incondicional. |
|
|
| `resposta_sim` | `registrar_sim` | — | sempre | Transição incondicional. |
|
|
| `explicar_cancelamento` | `registrar_nao` | — | sempre | Transição incondicional. |
|
|
| `registrar_sim` | `END` | — | sempre | Transição incondicional. |
|
|
| `registrar_nao` | `END` | — | sempre | Transição incondicional. |
|
|
| `resposta_bundle` | `registrar_bundle` | — | sempre | Transição incondicional. |
|
|
| `registrar_bundle` | `END` | — | sempre | Transição incondicional. |
|
|
| `registrar_outro` | `END` | — | sempre | Transição incondicional. |
|
|
|
|
#### Como funciona a pausa e o resume
|
|
|
|
- Em `preparar`, a execução pausa quando `{"eq": ["$.output.await_user_input", true]}` é verdadeira. A mensagem devolvida ao cliente vem de `$.output.mensagem`. O runtime persiste `workflow_name` e `execution_id`; a próxima fala é normalizada no campo `resposta_usuario` e a execução retorna em `decisao`. Valores esperados: `['SIM', 'NAO', 'OUTRO']`.
|
|
|
|
#### Término
|
|
|
|
- O fluxo termina após `registrar_sim` quando a transição final é alcançada.
|
|
- O fluxo termina após `registrar_nao` quando a transição final é alcançada.
|
|
- O fluxo termina após `registrar_bundle` quando a transição final é alcançada.
|
|
- O fluxo termina após `registrar_outro` quando a transição final é alcançada.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_vas_strategic` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
- `app/domain/contas/service.py`: regra de domínio e contrato de retorno.
|
|
- `app/domain/contas/client.py`: chamada concreta das integrações TIM.
|
|
- `app/domain/contas/invoice_resolver.py` e parsers: resolução canônica/classificação de itens de fatura.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- VAS: endpoints/credenciais de consulta, histórico, bloqueio/cancelamento e defaults TIM; entre as variáveis presentes no cliente estão `TIM_VAS_HISTORY_URL`, `TIM_VAS_HISTORY_AUTH`, `TIM_VAS_HISTORY_TIMEOUT` e configuração de gateway.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# 12. Regra — Consulta de VAS
|
|
|
|
**Intent:** `contas_vas_information`
|
|
**Agente:** `vas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `110`
|
|
|
|
## O que esta regra significa
|
|
|
|
Consulta ou explicação de VAS, serviço adicional, assinatura, aplicativo, parceiro, bundle ou benefício adicional. Não use esta intent para perguntas sobre nome, identificação ou valor do plano principal/plano contratado da linha.
|
|
|
|
### Limite da regra
|
|
|
|
A regra deve permanecer dentro da descrição declarada; quando o objetivo muda, o roteamento/handoff deve mudar também.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_vas_information | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | vas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 110 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Consulta ou explicação de VAS, serviço adicional, assinatura, aplicativo, parceiro, bundle ou benefício adicional. Não use esta intent para perguntas sobre nome, identificação ou valor do plano principal/plano contratado da linha. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | consultar_vas | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | vas<br>serviço adicional<br>servico adicional<br>aplicativo<br>assinatura<br>serviços ativos<br>servicos ativos<br>quais são meus serviços<br>quais sao meus servicos<br>meus serviços<br>meus servicos<br>benefício<br>beneficio<br>incluso no plano<br>pacote digital<br>parceiro | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | O que é esse serviço?<br>Quais VAS estão ativos?<br>Esse aplicativo está incluso?<br>Quais serviços adicionais eu tenho? | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `vas`, `serviço adicional`, `servico adicional`, `aplicativo`, `assinatura`, `serviços ativos`, `servicos ativos`, `quais são meus serviços`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `110` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `O que é esse serviço?`, `Quais VAS estão ativos?`, `Esse aplicativo está incluso?` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=vas_agent` e `mcp_tools=['consultar_vas']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `consultar_vas`
|
|
|
|
**O que faz:** Consulta serviços VAS ativos.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna o catálogo de VAS ativos fornecido pela integração TIM.
|
|
|
|
**Workflow:** não há workflow dedicado; a execução é direta no MCP/serviço ou é tratada pelo runtime do framework.
|
|
|
|
## Workflow
|
|
|
|
Não existe workflow dedicado para esta regra. A capability é executada diretamente ou a resposta é produzida pelo runtime/agente.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_vas_information` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
- `app/domain/contas/service.py`: regra de domínio e contrato de retorno.
|
|
- `app/domain/contas/client.py`: chamada concreta das integrações TIM.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- VAS: endpoints/credenciais de consulta, histórico, bloqueio/cancelamento e defaults TIM; entre as variáveis presentes no cliente estão `TIM_VAS_HISTORY_URL`, `TIM_VAS_HISTORY_AUTH`, `TIM_VAS_HISTORY_TIMEOUT` e configuração de gateway.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# 13. Regra — Histórico de VAS
|
|
|
|
**Intent:** `contas_vas_history`
|
|
**Agente:** `vas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `105`
|
|
|
|
## O que esta regra significa
|
|
|
|
Consulta de histórico de VAS/serviços que já estiveram ativos ou sofreram alterações.
|
|
|
|
### Limite da regra
|
|
|
|
A regra deve permanecer dentro da descrição declarada; quando o objetivo muda, o roteamento/handoff deve mudar também.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_vas_history | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | vas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 105 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Consulta de histórico de VAS/serviços que já estiveram ativos ou sofreram alterações. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | consultar_historico_vas | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | histórico de vas<br>historico de vas<br>histórico de serviços<br>historico de servicos<br>serviços anteriores<br>servicos anteriores<br>já tive esse serviço<br>ja tive esse servico | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Quero ver meu histórico de serviços<br>Eu já tive esse VAS antes? | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `histórico de vas`, `historico de vas`, `histórico de serviços`, `historico de servicos`, `serviços anteriores`, `servicos anteriores`, `já tive esse serviço`, `ja tive esse servico`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `105` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Quero ver meu histórico de serviços`, `Eu já tive esse VAS antes?` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=vas_agent` e `mcp_tools=['consultar_historico_vas']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `consultar_historico_vas`
|
|
|
|
**O que faz:** Consulta histórico de serviços VAS.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna histórico de VAS/serviços, usado também como fallback quando um serviço não aparece mais entre os ativos.
|
|
|
|
**Workflow:** não há workflow dedicado; a execução é direta no MCP/serviço ou é tratada pelo runtime do framework.
|
|
|
|
## Workflow
|
|
|
|
Não existe workflow dedicado para esta regra. A capability é executada diretamente ou a resposta é produzida pelo runtime/agente.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_vas_history` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
- `app/domain/contas/service.py`: regra de domínio e contrato de retorno.
|
|
- `app/domain/contas/client.py`: chamada concreta das integrações TIM.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- VAS: endpoints/credenciais de consulta, histórico, bloqueio/cancelamento e defaults TIM; entre as variáveis presentes no cliente estão `TIM_VAS_HISTORY_URL`, `TIM_VAS_HISTORY_AUTH`, `TIM_VAS_HISTORY_TIMEOUT` e configuração de gateway.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# 14. Regra — Conhecimento Geral de Contas
|
|
|
|
**Intent:** `contas_knowledge`
|
|
**Agente:** `suporte_contas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `120`
|
|
|
|
## O que esta regra significa
|
|
|
|
Perguntas gerais, conceituais, explicativas ou de procedimento sobre funcionamento, tarifação, regras, condições e características de planos, produtos, faturas e serviços que não exigem consultar dados específicos do cliente. Use esta intent quando o usuário perguntar como um plano/produto funciona, mesmo citando seu nome. Não use para descobrir qual plano está contratado na linha nem para consultar valor/dados contratuais do plano atual.
|
|
|
|
### Limite da regra
|
|
|
|
Serve para conhecimento geral que não requer consultar dados particulares da linha; perguntas sobre 'meu plano/minha fatura' pertencem a intents de dados do cliente.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_knowledge | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | suporte_contas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 120 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Perguntas gerais, conceituais, explicativas ou de procedimento sobre funcionamento, tarifação, regras, condições e características de planos, produtos, faturas e serviços que não exigem consultar dados específicos do cliente. Use esta intent quando o usuário perguntar como um plano/produto funciona, mesmo citando seu nome. Não use para descobrir qual plano está contratado na linha nem para consultar valor/dados contratuais do plano atual. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | — | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | o que é<br>o que significa<br>como funciona<br>como é a tarifação<br>como funciona a tarifação<br>tarifação do plano<br>tarifacao do plano<br>qual a regra<br>quais são as regras<br>quais sao as regras<br>como faço<br>onde encontro<br>informação sobre<br>informacao sobre | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Como funciona o Infinity Pós?<br>Como funciona a tarifação do Infinity Pós?<br>Quais são as regras do Infinity Pós?<br>O que significa cobrança proporcional?<br>Como funciona o vencimento da fatura? | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `o que é`, `o que significa`, `como funciona`, `como é a tarifação`, `como funciona a tarifação`, `tarifação do plano`, `tarifacao do plano`, `qual a regra`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `120` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Como funciona o Infinity Pós?`, `Como funciona a tarifação do Infinity Pós?`, `Quais são as regras do Infinity Pós?` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=suporte_contas_agent` e `mcp_tools=[]`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
Esta intent não declara MCP tools. O tratamento é conversacional, de clarificação ou de conhecimento por mecanismos do agente/framework.
|
|
|
|
## Workflow
|
|
|
|
Não existe workflow dedicado para esta regra. A capability é executada diretamente ou a resposta é produzida pelo runtime/agente.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_knowledge` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# 15. Regra — Status de Solicitação
|
|
|
|
**Intent:** `contas_service_status`
|
|
**Agente:** `suporte_contas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `90`
|
|
|
|
## O que esta regra significa
|
|
|
|
Consulta de status, andamento, protocolo ou acompanhamento de solicitação já aberta.
|
|
|
|
### Limite da regra
|
|
|
|
A regra deve permanecer dentro da descrição declarada; quando o objetivo muda, o roteamento/handoff deve mudar também.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_service_status | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | suporte_contas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 90 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Consulta de status, andamento, protocolo ou acompanhamento de solicitação já aberta. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | consultar_status_solicitacao | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | protocolo<br>status da solicitação<br>status da solicitacao<br>andamento<br>acompanhamento<br>acompanhar solicitação<br>acompanhar solicitacao<br>pedido em andamento | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Qual o status da minha solicitação?<br>Quero acompanhar o protocolo | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `protocolo`, `status da solicitação`, `status da solicitacao`, `andamento`, `acompanhamento`, `acompanhar solicitação`, `acompanhar solicitacao`, `pedido em andamento`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `90` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Qual o status da minha solicitação?`, `Quero acompanhar o protocolo` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=suporte_contas_agent` e `mcp_tools=['consultar_status_solicitacao']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `consultar_status_solicitacao`
|
|
|
|
**O que faz:** Consulta status de solicitação/protocolo TIM.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
| `protocol` | `string` | extraído de `message` via `llm` | Número ou identificador de protocolo/solicitação informado pelo cliente ou retornado por sistema. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Extração conversacional:**
|
|
- `protocol`: Extraia somente o número de protocolo explicitamente informado pelo cliente; não use message_id ou interaction_key como protocolo. Estratégia: `llm`.
|
|
|
|
**Retorno esperado:** Retorna o status da solicitação/SR consultada pelo protocolo.
|
|
|
|
**Workflow:** não há workflow dedicado; a execução é direta no MCP/serviço ou é tratada pelo runtime do framework.
|
|
|
|
## Workflow
|
|
|
|
Não existe workflow dedicado para esta regra. A capability é executada diretamente ou a resposta é produzida pelo runtime/agente.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_service_status` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
- `app/domain/contas/service.py`: regra de domínio e contrato de retorno.
|
|
- `app/domain/contas/client.py`: chamada concreta das integrações TIM.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- Solicitação/finalização: `TIM_SERVICE_REQUEST_STATUS_*`, `TIM_DEFAULT_CHANNEL` e configuração de protocolo.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# 16. Regra — Pró-rata
|
|
|
|
**Intent:** `contas_pro_rata`
|
|
**Agente:** `faturas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `128`
|
|
|
|
## O que esta regra significa
|
|
|
|
Cobrança proporcional/pró-rata decorrente de troca de plano.
|
|
|
|
### Limite da regra
|
|
|
|
A regra deve permanecer dentro da descrição declarada; quando o objetivo muda, o roteamento/handoff deve mudar também.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_pro_rata | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | faturas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 128 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Cobrança proporcional/pró-rata decorrente de troca de plano. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | pro_rata | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | pró-rata<br>pro rata<br>pro-rata<br>cobrança proporcional<br>cobranca proporcional<br>troca de plano | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Por que veio cobrança proporcional?<br>Troquei de plano e vieram duas cobranças | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `pró-rata`, `pro rata`, `pro-rata`, `cobrança proporcional`, `cobranca proporcional`, `troca de plano`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `128` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Por que veio cobrança proporcional?`, `Troquei de plano e vieram duas cobranças` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=faturas_agent` e `mcp_tools=['pro_rata']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `pro_rata`
|
|
|
|
**O que faz:** Explica cobrança proporcional e conduz pause/resume pelo WorkflowRuntime.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `conversational` |
|
|
| operation_type | `conversational` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
| `planos` | `array` | fornecido pelo runtime/contexto | Lista de planos identificados no contexto ou retornados por sistemas para análise de pró-rata. |
|
|
| `has_plano_controle` | `boolean` | fornecido pelo runtime/contexto | Indicador booleano que informa se há plano Controle entre os planos considerados no fluxo. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna o resultado do workflow conversacional de pró-rata, podendo pausar para esclarecimento.
|
|
|
|
**Workflow(s):** `workflows/pro_rata.v3.yaml`.
|
|
|
|
## Workflows envolvidos
|
|
|
|
### Workflow `pro_rata.v3.yaml`
|
|
|
|
**Nome lógico:** `pro_rata` · **versão:** `3` · **start:** `preparar`
|
|
|
|
**Por que existe dessa forma:** Pró-rata exige explicação e possível esclarecimento do cliente. Por isso o workflow contém pause/resume e caminhos diferentes para plano Controle, aceite e necessidade de repergunta.
|
|
|
|
#### Nós
|
|
|
|
| Nó | Action Python | Papel | Pause/Resume |
|
|
|---|---|---|---|
|
|
| `preparar` | `preparar_pro_rata` | Executa `preparar_pro_rata`. É o ponto inicial. | não |
|
|
| `formatar` | `formatar_pro_rata` | Executa `formatar_pro_rata`. | sim; `return_from=$.output.mensagem`; resposta em `resposta_usuario`; permitidos=['SIM', 'NAO', 'OUTRO']; `resume_from=decisao_esclarecimento` |
|
|
| `decisao_esclarecimento` | `no_op` | Executa `no_op`. É nó de decisão/orquestração, sem efeito de domínio. | não |
|
|
| `devolver_orquestrador` | `no_op` | Executa `no_op`. É nó de decisão/orquestração, sem efeito de domínio. | não |
|
|
| `reperguntar_esclarecimento` | `formatar_pro_rata` | Executa `formatar_pro_rata`. | sim; `return_from=$.output.mensagem`; resposta em `resposta_usuario`; permitidos=['SIM', 'NAO', 'OUTRO']; `resume_from=decisao_esclarecimento` |
|
|
| `registrar_nao_controle` | `registrar_atendimento_pro_rata` | Executa `registrar_atendimento_pro_rata`. | não |
|
|
| `registrar_aceitou` | `registrar_atendimento_pro_rata` | Executa `registrar_atendimento_pro_rata`. | não |
|
|
|
|
#### Transições e condições
|
|
|
|
| De | Para | Prioridade | Condição | Interpretação |
|
|
|---|---|---:|---|---|
|
|
| `preparar` | `formatar` | — | sempre | Transição incondicional. |
|
|
| `formatar` | `decisao_esclarecimento` | 10 | `{"eq": ["$.vars.preparar.await_user_input", true]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `formatar` | `registrar_nao_controle` | 20 | sempre | Transição incondicional. |
|
|
| `decisao_esclarecimento` | `registrar_aceitou` | 10 | `{"eq": ["$.input.resposta_usuario", "SIM"]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `decisao_esclarecimento` | `devolver_orquestrador` | 20 | `{"eq": ["$.input.resposta_usuario", "NAO"]}` | A transição só ocorre quando a expressão declarativa é verdadeira; quando há várias saídas, o runtime avalia por prioridade crescente. |
|
|
| `decisao_esclarecimento` | `reperguntar_esclarecimento` | 30 | sempre | Transição incondicional. |
|
|
| `devolver_orquestrador` | `END` | — | sempre | Transição incondicional. |
|
|
| `reperguntar_esclarecimento` | `decisao_esclarecimento` | — | sempre | Transição incondicional. |
|
|
| `registrar_nao_controle` | `END` | — | sempre | Transição incondicional. |
|
|
| `registrar_aceitou` | `END` | — | sempre | Transição incondicional. |
|
|
|
|
#### Como funciona a pausa e o resume
|
|
|
|
- Em `formatar`, a execução pausa quando `{"eq": ["$.vars.preparar.await_user_input", true]}` é verdadeira. A mensagem devolvida ao cliente vem de `$.output.mensagem`. O runtime persiste `workflow_name` e `execution_id`; a próxima fala é normalizada no campo `resposta_usuario` e a execução retorna em `decisao_esclarecimento`. Valores esperados: `['SIM', 'NAO', 'OUTRO']`.
|
|
- Em `reperguntar_esclarecimento`, a execução pausa quando `null` é verdadeira. A mensagem devolvida ao cliente vem de `$.output.mensagem`. O runtime persiste `workflow_name` e `execution_id`; a próxima fala é normalizada no campo `resposta_usuario` e a execução retorna em `decisao_esclarecimento`. Valores esperados: `['SIM', 'NAO', 'OUTRO']`.
|
|
|
|
#### Término
|
|
|
|
- O fluxo termina após `devolver_orquestrador` quando a transição final é alcançada.
|
|
- O fluxo termina após `registrar_nao_controle` quando a transição final é alcançada.
|
|
- O fluxo termina após `registrar_aceitou` quando a transição final é alcançada.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_pro_rata` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- Billing/fatura: URLs e timeouts de fatura/PDF definidos no `.env` e complementados por `config/tim_integration_defaults.yaml`.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# 17. Regra — Término de Desconto
|
|
|
|
**Intent:** `contas_termino_desconto`
|
|
**Agente:** `faturas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `127`
|
|
|
|
## O que esta regra significa
|
|
|
|
Término de desconto ou promoção refletido na fatura.
|
|
|
|
### Limite da regra
|
|
|
|
A regra deve permanecer dentro da descrição declarada; quando o objetivo muda, o roteamento/handoff deve mudar também.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_termino_desconto | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | faturas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 127 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Término de desconto ou promoção refletido na fatura. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | termino_desconto | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | término de desconto<br>termino de desconto<br>desconto acabou<br>fim do desconto | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Meu desconto acabou? | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `término de desconto`, `termino de desconto`, `desconto acabou`, `fim do desconto`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `127` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Meu desconto acabou?` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=faturas_agent` e `mcp_tools=['termino_desconto']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `termino_desconto`
|
|
|
|
**O que faz:** Analisa término/retirada de desconto somente com causa suportada por evidência autoritativa.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
| `nome_plano` | `string` | extraído de `message` via `llm` | Nome do plano ao qual a informação ou tratamento se refere. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Extração conversacional:**
|
|
- `nome_plano`: Extraia o nome do plano se explicitamente citado; null se ausente. Estratégia: `llm`.
|
|
|
|
**Retorno esperado:** Retorna resposta formatada a partir de evidência autoritativa sobre o término do desconto.
|
|
|
|
**Workflow(s):** `workflows/termino_desconto.v1.yaml`.
|
|
|
|
## Workflows envolvidos
|
|
|
|
### Workflow `termino_desconto.v1.yaml`
|
|
|
|
**Nome lógico:** `termino_desconto` · **versão:** `1` · **start:** `formatar`
|
|
|
|
**Por que existe dessa forma:** A regra foi reduzida a formatação porque a decisão deve estar apoiada em evidência autoritativa de desconto; o workflow não inventa causa nem cria transação.
|
|
|
|
#### Nós
|
|
|
|
| Nó | Action Python | Papel | Pause/Resume |
|
|
|---|---|---|---|
|
|
| `formatar` | `formatar_capability_resposta` | Executa `formatar_capability_resposta`. É o ponto inicial. | não |
|
|
|
|
#### Transições e condições
|
|
|
|
| De | Para | Prioridade | Condição | Interpretação |
|
|
|---|---|---:|---|---|
|
|
| `formatar` | `END` | — | sempre | Transição incondicional. |
|
|
|
|
#### Término
|
|
|
|
- O fluxo termina após `formatar` quando a transição final é alcançada.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_termino_desconto` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- Billing/fatura: URLs e timeouts de fatura/PDF definidos no `.env` e complementados por `config/tim_integration_defaults.yaml`.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# 18. Regra — Valor Divergente
|
|
|
|
**Intent:** `contas_valor_divergente`
|
|
**Agente:** `faturas_agent`
|
|
**Domínio:** `telecom_contas`
|
|
**Prioridade:** `126`
|
|
|
|
## O que esta regra significa
|
|
|
|
Capability de valor divergente.
|
|
|
|
### Limite da regra
|
|
|
|
A regra deve permanecer dentro da descrição declarada; quando o objetivo muda, o roteamento/handoff deve mudar também.
|
|
|
|
## `routing.yaml` atributo por atributo
|
|
|
|
| Atributo | Valor nesta regra | Como participa da decisão |
|
|
|---|---|---|
|
|
| `name` | contas_valor_divergente | Identificador estável da intent. É o valor gravado na decisão de roteamento e usado para recuperar tools/agente. |
|
|
| `domain` | telecom_contas | Domínio lógico. Impede que a intent seja tratada como capability genérica sem contexto de Contas. |
|
|
| `agent` | faturas_agent | Agente proprietário da conversa depois que a intent é escolhida. |
|
|
| `priority` | 126 | Desempate determinístico entre keywords concorrentes. No `EnterpriseRouter`, **menor número vence**. |
|
|
| `description` | Capability de valor divergente. | Definição semântica usada pelo fallback LLM e pela manutenção humana. Deve dizer também quando **não** usar a intent. |
|
|
| `mcp_tools` | valor_divergente | Conjunto de tools que o roteamento entrega como capabilities esperadas para esta intent. |
|
|
| `keywords` | valor divergente<br>divergência de valor<br>divergencia de valor | Gatilhos determinísticos. O router tenta match exato, sequência ordenada de tokens e tokens informativos. |
|
|
| `examples` | Tem um valor divergente na minha conta | Exemplos fornecidos ao classificador LLM. Não são regex nem são executados diretamente. |
|
|
|
|
## Como esta intent é encontrada
|
|
|
|
1. O router procura primeiro keywords desta regra. Exemplos: `valor divergente`, `divergência de valor`, `divergencia de valor`.
|
|
2. Um match pode ser exato ou tolerante a tokens intermediários. Se outra intent também casar, a prioridade `126` participa do desempate.
|
|
3. Se o caminho LLM for usado, a descrição acima e exemplos como `Tem um valor divergente na minha conta` entram no catálogo de classificação.
|
|
4. Ao escolher a intent, o router entrega `agent=faturas_agent` e `mcp_tools=['valor_divergente']`. O agente não precisa hardcodar esse mapeamento.
|
|
|
|
## Tools desta regra
|
|
|
|
### Tool `valor_divergente`
|
|
|
|
**O que faz:** Trata variação/divergência de valor conforme workflow do Contas.
|
|
|
|
| Propriedade | Valor |
|
|
|---|---|
|
|
| MCP server | `contas` |
|
|
| enabled | `True` |
|
|
| tool_type | `read_only/implícito` |
|
|
| operation_type | `read_only` |
|
|
| require_confirmation | `False` |
|
|
| parâmetros obrigatórios pela policy | — |
|
|
| pre-validation | — |
|
|
|
|
**Dados necessários para chamada**
|
|
|
|
| Campo | Tipo | Origem / obtenção | Significado |
|
|
|---|---|---|---|
|
|
| `msisdn` | `string` | mapeado automaticamente de `customer_key` | Número da linha do cliente (MSISDN) usado para consultar dados associados ao atendimento. |
|
|
|
|
**Mapeamento técnico:** `customer_key → msisdn`, `session_key → session_id`.
|
|
|
|
**Retorno esperado:** Retorna resposta formatada pelo workflow de divergência de valor.
|
|
|
|
**Workflow(s):** `workflows/valor_divergente.v1.yaml`.
|
|
|
|
## Workflows envolvidos
|
|
|
|
### Workflow `valor_divergente.v1.yaml`
|
|
|
|
**Nome lógico:** `valor_divergente` · **versão:** `1` · **start:** `formatar`
|
|
|
|
**Por que existe dessa forma:** É um capability workflow simples de apresentação: recebe a evidência preparada pelo domínio e produz a resposta sem efeitos transacionais.
|
|
|
|
#### Nós
|
|
|
|
| Nó | Action Python | Papel | Pause/Resume |
|
|
|---|---|---|---|
|
|
| `formatar` | `formatar_capability_resposta` | Executa `formatar_capability_resposta`. É o ponto inicial. | não |
|
|
|
|
#### Transições e condições
|
|
|
|
| De | Para | Prioridade | Condição | Interpretação |
|
|
|---|---|---:|---|---|
|
|
| `formatar` | `END` | — | sempre | Transição incondicional. |
|
|
|
|
#### Término
|
|
|
|
- O fluxo termina após `formatar` quando a transição final é alcançada.
|
|
|
|
## Amarração Python
|
|
|
|
- `agent_framework_oci/.../routing/enterprise_router.py`: resolve `contas_valor_divergente` e entrega agente/tools.
|
|
- `app/agents/runtime.py` + runtime do framework: seleção/execução de tools, parâmetros, confirmação e pause/resume.
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`: enriquecimento, preflight, validação e dispatch MCP.
|
|
|
|
### `.env` e defaults relevantes
|
|
|
|
- Configuração estrutural: `ROUTING_CONFIG_PATH`, `TOOLS_CONFIG_PATH`, `TOOL_POLICIES_PATH`, `MCP_PARAMETER_MAPPING_PATH`, `MCP_SERVERS_CONFIG_PATH`.
|
|
- Roteamento: `ENABLE_LLM_ROUTER` e parâmetros `ROUTE_STICKINESS_*` quando habilitados.
|
|
- Billing/fatura: URLs e timeouts de fatura/PDF definidos no `.env` e complementados por `config/tim_integration_defaults.yaml`.
|
|
- Resiliência de integração: `TIM_GATEWAY_MODE`, `TIM_GATEWAY_DEFAULT_TIMEOUT`, `TIM_GATEWAY_RETRY_MAX_RETRIES`, `TIM_GATEWAY_RETRY_BACKOFF_FACTOR`, `TIM_USE_MOCK_GATEWAY`.
|
|
|
|
# Regras transversais
|
|
|
|
## Confirmação transacional
|
|
|
|
`tool_policies.yaml` é a fonte declarativa que diferencia leitura, conversa e transação. `cancelar_vas_avulso` e `contestar_cobranca` usam `require_confirmation: true`. O runtime coleta parâmetros, chama a pre-validation e só então pergunta ao usuário. Uma resposta inequívoca é processada deterministicamente; respostas inconclusivas podem usar o `transaction_confirmation.semantic_fallback` definido em `routing.yaml`.
|
|
|
|
## Coleta de parâmetros
|
|
|
|
Os campos obrigatórios vêm da policy (`requires`) e do schema da tool. `mcp_parameter_mapping.yaml` informa o que pode vir automaticamente do contexto e o que deve ser extraído da mensagem. Se um campo obrigatório continuar faltando, a sessão entra em `COLLECTING_*_PARAMETERS`, e `state_policies` mantém a fala seguinte no agente proprietário.
|
|
|
|
## Pre-validation
|
|
|
|
Pre-validation não deve produzir efeito externo. Ela resolve entidade, elegibilidade, valor e classe de negócio. Em VAS, `validar_vas_subject` pode mudar a tool efetiva. Em contestação, `validar_contestacao` protege contra item/valor não suportado pela fatura.
|
|
|
|
## Pause/Resume de workflow
|
|
|
|
Um nó com `pause.enabled=true` devolve uma mensagem ao cliente e persiste a execução. A próxima fala é entregue ao mesmo workflow por `execution_id`, normalizada conforme `expected_input` e retomada em `resume_from`. `retomar_workflow` é infraestrutura; não representa uma intent de negócio.
|
|
|
|
## Multi-intent
|
|
|
|
O MultiIntentPlanner deve separar objetivos independentes, por exemplo “cancelar X e mandar segunda via”. Ele não deve decompor `subject`, `valor` e `motivo` de uma única contestação em intents diferentes. Em pedidos com vários VAS, os itens canônicos permanecem em `items[]` para evitar reinterpretação da string agregada.
|
|
|
|
## State stickiness
|
|
|
|
Estados `WAITING_*_CONFIRMATION` e `COLLECTING_*_PARAMETERS` têm precedência sobre uma nova classificação de uma fala curta. Mudança explícita de assunto pode liberar handoff conforme as políticas de continuidade/intent shift.
|
|
|
|
# Guia de diagnóstico de uma decisão inesperada
|
|
|
|
Use esta sequência:
|
|
|
|
1. **Qual era o estado antes da fala?** Veja `transaction_status`, workflow pausado e `state_policies`.
|
|
2. **Qual intent foi escolhida e por qual método?** `state`, `keyword`, LLM ou fallback.
|
|
3. **Qual keyword venceu?** Lembre que menor `priority` vence e keywords mais específicas desempatarão.
|
|
4. **Quais tools a intent autorizou?**
|
|
5. **Qual tool o runtime realmente selecionou?** Compare `selection_keywords`, transação ativa e pending topics.
|
|
6. **Quais parâmetros foram coletados?** Diferencie `requested_arguments` de `resolved_arguments`.
|
|
7. **O pre-validator alterou algo?** Verifique `effective_tool_name`, `action_changed`, `domain_policy.class` e entidade canônica.
|
|
8. **Havia múltiplos itens?** Se sim, `items[]` deve ser a fonte de verdade; não re-resolver a string unida.
|
|
9. **Qual workflow começou?** Confira versão ativa e `execution_id`.
|
|
10. **Em qual nó/aresta terminou ou pausou?** Avalie condições por prioridade.
|
|
11. **Qual integração falhou?** Diferencie erro de classificação, elegibilidade e erro técnico (`service_not_found`, timeout, backend etc.).
|
|
12. **A resposta final preservou resultados parciais?** Um item bem-sucedido não autoriza afirmar sucesso para os demais.
|
|
|
|
# Exemplo completo — “quero cancelar Tamboro e Paramount+”
|
|
|
|
```text
|
|
Mensagem
|
|
↓
|
|
routing.yaml → contas_vas_cancel
|
|
↓
|
|
tools candidatas: consultar_vas + cancelar_vas_avulso
|
|
↓
|
|
extração de subject / resolução de múltiplas entidades
|
|
↓
|
|
validar_vas_subject / invoice_resolver
|
|
├─ Tamboro Mensal → avulso → cancelar_vas_avulso
|
|
└─ Paramount+ → estratégico/bundle conforme evidência → tratar_vas_estrategico
|
|
↓
|
|
cada item preserva sua classe e resultado
|
|
├─ avulso → confirmação → cancelamento_vas_avulso.v1
|
|
└─ estratégico → vas_estrategico.v3 → explicação/orientação/pause-resume
|
|
```
|
|
|
|
A lição arquitetural é que **o verbo do usuário escolhe a intenção, mas a evidência do domínio escolhe a operação válida para a entidade**. É exatamente por isso que dois serviços citados na mesma frase podem terminar em regras diferentes.
|
|
|
|
# Arquivos-fonte mais importantes
|
|
|
|
- `config/routing.yaml`
|
|
- `config/tools.yaml`
|
|
- `config/tool_policies.yaml`
|
|
- `config/mcp_parameter_mapping.yaml`
|
|
- `config/agents.yaml`
|
|
- `config/tim_integration_defaults.yaml`
|
|
- `.env.example`
|
|
- `contas_mcp/servers/contas_mcp_server/main.py`
|
|
- `app/domain/contas/invoice_resolver.py`
|
|
- `app/domain/contas/parsers/bill_processor.py`
|
|
- `app/domain/contas/workflow_actions.py`
|
|
- `app/domain/contas/service.py`
|
|
- `app/domain/contas/client.py`
|
|
- `agent_framework_oci/libs/agent_framework/src/agent_framework/routing/enterprise_router.py`
|
|
- `agent_framework_oci/libs/agent_framework/src/agent_framework/runtime/agent_runtime.py`
|
|
- `agent_framework_oci/libs/agent_framework/src/agent_framework/workflows/runtime.py`
|