Ajustes conforme relatorio de testes 2026-08-27

This commit is contained in:
2026-08-29 11:22:05 -03:00
parent 5cf3097e5a
commit 71f6c18e78
242 changed files with 246 additions and 9 deletions

View File

@@ -11207,6 +11207,7 @@ O conteúdo desta pasta deve ser tratado como uma extensão adicional do framewo
| Uma resposta que deveria preencher parâmetro é interpretada como novo intent | precedência transacional, parameter extraction | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) |
| A transação fica pedindo o mesmo parâmetro | estado transacional, extractor, schema | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) e [MCP/Tools](docs/developer/pt/04_mcp_integration_tools_and_policies.md) |
| A confirmação “sim/não” não continua o fluxo | confirmation state, transaction state | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) |
| Uma fala inválida durante um `expected_input` vira `CONTINUAR` em vez de pedir esclarecimento | `semantic_classifier.unmatched_value`, `reprompt`, `contextual_reentry`, COER delegado | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) e [Feedback de Guardrails de Entrada](docs/developer/pt/12_input_guardrail_feedback_and_blocked_turns.md) |
| Uma transação encerrada reaparece | checkpoint antigo versus estado transacional ativo | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) e [LTM/Checkpoint](docs/developer/pt/08_long_term_memory_and_checkpoint.md) |
| O sistema diz que executou algo, mas não existe evidência | MCP result, estado `COMPLETED`, judges transacionais | [Workflows Transacionais](docs/developer/pt/03_transaction_workflows_and_state.md) e [Guardrails/Judges](docs/developer/pt/06_guardrails_judges_and_transaction_evaluation.md) |
| Uma tool não aparece ou não é encontrada | `tools.yaml`, catálogo MCP, discovery | [MCP/Tools](docs/developer/pt/04_mcp_integration_tools_and_policies.md) |
@@ -11252,9 +11253,9 @@ O conteúdo desta pasta deve ser tratado como uma extensão adicional do framewo
### [03 — Workflows Transacionais e Estado](docs/developer/pt/03_transaction_workflows_and_state.md)
**O que é:** ciclo transacional multi-turno, estados, confirmação, pausa/retomada e evidência operacional.
**O que é:** ciclo transacional multi-turno, estados, confirmação, pausa/retomada, `expected_input`, `semantic_classifier`, `unmatched_value`/`reprompt` e evidência operacional.
**Use quando:** há loops, confirmações incorretas, retomadas erradas ou operações críticas.
**Use quando:** há loops, confirmações incorretas, retomadas erradas, `CONTINUAR`/`contextual_reentry` indevido, `reprompt` ausente ou operações críticas.
### [04 — MCP, Tools, Policies e Extração de Parâmetros](docs/developer/pt/04_mcp_integration_tools_and_policies.md)

View File

@@ -11114,6 +11114,7 @@ The content of this folder should be treated as an additional framework extensio
| A parameter answer is mistaken for a new intent | transaction precedence, parameter extraction | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) |
| Transaction keeps asking for the same parameter | transaction state, extractor, schema | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [MCP/Tools](docs/developer/en/04_mcp_integration_tools_and_policies.md) |
| “yes/no” confirmation does not continue the flow | confirmation state | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) |
| Invalid input during `expected_input` becomes `CONTINUAR` instead of asking for clarification | `semantic_classifier.unmatched_value`, `reprompt`, `contextual_reentry`, delegated COER | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [Input Guardrail Feedback](docs/developer/en/12_input_guardrail_feedback_and_blocked_turns.md) |
| A closed transaction reappears | old checkpoint vs active transaction | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [LTM/Checkpoint](docs/developer/en/08_long_term_memory_and_checkpoint.md) |
| System claims an operation ran but there is no evidence | MCP results, `COMPLETED`, transaction judges | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [Guardrails/Judges](docs/developer/en/06_guardrails_judges_and_transaction_evaluation.md) |
| A tool is missing | tools config, MCP catalog/discovery | [MCP/Tools](docs/developer/en/04_mcp_integration_tools_and_policies.md) |

View File

