rasa-pro 3.14.0.dev20250901__py3-none-any.whl → 3.14.0.dev20250922__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/config.py +1 -0
- rasa/builder/copilot/constants.py +3 -0
- rasa/builder/copilot/copilot.py +128 -54
- rasa/builder/copilot/models.py +39 -3
- rasa/builder/copilot/prompts/copilot_system_prompt.jinja2 +183 -188
- rasa/builder/copilot/prompts/latest_user_message_context_prompt.jinja2 +61 -0
- rasa/builder/copilot/telemetry.py +46 -20
- rasa/builder/document_retrieval/models.py +3 -3
- rasa/builder/download.py +1 -8
- rasa/builder/jobs.py +33 -21
- rasa/builder/main.py +38 -62
- rasa/builder/models.py +7 -7
- rasa/builder/project_generator.py +143 -147
- rasa/builder/service.py +42 -27
- rasa/builder/template_cache.py +69 -0
- rasa/builder/training_service.py +74 -4
- rasa/cli/project_templates/basic/README.md +23 -0
- rasa/cli/project_templates/basic/actions/actions.md +10 -0
- rasa/cli/project_templates/basic/config.yml +6 -4
- rasa/cli/project_templates/basic/data/data.md +5 -6
- rasa/cli/project_templates/basic/domain/domain.md +7 -5
- rasa/cli/project_templates/basic/domain/general/show_faqs.yml +1 -1
- rasa/cli/project_templates/basic/endpoints.yml +5 -1
- rasa/cli/project_templates/default/config.yml +4 -0
- rasa/cli/project_templates/default/endpoints.yml +4 -0
- rasa/cli/project_templates/finance/README.md +26 -0
- rasa/cli/project_templates/finance/actions/__init__.py +0 -46
- rasa/cli/project_templates/finance/actions/accounts/check_balance.py +18 -0
- rasa/cli/project_templates/finance/actions/actions.md +15 -0
- rasa/cli/project_templates/finance/actions/{transfers/action_process_immediate_payment.py → cards/check_that_card_exists.py} +6 -3
- rasa/cli/project_templates/finance/actions/cards/list_cards.py +22 -0
- rasa/cli/project_templates/finance/actions/contacts/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/contacts/add_contact.py +30 -0
- rasa/cli/project_templates/finance/actions/contacts/list_contacts.py +22 -0
- rasa/cli/project_templates/finance/actions/contacts/remove_contact.py +35 -0
- rasa/cli/project_templates/finance/actions/db.py +117 -0
- rasa/cli/project_templates/finance/actions/general/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/general/action_human_handoff.py +49 -0
- rasa/cli/project_templates/finance/actions/transfers/check_transfer_funds.py +27 -0
- rasa/cli/project_templates/finance/actions/transfers/check_transfer_limit.py +36 -0
- rasa/cli/project_templates/finance/actions/transfers/execute_recurrent_payment.py +20 -0
- rasa/cli/project_templates/finance/actions/transfers/execute_transfer.py +45 -0
- rasa/cli/project_templates/finance/actions/transfers/list_transactions.py +32 -0
- rasa/cli/project_templates/finance/config.yml +8 -0
- rasa/cli/project_templates/finance/credentials.yml +7 -6
- rasa/cli/project_templates/finance/data/accounts/check_balance.yml +3 -4
- rasa/cli/project_templates/finance/data/accounts/download_statements.yml +26 -0
- rasa/cli/project_templates/finance/data/bills/bill_pay_reminder.yml +25 -0
- rasa/cli/project_templates/finance/data/cards/activate_card.yml +35 -0
- rasa/cli/project_templates/finance/data/cards/block_card.yml +37 -58
- rasa/cli/project_templates/finance/data/cards/list_cards.yml +14 -0
- rasa/cli/project_templates/finance/data/cards/replace_card.yml +16 -0
- rasa/cli/project_templates/finance/data/cards/replace_eligible_card.yml +29 -0
- rasa/cli/project_templates/finance/data/contacts/add_contact.yml +33 -0
- rasa/cli/project_templates/finance/data/contacts/list_contacts.yml +14 -0
- rasa/cli/project_templates/finance/data/contacts/remove_contact.yml +31 -0
- rasa/cli/project_templates/finance/data/data.md +14 -0
- rasa/cli/project_templates/finance/data/general/bot_challenge.yml +6 -0
- rasa/cli/project_templates/finance/data/general/goodbye.yml +1 -1
- rasa/cli/project_templates/finance/data/general/hello.yml +1 -2
- rasa/cli/project_templates/finance/data/general/help.yml +2 -2
- rasa/cli/project_templates/finance/data/general/human_handoff.yml +2 -2
- rasa/cli/project_templates/finance/data/system/patterns/pattern_session_start.yml +1 -1
- rasa/cli/project_templates/finance/data/transfers/check_transfer_limit.yml +18 -0
- rasa/cli/project_templates/finance/data/transfers/list_transactions.yml +46 -0
- rasa/cli/project_templates/finance/data/transfers/move_money_between_accounts.yml +51 -0
- rasa/cli/project_templates/finance/data/transfers/transfer_money.yml +29 -62
- rasa/cli/project_templates/finance/data/transfers/transfer_money_to_a_third_party.yml +175 -0
- rasa/cli/project_templates/finance/db/cards.json +18 -0
- rasa/cli/project_templates/finance/db/contacts.json +10 -0
- rasa/cli/project_templates/finance/db/my_account.json +6 -0
- rasa/cli/project_templates/finance/db/transactions.json +22 -0
- rasa/cli/project_templates/finance/docs/docs.md +8 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/budgeting_analytics.txt +22 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/multi_currency_accounts.txt +19 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/premium_benefits.txt +19 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/contactless_limits.txt +16 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/freeze_unfreeze_card.txt +16 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/lost_stolen_card.txt +19 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/money_transfers/instant_payments.txt +19 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/money_transfers/international_transfers.txt +19 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/security_fraud/fraud_protection.txt +22 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/security_fraud/secure_payments.txt +22 -0
- rasa/cli/project_templates/finance/domain/accounts/check_balance.yml +9 -5
- rasa/cli/project_templates/finance/domain/accounts/download_statements.yml +40 -0
- rasa/cli/project_templates/finance/domain/bills/bill_pay_reminder.yml +49 -0
- rasa/cli/project_templates/finance/domain/cards/activate_card.yml +24 -0
- rasa/cli/project_templates/finance/domain/cards/block_card.yml +33 -90
- rasa/cli/project_templates/finance/domain/cards/list_cards.yml +16 -0
- rasa/cli/project_templates/finance/domain/cards/replace_card.yml +43 -0
- rasa/cli/project_templates/finance/domain/cards/shared.yml +15 -0
- rasa/cli/project_templates/finance/domain/contacts/add_contact.yml +37 -0
- rasa/cli/project_templates/finance/domain/contacts/list_contacts.yml +16 -0
- rasa/cli/project_templates/finance/domain/contacts/remove_contact.yml +32 -0
- rasa/cli/project_templates/finance/domain/domain.md +18 -0
- rasa/cli/project_templates/finance/domain/general/_shared.yml +39 -0
- rasa/cli/project_templates/finance/domain/general/bot_challenge.yml +4 -0
- rasa/cli/project_templates/finance/domain/general/cannot_handle.yml +5 -2
- rasa/cli/project_templates/finance/domain/general/feedback.yml +0 -3
- rasa/cli/project_templates/finance/domain/general/goodbye.yml +6 -6
- rasa/cli/project_templates/finance/domain/general/human_handoff.yml +10 -9
- rasa/cli/project_templates/finance/domain/general/welcome.yml +33 -2
- rasa/cli/project_templates/finance/domain/transfers/check_transfer_limit.yml +32 -0
- rasa/cli/project_templates/finance/domain/transfers/list_transactions.yml +44 -0
- rasa/cli/project_templates/finance/domain/transfers/shared.yml +17 -0
- rasa/cli/project_templates/finance/domain/transfers/transfer_money.yml +203 -61
- rasa/cli/project_templates/finance/endpoints.yml +8 -4
- rasa/cli/project_templates/finance/prompts/rephraser_demo_personality_prompt.jinja2 +31 -12
- rasa/cli/project_templates/finance/tests/e2e_test_cases/accounts/check_balance.yml +9 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/accounts/download_statements.yml +43 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/cards/block_card.yml +55 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/bot_challenge.yml +8 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/feedback.yml +46 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/goodbye.yml +9 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/hello.yml +8 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/human_handoff.yml +35 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/patterns.yml +22 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/transfers/transfer_money.yml +56 -0
- rasa/cli/project_templates/telco/README.md +25 -0
- rasa/cli/project_templates/telco/actions/actions.md +12 -0
- rasa/cli/project_templates/telco/config.yml +6 -4
- rasa/cli/project_templates/telco/data/data.md +11 -0
- rasa/cli/project_templates/telco/data/general/human_handoff.yml +1 -1
- rasa/cli/project_templates/telco/docs/docs.md +3 -0
- rasa/cli/project_templates/telco/domain/domain.md +13 -0
- rasa/cli/project_templates/telco/domain/general/human_handoff.yml +3 -6
- rasa/cli/project_templates/telco/endpoints.yml +5 -1
- rasa/cli/project_templates/telco/prompts/rephraser_demo_personality_prompt.jinja2 +1 -1
- rasa/cli/project_templates/telco/tests/e2e_test_cases/billing/understand_bill.yml +67 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/bot_challenge.yml +8 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/feedback.yml +46 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/goodbye.yml +9 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/hello.yml +8 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/human_handoff.yml +35 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/patterns.yml +23 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/network/solve_internet_issue.yml +57 -0
- rasa/core/actions/action_run_slot_rejections.py +1 -1
- rasa/core/actions/direct_custom_actions_executor.py +9 -2
- rasa/core/brokers/broker.py +1 -1
- rasa/core/brokers/kafka.py +52 -8
- rasa/core/channels/development_inspector.py +1 -21
- rasa/core/channels/hangouts.py +2 -2
- rasa/core/channels/inspector/dist/assets/{arc-18042c22.js → arc-35222594.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-fdd6bcfa.js → blockDiagram-38ab4fdb-a0efbfd3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-f5ae6786.js → c4Diagram-3d4e48cf-0584c0f2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-8e08bed9.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-81efba3e.js → classDiagram-70f12bd4-39f40dbe.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-3b6b6a92.js → classDiagram-v2-f2320105-1ad755f3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-78c82dea.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-31422447.js → createText-2e5e7dd3-b0f4f0fe.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-518a90db.js → edges-e0da2a9e-9039bff9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-a6d3c25a.js → erDiagram-9861fffd-65c9b127.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-e048c2be.js → flowDb-956e92f1-4f08b38e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-c7474c91.js → flowDiagram-66a62f08-e95c362a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-2b08f601.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-cb4d8723.js → flowchart-elk-definition-4a651766-703c3015.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-346636a2.js → ganttDiagram-c361ad54-699328ea.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-7c508874.js → gitGraphDiagram-72cf32ee-04cf4b05.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-14702d8a.js → graph-ee94449e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-f18b534b.js → index-3862675e-940162b4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-4d4bdf3a.js → index-c941dcb3.js} +132 -131
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-64154b83.js → infoDiagram-f8f76790-c79c2866.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-833a5f95.js → journeyDiagram-49397b02-84489d30.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-5a3b2123.js → layout-a9aa9858.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-2272a8c7.js → line-eb73cf26.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-35bcf273.js → linear-b3399f9a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-92dcb0e9.js → mindmap-definition-fc14e90a-b095bf1a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-94dbc900.js → pieDiagram-8a3498a8-07644b66.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-8b7a9c33.js → quadrantDiagram-120e2f19-573a3f9c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-6f7eab81.js → requirementDiagram-deff3bca-d457e1e1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-f43e581d.js → sankeyDiagram-04a897e0-9d26e1a2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-0bcbefc3.js → sequenceDiagram-704730f1-3a9cde10.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-b8a74083.js → stateDiagram-587899a1-4f3e8cec.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-2070218f.js → stateDiagram-v2-d93cdb3a-e617e5bf.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-f1d54e34.js → styles-6aaf32cf-eab30d2f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-980de489.js → styles-9a916d00-09994be2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-3c03abde.js → styles-c10674c1-b7110364.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-46ba068f.js → svgDrawCommon-08f97a94-3ebc92ad.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-901f5e3d.js → timeline-definition-85554ec2-7d13d2f2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-acbc628a.js → xychartDiagram-e933f94c-488385e1.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/App.tsx +5 -31
- rasa/core/channels/inspector/src/components/Chat.tsx +2 -3
- rasa/core/channels/inspector/src/components/DialogueInformation.tsx +9 -1
- rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +63 -35
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +14 -0
- rasa/core/channels/inspector/src/types.ts +32 -7
- rasa/core/channels/studio_chat.py +23 -41
- rasa/core/channels/voice_stream/asr/asr_event.py +1 -1
- rasa/core/channels/voice_stream/asr/azure.py +6 -3
- rasa/core/channels/voice_stream/asr/deepgram.py +1 -1
- rasa/core/channels/voice_stream/audiocodes.py +3 -0
- rasa/core/channels/voice_stream/browser_audio.py +55 -3
- rasa/core/channels/voice_stream/genesys.py +2 -1
- rasa/core/channels/voice_stream/jambonz.py +9 -1
- rasa/core/channels/voice_stream/twilio_media_streams.py +16 -0
- rasa/core/channels/voice_stream/voice_channel.py +61 -0
- rasa/core/concurrent_lock_store.py +66 -16
- rasa/core/constants.py +7 -0
- rasa/core/iam_credentials_providers/__init__.py +0 -0
- rasa/core/iam_credentials_providers/aws_iam_credentials_providers.py +226 -0
- rasa/core/iam_credentials_providers/credentials_provider_protocol.py +90 -0
- rasa/core/lock_store.py +46 -10
- rasa/core/nlg/generator.py +1 -1
- rasa/core/policies/flows/flow_executor.py +1 -1
- rasa/core/processor.py +32 -0
- rasa/core/redis_connection_factory.py +469 -0
- rasa/core/tracker_stores/redis_tracker_store.py +32 -14
- rasa/core/tracker_stores/sql_tracker_store.py +57 -1
- rasa/engine/graph.py +5 -1
- rasa/engine/loader.py +12 -0
- rasa/engine/storage/local_model_storage.py +41 -4
- rasa/model_manager/socket_bridge.py +1 -2
- rasa/model_manager/warm_rasa_process.py +13 -3
- rasa/shared/core/constants.py +1 -0
- rasa/shared/core/events.py +2 -0
- rasa/shared/core/flows/flow.py +1 -1
- rasa/shared/nlu/training_data/schemas/responses.yml +3 -0
- rasa/utils/pypred.py +38 -0
- rasa/validator.py +12 -8
- rasa/version.py +1 -1
- {rasa_pro-3.14.0.dev20250901.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/METADATA +19 -16
- {rasa_pro-3.14.0.dev20250901.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/RECORD +231 -266
- rasa/cli/project_templates/finance/actions/accounts/action_ask_account.py +0 -47
- rasa/cli/project_templates/finance/actions/accounts/action_check_balance.py +0 -40
- rasa/cli/project_templates/finance/actions/action_session_start.py +0 -74
- rasa/cli/project_templates/finance/actions/cards/action_ask_card.py +0 -48
- rasa/cli/project_templates/finance/actions/cards/action_check_card_existence.py +0 -36
- rasa/cli/project_templates/finance/actions/cards/action_update_card_status.py +0 -54
- rasa/cli/project_templates/finance/actions/database.py +0 -277
- rasa/cli/project_templates/finance/actions/transfers/action_add_payee.py +0 -52
- rasa/cli/project_templates/finance/actions/transfers/action_ask_account_from.py +0 -51
- rasa/cli/project_templates/finance/actions/transfers/action_check_payee_existence.py +0 -40
- rasa/cli/project_templates/finance/actions/transfers/action_check_sufficient_funds.py +0 -40
- rasa/cli/project_templates/finance/actions/transfers/action_list_payees.py +0 -46
- rasa/cli/project_templates/finance/actions/transfers/action_remove_payee.py +0 -49
- rasa/cli/project_templates/finance/actions/transfers/action_schedule_payment.py +0 -19
- rasa/cli/project_templates/finance/actions/transfers/action_validate_payment_date.py +0 -36
- rasa/cli/project_templates/finance/csvs/accounts.csv +0 -8
- rasa/cli/project_templates/finance/csvs/advisors.csv +0 -7
- rasa/cli/project_templates/finance/csvs/appointments.csv +0 -211
- rasa/cli/project_templates/finance/csvs/branches.csv +0 -10
- rasa/cli/project_templates/finance/csvs/cards.csv +0 -11
- rasa/cli/project_templates/finance/csvs/payees.csv +0 -11
- rasa/cli/project_templates/finance/csvs/transactions.csv +0 -71
- rasa/cli/project_templates/finance/csvs/users.csv +0 -4
- rasa/cli/project_templates/finance/data/cards/select_card.yml +0 -12
- rasa/cli/project_templates/finance/data/general/bot_identity.yml +0 -6
- rasa/cli/project_templates/finance/data/system/patterns/pattern_chitchat.yml +0 -5
- rasa/cli/project_templates/finance/data/system/source/accounts.json +0 -51
- rasa/cli/project_templates/finance/data/system/source/advisors.json +0 -44
- rasa/cli/project_templates/finance/data/system/source/appointments.json +0 -1474
- rasa/cli/project_templates/finance/data/system/source/branches.json +0 -47
- rasa/cli/project_templates/finance/data/system/source/cards.json +0 -72
- rasa/cli/project_templates/finance/data/system/source/payees.json +0 -74
- rasa/cli/project_templates/finance/data/system/source/transactions.json +0 -492
- rasa/cli/project_templates/finance/data/system/source/users.json +0 -29
- rasa/cli/project_templates/finance/data/transfers/add_payee.yml +0 -29
- rasa/cli/project_templates/finance/data/transfers/list_payees.yml +0 -5
- rasa/cli/project_templates/finance/data/transfers/remove_payee.yml +0 -21
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/block_card/consequences_of_blocking_card.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/block_card/reasons_to_block_card.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/block_card/recovering_from_card_fraud.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/block_card/tips_for_card_security.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/block_card/what_to_do_if_card_is_lost.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/check_balance/account_balance_security.txt +0 -7
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/check_balance/common_balance_inquiries.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/check_balance/methods_to_check_balance.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/check_balance/understanding_balance_updates.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/check_balance/what_to_do_if_balance_is_incorrect.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/manage_payees/benefits_of_authorised_payees.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/manage_payees/common_issues_with_payees.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/manage_payees/general_payee_information.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/manage_payees/payee_management_tips.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/manage_payees/understanding_payee_types.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/transfer_money/common_transfer_errors.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/transfer_money/fees_for_transfers.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/transfer_money/general_transfer_information.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/transfer_money/security_tips_for_transfers.txt +0 -8
- rasa/cli/project_templates/finance/docs/bank_of_rasa_faq/transfer_money/transfer_processing_times.txt +0 -8
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part1.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part10.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part11.txt +0 -48
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part12.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part13.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part14.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part15.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part16.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part17.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part18.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part19.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part2.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part20.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part21.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part22.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part23.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part24.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part25.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part26.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part27.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part28.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part29.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part3.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part30.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part31.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part32.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part33.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part34.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part35.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part36.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part37.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part38.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part39.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part4.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part40.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part41.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part42.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part43.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part44.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part45.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part46.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part47.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part48.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part49.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part5.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part50.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part51.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part52.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part53.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part54.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part55.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part56.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part57.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part58.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part59.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part6.txt +0 -47
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part60.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part61.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part7.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part8.txt +0 -50
- rasa/cli/project_templates/finance/docs/huggingface_alpaca_dataset/questions_part9.txt +0 -47
- rasa/cli/project_templates/finance/domain/cards/select_card.yml +0 -12
- rasa/cli/project_templates/finance/domain/general/assistant_details.yml +0 -12
- rasa/cli/project_templates/finance/domain/general/bot_identity.yml +0 -5
- rasa/cli/project_templates/finance/domain/general/defaults.yml +0 -24
- rasa/cli/project_templates/finance/domain/general/help.yml +0 -5
- rasa/cli/project_templates/finance/domain/general/utils.yml +0 -13
- rasa/cli/project_templates/finance/domain/transfers/add_payee.yml +0 -47
- rasa/cli/project_templates/finance/domain/transfers/list_payees.yml +0 -4
- rasa/cli/project_templates/finance/domain/transfers/remove_payee.yml +0 -16
- rasa/core/channels/inspector/dist/assets/channel-b9b536fc.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-78d2ddcf.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-8b09c060.js +0 -1
- /rasa/cli/project_templates/telco/domain/billing/{domain_undertand_bill.yml → understand_bill.yml} +0 -0
- /rasa/cli/project_templates/telco/domain/network/{domain_reboot_router.yml → reboot_router.yml} +0 -0
- /rasa/cli/project_templates/telco/domain/network/{domain_reset_router.yml → reset_router.yml} +0 -0
- /rasa/cli/project_templates/telco/domain/network/{domain_run_speed_test.yml → run_speed_test.yml} +0 -0
- /rasa/cli/project_templates/telco/domain/network/{domain_solve_internet_issue.yml → solve_internet_issue.yml} +0 -0
- {rasa_pro-3.14.0.dev20250901.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/NOTICE +0 -0
- {rasa_pro-3.14.0.dev20250901.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/WHEEL +0 -0
- {rasa_pro-3.14.0.dev20250901.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/entry_points.txt +0 -0
|
@@ -99,10 +99,11 @@ class GenesysInputChannel(VoiceInputChannel):
|
|
|
99
99
|
server_url: str,
|
|
100
100
|
asr_config: Dict,
|
|
101
101
|
tts_config: Dict,
|
|
102
|
+
interruptions: Optional[Dict[str, int]] = None,
|
|
102
103
|
api_key: Optional[Text] = None,
|
|
103
104
|
client_secret: Optional[Text] = None,
|
|
104
105
|
) -> None:
|
|
105
|
-
super().__init__(server_url, asr_config, tts_config)
|
|
106
|
+
super().__init__(server_url, asr_config, tts_config, interruptions)
|
|
106
107
|
self.api_key = api_key
|
|
107
108
|
self.client_secret = client_secret
|
|
108
109
|
|
|
@@ -81,6 +81,7 @@ class JambonzStreamInputChannel(VoiceInputChannel):
|
|
|
81
81
|
server_url: str,
|
|
82
82
|
asr_config: Dict,
|
|
83
83
|
tts_config: Dict,
|
|
84
|
+
interruptions: Optional[Dict[str, int]] = None,
|
|
84
85
|
username: Optional[Text] = None,
|
|
85
86
|
password: Optional[Text] = None,
|
|
86
87
|
) -> None:
|
|
@@ -90,7 +91,7 @@ class JambonzStreamInputChannel(VoiceInputChannel):
|
|
|
90
91
|
username: Optional username for basic auth
|
|
91
92
|
password: Optional password for basic auth
|
|
92
93
|
"""
|
|
93
|
-
super().__init__(server_url, asr_config, tts_config)
|
|
94
|
+
super().__init__(server_url, asr_config, tts_config, interruptions)
|
|
94
95
|
self.username = username
|
|
95
96
|
self.password = password
|
|
96
97
|
|
|
@@ -185,6 +186,13 @@ class JambonzStreamInputChannel(VoiceInputChannel):
|
|
|
185
186
|
self.tts_cache,
|
|
186
187
|
)
|
|
187
188
|
|
|
189
|
+
async def interrupt_playback(
|
|
190
|
+
self, ws: Websocket, call_parameters: CallParameters
|
|
191
|
+
) -> None:
|
|
192
|
+
"""Interrupt the current playback of audio."""
|
|
193
|
+
logger.debug("jambonz.interrupt_playback")
|
|
194
|
+
await ws.send(json.dumps({"type": "killAudio"}))
|
|
195
|
+
|
|
188
196
|
def blueprint(
|
|
189
197
|
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
190
198
|
) -> Blueprint:
|
|
@@ -105,6 +105,7 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
105
105
|
server_url: str,
|
|
106
106
|
asr_config: Dict,
|
|
107
107
|
tts_config: Dict,
|
|
108
|
+
interruptions: Optional[Dict[str, int]] = None,
|
|
108
109
|
username: Optional[Text] = None,
|
|
109
110
|
password: Optional[Text] = None,
|
|
110
111
|
):
|
|
@@ -112,6 +113,7 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
112
113
|
server_url=server_url,
|
|
113
114
|
asr_config=asr_config,
|
|
114
115
|
tts_config=tts_config,
|
|
116
|
+
interruptions=interruptions,
|
|
115
117
|
)
|
|
116
118
|
self.username = username
|
|
117
119
|
self.password = password
|
|
@@ -195,6 +197,20 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
195
197
|
self.tts_cache,
|
|
196
198
|
)
|
|
197
199
|
|
|
200
|
+
async def interrupt_playback(
|
|
201
|
+
self, ws: Websocket, call_parameters: CallParameters
|
|
202
|
+
) -> None:
|
|
203
|
+
"""Interrupt the current playback of audio."""
|
|
204
|
+
logger.debug("twilio_media_streams.interrupt_playback")
|
|
205
|
+
await ws.send(
|
|
206
|
+
json.dumps(
|
|
207
|
+
{
|
|
208
|
+
"event": "clear",
|
|
209
|
+
"streamSid": call_parameters.stream_id,
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
|
|
198
214
|
def blueprint(
|
|
199
215
|
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
200
216
|
) -> Blueprint:
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import copy
|
|
5
|
+
import string
|
|
5
6
|
import time
|
|
6
7
|
from dataclasses import asdict, dataclass
|
|
7
8
|
from typing import Any, AsyncIterator, Awaitable, Callable, Dict, List, Optional, Tuple
|
|
@@ -53,6 +54,13 @@ from rasa.utils.io import remove_emojis
|
|
|
53
54
|
logger = structlog.get_logger(__name__)
|
|
54
55
|
|
|
55
56
|
# define constants for the voice channel
|
|
57
|
+
DEFAULT_INTERRUPTION_MIN_WORDS = 3
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class InterruptionConfig:
|
|
62
|
+
enabled: bool = False
|
|
63
|
+
min_words: int = DEFAULT_INTERRUPTION_MIN_WORDS
|
|
56
64
|
|
|
57
65
|
|
|
58
66
|
@dataclass
|
|
@@ -270,6 +278,10 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
270
278
|
except (WebsocketClosed, ServerError):
|
|
271
279
|
call_state.connection_failed = True
|
|
272
280
|
|
|
281
|
+
# Is the response interruptible?
|
|
282
|
+
allow_interruptions = kwargs.get("allow_interruptions", True)
|
|
283
|
+
call_state.channel_data["allow_interruptions"] = allow_interruptions
|
|
284
|
+
|
|
273
285
|
if cached_audio_bytes:
|
|
274
286
|
audio_stream = self.chunk_audio(cached_audio_bytes)
|
|
275
287
|
else:
|
|
@@ -368,6 +380,7 @@ class VoiceInputChannel(InputChannel):
|
|
|
368
380
|
server_url: str,
|
|
369
381
|
asr_config: Dict,
|
|
370
382
|
tts_config: Dict,
|
|
383
|
+
interruptions: Optional[Dict[str, Any]] = None,
|
|
371
384
|
):
|
|
372
385
|
if self.requires_voice_license:
|
|
373
386
|
validate_voice_license_scope()
|
|
@@ -376,12 +389,21 @@ class VoiceInputChannel(InputChannel):
|
|
|
376
389
|
self.asr_config = asr_config
|
|
377
390
|
self.tts_config = tts_config
|
|
378
391
|
self.tts_cache = TTSCache(tts_config.get("cache_size", 1000))
|
|
392
|
+
if interruptions:
|
|
393
|
+
self.interruption_config = InterruptionConfig(**interruptions)
|
|
394
|
+
else:
|
|
395
|
+
self.interruption_config = InterruptionConfig()
|
|
396
|
+
|
|
397
|
+
if self.interruption_config.enabled:
|
|
398
|
+
mark_as_beta_feature(f"Interruption Handling in {self.name()}")
|
|
379
399
|
|
|
380
400
|
logger.info(
|
|
381
401
|
"voice_channel.initialized",
|
|
402
|
+
name=self.name(),
|
|
382
403
|
server_url=self.server_url,
|
|
383
404
|
asr_config=self.asr_config,
|
|
384
405
|
tts_config=self.tts_config,
|
|
406
|
+
interruption_config=self.interruption_config,
|
|
385
407
|
)
|
|
386
408
|
|
|
387
409
|
def get_sender_id(self, call_parameters: CallParameters) -> str:
|
|
@@ -463,6 +485,43 @@ class VoiceInputChannel(InputChannel):
|
|
|
463
485
|
"""Map a channel input message to a voice channel action."""
|
|
464
486
|
raise NotImplementedError
|
|
465
487
|
|
|
488
|
+
def should_interrupt(self, e: ASREvent) -> bool:
|
|
489
|
+
"""Determine if the current ASR event should interrupt playback.
|
|
490
|
+
Returns True if the bot response is interruptible
|
|
491
|
+
And if the user spoke more than 3 words.
|
|
492
|
+
|
|
493
|
+
Arguments:
|
|
494
|
+
e: The ASR event to evaluate.
|
|
495
|
+
|
|
496
|
+
Returns:
|
|
497
|
+
True if the event should interrupt playback, False otherwise.
|
|
498
|
+
"""
|
|
499
|
+
# Are interruptions are enabled for the channel?
|
|
500
|
+
if not self.interruption_config.enabled:
|
|
501
|
+
return False
|
|
502
|
+
|
|
503
|
+
# Is the bot response interruptible?
|
|
504
|
+
if not call_state.channel_data.get("allow_interruptions", True):
|
|
505
|
+
return False
|
|
506
|
+
|
|
507
|
+
# Did the user speak more than 3 words?
|
|
508
|
+
min_words = self.interruption_config.min_words
|
|
509
|
+
if isinstance(e, UserIsSpeaking):
|
|
510
|
+
translator = str.maketrans("", "", string.punctuation)
|
|
511
|
+
words = e.text.translate(translator).split()
|
|
512
|
+
return len(words) >= min_words
|
|
513
|
+
return False
|
|
514
|
+
|
|
515
|
+
async def interrupt_playback(
|
|
516
|
+
self, ws: Websocket, call_parameters: CallParameters
|
|
517
|
+
) -> None:
|
|
518
|
+
"""Interrupt the current playback of audio.
|
|
519
|
+
|
|
520
|
+
This function is used for interruption handling.
|
|
521
|
+
As not all channels support flushing bot audio buffer,
|
|
522
|
+
if a channel does not implement it. It has no effect."""
|
|
523
|
+
pass
|
|
524
|
+
|
|
466
525
|
async def run_audio_streaming(
|
|
467
526
|
self,
|
|
468
527
|
on_new_message: Callable[[UserMessage], Awaitable[Any]],
|
|
@@ -598,6 +657,8 @@ class VoiceInputChannel(InputChannel):
|
|
|
598
657
|
call_state.user_speech_start_time = time.time()
|
|
599
658
|
self._cancel_silence_timeout_watcher()
|
|
600
659
|
call_state.is_user_speaking = True
|
|
660
|
+
if self.should_interrupt(e):
|
|
661
|
+
await self.interrupt_playback(voice_websocket, call_parameters)
|
|
601
662
|
elif isinstance(e, UserSilence):
|
|
602
663
|
output_channel = self.create_output_channel(voice_websocket, tts_engine)
|
|
603
664
|
message = UserMessage(
|
|
@@ -4,6 +4,7 @@ from collections import deque
|
|
|
4
4
|
from typing import Deque, Optional, Text
|
|
5
5
|
|
|
6
6
|
import structlog
|
|
7
|
+
from pydantic import ValidationError
|
|
7
8
|
|
|
8
9
|
from rasa.core.lock import Ticket, TicketLock
|
|
9
10
|
from rasa.core.lock_store import (
|
|
@@ -12,6 +13,12 @@ from rasa.core.lock_store import (
|
|
|
12
13
|
LockError,
|
|
13
14
|
LockStore,
|
|
14
15
|
)
|
|
16
|
+
from rasa.core.redis_connection_factory import (
|
|
17
|
+
DeploymentMode,
|
|
18
|
+
RedisConfig,
|
|
19
|
+
RedisConnectionFactory,
|
|
20
|
+
)
|
|
21
|
+
from rasa.shared.exceptions import RasaException
|
|
15
22
|
from rasa.utils.endpoints import EndpointConfig
|
|
16
23
|
|
|
17
24
|
DEFAULT_REDIS_DB = 1
|
|
@@ -74,9 +81,10 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
74
81
|
alphanumeric.
|
|
75
82
|
socket_timeout - Timeout in seconds after which an exception will be raised
|
|
76
83
|
in case Redis doesn't respond within `socket_timeout` seconds.
|
|
84
|
+
deployment_mode - Redis deployment mode: standard, cluster, or sentinel.
|
|
85
|
+
endpoints - List of endpoints for cluster/sentinel mode in host:port format.
|
|
86
|
+
sentinel_service - Sentinel service name.
|
|
77
87
|
"""
|
|
78
|
-
import redis
|
|
79
|
-
|
|
80
88
|
host = endpoint_config.kwargs.get("host", DEFAULT_HOSTNAME)
|
|
81
89
|
port = endpoint_config.kwargs.get("port", DEFAULT_PORT)
|
|
82
90
|
db = endpoint_config.kwargs.get("db", DEFAULT_REDIS_DB)
|
|
@@ -90,20 +98,33 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
90
98
|
socket_timeout = endpoint_config.kwargs.get(
|
|
91
99
|
"socket_timeout", DEFAULT_SOCKET_TIMEOUT_IN_SECONDS
|
|
92
100
|
)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
host=host,
|
|
96
|
-
port=int(port),
|
|
97
|
-
db=int(db),
|
|
98
|
-
username=username,
|
|
99
|
-
password=password,
|
|
100
|
-
ssl=use_ssl,
|
|
101
|
-
ssl_certfile=ssl_certfile,
|
|
102
|
-
ssl_keyfile=ssl_keyfile,
|
|
103
|
-
ssl_ca_certs=ssl_ca_certs,
|
|
104
|
-
socket_timeout=socket_timeout,
|
|
101
|
+
deployment_mode = endpoint_config.kwargs.get(
|
|
102
|
+
"deployment_mode", DeploymentMode.STANDARD.value
|
|
105
103
|
)
|
|
104
|
+
endpoints = endpoint_config.kwargs.get("endpoints", [])
|
|
105
|
+
sentinel_service = endpoint_config.kwargs.get("sentinel_service")
|
|
106
106
|
|
|
107
|
+
try:
|
|
108
|
+
redis_config = RedisConfig(
|
|
109
|
+
host=host,
|
|
110
|
+
port=port,
|
|
111
|
+
db=db,
|
|
112
|
+
username=username,
|
|
113
|
+
password=password,
|
|
114
|
+
use_ssl=use_ssl,
|
|
115
|
+
ssl_certfile=ssl_certfile,
|
|
116
|
+
ssl_keyfile=ssl_keyfile,
|
|
117
|
+
ssl_ca_certs=ssl_ca_certs,
|
|
118
|
+
socket_timeout=socket_timeout,
|
|
119
|
+
deployment_mode=deployment_mode,
|
|
120
|
+
endpoints=endpoints,
|
|
121
|
+
sentinel_service=sentinel_service,
|
|
122
|
+
)
|
|
123
|
+
self.red = RedisConnectionFactory.create_connection(redis_config)
|
|
124
|
+
except ValidationError as e:
|
|
125
|
+
raise RasaException(f"Invalid Redis configuration: {e}")
|
|
126
|
+
|
|
127
|
+
self.deployment_mode = deployment_mode
|
|
107
128
|
self.key_prefix = DEFAULT_CONCURRENT_REDIS_LOCK_STORE_KEY_PREFIX
|
|
108
129
|
if key_prefix:
|
|
109
130
|
structlogger.debug(
|
|
@@ -129,6 +150,32 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
129
150
|
),
|
|
130
151
|
)
|
|
131
152
|
|
|
153
|
+
def _get_keys_by_pattern(self, pattern: Text) -> list:
|
|
154
|
+
"""Get keys by pattern, using SCAN for cluster mode and KEYS for others."""
|
|
155
|
+
if self.deployment_mode == DeploymentMode.CLUSTER.value:
|
|
156
|
+
# In cluster mode, use SCAN to get keys more reliably
|
|
157
|
+
keys = []
|
|
158
|
+
cursor = 0
|
|
159
|
+
|
|
160
|
+
while True:
|
|
161
|
+
try:
|
|
162
|
+
cursor, batch_keys = self.red.scan(cursor, match=pattern, count=100)
|
|
163
|
+
keys.extend(batch_keys)
|
|
164
|
+
if cursor == 0:
|
|
165
|
+
break
|
|
166
|
+
except Exception as e:
|
|
167
|
+
structlogger.warning(
|
|
168
|
+
"concurrent_redis_lock_store._get_keys_by_pattern.scan_interrupted",
|
|
169
|
+
event_info=f"SCAN interrupted in cluster mode: {e}. "
|
|
170
|
+
f"Returning {len(keys)} keys found so far.",
|
|
171
|
+
)
|
|
172
|
+
break
|
|
173
|
+
else:
|
|
174
|
+
# Standard and sentinel modes use KEYS
|
|
175
|
+
keys = self.red.keys(pattern)
|
|
176
|
+
|
|
177
|
+
return keys
|
|
178
|
+
|
|
132
179
|
def issue_ticket(
|
|
133
180
|
self, conversation_id: Text, lock_lifetime: float = LOCK_LIFETIME
|
|
134
181
|
) -> int:
|
|
@@ -157,11 +204,14 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
157
204
|
tickets: Deque[Ticket] = deque()
|
|
158
205
|
|
|
159
206
|
pattern = self.key_prefix + conversation_id + ":" + "[0-9]*"
|
|
160
|
-
redis_keys = self.
|
|
207
|
+
redis_keys = self._get_keys_by_pattern(pattern)
|
|
161
208
|
|
|
162
209
|
for key in redis_keys:
|
|
163
210
|
serialised_ticket = self.red.get(key)
|
|
164
211
|
if serialised_ticket:
|
|
212
|
+
# Handle bytes to string conversion for JSON parsing
|
|
213
|
+
if isinstance(serialised_ticket, bytes):
|
|
214
|
+
serialised_ticket = serialised_ticket.decode("utf-8")
|
|
165
215
|
ticket = Ticket.from_dict(json.loads(serialised_ticket))
|
|
166
216
|
tickets.appendleft(ticket)
|
|
167
217
|
|
|
@@ -172,7 +222,7 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
172
222
|
def delete_lock(self, conversation_id: Text) -> None:
|
|
173
223
|
"""Deletes lock for conversation ID."""
|
|
174
224
|
pattern = self.key_prefix + conversation_id + ":*"
|
|
175
|
-
redis_keys = self.
|
|
225
|
+
redis_keys = self._get_keys_by_pattern(pattern)
|
|
176
226
|
|
|
177
227
|
if not redis_keys:
|
|
178
228
|
structlogger.debug(
|
rasa/core/constants.py
CHANGED
|
@@ -112,3 +112,10 @@ ACTIVE_FLOW_METADATA_KEY = "active_flow"
|
|
|
112
112
|
STEP_ID_METADATA_KEY = "step_id"
|
|
113
113
|
KEY_IS_CALM_SYSTEM = "is_calm_system"
|
|
114
114
|
KEY_IS_COEXISTENCE_ASSISTANT = "is_coexistence_assistant"
|
|
115
|
+
|
|
116
|
+
IAM_CLOUD_PROVIDER_ENV_VAR_NAME = "IAM_CLOUD_PROVIDER"
|
|
117
|
+
SQL_TRACKER_STORE_SSL_MODE_ENV_VAR_NAME = "SQL_TRACKER_STORE_SSL_MODE"
|
|
118
|
+
SQL_TRACKER_STORE_SSL_ROOT_CERTIFICATE_ENV_VAR_NAME = (
|
|
119
|
+
"SQL_TRACKER_STORE_SSL_ROOT_CERTIFICATE"
|
|
120
|
+
)
|
|
121
|
+
AWS_ELASTICACHE_CLUSTER_NAME_ENV_VAR_NAME = "AWS_ELASTICACHE_CLUSTER_NAME"
|
|
File without changes
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import threading
|
|
3
|
+
import time
|
|
4
|
+
from typing import Optional, Tuple
|
|
5
|
+
from urllib.parse import ParseResult, urlencode, urlunparse
|
|
6
|
+
|
|
7
|
+
import boto3
|
|
8
|
+
import redis
|
|
9
|
+
import structlog
|
|
10
|
+
from aws_msk_iam_sasl_signer import MSKAuthTokenProvider
|
|
11
|
+
from botocore.exceptions import BotoCoreError
|
|
12
|
+
from botocore.model import ServiceId
|
|
13
|
+
from botocore.session import get_session
|
|
14
|
+
from botocore.signers import RequestSigner
|
|
15
|
+
from cachetools import TTLCache, cached
|
|
16
|
+
|
|
17
|
+
from rasa.core.iam_credentials_providers.credentials_provider_protocol import (
|
|
18
|
+
IAMCredentialsProvider,
|
|
19
|
+
IAMCredentialsProviderInput,
|
|
20
|
+
SupportedServiceType,
|
|
21
|
+
TemporaryCredentials,
|
|
22
|
+
)
|
|
23
|
+
from rasa.shared.exceptions import ConnectionException
|
|
24
|
+
|
|
25
|
+
structlogger = structlog.get_logger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AWSRDSIAMCredentialsProvider(IAMCredentialsProvider):
|
|
29
|
+
"""Generates temporary credentials for AWS RDS using IAM roles."""
|
|
30
|
+
|
|
31
|
+
def __init__(self, username: str, host: str, port: int) -> None:
|
|
32
|
+
"""Initializes the provider."""
|
|
33
|
+
self.username = username
|
|
34
|
+
self.host = host
|
|
35
|
+
self.port = port
|
|
36
|
+
|
|
37
|
+
def get_temporary_credentials(self) -> TemporaryCredentials:
|
|
38
|
+
"""Generates temporary credentials for AWS RDS."""
|
|
39
|
+
structlogger.debug(
|
|
40
|
+
"rasa.core.aws_rds_iam_credentials_provider.get_credentials",
|
|
41
|
+
event_info="IAM authentication for AWS RDS enabled. "
|
|
42
|
+
"Generating temporary auth token...",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
client = boto3.client("rds")
|
|
47
|
+
auth_token = client.generate_db_auth_token(
|
|
48
|
+
DBHostname=self.host,
|
|
49
|
+
Port=self.port,
|
|
50
|
+
DBUsername=self.username,
|
|
51
|
+
)
|
|
52
|
+
structlogger.info(
|
|
53
|
+
"rasa.core.aws_rds_iam_credentials_provider.generated_credentials",
|
|
54
|
+
event_info="Successfully generated temporary auth token for AWS RDS.",
|
|
55
|
+
)
|
|
56
|
+
return TemporaryCredentials(auth_token=auth_token)
|
|
57
|
+
except (BotoCoreError, ValueError) as exc:
|
|
58
|
+
structlogger.error(
|
|
59
|
+
"rasa.core.aws_rds_iam_credentials_provider.error_generating_credentials",
|
|
60
|
+
event_info="Failed to generate temporary auth token for AWS RDS.",
|
|
61
|
+
error=str(exc),
|
|
62
|
+
)
|
|
63
|
+
return TemporaryCredentials(auth_token=None)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class AWSMSKafkaIAMCredentialsProvider(IAMCredentialsProvider):
|
|
67
|
+
"""Generates temporary credentials for AWS MSK using IAM roles."""
|
|
68
|
+
|
|
69
|
+
def __init__(self) -> None:
|
|
70
|
+
self.region = os.getenv("AWS_DEFAULT_REGION", os.getenv("AWS_REGION"))
|
|
71
|
+
self._token: Optional[str] = None
|
|
72
|
+
self._expires_at: float = 0
|
|
73
|
+
self.refresh_margin_seconds = 60 # Refresh 60 seconds before expiry
|
|
74
|
+
# ensure thread safety when refreshing token because the
|
|
75
|
+
# kafka client library we use (confluent-kafka) is multithreaded
|
|
76
|
+
self.lock = threading.Lock()
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def token(self) -> Optional[str]:
|
|
80
|
+
return self._token
|
|
81
|
+
|
|
82
|
+
@token.setter
|
|
83
|
+
def token(self, value: str) -> None:
|
|
84
|
+
self._token = value
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def expires_at(self) -> float:
|
|
88
|
+
return self._expires_at
|
|
89
|
+
|
|
90
|
+
@expires_at.setter
|
|
91
|
+
def expires_at(self, value: float) -> None:
|
|
92
|
+
self._expires_at = value
|
|
93
|
+
|
|
94
|
+
def get_temporary_credentials(self) -> TemporaryCredentials:
|
|
95
|
+
"""Generates temporary credentials for AWS MSK."""
|
|
96
|
+
with self.lock:
|
|
97
|
+
current_time = time.time() # Current time in seconds
|
|
98
|
+
if (
|
|
99
|
+
not self.token
|
|
100
|
+
or current_time >= self.expires_at - self.refresh_margin_seconds
|
|
101
|
+
):
|
|
102
|
+
try:
|
|
103
|
+
auth_token, expiry_ms = MSKAuthTokenProvider.generate_auth_token(
|
|
104
|
+
self.region
|
|
105
|
+
)
|
|
106
|
+
structlogger.debug(
|
|
107
|
+
"rasa.core.aws_msk_iam_credentials_provider.get_credentials",
|
|
108
|
+
event_info="Successfully generated AWS IAM token for "
|
|
109
|
+
"Kafka authentication.",
|
|
110
|
+
)
|
|
111
|
+
self.token = auth_token
|
|
112
|
+
self.expires_at = int(expiry_ms) / 1000 # Convert ms to seconds
|
|
113
|
+
return TemporaryCredentials(
|
|
114
|
+
auth_token=auth_token,
|
|
115
|
+
expiration=self.expires_at,
|
|
116
|
+
)
|
|
117
|
+
except Exception as exc:
|
|
118
|
+
raise ConnectionException(
|
|
119
|
+
f"Failed to generate AWS IAM token "
|
|
120
|
+
f"for MSK authentication. Original exception: {exc}"
|
|
121
|
+
) from exc
|
|
122
|
+
else:
|
|
123
|
+
structlogger.debug(
|
|
124
|
+
"rasa.core.aws_msk_iam_credentials_provider.get_credentials",
|
|
125
|
+
event_info="Using cached AWS IAM token for Kafka authentication.",
|
|
126
|
+
)
|
|
127
|
+
return TemporaryCredentials(
|
|
128
|
+
auth_token=self.token,
|
|
129
|
+
expiration=self.expires_at,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class AWSElasticacheRedisIAMCredentialsProvider(redis.CredentialProvider):
|
|
134
|
+
"""Generates temporary credentials for AWS ElastiCache Redis using IAM roles."""
|
|
135
|
+
|
|
136
|
+
def __init__(self, username: str, cluster_name: Optional[str] = None) -> None:
|
|
137
|
+
"""Initializes the provider."""
|
|
138
|
+
self.username = username
|
|
139
|
+
self.cluster_name = cluster_name
|
|
140
|
+
self.region = os.getenv("AWS_DEFAULT_REGION", os.getenv("AWS_REGION"))
|
|
141
|
+
self.session = get_session()
|
|
142
|
+
self.request_signer = RequestSigner(
|
|
143
|
+
ServiceId("elasticache"),
|
|
144
|
+
self.region,
|
|
145
|
+
"elasticache",
|
|
146
|
+
"v4",
|
|
147
|
+
self.session.get_credentials(),
|
|
148
|
+
self.session.get_component("event_emitter"),
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Generated IAM tokens are valid for 15 minutes
|
|
152
|
+
@cached(cache=TTLCache(maxsize=128, ttl=900))
|
|
153
|
+
def get_credentials(self) -> Tuple[str, str]:
|
|
154
|
+
"""Generates temporary credentials for AWS ElastiCache Redis.
|
|
155
|
+
|
|
156
|
+
Required method implementation by redis-py CredentialProvider parent class.
|
|
157
|
+
Used internally by redis-py when connecting to Redis.
|
|
158
|
+
"""
|
|
159
|
+
query_params = {"Action": "connect", "User": self.username}
|
|
160
|
+
url = urlunparse(
|
|
161
|
+
ParseResult(
|
|
162
|
+
scheme="https",
|
|
163
|
+
netloc=self.cluster_name,
|
|
164
|
+
path="/",
|
|
165
|
+
query=urlencode(query_params),
|
|
166
|
+
params="",
|
|
167
|
+
fragment="",
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
signed_url = self.request_signer.generate_presigned_url(
|
|
171
|
+
{"method": "GET", "url": url, "body": {}, "headers": {}, "context": {}},
|
|
172
|
+
operation_name="connect",
|
|
173
|
+
expires_in=900,
|
|
174
|
+
region_name=self.region,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# RequestSigner only seems to work if the URL has a protocol, but
|
|
178
|
+
# Elasticache only accepts the URL without a protocol
|
|
179
|
+
# So strip it off the signed URL before returning
|
|
180
|
+
return self.username, signed_url.removeprefix("https://")
|
|
181
|
+
|
|
182
|
+
def get_temporary_credentials(self) -> TemporaryCredentials:
|
|
183
|
+
"""Generates temporary credentials for AWS ElastiCache Redis.
|
|
184
|
+
|
|
185
|
+
Implemented to comply with the IAMCredentialsProvider rasa-pro interface.
|
|
186
|
+
Calls the get_credentials method which is used internally by redis-py.
|
|
187
|
+
"""
|
|
188
|
+
try:
|
|
189
|
+
username, signed_url = self.get_credentials()
|
|
190
|
+
structlogger.info(
|
|
191
|
+
"rasa.core.aws_elasticache_redis_iam_credentials_provider.generated_credentials",
|
|
192
|
+
event_info="Successfully generated temporary credentials for "
|
|
193
|
+
"AWS ElastiCache Redis.",
|
|
194
|
+
)
|
|
195
|
+
return TemporaryCredentials(username=username, presigned_url=signed_url)
|
|
196
|
+
except Exception as exc:
|
|
197
|
+
structlogger.error(
|
|
198
|
+
"rasa.core.aws_elasticache_redis_iam_credentials_provider.error_generating_credentials",
|
|
199
|
+
event_info="Failed to generate temporary credentials for "
|
|
200
|
+
"AWS ElastiCache Redis.",
|
|
201
|
+
error=str(exc),
|
|
202
|
+
)
|
|
203
|
+
return TemporaryCredentials()
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def create_aws_iam_credentials_provider(
|
|
207
|
+
provider_input: "IAMCredentialsProviderInput",
|
|
208
|
+
) -> Optional["IAMCredentialsProvider"]:
|
|
209
|
+
"""Factory function to create an AWS IAM credentials provider."""
|
|
210
|
+
if provider_input.service_name == SupportedServiceType.TRACKER_STORE:
|
|
211
|
+
return AWSRDSIAMCredentialsProvider(
|
|
212
|
+
username=provider_input.username,
|
|
213
|
+
host=provider_input.host,
|
|
214
|
+
port=provider_input.port,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
if provider_input.service_name == SupportedServiceType.EVENT_BROKER:
|
|
218
|
+
return AWSMSKafkaIAMCredentialsProvider()
|
|
219
|
+
|
|
220
|
+
if provider_input.service_name == SupportedServiceType.LOCK_STORE:
|
|
221
|
+
return AWSElasticacheRedisIAMCredentialsProvider(
|
|
222
|
+
username=provider_input.username,
|
|
223
|
+
cluster_name=provider_input.cluster_name,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
return None
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Optional, Protocol, runtime_checkable
|
|
6
|
+
|
|
7
|
+
import structlog
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
from rasa.core.constants import IAM_CLOUD_PROVIDER_ENV_VAR_NAME
|
|
11
|
+
|
|
12
|
+
structlogger = structlog.get_logger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TemporaryCredentials(BaseModel):
|
|
16
|
+
"""Dataclass storing temporary credentials."""
|
|
17
|
+
|
|
18
|
+
auth_token: Optional[str] = None
|
|
19
|
+
expiration: Optional[float] = None
|
|
20
|
+
username: Optional[str] = None
|
|
21
|
+
presigned_url: Optional[str] = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@runtime_checkable
|
|
25
|
+
class IAMCredentialsProvider(Protocol):
|
|
26
|
+
"""Interface for generating temporary credentials using IAM roles."""
|
|
27
|
+
|
|
28
|
+
def get_temporary_credentials(self) -> TemporaryCredentials:
|
|
29
|
+
"""Generates temporary credentials using IAM roles."""
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class IAMCredentialsProviderType(Enum):
|
|
34
|
+
"""Enum for supported IAM credentials provider types."""
|
|
35
|
+
|
|
36
|
+
AWS = "aws"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class SupportedServiceType(Enum):
|
|
40
|
+
"""Enum for supported services using IAM credentials providers."""
|
|
41
|
+
|
|
42
|
+
TRACKER_STORE = "tracker_store"
|
|
43
|
+
EVENT_BROKER = "event_broker"
|
|
44
|
+
LOCK_STORE = "lock_store"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class IAMCredentialsProviderInput(BaseModel):
|
|
48
|
+
"""Input data for creating an IAM credentials provider."""
|
|
49
|
+
|
|
50
|
+
service_name: SupportedServiceType
|
|
51
|
+
username: Optional[str] = None
|
|
52
|
+
host: Optional[str] = None
|
|
53
|
+
port: Optional[int] = None
|
|
54
|
+
cluster_name: Optional[str] = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def create_iam_credentials_provider(
|
|
58
|
+
provider_input: IAMCredentialsProviderInput,
|
|
59
|
+
) -> Optional[IAMCredentialsProvider]:
|
|
60
|
+
"""Factory function to create an IAM credentials provider.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
provider_input: Input data for creating an IAM credentials provider.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
An instance of the specified IAM credentials provider or
|
|
67
|
+
None if the type is unsupported.
|
|
68
|
+
"""
|
|
69
|
+
iam_cloud_provider = os.getenv(IAM_CLOUD_PROVIDER_ENV_VAR_NAME)
|
|
70
|
+
|
|
71
|
+
if iam_cloud_provider is None:
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
provider_type = IAMCredentialsProviderType(iam_cloud_provider.lower())
|
|
76
|
+
except ValueError:
|
|
77
|
+
structlogger.warning(
|
|
78
|
+
"rasa.core.iam_credentials_provider.create_iam_credentials_provider.unsupported_provider",
|
|
79
|
+
event_info=f"Unsupported IAM cloud provider: {iam_cloud_provider}",
|
|
80
|
+
)
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
if provider_type == IAMCredentialsProviderType.AWS:
|
|
84
|
+
from rasa.core.iam_credentials_providers.aws_iam_credentials_providers import (
|
|
85
|
+
create_aws_iam_credentials_provider,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return create_aws_iam_credentials_provider(provider_input)
|
|
89
|
+
|
|
90
|
+
return None
|