rasa-pro 3.10.17__py3-none-any.whl → 3.10.19__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 (91) hide show
  1. rasa/core/brokers/kafka.py +59 -20
  2. rasa/core/channels/audiocodes.py +43 -16
  3. rasa/core/channels/inspector/dist/assets/Tableau10-1b767f5e.js +1 -0
  4. rasa/core/channels/inspector/dist/assets/arc-e2e71d6e.js +1 -0
  5. rasa/core/channels/inspector/dist/assets/blockDiagram-38ab4fdb-9d4eeea5.js +118 -0
  6. rasa/core/channels/inspector/dist/assets/c4Diagram-3d4e48cf-757f3070.js +10 -0
  7. rasa/core/channels/inspector/dist/assets/channel-0e91cabd.js +1 -0
  8. rasa/core/channels/inspector/dist/assets/classDiagram-70f12bd4-cd47db3e.js +2 -0
  9. rasa/core/channels/inspector/dist/assets/classDiagram-v2-f2320105-9bcb314f.js +2 -0
  10. rasa/core/channels/inspector/dist/assets/clone-55f6f037.js +1 -0
  11. rasa/core/channels/inspector/dist/assets/{createText-62fc7601-8b6fcc2a.js → createText-2e5e7dd3-393aac05.js} +1 -1
  12. rasa/core/channels/inspector/dist/assets/edges-e0da2a9e-ce972c1a.js +4 -0
  13. rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-60ffc87f.js → erDiagram-9861fffd-854b01fe.js} +4 -4
  14. rasa/core/channels/inspector/dist/assets/flowDb-956e92f1-362cb0e1.js +10 -0
  15. rasa/core/channels/inspector/dist/assets/flowDiagram-66a62f08-3296ca50.js +4 -0
  16. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-1fdfd51c.js +1 -0
  17. rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-4a651766-4f3849e9.js +139 -0
  18. rasa/core/channels/inspector/dist/assets/ganttDiagram-c361ad54-624048d2.js +257 -0
  19. rasa/core/channels/inspector/dist/assets/gitGraphDiagram-72cf32ee-f236b71c.js +70 -0
  20. rasa/core/channels/inspector/dist/assets/graph-c8c56300.js +1 -0
  21. rasa/core/channels/inspector/dist/assets/index-3862675e-71d2e803.js +1 -0
  22. rasa/core/channels/inspector/dist/assets/index-e789f855.js +1045 -0
  23. rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-72a0fa5f.js → infoDiagram-f8f76790-3172ab5a.js} +1 -1
  24. rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-82218c41.js → journeyDiagram-49397b02-60a1cb37.js} +4 -4
  25. rasa/core/channels/inspector/dist/assets/katex-498eb57e.js +261 -0
  26. rasa/core/channels/inspector/dist/assets/layout-60411930.js +1 -0
  27. rasa/core/channels/inspector/dist/assets/{line-5038b469.js → line-c774d6a4.js} +1 -1
  28. rasa/core/channels/inspector/dist/assets/linear-10ded498.js +1 -0
  29. rasa/core/channels/inspector/dist/assets/mindmap-definition-fc14e90a-b7d34e2c.js +312 -0
  30. rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-a8d03059.js → pieDiagram-8a3498a8-a29b9a48.js} +7 -7
  31. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-6a0e56b2.js → quadrantDiagram-120e2f19-ce394e00.js} +1 -1
  32. rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-2dc7c7bd.js → requirementDiagram-deff3bca-5a67a73c.js} +2 -2
  33. rasa/core/channels/inspector/dist/assets/sankeyDiagram-04a897e0-a59e3bd7.js +8 -0
  34. rasa/core/channels/inspector/dist/assets/sequenceDiagram-704730f1-eb2462a7.js +122 -0
  35. rasa/core/channels/inspector/dist/assets/stateDiagram-587899a1-67b2fb72.js +1 -0
  36. rasa/core/channels/inspector/dist/assets/stateDiagram-v2-d93cdb3a-d218a869.js +1 -0
  37. rasa/core/channels/inspector/dist/assets/{styles-9c745c82-f0fc6921.js → styles-6aaf32cf-6b0132de.js} +1 -1
  38. rasa/core/channels/inspector/dist/assets/styles-9a916d00-0bed1d14.js +160 -0
  39. rasa/core/channels/inspector/dist/assets/styles-c10674c1-784e573a.js +116 -0
  40. rasa/core/channels/inspector/dist/assets/svgDrawCommon-08f97a94-12f0b679.js +1 -0
  41. rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-bf3e91c1.js → timeline-definition-85554ec2-69c1a04a.js} +3 -3
  42. rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-4d4026c0.js → xychartDiagram-e933f94c-b01ebabe.js} +3 -3
  43. rasa/core/channels/inspector/dist/index.html +1 -1
  44. rasa/core/channels/inspector/package.json +11 -4
  45. rasa/core/channels/inspector/yarn.lock +89 -99
  46. rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +1 -1
  47. rasa/core/policies/intentless_policy.py +5 -58
  48. rasa/dialogue_understanding/generator/nlu_command_adapter.py +1 -1
  49. rasa/dialogue_understanding/processor/command_processor.py +21 -5
  50. rasa/dialogue_understanding/processor/command_processor_component.py +5 -2
  51. rasa/engine/validation.py +44 -9
  52. rasa/llm_fine_tuning/conversations.py +1 -1
  53. rasa/model_training.py +2 -1
  54. rasa/shared/constants.py +3 -0
  55. rasa/shared/core/constants.py +2 -0
  56. rasa/shared/core/domain.py +12 -3
  57. rasa/shared/core/events.py +73 -6
  58. rasa/shared/core/policies/__init__.py +0 -0
  59. rasa/shared/core/policies/utils.py +87 -0
  60. rasa/shared/utils/schemas/events.py +2 -2
  61. rasa/tracing/instrumentation/attribute_extractors.py +2 -0
  62. rasa/version.py +1 -1
  63. {rasa_pro-3.10.17.dist-info → rasa_pro-3.10.19.dist-info}/METADATA +10 -12
  64. {rasa_pro-3.10.17.dist-info → rasa_pro-3.10.19.dist-info}/RECORD +67 -60
  65. {rasa_pro-3.10.17.dist-info → rasa_pro-3.10.19.dist-info}/WHEEL +1 -1
  66. README.md +0 -41
  67. rasa/core/channels/inspector/dist/assets/arc-b6e548fe.js +0 -1
  68. rasa/core/channels/inspector/dist/assets/c4Diagram-d0fbc5ce-fa03ac9e.js +0 -10
  69. rasa/core/channels/inspector/dist/assets/classDiagram-936ed81e-ee67392a.js +0 -2
  70. rasa/core/channels/inspector/dist/assets/classDiagram-v2-c3cb15f1-9b283fae.js +0 -2
  71. rasa/core/channels/inspector/dist/assets/edges-f2ad444c-22e77f4f.js +0 -4
  72. rasa/core/channels/inspector/dist/assets/flowDb-1972c806-9dd802e4.js +0 -6
  73. rasa/core/channels/inspector/dist/assets/flowDiagram-7ea5b25a-5fa1912f.js +0 -4
  74. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-1844e5a5.js +0 -1
  75. rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-abe16c3d-622a1fd2.js +0 -139
  76. rasa/core/channels/inspector/dist/assets/ganttDiagram-9b5ea136-e285a63a.js +0 -266
  77. rasa/core/channels/inspector/dist/assets/gitGraphDiagram-99d0ae7c-f237bdca.js +0 -70
  78. rasa/core/channels/inspector/dist/assets/index-2c4b9a3b-4b03d70e.js +0 -1
  79. rasa/core/channels/inspector/dist/assets/index-a5d3e69d.js +0 -1040
  80. rasa/core/channels/inspector/dist/assets/layout-78cff630.js +0 -1
  81. rasa/core/channels/inspector/dist/assets/linear-c4fc4098.js +0 -1
  82. rasa/core/channels/inspector/dist/assets/mindmap-definition-beec6740-c33c8ea6.js +0 -109
  83. rasa/core/channels/inspector/dist/assets/sankeyDiagram-8f13d901-2360fe39.js +0 -8
  84. rasa/core/channels/inspector/dist/assets/sequenceDiagram-b655622a-41b9f9ad.js +0 -122
  85. rasa/core/channels/inspector/dist/assets/stateDiagram-59f0c015-0aad326f.js +0 -1
  86. rasa/core/channels/inspector/dist/assets/stateDiagram-v2-2b26beab-9847d984.js +0 -1
  87. rasa/core/channels/inspector/dist/assets/styles-080da4f6-564d890e.js +0 -110
  88. rasa/core/channels/inspector/dist/assets/styles-3dcbcfbf-38957613.js +0 -159
  89. rasa/core/channels/inspector/dist/assets/svgDrawCommon-4835440b-ef3c5a77.js +0 -1
  90. {rasa_pro-3.10.17.dist-info → rasa_pro-3.10.19.dist-info}/NOTICE +0 -0
  91. {rasa_pro-3.10.17.dist-info → rasa_pro-3.10.19.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  import importlib.resources
2
2
  import math
3
3
  from dataclasses import dataclass, field
4
- from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING, Text, Tuple
4
+ from typing import Any, Dict, List, Optional, TYPE_CHECKING, Text, Tuple
5
5
 
6
6
  import structlog
7
7
  import tiktoken
@@ -29,7 +29,6 @@ from rasa.engine.storage.storage import ModelStorage
29
29
  from rasa.graph_components.providers.forms_provider import Forms
30
30
  from rasa.graph_components.providers.responses_provider import Responses
31
31
  from rasa.shared.constants import (
32
- REQUIRED_SLOTS_KEY,
33
32
  EMBEDDINGS_CONFIG_KEY,
34
33
  LLM_CONFIG_KEY,
35
34
  MODEL_CONFIG_KEY,
@@ -49,6 +48,7 @@ from rasa.shared.core.events import (
49
48
  )
50
49
  from rasa.shared.core.flows import FlowsList
51
50
  from rasa.shared.core.generator import TrackerWithCachedStates
51
+ from rasa.shared.core.policies.utils import filter_responses_for_intentless_policy
52
52
  from rasa.shared.core.trackers import DialogueStateTracker
53
53
  from rasa.shared.exceptions import FileIOException, RasaCoreException
54
54
  from rasa.shared.nlu.constants import PREDICTED_CONFIDENCE_KEY
@@ -81,8 +81,6 @@ from rasa.utils.ml_utils import (
81
81
  persist_faiss_vector_store,
82
82
  response_for_template,
83
83
  )
84
- from rasa.dialogue_understanding.patterns.chitchat import FLOW_PATTERN_CHITCHAT
85
- from rasa.shared.core.constants import ACTION_TRIGGER_CHITCHAT
86
84
  from rasa.utils.log_utils import log_llm
87
85
 
88
86
  if TYPE_CHECKING:
@@ -142,59 +140,6 @@ class Conversation:
142
140
  interactions: List[Interaction] = field(default_factory=list)
143
141
 
144
142
 
145
- def collect_form_responses(forms: Forms) -> Set[Text]:
146
- """Collect responses that belong the requested slots in forms.
147
-
148
- Args:
149
- forms: the forms from the domain
150
- Returns:
151
- all utterances used in forms
152
- """
153
- form_responses = set()
154
- for _, form_info in forms.data.items():
155
- for required_slot in form_info.get(REQUIRED_SLOTS_KEY, []):
156
- form_responses.add(f"utter_ask_{required_slot}")
157
- return form_responses
158
-
159
-
160
- def filter_responses(responses: Responses, forms: Forms, flows: FlowsList) -> Responses:
161
- """Filters out responses that are unwanted for the intentless policy.
162
-
163
- This includes utterances used in flows and forms.
164
-
165
- Args:
166
- responses: the responses from the domain
167
- forms: the forms from the domain
168
- flows: all flows
169
- Returns:
170
- The remaining, relevant responses for the intentless policy.
171
- """
172
- form_responses = collect_form_responses(forms)
173
- flow_responses = flows.utterances
174
- combined_responses = form_responses | flow_responses
175
- filtered_responses = {
176
- name: variants
177
- for name, variants in responses.data.items()
178
- if name not in combined_responses
179
- }
180
-
181
- pattern_chitchat = flows.flow_by_id(FLOW_PATTERN_CHITCHAT)
182
-
183
- # The following condition is highly unlikely, but mypy requires the case
184
- # of pattern_chitchat == None to be addressed
185
- if not pattern_chitchat:
186
- return Responses(data=filtered_responses)
187
-
188
- # if action_trigger_chitchat, filter out "utter_free_chitchat_response"
189
- has_action_trigger_chitchat = pattern_chitchat.has_action_step(
190
- ACTION_TRIGGER_CHITCHAT
191
- )
192
- if has_action_trigger_chitchat:
193
- filtered_responses.pop("utter_free_chitchat_response", None)
194
-
195
- return Responses(data=filtered_responses)
196
-
197
-
198
143
  def action_from_response(
199
144
  text: Optional[str], responses: Dict[Text, List[Dict[Text, Any]]]
200
145
  ) -> Optional[str]:
@@ -495,7 +440,9 @@ class IntentlessPolicy(Policy):
495
440
  "IntentlessPolicy",
496
441
  )
497
442
 
498
- responses = filter_responses(responses, forms, flows or FlowsList([]))
443
+ responses = filter_responses_for_intentless_policy(
444
+ responses, forms, flows or FlowsList([])
445
+ )
499
446
  telemetry.track_intentless_policy_train()
500
447
  response_texts = [r for r in extract_ai_response_examples(responses.data)]
501
448
 
@@ -139,7 +139,7 @@ class NLUCommandAdapter(GraphComponent, CommandGenerator):
139
139
 
140
140
  if commands:
141
141
  commands = clean_up_commands(
142
- commands, tracker, flows, self._execution_context
142
+ commands, tracker, flows, self._execution_context, domain
143
143
  )
144
144
  log_llm(
145
145
  logger=structlogger,
@@ -1,6 +1,8 @@
1
1
  from typing import List, Optional, Type, Set, Dict
2
2
 
3
3
  import structlog
4
+
5
+ from rasa.shared.core.domain import Domain
4
6
  from rasa.shared.core.training_data.structures import StoryGraph
5
7
  from rasa.dialogue_understanding.commands import (
6
8
  CancelFlowCommand,
@@ -43,6 +45,7 @@ from rasa.shared.core.constants import FLOW_HASHES_SLOT
43
45
  from rasa.shared.core.events import Event, SlotSet
44
46
  from rasa.shared.core.flows import FlowsList
45
47
  from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
48
+ from rasa.shared.core.policies.utils import contains_intentless_policy_responses
46
49
  from rasa.shared.core.slots import Slot
47
50
  from rasa.shared.core.trackers import DialogueStateTracker
48
51
  from rasa.shared.nlu.constants import COMMANDS
@@ -181,6 +184,7 @@ def execute_commands(
181
184
  all_flows: FlowsList,
182
185
  execution_context: ExecutionContext,
183
186
  story_graph: Optional[StoryGraph] = None,
187
+ domain: Optional[Domain] = None,
184
188
  ) -> List[Event]:
185
189
  """Executes a list of commands.
186
190
 
@@ -190,6 +194,7 @@ def execute_commands(
190
194
  all_flows: All flows.
191
195
  execution_context: Information about the single graph run.
192
196
  story_graph: StoryGraph object with stories available for training.
197
+ domain: The domain of the bot.
193
198
 
194
199
  Returns:
195
200
  A list of the events that were created.
@@ -198,7 +203,7 @@ def execute_commands(
198
203
  original_tracker = tracker.copy()
199
204
 
200
205
  commands = clean_up_commands(
201
- commands, tracker, all_flows, execution_context, story_graph
206
+ commands, tracker, all_flows, execution_context, story_graph, domain
202
207
  )
203
208
 
204
209
  updated_flows = find_updated_flows(tracker, all_flows)
@@ -332,6 +337,7 @@ def clean_up_commands(
332
337
  all_flows: FlowsList,
333
338
  execution_context: ExecutionContext,
334
339
  story_graph: Optional[StoryGraph] = None,
340
+ domain: Optional[Domain] = None,
335
341
  ) -> List[Command]:
336
342
  """Clean up a list of commands.
337
343
 
@@ -347,10 +353,13 @@ def clean_up_commands(
347
353
  all_flows: All flows.
348
354
  execution_context: Information about a single graph run.
349
355
  story_graph: StoryGraph object with stories available for training.
356
+ domain: The domain of the bot.
350
357
 
351
358
  Returns:
352
359
  The cleaned up commands.
353
360
  """
361
+ domain = domain if domain else Domain.empty()
362
+
354
363
  slots_so_far, active_flow = filled_slots_for_active_flow(tracker, all_flows)
355
364
 
356
365
  clean_commands: List[Command] = []
@@ -393,7 +402,12 @@ def clean_up_commands(
393
402
  # handle chitchat command differently from other free-form answer commands
394
403
  elif isinstance(command, ChitChatAnswerCommand):
395
404
  clean_commands = clean_up_chitchat_command(
396
- clean_commands, command, all_flows, execution_context, story_graph
405
+ clean_commands,
406
+ command,
407
+ all_flows,
408
+ execution_context,
409
+ domain,
410
+ story_graph,
397
411
  )
398
412
 
399
413
  elif isinstance(command, FreeFormAnswerCommand):
@@ -570,6 +584,7 @@ def clean_up_chitchat_command(
570
584
  command: ChitChatAnswerCommand,
571
585
  flows: FlowsList,
572
586
  execution_context: ExecutionContext,
587
+ domain: Domain,
573
588
  story_graph: Optional[StoryGraph] = None,
574
589
  ) -> List[Command]:
575
590
  """Clean up a chitchat answer command.
@@ -583,6 +598,8 @@ def clean_up_chitchat_command(
583
598
  flows: All flows.
584
599
  execution_context: Information about a single graph run.
585
600
  story_graph: StoryGraph object with stories available for training.
601
+ domain: The domain of the bot.
602
+
586
603
  Returns:
587
604
  The cleaned up commands.
588
605
  """
@@ -608,10 +625,9 @@ def clean_up_chitchat_command(
608
625
  )
609
626
  defines_intentless_policy = execution_context.has_node(IntentlessPolicy)
610
627
 
611
- has_e2e_stories = True if (story_graph and story_graph.has_e2e_stories()) else False
612
-
613
628
  if (has_action_trigger_chitchat and not defines_intentless_policy) or (
614
- defines_intentless_policy and not has_e2e_stories
629
+ defines_intentless_policy
630
+ and not contains_intentless_policy_responses(flows, domain, story_graph)
615
631
  ):
616
632
  resulting_commands.insert(
617
633
  0, CannotHandleCommand(RASA_PATTERN_CANNOT_HANDLE_CHITCHAT)
@@ -6,6 +6,7 @@ import rasa.dialogue_understanding.processor.command_processor
6
6
  from rasa.engine.graph import ExecutionContext, GraphComponent
7
7
  from rasa.engine.storage.resource import Resource
8
8
  from rasa.engine.storage.storage import ModelStorage
9
+ from rasa.shared.core.domain import Domain
9
10
  from rasa.shared.core.events import Event
10
11
  from rasa.shared.core.flows import FlowsList
11
12
  from rasa.shared.core.trackers import DialogueStateTracker
@@ -15,7 +16,8 @@ from rasa.shared.core.training_data.structures import StoryGraph
15
16
  class CommandProcessorComponent(GraphComponent):
16
17
  """Processes commands by issuing events to modify a tracker.
17
18
 
18
- Minimal component that applies commands to a tracker."""
19
+ Minimal component that applies commands to a tracker.
20
+ """
19
21
 
20
22
  def __init__(self, execution_context: ExecutionContext):
21
23
  self._execution_context = execution_context
@@ -36,8 +38,9 @@ class CommandProcessorComponent(GraphComponent):
36
38
  tracker: DialogueStateTracker,
37
39
  flows: FlowsList,
38
40
  story_graph: StoryGraph,
41
+ domain: Domain,
39
42
  ) -> List[Event]:
40
43
  """Execute commands to update tracker state."""
41
44
  return rasa.dialogue_understanding.processor.command_processor.execute_commands(
42
- tracker, flows, self._execution_context, story_graph
45
+ tracker, flows, self._execution_context, story_graph, domain
43
46
  )
rasa/engine/validation.py CHANGED
@@ -5,18 +5,18 @@ import logging
5
5
  import sys
6
6
  import typing
7
7
  from typing import (
8
- Optional,
8
+ Any,
9
9
  Callable,
10
+ Dict,
11
+ List,
12
+ Literal,
13
+ Optional,
14
+ Set,
10
15
  Text,
11
16
  Tuple,
12
- Dict,
13
17
  Type,
14
- Any,
15
- Set,
16
- Union,
17
18
  TypeVar,
18
- List,
19
- Literal,
19
+ Union,
20
20
  )
21
21
 
22
22
  import structlog
@@ -60,8 +60,10 @@ from rasa.shared.constants import (
60
60
  )
61
61
  from rasa.shared.core.constants import ACTION_RESET_ROUTING, ACTION_TRIGGER_CHITCHAT
62
62
  from rasa.shared.core.domain import Domain
63
- from rasa.shared.core.flows import FlowsList, Flow
63
+ from rasa.shared.core.flows import Flow, FlowsList
64
+ from rasa.shared.core.policies.utils import contains_intentless_policy_responses
64
65
  from rasa.shared.core.slots import Slot
66
+ from rasa.shared.core.training_data.structures import StoryGraph
65
67
  from rasa.shared.exceptions import RasaException
66
68
  from rasa.shared.nlu.training_data.message import Message
67
69
 
@@ -621,11 +623,18 @@ def _recursively_check_required_components(
621
623
 
622
624
 
623
625
  def validate_flow_component_dependencies(
624
- flows: FlowsList, model_configuration: GraphModelConfiguration
626
+ flows: FlowsList,
627
+ domain: Domain,
628
+ story_graph: StoryGraph,
629
+ model_configuration: GraphModelConfiguration,
625
630
  ) -> None:
626
631
  if (pattern_chitchat := flows.flow_by_id(FLOW_PATTERN_CHITCHAT)) is not None:
627
632
  _validate_chitchat_dependencies(pattern_chitchat, model_configuration)
628
633
 
634
+ _validate_intentless_policy_responses(
635
+ flows, domain, story_graph, model_configuration
636
+ )
637
+
629
638
 
630
639
  def _validate_chitchat_dependencies(
631
640
  pattern_chitchat: Flow, model_configuration: GraphModelConfiguration
@@ -653,6 +662,32 @@ def _validate_chitchat_dependencies(
653
662
  )
654
663
 
655
664
 
665
+ def _validate_intentless_policy_responses(
666
+ flows: FlowsList,
667
+ domain: Domain,
668
+ story_graph: StoryGraph,
669
+ model_configuration: GraphModelConfiguration,
670
+ ) -> None:
671
+ """If IntentlessPolicy is configured, validate that it has responses to use:
672
+ either responses from the domain that are not part of any flow, or from
673
+ end-to-end stories.
674
+ """
675
+ if not model_configuration.predict_schema.has_node(IntentlessPolicy):
676
+ return
677
+
678
+ if not contains_intentless_policy_responses(flows, domain, story_graph):
679
+ structlogger.error(
680
+ "validation.intentless_policy.no_applicable_responses_found",
681
+ event_info=(
682
+ "IntentlessPolicy is configured, but no applicable responses are "
683
+ "found. Please make sure that there are responses defined in the "
684
+ "domain that are not part of any flow, or that there are "
685
+ "end-to-end stories in the training data."
686
+ ),
687
+ )
688
+ sys.exit(1)
689
+
690
+
656
691
  def get_component_index(schema: GraphSchema, component_class: Type) -> Optional[int]:
657
692
  """Extracts the index of a component of the given class in the schema.
658
693
  This function assumes that each component's node name is stored in a way
@@ -45,7 +45,7 @@ class ConversationStep:
45
45
  elif isinstance(command, SetSlotCommand):
46
46
  output.append(f"SetSlot({command.name}, {command.value})")
47
47
  elif isinstance(command, ClarifyCommand):
48
- output.append(f"Clarify({command.options})")
48
+ output.append(f"Clarify({', '.join(command.options)})")
49
49
  elif isinstance(command, CancelFlowCommand):
50
50
  output.append("CancelFlow()")
51
51
  elif isinstance(command, ChitChatAnswerCommand):
rasa/model_training.py CHANGED
@@ -302,6 +302,7 @@ async def _train_graph(
302
302
  )
303
303
  flows = file_importer.get_flows()
304
304
  domain = file_importer.get_domain()
305
+ story_graph = file_importer.get_stories()
305
306
  model_configuration = recipe.graph_config_for_recipe(
306
307
  config,
307
308
  kwargs,
@@ -314,7 +315,7 @@ async def _train_graph(
314
315
  )
315
316
  rasa.engine.validation.validate_model_client_configuration_setup(config)
316
317
  rasa.engine.validation.validate_flow_component_dependencies(
317
- flows, model_configuration
318
+ flows, domain, story_graph, model_configuration
318
319
  )
319
320
  rasa.engine.validation.validate_command_generator_setup(model_configuration)
320
321
 
rasa/shared/constants.py CHANGED
@@ -97,6 +97,8 @@ UTTER_ASK_PREFIX = "utter_ask_"
97
97
  ACTION_ASK_PREFIX = "action_ask_"
98
98
  FLOW_PREFIX = "flow_"
99
99
 
100
+ UTTER_FREE_CHITCHAT_RESPONSE = "utter_free_chitchat_response"
101
+
100
102
  ASSISTANT_ID_KEY = "assistant_id"
101
103
  ASSISTANT_ID_DEFAULT_VALUE = "placeholder_default"
102
104
 
@@ -115,6 +117,7 @@ CONFIG_MANDATORY_KEYS_NLU = ["language"] + CONFIG_MANDATORY_COMMON_KEYS
115
117
  CONFIG_MANDATORY_KEYS = list(
116
118
  set(CONFIG_MANDATORY_KEYS_CORE + CONFIG_MANDATORY_KEYS_NLU)
117
119
  )
120
+ CONFIG_RECIPE_KEY = "recipe"
118
121
 
119
122
  # Keys related to Forms (in the Domain)
120
123
  REQUIRED_SLOTS_KEY = "required_slots"
@@ -165,3 +165,5 @@ POLICY_NAME_RULE = "RulePolicy"
165
165
  CLASSIFIER_NAME_FALLBACK = "FallbackClassifier"
166
166
 
167
167
  POLICIES_THAT_EXTRACT_ENTITIES = {"TEDPolicy"}
168
+
169
+ ERROR_CODE_KEY = "error_code"
@@ -1651,6 +1651,14 @@ class Domain:
1651
1651
  """Write domain to a file."""
1652
1652
  as_yaml = self.as_yaml()
1653
1653
  rasa.shared.utils.io.write_text_file(as_yaml, filename)
1654
+ # run the check again on the written domain to catch any errors
1655
+ # that may have been missed in the user defined domain files
1656
+ structlogger.info(
1657
+ "domain.persist.domain_written_to_file",
1658
+ event_info="The entire domain content has been written to file.",
1659
+ filename=filename,
1660
+ )
1661
+ Domain.is_domain_file(filename)
1654
1662
 
1655
1663
  def as_yaml(self) -> Text:
1656
1664
  """Dump the `Domain` object as a YAML string.
@@ -1945,17 +1953,18 @@ class Domain:
1945
1953
 
1946
1954
  try:
1947
1955
  content = read_yaml_file(filename)
1948
- except (RasaException, YamlSyntaxException):
1949
- structlogger.warning(
1956
+ except (RasaException, YamlSyntaxException) as error:
1957
+ structlogger.error(
1950
1958
  "domain.cannot_load_domain_file",
1951
1959
  file=filename,
1960
+ error=error,
1952
1961
  event_info=(
1953
1962
  f"The file {filename} could not be loaded as domain file. "
1954
1963
  f"You can use https://yamlchecker.com/ to validate "
1955
1964
  f"the YAML syntax of your file."
1956
1965
  ),
1957
1966
  )
1958
- return False
1967
+ raise RasaException(f"Domain could not be loaded: {error}")
1959
1968
 
1960
1969
  return any(key in content for key in ALL_DOMAIN_KEYS)
1961
1970
 
@@ -31,15 +31,16 @@ from typing import Union
31
31
 
32
32
  from rasa.shared.constants import DOCS_URL_TRAINING_DATA
33
33
  from rasa.shared.core.constants import (
34
- LOOP_NAME,
35
- EXTERNAL_MESSAGE_PREFIX,
34
+ ACTION_LISTEN_NAME,
36
35
  ACTION_NAME_SENDER_ID_CONNECTOR_STR,
36
+ ACTION_SESSION_START_NAME,
37
+ ENTITY_LABEL_SEPARATOR,
38
+ ERROR_CODE_KEY,
39
+ EXTERNAL_MESSAGE_PREFIX,
37
40
  IS_EXTERNAL,
38
- USE_TEXT_FOR_FEATURIZATION,
39
41
  LOOP_INTERRUPTED,
40
- ENTITY_LABEL_SEPARATOR,
41
- ACTION_SESSION_START_NAME,
42
- ACTION_LISTEN_NAME,
42
+ USE_TEXT_FOR_FEATURIZATION,
43
+ LOOP_NAME,
43
44
  )
44
45
  from rasa.shared.exceptions import UnsupportedFeatureException
45
46
  from rasa.shared.nlu.constants import (
@@ -2528,3 +2529,69 @@ class FlowCancelled(SkipEventInMDStoryMixin):
2528
2529
  )
2529
2530
  except KeyError as e:
2530
2531
  raise ValueError(f"Failed to parse flow_cancelled event. {e}")
2532
+
2533
+
2534
+ class ErrorHandled(Event):
2535
+ """An error occurred during the conversation.
2536
+
2537
+ The error message is stored in the metadata of the event.
2538
+ """
2539
+
2540
+ type_name = "error"
2541
+
2542
+ def __init__(
2543
+ self,
2544
+ error_code: int,
2545
+ timestamp: Optional[float] = None,
2546
+ metadata: Optional[Dict[str, Any]] = None,
2547
+ ) -> None:
2548
+ """Creates event for an error.
2549
+
2550
+ Args:
2551
+ error_code: Error int code.
2552
+ timestamp: When the event was created.
2553
+ metadata: Additional event metadata.
2554
+ """
2555
+ self.error_code = error_code
2556
+ super().__init__(timestamp, metadata)
2557
+
2558
+ def __str__(self) -> Text:
2559
+ """Returns text representation of event."""
2560
+ return f"ErrorHandled({self.error_code})"
2561
+
2562
+ def __repr__(self) -> Text:
2563
+ """Returns event as string for debugging."""
2564
+ return f"ErrorHandled({self.error_code}, {self.timestamp}, {self.metadata})"
2565
+
2566
+ def __hash__(self) -> int:
2567
+ """Returns unique hash for event."""
2568
+ return hash(self.error_code)
2569
+
2570
+ def __eq__(self, other: Any) -> bool:
2571
+ """Compares object with other object."""
2572
+ if not isinstance(other, ErrorHandled):
2573
+ return NotImplemented
2574
+
2575
+ return self.error_code == other.error_code
2576
+
2577
+ def as_story_string(self) -> Text:
2578
+ """Returns text representation of event."""
2579
+ props = json.dumps({ERROR_CODE_KEY: self.error_code})
2580
+ return f"{ErrorHandled.type_name}{props}"
2581
+
2582
+ @classmethod
2583
+ def _from_story_string(cls, parameters: Dict[Text, Any]) -> List["ErrorHandled"]:
2584
+ """Called to convert a parsed story line into an event."""
2585
+ return [
2586
+ ErrorHandled(
2587
+ parameters.get(ERROR_CODE_KEY),
2588
+ parameters.get("timestamp"),
2589
+ parameters.get("metadata"),
2590
+ )
2591
+ ]
2592
+
2593
+ def as_dict(self) -> Dict[Text, Any]:
2594
+ """Returns serialized event."""
2595
+ serialized = super().as_dict()
2596
+ serialized.update({ERROR_CODE_KEY: self.error_code})
2597
+ return serialized
File without changes
@@ -0,0 +1,87 @@
1
+ from typing import Set, Text
2
+
3
+ from rasa.dialogue_understanding.patterns.chitchat import FLOW_PATTERN_CHITCHAT
4
+ from rasa.graph_components.providers.forms_provider import Forms
5
+ from rasa.graph_components.providers.responses_provider import Responses
6
+ from rasa.shared.constants import (
7
+ REQUIRED_SLOTS_KEY,
8
+ UTTER_ASK_PREFIX,
9
+ UTTER_FREE_CHITCHAT_RESPONSE,
10
+ )
11
+ from rasa.shared.core.constants import ACTION_TRIGGER_CHITCHAT
12
+ from rasa.shared.core.domain import Domain
13
+ from rasa.shared.core.flows import FlowsList
14
+ from rasa.shared.core.training_data.structures import StoryGraph
15
+
16
+
17
+ def collect_form_responses(forms: Forms) -> Set[Text]:
18
+ """Collect responses that belong the requested slots in forms.
19
+
20
+ Args:
21
+ forms: the forms from the domain
22
+ Returns:
23
+ all utterances used in forms
24
+ """
25
+ form_responses = set()
26
+ for _, form_info in forms.data.items():
27
+ for required_slot in form_info.get(REQUIRED_SLOTS_KEY, []):
28
+ form_responses.add(f"{UTTER_ASK_PREFIX}{required_slot}")
29
+ return form_responses
30
+
31
+
32
+ def filter_responses_for_intentless_policy(
33
+ responses: Responses, forms: Forms, flows: FlowsList
34
+ ) -> Responses:
35
+ """Filters out responses that are unwanted for the intentless policy.
36
+
37
+ This includes utterances used in flows and forms.
38
+
39
+ Args:
40
+ responses: the responses from the domain
41
+ forms: the forms from the domain
42
+ flows: all flows
43
+ Returns:
44
+ The remaining, relevant responses for the intentless policy.
45
+ """
46
+ form_responses = collect_form_responses(forms)
47
+ flow_responses = flows.utterances
48
+ combined_responses = form_responses | flow_responses
49
+ filtered_responses = {
50
+ name: variants
51
+ for name, variants in responses.data.items()
52
+ if name not in combined_responses
53
+ }
54
+
55
+ pattern_chitchat = flows.flow_by_id(FLOW_PATTERN_CHITCHAT)
56
+
57
+ # The following condition is highly unlikely, but mypy requires the case
58
+ # of pattern_chitchat == None to be addressed
59
+ if not pattern_chitchat:
60
+ return Responses(data=filtered_responses)
61
+
62
+ # if action_trigger_chitchat, filter out "utter_free_chitchat_response"
63
+ has_action_trigger_chitchat = pattern_chitchat.has_action_step(
64
+ ACTION_TRIGGER_CHITCHAT
65
+ )
66
+ if has_action_trigger_chitchat:
67
+ filtered_responses.pop(UTTER_FREE_CHITCHAT_RESPONSE, None)
68
+
69
+ return Responses(data=filtered_responses)
70
+
71
+
72
+ def contains_intentless_policy_responses(
73
+ flows: FlowsList, domain: Domain, story_graph: StoryGraph
74
+ ) -> bool:
75
+ """Checks if IntentlessPolicy has applicable responses: either responses in the
76
+ domain that are not part of any flow, or if there are e2e stories.
77
+ """
78
+ responses = filter_responses_for_intentless_policy(
79
+ Responses(data=domain.responses), Forms(data=domain.forms), flows
80
+ )
81
+
82
+ has_applicable_responses = bool(
83
+ responses and responses.data and len(responses.data) > 0
84
+ )
85
+ has_e2e_stories = bool(story_graph and story_graph.has_e2e_stories())
86
+
87
+ return has_applicable_responses or has_e2e_stories
@@ -164,8 +164,7 @@ DIALOGUE_STACK_UPDATED = {
164
164
  }
165
165
  ROUTING_SESSION_ENDED = {"properties": {"event": {"const": "routing_session_ended"}}}
166
166
 
167
-
168
- ROUTING_SESSION_ENDED = {"properties": {"event": {"const": "routing_session_ended"}}}
167
+ ERROR_HANDLED = {"properties": {"event": {"const": "error"}}}
169
168
 
170
169
  EVENT_SCHEMA = {
171
170
  "type": "object",
@@ -206,6 +205,7 @@ EVENT_SCHEMA = {
206
205
  FLOW_CANCELLED,
207
206
  DIALOGUE_STACK_UPDATED,
208
207
  ROUTING_SESSION_ENDED,
208
+ ERROR_HANDLED,
209
209
  ],
210
210
  }
211
211
 
@@ -376,6 +376,7 @@ def extract_attrs_for_execute_commands(
376
376
  all_flows: FlowsList,
377
377
  execution_context: ExecutionContext,
378
378
  story_graph: Optional[StoryGraph] = None,
379
+ domain: Optional[Domain] = None,
379
380
  ) -> Dict[str, Any]:
380
381
  return {
381
382
  "number_of_events": len(tracker.events),
@@ -419,6 +420,7 @@ def extract_attrs_for_clean_up_commands(
419
420
  all_flows: FlowsList,
420
421
  execution_context: ExecutionContext,
421
422
  story_graph: Optional[StoryGraph] = None,
423
+ domain: Optional[Domain] = None,
422
424
  ) -> Dict[str, Any]:
423
425
  commands_list = []
424
426
 
rasa/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  # this file will automatically be changed,
2
2
  # do not add anything but the version number here!
3
- __version__ = "3.10.17"
3
+ __version__ = "3.10.19"