rasa-pro 3.9.18__py3-none-any.whl → 3.10.3__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 (189) hide show
  1. README.md +26 -57
  2. rasa/__init__.py +1 -2
  3. rasa/__main__.py +5 -0
  4. rasa/anonymization/anonymization_rule_executor.py +2 -2
  5. rasa/api.py +26 -22
  6. rasa/cli/arguments/data.py +27 -2
  7. rasa/cli/arguments/default_arguments.py +25 -3
  8. rasa/cli/arguments/run.py +9 -9
  9. rasa/cli/arguments/train.py +2 -0
  10. rasa/cli/data.py +70 -8
  11. rasa/cli/e2e_test.py +108 -433
  12. rasa/cli/interactive.py +1 -0
  13. rasa/cli/llm_fine_tuning.py +395 -0
  14. rasa/cli/project_templates/calm/endpoints.yml +1 -1
  15. rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
  16. rasa/cli/run.py +14 -13
  17. rasa/cli/scaffold.py +10 -8
  18. rasa/cli/train.py +8 -7
  19. rasa/cli/utils.py +15 -0
  20. rasa/constants.py +7 -1
  21. rasa/core/actions/action.py +98 -49
  22. rasa/core/actions/action_run_slot_rejections.py +4 -1
  23. rasa/core/actions/custom_action_executor.py +9 -6
  24. rasa/core/actions/direct_custom_actions_executor.py +80 -0
  25. rasa/core/actions/e2e_stub_custom_action_executor.py +68 -0
  26. rasa/core/actions/grpc_custom_action_executor.py +2 -2
  27. rasa/core/actions/http_custom_action_executor.py +6 -5
  28. rasa/core/agent.py +21 -17
  29. rasa/core/channels/__init__.py +2 -0
  30. rasa/core/channels/audiocodes.py +1 -16
  31. rasa/core/channels/inspector/dist/index.html +0 -2
  32. rasa/core/channels/inspector/index.html +0 -2
  33. rasa/core/channels/voice_aware/__init__.py +0 -0
  34. rasa/core/channels/voice_aware/jambonz.py +103 -0
  35. rasa/core/channels/voice_aware/jambonz_protocol.py +344 -0
  36. rasa/core/channels/voice_aware/utils.py +20 -0
  37. rasa/core/channels/voice_native/__init__.py +0 -0
  38. rasa/core/constants.py +6 -1
  39. rasa/core/featurizers/single_state_featurizer.py +1 -22
  40. rasa/core/featurizers/tracker_featurizers.py +18 -115
  41. rasa/core/information_retrieval/faiss.py +7 -4
  42. rasa/core/information_retrieval/information_retrieval.py +8 -0
  43. rasa/core/information_retrieval/milvus.py +9 -2
  44. rasa/core/information_retrieval/qdrant.py +1 -1
  45. rasa/core/nlg/contextual_response_rephraser.py +32 -10
  46. rasa/core/nlg/summarize.py +4 -3
  47. rasa/core/policies/enterprise_search_policy.py +100 -44
  48. rasa/core/policies/flows/flow_executor.py +130 -94
  49. rasa/core/policies/intentless_policy.py +52 -28
  50. rasa/core/policies/ted_policy.py +33 -58
  51. rasa/core/policies/unexpected_intent_policy.py +7 -15
  52. rasa/core/processor.py +20 -53
  53. rasa/core/run.py +5 -4
  54. rasa/core/tracker_store.py +8 -4
  55. rasa/core/utils.py +45 -56
  56. rasa/dialogue_understanding/coexistence/llm_based_router.py +45 -12
  57. rasa/dialogue_understanding/commands/__init__.py +4 -0
  58. rasa/dialogue_understanding/commands/change_flow_command.py +0 -6
  59. rasa/dialogue_understanding/commands/session_start_command.py +59 -0
  60. rasa/dialogue_understanding/commands/set_slot_command.py +1 -5
  61. rasa/dialogue_understanding/commands/utils.py +38 -0
  62. rasa/dialogue_understanding/generator/constants.py +10 -3
  63. rasa/dialogue_understanding/generator/flow_retrieval.py +14 -5
  64. rasa/dialogue_understanding/generator/llm_based_command_generator.py +12 -2
  65. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +106 -87
  66. rasa/dialogue_understanding/generator/nlu_command_adapter.py +28 -6
  67. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +90 -37
  68. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +15 -15
  69. rasa/dialogue_understanding/patterns/session_start.py +37 -0
  70. rasa/dialogue_understanding/processor/command_processor.py +13 -14
  71. rasa/e2e_test/aggregate_test_stats_calculator.py +124 -0
  72. rasa/e2e_test/assertions.py +1181 -0
  73. rasa/e2e_test/assertions_schema.yml +106 -0
  74. rasa/e2e_test/constants.py +20 -0
  75. rasa/e2e_test/e2e_config.py +220 -0
  76. rasa/e2e_test/e2e_config_schema.yml +26 -0
  77. rasa/e2e_test/e2e_test_case.py +131 -8
  78. rasa/e2e_test/e2e_test_converter.py +363 -0
  79. rasa/e2e_test/e2e_test_converter_prompt.jinja2 +70 -0
  80. rasa/e2e_test/e2e_test_coverage_report.py +364 -0
  81. rasa/e2e_test/e2e_test_result.py +26 -6
  82. rasa/e2e_test/e2e_test_runner.py +491 -72
  83. rasa/e2e_test/e2e_test_schema.yml +96 -0
  84. rasa/e2e_test/pykwalify_extensions.py +39 -0
  85. rasa/e2e_test/stub_custom_action.py +70 -0
  86. rasa/e2e_test/utils/__init__.py +0 -0
  87. rasa/e2e_test/utils/e2e_yaml_utils.py +55 -0
  88. rasa/e2e_test/utils/io.py +596 -0
  89. rasa/e2e_test/utils/validation.py +80 -0
  90. rasa/engine/recipes/default_components.py +0 -2
  91. rasa/engine/storage/local_model_storage.py +0 -1
  92. rasa/env.py +9 -0
  93. rasa/llm_fine_tuning/__init__.py +0 -0
  94. rasa/llm_fine_tuning/annotation_module.py +241 -0
  95. rasa/llm_fine_tuning/conversations.py +144 -0
  96. rasa/llm_fine_tuning/llm_data_preparation_module.py +178 -0
  97. rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +407 -0
  98. rasa/llm_fine_tuning/paraphrasing/__init__.py +0 -0
  99. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +281 -0
  100. rasa/llm_fine_tuning/paraphrasing/default_rephrase_prompt_template.jina2 +44 -0
  101. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +121 -0
  102. rasa/llm_fine_tuning/paraphrasing/rephrased_user_message.py +10 -0
  103. rasa/llm_fine_tuning/paraphrasing_module.py +128 -0
  104. rasa/llm_fine_tuning/storage.py +174 -0
  105. rasa/llm_fine_tuning/train_test_split_module.py +441 -0
  106. rasa/model_training.py +48 -16
  107. rasa/nlu/classifiers/diet_classifier.py +25 -38
  108. rasa/nlu/classifiers/logistic_regression_classifier.py +9 -44
  109. rasa/nlu/classifiers/sklearn_intent_classifier.py +16 -37
  110. rasa/nlu/extractors/crf_entity_extractor.py +50 -93
  111. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +45 -78
  112. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +17 -52
  113. rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +3 -5
  114. rasa/nlu/persistor.py +129 -32
  115. rasa/server.py +45 -10
  116. rasa/shared/constants.py +63 -15
  117. rasa/shared/core/domain.py +15 -12
  118. rasa/shared/core/events.py +28 -2
  119. rasa/shared/core/flows/flow.py +208 -13
  120. rasa/shared/core/flows/flow_path.py +84 -0
  121. rasa/shared/core/flows/flows_list.py +28 -10
  122. rasa/shared/core/flows/flows_yaml_schema.json +269 -193
  123. rasa/shared/core/flows/validation.py +112 -25
  124. rasa/shared/core/flows/yaml_flows_io.py +149 -10
  125. rasa/shared/core/trackers.py +6 -0
  126. rasa/shared/core/training_data/visualization.html +2 -2
  127. rasa/shared/exceptions.py +4 -0
  128. rasa/shared/importers/importer.py +60 -11
  129. rasa/shared/importers/remote_importer.py +196 -0
  130. rasa/shared/nlu/constants.py +2 -0
  131. rasa/shared/nlu/training_data/features.py +2 -120
  132. rasa/shared/providers/_configs/__init__.py +0 -0
  133. rasa/shared/providers/_configs/azure_openai_client_config.py +181 -0
  134. rasa/shared/providers/_configs/client_config.py +57 -0
  135. rasa/shared/providers/_configs/default_litellm_client_config.py +130 -0
  136. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +234 -0
  137. rasa/shared/providers/_configs/openai_client_config.py +175 -0
  138. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +171 -0
  139. rasa/shared/providers/_configs/utils.py +101 -0
  140. rasa/shared/providers/_ssl_verification_utils.py +124 -0
  141. rasa/shared/providers/embedding/__init__.py +0 -0
  142. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +254 -0
  143. rasa/shared/providers/embedding/_langchain_embedding_client_adapter.py +74 -0
  144. rasa/shared/providers/embedding/azure_openai_embedding_client.py +277 -0
  145. rasa/shared/providers/embedding/default_litellm_embedding_client.py +102 -0
  146. rasa/shared/providers/embedding/embedding_client.py +90 -0
  147. rasa/shared/providers/embedding/embedding_response.py +41 -0
  148. rasa/shared/providers/embedding/huggingface_local_embedding_client.py +191 -0
  149. rasa/shared/providers/embedding/openai_embedding_client.py +172 -0
  150. rasa/shared/providers/llm/__init__.py +0 -0
  151. rasa/shared/providers/llm/_base_litellm_client.py +227 -0
  152. rasa/shared/providers/llm/azure_openai_llm_client.py +338 -0
  153. rasa/shared/providers/llm/default_litellm_llm_client.py +84 -0
  154. rasa/shared/providers/llm/llm_client.py +76 -0
  155. rasa/shared/providers/llm/llm_response.py +50 -0
  156. rasa/shared/providers/llm/openai_llm_client.py +155 -0
  157. rasa/shared/providers/llm/self_hosted_llm_client.py +169 -0
  158. rasa/shared/providers/mappings.py +75 -0
  159. rasa/shared/utils/cli.py +30 -0
  160. rasa/shared/utils/io.py +65 -3
  161. rasa/shared/utils/llm.py +223 -200
  162. rasa/shared/utils/yaml.py +122 -7
  163. rasa/studio/download.py +19 -13
  164. rasa/studio/train.py +2 -3
  165. rasa/studio/upload.py +2 -3
  166. rasa/telemetry.py +113 -58
  167. rasa/tracing/config.py +2 -3
  168. rasa/tracing/instrumentation/attribute_extractors.py +29 -17
  169. rasa/tracing/instrumentation/instrumentation.py +4 -47
  170. rasa/utils/common.py +18 -19
  171. rasa/utils/endpoints.py +7 -4
  172. rasa/utils/io.py +66 -0
  173. rasa/utils/json_utils.py +60 -0
  174. rasa/utils/licensing.py +9 -1
  175. rasa/utils/ml_utils.py +4 -2
  176. rasa/utils/tensorflow/model_data.py +193 -2
  177. rasa/validator.py +195 -1
  178. rasa/version.py +1 -1
  179. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.3.dist-info}/METADATA +47 -72
  180. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.3.dist-info}/RECORD +185 -121
  181. rasa/nlu/classifiers/llm_intent_classifier.py +0 -519
  182. rasa/shared/providers/openai/clients.py +0 -43
  183. rasa/shared/providers/openai/session_handler.py +0 -110
  184. rasa/utils/tensorflow/feature_array.py +0 -366
  185. /rasa/{shared/providers/openai → cli/project_templates/tutorial/actions}/__init__.py +0 -0
  186. /rasa/cli/project_templates/tutorial/{actions.py → actions/actions.py} +0 -0
  187. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.3.dist-info}/NOTICE +0 -0
  188. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.3.dist-info}/WHEEL +0 -0
  189. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.3.dist-info}/entry_points.txt +0 -0
