rasa-pro 3.9.18__py3-none-any.whl → 3.10.16__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 (183) hide show
  1. README.md +0 -374
  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 +27 -23
  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 +11 -3
  10. rasa/cli/data.py +70 -8
  11. rasa/cli/e2e_test.py +104 -431
  12. rasa/cli/evaluate.py +1 -1
  13. rasa/cli/interactive.py +1 -0
  14. rasa/cli/llm_fine_tuning.py +398 -0
  15. rasa/cli/project_templates/calm/endpoints.yml +1 -1
  16. rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
  17. rasa/cli/run.py +15 -14
  18. rasa/cli/scaffold.py +10 -8
  19. rasa/cli/studio/studio.py +35 -5
  20. rasa/cli/train.py +56 -8
  21. rasa/cli/utils.py +22 -5
  22. rasa/cli/x.py +1 -1
  23. rasa/constants.py +7 -1
  24. rasa/core/actions/action.py +98 -49
  25. rasa/core/actions/action_run_slot_rejections.py +4 -1
  26. rasa/core/actions/custom_action_executor.py +9 -6
  27. rasa/core/actions/direct_custom_actions_executor.py +80 -0
  28. rasa/core/actions/e2e_stub_custom_action_executor.py +68 -0
  29. rasa/core/actions/grpc_custom_action_executor.py +2 -2
  30. rasa/core/actions/http_custom_action_executor.py +6 -5
  31. rasa/core/agent.py +21 -17
  32. rasa/core/channels/__init__.py +2 -0
  33. rasa/core/channels/audiocodes.py +1 -16
  34. rasa/core/channels/voice_aware/__init__.py +0 -0
  35. rasa/core/channels/voice_aware/jambonz.py +103 -0
  36. rasa/core/channels/voice_aware/jambonz_protocol.py +344 -0
  37. rasa/core/channels/voice_aware/utils.py +20 -0
  38. rasa/core/channels/voice_native/__init__.py +0 -0
  39. rasa/core/constants.py +6 -1
  40. rasa/core/information_retrieval/faiss.py +7 -4
  41. rasa/core/information_retrieval/information_retrieval.py +8 -0
  42. rasa/core/information_retrieval/milvus.py +9 -2
  43. rasa/core/information_retrieval/qdrant.py +1 -1
  44. rasa/core/nlg/contextual_response_rephraser.py +32 -10
  45. rasa/core/nlg/summarize.py +4 -3
  46. rasa/core/policies/enterprise_search_policy.py +113 -45
  47. rasa/core/policies/flows/flow_executor.py +122 -76
  48. rasa/core/policies/intentless_policy.py +83 -29
  49. rasa/core/processor.py +72 -54
  50. rasa/core/run.py +5 -4
  51. rasa/core/tracker_store.py +8 -4
  52. rasa/core/training/interactive.py +1 -1
  53. rasa/core/utils.py +56 -57
  54. rasa/dialogue_understanding/coexistence/llm_based_router.py +53 -13
  55. rasa/dialogue_understanding/commands/__init__.py +6 -0
  56. rasa/dialogue_understanding/commands/restart_command.py +58 -0
  57. rasa/dialogue_understanding/commands/session_start_command.py +59 -0
  58. rasa/dialogue_understanding/commands/utils.py +40 -0
  59. rasa/dialogue_understanding/generator/constants.py +10 -3
  60. rasa/dialogue_understanding/generator/flow_retrieval.py +21 -5
  61. rasa/dialogue_understanding/generator/llm_based_command_generator.py +13 -3
  62. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +134 -90
  63. rasa/dialogue_understanding/generator/nlu_command_adapter.py +47 -7
  64. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +127 -41
  65. rasa/dialogue_understanding/patterns/restart.py +37 -0
  66. rasa/dialogue_understanding/patterns/session_start.py +37 -0
  67. rasa/dialogue_understanding/processor/command_processor.py +16 -3
  68. rasa/dialogue_understanding/processor/command_processor_component.py +6 -2
  69. rasa/e2e_test/aggregate_test_stats_calculator.py +134 -0
  70. rasa/e2e_test/assertions.py +1223 -0
  71. rasa/e2e_test/assertions_schema.yml +106 -0
  72. rasa/e2e_test/constants.py +20 -0
  73. rasa/e2e_test/e2e_config.py +220 -0
  74. rasa/e2e_test/e2e_config_schema.yml +26 -0
  75. rasa/e2e_test/e2e_test_case.py +131 -8
  76. rasa/e2e_test/e2e_test_converter.py +363 -0
  77. rasa/e2e_test/e2e_test_converter_prompt.jinja2 +70 -0
  78. rasa/e2e_test/e2e_test_coverage_report.py +364 -0
  79. rasa/e2e_test/e2e_test_result.py +26 -6
  80. rasa/e2e_test/e2e_test_runner.py +493 -71
  81. rasa/e2e_test/e2e_test_schema.yml +96 -0
  82. rasa/e2e_test/pykwalify_extensions.py +39 -0
  83. rasa/e2e_test/stub_custom_action.py +70 -0
  84. rasa/e2e_test/utils/__init__.py +0 -0
  85. rasa/e2e_test/utils/e2e_yaml_utils.py +55 -0
  86. rasa/e2e_test/utils/io.py +598 -0
  87. rasa/e2e_test/utils/validation.py +80 -0
  88. rasa/engine/graph.py +9 -3
  89. rasa/engine/recipes/default_components.py +0 -2
  90. rasa/engine/recipes/default_recipe.py +10 -2
  91. rasa/engine/storage/local_model_storage.py +40 -12
  92. rasa/engine/validation.py +78 -1
  93. rasa/env.py +9 -0
  94. rasa/graph_components/providers/story_graph_provider.py +59 -6
  95. rasa/llm_fine_tuning/__init__.py +0 -0
  96. rasa/llm_fine_tuning/annotation_module.py +241 -0
  97. rasa/llm_fine_tuning/conversations.py +144 -0
  98. rasa/llm_fine_tuning/llm_data_preparation_module.py +178 -0
  99. rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +407 -0
  100. rasa/llm_fine_tuning/paraphrasing/__init__.py +0 -0
  101. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +281 -0
  102. rasa/llm_fine_tuning/paraphrasing/default_rephrase_prompt_template.jina2 +44 -0
  103. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +121 -0
  104. rasa/llm_fine_tuning/paraphrasing/rephrased_user_message.py +10 -0
  105. rasa/llm_fine_tuning/paraphrasing_module.py +128 -0
  106. rasa/llm_fine_tuning/storage.py +174 -0
  107. rasa/llm_fine_tuning/train_test_split_module.py +441 -0
  108. rasa/model_training.py +56 -16
  109. rasa/nlu/persistor.py +157 -36
  110. rasa/server.py +45 -10
  111. rasa/shared/constants.py +76 -16
  112. rasa/shared/core/domain.py +27 -19
  113. rasa/shared/core/events.py +28 -2
  114. rasa/shared/core/flows/flow.py +208 -13
  115. rasa/shared/core/flows/flow_path.py +84 -0
  116. rasa/shared/core/flows/flows_list.py +33 -11
  117. rasa/shared/core/flows/flows_yaml_schema.json +269 -193
  118. rasa/shared/core/flows/validation.py +112 -25
  119. rasa/shared/core/flows/yaml_flows_io.py +149 -10
  120. rasa/shared/core/trackers.py +6 -0
  121. rasa/shared/core/training_data/structures.py +20 -0
  122. rasa/shared/core/training_data/visualization.html +2 -2
  123. rasa/shared/exceptions.py +4 -0
  124. rasa/shared/importers/importer.py +64 -16
  125. rasa/shared/nlu/constants.py +2 -0
  126. rasa/shared/providers/_configs/__init__.py +0 -0
  127. rasa/shared/providers/_configs/azure_openai_client_config.py +183 -0
  128. rasa/shared/providers/_configs/client_config.py +57 -0
  129. rasa/shared/providers/_configs/default_litellm_client_config.py +130 -0
  130. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +234 -0
  131. rasa/shared/providers/_configs/openai_client_config.py +175 -0
  132. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +176 -0
  133. rasa/shared/providers/_configs/utils.py +101 -0
  134. rasa/shared/providers/_ssl_verification_utils.py +124 -0
  135. rasa/shared/providers/embedding/__init__.py +0 -0
  136. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +259 -0
  137. rasa/shared/providers/embedding/_langchain_embedding_client_adapter.py +74 -0
  138. rasa/shared/providers/embedding/azure_openai_embedding_client.py +277 -0
  139. rasa/shared/providers/embedding/default_litellm_embedding_client.py +102 -0
  140. rasa/shared/providers/embedding/embedding_client.py +90 -0
  141. rasa/shared/providers/embedding/embedding_response.py +41 -0
  142. rasa/shared/providers/embedding/huggingface_local_embedding_client.py +191 -0
  143. rasa/shared/providers/embedding/openai_embedding_client.py +172 -0
  144. rasa/shared/providers/llm/__init__.py +0 -0
  145. rasa/shared/providers/llm/_base_litellm_client.py +251 -0
  146. rasa/shared/providers/llm/azure_openai_llm_client.py +338 -0
  147. rasa/shared/providers/llm/default_litellm_llm_client.py +84 -0
  148. rasa/shared/providers/llm/llm_client.py +76 -0
  149. rasa/shared/providers/llm/llm_response.py +50 -0
  150. rasa/shared/providers/llm/openai_llm_client.py +155 -0
  151. rasa/shared/providers/llm/self_hosted_llm_client.py +293 -0
  152. rasa/shared/providers/mappings.py +75 -0
  153. rasa/shared/utils/cli.py +30 -0
  154. rasa/shared/utils/io.py +65 -2
  155. rasa/shared/utils/llm.py +246 -200
  156. rasa/shared/utils/yaml.py +121 -15
  157. rasa/studio/auth.py +6 -4
  158. rasa/studio/config.py +13 -4
  159. rasa/studio/constants.py +1 -0
  160. rasa/studio/data_handler.py +10 -3
  161. rasa/studio/download.py +19 -13
  162. rasa/studio/train.py +2 -3
  163. rasa/studio/upload.py +19 -11
  164. rasa/telemetry.py +113 -58
  165. rasa/tracing/instrumentation/attribute_extractors.py +32 -17
  166. rasa/utils/common.py +18 -19
  167. rasa/utils/endpoints.py +7 -4
  168. rasa/utils/json_utils.py +60 -0
  169. rasa/utils/licensing.py +9 -1
  170. rasa/utils/ml_utils.py +4 -2
  171. rasa/validator.py +213 -3
  172. rasa/version.py +1 -1
  173. rasa_pro-3.10.16.dist-info/METADATA +196 -0
  174. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/RECORD +179 -113
  175. rasa/nlu/classifiers/llm_intent_classifier.py +0 -519
  176. rasa/shared/providers/openai/clients.py +0 -43
  177. rasa/shared/providers/openai/session_handler.py +0 -110
  178. rasa_pro-3.9.18.dist-info/METADATA +0 -563
  179. /rasa/{shared/providers/openai → cli/project_templates/tutorial/actions}/__init__.py +0 -0
  180. /rasa/cli/project_templates/tutorial/{actions.py → actions/actions.py} +0 -0
  181. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/NOTICE +0 -0
  182. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/WHEEL +0 -0
  183. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/entry_points.txt +0 -0
