rasa-pro 3.12.18__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/__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 +43 -29
- 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 +56 -17
- rasa/core/processor.py +64 -49
- 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 +9 -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 +4 -0
- rasa/dialogue_understanding/commands/skip_question_command.py +2 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +4 -0
- 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 +1 -2
- 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 -461
- 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/utils.py +3 -1
- 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/du_test_schema.yml +3 -3
- rasa/dialogue_understanding_test/io.py +35 -8
- rasa/e2e_test/e2e_test_runner.py +1 -1
- rasa/e2e_test/e2e_test_schema.yml +3 -3
- 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 -30
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +1 -5
- 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 +14 -0
- 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/llm/default_litellm_llm_client.py +2 -2
- 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 +47 -9
- 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.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/METADATA +12 -13
- {rasa_pro-3.12.18.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/RECORD +308 -283
- 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/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.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.18.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.18.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/entry_points.txt +0 -0
rasa/shared/core/domain.py
CHANGED
|
@@ -32,6 +32,7 @@ from ruamel.yaml.scalarstring import DoubleQuotedScalarString
|
|
|
32
32
|
import rasa.shared.core.slot_mappings
|
|
33
33
|
import rasa.shared.utils.common
|
|
34
34
|
import rasa.shared.utils.io
|
|
35
|
+
from rasa.core.available_endpoints import AvailableEndpoints
|
|
35
36
|
from rasa.shared.constants import (
|
|
36
37
|
DEFAULT_CARRY_OVER_SLOTS_TO_NEW_SESSION,
|
|
37
38
|
DEFAULT_SESSION_EXPIRATION_TIME_IN_MINUTES,
|
|
@@ -48,6 +49,7 @@ from rasa.shared.core.constants import (
|
|
|
48
49
|
ACTION_SHOULD_SEND_DOMAIN,
|
|
49
50
|
KEY_MAPPING_TYPE,
|
|
50
51
|
KNOWLEDGE_BASE_SLOT_NAMES,
|
|
52
|
+
SILENCE_TIMEOUT_SLOT,
|
|
51
53
|
SLOT_MAPPINGS,
|
|
52
54
|
SlotMappingType,
|
|
53
55
|
)
|
|
@@ -134,6 +136,22 @@ ALL_DOMAIN_KEYS = [
|
|
|
134
136
|
|
|
135
137
|
PREV_PREFIX = "prev_"
|
|
136
138
|
|
|
139
|
+
MERGE_FUNC_MAPPING: Dict[Text, Callable[..., Any]] = {
|
|
140
|
+
KEY_ACTIONS: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
141
|
+
KEY_RESPONSES: rasa.shared.utils.common.merge_dicts,
|
|
142
|
+
KEY_SLOTS: rasa.shared.utils.common.merge_dicts,
|
|
143
|
+
KEY_INTENTS: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
144
|
+
KEY_ENTITIES: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
145
|
+
KEY_E2E_ACTIONS: rasa.shared.utils.common.merge_lists,
|
|
146
|
+
KEY_FORMS: rasa.shared.utils.common.merge_dicts,
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
DICT_DATA_KEYS = [
|
|
150
|
+
key
|
|
151
|
+
for key, value in MERGE_FUNC_MAPPING.items()
|
|
152
|
+
if value == rasa.shared.utils.common.merge_dicts
|
|
153
|
+
]
|
|
154
|
+
|
|
137
155
|
# State is a dictionary with keys (USER, PREVIOUS_ACTION, SLOTS, ACTIVE_LOOP)
|
|
138
156
|
# representing the origin of a SubState;
|
|
139
157
|
# the values are SubStates, that contain the information needed for featurization
|
|
@@ -290,6 +308,11 @@ class Domain:
|
|
|
290
308
|
responses = data.get(KEY_RESPONSES, {})
|
|
291
309
|
|
|
292
310
|
domain_slots = data.get(KEY_SLOTS, {})
|
|
311
|
+
for slot_name, slot in domain_slots.items():
|
|
312
|
+
if slot_name == SILENCE_TIMEOUT_SLOT:
|
|
313
|
+
slot["initial_value"] = (
|
|
314
|
+
AvailableEndpoints.get_instance().interaction_handling.global_silence_timeout
|
|
315
|
+
)
|
|
293
316
|
slots = cls.collect_slots(domain_slots)
|
|
294
317
|
domain_actions = data.get(KEY_ACTIONS, [])
|
|
295
318
|
actions = cls._collect_action_names(domain_actions)
|
|
@@ -466,17 +489,7 @@ class Domain:
|
|
|
466
489
|
|
|
467
490
|
duplicates: Dict[Text, List[Text]] = {}
|
|
468
491
|
|
|
469
|
-
|
|
470
|
-
KEY_INTENTS: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
471
|
-
KEY_ENTITIES: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
472
|
-
KEY_ACTIONS: rasa.shared.utils.common.merge_lists_of_dicts,
|
|
473
|
-
KEY_E2E_ACTIONS: rasa.shared.utils.common.merge_lists,
|
|
474
|
-
KEY_FORMS: rasa.shared.utils.common.merge_dicts,
|
|
475
|
-
KEY_RESPONSES: rasa.shared.utils.common.merge_dicts,
|
|
476
|
-
KEY_SLOTS: rasa.shared.utils.common.merge_dicts,
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
for key, merge_func in merge_func_mappings.items():
|
|
492
|
+
for key, merge_func in MERGE_FUNC_MAPPING.items():
|
|
480
493
|
duplicates[key] = rasa.shared.utils.common.extract_duplicates(
|
|
481
494
|
combined.get(key, []), domain_dict.get(key, [])
|
|
482
495
|
)
|
|
@@ -494,6 +507,74 @@ class Domain:
|
|
|
494
507
|
|
|
495
508
|
return combined
|
|
496
509
|
|
|
510
|
+
def partial_merge(self, other: Domain) -> Domain:
|
|
511
|
+
"""
|
|
512
|
+
Returns a new Domain with intersection-based merging:
|
|
513
|
+
- For each domain section only overwrite items that already exist in self.
|
|
514
|
+
- Brand-new items in `other` are ignored.
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
other: The domain to merge with.
|
|
518
|
+
|
|
519
|
+
Returns:
|
|
520
|
+
A new Domain object with the merged content.
|
|
521
|
+
"""
|
|
522
|
+
updated_self = copy.deepcopy(self.as_dict())
|
|
523
|
+
other_dict = other.as_dict()
|
|
524
|
+
|
|
525
|
+
keys_to_merge = MERGE_FUNC_MAPPING.keys()
|
|
526
|
+
for key in keys_to_merge:
|
|
527
|
+
if key in DICT_DATA_KEYS:
|
|
528
|
+
# Merge dictionaries
|
|
529
|
+
self_val = updated_self.get(key, {})
|
|
530
|
+
other_val = other_dict.get(key, {})
|
|
531
|
+
updated_self[key] = rasa.shared.utils.common.partial_merge_dict(
|
|
532
|
+
self_val, other_val
|
|
533
|
+
)
|
|
534
|
+
else:
|
|
535
|
+
# Merge lists
|
|
536
|
+
self_val = updated_self.get(key, [])
|
|
537
|
+
other_val = other_dict.get(key, [])
|
|
538
|
+
is_same_item_fn = SAME_ITEM_FUNCTIONS.get(key, default_is_same_item)
|
|
539
|
+
updated_self[key] = rasa.shared.utils.common.partial_merge_list(
|
|
540
|
+
self_val, other_val, is_same_item_fn
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
return Domain.from_dict(updated_self)
|
|
544
|
+
|
|
545
|
+
def difference(self, other: Domain) -> Domain:
|
|
546
|
+
"""
|
|
547
|
+
Returns a new Domain containing items in `self` that are NOT in `other`,
|
|
548
|
+
using simple equality checks for dict/list items.
|
|
549
|
+
|
|
550
|
+
Args:
|
|
551
|
+
other: The domain to compare with.
|
|
552
|
+
|
|
553
|
+
Returns:
|
|
554
|
+
A new Domain object with the difference content.
|
|
555
|
+
"""
|
|
556
|
+
self_dict = self.as_dict()
|
|
557
|
+
other_dict = other.as_dict()
|
|
558
|
+
|
|
559
|
+
difference_dict = {}
|
|
560
|
+
for key in MERGE_FUNC_MAPPING.keys():
|
|
561
|
+
is_dict = key in DICT_DATA_KEYS
|
|
562
|
+
self_val = self_dict.get(key, {} if is_dict else [])
|
|
563
|
+
other_val = other_dict.get(key, {} if is_dict else [])
|
|
564
|
+
|
|
565
|
+
if is_dict and isinstance(self_val, dict) and isinstance(other_val, dict):
|
|
566
|
+
difference_dict[key] = {
|
|
567
|
+
k: v
|
|
568
|
+
for k, v in self_val.items()
|
|
569
|
+
if k not in other_val or v != other_val[k]
|
|
570
|
+
}
|
|
571
|
+
else:
|
|
572
|
+
difference_dict[key] = [
|
|
573
|
+
item for item in self_val if item not in other_val
|
|
574
|
+
] # type: ignore[assignment]
|
|
575
|
+
|
|
576
|
+
return Domain.from_dict(difference_dict)
|
|
577
|
+
|
|
497
578
|
def _preprocess_domain_dict(
|
|
498
579
|
self,
|
|
499
580
|
data: Dict,
|
|
@@ -2120,6 +2201,11 @@ class Domain:
|
|
|
2120
2201
|
"""Remove all builtin slots from the domain."""
|
|
2121
2202
|
self.slots = [slot for slot in self.slots if not slot.is_builtin]
|
|
2122
2203
|
|
|
2204
|
+
def __eq__(self, other: object) -> bool:
|
|
2205
|
+
if isinstance(other, Domain):
|
|
2206
|
+
return self.as_dict() == other.as_dict()
|
|
2207
|
+
return False
|
|
2208
|
+
|
|
2123
2209
|
|
|
2124
2210
|
def warn_about_duplicates_found_during_domain_merging(
|
|
2125
2211
|
duplicates: Dict[Text, List[Text]],
|
|
@@ -2178,3 +2264,78 @@ def _validate_forms(forms: Union[Dict, List]) -> None:
|
|
|
2178
2264
|
f"the keyword `{REQUIRED_SLOTS_KEY}` is required. "
|
|
2179
2265
|
f"Please see {DOCS_URL_FORMS} for more information."
|
|
2180
2266
|
)
|
|
2267
|
+
|
|
2268
|
+
|
|
2269
|
+
def is_same_entity(e1: Any, e2: Any) -> bool:
|
|
2270
|
+
"""Check if two entities are the 'same' (string or dict).
|
|
2271
|
+
|
|
2272
|
+
Args:
|
|
2273
|
+
e1: First entity to compare.
|
|
2274
|
+
e2: Second entity to compare.
|
|
2275
|
+
|
|
2276
|
+
Returns:
|
|
2277
|
+
True if the entities are the same, False otherwise.
|
|
2278
|
+
"""
|
|
2279
|
+
if isinstance(e1, str) and isinstance(e2, str):
|
|
2280
|
+
return e1 == e2
|
|
2281
|
+
|
|
2282
|
+
if isinstance(e1, dict) and isinstance(e2, dict):
|
|
2283
|
+
return (
|
|
2284
|
+
e1.get(ENTITY_ATTRIBUTE_TYPE) == e2.get(ENTITY_ATTRIBUTE_TYPE)
|
|
2285
|
+
and e1.get(ENTITY_ATTRIBUTE_ROLE) == e2.get(ENTITY_ATTRIBUTE_ROLE)
|
|
2286
|
+
and e1.get(ENTITY_ATTRIBUTE_GROUP) == e2.get(ENTITY_ATTRIBUTE_GROUP)
|
|
2287
|
+
)
|
|
2288
|
+
|
|
2289
|
+
return False
|
|
2290
|
+
|
|
2291
|
+
|
|
2292
|
+
def is_same_intent(i1: Any, i2: Any) -> bool:
|
|
2293
|
+
"""Check if two intents are the 'same' (string or dict).
|
|
2294
|
+
|
|
2295
|
+
Args:
|
|
2296
|
+
i1: First intent to compare.
|
|
2297
|
+
i2: Second intent to compare.
|
|
2298
|
+
|
|
2299
|
+
Returns:
|
|
2300
|
+
True if the intents are the same, False otherwise.
|
|
2301
|
+
"""
|
|
2302
|
+
if isinstance(i1, str) and isinstance(i2, str):
|
|
2303
|
+
return i1 == i2
|
|
2304
|
+
|
|
2305
|
+
if isinstance(i1, dict) and isinstance(i2, dict):
|
|
2306
|
+
key1, key2 = next(iter(i1.keys())), next(iter((i2.keys())))
|
|
2307
|
+
return key1 == key2
|
|
2308
|
+
|
|
2309
|
+
return False
|
|
2310
|
+
|
|
2311
|
+
|
|
2312
|
+
def is_same_action(a1: Any, a2: Any) -> bool:
|
|
2313
|
+
"""Check if two actions are the 'same' (string or dict).
|
|
2314
|
+
|
|
2315
|
+
Args:
|
|
2316
|
+
a1: First action to compare.
|
|
2317
|
+
a2: Second action to compare.
|
|
2318
|
+
|
|
2319
|
+
Returns:
|
|
2320
|
+
True if the actions are the same, False otherwise.
|
|
2321
|
+
"""
|
|
2322
|
+
if isinstance(a1, str) and isinstance(a2, str):
|
|
2323
|
+
return a1 == a2
|
|
2324
|
+
|
|
2325
|
+
if isinstance(a1, dict) and isinstance(a2, dict):
|
|
2326
|
+
key1, key2 = next(iter((a1.keys()))), next(iter((a2.keys())))
|
|
2327
|
+
return key1 == key2
|
|
2328
|
+
|
|
2329
|
+
return False
|
|
2330
|
+
|
|
2331
|
+
|
|
2332
|
+
def default_is_same_item(a: Any, b: Any) -> bool:
|
|
2333
|
+
"""Fallback exact equality check if a key doesn't need special handling."""
|
|
2334
|
+
return a == b
|
|
2335
|
+
|
|
2336
|
+
|
|
2337
|
+
SAME_ITEM_FUNCTIONS: Dict[Text, Callable[[Any, Any], bool]] = {
|
|
2338
|
+
KEY_ENTITIES: is_same_entity,
|
|
2339
|
+
KEY_INTENTS: is_same_intent,
|
|
2340
|
+
KEY_ACTIONS: is_same_action,
|
|
2341
|
+
}
|
rasa/shared/core/events.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import abc
|
|
2
4
|
import copy
|
|
3
5
|
import json
|
|
@@ -6,7 +8,7 @@ import re
|
|
|
6
8
|
import time
|
|
7
9
|
import uuid
|
|
8
10
|
from abc import ABC
|
|
9
|
-
from datetime import datetime
|
|
11
|
+
from datetime import datetime, timezone
|
|
10
12
|
from typing import (
|
|
11
13
|
TYPE_CHECKING,
|
|
12
14
|
Any,
|
|
@@ -107,6 +109,8 @@ if TYPE_CHECKING:
|
|
|
107
109
|
logger = logging.getLogger(__name__)
|
|
108
110
|
structlogger = structlog.get_logger()
|
|
109
111
|
|
|
112
|
+
INVALID_DATETIME_ERROR_MESSAGE = "`anonymized_at` must be a datetime object."
|
|
113
|
+
|
|
110
114
|
|
|
111
115
|
def deserialise_events(serialized_events: List[Dict[Text, Any]]) -> List["Event"]:
|
|
112
116
|
"""Convert a list of dictionaries to a list of corresponding events.
|
|
@@ -122,9 +126,7 @@ def deserialise_events(serialized_events: List[Dict[Text, Any]]) -> List["Event"
|
|
|
122
126
|
if event:
|
|
123
127
|
deserialised.append(event)
|
|
124
128
|
else:
|
|
125
|
-
structlogger.warning(
|
|
126
|
-
"event.deserialization.failed", rasa_event=copy.deepcopy(event)
|
|
127
|
-
)
|
|
129
|
+
structlogger.warning("event.deserialization.failed")
|
|
128
130
|
|
|
129
131
|
return deserialised
|
|
130
132
|
|
|
@@ -451,6 +453,7 @@ class UserUttered(Event):
|
|
|
451
453
|
message_id: Optional[Text] = None,
|
|
452
454
|
metadata: Optional[Dict] = None,
|
|
453
455
|
use_text_for_featurization: Optional[bool] = None,
|
|
456
|
+
anonymized_at: Optional[float] = None,
|
|
454
457
|
) -> None:
|
|
455
458
|
"""Creates event for incoming user message.
|
|
456
459
|
|
|
@@ -465,6 +468,7 @@ class UserUttered(Event):
|
|
|
465
468
|
message_id: Unique ID for message.
|
|
466
469
|
use_text_for_featurization: `True` if the message's text was used to predict
|
|
467
470
|
next action. `False` if the message's intent was used.
|
|
471
|
+
anonymized_at: When the event was anonymized in the tracker store.
|
|
468
472
|
|
|
469
473
|
"""
|
|
470
474
|
self.text = text
|
|
@@ -498,6 +502,27 @@ class UserUttered(Event):
|
|
|
498
502
|
if parse_data:
|
|
499
503
|
self.parse_data.update(**parse_data)
|
|
500
504
|
|
|
505
|
+
self._anonymized_at: Optional[datetime] = (
|
|
506
|
+
datetime.fromtimestamp(anonymized_at, tz=timezone.utc)
|
|
507
|
+
if anonymized_at is not None
|
|
508
|
+
else None
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
@property
|
|
512
|
+
def anonymized_at(self) -> Optional[datetime]:
|
|
513
|
+
"""Returns the time when the event was anonymized in the tracker store.
|
|
514
|
+
|
|
515
|
+
If the event was not anonymized, it returns None.
|
|
516
|
+
"""
|
|
517
|
+
return self._anonymized_at
|
|
518
|
+
|
|
519
|
+
@anonymized_at.setter
|
|
520
|
+
def anonymized_at(self, value: Optional[datetime]) -> None:
|
|
521
|
+
"""Sets the time when the event was anonymized in the tracker store."""
|
|
522
|
+
if value is not None and not isinstance(value, datetime):
|
|
523
|
+
raise ValueError(INVALID_DATETIME_ERROR_MESSAGE)
|
|
524
|
+
self._anonymized_at = value
|
|
525
|
+
|
|
501
526
|
@staticmethod
|
|
502
527
|
def _from_parse_data(
|
|
503
528
|
text: Text,
|
|
@@ -506,6 +531,7 @@ class UserUttered(Event):
|
|
|
506
531
|
input_channel: Optional[Text] = None,
|
|
507
532
|
message_id: Optional[Text] = None,
|
|
508
533
|
metadata: Optional[Dict] = None,
|
|
534
|
+
anonymized_at: Optional[float] = None,
|
|
509
535
|
) -> "UserUttered":
|
|
510
536
|
return UserUttered(
|
|
511
537
|
text,
|
|
@@ -516,6 +542,7 @@ class UserUttered(Event):
|
|
|
516
542
|
input_channel,
|
|
517
543
|
message_id,
|
|
518
544
|
metadata,
|
|
545
|
+
anonymized_at,
|
|
519
546
|
)
|
|
520
547
|
|
|
521
548
|
def __hash__(self) -> int:
|
|
@@ -614,6 +641,9 @@ class UserUttered(Event):
|
|
|
614
641
|
"input_channel": getattr(self, "input_channel", None),
|
|
615
642
|
"message_id": getattr(self, "message_id", None),
|
|
616
643
|
"metadata": self.metadata,
|
|
644
|
+
"anonymized_at": self.anonymized_at.timestamp()
|
|
645
|
+
if self.anonymized_at
|
|
646
|
+
else None,
|
|
617
647
|
}
|
|
618
648
|
)
|
|
619
649
|
return _dict
|
|
@@ -673,6 +703,7 @@ class UserUttered(Event):
|
|
|
673
703
|
parameters.get("input_channel"),
|
|
674
704
|
parameters.get("message_id"),
|
|
675
705
|
parameters.get("metadata"),
|
|
706
|
+
parameters.get("anonymized_at"),
|
|
676
707
|
)
|
|
677
708
|
]
|
|
678
709
|
except KeyError as e:
|
|
@@ -900,6 +931,7 @@ class BotUttered(SkipEventInMDStoryMixin):
|
|
|
900
931
|
data: Optional[Dict] = None,
|
|
901
932
|
metadata: Optional[Dict[Text, Any]] = None,
|
|
902
933
|
timestamp: Optional[float] = None,
|
|
934
|
+
anonymized_at: Optional[float] = None,
|
|
903
935
|
) -> None:
|
|
904
936
|
"""Creates event for a bot response.
|
|
905
937
|
|
|
@@ -908,11 +940,32 @@ class BotUttered(SkipEventInMDStoryMixin):
|
|
|
908
940
|
data: Additional data for more complex utterances (e.g. buttons).
|
|
909
941
|
timestamp: When the event was created.
|
|
910
942
|
metadata: Additional event metadata.
|
|
943
|
+
anonymized_at: When the event was anonymized in the tracker store.
|
|
911
944
|
"""
|
|
912
945
|
self.text = text
|
|
913
946
|
self.data = data or {}
|
|
947
|
+
self._anonymized_at: Optional[datetime] = (
|
|
948
|
+
datetime.fromtimestamp(anonymized_at, tz=timezone.utc)
|
|
949
|
+
if anonymized_at is not None
|
|
950
|
+
else None
|
|
951
|
+
)
|
|
914
952
|
super().__init__(timestamp, metadata)
|
|
915
953
|
|
|
954
|
+
@property
|
|
955
|
+
def anonymized_at(self) -> Optional[datetime]:
|
|
956
|
+
"""Returns the time when the event was anonymized in the tracker store.
|
|
957
|
+
|
|
958
|
+
If the event was not anonymized, it returns None.
|
|
959
|
+
"""
|
|
960
|
+
return self._anonymized_at
|
|
961
|
+
|
|
962
|
+
@anonymized_at.setter
|
|
963
|
+
def anonymized_at(self, value: Optional[datetime]) -> None:
|
|
964
|
+
"""Sets the time when the event was anonymized in the tracker store."""
|
|
965
|
+
if value is not None and not isinstance(value, datetime):
|
|
966
|
+
raise ValueError(INVALID_DATETIME_ERROR_MESSAGE)
|
|
967
|
+
self._anonymized_at = value
|
|
968
|
+
|
|
916
969
|
def __members(self) -> Tuple[Optional[Text], Text, Text]:
|
|
917
970
|
data_no_nones = {k: v for k, v in self.data.items() if v is not None}
|
|
918
971
|
meta_no_nones = {k: v for k, v in self.metadata.items() if v is not None}
|
|
@@ -999,7 +1052,16 @@ class BotUttered(SkipEventInMDStoryMixin):
|
|
|
999
1052
|
def as_dict(self) -> Dict[Text, Any]:
|
|
1000
1053
|
"""Returns serialized event."""
|
|
1001
1054
|
d = super().as_dict()
|
|
1002
|
-
d.update(
|
|
1055
|
+
d.update(
|
|
1056
|
+
{
|
|
1057
|
+
"text": self.text,
|
|
1058
|
+
"data": self.data,
|
|
1059
|
+
"metadata": self.metadata,
|
|
1060
|
+
"anonymized_at": self.anonymized_at.timestamp()
|
|
1061
|
+
if self.anonymized_at
|
|
1062
|
+
else None,
|
|
1063
|
+
}
|
|
1064
|
+
)
|
|
1003
1065
|
return d
|
|
1004
1066
|
|
|
1005
1067
|
@classmethod
|
|
@@ -1010,6 +1072,7 @@ class BotUttered(SkipEventInMDStoryMixin):
|
|
|
1010
1072
|
parameters.get("data"),
|
|
1011
1073
|
parameters.get("metadata"),
|
|
1012
1074
|
parameters.get("timestamp"),
|
|
1075
|
+
parameters.get("anonymized_at"),
|
|
1013
1076
|
)
|
|
1014
1077
|
except KeyError as e:
|
|
1015
1078
|
raise ValueError(f"Failed to parse bot uttered event. {e}")
|
|
@@ -1034,6 +1097,7 @@ class SlotSet(Event):
|
|
|
1034
1097
|
timestamp: Optional[float] = None,
|
|
1035
1098
|
metadata: Optional[Dict[Text, Any]] = None,
|
|
1036
1099
|
filled_by: Optional[str] = None,
|
|
1100
|
+
anonymized_at: Optional[float] = None,
|
|
1037
1101
|
) -> None:
|
|
1038
1102
|
"""Creates event to set slot.
|
|
1039
1103
|
|
|
@@ -1046,8 +1110,28 @@ class SlotSet(Event):
|
|
|
1046
1110
|
self.key = key
|
|
1047
1111
|
self.value = value
|
|
1048
1112
|
self._filled_by = filled_by
|
|
1113
|
+
self._anonymized_at: Optional[datetime] = (
|
|
1114
|
+
datetime.fromtimestamp(anonymized_at, tz=timezone.utc)
|
|
1115
|
+
if anonymized_at is not None
|
|
1116
|
+
else None
|
|
1117
|
+
)
|
|
1049
1118
|
super().__init__(timestamp, metadata)
|
|
1050
1119
|
|
|
1120
|
+
@property
|
|
1121
|
+
def anonymized_at(self) -> Optional[datetime]:
|
|
1122
|
+
"""Returns the time when the event was anonymized in the tracker store.
|
|
1123
|
+
|
|
1124
|
+
If the event was not anonymized, it returns None.
|
|
1125
|
+
"""
|
|
1126
|
+
return self._anonymized_at
|
|
1127
|
+
|
|
1128
|
+
@anonymized_at.setter
|
|
1129
|
+
def anonymized_at(self, value: Optional[datetime]) -> None:
|
|
1130
|
+
"""Sets the time when the event was anonymized in the tracker store."""
|
|
1131
|
+
if value is not None and not isinstance(value, datetime):
|
|
1132
|
+
raise ValueError(INVALID_DATETIME_ERROR_MESSAGE)
|
|
1133
|
+
self._anonymized_at = value
|
|
1134
|
+
|
|
1051
1135
|
def __repr__(self) -> Text:
|
|
1052
1136
|
"""Returns text representation of event."""
|
|
1053
1137
|
return f"SlotSet(key: {self.key}, value: {self.value})"
|
|
@@ -1092,7 +1176,16 @@ class SlotSet(Event):
|
|
|
1092
1176
|
def as_dict(self) -> Dict[Text, Any]:
|
|
1093
1177
|
"""Returns serialized event."""
|
|
1094
1178
|
d = super().as_dict()
|
|
1095
|
-
d.update(
|
|
1179
|
+
d.update(
|
|
1180
|
+
{
|
|
1181
|
+
"name": self.key,
|
|
1182
|
+
"value": self.value,
|
|
1183
|
+
"filled_by": self.filled_by,
|
|
1184
|
+
"anonymized_at": self.anonymized_at.timestamp()
|
|
1185
|
+
if self.anonymized_at
|
|
1186
|
+
else None,
|
|
1187
|
+
}
|
|
1188
|
+
)
|
|
1096
1189
|
return d
|
|
1097
1190
|
|
|
1098
1191
|
@classmethod
|
|
@@ -1104,6 +1197,7 @@ class SlotSet(Event):
|
|
|
1104
1197
|
parameters.get("timestamp"),
|
|
1105
1198
|
parameters.get("metadata"),
|
|
1106
1199
|
filled_by=parameters.get("filled_by"),
|
|
1200
|
+
anonymized_at=parameters.get("anonymized_at"),
|
|
1107
1201
|
)
|
|
1108
1202
|
except KeyError as e:
|
|
1109
1203
|
raise ValueError(f"Failed to parse set slot event. {e}")
|
rasa/shared/core/flows/flow.py
CHANGED
|
@@ -53,6 +53,8 @@ from rasa.shared.core.slots import Slot
|
|
|
53
53
|
|
|
54
54
|
structlogger = structlog.get_logger()
|
|
55
55
|
|
|
56
|
+
DEFAULT_RUN_PATTERN_COMPLETED = True
|
|
57
|
+
|
|
56
58
|
|
|
57
59
|
class FlowLanguageTranslation(BaseModel):
|
|
58
60
|
"""Represents the translation of the flow properties in a specific language."""
|
|
@@ -61,8 +63,15 @@ class FlowLanguageTranslation(BaseModel):
|
|
|
61
63
|
"""The human-readable name of the flow."""
|
|
62
64
|
|
|
63
65
|
class Config:
|
|
66
|
+
"""Config for the FlowLanguageTranslation class."""
|
|
67
|
+
|
|
64
68
|
extra = "ignore"
|
|
65
69
|
|
|
70
|
+
def __eq__(self, other: object) -> bool:
|
|
71
|
+
if isinstance(other, FlowLanguageTranslation):
|
|
72
|
+
return self.name == other.name
|
|
73
|
+
return False
|
|
74
|
+
|
|
66
75
|
|
|
67
76
|
@dataclass
|
|
68
77
|
class Flow:
|
|
@@ -90,8 +99,25 @@ class Flow:
|
|
|
90
99
|
"""The path to the file where the flow is stored."""
|
|
91
100
|
persisted_slots: List[str] = field(default_factory=list)
|
|
92
101
|
"""The list of slots that should be persisted after the flow ends."""
|
|
93
|
-
run_pattern_completed: bool =
|
|
102
|
+
run_pattern_completed: bool = DEFAULT_RUN_PATTERN_COMPLETED
|
|
94
103
|
"""Whether the pattern_completed flow should be run after the flow ends."""
|
|
104
|
+
metadata: Dict[Text, Any] = field(default_factory=dict)
|
|
105
|
+
|
|
106
|
+
def __eq__(self, other: object) -> bool:
|
|
107
|
+
if isinstance(other, Flow):
|
|
108
|
+
return (
|
|
109
|
+
self.id == other.id
|
|
110
|
+
and self.custom_name == other.custom_name
|
|
111
|
+
and self.description == other.description
|
|
112
|
+
and self.translation == other.translation
|
|
113
|
+
and self.guard_condition == other.guard_condition
|
|
114
|
+
and self.step_sequence == other.step_sequence
|
|
115
|
+
and self.nlu_triggers == other.nlu_triggers
|
|
116
|
+
and self.always_include_in_prompt == other.always_include_in_prompt
|
|
117
|
+
and self.persisted_slots == other.persisted_slots
|
|
118
|
+
and self.run_pattern_completed == other.run_pattern_completed
|
|
119
|
+
)
|
|
120
|
+
return False
|
|
95
121
|
|
|
96
122
|
@staticmethod
|
|
97
123
|
def from_json(
|
|
@@ -130,7 +156,9 @@ class Flow:
|
|
|
130
156
|
# data. When the model is trained, take the provided file_path.
|
|
131
157
|
file_path=data.get(KEY_FILE_PATH) if KEY_FILE_PATH in data else file_path,
|
|
132
158
|
persisted_slots=data.get(KEY_PERSISTED_SLOTS, []),
|
|
133
|
-
run_pattern_completed=data.get(
|
|
159
|
+
run_pattern_completed=data.get(
|
|
160
|
+
KEY_RUN_PATTERN_COMPLETED, DEFAULT_RUN_PATTERN_COMPLETED
|
|
161
|
+
),
|
|
134
162
|
translation=extract_translations(
|
|
135
163
|
translation_data=data.get(KEY_TRANSLATION, {})
|
|
136
164
|
),
|
|
@@ -209,7 +237,7 @@ class Flow:
|
|
|
209
237
|
if self.persisted_slots:
|
|
210
238
|
data[KEY_PERSISTED_SLOTS] = self.persisted_slots
|
|
211
239
|
if self.run_pattern_completed is not None:
|
|
212
|
-
data[
|
|
240
|
+
data[KEY_RUN_PATTERN_COMPLETED] = self.run_pattern_completed
|
|
213
241
|
if self.translation:
|
|
214
242
|
data[KEY_TRANSLATION] = {
|
|
215
243
|
language_code: translation.dict()
|
|
@@ -232,9 +260,9 @@ class Flow:
|
|
|
232
260
|
return translation.name if translation else None
|
|
233
261
|
|
|
234
262
|
def readable_name(self, language: Optional[Language] = None) -> str:
|
|
235
|
-
"""
|
|
236
|
-
|
|
237
|
-
falls back to the flow's name, and finally the flow's ID.
|
|
263
|
+
"""Returns the flow's name in the specified language if available.
|
|
264
|
+
|
|
265
|
+
Otherwise falls back to the flow's name, and finally the flow's ID.
|
|
238
266
|
|
|
239
267
|
Args:
|
|
240
268
|
language: Preferred language code.
|
|
@@ -378,8 +406,7 @@ class Flow:
|
|
|
378
406
|
structlogger.error(
|
|
379
407
|
"command_generator.validate_flow_starting_conditions.error",
|
|
380
408
|
predicate=self.guard_condition,
|
|
381
|
-
|
|
382
|
-
slots=slots,
|
|
409
|
+
flow_id=self.id,
|
|
383
410
|
error=str(e),
|
|
384
411
|
)
|
|
385
412
|
return False
|
|
@@ -52,7 +52,13 @@ def step_from_json(flow_id: Text, data: Dict[Text, Any]) -> FlowStep:
|
|
|
52
52
|
return SetSlotsFlowStep.from_json(flow_id, data)
|
|
53
53
|
if "noop" in data:
|
|
54
54
|
return NoOperationFlowStep.from_json(flow_id, data)
|
|
55
|
-
|
|
55
|
+
|
|
56
|
+
required_properties = ["action", "collect", "link", "call", "set_slots", "noop"]
|
|
57
|
+
raise RasaException(
|
|
58
|
+
f"Failed to parse step from json. Unknown type for {data}. "
|
|
59
|
+
f"At lest one of the following properties is required: "
|
|
60
|
+
f"{', '.join(required_properties)}"
|
|
61
|
+
)
|
|
56
62
|
|
|
57
63
|
|
|
58
64
|
@dataclass
|
|
@@ -100,7 +106,9 @@ class FlowStep:
|
|
|
100
106
|
"""Most steps allow linking to the next step. But some don't."""
|
|
101
107
|
return True
|
|
102
108
|
|
|
103
|
-
def as_json(
|
|
109
|
+
def as_json(
|
|
110
|
+
self, step_properties: Optional[Dict[Text, Any]] = None
|
|
111
|
+
) -> Dict[Text, Any]:
|
|
104
112
|
"""Serialize the FlowStep object.
|
|
105
113
|
|
|
106
114
|
Returns:
|
|
@@ -108,10 +116,13 @@ class FlowStep:
|
|
|
108
116
|
"""
|
|
109
117
|
data: Dict[Text, Any] = {"id": self.id}
|
|
110
118
|
|
|
111
|
-
if
|
|
112
|
-
data
|
|
119
|
+
if step_properties:
|
|
120
|
+
data.update(step_properties)
|
|
121
|
+
|
|
113
122
|
if self.description:
|
|
114
123
|
data["description"] = self.description
|
|
124
|
+
if dumped_next := self.next.as_json():
|
|
125
|
+
data["next"] = dumped_next
|
|
115
126
|
if self.metadata:
|
|
116
127
|
data["metadata"] = self.metadata
|
|
117
128
|
return data
|
|
@@ -143,6 +154,17 @@ class FlowStep:
|
|
|
143
154
|
"""Return all the utterances used in this step."""
|
|
144
155
|
return set()
|
|
145
156
|
|
|
157
|
+
def __eq__(self, other: object) -> bool:
|
|
158
|
+
if not isinstance(other, FlowStep):
|
|
159
|
+
return False
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
self.idx == other.idx
|
|
163
|
+
and self.description == other.description
|
|
164
|
+
and self.next == other.next
|
|
165
|
+
and self.flow_id == other.flow_id
|
|
166
|
+
)
|
|
167
|
+
|
|
146
168
|
|
|
147
169
|
@dataclass
|
|
148
170
|
class FlowStepWithFlowReference:
|
|
@@ -74,6 +74,11 @@ class FlowStepLinks:
|
|
|
74
74
|
depth = max(depth, link.depth_in_tree())
|
|
75
75
|
return depth
|
|
76
76
|
|
|
77
|
+
def __eq__(self, other: object) -> bool:
|
|
78
|
+
if isinstance(other, FlowStepLinks):
|
|
79
|
+
return self.links == other.links
|
|
80
|
+
return False
|
|
81
|
+
|
|
77
82
|
|
|
78
83
|
class FlowStepLink:
|
|
79
84
|
"""A flow step link that links two steps in a single flow."""
|
|
@@ -193,6 +198,11 @@ class BranchingFlowStepLink(FlowStepLink):
|
|
|
193
198
|
return depth + 1
|
|
194
199
|
return 1
|
|
195
200
|
|
|
201
|
+
def __eq__(self, other: object) -> bool:
|
|
202
|
+
if isinstance(other, BranchingFlowStepLink):
|
|
203
|
+
return self.target_reference == other.target_reference
|
|
204
|
+
return False
|
|
205
|
+
|
|
196
206
|
|
|
197
207
|
@dataclass
|
|
198
208
|
class IfFlowStepLink(BranchingFlowStepLink):
|
|
@@ -324,3 +334,8 @@ class StaticFlowStepLink(FlowStepLink):
|
|
|
324
334
|
def depth_in_tree(self) -> int:
|
|
325
335
|
"""Returns the depth in the tree."""
|
|
326
336
|
return 0
|
|
337
|
+
|
|
338
|
+
def __eq__(self, other: object) -> bool:
|
|
339
|
+
if isinstance(other, StaticFlowStepLink):
|
|
340
|
+
return self.target_step_id == other.target_step_id
|
|
341
|
+
return False
|
|
@@ -70,3 +70,9 @@ class FlowStepSequence:
|
|
|
70
70
|
def empty(cls) -> FlowStepSequence:
|
|
71
71
|
"""Create an empty FlowStepSequence object."""
|
|
72
72
|
return cls(child_steps=[])
|
|
73
|
+
|
|
74
|
+
def __eq__(self, other: object) -> bool:
|
|
75
|
+
return (
|
|
76
|
+
isinstance(other, FlowStepSequence)
|
|
77
|
+
and self.child_steps == other.child_steps
|
|
78
|
+
)
|