rasa-pro 3.14.0.dev20250825__py3-none-any.whl → 3.14.0.dev20250901__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/builder/README.md +120 -0
- rasa/builder/__init__.py +0 -0
- rasa/builder/auth.py +176 -0
- rasa/builder/config.py +91 -0
- rasa/builder/copilot/__init__.py +0 -0
- rasa/builder/copilot/constants.py +28 -0
- rasa/builder/copilot/copilot.py +376 -0
- rasa/builder/copilot/copilot_response_handler.py +522 -0
- rasa/builder/copilot/copilot_templated_message_provider.py +58 -0
- rasa/builder/copilot/exceptions.py +32 -0
- rasa/builder/copilot/models.py +464 -0
- rasa/builder/copilot/prompts/__init__.py +0 -0
- rasa/builder/copilot/prompts/copilot_system_prompt.jinja2 +771 -0
- rasa/builder/copilot/signing.py +305 -0
- rasa/builder/copilot/telemetry.py +200 -0
- rasa/builder/copilot/templated_messages/__init__.py +0 -0
- rasa/builder/copilot/templated_messages/copilot_internal_messages_templates.yml +16 -0
- rasa/builder/copilot/templated_messages/copilot_templated_responses.yml +38 -0
- rasa/builder/document_retrieval/__init__.py +0 -0
- rasa/builder/document_retrieval/constants.py +15 -0
- rasa/builder/document_retrieval/inkeep-rag-response-schema.json +64 -0
- rasa/builder/document_retrieval/inkeep_document_retrieval.py +238 -0
- rasa/builder/document_retrieval/models.py +62 -0
- rasa/builder/download.py +147 -0
- rasa/builder/exceptions.py +91 -0
- rasa/builder/guardrails/__init__.py +1 -0
- rasa/builder/guardrails/constants.py +9 -0
- rasa/builder/guardrails/exceptions.py +4 -0
- rasa/builder/guardrails/lakera.py +206 -0
- rasa/builder/guardrails/models.py +231 -0
- rasa/builder/guardrails/store.py +238 -0
- rasa/builder/guardrails/utils.py +328 -0
- rasa/builder/job_manager.py +87 -0
- rasa/builder/jobs.py +270 -0
- rasa/builder/llm_service.py +246 -0
- rasa/builder/logging_utils.py +265 -0
- rasa/builder/main.py +258 -0
- rasa/builder/models.py +216 -0
- rasa/builder/project_generator.py +462 -0
- rasa/builder/project_info.py +72 -0
- rasa/builder/scrape_rasa_docs.py +97 -0
- rasa/builder/service.py +1335 -0
- rasa/builder/shared/tracker_context.py +212 -0
- rasa/builder/skill_to_bot_prompt.jinja2 +164 -0
- rasa/builder/training_service.py +124 -0
- rasa/builder/validation_service.py +97 -0
- rasa/cli/project_templates/basic/actions/__init__ +0 -0
- rasa/cli/project_templates/basic/actions/action_human_handoff.py +40 -0
- rasa/cli/project_templates/basic/config.yml +27 -0
- rasa/cli/project_templates/basic/credentials.yml +33 -0
- rasa/cli/project_templates/basic/data/data.md +9 -0
- rasa/cli/project_templates/basic/data/general/feedback.yml +21 -0
- rasa/cli/project_templates/basic/data/general/goodbye.yml +6 -0
- rasa/cli/project_templates/basic/data/general/hello.yml +6 -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/show_faqs.yml +6 -0
- rasa/cli/project_templates/basic/data/system/patterns/pattern_cannot_handle.yml +7 -0
- rasa/cli/project_templates/basic/data/system/patterns/pattern_completed.yml +7 -0
- rasa/cli/project_templates/basic/data/system/patterns/pattern_correction.yml +7 -0
- rasa/cli/project_templates/basic/data/system/patterns/pattern_search.yml +8 -0
- rasa/cli/project_templates/basic/data/system/patterns/pattern_session_start.yml +8 -0
- rasa/cli/project_templates/basic/docs/docs.md +5 -0
- rasa/cli/project_templates/basic/docs/template.txt +28 -0
- rasa/cli/project_templates/basic/domain/domain.md +9 -0
- rasa/cli/project_templates/basic/domain/general/feedback.yml +25 -0
- rasa/cli/project_templates/basic/domain/general/goodbye.yml +9 -0
- rasa/cli/project_templates/basic/domain/general/hello.yml +7 -0
- rasa/cli/project_templates/basic/domain/general/help.yml +21 -0
- rasa/cli/project_templates/basic/domain/general/human_handoff.yml +32 -0
- rasa/cli/project_templates/basic/domain/general/show_faqs.yml +14 -0
- rasa/cli/project_templates/basic/domain/system/patterns/pattern_cannot_handle.yml +5 -0
- rasa/cli/project_templates/basic/domain/system/patterns/pattern_session_start.yml +19 -0
- rasa/cli/project_templates/basic/endpoints.yml +63 -0
- rasa/cli/project_templates/basic/prompts/rephraser_demo_personality_prompt.jinja2 +38 -0
- 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/accounts/action_ask_account.py +47 -0
- rasa/cli/project_templates/finance/actions/accounts/action_check_balance.py +40 -0
- rasa/cli/project_templates/finance/actions/action_session_start.py +74 -0
- rasa/cli/project_templates/finance/actions/cards/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/cards/action_ask_card.py +48 -0
- rasa/cli/project_templates/finance/actions/cards/action_check_card_existence.py +36 -0
- rasa/cli/project_templates/finance/actions/cards/action_update_card_status.py +54 -0
- rasa/cli/project_templates/finance/actions/database.py +277 -0
- rasa/cli/project_templates/finance/actions/transfers/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/transfers/action_add_payee.py +52 -0
- rasa/cli/project_templates/finance/actions/transfers/action_ask_account_from.py +51 -0
- rasa/cli/project_templates/finance/actions/transfers/action_check_payee_existence.py +40 -0
- rasa/cli/project_templates/finance/actions/transfers/action_check_sufficient_funds.py +40 -0
- rasa/cli/project_templates/finance/actions/transfers/action_list_payees.py +46 -0
- rasa/cli/project_templates/finance/actions/transfers/action_process_immediate_payment.py +18 -0
- rasa/cli/project_templates/finance/actions/transfers/action_remove_payee.py +49 -0
- rasa/cli/project_templates/finance/actions/transfers/action_schedule_payment.py +19 -0
- rasa/cli/project_templates/finance/actions/transfers/action_validate_payment_date.py +36 -0
- rasa/cli/project_templates/finance/config.yml +21 -0
- rasa/cli/project_templates/finance/credentials.yml +32 -0
- rasa/cli/project_templates/finance/csvs/accounts.csv +8 -0
- rasa/cli/project_templates/finance/csvs/advisors.csv +7 -0
- rasa/cli/project_templates/finance/csvs/appointments.csv +211 -0
- rasa/cli/project_templates/finance/csvs/branches.csv +10 -0
- rasa/cli/project_templates/finance/csvs/cards.csv +11 -0
- rasa/cli/project_templates/finance/csvs/payees.csv +11 -0
- rasa/cli/project_templates/finance/csvs/transactions.csv +71 -0
- rasa/cli/project_templates/finance/csvs/users.csv +4 -0
- rasa/cli/project_templates/finance/data/accounts/check_balance.yml +10 -0
- rasa/cli/project_templates/finance/data/cards/block_card.yml +66 -0
- rasa/cli/project_templates/finance/data/cards/select_card.yml +12 -0
- 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/general/help.yml +9 -0
- 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/system/patterns/pattern_chitchat.yml +5 -0
- 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/system/patterns/pattern_session_start.yml +8 -0
- rasa/cli/project_templates/finance/data/system/source/accounts.json +51 -0
- rasa/cli/project_templates/finance/data/system/source/advisors.json +44 -0
- rasa/cli/project_templates/finance/data/system/source/appointments.json +1474 -0
- rasa/cli/project_templates/finance/data/system/source/branches.json +47 -0
- rasa/cli/project_templates/finance/data/system/source/cards.json +72 -0
- rasa/cli/project_templates/finance/data/system/source/payees.json +74 -0
- rasa/cli/project_templates/finance/data/system/source/transactions.json +492 -0
- rasa/cli/project_templates/finance/data/system/source/users.json +29 -0
- rasa/cli/project_templates/finance/data/transfers/add_payee.yml +29 -0
- rasa/cli/project_templates/finance/data/transfers/list_payees.yml +5 -0
- rasa/cli/project_templates/finance/data/transfers/remove_payee.yml +21 -0
- rasa/cli/project_templates/finance/data/transfers/transfer_money.yml +67 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/block_card/consequences_of_blocking_card.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/block_card/reasons_to_block_card.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/block_card/recovering_from_card_fraud.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/block_card/tips_for_card_security.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/block_card/what_to_do_if_card_is_lost.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/check_balance/account_balance_security.txt +7 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/check_balance/common_balance_inquiries.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/check_balance/methods_to_check_balance.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/check_balance/understanding_balance_updates.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/check_balance/what_to_do_if_balance_is_incorrect.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/manage_payees/benefits_of_authorised_payees.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/manage_payees/common_issues_with_payees.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/manage_payees/general_payee_information.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/manage_payees/payee_management_tips.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/manage_payees/understanding_payee_types.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/transfer_money/common_transfer_errors.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/transfer_money/fees_for_transfers.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/transfer_money/general_transfer_information.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/transfer_money/security_tips_for_transfers.txt +8 -0
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/transfer_money/transfer_processing_times.txt +8 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part1.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part10.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part11.txt +48 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part12.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part13.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part14.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part15.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part16.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part17.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part18.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part19.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part2.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part20.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part21.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part22.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part23.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part24.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part25.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part26.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part27.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part28.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part29.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part3.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part30.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part31.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part32.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part33.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part34.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part35.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part36.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part37.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part38.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part39.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part4.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part40.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part41.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part42.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part43.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part44.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part45.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part46.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part47.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part48.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part49.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part5.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part50.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part51.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part52.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part53.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part54.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part55.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part56.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part57.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part58.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part59.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part6.txt +47 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part60.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part61.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part7.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part8.txt +50 -0
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part9.txt +47 -0
- rasa/cli/project_templates/finance/domain/accounts/check_balance.yml +11 -0
- rasa/cli/project_templates/finance/domain/cards/block_card.yml +101 -0
- rasa/cli/project_templates/finance/domain/cards/select_card.yml +12 -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/domain/transfers/add_payee.yml +47 -0
- rasa/cli/project_templates/finance/domain/transfers/list_payees.yml +4 -0
- rasa/cli/project_templates/finance/domain/transfers/remove_payee.yml +16 -0
- rasa/cli/project_templates/finance/domain/transfers/transfer_money.yml +79 -0
- rasa/cli/project_templates/finance/endpoints.yml +63 -0
- rasa/cli/project_templates/finance/prompts/rephraser_demo_personality_prompt.jinja2 +19 -0
- rasa/cli/project_templates/telco/actions/__init__.py +0 -0
- rasa/cli/project_templates/telco/actions/billing/__init__.py +0 -0
- rasa/cli/project_templates/telco/actions/billing/actions_billing.py +204 -0
- rasa/cli/project_templates/telco/actions/general/__init__.py +0 -0
- rasa/cli/project_templates/telco/actions/general/action_human_handoff.py +49 -0
- rasa/cli/project_templates/telco/actions/network/__init__.py +0 -0
- rasa/cli/project_templates/telco/actions/network/actions_get_data_from_db.py +48 -0
- rasa/cli/project_templates/telco/actions/network/actions_run_diagnostics.py +28 -0
- rasa/cli/project_templates/telco/actions/network/actions_session_start.py +18 -0
- rasa/cli/project_templates/telco/config.yml +27 -0
- rasa/cli/project_templates/telco/credentials.yml +33 -0
- rasa/cli/project_templates/telco/csvs/billing.csv +19 -0
- rasa/cli/project_templates/telco/csvs/customers.csv +5 -0
- rasa/cli/project_templates/telco/data/billing/flow_understand_bill.yml +45 -0
- rasa/cli/project_templates/telco/data/general/bot_challenge.yml +6 -0
- rasa/cli/project_templates/telco/data/general/feedback.yml +20 -0
- rasa/cli/project_templates/telco/data/general/goodbye.yml +6 -0
- rasa/cli/project_templates/telco/data/general/hello.yml +6 -0
- rasa/cli/project_templates/telco/data/general/human_handoff.yml +16 -0
- rasa/cli/project_templates/telco/data/general/patterns.yml +30 -0
- rasa/cli/project_templates/telco/data/network/flow_reboot_router.yml +8 -0
- rasa/cli/project_templates/telco/data/network/flow_reset_router.yml +7 -0
- rasa/cli/project_templates/telco/data/network/flow_solve_internet_issue.yml +73 -0
- rasa/cli/project_templates/telco/docs/docs.md +5 -0
- rasa/cli/project_templates/telco/docs/network/reset_vs_rboot_router.txt +1 -0
- rasa/cli/project_templates/telco/docs/network/restart_router.txt +6 -0
- rasa/cli/project_templates/telco/docs/network/run_speed_test.txt +6 -0
- rasa/cli/project_templates/telco/domain/billing/domain_undertand_bill.yml +102 -0
- rasa/cli/project_templates/telco/domain/general/bot_challenge.yml +4 -0
- rasa/cli/project_templates/telco/domain/general/feedback.yml +25 -0
- rasa/cli/project_templates/telco/domain/general/goodbye.yml +7 -0
- rasa/cli/project_templates/telco/domain/general/hello.yml +5 -0
- rasa/cli/project_templates/telco/domain/general/human_handoff.yml +29 -0
- rasa/cli/project_templates/telco/domain/general/patterns.yml +33 -0
- rasa/cli/project_templates/telco/domain/network/domain_reboot_router.yml +21 -0
- rasa/cli/project_templates/telco/domain/network/domain_reset_router.yml +12 -0
- rasa/cli/project_templates/telco/domain/network/domain_run_speed_test.yml +25 -0
- rasa/cli/project_templates/telco/domain/network/domain_solve_internet_issue.yml +75 -0
- rasa/cli/project_templates/telco/domain/shared.yml +129 -0
- rasa/cli/project_templates/telco/endpoints.yml +63 -0
- rasa/cli/project_templates/telco/prompts/rephraser_demo_personality_prompt.jinja2 +40 -0
- rasa/cli/project_templates/tutorial/config.yml +2 -1
- rasa/cli/scaffold.py +46 -2
- rasa/core/actions/action.py +0 -1
- rasa/core/channels/inspector/dist/assets/{arc-1ddec37b.js → arc-18042c22.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-18af387c.js → blockDiagram-38ab4fdb-fdd6bcfa.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-250127a3.js → c4Diagram-3d4e48cf-f5ae6786.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-b9b536fc.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-c3388b34.js → classDiagram-70f12bd4-81efba3e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-9c893a82.js → classDiagram-v2-f2320105-3b6b6a92.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-78d2ddcf.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-c111213b.js → createText-2e5e7dd3-31422447.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-812a729d.js → edges-e0da2a9e-518a90db.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-fd5051bc.js → erDiagram-9861fffd-a6d3c25a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-3287ac02.js → flowDb-956e92f1-e048c2be.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-692fb0b2.js → flowDiagram-66a62f08-c7474c91.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-8b09c060.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-008376f1.js → flowchart-elk-definition-4a651766-cb4d8723.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-df330a69.js → ganttDiagram-c361ad54-346636a2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-e03676fb.js → gitGraphDiagram-72cf32ee-7c508874.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-46fad2ba.js → graph-14702d8a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-a484ac55.js → index-3862675e-f18b534b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-a003633f.js → index-4d4bdf3a.js} +231 -231
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-3f9e6ec2.js → infoDiagram-f8f76790-64154b83.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-79f72383.js → journeyDiagram-49397b02-833a5f95.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-aad098e5.js → layout-5a3b2123.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-219ab7ae.js → line-2272a8c7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-2cddbe62.js → linear-35bcf273.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-1d41ed99.js → mindmap-definition-fc14e90a-92dcb0e9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-cc496ee8.js → pieDiagram-8a3498a8-94dbc900.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-84d32884.js → quadrantDiagram-120e2f19-8b7a9c33.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-c0deb984.js → requirementDiagram-deff3bca-6f7eab81.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-b9d7fd62.js → sankeyDiagram-04a897e0-f43e581d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-7d517565.js → sequenceDiagram-704730f1-0bcbefc3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-98ef9b27.js → stateDiagram-587899a1-b8a74083.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-cee70748.js → stateDiagram-v2-d93cdb3a-2070218f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-3f9d1c96.js → styles-6aaf32cf-f1d54e34.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-67471923.js → styles-9a916d00-980de489.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-bd093fb7.js → styles-c10674c1-3c03abde.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-675794e8.js → svgDrawCommon-08f97a94-46ba068f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-0ac67617.js → timeline-definition-85554ec2-901f5e3d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-c018dc37.js → xychartDiagram-e933f94c-acbc628a.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +2 -2
- rasa/core/channels/inspector/index.html +1 -1
- rasa/core/channels/inspector/src/App.tsx +10 -11
- rasa/core/channels/inspector/src/components/DialogueInformation.tsx +12 -3
- rasa/core/channels/studio_chat.py +25 -7
- rasa/core/policies/enterprise_search_policy.py +4 -7
- rasa/core/policies/flows/flow_executor.py +8 -1
- rasa/dialogue_understanding/generator/flow_retrieval.py +10 -9
- rasa/engine/storage/local_model_storage.py +45 -2
- rasa/model_manager/model_api.py +1 -2
- rasa/model_manager/runner_service.py +1 -1
- rasa/model_manager/trainer_service.py +12 -9
- rasa/model_manager/utils.py +1 -29
- rasa/shared/core/domain.py +62 -15
- rasa/shared/core/flows/flow_step.py +7 -1
- rasa/shared/core/flows/steps/call.py +8 -1
- rasa/shared/core/flows/yaml_flows_io.py +16 -8
- rasa/shared/core/slots.py +4 -0
- rasa/shared/importers/importer.py +6 -0
- rasa/shared/importers/utils.py +77 -1
- rasa/studio/upload.py +12 -46
- rasa/telemetry.py +97 -23
- rasa/utils/io.py +27 -9
- rasa/utils/json_utils.py +6 -1
- rasa/utils/log_utils.py +5 -1
- rasa/utils/openapi.py +144 -0
- rasa/validator.py +7 -3
- rasa/version.py +1 -1
- {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250901.dist-info}/METADATA +9 -10
- {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250901.dist-info}/RECORD +347 -73
- rasa/core/channels/inspector/dist/assets/channel-59f6d54b.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-26177ddb.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-29c03f5a.js +0 -1
- {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250901.dist-info}/NOTICE +0 -0
- {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250901.dist-info}/WHEEL +0 -0
- {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250901.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"""Service for handling LLM interactions."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import importlib
|
|
5
|
+
import json
|
|
6
|
+
from contextlib import asynccontextmanager
|
|
7
|
+
from copy import deepcopy
|
|
8
|
+
from typing import Any, AsyncGenerator, Dict, List, Optional
|
|
9
|
+
|
|
10
|
+
import importlib_resources
|
|
11
|
+
import openai
|
|
12
|
+
import structlog
|
|
13
|
+
from jinja2 import Template
|
|
14
|
+
|
|
15
|
+
from rasa.builder import config
|
|
16
|
+
from rasa.builder.copilot.copilot import Copilot
|
|
17
|
+
from rasa.builder.copilot.copilot_response_handler import CopilotResponseHandler
|
|
18
|
+
from rasa.builder.copilot.copilot_templated_message_provider import (
|
|
19
|
+
load_copilot_internal_message_templates,
|
|
20
|
+
)
|
|
21
|
+
from rasa.builder.exceptions import LLMGenerationError
|
|
22
|
+
from rasa.builder.guardrails.lakera import LakeraAIGuardrails
|
|
23
|
+
from rasa.constants import PACKAGE_NAME
|
|
24
|
+
from rasa.shared.constants import DOMAIN_SCHEMA_FILE, RESPONSES_SCHEMA_FILE
|
|
25
|
+
from rasa.shared.core.flows.yaml_flows_io import FLOWS_SCHEMA_FILE
|
|
26
|
+
from rasa.shared.utils.io import read_json_file
|
|
27
|
+
from rasa.shared.utils.yaml import read_schema_file
|
|
28
|
+
|
|
29
|
+
structlogger = structlog.get_logger()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class LLMService:
|
|
33
|
+
"""Handles OpenAI LLM interactions with caching for efficiency."""
|
|
34
|
+
|
|
35
|
+
def __init__(self) -> None:
|
|
36
|
+
self._client: Optional[openai.AsyncOpenAI] = None
|
|
37
|
+
self._domain_schema: Optional[Dict[str, Any]] = None
|
|
38
|
+
self._flows_schema: Optional[Dict[str, Any]] = None
|
|
39
|
+
self._copilot: Optional[Copilot] = None
|
|
40
|
+
self._guardrails: Optional[LakeraAIGuardrails] = None
|
|
41
|
+
self._copilot_response_handler: Optional[CopilotResponseHandler] = None
|
|
42
|
+
self._copilot_internal_message_templates: Optional[Dict[str, str]] = None
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def copilot(self) -> Copilot:
|
|
46
|
+
"""Get or lazy create copilot instance."""
|
|
47
|
+
if self._copilot is None:
|
|
48
|
+
self._copilot = Copilot()
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
return self._copilot
|
|
52
|
+
except Exception as e:
|
|
53
|
+
structlogger.error(
|
|
54
|
+
"llm_service.copilot.error",
|
|
55
|
+
event_info="LLM Service: Error getting copilot instance.",
|
|
56
|
+
error=str(e),
|
|
57
|
+
)
|
|
58
|
+
raise
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def copilot_response_handler(self) -> CopilotResponseHandler:
|
|
62
|
+
"""Get or lazy create copilot response handler instance."""
|
|
63
|
+
if self._copilot_response_handler is None:
|
|
64
|
+
self._copilot_response_handler = CopilotResponseHandler(
|
|
65
|
+
rolling_buffer_size=config.COPILOT_HANDLER_ROLLING_BUFFER_SIZE,
|
|
66
|
+
)
|
|
67
|
+
try:
|
|
68
|
+
return self._copilot_response_handler
|
|
69
|
+
except Exception as e:
|
|
70
|
+
structlogger.error(
|
|
71
|
+
"llm_service.copilot_response_handler.error",
|
|
72
|
+
event_info=(
|
|
73
|
+
"LLM Service: Error getting copilot response handler instance."
|
|
74
|
+
),
|
|
75
|
+
error=str(e),
|
|
76
|
+
)
|
|
77
|
+
raise
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def guardrails(self) -> LakeraAIGuardrails:
|
|
81
|
+
"""Get or lazy create guardrails instance."""
|
|
82
|
+
if self._guardrails is None:
|
|
83
|
+
self._guardrails = LakeraAIGuardrails()
|
|
84
|
+
try:
|
|
85
|
+
return self._guardrails
|
|
86
|
+
except Exception as e:
|
|
87
|
+
structlogger.error(
|
|
88
|
+
"llm_service.guardrails.error",
|
|
89
|
+
event_info="LLM Service: Error getting guardrails instance.",
|
|
90
|
+
error=str(e),
|
|
91
|
+
)
|
|
92
|
+
raise
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def copilot_internal_message_templates(self) -> Dict[str, str]:
|
|
96
|
+
"""Get or lazy load copilot internal message templates."""
|
|
97
|
+
if self._copilot_internal_message_templates is None:
|
|
98
|
+
self._copilot_internal_message_templates = (
|
|
99
|
+
load_copilot_internal_message_templates()
|
|
100
|
+
)
|
|
101
|
+
return self._copilot_internal_message_templates
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def instantiate_copilot() -> Copilot:
|
|
105
|
+
"""Instantiate a new Copilot instance."""
|
|
106
|
+
return Copilot()
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def instantiate_handler(rolling_buffer_size: int) -> CopilotResponseHandler:
|
|
110
|
+
"""Instantiate a new CopilotResponseHandler instance."""
|
|
111
|
+
return CopilotResponseHandler(
|
|
112
|
+
rolling_buffer_size=rolling_buffer_size,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
@asynccontextmanager
|
|
116
|
+
async def _get_client(self) -> AsyncGenerator[openai.AsyncOpenAI, None]:
|
|
117
|
+
"""Get or create OpenAI client with proper resource management."""
|
|
118
|
+
if self._client is None:
|
|
119
|
+
self._client = openai.AsyncOpenAI(timeout=config.OPENAI_TIMEOUT)
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
yield self._client
|
|
123
|
+
except Exception as e:
|
|
124
|
+
structlogger.error("llm.client_error", error=str(e))
|
|
125
|
+
raise
|
|
126
|
+
|
|
127
|
+
def _prepare_schemas(self) -> None:
|
|
128
|
+
"""Prepare and cache schemas for LLM generation."""
|
|
129
|
+
if self._domain_schema is None:
|
|
130
|
+
self._domain_schema = _prepare_domain_schema()
|
|
131
|
+
|
|
132
|
+
if self._flows_schema is None:
|
|
133
|
+
self._flows_schema = _prepare_flows_schema()
|
|
134
|
+
|
|
135
|
+
async def generate_rasa_project(
|
|
136
|
+
self, messages: List[Dict[str, Any]]
|
|
137
|
+
) -> Dict[str, Any]:
|
|
138
|
+
"""Generate Rasa project data using OpenAI."""
|
|
139
|
+
self._prepare_schemas()
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
async with self._get_client() as client:
|
|
143
|
+
response_format = {
|
|
144
|
+
"type": "json_schema",
|
|
145
|
+
"json_schema": {
|
|
146
|
+
"name": "rasa_project",
|
|
147
|
+
"schema": {
|
|
148
|
+
"type": "object",
|
|
149
|
+
"properties": {
|
|
150
|
+
"domain": self._domain_schema,
|
|
151
|
+
"flows": self._flows_schema,
|
|
152
|
+
},
|
|
153
|
+
"required": ["domain", "flows"],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
response = await client.chat.completions.create( # type: ignore
|
|
158
|
+
model=config.OPENAI_MODEL,
|
|
159
|
+
messages=messages,
|
|
160
|
+
temperature=config.OPENAI_TEMPERATURE,
|
|
161
|
+
response_format=response_format,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
content = response.choices[0].message.content
|
|
165
|
+
if not content:
|
|
166
|
+
raise LLMGenerationError("Empty response from LLM")
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
return json.loads(content)
|
|
170
|
+
except json.JSONDecodeError as e:
|
|
171
|
+
raise LLMGenerationError(f"Invalid JSON from LLM: {e}")
|
|
172
|
+
|
|
173
|
+
except openai.OpenAIError as e:
|
|
174
|
+
raise LLMGenerationError(f"OpenAI API error: {e}")
|
|
175
|
+
except asyncio.TimeoutError:
|
|
176
|
+
raise LLMGenerationError("LLM request timed out")
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# Schema preparation functions (stateless)
|
|
180
|
+
def _prepare_domain_schema() -> Dict[str, Any]:
|
|
181
|
+
"""Prepare domain schema by removing unnecessary parts."""
|
|
182
|
+
domain_schema = deepcopy(read_schema_file(DOMAIN_SCHEMA_FILE, PACKAGE_NAME, False))
|
|
183
|
+
|
|
184
|
+
if not isinstance(domain_schema, dict):
|
|
185
|
+
raise ValueError("Domain schema is not a dictionary")
|
|
186
|
+
|
|
187
|
+
# Remove parts not needed for CALM bots
|
|
188
|
+
unnecessary_keys = ["intents", "entities", "forms", "config", "session_config"]
|
|
189
|
+
|
|
190
|
+
for key in unnecessary_keys:
|
|
191
|
+
domain_schema["mapping"].pop(key, None)
|
|
192
|
+
|
|
193
|
+
# Remove problematic slot mappings
|
|
194
|
+
slot_mapping = domain_schema["mapping"]["slots"]["mapping"]["regex;([A-Za-z]+)"][
|
|
195
|
+
"mapping"
|
|
196
|
+
]
|
|
197
|
+
slot_mapping.pop("mappings", None)
|
|
198
|
+
slot_mapping.pop("validation", None)
|
|
199
|
+
|
|
200
|
+
# Add responses schema
|
|
201
|
+
responses_schema = read_schema_file(RESPONSES_SCHEMA_FILE, PACKAGE_NAME, False)
|
|
202
|
+
if isinstance(responses_schema, dict):
|
|
203
|
+
domain_schema["mapping"]["responses"] = responses_schema["schema;responses"]
|
|
204
|
+
else:
|
|
205
|
+
raise ValueError("Expected responses schema to be a dictionary.")
|
|
206
|
+
|
|
207
|
+
return domain_schema
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _prepare_flows_schema() -> Dict[str, Any]:
|
|
211
|
+
"""Prepare flows schema by removing nlu_trigger."""
|
|
212
|
+
schema_file = str(
|
|
213
|
+
importlib_resources.files(PACKAGE_NAME).joinpath(FLOWS_SCHEMA_FILE)
|
|
214
|
+
)
|
|
215
|
+
flows_schema = deepcopy(read_json_file(schema_file))
|
|
216
|
+
flows_schema["$defs"]["flow"]["properties"].pop("nlu_trigger", None)
|
|
217
|
+
return flows_schema
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
# Template functions (stateless with caching)
|
|
221
|
+
_skill_template: Optional[Template] = None
|
|
222
|
+
_helper_template: Optional[Template] = None
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def get_skill_generation_messages(
|
|
226
|
+
skill_description: str, project_data: Dict[str, str]
|
|
227
|
+
) -> List[Dict[str, Any]]:
|
|
228
|
+
"""Get messages for skill generation."""
|
|
229
|
+
global _skill_template
|
|
230
|
+
|
|
231
|
+
if _skill_template is None:
|
|
232
|
+
template_content = importlib.resources.read_text(
|
|
233
|
+
"rasa.builder",
|
|
234
|
+
"skill_to_bot_prompt.jinja2",
|
|
235
|
+
)
|
|
236
|
+
_skill_template = Template(template_content)
|
|
237
|
+
|
|
238
|
+
system_prompt = _skill_template.render(
|
|
239
|
+
skill_description=skill_description,
|
|
240
|
+
project_data=project_data,
|
|
241
|
+
)
|
|
242
|
+
return [{"role": "system", "content": system_prompt}]
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# Global service instance
|
|
246
|
+
llm_service = LLMService()
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"""Logging and Sentry utilities for the builder service."""
|
|
2
|
+
|
|
3
|
+
import collections
|
|
4
|
+
import logging
|
|
5
|
+
import threading
|
|
6
|
+
import time
|
|
7
|
+
import uuid
|
|
8
|
+
from contextlib import contextmanager
|
|
9
|
+
from typing import Any, Deque, Dict, Generator, List, Mapping, MutableMapping, Optional
|
|
10
|
+
|
|
11
|
+
import sentry_sdk
|
|
12
|
+
import structlog
|
|
13
|
+
from sanic import Request
|
|
14
|
+
|
|
15
|
+
from rasa.builder import config
|
|
16
|
+
from rasa.builder.auth import HEADER_USER_ID
|
|
17
|
+
|
|
18
|
+
structlogger = structlog.get_logger()
|
|
19
|
+
|
|
20
|
+
# Thread-safe deque for collecting recent logs
|
|
21
|
+
_recent_logs: Deque[str] = collections.deque(maxlen=config.MAX_LOG_ENTRIES)
|
|
22
|
+
_logs_lock = threading.RLock()
|
|
23
|
+
# Thread-local storage for validation logs
|
|
24
|
+
_validation_logs = threading.local()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def collecting_logs_processor(
|
|
28
|
+
logger: Any, log_level: str, event_dict: MutableMapping[str, Any]
|
|
29
|
+
) -> MutableMapping[str, Any]:
|
|
30
|
+
"""Structlog processor that collects recent log entries.
|
|
31
|
+
|
|
32
|
+
This processor is thread-safe and maintains a rolling buffer of recent logs.
|
|
33
|
+
"""
|
|
34
|
+
if log_level != logging.getLevelName(logging.DEBUG).lower():
|
|
35
|
+
event_message = event_dict.get("event_info") or event_dict.get("event", "")
|
|
36
|
+
log_entry = f"[{log_level}] {event_message}"
|
|
37
|
+
|
|
38
|
+
with _logs_lock:
|
|
39
|
+
_recent_logs.append(log_entry)
|
|
40
|
+
|
|
41
|
+
return event_dict
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def collecting_validation_logs_processor(
|
|
45
|
+
logger: Any, method_name: str, event_dict: Dict[str, Any]
|
|
46
|
+
) -> Dict[str, Any]:
|
|
47
|
+
"""Structlog processor that captures validation logs in thread-local storage.
|
|
48
|
+
|
|
49
|
+
It's designed to be used with the capture_validation_logs context manager.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
logger: The structlog logger instance
|
|
53
|
+
method_name: The logging method name (e.g., "error", "warning", "info", "debug")
|
|
54
|
+
event_dict: The event dictionary containing log data
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
The unmodified event_dict (this processor doesn't modify the log data)
|
|
58
|
+
"""
|
|
59
|
+
# Only capture logs if we're in a validation context
|
|
60
|
+
# (logs list exists for this thread)
|
|
61
|
+
if hasattr(_validation_logs, "logs"):
|
|
62
|
+
log_entry = {"log_level": method_name, **event_dict}
|
|
63
|
+
_validation_logs.logs.append(log_entry)
|
|
64
|
+
|
|
65
|
+
return event_dict
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@contextmanager
|
|
69
|
+
def capture_validation_logs() -> Generator[List[Dict[str, Any]], Any, None]:
|
|
70
|
+
"""Context manager to capture validation logs using thread-local storage.
|
|
71
|
+
|
|
72
|
+
This context manager temporarily reconfigures structlog to capture all logs
|
|
73
|
+
during validation and stores them in thread-local storage. It's thread-safe
|
|
74
|
+
and automatically cleans up after use.
|
|
75
|
+
|
|
76
|
+
Yields:
|
|
77
|
+
A list of captured log entries, each containing the log level and all
|
|
78
|
+
original log data from the event_dict.
|
|
79
|
+
"""
|
|
80
|
+
# Temporarily reconfigure structlog to add our capture processor
|
|
81
|
+
original_processors = structlog.get_config()["processors"]
|
|
82
|
+
new_processors = [collecting_validation_logs_processor] + original_processors
|
|
83
|
+
structlog.configure(processors=new_processors)
|
|
84
|
+
|
|
85
|
+
# Initialize thread-local logs storage
|
|
86
|
+
_validation_logs.logs = []
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
yield _validation_logs.logs
|
|
90
|
+
finally:
|
|
91
|
+
# Restore original configuration and clean up thread-local storage
|
|
92
|
+
structlog.configure(processors=original_processors)
|
|
93
|
+
if hasattr(_validation_logs, "logs"):
|
|
94
|
+
delattr(_validation_logs, "logs")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def attach_request_id_processor(
|
|
98
|
+
logger: Any, log_level: str, event_dict: MutableMapping[str, Any]
|
|
99
|
+
) -> MutableMapping[str, Any]:
|
|
100
|
+
"""Structlog processor that attaches the request id to the event dict.
|
|
101
|
+
|
|
102
|
+
This processor is thread-safe and maintains a rolling buffer of recent logs.
|
|
103
|
+
"""
|
|
104
|
+
try:
|
|
105
|
+
request = Request.get_current()
|
|
106
|
+
event_dict["correlation_id"] = request.ctx.correlation_id
|
|
107
|
+
return event_dict
|
|
108
|
+
except Exception:
|
|
109
|
+
# there is no request context, so we don't attach the request id
|
|
110
|
+
return event_dict
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def get_recent_logs() -> str:
|
|
114
|
+
"""Get recent log entries as a formatted string.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Formatted string of recent log entries, one per line.
|
|
118
|
+
"""
|
|
119
|
+
with _logs_lock:
|
|
120
|
+
return "\n".join(list(_recent_logs))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def clear_recent_logs() -> None:
|
|
124
|
+
"""Clear the recent logs buffer."""
|
|
125
|
+
with _logs_lock:
|
|
126
|
+
_recent_logs.clear()
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_log_count() -> int:
|
|
130
|
+
"""Get the current number of log entries."""
|
|
131
|
+
with _logs_lock:
|
|
132
|
+
return len(_recent_logs)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _sanitize_headers(headers: Mapping[str, str]) -> Dict[str, Any]:
|
|
136
|
+
"""Remove or redact sensitive headers for safe logging and Sentry context."""
|
|
137
|
+
lowered = {k.lower(): v for k, v in headers.items()}
|
|
138
|
+
result: Dict[str, Any] = {}
|
|
139
|
+
# Safe keepers
|
|
140
|
+
if "user-agent" in lowered:
|
|
141
|
+
result["user-agent"] = lowered["user-agent"]
|
|
142
|
+
if HEADER_USER_ID in lowered:
|
|
143
|
+
result[HEADER_USER_ID] = lowered[HEADER_USER_ID]
|
|
144
|
+
# Redact auth info
|
|
145
|
+
if "authorization" in lowered:
|
|
146
|
+
auth_val = lowered["authorization"]
|
|
147
|
+
# Keep only the scheme if present
|
|
148
|
+
scheme = auth_val.split(" ")[0] if auth_val else ""
|
|
149
|
+
result["authorization"] = f"{scheme} <redacted>" if scheme else "present"
|
|
150
|
+
return result
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def ensure_correlation_id_on_request(request: Any) -> str:
|
|
154
|
+
"""Ensure a correlation id exists on the request and return it."""
|
|
155
|
+
if not hasattr(request.ctx, "correlation_id") or not request.ctx.correlation_id:
|
|
156
|
+
request.ctx.correlation_id = uuid.uuid4().hex
|
|
157
|
+
return request.ctx.correlation_id
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def extract_request_context() -> Dict[str, Any]:
|
|
161
|
+
"""Extract safe request context for logging / Sentry."""
|
|
162
|
+
try:
|
|
163
|
+
request = Request.get_current()
|
|
164
|
+
headers = getattr(request, "headers", {}) or {}
|
|
165
|
+
args = getattr(request, "args", {}) or {}
|
|
166
|
+
json_body = getattr(request, "json", None)
|
|
167
|
+
content_length = getattr(request, "content_length", None)
|
|
168
|
+
ctx: Dict[str, Any] = {
|
|
169
|
+
"method": getattr(request, "method", None),
|
|
170
|
+
"path": getattr(request, "path", None),
|
|
171
|
+
"query_args": dict(args) if hasattr(args, "items") else args,
|
|
172
|
+
"remote_addr": getattr(request, "remote_addr", None),
|
|
173
|
+
"content_length": content_length,
|
|
174
|
+
"has_json": json_body is not None,
|
|
175
|
+
"headers": _sanitize_headers(dict(headers)),
|
|
176
|
+
}
|
|
177
|
+
if hasattr(request, "ctx"):
|
|
178
|
+
ctx["correlation_id"] = ensure_correlation_id_on_request(request)
|
|
179
|
+
# Common custom fields if present
|
|
180
|
+
ctx["user_id"] = request.headers.get(HEADER_USER_ID)
|
|
181
|
+
return ctx
|
|
182
|
+
except Exception:
|
|
183
|
+
return {}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def capture_exception_with_context(
|
|
187
|
+
exc: BaseException,
|
|
188
|
+
event_id: str,
|
|
189
|
+
extra: Optional[Dict[str, Any]] = None,
|
|
190
|
+
tags: Optional[Dict[str, str]] = None,
|
|
191
|
+
) -> None:
|
|
192
|
+
"""Capture exception in Sentry and log it with rich context.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
request: Sanic request
|
|
196
|
+
exc: exception instance
|
|
197
|
+
event_id: structlog event id
|
|
198
|
+
extra: additional context to include
|
|
199
|
+
tags: sentry tags to attach
|
|
200
|
+
"""
|
|
201
|
+
request_ctx = extract_request_context()
|
|
202
|
+
if extra is None:
|
|
203
|
+
extra = {}
|
|
204
|
+
# Sentry scope
|
|
205
|
+
try:
|
|
206
|
+
with sentry_sdk.configure_scope() as scope:
|
|
207
|
+
scope.set_tag("service", "bot-builder")
|
|
208
|
+
if tags:
|
|
209
|
+
for k, v in tags.items():
|
|
210
|
+
scope.set_tag(k, v)
|
|
211
|
+
# Flatten some useful fields as tags
|
|
212
|
+
if request_ctx.get("path"):
|
|
213
|
+
scope.set_tag("route", request_ctx["path"])
|
|
214
|
+
if request_ctx.get("method"):
|
|
215
|
+
scope.set_tag("method", request_ctx["method"])
|
|
216
|
+
if request_ctx.get("correlation_id"):
|
|
217
|
+
scope.set_tag("correlation_id", request_ctx["correlation_id"])
|
|
218
|
+
user_id = request_ctx.get("user_id")
|
|
219
|
+
if user_id and hasattr(scope, "set_user"):
|
|
220
|
+
scope.set_user({"id": str(user_id)})
|
|
221
|
+
# Context blocks
|
|
222
|
+
scope.set_context("request", request_ctx)
|
|
223
|
+
if extra:
|
|
224
|
+
scope.set_context("extra", extra)
|
|
225
|
+
sentry_sdk.capture_exception(exc)
|
|
226
|
+
except Exception:
|
|
227
|
+
# Never fail the app because Sentry failed
|
|
228
|
+
pass
|
|
229
|
+
|
|
230
|
+
# Structlog error with merged context (avoid dumping huge payloads)
|
|
231
|
+
structlogger.error(
|
|
232
|
+
event_id,
|
|
233
|
+
error=str(exc),
|
|
234
|
+
**{k: v for k, v in {**request_ctx, **extra}.items() if k not in {"headers"}},
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def log_request_start(request: Any) -> float:
|
|
239
|
+
"""Log request start and return start time."""
|
|
240
|
+
start = time.perf_counter()
|
|
241
|
+
cid = ensure_correlation_id_on_request(request)
|
|
242
|
+
ctx = extract_request_context()
|
|
243
|
+
structlogger.info(
|
|
244
|
+
"request.received",
|
|
245
|
+
method=ctx.get("method"),
|
|
246
|
+
path=ctx.get("path"),
|
|
247
|
+
remote_addr=ctx.get("remote_addr") or "unknown",
|
|
248
|
+
correlation_id=cid,
|
|
249
|
+
user_id=ctx.get("user_id"),
|
|
250
|
+
)
|
|
251
|
+
return start
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def log_request_end(request: Any, response: Any, start: float) -> None:
|
|
255
|
+
"""Log request completion with latency and correlation id."""
|
|
256
|
+
latency_ms = int((time.perf_counter() - start) * 1000)
|
|
257
|
+
cid = ensure_correlation_id_on_request(request)
|
|
258
|
+
structlogger.info(
|
|
259
|
+
"request.completed",
|
|
260
|
+
method=getattr(request, "method", None),
|
|
261
|
+
path=getattr(request, "path", None),
|
|
262
|
+
status=getattr(response, "status", None),
|
|
263
|
+
latency_ms=latency_ms,
|
|
264
|
+
correlation_id=cid,
|
|
265
|
+
)
|