rasa-pro 3.12.0.dev13__py3-none-any.whl → 3.12.0rc2__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.
- README.md +10 -13
- rasa/anonymization/anonymization_rule_executor.py +16 -10
- rasa/cli/data.py +16 -0
- rasa/cli/project_templates/calm/config.yml +2 -2
- rasa/cli/project_templates/calm/domain/list_contacts.yml +1 -2
- rasa/cli/project_templates/calm/domain/remove_contact.yml +1 -2
- rasa/cli/project_templates/calm/domain/shared.yml +1 -4
- rasa/cli/project_templates/calm/endpoints.yml +2 -2
- rasa/cli/utils.py +12 -0
- rasa/core/actions/action.py +84 -191
- rasa/core/actions/action_handle_digressions.py +35 -13
- rasa/core/actions/action_run_slot_rejections.py +16 -4
- rasa/core/channels/__init__.py +2 -0
- rasa/core/channels/studio_chat.py +19 -0
- rasa/core/channels/telegram.py +42 -24
- rasa/core/channels/voice_ready/utils.py +1 -1
- rasa/core/channels/voice_stream/asr/asr_engine.py +10 -4
- rasa/core/channels/voice_stream/asr/azure.py +14 -1
- rasa/core/channels/voice_stream/asr/deepgram.py +20 -4
- rasa/core/channels/voice_stream/audiocodes.py +264 -0
- rasa/core/channels/voice_stream/browser_audio.py +4 -1
- rasa/core/channels/voice_stream/call_state.py +3 -0
- rasa/core/channels/voice_stream/genesys.py +6 -2
- rasa/core/channels/voice_stream/tts/azure.py +9 -1
- rasa/core/channels/voice_stream/tts/cartesia.py +14 -8
- rasa/core/channels/voice_stream/voice_channel.py +23 -2
- rasa/core/constants.py +2 -0
- rasa/core/nlg/contextual_response_rephraser.py +18 -1
- rasa/core/nlg/generator.py +83 -15
- rasa/core/nlg/response.py +6 -3
- rasa/core/nlg/translate.py +55 -0
- rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +1 -1
- rasa/core/policies/flows/flow_executor.py +19 -7
- rasa/core/processor.py +71 -9
- rasa/dialogue_understanding/commands/can_not_handle_command.py +20 -2
- rasa/dialogue_understanding/commands/cancel_flow_command.py +24 -6
- rasa/dialogue_understanding/commands/change_flow_command.py +20 -2
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +20 -2
- rasa/dialogue_understanding/commands/clarify_command.py +29 -3
- rasa/dialogue_understanding/commands/command.py +1 -16
- rasa/dialogue_understanding/commands/command_syntax_manager.py +55 -0
- rasa/dialogue_understanding/commands/handle_digressions_command.py +1 -7
- rasa/dialogue_understanding/commands/human_handoff_command.py +20 -2
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +20 -2
- rasa/dialogue_understanding/commands/prompt_command.py +94 -0
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +20 -2
- rasa/dialogue_understanding/commands/set_slot_command.py +24 -2
- rasa/dialogue_understanding/commands/skip_question_command.py +20 -2
- rasa/dialogue_understanding/commands/start_flow_command.py +22 -2
- rasa/dialogue_understanding/commands/utils.py +71 -4
- rasa/dialogue_understanding/generator/__init__.py +2 -0
- rasa/dialogue_understanding/generator/command_parser.py +15 -12
- rasa/dialogue_understanding/generator/constants.py +3 -0
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +12 -5
- rasa/dialogue_understanding/generator/llm_command_generator.py +5 -3
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +17 -3
- rasa/dialogue_understanding/generator/prompt_templates/__init__.py +0 -0
- rasa/dialogue_understanding/generator/{single_step → prompt_templates}/command_prompt_template.jinja2 +2 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +77 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_default.jinja2 +68 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +84 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +522 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +12 -310
- rasa/dialogue_understanding/patterns/collect_information.py +1 -1
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +16 -0
- rasa/dialogue_understanding/patterns/validate_slot.py +65 -0
- rasa/dialogue_understanding/processor/command_processor.py +39 -0
- rasa/dialogue_understanding/stack/utils.py +38 -0
- rasa/dialogue_understanding_test/du_test_case.py +58 -18
- rasa/dialogue_understanding_test/du_test_result.py +14 -10
- rasa/dialogue_understanding_test/io.py +14 -0
- rasa/e2e_test/assertions.py +6 -8
- rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2 +5 -1
- rasa/e2e_test/llm_judge_prompts/groundedness_prompt_template.jinja2 +4 -0
- rasa/e2e_test/utils/io.py +0 -37
- rasa/engine/graph.py +1 -0
- rasa/engine/language.py +140 -0
- rasa/engine/recipes/config_files/default_config.yml +4 -0
- rasa/engine/recipes/default_recipe.py +2 -0
- rasa/engine/recipes/graph_recipe.py +2 -0
- rasa/engine/storage/local_model_storage.py +1 -0
- rasa/engine/storage/storage.py +4 -1
- rasa/llm_fine_tuning/conversations.py +1 -1
- rasa/model_manager/runner_service.py +7 -4
- rasa/model_manager/socket_bridge.py +7 -6
- rasa/shared/constants.py +15 -13
- rasa/shared/core/constants.py +2 -0
- rasa/shared/core/flows/constants.py +11 -0
- rasa/shared/core/flows/flow.py +83 -19
- rasa/shared/core/flows/flows_yaml_schema.json +31 -3
- rasa/shared/core/flows/steps/collect.py +1 -36
- rasa/shared/core/flows/utils.py +28 -4
- rasa/shared/core/flows/validation.py +1 -1
- rasa/shared/core/slot_mappings.py +208 -5
- rasa/shared/core/slots.py +137 -1
- rasa/shared/core/trackers.py +74 -1
- rasa/shared/importers/importer.py +50 -2
- rasa/shared/nlu/training_data/schemas/responses.yml +19 -12
- rasa/shared/providers/_configs/azure_entra_id_config.py +541 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +138 -3
- rasa/shared/providers/_configs/client_config.py +3 -1
- rasa/shared/providers/_configs/default_litellm_client_config.py +3 -1
- rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +3 -1
- rasa/shared/providers/_configs/litellm_router_client_config.py +3 -1
- rasa/shared/providers/_configs/model_group_config.py +4 -2
- rasa/shared/providers/_configs/oauth_config.py +33 -0
- rasa/shared/providers/_configs/openai_client_config.py +3 -1
- rasa/shared/providers/_configs/rasa_llm_client_config.py +3 -1
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +3 -1
- rasa/shared/providers/constants.py +6 -0
- rasa/shared/providers/embedding/azure_openai_embedding_client.py +28 -3
- rasa/shared/providers/embedding/litellm_router_embedding_client.py +3 -1
- rasa/shared/providers/llm/_base_litellm_client.py +42 -17
- rasa/shared/providers/llm/azure_openai_llm_client.py +81 -25
- rasa/shared/providers/llm/default_litellm_llm_client.py +3 -1
- rasa/shared/providers/llm/litellm_router_llm_client.py +29 -8
- rasa/shared/providers/llm/llm_client.py +23 -7
- rasa/shared/providers/llm/openai_llm_client.py +9 -3
- rasa/shared/providers/llm/rasa_llm_client.py +11 -2
- rasa/shared/providers/llm/self_hosted_llm_client.py +30 -11
- rasa/shared/providers/router/_base_litellm_router_client.py +3 -1
- rasa/shared/providers/router/router_client.py +3 -1
- rasa/shared/utils/constants.py +3 -0
- rasa/shared/utils/llm.py +33 -7
- rasa/shared/utils/pykwalify_extensions.py +24 -0
- rasa/shared/utils/schemas/domain.yml +26 -0
- rasa/telemetry.py +2 -1
- rasa/tracing/config.py +2 -0
- rasa/tracing/constants.py +12 -0
- rasa/tracing/instrumentation/instrumentation.py +36 -0
- rasa/tracing/instrumentation/metrics.py +41 -0
- rasa/tracing/metric_instrument_provider.py +40 -0
- rasa/validator.py +372 -7
- rasa/version.py +1 -1
- {rasa_pro-3.12.0.dev13.dist-info → rasa_pro-3.12.0rc2.dist-info}/METADATA +13 -14
- {rasa_pro-3.12.0.dev13.dist-info → rasa_pro-3.12.0rc2.dist-info}/RECORD +139 -124
- {rasa_pro-3.12.0.dev13.dist-info → rasa_pro-3.12.0rc2.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.0.dev13.dist-info → rasa_pro-3.12.0rc2.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.0.dev13.dist-info → rasa_pro-3.12.0rc2.dist-info}/entry_points.txt +0 -0
|
@@ -4,6 +4,7 @@ from typing import Any, Dict, Optional
|
|
|
4
4
|
import structlog
|
|
5
5
|
from socketio import AsyncServer
|
|
6
6
|
from socketio.asyncio_client import AsyncClient
|
|
7
|
+
from socketio.exceptions import ConnectionRefusedError
|
|
7
8
|
|
|
8
9
|
from rasa.model_manager.runner_service import BotSession
|
|
9
10
|
from rasa.model_manager.studio_jwt_auth import (
|
|
@@ -29,7 +30,7 @@ async def socketio_websocket_traffic_wrapper(
|
|
|
29
30
|
|
|
30
31
|
if auth_token is None:
|
|
31
32
|
structlogger.error("model_runner.user_no_token", sid=sid)
|
|
32
|
-
|
|
33
|
+
raise ConnectionRefusedError("model_runner.user_no_token")
|
|
33
34
|
|
|
34
35
|
try:
|
|
35
36
|
authenticate_user_to_service(auth_token)
|
|
@@ -38,22 +39,22 @@ async def socketio_websocket_traffic_wrapper(
|
|
|
38
39
|
structlogger.error(
|
|
39
40
|
"model_runner.user_authentication_failed", sid=sid, error=str(error)
|
|
40
41
|
)
|
|
41
|
-
|
|
42
|
+
raise ConnectionRefusedError("model_runner.user_authentication_failed")
|
|
42
43
|
|
|
43
44
|
deployment_id = auth.get("deployment_id") if auth else None
|
|
44
45
|
|
|
45
46
|
if deployment_id is None:
|
|
46
47
|
structlogger.error("model_runner.bot_no_deployment_id", sid=sid)
|
|
47
|
-
|
|
48
|
+
raise ConnectionRefusedError("model_runner.bot_no_deployment_id")
|
|
48
49
|
|
|
49
50
|
bot = running_bots.get(deployment_id)
|
|
50
51
|
if bot is None:
|
|
51
52
|
structlogger.error("model_runner.bot_not_found", deployment_id=deployment_id)
|
|
52
|
-
|
|
53
|
+
raise ConnectionRefusedError("model_runner.bot_not_found")
|
|
53
54
|
|
|
54
55
|
if not bot.is_alive():
|
|
55
56
|
structlogger.error("model_runner.bot_not_alive", deployment_id=deployment_id)
|
|
56
|
-
|
|
57
|
+
raise ConnectionRefusedError("model_runner.bot_not_alive")
|
|
57
58
|
|
|
58
59
|
client = await create_bridge_client(sio, bot.internal_url, sid, deployment_id)
|
|
59
60
|
|
|
@@ -67,7 +68,7 @@ async def socketio_websocket_traffic_wrapper(
|
|
|
67
68
|
structlogger.error(
|
|
68
69
|
"model_runner.bot_connection_failed", deployment_id=deployment_id
|
|
69
70
|
)
|
|
70
|
-
|
|
71
|
+
raise ConnectionRefusedError("model_runner.bot_connection_failed")
|
|
71
72
|
|
|
72
73
|
|
|
73
74
|
def create_bridge_server(sio: AsyncServer, running_bots: Dict[str, BotSession]) -> None:
|
rasa/shared/constants.py
CHANGED
|
@@ -83,6 +83,7 @@ ENV_LOG_LEVEL_LLM = "LOG_LEVEL_LLM"
|
|
|
83
83
|
ENV_LOG_LEVEL_LLM_MODULE_NAMES = {
|
|
84
84
|
"LLMCommandGenerator": "LOG_LEVEL_LLM_COMMAND_GENERATOR",
|
|
85
85
|
"SingleStepLLMCommandGenerator": "LOG_LEVEL_LLM_COMMAND_GENERATOR",
|
|
86
|
+
"CompactLLMCommandGenerator": "LOG_LEVEL_LLM_COMMAND_GENERATOR",
|
|
86
87
|
"MultiStepLLMCommandGenerator": "LOG_LEVEL_LLM_COMMAND_GENERATOR",
|
|
87
88
|
"EnterpriseSearchPolicy": "LOG_LEVEL_LLM_ENTERPRISE_SEARCH",
|
|
88
89
|
"IntentlessPolicy": "LOG_LEVEL_LLM_INTENTLESS_POLICY",
|
|
@@ -106,6 +107,7 @@ CONFIG_NAME_KEY = "name"
|
|
|
106
107
|
CONFIG_POLICIES_KEY = "policies"
|
|
107
108
|
CONFIG_PIPELINE_KEY = "pipeline"
|
|
108
109
|
CONFIG_LANGUAGE_KEY = "language"
|
|
110
|
+
CONFIG_ADDITIONAL_LANGUAGES_KEY = "additional_languages"
|
|
109
111
|
CONFIG_RECIPE_KEY = "recipe"
|
|
110
112
|
CONFIG_LLM_KEY = "llm"
|
|
111
113
|
CONFIG_MODEL_NAME_KEY = "model_name"
|
|
@@ -150,6 +152,8 @@ DEFAULT_MARKERS_CONFIG_PATH = "markers/config"
|
|
|
150
152
|
DEFAULT_MARKERS_OUTPUT_PATH = "markers/output"
|
|
151
153
|
DEFAULT_MARKERS_STATS_PATH = "markers/stats"
|
|
152
154
|
|
|
155
|
+
DEFAULT_PROMPT_PACKAGE_NAME = "rasa.dialogue_understanding.generator.prompt_templates"
|
|
156
|
+
|
|
153
157
|
DIAGNOSTIC_DATA = "diagnostic_data"
|
|
154
158
|
|
|
155
159
|
RESPONSE_CONDITION = "condition"
|
|
@@ -162,6 +166,7 @@ AZURE_AD_TOKEN_ENV_VAR = "AZURE_AD_TOKEN"
|
|
|
162
166
|
AZURE_API_BASE_ENV_VAR = "AZURE_API_BASE"
|
|
163
167
|
AZURE_API_VERSION_ENV_VAR = "AZURE_API_VERSION"
|
|
164
168
|
AZURE_API_TYPE_ENV_VAR = "AZURE_API_TYPE"
|
|
169
|
+
AZURE_AD_SCOPES_ENV_VAR = "AZURE_AD_SCOPES"
|
|
165
170
|
AZURE_SPEECH_API_KEY_ENV_VAR = "AZURE_SPEECH_API_KEY"
|
|
166
171
|
|
|
167
172
|
DEEPGRAM_API_KEY_ENV_VAR = "DEEPGRAM_API_KEY"
|
|
@@ -198,7 +203,6 @@ MODEL_CONFIG_KEY = "model"
|
|
|
198
203
|
MODEL_NAME_CONFIG_KEY = "model_name"
|
|
199
204
|
PROMPT_CONFIG_KEY = "prompt"
|
|
200
205
|
PROMPT_TEMPLATE_CONFIG_KEY = "prompt_template"
|
|
201
|
-
|
|
202
206
|
STREAM_CONFIG_KEY = "stream"
|
|
203
207
|
N_REPHRASES_CONFIG_KEY = "n"
|
|
204
208
|
USE_CHAT_COMPLETIONS_ENDPOINT_CONFIG_KEY = "use_chat_completions_endpoint"
|
|
@@ -232,12 +236,6 @@ LITELLM_PARAMS_KEY = "litellm_params"
|
|
|
232
236
|
LLM_API_HEALTH_CHECK_ENV_VAR = "LLM_API_HEALTH_CHECK"
|
|
233
237
|
LLM_API_HEALTH_CHECK_DEFAULT_VALUE = "false"
|
|
234
238
|
|
|
235
|
-
AZURE_API_KEY_ENV_VAR = "AZURE_API_KEY"
|
|
236
|
-
AZURE_AD_TOKEN_ENV_VAR = "AZURE_AD_TOKEN"
|
|
237
|
-
AZURE_API_BASE_ENV_VAR = "AZURE_API_BASE"
|
|
238
|
-
AZURE_API_VERSION_ENV_VAR = "AZURE_API_VERSION"
|
|
239
|
-
AZURE_API_TYPE_ENV_VAR = "AZURE_API_TYPE"
|
|
240
|
-
|
|
241
239
|
AWS_REGION_NAME_CONFIG_KEY = "aws_region_name"
|
|
242
240
|
AWS_ACCESS_KEY_ID_CONFIG_KEY = "aws_access_key_id"
|
|
243
241
|
AWS_SECRET_ACCESS_KEY_CONFIG_KEY = "aws_secret_access_key"
|
|
@@ -273,17 +271,11 @@ RASA_PROVIDER = "rasa"
|
|
|
273
271
|
SELF_HOSTED_VLLM_PREFIX = "hosted_vllm"
|
|
274
272
|
SELF_HOSTED_VLLM_API_KEY_ENV_VAR = "HOSTED_VLLM_API_KEY"
|
|
275
273
|
|
|
276
|
-
SELF_HOSTED_VLLM_PREFIX = "hosted_vllm"
|
|
277
|
-
SELF_HOSTED_VLLM_API_KEY_ENV_VAR = "HOSTED_VLLM_API_KEY"
|
|
278
|
-
|
|
279
274
|
VALID_PROVIDERS_FOR_API_TYPE_CONFIG_KEY = [
|
|
280
275
|
OPENAI_PROVIDER,
|
|
281
276
|
AZURE_OPENAI_PROVIDER,
|
|
282
277
|
]
|
|
283
278
|
|
|
284
|
-
SELF_HOSTED_VLLM_PREFIX = "hosted_vllm"
|
|
285
|
-
SELF_HOSTED_VLLM_API_KEY_ENV_VAR = "HOSTED_VLLM_API_KEY"
|
|
286
|
-
|
|
287
279
|
AZURE_API_TYPE = "azure"
|
|
288
280
|
OPENAI_API_TYPE = "openai"
|
|
289
281
|
|
|
@@ -329,3 +321,13 @@ BUTTONS = "buttons"
|
|
|
329
321
|
ATTACHMENT = "attachment"
|
|
330
322
|
IMAGE = "image"
|
|
331
323
|
CUSTOM = "custom"
|
|
324
|
+
TITLE = "title"
|
|
325
|
+
PAYLOAD = "payload"
|
|
326
|
+
|
|
327
|
+
# Used for LLM command generation
|
|
328
|
+
ROLE_USER = "user"
|
|
329
|
+
ROLE_SYSTEM = "system"
|
|
330
|
+
|
|
331
|
+
# Used for key values in ValidateSlotPatternFlowStackFrame
|
|
332
|
+
REFILL_UTTER = "refill_utter"
|
|
333
|
+
REJECTIONS = "rejections"
|
rasa/shared/core/constants.py
CHANGED
|
@@ -13,6 +13,7 @@ USER_INTENT_SESSION_START = "session_start"
|
|
|
13
13
|
USER_INTENT_SESSION_END = "session_end"
|
|
14
14
|
USER_INTENT_SILENCE_TIMEOUT = "silence_timeout"
|
|
15
15
|
SESSION_START_METADATA_SLOT = "session_started_metadata"
|
|
16
|
+
LANGUAGE_SLOT = "language"
|
|
16
17
|
|
|
17
18
|
DEFAULT_INTENTS = [
|
|
18
19
|
USER_INTENT_RESTART,
|
|
@@ -145,6 +146,7 @@ KEY_MAPPING_TYPE = "type"
|
|
|
145
146
|
KEY_ALLOW_NLU_CORRECTION = "allow_nlu_correction"
|
|
146
147
|
KEY_ACTION = "action"
|
|
147
148
|
KEY_RUN_ACTION_EVERY_TURN = "run_action_every_turn"
|
|
149
|
+
KEY_COEXISTENCE_SYSTEM = "coexistence_system"
|
|
148
150
|
|
|
149
151
|
|
|
150
152
|
class SlotMappingType(Enum):
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
KEY_ID = "id"
|
|
2
|
+
KEY_STEPS = "steps"
|
|
3
|
+
KEY_NAME = "name"
|
|
4
|
+
KEY_DESCRIPTION = "description"
|
|
5
|
+
KEY_IF = "if"
|
|
6
|
+
KEY_ALWAYS_INCLUDE_IN_PROMPT = "always_include_in_prompt"
|
|
7
|
+
KEY_NLU_TRIGGER = "nlu_trigger"
|
|
8
|
+
KEY_FILE_PATH = "file_path"
|
|
9
|
+
KEY_PERSISTED_SLOTS = "persisted_slots"
|
|
10
|
+
KEY_RUN_PATTERN_COMPLETED = "run_pattern_completed"
|
|
11
|
+
KEY_TRANSLATION = "translation"
|
rasa/shared/core/flows/flow.py
CHANGED
|
@@ -7,14 +7,29 @@ from pathlib import Path
|
|
|
7
7
|
from typing import Any, Dict, List, Optional, Set, Text, Union
|
|
8
8
|
|
|
9
9
|
import structlog
|
|
10
|
+
from pydantic import BaseModel
|
|
10
11
|
from pypred import Predicate
|
|
11
12
|
|
|
12
13
|
import rasa.shared.utils.io
|
|
14
|
+
from rasa.engine.language import Language
|
|
13
15
|
from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
|
|
14
16
|
from rasa.shared.core.constants import (
|
|
15
17
|
KEY_ASK_CONFIRM_DIGRESSIONS,
|
|
16
18
|
KEY_BLOCK_DIGRESSIONS,
|
|
17
19
|
)
|
|
20
|
+
from rasa.shared.core.flows.constants import (
|
|
21
|
+
KEY_ALWAYS_INCLUDE_IN_PROMPT,
|
|
22
|
+
KEY_DESCRIPTION,
|
|
23
|
+
KEY_FILE_PATH,
|
|
24
|
+
KEY_ID,
|
|
25
|
+
KEY_IF,
|
|
26
|
+
KEY_NAME,
|
|
27
|
+
KEY_NLU_TRIGGER,
|
|
28
|
+
KEY_PERSISTED_SLOTS,
|
|
29
|
+
KEY_RUN_PATTERN_COMPLETED,
|
|
30
|
+
KEY_STEPS,
|
|
31
|
+
KEY_TRANSLATION,
|
|
32
|
+
)
|
|
18
33
|
from rasa.shared.core.flows.flow_path import FlowPath, FlowPathsList, PathNode
|
|
19
34
|
from rasa.shared.core.flows.flow_step import FlowStep
|
|
20
35
|
from rasa.shared.core.flows.flow_step_links import (
|
|
@@ -43,6 +58,16 @@ from rasa.shared.core.slots import Slot
|
|
|
43
58
|
structlogger = structlog.get_logger()
|
|
44
59
|
|
|
45
60
|
|
|
61
|
+
class FlowLanguageTranslation(BaseModel):
|
|
62
|
+
"""Represents the translation of the flow properties in a specific language."""
|
|
63
|
+
|
|
64
|
+
name: str
|
|
65
|
+
"""The human-readable name of the flow."""
|
|
66
|
+
|
|
67
|
+
class Config:
|
|
68
|
+
extra = "ignore"
|
|
69
|
+
|
|
70
|
+
|
|
46
71
|
@dataclass
|
|
47
72
|
class Flow:
|
|
48
73
|
"""Represents the configuration of a flow."""
|
|
@@ -53,6 +78,8 @@ class Flow:
|
|
|
53
78
|
"""The human-readable name of the flow."""
|
|
54
79
|
description: Optional[Text] = None
|
|
55
80
|
"""The description of the flow."""
|
|
81
|
+
translation: Dict[Text, FlowLanguageTranslation] = field(default_factory=dict)
|
|
82
|
+
"""The translation of the flow properties in different languages."""
|
|
56
83
|
guard_condition: Optional[Text] = None
|
|
57
84
|
"""The condition that needs to be fulfilled for the flow to be startable."""
|
|
58
85
|
step_sequence: FlowStepSequence = field(default_factory=FlowStepSequence.empty)
|
|
@@ -71,6 +98,8 @@ class Flow:
|
|
|
71
98
|
"""The flow ids for which the assistant should ask for confirmation."""
|
|
72
99
|
block_digressions: List[str] = field(default_factory=list)
|
|
73
100
|
"""The flow ids that the assistant should block from digressing to."""
|
|
101
|
+
run_pattern_completed: bool = True
|
|
102
|
+
"""Whether the pattern_completed flow should be run after the flow ends."""
|
|
74
103
|
|
|
75
104
|
@staticmethod
|
|
76
105
|
def from_json(
|
|
@@ -88,6 +117,8 @@ class Flow:
|
|
|
88
117
|
Returns:
|
|
89
118
|
A Flow object.
|
|
90
119
|
"""
|
|
120
|
+
from rasa.shared.core.flows.utils import extract_translations
|
|
121
|
+
|
|
91
122
|
step_sequence = FlowStepSequence.from_json(flow_id, data.get("steps"))
|
|
92
123
|
nlu_triggers = NLUTriggers.from_json(data.get("nlu_trigger"))
|
|
93
124
|
|
|
@@ -96,21 +127,25 @@ class Flow:
|
|
|
96
127
|
|
|
97
128
|
return Flow(
|
|
98
129
|
id=flow_id,
|
|
99
|
-
custom_name=data.get(
|
|
100
|
-
description=data.get(
|
|
101
|
-
always_include_in_prompt=data.get(
|
|
102
|
-
# str or bool are permitted in the flow schema but internally we want a str
|
|
103
|
-
guard_condition=str(data[
|
|
130
|
+
custom_name=data.get(KEY_NAME),
|
|
131
|
+
description=data.get(KEY_DESCRIPTION),
|
|
132
|
+
always_include_in_prompt=data.get(KEY_ALWAYS_INCLUDE_IN_PROMPT),
|
|
133
|
+
# str or bool are permitted in the flow schema, but internally we want a str
|
|
134
|
+
guard_condition=str(data[KEY_IF]) if KEY_IF in data else None,
|
|
104
135
|
step_sequence=Flow.resolve_default_ids(step_sequence),
|
|
105
136
|
nlu_triggers=nlu_triggers,
|
|
106
137
|
# If we are reading the flows in after training the file_path is part of
|
|
107
138
|
# data. When the model is trained, take the provided file_path.
|
|
108
|
-
file_path=data.get(
|
|
109
|
-
persisted_slots=data.get(
|
|
139
|
+
file_path=data.get(KEY_FILE_PATH) if KEY_FILE_PATH in data else file_path,
|
|
140
|
+
persisted_slots=data.get(KEY_PERSISTED_SLOTS, []),
|
|
110
141
|
ask_confirm_digressions=extract_digression_prop(
|
|
111
142
|
KEY_ASK_CONFIRM_DIGRESSIONS, data
|
|
112
143
|
),
|
|
113
144
|
block_digressions=extract_digression_prop(KEY_BLOCK_DIGRESSIONS, data),
|
|
145
|
+
run_pattern_completed=data.get(KEY_RUN_PATTERN_COMPLETED, True),
|
|
146
|
+
translation=extract_translations(
|
|
147
|
+
translation_data=data.get(KEY_TRANSLATION, {})
|
|
148
|
+
),
|
|
114
149
|
)
|
|
115
150
|
|
|
116
151
|
def get_full_name(self) -> str:
|
|
@@ -168,33 +203,62 @@ class Flow:
|
|
|
168
203
|
The Flow object as serialized data.
|
|
169
204
|
"""
|
|
170
205
|
data: Dict[Text, Any] = {
|
|
171
|
-
|
|
172
|
-
|
|
206
|
+
KEY_ID: self.id,
|
|
207
|
+
KEY_STEPS: self.step_sequence.as_json(),
|
|
173
208
|
}
|
|
174
209
|
if self.custom_name is not None:
|
|
175
|
-
data[
|
|
210
|
+
data[KEY_NAME] = self.custom_name
|
|
176
211
|
if self.description is not None:
|
|
177
|
-
data[
|
|
212
|
+
data[KEY_DESCRIPTION] = self.description
|
|
178
213
|
if self.guard_condition is not None:
|
|
179
|
-
data[
|
|
214
|
+
data[KEY_IF] = self.guard_condition
|
|
180
215
|
if self.always_include_in_prompt is not None:
|
|
181
|
-
data[
|
|
216
|
+
data[KEY_ALWAYS_INCLUDE_IN_PROMPT] = self.always_include_in_prompt
|
|
182
217
|
if self.nlu_triggers:
|
|
183
|
-
data[
|
|
218
|
+
data[KEY_NLU_TRIGGER] = self.nlu_triggers.as_json()
|
|
184
219
|
if self.file_path:
|
|
185
|
-
data[
|
|
220
|
+
data[KEY_FILE_PATH] = self.file_path
|
|
186
221
|
if self.persisted_slots:
|
|
187
|
-
data[
|
|
222
|
+
data[KEY_PERSISTED_SLOTS] = self.persisted_slots
|
|
188
223
|
if self.ask_confirm_digressions:
|
|
189
224
|
data[KEY_ASK_CONFIRM_DIGRESSIONS] = self.ask_confirm_digressions
|
|
190
225
|
if self.block_digressions:
|
|
191
226
|
data[KEY_BLOCK_DIGRESSIONS] = self.block_digressions
|
|
227
|
+
if self.run_pattern_completed is not None:
|
|
228
|
+
data["run_pattern_completed"] = self.run_pattern_completed
|
|
229
|
+
if self.translation:
|
|
230
|
+
data[KEY_TRANSLATION] = {
|
|
231
|
+
language_code: translation.dict()
|
|
232
|
+
for language_code, translation in self.translation.items()
|
|
233
|
+
}
|
|
192
234
|
|
|
193
235
|
return data
|
|
194
236
|
|
|
195
|
-
def
|
|
196
|
-
"""Returns the
|
|
197
|
-
|
|
237
|
+
def localized_name(self, language: Optional[Language] = None) -> Optional[Text]:
|
|
238
|
+
"""Returns the language specific flow name or None.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
language: Preferred language code.
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
Flow name in the specified language or None.
|
|
245
|
+
"""
|
|
246
|
+
language_code = language.code if language else None
|
|
247
|
+
translation = self.translation.get(language_code)
|
|
248
|
+
return translation.name if translation else None
|
|
249
|
+
|
|
250
|
+
def readable_name(self, language: Optional[Language] = None) -> str:
|
|
251
|
+
"""
|
|
252
|
+
Returns the flow's name in the specified language if available; otherwise
|
|
253
|
+
falls back to the flow's name, and finally the flow's ID.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
language: Preferred language code.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
string: the localized name, the default name, or the flow's ID.
|
|
260
|
+
"""
|
|
261
|
+
return self.localized_name(language) or self.name or self.id
|
|
198
262
|
|
|
199
263
|
def step_by_id(self, step_id: Optional[Text]) -> Optional[FlowStep]:
|
|
200
264
|
"""Returns the step with the given id."""
|
|
@@ -288,9 +288,37 @@
|
|
|
288
288
|
"additionalProperties": false,
|
|
289
289
|
"schema_name": "dictionary with flow properties",
|
|
290
290
|
"properties": {
|
|
291
|
+
"name": {
|
|
292
|
+
"type": "string"
|
|
293
|
+
},
|
|
291
294
|
"description": {
|
|
292
295
|
"type": "string"
|
|
293
296
|
},
|
|
297
|
+
"translation": {
|
|
298
|
+
"type": "object",
|
|
299
|
+
"schema_name": "flow translation mapping",
|
|
300
|
+
"properties": {
|
|
301
|
+
"metadata": {
|
|
302
|
+
"type": "object"
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
"patternProperties": {
|
|
306
|
+
"^(?!metadata$).+": {
|
|
307
|
+
"type": "object",
|
|
308
|
+
"additionalProperties": false,
|
|
309
|
+
"required": [
|
|
310
|
+
"name"
|
|
311
|
+
],
|
|
312
|
+
"properties": {
|
|
313
|
+
"name": {
|
|
314
|
+
"type": "string"
|
|
315
|
+
},
|
|
316
|
+
"metadata": {}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
"additionalProperties": false
|
|
321
|
+
},
|
|
294
322
|
"if": {
|
|
295
323
|
"type": [
|
|
296
324
|
"string",
|
|
@@ -300,9 +328,6 @@
|
|
|
300
328
|
"always_include_in_prompt": {
|
|
301
329
|
"type": "boolean"
|
|
302
330
|
},
|
|
303
|
-
"name": {
|
|
304
|
-
"type": "string"
|
|
305
|
-
},
|
|
306
331
|
"nlu_trigger": {
|
|
307
332
|
"$ref": "#/$defs/nlu_trigger"
|
|
308
333
|
},
|
|
@@ -320,6 +345,9 @@
|
|
|
320
345
|
},
|
|
321
346
|
"block_digressions": {
|
|
322
347
|
"$ref": "#/$defs/block_digressions"
|
|
348
|
+
},
|
|
349
|
+
"run_pattern_completed": {
|
|
350
|
+
"type": "boolean"
|
|
323
351
|
}
|
|
324
352
|
}
|
|
325
353
|
},
|
|
@@ -10,42 +10,7 @@ from rasa.shared.core.constants import (
|
|
|
10
10
|
)
|
|
11
11
|
from rasa.shared.core.flows.flow_step import FlowStep
|
|
12
12
|
from rasa.shared.core.flows.utils import extract_digression_prop
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@dataclass
|
|
16
|
-
class SlotRejection:
|
|
17
|
-
"""A pair of validation condition and an utterance for the case of failure."""
|
|
18
|
-
|
|
19
|
-
if_: str
|
|
20
|
-
"""The condition that should be checked."""
|
|
21
|
-
utter: str
|
|
22
|
-
"""The utterance that should be executed if the condition is met."""
|
|
23
|
-
|
|
24
|
-
@staticmethod
|
|
25
|
-
def from_dict(data: Dict[str, Any]) -> SlotRejection:
|
|
26
|
-
"""Create a SlotRejection object from serialized data.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
data: data for a SlotRejection object in a serialized format
|
|
30
|
-
|
|
31
|
-
Returns:
|
|
32
|
-
A SlotRejection object
|
|
33
|
-
"""
|
|
34
|
-
return SlotRejection(
|
|
35
|
-
if_=data["if"],
|
|
36
|
-
utter=data["utter"],
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
def as_dict(self) -> Dict[str, Any]:
|
|
40
|
-
"""Serialize the SlotRejection object.
|
|
41
|
-
|
|
42
|
-
Returns:
|
|
43
|
-
the SlotRejection object as serialized data
|
|
44
|
-
"""
|
|
45
|
-
return {
|
|
46
|
-
"if": self.if_,
|
|
47
|
-
"utter": self.utter,
|
|
48
|
-
}
|
|
13
|
+
from rasa.shared.core.slots import SlotRejection
|
|
49
14
|
|
|
50
15
|
|
|
51
16
|
@dataclass
|
rasa/shared/core/flows/utils.py
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
from typing import Any, Dict, List, Set
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Set, Text
|
|
2
2
|
|
|
3
3
|
from rasa.shared.utils.io import raise_deprecation_warning
|
|
4
4
|
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from rasa.shared.core.flows.flow import FlowLanguageTranslation
|
|
7
|
+
|
|
8
|
+
|
|
5
9
|
RESET_PROPERTY_NAME = "reset_after_flow_ends"
|
|
6
10
|
PERSIST_PROPERTY_NAME = "persisted_slots"
|
|
7
11
|
ALL_LABEL = "ALL"
|
|
8
12
|
|
|
9
13
|
|
|
10
|
-
def warn_deprecated_collect_step_config(
|
|
14
|
+
def warn_deprecated_collect_step_config() -> None:
|
|
11
15
|
"""Warns about deprecated reset_after_flow_ends usage in collect steps."""
|
|
12
16
|
raise_deprecation_warning(
|
|
13
|
-
f"Configuring '{RESET_PROPERTY_NAME}' in collect
|
|
14
|
-
f"deprecated and will be removed in Rasa Pro 4.0.0. In
|
|
17
|
+
f"Configuring '{RESET_PROPERTY_NAME}' in collect steps is "
|
|
18
|
+
f"deprecated and will be removed in Rasa Pro 4.0.0. In the parent flow, "
|
|
15
19
|
f"please use the '{PERSIST_PROPERTY_NAME}' "
|
|
16
20
|
"property at the flow level instead."
|
|
17
21
|
)
|
|
@@ -53,3 +57,23 @@ def extract_digression_prop(prop: str, data: Dict[str, Any]) -> List[str]:
|
|
|
53
57
|
digression_property = [ALL_LABEL] if digression_property else []
|
|
54
58
|
|
|
55
59
|
return digression_property
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def extract_translations(
|
|
63
|
+
translation_data: Dict[Text, Any],
|
|
64
|
+
) -> Dict[Text, "FlowLanguageTranslation"]:
|
|
65
|
+
"""Extracts translations from a dictionary.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
translation_data: The dictionary containing the translations.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
A dictionary containing the extracted translations.
|
|
72
|
+
"""
|
|
73
|
+
from rasa.shared.core.flows.flow import FlowLanguageTranslation
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
language_code: FlowLanguageTranslation.parse_obj({**data})
|
|
77
|
+
for language_code, data in translation_data.items()
|
|
78
|
+
if language_code != "metadata"
|
|
79
|
+
}
|
|
@@ -723,7 +723,7 @@ def validate_slot_persistence_configuration(flow: Flow) -> None:
|
|
|
723
723
|
flow_slots.add(step.collect)
|
|
724
724
|
if not step.reset_after_flow_ends:
|
|
725
725
|
collect_step = step.collect
|
|
726
|
-
warn_deprecated_collect_step_config(
|
|
726
|
+
warn_deprecated_collect_step_config()
|
|
727
727
|
if has_flow_level_persistence:
|
|
728
728
|
raise DuplicateSlotPersistConfigException(flow_id, collect_step)
|
|
729
729
|
|