rasa-pro 3.12.18.dev1__py3-none-any.whl → 3.13.0a1.dev1__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/__init__.py +0 -6
- rasa/__main__.py +3 -4
- rasa/api.py +1 -1
- rasa/builder/create_openai_vector_store.py +69 -0
- rasa/builder/llm-helper-schema.json +69 -0
- rasa/builder/prompt_to_bot.py +645 -0
- rasa/builder/scrape_rasa_docs.py +97 -0
- rasa/builder/skill_to_bot_prompt.jinja +158 -0
- rasa/cli/dialogue_understanding_test.py +1 -1
- rasa/cli/e2e_test.py +1 -1
- rasa/cli/evaluate.py +2 -2
- rasa/cli/export.py +3 -3
- rasa/cli/llm_fine_tuning.py +1 -1
- rasa/cli/project_templates/default/config.yml +5 -32
- rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_cancels_during_a_correction.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_handle.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_name.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_lists_contacts.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact_from_list.yml +1 -1
- rasa/cli/project_templates/default/endpoints.yml +18 -2
- rasa/cli/project_templates/defaults.py +133 -0
- rasa/cli/run.py +1 -1
- rasa/cli/scaffold.py +2 -3
- rasa/cli/studio/download.py +1 -1
- rasa/cli/studio/link.py +53 -0
- rasa/cli/studio/pull.py +78 -0
- rasa/cli/studio/push.py +78 -0
- rasa/cli/studio/studio.py +12 -0
- rasa/cli/studio/upload.py +5 -3
- rasa/cli/train.py +1 -1
- rasa/cli/utils.py +1 -1
- rasa/cli/x.py +1 -1
- rasa/constants.py +2 -0
- rasa/core/__init__.py +0 -16
- rasa/core/actions/action.py +42 -31
- rasa/core/actions/action_repeat_bot_messages.py +18 -22
- rasa/core/actions/action_run_slot_rejections.py +1 -2
- rasa/core/agent.py +18 -3
- rasa/core/available_endpoints.py +146 -0
- rasa/core/brokers/kafka.py +4 -0
- rasa/core/brokers/pika.py +5 -2
- rasa/core/brokers/sql.py +1 -1
- rasa/core/channels/botframework.py +2 -2
- rasa/core/channels/channel.py +2 -2
- rasa/core/channels/development_inspector.py +1 -1
- rasa/core/channels/facebook.py +1 -4
- rasa/core/channels/hangouts.py +8 -5
- rasa/core/channels/inspector/.eslintrc.cjs +12 -6
- rasa/core/channels/inspector/.prettierrc +5 -0
- rasa/core/channels/inspector/README.md +11 -5
- rasa/core/channels/inspector/dist/assets/{arc-9f75cc3b.js → arc-02053cc1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7f34db23.js → blockDiagram-38ab4fdb-008b6289.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-948bab2c.js → c4Diagram-3d4e48cf-fb2597be.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-078dada8.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-53b0dd0e.js → classDiagram-70f12bd4-7f847e00.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-fdf789e7.js → classDiagram-v2-f2320105-ba1d689b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-5b4516de.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-87c4ece5.js → createText-2e5e7dd3-dd8e67c4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-5a8b0749.js → edges-e0da2a9e-10784939.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-66da90e2.js → erDiagram-9861fffd-24947ae6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-10044f05.js → flowDb-956e92f1-a9ced505.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-f338f66a.js → flowDiagram-66a62f08-afda9c7c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-f9613071.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b13140aa.js → flowchart-elk-definition-4a651766-6ef530b8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-f2b4a55a.js → ganttDiagram-c361ad54-0c7dd39a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-dedc298d.js → gitGraphDiagram-72cf32ee-b57239d6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-4ede11ff.js → graph-9ed57cec.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-65549d37.js → index-3862675e-233090de.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3a23e736.js → index-72184470.js} +123 -123
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-65439671.js → infoDiagram-f8f76790-aa116649.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-56d03d98.js → journeyDiagram-49397b02-e51877cc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-dd48f7f4.js → layout-3ca3798c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-1569ad2c.js → line-26ee10d3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-48bf4935.js → linear-aedded32.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-688504c1.js → mindmap-definition-fc14e90a-d8957261.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-78b6d7e6.js → pieDiagram-8a3498a8-d771f885.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-048b84b3.js → quadrantDiagram-120e2f19-09fdf50c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-dd67f107.js → requirementDiagram-deff3bca-9f0af02e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-8128436e.js → sankeyDiagram-04a897e0-84415b37.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-1a0d1461.js → sequenceDiagram-704730f1-8dec4055.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-46d388ed.js → stateDiagram-587899a1-c5431d07.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-ea42951a.js → stateDiagram-v2-d93cdb3a-274e77d9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-7427ed0c.js → styles-6aaf32cf-e364a1d7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-ff5e5a16.js → styles-9a916d00-0dae36f6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-7b3680cf.js → styles-c10674c1-c4641675.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f860f2ad.js → svgDrawCommon-08f97a94-831fe9a1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-2eebf0c8.js → timeline-definition-85554ec2-c3304b3a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-5d7f4e96.js → xychartDiagram-e933f94c-da799369.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/package.json +3 -1
- rasa/core/channels/inspector/src/App.tsx +91 -90
- rasa/core/channels/inspector/src/components/Chat.tsx +45 -41
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +40 -40
- rasa/core/channels/inspector/src/components/DialogueInformation.tsx +57 -57
- rasa/core/channels/inspector/src/components/DialogueStack.tsx +36 -27
- rasa/core/channels/inspector/src/components/ExpandIcon.tsx +4 -4
- rasa/core/channels/inspector/src/components/FullscreenButton.tsx +7 -7
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +28 -12
- rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +9 -9
- rasa/core/channels/inspector/src/components/RasaLogo.tsx +5 -5
- rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +55 -60
- rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +5 -5
- rasa/core/channels/inspector/src/components/Slots.tsx +22 -22
- rasa/core/channels/inspector/src/components/Welcome.tsx +28 -31
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +245 -0
- rasa/core/channels/inspector/src/helpers/audio/microphone-processor.js +12 -0
- rasa/core/channels/inspector/src/helpers/audio/playback-processor.js +36 -0
- rasa/core/channels/inspector/src/helpers/conversation.ts +7 -7
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +181 -181
- rasa/core/channels/inspector/src/helpers/formatters.ts +111 -111
- rasa/core/channels/inspector/src/helpers/utils.ts +78 -61
- rasa/core/channels/inspector/src/main.tsx +8 -8
- rasa/core/channels/inspector/src/theme/Button/Button.ts +8 -8
- rasa/core/channels/inspector/src/theme/Heading/Heading.ts +7 -7
- rasa/core/channels/inspector/src/theme/Input/Input.ts +9 -9
- rasa/core/channels/inspector/src/theme/Link/Link.ts +6 -6
- rasa/core/channels/inspector/src/theme/Modal/Modal.ts +13 -13
- rasa/core/channels/inspector/src/theme/Table/Table.tsx +10 -10
- rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/breakpoints.ts +7 -7
- rasa/core/channels/inspector/src/theme/base/colors.ts +64 -64
- rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +21 -18
- rasa/core/channels/inspector/src/theme/base/radii.ts +8 -8
- rasa/core/channels/inspector/src/theme/base/shadows.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/sizes.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/space.ts +12 -12
- rasa/core/channels/inspector/src/theme/base/styles.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/typography.ts +12 -12
- rasa/core/channels/inspector/src/theme/base/zIndices.ts +3 -3
- rasa/core/channels/inspector/src/theme/index.ts +38 -38
- rasa/core/channels/inspector/src/types.ts +56 -50
- rasa/core/channels/inspector/yarn.lock +5 -0
- rasa/core/channels/mattermost.py +1 -1
- rasa/core/channels/rasa_chat.py +2 -4
- rasa/core/channels/rest.py +5 -4
- rasa/core/channels/socketio.py +56 -41
- rasa/core/channels/studio_chat.py +337 -71
- rasa/core/channels/vier_cvg.py +1 -2
- rasa/core/channels/voice_ready/audiocodes.py +4 -11
- rasa/core/channels/voice_stream/audiocodes.py +8 -5
- rasa/core/channels/voice_stream/browser_audio.py +1 -1
- rasa/core/channels/voice_stream/genesys.py +2 -2
- rasa/core/channels/voice_stream/tts/__init__.py +8 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +10 -5
- rasa/core/channels/voice_stream/voice_channel.py +65 -23
- rasa/core/concurrent_lock_store.py +24 -10
- rasa/core/evaluation/marker_tracker_loader.py +1 -1
- rasa/core/exporter.py +1 -1
- rasa/core/http_interpreter.py +3 -7
- rasa/core/information_retrieval/faiss.py +18 -11
- rasa/core/information_retrieval/ingestion/__init__.py +0 -0
- rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
- rasa/core/jobs.py +2 -1
- rasa/core/lock_store.py +151 -60
- rasa/core/nlg/contextual_response_rephraser.py +17 -7
- rasa/core/nlg/generator.py +5 -22
- rasa/core/nlg/interpolator.py +2 -3
- rasa/core/nlg/response.py +6 -43
- rasa/core/nlg/summarize.py +1 -1
- rasa/core/nlg/translate.py +0 -8
- rasa/core/policies/enterprise_search_policy.py +262 -62
- rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +63 -0
- rasa/core/policies/flow_policy.py +1 -1
- rasa/core/policies/flows/flow_executor.py +96 -17
- rasa/core/policies/intentless_policy.py +57 -20
- rasa/core/processor.py +114 -54
- rasa/core/run.py +33 -11
- rasa/core/tracker_stores/__init__.py +0 -0
- rasa/core/{auth_retry_tracker_store.py → tracker_stores/auth_retry_tracker_store.py} +5 -1
- rasa/core/tracker_stores/dynamo_tracker_store.py +218 -0
- rasa/core/tracker_stores/mongo_tracker_store.py +206 -0
- rasa/core/tracker_stores/redis_tracker_store.py +219 -0
- rasa/core/tracker_stores/sql_tracker_store.py +555 -0
- rasa/core/tracker_stores/tracker_store.py +805 -0
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +24 -95
- rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
- rasa/dialogue_understanding/coexistence/llm_based_router.py +10 -6
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +5 -1
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/clarify_command.py +4 -0
- rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +1 -3
- rasa/dialogue_understanding/commands/human_handoff_command.py +2 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
- rasa/dialogue_understanding/commands/set_slot_command.py +10 -0
- rasa/dialogue_understanding/commands/skip_question_command.py +2 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +4 -0
- rasa/dialogue_understanding/commands/utils.py +26 -2
- rasa/dialogue_understanding/generator/__init__.py +7 -1
- rasa/dialogue_understanding/generator/command_generator.py +4 -2
- rasa/dialogue_understanding/generator/command_parser.py +2 -2
- rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +5 -17
- rasa/dialogue_understanding/generator/llm_command_generator.py +1 -3
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +4 -44
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +78 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +26 -474
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
- rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +477 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +11 -64
- rasa/dialogue_understanding/patterns/cancel.py +1 -2
- rasa/dialogue_understanding/patterns/clarify.py +1 -1
- rasa/dialogue_understanding/patterns/correction.py +2 -2
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +37 -25
- rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
- rasa/dialogue_understanding/processor/command_processor.py +6 -7
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
- rasa/dialogue_understanding/stack/utils.py +3 -1
- rasa/dialogue_understanding/utils.py +68 -12
- rasa/dialogue_understanding_test/command_metric_calculation.py +7 -40
- rasa/dialogue_understanding_test/command_metrics.py +38 -0
- rasa/dialogue_understanding_test/du_test_case.py +58 -25
- rasa/dialogue_understanding_test/du_test_result.py +228 -132
- rasa/dialogue_understanding_test/du_test_runner.py +11 -2
- rasa/dialogue_understanding_test/io.py +35 -8
- rasa/e2e_test/e2e_test_runner.py +1 -1
- rasa/engine/constants.py +1 -1
- rasa/engine/graph.py +2 -2
- rasa/engine/recipes/default_recipe.py +1 -1
- rasa/engine/validation.py +3 -2
- rasa/hooks.py +2 -85
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +1 -5
- rasa/llm_fine_tuning/utils.py +2 -4
- rasa/model_manager/model_api.py +90 -2
- rasa/model_manager/socket_bridge.py +0 -7
- rasa/model_manager/trainer_service.py +15 -12
- rasa/plugin.py +2 -15
- rasa/privacy/__init__.py +0 -0
- rasa/privacy/constants.py +83 -0
- rasa/privacy/event_broker_utils.py +77 -0
- rasa/privacy/privacy_config.py +281 -0
- rasa/privacy/privacy_config_schema.json +86 -0
- rasa/privacy/privacy_filter.py +340 -0
- rasa/privacy/privacy_manager.py +576 -0
- rasa/server.py +23 -2
- rasa/shared/constants.py +13 -4
- rasa/shared/core/command_payload_reader.py +1 -5
- rasa/shared/core/constants.py +4 -3
- rasa/shared/core/domain.py +172 -11
- rasa/shared/core/events.py +100 -6
- rasa/shared/core/flows/flow.py +35 -8
- rasa/shared/core/flows/flow_step.py +26 -4
- rasa/shared/core/flows/flow_step_links.py +15 -0
- rasa/shared/core/flows/flow_step_sequence.py +6 -0
- rasa/shared/core/flows/flows_yaml_schema.json +3 -0
- rasa/shared/core/flows/nlu_trigger.py +13 -0
- rasa/shared/core/flows/steps/action.py +7 -4
- rasa/shared/core/flows/steps/call.py +11 -4
- rasa/shared/core/flows/steps/collect.py +71 -6
- rasa/shared/core/flows/steps/internal.py +6 -1
- rasa/shared/core/flows/steps/link.py +7 -4
- rasa/shared/core/flows/steps/no_operation.py +7 -4
- rasa/shared/core/flows/steps/set_slots.py +8 -4
- rasa/shared/core/flows/validation.py +16 -3
- rasa/shared/core/flows/yaml_flows_io.py +106 -5
- rasa/shared/core/slots.py +33 -1
- rasa/shared/core/trackers.py +4 -10
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
- rasa/shared/importers/importer.py +14 -0
- rasa/shared/importers/static.py +63 -0
- rasa/shared/providers/constants.py +0 -9
- rasa/shared/providers/llm/_base_litellm_client.py +4 -14
- rasa/shared/providers/llm/default_litellm_llm_client.py +2 -2
- rasa/shared/providers/llm/litellm_router_llm_client.py +7 -17
- rasa/shared/providers/llm/llm_client.py +15 -24
- rasa/shared/providers/llm/self_hosted_llm_client.py +2 -10
- rasa/shared/utils/common.py +43 -1
- rasa/shared/utils/llm.py +155 -3
- rasa/shared/utils/yaml.py +32 -0
- rasa/studio/data_handler.py +3 -3
- rasa/studio/download/__init__.py +0 -0
- rasa/studio/download/domains.py +49 -0
- rasa/studio/download/download.py +416 -0
- rasa/studio/download/flows.py +351 -0
- rasa/studio/link.py +200 -0
- rasa/studio/pull.py +94 -0
- rasa/studio/push.py +131 -0
- rasa/studio/results_logger.py +6 -1
- rasa/studio/upload.py +185 -71
- rasa/telemetry.py +83 -26
- rasa/tracing/config.py +4 -5
- rasa/tracing/constants.py +19 -1
- rasa/tracing/instrumentation/attribute_extractors.py +49 -11
- rasa/tracing/instrumentation/instrumentation.py +54 -3
- rasa/tracing/instrumentation/metrics.py +98 -15
- rasa/tracing/metric_instrument_provider.py +75 -3
- rasa/utils/common.py +37 -27
- rasa/utils/endpoints.py +22 -1
- rasa/utils/licensing.py +2 -3
- rasa/utils/log_utils.py +1 -45
- rasa/validator.py +9 -11
- rasa/version.py +1 -1
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/METADATA +12 -14
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/RECORD +318 -294
- rasa/anonymization/__init__.py +0 -2
- rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
- rasa/anonymization/anonymization_pipeline.py +0 -286
- rasa/anonymization/anonymization_rule_executor.py +0 -266
- rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
- rasa/anonymization/schemas/config.yml +0 -47
- rasa/anonymization/utils.py +0 -118
- rasa/cli/project_templates/calm/config.yml +0 -10
- rasa/cli/project_templates/calm/credentials.yml +0 -33
- rasa/cli/project_templates/calm/endpoints.yml +0 -58
- rasa/cli/project_templates/default/actions/actions.py +0 -27
- rasa/cli/project_templates/default/data/nlu.yml +0 -91
- rasa/cli/project_templates/default/data/rules.yml +0 -13
- rasa/cli/project_templates/default/data/stories.yml +0 -30
- rasa/cli/project_templates/default/domain.yml +0 -34
- rasa/cli/project_templates/default/tests/test_stories.yml +0 -91
- rasa/core/channels/inspector/dist/assets/channel-dfa68278.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-edb7f119.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-65e7c670.js +0 -1
- rasa/core/channels/inspector/src/helpers/audiostream.ts +0 -191
- rasa/core/tracker_store.py +0 -1792
- rasa/monkey_patches.py +0 -91
- rasa/studio/download.py +0 -489
- /rasa/{cli/project_templates/calm/actions → builder}/__init__.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/action_template.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/add_contact.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/db.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/list_contacts.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/remove_contact.py +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/add_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/list_contacts.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/remove_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/db/contacts.json +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/add_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/list_contacts.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/remove_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/shared.yml +0 -0
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,805 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from inspect import isawaitable, iscoroutinefunction
|
|
5
|
+
from typing import (
|
|
6
|
+
Any,
|
|
7
|
+
Callable,
|
|
8
|
+
Dict,
|
|
9
|
+
Generic,
|
|
10
|
+
Iterable,
|
|
11
|
+
List,
|
|
12
|
+
Optional,
|
|
13
|
+
Text,
|
|
14
|
+
TypeVar,
|
|
15
|
+
Union,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
import structlog
|
|
19
|
+
|
|
20
|
+
import rasa.shared.utils.cli
|
|
21
|
+
import rasa.shared.utils.common
|
|
22
|
+
import rasa.shared.utils.io
|
|
23
|
+
import rasa.utils.json_utils
|
|
24
|
+
from rasa.core.brokers.broker import EventBroker
|
|
25
|
+
from rasa.plugin import plugin_manager
|
|
26
|
+
from rasa.shared.core.constants import ACTION_LISTEN_NAME
|
|
27
|
+
from rasa.shared.core.conversation import Dialogue
|
|
28
|
+
from rasa.shared.core.domain import Domain
|
|
29
|
+
from rasa.shared.core.events import Event
|
|
30
|
+
from rasa.shared.core.trackers import (
|
|
31
|
+
ActionExecuted,
|
|
32
|
+
DialogueStateTracker,
|
|
33
|
+
TrackerEventDiffEngine,
|
|
34
|
+
)
|
|
35
|
+
from rasa.shared.exceptions import ConnectionException, RasaException
|
|
36
|
+
from rasa.utils.endpoints import EndpointConfig
|
|
37
|
+
|
|
38
|
+
structlogger = structlog.get_logger(__name__)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def check_if_tracker_store_async(tracker_store: TrackerStore) -> bool:
|
|
42
|
+
"""Evaluates if a tracker store object is async based on implementation of methods.
|
|
43
|
+
|
|
44
|
+
:param tracker_store: tracker store object we're evaluating
|
|
45
|
+
:return: if the tracker store correctly implements all async methods
|
|
46
|
+
"""
|
|
47
|
+
return all(
|
|
48
|
+
iscoroutinefunction(getattr(tracker_store, method))
|
|
49
|
+
for method in _get_async_tracker_store_methods()
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _get_async_tracker_store_methods() -> List[str]:
|
|
54
|
+
return [
|
|
55
|
+
attribute
|
|
56
|
+
for attribute in dir(TrackerStore)
|
|
57
|
+
if iscoroutinefunction(getattr(TrackerStore, attribute))
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TrackerDeserialisationException(RasaException):
|
|
62
|
+
"""Raised when an error is encountered while deserialising a tracker."""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
SerializationType = TypeVar("SerializationType")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class SerializedTrackerRepresentation(Generic[SerializationType]):
|
|
69
|
+
"""Mixin class for specifying different serialization methods per tracker store."""
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def serialise_tracker(tracker: DialogueStateTracker) -> SerializationType:
|
|
73
|
+
"""Requires implementation to return representation of tracker."""
|
|
74
|
+
raise NotImplementedError()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class SerializedTrackerAsText(SerializedTrackerRepresentation[Text]):
|
|
78
|
+
"""Mixin class that returns the serialized tracker as string."""
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def serialise_tracker(tracker: DialogueStateTracker) -> Text:
|
|
82
|
+
"""Serializes the tracker, returns representation of the tracker."""
|
|
83
|
+
dialogue = tracker.as_dialogue()
|
|
84
|
+
|
|
85
|
+
return json.dumps(dialogue.as_dict())
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class SerializedTrackerAsDict(SerializedTrackerRepresentation[Dict]):
|
|
89
|
+
"""Mixin class that returns the serialized tracker as dictionary."""
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def serialise_tracker(tracker: DialogueStateTracker) -> Dict:
|
|
93
|
+
"""Serializes the tracker, returns representation of the tracker."""
|
|
94
|
+
d = tracker.as_dialogue().as_dict()
|
|
95
|
+
d.update({"sender_id": tracker.sender_id})
|
|
96
|
+
return d
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class TrackerStore:
|
|
100
|
+
"""Represents common behavior and interface for all `TrackerStore`s."""
|
|
101
|
+
|
|
102
|
+
def __init__(
|
|
103
|
+
self,
|
|
104
|
+
domain: Optional[Domain],
|
|
105
|
+
event_broker: Optional[EventBroker] = None,
|
|
106
|
+
**kwargs: Dict[Text, Any],
|
|
107
|
+
) -> None:
|
|
108
|
+
"""Create a TrackerStore.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
domain: The `Domain` to initialize the `DialogueStateTracker`.
|
|
112
|
+
event_broker: An event broker to publish any new events to another
|
|
113
|
+
destination.
|
|
114
|
+
kwargs: Additional kwargs.
|
|
115
|
+
"""
|
|
116
|
+
self._domain = domain or Domain.empty()
|
|
117
|
+
self.event_broker = event_broker
|
|
118
|
+
self.max_event_history: Optional[int] = None
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def create(
|
|
122
|
+
obj: Union[TrackerStore, EndpointConfig, None],
|
|
123
|
+
domain: Optional[Domain] = None,
|
|
124
|
+
event_broker: Optional[EventBroker] = None,
|
|
125
|
+
) -> TrackerStore:
|
|
126
|
+
"""Factory to create a tracker store."""
|
|
127
|
+
if isinstance(obj, TrackerStore):
|
|
128
|
+
return obj
|
|
129
|
+
|
|
130
|
+
import pymongo.errors
|
|
131
|
+
import sqlalchemy.exc
|
|
132
|
+
from botocore.exceptions import BotoCoreError, ClientError
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
_tracker_store = plugin_manager().hook.create_tracker_store(
|
|
136
|
+
endpoint_config=obj,
|
|
137
|
+
domain=domain,
|
|
138
|
+
event_broker=event_broker,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
tracker_store = (
|
|
142
|
+
_tracker_store
|
|
143
|
+
if _tracker_store
|
|
144
|
+
else create_tracker_store(obj, domain, event_broker)
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return tracker_store
|
|
148
|
+
except (
|
|
149
|
+
BotoCoreError,
|
|
150
|
+
ClientError,
|
|
151
|
+
pymongo.errors.ConnectionFailure,
|
|
152
|
+
sqlalchemy.exc.OperationalError,
|
|
153
|
+
ConnectionError,
|
|
154
|
+
pymongo.errors.OperationFailure,
|
|
155
|
+
) as error:
|
|
156
|
+
raise ConnectionException(
|
|
157
|
+
"Cannot connect to tracker store." + str(error)
|
|
158
|
+
) from error
|
|
159
|
+
|
|
160
|
+
async def get_or_create_tracker(
|
|
161
|
+
self,
|
|
162
|
+
sender_id: Text,
|
|
163
|
+
max_event_history: Optional[int] = None,
|
|
164
|
+
append_action_listen: bool = True,
|
|
165
|
+
) -> "DialogueStateTracker":
|
|
166
|
+
"""Returns tracker or creates one if the retrieval returns None.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
sender_id: Conversation ID associated with the requested tracker.
|
|
170
|
+
max_event_history: Value to update the tracker store's max event history to.
|
|
171
|
+
append_action_listen: Whether or not to append an initial `action_listen`.
|
|
172
|
+
"""
|
|
173
|
+
self.max_event_history = max_event_history
|
|
174
|
+
|
|
175
|
+
tracker = await self.retrieve(sender_id)
|
|
176
|
+
|
|
177
|
+
if tracker is None:
|
|
178
|
+
tracker = await self.create_tracker(
|
|
179
|
+
sender_id, append_action_listen=append_action_listen
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return tracker
|
|
183
|
+
|
|
184
|
+
def init_tracker(self, sender_id: Text) -> "DialogueStateTracker":
|
|
185
|
+
"""Returns a Dialogue State Tracker."""
|
|
186
|
+
return DialogueStateTracker(
|
|
187
|
+
sender_id,
|
|
188
|
+
self.domain.slots,
|
|
189
|
+
max_event_history=self.max_event_history,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
async def create_tracker(
|
|
193
|
+
self, sender_id: Text, append_action_listen: bool = True
|
|
194
|
+
) -> DialogueStateTracker:
|
|
195
|
+
"""Creates a new tracker for `sender_id`.
|
|
196
|
+
|
|
197
|
+
The tracker begins with a `SessionStarted` event and is initially listening.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
sender_id: Conversation ID associated with the tracker.
|
|
201
|
+
append_action_listen: Whether or not to append an initial `action_listen`.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
The newly created tracker for `sender_id`.
|
|
205
|
+
"""
|
|
206
|
+
tracker = self.init_tracker(sender_id)
|
|
207
|
+
|
|
208
|
+
if append_action_listen:
|
|
209
|
+
tracker.update(ActionExecuted(ACTION_LISTEN_NAME))
|
|
210
|
+
|
|
211
|
+
await self.save(tracker)
|
|
212
|
+
|
|
213
|
+
return tracker
|
|
214
|
+
|
|
215
|
+
async def save(self, tracker: DialogueStateTracker) -> None:
|
|
216
|
+
"""Save method that will be overridden by specific tracker."""
|
|
217
|
+
raise NotImplementedError()
|
|
218
|
+
|
|
219
|
+
async def exists(self, conversation_id: Text) -> bool:
|
|
220
|
+
"""Checks if tracker exists for the specified ID.
|
|
221
|
+
|
|
222
|
+
This method may be overridden by the specific tracker store for
|
|
223
|
+
faster implementations.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
conversation_id: Conversation ID to check if the tracker exists.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
`True` if the tracker exists, `False` otherwise.
|
|
230
|
+
"""
|
|
231
|
+
return await self.retrieve(conversation_id) is not None
|
|
232
|
+
|
|
233
|
+
async def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]:
|
|
234
|
+
"""Retrieves tracker for the latest conversation session.
|
|
235
|
+
|
|
236
|
+
This method will be overridden by the specific tracker store.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
sender_id: Conversation ID to fetch the tracker for.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
Tracker containing events from the latest conversation sessions.
|
|
243
|
+
"""
|
|
244
|
+
raise NotImplementedError()
|
|
245
|
+
|
|
246
|
+
async def delete(self, sender_id: str) -> None:
|
|
247
|
+
"""Delete tracker for the given sender_id.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
sender_id: Conversation ID to delete the tracker for.
|
|
251
|
+
"""
|
|
252
|
+
raise NotImplementedError()
|
|
253
|
+
|
|
254
|
+
async def retrieve_full_tracker(
|
|
255
|
+
self, conversation_id: Text
|
|
256
|
+
) -> Optional[DialogueStateTracker]:
|
|
257
|
+
"""Retrieve method for fetching all tracker events.
|
|
258
|
+
|
|
259
|
+
Fetches events across conversation sessions. The default implementation
|
|
260
|
+
uses `self.retrieve()`.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
conversation_id: The conversation ID to retrieve the tracker for.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
The fetch tracker containing all events across session starts.
|
|
267
|
+
"""
|
|
268
|
+
return await self.retrieve(conversation_id)
|
|
269
|
+
|
|
270
|
+
async def get_or_create_full_tracker(
|
|
271
|
+
self,
|
|
272
|
+
sender_id: Text,
|
|
273
|
+
append_action_listen: bool = True,
|
|
274
|
+
) -> "DialogueStateTracker":
|
|
275
|
+
"""Returns tracker or creates one if the retrieval returns None.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
sender_id: Conversation ID associated with the requested tracker.
|
|
279
|
+
append_action_listen: Whether to append an initial `action_listen`.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
The tracker for the conversation ID.
|
|
283
|
+
"""
|
|
284
|
+
tracker = await self.retrieve_full_tracker(sender_id)
|
|
285
|
+
|
|
286
|
+
if tracker is None:
|
|
287
|
+
tracker = await self.create_tracker(
|
|
288
|
+
sender_id, append_action_listen=append_action_listen
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
return tracker
|
|
292
|
+
|
|
293
|
+
async def stream_events(self, tracker: DialogueStateTracker) -> None:
|
|
294
|
+
"""Streams events to a message broker."""
|
|
295
|
+
if self.event_broker is None:
|
|
296
|
+
structlogger.debug(
|
|
297
|
+
"tracker_store.stream_events.no_broker_configured",
|
|
298
|
+
event_info="No event broker configured. Skipping streaming events.",
|
|
299
|
+
)
|
|
300
|
+
return None
|
|
301
|
+
|
|
302
|
+
if (
|
|
303
|
+
hasattr(self.event_broker, "stream_pii")
|
|
304
|
+
and not self.event_broker.stream_pii
|
|
305
|
+
):
|
|
306
|
+
# If the event broker is configured to not stream un-anonymized events,
|
|
307
|
+
# skip streaming
|
|
308
|
+
structlogger.debug(
|
|
309
|
+
"tracker_store.stream_events.no_streaming",
|
|
310
|
+
event_info="Un-anonymized events will not be published "
|
|
311
|
+
"to the event broker.",
|
|
312
|
+
)
|
|
313
|
+
return None
|
|
314
|
+
|
|
315
|
+
old_tracker = await self.retrieve(tracker.sender_id)
|
|
316
|
+
new_events = TrackerEventDiffEngine.event_difference(old_tracker, tracker)
|
|
317
|
+
|
|
318
|
+
await self._stream_new_events(self.event_broker, new_events, tracker.sender_id)
|
|
319
|
+
|
|
320
|
+
async def _stream_new_events(
|
|
321
|
+
self,
|
|
322
|
+
event_broker: EventBroker,
|
|
323
|
+
new_events: List[Event],
|
|
324
|
+
sender_id: Text,
|
|
325
|
+
) -> None:
|
|
326
|
+
"""Publishes new tracker events to a message broker."""
|
|
327
|
+
for event in new_events:
|
|
328
|
+
body = {"sender_id": sender_id}
|
|
329
|
+
body.update(event.as_dict())
|
|
330
|
+
event_broker.publish(body)
|
|
331
|
+
|
|
332
|
+
async def keys(self) -> Iterable[Text]:
|
|
333
|
+
"""Returns the set of values for the tracker store's primary key."""
|
|
334
|
+
raise NotImplementedError()
|
|
335
|
+
|
|
336
|
+
async def count_conversations(self, after_timestamp: float = 0.0) -> int:
|
|
337
|
+
"""Returns the number of conversations that have occurred after a timestamp.
|
|
338
|
+
|
|
339
|
+
By default, this method returns the number of conversations that
|
|
340
|
+
have occurred after the Unix epoch (i.e. timestamp 0). A conversation
|
|
341
|
+
is considered to have occurred after a timestamp if at least one event
|
|
342
|
+
happened after that timestamp.
|
|
343
|
+
"""
|
|
344
|
+
tracker_keys = await self.keys()
|
|
345
|
+
|
|
346
|
+
conversation_count = 0
|
|
347
|
+
for key in tracker_keys:
|
|
348
|
+
tracker = await self.retrieve(key)
|
|
349
|
+
if tracker is None or not tracker.events:
|
|
350
|
+
continue
|
|
351
|
+
|
|
352
|
+
last_event = tracker.events[-1]
|
|
353
|
+
if last_event.timestamp >= after_timestamp:
|
|
354
|
+
conversation_count += 1
|
|
355
|
+
|
|
356
|
+
return conversation_count
|
|
357
|
+
|
|
358
|
+
def deserialise_tracker(
|
|
359
|
+
self, sender_id: Text, serialised_tracker: Union[Text, bytes]
|
|
360
|
+
) -> Optional[DialogueStateTracker]:
|
|
361
|
+
"""Deserializes the tracker and returns it."""
|
|
362
|
+
tracker = self.init_tracker(sender_id)
|
|
363
|
+
|
|
364
|
+
try:
|
|
365
|
+
dialogue = Dialogue.from_parameters(json.loads(serialised_tracker))
|
|
366
|
+
except UnicodeDecodeError as e:
|
|
367
|
+
raise TrackerDeserialisationException(
|
|
368
|
+
"Tracker cannot be deserialised. "
|
|
369
|
+
"Trackers must be serialised as json. "
|
|
370
|
+
"Support for deserialising pickled trackers has been removed."
|
|
371
|
+
) from e
|
|
372
|
+
|
|
373
|
+
tracker.recreate_from_dialogue(dialogue)
|
|
374
|
+
|
|
375
|
+
return tracker
|
|
376
|
+
|
|
377
|
+
@property
|
|
378
|
+
def domain(self) -> Domain:
|
|
379
|
+
"""Returns the domain of the tracker store."""
|
|
380
|
+
return self._domain
|
|
381
|
+
|
|
382
|
+
@domain.setter
|
|
383
|
+
def domain(self, domain: Optional[Domain]) -> None:
|
|
384
|
+
self._domain = domain or Domain.empty()
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
class InMemoryTrackerStore(TrackerStore, SerializedTrackerAsText):
|
|
388
|
+
"""Stores conversation history in memory."""
|
|
389
|
+
|
|
390
|
+
def __init__(
|
|
391
|
+
self,
|
|
392
|
+
domain: Domain,
|
|
393
|
+
event_broker: Optional[EventBroker] = None,
|
|
394
|
+
**kwargs: Dict[Text, Any],
|
|
395
|
+
) -> None:
|
|
396
|
+
"""Initializes the tracker store."""
|
|
397
|
+
self.store: Dict[Text, Text] = {}
|
|
398
|
+
super().__init__(domain, event_broker, **kwargs)
|
|
399
|
+
|
|
400
|
+
async def save(self, tracker: DialogueStateTracker) -> None:
|
|
401
|
+
"""Updates and saves the current conversation state."""
|
|
402
|
+
await self.stream_events(tracker)
|
|
403
|
+
serialised = InMemoryTrackerStore.serialise_tracker(tracker)
|
|
404
|
+
self.store[tracker.sender_id] = serialised
|
|
405
|
+
|
|
406
|
+
async def delete(self, sender_id: Text) -> None:
|
|
407
|
+
"""Delete tracker for the given sender_id."""
|
|
408
|
+
if sender_id not in self.store:
|
|
409
|
+
structlogger.info(
|
|
410
|
+
"in_memory_tracker_store.delete.no_tracker_for_sender_id",
|
|
411
|
+
event_info=f"Could not find tracker for conversation ID '{sender_id}'.",
|
|
412
|
+
)
|
|
413
|
+
return None
|
|
414
|
+
|
|
415
|
+
del self.store[sender_id]
|
|
416
|
+
|
|
417
|
+
structlogger.info(
|
|
418
|
+
"in_memory_tracker_store.delete.deleted_tracker",
|
|
419
|
+
sender_id=sender_id,
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
async def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]:
|
|
423
|
+
"""Returns tracker matching sender_id."""
|
|
424
|
+
return await self._retrieve(sender_id, fetch_all_sessions=False)
|
|
425
|
+
|
|
426
|
+
async def keys(self) -> Iterable[Text]:
|
|
427
|
+
"""Returns sender_ids of the Tracker Store in memory."""
|
|
428
|
+
return self.store.keys()
|
|
429
|
+
|
|
430
|
+
async def retrieve_full_tracker(
|
|
431
|
+
self, sender_id: Text
|
|
432
|
+
) -> Optional[DialogueStateTracker]:
|
|
433
|
+
"""Returns tracker matching sender_id.
|
|
434
|
+
|
|
435
|
+
Args:
|
|
436
|
+
sender_id: Conversation ID to fetch the tracker for.
|
|
437
|
+
"""
|
|
438
|
+
return await self._retrieve(sender_id, fetch_all_sessions=True)
|
|
439
|
+
|
|
440
|
+
async def _retrieve(
|
|
441
|
+
self, sender_id: Text, fetch_all_sessions: bool
|
|
442
|
+
) -> Optional[DialogueStateTracker]:
|
|
443
|
+
"""Returns tracker matching sender_id.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
sender_id: Conversation ID to fetch the tracker for.
|
|
447
|
+
fetch_all_sessions: Whether to fetch all sessions or only the last one.
|
|
448
|
+
"""
|
|
449
|
+
if sender_id not in self.store:
|
|
450
|
+
structlogger.debug(
|
|
451
|
+
"in_memory_tracker_store.retrieve.no_tracker_for_sender_id",
|
|
452
|
+
event_info=f"Could not find tracker for conversation ID '{sender_id}'.",
|
|
453
|
+
)
|
|
454
|
+
return None
|
|
455
|
+
|
|
456
|
+
tracker = self.deserialise_tracker(sender_id, self.store[sender_id])
|
|
457
|
+
|
|
458
|
+
if not tracker:
|
|
459
|
+
structlogger.debug(
|
|
460
|
+
"in_memory_tracker_store.retrieve.failed_to_deserialize_tracker",
|
|
461
|
+
event_info=(
|
|
462
|
+
f"Could not deserialize tracker "
|
|
463
|
+
f"for conversation ID '{sender_id}'.",
|
|
464
|
+
),
|
|
465
|
+
)
|
|
466
|
+
return None
|
|
467
|
+
|
|
468
|
+
if fetch_all_sessions:
|
|
469
|
+
return tracker
|
|
470
|
+
|
|
471
|
+
# only return the last session
|
|
472
|
+
multiple_tracker_sessions = (
|
|
473
|
+
rasa.shared.core.trackers.get_trackers_for_conversation_sessions(tracker)
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
if len(multiple_tracker_sessions) <= 1:
|
|
477
|
+
return tracker
|
|
478
|
+
|
|
479
|
+
return multiple_tracker_sessions[-1]
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def validate_port(port: Any) -> Optional[int]:
|
|
483
|
+
"""Ensure that port can be converted to integer.
|
|
484
|
+
|
|
485
|
+
Raises:
|
|
486
|
+
RasaException if port cannot be cast to integer.
|
|
487
|
+
"""
|
|
488
|
+
if port is not None and not isinstance(port, int):
|
|
489
|
+
try:
|
|
490
|
+
port = int(port)
|
|
491
|
+
except ValueError as e:
|
|
492
|
+
raise RasaException(f"The port '{port}' cannot be cast to integer.") from e
|
|
493
|
+
|
|
494
|
+
return port
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
class FailSafeTrackerStore(TrackerStore):
|
|
498
|
+
"""Tracker store wrapper.
|
|
499
|
+
|
|
500
|
+
Allows a fallback to a different tracker store in case of errors.
|
|
501
|
+
"""
|
|
502
|
+
|
|
503
|
+
def __init__(
|
|
504
|
+
self,
|
|
505
|
+
tracker_store: TrackerStore,
|
|
506
|
+
on_tracker_store_error: Optional[Callable[[Exception], None]] = None,
|
|
507
|
+
fallback_tracker_store: Optional[TrackerStore] = None,
|
|
508
|
+
) -> None:
|
|
509
|
+
"""Create a `FailSafeTrackerStore`.
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
tracker_store: Primary tracker store.
|
|
513
|
+
on_tracker_store_error: Callback which is called when there is an error
|
|
514
|
+
in the primary tracker store.
|
|
515
|
+
fallback_tracker_store: Fallback tracker store.
|
|
516
|
+
"""
|
|
517
|
+
self._fallback_tracker_store: Optional[TrackerStore] = fallback_tracker_store
|
|
518
|
+
self._tracker_store = tracker_store
|
|
519
|
+
self._on_tracker_store_error = on_tracker_store_error
|
|
520
|
+
|
|
521
|
+
super().__init__(tracker_store.domain, tracker_store.event_broker)
|
|
522
|
+
|
|
523
|
+
@property
|
|
524
|
+
def domain(self) -> Domain:
|
|
525
|
+
"""Returns the domain of the primary tracker store."""
|
|
526
|
+
return self._tracker_store.domain
|
|
527
|
+
|
|
528
|
+
@domain.setter
|
|
529
|
+
def domain(self, domain: Domain) -> None:
|
|
530
|
+
self._tracker_store.domain = domain
|
|
531
|
+
|
|
532
|
+
if self._fallback_tracker_store:
|
|
533
|
+
self._fallback_tracker_store.domain = domain
|
|
534
|
+
|
|
535
|
+
@property
|
|
536
|
+
def fallback_tracker_store(self) -> TrackerStore:
|
|
537
|
+
"""Returns the fallback tracker store."""
|
|
538
|
+
if not self._fallback_tracker_store:
|
|
539
|
+
self._fallback_tracker_store = InMemoryTrackerStore(
|
|
540
|
+
self._tracker_store.domain, self._tracker_store.event_broker
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
return self._fallback_tracker_store
|
|
544
|
+
|
|
545
|
+
def on_tracker_store_error(self, error: Exception) -> None:
|
|
546
|
+
"""Calls the callback when there is an error in the primary tracker store."""
|
|
547
|
+
if self._on_tracker_store_error:
|
|
548
|
+
self._on_tracker_store_error(error)
|
|
549
|
+
else:
|
|
550
|
+
structlogger.error(
|
|
551
|
+
"fail_safe_tracker_store.tracker_store_error",
|
|
552
|
+
event_info=(
|
|
553
|
+
f"Error happened when trying to save conversation tracker to "
|
|
554
|
+
f"'{self._tracker_store.__class__.__name__}'. Falling back to use "
|
|
555
|
+
f"the '{InMemoryTrackerStore.__name__}'. Please "
|
|
556
|
+
f"investigate the following error: {error}."
|
|
557
|
+
),
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
async def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]:
|
|
561
|
+
"""Calls `retrieve` method of primary tracker store."""
|
|
562
|
+
try:
|
|
563
|
+
return await self._tracker_store.retrieve(sender_id)
|
|
564
|
+
except Exception as e:
|
|
565
|
+
self.on_tracker_store_retrieve_error(e)
|
|
566
|
+
return None
|
|
567
|
+
|
|
568
|
+
async def keys(self) -> Iterable[Text]:
|
|
569
|
+
"""Calls `keys` method of primary tracker store."""
|
|
570
|
+
try:
|
|
571
|
+
return await self._tracker_store.keys()
|
|
572
|
+
except Exception as e:
|
|
573
|
+
self.on_tracker_store_error(e)
|
|
574
|
+
return []
|
|
575
|
+
|
|
576
|
+
async def save(self, tracker: DialogueStateTracker) -> None:
|
|
577
|
+
"""Calls `save` method of primary tracker store."""
|
|
578
|
+
try:
|
|
579
|
+
await self._tracker_store.save(tracker)
|
|
580
|
+
except Exception as e:
|
|
581
|
+
self.on_tracker_store_error(e)
|
|
582
|
+
await self.fallback_tracker_store.save(tracker)
|
|
583
|
+
|
|
584
|
+
async def delete(self, sender_id: Text) -> None:
|
|
585
|
+
"""Delete tracker for the given sender_id."""
|
|
586
|
+
await self._tracker_store.delete(sender_id)
|
|
587
|
+
|
|
588
|
+
async def retrieve_full_tracker(
|
|
589
|
+
self, sender_id: Text
|
|
590
|
+
) -> Optional[DialogueStateTracker]:
|
|
591
|
+
"""Calls `retrieve_full_tracker` method of primary tracker store.
|
|
592
|
+
|
|
593
|
+
Args:
|
|
594
|
+
sender_id: The sender id of the tracker to retrieve.
|
|
595
|
+
"""
|
|
596
|
+
try:
|
|
597
|
+
return await self._tracker_store.retrieve_full_tracker(sender_id)
|
|
598
|
+
except Exception as e:
|
|
599
|
+
self.on_tracker_store_retrieve_error(e)
|
|
600
|
+
return None
|
|
601
|
+
|
|
602
|
+
def on_tracker_store_retrieve_error(self, error: Exception) -> None:
|
|
603
|
+
"""Calls `_on_tracker_store_error` callable attribute if set.
|
|
604
|
+
|
|
605
|
+
Otherwise, logs the error.
|
|
606
|
+
|
|
607
|
+
Args:
|
|
608
|
+
error: The error that occurred.
|
|
609
|
+
"""
|
|
610
|
+
if self._on_tracker_store_error:
|
|
611
|
+
self._on_tracker_store_error(error)
|
|
612
|
+
else:
|
|
613
|
+
structlogger.error(
|
|
614
|
+
"fail_safe_tracker_store.tracker_store_retrieve_error",
|
|
615
|
+
event_info=(
|
|
616
|
+
f"Error happened when trying to retrieve conversation tracker from "
|
|
617
|
+
f"'{self._tracker_store.__class__.__name__}'. Falling back to use "
|
|
618
|
+
f"the '{InMemoryTrackerStore.__name__}'."
|
|
619
|
+
),
|
|
620
|
+
exec_info=error,
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def _create_from_endpoint_config(
|
|
625
|
+
endpoint_config: Optional[EndpointConfig] = None,
|
|
626
|
+
domain: Optional[Domain] = None,
|
|
627
|
+
event_broker: Optional[EventBroker] = None,
|
|
628
|
+
) -> TrackerStore:
|
|
629
|
+
"""Given an endpoint configuration, create a proper tracker store object."""
|
|
630
|
+
from rasa.core.tracker_stores.dynamo_tracker_store import DynamoTrackerStore
|
|
631
|
+
from rasa.core.tracker_stores.mongo_tracker_store import MongoTrackerStore
|
|
632
|
+
from rasa.core.tracker_stores.redis_tracker_store import (
|
|
633
|
+
RedisTrackerStore,
|
|
634
|
+
)
|
|
635
|
+
from rasa.core.tracker_stores.sql_tracker_store import SQLTrackerStore
|
|
636
|
+
|
|
637
|
+
domain = domain or Domain.empty()
|
|
638
|
+
|
|
639
|
+
if endpoint_config is None or endpoint_config.type is None:
|
|
640
|
+
# default tracker store if no type is set
|
|
641
|
+
tracker_store: TrackerStore = InMemoryTrackerStore(domain, event_broker)
|
|
642
|
+
elif endpoint_config.type.lower() == "redis":
|
|
643
|
+
tracker_store = RedisTrackerStore(
|
|
644
|
+
domain=domain,
|
|
645
|
+
host=endpoint_config.url,
|
|
646
|
+
event_broker=event_broker,
|
|
647
|
+
**endpoint_config.kwargs,
|
|
648
|
+
)
|
|
649
|
+
elif endpoint_config.type.lower() == "mongod":
|
|
650
|
+
tracker_store = MongoTrackerStore(
|
|
651
|
+
domain=domain,
|
|
652
|
+
host=endpoint_config.url,
|
|
653
|
+
event_broker=event_broker,
|
|
654
|
+
**endpoint_config.kwargs,
|
|
655
|
+
)
|
|
656
|
+
elif endpoint_config.type.lower() == "sql":
|
|
657
|
+
tracker_store = SQLTrackerStore(
|
|
658
|
+
domain=domain,
|
|
659
|
+
host=endpoint_config.url,
|
|
660
|
+
event_broker=event_broker,
|
|
661
|
+
**endpoint_config.kwargs,
|
|
662
|
+
)
|
|
663
|
+
elif endpoint_config.type.lower() == "dynamo":
|
|
664
|
+
tracker_store = DynamoTrackerStore(
|
|
665
|
+
domain=domain, event_broker=event_broker, **endpoint_config.kwargs
|
|
666
|
+
)
|
|
667
|
+
else:
|
|
668
|
+
tracker_store = _load_from_module_name_in_endpoint_config(
|
|
669
|
+
domain, endpoint_config, event_broker
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
structlogger.debug(
|
|
673
|
+
"tracker_store.create_tracker_store_from_endpoint_config",
|
|
674
|
+
event_info=f"Connected to {tracker_store.__class__.__name__}.",
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
return tracker_store
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
def _load_from_module_name_in_endpoint_config(
|
|
681
|
+
domain: Domain, store: EndpointConfig, event_broker: Optional[EventBroker] = None
|
|
682
|
+
) -> TrackerStore:
|
|
683
|
+
"""Initializes a custom tracker.
|
|
684
|
+
|
|
685
|
+
Defaults to the InMemoryTrackerStore if the module path can not be found.
|
|
686
|
+
|
|
687
|
+
Args:
|
|
688
|
+
domain: defines the universe in which the assistant operates
|
|
689
|
+
store: the specific tracker store
|
|
690
|
+
event_broker: an event broker to publish events
|
|
691
|
+
|
|
692
|
+
Returns:
|
|
693
|
+
a tracker store from a specified type in a stores endpoint configuration
|
|
694
|
+
"""
|
|
695
|
+
try:
|
|
696
|
+
tracker_store_class = rasa.shared.utils.common.class_from_module_path(
|
|
697
|
+
store.type
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
return tracker_store_class(
|
|
701
|
+
host=store.url, domain=domain, event_broker=event_broker, **store.kwargs
|
|
702
|
+
)
|
|
703
|
+
except (AttributeError, ImportError):
|
|
704
|
+
rasa.shared.utils.io.raise_warning(
|
|
705
|
+
f"Tracker store with type '{store.type}' not found. "
|
|
706
|
+
f"Using `InMemoryTrackerStore` instead."
|
|
707
|
+
)
|
|
708
|
+
return InMemoryTrackerStore(domain)
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
def create_tracker_store(
|
|
712
|
+
endpoint_config: Optional[EndpointConfig],
|
|
713
|
+
domain: Optional[Domain] = None,
|
|
714
|
+
event_broker: Optional[EventBroker] = None,
|
|
715
|
+
) -> TrackerStore:
|
|
716
|
+
"""Creates a tracker store based on the current configuration."""
|
|
717
|
+
tracker_store = _create_from_endpoint_config(endpoint_config, domain, event_broker)
|
|
718
|
+
|
|
719
|
+
if not check_if_tracker_store_async(tracker_store):
|
|
720
|
+
rasa.shared.utils.io.raise_deprecation_warning(
|
|
721
|
+
f"Tracker store implementation "
|
|
722
|
+
f"{tracker_store.__class__.__name__} "
|
|
723
|
+
f"is not asynchronous. Non-asynchronous tracker stores "
|
|
724
|
+
f"are currently deprecated and will be removed in 4.0. "
|
|
725
|
+
f"Please make the following methods async: "
|
|
726
|
+
f"{_get_async_tracker_store_methods()}"
|
|
727
|
+
)
|
|
728
|
+
tracker_store = AwaitableTrackerStore(tracker_store)
|
|
729
|
+
|
|
730
|
+
return tracker_store
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
class AwaitableTrackerStore(TrackerStore):
|
|
734
|
+
"""Wraps a tracker store so it can be implemented with async overrides."""
|
|
735
|
+
|
|
736
|
+
def __init__(
|
|
737
|
+
self,
|
|
738
|
+
tracker_store: TrackerStore,
|
|
739
|
+
) -> None:
|
|
740
|
+
"""Create a `AwaitableTrackerStore`.
|
|
741
|
+
|
|
742
|
+
Args:
|
|
743
|
+
tracker_store: the wrapped tracker store.
|
|
744
|
+
"""
|
|
745
|
+
self._tracker_store = tracker_store
|
|
746
|
+
|
|
747
|
+
super().__init__(tracker_store.domain, tracker_store.event_broker)
|
|
748
|
+
|
|
749
|
+
@property
|
|
750
|
+
def domain(self) -> Domain:
|
|
751
|
+
"""Returns the domain of the primary tracker store."""
|
|
752
|
+
return self._tracker_store.domain
|
|
753
|
+
|
|
754
|
+
@domain.setter
|
|
755
|
+
def domain(self, domain: Optional[Domain]) -> None:
|
|
756
|
+
"""Setter method to modify the wrapped tracker store's domain field."""
|
|
757
|
+
self._tracker_store.domain = domain or Domain.empty()
|
|
758
|
+
|
|
759
|
+
@staticmethod
|
|
760
|
+
def create(
|
|
761
|
+
obj: Union[TrackerStore, EndpointConfig, None],
|
|
762
|
+
domain: Optional[Domain] = None,
|
|
763
|
+
event_broker: Optional[EventBroker] = None,
|
|
764
|
+
) -> TrackerStore:
|
|
765
|
+
"""Wrapper to call `create` method of primary tracker store."""
|
|
766
|
+
if isinstance(obj, TrackerStore):
|
|
767
|
+
return AwaitableTrackerStore(obj)
|
|
768
|
+
elif isinstance(obj, EndpointConfig):
|
|
769
|
+
return AwaitableTrackerStore(_create_from_endpoint_config(obj))
|
|
770
|
+
else:
|
|
771
|
+
raise ValueError(
|
|
772
|
+
f"{type(obj).__name__} supplied "
|
|
773
|
+
f"but expected object of type {TrackerStore.__name__} or "
|
|
774
|
+
f"of type {EndpointConfig.__name__}."
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
async def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]:
|
|
778
|
+
"""Wrapper to call `retrieve` method of primary tracker store."""
|
|
779
|
+
result = self._tracker_store.retrieve(sender_id)
|
|
780
|
+
return (
|
|
781
|
+
await result if isawaitable(result) else result # type: ignore[return-value, misc]
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
async def keys(self) -> Iterable[Text]:
|
|
785
|
+
"""Wrapper to call `keys` method of primary tracker store."""
|
|
786
|
+
result = self._tracker_store.keys()
|
|
787
|
+
return await result if isawaitable(result) else result
|
|
788
|
+
|
|
789
|
+
async def save(self, tracker: DialogueStateTracker) -> None:
|
|
790
|
+
"""Wrapper to call `save` method of primary tracker store."""
|
|
791
|
+
result = self._tracker_store.save(tracker)
|
|
792
|
+
return await result if isawaitable(result) else result
|
|
793
|
+
|
|
794
|
+
async def delete(self, sender_id: Text) -> None:
|
|
795
|
+
"""Delete tracker for the given sender_id."""
|
|
796
|
+
await self._tracker_store.delete(sender_id)
|
|
797
|
+
|
|
798
|
+
async def retrieve_full_tracker(
|
|
799
|
+
self, conversation_id: Text
|
|
800
|
+
) -> Optional[DialogueStateTracker]:
|
|
801
|
+
"""Wrapper to call `retrieve_full_tracker` method of primary tracker store."""
|
|
802
|
+
result = self._tracker_store.retrieve_full_tracker(conversation_id)
|
|
803
|
+
return (
|
|
804
|
+
await result if isawaitable(result) else result # type: ignore[return-value, misc]
|
|
805
|
+
)
|