@@ -624,6 +624,74 @@ When semantic confirmation succeeds, the router records:
`AgentRuntime` reuses this routed decision instead of re-running the deterministic parser. The change is additive: existing explicit yes/no inputs continue through the deterministic path with no extra LLM call. Semantic generations are named `transaction.confirmation.semantic_classifier` for observability.
### `expected_input.semantic_classifier.unmatched_value` and `reprompt`
Paused workflows may accept literal replies and also classify free-text replies semantically. When `semantic_classifier` is enabled, an utterance that **cannot safely be mapped to any valid class** must not be forced into `SIM`, `NAO`, or `CONTINUAR`. For that case, the workflow may declare a classifier sentinel through `unmatched_value`.
Example:
```yaml
expected_input:
key: resposta_usuario
allowed_values:
- SIM
- NAO
- CONTINUAR
normalize: upper_strip
reprompt: >
I did not understand. Did this explanation resolve your question?
Please answer yes or no.
semantic_classifier:
enabled: true
include_relevant_context: true
unmatched_value: OUTRO
prompt: |
Classify the customer's utterance into a valid option only when there is
enough meaning to do so safely.
SIM: unambiguous understanding/acceptance.
NAO: unambiguous negative answer.
CONTINUAR: a meaningful utterance that complements or continues the request.
OUTRO: incomprehensible, disconnected, or insufficient input for any valid class.
Return only SIM, NAO, CONTINUAR, or OUTRO.
option_actions:
CONTINUAR:
action: contextual_reentry
```
The contract is:
```text
SIM -> resume with SIM
NAO -> resume with NAO
CONTINUAR -> execute the configured option_action (for example contextual_reentry)
OUTRO -> never resume with this value; return reprompt and keep the workflow paused
```
Important rules:
- `unmatched_value` is a **classifier sentinel**, not a business response;
- do not add the sentinel to `allowed_values`; `allowed_values` contains only values the workflow may consume;
- `CONTINUAR` is valid only for a meaningful utterance that actually continues the topic; contextually meaningless input should return `unmatched_value` and trigger `reprompt`;
- `reprompt` does not complete or restart the execution: the same workflow remains `PAUSED` and waits for another reply;
- internal values such as `SIM`, `NAO`, `CONTINUAR`, and the sentinel must never leak as customer-facing output.
Behavioral example:
```text
Pending prompt: "Did this explanation resolve your question?"
"sim" -> SIM
"não resolveu" -> NAO
"mas e a cobrança de R$ 14,99?" -> CONTINUAR -> contextual_reentry
"ano" -> OUTRO -> reprompt
```
This option is **opt-in per workflow**. Workflows that do not declare `semantic_classifier.unmatched_value` keep the previous contract, preventing a change in one flow from silently changing other workflows or agents.
### Durable interrupt compatibility in pause/resume
The runtime does not use `snapshot.next` alone to decide whether a workflow is paused. A truthy `next` may represent LangGraph helper work, including framework-generated synthetic nodes such as `__pause` and `__continue`.

View File