rasa/cli/e2e_test.py CHANGED
@@ -1,50 +1,62 @@
1
1
  import argparse
2
2
  import asyncio
3
- import logging
4
- import math
5
- import shutil
6
3
  import sys
7
4
  from pathlib import Path
8
- from textwrap import dedent
9
- from typing import Any, Dict, Generator, List, Optional, Text, Tuple, Union
5
+ from typing import List
6
+
7
+ import structlog
10
8
 
11
9
  import rasa.cli.arguments.run
12
10
  import rasa.cli.utils
13
11
  import rasa.shared.data
14
12
  import rasa.shared.utils.cli
15
13
  import rasa.shared.utils.io
16
- import rich
14
+ import rasa.utils.io
17
15
  from rasa.cli import SubParsersAction
18
- from rasa.cli.arguments.default_arguments import add_endpoint_param, add_model_param
16
+ from rasa.cli.arguments.default_arguments import (
17
+ add_endpoint_param,
18
+ add_model_param,
19
+ add_remote_storage_param,
20
+ )
19
21
  from rasa.core.exceptions import AgentNotReady
20
22
  from rasa.core.utils import AvailableEndpoints
21
- from rasa.exceptions import RasaException
22
- from rasa.shared.constants import DEFAULT_ENDPOINTS_PATH, DEFAULT_MODELS_PATH
23
-
24
- from rasa.e2e_test.constants import SCHEMA_FILE_PATH, KEY_TEST_CASE
23
+ from rasa.e2e_test.aggregate_test_stats_calculator import (
24
+ AggregateTestStatsCalculator,
25
+ )
26
+ from rasa.e2e_test.constants import (
27
+ DEFAULT_COVERAGE_OUTPUT_PATH,
28
+ DEFAULT_E2E_INPUT_TESTS_PATH,
29
+ DEFAULT_E2E_OUTPUT_TESTS_PATH,
30
+ STATUS_FAILED,
31
+ STATUS_PASSED,
32
+ )
25
33
  from rasa.e2e_test.e2e_test_case import (
26
- KEY_FIXTURES,
27
- KEY_METADATA,
28
- Fixture,
29
- Metadata,
30
- TestCase,
31
- TestSuite,
34
+ KEY_STUB_CUSTOM_ACTIONS,
35
+ )
36
+ from rasa.e2e_test.e2e_test_coverage_report import (
37
+ create_coverage_report,
38
+ extract_tested_commands,
32
39
  )
