From 762f6fb0246f8384c55f71544f34de65a3dd781a Mon Sep 17 00:00:00 2001 From: "cristiano.hoshikawa" Date: Thu, 20 Aug 2026 00:23:50 -0300 Subject: [PATCH] bugfixes: transaction parameter collector, generic formatting messages, guardrails, prompts. Testing contas --- .../app/agents/runtime.py | 3 + .../app/presentation/__init__.py | 3 + .../tool_renderers.cpython-313.pyc | Bin 0 -> 4405 bytes .../app/presentation/tool_renderers.py | 74 +++ .../config/tools.yaml | 12 + .../app/presentation/__init__.py | 3 + .../tool_renderers.cpython-313.pyc | Bin 0 -> 4412 bytes .../app/presentation/tool_renderers.py | 74 +++ .../agent_template_backend/config/tools.yaml | 12 + .../app/agents/runtime.py | 3 + .../app/presentation/__init__.py | 3 + .../tool_renderers.cpython-313.pyc | Bin 0 -> 4402 bytes .../app/presentation/tool_renderers.py | 74 +++ .../agent_template_backend/config/tools.yaml | 12 + .../app/agents/runtime.py | 3 + .../app/presentation/__init__.py | 3 + .../tool_renderers.cpython-313.pyc | Bin 0 -> 4392 bytes .../app/presentation/tool_renderers.py | 74 +++ .../agent_template_backend/config/tools.yaml | 12 + .../Offline_Workflow_Regression/README.md | 2 +- .../app/agents/runtime.py | 3 + .../app/presentation/__init__.py | 3 + .../tool_renderers.cpython-313.pyc | Bin 0 -> 4401 bytes .../app/presentation/tool_renderers.py | 74 +++ .../agent_template_backend/config/tools.yaml | 12 + docs/features/01_authentication.md | 165 ++++++ ...02_deterministic_transactional_workflow.md | 183 +++++++ .../03_domain_requested_llm_composition.md | 157 ++++++ docs/features/04_domain_requested_rag.md | 167 ++++++ docs/features/05_long_term_memory.md | 167 ++++++ .../06_offline_workflow_regression.md | 163 ++++++ docs/features/07_pause_resume_workflow.md | 165 ++++++ docs/features/08_route_stickiness.md | 151 ++++++ docs/features/09_voice_interruption_replay.md | 153 ++++++ docs/features/10_workflow_error_recovery.md | 167 ++++++ docs/features/11_clarification.md | 169 ++++++ docs/features/12_durable_idempotency.md | 163 ++++++ .../features/13_dynamic_transaction_states.md | 157 ++++++ docs/features/14_post_finalization_replay.md | 159 ++++++ docs/features/15_retrieval_tool_guardrails.md | 171 ++++++ docs/features/README.md | 64 ++- .../src/agent_framework.egg-info/SOURCES.txt | 8 + .../__pycache__/__init__.cpython-313.pyc | Bin 267 -> 427 bytes .../__pycache__/idempotency.cpython-313.pyc | Bin 0 -> 5711 bytes .../__pycache__/observer.cpython-313.pyc | Bin 13256 -> 17571 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 489 -> 563 bytes .../composite_publisher.cpython-313.pyc | Bin 2444 -> 2518 bytes .../__pycache__/event_builder.cpython-313.pyc | Bin 1202 -> 1276 bytes .../__pycache__/factory.cpython-313.pyc | Bin 3664 -> 4012 bytes .../__pycache__/publisher.cpython-313.pyc | Bin 1814 -> 1888 bytes .../tim_payload_mapper.cpython-313.pyc | Bin 8393 -> 9302 bytes .../__pycache__/tim_sequence.cpython-313.pyc | Bin 15277 -> 17577 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 456 -> 530 bytes .../__pycache__/kafka.cpython-313.pyc | Bin 1754 -> 1828 bytes .../__pycache__/langfuse.cpython-313.pyc | Bin 22279 -> 22399 bytes .../__pycache__/oci_streaming.cpython-313.pyc | Bin 1511 -> 1837 bytes .../__pycache__/pubsub.cpython-313.pyc | Bin 7382 -> 7456 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 345 -> 419 bytes .../usage_repository.cpython-313.pyc | Bin 15628 -> 15702 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 155 -> 229 bytes .../cache/__pycache__/cache.cpython-313.pyc | Bin 16465 -> 16539 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 158 -> 232 bytes .../__pycache__/adapters.cpython-313.pyc | Bin 4114 -> 4188 bytes .../channels/__pycache__/base.cpython-313.pyc | Bin 1738 -> 1812 bytes .../__pycache__/gateway.cpython-313.pyc | Bin 5713 -> 5787 bytes .../__pycache__/interruption.cpython-313.pyc | Bin 0 -> 6472 bytes .../__pycache__/transcription.cpython-313.pyc | Bin 0 -> 1445 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 865 -> 939 bytes .../checkpoint_repository.cpython-313.pyc | Bin 27072 -> 27179 bytes .../langgraph_saver.cpython-313.pyc | Bin 11186 -> 11260 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 196 -> 230 bytes .../agent_registry.cpython-313.pyc | Bin 6889 -> 6963 bytes .../__pycache__/settings.cpython-313.pyc | Bin 12232 -> 12585 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 287 -> 322 bytes .../mcp_gateway_client.cpython-313.pyc | Bin 3313 -> 3348 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 1443 -> 1517 bytes .../__pycache__/base.cpython-313.pyc | Bin 1317 -> 1391 bytes .../__pycache__/config_loader.cpython-313.pyc | Bin 6891 -> 7265 bytes .../__pycache__/custom_rails.cpython-313.pyc | Bin 4338 -> 4412 bytes .../framework_llm_client.cpython-313.pyc | Bin 16000 -> 18079 bytes .../__pycache__/llm_rails.cpython-313.pyc | Bin 6584 -> 6658 bytes .../output_supervisor.cpython-313.pyc | Bin 16045 -> 16119 bytes .../parallel_executor.cpython-313.pyc | Bin 19853 -> 19927 bytes .../__pycache__/pipeline.cpython-313.pyc | Bin 10831 -> 10905 bytes .../__pycache__/rail_action.cpython-313.pyc | Bin 596 -> 670 bytes .../__pycache__/rail_decision.cpython-313.pyc | Bin 1547 -> 1621 bytes .../__pycache__/rail_result.cpython-313.pyc | Bin 946 -> 1020 bytes .../__pycache__/rails.cpython-313.pyc | Bin 29583 -> 31612 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 2927 -> 2978 bytes .../__pycache__/_compat.cpython-313.pyc | Bin 2387 -> 2461 bytes .../contestation_validation.cpython-313.pyc | Bin 21084 -> 22886 bytes .../__pycache__/contracts.cpython-313.pyc | Bin 6831 -> 6905 bytes .../__pycache__/input_size.cpython-313.pyc | Bin 3488 -> 3562 bytes .../__pycache__/llm_adapter.cpython-313.pyc | Bin 3723 -> 3815 bytes .../__pycache__/llm_client.cpython-313.pyc | Bin 12872 -> 7349 bytes .../__pycache__/llm_rails.cpython-313.pyc | Bin 8823 -> 8897 bytes .../output_sanitization.cpython-313.pyc | Bin 12202 -> 13926 bytes .../__pycache__/pipeline.cpython-313.pyc | Bin 12593 -> 12667 bytes .../calibrated/contestation_validation.py | 44 +- .../__pycache__/__init__.cpython-313.pyc | Bin 415 -> 489 bytes .../__pycache__/_context.cpython-313.pyc | Bin 6803 -> 5391 bytes .../ausencia_oferta_proativa.cpython-313.pyc | Bin 10682 -> 9580 bytes .../__pycache__/coerencia.cpython-313.pyc | Bin 0 -> 9496 bytes .../__pycache__/dlex_in.cpython-313.pyc | Bin 1246 -> 1320 bytes .../__pycache__/dlex_out.cpython-313.pyc | Bin 1533 -> 1607 bytes .../__pycache__/fallback.cpython-313.pyc | Bin 14612 -> 17205 bytes .../__pycache__/fraseologia.cpython-313.pyc | Bin 0 -> 6068 bytes .../__pycache__/out_of_scope.cpython-313.pyc | Bin 17572 -> 17099 bytes .../prompts/__pycache__/pinj.cpython-313.pyc | Bin 9764 -> 8323 bytes .../__pycache__/ragsec.cpython-313.pyc | Bin 1047 -> 1121 bytes .../__pycache__/revprec.cpython-313.pyc | Bin 10328 -> 5422 bytes .../prompts/__pycache__/tox.cpython-313.pyc | Bin 571 -> 645 bytes .../toxicidade_output.cpython-313.pyc | Bin 865 -> 939 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 1609 -> 1683 bytes .../rails/__pycache__/alcada.cpython-313.pyc | Bin 4932 -> 5015 bytes .../rails/__pycache__/anatel.cpython-313.pyc | Bin 9259 -> 9164 bytes .../__pycache__/confirmation.cpython-313.pyc | Bin 10949 -> 11032 bytes .../rails/__pycache__/dlex_in.cpython-313.pyc | Bin 3221 -> 3295 bytes .../__pycache__/dlex_out.cpython-313.pyc | Bin 3273 -> 3347 bytes .../rails/__pycache__/ragsec.cpython-313.pyc | Bin 5355 -> 5429 bytes .../rails/__pycache__/revprec.cpython-313.pyc | Bin 5363 -> 5437 bytes .../rails/__pycache__/tox.cpython-313.pyc | Bin 8178 -> 8252 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 479 -> 553 bytes .../rules/__pycache__/alcada.cpython-313.pyc | Bin 1823 -> 1897 bytes .../__pycache__/pinj_patterns.cpython-313.pyc | Bin 3664 -> 3738 bytes .../__pycache__/tox_blocklist.cpython-313.pyc | Bin 1448 -> 1522 bytes .../src/agent_framework/guardrails/rails.py | 62 +-- .../__pycache__/__init__.cpython-313.pyc | Bin 389 -> 424 bytes .../__pycache__/mcp_mapper.cpython-313.pyc | Bin 4673 -> 4708 bytes .../__pycache__/models.cpython-313.pyc | Bin 3125 -> 3160 bytes .../__pycache__/resolver.cpython-313.pyc | Bin 4694 -> 4729 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 560 -> 634 bytes .../judges/__pycache__/judge.cpython-313.pyc | Bin 36374 -> 36448 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 167 -> 241 bytes .../__pycache__/llm_client.cpython-313.pyc | Bin 6044 -> 6118 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 175 -> 249 bytes .../prompts/__pycache__/aluc.cpython-313.pyc | Bin 6390 -> 6464 bytes .../prompts/__pycache__/csi.cpython-313.pyc | Bin 1259 -> 1333 bytes .../__pycache__/fallback.cpython-313.pyc | Bin 7946 -> 8029 bytes .../prompts/__pycache__/rqlt.cpython-313.pyc | Bin 1097 -> 1171 bytes .../prompts/__pycache__/vctn.cpython-313.pyc | Bin 568 -> 642 bytes .../llm/__pycache__/__init__.cpython-313.pyc | Bin 153 -> 227 bytes .../llm/__pycache__/base.cpython-313.pyc | Bin 761 -> 835 bytes .../profile_resolver.cpython-313.pyc | Bin 9221 -> 9295 bytes .../llm/__pycache__/providers.cpython-313.pyc | Bin 33718 -> 35982 bytes .../mcp/__pycache__/__init__.cpython-313.pyc | Bin 454 -> 489 bytes .../mcp/__pycache__/client.cpython-313.pyc | Bin 18407 -> 18442 bytes .../mcp/__pycache__/models.cpython-313.pyc | Bin 2063 -> 2152 bytes .../mcp/__pycache__/registry.cpython-313.pyc | Bin 4677 -> 4756 bytes .../__pycache__/tool_policy.cpython-313.pyc | Bin 4688 -> 4753 bytes .../__pycache__/tool_router.cpython-313.pyc | Bin 13999 -> 14034 bytes .../src/agent_framework/mcp/models.py | 5 + .../src/agent_framework/mcp/registry.py | 1 + .../__pycache__/__init__.cpython-313.pyc | Bin 1077 -> 1151 bytes .../long_term_extractor.cpython-313.pyc | Bin 2455 -> 2529 bytes .../long_term_memory.cpython-313.pyc | Bin 6781 -> 6855 bytes .../long_term_models.cpython-313.pyc | Bin 1690 -> 1764 bytes .../long_term_store.cpython-313.pyc | Bin 29128 -> 29202 bytes .../message_history.cpython-313.pyc | Bin 8301 -> 8375 bytes .../summary_memory.cpython-313.pyc | Bin 12452 -> 12526 bytes .../__pycache__/summary_store.cpython-313.pyc | Bin 9462 -> 9536 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 156 -> 230 bytes .../__pycache__/identity.cpython-313.pyc | Bin 3407 -> 3481 bytes .../__pycache__/session.cpython-313.pyc | Bin 2650 -> 2724 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 1336 -> 1410 bytes .../__pycache__/context.cpython-313.pyc | Bin 7328 -> 7402 bytes .../__pycache__/event_bus.cpython-313.pyc | Bin 3574 -> 3648 bytes .../guardrail_events.cpython-313.pyc | Bin 1992 -> 2066 bytes .../__pycache__/ic_events.cpython-313.pyc | Bin 567 -> 641 bytes .../__pycache__/judge_events.cpython-313.pyc | Bin 1352 -> 1426 bytes .../langgraph_telemetry.cpython-313.pyc | Bin 4905 -> 4979 bytes .../__pycache__/llm_advisors.cpython-313.pyc | Bin 2879 -> 2953 bytes .../__pycache__/noc_contract.cpython-313.pyc | Bin 5016 -> 5090 bytes .../__pycache__/noc_otel.cpython-313.pyc | Bin 6263 -> 6337 bytes .../__pycache__/observer.cpython-313.pyc | Bin 5570 -> 4709 bytes .../__pycache__/otel.cpython-313.pyc | Bin 3353 -> 3427 bytes .../streaming_events.cpython-313.pyc | Bin 1776 -> 1850 bytes .../__pycache__/telemetry.cpython-313.pyc | Bin 50530 -> 51538 bytes .../__pycache__/token_cost.cpython-313.pyc | Bin 8538 -> 8612 bytes .../workflow_events.cpython-313.pyc | Bin 3271 -> 3345 bytes .../oci/__pycache__/__init__.cpython-313.pyc | Bin 153 -> 227 bytes .../oci/__pycache__/auth.cpython-313.pyc | Bin 3185 -> 3259 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 161 -> 235 bytes .../__pycache__/oracle_store.cpython-313.pyc | Bin 44897 -> 44971 bytes .../__pycache__/sqlite_store.cpython-313.pyc | Bin 14960 -> 15034 bytes .../agent_framework/presentation/__init__.py | 15 + .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 470 bytes .../__pycache__/renderers.cpython-313.pyc | Bin 0 -> 4333 bytes .../agent_framework/presentation/renderers.py | 104 ++++ .../rag/__pycache__/__init__.cpython-313.pyc | Bin 651 -> 725 bytes .../embedding_provider.cpython-313.pyc | Bin 6468 -> 6542 bytes .../__pycache__/graph_store.cpython-313.pyc | Bin 5469 -> 5543 bytes .../rag/__pycache__/ingest.cpython-313.pyc | Bin 12522 -> 12596 bytes .../__pycache__/rag_service.cpython-313.pyc | Bin 9991 -> 10065 bytes .../__pycache__/vector_store.cpython-313.pyc | Bin 18597 -> 18671 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 162 -> 236 bytes .../session_repository.cpython-313.pyc | Bin 8531 -> 8605 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 367 -> 441 bytes .../__pycache__/config_loader.cpython-313.pyc | Bin 2238 -> 2312 bytes .../__pycache__/continuity.cpython-313.pyc | Bin 13180 -> 13254 bytes .../enterprise_router.cpython-313.pyc | Bin 14224 -> 14298 bytes .../__pycache__/models.cpython-313.pyc | Bin 2388 -> 2462 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 290 -> 364 bytes .../__pycache__/agent_runtime.cpython-313.pyc | Bin 82264 -> 128156 bytes .../agent_framework/runtime/agent_runtime.py | 488 ++++++++++++++++-- .../sse/__pycache__/__init__.cpython-313.pyc | Bin 153 -> 227 bytes .../sse/__pycache__/events.cpython-313.pyc | Bin 9529 -> 9603 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 160 -> 234 bytes .../__pycache__/supervisor.cpython-313.pyc | Bin 4630 -> 4704 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 688 -> 894 bytes .../__pycache__/graph.cpython-313.pyc | Bin 0 -> 1431 bytes .../__pycache__/models.cpython-313.pyc | Bin 3636 -> 5248 bytes .../__pycache__/registry.cpython-313.pyc | Bin 2342 -> 2377 bytes .../__pycache__/repository.cpython-313.pyc | Bin 2695 -> 2730 bytes .../__pycache__/runtime.cpython-313.pyc | Bin 9220 -> 29143 bytes .../__pycache__/tool_executor.cpython-313.pyc | Bin 1908 -> 1982 bytes .../src/agent_framework/workflows/runtime.py | 19 +- .../app/agents/runtime.py | 3 + .../app/presentation/__init__.py | 3 + .../tool_renderers.cpython-313.pyc | Bin 0 -> 4366 bytes .../app/presentation/tool_renderers.py | 74 +++ .../agent_template_backend/config/tools.yaml | 12 + .../conftest.cpython-313-pytest-9.0.2.pyc | Bin 789 -> 817 bytes ..._presentation.cpython-313-pytest-9.0.2.pyc | Bin 0 -> 5905 bytes ...ction_runtime.cpython-313-pytest-9.0.2.pyc | Bin 0 -> 8824 bytes ...nal_tool_flow.cpython-313-pytest-9.0.2.pyc | Bin 0 -> 30624 bytes ...test_generic_tool_response_presentation.py | 72 +++ .../test_mcp_parameter_extraction_runtime.py | 51 ++ tests/test_transactional_tool_flow.py | 199 +++++++ ...ckpoint_saver.cpython-313-pytest-9.0.2.pyc | Bin 0 -> 7140 bytes ..._checkpointer.cpython-313-pytest-9.0.2.pyc | Bin 0 -> 5311 bytes 231 files changed, 3999 insertions(+), 141 deletions(-) create mode 100644 Tuning-Performance/Authentication/agent_template_backend_authentication/app/presentation/__init__.py create mode 100644 Tuning-Performance/Authentication/agent_template_backend_authentication/app/presentation/__pycache__/tool_renderers.cpython-313.pyc create mode 100644 Tuning-Performance/Authentication/agent_template_backend_authentication/app/presentation/tool_renderers.py create mode 100644 Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/__init__.py create mode 100644 Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc create mode 100644 Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/tool_renderers.py create mode 100644 Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/__init__.py create mode 100644 Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc create mode 100644 Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/tool_renderers.py create mode 100644 Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/__init__.py create mode 100644 Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc create mode 100644 Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/tool_renderers.py create mode 100644 Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/__init__.py create mode 100644 Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc create mode 100644 Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/tool_renderers.py create mode 100644 docs/features/01_authentication.md create mode 100644 docs/features/02_deterministic_transactional_workflow.md create mode 100644 docs/features/03_domain_requested_llm_composition.md create mode 100644 docs/features/04_domain_requested_rag.md create mode 100644 docs/features/05_long_term_memory.md create mode 100644 docs/features/06_offline_workflow_regression.md create mode 100644 docs/features/07_pause_resume_workflow.md create mode 100644 docs/features/08_route_stickiness.md create mode 100644 docs/features/09_voice_interruption_replay.md create mode 100644 docs/features/10_workflow_error_recovery.md create mode 100644 docs/features/11_clarification.md create mode 100644 docs/features/12_durable_idempotency.md create mode 100644 docs/features/13_dynamic_transaction_states.md create mode 100644 docs/features/14_post_finalization_replay.md create mode 100644 docs/features/15_retrieval_tool_guardrails.md create mode 100644 libs/agent_framework/src/agent_framework/__pycache__/idempotency.cpython-313.pyc create mode 100644 libs/agent_framework/src/agent_framework/channels/__pycache__/interruption.cpython-313.pyc create mode 100644 libs/agent_framework/src/agent_framework/channels/__pycache__/transcription.cpython-313.pyc create mode 100644 libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/coerencia.cpython-313.pyc create mode 100644 libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/fraseologia.cpython-313.pyc create mode 100644 libs/agent_framework/src/agent_framework/presentation/__init__.py create mode 100644 libs/agent_framework/src/agent_framework/presentation/__pycache__/__init__.cpython-313.pyc create mode 100644 libs/agent_framework/src/agent_framework/presentation/__pycache__/renderers.cpython-313.pyc create mode 100644 libs/agent_framework/src/agent_framework/presentation/renderers.py create mode 100644 libs/agent_framework/src/agent_framework/workflows/__pycache__/graph.cpython-313.pyc create mode 100644 templates/agent_template_backend/app/presentation/__init__.py create mode 100644 templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc create mode 100644 templates/agent_template_backend/app/presentation/tool_renderers.py create mode 100644 tests/__pycache__/test_generic_tool_response_presentation.cpython-313-pytest-9.0.2.pyc create mode 100644 tests/__pycache__/test_mcp_parameter_extraction_runtime.cpython-313-pytest-9.0.2.pyc create mode 100644 tests/__pycache__/test_transactional_tool_flow.cpython-313-pytest-9.0.2.pyc create mode 100644 tests/test_generic_tool_response_presentation.py create mode 100644 tests/unit/__pycache__/test_langgraph_checkpoint_saver.cpython-313-pytest-9.0.2.pyc create mode 100644 tests/unit/__pycache__/test_resilient_checkpointer.cpython-313-pytest-9.0.2.pyc diff --git a/Tuning-Performance/Authentication/agent_template_backend_authentication/app/agents/runtime.py b/Tuning-Performance/Authentication/agent_template_backend_authentication/app/agents/runtime.py index e6429c4..7a1a9be 100644 --- a/Tuning-Performance/Authentication/agent_template_backend_authentication/app/agents/runtime.py +++ b/Tuning-Performance/Authentication/agent_template_backend_authentication/app/agents/runtime.py @@ -3,5 +3,8 @@ from __future__ import annotations # Compatibilidade local do template/backend. # A implementação oficial agora fica no framework para evitar duplicação entre agentes. from agent_framework.runtime import AgentRuntimeMixin, MessageBuilder, RuntimeContext +from app.presentation import register_tool_renderers + +register_tool_renderers() __all__ = ["AgentRuntimeMixin", "MessageBuilder", "RuntimeContext"] diff --git a/Tuning-Performance/Authentication/agent_template_backend_authentication/app/presentation/__init__.py b/Tuning-Performance/Authentication/agent_template_backend_authentication/app/presentation/__init__.py new file mode 100644 index 0000000..c0eba0d --- /dev/null +++ b/Tuning-Performance/Authentication/agent_template_backend_authentication/app/presentation/__init__.py @@ -0,0 +1,3 @@ +from .tool_renderers import register_tool_renderers + +__all__ = ["register_tool_renderers"] diff --git a/Tuning-Performance/Authentication/agent_template_backend_authentication/app/presentation/__pycache__/tool_renderers.cpython-313.pyc b/Tuning-Performance/Authentication/agent_template_backend_authentication/app/presentation/__pycache__/tool_renderers.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c79403de000304b0a34d273486421308878347d GIT binary patch literal 4405 zcmb_fO>7&-6`tkpa+m-5qpZJ5D_gQnS3hN+gJjk91*M{zJ*ctIgcq$1XIjJOqBv8o(l1L?Y#20Z<$+O@N`M)Ad zh8W8utEy(mMoLq4XtLw#3jB3pWg(>-3XU6^mX2dZUxI!G1U0E(1t%CXyj(c=XAxqa z=0JFaI#I0J8$}~!Il=_cP0%`AB8~_?L>P9g#8!a(sMH+SpNcJNnp_r@kZGUFn z(S>@@JQ`!W&^#03!dZ6UrFn}Pu$aCOZ}IbKO*Sk6D@$oPp;)e4D@)1*#u~QV-;>js zvdroRhK=*f_0Qa0p4c|lQ)ctTSRS&xIP;8bGYEz2YEdm6r5)|$ui zqC(nnEs+|$l~GgbLjUUup4afAtR|Gf@r>~%OqWVfx0gp5$|4wODDgQtaTnYimk((z zEe$TgLBK$JSovh^1JMVTRxEdXQB#$b_#95-I@o~-KYbjk9D3ql`L?}=V|o5(eRkmf%B$#{$G3E;Lo$B=lD~^fM%d!edOKjXJYFU7Mfq{UYOfGEvqKu#GZMvqO9jfW zQXZAC0HZzz9m_?xq=NS>C+rjyEMAA*Du7bz|Fk@(q;;~S1O*2`u$pa5#tkK{B(%kN zN?q1c2?e)6CsELekV7S(|G^I)ESl|Sx0<)aZN~JBn%wA9=tH&lA_4{;p(t~cVBt`S zFcnySgtzOd4vXE)exf2xgbJOzUI|&MxC&tFvM2$ zB@`9r;1G_`7o!5$=GfPcxNefOJ5-|8^&{?n=!5g~ge@M>scN_ZK4gerXQhaek?2S1 z@yC+oNvXgWs$#?!<}4>Uwv3+T;6$V>D_wsjE7+f;tfS99@(^pW3yNVm<)tOSyT#qn zQff%V1Vk7%jc_xmj*+SzDzHGthK@VPhi^co6MPdOkYaHOFxYXx7w{H32Ecs&I-{$I#iIhiGkUU6nP)nA6|@ zQj)NL2@N7ugr6%${6b4qjFF?Kr4ls6tedlNwCXR%hNHRy?f}du2`8# zLN{^FN7gkfy{;rvNlnVSMx`<*&=6pGAogk`<1plOwhm&mh9%k+Y=AJ-7IF>*E{*~vL>y3^3 z8+W!`+b6eMKB+f-ubSSgz+h#vd#mW}rDRtSTFS&^9y|4G_tr@9^hNX3=ytamyu2fh zRrCot?s|JSUV=f=@mzRMs9*2>Mboa(38eSurq%~n_X4f?o{zZQKyM+?TWaa}Kzv`^ zXfL+(@3!39YWiKvZ(Fuc7SD}C>yul5ocY7dr^@5_L;j1Fj&;5iXv$B09ynR5>)fsD zE!6dXl-TV3@Xnv=&i&nof^GlwBeA){o^Nb4{i^kst(#Yh-J^xz=ys$K{PvDGUh??Y zF05WypLq9MCfD{NheC#JbLd||_&;%IZQiOf+mY|(2}VI zEskZ#ZJ+xyy4ij92pS}v!3wJ%({@(3}w@vA6F?cQ)E?<4KB~z)*{yoW@Lj`CSeADlyhdOd;^0S9k#|6N^xVTP!okxD#g2$j-|*cDOLe8{wVd>pR@! zLDAOuoD0(h!Xb{v2TUAH9y{ str: + try: + return f"{float(value):.2f}".replace(".", ",") + except (TypeError, ValueError): + return str(value) + + +def render_telecom_invoice(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + return f"[{agent_label}] Fatura consultada: {result}." + + +def render_telecom_plan(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + plano = result.get("plano") + if plano is None: + return None + parts = [f"[{agent_label}] Seu plano é {plano}"] + internet_gb = result.get("internet_gb") + status = result.get("status") + if internet_gb is not None: + parts.append(f"com {internet_gb} GB") + if status is not None: + parts.append(f"status {status}") + return ", ".join(parts) + "." + + +def render_retail_order(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + status = result.get("status") + if order_id is None or status is None: + return None + lines = [f"[{agent_label}] Pedido {order_id}: status {status}."] + total = result.get("valor_total") + if total is not None: + lines.append(f"Valor total: R$ {_money_brl(total)}.") + items = result.get("itens") or [] + rendered_items: list[str] = [] + if isinstance(items, list): + for item in items: + if isinstance(item, dict): + value = item.get("descricao") or item.get("nome") or item.get("sku") + else: + value = item + if value not in (None, ""): + rendered_items.append(str(value)) + if rendered_items: + lines.append("Itens: " + "; ".join(rendered_items) + ".") + return " ".join(lines) + + +def render_retail_delivery(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + transportadora = result.get("transportadora") + codigo = result.get("codigo_rastreio") + previsao = result.get("previsao_entrega") + if any(v is None for v in (order_id, transportadora, codigo, previsao)): + return None + return ( + f"[{agent_label}] Entrega do pedido {order_id}: transportadora {transportadora}, " + f"rastreio {codigo}, previsão {previsao}." + ) + + +def register_tool_renderers() -> None: + register_tool_response_renderer("telecom.invoice", render_telecom_invoice) + register_tool_response_renderer("telecom.plan", render_telecom_plan) + register_tool_response_renderer("retail.order", render_retail_order) + register_tool_response_renderer("retail.delivery", render_retail_delivery) diff --git a/Tuning-Performance/Authentication/agent_template_backend_authentication/config/tools.yaml b/Tuning-Performance/Authentication/agent_template_backend_authentication/config/tools.yaml index d85fae1..6273371 100644 --- a/Tuning-Performance/Authentication/agent_template_backend_authentication/config/tools.yaml +++ b/Tuning-Performance/Authentication/agent_template_backend_authentication/config/tools.yaml @@ -10,6 +10,9 @@ tools: - fatura - conta - boleto + response: + mode: renderer + renderer: telecom.invoice consultar_pagamentos: description: Consulta histórico de pagamentos do cliente. mcp_server: telecom @@ -28,6 +31,9 @@ tools: asset_id: string selection_keywords: - plano + response: + mode: renderer + renderer: telecom.plan listar_servicos: description: Lista serviços ativos e adicionais VAS. mcp_server: telecom @@ -49,6 +55,9 @@ tools: - consultar pedido - status do pedido - pedido + response: + mode: renderer + renderer: retail.order consultar_entrega: description: Consulta entrega e rastreamento do pedido. mcp_server: retail @@ -61,6 +70,9 @@ tools: - rastreamento - transportadora - previsão + response: + mode: renderer + renderer: retail.delivery solicitar_troca: description: Simula abertura de solicitação de troca. mcp_server: retail diff --git a/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/__init__.py b/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/__init__.py new file mode 100644 index 0000000..c0eba0d --- /dev/null +++ b/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/__init__.py @@ -0,0 +1,3 @@ +from .tool_renderers import register_tool_renderers + +__all__ = ["register_tool_renderers"] diff --git a/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc b/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..009b7c12fbc13a60978eabb33f4e2eeba0d9df9c GIT binary patch literal 4412 zcmb_fO>7&-6`tkpa+m-5qfGr&TG^6qy85vr$+2ZitrN>urJ4y$vr$Y4#EM+0w5eTT zb|qVEQ?Nl$SO^NqXpJyHfv8A;DnJkFp{Nc$r0}6RE<>dvwki;`$RRfuc8fNrzL_N{ zOQwn*Isk`ncHaEG_s#d-JoWk92+DZkCwB%t2>p#TD#c+7%+nMIk5CjvnJF~MU`8Uc zW6CkfVwTG66gSCZ9%N6HYejcB?2LM&Je35HoKzA)5~$WjLlOyfc8!d5XMH+GlNcJNnp}4E^ZGUFn z(TTdz92#Xi(Hs-zB3ZWor8$e~x0v2AZ}D>(O*Sk6D~lO9saURCD~rlF#u~QV-;*;- zWtr6t3f5=lfn)@SKJhWHqS_Tvfob3uzTB471$AvZ~8T;sH66cmu}4j_;M{ zGL!|_wxJ|u<>Xy3{(!u=IIsx*fbCGH4U`>Z`$g|xT(R7V1x-~}60);?F{PZhO z<&@$C{fXT`Zz0gT8QnTj44gN`^Z(lO27jJ4J;$FS1~dZ=>%;G6 zKNDM?u+aQk_rff1w|Als+D6&mGox%0+O!a_@$jQKXaWIH%*0qfpf|=q%?|S22z+BP z@oaELx+WV-SeC$^`clS_Q}T#}1sL@)=vXd#Bo&NkIpL(BVDUPfRspb5H)P~lC8Lui zB`7!mg4Jw8GhrwhC8;eW((1C7PAWJAokT$=LJpOD{s%vJuwb^G-D=(vw;9tjVsax- zp%2wQiwID7gksE10*ON<%2d#;axsqFiFtBfa%wil`OzRZz^MEYW4Y>B=MfrwRYQn5 zXM+gE_?kD!8FRvl!XR7GmrzWY1t%P#FUADen`2))>bgmMcc{dw>qp&v&1>dBw1tfNTJ`#of`;YFNYsL>LZ@a5Jfnk*W#lbzH5Lzl-_wvj6@0-C>JL2h*C$M&L_2PQ0=xNI*3!W~M>%uLts{;@u_kmugZJ@{h z34*mjT6Hu)k(-4XV|*E^EQKmS7vRIkc&MF&0zmdCKnfMer~&}217>p81f&?R!YNiA zLuY>;qP2JHs;n`}oCX7sl7jO~XaK1q{9JKj7g}OsoVcErN(iZpk>7#ciH&IDM+m9z z=f=3>Gz^nLFN}Ew#<*)bnGlLe738 z1^aTMpC0wk;?str>Xs{|=t&5|vSx9r2BCu0?=FQM5esF7?+}dtL;UUoPB4hf&{XkQJ;97Pyn?F+w^yDTE zb5Eck9Lt}7f9yHtdUNCc#+@zK_Q~zgC-tW9RnvPF7_3ZoZxy{glc=dM8OlUskB{=@XA%HzaC{)Uus(ZuWe5=TCL#{_aD;)_?ku*j!=HH#eGo)$+@h&9P$F zNFg|~9W4aEy(3;JdHib^RxhlNzxyqdYkiSJApB|r{AL1I(aQR#1_Ec{z009yUCuM7avb9Lr+C>Aun}qYIXV3$;%^Sf4q?X?x zN#&x3A-B@7Yz2~9Dm||yuncLglGdy`$RU^0x~wH2k%VMlK9JFq?G2KQo^0U+Pzaa~ zV&{a2kX9c>-$l#l5f20dR7wbD9=*&$=FLPfiLYUY<>)_aG0Qq|7pjD0*JYA5-(SRI zR=6CU%dk%=ne?)PSNbn!w4|KT$NHUcG=-G)K;lt0gS12v+Fr>v#^VpQa!TT$jA5}dJcep# zBE-u0JXDs`HmxOAELtNUsU)X|PK>X>1Q+3_uR`_0T@SXscl+UOQ#xA=p36nbSKkbU zi@r0Eci6mOw)PeSeYuG}!Ci1qY6(+a_Km9CJIkd-}FuR9$ zUcRxzML^z&>w#MgNgf0*Xb2L6+Vqo&vfme}A!%*05M<5!KNEZCHpM&RrUGW|NJ}CHWvw>HEl+0aoBL;6z$Zjz4P;GHuV!x*6v`S~=!5hMMU=9`vsK literal 0 HcmV?d00001 diff --git a/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/tool_renderers.py b/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/tool_renderers.py new file mode 100644 index 0000000..f77c47a --- /dev/null +++ b/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/presentation/tool_renderers.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from typing import Any + +from agent_framework.presentation import register_tool_response_renderer + + +def _money_brl(value: Any) -> str: + try: + return f"{float(value):.2f}".replace(".", ",") + except (TypeError, ValueError): + return str(value) + + +def render_telecom_invoice(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + return f"[{agent_label}] Fatura consultada: {result}." + + +def render_telecom_plan(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + plano = result.get("plano") + if plano is None: + return None + parts = [f"[{agent_label}] Seu plano é {plano}"] + internet_gb = result.get("internet_gb") + status = result.get("status") + if internet_gb is not None: + parts.append(f"com {internet_gb} GB") + if status is not None: + parts.append(f"status {status}") + return ", ".join(parts) + "." + + +def render_retail_order(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + status = result.get("status") + if order_id is None or status is None: + return None + lines = [f"[{agent_label}] Pedido {order_id}: status {status}."] + total = result.get("valor_total") + if total is not None: + lines.append(f"Valor total: R$ {_money_brl(total)}.") + items = result.get("itens") or [] + rendered_items: list[str] = [] + if isinstance(items, list): + for item in items: + if isinstance(item, dict): + value = item.get("descricao") or item.get("nome") or item.get("sku") + else: + value = item + if value not in (None, ""): + rendered_items.append(str(value)) + if rendered_items: + lines.append("Itens: " + "; ".join(rendered_items) + ".") + return " ".join(lines) + + +def render_retail_delivery(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + transportadora = result.get("transportadora") + codigo = result.get("codigo_rastreio") + previsao = result.get("previsao_entrega") + if any(v is None for v in (order_id, transportadora, codigo, previsao)): + return None + return ( + f"[{agent_label}] Entrega do pedido {order_id}: transportadora {transportadora}, " + f"rastreio {codigo}, previsão {previsao}." + ) + + +def register_tool_renderers() -> None: + register_tool_response_renderer("telecom.invoice", render_telecom_invoice) + register_tool_response_renderer("telecom.plan", render_telecom_plan) + register_tool_response_renderer("retail.order", render_retail_order) + register_tool_response_renderer("retail.delivery", render_retail_delivery) diff --git a/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/config/tools.yaml b/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/config/tools.yaml index d85fae1..6273371 100644 --- a/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/config/tools.yaml +++ b/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/config/tools.yaml @@ -10,6 +10,9 @@ tools: - fatura - conta - boleto + response: + mode: renderer + renderer: telecom.invoice consultar_pagamentos: description: Consulta histórico de pagamentos do cliente. mcp_server: telecom @@ -28,6 +31,9 @@ tools: asset_id: string selection_keywords: - plano + response: + mode: renderer + renderer: telecom.plan listar_servicos: description: Lista serviços ativos e adicionais VAS. mcp_server: telecom @@ -49,6 +55,9 @@ tools: - consultar pedido - status do pedido - pedido + response: + mode: renderer + renderer: retail.order consultar_entrega: description: Consulta entrega e rastreamento do pedido. mcp_server: retail @@ -61,6 +70,9 @@ tools: - rastreamento - transportadora - previsão + response: + mode: renderer + renderer: retail.delivery solicitar_troca: description: Simula abertura de solicitação de troca. mcp_server: retail diff --git a/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/agents/runtime.py b/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/agents/runtime.py index e6429c4..7a1a9be 100644 --- a/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/agents/runtime.py +++ b/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/agents/runtime.py @@ -3,5 +3,8 @@ from __future__ import annotations # Compatibilidade local do template/backend. # A implementação oficial agora fica no framework para evitar duplicação entre agentes. from agent_framework.runtime import AgentRuntimeMixin, MessageBuilder, RuntimeContext +from app.presentation import register_tool_renderers + +register_tool_renderers() __all__ = ["AgentRuntimeMixin", "MessageBuilder", "RuntimeContext"] diff --git a/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/__init__.py b/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/__init__.py new file mode 100644 index 0000000..c0eba0d --- /dev/null +++ b/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/__init__.py @@ -0,0 +1,3 @@ +from .tool_renderers import register_tool_renderers + +__all__ = ["register_tool_renderers"] diff --git a/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc b/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32cbdf804cb8637d1026aa386d7d188a32214831 GIT binary patch literal 4402 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 literal 0 HcmV?d00001 diff --git a/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/tool_renderers.py b/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/tool_renderers.py new file mode 100644 index 0000000..f77c47a --- /dev/null +++ b/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/presentation/tool_renderers.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from typing import Any + +from agent_framework.presentation import register_tool_response_renderer + + +def _money_brl(value: Any) -> str: + try: + return f"{float(value):.2f}".replace(".", ",") + except (TypeError, ValueError): + return str(value) + + +def render_telecom_invoice(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + return f"[{agent_label}] Fatura consultada: {result}." + + +def render_telecom_plan(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + plano = result.get("plano") + if plano is None: + return None + parts = [f"[{agent_label}] Seu plano é {plano}"] + internet_gb = result.get("internet_gb") + status = result.get("status") + if internet_gb is not None: + parts.append(f"com {internet_gb} GB") + if status is not None: + parts.append(f"status {status}") + return ", ".join(parts) + "." + + +def render_retail_order(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + status = result.get("status") + if order_id is None or status is None: + return None + lines = [f"[{agent_label}] Pedido {order_id}: status {status}."] + total = result.get("valor_total") + if total is not None: + lines.append(f"Valor total: R$ {_money_brl(total)}.") + items = result.get("itens") or [] + rendered_items: list[str] = [] + if isinstance(items, list): + for item in items: + if isinstance(item, dict): + value = item.get("descricao") or item.get("nome") or item.get("sku") + else: + value = item + if value not in (None, ""): + rendered_items.append(str(value)) + if rendered_items: + lines.append("Itens: " + "; ".join(rendered_items) + ".") + return " ".join(lines) + + +def render_retail_delivery(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + transportadora = result.get("transportadora") + codigo = result.get("codigo_rastreio") + previsao = result.get("previsao_entrega") + if any(v is None for v in (order_id, transportadora, codigo, previsao)): + return None + return ( + f"[{agent_label}] Entrega do pedido {order_id}: transportadora {transportadora}, " + f"rastreio {codigo}, previsão {previsao}." + ) + + +def register_tool_renderers() -> None: + register_tool_response_renderer("telecom.invoice", render_telecom_invoice) + register_tool_response_renderer("telecom.plan", render_telecom_plan) + register_tool_response_renderer("retail.order", render_retail_order) + register_tool_response_renderer("retail.delivery", render_retail_delivery) diff --git a/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/config/tools.yaml b/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/config/tools.yaml index d85fae1..6273371 100644 --- a/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/config/tools.yaml +++ b/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/config/tools.yaml @@ -10,6 +10,9 @@ tools: - fatura - conta - boleto + response: + mode: renderer + renderer: telecom.invoice consultar_pagamentos: description: Consulta histórico de pagamentos do cliente. mcp_server: telecom @@ -28,6 +31,9 @@ tools: asset_id: string selection_keywords: - plano + response: + mode: renderer + renderer: telecom.plan listar_servicos: description: Lista serviços ativos e adicionais VAS. mcp_server: telecom @@ -49,6 +55,9 @@ tools: - consultar pedido - status do pedido - pedido + response: + mode: renderer + renderer: retail.order consultar_entrega: description: Consulta entrega e rastreamento do pedido. mcp_server: retail @@ -61,6 +70,9 @@ tools: - rastreamento - transportadora - previsão + response: + mode: renderer + renderer: retail.delivery solicitar_troca: description: Simula abertura de solicitação de troca. mcp_server: retail diff --git a/Tuning-Performance/Normal/templates/agent_template_backend/app/agents/runtime.py b/Tuning-Performance/Normal/templates/agent_template_backend/app/agents/runtime.py index e6429c4..7a1a9be 100644 --- a/Tuning-Performance/Normal/templates/agent_template_backend/app/agents/runtime.py +++ b/Tuning-Performance/Normal/templates/agent_template_backend/app/agents/runtime.py @@ -3,5 +3,8 @@ from __future__ import annotations # Compatibilidade local do template/backend. # A implementação oficial agora fica no framework para evitar duplicação entre agentes. from agent_framework.runtime import AgentRuntimeMixin, MessageBuilder, RuntimeContext +from app.presentation import register_tool_renderers + +register_tool_renderers() __all__ = ["AgentRuntimeMixin", "MessageBuilder", "RuntimeContext"] diff --git a/Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/__init__.py b/Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/__init__.py new file mode 100644 index 0000000..c0eba0d --- /dev/null +++ b/Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/__init__.py @@ -0,0 +1,3 @@ +from .tool_renderers import register_tool_renderers + +__all__ = ["register_tool_renderers"] diff --git a/Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc b/Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23b52e138221f8fc623622c7fe8fe767b8579417 GIT binary patch literal 4392 zcmb_fO>7&-6`tkpa+m-5qfGr&TG^6qy85vr$+2ZisT0dqrJ4y$vsFw8#EM+0w5eTT zb|qVEQ?Nl$SO^NqXpJyHfhb6TDnJkFsXFwK!iVO#43&!5szA^phumD)E!v#=W|pKZ znJRkd035#AdGq()H{W~n)aP>}DC3Er-5K;C^f%I|6o)M^Pg5W~LQxcDrqCpV8Hvb_ zDaRy>St_$r+$4{AkUdeZ72V;mGwO}@w5&9Jn)Rcl1oMg!Ga^c{gMTmKt z1K| z6w*#;$@IXjB{i+i_r0OuISnt!YEl`95Fs;QC=0M9L($9QD(%FqoV*K$9*`Fo2NuEh zurzhhK-n3#5A^=U70aDi&{Sn5F^e;}4mK^qPrm|H4n1+OeCuAru{{5a-n?$spV$rb z76QGS(XA83zbFt+K3(aqIFU<0Gdnfv!ZIt~z zGs-5RO$+f54?pVjCJ+FzOpNsdQezC%>>%Hbzz-G^&jx3tYqGI~WeIGjFJ%llC67p0 zfKi`-j^(09Qo&%B6HW>W7O%r;6#ynRc}AX9GCEmOf`S7eSj{#J6NZvelG;KdtuAZn zq=G}xNfdM<!Ipn=w5jCO7gF`cUn&h~V}|D8}3*?mtwbOa;j* z7vl*2=gE1=so5CkM}yn|qw+_L<*H+yM`-X>4I$>74I&idYu*-T%n2(BgKR}#LNQ?$ zoN$D`7!zP`j(zQ@>n8Etp%SaEA9eRZANbD`v3P)|s^JFsute-SBSn=ZiGGwGe{)^ZZJE$LYfJR)UT>H4c#!Tuy=9lf^8!>q;5D~9C+WCOr0?v9pL!y+ai z!fg~K(^mXN~m4t?Z&`}b7Yu;7wx{;sCk8ZMNuy;r7D+#`W&{FBTmtW5R&OA(sq#Va%&A#$EHGyKC$! zOm=mIzNdzM{eRK-R`gZR>yDUP^~5|;-z6Xva`qc3*q5u8rQ<&P^w3{ju`-i{ZsZX1 zkUhGpRyhfpwSDG~25yr3e5k~#{vZ?(b&`62g=k&PG0utxP)2>k5;Y77LL!}_*OgL7 z)-@x&p`_9&P0G4Pq%tSa5MX&A+-fArFyu_O4#Kg9CE6H~Zgxu+pEeX#w_GVjPeQV1FyttR#!Z``?D`;0 zVa1TsnFKWx9s>O?GNvEg4>T1Bu4PxV`7^~pPj2Ec_XG;UvHbb>$DU)ZH#hEY+}Uz% zpWF_8T5tMZGrd=V!OCR!R?*u-$*v%T%EV+IJM|m))^PFkMf23ic9$8vyd#cQ^a(lc zdV4lrfa%Ze35IuIJ-c4{ih#^%@y{1bEE0kEg!aQjupE`3c-=>Xd(EW9q~%Z<6pb5dSQM1 z-B(Pm^+gVaq}t}tzk=|8;?UZ>Rb{p#*>gYO3vpm!yO1<}dVG3*h-*Z{o4EvOlNiQpSrT=n9OUfC2 ztiP%{1{3Hc5%?Nzg6W?6ykjz7zs~*qA_)Jc3E4rz8%_7#1tT!>4v8LadC>LuEN_(^_K1qBZi7N^*MW z#P|wKa1nm`DpW7r^>hs_ISYi}{omz&rV+y(bk z{{D7zp<}Y>p4t_r3c?i7!k2E(gQ*9jW~g^_dUMh|fBiGRdHn}Z5Hrm*m6}@DFXS(8 ziW}LjddToyLr++icOJY(urtKLkESB;fbi(Kw_KEo6DQMB38(NP1HjrP>ezp~)$C{Y zUvxG5xfeq`!CRP*WCP_?zrUR7XT6mVB;Ct;ZDaRSR?P;=tqRz}@L+~5(&quq3@PtY zhfokx8`vy;?C`s{{M5p)!35Xfr=Nu?hxWJ=X7}*U%Qtqo2*?|eouTVH+{8iA*7$;p z&;=r4j>ZQ}3``z7@G4Si7z(@X2t-2?$%4P}lMoe$>)R{Adwj;uipQbHPK~MJRcL12 zpdn?8pHer9sde7e}yKVIXR~FnV(@UJrh05@n`Kp TrtR5TH{<+AE62RfP&54pPN=4j literal 0 HcmV?d00001 diff --git a/Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/tool_renderers.py b/Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/tool_renderers.py new file mode 100644 index 0000000..f77c47a --- /dev/null +++ b/Tuning-Performance/Normal/templates/agent_template_backend/app/presentation/tool_renderers.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from typing import Any + +from agent_framework.presentation import register_tool_response_renderer + + +def _money_brl(value: Any) -> str: + try: + return f"{float(value):.2f}".replace(".", ",") + except (TypeError, ValueError): + return str(value) + + +def render_telecom_invoice(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + return f"[{agent_label}] Fatura consultada: {result}." + + +def render_telecom_plan(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + plano = result.get("plano") + if plano is None: + return None + parts = [f"[{agent_label}] Seu plano é {plano}"] + internet_gb = result.get("internet_gb") + status = result.get("status") + if internet_gb is not None: + parts.append(f"com {internet_gb} GB") + if status is not None: + parts.append(f"status {status}") + return ", ".join(parts) + "." + + +def render_retail_order(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + status = result.get("status") + if order_id is None or status is None: + return None + lines = [f"[{agent_label}] Pedido {order_id}: status {status}."] + total = result.get("valor_total") + if total is not None: + lines.append(f"Valor total: R$ {_money_brl(total)}.") + items = result.get("itens") or [] + rendered_items: list[str] = [] + if isinstance(items, list): + for item in items: + if isinstance(item, dict): + value = item.get("descricao") or item.get("nome") or item.get("sku") + else: + value = item + if value not in (None, ""): + rendered_items.append(str(value)) + if rendered_items: + lines.append("Itens: " + "; ".join(rendered_items) + ".") + return " ".join(lines) + + +def render_retail_delivery(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + transportadora = result.get("transportadora") + codigo = result.get("codigo_rastreio") + previsao = result.get("previsao_entrega") + if any(v is None for v in (order_id, transportadora, codigo, previsao)): + return None + return ( + f"[{agent_label}] Entrega do pedido {order_id}: transportadora {transportadora}, " + f"rastreio {codigo}, previsão {previsao}." + ) + + +def register_tool_renderers() -> None: + register_tool_response_renderer("telecom.invoice", render_telecom_invoice) + register_tool_response_renderer("telecom.plan", render_telecom_plan) + register_tool_response_renderer("retail.order", render_retail_order) + register_tool_response_renderer("retail.delivery", render_retail_delivery) diff --git a/Tuning-Performance/Normal/templates/agent_template_backend/config/tools.yaml b/Tuning-Performance/Normal/templates/agent_template_backend/config/tools.yaml index d85fae1..6273371 100644 --- a/Tuning-Performance/Normal/templates/agent_template_backend/config/tools.yaml +++ b/Tuning-Performance/Normal/templates/agent_template_backend/config/tools.yaml @@ -10,6 +10,9 @@ tools: - fatura - conta - boleto + response: + mode: renderer + renderer: telecom.invoice consultar_pagamentos: description: Consulta histórico de pagamentos do cliente. mcp_server: telecom @@ -28,6 +31,9 @@ tools: asset_id: string selection_keywords: - plano + response: + mode: renderer + renderer: telecom.plan listar_servicos: description: Lista serviços ativos e adicionais VAS. mcp_server: telecom @@ -49,6 +55,9 @@ tools: - consultar pedido - status do pedido - pedido + response: + mode: renderer + renderer: retail.order consultar_entrega: description: Consulta entrega e rastreamento do pedido. mcp_server: retail @@ -61,6 +70,9 @@ tools: - rastreamento - transportadora - previsão + response: + mode: renderer + renderer: retail.delivery solicitar_troca: description: Simula abertura de solicitação de troca. mcp_server: retail diff --git a/Tuning-Performance/Offline_Workflow_Regression/README.md b/Tuning-Performance/Offline_Workflow_Regression/README.md index bbd3250..f3bc196 100644 --- a/Tuning-Performance/Offline_Workflow_Regression/README.md +++ b/Tuning-Performance/Offline_Workflow_Regression/README.md @@ -2,7 +2,7 @@ O backend de produção de `WorkflowRuntime` continua sendo **LangGraph**. A ausência do pacote `langgraph` em produção é erro de configuração. -Para builders restritos/offline, o runtime aceita `allow_deterministic_fallback=True`. Esse modo é deliberadamente opt-in e existe somente para exercitar a DSL do framework (actions, edges, condições, pause/resume e trace) de forma reproduzível em testes offline/regressão. Quando `allow_deterministic_fallback=True`, o backend determinístico é selecionado explicitamente mesmo que LangGraph esteja instalado. Ele nunca é selecionado automaticamente em produção. +Para builders restritos/offline, o runtime aceita `allow_deterministic_fallback=True`. Esse modo é deliberadamente opt-in e existe somente para exercitar a DSL do framework (actions, edges, condições, pause/resume e trace) quando a dependência externa não pode ser instalada. Ele não é selecionado automaticamente. Exemplo de teste: diff --git a/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/agents/runtime.py b/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/agents/runtime.py index e6429c4..7a1a9be 100644 --- a/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/agents/runtime.py +++ b/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/agents/runtime.py @@ -3,5 +3,8 @@ from __future__ import annotations # Compatibilidade local do template/backend. # A implementação oficial agora fica no framework para evitar duplicação entre agentes. from agent_framework.runtime import AgentRuntimeMixin, MessageBuilder, RuntimeContext +from app.presentation import register_tool_renderers + +register_tool_renderers() __all__ = ["AgentRuntimeMixin", "MessageBuilder", "RuntimeContext"] diff --git a/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/__init__.py b/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/__init__.py new file mode 100644 index 0000000..c0eba0d --- /dev/null +++ b/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/__init__.py @@ -0,0 +1,3 @@ +from .tool_renderers import register_tool_renderers + +__all__ = ["register_tool_renderers"] diff --git a/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc b/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..567eb4dcb26331acc08869aa04106d30e73d78d5 GIT binary patch literal 4401 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 literal 0 HcmV?d00001 diff --git a/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/tool_renderers.py b/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/tool_renderers.py new file mode 100644 index 0000000..f77c47a --- /dev/null +++ b/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/presentation/tool_renderers.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from typing import Any + +from agent_framework.presentation import register_tool_response_renderer + + +def _money_brl(value: Any) -> str: + try: + return f"{float(value):.2f}".replace(".", ",") + except (TypeError, ValueError): + return str(value) + + +def render_telecom_invoice(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + return f"[{agent_label}] Fatura consultada: {result}." + + +def render_telecom_plan(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + plano = result.get("plano") + if plano is None: + return None + parts = [f"[{agent_label}] Seu plano é {plano}"] + internet_gb = result.get("internet_gb") + status = result.get("status") + if internet_gb is not None: + parts.append(f"com {internet_gb} GB") + if status is not None: + parts.append(f"status {status}") + return ", ".join(parts) + "." + + +def render_retail_order(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + status = result.get("status") + if order_id is None or status is None: + return None + lines = [f"[{agent_label}] Pedido {order_id}: status {status}."] + total = result.get("valor_total") + if total is not None: + lines.append(f"Valor total: R$ {_money_brl(total)}.") + items = result.get("itens") or [] + rendered_items: list[str] = [] + if isinstance(items, list): + for item in items: + if isinstance(item, dict): + value = item.get("descricao") or item.get("nome") or item.get("sku") + else: + value = item + if value not in (None, ""): + rendered_items.append(str(value)) + if rendered_items: + lines.append("Itens: " + "; ".join(rendered_items) + ".") + return " ".join(lines) + + +def render_retail_delivery(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + transportadora = result.get("transportadora") + codigo = result.get("codigo_rastreio") + previsao = result.get("previsao_entrega") + if any(v is None for v in (order_id, transportadora, codigo, previsao)): + return None + return ( + f"[{agent_label}] Entrega do pedido {order_id}: transportadora {transportadora}, " + f"rastreio {codigo}, previsão {previsao}." + ) + + +def register_tool_renderers() -> None: + register_tool_response_renderer("telecom.invoice", render_telecom_invoice) + register_tool_response_renderer("telecom.plan", render_telecom_plan) + register_tool_response_renderer("retail.order", render_retail_order) + register_tool_response_renderer("retail.delivery", render_retail_delivery) diff --git a/Tuning-Performance/Route_Stickness/templates/agent_template_backend/config/tools.yaml b/Tuning-Performance/Route_Stickness/templates/agent_template_backend/config/tools.yaml index d85fae1..6273371 100644 --- a/Tuning-Performance/Route_Stickness/templates/agent_template_backend/config/tools.yaml +++ b/Tuning-Performance/Route_Stickness/templates/agent_template_backend/config/tools.yaml @@ -10,6 +10,9 @@ tools: - fatura - conta - boleto + response: + mode: renderer + renderer: telecom.invoice consultar_pagamentos: description: Consulta histórico de pagamentos do cliente. mcp_server: telecom @@ -28,6 +31,9 @@ tools: asset_id: string selection_keywords: - plano + response: + mode: renderer + renderer: telecom.plan listar_servicos: description: Lista serviços ativos e adicionais VAS. mcp_server: telecom @@ -49,6 +55,9 @@ tools: - consultar pedido - status do pedido - pedido + response: + mode: renderer + renderer: retail.order consultar_entrega: description: Consulta entrega e rastreamento do pedido. mcp_server: retail @@ -61,6 +70,9 @@ tools: - rastreamento - transportadora - previsão + response: + mode: renderer + renderer: retail.delivery solicitar_troca: description: Simula abertura de solicitação de troca. mcp_server: retail diff --git a/docs/features/01_authentication.md b/docs/features/01_authentication.md new file mode 100644 index 0000000..1460cbb --- /dev/null +++ b/docs/features/01_authentication.md @@ -0,0 +1,165 @@ +# Autenticação / Authentication + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `security/authentication.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Verifica quem pode acessar APIs, gateways e serviços protegidos antes que a requisição chegue ao agente. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +Cliente/Sistema + ↓ +Authentication Provider + ↓ +credencial válida? + ├─ não → 401/nega acesso + └─ sim → principal autenticado → agente +``` + +### 4. Como funciona internamente + +O framework contém uma abstração `AuthenticationProvider` e implementações para cenários diferentes. Entre as implementações atuais estão `NoAuthenticationProvider`, `DenyAuthenticationProvider`, `BasicAuthenticationProvider`, `ApiKeyAuthenticationProvider`, `StaticBearerAuthenticationProvider`, `JwtAuthenticationProvider`, `OAuth2IntrospectionAuthenticationProvider` e `TrustedProxyAuthenticationProvider`. + +A autenticação produz um `AuthenticatedPrincipal` com `subject`, `scheme` e, quando aplicável, `claims`. A regra de negócio do agente não deve validar senha/token diretamente. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```python +from agent_framework.security.authentication import BasicAuthenticationProvider + +provider = BasicAuthenticationProvider( + client_id="client-a", + secret_hash="pbkdf2_sha256:...", +) +result = await provider.authenticate(request) +if not result.authenticated: + # negar acesso + ... +``` + +Segredos podem ser verificados em formato simples, SHA-256 ou PBKDF2; em produção, prefira hashes fortes e secret stores. + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Basic auth retornando 401: validar `Authorization: Basic ...` e o secret configurado. +- Confundir autenticação do usuário com `OCI_AUTH_MODE`: são problemas diferentes. +- Usar `NoAuthenticationProvider` em produção sem decisão explícita de arquitetura. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/security/authentication.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Checks who may access protected APIs, gateways, and services before the request reaches the agent. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +Client/System + ↓ +Authentication Provider + ↓ +valid credential? + ├─ no → 401/deny + └─ yes → authenticated principal → agent +``` + +### 4. How it works internally + +The framework exposes an `AuthenticationProvider` abstraction with multiple implementations. Current providers include `NoAuthenticationProvider`, `DenyAuthenticationProvider`, `BasicAuthenticationProvider`, `ApiKeyAuthenticationProvider`, `StaticBearerAuthenticationProvider`, `JwtAuthenticationProvider`, `OAuth2IntrospectionAuthenticationProvider`, and `TrustedProxyAuthenticationProvider`. + +Authentication produces an `AuthenticatedPrincipal` containing `subject`, `scheme`, and optional `claims`. Domain code should not validate credentials directly. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```python +from agent_framework.security.authentication import BasicAuthenticationProvider + +provider = BasicAuthenticationProvider( + client_id="client-a", + secret_hash="pbkdf2_sha256:...", +) +result = await provider.authenticate(request) +if not result.authenticated: + # deny access + ... +``` + +Secrets may be verified as plain, SHA-256, or PBKDF2 values; for production, prefer strong hashes and managed secret stores. + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Basic auth returns 401: validate the `Authorization: Basic ...` header and configured secret. +- Do not confuse API authentication with `OCI_AUTH_MODE`; they solve different problems. +- Avoid `NoAuthenticationProvider` in production unless explicitly accepted by architecture. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/security/authentication.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/02_deterministic_transactional_workflow.md b/docs/features/02_deterministic_transactional_workflow.md new file mode 100644 index 0000000..5485b94 --- /dev/null +++ b/docs/features/02_deterministic_transactional_workflow.md @@ -0,0 +1,183 @@ +# Workflow Transacional Determinístico / Deterministic Transactional Workflow + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `workflows/runtime.py + mcp/tool_policy.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Garante que operações que alteram estado sigam passos previsíveis, com confirmação e controle de execução, em vez de depender da criatividade do LLM. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +Mensagem do cliente + ↓ +LLM entende intenção + ↓ +Tool policy = transactional + ↓ +Workflow determinístico + ↓ +confirmação + ↓ +execução controlada + ↓ +resultado +``` + +### 4. Como funciona internamente + +O LLM pode ajudar a interpretar a intenção e extrair parâmetros, mas não deve decidir a sequência crítica de uma transação. O `ToolPolicyRegistry` classifica tools, e `operation_type: transactional` ativa a política transacional. O `WorkflowRuntime` executa o workflow, mantém estado e integra pause/resume e recuperação de erro. + +A configuração `ENABLE_TRANSACTIONAL_WORKFLOWS` controla a capability global, e `WORKFLOWS_PATH` aponta para os YAMLs. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```yaml +tools: + cancelar_servico: + operation_type: transactional + requires_confirmation: true +``` + +```text +1. localizar serviço +2. validar elegibilidade +3. pedir confirmação +4. PAUSE +5. receber confirmação +6. RESUME +7. executar side effect +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Marcar uma tool de escrita como `read_only` elimina proteções transacionais. +- Reexecutar steps anteriores ao pause pode duplicar side effects; use o runtime oficial. +- Não use prompt como única garantia de confirmação. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/workflows/runtime.py` +- `libs/agent_framework/src/agent_framework/mcp/tool_policy.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Ensures state-changing operations follow predictable steps with confirmation and execution control instead of depending on LLM creativity. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +Customer message + ↓ +LLM understands intent + ↓ +Tool policy = transactional + ↓ +Deterministic workflow + ↓ +confirmation + ↓ +controlled execution + ↓ +result +``` + +### 4. How it works internally + +The LLM may help interpret intent and extract parameters, but it should not decide the critical sequence of a transaction. `ToolPolicyRegistry` classifies tools, and `operation_type: transactional` activates transactional behavior. `WorkflowRuntime` executes the workflow, preserves state, and integrates pause/resume and error recovery. + +`ENABLE_TRANSACTIONAL_WORKFLOWS` controls the capability globally, while `WORKFLOWS_PATH` points to workflow YAML files. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```yaml +tools: + cancel_service: + operation_type: transactional + requires_confirmation: true +``` + +```text +1. locate service +2. validate eligibility +3. ask for confirmation +4. PAUSE +5. receive confirmation +6. RESUME +7. execute side effect +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Marking a write tool as `read_only` bypasses transactional protections. +- Re-running steps before a pause can duplicate side effects; use the official runtime. +- Do not use prompts as the only confirmation guarantee. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/workflows/runtime.py` +- `libs/agent_framework/src/agent_framework/mcp/tool_policy.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/03_domain_requested_llm_composition.md b/docs/features/03_domain_requested_llm_composition.md new file mode 100644 index 0000000..4d70018 --- /dev/null +++ b/docs/features/03_domain_requested_llm_composition.md @@ -0,0 +1,157 @@ +# Composição por LLM Solicitada pelo Domínio / Domain Requested LLM Composition + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `runtime/agent_runtime.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Permite que a regra de negócio calcule o resultado e peça ao LLM apenas para redigir a resposta final. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +Regra de negócio calcula + ↓ +requires_llm_composition=true + ↓ +framework impede resposta MCP direta + ↓ +LLMProvider oficial + ↓ +redação natural +``` + +### 4. Como funciona internamente + +O domínio retorna dados confiáveis e uma instrução de composição. O `AgentRuntimeMixin` detecta `requires_llm_composition` de forma recursiva no resultado da tool/workflow e não encerra a resposta pelo caminho direto de MCP. A composição segue pelo LLM oficial do agente, preservando profiles, tracing, usage e políticas do framework. + +O LLM deve redigir; ele não deve recalcular valores nem decidir regras de negócio já resolvidas. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```json +{ + "success": true, + "refund_amount": "38,00", + "requires_llm_composition": true, + "response_instruction": "Explique a devolução usando somente os valores calculados." +} +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Instrução muito aberta pode fazer o LLM adicionar conteúdo não autorizado. +- Não envie ao LLM a responsabilidade de recalcular valores determinísticos. +- Se não houver necessidade de redação livre, prefira resposta determinística direta. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Lets domain logic compute the authoritative result and ask the LLM only to compose the final user-facing response. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +Domain logic computes + ↓ +requires_llm_composition=true + ↓ +framework prevents direct MCP answer + ↓ +official LLMProvider + ↓ +natural-language response +``` + +### 4. How it works internally + +The domain returns authoritative data plus a composition instruction. `AgentRuntimeMixin` recursively detects `requires_llm_composition` in tool/workflow results and avoids terminating through the direct MCP-answer path. Composition then uses the agent's official LLM provider, preserving profiles, tracing, usage accounting, and framework policies. + +The LLM should compose language, not recalculate values or override already-resolved business rules. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```json +{ + "success": true, + "refund_amount": "38.00", + "requires_llm_composition": true, + "response_instruction": "Explain the refund using only the computed values." +} +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- An overly broad instruction may let the LLM add unauthorized content. +- Do not delegate deterministic calculations back to the LLM. +- If free-form wording is unnecessary, prefer a deterministic direct response. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/04_domain_requested_rag.md b/docs/features/04_domain_requested_rag.md new file mode 100644 index 0000000..745397f --- /dev/null +++ b/docs/features/04_domain_requested_rag.md @@ -0,0 +1,167 @@ +# RAG Solicitado pelo Domínio / Domain Requested RAG + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `runtime/agent_runtime.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Permite que uma tool ou workflow declare que a resposta precisa consultar conhecimento externo, mesmo quando já existe resultado MCP. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +Tool/Workflow + ↓ +requires_rag=true + ↓ +rag_query / rag_queries + ↓ +RagService do framework + ↓ +Retrieval Guardrails + ↓ +LLM/resposta +``` + +### 4. Como funciona internamente + +Normalmente o framework pode pular RAG quando MCP já trouxe informação suficiente (`SKIP_RAG_WHEN_MCP_SUFFICIENT`). Esta feature permite que o domínio substitua essa decisão para um caso específico. O resultado pode declarar `requires_rag`, `rag_query` ou `rag_queries`; o runtime usa essas queries como override e executa o `RagService`. + +O domínio informa **o que precisa saber**. Ele não implementa cliente de vetor, retriever ou prompt RAG paralelo. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```json +{ + "requires_rag": true, + "rag_queries": [ + "Como cancelar YouTube Premium?", + "Como cancelar Aya Books?" + ] +} +``` + +Configurações relacionadas incluem `RAG_TOP_K` e `SKIP_RAG_WHEN_MCP_SUFFICIENT`. + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Declarar RAG para fatos transacionais já resolvidos pela API pode aumentar custo e latência. +- Query genérica demais reduz relevância. +- Nunca confie no retrieval sem `Retrieval Guardrails` quando o dado influencia resposta crítica. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Allows a tool or workflow to declare that external knowledge retrieval is required even when an MCP result already exists. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +Tool/Workflow + ↓ +requires_rag=true + ↓ +rag_query / rag_queries + ↓ +framework RagService + ↓ +Retrieval Guardrails + ↓ +LLM/response +``` + +### 4. How it works internally + +Normally the framework may skip RAG when MCP already provides sufficient data (`SKIP_RAG_WHEN_MCP_SUFFICIENT`). This feature lets the domain override that decision for a specific case. A result may declare `requires_rag`, `rag_query`, or `rag_queries`; the runtime uses those queries as overrides and invokes `RagService`. + +The domain declares **what knowledge is needed**. It does not implement its own vector client, retriever, or parallel RAG prompt stack. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```json +{ + "requires_rag": true, + "rag_queries": [ + "How to cancel YouTube Premium?", + "How to cancel Aya Books?" + ] +} +``` + +Related settings include `RAG_TOP_K` and `SKIP_RAG_WHEN_MCP_SUFFICIENT`. + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Requesting RAG for transactional facts already resolved by an API adds unnecessary cost and latency. +- Queries that are too broad reduce relevance. +- Do not trust retrieved content for critical responses without Retrieval Guardrails. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/05_long_term_memory.md b/docs/features/05_long_term_memory.md new file mode 100644 index 0000000..e9e43e3 --- /dev/null +++ b/docs/features/05_long_term_memory.md @@ -0,0 +1,167 @@ +# Memória de Longo Prazo / Long Term Memory + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `memory/long_term_memory.py + memory/long_term_store.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Permite lembrar informações úteis entre sessões diferentes, sem depender do histórico completo de uma conversa. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +Sessão A + ↓ +extração de memória relevante + ↓ +Long Term Memory Store + ↓ +... dias depois ... + ↓ +Sessão B + ↓ +recupera contexto relevante + ↓ +agente +``` + +### 4. Como funciona internamente + +A memória de longo prazo é diferente de histórico de mensagens e de checkpoint. Ela persiste fatos/preferências úteis e os recupera como contexto de uma nova sessão. O framework oferece providers `memory`, `sqlite`, `autonomous` e `oracle`. + +Configurações importantes: `ENABLE_LONG_TERM_MEMORY`, `LONG_TERM_MEMORY_PROVIDER`, `LONG_TERM_MEMORY_MAX_CONTEXT_ITEMS`, `LONG_TERM_MEMORY_MIN_CONFIDENCE`, `LONG_TERM_MEMORY_AUTO_EXTRACT` e `LONG_TERM_MEMORY_INJECT_CONTEXT`. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```env +ENABLE_LONG_TERM_MEMORY=true +LONG_TERM_MEMORY_PROVIDER=oracle +LONG_TERM_MEMORY_MAX_CONTEXT_ITEMS=20 +LONG_TERM_MEMORY_MIN_CONFIDENCE=0.70 +LONG_TERM_MEMORY_AUTO_EXTRACT=true +LONG_TERM_MEMORY_INJECT_CONTEXT=true +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Não confundir LTM com replay de toda conversa. +- Memória irrelevante ou de baixa confiança não deveria ser injetada. +- Em múltiplas réplicas, prefira storage durável compartilhado em vez de memória local. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/memory/long_term_memory.py` +- `libs/agent_framework/src/agent_framework/memory/long_term_store.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Allows useful information to persist across different sessions without depending on the full transcript of a previous conversation. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +Session A + ↓ +extract relevant memory + ↓ +Long Term Memory Store + ↓ +... days later ... + ↓ +Session B + ↓ +retrieve relevant context + ↓ +agent +``` + +### 4. How it works internally + +Long-term memory is different from message history and checkpoints. It persists useful facts/preferences and retrieves them as context for a future session. The framework supports `memory`, `sqlite`, `autonomous`, and `oracle` providers. + +Important settings include `ENABLE_LONG_TERM_MEMORY`, `LONG_TERM_MEMORY_PROVIDER`, `LONG_TERM_MEMORY_MAX_CONTEXT_ITEMS`, `LONG_TERM_MEMORY_MIN_CONFIDENCE`, `LONG_TERM_MEMORY_AUTO_EXTRACT`, and `LONG_TERM_MEMORY_INJECT_CONTEXT`. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```env +ENABLE_LONG_TERM_MEMORY=true +LONG_TERM_MEMORY_PROVIDER=oracle +LONG_TERM_MEMORY_MAX_CONTEXT_ITEMS=20 +LONG_TERM_MEMORY_MIN_CONFIDENCE=0.70 +LONG_TERM_MEMORY_AUTO_EXTRACT=true +LONG_TERM_MEMORY_INJECT_CONTEXT=true +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Do not confuse LTM with replaying the entire transcript. +- Irrelevant or low-confidence memories should not be injected. +- For multiple replicas, prefer shared durable storage over local memory. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/memory/long_term_memory.py` +- `libs/agent_framework/src/agent_framework/memory/long_term_store.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/06_offline_workflow_regression.md b/docs/features/06_offline_workflow_regression.md new file mode 100644 index 0000000..5569f63 --- /dev/null +++ b/docs/features/06_offline_workflow_regression.md @@ -0,0 +1,163 @@ +# Regressão Offline de Workflow / Offline Workflow Regression + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `workflows/runtime.py + Tuning-Performance/Offline_Workflow_Regression` + +--- + +## Português (PT-BR) + +### 1. O que é + +Permite testar a lógica de workflows sem exigir toda a infraestrutura de produção. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +Teste + ↓ +backend determinístico explicitamente habilitado + ↓ +run → PAUSED + ↓ +resume → COMPLETED + ↓ +asserts de estado/side effects +``` + +### 4. Como funciona internamente + +O `WorkflowRuntime` possui um caminho determinístico/offline **explicitamente opt-in para testes**. Ele permite validar DSL, condições, pause/resume e proteção contra reexecução sem exigir LangGraph, banco, OCI ou APIs externas. + +O comportamento de produção continua usando LangGraph. O modo offline não deve virar fallback silencioso quando LangGraph falha ou está ausente em produção. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```text +run(workflow) + action_a = 1 execução + status = PAUSED + +resume(workflow) + action_a continua com 1 execução + action_b = 1 execução + status = COMPLETED +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Usar o backend offline em produção mascara problemas reais. +- Mockar tanto que o teste deixa de validar a DSL real. +- Não verificar side effects anteriores ao pause pode esconder duplicações. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/workflows/runtime.py` +- `libs/agent_framework/src/agent_framework/Tuning-Performance/Offline_Workflow_Regression` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Allows workflow logic to be regression-tested without requiring the full production infrastructure. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +Test + ↓ +explicit deterministic test backend + ↓ +run → PAUSED + ↓ +resume → COMPLETED + ↓ +state/side-effect assertions +``` + +### 4. How it works internally + +`WorkflowRuntime` includes an **explicitly opt-in deterministic/offline test backend**. It can validate DSL rules, conditions, pause/resume behavior, and duplicate-execution protection without requiring LangGraph, a database, OCI, or external APIs. + +Production behavior still uses LangGraph. Offline mode must never become a silent fallback when LangGraph fails or is unavailable in production. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```text +run(workflow) + action_a = executed once + status = PAUSED + +resume(workflow) + action_a remains executed once + action_b = executed once + status = COMPLETED +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Using the offline backend in production hides real issues. +- Over-mocking can stop the test from validating real DSL behavior. +- Failing to assert pre-pause side effects may hide duplicate execution. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/workflows/runtime.py` +- `libs/agent_framework/src/agent_framework/Tuning-Performance/Offline_Workflow_Regression` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/07_pause_resume_workflow.md b/docs/features/07_pause_resume_workflow.md new file mode 100644 index 0000000..b600937 --- /dev/null +++ b/docs/features/07_pause_resume_workflow.md @@ -0,0 +1,165 @@ +# Pause / Resume de Workflow / Pause / Resume Workflow + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `workflows/runtime.py + workflows/graph.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Permite interromper um workflow em um ponto seguro, persistir o estado e continuar depois com a resposta do usuário ou outro evento. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +Workflow + ↓ +ações prévias + ↓ +PAUSE + ↓ +checkpoint/estado + ↓ +nova mensagem + ↓ +RESUME + ↓ +ações seguintes +``` + +### 4. Como funciona internamente + +`WorkflowRuntime` expõe `arun(...)` e `aresume(...)`. O nó de pause é separado da action anterior para evitar reexecutar side effects quando o workflow retoma. O mesmo `execution_id/thread_id` identifica a execução pausada e retomada. + +O runtime suporta condições declarativas como `all`, `any`, `not`, `eq`, `neq` e `exists`, permitindo definir quando pausar ou continuar sem colocar lógica conversacional no prompt. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```text +status = await runtime.arun(...) +# status == PAUSED + +status = await runtime.aresume(execution_id, input={"confirmed": true}) +# status == COMPLETED +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Perder o `execution_id` impede retomar a execução correta. +- Reexecutar o workflow do zero após confirmação pode repetir side effects. +- Pause sem storage/checkpoint compartilhado é frágil em múltiplas réplicas. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/workflows/runtime.py` +- `libs/agent_framework/src/agent_framework/workflows/graph.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Allows a workflow to stop at a safe point, persist state, and continue later using user input or another event. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +Workflow + ↓ +pre-pause actions + ↓ +PAUSE + ↓ +checkpoint/state + ↓ +new message + ↓ +RESUME + ↓ +remaining actions +``` + +### 4. How it works internally + +`WorkflowRuntime` exposes `arun(...)` and `aresume(...)`. The pause node is separated from the preceding action so previous side effects are not executed again on resume. The same `execution_id/thread_id` identifies the paused and resumed execution. + +The runtime supports declarative conditions such as `all`, `any`, `not`, `eq`, `neq`, and `exists`, so pause/continue decisions do not need to live in the prompt. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```text +status = await runtime.arun(...) +# status == PAUSED + +status = await runtime.aresume(execution_id, input={"confirmed": true}) +# status == COMPLETED +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Losing the `execution_id` prevents resuming the right execution. +- Restarting the workflow from scratch after confirmation may duplicate side effects. +- Pause without shared checkpoint/state storage is fragile across multiple replicas. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/workflows/runtime.py` +- `libs/agent_framework/src/agent_framework/workflows/graph.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/08_route_stickiness.md b/docs/features/08_route_stickiness.md new file mode 100644 index 0000000..264a17e --- /dev/null +++ b/docs/features/08_route_stickiness.md @@ -0,0 +1,151 @@ +# Aderência de Rota / Route Stickiness + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `routing/enterprise_router.py + runtime/agent_runtime.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Evita que pequenas mensagens de continuação façam a conversa trocar de agente sem necessidade. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +mensagem atual + + histórico curto + + rota anterior + ↓ +continuidade semântica + ↓ +manter rota ou handoff +``` + +### 4. Como funciona internamente + +Route Stickiness avalia se a nova mensagem continua semanticamente ligada ao assunto/agente atual. Isso reduz ping-pong de agentes em mensagens como “e esse valor?”, “sim”, “o segundo” ou “e no mês passado?”. + +Configurações existentes incluem `ENABLE_ROUTE_STICKINESS`, `ROUTE_STICKINESS_LLM_PROFILE`, `ROUTE_STICKINESS_CONFIDENCE_THRESHOLD`, `ROUTE_STICKINESS_HISTORY_TURNS` e `ROUTE_STICKINESS_MAX_TOKENS`. A decisão pode permitir handoff quando há evidência suficiente de mudança de assunto. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```env +ENABLE_ROUTE_STICKINESS=true +ROUTE_STICKINESS_CONFIDENCE_THRESHOLD=0.90 +ROUTE_STICKINESS_HISTORY_TURNS=2 +ROUTE_STICKINESS_MAX_TOKENS=80 +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Threshold muito baixo pode prender o cliente no agente errado. +- Threshold alto demais perde continuidade em mensagens curtas. +- Stickiness não deve bloquear handoff explícito quando a intenção realmente mudou. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/routing/enterprise_router.py` +- `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Prevents short follow-up messages from unnecessarily switching the conversation to another agent. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +current message + + short history + + previous route + ↓ +semantic continuity + ↓ +keep route or handoff +``` + +### 4. How it works internally + +Route Stickiness evaluates whether a new message is semantically continuous with the current subject/agent. It reduces agent ping-pong for messages such as “what about that amount?”, “yes”, “the second one”, or “and last month?”. + +Existing settings include `ENABLE_ROUTE_STICKINESS`, `ROUTE_STICKINESS_LLM_PROFILE`, `ROUTE_STICKINESS_CONFIDENCE_THRESHOLD`, `ROUTE_STICKINESS_HISTORY_TURNS`, and `ROUTE_STICKINESS_MAX_TOKENS`. The decision may still allow handoff when there is enough evidence of a topic change. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```env +ENABLE_ROUTE_STICKINESS=true +ROUTE_STICKINESS_CONFIDENCE_THRESHOLD=0.90 +ROUTE_STICKINESS_HISTORY_TURNS=2 +ROUTE_STICKINESS_MAX_TOKENS=80 +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- A threshold that is too low may trap the user on the wrong agent. +- A threshold that is too high may lose continuity on short follow-ups. +- Stickiness should not block explicit handoff when the user clearly changes intent. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/routing/enterprise_router.py` +- `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/09_voice_interruption_replay.md b/docs/features/09_voice_interruption_replay.md new file mode 100644 index 0000000..85bd363 --- /dev/null +++ b/docs/features/09_voice_interruption_replay.md @@ -0,0 +1,153 @@ +# Replay em Interrupções de Voz / Voice Interruption Replay + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `channels/interruption.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Decide se um áudio recebido durante a fala do agente representa uma nova intenção, um ruído/backchannel ou algo que deve apenas repetir/continuar a última fala. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +áudio durante fala + ↓ +InterruptionPolicy + ├─ process → nova mensagem + ├─ classify → classificador leve + └─ replay → última fala +``` + +### 4. Como funciona internamente + +A política fica no framework, não no domínio. Ela diferencia sessão terminal, `idle_nudge`, fala não interrompível e fala potencialmente interrompível. Quando necessário, pode usar um classificador leve baseado no `LLMProvider`; quando a classificação falha, a política é conservadora e pode optar por replay. + +O objetivo é evitar que “aham”, ruído, eco ou fragmentos residuais sejam tratados como uma nova intenção completa. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```text +Agente: "Sua fatura possui..." +Cliente: "aham" +→ replay/continua + +Agente: "Sua fatura possui..." +Cliente: "espera, quero falar de outra coisa" +→ processa nova intenção +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Classificar todo ruído com LLM aumenta latência e custo. +- Permitir interrupção em fala transacional não interrompível pode corromper UX/estado. +- Replay deve usar uma fala real anterior, não um envelope técnico. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/channels/interruption.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Decides whether audio received while the agent is speaking represents a new intent, a backchannel/noise event, or something that should simply replay/continue the previous speech. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +audio during speech + ↓ +InterruptionPolicy + ├─ process → new message + ├─ classify → lightweight classifier + └─ replay → previous speech +``` + +### 4. How it works internally + +The policy lives in the framework rather than domain code. It distinguishes terminal sessions, `idle_nudge`, non-interruptible speech, and potentially interruptible speech. When needed, it may use a lightweight classifier backed by `LLMProvider`; on classification failure, it can fail safely to replay. + +The goal is to prevent “uh-huh”, noise, echo, or residual audio fragments from being interpreted as a full new intent. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```text +Agent: "Your invoice contains..." +User: "uh-huh" +→ replay/continue + +Agent: "Your invoice contains..." +User: "wait, I want to ask something else" +→ process new intent +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Sending every noise fragment to an LLM increases latency and cost. +- Allowing interruption during non-interruptible transactional speech may corrupt UX/state. +- Replay should use a real previous utterance, not a technical envelope. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/channels/interruption.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/10_workflow_error_recovery.md b/docs/features/10_workflow_error_recovery.md new file mode 100644 index 0000000..e5ef8d6 --- /dev/null +++ b/docs/features/10_workflow_error_recovery.md @@ -0,0 +1,167 @@ +# Recuperação de Erro em Workflow / Workflow Error Recovery + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `workflows/runtime.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Preserva o estado parcial de uma execução quando um passo posterior falha, permitindo entender o que já aconteceu e evitar repetir side effects. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +passo A ✅ +passo B ✅ +passo C ❌ + ↓ +FAILED + snapshot parcial + ↓ +recovery decide o que pode continuar/repetir +``` + +### 4. Como funciona internamente + +O runtime preserva o snapshot parcial do LangGraph quando uma etapa posterior falha e produz `error_details` genérico. Quando a exceção externa possui informações estruturadas, podem ser preservados status HTTP, body, número de tentativas, code e metadata. + +A feature não significa “tentar tudo de novo”. Recuperação segura depende de conhecer o estado já executado, a idempotência e a natureza do erro. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```json +{ + "status": "FAILED", + "error_details": { + "status": 503, + "attempts": 3, + "code": "UPSTREAM_UNAVAILABLE" + }, + "state": { + "protocol_created": true, + "operation_completed": true, + "sms_sent": false + } +} +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Retry indiscriminado pode repetir transações. +- Se a exceção externa perde metadata, a recuperação fica menos precisa. +- Combine sempre com Durable Idempotency em side effects críticos. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/workflows/runtime.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Preserves partial execution state when a later step fails, making it possible to know what already happened and avoid repeating side effects. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +step A ✅ +step B ✅ +step C ❌ + ↓ +FAILED + partial snapshot + ↓ +recovery decides what may continue/retry +``` + +### 4. How it works internally + +The runtime preserves the partial LangGraph snapshot when a later step fails and produces generic `error_details`. When an external exception provides structured information, HTTP status, body, attempt count, code, and metadata may be preserved. + +This feature does not mean “retry everything”. Safe recovery depends on knowing what already executed, idempotency guarantees, and the nature of the failure. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```json +{ + "status": "FAILED", + "error_details": { + "status": 503, + "attempts": 3, + "code": "UPSTREAM_UNAVAILABLE" + }, + "state": { + "protocol_created": true, + "operation_completed": true, + "sms_sent": false + } +} +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Blind retries may repeat transactions. +- If external exceptions discard metadata, recovery becomes less precise. +- Always combine with Durable Idempotency for critical side effects. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/workflows/runtime.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/11_clarification.md b/docs/features/11_clarification.md new file mode 100644 index 0000000..6ef6a15 --- /dev/null +++ b/docs/features/11_clarification.md @@ -0,0 +1,169 @@ +# Clarificação / Clarification + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `runtime/agent_runtime.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Quando faltam dados ou uma tool encontra múltiplas opções, o framework pergunta ao usuário em vez de adivinhar. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +pedido ambíguo + ↓ +NEEDS_CLARIFICATION + ↓ +pergunta + opções + ↓ +usuário responde + ↓ +framework resolve + ↓ +retoma mesma tool/workflow +``` + +### 4. Como funciona internamente + +O runtime suporta clarificação tanto de parâmetros faltantes quanto de resultados de tools. Para tool-result clarification, um resultado com `status: NEEDS_CLARIFICATION` pode trazer opções; o runtime persiste `pending_tool_clarification`, entra em `TOOL_RESULT_CLARIFICATION` e consegue resolver respostas por ordinal ou nome. + +Depois da escolha, o framework reutiliza a mesma tool e injeta os argumentos resolvidos, evitando que o roteador trate a resposta curta como uma intenção nova. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```json +{ + "status": "NEEDS_CLARIFICATION", + "question": "Qual serviço?", + "options": [ + {"id": "tim_music", "label": "TIM Music"}, + {"id": "hbo_max", "label": "HBO Max"} + ] +} +``` + +Usuário: `o segundo` → `hbo_max`. + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Não descarte `pending_tool_clarification` entre turns. +- Uma resposta curta deve ser resolvida contra as opções antes do roteamento normal. +- Opções sem identificador/label consistente pioram a resolução. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +When required information is missing or a tool finds multiple options, the framework asks the user instead of guessing. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +ambiguous request + ↓ +NEEDS_CLARIFICATION + ↓ +question + options + ↓ +user answers + ↓ +framework resolves + ↓ +resume same tool/workflow +``` + +### 4. How it works internally + +The runtime supports clarification for both missing parameters and ambiguous tool results. For tool-result clarification, a result with `status: NEEDS_CLARIFICATION` may include options; the runtime persists `pending_tool_clarification`, moves to `TOOL_RESULT_CLARIFICATION`, and can resolve responses by ordinal or name. + +After selection, the framework reuses the same tool and injects resolved arguments, preventing the router from treating a short reply as a brand-new intent. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```json +{ + "status": "NEEDS_CLARIFICATION", + "question": "Which service?", + "options": [ + {"id": "tim_music", "label": "TIM Music"}, + {"id": "hbo_max", "label": "HBO Max"} + ] +} +``` + +User: `the second one` → `hbo_max`. + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Do not discard `pending_tool_clarification` between turns. +- A short answer should be resolved against pending options before normal routing. +- Options without stable identifiers/labels reduce resolution quality. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/12_durable_idempotency.md b/docs/features/12_durable_idempotency.md new file mode 100644 index 0000000..98969e3 --- /dev/null +++ b/docs/features/12_durable_idempotency.md @@ -0,0 +1,163 @@ +# Idempotência Durável / Durable Idempotency + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `idempotency.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Impede que a mesma operação crítica seja executada duas vezes, inclusive quando outra réplica/pod recebe a repetição. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +requisição + ↓ +idempotency key + ↓ +store durável + ├─ existe → retorna resultado anterior + └─ não existe → executa → persiste resultado +``` + +### 4. Como funciona internamente + +`create_idempotency_store(settings, ...)` escolhe o backend conforme configuração/plataforma. O framework possui `IdempotencyStore` e `InMemoryIdempotencyStore`, mas produção distribuída deve preferir storage compartilhado. As configurações incluem `IDEMPOTENCY_PROVIDER`, `IDEMPOTENCY_REQUIRE_DURABLE` e `IDEMPOTENCY_TTL_SECONDS`. + +Idempotência é diferente de retry: retry repete a tentativa; idempotência garante que a repetição não produza um novo side effect. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```text +Pod A recebe cancelamento +→ key=cliente:servico:operacao +→ executa +→ grava resultado + +Pod A cai + +Pod B recebe retry +→ mesma key +→ encontra resultado +→ NÃO cancela de novo +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Usar store em memória com múltiplos pods não é idempotência durável. +- Chave ampla demais pode bloquear operações legítimas; estreita demais permite duplicidade. +- TTL deve ser compatível com a janela real de retry/replay. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/idempotency.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Prevents the same critical operation from executing twice, including when a retry lands on another replica/pod. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +request + ↓ +idempotency key + ↓ +durable store + ├─ exists → return previous result + └─ missing → execute → persist result +``` + +### 4. How it works internally + +`create_idempotency_store(settings, ...)` chooses a backend according to configuration/platform. The framework provides `IdempotencyStore` and `InMemoryIdempotencyStore`, but distributed production should prefer shared storage. Settings include `IDEMPOTENCY_PROVIDER`, `IDEMPOTENCY_REQUIRE_DURABLE`, and `IDEMPOTENCY_TTL_SECONDS`. + +Idempotency is different from retry: retry repeats an attempt; idempotency guarantees that repetition does not create another side effect. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```text +Pod A receives cancellation +→ key=customer:service:operation +→ executes +→ stores result + +Pod A crashes + +Pod B receives retry +→ same key +→ finds stored result +→ DOES NOT cancel again +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- An in-memory store across multiple pods is not durable idempotency. +- A key that is too broad may block legitimate operations; too narrow may allow duplicates. +- TTL should match the real retry/replay window. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/idempotency.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/13_dynamic_transaction_states.md b/docs/features/13_dynamic_transaction_states.md new file mode 100644 index 0000000..6cd06ce --- /dev/null +++ b/docs/features/13_dynamic_transaction_states.md @@ -0,0 +1,157 @@ +# Estados Transacionais Dinâmicos / Dynamic Transaction States + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `runtime/agent_runtime.py + mcp/tool_policy.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Permite criar estados de confirmação baseados no agente/domínio atual sem hardcode de todos os domínios dentro do framework. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +tool transactional + ↓ +agente/domínio atual + ↓ +WAITING__CONFIRMATION + ↓ +confirmação/rejeição + ↓ +estado seguinte +``` + +### 4. Como funciona internamente + +Em vez de manter estados fixos como `WAITING_BILLING_CONFIRMATION`, `WAITING_PRODUCT_CONFIRMATION` etc. para cada domínio conhecido, o runtime deriva o prefixo do agente atual e gera o estado dinamicamente. A função interna de estado transacional mantém o framework genérico. + +A classificação `operation_type` aceita `read_only`, `transactional`, `conversational` e `internal`; somente `transactional` entra no caminho de confirmação transacional. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```text +VasAgent + cancelar_vas +→ WAITING_VAS_CONFIRMATION + +AddressAgent + alterar_endereco +→ WAITING_ADDRESS_CONFIRMATION +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Hardcode de estados no domínio reduz reutilização. +- Classificar uma tool como `conversational` não deve ativar confirmação transacional. +- Mudanças no identificador do agente podem mudar o prefixo; mantenha IDs estáveis. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` +- `libs/agent_framework/src/agent_framework/mcp/tool_policy.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Allows confirmation states to be derived from the current agent/domain instead of hardcoding every business domain into the framework. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +transactional tool + ↓ +current agent/domain + ↓ +WAITING__CONFIRMATION + ↓ +confirm/reject + ↓ +next state +``` + +### 4. How it works internally + +Instead of maintaining fixed states such as `WAITING_BILLING_CONFIRMATION`, `WAITING_PRODUCT_CONFIRMATION`, and so on for every known domain, the runtime derives a prefix from the current agent and builds the confirmation state dynamically. This keeps the framework generic. + +`operation_type` accepts `read_only`, `transactional`, `conversational`, and `internal`; only `transactional` enters the transactional confirmation path. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```text +VasAgent + cancel_vas +→ WAITING_VAS_CONFIRMATION + +AddressAgent + change_address +→ WAITING_ADDRESS_CONFIRMATION +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Hardcoding states in domain code reduces reuse. +- Classifying a tool as `conversational` should not trigger transactional confirmation. +- Changing agent identifiers may change state prefixes; keep IDs stable. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/runtime/agent_runtime.py` +- `libs/agent_framework/src/agent_framework/mcp/tool_policy.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/14_post_finalization_replay.md b/docs/features/14_post_finalization_replay.md new file mode 100644 index 0000000..8175336 --- /dev/null +++ b/docs/features/14_post_finalization_replay.md @@ -0,0 +1,159 @@ +# Replay Após Finalização / Post Finalization Replay + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `channels/interruption.py + config/settings.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Evita que áudio residual ou mensagens tardias reabram uma sessão já finalizada. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +sessão terminal + ↓ +entrada residual + ↓ +policy detecta finalização + ↓ +replay última fala/fallback + ↓ +NÃO reabre LangGraph +``` + +### 4. Como funciona internamente + +A política de interrupção verifica metadata de sessão terminal antes de tratar uma entrada como nova intenção. Quando há texto terminal disponível, usa `last_assistant_text`/`terminal_replay_text`; caso contrário, pode usar a mensagem configurada em `POST_FINALIZE_REPLAY_MESSAGE`. + +O objetivo é proteger o fechamento lógico da sessão, especialmente em canais de voz onde pacotes de áudio podem chegar depois do evento de finalização. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```text +Agente: "Atendimento concluído." +→ sessão finalizada + +chega fragmento: "ã..." +→ replay "Atendimento concluído." +→ nenhum routing / tool / LLM novo +``` + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Se o estado terminal não for persistido, outra réplica pode reabrir a jornada. +- Não use replay técnico/JSON como fala do cliente. +- Essa feature não substitui política de nova sessão intencional. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/channels/interruption.py` +- `libs/agent_framework/src/agent_framework/config/settings.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Prevents residual audio or late messages from reopening a session that has already been finalized. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +terminal session + ↓ +residual input + ↓ +policy detects finalization + ↓ +replay last utterance/fallback + ↓ +DO NOT reopen LangGraph +``` + +### 4. How it works internally + +The interruption policy checks terminal-session metadata before treating an input as a new intent. When terminal speech is available, it uses `last_assistant_text`/`terminal_replay_text`; otherwise it may use `POST_FINALIZE_REPLAY_MESSAGE`. + +The purpose is to protect the logical end of a session, especially on voice channels where audio packets may arrive after the finalization event. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```text +Agent: "The interaction is complete." +→ session finalized + +late fragment arrives: "uh..." +→ replay "The interaction is complete." +→ no new routing / tool / LLM call +``` + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- If terminal state is not persisted, another replica may reopen the journey. +- Do not replay technical/JSON envelopes as user-facing speech. +- This feature does not replace an intentional new-session policy. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/channels/interruption.py` +- `libs/agent_framework/src/agent_framework/config/settings.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/15_retrieval_tool_guardrails.md b/docs/features/15_retrieval_tool_guardrails.md new file mode 100644 index 0000000..0a565a0 --- /dev/null +++ b/docs/features/15_retrieval_tool_guardrails.md @@ -0,0 +1,171 @@ +# Guardrails de Retrieval e Tools / Retrieval / Tool Guardrails + +> Feature do `agent_framework_oci` — guia bilíngue PT-BR / EN. + +**Implementação principal / Main implementation:** `guardrails/pipeline.py + guardrails/rails.py` + +--- + +## Português (PT-BR) + +### 1. O que é + +Aplica proteção não apenas na mensagem do usuário e na resposta final, mas também no conhecimento recuperado por RAG e nos argumentos/resultados de ferramentas. + +### 2. Problema que resolve + +Em agentes de produção, não é suficiente pedir ao LLM que “faça a coisa certa”. Esta feature move uma responsabilidade específica para uma camada controlada do framework, reduzindo comportamento imprevisível e código duplicado nos agentes de domínio. + +### 3. Fluxo simplificado + +```text +Usuário + ↓ +Input Guardrails + ↓ +RAG → Retrieval Guardrails + ↓ +LLM/Tool call → Tool Guardrails + ↓ +API + ↓ +Output Guardrails +``` + +### 4. Como funciona internamente + +O framework possui stages distintos de guardrails. Para retrieval, rails como `RAGSEC` e `RET_REL` podem validar segurança e relevância do conteúdo recuperado. Para tools, `TOOL_VAL` valida o uso/argumentos antes ou ao redor da execução. + +As configurações globais incluem `ENABLE_INPUT_GUARDRAILS`, `ENABLE_OUTPUT_GUARDRAILS`, `ENABLE_PARALLEL_GUARDRAILS`, `GUARDRAILS_FAIL_FAST` e `GUARDRAILS_CONFIG_PATH`. O YAML é a fonte de verdade dos rails ativados por agente. + +### 5. Como ativar/configurar + +A ativação exata depende do template/agente. Verifique o arquivo de settings, YAMLs de configuração e o template usado pelo serviço. Nem toda feature precisa de uma flag global: algumas são ativadas pelo contrato retornado por uma tool/workflow. + +### 6. Exemplo + +```yaml +retrieval: + rails: + - RAGSEC + - RET_REL + +tool: + rails: + - TOOL_VAL +``` + +Exemplo: a pergunta é sobre cancelamento de um serviço, mas o RAG retorna documentação de modem. `RET_REL` pode rejeitar o contexto antes que ele seja usado na resposta. + +### 7. Telemetria e observabilidade + +Quando a feature participa de uma execução de agente, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id` e demais chaves de correlação no estado/eventos. Isso permite acompanhar a decisão no Langfuse/Observer sem colocar lógica de observabilidade dentro do domínio. + +### 8. Como testar + +1. Crie um teste unitário do comportamento principal. +2. Crie um teste de integração do runtime quando houver estado entre turns. +3. Verifique o caso feliz e pelo menos um caso de falha/negação. +4. Confirme que não há side effects duplicados em retry/replay quando a feature toca transações. +5. Em produção, valide também telemetria e correlação de IDs. + +### 9. Erros comuns + +- Ter a implementação do rail não significa que ele está ativo: confira `guardrails.yaml`. +- Fail-fast deve ser escolhido conscientemente para cada stage. +- Tool guardrail não substitui validação de negócio dentro da própria API/action. + +### 10. Relação com outras features + +Esta feature deve ser usada junto das demais capacidades horizontais do framework, em vez de criar uma implementação paralela no agente de domínio. Em fluxos transacionais, considere especialmente **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery** e **Guardrails**. + +### 11. Referências no repositório + +- `libs/agent_framework/src/agent_framework/guardrails/pipeline.py` +- `libs/agent_framework/src/agent_framework/guardrails/rails.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` + +--- + +## English (EN) + +### 1. What it is + +Applies safety and validation not only to user input and final output, but also to RAG-retrieved knowledge and tool arguments/results. + +### 2. Problem it solves + +Production agents should not rely on prompts alone to “do the right thing”. This feature moves a specific responsibility into a controlled framework layer, reducing unpredictable behavior and duplicate domain-agent code. + +### 3. Simplified flow + +```text +User + ↓ +Input Guardrails + ↓ +RAG → Retrieval Guardrails + ↓ +LLM/Tool call → Tool Guardrails + ↓ +API + ↓ +Output Guardrails +``` + +### 4. How it works internally + +The framework has distinct guardrail stages. For retrieval, rails such as `RAGSEC` and `RET_REL` can validate retrieved-content safety and relevance. For tools, `TOOL_VAL` validates usage/arguments before or around execution. + +Global settings include `ENABLE_INPUT_GUARDRAILS`, `ENABLE_OUTPUT_GUARDRAILS`, `ENABLE_PARALLEL_GUARDRAILS`, `GUARDRAILS_FAIL_FAST`, and `GUARDRAILS_CONFIG_PATH`. The agent YAML is the source of truth for enabled rails. + +### 5. How to enable/configure + +Exact activation depends on the template/agent. Check framework settings, YAML configuration, and the service template. Not every feature requires a global flag: some are activated by the contract returned from a tool/workflow. + +### 6. Example + +```yaml +retrieval: + rails: + - RAGSEC + - RET_REL + +tool: + rails: + - TOOL_VAL +``` + +Example: the question concerns canceling a service, but RAG retrieves modem documentation. `RET_REL` can reject that context before it is used in the answer. + +### 7. Telemetry and observability + +When the feature participates in an agent execution, preserve `request_id`, `trace_id`, `session_id`, `agent_id`, `message_id`, and other correlation keys in state/events. This makes the decision observable through Langfuse/Observer without embedding observability logic in the domain. + +### 8. How to test + +1. Add a unit test for the core behavior. +2. Add a runtime integration test when state spans multiple turns. +3. Test the happy path and at least one failure/rejection path. +4. Confirm retries/replays do not duplicate side effects for transactional features. +5. In production, also validate telemetry and ID correlation. + +### 9. Common mistakes + +- Having a rail implementation does not mean it is enabled: check `guardrails.yaml`. +- Fail-fast behavior should be chosen intentionally for each stage. +- Tool guardrails do not replace business validation inside the API/action itself. + +### 10. Relationship with other features + +Use this feature together with the framework's horizontal capabilities rather than creating a parallel implementation in domain-agent code. For transactional journeys, pay special attention to **Clarification**, **Pause/Resume**, **Durable Idempotency**, **Workflow Error Recovery**, and **Guardrails**. + +### 11. Repository references + +- `libs/agent_framework/src/agent_framework/guardrails/pipeline.py` +- `libs/agent_framework/src/agent_framework/guardrails/rails.py` +- `Tuning-Performance/` +- `Documentacao/` +- `libs/agent_framework/docs/` diff --git a/docs/features/README.md b/docs/features/README.md index d09ad96..f925f85 100644 --- a/docs/features/README.md +++ b/docs/features/README.md @@ -1,10 +1,62 @@ -# Feature Guides / Guias de Features +# Feature Guide — agent_framework_oci -Escolha o idioma / Choose a language: +Guia consolidado e bilíngue das principais capabilities horizontais do framework. Cada página contém **Português (PT-BR)** e **English (EN)** no mesmo arquivo. -- [Português (PT-BR)](pt-BR/README.md) -- [English (EN)](en/README.md) +Consolidated bilingual guide for the framework's main horizontal capabilities. Each page contains **Portuguese (PT-BR)** and **English (EN)** in the same file. -Os 15 arquivos bilíngues originais continuam neste diretório para compatibilidade, mas as árvores `pt-BR/` e `en/` são as versões recomendadas para leitura e distribuição. +| # | Feature | +|---:|---| +| 01 | [Autenticação / Authentication](01_authentication.md) | +| 02 | [Workflow Transacional Determinístico / Deterministic Transactional Workflow](02_deterministic_transactional_workflow.md) | +| 03 | [Composição por LLM Solicitada pelo Domínio / Domain Requested LLM Composition](03_domain_requested_llm_composition.md) | +| 04 | [RAG Solicitado pelo Domínio / Domain Requested RAG](04_domain_requested_rag.md) | +| 05 | [Memória de Longo Prazo / Long Term Memory](05_long_term_memory.md) | +| 06 | [Regressão Offline de Workflow / Offline Workflow Regression](06_offline_workflow_regression.md) | +| 07 | [Pause / Resume de Workflow / Pause / Resume Workflow](07_pause_resume_workflow.md) | +| 08 | [Aderência de Rota / Route Stickiness](08_route_stickiness.md) | +| 09 | [Replay em Interrupções de Voz / Voice Interruption Replay](09_voice_interruption_replay.md) | +| 10 | [Recuperação de Erro em Workflow / Workflow Error Recovery](10_workflow_error_recovery.md) | +| 11 | [Clarificação / Clarification](11_clarification.md) | +| 12 | [Idempotência Durável / Durable Idempotency](12_durable_idempotency.md) | +| 13 | [Estados Transacionais Dinâmicos / Dynamic Transaction States](13_dynamic_transaction_states.md) | +| 14 | [Replay Após Finalização / Post Finalization Replay](14_post_finalization_replay.md) | +| 15 | [Guardrails de Retrieval e Tools / Retrieval / Tool Guardrails](15_retrieval_tool_guardrails.md) | -The original 15 bilingual files remain in this directory for backward compatibility, but the `pt-BR/` and `en/` trees are the recommended versions for reading and distribution. +## Mapa conceitual / Conceptual map + +```text +LLM +│ +├── Conversation +│ ├── Clarification +│ ├── Route Stickiness +│ └── Long Term Memory +│ +├── Knowledge +│ ├── Domain Requested RAG +│ └── Retrieval Guardrails +│ +├── Transactions +│ ├── Deterministic Transactional Workflow +│ ├── Pause / Resume +│ ├── Dynamic Transaction States +│ ├── Durable Idempotency +│ └── Workflow Error Recovery +│ +├── Response +│ └── Domain Requested LLM Composition +│ +├── Voice +│ ├── Voice Interruption Replay +│ └── Post Finalization Replay +│ +└── Platform + ├── Authentication + └── Offline Workflow Regression +``` + +## Princípio de arquitetura / Architecture principle + +**PT-BR:** o LLM entende e redige; o framework controla estado, segurança, memória, roteamento e transações; o domínio contém regras específicas de negócio. + +**EN:** the LLM understands and writes; the framework controls state, security, memory, routing, and transactions; the domain contains business-specific rules. diff --git a/libs/agent_framework/src/agent_framework.egg-info/SOURCES.txt b/libs/agent_framework/src/agent_framework.egg-info/SOURCES.txt index c6d6ac6..723d0a0 100644 --- a/libs/agent_framework/src/agent_framework.egg-info/SOURCES.txt +++ b/libs/agent_framework/src/agent_framework.egg-info/SOURCES.txt @@ -1,6 +1,7 @@ pyproject.toml src/agent_framework/__init__.py src/agent_framework/gateway_policy_context.py +src/agent_framework/idempotency.py src/agent_framework/observer.py src/agent_framework/runtime_mcp_gateway_adapter.py src/agent_framework.egg-info/PKG-INFO @@ -28,6 +29,8 @@ src/agent_framework/channels/__init__.py src/agent_framework/channels/adapters.py src/agent_framework/channels/base.py src/agent_framework/channels/gateway.py +src/agent_framework/channels/interruption.py +src/agent_framework/channels/transcription.py src/agent_framework/checkpoints/__init__.py src/agent_framework/checkpoints/checkpoint_repository.py src/agent_framework/checkpoints/langgraph_saver.py @@ -73,9 +76,11 @@ src/agent_framework/guardrails/calibrated/pipeline.py src/agent_framework/guardrails/calibrated/prompts/__init__.py src/agent_framework/guardrails/calibrated/prompts/_context.py src/agent_framework/guardrails/calibrated/prompts/ausencia_oferta_proativa.py +src/agent_framework/guardrails/calibrated/prompts/coerencia.py src/agent_framework/guardrails/calibrated/prompts/dlex_in.py src/agent_framework/guardrails/calibrated/prompts/dlex_out.py src/agent_framework/guardrails/calibrated/prompts/fallback.py +src/agent_framework/guardrails/calibrated/prompts/fraseologia.py src/agent_framework/guardrails/calibrated/prompts/out_of_scope.py src/agent_framework/guardrails/calibrated/prompts/pinj.py src/agent_framework/guardrails/calibrated/prompts/ragsec.py @@ -174,6 +179,8 @@ src/agent_framework/persistence/__init__.py src/agent_framework/persistence/mongodb_store.py src/agent_framework/persistence/oracle_store.py src/agent_framework/persistence/sqlite_store.py +src/agent_framework/presentation/__init__.py +src/agent_framework/presentation/renderers.py src/agent_framework/rag/__init__.py src/agent_framework/rag/embedding_provider.py src/agent_framework/rag/graph_store.py @@ -200,6 +207,7 @@ src/agent_framework/supervisor/__init__.py src/agent_framework/supervisor/router_supervisor.py src/agent_framework/supervisor/supervisor.py src/agent_framework/workflows/__init__.py +src/agent_framework/workflows/graph.py src/agent_framework/workflows/models.py src/agent_framework/workflows/registry.py src/agent_framework/workflows/repository.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 35a52809e59818a3e0eed44e221a5656666bcdd2..adb49c3eeaff0e06d5ed31cdc353941b81ec9088 100644 GIT binary patch delta 305 zcmeBXTFuP+nU|M~0SGGd+p^|NXMZOG+~H(u-d*0<~%~7BPV+=34@uDXF;y`6a1&$(6w+ z`9-O>Bs}wcQ*-l+Dluh}i&7IyQsXmIgy4GOi$R+FG}$Lc%SYYf&P142!~(RTh!sSz z0g06ipMfO9tvdbOyb}Esecxcu_<*APtkmR^V*RwtqT-VHbyYhAjcPr0*MdIjEsyoxJ5g38rbhLs6J(qX1M-0lHG zSyt34OVlc`R!S_lRwzG&{n*0VA3nAC-H(amR@gRfQKhw8{IQi(MfYpZ>7Jgvz%Osj z+`jkRbMC$8anCvT&NVbd36x3e-SL(NLVm5M_mx)YdrjPV8l##F<>I>13 z_hl*TeL2d(m+j+w1uA$rTwl0Xq+)M`MtY+(+8d)WiJauJ&A}3j-|a-^+Zn%48=499 zg-t{bw})!5ga;D=7CD({XKT=;9F;?ItTiMz$ni~NoEs0(#zH8axQ7U7#*L|_X*sH6 zSf-tUKHF(dra8Bv$9z#QS#+{X)y8x;)=yQfsQaC0R?i!DZ9snMgyHxD=Udc*ZaT^+ zRZIFgi=J*Z@_K2)a&%Lh)cg(kb!~Ud+ywM5laqupG688ZAgK^YiIq8-hdn2dM{m#k zNkLA^VeGZnW};!aQ3ig;IV#F){;BH z>{wL42f8KYqfljF@AibM=~8|3jxMPamZ9b?$+RRJ@PSVWSiOCN8k!{me34~0R;SY@ zGdDtR#0+M1V~$f)Y+bX=ysg#rM(~S&kO?!l3mTWnP-79kei@RAHLVje^kgxhA_a1T z$=qPw@QA9N*3CRk06tAZ1={0my*NtOBBTzsIp|7I+_&0Frqh;hdr|ID2Byx${&g-LUx#*nd%g*TU52V8`H*Q;|%je6b3EO3D zhq~c0)gA-syMjHY?rq=a3UJ7*yzWNE^w;x7LARZB$mJ(g>Hq~*&)FykNuo{gaT_$% zv`j-&i@2h@Wt9$=jU$P@AF3(xQzCV7{QdDOP1kd`@_+A|P7J)q&L-DieDnP`uV|l- ze>#4BLv_oZYI5&P^6+%>a5dRc5j!Zlv%0-Q8*SaU_Z`r<4BE&dbVW&kj&e+bJjH^{ zLK&Ailx940z7eA90M}(vT1(mDJZ_p+af9GZKw;xXz?xF)KWY7_wX$a0)iqb2y1KKH z+*J{Gt==X2_jk~yC^Q}=(nEKeMSfNk;HefLmJZ~Yz(#^^55$Twpg+r8W;1-8>>wh^ zaQoR&hOPn1H0vE>mo4ZHeF6aVcTg?mnzjMJUAKy9AlQtk=u++>*G(HgIr-7anWml7 zO*^mVzcj8HH`y=DYE%16vb`dAUJ+ea9mArb|5(4H+rT+cf)ipe^xD) zb&tWibM(#!-HXGkMG8|%Fk<6b_CyM&p?IMuW!I^Llx@`{Y-r zDTfOGhZ)^!>DA0m z$m>Pj(H~-Y`(TUihEw};_D-mlNow14V%yanU#736uXlaXT21Vk5%*NZJ%QyN z0L$CQeI*=VD0=?1;0G}d+I}S4iY?US|DuNJNN-3P%hb~xMMpvr%@wHbl&MJ(69!Pz zUYi~aTC1Svqmc9jbBRkxo3h6~|ovH4G%KihhG9>l>Fc-#Z=KrSorcv*PBe6Ulv zlL>)~d{Fcb3@3~Htti2m$qq+?pzU;;{D>S4@R!KQ z-)po^&F5G-hDM=+iiYdiXO7e{g#I@GCw^$ChJ*ghE6Z@k0jHskgTZPw&Jf@vytN>` z$Z>(*RM`J8-Z;D>CxexBX1FPU)@3C0w=bat8(%`%m}4R5t4jvx(Xzdg-59hMzw(+K z8{B~<@}RYb(ZIbjq~>@zbrAE(wPl4Nq>CDAaL>E_7gK|tt(PSIb)#TV3GO|kMgh$G z_LsN6fNNfPq6jH-UX|dddTno@H5whDx~Av-84g7yspok2iv#_G-I=ael!0vjAE2L= zc7gXd;jReTJ=}frRvHkyUg+-X8|d%J3@X{~fquDXus^#<0tj-qEcf(h9x~e12@@#C zI=lM1Gso*IMWdazZIq;PY1uxdGi6;GzkN*t|7IID+-gs#X5o3NPK-&wbZ6PIOsiy- zZHemY1hvlUhNDVW6z;<%OY$E8yvwo#w~Ccw%j=Rp3Ivu7(u0J-wCvU>q)-nKgiG8l zzs|SY@+)k+>mSUuE0nwk3%6zIqS@}3ay{8@<#;aJdF({@bC9kq+0x+P2}SPi>dzdP zjj5Ly(g6nxG6=Zf!()dVRqG;gd5UiyaN9algy)V9bYnDwRTe2k!}J#~4?wpTxoQRl z{_*y;vw9Jv3JRb`UVTC;skQ`Rf2>@RP|!wRr(j++Jh-}nlIq5nx5}7?z(u`=SAUsU zxqyjQ3gHVbl5lxHB$Y8jJe+PP>|q(jGg8_1EEIUT{WmxoeoRbw>606V3k4<_5FsJc zm~i=`bxx-)H)2^umxW}EVi2b28mS1C8_$+a$0+IDlv>n_rLIu43I!kvpHr!6m<2B{ zf%~lpnY9Cb+YhsSNG=AFaT{wPMyZ9IyvxEvikBJMxEwxeK=ERm+pK~0I=TWf4W6DL zMS>?DItr+mL)o2h@~6mrGih8qD<&_Al}%6H++G#i7YG+wHycY`I#AhsQjxDeN z`N@YIx^=7?dv<{b$h<(}YZ0sc=Ihni(SC?Akxav&}+@ z(K(ao{W@2T_Dyx&4JRvWcUQx^XH%Q6j8#*QUkKlcthw}ZHS)-8>X9o$)zo7?WT+b1 zybPz()K-nO{VUcoo7z&@dZwD9l{lSEZT(~0h48<9=(fR1?$yfRYn81^HFc^IKQ${R zE+#G{DjRZ@mzD3tQy%(z;n`TrmFK_KrenPouGdQoAU|JBP*7{Hh-`=o*9o literal 0 HcmV?d00001 diff --git a/libs/agent_framework/src/agent_framework/__pycache__/observer.cpython-313.pyc b/libs/agent_framework/src/agent_framework/__pycache__/observer.cpython-313.pyc index 7300893fd31215c0495c06bb1660c6528d158d63..cfb87c2c36f5c49c909d08d2fd790449117fe32a 100644 GIT binary patch delta 6817 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 delta 2906 zcmaJ@U2Ggz6`nggJNsvQAJSWr(go!LgP6WWZzT*J`c}P7pg5waK%Iy-3Dl);)7u3~ z=uhdJ1?tv^^_W1(l%Cc#y@M2V+M{pR<6@#$m&LD>|B}UHBYKx$$k4Zbe0fAqG{^h( z9eTI091x6TM(&r^|MZ=DPm`P4kkQ*@3~tEiYcht2v8+F7nf@ka%Z5${nvAU*GEz;( zwz8~c9?WVUJl`iuC$~XDhXq?7qp86g2dqaOFzrBv44M50`-f{;i%qmf~;qObsPy zw6pN#igO;lm=0Lg!n|>=SgSfV?8V7L^+4~a+$EkmPGq%W+6FkTa>1&Ye71iaw`;k- z)BhQq{A~Su{c|C;Q_CcVUD(wkQ1; zapVj2neDD}@f6W!QD_k_7=K~*__H%W-3N#VWDY8cAPQHlTII3n=ttQXi0c!s#Hd(kMS>)bgE+w!+=+s977yl%0pQ^H zoBY>fEGCZA!f#w*#uaL^4D?M1UxvH11upz4E~3D@|0*{Qj! zX!VK6T%~GR3$Ef6?Tep^&F_Ww3Yxu(e;ZJIRca)C{ukN(Xy;#|!|z9j??$z6DvcmN zvwLDXBDEw|CFV`Pdi9m7KiK`_t?wNDW6#{(=$ZF}XBs}5`;Sc-`So}%EZq*Lb6MZ* zNtVmV zKutyL>xu$HgdZJ>8-CP2=4}P1=tR7H@D(d1xPe2i#Pd(TH%iVP`l5}1S5Z7}0~s18 z@ehd~+4tb|D8iHAh2axzNhG@$i~kd`z;&_~x#34dku*b5iqvyn$H9;Bze*MOfd657 zJO9;`yKij`%x~&^-V!3j*HE<|cLu~4g4OR#tL*tP)YoF94!9O0Ji&ph6tQ2z_mS9& zog2PO7H^>7A549R|8#$PdCen6wB~Tbh=>m)y2;;7(x@yoc0^O5lT>;H=pwNh1?7fQ z15+qk^GL;u5|ZoXjBFf8#Og845I$LARckOK$c0TPO%g@ zYgyHYK?q}t65Ue)EVVZ)J9852^>of$JmW1O77Kcr^~43p|C+a_+;E|Au7Kb#Ly8-qc3UyaqSLw|=R6q2dD5v!T-8}zAjQvFZkVZD%k5aEM{`5iL}x{#_G(tN z?r5Q~?%M*_2~!Xz3HpNYz63;#iu4s3BRZ>i!HAauHFD9DMd^S@B~kcPprYbFFY3d~ zZpuxOP+${U>+!+qOV)g?YV3!f;RI%zWIu=RQ0zvG{Y@HbC=sTtCM6cVC$-&^LVuN# z{P{zB_{yP|vK?&VgK%rZhxdjmMN*9bp`aAq+6WN}OYOal2%#29?fJMB(Z4eF(z6HI F{{WBWe-Z!y diff --git a/libs/agent_framework/src/agent_framework/analytics/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/__pycache__/__init__.cpython-313.pyc index ffb0cb857c288400b81652c4dceb67409f4c539d..79a9c4c358ffb5c7493ac2b2658ffaac5dc967ec 100644 GIT binary patch delta 100 zcmaFKyqSgjGcPX}0}xc^w{7IkV)X9N&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY qD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjB<7>fbDP9#+M#mHzk`2b@v0AMT!E&u=k diff --git a/libs/agent_framework/src/agent_framework/analytics/__pycache__/composite_publisher.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/__pycache__/composite_publisher.cpython-313.pyc index 70b42755d78780417536909ede1a76d7fbe3a8c0..b42102664dd8f88d8b26acbe5a2942c31f87218b 100644 GIT binary patch delta 101 zcmeAXz9!85nU|M~0SGGd+ct79XY!t`pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&-Xf{D?2vmNt3MgVS?2fP3P diff --git a/libs/agent_framework/src/agent_framework/analytics/__pycache__/factory.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/__pycache__/factory.cpython-313.pyc index 1586e5374eb7cdbbd65486d3a1bb1f0d2644010d..17536e650fc3911c3b5d5f1636aa8c29f8b241be 100644 GIT binary patch delta 549 zcmYk3!D|yi6vk(EH*u5fZW0P>#b{Pa4574Z2|3vWdWcOCu{87`9+v6uY}~lJQ)V{N z3L;)AJyn>ycR>UVconQgk3uh@AowQ;&CQFmRK*ALoB6(vH}hb=Ro+yMGhNREQF~;6 z_{(@_tVy?D*ioF=o_(jk;cQYe#BRcDKcFmeToNaUIZ-g6$Rjoy;P|ikNB9&)_z|HG z9pVNy-;_Q|rZOqZm*wIL0QW2DTWM|8cv+dtTC?5DDhJ|(0N^poHoX`MS3{zxzn7N21$U_!Nutm~a z9|uv1SQN8FB(xx=ZkYUi?zoV_loEQX3`xL8`49P35tYPZvq`HkhKn;5}-phL@T6L;jnQE0;A)Cw33{bkx-)ar%F62|K*<8P>e5z*!kECns3(`?7 zO}S(Wep#@3YUb+&*i(5&@4z;Hs*h{w5U;_RAfRP|Q*|{W-YCQ!dP~Uk R1K0|mH*Vy*5H@L7=--pnowoo0 delta 205 zcmZ1@e?f-tGcPX}0}#yB&(HeBvysn{iP3iQET;WTCzv-!GfOj1e#R`ps5<#Bn>wTV zWLEZMUL^*GGzME{d4@DbP4Ug8?3bCCG({#~=Q=uhCHEFCE1*#VKwNx!b2?8MBl8`8 z)yW)unvB+yjroj?-OO1Isj~se!%T{9HcW?ALF5q*MWTr$V>Sxzimb;K r7~K^o&*ZZM>b}8O#%ML!pI?g01!y`W$OePS#ry^w){MqQ&Oj~zjc77; diff --git a/libs/agent_framework/src/agent_framework/analytics/__pycache__/publisher.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/__pycache__/publisher.cpython-313.pyc index b9d5d60d1a897c4a7f211949ce4f409b2f4d6eec..fa87ebb47ca2ab8dbcf280c24a2aeeb765485b20 100644 GIT binary patch delta 101 zcmbQn_kfT4GcPX}0}xc^w{7G;#N^$npPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&*>h>6jDvjnpT3jk*12Fd^c diff --git a/libs/agent_framework/src/agent_framework/analytics/__pycache__/tim_payload_mapper.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/__pycache__/tim_payload_mapper.cpython-313.pyc index 5086a1931aa770d81c72eb6dc0448c872b9b79d4..0fffb667e6e9d090d31695ae0c7a28acc2fe8cdb 100644 GIT binary patch delta 1323 zcmbtTOKclO82-om^mA>Rw0;n;8;o5iPTWc*5>2RDk+?54pl*vqeb_GXLpF&w%sN65 zNa2K#5Gd|Y6;LHoDNT_$Rlf9AgrEo{M50P0Ea{o6QG5W(ff+l-Ipk1@UF|pD|NXPy zH?x}k;q)(OeLG&S3+T0IzF+wXDf_5$kERVmjq zmPnnC$PQ{N#UV;&`PY4Wy4~2R{bG;)-`J&YER^Vd7;=5x1?LX_$9mfecD3GkoRh%d z0AirR^p{0=iBqA7p4MrwX9Td{twluQ!Bai1;D8`vu3Et$s0h%OAfhbRlt z$0{RoLwILN3M?mXJ+~=EH>Bvw*xiZS6L(MEKG}2#&cJqm=;qbyS69SG{mBoq+e+xu z#AJefE&j_oOzSwvWyeE>k z)MroO0X9p-h1vqHVv!ap9{029jN`Q~ONnhie1{2b`!-u6KdA#}zF;CV!Yd5g9kvde zf5S9qJ0?s_xowxO7Z+$&LDw-o*noKk0t1z#V-b;^6}(C=#==LxqLls9)@2IxTO;%s g27ia-Z{U6m2U{YK{4Jk^4z&6PkiU5r5fU5w7Xh**-v9sr delta 577 zcmYk2O=uHA6vyZ7*KD%xrqB>vlkBqgNP^RZK=4+{^mdbdGp@e_jP%D$@}TLMW&vu zlf&@y!Ni+~FljU{Tr$zDG2sZ~5DN{o!~tREiVIg*xv~Wp_6ex6|6k#W0-c5$7W&0x zGf1{Sz_R=T*MX;XEdcQ36}_XaLi$cGfsD)>TA#@o-U3T5@>816<$HeGjJWDa{^BjC zuEf0hqA`8G*83LU=Ck zmlvTfKbEWI1v09Hib7^|J8=h()Bc$JUA|~;D%niWAAW1CT=p%bVg2#CYq#T@QH()t zX|S<^4&Bt%KC`eFk8psNa(n}4)skx*?<zYqwFSV1r;%uoZ9IT^scG3VUSF5onS~zw?IWqeEBe%szW( v*d49+&f#m;WDJxST~*lC0bqyKzq7^;o10h$Oierv)03GJOzj4;cJ$0&wmg5? 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 7b9a85a935b87ec324493f8b85f954c8d5f6353e..e9ab31def78abbde9d67dd7e617dbdec3b9902ed 100644 GIT binary patch delta 6093 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 aQFF$l&+Tb1*?0m~pz>dLHKI~>3jYK1_0OvS delta 4297 zcma)9eQaCR6~FgA``LcBn09 zL5iWz)N7)qUNbfKTBt?m8T;g3E4B98sEwd~;y@W2mJ8Y6t1J@D+b0ZEv8QllJb$0$ zMf(a`FgJh@btBFg(y}X6)Dw#9)hPpMamc;7)x ztCa?&SeNrEC5LOWOTx7*jZ0lVrBv^$Q`ReGI$Fp1oj#>pZ`CV}N`;OZ{*RR=rIPo7 z6`!&}snX@vj|)D3VnBEu<8JnC!vHR1=M2BY6^U`<62>I4)wCJo^$E>y{@l zZcXgAx-jl!0oy&sKfzv}VQG_>y>E8o9c+)>hSvkFW51N$ci0gkXo&B({!d5Q#;(fXr9b z2Frp8g(Bl1AK`Q2Q=geoVgAt^6(po_fw9o|G*w6aa>~mBmJ;^oyq#5!>{?cr;uC2x zY&|XEq>EkdcCkK3vC;!gZ4ZzWXvK*v){~aUEJK>iK|vAMqzpr*RUwq?Z-XLuopI2Rhc+2&bH`#uS{rNp+SoYa&Z-YK z4H`3peda(V*zTSVg|p|X`zAT0&NjiJt7F_j;QV4V5YYk|-wSEcaDX2rIPl1brfS?T zhC`zxBZR7xflx#v0r-O>oty%>1EFvzHcQ6h;3B$*=ur_Kg^&QR8l4V8D1gfZV)AGd z{31qX)ffZ|IMv8Vj@g}{-%tA08KQf)Mkc4V7>^VJP6@U$^PWTGG^L+26_+IciWE#+1BDlXU2dvM-Mw%e5ZW^WVJ~k;MyhZ zYH^wG15@GEA~Ii8lTS#AaDMEMq{00NSV~zSON6MZb;alp zp`8$`tFd&JPo$2m_ts#-`n^3^Vo!KmTqWhpmE;qnSef^U%kGsQkF;*dne!=F+|X~05Vt+`@~+uqyQJJc~H0uD+ah4%m)n-JfvUIU=|J7IQ{bD zMT58nvuo`|dts<__#2orqy7NAJK!y^Mnid7g(eh$lZCs2=Lr27aIpoC>u#eWDW*1< zng{i_jiGI#2aVxs-CDK~DI6VjJw$nJs}*;u-%#35vcY!=6`&vNWM3)B_GgOHx} ztjdFGcQi5{y?xJ&MuYkt1L->J%S4NXAW_dm=^>5GgklrX=@`TwuyeV07=>OomGeR zCDRzN;OaTXyBR0PfoOb!gq)y|!BNUIoEeeYz%JHT#Qk@NqrpH}>+rAgm-z?<$juYz zz0%s}9(Z=&Qt6$iq_kits9CPAf61}b&~~}H{oSp*mbUg^uHJL1ciCNa#oc(>-S|S^ zTV2Tq9!&Da@O5|D*b?xPrCC8Q^L5$Lg5BBW5s%fef3K_a?DgT4Sv?wr zMT|uu$R(oo2U;6ta*mxpK_A3=6l#P zzS{WDf%_J`+Dkxg{tYtJjXY$oc*j)!Gw%R9q7HfJ+9cr`&W&#yxi1C993&VpC65;y=C) zY~{O1`7zMv*p9{rq~`&CjM(#y*W|S{`8uoixiaYy<>Wo~T+_YHkSua}ka}tnB$AEr znpTqun)pgGIaqWKto#>Vtr-YEx@(T|$LHA8hVni66({F1zaP(iq4B%#2iC4~{1d!Q zdRzo>x~vO}zpw$ifIFp&5`Z@_kOeGtm6#SxxJ$Mzm~9-pOVzUc!hji@n|?QY&;SbU2tD%Zv)_4_K~%aZQA@n+$Yg;u7{U~v;s)Va3C5D(|O+h z4G^F3HJr*Bmb3~8P)p1;LR>y9RC0faKn>pDZ=Tx^npG7|0 z?=#aNZ(iVJbPcI%Xr3covqX<%aVFfk4SmM9Amzuhld59zm*Jn?E%PlmrH@fQBKe~3} z7g<}k2fxO?+ud9HGj8iyPR??o2O*Ch%x>Ec|SyX zf8~D`=IE(56`!1YZ0<+jV_SOek7L}iV#c@^ub2hA1E=$mcU{_4fVV8?m83=ZUe7N} z8{wOlP@zZff&3;}KC=LCrNNEeX+J8dOd|KPyZr2~Cw8&^Bq~Tteq6k4v86@$UI$G^ z_=1Ll^0bK~GuLGSRFRgEvoLMtOdFE&SL}dR4&VyhknUiO+qW4-T$gsT$?Z+n&mP42 J*hL8}?tj$PQq%wd diff --git a/libs/agent_framework/src/agent_framework/analytics/providers/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/providers/__pycache__/__init__.cpython-313.pyc index 3eb59a0f316d9dd6759489e136bcd2178afe20be..3159299b3c442a53164b10650ba2da13bc8e8508 100644 GIT binary patch delta 100 zcmX@XJc)(-GcPX}0}xc^w{7IMXY`(=pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&*x&&cR8c`9Qq09Yyps{jB1 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 6cc8bb37ef8d7653a6711c1f2fe978c58d57bc35..15e67e5d4a46037bfe2d2b4ed23f7938f6b001dc 100644 GIT binary patch delta 101 zcmcb`yM&MXGcPX}0}xc^w{7HhVDj$Q&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjZ3nEF@%(!nG^ delta 27 hcmZ3&cZ-+%GcPX}0}#y9&)>-Hz{Kdfc^Xq63jk$32N?hW 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 ce24c06619a2e1928fc810a6faa1f09415a55778..d351d93ea8076e0a961f0424586e99c127a50399 100644 GIT binary patch delta 617 zcmZo)$M}C8Bj0CUUM>b8sLXH6s&U=O7ticHNk2EQL_bB}H`p^ipeR2pHMyi%KP|JU zxFkL~Kd&UQI6gNsy(lpyUq3NDH4i2T<)jrQ=BAeC7iGuiCuiz!&SU0KW!$p4Tw?)G zR00D-G%Lt15D4WmWrVPT6+@Xr1%j3ISn>p;)gfXG45m1_`t4;^r5{&F{z>Y!JI(>2+DwdxF~sCKf?I#>s{r zqLbs@6xmf71l$T8xj%Ijd4AS?=1T10h$ezN&{Me2aDD;Gx5y*bR z!VF@wvjMGm!YiL*!2Co9ETYc{VjFB*_`k5 zn~^=3iM4?7d)DSczqO2vvo^~IWHT}@ncN-tfN{m-oS=h@Yc}fz*D?!wF*61+UQjgt U!T@G{iJH78Op>vF^0hES05H$5ApigX delta 481 zcmeyrjb8n5UngRqV2nFP@pvWAhGX4pqiUn-6L%;9>P=V2IY8tfw!- z6|5M_94Zj3q{p&(o#_WI#x0xYJ6vP672y=W!!I_WWP0ty+6!tf*ZEy9^1I%V)VU)g ze?h_IvW)2sdDR=Tsy7r2KXS6_34P#V5K;Zi%_^lff$am&|30?NutcR#5h1~IYFSBTL#X;$u<0lOq2=0|+YK<$qN89{6zFk6%> zNtykTJcu3jNC~9xkuq39&5=FXnEA0TD^TdM5hI9g%nV|iu>q}kY$Kl{&-_FhB=SU# z5yX}Uvz6piS(u+Pg6w?C%m`w$0L3@kc&%b$?AZL==Qks}KND*K8cFM1BR5fs8*sluz~xHv|Byzl}Hm diff --git a/libs/agent_framework/src/agent_framework/analytics/providers/__pycache__/oci_streaming.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/providers/__pycache__/oci_streaming.cpython-313.pyc index d00300c961ed6ee49f4f3d9f48b173bd046bc28d..29655c5d090eacbddc6ac1f2b1c4ecaadcc04183 100644 GIT binary patch delta 812 zcmYLHO-~a+7=CBJy8RTa7DR{(BCv*}Xe1;?KB@-=;zrpJjny=zotDLR7iP8?j0wa8 z@utm&c+j&(jfsiBz<(g|K-kEU7%xU6YUJe1Qsg~6^Sqxk^UQpSzD*>4#^VuSw&bkN zy^-sQRy0xX)q6}ZrAcKXL_!+0LKm2F8<@&%c~IoV07NZ^bhSQrrd>yVE4FEk;2gyZ zHEb7f4%>^k;>_dvvnmR|52HSWqTX5IbTYSZQxf zSV1u_B~C2AX7f*i25XQ-j0QF>WQBb`*kFB)Kt2hO<%bGvS{Q6}je`lZOov6ZCK_@K zY+)Lvl>NGcbt-(o8S@^CJwtse7@;Atgmh#uAtDyFZ0hEjXuedm3NGPuNSuKmny<}N zEIO-;q{&+sJEMnr>KIS;c;AE*1C9I<7NM6Ie1#R*i9sy&r2O37h<2|>yFa&|dw1hg z`|w6;_|au=Kx$cDS4V${&@!^Aj{c>ctm|QSCW&64%pvJz7h@m7DAO!`h$x&lBZfK( z&Z7&4p-aJ|?M5>8lJ-C|92*BY(!mDl3Tb1DFH)C~PJHA4&_lkWh zrYpOMw<~p=KgwxvF_kk8Ts7LvU==nc^S7kPH_@LaRUShmsOB|>9`>%wR|KZSg4{Oa zTGjubZ%@HsS}&{I>)|{2>V>LPtX1#`>1Qr~OsX;XE+T}splcga+i-CUCU=x18bcpX L4gCU6f(icsOoFy_ delta 498 zcmZ3>_ne#WGcPX}0}#y9&(BI`p2#P`Xg5(^Q%ZtCi6NLpiXoUahSiiAq=12;h%KE> zlYL^D;l#taj2xQ{88sLgxh6+3X<2duWi?rEu@tA~q!odTE8+nXw**pB(-KQ_O5%%C zOG+~H(u<2g3X55RgaQcM@}11i+`z~^xr5nDDGVs8%%H$9l_8WN2*^eULClj~Sd3*@ z&6(2}H5vUhnILws7nCODWEN*=G8gerUdN)yEeOj0XA6?5fBsXMs^SjL~u-YWD^x+WOZOH0?UHL{507or?YwZffW>~fRw^@-r}&y y%}*)KNwq7|07@_daj`6r_`uA_$at4Q=_!NQQwFCmY&?t(j2BeRzcPRrVC?|G6J=BY diff --git a/libs/agent_framework/src/agent_framework/analytics/providers/__pycache__/pubsub.cpython-313.pyc b/libs/agent_framework/src/agent_framework/analytics/providers/__pycache__/pubsub.cpython-313.pyc index 5c251f36002532e20738f3d256ead43a8a35d35b..3d88873dcce0e319b41e374bbacb5758c7d6a643 100644 GIT binary patch delta 101 zcmca+xxkA1GcPX}0}xc^w{7Hp$KgFeKR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX-Xj)T!{vkT`PVE}T`2rvKu diff --git a/libs/agent_framework/src/agent_framework/billing/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/billing/__pycache__/__init__.cpython-313.pyc index 53bb2f90d6611f71626a7c82bc18e5106fdbc018..385e821125fe24312078c1605cce5ad4c2eb8c55 100644 GIT binary patch delta 98 zcmcb~w3wOuGcPX}0}xc^w@u`J?A@lHn^&TrqVF5*86QxTpOum*gnU|M~0SGGd+ct9Nv3vLF=jN5@r|A0zd&UP8__RGcPX}0}xc^w@u_W_HNP7%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP oNi2@f%}g&!Ov%?zOi#^&2|_t(MTxno<@rU~@%hP_`V;MA0BMpVhyVZp delta 24 ecmaFLIGd6CGcPX}0}#yB&!5O`%xE>SGX?-o>jq!| diff --git a/libs/agent_framework/src/agent_framework/cache/__pycache__/cache.cpython-313.pyc b/libs/agent_framework/src/agent_framework/cache/__pycache__/cache.cpython-313.pyc index 031db81895d5f62eb3819fa88ba649124473b170..78b45b818687a91690cfad4dc840e990ee7021a9 100644 GIT binary patch delta 103 zcmccEz&N{+k^3_*FBbz4ROYvB;M%QB#Zz6 delta 29 jcmbQ;$at}Vk^3_*FBbz4%+=4|$SusoXudg<$;b`>dUOY5 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 dfe01b6ade6bffb11efcd3dcf3c419cc7a59acf0..eff88e24dc71695ba241c9409adc5a0fef6d3f35 100644 GIT binary patch delta 98 zcmbQo_=1u9GcPX}0}xc^w@u_W_HNhD%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP oNi2@f%}g&!Ov%?zOi#^&2|_t(MTxno<@rU~@%hP_`V;Nr0c^!1lmGw# delta 24 ecmaFCIFFJ0GcPX}0}#yB&!5O`%xF8YGadj>ga&K? 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 78a8552577f516f2d844f688aa098db1396aeb92..299197d854d5a427ffafeabb22d0f16018a682e1 100644 GIT binary patch delta 101 zcmbQFa7TgrGcPX}0}xc^w{7G;%jDgzpPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&*>mWk1Jvof` diff --git a/libs/agent_framework/src/agent_framework/channels/__pycache__/base.cpython-313.pyc b/libs/agent_framework/src/agent_framework/channels/__pycache__/base.cpython-313.pyc index 847f9cedaa7262b91461e38c99bbf17b78794701..a10e14b6e0b5b2e60bf2b788016902ff1baa1b49 100644 GIT binary patch delta 101 zcmX@bJB5$?GcPX}0}xc^w{7IMV)Aa*&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjaEm|9o>z+)r+ delta 27 hcmbQjcZ!$$GcPX}0}#yB&)>*x#l&d2c>+@l3jkq72G#%o diff --git a/libs/agent_framework/src/agent_framework/channels/__pycache__/gateway.cpython-313.pyc b/libs/agent_framework/src/agent_framework/channels/__pycache__/gateway.cpython-313.pyc index bdfb79a44c3b368bebc851c95a0e642a8b372e9c..f81ae9e2e27ec43c50098afd407eae5aab46ea9a 100644 GIT binary patch delta 101 zcmcbpGh3JYGcPX}0}xc^w{7H}&+gr(pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&*BpPkWW^H=s|d;o5D2qgdj 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 new file mode 100644 index 0000000000000000000000000000000000000000..fb063321b42a7d77d0dee43ab4a1f8d0aeb22df0 GIT binary patch literal 6472 zcmb_gU2GiJb-uH+yR*NXC3lzqB8Pu+*QU7ov3{r@yRvCoq9`TRXx*T6ydCZi$+2f= zHg|R@Q#BGM23i^^V5*HEr7scCAXN$kF%l#&`qV@(1^PmE(d>Ajqz0NkxKFD}sf(fy zJ?GBO?vj?`w&)PNd+xpGo_p@O_uTW{^C%vV5coFCKYp_-O~^lE#rpy-!9DsZ5Vwd- zWbP7K;3y{{?Yrb#;3>~&{*r$oKm!taogXK%Uk=Q2{RF7sAd!XRK3C3h_lMA++#`nu z$(w#E$YJ=4$k7>oggog_PRcRleA7omz!{gjW_(ZL8zFK^7Mq;mERhqx$I-}YcP9M_ z&YIzzsA3pqMX6|}VL>%qR4PhAS1hdX=Z%eP@EfpnvtkvRda@tht#FUZK-?m)6Uxbi z`ecssQ(%MF{WAXy^f1cLD6j*o1)H@Xs|lf05EI8myWb!8*ZszItMmT6pb{L7}P zI|Rm+L2sR}K!(cdRmGEpa#&l^ff&F7s+K3_76RUPSA zKL3@fqBncQe11ivRz=qg)i9wO8ak|<&(ki@mx@?)W6^^}5(+1sXESSsyi%!9ZMj-e zE#OZ<-y`@Z&Ns6qqmnIVFUuG6U!>-nYN29f*=+fOX;c&|U(!~oQZ%#5s%li4jm^pm z1=X*c^sT&E(6YL=Z0+yJTD0()w!#`{uj*E|Z7kE6DR0maXv7M%zx5&%e?mTviSJ&r zBk^}H+I<6?m$s8N|A5_-+MM5dx#myV2gY{%sqJFTKV}ad*!;q_T=O5Wd;2#Rw)tQ9 z`{|G;vA_Z4eL*1L;Bk+>3az(DmKfYptKV}Y!O2rKW2WlH-?fHuiar>Wxz1Ldfw?oWtkMA@irN6QY3p%UME}!k(F3Pe%Ku|Iz@Ue}u>O{06_<&I@uBtQ!QYg-s34uGR6^CDiA_7io zfI}Gt)$td#LWSZT3%3iL@Up`z#Ui+ExvUz+Ou!M!%7$(#MTa-56~}L>s^J9KgiN}H zJ0;;qhfzo@-=5y0)6j&@WWlbIO=73}HeY^_?*H@L=A7N#e|zZW(48;Ux)0X7r|*sb zL-+Jn;DI=BXX?ADx_EF`Ja}*FhneqZKA5jPd*;J;YR_K!D3*F4_G}-&J$rNZ&TF;g zWIg%pJzq_Ht}Y(g6_3=!V_W`zii%s$Z_oW>YSNA+-oNnPh3#v9dc}^3?=QT!uwD5@ zZ1`cE^c-q*k(ju-;2v+Zk27ATW`Uwf)N-2j;p}2|C5DWKn~6LvK+>z92`42n)7#&V?H@H8@vckwg#@Z&fVg#1Y*Pp zF0~vn7nI|<;PGbN5IS5<_{^d2Y8`sKQTBbULm$e8uC^Sj%_NK7=t&YHSLVjZ5{u=? zArJ*LkjN;keTAIkN689zl3(F6iE0{_i-Dx5N|q{BOVYAJSJgwBA-UI`St{TE!MdtT z>f73?Dp3{gRh26D|LXo7I#1<`qppWGO4^X$ix@SE?$NAXu5xEhcGQ zxuGeNS(R2yT2d+|OakLUUeN@mib)Mcnpbp7osO(1H^3#Z86y}@wW8>Xq+rC-OgbZd zK`NT1`#&%=Q!-E)2motpL6uaiqDtO5Du85qCZg)FHcNp;6!fa4t;1OXIg%+YE?$N> zvJT6qAWmw9h?&Th`Rc1+o7c?3{lD%I*ECDD3>Nr_YDr+Xb@PT)tWwkr4A?da_9+!u zgod-3GtyPGl>sZUOn3exXo|x#kt5PM$z5Nz00wtYIG7g}#ZEcMfr|qIJF}glg9#K+ zgc;G@2?{G*XBq%++uk671ws{cS;rlw(C6-85w`3wo7anLt|Vqlce4$1y)ElZQ^VE{ zbc!si6%7SO?*D~e(ZB|5uUfO8ma2F+eWtgyIxroWvOO6L7{>uGx2@3%zpk2qPZa&M zIE9cvKEWt`!>{Y58Mt1fz=y}JQl)Tpmz1~j74t3C zu;^jna=Os?CZLuIyG0W2P&8v5#ybMs^N3j3%}%FKRs?*4 zR;=qXZYTayXd*}=bhKNaAMS^gtmC6+-#JtO}REMX^bvFW_ z>$3>Zjso8C+{i!WTBWbRpi%g@{vL`?AT~6HNhtdDKeEMC!ygDwG$Lg3=+5}j2H}pK zuur_Qb9^4iSGj3>`rOWQFMPP%5QXqdT!SZpXd@L5r0s#>?+kr=$nG7vcVahwbSHMq z?jNxG`t5-!d*~T^Wc=>gyE8k(M;dW5IMpD+VB}LGq#|3P#|a|#Zm-=9-#b<7dVY(? z5OeJI?49v%ezh)6?1~dLacawNi^=!D_TJa-ST%8CCp7Ue4P*b~aW9Fb9}zB){s`3O z;rG9+Sy<0Ex?c)&-x@hTOMb+iKk5JRc^=50o#3GLXD2zNXCp5K`JeMXX!&`7LpsO< z?eyUFl!vprrsORR50L_=sJ8`!p+{d<3U9gix&O26E>13h670k1jQhi5*cpZ(1R=+_ z|C&Ecj6fT|oQ{#;w(yMnAFZ=v6xMqf~^`Lt$mV$ax5pv@!7y6 z0v$M|`#-q_L5#=}A~p8qB1@o^`*~-kHOozy1>&Up*+;n@9E*> zzF8ldnSwc96SqlI#@Qa8~vZ^Zpf)Kc!mYRVMBp8S!b%v*AB2E%= zIF&r)ao{$Gf$ZXTBlhUNp8eU6YfciTTvw^ZvO@3@F)g*|q&!3CJ5nhuW#K?R1)-@E zM*s{t4@jJ7H`Mt|kfM*euR-*i{izNK+A@KsGC6%ui{dOt(r*A7@gQ48gS<^15VTrY z`)%{Gk)b9i-f&V+8V_$z_fh7IKB+qoxtukys!2EYD37maH;;ppWPI&)WkN0l8~f{wn511=zE$ZK=LY+qS| ztA~+$ly`GY_$YQ_?GDJ01z2j!i504pBH%*-7T$O*Y}LkBX@J&x6`*{F-A#kO0o)hi z-}+Z@V}Mi=Nl0~Z>h96a3l9>>?F+XTZ!YePov5Ww)>G#`JX%Y8gu#jDr;)~BB zRyuY2?9H<~(urE~WIc&e#TV-0+^#rR6X!qWf$7&`&rUK^PiF63t%-;0;)z}HL`^)^ z5J))nI6{U-ylKzYM$XkoUjEyj+TdJ$aA9|Fp*FZ!A6(n{;@Xz@t7z|oH<6$?|R%rLaFUn>%#D^F#NrN2jYaC9J0F)*!^R6a@0PMeHaZU zA`KD@M;Zx|8oGVv=9!(*Q?=ym=HdgPdwcr3{<<)=D@>uS7VD|W-PGjW*K4Vx_0*{k zmTQUGdg8_1#EZ4WdB{`r4c<9hA3A*Rc&+b9z3=31-^p6v>{jeo;@J1J4n3#rz9XpT zkkr=m-xGiu8P6D73-BDW#{i{v@Bk=HOxnp|R6qGVWa;d_;kNqF8^&a?!1UuL->t=db zhAMQ{O%uOBRTzap!TJaafbSglOEUg1WbBuu_hFFuqT8umuJ==)zzx9p;sze^#Mjrr z>f=;|6C2}Xc*H(1YWJUg7=MOK+u>M)hu=n!r288JQX$ei&}?=F z!hIYcY6KVsvVdD~=@99gZiHPrLJmlcs7uGl=y<~& Wi82R&BeM2?d&B3C`o1o(rT;g?2P}2~ literal 0 HcmV?d00001 diff --git a/libs/agent_framework/src/agent_framework/channels/__pycache__/transcription.cpython-313.pyc b/libs/agent_framework/src/agent_framework/channels/__pycache__/transcription.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e21bd77e9dba66204b7b9d2135ff40012d06f55b GIT binary patch literal 1445 zcmaJAO>Yxd@a?X@?IcSODoq7hAT2mSv7ky(rM5INrkDg1d9!U*gPzvA&tcvDu->i{ zVyeo$pj05yRzl=hi9_2%kCl4QA4p`RSWnOkr{0X*-aF49U|OlO+IjOm^XAQT$Ho!} zV9UE(ZAb_`=gbg*=OA?N0)B|zMk=C66;yFqxGGXn;k2|YQ3=k_a_DN9hCvpFFETIE zh#I{SRb!{Y_l8uId8F6jBvRuGLSIJXs-!07h2v=Wsbgw#3ROc@ktWobn#zbYxh|#0 z>#N|A^(ZB~KkfcTe8nUIp^oM5{^|#oq5BF^4A1om-Ox>s0$>g0}BEafRA3&Yctz;$X&@EPHfapf zFln6x;1>$W?SS$tFp27$EY=HABPNT(OqiCb2ZV(Ky=)Vfq@-r+262cR_`G9EAK3kj z;|3Wsb4|_TRq9oV5%`&kMg0K7@CCY$9c!J!0A}=c@Er&TOoi$W+4Sg_*fXq*ZI%6h zD>6Pc{v$JP!E_Sa&kSd|#^-dtw#81sNa4*}o=tE)fNjuSgW%V!=$lYH-$8!^P!s)? zK*{lK^Fj5y^1Vzm+n$(wu=VZMy*te-e$E_3;Xhg zmi+#KytFSbwd709d^>gMAa(x9k@L-5d-9D(>F?7!`PSq+&E@v=?Edt7_ut*V(@MUz z7rOX+7El*5qh2BD2%Y3~iX;9KjiZA_d$m!@S4zQi35!q?)T!IEO{Z8CW79J*W(kZd zbhmP%h-9?fhb`t3D zkw>#X%Anmp5-=%mo;xfjut@UhTNjCCYVbRsA<)9J||N+kYwyeB=5QgeG}ukR&R Jzlrt=`UeSGX5|0? literal 0 HcmV?d00001 diff --git a/libs/agent_framework/src/agent_framework/checkpoints/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/checkpoints/__pycache__/__init__.cpython-313.pyc index ee2e1319b7129aceba548c61abde7432d564b25b..aa50b8caaa0c8b94c35284c6707f1e3f4836546a 100644 GIT binary patch delta 100 zcmaFJwwj&$GcPX}0}xc^w{7IU#N^$jpPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&Hf-18+c delta 26 gcmZ3@{*aCPGcPX}0}#yB&)>*>iHXr+vIcWA0AR@n2><{9 diff --git a/libs/agent_framework/src/agent_framework/checkpoints/__pycache__/checkpoint_repository.cpython-313.pyc b/libs/agent_framework/src/agent_framework/checkpoints/__pycache__/checkpoint_repository.cpython-313.pyc index eb3a70244b5e843dd7e89d61f792731dd55994ca..069919d0f7f10aca48e3f2d5b733e11bb7162b51 100644 GIT binary patch delta 419 zcmX?bnQ`?MM&8f7yj%=GP?_JB^=c!pBD42&{oK3~{S-eDe8-M8=Do4I?)*GFACZ zmXDUzPtHh9&MwH$%qvkS$tX%qOo`7-u~jWrC@x7XD#^@Ck54N~EzVF#Eh@?{0*X(T zjSgbunp_ZVFnMY80wBvRX1eSX9-)4pPM;eBaW@1cZwRPA7W+%u~{5hfSkjeTrLc( zhlQ1#tyvG7vVlabS%D%)7?@p{H_wYb&d6xGIW1nDiLrZgU*cv)#wnYfk`9%)-G;avG9jH8zeL*1TGc%Jg-veQd z53EeQn%_7WcqH%e2=)7Q`h8$x6f}4sAbCST_6sK~FW(0~1_6Le1Y{p#W(2WWtby#q3|!9UtcSUjoQ+ry>#%`Dj95V; z=FHAkn>pi-Gcp=(z8J60#Mr+1XX0i?#tEC(CMz&A&fI)1&6-)MmXT59f{No81`y** Y9Wxsv+b1D5My=06JdA8bLO^!_0LSoeEdT%j 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 dbf746610bcfa92805b5c4699a9e27f2ace01e3e..0c863dc8fbab24672718c5231c5b272fc5209387 100644 GIT binary patch delta 101 zcmdlK{wJLKGcPX}0}xc^w{7HJ#ppdzKR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX#`s4Q07E<`Y5)KL delta 26 gcmewpzA2phGcPX}0}#yB&)>+sijmQM6Vo3}0CX@2LI3~& 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 06f2a479da732e6325f2726798116cfeb7c5c8f4..6d15035686f818eb81fd7a9f4f756cb1562f1ca5 100644 GIT binary patch delta 77 zcmX@Y_>7VJGcPX}0}xc^w@u_WHfz<-%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP ZNi2@f%}g&!Ov%?zOi#^&2~G?u0sz_c8-spa`a+41?wnfjZ3ndgWD0R03c&j0`b delta 27 hcmdmN_R^I5GcPX}0}#yB&)>-H$js=tc{=kPaR6{S2d4l4 diff --git a/libs/agent_framework/src/agent_framework/config/__pycache__/settings.cpython-313.pyc b/libs/agent_framework/src/agent_framework/config/__pycache__/settings.cpython-313.pyc index 6986b7334a5e77c39b1cf7f2a14dcaf4b2ea2c40..b5ac2ad5c3a73b2764dac7895819153ad272bfd4 100644 GIT binary patch delta 3859 zcmZ9O33yXg8isReN-J0>OQDW{x1>9z0a;2YTT7c#=mudY5Yjf3ls1t+H|%iPL2v;s zLRr)zLP6XxD(JW|IEu44FjQrt<1#Fx2#SN^>@(;8dYHM7JP&W~`g7&!Wy!U&k@chAI$GsG`%@oSu55CTsfiug z08&vgP*$XvD(;n8UsE;+*5T6j6?wtr+H{{+LxFEf+RUnjKaObI<_Tc-RCQDEgPlt(GHG>0Z;3 zDv(vuAifd0t4fv(HkC|7R!Bpzp-C_o4Rv=F+nWq?QXUqaB5fFKsx${|nzZ4t>C*CH zGhj1GAAu!iK?`Xl%nh4OqhNDj9vTgs3-i(#Y^EAkLj|x}IaUbs!6wjHaX;qC`%#BX zrJ~!1tr91iFT>*7p~(C)bDFYxnU$Eb1u`3VJ2U#krs)f50^TyhXo$*S8q7iExC3F> zBC5dHV%T7+G`&7cWL71zrSbsFkS(W)n6(1tph@Vs61Iw5I_{JXb<$)Eu9l@!U~8mJ zg{_q~4Ym%}m8Oej*UM!$AlpbYuc8;*=E+-N6C^WMD(>@P7PD}8|?skG9x&`FuC zGG(tIdzIS0@qZ3;(rWa0P1+hZ-SxWEwHSOu+B(>q($>S?lC}YMO4>%)FJKwJtQ8`S^0p@$%=|1Jf#~DjHr0EVih^ilu-=Zf`^&{-BbO;;x8%(9crZxVK>>t#E`hUXyMMq%& zhW&?*vXv+<3%mGK=qY!i_-xnq1jJQL+qb7m$Nt}1#8xzL($l;(;jz-6k=|bVv(n?_ z0`c^mT=EWC@w}|)AS*i3aekzt=bcD&#g#xW@F_*qNluE$Nu8y?C_NE=iC&WRUEqW1 zW${+YKLtdWu1HlnAyWK8y!}U-80*Gk;|+S6T?xf zMqytxcAmE(718cL$(_#1Nt2EGgf+&sgnT8( z$n11o8D{k8d_pORyx+Nt(v$yy%Cgch@j-k|!x{OJTZz=Jqd5q58=-VWnXGuVyHiot zN0c7+cFKNZVDj9QtoCg?jU`{LKSU!$r)X?rFi;n4>t7f-nLIm2ITh*A%ctm5#Bf!R zRPVyDU!CU7 zr-mCgswY{V5lq-?h>HxF5A+lZsY6ij2#Svv6Hcjv76Dv*u&V%*vDvQ9AG@bIK(*2Xki>N+^IFGuk+;_ zj5ir?F-|kyX1v3A*SMIPueb8$2aFFHA2BX4qKuCjpD;dUe8%{KaglME@g?Ic##P4G zjBAYRjBgmjSdJ>v(9NAQ-oj3#+J;>FbbH6E{~k-s{u`9dBK{V2w`-V)tl zZwzSmT6?*x)Kf*ldS8tevd{BVNb}SL1DZGFY4q2Tw>D_^)`=el85*b3Jc{2)N#A0- z(ZMouta8?RS5w|u+pu$YJI-4RFJ$yPYfWylHCy*&pSSjl97|7X-}8o5xg+yNj3qXu z*>=+s6Wjhqyd`_FVw}!tO>4EP-^E*slnT*EZO%BCJ^EbVF|F3}&rOY5jo13`YZs#! zGjhl0@c}4C5wHqG@2vA_o{&$|{DHa<#fgYd7wRCe+H$F5x2?m^T9ZV*5zX~x@o+T$ sf7L%}6+faeSQ~EejiOFQtv#npO^n#p<`v&taB*XNoN>Tzv+~ma1p>O5>Hq)$ delta 3429 zcmZ9Pd013c7{=$q2nd2(mgPFYFoMhAGA@AIsGy>_jGD_RvWbW=`Z0q0xMwbstb#gIqDhaXzWASgzBTxR4NS&m1dGPG-P&U@nlg; zHbLh*)M>WM6snqwn+Nu!0K(HmI@AGO3~ zr9t~pD|ZcbL49FPa$wPZVy$8Q#oEAJVr^jq#M;3I!Ujs3|Zf^~brX(scQt(?kcrri%@PJ^4kcL4(w?Gi2GBXw0G) zvFvQ=4@Q3uY%UE^{dv-V3E6xaivG(mCk<15Ux;e~)Ix5o${5z5fJJ76vSr0ofR^LI&g*2CS59lp$LsqjE87 zHEa!y#*AyFpJ(W=lWYt!UohUj)=QXgC~lB!tRdTo>@_ODBfSasIu)v|-Yi?a1(}mP zxSXwG<6v*Vw$XUiFMZPYxwa#;5E+&!ldQ;)?U2lC$aW&zMH6thyJ35%7!TZDn3GDd z^gh^rnuz9`a&D3vZ)$$1gC?W;7R*9Z3=6$2*;GSz0NFb<4O6}gbJBFo@t)X|$NQkz z44ivkY$lt}^?~RtoIE5p8}^~t9N1ylFq(_|I|BQN=3)7xuw(QR>|@w*nh!exJ4r9Y zPQgB*1u);IPzNo<5}(07r$y=&`a)jOFQu^er_~tu9qb0Jf!&1N zqP2#X>^3q7t;1Y*l<6HqYsIOLk-Iqa6K%xUd$6DBHLUWBjN0V3>T^P^VHVo*bWVLw zXdV0|@drAOXdA}=3Hysm)i(Yu+xQrng|VKinmVKigd8S#wfj24WxjCPC!MxsK6In(1AOC8xe zGrBOkF_IZ6jP8scjGl~C^=V+DUW_zGA4XqBKSqCsi!p#PkTHlcm@$Mgj4_-sf|1S` z$;e=2GO`%ij2y-&#%M;K$&_oNd_Ek@C}4OP;~3)^MGP;am{G!*$e6^K%$UlU#+c5S z$(Y5M&6vZOs~?VT-ES!$E@SA7<%|`Km5gL1GrSpg^?Z&_FY!>mem5pvYoVvw7WjX+ z)d~u{7+b7IH~ZRp*4*%Zh^ecVrj?r;ZnBlfbvzx}>8!c;HCy9ybM4hpo6KwC&g%8- z>jEB|^n>=EZFm`a%=m}bs*;=IO)tvvdh-f%izq-dnfU68_}`xyrki0k7bcXOYpK4T z7@rZ#rz=AKYyWSmkfZ`n_JpxH9jLN?JibZwA%W_u=1=|2goFFVL3%**C^IkpFXG}9 AMF0Q* diff --git a/libs/agent_framework/src/agent_framework/gateways/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/gateways/__pycache__/__init__.cpython-313.pyc index f0a3330139ce8795157c1b583357936b308b117f..296f332087a9bdfcd8f357ba086b040d60b209b0 100644 GIT binary patch delta 77 zcmbQwbcl)jGcPX}0}xc^w@u`3GHch*%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP ZNi2@f%}g&!Ov%?zOi#^&2~J#44*=LL8~6YK delta 42 wcmX@aG@pt4GcPX}0}#yB&!5QMB%Gq3n^&Trl30?cpO{u2U!Gr-J@Ifo00JNm0RR91 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 7a436a54248734b0001397df9a228d57373b0d28..1d1e2cc130d2cbd009109d3b8ec218001e65b26f 100644 GIT binary patch delta 80 zcmew;IYo;5GcPX}0}xc^w{7G;!Du#7KR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm cuOzWJJ~uPHC^02pKQTQu4<@+z86!700814dyZ`_I delta 45 zcmbOt^-+@hGcPX}0}#yB&)>*>f>Ah6KR2&LKP9mwQ9m)QJia`?D0?#}6E`;iIS~!U 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 794591bc4e47a68509bbd24506c27cd16539ffa9..eb6b6aeb2af959ca06d090ed8ba17913349ca7fe 100644 GIT binary patch delta 100 zcmZ3?{g#{iGcPX}0}xc^w{7J9$l~3ppPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&^CK$ delta 26 gcmaFMy_lQ(GcPX}0}#y9&)>-Xk%iHIvODWC0Av;idjJ3c 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 16295820759eae5ba95a1a210a81c8870eaf7cac..b7c49337f4a5f208e859af570b0db32d48c4d990 100644 GIT binary patch delta 101 zcmZ3=^`49SGcPX}0}xc@w{7I+W%6#-&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjY0nRu81!viB- delta 27 hcmaFQwUmqdGcPX}0}#y9&)>++%fx8CIhl!v831E(1~mWx 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 aa5b2b8ba588d2e11465954a17df9b9b0ffbca5e..77be6a8dd5039a4bb84ee2e8212de7671f3fd9cd 100644 GIT binary patch delta 1453 zcmZXUO>7%Q6vt;BukEqD{)oR4r*YiIN$NC>(}uLAEmhs%l%%B&cBZPRD$6*V)WP0O z#zrMHiYp;1PLhJjpeUc5XHIZh5h?%*_qG)^6q2>b%vi)J&sYZB?4} zbzWUHbJca-cvbvQ)_Aq4KQQ@+6|+{)?cH?rsXix+?;}KcIi*l_*Sz{C!U<4RsUSLQv%zTjhB_m9! zD6l7r@8uW^Rys;K4sS|1!8G6i3jhZtldKQ&5OV^LNe(j=a!PW9^+Qfe9%o_5Cs+hH ziYzD@lFi)uQ-PcPI@Z(X&HFmnjhbGn)*HRRyxH7r)T`(g^ZeouF5lID#*aIiUn4k#Y@#iCR)X8qv*UfHs^c1dl+r@XQEowl#I zw;-}K>e6JMRaeRQ^5WbBFAUL4sY}8wA{tz9< za%}Ips+*g-v6}VpQB<|nhMzy*!R&^A19Ey3%>$d(>qfP~aXEir%|u4k#}Ie-?nFN8 zgY*6te|icR9j%CCk|)5XtdpO`LJEPK_?GoNF{wU<_-yZ|#6?B3u&M&G4sKcD!HiEX za$(uBt`5fUNdE#I&&Qw1D}YbDd1E`hlfGpdde(I`UbcOT9ii846d%A{=)L#qIK%Rq z_03?p^aNs$7Cx@&o9()3aC!bDUY|wC2m1Q4al9vvhvykY0)ao!p67DYT>Yq_U*XTK ka?WHZn{2Xalcr5u6WeZ#ZLPFw1yQg^y`msqk}(AoY1M^IS+mLHabIbpeAg;+eqf=pvt zP9IjMXqp(&i{B`W_%gzGJv;of@`=CmPB;vefA=PMr|&7%`D@>zG66Z22nf&mGxa3^ z10z|ey+saOx+EWv|K$h9L?-2zw>^5JEF>Ty6D8OP3OBNcDC)f%LP7Sn*@x^$UKasm z74lo5ln9~;5k+s*XN86)Oq5U~CL+i>p6U@%^@ouMprla}rv}js5q-c)9JL|?R`-ad8&@)Ei{LMyVSh`IBhQTE^SFG z18*q{`MGM@EEXydeWVRbHHem)@3nQu6?}X1DvF9y0@-pc7b{is8hSj|#PlsWzq(o| z%^Mywg;uIm^NR&@4cT2NRqfM@=seJAu~^D4o7mi}@E3YYx(!%se$?+cVczN3!z0+J z-J%1@o&b{!mpO)kBnoyiSGX3>NE?8S=Gpip4Qygm0x=xsCcoR2p0FFq7{U?po zIs;e8_MIzTpEcz6Bo8nF2R0jaD&Ohq%-X>^di=HQ`kI3GpRr5-PSevaNGEdiK3_{D yqxQ4?dmIxdH#hjJL=Sz!KO}OANh-spa`a+41?wnfjZvSUPwB|1l)k delta 27 hcmdm^^huHXGcPX}0}#y9&)>)$$HM5mc?(Mi4*+kG2eAME 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 c0b1288dbb918c1ca650e3b1e4978317de1f1d09..101812dba3003f19cc37be56c4f4e847289e9d89 100644 GIT binary patch delta 6797 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 mY}EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXXb%7 delta 27 hcmexfySA45GcPX}0}#y9&)>*BgM-my^E(bsGXR5A2#Npz 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 e3f5b3b2561dc5bf869ed54ad28b7fa53aadbdee..924a7ed5600aba9a5427fc3d84f20ceb93a8a238 100644 GIT binary patch delta 103 zcmeC3&3Jt_Bll-sUM>b8sLXHM$o-SWdy;-`UWtB+zHhK+d_YltR%&udv3^=+QE^Fp ua(-S(VsU(KW_nR#O1^$#dTJg_5Xwm_O3Y0y&o9c3&rib8n5Un=k^3hLqsL}{)(#HfGBcF>GcPX}0}xc^w{7Hp%=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&-Xn3>Ujvn5M{8US?G2gm>b 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 35ae6178f58fd0ffe1a736522a8023a81ac24328..06ba04d21d10e30332af657583aa1564b5d61a4b 100644 GIT binary patch delta 100 zcmcb@GLMz}GcPX}0}xc^w{7IkXY}sT&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjBf8E*mru^%L& delta 26 gcmbQodWD7iGcPX}0}#y9&)>+M&&cRB`6%N}09^nFdjJ3c 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 a1aafa91a92c4f75fb8afa806a6d6f53c7a60d28..baa7d7b397ccb1b018c7a1f808652251ad6d3759 100644 GIT binary patch delta 101 zcmeC?xyr-+nU|M~0SGGd+ct8SGkf>x=jN5@r|A0zd&UP8@j$2VVdH diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/rail_result.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/rail_result.cpython-313.pyc index db02d0e48609cf24243e5fcba3ff9807ac6202bc..d8b61160e23548c326ba4166c0b260eab8b3272b 100644 GIT binary patch delta 101 zcmdnQ{)e6WGcPX}0}xc^w{7H3X7cXQ&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjaanVcB`>Q^LK delta 27 hcmeyvzKNatGcPX}0}#y9&)>+M%*5!lc_))IBLHf12QdHu diff --git a/libs/agent_framework/src/agent_framework/guardrails/__pycache__/rails.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/__pycache__/rails.cpython-313.pyc index bdfffe024abe26cfd47ffc36a02674a44ae865fc..d1871ca841d5a5b903039c0675770854eb482165 100644 GIT binary patch delta 2283 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 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 460b8117b6a1a9fcabfcb71daef5fe2854ed387b..2b205257f527c99b7a80812c4cdb2c64d2877faa 100644 GIT binary patch delta 183 zcmaDawn&`sGcPX}0}xc@w`G0gn#i}6@xsI-aSHKiMTxno<@rU~dg-N!MJYvznK{LJ z$%#3cNkxezsVSQ+84cLvkyPd6b1