@@ -1,14 +1,15 @@
1
1
  import copy
2
2
  import logging
3
+ from functools import lru_cache
3
4
  from typing import (
5
+ TYPE_CHECKING,
6
+ Any,
7
+ Dict,
4
8
  List,
5
- Text,
6
9
  Optional,
7
- Dict,
8
- Any,
9
- TYPE_CHECKING,
10
- Tuple,
11
10
  Set,
11
+ Text,
12
+ Tuple,
12
13
  cast,
13
14
  )
14
15
 
@@ -16,59 +17,68 @@ import rasa.core
16
17
  import rasa.shared.utils.io
17
18
  from rasa.core.actions.custom_action_executor import (
18
19
  CustomActionExecutor,
19
- RetryCustomActionExecutor,
20
20
  NoEndpointCustomActionExecutor,
21
+ RetryCustomActionExecutor,
22
+ )
23
+ from rasa.core.actions.direct_custom_actions_executor import DirectCustomActionExecutor
24
+ from rasa.core.actions.e2e_stub_custom_action_executor import (
25
+ E2EStubCustomActionExecutor,
21
26
  )
22
27
  from rasa.core.actions.grpc_custom_action_executor import GRPCCustomActionExecutor
23
28
  from rasa.core.actions.http_custom_action_executor import HTTPCustomActionExecutor
