From 1f1188dd4ea6b5f0ea5eb5a2d7fe5873ceab2a9c Mon Sep 17 00:00:00 2001 From: hoshikawa2 Date: Sat, 13 Jun 2026 15:40:44 -0300 Subject: [PATCH] bugfixes --- .env | 14 +- BACKOFFICE_REST_CHANNEL_PATCH_SUMMARY.md | 53 ++ README_BACKOFFICE_FRAMEWORK_NATIVE_100.md | 4 +- app/__pycache__/__init__.cpython-313.pyc | Bin 184 -> 171 bytes .../identity_extraction.cpython-313.pyc | Bin 4350 -> 4337 bytes app/__pycache__/main.cpython-313.pyc | Bin 47832 -> 49039 bytes app/__pycache__/state.cpython-313.pyc | Bin 1715 -> 1702 bytes .../backoffice_agent.cpython-313.pyc | Bin 20700 -> 21914 bytes .../__pycache__/billing_agent.cpython-313.pyc | Bin 4042 -> 4029 bytes .../__pycache__/orders_agent.cpython-313.pyc | Bin 3940 -> 3927 bytes .../__pycache__/product_agent.cpython-313.pyc | Bin 4066 -> 4053 bytes .../__pycache__/prompting.cpython-313.pyc | Bin 1181 -> 1168 bytes .../__pycache__/runtime.cpython-313.pyc | Bin 15323 -> 15310 bytes .../__pycache__/support_agent.cpython-313.pyc | Bin 3777 -> 3764 bytes app/agents/backoffice_agent.py | 8 +- app/channels/__init__.py | 10 + .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 632 bytes .../backoffice_rest_adapter.cpython-313.pyc | Bin 0 -> 10630 bytes app/channels/backoffice_rest_adapter.py | 192 +++++ .../__pycache__/__init__.cpython-313.pyc | Bin 137 -> 0 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 148 -> 0 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 201 -> 0 bytes .../__pycache__/grl_examples.cpython-313.pyc | Bin 1783 -> 0 bytes .../__pycache__/ic_examples.cpython-313.pyc | Bin 1739 -> 0 bytes .../__pycache__/mcp_examples.cpython-313.pyc | Bin 1881 -> 0 bytes .../__pycache__/noc_examples.cpython-313.pyc | Bin 1828 -> 0 bytes .../observer_examples.cpython-313.pyc | Bin 1337 -> 0 bytes app/main.py | 94 +-- .../__pycache__/agent_graph.cpython-313.pyc | Bin 46274 -> 46426 bytes ...office_workflow_dispatcher.cpython-313.pyc | Bin 0 -> 4545 bytes ...koffice_workflow_executor.cpython-313.pyc} | Bin 59884 -> 61435 bytes app/workflows/backoffice_native_runtime.py | 753 +---------------- .../backoffice_workflow_dispatcher.py | 69 ++ app/workflows/backoffice_workflow_executor.py | 779 ++++++++++++++++++ debug_events.jsonl | 13 + docs/AJUSTES_IC_NOC_GRL_OCI_OPENAI.md | 2 +- ...BACKOFFICE_REST_AS_CHANNEL_ARCHITECTURE.md | 97 +++ docs/RELATORIO_FRAMEWORK_NATIVE_100.md | 4 +- .../mock_imdb_server.cpython-313.pyc | Bin 0 -> 2226 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 289 -> 276 bytes .../__pycache__/clients.cpython-313.pyc | Bin 3288 -> 3275 bytes .../__pycache__/main.cpython-313.pyc | Bin 7589 -> 7576 bytes .../__pycache__/models.cpython-313.pyc | Bin 1955 -> 1942 bytes .../__pycache__/settings.cpython-313.pyc | Bin 5824 -> 5804 bytes .../__pycache__/store.cpython-313.pyc | Bin 19084 -> 19071 bytes mock_servers/mock_imdb_server.py | 82 +- src/__pycache__/__init__.cpython-313.pyc | Bin 309 -> 296 bytes src/__pycache__/__init__.cpython-39.pyc | Bin 302 -> 0 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 256 -> 243 bytes src/agent/__pycache__/__init__.cpython-39.pyc | Bin 252 -> 0 bytes src/agent/graphs_README_DISABLED.md | 2 +- .../canceling_analysis.cpython-313.pyc | Bin 2037 -> 2024 bytes .../duplicate_analysis.cpython-313.pyc | Bin 6923 -> 6910 bytes .../postprocess_tais_kb_query.cpython-313.pyc | Bin 4263 -> 4250 bytes .../preprocess_tais_kb_query.cpython-313.pyc | Bin 2920 -> 2907 bytes .../speech_history_analysis.cpython-313.pyc | Bin 1854 -> 1841 bytes .../ticket_reclassification.cpython-313.pyc | Bin 2141 -> 2128 bytes .../tim_complaint_analysis.cpython-313.pyc | Bin 4655 -> 4642 bytes .../treatment_decision_prompt.cpython-313.pyc | Bin 4502 -> 4489 bytes .../anatel_motives.cpython-313.pyc | Bin 16628 -> 16615 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 213 -> 200 bytes ...sponse_emulator_generation.cpython-313.pyc | Bin 10955 -> 10942 bytes .../__pycache__/validation.cpython-313.pyc | Bin 10319 -> 10306 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 914 -> 901 bytes .../nodes/__pycache__/__init__.cpython-39.pyc | Bin 883 -> 0 bytes .../bypass_rules_node.cpython-313.pyc | Bin 6236 -> 6223 bytes .../cache_check_node.cpython-313.pyc | Bin 4826 -> 4813 bytes .../canceling_analysis_node.cpython-313.pyc | Bin 17639 -> 17626 bytes ...nt_complaint_operator_node.cpython-313.pyc | Bin 10047 -> 10034 bytes ...ent_complaint_operator_node.cpython-39.pyc | Bin 6214 -> 0 bytes .../fetch_ticket_node.cpython-313.pyc | Bin 2594 -> 2581 bytes ...identity_verification_node.cpython-313.pyc | Bin 8332 -> 8319 bytes .../imdb_enrichment_node.cpython-313.pyc | Bin 8163 -> 11161 bytes ...ledge_base_enrichment_node.cpython-313.pyc | Bin 15466 -> 18985 bytes ...assification_analysis_node.cpython-313.pyc | Bin 11958 -> 11945 bytes .../siebel_sr_opening_node.cpython-313.pyc | Bin 14440 -> 14948 bytes ...riplet_classification_node.cpython-313.pyc | Bin 6236 -> 0 bytes .../speech_enrichment_node.cpython-313.pyc | Bin 7416 -> 20260 bytes ...im_complaint_analysis_node.cpython-313.pyc | Bin 10388 -> 10375 bytes .../tim_complaint_node.cpython-313.pyc | Bin 1977 -> 1964 bytes .../treatment_decision_node.cpython-313.pyc | Bin 5072 -> 5059 bytes ...ed_complaint_operator_node.cpython-313.pyc | Bin 16519 -> 16506 bytes .../validation_node.cpython-313.pyc | Bin 10155 -> 10142 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 656 -> 643 bytes .../__pycache__/_rag_query.cpython-313.pyc | Bin 3864 -> 3851 bytes .../approve_draft_node.cpython-313.pyc | Bin 3185 -> 3172 bytes .../close_case_node.cpython-313.pyc | Bin 13212 -> 13199 bytes .../fetch_case_node.cpython-313.pyc | Bin 4966 -> 4953 bytes .../generate_response_node.cpython-313.pyc | Bin 20773 -> 20760 bytes .../persist_draft_node.cpython-313.pyc | Bin 4317 -> 4304 bytes .../retrieve_history_node.cpython-313.pyc | Bin 3746 -> 3733 bytes .../retrieve_templates_node.cpython-313.pyc | Bin 2233 -> 2220 bytes .../__pycache__/router_node.cpython-313.pyc | Bin 2974 -> 2961 bytes ...rt_response_emulation_node.cpython-313.pyc | Bin 5449 -> 5436 bytes .../validate_actions_node.cpython-313.pyc | Bin 7238 -> 7225 bytes .../validate_response_node.cpython-313.pyc | Bin 7685 -> 7672 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 415 -> 402 bytes .../state/__pycache__/__init__.cpython-39.pyc | Bin 401 -> 0 bytes .../__pycache__/agent_state.cpython-313.pyc | Bin 9896 -> 9883 bytes .../__pycache__/agent_state.cpython-39.pyc | Bin 9232 -> 0 bytes .../__pycache__/step_helpers.cpython-313.pyc | Bin 4619 -> 4730 bytes .../step_helpers_emulator.cpython-313.pyc | Bin 3638 -> 3625 bytes .../__pycache__/step_notes.cpython-313.pyc | Bin 3361 -> 3348 bytes .../step_notes_emulator.cpython-313.pyc | Bin 2726 -> 2713 bytes .../state/__pycache__/steps.cpython-313.pyc | Bin 2980 -> 2967 bytes .../steps_emulator.cpython-313.pyc | Bin 2020 -> 2007 bytes .../transitions_emulator.cpython-313.pyc | Bin 2635 -> 2622 bytes src/api/LEGACY_ROUTES_DISABLED.md | 10 +- src/api/__pycache__/__init__.cpython-313.pyc | Bin 246 -> 233 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 147 -> 0 bytes .../logging_context.cpython-313.pyc | Bin 3221 -> 0 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 388 -> 0 bytes .../__pycache__/error_handler.cpython-313.pyc | Bin 5565 -> 0 bytes .../__pycache__/logging.cpython-313.pyc | Bin 2800 -> 0 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 460 -> 447 bytes .../__pycache__/abrt_schemas.cpython-313.pyc | Bin 1518 -> 1505 bytes ..._response_emulator_schemas.cpython-313.pyc | Bin 7730 -> 7717 bytes .../anatel_schemas.cpython-313.pyc | Bin 15442 -> 15429 bytes .../emulator_rag_schemas.cpython-313.pyc | Bin 1354 -> 0 bytes .../__pycache__/imdb_schemas.cpython-313.pyc | Bin 1427 -> 1414 bytes .../portability_schemas.cpython-313.pyc | Bin 3117 -> 3104 bytes .../__pycache__/request.cpython-313.pyc | Bin 2164 -> 2151 bytes .../__pycache__/response.cpython-313.pyc | Bin 2464 -> 2451 bytes .../siebel_schemas.cpython-313.pyc | Bin 11454 -> 11441 bytes .../tais_kb_schemas.cpython-313.pyc | Bin 3848 -> 0 bytes .../__pycache__/agent_helpers.cpython-313.pyc | Bin 9751 -> 9733 bytes .../emulator_response_builder.cpython-313.pyc | Bin 9346 -> 0 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 191 -> 178 bytes .../framework_observer.cpython-313.pyc | Bin 5887 -> 5874 bytes .../framework_services.cpython-313.pyc | Bin 0 -> 2979 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 256 -> 243 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 347 -> 0 bytes .../__pycache__/mongodb_saver.cpython-313.pyc | Bin 10431 -> 0 bytes .../__pycache__/abrt_client.cpython-313.pyc | Bin 10905 -> 10892 bytes .../emulator_rag_client.cpython-313.pyc | Bin 14219 -> 14206 bytes .../__pycache__/imdb_client.cpython-313.pyc | Bin 10767 -> 10754 bytes .../portability_client.cpython-313.pyc | Bin 11187 -> 11174 bytes .../__pycache__/siebel_client.cpython-313.pyc | Bin 20117 -> 20104 bytes .../speech_analytics_client.cpython-313.pyc | Bin 16122 -> 0 bytes .../tais_kb_client.cpython-313.pyc | Bin 35370 -> 35357 bytes .../abrt_exceptions.cpython-313.pyc | Bin 4689 -> 4676 bytes .../emulator_rag_exceptions.cpython-313.pyc | Bin 1811 -> 1798 bytes .../imdb_exceptions.cpython-313.pyc | Bin 3994 -> 3981 bytes .../portability_exceptions.cpython-313.pyc | Bin 4815 -> 4802 bytes .../siebel_exceptions.cpython-313.pyc | Bin 4635 -> 4622 bytes .../speech_exceptions.cpython-313.pyc | Bin 2054 -> 0 bytes .../tais_kb_exceptions.cpython-313.pyc | Bin 1798 -> 1785 bytes .../rag/__pycache__/__init__.cpython-313.pyc | Bin 858 -> 845 bytes .../history_rag_client.cpython-313.pyc | Bin 8091 -> 8078 bytes .../templates_rag_client.cpython-313.pyc | Bin 4952 -> 4939 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 404 -> 0 bytes .../__pycache__/example_tool.cpython-313.pyc | Bin 3329 -> 0 bytes src/core/__pycache__/__init__.cpython-313.pyc | Bin 875 -> 862 bytes src/core/__pycache__/config.cpython-313.pyc | Bin 24752 -> 24875 bytes .../__pycache__/exceptions.cpython-313.pyc | Bin 2373 -> 2360 bytes src/core/__pycache__/logging.cpython-313.pyc | Bin 25958 -> 25945 bytes .../prompt_manager.cpython-313.pyc | Bin 3523 -> 3510 bytes .../__pycache__/state_logger.cpython-313.pyc | Bin 569 -> 0 bytes .../__pycache__/client.cpython-313.pyc | Bin 1137 -> 0 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 328 -> 315 bytes .../__pycache__/cases_manager.cpython-313.pyc | Bin 2934 -> 2921 bytes .../__pycache__/connection.cpython-313.pyc | Bin 11174 -> 11161 bytes .../memory_manager.cpython-313.pyc | Bin 5708 -> 5695 bytes .../__pycache__/client.cpython-313.pyc | Bin 6666 -> 0 bytes .../__pycache__/consumer.cpython-313.pyc | Bin 9212 -> 0 bytes .../debug_producer.cpython-313.pyc | Bin 3115 -> 3102 bytes .../__pycache__/producer.cpython-313.pyc | Bin 3239 -> 0 bytes .../langfuse_provider.cpython-313.pyc | Bin 4854 -> 4841 bytes .../__pycache__/llm_provider.cpython-313.pyc | Bin 9728 -> 10693 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 235 -> 222 bytes .../cancellation_helpers.cpython-313.pyc | Bin 1923 -> 0 bytes .../decision_helpers.cpython-313.pyc | Bin 2849 -> 2836 bytes .../external_response_builder.cpython-313.pyc | Bin 3067 -> 3054 bytes .../forwarding_helpers.cpython-313.pyc | Bin 8943 -> 8930 bytes src/utils/__pycache__/http.cpython-313.pyc | Bin 8268 -> 8255 bytes .../__pycache__/ics_collector.cpython-313.pyc | Bin 27664 -> 27651 bytes src/utils/__pycache__/loaders.cpython-313.pyc | Bin 743 -> 0 bytes .../__pycache__/observer.cpython-313.pyc | Bin 29099 -> 29086 bytes src/utils/__pycache__/text.cpython-313.pyc | Bin 833 -> 820 bytes .../validate_parity.cpython-313.pyc | Bin 5973 -> 0 bytes tools/validate_parity.py | 8 +- 181 files changed, 1345 insertions(+), 849 deletions(-) create mode 100644 BACKOFFICE_REST_CHANNEL_PATCH_SUMMARY.md create mode 100644 app/channels/__init__.py create mode 100644 app/channels/__pycache__/__init__.cpython-313.pyc create mode 100644 app/channels/__pycache__/backoffice_rest_adapter.cpython-313.pyc create mode 100644 app/channels/backoffice_rest_adapter.py delete mode 100644 app/domain/__pycache__/__init__.cpython-313.pyc delete mode 100644 app/domain/backoffice/__pycache__/__init__.cpython-313.pyc delete mode 100644 app/examples/__pycache__/__init__.cpython-313.pyc delete mode 100644 app/examples/__pycache__/grl_examples.cpython-313.pyc delete mode 100644 app/examples/__pycache__/ic_examples.cpython-313.pyc delete mode 100644 app/examples/__pycache__/mcp_examples.cpython-313.pyc delete mode 100644 app/examples/__pycache__/noc_examples.cpython-313.pyc delete mode 100644 app/examples/__pycache__/observer_examples.cpython-313.pyc create mode 100644 app/workflows/__pycache__/backoffice_workflow_dispatcher.cpython-313.pyc rename app/workflows/__pycache__/{backoffice_native_runtime.cpython-313.pyc => backoffice_workflow_executor.cpython-313.pyc} (60%) create mode 100644 app/workflows/backoffice_workflow_dispatcher.py create mode 100644 app/workflows/backoffice_workflow_executor.py create mode 100644 docs/BACKOFFICE_REST_AS_CHANNEL_ARCHITECTURE.md create mode 100644 legacy_backend/__pycache__/mock_imdb_server.cpython-313.pyc delete mode 100644 src/__pycache__/__init__.cpython-39.pyc delete mode 100644 src/agent/__pycache__/__init__.cpython-39.pyc delete mode 100644 src/agent/nodes/__pycache__/__init__.cpython-39.pyc delete mode 100644 src/agent/nodes/__pycache__/different_complaint_operator_node.cpython-39.pyc delete mode 100644 src/agent/nodes/__pycache__/siebel_triplet_classification_node.cpython-313.pyc delete mode 100644 src/agent/state/__pycache__/__init__.cpython-39.pyc delete mode 100644 src/agent/state/__pycache__/agent_state.cpython-39.pyc delete mode 100644 src/api/dependencies/__pycache__/__init__.cpython-313.pyc delete mode 100644 src/api/dependencies/__pycache__/logging_context.cpython-313.pyc delete mode 100644 src/api/middleware/__pycache__/__init__.cpython-313.pyc delete mode 100644 src/api/middleware/__pycache__/error_handler.cpython-313.pyc delete mode 100644 src/api/middleware/__pycache__/logging.cpython-313.pyc delete mode 100644 src/api/schemas/__pycache__/emulator_rag_schemas.cpython-313.pyc delete mode 100644 src/api/schemas/__pycache__/tais_kb_schemas.cpython-313.pyc delete mode 100644 src/api/utils/__pycache__/emulator_response_builder.cpython-313.pyc create mode 100644 src/compat/__pycache__/framework_services.cpython-313.pyc delete mode 100644 src/components/checkpointing/__pycache__/__init__.cpython-313.pyc delete mode 100644 src/components/checkpointing/__pycache__/mongodb_saver.cpython-313.pyc delete mode 100644 src/components/clients/__pycache__/speech_analytics_client.cpython-313.pyc delete mode 100644 src/components/clients/exceptions/__pycache__/speech_exceptions.cpython-313.pyc delete mode 100644 src/components/tools/__pycache__/__init__.cpython-313.pyc delete mode 100644 src/components/tools/__pycache__/example_tool.cpython-313.pyc delete mode 100644 src/core/__pycache__/state_logger.cpython-313.pyc delete mode 100644 src/core/streaming/__pycache__/client.cpython-313.pyc delete mode 100644 src/infrastructure/streaming/__pycache__/client.cpython-313.pyc delete mode 100644 src/infrastructure/streaming/__pycache__/consumer.cpython-313.pyc delete mode 100644 src/infrastructure/streaming/__pycache__/producer.cpython-313.pyc delete mode 100644 src/utils/__pycache__/cancellation_helpers.cpython-313.pyc delete mode 100644 src/utils/__pycache__/loaders.cpython-313.pyc delete mode 100644 tools/__pycache__/validate_parity.cpython-313.pyc diff --git a/.env b/.env index 672d296..cd6feb8 100644 --- a/.env +++ b/.env @@ -214,24 +214,24 @@ GOOGLE_APPLICATION_CREDENTIALS=/Users/cristianohoshikawa/Dropbox/ORACLE/TIM/comp SPEECH_TIMEOUT=30 SPEECH_SIMILARITY_THRESHOLD=70 -TAIS_DB_USER=USR_ADB_AGNTATEND_W_DEV -TAIS_DB_PASSWORD=T!M#Esta026! -TAIS_DB_DSN="(description= (retry_count=3)(retry_delay=7)(address=(protocol=tcps)(port=1522)(host=10.152.100.72))(connect_data=(service_name=gf9a4a2e79cfeb2_agntatendimentodev_high.adb.oraclecloud.com))(security=(ssl_server_dn_match=no)))" +TAIS_DB_USER=admin +TAIS_DB_PASSWORD=Moniquinha1972 +TAIS_DB_DSN=" (description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=adb.sa-saopaulo-1.oraclecloud.com))(connect_data=(service_name=jy2otyfomimhaoc_oradb23ai_high.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))" TAIS_DB_TIMEOUT=30 -TAIS_GENAI_ENDPOINT=https://inference.generativeai.sa-saopaulo-1.oci.oraclecloud.com -TAIS_GENAI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaa3prjvf7mkvijwn5ng5h6n5ftanbbwqfg6cu44kmffwamhyy267iq +TAIS_GENAI_ENDPOINT=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com +TAIS_GENAI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaexpiw4a7dio64mkfv2t273s2hgdl6mgfvvyv7tycalnjlvpvfl3q TAIS_GENAI_EMBED_MODEL_ID=cohere.embed-multilingual-v3.0 TAIS_TABLE_CHUNKS=CHUNKS_CHAR_COHERE_3 TAIS_TOP_K=3 # LLM CLASSIFICATION -CLASSIFICATION_LLM_MODEL=bo_gptoss20b_dev +CLASSIFICATION_LLM_MODEL=openai.gpt-4.1 CLASSIFICATION_LLM_TEMPERATURE=0.3 CLASSIFICATION_LLM_MAX_TOKENS=2000 CLASSIFICATION_LLM_TOP_P=0.9 CLASSIFICATION_LLM_TOP_K=250 -CLASSIFICATION_LARGE_LLM_MODEL=bo_gptoss120b_dev +CLASSIFICATION_LARGE_LLM_MODEL=openai.gpt-4.1 CLASSIFICATION_LARGE_LLM_TEMPERATURE=0.3 CLASSIFICATION_LARGE_LLM_MAX_TOKENS=4000 CLASSIFICATION_LARGE_LLM_TOP_P=0.9 diff --git a/BACKOFFICE_REST_CHANNEL_PATCH_SUMMARY.md b/BACKOFFICE_REST_CHANNEL_PATCH_SUMMARY.md new file mode 100644 index 0000000..fdaf0dc --- /dev/null +++ b/BACKOFFICE_REST_CHANNEL_PATCH_SUMMARY.md @@ -0,0 +1,53 @@ +# Patch Summary — Backoffice REST as Channel + +## Goal + +Adapt the Backoffice project so legacy REST endpoints behave as framework channel entrypoints instead of directly invoking `BackofficeWorkflowExecutor` from FastAPI routes. + +## Added + +- `app/channels/__init__.py` +- `app/channels/backoffice_rest_adapter.py` +- `app/workflows/backoffice_workflow_dispatcher.py` +- `docs/BACKOFFICE_REST_AS_CHANNEL_ARCHITECTURE.md` + +## Modified + +- `app/main.py` + - Instantiates `BackofficeRestChannelAdapter` and `BackofficeWorkflowDispatcher`. + - Updates `/agent/*` routes to create a `BackofficeChannelEnvelope` and dispatch through the channel path. + - Updates response metadata with `framework_entrypoint=channel_gateway` and `source_channel=backoffice_rest`. + - Updates readiness/debug metadata to show the channel gateway entrypoint. + +- `app/agents/backoffice_agent.py` + - Removes guidance that operational checklist should be called through direct `BackofficeWorkflowExecutor` usage. + - Documents that operational ticket/emulator flows enter through the channel adapter and dispatcher. + +- `app/workflows/backoffice_workflow_executor.py` + - Repositioned as the workflow execution engine behind the dispatcher, not the REST entrypoint. + +- `src/api/LEGACY_ROUTES_DISABLED.md` + - Updated to describe the new REST → ChannelGateway → dispatcher → workflow path. + +## New execution chain + +```text +Legacy REST route + → BackofficeRestChannelAdapter + → ChannelGateway.normalize(...) + → BackofficeWorkflowDispatcher + → BackofficeWorkflowExecutor / LangGraph workflow + → Response builder preserving legacy contract +``` + +## Validation done + +Python syntax compilation succeeded for the changed Python files: + +```text +app/main.py +app/agents/backoffice_agent.py +app/channels/backoffice_rest_adapter.py +app/workflows/backoffice_workflow_dispatcher.py +app/workflows/backoffice_workflow_executor.py +``` diff --git a/README_BACKOFFICE_FRAMEWORK_NATIVE_100.md b/README_BACKOFFICE_FRAMEWORK_NATIVE_100.md index 31c9c30..877120e 100644 --- a/README_BACKOFFICE_FRAMEWORK_NATIVE_100.md +++ b/README_BACKOFFICE_FRAMEWORK_NATIVE_100.md @@ -6,7 +6,7 @@ Esta versão substitui a execução direta dos grafos legados por workflows comp - O framework é dono do motor de workflow/LangGraph, checkpoint, telemetry, guardrails, judges, supervisor e persistência de execução. - O backend fornece apenas customizações de domínio: nós, services/clients, prompts, schemas e contratos REST. -- Os contratos REST antigos continuam existindo, mas agora são adapters finos para `BackofficeNativeRuntime.execute_workflow(...)`. +- Os contratos REST antigos continuam existindo, mas agora são adapters finos para `BackofficeWorkflowExecutor.execute_workflow(...)`. ## O que foi removido do caminho ativo @@ -26,7 +26,7 @@ legacy_reference_disabled/original_develop/ ## Runtime ativo ```text -app/workflows/backoffice_native_runtime.py +app/workflows/backoffice_workflow_executor.py ``` Esse runtime monta dois workflows com o motor do framework: diff --git a/app/__pycache__/__init__.cpython-313.pyc b/app/__pycache__/__init__.cpython-313.pyc index 0186b348a4832540c6feb5bde1fcb36fdb3c42c9..74dd46d6dd9c9fb540e924df39792983b6920297 100644 GIT binary patch delta 46 zcmdnNxSEmsGcPX}0}wPV(w)d{%;+`IUPCB3Ker&UxHvv3F*!RwEiE%Sbz++l055G0 Am;e9( delta 59 zcmZ3@xPy`VGcPX}0}vQGDox}zW(=QbuOXk5n4F!TmX?{E8lRk>SC(2-l9`eppH`HZ Nn_8YgT2zvmk{_Q| Rl$e`Zo?n!`xtzI*7XV#p6wd$v diff --git a/app/__pycache__/main.cpython-313.pyc b/app/__pycache__/main.cpython-313.pyc index ce055f54e30802607ed112d286091c134186634b..ef970ebfa970f51deda51c066c9b438910206d8e 100644 GIT binary patch delta 13761 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 J(s!-V{THchMfCsx delta 12981 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 P)20RbpO~^XEz&TKhyMRrb zn$RXg9#SqRZJ;GJG@aso%U5Qzk)gk%KdBo%u;rx1f%cxP+GZIr4(OfCD2q+Q2F~>U z(H%PUBDt%pwnh?T-ubh(>pihI$)GWvx>Con+kp?sXUCNiff0!8uj!jxLQG@p6U6=YV{D}8k48Y9SBX5&n(`)#JGU@h?t1; zF;7%DD0qapjCtxt7$JcysxEQ|$7_8b&>&xR2`9v5Ppcv(2aPu538X`GiMBLYqa zv)@#0Fh%fKA5O@LNFtW842eQ4Ds4@K#-r3eW1;(O#qt#>M3w$(r*3Gn;#Y?Xz+*}ej4jQOwO3X zajFPQGNfnY{Fp%F>22PUJ_yiDA%igPhJWp%r(~dvhjiJzs@-ZbVfz5>NY>{43{7P* z*8KTg@9kXg%+6G9%Q5YOmMJJsJKginn%mBrx!OR=*_n1#ri-fYxk{&7&$ON!OSx92 z-R0AxXGZ6^mXy0Sy+pCVstYY?TiLv=>b9+F#+b4-&D&Zo;{`R9-^(dIx9URc`PMn# z+EiKleT`aIXj#Z&oNn?rdyA>Wo?~2K>;~h52x-W#oO+OLq_l&v4xM?oX|Nr9iz*L00Rv-MhwiPG0u6tuF}HHDPkaovrAcJ_KnJ!Njts1Ei5keP}lMmisncUs5dN5PCI9%3G0k5F!neR7I(F6v!9I*A*`6mS4FJ zZ6n(&>rg8BT4k9Y?I%C?twuQcC*L5d`zAHzbQujao`hjh8Fl0U##0dD+ra9DiSd{i z5oNke!QZLUA#&M&x?Bc>0{{}hL4ZR569AI{he@pA79u3j=(1j<0$Q50Ab%U+$7H0j z!b%4mgTD(Y;;gX#J z1*|V)eRSu9XjqKWa}ec8{3Fo*6kvw9o18gH_9xrLr^)6fkMA+Z6LlqvT5}LRi@HDwJ)Q1A8QMYi2fR7TiuQux;^igp1-j^v|97AQZA!YI z?^n~>?_X;VL5VU3nENqajLR8)ff4CaNTgm5Z8<0%Q?Y}}ka;yEb!KZ_dPEXIF1b%5KmN+DN`0?4KWQ-^97#|Z4 z^RpLb-${7Jh1ma@srAd}Df#od^7geMN${+H^1bS(qxX^3x+p&`3)oY;M7`}%>Tf)m z#H4pUM_Y4peZ=uH{gz23bO&EDN0WW0O1 zj-$|69!JQ1jFfmF4`LaRhAR#GS* z75q$ye0-Ih=xIi~$*+6Ln<5aT9{}ovw*kPFz%K%91^7JxjBh*(u#0$lUFZ&ZzBj5H zMjGS8el@w!8z&6~`8nI^5r3ZvAse r|cdohm9IySO~E*Q+I{D4(3*3^{RiNIjs2 z%NDV(ZjLhOLS$HJSV zoG~#T#!vq_V-IeH#X_1kHHC}~9uU3Cqidj_zBl4xd^nTG@53SvM@INDKAL#+y~YLL z`35+#@Fu{^zxVVEo(iUv7eFUCDD9_NY%w^x3@ggQn6d&Tn53aX+HH@o@lJ38_yF$3 z2}&GcKF@I-W7FBT;}fq>oHnJh%jdJ3XV^>nclDR^Q`OB>XUd+l?Yv{!nYI_cwf*Gw zsna7Vd)2&s!_3M{&F?l}?nu=JDEE(I--@xP+E#xs-mLr|GmaeLYZups2RPIAo#uyHhqCTuu pc5;Ut?{gUcOC9KT7>OhA_Z2#Zw5V(@zv>|a#6SDYCS*}!{ttmC|7ZXJ delta 2090 zcmZ{l3v3is6hPd7v^(X^ zv=jppQ4>ET3Qv@%B%;PBBpMtNi4f)6N>soY6erYZlo%s~zljM^@0|t$By2Kg?z`{K zeeZtW+c)>a#l0}Pp0vXiQD^D@;$s)o2%!dz6hTThB|J&$~0w%d>(2H%-wv;QY;=lG-M;=J3PmC3c}T zm%o(}c1u%%))Is^8-L7|0~7f50&jDbu%x_FTvAb)GEQ&`PuL>WNQm6Fc+%p>7FSqo z&}@D|vn3r}XdU?(pFwQxi^=HZ_C)wy{_Yu12`XO8x} z8&JbS2q}fn99`|GA~BsmH~L_C(U18PzRRC*uDtg9{O|?e_zMNWU&a*jBY892 zZg-aJn&3`z-H>;B$8Wu!=}L25_X?gha9vD8F*_yA^^f)?df%2GE{C@voG$JOp>!-C z!kOYR-xQROkAkpAJf7(#IRN1t@p!N<2L~rY5cY~EX4AyUTnPKblX=xBpGut^F7lk3 z;YN8-gm9@im@)?Cj=>@bmx+VLRX7+zuK{r=vw-As2utEnMO_IFPG2~*P_p2 zk%MN-EEzY0vV=7L^QPK5=3^j?GA@bM%S@MJRI#X4A2x%g$wo?LE%-7;syHhm(XJ`F zX_w=1(;@fvD#Cg9TKLuCLRii- z{1Qa?G=HVz5ZV08f2}Jqw)^*sFyEM7CILKcbdH}16KQR>8ewKebye+-%4|(v4|b4d zy09CVu5C={YgvrU7V^^pANsx&sDoA>2u_5rjJ9B@6V~xf)ze_TaiF>#ChBM^rJ5^86*ka1eMTB*g#+ejn_^& z1KYW)#^-q-6`0#yq<@|82A@__=Gjc*7D5364PN2N8gIE3r-RfV61LHtXC$Guq_FC- zoTQieftu0MP7-NHrUwrO!`dnFXd;e@N$8u{Yc#uuu$Nz{$9Bz4mn>(g|#M`0K;1#60(SWebQp864} z9%&y^SY@!Wm?q-Lk3SY9^G4P1H?g&Hj~rKBcq!ezd8*{N z+^Z{0^T$;`UB1}3{F`~>8tU6LLct2GPjww%4)R9i!{P}yfY$85me(LOm33w54qCpICU>)?fi1Y5AX1d z#p^;=?b30UeMBG$)Bd3LsWdw1EAXtZdT@>(TwJo%YEG*cE$P8eM;yBDb7=L6Wob2w zwX_xO@Ao!AvkxvrQ$wV+jcn7ha9CaottG7co;~CummTICny14uzOQ-Ql$GRU5rOi= zS_#zeY$;(e;Vj`0;RvCfLyHg2@WPgO>Pkp)-P&y9FSI1>5y{QJUfLfyLq_FQUo;-O6ls4Ttm>td%0J*#Tf!7<);`y(H8Q3$urX>RXN#4k$gB8@MfyU^)38w^J;8 diff --git a/app/agents/__pycache__/billing_agent.cpython-313.pyc b/app/agents/__pycache__/billing_agent.cpython-313.pyc index 9962052bd05cb4d8db875e83d5ddac4ecd66197e..59b62dfdd456d18a86d8f68836b1cc517d2431d8 100644 GIT binary patch delta 50 zcmX>lzgM37GcPX}0}wPV(%s1YhLJIB@()H0q2&DBg2dwD_@u<-?EJK}%;eO~_DtQp E0Ga&|-2eap delta 63 zcmdlhe@dSFGcPX}0}vQGDsAL`!^oIC`3Iwhd{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W+SF0zg diff --git a/app/agents/__pycache__/product_agent.cpython-313.pyc b/app/agents/__pycache__/product_agent.cpython-313.pyc index af4b48f1a6bbaad95549b72e42ecceda9935541a..cbbab225bd59bb91631a417f1dc5224425a0c453 100644 GIT binary patch delta 50 zcmaDPe^s9QGcPX}0}wPV(%s1YhLJIB@()H0q2&DBg2dwD_@u<-?EJK}%;eO~_DqX; E0i#_JB>(^b delta 63 zcmcaA|45$uGcPX}0}vQGDsAL`!^oIC`3Iwhd{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W+SG>ya0>473lx~ diff --git a/app/agents/__pycache__/prompting.cpython-313.pyc b/app/agents/__pycache__/prompting.cpython-313.pyc index b5a95e339791934c088d77757dd097245c5b98fe..995e8f3125a40212442c97906d3436b33461df8c 100644 GIT binary patch delta 50 zcmbQsIf0Y=GcPX}0}wPV(%r}{z|0slS%z6dC^gT2zvmk{_Q| Rl$e`Zo?n!`IgHtg5dao?6Dt4! diff --git a/app/agents/__pycache__/runtime.cpython-313.pyc b/app/agents/__pycache__/runtime.cpython-313.pyc index f14d167230a4e86a49384dcc8e04255307c5ca70..eb5576ab6e20e2a0e52c20780f29f1e3c2ae357f 100644 GIT binary patch delta 50 zcmcazey*JRGcPX}0}wPV(%s1Yjg2v2G84OoP;!25L1J-nd{Sa^c79q~W^(FgPxeVB E0I9+e1poj5 delta 63 zcmX?Ce!HCeGcPX}0}vQGDsANc#>N;snTcIPJ}EIdJ3lQgGdVRrIX|x~wWuUBB|ko` RC^0v+JijP=vkm(s69A5%70Cbq diff --git a/app/agents/__pycache__/support_agent.cpython-313.pyc b/app/agents/__pycache__/support_agent.cpython-313.pyc index 2d774139d6b98acf61ac9a274296b79209f11b00..8ef5397b7abc90b3f63e060d62d676fa85292cc2 100644 GIT binary patch delta 50 zcmX>oyG54!GcPX}0}wPV(%s1YmXR@R@=rz$q2&DBg2dwD_@u<-?EJK}%;eO~4ord{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W@DyC9sqjZ6@vf( diff --git a/app/agents/backoffice_agent.py b/app/agents/backoffice_agent.py index 65e8465..716b368 100644 --- a/app/agents/backoffice_agent.py +++ b/app/agents/backoffice_agent.py @@ -94,7 +94,7 @@ class BackofficeAgent(AgentRuntimeMixin): "BACKOFFICE_TICKET_CONTEXT_DETECTED", normalized_state, { - "status": "Contexto de ticket detectado; execução checklist deve ocorrer pelo BackofficeNativeRuntime nas rotas /agent/*", + "status": "Contexto de ticket detectado; execução operacional deve entrar como canal backoffice_rest via ChannelGateway/dispatcher", "framework_native": True, "reason": "o agente conversacional não compila nem executa grafos de domínio", }, @@ -383,14 +383,14 @@ class BackofficeAgent(AgentRuntimeMixin): A migração framework-native não permite que o agente conversacional compile/execute ``src.agent.graphs`` diretamente. Os fluxos checklist e - response emulator são executados pelo BackofficeNativeRuntime chamado - pelas rotas/adapters do backend. + response emulator são executados pelo dispatcher de workflows após + normalização pelo canal backoffice_rest/ChannelGateway. """ return { "executed": False, "error": { "type": "DeprecatedDirectGraphExecution", - "message": "Use BackofficeNativeRuntime.execute_workflow('backoffice_checklist')", + "message": "Use BackofficeRestChannelAdapter + BackofficeWorkflowDispatcher", }, } diff --git a/app/channels/__init__.py b/app/channels/__init__.py new file mode 100644 index 0000000..14fa58d --- /dev/null +++ b/app/channels/__init__.py @@ -0,0 +1,10 @@ +"""Channel adapters owned by the application domain. + +The framework ChannelGateway remains the canonical normalization boundary. +Domain REST contracts should enter the backend through adapters in this package +instead of calling workflow runtimes directly from FastAPI routes. +""" + +from .backoffice_rest_adapter import BackofficeChannelEnvelope, BackofficeRestChannelAdapter + +__all__ = ["BackofficeChannelEnvelope", "BackofficeRestChannelAdapter"] diff --git a/app/channels/__pycache__/__init__.cpython-313.pyc b/app/channels/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..764df6ad10473ba3e5181ecbce09792989ca5bc5 GIT binary patch literal 632 zcmYLGv2GMG5cTff5!fh5R0u&a72*nRe*hr`NTLLRqHJ1Z`E2i<6R*7*dpRu~`~yEg z$5-$RskcI+q61w)%k163O<|2a^WMBSUL73djN;Rmr&r$+#(oT!f01sJ6;Se-l?+*# zl?Qihno#zMtB_2@pdxq_c&Kxa^Bw`JZ$JV5{PdXzH1+PNi*kP*^1DtFN@m6 zLKSbyQ#eO|MWRDNE?wmR*U!B)h4ghJLg2d*1$|s0H(whH&W$sX^J&xdx1ZHswN^jJ oeVQ?N4G-z~l_g2?I~^yZKX+O3F8RLy_~yy+O@8um5ARU@FOjCpB>(^b literal 0 HcmV?d00001 diff --git a/app/channels/__pycache__/backoffice_rest_adapter.cpython-313.pyc b/app/channels/__pycache__/backoffice_rest_adapter.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fba0c8af6885d818edf93021725d92253322bb89 GIT binary patch literal 10630 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 literal 0 HcmV?d00001 diff --git a/app/channels/backoffice_rest_adapter.py b/app/channels/backoffice_rest_adapter.py new file mode 100644 index 0000000..da4cc3f --- /dev/null +++ b/app/channels/backoffice_rest_adapter.py @@ -0,0 +1,192 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from types import SimpleNamespace +from typing import Any +from uuid import uuid4 + + +@dataclass(slots=True) +class BackofficeChannelEnvelope: + """Canonical channel envelope for Backoffice REST requests. + + REST remains only a transport/channel contract. This envelope carries the + normalized information required by the framework layers before a workflow is + dispatched. The domain payload is preserved under ``payload`` so existing + business nodes can continue to read the original TIM/ANATEL contract from + ``state["metadata"]["request_context"]``. + """ + + workflow_id: str + payload: dict[str, Any] + transaction_id: str + channel: str = "backoffice_rest" + tenant_id: str = "default" + agent_id: str = "backoffice_anatel" + user_id: str | None = None + message_id: str = field(default_factory=lambda: str(uuid4())) + text: str = "" + business_context: dict[str, Any] = field(default_factory=dict) + metadata: dict[str, Any] = field(default_factory=dict) + + def gateway_payload(self) -> dict[str, Any]: + """Payload sent to the framework ChannelGateway. + + The web adapter shape is intentionally also populated as a compatibility + fallback for framework versions that do not yet register a dedicated + ``backoffice_rest`` adapter. + """ + return { + "channel": self.channel, + "message": self.text, + "text": self.text, + "session_id": self.transaction_id, + "conversation_key": f"{self.tenant_id}:{self.agent_id}:{self.transaction_id}", + "message_id": self.message_id, + "user_id": self.user_id or self.business_context.get("customer_key") or self.transaction_id, + "tenant_id": self.tenant_id, + "agent_id": self.agent_id, + "business_context": self.business_context, + "metadata": { + **self.metadata, + "workflow_id": self.workflow_id, + "transaction_id": self.transaction_id, + "source_channel": self.channel, + "request_context": self.payload, + }, + } + + +class BackofficeRestChannelAdapter: + """Adapter that turns legacy Backoffice REST contracts into a framework channel. + + This class deliberately contains translation only. It does not run LangGraph, + does not know node order and does not call domain services. Execution is + delegated to the framework workflow dispatcher after channel normalization. + """ + + channel_name = "backoffice_rest" + agent_id = "backoffice_anatel" + tenant_id = "default" + + def from_ticket_event(self, event: Any, *, legacy_contract: str) -> BackofficeChannelEnvelope: + payload = self._to_dict(event) + transaction_id = payload.get("transactionId") or payload.get("transaction_id") or f"man-{uuid4().hex[:8]}" + complaint = payload.get("complaint") or {} + customer = payload.get("customer") or {} + text = self._first_non_empty( + complaint.get("description"), + complaint.get("motive"), + payload.get("description"), + f"Processar chamado backoffice {transaction_id}", + ) + business_context = self._business_context(payload, transaction_id) + return BackofficeChannelEnvelope( + workflow_id="backoffice_checklist", + payload=payload, + transaction_id=transaction_id, + channel=self.channel_name, + tenant_id=self.tenant_id, + agent_id=self.agent_id, + user_id=customer.get("cpfCnpj") or customer.get("msisdn") or business_context.get("customer_key"), + text=text, + business_context=business_context, + metadata={ + "legacy_contract": legacy_contract, + "case_type": payload.get("caseType"), + "complaint_protocol": complaint.get("complaintProtocol"), + "crm_protocol": payload.get("crmProtocol"), + "adapter": self.__class__.__name__, + }, + ) + + def from_emulator_event(self, event: Any, *, legacy_contract: str) -> BackofficeChannelEnvelope: + payload = self._to_dict(event) + transaction_id = payload.get("transactionId") or payload.get("transaction_id") or f"emu-{uuid4().hex[:8]}" + selected_actions = payload.get("selected_actions") or payload.get("selectedActions") or [] + flow_mode = payload.get("flow_mode") or payload.get("flowMode") or payload.get("action") + text = self._first_non_empty( + payload.get("operator_instructions"), + payload.get("previous_response"), + f"Executar emulador de resposta do caso {transaction_id}", + ) + return BackofficeChannelEnvelope( + workflow_id="backoffice_response_emulator", + payload=payload, + transaction_id=transaction_id, + channel=self.channel_name, + tenant_id=self.tenant_id, + agent_id=self.agent_id, + user_id=transaction_id, + text=text, + business_context={"interaction_key": transaction_id, "session_key": transaction_id}, + metadata={ + "legacy_contract": legacy_contract, + "flow_mode": flow_mode, + "selected_actions": selected_actions, + "adapter": self.__class__.__name__, + }, + ) + + async def normalize(self, channel_gateway: Any, envelope: BackofficeChannelEnvelope) -> Any: + """Normalize through ChannelGateway, with a compatibility fallback. + + Newer framework versions may support registering ``backoffice_rest`` as a + first-class adapter. Older versions only know web/whatsapp/voice; in that + case the payload is still passed through the web adapter shape and then + tagged back as ``backoffice_rest``. + """ + payload = envelope.gateway_payload() + try: + msg = await channel_gateway.normalize(envelope.channel, payload) + return msg + except Exception: + try: + msg = await channel_gateway.normalize("web", payload) + try: + msg.channel = envelope.channel + except Exception: + pass + return msg + except Exception: + return SimpleNamespace( + channel=envelope.channel, + channel_id=None, + session_id=envelope.transaction_id, + user_id=envelope.user_id, + text=envelope.text, + context=payload, + ) + + def _business_context(self, payload: dict[str, Any], transaction_id: str) -> dict[str, Any]: + customer = payload.get("customer") or {} + complaint = payload.get("complaint") or {} + cpf = customer.get("cpfCnpj") or (customer.get("subscriber") or {}).get("cpfCnpj") + msisdn = customer.get("msisdn") or ((customer.get("phones") or [])[:1] or [None])[0] + protocol = complaint.get("complaintProtocol") or payload.get("crmProtocol") or transaction_id + return { + "customer_key": msisdn or cpf, + "contract_key": cpf, + "interaction_key": protocol, + "session_key": transaction_id, + "metadata": { + "cpf_cnpj": cpf, + "msisdn": msisdn, + "transaction_id": transaction_id, + }, + } + + def _to_dict(self, value: Any) -> dict[str, Any]: + if isinstance(value, dict): + return dict(value) + if hasattr(value, "model_dump"): + return value.model_dump(mode="json", by_alias=True) + if hasattr(value, "dict"): + return value.dict(by_alias=True) + raise TypeError(f"Unsupported backoffice REST event type: {type(value).__name__}") + + def _first_non_empty(self, *values: Any) -> str: + for value in values: + if value is not None and str(value).strip(): + return str(value).strip() + return "Backoffice REST request" diff --git a/app/domain/__pycache__/__init__.cpython-313.pyc b/app/domain/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 0f87383ce4c0c4c2d556e6f78ec7710fc201b6b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137 zcmey&%ge<81n*RpvOx4>5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa~h`er{fgeoA6V zqJCOtMSOBWntozIfqqJUZenJhetdjpUS>&ryk0@&Ee@O9{FKt1RJ$Tpphl3v#URE< MW=2NFB4!{90BaN;H~;_u diff --git a/app/domain/backoffice/__pycache__/__init__.cpython-313.pyc b/app/domain/backoffice/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 9983ee42532e33a4b51f8adf3fba562abea37896..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmey&%ge<81n*RpvOx4>5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa~icer{fgeoA6V zqJCOtMSOBWntozIfqqJUZenJheo|s`c79q~W^$^2e0*kJW=VX!UP0w84x8Nkl+v73 XyCPPg86Z1~L5z>gjEsy$%s>_Z9aSQ4 diff --git a/app/examples/__pycache__/__init__.cpython-313.pyc b/app/examples/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index eac1e1c6b326f1f1cbc57f74897e1a8326370455..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 201 zcmXv|Jqp4w7)?~P2)#ob>(ER(iJPm72l$B1SBbVwNK&ZY!$Wu+*W%^{gkHb|^eyiP z-s25vIwt|I=iH^?FhPc`+Hus5?RG@jhR;K0dZD?>NQ-_RvUST`;Z(Ncvaiu1L7Oy9648Kg zGa`(b8>H!b1B>45W?QEU3D0Q^S!3?`wGaU62K2!cDE98Xo3{j*VAvO&Nwm$4=dR zR{bWv{%qE}grL)N>Xp;_=j7E3^4c(;T2XA>(j+fS%KJdr8hqadexOvf5m>*0GN`KE zQdV&>TNUX$Z`;eYyUSwC4FfnRPGUa{oOQY-3{E+hf$xcI4A&6E(#<3%4PH@WBd{}; zmoh3vmy!ngYlLnRz>RXN!J4~RWZke8g#ldAZc1b%GY%w#(xCCK%H+v2$@*CbF6T@b z!YZ|bxa5(Tlve#s$BkA?B#KI>3zVRba~fFDmYAUf(w!lH&VT~qg=`YK=HTILAWzVj zsB2t)Y|K0|X1bY6zf8ZhQ`{~dU3>j_`qty=+TP6{m-d%B_2b*MZsEn9!gk@|?c+kJ zJ9Tv@yPbV_<9O=TZehMVF?*8JvqodUC5|jU?AnDF#AzP63>mcU{$p2>ox)WDV@@arzOhRxa zfgmR#$Vmu5P9d19yo?VPaHXgoT+_iXrbXIuywG(Vp~qX1A2gW!oe0(Q-B>6*W(l;( zckiM;q|ji8nKxRY*KX3c*aFPSpABz=^c0NoNlL@&(@}&cdwLG*-zz-?X7An3c*pHb z?N^iV=;KcZ)@uxGGx}YY^=3z~{@pu01ZGd&vpWlWpX`q&;gNlJU_WyQcCGnTma%zQ F`EO9Hn^6D& diff --git a/app/examples/__pycache__/ic_examples.cpython-313.pyc b/app/examples/__pycache__/ic_examples.cpython-313.pyc deleted file mode 100644 index 026b8e0fb272813ba5b53ed191bd8535fae50aac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1739 zcmdUvO>Y}T7{_P5FZQmJs(GPJ9MMeM24nX6$d0vy*UaMf)mfI<5ERbAa0Db&&xdjXLe@x zXCIA@8VJTu56`cyCPkul zjiuHUOS95fGFB#s))c1xjYbEJQPUEgVPz9tx|z<8w7-KTZf;V)<%JyADK3}r0xn0? z7fC4$A{KhIU>M~R$BecZZK}$fJKYZ)BVFBOtD96Ne{eh+&G(zSRCAhDHj_>qgt)2?$|Dld*l>f5&~>Qo)?fkpcfD zJV!r*xri`ab`>p2$JJ+?B~_)RXFHE;R_f}p`gQ5j@mzfj!Aj53%R~Kh>dHUV)u;88 zr4O13YW!61mDJ9r=8f~lyi~5ed!SmNDzrILz?g{A<8REpvkhrj0mHF`6Ej=39v(X z!F6_|Sa(9d6$a3GFYagv)2 zfYvw_t~=uF!=Xcvkk^CY|3+R_2KLl{$KDvQXO_%6g1pl0YWarA#Mw`Plvhtouor~r zj4-3ZoD$|V7+~-(hMtPJm;;b7n}8rbGvtFfBouTwUfTsYrl5Eh9=;0Z1ROK}1&*1Q zdgGIaSq=C&CHR;~_%H+?hTsFtkPmELmi8`4<|SqCq6Tq36Q^yv9y+!iYf-1=22Cb@ z4zW^qohX)h#1fceWhD%~Wa~TV2n1+w#>{JeSZ{mu4TfP({0ng(Okb8H=`f{8%99Z! zo$YIeq1OL&=ucF+~WkLE%AA$Qi>XvpVx^I8;S(5HA Tzd!IFl7VlmJrOcC3vc`rIMIje diff --git a/app/examples/__pycache__/mcp_examples.cpython-313.pyc b/app/examples/__pycache__/mcp_examples.cpython-313.pyc deleted file mode 100644 index cd4702c48034162b1e63cc53206159a9586876f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1881 zcmb^xO>Y}j@a?DVwd2Ni6ud6bO%qTT8XJ*TBtVg(q?Ho#MHXKm(rUZANjJ53w{O?M zj*1k)FW^u?PEEz794dtqJvMR=Jv#Ei)~bg}oO*KCKz3H#2YE z%p4C42ng2G!;#HDScHBhM7R5pvNXM6+WuhO$5#VXQkL3u4 zk%cg+G|Uq~LdH=7$XiI;d6kmy5w>))f_$ND`vpVuwZghpRdsj0pt)`#d}e{nm5|80 zwIE}j%qg`uI>_L`IWS1(rgsrK^Eui?07SkZ>8q;-}*)VS$??Ce1C3d z{+W<&3AsZd*N(paEH~B`-@GgCihCb5#X>v##@*O%Z10_BcDyZ~KZ8(*F6DICUsaH9lNu zii<5#X?&)H&Ze5;cuSnvPj_NyXsm;{Au!A(`JHQ>B#LLk__F^V-_x}C!`pjf_t|E8 z{3y;ttVt4UrW>n3ViicN1Y}Vny|Z|91>!y$21iFp;QsDSLe{>S9+}Ni2cy*N5PLAz zCF&eCJIvPk=?F+34^XpN_HnX{4^xDbC2&dRgNUjcj;^W!@7G+*-oT`B0@ko}KVV?u zcfaN*bPQaCMIwuSTy~5~$@~P5015wvye|NB7>c5fXqIAMBoOslhaaKR_a{0Cj)$Y& w=j$%7gU}3pjebF{V+qXv2^KxADgXcg diff --git a/app/examples/__pycache__/noc_examples.cpython-313.pyc b/app/examples/__pycache__/noc_examples.cpython-313.pyc deleted file mode 100644 index 5cc37961c29a9e1a37fbc1948e796609db8a6dd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1828 zcmdUv&2Jk;6u@V_>$SbM(^8jEJN=lD0@(s~piQf&fMi9Lpa@sWVk9JsWx6|YH?en} znROaVfDrr*J>-;fBL^gUGbbAL!UZW+4mBeVNSu0eWhw+G-mJY8Ra9``!btn(y_vUf z-oE+m8|Cu`g7M?s*|i@ugnpJrJaQ9dbPbdn$U+QRij{aD$z zi6r<~$%ba>jii-=Cv9cUnMSiJf#>{uWhftTcXuH!2ICd$n zU0E(021v|khfz-bkl>KEXq$%2BRJ?#MjS8jNvn*n;OhZfUu^}~u^WIFL?I!?Yj?iD zwC#Z=qb)4F@{$Y)$|8=J&X@5e9#W2Je0DqFAtP-}H{nRgg}7dHjK}dtmtunXMwhs_ z6S&ln!950NfEhVE?9NxA=LEcL+?Rzk6`@xBo=68*Ic1xai6jppHIX76&+f98$V$7* zZ3p5BL#FLJJ-f|?&S=}&t9pZs$_QCI6gN?Es3R(eT&3)s2_8Ez^!)LJqJ88lHE z)sh#~RmIHIgu1ZssyOTfK2(j95N_IDr#)eC%DFT=S7e}A#1EyKCQZ05&`h1>;k($B z6o)_v9ZFq?N*m)!FUvw_CWU^7|DK~;1bCsm><7-SA~H_UhTDW_y9tq&H*CX(P@6O~ zlMH?r#N>@IU5b9I<;eNoBOBFACxZKE3Nbwzg_xf z>2~Ab;>w_Sa;Lamym|4USQ#8Uv6I=(+&pt|?B&7qi9zYPL2>RuK9w^nk(z8MM?nyFAdKa7BmGT%ib*hk|}OuyC++-{4$ z!Crth*_!xAAcm@@VLg^xwSoNo4N7_x^Zpu8rq_Ka_6lc}U<7MCGZI diff --git a/app/examples/__pycache__/observer_examples.cpython-313.pyc b/app/examples/__pycache__/observer_examples.cpython-313.pyc deleted file mode 100644 index 3c3b1aad79f229b4fbb6d4cc6cc74f5522ac34cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1337 zcmbtT&u+PNj_sv|G_Ng!Bi3R*GGV8iI{HO@&%Zt7Ug$mfE}9 znRSFYAVmLy9#GG{l~du=925cTTfOEYO1ljIzQKp)Slb?Ewah_Qk1sg2yU%!*pF)dz$a|1+lS#{nUQ|BPvp zDMx)(r5$9T#+R^`U===8*Reg_5U=}j1cT==@;Gw8rUPMe%DLQx!L6Bk)u~;rUB0r~ zbQ`q`&1$_V46j3@6i#i06`)2YU+k?Sz3KImF6B-(Z+HL&crQsDfxDQ^!ZfecS}PEz zv9c=i%?hctzNiVkx<)>4UbfYLB8md@!mjJb0kt)uc4#W{v=>5RUl{u!iZj$6q3;H6%9J-q4q$$HsKl5$pWIjh&rEKV{IM`VVOxpV`HkGXrz z?WOvii+`9iJLde* zoF5qrqoa#I4ek#%=eNtB4vpGq=J+^|rb=U^P3eCkEvEwlHI1fbcg)hzERBpeU(Q+h zH%{?I&SUb`&}dImy+GTQsdne2n$FZ;`~$es-IdoWOL(h@D<`$B8C&9WxZ-GA=ideV z=mf5u(jL97OYC5&Pf2a-BJa9E?7Obe(?JqO9VXi^v>^0Tq4JdNckVvg11n;0$TQ=7 zFAn-$`UzWrt^BF^X;5PoW4x=VSbJ_Fd~~eOV*ST6V+5ZE>1Oqp+0D-$-rnE-cI>&d IvJ$ZV2Kg*E4*&oF diff --git a/app/main.py b/app/main.py index 9649c0b..b4acf43 100644 --- a/app/main.py +++ b/app/main.py @@ -32,7 +32,9 @@ from agent_framework.cache.cache import create_cache from agent_framework.billing.usage_repository import create_usage_repository from agent_framework.sse.events import SSEHub from app.workflows.agent_graph import AgentWorkflow -from app.workflows.backoffice_native_runtime import BackofficeNativeRuntime +from app.workflows.backoffice_workflow_executor import BackofficeWorkflowExecutor +from app.channels.backoffice_rest_adapter import BackofficeRestChannelAdapter +from app.workflows.backoffice_workflow_dispatcher import BackofficeWorkflowDispatcher from app.identity_extraction import enrich_payload_with_text_identity, extract_identity_from_text logging.basicConfig(level=settings.LOG_LEVEL) @@ -69,7 +71,9 @@ identity_resolver = IdentityResolver.from_yaml(settings.IDENTITY_CONFIG_PATH) agent_profiles = AgentProfileRegistry(settings) sse_hub = SSEHub(settings, telemetry=telemetry) workflow = AgentWorkflow(llm, memory, telemetry, analytics, settings, observer=observer, tool_router=tool_router, summary_memory=summary_memory) -backoffice_runtime = BackofficeNativeRuntime(settings=settings, telemetry=telemetry, analytics=analytics, observer=observer) +backoffice_executor = BackofficeWorkflowExecutor(settings=settings, telemetry=telemetry, analytics=analytics, observer=observer) +backoffice_rest_adapter = BackofficeRestChannelAdapter() +backoffice_dispatcher = BackofficeWorkflowDispatcher(channel_gateway=gateway, executor=backoffice_executor, telemetry=telemetry, adapter=backoffice_rest_adapter) logger.info("LLM provider carregado: %s", llm.__class__.__name__) logger.info("Langfuse habilitado: %s host=%s", telemetry.is_enabled(), settings.LANGFUSE_HOST) @@ -498,12 +502,12 @@ async def shutdown(): # --------------------------------------------------------------------------- -# Backoffice TIM/ANATEL develop — execução 100% framework-native +# Backoffice TIM/ANATEL develop — REST como canal do framework # --------------------------------------------------------------------------- -# As rotas antigas permanecem como adapters REST, mas não registram routers -# legados e não executam legacy graph package nem legacy executor package. -# Elas chamam o BackofficeNativeRuntime, que compila os workflows com o motor -# do framework e aplica guardrails, judges, supervisor, checkpoint e telemetry. +# As rotas antigas permanecem como contratos HTTP de compatibilidade, mas agora +# atuam apenas como REST adapters. Elas traduzem o payload legado para um +# BackofficeChannelEnvelope, passam pelo ChannelGateway e só então o dispatcher +# aciona o workflow LangGraph registrado para o domínio. from src.api.schemas.anatel_schemas import TicketRequestEvent from src.api.schemas.anatel_response_emulator_schemas import EmulatorGenerateRequest, EmulatorFinalizeRequest @@ -599,29 +603,23 @@ async def native_validation_exception_handler(request: Request, exc: RequestVali return JSONResponse(status_code=422, content={"detail": exc.errors()}) -async def _run_native_checklist(event, request: Request): +async def _run_native_checklist(event, request: Request, *, legacy_contract: str = "agent.process-ticket"): from src.api.utils import agent_helpers - transaction_id = event.transactionId or f"man-{uuid4().hex[:8]}" - payload = event.model_dump(mode="json", by_alias=True) - final_state = await backoffice_runtime.execute_workflow( - "backoffice_checklist", - payload=payload, - transaction_id=transaction_id, - app_state=request.app.state, - metadata={ - "tenant_id": "default", - "agent_id": "backoffice_anatel", - "channel": "rest", - "legacy_contract": "agent.process-ticket", - }, - ) + envelope = backoffice_rest_adapter.from_ticket_event(event, legacy_contract=legacy_contract) + final_state = await backoffice_dispatcher.execute(envelope, app_state=request.app.state) try: - response_event = agent_helpers.build_cms_response_event(final_state, transaction_id) - return response_event.model_dump(mode="json", by_alias=True) + response_event = agent_helpers.build_cms_response_event(final_state, envelope.transaction_id) + response = response_event.model_dump(mode="json", by_alias=True) + response.setdefault("metadata", {}) + response["metadata"]["framework_entrypoint"] = "channel_gateway" + response["metadata"]["source_channel"] = envelope.channel + return response except Exception: return { - "transactionId": transaction_id, + "transactionId": envelope.transaction_id, "framework_native": True, + "framework_entrypoint": "channel_gateway", + "source_channel": envelope.channel, "current_step": str(final_state.get("current_step")), "final_response": final_state.get("final_response"), "error": final_state.get("error"), @@ -631,17 +629,17 @@ async def _run_native_checklist(event, request: Request): @app.post("/agent/process-ticket", status_code=status.HTTP_200_OK) async def native_process_ticket(request: Request, event: TicketRequestEvent): - return await _run_native_checklist(event, request) + return await _run_native_checklist(event, request, legacy_contract="agent.process-ticket") @app.post("/agent/execute", status_code=status.HTTP_200_OK) async def native_agent_execute(request: Request, event: TicketRequestEvent): - return await _run_native_checklist(event, request) + return await _run_native_checklist(event, request, legacy_contract="agent.execute") @app.post("/agent/process-and-stream", status_code=status.HTTP_200_OK) async def native_process_and_stream(request: Request, event: TicketRequestEvent): - return await _run_native_checklist(event, request) + return await _run_native_checklist(event, request, legacy_contract="agent.process-and-stream") @app.post("/agent/search-tais-kb", status_code=status.HTTP_200_OK) @@ -660,31 +658,23 @@ async def native_search_tais_kb(body: dict): return {"framework_native": True, "result": result} -async def _run_native_emulator(request: Request, event): - transaction_id = event.transactionId - payload = event.model_dump(mode="json", by_alias=True) - final_state = await backoffice_runtime.execute_workflow( - "backoffice_response_emulator", - payload=payload, - transaction_id=transaction_id, - app_state=request.app.state, - metadata={ - "tenant_id": "default", - "agent_id": "backoffice_anatel", - "channel": "rest", - "flow_mode": event.flow_mode, - "selected_actions": [a.model_dump(mode="json") for a in event.selected_actions], - "legacy_contract": "case.response-emulator", - }, - ) +async def _run_native_emulator(request: Request, event, *, legacy_contract: str = "case.response-emulator"): + envelope = backoffice_rest_adapter.from_emulator_event(event, legacy_contract=legacy_contract) + final_state = await backoffice_dispatcher.execute(envelope, app_state=request.app.state) try: from src.api.utils.emulator_response_builder import build_emulator_response_event - response_event = build_emulator_response_event(final_state, transaction_id) - return response_event.model_dump(mode="json", by_alias=True) + response_event = build_emulator_response_event(final_state, envelope.transaction_id) + response = response_event.model_dump(mode="json", by_alias=True) + response.setdefault("metadata", {}) + response["metadata"]["framework_entrypoint"] = "channel_gateway" + response["metadata"]["source_channel"] = envelope.channel + return response except Exception: return { - "transactionId": transaction_id, + "transactionId": envelope.transaction_id, "framework_native": True, + "framework_entrypoint": "channel_gateway", + "source_channel": envelope.channel, "current_step": str(final_state.get("current_step")), "final_response": final_state.get("final_response"), "error": final_state.get("error"), @@ -782,6 +772,8 @@ async def native_health_ready(): "workflows": list(backoffice_runtime._graphs.keys()), "framework_layers": { "gateway": True, + "channel_gateway_entrypoint": True, + "backoffice_rest_adapter": True, "identity": True, "session_repository": settings.SESSION_REPOSITORY_PROVIDER, "memory_repository": settings.MEMORY_REPOSITORY_PROVIDER, @@ -802,7 +794,9 @@ async def debug_backoffice_parity(): "legacy_graph_execution": False, "legacy_router_registration": False, "forbidden_active_imports": ["legacy_reference_disabled/original_develop/src_agent_graphs", "legacy_reference_disabled/original_develop/src_api_executors"], - "runtime": "app.workflows.backoffice_native_runtime.BackofficeNativeRuntime", + "entrypoint": "app.channels.backoffice_rest_adapter.BackofficeRestChannelAdapter", + "dispatcher": "app.workflows.backoffice_workflow_dispatcher.BackofficeWorkflowDispatcher", + "runtime": "app.workflows.backoffice_workflow_executor.BackofficeWorkflowExecutor", "domain_package": "src.agent.nodes + src.components.clients + src.agent.local_prompts", "workflows": { "backoffice_checklist": [ @@ -814,6 +808,8 @@ async def debug_backoffice_parity(): }, "framework_layers": { "gateway": True, + "channel_gateway_entrypoint": True, + "backoffice_rest_adapter": True, "identity": True, "session_repository": settings.SESSION_REPOSITORY_PROVIDER, "memory_repository": settings.MEMORY_REPOSITORY_PROVIDER, diff --git a/app/workflows/__pycache__/agent_graph.cpython-313.pyc b/app/workflows/__pycache__/agent_graph.cpython-313.pyc index e0318af428e45a1d6e67c8652099bcd00d64a813..e7275a04c5b0c6444daab827f637adb097b049fe 100644 GIT binary patch delta 6135 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 S6@o9iSYs|L`9uNA;r|B^w!|F( delta 6141 zcmb7Idu&uy8ozg5oxWRWr*GOq9}M6K*n&I+D{ZwBhWqA9lA>+IB^c0Dn1$8s~cRYC@BVS&AsybJmmoLqf+VTpew)|QH z<|Tl;Ly+!uoNKif?^O?pc;6%?vLpWR#U@J-p34 zyR_Tw83=6N?DZ%vPryH{u%Ndm;M&aGgUU#N4e)*DHF8DdWAn?#jCr(9v$#D$Z@|wM z^25p9xgfC`z(T+xz+!Goxmzyf8&c|Li6z#yx|XK)ri~4nxvsf+-3EIqn+3+%06Tv( zrM4(8M@=PSS>j<8JR^01TphVPbxf9L@^{l3bmk;1t|ZWmYLIEB9hqTm*$)veUqHI{7P17>cscYvP);0ml!)FAM_EAvmibyijH{6@AG(9c6n+^d@7gk z&7LgkM$whw%s78}Y*ZT^(3Y`dN>12EJQHRU$F#?0JB+omKBm>VF{<;n*l5yxo+O3! z3Fm^FG9>hj?J7+Y5Yt|AE{U%C;Zu4#q}CPuT+(!-)Vh=hr`yA64vXLFY|v+EUapbnOC8pF zd67&TB2dNSY>JJhaKvrwT>CQ|2s`mO*T+T)88u>?xGS6;H?jzhxpBJG`XGOP)^zfN zc<7LENA*hfbiOsGUT)`a<*W_26N8pI=-%RDN|1RKl|4ulwvoUtYso>yrwr1>qm&+u zKHng73I1Rp;B&D+D5x;IMbMaAOfYw^OI6q~~ z29?18dvvb8_yHoZX#nuB9smR~TrADhP1~`h{9JCXT+BbpJ(^XBIS&Al#Jc%Wn?Iba zr;IL86adc3glHj9h!)38bN4F#ple{n&3aWenb_jlL{AEEm}aX3*9OXPn|*;1hs)*l zdxI`lC(Wtf%96BQx-{Lk*LulTyf^hy!A$;KUWK`+>O*TjKbv>8zo_y^-^HT(F%uCk z+p3OiIoov6)-q-y-b%;oBWHu>AG)xq>+dVw7ufK1k|?h-T+@HPk)#$wtAU6uhE5Ri zL&VJnKZx55O-3R{fAUuwc}78>1p(wS@(cEy$o>MGY%QmEyMYDxi-jebh)~r;P_}*h zc1o98VT~N-nME&D-VZjDZn!Xw+2eri1cJY-tE-Io|4~$0hzS)*<$v3y>jpz|^*0tN zD}OALRY!7)$EcZV!O28{hV?@`Sra= zTp!wM84hnxVxv6gWI5kcS)H|m2y7={7XTC0{Nu{${D;c6nQ$hl2Boy5?vU5lqp)bf z(!Dp#hpI~DCnNi-mKx=1{=R*~?0SgdfM*HD_0{Y#8c$kzn6I8QM}CQi=2Vz)DE{y^ zTO=~akz9I=-ZZnuIG!|dDL7AoGnu))KB~K7@&+Z{gTtR-iwod*p|99=2+$qbk5v%8SEILpL8SD+fn-kZ9a29Zm z;0JznQK|e6PhNZiFa3z;_<3zP=tA`M2ua3J$?{)+6?{n^D8y^@~e^2J0q#` z5MNebn)L$B>Yfscj`RL{N7iu=2LK{q_wi%(^HzO=_bUL=`7EXpMLBGxnMDR-Q#dYz zSFo7`8~cRkHB@>))-qbxb+k9Q+8UZ0R<$?OMS@R@^{WBDU1lF+ znI*afjoBCca6?}B638|tOpQyXC(!pX5`KezT8c>ft|1?JGXR1~>FHG_X!0re;|jAO zyowVEw)r23HJyKz%gWWoRnvpKg#4Gj$iSdiVK(SkSMh?lR;=PjM-vYT(}yb|4K;3;C>T7VA) zQAS1JI})E1x4L)e=6i$s6#vONOYZ08n?9w@<%i~)=Y0;kh)5iR;%gLyF~DxX9zgVj zJWI)MnsOYfGh%f-mRg7+Zg3hta)uR`ev!{Z4tgw_{tV;u{FUy|dnBO5sG=sauQ2))y_II| zbNhRIRADvikej~z+&i5t-5re%Kd) z#r(&<9V?&~)rt72gbJ}PYjaLmw4Vj^SrfmbB!gmt~3H3EbhW)xP1{S5>hl8LR`@p=^? zLLw;^X~`h11gs#?lGfeRW@%`Bpn=Wi9V2Cp%R$UUh>&3rpKhu!iJnF;X3@qRo{fIc zWArb8Fx9*KwUHu=2&7-~%Oe%?iHN-AL|T^6Q)sWdn7{sHS#u&)A+@s?0dXg27WyVZ z4-t0;IedzrPGN;U&$sO=t5hl0$Ty(c0e=F#1c}5W;u4D zz~q)lcPJVnb^!o4lJbc=eK)9efDa3SqWQ7VNYvBl?RuK*Ur6Upkqwcq(N)&D33HEQ z5l&2>g4RbuiYorbBRnHKVdoz_Z7YtuVsa;pwWZJO&kZNSQbcJ#O=xMcUeD$B`IsNP zLQ4^%&}dR$P)aeYB}G#qtDv{3UBP|`onANT>#aXTT}q=N@~i!in{pFM2@gb%Uwv@a zdJ!wQ6=b?8M;(Av3sZ)@%7`%bq>N<<4BRYR9pJw`SRrqUoIUuxC7jqc5uSQA(c34S zL(8nYx1puowQAkk`SJIj*HgWVc;lx7~<)hW04+rqFUW> zJL1c=G`C+Jp*!vAb2C-kkFA+{@%97;hkOdP=G1RbF;YB@MEiSxz#}3N2Ftlg`|}Kc z|4^Yk5c%@Z2PqcaKK#{VOET>^Yf^~*l;HCAuyJk}cP#%1stggtLTe>VaRQvCpu1Pq zGQ{y*u~uVZZs5N0*}ao3rKON&e!t?w4)qX)R&Q%oY`Mej^$!OI6rsA7uDhkJy{;8b zxw-KgA*G)GFkY29VJ|-Kc**i9IXRKBeL_=_gs8Fz`z?i-tI!sgn2qqA$LG4&f-l+S z^7!1U>T3^)wf3D^Y~1&jf91NH!(0_+3q-4|QB|0B`Mx6Sco~&C$pD5a()w29{kYK!Ktte3Pt$+n|Te>~cw&k{$E` ze0)1IZ)V=iyqS4BEiC~8zZLH zYpvN?ZpKaBGal-(zPVZNjF0+w(n0!(;O-)VC+)JiQGec>@IA$k1Y-szMNxH0FQ|$J zpX|7@o^Y9+Z%UaJHJ2-74qXlWJ1Skt z71f&)x8%&4uF{OHfIYMJAG0$Fi+kjkgfar5E`gz};G&$s3S5#A0;v0S?z)S*0pbBj zQ1I3u9w8+7a812}pZfA_qGh*sj`X(*T1nC~%QAiH2T{_83?Y+LT9t2tddG88rl92c zY@LYDsg!S=frm3w%REw%#~pYeEg1+*N}4`?Wtykznl5X6Mk*G0eYv3RW_7cmFY^+g zu}#R!H5(@RtIP5(x+?j;gCbuvRMCrlfL4FRt^t3VgEas#H+w(s;QR3(3G71dF%E zJ_A0n21Y!_DMSaevj~fOWU;Mip>SH{iw-4OJW;GgG$9MzdFE)1Dhv0CCre&uQ@XZT zAjR5!A|wx?KbLTu;o339ylqC)=jdnpb-5_7$~s-A9^gQOFu@K^lZ!dpf{<36!VXSz z!-~gYUQewmdMcZ`EKKuPsCpgDp{1lem`tquPgFC7R7PDbNtz~JtKYViR4S$FVU}tj zLO{($a6JJlYga4?d+S&h6 zYcm06ChcU5713NfU^d`z7zaO_sb#%{7>dF(3{5m;U)llzVu8(`_k@rQrCi82#mP*#I5Hgb_~8$ z=04n)5{@1Vo_#G6axCKfFAe|5juwZ~`4?J~+$(J986-Y3#mqhOk-5LXPk~>{88*ix z!gHnLoBM);Q5l zLsDq!twYc5fr4CTk*+4XI|hDCecj zy2X`B867fyu%3BA;Z~hWiUtVimrxm0o8o<-7-|X5^p>RcqAF$SAOa7-Wcr|rK%LX2 z+kLx)J6x0Xe4aH!nKeqWOhBzJnQoa` zEo8tMd628?)C||Eo9O6_yMh^br=BL`m z^nJY&J7vV?ANY*3SITFvRL;&_|CwWV1hUf8hT5gQLdiOnG#s(m%V|b!cN?6|E%%I8Ls28dmqUCt+G9iq%h5qg+R1YF$?Cy)^+4}dko3L*J9`7b zBNn(D+-j|BHo8}{&7Sy1@T>3_;cr?i{8**u;$~;>rz@YUpQ-ormA=!J&NJJ7_jypt zjY_#uDV##2t^2XB>)8}T!n4eFA85PX3gWg~0s9~A=iuBs$EMz3{=`h3T7jw(y_P19f2R})E zoHQas<;c*6{$TWRWax2Z(g;mfLX-dA40r4h#(%nrsuD>Xp>!pbuHoDN7HZpK8GrkK zwP|2}hZ#T0eAt^HUoc0wFS!KyBLco+66EWnRY?aX-8^DyGZb<72*hn;?0_gm{h z2G@sKfP-zYXKZTl6FwV&-n83(OjmaAZ^3ZS?Oo>B`!eR==jT*KPI%}~aVtI+tfWYB zzv-c}zDAWFS}}1iK^}dbhllvDfcgRw{sbq?v2+}#i!hm-#mjgg*@v`ESU!%j@=SMabK(cU{j3=N@O^O25s#%RDE8?(XN87>~Q%W`UdL zpa%e5b8B#9(3N6fnI3(;1g}Ti9E0%UaH_MGY!pqA!Yfv+y%}vA;uSEDA-xmkFKlpt zqVuk!mglTPOvBd3!A##d+jm5${6N*(*I9#@Ly#4d-99to^wq5GXj&f F`G1o(C1d~q literal 0 HcmV?d00001 diff --git a/app/workflows/__pycache__/backoffice_native_runtime.cpython-313.pyc b/app/workflows/__pycache__/backoffice_workflow_executor.cpython-313.pyc similarity index 60% rename from app/workflows/__pycache__/backoffice_native_runtime.cpython-313.pyc rename to app/workflows/__pycache__/backoffice_workflow_executor.cpython-313.pyc index c39919f486b3e03419fd229a9798dc187ed1b26b..1c56f5c776b407363d442eae021df6e97144bdfc 100644 GIT binary patch delta 6965 zcma($3se+Wmi4OtMFR~@)6gF%K#cqvP*M4*XrzHgFqR}365FCFpcSfns~Z&Z!6a(b z{MLChG1;>_>&ZG3b0*1XYBrn1m{BppL{Ef+Sv+j!#K}yOaduAz95b0DlVtBJXj+r8 zXUfCvTld|2-+lMp&#UMEO{l*5K$Y;P_;`kb=i%pyw%K1kp71q7M`RW~hiydr-&?9v5VPKh+ z@&`mV9AH>QqEq5~1;Ss{%Zq%M(7`tHVwYRugWbixZo#)b81ReX;xOoN^a^2VfDQVC zLXTe*Dw%wikQHhneo9rdij@R1Kd6qX4eStw4#FF?{;oOmZuf_Rd>CetSRdch6T+XW zQmgsSFuZSE$8BPR{6J5D?|@ZE0xJfjUcSda2o|;vD5kIN=0#EHal_Jf@L(4o?v^vv z57U{B_IXFSBCha8Jm#bD=@ThAv-#$Mf`YG0r?2wwC?g^KxLus9+ZDvl0#BgA=a z_+6b9RmmUgzNFD=`8Ui_8a2rW;-_?|RTeC-(&!*|q+#?!`B+-L1|5>Wbe0fW0b5Q# zgYZSG1>eVpRS7l<|Cy~GD&$gZ)Hbzb;R-p6f~9gQr`Enho`=AVO{_x#pS;ekssLQnt4*6efd^ z6X9;4b#*gaw?>z+Q3!?S@}Q=J9|{8B)~$;1H*($ey@Ug%P(WEpR2SPWbo2c%XODlo z0H*l@QZOJvcCo(MOalhkt66_XGJ&kbFZKtv3mq;-=Cf&CZcbEXWa3B=xV&D!=ns3n zXXQP48#E4A3|4&FWk#RKbny@A{6#VNydl0*@Cv=4*6;gFK3V!9U6A*W@rwc9SMtcx zkLkjHP@qfdp^^OG%il%?F-=meX&>HNIZml%Mr_ZXSsFpb%m7Y`K zmkQEu=Tv2L#)-PtE{;}HqP|7HXpX-F#=7V>`@Fa|!rh|g^tS;S6q+&OQx+6cW%MkY zXlT)!sk#dkB{FT!c~NH0x=#}g_}I4Ow1_4#u5E6`pp7t%7dr6Pu*p4&3llg*1t zX#DjaD}KM4Rj2eVre9gviH4Y(o~}NqP2#W&sRy09BS6wV%=fYZHWViLCkZ~G-QN*l z2?||bgt4Z82!*Yg-2tsSC`e4CKk}>qM*>LRUPxY00<|Mh$oBHk{XrQU3_vYmf!;p+ zLN7b~0z1?pbP8g~-w$KF#53aXe+1yjAW41gyaX0>NqlDj#7K|s3-N3ROwj8Og=X1U zp`T1JZ@7yYEa$fSgF(O8r7Xrbz}By2+a-TT7ZhpGB0@@3=Z2t`5PbrhHM>M8Be|g_ zi3H6HXv$c>HncX-(R6)SY1c3J`>3<1$7686) z^&NP8_47kTv1-Gtp#SXXd& z;5lkHetvBWeMBvPvvv!DQsPU;J94tJ5;v(MX-x7)M9t+lWIt+ikm6-s0L3d4j8h)Y zv`L*naY=1Sq=w-cS7N*zf*0YRP0f;wf!({IITS!$DJV~$doLhI^KGTvHig#jb} zV4b8hx1dexwp`p=n`usoD2V)W7JQ)AWB!?*a-*ir3anOOG5)ajrzRk(^iSa#gsZ}${IIi9nL@6e#umNIn_3qS~Q+obhPtW$3$x7 zq^WYuR0-5W;z4mT75}(l|BXi3tk4$I)}Tpi%_VEiHCmmNe2vinz*{|)L$#;Er#i>7 z*H0TLyK9=#*i%2JG?vsE0;Y|W#rD;7qAtny<+X)WQq>F*o*}}YH%D}W+A(X*UqinJ z=RJ~DZ$d|qJ5l=+6<|kelIoVJPM0Hhvi5XE2HIe9cI1d0nn%Gy~OT=|?lQ1kcp~eKcQPSFlVqT0#Uy7b|cn z0!5?CwDs}2(JEB8$~X$s#Or=#(AAspnMP0f4d?0a28PQ^LUJXE3=25p%U#sxw9Ak& zLjjoHBClP4QR^&O@Z8Nn*|+%Way7$Z*i`%xx2<>`Bw2!|nStmmOLEUjJ6bjH z0bkzils}NZrBONlps%R7@YaU9yz}2R-fex*u|pIsujofKEVp83En1Hs+PTUZW2G)H zUbWLs>uLG(on`cGt;9VHfWZZ^Jc>8mcL!?4&)w%KiP@Z^#=(In7ZH9jeA# z?{7iX@~ijnMX|p=$f?NRBjn;O4}ODu_}-!7g$rW1qe}>T;rtWqF2p|{3ZvKL1-m9` zmP_CgT}-4Au@oH36F8Gc-JlWm&?fbGI-G)^+GAA1Ni&JGy2PXwEtkxhxfB=8S-4bO zI%tIg4Q*GKR&G2;g23MtLEhJwFPFJF%)MvaOs?_1wpU1 zx2T}Ss!C7^5}6D*r{bjDDUQ}{oTHqEV=Q&!F;5X*QSBMm`girzJk(!i|eCde)2z@I!mex&?Dqt8k^zojLHxjhm5U2v#NzCAi7t8M2|_Y+FNq z>RHM{poML=p|fSShT^oh%@zU|F+h2HiM3%Vb&g2`{9HEjXw>I&DghtKKpwq%B$G&u zQpp|{HJXe(jC$0ZPVhqHF{($4Gz4E#li^9A-$}N5GU#{m;y~b?rHp5YR=u-Q1uy3j z^3baDw3^_0L?DAe?z~Zf35>_CIiE%ox(yNBu1IAto&wGJMG8G15xhX5yO_ob)%g|6 z8p~7{T&S^Bd!blM@G=e1FI1=+tEmgssM*@Ay0EGyqbWoEt`pu=?`AMf1-f@ZAK>|j z;GhriVr#QbeNjtzF6x-(6y3!n!gJA#2%bWCE?Qw`Ipd%2wwfx))~+L z*T0pI{A7Fj)L;_%C|34q%IFt;0nyjf2VcyAxm_d5O94cVEj57O(2hsWczMVgA(Zx0(N85d#ru=~U_-v=!kuf18_^uW3WqTTzK7 z?Rp0)&{(GLMwB*rhNd-}(VtX+PAlkjJ!XDap{deXu01H%|1Jd~y}ackmkJ8g6Tko0 v^lb0~=%+%*0Zgk9LNjz6Qh#Q{YpzP_@(Du)e(h>*B4sG!hbTAp`=1KwyIb2~5BN;RohrkPS9trN&CE2r&W~A(4^5vA3~Z zzY;&=_}1CeuD8veKJ1>|oQ*xZ*-g7`f-zvnu}zM1PFl5joOU;{({_Us?|PF>ll`wi zV0@}U^ER5ccEx12qn{3ndla^vi;En)XiGFcN3`;x9)h6;T z+i0|@mzn%xzuU9Z)ZHR%HhF@9u;liHLne>g?1%p6}J6c*imrl2>bDLyHBM#4cU zB%kN@F^243w`VZu_4+)bCEyPGMn%_LG-RXl2UsF^l_mKLIxc8qRFuNLzMyM9eqvD> zmMk{54DXC2xrU|ScF_}dNx@)PvOp5*5f8dzrPhdk?R<7Sqsi@_9qHRILqxl5t+5KIfB_c!Otcuh{@{-Jg75|xFuymGUsS})dFp^If-Qx>QahkHYT)u!W>~g&#pD){}s3?o8*Xs_6E^$;0 zgk8h#o&KP^?>BN))wh|Y#c@qSZZDV&fqS3lBl+X%-!dgj{sQGd&@&@{QTqW?`j=?; zOa6OEPOhK8CGjJP2GP3{>a$P$5|J-$?;AF=2$_)yokm6^V1cot4jf=j$brf5-)1IP zq8f%420{T2M4M_dNQzZWp4z1$!xkQMQOQdy)foYW5jhkkv%1KghLD3L=cSBXhoT10 zO1rQX1$bxDoDOnCt$9Hy;2MUE4eJ|mOf{g~(l4+a3aA{an9n|N)6Y6n=FRz-wu2Lt zOF;|{_x_E}tgMit5W)hVQEO$Mu(bK-wS&CJo=9u1!L?0Q1uVuTdSeAgkLs9PU%yYRo|ydzOa zbuh`Oni10KxOOD4127_^_%z$8NQ7~5By?vl=*QTWpGJECjjwVrLb`>GMQ=hIt|O!Y z!+y2^Ik}jD61l;x3FU*_i&nDv$cyQHa%@c*ryc3T^3T?Iai&BE`zJV(*xnRs3i|!9 zE(N7dvZm?hhLYa->Gj|mXlP!FlgQ)En{YjOvH9=om&L8_Udh+jFS=&eW0(#hB@All z1%TUVFPce}CtC{fl9B1rJu@^3jST#)$7`AC^dex|CgvVONljFm)I`$Tx_XYRwYSEafsTM9KGI8q?enMXke3DhSrm~Ys4CN`9@>G^`ZDOmL zoy?E&LQJ`t1G$GKRr@nYq-`a0ot3lKZNuDVMYo=`cR1OUxe4))>ng~tj&5bD18?S> z*`(2)uS<&!NbDa5i6JZ6jfB|ClA2Yh^A7ypg5Lyr)BfY+&aZ&}1N=te=Os_Cuftk0 zwtk10*biq>w`C+wr6*EuRJP$_a<1E6 zoA$*zv)n+!ghg9Y;HqX+O> zlDb1LJ0H7=aTBq+{u;NE_nyon|L*!DY1p5DH{&q+6Pm%p7``(|$KOQSb) zS52?&xtZJZ%+6_*Z`$Ppl#_aEm4>poeI%Rypp`>DEyi`^>Fqz}>!1;-o>UKxWtI2O9LkHCr;`Yo2X zd=oR!+pW7>aVPn^-K!1pnzp!zYj+Ow5ta>mYM7!Pni@60u7ddK9R1cN+(RyZ%U%(G zah^Y_x`st5#tGOUv|NBL# zAXtP3lF7RV!#E-fhu&tI9b7LQ4x9;4OVJPP>&XJDfsKoPy0CzR6d~23iLI$7dS*!x z((H;3KA?iVQq`S8ro9>D@xw{v?BR@*bO$eJg$zMwVT4RUPa4}Z7zZMiYjinTa4Xw6 zza=~8H(3Wm)-1^&L;F?alfzne&WwZoJC8hkFt0j6FbFvgoQ#BA2MhZ)TZt=iKn#w&^H+ZXnf;qgL4hb{9G(oxizy2|jS8iO5WO=xu# zOL9Om$?5G1G?|k{c{R3Ya+43)fKOSmJ)4`Vq*j;H((S9!Wiz(taF>g+DPM{0dEDhy z3gB0`Mx#BSdEKnHTbbAEHDGX6p|=e4m6EC_84g-y-yuN_j@7pDoauVH;q^z|l6U07{wJdA}C;qKsbxLBtj>LFCp2Gyb0Z z`9u$n#oIHLYn-4)@w#gvNpcSUiF{!yh++FKyi$&jlddZ@F$YJk6y{A*2Q_h8C2w3Y z;+N##UrA1TWLja{*MAa__M9Cc%BT9HWkb+2{j=pv4gQUSifaCxvT9;`rvU$gJoZk*<|!(mZ~dfx3YXz>Q93;! zh*ZSsn8g)+4G6DQM*MDgMx8xP{7jyC$F6ckG*@P=A9hocZ~eg57Zd*Wa7h(HA=9S;4K4^8YraG7E~ZB7PF$wY z&1}VpPydv`itYGQ7U)cr-sMU5NA(JuLifoxu;CL#QKF9%{|91ZQVak9 diff --git a/app/workflows/backoffice_native_runtime.py b/app/workflows/backoffice_native_runtime.py index 26c65e0..6d5e878 100644 --- a/app/workflows/backoffice_native_runtime.py +++ b/app/workflows/backoffice_native_runtime.py @@ -1,750 +1,13 @@ -"""Backoffice TIM/ANATEL workflows executed by the framework runtime. - -This module is the migration boundary that makes the backoffice **framework-native**: - -* domain logic remains in business nodes/services/prompts copied from develop; -* the backend no longer imports or executes ``src.agent.graphs.*``; -* the framework runtime builds/compiles the LangGraph workflows, owns telemetry, - guardrails, judges, supervisor, checkpoint and persistence hooks; -* legacy REST contracts call ``execute_workflow`` instead of legacy executors. -""" - from __future__ import annotations -from typing import Any, Callable -from pathlib import Path -import inspect -import json -import logging +# Compatibility shim. The framework-native name is BackofficeWorkflowExecutor. +# Existing external imports from app.workflows.backoffice_native_runtime keep working, +# but application code should import BackofficeWorkflowExecutor from +# app.workflows.backoffice_workflow_executor. -import yaml +from app.workflows.backoffice_workflow_executor import BackofficeWorkflowExecutor -from langgraph.graph import END, START, StateGraph +# Deprecated alias for backward compatibility only. +BackofficeNativeRuntime = BackofficeWorkflowExecutor -from agent_framework.checkpoints.langgraph_saver import create_langgraph_checkpointer -from agent_framework.guardrails.pipeline import GuardrailPipeline -from agent_framework.guardrails.output_supervisor import OutputSupervisor -from agent_framework.guardrails.rail_action import RailAction -from agent_framework.guardrails.rail_result import RailResult -from agent_framework.judges.judge import JudgePipeline -from agent_framework.supervisor.supervisor import Supervisor -from agent_framework.observability.workflow_events import WorkflowTelemetry -from agent_framework.observability.guardrail_events import GuardrailTelemetry -from agent_framework.observability.judge_events import JudgeTelemetry -from agent_framework.observability.langgraph_telemetry import LangGraphDeepTelemetry -from agent_framework.observability.observer import AgentObserver - -from src.agent.state.agent_state import AgentState, create_initial_state, increment_iteration -from src.agent.state.steps import GraphStep -from src.agent.state.steps_emulator import EmulatorGraphStep -import src.agent.nodes as checklist_nodes -from src.agent.nodes.emulator import ( - approve_draft_node, - close_case_node, - fetch_case_node, - generate_response_node, - persist_draft_node, - retrieve_history_node, - retrieve_templates_node, - router_node, - start_response_emulation_node, - validate_actions_node, - validate_response_node, -) - -logger = logging.getLogger("backoffice.native_runtime") - - -def _project_root() -> Path: - return Path(__file__).resolve().parents[2] - - -def _load_yaml(path: str | Path) -> dict[str, Any]: - resolved = Path(path) - if not resolved.is_absolute(): - resolved = _project_root() / resolved - if not resolved.exists(): - raise FileNotFoundError(f"Configuração não encontrada: {resolved}") - with resolved.open("r", encoding="utf-8") as fh: - data = yaml.safe_load(fh) or {} - if not isinstance(data, dict): - raise ValueError(f"Configuração YAML inválida: {resolved}") - data["_config_path"] = str(resolved) - return data - - -def _resolve_agent_profile(agent_id: str = "backoffice_anatel") -> dict[str, Any]: - agents_cfg = _load_yaml("config/agents.yaml") - for agent in agents_cfg.get("agents", []) or []: - if agent.get("agent_id") == agent_id: - profile = dict(agent) - profile["_agents_config_path"] = agents_cfg.get("_config_path") - return profile - raise ValueError(f"agent_id={agent_id!r} não encontrado em config/agents.yaml") - - -def _build_guardrail_pipeline(*, settings, observer: AgentObserver, guardrails_config: dict[str, Any]) -> GuardrailPipeline: - """Cria o GuardrailPipeline do framework amarrado ao profile do agente. - - O framework local pode ter assinaturas diferentes conforme a versão. Este - helper tenta usar config_path/config/profile quando suportado; em versões - antigas, instancia o pipeline e anexa a configuração ativa para telemetry e - debug, evitando depender apenas do config global. - """ - base_kwargs: dict[str, Any] = { - "observer": observer, - "enable_parallel": bool(getattr(settings, "ENABLE_PARALLEL_GUARDRAILS", True)), - "fail_fast": bool(getattr(settings, "GUARDRAILS_FAIL_FAST", True)), - } - config_path = guardrails_config.get("_config_path") - - try: - accepted = set(inspect.signature(GuardrailPipeline.__init__).parameters) - except Exception: - accepted = set() - - kwargs = dict(base_kwargs) - if "config_path" in accepted: - kwargs["config_path"] = config_path - if "config_file" in accepted: - kwargs["config_file"] = config_path - if "config" in accepted: - kwargs["config"] = guardrails_config - if "profile" in accepted: - kwargs["profile"] = guardrails_config.get("profile") or guardrails_config.get("agent_id") - if "agent_id" in accepted: - kwargs["agent_id"] = guardrails_config.get("agent_id") - - try: - pipeline = GuardrailPipeline(**kwargs) - except TypeError: - pipeline = GuardrailPipeline(**base_kwargs) - - for method_name in ("load_config", "configure", "set_config", "with_config"): - method = getattr(pipeline, method_name, None) - if callable(method): - try: - method(guardrails_config) - break - except TypeError: - try: - method(config_path) - break - except TypeError: - continue - - setattr(pipeline, "active_agent_id", guardrails_config.get("agent_id")) - setattr(pipeline, "active_profile", guardrails_config.get("profile")) - setattr(pipeline, "active_config_path", config_path) - setattr(pipeline, "active_config", guardrails_config) - return pipeline - - -class NativeOutputGuardrailRail: - code = "NATIVE_OUTPUT_GUARDRAILS" - - def __init__(self, pipeline: GuardrailPipeline): - self.pipeline = pipeline - - async def evaluate(self, candidate: str, context: dict[str, Any]): - final, decisions = await self.pipeline.run_output(candidate, context) - serialized = [d.model_dump() for d in decisions] - blocked = [d for d in decisions if not getattr(d, "allowed", True)] - if blocked: - first = blocked[0] - code = (getattr(first, "code", "") or "").upper() - action = RailAction.RETRY if code in {"REVPREC", "CMP", "SCO", "GND"} else RailAction.BLOCK - return RailResult( - code=code or self.code, - action=action, - reason=getattr(first, "reason", "Resposta bloqueada por guardrail de saída"), - guidance=getattr(first, "reason", "Regerar resposta seguindo as políticas de saída."), - sanitized_text=final, - metadata={"native_decisions": serialized}, - ) - if final != candidate: - return RailResult( - code=self.code, - action=RailAction.SANITIZE, - reason="Resposta sanitizada por guardrail de saída.", - sanitized_text=final, - metadata={"native_decisions": serialized}, - ) - return RailResult( - code=self.code, - action=RailAction.ALLOW, - reason="Resposta aprovada pelos guardrails de saída.", - sanitized_text=final, - metadata={"native_decisions": serialized}, - ) - - -class BackofficeNativeRuntime: - """Framework-owned workflow runtime for the backoffice domain.""" - - def __init__(self, *, settings, telemetry, analytics, observer: AgentObserver | None = None): - self.settings = settings - self.telemetry = telemetry - self.analytics = analytics - self.observer = observer or AgentObserver(analytics=analytics) - self.agent_profile = _resolve_agent_profile("backoffice_anatel") - self.guardrails_config = _load_yaml(self.agent_profile["guardrails_config_path"]) - self.guardrails = _build_guardrail_pipeline( - settings=settings, - observer=self.observer, - guardrails_config=self.guardrails_config, - ) - logger.info( - "Backoffice guardrails bound to framework profile agent_id=%s profile=%s config_path=%s input=%s output=%s", - self.guardrails_config.get("agent_id"), - self.guardrails_config.get("profile"), - self.guardrails_config.get("_config_path"), - [r.get("code") for r in self.guardrails_config.get("input", [])], - [r.get("code") for r in self.guardrails_config.get("output", [])], - ) - self.output_supervisor_engine = OutputSupervisor( - rails=[NativeOutputGuardrailRail(self.guardrails)], - observer=self.observer, - max_retries=int(getattr(settings, "OUTPUT_SUPERVISOR_MAX_RETRIES", 3)), - enable_parallel=bool(getattr(settings, "ENABLE_PARALLEL_GUARDRAILS", True)), - fail_fast=bool(getattr(settings, "GUARDRAILS_FAIL_FAST", True)), - ) - self.judges = JudgePipeline() - self.supervisor = Supervisor() - self.workflow_telemetry = WorkflowTelemetry(telemetry) - self.guardrail_telemetry = GuardrailTelemetry(telemetry) - self.judge_telemetry = JudgeTelemetry(telemetry) - self.langgraph_telemetry = LangGraphDeepTelemetry(telemetry) - self._graphs: dict[str, Any] = {} - - def _base_event_payload(self, state: AgentState | None = None, **extra: Any) -> dict[str, Any]: - state = state or {} - metadata = state.get("metadata", {}) or {} - payload = { - "workflow_id": metadata.get("framework_workflow_id"), - "session_id": state.get("session_id") or metadata.get("session_id") or metadata.get("transaction_id"), - "transaction_id": metadata.get("transaction_id"), - "agent_id": metadata.get("agent_id") or self.guardrails_config.get("agent_id"), - "guardrails_profile": metadata.get("guardrails_profile") or self.guardrails_config.get("profile"), - "framework_native": True, - } - payload.update({k: v for k, v in extra.items() if v is not None}) - return payload - - async def _safe_emit_ic(self, code: str, state: AgentState | None = None, payload: dict[str, Any] | None = None, *, component: str) -> None: - try: - await self.observer.emit_ic(code, self._base_event_payload(state, **(payload or {})), component=component) - except Exception as exc: - logger.debug("Falha ao emitir IC %s: %s", code, exc) - - async def _safe_emit_noc(self, code: str, state: AgentState | None = None, payload: dict[str, Any] | None = None, *, component: str) -> None: - try: - normalized = code if str(code).startswith("NOC.") else f"NOC.{str(code).zfill(3)}" - await self.observer.emit_noc(normalized, self._base_event_payload(state, **(payload or {})), component=component) - except Exception as exc: - logger.debug("Falha ao emitir NOC %s: %s", code, exc) - - async def _safe_emit_grl(self, code: str, state: AgentState | None = None, payload: dict[str, Any] | None = None, *, component: str) -> None: - try: - normalized = code if str(code).startswith("GRL.") else f"GRL.{str(code).zfill(3)}" - await self.observer.emit_grl(normalized, self._base_event_payload(state, **(payload or {})), component=component) - except Exception as exc: - logger.debug("Falha ao emitir GRL %s: %s", code, exc) - - async def _emit_by_code(self, code: str, state: AgentState, payload: dict[str, Any] | None, *, component: str) -> None: - code = str(code or "IC.UNKNOWN") - if code.startswith("NOC."): - await self._safe_emit_noc(code, state, payload, component=component) - elif code.startswith("GRL."): - await self._safe_emit_grl(code, state, payload, component=component) - else: - await self._safe_emit_ic(code, state, payload, component=component) - - async def _bridge_legacy_ics(self, state: AgentState, node_name: str) -> None: - """Reemite IC/NOC/GRL legados do develop pelo AgentObserver do framework. - - Os nós originais ainda chamam ``agent_framework.observer.event(...)``. - O coletor legado captura esses eventos; esta ponte pega apenas os novos - eventos desde a última etapa e os publica de forma padronizada no - observer do framework, preservando AGA.*, NOC.* e GRL.* no Langfuse/OCI. - """ - try: - from src.utils.ics_collector import ICsCollector - except Exception: - return - metadata = state.setdefault("metadata", {}) - session_id = state.get("session_id") or metadata.get("transaction_id") - try: - events = ICsCollector.get_current(session_id) if session_id else [] - except Exception: - events = [] - last_idx = int(metadata.get("_framework_ics_bridge_index", 0) or 0) - new_events = events[last_idx:] - if not new_events: - return - metadata["_framework_ics_bridge_index"] = len(events) - bridge_log = metadata.setdefault("framework_ics_bridge", []) - for item in new_events: - code = str(item.get("code") or "IC.UNKNOWN") - event_payload = dict(item.get("metadata") or {}) - event_payload.update({ - "legacy_bridge": True, - "legacy_type": item.get("type"), - "legacy_description": item.get("description"), - "legacy_timestamp": item.get("timestamp"), - "source_node": node_name, - }) - await self._emit_by_code(code, state, event_payload, component=f"backoffice.native_runtime.legacy_bridge.{node_name}") - bridge_log.append({"code": code, "type": item.get("type"), "node": node_name}) - - def _node(self, name: str, fn: Callable[[AgentState], Any]): - async def _wrapped(state: AgentState) -> AgentState: - async with self.langgraph_telemetry.node(name, state): - await self.telemetry.event( - "backoffice.workflow.node.started", - {"workflow_id": state.get("metadata", {}).get("framework_workflow_id"), "node": name, "session_id": state.get("session_id")}, - kind="workflow", - ) - await self._safe_emit_ic( - "IC.BACKOFFICE_NODE_STARTED", - state, - {"node": name}, - component=f"backoffice.native_runtime.node.{name}", - ) - try: - result = await fn(state) - except Exception as exc: - await self._safe_emit_noc( - "NOC.009", - state, - {"node": name, "type": "ERROR", "error_type": type(exc).__name__, "error": str(exc)}, - component=f"backoffice.native_runtime.node.{name}", - ) - raise - await self._bridge_legacy_ics(result, name) - await self.telemetry.event( - "backoffice.workflow.node.completed", - {"workflow_id": result.get("metadata", {}).get("framework_workflow_id"), "node": name, "session_id": result.get("session_id")}, - kind="workflow", - ) - await self._safe_emit_ic( - "IC.BACKOFFICE_NODE_COMPLETED", - result, - {"node": name, "has_error": bool(result.get("error"))}, - component=f"backoffice.native_runtime.node.{name}", - ) - return result - return _wrapped - - async def _framework_input_guardrails(self, state: AgentState) -> AgentState: - await self._safe_emit_grl( - "GRL.001", - state, - {"phase": "input", "status": "started", "rails": [r.get("code") for r in self.guardrails_config.get("input", []) if r.get("enabled", True)]}, - component="backoffice.native_runtime.guardrails.input", - ) - payload = state.get("metadata", {}).get("request_context", {}) - serialized = json.dumps(payload, ensure_ascii=False, default=str) - context = { - **state.get("metadata", {}), - "workflow_id": state.get("metadata", {}).get("framework_workflow_id"), - "agent_id": self.guardrails_config.get("agent_id"), - "guardrails_profile": self.guardrails_config.get("profile"), - "guardrails_config_path": self.guardrails_config.get("_config_path"), - "active_input_rails": [r.get("code") for r in self.guardrails_config.get("input", []) if r.get("enabled", True)], - "active_output_rails": [r.get("code") for r in self.guardrails_config.get("output", []) if r.get("enabled", True)], - } - sanitized, decisions = await self.guardrails.run_input(serialized, context) - state.setdefault("metadata", {})["framework_input_guardrails"] = [d.model_dump() for d in decisions] - blocked = [d for d in decisions if not getattr(d, "allowed", True)] - await self._safe_emit_grl( - "GRL.002", - state, - { - "phase": "input", - "status": "completed", - "decision_count": len(decisions), - "blocked": bool(blocked), - "codes": [getattr(d, "code", None) for d in decisions], - }, - component="backoffice.native_runtime.guardrails.input", - ) - if blocked: - first = blocked[0] - state["error"] = {"type": "InputGuardrailBlocked", "message": getattr(first, "reason", "Entrada bloqueada"), "step": "framework_input_guardrails"} - state["final_response"] = sanitized or "Entrada bloqueada por política de segurança." - await self._safe_emit_grl( - "GRL.003", - state, - {"phase": "input", "status": "blocked", "code": getattr(first, "code", None), "reason": getattr(first, "reason", None)}, - component="backoffice.native_runtime.guardrails.input", - ) - return state - - @staticmethod - def _after_input_guardrails(state): - error = state.get("error") or {} - return "blocked" if error.get("type") == "InputGuardrailBlocked" else "continue" - - async def _framework_output_supervisor(self, state: AgentState) -> AgentState: - await self._safe_emit_grl( - "GRL.004", - state, - {"phase": "output_supervisor", "status": "started"}, - component="backoffice.native_runtime.output_supervisor", - ) - candidate = state.get("final_response") or state.get("response") or str(state.get("metadata", {}).get("request_context", {}).get("transactionId", "")) - context = { - **state.get("metadata", {}), - "session_id": state.get("session_id"), - "agent_id": self.guardrails_config.get("agent_id"), - "guardrails_profile": self.guardrails_config.get("profile"), - "guardrails_config_path": self.guardrails_config.get("_config_path"), - "active_output_rails": [r.get("code") for r in self.guardrails_config.get("output", []) if r.get("enabled", True)], - } - decision = await self.output_supervisor_engine.evaluate(candidate, context) - if decision.action in {RailAction.ALLOW, RailAction.SANITIZE, RailAction.OBSERVE}: - final = decision.candidate - elif decision.action == RailAction.HANDOVER: - final = "Encaminhado para continuidade com especialista." - else: - final = decision.fallback_message - state["final_response"] = final - state.setdefault("metadata", {})["framework_output_supervisor"] = { - "action": decision.action.value, - "approved": decision.approved, - "results": [ - {"code": r.code, "action": r.action.value, "reason": r.reason, "guidance": r.guidance, "metadata": r.metadata} - for r in decision.results - ], - } - await self._safe_emit_grl( - "GRL.005", - state, - { - "phase": "output_supervisor", - "status": "completed", - "action": decision.action.value, - "approved": decision.approved, - "result_codes": [r.code for r in decision.results], - }, - component="backoffice.native_runtime.output_supervisor", - ) - if decision.action not in {RailAction.ALLOW, RailAction.SANITIZE, RailAction.OBSERVE}: - await self._safe_emit_grl( - "GRL.006", - state, - {"phase": "output_supervisor", "status": "blocked_or_handover", "action": decision.action.value}, - component="backoffice.native_runtime.output_supervisor", - ) - return state - - async def _framework_output_guardrails(self, state: AgentState) -> AgentState: - await self._safe_emit_grl( - "GRL.007", - state, - {"phase": "output", "status": "started", "rails": [r.get("code") for r in self.guardrails_config.get("output", []) if r.get("enabled", True)]}, - component="backoffice.native_runtime.guardrails.output", - ) - candidate = state.get("final_response") or "" - context = { - **state.get("metadata", {}), - "agent_id": self.guardrails_config.get("agent_id"), - "guardrails_profile": self.guardrails_config.get("profile"), - "guardrails_config_path": self.guardrails_config.get("_config_path"), - "active_output_rails": [r.get("code") for r in self.guardrails_config.get("output", []) if r.get("enabled", True)], - } - final, decisions = await self.guardrails.run_output(candidate, context) - state["final_response"] = final - state.setdefault("metadata", {})["framework_output_guardrails"] = [d.model_dump() for d in decisions] - blocked = [d for d in decisions if not getattr(d, "allowed", True)] - await self._safe_emit_grl( - "GRL.008", - state, - { - "phase": "output", - "status": "completed", - "decision_count": len(decisions), - "blocked": bool(blocked), - "sanitized": final != candidate, - "codes": [getattr(d, "code", None) for d in decisions], - }, - component="backoffice.native_runtime.guardrails.output", - ) - if blocked or final != candidate: - await self._safe_emit_grl( - "GRL.009", - state, - {"phase": "output", "status": "blocked_or_sanitized", "blocked": bool(blocked), "sanitized": final != candidate}, - component="backoffice.native_runtime.guardrails.output", - ) - return state - - async def _framework_judges(self, state: AgentState) -> AgentState: - payload = state.get("metadata", {}).get("request_context", {}) - question = json.dumps(payload, ensure_ascii=False, default=str) - answer = state.get("final_response") or "" - results = await self.judges.evaluate_all(question, answer, state.get("metadata", {})) - state.setdefault("metadata", {})["framework_judges"] = [r.model_dump() for r in results] - return state - - async def _framework_supervisor_review(self, state: AgentState) -> AgentState: - answer = state.get("final_response") or "" - ok, reviewed = await self.supervisor.review(answer, state.get("metadata", {})) - state["final_response"] = reviewed if ok else reviewed - state.setdefault("metadata", {})["framework_supervisor_review"] = {"approved": ok} - return state - - async def _framework_persist(self, state: AgentState) -> AgentState: - await self._safe_emit_ic( - "IC.BACKOFFICE_WORKFLOW_COMPLETED", - state, - { - "current_step": str(state.get("current_step")), - "has_error": bool(state.get("error")), - }, - component="backoffice.native_runtime.persist", - ) - await self._safe_emit_noc( - "NOC.006", - state, - { - "type": "INFO" if not state.get("error") else "FAILURE", - "status": "Backoffice workflow completed", - "current_step": str(state.get("current_step")), - }, - component="backoffice.native_runtime.persist", - ) - return state - - def _compile(self, workflow_id: str): - if workflow_id == "backoffice_checklist": - return self._build_checklist_graph() - if workflow_id == "backoffice_response_emulator": - return self._build_emulator_graph() - raise ValueError(f"Unknown workflow_id={workflow_id}") - - def get_graph(self, workflow_id: str): - graph = self._graphs.get(workflow_id) - if graph is None: - graph = self._compile(workflow_id) - self._graphs[workflow_id] = graph - return graph - - async def execute_workflow(self, workflow_id: str, *, payload: dict[str, Any], transaction_id: str | None = None, app_state=None, metadata: dict[str, Any] | None = None) -> AgentState: - transaction_id = transaction_id or payload.get("transactionId") or payload.get("transaction_id") or "backoffice-session" - state = create_initial_state(session_id=transaction_id) - state["metadata"].update(metadata or {}) - state["metadata"].update({ - "transaction_id": transaction_id, - "request_context": payload, - "framework_workflow_id": workflow_id, - "framework_native": True, - "agent_id": self.guardrails_config.get("agent_id"), - "guardrails_profile": self.guardrails_config.get("profile"), - "guardrails_config_path": self.guardrails_config.get("_config_path"), - "active_input_rails": [r.get("code") for r in self.guardrails_config.get("input", []) if r.get("enabled", True)], - "active_output_rails": [r.get("code") for r in self.guardrails_config.get("output", []) if r.get("enabled", True)], - # Progress producer is kept in src.compat.framework_services, not in state, - # so checkpoints remain JSON-stable and integrity hashes do not change. - "_framework_ics_bridge_index": 0, - }) - try: - from src.utils.ics_collector import ICsCollector - ICsCollector.start(transaction_id) - except Exception: - pass - await self._safe_emit_noc( - "NOC.001", - state, - {"type": "INFO", "status": "Backoffice workflow started"}, - component="backoffice.native_runtime.execute", - ) - await self._safe_emit_ic( - "IC.BACKOFFICE_WORKFLOW_STARTED", - state, - {"payload_keys": sorted(list(payload.keys()))}, - component="backoffice.native_runtime.execute", - ) - graph = self.get_graph(workflow_id) - config = {"configurable": {"thread_id": f"{workflow_id}:{transaction_id}"}} - try: - final_state = await graph.ainvoke(state, config=config) - await self._bridge_legacy_ics(final_state, "workflow_end") - return final_state - except Exception as exc: - await self._safe_emit_noc( - "NOC.009", - state, - {"type": "ERROR", "status": "Backoffice workflow failed", "error_type": type(exc).__name__, "error": str(exc)}, - component="backoffice.native_runtime.execute", - ) - raise - finally: - try: - final_ref = locals().get("final_state", state) - final_ref.get("metadata", {}).pop("_oci_producer", None) - final_ref.get("metadata", {}).pop("_framework_ics_bridge_index", None) - except Exception: - pass - try: - from src.utils.ics_collector import ICsCollector - ICsCollector.stop(transaction_id) - except Exception: - pass - - # -------------------- Checklist workflow -------------------- - def _build_checklist_graph(self): - builder = StateGraph(AgentState) - builder.add_node("framework_input_guardrails", self._node("framework_input_guardrails", self._framework_input_guardrails)) - builder.add_node("fetch_ticket", self._node("fetch_ticket", self._fetch_ticket)) - builder.add_node(GraphStep.VALIDATION, self._node(str(GraphStep.VALIDATION), checklist_nodes.validation_node.validate_ticket)) - builder.add_node(GraphStep.BYPASS_RULES, self._node(str(GraphStep.BYPASS_RULES), checklist_nodes.bypass_rules_node.evaluate_bypass_rules)) - builder.add_node(GraphStep.CACHE_CHECK, self._node(str(GraphStep.CACHE_CHECK), checklist_nodes.cache_check_node.check_cache_node)) - builder.add_node(GraphStep.IMDB_ENRICHMENT, self._node(str(GraphStep.IMDB_ENRICHMENT), checklist_nodes.imdb_enrichment_node.imdb_enrich_ticket)) - builder.add_node(GraphStep.IDENTITY_VERIFICATION, self._node(str(GraphStep.IDENTITY_VERIFICATION), checklist_nodes.identity_verification_node.perform_identity_verification)) - builder.add_node(GraphStep.SPEECH_ENRICHMENT, self._node(str(GraphStep.SPEECH_ENRICHMENT), checklist_nodes.speech_enrichment_node.enrich_with_speech)) - builder.add_node("knowledge_base_enrichment", self._node("knowledge_base_enrichment", checklist_nodes.knowledge_base_enrichment_node.enrich_with_knowledge_base)) - builder.add_node(GraphStep.CANCELING_ANALYSIS, self._node(str(GraphStep.CANCELING_ANALYSIS), checklist_nodes.canceling_analysis_node.perform_canceling_analysis)) - builder.add_node(GraphStep.TIM_COMPLAINT_ANALYSIS, self._node(str(GraphStep.TIM_COMPLAINT_ANALYSIS), checklist_nodes.tim_complaint_analysis_node.perform_tim_complaint_analysis)) - builder.add_node("different_complaint_operator", self._node("different_complaint_operator", checklist_nodes.different_complaint_operator_node.perform_different_operator)) - builder.add_node("undefined_complaint_operator", self._node("undefined_complaint_operator", checklist_nodes.undefined_complaint_operator_node.perform_undefined_complaint)) - builder.add_node("tim_complaint", self._node("tim_complaint", checklist_nodes.tim_complaint_node.handle_tim_complaint)) - builder.add_node(GraphStep.RECLASSIFICATION_ANALYSIS, self._node(str(GraphStep.RECLASSIFICATION_ANALYSIS), checklist_nodes.reclassification_analysis_node.perform_reclassification_analysis)) - builder.add_node(GraphStep.TREATMENT_DECISION, self._node(str(GraphStep.TREATMENT_DECISION), checklist_nodes.treatment_decision_node.treatment_decision)) - builder.add_node(GraphStep.SIEBEL_SR_OPENING, self._node(str(GraphStep.SIEBEL_SR_OPENING), checklist_nodes.siebel_sr_opening_node.open_siebel_sr)) - builder.add_node("framework_output_supervisor", self._node("framework_output_supervisor", self._framework_output_supervisor)) - builder.add_node("framework_output_guardrails", self._node("framework_output_guardrails", self._framework_output_guardrails)) - builder.add_node("framework_judges", self._node("framework_judges", self._framework_judges)) - builder.add_node("framework_supervisor_review", self._node("framework_supervisor_review", self._framework_supervisor_review)) - builder.add_node("framework_persist", self._node("framework_persist", self._framework_persist)) - - builder.add_edge(START, "framework_input_guardrails") - builder.add_conditional_edges("framework_input_guardrails", self._after_input_guardrails, {"blocked": "framework_persist", "continue": "fetch_ticket"}) - builder.add_edge("fetch_ticket", GraphStep.VALIDATION) - builder.add_conditional_edges(GraphStep.VALIDATION, checklist_nodes.validation_node.should_continue, {"continue": GraphStep.BYPASS_RULES, "reject": "framework_output_supervisor"}) - builder.add_edge(GraphStep.BYPASS_RULES, GraphStep.CACHE_CHECK) - builder.add_conditional_edges(GraphStep.CACHE_CHECK, self._route_after_cache_check, {GraphStep.TREATMENT_DECISION: GraphStep.TREATMENT_DECISION, GraphStep.CANCELING_ANALYSIS: GraphStep.CANCELING_ANALYSIS, GraphStep.IMDB_ENRICHMENT: GraphStep.IMDB_ENRICHMENT}) - builder.add_conditional_edges(GraphStep.IMDB_ENRICHMENT, checklist_nodes.imdb_enrichment_node.should_continue, {"continue": GraphStep.IDENTITY_VERIFICATION, "failed": "framework_output_supervisor"}) - builder.add_conditional_edges(GraphStep.IDENTITY_VERIFICATION, checklist_nodes.identity_verification_node.route_after_identity_verification, {"proceed": GraphStep.SPEECH_ENRICHMENT, "cancel": GraphStep.SIEBEL_SR_OPENING, "smart_human": GraphStep.TREATMENT_DECISION, "failed": "framework_output_supervisor"}) - builder.add_edge(GraphStep.SPEECH_ENRICHMENT, "knowledge_base_enrichment") - builder.add_conditional_edges("knowledge_base_enrichment", self._route_after_knowledge_base, {GraphStep.CANCELING_ANALYSIS: GraphStep.CANCELING_ANALYSIS, GraphStep.TREATMENT_DECISION: GraphStep.TREATMENT_DECISION}) - builder.add_conditional_edges(GraphStep.CANCELING_ANALYSIS, self._route_after_canceling, {GraphStep.SIEBEL_SR_OPENING: GraphStep.SIEBEL_SR_OPENING, GraphStep.PROCEED_GRAPH: GraphStep.TIM_COMPLAINT_ANALYSIS, "finalize": "framework_output_supervisor"}) - builder.add_conditional_edges(GraphStep.TIM_COMPLAINT_ANALYSIS, self._route_after_tim_complaint_analysis, {"tim_complaint": "tim_complaint", "different_complaint_operator": "different_complaint_operator", "undefined_complaint_operator": "undefined_complaint_operator", "finalize": "framework_output_supervisor"}) - builder.add_edge("tim_complaint", GraphStep.RECLASSIFICATION_ANALYSIS) - builder.add_conditional_edges("different_complaint_operator", self._route_after_operator_check, {GraphStep.SIEBEL_SR_OPENING: GraphStep.SIEBEL_SR_OPENING, GraphStep.PROCEED_GRAPH: GraphStep.RECLASSIFICATION_ANALYSIS}) - builder.add_conditional_edges("undefined_complaint_operator", self._route_after_operator_check, {GraphStep.SIEBEL_SR_OPENING: GraphStep.SIEBEL_SR_OPENING, GraphStep.PROCEED_GRAPH: GraphStep.RECLASSIFICATION_ANALYSIS}) - builder.add_conditional_edges(GraphStep.RECLASSIFICATION_ANALYSIS, self._route_after_reclassification, {GraphStep.SIEBEL_SR_OPENING: GraphStep.SIEBEL_SR_OPENING, GraphStep.PROCEED_GRAPH: GraphStep.TREATMENT_DECISION, "finalize": "framework_output_supervisor"}) - builder.add_edge(GraphStep.TREATMENT_DECISION, GraphStep.SIEBEL_SR_OPENING) - builder.add_edge(GraphStep.SIEBEL_SR_OPENING, "framework_output_supervisor") - builder.add_edge("framework_output_supervisor", "framework_output_guardrails") - builder.add_edge("framework_output_guardrails", "framework_judges") - builder.add_edge("framework_judges", "framework_supervisor_review") - builder.add_edge("framework_supervisor_review", "framework_persist") - builder.add_edge("framework_persist", END) - return builder.compile(checkpointer=create_langgraph_checkpointer(self.settings)) - - async def _fetch_ticket(self, state: AgentState) -> AgentState: - increment_iteration(state) - return await checklist_nodes.fetch_ticket_node.fetch_ticket_data(state) - - @staticmethod - def _route_after_cache_check(state: AgentState) -> str: - if state.get("cache_found") is True: - if state.get("bypass_treatment_validations"): - return GraphStep.TREATMENT_DECISION - return GraphStep.CANCELING_ANALYSIS - return GraphStep.IMDB_ENRICHMENT - - @staticmethod - def _route_after_knowledge_base(state: AgentState) -> str: - return GraphStep.TREATMENT_DECISION if state.get("bypass_treatment_validations") else GraphStep.CANCELING_ANALYSIS - - @staticmethod - def _route_after_canceling(state: AgentState) -> str: - step = state.get("current_step") - if step == GraphStep.CANCELING_ANALYSIS_CANCEL_TICKET: - return GraphStep.SIEBEL_SR_OPENING - if step == GraphStep.PROCEED_GRAPH: - return GraphStep.PROCEED_GRAPH - return "finalize" - - @staticmethod - def _route_after_tim_complaint_analysis(state: AgentState) -> str: - decision = state.get("metadata", {}).get("request_context", {}).get("is_tim_complaint", "") - if decision == "sim": - return "tim_complaint" - if decision == "não": - return "different_complaint_operator" - if decision == "inconclusivo": - return "undefined_complaint_operator" - return "finalize" - - @staticmethod - def _route_after_operator_check(state: AgentState) -> str: - context = state.get("metadata", {}).get("request_context", {}) - if context.get("forward_complaint"): - return GraphStep.SIEBEL_SR_OPENING - return GraphStep.PROCEED_GRAPH - - @staticmethod - def _route_after_reclassification(state: AgentState) -> str: - step = state.get("current_step") - if step == GraphStep.RECLASSIFICATION_ANALYSIS_COMPLETED: - context = state.get("metadata", {}).get("request_context", {}) - if context.get("siebel_action") == "reclassificar": - return GraphStep.SIEBEL_SR_OPENING - return GraphStep.PROCEED_GRAPH - return "finalize" - - # -------------------- Emulator workflow -------------------- - def _build_emulator_graph(self): - builder = StateGraph(AgentState) - builder.add_node("framework_input_guardrails", self._node("framework_input_guardrails", self._framework_input_guardrails)) - builder.add_node(EmulatorGraphStep.RESPONSE_EMULATION_START, self._node(str(EmulatorGraphStep.RESPONSE_EMULATION_START), start_response_emulation_node.start_response_emulation)) - builder.add_node(EmulatorGraphStep.FETCH_CASE, self._node(str(EmulatorGraphStep.FETCH_CASE), fetch_case_node.fetch_case)) - builder.add_node(EmulatorGraphStep.VALIDATE_ACTIONS, self._node(str(EmulatorGraphStep.VALIDATE_ACTIONS), validate_actions_node.validate_actions)) - builder.add_node(EmulatorGraphStep.ROUTER_DECISION, self._node(str(EmulatorGraphStep.ROUTER_DECISION), router_node.route)) - builder.add_node(EmulatorGraphStep.RETRIEVE_TEMPLATES, self._node(str(EmulatorGraphStep.RETRIEVE_TEMPLATES), retrieve_templates_node.retrieve_templates)) - builder.add_node(EmulatorGraphStep.RETRIEVE_HISTORY, self._node(str(EmulatorGraphStep.RETRIEVE_HISTORY), retrieve_history_node.retrieve_history)) - builder.add_node(EmulatorGraphStep.GENERATE_RESPONSE, self._node(str(EmulatorGraphStep.GENERATE_RESPONSE), generate_response_node.generate_response)) - builder.add_node(EmulatorGraphStep.VALIDATE_RESPONSE, self._node(str(EmulatorGraphStep.VALIDATE_RESPONSE), validate_response_node.validate_response)) - builder.add_node(EmulatorGraphStep.PERSIST_DRAFT, self._node(str(EmulatorGraphStep.PERSIST_DRAFT), persist_draft_node.persist_draft)) - builder.add_node(EmulatorGraphStep.APPROVE_DRAFT, self._node(str(EmulatorGraphStep.APPROVE_DRAFT), approve_draft_node.approve_draft)) - builder.add_node(EmulatorGraphStep.CLOSE_CASE, self._node(str(EmulatorGraphStep.CLOSE_CASE), close_case_node.close_case)) - builder.add_node("framework_output_supervisor", self._node("framework_output_supervisor", self._framework_output_supervisor)) - builder.add_node("framework_output_guardrails", self._node("framework_output_guardrails", self._framework_output_guardrails)) - builder.add_node("framework_judges", self._node("framework_judges", self._framework_judges)) - builder.add_node("framework_supervisor_review", self._node("framework_supervisor_review", self._framework_supervisor_review)) - builder.add_node("framework_persist", self._node("framework_persist", self._framework_persist)) - - builder.add_edge(START, "framework_input_guardrails") - builder.add_conditional_edges("framework_input_guardrails", self._after_input_guardrails, {"blocked": "framework_persist", "continue": EmulatorGraphStep.RESPONSE_EMULATION_START}) - builder.add_edge(EmulatorGraphStep.RESPONSE_EMULATION_START, EmulatorGraphStep.FETCH_CASE) - builder.add_conditional_edges(EmulatorGraphStep.FETCH_CASE, self._emulator_route_after_fetch, {"generate": EmulatorGraphStep.VALIDATE_ACTIONS, "approve": EmulatorGraphStep.APPROVE_DRAFT, "close": EmulatorGraphStep.CLOSE_CASE, "failed": "framework_output_supervisor"}) - builder.add_conditional_edges(EmulatorGraphStep.VALIDATE_ACTIONS, validate_actions_node.should_continue, {"continue": EmulatorGraphStep.ROUTER_DECISION, "failed": "framework_output_supervisor"}) - builder.add_conditional_edges(EmulatorGraphStep.ROUTER_DECISION, router_node.next_step_after_router, {EmulatorGraphStep.RETRIEVE_TEMPLATES: EmulatorGraphStep.RETRIEVE_TEMPLATES, EmulatorGraphStep.RETRIEVE_HISTORY: EmulatorGraphStep.RETRIEVE_HISTORY, EmulatorGraphStep.GENERATE_RESPONSE: EmulatorGraphStep.GENERATE_RESPONSE}) - builder.add_conditional_edges(EmulatorGraphStep.RETRIEVE_TEMPLATES, router_node.next_step_after_templates, {EmulatorGraphStep.RETRIEVE_HISTORY: EmulatorGraphStep.RETRIEVE_HISTORY, EmulatorGraphStep.GENERATE_RESPONSE: EmulatorGraphStep.GENERATE_RESPONSE}) - builder.add_edge(EmulatorGraphStep.RETRIEVE_HISTORY, EmulatorGraphStep.GENERATE_RESPONSE) - builder.add_conditional_edges(EmulatorGraphStep.GENERATE_RESPONSE, generate_response_node.should_continue, {"continue": EmulatorGraphStep.VALIDATE_RESPONSE, "failed": "framework_output_supervisor"}) - builder.add_edge(EmulatorGraphStep.VALIDATE_RESPONSE, EmulatorGraphStep.PERSIST_DRAFT) - builder.add_edge(EmulatorGraphStep.PERSIST_DRAFT, "framework_output_supervisor") - builder.add_edge(EmulatorGraphStep.APPROVE_DRAFT, "framework_output_supervisor") - builder.add_edge(EmulatorGraphStep.CLOSE_CASE, "framework_output_supervisor") - builder.add_edge("framework_output_supervisor", "framework_output_guardrails") - builder.add_edge("framework_output_guardrails", "framework_judges") - builder.add_edge("framework_judges", "framework_supervisor_review") - builder.add_edge("framework_supervisor_review", "framework_persist") - builder.add_edge("framework_persist", END) - return builder.compile(checkpointer=create_langgraph_checkpointer(self.settings)) - - @staticmethod - def _emulator_route_after_fetch(state: AgentState) -> str: - if state.get("error"): - return "failed" - flow_mode = (state.get("metadata") or {}).get("flow_mode") - if flow_mode == "close": - return "close" - if flow_mode == "approve": - return "approve" - return "generate" +__all__ = ["BackofficeWorkflowExecutor", "BackofficeNativeRuntime"] diff --git a/app/workflows/backoffice_workflow_dispatcher.py b/app/workflows/backoffice_workflow_dispatcher.py new file mode 100644 index 0000000..c38a610 --- /dev/null +++ b/app/workflows/backoffice_workflow_dispatcher.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from typing import Any + +from app.channels.backoffice_rest_adapter import BackofficeChannelEnvelope, BackofficeRestChannelAdapter +from app.workflows.backoffice_workflow_executor import BackofficeWorkflowExecutor + + +class BackofficeWorkflowDispatcher: + """Framework-facing dispatcher for Backoffice operational workflows. + + FastAPI routes call this dispatcher with a channel envelope. The dispatcher + first normalizes the envelope through the framework ChannelGateway and only + then dispatches the requested LangGraph workflow. This keeps REST as a + channel adapter concern and prevents routes from coupling directly to a + domain workflow executor. + """ + + def __init__(self, *, channel_gateway: Any, executor: BackofficeWorkflowExecutor, telemetry: Any, adapter: BackofficeRestChannelAdapter | None = None): + self.channel_gateway = channel_gateway + self.executor = executor + self.telemetry = telemetry + self.adapter = adapter or BackofficeRestChannelAdapter() + + async def execute(self, envelope: BackofficeChannelEnvelope, *, app_state: Any = None) -> dict[str, Any]: + msg = await self.adapter.normalize(self.channel_gateway, envelope) + context = dict(getattr(msg, "context", None) or envelope.gateway_payload()) + metadata = { + **(envelope.metadata or {}), + "tenant_id": envelope.tenant_id, + "agent_id": envelope.agent_id, + "channel": envelope.channel, + "normalized_channel": getattr(msg, "channel", envelope.channel), + "channel_id": getattr(msg, "channel_id", None), + "message_id": envelope.message_id, + "user_id": getattr(msg, "user_id", envelope.user_id), + "business_context": envelope.business_context, + "channel_context": context, + "framework_entrypoint": "channel_gateway", + } + await self._event("backoffice.channel.normalized", { + "workflow_id": envelope.workflow_id, + "transaction_id": envelope.transaction_id, + "channel": envelope.channel, + "agent_id": envelope.agent_id, + "legacy_contract": envelope.metadata.get("legacy_contract"), + }) + final_state = await self.executor.execute_workflow( + envelope.workflow_id, + payload=envelope.payload, + transaction_id=envelope.transaction_id, + app_state=app_state, + metadata=metadata, + ) + await self._event("backoffice.workflow.dispatched", { + "workflow_id": envelope.workflow_id, + "transaction_id": envelope.transaction_id, + "current_step": str(final_state.get("current_step")), + "has_error": bool(final_state.get("error")), + }) + return final_state + + async def _event(self, name: str, payload: dict[str, Any]) -> None: + try: + await self.telemetry.event(name, payload, kind="workflow") + except TypeError: + await self.telemetry.event(name, payload) + except Exception: + pass diff --git a/app/workflows/backoffice_workflow_executor.py b/app/workflows/backoffice_workflow_executor.py new file mode 100644 index 0000000..f5ccb0d --- /dev/null +++ b/app/workflows/backoffice_workflow_executor.py @@ -0,0 +1,779 @@ +"""Backoffice TIM/ANATEL workflows executed by the framework runtime. + +This module is the migration boundary that makes the backoffice **framework-native**: + +* domain logic remains in business nodes/services/prompts copied from develop; +* the backend no longer imports or executes ``src.agent.graphs.*``; +* the Backoffice executor assembles the domain workflows and delegates execution to + the framework-managed LangGraph/checkpoint/telemetry pipeline; +* telemetry, guardrails, judges, supervisor, checkpoint and persistence hooks remain + framework-owned; +* BackofficeWorkflowDispatcher calls ``execute_workflow`` after REST payloads are normalized by the ChannelGateway path. +""" + +from __future__ import annotations + +from typing import Any, Callable +from pathlib import Path +import inspect +import json +import logging + +import yaml + +from langgraph.graph import END, START, StateGraph + +from agent_framework.checkpoints.langgraph_saver import create_langgraph_checkpointer +from agent_framework.guardrails.pipeline import GuardrailPipeline +from agent_framework.guardrails.output_supervisor import OutputSupervisor +from agent_framework.guardrails.rail_action import RailAction +from agent_framework.guardrails.rail_result import RailResult +from agent_framework.judges.judge import JudgePipeline +from agent_framework.supervisor.supervisor import Supervisor +from agent_framework.observability.workflow_events import WorkflowTelemetry +from agent_framework.observability.guardrail_events import GuardrailTelemetry +from agent_framework.observability.judge_events import JudgeTelemetry +from agent_framework.observability.langgraph_telemetry import LangGraphDeepTelemetry +from agent_framework.observability.observer import AgentObserver + +from src.agent.state.agent_state import AgentState, create_initial_state, increment_iteration +from src.agent.state.steps import GraphStep +from src.agent.state.steps_emulator import EmulatorGraphStep +import src.agent.nodes as checklist_nodes +from src.agent.nodes.emulator import ( + approve_draft_node, + close_case_node, + fetch_case_node, + generate_response_node, + persist_draft_node, + retrieve_history_node, + retrieve_templates_node, + router_node, + start_response_emulation_node, + validate_actions_node, + validate_response_node, +) + +logger = logging.getLogger("backoffice.workflow_executor") + + +def _project_root() -> Path: + return Path(__file__).resolve().parents[2] + + +def _load_yaml(path: str | Path) -> dict[str, Any]: + resolved = Path(path) + if not resolved.is_absolute(): + resolved = _project_root() / resolved + if not resolved.exists(): + raise FileNotFoundError(f"Configuração não encontrada: {resolved}") + with resolved.open("r", encoding="utf-8") as fh: + data = yaml.safe_load(fh) or {} + if not isinstance(data, dict): + raise ValueError(f"Configuração YAML inválida: {resolved}") + data["_config_path"] = str(resolved) + return data + + +def _resolve_agent_profile(agent_id: str = "backoffice_anatel") -> dict[str, Any]: + agents_cfg = _load_yaml("config/agents.yaml") + for agent in agents_cfg.get("agents", []) or []: + if agent.get("agent_id") == agent_id: + profile = dict(agent) + profile["_agents_config_path"] = agents_cfg.get("_config_path") + return profile + raise ValueError(f"agent_id={agent_id!r} não encontrado em config/agents.yaml") + + +def _build_guardrail_pipeline(*, settings, observer: AgentObserver, guardrails_config: dict[str, Any]) -> GuardrailPipeline: + """Cria o GuardrailPipeline do framework amarrado ao profile do agente. + + O framework local pode ter assinaturas diferentes conforme a versão. Este + helper tenta usar config_path/config/profile quando suportado; em versões + antigas, instancia o pipeline e anexa a configuração ativa para telemetry e + debug, evitando depender apenas do config global. + """ + base_kwargs: dict[str, Any] = { + "observer": observer, + "enable_parallel": bool(getattr(settings, "ENABLE_PARALLEL_GUARDRAILS", True)), + "fail_fast": bool(getattr(settings, "GUARDRAILS_FAIL_FAST", True)), + } + config_path = guardrails_config.get("_config_path") + + try: + accepted = set(inspect.signature(GuardrailPipeline.__init__).parameters) + except Exception: + accepted = set() + + kwargs = dict(base_kwargs) + if "config_path" in accepted: + kwargs["config_path"] = config_path + if "config_file" in accepted: + kwargs["config_file"] = config_path + if "config" in accepted: + kwargs["config"] = guardrails_config + if "profile" in accepted: + kwargs["profile"] = guardrails_config.get("profile") or guardrails_config.get("agent_id") + if "agent_id" in accepted: + kwargs["agent_id"] = guardrails_config.get("agent_id") + + try: + pipeline = GuardrailPipeline(**kwargs) + except TypeError: + pipeline = GuardrailPipeline(**base_kwargs) + + for method_name in ("load_config", "configure", "set_config", "with_config"): + method = getattr(pipeline, method_name, None) + if callable(method): + try: + method(guardrails_config) + break + except TypeError: + try: + method(config_path) + break + except TypeError: + continue + + setattr(pipeline, "active_agent_id", guardrails_config.get("agent_id")) + setattr(pipeline, "active_profile", guardrails_config.get("profile")) + setattr(pipeline, "active_config_path", config_path) + setattr(pipeline, "active_config", guardrails_config) + return pipeline + + +class NativeOutputGuardrailRail: + code = "NATIVE_OUTPUT_GUARDRAILS" + + def __init__(self, pipeline: GuardrailPipeline): + self.pipeline = pipeline + + async def evaluate(self, candidate: str, context: dict[str, Any]): + final, decisions = await self.pipeline.run_output(candidate, context) + serialized = [d.model_dump() for d in decisions] + blocked = [d for d in decisions if not getattr(d, "allowed", True)] + if blocked: + first = blocked[0] + code = (getattr(first, "code", "") or "").upper() + action = RailAction.RETRY if code in {"REVPREC", "CMP", "SCO", "GND"} else RailAction.BLOCK + return RailResult( + code=code or self.code, + action=action, + reason=getattr(first, "reason", "Resposta bloqueada por guardrail de saída"), + guidance=getattr(first, "reason", "Regerar resposta seguindo as políticas de saída."), + sanitized_text=final, + metadata={"native_decisions": serialized}, + ) + if final != candidate: + return RailResult( + code=self.code, + action=RailAction.SANITIZE, + reason="Resposta sanitizada por guardrail de saída.", + sanitized_text=final, + metadata={"native_decisions": serialized}, + ) + return RailResult( + code=self.code, + action=RailAction.ALLOW, + reason="Resposta aprovada pelos guardrails de saída.", + sanitized_text=final, + metadata={"native_decisions": serialized}, + ) + + +class BackofficeWorkflowExecutor: + """Domain executor for Backoffice LangGraph workflows. + + This class does not replace the framework LangGraph runtime. It owns the + Backoffice-specific workflow assembly and delegates execution to the + framework-managed LangGraph/checkpoint/telemetry pipeline. + + It is not a FastAPI entrypoint. REST routes must enter through + ``BackofficeRestChannelAdapter`` and ``BackofficeWorkflowDispatcher`` so the + Backoffice behaves like a corporate channel before the workflow is invoked. + """ + + def __init__(self, *, settings, telemetry, analytics, observer: AgentObserver | None = None): + self.settings = settings + self.telemetry = telemetry + self.analytics = analytics + self.observer = observer or AgentObserver(analytics=analytics) + self.agent_profile = _resolve_agent_profile("backoffice_anatel") + self.guardrails_config = _load_yaml(self.agent_profile["guardrails_config_path"]) + self.guardrails = _build_guardrail_pipeline( + settings=settings, + observer=self.observer, + guardrails_config=self.guardrails_config, + ) + logger.info( + "Backoffice guardrails bound to framework profile agent_id=%s profile=%s config_path=%s input=%s output=%s", + self.guardrails_config.get("agent_id"), + self.guardrails_config.get("profile"), + self.guardrails_config.get("_config_path"), + [r.get("code") for r in self.guardrails_config.get("input", [])], + [r.get("code") for r in self.guardrails_config.get("output", [])], + ) + self.output_supervisor_engine = OutputSupervisor( + rails=[NativeOutputGuardrailRail(self.guardrails)], + observer=self.observer, + max_retries=int(getattr(settings, "OUTPUT_SUPERVISOR_MAX_RETRIES", 3)), + enable_parallel=bool(getattr(settings, "ENABLE_PARALLEL_GUARDRAILS", True)), + fail_fast=bool(getattr(settings, "GUARDRAILS_FAIL_FAST", True)), + ) + self.judges = JudgePipeline() + self.supervisor = Supervisor() + self.workflow_telemetry = WorkflowTelemetry(telemetry) + self.guardrail_telemetry = GuardrailTelemetry(telemetry) + self.judge_telemetry = JudgeTelemetry(telemetry) + self.langgraph_telemetry = LangGraphDeepTelemetry(telemetry) + self._graphs: dict[str, Any] = {} + + def _base_event_payload(self, state: AgentState | None = None, **extra: Any) -> dict[str, Any]: + state = state or {} + metadata = state.get("metadata", {}) or {} + payload = { + "workflow_id": metadata.get("framework_workflow_id"), + "session_id": state.get("session_id") or metadata.get("session_id") or metadata.get("transaction_id"), + "transaction_id": metadata.get("transaction_id"), + "agent_id": metadata.get("agent_id") or self.guardrails_config.get("agent_id"), + "guardrails_profile": metadata.get("guardrails_profile") or self.guardrails_config.get("profile"), + "framework_native": True, + } + payload.update({k: v for k, v in extra.items() if v is not None}) + return payload + + async def _safe_emit_ic(self, code: str, state: AgentState | None = None, payload: dict[str, Any] | None = None, *, component: str) -> None: + try: + await self.observer.emit_ic(code, self._base_event_payload(state, **(payload or {})), component=component) + except Exception as exc: + logger.debug("Falha ao emitir IC %s: %s", code, exc) + + async def _safe_emit_noc(self, code: str, state: AgentState | None = None, payload: dict[str, Any] | None = None, *, component: str) -> None: + try: + normalized = code if str(code).startswith("NOC.") else f"NOC.{str(code).zfill(3)}" + await self.observer.emit_noc(normalized, self._base_event_payload(state, **(payload or {})), component=component) + except Exception as exc: + logger.debug("Falha ao emitir NOC %s: %s", code, exc) + + async def _safe_emit_grl(self, code: str, state: AgentState | None = None, payload: dict[str, Any] | None = None, *, component: str) -> None: + try: + normalized = code if str(code).startswith("GRL.") else f"GRL.{str(code).zfill(3)}" + await self.observer.emit_grl(normalized, self._base_event_payload(state, **(payload or {})), component=component) + except Exception as exc: + logger.debug("Falha ao emitir GRL %s: %s", code, exc) + + async def _emit_by_code(self, code: str, state: AgentState, payload: dict[str, Any] | None, *, component: str) -> None: + code = str(code or "IC.UNKNOWN") + if code.startswith("NOC."): + await self._safe_emit_noc(code, state, payload, component=component) + elif code.startswith("GRL."): + await self._safe_emit_grl(code, state, payload, component=component) + else: + await self._safe_emit_ic(code, state, payload, component=component) + + async def _bridge_legacy_ics(self, state: AgentState | None, node_name: str) -> None: + """Reemite IC/NOC/GRL legados do develop pelo AgentObserver do framework. + + Os nós originais ainda chamam ``agent_framework.observer.event(...)``. + O coletor legado captura esses eventos; esta ponte pega apenas os novos + eventos desde a última etapa e os publica de forma padronizada no + observer do framework, preservando AGA.*, NOC.* e GRL.* no Langfuse/OCI. + + Alguns nós legados mutam o state recebido e retornam None. O wrapper + normaliza esse comportamento, mas esta ponte também é defensiva para + não derrubar o grafo por causa da emissão de eventos legados. + """ + if not isinstance(state, dict): + logger.debug("Skipping legacy IC bridge for node=%s because state is %s", node_name, type(state).__name__) + return + try: + from src.utils.ics_collector import ICsCollector + except Exception: + return + metadata = state.setdefault("metadata", {}) + session_id = state.get("session_id") or metadata.get("transaction_id") + try: + events = ICsCollector.get_current(session_id) if session_id else [] + except Exception: + events = [] + last_idx = int(metadata.get("_framework_ics_bridge_index", 0) or 0) + new_events = events[last_idx:] + if not new_events: + return + metadata["_framework_ics_bridge_index"] = len(events) + bridge_log = metadata.setdefault("framework_ics_bridge", []) + for item in new_events: + code = str(item.get("code") or "IC.UNKNOWN") + event_payload = dict(item.get("metadata") or {}) + event_payload.update({ + "legacy_bridge": True, + "legacy_type": item.get("type"), + "legacy_description": item.get("description"), + "legacy_timestamp": item.get("timestamp"), + "source_node": node_name, + }) + await self._emit_by_code(code, state, event_payload, component=f"backoffice.workflow_executor.legacy_bridge.{node_name}") + bridge_log.append({"code": code, "type": item.get("type"), "node": node_name}) + + def _node(self, name: str, fn: Callable[[AgentState], Any]): + async def _wrapped(state: AgentState) -> AgentState: + async with self.langgraph_telemetry.node(name, state): + await self.telemetry.event( + "backoffice.workflow.node.started", + {"workflow_id": state.get("metadata", {}).get("framework_workflow_id"), "node": name, "session_id": state.get("session_id")}, + kind="workflow", + ) + await self._safe_emit_ic( + "IC.BACKOFFICE_NODE_STARTED", + state, + {"node": name}, + component=f"backoffice.workflow_executor.node.{name}", + ) + try: + result = await fn(state) + except Exception as exc: + await self._safe_emit_noc( + "NOC.009", + state, + {"node": name, "type": "ERROR", "error_type": type(exc).__name__, "error": str(exc)}, + component=f"backoffice.workflow_executor.node.{name}", + ) + raise + + # Alguns nós do projeto original seguem o padrão "mutate in place" + # e retornam None. LangGraph precisa receber um state válido para + # continuar; nesses casos preservamos o mesmo objeto de entrada. + if result is None: + logger.debug("Node %s returned None; preserving mutated input state", name) + result = state + elif not isinstance(result, dict): + raise TypeError(f"Backoffice workflow node {name} returned unsupported type: {type(result).__name__}") + + result.setdefault("metadata", {}) + await self._bridge_legacy_ics(result, name) + await self.telemetry.event( + "backoffice.workflow.node.completed", + {"workflow_id": result.get("metadata", {}).get("framework_workflow_id"), "node": name, "session_id": result.get("session_id")}, + kind="workflow", + ) + await self._safe_emit_ic( + "IC.BACKOFFICE_NODE_COMPLETED", + result, + {"node": name, "has_error": bool(result.get("error"))}, + component=f"backoffice.workflow_executor.node.{name}", + ) + return result + return _wrapped + + async def _framework_input_guardrails(self, state: AgentState) -> AgentState: + await self._safe_emit_grl( + "GRL.001", + state, + {"phase": "input", "status": "started", "rails": [r.get("code") for r in self.guardrails_config.get("input", []) if r.get("enabled", True)]}, + component="backoffice.workflow_executor.guardrails.input", + ) + payload = state.get("metadata", {}).get("request_context", {}) + serialized = json.dumps(payload, ensure_ascii=False, default=str) + context = { + **state.get("metadata", {}), + "workflow_id": state.get("metadata", {}).get("framework_workflow_id"), + "agent_id": self.guardrails_config.get("agent_id"), + "guardrails_profile": self.guardrails_config.get("profile"), + "guardrails_config_path": self.guardrails_config.get("_config_path"), + "active_input_rails": [r.get("code") for r in self.guardrails_config.get("input", []) if r.get("enabled", True)], + "active_output_rails": [r.get("code") for r in self.guardrails_config.get("output", []) if r.get("enabled", True)], + } + sanitized, decisions = await self.guardrails.run_input(serialized, context) + state.setdefault("metadata", {})["framework_input_guardrails"] = [d.model_dump() for d in decisions] + blocked = [d for d in decisions if not getattr(d, "allowed", True)] + await self._safe_emit_grl( + "GRL.002", + state, + { + "phase": "input", + "status": "completed", + "decision_count": len(decisions), + "blocked": bool(blocked), + "codes": [getattr(d, "code", None) for d in decisions], + }, + component="backoffice.workflow_executor.guardrails.input", + ) + if blocked: + first = blocked[0] + state["error"] = {"type": "InputGuardrailBlocked", "message": getattr(first, "reason", "Entrada bloqueada"), "step": "framework_input_guardrails"} + state["final_response"] = sanitized or "Entrada bloqueada por política de segurança." + await self._safe_emit_grl( + "GRL.003", + state, + {"phase": "input", "status": "blocked", "code": getattr(first, "code", None), "reason": getattr(first, "reason", None)}, + component="backoffice.workflow_executor.guardrails.input", + ) + return state + + @staticmethod + def _after_input_guardrails(state): + error = state.get("error") or {} + return "blocked" if error.get("type") == "InputGuardrailBlocked" else "continue" + + async def _framework_output_supervisor(self, state: AgentState) -> AgentState: + await self._safe_emit_grl( + "GRL.004", + state, + {"phase": "output_supervisor", "status": "started"}, + component="backoffice.workflow_executor.output_supervisor", + ) + candidate = state.get("final_response") or state.get("response") or str(state.get("metadata", {}).get("request_context", {}).get("transactionId", "")) + context = { + **state.get("metadata", {}), + "session_id": state.get("session_id"), + "agent_id": self.guardrails_config.get("agent_id"), + "guardrails_profile": self.guardrails_config.get("profile"), + "guardrails_config_path": self.guardrails_config.get("_config_path"), + "active_output_rails": [r.get("code") for r in self.guardrails_config.get("output", []) if r.get("enabled", True)], + } + decision = await self.output_supervisor_engine.evaluate(candidate, context) + if decision.action in {RailAction.ALLOW, RailAction.SANITIZE, RailAction.OBSERVE}: + final = decision.candidate + elif decision.action == RailAction.HANDOVER: + final = "Encaminhado para continuidade com especialista." + else: + final = decision.fallback_message + state["final_response"] = final + state.setdefault("metadata", {})["framework_output_supervisor"] = { + "action": decision.action.value, + "approved": decision.approved, + "results": [ + {"code": r.code, "action": r.action.value, "reason": r.reason, "guidance": r.guidance, "metadata": r.metadata} + for r in decision.results + ], + } + await self._safe_emit_grl( + "GRL.005", + state, + { + "phase": "output_supervisor", + "status": "completed", + "action": decision.action.value, + "approved": decision.approved, + "result_codes": [r.code for r in decision.results], + }, + component="backoffice.workflow_executor.output_supervisor", + ) + if decision.action not in {RailAction.ALLOW, RailAction.SANITIZE, RailAction.OBSERVE}: + await self._safe_emit_grl( + "GRL.006", + state, + {"phase": "output_supervisor", "status": "blocked_or_handover", "action": decision.action.value}, + component="backoffice.workflow_executor.output_supervisor", + ) + return state + + async def _framework_output_guardrails(self, state: AgentState) -> AgentState: + await self._safe_emit_grl( + "GRL.007", + state, + {"phase": "output", "status": "started", "rails": [r.get("code") for r in self.guardrails_config.get("output", []) if r.get("enabled", True)]}, + component="backoffice.workflow_executor.guardrails.output", + ) + candidate = state.get("final_response") or "" + context = { + **state.get("metadata", {}), + "agent_id": self.guardrails_config.get("agent_id"), + "guardrails_profile": self.guardrails_config.get("profile"), + "guardrails_config_path": self.guardrails_config.get("_config_path"), + "active_output_rails": [r.get("code") for r in self.guardrails_config.get("output", []) if r.get("enabled", True)], + } + final, decisions = await self.guardrails.run_output(candidate, context) + state["final_response"] = final + state.setdefault("metadata", {})["framework_output_guardrails"] = [d.model_dump() for d in decisions] + blocked = [d for d in decisions if not getattr(d, "allowed", True)] + await self._safe_emit_grl( + "GRL.008", + state, + { + "phase": "output", + "status": "completed", + "decision_count": len(decisions), + "blocked": bool(blocked), + "sanitized": final != candidate, + "codes": [getattr(d, "code", None) for d in decisions], + }, + component="backoffice.workflow_executor.guardrails.output", + ) + if blocked or final != candidate: + await self._safe_emit_grl( + "GRL.009", + state, + {"phase": "output", "status": "blocked_or_sanitized", "blocked": bool(blocked), "sanitized": final != candidate}, + component="backoffice.workflow_executor.guardrails.output", + ) + return state + + async def _framework_judges(self, state: AgentState) -> AgentState: + payload = state.get("metadata", {}).get("request_context", {}) + question = json.dumps(payload, ensure_ascii=False, default=str) + answer = state.get("final_response") or "" + results = await self.judges.evaluate_all(question, answer, state.get("metadata", {})) + state.setdefault("metadata", {})["framework_judges"] = [r.model_dump() for r in results] + return state + + async def _framework_supervisor_review(self, state: AgentState) -> AgentState: + answer = state.get("final_response") or "" + ok, reviewed = await self.supervisor.review(answer, state.get("metadata", {})) + state["final_response"] = reviewed if ok else reviewed + state.setdefault("metadata", {})["framework_supervisor_review"] = {"approved": ok} + return state + + async def _framework_persist(self, state: AgentState) -> AgentState: + await self._safe_emit_ic( + "IC.BACKOFFICE_WORKFLOW_COMPLETED", + state, + { + "current_step": str(state.get("current_step")), + "has_error": bool(state.get("error")), + }, + component="backoffice.workflow_executor.persist", + ) + await self._safe_emit_noc( + "NOC.006", + state, + { + "type": "INFO" if not state.get("error") else "FAILURE", + "status": "Backoffice workflow completed", + "current_step": str(state.get("current_step")), + }, + component="backoffice.workflow_executor.persist", + ) + return state + + def _compile(self, workflow_id: str): + if workflow_id == "backoffice_checklist": + return self._build_checklist_graph() + if workflow_id == "backoffice_response_emulator": + return self._build_emulator_graph() + raise ValueError(f"Unknown workflow_id={workflow_id}") + + def get_graph(self, workflow_id: str): + graph = self._graphs.get(workflow_id) + if graph is None: + graph = self._compile(workflow_id) + self._graphs[workflow_id] = graph + return graph + + async def execute_workflow(self, workflow_id: str, *, payload: dict[str, Any], transaction_id: str | None = None, app_state=None, metadata: dict[str, Any] | None = None) -> AgentState: + transaction_id = transaction_id or payload.get("transactionId") or payload.get("transaction_id") or "backoffice-session" + state = create_initial_state(session_id=transaction_id) + state["metadata"].update(metadata or {}) + state["metadata"].update({ + "transaction_id": transaction_id, + "request_context": payload, + "framework_workflow_id": workflow_id, + "framework_native": True, + "agent_id": self.guardrails_config.get("agent_id"), + "guardrails_profile": self.guardrails_config.get("profile"), + "guardrails_config_path": self.guardrails_config.get("_config_path"), + "active_input_rails": [r.get("code") for r in self.guardrails_config.get("input", []) if r.get("enabled", True)], + "active_output_rails": [r.get("code") for r in self.guardrails_config.get("output", []) if r.get("enabled", True)], + # Progress producer is kept in src.compat.framework_services, not in state, + # so checkpoints remain JSON-stable and integrity hashes do not change. + "_framework_ics_bridge_index": 0, + }) + try: + from src.utils.ics_collector import ICsCollector + ICsCollector.start(transaction_id) + except Exception: + pass + await self._safe_emit_noc( + "NOC.001", + state, + {"type": "INFO", "status": "Backoffice workflow started"}, + component="backoffice.workflow_executor.execute", + ) + await self._safe_emit_ic( + "IC.BACKOFFICE_WORKFLOW_STARTED", + state, + {"payload_keys": sorted(list(payload.keys()))}, + component="backoffice.workflow_executor.execute", + ) + graph = self.get_graph(workflow_id) + config = {"configurable": {"thread_id": f"{workflow_id}:{transaction_id}"}} + try: + final_state = await graph.ainvoke(state, config=config) + await self._bridge_legacy_ics(final_state, "workflow_end") + return final_state + except Exception as exc: + await self._safe_emit_noc( + "NOC.009", + state, + {"type": "ERROR", "status": "Backoffice workflow failed", "error_type": type(exc).__name__, "error": str(exc)}, + component="backoffice.workflow_executor.execute", + ) + raise + finally: + try: + final_ref = locals().get("final_state", state) + final_ref.get("metadata", {}).pop("_oci_producer", None) + final_ref.get("metadata", {}).pop("_framework_ics_bridge_index", None) + except Exception: + pass + try: + from src.utils.ics_collector import ICsCollector + ICsCollector.stop(transaction_id) + except Exception: + pass + + # -------------------- Checklist workflow -------------------- + def _build_checklist_graph(self): + builder = StateGraph(AgentState) + builder.add_node("framework_input_guardrails", self._node("framework_input_guardrails", self._framework_input_guardrails)) + builder.add_node("fetch_ticket", self._node("fetch_ticket", self._fetch_ticket)) + builder.add_node(GraphStep.VALIDATION, self._node(str(GraphStep.VALIDATION), checklist_nodes.validation_node.validate_ticket)) + builder.add_node(GraphStep.BYPASS_RULES, self._node(str(GraphStep.BYPASS_RULES), checklist_nodes.bypass_rules_node.evaluate_bypass_rules)) + builder.add_node(GraphStep.CACHE_CHECK, self._node(str(GraphStep.CACHE_CHECK), checklist_nodes.cache_check_node.check_cache_node)) + builder.add_node(GraphStep.IMDB_ENRICHMENT, self._node(str(GraphStep.IMDB_ENRICHMENT), checklist_nodes.imdb_enrichment_node.imdb_enrich_ticket)) + builder.add_node(GraphStep.IDENTITY_VERIFICATION, self._node(str(GraphStep.IDENTITY_VERIFICATION), checklist_nodes.identity_verification_node.perform_identity_verification)) + builder.add_node(GraphStep.SPEECH_ENRICHMENT, self._node(str(GraphStep.SPEECH_ENRICHMENT), checklist_nodes.speech_enrichment_node.enrich_with_speech)) + builder.add_node("knowledge_base_enrichment", self._node("knowledge_base_enrichment", checklist_nodes.knowledge_base_enrichment_node.enrich_with_knowledge_base)) + builder.add_node(GraphStep.CANCELING_ANALYSIS, self._node(str(GraphStep.CANCELING_ANALYSIS), checklist_nodes.canceling_analysis_node.perform_canceling_analysis)) + builder.add_node(GraphStep.TIM_COMPLAINT_ANALYSIS, self._node(str(GraphStep.TIM_COMPLAINT_ANALYSIS), checklist_nodes.tim_complaint_analysis_node.perform_tim_complaint_analysis)) + builder.add_node("different_complaint_operator", self._node("different_complaint_operator", checklist_nodes.different_complaint_operator_node.perform_different_operator)) + builder.add_node("undefined_complaint_operator", self._node("undefined_complaint_operator", checklist_nodes.undefined_complaint_operator_node.perform_undefined_complaint)) + builder.add_node("tim_complaint", self._node("tim_complaint", checklist_nodes.tim_complaint_node.handle_tim_complaint)) + builder.add_node(GraphStep.RECLASSIFICATION_ANALYSIS, self._node(str(GraphStep.RECLASSIFICATION_ANALYSIS), checklist_nodes.reclassification_analysis_node.perform_reclassification_analysis)) + builder.add_node(GraphStep.TREATMENT_DECISION, self._node(str(GraphStep.TREATMENT_DECISION), checklist_nodes.treatment_decision_node.treatment_decision)) + builder.add_node(GraphStep.SIEBEL_SR_OPENING, self._node(str(GraphStep.SIEBEL_SR_OPENING), checklist_nodes.siebel_sr_opening_node.open_siebel_sr)) + builder.add_node("framework_output_supervisor", self._node("framework_output_supervisor", self._framework_output_supervisor)) + builder.add_node("framework_output_guardrails", self._node("framework_output_guardrails", self._framework_output_guardrails)) + builder.add_node("framework_judges", self._node("framework_judges", self._framework_judges)) + builder.add_node("framework_supervisor_review", self._node("framework_supervisor_review", self._framework_supervisor_review)) + builder.add_node("framework_persist", self._node("framework_persist", self._framework_persist)) + + builder.add_edge(START, "framework_input_guardrails") + builder.add_conditional_edges("framework_input_guardrails", self._after_input_guardrails, {"blocked": "framework_persist", "continue": "fetch_ticket"}) + builder.add_edge("fetch_ticket", GraphStep.VALIDATION) + builder.add_conditional_edges(GraphStep.VALIDATION, checklist_nodes.validation_node.should_continue, {"continue": GraphStep.BYPASS_RULES, "reject": "framework_output_supervisor"}) + builder.add_edge(GraphStep.BYPASS_RULES, GraphStep.CACHE_CHECK) + builder.add_conditional_edges(GraphStep.CACHE_CHECK, self._route_after_cache_check, {GraphStep.TREATMENT_DECISION: GraphStep.TREATMENT_DECISION, GraphStep.CANCELING_ANALYSIS: GraphStep.CANCELING_ANALYSIS, GraphStep.IMDB_ENRICHMENT: GraphStep.IMDB_ENRICHMENT}) + builder.add_conditional_edges(GraphStep.IMDB_ENRICHMENT, checklist_nodes.imdb_enrichment_node.should_continue, {"continue": GraphStep.IDENTITY_VERIFICATION, "failed": "framework_output_supervisor"}) + builder.add_conditional_edges(GraphStep.IDENTITY_VERIFICATION, checklist_nodes.identity_verification_node.route_after_identity_verification, {"proceed": GraphStep.SPEECH_ENRICHMENT, "cancel": GraphStep.SIEBEL_SR_OPENING, "smart_human": GraphStep.TREATMENT_DECISION, "failed": "framework_output_supervisor"}) + builder.add_edge(GraphStep.SPEECH_ENRICHMENT, "knowledge_base_enrichment") + builder.add_conditional_edges("knowledge_base_enrichment", self._route_after_knowledge_base, {GraphStep.CANCELING_ANALYSIS: GraphStep.CANCELING_ANALYSIS, GraphStep.TREATMENT_DECISION: GraphStep.TREATMENT_DECISION}) + builder.add_conditional_edges(GraphStep.CANCELING_ANALYSIS, self._route_after_canceling, {GraphStep.SIEBEL_SR_OPENING: GraphStep.SIEBEL_SR_OPENING, GraphStep.PROCEED_GRAPH: GraphStep.TIM_COMPLAINT_ANALYSIS, "finalize": "framework_output_supervisor"}) + builder.add_conditional_edges(GraphStep.TIM_COMPLAINT_ANALYSIS, self._route_after_tim_complaint_analysis, {"tim_complaint": "tim_complaint", "different_complaint_operator": "different_complaint_operator", "undefined_complaint_operator": "undefined_complaint_operator", "finalize": "framework_output_supervisor"}) + builder.add_edge("tim_complaint", GraphStep.RECLASSIFICATION_ANALYSIS) + builder.add_conditional_edges("different_complaint_operator", self._route_after_operator_check, {GraphStep.SIEBEL_SR_OPENING: GraphStep.SIEBEL_SR_OPENING, GraphStep.PROCEED_GRAPH: GraphStep.RECLASSIFICATION_ANALYSIS}) + builder.add_conditional_edges("undefined_complaint_operator", self._route_after_operator_check, {GraphStep.SIEBEL_SR_OPENING: GraphStep.SIEBEL_SR_OPENING, GraphStep.PROCEED_GRAPH: GraphStep.RECLASSIFICATION_ANALYSIS}) + builder.add_conditional_edges(GraphStep.RECLASSIFICATION_ANALYSIS, self._route_after_reclassification, {GraphStep.SIEBEL_SR_OPENING: GraphStep.SIEBEL_SR_OPENING, GraphStep.PROCEED_GRAPH: GraphStep.TREATMENT_DECISION, "finalize": "framework_output_supervisor"}) + builder.add_edge(GraphStep.TREATMENT_DECISION, GraphStep.SIEBEL_SR_OPENING) + builder.add_edge(GraphStep.SIEBEL_SR_OPENING, "framework_output_supervisor") + builder.add_edge("framework_output_supervisor", "framework_output_guardrails") + builder.add_edge("framework_output_guardrails", "framework_judges") + builder.add_edge("framework_judges", "framework_supervisor_review") + builder.add_edge("framework_supervisor_review", "framework_persist") + builder.add_edge("framework_persist", END) + return builder.compile(checkpointer=create_langgraph_checkpointer(self.settings)) + + async def _fetch_ticket(self, state: AgentState) -> AgentState: + increment_iteration(state) + return await checklist_nodes.fetch_ticket_node.fetch_ticket_data(state) + + @staticmethod + def _route_after_cache_check(state: AgentState) -> str: + if state.get("cache_found") is True: + if state.get("bypass_treatment_validations"): + return GraphStep.TREATMENT_DECISION + return GraphStep.CANCELING_ANALYSIS + return GraphStep.IMDB_ENRICHMENT + + @staticmethod + def _route_after_knowledge_base(state: AgentState) -> str: + return GraphStep.TREATMENT_DECISION if state.get("bypass_treatment_validations") else GraphStep.CANCELING_ANALYSIS + + @staticmethod + def _route_after_canceling(state: AgentState) -> str: + step = state.get("current_step") + if step == GraphStep.CANCELING_ANALYSIS_CANCEL_TICKET: + return GraphStep.SIEBEL_SR_OPENING + if step == GraphStep.PROCEED_GRAPH: + return GraphStep.PROCEED_GRAPH + return "finalize" + + @staticmethod + def _route_after_tim_complaint_analysis(state: AgentState) -> str: + decision = state.get("metadata", {}).get("request_context", {}).get("is_tim_complaint", "") + if decision == "sim": + return "tim_complaint" + if decision == "não": + return "different_complaint_operator" + if decision == "inconclusivo": + return "undefined_complaint_operator" + return "finalize" + + @staticmethod + def _route_after_operator_check(state: AgentState) -> str: + context = state.get("metadata", {}).get("request_context", {}) + if context.get("forward_complaint"): + return GraphStep.SIEBEL_SR_OPENING + return GraphStep.PROCEED_GRAPH + + @staticmethod + def _route_after_reclassification(state: AgentState) -> str: + step = state.get("current_step") + if step == GraphStep.RECLASSIFICATION_ANALYSIS_COMPLETED: + context = state.get("metadata", {}).get("request_context", {}) + if context.get("siebel_action") == "reclassificar": + return GraphStep.SIEBEL_SR_OPENING + return GraphStep.PROCEED_GRAPH + return "finalize" + + # -------------------- Emulator workflow -------------------- + def _build_emulator_graph(self): + builder = StateGraph(AgentState) + builder.add_node("framework_input_guardrails", self._node("framework_input_guardrails", self._framework_input_guardrails)) + builder.add_node(EmulatorGraphStep.RESPONSE_EMULATION_START, self._node(str(EmulatorGraphStep.RESPONSE_EMULATION_START), start_response_emulation_node.start_response_emulation)) + builder.add_node(EmulatorGraphStep.FETCH_CASE, self._node(str(EmulatorGraphStep.FETCH_CASE), fetch_case_node.fetch_case)) + builder.add_node(EmulatorGraphStep.VALIDATE_ACTIONS, self._node(str(EmulatorGraphStep.VALIDATE_ACTIONS), validate_actions_node.validate_actions)) + builder.add_node(EmulatorGraphStep.ROUTER_DECISION, self._node(str(EmulatorGraphStep.ROUTER_DECISION), router_node.route)) + builder.add_node(EmulatorGraphStep.RETRIEVE_TEMPLATES, self._node(str(EmulatorGraphStep.RETRIEVE_TEMPLATES), retrieve_templates_node.retrieve_templates)) + builder.add_node(EmulatorGraphStep.RETRIEVE_HISTORY, self._node(str(EmulatorGraphStep.RETRIEVE_HISTORY), retrieve_history_node.retrieve_history)) + builder.add_node(EmulatorGraphStep.GENERATE_RESPONSE, self._node(str(EmulatorGraphStep.GENERATE_RESPONSE), generate_response_node.generate_response)) + builder.add_node(EmulatorGraphStep.VALIDATE_RESPONSE, self._node(str(EmulatorGraphStep.VALIDATE_RESPONSE), validate_response_node.validate_response)) + builder.add_node(EmulatorGraphStep.PERSIST_DRAFT, self._node(str(EmulatorGraphStep.PERSIST_DRAFT), persist_draft_node.persist_draft)) + builder.add_node(EmulatorGraphStep.APPROVE_DRAFT, self._node(str(EmulatorGraphStep.APPROVE_DRAFT), approve_draft_node.approve_draft)) + builder.add_node(EmulatorGraphStep.CLOSE_CASE, self._node(str(EmulatorGraphStep.CLOSE_CASE), close_case_node.close_case)) + builder.add_node("framework_output_supervisor", self._node("framework_output_supervisor", self._framework_output_supervisor)) + builder.add_node("framework_output_guardrails", self._node("framework_output_guardrails", self._framework_output_guardrails)) + builder.add_node("framework_judges", self._node("framework_judges", self._framework_judges)) + builder.add_node("framework_supervisor_review", self._node("framework_supervisor_review", self._framework_supervisor_review)) + builder.add_node("framework_persist", self._node("framework_persist", self._framework_persist)) + + builder.add_edge(START, "framework_input_guardrails") + builder.add_conditional_edges("framework_input_guardrails", self._after_input_guardrails, {"blocked": "framework_persist", "continue": EmulatorGraphStep.RESPONSE_EMULATION_START}) + builder.add_edge(EmulatorGraphStep.RESPONSE_EMULATION_START, EmulatorGraphStep.FETCH_CASE) + builder.add_conditional_edges(EmulatorGraphStep.FETCH_CASE, self._emulator_route_after_fetch, {"generate": EmulatorGraphStep.VALIDATE_ACTIONS, "approve": EmulatorGraphStep.APPROVE_DRAFT, "close": EmulatorGraphStep.CLOSE_CASE, "failed": "framework_output_supervisor"}) + builder.add_conditional_edges(EmulatorGraphStep.VALIDATE_ACTIONS, validate_actions_node.should_continue, {"continue": EmulatorGraphStep.ROUTER_DECISION, "failed": "framework_output_supervisor"}) + builder.add_conditional_edges(EmulatorGraphStep.ROUTER_DECISION, router_node.next_step_after_router, {EmulatorGraphStep.RETRIEVE_TEMPLATES: EmulatorGraphStep.RETRIEVE_TEMPLATES, EmulatorGraphStep.RETRIEVE_HISTORY: EmulatorGraphStep.RETRIEVE_HISTORY, EmulatorGraphStep.GENERATE_RESPONSE: EmulatorGraphStep.GENERATE_RESPONSE}) + builder.add_conditional_edges(EmulatorGraphStep.RETRIEVE_TEMPLATES, router_node.next_step_after_templates, {EmulatorGraphStep.RETRIEVE_HISTORY: EmulatorGraphStep.RETRIEVE_HISTORY, EmulatorGraphStep.GENERATE_RESPONSE: EmulatorGraphStep.GENERATE_RESPONSE}) + builder.add_edge(EmulatorGraphStep.RETRIEVE_HISTORY, EmulatorGraphStep.GENERATE_RESPONSE) + builder.add_conditional_edges(EmulatorGraphStep.GENERATE_RESPONSE, generate_response_node.should_continue, {"continue": EmulatorGraphStep.VALIDATE_RESPONSE, "failed": "framework_output_supervisor"}) + builder.add_edge(EmulatorGraphStep.VALIDATE_RESPONSE, EmulatorGraphStep.PERSIST_DRAFT) + builder.add_edge(EmulatorGraphStep.PERSIST_DRAFT, "framework_output_supervisor") + builder.add_edge(EmulatorGraphStep.APPROVE_DRAFT, "framework_output_supervisor") + builder.add_edge(EmulatorGraphStep.CLOSE_CASE, "framework_output_supervisor") + builder.add_edge("framework_output_supervisor", "framework_output_guardrails") + builder.add_edge("framework_output_guardrails", "framework_judges") + builder.add_edge("framework_judges", "framework_supervisor_review") + builder.add_edge("framework_supervisor_review", "framework_persist") + builder.add_edge("framework_persist", END) + return builder.compile(checkpointer=create_langgraph_checkpointer(self.settings)) + + @staticmethod + def _emulator_route_after_fetch(state: AgentState) -> str: + if state.get("error"): + return "failed" + flow_mode = (state.get("metadata") or {}).get("flow_mode") + if flow_mode == "close": + return "close" + if flow_mode == "approve": + return "approve" + return "generate" diff --git a/debug_events.jsonl b/debug_events.jsonl index b7d6a42..7c508f6 100644 --- a/debug_events.jsonl +++ b/debug_events.jsonl @@ -144,3 +144,16 @@ {"ts": "2026-06-13T13:13:33.430808Z", "key": "man-1448d83f", "payload": {"transactionId": "man-1448d83f", "processing": {"status": "processing", "current_step": "reclassification_analysis", "action": "await_response", "note": "[13/06/2026 10:13:27] Chamado recebido, iniciando processamento.\n[13/06/2026 10:13:27] Enriquecendo chamado no IMDB....\n[13/06/2026 10:13:27] Realizando verificação de CPF divergente....\n[13/06/2026 10:13:27] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 10:13:27] Consultando procedimentos na base de conhecimento....\n[13/06/2026 10:13:28] Realizando análise de cancelamento....\n[13/06/2026 10:13:30] Realizando análise de reencaminhamento....\n[13/06/2026 10:13:33] Realizando análise de reclassificação do chamado....\n[13/06/2026 10:13:33] Realizando análise de reclassificação do chamado....", "timestamp": "2026-06-13T13:13:33.430794Z"}}} {"ts": "2026-06-13T13:13:37.097443Z", "key": "man-1448d83f", "payload": {"transactionId": "man-1448d83f", "processing": {"status": "processing", "current_step": "siebel_sr_opening", "action": "await_response", "note": "[13/06/2026 10:13:27] Chamado recebido, iniciando processamento.\n[13/06/2026 10:13:27] Enriquecendo chamado no IMDB....\n[13/06/2026 10:13:27] Realizando verificação de CPF divergente....\n[13/06/2026 10:13:27] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 10:13:27] Consultando procedimentos na base de conhecimento....\n[13/06/2026 10:13:28] Realizando análise de cancelamento....\n[13/06/2026 10:13:30] Realizando análise de reencaminhamento....\n[13/06/2026 10:13:33] Realizando análise de reclassificação do chamado....\n[13/06/2026 10:13:33] Realizando análise de reclassificação do chamado....\n[13/06/2026 10:13:37] Abrindo chamado no Siebel....", "timestamp": "2026-06-13T13:13:37.097424Z"}}} {"ts": "2026-06-13T13:13:37.103780Z", "key": "man-1448d83f", "payload": {"transactionId": "man-1448d83f", "processing": {"status": "processing", "current_step": "siebel_sr_opened", "action": "await_response", "note": "[13/06/2026 10:13:27] Chamado recebido, iniciando processamento.\n[13/06/2026 10:13:27] Enriquecendo chamado no IMDB....\n[13/06/2026 10:13:27] Realizando verificação de CPF divergente....\n[13/06/2026 10:13:27] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 10:13:27] Consultando procedimentos na base de conhecimento....\n[13/06/2026 10:13:28] Realizando análise de cancelamento....\n[13/06/2026 10:13:30] Realizando análise de reencaminhamento....\n[13/06/2026 10:13:33] Realizando análise de reclassificação do chamado....\n[13/06/2026 10:13:33] Realizando análise de reclassificação do chamado....\n[13/06/2026 10:13:37] Abrindo chamado no Siebel....\n[13/06/2026 10:13:37] Chamado aberto no Siebel.", "timestamp": "2026-06-13T13:13:37.103766Z"}}} +{"ts": "2026-06-13T18:36:33.638465Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "fetching_ticket", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.", "timestamp": "2026-06-13T18:36:33.638442Z"}}} +{"ts": "2026-06-13T18:36:33.647743Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "validation", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.", "timestamp": "2026-06-13T18:36:33.647718Z"}}} +{"ts": "2026-06-13T18:36:33.665164Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "imdb_enrichment", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....", "timestamp": "2026-06-13T18:36:33.665136Z"}}} +{"ts": "2026-06-13T18:36:37.714001Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "identity_verification", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....\n[13/06/2026 15:36:37] Realizando verificação de CPF divergente....", "timestamp": "2026-06-13T18:36:37.713972Z"}}} +{"ts": "2026-06-13T18:36:37.723098Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "speech_enrichment", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....\n[13/06/2026 15:36:37] Realizando verificação de CPF divergente....\n[13/06/2026 15:36:37] Enriquecendo chamado via Speech Analytics.", "timestamp": "2026-06-13T18:36:37.723075Z"}}} +{"ts": "2026-06-13T18:36:37.798786Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "knowledge_base_enrichment", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....\n[13/06/2026 15:36:37] Realizando verificação de CPF divergente....\n[13/06/2026 15:36:37] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 15:36:37] Consultando procedimentos na base de conhecimento....", "timestamp": "2026-06-13T18:36:37.798757Z"}}} +{"ts": "2026-06-13T18:37:08.751641Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "knowledge_base_enrichment_unavailable", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....\n[13/06/2026 15:36:37] Realizando verificação de CPF divergente....\n[13/06/2026 15:36:37] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 15:36:37] Consultando procedimentos na base de conhecimento....\n[13/06/2026 15:37:08] Base de conhecimento consultada - indisponível no momento.", "timestamp": "2026-06-13T18:37:08.751624Z"}}} +{"ts": "2026-06-13T18:37:08.759915Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "canceling_analysis", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....\n[13/06/2026 15:36:37] Realizando verificação de CPF divergente....\n[13/06/2026 15:36:37] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 15:36:37] Consultando procedimentos na base de conhecimento....\n[13/06/2026 15:37:08] Base de conhecimento consultada - indisponível no momento.\n[13/06/2026 15:37:08] Realizando análise de cancelamento....", "timestamp": "2026-06-13T18:37:08.759889Z"}}} +{"ts": "2026-06-13T18:37:12.004864Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "tim_complaint_analysis", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....\n[13/06/2026 15:36:37] Realizando verificação de CPF divergente....\n[13/06/2026 15:36:37] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 15:36:37] Consultando procedimentos na base de conhecimento....\n[13/06/2026 15:37:08] Base de conhecimento consultada - indisponível no momento.\n[13/06/2026 15:37:08] Realizando análise de cancelamento....\n[13/06/2026 15:37:12] Realizando análise de reencaminhamento....", "timestamp": "2026-06-13T18:37:12.004841Z"}}} +{"ts": "2026-06-13T18:37:15.091211Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "reclassification_analysis", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....\n[13/06/2026 15:36:37] Realizando verificação de CPF divergente....\n[13/06/2026 15:36:37] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 15:36:37] Consultando procedimentos na base de conhecimento....\n[13/06/2026 15:37:08] Base de conhecimento consultada - indisponível no momento.\n[13/06/2026 15:37:08] Realizando análise de cancelamento....\n[13/06/2026 15:37:12] Realizando análise de reencaminhamento....\n[13/06/2026 15:37:15] Realizando análise de reclassificação do chamado....", "timestamp": "2026-06-13T18:37:15.091188Z"}}} +{"ts": "2026-06-13T18:37:15.100227Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "reclassification_analysis", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....\n[13/06/2026 15:36:37] Realizando verificação de CPF divergente....\n[13/06/2026 15:36:37] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 15:36:37] Consultando procedimentos na base de conhecimento....\n[13/06/2026 15:37:08] Base de conhecimento consultada - indisponível no momento.\n[13/06/2026 15:37:08] Realizando análise de cancelamento....\n[13/06/2026 15:37:12] Realizando análise de reencaminhamento....\n[13/06/2026 15:37:15] Realizando análise de reclassificação do chamado....\n[13/06/2026 15:37:15] Realizando análise de reclassificação do chamado....", "timestamp": "2026-06-13T18:37:15.100198Z"}}} +{"ts": "2026-06-13T18:37:18.928802Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "siebel_sr_opening", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....\n[13/06/2026 15:36:37] Realizando verificação de CPF divergente....\n[13/06/2026 15:36:37] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 15:36:37] Consultando procedimentos na base de conhecimento....\n[13/06/2026 15:37:08] Base de conhecimento consultada - indisponível no momento.\n[13/06/2026 15:37:08] Realizando análise de cancelamento....\n[13/06/2026 15:37:12] Realizando análise de reencaminhamento....\n[13/06/2026 15:37:15] Realizando análise de reclassificação do chamado....\n[13/06/2026 15:37:15] Realizando análise de reclassificação do chamado....\n[13/06/2026 15:37:18] Abrindo chamado no Siebel....", "timestamp": "2026-06-13T18:37:18.928779Z"}}} +{"ts": "2026-06-13T18:37:18.937657Z", "key": "man-e10208c7", "payload": {"transactionId": "man-e10208c7", "processing": {"status": "processing", "current_step": "siebel_sr_opened", "action": "await_response", "note": "[13/06/2026 15:36:33] Chamado recebido, iniciando processamento.\n[13/06/2026 15:36:33] Enriquecendo chamado no IMDB....\n[13/06/2026 15:36:37] Realizando verificação de CPF divergente....\n[13/06/2026 15:36:37] Enriquecendo chamado via Speech Analytics.\n[13/06/2026 15:36:37] Consultando procedimentos na base de conhecimento....\n[13/06/2026 15:37:08] Base de conhecimento consultada - indisponível no momento.\n[13/06/2026 15:37:08] Realizando análise de cancelamento....\n[13/06/2026 15:37:12] Realizando análise de reencaminhamento....\n[13/06/2026 15:37:15] Realizando análise de reclassificação do chamado....\n[13/06/2026 15:37:15] Realizando análise de reclassificação do chamado....\n[13/06/2026 15:37:18] Abrindo chamado no Siebel....\n[13/06/2026 15:37:18] Chamado aberto no Siebel.", "timestamp": "2026-06-13T18:37:18.937634Z"}}} diff --git a/docs/AJUSTES_IC_NOC_GRL_OCI_OPENAI.md b/docs/AJUSTES_IC_NOC_GRL_OCI_OPENAI.md index e7322b4..46778b1 100644 --- a/docs/AJUSTES_IC_NOC_GRL_OCI_OPENAI.md +++ b/docs/AJUSTES_IC_NOC_GRL_OCI_OPENAI.md @@ -33,7 +33,7 @@ Esta versão corrige dois pontos do runtime nativo do backoffice: ## Arquivos alterados -- `app/workflows/backoffice_native_runtime.py` +- `app/workflows/backoffice_workflow_executor.py` - `src/core/config.py` - `.env.example` - `tools/validate_parity.py` diff --git a/docs/BACKOFFICE_REST_AS_CHANNEL_ARCHITECTURE.md b/docs/BACKOFFICE_REST_AS_CHANNEL_ARCHITECTURE.md new file mode 100644 index 0000000..390c97a --- /dev/null +++ b/docs/BACKOFFICE_REST_AS_CHANNEL_ARCHITECTURE.md @@ -0,0 +1,97 @@ +# Backoffice REST as a Framework Channel + +This project now treats the TIM/ANATEL Backoffice REST contracts as a corporate channel instead of letting the HTTP routes call a domain workflow executor directly. + +## Target execution model + +```text +Legacy-compatible REST endpoint + ↓ +BackofficeRestChannelAdapter + ↓ +ChannelGateway normalization path + ↓ +BackofficeWorkflowDispatcher + ↓ +Backoffice workflow LangGraph + ↓ +Framework layers: guardrails, supervisor, judges, checkpoint, telemetry, MCP + ↓ +Legacy-compatible REST response adapter +``` + +## What changed + +### New files + +- `app/channels/backoffice_rest_adapter.py` + - Converts legacy Backoffice REST payloads into `BackofficeChannelEnvelope`. + - Preserves the original payload under `request_context`. + - Extracts canonical `business_context` such as `customer_key`, `contract_key`, `interaction_key` and `session_key`. + - Passes the request through `ChannelGateway.normalize(...)` using `channel = backoffice_rest`. + - Falls back to the web adapter shape when the installed framework does not yet have a dedicated `backoffice_rest` adapter. + +- `app/workflows/backoffice_workflow_dispatcher.py` + - Receives a normalized channel envelope. + - Emits framework telemetry events for channel normalization and workflow dispatch. + - Invokes the correct operational workflow: + - `backoffice_checklist` + - `backoffice_response_emulator` + +### Updated file + +- `app/main.py` + - The compatibility routes no longer call `BackofficeWorkflowExecutor.execute_workflow(...)` directly. + - They now call: + +```python +BackofficeRestChannelAdapter + ↓ +BackofficeWorkflowDispatcher + ↓ +BackofficeWorkflowExecutor +``` + +The `BackofficeWorkflowExecutor` still owns the compiled LangGraph workflows, but it is now behind the channel/dispatcher boundary rather than being the direct REST entrypoint. + +## Why this is architecturally cleaner + +The REST routes are now only transport adapters. They preserve the old external contract, but the request enters the same conceptual pipeline used by other framework channels. + +This avoids the previous coupling: + +```text +REST route → BackofficeWorkflowExecutor +``` + +and replaces it with: + +```text +REST route → channel adapter → ChannelGateway → workflow dispatcher → LangGraph workflow +``` + +## Compatibility + +The existing routes remain available: + +- `POST /agent/process-ticket` +- `POST /agent/execute` +- `POST /agent/process-and-stream` +- `POST /case/{transaction_id}/response-emulator/generate` +- `POST /case/{transaction_id}/response-emulator/finalize` + +The response builders are preserved, so external clients should not need to change their payload or response handling. + +## Runtime notes + +The metadata added to workflow state now includes: + +```text +framework_entrypoint = channel_gateway +channel = backoffice_rest +normalized_channel = backoffice_rest or web fallback +business_context = canonical business keys +channel_context = normalized gateway context +``` + +This makes Langfuse/telemetry easier to interpret because Backoffice REST is visible as a channel entrypoint, not as an ad-hoc executor call. diff --git a/docs/RELATORIO_FRAMEWORK_NATIVE_100.md b/docs/RELATORIO_FRAMEWORK_NATIVE_100.md index a2ad1ef..68365a3 100644 --- a/docs/RELATORIO_FRAMEWORK_NATIVE_100.md +++ b/docs/RELATORIO_FRAMEWORK_NATIVE_100.md @@ -9,7 +9,7 @@ A versão foi refatorada para que o backoffice não execute mais grafos LangGrap O backend ativo usa: - `app/main.py` como camada de rotas/adapters. -- `app/workflows/backoffice_native_runtime.py` como runtime de workflows do framework. +- `app/workflows/backoffice_workflow_executor.py` como executor de workflows de domínio sobre o runtime LangGraph do framework. - `src/agent/nodes/*` como nós de domínio. - `src/components/clients/*` como services/clients de domínio. - `src/agent/local_prompts/*` como prompts de domínio. @@ -75,7 +75,7 @@ Agora: ```text app/main.py chama backoffice_runtime.execute_workflow -BackofficeNativeRuntime compila os workflows +BackofficeWorkflowExecutor compila os workflows os nós originais são apenas plugins de domínio guardrails/judges/supervisor/checkpoint/telemetry entram no runtime ``` diff --git a/legacy_backend/__pycache__/mock_imdb_server.cpython-313.pyc b/legacy_backend/__pycache__/mock_imdb_server.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c70fd09a8b55bbbe0ed9ea30b0f2bd2b40ed35b GIT binary patch literal 2226 zcmb7FOKcle6n*pY_@9rRuTwQcnl!kPJ^8m4ACUx7(ke~lX%>heYchULC$(p$?~Ma7 zLTU>VTQ*1_kf>O-3s!8pVAnlLltrw!3S!lrBdbE}xNmHyN<@(uYwo8`Zi+-y(WWqhbWxYC3q;zKa^bew ztFJE43C)=v*c4|)T}h!Gd9I~E0vz83hmVGah2w9qG;&TsbYW;Icuzh4mE{%;EbLOucG+)iLj>E35A>s&`ga(*g^4 zmRG{nPR%e)OsTdzrCD~-VL{TgFk6@Oj}L+T65hsdATA*l61RbJ{?=KMlg`fhOc&aL zzazZa+AfF)yy)Wp@FKm|i>wE9MGt00J*0>A2>ha1S&zXuu6JZ5P0%~Dfl+i-DhlbY z+bn3h#UAC5-nVG4{d8U-9MGH2I&QD*zHZ?UjJu^MaLhEaKetqG_+RJ_j z91^E4mJG<_vQd8iOUW|Sxyc)gPemr**>f?IZKI4?$aHL4DPzJE!}P3Oy!=#VL5jD_ z*!Gx0J;SR|)&*K#rEFA}D%5khcGM}D?Mbz}4CTsj9Rf}=lao`GZirwBmntQLsO!&v zr5V@QcG41yw6#_Wgu{jfUE&lfrk4&7UN^#ffyr*kupzegY2mgN1-QfjBV;e{8pJ45 zCT(LcEf59FCA{Go7+)P@3O@ zBss;RWn!&_w+(a8U%_@kA5xO|kja*(+4JcPa}z8>x4p;ptjxq&Ad23Ci(~x}@|)PKJ77N*(nC zl)ovz{-cG|!Udr^aIQzR&zo5J!cXnLHwp)OyHRw3Gm0()Kz*R zm8)~cYUMULSWBw^ov)M5I8RNSr-oDLqppO&S)@|23bWNWv^KDOBH`s<^UJU292eV` zy$z@|_DYUXIFl|Q=O(Z4LO0W;3mY!OGJ|{9|VG9$_srLEgsatppmsCBc zt~KwJ7Ml&H5NuG#X2CKLDYQj3y>!xw^8`~D=mxVW5QR-GZcoz^8Rhqo z?&8m&LavJmggVBTLck5abIMbys!h1`zUtRJCHYp#$SkPLz)L>@!J%^8J^16;592>g zd_VDc>+${Xw4;=EkkSrQQ~QI{`<*inK7>Y1UZ@R^*ZPN#q2Kzl(0@a`|Kff7{fl); zOhrItAa&9o<8X?d!s+UD;dVOCf<^e_GF*%B{}IB0#w5da$wfX@{VDZ`4`L>B>@{yH zyAJi3T(C^fkD82tY6D)>ykO|B#ix`#J^cPP(~j} z$AbKI|HJg{T06Gj0 Ag8%>k delta 59 zcmbQjw2+DWGcPX}0}vQGDoy0BW-Oi9t|6b4n4F!TmX?{E8lRk>SC(2-l9`eppH`HZ Nn_8YV!Z delta 63 zcmX>tc|(%>GcPX}0}vQGDsALG$H-VR`4*#wd{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W)Y_CTmXEC6_Ee{ diff --git a/mcp_servers/backoffice_mcp_server/__pycache__/main.cpython-313.pyc b/mcp_servers/backoffice_mcp_server/__pycache__/main.cpython-313.pyc index b253c11ca53eed9f0b5962ef234d701839339af6..aab9e5d4a316d912ffeefa84253f6feff040c60d 100644 GIT binary patch delta 50 zcmZ2#J;R#&GcPX}0}wPV(%s12!N-^~c?zF~P;!25L1J-nd{Sa^c79q~W^(H0+kB_^ E0EX2O6951J delta 63 zcmbPXz0{ifGcPX}0}vQGDsANM;A1SDJcUm~J}EIdJ3lQgGdVRrIX|x~wWuUBB|ko` RC^0v+JijP=^Etj#d;nv)71sa& diff --git a/mcp_servers/backoffice_mcp_server/__pycache__/models.cpython-313.pyc b/mcp_servers/backoffice_mcp_server/__pycache__/models.cpython-313.pyc index ff077b308da30e64927369ae678072898ac1f30f..afd3977a76c43a0c0bba01984608721807b87239 100644 GIT binary patch delta 50 zcmZ3?KaHRJGcPX}0}wPV(%s0-#LSpBnU7gRC^gT2zvmk{_Q| Rl$e`Zo?n!`*@M}S1ppe;6GQ+2 diff --git a/mcp_servers/backoffice_mcp_server/__pycache__/settings.cpython-313.pyc b/mcp_servers/backoffice_mcp_server/__pycache__/settings.cpython-313.pyc index f069ff1e391742daaffcfa8c4c1d4fc9aad97f3e..d1cac449220dec9cf897153550310010cb81fd6f 100644 GIT binary patch delta 793 zcmZ9~%TB^T6b4|ZZB!6Mw4huSQSgGISQWhC1wquraEvPwFIA!v0@1Bf zT#IsLFn}peU3G#h-vREBywA7G!h_BWK8`}9DjWD^)vu`mQ~?+yR2P_K71Y!as$mFm zl+YArhp@~>G^U1)!Wa?OjbY=OieT6TOcJUGRa8@I))Y(=iUmQbET&^Kz!A)WVY50l z2lIq-qKfNO0u~6>i)yi<1W+qmf@OmBAzNuMNMe_(oU!S>T(Bk=zpgVIgmI%u>CC2P z1m&+ih|)Tg(U4-iXts1FOBf%TZJpU6j33Qz!%*N5ql~jt8MZw<9FT`CC>}5|COLBO z!-_T=D?Kqe%D6B7wXQLAsmvFp^)@#x9d^7Jjpw4-8n*N0Qswyi`tanKFP0013;s;X pS*^5x=6$@DKB}EmYF9V)#O)_ry~{kD*6HeZD*I(~NP>Np{s(r2jG6!d delta 805 zcmZ9~%TB^T6b4{gOH{6ka#2JCRJ@^})*AwXH$+WLjxjDs2o^{x0ufPHT9?Kx@8Cu^ zrYm+I#hly+3Lui=JZf3sxIcMg)20jADU!zf{kya?~JrBMapJ_px)_FBx13Ng_ z4*5!>0o^KHHN!yK0E2#MpYE1~6WtKFSQ=4N^}w*C+=?1O2fm?FaZFl<^;GZ+?tSwi)rnp0FWD+nP%SwWC1n^&;~SR|MY!&sGC zf@MP4QLU)dDy$L8fhycm0yHaIhX}z2kVRVzV%X&dOSQe%AjGBO6DqSw7$=%7mDyH| zApi9cq8%05Rgi34Xp$~xp37&rO8F*Vt?{`^ zrclk6^0$?0QH+{QjGKL5ZzQt~?y_-p_Z7bXvb8Xj-JZk=vG)F?F&htAgEZo Ge_Q~kG7*CS delta 65 zcmexAg|TNUBll-sUM>b8FmzPf$ZgBYSTxy_RYN{0F*!RwEiE%SH9k2%uPn8wBr_#H TKCLJ*H?=&!D0_1=>mL^YiZT{Q diff --git a/mock_servers/mock_imdb_server.py b/mock_servers/mock_imdb_server.py index 7f6ab28..f47e020 100644 --- a/mock_servers/mock_imdb_server.py +++ b/mock_servers/mock_imdb_server.py @@ -1,47 +1,67 @@ -from __future__ import annotations +# /compass_backoffice/legacy_backend/ +# uvicorn mock_imdb_server:app --port 8011 from fastapi import FastAPI, Request -app = FastAPI(title="Mock IMDB TIM", version="1.0.0") +app = FastAPI(title="Mock IMDB TIM") - -def _payload(msisdn: str | None = None, cpf_cnpj: str | None = None): +@app.get("/access/v1/info") +async def get_access_info(request: Request): return { - "msisdn": msisdn or "62981152324", - "cpfCnpj": cpf_cnpj or "06252533106", - "socialSecNo": cpf_cnpj or "06252533106", + "cpfCnpj": request.query_params.get("cpfCnpj") or "06252533106", + "msisdn": request.query_params.get("msisdn") or "62981152324", "plan": { "Type": "POS_PAGO", - "name": "TIM Black Família 50GB", - "commercialName": "TIM Black Família 50GB", + "name": "TIM Black Família 50GB" }, - "statusType": "ACTIVE", - "statusDescription": "Cliente ativo", "customer": { "segment": "consumer", "status": "active", "contumazCustomer": False, - "odcCustomer": False, + "odcCustomer": False }, + "contracts": [ + { + "contractId": "mock-contract-001", + "status": "active", + "product": "Celular Pós-pago" + } + ] } - -@app.get("/health") -async def health(): - return {"status": "ok", "service": "mock_imdb"} - - -@app.get("/access/v1/info") -async def get_access_info(request: Request): - return _payload( - msisdn=request.query_params.get("msisdn"), - cpf_cnpj=request.query_params.get("cpfCnpj") or request.query_params.get("cpf_cnpj"), - ) - - @app.get("/access/v1/info/{msisdn}") -async def get_access_info_by_msisdn(msisdn: str, request: Request): - return _payload( - msisdn=msisdn, - cpf_cnpj=request.query_params.get("cpfCnpj") or request.query_params.get("cpf_cnpj"), - ) +async def get_access_info_by_msisdn(msisdn: str): + return { + "msisdn": msisdn, + "cpfCnpj": "06252533106", + "plan": { + "Type": "POS_PAGO", + "name": "TIM Black Família 50GB" + }, + "customer": { + "segment": "consumer", + "status": "active", + "contumazCustomer": False, + "odcCustomer": False + } + } + +from uuid import uuid4 + +@app.post("/customers/v1/backOfficeSRopening") +async def backoffice_sr_opening(payload: dict): + protocol = f"SR-MOCK-{uuid4().hex[:8].upper()}" + + return { + "status": "success", + "interactionProtocol": protocol, + "crmProtocol": protocol, + "fieldsToUpdate": { + "status": "Aberto", + "reason": "Mock Siebel SR Opening" + }, + "case_response": { + "message": "Chamado Siebel aberto com sucesso no mock" + }, + "transitions": [] + } \ No newline at end of file diff --git a/src/__pycache__/__init__.cpython-313.pyc b/src/__pycache__/__init__.cpython-313.pyc index e4c5c466f5661746fb96bec5652cfd793fffc51b..c68503c2d1957ade8b7c21848fe1cc9fdb9e1d3f 100644 GIT binary patch delta 46 zcmdnWw1SEIGcPX}0}wPV(w)e?g3)W@77d}~{M>@X;^O$E#N_P!w6x6R)QP{X07q>P A`v3p{ delta 59 zcmZ3%w3UhbGcPX}0}vQGDox~G!5BVqi-vqsVsdtVT3TjuYJ75jURi2UNoGoZd|FXr NZfbdcQTD`lRsa^%6u$rf diff --git a/src/__pycache__/__init__.cpython-39.pyc b/src/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index c93d7151297ac9363ef8ac7d856ae32c3aa8c3e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 302 zcmYjNO-sW-5KU4=QTrbjZ#|f8J&RaB@FJp!mm&<)-A%J5*$F!vOZ$)fOS$?lJh{oq z2lM7VW?&wJ)9FbPu~?peQtUs2`HwW3n^=4nNhhmBr>j(FZ^>-3e|_17lAKs>j0@tH zY;Am7V=&@EJaF(`=sb!wvJovtg~Og#^L+k1%lab# zO$wkt1^6VhosAry-P_pIeYvTpXX2n4F!TmX?{EI`ODA06*Ce AbpQYW delta 59 zcmey&*ucd7nU|M~0SF8ol_qi*F~&};(~wU}OwP_vOUq17jZe5MTk1l*XU2x-zRYe{z}pHF-2${fy*@+G%P+Ta>a|9kKXUMm5)h3v#q@(#uO;( zJzhNPMfOBMb1Mc$6D|<@;b>#j_a8K~lg-HAx*B?9n_@ zA5Vl%3=RjOWNdv;+yL1Ccg9lNp$Ht%HdL0udLwNAmJL9NAptDA%XPAD$(>JrGko-w GseS-7KS~w= diff --git a/src/agent/graphs_README_DISABLED.md b/src/agent/graphs_README_DISABLED.md index 43cf2a2..f65d5df 100644 --- a/src/agent/graphs_README_DISABLED.md +++ b/src/agent/graphs_README_DISABLED.md @@ -2,4 +2,4 @@ The original `src/agent/graphs` package was moved to `legacy_reference_disabled/original_develop/src_agent_graphs`. -It is intentionally not importable by the active backend. The active backend builds and executes workflows through `app.workflows.backoffice_native_runtime.BackofficeNativeRuntime`, which uses the framework runtime and the original domain nodes/services/prompts as customizations. +It is intentionally not importable by the active backend. The active backend builds and executes workflows through `app.workflows.backoffice_workflow_executor.BackofficeWorkflowExecutor`, which uses the framework runtime and the original domain nodes/services/prompts as customizations. diff --git a/src/agent/local_prompts/__pycache__/canceling_analysis.cpython-313.pyc b/src/agent/local_prompts/__pycache__/canceling_analysis.cpython-313.pyc index a246bb74348256800d4869a6f7ec089cb40762f3..5de576e28b46acf93446ea5336a80019afb699a6 100644 GIT binary patch delta 49 zcmey$|AL?UGcPX}0}wPV(%s1I#m<;9IgDLHC^gT2zvmk{_Q| Ql$e`Zo?nzbc>;R`07v^2v;Y7A diff --git a/src/agent/local_prompts/__pycache__/duplicate_analysis.cpython-313.pyc b/src/agent/local_prompts/__pycache__/duplicate_analysis.cpython-313.pyc index d0c884ebc0cfaaec0d26876ab35fdd3fb163debd..b04e02dae67d07707b4366aa8e5b4ccd929c17c3 100644 GIT binary patch delta 49 zcmeA+`)A7inU|M~0SKBF>2BnXmtxGAoGqmxl$@VikXT$CpOl!Kou8JLnVdR#lT;)C DdJPa_ delta 62 zcmexo+HJ=DnU|M~0SF8ol{Rw6OEH#C&X&@UPfASA&QD9rOiqnY&d)1LEh@=O$&XJf QO3Y0y&o9cJyi_U@08_dZCIA2c diff --git a/src/agent/local_prompts/__pycache__/postprocess_tais_kb_query.cpython-313.pyc b/src/agent/local_prompts/__pycache__/postprocess_tais_kb_query.cpython-313.pyc index 425f2b7176ff698c3d3da549c70b231a11e8c4bf..114cc014d69cf1538a7aabe8dafe955d50399fbd 100644 GIT binary patch delta 48 zcmZ3kI7^ZHGcPX}0}wPV(%s1Yg`Y8hl7NO#a(-?>VsUYNQetv;ep*^)a_VGvfdl|! C5f7dK delta 61 zcmbQGxLlF@GcPX}0}vQGDsANc!p~SUNkBtBDKR-aKP@dYIW;~xKd&scs3bEbKR&G} PF*mh5zbJdMl|TXjI1&_M diff --git a/src/agent/local_prompts/__pycache__/preprocess_tais_kb_query.cpython-313.pyc b/src/agent/local_prompts/__pycache__/preprocess_tais_kb_query.cpython-313.pyc index d4486a58a4f131f0d1802180d35c89b3e8707681..b935f7cf9781d5c7fb3d965532d43d88c950c40a 100644 GIT binary patch delta 49 zcmaDMc3X`5GcPX}0}wPV(%s0tjf*jF@*yq_q2&DBg2dwD_@u<-?EJK}%;eO`oZRsM Dh+hyt delta 62 zcmcaD_Ck#NGcPX}0}vQGDsAN6#>H4Y`4E?ed{Sa^c79q~W^!tLa(-S}YEemMN`8D= QQDSatd45s$$gGcPX}0}wPV(%s12$;OyFc`BQRP;!25L1J-nd{Sa^c79q~W^(G}J8Ve+ DZ6pv$ delta 62 zcmdnUw~vqeGcPX}0}vQGDsANMWMizFJe5sDJ}EIdJ3lQgGdVRrIX|x~wWuUBB|ko` QC^0v+JijP=@_Du-07Cl}4FCWD diff --git a/src/agent/local_prompts/__pycache__/ticket_reclassification.cpython-313.pyc b/src/agent/local_prompts/__pycache__/ticket_reclassification.cpython-313.pyc index f08979a5a1a78a125edcd4ff9502699af036afa1..c5d650dffa24bc2b7ef6f5d1bc163c5dfb48c640 100644 GIT binary patch delta 48 zcmcaBa6y3kGcPX}0}wPV(%s0tmYp$o@=kUQq2&DBg2dwD_@u<-?EJK}%;eNb9I*gz Ck`MI& delta 62 zcmca0a94o)GcPX}0}vQGDsALm%g$Iec_+Jud{Sa^c79q~W^!tLa(-S}YEemMN`8D= QQDSatd45s$J+#{$VpOl!Kou8JLnVcG*oS#>gT2zvmk{_Q| Ql$e`Zo?nzb`Iuk~07iio8UO$Q diff --git a/src/agent/local_prompts/__pycache__/treatment_decision_prompt.cpython-313.pyc b/src/agent/local_prompts/__pycache__/treatment_decision_prompt.cpython-313.pyc index 4ab6fc6fada159f97b780e205d561e470ceada07..7bc6b19bc93cad65a97c3cb9edd095d572923dc3 100644 GIT binary patch delta 49 zcmbQH+^Nj{nU|M~0SKBF>2BnHBEXnG`GbIlP;!25L1J-nd{Sa^c79q~W^(FebHR83 DdY=$d delta 62 zcmeBFo~F$GnU|M~0SF8ol{Rue5n!yD{6RoNJ}EIdJ3lQgGdVRrIX|x~wWuUBB|ko` QC^0v+JijP=vX)>x09fP|761SM diff --git a/src/agent/local_prompts/anatel_motives/__pycache__/anatel_motives.cpython-313.pyc b/src/agent/local_prompts/anatel_motives/__pycache__/anatel_motives.cpython-313.pyc index 0d48d0cb959423ab5a7203aae6cd8369103889ae..a59e4abd72684934a09ef95da47ce0f422b65156 100644 GIT binary patch delta 52 zcmey;$oRaGk^3_*FBbz4G%eEI$StSASUg!vLqjMzKer&UxHvv3F*!RwEiE%Sb#tLc GvjhOKIT0ZM delta 65 zcmaFf$oQp^k^3_*FBbz47&SC(2-l9`ep TpH`HZn_8YSC(2-l9`eppH`HZ Nn_8Yc>6VLzv diff --git a/src/agent/local_prompts/emulator/__pycache__/response_emulator_generation.cpython-313.pyc b/src/agent/local_prompts/emulator/__pycache__/response_emulator_generation.cpython-313.pyc index 0f83abb9f754b8fca92e5ebd852aa2a7dc06f812..050acc44fc94d0fea9f23b4d2bbdb0a62ac094e0 100644 GIT binary patch delta 49 zcmX>dx-XRbGcPX}0}wPV(%r~?Mw796@(oQ5q2&DBg2dwD_@u<-?EJK}%;eO`@>**E DqG=I) delta 62 zcmdlNdODQ*GcPX}0}vQGDsALGqsiDY`G%&3d{Sa^c79q~W^!tLa(-S}YEemMN`8D= QQDSatd45s$WFf6J0E^ldKmY&$ diff --git a/src/agent/logic/__pycache__/validation.cpython-313.pyc b/src/agent/logic/__pycache__/validation.cpython-313.pyc index b9525d70599969d59a87ae2651a06573149344b4..52bc34ce859a4cf7c4186e5cac268bdc0af13eef 100644 GIT binary patch delta 50 zcmX>fa43NLGcPX}0}wPV(%r~?LWD75@)Z#cq2&DBg2dwD_@u<-?EJK}%;eO~(xN89 E0I6{h#{d8T delta 63 zcmX>Ua6W+hGcPX}0}vQGDsALGA;OqC`HF~!d{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W diff --git a/src/agent/nodes/__pycache__/__init__.cpython-313.pyc b/src/agent/nodes/__pycache__/__init__.cpython-313.pyc index 7c18e7e09ccef0cf8f0149b206756323aac192f4..395325592fcb38541e97bf55e8e518408d5d0992 100644 GIT binary patch delta 49 zcmbQl-pbDXnU|M~0SKBF>2BnH$ix^n`7M)%P;!25L1J-nd{Sa^c79q~W^(Fe6XrMo DXh;vm delta 62 zcmZo=pTy4nnU|M~0SF8ol{RueWMWL7{FX^WJ}EIdJ3lQgGdVRrIX|x~wWuUBB|ko` QC^0v+JijP=vO04d06TU#&k;l-QkCeGq`E^o zx=XscM|!$X`g%YHdPs(PL`Hf{#(F{~dP=5xMrL|W=6XREdP$Z|d_`7ivQI?kYf3WF z{g`ZfKhj9Q&FWhrivk>&K)KZi#bjLB12`6}qs9uTue^jEDC!+1j5PZ;o)r*yNrU7S zgf_H%U`h%Wq&00|BemF3Fi!GPqe#Q}M2fhU;Y1(6$wKn88`qo}4hmJ6Vd~_iZ!cZ> z13=XKo9w1C_NYMYf$o@xfAZJC0Sk?|051KXx2-tiCD1r|)k-`KQlGWqQh$A!Yzn!( zHv$T2K%8B>?B0z7u9)|aWnR#_Y5a#e+no;a40ZPk+H$vRG7i?N=3%ZI54q@;#Ptyd z2t$Ms!WaQv)sVRvuI2~}1T>UeBCHTl&t(xlY}fVg?Ela|G9zg{q?9Q|>9@pfPzm8@ znSb)&e9oQpK{8`Y>q}X&Bg@~}qfwR#pR+ysqi{^a(YlISF6mv4ro_(d7_V#*tpd4s hygi)bANZV7X=I@E`QcQLUTG_06JMjfJ(m7{^9xg>36KB) diff --git a/src/agent/nodes/__pycache__/bypass_rules_node.cpython-313.pyc b/src/agent/nodes/__pycache__/bypass_rules_node.cpython-313.pyc index 2735373c6ca473d3679a363395d55a891eb982e2..eba6319b97f2f841bd3a50c55fc1c4a2cf16c696 100644 GIT binary patch delta 50 zcmca(aNdCXGcPX}0}wPV(%s1IFUS}_Ia*LdC^gT2zvmk{_Q| Rl$e`Zo?n!`d8*(pHUMQ-6>tCm diff --git a/src/agent/nodes/__pycache__/cache_check_node.cpython-313.pyc b/src/agent/nodes/__pycache__/cache_check_node.cpython-313.pyc index 89f414348ed2dccbe1582b217bfffcf94d9ffc0f..d71b2c839772ef2ffff288ab4c7be4731d065217 100644 GIT binary patch delta 50 zcmcbmdRCSDGcPX}0}wPV(%r}{%EK5pS&>IWC^gT2zvmk{_Q| Rl$e`Zo?n!`Ihv=44FE`v6i@&F diff --git a/src/agent/nodes/__pycache__/canceling_analysis_node.cpython-313.pyc b/src/agent/nodes/__pycache__/canceling_analysis_node.cpython-313.pyc index 4f1849af4c60c3d15f326611850ad049be31038f..6db86e9b5dcd2d3fa09be11e8b1de7d5b351cf44 100644 GIT binary patch delta 52 zcmaFf$#|=ik^3_*FBbz4G%eEI$j!mRm^xX6MMEe#Ker&UxHvv3F*!RwEiE%Sb#pXJ Gj{^Xo`Vfo& delta 65 zcmccB$@sjJk^3_*FBbz47&SC(2-l9`ep TpH`HZn_8YgT2zvmk{_Q| Rl$e`Zo?n!`Iau_*AOKSF6!-uD diff --git a/src/agent/nodes/__pycache__/different_complaint_operator_node.cpython-39.pyc b/src/agent/nodes/__pycache__/different_complaint_operator_node.cpython-39.pyc deleted file mode 100644 index 64a48f2db47587ec50c9009a7886f6513e6c81b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6214 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 KLjP*u+W!EUQKUTp diff --git a/src/agent/nodes/__pycache__/fetch_ticket_node.cpython-313.pyc b/src/agent/nodes/__pycache__/fetch_ticket_node.cpython-313.pyc index 65e7ad8356df0335b821e93c4c3b73242529e54d..8631a20dcba7ca57ccab383dfce6da52d780dda5 100644 GIT binary patch delta 50 zcmZ1^GF628GcPX}0}wPV(%s0to{cen@@_T_q2&DBg2dwD_@u<-?EJK}%;eO~OzaBG E0C?LEV*mgE delta 63 zcmbO#vPgvcGcPX}0}vQGDsALm&&HTDc{iJed{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$=C5oD%m7$j6(#@x diff --git a/src/agent/nodes/__pycache__/identity_verification_node.cpython-313.pyc b/src/agent/nodes/__pycache__/identity_verification_node.cpython-313.pyc index 9998b4bd33209e84d5b0812577fb4641808ce1f0..4de9eaa682c8b34528b402d3a6172cf9dda15765 100644 GIT binary patch delta 50 zcmeBi{O`d1nU|M~0SKBF>2Bn%V`j{l+{LURl$@VikXT$CpOl!Kou8JLnVh=$BJ*w; E0Ftf|FaQ7m delta 63 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 delta 3320 zcmb^zS!^4}b!K;YAG$^HlBg>ZMV--MOO|X=zM{w$6;2j*OQkGDE-A{=QXP`6(-x4^ z14Yp&r4GQQ_h25f`eX}G*DwYit?GSwP z=3V=)dAmQo^tV&arw)e|!5Ry9ZQSg*;cUZyztQ*o9otgN>#ejkfCwUZ$wghOC_2jJ z4zDh>>Yl_U8uhF;68ow^9IL{FM4TS9Ax)OWskhAW0jG|0s6T^)^?RJZ927NcIHRZq zQb-gO&5~DGJ6^C^7q?Ptr#G{}U~l2}`nu}*ETuWhuHjHjGvsw8BUK7TswT_M=+AWk z{2u(D{tH6vMgjCLiXHGPuBkXC>e2vY6q71=)W~jFhlQwx{Y+|NCk4Ahi0PT)0#S!f z-4Hyu#J?rj%h(5k-7ONcES>*>Q8tz{^i|1fFddw}BU!y>*?bU4=8*GVcxH#+U$IV_NHb}X1=0lnR^l2q z#yZ%p)H@~;uO4=1Me?#peA9yZqF{Oc#%$dO(nXdtxX<@i&a$bJE+-=Gu`1nAL+=J8S=RdFnU+L4T-L0)yy5*;Y-gS>b{-K1w)T!f3d z4sCT6zbh^q?5GGO+P))OljOP7H*NJ+?UGky6T$kgZy1V9%zDaei_`z*;#B;GW@?gc zBxnEv>;vUJRNe>qPKMa0jy6vuNrq(;22Xg^fxH!RIN zkV*r$|7E)}>Op37UR=JdLoYyK`7<3h0L068boiPXEl+f!*i^-56Yvs0LP)j8U| zjE^LJ$@Yrp(OI3qZd#q4<=Ln@UNTEM*v-27q3Np8swpQL7a)uyC)KzE0-Je(mPp*> z#Iyi2>{Qu5B-=@lx$C{5>QI`m@Tz<4bOi_b0T!=sIa_OCfZ$2E5qzz|yWo)Z8eRmG z*+Z5>+|o|1rO-<()$nvnwR(du(W~KcJu);bsm|EJy_+X<G%em^z zEQQKnV?cGXH>|Eu&D^hAIl2#Eb~g2uTc9diE$?$9%-3l3+Qar97(6QMX`DuLVh2j& zV`3Ty!*|1tD*|q0KWXl2=Wb}t`K<&k#Mg^k2{pc+P*a;(H50_Nl|5>He>^Bq9=m2q z>TmpbHubHBb4nq(4nl#&i)R)B;g!Wb{@w|Sx+LvmWA3k<-up8r88jRJ4k+g1$y`d& z%*pL^JgIJPXwvp(Le;D#=9_PCD_TPdKcnQ6G`n5M=2Z5+dj^Nt6L&ki=Q=*Jcc1%V zgAWS&Hkd1_1*$*RKtsTwgBoT?d8#jWi;wdvCN0;PNgY36ubO>8OgxMs>Ikdp${94i+W z&%_~r@z)~cP0h5P$a8wIj@EGvV=3jdksnOSoLW$>6*O@xpP~F+K)oF3Ve1vLXW6&? zXIr>x;PBFN>~nvA$66wJC6`WTlM19yy{gbcHkFH~DR}kG9KFI?+UNXV1MPbF=Pw%( z+C$gTGb?ho{do2Ixi74qyX);Igtq36_tKv>EnL6wg=GEV(mP9^nZ3_MZ1A%y-7|N8 z+5JZ>oR`>oug}paby)v#PC%9={O@OXf8P5D@B9Hwf45(r#=pT4r*vn*2Iz-VIMN_} zcr0vy!@XG?X_oHIowmT?BO{Kuq>oHtu5o_^M?BK~(OJO%G}IsILLax_h+q1+^-K#K z9)xftAUzoD1pJ{x0HKEsn8Rirx^x)!=$jvNp@0s%Z1R-&aOi|QCVtY7S3<^5f@cLd zJPu)CJRamuJsvY~d`gt3ncDxsN;5$-FesJ~}dgCn?|{UTUo3%(v~X0CxQm!%|6lf%gzRRE~z zY=&A{#&-8{a-Df zM;6bmUoaSP^R1bE1lzB=|H(Jq Gi~j(vWnl{d diff --git a/src/agent/nodes/__pycache__/knowledge_base_enrichment_node.cpython-313.pyc b/src/agent/nodes/__pycache__/knowledge_base_enrichment_node.cpython-313.pyc index 240b7fe247ece342bfe95915dfc15d6a63d65c86..97e125cfdf2b759d92c34a226b09ff17d66117d8 100644 GIT binary patch delta 6163 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 delta 3701 zcmb^zYiwIr`J8*N-;X$cBu-L0cHT}JC(Wa&L)#>6(=>6DbUAg`)}D-G-=uEc>+D>o zk4aM~8ZZfIT6>0gNQhPZ*veB~(1Z{|LWoBPOq9{m-Zcy~38V?Ou@;Fpb|_g#4bzjMxc*Ws`tSlh;$PBxETbo%iRF1C-XOj)Tlga{(WxNXW# z?fTvncT72{Q{S88RZ}kN()X5l^^}{sr##d%<)vO7XN~)&YG_RerO;fI8+dRvp_G3R zmvOX?*l0bm(+1+8TZl6iAS<}rgb=Ap1qUSJsz)a!+6bor(eVQUsn&5J;!cGD-&CPI z{2dStU;}h`bpB@It#Az8fa|I%g}X14>mY3`Xm9 zOq-5rSjQU479HE3a*;qv08RlogB&-wo+8?@DB?&XyNRdS8-3lZNjSOsRUwD%E?`i3 z(n8vK=8!rX=QG(;#f61@R!(P&${CrK^0{Jqfo4w2XN&X{n~>s$THvo|UzEOwUF@JC zu#GFx40%P7sV0@=b0t;e8bcvk!znhiPMFb5@;TV6DiHgDsF}t$&OB2zrXzFt#e6AK0H!Vc zY$z1Z$}}Ra8|Nro(uAy{N(h;Fm=Gs(IHHE#K-|0O+ZB$6IfB z91fph7GD^|x_lvFpL2EEcSx)WqND>z`XYW(N9q%p_*uBs2aIorItP=@6>_C^6;r}A z*IL2e|0bkl+xqF^WgnXi58+OBA>4?!vdiHBjezQgYUJ8_ty#Y)A zyc411(7HL4u#$GJsq(KjiwPzjQR$E{eGDNR3L(X&uyE)5K2f18|jJ)iUWcNCoTmo^@=m$+~9#)KKeJ(&1(}l9t#G&N>!rj0rI~{ zl*L<`#h$XUs@{IF;u()xkL|^vm;I>4-0DjDHllEW>FSuERBy_4AL%b^2@fRstJ7D) zRng}}WU${rwnK6B@!}Bs64mUx?LIcsY8Qvfl9nC)qRwIE9PIg4$zUJHz_-iqXIEQm zv4hRFG&*7xoe%pMdBDdW^avk^iTzO?m_DK7AGZ7LwmPh5!Lzeslk7T(GN<&ELelYW zcD>5O{O!Y*Fd2bMa+k9> zBVY6IUy%G58Welg1GK6CBDab5A95jrkAJK|AXaExu>5p3-9Vfid{h!P?j){PXB_U} z>8`qN@0fQ2&-4?lz-|F2_m#usZ6fncp7JClzP#op_`k>WbUFRRLuO*a|0DVAubq7p zkGi%;#WwrD#}+8Z_UB4$3uu?vh!*gWxPT*vR#&_33Am5F9Q_8KWu#}x7=bY9adxfe z3{JAq-fu}MKwRoi;y6q7e<}D$PUbwCwU8;vO7?vEv`Tp)LE9}c$H0~qQy#hyEoL=q zDPJnc<$bxQDkaUF%d4e~l9eNpX3Z6|%co_fG?~*3I*2+(Wkftv9GuHDSN2G z)S*Ve#zr60YL<#>i5r5!Ag?U)u?HL~8R#JpW@O;YHqAs5d-skLvfRTmJ#EZ8_!{2N z{xG;3msnu?PdyQ=cR>1C5TKvq;92(W_MhVx_UcgE3UBe6u~1xGhK4t{EjdG+hVzr^gLk;$5SUgQq4;IqbCp|;qA zI+zOK7jeQaUEXhm?aw;))Fo=sHH;Hg(lueM0}iisjs+8L=~w0hopAbHUjy*nsKT(n z;WltsYfA;h8%<;8W3A%NPJE=>c(ZHI032>Na-FwZ9YDX`H)cxtMJmWB4e)3av_|*=V*%WdO=Tez9BDEI5@%qzZ}ZPaq8iqmV-tPc*()TT3#y1n`Tu$QkDx*uO@z%R}j_5OBh5) zkY?U_x|mxo$h+yQK;sQVeH`HXBF6YlK$Q diff --git a/src/agent/nodes/__pycache__/reclassification_analysis_node.cpython-313.pyc b/src/agent/nodes/__pycache__/reclassification_analysis_node.cpython-313.pyc index d99473931fdfc4f133f6c845b7db713854fe1465..c7ec56325b362d21c899d05642b5d36e05c64b68 100644 GIT binary patch delta 50 zcmdlMyE2yhGcPX}0}wPV(%s1I#=@90Ifz9=C^gT2zvmk{_Q| Rl$e`Zo?n!`xraqo3jks56wm+w diff --git a/src/agent/nodes/__pycache__/siebel_sr_opening_node.cpython-313.pyc b/src/agent/nodes/__pycache__/siebel_sr_opening_node.cpython-313.pyc index b37c566f9e5df220659b08f32c93e180a7d69903..04e156ffbc0edd0a9cfdafaca3dcc851a1c3b8c2 100644 GIT binary patch delta 3556 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 Iv8=cM0=(~d?f?J) diff --git a/src/agent/nodes/__pycache__/siebel_triplet_classification_node.cpython-313.pyc b/src/agent/nodes/__pycache__/siebel_triplet_classification_node.cpython-313.pyc deleted file mode 100644 index 04733973b1b27ad6f904793a9af3b3393bb1abe5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6236 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 diff --git a/src/agent/nodes/__pycache__/speech_enrichment_node.cpython-313.pyc b/src/agent/nodes/__pycache__/speech_enrichment_node.cpython-313.pyc index 051a321aba54b22ea4038c5761bb199d52938b78..4527896fb887fa8348386cf823e39f4a1931970f 100644 GIT binary patch literal 20260 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 p0`eIS)JB`?9wub}LB#5UOIX diff --git a/src/agent/nodes/__pycache__/tim_complaint_analysis_node.cpython-313.pyc b/src/agent/nodes/__pycache__/tim_complaint_analysis_node.cpython-313.pyc index 25051744bbe9321cb27426ad9606f6d7ce8cfac1..ea16ef80b899e5524823fce157af69e0594a918d 100644 GIT binary patch delta 50 zcmbOd*dECJnU|M~0SKBF>2Bn9V`j{p9K@_4l$@VikXT$CpOl!Kou8JLnVh3QKq2&DBg2dwD_@u<-?EJK}%;eO~I;_1+ E0E(RuYybcN delta 63 zcmZ3(zmuQ)GcPX}0}vQGDsAMx$-gT2zvmk{_Q| Rl$e`Zo?n!`Ihikk6#z*e6jA^H diff --git a/src/agent/nodes/__pycache__/undefined_complaint_operator_node.cpython-313.pyc b/src/agent/nodes/__pycache__/undefined_complaint_operator_node.cpython-313.pyc index a08901dfaad169aff6bb9b43c16f593bec541844..d7f3a76338249255173d8880d14879015759ad66 100644 GIT binary patch delta 52 zcmZo~Wc<~@$o-j@mx}=inilD9z}Vi%$o-j@mx}=i3>}p=avMl6)=ajM(2!3`OwP_vOUq17jZeC^gT2zvmk{_Q| Rl$e`Zo?n!`xtT>;830gA6l(wg diff --git a/src/agent/nodes/emulator/__pycache__/__init__.cpython-313.pyc b/src/agent/nodes/emulator/__pycache__/__init__.cpython-313.pyc index 2d5a440674ad719e704e66b69bf5dbbe0aecb828..d6647e2b7c013eaaac7a891001ea73fa1d95bd0e 100644 GIT binary patch delta 49 zcmbQh+RV!RnU|M~0SKBF>2Bn{&Bz!(`8lJ8P;!25L1J-nd{Sa^c79q~W^(FeJ*Ff8 DW-AZ1 delta 62 zcmZo>oxsZdnU|M~0SJs7l{RwUW@OBn{G3rkJ}EIdJ3lQgGdVRrIX|x~wWuUBB|ko` QC^0v+JijP=vLaIw06n=BdH?_b diff --git a/src/agent/nodes/emulator/__pycache__/_rag_query.cpython-313.pyc b/src/agent/nodes/emulator/__pycache__/_rag_query.cpython-313.pyc index 18ee524d6daba9b5155d7bfa87d71ed45e7ac217..066f01670ecb8a1abd1d6c990edc12663abb1d9f 100644 GIT binary patch delta 50 zcmbOs*Dc5WnU|M~0SKBF>2Bmc$-i_@% delta 63 zcmaDN@lk^NGcPX}0}vQFDsANc%FI|cnUO_9J}EIdJ3lQgGdVRrIX|x~wWuUBB|ko` RC^0v+JijP=vo(t*2LNsK6tDmQ diff --git a/src/agent/nodes/emulator/__pycache__/close_case_node.cpython-313.pyc b/src/agent/nodes/emulator/__pycache__/close_case_node.cpython-313.pyc index f3624259a6e459a0f5ee128f17d9b87e3eacbaf6..f741a264f1bac1e43fec93a840f32aceb2fc4a7a 100644 GIT binary patch delta 50 zcmbP}-k;9>nU|M~0SKBF>2BnXc4h^B?{M>@X;^O$E#N_P!w6x6R)XkGP HCVKz?pAr!Q delta 65 zcmbQSh;iv6M()qNyj%=GVC1N@k=vewv1+n6hlYGoVsdtVT3TjuYJ75jURi2UNoGoZ Td|FXrZfbdcQTFCmj>#SXe;O6X diff --git a/src/agent/nodes/emulator/__pycache__/persist_draft_node.cpython-313.pyc b/src/agent/nodes/emulator/__pycache__/persist_draft_node.cpython-313.pyc index d29a928d4dff1910b5f3ad1685d275222668bd46..20af52b028c9bfab11a9acffdf37bd094229fc43 100644 GIT binary patch delta 50 zcmcbsctMf-GcPX}0}wPV(%r~?f`u`2@)Z^hq2&DBg2dwD_@u<-?EJK}%;eO~(yWKL E0i13S>;M1& delta 63 zcmcbhcvq48GcPX}0}vQFDsALG!NOQJ`3j4Md{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W$vCxrkLmC^gT2zvmk{_Q| Ql$e`Zo?n!`cnvEv05&HSPyhe` diff --git a/src/agent/nodes/emulator/__pycache__/router_node.cpython-313.pyc b/src/agent/nodes/emulator/__pycache__/router_node.cpython-313.pyc index d18f8eeefff9618cd80a80490aefb86ef2fcc749..2d54aaaed3ef557fc09d62d39fc233ce4bc745fd 100644 GIT binary patch delta 50 zcmbOyK2e(^b delta 63 zcmbOzK2MzcGcPX}0}vQFDsAMx%)*#I`96z=d{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W=YlxHUME66zTu~ diff --git a/src/agent/nodes/emulator/__pycache__/start_response_emulation_node.cpython-313.pyc b/src/agent/nodes/emulator/__pycache__/start_response_emulation_node.cpython-313.pyc index eb783d72a4572c10def608fd145ec7b2265a2715..f4f51853766538c799396bae861546f980671885 100644 GIT binary patch delta 50 zcmX@9wMUElGcPX}0}wPV(%s12!OB=Nc?zqBP;!25L1J-nd{Sa^c79q~W^(H0+pKx~ E0F62j(*OVf delta 63 zcmdm^byAD_GcPX}0}vQFDsANMU}bEaJcU(5J}EIdJ3lQgGdVRrIX|x~wWuUBB|ko` RC^0v+JijP=^EuW$egJGF6_@}3 diff --git a/src/agent/nodes/emulator/__pycache__/validate_actions_node.cpython-313.pyc b/src/agent/nodes/emulator/__pycache__/validate_actions_node.cpython-313.pyc index dcf7590b708373d17d77a1e971cabf003a704d6a..9a83dcedef05eee9106b0339c36089b87d869e7b 100644 GIT binary patch delta 50 zcmX?RvD1S4GcPX}0}wPV(%s0tg@rL^@&OhNq2&DBg2dwD_@u<-?EJK}%;eO~?5y_U E0G6>3JOBUy delta 63 zcmdmKam<4IGcPX}0}vQFDsAN6!opZN`2dTCd{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$=3gxK;sAcE761SM diff --git a/src/agent/nodes/emulator/__pycache__/validate_response_node.cpython-313.pyc b/src/agent/nodes/emulator/__pycache__/validate_response_node.cpython-313.pyc index 0a9ec408080846acf99644d54e39890bcd145fe0..741a95f092a78c6685a9d3cf6d89b3dcb50a7a84 100644 GIT binary patch delta 50 zcmZp*`C-ldnU|M~0SKBF>2Bm+&%&5Hc{huOP;!25L1J-nd{Sa^c79q~W^(FgCRS!i E0F{gn`2YX_ delta 63 zcmexi-D<=AnU|M~0SJs7l{Rv(XJM?GyqiTsJ}EIdJ3lQgGdVRrIX|x~wWuUBB|ko` RC^0v+JijP=^H&yTNdSIP6}Z?a(-?>VsUYNQetv;ep*^)a_Zy&Mt=ZK CbPo3b delta 61 zcmbQlJfE5SGcPX}0}vQFDoy16%a}ZwlTkxHDKR-aKP@dYIW;~xKd&scs3bEbKR&G} PF*mh5zbJdMGowEM9AXo^ diff --git a/src/agent/state/__pycache__/__init__.cpython-39.pyc b/src/agent/state/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index c5b384bca2e97596354da4609bbaee1361f6aa1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 401 zcmZWly-ve05O&f~P()t<7K^P*EOkbRN=Ph-rLbfz z9A`n|B!9k>zMs?KVv(~@tM$#>XZXLy;cum3xDSu60w`88m8i5$y0lCare<|g&Q!Kx z%d>ZruWN04PCfRTD_t3DdgCnd%6a~Twtn=uZ;CvBX$C$hI)h6HI5py!y}3ZceJfTMIzcl<+0O8=XcgT2zvmk{_Q| Rl$e`Zo?n!`IYPi$3;;sK6dV8m diff --git a/src/agent/state/__pycache__/agent_state.cpython-39.pyc b/src/agent/state/__pycache__/agent_state.cpython-39.pyc deleted file mode 100644 index 7c4f15afef4dd36bd1a81e6deb67c79ba8517116..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9232 zcmcIpTW=i6b?(ayFT){4Nz`TSO;VmNxMr&qJxMF!y_oo=2Vf> zR!{eAb&n|86cAwdb$@^XJ?y>&u%GfH0^~pRWAc&(0>gQYy-B`vs&6wKCSGGR#ME?E zSDmUl=Q~&WtE(*wpSQO=Kl_h2EbCvXQ~xZY^De&0Z_r4qZ%JD^p*?c?&dBY%qej0m zYWAC>h5o{5vA<~3dpBGfE%%rCxe>NTEBzIIZiemAYJb(X-nZm}T>Qk6i^}=f?XSsi zs)oAonw7U}a`}}jTXN--W`A9+sissYw|kAu1<};CclBPYjWwa)%}y7|5I!G zNJXhgQa@Efs>2`((jbn+VXVbNKRS9}`{QA+)!G{di5SIl66VuXBGRGC7bdBm4AO~K z81qwssbfD$loSUlJyt3bQ7l!`3L;+P^Oi?US?rZWMt%^b_$I;+LlHzc!pP^tL`q2z zlM@|8M=i5ly-=oDTttz6-`T z)dGaPc<7*AlFl7VE#ue4ZwtQ-{I1})iQhKnu3~hJ=F%U=7kIqI&x^I^B|MjNF>jgQ zl_NaA#bX4qCAm_2Zr`!wDnz}O8A(5;n@@hcVp%PL4|heu`I5(?CL&SeG%ewE42P24 z1~?@m3M|BjHHa`U4#W7EaHHeN(U1udhH9Jj#5QElXc1ZsRPdZ21w0vm`U!9`o}|K$ zB;EsY5mWIaF&Rsesd%n*LIB3pc#>jnk7sbRou)cCn4~J%;yztxWQ3n=34)BknFn!1 zL=5zb*W%^}laU|gP`M?xcgjbV4tm{^9?|3vvj``r8;*4_^7V;0_D@6_i&XoAXZ&Jn zFXE0lZ9#*7OVWdh)=*Y20Wh~9I?@L4Lk0t!6_2!2J_r0#W4z-r*0fnMPHjP*4-<7b z30d)_I+z?C5lP}R&M4U^_@RK{XsbD=BoYr^_@i+M?ut$rj=Zss2jDK|cW#MJ8pokm zVu?m_Vx3lb!)k>G9VJ3L(Lk#aZjH^u7zYXi?#Wn;VWRdEm3no)>;pU{IXctS$C#8@ zbe`P5zxn9V=1=hvAAGR&=+V~W$4`NUhz!A~^)G+_51pQPkc?G0^v@?3ivcbii~Z`{ zJv#TkP|@?i#~J-t+9!;ez8hN>q&p@GNxo8W#xVJe^L?(@CXj#$aj((;=P1 zvPq(JPdrwsIDj6ObjaMmQvnV;YkXm zDM4SZ5@62|CaN++<)LrmHqU@V4~LaoVh^q=%!h~z$z-Ht$+p_6auY9whF~FDk@_IT z$EpxIZ!sLZ3O$l1%;3XE4}pG0TyJj7l7N0r*oYOFk$931bl)1~?Om11zhIIiVBBnGyJq;$u$$+3>l+WYr% zivWXwkc%{*NqO9Z_UB%+dNE4a2as2y!DF&EUXXf2HbhExUh*Ni$-PLW8+Y&CHU57~ zY*XlHf|hs0FUpJcdOf~ru`$`5Cv}H?lSGfD?{q#;VHkJ1Pj8)FT=ye%%2^+Fc17KA zW5sS9sX26~jobP23Y&r%WNAw)fc|%0&Y@fB0cLcdt@^FEzuTEJv4opJBGH>Oi$#cc zbc?C0)?~BGUb%dGyB4mECh%51to}Hyi)l{CR(oBev`Z<1NQUtwlzB8K;wUT(wF)K2 zQYV740anvk28Sm#3VX2VWxU4DGpBX{OQ;oxhd7S$eYc5rZ84OqGS6f=I7lNkfLL@e zz&be0Dl)2R4O7XMimkJD9Z1=FWqM6elU%M-x9J^N-%5 z=gD~Bd73g~?NYNu%`%$og6H`reIk;WM9FpL!b@i^vNzqJnG4iVqLekr`Txq&e?}wJ z{O7YxFj^;@1C8J&@S}JbC&S>Gf9!AGkB_4;_GPlk34wR0aiHT^Kl9>2;Jv*$h(~<8 z0|d|U;bAaPn~5Hn$(x)X>XH%7!E=HaV$8sGB)$JxJOwyLYZ+4p&+CrzKQ+%{q{+N64Ipo0=N6( zI7ktdh`Ql4-sm>MiNQ0(O%;~6L_7-88KOU6H)akRkIDT(r70Q12~J41xx!J9WR8yA z4WN6uQ-z6wrGAm_-$Ephe2f+k=sNi^^Q&*`qgwP-zgf+{(Qvs={A7q&2p4#c5JBGJ z%Y!N9?en9tA1OFNxeNUL6hjOhx;&zkTQveC8jXOO;+I;0QE6}OWJR>HbN_#fQjC=U zmh;@&ZFdYHf}ewh+m%BEV5EsbXA(ZXnYIB{)Hd4n%XIDjV(u9;Yxf8<_|t9lS8D#J zzcw9QW-G?qbDWp0)FQg~x+}U35}Fi5uTgV>8d5@iks4AfeVLjKYOYXo6-~F9T?I_NBei0&lYoNjE&>z+;FvFs6r^6IGjYBlH^_#fonktX%Dl4+?o$ZdMr>p$g>wF1EYZ4 zg9>?N@ee*PRRiFf5+>f3^f5ZhvqfGut&KcsOWZT%in`t6$)sU#zG?WkB_0)L%WsJj zm{LwTmmkh3!H0Rhr)Cv-B7+NZYS7Ix_eiDLf+5&-br(X>Z=&h9ae3H!!{N$58N6IE z3k*)mS-&KSk}I?>uG=m65#7Uc*D+Mj0D(Y3zTzIf34xu2-9)8NI^VZkD;K-#e^H3N zEOjua%NPM!2of!bHJATf$yb5S0L4?-1sKd+UYd(qiV6Y7E|ip+U*NYXM-Ag+WIhq% zEo6=fg8v(+y-{WXYI((uNiq@R7MQ?Smi-?rPh*9Hq5?z?qe!U?Q!ax??M111@uXAE%meMG)!esu6E=q=aT5;x z$~NGcu~(Pp?EQ}fBf^t)dEM4;;kVo5#aXM$y|PvFoSV+9K?#?!QM{Cv<3skTgyy^G zoZ7HO?s$zLN&tQ3QV2s3{mhaLvRwFW%7xDzxp>Wb*+}hE>$D-4K6PFi>$U8^Q3Nhj zUg1-KgSEuclp<%r`<1~{-4!JcGBUcsvuPllLDZg}DB6`ZN(?El%{RLx-t$9bvoQ{&kAtL2=D$uz8M}vl z>wxN3_~0{?cc>fIQW_-)_fSlGQ0go?g&KA$dKKQz-;;P^Fh>4%7uJ>G@*Q+$UHo!M z<=^o(f$_4eOZu~u2P}m2AA`4!$P6|7ypgVuKr6r7LgeZ z&x(J2c3&HUGw$_b+txq8k|`Vz21*>-VrqNQpNJ{DQ!`A|s+J8+;>VF(| z*yuf}s=ZHvq_bn+7Ej85)7A>W0V$?d-$D_1>KHSC^n*Vdlf@1>E+K2myqC+vaE`o- z`0WPXXo3?Ps%(i0`x-@^tQDa2fEz^vg%p?57M?~}&Rm>y7SNYVKv(C!N|>e<)}^-7 zw%bTrTDE={{jRgS+qHMQ*Y!8h%NF2@krHaMcBbM-SmzR+DdsIwmk&$%Pqt)gJFzxJ z!7C`k^*9gfu@KOzal*;EN!!VAa{kPon}b(&x%yA(1sPq|I6hkKV(i8R-eya8OtJDV zu`(g$ZY&902-kAg{|>74Uyi+iKj+K#ZBEy}Y+qadruBP%hNH)u-?iUZzp`=Ve*o)Z B{&)ZY diff --git a/src/agent/state/__pycache__/step_helpers.cpython-313.pyc b/src/agent/state/__pycache__/step_helpers.cpython-313.pyc index 07d7d96998e9e36a6955da45fbb7228e2e3ce755..1e22c3fec4d633cf36b3e8b4e63965cc5e481fd7 100644 GIT binary patch delta 865 zcmZ8g&rcIU6yE9Y-R{zsvI171v_)ttqzV`$fJ)kss0ZnWMCm4*TBZ%Zy5w!aXp9H1 zUaWKA)~q=h{Oe*6jI!AG7^Fwog{4yx^xw}TsZfXsEt3n9)vRp zjk%L+I6E&Lt%~caE_+ea2Q_IJXDz4)G+CE5MRQH~w2srlngX$(pfe)w@PTcQ!1~UmC90fvJbL7 zX|yllaKBLMX>Ik`F|>au-6H)_wA}Y)vf1fu)+WnoH}FNar)JhE#Mp}burmt00wD9@ z6d!`@o7_XXSwOkH*e)VhlQ`G`r^GPCsh951THW#?j<*8%2JEnfT`6w^VA8PabPJ|X zzJ!mJWG|JR_&&7oE}MUwU0^?ykF(?XFnN7(Ud?5MgCNPJJqPj`jzVnx2{A2-AmIS;7+p8F5M`I8*$}(3Dckl=H7G9oXdUp@&4pq!s3CsWe2}MJJi1%Fxxex+W3f zSa^=3gzZfNEX3djPM~Snz>mx0D`cv~T6~AZ+I>xl3Z%di?eUyXbvWyt7 zI4LhmpoPvr4#!X#w!`1o*eQo0!>G3D2GwrEYIh7{ya1d0jw2bGNQ&8fl>>U>eRGv; U(vm&J&Np}&$-{@pnTy%}0(;VpMgRZ+ diff --git a/src/agent/state/__pycache__/step_helpers_emulator.cpython-313.pyc b/src/agent/state/__pycache__/step_helpers_emulator.cpython-313.pyc index 14532635640d52fcf0e6cf6321b0aa91027d87aa..4c8c95de19df64f435174e934518ab614e1eeb17 100644 GIT binary patch delta 50 zcmdlcvr>lpGcPX}0}wPV(%s0d%gUHM*^*U5C^gT2zvmk{_Q| Rl$e`Zo?n!`xtMhu2LL)?6md{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W?k;*i~wvX6{G+F diff --git a/src/agent/state/__pycache__/step_notes_emulator.cpython-313.pyc b/src/agent/state/__pycache__/step_notes_emulator.cpython-313.pyc index 510ec60199186751bb076ebea25b1a1563db73f5..1b4dba93f217083443f22673a2228aae66d6d82e 100644 GIT binary patch delta 50 zcmZ1`I#ZPUGcPX}0}wPV(%r~iz`>X}xrReSC^gT2zvmk{_Q| Rl$e`Zo?n!`c^k)LMgT{a6+Hj| diff --git a/src/agent/state/__pycache__/steps.cpython-313.pyc b/src/agent/state/__pycache__/steps.cpython-313.pyc index 435000428e2efea47a3c41d018340191b7460e3b..d4838acd0946c7436017c6942d08c274e1f19ed3 100644 GIT binary patch delta 50 zcmZ1?K3$yqGcPX}0}wPV(%s1YjFT~V@+VFWq2&DBg2dwD_@u<-?EJK}%;eO~mR#A4 E0EjdYSO5S3 delta 63 zcmbO(zC@h+GcPX}0}vQFDsAL`#>tp4`4gvxd{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W*x3gT2zvmk{_Q| Rl$e`Zo?n!`xs@%55dcpa6n+2z diff --git a/src/agent/state/__pycache__/transitions_emulator.cpython-313.pyc b/src/agent/state/__pycache__/transitions_emulator.cpython-313.pyc index 2085c6f4bb595871885c33f5062895013b2e1b22..c9ba59bcc9452f0454ec4e34cd46ea0e5cda1cfc 100644 GIT binary patch delta 50 zcmX>tvQLEjGcPX}0}wPV(%r}%&%&5AIh#d8C^gT2zvmk{_Q| Rl$e`Zo?n!`c`3_GRsd096#)PM diff --git a/src/api/LEGACY_ROUTES_DISABLED.md b/src/api/LEGACY_ROUTES_DISABLED.md index eab1a6c..d729e4b 100644 --- a/src/api/LEGACY_ROUTES_DISABLED.md +++ b/src/api/LEGACY_ROUTES_DISABLED.md @@ -1,5 +1,9 @@ -# Disabled legacy REST/executor layer +# Legacy routers disabled -The original route and executor modules were moved to `legacy_reference_disabled/original_develop/` and are kept only for audit/reference. +The original legacy API router/executor packages are not mounted by the active backend. -Active endpoints are implemented in `app/main.py` as thin adapters that call `BackofficeNativeRuntime.execute_workflow(...)`. +Active endpoints are implemented in `app/main.py` as compatibility REST adapters. They now translate the legacy payload into a `backoffice_rest` channel envelope, normalize it through the framework ChannelGateway path, and dispatch the requested LangGraph workflow through `BackofficeWorkflowDispatcher`. + +The dispatcher is the only layer that calls `BackofficeWorkflowExecutor.execute_workflow(...)`. FastAPI routes no longer call the workflow executor directly. + +This preserves legacy external contracts while keeping execution behind the framework channel/workflow boundary. diff --git a/src/api/__pycache__/__init__.cpython-313.pyc b/src/api/__pycache__/__init__.cpython-313.pyc index ed19873671e21d22e66a27a8a30061f294e0769a..a5ff6be170cda7d67481aa77fb949f7e4791dc43 100644 GIT binary patch delta 46 zcmeyy_>z(PGcPX}0}wPV(w)ei#ppM&OhYI+Ker&UxHvv3F*!RwEiE%Sb>d!208v5@ A!~g&Q delta 59 zcmaFK_>GbKGcPX}0}vQFDoy0hVvL?xrXin{n4F!TmX?{E8lRk>SC(2-l9`eppH`HZ Nn_8Y*8m6o~); diff --git a/src/api/dependencies/__pycache__/__init__.cpython-313.pyc b/src/api/dependencies/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 268b39195859aa714c783de2868f00eaf35d2d9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147 zcmey&%ge<81dmTCW`SuC0RxOs#%C5FV=6;BgC?WjN`@jPAn!9s>XwmyZeEFgN@7W( zep+Tld~!jWesNK4VR%qdAwUv(X@*hJCxdB27zbf^2X^9rXPM+P=xaH@z-qhrXv^7qbyhF6%CH%?k5m>bD%5 zWkoN&WE!tAx5!?vG49UYV77}^nKRcl?RB1wd&f{O8IFB}0oPsAu}j?5!7aJm8>A^{ zEiIX4?`YQ;SC{m4+^*%t8RxVXz0%~xof;UdWNhfR%`7iTHWzd>p~nD?YMcQL`WOY} z4dSfLb;FMU%`sqZ4QwM4JO+sv{-gN6cLlAtg=O&>@f_K)m6L*?2+KmTHSFna5$)ak z1haNzITEhdas6_nDD^D#2QP`LXh*d$DFm%Q^wInjqEQi7-`~cCnZPt7wvG_^D=XYlRvmXkaW|N9Md$8w*XETnt1`RHY-3Z=?Xo}h(&c%DyTJ4cekgI%f!7!) zhHhE@EY~ZHqA-n|a@iqRVk`g*!$X8A^UrhTTmZ^^0K0s`$5x&&l~t-%jr%)wqxyVs z9%apBR+%fbg9#Y(>L&RnD5k5y(W{PSVz}peK|D!U@&HR9)gV<&CW46Cw2;ju7CpgB zR!ocT2A7uk9b_KjCSGO6ud&Ccre>$6Jn_}+!(OTj{qqQZ2TXhfB#PQ<#dKX(zO)H4 zzN#0+d-J4PjfjK#X&?{+;SW;e5TiSoF9V?zh%mgwb1%#-E|r#Exi*J9rMxM!bgr(I@PKy<6 z-qZPt?dFk@_57OoM#-qI^oW;F~ zAo!=)Z3_oSh0%%TL$e>$nrCNs&(3Zyew9kUweshc?JM7A^E*#AN6vgPa^~Zu?W^BO z>01|Wx$kWKZR_nf_eLff(wTiJz4L5C8sC?OcQOr0*_Vd?`Q}ctIehwy;nSa_8`8yn zY3#kR=CR4$W0MW({Qu&qoyVH#Gx*z=kH7n5^F(g`tDpUbbDbA@& zm@wt4W7;myc~PUnfvPZ2!G%%k=$wn$v`TC^i2G?swu1X{;CR`_kx6ts$L6 zaPP~*Zzcbdy!G-sD}P+)PvesNcR@$N?bWo=Jh`6(Ldi}?`9 zii?OQs>0ck*1b@Yx2QFPJeWfs%yDCbRdk-yZ7jQ1DHuW@dU`|Tghh{GXRn#-Eg~Oo zTLao`aW~b4)+PHF?~{7F9<<(uxDyDqKzDRU@S|*DT)tRw$~B8U3m0&Tz|S4*4x*wc zek~0ATR8h);hArQiC-eJ82LrO?gzgc9Ti=%K0bXQkn)+)lJ(_Re)0_mPejEd^~}_P fKyv1VA4&d@Oo*|6sRsgzPcHc4?)1+z@&oz}PKU-O diff --git a/src/api/middleware/__pycache__/__init__.cpython-313.pyc b/src/api/middleware/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 05c5bbea1240a653dfa8669cd0796dcc639a4948..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 388 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 U@rq;9F>2$)<&OAg1PP}5er~m)} diff --git a/src/api/middleware/__pycache__/logging.cpython-313.pyc b/src/api/middleware/__pycache__/logging.cpython-313.pyc deleted file mode 100644 index 309e36105f071a0ca18b92f443f79ab5e77033cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2800 zcmZt|OKcm*b(XtaE>}yDRwS9GWN9R)jcG_^3|okTI?cy&Ye}&ca6{C9)T~zAA-U;t zmziD4mQxf#3lt8}Aojs%JQ(35Xcl|n_)L*FcSO{evM ze7|`!@6CH}-t0jpqaql8|MS$_4`jfciAORb4mN?fjdVnjF6fD6feL`d<;0RmMa*T= zvb2<>$t9V}A)j1MEh$t9X?Z!lq*8ThfDSBaR9ni>3`T1M(`apQPUu;n**uy?da8hQ zWlfnABWbRYD5lLJP*Pv_8V%cR;FfJ!4!LSlg6kf|KQjH`)i)MPs`?XZwtY;@S`$<9 zPKWpbwq0!E^>xQ<7+#xDGq64PF1wU0Rd%neoy@|ae2ZBL@quvn4ZCHuib&LfSjj-`^$@> zAK6~eNy`rWUPAvjov_5moA&?J#rk>)pYJ7zr!x!=WZ!dDa?K8Sjrg4npGVgXVvl?r z)=aN7%y5m1eePaKWvM7)EM0^A7%pU<$&>^g>eizA4kI@J@K^9Z_(KAr69_{TSEE~j z&??A!qawvrA5WvXh>7o!D_%KWiF49dM9$;YtK42Vs$#qfqpDERVtF6C637Spd`wkx zG1bRz5_E_9d`z8;2y+y1D^Jm=49B{CyaH9^$`feyXe{G>XEh&lRjHb+%CKJ{mh^Gu zc%P0b{qb3K>BW?Q7GeJ;WMNadEnZG)$W2uf)8Jnmkwxfr-$rj2) zvu$5jJ3gVaW&>_VQHGNDTF`xfVKTp?&{O0V37Ve8BJ z`ek^TTmQlBfV^LmKGz9>fl;jhqPWd&USq^v^ga*RB zDX&SE@Y+nFQOotY0UQrjF1OsEY?*;suG`m)TDxBMX{`)VEB7C>a@5L7?JcHQwhvLN zHCf^HUW4oR$5K3p!G@oP+-w%IM_^9yl`2CUZ-%z_JWkpLaZ;s^eOx&8dA$PN*AHMtkySv%Ro$TZdsXKf2v$sBb>t^GQd&}J&E&g@1`1$aS zfjudk9)EcB*=}y4TbO)!^mrG3BgeYq&vnP9KY96gFYk_(cE(C~e|~@L++kM95B>uI z*vp}z;lE9ty8FWYsWZD{XKpIp+|V8EmiF79-o3ax^UBW5D-Uw7cF(-Do5MRf{OQC_ z?)mP~$-`r?_AuOlgKx)Crtrba{&Ar9htT-h!)N08zS6(2YQZ!UeX@*n>f5RzZM zmb{P^?kUe-Kg`i;av^gV5vHMV?nj{JmXHWV<4aofe)inzl2L0@R>pRgT2zvmk{_Q| Ql$e`Zo?nzbIhQdA03K!&xBvhE diff --git a/src/api/schemas/__pycache__/abrt_schemas.cpython-313.pyc b/src/api/schemas/__pycache__/abrt_schemas.cpython-313.pyc index 7f49b8c27a483a1b27225a32ba2b58807d524f65..fcf84f23acf7b5fe4aa698337a014c89bbb48234 100644 GIT binary patch delta 50 zcmaFI{g9jcGcPX}0}wPV(%s0N$HW*lxr#|cC^h E0EH?LApigX delta 63 zcmaFJ{f?XaGcPX}0}vQFDsAM>V`5C7T*agzpOl!Kou8JLnVcG*oS#>gT2zvmk{_Q| Rl$e`Zo?n!`c?**+GXP+06y^W` diff --git a/src/api/schemas/__pycache__/anatel_response_emulator_schemas.cpython-313.pyc b/src/api/schemas/__pycache__/anatel_response_emulator_schemas.cpython-313.pyc index a757953932ccc5309238e1b465258ac34bf23dab..f55225bcba070c7f5654f841f4c8e29a4a4afddc 100644 GIT binary patch delta 50 zcmdmFv($$BGcPX}0}wPV(%r~?l$|ke@I#X`+q+5-q70jip&kfN9a2TLPk&u&b;w(~qI z5l)p>DsbaciDRz(E1W=)&@xxlLvBdB+<7y0q(<76_RV+R^LsP%d1EgIgC4=(KfmvO z_pXVfnq2;zPAoDMuSi6IL`GyjH4aQL1EsB})&T_?kQ?M3646^EvST|oAJR4x9PM|| z@5c0@)p=d*_0a3T;q}J7u>Zq@uTHb16nPpn=`o)qO)#n;5XU^=lWCC%oE&}nI1s!M z0WY(<%1g0#p$dnFq>sw!1V{g~q~Tvy886ay$<`X(WN`<@D-shh@Jwc8fEAfQBMa<^ zf-|;5M{YmrmODzuQ8k5>tJ)VHW=dc1NsW8qjoe5|918}#sjEgLzmdbxl^$bdGU1HL z9%GX#n-)s1F?KRdiY~Ij*eHia6nV+ZiZM{7!B_RS8N*V@fF(je{_PZ3!Ut5N7WgOf z!{MY9!z>ZWaFl<~(t0#(ARQ)kKJ2IsFKIDI#;kMh)u*6(s*PH%Swr)Z%r|epcrxF) zH+u$~m*Femy2g>kK8CM?dym94wj=W%MzpfDa?nSWifnLWFS75u7`G!w`&{r5vL|o9 z37IF59v|^$T8JkI_+o(B(#$jIrd26;DWsR>$fZpAq4XwPBnp70684~vPlGxRs61F# z$yOskBIl$mE5)-a5u>z6MU@D+p`M^wo(kAd8H#Ru{A)^WT^d!cc^l1-WbXB6kLQEU z*%$Nmt=Y5ro#4g(PuVYD|NQ(f8nn48Z8f@YFtQ4rjsDo_0J^AJfF3FhF!oW|8mfwF zfZFG3lpgfPe%O;YSD~!&#Qfqqt{`2!p-8ro1A#2`h1FB1(U)7=CsPim(iTn2WD61}Se%BcM`AsQq)xc0|e_x~L1ozuPf*3LQI znXm1h)7^Q0eRj|qf9>Ud%U0zchQ4$e%c>MRNjbifpf0EM>h7}v>eB;y6Z)#_KI)~f zHduNew=d==@BwD1Pebzn&A*mm7=M$GUX$(D2Boyz{nUi`46LpP;!25L1J-nd{Sa^c79q~W^(FgXQlvV E0DfN(5&!@I delta 63 zcmZqUp3KetnU|M~0SJs7l{RvJU}Q|6{D)CPJ}EIdJ3lQgGdVRrIX|x~wWuUBB|ko` RC^0v+JijP=vl&wWGXPzE6xRR% diff --git a/src/api/schemas/__pycache__/portability_schemas.cpython-313.pyc b/src/api/schemas/__pycache__/portability_schemas.cpython-313.pyc index f72ad108f0bbc05ef26378b6165df203d9507b7a..332eb520dcd2b6c1b52bf025fe8d1b9fa3248178 100644 GIT binary patch delta 50 zcmZ20u|R_RGcPX}0}wPV(%s0-%EXvBS&&IXC^mEXbrGpOl!Kou8JLnVcG*oS#>gT2zvmk{_Q| Rl$e`Zo?n!`*_-JqCjccK6ZilC diff --git a/src/api/schemas/__pycache__/request.cpython-313.pyc b/src/api/schemas/__pycache__/request.cpython-313.pyc index 97bb5ea466d0063bb871d95ae272c357524b8df1..b851534ada218ae8aac0774f67fd762198881b98 100644 GIT binary patch delta 50 zcmew&@LYiVGcPX}0}wPV(%s1Yl!Y;L@<$d8q2&DBg2dwD_@u<-?EJK}%;eO~7OXbR E0HUW5tpET3 delta 63 zcmaDZ@I`?8GcPX}0}vQFDsAL`%EFj5`6G*ld{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W^Gm*W&n#26>yBrS&3CcC^gT2zvmk{_Q| Rl$e`Zo?n!`Ifm7o1ppvR6Jh`W diff --git a/src/api/schemas/__pycache__/siebel_schemas.cpython-313.pyc b/src/api/schemas/__pycache__/siebel_schemas.cpython-313.pyc index 759371a4709f7b237cdac27b1145494b154c7e2f..d4d89f0afc72adc575c69405920183de8857b124 100644 GIT binary patch delta 50 zcmdlNxiOOaGcPX}0}wPV(%s1Yn1?ZD@_QZ)q2&DBg2dwD_@u<-?EJK}%;eO~X1pEp E0IWO_Q~&?~ delta 63 zcmdlOxi6CYGcPX}0}vQFDsAL`%)^*D`8|(@d{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W=-A>c>tG+78w8l diff --git a/src/api/schemas/__pycache__/tais_kb_schemas.cpython-313.pyc b/src/api/schemas/__pycache__/tais_kb_schemas.cpython-313.pyc deleted file mode 100644 index ab4dc36c8c144ec2857612be057f564fb5193d52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3848 zcmb_fO>Emn7A7gmk|ittku3iun@OEytst_}O}c1=I#|cfc4f;>Qo4ttDhQe!*=#9N z8IGD**aE&aM_&pkH}B28^{|IM?{QBO3=|a?d)iZOHIl_%_sx)!Y1hsMNCoJT{N6Wj zhHsv}H+q#yB?S2V`yW@n{AUub?4kFG1~;!B!OeGqA`n3l6=_vmk%+VsArZu$BdhXC zlths*DZD2r^0c5tE7AuMe=Hf`=m4Ox5E|Qx=LVZ!CqBV$-LYMaTzwnYG#6DJg6K9z z8;d0ct=i603maP)-PeG#_^33WNNjAIE~+_3!@|hGRnx{UdbDF`HZ^sIW6O`?N4Sq% ztPy=1kzgiwKJk(*Ehl+{Eb1B?;YI&wV#~;ho?JFvs{3pAZ9fTrhv)BviaEII%D``d8{jdH4{|&n!Us8?;CLd0Cpn(v_)rK>aeRp5 z7ee?j$5R|13E`t0zfc*5^^7rGNt2PSOm5uEZfK^vx~cHQzz#GlTB5l261HE^Hbp^5 zD5kx|((CAr8n!7*9*|I#IJIDBdU=HnS)`Phn+=NHVgkX(G}JnA^degB4KFQo2Q{gM zPy0AnU<0txAQ;(N4Rf}EU7eV9YC87mF(DVH>W)oenV}g2gnM1Q#a<%h4G^STn(LZX zQ`gumKDn`}25vVzqOqBO!zcraMzeKXL`#kf6^VKPn!A;M|0c4WrYVYW@-*>zH8P@OCvci-b>*3!g_Ahi>oTD3svVJ)g&&pApf=l?wG0?j;^XihPo!KxV?x=i3dc@wjIhh-39*;^QV}(z|1f+ zBg~9~@uF4B(Wp1Bs<6kPF{;+DcNjYclvnT-ygP-OO$&xbwL;Z=rt0--!6kY@tDA*D z+zJ$acj{MAV7}PR*LO$^hH}H!=Y9+3Tj5AbM&n15LT0L!KFD{{AMSqqTsf3K>}F?L zOYMBQlU>_g*^3;?Yu$@i_GjC-OPz}=Z8@{2AIdA;^kggDzVT5fz2Fa92$0oIy6hw6 z?&PJG-Y#r(CO_RR@68^{p9Y~n?_?{xe|nC8lq=+7Z)Inz;dRi7w^KtVpq0ThG%-<0 z0{%-)9IB)MKi0&gG8AZ8N=fD+W8h6OMdJ#aR4#DuaOK!L9P*BE??`2|l42|AM;Hxp z#yDrJl7^X6ccc@%bcmPXyi91O@xC{rWVv^ouYQ8z$|T8dC390==9J>{p7-(!P_(~F zptt=t$otn@>Z~uypi-=5A*UMZbRgC)moo}wZmE6ddZV@pLIm6Zf-7wh8ylScq=Cs! z5j`a4mT7Ai;?IcUXOz1MhVEQzSQ^C!{PH;WF}onG3aW=XwIyL2n&=naE?ceO`SPvbtZib#1}?$yAyM$uC^pW$a% zhgNSu2P^sqh<+)#4gm+++yTVGU$cIQ=2+*0>g>rmEDt0)M+Twvy;$(J&FS;&(o3Bv z;b!`b;`E}t7}uK%?^KQ6*e?sb`Goucx4|Ulj7c`zfCMDf8$k8p#hpOWtUY&2>__S3)E@a10BfU+N4m?=C%0|0pl}Ib!Kq&&Bz+c=3Ah_l>YWjeM890lLG) zGqh1WqbIZM#Xs^7gZD@QMnaMWcOJ~o5m6M6Bw3XIJ0ytL|0PVk9!QH{h^^0F3+(#( R=Ct@gY~B5jz^;5n{{tGOo7?~Z diff --git a/src/api/utils/__pycache__/agent_helpers.cpython-313.pyc b/src/api/utils/__pycache__/agent_helpers.cpython-313.pyc index 5e1051e29b8e916bc3eab9937777d760c50b6e1f..5cf30eb5d212d4a3d599805680442f3681ac13bb 100644 GIT binary patch delta 66 zcmbR4)9S2BnH$D$FbpPN^rpQ7&@?5Pk?l%JKFTvDu`n4X$f5}#I- Un44OjUz8o6pPaebnDvPQ0KL;(P%VIBtn diff --git a/src/api/utils/__pycache__/emulator_response_builder.cpython-313.pyc b/src/api/utils/__pycache__/emulator_response_builder.cpython-313.pyc deleted file mode 100644 index 75034e6eb4094fca1df6e8c43aa3f7887ad12dbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9346 zcmb_iTWlLwdLCXyk&<}P#ggUASiXrdN%?+D>|MuJY)h8pYQ%L?2_Q%0NMcORuxEx= zlub}Q74TE6MFVSr0(D;&3Q(Z#q7Qk@W7{XP3_xPw28(U_ke5QK-QCxI{}~QRX(e}2 z?7*5ibLO1?oc}-n|NR&Gb$7R4!1W*hdhFvLj^Rl!_SMs9y#BRA5WW;n3X;GC$ssu> z9TN`bm~b+uNbjym*Myt7dD}hdneZ|%Z+j*?CVb2{(aAa|{LDWQU;$BB@Xrp~3$&gK zowEm9Z+7dV6Qd8=Z>{HBMjvU7vRfD}+U?f!qEqrFTr9j0S?FEpTktP*UUYi!*}5Ld}+c$9g^~ z%x4Wsk%b|t7c*NU`=QZAp>MPo$~({s7ZW5t+N^rEKf%J>sSHPYge#`sseTO2Qx^0I;6rM$M9@cSo~ zq9N)^QD(BCh)YZ>h-rBlb5koyzNj!gu}EvAG6g-w8njc2MSL`~qGTTDbGmU__w!*2 zi;9LO%1^XhR?KLnVm_xX^9>lQnwZrJa!%C~qGZTMNf!%pu}I%Xb^accGe%BRqu2c+ zE`>4dQZ__cT@!UfDN^S?*Khyo7vhqf%PZNK$P|OEaSFs?s-R_+8zW#yAqGeGAs`Y3 zc~#CC*bn%8l2cY=R!5WT-88Xzrajr8q(##jgne=9`x49KHT^B5L{2QLsR}V@ov`0O zhhyhQA?6@VMOFlFzs}sgFWNfcmkg%J1+FWy zxSYe`iWynQQo6tD?oD_Y4AnVi7@ zd6`bz5EYr_a|#n5GHn^Nb*`E^bnp0a@zILHz=WJx5tnjGJ}c(2ybg_k<{0AQ8s3)_ zBUezOet%p{L*k&Us#gMbIA*aPrsA-&)R8i01j58~-1`$oouZcN}U+BD|8#ux? z5@}H{EoQY$^t$+Q3HwZQl}n4OD-Zyg)H0Kc*cVr|uMXq9vb)RH)7 z!_c7mYF1p8buml2pOHzQI4u%r9E*wR*2WhVXsGzx^}hx!TJP@ooT#YTqL#x+%6S}0 zb`A2DVc}2Yd=A{gJjQe-uVf4*o3hMBw~Q9^L4~i9hfd_%*5T*)SW&pG$s(D0K93O@ zt+*zZ)GUr>hg7hAkSdmNFj*`vt}40Z6{ywHx)Ot4srAK%uZ6!$wPLg3hSL z->9J#LErMQxM|um}V11VqQ33`=-KHOA)UW|F)N0@2*xBA=fvnlPhhK=g zOrH&jW=8|aOb-Vkvp4m@gPBLEshK0L?J*}z zdrLa^9PhTrpAe#+(lxgr%yPyp=xgb*lv7~IqBJW4o(wIcCM(8<8YBxPIC#IXCPh?mDC(f5h`y1BCG|iyp z(oFe_5~!sznrbMY7&`_7;z;{xY{MWewAEBU@3*G5oXHN&)^iPm8Y9csp`e7SfGzGZ zuw9X3Yf)ayYlKxfgacxFhwywWaLaWp-0{_Oe7XA_CUNE)FAK~h8fmQw0m;+!dRY6igzQP7GC z1s)#&Y6y|JCxgJ@V^*~i+zw8z2!91U<1`nw<&y3P=#~`lN+yf}w&!U-g(k3Y+Yuk$ zn!A0kL6Z0Iod5{1rZkJQpJVVes~R()1C5i8ku)_1DNx{ZF0ubwB=S|3GYt4AxJEj; zCh9=shQbQuk3j_&fC;Qy0iDh@G^I0c!3l7LXov$wQ=JmxZCTY+xU75v1kPg{f5a@V z1vxcdPzoAc0D0VZq0_*81S8fyn%=azRq;#{q6uJ$ePTtI3kXy!F^i+5QhJmmhEF!4 zi&IGiHA-fM;u2U7KgOm5viWbYzNlnmcxa;S-x0xBzAJ|n__}RJYexj{idq3;wtY9Z z75}FS(=a7x#Gqq21T5G9?R&9A9v+Ig$h61sF#Oz8WVC6-VhF&Mgx~bH^vCSkDOfYm zrch?@9*6Ul!*nexM%2ZEz)Tjw&Fp9#rcS7f<2K(LE2zd8A@tZ%?vqrexHP7-%$Quv zjlm1%^)XwB%@{P*2-y?GHM5_3DXvRlGbwDAgAAj*?JWNES=`oz?U)cg_&m5dyMDip z#^H^_o1ay~v0C{2OXvDTz30Feg{Ot`p;)yiUhBE=GO~WR9_at#=F^*-@oHeS7MR|; z`wx>}O_r}tRb$g-_w;K}6-*D8Z-yALFKW}@>(6k5J83!-8O|i>I00Akht6V85PzF< zaV1@Q%}F+$3xMBQdV(cw;7_Z{YKp^x9VW68Oc^l;B0{bWEw^B!M>~MGv>@?w&h_VM z%OPC1JO#pU9&?geP}~VOpd^-Iiwz&0$})Kg5fYD7q5lmP*Oo-tZ!lSfW)V8;dP#}K z_HpMD9qb>VlS;0xD-gJs`fJu>`!Y?IZ(rz+u7FJRIaYvJo( zlSwzs_hdC7mfa#7rWO2L`%*b|Ni(~7aAJ$t>}=-TJItACFWj8#i1a8rv|~g06wKKv zIj(;w2(l;$^B8Ddv#`3|*F15`uUW6%YCSJH2^N}^#U0dqt#NkikDzAn4Ar6*1ZDp; zl%1UCKRM-jUh*RzXS;1qThF9(H*89-HktoFq;#oqPJl}HG@~V105?;JcCb!r^h@{0 z-yeUFy8U2Ax<7q4^}((C5615>TFUgyj?c}0WO^HYRFh-}aD%54seO!YBe>aK&QkGE zQ^k?sWi;ewbn1&V?w@djYWoFW#m z?>fT#)2T}E)VHHoYoj+Sqc_XJn`Ph4dPnHl-D=11ucqEMVxrn{FaT$5tZM&fUF zH1b)qrH9vWd^zP$K^F*z6q)1`1h$+?62p-83 zp+>kSK33L{#aLm!A7Q?X0!yQUM(c53*~lKr!?smX5Qd{lfx3cEH1z8=kESgL; zFz)%V2N@}^*|T#=6F%OqKSVvIyP?HYVQzFom$~7yICQ{t$_9&~!QP=80fHH7g|k+b zC+cCO=B7*4Rv9@8(*J&aw$uoC`s9XEu?BSPm;y>Fy`H2(5X<>-z25Socsk%P};zli=75hq#vw{uj zyIloJIL>`aCC!L=k2$V==D2L|Xq#h|WA=>7rRI3mJx_e_YacF}rJFX|kcB8n9(z^Q zv(H>_bA)%Fop;zHc2kFhI`*04+hfk#xNVMCefv=Cv?;2c`;740BX;j|Oi=y%%n8_Y z)WF`^k<`^3(Y22RyQLmmht%$U)(P5FcJB=`?3t&4(K_EAdz>1aCyV6Qhu=dR8ae=N zX!ZXfbvFAu=bKLH!)(%L_m`jtYDf)Zok-H#bSPLc=}kr~M>9_$48M~8WJl7M3?#df z-BRe9SM8l|hE++&JmuroxKPs5#t9;EQD|xDe8?U*OUe7L%jPf{-bbEcdqmp`mNpB? zAl!LpGV+ICq{ua2vRCT8=7M|dn>KwmVwu5Rl|mk7nO&I@V*vCN{no}#V2`GU2l{QG z8)!?QEHJ%@aqJx32tpa*4bN1f-v0w^L#I z)bTsfK6afxyh}GC#%|J$uT2}XBGaZLVthZ`vFvmwR>IcRUQRLn^ebwE$vdEBhV9I$ z$2aY_?Z{*9zFIERG)dt@EIqGT!N!9ZN2`73YJDHQOw}&kt6aMG&qu45 zK3bo8)jRO4^n7h&?ZuJmfwQ#(mtVeL?Y*-8pdKE0KD05kd8HaYj)XBh^!(7qq0M|X ze5MvYx5dyE8hqZh(X}~W4Ml6AsjXBk{?khQr{4@$<5Q?3k!Re9ZGK*j#MdY52aZ1f zY~!=?iObakS84}te0{#`?yL6Q(RP)=;(g!uo?ZUZFp}_0czfS?zlSrXufbUHj%nHS%Zc zliv?Tx8C{Yqw3I1#XYb-@yxsJ6^N(!-f)Y25VPdiZd5=4az~O!u9cX}sHC z7{w!|JBuGb*j;LR4E$t@WG0o8RXZHl!6(%qTlQHiy;E);|;QzmWyO5jnDWgWiv z@SA@ruiRt{_yiLWbPe}ym&4)sZ|9K1{rk&;WAs0T^Zzcq_j{+u;e0LNM$#UE##X}T z$`@|eF3eUg%$7q^JtWpb(Ml*SQIIbP{GUOsuLcJgNBr@Lr|={%gUFWqO7jGmaN?TX+6$ep{gS zOX=&2|M=%`czgS5uj5!f*!wK|^yk|yw4s7s!8aY$iiI5BdZ_Q2u@TsIq5YfQfz7^+ z>)Rf*F)W02pMJXCL2o|68z={c%ZKCTK)m8fyy>LgQ^y=b^?`%iEf83<**1~h zd_qs;*`25J+nx007y1V`Pi#zV2k5O!7#P~_rdE&O^}h*H>z?DB!@G5GTfpNRi9gCy L>Hncuejxt~JS~jt diff --git a/src/compat/__pycache__/__init__.cpython-313.pyc b/src/compat/__pycache__/__init__.cpython-313.pyc index 57ae5303f5b00cd80c0246f0c71edeb5fa989f6e..f10ed64f35330d3bb4e1b04c942ef079619b0f1e 100644 GIT binary patch delta 46 zcmdnbxQUVbGcPX}0}wPX(w)d{%osS)UPCB3Ker&UxHvv3F*!RwEiE%Sbz++(05ZW2 AwEzGB delta 59 zcmdnQxSx^xGcPX}0}vQFDox}zW{jI?uOXk5n4F!TmX?{E8lRk>SC(2-l9`eppH`HZ Nn_8YPx# delta 63 zcmeyQ`(Ky)GcPX}0}vQHDsANEVP?#jEWxZHpOl!Kou8JLnVcG*oS#>gT2zvmk{_Q| Rl$e`Zo?n!`If!|IFaTI`6s`aO diff --git a/src/compat/__pycache__/framework_services.cpython-313.pyc b/src/compat/__pycache__/framework_services.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..12891271a6953ad489efc213655891b4dd564218 GIT binary patch literal 2979 zcmb7G&2JmW6`$qq^7})ktPd-tJQXQdOeNAu;I*t<*!=^@8ik0h4+e@Jf?k+PMT)eCzBemMvYksu z;>>$*-n{o_=FRWzP9hN{(BA)KVfD9RLjH!#ut`24?EC?U+hmp~gb_th0vClh11vz1 z7B7l#N=)LkbWvvV6?r8-G;lD^kSn26g3q(CB3+9p@|CC({1%9Si*YXGbBd&d3jrmm zM5f59v>IS>C8b1>W(lBToJvj;Wdt-OC0+jtgajJC`=(_EuUE1JG$*J?OjwOg8LQOm9xP9Yk7yJ0%CWmh{* zg92q*u3@>RZE4Ns26atqgKAclR*kk{RSiquSZJE{hFhQ)T-r2ThuTe;J!CSf!%A8k zMzvtCTi|~$Hiyn#TDnY`-Ej@Z4Y!$HXNKcYAgUeRV0pT3x(!gEj%zd1sz)u`T7dPY z)-*S@3WRA_Rt+6oo0el%4f>X5)!$%Ry8$a;vqimO=xc2ob^`nR94{y@crnegY?y|f zIlzjqTN}#^v%!n2u5C9}KPE4&4kJQ>M|3aX#SW_+c}_z|C)fh;!;}zV*qH+2HYt$` zNK51zDG3#jmxOCVoz%%aVL2aQGU%`%b|L5-Tu-T2F19SUSS?;sF3`)&=DRIwb+{OH z|6o;HH;cO6YHN<89$atHVY)ANiwC;H<1e%~yohdFHM8Df21|guH2R%}?k0H>O7}w3 z{fU{act14R3+4KmLN7cu5J`A;2QM7&a)iZz$P0XT_XtA;hA+rV z)eZOXakC>J#dC7tp+W?YV-sCzf-m@geepva0V{{xjiI~eZi|hA7Vdc8X{IY>_%gWa zkxIugEyzd}&dD{dyWR+-VcmoWF_h?dP1tb6z~9H~{u3NXmQXwjJR06k?TwaHk}7c0 zWk>+Ol_Vvgh^O}WxjktWcAaf z8C(nf+LcQ1v~&TmuL1GAC)^g7^?m3-R)uW(=p^lFJP~EGLPJoFcfwa4%Ul8 z#W0#`wbN>Q(yC)yfTaHge$#JLvxU2-{7H`@LmD=E#2@WyZ|rq{p-5XMyU6KO}kz< zm={{tm<7ee6CIc3LtX^ksuq+^FQTz}rv=#RFw7Y??nlpWg&jvmgm@f$3)F8umL)J2 zwWYT?pfSi$G6O&7AJBacShhP!l9@+|>6_>Kp~NqK{?U&={?Xlc@5|env%SpO{`d>s z6BoOstG$%k4XcAdQeG1J6PaJ%`0z$QJ_i3E{NPTypIO+>yz;3(E`EA!JF|GdGKi4L z?10FV(JzUdj&22a<0L+M>pOQ|+m6lkVsrh`W80&--e~UbiSB5wJNi;L{?g;v*sa<} z)$Lfe7t4ae)}{XV)W@}6YOxz${9+8u{Cjtt#K(3>0OEKYPJWR5RkAy=^v8F*S1Vh| zURZ~Kf3M%o{;qL9(o3EDOZeP>1~TgY*SQM&{pE=zD%?ALZkBvDBb>`hpJlT^KL`pS zeh?Z*I>YH{3F#S5X9c8Zqe~g_K{2~DDLzaKKtCLnVb#M)8R?7&bUw%sWxt9-(WXD8 z%eG}OgdJ9d4igPun_rshvHLc3UyWgolpzh~DcJkT&>+A2mr)B7 zfN=^BXKYZ{gSc@3yn-RZzyFvw0F2M7WcwB>3o>6^UMpZm}ad|VNvF9(WQXH+Og5C zneSKZQdpaW<)TQ338l5+lnz_Y@^YzL^1p_qiro5yx?gf+vaX}_0gTaM*d|JQQZvs; zBd;j$8xkbRQj+|WB$P@mJ*8!TJ!HGe)EAxDv+-Lnq+1W=J%JE@AOzFT48S>jS>1Tf KXSWlZh2s}ECuWHN diff --git a/src/components/checkpointing/__pycache__/mongodb_saver.cpython-313.pyc b/src/components/checkpointing/__pycache__/mongodb_saver.cpython-313.pyc deleted file mode 100644 index f3167f7f011dd063b46300ca817b8fd5db732dbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10431 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