PyP(vve1GxPLva&qI-5|c~viz@Y!i&7IyQsd#0 RnEwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX*BhmFy5^Cz~|OaN)~2lM~{ 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 a2222fe953b9bfc09d8f40cb49dacfb44ecf99fc..c0a98cd23ff5665dda1d1bf076fdc49cb108a9e0 100644 GIT binary patch delta 5377 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 KScAMg|NjBO!{t2y delta 4111 zcmZ`+3vipo5x&#omt;LGSr5mOt%o16Wyi7|KN353j1xkfI5xz;{y0Gs2gOp1(^$%! z90Q#u4&hN~OBr&6$xLS&r%;m62M6UP2 zw`=@_c!{XsXYBd>=k`2}MeeKkf9?5twM19J{8Hi3B*u-vT|DAa7BY%Eirh;p}TBOFFYE{SJLlK#GQ7k zH-T;?A@uUQD*m9WMoGh;O}yy3n{EyNh7d`$a{^H`w>(Tp_*XzHdX2c9Yn!ADMdI& z8qCH4&fFk#0U>t}HBIpQx?8 zN}C=7+w7=^?dOtmU z;B)pIuV3z`_wwz_x8ywm5~q}GAI?ed@}=bi!YS;(zytN0@_quOU(ayyq!Mgn$N7)y zo%C^jqQ1287|M;Kgf?Y;&OkU88H#{gBp515nn%NXus;-!?T9iKXY7f?4N>(QFjg?J zyJ0sqJfS6|-`a2MxA!~v#YPvn*_Vy`+wI~S$=*Okjg#!w?pDQ=A{n;2$+dstTFELo z8Wf^7Ev1r(m8@5Ej`PW;_lj&mTLmnHEutW#`v4(9n`n~%jJ&q3VoWB@q9ve`oqA4G5xoW!JEBy?cRl`f-CdY&6@3n znUyo&m_agRv_+PH#S6M4Fgty0Md@R6FFv;Qw0k^#Tpm2G)Lsj`3!04~AFhi{GKLI% zhfq)}AT9b@S|Ipl^%sjJ^0kzHL;oehzixFcr(@{oyv7Aq43))udehWm}Ct+c!bqIVLs))G;%fk`c^) zC3EJ6yd-EHfHWsIN@lT14I=O~Rsg*+O*hx8hpmguYC*HI&n%-SW?3Y&3S`>8O(-vD z-MJ2SS(PzGg4`Q)1g&Cgv&u^(Wib)kL{mt^15JfZK}SZrWRdbvEL5GDm>m;W2ee{) zvjV1rWkDT|f{!nrTW{Bp~eIuhtaT`LFL`r$PC5a{^Hag8LvQ zM%ZtG!F~?_;rhG`?$yB}US* z`4sP8vyI02g+7qp)bASS5ng)n^EQw-3tfnR4ltC_SI(C( z0JjZUZz0dH+n}FN0(iX#d0<1!x`)8XL=7-L`+yuIb3|pyyHr+lRCgiYf71VC^{MJf z;jCh&a_!k|Z|2{4MNRDPhc+b3YCcbBVa{D;jr5ngM#}v+^c4LI80=kyg9vv5KrJ)6 zZ%-o5?&9Ze=+M81{O=(sxNZG*;e8}O;J2+mWBxai|3P>P;Yq%(bFy5%7`ZPGf=pCkSM#KARRMKKk7iwuIC20BTBMMw6r zSW?v!k42%VcpI2kO_8C2kq}gy%e)=2JGRRXoGPLIfeREPTt)Z-z@MM09FHRd-wFFG z!s7_%`G=c)V@Xvkdiw|qAqPVo+lf$ta1R2yGy4ky^kBz0g(6uXG<019cKN*)@HMv}U80R#t!n@L)%!{L#ETceR3SrOBL zhgj^FjT)b6%1|_CCT8DsZpB+>&#bL*)>c33C_K9DXxCKv#wlCZyawby2Kjy*UqobTi>^|nt4qKg`C6bw1S#{{95R|lI`3?kzS zGGw@#z%u7Wb5Gl5m2xV-1aMlFvpG)#*A4YR+S#uXel}=Rz~_yiXQ_OJI@lR_PA$rO ziBN}-y<#1ANzNs*C^9qZ(0RZIc(>$^$b)#X-xvgmG&g#!&NMfU+_WN~(w1boi)Zok zk}E&EkTw;rWHXO&y2Vxe2rARVW>TJsYQY@zAC{Bi^3_{hx8T)g7(mHe%2^~PzeRaM zR#JYI*%OhSURX5eE7U2U9URE%Er;ksytS`dIFIaeJl^M~$M}!?R+Zj|jE519BgiiV z%lwqbqnk0#Kk8eOV*?WYNurDAZoR8cONDudgPP}7k^vH2 v;CHm({6q)T`~k{e-gEwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX+skB!lLvk3cBVE}b42m=5B diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/input_size.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/__pycache__/input_size.cpython-313.pyc index 49b182aa5f0b85dd018c7f858f32625d53de1694..0504ddbb7c796226003a2e8f343a8570a271bb2c 100644 GIT binary patch delta 101 zcmZ1={YskqGcPX}0}xc@w{7HJ&Eh>xKR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX&hnB2013M#r~m)} delta 27 hcmaDQy+E4#GcPX}0}#y9&)>+snuXD4Gb8Iu4ghQe2Y~

Zmi*FR)|k4O3Y0y&o9c>OD|0=%^#U7SiGm}=jN5@r|A0zd&UP8cSR7xHnX8vxnpl)ll$e=Q YJb5*<1unVG%q$fwjJ}(XaVW9@09GCzwEzGB 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 fed7d53664d12c093b8511ca77cad1bd1a2eccd5..345834be6ee88a2598e8a3e44b09de30e64235c4 100644 GIT binary patch literal 7349 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 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 f79860cb6e39f286fbbe389d6f51d3d9b718ad21..079c6c3ca2fa6937ca88ecddae656b0b5ef1ac30 100644 GIT binary patch delta 101 zcmezFa?q9gGcPX}0}xc@w{7G$WcHq_pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&5GcPX}0}#y9&)>*x$js=yxt-Zc9sqQ{2XX)a 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 bc6a8e1e27fd33a322644aac8087e7288a626f8f..918515cdfd9823136395f60a06e28fdd5cea69f4 100644 GIT binary patch delta 3436 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 QHp(r(C%K<`MWuZI01bzOJpcdz 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 e1abd2c68a7219d278eb280e0710b3927f43dd28..2a985320aa77c9ba234d841236325e1330a87e65 100644 GIT binary patch delta 101 zcmdm(^gD_BGcPX}0}xc@w{7H>7Vw^;pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&)`Ex_otxln*h5de7A2VejI diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/contestation_validation.py b/libs/agent_framework/src/agent_framework/guardrails/calibrated/contestation_validation.py index dc3d302..58bdc74 100644 --- a/libs/agent_framework/src/agent_framework/guardrails/calibrated/contestation_validation.py +++ b/libs/agent_framework/src/agent_framework/guardrails/calibrated/contestation_validation.py @@ -129,6 +129,8 @@ def _is_vas_section_name(section_name: str) -> bool: or "servicos de valor adicionado" in normalized or "servicos valor adicionado" in normalized or "sva detalhe total" in normalized + or "servicos contratados de parceiros" in normalized + or "servico contratado de parceiro" in normalized ) @@ -185,13 +187,23 @@ def _extract_contestation_invoice_items( "validatedAmount", ) if candidate_name and candidate_amount is not None and candidate_amount > 0: + payload_type = str(payload.get("type") or payload.get("tipo") or "").strip() + payload_desc = str(payload.get("desc") or "").strip() + classe = str(payload.get("classe", "")).strip().lower() + is_vas = ( + _is_vas_section_name(section_name) + or _is_vas_section_name(payload_type) + or classe in {"avulso", "estrategico"} + ) found.append( { "name": candidate_name, "amount": _money(candidate_amount), - "is_vas": _is_vas_section_name(section_name), + "is_vas": is_vas, "section": section_name, - "classe": str(payload.get("classe", "")).strip().lower(), + "source_type": payload_type, + "source_desc": payload_desc, + "classe": classe, "estrategico": bool(payload.get("estrategico")), "verb": str(payload.get("verb", "")).strip().lower(), } @@ -397,14 +409,25 @@ def validate_contestation_items( "vas_estrategico": False, "status": "em_validacao", } - matched_candidate = next( - ( - candidate - for candidate in candidates - if _is_same_plan_name(candidate.get("name", ""), item_name) - ), - None, + matching_candidates = [ + candidate + for candidate in candidates + if _is_same_plan_name(candidate.get("name", ""), item_name) + ] + # A mesma cobrança pode aparecer em múltiplas visões da fatura. + # Prefira a evidência que traz classificação explícita de VAS em vez + # de aceitar a primeira ocorrência genérica e concluir incorretamente + # que o item está fora da seção VAS. + matching_candidates.sort( + key=lambda candidate: ( + 0 if ( + str(candidate.get("classe", "")).strip().lower() in {"avulso", "estrategico"} + or bool(candidate.get("is_vas")) + ) else 1, + 0 if _normalize_match_text(candidate.get("name", "")) == _normalize_match_text(item_name) else 1, + ) ) + matched_candidate = matching_candidates[0] if matching_candidates else None if matched_candidate is None: _record_failure( item_log, @@ -414,6 +437,9 @@ def validate_contestation_items( continue item_log["item_na_fatura"] = True item_log["item_confirmado"] = True + item_log["item_fatura_resolvido"] = str(matched_candidate.get("name", "") or "") + item_log["secao_fatura"] = str(matched_candidate.get("section", "") or "") + item_log["tipo_fatura"] = str(matched_candidate.get("source_type", "") or "") classe = str(matched_candidate.get("classe", "")).strip().lower() is_strategic = ( 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 0884551846b7b10124c9e298526eb319a404ceaf..7c5d9de6c8c3dd619b78d3812e65300e93770dc1 100644 GIT binary patch delta 100 zcmbQw{F0gbGcPX}0}xc@w{7I+XY`(=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&++&&U`wIhC;m09!Z)i2wiq diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/_context.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/_context.cpython-313.pyc index 7a1b44700a2f59e32e54aca2b720115e1940ef1f..96983540fb82ffa17d8568ec8ed2e5d3cdbb9191 100644 GIT binary patch delta 2065 zcmaJ>U2Gdg5Z*gGc6^Q#J8{x9Y173`DjTJCD-;5zKe9>+`8VFU6b0#ewb$+?_FdS! zOWUZ(m5`_qhzho?`cNSrK!O(p;t?SsBtR+>3KXHpLVW=729l%xh(~76PSU=xmUriN zXJ%*T`)2sq)hBEBLLmjgSTo;TdMAv~pW#?WBh&LX!o^^Ij4p9Z7iz zJ^CY25^`P1Oo8*xq_lHNdP!I7ELaXF`kX<}7hnG_by93%MvWq6`kJQjALLXG6BC;j zwjE}`Qlz+~RWwWun`zawLM~c1t z*yb`du&{QDy4N;Yf@eH^{IuuC>07C)VW*0zSu&|+nYly@wv{UB%(B&jY1o>jR`s%Y zR|?W$Y;CqaN{}&n-ek+FS`1Ru8+>AOSuUDDLjxK19dSB|6)&50@L0tDc?rCL>d#Z!Pw%Y(VlP5?E>?dQWUq@ z2<5%}^Ny%O+VcKRM0|^bJQ~5u>p9WzJ{?^Zk ze;?I+zjnv&1Y>-(cP#$)@r{ni)tR?uZXUk5aP#Dcv5#K)VVj=HK*2BcDoa1l$x_?FC8vZtrR$554JG*^u*c91g`OfU)D<+Vz3V#`(VfR8pYLhG0r~>VB7h7i<@|dZ@(`Ritp)@_-KJtNlZfBOtvDf9nO9 zE~EQN{&D}XG|q4L@0aHIKmFsiV{pI*VM?^KLqhh7$z|J7Aqig8y=S3)vmI3*OT+eB zu&5VodU-$(N{L1o^$u=C z_H4F!y5-BAo1G}S_m{odJ3TM0qwsxSNE&Y(Ktr*O;rM1?pR{Kq6mEE6ZTL|CV8bt@ ub~tW`vxb6vfd@e$O-X1ZabOe9(;K0FVUY$4&=Wgg;R`$ji!|$m!2Sci*hFIh delta 3146 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 literal 0 HcmV?d00001 diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/dlex_in.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/dlex_in.cpython-313.pyc index 2bd01ff011862ffcf82781298f364b1ca7d1667f..c9e4fd7070a50828fd365654deaf8cf927e19501 100644 GIT binary patch delta 100 zcmcb|xq^%PGcPX}0}xc@w{7J9%j`W{KR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm ruOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX;PpWVs3e?r|jT delta 26 gcmZ3%b&r$#GcPX}0}#y9&)>-XmzgneaxlwP0ApDP#Q*>R diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/dlex_out.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/dlex_out.cpython-313.pyc index 11dd10de63877a4d8a4f93f0ed2eaab9367c13f0..b358a98a4e032467f0bff9fba79de46c2081f8c2 100644 GIT binary patch delta 101 zcmey%eVm8;GcPX}0}xc@w{7Hp&*D8tKR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX-Xo`o@JvnwkTBLHwD2Rr}( diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/fallback.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/fallback.cpython-313.pyc index 113239377692eee6d27d663fdc1c6540d3e5ede9..c94d019855df50d29f37adf97ead14e14d450c1c 100644 GIT binary patch delta 4023 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 literal 0 HcmV?d00001 diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/out_of_scope.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/out_of_scope.cpython-313.pyc index 905ecd1068fccf08eda78bcf2f1d9641811c0938..d5528f05cf3600a2b9e599af01b6187685486074 100644 GIT binary patch delta 533 zcmYjPO=uHA6wbtjhQU;@Xe|`_*!Ch+mO?<;+Ml!rw9r}%cny!;w_)qL8X ztv;AsFXyiZ&4sCL%yb+INJM~1N|`1Yd|sNdNJol2(qfVCcL^k^4#gV5Tw`Ia-!8Hy4Y&@(je>JoB|C-v$?{WC$>Z|F?BKMf{Mvu}?BH*q$TfJ#M zteub3zpZ~VAL~D^ozT4QTH({&!cn1zJvG4Ht5eINFNyH(A zR+W}r@*+$WEf$H(#)@FXTKS*$0YPGp0zv{(8YM(RB3LI#1)^iO6qcYLNwlRwS87~_ zu}g|ZJ}52YtZl{QF}nPizb)M^4;@WCJ)8)Hb+@Ng*^U8VcRgn_ WTz}A?a+vdrm)QItC$dLbe1m_oVYC(i delta 933 zcmb7D&ui0A9B)RdTUf`yA17g7vK=PO&R)dUbvEldT-ln^)*bZFz9cX8%_OhBBy%b< zK}2>DN<4WG1O+eRVSj=r@gVyb`~#$*BI3nwIvMrHnC9|czRCOi`hMTL2h#IxY3x%f zr6llqI?LCq#qL-kNs>|`(XCF^i@d{##bJXAg9OY4i$aUEsTVYDL0o#1i|grjNQ5N_ zbNsYNU7qd;?sft{&AFd8LgrXa+%@;AEv5S~bKK!3abWsJNI_7)Ls>wS?(W3&X`n80 z-3Fv=t*opT9fnjbxP}BKx2Odc0f!mg-ld`Mg`J#KK7Z9A26faNsLPdRy{K19>I|rY z5}$ila6zXdlG?rJRN7-kUL-4I| zgP|y&8-fB0P``=WII|eEL0p3iJ^-1`y+64Rsb6k1^`)P(caj%|qyxT1^4zzr{bPT3 zYI4tJ!X+l*V20u!EaQoQc_He@wxVL&2{(CcT)nF(rA_K~91iFDMuJd8r}Eq65Dhl| z@LR6jrhP3G$a;uLS=dob1nDg9GLPX(!6ryR`kBAZf6n|jOSGFmF}~M>0jO8=Zx71T zzxeS;_!5U+i86)B@iU52iwDI+f#tehiCz?-`lpIn^_Py#C@?r`b2aVCoBKK}mY`H` zXf;^UYZ@%-_=a<-&qrsq327~QqPfyYG`ujC8aXQU?hM=VsN74~QFdYLSW=R|j3%VX MuX0AH}u5>Qkw5l6UK+&I85K!QKOqKX3`G47JGyu&BYywQ9!^NrtB_q9y@w@5?| z;W^K4j4yAVtj~mZFPrTDQZ5jGMkjDE*Xv&y$YnsMLZ{HKwC_qPdy>k|y`ZL5=m3)z z{TauwSOQcfa2WPD)f|J_ZIH1YDu4kehAEe*ZV*r}M2Ts#GgOZzAZn5kY6c&i62a`~ zC3PQ$t7w(cRDp7WwnYraVZ>w_!!p2O6Vw*+;p{-Bv#$UpymMS`Gl&r|iQ`Y(8WQRA zv~i$dQ+v#{Kx4LWEknn6%u?b^cl{^+V+JOMGg+N0Ms0(FUjbGQ!W~YWIZ81<49nG- z3m-4v1&tey|BM?zjr zR+egK*M~x~*I(P>iQ3l2Y9PcG2BcJ`Yrobt{eO{;R~|%;)X1C)><{-!@qVp2Cn?_f zhUE6DGo1j73LMq^cyN2{F@i;T?;Bhx?Hy_CiY&zj{;9^}@&a`Srd-i<15^HJx{CN| zZGdmq-9&t`zKnQ%!$m~4aS$=SDe%{CeuOxa_K-?mIoG_&E&JanF9PR zL;7C{ls`rvZ}UF1ZaI1{W!X+jPxTaX!+FkvA4{Z04KAGFU_FT#wu~YtI!lovwHKWW z#waHiJ;V6KFw=~b_p^0WYVx!l(a1o!PWrrND7>=fb7;uBv!mR&N~)QKkks;hc`+>2 I@ZdrC4OWe582|tP delta 2469 zcmb7GT}T{P6m~b;SR|Sn{}QA1u%+FkD3VZG5F}V)XtYrqLzA$D_BwNCy=G?a^xm0O zW5tp}9|C=l>0>DL51T*;t<8(jmuw$Oq0na^`(B7GrEjI*on2*J2{QYnbMHOhcfRwT zbMGf(-@M)ScWY})6MkO|%Z09&*W1Rji<$LzcH-=j-!fa9zaLr1T(zV}6SLD(BQ1pA z%1WNOu3Y4HeuP35@nMI#nh#RmWpmuc$NcnUemFmKd1@k$uZlA*ee?MoIf`kXUtQf? zeQqt2T_1@5J37%}Hqx0|%+Vy+X0iFN=A2pBWXIpiby+UcS~%jvh!faIGE4Dh$8xeK z9_k!=^}v?t$wBhC#%7!{%q{7M+@ELhN@tXvo{V=oFLl?Qs&2t{EM4rn-j-xTqf|{K z{%d@U(piV@;S#S|%CLNSO_ncc>}dKthT1xk8B zm|u+_b>I0QCDZ~F?i{Lpi!P2$ktg@%ECX&(H833EhDvIHobS2&eoBx)^T?J%AuAE$ zCvthLnwgeB*OuZ?yp|p?e(G7fo)ROeQYgyIK=7r6FSyGCB8{H>D6Jmo!3U3x=CRJHGxJNhi`4 z^YNhpSNIFu3I*DCHEut3x0n)We*>WO!Y{d%2RdQCEF)rylP?$P2IAj4^;KFi8`$ou zL>{^*Qp{#%SWv)ifz%))aVp+-Un&9nt6cEs{busAOzRRm1J_l%_JB+YOXFb zx%Z5M%j6kT>0JEgi)tuMk*xT=_TDwf*(jQUV6dz$l7=;|yNaqwAF7Paj8DN9=2b%F z%9k#bA518EOx?2OqK}KsFb??=3dC$-VTdtzq@|Hr?eQWGf4z(^1@2z^S`myyAYyY% zXmh!qsl9H_g6I9Fv)S#O!QO68hV4?Qvv^|>ZBNC;0VmTMKN-lk&Ssl4Puq*xW4WhI c#dv36t>gJj?w=D)nV0@OI-kwtlzEu_4}9HN-v9sr diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/ragsec.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/ragsec.cpython-313.pyc index 4911908597dfc652ea89a677b974b2905dd27f17..25710434efe567d62cf34b437559cc8fcd082d01 100644 GIT binary patch delta 100 zcmbQv@sNZ2GcPX}0}xc@w{7I+W%iz>pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&++%gh)sIhpw%09ynG`v3p{ diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/revprec.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/__pycache__/revprec.cpython-313.pyc index 4554b516ff966ca165630c23a12b353c95f6f321..126e47fec2e34b771117b4d4d6daa6a3301ce29a 100644 GIT binary patch literal 5422 zcma)A&u<&Y6<$iVoNkgLK!YCI%YaQ=Q=mx64ct_YYcLY+(vd`lq+I7va7Vi%dgLXC zp4nv-7X=a&Nbmh|X@R0f4{i$Nlpcy)`CsT%w5Q%w7)7uB-kT*Q+i76}mY2)fH}A*y zzW2>OdG*yWz~`a)pm-%PeUzDDdaq*j=7ucXz>Mgxny1itVM9{m~Tj?!- zBRINnRI=O#P$O|={mRv~^|#j6uhv9EOqF%BKf(%ZSZ%Dhd}aOn zBGu!2(pA|4o*NmFDDeX^ks~^hQW7=I+#l+Y!He;9BobOe!r9P&|X;*25 zI+mFnajXV0I>W(g@>^lSrZC<=aRpDNQY7?j`&}W!G8W`%CXv9g5uFBH*=`FY2x;s! z_xjCpP24mZkGWV{tdoMwYAcbuwokeo8Y=}1P0Sd%*xzl4iL%3doJnz@$FoOP!v!g3 zU!<8HNpUF2g++Dbp|-e7<;h2(uMh`gL>*Q$?1f!ncq&sAp)Qb$Ou4Mc&(Z9WkbEmv z`He8_U=7(q&5bzB$FVkJ$$7=TxHU0OXL^cwr6^3KYB>9hT%$xWj@;~XVGXu@kjpV# zHDSB^-hQ*!?;<_jvsh8Be)Dd>T@&y5g$tW=m)LP-6Pcipl=~^3K`=Q&&WuSBaGEk+ zm5AhIl72Wac{a(j0XgC#07^3g9a84lJ12H_cITemL--LH8jvBZM;Wu+j!k%Zq9+Py zRkg{7Ra9*%Q3qs>Qm>>XHtW#TPHRF_x z1dxV`;|USD`+DMCz23LEifW>rBil#FC3=p^bOwg_o*E)ShWxLF3jkmd)sSI8$)?m4 zm7zkaREfRW&)XtH<|tBN8M~`v73Z0>z+sPjPQ26Fn|<7EHQ2FvkP=S$hC+zB5@sHx<>>NdWZbl>*63aa7N2(B3h?a4B}Le zCX%RPf%ij78jy8p2-5}Dq_|vOa8QA8liw&;sIw`=*{2K*x=a|(xt%?VX)|iKIS-Af z%~0MbO-F+`)u=)gUXBKcyU~4r@Xk(q>)pY2>sG5DRgjhKTsm=RsaeoMj++AT_k=mI zD%MVl5tAE`>3??29)KD;CPz;wfkIE^XfqUIO{}io)2P+wR>x*_brXdu2(@U}Lq$A_ z3Lf!AtgNS1#^V`{-fV3(5C=>Oab^%MjEV0K!8X`3)x=524`E0#?ym`IOGBlIjVLoL zfv?Rn<&Oz9G1m%55oU%}Df@|DpM5b>mZ^I23tOYikH81mD^U}pIdldYwZBDT#u<49 zOtQaRcB&J)%*uxhCqSIR=%E6pM?Zh^OR-)H|4B2gQaX8Aj>jgG8K}s`OLVjNT*Uv& zK~Q?~IxaBuO8cd+2EC>I0DqUickzv&av}doDF}8^MM*6FrQ;68ZrGutA_;WKaklw1 z*A5j^DA-`pbC*5gqMLy?pF0WAkOAgWvT?39M6wKNo)lD-DDu9z+Msx#<`>Mr4ya7` zqlj&iU2OS3CIE`iX>T{spy<{VThaKQb0vBWMs)hMgsFFJ-p8Xl4H_#S48%flFkcl6^;C~keR>zuYs{4N%#3?(nuK3EO%R_E4jrkA@wspa z6zlmxaVp1{f|M6TMp4zojv1P2L2%Y{A7PrRJXc6{p1dZn7tiRppvfSqZ|T;r)jvr2{x9U3%* zMjBIR%s_)UPIIT>eW5L&R~wyHe}4yqi{+_jQ^)0CN=1&S(RToavU_tySizd;D?G`Cw&*whov?ry8s zgR-fLk#bO9F}Q~W(D}3?%N>)z1&7QGb8Q)CG(69*qMT8T&b?F zb2p)3=5@M3X}D#;3ebf>@|j7Rxe#x2gS@a~NKbng=-{*_n!T-dhtCRhB0wT3i^!ZA z--EVDB+f!eO(C`j$B=~OCM``gBNEL`{i{eVGBH`5qxCp&;x1bB{hHV^==}_* zHn@F<_ydPBl3UhGeHMjmlD%6Ttk?+#CY_V!%?MYfuu`JTa(cWKd6NMZ5DeTAP<{DdTE0vdE>CVoDX zA-Pm5MC)_oP+oOBNl7^`deU9<-WLUeq)u?+TodhX3#ZbC4;6|i&!FnCNT!G@)kCC+ zfv~#q=9{qV49sfi$ET}Fj(asUnIN-p1rNoL$*3iR66qi~%wHHt%b410-fHw)cUY$Q zv|>|EGOgFc#U{)hJXdKasfn8XIwp9fpUWIv-~|)(Iw5I}OyqIQ0$6h2&>7$O?z`LB zfsW=xptI>{jMoB4HAz;mm-SPGUP$DLceYCWgQ1fGNSON0;e_r{#amMw!i_mz7P0f5 zFpU^cI?QTnWfnU>YW4cFUv*nsZPo^unFJ$9HIU%`m!1vq`U4HZuA%54PCBWcoeUbC z2Bu*%Bn?;``pBXz1YvPP;8!jA{A>VNl4!#l6AW9QM6{NV3na$c7SPApsU~jYtxK*# zXZ*X8Vn`y#&mAcc-`Wd&9=_~nFW6u+%>N1z|3Z&JIWgf;S3kFPaT0#Pp^ci7Cip)u zL>A(p(P{2Ade8`f0j2>FBM&_8txto>(#ZuX-pQq+ijGbyLY(}rJ{o8Bq`up04WPJ> zRGhgw7}aI0^`#q(^bnKR)R|$5o5hzy0^$e8-XEA)*HeAqp8cWjZ2a6kCR=_3QYQt7 zNu8;rjuDQxeGb}mN(WfH*f@FpAlGR!DDDjW3i}oE9RFMee?AIMzg~Im+o#=9@SU|k zv`&MiTIp}4iyy6=1}m4od-~(j#w)9*!N$eaCs-Wp;k*`9R_qF{PnIDm>?K^;SLo{s zzzf9km&%2cOM^jT;=$k~91IR~{GtW}yG*NTe@lluOD{a_OZap0(%U1GXkE8vkgFg-ZsPoc-0NTPDoFkS0|B|nRi5`$Rd)}$v}6_@`Rl=tZ=PNM z-r(u=ryJGA<&EuIF9t8JFSBRM7q=$m+%9fb*|MqTlWS={{@&pKCjYu!YUuN@ZKFj9I()rR&ik!>L zO}%?~bbrsCHQqJzeB#~GSJ{Pk*>F<$y3Q}SS2^!4eBs@ccQ5Tdf9~^VOjFKEck-bt z8~5P!@c#JWqto%;aClJ8pJbD`8ZTWG4TD+e&T!Wq`1vF&yos{I42V%L{lu3$j&0|a zMl3>q`U7gPsMOHiH;|`MWxONM+zpA)69-lZ=I`>H@y?yVxLy1`V zyl``ScapPwow26YVsV5i5rw;1Jt-HgcvxTsl*KK-$mT4e@e(L#n(fZAWrm#3vPpw= zFf5Bpwu^i&U7|8~(byL2Y^DWf9xF59BC9S@j^ANAu4g%WL6zwIB4?24JjkKZ++Jl> z?PZ6$DV832xi={qNnSRZq{?p_i_dhr} zbC_qs!>r1=lJ&~-D!)Wp-PksCoE|+qJUu#b<2xAR0+nY$=Mo>SgE%+3J3^7N1X@LH zQ4SVI#I4bytm|^LXH1f|DZrN1(#!88an?D?j?3rM44Y5oQt}6oU@FJl({fL~ zlC<#w+L$-&dZ`UXd6AGbpuB@ zf!|y`-uH_FL<*BaiSfsNk3E7cmpOQ~5uhMZ5vo5EZ{P%#`{>d5Z$5f-cq&E}9kBUn znfH*q^QvX>hjDQUsF%<3D@uLG*QZ{OI^#41c5R*8jc+YHn+m)rdO5Z$**Okd=5N zD9*Q3tShq*T#*=C52Nz9tV`6+Ow~40u|1pQ(}; zstzs~RE}BX>Ve+Z9DZMuC-=qDcUrG!waX^2g2&?^uYCsz*fNaKEQu}@VA=<|YcHog zb@NFerjM^`P?Z^&d~ZOxnYr(yEiPl6%~hOiLKU zO|mL}jnrpm$>$BPNX~$nXl(I_f?QtCVZh+JeT$mItl3>tB-6{bA*6xto&omTIFo=V zeFCqVC=o<3#ie-k<-dY`5B&sFFx5b$z2m4XKvEKt#Yxo z$Ru}{+dm~xwn54)W%DaSg?O0(O8^;C8aKj+j0OJ!&l502qxMGY5@PAVW2l=zHgg|C z>AuHlWyoCIuaNl?#Ul&*$>&ff^n$~ak6rjxS?!rgf=x&RfShB#MM3fc2g6EiN{aC- zxT7-KCp#<4Lff_NiMFNFMA^`2U#z6eUV0A7Tfs%%4HGOg4Pagk-2k%zZCgTa{Oa4XWHHmQK_9*ob<#=kfbtwU00 z7RzLMNaZ}}+_XHpD087(fk%JIM$5)7%3N}X+$7yd{x>E1OD}qxq)I_Rx5D@Af+Ta5 zZfL&NZ`=2@-0RaPUW;?V#s%4rAX2)eGExIa=V*KGwB0gDtTG!9Zj>7evB523?q-TR zvK^6w&(0Ohl*tik4Xc<@n#?7dxTQ*N2Vkh>P^u z#3$k%%Q&uXo+>LqT3`~Q?0%bw3pvV_ZQDUQ*|{X2u>`hf@s*b$hy^f|GBguJ8hDoD z%^_$@#`plsngM3A;z}G9){wiAqq$>6Vb_4s6dt8gQz%{|f|!>iH|8Y&^~FDEmY7=? z<;1MOegJ~DX8sw+VxO${BxH2{0r1}I=#wOpkVCrImh9}{GOuK`5{bC)(eFN;|M-b+WA=ciT#8VPA)52PY3sVvw=|RJ_6iiv{2Z=c_Q@d6gMCZDr5)Nb?TSG#w3# zipni!MM*Ygo3>&0c?i%k{CUfEx&x^x{=LW!0V zM&~JXf^P;nvGY$lI|nw7;wmMhsR7SW6Uyx%U=sacTN#~}h9wcTA#svV3ap{UqIKkM zmauv%Csh;dSIrR`RGJ&#mHuLHOZy0T9S+~$a|a$qkrPy&X2XuqMRQB4P{I?-k07p3 z-4XdsTVQLx*k;*MtxYJxfmCp}SIPzKu9e=3Rqo^wPGYro@BOfV^%J&6DPdGL7lUlf zPS{asdg+l~@8>c$JeJb9DfC7QFGkXBtVXhi?`vyTy8GHDu+qJNM4_}=>S;?v?DkXA z&|d8&zb1)jRyngLO`c|#CMKM0l!{jp&Dw?nj`{jN)2GIwU^Xm2{9XW49RS*F{bDbCR%%|d1O5!K%oLa zpoEE{83I@^MH2MxXj>J$YQJ|aPf>p|P!Ja`kCrhsdXGd3Y1WT?JTRq@RPXFb;!U?R|;{G7PjHZ z1{%F4MyGQ6BT?6~k%z!yn?sqL&|wiqF=9?LEXzX&a`fOT2t=jFT(@+O$7hsD4c(}_ zrqC;1QpOQFAtEOsZLL41j)cV~9CO`{J8B3;2#BrKAAPO@N(qO$MWn=}1mTLeC;GZ7 zYe_ySPS=B4=vWj>Y5fmkPzDK2TX~R_+95G+Lq)}TQ&akght(t~p5R4{53R&2T)Ul`9lT+3 zL6OiL>tJ+XiGe#%Bq@vR8?U|AMQWW$>wc5@*PBr7>+3JCc|wBaT4M^WC?| zLa=>2%~4#d8_gF3!gviB8r+sAzMU`j*{uuHJ-3DNq&JXuAhIx{9q+x8tuXuWUiR5; z{iIxihAFiOEhm_6E7K7pwG0R$u}An&iaAPOYlY}R%*dwYu`>P7jpQ*O6QveRia`6ps4Z9e>-cKLJ-pNQ- z8-?&m)?b8|^GfN#JKL@S+!vD*;#!WMY7g=GsnF`D3^?qR=G zG{FTe?y3oI^J+e(nDMP!q$cpI&(kCtLV%v}U1-QCT)K-8LC-7>5Fnr#0_=-j8ToLstiNm4 z3)RAH`8!o1_H^edZO(uK}`#1iUn;j?BnEvH`>#NgbuJ6@44eeJrj zY_|=(}6^L;?J}2%bp8Z2{qf<=&*m- z7S*QKhV@?bo08B~xH}9&a$4uc4-SthLVtO7ax4l}i+oEE(l5wZLu{&aBb))!WcV%G z8Tq0pKg*`0J1~=s*{EMyXUblR<`aGiFv~tGtKaO` z)#SB%Rz>P3R`tHlP-xpOv#Ea8Fj+(<80gPX^j-@g8GaJ+fr z`d5q}9B*$_l6d>ti%q(^Hd}Rz8`V%B-{RxNxBhBYPMae8dG&3++FIY|;^pSX#>W3# bJK5a0{!jJGf&Tv6S@`=O-~V6xZj<~!C>Vkc 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 4baa1ebf1cd4775fc678ebf78409c90e3ed80bd4..7c9f87584df66348f02e40326b25404f9361e636 100644 GIT binary patch delta 100 zcmdnZ(#p#HnU|M~0SKz{+ct71F?vte&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjCS7|#L#ohT$$ delta 26 gcmZo=-Oa-NnU|M~0SM;l=WparVr2B4yo2#909U#PE&u=k 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 00322c01401ca7013677e95a58ec34f895ccb204..cee57ac75bb0be803d23319e7f3d6b02cb13bfc6 100644 GIT binary patch delta 100 zcmaFJwwj&$GcPX}0}xc@w{7H(Ve($8pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&)$!^9Xpc@xu50AIfct^fc4 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 7c5189f655aec8223253d420c994a0f3b8343c9c..70d57eecb719663e1bf76042d5706ad816ef1b55 100644 GIT binary patch delta 100 zcmX@fGntqBGcPX}0}xc@w{7HJ%IZB!KR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm ruOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX;Ph$T|Z6#$P1f delta 26 gcmbQtdy+sl$9}H@^97|0AAGxwg3PC 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 5b34ba65817ab32631a80e7ca28e7facd5ab13d2..bef8c2879f6c8e9854b653fbebef17b20ba4c6cc 100644 GIT binary patch delta 147 zcmX@2HeH?XGcPX}0}xc@w`DQ$Pvl$3xNPHwd5jA2X+?>-spa`a*?Q@viA5xOz$6yv5 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 0346dc61adf78e41954a83291cfd771fefd0f8ca..a6955f390bfdec9ed2a6661c293ba84210b4003d 100644 GIT binary patch delta 1171 zcmah{-Afcv6u)=e4_)2bRohf-chababf+F9A_+3JOf=nfBe0yt-BCwpckIq=hWSwx z6yzQNa5zNZ z%$m0*&#Z(WQ`+u4rym4S8DnZ*n=#o`a=fUr98-0}N@i6z6>FiL?me;Rl(IzO_**J-b17^=X&Tot(MAM z+Uiopr6TKqSjo@Zs>H=I*MC_xikcg+%_*&5xk7frDg#~=MfZ`MFW7QU?o0P51I(P% zvbH6U>CCc~tXZ&COUdiwOwF0HI<6HqjK7r4y(nf@mth^&--K*2e!uEO^fZ)%TM%m; z;2K$t@rrQPzXl57^Whb$JMy+>;Xn`Qt}komG^O%4EV$GZu*5U#19?B;jm7GE&w+G!)N-m>-TtT4 zw8{Zsi{4>4JT}cEiT(5qKayAuz%wFjkiSjD29`ja4M9S2PV6@enj|nZu{?m}V?~tl z{v|6uO({?+c^9o%cecXNEqfSpTwqJQQ`Gv0kUEDjj4*;Qk1!43?obrVR&712s5abZ zv}kLVqLfDJb>{WkhyDmUUl(sSdjzV`R5wyyd9PKJq!@d^pX}}k+(YgX|G2x07I;fj zqSc!r2D(8-Q4M2DCAYjiZ{~`Ic8o1MSDGHucnxh_Z#gN@ecuS;>X46A)!j*64>IiH ECr20;3jhEB delta 1259 zcmZ`%U1%It6h3!m_9w{>yKCZ_O}n#`q(82vse%0*sI}!Xxbwf>@vK_gB8(P_Gd3Q1m6aBRyc74c`l`zzm&J)5~p(HmT*f0sBgs zz84q$t(;I69wPvkK!Yl&O7n1(cti(-On?Cg1cPfAj6+@N*#HT!WB?tCa7;M~Ps>F( zN%n&$8L*gO-|QIEhheS?;K_zuPxeJm3d0%$Fr>vH_SwMjfxC<$#{}0er9*kIh?486 zdns#onQh8>R90oI)sz6rqKmQtFeI9-DvRlU#(#H1>et-`rC4MPzD(AsP(q3D^l86g zxz3txHl1ZB3`#O5`#3Q<(di6^B>7Hj+4jQ!3_i41L$e)sy_Q=78b|JqEluTza|fWv!N z&A^4hf_#M(WTvSb#E-74lhVTrg5yfVZ`wTltY?L`yC{CpG&(wh+QN70!0oh1&9uy! zEcQT;3kdL^=yZWy%S_#O799xzqO&+;Mrch0>p3yf3f-g)BuIxr>A>v6;~(G1wQQuaX5eke?tIqp7@0NGQg;D%yDe zo;Qx(c(3F~=*7Bg1FjQ6i5_l9%J&#nke79A!N;duIH(_yy!b_TKnm@+SLn zytuDBLlp9aXaIwOqtGcPX}0}xc@w`DDu$a{&=VB>?;%nI>oMTxno<@rU~dg-N!MJYvznK{LJ z$%#3cNkxezsVSQmvE&PR&(qJ%E74EU_YL-p4=BpdN=+^))=$eUDlUmn&d)1JERN63 fOfO1I$=6RzPtAh~LOF07;`5U;^*0NNZx#jst^zlB delta 63 zcmbOcb~KdtGcPX}0}#y9&(E4Zk@pg#`o;&VnZ;A%lk@XR5{u(YGIRCPOB0JyiV`z( SiZ`!j$roY_*_EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX*>kd@JYvpCxcHUMf`2Xz1d diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/dlex_out.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rails/__pycache__/dlex_out.cpython-313.pyc index efe66e0c1c035e4e3ff61791d9322222195674a8..fc272623987a05fbc4e950b722a60a964b900520 100644 GIT binary patch delta 101 zcmX>pIa!MPGcPX}0}xc@w{7G;!sEwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX*>gq1O1vlQD;HUMZ72bKT; 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 cbb1164b38891978b494b0e783e7025266d33009..3ecaadc73f68316bc46d492b3b8a658a307cc85e 100644 GIT binary patch delta 101 zcmaE@xmAn%GcPX}0}xc@w{7I!%I-ZwKR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX+sm7URVGdG78F92`L2NnPT 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 1e25c612d8132ef2818e930e829c02a243414798..35c858f29527b7e1b6e6c3d32673e307ea7062af 100644 GIT binary patch delta 101 zcmeyYxmSz(GcPX}0}xc@w{7G;!R|d%KR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX*>f}PQSvmA#!F932<2SNY< 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 07441aee62c65ba8a3829fefd87ff07cbe71fc1d..df3ae4b25a01a32effa92f8e742388fa18bb5a9a 100644 GIT binary patch delta 101 zcmexlzsG_5GcPX}0}xc@w{7IUB;Y+&KR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX*>Nr2INvxcAuKLB?l2ZaCt diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rules/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rules/__pycache__/__init__.cpython-313.pyc index 4e813efa47ef37ce8ddf256d058cc2a416d54877..bec637aea5704e1935e2d321c0f68891c932a9ed 100644 GIT binary patch delta 100 zcmcc5ypo0cGcPX}0}xc@w{7H(Vf3D*pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&)$!^jvgc@twf0A2|P6#xJL diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/rules/__pycache__/alcada.cpython-313.pyc b/libs/agent_framework/src/agent_framework/guardrails/calibrated/rules/__pycache__/alcada.cpython-313.pyc index 4934703eae1e19733ac70b26412fb852ab09e8e4..8035625518e1f7cedc496124ce14cacf53d4f5a4 100644 GIT binary patch delta 101 zcmbQw_mYqMGcPX}0}xc@w{7H3V)dS(pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&+M#LDQmc?au8MgVCo2bTZ< 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 587b3d81ef62914356d21ccdc3e31ee661408102..1f8f177a5a0fc4dca1d29f30e92e9c73f403a8dd 100644 GIT binary patch delta 101 zcmca0GfS5HGcPX}0}xc@w{7HJz~wz(KR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX+sfQvD7^Ea*~%m8cV2p9kW 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 daddf1d387f9a52d8079f46af884add44f90bd9e..f150fb0a30a88e2b7f3785fe8c970facce5d3927 100644 GIT binary patch delta 101 zcmZ3%{fV3VGcPX}0}xc@w{7H>WAUD^pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&)`$HEx8xrC*T5ddbe2JHX< diff --git a/libs/agent_framework/src/agent_framework/guardrails/rails.py b/libs/agent_framework/src/agent_framework/guardrails/rails.py index 810e694..87f4d73 100644 --- a/libs/agent_framework/src/agent_framework/guardrails/rails.py +++ b/libs/agent_framework/src/agent_framework/guardrails/rails.py @@ -328,47 +328,6 @@ class ProactiveOfferRail(Guardrail): ) -def _sanitize_low_risk_phraseology(text: str, reason: str) -> str | None: - """Remove apenas fechamentos/redirecionamentos de baixo risco. - - FRASEOLOGIA continua fail-closed para conteúdo material. Para B4 e ofertas - genéricas de continuação, porém, bloquear toda uma resposta grounded piora a - UX; nesses casos removemos somente a sentença ofensora. - """ - normalized_reason = (reason or "").casefold() - low_risk = any(token in normalized_reason for token in ( - "viola b4", "outro canal", "atendimento especializado", - "realizar alguma ação", "oferta de ação", "orienta o cliente", - )) - if not low_risk: - return None - - forbidden = ( - "entre em contato", "fale com um atendente", "procure uma loja", - "acesse o app", "acesse o site", "atendimento especializado", - "área de planos", "area de planos", "é só me avisar", - "e so me avisar", "realizar alguma ação", "realizar alguma acao", - "gerenciar esses serviços", "gerenciar esses servicos", - ) - sentences = re.split(r"(?<=[.!?])\s+", (text or "").strip()) - kept: list[str] = [] - removed = False - for sentence in sentences: - normalized = sentence.casefold() - proactive = ( - ("se quiser" in normalized or "caso queira" in normalized or "se desejar" in normalized) - and any(token in normalized for token in ("realizar", "gerenciar", "cancelar", "contratar", "alterar", "ação", "acao")) - ) - if proactive or any(token in normalized for token in forbidden): - removed = True - continue - kept.append(sentence.strip()) - sanitized = " ".join(x for x in kept if x).strip() - if removed and sanitized: - return sanitized - return None - - class PhraseologyRail(Guardrail): """FRASEOLOGIA calibrado: bloqueia fraseados proibidos do agente.""" code = "FRASEOLOGIA" @@ -380,26 +339,9 @@ class PhraseologyRail(Guardrail): _llm(ctx), "FRASEOLOGIA", {"text": text or "", "context": ctx}, profile_name="grl", component_name="guardrail.fraseologia", generation_name="guardrail.fraseologia", ) - allowed = bool(out.get("allowed", True)) - reason = str(out.get("reason") or out.get("label") or "FRASEOLOGIA avaliado") - if not allowed: - sanitized = _sanitize_low_risk_phraseology(text or "", reason) - if sanitized: - return RailDecision( - code=self.code, - allowed=True, - reason=f"FRASEOLOGIA sanitizada: {reason}", - sanitized_text=sanitized, - metadata={ - "mechanism": "llm_rail+deterministic_sanitize", - "data": out, - "calibrated": True, - "original_allowed": False, - }, - ) return RailDecision( - code=self.code, allowed=allowed, - reason=reason, + code=self.code, allowed=bool(out.get("allowed", True)), + reason=str(out.get("reason") or out.get("label") or "FRASEOLOGIA avaliado"), sanitized_text=text, metadata={"mechanism": "llm_rail", "data": out, "calibrated": True}, ) 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 c6acc34bbd373ae3aad4a72c947829d455dde7e9..2770326ab39c713494ee6f46a8f4acfc72b11135 100644 GIT binary patch delta 78 zcmZo=Uct=$nU|M~0SKz{+a_{9HEY+;%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP aNi2@f%}g&!Ov%?zOi#^&2~K8aYytrKMH`a< delta 43 xcmZ3%+{(=TnU|M~0SM;m=TGE*Dx9L9n^&Trl30?cpO{u2U!Gr-Jz0&h2>=gG4VwS} 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 4c687e48a2eb4847b3319db8d66e87ba3eb9f71e..669dd279dff539cb88c95ad451c963384c58fd29 100644 GIT binary patch delta 80 zcmX@8@-H#4MbqpPN^rpORRTsGpct9$%hcl)br``5_+wH-iqt diff --git a/libs/agent_framework/src/agent_framework/identity/__pycache__/models.cpython-313.pyc b/libs/agent_framework/src/agent_framework/identity/__pycache__/models.cpython-313.pyc index b476d0567f8364bc0305dc2843ce4725ee6ed9fa..39d33a3712b9b879195a31df98cf39a44213cdfe 100644 GIT binary patch delta 80 zcmdlgaYKUpGcPX}0}xc@w{7GuXEtlq&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY cD@iPl&&^CPN=(VuPfSnEg9&b)%DjLB05)hGssI20 delta 45 zcmca1u~mZmGcPX}0}#yB&)>*h&McgypPN^rpORRTsGpct9$%hcl)ZTe^8yY4G~N!f 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 20ca015aea2f9eb0c2885f5591b87a18eae49b1f..0cf4b8127cdbb8666d67c04a2435491fa6a38c57 100644 GIT binary patch delta 80 zcmcbn@>7NTGcPX}0}xc@w{7GOW;Scr&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY cD@iPl&&^CPN=(VuPfSnEg9&afWPZvA07=vx2><{9 delta 45 zcmeyVa!rN%GcPX}0}#yB&)>)$%q*OupPN^rpORRTsGpct9$%hcl)ZTh^HV+mK%x&3 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 953c1f9a9e3a2e2176576ca670a52e18c119007b..b02a300c6a21fbce7f730a984ab4ed56cfd5ec44 100644 GIT binary patch delta 100 zcmdnM@{5K0GcPX}0}xc@w{7I!$mrdwpPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&+sk&)4QGCNZ-0Ael%$^ZZW diff --git a/libs/agent_framework/src/agent_framework/judges/__pycache__/judge.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/__pycache__/judge.cpython-313.pyc index c31ebd724d2f642b4c2df32baa3924f7a15a3b77..085b315a3d6a5c153a8430123b88eed6591da9da 100644 GIT binary patch delta 103 zcmbO>hv~r_ChpI?yj%=GP?g`dk^2U-cawf@UWtB+zHhK+d_YltR%&udv3^=+QE^Fp ua(-S(VsU(KW_nR#O1^$#dTJg_5Xwm_O3Y0y&o9c3&rin5oH delta 29 jcmaDbhiTdzChpI?yj%=GFi$^!BlitvMvKjQEJj@bh?xk2 diff --git a/libs/agent_framework/src/agent_framework/judges/calibrated/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/calibrated/__pycache__/__init__.cpython-313.pyc index 8819c5113bab64c8f1016b4800dada84dac2112f..609ab11e151925bd7bf3057567c18eeaf670d4a6 100644 GIT binary patch delta 98 zcmZ3^_>qzOGcPX}0}xc@w@u_W_MV`hn^&TrqVF5*86QxTpOuEwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX*>jhWG7vkuEHVE}N{2h9Kg 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 cedce7428f7b7c4759e390fcf76a54720005551b..b087b790aa3684b328fa8ffa554221ae543b1ec1 100644 GIT binary patch delta 98 zcmZ3__>+U0 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 cab6b1386c9d26d61d456779a20d9fc822e1ab2a..d2052d5d5369b0bcfaeacc60ff147d9634914bfb 100644 GIT binary patch delta 100 zcmexnc)*DJGcPX}0}xc@w{7I+mGGXTpPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&++E5YbBIa%T^0BG3pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&)`#=_`1IfvyW0A9%k{r~^~ 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 a7a3013f0d3c827f02fd2f26cfd9ea57fd7fbedf..9587d8dee4df5d6f31b9ec78e539731323790302 100644 GIT binary patch delta 145 zcmeCOyKBe$nU|M~0SKz{+p@AJ@-AZ3owy-hAwI1rF*mh5zbIQjy)>~Xr6@5or&vEZ zF()&rD6u3pWwRP%9Iy8b{oK3~{Sb1Pq~007_dHS7QY delta 62 zcmca>*Ja21nU|M~0SM;l=Vv8Nh+pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&+M#?0t7c@Oh-09$VdWdHyG diff --git a/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/vctn.cpython-313.pyc b/libs/agent_framework/src/agent_framework/judges/calibrated/prompts/__pycache__/vctn.cpython-313.pyc index c4f3c1a8fba7abef3fb4cfa428154db5adeae3be..2be23c0f38125e49cf0facdc7f77bb620f8e45fc 100644 GIT binary patch delta 100 zcmdnN(!|RBnU|M~0SKz{+ct71GI~$Z&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjA+8BYTMnUW+) delta 26 gcmZo--NC~BnU|M~0SM;l=WparWMuT3yq)nh09ObHApigX 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 644807836f0ac0e653a641cdec51b08bc68084ed..b929ed76e7c4df26613113dba2517bf1731b056f 100644 GIT binary patch delta 98 zcmbQq_?VIVGcPX}0}xc@w@u_W_HNS8%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP oNi2@f%}g&!Ov%?zOi#^&2|_t(MTxno<@rU~@%hP_`V;M=0B6M`fdBvi delta 24 ecmaFNIFph4GcPX}0}#yB&!5O`%xE#OGYSAsg$7sv 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 648393401c8759080a8265f0fc8716458145ec4e..bd6c7051d09f3ce979ce0601868451d7bac889dc 100644 GIT binary patch delta 101 zcmey#dYFy-GcPX}0}xc@w{7J1Vf3!k&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY sD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjX}7#A`E0OPYHga7~l delta 27 hcmX@i_LG(SGcPX}0}#yB&)>-H!^mi|c@g76MgVF#2U`FD diff --git a/libs/agent_framework/src/agent_framework/llm/__pycache__/profile_resolver.cpython-313.pyc b/libs/agent_framework/src/agent_framework/llm/__pycache__/profile_resolver.cpython-313.pyc index 842b81337819a666eeb1e942320c2af499924e58..ce8be980630e9ddca20b12da65a94001ddfd4927 100644 GIT binary patch delta 101 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℘wFE|WH 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 bD@iPl&&^CPN=(VuPfSnEg9%RdV5|cG0&E+% delta 44 ycmaFKe2kg+c#V8!FpPN^rpORRTsGpct9$%hcls!3{u?_$mC=I^= 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 ccc9304d4c412e5d540402b4fa5faef99f4d9f54..8bf79966cb419a84223d3fed2dd2efe8e2f85efb 100644 GIT binary patch delta 82 zcmaFf&)7AAk^3_*FBbz4ROPpAcSR9|5nO>BblCPhbo|*>}+`OMz!vz3@vmKHE delta 47 zcmeC0!1%nMk^3_*FBbz4%+=4|$i0wRI95M5uS7p3u_RGHF|9nlJijP=^CM;r7XV+O B51Ie~ 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 ab6c0249df60bb557ea299be273a3b596ba16afd..237181e8363759cd7a09d764173447712b765498 100644 GIT binary patch delta 284 zcmeAdcp<>|nU|M~0SKz{+p=`oH}bhMnKkI==9TED==%nH#s?JTXQd{W6zivD78RGo zC+FvtBo@c#W~LVR@vYKiGv?KDG3-hVF&x2MmW)M$!Q3${ z!Q$#bOM)eegwlC6B`3dRzAesClv-SnpI4lEi#0hhIU}`51gJt&c=AP-2u7XB|Jfua z+p_X8PM_?>MAk=5$qsB7ettY zv~wANm>@!XvLd@Pqrv1ScSR9|5nO>BblCPhbo|*>}+-$@&my?ShXc9961LNmUlW%gTF&^6Nz!S%48p;|Z z2eJbd1T*S!n=(Sg6c~JuFfed4C@_RFt1xIX`Dt=b-pgAq#8H%5T#%nvoO+8jIWajS zRa0QH4PO9Lk<;W(zGB9MlmGH9lv7Yy&byHJhOFZJsF_h8#d&0ezA^9!3V-Be5S99% zGsX85k58e0MT1 za0BU3W)%iaCO=KC$=`U(IareulQU8^`6t)&1x&ueSHQSyvMc{WaaqOrQ8S}HigL>c zePiGj6#mG`AS(4iVKR$=5u?{+a{(Pj@5w0ws%&0Bql>&J_X{Y(nA-%DC0v1`RRTGg z#U;_jB}K6cH41+Dd8t5k9|ejTJtn6L#wiH13V&n(5=F`&6U2aoCQFe3hz&LJv0x2j T*yIEubzU1r;ZF=e0<07OiI__D 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 7995057056359bf0ac7874dac8af15ab6caf771e..db288d470179c85a50baac041c7a58f3c7a31416 100644 GIT binary patch delta 135 zcmcbhGEtTHGcPX}0}xc@w`FN;;M1& 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 823bf00126437c5de211dd09c55ed4ac6cc49c41..8a43c7a407729300fc22f1a6e0af233825833a6f 100644 GIT binary patch delta 80 zcmZ3VdnuRuGcPX}0}xc@w{7I!&t=xCpPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( cSCUv9pPQLpl$esQpO~JS2NT?Um+O)?0DD&+I{*Lx delta 44 ycmcbVyFQouGcPX}0}wpuF4)MupG!DNKR2&LKP9mwQ9m)QJia`?D0>t4C2as&D-YuU diff --git a/libs/agent_framework/src/agent_framework/mcp/models.py b/libs/agent_framework/src/agent_framework/mcp/models.py index 98f1529..97046c3 100644 --- a/libs/agent_framework/src/agent_framework/mcp/models.py +++ b/libs/agent_framework/src/agent_framework/mcp/models.py @@ -28,6 +28,11 @@ class MCPToolConfig(BaseModel): execution_policy: dict[str, Any] = Field(default_factory=dict) selection_keywords: list[str] = Field(default_factory=list) + # Política declarativa opcional de apresentação da resposta da tool. + # Para novos projetos prefira mode=renderer + renderer=. + # O framework resolve o nome no registry; a regra de negócio fica na aplicação. + response: dict[str, Any] = Field(default_factory=dict) + # Política declarativa de cache da tool, lida diretamente de config/tools.yaml. # Exemplo: # cache: diff --git a/libs/agent_framework/src/agent_framework/mcp/registry.py b/libs/agent_framework/src/agent_framework/mcp/registry.py index 6ac4308..b37efc8 100644 --- a/libs/agent_framework/src/agent_framework/mcp/registry.py +++ b/libs/agent_framework/src/agent_framework/mcp/registry.py @@ -70,6 +70,7 @@ class MCPRegistry: "confirmation_required": tool.confirmation_required, "execution_policy": tool.execution_policy, "selection_keywords": tool.selection_keywords, + "response": tool.response, "cache": tool.cache, }) return out diff --git a/libs/agent_framework/src/agent_framework/memory/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/memory/__pycache__/__init__.cpython-313.pyc index 0a0f164baa0800634db396dbba889556818fbf9a..de3110514752747e8a7995b1c5710c1e5f23c9ae 100644 GIT binary patch delta 100 zcmdnW@t=eHGcPX}0}xc@w{7H}%k15%pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( rSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&*BmzmLe@@M8A0A?r$&j0`b diff --git a/libs/agent_framework/src/agent_framework/memory/__pycache__/long_term_extractor.cpython-313.pyc b/libs/agent_framework/src/agent_framework/memory/__pycache__/long_term_extractor.cpython-313.pyc index b7442fc0e7f05270e463f01681f85fa4e8369d6b..63ffd966e961b0668d9a255c60cd57587f3760c3 100644 GIT binary patch delta 101 zcmbO({7{(tGcPX}0}xc@w{7I!%H};mKR2&LKSkd+*fTz$C_gJTxujS>EwiY&BtAJm suOzWJJ~uPHC^02pKQTQu4<-oZq!lIRrk3XyWyj|yXX+sm5tGDGdKG+CID#J2Uh?9 diff --git a/libs/agent_framework/src/agent_framework/memory/__pycache__/long_term_memory.cpython-313.pyc b/libs/agent_framework/src/agent_framework/memory/__pycache__/long_term_memory.cpython-313.pyc index e86f11020f4bb7dc4f6d1dda0d02add86c4cd5a3..b43fee84881144b66df0f59af2a42cd821d2b906 100644 GIT binary patch delta 101 zcmexsa@>^rGcPX}0}xc@w{7IMV)E|Q&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjaEn9L;r31%dO delta 27 hcmX?Z`qzZ}GcPX}0}#yB&)>*x#l+~mc>-spa`a+41?wnfjZjF|x1%0O?gEM*si- delta 27 hcmaFDJBye5GcPX}0}#yB&)>-1#mMNq`2iyfD*$LM2Oa~=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&-XkCD-7a|lzi8~}Jx2nzrJ diff --git a/libs/agent_framework/src/agent_framework/memory/__pycache__/summary_memory.cpython-313.pyc b/libs/agent_framework/src/agent_framework/memory/__pycache__/summary_memory.cpython-313.pyc index 49b62d8fdc6c69fb3bcf3b0a27cc99c2164062c5..23a63b24a26898019424cbaef5ceaab95e86ac83 100644 GIT binary patch delta 101 zcmZ3I_%4zAGcPX}0}xc@w{7G;%Iw{(pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&*>l$p_SvoyW%BOQ&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY sD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjYGna(N!01B5S0{{R3 delta 27 hcmX@$_05y}GcPX}0}#yB&)>)`%f#rgxtQs!5&(5h2igDt diff --git a/libs/agent_framework/src/agent_framework/models/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/models/__pycache__/__init__.cpython-313.pyc index 6dbf7ed5e3483562dc393f84b166363d1205d817..0d18e5edce90c9f38f9ad7d4da91158b4025bb69 100644 GIT binary patch delta 98 zcmbQk_>7VJGcPX}0}xc@w@u_W_HNbB%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP oNi2@f%}g&!Ov%?zOi#^&2|_t(MTxno<@rU~@%hP_`V;MA0c!XojQ{`u delta 24 ecmaFHIERt@GcPX}0}#yB&!5O`%xFEaGZp|(9tLCp diff --git a/libs/agent_framework/src/agent_framework/models/__pycache__/identity.cpython-313.pyc b/libs/agent_framework/src/agent_framework/models/__pycache__/identity.cpython-313.pyc index c2b0f6fd924277dafbc13dae16a9938f45c75fe6..df67cd473213b8efe3a4da96df26792ab3574578 100644 GIT binary patch delta 101 zcmX>vHB*}VGcPX}0}xc@w{7G;%IMvypPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&*>l#$VTvoup3Hvnhh2ND1P diff --git a/libs/agent_framework/src/agent_framework/models/__pycache__/session.cpython-313.pyc b/libs/agent_framework/src/agent_framework/models/__pycache__/session.cpython-313.pyc index b08fe680dff633b9878d5ac8599de2ccf82eac2c..51f483b0c0e96da2ee3cdb2fa02e40144b2bf43c 100644 GIT binary patch delta 101 zcmca5vP6{oGcPX}0}xc@w{7HRX7+B;&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjagnZ4Noz$zn* delta 27 hcmZ1?dP{`+GcPX}0}#yB&)>++%*<%DIg;6%9ROmw24esK diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/__init__.cpython-313.pyc index b0ef011f121197e7fd3cedb4d0d75088d9440d88..8f32787e3a9da6b530e8c40b3968cad8253ad8fd 100644 GIT binary patch delta 100 zcmdnN)x^#HnU|M~0SKz|+ct7XvUvCC=jN5@r|A0zd&UP8TA^-pY diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/context.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/context.cpython-313.pyc index 68ac915279ec4e633cee0b77d63e9a032d443738..46068d0361c0689d0f076d3982f6b50357f8b0a5 100644 GIT binary patch delta 101 zcmZ2r`O1>}GcPX}0}xc@w{7G;&F0;$pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&*>nvKzMvm*ORQ2=ui2jTz# diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/event_bus.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/event_bus.cpython-313.pyc index cec5a48c4ff40cc762dbd8121a015d7325b3d8b5..de174b9b723dbec22cb3735af966a36d76c394d9 100644 GIT binary patch delta 101 zcmew+eL#l$GcPX}0}xc_w{7J9!R+0upPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&g^G%xjGcPX}0}#yB&)>-XgPGBJvmeVRP5^Vl2u1(^ diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/guardrail_events.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/guardrail_events.cpython-313.pyc index 02de7c73c8857ed95241698d6df1dd9b5503a786..a76205e29289e46b94db86f94fe5f38a7f244331 100644 GIT binary patch delta 101 zcmX@XKS_Z5GcPX}0}xc@w{7HBV)UM(pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&)_5c6? delta 27 hcmbOvaDt!vGcPX}0}#yB&)>+c#K`Eixq@*P8vtOE2F(Bf diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/ic_events.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/ic_events.cpython-313.pyc index 17816e5d674877eb95160d2265d2bf791fc78dd6..5c37f19a30d18ac4d442bd5c74d298302803ae24 100644 GIT binary patch delta 100 zcmdna(#XpFnU|M~0SKz|+ct7fV)X9S&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjCGG0p@4rwt@= delta 26 gcmZo<-Oj@OnU|M~0SM;m=Wpbm#K`D8`32)l09cO)M*si- diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/judge_events.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/judge_events.cpython-313.pyc index 1609099f13f7e55909b1c86f1cdaaa68b5a0c723..475de2228e6b48f86930892d022c302429492163 100644 GIT binary patch delta 101 zcmX@XHHn-1GcPX}0}xc@w{7GWVf3D$pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&0J8EUSO5S3 delta 27 hcmbQleS(YoGcPX}0}#yB&)>)`!pP{hIg3$)1pr;-1}^{r diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/langgraph_telemetry.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/langgraph_telemetry.cpython-313.pyc index f62149679a2001fd5fce26d6d944945b0d0a0d0e..908146455b600a7d30cfa6514917d86aaa1ca21e 100644 GIT binary patch delta 101 zcmZ3f_F0YlGcPX}0}xc_w{7IMXZD`1pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&*x&&=q%c`EZgegJM<2g(2d diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/llm_advisors.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/llm_advisors.cpython-313.pyc index 1ae15bfbb77a5e07ef71e23830bed97c499923e3..ead586ded083efc247578253d65390ec54bc2652 100644 GIT binary patch delta 101 zcmdll)+x^YnU|M~0SKz|+ct79V)UM%pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&Px# delta 27 hcmeAa-!I1fnU|M~0SM;m=Wpa*#K`Ej`3K`fP5@?g2fqLS diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/noc_contract.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/noc_contract.cpython-313.pyc index bf06b290a91cc031eadae050fa3d831ea959cba3..41a43934182ca4b074891ab6df22296c516178fe 100644 GIT binary patch delta 101 zcmbQC{z#qsGcPX}0}xc_w{7HhV)CA#pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&-H#Kh>fc?Of0AOLCR2NeJS 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 2b64d41c7e5bcbc333edb19a48671bc65ce5fd10..bb7269ab11b97895c3984243e508d186101f8b36 100644 GIT binary patch delta 101 zcmexvaL|zZGcPX}0}xc_w{7HJ$L!sspPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&+sj+xPEGYiXJ5dd@P2eSYG diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/observer.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/observer.cpython-313.pyc index f2a759b6ee633018afa8dce97edb714e44bfc9d9..2f400d171db8bdd7ccab0496c0a9e66f60d5c69e 100644 GIT binary patch delta 1136 zcmaKqO-vI}5P)~L+fo*`rGG#nrG-LB1GET22^K;rLLh*~Vj?kGOS>(tZCBqeAy!Ww zIQSF97ZSax2ek(i4R>O^a1>7_d-rUlQ6eYbyb2LQ+@xRTf97@OQ`fh4Q&|)RhJ1JB zwQPOuhN+QV+vv=;3el=2Cd(tSk!fS1#wI3OJ-|U6!yr?d^VMwZzSt`9>+EDvHy!a8 z`S4WOuW^~g!T~>jA>!9`1vydVr!LJBF^zIQoyI3K2~`smNli+r_(~3BHI7teHKQ(L z)exN39tH9RHINLCWPfLYE<6k9(;(2LR zMmJ+}A``&lTm*kGIQ5NWn8i?{pHYX08l!)Z51)`___hj;rg0LUuqcK*aBAdxJ0xG7xAw zMMcO$rL?3XBRJ?ZFo0HdYh@{yQI_d!$c61t!Clw6u-Ykl2M1OT$YXGDGSaf|4FVL5)wyN$H=8^~8AW!JB5UVG@k} zc-!ptK2zVTPZoC_p|9r9t}*n*9Qs{`2j1`Svv1gL{;l4RKbjg&jNuVU$O1Y`hz012SGndMbu3Ld2mbs&OfzHINCvim7yU(2rz~hZ7zC&r~&lmL%@M4 zukgBUGc@wc$mvJ+0Y4Z51P4na$t&p{oz|R=F@cNrF4l}++aL7xKo-4Q+GG|~S_v9! k#!y~PuH>Xq6eTK4eo7GEc68f#fvw+f8e&KG7y_E{2fPylVE_OC delta 1891 zcmbVMUr1YL6u;lSHzr<_d)1iKKW*chWH#2us?}8L%%WoFkTfyIbt_DwMvaR}_uVUH zWze#xc4e&cQN~~!eJBOr()m*8+g|D(1`!L6%NTpu9tL~aQdZiho%2P~hE*K9aDSZd zocn#}ch32J_cz~nC)AR|p$PDN-JM^N)pfO*++FWj2|E(jR$)b^j)Ws&O$I5} zwIP|3Zcx(#khx?kx{;!WemP?-ZxBKiYzT)@GdCB12p$v<}v$n3fgq9J@TQYnqM#Rx!k@Kt}Jz!XyjTAK_Z&SB7??69J{F-(#!ww`bzyZ<}bDB2PK~ zDWJ_SEB_GceZhcdLoQG%*XpZyafUHA+;D<4vXzEUBWE!w%8&91^G@@t!r5HF0N%Fp xPtrEDnqOGUribY)`0%f-Pq5b;yZkjGnITUUkqqyFLflVV&yXqdmw?F6_y?z!bF2UW diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/otel.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/otel.cpython-313.pyc index f3ae6deaffa8e3729fb166ef0e96ff37d804bbb3..78aa6dbb20335d30f392c98afcfb1f999ecf6c2c 100644 GIT binary patch delta 101 zcmbO!^;nAgGcPX}0}xc@w{7HJ#pd0ipPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&+sijC236MHfn0Ah{?+W-In diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/streaming_events.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/streaming_events.cpython-313.pyc index 33c3b7353f8e4d3b4100ab38158bfcd0df2cf888..f32b12eece4f4917699a88e1567ba6edbe507c6b 100644 GIT binary patch delta 101 zcmeysyNi$eGcPX}0}xc@w{7G$VDz4%pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&*xz{u#exs7oPD*$OX2TlM0 diff --git a/libs/agent_framework/src/agent_framework/observability/__pycache__/telemetry.cpython-313.pyc b/libs/agent_framework/src/agent_framework/observability/__pycache__/telemetry.cpython-313.pyc index e9cbe6ac29f1da38a5ce969c75954f6dd2ba31eb..b28731e5e915705a554792b222ec4a8b70f4266c 100644 GIT binary patch delta 4686 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 delta 3685 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 bSS%yjAqMg3YK4rbhZqX~ijtE^eu4f2vkjp} 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 760aea30e28ebfefe89a66a85d92f825a1d43c01..b684fe423ffaa5f22e40bad84bda051703902df7 100644 GIT binary patch delta 101 zcmccRw8WYFGcPX}0}xc@w{7G$-spa`a+41?wnfjZZI3*+i`P?Kz delta 27 hcmZ4De9MXZGcPX}0}#yB&)>*x#>wcixrb9i0swAy2N?hW 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 258d9ab4c3023261762ddfd4f533cd069fd5865e..693bcfca8fa00608d47e39c96484cfd89ecbc75b 100644 GIT binary patch delta 101 zcmX>uIZ=xHGcPX}0}xc_w{7J1W%Qn`pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&Hvj+t delta 27 hcmbOzbzGABGcPX}0}#yB&)>-H%gE@tc`;)iHvnWP2MquK 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 103017253a0bf0d4e62a75902e93c91cb297ccb4..23dbf2ff7b2d94d1120f9e45dd439beb59b86fca 100644 GIT binary patch delta 98 zcmbQq_?VIVGcPX}0}xc_w@u_W_HNS8%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP oNi2@f%}g&!Ov%?zOi#^&2|_t(MTxno<@rU~@%hP_`V;M=0B9N`f&c&j delta 24 ecmaFNIFph4GcPX}0}#yB&!5O`%xE#OGYSAsg$7sv 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 6e1dabf39a815831aab9f30b6f17b157e2f8a362..7cb6d9c66e0061b40efd9f51f1e647229cf0e3fb 100644 GIT binary patch delta 101 zcmew;v0IY+GcPX}0}xc_w{7IE<@B!8&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY sD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjYMIbSdV003$wRR910 delta 27 hcmdlj`B8%VGcPX}0}#yB&)>*h%gJc6`7-AVCID}<2rB>p 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 2fbd9dfe2a5fcee2a1bc30be2dacd041031604a9..297b8600384cf6b055fcb76904b544d53c6c1200 100644 GIT binary patch delta 98 zcmZ3;_?nUXGcPX}0}xc_w@u_W_U_Wp%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP oNi2@f%}g&!Ov%?zOi#^&2|_t(MTxno<@rU~@%hP_`V;Mw0C1usq5uE@ delta 24 ecmaFOxR8b>KSU)YZsJJ9P uIX|x?u{b_AGrcG=C0{==Jv9#|2<4;|CFZ7<=NDzi=O<_CZx&|qTMGbfuqEsO delta 29 jcmZ2|pXuQ}ChpI?yj%=GFjqf+BR4w}qs!)4Ccm`+k>&`( diff --git a/libs/agent_framework/src/agent_framework/persistence/__pycache__/sqlite_store.cpython-313.pyc b/libs/agent_framework/src/agent_framework/persistence/__pycache__/sqlite_store.cpython-313.pyc index e200c5cd30c3a9774991f930239d7ce533263fe1..04a15a1a1db590293a883e3f07dce77633e305a7 100644 GIT binary patch delta 100 zcmexRva6K)GcPX}0}xc_w{7H3Vf60P&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY qD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfi+h7%c%A+a(wP delta 26 gcmdm0`k{pTGcPX}0}#yB&)>+M!pP{dco(B30Ct=Q?f?J) diff --git a/libs/agent_framework/src/agent_framework/presentation/__init__.py b/libs/agent_framework/src/agent_framework/presentation/__init__.py new file mode 100644 index 0000000..a96f24f --- /dev/null +++ b/libs/agent_framework/src/agent_framework/presentation/__init__.py @@ -0,0 +1,15 @@ +from .renderers import ( + ToolResponseRenderer, + ToolResponseRendererRegistry, + register_tool_response_renderer, + render_tool_response, + tool_response_renderers, +) + +__all__ = [ + "ToolResponseRenderer", + "ToolResponseRendererRegistry", + "register_tool_response_renderer", + "render_tool_response", + "tool_response_renderers", +] 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 new file mode 100644 index 0000000000000000000000000000000000000000..3f10a11351d41aeb79502685a7a36dd1a158b389 GIT binary patch literal 470 zcmZutu};G<5Veyg0jf$26)Z?F(gptjVkZa$4f`o1Zsd~K)!7JDOe`$Sd<4Jbm5B{e zAyzJs4nS{sdhed!>CTJ6V1rTJnTKh~8GC8PvVx8*_K7^PjAi_Ur5t%0V339wrakPX z5k`AVkaxi`u7XkcN^{sK^21AG>anylqpciET}qVbcUE=BvQpOJ-0$KylL(H&fL)qM z7a#tx-?rag{o0<562HF8S`2A1?6nZJ5Vw#J_yi!YYk+6AAj$lrXtWchIL(gX9L-b~ z&Wedb>!2{&J10zhfy r01jqzzjoM|@}`zYIH29y&$U|wZz1RWGl+Tc!3f?r<9=|TV4tingtn8o literal 0 HcmV?d00001 diff --git a/libs/agent_framework/src/agent_framework/presentation/__pycache__/renderers.cpython-313.pyc b/libs/agent_framework/src/agent_framework/presentation/__pycache__/renderers.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..777eefb53c56f8dbdfa8967ddb68e4b7fa9fc621 GIT binary patch literal 4333 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 str | None: ... + + +class ToolResponseRendererRegistry: + """Thread-safe registry for application/domain response renderers. + + The framework stores only symbolic renderer names. Business-specific + formatting lives in the application that registers the renderer. + """ + + def __init__(self) -> None: + self._renderers: dict[str, ToolResponseRenderer] = {} + self._lock = RLock() + + def register( + self, + name: str, + renderer: ToolResponseRenderer, + *, + replace: bool = True, + ) -> None: + key = str(name or "").strip() + if not key: + raise ValueError("renderer name must not be empty") + if not callable(renderer): + raise TypeError("renderer must be callable") + with self._lock: + if not replace and key in self._renderers: + raise KeyError(f"renderer already registered: {key}") + self._renderers[key] = renderer + + def get(self, name: str | None) -> ToolResponseRenderer | None: + key = str(name or "").strip() + if not key: + return None + with self._lock: + return self._renderers.get(key) + + def render( + self, + name: str | None, + *, + tool_name: str, + result: dict[str, Any], + state: dict[str, Any], + agent_label: str, + ) -> str | None: + renderer = self.get(name) + if renderer is None: + return None + value = renderer( + tool_name=tool_name, + result=result, + state=state, + agent_label=agent_label, + ) + if value is None: + return None + text = str(value).strip() + return text or None + + +tool_response_renderers = ToolResponseRendererRegistry() + + +def register_tool_response_renderer( + name: str, + renderer: ToolResponseRenderer, + *, + replace: bool = True, +) -> None: + tool_response_renderers.register(name, renderer, replace=replace) + + +def render_tool_response( + name: str | None, + *, + tool_name: str, + result: dict[str, Any], + state: dict[str, Any], + agent_label: str, +) -> str | None: + return tool_response_renderers.render( + name, + tool_name=tool_name, + result=result, + state=state, + agent_label=agent_label, + ) 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 2f70874cd4d7c9fd3dd472cd3ca78d67cee385b8..5a34028961e3a2703433b2fef228f1cc731508e2 100644 GIT binary patch delta 100 zcmeBXy~@h{nU|M~0SKz|+ct7@GI=-Y=jN5@r|A0zd&UP8-spa`a+41?wnfjZ<8QDYt>whE^ delta 27 hcmZ3keOHV7GcPX}0}#yB&)>-H&B$oIc_Aa42morm2I>F+ 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 b056e8c6eacfc8bc6ea896bee3d038846b5cd691..6297b7f5a9a748d3b1582dde1715192125867ba6 100644 GIT binary patch delta 101 zcmaErxFw1EGcPX}0}xc_w{7GWWcF^*&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY sD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjY$na}D101Zne2LJ#7 delta 27 hcmdmz^eU12GcPX}0}#yB&)>)`$joTAIi2~eE&z7S2i*Vw diff --git a/libs/agent_framework/src/agent_framework/rag/__pycache__/rag_service.cpython-313.pyc b/libs/agent_framework/src/agent_framework/rag/__pycache__/rag_service.cpython-313.pyc index cb2b2befc10c58f079ffb9d8ea2f31713e44ea76..6899d3647f380299a66ebff2f79db9f3483fe124 100644 GIT binary patch delta 101 zcmZqoyXeRLnU|M~0SKz|+ct8$vUs=Z=jN5@r|A0zd&UP8 diff --git a/libs/agent_framework/src/agent_framework/repositories/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/repositories/__pycache__/__init__.cpython-313.pyc index ab5a21f735ed73e38bbaa4d39ee9416088f89cdd..a750b2a0e5d8afe453663bb9b6983cc72fd63fdf 100644 GIT binary patch delta 98 zcmZ3)_=b`DGcPX}0}xc_w@u_W_U_it%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP oNi2@f%}g&!Ov%?zOi#^&2|_t(MTxno<@rU~@%hP_`V;Mw0dcbW%8b?pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&)`%f#rtxtK{y9sq022I~L- diff --git a/libs/agent_framework/src/agent_framework/routing/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/routing/__pycache__/__init__.cpython-313.pyc index 17174f66bd4186bf3ba1bfe68c433fcb78d88114..525c7c7cb50e8bd9e348b68e106091bcadcd9ade 100644 GIT binary patch delta 99 zcmaFQw3C_pGcPX}0}xc_w@u{!>fNTFn^&TrqVF5*86QxTpOu-spa`a+41?wnfjZPnIsJXH_9a! delta 27 hcmX?>{wIz5GcPX}0}#y9&)>)$&ctZ9c`cKqApm{L2krm> 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 f636bad673aba8435070d4453e4cc9811bc77a79..dde408bc420aaf4a2a694cc6408775b77757a9fa 100644 GIT binary patch delta 101 zcmbP`e=DE+GcPX}0}xc_w{7I^;_&X*&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY sD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjZjas1K)05ZTPCjbBd delta 27 hcmcbWKOvv{GcPX}0}#y9&)>-1#lh&h`2oi-Jpg;f2>t*7 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 e6d1791ce454f23d8908c4a65a636098ed53ec9b..9e67e6f770621c842590aff0465074edb3585aa1 100644 GIT binary patch delta 101 zcmca2G*6iOGcPX}0}xc_w{7HBWA<**&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjZJn3dQ7#n>a6 delta 27 hcmbOyd_{=+GcPX}0}#y9&)>+c#>{B7xrSMZ4FF=G25)ocGn^&TrqVF5*86QxTpOumeFQ1Gh-$ISW*Ud 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 c5673e370726aacad845fa868676f23e9fa495a7..cac260cbaadc147d368b348f0550fe132b6f2efc 100644 GIT binary patch delta 57478 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 RJwi?1{XW5TRYfjW@L#S|!65(u delta 21937 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 dict[str, Any]: + """Remove valores herdados para campos cujo contrato diz ``from: message``. + + Em uma NOVA transação, ``context.tool_arguments`` pode ainda carregar + parâmetros de uma operação anterior. Campos declarados pelo mapper como + extraídos da mensagem corrente não podem nascer desse contexto antigo. + Valores explicitamente extraídos deterministicamente do turno atual são + preservados. Durante coleta incremental este helper não é usado. + """ + router = getattr(self, "tool_router", None) + if not router or not hasattr(router, "parameter_extract_rules"): + return dict(arguments or {}) + rules = router.parameter_extract_rules(tool_name) or {} + explicit = {str(name) for name in explicit_fields} + cleaned = dict(arguments or {}) + for field_name, rule in rules.items(): + if ( + str(rule.get("from") or "message").lower() == "message" + and str(field_name) not in explicit + ): + cleaned.pop(str(field_name), None) + return cleaned + async def _extract_mcp_parameters( self, tool_name: str, arguments: dict[str, Any], state: dict[str, Any], + *, + overwrite_from_message: bool = False, ) -> dict[str, Any]: """Executa regras ``extract`` declaradas para a tool escolhida. @@ -544,9 +591,13 @@ class AgentRuntimeMixin: llm = getattr(self, "llm", None) for field_name, rule in rules.items(): - if resolved.get(field_name) not in _EMPTY_VALUES: + from_message = str(rule.get("from") or "message").lower() == "message" + if not from_message: continue - if str(rule.get("from") or "message").lower() != "message": + # Em uma nova transação, a mensagem atual prevalece para campos + # declarados como ``from: message``. Durante COLLECTING_PARAMETERS + # o default permanece False para congelar valores já coletados. + if resolved.get(field_name) not in _EMPTY_VALUES and not overwrite_from_message: continue strategy = str(rule.get("strategy") or "llm").lower() value: Any = None @@ -1167,19 +1218,13 @@ class AgentRuntimeMixin: return None def _select_transactional_tool(self, tools: list[str], text: str) -> str | None: - """Seleciona a ação transacional da intent atual. - - O match por ``selection_keywords`` continua tendo precedência. Porém, depois - que o EnterpriseRouter já restringiu ``tools`` às capabilities da intent, - uma única tool transacional é uma escolha determinística e segura. Isso - evita perder frases naturais como ``quero cancelar TIM Fashion Mensal`` ou - ``não contratei esse serviço`` só porque elas não repetem literalmente uma - keyword de ``tools.yaml``. - """ matched = self._transactional_action_match(text, tools) if matched: return matched + # Generic fallback: once routing has constrained the allowlist, a single + # transactional capability is unambiguous even when the user's wording + # does not contain one of the tool-specific selection keywords. transactional = [ tool for tool in tools @@ -1348,12 +1393,112 @@ class AgentRuntimeMixin: state["transaction_status"] = "COMPLETED" if result.get("ok") else "FAILED" return result + @staticmethod + def _transaction_is_active(state: dict[str, Any]) -> bool: + return str(state.get("transaction_status") or "") in _ACTIVE_TRANSACTION_STATUSES + + @staticmethod + def _transaction_is_terminal(state: dict[str, Any]) -> bool: + return str(state.get("transaction_status") or "") in _TERMINAL_TRANSACTION_STATUSES + + def _active_transaction(self, state: dict[str, Any]) -> dict[str, Any] | None: + """Return only the operationally active transaction. + + Closed transactions are history and must never provide tool/arguments for + a later turn. For backward compatibility, an old checkpoint that has the + legacy selected/pending fields but an ACTIVE status is lazily hydrated into + ``active_transaction``. + """ + if not self._transaction_is_active(state): + return None + current = state.get("active_transaction") + if isinstance(current, dict) and current.get("tool_name"): + return current + legacy = state.get("pending_tool_call") or state.get("selected_tool_call") or {} + if not isinstance(legacy, dict) or not legacy.get("tool_name"): + return None + current = { + "transaction_id": str(uuid.uuid4()), + "tool_name": legacy.get("tool_name"), + "arguments": dict(legacy.get("arguments") or {}), + "status": state.get("transaction_status"), + "started_from_intent": state.get("intent"), + } + state["active_transaction"] = current + return current + + def _set_active_transaction( + self, + state: dict[str, Any], + *, + tool_name: str, + arguments: dict[str, Any], + status: str, + transaction_id: str | None = None, + ) -> 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()) + tx = { + "transaction_id": txid, + "tool_name": tool_name, + "arguments": dict(arguments or {}), + "status": status, + "started_from_intent": current.get("started_from_intent") or state.get("intent"), + } + state["active_transaction"] = tx + return tx + + def _finish_active_transaction(self, state: dict[str, Any], status: str) -> None: + """Close the active transaction without leaving operational state behind.""" + active = self._active_transaction(state) + if isinstance(active, dict): + state["last_transaction"] = { + **active, + "status": status, + } + state["active_transaction"] = None + state["selected_tool_call"] = {} + state["pending_tool_call"] = {} + state["missing_parameters"] = [] + state["confirmation_required"] = False + state["confirmation_received"] = status == "COMPLETED" + state["next_state"] = None + state["transaction_status"] = status + + def _normalize_transaction_lifecycle(self, state: dict[str, Any]) -> None: + """Ensure closed transactions cannot leak into a later user turn.""" + if self._transaction_is_terminal(state): + # Preserve a compact audit snapshot, but remove every operational latch. + active = state.get("active_transaction") + if not isinstance(active, dict): + legacy = state.get("pending_tool_call") or state.get("selected_tool_call") + if isinstance(legacy, dict) and legacy.get("tool_name"): + active = { + "transaction_id": str(uuid.uuid4()), + "tool_name": legacy.get("tool_name"), + "arguments": dict(legacy.get("arguments") or {}), + "status": state.get("transaction_status"), + "started_from_intent": state.get("intent"), + } + if isinstance(active, dict): + state["last_transaction"] = {**active, "status": state.get("transaction_status")} + state["active_transaction"] = None + state["selected_tool_call"] = {} + state["pending_tool_call"] = {} + state["missing_parameters"] = [] + state["confirmation_required"] = False + state["confirmation_received"] = False + state["next_state"] = None + return + if self._transaction_is_active(state): + self._active_transaction(state) + def transaction_state_patch(self, state: dict[str, Any]) -> dict[str, Any]: keys = ( "available_mcp_tools", "selected_tool_call", "pending_tool_call", "transaction_status", "confirmation_required", "confirmation_received", "tool_policy_result", "missing_parameters", "next_state", "pending_domain_workflow", "pending_tool_clarification", - "business_workflows_executed", + "business_workflows_executed", "active_transaction", "last_transaction", ) return {key: state.get(key) for key in keys if key in state} @@ -1411,6 +1556,9 @@ class AgentRuntimeMixin: "next_state": collecting_state, "tool_policy_result": {**policy, "tool_name": tool_name, "action": "collecting_parameters"}, }) + self._set_active_transaction( + state, tool_name=tool_name, arguments=arguments, status="COLLECTING_PARAMETERS" + ) def transaction_confirmation_message(self, state: dict[str, Any]) -> str | None: if state.get("transaction_status") != "AWAITING_CONFIRMATION": @@ -1446,6 +1594,185 @@ class AgentRuntimeMixin: matches.append(name) return matches or available_tools[:1] + @staticmethod + def _response_path_get(data: Any, path: str | None) -> Any: + """Resolve caminho simples ``a.b.c`` em dicts sem conhecer o domínio.""" + if not path: + return data + current = data + for part in str(path).split("."): + if isinstance(current, Mapping): + current = current.get(part) + else: + return None + return current + + @staticmethod + def _response_format_value(value: Any, formatter: str | None) -> Any: + """Formatadores genéricos permitidos pela política declarativa de resposta.""" + if formatter in (None, "", "raw"): + return value + if formatter == "decimal_2_comma": + try: + return f"{float(value):.2f}".replace(".", ",") + except (TypeError, ValueError): + return value + if formatter == "decimal_2": + try: + return f"{float(value):.2f}" + except (TypeError, ValueError): + return value + if formatter == "str": + return "" if value is None else str(value) + return value + + @classmethod + def _response_template(cls, template: str, data: Mapping[str, Any], formats: Mapping[str, Any] | None = None) -> str | None: + """Renderiza template somente se todos os placeholders existirem. + + Isso evita respostas como ``None`` quando o contrato da tool não corresponde + à configuração. Nesse caso o runtime cai no fallback legado/LLM. + """ + formats = formats or {} + names = set(re.findall(r"\{([A-Za-z_][A-Za-z0-9_]*)\}", str(template))) + values: dict[str, Any] = {} + for name in names: + if name not in data or data.get(name) is None: + return None + values[name] = cls._response_format_value(data.get(name), formats.get(name)) + try: + return str(template).format(**values) + except Exception: + return None + + def _render_declared_tool_response(self, tool_name: str | None, data: dict[str, Any], *, agent_label: str, state: dict[str, Any] | None = None) -> str | None: + """Renderiza resposta MCP por configuração, sem regras de negócio no core. + + A configuração vive em ``tools.yaml`` e suporta primitives genéricas: + ``template``, ``list`` e ``lines``. Se não houver política, retorna ``None`` + para preservar integralmente o comportamento legado. + """ + router = getattr(self, "tool_router", None) + registry = getattr(router, "registry", None) + cfg = registry.get_tool(str(tool_name)) if registry and tool_name else None + policy = dict(getattr(cfg, "response", None) or {}) if cfg else {} + if not policy: + return None + + mode = str(policy.get("mode") or "").strip().lower() + + # Extensão preferencial: o core conhece apenas um nome simbólico. + # O código do renderer é registrado pela aplicação/domínio. + if mode == "renderer": + renderer_name = str(policy.get("renderer") or "").strip() + if not renderer_name: + return None + try: + from agent_framework.presentation import render_tool_response + + return render_tool_response( + renderer_name, + tool_name=str(tool_name or ""), + result=data, + state=state or {}, + agent_label=agent_label, + ) + except Exception: + # Compatibilidade/fail-open: renderer ausente ou com erro não quebra + # agentes legados; o fluxo continua para o fallback existente. + return None + + # Modos declarativos da versão anterior são preservados apenas por + # compatibilidade. Novos projetos devem usar mode=renderer. + base: dict[str, Any] = {**data, "agent_label": agent_label, "result": data} + + if mode == "template": + template = policy.get("template") + if not template: + return None + # ``result`` pode ser usado para debug/compatibilidade; demais campos + # precisam existir para impedir None em texto de cliente. + if "{result}" in str(template): + try: + return str(template).replace("{result}", str(data)).replace("{agent_label}", agent_label) + except Exception: + return None + return self._response_template(str(template), base, policy.get("formats")) + + if mode == "list": + items = self._response_path_get(data, policy.get("source")) + if not isinstance(items, list) or not items: + return str(policy.get("empty_message") or "").strip() or None + rendered_items: list[str] = [] + item_template = str(policy.get("item_template") or "{item}") + item_formats = policy.get("item_formats") or {} + for raw in items: + if isinstance(raw, Mapping): + item_data = dict(raw) + else: + item_data = {"item": raw} + item_data["agent_label"] = agent_label + line = self._response_template(item_template, item_data, item_formats) + if line: + rendered_items.append(line) + if not rendered_items: + return None + count = len(rendered_items) + heading_template = policy.get("heading_singular") if count == 1 else policy.get("heading_plural") + heading = None + if heading_template: + heading = self._response_template( + str(heading_template), + {"agent_label": agent_label, "count": count}, + ) + sep = str(policy.get("separator") or "\n") + body = sep.join(rendered_items) + return f"{heading}\n{body}" if heading else body + + if mode == "lines": + lines: list[str] = [] + for spec in policy.get("lines") or []: + if not isinstance(spec, Mapping): + continue + kind = str(spec.get("kind") or "template") + if kind == "template": + when = spec.get("when_present") + if when and self._response_path_get(data, str(when)) is None: + continue + line = self._response_template(str(spec.get("template") or ""), base, spec.get("formats")) + if line: + lines.append(line) + elif kind == "list": + values = self._response_path_get(data, spec.get("source")) + if not isinstance(values, list) or not values: + continue + fields = list(spec.get("item_fields") or ["item"]) + rendered: list[str] = [] + for value in values: + if isinstance(value, Mapping): + chosen = next((value.get(f) for f in fields if value.get(f) not in _EMPTY_VALUES), None) + else: + chosen = value + if chosen not in _EMPTY_VALUES: + rendered.append(str(chosen)) + if rendered: + lines.append( + str(spec.get("prefix") or "") + + str(spec.get("separator") or "; ").join(rendered) + + str(spec.get("suffix") or "") + ) + if not lines: + return None + return str(policy.get("joiner") or " ").join(lines) + + if mode == "field": + value = self._response_path_get(data, policy.get("field")) + return str(value).strip() if value not in _EMPTY_VALUES else None + + if mode in {"llm", "none"}: + return None + return None + def build_direct_mcp_answer(self, state: dict[str, Any], mcp_results: list[dict[str, Any]], *, agent_label: str) -> str | None: """Resposta determinística para consultas estruturadas simples.""" requires_rag, _ = self._mcp_rag_directive(mcp_results) @@ -1475,6 +1802,14 @@ class AgentRuntimeMixin: return None tool = ok[0].get("tool_name") data = ok[0]["result"] + + # Primeiro tenta o contrato genérico e declarativo de apresentação. + # Se a aplicação não o configurou, preserva exatamente o fallback legado + # abaixo para não quebrar projetos existentes. + declared = self._render_declared_tool_response(tool, data, agent_label=agent_label, state=state) + if declared is not None: + return declared + if tool == "consultar_pedido": oid=data.get("order_id"); status=data.get("status"); total=data.get("valor_total") lines=[f"[{agent_label}] Pedido {oid}: status {status}."] @@ -1509,6 +1844,7 @@ class AgentRuntimeMixin: available_tools = list(tools if tools is not None else (state.get("mcp_tools") or [])) state["available_mcp_tools"] = available_tools text = state.get("sanitized_input") or state.get("user_text") or "" + self._normalize_transaction_lifecycle(state) # Clarificação de resultado de tool tem precedência: reutiliza a mesma tool # e argumentos, alterando apenas o parâmetro escolhido pelo usuário. @@ -1524,7 +1860,7 @@ class AgentRuntimeMixin: # Antes de confirmar, complete os parâmetros obrigatórios da ação. if state.get("transaction_status") == "COLLECTING_PARAMETERS": - selected = dict(state.get("selected_tool_call") or {}) + selected = dict(self._active_transaction(state) or state.get("selected_tool_call") or {}) tool_name = selected.get("tool_name") if tool_name: previous_args = dict(selected.get("arguments") or {}) @@ -1535,14 +1871,20 @@ class AgentRuntimeMixin: aliases=aliases, extra_args=self._extract_action_arguments(text), ) - arguments = { - **previous_args, - **{k: v for k, v in new_args.items() if v not in (None, "", [], {})}, - } - # Execute parameter extraction before deciding whether the workflow - # must enter COLLECTING_PARAMETERS. Otherwise parameters declared - # with strategy=llm in mcp_parameter_mapping.yaml are invisible to - # the deterministic transaction state machine. + # Durante coleta incremental, valores de contexto podem ainda conter + # parâmetros de uma operação anterior. O que já foi coletado para a + # transação pendente prevalece; o turno atual só preenche lacunas. + non_empty_new = {k: v for k, v in new_args.items() if v not in (None, "", [], {})} + arguments = {**non_empty_new, **previous_args} + + # Campos de envelope pertencem ao turno corrente e devem permanecer + # atualizados, mesmo quando os parâmetros de negócio ficam congelados. + for per_turn_key in ("query", "operator_instructions", "interaction_key"): + if non_empty_new.get(per_turn_key) not in (None, "", [], {}): + arguments[per_turn_key] = non_empty_new[per_turn_key] + + # Reutiliza o contrato declarativo para preencher somente os campos + # ainda faltantes; campos previamente coletados não são sobrescritos. arguments = await self._extract_mcp_parameters(tool_name, arguments, state) policy = self._resolve_tool_execution_policy(tool_name, arguments) missing = self._missing_required_arguments(policy, arguments) @@ -1562,6 +1904,9 @@ class AgentRuntimeMixin: selected = {"tool_name": tool_name, "arguments": arguments} state["selected_tool_call"] = selected + self._set_active_transaction( + state, tool_name=tool_name, arguments=arguments, status="COLLECTING_PARAMETERS" + ) state["missing_parameters"] = [] if policy.get("require_confirmation"): waiting_state = self._waiting_state_name(state) @@ -1573,6 +1918,9 @@ class AgentRuntimeMixin: "next_state": waiting_state, "tool_policy_result": {**policy, "tool_name": tool_name}, }) + self._set_active_transaction( + state, tool_name=tool_name, arguments=arguments, status="AWAITING_CONFIRMATION" + ) return [{ "ok": True, "executed": False, @@ -1586,27 +1934,29 @@ class AgentRuntimeMixin: result = await self._call_mcp_tool(tool_name, arguments, state) self._capture_pending_domain_workflow(state, result) self._capture_pending_tool_clarification(state, result, tool_name=tool_name, arguments=arguments) - state.update({ - "transaction_status": ("WORKFLOW_PAUSED" if state.get("pending_domain_workflow") else ("TOOL_RESULT_CLARIFICATION" if state.get("pending_tool_clarification") else ("COMPLETED" if result.get("ok") else "FAILED"))), - "confirmation_required": False, - "confirmation_received": True, - "pending_tool_call": {}, - "missing_parameters": [], - }) + final_status = ("WORKFLOW_PAUSED" if state.get("pending_domain_workflow") else ("TOOL_RESULT_CLARIFICATION" if state.get("pending_tool_clarification") else ("COMPLETED" if result.get("ok") else "FAILED"))) + if final_status in _TERMINAL_TRANSACTION_STATUSES: + self._finish_active_transaction(state, final_status) + else: + state.update({ + "transaction_status": final_status, + "confirmation_required": False, + "confirmation_received": True, + "pending_tool_call": {}, + "missing_parameters": [], + }) + self._set_active_transaction( + state, tool_name=tool_name, arguments=arguments, status=final_status + ) return [result] - pending = state.get("pending_tool_call") or {} + active_tx = self._active_transaction(state) + pending = (active_tx if isinstance(active_tx, dict) and active_tx.get("status") == "AWAITING_CONFIRMATION" else state.get("pending_tool_call")) or {} if pending: decision = self._confirmation_decision(text) if decision == "reject": - state.update({ - "transaction_status": "CANCELLED", - "confirmation_received": False, - "confirmation_required": False, - "selected_tool_call": pending, - "pending_tool_call": {}, - "tool_policy_result": {"action": "cancelled", "tool_name": pending.get("tool_name")}, - }) + state["tool_policy_result"] = {"action": "cancelled", "tool_name": pending.get("tool_name")} + self._finish_active_transaction(state, "CANCELLED") return [{"ok": True, "tool_name": pending.get("tool_name"), "transaction_status": "CANCELLED", "cancelled": True}] if decision == "confirm": tool_name = pending.get("tool_name") @@ -1616,17 +1966,26 @@ class AgentRuntimeMixin: result = await self._call_mcp_tool(tool_name, arguments, state) self._capture_pending_domain_workflow(state, result) self._capture_pending_tool_clarification(state, result, tool_name=tool_name, arguments=arguments) - state.update({ - "transaction_status": ("WORKFLOW_PAUSED" if state.get("pending_domain_workflow") else ("TOOL_RESULT_CLARIFICATION" if state.get("pending_tool_clarification") else ("COMPLETED" if result.get("ok") else "FAILED"))), - "confirmation_required": False, - "selected_tool_call": pending, - "pending_tool_call": {}, - "tool_policy_result": {"action": "executed_after_confirmation", "tool_name": tool_name}, - }) + final_status = ("WORKFLOW_PAUSED" if state.get("pending_domain_workflow") else ("TOOL_RESULT_CLARIFICATION" if state.get("pending_tool_clarification") else ("COMPLETED" if result.get("ok") else "FAILED"))) + state["tool_policy_result"] = {"action": "executed_after_confirmation", "tool_name": tool_name} + if final_status in _TERMINAL_TRANSACTION_STATUSES: + self._finish_active_transaction(state, final_status) + else: + state.update({ + "transaction_status": final_status, + "confirmation_required": False, + "pending_tool_call": {}, + }) + self._set_active_transaction( + state, tool_name=tool_name, arguments=arguments, status=final_status + ) results.append(result) return results state["transaction_status"] = "AWAITING_CONFIRMATION" state["confirmation_required"] = True + self._set_active_transaction( + state, tool_name=str(pending.get("tool_name") or ""), arguments=dict(pending.get("arguments") or {}), status="AWAITING_CONFIRMATION" + ) return [{"ok": False, "tool_name": pending.get("tool_name"), "awaiting_confirmation": True, "transaction_status": "AWAITING_CONFIRMATION"}] read_only_tools = [ @@ -1669,19 +2028,30 @@ class AgentRuntimeMixin: if not selected_action: return results + explicit_action_args = self._extract_action_arguments(text) action_args = self.build_tool_arguments( state, tool_name=selected_action, intent=state.get("intent"), aliases=aliases, - extra_args=self._extract_action_arguments(text), + extra_args=explicit_action_args, + ) + # Nova transação: parâmetros declarados ``from: message`` não podem ser + # herdados de context.tool_arguments de uma operação anterior. + action_args = self._drop_stale_message_extracted_arguments( + selected_action, action_args, explicit_fields=explicit_action_args.keys() + ) + # A mensagem atual é a fonte de verdade para esses campos no primeiro + # turno transacional. + action_args = await self._extract_mcp_parameters( + selected_action, action_args, state, overwrite_from_message=True ) - # Extract parameters (including LLM-declared extraction rules) before - # validating required fields and before persisting the pending call. - action_args = await self._extract_mcp_parameters(selected_action, action_args, state) policy = self._resolve_tool_execution_policy(selected_action, action_args) selected = {"tool_name": selected_action, "arguments": action_args} state["selected_tool_call"] = selected + self._set_active_transaction( + state, tool_name=selected_action, arguments=action_args, status="COLLECTING_PARAMETERS" + ) state["tool_policy_result"] = {**policy, "tool_name": selected_action} missing = self._missing_required_arguments(policy, action_args) @@ -1718,6 +2088,9 @@ class AgentRuntimeMixin: "confirmation_required": True, "confirmation_received": False, }) + self._set_active_transaction( + state, tool_name=selected_action, arguments=action_args, status="AWAITING_CONFIRMATION" + ) state["next_state"] = self._waiting_state_name(state) if emit_events: await self._emit_ic("IC.TRANSACTION_CONFIRMATION_REQUIRED", state, {"tool_name": selected_action, **policy}, component="agent_runtime.tool_policy") @@ -1727,12 +2100,19 @@ class AgentRuntimeMixin: action_args["confirmed"] = True result = await self._call_mcp_tool(selected_action, action_args, state) self._capture_pending_domain_workflow(state, result) - state.update({ - "transaction_status": ("WORKFLOW_PAUSED" if state.get("pending_domain_workflow") else ("TOOL_RESULT_CLARIFICATION" if state.get("pending_tool_clarification") else ("COMPLETED" if result.get("ok") else "FAILED"))), - "confirmation_required": False, - "confirmation_received": True, - "pending_tool_call": {}, - }) + final_status = ("WORKFLOW_PAUSED" if state.get("pending_domain_workflow") else ("TOOL_RESULT_CLARIFICATION" if state.get("pending_tool_clarification") else ("COMPLETED" if result.get("ok") else "FAILED"))) + if final_status in _TERMINAL_TRANSACTION_STATUSES: + self._finish_active_transaction(state, final_status) + else: + state.update({ + "transaction_status": final_status, + "confirmation_required": False, + "confirmation_received": True, + "pending_tool_call": {}, + }) + self._set_active_transaction( + state, tool_name=selected_action, arguments=action_args, status=final_status + ) results.append(result) return results diff --git a/libs/agent_framework/src/agent_framework/sse/__pycache__/__init__.cpython-313.pyc b/libs/agent_framework/src/agent_framework/sse/__pycache__/__init__.cpython-313.pyc index 2e67dadce1b136371f7efc6d04908a8fbec46d0f..f70e36607bd1c2cea7b38775d3302f342d826a13 100644 GIT binary patch delta 98 zcmbQq_?VIVGcPX}0}xc_w@u_W_HNS8%`4GQ(f1AZj1MTv&q_@$Db`QREGjOEPtMOP oNi2@f%}g&!Ov%?zOi#^&2|_t(MTxno<@rU~@%hP_`V;M=0B9N`f&c&j delta 24 ecmaFNIFph4GcPX}0}#yB&!5O`%xE#OGYSAsg$7sv 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 fed8b2283253a16cefc1aa0ecdb3045e19013448..a97b0b6ea68aa82e41c3835d66e0d7e7a00cfbc0 100644 GIT binary patch delta 101 zcmdn#)$GmvnU|M~0SKz|+ct84XZCK;&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY rD@iPl&&^CPN=(VuPfSnEg9$=8X+?>-spa`a+41?wnfjZVS-spa`a+41?wnfjY&G1u?`0Q$Bh`2YX_ delta 27 hcmaE$GEIg1GcPX}0}#y9&)>-1$IR%s`3Z9k9{_D22hacj 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 536364c24b748c267a0cecfdbcf67769d597ca23..2ea80425a222f77c000ebd2f870285036e791122 100644 GIT binary patch literal 894 zcmaKq&yUhT6vwA6w1uS$>YwvyV65b%eetBVW?a)@CI? zpOKGz%|loN4eOv|1B^4J>0SXBp@>Z|u>}^k!Nw&h;WCsnzu_I=3RJKI4nBm#Oe=U* zT!UJ+FM4%+1V`E4^p5cfoSY#S`PNGfPG@$r^h1;7n}#qty|yU&!`5IZj=K=d>5{=a zp9h>ihhXuxX^NwfRHhMIw&^sCLmskNRC28|nNe}Nw^j=}=5%ryFH-&|sK+K$IC;=@ zkS0{rb90c!1Dd1}m)$&Qce<@tS3@%D54`SGe?(f(hL`=GFB*AxYpfa=&{>#pSc~d% z*Bl8lM^h7xZWz%#d_Wg02|0tc^i=n18uM^YrF4=@L&l=cijGqm+pI!C9uF7_MFmsA zQm_?D3hIvGK*3R{C>$zO6>17~iC(iIiZgYV+k9DOl~kB>c`i}%|K!4k-K^URSuIsY zlwm(xR#I579V@FX94;p!bT?Agim(U?qKJ?$Xd^Qq@yVUX+?}{D{7Z5T>_%Q*;!ZEr>r&?PZ&f`nUW zaT{$;kv2`;iXHBv%Na86p;y)HxW;|-tC+@h9$-+#P8{+EHkuGY*F7b;HDYb=gXk4) zx_D^?L0{t4FqiX=94uSp@zzIMi%1O|1J}SaU-?+tou=)XdL1xG75SV8nfY2CVG IxTCv%0pV<1S^xk5 diff --git a/libs/agent_framework/src/agent_framework/workflows/__pycache__/graph.cpython-313.pyc b/libs/agent_framework/src/agent_framework/workflows/__pycache__/graph.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca8c8f0fb32871def1d86afda73deb89c45cc12e GIT binary patch literal 1431 zcmZuxL2n#26t>4Zvzu+g1~w!ppw^^-voI6d{cw9C;gf-P0a*KG`7aHC+S0rv1p*!Bc1nMZqG9 z>X*Fgw66CWohiP65qg))-rJhzecI(QPXtvXDH6JSNO@04%etBm#7OD=j}Gya;O&`H{DX_Fy~_(SEPi35xdGDd`C6h;kP9 zTW~U-;FO>~SlGnlq{KX54IQmx34`9QEun23;%)DJ{Ce;T+9p@=Yxp_zEV?m~3qp0o zA4f>~Hyl#AB611l@7A_2ya;lueiwJqo8$uO;!bT-I|A_1%}2zB8?bdYIVz98frc7; z{B=2Hp7BJzF>wWjfh8h`{v6+yaq1#fiR$IEIdw?UI)kf(pwB^xqJ3Q@!%S={yQYRR zxu&(!&@2*XrkIBATfq#BY`}{e*F94N`y=;X9VX(F*aQGW%T;_H4x|l}@OtzPdrzx9 zP?-t4sWz6y3Y28nAO#U7Dy%eLZBBwSu1v*gn5Dbs--*!Z_&*h>Hit|@+3J6w9OirBXr{VQwu*&zxtqwW*5JF=}v3q+qoZGE8oxm&|10ESo!n! zDKvX=jL6i&Pft95clM((@!F5wYtNtf-ps<^Cj=6I8He{-Fo(WqhUBa17s+iuB;TRU zPN1E}w9|)n&r}{rr1GHG4PXS<3HUY{8kD;C|M9co~t z;j4&>z#issSxe@HA8oCEuvL(2n^!AjSFJ*F)r!WI>J{G7OAtEYn-{>G5RCBy&&Rbt drV+mQE1JL8Xdn4^gVqsw7&P$Z-w>D*=O5)ynCk!l literal 0 HcmV?d00001 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 08349f9a1c0789bcf9a36251ec937af44423493e..7cd96e200102a62e0dbadb5fbbb3283d427c5bc6 100644 GIT binary patch delta 2531 zcmaJ?O>7fK6rPD^*Xw^L*!d$Q#tAW|lt2m4P$2v?g%Dz*EGeyUWK6tCojAMJ>>7w$ zDV8b$Ri%<>F7#A-q*A4-?IB21^hi&2WEH}yRgWk)s-%bZ)Oq7rqEXtB{mpxCX5P+x z@6DU<+e&f&n$PD(ynSfgn$Ecw{muB%Vr+4LGm0YB+lo|QQa2?$ZYu==?*@QO7s z6^z#}KDx%PNG?3W?m9ZyS?upmI#sz3Q$=+qWmSps^{R`yR5#Z=Li1AhlrQeL!H1yhc-|MYDNOVa+RQ)jn>!bc4>O zbJ?Qy043ts!}isU_-q27qamQ6kuB71KiR~^HU3BTt)5xk>dEvBtAnW#YE1J3m_3tO zYFeoYL$}gqYBoDX(;1^DJ*DY2BYRSJ^}uU<{cZF-5W0_-1JTl%JKHKG`aH7ho6K_L ztx{rPutMHiIhQC6mIDJ%NrHB;yd&)1hy`9tviqL!JSD0lDXBy-Dp6ULx#kp_LY=CM zYwnFPMfGsayP>&wWF^%vv;dEU6c5_IS|mo&1yft~@eN+G$u+~s*-lMQU(0Ek#NXje zcEY;C`PdsdrL!3lm@g__`;3CcgGPhEiHB-df$FJAYRnefYCiuJ-N;9g1P_eu*EV9F z%0kfpc5}bAG494J%xc071;*nZ+RQuJ0?-Pu9bkSJU>g9OhVBN40|3Lc9RQZo4uA+i zv<7fQ^Du|oXeHEKI(z3*g*2~3yGw7E-5nLuz0$O^G_=42vvcL(ky4@@+Fv0@R@$T7 z*!q-2g-c1eWA(TZmo~Eh(tsM|d0sErZJ^$%Kzy6+tuc`>GTLewwg8`}egHvST{dIO zJjJtyP8+zDt>TmOiDIa>P=uvMkCcZXRf+L!NsI!HdjJGE`?+Kjh#q|djBf(;0c=Il z>oCB3B-ItAxVDiN*Rb`^@n%-oYBk&^+yi#c=r53`j>f z*h-#e4Vty){%^}pnCYG61m)oVO!B)UPH_s{h*O*aNyK>oq^-8@J_aKIJJ?_3f-K^G zj15VTq9Ro`u}<{#tQN=g5Ue`F;JS=kL}=?->O_kY2rAcy%IWx*ZtgtVX zq4w>sT+c{W*KYC}$t#=|(PksXI`%?2bIe1Bxi67|wj-zMw!_pc+x;$7>H$g(N-w~; z$U$*e6QGJ%pJ7SYJ{)16x(++{a;te5vnQ_W?-lPBKPleJd@=p`^t1L}{#$PET?##J zec1Y}@8WXb#q#CkFMY{h8zbe;6HC_P8xLsv$&DL8ygRA z>bgcvUUZ7PS>D@7Mox{XtmJK)hZ;l=aIocSeYYjkN?Tf@dch%X#gKT4Uwsqi#>Z{R zqUi~Z?t!(E2BEfnqDy5oE1k`m)glnsvTg}ZImN?>9)%rD0!#sjOxXd_2LM@sX@ITR zz6t{X{rqp{Sj5*tdMl)t9rtyd?2JJbi&RMLc{H{}mZQf-RjZKWE6r`CfjdVlr0scE ze5q@>tG_h7aN;THuSN(QCgMRxeP`#zGXnKb6dMs)@xe{cjjbHx6|IodPEegshFfWl zb9m{%82^T%FHpzt=yV00UY8yCBEC1cj-X%nO1N`@E4*6|N;tOA2XYMLW{{)2Uk^6n X(7l#*#JlxgH$I8)x&B1Zi|zgczNJ~a delta 1077 zcmZvaO-vI(6vubk-R%dv%eJM3+Lj_HP!cFHLFFR`if9PX7?2nf6>Ga~s-=swTM#sX z#DgXtqGJ16RR<&oHN_z%@nIV1|#b@8>Wb!BXxeTGVOLT%}k(A=6e&#Sv|YlL!}sB`vaMN())NoG%ur z8`pag?T93zA8`h83V{U=AJU0Y_Yo9$@17Rz7j{F$^S0gYQO2}_P#G+~oLSTogobe? z0zW-k1FG#rwH=O~qPLL{393?zHTFvC5}fn=tO9#d2T|d-)DgrY|BX2w;!?99u$?N~ z*#?FjAR;`Gr=TW}x;=D=9iToKR!*pc7!D)s9+RLeeWVj!Dra5Tmhp*$J!Kho8gHo0 zTw~G@*y8ix_y|v95LdhAk5kc>>>Sp#B|DFieUAsDNyKrw4PXKhf*0y^lO#0NoSfKE zbFk=8-T|g!m^^@>uM(S6skb0A5BiQgI9n;tY6f%LelL9Wb+*{QT}98JLl>4cYA{!> zwL;t!u|dX2z@-G=R4U87xt+m`fGY5-_8s*Sv;F+a9&0^|EFO8l^ft zv{1vb7P4Em73jcmdBjoQk-rTygBb+=0wV>{K$!3O$oIftARcOoZcIEK+U28% z65zIULV>No<%hP>Y}M=v|Ju-Uk1!usO4ro9b#4Y1#_cIX2b%TqL&TIpEl2zvB;>4e*u# 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 2a96f3a262cc226190ee320226465aadef1e224c..20e524d19e2fc27c2970118e057583ce2757bd08 100644 GIT binary patch delta 80 zcmZ1`bW(`>GcPX}0}xc_w{7G;#c0-{pPN^rpQ7&@>=_?Wl%JKFTvDu`mRVF>5}%x( cSCUv9pPQLpl$esQpO~JS2NT@pv`mQmGcPX}0}!0=F4)L@icvUKKR2&LKP9mwQ9m)QJia`?D0?$ElN~z%M2!ww diff --git a/libs/agent_framework/src/agent_framework/workflows/__pycache__/repository.cpython-313.pyc b/libs/agent_framework/src/agent_framework/workflows/__pycache__/repository.cpython-313.pyc index 60b2dd28df51b3429ac5405e01b2af8dbc2289d7..accb9fd35a9f2f76a251df6a80649dc8f87ec1d6 100644 GIT binary patch delta 80 zcmZn{T_wu>nU|M~0SKz|+ct9FWHjs2&&?~*Pto@c_KXiG%FjwoE-BVe%PcA`iBHbY cD@iPl&&^CPN=(VuPfSnEg9&c_&NzVs05U!t{r~^~ delta 45 zcmZ1_+AhldnU|M~0SL}_7i{Fd$tawzpPN^rpORRTsGpct9$%hcl)YJsX#xiTJ&g{P diff --git a/libs/agent_framework/src/agent_framework/workflows/__pycache__/runtime.cpython-313.pyc b/libs/agent_framework/src/agent_framework/workflows/__pycache__/runtime.cpython-313.pyc index 206eb3eaa011834f54a803f38bdd8b9a532fc949..353244b873ec1ed03939e5c8d42f135b52550602 100644 GIT binary patch literal 29143 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 z z(cFBne?EBRV(pPr!*AELpM!v(x;SYpOd3T(X6c}Gg^*EcT!Pw8X}9zVe)dY2OCM;Q zkPb?7A7M375~fi#C8Z^39F-1ZjY-F_N9`Gr~>>;stkNs5eWRH$Afqz+yFzsh6>&d zypW%`4qi3|vT$CQxXOP1z zA)@1iD{bV+cAeKKC!{ARRVsJ@d z>4T8U%vkJ6BCb!RcX|&hBUuA~CT4^0kU!Y=7Tsj+`o(1{7DMfqJ#J;gd$lWz3Ve$W zQoXw9M9xJ5t;GuD+@!X-h+1<+FL8N4t_1c<(!0s@oLOQh|6;=M!~E|EI;{Ttc%F1hs*>As>mXw{WEI}KJ{sddvW P^poZ&rRW~<5!U|?=$=_?Wl%JKFTvDu`mRVF>5}%x( sSCUv9pPQLpl$esQpO~JS2NQ&H(uxvuQ_J&Ad2 diff --git a/libs/agent_framework/src/agent_framework/workflows/runtime.py b/libs/agent_framework/src/agent_framework/workflows/runtime.py index bc8a1b6..f818233 100644 --- a/libs/agent_framework/src/agent_framework/workflows/runtime.py +++ b/libs/agent_framework/src/agent_framework/workflows/runtime.py @@ -434,15 +434,11 @@ class WorkflowRuntime: "current_node": None, } config = {"configurable": {"thread_id": eid}} - # Explicit offline-regression mode. When enabled, always use the - # deterministic backend, regardless of whether LangGraph happens to be - # installed in the current environment. This keeps regression results - # reproducible across developer machines and CI while production - # (the default) continues to require/use LangGraph. if self.allow_deterministic_fallback: - return await self._run_fallback( - definition, initial, start_node=definition.start, execution_id=eid - ) + try: + import langgraph # noqa: F401 + except ModuleNotFoundError: + return await self._run_fallback(definition, initial, start_node=definition.start, execution_id=eid) try: graph = self._compile(definition) state = await graph.ainvoke(initial, config=config) @@ -503,9 +499,10 @@ class WorkflowRuntime: definition = self.repository.get_version(name, version) if version else self.repository.get_active(name) config = {"configurable": {"thread_id": execution_id}} if self.allow_deterministic_fallback: - return await self._resume_fallback( - name, execution_id, resume_value, version=version - ) + try: + import langgraph # noqa: F401 + except ModuleNotFoundError: + return await self._resume_fallback(name, execution_id, resume_value, version=version) try: from langgraph.types import Command except ModuleNotFoundError as exc: diff --git a/templates/agent_template_backend/app/agents/runtime.py b/templates/agent_template_backend/app/agents/runtime.py index e6429c4..7a1a9be 100644 --- a/templates/agent_template_backend/app/agents/runtime.py +++ b/templates/agent_template_backend/app/agents/runtime.py @@ -3,5 +3,8 @@ from __future__ import annotations # Compatibilidade local do template/backend. # A implementação oficial agora fica no framework para evitar duplicação entre agentes. from agent_framework.runtime import AgentRuntimeMixin, MessageBuilder, RuntimeContext +from app.presentation import register_tool_renderers + +register_tool_renderers() __all__ = ["AgentRuntimeMixin", "MessageBuilder", "RuntimeContext"] diff --git a/templates/agent_template_backend/app/presentation/__init__.py b/templates/agent_template_backend/app/presentation/__init__.py new file mode 100644 index 0000000..c0eba0d --- /dev/null +++ b/templates/agent_template_backend/app/presentation/__init__.py @@ -0,0 +1,3 @@ +from .tool_renderers import register_tool_renderers + +__all__ = ["register_tool_renderers"] diff --git a/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc b/templates/agent_template_backend/app/presentation/__pycache__/tool_renderers.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32e74b958bd684add894a70a4d279c35cf81b204 GIT binary patch literal 4366 zcmb_fO>7&-6`tkpa+m-5qfGr&TG^6qy0T%~mlX5G!(}(x!HW z*_CXuO`!%sYau8kqcy?+1)?GWssKHxr|Qr{3Ll!|GE^#Js{%ob9CCAEw`gN6;tU~=2Xp0rgY6zj3me^&ZPF;vNV*ur{lY2ty!$h ztE8ROQ<;8Kori@@)hPE?+Q}Iubr;;(uPiL|FMx+(0eTGmWtTgiHu@HpZEtd3*VN_Y z49?;@FinJ?aRsUs^u)#Tt$Pi}^8C+x^M+M_VmH)V2=#8tTPKR43zm4{Uwi)WFLIXe z_*2AyW~gC(=$+iBV#^a2nqL`ynB}eZPV|1;2>W|xgiS%47IF?e{OHLxfdIH<;%pG` z7-yhn2l#FT-nN-UE<7z=Q_MxINZ=u3F>5MmWmv)jjQR+4Y!BU%25zz4uv1X5c>{K< z0{p0Bv&xK`HOP_@6dVG9_$tEE2y?OR~Bs(T~#Ok0jfd(SQgv)lAOK*lu!ci$;!v6OnSP zbp6$w;CzyDu3qQJqpZ!&siy4)WCOr$?v9?(q9P_B!mw$Cn@M$yRBcd!1qwC|+)h4x z4Jw1+n*f0n2Mmpez(CBy$3d-;=s$!Ckl=4vn^>J#zgP5ku8frg|Bv4+g&Iqty7jj8 zKt8z{-@I-G1}*;(bT&lZJ@fEPe!AH3^_9s|pmFW?>g~K(40NqrD+vt+p`#=Q*8Hpf zbu&MiAK7HBaPN+Iwj=}!LQAFVUVbV6eJgxwM?78fh1M>uURsYAeQo(v!PjMRUAP6T zIsid(ALw=32EzNFAXpou)q@5oax*YvoG(L_rBDUv0(|&554C$h0LUH%NTC85O#py( zz)bF%fD{u|IK``D=b53Y1qGn`jIBW&yyg2p(QRR$kEeM2?~`l z%G+R_*oek|gplTaZj3iU11lNy!kAZKjJM`R_tvl~N~}6U-&aGw{=ew^EBc!6bywW0 z`Qkn~@CpzL+53$&*yX9^=|sTUJ@i*stjr{#8!HI;h>f1AS5AUv?K2C?p_}ABA1d+c zc@PSa-K5@ML9VMg#$C|>%BYXoqK+XANM_RXx>D-Md8VcBsOd~vmvWwAsmuv91lT?Z zsyay}OeLGEgP^Npi8h9%o86MlXG~QyY)@J>QV>=Z-R3kMLIrEwU5vV7Hp&U#A{xU$ zF|SBABLSBHR1xkZ6^VzoH)CWpSW|-l&t)NVvAJ|6Wn$t@EI}3Z*QB3r(oZPI=Cc`1 zHEf>RMNOJF>|i(dU@!jg9*oceXs+C$}RX*IR+tEdNzturk@bS@ic% zvMUIYGBH`lPW{HaHB>x($vQQ>-DQO@?}#H6eL{}A{+^AOV32ftCAKHjulM}2X;a%Ze35IuIIzlX3qzA{#1AV?*SBU{bvw~%@y{1 zW25QUEx&5n94&SY7sA8aav}W99q~%Z7hJozdU1X1oo`rN>x&!;sk6hOe+A+H#G$o$ ztIBLgvgdxl7ZSk2P9e$o)Y#PAAlHb7%HJxtr+RAv2#{E~DO(GatwqY#9vb+)B%I5> z0Uz8pe+(0l+CdX58f4)Zaw{Dxb||H%GjncZQo#P@xdcBOkjh4_O9tZ}gln~4udYOe>nu%c&U!yMD)pyQjmJHx7 zR0+wR%OnrJzko;WXgNBUVV_pBnI#o3_g&8FDJ5%+_El9!VFH6B0$;*Su)LF>c1+~! z*SViv0^#2@0eq{jfpHk6X<8a{wju$mER@Nmepou_3MuD<#G~v6X^|wfy^`aM#~V}z zM^llvL3s4si%n({>Q zBCMe%lbGCb+ifl{WVAVF{dVVdReg~5J^#*h+(p7?O`j289Cn;|d0tO1X4O$V0lfqh z##yKUXbkfgbo>j{`~@0+=H{5zXF-N}<(cSXjz4P;Gi}e#c^UUVS~=!*hPvrLZU>y2 literal 0 HcmV?d00001 diff --git a/templates/agent_template_backend/app/presentation/tool_renderers.py b/templates/agent_template_backend/app/presentation/tool_renderers.py new file mode 100644 index 0000000..f77c47a --- /dev/null +++ b/templates/agent_template_backend/app/presentation/tool_renderers.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from typing import Any + +from agent_framework.presentation import register_tool_response_renderer + + +def _money_brl(value: Any) -> str: + try: + return f"{float(value):.2f}".replace(".", ",") + except (TypeError, ValueError): + return str(value) + + +def render_telecom_invoice(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + return f"[{agent_label}] Fatura consultada: {result}." + + +def render_telecom_plan(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + plano = result.get("plano") + if plano is None: + return None + parts = [f"[{agent_label}] Seu plano é {plano}"] + internet_gb = result.get("internet_gb") + status = result.get("status") + if internet_gb is not None: + parts.append(f"com {internet_gb} GB") + if status is not None: + parts.append(f"status {status}") + return ", ".join(parts) + "." + + +def render_retail_order(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + status = result.get("status") + if order_id is None or status is None: + return None + lines = [f"[{agent_label}] Pedido {order_id}: status {status}."] + total = result.get("valor_total") + if total is not None: + lines.append(f"Valor total: R$ {_money_brl(total)}.") + items = result.get("itens") or [] + rendered_items: list[str] = [] + if isinstance(items, list): + for item in items: + if isinstance(item, dict): + value = item.get("descricao") or item.get("nome") or item.get("sku") + else: + value = item + if value not in (None, ""): + rendered_items.append(str(value)) + if rendered_items: + lines.append("Itens: " + "; ".join(rendered_items) + ".") + return " ".join(lines) + + +def render_retail_delivery(*, tool_name: str, result: dict[str, Any], state: dict[str, Any], agent_label: str) -> str | None: + order_id = result.get("order_id") + transportadora = result.get("transportadora") + codigo = result.get("codigo_rastreio") + previsao = result.get("previsao_entrega") + if any(v is None for v in (order_id, transportadora, codigo, previsao)): + return None + return ( + f"[{agent_label}] Entrega do pedido {order_id}: transportadora {transportadora}, " + f"rastreio {codigo}, previsão {previsao}." + ) + + +def register_tool_renderers() -> None: + register_tool_response_renderer("telecom.invoice", render_telecom_invoice) + register_tool_response_renderer("telecom.plan", render_telecom_plan) + register_tool_response_renderer("retail.order", render_retail_order) + register_tool_response_renderer("retail.delivery", render_retail_delivery) diff --git a/templates/agent_template_backend/config/tools.yaml b/templates/agent_template_backend/config/tools.yaml index d85fae1..6273371 100644 --- a/templates/agent_template_backend/config/tools.yaml +++ b/templates/agent_template_backend/config/tools.yaml @@ -10,6 +10,9 @@ tools: - fatura - conta - boleto + response: + mode: renderer + renderer: telecom.invoice consultar_pagamentos: description: Consulta histórico de pagamentos do cliente. mcp_server: telecom @@ -28,6 +31,9 @@ tools: asset_id: string selection_keywords: - plano + response: + mode: renderer + renderer: telecom.plan listar_servicos: description: Lista serviços ativos e adicionais VAS. mcp_server: telecom @@ -49,6 +55,9 @@ tools: - consultar pedido - status do pedido - pedido + response: + mode: renderer + renderer: retail.order consultar_entrega: description: Consulta entrega e rastreamento do pedido. mcp_server: retail @@ -61,6 +70,9 @@ tools: - rastreamento - transportadora - previsão + response: + mode: renderer + renderer: retail.delivery solicitar_troca: description: Simula abertura de solicitação de troca. mcp_server: retail diff --git a/tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc b/tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc index db53f3f8ef98d16bce001c8430beee43c5bfb92e..dff3d6833be99c0b51c704c4ecd31b8cc56cdc17 100644 GIT binary patch delta 68 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 literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_mcp_parameter_extraction_runtime.cpython-313-pytest-9.0.2.pyc b/tests/__pycache__/test_mcp_parameter_extraction_runtime.cpython-313-pytest-9.0.2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c07d300f2f2e537e24190299b5ddd1352f107e4 GIT binary patch literal 8824 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 X1LRQ+!wJQDjqF~QDt^f!OGo|>!Q{q1 literal 0 HcmV?d00001 diff --git a/tests/unit/__pycache__/test_resilient_checkpointer.cpython-313-pytest-9.0.2.pyc b/tests/unit/__pycache__/test_resilient_checkpointer.cpython-313-pytest-9.0.2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8453472727f69487e5eedd894b908605e3f1723a GIT binary patch literal 5311 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