29
+ from rasa.core.constants import (
30
+ UTTER_SOURCE_METADATA_KEY,
31
+ )
24
32
  from rasa.core.policies.policy import PolicyPrediction
33
+ from rasa.core.utils import add_bot_utterance_metadata
34
+ from rasa.e2e_test.constants import KEY_STUB_CUSTOM_ACTIONS
25
35
  from rasa.nlu.constants import (
26
36
  RESPONSE_SELECTOR_DEFAULT_INTENT,
27
- RESPONSE_SELECTOR_PROPERTY_NAME,
28
37
  RESPONSE_SELECTOR_PREDICTION_KEY,
38
+ RESPONSE_SELECTOR_PROPERTY_NAME,
29
39
  RESPONSE_SELECTOR_UTTER_ACTION_KEY,
30
40
  )
31
41
  from rasa.shared.constants import (
32
- DOCS_BASE_URL,
33
42
  DEFAULT_NLU_FALLBACK_INTENT_NAME,
43
+ DOCS_BASE_URL,
44
+ FLOW_PREFIX,
34
45
  ROUTE_TO_CALM_SLOT,
35
46
  UTTER_PREFIX,
36
- FLOW_PREFIX,
37
47
  )
38
48
  from rasa.shared.core.constants import (
39
- ACTION_RESET_ROUTING,
40
- USER_INTENT_OUT_OF_SCOPE,
49
+ ACTION_BACK_NAME,
50
+ ACTION_DEACTIVATE_LOOP_NAME,
51
+ ACTION_DEFAULT_ASK_AFFIRMATION_NAME,
52
+ ACTION_DEFAULT_ASK_REPHRASE_NAME,
53
+ ACTION_DEFAULT_FALLBACK_NAME,
54
+ ACTION_EXTRACT_SLOTS,
41
55
  ACTION_LISTEN_NAME,
56
+ ACTION_RESET_ROUTING,
42
57
  ACTION_RESTART_NAME,
58
+ ACTION_REVERT_FALLBACK_EVENTS_NAME,
43
59
  ACTION_SEND_TEXT_NAME,
44
60
  ACTION_SESSION_START_NAME,
45
- ACTION_DEFAULT_FALLBACK_NAME,
46
- ACTION_DEACTIVATE_LOOP_NAME,
47
- ACTION_REVERT_FALLBACK_EVENTS_NAME,
48
- ACTION_DEFAULT_ASK_AFFIRMATION_NAME,
49
- ACTION_DEFAULT_ASK_REPHRASE_NAME,
50
61
  ACTION_UNLIKELY_INTENT_NAME,
51
- ACTION_BACK_NAME,
52
- REQUESTED_SLOT,
53
- ACTION_EXTRACT_SLOTS,
54
- DEFAULT_SLOT_NAMES,
55
62
  ACTION_VALIDATE_SLOT_MAPPINGS,
63
+ DEFAULT_SLOT_NAMES,
64
+ KNOWLEDGE_BASE_SLOT_NAMES,
56
65
  MAPPING_TYPE,
66
+ REQUESTED_SLOT,
67
+ USER_INTENT_OUT_OF_SCOPE,
57
68
  SlotMappingType,
58
- KNOWLEDGE_BASE_SLOT_NAMES,
59
69
  )
