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,1345 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+ import json
5
+ import re
6
+ from dataclasses import dataclass
7
+ from enum import Enum
8
+ from functools import lru_cache
9
+ from typing import (
10
+ Any,
11
+ Callable,
12
+ Dict,
13
+ List,
14
+ Optional,
15
+ Set,
16
+ TYPE_CHECKING,
17
+ Text,
18
+ Tuple,
19
+ Type,
20
+ )
21
+
22
+ import pandas as pd
23
+ import structlog
24
+
25
+ import rasa.shared.utils.common
26
+ from rasa.core.constants import (
27
+ DOMAIN_GROUND_TRUTH_METADATA_KEY,
28
+ UTTER_SOURCE_METADATA_KEY,
29
+ )
30
+ from rasa.core.policies.enterprise_search_policy import (
31
+ SEARCH_QUERY_METADATA_KEY,
32
+ SEARCH_RESULTS_METADATA_KEY,
33
+ )
34
+ from rasa.dialogue_understanding.patterns.clarify import FLOW_PATTERN_CLARIFICATION
35
+ from rasa.shared.core.constants import DEFAULT_SLOT_NAMES
36
+ from rasa.shared.core.events import (
37
+ ActionExecuted,
38
+ BotUttered,
39
+ DefinePrevUserUtteredFeaturization,
40
+ DialogueStackUpdated,
41
+ Event,
42
+ FlowCancelled,
43
+ FlowCompleted,
44
+ FlowStarted,
45
+ SlotSet,
46
+ )
47
+ from rasa.shared.exceptions import RasaException
48
+ from rasa.utils.common import update_mlflow_log_level
49
+ from rasa.utils.json_utils import SetEncoder
50
+
51
+ if TYPE_CHECKING:
52
+ from rasa.e2e_test.e2e_config import LLMJudgeConfig
53
+
54
+
55
+ structlogger = structlog.get_logger()
56
+
57
+ DEFAULT_THRESHOLD = 0.5
58
+ ELIGIBLE_UTTER_SOURCE_METADATA = [
59
+ "EnterpriseSearchPolicy",
60
+ "ContextualResponseRephraser",
61
+ "IntentlessPolicy",
62
+ ]
63
+
64
+
65
+ class AssertionType(Enum):
66
+ FLOW_STARTED = "flow_started"
67
+ FLOW_COMPLETED = "flow_completed"
68
+ FLOW_CANCELLED = "flow_cancelled"
69
+ PATTERN_CLARIFICATION_CONTAINS = "pattern_clarification_contains"
70
+ ACTION_EXECUTED = "action_executed"
71
+ SLOT_WAS_SET = "slot_was_set"
72
+ SLOT_WAS_NOT_SET = "slot_was_not_set"
73
+ BOT_UTTERED = "bot_uttered"
74
+ BOT_DID_NOT_UTTER = "bot_did_not_utter"
75
+ GENERATIVE_RESPONSE_IS_RELEVANT = "generative_response_is_relevant"
76
+ GENERATIVE_RESPONSE_IS_GROUNDED = "generative_response_is_grounded"
77
+
78
+
79
+ @lru_cache(maxsize=1)
80
+ def _get_all_assertion_subclasses() -> Dict[str, Type[Assertion]]:
81
+ return {
82
+ sub_class.type(): sub_class
83
+ for sub_class in rasa.shared.utils.common.all_subclasses(Assertion)
84
+ }
85
+
86
+
87
+ class InvalidAssertionType(RasaException):
88
+ """Raised if an assertion type is invalid."""
89
+
90
+ def __init__(self, assertion_type: str) -> None:
91
+ """Creates a `InvalidAssertionType`.
92
+
93
+ Args:
94
+ assertion_type: The invalid assertion type.
95
+ """
96
+ super().__init__(f"Invalid assertion type '{assertion_type}'.")
97
+
98
+
99
+ @dataclass
100
+ class Assertion:
101
+ """Base class for storing assertions."""
102
+
103
+ @classmethod
104
+ def type(cls) -> str:
105
+ """Returns the type of the assertion."""
106
+ raise NotImplementedError
107
+
108
+ @staticmethod
109
+ def from_dict(assertion_dict: Dict[Text, Any]) -> Assertion:
110
+ """Creates an assertion from a dictionary."""
111
+ raise NotImplementedError
112
+
113
+ def as_dict(self) -> Dict[str, Any]:
114
+ """Return the `Assertion` as a dictionary.
115
+
116
+ Returns:
117
+ The `Assertion` as a dictionary.
118
+ """
119
+ data = dataclasses.asdict(self)
120
+ data["type"] = self.type()
121
+ return data
122
+
123
+ @staticmethod
124
+ def create_typed_assertion(data: Dict[str, Any]) -> Assertion:
125
+ """Creates a `Assertion` from a dictionary.
126
+
127
+ Args:
128
+ data: The dictionary to create the `Assertion` from.
129
+
130
+ Returns:
131
+ The created `Assertion`.
132
+ """
133
+ typ = next(iter(data.keys()))
134
+
135
+ subclass_mapping = _get_all_assertion_subclasses()
136
+
137
+ clazz = subclass_mapping.get(typ)
138
+
139
+ if clazz is None:
140
+ structlogger.warning("assertion.unknown_type", data=data)
141
+ raise InvalidAssertionType(typ)
142
+
143
+ try:
144
+ return clazz.from_dict(data)
145
+ except NotImplementedError:
146
+ structlogger.warning("assertion.unknown_type", data=data)
147
+ raise InvalidAssertionType(typ)
148
+
149
+ def run(
150
+ self,
151
+ turn_events: List[Event],
152
+ prior_events: List[Event],
153
+ assertion_order_error_message: str = "",
154
+ **kwargs: Any,
155
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
156
+ """Run the assertion on the given events for that user turn.
157
+
158
+ Args:
159
+ turn_events: The events to run the assertion on.
160
+ prior_events: All events prior to the current turn.
161
+ assertion_order_error_message: The error message to append if the assertion
162
+ order is enabled.
163
+ kwargs: Additional keyword arguments.
164
+
165
+ Returns:
166
+ A tuple of the assertion failure and the matching event if the assertion
167
+ passes, otherwise `None`.
168
+ """
169
+ raise NotImplementedError
170
+
171
+ def _generate_assertion_failure(
172
+ self,
173
+ error_message: str,
174
+ prior_events: List[Event],
175
+ turn_events: List[Event],
176
+ line: Optional[int] = None,
177
+ ) -> Tuple[AssertionFailure, None]:
178
+ return AssertionFailure(
179
+ assertion=self,
180
+ error_message=error_message,
181
+ actual_events_transcript=create_actual_events_transcript(
182
+ prior_events, turn_events
183
+ ),
184
+ error_line=line,
185
+ ), None
186
+
187
+
188
+ @dataclass
189
+ class FlowStartedAssertion(Assertion):
190
+ """Class for storing the flow started assertion."""
191
+
192
+ flow_id: str
193
+ line: Optional[int] = None
194
+
195
+ @classmethod
196
+ def type(cls) -> str:
197
+ return AssertionType.FLOW_STARTED.value
198
+
199
+ @staticmethod
200
+ def from_dict(assertion_dict: Dict[Text, Any]) -> FlowStartedAssertion:
201
+ return FlowStartedAssertion(
202
+ flow_id=assertion_dict.get(AssertionType.FLOW_STARTED.value),
203
+ line=assertion_dict.lc.line + 1 if hasattr(assertion_dict, "lc") else None,
204
+ )
205
+
206
+ def run(
207
+ self,
208
+ turn_events: List[Event],
209
+ prior_events: List[Event],
210
+ assertion_order_error_message: str = "",
211
+ **kwargs: Any,
212
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
213
+ """Run the flow started assertion on the given events for that user turn."""
214
+ try:
215
+ matching_event = next(
216
+ event
217
+ for event in turn_events
218
+ if isinstance(event, FlowStarted) and event.flow_id == self.flow_id
219
+ )
220
+ except StopIteration:
221
+ error_message = f"Flow with id '{self.flow_id}' did not start."
222
+ error_message += assertion_order_error_message
223
+
224
+ return self._generate_assertion_failure(
225
+ error_message, prior_events, turn_events, self.line
226
+ )
227
+
228
+ return None, matching_event
229
+
230
+ def __hash__(self) -> int:
231
+ return hash(json.dumps(self.as_dict()))
232
+
233
+
234
+ @dataclass
235
+ class FlowCompletedAssertion(Assertion):
236
+ """Class for storing the flow completed assertion."""
237
+
238
+ flow_id: str
239
+ flow_step_id: Optional[str] = None
240
+ line: Optional[int] = None
241
+
242
+ @classmethod
243
+ def type(cls) -> str:
244
+ return AssertionType.FLOW_COMPLETED.value
245
+
246
+ @staticmethod
247
+ def from_dict(assertion_dict: Dict[Text, Any]) -> FlowCompletedAssertion:
248
+ line = assertion_dict.lc.line + 1 if hasattr(assertion_dict, "lc") else None
249
+ assertion_dict = assertion_dict.get(AssertionType.FLOW_COMPLETED.value, {})
250
+
251
+ return FlowCompletedAssertion(
252
+ flow_id=assertion_dict.get("flow_id"),
253
+ flow_step_id=assertion_dict.get("flow_step_id"),
254
+ line=line,
255
+ )
256
+
257
+ def run(
258
+ self,
259
+ turn_events: List[Event],
260
+ prior_events: List[Event],
261
+ assertion_order_error_message: str = "",
262
+ **kwargs: Any,
263
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
264
+ """Run the flow completed assertion on the given events for that user turn."""
265
+ try:
266
+ matching_event = next(
267
+ event
268
+ for event in turn_events
269
+ if isinstance(event, FlowCompleted) and event.flow_id == self.flow_id
270
+ )
271
+ except StopIteration:
272
+ error_message = f"Flow with id '{self.flow_id}' did not complete."
273
+ error_message += assertion_order_error_message
274
+
275
+ return self._generate_assertion_failure(
276
+ error_message, prior_events, turn_events, self.line
277
+ )
278
+
279
+ if (
280
+ self.flow_step_id is not None
281
+ and matching_event.step_id != self.flow_step_id
282
+ ):
283
+ error_message = (
284
+ f"Flow with id '{self.flow_id}' did not complete "
285
+ f"at expected step id '{self.flow_step_id}'. The actual "
286
+ f"step id was '{matching_event.step_id}'."
287
+ )
288
+ error_message += assertion_order_error_message
289
+ return self._generate_assertion_failure(
290
+ error_message, prior_events, turn_events, self.line
291
+ )
292
+
293
+ return None, matching_event
294
+
295
+ def __hash__(self) -> int:
296
+ return hash(json.dumps(self.as_dict()))
297
+
298
+
299
+ @dataclass
300
+ class FlowCancelledAssertion(Assertion):
301
+ """Class for storing the flow cancelled assertion."""
302
+
303
+ flow_id: str
304
+ flow_step_id: Optional[str] = None
305
+ line: Optional[int] = None
306
+
307
+ @classmethod
308
+ def type(cls) -> str:
309
+ return AssertionType.FLOW_CANCELLED.value
310
+
311
+ @staticmethod
312
+ def from_dict(assertion_dict: Dict[Text, Any]) -> FlowCancelledAssertion:
313
+ line = assertion_dict.lc.line + 1 if hasattr(assertion_dict, "lc") else None
314
+ assertion_dict = assertion_dict.get(AssertionType.FLOW_CANCELLED.value, {})
315
+
316
+ return FlowCancelledAssertion(
317
+ flow_id=assertion_dict.get("flow_id"),
318
+ flow_step_id=assertion_dict.get("flow_step_id"),
319
+ line=line,
320
+ )
321
+
322
+ def run(
323
+ self,
324
+ turn_events: List[Event],
325
+ prior_events: List[Event],
326
+ assertion_order_error_message: str = "",
327
+ **kwargs: Any,
328
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
329
+ """Run the flow cancelled assertion on the given events for that user turn."""
330
+ try:
331
+ matching_event = next(
332
+ event
333
+ for event in turn_events
334
+ if isinstance(event, FlowCancelled) and event.flow_id == self.flow_id
335
+ )
336
+ except StopIteration:
337
+ error_message = f"Flow with id '{self.flow_id}' was not cancelled."
338
+ error_message += assertion_order_error_message
339
+
340
+ return self._generate_assertion_failure(
341
+ error_message, prior_events, turn_events, self.line
342
+ )
343
+
344
+ if (
345
+ self.flow_step_id is not None
346
+ and matching_event.step_id != self.flow_step_id
347
+ ):
348
+ error_message = (
349
+ f"Flow with id '{self.flow_id}' was not cancelled "
350
+ f"at expected step id '{self.flow_step_id}'. The actual "
351
+ f"step id was '{matching_event.step_id}'."
352
+ )
353
+ error_message += assertion_order_error_message
354
+
355
+ return self._generate_assertion_failure(
356
+ error_message, prior_events, turn_events, self.line
357
+ )
358
+
359
+ return None, matching_event
360
+
361
+ def __hash__(self) -> int:
362
+ return hash(json.dumps(self.as_dict()))
363
+
364
+
365
+ @dataclass
366
+ class PatternClarificationContainsAssertion(Assertion):
367
+ """Class for storing the pattern clarification contains assertion."""
368
+
369
+ flow_names: Set[str]
370
+ line: Optional[int] = None
371
+
372
+ @classmethod
373
+ def type(cls) -> str:
374
+ return AssertionType.PATTERN_CLARIFICATION_CONTAINS.value
375
+
376
+ @staticmethod
377
+ def from_dict(
378
+ assertion_dict: Dict[Text, Any],
379
+ ) -> PatternClarificationContainsAssertion:
380
+ return PatternClarificationContainsAssertion(
381
+ flow_names=set(
382
+ assertion_dict.get(
383
+ AssertionType.PATTERN_CLARIFICATION_CONTAINS.value, []
384
+ )
385
+ ),
386
+ line=assertion_dict.lc.line + 1 if hasattr(assertion_dict, "lc") else None,
387
+ )
388
+
389
+ def run(
390
+ self,
391
+ turn_events: List[Event],
392
+ prior_events: List[Event],
393
+ assertion_order_error_message: str = "",
394
+ **kwargs: Any,
395
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
396
+ """Run the flow completed assertion on the given events for that user turn."""
397
+ try:
398
+ matching_event = next(
399
+ event
400
+ for event in turn_events
401
+ if isinstance(event, FlowStarted)
402
+ and event.flow_id == FLOW_PATTERN_CLARIFICATION
403
+ )
404
+ except StopIteration:
405
+ error_message = f"'{FLOW_PATTERN_CLARIFICATION}' pattern did not trigger."
406
+ error_message += assertion_order_error_message
407
+
408
+ return self._generate_assertion_failure(
409
+ error_message, prior_events, turn_events, self.line
410
+ )
411
+
412
+ actual_flow_names = set(matching_event.metadata.get("names", set()))
413
+ if actual_flow_names != self.flow_names:
414
+ error_message = (
415
+ f"'{FLOW_PATTERN_CLARIFICATION}' pattern did not contain "
416
+ f"the expected options. Expected options: {self.flow_names}. "
417
+ )
418
+ error_message += assertion_order_error_message
419
+
420
+ return self._generate_assertion_failure(
421
+ error_message, prior_events, turn_events, self.line
422
+ )
423
+
424
+ return None, matching_event
425
+
426
+ def __hash__(self) -> int:
427
+ return hash(json.dumps(self.as_dict(), cls=SetEncoder))
428
+
429
+
430
+ @dataclass
431
+ class ActionExecutedAssertion(Assertion):
432
+ """Class for storing the action executed assertion."""
433
+
434
+ action_name: str
435
+ line: Optional[int] = None
436
+
437
+ @classmethod
438
+ def type(cls) -> str:
439
+ return AssertionType.ACTION_EXECUTED.value
440
+
441
+ @staticmethod
442
+ def from_dict(assertion_dict: Dict[Text, Any]) -> ActionExecutedAssertion:
443
+ return ActionExecutedAssertion(
444
+ action_name=assertion_dict.get(AssertionType.ACTION_EXECUTED.value),
445
+ line=assertion_dict.lc.line + 1 if hasattr(assertion_dict, "lc") else None,
446
+ )
447
+
448
+ def run(
449
+ self,
450
+ turn_events: List[Event],
451
+ prior_events: List[Event],
452
+ assertion_order_error_message: str = "",
453
+ **kwargs: Any,
454
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
455
+ """Run the action executed assertion on the given events for that user turn."""
456
+ step_index = kwargs.get("step_index")
457
+ original_turn_events, turn_events = _get_turn_events_based_on_step_index(
458
+ step_index, turn_events, prior_events
459
+ )
460
+
461
+ try:
462
+ matching_event = next(
463
+ event
464
+ for event in turn_events
465
+ if isinstance(event, ActionExecuted)
466
+ and event.action_name == self.action_name
467
+ )
468
+ except StopIteration:
469
+ error_message = f"Action '{self.action_name}' did not execute."
470
+ error_message += assertion_order_error_message
471
+
472
+ return self._generate_assertion_failure(
473
+ error_message, prior_events, original_turn_events, self.line
474
+ )
475
+
476
+ return None, matching_event
477
+
478
+ def __hash__(self) -> int:
479
+ return hash(json.dumps(self.as_dict()))
480
+
481
+
482
+ @dataclass
483
+ class AssertedSlot:
484
+ """Class for storing information asserted about slots."""
485
+
486
+ name: str
487
+ value: Any
488
+ line: Optional[int] = None
489
+
490
+ @staticmethod
491
+ def from_dict(slot_dict: Dict[Text, Any]) -> AssertedSlot:
492
+ return AssertedSlot(
493
+ name=slot_dict.get("name"),
494
+ value=slot_dict.get("value", "value key is undefined"),
495
+ line=slot_dict.lc.line + 1 if hasattr(slot_dict, "lc") else None,
496
+ )
497
+
498
+
499
+ @dataclass
500
+ class SlotWasSetAssertion(Assertion):
501
+ """Class for storing the slot was set assertion."""
502
+
503
+ slots: List[AssertedSlot]
504
+
505
+ @classmethod
506
+ def type(cls) -> str:
507
+ return AssertionType.SLOT_WAS_SET.value
508
+
509
+ @staticmethod
510
+ def from_dict(assertion_dict: Dict[Text, Any]) -> SlotWasSetAssertion:
511
+ return SlotWasSetAssertion(
512
+ slots=[
513
+ AssertedSlot.from_dict(slot)
514
+ for slot in assertion_dict.get(AssertionType.SLOT_WAS_SET.value, [])
515
+ ],
516
+ )
517
+
518
+ def run(
519
+ self,
520
+ turn_events: List[Event],
521
+ prior_events: List[Event],
522
+ assertion_order_error_message: str = "",
523
+ **kwargs: Any,
524
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
525
+ """Run the slot_was_set assertion on the given events for that user turn."""
526
+ matching_event = None
527
+
528
+ step_index = kwargs.get("step_index")
529
+ original_turn_events, turn_events = _get_turn_events_based_on_step_index(
530
+ step_index, turn_events, prior_events
531
+ )
532
+
533
+ for slot in self.slots:
534
+ matching_events = [
535
+ event
536
+ for event in turn_events
537
+ if isinstance(event, SlotSet) and event.key == slot.name
538
+ ]
539
+ if not matching_events:
540
+ error_message = f"Slot '{slot.name}' was not set."
541
+ error_message += assertion_order_error_message
542
+
543
+ return self._generate_assertion_failure(
544
+ error_message, prior_events, turn_events, slot.line
545
+ )
546
+
547
+ if slot.value == "value key is undefined":
548
+ matching_event = matching_events[0]
549
+ structlogger.debug(
550
+ "slot_was_set_assertion.run",
551
+ last_event_seen=matching_event,
552
+ event_info="Slot value is not asserted and we have "
553
+ "multiple events for the same slot. "
554
+ "We will mark the first event as last event seen.",
555
+ )
556
+ continue
557
+
558
+ try:
559
+ matching_event = next(
560
+ event for event in matching_events if event.value == slot.value
561
+ )
562
+ except StopIteration:
563
+ error_message = (
564
+ f"Slot '{slot.name}' was set to a different value "
565
+ f"'{matching_events[-1].value}' than the "
566
+ f"expected '{slot.value}' value."
567
+ )
568
+ error_message += assertion_order_error_message
569
+
570
+ return self._generate_assertion_failure(
571
+ error_message, prior_events, original_turn_events, slot.line
572
+ )
573
+
574
+ return None, matching_event
575
+
576
+ def __hash__(self) -> int:
577
+ return hash(json.dumps(self.as_dict()))
578
+
579
+
580
+ @dataclass
581
+ class SlotWasNotSetAssertion(Assertion):
582
+ """Class for storing the slot was not set assertion."""
583
+
584
+ slots: List[AssertedSlot]
585
+
586
+ @classmethod
587
+ def type(cls) -> str:
588
+ return AssertionType.SLOT_WAS_NOT_SET.value
589
+
590
+ @staticmethod
591
+ def from_dict(assertion_dict: Dict[Text, Any]) -> SlotWasNotSetAssertion:
592
+ return SlotWasNotSetAssertion(
593
+ slots=[
594
+ AssertedSlot.from_dict(slot)
595
+ for slot in assertion_dict.get(AssertionType.SLOT_WAS_NOT_SET.value, [])
596
+ ]
597
+ )
598
+
599
+ def run(
600
+ self,
601
+ turn_events: List[Event],
602
+ prior_events: List[Event],
603
+ assertion_order_error_message: str = "",
604
+ **kwargs: Any,
605
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
606
+ """Run the slot_was_not_set assertion on the given events for that user turn."""
607
+ matching_event = None
608
+
609
+ step_index = kwargs.get("step_index")
610
+ original_turn_events, turn_events = _get_turn_events_based_on_step_index(
611
+ step_index, turn_events, prior_events
612
+ )
613
+
614
+ for slot in self.slots:
615
+ matching_events = [
616
+ event
617
+ for event in turn_events
618
+ if isinstance(event, SlotSet) and event.key == slot.name
619
+ ]
620
+ if not matching_events:
621
+ continue
622
+
623
+ # take the most recent event in the list of matching events
624
+ # since that is the final value in the tracker for that user turn
625
+ matching_event = matching_events[-1]
626
+
627
+ if (
628
+ slot.value == "value key is undefined"
629
+ and matching_event.value is not None
630
+ ):
631
+ error_message = (
632
+ f"Slot '{slot.name}' was set to '{matching_event.value}' but "
633
+ f"it should not have been set."
634
+ )
635
+ error_message += assertion_order_error_message
636
+
637
+ return self._generate_assertion_failure(
638
+ error_message, prior_events, turn_events, slot.line
639
+ )
640
+
641
+ if matching_event.value == slot.value:
642
+ error_message = (
643
+ f"Slot '{slot.name}' was set to '{slot.value}' "
644
+ f"but it should not have been set."
645
+ )
646
+ error_message += assertion_order_error_message
647
+
648
+ return self._generate_assertion_failure(
649
+ error_message, prior_events, original_turn_events, slot.line
650
+ )
651
+
652
+ return None, matching_event
653
+
654
+ def __hash__(self) -> int:
655
+ return hash(json.dumps(self.as_dict()))
656
+
657
+
658
+ @dataclass
659
+ class AssertedButton:
660
+ """Class for storing information asserted about buttons."""
661
+
662
+ title: str
663
+ payload: Optional[str] = None
664
+
665
+ @staticmethod
666
+ def from_dict(button_dict: Dict[Text, Any]) -> AssertedButton:
667
+ return AssertedButton(
668
+ title=button_dict.get("title"),
669
+ payload=button_dict.get("payload"),
670
+ )
671
+
672
+
673
+ @dataclass
674
+ class BotUtteredAssertion(Assertion):
675
+ """Class for storing the bot uttered assertion."""
676
+
677
+ utter_name: Optional[str] = None
678
+ text_matches: Optional[str] = None
679
+ buttons: Optional[List[AssertedButton]] = None
680
+ line: Optional[int] = None
681
+
682
+ @classmethod
683
+ def type(cls) -> str:
684
+ return AssertionType.BOT_UTTERED.value
685
+
686
+ @staticmethod
687
+ def from_dict(assertion_dict: Dict[Text, Any]) -> BotUtteredAssertion:
688
+ utter_name, text_matches, buttons = (
689
+ BotUtteredAssertion._extract_assertion_properties(assertion_dict)
690
+ )
691
+
692
+ if BotUtteredAssertion._assertion_is_empty(utter_name, text_matches, buttons):
693
+ raise RasaException(
694
+ "A 'bot_uttered' assertion is empty, it should contain at least one "
695
+ "of the allowed properties: 'utter_name', 'text_matches', 'buttons'."
696
+ )
697
+
698
+ return BotUtteredAssertion(
699
+ utter_name=utter_name,
700
+ text_matches=text_matches,
701
+ buttons=buttons,
702
+ line=assertion_dict.lc.line + 1 if hasattr(assertion_dict, "lc") else None,
703
+ )
704
+
705
+ @staticmethod
706
+ def _extract_assertion_properties(
707
+ assertion_dict: Dict[Text, Any],
708
+ ) -> Tuple[Optional[str], Optional[str], List[AssertedButton]]:
709
+ """Extracts the assertion properties from a dictionary."""
710
+ assertion_dict = assertion_dict.get(AssertionType.BOT_UTTERED.value, {})
711
+ utter_name = assertion_dict.get("utter_name")
712
+ text_matches = assertion_dict.get("text_matches")
713
+ buttons = [
714
+ AssertedButton.from_dict(button)
715
+ for button in assertion_dict.get("buttons", [])
716
+ ]
717
+
718
+ return utter_name, text_matches, buttons
719
+
720
+ @staticmethod
721
+ def _assertion_is_empty(
722
+ utter_name: Optional[str],
723
+ text_matches: Optional[str],
724
+ buttons: List[AssertedButton],
725
+ ) -> bool:
726
+ """Validate if the bot uttered assertion is empty."""
727
+ if not utter_name and not text_matches and not buttons:
728
+ return True
729
+
730
+ return False
731
+
732
+ def run(
733
+ self,
734
+ turn_events: List[Event],
735
+ prior_events: List[Event],
736
+ assertion_order_error_message: str = "",
737
+ **kwargs: Any,
738
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
739
+ """Run the bot_uttered assertion on the given events for that user turn."""
740
+ matching_event = None
741
+ error_messages = []
742
+
743
+ step_index = kwargs.get("step_index")
744
+ original_turn_events, turn_events = _get_turn_events_based_on_step_index(
745
+ step_index, turn_events, prior_events
746
+ )
747
+
748
+ if self.utter_name is not None:
749
+ try:
750
+ matching_event = next(
751
+ event
752
+ for event in turn_events
753
+ if isinstance(event, BotUttered)
754
+ and event.metadata.get("utter_action") == self.utter_name
755
+ )
756
+ except StopIteration:
757
+ error_messages.append(
758
+ f"Bot did not utter '{self.utter_name}' response."
759
+ )
760
+
761
+ if self.text_matches is not None:
762
+ pattern = re.compile(self.text_matches)
763
+ try:
764
+ matching_event = next(
765
+ event
766
+ for event in turn_events
767
+ if isinstance(event, BotUttered) and pattern.search(event.text)
768
+ )
769
+ except StopIteration:
770
+ error_messages.append(
771
+ f"Bot did not utter any response which "
772
+ f"matches the provided text pattern "
773
+ f"'{self.text_matches}'."
774
+ )
775
+
776
+ if self.buttons:
777
+ try:
778
+ matching_event = next(
779
+ event
780
+ for event in turn_events
781
+ if isinstance(event, BotUttered) and self._buttons_match(event)
782
+ )
783
+ except StopIteration:
784
+ error_messages.append(
785
+ "Bot did not utter any response with the expected buttons."
786
+ )
787
+
788
+ if error_messages:
789
+ error_message = " ".join(error_messages)
790
+ error_message += assertion_order_error_message
791
+ return self._generate_assertion_failure(
792
+ error_message, prior_events, original_turn_events, self.line
793
+ )
794
+
795
+ return None, matching_event
796
+
797
+ def _buttons_match(self, event: BotUttered) -> bool:
798
+ """Check if the bot response contains the expected buttons."""
799
+ # a button is a dictionary with keys 'title' and 'payload'
800
+ actual_buttons = event.data.get("buttons", [])
801
+ if not actual_buttons:
802
+ return False
803
+
804
+ return all(
805
+ self._button_matches(actual_button, expected_button)
806
+ for actual_button, expected_button in zip(actual_buttons, self.buttons)
807
+ )
808
+
809
+ @staticmethod
810
+ def _button_matches(
811
+ actual_button: Dict[str, Any], expected_button: AssertedButton
812
+ ) -> bool:
813
+ """Check if the actual button matches the expected button."""
814
+ return (
815
+ actual_button.get("title") == expected_button.title
816
+ and actual_button.get("payload") == expected_button.payload
817
+ )
818
+
819
+ def __hash__(self) -> int:
820
+ return hash(json.dumps(self.as_dict()))
821
+
822
+
823
+ @dataclass
824
+ class BotDidNotUtterAssertion(Assertion):
825
+ """Class for the 'bot_did_not_utter' assertion."""
826
+
827
+ utter_name: Optional[str] = None
828
+ text_matches: Optional[str] = None
829
+ buttons: Optional[List[AssertedButton]] = None
830
+ line: Optional[int] = None
831
+
832
+ @classmethod
833
+ def type(cls) -> str:
834
+ return AssertionType.BOT_DID_NOT_UTTER.value
835
+
836
+ @staticmethod
837
+ def from_dict(assertion_dict: Dict[Text, Any]) -> BotDidNotUtterAssertion:
838
+ """Creates a BotDidNotUtterAssertion from a dictionary."""
839
+ assertion_dict = assertion_dict.get(AssertionType.BOT_DID_NOT_UTTER.value, {})
840
+ utter_name = assertion_dict.get("utter_name")
841
+ text_matches = assertion_dict.get("text_matches")
842
+ buttons = [
843
+ AssertedButton.from_dict(button)
844
+ for button in assertion_dict.get("buttons", [])
845
+ ]
846
+
847
+ if not utter_name and not text_matches and not buttons:
848
+ raise RasaException(
849
+ "A 'bot_did_not_utter' assertion is empty. "
850
+ "It should contain at least one of the allowed properties: "
851
+ "'utter_name', 'text_matches', or 'buttons'."
852
+ )
853
+
854
+ return BotDidNotUtterAssertion(
855
+ utter_name=utter_name,
856
+ text_matches=text_matches,
857
+ buttons=buttons,
858
+ line=assertion_dict.lc.line + 1 if hasattr(assertion_dict, "lc") else None,
859
+ )
860
+
861
+ def run(
862
+ self,
863
+ turn_events: List[Event],
864
+ prior_events: List[Event],
865
+ assertion_order_error_message: str = "",
866
+ **kwargs: Any,
867
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
868
+ """Checks that the bot did not utter the specified messages or buttons."""
869
+ step_index = kwargs.get("step_index")
870
+ original_turn_events, turn_events = _get_turn_events_based_on_step_index(
871
+ step_index, turn_events, prior_events
872
+ )
873
+
874
+ for event in turn_events:
875
+ if isinstance(event, BotUttered):
876
+ error_messages = []
877
+ if self._utter_name_matches(event):
878
+ error_messages.append(
879
+ f"Bot uttered a forbidden utterance '{self.utter_name}'."
880
+ )
881
+ if self._text_matches(event):
882
+ error_messages.append(
883
+ f"Bot uttered a forbidden message matching "
884
+ f"the pattern '{self.text_matches}'."
885
+ )
886
+ if self._buttons_match(event):
887
+ error_messages.append(
888
+ "Bot uttered a forbidden response with specified buttons."
889
+ )
890
+
891
+ if error_messages:
892
+ error_message = " ".join(error_messages)
893
+ error_message += assertion_order_error_message
894
+ return self._generate_assertion_failure(
895
+ error_message, prior_events, original_turn_events, self.line
896
+ )
897
+ return None, None
898
+
899
+ def _utter_name_matches(self, event: BotUttered) -> bool:
900
+ if self.utter_name is not None:
901
+ if event.metadata.get("utter_action") == self.utter_name:
902
+ return True
903
+ return False
904
+
905
+ def _text_matches(self, event: BotUttered) -> bool:
906
+ if self.text_matches is not None:
907
+ pattern = re.compile(self.text_matches)
908
+ if pattern.search(event.text):
909
+ return True
910
+ return False
911
+
912
+ def _buttons_match(self, event: BotUttered) -> bool:
913
+ """Check if the bot response contains any of the forbidden buttons."""
914
+ if self.buttons is None:
915
+ return False
916
+
917
+ actual_buttons = event.data.get("buttons", [])
918
+ if not actual_buttons:
919
+ return False
920
+
921
+ for actual_button in actual_buttons:
922
+ if any(
923
+ self._is_forbidden_button(actual_button, forbidden_button)
924
+ for forbidden_button in self.buttons
925
+ ):
926
+ return True
927
+ return False
928
+
929
+ @staticmethod
930
+ def _is_forbidden_button(
931
+ actual_button: Dict[str, Any], forbidden_button: AssertedButton
932
+ ) -> bool:
933
+ """Check if the button matches any of the forbidden buttons."""
934
+ actual_title = actual_button.get("title")
935
+ actual_payload = actual_button.get("payload")
936
+
937
+ title_matches = forbidden_button.title == actual_title
938
+ payload_matches = forbidden_button.payload == actual_payload
939
+ if title_matches and payload_matches:
940
+ return True
941
+ return False
942
+
943
+ def __hash__(self) -> int:
944
+ """Hash method to ensure the assertion is hashable."""
945
+ return hash(json.dumps(self.as_dict()))
946
+
947
+
948
+ @dataclass
949
+ class GenerativeResponseMixin(Assertion):
950
+ """Mixin class for storing generative response assertions."""
951
+
952
+ threshold: float = DEFAULT_THRESHOLD
953
+ utter_name: Optional[str] = None
954
+ line: Optional[int] = None
955
+ metric_adjective: Optional[str] = None
956
+ metric_name: Optional[str] = None
957
+ mlflow_metric: Callable = print
958
+
959
+ @classmethod
960
+ def type(cls) -> str:
961
+ return ""
962
+
963
+ def _get_ground_truth(self, matching_event: BotUttered) -> str:
964
+ raise NotImplementedError
965
+
966
+ def as_dict(self) -> Dict[str, Any]:
967
+ data = super().as_dict()
968
+ data.pop("metric_name")
969
+ data.pop("metric_adjective")
970
+ data.pop("mlflow_metric")
971
+
972
+ return data
973
+
974
+ def _run_llm_evaluation(
975
+ self,
976
+ matching_event: BotUttered,
977
+ step_text: str,
978
+ llm_judge_config: "LLMJudgeConfig",
979
+ assertion_order_error_message: str,
980
+ prior_events: List[Event],
981
+ turn_events: List[Event],
982
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
983
+ """Run the LLM evaluation on the given event."""
984
+ import mlflow
985
+
986
+ # we need to configure the log level for mlflow
987
+ # after a local import to avoid unnecessary logs
988
+ update_mlflow_log_level()
989
+
990
+ # extract user question from event if available
991
+ user_question_from_event = matching_event.metadata.get(
992
+ SEARCH_QUERY_METADATA_KEY
993
+ )
994
+ user_question = (
995
+ user_question_from_event if user_question_from_event else step_text
996
+ )
997
+
998
+ ground_truth = self._get_ground_truth(matching_event)
999
+
1000
+ eval_data = pd.DataFrame(
1001
+ {
1002
+ "inputs": [user_question],
1003
+ "ground_truth": [ground_truth],
1004
+ "predictions": [matching_event.text],
1005
+ }
1006
+ )
1007
+
1008
+ model_uri = llm_judge_config.get_model_uri()
1009
+
1010
+ structlogger.debug(
1011
+ f"generative_response_is_{self.metric_adjective}_assertion.run_llm_evaluation",
1012
+ model_uri=model_uri,
1013
+ )
1014
+
1015
+ with mlflow.start_run():
1016
+ results = mlflow.evaluate(
1017
+ data=eval_data,
1018
+ targets="ground_truth",
1019
+ predictions="predictions",
1020
+ model_type="question-answering",
1021
+ evaluators="default",
1022
+ extra_metrics=[
1023
+ self.mlflow_metric(model_uri),
1024
+ ],
1025
+ )
1026
+
1027
+ # Evaluation result for each data record is available in `results.tables`.
1028
+ eval_table = results.tables["eval_results_table"]
1029
+ score = eval_table.iloc[0][f"{self.metric_name}/v1/score"]
1030
+ justification = eval_table.iloc[0][f"{self.metric_name}/v1/justification"]
1031
+
1032
+ # convert 1-5 score to 0-1 float
1033
+ score = score * 20 / 100 if score is not None else 0
1034
+
1035
+ structlogger.debug(
1036
+ f"generative_response_is_{self.metric_adjective}_assertion.run_results",
1037
+ matching_event=repr(matching_event),
1038
+ score=score,
1039
+ justification=justification,
1040
+ )
1041
+
1042
+ if score < self.threshold:
1043
+ error_message = (
1044
+ f"Generative response '{matching_event.text}' "
1045
+ f"given to the user input '{user_question}' "
1046
+ f"was not {self.metric_adjective}. "
1047
+ f"Expected score to be above '{self.threshold}' threshold, "
1048
+ f"but was '{score}'. The explanation for this score is: "
1049
+ f"{justification}."
1050
+ )
1051
+ error_message += assertion_order_error_message
1052
+
1053
+ return self._generate_assertion_failure(
1054
+ error_message, prior_events, turn_events, self.line
1055
+ )
1056
+
1057
+ return None, matching_event
1058
+
1059
+ def _run_assertion_with_utter_name(
1060
+ self,
1061
+ matching_events: List[BotUttered],
1062
+ step_text: str,
1063
+ llm_judge_config: "LLMJudgeConfig",
1064
+ assertion_order_error_message: str,
1065
+ prior_events: List[Event],
1066
+ turn_events: List[Event],
1067
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
1068
+ """Assert metric for the given utter name."""
1069
+ try:
1070
+ matching_event = next(
1071
+ event
1072
+ for event in matching_events
1073
+ if event.metadata.get("utter_action") == self.utter_name
1074
+ )
1075
+ except StopIteration:
1076
+ error_message = f"Bot did not utter '{self.utter_name}' response."
1077
+ error_message += assertion_order_error_message
1078
+
1079
+ return self._generate_assertion_failure(
1080
+ error_message, prior_events, turn_events, self.line
1081
+ )
1082
+
1083
+ return self._run_llm_evaluation(
1084
+ matching_event,
1085
+ step_text,
1086
+ llm_judge_config,
1087
+ assertion_order_error_message,
1088
+ prior_events,
1089
+ turn_events,
1090
+ )
1091
+
1092
+ def _run_assertion_for_multiple_generative_responses(
1093
+ self,
1094
+ matching_events: List[BotUttered],
1095
+ step_text: str,
1096
+ llm_judge_config: "LLMJudgeConfig",
1097
+ assertion_order_error_message: str,
1098
+ prior_events: List[Event],
1099
+ turn_events: List[Event],
1100
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
1101
+ """Run LLM evaluation for multiple bot utterances."""
1102
+ structlogger.debug(
1103
+ f"generative_response_is_{self.metric_adjective}_assertion.run",
1104
+ event_info="Multiple generative responses found, "
1105
+ "we will evaluate each of the responses.",
1106
+ )
1107
+
1108
+ passing_events = set()
1109
+ for event in matching_events:
1110
+ failure, event_result = self._run_llm_evaluation(
1111
+ event,
1112
+ step_text,
1113
+ llm_judge_config,
1114
+ assertion_order_error_message,
1115
+ prior_events,
1116
+ turn_events,
1117
+ )
1118
+ if event_result is not None:
1119
+ passing_events.add(event_result)
1120
+ else:
1121
+ if not passing_events:
1122
+ error_message = (
1123
+ f"None of the generative responses issued by either the "
1124
+ f"Enterprise Search Policy, IntentlessPolicy or the "
1125
+ f"Contextual Response Rephraser were {self.metric_adjective}."
1126
+ )
1127
+ error_message += assertion_order_error_message
1128
+
1129
+ return self._generate_assertion_failure(
1130
+ error_message, prior_events, turn_events, self.line
1131
+ )
1132
+
1133
+ return None, list(passing_events)[-1]
1134
+
1135
+ def run(
1136
+ self,
1137
+ turn_events: List[Event],
1138
+ prior_events: List[Event],
1139
+ assertion_order_error_message: str = "",
1140
+ llm_judge_config: Optional["LLMJudgeConfig"] = None,
1141
+ step_text: Optional[str] = None,
1142
+ **kwargs: Any,
1143
+ ) -> Tuple[Optional[AssertionFailure], Optional[Event]]:
1144
+ """Run the LLM evaluation on the given events for that user turn."""
1145
+ matching_events: List[BotUttered] = _find_matching_generative_events(
1146
+ turn_events
1147
+ )
1148
+
1149
+ if not matching_events:
1150
+ error_message = (
1151
+ "No generative response issued by either the Enterprise Search Policy, "
1152
+ "IntentlessPolicy or the Contextual Response Rephraser was found, "
1153
+ "but one was expected."
1154
+ )
1155
+ error_message += assertion_order_error_message
1156
+
1157
+ return self._generate_assertion_failure(
1158
+ error_message, prior_events, turn_events, self.line
1159
+ )
1160
+
1161
+ if self.utter_name is not None:
1162
+ return self._run_assertion_with_utter_name(
1163
+ matching_events,
1164
+ step_text,
1165
+ llm_judge_config,
1166
+ assertion_order_error_message,
1167
+ prior_events,
1168
+ turn_events,
1169
+ )
1170
+
1171
+ if len(matching_events) > 1:
1172
+ return self._run_assertion_for_multiple_generative_responses(
1173
+ matching_events,
1174
+ step_text,
1175
+ llm_judge_config,
1176
+ assertion_order_error_message,
1177
+ prior_events,
1178
+ turn_events,
1179
+ )
1180
+
1181
+ matching_event = matching_events[0]
1182
+
1183
+ return self._run_llm_evaluation(
1184
+ matching_event,
1185
+ step_text,
1186
+ llm_judge_config,
1187
+ assertion_order_error_message,
1188
+ prior_events,
1189
+ turn_events,
1190
+ )
1191
+
1192
+
1193
+ @dataclass
1194
+ class GenerativeResponseIsRelevantAssertion(GenerativeResponseMixin):
1195
+ """Class for storing the generative response is relevant assertion."""
1196
+
1197
+ def _get_ground_truth(self, matching_event: BotUttered) -> str:
1198
+ return ""
1199
+
1200
+ @classmethod
1201
+ def type(cls) -> str:
1202
+ return AssertionType.GENERATIVE_RESPONSE_IS_RELEVANT.value
1203
+
1204
+ @staticmethod
1205
+ def from_dict(
1206
+ assertion_dict: Dict[Text, Any],
1207
+ ) -> GenerativeResponseIsRelevantAssertion:
1208
+ import mlflow
1209
+
1210
+ assertion_dict = assertion_dict.get(
1211
+ AssertionType.GENERATIVE_RESPONSE_IS_RELEVANT.value, {}
1212
+ )
1213
+ return GenerativeResponseIsRelevantAssertion(
1214
+ threshold=assertion_dict.get("threshold", DEFAULT_THRESHOLD),
1215
+ utter_name=assertion_dict.get("utter_name"),
1216
+ line=assertion_dict.lc.line + 1 if hasattr(assertion_dict, "lc") else None,
1217
+ metric_name="answer_relevance",
1218
+ metric_adjective="relevant",
1219
+ mlflow_metric=mlflow.metrics.genai.answer_relevance,
1220
+ )
1221
+
1222
+ def __hash__(self) -> int:
1223
+ return hash(json.dumps(self.as_dict()))
1224
+
1225
+
1226
+ @dataclass
1227
+ class GenerativeResponseIsGroundedAssertion(GenerativeResponseMixin):
1228
+ """Class for storing the generative response is grounded assertion."""
1229
+
1230
+ ground_truth: Optional[str] = None
1231
+
1232
+ @classmethod
1233
+ def type(cls) -> str:
1234
+ return AssertionType.GENERATIVE_RESPONSE_IS_GROUNDED.value
1235
+
1236
+ @staticmethod
1237
+ def from_dict(
1238
+ assertion_dict: Dict[Text, Any],
1239
+ ) -> GenerativeResponseIsGroundedAssertion:
1240
+ import mlflow
1241
+
1242
+ assertion_dict = assertion_dict.get(
1243
+ AssertionType.GENERATIVE_RESPONSE_IS_GROUNDED.value, {}
1244
+ )
1245
+ return GenerativeResponseIsGroundedAssertion(
1246
+ threshold=assertion_dict.get("threshold", DEFAULT_THRESHOLD),
1247
+ utter_name=assertion_dict.get("utter_name"),
1248
+ ground_truth=assertion_dict.get("ground_truth"),
1249
+ line=assertion_dict.lc.line + 1 if hasattr(assertion_dict, "lc") else None,
1250
+ metric_name="answer_correctness",
1251
+ metric_adjective="grounded",
1252
+ mlflow_metric=mlflow.metrics.genai.answer_correctness,
1253
+ )
1254
+
1255
+ def __hash__(self) -> int:
1256
+ return hash(json.dumps(self.as_dict()))
1257
+
1258
+ def _get_ground_truth(self, matching_event: BotUttered) -> str:
1259
+ # extract ground truth from event if available or use the provided ground truth
1260
+ ground_truth_event_metadata = matching_event.metadata.get(
1261
+ SEARCH_RESULTS_METADATA_KEY, ""
1262
+ ) or matching_event.metadata.get(DOMAIN_GROUND_TRUTH_METADATA_KEY, "")
1263
+
1264
+ if isinstance(ground_truth_event_metadata, list):
1265
+ ground_truth_event_metadata = "\n".join(ground_truth_event_metadata)
1266
+
1267
+ ground_truth = (
1268
+ self.ground_truth
1269
+ if self.ground_truth is not None
1270
+ else ground_truth_event_metadata
1271
+ )
1272
+
1273
+ return ground_truth
1274
+
1275
+
1276
+ @dataclass
1277
+ class AssertionFailure:
1278
+ """Class for storing the assertion failure."""
1279
+
1280
+ assertion: Assertion
1281
+ error_message: Text
1282
+ actual_events_transcript: List[Text]
1283
+ error_line: Optional[int] = None
1284
+
1285
+ def as_dict(self) -> Dict[Text, Any]:
1286
+ """Returns the assertion failure as a dictionary."""
1287
+ return {
1288
+ "assertion": self.assertion.as_dict(),
1289
+ "error_message": self.error_message,
1290
+ "actual_events_transcript": self.actual_events_transcript,
1291
+ }
1292
+
1293
+
1294
+ def create_actual_events_transcript(
1295
+ prior_events: List[Event], turn_events: List[Event]
1296
+ ) -> List[Text]:
1297
+ """Create the actual events transcript for the assertion failure."""
1298
+ all_events = prior_events + turn_events
1299
+
1300
+ event_transcript = []
1301
+
1302
+ for event in all_events:
1303
+ if isinstance(event, SlotSet) and event.key in DEFAULT_SLOT_NAMES:
1304
+ continue
1305
+ if isinstance(event, DefinePrevUserUtteredFeaturization):
1306
+ continue
1307
+ if isinstance(event, DialogueStackUpdated):
1308
+ continue
1309
+
1310
+ event_transcript.append(repr(event))
1311
+
1312
+ return event_transcript
1313
+
1314
+
1315
+ def _find_matching_generative_events(turn_events: List[Event]) -> List[BotUttered]:
1316
+ """Find the matching events for the generative response assertions."""
1317
+ return [
1318
+ event
1319
+ for event in turn_events
1320
+ if isinstance(event, BotUttered)
1321
+ and event.metadata.get(UTTER_SOURCE_METADATA_KEY)
1322
+ in ELIGIBLE_UTTER_SOURCE_METADATA
1323
+ ]
1324
+
1325
+
1326
+ def _get_turn_events_based_on_step_index(
1327
+ step_index: int, turn_events: List[Event], prior_events: List[Event]
1328
+ ) -> Tuple[List[Event], List[Event]]:
1329
+ """Get the turn events based on the step index.
1330
+
1331
+ For the first step, we need to include the prior events as well
1332
+ in the same user turn. For the subsequent steps, we only need the
1333
+ events that follow the user uttered event on which the tracker
1334
+ was originally sliced by.
1335
+
1336
+ Returns:
1337
+ List[Event]: The copy of turn_events
1338
+ List[Event]: The turn events based on the step index
1339
+
1340
+ """
1341
+ original_turn_events = turn_events[:]
1342
+ if step_index == 0:
1343
+ return original_turn_events, prior_events + turn_events
1344
+
1345
+ return original_turn_events, turn_events