@@ -95,6 +95,35 @@ A response created because of an input block is still agent output. Therefore it
This allows `DLEX_OUT`, `PINJ`, `TOXOUT`, Output Supervisor, and other policies to remove or sanitize information that should not be exposed.
## COER, `expected_input`, and `reprompt` in paused workflows
When an active `expected_input.semantic_classifier` exists, the framework may delegate semantic interpretation to the workflow contract instead of immediately treating an ambiguous input as a generic `COER` block. In this mode, the guardrail may be recorded as allowed/delegated, for example with mechanism `expected_input_semantic_classifier`.
The workflow remains responsible for distinguishing:
```text
valid, meaningful reply -> valid class / option_action
insufficient or meaningless -> unmatched_value -> reprompt
```
Example:
```yaml
expected_input:
allowed_values: [SIM, NAO, CONTINUAR]
reprompt: "I did not understand. Did this explanation resolve your question? Please answer yes or no."
semantic_classifier:
enabled: true
unmatched_value: OUTRO
option_actions:
CONTINUAR:
action: contextual_reentry
```
Under this contract, `CONTINUAR` does not mean "anything other than SIM or NAO". It represents a **coherent, contextual** utterance that continues the topic. Input such as `ano`, which has insufficient meaning for the pending prompt, should return sentinel `OUTRO` and produce the `reprompt`, while keeping the same workflow paused.
`OUTRO` must not be added to `allowed_values` or sent to the runtime as a resume value. See [03 — Transactional Workflows and State](./03_transaction_workflows_and_state.md#expected_inputsemantic_classifierunmatched_value-and-reprompt) for the full contract.
## Relationship with `agent_graph.py`
This feature belongs to template orchestration because it defines precedence between graph nodes and blocked-turn state semantics.
@@ -151,6 +180,8 @@ input_guardrails blocked
Cover at least:
- `COER=false` asks for clarification instead of returning a generic security message;
- with `expected_input.semantic_classifier.unmatched_value`, incoherent/insufficient input triggers `reprompt` and keeps the workflow `PAUSED`;
- meaningful input outside literal SIM/NAO can still follow `CONTINUAR -> contextual_reentry` without being confused with incoherent input;
- blocked branch does not retain previous-turn `mcp_results`/routing;
- no transactional tool executes after an input block;
- the public message passes through output guardrails;

View File

@@ -21,6 +21,7 @@ If something is not working, use **Search by problem** below.
| An answer that should fill a parameter is interpreted as a new intent | transactional precedence, parameter extraction | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) |
| The transaction keeps asking for the same parameter | transaction state, extractor, schema | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [MCP/Tools](docs/developer/en/04_mcp_integration_tools_and_policies.md) |
| “yes/no” confirmation does not continue the flow | confirmation state, transaction state | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) |
| Invalid input during `expected_input` becomes `CONTINUAR` instead of asking for clarification | `semantic_classifier.unmatched_value`, `reprompt`, `contextual_reentry`, delegated COER | [Transactional Workflows](./03_transaction_workflows_and_state.md) and [Input Guardrail Feedback](./12_input_guardrail_feedback_and_blocked_turns.md) |
| A completed transaction reappears | old checkpoint versus active transaction state | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [LTM/Checkpoint](docs/developer/en/08_long_term_memory_and_checkpoint.md) |
| The system says it executed something, but there is no evidence | MCP result, `COMPLETED` state, transactional judges | [Transactional Workflows](docs/developer/en/03_transaction_workflows_and_state.md) and [Guardrails/Judges](docs/developer/en/06_guardrails_judges_and_transaction_evaluation.md) |
| A tool does not appear or cannot be found | `tools.yaml`, MCP catalog, discovery | [MCP/Tools](docs/developer/en/04_mcp_integration_tools_and_policies.md) |
@@ -68,7 +69,7 @@ If something is not working, use **Search by problem** below.
**What it is:** multi-turn transaction lifecycle, states, confirmation, pause/resume, and operational evidence.
**Use when:** there are loops, incorrect confirmations, incorrect resumes, or critical operations.
**Use when:** there are loops, incorrect confirmations/resumes, unintended `CONTINUAR`/`contextual_reentry`, missing `reprompt`, or critical operations.
### [04 — MCP, Tools, Policies, and Parameter Extraction](docs/developer/en/04_mcp_integration_tools_and_policies.md)

View File