60
70
  from rasa.shared.core.domain import Domain
61
71
  from rasa.shared.core.events import (
62
- RoutingSessionEnded,
63
- UserUtteranceReverted,
64
- UserUttered,
65
72
  ActionExecuted,
66
- Event,
67
- BotUttered,
68
- SlotSet,
69
73
  ActiveLoop,
74
+ BotUttered,
75
+ Event,
70
76
  Restarted,
77
+ RoutingSessionEnded,
71
78
  SessionStarted,
79
+ SlotSet,
80
+ UserUtteranceReverted,
81
+ UserUttered,
72
82
  )
73
83
  from rasa.shared.core.flows import FlowsList
74
84
  from rasa.shared.core.slot_mappings import (
@@ -81,28 +91,30 @@ from rasa.shared.nlu.constants import (
81
91
  INTENT_NAME_KEY,
82
92
  INTENT_RANKING_KEY,
83
93
  )
94
+ from rasa.shared.utils.io import raise_warning
84
95
  from rasa.shared.utils.schemas.events import EVENTS_SCHEMA
85
- from rasa.utils.endpoints import EndpointConfig, ClientResponseError
86
- from rasa.utils.url_tools import get_url_schema, UrlSchema
96
+ from rasa.utils.endpoints import ClientResponseError, EndpointConfig
97
+ from rasa.utils.url_tools import UrlSchema, get_url_schema
87
98
 
88
99
  if TYPE_CHECKING:
89
- from rasa.core.nlg import NaturalLanguageGenerator
90
100
  from rasa.core.channels.channel import OutputChannel
101
+ from rasa.core.nlg import NaturalLanguageGenerator
91
102
  from rasa.shared.core.events import IntentPrediction
92
103
 
104
+
93
105
  logger = logging.getLogger(__name__)
94
106
 
95
107
 
96
108
  def default_actions(action_endpoint: Optional[EndpointConfig] = None) -> List["Action"]:
97
109
  """List default actions."""
98
- from rasa.core.actions.two_stage_fallback import TwoStageFallbackAction
99
- from rasa.dialogue_understanding.patterns.correction import ActionCorrectFlowSlot
100
- from rasa.dialogue_understanding.patterns.cancel import ActionCancelFlow
101
- from rasa.dialogue_understanding.patterns.clarify import ActionClarifyFlows
110
+ from rasa.core.actions.action_clean_stack import ActionCleanStack
102
111
  from rasa.core.actions.action_run_slot_rejections import ActionRunSlotRejections
103
112
  from rasa.core.actions.action_trigger_chitchat import ActionTriggerChitchat
104
113
  from rasa.core.actions.action_trigger_search import ActionTriggerSearch
105
- from rasa.core.actions.action_clean_stack import ActionCleanStack
114
+ from rasa.core.actions.two_stage_fallback import TwoStageFallbackAction
115
+ from rasa.dialogue_understanding.patterns.cancel import ActionCancelFlow
116
+ from rasa.dialogue_understanding.patterns.clarify import ActionClarifyFlows
117
+ from rasa.dialogue_understanding.patterns.correction import ActionCorrectFlowSlot
106
118
 
107
119
  return [
108
120
  ActionListen(),
@@ -130,7 +142,9 @@ def default_actions(action_endpoint: Optional[EndpointConfig] = None) -> List["A
130
142
 
131
143
 
132
144
  def action_for_index(
133
- index: int, domain: Domain, action_endpoint: Optional[EndpointConfig]
145
+ index: int,
146
+ domain: Domain,
147
+ action_endpoint: Optional[EndpointConfig],
134
148
  ) -> "Action":
135
149
  """Get an action based on its index in the list of available actions.
136
150
 
@@ -153,7 +167,9 @@ def action_for_index(
153
167
  )
154
168
 
155
169
  return action_for_name_or_text(
156
- domain.action_names_or_texts[index], domain, action_endpoint
170
+ domain.action_names_or_texts[index],
171
+ domain,
172
+ action_endpoint,
157
173
  )
158
174
 
159
175
 
@@ -177,7 +193,9 @@ def is_retrieval_action(action_name: Text, retrieval_intents: List[Text]) -> boo
177
193
 
178
194
 
179
195
  def action_for_name_or_text(
180
- action_name_or_text: Text, domain: Domain, action_endpoint: Optional[EndpointConfig]
196
+ action_name_or_text: Text,
197
+ domain: Domain,
198
+ action_endpoint: Optional[EndpointConfig],
181
199
  ) -> "Action":
182
200
  """Retrieves an action by its name or by its text in case it's an end-to-end action.
183
201
 
@@ -347,8 +365,11 @@ class ActionBotResponse(Action):
347
365
  )
348
366
  )
349
367
  return []
350
- message["utter_action"] = self.utter_action
351
368
 
369
+ message.update(metadata or {})
370
+ message = add_bot_utterance_metadata(
371
+ message, self.utter_action, nlg, domain, tracker
372
+ )
352
373
  return [create_bot_utterance(message)]
353
374
 
354
375
  def name(self) -> Text:
@@ -702,12 +723,15 @@ class ActionDeactivateLoop(Action):
702
723
 
703
724
  class RemoteAction(Action):
704
725
  def __init__(
705
- self, name: Text, action_endpoint: Optional[EndpointConfig] = None
726
+ self,
727
+ name: Text,
728
+ action_endpoint: Optional[EndpointConfig] = None,
706
729
  ) -> None:
707
730
  self._name = name
708
731
  self.action_endpoint = action_endpoint
709
732
  self.executor = self._create_executor()
710
733
 
734
+ @lru_cache(maxsize=1)
711
735
  def _create_executor(self) -> CustomActionExecutor:
712
736
  """Creates an executor based on the action endpoint configuration.
713
737
 
@@ -717,10 +741,22 @@ class RemoteAction(Action):
717
741
  Raises:
718
742
  RasaException: If no valid action endpoint is configured.
719
743
  """
720
-
721
744
  if not self.action_endpoint:
722
745
  return NoEndpointCustomActionExecutor(self.name())
723
746
 
747
+ if self.action_endpoint.kwargs.get(KEY_STUB_CUSTOM_ACTIONS):
748
+ return E2EStubCustomActionExecutor(self.name(), self.action_endpoint)
749
+
750
+ if self.action_endpoint.url and self.action_endpoint.actions_module:
751
+ raise_warning(
752
+ "Both 'actions_module' and 'url' are defined. "
753
+ "As they are mutually exclusive and 'actions_module' "
754
+ "is prioritized, actions will be executed by the assistant."
755
+ )
756
+
757
+ if self.action_endpoint and self.action_endpoint.actions_module:
758
+ return DirectCustomActionExecutor(self.name(), self.action_endpoint)
759
+
724
760
  url_schema = get_url_schema(self.action_endpoint.url)
725
761
 
726
762
  if url_schema == UrlSchema.GRPC:
@@ -760,8 +796,7 @@ class RemoteAction(Action):
760
796
  return schema
761
797
 
762
798
  def _validate_action_result(self, result: Dict[Text, Any]) -> bool:
763
- from jsonschema import validate
764
- from jsonschema import ValidationError
799
+ from jsonschema import ValidationError, validate
765
800
 
766
801
  try:
767
802
  validate(result, self.action_response_format_spec())
@@ -781,20 +816,25 @@ class RemoteAction(Action):
781
816
  output_channel: "OutputChannel",
782
817
  nlg: "NaturalLanguageGenerator",
783
818
  tracker: "DialogueStateTracker",
819
+ **kwargs: Any,
784
820
  ) -> List[BotUttered]:
785
821
  """Use the responses generated by the action endpoint and utter them."""
786
822
  bot_messages = []
823
+ domain: Domain = kwargs.get("domain", None)
824
+ action_name: str = kwargs.get("action_name", None)
787
825
  for response in responses:
788
826
  generated_response = response.pop("response", None)
789
- if generated_response:
827
+ if generated_response is not None:
790
828
  draft = await nlg.generate(
791
829
  generated_response, tracker, output_channel.name(), **response
792
830
  )
793
831
  if not draft:
794
832
  continue
795
- draft["utter_action"] = generated_response
833
+ draft = add_bot_utterance_metadata(
834
+ draft, generated_response, nlg, domain, tracker
835
+ )
796
836
  else:
797
- draft = {}
837
+ draft = {UTTER_SOURCE_METADATA_KEY: action_name}
798
838
 
799
839
  buttons = response.pop("buttons", []) or []
800
840
  if buttons:
@@ -817,13 +857,21 @@ class RemoteAction(Action):
817
857
  metadata: Optional[Dict[Text, Any]] = None,
818
858
  ) -> List[Event]:
819
859
  """Runs action. Please see parent class for the full docstring."""
820
- response = await self.executor.run(tracker=tracker, domain=domain)
860
+ response = await self.executor.run(
861
+ domain=domain,
862
+ tracker=tracker,
863
+ )
821
864
  self._validate_action_result(response)
