rasa-pro 3.12.0.dev1__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 (790) hide show
  1. README.md +41 -0
  2. rasa/__init__.py +9 -0
  3. rasa/__main__.py +177 -0
  4. rasa/anonymization/__init__.py +2 -0
  5. rasa/anonymization/anonymisation_rule_yaml_reader.py +91 -0
  6. rasa/anonymization/anonymization_pipeline.py +286 -0
  7. rasa/anonymization/anonymization_rule_executor.py +260 -0
  8. rasa/anonymization/anonymization_rule_orchestrator.py +120 -0
  9. rasa/anonymization/schemas/config.yml +47 -0
  10. rasa/anonymization/utils.py +118 -0
  11. rasa/api.py +160 -0
  12. rasa/cli/__init__.py +5 -0
  13. rasa/cli/arguments/__init__.py +0 -0
  14. rasa/cli/arguments/data.py +106 -0
  15. rasa/cli/arguments/default_arguments.py +207 -0
  16. rasa/cli/arguments/evaluate.py +65 -0
  17. rasa/cli/arguments/export.py +51 -0
  18. rasa/cli/arguments/interactive.py +74 -0
  19. rasa/cli/arguments/run.py +219 -0
  20. rasa/cli/arguments/shell.py +17 -0
  21. rasa/cli/arguments/test.py +211 -0
  22. rasa/cli/arguments/train.py +279 -0
  23. rasa/cli/arguments/visualize.py +34 -0
  24. rasa/cli/arguments/x.py +30 -0
  25. rasa/cli/data.py +354 -0
  26. rasa/cli/dialogue_understanding_test.py +251 -0
  27. rasa/cli/e2e_test.py +259 -0
  28. rasa/cli/evaluate.py +222 -0
  29. rasa/cli/export.py +250 -0
  30. rasa/cli/inspect.py +75 -0
  31. rasa/cli/interactive.py +166 -0
  32. rasa/cli/license.py +65 -0
  33. rasa/cli/llm_fine_tuning.py +403 -0
  34. rasa/cli/markers.py +78 -0
  35. rasa/cli/project_templates/__init__.py +0 -0
  36. rasa/cli/project_templates/calm/actions/__init__.py +0 -0
  37. rasa/cli/project_templates/calm/actions/action_template.py +27 -0
  38. rasa/cli/project_templates/calm/actions/add_contact.py +30 -0
  39. rasa/cli/project_templates/calm/actions/db.py +57 -0
  40. rasa/cli/project_templates/calm/actions/list_contacts.py +22 -0
  41. rasa/cli/project_templates/calm/actions/remove_contact.py +35 -0
  42. rasa/cli/project_templates/calm/config.yml +10 -0
  43. rasa/cli/project_templates/calm/credentials.yml +33 -0
  44. rasa/cli/project_templates/calm/data/flows/add_contact.yml +31 -0
  45. rasa/cli/project_templates/calm/data/flows/list_contacts.yml +14 -0
  46. rasa/cli/project_templates/calm/data/flows/remove_contact.yml +29 -0
  47. rasa/cli/project_templates/calm/db/contacts.json +10 -0
  48. rasa/cli/project_templates/calm/domain/add_contact.yml +39 -0
  49. rasa/cli/project_templates/calm/domain/list_contacts.yml +17 -0
  50. rasa/cli/project_templates/calm/domain/remove_contact.yml +38 -0
  51. rasa/cli/project_templates/calm/domain/shared.yml +10 -0
  52. rasa/cli/project_templates/calm/e2e_tests/cancelations/user_cancels_during_a_correction.yml +16 -0
  53. rasa/cli/project_templates/calm/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +7 -0
  54. rasa/cli/project_templates/calm/e2e_tests/corrections/user_corrects_contact_handle.yml +20 -0
  55. rasa/cli/project_templates/calm/e2e_tests/corrections/user_corrects_contact_name.yml +19 -0
  56. rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +15 -0
  57. rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_lists_contacts.yml +5 -0
  58. rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_removes_contact.yml +11 -0
  59. rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_removes_contact_from_list.yml +12 -0
  60. rasa/cli/project_templates/calm/endpoints.yml +58 -0
  61. rasa/cli/project_templates/default/actions/__init__.py +0 -0
  62. rasa/cli/project_templates/default/actions/actions.py +27 -0
  63. rasa/cli/project_templates/default/config.yml +44 -0
  64. rasa/cli/project_templates/default/credentials.yml +33 -0
  65. rasa/cli/project_templates/default/data/nlu.yml +91 -0
  66. rasa/cli/project_templates/default/data/rules.yml +13 -0
  67. rasa/cli/project_templates/default/data/stories.yml +30 -0
  68. rasa/cli/project_templates/default/domain.yml +34 -0
  69. rasa/cli/project_templates/default/endpoints.yml +42 -0
  70. rasa/cli/project_templates/default/tests/test_stories.yml +91 -0
  71. rasa/cli/project_templates/tutorial/actions/__init__.py +0 -0
  72. rasa/cli/project_templates/tutorial/actions/actions.py +22 -0
  73. rasa/cli/project_templates/tutorial/config.yml +12 -0
  74. rasa/cli/project_templates/tutorial/credentials.yml +33 -0
  75. rasa/cli/project_templates/tutorial/data/flows.yml +8 -0
  76. rasa/cli/project_templates/tutorial/data/patterns.yml +11 -0
  77. rasa/cli/project_templates/tutorial/domain.yml +35 -0
  78. rasa/cli/project_templates/tutorial/endpoints.yml +55 -0
  79. rasa/cli/run.py +143 -0
  80. rasa/cli/scaffold.py +273 -0
  81. rasa/cli/shell.py +141 -0
  82. rasa/cli/studio/__init__.py +0 -0
  83. rasa/cli/studio/download.py +62 -0
  84. rasa/cli/studio/studio.py +296 -0
  85. rasa/cli/studio/train.py +59 -0
  86. rasa/cli/studio/upload.py +62 -0
  87. rasa/cli/telemetry.py +102 -0
  88. rasa/cli/test.py +280 -0
  89. rasa/cli/train.py +278 -0
  90. rasa/cli/utils.py +484 -0
  91. rasa/cli/visualize.py +40 -0
  92. rasa/cli/x.py +206 -0
  93. rasa/constants.py +45 -0
  94. rasa/core/__init__.py +17 -0
  95. rasa/core/actions/__init__.py +0 -0
  96. rasa/core/actions/action.py +1318 -0
  97. rasa/core/actions/action_clean_stack.py +59 -0
  98. rasa/core/actions/action_exceptions.py +24 -0
  99. rasa/core/actions/action_hangup.py +29 -0
  100. rasa/core/actions/action_repeat_bot_messages.py +89 -0
  101. rasa/core/actions/action_run_slot_rejections.py +210 -0
  102. rasa/core/actions/action_trigger_chitchat.py +31 -0
  103. rasa/core/actions/action_trigger_flow.py +109 -0
  104. rasa/core/actions/action_trigger_search.py +31 -0
  105. rasa/core/actions/constants.py +5 -0
  106. rasa/core/actions/custom_action_executor.py +191 -0
  107. rasa/core/actions/direct_custom_actions_executor.py +109 -0
  108. rasa/core/actions/e2e_stub_custom_action_executor.py +72 -0
  109. rasa/core/actions/forms.py +741 -0
  110. rasa/core/actions/grpc_custom_action_executor.py +251 -0
  111. rasa/core/actions/http_custom_action_executor.py +145 -0
  112. rasa/core/actions/loops.py +114 -0
  113. rasa/core/actions/two_stage_fallback.py +186 -0
  114. rasa/core/agent.py +559 -0
  115. rasa/core/auth_retry_tracker_store.py +122 -0
  116. rasa/core/brokers/__init__.py +0 -0
  117. rasa/core/brokers/broker.py +126 -0
  118. rasa/core/brokers/file.py +58 -0
  119. rasa/core/brokers/kafka.py +324 -0
  120. rasa/core/brokers/pika.py +388 -0
  121. rasa/core/brokers/sql.py +86 -0
  122. rasa/core/channels/__init__.py +61 -0
  123. rasa/core/channels/botframework.py +338 -0
  124. rasa/core/channels/callback.py +84 -0
  125. rasa/core/channels/channel.py +456 -0
  126. rasa/core/channels/console.py +241 -0
  127. rasa/core/channels/development_inspector.py +197 -0
  128. rasa/core/channels/facebook.py +419 -0
  129. rasa/core/channels/hangouts.py +329 -0
  130. rasa/core/channels/inspector/.eslintrc.cjs +25 -0
  131. rasa/core/channels/inspector/.gitignore +23 -0
  132. rasa/core/channels/inspector/README.md +54 -0
  133. rasa/core/channels/inspector/assets/favicon.ico +0 -0
  134. rasa/core/channels/inspector/assets/rasa-chat.js +2 -0
  135. rasa/core/channels/inspector/custom.d.ts +3 -0
  136. rasa/core/channels/inspector/dist/assets/arc-861ddd57.js +1 -0
  137. rasa/core/channels/inspector/dist/assets/array-9f3ba611.js +1 -0
  138. rasa/core/channels/inspector/dist/assets/c4Diagram-d0fbc5ce-921f02db.js +10 -0
  139. rasa/core/channels/inspector/dist/assets/classDiagram-936ed81e-b436c4f8.js +2 -0
  140. rasa/core/channels/inspector/dist/assets/classDiagram-v2-c3cb15f1-511a23cb.js +2 -0
  141. rasa/core/channels/inspector/dist/assets/createText-62fc7601-ef476ecd.js +7 -0
  142. rasa/core/channels/inspector/dist/assets/edges-f2ad444c-f1878e0a.js +4 -0
  143. rasa/core/channels/inspector/dist/assets/erDiagram-9d236eb7-fac75185.js +51 -0
  144. rasa/core/channels/inspector/dist/assets/flowDb-1972c806-201c5bbc.js +6 -0
  145. rasa/core/channels/inspector/dist/assets/flowDiagram-7ea5b25a-f904ae41.js +4 -0
  146. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-b080d6f2.js +1 -0
  147. rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-abe16c3d-1813da66.js +139 -0
  148. rasa/core/channels/inspector/dist/assets/ganttDiagram-9b5ea136-872af172.js +266 -0
  149. rasa/core/channels/inspector/dist/assets/gitGraphDiagram-99d0ae7c-34a0af5a.js +70 -0
  150. rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-128cfa44.ttf +0 -0
  151. rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-21dbcb97.woff +0 -0
  152. rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-222b5e26.svg +329 -0
  153. rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-9ad89b2a.woff2 +0 -0
  154. rasa/core/channels/inspector/dist/assets/index-2c4b9a3b-42ba3e3d.js +1 -0
  155. rasa/core/channels/inspector/dist/assets/index-37817b51.js +1317 -0
  156. rasa/core/channels/inspector/dist/assets/index-3ee28881.css +1 -0
  157. rasa/core/channels/inspector/dist/assets/infoDiagram-736b4530-6b731386.js +7 -0
  158. rasa/core/channels/inspector/dist/assets/init-77b53fdd.js +1 -0
  159. rasa/core/channels/inspector/dist/assets/journeyDiagram-df861f2b-e8579ac6.js +139 -0
  160. rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-60c05ee4.woff +0 -0
  161. rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-8335d9b8.svg +438 -0
  162. rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-9cc39c75.ttf +0 -0
  163. rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-ead13ccf.woff2 +0 -0
  164. rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-16705655.woff2 +0 -0
  165. rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-5aeb07f9.woff +0 -0
  166. rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-9c459044.ttf +0 -0
  167. rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-9e2898a4.svg +435 -0
  168. rasa/core/channels/inspector/dist/assets/layout-89e6403a.js +1 -0
  169. rasa/core/channels/inspector/dist/assets/line-dc73d3fc.js +1 -0
  170. rasa/core/channels/inspector/dist/assets/linear-f5b1d2bc.js +1 -0
  171. rasa/core/channels/inspector/dist/assets/mindmap-definition-beec6740-82cb74fa.js +109 -0
  172. rasa/core/channels/inspector/dist/assets/ordinal-ba9b4969.js +1 -0
  173. rasa/core/channels/inspector/dist/assets/path-53f90ab3.js +1 -0
  174. rasa/core/channels/inspector/dist/assets/pieDiagram-dbbf0591-bdf5f29b.js +35 -0
  175. rasa/core/channels/inspector/dist/assets/quadrantDiagram-4d7f4fd6-c7a0cbe4.js +7 -0
  176. rasa/core/channels/inspector/dist/assets/requirementDiagram-6fc4c22a-7ec5410f.js +52 -0
  177. rasa/core/channels/inspector/dist/assets/sankeyDiagram-8f13d901-caee5554.js +8 -0
  178. rasa/core/channels/inspector/dist/assets/sequenceDiagram-b655622a-2935f8db.js +122 -0
  179. rasa/core/channels/inspector/dist/assets/stateDiagram-59f0c015-8f5d9693.js +1 -0
  180. rasa/core/channels/inspector/dist/assets/stateDiagram-v2-2b26beab-d565d1de.js +1 -0
  181. rasa/core/channels/inspector/dist/assets/styles-080da4f6-75ad421d.js +110 -0
  182. rasa/core/channels/inspector/dist/assets/styles-3dcbcfbf-7e764226.js +159 -0
  183. rasa/core/channels/inspector/dist/assets/styles-9c745c82-7a4e0e61.js +207 -0
  184. rasa/core/channels/inspector/dist/assets/svgDrawCommon-4835440b-4019d1bf.js +1 -0
  185. rasa/core/channels/inspector/dist/assets/timeline-definition-5b62e21b-01ea12df.js +61 -0
  186. rasa/core/channels/inspector/dist/assets/xychartDiagram-2b33534f-89407137.js +7 -0
  187. rasa/core/channels/inspector/dist/index.html +42 -0
  188. rasa/core/channels/inspector/index.html +40 -0
  189. rasa/core/channels/inspector/jest.config.ts +13 -0
  190. rasa/core/channels/inspector/package.json +52 -0
  191. rasa/core/channels/inspector/setupTests.ts +2 -0
  192. rasa/core/channels/inspector/src/App.tsx +220 -0
  193. rasa/core/channels/inspector/src/components/Chat.tsx +95 -0
  194. rasa/core/channels/inspector/src/components/DiagramFlow.tsx +108 -0
  195. rasa/core/channels/inspector/src/components/DialogueInformation.tsx +187 -0
  196. rasa/core/channels/inspector/src/components/DialogueStack.tsx +136 -0
  197. rasa/core/channels/inspector/src/components/ExpandIcon.tsx +16 -0
  198. rasa/core/channels/inspector/src/components/FullscreenButton.tsx +45 -0
  199. rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +22 -0
  200. rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +21 -0
  201. rasa/core/channels/inspector/src/components/RasaLogo.tsx +32 -0
  202. rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +39 -0
  203. rasa/core/channels/inspector/src/components/Slots.tsx +91 -0
  204. rasa/core/channels/inspector/src/components/Welcome.tsx +54 -0
  205. rasa/core/channels/inspector/src/helpers/audiostream.ts +191 -0
  206. rasa/core/channels/inspector/src/helpers/formatters.test.ts +392 -0
  207. rasa/core/channels/inspector/src/helpers/formatters.ts +306 -0
  208. rasa/core/channels/inspector/src/helpers/utils.ts +127 -0
  209. rasa/core/channels/inspector/src/main.tsx +13 -0
  210. rasa/core/channels/inspector/src/theme/Button/Button.ts +29 -0
  211. rasa/core/channels/inspector/src/theme/Heading/Heading.ts +31 -0
  212. rasa/core/channels/inspector/src/theme/Input/Input.ts +27 -0
  213. rasa/core/channels/inspector/src/theme/Link/Link.ts +10 -0
  214. rasa/core/channels/inspector/src/theme/Modal/Modal.ts +47 -0
  215. rasa/core/channels/inspector/src/theme/Table/Table.tsx +38 -0
  216. rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +12 -0
  217. rasa/core/channels/inspector/src/theme/base/breakpoints.ts +8 -0
  218. rasa/core/channels/inspector/src/theme/base/colors.ts +88 -0
  219. rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +29 -0
  220. rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.eot +0 -0
  221. rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.svg +329 -0
  222. rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.ttf +0 -0
  223. rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.woff +0 -0
  224. rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.woff2 +0 -0
  225. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.eot +0 -0
  226. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.svg +438 -0
  227. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.ttf +0 -0
  228. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.woff +0 -0
  229. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.woff2 +0 -0
  230. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.eot +0 -0
  231. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.svg +435 -0
  232. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.ttf +0 -0
  233. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.woff +0 -0
  234. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.woff2 +0 -0
  235. rasa/core/channels/inspector/src/theme/base/radii.ts +9 -0
  236. rasa/core/channels/inspector/src/theme/base/shadows.ts +7 -0
  237. rasa/core/channels/inspector/src/theme/base/sizes.ts +7 -0
  238. rasa/core/channels/inspector/src/theme/base/space.ts +15 -0
  239. rasa/core/channels/inspector/src/theme/base/styles.ts +13 -0
  240. rasa/core/channels/inspector/src/theme/base/typography.ts +24 -0
  241. rasa/core/channels/inspector/src/theme/base/zIndices.ts +19 -0
  242. rasa/core/channels/inspector/src/theme/index.ts +101 -0
  243. rasa/core/channels/inspector/src/types.ts +84 -0
  244. rasa/core/channels/inspector/src/vite-env.d.ts +1 -0
  245. rasa/core/channels/inspector/tests/__mocks__/fileMock.ts +1 -0
  246. rasa/core/channels/inspector/tests/__mocks__/matchMedia.ts +16 -0
  247. rasa/core/channels/inspector/tests/__mocks__/styleMock.ts +1 -0
  248. rasa/core/channels/inspector/tests/renderWithProviders.tsx +14 -0
  249. rasa/core/channels/inspector/tsconfig.json +26 -0
  250. rasa/core/channels/inspector/tsconfig.node.json +10 -0
  251. rasa/core/channels/inspector/vite.config.ts +8 -0
  252. rasa/core/channels/inspector/yarn.lock +6249 -0
  253. rasa/core/channels/mattermost.py +229 -0
  254. rasa/core/channels/rasa_chat.py +126 -0
  255. rasa/core/channels/rest.py +230 -0
  256. rasa/core/channels/rocketchat.py +174 -0
  257. rasa/core/channels/slack.py +620 -0
  258. rasa/core/channels/socketio.py +302 -0
  259. rasa/core/channels/telegram.py +298 -0
  260. rasa/core/channels/twilio.py +169 -0
  261. rasa/core/channels/vier_cvg.py +374 -0
  262. rasa/core/channels/voice_ready/__init__.py +0 -0
  263. rasa/core/channels/voice_ready/audiocodes.py +501 -0
  264. rasa/core/channels/voice_ready/jambonz.py +121 -0
  265. rasa/core/channels/voice_ready/jambonz_protocol.py +396 -0
  266. rasa/core/channels/voice_ready/twilio_voice.py +403 -0
  267. rasa/core/channels/voice_ready/utils.py +37 -0
  268. rasa/core/channels/voice_stream/__init__.py +0 -0
  269. rasa/core/channels/voice_stream/asr/__init__.py +0 -0
  270. rasa/core/channels/voice_stream/asr/asr_engine.py +89 -0
  271. rasa/core/channels/voice_stream/asr/asr_event.py +18 -0
  272. rasa/core/channels/voice_stream/asr/azure.py +130 -0
  273. rasa/core/channels/voice_stream/asr/deepgram.py +90 -0
  274. rasa/core/channels/voice_stream/audio_bytes.py +8 -0
  275. rasa/core/channels/voice_stream/browser_audio.py +107 -0
  276. rasa/core/channels/voice_stream/call_state.py +23 -0
  277. rasa/core/channels/voice_stream/tts/__init__.py +0 -0
  278. rasa/core/channels/voice_stream/tts/azure.py +106 -0
  279. rasa/core/channels/voice_stream/tts/cartesia.py +118 -0
  280. rasa/core/channels/voice_stream/tts/tts_cache.py +27 -0
  281. rasa/core/channels/voice_stream/tts/tts_engine.py +58 -0
  282. rasa/core/channels/voice_stream/twilio_media_streams.py +173 -0
  283. rasa/core/channels/voice_stream/util.py +57 -0
  284. rasa/core/channels/voice_stream/voice_channel.py +427 -0
  285. rasa/core/channels/webexteams.py +134 -0
  286. rasa/core/concurrent_lock_store.py +210 -0
  287. rasa/core/constants.py +112 -0
  288. rasa/core/evaluation/__init__.py +0 -0
  289. rasa/core/evaluation/marker.py +267 -0
  290. rasa/core/evaluation/marker_base.py +923 -0
  291. rasa/core/evaluation/marker_stats.py +293 -0
  292. rasa/core/evaluation/marker_tracker_loader.py +103 -0
  293. rasa/core/exceptions.py +29 -0
  294. rasa/core/exporter.py +284 -0
  295. rasa/core/featurizers/__init__.py +0 -0
  296. rasa/core/featurizers/precomputation.py +410 -0
  297. rasa/core/featurizers/single_state_featurizer.py +421 -0
  298. rasa/core/featurizers/tracker_featurizers.py +1262 -0
  299. rasa/core/http_interpreter.py +89 -0
  300. rasa/core/information_retrieval/__init__.py +7 -0
  301. rasa/core/information_retrieval/faiss.py +124 -0
  302. rasa/core/information_retrieval/information_retrieval.py +137 -0
  303. rasa/core/information_retrieval/milvus.py +59 -0
  304. rasa/core/information_retrieval/qdrant.py +96 -0
  305. rasa/core/jobs.py +63 -0
  306. rasa/core/lock.py +139 -0
  307. rasa/core/lock_store.py +343 -0
  308. rasa/core/migrate.py +403 -0
  309. rasa/core/nlg/__init__.py +3 -0
  310. rasa/core/nlg/callback.py +146 -0
  311. rasa/core/nlg/contextual_response_rephraser.py +320 -0
  312. rasa/core/nlg/generator.py +230 -0
  313. rasa/core/nlg/interpolator.py +143 -0
  314. rasa/core/nlg/response.py +155 -0
  315. rasa/core/nlg/summarize.py +70 -0
  316. rasa/core/persistor.py +538 -0
  317. rasa/core/policies/__init__.py +0 -0
  318. rasa/core/policies/ensemble.py +329 -0
  319. rasa/core/policies/enterprise_search_policy.py +905 -0
  320. rasa/core/policies/enterprise_search_prompt_template.jinja2 +25 -0
  321. rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +60 -0
  322. rasa/core/policies/flow_policy.py +205 -0
  323. rasa/core/policies/flows/__init__.py +0 -0
  324. rasa/core/policies/flows/flow_exceptions.py +44 -0
  325. rasa/core/policies/flows/flow_executor.py +754 -0
  326. rasa/core/policies/flows/flow_step_result.py +43 -0
  327. rasa/core/policies/intentless_policy.py +1031 -0
  328. rasa/core/policies/intentless_prompt_template.jinja2 +22 -0
  329. rasa/core/policies/memoization.py +538 -0
  330. rasa/core/policies/policy.py +725 -0
  331. rasa/core/policies/rule_policy.py +1273 -0
  332. rasa/core/policies/ted_policy.py +2169 -0
  333. rasa/core/policies/unexpected_intent_policy.py +1022 -0
  334. rasa/core/processor.py +1465 -0
  335. rasa/core/run.py +342 -0
  336. rasa/core/secrets_manager/__init__.py +0 -0
  337. rasa/core/secrets_manager/constants.py +36 -0
  338. rasa/core/secrets_manager/endpoints.py +391 -0
  339. rasa/core/secrets_manager/factory.py +241 -0
  340. rasa/core/secrets_manager/secret_manager.py +262 -0
  341. rasa/core/secrets_manager/vault.py +584 -0
  342. rasa/core/test.py +1335 -0
  343. rasa/core/tracker_store.py +1703 -0
  344. rasa/core/train.py +105 -0
  345. rasa/core/training/__init__.py +89 -0
  346. rasa/core/training/converters/__init__.py +0 -0
  347. rasa/core/training/converters/responses_prefix_converter.py +119 -0
  348. rasa/core/training/interactive.py +1744 -0
  349. rasa/core/training/story_conflict.py +381 -0
  350. rasa/core/training/training.py +93 -0
  351. rasa/core/utils.py +366 -0
  352. rasa/core/visualize.py +70 -0
  353. rasa/dialogue_understanding/__init__.py +0 -0
  354. rasa/dialogue_understanding/coexistence/__init__.py +0 -0
  355. rasa/dialogue_understanding/coexistence/constants.py +4 -0
  356. rasa/dialogue_understanding/coexistence/intent_based_router.py +196 -0
  357. rasa/dialogue_understanding/coexistence/llm_based_router.py +327 -0
  358. rasa/dialogue_understanding/coexistence/router_template.jinja2 +12 -0
  359. rasa/dialogue_understanding/commands/__init__.py +61 -0
  360. rasa/dialogue_understanding/commands/can_not_handle_command.py +70 -0
  361. rasa/dialogue_understanding/commands/cancel_flow_command.py +125 -0
  362. rasa/dialogue_understanding/commands/change_flow_command.py +44 -0
  363. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +57 -0
  364. rasa/dialogue_understanding/commands/clarify_command.py +86 -0
  365. rasa/dialogue_understanding/commands/command.py +85 -0
  366. rasa/dialogue_understanding/commands/correct_slots_command.py +297 -0
  367. rasa/dialogue_understanding/commands/error_command.py +79 -0
  368. rasa/dialogue_understanding/commands/free_form_answer_command.py +9 -0
  369. rasa/dialogue_understanding/commands/handle_code_change_command.py +73 -0
  370. rasa/dialogue_understanding/commands/human_handoff_command.py +66 -0
  371. rasa/dialogue_understanding/commands/knowledge_answer_command.py +57 -0
  372. rasa/dialogue_understanding/commands/noop_command.py +54 -0
  373. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +60 -0
  374. rasa/dialogue_understanding/commands/restart_command.py +58 -0
  375. rasa/dialogue_understanding/commands/session_end_command.py +61 -0
  376. rasa/dialogue_understanding/commands/session_start_command.py +59 -0
  377. rasa/dialogue_understanding/commands/set_slot_command.py +160 -0
  378. rasa/dialogue_understanding/commands/skip_question_command.py +75 -0
  379. rasa/dialogue_understanding/commands/start_flow_command.py +107 -0
  380. rasa/dialogue_understanding/commands/user_silence_command.py +59 -0
  381. rasa/dialogue_understanding/commands/utils.py +45 -0
  382. rasa/dialogue_understanding/generator/__init__.py +21 -0
  383. rasa/dialogue_understanding/generator/command_generator.py +464 -0
  384. rasa/dialogue_understanding/generator/constants.py +27 -0
  385. rasa/dialogue_understanding/generator/flow_document_template.jinja2 +4 -0
  386. rasa/dialogue_understanding/generator/flow_retrieval.py +466 -0
  387. rasa/dialogue_understanding/generator/llm_based_command_generator.py +500 -0
  388. rasa/dialogue_understanding/generator/llm_command_generator.py +67 -0
  389. rasa/dialogue_understanding/generator/multi_step/__init__.py +0 -0
  390. rasa/dialogue_understanding/generator/multi_step/fill_slots_prompt.jinja2 +62 -0
  391. rasa/dialogue_understanding/generator/multi_step/handle_flows_prompt.jinja2 +38 -0
  392. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +920 -0
  393. rasa/dialogue_understanding/generator/nlu_command_adapter.py +261 -0
  394. rasa/dialogue_understanding/generator/single_step/__init__.py +0 -0
  395. rasa/dialogue_understanding/generator/single_step/command_prompt_template.jinja2 +60 -0
  396. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +486 -0
  397. rasa/dialogue_understanding/patterns/__init__.py +0 -0
  398. rasa/dialogue_understanding/patterns/cancel.py +111 -0
  399. rasa/dialogue_understanding/patterns/cannot_handle.py +43 -0
  400. rasa/dialogue_understanding/patterns/chitchat.py +37 -0
  401. rasa/dialogue_understanding/patterns/clarify.py +97 -0
  402. rasa/dialogue_understanding/patterns/code_change.py +41 -0
  403. rasa/dialogue_understanding/patterns/collect_information.py +90 -0
  404. rasa/dialogue_understanding/patterns/completed.py +40 -0
  405. rasa/dialogue_understanding/patterns/continue_interrupted.py +42 -0
  406. rasa/dialogue_understanding/patterns/correction.py +278 -0
  407. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +301 -0
  408. rasa/dialogue_understanding/patterns/human_handoff.py +37 -0
  409. rasa/dialogue_understanding/patterns/internal_error.py +47 -0
  410. rasa/dialogue_understanding/patterns/repeat.py +37 -0
  411. rasa/dialogue_understanding/patterns/restart.py +37 -0
  412. rasa/dialogue_understanding/patterns/search.py +37 -0
  413. rasa/dialogue_understanding/patterns/session_start.py +37 -0
  414. rasa/dialogue_understanding/patterns/skip_question.py +38 -0
  415. rasa/dialogue_understanding/patterns/user_silence.py +37 -0
  416. rasa/dialogue_understanding/processor/__init__.py +0 -0
  417. rasa/dialogue_understanding/processor/command_processor.py +720 -0
  418. rasa/dialogue_understanding/processor/command_processor_component.py +43 -0
  419. rasa/dialogue_understanding/stack/__init__.py +0 -0
  420. rasa/dialogue_understanding/stack/dialogue_stack.py +178 -0
  421. rasa/dialogue_understanding/stack/frames/__init__.py +19 -0
  422. rasa/dialogue_understanding/stack/frames/chit_chat_frame.py +27 -0
  423. rasa/dialogue_understanding/stack/frames/dialogue_stack_frame.py +137 -0
  424. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +157 -0
  425. rasa/dialogue_understanding/stack/frames/pattern_frame.py +10 -0
  426. rasa/dialogue_understanding/stack/frames/search_frame.py +27 -0
  427. rasa/dialogue_understanding/stack/utils.py +211 -0
  428. rasa/dialogue_understanding/utils.py +14 -0
  429. rasa/dialogue_understanding_test/__init__.py +0 -0
  430. rasa/dialogue_understanding_test/command_metric_calculation.py +12 -0
  431. rasa/dialogue_understanding_test/constants.py +17 -0
  432. rasa/dialogue_understanding_test/du_test_case.py +118 -0
  433. rasa/dialogue_understanding_test/du_test_result.py +11 -0
  434. rasa/dialogue_understanding_test/du_test_runner.py +93 -0
  435. rasa/dialogue_understanding_test/io.py +54 -0
  436. rasa/dialogue_understanding_test/validation.py +22 -0
  437. rasa/e2e_test/__init__.py +0 -0
  438. rasa/e2e_test/aggregate_test_stats_calculator.py +134 -0
  439. rasa/e2e_test/assertions.py +1345 -0
  440. rasa/e2e_test/assertions_schema.yml +129 -0
  441. rasa/e2e_test/constants.py +31 -0
  442. rasa/e2e_test/e2e_config.py +220 -0
  443. rasa/e2e_test/e2e_config_schema.yml +26 -0
  444. rasa/e2e_test/e2e_test_case.py +569 -0
  445. rasa/e2e_test/e2e_test_converter.py +363 -0
  446. rasa/e2e_test/e2e_test_converter_prompt.jinja2 +70 -0
  447. rasa/e2e_test/e2e_test_coverage_report.py +364 -0
  448. rasa/e2e_test/e2e_test_result.py +54 -0
  449. rasa/e2e_test/e2e_test_runner.py +1192 -0
  450. rasa/e2e_test/e2e_test_schema.yml +181 -0
  451. rasa/e2e_test/pykwalify_extensions.py +39 -0
  452. rasa/e2e_test/stub_custom_action.py +70 -0
  453. rasa/e2e_test/utils/__init__.py +0 -0
  454. rasa/e2e_test/utils/e2e_yaml_utils.py +55 -0
  455. rasa/e2e_test/utils/io.py +598 -0
  456. rasa/e2e_test/utils/validation.py +178 -0
  457. rasa/engine/__init__.py +0 -0
  458. rasa/engine/caching.py +463 -0
  459. rasa/engine/constants.py +17 -0
  460. rasa/engine/exceptions.py +14 -0
  461. rasa/engine/graph.py +642 -0
  462. rasa/engine/loader.py +48 -0
  463. rasa/engine/recipes/__init__.py +0 -0
  464. rasa/engine/recipes/config_files/default_config.yml +41 -0
  465. rasa/engine/recipes/default_components.py +97 -0
  466. rasa/engine/recipes/default_recipe.py +1272 -0
  467. rasa/engine/recipes/graph_recipe.py +79 -0
  468. rasa/engine/recipes/recipe.py +93 -0
  469. rasa/engine/runner/__init__.py +0 -0
  470. rasa/engine/runner/dask.py +250 -0
  471. rasa/engine/runner/interface.py +49 -0
  472. rasa/engine/storage/__init__.py +0 -0
  473. rasa/engine/storage/local_model_storage.py +244 -0
  474. rasa/engine/storage/resource.py +110 -0
  475. rasa/engine/storage/storage.py +199 -0
  476. rasa/engine/training/__init__.py +0 -0
  477. rasa/engine/training/components.py +176 -0
  478. rasa/engine/training/fingerprinting.py +64 -0
  479. rasa/engine/training/graph_trainer.py +256 -0
  480. rasa/engine/training/hooks.py +164 -0
  481. rasa/engine/validation.py +1451 -0
  482. rasa/env.py +14 -0
  483. rasa/exceptions.py +69 -0
  484. rasa/graph_components/__init__.py +0 -0
  485. rasa/graph_components/converters/__init__.py +0 -0
  486. rasa/graph_components/converters/nlu_message_converter.py +48 -0
  487. rasa/graph_components/providers/__init__.py +0 -0
  488. rasa/graph_components/providers/domain_for_core_training_provider.py +87 -0
  489. rasa/graph_components/providers/domain_provider.py +71 -0
  490. rasa/graph_components/providers/flows_provider.py +74 -0
  491. rasa/graph_components/providers/forms_provider.py +44 -0
  492. rasa/graph_components/providers/nlu_training_data_provider.py +56 -0
  493. rasa/graph_components/providers/responses_provider.py +44 -0
  494. rasa/graph_components/providers/rule_only_provider.py +49 -0
  495. rasa/graph_components/providers/story_graph_provider.py +96 -0
  496. rasa/graph_components/providers/training_tracker_provider.py +55 -0
  497. rasa/graph_components/validators/__init__.py +0 -0
  498. rasa/graph_components/validators/default_recipe_validator.py +550 -0
  499. rasa/graph_components/validators/finetuning_validator.py +302 -0
  500. rasa/hooks.py +111 -0
  501. rasa/jupyter.py +63 -0
  502. rasa/llm_fine_tuning/__init__.py +0 -0
  503. rasa/llm_fine_tuning/annotation_module.py +241 -0
  504. rasa/llm_fine_tuning/conversations.py +144 -0
  505. rasa/llm_fine_tuning/llm_data_preparation_module.py +178 -0
  506. rasa/llm_fine_tuning/paraphrasing/__init__.py +0 -0
  507. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +281 -0
  508. rasa/llm_fine_tuning/paraphrasing/default_rephrase_prompt_template.jina2 +44 -0
  509. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +121 -0
  510. rasa/llm_fine_tuning/paraphrasing/rephrased_user_message.py +10 -0
  511. rasa/llm_fine_tuning/paraphrasing_module.py +128 -0
  512. rasa/llm_fine_tuning/storage.py +174 -0
  513. rasa/llm_fine_tuning/train_test_split_module.py +441 -0
  514. rasa/markers/__init__.py +0 -0
  515. rasa/markers/marker.py +269 -0
  516. rasa/markers/marker_base.py +828 -0
  517. rasa/markers/upload.py +74 -0
  518. rasa/markers/validate.py +21 -0
  519. rasa/model.py +118 -0
  520. rasa/model_manager/__init__.py +0 -0
  521. rasa/model_manager/config.py +40 -0
  522. rasa/model_manager/model_api.py +559 -0
  523. rasa/model_manager/runner_service.py +286 -0
  524. rasa/model_manager/socket_bridge.py +146 -0
  525. rasa/model_manager/studio_jwt_auth.py +86 -0
  526. rasa/model_manager/trainer_service.py +325 -0
  527. rasa/model_manager/utils.py +87 -0
  528. rasa/model_manager/warm_rasa_process.py +187 -0
  529. rasa/model_service.py +112 -0
  530. rasa/model_testing.py +457 -0
  531. rasa/model_training.py +596 -0
  532. rasa/nlu/__init__.py +7 -0
  533. rasa/nlu/classifiers/__init__.py +3 -0
  534. rasa/nlu/classifiers/classifier.py +5 -0
  535. rasa/nlu/classifiers/diet_classifier.py +1881 -0
  536. rasa/nlu/classifiers/fallback_classifier.py +192 -0
  537. rasa/nlu/classifiers/keyword_intent_classifier.py +188 -0
  538. rasa/nlu/classifiers/logistic_regression_classifier.py +253 -0
  539. rasa/nlu/classifiers/mitie_intent_classifier.py +156 -0
  540. rasa/nlu/classifiers/regex_message_handler.py +56 -0
  541. rasa/nlu/classifiers/sklearn_intent_classifier.py +330 -0
  542. rasa/nlu/constants.py +77 -0
  543. rasa/nlu/convert.py +40 -0
  544. rasa/nlu/emulators/__init__.py +0 -0
  545. rasa/nlu/emulators/dialogflow.py +55 -0
  546. rasa/nlu/emulators/emulator.py +49 -0
  547. rasa/nlu/emulators/luis.py +86 -0
  548. rasa/nlu/emulators/no_emulator.py +10 -0
  549. rasa/nlu/emulators/wit.py +56 -0
  550. rasa/nlu/extractors/__init__.py +0 -0
  551. rasa/nlu/extractors/crf_entity_extractor.py +715 -0
  552. rasa/nlu/extractors/duckling_entity_extractor.py +206 -0
  553. rasa/nlu/extractors/entity_synonyms.py +178 -0
  554. rasa/nlu/extractors/extractor.py +470 -0
  555. rasa/nlu/extractors/mitie_entity_extractor.py +293 -0
  556. rasa/nlu/extractors/regex_entity_extractor.py +220 -0
  557. rasa/nlu/extractors/spacy_entity_extractor.py +95 -0
  558. rasa/nlu/featurizers/__init__.py +0 -0
  559. rasa/nlu/featurizers/dense_featurizer/__init__.py +0 -0
  560. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +445 -0
  561. rasa/nlu/featurizers/dense_featurizer/dense_featurizer.py +57 -0
  562. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +768 -0
  563. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +170 -0
  564. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +132 -0
  565. rasa/nlu/featurizers/featurizer.py +89 -0
  566. rasa/nlu/featurizers/sparse_featurizer/__init__.py +0 -0
  567. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +867 -0
  568. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +571 -0
  569. rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +271 -0
  570. rasa/nlu/featurizers/sparse_featurizer/sparse_featurizer.py +9 -0
  571. rasa/nlu/model.py +24 -0
  572. rasa/nlu/run.py +27 -0
  573. rasa/nlu/selectors/__init__.py +0 -0
  574. rasa/nlu/selectors/response_selector.py +987 -0
  575. rasa/nlu/test.py +1940 -0
  576. rasa/nlu/tokenizers/__init__.py +0 -0
  577. rasa/nlu/tokenizers/jieba_tokenizer.py +148 -0
  578. rasa/nlu/tokenizers/mitie_tokenizer.py +75 -0
  579. rasa/nlu/tokenizers/spacy_tokenizer.py +72 -0
  580. rasa/nlu/tokenizers/tokenizer.py +239 -0
  581. rasa/nlu/tokenizers/whitespace_tokenizer.py +95 -0
  582. rasa/nlu/utils/__init__.py +35 -0
  583. rasa/nlu/utils/bilou_utils.py +462 -0
  584. rasa/nlu/utils/hugging_face/__init__.py +0 -0
  585. rasa/nlu/utils/hugging_face/registry.py +108 -0
  586. rasa/nlu/utils/hugging_face/transformers_pre_post_processors.py +311 -0
  587. rasa/nlu/utils/mitie_utils.py +113 -0
  588. rasa/nlu/utils/pattern_utils.py +168 -0
  589. rasa/nlu/utils/spacy_utils.py +310 -0
  590. rasa/plugin.py +90 -0
  591. rasa/server.py +1588 -0
  592. rasa/shared/__init__.py +0 -0
  593. rasa/shared/constants.py +311 -0
  594. rasa/shared/core/__init__.py +0 -0
  595. rasa/shared/core/command_payload_reader.py +109 -0
  596. rasa/shared/core/constants.py +180 -0
  597. rasa/shared/core/conversation.py +46 -0
  598. rasa/shared/core/domain.py +2172 -0
  599. rasa/shared/core/events.py +2559 -0
  600. rasa/shared/core/flows/__init__.py +7 -0
  601. rasa/shared/core/flows/flow.py +562 -0
  602. rasa/shared/core/flows/flow_path.py +84 -0
  603. rasa/shared/core/flows/flow_step.py +146 -0
  604. rasa/shared/core/flows/flow_step_links.py +319 -0
  605. rasa/shared/core/flows/flow_step_sequence.py +70 -0
  606. rasa/shared/core/flows/flows_list.py +258 -0
  607. rasa/shared/core/flows/flows_yaml_schema.json +303 -0
  608. rasa/shared/core/flows/nlu_trigger.py +117 -0
  609. rasa/shared/core/flows/steps/__init__.py +24 -0
  610. rasa/shared/core/flows/steps/action.py +56 -0
  611. rasa/shared/core/flows/steps/call.py +64 -0
  612. rasa/shared/core/flows/steps/collect.py +112 -0
  613. rasa/shared/core/flows/steps/constants.py +5 -0
  614. rasa/shared/core/flows/steps/continuation.py +36 -0
  615. rasa/shared/core/flows/steps/end.py +22 -0
  616. rasa/shared/core/flows/steps/internal.py +44 -0
  617. rasa/shared/core/flows/steps/link.py +51 -0
  618. rasa/shared/core/flows/steps/no_operation.py +48 -0
  619. rasa/shared/core/flows/steps/set_slots.py +50 -0
  620. rasa/shared/core/flows/steps/start.py +30 -0
  621. rasa/shared/core/flows/utils.py +39 -0
  622. rasa/shared/core/flows/validation.py +735 -0
  623. rasa/shared/core/flows/yaml_flows_io.py +405 -0
  624. rasa/shared/core/generator.py +908 -0
  625. rasa/shared/core/slot_mappings.py +526 -0
  626. rasa/shared/core/slots.py +654 -0
  627. rasa/shared/core/trackers.py +1183 -0
  628. rasa/shared/core/training_data/__init__.py +0 -0
  629. rasa/shared/core/training_data/loading.py +89 -0
  630. rasa/shared/core/training_data/story_reader/__init__.py +0 -0
  631. rasa/shared/core/training_data/story_reader/story_reader.py +129 -0
  632. rasa/shared/core/training_data/story_reader/story_step_builder.py +168 -0
  633. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +888 -0
  634. rasa/shared/core/training_data/story_writer/__init__.py +0 -0
  635. rasa/shared/core/training_data/story_writer/story_writer.py +76 -0
  636. rasa/shared/core/training_data/story_writer/yaml_story_writer.py +444 -0
  637. rasa/shared/core/training_data/structures.py +858 -0
  638. rasa/shared/core/training_data/visualization.html +146 -0
  639. rasa/shared/core/training_data/visualization.py +603 -0
  640. rasa/shared/data.py +249 -0
  641. rasa/shared/engine/__init__.py +0 -0
  642. rasa/shared/engine/caching.py +26 -0
  643. rasa/shared/exceptions.py +167 -0
  644. rasa/shared/importers/__init__.py +0 -0
  645. rasa/shared/importers/importer.py +770 -0
  646. rasa/shared/importers/multi_project.py +215 -0
  647. rasa/shared/importers/rasa.py +108 -0
  648. rasa/shared/importers/remote_importer.py +196 -0
  649. rasa/shared/importers/utils.py +36 -0
  650. rasa/shared/nlu/__init__.py +0 -0
  651. rasa/shared/nlu/constants.py +53 -0
  652. rasa/shared/nlu/interpreter.py +10 -0
  653. rasa/shared/nlu/training_data/__init__.py +0 -0
  654. rasa/shared/nlu/training_data/entities_parser.py +208 -0
  655. rasa/shared/nlu/training_data/features.py +492 -0
  656. rasa/shared/nlu/training_data/formats/__init__.py +10 -0
  657. rasa/shared/nlu/training_data/formats/dialogflow.py +163 -0
  658. rasa/shared/nlu/training_data/formats/luis.py +87 -0
  659. rasa/shared/nlu/training_data/formats/rasa.py +135 -0
  660. rasa/shared/nlu/training_data/formats/rasa_yaml.py +618 -0
  661. rasa/shared/nlu/training_data/formats/readerwriter.py +244 -0
  662. rasa/shared/nlu/training_data/formats/wit.py +52 -0
  663. rasa/shared/nlu/training_data/loading.py +137 -0
  664. rasa/shared/nlu/training_data/lookup_tables_parser.py +30 -0
  665. rasa/shared/nlu/training_data/message.py +490 -0
  666. rasa/shared/nlu/training_data/schemas/__init__.py +0 -0
  667. rasa/shared/nlu/training_data/schemas/data_schema.py +85 -0
  668. rasa/shared/nlu/training_data/schemas/nlu.yml +53 -0
  669. rasa/shared/nlu/training_data/schemas/responses.yml +70 -0
  670. rasa/shared/nlu/training_data/synonyms_parser.py +42 -0
  671. rasa/shared/nlu/training_data/training_data.py +729 -0
  672. rasa/shared/nlu/training_data/util.py +223 -0
  673. rasa/shared/providers/__init__.py +0 -0
  674. rasa/shared/providers/_configs/__init__.py +0 -0
  675. rasa/shared/providers/_configs/azure_openai_client_config.py +677 -0
  676. rasa/shared/providers/_configs/client_config.py +59 -0
  677. rasa/shared/providers/_configs/default_litellm_client_config.py +132 -0
  678. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +236 -0
  679. rasa/shared/providers/_configs/litellm_router_client_config.py +222 -0
  680. rasa/shared/providers/_configs/model_group_config.py +173 -0
  681. rasa/shared/providers/_configs/openai_client_config.py +177 -0
  682. rasa/shared/providers/_configs/rasa_llm_client_config.py +75 -0
  683. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +178 -0
  684. rasa/shared/providers/_configs/utils.py +117 -0
  685. rasa/shared/providers/_ssl_verification_utils.py +124 -0
  686. rasa/shared/providers/_utils.py +79 -0
  687. rasa/shared/providers/constants.py +7 -0
  688. rasa/shared/providers/embedding/__init__.py +0 -0
  689. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +243 -0
  690. rasa/shared/providers/embedding/_langchain_embedding_client_adapter.py +74 -0
  691. rasa/shared/providers/embedding/azure_openai_embedding_client.py +335 -0
  692. rasa/shared/providers/embedding/default_litellm_embedding_client.py +126 -0
  693. rasa/shared/providers/embedding/embedding_client.py +90 -0
  694. rasa/shared/providers/embedding/embedding_response.py +41 -0
  695. rasa/shared/providers/embedding/huggingface_local_embedding_client.py +191 -0
  696. rasa/shared/providers/embedding/litellm_router_embedding_client.py +138 -0
  697. rasa/shared/providers/embedding/openai_embedding_client.py +172 -0
  698. rasa/shared/providers/llm/__init__.py +0 -0
  699. rasa/shared/providers/llm/_base_litellm_client.py +265 -0
  700. rasa/shared/providers/llm/azure_openai_llm_client.py +415 -0
  701. rasa/shared/providers/llm/default_litellm_llm_client.py +110 -0
  702. rasa/shared/providers/llm/litellm_router_llm_client.py +202 -0
  703. rasa/shared/providers/llm/llm_client.py +78 -0
  704. rasa/shared/providers/llm/llm_response.py +50 -0
  705. rasa/shared/providers/llm/openai_llm_client.py +161 -0
  706. rasa/shared/providers/llm/rasa_llm_client.py +120 -0
  707. rasa/shared/providers/llm/self_hosted_llm_client.py +276 -0
  708. rasa/shared/providers/mappings.py +94 -0
  709. rasa/shared/providers/router/__init__.py +0 -0
  710. rasa/shared/providers/router/_base_litellm_router_client.py +185 -0
  711. rasa/shared/providers/router/router_client.py +75 -0
  712. rasa/shared/utils/__init__.py +0 -0
  713. rasa/shared/utils/cli.py +102 -0
  714. rasa/shared/utils/common.py +324 -0
  715. rasa/shared/utils/constants.py +4 -0
  716. rasa/shared/utils/health_check/__init__.py +0 -0
  717. rasa/shared/utils/health_check/embeddings_health_check_mixin.py +31 -0
  718. rasa/shared/utils/health_check/health_check.py +258 -0
  719. rasa/shared/utils/health_check/llm_health_check_mixin.py +31 -0
  720. rasa/shared/utils/io.py +499 -0
  721. rasa/shared/utils/llm.py +764 -0
  722. rasa/shared/utils/pykwalify_extensions.py +27 -0
  723. rasa/shared/utils/schemas/__init__.py +0 -0
  724. rasa/shared/utils/schemas/config.yml +2 -0
  725. rasa/shared/utils/schemas/domain.yml +145 -0
  726. rasa/shared/utils/schemas/events.py +214 -0
  727. rasa/shared/utils/schemas/model_config.yml +36 -0
  728. rasa/shared/utils/schemas/stories.yml +173 -0
  729. rasa/shared/utils/yaml.py +1068 -0
  730. rasa/studio/__init__.py +0 -0
  731. rasa/studio/auth.py +270 -0
  732. rasa/studio/config.py +136 -0
  733. rasa/studio/constants.py +19 -0
  734. rasa/studio/data_handler.py +368 -0
  735. rasa/studio/download.py +489 -0
  736. rasa/studio/results_logger.py +137 -0
  737. rasa/studio/train.py +134 -0
  738. rasa/studio/upload.py +563 -0
  739. rasa/telemetry.py +1876 -0
  740. rasa/tracing/__init__.py +0 -0
  741. rasa/tracing/config.py +355 -0
  742. rasa/tracing/constants.py +62 -0
  743. rasa/tracing/instrumentation/__init__.py +0 -0
  744. rasa/tracing/instrumentation/attribute_extractors.py +765 -0
  745. rasa/tracing/instrumentation/instrumentation.py +1306 -0
  746. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +144 -0
  747. rasa/tracing/instrumentation/metrics.py +294 -0
  748. rasa/tracing/metric_instrument_provider.py +205 -0
  749. rasa/utils/__init__.py +0 -0
  750. rasa/utils/beta.py +83 -0
  751. rasa/utils/cli.py +28 -0
  752. rasa/utils/common.py +639 -0
  753. rasa/utils/converter.py +53 -0
  754. rasa/utils/endpoints.py +331 -0
  755. rasa/utils/io.py +252 -0
  756. rasa/utils/json_utils.py +60 -0
  757. rasa/utils/licensing.py +542 -0
  758. rasa/utils/log_utils.py +181 -0
  759. rasa/utils/mapper.py +210 -0
  760. rasa/utils/ml_utils.py +147 -0
  761. rasa/utils/plotting.py +362 -0
  762. rasa/utils/sanic_error_handler.py +32 -0
  763. rasa/utils/singleton.py +23 -0
  764. rasa/utils/tensorflow/__init__.py +0 -0
  765. rasa/utils/tensorflow/callback.py +112 -0
  766. rasa/utils/tensorflow/constants.py +116 -0
  767. rasa/utils/tensorflow/crf.py +492 -0
  768. rasa/utils/tensorflow/data_generator.py +440 -0
  769. rasa/utils/tensorflow/environment.py +161 -0
  770. rasa/utils/tensorflow/exceptions.py +5 -0
  771. rasa/utils/tensorflow/feature_array.py +366 -0
  772. rasa/utils/tensorflow/layers.py +1565 -0
  773. rasa/utils/tensorflow/layers_utils.py +113 -0
  774. rasa/utils/tensorflow/metrics.py +281 -0
  775. rasa/utils/tensorflow/model_data.py +798 -0
  776. rasa/utils/tensorflow/model_data_utils.py +499 -0
  777. rasa/utils/tensorflow/models.py +935 -0
  778. rasa/utils/tensorflow/rasa_layers.py +1094 -0
  779. rasa/utils/tensorflow/transformer.py +640 -0
  780. rasa/utils/tensorflow/types.py +6 -0
  781. rasa/utils/train_utils.py +572 -0
  782. rasa/utils/url_tools.py +53 -0
  783. rasa/utils/yaml.py +54 -0
  784. rasa/validator.py +1644 -0
  785. rasa/version.py +3 -0
  786. rasa_pro-3.12.0.dev1.dist-info/METADATA +199 -0
  787. rasa_pro-3.12.0.dev1.dist-info/NOTICE +5 -0
  788. rasa_pro-3.12.0.dev1.dist-info/RECORD +790 -0
  789. rasa_pro-3.12.0.dev1.dist-info/WHEEL +4 -0
  790. rasa_pro-3.12.0.dev1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,1192 @@
