rasa-pro 3.13.0.dev20250612__py3-none-any.whl → 3.13.0rc1__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 +0 -3
- rasa/api.py +1 -1
- rasa/cli/dialogue_understanding_test.py +1 -1
- rasa/cli/e2e_test.py +1 -8
- rasa/cli/evaluate.py +1 -1
- rasa/cli/export.py +3 -1
- rasa/cli/llm_fine_tuning.py +12 -11
- rasa/cli/project_templates/defaults.py +133 -0
- rasa/cli/project_templates/tutorial/config.yml +1 -1
- rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
- rasa/cli/run.py +1 -1
- rasa/cli/studio/download.py +1 -23
- rasa/cli/studio/link.py +52 -0
- rasa/cli/studio/pull.py +79 -0
- rasa/cli/studio/push.py +78 -0
- rasa/cli/studio/studio.py +12 -0
- rasa/cli/studio/train.py +0 -1
- rasa/cli/studio/upload.py +8 -0
- 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 +5 -1
- rasa/core/actions/action_repeat_bot_messages.py +18 -22
- rasa/core/actions/action_run_slot_rejections.py +0 -1
- rasa/core/agent.py +16 -1
- rasa/core/available_endpoints.py +146 -0
- rasa/core/brokers/pika.py +1 -2
- rasa/core/channels/__init__.py +2 -0
- 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/README.md +3 -3
- rasa/core/channels/inspector/dist/assets/{arc-c4b064fc.js → arc-371401b1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-215b5026.js → blockDiagram-38ab4fdb-3f126156.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-2b54a0a3.js → c4Diagram-3d4e48cf-12f22eb7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-daacea5f.js → classDiagram-70f12bd4-03b1d386.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-930d4dc2.js → classDiagram-v2-f2320105-84f69d63.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-83c206ba.js → createText-2e5e7dd3-ca47fd38.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-b0eb01d0.js → edges-e0da2a9e-f837ca8a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-17586500.js → erDiagram-9861fffd-8717ac54.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-be2a1776.js → flowDb-956e92f1-94f38b83.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-c2120ebd.js → flowDiagram-66a62f08-b616f9fb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-a6ab5c48.js → flowchart-elk-definition-4a651766-f5d24bb8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-ef613457.js → ganttDiagram-c361ad54-b43ba8d9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-d59185b3.js → gitGraphDiagram-72cf32ee-c3aafaa5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-0f155405.js → graph-0d0a2c10.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-d5f1d1b7.js → index-3862675e-58ea0305.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-47737d3a.js → index-cce6f8a1.js} +3 -3
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-b07d141f.js → infoDiagram-f8f76790-b8f60461.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-1936d429.js → journeyDiagram-49397b02-95be5545.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-dde8d0f3.js → layout-da885b9b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-0c2c7ee0.js → line-f1c817d3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-35dd89a4.js → linear-d42801e6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-56192851.js → mindmap-definition-fc14e90a-a38923a6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-fc21ed78.js → pieDiagram-8a3498a8-ca6e71e9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-25e98518.js → quadrantDiagram-120e2f19-b290dae9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-546ff1f5.js → requirementDiagram-deff3bca-03f02ceb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-02d8b82d.js → sankeyDiagram-04a897e0-c49eee40.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3ca5a92e.js → sequenceDiagram-704730f1-b2cd6a3d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-128ea07c.js → stateDiagram-587899a1-e53a2028.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-95f290af.js → stateDiagram-v2-d93cdb3a-e1982a03.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-4984898a.js → styles-6aaf32cf-d0226ca5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1bf266ba.js → styles-9a916d00-0e21dc00.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-60521c63.js → styles-c10674c1-9588494e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-a25b6e12.js → svgDrawCommon-08f97a94-be478d4f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-0fc086bf.js → timeline-definition-85554ec2-74631749.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-44ee592e.js → xychartDiagram-e933f94c-a043552f.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +1 -1
- 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 +314 -10
- rasa/core/channels/vier_cvg.py +1 -2
- rasa/core/channels/voice_ready/audiocodes.py +2 -9
- rasa/core/channels/voice_stream/asr/azure.py +9 -0
- 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/jambonz.py +166 -0
- rasa/core/channels/voice_stream/tts/__init__.py +8 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +17 -5
- rasa/core/channels/voice_stream/voice_channel.py +44 -24
- rasa/core/exporter.py +36 -0
- rasa/core/http_interpreter.py +3 -7
- rasa/core/information_retrieval/faiss.py +18 -11
- rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
- rasa/core/jobs.py +2 -1
- rasa/core/nlg/contextual_response_rephraser.py +48 -12
- rasa/core/nlg/generator.py +0 -1
- rasa/core/nlg/interpolator.py +2 -3
- rasa/core/nlg/summarize.py +39 -5
- rasa/core/policies/enterprise_search_policy.py +298 -184
- rasa/core/policies/enterprise_search_policy_config.py +241 -0
- rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +64 -0
- rasa/core/policies/flow_policy.py +1 -1
- rasa/core/policies/flows/flow_executor.py +96 -17
- rasa/core/policies/intentless_policy.py +71 -26
- rasa/core/processor.py +104 -51
- rasa/core/run.py +33 -11
- rasa/core/tracker_stores/tracker_store.py +1 -1
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +35 -99
- rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
- rasa/dialogue_understanding/coexistence/llm_based_router.py +13 -17
- rasa/dialogue_understanding/commands/__init__.py +4 -0
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +6 -2
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/clarify_command.py +7 -3
- rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +5 -6
- rasa/dialogue_understanding/commands/error_command.py +1 -1
- rasa/dialogue_understanding/commands/human_handoff_command.py +3 -3
- 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 +15 -5
- rasa/dialogue_understanding/commands/skip_question_command.py +3 -3
- rasa/dialogue_understanding/commands/start_flow_command.py +7 -3
- rasa/dialogue_understanding/commands/utils.py +26 -2
- rasa/dialogue_understanding/generator/__init__.py +7 -1
- rasa/dialogue_understanding/generator/command_generator.py +15 -3
- rasa/dialogue_understanding/generator/command_parser.py +2 -2
- rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
- rasa/dialogue_understanding/generator/constants.py +2 -2
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +0 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +1 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +79 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +79 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +28 -463
- 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 +461 -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 +11 -12
- rasa/dialogue_understanding/processor/command_processor_component.py +3 -3
- 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/du_test_case.py +1 -1
- rasa/dialogue_understanding_test/du_test_runner.py +4 -22
- rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +2 -6
- rasa/e2e_test/e2e_test_coverage_report.py +1 -1
- 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 +26 -2
- rasa/engine/validation.py +3 -2
- rasa/hooks.py +0 -28
- rasa/llm_fine_tuning/annotation_module.py +39 -9
- rasa/llm_fine_tuning/conversations.py +3 -0
- rasa/llm_fine_tuning/llm_data_preparation_module.py +66 -49
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +5 -7
- rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +52 -44
- rasa/llm_fine_tuning/paraphrasing_module.py +10 -12
- rasa/llm_fine_tuning/storage.py +4 -4
- rasa/llm_fine_tuning/utils.py +63 -1
- rasa/model_manager/model_api.py +88 -0
- rasa/model_manager/trainer_service.py +4 -4
- rasa/plugin.py +1 -11
- 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 +18 -0
- rasa/shared/core/command_payload_reader.py +1 -5
- rasa/shared/core/constants.py +4 -3
- rasa/shared/core/domain.py +7 -0
- rasa/shared/core/events.py +38 -10
- rasa/shared/core/flows/constants.py +2 -0
- rasa/shared/core/flows/flow.py +127 -14
- rasa/shared/core/flows/flows_list.py +18 -1
- rasa/shared/core/flows/flows_yaml_schema.json +3 -0
- rasa/shared/core/flows/steps/collect.py +46 -2
- rasa/shared/core/flows/steps/link.py +7 -2
- rasa/shared/core/flows/validation.py +25 -5
- rasa/shared/core/slots.py +28 -0
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
- rasa/shared/exceptions.py +4 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +6 -2
- rasa/shared/providers/_configs/default_litellm_client_config.py +1 -1
- rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -1
- rasa/shared/providers/_configs/openai_client_config.py +5 -1
- rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -1
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -1
- rasa/shared/providers/_configs/utils.py +0 -99
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +3 -0
- rasa/shared/providers/llm/_base_litellm_client.py +5 -2
- rasa/shared/utils/common.py +1 -1
- rasa/shared/utils/configs.py +110 -0
- rasa/shared/utils/constants.py +0 -3
- rasa/shared/utils/llm.py +195 -9
- rasa/shared/utils/pykwalify_extensions.py +0 -9
- rasa/shared/utils/yaml.py +32 -0
- rasa/studio/constants.py +1 -0
- rasa/studio/data_handler.py +11 -4
- rasa/studio/download.py +167 -0
- rasa/studio/link.py +200 -0
- rasa/studio/prompts.py +223 -0
- rasa/studio/pull/__init__.py +0 -0
- rasa/studio/{download/flows.py → pull/data.py} +23 -160
- rasa/studio/{download → pull}/domains.py +1 -1
- rasa/studio/pull/pull.py +235 -0
- rasa/studio/push.py +136 -0
- rasa/studio/train.py +1 -1
- rasa/studio/upload.py +117 -67
- rasa/telemetry.py +82 -25
- rasa/tracing/config.py +3 -4
- rasa/tracing/constants.py +19 -1
- rasa/tracing/instrumentation/attribute_extractors.py +30 -8
- rasa/tracing/instrumentation/instrumentation.py +53 -2
- rasa/tracing/instrumentation/metrics.py +98 -15
- rasa/tracing/metric_instrument_provider.py +75 -3
- rasa/utils/common.py +7 -22
- rasa/utils/log_utils.py +1 -45
- rasa/validator.py +2 -8
- rasa/version.py +1 -1
- {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/METADATA +8 -9
- {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/RECORD +241 -220
- 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/core/channels/inspector/dist/assets/channel-3730f5fd.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-e847561e.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-efbbfe00.js +0 -1
- rasa/studio/download/download.py +0 -439
- /rasa/{studio/download → core/information_retrieval/ingestion}/__init__.py +0 -0
- {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/entry_points.txt +0 -0
rasa/shared/core/constants.py
CHANGED
|
@@ -113,10 +113,11 @@ FLOW_HASHES_SLOT = "flow_hashes"
|
|
|
113
113
|
FLOW_SLOT_NAMES = [FLOW_HASHES_SLOT]
|
|
114
114
|
|
|
115
115
|
# slots for audio timeout
|
|
116
|
-
|
|
116
|
+
GLOBAL_SILENCE_TIMEOUT_KEY = "global_silence_timeout"
|
|
117
|
+
SILENCE_TIMEOUT_SLOT = "silence_timeout"
|
|
117
118
|
SLOT_CONSECUTIVE_SILENCE_TIMEOUTS = "consecutive_silence_timeouts"
|
|
118
|
-
|
|
119
|
-
SILENCE_SLOTS = [
|
|
119
|
+
GLOBAL_SILENCE_TIMEOUT_DEFAULT_VALUE = 7.0
|
|
120
|
+
SILENCE_SLOTS = [SILENCE_TIMEOUT_SLOT, SLOT_CONSECUTIVE_SILENCE_TIMEOUTS]
|
|
120
121
|
# slots for knowledge base
|
|
121
122
|
SLOT_LISTED_ITEMS = "knowledge_base_listed_objects"
|
|
122
123
|
SLOT_LAST_OBJECT = "knowledge_base_last_object"
|
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
|
)
|
|
@@ -306,6 +308,11 @@ class Domain:
|
|
|
306
308
|
responses = data.get(KEY_RESPONSES, {})
|
|
307
309
|
|
|
308
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
|
+
)
|
|
309
316
|
slots = cls.collect_slots(domain_slots)
|
|
310
317
|
domain_actions = data.get(KEY_ACTIONS, [])
|
|
311
318
|
actions = cls._collect_action_names(domain_actions)
|
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,
|
|
@@ -124,9 +126,7 @@ def deserialise_events(serialized_events: List[Dict[Text, Any]]) -> List["Event"
|
|
|
124
126
|
if event:
|
|
125
127
|
deserialised.append(event)
|
|
126
128
|
else:
|
|
127
|
-
structlogger.warning(
|
|
128
|
-
"event.deserialization.failed", rasa_event=copy.deepcopy(event)
|
|
129
|
-
)
|
|
129
|
+
structlogger.warning("event.deserialization.failed")
|
|
130
130
|
|
|
131
131
|
return deserialised
|
|
132
132
|
|
|
@@ -453,6 +453,7 @@ class UserUttered(Event):
|
|
|
453
453
|
message_id: Optional[Text] = None,
|
|
454
454
|
metadata: Optional[Dict] = None,
|
|
455
455
|
use_text_for_featurization: Optional[bool] = None,
|
|
456
|
+
anonymized_at: Optional[float] = None,
|
|
456
457
|
) -> None:
|
|
457
458
|
"""Creates event for incoming user message.
|
|
458
459
|
|
|
@@ -467,6 +468,7 @@ class UserUttered(Event):
|
|
|
467
468
|
message_id: Unique ID for message.
|
|
468
469
|
use_text_for_featurization: `True` if the message's text was used to predict
|
|
469
470
|
next action. `False` if the message's intent was used.
|
|
471
|
+
anonymized_at: When the event was anonymized in the tracker store.
|
|
470
472
|
|
|
471
473
|
"""
|
|
472
474
|
self.text = text
|
|
@@ -500,7 +502,11 @@ class UserUttered(Event):
|
|
|
500
502
|
if parse_data:
|
|
501
503
|
self.parse_data.update(**parse_data)
|
|
502
504
|
|
|
503
|
-
self._anonymized_at: Optional[datetime] =
|
|
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
|
+
)
|
|
504
510
|
|
|
505
511
|
@property
|
|
506
512
|
def anonymized_at(self) -> Optional[datetime]:
|
|
@@ -525,6 +531,7 @@ class UserUttered(Event):
|
|
|
525
531
|
input_channel: Optional[Text] = None,
|
|
526
532
|
message_id: Optional[Text] = None,
|
|
527
533
|
metadata: Optional[Dict] = None,
|
|
534
|
+
anonymized_at: Optional[float] = None,
|
|
528
535
|
) -> "UserUttered":
|
|
529
536
|
return UserUttered(
|
|
530
537
|
text,
|
|
@@ -535,6 +542,7 @@ class UserUttered(Event):
|
|
|
535
542
|
input_channel,
|
|
536
543
|
message_id,
|
|
537
544
|
metadata,
|
|
545
|
+
anonymized_at,
|
|
538
546
|
)
|
|
539
547
|
|
|
540
548
|
def __hash__(self) -> int:
|
|
@@ -633,7 +641,9 @@ class UserUttered(Event):
|
|
|
633
641
|
"input_channel": getattr(self, "input_channel", None),
|
|
634
642
|
"message_id": getattr(self, "message_id", None),
|
|
635
643
|
"metadata": self.metadata,
|
|
636
|
-
"anonymized_at": self.anonymized_at
|
|
644
|
+
"anonymized_at": self.anonymized_at.timestamp()
|
|
645
|
+
if self.anonymized_at
|
|
646
|
+
else None,
|
|
637
647
|
}
|
|
638
648
|
)
|
|
639
649
|
return _dict
|
|
@@ -693,6 +703,7 @@ class UserUttered(Event):
|
|
|
693
703
|
parameters.get("input_channel"),
|
|
694
704
|
parameters.get("message_id"),
|
|
695
705
|
parameters.get("metadata"),
|
|
706
|
+
parameters.get("anonymized_at"),
|
|
696
707
|
)
|
|
697
708
|
]
|
|
698
709
|
except KeyError as e:
|
|
@@ -920,6 +931,7 @@ class BotUttered(SkipEventInMDStoryMixin):
|
|
|
920
931
|
data: Optional[Dict] = None,
|
|
921
932
|
metadata: Optional[Dict[Text, Any]] = None,
|
|
922
933
|
timestamp: Optional[float] = None,
|
|
934
|
+
anonymized_at: Optional[float] = None,
|
|
923
935
|
) -> None:
|
|
924
936
|
"""Creates event for a bot response.
|
|
925
937
|
|
|
@@ -928,10 +940,15 @@ class BotUttered(SkipEventInMDStoryMixin):
|
|
|
928
940
|
data: Additional data for more complex utterances (e.g. buttons).
|
|
929
941
|
timestamp: When the event was created.
|
|
930
942
|
metadata: Additional event metadata.
|
|
943
|
+
anonymized_at: When the event was anonymized in the tracker store.
|
|
931
944
|
"""
|
|
932
945
|
self.text = text
|
|
933
946
|
self.data = data or {}
|
|
934
|
-
self._anonymized_at: Optional[datetime] =
|
|
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
|
+
)
|
|
935
952
|
super().__init__(timestamp, metadata)
|
|
936
953
|
|
|
937
954
|
@property
|
|
@@ -1040,7 +1057,9 @@ class BotUttered(SkipEventInMDStoryMixin):
|
|
|
1040
1057
|
"text": self.text,
|
|
1041
1058
|
"data": self.data,
|
|
1042
1059
|
"metadata": self.metadata,
|
|
1043
|
-
"anonymized_at": self.anonymized_at
|
|
1060
|
+
"anonymized_at": self.anonymized_at.timestamp()
|
|
1061
|
+
if self.anonymized_at
|
|
1062
|
+
else None,
|
|
1044
1063
|
}
|
|
1045
1064
|
)
|
|
1046
1065
|
return d
|
|
@@ -1053,6 +1072,7 @@ class BotUttered(SkipEventInMDStoryMixin):
|
|
|
1053
1072
|
parameters.get("data"),
|
|
1054
1073
|
parameters.get("metadata"),
|
|
1055
1074
|
parameters.get("timestamp"),
|
|
1075
|
+
parameters.get("anonymized_at"),
|
|
1056
1076
|
)
|
|
1057
1077
|
except KeyError as e:
|
|
1058
1078
|
raise ValueError(f"Failed to parse bot uttered event. {e}")
|
|
@@ -1077,6 +1097,7 @@ class SlotSet(Event):
|
|
|
1077
1097
|
timestamp: Optional[float] = None,
|
|
1078
1098
|
metadata: Optional[Dict[Text, Any]] = None,
|
|
1079
1099
|
filled_by: Optional[str] = None,
|
|
1100
|
+
anonymized_at: Optional[float] = None,
|
|
1080
1101
|
) -> None:
|
|
1081
1102
|
"""Creates event to set slot.
|
|
1082
1103
|
|
|
@@ -1089,7 +1110,11 @@ class SlotSet(Event):
|
|
|
1089
1110
|
self.key = key
|
|
1090
1111
|
self.value = value
|
|
1091
1112
|
self._filled_by = filled_by
|
|
1092
|
-
self._anonymized_at: Optional[datetime] =
|
|
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
|
+
)
|
|
1093
1118
|
super().__init__(timestamp, metadata)
|
|
1094
1119
|
|
|
1095
1120
|
@property
|
|
@@ -1156,7 +1181,9 @@ class SlotSet(Event):
|
|
|
1156
1181
|
"name": self.key,
|
|
1157
1182
|
"value": self.value,
|
|
1158
1183
|
"filled_by": self.filled_by,
|
|
1159
|
-
"anonymized_at": self.anonymized_at
|
|
1184
|
+
"anonymized_at": self.anonymized_at.timestamp()
|
|
1185
|
+
if self.anonymized_at
|
|
1186
|
+
else None,
|
|
1160
1187
|
}
|
|
1161
1188
|
)
|
|
1162
1189
|
return d
|
|
@@ -1170,6 +1197,7 @@ class SlotSet(Event):
|
|
|
1170
1197
|
parameters.get("timestamp"),
|
|
1171
1198
|
parameters.get("metadata"),
|
|
1172
1199
|
filled_by=parameters.get("filled_by"),
|
|
1200
|
+
anonymized_at=parameters.get("anonymized_at"),
|
|
1173
1201
|
)
|
|
1174
1202
|
except KeyError as e:
|
|
1175
1203
|
raise ValueError(f"Failed to parse set slot event. {e}")
|
rasa/shared/core/flows/flow.py
CHANGED
|
@@ -4,7 +4,7 @@ import copy
|
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from functools import cached_property
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Any, Dict, List, Optional, Set, Text, Union
|
|
7
|
+
from typing import Any, Dict, List, Optional, Set, Text, Tuple, Union
|
|
8
8
|
|
|
9
9
|
import structlog
|
|
10
10
|
from pydantic import BaseModel
|
|
@@ -15,10 +15,12 @@ from rasa.engine.language import Language
|
|
|
15
15
|
from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
|
|
16
16
|
from rasa.shared.core.flows.constants import (
|
|
17
17
|
KEY_ALWAYS_INCLUDE_IN_PROMPT,
|
|
18
|
+
KEY_CALLED_FLOW,
|
|
18
19
|
KEY_DESCRIPTION,
|
|
19
20
|
KEY_FILE_PATH,
|
|
20
21
|
KEY_ID,
|
|
21
22
|
KEY_IF,
|
|
23
|
+
KEY_LINKED_FLOW,
|
|
22
24
|
KEY_NAME,
|
|
23
25
|
KEY_NLU_TRIGGER,
|
|
24
26
|
KEY_PERSISTED_SLOTS,
|
|
@@ -41,6 +43,7 @@ from rasa.shared.core.flows.steps import (
|
|
|
41
43
|
CallFlowStep,
|
|
42
44
|
CollectInformationFlowStep,
|
|
43
45
|
EndFlowStep,
|
|
46
|
+
LinkFlowStep,
|
|
44
47
|
StartFlowStep,
|
|
45
48
|
)
|
|
46
49
|
from rasa.shared.core.flows.steps.constants import (
|
|
@@ -63,7 +66,7 @@ class FlowLanguageTranslation(BaseModel):
|
|
|
63
66
|
"""The human-readable name of the flow."""
|
|
64
67
|
|
|
65
68
|
class Config:
|
|
66
|
-
"""
|
|
69
|
+
"""Configuration for the FlowLanguageTranslation model."""
|
|
67
70
|
|
|
68
71
|
extra = "ignore"
|
|
69
72
|
|
|
@@ -262,7 +265,7 @@ class Flow:
|
|
|
262
265
|
def readable_name(self, language: Optional[Language] = None) -> str:
|
|
263
266
|
"""Returns the flow's name in the specified language if available.
|
|
264
267
|
|
|
265
|
-
Otherwise falls back to the flow's name, and finally the flow's ID.
|
|
268
|
+
Otherwise, falls back to the flow's name, and finally the flow's ID.
|
|
266
269
|
|
|
267
270
|
Args:
|
|
268
271
|
language: Preferred language code.
|
|
@@ -406,8 +409,7 @@ class Flow:
|
|
|
406
409
|
structlogger.error(
|
|
407
410
|
"command_generator.validate_flow_starting_conditions.error",
|
|
408
411
|
predicate=self.guard_condition,
|
|
409
|
-
|
|
410
|
-
slots=slots,
|
|
412
|
+
flow_id=self.id,
|
|
411
413
|
error=str(e),
|
|
412
414
|
)
|
|
413
415
|
return False
|
|
@@ -516,6 +518,9 @@ class Flow:
|
|
|
516
518
|
current_path: FlowPath,
|
|
517
519
|
all_paths: FlowPathsList,
|
|
518
520
|
visited_step_ids: Set[str],
|
|
521
|
+
call_stack: Optional[
|
|
522
|
+
List[Tuple[Optional[FlowStep], Optional[Flow], str]]
|
|
523
|
+
] = None,
|
|
519
524
|
) -> None:
|
|
520
525
|
"""Processes the flow steps recursively.
|
|
521
526
|
|
|
@@ -524,19 +529,25 @@ class Flow:
|
|
|
524
529
|
current_path: The current path being constructed.
|
|
525
530
|
all_paths: The list where completed paths are added.
|
|
526
531
|
visited_step_ids: A set of steps that have been visited to avoid cycles.
|
|
532
|
+
call_stack: Tuple list of (flow, path, flow_type) to track path when \
|
|
533
|
+
calling flows through call and link steps.
|
|
527
534
|
|
|
528
535
|
Returns:
|
|
529
536
|
None: This function modifies all_paths in place by appending new paths
|
|
530
537
|
as they are found.
|
|
531
538
|
"""
|
|
539
|
+
if call_stack is None:
|
|
540
|
+
call_stack = []
|
|
541
|
+
|
|
532
542
|
# Check if the step is relevant for testable_paths extraction.
|
|
533
|
-
# We only create new path nodes for
|
|
534
|
-
#
|
|
535
|
-
#
|
|
543
|
+
# We only create new path nodes for CollectInformationFlowStep,
|
|
544
|
+
# ActionFlowStep, CallFlowStep and LinkFlowStep,
|
|
545
|
+
# because these are externally visible changes
|
|
546
|
+
# in the assistant's behaviour (trackable in the e2e tests).
|
|
536
547
|
# For other flow steps, we only follow their links.
|
|
537
|
-
# We decided to ignore calls to other flows in our coverage analysis.
|
|
538
548
|
should_add_node = isinstance(
|
|
539
|
-
current_step,
|
|
549
|
+
current_step,
|
|
550
|
+
(CollectInformationFlowStep, ActionFlowStep, CallFlowStep, LinkFlowStep),
|
|
540
551
|
)
|
|
541
552
|
if should_add_node:
|
|
542
553
|
# Add current step to the current path that is being constructed.
|
|
@@ -548,10 +559,45 @@ class Flow:
|
|
|
548
559
|
)
|
|
549
560
|
)
|
|
550
561
|
|
|
562
|
+
# Check if the current step has already been visited or
|
|
563
|
+
# if the end of the path has been reached.
|
|
564
|
+
# If so, and we’re not within a called flow, we terminate the current path.
|
|
565
|
+
# This also applies for when we're inside a linked flow and reach its end.
|
|
566
|
+
# If we're inside a called flow and reach its end,
|
|
567
|
+
# continue with the next steps in its parent flow.
|
|
551
568
|
if current_step.id in visited_step_ids or self.is_end_of_path(current_step):
|
|
552
|
-
#
|
|
553
|
-
|
|
554
|
-
#
|
|
569
|
+
# Shallow copy is sufficient, since we only pop from the list and
|
|
570
|
+
# don't mutate the objects inside the tuples.
|
|
571
|
+
# The state of FlowStep and Flow does not change during the traversal.
|
|
572
|
+
call_stack_copy = call_stack.copy()
|
|
573
|
+
# parent_flow_type could be any of: None, i.e. main flow,
|
|
574
|
+
# KEY_CALLED_FLOW(=called_flow) or KEY_LINKED_FLOW(=linked_flow)
|
|
575
|
+
parent_step, parent_flow, parent_flow_type = (
|
|
576
|
+
call_stack_copy.pop() if call_stack_copy else (None, None, None)
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
# Check if within a called flow.
|
|
580
|
+
# If within linked flow, stop the traversal as this takes precedence.
|
|
581
|
+
if parent_step and parent_flow_type == KEY_CALLED_FLOW:
|
|
582
|
+
# As we have reached the END step of a called flow, we need to
|
|
583
|
+
# continue with the next links of the parent step.
|
|
584
|
+
if parent_flow is not None:
|
|
585
|
+
for link in parent_step.next.links:
|
|
586
|
+
parent_flow._handle_link(
|
|
587
|
+
current_path,
|
|
588
|
+
all_paths,
|
|
589
|
+
visited_step_ids,
|
|
590
|
+
link,
|
|
591
|
+
call_stack_copy,
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
else:
|
|
595
|
+
# Found a cycle, or reached an end step, do not proceed further.
|
|
596
|
+
all_paths.paths.append(copy.deepcopy(current_path))
|
|
597
|
+
|
|
598
|
+
# Backtrack: remove the last node after reaching a terminal step.
|
|
599
|
+
# Ensures the path is correctly backtracked, after a path ends or
|
|
600
|
+
# a cycle is detected.
|
|
555
601
|
if should_add_node:
|
|
556
602
|
current_path.nodes.pop()
|
|
557
603
|
return
|
|
@@ -559,6 +605,62 @@ class Flow:
|
|
|
559
605
|
# Mark current step as visited in this path.
|
|
560
606
|
visited_step_ids.add(current_step.id)
|
|
561
607
|
|
|
608
|
+
# If the current step is a call step, we need to resolve the call
|
|
609
|
+
# and continue with the steps of the called flow.
|
|
610
|
+
if isinstance(current_step, CallFlowStep):
|
|
611
|
+
# Get the steps of the called flow and continue with them.
|
|
612
|
+
called_flow = current_step.called_flow_reference
|
|
613
|
+
if called_flow and (
|
|
614
|
+
start_step_in_called_flow := called_flow.first_step_in_flow()
|
|
615
|
+
):
|
|
616
|
+
call_stack.append((current_step, self, KEY_CALLED_FLOW))
|
|
617
|
+
called_flow._go_over_steps(
|
|
618
|
+
start_step_in_called_flow,
|
|
619
|
+
current_path,
|
|
620
|
+
all_paths,
|
|
621
|
+
visited_step_ids,
|
|
622
|
+
call_stack,
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
# After processing the steps of the called (child) flow,
|
|
626
|
+
# remove them from the visited steps
|
|
627
|
+
# to allow the calling (parent) flow to revisit them later.
|
|
628
|
+
visited_step_ids.remove(current_step.id)
|
|
629
|
+
call_stack.pop()
|
|
630
|
+
|
|
631
|
+
# Backtrack: remove the last node
|
|
632
|
+
# after returning from a called (child) flow.
|
|
633
|
+
# Ensures the parent flow can continue exploring other branches.
|
|
634
|
+
if should_add_node:
|
|
635
|
+
current_path.nodes.pop()
|
|
636
|
+
return
|
|
637
|
+
|
|
638
|
+
# If the current step is a LinkFlowStep, step into the linked flow,
|
|
639
|
+
# process its links, and do not return from that flow anymore.
|
|
640
|
+
if isinstance(current_step, LinkFlowStep):
|
|
641
|
+
# Get the steps of the linked flow and continue with them.
|
|
642
|
+
linked_flow = current_step.linked_flow_reference
|
|
643
|
+
if linked_flow and (
|
|
644
|
+
start_step_in_linked_flow := linked_flow.first_step_in_flow()
|
|
645
|
+
):
|
|
646
|
+
call_stack.append((current_step, self, KEY_LINKED_FLOW))
|
|
647
|
+
linked_flow._go_over_steps(
|
|
648
|
+
start_step_in_linked_flow,
|
|
649
|
+
current_path,
|
|
650
|
+
all_paths,
|
|
651
|
+
visited_step_ids,
|
|
652
|
+
call_stack,
|
|
653
|
+
)
|
|
654
|
+
visited_step_ids.remove(current_step.id)
|
|
655
|
+
call_stack.pop()
|
|
656
|
+
|
|
657
|
+
# Backtrack: remove the last node
|
|
658
|
+
# after returning from a linked (child) flow.
|
|
659
|
+
# Ensures the parent can continue after the linked flow is processed.
|
|
660
|
+
if should_add_node:
|
|
661
|
+
current_path.nodes.pop()
|
|
662
|
+
return
|
|
663
|
+
|
|
562
664
|
# Iterate over all links of the current step.
|
|
563
665
|
for link in current_step.next.links:
|
|
564
666
|
self._handle_link(
|
|
@@ -566,12 +668,15 @@ class Flow:
|
|
|
566
668
|
all_paths,
|
|
567
669
|
visited_step_ids,
|
|
568
670
|
link,
|
|
671
|
+
call_stack,
|
|
569
672
|
)
|
|
570
673
|
|
|
571
674
|
# Backtrack the current step and remove it from the path.
|
|
572
675
|
visited_step_ids.remove(current_step.id)
|
|
573
676
|
|
|
574
|
-
#
|
|
677
|
+
# Backtrack: remove the last node
|
|
678
|
+
# after processing all links of the current step.
|
|
679
|
+
# Ensures the next recursion can start once all links are explored.
|
|
575
680
|
if should_add_node:
|
|
576
681
|
current_path.nodes.pop()
|
|
577
682
|
|
|
@@ -581,6 +686,9 @@ class Flow:
|
|
|
581
686
|
all_paths: FlowPathsList,
|
|
582
687
|
visited_step_ids: Set[str],
|
|
583
688
|
link: FlowStepLink,
|
|
689
|
+
call_stack: Optional[
|
|
690
|
+
List[Tuple[Optional[FlowStep], Optional[Flow], str]]
|
|
691
|
+
] = None,
|
|
584
692
|
) -> None:
|
|
585
693
|
"""Handles the next step in a flow.
|
|
586
694
|
|
|
@@ -589,6 +697,8 @@ class Flow:
|
|
|
589
697
|
all_paths: The list where completed paths are added.
|
|
590
698
|
visited_step_ids: A set of steps that have been visited to avoid cycles.
|
|
591
699
|
link: The link to be followed.
|
|
700
|
+
call_stack: Tuple list of (flow, path, flow_type) to track path when \
|
|
701
|
+
calling flows through call and link steps..
|
|
592
702
|
|
|
593
703
|
Returns:
|
|
594
704
|
None: This function modifies all_paths in place by appending new paths
|
|
@@ -603,6 +713,7 @@ class Flow:
|
|
|
603
713
|
current_path,
|
|
604
714
|
all_paths,
|
|
605
715
|
visited_step_ids,
|
|
716
|
+
call_stack,
|
|
606
717
|
)
|
|
607
718
|
return
|
|
608
719
|
# IfFlowStepLink and ElseFlowStepLink are conditional links.
|
|
@@ -616,6 +727,7 @@ class Flow:
|
|
|
616
727
|
current_path,
|
|
617
728
|
all_paths,
|
|
618
729
|
visited_step_ids,
|
|
730
|
+
call_stack,
|
|
619
731
|
)
|
|
620
732
|
return
|
|
621
733
|
else:
|
|
@@ -626,6 +738,7 @@ class Flow:
|
|
|
626
738
|
current_path,
|
|
627
739
|
all_paths,
|
|
628
740
|
visited_step_ids,
|
|
741
|
+
call_stack,
|
|
629
742
|
)
|
|
630
743
|
return
|
|
631
744
|
|
|
@@ -36,6 +36,7 @@ class FlowsList:
|
|
|
36
36
|
def __post_init__(self) -> None:
|
|
37
37
|
"""Initializes the FlowsList object."""
|
|
38
38
|
self._resolve_called_flows()
|
|
39
|
+
self._resolve_linked_flows()
|
|
39
40
|
|
|
40
41
|
def __iter__(self) -> Generator[Flow, None, None]:
|
|
41
42
|
"""Iterates over the flows."""
|
|
@@ -103,7 +104,10 @@ class FlowsList:
|
|
|
103
104
|
)
|
|
104
105
|
|
|
105
106
|
def _resolve_called_flows(self) -> None:
|
|
106
|
-
"""Resolves the called flows.
|
|
107
|
+
"""Resolves the called flows.
|
|
108
|
+
|
|
109
|
+
`Resolving` here means connecting the step to the actual `Flow` object.
|
|
110
|
+
"""
|
|
107
111
|
from rasa.shared.core.flows.steps import CallFlowStep
|
|
108
112
|
|
|
109
113
|
for flow in self.underlying_flows:
|
|
@@ -112,6 +116,19 @@ class FlowsList:
|
|
|
112
116
|
# only resolve the reference, if it isn't already resolved
|
|
113
117
|
step.called_flow_reference = self.flow_by_id(step.call)
|
|
114
118
|
|
|
119
|
+
def _resolve_linked_flows(self) -> None:
|
|
120
|
+
"""Resolves the linked flows.
|
|
121
|
+
|
|
122
|
+
`Resolving` here means connecting the step to the actual `Flow` object.
|
|
123
|
+
"""
|
|
124
|
+
from rasa.shared.core.flows.steps import LinkFlowStep
|
|
125
|
+
|
|
126
|
+
for flow in self.underlying_flows:
|
|
127
|
+
for step in flow.steps:
|
|
128
|
+
if isinstance(step, LinkFlowStep) and not step.linked_flow_reference:
|
|
129
|
+
# only resolve the reference, if it isn't already resolved
|
|
130
|
+
step.linked_flow_reference = self.flow_by_id(step.link)
|
|
131
|
+
|
|
115
132
|
def as_json_list(self) -> List[Dict[Text, Any]]:
|
|
116
133
|
"""Serialize the FlowsList object to list format and not to the original dict.
|
|
117
134
|
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Any, Dict, List, Set, Text
|
|
4
|
+
from typing import Any, Dict, List, Optional, Set, Text, Union
|
|
5
|
+
|
|
6
|
+
import structlog
|
|
5
7
|
|
|
6
8
|
from rasa.shared.constants import ACTION_ASK_PREFIX, UTTER_ASK_PREFIX
|
|
7
9
|
from rasa.shared.core.flows.flow_step import FlowStep
|
|
8
10
|
from rasa.shared.core.slots import SlotRejection
|
|
11
|
+
from rasa.shared.exceptions import RasaException
|
|
9
12
|
|
|
10
13
|
DEFAULT_ASK_BEFORE_FILLING = False
|
|
11
14
|
DEFAULT_RESET_AFTER_FLOW_ENDS = True
|
|
12
15
|
DEFAULT_FORCE_SLOT_FILLING = False
|
|
13
16
|
|
|
17
|
+
logger = structlog.get_logger(__name__)
|
|
18
|
+
|
|
19
|
+
SilenceTimeoutInstructionType = Union[int, float, Dict[str, Any]]
|
|
20
|
+
|
|
14
21
|
|
|
15
22
|
@dataclass
|
|
16
23
|
class CollectInformationFlowStep(FlowStep):
|
|
@@ -30,6 +37,8 @@ class CollectInformationFlowStep(FlowStep):
|
|
|
30
37
|
"""Whether to reset the slot value at the end of the flow."""
|
|
31
38
|
force_slot_filling: bool = False
|
|
32
39
|
"""Whether to keep only the SetSlot command for the collected slot."""
|
|
40
|
+
silence_timeout: Optional[float] = None
|
|
41
|
+
"""The silence timeout for the collect information step."""
|
|
33
42
|
|
|
34
43
|
@classmethod
|
|
35
44
|
def from_json(
|
|
@@ -44,6 +53,11 @@ class CollectInformationFlowStep(FlowStep):
|
|
|
44
53
|
Returns:
|
|
45
54
|
A CollectInformationFlowStep object
|
|
46
55
|
"""
|
|
56
|
+
|
|
57
|
+
silence_timeout = cls._deserialise_silence_timeout(
|
|
58
|
+
data.get("silence_timeout", None)
|
|
59
|
+
)
|
|
60
|
+
|
|
47
61
|
base = super().from_json(flow_id, data)
|
|
48
62
|
return CollectInformationFlowStep(
|
|
49
63
|
collect=data["collect"],
|
|
@@ -58,14 +72,40 @@ class CollectInformationFlowStep(FlowStep):
|
|
|
58
72
|
for rejection in data.get("rejections", [])
|
|
59
73
|
],
|
|
60
74
|
force_slot_filling=data.get("force_slot_filling", False),
|
|
75
|
+
silence_timeout=silence_timeout,
|
|
61
76
|
**base.__dict__,
|
|
62
77
|
)
|
|
63
78
|
|
|
79
|
+
@staticmethod
|
|
80
|
+
def _deserialise_silence_timeout(
|
|
81
|
+
silence_timeout_json: Optional[SilenceTimeoutInstructionType],
|
|
82
|
+
) -> Optional[float]:
|
|
83
|
+
"""Deserialize silence timeout from JSON."""
|
|
84
|
+
if not silence_timeout_json:
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
if not isinstance(silence_timeout_json, (int, float)):
|
|
88
|
+
raise RasaException(
|
|
89
|
+
f"Invalid silence timeout value: {silence_timeout_json}. "
|
|
90
|
+
"If defined at collect step, silence timeout must be a number."
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
silence_timeout = silence_timeout_json
|
|
94
|
+
|
|
95
|
+
if silence_timeout and silence_timeout < 0:
|
|
96
|
+
raise RasaException(
|
|
97
|
+
f"Invalid silence timeout value: {silence_timeout}. "
|
|
98
|
+
"Silence timeout must be a non-negative number."
|
|
99
|
+
)
|
|
100
|
+
return silence_timeout
|
|
101
|
+
|
|
64
102
|
@staticmethod
|
|
65
103
|
def _default_utter(collect: str) -> str:
|
|
66
104
|
return f"{UTTER_ASK_PREFIX}{collect}"
|
|
67
105
|
|
|
68
|
-
def as_json(
|
|
106
|
+
def as_json(
|
|
107
|
+
self, step_properties: Optional[Dict[Text, Any]] = None
|
|
108
|
+
) -> Dict[str, Any]:
|
|
69
109
|
"""Serialize the CollectInformationFlowStep object.
|
|
70
110
|
|
|
71
111
|
Returns:
|
|
@@ -78,6 +118,9 @@ class CollectInformationFlowStep(FlowStep):
|
|
|
78
118
|
data["reset_after_flow_ends"] = self.reset_after_flow_ends
|
|
79
119
|
data["rejections"] = [rejection.as_dict() for rejection in self.rejections]
|
|
80
120
|
data["force_slot_filling"] = self.force_slot_filling
|
|
121
|
+
if self.silence_timeout:
|
|
122
|
+
data["silence_timeout"] = self.silence_timeout
|
|
123
|
+
|
|
81
124
|
return super().as_json(step_properties=data)
|
|
82
125
|
|
|
83
126
|
@property
|
|
@@ -100,6 +143,7 @@ class CollectInformationFlowStep(FlowStep):
|
|
|
100
143
|
and self.ask_before_filling == other.ask_before_filling
|
|
101
144
|
and self.reset_after_flow_ends == other.reset_after_flow_ends
|
|
102
145
|
and self.force_slot_filling == other.force_slot_filling
|
|
146
|
+
and self.silence_timeout == other.silence_timeout
|
|
103
147
|
and super().__eq__(other)
|
|
104
148
|
)
|
|
105
149
|
return False
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Any, Dict, Text
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, Text
|
|
5
5
|
|
|
6
|
-
from rasa.shared.core.flows.flow_step import FlowStep
|
|
6
|
+
from rasa.shared.core.flows.flow_step import FlowStep, Optional
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from rasa.shared.core.flows.flow import Flow
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
@dataclass
|
|
@@ -12,6 +15,8 @@ class LinkFlowStep(FlowStep):
|
|
|
12
15
|
|
|
13
16
|
link: Text
|
|
14
17
|
"""The id of the flow that should be started subsequently."""
|
|
18
|
+
linked_flow_reference: Optional["Flow"] = None
|
|
19
|
+
"""The flow that is linked to by this step."""
|
|
15
20
|
|
|
16
21
|
def does_allow_for_next_step(self) -> bool:
|
|
17
22
|
"""Returns whether this step allows for following steps.
|