822
865
 
823
866
  events_json = response.get("events", [])
824
867
  responses = response.get("responses", [])
825
868
  bot_messages = await self._utter_responses(
826
- responses, output_channel, nlg, tracker
869
+ responses,
870
+ output_channel,
871
+ nlg,
872
+ tracker,
873
+ domain=domain,
874
+ action_name=self.name(),
827
875
  )
828
876
 
829
877
  events = rasa.shared.core.events.deserialise_events(events_json)
@@ -1029,7 +1077,8 @@ class ActionSendText(Action):
1029
1077
  ) -> List[Event]:
1030
1078
  """Runs action. Please see parent class for the full docstring."""
1031
1079
  fallback = {"text": ""}
1032
- message = metadata.get("message", fallback) if metadata else fallback
1080
+ metadata_copy = copy.deepcopy(metadata) if metadata else {}
1081
+ message = metadata_copy.get("message", fallback)
1033
1082
  return [create_bot_utterance(message)]
1034
1083
 
1035
1084
 
@@ -5,6 +5,7 @@ from jinja2 import Template
5
5
  from pypred import Predicate
6
6
 
7
7
  from rasa.core.actions.action import Action, create_bot_utterance
8
+ from rasa.core.utils import add_bot_utterance_metadata
8
9
  from rasa.dialogue_understanding.patterns.collect_information import (
9
10
  CollectInformationPatternFlowStackFrame,
10
11
  )
@@ -201,7 +202,9 @@ class ActionRunSlotRejections(Action):
201
202
  utterance=utterance,
202
203
  )
203
204
  else:
204
- message["utter_action"] = utterance
205
+ message = add_bot_utterance_metadata(
206
+ message, utterance, nlg, domain, tracker
207
+ )
205
208
  events.append(create_bot_utterance(message))
206
209
 
207
210
  return events
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import abc
2
4
  import logging
3
5
  from typing import TYPE_CHECKING, Any, Dict, Text
@@ -36,7 +38,7 @@ class CustomActionExecutor(abc.ABC):
36
38
  Args:
37
39
  tracker: The current state of the dialogue.
38
40
  domain: The domain object containing domain-specific information.
39
- include_domain: If True, the domain information is included in the request.
41
+ include_domain: If True, the domain is included in the request.
40
42
 
41
43
  Returns:
42
44
  The response from the execution of the custom action.
@@ -71,8 +73,7 @@ class NoEndpointCustomActionExecutor(CustomActionExecutor):
71
73
  Args:
72
74
  tracker: The current state of the dialogue.
73
75
  domain: The domain object containing domain-specific information.
74
- include_domain: If True, the domain information
75
- is included in the request.
76
+ include_domain: If True, the domain is included in the request.
76
77
 
