rasa-pro 3.12.0.dev10__py3-none-any.whl → 3.12.0.dev11__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.

Files changed (37) hide show
  1. rasa/cli/inspect.py +20 -1
  2. rasa/cli/shell.py +3 -3
  3. rasa/core/actions/action.py +5 -6
  4. rasa/core/actions/forms.py +6 -3
  5. rasa/core/channels/__init__.py +2 -0
  6. rasa/core/channels/voice_stream/browser_audio.py +1 -0
  7. rasa/core/channels/voice_stream/call_state.py +7 -1
  8. rasa/core/channels/voice_stream/genesys.py +331 -0
  9. rasa/core/channels/voice_stream/tts/cartesia.py +16 -3
  10. rasa/core/channels/voice_stream/twilio_media_streams.py +2 -1
  11. rasa/core/channels/voice_stream/voice_channel.py +2 -1
  12. rasa/core/policies/flows/flow_executor.py +3 -41
  13. rasa/core/run.py +4 -3
  14. rasa/dialogue_understanding/generator/command_generator.py +104 -1
  15. rasa/dialogue_understanding/generator/llm_based_command_generator.py +40 -6
  16. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +1 -1
  17. rasa/dialogue_understanding/generator/nlu_command_adapter.py +41 -2
  18. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +1 -1
  19. rasa/dialogue_understanding/generator/utils.py +32 -1
  20. rasa/dialogue_understanding/processor/command_processor.py +10 -12
  21. rasa/dialogue_understanding_test/README.md +50 -0
  22. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +3 -3
  23. rasa/model_service.py +4 -0
  24. rasa/model_training.py +24 -27
  25. rasa/shared/core/constants.py +6 -2
  26. rasa/shared/core/domain.py +11 -20
  27. rasa/shared/core/slot_mappings.py +143 -107
  28. rasa/shared/core/slots.py +4 -2
  29. rasa/telemetry.py +43 -13
  30. rasa/utils/common.py +0 -1
  31. rasa/validator.py +31 -74
  32. rasa/version.py +1 -1
  33. {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev11.dist-info}/METADATA +1 -1
  34. {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev11.dist-info}/RECORD +37 -36
  35. {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev11.dist-info}/NOTICE +0 -0
  36. {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev11.dist-info}/WHEEL +0 -0
  37. {rasa_pro-3.12.0.dev10.dist-info → rasa_pro-3.12.0.dev11.dist-info}/entry_points.txt +0 -0
@@ -1,15 +1,20 @@
1
+ from __future__ import annotations
2
+
3
+ import copy
1
4
  import logging
2
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Text, Tuple, cast
5
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Text, Tuple, Union, cast
6
+
7
+ from pydantic import BaseModel, Field
3
8
 
4
9
  import rasa.shared.utils.io
5
10
  from rasa.shared.constants import DOCS_URL_NLU_BASED_SLOTS, IGNORED_INTENTS
6
11
  from rasa.shared.core.constants import (
7
- ACTIVE_FLOW,
8
12
  ACTIVE_LOOP,
13
+ KEY_ACTION,
9
14
  KEY_MAPPING_TYPE,
15
+ KEY_RUN_ACTION_EVERY_TURN,
10
16
  MAPPING_CONDITIONS,
11
17
  REQUESTED_SLOT,
12
- SLOT_MAPPINGS,
13
18
  SlotMappingType,
14
19
  )
15
20
  from rasa.shared.core.slots import ListSlot, Slot
@@ -21,7 +26,6 @@ from rasa.shared.nlu.constants import (
21
26
  ENTITY_ATTRIBUTE_VALUE,
22
27
  INTENT,
23
28
  INTENT_NAME_KEY,
24
- NOT_INTENT,
25
29
  TEXT,
26
30
  )
27
31
 
@@ -35,11 +39,81 @@ if TYPE_CHECKING:
35
39
  logger = logging.getLogger(__name__)
36
40
 
37
41
 