1
+ import asyncio
2
+ import copy
3
+ import datetime
4
+ import difflib
5
+ from asyncio import CancelledError
6
+ from collections import defaultdict
7
+ from pathlib import Path
8
+ from typing import Any, DefaultDict, Dict, List, Optional, Text, Tuple, Union
9
+ from urllib.parse import urlparse
10
+
11
+ import requests
12
+ import structlog
13
+ from tqdm import tqdm
14
+
15
+ import rasa.shared.utils.io
16
+ from rasa.core.channels import CollectingOutputChannel, UserMessage
17
+ from rasa.core.constants import ACTIVE_FLOW_METADATA_KEY, STEP_ID_METADATA_KEY
18
+ from rasa.core.exceptions import AgentNotReady
19
+ from rasa.core.persistor import StorageType
20
+ from rasa.core.utils import AvailableEndpoints
21
+ from rasa.e2e_test.constants import TEST_CASE_NAME, TEST_FILE_NAME
22
+ from rasa.e2e_test.e2e_config import create_llm_judge_config
23
+ from rasa.e2e_test.e2e_test_case import (
24
+ KEY_STUB_CUSTOM_ACTIONS,
25
+ ActualStepOutput,
26
+ Fixture,
27
+ Metadata,
28
+ TestCase,
29
+ TestStep,
30
+ )
31
+ from rasa.e2e_test.e2e_test_result import (
32
+ NO_RESPONSE,
33
+ NO_SLOT,
34
+ TestFailure,
35
+ TestResult,
36
+ )
37
+ from rasa.llm_fine_tuning.conversations import Conversation
38
+ from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
39
+ from rasa.shared.core.events import (
40
+ ActionExecuted,
41
+ BotUttered,
42
+ Event,
43
+ FlowCompleted,
44
+ FlowStarted,
45
+ SlotSet,
46
+ UserUttered,
47
+ )
48
+ from rasa.shared.core.flows.flow_path import FlowPath, PathNode
49
+ from rasa.shared.core.trackers import DialogueStateTracker
50
+ from rasa.shared.exceptions import RasaException
51
+ from rasa.shared.nlu.constants import COMMANDS
52
+ from rasa.telemetry import track_e2e_test_run
53
+ from rasa.utils.endpoints import EndpointConfig
54
+
55
+ structlogger = structlog.get_logger()
56
+
57
+ TEST_TURNS_TYPE = Dict[int, Union[TestStep, ActualStepOutput]]
58
+
59
+
60
+ class E2ETestRunner:
61
+ def __init__(
62
+ self,
63
+ model_path: Optional[Text] = None,
64
+ model_server: Optional[EndpointConfig] = None,
65
+ remote_storage: Optional[StorageType] = None,
66
+ endpoints: Optional[AvailableEndpoints] = None,
67
+ **kwargs: Any,
68
+ ) -> None:
69
+ """Initializes the E2E test suite runner.
70
+
71
+ Args:
72
+ model_path: Path to the model.
73
+ model_server: Model server configuration.
74
+ remote_storage: Remote storage to use for model retrieval.
75
+ endpoints: Endpoints configuration.
76
+ **kwargs: Additional arguments
77
+ """
78
+ import rasa.core.agent
79
+
80
+ structlogger.info(
81
+ "e2e_test_runner.init",
82
+ event_info="Started running end-to-end testing.",
83
+ )
84
+
85
+ test_case_path = kwargs.get("test_case_path")
86
+ self.llm_judge_config = create_llm_judge_config(test_case_path)
87
+
88
+ are_custom_actions_stubbed = (
89
+ endpoints
90
+ and endpoints.action
91
+ and endpoints.action.kwargs.get(KEY_STUB_CUSTOM_ACTIONS)
92
+ )
93
+ if endpoints and not are_custom_actions_stubbed:
94
+ self._action_server_is_reachable(endpoints)
95
+
96
+ self.agent = asyncio.run(
97
+ rasa.core.agent.load_agent(
98
+ model_path=model_path,
99
+ model_server=model_server,
100
+ remote_storage=remote_storage,
101
+ endpoints=endpoints,
102
+ )
103
+ )
104
+
105
+ if not self.agent.is_ready():
106
+ raise AgentNotReady(
107
+ "Agent needs to be prepared before usage. "
108
+ "Please check that the agent was able to "
109
+ "load the trained model."
110
+ )
111
+
112
+ async def run_prediction_loop(
113
+ self,
114
+ collector: CollectingOutputChannel,
115
+ steps: List[TestStep],
116
+ sender_id: Text,
117
+ test_case_metadata: Optional[Metadata] = None,
118
+ input_metadata: Optional[List[Metadata]] = None,
119
+ ) -> TEST_TURNS_TYPE:
120
+ """Runs dialogue prediction.
121
+
122
+ Args:
123
+ collector: Output channel.
124
+ steps: List of steps to run.
125
+ sender_id: The test case name with added timestamp suffix.
126
+ test_case_metadata: Metadata of test case.
127
+ input_metadata: List of metadata.
128
+
129
+ Returns:
130
+ Test turns: {turn_sequence (int) : TestStep or ActualStepOutput}.
131
+ """
132
+ turns: TEST_TURNS_TYPE = {}
133
+ event_cursor = 0
134
+
135
+ if not self.agent.processor:
136
+ return turns
137
+
138
+ tracker = await self.agent.processor.fetch_tracker_with_initial_session(
139
+ sender_id, output_channel=collector
140
+ )
141
+ # turn -1 i used to contain events that happen during
142
+ # the start of the session and before the first user message
143
+ # TestStep is a placeholder just for the sake of having a turn
144
+ # to specify the actor
145
+ turns[-1], event_cursor = self.get_actual_step_output(
146
+ tracker,
147
+ TestStep(
148
+ actor="bot",
149
+ text=None,
150
+ ),
151
+ event_cursor,
152
+ )
153
+
154
+ for position, step in enumerate(steps):
155
+ if step.actor != "user":
156
+ turns[position] = step
157
+ continue
158
+ elif not step.text:
159
+ rasa.shared.utils.io.raise_warning(
160
+ f"The test case '{sender_id}' contains a `user` step in line "
161
+ f"{position + 1} without a text value. "
162
+ f"Skipping this step and proceeding to the next user step.",
163
+ UserWarning,
164
+ )
165
+ continue
166
+
167
+ metadata = test_case_metadata.metadata if test_case_metadata else {}
168
+
169
+ if input_metadata:
170
+ step_metadata = self.filter_metadata_for_input(
171
+ step.metadata_name, input_metadata
172
+ )
173
+ step_metadata_dict = step_metadata.metadata if step_metadata else {}
174
+ metadata = self.merge_metadata(
175
+ sender_id, step.text, metadata, step_metadata_dict
176
+ )
177
+
178
+ try:
179
+ await self.agent.handle_message(
180
+ UserMessage(
181
+ step.text,
182
+ collector,
183
+ sender_id,
184
+ metadata=metadata,
185
+ )
186
+ )
187
+ except CancelledError:
188
+ structlogger.error(
189
+ "e2e_test_runner.run_prediction_loop",
190
+ error=f"Message handling timed out for user message '{step.text}'.",
191
+ exc_info=True,
192
+ )
193
+ except Exception as exc:
194
+ structlogger.error(
195
+ "e2e_test_runner.run_prediction_loop",
196
+ error=f"An exception occurred while handling "
197
+ f"user message '{step.text}'. Error: {exc}",
198
+ )
199
+ tracker = await self.agent.tracker_store.retrieve(sender_id) # type: ignore[assignment]
200
+ turns[position], event_cursor = self.get_actual_step_output(
201
+ tracker, step, event_cursor
202
+ )
203
+ return turns
204
+
205
+ @staticmethod
206
+ def merge_metadata(
207
+ sender_id: Text,
208
+ step_text: Text,
209
+ test_case_metadata: Dict[Text, Text],
210
+ step_metadata: Dict[Text, Text],
211
+ ) -> Dict[Text, Text]:
212
+ """Merges the test case and user step metadata.
213
+
214
+ Args:
215
+ sender_id: The test case name with added timestamp suffix.
216
+ step_text: The user step text.
217
+ test_case_metadata: The test case metadata dict.
218
+ step_metadata: The user step metadata dict.
219
+
220
+ Returns:
221
+ A dictionary with the merged metadata.
222
+ """
223
+ if not test_case_metadata:
224
+ return step_metadata
225
+ if not step_metadata:
226
+ return test_case_metadata
227
+
228
+ keys_to_overwrite = []
229
+
230
+ for key in step_metadata.keys():
231
+ if key in test_case_metadata.keys():
232
+ keys_to_overwrite.append(key)
233
+
234
+ if keys_to_overwrite:
235
+ test_case_name = sender_id.rsplit("_", 1)[0]
236
+ structlogger.warning(
237
+ "e2e_test_runner.merge_metadata",
238
+ message=f"Metadata {keys_to_overwrite} exist in both the test case "
239
+ f"'{test_case_name}' and the user step '{step_text}'. "
240
+ "The user step metadata takes precedence and will "
241
+ "override the test case metadata.",
242
+ )
243
+
244
+ merged_metadata = copy.deepcopy(test_case_metadata)
245
+ merged_metadata.update(step_metadata)
246
+
247
+ return merged_metadata
248
+
249
+ @staticmethod
250
+ def get_actual_step_output(
251
+ tracker: DialogueStateTracker,
252
+ test_step: TestStep,
253
+ event_cursor: int,
254
+ ) -> Tuple[ActualStepOutput, int]:
255
+ """Returns the events that are generated from the current step.
256
+
257
+ Args:
258
+ tracker: The tracker for the current test case.
259
+ test_step: The test step.
260
+ event_cursor: The event cursor where the previous step left off.
261
+
262
+ Returns:
263
+ The events generated from the current step and the updated event
264
+ cursor position.
265
+ """
266
+ session_events = list(tracker.events)[event_cursor:]
267
+ if session_events:
268
+ event_cursor += len(session_events)
269
+ return (
270
+ ActualStepOutput.from_test_step(
271
+ test_step,
272
+ [
273
+ event
274
+ for event in session_events
275
+ if isinstance(event, (BotUttered, UserUttered, SlotSet))
276
+ ],
277
+ ),
278
+ event_cursor,
279
+ )
280
+ else:
281
+ structlogger.warning(
282
+ "e2e_test_runner.get_actual_step_output",
283
+ message=f"No events found for '{tracker.sender_id}' after processing "
284
+ f"test step '{test_step.text}'.",
285
+ )
286
+ # if there are no events, we still want to return an
287
+ # ActualStepOutput object with the test step as the
288
+ # response to be able to generate a diff
289
+ return (
290
+ ActualStepOutput.from_test_step(
291
+ test_step,
292
+ [
293
+ UserUttered(text=test_step.text),
294
+ BotUttered(text=NO_RESPONSE),
295
+ ],
296
+ ),
297
+ event_cursor,
298
+ )
299
+
300
+ @classmethod
301
+ def generate_test_result(
302
+ cls,
303
+ test_turns: TEST_TURNS_TYPE,
304
+ test_case: TestCase,
305
+ ) -> TestResult:
306
+ """Generates test result.
307
+
308
+ Args:
309
+ test_turns: the turns that happened when running the test case or test step.
310
+ test_case: the `TestCase` instance.
311
+
312
+ Returns:
313
+ Test result.
314
+ """
315
+ difference = []
316
+ error_line = None
317
+ test_failures = cls.find_test_failures(test_turns, test_case)
318
+ if test_failures:
319
+ first_failure = test_failures[0][0]
320
+ difference = cls.human_readable_diff(test_turns, test_failures)
321
+ error_line = first_failure.error_line if first_failure else None
322
+
323
+ return TestResult(
324
+ pass_status=len(test_failures) == 0,
325
+ test_case=test_case,
326
+ difference=difference,
327
+ error_line=error_line,
328
+ )
329
+
330
+ def _get_additional_splitting_conditions(
331
+ self,
332
+ step: TestStep,
333
+ input_metadata: List[Metadata],
334
+ tracker: DialogueStateTracker,
335
+ test_case: TestCase,
336
+ ) -> Dict[str, Any]:
337
+ """Returns additional splitting conditions for the user message."""
338
+ additional_splitting_conditions: Dict[str, Any] = {"text": step.text}
339
+
340
+ if not step.metadata_name:
341
+ return additional_splitting_conditions
342
+
343
+ step_metadata = self.filter_metadata_for_input(
344
+ step.metadata_name, input_metadata
345
+ )
346
+ step_metadata_dict = step_metadata.metadata if step_metadata else {}
347
+
348
+ test_case_metadata = self.filter_metadata_for_input(
349
+ test_case.metadata_name, input_metadata
350
+ )
351
+ test_case_metadata_as_dict = (
352
+ test_case_metadata.metadata if test_case_metadata else {}
353
+ )
354
+
355
+ metadata: Dict[str, Any] = self.merge_metadata(
356
+ tracker.sender_id,
357
+ step.text,
358
+ test_case_metadata_as_dict,
359
+ step_metadata_dict,
360
+ )
361
+ metadata["model_id"] = tracker.model_id
362
+ metadata["assistant_id"] = tracker.assistant_id
363
+
364
+ additional_splitting_conditions["metadata"] = metadata
365
+
366
+ return additional_splitting_conditions
367
+
368
+ @staticmethod
369
+ def _get_current_user_turn_and_prior_events(
370
+ tracker: DialogueStateTracker,
371
+ additional_splitting_conditions: Dict[str, Any],
372
+ step: TestStep,
373
+ ) -> Tuple[List[Event], List[Event]]:
374
+ """Returns the current user turn and prior events."""
375
+ actual_events = tracker.events
376
+
377
+ # this returns 2 lists, the first list contains the events until the user
378
+ # message and the second list contains the events after the
379
+ # user message, including the user message
380
+ step_events = rasa.shared.core.events.split_events(
381
+ actual_events,
382
+ UserUttered,
383
+ additional_splitting_conditions=additional_splitting_conditions,
384
+ include_splitting_event=True,
385
+ )
386
+
387
+ if len(step_events) < 2:
388
+ structlogger.error(
389
+ "e2e_test_runner.run_assertions.user_message_not_found",
390
+ message=f"User message '{step.text}' was not found in "
391
+ f"the actual events. The user message "
392
+ f"properties which were searched: "
393
+ f"{additional_splitting_conditions}",
394
+ )
395
+ return [], []
396
+
397
+ post_step_events = step_events[1]
398
+ prior_events = step_events[0]
399
+
400
+ # subset of events until the next user message
401
+ turn_events = []
402
+ for event in post_step_events:
403
+ # we reached the next user message
404
+ if isinstance(event, UserUttered) and step.text != event.text:
405
+ break
406
+
407
+ turn_events.append(event)
408
+
409
+ return turn_events, prior_events
410
+
411
+ @staticmethod
412
+ def _slice_turn_events(
413
+ step: TestStep,
414
+ matching_event: Event,
415
+ turn_events: List[Event],
416
+ prior_events: List[Event],
417
+ ) -> Tuple[List[Event], List[Event]]:
418
+ """Slices the turn events when assertion order is enabled."""
419
+ if not step.assertion_order_enabled:
420
+ return turn_events, prior_events
421
+
422
+ if not matching_event:
423
+ return turn_events, prior_events
424
+
425
+ matching_event_index = turn_events.index(matching_event)
426
+ if matching_event_index + 1 < len(turn_events):
427
+ prior_events += turn_events[: matching_event_index + 1]
428
+ turn_events = turn_events[matching_event_index + 1 :]
429
+
430
+ return turn_events, prior_events
431
+
432
+ async def run_assertions(
433
+ self,
434
+ sender_id: str,
435
+ test_case: TestCase,
436
+ input_metadata: Optional[List[Metadata]],
437
+ ) -> TestResult:
438
+ """Runs the assertions defined in the test case."""
439
+ tracker = await self.agent.processor.get_tracker(sender_id) # type: ignore[union-attr]
440
+
441
+ assertion_failure = None
442
+ assertion_failure_found = False
443
+ input_metadata = input_metadata if input_metadata else []
444
+
445
+ for index, step in enumerate(test_case.steps):
446
+ if not step.assertions:
447
+ structlogger.debug(
448
+ "e2e_test_runner.run_assertions.no_assertions.skipping_step",
449
+ step=step,
450
+ )
451
+ continue
452
+
453
+ additional_splitting_conditions = self._get_additional_splitting_conditions(
454
+ step, input_metadata, tracker, test_case
455
+ )
456
+
457
+ turn_events, prior_events = self._get_current_user_turn_and_prior_events(
458
+ tracker, additional_splitting_conditions, step
459
+ )
460
+
461
+ if not turn_events:
462
+ return TestResult(
463
+ pass_status=False,
464
+ test_case=test_case,
465
+ difference=[],
466
+ error_line=step.line,
467
+ assertion_failure=None,
468
+ )
469
+
470
+ for assertion in step.assertions:
471
+ structlogger.debug(
472
+ "e2e_test_runner.run_assertions.running_assertion",
473
+ test_case_name=test_case.name,
474
+ step_text=step.text,
475
+ assertion_type=assertion.type(),
476
+ )
477
+
478
+ assertion_order_error_msg = ""
479
+
480
+ if step.assertion_order_enabled:
481
+ assertion_order_error_msg = (
482
+ " You have enabled assertion order, "
483
+ "you should check the order in which the "
484
+ "assertions are listed for this user step."
485
+ )
486
+
487
+ assertion_failure, matching_event = assertion.run(
488
+ turn_events,
489
+ prior_events=prior_events,
490
+ assertion_order_error_message=assertion_order_error_msg,
491
+ llm_judge_config=self.llm_judge_config,
492
+ step_text=step.text,
493
+ step_index=index,
494
+ )
495
+
496
+ if assertion_failure:
497
+ assertion_failure_found = True
498
+ structlogger.debug(
499
+ "e2e_test_runner.run_assertions.assertion_failure_found",
500
+ test_case_name=test_case.name,
501
+ error_line=assertion_failure.error_line,
502
+ )
503
+ break
504
+
505
+ turn_events, prior_events = self._slice_turn_events(
506
+ step, matching_event, turn_events, copy.deepcopy(prior_events)
507
+ )
508
+
509
+ if assertion_failure_found:
510
+ # don't continue with the next steps if an assertion failed
511
+ break
512
+
513
+ return TestResult(
514
+ pass_status=not assertion_failure,
515
+ test_case=test_case,
516
+ difference=[],
517
+ error_line=assertion_failure.error_line if assertion_failure else None,
518
+ assertion_failure=assertion_failure,
519
+ )
520
+
521
+ @classmethod
522
+ def _resolve_successful_bot_utter(
523
+ cls,
524
+ expected_result: TestStep,
525
+ test_response: ActualStepOutput,
526
+ ) -> str:
527
+ """Returns the diff text for a successful bot utter test step."""
528
+ for event in test_response.bot_uttered_events:
529
+ if expected_result.matches_event(event):
530
+ # remove the event that is already matched so
531
+ # that we dont compare against it again
532
+ test_response.remove_bot_uttered_event(event)
533
+ if expected_result.text is not None:
534
+ text = f"{expected_result.actor}: {expected_result.text}"
535
+ elif expected_result.template is not None:
536
+ text = f"{expected_result.actor}: {expected_result.template}"
537
+ break
538
+
539
+ return text
540
+
541
+ @classmethod
542
+ def _resolve_successful_set_slot(
543
+ cls,
544
+ expected_result: TestStep,
545
+ test_response: ActualStepOutput,
546
+ ) -> str:
547
+ """Returns the diff text for a successful set slot test step."""
548
+ slot_name = expected_result.get_slot_name()
549
+ text = f"slot_was_set: {slot_name}"
550
+
551
+ for event in test_response.slot_set_events:
552
+ if expected_result.matches_event(event):
553
+ # remove the event that is already matched so
554
+ # that we dont compare against it again
555
+ test_response.remove_slot_set_event(event)
556
+ if event.value is not None:
557
+ text += f": {event.value} ({type(event.value).__name__})"
558
+ break
559
+
560
+ return text
561
+
562
+ @classmethod
563
+ def _resolve_successful_slot_was_not_set(cls, expected_result: TestStep) -> str:
564
+ """Returns the diff text for a successful slot was not set test step."""
565
+ slot_name = expected_result.get_slot_name()
566
+ slot_value = expected_result.get_slot_value()
567
+ text = f"slot_was_not_set: {slot_name}"
568
+ if expected_result.is_slot_instance_dict():
569
+ text += f": {slot_value}"
570
+
571
+ return text
572
+
573
+ @classmethod
574
+ def _find_first_non_matched_utterance(
575
+ cls,
576
+ test_response: ActualStepOutput,
577
+ bot_utter_test_steps: List[TestStep],
578
+ ) -> Optional[BotUttered]:
579
+ """Finds the first non matched utterance in events (if any)."""
580
+ bot_events = test_response.bot_uttered_events
581
+ matching_events = []
582
+ for event in bot_events:
583
+ for test_step in bot_utter_test_steps:
584
+ if test_step.matches_event(event):
585
+ matching_events.append(event)
586
+ break
587
+ not_matching_events = [
588
+ event for event in bot_events if event not in matching_events
589
+ ]
590
+ return not_matching_events[0] if not_matching_events else None
591
+
592
+ @classmethod
593
+ def _handle_fail_diff(
594
+ cls,
595
+ failed_step: TestStep,
596
+ test_response: ActualStepOutput,
597
+ bot_utter_test_steps: List[TestStep],
598
+ ) -> Tuple[str, str]:
599
+ """Handles generating the diff text for a failed test step."""
600
+ if failed_step.text is not None:
601
+ diff_test_text = f"{failed_step.actor}: {failed_step.text}"
602
+ diff_actual_text = NO_RESPONSE
603
+ event: Optional[Union[BotUttered, SlotSet]] = (
604
+ cls._find_first_non_matched_utterance(
605
+ test_response, bot_utter_test_steps
606
+ )
607
+ )
608
+ if event and isinstance(event, BotUttered):
609
+ test_response.remove_bot_uttered_event(event)
610
+ diff_actual_text = f"bot: {event.text}"
611
+
612
+ elif failed_step.template is not None:
613
+ diff_test_text = f"{failed_step.actor}: {failed_step.template}"
614
+ diff_actual_text = NO_RESPONSE
615
+ event = cls._find_first_non_matched_utterance(
616
+ test_response, bot_utter_test_steps
617
+ )
618
+ if event:
619
+ test_response.remove_bot_uttered_event(event)
620
+ diff_actual_text = f"bot: {event.metadata.get('utter_action')}"
621
+
622
+ elif failed_step.slot_was_set:
623
+ slot_name = failed_step.get_slot_name()
624
+
625
+ diff_test_text = f"slot_was_set: {slot_name}"
626
+ if failed_step.is_slot_instance_dict():
627
+ slot_value = failed_step.get_slot_value()
628
+ diff_test_text += f": {slot_value} ({type(slot_value).__name__})"
629
+
630
+ diff_actual_text = NO_SLOT
631
+ for event in test_response.slot_set_events:
632
+ if slot_name == event.key:
633
+ diff_actual_text = (
634
+ f"slot_was_set: {event.key}: {event.value} "
635
+ f"({type(event.value).__name__})"
636
+ )
637
+ test_response.remove_slot_set_event(event)
638
+ break
639
+
640
+ elif failed_step.slot_was_not_set:
641
+ slot_name = failed_step.get_slot_name()
642
+
643
+ diff_test_text = f"slot_was_not_set: {slot_name}"
644
+ if failed_step.is_slot_instance_dict():
645
+ slot_value = failed_step.get_slot_value()
646
+ diff_test_text += f": {slot_value}"
647
+
648
+ for event in test_response.slot_set_events:
649
+ if slot_name == event.key:
650
+ diff_actual_text = (
651
+ f"slot_was_set: {event.key}: {event.value} "
652
+ f"({type(event.value).__name__})"
653
+ )
654
+ test_response.remove_slot_set_event(event)
655
+ break
656
+
657
+ return diff_test_text, diff_actual_text
658
+
659
+ @classmethod
660
+ def _select_bot_utter_turns(
661
+ cls,
662
+ test_turns: TEST_TURNS_TYPE,
663
+ start_index: int,
664
+ ) -> List[TestStep]:
665
+ """Selects the TestSteps from the test turns that match BotUttered events."""
666
+ bot_utter_turns = []
667
+ for index in range(start_index, len(test_turns) - 1):
668
+ test_turn = test_turns[index]
669
+ if isinstance(test_turn, TestStep):
670
+ if test_turn.text is not None or test_turn.template is not None:
671
+ bot_utter_turns.append(test_turn)
672
+ elif isinstance(test_turn, ActualStepOutput):
673
+ break
674
+
675
+ return bot_utter_turns
676
+
677
+ @classmethod
678
+ def human_readable_diff(
679
+ cls,
680
+ test_turns: TEST_TURNS_TYPE,
681
+ fail_positions: List[Tuple[TestFailure, int]],
682
+ ) -> List[str]:
683
+ """Returns a human readable diff of the test case and the actual conversation.
684
+
685
+ Given an ordered list of test steps and actual conversation events, this
686
+ method will return a human readable diff of the two.
687
+ The diff uses difflib to compare the two lists and will highlight
688
+ differences between the two in a pytest style diff.
689
+
690
+ Args:
691
+ test_turns: The transcript of test cases and events.
692
+ fail_positions: The positions of the test failures.
693
+
694
+ Returns:
695
+ The human readable diff.
696
+ """
697
+ actual_transcript = []
698
+ expected_transcript = []
699
+ failure_points = {position for _, position in fail_positions}
700
+ # This will only be used when the TestCase is not started
701
+ # with a user step
702
+ latest_response: ActualStepOutput = test_turns[-1] # type: ignore[assignment]
703
+
704
+ for index in range(max(failure_points) + 1):
705
+ test_result = test_turns[index]
706
+ if index in failure_points:
707
+ diff_test_text, diff_actual_text = cls._handle_fail_diff(
708
+ test_result, # type: ignore[arg-type]
709
+ latest_response,
710
+ cls._select_bot_utter_turns(test_turns, index),
711
+ ) # test_result can only be TestStep in failure_points
712
+ actual_transcript.append(diff_actual_text)
713
+ expected_transcript.append(diff_test_text)
714
+ continue
715
+
716
+ if isinstance(test_result, TestStep):
717
+ if test_result.text is not None or test_result.template is not None:
718
+ diff_test_text = cls._resolve_successful_bot_utter(
719
+ expected_result=test_result,
720
+ test_response=latest_response,
721
+ )
722
+
723
+ if test_result.slot_was_set:
724
+ diff_test_text = cls._resolve_successful_set_slot(
725
+ expected_result=test_result,
726
+ test_response=latest_response,
727
+ )
728
+
729
+ if test_result.slot_was_not_set:
730
+ diff_test_text = cls._resolve_successful_slot_was_not_set(
731
+ expected_result=test_result,
732
+ )
733
+
734
+ elif isinstance(test_result, ActualStepOutput):
735
+ latest_response = test_result
736
+ event = test_result.get_user_uttered_event()
737
+ if event:
738
+ diff_test_text = f"{test_result.actor}: {event.text}"
739
+ else:
740
+ raise RasaException(
741
+ f"Bot did not catch user "
742
+ f"event: {test_result.actor}: {test_result.text}."
743
+ )
744
+ else:
745
+ raise ValueError(f"Unexpected test result type: {type(test_result)}")
746
+
747
+ # test passed in these cases so it's the same
748
+ actual_transcript.append(diff_test_text)
749
+ expected_transcript.append(diff_test_text)
750
+
751
+ return list(difflib.ndiff(actual_transcript, expected_transcript))
752
+
753
+ @classmethod
754
+ def find_test_failures(
755
+ cls,
756
+ test_turns: TEST_TURNS_TYPE,
757
+ test_case: TestCase,
758
+ ) -> List[Tuple[TestFailure, int]]:
759
+ """Finds the test failures in the transcript.
760
+
761
+ Args:
762
+ test_turns: The transcript of test cases and events.
763
+ test_case: The test case.
764
+
765
+ Returns:
766
+ The test failures or an empty list if there is no test failure.
767
+ """
768
+ # This will only be used when the TestCase is not started
769
+ # with a user step
770
+ latest_response: ActualStepOutput = test_turns[-1] # type: ignore[assignment]
771
+ failures = []
772
+ position = 0
773
+ match = None
774
+ for position in range(len(test_turns) - 1):
775
+ turn_value = test_turns[position]
776
+ if isinstance(turn_value, ActualStepOutput):
777
+ latest_response = turn_value
778
+ elif isinstance(turn_value, TestStep):
779
+ if turn_value.text is not None or turn_value.template is not None:
780
+ match = cls._does_match_exist(
781
+ latest_response.bot_uttered_events, turn_value
782
+ )
783
+ if turn_value.slot_was_set:
784
+ match = cls._does_match_exist(
785
+ latest_response.slot_set_events, turn_value
786
+ )
787
+ if turn_value.slot_was_not_set:
788
+ match = not cls._does_match_exist(
789
+ latest_response.slot_set_events, turn_value
790
+ )
791
+ if not match:
792
+ failures.append((TestFailure(test_case, turn_value.line), position))
793
+ else:
794
+ raise ValueError(f"Unexpected turn value type: {type(turn_value)}")
795
+
796
+ return failures
797
+
798
+ @classmethod
799
+ def _does_match_exist(
800
+ cls,
801
+ actual_events: Optional[List[Union[UserUttered, BotUttered, SlotSet]]],
802
+ expected: TestStep,
803
+ ) -> bool:
804
+ if not actual_events:
805
+ return False
806
+
807
+ match = False
808
+ for event in actual_events:
809
+ if expected.matches_event(event):
810
+ return True
811
+ return match
812
+
813
+ async def set_up_fixtures(
814
+ self,
815
+ fixtures: List[Fixture],
816
+ sender_id: Text,
817
+ ) -> None:
818
+ """Sets slots in the tracker as defined by the input fixtures.
819
+
820
+ Args:
821
+ fixtures: List of `Fixture` objects.
822
+ sender_id: The conversation id.
823
+ """
824
+ if not fixtures:
825
+ return
826
+ if not self.agent.processor:
827
+ return
828
+
829
+ tracker = await self.agent.processor.fetch_tracker_with_initial_session(
830
+ sender_id, output_channel=CollectingOutputChannel()
831
+ )
832
+
833
+ for fixture in fixtures:
834
+ for slot_name, slot_value in fixture.slots_set.items():
835
+ tracker.update(SlotSet(slot_name, slot_value))
836
+
837
+ await self.agent.tracker_store.save(tracker)
838
+
839
+ @staticmethod
840
+ def filter_fixtures_for_test_case(
841
+ test_case: TestCase, fixtures: List[Fixture]
842
+ ) -> List[Fixture]:
843
+ """Filters the input fixtures for the input test case.
844
+
845
+ Args:
846
+ test_case: The test case.
847
+ fixtures: The fixtures.
848
+
849
+ Returns:
850
+ The filtered fixtures.
851
+ """
852
+ return list(
853
+ filter(
854
+ lambda fixture: test_case.fixture_names
855
+ and fixture.name in test_case.fixture_names,
856
+ fixtures,
857
+ )
858
+ )
859
+
860
+ @staticmethod
861
+ def filter_metadata_for_input(
862
+ metadata_name: Optional[Text], test_suite_metadata: List[Metadata]
863
+ ) -> Optional[Metadata]:
864
+ """Filters the test suite metadata for a metadata name.
865
+
866
+ Args:
867
+ metadata_name: The test case or user step metadata name.
868
+ test_suite_metadata: The top level list of all metadata definitions.
869
+
870
+ Returns:
871
+ The filtered metadata.
872
+ """
873
+ if not metadata_name:
874
+ return None
875
+
876
+ filtered_metadata = list(
877
+ filter(
878
+ lambda metadata: metadata_name and metadata.name == metadata_name,
879
+ test_suite_metadata,
880
+ )
881
+ )
882
+
883
+ if not filtered_metadata:
884
+ structlogger.warning(
885
+ "e2e_test_runner.filter_metadata_for_input",
886
+ message=f"Metadata '{metadata_name}' is not defined in the input "
887
+ f"metadata.",
888
+ )
889
+ return None
890
+
891
+ return filtered_metadata[0]
892
+
893
+ async def run_tests(
894
+ self,
895
+ input_test_cases: List[TestCase],
896
+ input_fixtures: List[Fixture],
897
+ fail_fast: bool = False,
898
+ **kwargs: Any,
899
+ ) -> List["TestResult"]:
900
+ """Runs the test cases.
901
+
902
+ Args:
903
+ input_test_cases: Input test cases.
904
+ input_fixtures: Input fixtures.
905
+ fail_fast: Whether to fail fast.
906
+ **kwargs: Additional arguments which are passed here.
907
+
908
+ Returns:
909
+ List of test results.
910
+ """
911
+ results = []
912
+ input_metadata = kwargs.get("input_metadata", None)
913
+
914
+ # telemetry call for tracking test runs
915
+ track_e2e_test_run(input_test_cases, input_fixtures, input_metadata)
916
+
917
+ for test_case in input_test_cases:
918
+ test_case_name = test_case.name.replace(" ", "_")
919
+ # Add the name of the file and the current test case name being
920
+ # executed in order to properly retrieve stub custom action
921
+ if self.agent.endpoints and self.agent.endpoints.action:
922
+ self.agent.endpoints.action.kwargs[TEST_FILE_NAME] = Path(
923
+ test_case.file
924
+ ).name
925
+ self.agent.endpoints.action.kwargs[TEST_CASE_NAME] = test_case_name
926
+
927
+ # add timestamp suffix to ensure sender_id is unique
928
+ sender_id = f"{test_case_name}_{datetime.datetime.now()}"
929
+ test_turns = await self._run_test_case(
930
+ sender_id, input_fixtures, input_metadata, test_case
931
+ )
932
+
933
+ if not test_case.uses_assertions():
934
+ test_result = self.generate_test_result(test_turns, test_case)
935
+ else:
936
+ test_result = await self.run_assertions(
937
+ sender_id, test_case, input_metadata
938
+ )
939
+
940
+ results.append(test_result)
941
+
942
+ coverage = kwargs.get("coverage", False)
943
+ if coverage:
944
+ tracker = await self.agent.tracker_store.retrieve(sender_id)
945
+ if tracker:
946
+ test_result.tested_paths, test_result.tested_commands = (
947
+ self._get_tested_flow_paths_and_commands(
948
+ tracker.events, test_result
949
+ )
950
+ )
951
+
952
+ if fail_fast and not test_result.pass_status:
953
+ break
954
+
955
+ return results
956
+
957
+ async def _run_test_case(
958
+ self,
959
+ sender_id: str,
960
+ input_fixtures: List[Fixture],
961
+ input_metadata: Optional[List[Metadata]],
962
+ test_case: TestCase,
963
+ ) -> TEST_TURNS_TYPE:
964
+ collector = CollectingOutputChannel()
965
+
966
+ if input_fixtures:
967
+ test_fixtures = self.filter_fixtures_for_test_case(
968
+ test_case, input_fixtures
969
+ )
970
+ await self.set_up_fixtures(test_fixtures, sender_id)
971
+
972
+ test_case_metadata = None
973
+ if input_metadata:
974
+ test_case_metadata = self.filter_metadata_for_input(
975
+ test_case.metadata_name, input_metadata
976
+ )
977
+
978
+ return await self.run_prediction_loop(
979
+ collector,
980
+ test_case.steps,
981
+ sender_id,
982
+ test_case_metadata,
983
+ input_metadata,
984
+ )
985
+
986
+ async def run_tests_for_fine_tuning(
987
+ self,
988
+ input_test_cases: List[TestCase],
989
+ input_fixtures: List[Fixture],
990
+ input_metadata: Optional[List[Metadata]],
991
+ ) -> List[Conversation]:
992
+ """Runs the test cases for fine-tuning.
993
+
994
+ Converts passing test cases into conversation objects containing the
995
+ prompts and llm commands per user message.
996
+
997
+ Args:
998
+ input_test_cases: Input test cases.
999
+ input_fixtures: Input fixtures.
1000
+ input_metadata: Input metadata.
1001
+
1002
+ Returns:
1003
+ List of conversations.
1004
+ """
1005
+ import rasa.llm_fine_tuning.annotation_module
1006
+
1007
+ conversations = []
1008
+
1009
+ for i in tqdm(range(len(input_test_cases))):
1010
+ test_case = input_test_cases[i]
1011
+ # add timestamp suffix to ensure sender_id is unique
1012
+ sender_id = f"{test_case.name}_{datetime.datetime.now()}"
1013
+ test_turns = await self._run_test_case(
1014
+ sender_id, input_fixtures, input_metadata, test_case
1015
+ )
1016
+
1017
+ # check if the e2e test is passing, only convert passing e2e tests into
1018
+ # conversations
1019
+ if not test_case.uses_assertions():
1020
+ test_result = self.generate_test_result(test_turns, test_case)
1021
+ else:
1022
+ test_result = await self.run_assertions(
1023
+ sender_id, test_case, input_metadata
1024
+ )
1025
+ if not test_result.pass_status:
1026
+ structlogger.warning(
1027
+ "annotation_module.skip_test_case.failing_e2e_test",
1028
+ test_case=test_case.name,
1029
+ file=test_case.file,
1030
+ )
1031
+ continue
1032
+
1033
+ tracker = await self.agent.tracker_store.retrieve(sender_id)
1034
+ conversation = rasa.llm_fine_tuning.annotation_module.generate_conversation(
1035
+ test_turns, test_case, tracker, test_case.uses_assertions()
1036
+ )
1037
+
1038
+ if conversation:
1039
+ conversations.append(conversation)
1040
+
1041
+ return conversations
1042
+
1043
+ @staticmethod
1044
+ def _action_server_is_reachable(
1045
+ endpoints: AvailableEndpoints, module: str = "e2e_test_runner"
1046
+ ) -> None:
1047
+ """Calls the action server health endpoint."""
1048
+ if not endpoints.action:
1049
+ structlogger.debug(
1050
+ f"{module}._action_server_is_reachable",
1051
+ message="No action endpoint configured. Skipping the health check "
1052
+ "of the action server.",
1053
+ )
1054
+ return
1055
+
1056
+ if endpoints.action.actions_module:
1057
+ structlogger.debug(
1058
+ f"{module}._action_server_is_reachable",
1059
+ message="Rasa server is configured to run custom actions directly. "
1060
+ "Skipping the health check of the action server.",
1061
+ )
1062
+ return
1063
+
1064
+ if not endpoints.action.url:
1065
+ structlogger.debug(
1066
+ f"{module}._action_server_is_reachable",
1067
+ message="Action endpoint URL is not defined in the endpoint "
1068
+ "configuration.",
1069
+ )
1070
+ return
1071
+
1072
+ structlogger.debug(
1073
+ f"{module}._action_server_is_reachable",
1074
+ message="Detected action URL in the endpoint configuration.\n"
1075
+ f"Action Server URL: {endpoints.action.url}\n"
1076
+ "Sending a health request to the action endpoint.",
1077
+ )
1078
+ url = urlparse(endpoints.action.url)
1079
+ # replace /<path> with just /health
1080
+ url = url._replace(path="/health").geturl() # type: ignore[assignment]
1081
+ try:
1082
+ response = requests.get(url, timeout=3)
1083
+ except requests.exceptions.ConnectionError as error:
1084
+ raise RasaException(
1085
+ "Action endpoint could not be reached. "
1086
+ "Actions server URL is defined in your endpoint configuration as "
1087
+ f"'{endpoints.action.url}'.\n"
1088
+ "Please make sure your action server is running and properly "
1089
+ "configured. Since running tests without a action server may "
1090
+ f"lead to unpredictable results.\n{error}"
1091
+ )
1092
+
1093
+ if response.status_code != 200:
1094
+ raise RasaException(
1095
+ "Action endpoint is responding, but health status responded with "
1096
+ f"code {response.status_code}. Make sure your action server"
1097
+ " is properly configured and that the '/health' endpoint is available."
1098
+ )
1099
+
1100
+ structlogger.debug(
1101
+ f"{module}._action_server_is_reachable",
1102
+ message="Action endpoint has responded successfully.\n"
1103
+ f"Response message: {response.text}\n"
1104
+ f"Response status code: {response.status_code}.",
1105
+ )
1106
+
1107
+ def _get_tested_flow_paths_and_commands(
1108
+ self, events: List[Event], test_result: TestResult
1109
+ ) -> Tuple[Optional[List[FlowPath]], Dict[str, Dict[str, int]]]:
1110
+ """Extract tested paths and commands from dialog events.
1111
+
1112
+ A flow path consists of bot utterances and custom actions.
1113
+
1114
+ Args:
1115
+ events: The list of dialog events.
1116
+ test_result: The result of the test incl. the pass status.
1117
+
1118
+ Returns:
1119
+ Tuple[flow_paths: Optional[List[FlowPath]], tested_commands:
1120
+ Dict[str, Dict[str, int]]], where tested_commands is a
1121
+ dictionary like
1122
+ {"flow1": {"set slot": 5, "clarify": 1}, "flow2": {"set slot": 3}}
1123
+ """
1124
+ tested_paths = []
1125
+ # we want to create a flow path per flow the e2e test covers
1126
+ # as an e2e test can cover multiple flows, we might end up creating
1127
+ # multiple flow paths
1128
+ _tested_commands: DefaultDict[str, DefaultDict[str, int]] = defaultdict(
1129
+ lambda: defaultdict(int)
1130
+ )
1131
+ flow_paths_stack = []
1132
+
1133
+ for event in events:
1134
+ if isinstance(event, FlowStarted) and not event.flow_id.startswith(
1135
+ RASA_DEFAULT_FLOW_PATTERN_PREFIX
1136
+ ):
1137
+ flow_paths_stack.append(FlowPath(event.flow_id))
1138
+
1139
+ elif (
1140
+ isinstance(event, FlowCompleted)
1141
+ and len(flow_paths_stack) > 0
1142
+ and event.flow_id == flow_paths_stack[-1].flow
1143
+ ):
1144
+ # flow path is completed as the flow ended
1145
+ tested_paths.append(flow_paths_stack.pop())
1146
+
1147
+ elif isinstance(event, BotUttered):
1148
+ if (
1149
+ flow_paths_stack
1150
+ and STEP_ID_METADATA_KEY in event.metadata
1151
+ and ACTIVE_FLOW_METADATA_KEY in event.metadata
1152
+ ):
1153
+ flow_paths_stack[-1].nodes.append(self._create_path_node(event))
1154
+
1155
+ elif isinstance(event, ActionExecuted):
1156
+ # we are only interested in custom actions
1157
+ if (
1158
+ flow_paths_stack
1159
+ and self.agent.domain
1160
+ and self.agent.domain.is_custom_action(event.action_name)
1161
+ and STEP_ID_METADATA_KEY in event.metadata
1162
+ and ACTIVE_FLOW_METADATA_KEY in event.metadata
1163
+ ):
1164
+ flow_paths_stack[-1].nodes.append(self._create_path_node(event))
1165
+
1166
+ # Time to gather tested commands
1167
+ elif isinstance(event, UserUttered):
1168
+ if event.parse_data and COMMANDS in event.parse_data:
1169
+ commands = [
1170
+ command["command"] for command in event.parse_data[COMMANDS]
1171
+ ]
1172
+ current_flow = (
1173
+ flow_paths_stack[-1].flow if flow_paths_stack else "no_flow"
1174
+ )
1175
+ for command in commands:
1176
+ _tested_commands[current_flow][command] += 1
1177
+
1178
+ # It might be that an e2e test stops before a flow was completed.
1179
+ # Add the remaining flow paths to the tested paths list.
1180
+ while len(flow_paths_stack) > 0:
1181
+ tested_paths.append(flow_paths_stack.pop())
1182
+
1183
+ # Convert _tested_commands to normal dicts
1184
+ tested_commands = {key: dict(value) for key, value in _tested_commands.items()} # type: Dict[str, Dict[str, int]]
1185
+
1186
+ return tested_paths, tested_commands
1187
+
1188
+ @staticmethod
1189
+ def _create_path_node(event: Event) -> PathNode:
1190
+ flow_id = event.metadata[ACTIVE_FLOW_METADATA_KEY]
1191
+ step_id = event.metadata[STEP_ID_METADATA_KEY]
1192
+ return PathNode(step_id=step_id, flow=flow_id)