From f4638e287aad3790b80d1fb4ed9d80a6b875183a Mon Sep 17 00:00:00 2001 From: T3782834 Date: Tue, 1 Sep 2026 11:23:22 -0300 Subject: [PATCH] ajuste no contas --- .../__pycache__/__init__.cpython-313.pyc | Bin 411 -> 412 bytes .../__pycache__/extensions.cpython-313.pyc | Bin 2139 -> 2140 bytes .../gateway_policy_context.cpython-313.pyc | Bin 1453 -> 1453 bytes .../__pycache__/idempotency.cpython-313.pyc | Bin 5695 -> 8913 bytes .../__pycache__/observer.cpython-313.pyc | Bin 17555 -> 17556 bytes ...untime_mcp_gateway_adapter.cpython-313.pyc | Bin 2150 -> 2150 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 547 -> 548 bytes .../composite_publisher.cpython-313.pyc | Bin 2502 -> 2503 bytes .../__pycache__/event_builder.cpython-313.pyc | Bin 1260 -> 1261 bytes .../__pycache__/factory.cpython-313.pyc | Bin 3996 -> 3997 bytes .../__pycache__/publisher.cpython-313.pyc | Bin 1872 -> 1873 bytes .../tim_payload_mapper.cpython-313.pyc | Bin 9286 -> 9287 bytes .../__pycache__/tim_sequence.cpython-313.pyc | Bin 17561 -> 17562 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 514 -> 515 bytes .../__pycache__/kafka.cpython-313.pyc | Bin 1812 -> 1813 bytes .../__pycache__/langfuse.cpython-313.pyc | Bin 23172 -> 23173 bytes .../__pycache__/oci_streaming.cpython-313.pyc | Bin 1821 -> 1822 bytes .../__pycache__/pubsub.cpython-313.pyc | Bin 7440 -> 7441 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 403 -> 404 bytes .../usage_repository.cpython-313.pyc | Bin 15686 -> 15687 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 213 -> 214 bytes .../cache/__pycache__/cache.cpython-313.pyc | Bin 16523 -> 16524 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 216 -> 217 bytes .../__pycache__/adapters.cpython-313.pyc | Bin 4172 -> 4173 bytes .../channels/__pycache__/base.cpython-313.pyc | Bin 1796 -> 1797 bytes .../__pycache__/gateway.cpython-313.pyc | Bin 5771 -> 5772 bytes .../__pycache__/interruption.cpython-313.pyc | Bin 6456 -> 6457 bytes .../__pycache__/transcription.cpython-313.pyc | Bin 1429 -> 1430 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 923 -> 924 bytes .../checkpoint_repository.cpython-313.pyc | Bin 27163 -> 27164 bytes .../langgraph_saver.cpython-313.pyc | Bin 32222 -> 33266 bytes .../checkpoints/langgraph_saver.py | 30 ++- .../__pycache__/__init__.cpython-313.pyc | Bin 214 -> 215 bytes .../agent_registry.cpython-313.pyc | Bin 6947 -> 6948 bytes .../__pycache__/settings.cpython-313.pyc | Bin 13789 -> 13790 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 176 -> 176 bytes .../__pycache__/oci_streaming.cpython-313.pyc | Bin 3280 -> 3280 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 306 -> 307 bytes .../mcp_gateway_client.cpython-313.pyc | Bin 3332 -> 3333 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 682 -> 682 bytes .../__pycache__/client.cpython-313.pyc | Bin 4572 -> 4572 bytes .../__pycache__/config.cpython-313.pyc | Bin 5007 -> 5007 bytes .../__pycache__/models.cpython-313.pyc | Bin 4500 -> 4500 bytes .../__pycache__/router.cpython-313.pyc | Bin 14147 -> 14147 bytes .../__pycache__/session_store.cpython-313.pyc | Bin 3491 -> 3491 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 1502 -> 1502 bytes .../__pycache__/base.cpython-313.pyc | Bin 1376 -> 1376 bytes .../__pycache__/config_loader.cpython-313.pyc | Bin 9161 -> 9161 bytes .../__pycache__/custom_rails.cpython-313.pyc | Bin 4405 -> 4405 bytes .../__pycache__/executor.cpython-313.pyc | Bin 315 -> 315 bytes .../framework_llm_client.cpython-313.pyc | Bin 17784 -> 19674 bytes .../langgraph_adapters.cpython-313.pyc | Bin 3783 -> 3783 bytes .../__pycache__/llm_rails.cpython-313.pyc | Bin 5924 -> 5924 bytes .../output_supervisor.cpython-313.pyc | Bin 24307 -> 24307 bytes .../parallel_executor.cpython-313.pyc | Bin 21863 -> 21863 bytes .../__pycache__/pipeline.cpython-313.pyc | Bin 10890 -> 10890 bytes .../__pycache__/rail_action.cpython-313.pyc | Bin 655 -> 655 bytes .../__pycache__/rail_decision.cpython-313.pyc | Bin 1606 -> 1606 bytes .../__pycache__/rail_result.cpython-313.pyc | Bin 1005 -> 1005 bytes .../__pycache__/rails.cpython-313.pyc | Bin 41640 -> 42854 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 2995 -> 2995 bytes .../__pycache__/_compat.cpython-313.pyc | Bin 2446 -> 2446 bytes .../__pycache__/config.cpython-313.pyc | Bin 7629 -> 7629 bytes .../contestation_validation.cpython-313.pyc | Bin 2178 -> 2178 bytes .../__pycache__/contracts.cpython-313.pyc | Bin 6902 -> 6902 bytes .../__pycache__/input_size.cpython-313.pyc | Bin 3650 -> 3650 bytes .../__pycache__/llm_adapter.cpython-313.pyc | Bin 3800 -> 3800 bytes .../__pycache__/llm_client.cpython-313.pyc | Bin 7455 -> 7455 bytes .../__pycache__/llm_rails.cpython-313.pyc | Bin 8895 -> 8895 bytes .../output_sanitization.cpython-313.pyc | Bin 13911 -> 13911 bytes .../__pycache__/pipeline.cpython-313.pyc | Bin 12662 -> 12662 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 474 -> 474 bytes .../__pycache__/_context.cpython-313.pyc | Bin 5872 -> 5872 bytes .../ausencia_oferta_proativa.cpython-313.pyc | Bin 11266 -> 12206 bytes .../__pycache__/coerencia.cpython-313.pyc | Bin 4158 -> 4158 bytes .../__pycache__/dlex_in.cpython-313.pyc | Bin 1305 -> 1305 bytes .../__pycache__/dlex_out.cpython-313.pyc | Bin 1816 -> 1816 bytes .../__pycache__/fallback.cpython-313.pyc | Bin 17653 -> 17653 bytes .../__pycache__/fraseologia.cpython-313.pyc | Bin 7634 -> 7634 bytes .../__pycache__/out_of_scope.cpython-313.pyc | Bin 17494 -> 17494 bytes .../prompts/__pycache__/pinj.cpython-313.pyc | Bin 8425 -> 8425 bytes .../__pycache__/ragsec.cpython-313.pyc | Bin 1121 -> 1121 bytes .../__pycache__/revprec.cpython-313.pyc | Bin 5412 -> 3151 bytes .../__pycache__/safe_out.cpython-313.pyc | Bin 1004 -> 1004 bytes .../prompts/__pycache__/tox.cpython-313.pyc | Bin 645 -> 645 bytes .../toxicidade_output.cpython-313.pyc | Bin 929 -> 929 bytes .../prompts/ausencia_oferta_proativa.py | 13 ++ .../guardrails/calibrated/prompts/revprec.py | 118 ++++-------- .../__pycache__/__init__.cpython-313.pyc | Bin 606 -> 606 bytes .../supervision_template.cpython-313.pyc | Bin 2190 -> 2190 bytes .../__pycache__/tts_rules.cpython-313.pyc | Bin 1140 -> 1140 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 1664 -> 1664 bytes .../rails/__pycache__/alcada.cpython-313.pyc | Bin 5000 -> 5000 bytes .../rails/__pycache__/anatel.cpython-313.pyc | Bin 9149 -> 9149 bytes .../__pycache__/confirmation.cpython-313.pyc | Bin 11043 -> 11043 bytes .../rails/__pycache__/dlex_in.cpython-313.pyc | Bin 3280 -> 3280 bytes .../__pycache__/dlex_out.cpython-313.pyc | Bin 3332 -> 3332 bytes .../rails/__pycache__/ragsec.cpython-313.pyc | Bin 5463 -> 5463 bytes .../rails/__pycache__/revprec.cpython-313.pyc | Bin 5471 -> 5471 bytes .../rails/__pycache__/tox.cpython-313.pyc | Bin 8294 -> 8294 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 5725 -> 5725 bytes .../correspondencia_item.cpython-313.pyc | Bin 9226 -> 9226 bytes .../__pycache__/groundedness.cpython-313.pyc | Bin 8659 -> 8659 bytes .../intencao_cancelar.cpython-313.pyc | Bin 9376 -> 9376 bytes .../quantidade_coerente.cpython-313.pyc | Bin 9246 -> 9246 bytes .../servico_correto.cpython-313.pyc | Bin 9047 -> 9047 bytes .../verbalizacao_prematura.cpython-313.pyc | Bin 8595 -> 8595 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 534 -> 534 bytes .../rules/__pycache__/alcada.cpython-313.pyc | Bin 1882 -> 1882 bytes .../__pycache__/oos_blocklist.cpython-313.pyc | Bin 3022 -> 3022 bytes .../__pycache__/pinj_patterns.cpython-313.pyc | Bin 3731 -> 3731 bytes .../__pycache__/tox_blocklist.cpython-313.pyc | Bin 1507 -> 1507 bytes .../guardrails/framework_llm_client.py | 61 +++--- .../src/agent_framework/guardrails/rails.py | 37 +++- .../src/agent_framework/idempotency.py | 73 +++++++- .../__pycache__/__init__.cpython-313.pyc | Bin 408 -> 409 bytes .../__pycache__/mcp_mapper.cpython-313.pyc | Bin 4692 -> 4693 bytes .../__pycache__/models.cpython-313.pyc | Bin 3144 -> 3145 bytes .../__pycache__/resolver.cpython-313.pyc | Bin 4713 -> 4714 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 618 -> 619 bytes .../judges/__pycache__/judge.cpython-313.pyc | Bin 37576 -> 41126 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 225 -> 226 bytes .../__pycache__/_compat.cpython-313.pyc | Bin 2227 -> 2227 bytes .../__pycache__/llm_client.cpython-313.pyc | Bin 5404 -> 5405 bytes .../__pycache__/models.cpython-313.pyc | Bin 900 -> 900 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 233 -> 234 bytes .../prompts/__pycache__/aluc.cpython-313.pyc | Bin 6529 -> 6530 bytes .../prompts/__pycache__/csi.cpython-313.pyc | Bin 1332 -> 1333 bytes .../__pycache__/fallback.cpython-313.pyc | Bin 8035 -> 8036 bytes .../prompts/__pycache__/rqlt.cpython-313.pyc | Bin 1165 -> 1166 bytes .../prompts/__pycache__/vctn.cpython-313.pyc | Bin 626 -> 627 bytes .../src/agent_framework/judges/judge.py | 80 +++++++- .../llm/__pycache__/__init__.cpython-313.pyc | Bin 476 -> 477 bytes .../llm/__pycache__/base.cpython-313.pyc | Bin 1623 -> 1624 bytes .../profile_resolver.cpython-313.pyc | Bin 9322 -> 9323 bytes .../llm/__pycache__/providers.cpython-313.pyc | Bin 45439 -> 46979 bytes .../structured_output.cpython-313.pyc | Bin 7459 -> 7460 bytes .../llm/__pycache__/types.cpython-313.pyc | Bin 1274 -> 1275 bytes .../src/agent_framework/llm/providers.py | 26 +++ .../mcp/__pycache__/__init__.cpython-313.pyc | Bin 473 -> 474 bytes .../mcp/__pycache__/client.cpython-313.pyc | Bin 18426 -> 18427 bytes .../mcp/__pycache__/models.cpython-313.pyc | Bin 2136 -> 2137 bytes .../mcp/__pycache__/registry.cpython-313.pyc | Bin 4740 -> 4741 bytes .../__pycache__/tool_policy.cpython-313.pyc | Bin 5685 -> 5686 bytes .../__pycache__/tool_router.cpython-313.pyc | Bin 14189 -> 14190 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 1135 -> 1136 bytes .../long_term_extractor.cpython-313.pyc | Bin 2513 -> 2514 bytes .../long_term_memory.cpython-313.pyc | Bin 6839 -> 6840 bytes .../long_term_models.cpython-313.pyc | Bin 1748 -> 1749 bytes .../long_term_store.cpython-313.pyc | Bin 29186 -> 29187 bytes .../message_history.cpython-313.pyc | Bin 8359 -> 8360 bytes .../summary_memory.cpython-313.pyc | Bin 12510 -> 12511 bytes .../__pycache__/summary_store.cpython-313.pyc | Bin 9520 -> 9521 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 214 -> 215 bytes .../__pycache__/identity.cpython-313.pyc | Bin 3465 -> 3466 bytes .../__pycache__/session.cpython-313.pyc | Bin 2708 -> 2709 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 1394 -> 1395 bytes .../__pycache__/code_mapper.cpython-313.pyc | Bin 21447 -> 21448 bytes .../__pycache__/context.cpython-313.pyc | Bin 7386 -> 7387 bytes .../control_events.cpython-313.pyc | Bin 2036 -> 2036 bytes .../__pycache__/decorators.cpython-313.pyc | Bin 1747 -> 1747 bytes .../__pycache__/event_bus.cpython-313.pyc | Bin 3632 -> 3633 bytes .../__pycache__/grl_events.cpython-313.pyc | Bin 908 -> 908 bytes .../guardrail_events.cpython-313.pyc | Bin 2050 -> 2051 bytes .../__pycache__/ic_events.cpython-313.pyc | Bin 625 -> 626 bytes .../informational_events.cpython-313.pyc | Bin 427 -> 427 bytes .../__pycache__/judge_events.cpython-313.pyc | Bin 1410 -> 1411 bytes .../langfuse_enterprise.cpython-313.pyc | Bin 3736 -> 3736 bytes .../langgraph_telemetry.cpython-313.pyc | Bin 4963 -> 4964 bytes .../__pycache__/llm_advisors.cpython-313.pyc | Bin 2937 -> 2938 bytes .../__pycache__/noc_contract.cpython-313.pyc | Bin 5074 -> 5075 bytes .../__pycache__/noc_events.cpython-313.pyc | Bin 568 -> 568 bytes .../__pycache__/noc_otel.cpython-313.pyc | Bin 6321 -> 6322 bytes .../__pycache__/observer.cpython-313.pyc | Bin 5104 -> 5105 bytes .../__pycache__/otel.cpython-313.pyc | Bin 3411 -> 3412 bytes .../streaming_events.cpython-313.pyc | Bin 1834 -> 1835 bytes .../streaming_exporter.cpython-313.pyc | Bin 1315 -> 1315 bytes .../__pycache__/telemetry.cpython-313.pyc | Bin 52427 -> 52428 bytes .../tim_backoffice_contract.cpython-313.pyc | Bin 1756 -> 1756 bytes .../__pycache__/token_cost.cpython-313.pyc | Bin 8690 -> 8691 bytes .../workflow_events.cpython-313.pyc | Bin 3329 -> 3330 bytes .../oci/__pycache__/__init__.cpython-313.pyc | Bin 211 -> 212 bytes .../oci/__pycache__/auth.cpython-313.pyc | Bin 3243 -> 3244 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 219 -> 220 bytes .../__pycache__/mongodb_store.cpython-313.pyc | Bin 7641 -> 7641 bytes .../__pycache__/oracle_store.cpython-313.pyc | Bin 44955 -> 45932 bytes .../__pycache__/sqlite_store.cpython-313.pyc | Bin 15018 -> 15019 bytes .../persistence/oracle_store.py | 21 ++- .../__pycache__/__init__.cpython-313.pyc | Bin 454 -> 455 bytes .../__pycache__/renderers.cpython-313.pyc | Bin 4317 -> 4318 bytes .../rag/__pycache__/__init__.cpython-313.pyc | Bin 709 -> 710 bytes .../embedding_provider.cpython-313.pyc | Bin 6516 -> 6517 bytes .../__pycache__/graph_store.cpython-313.pyc | Bin 5527 -> 5528 bytes .../rag/__pycache__/ingest.cpython-313.pyc | Bin 12580 -> 12581 bytes .../__pycache__/kbdb_service.cpython-313.pyc | Bin 10011 -> 10012 bytes .../__pycache__/rag_service.cpython-313.pyc | Bin 10897 -> 10898 bytes .../__pycache__/vector_store.cpython-313.pyc | Bin 18655 -> 18656 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 220 -> 221 bytes .../session_repository.cpython-313.pyc | Bin 8589 -> 8590 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 425 -> 426 bytes .../__pycache__/config_loader.cpython-313.pyc | Bin 2296 -> 2297 bytes .../__pycache__/continuity.cpython-313.pyc | Bin 15933 -> 15934 bytes .../enterprise_router.cpython-313.pyc | Bin 61971 -> 61972 bytes .../__pycache__/models.cpython-313.pyc | Bin 2446 -> 2447 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 348 -> 349 bytes .../__pycache__/agent_runtime.cpython-313.pyc | Bin 178194 -> 185641 bytes .../transaction_input.cpython-313.pyc | Bin 2891 -> 2891 bytes .../transaction_parameters.cpython-313.pyc | Bin 11117 -> 11118 bytes .../agent_framework/runtime/agent_runtime.py | 177 +++++++++++++++++- .../__pycache__/__init__.cpython-313.pyc | Bin 1199 -> 1168 bytes .../authentication.cpython-313.pyc | Bin 15419 -> 15388 bytes .../__pycache__/factory.cpython-313.pyc | Bin 7988 -> 7957 bytes .../__pycache__/installer.cpython-313.pyc | Bin 5606 -> 5575 bytes .../__pycache__/middleware.cpython-313.pyc | Bin 8890 -> 8859 bytes .../sse/__pycache__/__init__.cpython-313.pyc | Bin 211 -> 212 bytes .../sse/__pycache__/events.cpython-313.pyc | Bin 9587 -> 9588 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 218 -> 219 bytes .../router_supervisor.cpython-313.pyc | Bin 373 -> 373 bytes .../__pycache__/supervisor.cpython-313.pyc | Bin 4943 -> 4944 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 878 -> 879 bytes .../__pycache__/graph.cpython-313.pyc | Bin 1415 -> 1416 bytes .../input_contract.cpython-313.pyc | Bin 8790 -> 8791 bytes .../__pycache__/models.cpython-313.pyc | Bin 7669 -> 7670 bytes .../__pycache__/registry.cpython-313.pyc | Bin 2361 -> 2362 bytes .../__pycache__/repository.cpython-313.pyc | Bin 2714 -> 2715 bytes .../__pycache__/runtime.cpython-313.pyc | Bin 36150 -> 36153 bytes .../__pycache__/tool_executor.cpython-313.pyc | Bin 1966 -> 1967 bytes .../src/agent_framework/workflows/runtime.py | 8 +- .../conftest.cpython-313-pytest-9.0.2.pyc | Bin 799 -> 791 bytes ...ession_matrix.cpython-313-pytest-9.0.2.pyc | Bin 52058 -> 52049 bytes tests/test_llm_context_compaction.py | 93 +++++++++ ...pt_controlled.cpython-313-pytest-9.0.2.pyc | Bin 16552 -> 16543 bytes ...untime_config.cpython-313-pytest-9.0.2.pyc | Bin 30682 -> 36366 bytes ...est_langgraph_checkpoint_runtime_config.py | 28 +++ ...st_workflow_terminal_snapshot_semantics.py | 28 +++ 235 files changed, 669 insertions(+), 124 deletions(-) create mode 100644 tests/test_llm_context_compaction.py diff --git a/libs/agent_framework/src/agent_framework/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/__pycache__/__init__.cpython-313.pyc index 6d3794049acb00bf7f2770796992b067a3a0a8ac..dd2ef206b629071b9100effdd8bc62016e5b34f0 100644 GIT binary patch delta 36 qcmbQuJcpV4GcPX}0}zCroi>sCJx{)VZeEFgvc6++Y4K!M#%Tb-5eq2* delta 35 ocmbQkJe!&OGcPX}0|-2rI+6Q5cby_TE%GcPX}0}u#YnY5965i0;Vf(2{< delta 20 acmZ3>y_TE%GcPX}0}wplIdLQRB31xByap!# diff --git a/libs/agent_framework/src/agent_framework/__pycache__/idempotency.cpython-313.pyc b/libs/agent_framework/src/agent_framework/__pycache__/idempotency.cpython-313.pyc index 8a37c45ad9a7c12457c9d6df51a048eb8a266bf6..7c1f07aa6f5469aead0953ba621e46835b350a85 100644 GIT binary patch literal 8913 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 delta 39 scmbQz$vC-_k^3_*FBby{JeazXJDrU?Pd_)WL_bB}H`sG?9h;aP0N!5md|a6OGcPX}0}zCtowkvCITKHder{fgezLw}acS}9y-b|!0OSA*;s5{u delta 37 rcmX>ud`y`8GcPX}0}wDhn7WaBITLrYer{fgeu}cae|#GcPX}0}zCtowkwt5ED<8er{fgezLw}acS}98%z}}0O&Ogga7~l delta 37 rcmcb}cY%-lGcPX}0}wDhn7Wbs5EFN$er{fgeu}jFG!ZKR2&LKSkd+*mH9)<1Qrt+TIJj diff --git a/libs/agent_framework/src/agent_framework/analytics/__pycache__/tim_sequence.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/__pycache__/tim_sequence.cpython-313.pyc index 2abecba19cf5fd47c3ae8d9f1be41578061d9c28..526cd36a24b2909ec3dec934da9e6fef5fd759b2 100644 GIT binary patch delta 40 ucmbQ)$vCT%k^3_*FBbz4grA+Zk(-f)r&d2VuS7pt-?6x~c(XW5lLG+lFbmlL delta 39 tcmbQ$$vCrX=362%*)Hg00c}Arf%f6XXI|u&&?~*Pto@c_M9BXxE27VX$kNE diff --git a/libs/agent_framework/src/agent_framework/analytics/providers/__pycache__/kafka.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/providers/__pycache__/kafka.cpython-313.pyc index a2c34053c98032839884d7dfb15ff5fe81096bc1..b84fe312abf9458fe51dac50a890335db40ba060 100644 GIT binary patch delta 38 scmbQjH@jex9198 diff --git a/libs/agent_framework/src/agent_framework/analytics/providers/__pycache__/langfuse.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/providers/__pycache__/langfuse.cpython-313.pyc index 43b00a01f9fe2c93f697533c21b92c725aeed738..af8601cef6a5c5e6d080229f39fefa22fd34841d 100644 GIT binary patch delta 40 ucmZqK%GkPJ0N9BO=l}o! delta 37 rcmbQoHsCF;BUEZeEFgvc6++Y4OCLvjDa43<>}M delta 34 ocmbQjJeisMGcPX}0}wDhm^zXBF?X4MZeEFgioS2K=fq#L0HhoX6#xJL diff --git a/libs/agent_framework/src/agent_framework/billing/__pycache__/usage_repository.cpython-313.pyc b/libs/agent_framework/src/agent_framework/billing/__pycache__/usage_repository.cpython-313.pyc index 4854b890f046b3cccd55dc1ec8a551a9428f024c..8fe711565190e828d5e6ae19e9d406ffaf0e5842 100644 GIT binary patch delta 38 scmX?Bb-arEGcPX}0}zCrowkuXkDaGpKR2&LKUv?gxU_h43;Q8c0R2D>DF6Tf delta 37 rcmX?Jb*zf}GcPX}0}wDhn7WZWkDa?tKR2&LKSkd+*mH9$`yo>R=ras7 diff --git a/libs/agent_framework/src/agent_framework/cache/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/cache/__pycache__/__init__.cpython-313.pyc index f6a00c976eac01ceb1405b28db1a4bf55ce995f6..a0808ef17b677bca4bea04f460f20f9e94d9e58c 100644 GIT binary patch delta 35 pcmcc0c#Vr%n5R@fH?KrLS>Lg^w0NRt4*E74EU_YL;kti_aM2LRIV3abDB diff --git a/libs/agent_framework/src/agent_framework/channels/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/channels/__pycache__/__init__.cpython-313.pyc index dfa342772fc0caeb7df8d5f9406248919055cd3a..f3fdadf1a0e56bae2959c792d7e91e0e36abd9f9 100644 GIT binary patch delta 35 pcmcb?c$1O)GcPX}0}zCroi>r%n5RNNH?KrLS>Lg^w0NRtKLEP33nl;n delta 34 ocmcb~c!QDqGcPX}0}wDjm^zW$n7dp*H?KrLMc+5rbD~#20I41dG5`Po diff --git a/libs/agent_framework/src/agent_framework/channels/__pycache__/adapters.cpython-313.pyc b/libs/agent_framework/src/agent_framework/channels/__pycache__/adapters.cpython-313.pyc index 13dd9664c6b31a18c3bc2131aac96c92faf999ce..e099198789afb696318821a538114d3e68f42069 100644 GIT binary patch delta 38 scmX@3a8`l)GcPX}0}zCrowkwtEE7+Ker{fgezLw}acS}9$4r^L0PNKatpET3 delta 37 rcmX@Ba7KaqGcPX}0}wDjn7WbsEE9LRer{fgeu}pPN^rpRDg#Tw1(&EBiG*0NR@jU;qFB delta 37 rcmeCt?bhY~%*)Hg00hhrrf%e(&(2+@pPN^rpQ7&@?74Xx`!zlQ#*GVX diff --git a/libs/agent_framework/src/agent_framework/channels/__pycache__/interruption.cpython-313.pyc b/libs/agent_framework/src/agent_framework/channels/__pycache__/interruption.cpython-313.pyc index 1708c0f92550dd10ba69609bcf8a3eeb7f84936c..f51d600e8163d915c377dcad1592b25e077ba070 100644 GIT binary patch delta 38 scmdmCw9|lXmM()qNyj%=G5O#LjMs8(ho(}!oyb}FneaGU`;?0)KkJ11LbPYuS delta 39 tcmbPpg>m*3M()qNyj%=G!2Dq9Ms8(h?som$yb}Esecxcu%~s5h(g5>U3{e08 diff --git a/libs/agent_framework/src/agent_framework/checkpoints/__pycache__/langgraph_saver.cpython-313.pyc b/libs/agent_framework/src/agent_framework/checkpoints/__pycache__/langgraph_saver.cpython-313.pyc index fff33effd8ce0f0d26ebc5ad92b2d696eb79e7e2..2c808c8d433c84d649e120f6f213034fe636363b 100644 GIT binary patch delta 2301 zcmaJ?YfMvD96#r__qMl>OCPrdLFfZ4R5yws@r47N0zTFX%@u?NETu&rRwzXQx3Oum zV2F$EB#PNX%sz}I`@ll7eKXE|*p?`3SCUr7j9<27AC|!|f-}>db4#U6w)5eC|Igq5 zasDUw{uB7;d5T+9s}%sBqj#@#?hk&!O;M_Ij+23q!|SN*>+hSoLw)I`-jkupFh}c}? znp)TurBZ_{QKVFoFsxJ}Yb6NkI%MJivC)WJnI9;c_XJ;04w#&&TZlG?SK%&FRTdA=wtY zF?lT*gIO2jZbxz;>tbMYDh9hAhEkEtlDK91Gu&aK1XJe*sX!+L!>ZfrhKO!TMG;6g zE6#XzV`zMdiSYHDQis0H1>IyJRCpm&t78;Y$>Q(`6k_=s*3Jp4k-0N>w_2d~z~r^G z;nACc1L#4`VF3EE)bmHmeAAMc0ga%p%R+B;rVn#X_zn_B0ChP@e)TJ8+?*icfICg# zI8Y)@*)}eT=hp110l=-@DRt`#rAe(ByygTzNtXVeTTObv8Msws!lAH-Hdxl`h}3Wl z6?U0i5~s`pnsiCK40u%H4$}fdo{1{5!F|O{7eX`F?b!hy0e*I zF>BYNGu_tL)j?lxzppRkYisfP+h>g_;;DeYqrE@qY3=p}KgJQWOt&Y5U1zn4Z;SVY z&)d~=sv{7ZbhM%I?gCbeBhBQXJKYC|4@&^}4ZIEJ_?)rRQQkJf&Sm6JFwqRh zhZ4G;SqqV`A&_JweFj6%*o*lCkM=ZsYugqBX&I3?E?WMx4KZtT#M&IS9uLb+^AyW+@hsEz@@uH%q<*-83fDDZ zko{COg+BsSPc2{xHc%r~4|$+6Uh;p~7E|W_sLXw+1AD6Bt<&EQeLWPeYmQd8%y@jU zGJmAZKhAurxS^ORn=$VQcL&0%?73W9Tw}bdxU3i}k7~9o0g2Wa*XPCb1rdG01RvEG zE=jQJL8Bq-YUAa`ae35Wj~N^jbuoThgx@yV9Od`L_=De3F}*9IcZH9%MD@p)XdE)n z0N%LB(s|sH0;KU5e5392N}#qp;()f`K3@>$w?z3@A83qILno);a5V*tm2i13En^YL zSnff#EuNVl&oRe0=ESXe3rfbwjaJP|u<5UbeH36zANL)=mvpYO+(pCNRE~2qxNU~c zeCchAmhi=g9M~{zfi8)3+Da2XA7aDwW}OR2rpqKmQw}lz1CY9C3G~uvp`J&Rrv$i+ zn4T8+F7o&Mr2HEv2|gv{89Lls0WYA7y>k?Vs4KV~zK=c$4&YzZ#y(rI3}PQ~$wf}w zZ-(f8A;E;RL-94(<%t&{L!rLinWBrBMC8OwBKHh^-&d0N-)4d;C-^KfhXmC!k)IGk zLG(_j3|>MvLp8DkkS=|6l$uiYzbt_ov}<59roMr#G>=2a&<6w8A&Yhon$lSUm4@T( z(x8>V5FTUq4%!*fCPU+cJFxS;!4gc>L#E->5V7$@2mvA^z(C>T})eL82-M~b546W{hR$kT4y7xO{_Ex(Bc2HiBvOH%z!Op=_bqed1jBOV`U@W3 zgJjgskjn!$^3n4)@_AovgB77_By%x6SimFWFfOnl3L**Dvk5*X6cifeNvFXTJc_%H zBNQ`faz|H~DR7yWbh|0tT+(hKU3+b0I#@>5f-Vw_v!)$drOaj&Wt3JESOP?@(wM%9^0967|! zRB^z4mhWG>yxH*n!UdvUIM>_Hti zlIZvzieuvqoRwBil26B{F-O`mUW&<#gW}5>zsP|rG(k6FD&r;jjGabqXF?QfCLp(Y z!jUayv5MNP1uoyLs$FhTeUMgCf%)0OMAT+C9Fz$N@yat$pw9Fvuwv5QqPVpd7MiN+ zUr|VYJqxWlv$ws_wxS0c_@XOj3O^bS4kUYq`%fNH>^a}$MO@y;;PTn(&J5NOb diff --git a/libs/agent_framework/src/agent_framework/checkpoints/langgraph_saver.py b/libs/agent_framework/src/agent_framework/checkpoints/langgraph_saver.py index 18dac4a..2ca31b4 100644 --- a/libs/agent_framework/src/agent_framework/checkpoints/langgraph_saver.py +++ b/libs/agent_framework/src/agent_framework/checkpoints/langgraph_saver.py @@ -570,18 +570,42 @@ class RepositoryCheckpointSaver(BaseCheckpointSaver): async def aput_writes(self, config: dict[str, Any], writes: list[tuple[str, Any]], task_id: str, task_path: str = ""): thread_id = _thread_id(config) + requested_cfg = _durable_config(config) + requested_configurable = requested_cfg.get("configurable") if isinstance(requested_cfg.get("configurable"), dict) else {} + requested_checkpoint_id = str(requested_configurable.get("checkpoint_id") or "").strip() try: - latest = await self.repository.get_latest(thread_id) or {"thread_id": thread_id, "config": _durable_config(config), "checkpoint": {}, "metadata": {}} - except: + latest = await self.repository.get_latest(thread_id) or {"thread_id": thread_id, "config": requested_cfg, "checkpoint": {}, "metadata": {}} + except Exception: latest = { "thread_id": thread_id, - "config": _durable_config(config), + "config": requested_cfg, "checkpoint": {}, "metadata": {}, "pending_writes": [], } if isinstance(latest, dict): + # LangGraph may finish aput_writes() for an older super-step after a + # newer aput() has already persisted the next checkpoint. The + # repository is append-only, so blindly re-putting that older full + # payload would make the stale checkpoint the newest row and the next + # user turn would appear to "go back in time". Pending writes belong + # only to the checkpoint identified by config.checkpoint_id. If the + # durable latest checkpoint has already advanced, never append the + # stale payload as a new latest record. + latest_checkpoint = latest.get("checkpoint") if isinstance(latest.get("checkpoint"), dict) else {} + latest_checkpoint_id = str( + latest.get("checkpoint_id") + or latest_checkpoint.get("id") + or ((latest.get("config") or {}).get("configurable") or {}).get("checkpoint_id") + or "" + ).strip() + if ( + requested_checkpoint_id + and latest_checkpoint_id + and requested_checkpoint_id != latest_checkpoint_id + ): + return # Do not keep extending a persisted RunnableConfig across super-steps. # Rebuild the same canonical config that aget_tuple() will expose. latest["config"] = _canonical_checkpoint_config(latest, config) diff --git a/libs/agent_framework/src/agent_framework/config/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/config/__pycache__/__init__.cpython-313.pyc index 778acb77d1c8c186715303cd1379785ce2f7db7a..c2ae0f81294ca94363cbd776d8a34eaa2172b599 100644 GIT binary patch delta 35 pcmcb{c%6~^GcPX}0}zCroi>r%n5RrXH?KrLS>Lg^w0NRtF95m=3myOf delta 34 ocmcc4c#VOc$H diff --git a/libs/agent_framework/src/agent_framework/events/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/events/__pycache__/__init__.cpython-313.pyc index 4be3b308f3346ebd54d13ee509b2f527bd5a6470..7f8879c5631ef1b02419ef9b27c038adb913f205 100644 GIT binary patch delta 19 ZcmdnMxPg)TGcPX}0}u#anKY4mDF89o1w8-& delta 19 ZcmdnMxPg)TGcPX}0}#B}IdLNQQUEqq1^55} diff --git a/libs/agent_framework/src/agent_framework/events/__pycache__/oci_streaming.cpython-313.pyc b/libs/agent_framework/src/agent_framework/events/__pycache__/oci_streaming.cpython-313.pyc index 28c590a61fd0c4fcc35fc1e30be812e6ba71ce3e..2787c39178342b36d475ed97c56cea574f8e8d64 100644 GIT binary patch delta 20 acmca0c|nrrXiKjw8H?KrLS>Lg^w0Po-Spc@%3x)sy delta 34 ncmdnYw26uPGcPX}0|-2rI+44HyIemvuS7pZ-#6HE;>=k9r0fcg diff --git a/libs/agent_framework/src/agent_framework/gateways/__pycache__/mcp_gateway_client.cpython-313.pyc b/libs/agent_framework/src/agent_framework/gateways/__pycache__/mcp_gateway_client.cpython-313.pyc index e73589762e435e8f36a8407174f5a92632eaa1cd..a661b749a58696e7cefeec919beb367dfeaa480c 100644 GIT binary patch delta 38 scmZpXYL(*t%*)Hg00iM@r)}gu!N}93pPN^rpRDg#Tw1*O9-|sJ0M-Hv%K!iX delta 37 qcmZpbYLVjp%*)Hg00IxDZsb0}$la))n^&TrqVF5*x%ob$8aDvJnF`YY diff --git a/libs/agent_framework/src/agent_framework/global_supervisor/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/global_supervisor/__pycache__/__init__.cpython-313.pyc index 6a97e1d708bcd2348b9cc9645e4e1cffda9601c5..17a4e0e0cf39f4427a4705141ec351d4711a655f 100644 GIT binary patch delta 20 acmZ3*x{8(iGcPX}0}u#ZnY596J`(^pJq1<( delta 20 acmZ3*x{8(iGcPX}0}#B}IdLQRd?o-qa0UK9 diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/__init__.cpython-313.pyc index d3fa4e7a71cc96f834932eefe8903efe8cd52035..d0b2b90738a03416fa836880cb94d155e77983fe 100644 GIT binary patch delta 19 Zcmcb|eUF>#GcPX}0}zCt-N#GcPX}0}!~0ZsfYc3II0n1mgez diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/base.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/base.cpython-313.pyc index 3dbd1ac6f91fb1ceb235abb48c083b17347c1f9a..3609a1ec818bd020954a198184dbeb04a8b1a338 100644 GIT binary patch delta 19 ZcmaFB^?-}(GcPX}0}zCt-N+Tj3IIA71uy^r delta 19 ZcmaFB^?-}(GcPX}0}!~0ZsZDM1pqc01ZMyM diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/config_loader.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/config_loader.cpython-313.pyc index 67e644df39926ad2f47693d7a7b047472971931a..750a7f1f5e827af5e957ed077ceffa4cd70512da 100644 GIT binary patch delta 19 ZcmX@aa2mm(n1nU3* delta 19 Zcmdn0v{i}gGcPX}0}!~0ZsgJy1OPJh1R?+c diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/executor.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/executor.cpython-313.pyc index 9f64e656d0d87cf0a6252aef4ac10ed0a80efa1a..20cae0e92f1d2020b2a8f6cce37ca8a110e48d2c 100644 GIT binary patch delta 20 acmdnZw3~_hGcPX}0}u#anY5AHfDr&VaRmVY delta 20 acmdnZw3~_hGcPX}0}wplIdLPm0V4oCqy@VG diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/framework_llm_client.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/framework_llm_client.cpython-313.pyc index 0a90f41fb591cabe6e207dadeaa881476e2523e7..1c44d7be708b26345ab95b519bf56568302baeda 100644 GIT binary patch delta 3108 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 delta 20 acmX>udt8?LGcPX}0}wplIdLQR9zFm>T?V26 diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/llm_rails.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/llm_rails.cpython-313.pyc index ddedee0ccb4721dec7a0e8dcf7a5d3118fe2617d..3e23168589e04dd8d4421607ae797f85065730f9 100644 GIT binary patch delta 19 ZcmZ3Yw?vQYGcPX}0}zCt-N+>+4gfX^1l9lm delta 19 ZcmZ3Yw?vQYGcPX}0}!~0Zsd{@2LLh*1PuTH diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/output_supervisor.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/output_supervisor.cpython-313.pyc index 370643585eca79bb76f46c1790218d78ca6a6d11..863d19cd864fc7ea77c66ed77dcb98566b17ec1d 100644 GIT binary patch delta 21 bcmeyom+|vnMy}7iyj%=G5Po(e*ULBnTRsP> delta 21 bcmeyom+|vnMy}7iyj%=G;3m3}>t!4OS3m~g diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/parallel_executor.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/parallel_executor.cpython-313.pyc index 8936cb0fd7d98a865b9906cbe2209542a5f8364c..e4bd26ef64c4347c1838419e5787ea09aa1aee86 100644 GIT binary patch delta 21 bcmaF9it+g>My}7iyj%=G5Po(eS8ON%Rf-1J delta 21 bcmaF9it+g>My}7iyj%=G;3m3}D>f7WQH%x- diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/pipeline.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/pipeline.cpython-313.pyc index 892395c349d4c23396f9f15bcefb9ee2a2916d6d..063409316710bad40f31a1e3fff6ba1e1cfb7d1d 100644 GIT binary patch delta 19 ZcmeAQ?F!}k%*)Hg00iM@H*z&-0RT8}1!({P delta 19 YcmeAQ?F!}k%*)Hg00eHL8@U>^05ov~pa1{> diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/rail_action.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/rail_action.cpython-313.pyc index 13d5a9c03b42ee290c0c651ef1306417b2e3b4dd..3dc9f8ef64a804c207612a492fa40ba2b16434ad 100644 GIT binary patch delta 19 ZcmeBY?Puls%*)Hg00iM@H*&Qy0RS##1h4=A delta 19 YcmeBY?Puls%*)Hg00eHL8@XDU04iq#=Kufz diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/rail_decision.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/rail_decision.cpython-313.pyc index 41e348e4cf9be56a7634f18f3b6210c0b4f796be..da395c68e0feffb0012b32daf0c910afd87d1a79 100644 GIT binary patch delta 19 ZcmX@cbBu@UGcPX}0}zCt-N(7Eeh!PY*P@?=lSEE>QyZkLbyLjKO29gL# z(4s~oo+$n#YMNA;8q)LKAV4m!8mEJjXeS4Xlx4;9h^^XfIzA`P71wuQ9;1*AqwOb6m|c z%T69*H(TItaUx79F6^>#jl5k~PEWF3bPNN<*{O$)a8|M?(-^w>9ci=K}~A7)ZxMBlWKQfY3#C{OF5kO+aKfBmO75UO>6+0p82{2y+lVo9$e4M}96y*~A4!-x zlrZ&hQ!pWCBw_BU=|S_n5p&UyxhQB}IASgxGM5I;<%3b>p;56kg&oa}=X^S%+2kDz z{B#!Fbk54{!tlY5B{_PLhuU+)Hq2^BveUeqJhfE7}WGBqE6(rT=tWA zi-H*8)QY^Qcj&~(IXW9xGwSJcoCGfX%%=6~oa*jOZ6=q^o`@rC#LO)dBtDaqcr#a$ z%yC}fh0Ov)^iG8Qm-Xfdui(@@ONcm@5D`$26bEgq4N;;Y_bA6z5K-{zVdy7T(W!sR zoXkC+V;YG@MvHnOeIlMZ;na)KVvIv0j+&#jvC~-DzgKABax@LZKDr!!UzCutv@_G~ z^ZGsBfTzw?_bhu@^0-=a;Y^XmqC_`&B)^Y#)cWgR^Glu|A3uJ)5QY|~6CLE|rN)I* zu!4C{s~OzEP(W;+!$ALxvO!#~$V;AWpjo)Sh=8?7UtyqVTI;=vwv|00oSiIO;S^PL zZePIbw?~3&iiMnnU*{zo(UydDVzojr&(>9oSr)_K4%f|Hi!trU+1l2t38jo5Ny#2c z$v*B5XWBgz7d38h{Oq7{_BC^A$dcHb{{UBS#n zBbj9b(}R=B2k3w_I7tj^p;*<9j z!Kx9<#39SXpvB&62sx%5Ydq3;+;^G=9g7F156l>HR0K_x!;Xr>vG32?Galyj=lA7b zG258DH)7CK2~~4T=T(u1l9@U8c410U0y&$SUS!gq;|nZoLF<^j+^!9mX#-o(Mg+C0 z>)Fh10Poasu}TzHr^nq^?{D(eu~@^Kb;)pLZj2+Hkv4H5qp70gldyvOJijk{HP-e_R!qE2!`7D_(nr_jrc%eqh* zZc$s>vwWieKpA#8+Jo>nNLo@(?!vf^6xg(+g`AbYU*aTjcbHBwx?5e6^u+nQs`G|h zxC!A9yj500ZmF)tmB*5saz^Q@PQByScs6EXs3=V3Bg{+;t7;bVFEx62hmX28xB8;Ap9S1uzN(6rKF%w;Ai zmL|=Ck5(SxlX$tb#;zp`U|nqm!#~!7umIH+P`hTy=n9;w@lZoC44<=(1hSgr$$VJUJdJchNAs}YN3jG|Ei=h_c@smjPBn{F zNmYQqw`TCQXtfwB+7d{Y+}JimVw#ZPLAcHQfr1V3u*z4WZ(|ac1Nm^&mn_U@3uPKq zwpn1x+DQ1;XC|9=wx<&x*xD=8)}q$bud3LPb?G8Rb zU~EfT9Nma?W5DaKr+$~m>+evHodoe~Q^`9pYwZm~Cu2~AE*M9xd}sK~8)+=rCil}` zLbig{-zW63<|f@>X<>#x`R^OH;4Xx1a3Nsjw}f{&*2R;4xp-XzPx|2KYoC+-@@pNn z#IOU|2>tL?rgu*{=Waf(s2F zl+V3gNYd1oy8#7NY}b>EzgxZdsrnM;fM;U{l=Ya&MR4^5#N+q`ymzhE7ijbZ6JNye zBrw&#u_52%_=QAJ(x>m4xkK0<^Yi?N^f!#ey4drNkwiwO0kCgu)SYCy&tTWa>*TU5 zZ91SEt!DYBO!}no$l30kruu~~lfH~F0Rhd>4-oLnMiBz-buNEB z4YGwj7W$T0V0e36xX=#5x7!yA=a73EX20hq!}163&C?i8p#RwAm4m)2Gnm(q8k8y1lv7=T<-Bx~MZK#YIItwRXIP_-+8DLuPV1yx!C1s!AH zlU-J_2rlgEO&nybayx0h|f z{qQ{b9x4x57&aWR37DmHg}mdy88TPBGSp72c2W*iYKKtkPAwy~I@A}czCraJsP12d k?T1zw9|(r~eC&WC)VP^4gj;1=D2UPu)h^s<;Q z$YQEcWf6psemjr0@ObqU;NHve_+C-0*$~oub>IJ{OG*<2ufY|E*%_($uiCf-x6W}+ z5S-xFhm3e|jrD-n_#f>Lgm2ptAKY!=GUN87{|;j){ANh6(H-NCwd>q*&+2pel&t(4 z((e?W(d`7AsV9*~tV>uFZ}dlfnGk0(!_d_k+Jh-7lshh_Qwx4Zp8YcL$fA3txw z`QohlGkR9dJ6RQBGr`Sai)DPV0$W8WAQW;$4Zd(Bq%hiU%`2)4`a`xD)I@_Bun!Nh1| z*cF7Vjp!&dgQV7%Efe7;2FuSwn`)^@1Jg7~2ogFfb6^@5IhJB~r3Cxc*~%G6kD5!i zlvI1F>nfYeoOKn|uG$h$wX;rrr}~JP8`TH-nXp`n@gokKA*%BQWj4gyQKPI#N<>C~ z%|3WVy;n0K;&kzHyy$!?`8GK$A@mbI!5L>AJixjAnOIie0VmY+^m*Fz9)F=_mN#t%wjld|!3%t!!!=wx0qRzG8QOh`?OB<$<>;xyC=vpZ@0zzInCa`p9Qghi9#QR9lO1O7a zkz(6<%cf%v3@8>@kB60Y;KTQn<**CyEA=@+-W^S8mx95FFA$QHKseOQ0&)lI;2j>D z$fw|r*u_r3*>Fx8>m_-7B;@lmMGAzJ9&L&lI33A?7W^u5*A(FjMrgvhZmSs4=9iM> zlG@yUUxWpeg?!nidiD$e9L76)k3dKb_r!zg5V;a|VgEj>cxYj1f8O_0qQXm0G-g9h z`PSy@I&98crrLg5EW*ne*gp}omv_opfX&BjYU_&yU>c%01O<;Du)>h~y91YX;J|}@ zImY$e9DN#J=(FM<`ceV$PM@<7$>B480#Sn!=?wa9Mn)Bt{fflK-ICnlZ;i%wvak~N zg@aLDhrfp%L#aQ_qIgV3!e$WbU2>e|{`0sDv)Fl}FnfYlY5MkE z#5}YmT3tOzai;M1C+wD4-i+!c)+R?|nZGL%U_1%*A!)atxiEP=!+4jp_pxBS6zr-z z{uY>Sl7*0mtKP8k(qHw)mGp-+S}gO@7zRQ);UO-6GuKE7#yo26o0s7^?cG3iRx6EK zCDHD=cA2zmq2)Bwj#E27?F6)y-^5KPn@saO8vh9LIlOrCK|&&!26`R|{O6GsPoBE` EZ-slDIsgCw diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/__init__.cpython-313.pyc index 21efb858d21ad2d69621879002430b15b5a36df0..57f8c4542d823419bc78cb51c051417de7b08ab0 100644 GIT binary patch delta 19 ZcmdlizFC~>GcPX}0}zCt-N?0)8vr&c1xWw^ delta 19 ZcmdlizFC~>GcPX}0}!~0Zsc0Y4FEDM1b_el diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/_compat.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/_compat.cpython-313.pyc index 4708cfe616911e4c77e3f6272997500b3f37a7b4..20682da7bb6f8e411924e7e17ad7331b6034f6c6 100644 GIT binary patch delta 19 ZcmeAZ?i1$v%*)Hg00iM@H*&Rb0st@~1keBg delta 19 YcmeAZ?i1$v%*)Hg00eHL8@XCI0W2g02LJ#7 diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/config.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/config.cpython-313.pyc index 46bd8d0ab38fbff5b07bea4f0830ce0621050086..1e3b36da539b7134df6e694401fdda2fe0ac2b6c 100644 GIT binary patch delta 20 acmX?Web$=$GcPX}0}u#anY5AnkSqX1VFpD2 delta 20 acmX?Web$=$GcPX}0}wplIdLQRAz1)Plm`C* diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/contestation_validation.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/contestation_validation.cpython-313.pyc index bce60815c6de5c69ba929ea8b4592268dbdd8c04..e88ed6e5bd2da5259d7b84913ba03e1d69d22ebd 100644 GIT binary patch delta 19 ZcmZn?Y!c-9%*)Hg00iM@H*!^Q001r(1g8K1 delta 19 YcmZn?Y!c-9%*)Hg00eHL8@Vbt04f&)-T(jq diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/contracts.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/contracts.cpython-313.pyc index 9316b89e5f749fab5365b6386c819854b7a2c03c..2e692edbd55785466e6c15d1c72d616381a30563 100644 GIT binary patch delta 19 Zcmexn`puNkb4Z5kGcPX}0}zCt-Nkb4Z5kGcPX}0}!~0ZsfAy0{}D=1Udi! diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/llm_adapter.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/llm_adapter.cpython-313.pyc index fd4d59d8f7cfe565e743677734375a893dd13f79..9772a2ded6f2e8ceba2122fc7f6a53225d75cfca 100644 GIT binary patch delta 19 Zcmca1dqbA%GcPX}0}zCt-N<#04*)!O1;+pY delta 19 Zcmca1dqbA%GcPX}0}!~0Zsa=02LL#E1pWX3 diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/llm_client.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/llm_client.cpython-313.pyc index 5044c0010d00e1fa0e80b9e8c8e11abdd164ec6e..caf4f1bdbc1451354c860fd3e6bfb3c020094a3d 100644 GIT binary patch delta 19 ZcmbPlHQ$QsGcPX}0}zCt-N+>>3jj9i1myq# delta 19 ZcmbPlHQ$QsGcPX}0}!~0ZsZb`1pqSa1RMYW diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/llm_rails.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/llm_rails.cpython-313.pyc index 156e566959c917871b3950a65c7aeda06f050723..fcdc277ac7b95a90672b7e4ad851d479d2cb1294 100644 GIT binary patch delta 19 Zcmdn*y5E)SGcPX}0}zCt-N?072>?DN1>gVx delta 19 Zcmdn*y5E)SGcPX}0}!~0Zsgjk1OPfG1s4DS diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/output_sanitization.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/output_sanitization.cpython-313.pyc index 164657072d60a4e4304655fae4e18d32d7f53d3b..a36bce592cbe6c0296e9575facd16d35449f8e81 100644 GIT binary patch delta 19 Zcmcbfb3KRaGcPX}0}zCt-N@x@1^`9(1_}TG delta 19 Zcmcbfb3KRaGcPX}0}!~0ZshVc0{}t!1wjA+ diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/pipeline.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/pipeline.cpython-313.pyc index d3208e5e6b31f912e1fc67ac651a80f697bfdcb9..daa206a97acdf592ee3d7a8fa1bf052e5395541c 100644 GIT binary patch delta 19 ZcmeyC^eu_&GcPX}0}zCt-N=<=2mnbq22KC~ delta 19 ZcmeyC^eu_&GcPX}0}!~0Zsf`_1OP=k1%&_r diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/__init__.cpython-313.pyc index f2432c29a61751b053021d7c75068b1e14b4e382..24c0300fb4635484c3c12be9d42734fc314a319d 100644 GIT binary patch delta 19 Zcmcb`e2bauGcPX}0}zCt-N28g^&NM7w*JnH>|+7|~Fp zNC_n+6%wN1C-?&jKEVELmht>Cu zznfoAx7Y4;hJ#6eu-ESf-5xz2j;Iq1f*lHWCcV)hnDqCDTjVqy=S$aSF&olHd169S zs8nZ#ZW2+hBNHhc2~(ID`IvHL6)~mSrA#WBGHFtn)u9g+Q_hyO!@W>tDxp{<2kcuE zn~=Rgnk+Id=gdrXLhLCkXJ(NG6-yy!VdAl~MQmlCveZ15!dkrvNT2=1K~T-3C-ZGfDWhjB?U;1n1Fx5Eg|B|)xG_Gw>RkY z16VZ~?M?PZK{wdKb(LWXs(1#LN5%iTK*k>-lXA1;su~eLki}NxgQ>x^mS>+73eTv@ zq6c@K4>cS{^r!$jq^zXSB2$2@q^>ih4Ve+&Ys~}{&*%+?v=gIq#=$6=#v)ucFvJ%y ztWbrSDiM6L|p1wcP3qLHwA1T(Gh-d-+r#0T;GTrS2yN6 z%eCA0KlSIeM!Wv2zWnymyw<#2pFdf)jVnv@nms<PsKpye8-8adm#b^{0Gq H<=@~Rf^KEt delta 110 zcmZ1%-xR_3nU|M~0SMehr)3ptP2_853ewm(-IjlIgYZ0Q)kr1*)el813~IUyJU=in z=`lWFWNl#kz`(`M_@SI7m5GPt14HU$XMHclG$uxt8O0wMK=g`W2)#r38<<}NvH<|b C1Rbpa diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/coerencia.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/coerencia.cpython-313.pyc index 131939a251faa6dd8d41f03c74d841e2c54a7d9d..f78d1ba0acc9454e37fa4d15068e5014008b1e41 100644 GIT binary patch delta 19 Zcmdm|uup;OGcPX}0}zCt-NLYXP1Xia delta 21 bcmccC!Fa8Mk?S)rFBbz4xQlM&@^JwGN!|sA diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/pinj.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/pinj.cpython-313.pyc index 5d759dfdd23e6b995325ed072129b58acb4585f4..528d2668fa31b5b03e8f9cdf8c38d2f465f9639b 100644 GIT binary patch delta 19 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 diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/safe_out.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/safe_out.cpython-313.pyc index d1787ac553af010e0e221ddb1830bcd9ad911758..2774d2dd128e7c4d40c051d732584a124ad60435 100644 GIT binary patch delta 20 acmaFE{)V0VGcPX}0}u#anY5AnAu|9$&jug> delta 20 acmaFE{)V0VGcPX}0}#B}IdLQRLuLR+2?pB$ diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/tox.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/tox.cpython-313.pyc index 09c1849f02b7b48c74f58ea1615c124a6e9bf4e3..84f78f39621fe372343b03b9b3f0a6dce95186ba 100644 GIT binary patch delta 19 ZcmZo=ZDr;9%*)Hg00iM@H*!@o0RSxN1d;#% delta 19 YcmZo=ZDr;9%*)Hg00i!$8@Z~P04VVT$^ZZW diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/toxicidade_output.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/toxicidade_output.cpython-313.pyc index f49141f04b6cf9ad8dd85ed64594fff3567d77c7..9600db02d704117cf52dd9f357d843c4f6acbcff 100644 GIT binary patch delta 19 ZcmZ3;zL1^kGcPX}0}zCt-N-ea82~X>1nU3* delta 19 ZcmZ3;zL1^kGcPX}0}!~2ZseNI3;-=&1S0?d diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/ausencia_oferta_proativa.py b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/ausencia_oferta_proativa.py index 88d977e..9686035 100644 --- a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/ausencia_oferta_proativa.py +++ b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/ausencia_oferta_proativa.py @@ -62,6 +62,19 @@ Decida na ordem, PARE no primeiro match: mesmo alvo, a fala do agente que apenas pede CONFIRMACAO da transacao e allowed=true. A confirmacao NAO precisa repetir a justificativa do cliente ("nao reconheco", "esta caro" etc.); o pedido transacional anterior basta. + CONTINUIDADE POR CANAL ALTERNATIVO: se a acao transacional foi explicitamente + pedida pelo cliente para o mesmo alvo e a execucao por este canal falhou, ficou + indisponivel ou nao pode ser concluida, orientar o cliente sobre COMO concluir + ESSA MESMA acao em outro canal oficial e allowed=true. Isso nao cria uma nova + oferta: apenas informa o caminho operacional para cumprir o pedido ja existente. + Bloqueie somente se a orientacao introduzir outra acao, outro alvo ou ampliar o + escopo alem do que o cliente pediu. + EVIDENCIA ESTRUTURADA: quando o contexto operacional trouxer alvo solicitado/ + resolvido e resultado da execucao (sucesso, falha parcial, item nao encontrado), + trate esses campos como evidencia autoritativa do pedido atual. Se a resposta + orientar outro canal para o MESMO alvo cuja execucao falhou, allowed=true, mesmo + que a ultima mensagem do cliente seja apenas uma confirmacao como "sim". + Vale tambem trocar uma variante transacional por outra DA MESMA FAMILIA sobre o MESMO escopo, sempre limitada ao valor JA COBRADO no item (ressarcimento <-> devolucao <-> reembolso <-> cancelamento <-> credito em fatura): negar o dobro e diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/revprec.py b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/revprec.py index 52bd28b..7158db3 100644 --- a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/revprec.py +++ b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/revprec.py @@ -1,92 +1,54 @@ -"""Prompt do rail REVPREC — "o agente disse que cancelou algo?". - -Reescrito em 2026-08-06. A versão anterior (207 linhas, algoritmo de 9 passos, saída -`{allowed,label,reason,score}`) julgava PROMESSA FUTURA sem autorização e, por -construção, deixava passar exatamente o caso que interessa: o passo 2 dela dava OK a -"resultado no PASSADO ou PRESENTE". Foi descartada inteira. - -O rail agora responde UMA pergunta binária: a última fala do agente afirma que um -cancelamento / retirada de valor / contestação já aconteceu? - -Por que isso funciona sem falso positivo na ação legítima: o rail só roda quando o -ORQUESTRADOR responde em TEXTO. Quando a ação acontece de verdade, ela vem de uma tool -call — e `apply_output_rails` sai antes dos rails LLM quando há `tool_calls` no turno -(pipeline.py, invariante do early-exit), assim como a fala canônica do -`ResponseComposer` entra com `skip_rails=True`. Ou seja: se esta pergunta chega ao LLM, -o agente está afirmando uma ação que ele NÃO tem tool para executar. - -Saída BINÁRIA com polaridade INVERTIDA em relação a PINJ/COER: aqui `1` = achou a -afirmação = bloqueia; `0` = fala limpa. A pergunta fica na forma positiva ("disse que -cancelou?") porque é ela que dá acurácia; a inversão mora no `llm_client` -(`_BINARY_BLOCK_DIGIT`). - -Duas fronteiras que o prompt precisa manter, e que os casos da suíte travam: - - **histórico**: um cancelamento feito do jeito certo em turno anterior FICA no - histórico e não foi avaliado por este rail; só o bloco "Resposta:" é julgado; - - **protocolo**: o número de protocolo só é emitido depois da tool rodar, então uma - fala que o traz relata execução real → 0. -""" +"""REVPREC: detecta verbalização de resultado operacional sem evidência atual.""" from __future__ import annotations def build_revprec_prompt(text: str, context: str = "") -> str: - """Monta o prompt do rail REVPREC. + """Compara a fala candidata com a evidência estrutural do turno atual. - Args: - text: última fala gerada pelo agente (a que será julgada). - context: histórico já formatado por ``prompts._context.format_context_block`` - (a última fala do agente é PODADA de lá — ela vem em ``text``). - - Returns: - Prompt cuja resposta esperada é um único caractere: ``1`` ou ``0``. + Polaridade: 1 = a fala afirma conclusão/efeito operacional não comprovado ou + contradito pela evidência; 0 = permitido. """ - return f"""Você audita UMA fala do agente de fatura do provedor e responde 1 ou 0. + return f"""Você audita UMA fala de um agente de atendimento TIM. -O agente NÃO executa cancelamento, contestação nem retirada de valor. Quando a ação -acontece de verdade, é o sistema que responde ao cliente — nunca esta fala. Logo, -afirmar aqui que já cancelou/retirou/contestou é sempre falso. +Sua tarefa NÃO é decidir se a frase "soa" como ação concluída. Sua tarefa é comparar +as afirmações da RESPOSTA com a EVIDÊNCIA REAL DO TURNO ATUAL. -ANTES DE TUDO: se a fala traz NÚMERO DE PROTOCOLO — um ou vários, no formato "PRT..." -bruto, vocalizado ("pê erre tê nove cê dois...") ou dígitos depois da palavra protocolo — -responda 0 e pare. O protocolo só é emitido DEPOIS de a ação rodar de verdade; com ele a -fala relata execução real, inclusive quando RECAPITULA cancelamentos já feitos, por mais -concluída que soe. +Responda 1 SOMENTE quando a resposta afirmar que uma ação/efeito operacional já foi +concluído (por exemplo cancelamento, contestação, retirada de valor, crédito, reembolso, +envio ou alteração) e essa conclusão NÃO estiver suportada pela evidência atual, ou +estiver contradita por ela. -Responda 1 quando a fala AFIRMA que um cancelamento, retirada de valor, contestação ou -reembolso JÁ ACONTECEU. Ex.: "cancelamento confirmado", "já foi cancelado", "cancelado -com sucesso", "cancelei o serviço", "retiramos o valor", "sua contestação foi -registrada", "o reembolso já foi processado", "a cobrança não vai mais aparecer porque -removi o serviço". +Responda 0 quando: +- a evidência atual comprova a ação/resultado afirmado; +- a resposta apenas explica dados de fatura, cobrança, desconto, plano, valor, data, + status ou motivo presentes na evidência; +- a resposta pede confirmação/permissão ou solicita parâmetro; +- a resposta anuncia uma ação futura sem afirmar que já ocorreu; +- a resposta nega que a ação ocorreu; +- a resposta expressa ausência de evidência ou incerteza; +- não existe afirmação de conclusão operacional. -Responda 0 em todo o resto. Em particular: -- PERGUNTA ou PEDIDO DE PERMISSÃO, mesmo citando cancelamento: "Podemos seguir com o - cancelamento do serviço X, no valor de R$ 12,00, você confirma?", "Gostaria de - cancelar esse serviço?", "Posso seguir?". -- ESCOPO ou intenção reconhecida, sem ação feita: "Entendi que você deseja falar sobre - os serviços X e Y. Correto?", "Vou verificar isso para você". -- PROMESSA sem afirmar execução: "vou cancelar", "seguiremos com o cancelamento, aguarde - um instante", "o valor será retirado da sua fatura". Aqui a pergunta é se a ação foi - DADA COMO FEITA; anúncio do que vem depois não é. -- DESCRIÇÃO DA FATURA, não ação do agente: "Foi removido um desconto de R$ 6,00", "foi - adicionada a cobrança do X", "esse serviço foi cobrado em duas datas" — isso compara - faturas e explica cobranças; não cancela nada. -- ORIENTAÇÃO a outro canal: "ligue para *144 e solicite o cancelamento", "pelo app do - parceiro você consegue cancelar". -- NEGATIVA de ação: "não consigo cancelar por aqui", "ainda não cancelei", "esse serviço - não pode ser cancelado neste atendimento". -- EXPLICAÇÃO, valor, data, encerramento, saudação, ou qualquer assunto que não seja - ação de cancelamento dada como feita. +REGRAS IMPORTANTES: +1. Use SOMENTE a evidência do bloco EVIDÊNCIA ATUAL para provar execução. Não use + histórico, memória ou suposições. + Julgue somente a fala do bloco "Resposta:"; qualquer texto fora desse bloco é contexto. +2. Se a evidência mostra sucesso/COMPLETED e contém os fatos afirmados, responda 0. +3. Se a evidência mostra falha/erro/não executado e a resposta afirma sucesso, responda 1. +4. Se não existe evidência de execução e a resposta afirma que uma ação transacional já + foi realizada, responda 1. +5. Descrição de algo que aconteceu na conta/fatura (ex.: desconto expirou, cobrança foi + lançada) não é "ação prematura" se isso estiver suportado pelos dados atuais. +6. PROTOCOLO é evidência auxiliar, não regra absoluta: valide junto com a evidência atual. +7. DESCRIÇÃO DA FATURA (cobrança, desconto, data, status, motivo) não é execução de ação + pelo agente quando estiver sustentada pelos dados atuais. -O HISTÓRICO é só contexto. Um cancelamento feito corretamente em turno anterior APARECE -lá e NÃO conta — ele não passou por esta auditoria e não é o que se julga agora. Julgue -somente a fala do bloco "Resposta:". - -------------------------------------{context} -Resposta: +---------------- EVIDÊNCIA ATUAL ---------------- +{context or '[]'} +---------------- RESPOSTA ---------------- {text} ------------------------------------- +-------------------------------------------------- -A fala do bloco "Resposta:" afirma que um cancelamento, retirada de valor ou -contestação já aconteceu? +A RESPOSTA contém alguma afirmação de resultado operacional concluído que NÃO esteja +suportada (ou esteja contradita) pela EVIDÊNCIA ATUAL? -Responda APENAS 1 ou 0, sem mais nada.""" +Responda APENAS 1 ou 0.""" diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/shared/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/shared/__pycache__/__init__.cpython-313.pyc index d5a6bac633c8c73df742da665cd3c00cb2b10bf2..81b6a1f9ab5fcdaa95cbde1965bf92fffc28c267 100644 GIT binary patch delta 20 acmcb|a*u`kGcPX}0}u#anY58Rm=Wev%*)Hg00e?pCT-+y<^TXRj0GP6 delta 20 acmeAZ>=Wev%*)Hg00b{~PTa`d%mDy7#s%5{ diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/shared/__pycache__/tts_rules.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/shared/__pycache__/tts_rules.cpython-313.pyc index 8708f30e65cdd1011a1c51ba2e6f307a2a998ffa..99288c8a63c3a4b09ac698eb1c98912f5469f7fa 100644 GIT binary patch delta 20 acmeyu@r8r?GcPX}0}u#anY58RlLY`mGzGf= delta 20 acmeyu@r8r?GcPX}0}#B}IdLO*CJO*ZZU%M$ diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/__init__.cpython-313.pyc index b332bab4d00cab4250fdd2a81a0bcb8cf3fea6db..679d83d10e29c60713d7d83b41dbf7039be865d1 100644 GIT binary patch delta 19 ZcmZqRZQ$kl%*)Hg00iM@H*%G+0RSyO1eX8+ delta 19 YcmZqRZQ$kl%*)Hg00i!$8@bBZ04YZU&j0`b diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/alcada.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/alcada.cpython-313.pyc index 0d98db377ce5acc6a1a4d2a6fdffbfa69e17b536..5001ab461a8e646449038af40d777a3bbbaa09e6 100644 GIT binary patch delta 19 ZcmeBB?@;IZ%*)Hg00iM@H*(bp0{}7b1n>X= delta 19 YcmeBB?@;IZ%*)Hg00i!$8@cL)0WJ6hC;$Ke diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/anatel.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/anatel.cpython-313.pyc index 31ea4b6ed35ad7daec8311567381ad0e33af15fd..93af9183a3a89a4dd1f21e88e95ec25e8f6823b0 100644 GIT binary patch delta 19 Zcmdn%zSo`WGcPX}0}zCt-N?0B82~;W1>XPw delta 19 Zcmdn%zSo`WGcPX}0}!~2Zsgjm3;;SN1s4DS diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/confirmation.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/confirmation.cpython-313.pyc index 6b3a60ed5cfcb187c8768d5bb785d11b24f88911..5d65f5852881ac4d6431a4c4fba1b6133daf547e 100644 GIT binary patch delta 19 ZcmZ1+wm6LIGcPX}0}zCt-N+@W4FEex1vdZy delta 19 ZcmZ1+wm6LIGcPX}0}!~2Zsd~G1^_ou1aANU diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/dlex_in.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/dlex_in.cpython-313.pyc index 99a2d6d93d74e7fa6d7ed4548077ae4e27813f4c..2d893db11a0d4a7f7744c5eaae535ef28c406c98 100644 GIT binary patch delta 19 Zcmca0c|nrvGcPX}0}zCt-Nr0RS+U1w#M; delta 19 ZcmZpXYLVjl%*)Hg00i!$8@Yb*001nX1bYAg diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/ragsec.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/ragsec.cpython-313.pyc index e62ed4203d02d6511df08bda5482a1847331580f..26340d559a39bb93ce8dd1620f3a304b420c1776 100644 GIT binary patch delta 19 ZcmcbvbzO_=GcPX}0}zCt-N@xD3IIJ41!VvL delta 19 ZcmcbvbzO_=GcPX}0}!~2ZshV61pql31f2i? diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/revprec.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/revprec.cpython-313.pyc index 0de4a468c3e4783adb72d0d20318804a98821f20..19b310af4e6cda8495aed73a38e00d177ae1cc97 100644 GIT binary patch delta 19 Zcmcbwbzh6?GcPX}0}zCt-N+Rx3IIMr1$_Vj delta 19 Zcmcbwbzh6?GcPX}0}!~2ZsZCT1pqoq1hoJF diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/tox.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/tox.cpython-313.pyc index 5af6e2e113010c3d183acb28b51de5c747eb2b39..d82a04f723afe6eeaca9d3c9aded8def5539e6ce 100644 GIT binary patch delta 19 ZcmaFn@XUehGcPX}0}zCt-N+TA002Tm1<3#a delta 19 ZcmaFn@XUehGcPX}0}!~2Zsdwl002Hq1pxp6 diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/supervision/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/supervision/__pycache__/__init__.cpython-313.pyc index 6cc5508963b7d16740c19baea2e6599cfafb135b..da950c0143ad61e8fbbad20cae3607b7179a9e9f 100644 GIT binary patch delta 20 acmcbsb61D^GcPX}0}u#anY58RNDKf&z6H<# delta 20 acmcbsb61D^GcPX}0}#B}IdLO*kQe|+_y&sr diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/supervision/__pycache__/correspondencia_item.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/supervision/__pycache__/correspondencia_item.cpython-313.pyc index aeec1850b964ba166869ea4dc66b0e8662673b45..d6a00dc136f70c36d63d1448914c612a38e8f107 100644 GIT binary patch delta 20 acmeD3=neombGGcPX}0}u#anY5AnFgE}{X9ey6 delta 20 acmX>neombGGcPX}0}#B}IdLQRVQv6Kp$4e{ diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rules/__pycache__/pinj_patterns.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rules/__pycache__/pinj_patterns.cpython-313.pyc index 414c3b868d4160b2590b7ab9556742cef4f6c609..65efbd1a120ab8277effbfec8e31f1a8ae2c8f73 100644 GIT binary patch delta 19 ZcmbO%J6V?NGcPX}0}zCt-N@C+2LLiT1o!{| delta 19 ZcmbO%J6V?NGcPX}0}!~2Zsh9Z0{|{T1TX*q diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rules/__pycache__/tox_blocklist.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rules/__pycache__/tox_blocklist.cpython-313.pyc index 34abe3d0821f855857a4cd8e247ed7c93f4d21af..32b0d827c0580565b245d1189928abefdba482d2 100644 GIT binary patch delta 19 ZcmaFN{g|8UGcPX}0}zCt-N<#56#zS|1-k$M delta 19 ZcmaFN{g|8UGcPX}0}!~2ZsfYj3II2>1oHp@ diff --git a/libs/agent_framework/src/agent_framework/guardrails/framework_llm_client.py b/libs/agent_framework/src/agent_framework/guardrails/framework_llm_client.py index f3d4e6a..bce98a5 100644 --- a/libs/agent_framework/src/agent_framework/guardrails/framework_llm_client.py +++ b/libs/agent_framework/src/agent_framework/guardrails/framework_llm_client.py @@ -396,6 +396,7 @@ async def classify_with_framework_llm( cliente LLM paralelo fora da arquitetura do framework. """ selected_profile = _selected_profile_for_task(task, profile_name) + owned_llm = llm is None llm = _ensure_framework_llm(llm) # USE_MOCK_LLM remains useful for local development, but it must not hide an @@ -420,27 +421,39 @@ async def classify_with_framework_llm( if task in _BINARY_TASKS else "Responda apenas JSON válido, sem markdown." ) - raw = await llm.ainvoke( - [ - {"role": "system", "content": system_instruction}, - {"role": "user", "content": prompt}, - ], - profile_name=selected_profile, - component_name=selected_component, - generation_name=selected_generation, - ) - output = _extract_text(raw) - if task == "TOXOUT": - return {"text": output} - if not output: - return {"allowed": True, "label": "EMPTY", "reason": ""} - if task in _BINARY_TASKS: - block_digit = _BINARY_BLOCK_DIGIT.get(task, "0") - digits = [ch for ch in output if ch in "01"] - allowed = digits[-1] != block_digit if digits else True - return { - "allowed": allowed, - "label": "OK" if allowed else task, - "reason": "" if allowed else _BINARY_TASKS[task], - } - return _parse_json(output) + try: + raw = await llm.ainvoke( + [ + {"role": "system", "content": system_instruction}, + {"role": "user", "content": prompt}, + ], + profile_name=selected_profile, + component_name=selected_component, + generation_name=selected_generation, + ) + output = _extract_text(raw) + if task == "TOXOUT": + return {"text": output} + if not output: + return {"allowed": True, "label": "EMPTY", "reason": ""} + if task in _BINARY_TASKS: + block_digit = _BINARY_BLOCK_DIGIT.get(task, "0") + digits = [ch for ch in output if ch in "01"] + allowed = digits[-1] != block_digit if digits else True + return { + "allowed": allowed, + "label": "OK" if allowed else task, + "reason": "" if allowed else _BINARY_TASKS[task], + } + return _parse_json(output) + finally: + if owned_llm and llm is not None: + close = getattr(llm, "aclose", None) + if callable(close): + try: + result = close() + if hasattr(result, "__await__"): + await result + except Exception: + # Guardrail classification result must not be replaced by a cleanup failure. + pass diff --git a/libs/agent_framework/src/agent_framework/guardrails/rails.py b/libs/agent_framework/src/agent_framework/guardrails/rails.py index 187e557..fcfb31b 100644 --- a/libs/agent_framework/src/agent_framework/guardrails/rails.py +++ b/libs/agent_framework/src/agent_framework/guardrails/rails.py @@ -338,9 +338,44 @@ class LoopRail(Guardrail): code = "VLOOP" stage = "input" + @staticmethod + def _transaction_status(ctx: dict[str, Any]) -> str: + status = str(ctx.get("transaction_status") or "").strip().upper() + if status: + return status + active_transaction = ctx.get("active_transaction") + if isinstance(active_transaction, dict): + return str(active_transaction.get("status") or "").strip().upper() + return "" + async def evaluate(self, text: str, context: dict[str, Any]) -> RailDecision: + ctx = _ctx(context) + transaction_status = self._transaction_status(ctx) + + # A short confirmation (for example ``sim``/``não``) may legitimately + # appear several times in the same session because each transaction has + # its own confirmation boundary. VLOOP protects against conversational + # repetition; it must not consume the input that belongs to an active + # transaction awaiting confirmation. The transaction runtime/classifier + # remains responsible for deciding whether the utterance is actually a + # valid confirm/reject response. + if transaction_status == "AWAITING_CONFIRMATION": + return RailDecision( + code=self.code, + allowed=True, + reason="continuidade_transacional:AWAITING_CONFIRMATION", + sanitized_text=text, + metadata={ + "history_window": len(list(ctx.get("history_texts") or [])[-6:]), + "repeated": False, + "mechanism": "deterministic_transaction_bypass", + "transaction_status": transaction_status, + "calibrated": True, + }, + ) + normalized = _lower(text).strip() - history = [_lower(h).strip() for h in _ctx(context).get("history_texts", [])[-6:]] + history = [_lower(h).strip() for h in ctx.get("history_texts", [])[-6:]] repeated = history.count(normalized) >= 2 if normalized else False return RailDecision( code=self.code, diff --git a/libs/agent_framework/src/agent_framework/idempotency.py b/libs/agent_framework/src/agent_framework/idempotency.py index 1b67040..af39ceb 100644 --- a/libs/agent_framework/src/agent_framework/idempotency.py +++ b/libs/agent_framework/src/agent_framework/idempotency.py @@ -13,10 +13,20 @@ logger = logging.getLogger("agent_framework.idempotency") class IdempotencyStore: """Namespace idempotente apoiado no storage genérico do framework.""" - def __init__(self, backend: Any, *, namespace: str = "idempotency", ttl_seconds: int | None = None): + def __init__( + self, + backend: Any, + *, + namespace: str = "idempotency", + ttl_seconds: int | None = None, + fallback_backend: Any | None = None, + fail_open: bool = False, + ): self.backend = backend self.namespace = namespace self.ttl_seconds = ttl_seconds + self.fallback_backend = fallback_backend + self.fail_open = bool(fail_open) @staticmethod def canonical_key(*parts: Any) -> str: @@ -27,13 +37,58 @@ class IdempotencyStore: return f"{self.namespace}:{key}" async def get(self, key: str) -> Any | None: - return await self.backend.get(self._key(key)) + scoped = self._key(key) + try: + value = await self.backend.get(scoped) + if value is not None: + return value + except Exception as exc: + if not self.fail_open or self.fallback_backend is None: + raise + logger.warning("Falha no backend primário de idempotência em get(%s); usando fallback em memória: %s", scoped, exc) + if self.fallback_backend is not None: + try: + return await self.fallback_backend.get(scoped) + except Exception as exc: + logger.warning("Falha no fallback de idempotência em get(%s): %s", scoped, exc) + return None async def set(self, key: str, value: Any, *, ttl_seconds: int | None = None) -> None: - await self.backend.set(self._key(key), value, ttl_seconds if ttl_seconds is not None else self.ttl_seconds) + scoped = self._key(key) + ttl = ttl_seconds if ttl_seconds is not None else self.ttl_seconds + primary_ok = False + try: + await self.backend.set(scoped, value, ttl) + primary_ok = True + except Exception as exc: + if not self.fail_open or self.fallback_backend is None: + raise + logger.warning("Falha no backend primário de idempotência em set(%s); usando fallback em memória: %s", scoped, exc) + if self.fallback_backend is not None: + try: + await self.fallback_backend.set(scoped, value, ttl) + except Exception as exc: + logger.warning("Falha no fallback de idempotência em set(%s): %s", scoped, exc) + if not primary_ok and not self.fail_open: + raise async def delete(self, key: str) -> None: - await self.backend.delete(self._key(key)) + scoped = self._key(key) + primary_error = None + try: + await self.backend.delete(scoped) + except Exception as exc: + primary_error = exc + if not self.fail_open or self.fallback_backend is None: + raise + logger.warning("Falha no backend primário de idempotência em delete(%s); limpando fallback: %s", scoped, exc) + if self.fallback_backend is not None: + try: + await self.fallback_backend.delete(scoped) + except Exception as exc: + logger.warning("Falha no fallback de idempotência em delete(%s): %s", scoped, exc) + if primary_error is not None and not self.fail_open: + raise class InMemoryIdempotencyStore(IdempotencyStore): @@ -81,4 +136,12 @@ def create_idempotency_store(settings, *, namespace: str = "idempotency", requir raise RuntimeError(f"Provider de idempotência durável não suportado: {provider}") logger.warning("Provider de idempotência %s não suportado; usando memória", provider) backend = InMemoryCache() - return IdempotencyStore(backend, namespace=namespace, ttl_seconds=ttl) + fail_open = bool(getattr(settings, "IDEMPOTENCY_FAIL_OPEN", not durable_required)) + fallback_backend = InMemoryCache() if fail_open and not isinstance(backend, InMemoryCache) else None + return IdempotencyStore( + backend, + namespace=namespace, + ttl_seconds=ttl, + fallback_backend=fallback_backend, + fail_open=fail_open, + ) diff --git a/libs/agent_framework/src/agent_framework/identity/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/identity/__pycache__/__init__.cpython-313.pyc index 54d3fb4716e1fcc4faee1801b27ab9c5e797a9f8..262a3b6125381c8197999499b2c48d479c149bab 100644 GIT binary patch delta 35 pcmbQiJd>IGGcPX}0}zCtoi>sCDNludZeEFgvc6++Y4OD0a{;%J3>^Rf delta 34 ocmbQqJcF70GcPX}0}wDhm^zXBDR;SkZeEFgioS2K=fppA0i~M@CjbBd diff --git a/libs/agent_framework/src/agent_framework/identity/__pycache__/mcp_mapper.cpython-313.pyc b/libs/agent_framework/src/agent_framework/identity/__pycache__/mcp_mapper.cpython-313.pyc index b05721bd60153844f11d68c12443c305a0f79322..78250ff95c18ca69c756d1188e092aae5568c5dd 100644 GIT binary patch delta 38 scmcbja#e-haZ-Z&GcPX}0}zCtowkv?oSCOgKR2&LKUv?gxU_h4FY|5=0OAP@Hvj+t delta 37 rcmX>paYBOoGcPX}0}wDhn7Wa>oSC~+KR2&LKSkd+*mH9q^KK3R&8G`N diff --git a/libs/agent_framework/src/agent_framework/identity/__pycache__/resolver.cpython-313.pyc b/libs/agent_framework/src/agent_framework/identity/__pycache__/resolver.cpython-313.pyc index dd8b6383135240df006a0b9e375f06feccb1ccac..ddd7be65763bdbbca544d509002462bfdb1575c3 100644 GIT binary patch delta 37 rcmaE<@=AsKGcPX}0}zCrowkuXn3<z+6s{X diff --git a/libs/agent_framework/src/agent_framework/judges/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/__pycache__/__init__.cpython-313.pyc index 4da852fe26305835171360bae621e15a9a0f8f9c..fd1f7bba3bf48294089f584285e04e79399c40bd 100644 GIT binary patch delta 37 rcmaFG@|uPFGcPX}0}zCtowkvCBO_0ler{fgezLw}acS}7|-X;u# delta 36 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 delta 34 ocmaFF_>htNGcPX}0}wDjm^zW$n7ctgH?KrLMc+5rbE4M_0IT;3RsaA1 diff --git a/libs/agent_framework/src/agent_framework/judges/calibrated/__pycache__/_compat.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/calibrated/__pycache__/_compat.cpython-313.pyc index 80394059003a6a4fe7701f7ab3ff7e085d4c53fd..f430abb6b02a91cb05687b6242427ffefeb4fa25 100644 GIT binary patch delta 20 acmdlixLJ_ diff --git a/libs/agent_framework/src/agent_framework/judges/calibrated/__pycache__/models.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/calibrated/__pycache__/models.cpython-313.pyc index 198f6bfb68eaa61db128dc05428b73194fa26194..8a144360d786c3c6e2b2bdb46d399ff99d948221 100644 GIT binary patch delta 20 acmZo+Z(-;D%*)Hg00cr;CT--dWCj2+mIUbl delta 20 acmZo+Z(-;D%*)Hg00b|0PTa^{$qWEC&;_Ib diff --git a/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/__init__.cpython-313.pyc index 6c7a3a6d64c8718ed18cbfd5bfd4125a78e5405f..0ab8d48c5dd19b866fe2dfcca9e25608b58575df 100644 GIT binary patch delta 35 pcmaFK_==JHGcPX}0}zCtoi>r%n5R=eH?KrLS>Lg^w0NTD0sz2W3u^!X delta 34 ocmaFG_>z(PGcPX}0}wDjm^zW$n7cziH?KrLMc+5rbE4M*0Iq)ub^rhX diff --git a/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/aluc.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/aluc.cpython-313.pyc index 02e8cbf88b640b7fed75e1a5db360392a86213c8..6c3e14d1ece3f4f805ee4a186657a8eee102bb7e 100644 GIT binary patch delta 38 scmZoPZZhWn%*)Hg00iM@r)}hpli+F9&&?~*Pu6!VE-l_%BEicD0MsoDF#rGn delta 37 rcmZoNZZzip%*)Hg00hhrrf%epli+UA&&?~*Pto@c_S{@5!OI8$z%U9t diff --git a/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/csi.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/csi.cpython-313.pyc index b088da73b9e096d7628aba6e936be01563612d1f..63a7acfad6dcb40a64eb282ac638f43394e4362d 100644 GIT binary patch delta 37 rcmdnOwUvweGcPX}0}zCtowku%m4&B8KR2&LKUv?gxU_h(HOo%`#smv> delta 36 qcmdnWwS|lOGcPX}0}wDjn7WZ$m4&-mKR2&LKSkd+*mJTC%TEBaHVS|M diff --git a/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/fallback.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/fallback.cpython-313.pyc index 26557c2835ef08410f3a3665269605f442dc5fb7..c3493b7de516228c63fa09d9fdca56c73fb52280 100644 GIT binary patch delta 38 scmaEC_r#9-GcPX}0}zCtowkv?osXweKR2&LKUv?gxU_ilT)txh0Qg!B6#xJL delta 37 rcmaE2_t=j6GcPX}0}wDjn7Wa>osYXiKR2&LKSkd+*mLtdzGDIa<6sOR diff --git a/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/rqlt.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/rqlt.cpython-313.pyc index b0a52527f4b0148af028ccded0b51656f4d3255f..032224bc1762a2d63934b67fa54170b9dee24128 100644 GIT binary patch delta 38 scmeC>?BnGA%*)Hg00iM@r)}geVCHGn&&?~*Pu6!VE-l{N#>~zL0L!Zi=>Px# delta 37 rcmeC list[dict[str, Any]]: return specs + +_JUDGE_CONTEXT_DROP_KEYS = { + 'state', 'vars', 'session', 'session_metadata', 'original_context', + 'agent_profile', 'business_events', 'trace', 'nodes', 'input', + 'raw_llm_answer', 'headers', 'request_kwargs', 'response_headers', +} + +def _compact_judge_context( + context: dict[str, Any], + *, + max_total_chars: int = 36000, + max_field_chars: int = 12000, + max_depth: int = 6, + max_items: int = 24, +) -> dict[str, Any]: + """Return a bounded, business-focused judge context. + + The full workflow/checkpoint remains available for telemetry and audit. Judges + receive only a compact projection so native and external implementations share + the same safety contract. + """ + def compact(value: Any, depth: int = 0) -> Any: + if depth >= max_depth: + return '[conteúdo aninhado omitido]' if isinstance(value, (dict, list, tuple, set)) else value + if isinstance(value, dict): + out: dict[str, Any] = {} + for idx, (key, raw) in enumerate(value.items()): + if idx >= max_items: + out['_omitted_fields'] = max(0, len(value) - max_items) + break + key_s = str(key) + if key_s.lower() in _JUDGE_CONTEXT_DROP_KEYS: + continue + out[key_s] = compact(raw, depth + 1) + return out + if isinstance(value, (list, tuple, set)): + seq = list(value) + out = [compact(item, depth + 1) for item in seq[:max_items]] + if len(seq) > max_items: + out.append(f'[+{len(seq)-max_items} itens omitidos]') + return out + if isinstance(value, str) and len(value) > max_field_chars: + return value[:max_field_chars] + '…[texto truncado]' + return value + + compacted = compact(context) + if not isinstance(compacted, dict): + compacted = {'context': compacted} + + # Enforce a final aggregate budget without discarding the top-level transaction + # signals used by sampling/always-run decisions. + try: + rendered = json.dumps(compacted, ensure_ascii=False, default=str) + except Exception: + rendered = str(compacted) + if len(rendered) <= max_total_chars: + return compacted + + priority = ( + 'transaction_status', 'confirmation_required', 'confirmation_received', + 'route', 'intent', 'transactional_tools', 'tool_policy_result', + 'selected_tool_call', 'pending_tool_call', + ) + bounded: dict[str, Any] = {k: compacted.get(k) for k in priority if k in compacted} + for key in ('mcp_results', 'transaction_evidence', 'evidence'): + if key not in compacted: + continue + value = compacted[key] + try: + text = json.dumps(value, ensure_ascii=False, default=str) + except Exception: + text = str(value) + bounded[key] = text[:max_field_chars] + ('…[contexto do judge truncado]' if len(text) > max_field_chars else '') + return bounded + def _extract_evidence(context: dict[str, Any]) -> str: if not context: return '' diff --git a/libs/agent_framework/src/agent_framework/llm/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/llm/__pycache__/__init__.cpython-313.pyc index a4090b47ba8e840a2e3cc8ac0f7d5a159ee30f7a..da7e2194d3e1cbc02ae6de36077e707945ae013f 100644 GIT binary patch delta 37 rcmcb^e3zN~GcPX}0}zCrowku%laZ%bKR2&LKUv?gxU_h(J>y&e&GHLN delta 36 qcmcc1e21C)GcPX}0}wDin7WZ$laaefKR2&LKSkd+*mJT2<6Ho`+zM3y diff --git a/libs/agent_framework/src/agent_framework/llm/__pycache__/base.cpython-313.pyc b/libs/agent_framework/src/agent_framework/llm/__pycache__/base.cpython-313.pyc index 8e26ef84e4e1db48bf62a6cc133271158212a3ef..972b6626a15dc2c21f74e63ed132814672b234d3 100644 GIT binary patch delta 38 scmcc4bAyNbGcPX}0}zCrowkwt3?omzer{fgezLw}acS}9M~tN`0O_j?kpKVy delta 37 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 diff --git a/libs/agent_framework/src/agent_framework/llm/__pycache__/structured_output.cpython-313.pyc b/libs/agent_framework/src/agent_framework/llm/__pycache__/structured_output.cpython-313.pyc index b52605191b347569134edf4420ab6d82af7952b7..f55398b848cf05da32e1c18aa86ee428ead339ae 100644 GIT binary patch delta 38 scmZ2%wZw}1GcPX}0}zCrowkvC4>M1Ver{fgezLw}acS}9OU!|i0OsioX8-^I delta 37 rcmZ2twb+XLGcPX}0}wDin7WaB4>NbQer{fgeu}%z=^s(nAYz diff --git a/libs/agent_framework/src/agent_framework/llm/__pycache__/types.cpython-313.pyc b/libs/agent_framework/src/agent_framework/llm/__pycache__/types.cpython-313.pyc index 75df3f79a6f4bb91c883b6731074e9495b6a2085..05014a07f54ea9675ce69b8e48635523902b644e 100644 GIT binary patch delta 38 scmeyx`J0pbGcPX}0}zCrowkv?f|;j4KR2&LKUv?gxU_h4A9D^P0P8snA^-pY delta 37 rcmey(`HPeLGcPX}0}wDin7Wa>f|)yCKR2&LKSkd+*mH9~a}FZ_)|U$` diff --git a/libs/agent_framework/src/agent_framework/llm/providers.py b/libs/agent_framework/src/agent_framework/llm/providers.py index ee91acd..b20c298 100644 --- a/libs/agent_framework/src/agent_framework/llm/providers.py +++ b/libs/agent_framework/src/agent_framework/llm/providers.py @@ -569,6 +569,32 @@ class OCICompatibleOpenAIProvider(LLMProvider): ) raise + async def aclose(self) -> None: + """Close all cached OpenAI-compatible clients inside their owning event loop. + + Temporary providers are created by legacy guardrail compatibility bridges. + Explicitly closing them before ``asyncio.run`` returns prevents the OpenAI/httpx + client finalizer from trying to close transports after the loop is already gone. + Persistent application-owned providers can call the same method at shutdown. + """ + clients = list(self._clients.values()) + self._clients.clear() + self.client = None + for client in clients: + close = getattr(client, "close", None) + aclose = getattr(client, "aclose", None) + try: + if callable(aclose): + result = aclose() + if hasattr(result, "__await__"): + await result + elif callable(close): + result = close() + if hasattr(result, "__await__"): + await result + except Exception: + logger.exception("Erro ao fechar cliente OpenAI-compatible") + def _using_langfuse_openai(self) -> bool: if self.client is None: return False diff --git a/libs/agent_framework/src/agent_framework/mcp/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/mcp/__pycache__/__init__.cpython-313.pyc index c44006141816a40366f140787d2c9ceb131c9668..c872622ec26f1cc1747386c877fb130238d83e38 100644 GIT binary patch delta 37 rcmcb~e2ba;GcPX}0}zCrowku%i;<^TKR2&LKUv?gxU_h(1LI5p%`6K; delta 36 qcmcb`e3O~`GcPX}0}wDhn7WZ$i;=rXKR2&LKSkd+*mJTY<4gd$G73%r diff --git a/libs/agent_framework/src/agent_framework/mcp/__pycache__/client.cpython-313.pyc b/libs/agent_framework/src/agent_framework/mcp/__pycache__/client.cpython-313.pyc index de3c3cf8ebf5a8980af11746f4acaf0daae9176f..d8ae516a55b17af386c3d8d5bf75f2dbbeb35fa7 100644 GIT binary patch delta 40 ucmey>&-lBak^3_*FBbz4gq@wXk$WLCPoaKpUWtCPzGHD|@#gK!&Mp8Mxec8F delta 39 tcmey}&-kmKk^3_*FBbz4Fg=*Mk$WLCcY%IxUWtB+zHhMS<{iw=E&v1g45$DA diff --git a/libs/agent_framework/src/agent_framework/mcp/__pycache__/models.cpython-313.pyc b/libs/agent_framework/src/agent_framework/mcp/__pycache__/models.cpython-313.pyc index 5b0803fe4e8d7893ac3f6b566ff271e0e75deef9..a64e27058d4aa21d0d6e7b193da7345ca3bf86f1 100644 GIT binary patch delta 38 scmca1a8rQ$GcPX}0}zCrowkwNgNdh5KR2&LKUv?gxU_h49MdmW0N?lw9RL6T delta 37 rcmca9a6^FmGcPX}0}wDhn7WbMgNeI9KR2&LKSkd+*mH9{(=S#4%hU@f diff --git a/libs/agent_framework/src/agent_framework/mcp/__pycache__/registry.cpython-313.pyc b/libs/agent_framework/src/agent_framework/mcp/__pycache__/registry.cpython-313.pyc index e6a2deef27a05b5346fd55c64571caa188d285e7..16e0b00f5c6e473ece8985ac4f72503b4633fe04 100644 GIT binary patch delta 38 scmZosZB^y|%*)Hg00d!Yr)}gGVd5#)&&?~*Pu6!VE-l`y#S|p~0LP^YqyPW_ delta 37 rcmZowZBga^%*)Hg00c}Arf%dGVd5^*&&?~*Pto@c_S~$^6eR!vv@r>< diff --git a/libs/agent_framework/src/agent_framework/mcp/__pycache__/tool_policy.cpython-313.pyc b/libs/agent_framework/src/agent_framework/mcp/__pycache__/tool_policy.cpython-313.pyc index 16e939bd144d63775db7a39af49c8f9af6912775..ca72d392d3580a0e9ab11b1ed83d63a50c05a53b 100644 GIT binary patch delta 38 scmdn0vrUKlGcPX}0}zCrowkv?h>536KR2&LKUv?gxU_h42h&<%0O4~CDF6Tf delta 37 rcmdm{vsH)tGcPX}0}wDhn7Wa>h>5#YKR2&LKSkd+*mH9y(^_Ew%`OWx diff --git a/libs/agent_framework/src/agent_framework/mcp/__pycache__/tool_router.cpython-313.pyc b/libs/agent_framework/src/agent_framework/mcp/__pycache__/tool_router.cpython-313.pyc index da436b7fee1b5d439aba876bce8c280860f4a9ff..bc53c02fab16f5c20c1822cc380e537811be8282 100644 GIT binary patch delta 38 scmaEx_b!k7GcPX}0}zCrowkvCKNnA#er{fgezLw}acS}9t6Vd501O!o%K!iX delta 37 rcmaEt_co9FGcPX}0}wDhn7WaBKNokYer{fgeu}i;=rlKR2&LKSkd+*mLtjMiW*5&i@MI diff --git a/libs/agent_framework/src/agent_framework/memory/__pycache__/long_term_store.cpython-313.pyc b/libs/agent_framework/src/agent_framework/memory/__pycache__/long_term_store.cpython-313.pyc index 36bbd5128dd76961caadeb270ab17bed4a367b00..d2853bee60a7039b7a915b7a4a0edbefb241319c 100644 GIT binary patch delta 40 ucmZpA!r1(Tk^3_*FBbz4grA+Zk^3r%n5RrXH?KrLS>Lg^w0NRtF95m=3myOf delta 34 ocmcc4c#VK%*)Hg00hhrrf%du%E(=+pPN^rpQ7&@?78_4<2r5t!k delta 37 rcmdlevq6UYGcPX}0}wDjn7Wbs2QzoAer{fgeu}DGcPX}0}u#ZnY58xmk9tkNd*1? delta 20 acmdnNvV(>DGcPX}0}#C2IdLPmE)xJfg9W(& diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/noc_otel.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/noc_otel.cpython-313.pyc index b127e4300bf32dc6d3163ae9b1cada768304a109..e4fbb18c4ce6f6ed733ff6f9aef17a16c8aa17b9 100644 GIT binary patch delta 38 scmdmJxXF-llja{X710tyj%=G5OH?eMs5Xmo;v;9yb}FneaGU`;>~94Q;z}w1&R$n delta 39 ucmX>zllk;aX710tyj%=G!2Dq9Ms5Xm?ppoayb}Esecxcu&F1V=j{*SjRt!l1 diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/tim_backoffice_contract.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/tim_backoffice_contract.cpython-313.pyc index 42851b9e4f0ff76abbe2eedbde5b608a99246882..1a5f3fc04514adb2cc09c5c39fc8d9108253a8f8 100644 GIT binary patch delta 20 acmcb^dxw|%GcPX}0}u#ZnY5AnA{zieF$Mqt delta 20 acmcb^dxw|%GcPX}0}#C2IdLQRMK%CMYX-Xj diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/token_cost.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/token_cost.cpython-313.pyc index 22641f99ec105078d88e8a247c1ef10e51fc3246..584ec9fb33f4517cf916a48cb1710de73d7082b0 100644 GIT binary patch delta 38 scmez5{MniNGcPX}0}w=Z~y=R delta 37 rcmezD{K=X7GcPX}0}wDjn7WbMjFY=gKR2&LKSkd+*mJWl=Q0TZ;BE_g diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/workflow_events.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/workflow_events.cpython-313.pyc index 110b3a8834561b121df3c93b295ebf8981022ffe..da593ed6dfd22ffe5f10a688a40a305b87cf2a78 100644 GIT binary patch delta 38 scmZpaYLepq%*)Hg00a?dr)}i+W#nnm&&?~*Pu6!VE-l`i%s7u50LsS;N&o-= delta 37 rcmZpYYLw#s%*)Hg00hhrrf%f+W#n$w&&?~*Pto@c_S~GpIFB0uw+sqY diff --git a/libs/agent_framework/src/agent_framework/oci/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/oci/__pycache__/__init__.cpython-313.pyc index f97326484307536b0154358941805538e7504e5e..48f640609babaf8ed513d3c09a40bc3efb4bf708 100644 GIT binary patch delta 35 pcmcc2c!iPsGcPX}0}zCtoi>r%n5S4jH?KrLS>Lg^w0NRt7XY~>3ljhU delta 34 ocmcb@c$ty=GcPX}0}wDjm^zW$n7c?nH?KrLMc+5rbD~!l0H=ux9smFU diff --git a/libs/agent_framework/src/agent_framework/oci/__pycache__/auth.cpython-313.pyc b/libs/agent_framework/src/agent_framework/oci/__pycache__/auth.cpython-313.pyc index 2cfd0d426d454feabe3d04ecb5e46301792b7d05..548cdccb95aee101b6e7ed39716fe7b52c40106d 100644 GIT binary patch delta 38 scmZ22xki%vGcPX}0}zCtowkv?mXjx6KR2&LKUv?gxU_ilWKIcY0NFtcXaE2J delta 37 rcmZ1@xmuF@GcPX}0}wDjn7Wa>mXkYAKR2&LKSkd+*mLs~P6=iJ#VQJO diff --git a/libs/agent_framework/src/agent_framework/persistence/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/persistence/__pycache__/__init__.cpython-313.pyc index 1d4abf93ec407d8b49feb03cd47c7be95e856a3c..41a9bdd9ee8fa74468d0c7893feff5a46bab0c56 100644 GIT binary patch delta 35 pcmcc3c!!buGcPX}0}zCroi>r%n5SAlH?KrLS>Lg^w0NTDBmldw3o-xz delta 34 ocmcb^c$<;?GcPX}0}wDjm^zW$n7c|pH?KrLMc+5rbE4NI0ICrRJ^%m! diff --git a/libs/agent_framework/src/agent_framework/persistence/__pycache__/mongodb_store.cpython-313.pyc b/libs/agent_framework/src/agent_framework/persistence/__pycache__/mongodb_store.cpython-313.pyc index 6d9acc930829b3097204ae4472a22c20480dbb1d..763cec20b1cf458eefd95fdaac1970dd7d37fe80 100644 GIT binary patch delta 20 acmca+5Yn|RkR|(EiHGx$ zlMqTsme*;Z2{geZTX3KSa;HtUGuutdW|=nWVuxv9Z_}jBrs*)7b|7RnEi>8d_nj+C zvg~g4$Is{So$q|F^PTTppZY}j;&UP6UV3_}0e+i*bz-L&x{~n~DIOx4X}8N4k`)3I zq86^}@dxYNbxlf0VI{&-#IBwZ>PUGO%u*|WA|Rbev*C}H=G>_S{7zrM^ro3|kG9NCqlMgc>D*CP~IZ z12t_mON*tXLc`9ad9W6LG+C;bOgKU)+p&>exDmAbHb8dKvl*;Ebq%`1Rla@+W z-p`cMp`Rr!lNu!(j_f2f8+w`0Ce$u9Nz0|I$aoI)viW!}theJR&69FqeZI6p%H{n@ zQXcdRq-H6f_Y0*-&@T#0Ez(M<0Ed8WG4u+dO=yXSXTi%tdq(k>nf#ii!_ZdoDPH)oX{av z0$~*pu9v1q2xmag!Re}{DwwU2W^k+qtcAH&sU|{M2R7Ou)kbPg!*p*Sjt!><;wwc!RW%4QJ<@aZ|d1{VBW1%umloHN&1NKnTOI4ZvZd zjci)(6q2p3&iz4weItwkix5=;l)8{=EhBa1C5_m82w@w5VgwK)hnOx?m)Bi2P1UJk zBBHBK8F$+0ZZ>^hH<;(xy#1t^<;|}ljjVaT2lgJC{}CY`^}s?^U_YxbVVmn0R<_`7 zYY|W=8ba6#pe1>{ptc>F4l79i)B4Jp2XGP>Xhx;a#|2d|*?^4EpPoLRK%yenb~r~B z8|ulNX6S>(AA>*iah$U{yX2r#krl-o@DJ&3qhXkddQCmNu)z9I&=W$&U zm0ceC4E9kPM|y(TU`VBD%G@JJYwY*-YR29`FD=4ua<@xy1%s5ngbP!6r0^{x7H7X` znxngqslxI!Vd*%bZBDOWk!jEg!KJvmWJhw02}l<3$vj?yvOh=2;p@EZuSeC50^##Jd`w%_u`L`o(jjL>))t9 zb{fgFaXZ_by`iAf-7UL!^#;J!^>>$v#k?k z56uWkl-r8i0&f|l{{zD32*^{H%>*rEtXG8eGxb}yk{BRid2)6mu0RH{(7z;uRn(%+ zAwsJaWV@^Sy0??+ahA(+^7HR; zDvIoscSDjz+reTQW`FU*-O7q~ddO{cVCSPmH=K_VpX`kqPBZRyQOe^BZ@7d6tXaUA zyvB}C>+~;3`B#M48TC_N0FYX!Dt05QvZcv3Gs=J(L1-4*dnfFA;d+c^_Kf{Qt%Qegb1c{-kl?WRb0}+jDO4wlxIe>p_fcCh2-hP)D^unbbboKNqqMjn_+V%yz1AejBMO`9P zbNKh_xvQ@RL`Cij!I<15Zfajqo0_WAi_J~#Ep_b=tZ$Lpo7T69y#bFbQaKo)eis!z zuAq!tz~UY;*dO-#I|J3C?C%S?{K0@25Z%6jdza`5q;^uMP4@)oF7fIRm#RPDmup;m zTvV>l7+b%~yIaN;kTPW23;Vi&7l<7|A*;o{5T6ZzIv#rU)o?(B ztJwox*%uIFTe@(BDo_e|sVML5^>UqmEGxCCtq!7@gZ(JD!$R}G&J<53O#w4%DWRY{ z(AlX#y7?InV(`SN4A3RO?z$9Objh%N-mrDvEnCh_Tj_|c^fk*l>!9_9 zt!CI#!(YMdcMXru8h4aao!l>2yN=eZ@1V|jC^5CN5oH>=#J*N$==X@QT3}^QG_z9H z$PR}x*l=)#(XcU%-92W{O_Gu@DbE9~@aH#eip;R{J4&WRhs~Qz({&1i3!cyauz7Jd zT)#8njFho_))m^ApS%Uj1^(LtXGi~SN@l~Md}H!PJA3lw5|Yd;yS-sQ%-y$(d%9&R ziz}K|tZs3xZFzXf;#qn^`2?o*{K7N*|5LMAL1_K@O-LOUJt3n};_~GnbhTu;9OF$^ z^o2b2TVNuRLnBGl#!~hanco2Z$``C^&(@jwMK|*nkK`?WYtCDJ|2+Rj-tvR1Ze{1) z%$`4zJ^ym>&AnIls{J>zmmgg5u`Ta=3r;Ozr}tD@?1qfugB^Er*njMqUXc%-BOOON z?kfeb-LWQHv)%ZPqp1S^T%9xv@ZapI&1J0B`$Y5KbT|b5Xx8Ssp`Eo2VEe zUS$K1eOoim5b2S~_sBjO5>O_vh(-Oy$7hiDLE{2;_wk%)1$AvM#@y3)*A}b6}CfC`baBI@1K+gI$ho?>;4Rv)nT^^4!DDMqog~4hD^3D2diLDtZ zgknG*m_cr^V*|6zmw=Dk%=+LPz;6e7Beg+*Nl*2Mc@-LagN?N_RPBwhlvbkb(-HIy za11XO%_8^g(A{VZWHw z2rTq;s%O)Dc4dD)ySIND`Ggfbv$u(xh0xh3*&Kj4S~?d8F^PPN6Bw=ohFdoKO$q-0@{r)=_%#Q#G-NKF^T)Ani74&E;#A(bk^bG*b$ket2TF-nb*ftCKLX2^9U_i8f=H z%g8UPBsx|$?nkI$VlLs{_?z`^^g$Fe74MS7^WBcBmqk?1AVumoFFi~e z#XjXd&TSZ+lFfHSi^d|bcd$ih(%pD{5U+{P2A5Yxa#$yd)fG>Uf_3Al z7oeG~KU)mxd*|6l1=7bpf9*U(?va1GM;>8M|DYzk2uL7w6a39{dm-}Sd5hZ!lNYT= z^2nvhogTACEPt7SQrB457bVmx;&OMbGf4M2-S9n<)t$>CtJJ1*^(4F$H)ue>kJ%1E zGefB!qJCaWLkY14r?@umzj)(def4)9}l#_?XxVHM>J-ZG`}dQSi@>oR(j9yv2D1P~HpCtuA5<#~kGL zY~03-Ou`Z6-o)7t5Kztgsrd163vRm&F4fp(*O7v6F^ny)*GP0}bX!Piu{Atm%=$+T zzVvfka0KB1>>m*-DUN_!nu}_QKFU)G zj|y%!-2gPY-ce8S;X)kC$VR9e1sqp8*jE>SS#~GKV9vfPq?>B*8KHFtTVG8krX^pRt){i) ze~Q_AKio5w^T6d0i_r+=Cvr4GvzYv&7348C^rO}}Z{R+>TH%knlF@AwsZdgb)HD5MD7rB$f!hprVw^ICD)VOlF32CxQ?e zKx(l*cpOV3@BwPA5L{Ng%XYPPS!`>c>r?r(k9FJSqphye$M>mq+17T^?!E8i-ei)l zZ~pk@JoedVpZz@N=1=e2PQPs{{!39&eh&QX?|iA>%`X>!%qoLScitU}4Js;wi5h)> z(?C4c6lvNZtryd6hgg~RxUGrJEP+X02%y@KtcI7uAH6{CR}*nLmIy^u9?(9vUt$Gy zNI3&xmKbqX`s%UiMZhJzia_Yj+lgD;KS<>5WSzMHAFTJ{D4!yg!}_Vx4U&)g719*w`=w54D)j?W1@tS^(i&;4Bf!t&=K=aJp0lgw;})G>!T-(sbz8N;gXDrRvPOI_TBVx*1ZpR7-R-r8=OS z1srdZW@PBDY;XJ@bnA;#V zWGLr@PI{!qOs`3r4-^Zeo24ck;my(l=r5EuO3l=7f!0E5Ednl^q?YBGg^Q`XDAQ|| zJ}WIIvL(=JHCs!l)h4y^rM<;LNt4}QvDeN7LkC@aI@-G$p$1{B6U{7)vMTXN;j)4; zMB90i>#lHOU?7^}e(`SE zR2Oc_d&Kp!N*4vjCav0=Z!7ZSum|OG@>QbMSI0`Vt-i1ND>k8!uJ9mN6P)irs%{*q z65WfdYCtmLcMFbh15oV%HJLc&D>bRaEU zx9Ab1weO84b$c?AC5}s2;CZL)WNQPOA5d z<6Zs^@&~fi1)RBvfCuFx2$vAZTed?>%>&5N_tV-RyNYiPN?aa96;LT5jp|OL-3%*& zo(X1wQGOcX41n&wOG$8Uad`hqsn^V3PZ&`Vx8pbRAVJ+eADFc9MRZ~+`l zFBBIxDxizvO?mb}FY+Hoz~H-vm6xRC&7yg8HQO&XZC;%wV?BgZ4+8}ACso8LoVQMC zkAlO{$ti`n#vIW)-FaMtM^s$^hS`l6`#$vb>YI5e98xDPB7Gj@To6R+)Cb=$OoUV`InI-wvF?Aci$`?FX`*&6=>YM@|l=k~ik?b<=f(> z0ERn)$#_hpo<|v92FUh2{(*LH-wxI=L3^b#C4h*ms*0@K4H*{ohivwXynZORqM<*+ zey<(x-^UE)?G$A(C2A^9x8EJ&oO}$cT2}Ve-JnpqP>;>&{I5v)Hv}sV{|Q|+7l5=n zYV}XFcVhkQ#tCwl7G(xFNwVXhlh~Me@J&=SQ;<;1hT5;kU zV>`v)k{i-Lfl-P&{v&Mt7y*sKe+mGe@CR&DI9k$U5MIoi)M(#E@|O^@EH^d?8RWW5 zwrxOCO1Iy^)_DZ7X-`hMvG5K;h1i^p_c(nXq0bZ8(&D=eUofB7& zOckNsis2l)D`sdm?A zOGR^8z;QF%;u5FtiKYjD{!?$w?mmSpHJu%uH?Ea$TDx_{vSve@Z^5*o+{`7x^dGtl z8D2wvPB|z`Wtr>16=Y&L%z5bQxyqholq-JKP}T(haf_-06?veHCqUKe|A^}&mEzCC zdE!rd+ot#`hS~9TN4nnfOc`GC^lgvd_T=qvR5ppt`{ue!bBe2uZ2zE4R7B_0`=E1l z`_b*6s(#q=c!#I6#r|@z!v%l7+tv*Dy_WnnOvuswbN{0`RK*OeE5L-8h@l}rMAylo zS?p`#osCn)8$(kd&i*je$=HB4fBznqMnXNGqQ|%bl%cy=i9gp!{FAAYsz2rYOrkJ0 z#hr->X_@j^cF`+^J@hG9^u(+KW$by;cHm!)6OL7s@v?{#Qy|jvP`RTwXAwC#kG&|4 z9c(1;dbf>?j}F3%@BnW^Yc$uBSR{uXMj`TzZ0biL{G#@NH`mzVCGp{*9`>$Secz$1 zBK+EYzNMJ2bXO!1hKSem=;e}x%Z+u*)AN*pJC#Tz8t)yK8O5~2^VoOA`ojyMAP*gW zAd}+aqTv3$X)37JJ#xI7;Q~TgvIb97i*ONyFzQ1cO7Dgp4XYg`>5?HH8c>b8mT#OD zj*CCz$klXYrEUNiCBXwU;^2IMt0M700N#9Ge4yCI z;^MIfFS)iN!R?~^p>XS&YSpk2JCOwc4XD=Az41 zQfoXGW4C18p`1o2Sru$T08wgQiP~9(Ko>9=l+{-W791^{`*8xPO|c?s9GqLS?knxf+>UVwmnXT0YxweksB-Qw&qL6U*lk zarn_1*T+DrK8?9gd*#u}>|4s8zf|F+2y(;|kuh)nij&RkACQ{-B7CykbrM7m+o)(B zKlvuP&1&^nAni7}*?m81ts;IMr^;wTX8(R)~|Qpq^=$PHnWONemPYt_5SZN8!+N z!3h_w|5&awao&SV|DVGlNjFNDUk-avY!es(zCk>4ww~o{FPz=VYA2kxAmiT2-d!;~ zwP-pYfb!6Nem1Mo`1w9tnocv}*<(KaIGunVeCJT*;}WB{;1W zc~;Q*Q7iajq&GEXGrkDPGqsd_!SZn{p=H-nS^W3NJl3lHeWaZgtU!kC2#dw4XME}P z<}ST>5_+N9_~%APgC)jgljKN`j`9O$>masj5e}KH`^?s1Y*7-UOoc57h5a~69DCES z>8Azw394qOrY8|sg0`L>@D+=MK9mqKl{RV-vp$q}#N6r<(^ zS7WbGO@&g?@PLx)OGL2lrZcZb2QJuzumfQw!XU!^2=^j9if{tq8HA@1zJc%p!Yc^h zNB9}Sn+U%`&=KB8_$|VR2p=H)9U=V*q74t6gOHElM(`rwjhF`z@LI}eAXFpJU5Rc{ z?buz7umqtCVJ*VV2pbS?Mc9l$iHmX?z4_{Ms$h`*`%{W?%pV2Rq}nYmKlhWOkIR{J z#Ye6J=S}RBfH-q`_Y9&(Qiy8PrzploeXc~bKHtgqiM`MFv|L7>beEu)6>ONGcPX}0}wDjn7WZWg^{~XKR2&LKSkd+*mH9=qk$y=+=&ZC diff --git a/libs/agent_framework/src/agent_framework/persistence/oracle_store.py b/libs/agent_framework/src/agent_framework/persistence/oracle_store.py index 45a62a0..2cd4ba5 100644 --- a/libs/agent_framework/src/agent_framework/persistence/oracle_store.py +++ b/libs/agent_framework/src/agent_framework/persistence/oracle_store.py @@ -412,6 +412,22 @@ class OracleStore: out.append({"id": row[0], "session_id": row[1], "event_name": row[2], "payload": _json_loads(v.read() if hasattr(v,"read") else v, {}), "created_at": row[4]}) return out + @staticmethod + def _normalize_datetime_for_compare(value): + """Normaliza timestamps Oracle/Python para comparação segura em UTC. + + Oracle DATE/TIMESTAMP pode retornar datetime sem tzinfo, enquanto o clock do + framework é timezone-aware. Para TTL/cache, datetime naive é interpretado + como UTC, que é o padrão usado pelo framework ao persistir expirações. + """ + if value is None: + return None + if not isinstance(value, datetime): + return value + if value.tzinfo is None or value.utcoffset() is None: + return value.replace(tzinfo=timezone.utc) + return value.astimezone(timezone.utc) + async def cache_get(self, key: str): return await asyncio.to_thread(self._cache_get, key) @@ -421,8 +437,9 @@ class OracleStore: cur.execute(f"select VALUE_JSON, EXPIRES_AT from {self.t('CACHE_ENTRY')} where CACHE_KEY=:1", [key]) row=cur.fetchone() if not row: return None - expires=row[1] - if expires and expires < self.now(): + expires = self._normalize_datetime_for_compare(row[1]) + now = self._normalize_datetime_for_compare(self.now()) + if expires and expires < now: cur.execute(f"delete from {self.t('CACHE_ENTRY')} where CACHE_KEY=:1", [key]) return None v=row[0] diff --git a/libs/agent_framework/src/agent_framework/presentation/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/presentation/__pycache__/__init__.cpython-313.pyc index f6e0008bc4c244c5d9667feb0bcb29040f8001b9..220e3febee452ddd94505dc8e2b21d8df6af81ab 100644 GIT binary patch delta 37 rcmX@ce4Ls4GcPX}0}zCtowkvihmog7KR2&LKUv?gxU_h(65|p8#q$dG delta 36 qcmX@ke2kgTw-yaNk diff --git a/libs/agent_framework/src/agent_framework/rag/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/rag/__pycache__/__init__.cpython-313.pyc index e603cf1e36e5f6118f331fe24b2285d82a5683cc..eeabd1b8c37cd46363e1b5e52517641e72e0ead7 100644 GIT binary patch delta 37 rcmX@gdW@C(GcPX}0}zCrowkvilZmHTKR2&LKUv?gxU_h(Jkv4&#bXNW delta 36 pcmX@cdX$y>GcPX}0|-2rx{;fciMvQYH?KrLMc+5rbFu={G61rF3H1N~ diff --git a/libs/agent_framework/src/agent_framework/rag/__pycache__/embedding_provider.cpython-313.pyc b/libs/agent_framework/src/agent_framework/rag/__pycache__/embedding_provider.cpython-313.pyc index d7dfa6f7eaff4efc3653ee3cd1f8e2cff1be474b..bf4541b273ae5f1b69855c8adb93d486a979b25c 100644 GIT binary patch delta 38 scmexj^wo&_GcPX}0}zCrowkwNmyxGdKR2&LKUv?gxU_h4GNYgb0PznC*8l(j delta 37 qcmexr^u>t#GcPX}0|-2rx{=$Lk-J7eH?KrLMc+5rb8`x#pacNiFACrQ diff --git a/libs/agent_framework/src/agent_framework/rag/__pycache__/graph_store.cpython-313.pyc b/libs/agent_framework/src/agent_framework/rag/__pycache__/graph_store.cpython-313.pyc index 59d7933370477b8a01ec2dba65f24e4a5a4cc768..4b40d3cb1fbfb38091a49327381938c9a0554b06 100644 GIT binary patch delta 38 scmbQPJwu!OGcPX}0}zCrowkwNn~|qXKR2&LKUv?gxU_h4BBPlI0Mpb9B>(^b delta 37 qcmbQCJzbmoGcPX}0|-2rx{=$Pk-JnsH?KrLMc+5rb8`}-nFs*C#R@I} diff --git a/libs/agent_framework/src/agent_framework/rag/__pycache__/ingest.cpython-313.pyc b/libs/agent_framework/src/agent_framework/rag/__pycache__/ingest.cpython-313.pyc index 09ce71df4ebfd904286ca7559eef1a1d86107e3f..f43963f6302b1be0c7d39ec1c8d629e40e135c76 100644 GIT binary patch delta 38 scmZ3Iv^0tPGcPX}0}zCrowku%keR1YKR2&LKUv?gxU_h)I`dy$0OK4C7ytkO delta 37 qcmZ3Qv?Pi9GcPX}0|-2rx{+IunY%zgH?KrLMc+5rbF&8XUtIvs!V4h) diff --git a/libs/agent_framework/src/agent_framework/rag/__pycache__/kbdb_service.cpython-313.pyc b/libs/agent_framework/src/agent_framework/rag/__pycache__/kbdb_service.cpython-313.pyc index 1dd680464edf90e18509499d5ea0982a59312c28..1c3214e2c8de13d98ad29126f7c14a2a8a8cb9f9 100644 GIT binary patch delta 38 scmbR3H^-0rGcPX}0}zCrowkvC79&r&er{fgezLw}acS}94UE~U0OrUHSO5S3 delta 37 qcmbQ^H`|Ze%U0Ntz$c>n+a delta 37 qcmbOfIx&>{GcPX}0|-2rx{=$Jg}YQgH?KrLMc+5rb8`%fnHm7eSPFsw diff --git a/libs/agent_framework/src/agent_framework/rag/__pycache__/vector_store.cpython-313.pyc b/libs/agent_framework/src/agent_framework/rag/__pycache__/vector_store.cpython-313.pyc index 9cad746a7c45df6ee775cb9b49b7f50f0c971cd9..2775a7a0c57d8bdcf5815e55417fc199dc905372 100644 GIT binary patch delta 40 vcmcaVk@3MqM()qNyj%=G5O#LjM(*cKJmvbic_sSE`i{k=#hd>!J#qyA8czr%n5RZRH?KrLS>Lg^w0NTDWB|Ma3pM}% delta 34 ncmcc1c!!buGcPX}0|-2rI+5F$yIMatuS7pZ-#6HEqSs^qsv`sCD^Iz8ZeEFgvc6++Y4K!k#(4n6>kDB3 delta 35 pcmZ3*ypoywGcPX}0}wDhm^zXBD|eZGZeEFgioS2K=VTtnc>uEI3TyxX diff --git a/libs/agent_framework/src/agent_framework/routing/__pycache__/config_loader.cpython-313.pyc b/libs/agent_framework/src/agent_framework/routing/__pycache__/config_loader.cpython-313.pyc index a29af095467b169b6e56f38c54cc5ea0b46b2ed5..5dc21fb9db74203844d944882e52c5f511c7d23c 100644 GIT binary patch delta 38 scmew%_*0PkGcPX}0}zCrowkv?pOL3VKR2&LKUv?gxU_ilQpR9*0PleeQ2+n{ delta 37 rcmew<_(PEUGcPX}0}wDhn7Wa>pOL#-KR2&LKSkd+*mLtT#$a{;+R6)D diff --git a/libs/agent_framework/src/agent_framework/routing/__pycache__/continuity.cpython-313.pyc b/libs/agent_framework/src/agent_framework/routing/__pycache__/continuity.cpython-313.pyc index ab458a29e78bdd681064211e18b19131b5b11016..170e4f41c41c2e7e82ba082fd78fe97afb476f96 100644 GIT binary patch delta 38 scmdm6v#*BxGcPX}0}zCrowkv?f{CY6KR2&LKUv?gxU_h4AJckk0Q)ix5&!@I delta 37 rcmdm2v$ux(GcPX}0}wDhn7Wa>f{D9AKR2&LKSkd+*mH9~(|T(F<}?f) diff --git a/libs/agent_framework/src/agent_framework/routing/__pycache__/enterprise_router.cpython-313.pyc b/libs/agent_framework/src/agent_framework/routing/__pycache__/enterprise_router.cpython-313.pyc index 8e15daba03d7e8eb77799fa8c6702d261cb4ce1b..9c23d1ae7092b56d180bf72aaefcdfaeba85bab4 100644 GIT binary patch delta 40 vcmbRIgn7ynX710tyj%=G5O#LjM(!XUo(BEgyb}FneaGU`;>{U6tDgb@5Cski delta 39 ucmbR8gn9B4X710tyj%=G!1Q41M(!XU?t1;)yb}Esecxcu&6zx_p8^2-j13e3 diff --git a/libs/agent_framework/src/agent_framework/routing/__pycache__/models.cpython-313.pyc b/libs/agent_framework/src/agent_framework/routing/__pycache__/models.cpython-313.pyc index bff8801cd688b4ea5a52c08062d0d3eac42d38e1..369446f1188f75443b7363147ff01d1c1564b9d6 100644 GIT binary patch delta 38 scmeAZ?ic3%%*)Hg00d!Yr)}g`W9BK<&&?~*Pu6!VE-l_{!yLp00LMoPssI20 delta 37 rcmeAd?i1$z%*)Hg00c}Arf%d`W9BZ=&&?~*Pto@c_S|gC9K;3yv(5>% diff --git a/libs/agent_framework/src/agent_framework/runtime/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/runtime/__pycache__/__init__.cpython-313.pyc index 9a2d984c300d4358e8de77f689dcbc065267ee42..da962e4492ef173d64d376c604a32f33860fecab 100644 GIT binary patch delta 35 pcmcb^beDqsEl;_AZeEFgvc6++Y4OCvGXcdU3@!iw delta 34 ocmcc1bcc!iGcPX}0}wDjm^zVrEq9rIZeEFgioS2K=fop30kZZBIRF3v diff --git a/libs/agent_framework/src/agent_framework/runtime/__pycache__/agent_runtime.cpython-313.pyc b/libs/agent_framework/src/agent_framework/runtime/__pycache__/agent_runtime.cpython-313.pyc index 295a6c50ba253915fdd3e4416cf616fb9a4e0096..a519316898d1bbae99e8403724ebc4a22602130c 100644 GIT binary patch delta 12633 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 Jgr&Iu{9jD|!<_&C delta 5937 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 delta 20 acmX>tc3O=4GcPX}0}#C2IdLPm12+Ie3 dict[str, Any]: current = state.get("active_transaction") if isinstance(state.get("active_transaction"), dict) else {} - txid = transaction_id or current.get("transaction_id") or str(uuid.uuid4()) + current_is_active = self._transaction_is_active(state) and bool(current.get("transaction_id")) + txid = transaction_id or (current.get("transaction_id") if current_is_active else None) or str(uuid.uuid4()) + normalized_arguments = dict(arguments or {}) + if not current_is_active and transaction_id is None: + # workflow_execution_id is transaction-scoped. A value left by a + # completed/failed transaction must never seed a new one in the same + # session. A paused workflow is resumed through pending_domain_workflow + # / retomar_workflow, not by opening a new transaction with this field. + normalized_arguments.pop("workflow_execution_id", None) if str(current.get("tool_name") or "") != str(tool_name): pre_validation = state.get("transaction_pre_validation") pre_validation = pre_validation if isinstance(pre_validation, dict) else {} @@ -1951,7 +1959,7 @@ class AgentRuntimeMixin: tx = { "transaction_id": txid, "tool_name": tool_name, - "arguments": dict(arguments or {}), + "arguments": normalized_arguments, "status": status, "started_from_intent": current.get("started_from_intent") or state.get("intent"), "requires": list(policy.get("requires") or getattr(cfg, "requires", []) or []), @@ -1962,7 +1970,14 @@ class AgentRuntimeMixin: "parameter_conversational_context": parameter_context or "", "user_claims_are_evidence": False if parameter_context else current.get("user_claims_are_evidence", False), } + # Invariant: the operational transaction and the scalar lifecycle status + # must always describe the same interaction. A previous terminal status + # (for example COMPLETED) must not survive after a new transaction is + # installed, otherwise the next input-boundary normalization may clear the + # newly created confirmation/parameter latches as if they belonged to the + # previous transaction. state["active_transaction"] = tx + state["transaction_status"] = status return tx @staticmethod @@ -3312,6 +3327,119 @@ class AgentRuntimeMixin: sections.append(f"Últimas mensagens completas da conversa:\n{rendered}") return sections + # ------------------------------------------------------------------ + # LLM context compaction + # ------------------------------------------------------------------ + _LLM_CONTEXT_DROP_KEYS = { + # Runtime/checkpoint internals are useful for audit/debug, but must not be + # recursively injected into an answering prompt. They frequently contain + # copies of the original request, session and previous workflow outputs. + "state", "vars", "session", "session_metadata", "original_context", + "agent_profile", "business_events", "trace", "nodes", "input", + # Provider / transport diagnostics do not add business grounding. + "raw_llm_answer", "headers", "request_kwargs", "response_headers", + } + + def _compact_llm_value( + self, + value: Any, + *, + max_chars: int = 16000, + max_depth: int = 6, + max_items: int = 24, + ) -> str: + """Render structured context for an LLM without checkpoint explosions. + + The operational state may intentionally retain complete workflow/MCP evidence + for auditability. Prompt context has a different contract: it contains the + business facts needed for the current answer, not recursive runtime objects. + This renderer therefore drops framework-internal recursive keys, bounds list + sizes/depth and finally enforces a hard character budget. + """ + truncated = False + + def compact(item: Any, depth: int = 0) -> Any: + nonlocal truncated + if depth >= max_depth: + if isinstance(item, (dict, list, tuple, set)): + truncated = True + return "[conteúdo aninhado omitido]" + return item + if isinstance(item, dict): + out: dict[str, Any] = {} + for idx, (key, raw) in enumerate(item.items()): + if idx >= max_items: + truncated = True + out["_omitted_fields"] = max(0, len(item) - max_items) + break + key_s = str(key) + if key_s.lower() in self._LLM_CONTEXT_DROP_KEYS: + truncated = True + continue + out[key_s] = compact(raw, depth + 1) + return out + if isinstance(item, (list, tuple, set)): + seq = list(item) + if len(seq) > max_items: + truncated = True + out = [compact(child, depth + 1) for child in seq[:max_items]] + if len(seq) > max_items: + out.append(f"[+{len(seq) - max_items} itens omitidos]") + return out + if isinstance(item, str) and len(item) > 4000: + truncated = True + return item[:4000] + "…[texto truncado]" + return item + + try: + rendered = json.dumps(compact(value), ensure_ascii=False, default=str, separators=(",", ":")) + except Exception: + rendered = str(value) + if len(rendered) > max_chars: + truncated = True + rendered = rendered[:max_chars] + "…[contexto truncado pelo framework]" + if truncated: + return rendered + "\n[observação: payload técnico/duplicado foi compactado; fatos preservados dentro do orçamento]" + return rendered + + @staticmethod + def _is_context_length_error(exc: Exception) -> bool: + text = str(exc).lower() + markers = ( + "maximum context length", + "max context length", + "context_length_exceeded", + "input length", + "too many tokens", + ) + return any(marker in text for marker in markers) + + def _compact_messages_for_retry( + self, + messages: list[dict[str, str]], + *, + max_total_chars: int = 60000, + ) -> list[dict[str, str]]: + """Emergency second-pass budget used only after provider rejection.""" + if not messages: + return messages + system_budget = min(20000, max_total_chars // 3) + remaining = max_total_chars - system_budget + compacted: list[dict[str, str]] = [] + for index, message in enumerate(messages): + content = str(message.get("content") or "") + role = str(message.get("role") or "user") + if role == "system": + budget = system_budget + else: + non_system_left = max(1, sum(1 for m in messages[index:] if str(m.get("role") or "") != "system")) + budget = max(4000, remaining // non_system_left) + remaining = max(0, remaining - budget) + if len(content) > budget: + content = content[:budget] + "…[mensagem compactada após limite de contexto]" + compacted.append({"role": role, "content": content}) + return compacted + # ------------------------------------------------------------------ # Messages / LLM / cache # ------------------------------------------------------------------ @@ -3337,19 +3465,26 @@ class AgentRuntimeMixin: f"Intent/rota escolhidos pelo framework:\nintent={state.get('intent')} route={state.get('route')}", ]) if include_business_context: - sections.append(f"BusinessContext canônico:\n{runtime.business_context or '[sem business_context]'}") + sections.append( + "BusinessContext canônico:\n" + + self._compact_llm_value(runtime.business_context or "[sem business_context]", max_chars=6000) + ) if mcp_results is not None: - sections.append(f"Resultados MCP normalizados pelo framework:\n{mcp_results}") + sections.append( + "Resultados MCP normalizados pelo framework:\n" + + self._compact_llm_value(mcp_results, max_chars=18000) + ) transaction_evidence = self.transaction_evidence_for_turn(state, mcp_results) if transaction_evidence: sections.append( "Evidências operacionais de transações anteriores relevantes ao recurso atual " - f"(persistidas pelo framework, não inferidas pela memória conversacional):\n{transaction_evidence}" + "(persistidas pelo framework, não inferidas pela memória conversacional):\n" + + self._compact_llm_value(transaction_evidence, max_chars=12000) ) if rag_context is not None: sections.append(f"Contexto de conhecimento (RAG):\n{rag_context or '[sem contexto RAG]'}") if rag_metadata is not None: - sections.append(f"Metadados RAG:\n{rag_metadata}") + sections.append("Metadados RAG:\n" + self._compact_llm_value(rag_metadata, max_chars=6000)) provider = str(rag_metadata.get("provider") or getattr(getattr(self, "settings", None), "RAG_PROVIDER", "standard")) grounded_only = bool(getattr(getattr(self, "settings", None), "RAG_GROUNDED_ONLY", False)) if provider == "kbdb": @@ -3363,7 +3498,7 @@ class AgentRuntimeMixin: "- Se o RAG estiver vazio, bloqueado ou com erro, ainda é permitido responder apenas a partes comprovadas por MCP/business context; não invente a parte documental ausente." ) for title, value in (extra_sections or {}).items(): - sections.append(f"{title}:\n{value}") + sections.append(f"{title}:\n" + self._compact_llm_value(value, max_chars=10000)) return MessageBuilder(state).system(system_prompt).user("\n\n".join(sections)).build() async def _cache_get(self, key: str): @@ -3425,7 +3560,33 @@ class AgentRuntimeMixin: return cached if telemetry: await telemetry.event("cache.llm.miss", {"agent": agent_name, "key": key}, kind="cache") - answer = await self.llm.ainvoke(messages, profile_name=agent_name, component_name=agent_name, generation_name=f"llm.{agent_name}") + try: + answer = await self.llm.ainvoke( + messages, + profile_name=agent_name, + component_name=agent_name, + generation_name=f"llm.{agent_name}", + ) + except Exception as exc: + if not self._is_context_length_error(exc): + raise + retry_messages = self._compact_messages_for_retry(messages) + if telemetry: + await telemetry.event( + "llm.context.compacted_retry", + { + "agent": agent_name, + "original_chars": sum(len(str(m.get("content") or "")) for m in messages), + "retry_chars": sum(len(str(m.get("content") or "")) for m in retry_messages), + }, + kind="llm", + ) + answer = await self.llm.ainvoke( + retry_messages, + profile_name=agent_name, + component_name=agent_name, + generation_name=f"llm.{agent_name}.context_retry", + ) await self._cache_set(key, answer, ttl) return answer diff --git a/libs/agent_framework/src/agent_framework/security/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/security/__pycache__/__init__.cpython-313.pyc index 2ee9826b89f4d2efacbce5c2d3f4315b6d695096..e4e83433895fbc18f5f7a703db6fcbf0b3baf7c5 100644 GIT binary patch delta 13 UcmZ3_Ie~M-duGPK$^0w}03u%mi~s-t delta 44 zcmbQhxt?>wduD|K{oK3~{glL#ME%6{)Vz}TGyG=B3QjEC4bN1_1y7 delta 45 zcmbPJvAbeJE3-nGer{fgeoA6VqJCm}YFr%n5S4jH?KrLS>Lg^w0NRt7XY~>3ljhU delta 34 ncmcb@c$ty=GcPX}0|-2rI+5F$yGTDbuS7pZ-#6HEqE{CHr%DPN diff --git a/libs/agent_framework/src/agent_framework/sse/__pycache__/events.cpython-313.pyc b/libs/agent_framework/src/agent_framework/sse/__pycache__/events.cpython-313.pyc index a22fe76a0f3bbf1c6211f1c069d7bacccf1ad09b..ff084315766d52c634f0e2981dd85af6940d7f20 100644 GIT binary patch delta 38 scmezD^~H<(GcPX}0}zCtowkwtJ2OwAer{fgezLw}acS{pUY0aP00XlOu>b%7 delta 37 qcmez3_1TO2GcPX}0|-2rx{>=kGk1Z0ZeEFgioS2K=Vm^ZG(`aI-3z$@ diff --git a/libs/agent_framework/src/agent_framework/supervisor/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/supervisor/__pycache__/__init__.cpython-313.pyc index 950d0ecf976aca7c2adb680a7ffc31263333cfed..a1defb9b480adccdafaf03344669936056da25ec 100644 GIT binary patch delta 35 pcmcb`c$<;?GcPX}0}zCtoi>r%n5RlVH?KrLS>Lg^w0NTDL;$;S3oifw delta 34 ocmcc3c#DzyGcPX}0}wDhm^zW$n7dLxH?KrLMc+5rbE4No0I91AIRF3v diff --git a/libs/agent_framework/src/agent_framework/supervisor/__pycache__/router_supervisor.cpython-313.pyc b/libs/agent_framework/src/agent_framework/supervisor/__pycache__/router_supervisor.cpython-313.pyc index 2c9b2f68fc1af5619fa0baa61513ded7991b88c9..3359cc74f134991726aceed1ccb783f7e8088495 100644 GIT binary patch delta 20 acmey$^p%PGGcPX}0}u#ZnY58RixB`phy}0! delta 20 acmey$^p%PGGcPX}0}#C2IdLO*79#*g!Uk&q diff --git a/libs/agent_framework/src/agent_framework/supervisor/__pycache__/supervisor.cpython-313.pyc b/libs/agent_framework/src/agent_framework/supervisor/__pycache__/supervisor.cpython-313.pyc index 1da17c2981a60192f67333301c0e7791d770c962..08a3aab28b88e9f5b5ff1dc616f862ce9c9562b0 100644 GIT binary patch delta 38 scmX@Fc0rB%GcPX}0}zCtowkv?kC~@NKR2&LKUv?gxU_il66V$X0P1uMi~s-t delta 37 rcmcbhc3zG9GcPX}0}wDhn7Wa>kD0q#KR2&LKSkd+*mLtz=GFWF)yoT( diff --git a/libs/agent_framework/src/agent_framework/workflows/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/workflows/__pycache__/__init__.cpython-313.pyc index 4ab9955c8dbbfd6b8e4a70399ecc2f2a7fa5c7e8..0bd6d734159fbba247704db7f802c0e311295e91 100644 GIT binary patch delta 37 rcmaFI_MVOVGcPX}0}zCtowkvCJ`+!+er{fgezLw}acS}7txP)s-k=PI delta 36 qcmaFQ_KuDFGcPX}0}wDin7WaBJ`;C^er{fgeu}r8&0L9q~qW}N^ delta 37 rcmeC+Zs+Fy%*)Hg00fK=rf%eRW9BZ^&&?~*Pto@c_S_uHtjz=fvMdR# diff --git a/libs/agent_framework/src/agent_framework/workflows/__pycache__/input_contract.cpython-313.pyc b/libs/agent_framework/src/agent_framework/workflows/__pycache__/input_contract.cpython-313.pyc index a39e10e7a832a31765770e5179fff43986be51da..4ca4c0b780d0bc13148d2b6d9808caa20a77c3e7 100644 GIT binary patch delta 38 scmccSa@~ddGcPX}0}zCtowkvC9Wzh8er{fgezLw}acS}9Bg~WJ0QdS04*&oF delta 37 rcmccaa?OSNGcPX}0}wDin7WaB9W!^Ger{fgeu}-*f diff --git a/libs/agent_framework/src/agent_framework/workflows/__pycache__/models.cpython-313.pyc b/libs/agent_framework/src/agent_framework/workflows/__pycache__/models.cpython-313.pyc index 0bbab8f2e94d8237f9fca80adc2864d79128aeb1..730f0f6463ee2725e0eedc57db453e0d6fe815b0 100644 GIT binary patch delta 38 scmexr{mq*DGcPX}0}zCtowkwt6BAFler{fgezLw}acS{p4(7K~008a{5dZ)H delta 37 rcmexn{neWLGcPX}0}wDin7Wbs6BBoter{fgeu}q-n7 diff --git a/libs/agent_framework/src/agent_framework/workflows/__pycache__/registry.cpython-313.pyc b/libs/agent_framework/src/agent_framework/workflows/__pycache__/registry.cpython-313.pyc index f6f021adf300f60996b6361669eacb676053c8e6..93500be293bfcaf212b8ca9ceefdb97ab11b1514 100644 GIT binary patch delta 38 scmdlfv`dKlGcPX}0}zCtowkwt6eCZier{fgezLw}acS}92aJ*I0OJh|PXGV_ delta 37 qcmdlbv{Q)tGcPX}0|-2rx{>=7BX@;R^er{fgezLw}acS}9_l&DK0Nox8iU0rr delta 37 rcmbO&I!l!MGcPX}0}wDin7WbsCL?#1er{fgeu}OHO9Y z5t;m_nwKS%AxL@hMJM6OYpPTPRY6)oAe1STF_bk(ZSun^QC>}m7*LcaNP99PyYOU( zdKG@2XkEBCf3(JA!8%!Set+g*!BBn!#%O)G98AxIYR$=T4O< z^%)r$if%JZR%uk59MX7@F>-Q!iTPyTCL>1c$qh}#Odq%=3zo@noDjV%?tekRe{z4R z;$)HLc-Ai>3;d$fxaL#ca?G@snqR6Kb?sp4eo z=J?41WpdmnL@$f`Ul8!W!!I^@esdP1`(&<`NJhQQDJ|}dd`_YsRt!f~8GZE_kE*F} z-r0Je#m1YFmG1$c;0IO^;{zLmxYP%BFp~qsz>% diff --git a/libs/agent_framework/src/agent_framework/workflows/__pycache__/tool_executor.cpython-313.pyc b/libs/agent_framework/src/agent_framework/workflows/__pycache__/tool_executor.cpython-313.pyc index 07ffe8975760a34efbe961df22562799072c0f21..b80ecdc29c862ea776cb9670e0d9b3f1adcf0b23 100644 GIT binary patch delta 38 scmZ3-zn-7_GcPX}0}zCtowkvCHX~1+er{fgezLw}acS}9jf{U;0o*zad;kCd delta 37 rcmZ3_zmA{#GcPX}0}wDin7WaBHY0bfer{fgeu}UyxXon44Ri JJ~@qPBLKPd5*Ppg diff --git a/tests/__pycache__/test_transaction_state_regression_matrix.cpython-313-pytest-9.0.2.pyc b/tests/__pycache__/test_transaction_state_regression_matrix.cpython-313-pytest-9.0.2.pyc index 4e295d22f564bb6296062b9e4ac33f2788e47def..d3d04a813ea4b3166b7a2e7b3483533d6375c731 100644 GIT binary patch delta 37 tcmcaLjrrm<<_&>7V$u4!c_sQOi6x2p$)!a_sd**wX_*z93wU1b0{|A94^jXC delta 46 zcmcaOjrrCz<_&>7@+tbcc_sQOi6x2piRr0%CGpAmc_oR(@oAYA<@rU~o6~t-?E?U; CWD^kp diff --git a/tests/test_llm_context_compaction.py b/tests/test_llm_context_compaction.py new file mode 100644 index 0000000..cdfcad2 --- /dev/null +++ b/tests/test_llm_context_compaction.py @@ -0,0 +1,93 @@ +import pytest + +from agent_framework.runtime.agent_runtime import AgentRuntimeMixin + + +class DummyRuntime(AgentRuntimeMixin): + def __init__(self, llm=None): + self.llm = llm + self.cache = None + self.telemetry = None + self.settings = None + + +class ContextFailThenOkLLM: + def __init__(self): + self.calls = [] + + async def ainvoke(self, messages, **kwargs): + self.calls.append((messages, kwargs)) + if len(self.calls) == 1: + raise RuntimeError("Input length (134212) exceeds model's maximum context length (131072)") + return "ok" + + +def test_compact_llm_value_drops_recursive_runtime_payload_but_keeps_business_facts(): + runtime = DummyRuntime() + payload = { + "result": { + "subject": "Tamboro Mensal", + "success": True, + "service": {"details": {"valor": "14,99"}}, + "state": {"session": {"secret": "must-not-leak"}, "huge": "x" * 20000}, + "business_events": [{"payload": "x" * 20000}], + } + } + rendered = runtime._compact_llm_value(payload, max_chars=8000) + assert "Tamboro Mensal" in rendered + assert "14,99" in rendered + assert "must-not-leak" not in rendered + assert "business_events" not in rendered + assert len(rendered) < 9000 + + +def test_build_messages_bounds_mcp_and_transaction_evidence(): + runtime = DummyRuntime() + giant = { + "tool_name": "cancelar_vas_avulso", + "ok": True, + "result": { + "subject": "Tamboro Mensal", + "validatedAmount": "14,99", + "state": {"payload": "x" * 100000}, + "services": [{"name": f"svc-{i}", "details": {"valor": "1,00"}} for i in range(100)], + }, + } + state = { + "user_text": "isso mesmo, pode cancelar", + "sanitized_input": "isso mesmo, pode cancelar", + "intent": "state:WAITING_CONFIRMATION", + "route": "contestacao_agent", + "business_context": {"customer_key": "11999999999"}, + "transaction_evidence": [{ + "transaction_id": "tx-1", + "tool_name": "cancelar_vas_avulso", + "arguments": {"subject": "Tamboro Mensal"}, + "status": "COMPLETED", + "result": giant, + }], + } + messages = runtime.build_messages(state, system_prompt="system", mcp_results=[giant]) + total = sum(len(m["content"]) for m in messages) + joined = "\n".join(m["content"] for m in messages) + assert total < 50000 + assert "Tamboro Mensal" in joined + assert "14,99" in joined + assert "x" * 5000 not in joined + + +@pytest.mark.asyncio +async def test_context_length_error_retries_once_with_compacted_messages(): + llm = ContextFailThenOkLLM() + runtime = DummyRuntime(llm=llm) + messages = [ + {"role": "system", "content": "s" * 30000}, + {"role": "user", "content": "u" * 120000}, + ] + answer = await runtime._invoke_llm_cached({}, "ContestacaoAgent", messages) + assert answer == "ok" + assert len(llm.calls) == 2 + first_chars = sum(len(m["content"]) for m in llm.calls[0][0]) + second_chars = sum(len(m["content"]) for m in llm.calls[1][0]) + assert second_chars < first_chars + assert second_chars <= 61000 diff --git a/tests/unit/__pycache__/test_langgraph_checkpoint_interrupt_controlled.cpython-313-pytest-9.0.2.pyc b/tests/unit/__pycache__/test_langgraph_checkpoint_interrupt_controlled.cpython-313-pytest-9.0.2.pyc index b2826cd4f0d6a0b702d2a00a7fa218450da508cb..98335bb23037350a5403ead4e88511b5045ef23a 100644 GIT binary patch delta 37 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 F@IMlA?w$Yu delta 1312 zcmZ9LeP~-%6u@({^rgvLyMC-qn=UTt4DOXRX$Q;DwlL=h2)aMkwFSE+eQmRm58q4g zd(pN!=5%QbZkFy0Md%oURH>VzzJ2+%q0SbEs4ElUA@<< zG_SB~G+Eesw6(%&(8`3>qLmBtp{)~EhgKo1{(w`dTB5BLX3MIk>85I?bj{d>W7xpH z-gE3oR$>$Eq&2)%iL1c13!FCQd%E&L+ME~QUT;S&kcNg<5kbg_KpB6ZIF$g#JHL!E=*S;`Ygi!oJY`r%gk&aMe0Vd;J z4VOqS6SflK2-`*X#jn7<_(JW6H2blb&5g8fwOz<iJ|bCC>66M zyuy6e None: persisted = repo.saved[1] assert persisted["pending_writes"][0]["value"] == {"ok": True} + + +def test_stale_pending_write_cannot_replace_newer_checkpoint() -> None: + """A delayed write for cp1 must never make cp1 latest after cp2 exists.""" + repo = _Repo() + saver = RepositoryCheckpointSaver(SimpleNamespace(), repository=repo) + + cfg0 = {"configurable": {"thread_id": "tx-thread"}} + cp1_cfg = asyncio.run(saver.aput(cfg0, {"id": "cp1", "v": 1, "channel_values": {"transaction_status": "COMPLETED"}}, {}, {})) + cp2_cfg = asyncio.run(saver.aput(cp1_cfg, {"id": "cp2", "v": 1, "channel_values": {"transaction_status": "AWAITING_CONFIRMATION", "confirmation_required": True}}, {}, {})) + + # Simulates aput_writes from the older cp1 finishing after cp2 was persisted. + asyncio.run(saver.aput_writes(cp1_cfg, [("result", {"old": True})], "late-task")) + + assert repo.saved is not None + latest = repo.saved[1] + assert latest["checkpoint_id"] == "cp2" + assert latest["checkpoint"]["channel_values"]["transaction_status"] == "AWAITING_CONFIRMATION" + assert "pending_writes" not in latest or not any( + isinstance(item, dict) and item.get("task_id") == "late-task" + for item in latest.get("pending_writes", []) + ) + + # A write for the actual latest checkpoint is still accepted. + asyncio.run(saver.aput_writes(cp2_cfg, [("result", {"new": True})], "current-task")) + latest = repo.saved[1] + assert latest["checkpoint_id"] == "cp2" + assert any(item.get("task_id") == "current-task" for item in latest.get("pending_writes", [])) diff --git a/tests/unit/test_workflow_terminal_snapshot_semantics.py b/tests/unit/test_workflow_terminal_snapshot_semantics.py index 7436db5..1fe4498 100644 --- a/tests/unit/test_workflow_terminal_snapshot_semantics.py +++ b/tests/unit/test_workflow_terminal_snapshot_semantics.py @@ -188,3 +188,31 @@ def test_snapshot_interrupts_deduplicates_task_and_persisted_shapes(tmp_path: Pa ) assert runtime._snapshot_interrupts(snapshot) == [payload] + +@pytest.mark.asyncio +async def test_aresume_ignores_stale_interrupt_after_advancing_to_terminal_node(tmp_path: Path, monkeypatch): + _write_workflow(tmp_path) + runtime = WorkflowRuntime(FileWorkflowRepository(tmp_path), actions=WorkflowActionRegistry()) + state = _terminal_state("exec-stale") + # Shape observed after resuming invoice_explanation: the durable snapshot can + # still expose the interrupt from the old pause although current_node has + # already advanced to the terminal handoff/finalization node. + stale = SimpleNamespace(value={"node": "old_pause", "prompt": "old prompt"}) + task = SimpleNamespace(interrupts=(stale,)) + snapshot = SimpleNamespace(next=("finish__continue",), tasks=(task,), values=state) + monkeypatch.setattr(runtime, "_compile", lambda definition: _FakeGraph(state, snapshot)) + + langgraph_module = ModuleType("langgraph") + types_module = ModuleType("langgraph.types") + class _Command: + def __init__(self, **kwargs): + self.kwargs = kwargs + types_module.Command = _Command + monkeypatch.setitem(sys.modules, "langgraph", langgraph_module) + monkeypatch.setitem(sys.modules, "langgraph.types", types_module) + + result = await runtime.aresume("terminal", "exec-stale", "nao") + + assert result.status == "COMPLETED" + assert result.pause is None + assert result.state["current_node"] == "finish"