33
- from rasa.e2e_test.e2e_test_result import TestResult
34
40
  from rasa.e2e_test.e2e_test_runner import E2ETestRunner
35
- import rasa.utils.io
36
- from rasa.shared.utils.yaml import (
37
- parse_raw_yaml,
38
- read_schema_file,
39
- validate_yaml_content_using_schema,
40
- is_key_in_yaml,
41
+ from rasa.e2e_test.utils.io import (
42
+ _save_coverage_report,
43
+ _save_tested_commands_histogram,
44
+ extract_test_case_from_path,
45
+ print_test_result,
46
+ read_test_cases,
47
+ save_test_cases_to_yaml,
48
+ split_into_passed_failed,
49
+ write_test_results_to_file,
41
50
  )
51
+ from rasa.e2e_test.utils.validation import validate_model_path
52
+ from rasa.exceptions import RasaException
53
+ from rasa.shared.constants import DEFAULT_ENDPOINTS_PATH, DEFAULT_MODELS_PATH
54
+ from rasa.utils.beta import ensure_beta_feature_is_enabled
55
+ from rasa.utils.endpoints import EndpointConfig
42
56
 
43
- DEFAULT_E2E_INPUT_TESTS_PATH = "tests/e2e_test_cases.yml"
44
- DEFAULT_E2E_OUTPUT_TESTS_PATH = "tests/e2e_results.yml"
45
- KEY_TEST_CASES = "test_cases"
57
+ RASA_PRO_BETA_FINE_TUNING_RECIPE_ENV_VAR_NAME = "RASA_PRO_BETA_FINE_TUNING_RECIPE"
46
58
 
47
- logger = logging.getLogger(__name__)
59
+ structlogger = structlog.get_logger()
48
60
 
49
61
 
50
62
  def add_subparser(
@@ -121,154 +133,38 @@ def add_e2e_test_arguments(parser: argparse.ArgumentParser) -> None:
121
133
  help="Results file containing end-to-end testing summary.",
122
134
  )
123
135
 
136
+ add_remote_storage_param(parser)
137
+
124
138
  parser.add_argument(
125
- "--remote-storage",
126
- help="Set the remote location where your Rasa model is stored, e.g. on AWS.",
139
+ "--coverage-report",
140
+ action="store_true",
141
+ help="Generate a coverage report on flow paths and commands covered in e2e "
142
+ "tests.",
127
143
  )
128
144
 
129
-
130
- def split_into_passed_failed(
131
- results: List[TestResult],
132
- ) -> Tuple[List[TestResult], List[TestResult]]:
133
- """Get the summary of the test results.
134
-
135
- Args:
136
- results: List of test results.
137
-
138
- Returns:
139
- Tuple consisting of passed count, failed count and failed test cases.
140
- """
141
- passed_cases = [r for r in results if r.pass_status]
142
- failed_cases = [r for r in results if not r.pass_status]
143
-
144
- return passed_cases, failed_cases
145
-
146
-
147
- def is_test_case_file(file_path: Union[Text, Path]) -> bool:
148
- """Check if file contains test cases.
149
-
150
- Args:
151
- file_path: Path of the file to check.
152
-
153
- Returns:
154
- `True` if the file contains test cases, `False` otherwise.
155
- """
156
- return rasa.shared.data.is_likely_yaml_file(file_path) and is_key_in_yaml(
157
- file_path, KEY_TEST_CASES
145
+ parser.add_argument(
146
+ "--coverage-output-path",
147
+ default=DEFAULT_COVERAGE_OUTPUT_PATH,
148
+ help="Directory where to save coverage report to.",
158
149
  )
159
150
 
160
151
 
161
- def validate_path_to_test_cases(path: Text) -> None:
162
- """Validate that path to test cases exists."""
163
- if not Path(path).exists():
164
- rasa.shared.utils.io.raise_warning(
165
- f"Path to test cases does not exist: {path}. "
166
- f"Please provide a valid path to test cases. "
167
- f"Exiting...",
168
- UserWarning,
169
- )
170
- sys.exit(1)
171
-
172
-
173
- def extract_test_case_from_path(path: Text) -> Tuple[Text, Text]:
174
- """Extract test case from path if specified.
175
-
176
- Args:
177
- path: Path to the file or folder containing test cases.
178
-
179
- Returns:
180
- Tuple consisting of the path to test cases and the extracted test case name.
181
- """
182
- test_case_name = ""
183
-
184
- if "::" in str(path):
185
- splitted_path = path.split("::")
186
- test_case_name = splitted_path[-1]
187
- path = splitted_path[0]
188
-
189
- return path, test_case_name
190
-
191
-
192
- def validate_test_case(test_case_name: Text, input_test_cases: List[TestCase]) -> None:
193
- """Validate that test case exists."""
194
- if test_case_name and not input_test_cases:
195
- rasa.shared.utils.io.raise_warning(
196
- f"Test case does not exist: {test_case_name}. "
197
- f"Please check for typos and provide a valid test case name. "
198
- f"Exiting...",
199
- UserWarning,
200
- )
201
- sys.exit(1)
202
-
203
-
204
- def read_test_cases(path: Text) -> TestSuite:
205
- """Read test cases from the given path.
206
-
207
- Args:
208
- path: Path to the file or folder containing test cases.
209
-
210
- Returns:
211
- TestSuite.
212
- """
213
- path, test_case_name = extract_test_case_from_path(path)
214
- validate_path_to_test_cases(path)
215
-
216
- test_files = rasa.shared.data.get_data_files([path], is_test_case_file)
217
- e2e_test_schema = read_e2e_test_schema()
218
-
219
- input_test_cases = []
220
- fixtures: Dict[Text, Fixture] = {}
221
- metadata: Dict[Text, Metadata] = {}
222
-
223
- for test_file in test_files:
224
- test_file_content = parse_raw_yaml(Path(test_file).read_text())
225
- validate_yaml_content_using_schema(test_file_content, e2e_test_schema)
226
-
227
- test_cases_content = test_file_content.get(KEY_TEST_CASES) or []
228
-
229
- if test_case_name:
230
- test_cases = [
231
- TestCase.from_dict(test_case_dict, file=test_file)
232
- for test_case_dict in test_cases_content
233
- if test_case_name == test_case_dict.get(KEY_TEST_CASE)
234
- ]
235
- else:
236
- test_cases = [
237
- TestCase.from_dict(test_case_dict, file=test_file)
238
- for test_case_dict in test_cases_content
239
- ]
240
-
241
- input_test_cases.extend(test_cases)
242
- fixtures_content = test_file_content.get(KEY_FIXTURES) or []
243
- metadata_contents = test_file_content.get(KEY_METADATA) or []
244
- for fixture in fixtures_content:
245
- fixture_obj = Fixture.from_dict(fixture_dict=fixture)
246
-
247
- # avoid adding duplicates from across multiple files
248
- if fixtures.get(fixture_obj.name) is None:
249
- fixtures[fixture_obj.name] = fixture_obj
250
-
251
- for metadata_content in metadata_contents:
252
- metadata_obj = Metadata.from_dict(metadata_dict=metadata_content)
253
-
254
- # avoid adding duplicates from across multiple files
255
- if metadata.get(metadata_obj.name) is None:
256
- metadata[metadata_obj.name] = metadata_obj
257
-
258
- validate_test_case(test_case_name, input_test_cases)
259
- return TestSuite(input_test_cases, list(fixtures.values()), list(metadata.values()))
260
-
261
-
262
152
  def execute_e2e_tests(args: argparse.Namespace) -> None:
263
153
  """Run the end-to-end tests.
264
154
 
265
155
  Args:
266
156
  args: Commandline arguments.
267
157
  """
158
+ if args.coverage_report:
159
+ ensure_beta_feature_is_enabled(
160
+ "LLM fine-tuning recipe",
161
+ env_flag=RASA_PRO_BETA_FINE_TUNING_RECIPE_ENV_VAR_NAME,
162
+ )
163
+
268
164
  args.endpoints = rasa.cli.utils.get_validated_path(
269
165
  args.endpoints, "endpoints", DEFAULT_ENDPOINTS_PATH, True
270
166
  )
271
- endpoints = AvailableEndpoints.read_endpoints(args.endpoints)
167
+ endpoints = AvailableEndpoints.get_instance(args.endpoints)
272
168
 
273
169
  # Ignore all endpoints apart from action server, model, nlu and nlg
274
170
  # to ensure InMemoryTrackerStore is being used instead of production
@@ -286,15 +182,28 @@ def execute_e2e_tests(args: argparse.Namespace) -> None:
286
182
 
287
183
  test_suite = read_test_cases(path_to_test_cases)
288
184
 
185
+ if test_suite.stub_custom_actions:
186
+ if not endpoints.action:
187
+ endpoints.action = EndpointConfig()
188
+
189
+ endpoints.action.kwargs[KEY_STUB_CUSTOM_ACTIONS] = (
190
+ test_suite.stub_custom_actions
191
+ )
192
+
193
+ test_case_path, _ = extract_test_case_from_path(path_to_test_cases)
194
+
289
195
  try:
290
196
  test_runner = E2ETestRunner(
291
197
  remote_storage=args.remote_storage,
292
198
  model_path=args.model,
293
199
  model_server=endpoints.model,
294
200
  endpoints=endpoints,
201
+ test_case_path=Path(test_case_path),
295
202
  )
296
203
  except AgentNotReady as error:
297
- logger.error(msg=error.message)
204
+ structlogger.error(
205
+ "rasa.e2e_test.execute_e2e_tests.agent_not_ready", message=error.message
206
+ )
298
207
  sys.exit(1)
299
208
 
300
209
  results = asyncio.run(
@@ -303,284 +212,48 @@ def execute_e2e_tests(args: argparse.Namespace) -> None:
303
212
  test_suite.fixtures,
304
213
  args.fail_fast,
305
214
  input_metadata=test_suite.metadata,
215
+ coverage=args.coverage_report,
306
216
  )
307
217
  )
308
218
 
309
- if args.e2e_results is not None:
310
- write_test_results_to_file(results, args.e2e_results)
311
-
312
219
  passed, failed = split_into_passed_failed(results)
313
- print_test_result(passed, failed, args.fail_fast)
314
-
315
220
 
316
- def write_test_results_to_file(results: List[TestResult], output_file: Text) -> None:
317
- """Write test results to a file.
318
-
319
- Args:
320
- results: List of test results.
321
- output_file: Path to the output file.
322
- """
323
- Path(output_file).touch()
324
-
325
- data = {"test_results": [test_result.as_dict() for test_result in results]}
326
-
327
- rasa.utils.io.write_yaml(
328
- data, target=output_file, transform=transform_results_output_to_yaml
329
- )
330
-
331
- rasa.shared.utils.cli.print_info(
332
- f"Overall results have been saved at path: {output_file}."
333
- )
334
-
335
-
336
- def transform_results_output_to_yaml(yaml_string: Text) -> Text:
337
- """Transform the output of the YAML writer to make it more readable.
338
-
339
- Args:
340
- yaml_string: The YAML string to transform.
341
-
342
- Returns:
343
- The transformed YAML string.
344
- """
345
- result = []
346
- for s in yaml_string.splitlines(True):
347
- if s.startswith("- name"):
348
- result.append("\n")
349
- result.append(s)
350
- elif s.startswith("\n"):
351
- result.append(s.strip())
352
- else:
353
- result.append(s)
354
- return "".join(result)
355
-
356
-
357
- def pad(text: Text, char: Text = "=", min: int = 3) -> Text:
358
- """Pad text to a certain length.
359
-
360
- Uses `char` to pad the text to the specified length. If the text is longer
361
- than the specified length, at least `min` are used.
362
-
363
- The padding is applied to the left and right of the text (almost) equally.
364
-
365
- Example:
366
- >>> pad("Hello")
367
- "========= Hello ========"
368
- >>> pad("Hello", char="-")
369
- "--------- Hello --------"
370
-
371
- Args:
372
- text: Text to pad.
373
- min: Minimum length of the padding.
374
- char: Character to pad with.
375
-
376
- Returns:
377
- Padded text.
378
- """
379
- width = shutil.get_terminal_size((80, 20)).columns
380
- padding = max(width - len(text) - 2, min * 2)
381
-
382
- return char * (padding // 2) + " " + text + " " + char * math.ceil(padding / 2)
383
-
384
-
385
- def color_difference(diff: List[Text]) -> Generator[Text, None, None]:
386
- """Colorize the difference between two strings.
387
-
388
- Example:
389
- >>> color_difference(["+ Hello", "- World"])
390
- ["<ansigreen>+ Hello</ansigreen>", "<ansired>- World</ansired>"]
391
-
392
- Args:
393
- diff: List of lines of the diff.
394
-
395
- Returns:
396
- Generator of colored lines.
397
- """
398
- for line in diff:
399
- if line.startswith("+"):
400
- yield "[green3]" + line + "[/green3]"
401
- elif line.startswith("-"):
402
- yield "[red3]" + line + "[/red3]"
403
- elif line.startswith("^"):
404
- yield "[blue3]" + line + "[/blue3]"
405
- elif line.startswith("?"):
406
- yield "[grey37]" + line + "[/grey37]"
407
- else:
408
- yield line
409
-
410
-
411
- def print_failed_case(fail: TestResult) -> None:
412
- """Print the details of a failed test case.
413
-
414
- Example:
415
- >>> print_failed_case(TestResult(TestCase("test", "test.md"), 1,
416
- ... ["- Hello", "+ World"]))
417
- ---------------------- test in test.md failed ----------------------
418
- Mismatch starting at test.md:1:
419
- <ansired>- Hello</ansired>
420
- <ansigreen>+ World</ansigreen>
421
- """
422
- fail_headline = (
423
- f"'{fail.test_case.name}' in {fail.test_case.file_with_line()} failed"
424
- )
425
- rasa.shared.utils.cli.print_error(f"{pad(fail_headline, char='-')}\n")
426
- print(f"Mismatch starting at {fail.test_case.file}:{fail.error_line}: \n")
427
- rich.print(("\n".join(color_difference(fail.difference))))
428
-
429
-
430
- def print_test_summary(failed: List[TestResult]) -> None:
431
- """Print the summary of the test run.
432
-
433
- Example:
434
- >>> print_test_summary([TestResult(TestCase("test", "test.md"), 1,
435
- ... ["- Hello", "+ World"])])
436
- =================== short test summary info ===================
437
- FAILED test.md::test
438
- """
439
- rasa.shared.utils.cli.print_info(pad("short test summary info"))
440
-
441
- for f in failed:
442
- rasa.shared.utils.cli.print_error(
443
- f"FAILED {f.test_case.file}::{f.test_case.name}"
444
- )
445
-
446
-
447
- def print_final_line(
448
- passed: List[TestResult], failed: List[TestResult], has_failed: bool
449
- ) -> None:
450
- """Print the final line of the test output.
451
-
452
- Args:
453
- passed: List of passed test cases.
454
- failed: List of failed test cases.
455
- has_failed: Boolean, true if the test run has failed.
456
- """
457
- final_line_color = "green3" if not has_failed else "red3"
458
-
459
- width = shutil.get_terminal_size((80, 20)).columns
460
-
461
- # calculate the length of the text - this is a bit hacky but works
462
- text_lengt = (
463
- math.ceil(len(passed) / 10) # length of the number of passed tests
464
- + math.ceil(len(failed) / 10) # length of the number of failed tests
465
- + 18 # length of the text " failed, passed "
466
- )
467
- # we can't use the padding function here as the text contains html tags
468
- # which are not taken into account when calculating the length
469
- padding = max(6, width - text_lengt)
470
- pre_pad = "=" * max(3, padding // 2)
471
- post_pad = "=" * max(3, math.ceil(padding / 2))
472
- rich.print(
473
- f"[{final_line_color}]{pre_pad} "
474
- f"[bold red3]{len(failed)} failed[/bold red3]"
475
- f"[bright_white], [/bright_white]"
476
- f"[bold green3]{len(passed)} passed[/bold green3]"
477
- f" {post_pad}[/{final_line_color}]"
478
- )
479
-
480
-
481
- def print_test_result(
482
- passed: List[TestResult],
483
- failed: List[TestResult],
484
- fail_fast: bool = False,
485
- ) -> None:
486
- """Print the result of the test run.
221
+ if args.e2e_results is not None:
222
+ results_path = Path(args.e2e_results)
487
223
 
488
- Args:
489
- passed: List of passed test cases.
490
- failed: List of failed test cases.
491
- fail_fast: If true, stop after the first failure.
492
- """
493
- if failed:
494
- # print failure headline
495
- print("\n")
496
- rich.print(f"[bold]{pad('FAILURES', char='=')}[/bold]")
497
-
498
- # print failed test_Case
499
- for fail in failed:
500
- print_failed_case(fail)
501
-
502
- print_test_summary(failed)
503
-
504
- if fail_fast:
505
- rasa.shared.utils.cli.print_error(pad("stopping after 1 failure", char="!"))
506
- has_failed = True
507
- elif len(failed) + len(passed) == 0:
508
- # no tests were run, print error
509
- rasa.shared.utils.cli.print_error(pad("no test cases found", char="!"))
510
- print_e2e_help()
511
- has_failed = True
512
- elif failed:
513
- has_failed = True
514
- else:
515
- has_failed = False
516
-
517
- print_final_line(passed, failed, has_failed=has_failed)
518
- sys.exit(1 if has_failed else 0)
519
-
520
-
521
- def print_e2e_help() -> None:
522
- """Print help guiding users how to write e2e tests."""
523
- rasa.shared.utils.cli.print_info(
524
- dedent(
525
- """\
526
- To start using e2e tests create a yaml file in a test directory, e.g.
527
- 'tests/test_cases.yml'. You can find example test cases in the starter
528
- pack at
529
-
530
- https://github.com/RasaHQ/starter-pack-intentless-policy#testing-the-policy
531
-
532
- Here is an example of a test case in yaml format:
533
-
534
- test_cases:
535
- - test_case: "test_greet"
536
- steps:
537
- - user: "hello there!"
538
- - bot: "Hey! How are you?"
539
-
540
- To run the e2e tests, execute:
541
- >>> rasa test e2e <path-to-test-cases>
542
- """
224
+ passed_file = rasa.cli.utils.get_e2e_results_file_name(
225
+ results_path, STATUS_PASSED
543
226
  )
544
- )
545
-
227
+ write_test_results_to_file(passed, passed_file)
546
228
 
547
- def validate_model_path(
548
- model_path: Optional[Text], parameter: Text, default: Text
549
- ) -> Text:
550
- """Validate the model path.
551
-
552
- Args:
553
- model_path: Path to the model.
554
- parameter: Name of the parameter.
555
- default: Default path to the model.
556
-
557
- Returns:
558
- Path to the model.
559
- """
560
- if model_path and Path(model_path).exists():
561
- return model_path
562
-
563
- if model_path and not Path(model_path).exists():
564
- rasa.shared.utils.io.raise_warning(
565
- f"The provided model path '{model_path}' could not be found. "
566
- f"Using default location '{default}' instead.",
567
- UserWarning,
229
+ failed_file = rasa.cli.utils.get_e2e_results_file_name(
230
+ results_path, STATUS_FAILED
568
231
  )
232
+ write_test_results_to_file(failed, failed_file)
569
233
 
570
- elif model_path is None:
571
- logger.info(
572
- f"Parameter '{parameter}' is not set. "
573
- f"Using default location '{default}' instead."
234
+ aggregate_stats_calculator = AggregateTestStatsCalculator(
235
+ passed_results=passed, failed_results=failed, test_cases=test_suite.test_cases
236
+ )
237
+ accuracy_calculations = aggregate_stats_calculator.calculate()
238
+
239
+ if args.coverage_report and test_runner.agent.processor:
240
+ coverage_output_path = args.coverage_output_path
241
+ rasa.shared.utils.io.create_directory(coverage_output_path)
242
+ flows = asyncio.run(test_runner.agent.processor.get_flows())
243
+
244
+ for results, status in [(passed, STATUS_PASSED), (failed, STATUS_FAILED)]:
245
+ report = create_coverage_report(flows, results)
246
+ _save_coverage_report(report, status, coverage_output_path)
247
+ tested_commands = extract_tested_commands(results)
248
+ _save_tested_commands_histogram(
249
+ tested_commands, status, coverage_output_path
250
+ )
251
+ save_test_cases_to_yaml(results, coverage_output_path, status, test_suite)
252
+
253
+ rasa.shared.utils.cli.print_info(
254
+ f"Coverage data and result is written to {coverage_output_path}."
574
255
  )
575
256
 
576
- Path(default).mkdir(exist_ok=True)
577
- return default
578
-
579
-
580
- def read_e2e_test_schema() -> Union[List[Any], Dict[Text, Any]]:
581
- """Read the schema for the e2e test files.
582
-
583
- Returns:
584
- The content of the schema.
585
- """
586
- return read_schema_file(SCHEMA_FILE_PATH)
257
+ print_test_result(
258
+ passed, failed, args.fail_fast, accuracy_calculations=accuracy_calculations
259
+ )
rasa/cli/evaluate.py CHANGED
@@ -217,6 +217,6 @@ def _create_tracker_loader(
217
217
  A MarkerTrackerLoader object configured with the specified strategy against
218
218
  the configured tracker store.
219
219
  """
220
- endpoints = AvailableEndpoints.read_endpoints(endpoint_config)
220
+ endpoints = AvailableEndpoints.get_instance(endpoint_config)
221
221
  tracker_store = TrackerStore.create(endpoints.tracker_store, domain=domain)
222
222
  return MarkerTrackerLoader(tracker_store, strategy, count, seed)
rasa/cli/interactive.py CHANGED
@@ -108,6 +108,7 @@ def _set_not_required_args(args: argparse.Namespace) -> None:
108
108
  args.skip_validation = True
109
109
  args.fail_on_validation_warnings = False
110
110
  args.validation_max_history = None
111
+ args.remote_storage = None
111
112
 
112
113
 
113
114
  def perform_interactive_learning(