77
78
  Returns:
78
79
  The response from the execution of the custom action.
@@ -123,7 +124,7 @@ class CustomActionRequestWriter:
123
124
  Args:
124
125
  tracker: The current state of the dialogue.
125
126
  domain: The domain object containing domain-specific information.
126
- include_domain: If True, the domain information is included in the request.
127
+ include_domain: If True, the domain is included in the request.
127
128
 
128
129
  Returns:
129
130
  A JSON payload to be sent to the action server.
@@ -173,14 +174,16 @@ class RetryCustomActionExecutor(CustomActionExecutor):
173
174
  Args:
174
175
  tracker: The current state of the dialogue.
175
176
  domain: The domain object containing domain-specific information.
176
- include_domain: If True, the domain information is included in the request
177
+ include_domain: If True, the domain is included in the request.
177
178
 
178
179
  Returns:
179
180
  The response from the execution of the custom action.
180
181
  """
181
182
  try:
182
183
  return await self._custom_action_executor.run(
183
- tracker, domain, include_domain=include_domain
184
+ tracker,
185
+ domain,
186
+ include_domain=include_domain,
184
187
  )
185
188
  except DomainNotFound:
186
189
  return await self._custom_action_executor.run(
@@ -0,0 +1,80 @@
1
+ from importlib.util import find_spec
2
+ from typing import (
3
+ Any,
4
+ Dict,
5
+ Text,
6
+ )
7
+
8
+ import structlog
9
+ from rasa_sdk.executor import ActionExecutor
10
+
11
+ import rasa
12
+ from rasa.core.actions.custom_action_executor import (
13
+ CustomActionExecutor,
14
+ )
15
+ from rasa.shared.core.domain import Domain
16
+ from rasa.shared.core.trackers import DialogueStateTracker, EventVerbosity
17
+ from rasa.shared.exceptions import RasaException
18
+ from rasa.utils.endpoints import EndpointConfig
19
+
20
+ structlogger = structlog.get_logger(__name__)
21
+
22
+
23
+ class DirectCustomActionExecutor(CustomActionExecutor):
24
+ def __init__(self, action_name: str, action_endpoint: EndpointConfig):
25
+ """Initializes the direct custom action executor.
26
+
27
+ Args:
28
+ action_name: Name of the custom action.
29
+ action_endpoint: The endpoint to execute custom actions.
30
+ """
31
+ self.action_name = action_name
32
+ self.action_endpoint = action_endpoint
33
+ self.action_executor = ActionExecutor()
34
+
35
+ def register_actions_from_a_module(self) -> None:
36
+ module_name = self.action_endpoint.actions_module
37
+ if not find_spec(module_name):
38
+ raise RasaException(
39
+ f"You've provided the custom actions module '{module_name}' "
40
+ f"to run directly by the rasa server, however this module does "
41
+ f"not exist. Please check for typos in your `endpoints.yml` file."
42
+ )
43
+
44
+ self.action_executor.register_package(module_name)
45
+
46
+ async def run(
47
+ self,
48
+ tracker: "DialogueStateTracker",
49
+ domain: "Domain",
50
+ include_domain: bool = False,
51
+ ) -> Dict[Text, Any]:
52
+ """Executes the custom action directly.
53
+
54
+ Args:
55
+ tracker: The current state of the dialogue.
56
+ domain: The domain object containing domain-specific information.
57
+ include_domain: If True, the domain is included in the request.
58
+
59
+ Returns:
60
+ The response from the execution of the custom action.
61
+ """
62
+ structlogger.debug(
63
+ "action.direct_custom_action_executor.run",
64
+ action_name=self.action_name,
65
+ )
66
+ self.register_actions_from_a_module()
67
+
68
+ tracker_state = tracker.current_state(EventVerbosity.ALL)
69
+ action_call = {
70
+ "next_action": self.action_name,
71
+ "sender_id": tracker.sender_id,
72
+ "tracker": tracker_state,
73
+ "version": rasa.__version__,
74
+ }
75
+
76
+ if domain:
77
+ action_call["domain"] = domain.as_dict()
78
+
79
+ result = await self.action_executor.run(action_call)
80
+ return result.model_dump() if result else {}
@@ -0,0 +1,68 @@
1
+ import typing
2
+ from typing import (
3
+ Any,
4
+ Dict,
5
+ Text,
6
+ )
7
+
8
+ import structlog
9
+
10
+ from rasa.core.actions.custom_action_executor import (
11
+ CustomActionExecutor,
12
+ )
13
+ from rasa.shared.core.domain import Domain
14
+ from rasa.shared.core.trackers import DialogueStateTracker
15
+ from rasa.shared.exceptions import RasaException
16
+ from rasa.utils.endpoints import EndpointConfig
17
+
18
+ if typing.TYPE_CHECKING:
19
+ from rasa.e2e_test.stub_custom_action import StubCustomAction
20
+
21
+ structlogger = structlog.get_logger(__name__)
22
+
23
+
24
+ class E2EStubCustomActionExecutor(CustomActionExecutor):
25
+ def __init__(
26
+ self,
27
+ action_name: str,
28
+ action_endpoint: EndpointConfig,
29
+ ):
30
+ """Initializes the e2e stub custom action executor.
31
+
32
+ Args:
33
+ action_name: Name of the custom action.
34
+ action_endpoint: The endpoint to execute custom actions.
35
+ """
36
+ self.action_name = action_name
37
+ self.action_endpoint = action_endpoint
38
+ self.stub_custom_action = self.get_stub_custom_action()
39
+
40
+ def get_stub_custom_action(self) -> "StubCustomAction":
41
+ from rasa.e2e_test.stub_custom_action import get_stub_custom_action
42
+
43
+ stub_custom_action = get_stub_custom_action(
44
+ self.action_endpoint, self.action_name
45
+ )
46
+
47
+ if stub_custom_action:
48
+ return stub_custom_action
49
+
50
+ # TODO Update message below with reference to the docs
51
+ raise RasaException(
52
+ f"You are using custom action stubs, however action `{self.action_name}` "
53
+ f"has not been stubbed. Note that you cannot stub some custom actions "
54
+ f"while running an action server instance, you must stub all custom "
55
+ f"actions called by the tests in the provided test path."
56
+ )
57
+
58
+ async def run(
59
+ self,
60
+ tracker: "DialogueStateTracker",
61
+ domain: "Domain",
62
+ include_domain: bool = False,
63
+ ) -> Dict[Text, Any]:
64
+ structlogger.debug(
65
+ "action.e2e_stub_custom_action_executor.run",
66
+ action_name=self.action_name,
67
+ )
68
+ return self.stub_custom_action.as_dict()
@@ -97,7 +97,7 @@ class GRPCCustomActionExecutor(CustomActionExecutor):
97
97
  Args:
98
98
  tracker: Tracker for the current conversation.
99
99
  domain: Domain of the assistant.
100
- include_domain: If True, the domain information is included in the request.
100
+ include_domain: If True, the domain is included in the request.
101
101
 
102
102
  Returns:
103
103
  Response from the action server.
@@ -184,7 +184,7 @@ class GRPCCustomActionExecutor(CustomActionExecutor):
184
184
  Args:
185
185
  tracker: Tracker for the current conversation.
186
186
  domain: Domain of the assistant.
187
- include_domain: If True, the domain information is included in the request.
187
+ include_domain: If True, the domain is included in the request.
188
188
 
189
189
  Returns:
190
190
  gRPC payload for the action server.
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  import logging
3
- from typing import TYPE_CHECKING, Any, Dict
3
+ from typing import Any, Dict, Optional, TYPE_CHECKING
4
4
 
5
5
  import aiohttp
6
6
 
@@ -14,14 +14,16 @@ from rasa.core.constants import (
14
14
  DEFAULT_COMPRESS_ACTION_SERVER_REQUEST,
15
15
  DEFAULT_REQUEST_TIMEOUT,
16
16
  )
17
+ from rasa.shared.core.domain import Domain
18
+ from rasa.shared.core.trackers import DialogueStateTracker
17
19
  from rasa.shared.exceptions import RasaException
18
20
  from rasa.utils.common import get_bool_env_variable
19
- from rasa.utils.endpoints import ClientResponseError, EndpointConfig
20
21
 
21
22
  if TYPE_CHECKING:
22
23
  from rasa.shared.core.domain import Domain
23
24
  from rasa.shared.core.trackers import DialogueStateTracker
24
25
 
26
+ from rasa.utils.endpoints import ClientResponseError, EndpointConfig
25
27
 
26
28
  logger = logging.getLogger(__name__)
27
29
 
@@ -48,7 +50,7 @@ class HTTPCustomActionExecutor(CustomActionExecutor):
48
50
  async def run(
49
51
  self,
50
52
  tracker: "DialogueStateTracker",
51
- domain: "Domain",
53
+ domain: Optional["Domain"] = None,
52
54
  include_domain: bool = False,
53
55
  ) -> Dict[str, Any]:
54
56
  """Execute the custom action using an HTTP POST request.
@@ -56,8 +58,7 @@ class HTTPCustomActionExecutor(CustomActionExecutor):
56
58
  Args:
57
59
  tracker: The current state of the dialogue.
58
60
  domain: The domain object containing domain-specific information.
59
- include_domain: If `True`, the domain information
60
- is included in the request.
61
+ include_domain: If True, the domain is included in the request.
61
62
 
62
63
  Returns:
63
64
  A dictionary containing the response from the custom action endpoint.