ajuste no contas
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
# Correção: transação ativa vence status terminal antigo
|
||||
|
||||
## Problema
|
||||
Em uma mesma sessão, uma transação anterior podia deixar `transaction_status=COMPLETED`. Quando uma nova transação já havia sido aberta em `AWAITING_CONFIRMATION`, o `input_guardrails` de `app/workflows/agent_graph.py` ainda usava o status terminal antigo como gatilho para limpar o contexto operacional. Isso apagava a nova `active_transaction`, fazendo a confirmação seguinte (`sim`) cair em `contas_no_match_retry`.
|
||||
|
||||
## Correção
|
||||
O reset operacional agora consulta primeiro `active_transaction.status`. Se existir uma transação ativa não-terminal (`COLLECTING_PARAMETERS`, `AWAITING_CONFIRMATION`, `EXECUTING`, `PAUSED` ou `WAITING_INPUT`), ela tem precedência sobre qualquer status terminal residual da transação anterior. O tombstone só ocorre quando não há transação ativa pendente.
|
||||
|
||||
## Resultado esperado
|
||||
- Transação anterior pode permanecer no histórico/evidência.
|
||||
- Nova transação não é apagada por status velho.
|
||||
- `sim` após a confirmação de TIM Fashion permanece no fluxo transacional.
|
||||
- Encerramentos reais continuam limpando o contexto quando não existe nova transação ativa.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Fix: isolamento do checkpoint LangGraph e snapshot do gateway
|
||||
|
||||
## Problema
|
||||
O gateway gravava `checkpoints.put(agent_session_id, {state: result, ...})` após `workflow.ainvoke()`.
|
||||
O LangGraph saver usa o mesmo repositório e a mesma chave `thread_id == agent_session_id`.
|
||||
Assim, o snapshot simplificado do gateway sobrescrevia o checkpoint nativo do LangGraph, removendo canais transacionais como `active_transaction`, `pending_tool_call`, `confirmation_snapshot` e `confirmation_required`.
|
||||
|
||||
## Correção
|
||||
O snapshot do gateway passou a usar o namespace `gateway:<session_id>`.
|
||||
O checkpoint LangGraph continua usando `<session_id>` sem interferência.
|
||||
O endpoint `/sessions/{session_id}/checkpoint` consulta o snapshot `gateway:<session_id>` para preservar o contrato de debug existente.
|
||||
|
||||
## Invariante
|
||||
- checkpoint LangGraph: chave `<session_id>`
|
||||
- snapshot/debug do gateway: chave `gateway:<session_id>`
|
||||
- nenhuma gravação externa pode sobrescrever o checkpoint nativo do LangGraph.
|
||||
25
docs/FIX_DATABASE_RESILIENCE_AND_FALLBACKS_20260831.md
Normal file
25
docs/FIX_DATABASE_RESILIENCE_AND_FALLBACKS_20260831.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Robustez de banco e fallbacks transacionais
|
||||
|
||||
## Objetivo
|
||||
Evitar que falhas de persistência/cache/idempotência derrubem o atendimento com HTTP 500 e contaminem a continuidade transacional.
|
||||
|
||||
## Alterações
|
||||
|
||||
1. `OracleStore.cache_get`
|
||||
- normaliza `datetime` naive/aware para UTC antes de comparar TTL;
|
||||
- elimina o `TypeError: can't compare offset-naive and offset-aware datetimes`.
|
||||
|
||||
2. `IdempotencyStore`
|
||||
- suporta backend de fallback;
|
||||
- quando `require_durable=False`, falhas do backend primário degradam para `InMemoryCache` por padrão;
|
||||
- `get`, `set` e `delete` não propagam indisponibilidade do backend primário em modo fail-open;
|
||||
- quando durabilidade é exigida, a semântica fail-closed continua disponível.
|
||||
|
||||
3. `cancelamento_vas_avulso_batch`
|
||||
- boundary por item converte exceções técnicas inesperadas em resultado recuperável;
|
||||
- um item com erro não derruba o batch nem o request HTTP inteiro;
|
||||
- erros são devolvidos com `reason=internal_processing_failed`/`recoverable=true` para composição controlada da resposta.
|
||||
|
||||
## Configuração opcional
|
||||
|
||||
`IDEMPOTENCY_FAIL_OPEN=true|false` pode sobrescrever o comportamento. Sem configuração explícita, `require_durable=False` usa fail-open e `require_durable=True` mantém fail-closed.
|
||||
19
docs/FIX_LLM_CONTEXT_COMPACTION_20260901.md
Normal file
19
docs/FIX_LLM_CONTEXT_COMPACTION_20260901.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Correção: compactação de contexto LLM
|
||||
|
||||
## Problema
|
||||
O estado operacional preserva resultados completos de MCP/workflows para auditoria e continuidade. Esses objetos podem conter cópias recursivas de `state`, `input`, `session`, `agent_profile`, `business_events`, `trace`, `nodes` e outros dados técnicos. Quando `build_messages()` serializava diretamente `mcp_results` e `transaction_evidence`, o prompt podia ultrapassar a janela do modelo.
|
||||
|
||||
Caso observado: `Input length (134212) exceeds model's maximum context length (131072)` no `ContestacaoAgent`.
|
||||
|
||||
## Correção
|
||||
- `build_messages()` passa a renderizar business context, MCP results, transaction evidence, RAG metadata e extra sections por um compactador genérico com orçamento de caracteres.
|
||||
- Objetos técnicos recursivos permanecem no estado/checkpoint para auditoria, mas não são reenviados integralmente ao LLM.
|
||||
- Fatos de negócio (tool, subject, status, valores, protocolos e resultados úteis) são preservados dentro do orçamento.
|
||||
- Se o provider ainda rejeitar por limite de contexto, `_invoke_llm_cached()` executa uma única segunda tentativa com orçamento emergencial de mensagens.
|
||||
- Não há loop de retries; qualquer outra exceção continua propagando normalmente.
|
||||
|
||||
## Invariantes
|
||||
1. Estado operacional completo != contexto de prompt.
|
||||
2. Compactação não altera a execução das tools/workflows.
|
||||
3. Context-limit error recebe no máximo um retry compactado.
|
||||
4. A correção é genérica e não contém regra específica do Contas/TIM.
|
||||
9
docs/FIX_REGRESSION_03_05_06_17_20_22_29_20260901.md
Normal file
9
docs/FIX_REGRESSION_03_05_06_17_20_22_29_20260901.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Estabilidade dos cenários 03/05/06/17/20/22/29
|
||||
|
||||
Correções de runtime incluídas:
|
||||
|
||||
1. `invoice_explanation` agora estreita a resposta para um item explicitamente nomeado pelo cliente quando o item é comprovado em `billing_analysis.currentInvoice`. Isso corrige VOD + Canais Abertos sem citar serviços não reclamados e evita falso positivo legítimo do AOFERTA.
|
||||
2. O roteamento do Contas explicita que fragmentos com palavra de domínio mas sem objeto/referente recuperável devem ir para clarificação (`contas_no_match`), em vez de disparar `contas_invoice_explanation`.
|
||||
3. O primeiro no-match após uma fronteira operacional concluída vira uma nova interação neutra (`contas_post_terminal_reentry`) em vez de tentar retomar fluxo antigo ou responder como erro.
|
||||
4. `TimResponseQualityJudge` normaliza corretamente o contrato de score 0..10. Antes, score `1` era interpretado como `1.0` em escala 0..1 e passava indevidamente o threshold.
|
||||
5. A correção anterior que dá precedência ao encerramento explícito sobre `contas_no_match` permanece preservada.
|
||||
17
docs/FIX_STALE_PENDING_WRITE_CHECKPOINT_20260901.md
Normal file
17
docs/FIX_STALE_PENDING_WRITE_CHECKPOINT_20260901.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Fix: stale pending writes cannot roll back the latest LangGraph checkpoint
|
||||
|
||||
## Problem
|
||||
`RepositoryCheckpointSaver.aput_writes()` used the latest full checkpoint payload, appended pending writes and persisted that payload as a new checkpoint row. Because the repository is append-only, an `aput_writes()` from an older super-step could finish after a newer `aput()` and become the newest database row. The next request would then restore an older transaction state.
|
||||
|
||||
Observed symptom in a single session:
|
||||
- turn N opens a new transaction and asks for confirmation;
|
||||
- turn N+1 restores an older completed transaction;
|
||||
- a standalone confirmation such as `sim` is routed to no-match.
|
||||
|
||||
## Fix
|
||||
`aput_writes()` now compares `config.configurable.checkpoint_id` with the durable latest checkpoint id. If the write belongs to an older checkpoint, it is ignored instead of re-persisting the stale full checkpoint as latest.
|
||||
|
||||
Writes for the actual latest checkpoint continue to be persisted normally.
|
||||
|
||||
## Invariant
|
||||
For a thread/session, checkpoint ordering is monotonic: a delayed pending write may enrich its own checkpoint, but it must never make a previous checkpoint become the session's latest state.
|
||||
19
docs/FIX_TEST24_AOFERTA_HTTPX_LIFECYCLE_20260901.md
Normal file
19
docs/FIX_TEST24_AOFERTA_HTTPX_LIFECYCLE_20260901.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Teste 24 — contexto AOFERTA e lifecycle do cliente HTTP
|
||||
|
||||
## Problemas corrigidos
|
||||
|
||||
1. A resposta terminal de cancelamento parcial era corretamente produzida pelo workflow, porém o TIM_AOFERTA podia receber um contexto JSON enorme truncado antes das evidências relevantes do pedido. Isso fazia a orientação de canal alternativo para o mesmo alvo ser julgada como ação não solicitada.
|
||||
2. O bridge síncrono de guardrails executava um provider temporário dentro de `asyncio.run()`. O `AsyncOpenAI`/httpx associado podia sobreviver ao loop e tentar fechar conexões após o loop ter sido encerrado, gerando `Task exception was never retrieved` / `RuntimeError: Event loop is closed`.
|
||||
|
||||
## Correções
|
||||
|
||||
- `TimProactiveOfferRail` usa contexto compacto e autoritativo com histórico recente, pedido/resolução transacional e resultado atual da execução. Não existe bypass para estado `COMPLETED`: o LLM continua julgando semanticamente e ainda pode bloquear alvo/ação realmente novos.
|
||||
- O prompt AOFERTA explicita que evidência estruturada do alvo solicitado/resolvido e da falha parcial é autoritativa para continuidade no mesmo alvo.
|
||||
- Providers OpenAI-compatible ganharam `aclose()` explícito para todos os clientes cacheados.
|
||||
- `classify_with_framework_llm()` identifica providers temporários criados internamente e os fecha no mesmo event loop, em `finally`; providers fornecidos pelo caller continuam sob responsabilidade do caller.
|
||||
|
||||
## Testes
|
||||
|
||||
- lifecycle + TIM_AOFERTA: 22 PASS
|
||||
- cancelamento/guardrails correlatos: 198 PASS
|
||||
- `tests/migration`: 830 PASS / 2 FAIL históricos não relacionados.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Fix TIM_AOFERTA - continuidade por canal alternativo
|
||||
|
||||
## Problema
|
||||
O TIM_AOFERTA classificava como oferta proativa uma orientação de canal alternativo para concluir a mesma ação transacional que o cliente já havia solicitado, após execução parcial/falha no canal atual.
|
||||
|
||||
## Correção
|
||||
O prompt do guardrail foi ajustado semanticamente, mantendo decisão via LLM e sem hardcodes de frases, regex ou nomes de serviços. A nova regra estabelece que orientar como concluir a mesma ação, no mesmo alvo e escopo já solicitado, por outro canal oficial, é continuidade do pedido e deve ser permitido. Continua bloqueada qualquer orientação que introduza nova ação, novo alvo ou amplie o escopo do pedido.
|
||||
|
||||
## Arquivos
|
||||
- `app/extensions/tim_prompts/ausencia_oferta_proativa.py`
|
||||
- `agent_framework_oci/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/ausencia_oferta_proativa.py`
|
||||
- `tests/migration/original_test_ausencia_oferta_proativa.py`
|
||||
|
||||
## Testes
|
||||
- 19/19 testes direcionados AOFERTA
|
||||
- 57/57 regressão cancelamento múltiplo/adversarial
|
||||
- 824 PASS / 2 FAIL em `tests/migration`
|
||||
- Os 2 FAIL são preexistentes: contestação histórica TIM Fashion Mensal/R$50 e fraseologia `termino_desconto`.
|
||||
39
docs/FIX_TRANSACTION_STATUS_AND_PREVALIDATED_VAS_20260901.md
Normal file
39
docs/FIX_TRANSACTION_STATUS_AND_PREVALIDATED_VAS_20260901.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Correção cirúrgica — status transacional e VAS pré-validado
|
||||
|
||||
## Escopo
|
||||
|
||||
Esta correção parte da versão estável anterior à expansão de `terminal outcomes` e altera apenas dois contratos já existentes.
|
||||
|
||||
### 1. `active_transaction` e `transaction_status` não podem divergir
|
||||
|
||||
`AgentRuntimeMixin._set_active_transaction()` agora atualiza também `state["transaction_status"]` com o mesmo `status` da transação instalada.
|
||||
|
||||
Isso evita que um status terminal da operação anterior (`COMPLETED`, por exemplo) sobreviva à criação de uma nova transação em `AWAITING_CONFIRMATION`. Sem essa invariável, o boundary do turno seguinte pode interpretar a nova confirmação como resíduo da transação encerrada e limpar seus latches antes do roteamento.
|
||||
|
||||
Não foi criada regra para a palavra `sim`, nem bypass de roteamento.
|
||||
|
||||
### 2. VAS estratégico reutiliza resolução já validada
|
||||
|
||||
`validar_vas_subject` já é o resolver autoritativo side-effect-free na fronteira transacional. Quando ele resolve um VAS e redireciona a ação para `tratar_vas_estrategico`, os `resolved_arguments` agora carregam:
|
||||
|
||||
- `subject` canônico;
|
||||
- `_vas_subject_prevalidated=true`;
|
||||
- `type` quando conhecido (`bundle`/`estrategico`).
|
||||
|
||||
Na execução da tool estratégica, `_preflight_subject()` não executa uma segunda resolução por `invoice_evidence` quando esse marcador está presente. Isso evita o caso em que `Aya Audiobooks Premium` era `ELIGIBLE` na pré-validação e depois virava `NEEDS_PARAMETER / subject_not_resolved` ao executar a tool efetiva.
|
||||
|
||||
## O que não foi alterado
|
||||
|
||||
- `agent_graph` e reset global de contexto;
|
||||
- route stickiness;
|
||||
- confirmation classifier;
|
||||
- estados terminais globais;
|
||||
- idempotência;
|
||||
- guardrails;
|
||||
- fluxo de múltiplos VAS.
|
||||
|
||||
## Testes
|
||||
|
||||
- testes direcionados novos + relacionados: 16 PASS;
|
||||
- VAS/transação/cancelamento/conversation policy: 420 PASS;
|
||||
- suíte `tests/migration`: 833 PASS / 2 FAIL históricos já existentes e não relacionados.
|
||||
19
docs/FIX_VLOOP_TRANSACTION_CONFIRMATION_BYPASS_20260901.md
Normal file
19
docs/FIX_VLOOP_TRANSACTION_CONFIRMATION_BYPASS_20260901.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# VLOOP: bypass para confirmação transacional
|
||||
|
||||
## Problema
|
||||
|
||||
Mensagens curtas como `sim` podem aparecer legitimamente várias vezes na mesma sessão, uma vez para cada transação. O VLOOP usava apenas repetição textual no histórico e podia bloquear uma confirmação válida em `AWAITING_CONFIRMATION`.
|
||||
|
||||
## Correção
|
||||
|
||||
O rail `VLOOP` agora permite a entrada quando o estado transacional atual é `AWAITING_CONFIRMATION`. O status é lido de `transaction_status` e, como fallback, de `active_transaction.status`.
|
||||
|
||||
A interpretação de `sim`/`não` continua sendo responsabilidade do runtime/classificador de confirmação. O bypass apenas impede que VLOOP intercepte a entrada antes dessa decisão.
|
||||
|
||||
Fora de `AWAITING_CONFIRMATION`, a detecção original de repetição continua inalterada.
|
||||
|
||||
## Validação
|
||||
|
||||
- 3 testes específicos do bypass: PASS
|
||||
- 71 testes de guardrails/transações/confirmação: PASS
|
||||
- suíte migration: 845 PASS / 2 FAIL históricos já existentes
|
||||
22
docs/FIX_WORKFLOW_EXECUTION_ID_TRANSACTION_SCOPE_20260901.md
Normal file
22
docs/FIX_WORKFLOW_EXECUTION_ID_TRANSACTION_SCOPE_20260901.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Workflow execution ID por transação
|
||||
|
||||
## Contrato
|
||||
|
||||
`workflow_execution_id` pertence à execução de workflow da transação ativa, não à sessão.
|
||||
|
||||
- Nova transação que inicia workflow: nova execução (`WorkflowRuntime.arun(..., execution_id=None)` gera UUID novo).
|
||||
- Mesmo workflow pausado: `retomar_workflow` reutiliza o `execution_id` via `aresume`.
|
||||
- Transação encerrada: o ID permanece apenas como histórico/evidência e não pode iniciar outra execução.
|
||||
- Uma nova transação não herda `transaction_id` nem `workflow_execution_id` de estado terminal anterior.
|
||||
|
||||
## Alterações
|
||||
|
||||
- `contas_mcp/.../main.py`: chamadas que iniciam workflow removem `workflow_execution_id` residual e deixam `WorkflowRuntime` gerar um ID novo.
|
||||
- `retomar_workflow`: permanece o único caminho que reutiliza ID existente.
|
||||
- `agent_runtime.py`: `_set_active_transaction` só reutiliza `transaction_id` de transação realmente ativa e remove `workflow_execution_id` residual ao abrir uma nova transação.
|
||||
|
||||
## Testes
|
||||
|
||||
- 4 testes específicos do contrato: PASS.
|
||||
- 95 testes de workflows/transações/cancelamento relacionados: PASS.
|
||||
- Suite `tests/migration`: 837 PASS / 2 FAIL históricos não relacionados.
|
||||
Reference in New Issue
Block a user