38
- class SlotMapping:
42
+ class SlotMappingCondition(BaseModel):
43
+ """Defines a condition for a slot mapping."""
44
+
45
+ active_loop: Optional[str]
46
+ requested_slot: Optional[str] = None
47
+ active_flow: Optional[str] = None
48
+
49
+ @staticmethod
50
+ def from_dict(data: Dict[str, Any]) -> SlotMappingCondition:
51
+ # we allow None as a valid value for active_loop
52
+ # therefore we need to set a different default value
53
+ active_loop = data.pop(ACTIVE_LOOP, "")
54
+
55
+ return SlotMappingCondition(active_loop=active_loop, **data)
56
+
57
+ def as_dict(self) -> Dict[str, Any]:
58
+ return self.model_dump(exclude_none=True)
59
+
60
+
61
+ class SlotMapping(BaseModel):
39
62
  """Defines functionality for the available slot mappings."""
40
63
 
64
+ type: SlotMappingType
65
+ conditions: List[SlotMappingCondition] = Field(default_factory=list)
66
+ entity: Optional[str] = None
67
+ intent: Optional[Union[str, List[str]]] = None
68
+ role: Optional[str] = None
69
+ group: Optional[str] = None
70
+ not_intent: Optional[Union[str, List[str]]] = None
71
+ value: Optional[Any] = None
72
+ allow_nlu_correction: Optional[bool] = None
73
+ run_action_every_turn: Optional[str] = None
74
+
75
+ @staticmethod
76
+ def from_dict(data: Dict[str, Any], slot_name: str) -> SlotMapping:
77
+ data_copy = copy.deepcopy(data)
78
+ mapping_type = SlotMapping.validate_mapping(data_copy, slot_name)
79
+ conditions = [
80
+ SlotMappingCondition.from_dict(condition)
81
+ for condition in data_copy.pop(MAPPING_CONDITIONS, [])
82
+ ]
83
+
84
+ deprecated_action = data_copy.pop(KEY_ACTION, None)
85
+ if deprecated_action:
86
+ rasa.shared.utils.io.raise_deprecation_warning(
87
+ f"The `{KEY_ACTION}` key in slot mappings is deprecated and "
88
+ f"will be removed in Rasa Pro 4.0.0. "
89
+ f"Please use the `{KEY_RUN_ACTION_EVERY_TURN}` key instead.",
90
+ )
91
+ data_copy[KEY_RUN_ACTION_EVERY_TURN] = deprecated_action
92
+
93
+ run_action_every_turn = data_copy.pop(KEY_RUN_ACTION_EVERY_TURN, None)
94
+
95
+ return SlotMapping(
96
+ type=mapping_type,
97
+ conditions=conditions,
98
+ run_action_every_turn=run_action_every_turn,
99
+ **data_copy,
100
+ )
101
+
102
+ def as_dict(self) -> Dict[str, Any]:
103
+ data = self.model_dump(mode="json", exclude_none=True)
104
+ data[KEY_MAPPING_TYPE] = self.type.value
105
+
106
+ if self.conditions:
107
+ data[MAPPING_CONDITIONS] = [
108
+ condition.as_dict() for condition in self.conditions
109
+ ]
110
+ else:
111
+ data.pop(MAPPING_CONDITIONS, None)
112
+
113
+ return data
114
+
41
115
  @staticmethod