@@ -679,6 +679,74 @@ A funcionalidade é aditiva. Entradas determinísticas já suportadas continuam
Para confirmações semânticas, o framework registra a geração como `transaction.confirmation.semantic_classifier` e acrescenta ao metadata do roteamento a fonte `semantic`, a classificação retornada e o contexto conversacional relevante utilizado. Para confirmações literais, a fonte permanece `deterministic`.
### `expected_input.semantic_classifier.unmatched_value` e `reprompt`
Workflows pausados podem aceitar respostas literais e também interpretar respostas livres por semântica. Quando o `semantic_classifier` é habilitado, uma fala que **não representa com segurança nenhuma das classes válidas** não deve ser forçada para `SIM`, `NAO` ou `CONTINUAR`. Para esse caso, o workflow pode declarar um valor sentinela com `unmatched_value`.
Exemplo:
```yaml
expected_input:
key: resposta_usuario
allowed_values:
- SIM
- NAO
- CONTINUAR
normalize: upper_strip
reprompt: >
Não entendi. Essa explicação resolveu sua dúvida?
Responda sim ou não.
semantic_classifier:
enabled: true
include_relevant_context: true
unmatched_value: OUTRO
prompt: |
Classifique a fala do cliente em exatamente uma das opções válidas quando houver
significado suficiente.
SIM: entendimento/aceite inequívoco.
NAO: negativa inequívoca.
CONTINUAR: fala compreensível que complementa ou continua a solicitação.
OUTRO: fala incompreensível, desconexa ou insuficiente para qualquer classe válida.
Retorne somente SIM, NAO, CONTINUAR ou OUTRO.
option_actions:
CONTINUAR:
action: contextual_reentry
```
O contrato é:
```text
SIM -> resume com SIM
NAO -> resume com NAO
CONTINUAR -> executa a option_action configurada (por exemplo contextual_reentry)
OUTRO -> não é usado como valor de resume; devolve o reprompt e mantém o workflow pausado
```
Regras importantes:
- `unmatched_value` é **sentinela do classificador**, não uma resposta de negócio;
- não adicione o sentinela a `allowed_values`; `allowed_values` continua descrevendo apenas valores que podem ser consumidos pelo workflow;
- `CONTINUAR` deve ser usado somente quando a fala é compreensível e realmente continua o assunto; uma fala sem significado contextual suficiente deve produzir `unmatched_value` e cair em `reprompt`;
- o `reprompt` não encerra nem reinicia a execução: o mesmo workflow permanece `PAUSED`, aguardando nova resposta;
- valores internos como `SIM`, `NAO`, `CONTINUAR` e o sentinela não devem vazar como resposta final do agente.
Exemplo comportamental:
```text
Pergunta pendente: "Com essa explicação, sanei sua dúvida?"
"sim" -> SIM
"não resolveu" -> NAO
"mas e a cobrança de R$ 14,99?" -> CONTINUAR -> contextual_reentry
"ano" -> OUTRO -> reprompt
```
A opção é **opt-in por workflow**. Workflows que não declaram `semantic_classifier.unmatched_value` preservam o contrato anterior. Isso evita que uma evolução específica de um fluxo altere silenciosamente os demais workflows/agentes.
### Compatibilidade de interrupts duráveis no pause/resume
O runtime não usa `snapshot.next` isoladamente para decidir se um workflow está pausado. Um `next` pode representar trabalho auxiliar do LangGraph, inclusive nós sintéticos criados pelo framework como `__pause` e `__continue`.

View File

