rasa-pro 3.10.7.dev5__py3-none-any.whl → 3.10.8__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 +37 -1
- rasa/api.py +2 -8
- rasa/cli/arguments/default_arguments.py +2 -23
- rasa/cli/arguments/run.py +0 -2
- rasa/cli/e2e_test.py +8 -10
- rasa/cli/inspect.py +2 -5
- rasa/cli/run.py +0 -7
- rasa/cli/studio/studio.py +21 -1
- rasa/cli/train.py +4 -9
- rasa/cli/utils.py +3 -3
- rasa/core/agent.py +2 -2
- rasa/core/brokers/kafka.py +1 -3
- rasa/core/brokers/pika.py +1 -3
- rasa/core/channels/socketio.py +1 -5
- rasa/core/channels/voice_aware/utils.py +5 -6
- rasa/core/nlg/contextual_response_rephraser.py +2 -11
- rasa/core/policies/enterprise_search_policy.py +2 -11
- rasa/core/policies/intentless_policy.py +2 -9
- rasa/core/run.py +1 -2
- rasa/core/secrets_manager/constants.py +0 -4
- rasa/core/secrets_manager/factory.py +0 -8
- rasa/core/secrets_manager/vault.py +1 -11
- rasa/core/utils.py +19 -30
- rasa/dialogue_understanding/coexistence/llm_based_router.py +2 -9
- rasa/dialogue_understanding/commands/__init__.py +2 -0
- rasa/dialogue_understanding/commands/restart_command.py +58 -0
- rasa/dialogue_understanding/commands/set_slot_command.py +5 -1
- rasa/dialogue_understanding/commands/utils.py +3 -1
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +2 -11
- rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +15 -15
- rasa/dialogue_understanding/patterns/restart.py +37 -0
- rasa/e2e_test/e2e_test_runner.py +1 -1
- rasa/engine/graph.py +1 -0
- rasa/engine/recipes/config_files/default_config.yml +3 -0
- rasa/engine/recipes/default_recipe.py +1 -0
- rasa/engine/recipes/graph_recipe.py +1 -0
- rasa/engine/storage/local_model_storage.py +1 -0
- rasa/engine/storage/storage.py +5 -1
- rasa/model_training.py +6 -11
- rasa/{core → nlu}/persistor.py +1 -1
- rasa/server.py +1 -1
- rasa/shared/constants.py +3 -2
- rasa/shared/core/domain.py +47 -101
- rasa/shared/core/flows/flows_list.py +6 -19
- rasa/shared/core/flows/validation.py +0 -25
- rasa/shared/core/flows/yaml_flows_io.py +24 -3
- rasa/shared/importers/importer.py +32 -32
- rasa/shared/importers/multi_project.py +11 -23
- rasa/shared/importers/rasa.py +2 -7
- rasa/shared/importers/remote_importer.py +2 -2
- rasa/shared/importers/utils.py +1 -3
- rasa/shared/nlu/training_data/training_data.py +19 -18
- rasa/shared/providers/_configs/azure_openai_client_config.py +5 -3
- rasa/shared/providers/llm/_base_litellm_client.py +26 -10
- rasa/shared/providers/llm/self_hosted_llm_client.py +15 -3
- rasa/shared/utils/common.py +22 -3
- rasa/shared/utils/llm.py +5 -29
- rasa/shared/utils/schemas/model_config.yml +10 -0
- rasa/studio/auth.py +4 -0
- rasa/tracing/instrumentation/attribute_extractors.py +1 -1
- rasa/validator.py +5 -2
- rasa/version.py +1 -1
- {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.8.dist-info}/METADATA +43 -7
- {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.8.dist-info}/RECORD +68 -74
- rasa/model_manager/__init__.py +0 -0
- rasa/model_manager/config.py +0 -12
- rasa/model_manager/model_api.py +0 -467
- rasa/model_manager/runner_service.py +0 -185
- rasa/model_manager/socket_bridge.py +0 -44
- rasa/model_manager/trainer_service.py +0 -240
- rasa/model_manager/utils.py +0 -27
- rasa/model_service.py +0 -66
- {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.8.dist-info}/NOTICE +0 -0
- {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.8.dist-info}/WHEEL +0 -0
- {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.8.dist-info}/entry_points.txt +0 -0
rasa/shared/constants.py
CHANGED
|
@@ -183,8 +183,6 @@ STREAM_CONFIG_KEY = "stream"
|
|
|
183
183
|
N_REPHRASES_CONFIG_KEY = "n"
|
|
184
184
|
USE_CHAT_COMPLETIONS_ENDPOINT_CONFIG_KEY = "use_chat_completions_endpoint"
|
|
185
185
|
|
|
186
|
-
LLM_API_HEALTH_CHECK_ENV_VAR = "LLM_API_HEALTH_CHECK"
|
|
187
|
-
|
|
188
186
|
AZURE_API_KEY_ENV_VAR = "AZURE_API_KEY"
|
|
189
187
|
AZURE_AD_TOKEN_ENV_VAR = "AZURE_AD_TOKEN"
|
|
190
188
|
AZURE_API_BASE_ENV_VAR = "AZURE_API_BASE"
|
|
@@ -212,6 +210,9 @@ AZURE_OPENAI_PROVIDER = "azure"
|
|
|
212
210
|
SELF_HOSTED_PROVIDER = "self-hosted"
|
|
213
211
|
HUGGINGFACE_LOCAL_EMBEDDING_PROVIDER = "huggingface_local"
|
|
214
212
|
|
|
213
|
+
SELF_HOSTED_VLLM_PREFIX = "hosted_vllm"
|
|
214
|
+
SELF_HOSTED_VLLM_API_KEY_ENV_VAR = "HOSTED_VLLM_API_KEY"
|
|
215
|
+
|
|
215
216
|
AZURE_API_TYPE = "azure"
|
|
216
217
|
OPENAI_API_TYPE = "openai"
|
|
217
218
|
|
rasa/shared/core/domain.py
CHANGED
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
import collections
|
|
4
2
|
import copy
|
|
5
3
|
import json
|
|
6
4
|
import os
|
|
7
5
|
from dataclasses import dataclass
|
|
8
|
-
from functools import cached_property
|
|
9
6
|
from pathlib import Path
|
|
10
7
|
from typing import (
|
|
11
8
|
TYPE_CHECKING,
|
|
12
9
|
Any,
|
|
13
10
|
Callable,
|
|
14
|
-
ClassVar,
|
|
15
11
|
Dict,
|
|
16
12
|
Iterable,
|
|
17
13
|
List,
|
|
18
|
-
MutableMapping,
|
|
19
14
|
NamedTuple,
|
|
20
15
|
NoReturn,
|
|
21
16
|
Optional,
|
|
@@ -24,6 +19,7 @@ from typing import (
|
|
|
24
19
|
Tuple,
|
|
25
20
|
Union,
|
|
26
21
|
cast,
|
|
22
|
+
MutableMapping,
|
|
27
23
|
)
|
|
28
24
|
|
|
29
25
|
import structlog
|
|
@@ -55,11 +51,11 @@ from rasa.shared.core.constants import (
|
|
|
55
51
|
)
|
|
56
52
|
from rasa.shared.core.events import SlotSet, UserUttered
|
|
57
53
|
from rasa.shared.core.slots import (
|
|
58
|
-
AnySlot,
|
|
59
|
-
CategoricalSlot,
|
|
60
|
-
ListSlot,
|
|
61
54
|
Slot,
|
|
55
|
+
CategoricalSlot,
|
|
62
56
|
TextSlot,
|
|
57
|
+
AnySlot,
|
|
58
|
+
ListSlot,
|
|
63
59
|
)
|
|
64
60
|
from rasa.shared.exceptions import (
|
|
65
61
|
RasaException,
|
|
@@ -67,21 +63,21 @@ from rasa.shared.exceptions import (
|
|
|
67
63
|
YamlSyntaxException,
|
|
68
64
|
)
|
|
69
65
|
from rasa.shared.nlu.constants import (
|
|
70
|
-
ENTITIES,
|
|
71
|
-
ENTITY_ATTRIBUTE_GROUP,
|
|
72
|
-
ENTITY_ATTRIBUTE_ROLE,
|
|
73
66
|
ENTITY_ATTRIBUTE_TYPE,
|
|
74
|
-
|
|
67
|
+
ENTITY_ATTRIBUTE_ROLE,
|
|
68
|
+
ENTITY_ATTRIBUTE_GROUP,
|
|
75
69
|
RESPONSE_IDENTIFIER_DELIMITER,
|
|
70
|
+
INTENT_NAME_KEY,
|
|
71
|
+
ENTITIES,
|
|
76
72
|
)
|
|
77
73
|
from rasa.shared.utils.cli import print_error_and_exit
|
|
78
74
|
from rasa.shared.utils.yaml import (
|
|
79
75
|
KEY_TRAINING_DATA_FORMAT_VERSION,
|
|
80
|
-
dump_obj_as_yaml_to_string,
|
|
81
76
|
read_yaml,
|
|
77
|
+
validate_training_data_format_version,
|
|
82
78
|
read_yaml_file,
|
|
79
|
+
dump_obj_as_yaml_to_string,
|
|
83
80
|
validate_raw_yaml_using_schema_file_with_responses,
|
|
84
|
-
validate_training_data_format_version,
|
|
85
81
|
)
|
|
86
82
|
|
|
87
83
|
if TYPE_CHECKING:
|
|
@@ -159,7 +155,7 @@ class SessionConfig(NamedTuple):
|
|
|
159
155
|
carry_over_slots: bool
|
|
160
156
|
|
|
161
157
|
@staticmethod
|
|
162
|
-
def default() -> SessionConfig:
|
|
158
|
+
def default() -> "SessionConfig":
|
|
163
159
|
"""Returns the SessionConfig with the default values."""
|
|
164
160
|
return SessionConfig(
|
|
165
161
|
DEFAULT_SESSION_EXPIRATION_TIME_IN_MINUTES,
|
|
@@ -195,15 +191,13 @@ class Domain:
|
|
|
195
191
|
and entities it can recognise.
|
|
196
192
|
"""
|
|
197
193
|
|
|
198
|
-
validate_yaml: ClassVar[bool] = True
|
|
199
|
-
|
|
200
194
|
@classmethod
|
|
201
|
-
def empty(cls) -> Domain:
|
|
195
|
+
def empty(cls) -> "Domain":
|
|
202
196
|
"""Returns empty Domain."""
|
|
203
197
|
return Domain.from_dict({})
|
|
204
198
|
|
|
205
199
|
@classmethod
|
|
206
|
-
def load(cls, paths: Union[List[Union[Path, Text]], Text, Path]) -> Domain:
|
|
200
|
+
def load(cls, paths: Union[List[Union[Path, Text]], Text, Path]) -> "Domain":
|
|
207
201
|
"""Returns loaded Domain after merging all domain files."""
|
|
208
202
|
if not paths:
|
|
209
203
|
raise InvalidDomain(
|
|
@@ -221,15 +215,8 @@ class Domain:
|
|
|
221
215
|
return domain
|
|
222
216
|
|
|
223
217
|
@classmethod
|
|
224
|
-
def from_path(cls, path: Union[Text, Path]) -> Domain:
|
|
225
|
-
"""Loads the `Domain` from a path.
|
|
226
|
-
|
|
227
|
-
Args:
|
|
228
|
-
path: Path to the domain file.
|
|
229
|
-
|
|
230
|
-
Returns:
|
|
231
|
-
The instantiated `Domain` object.
|
|
232
|
-
"""
|
|
218
|
+
def from_path(cls, path: Union[Text, Path]) -> "Domain":
|
|
219
|
+
"""Loads the `Domain` from a path."""
|
|
233
220
|
path = os.path.abspath(path)
|
|
234
221
|
|
|
235
222
|
if os.path.isfile(path):
|
|
@@ -245,30 +232,17 @@ class Domain:
|
|
|
245
232
|
return domain
|
|
246
233
|
|
|
247
234
|
@classmethod
|
|
248
|
-
def from_file(cls, path: Text) -> Domain:
|
|
249
|
-
"""Loads the `Domain` from a YAML file.
|
|
250
|
-
|
|
251
|
-
Args:
|
|
252
|
-
path: Path to the domain file.
|
|
253
|
-
|
|
254
|
-
Returns:
|
|
255
|
-
The instantiated `Domain` object.
|
|
256
|
-
"""
|
|
235
|
+
def from_file(cls, path: Text) -> "Domain":
|
|
236
|
+
"""Loads the `Domain` from a YAML file."""
|
|
257
237
|
return cls.from_yaml(rasa.shared.utils.io.read_file(path), path)
|
|
258
238
|
|
|
259
239
|
@classmethod
|
|
260
|
-
def from_yaml(cls, yaml: Text, original_filename: Text = "") -> Domain:
|
|
261
|
-
"""Loads the `Domain` from YAML text after validating it.
|
|
262
|
-
|
|
263
|
-
Args:
|
|
264
|
-
yaml: The YAML string to load the domain from.
|
|
265
|
-
original_filename: The filename of the original YAML file.
|
|
266
|
-
|
|
267
|
-
Returns:
|
|
268
|
-
The instantiated `Domain` object.
|
|
269
|
-
"""
|
|
240
|
+
def from_yaml(cls, yaml: Text, original_filename: Text = "") -> "Domain":
|
|
241
|
+
"""Loads the `Domain` from YAML text after validating it."""
|
|
270
242
|
try:
|
|
271
|
-
|
|
243
|
+
validate_raw_yaml_using_schema_file_with_responses(yaml, DOMAIN_SCHEMA_FILE)
|
|
244
|
+
|
|
245
|
+
data = read_yaml(yaml)
|
|
272
246
|
if not validate_training_data_format_version(data, original_filename):
|
|
273
247
|
return Domain.empty()
|
|
274
248
|
return cls.from_dict(data)
|
|
@@ -277,7 +251,7 @@ class Domain:
|
|
|
277
251
|
raise e
|
|
278
252
|
|
|
279
253
|
@classmethod
|
|
280
|
-
def from_dict(cls, data: Dict) -> Domain:
|
|
254
|
+
def from_dict(cls, data: Dict) -> "Domain":
|
|
281
255
|
"""Deserializes and creates domain.
|
|
282
256
|
|
|
283
257
|
Args:
|
|
@@ -308,8 +282,8 @@ class Domain:
|
|
|
308
282
|
_validate_forms(forms)
|
|
309
283
|
|
|
310
284
|
return cls(
|
|
311
|
-
intents=intents
|
|
312
|
-
entities=data.get(KEY_ENTITIES,
|
|
285
|
+
intents=intents,
|
|
286
|
+
entities=data.get(KEY_ENTITIES, {}),
|
|
313
287
|
slots=slots,
|
|
314
288
|
responses=responses,
|
|
315
289
|
action_names=actions,
|
|
@@ -334,15 +308,8 @@ class Domain:
|
|
|
334
308
|
return SessionConfig(session_expiration_time_min, carry_over_slots)
|
|
335
309
|
|
|
336
310
|
@classmethod
|
|
337
|
-
def from_directory(cls, path: Text) -> Domain:
|
|
338
|
-
"""Loads and merges multiple domain files recursively from a directory tree.
|
|
339
|
-
|
|
340
|
-
Args:
|
|
341
|
-
path: Path to the root directory.
|
|
342
|
-
|
|
343
|
-
Returns:
|
|
344
|
-
The instantiated `Domain` object.
|
|
345
|
-
"""
|
|
311
|
+
def from_directory(cls, path: Text) -> "Domain":
|
|
312
|
+
"""Loads and merges multiple domain files recursively from a directory tree."""
|
|
346
313
|
combined: Dict[Text, Any] = {}
|
|
347
314
|
duplicates: List[Dict[Text, List[Text]]] = []
|
|
348
315
|
|
|
@@ -352,10 +319,10 @@ class Domain:
|
|
|
352
319
|
if not Domain.is_domain_file(full_path):
|
|
353
320
|
continue
|
|
354
321
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
)
|
|
322
|
+
# does the validation here only
|
|
323
|
+
_ = Domain.from_file(full_path)
|
|
358
324
|
|
|
325
|
+
other_dict = read_yaml(rasa.shared.utils.io.read_file(full_path))
|
|
359
326
|
combined = Domain.merge_domain_dicts(other_dict, combined)
|
|
360
327
|
duplicates.append(combined.pop("duplicates", {}))
|
|
361
328
|
|
|
@@ -401,10 +368,10 @@ class Domain:
|
|
|
401
368
|
|
|
402
369
|
def merge(
|
|
403
370
|
self,
|
|
404
|
-
domain: Optional[Domain],
|
|
371
|
+
domain: Optional["Domain"],
|
|
405
372
|
override: bool = False,
|
|
406
373
|
ignore_warnings_about_duplicates: bool = False,
|
|
407
|
-
) -> Domain:
|
|
374
|
+
) -> "Domain":
|
|
408
375
|
"""Merges this domain dict with another one, combining their attributes.
|
|
409
376
|
|
|
410
377
|
This method merges domain dicts, and ensures all attributes (like ``intents``,
|
|
@@ -707,7 +674,7 @@ class Domain:
|
|
|
707
674
|
|
|
708
675
|
return intent
|
|
709
676
|
|
|
710
|
-
@
|
|
677
|
+
@rasa.shared.utils.common.lazy_property
|
|
711
678
|
def retrieval_intents(self) -> List[Text]:
|
|
712
679
|
"""List retrieval intents present in the domain."""
|
|
713
680
|
return [
|
|
@@ -932,7 +899,7 @@ class Domain:
|
|
|
932
899
|
self.store_entities_as_slots = store_entities_as_slots
|
|
933
900
|
self._check_domain_sanity()
|
|
934
901
|
|
|
935
|
-
def __deepcopy__(self, memo: Optional[Dict[int, Any]]) -> Domain:
|
|
902
|
+
def __deepcopy__(self, memo: Optional[Dict[int, Any]]) -> "Domain":
|
|
936
903
|
"""Enables making a deep copy of the `Domain` using `copy.deepcopy`.
|
|
937
904
|
|
|
938
905
|
See https://docs.python.org/3/library/copy.html#copy.deepcopy
|
|
@@ -1036,23 +1003,23 @@ class Domain:
|
|
|
1036
1003
|
sorted_intents = sorted(intents, key=sort)
|
|
1037
1004
|
return sorted_intents
|
|
1038
1005
|
|
|
1039
|
-
@
|
|
1006
|
+
@rasa.shared.utils.common.lazy_property
|
|
1040
1007
|
def user_actions_and_forms(self) -> List[Text]:
|
|
1041
1008
|
"""Returns combination of user actions and forms."""
|
|
1042
1009
|
return self.user_actions + self.form_names
|
|
1043
1010
|
|
|
1044
|
-
@
|
|
1011
|
+
@rasa.shared.utils.common.lazy_property
|
|
1045
1012
|
def num_actions(self) -> int:
|
|
1046
1013
|
"""Returns the number of available actions."""
|
|
1047
1014
|
# noinspection PyTypeChecker
|
|
1048
1015
|
return len(self.action_names_or_texts)
|
|
1049
1016
|
|
|
1050
|
-
@
|
|
1017
|
+
@rasa.shared.utils.common.lazy_property
|
|
1051
1018
|
def num_states(self) -> int:
|
|
1052
1019
|
"""Number of used input states for the action prediction."""
|
|
1053
1020
|
return len(self.input_states)
|
|
1054
1021
|
|
|
1055
|
-
@
|
|
1022
|
+
@rasa.shared.utils.common.lazy_property
|
|
1056
1023
|
def retrieval_intent_responses(self) -> Dict[Text, List[Dict[Text, Any]]]:
|
|
1057
1024
|
"""Return only the responses which are defined for retrieval intents."""
|
|
1058
1025
|
return dict(
|
|
@@ -1204,7 +1171,8 @@ class Domain:
|
|
|
1204
1171
|
f"Available actions are: \n{action_names}"
|
|
1205
1172
|
)
|
|
1206
1173
|
|
|
1207
|
-
|
|
1174
|
+
# noinspection PyTypeChecker
|
|
1175
|
+
@rasa.shared.utils.common.lazy_property
|
|
1208
1176
|
def slot_states(self) -> List[Text]:
|
|
1209
1177
|
"""Returns all available slot state strings."""
|
|
1210
1178
|
return [
|
|
@@ -1213,7 +1181,8 @@ class Domain:
|
|
|
1213
1181
|
for feature_index in range(0, slot.feature_dimensionality())
|
|
1214
1182
|
]
|
|
1215
1183
|
|
|
1216
|
-
|
|
1184
|
+
# noinspection PyTypeChecker
|
|
1185
|
+
@rasa.shared.utils.common.lazy_property
|
|
1217
1186
|
def entity_states(self) -> List[Text]:
|
|
1218
1187
|
"""Returns all available entity state strings."""
|
|
1219
1188
|
entity_states = copy.deepcopy(self.entities)
|
|
@@ -1261,12 +1230,12 @@ class Domain:
|
|
|
1261
1230
|
for entity_sub_label in entity_sub_labels
|
|
1262
1231
|
]
|
|
1263
1232
|
|
|
1264
|
-
@
|
|
1233
|
+
@rasa.shared.utils.common.lazy_property
|
|
1265
1234
|
def input_state_map(self) -> Dict[Text, int]:
|
|
1266
1235
|
"""Provide a mapping from state names to indices."""
|
|
1267
1236
|
return {f: i for i, f in enumerate(self.input_states)}
|
|
1268
1237
|
|
|
1269
|
-
@
|
|
1238
|
+
@rasa.shared.utils.common.lazy_property
|
|
1270
1239
|
def input_states(self) -> List[Text]:
|
|
1271
1240
|
"""Returns all available states."""
|
|
1272
1241
|
return (
|
|
@@ -1496,7 +1465,7 @@ class Domain:
|
|
|
1496
1465
|
ignore_rule_only_turns: bool = False,
|
|
1497
1466
|
rule_only_data: Optional[Dict[Text, Any]] = None,
|
|
1498
1467
|
) -> List[State]:
|
|
1499
|
-
"""List of states for each state of the
|
|
1468
|
+
"""List of states for each state of the trackers history.
|
|
1500
1469
|
|
|
1501
1470
|
Args:
|
|
1502
1471
|
tracker: Dialogue state tracker containing the dialogue so far.
|
|
@@ -1713,12 +1682,12 @@ class Domain:
|
|
|
1713
1682
|
"""Return the configuration for an intent."""
|
|
1714
1683
|
return self.intent_properties.get(intent_name, {})
|
|
1715
1684
|
|
|
1716
|
-
@
|
|
1685
|
+
@rasa.shared.utils.common.lazy_property
|
|
1717
1686
|
def intents(self) -> List[Text]:
|
|
1718
1687
|
"""Returns sorted list of intents."""
|
|
1719
1688
|
return sorted(self.intent_properties.keys())
|
|
1720
1689
|
|
|
1721
|
-
@
|
|
1690
|
+
@rasa.shared.utils.common.lazy_property
|
|
1722
1691
|
def entities(self) -> List[Text]:
|
|
1723
1692
|
"""Returns sorted list of entities."""
|
|
1724
1693
|
return sorted(self.entity_properties.entities)
|
|
@@ -2086,29 +2055,6 @@ class Domain:
|
|
|
2086
2055
|
def is_custom_action(self, action_name: str) -> bool:
|
|
2087
2056
|
return action_name in self._custom_actions
|
|
2088
2057
|
|
|
2089
|
-
@classmethod
|
|
2090
|
-
def _dict_from_raw_yaml_content(cls, raw_yaml_content: Text) -> Any:
|
|
2091
|
-
"""Loads the Domain dict from raw YAML content.
|
|
2092
|
-
|
|
2093
|
-
Validates the raw YAML content using the schema file if `validate_yaml` is set
|
|
2094
|
-
to `True`.
|
|
2095
|
-
|
|
2096
|
-
Args:
|
|
2097
|
-
raw_yaml_content: The raw YAML content of the domain file.
|
|
2098
|
-
|
|
2099
|
-
Returns:
|
|
2100
|
-
The Domain dict.
|
|
2101
|
-
"""
|
|
2102
|
-
if cls.validate_yaml:
|
|
2103
|
-
structlogger.info(
|
|
2104
|
-
"domain.from_yaml.validating",
|
|
2105
|
-
)
|
|
2106
|
-
validate_raw_yaml_using_schema_file_with_responses(
|
|
2107
|
-
raw_yaml_content, DOMAIN_SCHEMA_FILE
|
|
2108
|
-
)
|
|
2109
|
-
|
|
2110
|
-
return read_yaml(raw_yaml_content)
|
|
2111
|
-
|
|
2112
2058
|
|
|
2113
2059
|
def warn_about_duplicates_found_during_domain_merging(
|
|
2114
2060
|
duplicates: Dict[Text, List[Text]],
|
|
@@ -16,7 +16,6 @@ from rasa.shared.core.flows.validation import (
|
|
|
16
16
|
validate_patterns_are_not_called_or_linked,
|
|
17
17
|
validate_patterns_are_not_calling_or_linking_other_flows,
|
|
18
18
|
validate_step_ids_are_unique,
|
|
19
|
-
DuplicatedFlowIdException,
|
|
20
19
|
)
|
|
21
20
|
from rasa.shared.core.slots import Slot
|
|
22
21
|
|
|
@@ -50,31 +49,21 @@ class FlowsList:
|
|
|
50
49
|
return len(self.underlying_flows) == 0
|
|
51
50
|
|
|
52
51
|
@classmethod
|
|
53
|
-
def from_multiple_flows_lists(
|
|
54
|
-
cls, *other: FlowsList, ignore_duplicates: bool = True
|
|
55
|
-
) -> FlowsList:
|
|
52
|
+
def from_multiple_flows_lists(cls, *other: FlowsList) -> FlowsList:
|
|
56
53
|
"""Merges multiple lists of flows into a single flow ensuring each flow is
|
|
57
54
|
unique, based on its ID.
|
|
58
55
|
|
|
59
56
|
Args:
|
|
60
57
|
other: Variable number of flow lists instances to be merged.
|
|
61
|
-
ignore_duplicates: Whether to ignore duplicate flow ids, or raise an error.
|
|
62
58
|
|
|
63
59
|
Returns:
|
|
64
60
|
Merged flow list.
|
|
65
61
|
"""
|
|
66
|
-
merged_flows
|
|
62
|
+
merged_flows = dict()
|
|
67
63
|
for flow_list in other:
|
|
68
64
|
for flow in flow_list:
|
|
69
|
-
if flow.id in merged_flows:
|
|
70
|
-
|
|
71
|
-
continue
|
|
72
|
-
current_flow_path = flow.file_path
|
|
73
|
-
other_flow_path = merged_flows[flow.id].file_path
|
|
74
|
-
raise DuplicatedFlowIdException(
|
|
75
|
-
flow.id, current_flow_path, other_flow_path
|
|
76
|
-
)
|
|
77
|
-
merged_flows[flow.id] = flow
|
|
65
|
+
if flow.id not in merged_flows:
|
|
66
|
+
merged_flows[flow.id] = flow
|
|
78
67
|
return FlowsList(list(merged_flows.values()))
|
|
79
68
|
|
|
80
69
|
@classmethod
|
|
@@ -129,11 +118,9 @@ class FlowsList:
|
|
|
129
118
|
flow_dicts = [flow.as_json() for flow in self.underlying_flows]
|
|
130
119
|
return rasa.shared.utils.io.get_list_fingerprint(flow_dicts)
|
|
131
120
|
|
|
132
|
-
def merge(self, other: FlowsList
|
|
121
|
+
def merge(self, other: FlowsList) -> FlowsList:
|
|
133
122
|
"""Merges two lists of flows together."""
|
|
134
|
-
return FlowsList.from_multiple_flows_lists(
|
|
135
|
-
self, other, ignore_duplicates=ignore_duplicates
|
|
136
|
-
)
|
|
123
|
+
return FlowsList.from_multiple_flows_lists(self, other)
|
|
137
124
|
|
|
138
125
|
def flow_by_id(self, flow_id: Text) -> Optional[Flow]:
|
|
139
126
|
"""Return the flow with the given id."""
|
|
@@ -101,31 +101,6 @@ class DuplicatedStepIdException(RasaException):
|
|
|
101
101
|
)
|
|
102
102
|
|
|
103
103
|
|
|
104
|
-
class DuplicatedFlowIdException(RasaException):
|
|
105
|
-
"""Raised when a flow is using the same id as another flow."""
|
|
106
|
-
|
|
107
|
-
def __init__(
|
|
108
|
-
self, flow_id: str, first_file_path: str, second_file_path: str
|
|
109
|
-
) -> None:
|
|
110
|
-
"""Initializes the exception."""
|
|
111
|
-
self.flow_id = flow_id
|
|
112
|
-
self.first_file_path = first_file_path
|
|
113
|
-
self.second_file_path = second_file_path
|
|
114
|
-
|
|
115
|
-
def __str__(self) -> str:
|
|
116
|
-
"""Return a string representation of the exception."""
|
|
117
|
-
if self.first_file_path == self.second_file_path:
|
|
118
|
-
return (
|
|
119
|
-
f"Flow '{self.flow_id}' is used twice in `{self.first_file_path}`. "
|
|
120
|
-
f"Please make sure flow IDs are unique across all files."
|
|
121
|
-
)
|
|
122
|
-
return (
|
|
123
|
-
f"Flow '{self.flow_id}' is used in both "
|
|
124
|
-
f"`{self.first_file_path}` and `{self.second_file_path}`. "
|
|
125
|
-
f"Please make sure flow IDs are unique across all files."
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
|
|
129
104
|
class MissingElseBranchException(RasaException):
|
|
130
105
|
"""Raised when a flow step is missing an else branch."""
|
|
131
106
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import textwrap
|
|
1
2
|
from pathlib import Path
|
|
2
|
-
from typing import Any, Dict, List,
|
|
3
|
+
from typing import Any, Dict, List, Text, Union, Optional
|
|
3
4
|
|
|
4
5
|
import jsonschema
|
|
5
6
|
import ruamel.yaml.nodes as yaml_nodes
|
|
@@ -11,11 +12,12 @@ import rasa.shared.utils.io
|
|
|
11
12
|
from rasa.shared.core.flows.flow import Flow
|
|
12
13
|
from rasa.shared.core.flows.flows_list import FlowsList
|
|
13
14
|
from rasa.shared.exceptions import RasaException, YamlException
|
|
15
|
+
from rasa.shared.importers.importer import FlowSyncImporter
|
|
14
16
|
from rasa.shared.utils.yaml import (
|
|
17
|
+
validate_yaml_with_jsonschema,
|
|
18
|
+
read_yaml,
|
|
15
19
|
dump_obj_as_yaml_to_string,
|
|
16
20
|
is_key_in_yaml,
|
|
17
|
-
read_yaml,
|
|
18
|
-
validate_yaml_with_jsonschema,
|
|
19
21
|
)
|
|
20
22
|
|
|
21
23
|
FLOWS_SCHEMA_FILE = "shared/core/flows/flows_yaml_schema.json"
|
|
@@ -260,6 +262,25 @@ class YamlFlowsWriter:
|
|
|
260
262
|
rasa.shared.utils.io.write_text_file(YamlFlowsWriter.dumps(flows), filename)
|
|
261
263
|
|
|
262
264
|
|
|
265
|
+
def flows_from_str(yaml_str: str) -> FlowsList:
|
|
266
|
+
"""Reads flows from a YAML string."""
|
|
267
|
+
flows = YAMLFlowsReader.read_from_string(
|
|
268
|
+
textwrap.dedent(yaml_str), add_line_numbers=False
|
|
269
|
+
)
|
|
270
|
+
flows.validate()
|
|
271
|
+
return flows
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def flows_from_str_including_defaults(yaml_str: str) -> FlowsList:
|
|
275
|
+
"""Reads flows from a YAML string and combine them with default flows."""
|
|
276
|
+
flows = YAMLFlowsReader.read_from_string(
|
|
277
|
+
textwrap.dedent(yaml_str), add_line_numbers=False
|
|
278
|
+
)
|
|
279
|
+
all_flows = FlowSyncImporter.merge_with_default_flows(flows)
|
|
280
|
+
all_flows.validate()
|
|
281
|
+
return all_flows
|
|
282
|
+
|
|
283
|
+
|
|
263
284
|
def is_flows_file(file_path: Union[Text, Path]) -> bool:
|
|
264
285
|
"""Check if file contains Flow training data.
|
|
265
286
|
|