42
- def validate(mapping: Dict[Text, Any], slot_name: Text) -> None:
116
+ def validate_mapping(mapping: Dict[str, Any], slot_name: str) -> SlotMappingType:
43
117
  """Validates a slot mapping.
44
118
 
45
119
  Args:
@@ -58,12 +132,22 @@ class SlotMapping:
58
132
  f"{DOCS_URL_NLU_BASED_SLOTS} for more information."
59
133
  )
60
134
 
135
+ mapping_raw = mapping.pop(KEY_MAPPING_TYPE, SlotMappingType.FROM_LLM.value)
136
+
137
+ if mapping_raw == "custom":
138
+ rasa.shared.utils.io.raise_deprecation_warning(
139
+ "The `custom` slot mapping type is deprecated and "
140
+ "will be removed in Rasa Pro 4.0.0. "
141
+ "Please use the `controlled` slot mapping type instead.",
142
+ )
143
+ mapping_raw = "controlled"
144
+
61
145
  try:
62
- mapping_type = SlotMappingType(mapping.get(KEY_MAPPING_TYPE))
146
+ mapping_type = SlotMappingType(mapping_raw)
63
147
  except ValueError:
64
148
  raise InvalidDomain(
65
149
  f"Your domain uses an invalid slot mapping of type "
66
- f"'{mapping.get(KEY_MAPPING_TYPE)}' for slot '{slot_name}'. Please see "
150
+ f"'{mapping_raw}' for slot '{slot_name}'. Please see "
67
151
  f"{DOCS_URL_NLU_BASED_SLOTS} for more information."
68
152
  )
69
153
 
@@ -72,7 +156,7 @@ class SlotMapping:
72
156
  SlotMappingType.FROM_INTENT: ["value"],
73
157
  SlotMappingType.FROM_TRIGGER_INTENT: ["value"],
74
158
  SlotMappingType.FROM_TEXT: [],
75
- SlotMappingType.CUSTOM: [],
159
+ SlotMappingType.CONTROLLED: [],
76
160
  SlotMappingType.FROM_LLM: [],
77
161
  }
78
162
 
@@ -86,19 +170,18 @@ class SlotMapping:
86
170
  f"{DOCS_URL_NLU_BASED_SLOTS} for more information."
87
171
  )
88
172
 
89
- @staticmethod
173
+ return mapping_type
174
+
90
175
  def _get_active_loop_ignored_intents(
91
- mapping: Dict[Text, Any], domain: "Domain", active_loop_name: Text
176
+ self, domain: "Domain", active_loop_name: Text
92
177
  ) -> List[Text]:
93
- from rasa.shared.core.constants import ACTIVE_LOOP
94
-
95
- mapping_conditions = mapping.get(MAPPING_CONDITIONS)
178
+ mapping_conditions = self.conditions
96
179
  active_loop_match = True
97
180
  ignored_intents = []
98
181
 
99
182
  if mapping_conditions:
100
183
  match_list = [
101
- condition.get(ACTIVE_LOOP) == active_loop_name
184
+ condition.active_loop == active_loop_name
102
185
  for condition in mapping_conditions
103
186
  ]
104
187
  active_loop_match = any(match_list)
@@ -111,24 +194,21 @@ class SlotMapping:
111
194
 
112
195
  return ignored_intents
113
196
 
114
- @staticmethod
115
197
  def intent_is_desired(
116
- mapping: Dict[Text, Any],
198
+ self,
117
199
  tracker: "DialogueStateTracker",
118
200
  domain: "Domain",
119
201
  message: Optional["Message"] = None,
120
202
  ) -> bool:
121
203
  """Checks whether user intent matches slot mapping intent specifications."""
122
- mapping_intents = SlotMapping.to_list(mapping.get(INTENT, []))
123
- mapping_not_intents = SlotMapping.to_list(mapping.get(NOT_INTENT, []))
204
+ mapping_intents = SlotMapping.to_list(self.intent)
205
+ mapping_not_intents = SlotMapping.to_list(self.not_intent)
124
206
 
125
207
  active_loop_name = tracker.active_loop_name
126
208
  if active_loop_name:
127
209
  mapping_not_intents = (
128
210
  mapping_not_intents
129
- + SlotMapping._get_active_loop_ignored_intents(
130
- mapping, domain, active_loop_name
131
- )
211
+ + self._get_active_loop_ignored_intents(domain, active_loop_name)
132
212
  )
133
213
 
134
214
  if message is not None:
@@ -155,16 +235,14 @@ class SlotMapping:
155
235
 
156
236
  return x
157
237
 
158
- @staticmethod
159
238
  def entity_is_desired(
160
- mapping: Dict[Text, Any],
239
+ self,
161
240
  tracker: "DialogueStateTracker",
162
241
  message: Optional["Message"] = None,
163
242
  ) -> List[str]:
164
243
  """Checks whether slot should be filled by an entity in the input or not.
165
244
 
166
245
  Args:
167
- mapping: Slot mapping.
168
246
  tracker: The tracker.
169
247
  message: The message being processed.
170
248
 