@@ -95,6 +95,35 @@ Uma resposta criada em função de um bloqueio de entrada ainda é uma saída do
Isso permite que `DLEX_OUT`, `PINJ`, `TOXOUT`, Output Supervisor e outras políticas removam ou sanitizem informação que não deva ser apresentada.
## COER, `expected_input` e `reprompt` em workflows pausados
Quando existe um `expected_input.semantic_classifier` ativo, o framework pode delegar a decisão semântica ao contrato do workflow em vez de tratar imediatamente uma entrada ambígua como bloqueio genérico de `COER`. Nesse modo, o guardrail pode aparecer como permitido/delegado, por exemplo com mecanismo `expected_input_semantic_classifier`.
O workflow continua responsável por diferenciar:
```text
resposta válida e compreensível -> classe válida / option_action
resposta sem significado suficiente -> unmatched_value -> reprompt
```
Exemplo de configuração:
```yaml
expected_input:
allowed_values: [SIM, NAO, CONTINUAR]
reprompt: "Não entendi. Essa explicação resolveu sua dúvida? Responda sim ou não."
semantic_classifier:
enabled: true
unmatched_value: OUTRO
option_actions:
CONTINUAR:
action: contextual_reentry
```
Nesse contrato, `CONTINUAR` não significa "qualquer coisa que não seja SIM ou NAO". Ele representa uma fala **coerente e contextual** que continua o assunto. Uma entrada como `ano`, sem significado suficiente para a pergunta pendente, deve retornar o sentinela `OUTRO` e produzir o `reprompt`, mantendo o mesmo workflow pausado.
`OUTRO` não deve ser adicionado a `allowed_values` nem enviado ao runtime como valor de resume. A descrição completa do contrato está em [03 — Workflows Transacionais e Estado](./03_transaction_workflows_and_state.md#expected_inputsemantic_classifierunmatched_value-e-reprompt).
## Relação com `agent_graph.py`
Esta feature é responsabilidade da orquestração do template, porque define a precedência entre nós do grafo e o estado do turno.
@@ -151,6 +180,8 @@ input_guardrails bloqueou
Cubra pelo menos:
- `COER=false` gera solicitação de esclarecimento, não mensagem genérica de segurança;
- com `expected_input.semantic_classifier.unmatched_value`, entrada incoerente/sem significado suficiente aciona `reprompt` e mantém o workflow `PAUSED`;
- uma entrada compreensível fora de SIM/NAO pode seguir `CONTINUAR -> contextual_reentry` sem ser confundida com uma entrada incoerente;
- ramo bloqueado não conserva `mcp_results`/routing de turno anterior;
- nenhuma tool transacional é executada depois de um bloqueio de input;
- mensagem pública passa pelos guardrails de saída;

View File

@@ -22,6 +22,7 @@ Se algo não está funcionando, use **Buscar pelo problema** abaixo.
| Uma resposta que deveria preencher parâmetro é interpretada como novo intent | precedência transacional, parameter extraction | [Workflows Transacionais](./03_transaction_workflows_and_state.md) |
| A transação fica pedindo o mesmo parâmetro | estado transacional, extractor, schema | [Workflows Transacionais](./03_transaction_workflows_and_state.md) e [MCP/Tools](./04_mcp_integration_tools_and_policies.md) |
| A confirmação “sim/não” não continua o fluxo | confirmation state, transaction state | [Workflows Transacionais](./03_transaction_workflows_and_state.md) |
| Uma fala inválida durante um `expected_input` vira `CONTINUAR` em vez de pedir esclarecimento | `semantic_classifier.unmatched_value`, `reprompt`, `contextual_reentry`, COER delegado | [Workflows Transacionais](./03_transaction_workflows_and_state.md) e [Feedback de Guardrails de Entrada](./12_input_guardrail_feedback_and_blocked_turns.md) |
| Uma transação encerrada reaparece | checkpoint antigo versus estado transacional ativo | [Workflows Transacionais](./03_transaction_workflows_and_state.md) e [LTM/Checkpoint](./08_long_term_memory_and_checkpoint.md) |
| O sistema diz que executou algo, mas não existe evidência | MCP result, estado `COMPLETED`, judges transacionais | [Workflows Transacionais](./03_transaction_workflows_and_state.md) e [Guardrails/Judges](./06_guardrails_judges_and_transaction_evaluation.md) |
| Uma tool não aparece ou não é encontrada | `tools.yaml`, catálogo MCP, discovery | [MCP/Tools](./04_mcp_integration_tools_and_policies.md) |
@@ -67,9 +68,9 @@ Se algo não está funcionando, use **Buscar pelo problema** abaixo.
### [03 — Workflows Transacionais e Estado](./03_transaction_workflows_and_state.md)
**O que é:** ciclo transacional multi-turno, estados, confirmação, pausa/retomada e evidência operacional.
**O que é:** ciclo transacional multi-turno, estados, confirmação, pausa/retomada, `expected_input`, `semantic_classifier`, `unmatched_value`/`reprompt` e evidência operacional.
**Use quando:** há loops, confirmações incorretas, retomadas erradas ou operações críticas.
**Use quando:** há loops, confirmações incorretas, retomadas erradas, `CONTINUAR`/`contextual_reentry` indevido, `reprompt` ausente ou operações críticas.
### [04 — MCP, Tools, Policies e Extração de Parâmetros](./04_mcp_integration_tools_and_policies.md)

View File

@@ -207,9 +207,13 @@ class EnterpriseRouter:
.replace("{{ relevant_conversation_context }}", str(relevant_conversation_context or ""))
.replace("{{ user_input }}", str(text or ""))
)
unmatched_value = str(classifier.get("unmatched_value") or "").strip()
protocol_options = list(allowed)
if unmatched_value:
protocol_options.append(unmatched_value)
protocol = (
"\n\nPROTOCOLO OBRIGATÓRIO DO FRAMEWORK: responda somente com UMA das "
f"opções permitidas, sem explicação adicional: {json.dumps(allowed, ensure_ascii=False)}."
f"opções permitidas, sem explicação adicional: {json.dumps(protocol_options, ensure_ascii=False)}."
)
try:
answer = await self.llm.ainvoke(

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