rasa-pro 3.13.1a19__py3-none-any.whl → 3.13.1a20__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- rasa/__main__.py +8 -0
- rasa/builder/auth.py +71 -0
- rasa/builder/config.py +16 -0
- rasa/builder/copilot/constants.py +15 -0
- rasa/builder/copilot/copilot.py +342 -0
- rasa/builder/copilot/copilot_response_handler.py +471 -0
- rasa/builder/copilot/exceptions.py +20 -0
- rasa/builder/copilot/models.py +344 -0
- rasa/builder/copilot/prompts/copilot_system_prompt.jinja2 +495 -0
- rasa/builder/copilot/telemetry.py +195 -0
- rasa/builder/document_retrieval/__init__.py +0 -0
- rasa/builder/document_retrieval/constants.py +16 -0
- rasa/builder/{inkeep_document_retrieval.py → document_retrieval/inkeep_document_retrieval.py} +24 -30
- rasa/builder/document_retrieval/models.py +62 -0
- rasa/builder/download.py +140 -0
- rasa/builder/guardrails/__init__.py +1 -0
- rasa/builder/guardrails/constants.py +4 -0
- rasa/builder/guardrails/exceptions.py +4 -0
- rasa/builder/guardrails/lakera.py +188 -0
- rasa/builder/guardrails/models.py +199 -0
- rasa/builder/guardrails/utils.py +305 -0
- rasa/builder/job_manager.py +87 -0
- rasa/builder/jobs.py +232 -0
- rasa/builder/llm_service.py +59 -7
- rasa/builder/logging_utils.py +162 -4
- rasa/builder/main.py +29 -16
- rasa/builder/models.py +90 -233
- rasa/builder/project_generator.py +91 -7
- rasa/builder/scrape_rasa_docs.py +1 -1
- rasa/builder/service.py +632 -440
- rasa/builder/shared/tracker_context.py +212 -0
- rasa/builder/validation_service.py +4 -4
- rasa/cli/data.py +8 -3
- rasa/cli/project_templates/basic/actions/action_api.py +15 -0
- rasa/cli/project_templates/basic/actions/action_human_handoff.py +44 -0
- rasa/cli/project_templates/basic/config.yml +23 -0
- rasa/cli/project_templates/{plain → basic}/credentials.yml +8 -7
- rasa/cli/project_templates/basic/data/general/feedback.yml +20 -0
- rasa/cli/project_templates/basic/data/general/goodbye.yml +6 -0
- rasa/cli/project_templates/basic/data/general/hello.yml +7 -0
- rasa/cli/project_templates/basic/data/general/help.yml +6 -0
- rasa/cli/project_templates/basic/data/general/human_handoff.yml +16 -0
- rasa/cli/project_templates/basic/data/general/welcome.yml +9 -0
- rasa/cli/project_templates/{finance/data/patterns → basic/data/system}/pattern_completed.yml +2 -1
- rasa/cli/project_templates/basic/data/system/pattern_correction.yml +7 -0
- rasa/cli/project_templates/basic/data/system/pattern_search.yml +8 -0
- rasa/cli/project_templates/basic/data/system/pattern_session_start.yml +8 -0
- rasa/cli/project_templates/basic/docs/rasa_assistant_qa.txt +65 -0
- rasa/cli/project_templates/basic/docs/template.txt +7 -0
- rasa/cli/project_templates/basic/domain/general/assistant_details.yml +12 -0
- rasa/cli/project_templates/basic/domain/general/bot_identity.yml +5 -0
- rasa/cli/project_templates/basic/domain/general/cannot_handle.yml +5 -0
- rasa/cli/project_templates/basic/domain/general/feedback.yml +28 -0
- rasa/cli/project_templates/basic/domain/general/goodbye.yml +7 -0
- rasa/cli/project_templates/basic/domain/general/help.yml +5 -0
- rasa/cli/project_templates/basic/domain/general/human_handoff_domain.yml +35 -0
- rasa/cli/project_templates/{finance/domain/default_actions.yml → basic/domain/general/utils.yml} +0 -3
- rasa/cli/project_templates/basic/domain/general/welcome.yml +7 -0
- rasa/cli/project_templates/{plain → basic}/endpoints.yml +42 -27
- rasa/cli/project_templates/basic/prompts/rephraser_demo_personality_prompt.jinja2 +19 -0
- rasa/cli/project_templates/defaults.py +25 -3
- rasa/cli/project_templates/finance/actions/__init__.py +46 -0
- rasa/cli/project_templates/finance/actions/accounts/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/{action_ask_account.py → accounts/action_ask_account.py} +6 -9
- rasa/cli/project_templates/finance/actions/{action_check_balance.py → accounts/action_check_balance.py} +4 -4
- rasa/cli/project_templates/finance/actions/action_session_start.py +11 -6
- rasa/cli/project_templates/finance/actions/cards/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/{action_ask_card.py → cards/action_ask_card.py} +4 -3
- rasa/cli/project_templates/finance/actions/{action_check_card_existence.py → cards/action_check_card_existence.py} +4 -3
- rasa/cli/project_templates/finance/actions/{action_update_card_status.py → cards/action_update_card_status.py} +18 -9
- rasa/cli/project_templates/finance/actions/database.py +1 -0
- rasa/cli/project_templates/finance/actions/transfers/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/{action_add_payee.py → transfers/action_add_payee.py} +8 -3
- rasa/cli/project_templates/finance/actions/{action_ask_account_from.py → transfers/action_ask_account_from.py} +5 -4
- rasa/cli/project_templates/finance/actions/{action_check_payee_existence.py → transfers/action_check_payee_existence.py} +3 -3
- rasa/cli/project_templates/finance/actions/{action_check_sufficient_funds.py → transfers/action_check_sufficient_funds.py} +3 -4
- rasa/cli/project_templates/finance/actions/{action_list_payees.py → transfers/action_list_payees.py} +4 -3
- rasa/cli/project_templates/finance/actions/{action_remove_payee.py → transfers/action_remove_payee.py} +4 -4
- rasa/cli/project_templates/finance/config.yml +8 -19
- rasa/cli/project_templates/finance/credentials.yml +6 -7
- rasa/cli/project_templates/finance/csvs/cards.csv +10 -10
- rasa/cli/project_templates/finance/csvs/payees.csv +10 -9
- rasa/cli/project_templates/finance/data/{flows → accounts}/check_balance.yml +2 -1
- rasa/cli/project_templates/finance/data/general/bot_identity.yml +6 -0
- rasa/cli/project_templates/finance/data/general/feedback.yml +20 -0
- rasa/cli/project_templates/finance/data/general/goodbye.yml +6 -0
- rasa/cli/project_templates/finance/data/general/hello.yml +7 -0
- rasa/cli/project_templates/finance/data/{flows/welcome.yml → general/help.yml} +2 -7
- rasa/cli/project_templates/finance/data/general/human_handoff.yml +16 -0
- rasa/cli/project_templates/finance/data/general/welcome.yml +9 -0
- rasa/cli/project_templates/finance/data/{patterns → system/patterns}/pattern_chitchat.yml +0 -2
- rasa/cli/project_templates/finance/data/system/patterns/pattern_completed.yml +7 -0
- rasa/cli/project_templates/finance/data/system/patterns/pattern_correction.yml +7 -0
- rasa/cli/project_templates/finance/data/system/patterns/pattern_search.yml +8 -0
- rasa/cli/project_templates/finance/data/{patterns → system/patterns}/pattern_session_start.yml +0 -1
- rasa/cli/project_templates/finance/domain/{check_balance.yml → accounts/check_balance.yml} +2 -0
- rasa/cli/project_templates/finance/domain/general/assistant_details.yml +12 -0
- rasa/cli/project_templates/finance/domain/general/bot_identity.yml +5 -0
- rasa/cli/project_templates/finance/domain/general/cannot_handle.yml +5 -0
- rasa/cli/project_templates/finance/domain/general/defaults.yml +24 -0
- rasa/cli/project_templates/finance/domain/general/feedback.yml +28 -0
- rasa/cli/project_templates/finance/domain/general/goodbye.yml +7 -0
- rasa/cli/project_templates/finance/domain/general/help.yml +5 -0
- rasa/cli/project_templates/finance/domain/general/human_handoff.yml +30 -0
- rasa/cli/project_templates/finance/domain/general/utils.yml +13 -0
- rasa/cli/project_templates/finance/domain/general/welcome.yml +8 -0
- rasa/cli/project_templates/finance/endpoints.yml +1 -0
- rasa/cli/project_templates/finance/prompts/rephraser_demo_personality_prompt.jinja2 +3 -3
- rasa/cli/project_templates/telco/actions/actions_billing.py +24 -17
- rasa/cli/project_templates/telco/actions/actions_get_data_from_db.py +6 -1
- rasa/cli/project_templates/telco/actions/actions_run_diagnostics.py +6 -1
- rasa/cli/project_templates/telco/actions/actions_session_start.py +6 -1
- rasa/cli/project_templates/tutorial/config.yml +2 -1
- rasa/cli/scaffold.py +27 -2
- rasa/cli/train.py +8 -0
- rasa/cli/utils.py +31 -15
- rasa/core/actions/action.py +28 -41
- rasa/core/actions/action_run_slot_rejections.py +1 -1
- rasa/core/channels/development_inspector.py +47 -14
- rasa/core/channels/inspector/dist/assets/{arc-371401b1.js → arc-1ddec37b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-3f126156.js → blockDiagram-38ab4fdb-18af387c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-12f22eb7.js → c4Diagram-3d4e48cf-250127a3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-59f6d54b.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-03b1d386.js → classDiagram-70f12bd4-c3388b34.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-84f69d63.js → classDiagram-v2-f2320105-9c893a82.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-26177ddb.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-ca47fd38.js → createText-2e5e7dd3-c111213b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-f837ca8a.js → edges-e0da2a9e-812a729d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-8717ac54.js → erDiagram-9861fffd-fd5051bc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-94f38b83.js → flowDb-956e92f1-3287ac02.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-b616f9fb.js → flowDiagram-66a62f08-692fb0b2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-29c03f5a.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-f5d24bb8.js → flowchart-elk-definition-4a651766-008376f1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-b43ba8d9.js → ganttDiagram-c361ad54-df330a69.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-c3aafaa5.js → gitGraphDiagram-72cf32ee-e03676fb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-0d0a2c10.js → graph-46fad2ba.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-58ea0305.js → index-3862675e-a484ac55.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-cce6f8a1.js → index-a003633f.js} +179 -179
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-b8f60461.js → infoDiagram-f8f76790-3f9e6ec2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-95be5545.js → journeyDiagram-49397b02-79f72383.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-da885b9b.js → layout-aad098e5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-f1c817d3.js → line-219ab7ae.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-d42801e6.js → linear-2cddbe62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-a38923a6.js → mindmap-definition-fc14e90a-1d41ed99.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-ca6e71e9.js → pieDiagram-8a3498a8-cc496ee8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-b290dae9.js → quadrantDiagram-120e2f19-84d32884.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-03f02ceb.js → requirementDiagram-deff3bca-c0deb984.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-c49eee40.js → sankeyDiagram-04a897e0-b9d7fd62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-b2cd6a3d.js → sequenceDiagram-704730f1-7d517565.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-e53a2028.js → stateDiagram-587899a1-98ef9b27.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-e1982a03.js → stateDiagram-v2-d93cdb3a-cee70748.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-d0226ca5.js → styles-6aaf32cf-3f9d1c96.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-0e21dc00.js → styles-9a916d00-67471923.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-9588494e.js → styles-c10674c1-bd093fb7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-be478d4f.js → svgDrawCommon-08f97a94-675794e8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-74631749.js → timeline-definition-85554ec2-0ac67617.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-a043552f.js → xychartDiagram-e933f94c-c018dc37.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +2 -2
- rasa/core/channels/inspector/index.html +1 -1
- rasa/core/channels/inspector/package.json +4 -3
- rasa/core/channels/inspector/src/App.tsx +53 -7
- rasa/core/channels/inspector/src/components/Chat.tsx +3 -2
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +1 -1
- rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +268 -0
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +6 -2
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +8 -3
- rasa/core/channels/inspector/src/types.ts +8 -0
- rasa/core/channels/inspector/yarn.lock +12 -12
- rasa/core/channels/studio_chat.py +119 -34
- rasa/core/channels/voice_ready/twilio_voice.py +1 -1
- rasa/core/channels/voice_stream/asr/asr_engine.py +5 -1
- rasa/core/channels/voice_stream/asr/deepgram.py +5 -0
- rasa/core/channels/voice_stream/audiocodes.py +16 -8
- rasa/core/channels/voice_stream/browser_audio.py +39 -4
- rasa/core/channels/voice_stream/call_state.py +13 -2
- rasa/core/channels/voice_stream/genesys.py +16 -13
- rasa/core/channels/voice_stream/jambonz.py +14 -12
- rasa/core/channels/voice_stream/twilio_media_streams.py +14 -13
- rasa/core/channels/voice_stream/util.py +11 -1
- rasa/core/channels/voice_stream/voice_channel.py +108 -29
- rasa/core/nlg/callback.py +1 -1
- rasa/core/nlg/contextual_response_rephraser.py +19 -9
- rasa/core/nlg/generator.py +21 -5
- rasa/core/nlg/response.py +43 -6
- rasa/core/nlg/translate.py +8 -0
- rasa/core/policies/enterprise_search_policy.py +16 -21
- rasa/dialogue_understanding/commands/correct_slots_command.py +38 -10
- rasa/dialogue_understanding/generator/command_generator.py +5 -5
- rasa/dialogue_understanding/generator/command_parser.py +9 -13
- rasa/dialogue_understanding/processor/command_processor.py +149 -55
- rasa/dialogue_understanding/stack/utils.py +13 -3
- rasa/dialogue_understanding_test/du_test_schema.yml +3 -3
- rasa/dialogue_understanding_test/validation.py +9 -10
- rasa/e2e_test/e2e_config.py +18 -11
- rasa/e2e_test/e2e_test_schema.yml +3 -3
- rasa/e2e_test/utils/validation.py +17 -19
- rasa/engine/validation.py +86 -91
- rasa/exceptions.py +26 -1
- rasa/model_manager/model_api.py +2 -2
- rasa/model_manager/socket_bridge.py +8 -2
- rasa/shared/providers/_configs/default_litellm_client_config.py +3 -7
- rasa/shared/utils/cli.py +2 -0
- rasa/shared/utils/common.py +2 -1
- rasa/shared/utils/health_check/health_check.py +10 -14
- rasa/studio/upload.py +6 -2
- rasa/studio/utils.py +33 -22
- rasa/telemetry.py +95 -22
- rasa/utils/licensing.py +21 -10
- rasa/utils/log_utils.py +1 -1
- rasa/utils/tensorflow/transformer.py +3 -3
- rasa/validator.py +7 -5
- rasa/version.py +1 -1
- {rasa_pro-3.13.1a19.dist-info → rasa_pro-3.13.1a20.dist-info}/METADATA +7 -7
- {rasa_pro-3.13.1a19.dist-info → rasa_pro-3.13.1a20.dist-info}/RECORD +242 -205
- rasa/builder/constants.py +0 -4
- rasa/builder/copilot-llm-structured-output-response-schema.json +0 -69
- rasa/builder/copilot.py +0 -233
- rasa/builder/copilot_system_prompt.jinja2 +0 -245
- rasa/builder/create_openai_vector_store.py +0 -228
- rasa/builder/llm_context.py +0 -81
- rasa/cli/project_templates/finance/data/nlu.yml +0 -29
- rasa/cli/project_templates/finance/data/patterns/pattern_search.yml +0 -5
- rasa/cli/project_templates/finance/domain/default_flows.yml +0 -33
- rasa/cli/project_templates/finance/prompts/command-generator.jinja2 +0 -57
- rasa/cli/project_templates/finance/tests/conversation_repair/cancellations.yml +0 -12
- rasa/cli/project_templates/finance/tests/conversation_repair/cannot_handle.yml +0 -7
- rasa/cli/project_templates/finance/tests/conversation_repair/chitchat.yml +0 -7
- rasa/cli/project_templates/finance/tests/conversation_repair/clarification.yml +0 -9
- rasa/cli/project_templates/finance/tests/conversation_repair/completion.yml +0 -18
- rasa/cli/project_templates/finance/tests/conversation_repair/corrections.yml +0 -17
- rasa/cli/project_templates/finance/tests/conversation_repair/digressions.yml +0 -32
- rasa/cli/project_templates/finance/tests/conversation_repair/human_handoff.yml +0 -21
- rasa/cli/project_templates/finance/tests/conversation_repair/skipping_collect_steps.yml +0 -16
- rasa/cli/project_templates/finance/tests/demo_scripts/main.yml +0 -16
- rasa/cli/project_templates/finance/tests/happy_paths/balance_verification.yml +0 -15
- rasa/cli/project_templates/finance/tests/happy_paths/banking_questions.yml +0 -12
- rasa/cli/project_templates/finance/tests/happy_paths/card_blocking.yml +0 -52
- rasa/cli/project_templates/finance/tests/happy_paths/money_transfer.yml +0 -136
- rasa/cli/project_templates/finance/tests/happy_paths/payee_management.yml +0 -27
- rasa/cli/project_templates/finance/tests/happy_paths/user_greeted.yml +0 -5
- rasa/cli/project_templates/plain/config.yml +0 -17
- rasa/cli/project_templates/plain/data/patterns/pattern_session_start.yml +0 -7
- rasa/cli/project_templates/plain/domain.yml +0 -5
- rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +0 -1
- rasa/shared/importers/static.py +0 -63
- /rasa/{cli/project_templates/plain/actions → builder/copilot}/__init__.py +0 -0
- /rasa/builder/{inkeep-rag-response-schema.json → document_retrieval/inkeep-rag-response-schema.json} +0 -0
- /rasa/cli/project_templates/finance/actions/{action_process_immediate_payment.py → transfers/action_process_immediate_payment.py} +0 -0
- /rasa/cli/project_templates/finance/actions/{action_schedule_payment.py → transfers/action_schedule_payment.py} +0 -0
- /rasa/cli/project_templates/finance/actions/{action_validate_payment_date.py → transfers/action_validate_payment_date.py} +0 -0
- /rasa/cli/project_templates/finance/data/{flows → cards}/block_card.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → cards}/select_card.yml +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/accounts.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/advisors.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/appointments.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/branches.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/cards.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/payees.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/transactions.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/users.json +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/add_payee.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/list_payees.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/remove_payee.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/transfer_money.yml +0 -0
- /rasa/cli/project_templates/finance/domain/{block_card.yml → cards/block_card.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{select_card.yml → cards/select_card.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{add_payee.yml → transfers/add_payee.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{list_payees.yml → transfers/list_payees.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{remove_payee.yml → transfers/remove_payee.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{transfer_money.yml → transfers/transfer_money.yml} +0 -0
- {rasa_pro-3.13.1a19.dist-info → rasa_pro-3.13.1a20.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.1a19.dist-info → rasa_pro-3.13.1a20.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.1a19.dist-info → rasa_pro-3.13.1a20.dist-info}/entry_points.txt +0 -0
rasa/builder/jobs.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
import structlog
|
|
4
|
+
from sanic import Sanic
|
|
5
|
+
|
|
6
|
+
from rasa.builder.exceptions import (
|
|
7
|
+
LLMGenerationError,
|
|
8
|
+
ProjectGenerationError,
|
|
9
|
+
TrainingError,
|
|
10
|
+
ValidationError,
|
|
11
|
+
)
|
|
12
|
+
from rasa.builder.job_manager import JobInfo, job_manager
|
|
13
|
+
from rasa.builder.models import (
|
|
14
|
+
JobStatus,
|
|
15
|
+
JobStatusEvent,
|
|
16
|
+
)
|
|
17
|
+
from rasa.builder.training_service import train_and_load_agent
|
|
18
|
+
from rasa.builder.validation_service import validate_project
|
|
19
|
+
from rasa.cli.scaffold import ProjectTemplateName
|
|
20
|
+
|
|
21
|
+
structlogger = structlog.get_logger()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def push_job_status_event(
|
|
25
|
+
job: JobInfo, status: JobStatus, message: Optional[str] = None
|
|
26
|
+
) -> None:
|
|
27
|
+
event = JobStatusEvent.from_status(status=status.value, message=message)
|
|
28
|
+
job.status = status.value
|
|
29
|
+
await job.put(event)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
async def run_prompt_to_bot_job(
|
|
33
|
+
app: Any,
|
|
34
|
+
job: JobInfo,
|
|
35
|
+
prompt: str,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Run the prompt-to-bot job in the background.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
app: The Sanic application instance.
|
|
41
|
+
job: The job information instance.
|
|
42
|
+
prompt: The natural language prompt for bot generation.
|
|
43
|
+
"""
|
|
44
|
+
project_generator = app.ctx.project_generator
|
|
45
|
+
input_channel = app.ctx.input_channel
|
|
46
|
+
await push_job_status_event(job, JobStatus.received)
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
# 1. Generating
|
|
50
|
+
await push_job_status_event(job, JobStatus.generating)
|
|
51
|
+
bot_files = await project_generator.generate_project_with_retries(
|
|
52
|
+
prompt,
|
|
53
|
+
template=ProjectTemplateName.BASIC,
|
|
54
|
+
)
|
|
55
|
+
await push_job_status_event(job, JobStatus.generation_success)
|
|
56
|
+
|
|
57
|
+
# 2. Training
|
|
58
|
+
await push_job_status_event(job, JobStatus.training)
|
|
59
|
+
importer = project_generator._create_importer()
|
|
60
|
+
app.ctx.agent = await train_and_load_agent(importer)
|
|
61
|
+
input_channel.agent = app.ctx.agent
|
|
62
|
+
await push_job_status_event(job, JobStatus.train_success)
|
|
63
|
+
|
|
64
|
+
structlogger.info(
|
|
65
|
+
"bot_builder_service.prompt_to_bot.success",
|
|
66
|
+
files_generated=list(bot_files.keys()),
|
|
67
|
+
)
|
|
68
|
+
await push_job_status_event(job, JobStatus.done)
|
|
69
|
+
job_manager.mark_done(job)
|
|
70
|
+
|
|
71
|
+
except TrainingError as exc:
|
|
72
|
+
structlogger.debug(
|
|
73
|
+
"prompt_to_bot_job.training_error", job_id=job.id, error=str(exc)
|
|
74
|
+
)
|
|
75
|
+
await push_job_status_event(job, JobStatus.train_error, message=str(exc))
|
|
76
|
+
job_manager.mark_done(job, error=str(exc))
|
|
77
|
+
|
|
78
|
+
except ValidationError as exc:
|
|
79
|
+
structlogger.debug(
|
|
80
|
+
"prompt_to_bot_job.validation_error", job_id=job.id, error=str(exc)
|
|
81
|
+
)
|
|
82
|
+
await push_job_status_event(job, JobStatus.validation_error, message=str(exc))
|
|
83
|
+
job_manager.mark_done(job, error=str(exc))
|
|
84
|
+
|
|
85
|
+
except (ProjectGenerationError, LLMGenerationError) as exc:
|
|
86
|
+
structlogger.debug(
|
|
87
|
+
"prompt_to_bot_job.generation_error", job_id=job.id, error=str(exc)
|
|
88
|
+
)
|
|
89
|
+
await push_job_status_event(job, JobStatus.generation_error, message=str(exc))
|
|
90
|
+
job_manager.mark_done(job, error=str(exc))
|
|
91
|
+
|
|
92
|
+
except Exception as exc:
|
|
93
|
+
# Capture full traceback
|
|
94
|
+
structlogger.exception(
|
|
95
|
+
"prompt_to_bot_job.unexpected_error", job_id=job.id, error=str(exc)
|
|
96
|
+
)
|
|
97
|
+
await push_job_status_event(job, JobStatus.error, message=str(exc))
|
|
98
|
+
job_manager.mark_done(job, error=str(exc))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
async def run_template_to_bot_job(
|
|
102
|
+
app: "Sanic",
|
|
103
|
+
job: JobInfo,
|
|
104
|
+
template_name: ProjectTemplateName,
|
|
105
|
+
) -> None:
|
|
106
|
+
"""Run the template-to-bot job in the background.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
app: The Sanic application instance.
|
|
110
|
+
job: The job information instance.
|
|
111
|
+
template_name: The name of the template to use for bot generation.
|
|
112
|
+
"""
|
|
113
|
+
project_generator = app.ctx.project_generator
|
|
114
|
+
input_channel = app.ctx.input_channel
|
|
115
|
+
await push_job_status_event(job, JobStatus.received)
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
# 1) Generating
|
|
119
|
+
await push_job_status_event(job, JobStatus.generating)
|
|
120
|
+
await project_generator.init_from_template(template_name)
|
|
121
|
+
bot_files = project_generator.get_bot_files()
|
|
122
|
+
await push_job_status_event(job, JobStatus.generation_success)
|
|
123
|
+
|
|
124
|
+
# 2) Training
|
|
125
|
+
await push_job_status_event(job, JobStatus.training)
|
|
126
|
+
importer = project_generator._create_importer()
|
|
127
|
+
app.ctx.agent = await train_and_load_agent(importer)
|
|
128
|
+
input_channel.agent = app.ctx.agent
|
|
129
|
+
await push_job_status_event(job, JobStatus.train_success)
|
|
130
|
+
|
|
131
|
+
# 3) Done
|
|
132
|
+
structlogger.info(
|
|
133
|
+
"bot_builder_service.template_to_bot.success",
|
|
134
|
+
files_generated=list(bot_files.keys()),
|
|
135
|
+
)
|
|
136
|
+
await push_job_status_event(job, JobStatus.done)
|
|
137
|
+
job_manager.mark_done(job)
|
|
138
|
+
|
|
139
|
+
except TrainingError as exc:
|
|
140
|
+
structlogger.debug(
|
|
141
|
+
"template_to_bot_job.training_error",
|
|
142
|
+
job_id=job.id,
|
|
143
|
+
error=str(exc),
|
|
144
|
+
)
|
|
145
|
+
await push_job_status_event(job, JobStatus.train_error, message=str(exc))
|
|
146
|
+
job_manager.mark_done(job, error=str(exc))
|
|
147
|
+
|
|
148
|
+
except ValidationError as exc:
|
|
149
|
+
structlogger.debug(
|
|
150
|
+
"template_to_bot_job.validation_error",
|
|
151
|
+
job_id=job.id,
|
|
152
|
+
error=str(exc),
|
|
153
|
+
)
|
|
154
|
+
await push_job_status_event(job, JobStatus.validation_error, message=str(exc))
|
|
155
|
+
job_manager.mark_done(job, error=str(exc))
|
|
156
|
+
|
|
157
|
+
except ProjectGenerationError as exc:
|
|
158
|
+
structlogger.debug(
|
|
159
|
+
"template_to_bot_job.generation_error",
|
|
160
|
+
job_id=job.id,
|
|
161
|
+
error=str(exc),
|
|
162
|
+
)
|
|
163
|
+
await push_job_status_event(job, JobStatus.generation_error, message=str(exc))
|
|
164
|
+
job_manager.mark_done(job, error=str(exc))
|
|
165
|
+
|
|
166
|
+
except Exception as exc:
|
|
167
|
+
# Capture full traceback
|
|
168
|
+
structlogger.exception(
|
|
169
|
+
"template_to_bot_job.unexpected_error",
|
|
170
|
+
job_id=job.id,
|
|
171
|
+
error=str(exc),
|
|
172
|
+
)
|
|
173
|
+
await push_job_status_event(job, JobStatus.error, message=str(exc))
|
|
174
|
+
job_manager.mark_done(job, error=str(exc))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
async def run_update_files_job(
|
|
178
|
+
app: "Sanic",
|
|
179
|
+
job: JobInfo,
|
|
180
|
+
bot_files: dict,
|
|
181
|
+
) -> None:
|
|
182
|
+
project_generator = app.ctx.project_generator
|
|
183
|
+
input_channel = app.ctx.input_channel
|
|
184
|
+
await push_job_status_event(job, JobStatus.received)
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
project_generator.update_bot_files(bot_files)
|
|
188
|
+
|
|
189
|
+
# 1. Validating
|
|
190
|
+
await push_job_status_event(job, JobStatus.validating)
|
|
191
|
+
importer = project_generator._create_importer()
|
|
192
|
+
validation_error = await validate_project(importer)
|
|
193
|
+
if validation_error:
|
|
194
|
+
raise ValidationError(validation_error)
|
|
195
|
+
await push_job_status_event(job, JobStatus.validation_success)
|
|
196
|
+
|
|
197
|
+
# 2. Training
|
|
198
|
+
await push_job_status_event(job, JobStatus.training)
|
|
199
|
+
app.ctx.agent = await train_and_load_agent(importer)
|
|
200
|
+
input_channel.agent = app.ctx.agent
|
|
201
|
+
await push_job_status_event(job, JobStatus.train_success)
|
|
202
|
+
|
|
203
|
+
await push_job_status_event(job, JobStatus.done)
|
|
204
|
+
job_manager.mark_done(job)
|
|
205
|
+
|
|
206
|
+
except ValidationError as exc:
|
|
207
|
+
structlogger.debug(
|
|
208
|
+
"update_files_job.validation_error",
|
|
209
|
+
job_id=job.id,
|
|
210
|
+
error=str(exc),
|
|
211
|
+
)
|
|
212
|
+
await push_job_status_event(job, JobStatus.validation_error, message=str(exc))
|
|
213
|
+
job_manager.mark_done(job, error=str(exc))
|
|
214
|
+
|
|
215
|
+
except TrainingError as exc:
|
|
216
|
+
structlogger.debug(
|
|
217
|
+
"update_files_job.train_error",
|
|
218
|
+
job_id=job.id,
|
|
219
|
+
error=str(exc),
|
|
220
|
+
)
|
|
221
|
+
await push_job_status_event(job, JobStatus.train_error, message=str(exc))
|
|
222
|
+
job_manager.mark_done(job, error=str(exc))
|
|
223
|
+
|
|
224
|
+
except Exception as exc:
|
|
225
|
+
# Capture full traceback for anything truly unexpected
|
|
226
|
+
structlogger.exception(
|
|
227
|
+
"update_files_job.unexpected_error",
|
|
228
|
+
job_id=job.id,
|
|
229
|
+
error=str(exc),
|
|
230
|
+
)
|
|
231
|
+
await push_job_status_event(job, JobStatus.error, message=str(exc))
|
|
232
|
+
job_manager.mark_done(job, error=str(exc))
|
rasa/builder/llm_service.py
CHANGED
|
@@ -13,8 +13,10 @@ import structlog
|
|
|
13
13
|
from jinja2 import Template
|
|
14
14
|
|
|
15
15
|
from rasa.builder import config
|
|
16
|
-
from rasa.builder.copilot import Copilot
|
|
16
|
+
from rasa.builder.copilot.copilot import Copilot
|
|
17
|
+
from rasa.builder.copilot.copilot_response_handler import CopilotResponseHandler
|
|
17
18
|
from rasa.builder.exceptions import LLMGenerationError
|
|
19
|
+
from rasa.builder.guardrails.lakera import LakeraAIGuardrails
|
|
18
20
|
from rasa.constants import PACKAGE_NAME
|
|
19
21
|
from rasa.shared.constants import DOMAIN_SCHEMA_FILE, RESPONSES_SCHEMA_FILE
|
|
20
22
|
from rasa.shared.core.flows.yaml_flows_io import FLOWS_SCHEMA_FILE
|
|
@@ -31,10 +33,12 @@ class LLMService:
|
|
|
31
33
|
self._client: Optional[openai.AsyncOpenAI] = None
|
|
32
34
|
self._domain_schema: Optional[Dict[str, Any]] = None
|
|
33
35
|
self._flows_schema: Optional[Dict[str, Any]] = None
|
|
34
|
-
self._copilot = None
|
|
36
|
+
self._copilot: Optional[Copilot] = None
|
|
37
|
+
self._guardrails: Optional[LakeraAIGuardrails] = None
|
|
38
|
+
self._copilot_response_handler: Optional[CopilotResponseHandler] = None
|
|
35
39
|
|
|
36
40
|
@property
|
|
37
|
-
def copilot(self):
|
|
41
|
+
def copilot(self) -> Copilot:
|
|
38
42
|
"""Get or lazy create copilot instance."""
|
|
39
43
|
if self._copilot is None:
|
|
40
44
|
self._copilot = Copilot()
|
|
@@ -49,6 +53,52 @@ class LLMService:
|
|
|
49
53
|
)
|
|
50
54
|
raise
|
|
51
55
|
|
|
56
|
+
@property
|
|
57
|
+
def copilot_response_handler(self) -> CopilotResponseHandler:
|
|
58
|
+
"""Get or lazy create copilot response handler instance."""
|
|
59
|
+
if self._copilot_response_handler is None:
|
|
60
|
+
self._copilot_response_handler = CopilotResponseHandler(
|
|
61
|
+
rolling_buffer_size=config.COPILOT_HANDLER_ROLLING_BUFFER_SIZE,
|
|
62
|
+
)
|
|
63
|
+
try:
|
|
64
|
+
return self._copilot_response_handler
|
|
65
|
+
except Exception as e:
|
|
66
|
+
structlogger.error(
|
|
67
|
+
"llm_service.copilot_response_handler.error",
|
|
68
|
+
event_info=(
|
|
69
|
+
"LLM Service: Error getting copilot response handler instance."
|
|
70
|
+
),
|
|
71
|
+
error=str(e),
|
|
72
|
+
)
|
|
73
|
+
raise
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def guardrails(self) -> LakeraAIGuardrails:
|
|
77
|
+
"""Get or lazy create guardrails instance."""
|
|
78
|
+
if self._guardrails is None:
|
|
79
|
+
self._guardrails = LakeraAIGuardrails()
|
|
80
|
+
try:
|
|
81
|
+
return self._guardrails
|
|
82
|
+
except Exception as e:
|
|
83
|
+
structlogger.error(
|
|
84
|
+
"llm_service.guardrails.error",
|
|
85
|
+
event_info="LLM Service: Error getting guardrails instance.",
|
|
86
|
+
error=str(e),
|
|
87
|
+
)
|
|
88
|
+
raise
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def instantiate_copilot() -> Copilot:
|
|
92
|
+
"""Instantiate a new Copilot instance."""
|
|
93
|
+
return Copilot()
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def instantiate_handler(rolling_buffer_size: int) -> CopilotResponseHandler:
|
|
97
|
+
"""Instantiate a new CopilotResponseHandler instance."""
|
|
98
|
+
return CopilotResponseHandler(
|
|
99
|
+
rolling_buffer_size=rolling_buffer_size,
|
|
100
|
+
)
|
|
101
|
+
|
|
52
102
|
@asynccontextmanager
|
|
53
103
|
async def _get_client(self) -> AsyncGenerator[openai.AsyncOpenAI, None]:
|
|
54
104
|
"""Get or create OpenAI client with proper resource management."""
|
|
@@ -91,7 +141,7 @@ class LLMService:
|
|
|
91
141
|
},
|
|
92
142
|
},
|
|
93
143
|
}
|
|
94
|
-
response = await client.chat.completions.create(
|
|
144
|
+
response = await client.chat.completions.create( # type: ignore
|
|
95
145
|
model=config.OPENAI_MODEL,
|
|
96
146
|
messages=messages,
|
|
97
147
|
temperature=config.OPENAI_TEMPERATURE,
|
|
@@ -135,9 +185,11 @@ def _prepare_domain_schema() -> Dict[str, Any]:
|
|
|
135
185
|
slot_mapping.pop("validation", None)
|
|
136
186
|
|
|
137
187
|
# Add responses schema
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
188
|
+
responses_schema = read_schema_file(RESPONSES_SCHEMA_FILE, PACKAGE_NAME, False)
|
|
189
|
+
if isinstance(responses_schema, dict):
|
|
190
|
+
domain_schema["mapping"]["responses"] = responses_schema["schema;responses"]
|
|
191
|
+
else:
|
|
192
|
+
raise ValueError("Expected responses schema to be a dictionary.")
|
|
141
193
|
|
|
142
194
|
return domain_schema
|
|
143
195
|
|
rasa/builder/logging_utils.py
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
"""Logging utilities for the
|
|
1
|
+
"""Logging and Sentry utilities for the builder service."""
|
|
2
2
|
|
|
3
3
|
import collections
|
|
4
4
|
import logging
|
|
5
5
|
import threading
|
|
6
|
-
|
|
6
|
+
import time
|
|
7
|
+
import uuid
|
|
8
|
+
from typing import Any, Deque, Dict, Mapping, MutableMapping, Optional
|
|
9
|
+
|
|
10
|
+
import sentry_sdk
|
|
11
|
+
import structlog
|
|
12
|
+
from sanic import Request
|
|
7
13
|
|
|
8
14
|
from rasa.builder import config
|
|
15
|
+
from rasa.builder.auth import HEADER_USER_ID
|
|
16
|
+
|
|
17
|
+
structlogger = structlog.get_logger()
|
|
9
18
|
|
|
10
19
|
# Thread-safe deque for collecting recent logs
|
|
11
20
|
_recent_logs: Deque[str] = collections.deque(maxlen=config.MAX_LOG_ENTRIES)
|
|
@@ -13,8 +22,8 @@ _logs_lock = threading.RLock()
|
|
|
13
22
|
|
|
14
23
|
|
|
15
24
|
def collecting_logs_processor(
|
|
16
|
-
logger: Any, log_level: str, event_dict:
|
|
17
|
-
) ->
|
|
25
|
+
logger: Any, log_level: str, event_dict: MutableMapping[str, Any]
|
|
26
|
+
) -> MutableMapping[str, Any]:
|
|
18
27
|
"""Structlog processor that collects recent log entries.
|
|
19
28
|
|
|
20
29
|
This processor is thread-safe and maintains a rolling buffer of recent logs.
|
|
@@ -29,6 +38,22 @@ def collecting_logs_processor(
|
|
|
29
38
|
return event_dict
|
|
30
39
|
|
|
31
40
|
|
|
41
|
+
def attach_request_id_processor(
|
|
42
|
+
logger: Any, log_level: str, event_dict: MutableMapping[str, Any]
|
|
43
|
+
) -> MutableMapping[str, Any]:
|
|
44
|
+
"""Structlog processor that attaches the request id to the event dict.
|
|
45
|
+
|
|
46
|
+
This processor is thread-safe and maintains a rolling buffer of recent logs.
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
request = Request.get_current()
|
|
50
|
+
event_dict["correlation_id"] = request.ctx.correlation_id
|
|
51
|
+
return event_dict
|
|
52
|
+
except Exception:
|
|
53
|
+
# there is no request context, so we don't attach the request id
|
|
54
|
+
return event_dict
|
|
55
|
+
|
|
56
|
+
|
|
32
57
|
def get_recent_logs() -> str:
|
|
33
58
|
"""Get recent log entries as a formatted string.
|
|
34
59
|
|
|
@@ -49,3 +74,136 @@ def get_log_count() -> int:
|
|
|
49
74
|
"""Get the current number of log entries."""
|
|
50
75
|
with _logs_lock:
|
|
51
76
|
return len(_recent_logs)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _sanitize_headers(headers: Mapping[str, str]) -> Dict[str, Any]:
|
|
80
|
+
"""Remove or redact sensitive headers for safe logging and Sentry context."""
|
|
81
|
+
lowered = {k.lower(): v for k, v in headers.items()}
|
|
82
|
+
result: Dict[str, Any] = {}
|
|
83
|
+
# Safe keepers
|
|
84
|
+
if "user-agent" in lowered:
|
|
85
|
+
result["user-agent"] = lowered["user-agent"]
|
|
86
|
+
if HEADER_USER_ID in lowered:
|
|
87
|
+
result[HEADER_USER_ID] = lowered[HEADER_USER_ID]
|
|
88
|
+
# Redact auth info
|
|
89
|
+
if "authorization" in lowered:
|
|
90
|
+
auth_val = lowered["authorization"]
|
|
91
|
+
# Keep only the scheme if present
|
|
92
|
+
scheme = auth_val.split(" ")[0] if auth_val else ""
|
|
93
|
+
result["authorization"] = f"{scheme} <redacted>" if scheme else "present"
|
|
94
|
+
return result
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def ensure_correlation_id_on_request(request: Any) -> str:
|
|
98
|
+
"""Ensure a correlation id exists on the request and return it."""
|
|
99
|
+
if not hasattr(request.ctx, "correlation_id") or not request.ctx.correlation_id:
|
|
100
|
+
request.ctx.correlation_id = uuid.uuid4().hex
|
|
101
|
+
return request.ctx.correlation_id
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def extract_request_context() -> Dict[str, Any]:
|
|
105
|
+
"""Extract safe request context for logging / Sentry."""
|
|
106
|
+
try:
|
|
107
|
+
request = Request.get_current()
|
|
108
|
+
headers = getattr(request, "headers", {}) or {}
|
|
109
|
+
args = getattr(request, "args", {}) or {}
|
|
110
|
+
json_body = getattr(request, "json", None)
|
|
111
|
+
content_length = getattr(request, "content_length", None)
|
|
112
|
+
ctx: Dict[str, Any] = {
|
|
113
|
+
"method": getattr(request, "method", None),
|
|
114
|
+
"path": getattr(request, "path", None),
|
|
115
|
+
"query_args": dict(args) if hasattr(args, "items") else args,
|
|
116
|
+
"remote_addr": getattr(request, "remote_addr", None),
|
|
117
|
+
"content_length": content_length,
|
|
118
|
+
"has_json": json_body is not None,
|
|
119
|
+
"headers": _sanitize_headers(dict(headers)),
|
|
120
|
+
}
|
|
121
|
+
if hasattr(request, "ctx"):
|
|
122
|
+
ctx["correlation_id"] = ensure_correlation_id_on_request(request)
|
|
123
|
+
# Common custom fields if present
|
|
124
|
+
ctx["user_id"] = request.headers.get(HEADER_USER_ID)
|
|
125
|
+
return ctx
|
|
126
|
+
except Exception:
|
|
127
|
+
return {}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def capture_exception_with_context(
|
|
131
|
+
exc: BaseException,
|
|
132
|
+
event_id: str,
|
|
133
|
+
extra: Optional[Dict[str, Any]] = None,
|
|
134
|
+
tags: Optional[Dict[str, str]] = None,
|
|
135
|
+
) -> None:
|
|
136
|
+
"""Capture exception in Sentry and log it with rich context.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
request: Sanic request
|
|
140
|
+
exc: exception instance
|
|
141
|
+
event_id: structlog event id
|
|
142
|
+
extra: additional context to include
|
|
143
|
+
tags: sentry tags to attach
|
|
144
|
+
"""
|
|
145
|
+
request_ctx = extract_request_context()
|
|
146
|
+
if extra is None:
|
|
147
|
+
extra = {}
|
|
148
|
+
# Sentry scope
|
|
149
|
+
try:
|
|
150
|
+
with sentry_sdk.configure_scope() as scope:
|
|
151
|
+
scope.set_tag("service", "bot-builder")
|
|
152
|
+
if tags:
|
|
153
|
+
for k, v in tags.items():
|
|
154
|
+
scope.set_tag(k, v)
|
|
155
|
+
# Flatten some useful fields as tags
|
|
156
|
+
if request_ctx.get("path"):
|
|
157
|
+
scope.set_tag("route", request_ctx["path"])
|
|
158
|
+
if request_ctx.get("method"):
|
|
159
|
+
scope.set_tag("method", request_ctx["method"])
|
|
160
|
+
if request_ctx.get("correlation_id"):
|
|
161
|
+
scope.set_tag("correlation_id", request_ctx["correlation_id"])
|
|
162
|
+
user_id = request_ctx.get("user_id")
|
|
163
|
+
if user_id and hasattr(scope, "set_user"):
|
|
164
|
+
scope.set_user({"id": str(user_id)})
|
|
165
|
+
# Context blocks
|
|
166
|
+
scope.set_context("request", request_ctx)
|
|
167
|
+
if extra:
|
|
168
|
+
scope.set_context("extra", extra)
|
|
169
|
+
sentry_sdk.capture_exception(exc)
|
|
170
|
+
except Exception:
|
|
171
|
+
# Never fail the app because Sentry failed
|
|
172
|
+
pass
|
|
173
|
+
|
|
174
|
+
# Structlog error with merged context (avoid dumping huge payloads)
|
|
175
|
+
structlogger.error(
|
|
176
|
+
event_id,
|
|
177
|
+
error=str(exc),
|
|
178
|
+
**{k: v for k, v in {**request_ctx, **extra}.items() if k not in {"headers"}},
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def log_request_start(request: Any) -> float:
|
|
183
|
+
"""Log request start and return start time."""
|
|
184
|
+
start = time.perf_counter()
|
|
185
|
+
cid = ensure_correlation_id_on_request(request)
|
|
186
|
+
ctx = extract_request_context()
|
|
187
|
+
structlogger.info(
|
|
188
|
+
"request.received",
|
|
189
|
+
method=ctx.get("method"),
|
|
190
|
+
path=ctx.get("path"),
|
|
191
|
+
remote_addr=ctx.get("remote_addr") or "unknown",
|
|
192
|
+
correlation_id=cid,
|
|
193
|
+
user_id=ctx.get("user_id"),
|
|
194
|
+
)
|
|
195
|
+
return start
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def log_request_end(request: Any, response: Any, start: float) -> None:
|
|
199
|
+
"""Log request completion with latency and correlation id."""
|
|
200
|
+
latency_ms = int((time.perf_counter() - start) * 1000)
|
|
201
|
+
cid = ensure_correlation_id_on_request(request)
|
|
202
|
+
structlogger.info(
|
|
203
|
+
"request.completed",
|
|
204
|
+
method=getattr(request, "method", None),
|
|
205
|
+
path=getattr(request, "path", None),
|
|
206
|
+
status=getattr(response, "status", None),
|
|
207
|
+
latency_ms=latency_ms,
|
|
208
|
+
correlation_id=cid,
|
|
209
|
+
)
|
rasa/builder/main.py
CHANGED
|
@@ -11,8 +11,14 @@ from sanic.request import Request
|
|
|
11
11
|
from sanic_openapi import openapi3_blueprint
|
|
12
12
|
|
|
13
13
|
import rasa.core.utils
|
|
14
|
+
import rasa.telemetry
|
|
14
15
|
from rasa.builder import config
|
|
15
|
-
from rasa.builder.logging_utils import
|
|
16
|
+
from rasa.builder.logging_utils import (
|
|
17
|
+
attach_request_id_processor,
|
|
18
|
+
collecting_logs_processor,
|
|
19
|
+
log_request_end,
|
|
20
|
+
log_request_start,
|
|
21
|
+
)
|
|
16
22
|
from rasa.builder.service import bp, setup_project_generator
|
|
17
23
|
from rasa.core.channels.studio_chat import StudioChatInput
|
|
18
24
|
from rasa.server import configure_cors
|
|
@@ -37,7 +43,7 @@ def setup_logging() -> None:
|
|
|
37
43
|
configure_structlog(
|
|
38
44
|
log_level,
|
|
39
45
|
include_time=True,
|
|
40
|
-
additional_processors=[collecting_logs_processor],
|
|
46
|
+
additional_processors=[attach_request_id_processor, collecting_logs_processor],
|
|
41
47
|
)
|
|
42
48
|
|
|
43
49
|
|
|
@@ -52,23 +58,26 @@ def setup_input_channel() -> StudioChatInput:
|
|
|
52
58
|
def setup_middleware(app: Sanic) -> None:
|
|
53
59
|
"""Setup middleware for request/response processing."""
|
|
54
60
|
|
|
55
|
-
@app.middleware("request")
|
|
61
|
+
@app.middleware("request") # type: ignore[misc,no-untyped-call]
|
|
56
62
|
async def log_request(request: Request) -> None:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
method=request.method,
|
|
60
|
-
path=request.path,
|
|
61
|
-
remote_addr=request.remote_addr or "unknown",
|
|
62
|
-
)
|
|
63
|
+
# store start time on request ctx for later latency calculation
|
|
64
|
+
request.ctx._start_time = log_request_start(request)
|
|
63
65
|
|
|
64
|
-
@app.middleware("response")
|
|
66
|
+
@app.middleware("response") # type: ignore[misc,no-untyped-call]
|
|
65
67
|
async def log_response(request: Request, response: HTTPResponse) -> None:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
try:
|
|
69
|
+
start = getattr(request.ctx, "_start_time", None)
|
|
70
|
+
if start is None:
|
|
71
|
+
# If for some reason the request middleware didn't run
|
|
72
|
+
start = log_request_start(request)
|
|
73
|
+
# propagate correlation id for clients
|
|
74
|
+
correlation_id = getattr(request.ctx, "correlation_id", None)
|
|
75
|
+
if correlation_id:
|
|
76
|
+
response.headers["X-Correlation-Id"] = correlation_id
|
|
77
|
+
log_request_end(request, response, start)
|
|
78
|
+
except Exception:
|
|
79
|
+
# avoid breaking response path
|
|
80
|
+
pass
|
|
72
81
|
|
|
73
82
|
|
|
74
83
|
def create_app(project_folder: Optional[str] = None) -> Sanic:
|
|
@@ -116,6 +125,10 @@ def main(project_folder: Optional[str] = None) -> None:
|
|
|
116
125
|
# Setup logging
|
|
117
126
|
setup_logging()
|
|
118
127
|
|
|
128
|
+
# Setup telemetry
|
|
129
|
+
rasa.telemetry.initialize_telemetry()
|
|
130
|
+
rasa.telemetry.initialize_error_reporting(private_mode=False)
|
|
131
|
+
|
|
119
132
|
# Create and configure app
|
|
120
133
|
app = create_app(project_folder)
|
|
121
134
|
register_custom_sanic_error_handler(app)
|