d;3;rPEq`ftB2BoiV`EI1Jc~_3C^gT2zvmk{_Q| Rl$e`Zo?n!``3l<(WdLa|73}~3 diff --git a/src/components/clients/__pycache__/emulator_rag_client.cpython-313.pyc b/src/components/clients/__pycache__/emulator_rag_client.cpython-313.pyc index 1bcd4ebef0796df9d7166e518f1932e274aec88b..932f6a85616a88ff3395d78c5b49ad64aa0a0f2a 100644 GIT binary patch delta 50 zcmeCq|Ch)8nU|M~0SKBG>2Boy%fgs3nUhsRC^gT2zvmk{_Q| Rl$e`Zo?n!`*_qYa2mpwN6=whd diff --git a/src/components/clients/__pycache__/imdb_client.cpython-313.pyc b/src/components/clients/__pycache__/imdb_client.cpython-313.pyc index 3b693bcd4891e429ab70a12a7e3943757ae112b8..6bac22b0b846fe6a95a37ba9bcb46cbd9eda403d 100644 GIT binary patch delta 50 zcmeAVX$s-~%*)Hg00hm8bT@KWvoa=3ZfDgHO3u$MNGvXnPfASA&QD9rOitZ=j@3~G E0D&(MVE_OC delta 63 zcmZn)=?~%l%*)Hg00c&kN*lSWSs8ODx3g- diff --git a/src/components/clients/__pycache__/siebel_client.cpython-313.pyc b/src/components/clients/__pycache__/siebel_client.cpython-313.pyc index 57c0288954eb222498d64e724a03d81c835821f5..41c8b814850969af11c973493923307f4a2fc140 100644 GIT binary patch delta 52 zcmbO_m$73mBll-sUM>b8XkMhdk-MLhF=_H_P7R^t{M>@X;^O$E#N_P!w6x6R)Xk4L HH@g4;so@db delta 65 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 diff --git a/src/components/clients/__pycache__/tais_kb_client.cpython-313.pyc b/src/components/clients/__pycache__/tais_kb_client.cpython-313.pyc index f7481e57533df847d78c5179d1af29c6bce5da8c..0e32fa5f67ea42887ebdfe9855cd1da5310fa9f6 100644 GIT binary patch delta 52 zcmZ2Ag=y{-ChpI?yj%=G(7Z@@BX=@X;^O$E#N_P!w6x6R)Xm3O GQd$9~z!8T4 delta 65 zcmbO`g=y6kChpI?yj%=GVC1N@k-M0Mv0!pNi-vqsVsdtVT3TjuYJ75jURi2UNoGoZ Td|FXrZfbdcQTFDYEGex3iZK>T diff --git a/src/components/clients/exceptions/__pycache__/abrt_exceptions.cpython-313.pyc b/src/components/clients/exceptions/__pycache__/abrt_exceptions.cpython-313.pyc index 196b9b71c37523250c5c035333471b96d1685df4..f74e66b483dce86d2caac675fb95541f34b360fe 100644 GIT binary patch delta 50 zcmcbpazusuGcPX}0}wPX(%s1I#>|*MIfz+9C^gT2zvmk{_Q| Rl$e`Zo?n!`xrccN9{^QL6%+sf diff --git a/src/components/clients/exceptions/__pycache__/emulator_rag_exceptions.cpython-313.pyc b/src/components/clients/exceptions/__pycache__/emulator_rag_exceptions.cpython-313.pyc index c2b8c539835f088a905d59f7a75e99aa10fbca2e..29c4d9a6fd2221a9d48de3a3e05ecc084560fa18 100644 GIT binary patch delta 50 zcmbQt*T%>FnU|M~0SKBG>2BmsW@ap(oX@Nwl$@VikXT$CpOl!Kou8JLnVh2BoaXJX8sEX|}Ll$@VikXT$CpOl!Kou8JLnVh;giOGT& E09VHjuK)l5 delta 63 zcmeB`pC!-znU|M~0SJs7l{RwoGcndomS)nBPfASA&QD9rOiqnY&d)1LEh@=O$&XJf RO3Y0y&o9c}9Li+D3jia}6LSCn diff --git a/src/components/clients/exceptions/__pycache__/portability_exceptions.cpython-313.pyc b/src/components/clients/exceptions/__pycache__/portability_exceptions.cpython-313.pyc index c8feb2563fe57809df0d14e9e896c29cce40bd36..2f7ea0fd474ecc7ab9e07460677dbfb479df6532 100644 GIT binary patch delta 50 zcmX@FdPtS~GcPX}0}wPX(%r}%&CFOfIh|QUC^gT2zvmk{_Q| Rl$e`Zo?n!`c_FhRKLA`46v6-i diff --git a/src/components/clients/exceptions/__pycache__/siebel_exceptions.cpython-313.pyc b/src/components/clients/exceptions/__pycache__/siebel_exceptions.cpython-313.pyc index cf162c1fd3d2f485c3d731f24a978b9be4211ae4..f11cdb33db51797c80eabcc19c0fff88234d97e3 100644 GIT binary patch delta 50 zcmbQO(x<}xnU|M~0SKBG>2BoCVrDFyT*j;+l$@VikXT$CpOl!Kou8JLnVh-)|H}9H0GhciU~RC$>dwfsBBJBjwI0pdm_VkVF!NrrV1J3hQ)tuD8eB?lCh< zITDozV<74yNncESgg1EePtdm`l5pAh=96!&mB5qnJG*ynMReMm`Of#(e!rjZcfK3N zqK#m^J+rU*y@}9o>M~flKC!VEh`Y!^9PL8;kfTi^M_<&A8JV2x%SPF}`JR0`7BXsK zdc&h_8APGL^@wBHpx9|s>NW68NLWV(p1?D+XR*fu8p?|84Zf$&(f(!QD5Mu?`e#-QC%2e$@{4)LI8s2!DZnkGtW9cYQ))ZL(UBTDsyV}xsA)CL zrry+e!Lb)}NA;9HlJU9a6!}mMeV}ps04kS~9a;FN(|FHt9`WDv5FPnTL&%;ZfuKHK zY0&V0QYDPxItf??2?;xxQzD|!K15;wCMT)LVLmqgI7C3Xm$fp=QdJQTdsz7WN1o!Z>T;Fw4VQ$W^?Q9o1TRJ5TDsVnIXxy@j}$4iml$y6DUH1s-dOZ-FcT16U%jjFp#dxhd}p*_{xRE6qMDurDQKrNQPY3V?+qo6)GWB zP>gRSUsPM6toqeYoU?eAM@{HtQ3WudN9&xl=t{(|x{()Dmxy;Ys@DULLI;G`DYT0p zZRu16_o`mhf^vebsAjW6RJUeLb?^!{r%$Eb;cA>DlmB|Zl|iyQK`su$_WTz5)hga8 zJhFDJzV_I9qc?T%v9+r=w)0!7x99Ll2>7d{fEvdOx&6_irz5~K+$0;8Ru^1FQpUVrhXZh4PFE< zNde%OykA3LmK4)mB7*W)fD|fHC=1^KC!bKl*I$NB>SK>Gco#MWO=d3vh2j;!&-Ld1{k>kD6*zI9H2DW80?eDD9xB6y8 ziH23rh0p}9o7k?~iu{-?h{xw?Hi#cm;Z!Y&{_u`c` zgg)11bT}6E&-6bKaDOn?)bU{dkLJU}DfyGrbw2(1VoG---i-GOy_u z^mTQ+05>oP7S#j&nWEQI#;BPaUmbgf;CQOG6v;F?m^XYk1eXk*8MJxIzmGBOuMRy$aHMvB1I-B|cmMzZ diff --git a/src/components/clients/exceptions/__pycache__/tais_kb_exceptions.cpython-313.pyc b/src/components/clients/exceptions/__pycache__/tais_kb_exceptions.cpython-313.pyc index c8520f3cea5609d4cef0d9a0f19d82ca4a43a73e..ef876d01474f9b03cebabf1a1c9a96a76a42c418 100644 GIT binary patch delta 50 zcmZqU`^n4wnU|M~0SKBG>2BmsWo9gzT*#~;l$@VikXT$CpOl!Kou8JLnVh_y7O^ delta 63 zcmey#+s4QJnU|M~0SJs7l{RvxGBegsE@ak_PfASA&QD9rOiqnY&d)1LEh@=O$&XJf RO3Y0y&o9c}yqejM830ft6ubZc diff --git a/src/components/clients/rag/__pycache__/__init__.cpython-313.pyc b/src/components/clients/rag/__pycache__/__init__.cpython-313.pyc index c08dd8bad04e7ce73a21d9ebccc685d3c1cc79c9..1502177bbf1ee739648a87c3d48f8e369045b99b 100644 GIT binary patch delta 49 zcmcb`c9xC%GcPX}0}wPX(%s0tkclyI@>(Vhq2&DBg2dwD_@u<-?EJK}%;eO`UzpMW Dct{YY delta 62 zcmX@hc8iVsGcPX}0}vQFDsALm$i$d8c`cKMd{Sa^c79q~W^!tLa(-S}YEemMN`8D= QQDSatd45s$2BmUXJ^cw?98qql$@VikXT$CpOl!Kou8JLnVh=0i(OCx E0B&{gT2zvmk{_Q| Rl$e`Zo?n!`xsml0F923c6&e5l diff --git a/src/components/tools/__pycache__/__init__.cpython-313.pyc b/src/components/tools/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 05cfa1c2b19b5df9335888ef9531155c99ea67b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 404 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 delta 4512 zcmaKu3sh9c9me-AySySQA`)0Z1Pu^T0YO<6L{NNzJpLLLSKgoqvU)-Ag{z5)M2#A+ z@sXElo0zug1G`CV+9om9q_t^NOlqSfP1D*YO{-C(#-wSR&i~`?Fndl~3sqs%xmKbGLRh z=b)(Yt(s>drBSfcs>itOu24!(68*V?6D*WSBPfb8 zDB5Y$9jGKt8{P4f8ecOK0L z7z40C28yT{{#f`6rC&m&@b7|OCVdB$!%tGCOp-35#h}SZ-IHVy<72s(&{BXDfMqh^ zpbGeRE8Q(usLM4@Y}N{@%(99*5r0%Awk1`mUZGT1qq>G_sV*x3<(~e)cqLGy1o~$? zL80{uZNStfDzs73m9z>p4L8&z{SsOYKOKIvM*OJgJxlv_0o4x2mHxq%EJe)Q^6a6rzo9nlynnq2F*sNTcqD54%}A!KR9vR z25xE_ZAW4%68Fl4gYJVr&7%yoL*n~IhYz5`>F98$B;A5M2$BP`%a7~^$pzWtM;-#1 z0kT&T2YL2k9(l?%_AB^d(3uK7pil!eU!eyjj0smd;AEOKKE0tj`O4>_(pjAk{C;e7>AAU7{ zzW$*2AF%JyYXJVJfDaL|m(JkO6-1X;5>^A(>O6&`TehJ#F(0?lQE6^5&{!5|%7F6v28U_DH!CxcX zIzZ=WWEtS%N<)R)ufi%Tj){r@RIKH<9&u&!G10cuNTGoqAwhV_TF3h;u7Z6<}wPr><|9O}&%(H!qfIXEKVF0r5Z+>j6MfY*y-tE+MkC`3kW0cxYjDn~Lk4?14V+Py#_=~FvvX0qAuzO9GCRwXs>0tMn zEJHHh)k$DG{MJ0vuOf>pJo^29C6j$6q6^-YDd^?_b8)g2>J)S;=uVSPQ|NR-b3nUI zn(Lz^-eUxvfraxtXs(=mg%^ll;=9FnKK?m&nH2@T4g{HHR?J4lZnL7$S3$gT{V)4_ z%+;C8jI3m%0Kw)>2+)IE4<%SU6rQE^|FF6C3LqZ+LKnE~ncPKDjAgYgs~=l@-}*id z(%k=(EB>Fk{m3ow%LSPO8q=cVU1G$N{_)9z@k`Zy^aGfgk!cm*WlZ#ga3Wlf@EZ{P za`=aYPcat#u=rl2A6e;0UhKUZy+Iq+H?-DWwQ_B{yR9uFt+uMZp~KthSfoYtg-bu( z2i_dn9O->IBRz0%sp!4fUEk2+jxQ=IHUgb-$??fDVAjXG*T+lG*GYo<(j;<0Ir`mFA@zMzKI zjwapRs-I%W6@8&??KOIPTW3@ID*dc5QmlHU@l0`!w$!*(d{R4VxI-e1o`p@3%Q@m= zS;11tQf*|HBowXUW)n*@%NiCp%Q}`emUfm7mJKW$SwdJgv2?L)W7%#TFG-Eu&CNY5 zds+6eJZyYi5*vdBz`Z}l=Ho0+usmtRl_mrp=jO9UVQErK4>wP+cv+rjd6DI$v9mN` z=&Rg3#e#J^W4u(FKIv_~KF_k5Wh=`CmWwQXEbp&JxU$!}0}-g?A{3B^<)u2yW$ZD~4N%n(<0V)Q}=JSklC&?RBHK?1dq-ddoY` zjp^*QjXYBKj;+%;SYCJMf@>B_g|^TtW-zYA+G|UAs^EsjVlVLyp|e58?TT*gns?js z16p*Bs3_7ZxiGFu6h`iE6LYm!S-qoId}$2~@zvwCvBtvcSS`_L5t?r7s@{;& pWz$Nu?kzVhXk5<^wG0}*d+N5}3zpz_Em7wzQRgkudWM+je*s21&X52A diff --git a/src/core/__pycache__/exceptions.cpython-313.pyc b/src/core/__pycache__/exceptions.cpython-313.pyc index 9e05f811ec5de3abc60ec78e492d565bf0f85a33..c725b694c2d6f0777f5ceee5f4323b974b6d900b 100644 GIT binary patch delta 50 zcmX>qv_pvdGcPX}0}wPX(%r}%!OR#qIfYq6C^gT2zvmk{_Q| Rl$e`Zo?n!`c^>mDRscu%6v+Sp diff --git a/src/core/__pycache__/logging.cpython-313.pyc b/src/core/__pycache__/logging.cpython-313.pyc index e94d3de59b2943b90a5e14c889ef6a04fa1f583e..279f4588ac025b3ee20c4c17554eb5a23fb86f1d 100644 GIT binary patch delta 52 zcmaEMit*+tM()qNyj%=G(7Z@@BeyCCqu*ph4h^B?{M>@X;^O$E#N_P!w6x6R)Xfzf G?_vPIH4)bU delta 65 zcmcb4it*VgM()qNyj%=GVC1N@kz196F?zBghlYGoVsdtVT3TjuYJ75jURi2UNoGoZ Td|FXrZfbdcQTFC+j(0HtrHdAu diff --git a/src/core/__pycache__/prompt_manager.cpython-313.pyc b/src/core/__pycache__/prompt_manager.cpython-313.pyc index 97f973fa3b4296e1f94815b72cc41ecca4785bdc..1aff66ead6c97bc8c9706a8038f3c7462c0ab4e7 100644 GIT binary patch delta 50 zcmX>sy-k|?GcPX}0}wPX(%r}%#=#gmIf+9 delta 63 zcmdlceOQ|NGcPX}0}vQFDsAKr<6umhoW!9apOl!Kou8JLnVcG*oS#>gT2zvmk{_Q| Rl$e`Zo?n!`c@BpZD*#LG6l4GZ diff --git a/src/core/__pycache__/state_logger.cpython-313.pyc b/src/core/__pycache__/state_logger.cpython-313.pyc deleted file mode 100644 index ea466e707ba758f1eae9b89bdb8c43a485b9135e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 569 zcmYjOJ!>055S_j66X+x0A_$yZf(W@3x-JXDT z_~4TcFc?5j*|hwRZ(*QF25C(7RbOesIbm8%T3LN+dzS72B2Z{qRxLQ{ifp zEZ!)Y1<_>W#~&I_Ql@Fm+>vz2K6rs|!;uNYYr?G3B2N^;Qt1;g|*iv$1cz;ybXq z%&X{x^=X_9rx)~??I4t&m%m20R0$yuP+J;MdGXV3-rLPD`#UiuPLRB;%eGn4?$)=9(VHjZ zK@S`Ve}n&uw?>niXFYl1hN(u6&fD$MDo(O9^XB`_?`>~%R0X7OALfoe2`Kp?Cb_Tl z?x1oC1{lINP%g!7;gLwiS(t)(Fr)$)@~Rj`Q|UmOht+;6mFt40obyvz6Ijx>gTQg? zzSZ}K0{e#4E1)=q1E7KdR5S!C8DasbY)Dk8%bLQjS1iW}sBJc}$VS7l-QZloBr7h# z>u`gFU+*`vQ`koyQMEr}eCD#sqyM4(L~N)gV{IUZyy5Bw9KZCV7@a`2|_3M!hECd6ch}WhxsbvQa5-l^&9<(&J4;WnkE; zRzh3Kk6~iz2(bt*HqL{M-RkE3CuFnyV5d?l@8TdKmiR(s-)_`=zP?#j)SGUgADV%w z*PIu`YSna~TDs*?TfZ!?N2$fuOO_^2M=1H@YU212SK9A?l)=$>E z)3-X)YwhVZ9(=nW{BER&^+6NqIErwKWi7$y@eg4QbJ+xRaEXE1BfiY4zx!{4KG=-^oSv&b$aK@h%x a`W0^eN{k5Vci?OWrWQWt7TYipR`>$}KKpP0 diff --git a/src/infrastructure/oci/autonomous/__pycache__/__init__.cpython-313.pyc b/src/infrastructure/oci/autonomous/__pycache__/__init__.cpython-313.pyc index f6c7985fd45077ae06d1eac7b7db827bd60b265a..aae3160a882dde5c01960fe8f2a93b27233fcf67 100644 GIT binary patch delta 46 zcmX@Xw3~_hGcPX}0}wPX(w)dXoiStLVhy3>{M>@X;^O$E#N_P!w6x6R)QPX+08Q2q AF#rGn delta 59 zcmdnZbb^WdGcPX}0}vQFDox~`&R9Bev4(t7VsdtVT3TjuYJ75jURi2UNoGoZd|FXr NZfbdcQTD{UaR46#6!icA diff --git a/src/infrastructure/oci/autonomous/__pycache__/cases_manager.cpython-313.pyc b/src/infrastructure/oci/autonomous/__pycache__/cases_manager.cpython-313.pyc index ca8407d0d0933e0f0fab53940bae1efe52480e3f..95947c37885dcde974b11f5d3f741258f7fb92f8 100644 GIT binary patch delta 50 zcmew+_EL=dGcPX}0}wPX(%s1Yi=8odG8>16P;!25L1J-nd{Sa^c79q~W^(FgUk*)X E0Fzq~3;+NC delta 63 zcmaDU_DziYGcPX}0}vQFDsANc#m-nYnTQAZ`4F3id{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$=09xC`~ZE975)GK diff --git a/src/infrastructure/streaming/__pycache__/client.cpython-313.pyc b/src/infrastructure/streaming/__pycache__/client.cpython-313.pyc deleted file mode 100644 index 9997f6f1cbcd9f2c4672c59d45466baaeb8a756f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6666 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 diff --git a/src/providers/__pycache__/langfuse_provider.cpython-313.pyc b/src/providers/__pycache__/langfuse_provider.cpython-313.pyc index 919492d4b24d1dcea4af830a7da97fa3a86d07a8..60741a31e1493d5bf852e289eb1fea282d8cc698 100644 GIT binary patch delta 50 zcmeyS`cjqqGcPX}0}wPX(%r~?fQ2!3@);Hlq2&DBg2dwD_@u<-?EJK}%;eO~!mN*Z E0i=}?CIA2c delta 63 zcmaE<`c0MlGcPX}0}vQFDsALGz`~d{`3#GOd{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$W;WKxya0>U73u&0 diff --git a/src/providers/__pycache__/llm_provider.cpython-313.pyc b/src/providers/__pycache__/llm_provider.cpython-313.pyc index 5239a8c5b4ce4772817014ab2d4c21c6bff5d4c9..d3ac139bfa27e333da02c5ad149278e4975f6807 100644 GIT binary patch delta 1736 zcmZuxZ){Ul6u-Ca>u7mvC+*g*jP7oBNSPh7KPJc@`LnT&jVg zjWNV*i6Jqf5ppqV7R~e%#u%rK34{;E4}2hgp{dEVQ4=FE#!nat#KaHY(~dC>uj%jI z`#ZmT?mg$+cNT_kDxSY;Yu!XVuYDYwy54-*6Quuq@l+cPDIsOE;t!E2#}tL|iC`-^ z5f=Zt_&$ER-pBP|4L?s0Is|c;pRV)C^}8g9tjhRLG{E!n27a%qh@;{ORBT`8=-8U0 zoUP*MC6x7}>=~sYL|~`Vqy+E;(5Y-uf|XHMn1qQEM*QzjX;vCnPurcbM_J*%?S`Em z=U+OvZAux_dDS$N6Kd*|F*%t{X@$R?-%5dUeR2}iX>HbkQ^{!~t>u!snDSfl_j32L zveGkD>=`OG5A)AzE&2&>^;lg8M5JN zgPeK|TZ;1i8~q(|O2|88TwwJ{kiB%<>Nss9gb{`ItXkuCk*lUni8X<`osa~LOPI0E zwuiE{<$gjGyRg@YWuf`q!mE0Oka5?ldoo@rInES^BK6p-{JQ-+asS8aosZRr{-?*- zE05w-<{!5~HNYC3u1mmLxDgWFaPDSYGmYFCjj8$^%V`-kHOC$mkX6dX)Ld3InPo8R zq{h~2Sv7XJ-J`iQOV4X(w49M=DMO#kW=u9?YH60$Ee&)vx89FtcCbOc;%YjZ0o4+^ zJQ!12$`Yhuilg9mn#rbTOpEElFR%%XnVK#H1{*yzxMMW0=?4Z`ItyY|Zmz=(k$I7b zvVFoxmYtcrWte8=){K;0!^20DM@M`6hR=Bnu}sZ&2z#u%V`sDmJh(_QEy(7}Zqri1 zGH0{a$+DC)W;KAlXx=zEn>01c%IX;tHV7taE4xyvp3bJl*`ZA^rpWU=VGNqZ1ol0I z1ez`gSRnV@q_*yo>s{}A@si9|0k}e87(Zbna-}K@ain#zpB(L3~vBu2HtreBqa-ujm*uWeHS0qXBw>ClT5a zX3*q4qKuC8YAMk<`Tz_lJ99=xXaUb(u9;Oq7qx+mm_^;yrf`A(5&lqG6wLL)Tg}Jm zVdzJz1CEK;IZ@hZEM$;laO2DD@nuo=KOLM6r;3<;w+jnqkm1^#x6LKFPg zmO*-%$6AA)qewR);1%QFwAL3=t+!|$)}xv^OeHMxJ&`T$Yhs9f&HR+7A|C|rJ8Nmf xpJCDv`yuf3)#EF%kz#D56d2`l+fL6aHCBv`l>!NV_z~4#jP;iS1AL)v;a^)etpNZ4 delta 850 zcmY+A&rcIk5Xbx4E|uCAQYcHy7Ie#xZZN@8V<^GWVnk4b=pwdQ8l$_}&wKOz&YOKRALYt5&u_Qe zX<^TBQe6HaYZj?p*7M^(~BD`dhWx5qdLHLNML$Q3ieVI4m< zrG`0Yn)4mx9DA7!2eRuWPylAOogZc-3; zxhhj$8NSd0q0f5#_y5iTHn9fI)@&3`<4Nn}FB`6n3OKKS@*c6UZeP^26?lw}7lBhc zK70!y#R7C+S2D69)T8PQBq5uAja$2Yk;yKT_jI=%;X` V*^J^fK2DpYMii;>5qe3g`~kpv%_0B* diff --git a/src/utils/__pycache__/__init__.cpython-313.pyc b/src/utils/__pycache__/__init__.cpython-313.pyc index fc71056da95bea7983cc32fe98341cba1c13b490..c7b9af94da78feed772f8f69bdb21b0165440921 100644 GIT binary patch delta 46 zcmaFOc#o0$GcPX}0}wPX(w)d1%NQ^*Q$r{@Ker&UxHvv3F*!RwEiE%Sb>aqV080H2 Ai~s-t delta 59 zcmcb|_?nUXGcPX}0}vQFDox~$WsIGesUe?~n4F!TmX?{E8lRk>SC(2-l9`eppH`HZ Nn_8YdVr10?sj$^ zC8!7Y)b!R%svdi5dduI@ligH`HKkId9;)745%t_RvvvX~BhCAoH*fd7_j_}kN(~`c zfBiatKN|(kmBC8(h2y6nJV6*?X#-KtLmSe~5Dnc7)3Czz@P>RdLL&;=L6zab^*8(i z+KGKE1v-smnI>?A4&f+G;usyqahk#jI)aDjC{EHe9^M(lshzRQG9H;l_hmZ%F2WOd zbSETE(mNA)47T)93?c9fT^_>Y-0!|bGka1l^AG<}ITvC>>K?Iu>>EB|lTEh{T=%%9 z9}wRF)yPRKu}%$lAN#~TOm9=iB%bFen(Y&6J1nXC#I9Qh5XL#2DjK#)8ivpmZBj4zQA+$KwatDpMM=Xz`959)0&S9N z(4hA~z6(28UamAYm6%PbyTF(^xUB8G05q5?5W49~GwSYNm_5DK|4%M{ge zv9zgHwXL#VDXAFP%3H0M-fAu6B+7B<@j5B2kUy~fJa2e@*LtX%?rz?rX1?iL4KIH( zCw-qZTtdBN_Ys>lT(<%JIFYj6Pnn*Buv0vK9!Lwl%;s9_kGDGV+)=gwlGc%@-X?XE zBTtO@%fXMsFtH2Tg2e_E88vOqzo3^7~@d zq=D6zZqEnssD$+N2H}7B#>w!tHYQ>FGmGZLYWI78>K!cv=(i{+vA1SctGzcv7`l}~8PZ!`Q z%blx0TIkg`FU*^>_K&(a8Hxr=O3kwAQ=X1%ZcdEZvFCb#s^6 z>4i>w@n~-0#oStFZmm^%yxfszj*`kxlbz)CwtSt=K;WEI&P}oyPm&kpJfL*h;E&j{ zfJ-0;Zy4nW5LvOwvu?b8UQn3C9`QGWn#Fb9hQ~|S=>>i@!^tEk9LX%(FIRusw$|24 zWvtyQ>BX&bwN$RMnbQvH>a9|xs$nQOn>u}jOT}76tKMOYr|q?}TC3jJs%T%9R`u!) zt+J|bs}=B@KJB+!+uqcQYPG~<{)mV+v#{q=(S=`-C{@s`_|*fa-fWQ1X#tYp)9(EY zq!*SX=?^sWH`4w@OD_}Y7m3;560<*Ed7ik~iuU5@+y`xx=}uo1G!L{FMIV0AM%nJt zl{T8`E`dDNUD|4+#qQE4Z8Y7BMx}|Tat{G}mU+clZx+2X|8HVgQl)NkvKQvU%hXse h!Uc$zO7~(yjHC3#_tozXd&0Ljgre#HlKey@@;@5w3*`U+ diff --git a/src/utils/__pycache__/decision_helpers.cpython-313.pyc b/src/utils/__pycache__/decision_helpers.cpython-313.pyc index 0b2d4d310f54c250c4ed007a64784d3e90016e03..ec0586af47272b889a89d00d745a0699c206b1cf 100644 GIT binary patch delta 50 zcmZ1|Hbsp4GcPX}0}wPX(%s0d%*+@uS)W-$C^gT2zvmk{_Q| Rl$e`Zo?n!`Ig@!cI{+t56a)YO diff --git a/src/utils/__pycache__/external_response_builder.cpython-313.pyc b/src/utils/__pycache__/external_response_builder.cpython-313.pyc index c2eedfd4e6cd441c11223a38bc7c0fb70710694a..3e40e9603f61f190bb1cf9a8688f6e5d72324fba 100644 GIT binary patch delta 50 zcmew@{!X0xGcPX}0}wPX(%s0tl9@4a@>XUIq2&DBg2dwD_@u<-?EJK}%;eO~f0+NX F0|1}>5#;~? delta 63 zcmaDS{#%^;GcPX}0}vQFDsALm$;_BHc`LJqd{Sa^c79q~W^!tLa(-S}YEemMN`8D= RQDSatd45s$=J(A1*#U$X7O4OL diff --git a/src/utils/__pycache__/forwarding_helpers.cpython-313.pyc b/src/utils/__pycache__/forwarding_helpers.cpython-313.pyc index 7d515b9be956e3d21dee9f2f08883a2355cc5945..5c434d0adafce091662faa56149d56c8eff85bdb 100644 GIT binary patch delta 50 zcmaFw`pA|0GcPX}0}wPX(%r}{#>5ykS&2zQC^gT2zvmk{_Q| Rl$e`Zo?n!`IfkiC0RUdZ6v_Yq diff --git a/src/utils/__pycache__/http.cpython-313.pyc b/src/utils/__pycache__/http.cpython-313.pyc index 8860df0755a8cab883d8ae60e061245eceafd659..2fb650ae51323d75af4f776a94ab368065f83606 100644 GIT binary patch delta 50 zcmX@(u-}3EGcPX}0}wPX(%s1I#lq+_IgCX^C^gT2zvmk{_Q| Rl$e`Zo?n!`c>>FNX#iX<6*2$- diff --git a/src/utils/__pycache__/ics_collector.cpython-313.pyc b/src/utils/__pycache__/ics_collector.cpython-313.pyc index 72784d864c18fbd0f106721290c59d20d85214f0..6d14f331190e65b0e82bb0667884a902495ad1cb 100644 GIT binary patch delta 52 zcmbPmgR%JrBll-sUM>b8XkMhdkz1LcF?6y%zlKn9er`cxadCW7VsdtVT3Tju>gF>3 GSup^k`Vk2L delta 65 zcmZp^!8qXtBll-sUM>b8FmhDd$gRxJm^4|RUqe1AF*!RwEiE%SH9k2%uPn8wBr_#H TKCLJ*H?=&!D0_1z|Ew4QgWVO) diff --git a/src/utils/__pycache__/loaders.cpython-313.pyc b/src/utils/__pycache__/loaders.cpython-313.pyc deleted file mode 100644 index be47377ce3e514e5111de3e99b2a38abda5e5d04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 743 zcmYLHJ8#oa6h7CF#EA(|kf0z$ZxI3#C|(E;2`ZH`wNgN}GN4qlj32=ve(2hfNX5_* zkpTuOb<9}AA7Eu=3rnR7Ot7#;3J8gbbJMt-YoG5t?|ImhN~H`)-#;yO1_V(kIVm$? zQbS<}OfbnhFoDuKS(BJV!IU>;Q`uB*D5iQAIto+Uq+0kX5*t;*l}C2=l$ZRV>sgT< zdc45Atj8h;OC3@HB^lqz2V^_YI`p-qJf=RgZR9QG4n&hI=>Sa-JR+@P?rIWKGO@Wk zvILRT(sKL8bl_Y&zzfin@*1gRs^ZjV)hS$rMYsl6W+^WA;^XKGK=HKId-4MKIP_M1 z)n?3V+q4(bHS=MEx;9PhG_$Ge(J*$NrPK>)${eGY1>Mw`nhdT^krTG1_A-CzHm*(c zA}4l(sNJX*m{<+hENi+%ix(1`c~QodIPoH`bkZ1kH@4lX%*1xMl8BuXKNX3TQhvz@ zqs(ya%r^Ysx#c9j@xKX?>9O>B(&tBoY>93xaVtB4`Qpa(KC*52rNNQoZ?(blzD`Fv z9o`!0wY|q9{pR+AAEnAm_s#0?^5;@*&;EMs*c{_fo1#UB~USNBUbeEz2Rec=76 z6E;*))Wb^K%Oli;Lrv5|gv@)6z1NQ#UKH HcV__r)&3GQ delta 65 zcmbRDm~r)EM()qNyj%=GVC1N@k^3wgW9;OcY#Q=OiOJddX=$0ssqxAAd1a|ZC7CJt T@o7bgxvAy(McJE$*}Jm<$<`M4 diff --git a/src/utils/__pycache__/text.cpython-313.pyc b/src/utils/__pycache__/text.cpython-313.pyc index cdc0e71af0182e63c5e5f583b6315c2260f8353a..e9bbd3463dfbe44cbf8b4cf147f54d3466af410c 100644 GIT binary patch delta 49 zcmX@ewuO!RGcPX}0}wPX(%s0-#l+|{S&T_TC^gT2zvmk{_Q| Ql$e`Zo?nzbIe_U201zD$+yDRo diff --git a/tools/__pycache__/validate_parity.cpython-313.pyc b/tools/__pycache__/validate_parity.cpython-313.pyc deleted file mode 100644 index ced5a459f2979b291a78ad8eaecf501bb66b69da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5973 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 j@u!zib2BCh{2WDZ%w}Glh$wB?C|^_sSL3s diff --git a/tools/validate_parity.py b/tools/validate_parity.py index 2c81565..f97bbe3 100644 --- a/tools/validate_parity.py +++ b/tools/validate_parity.py @@ -3,7 +3,7 @@ from pathlib import Path REQUIRED = [ 'app/main.py', 'app/workflows/agent_graph.py', - 'app/workflows/backoffice_native_runtime.py', + 'app/workflows/backoffice_workflow_executor.py', 'app/agents/backoffice_agent.py', 'src/agent/nodes/fetch_ticket_node.py', 'src/agent/nodes/validation_node.py', @@ -55,7 +55,7 @@ for py in [p for p in Path('app').rglob('*.py') if '__pycache__' not in str(p)]: main = Path('app/main.py').read_text() needles = [ - 'BackofficeNativeRuntime', + 'BackofficeWorkflowExecutor', 'execute_workflow(', 'backoffice_checklist', 'backoffice_response_emulator', @@ -68,7 +68,7 @@ for n in needles: # Guardrails must be bound from the backoffice agent profile, not only from global config. -runtime = Path('app/workflows/backoffice_native_runtime.py').read_text(errors='ignore') +runtime = Path('app/workflows/backoffice_workflow_executor.py').read_text(errors='ignore') for needle in [ '_resolve_agent_profile("backoffice_anatel")', 'self.agent_profile["guardrails_config_path"]', @@ -91,7 +91,7 @@ print('OK: backoffice framework-native structural validation passed') print('python_files=', len(list(Path('.').rglob('*.py')))) # IC/NOC/GRL observability must be framework-native in the backoffice runtime. -runtime = Path('app/workflows/backoffice_native_runtime.py').read_text(errors='ignore') +runtime = Path('app/workflows/backoffice_workflow_executor.py').read_text(errors='ignore') for needle in [ '_safe_emit_ic', '_safe_emit_noc',