@@ -176,19 +254,16 @@ class SlotMapping:
176
254
  matching_values = [
177
255
  cast(Text, entity[ENTITY_ATTRIBUTE_VALUE])
178
256
  for entity in extracted_entities
179
- if entity.get(ENTITY_ATTRIBUTE_TYPE)
180
- == mapping.get(ENTITY_ATTRIBUTE_TYPE)
181
- and entity.get(ENTITY_ATTRIBUTE_GROUP)
182
- == mapping.get(ENTITY_ATTRIBUTE_GROUP)
183
- and entity.get(ENTITY_ATTRIBUTE_ROLE)
184
- == mapping.get(ENTITY_ATTRIBUTE_ROLE)
257
+ if entity.get(ENTITY_ATTRIBUTE_TYPE) == self.entity
258
+ and entity.get(ENTITY_ATTRIBUTE_GROUP) == self.group
259
+ and entity.get(ENTITY_ATTRIBUTE_ROLE) == self.role
185
260
  ]
186
261
  elif tracker.latest_message and tracker.latest_message.text is not None:
187
262
  matching_values = list(
188
263
  tracker.get_latest_entity_values(
189
- mapping.get(ENTITY_ATTRIBUTE_TYPE),
190
- mapping.get(ENTITY_ATTRIBUTE_ROLE),
191
- mapping.get(ENTITY_ATTRIBUTE_GROUP),
264
+ self.entity,
265
+ self.role,
266
+ self.group,
192
267
  )
193
268
  )
194
269
  else:
@@ -196,45 +271,38 @@ class SlotMapping:
196
271
 
197
272
  return matching_values
198
273
 
199
- @staticmethod
200
274
  def check_mapping_validity(
275
+ self,
201
276
  slot_name: Text,
202
- mapping_type: SlotMappingType,
203
- mapping: Dict[Text, Any],
204
277
  domain: "Domain",
205
278
  ) -> bool:
206
279
  """Checks the mapping for validity.
207
280
 
208
281
  Args:
209
282
  slot_name: The name of the slot to be validated.
210
- mapping_type: The type of the slot mapping.
211
- mapping: Slot mapping.
212
283
  domain: The domain to check against.
213
284
 
214
285
  Returns:
215
286
  True, if intent and entity specified in a mapping exist in domain.
216
287
  """
217
288
  if (
218
- mapping_type == SlotMappingType.FROM_ENTITY
219
- and mapping.get(ENTITY_ATTRIBUTE_TYPE) not in domain.entities
289
+ self.type == SlotMappingType.FROM_ENTITY
290
+ and self.entity not in domain.entities
220
291
  ):
221
292
  rasa.shared.utils.io.raise_warning(
222
293
  f"Slot '{slot_name}' uses a 'from_entity' mapping "
223
- f"for a non-existent entity '{mapping.get(ENTITY_ATTRIBUTE_TYPE)}'. "
294
+ f"for a non-existent entity '{self.entity}'. "
224
295
  f"Skipping slot extraction because of invalid mapping."
225
296
  )
226
297
  return False
227
298
 
228
- if (
229
- mapping_type == SlotMappingType.FROM_INTENT
230
- and mapping.get(INTENT) is not None
231
- ):
232
- intent_list = SlotMapping.to_list(mapping.get(INTENT))
299
+ if self.type == SlotMappingType.FROM_INTENT and self.intent is not None:
300
+ intent_list = SlotMapping.to_list(self.intent)
233
301
  for intent in intent_list:
234
302
  if intent and intent not in domain.intents:
235
303
  rasa.shared.utils.io.raise_warning(
236
304
  f"Slot '{slot_name}' uses a 'from_intent' mapping for "
237
- f"a non-existent intent '{mapping.get('intent')}'. "
305
+ f"a non-existent intent '{intent}'. "
238
306
  f"Skipping slot extraction because of invalid mapping."
239
307
  )
240
308
  return False
@@ -242,22 +310,6 @@ class SlotMapping:
242
310
  return True
243
311
 
244
312
 
245
- def validate_slot_mappings(domain_slots: Dict[Text, Any]) -> None:
246
- """Raises InvalidDomain exception if slot mappings are invalid."""
247
- rasa.shared.utils.io.raise_warning(
248
- f"Slot auto-fill has been removed in 3.0 and replaced with a "
249
- f"new explicit mechanism to set slots. "
250
- f"Please refer to {DOCS_URL_NLU_BASED_SLOTS} to learn more.",
251
- UserWarning,
252
- )
253
-
254
- for slot_name, properties in domain_slots.items():
255
- mappings = properties.get(SLOT_MAPPINGS, [])
256
-
257
- for slot_mapping in mappings:
258
- SlotMapping.validate(slot_mapping, slot_name)
259
-
260
-
261
313
  class SlotFillingManager:
262
314
  """Manages slot filling based on conversation context."""
263
315
 
@@ -276,41 +328,34 @@ class SlotFillingManager:
276
328
  def is_slot_mapping_valid(
277
329
  self,
278
330
  slot_name: str,
279
- mapping_type: SlotMappingType,
280
- mapping: Dict[str, Any],
331
+ mapping: SlotMapping,
281
332
  ) -> bool:
282
333
  """Check if a slot mapping is valid."""
283
- return SlotMapping.check_mapping_validity(
334
+ return mapping.check_mapping_validity(
284
335
  slot_name=slot_name,
285
- mapping_type=mapping_type,
286
- mapping=mapping,
287
336
  domain=self.domain,
288
337
  )
289
338
 
290
- def is_intent_desired(self, mapping: Dict[str, Any]) -> bool:
339
+ def is_intent_desired(self, mapping: SlotMapping) -> bool:
291
340
  """Check if the intent matches the one indicated in the slot mapping."""
292
- return SlotMapping.intent_is_desired(
293
- mapping=mapping,
341
+ return mapping.intent_is_desired(
294
342
  tracker=self.tracker,
295
343
  domain=self.domain,
296
344
  message=self.message,
297
345
  )
298
346
 
299
- def _verify_mapping_conditions(
300
- self, mapping: Dict[Text, Any], slot_name: Text
301
- ) -> bool:
302
- if mapping.get(MAPPING_CONDITIONS) and mapping[KEY_MAPPING_TYPE] != str(
347
+ def _verify_mapping_conditions(self, mapping: SlotMapping, slot_name: Text) -> bool:
348
+ if mapping.conditions and mapping.type != str(
303
349
  SlotMappingType.FROM_TRIGGER_INTENT
304
350
  ):
305
- if not self._matches_mapping_conditions(mapping, slot_name):
306
- return False
351
+ return self._matches_mapping_conditions(mapping, slot_name)
307
352
 
308
353
  return True
309
354
 
310
355
  def _matches_mapping_conditions(
311
- self, mapping: Dict[Text, Any], slot_name: Text
356
+ self, mapping: SlotMapping, slot_name: Text
312
357
  ) -> bool:
313
- slot_mapping_conditions = mapping.get(MAPPING_CONDITIONS)
358
+ slot_mapping_conditions = mapping.conditions
314
359
 
315
360
  if not slot_mapping_conditions:
316
361
  return True
@@ -328,20 +373,20 @@ class SlotFillingManager:
328
373
  @staticmethod
329
374
  def _mapping_conditions_match_flow(
330
375
  active_flow: str,
331
- slot_mapping_conditions: List[Dict[str, str]],
376
+ slot_mapping_conditions: List[SlotMappingCondition],
332
377
  ) -> bool:
333
378
  active_flow_conditions = list(
334
- filter(lambda x: x.get(ACTIVE_FLOW) is not None, slot_mapping_conditions)
379
+ filter(lambda x: x.active_flow is not None, slot_mapping_conditions)
335
380
  )
336
381
  return any(
337
382
  [
338
- condition.get(ACTIVE_FLOW) == active_flow
383
+ condition.active_flow == active_flow
339
384
  for condition in active_flow_conditions
340
385
  ]
341
386
  )
342
387
 
343
388
  def _mapping_conditions_match_form(
344
- self, slot_name: str, slot_mapping_conditions: List[Dict[str, str]]
389
+ self, slot_name: str, slot_mapping_conditions: List[SlotMappingCondition]
345
390
  ) -> bool:
346
391
  if (
347
392
  self.tracker.is_active_loop_rejected
@@ -351,12 +396,10 @@ class SlotFillingManager:
351
396
 
352
397
  # check if found mapping conditions matches form
353
398
  for condition in slot_mapping_conditions:
354
- # we allow None as a valid value for active_loop
355
- # therefore we need to set a different default value
356
- active_loop = condition.get(ACTIVE_LOOP, "")
399
+ active_loop = condition.active_loop
357
400
 
358
401
  if active_loop and active_loop == self.tracker.active_loop_name:
359
- condition_requested_slot = condition.get(REQUESTED_SLOT)
402
+ condition_requested_slot = condition.requested_slot
360
403
  if not condition_requested_slot:
361
404
  return True
362
405
  if condition_requested_slot == self.tracker.get_slot(REQUESTED_SLOT):
@@ -370,11 +413,11 @@ class SlotFillingManager:
370
413
  def _fails_unique_entity_mapping_check(
371
414
  self,
372
415
  slot_name: Text,
373
- mapping: Dict[Text, Any],
416
+ mapping: SlotMapping,
374
417
  ) -> bool:
375
418
  from rasa.core.actions.forms import FormAction
376
419
 
377
- if mapping[KEY_MAPPING_TYPE] != str(SlotMappingType.FROM_ENTITY):
420
+ if mapping.type != SlotMappingType.FROM_ENTITY:
378
421
  return False
379
422
 
380
423
  form_name = self.tracker.active_loop_name
@@ -395,12 +438,9 @@ class SlotFillingManager:
395
438
 
396
439
  return True
397
440
 
398
- def _is_trigger_intent_mapping_condition_met(
399
- self, mapping: Dict[Text, Any]
400
- ) -> bool:
441
+ def _is_trigger_intent_mapping_condition_met(self, mapping: SlotMapping) -> bool:
401
442
  active_loops_in_mapping_conditions = [
402
- condition.get(ACTIVE_LOOP)
403
- for condition in mapping.get(MAPPING_CONDITIONS, [])
443
+ condition.active_loop for condition in mapping.conditions
404
444
  ]
405
445
 
406
446
  trigger_mapping_condition_met = True
@@ -421,7 +461,7 @@ class SlotFillingManager:
421
461
  def extract_slot_value_from_predefined_mapping(
422
462
  self,
423
463
  mapping_type: SlotMappingType,
424
- mapping: Dict[Text, Any],
464
+ mapping: SlotMapping,
425
465
  ) -> List[Any]:
426
466
  """Extracts slot value if slot has an applicable predefined mapping."""
427
467
  if (
@@ -454,9 +494,9 @@ class SlotFillingManager:
454
494
  value: List[Any] = []
455
495
 
456
496
  if should_fill_entity_slot:
457
- value = SlotMapping.entity_is_desired(mapping, self.tracker, self.message)
497
+ value = mapping.entity_is_desired(self.tracker, self.message)
458
498
  elif should_fill_intent_slot or should_fill_trigger_slot:
459
- value = [mapping.get("value")]
499
+ value = [mapping.value]
460
500
  elif should_fill_text_slot:
461
501
  value = [self.message.get(TEXT)] if self.message is not None else []
462
502
  if not value:
@@ -468,11 +508,9 @@ class SlotFillingManager:
468
508
 
469
509
  return value
470
510
 
471
- def should_fill_slot(
472
- self, slot_name: str, mapping_type: SlotMappingType, mapping: Dict[Text, Any]
473
- ) -> bool:
511
+ def should_fill_slot(self, slot_name: str, mapping: SlotMapping) -> bool:
474
512
  """Checks if a slot should be filled based on the conversation context."""
475
- if not self.is_slot_mapping_valid(slot_name, mapping_type, mapping):
513
+ if not self.is_slot_mapping_valid(slot_name, mapping):
476
514
  return False
477
515
 
478
516
  if not self.is_intent_desired(mapping):
@@ -494,14 +532,12 @@ def extract_slot_value(
494
532
  is_extracted = False
495
533
 
496
534
  for mapping in slot.mappings:
497
- mapping_type = SlotMappingType(
498
- mapping.get(KEY_MAPPING_TYPE, SlotMappingType.FROM_LLM.value)
499
- )
535
+ mapping_type = mapping.type
500
536
 
501
- if mapping_type in [SlotMappingType.FROM_LLM, SlotMappingType.CUSTOM]:
537
+ if mapping_type in [SlotMappingType.FROM_LLM, SlotMappingType.CONTROLLED]:
502
538
  continue
503
539
 
504
- if not slot_filling_manager.should_fill_slot(slot.name, mapping_type, mapping):
540
+ if not slot_filling_manager.should_fill_slot(slot.name, mapping):
505
541
  continue
506
542
 
507
543
  value: List[Any] = (
rasa/shared/core/slots.py CHANGED
@@ -60,8 +60,10 @@ class Slot(ABC):
60
60
  dm1 or CALM finishes.
61
61
  filled_by: The name of the extractor that fills the slot.
62
62
  """
63
+ from rasa.shared.core.slot_mappings import SlotMapping
64
+
63
65
  self.name = name
64
- self.mappings = mappings
66
+ self.mappings = [SlotMapping.from_dict(mapping, name) for mapping in mappings]
65
67
  self._value = initial_value
66
68
  self.initial_value = initial_value
67
69
  self._value_reset_delay = value_reset_delay
@@ -193,7 +195,7 @@ class Slot(ABC):
193
195
  "type": rasa.shared.utils.common.module_path_from_instance(self),
194
196
  "initial_value": self.initial_value,
195
197
  "influence_conversation": self.influence_conversation,
196
- "mappings": self.mappings,
198
+ "mappings": [mapping.as_dict() for mapping in self.mappings],
197
199
  }
198
200
 
199
201
  def fingerprint(self) -> Text:
rasa/telemetry.py CHANGED
@@ -15,7 +15,7 @@ from collections import defaultdict
15
15
  from datetime import datetime
16
16
  from functools import wraps
17
17
  from pathlib import Path
18
- from typing import Any, Callable, Dict, List, Optional, Text
18
+ from typing import Any, Callable, Dict, List, Optional, Text, Tuple
19
19
 
20
20
  import importlib_resources
21
21
  import requests
@@ -35,6 +35,7 @@ from rasa.constants import (
35
35
  )
36
36
  from rasa.engine.storage.local_model_storage import LocalModelStorage
37
37
  from rasa.shared.constants import (
38
+ ASSISTANT_ID_KEY,
38
39
  CONFIG_LANGUAGE_KEY,
39
40
  CONFIG_PIPELINE_KEY,
40
41
  CONFIG_POLICIES_KEY,
@@ -111,6 +112,7 @@ CI_ENVIRONMENT_TELL = [
111
112
  # https://rasa.com/docs/rasa-pro/telemetry/reference
112
113
  TRAINING_STARTED_EVENT = "Training Started"
113
114
  TRAINING_COMPLETED_EVENT = "Training Completed"
115
+ TRAINING_FAILED_EVENT = "Training Failed"
114
116
  TELEMETRY_DISABLED_EVENT = "Telemetry Disabled"
115
117
  TELEMETRY_DATA_SPLIT_EVENT = "Training Data Split"
116
118
  TELEMETRY_DATA_VALIDATED_EVENT = "Training Data Validated"
@@ -976,6 +978,7 @@ def track_model_training(
976
978
  "language": config.get(CONFIG_LANGUAGE_KEY),
977
979
  "training_id": training_id,
978
980
  "type": model_type,
981
+ "assistant_id": config.get(ASSISTANT_ID_KEY),
979
982
  "pipeline": config.get(CONFIG_PIPELINE_KEY),
980
983
  "policies": config.get(CONFIG_POLICIES_KEY),
981
984
  "train_schema": config.get(CONFIG_TRAIN_SCHEMA),
@@ -1021,13 +1024,28 @@ def track_model_training(
1021
1024
  tracking_data,
1022
1025
  )
1023
1026
  start = datetime.now()
1024
- yield
1027
+ try:
1028
+ yield
1029
+ except (Exception, SystemExit):
1030
+ runtime = datetime.now() - start
1031
+ _track(
1032
+ TRAINING_FAILED_EVENT,
1033
+ {
1034
+ "training_id": training_id,
1035
+ "assistant_id": config.get(ASSISTANT_ID_KEY),
1036
+ "type": model_type,
1037
+ "runtime": int(runtime.total_seconds()),
1038
+ },
1039
+ )
1040
+ raise
1041
+
1025
1042
  runtime = datetime.now() - start
1026
1043
 
1027
1044
  _track(
1028
1045
  TRAINING_COMPLETED_EVENT,
1029
1046
  {
1030
1047
  "training_id": training_id,
1048
+ "assistant_id": config.get(ASSISTANT_ID_KEY),
1031
1049
  "type": model_type,
1032
1050
  "runtime": int(runtime.total_seconds()),
1033
1051
  },
@@ -1326,24 +1344,28 @@ def track_server_start(
1326
1344
  """
1327
1345
  from rasa.core.utils import AvailableEndpoints
1328
1346
 
1329
- def project_fingerprint_from_model(
1347
+ def project_fingerprint_and_assistant_id_from_model(
1330
1348
  _model_directory: Optional[Text],
1331
- ) -> Optional[Text]:
1349
+ ) -> Tuple[Optional[Text], Optional[Text]]:
1332
1350
  """Gets project fingerprint from an app's loaded model."""
1333
1351
  if not model_directory:
1334
- return None
1352
+ return None, None
1335
1353
 
1336
1354
  try:
1337
1355
  model_archive = model.get_local_model(_model_directory)
1338
1356
  metadata = LocalModelStorage.metadata_from_archive(model_archive)
1339
1357
 
1340
- return metadata.project_fingerprint
1358
+ return metadata.project_fingerprint, metadata.assistant_id
1341
1359
  except Exception:
1342
- return None
1360
+ return None, None
1343
1361
 
1344
1362
  if not endpoints:
1345
1363
  endpoints = AvailableEndpoints()
1346
1364
 
1365
+ project, assistant_id = project_fingerprint_and_assistant_id_from_model(
1366
+ model_directory
1367
+ )
1368
+
1347
1369
  _track(
1348
1370
  TELEMETRY_SERVER_STARTED_EVENT,
1349
1371
  {
@@ -1365,7 +1387,8 @@ def track_server_start(
1365
1387
  "endpoints_event_broker": endpoints.event_broker.type
1366
1388
  if endpoints.event_broker
1367
1389
  else None,
1368
- "project": project_fingerprint_from_model(model_directory),
1390
+ "project": project,
1391
+ "assistant_id": assistant_id,
1369
1392
  },
1370
1393
  )
1371
1394
 
@@ -1383,23 +1406,30 @@ def track_project_init(path: Text) -> None:
1383
1406
 
1384
1407
 
1385
1408
  @ensure_telemetry_enabled
1386
- def track_shell_started(model_type: Text) -> None:
1409
+ def track_shell_started(model_type: Text, assistant_id: Text) -> None:
1387
1410
  """Track when a user starts a bot using rasa shell.
1388
1411
 
1389
1412
  Args:
1390
1413
  model_type: Type of the model, core / nlu or rasa.
1391
1414
  """
1392
- _track(TELEMETRY_SHELL_STARTED_EVENT, {"type": model_type})
1415
+ _track(
1416
+ TELEMETRY_SHELL_STARTED_EVENT,
1417
+ {"type": model_type, "assistant_id": assistant_id},
1418
+ )
1393
1419
 
1394
1420
 
1395
1421
  @ensure_telemetry_enabled
1396
- def track_inspect_started(model_type: Text) -> None:
1422
+ def track_inspect_started(channel: Text, assistant_id: Text) -> None:
1397
1423
  """Track when a user starts a bot using rasa inspect.
1398
1424
 
1399
1425
  Args:
1400
- model_type: Type of the model, core / nlu or rasa.
1426
+ channel: Type of channel used.
1427
+ assistant_id: ID of the assistant being inspected.
1401
1428
  """
1402
- _track(TELEMETRY_INSPECT_STARTED_EVENT, {"type": model_type})
1429
+ _track(
1430
+ TELEMETRY_INSPECT_STARTED_EVENT,
1431
+ {"type": channel, "assistant_id": assistant_id},
1432
+ )
1403
1433
 
1404
1434
 
1405
1435
  @ensure_telemetry_enabled
rasa/utils/common.py CHANGED
@@ -70,7 +70,6 @@ EXPECTED_WARNINGS: List[Tuple[Type[Warning], str]] = [
70
70
  "Converting sparse IndexedSlices.* to a dense Tensor of unknown "
71
71
  "shape. This may consume a large amount of memory.",
72
72
  ),
73
- (UserWarning, "Slot auto-fill has been removed in 3.0 .*"),
74
73
  # Cannot fix this deprecation warning since we need to support two
75
74
  # numpy versions as long as we keep python 37 around
76
75
  (DeprecationWarning, "the `interpolation=` argument to quantile was renamed"),