rasa-pro 3.8.16__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rasa-pro might be problematic. Click here for more details.

Files changed (644) hide show
  1. README.md +380 -0
  2. rasa/__init__.py +10 -0
  3. rasa/__main__.py +151 -0
  4. rasa/anonymization/__init__.py +2 -0
  5. rasa/anonymization/anonymisation_rule_yaml_reader.py +91 -0
  6. rasa/anonymization/anonymization_pipeline.py +287 -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 +117 -0
  11. rasa/api.py +146 -0
  12. rasa/cli/__init__.py +5 -0
  13. rasa/cli/arguments/__init__.py +0 -0
  14. rasa/cli/arguments/data.py +81 -0
  15. rasa/cli/arguments/default_arguments.py +165 -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 +204 -0
  20. rasa/cli/arguments/shell.py +13 -0
  21. rasa/cli/arguments/test.py +211 -0
  22. rasa/cli/arguments/train.py +263 -0
  23. rasa/cli/arguments/visualize.py +34 -0
  24. rasa/cli/arguments/x.py +30 -0
  25. rasa/cli/data.py +292 -0
  26. rasa/cli/e2e_test.py +566 -0
  27. rasa/cli/evaluate.py +222 -0
  28. rasa/cli/export.py +251 -0
  29. rasa/cli/inspect.py +63 -0
  30. rasa/cli/interactive.py +164 -0
  31. rasa/cli/license.py +65 -0
  32. rasa/cli/markers.py +78 -0
  33. rasa/cli/project_templates/__init__.py +0 -0
  34. rasa/cli/project_templates/calm/actions/__init__.py +0 -0
  35. rasa/cli/project_templates/calm/actions/action_template.py +27 -0
  36. rasa/cli/project_templates/calm/actions/add_contact.py +30 -0
  37. rasa/cli/project_templates/calm/actions/db.py +57 -0
  38. rasa/cli/project_templates/calm/actions/list_contacts.py +22 -0
  39. rasa/cli/project_templates/calm/actions/remove_contact.py +35 -0
  40. rasa/cli/project_templates/calm/config.yml +12 -0
  41. rasa/cli/project_templates/calm/credentials.yml +33 -0
  42. rasa/cli/project_templates/calm/data/flows/add_contact.yml +31 -0
  43. rasa/cli/project_templates/calm/data/flows/list_contacts.yml +14 -0
  44. rasa/cli/project_templates/calm/data/flows/remove_contact.yml +29 -0
  45. rasa/cli/project_templates/calm/db/contacts.json +10 -0
  46. rasa/cli/project_templates/calm/domain/add_contact.yml +33 -0
  47. rasa/cli/project_templates/calm/domain/list_contacts.yml +14 -0
  48. rasa/cli/project_templates/calm/domain/remove_contact.yml +31 -0
  49. rasa/cli/project_templates/calm/domain/shared.yml +5 -0
  50. rasa/cli/project_templates/calm/e2e_tests/cancelations/user_cancels_during_a_correction.yml +16 -0
  51. rasa/cli/project_templates/calm/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +7 -0
  52. rasa/cli/project_templates/calm/e2e_tests/corrections/user_corrects_contact_handle.yml +20 -0
  53. rasa/cli/project_templates/calm/e2e_tests/corrections/user_corrects_contact_name.yml +19 -0
  54. rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +15 -0
  55. rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_lists_contacts.yml +5 -0
  56. rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_removes_contact.yml +11 -0
  57. rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_removes_contact_from_list.yml +12 -0
  58. rasa/cli/project_templates/calm/endpoints.yml +45 -0
  59. rasa/cli/project_templates/default/actions/__init__.py +0 -0
  60. rasa/cli/project_templates/default/actions/actions.py +27 -0
  61. rasa/cli/project_templates/default/config.yml +44 -0
  62. rasa/cli/project_templates/default/credentials.yml +33 -0
  63. rasa/cli/project_templates/default/data/nlu.yml +91 -0
  64. rasa/cli/project_templates/default/data/rules.yml +13 -0
  65. rasa/cli/project_templates/default/data/stories.yml +30 -0
  66. rasa/cli/project_templates/default/domain.yml +34 -0
  67. rasa/cli/project_templates/default/endpoints.yml +42 -0
  68. rasa/cli/project_templates/default/tests/test_stories.yml +91 -0
  69. rasa/cli/project_templates/tutorial/actions.py +22 -0
  70. rasa/cli/project_templates/tutorial/config.yml +11 -0
  71. rasa/cli/project_templates/tutorial/credentials.yml +33 -0
  72. rasa/cli/project_templates/tutorial/data/flows.yml +8 -0
  73. rasa/cli/project_templates/tutorial/domain.yml +17 -0
  74. rasa/cli/project_templates/tutorial/endpoints.yml +45 -0
  75. rasa/cli/run.py +136 -0
  76. rasa/cli/scaffold.py +268 -0
  77. rasa/cli/shell.py +141 -0
  78. rasa/cli/studio/__init__.py +0 -0
  79. rasa/cli/studio/download.py +51 -0
  80. rasa/cli/studio/studio.py +110 -0
  81. rasa/cli/studio/train.py +59 -0
  82. rasa/cli/studio/upload.py +85 -0
  83. rasa/cli/telemetry.py +90 -0
  84. rasa/cli/test.py +280 -0
  85. rasa/cli/train.py +260 -0
  86. rasa/cli/utils.py +453 -0
  87. rasa/cli/visualize.py +40 -0
  88. rasa/cli/x.py +205 -0
  89. rasa/constants.py +37 -0
  90. rasa/core/__init__.py +17 -0
  91. rasa/core/actions/__init__.py +0 -0
  92. rasa/core/actions/action.py +1450 -0
  93. rasa/core/actions/action_clean_stack.py +59 -0
  94. rasa/core/actions/action_run_slot_rejections.py +207 -0
  95. rasa/core/actions/action_trigger_chitchat.py +31 -0
  96. rasa/core/actions/action_trigger_flow.py +109 -0
  97. rasa/core/actions/action_trigger_search.py +31 -0
  98. rasa/core/actions/constants.py +2 -0
  99. rasa/core/actions/forms.py +737 -0
  100. rasa/core/actions/loops.py +111 -0
  101. rasa/core/actions/two_stage_fallback.py +186 -0
  102. rasa/core/agent.py +557 -0
  103. rasa/core/auth_retry_tracker_store.py +122 -0
  104. rasa/core/brokers/__init__.py +0 -0
  105. rasa/core/brokers/broker.py +126 -0
  106. rasa/core/brokers/file.py +58 -0
  107. rasa/core/brokers/kafka.py +322 -0
  108. rasa/core/brokers/pika.py +387 -0
  109. rasa/core/brokers/sql.py +86 -0
  110. rasa/core/channels/__init__.py +55 -0
  111. rasa/core/channels/audiocodes.py +463 -0
  112. rasa/core/channels/botframework.py +339 -0
  113. rasa/core/channels/callback.py +85 -0
  114. rasa/core/channels/channel.py +419 -0
  115. rasa/core/channels/console.py +243 -0
  116. rasa/core/channels/development_inspector.py +93 -0
  117. rasa/core/channels/facebook.py +422 -0
  118. rasa/core/channels/hangouts.py +335 -0
  119. rasa/core/channels/inspector/.eslintrc.cjs +25 -0
  120. rasa/core/channels/inspector/.gitignore +23 -0
  121. rasa/core/channels/inspector/README.md +54 -0
  122. rasa/core/channels/inspector/assets/favicon.ico +0 -0
  123. rasa/core/channels/inspector/assets/rasa-chat.js +2 -0
  124. rasa/core/channels/inspector/custom.d.ts +3 -0
  125. rasa/core/channels/inspector/dist/assets/arc-5623b6dc.js +1 -0
  126. rasa/core/channels/inspector/dist/assets/array-9f3ba611.js +1 -0
  127. rasa/core/channels/inspector/dist/assets/c4Diagram-d0fbc5ce-685c106a.js +10 -0
  128. rasa/core/channels/inspector/dist/assets/classDiagram-936ed81e-8cbed007.js +2 -0
  129. rasa/core/channels/inspector/dist/assets/classDiagram-v2-c3cb15f1-5889cf12.js +2 -0
  130. rasa/core/channels/inspector/dist/assets/createText-62fc7601-24c249d7.js +7 -0
  131. rasa/core/channels/inspector/dist/assets/edges-f2ad444c-7dd06a75.js +4 -0
  132. rasa/core/channels/inspector/dist/assets/erDiagram-9d236eb7-62c1e54c.js +51 -0
  133. rasa/core/channels/inspector/dist/assets/flowDb-1972c806-ce49b86f.js +6 -0
  134. rasa/core/channels/inspector/dist/assets/flowDiagram-7ea5b25a-4067e48f.js +4 -0
  135. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-85583a23.js +1 -0
  136. rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-abe16c3d-59fe4051.js +139 -0
  137. rasa/core/channels/inspector/dist/assets/ganttDiagram-9b5ea136-47e3a43b.js +266 -0
  138. rasa/core/channels/inspector/dist/assets/gitGraphDiagram-99d0ae7c-5a2ac0d9.js +70 -0
  139. rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-128cfa44.ttf +0 -0
  140. rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-21dbcb97.woff +0 -0
  141. rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-222b5e26.svg +329 -0
  142. rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-9ad89b2a.woff2 +0 -0
  143. rasa/core/channels/inspector/dist/assets/index-268a75c0.js +1040 -0
  144. rasa/core/channels/inspector/dist/assets/index-2c4b9a3b-dfb8efc4.js +1 -0
  145. rasa/core/channels/inspector/dist/assets/index-3ee28881.css +1 -0
  146. rasa/core/channels/inspector/dist/assets/infoDiagram-736b4530-b0c470f2.js +7 -0
  147. rasa/core/channels/inspector/dist/assets/init-77b53fdd.js +1 -0
  148. rasa/core/channels/inspector/dist/assets/journeyDiagram-df861f2b-2edb829a.js +139 -0
  149. rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-60c05ee4.woff +0 -0
  150. rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-8335d9b8.svg +438 -0
  151. rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-9cc39c75.ttf +0 -0
  152. rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-ead13ccf.woff2 +0 -0
  153. rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-16705655.woff2 +0 -0
  154. rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-5aeb07f9.woff +0 -0
  155. rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-9c459044.ttf +0 -0
  156. rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-9e2898a4.svg +435 -0
  157. rasa/core/channels/inspector/dist/assets/layout-b6873d69.js +1 -0
  158. rasa/core/channels/inspector/dist/assets/line-1efc5781.js +1 -0
  159. rasa/core/channels/inspector/dist/assets/linear-661e9b94.js +1 -0
  160. rasa/core/channels/inspector/dist/assets/mindmap-definition-beec6740-2d2e727f.js +109 -0
  161. rasa/core/channels/inspector/dist/assets/ordinal-ba9b4969.js +1 -0
  162. rasa/core/channels/inspector/dist/assets/path-53f90ab3.js +1 -0
  163. rasa/core/channels/inspector/dist/assets/pieDiagram-dbbf0591-9d3ea93d.js +35 -0
  164. rasa/core/channels/inspector/dist/assets/quadrantDiagram-4d7f4fd6-06a178a2.js +7 -0
  165. rasa/core/channels/inspector/dist/assets/requirementDiagram-6fc4c22a-0bfedffc.js +52 -0
  166. rasa/core/channels/inspector/dist/assets/sankeyDiagram-8f13d901-d76d0a04.js +8 -0
  167. rasa/core/channels/inspector/dist/assets/sequenceDiagram-b655622a-37bb4341.js +122 -0
  168. rasa/core/channels/inspector/dist/assets/stateDiagram-59f0c015-f52f7f57.js +1 -0
  169. rasa/core/channels/inspector/dist/assets/stateDiagram-v2-2b26beab-4a986a20.js +1 -0
  170. rasa/core/channels/inspector/dist/assets/styles-080da4f6-7dd9ae12.js +110 -0
  171. rasa/core/channels/inspector/dist/assets/styles-3dcbcfbf-46e1ca14.js +159 -0
  172. rasa/core/channels/inspector/dist/assets/styles-9c745c82-4a97439a.js +207 -0
  173. rasa/core/channels/inspector/dist/assets/svgDrawCommon-4835440b-823917a3.js +1 -0
  174. rasa/core/channels/inspector/dist/assets/timeline-definition-5b62e21b-9ea72896.js +61 -0
  175. rasa/core/channels/inspector/dist/assets/xychartDiagram-2b33534f-b631a8b6.js +7 -0
  176. rasa/core/channels/inspector/dist/index.html +39 -0
  177. rasa/core/channels/inspector/index.html +37 -0
  178. rasa/core/channels/inspector/jest.config.ts +13 -0
  179. rasa/core/channels/inspector/package.json +48 -0
  180. rasa/core/channels/inspector/setupTests.ts +2 -0
  181. rasa/core/channels/inspector/src/App.tsx +170 -0
  182. rasa/core/channels/inspector/src/components/DiagramFlow.tsx +97 -0
  183. rasa/core/channels/inspector/src/components/DialogueInformation.tsx +187 -0
  184. rasa/core/channels/inspector/src/components/DialogueStack.tsx +151 -0
  185. rasa/core/channels/inspector/src/components/ExpandIcon.tsx +16 -0
  186. rasa/core/channels/inspector/src/components/FullscreenButton.tsx +45 -0
  187. rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +19 -0
  188. rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +21 -0
  189. rasa/core/channels/inspector/src/components/RasaLogo.tsx +32 -0
  190. rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +39 -0
  191. rasa/core/channels/inspector/src/components/Slots.tsx +91 -0
  192. rasa/core/channels/inspector/src/components/Welcome.tsx +54 -0
  193. rasa/core/channels/inspector/src/helpers/formatters.test.ts +385 -0
  194. rasa/core/channels/inspector/src/helpers/formatters.ts +239 -0
  195. rasa/core/channels/inspector/src/helpers/utils.ts +42 -0
  196. rasa/core/channels/inspector/src/main.tsx +13 -0
  197. rasa/core/channels/inspector/src/theme/Button/Button.ts +29 -0
  198. rasa/core/channels/inspector/src/theme/Heading/Heading.ts +31 -0
  199. rasa/core/channels/inspector/src/theme/Input/Input.ts +27 -0
  200. rasa/core/channels/inspector/src/theme/Link/Link.ts +10 -0
  201. rasa/core/channels/inspector/src/theme/Modal/Modal.ts +47 -0
  202. rasa/core/channels/inspector/src/theme/Table/Table.tsx +38 -0
  203. rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +12 -0
  204. rasa/core/channels/inspector/src/theme/base/breakpoints.ts +8 -0
  205. rasa/core/channels/inspector/src/theme/base/colors.ts +88 -0
  206. rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +29 -0
  207. rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.eot +0 -0
  208. rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.svg +329 -0
  209. rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.ttf +0 -0
  210. rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.woff +0 -0
  211. rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.woff2 +0 -0
  212. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.eot +0 -0
  213. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.svg +438 -0
  214. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.ttf +0 -0
  215. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.woff +0 -0
  216. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.woff2 +0 -0
  217. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.eot +0 -0
  218. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.svg +435 -0
  219. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.ttf +0 -0
  220. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.woff +0 -0
  221. rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.woff2 +0 -0
  222. rasa/core/channels/inspector/src/theme/base/radii.ts +9 -0
  223. rasa/core/channels/inspector/src/theme/base/shadows.ts +7 -0
  224. rasa/core/channels/inspector/src/theme/base/sizes.ts +7 -0
  225. rasa/core/channels/inspector/src/theme/base/space.ts +15 -0
  226. rasa/core/channels/inspector/src/theme/base/styles.ts +13 -0
  227. rasa/core/channels/inspector/src/theme/base/typography.ts +24 -0
  228. rasa/core/channels/inspector/src/theme/base/zIndices.ts +19 -0
  229. rasa/core/channels/inspector/src/theme/index.ts +101 -0
  230. rasa/core/channels/inspector/src/types.ts +64 -0
  231. rasa/core/channels/inspector/src/vite-env.d.ts +1 -0
  232. rasa/core/channels/inspector/tests/__mocks__/fileMock.ts +1 -0
  233. rasa/core/channels/inspector/tests/__mocks__/matchMedia.ts +16 -0
  234. rasa/core/channels/inspector/tests/__mocks__/styleMock.ts +1 -0
  235. rasa/core/channels/inspector/tests/renderWithProviders.tsx +14 -0
  236. rasa/core/channels/inspector/tsconfig.json +26 -0
  237. rasa/core/channels/inspector/tsconfig.node.json +10 -0
  238. rasa/core/channels/inspector/vite.config.ts +8 -0
  239. rasa/core/channels/inspector/yarn.lock +6156 -0
  240. rasa/core/channels/mattermost.py +229 -0
  241. rasa/core/channels/rasa_chat.py +126 -0
  242. rasa/core/channels/rest.py +210 -0
  243. rasa/core/channels/rocketchat.py +175 -0
  244. rasa/core/channels/slack.py +620 -0
  245. rasa/core/channels/socketio.py +274 -0
  246. rasa/core/channels/telegram.py +298 -0
  247. rasa/core/channels/twilio.py +169 -0
  248. rasa/core/channels/twilio_voice.py +367 -0
  249. rasa/core/channels/vier_cvg.py +374 -0
  250. rasa/core/channels/webexteams.py +135 -0
  251. rasa/core/concurrent_lock_store.py +210 -0
  252. rasa/core/constants.py +107 -0
  253. rasa/core/evaluation/__init__.py +0 -0
  254. rasa/core/evaluation/marker.py +267 -0
  255. rasa/core/evaluation/marker_base.py +925 -0
  256. rasa/core/evaluation/marker_stats.py +294 -0
  257. rasa/core/evaluation/marker_tracker_loader.py +103 -0
  258. rasa/core/exceptions.py +29 -0
  259. rasa/core/exporter.py +284 -0
  260. rasa/core/featurizers/__init__.py +0 -0
  261. rasa/core/featurizers/precomputation.py +410 -0
  262. rasa/core/featurizers/single_state_featurizer.py +402 -0
  263. rasa/core/featurizers/tracker_featurizers.py +1172 -0
  264. rasa/core/http_interpreter.py +89 -0
  265. rasa/core/information_retrieval/__init__.py +0 -0
  266. rasa/core/information_retrieval/faiss.py +116 -0
  267. rasa/core/information_retrieval/information_retrieval.py +72 -0
  268. rasa/core/information_retrieval/milvus.py +59 -0
  269. rasa/core/information_retrieval/qdrant.py +102 -0
  270. rasa/core/jobs.py +63 -0
  271. rasa/core/lock.py +139 -0
  272. rasa/core/lock_store.py +344 -0
  273. rasa/core/migrate.py +404 -0
  274. rasa/core/nlg/__init__.py +3 -0
  275. rasa/core/nlg/callback.py +147 -0
  276. rasa/core/nlg/contextual_response_rephraser.py +270 -0
  277. rasa/core/nlg/generator.py +230 -0
  278. rasa/core/nlg/interpolator.py +143 -0
  279. rasa/core/nlg/response.py +155 -0
  280. rasa/core/nlg/summarize.py +69 -0
  281. rasa/core/policies/__init__.py +0 -0
  282. rasa/core/policies/ensemble.py +329 -0
  283. rasa/core/policies/enterprise_search_policy.py +717 -0
  284. rasa/core/policies/enterprise_search_prompt_template.jinja2 +62 -0
  285. rasa/core/policies/flow_policy.py +205 -0
  286. rasa/core/policies/flows/__init__.py +0 -0
  287. rasa/core/policies/flows/flow_exceptions.py +44 -0
  288. rasa/core/policies/flows/flow_executor.py +582 -0
  289. rasa/core/policies/flows/flow_step_result.py +43 -0
  290. rasa/core/policies/intentless_policy.py +924 -0
  291. rasa/core/policies/intentless_prompt_template.jinja2 +22 -0
  292. rasa/core/policies/memoization.py +538 -0
  293. rasa/core/policies/policy.py +716 -0
  294. rasa/core/policies/rule_policy.py +1276 -0
  295. rasa/core/policies/ted_policy.py +2146 -0
  296. rasa/core/policies/unexpected_intent_policy.py +1015 -0
  297. rasa/core/processor.py +1331 -0
  298. rasa/core/run.py +315 -0
  299. rasa/core/secrets_manager/__init__.py +0 -0
  300. rasa/core/secrets_manager/constants.py +32 -0
  301. rasa/core/secrets_manager/endpoints.py +391 -0
  302. rasa/core/secrets_manager/factory.py +233 -0
  303. rasa/core/secrets_manager/secret_manager.py +262 -0
  304. rasa/core/secrets_manager/vault.py +576 -0
  305. rasa/core/test.py +1337 -0
  306. rasa/core/tracker_store.py +1664 -0
  307. rasa/core/train.py +107 -0
  308. rasa/core/training/__init__.py +89 -0
  309. rasa/core/training/converters/__init__.py +0 -0
  310. rasa/core/training/converters/responses_prefix_converter.py +119 -0
  311. rasa/core/training/interactive.py +1742 -0
  312. rasa/core/training/story_conflict.py +381 -0
  313. rasa/core/training/training.py +93 -0
  314. rasa/core/utils.py +344 -0
  315. rasa/core/visualize.py +70 -0
  316. rasa/dialogue_understanding/__init__.py +0 -0
  317. rasa/dialogue_understanding/coexistence/__init__.py +0 -0
  318. rasa/dialogue_understanding/coexistence/constants.py +4 -0
  319. rasa/dialogue_understanding/coexistence/intent_based_router.py +189 -0
  320. rasa/dialogue_understanding/coexistence/llm_based_router.py +261 -0
  321. rasa/dialogue_understanding/coexistence/router_template.jinja2 +12 -0
  322. rasa/dialogue_understanding/commands/__init__.py +45 -0
  323. rasa/dialogue_understanding/commands/can_not_handle_command.py +61 -0
  324. rasa/dialogue_understanding/commands/cancel_flow_command.py +116 -0
  325. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +48 -0
  326. rasa/dialogue_understanding/commands/clarify_command.py +77 -0
  327. rasa/dialogue_understanding/commands/command.py +85 -0
  328. rasa/dialogue_understanding/commands/correct_slots_command.py +288 -0
  329. rasa/dialogue_understanding/commands/error_command.py +67 -0
  330. rasa/dialogue_understanding/commands/free_form_answer_command.py +9 -0
  331. rasa/dialogue_understanding/commands/handle_code_change_command.py +64 -0
  332. rasa/dialogue_understanding/commands/human_handoff_command.py +57 -0
  333. rasa/dialogue_understanding/commands/knowledge_answer_command.py +48 -0
  334. rasa/dialogue_understanding/commands/noop_command.py +45 -0
  335. rasa/dialogue_understanding/commands/set_slot_command.py +125 -0
  336. rasa/dialogue_understanding/commands/skip_question_command.py +66 -0
  337. rasa/dialogue_understanding/commands/start_flow_command.py +98 -0
  338. rasa/dialogue_understanding/generator/__init__.py +6 -0
  339. rasa/dialogue_understanding/generator/command_generator.py +257 -0
  340. rasa/dialogue_understanding/generator/command_prompt_template.jinja2 +57 -0
  341. rasa/dialogue_understanding/generator/flow_document_template.jinja2 +4 -0
  342. rasa/dialogue_understanding/generator/flow_retrieval.py +410 -0
  343. rasa/dialogue_understanding/generator/llm_command_generator.py +637 -0
  344. rasa/dialogue_understanding/generator/nlu_command_adapter.py +157 -0
  345. rasa/dialogue_understanding/patterns/__init__.py +0 -0
  346. rasa/dialogue_understanding/patterns/cancel.py +111 -0
  347. rasa/dialogue_understanding/patterns/cannot_handle.py +43 -0
  348. rasa/dialogue_understanding/patterns/chitchat.py +37 -0
  349. rasa/dialogue_understanding/patterns/clarify.py +97 -0
  350. rasa/dialogue_understanding/patterns/code_change.py +41 -0
  351. rasa/dialogue_understanding/patterns/collect_information.py +90 -0
  352. rasa/dialogue_understanding/patterns/completed.py +40 -0
  353. rasa/dialogue_understanding/patterns/continue_interrupted.py +42 -0
  354. rasa/dialogue_understanding/patterns/correction.py +278 -0
  355. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +243 -0
  356. rasa/dialogue_understanding/patterns/human_handoff.py +37 -0
  357. rasa/dialogue_understanding/patterns/internal_error.py +47 -0
  358. rasa/dialogue_understanding/patterns/search.py +37 -0
  359. rasa/dialogue_understanding/patterns/skip_question.py +38 -0
  360. rasa/dialogue_understanding/processor/__init__.py +0 -0
  361. rasa/dialogue_understanding/processor/command_processor.py +578 -0
  362. rasa/dialogue_understanding/processor/command_processor_component.py +39 -0
  363. rasa/dialogue_understanding/stack/__init__.py +0 -0
  364. rasa/dialogue_understanding/stack/dialogue_stack.py +178 -0
  365. rasa/dialogue_understanding/stack/frames/__init__.py +19 -0
  366. rasa/dialogue_understanding/stack/frames/chit_chat_frame.py +27 -0
  367. rasa/dialogue_understanding/stack/frames/dialogue_stack_frame.py +137 -0
  368. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +157 -0
  369. rasa/dialogue_understanding/stack/frames/pattern_frame.py +10 -0
  370. rasa/dialogue_understanding/stack/frames/search_frame.py +27 -0
  371. rasa/dialogue_understanding/stack/utils.py +211 -0
  372. rasa/e2e_test/__init__.py +0 -0
  373. rasa/e2e_test/constants.py +10 -0
  374. rasa/e2e_test/e2e_test_case.py +322 -0
  375. rasa/e2e_test/e2e_test_result.py +34 -0
  376. rasa/e2e_test/e2e_test_runner.py +659 -0
  377. rasa/e2e_test/e2e_test_schema.yml +67 -0
  378. rasa/engine/__init__.py +0 -0
  379. rasa/engine/caching.py +464 -0
  380. rasa/engine/constants.py +17 -0
  381. rasa/engine/exceptions.py +14 -0
  382. rasa/engine/graph.py +625 -0
  383. rasa/engine/loader.py +36 -0
  384. rasa/engine/recipes/__init__.py +0 -0
  385. rasa/engine/recipes/config_files/default_config.yml +44 -0
  386. rasa/engine/recipes/default_components.py +99 -0
  387. rasa/engine/recipes/default_recipe.py +1252 -0
  388. rasa/engine/recipes/graph_recipe.py +79 -0
  389. rasa/engine/recipes/recipe.py +93 -0
  390. rasa/engine/runner/__init__.py +0 -0
  391. rasa/engine/runner/dask.py +256 -0
  392. rasa/engine/runner/interface.py +49 -0
  393. rasa/engine/storage/__init__.py +0 -0
  394. rasa/engine/storage/local_model_storage.py +248 -0
  395. rasa/engine/storage/resource.py +110 -0
  396. rasa/engine/storage/storage.py +203 -0
  397. rasa/engine/training/__init__.py +0 -0
  398. rasa/engine/training/components.py +176 -0
  399. rasa/engine/training/fingerprinting.py +64 -0
  400. rasa/engine/training/graph_trainer.py +256 -0
  401. rasa/engine/training/hooks.py +164 -0
  402. rasa/engine/validation.py +839 -0
  403. rasa/env.py +5 -0
  404. rasa/exceptions.py +69 -0
  405. rasa/graph_components/__init__.py +0 -0
  406. rasa/graph_components/converters/__init__.py +0 -0
  407. rasa/graph_components/converters/nlu_message_converter.py +48 -0
  408. rasa/graph_components/providers/__init__.py +0 -0
  409. rasa/graph_components/providers/domain_for_core_training_provider.py +87 -0
  410. rasa/graph_components/providers/domain_provider.py +71 -0
  411. rasa/graph_components/providers/flows_provider.py +74 -0
  412. rasa/graph_components/providers/forms_provider.py +44 -0
  413. rasa/graph_components/providers/nlu_training_data_provider.py +56 -0
  414. rasa/graph_components/providers/responses_provider.py +44 -0
  415. rasa/graph_components/providers/rule_only_provider.py +49 -0
  416. rasa/graph_components/providers/story_graph_provider.py +43 -0
  417. rasa/graph_components/providers/training_tracker_provider.py +55 -0
  418. rasa/graph_components/validators/__init__.py +0 -0
  419. rasa/graph_components/validators/default_recipe_validator.py +552 -0
  420. rasa/graph_components/validators/finetuning_validator.py +302 -0
  421. rasa/hooks.py +113 -0
  422. rasa/jupyter.py +63 -0
  423. rasa/keys +1 -0
  424. rasa/markers/__init__.py +0 -0
  425. rasa/markers/marker.py +269 -0
  426. rasa/markers/marker_base.py +828 -0
  427. rasa/markers/upload.py +74 -0
  428. rasa/markers/validate.py +21 -0
  429. rasa/model.py +118 -0
  430. rasa/model_testing.py +457 -0
  431. rasa/model_training.py +535 -0
  432. rasa/nlu/__init__.py +7 -0
  433. rasa/nlu/classifiers/__init__.py +3 -0
  434. rasa/nlu/classifiers/classifier.py +5 -0
  435. rasa/nlu/classifiers/diet_classifier.py +1874 -0
  436. rasa/nlu/classifiers/fallback_classifier.py +192 -0
  437. rasa/nlu/classifiers/keyword_intent_classifier.py +188 -0
  438. rasa/nlu/classifiers/llm_intent_classifier.py +519 -0
  439. rasa/nlu/classifiers/logistic_regression_classifier.py +240 -0
  440. rasa/nlu/classifiers/mitie_intent_classifier.py +156 -0
  441. rasa/nlu/classifiers/regex_message_handler.py +56 -0
  442. rasa/nlu/classifiers/sklearn_intent_classifier.py +309 -0
  443. rasa/nlu/constants.py +77 -0
  444. rasa/nlu/convert.py +40 -0
  445. rasa/nlu/emulators/__init__.py +0 -0
  446. rasa/nlu/emulators/dialogflow.py +55 -0
  447. rasa/nlu/emulators/emulator.py +49 -0
  448. rasa/nlu/emulators/luis.py +86 -0
  449. rasa/nlu/emulators/no_emulator.py +10 -0
  450. rasa/nlu/emulators/wit.py +56 -0
  451. rasa/nlu/extractors/__init__.py +0 -0
  452. rasa/nlu/extractors/crf_entity_extractor.py +672 -0
  453. rasa/nlu/extractors/duckling_entity_extractor.py +206 -0
  454. rasa/nlu/extractors/entity_synonyms.py +178 -0
  455. rasa/nlu/extractors/extractor.py +470 -0
  456. rasa/nlu/extractors/mitie_entity_extractor.py +293 -0
  457. rasa/nlu/extractors/regex_entity_extractor.py +220 -0
  458. rasa/nlu/extractors/spacy_entity_extractor.py +95 -0
  459. rasa/nlu/featurizers/__init__.py +0 -0
  460. rasa/nlu/featurizers/dense_featurizer/__init__.py +0 -0
  461. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +449 -0
  462. rasa/nlu/featurizers/dense_featurizer/dense_featurizer.py +57 -0
  463. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +772 -0
  464. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +170 -0
  465. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +132 -0
  466. rasa/nlu/featurizers/featurizer.py +89 -0
  467. rasa/nlu/featurizers/sparse_featurizer/__init__.py +0 -0
  468. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +840 -0
  469. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +539 -0
  470. rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +269 -0
  471. rasa/nlu/featurizers/sparse_featurizer/sparse_featurizer.py +9 -0
  472. rasa/nlu/model.py +24 -0
  473. rasa/nlu/persistor.py +240 -0
  474. rasa/nlu/run.py +27 -0
  475. rasa/nlu/selectors/__init__.py +0 -0
  476. rasa/nlu/selectors/response_selector.py +990 -0
  477. rasa/nlu/test.py +1943 -0
  478. rasa/nlu/tokenizers/__init__.py +0 -0
  479. rasa/nlu/tokenizers/jieba_tokenizer.py +148 -0
  480. rasa/nlu/tokenizers/mitie_tokenizer.py +75 -0
  481. rasa/nlu/tokenizers/spacy_tokenizer.py +72 -0
  482. rasa/nlu/tokenizers/tokenizer.py +239 -0
  483. rasa/nlu/tokenizers/whitespace_tokenizer.py +106 -0
  484. rasa/nlu/utils/__init__.py +35 -0
  485. rasa/nlu/utils/bilou_utils.py +462 -0
  486. rasa/nlu/utils/hugging_face/__init__.py +0 -0
  487. rasa/nlu/utils/hugging_face/registry.py +108 -0
  488. rasa/nlu/utils/hugging_face/transformers_pre_post_processors.py +311 -0
  489. rasa/nlu/utils/mitie_utils.py +113 -0
  490. rasa/nlu/utils/pattern_utils.py +168 -0
  491. rasa/nlu/utils/spacy_utils.py +312 -0
  492. rasa/plugin.py +90 -0
  493. rasa/server.py +1536 -0
  494. rasa/shared/__init__.py +0 -0
  495. rasa/shared/constants.py +181 -0
  496. rasa/shared/core/__init__.py +0 -0
  497. rasa/shared/core/constants.py +168 -0
  498. rasa/shared/core/conversation.py +46 -0
  499. rasa/shared/core/domain.py +2106 -0
  500. rasa/shared/core/events.py +2507 -0
  501. rasa/shared/core/flows/__init__.py +7 -0
  502. rasa/shared/core/flows/flow.py +353 -0
  503. rasa/shared/core/flows/flow_step.py +146 -0
  504. rasa/shared/core/flows/flow_step_links.py +319 -0
  505. rasa/shared/core/flows/flow_step_sequence.py +70 -0
  506. rasa/shared/core/flows/flows_list.py +211 -0
  507. rasa/shared/core/flows/flows_yaml_schema.json +217 -0
  508. rasa/shared/core/flows/nlu_trigger.py +117 -0
  509. rasa/shared/core/flows/steps/__init__.py +24 -0
  510. rasa/shared/core/flows/steps/action.py +51 -0
  511. rasa/shared/core/flows/steps/call.py +64 -0
  512. rasa/shared/core/flows/steps/collect.py +112 -0
  513. rasa/shared/core/flows/steps/constants.py +5 -0
  514. rasa/shared/core/flows/steps/continuation.py +36 -0
  515. rasa/shared/core/flows/steps/end.py +22 -0
  516. rasa/shared/core/flows/steps/internal.py +44 -0
  517. rasa/shared/core/flows/steps/link.py +51 -0
  518. rasa/shared/core/flows/steps/no_operation.py +48 -0
  519. rasa/shared/core/flows/steps/set_slots.py +50 -0
  520. rasa/shared/core/flows/steps/start.py +30 -0
  521. rasa/shared/core/flows/validation.py +527 -0
  522. rasa/shared/core/flows/yaml_flows_io.py +278 -0
  523. rasa/shared/core/generator.py +907 -0
  524. rasa/shared/core/slot_mappings.py +235 -0
  525. rasa/shared/core/slots.py +647 -0
  526. rasa/shared/core/trackers.py +1159 -0
  527. rasa/shared/core/training_data/__init__.py +0 -0
  528. rasa/shared/core/training_data/loading.py +90 -0
  529. rasa/shared/core/training_data/story_reader/__init__.py +0 -0
  530. rasa/shared/core/training_data/story_reader/story_reader.py +129 -0
  531. rasa/shared/core/training_data/story_reader/story_step_builder.py +168 -0
  532. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +888 -0
  533. rasa/shared/core/training_data/story_writer/__init__.py +0 -0
  534. rasa/shared/core/training_data/story_writer/story_writer.py +76 -0
  535. rasa/shared/core/training_data/story_writer/yaml_story_writer.py +442 -0
  536. rasa/shared/core/training_data/structures.py +838 -0
  537. rasa/shared/core/training_data/visualization.html +146 -0
  538. rasa/shared/core/training_data/visualization.py +603 -0
  539. rasa/shared/data.py +192 -0
  540. rasa/shared/engine/__init__.py +0 -0
  541. rasa/shared/engine/caching.py +26 -0
  542. rasa/shared/exceptions.py +129 -0
  543. rasa/shared/importers/__init__.py +0 -0
  544. rasa/shared/importers/importer.py +705 -0
  545. rasa/shared/importers/multi_project.py +203 -0
  546. rasa/shared/importers/rasa.py +100 -0
  547. rasa/shared/importers/utils.py +34 -0
  548. rasa/shared/nlu/__init__.py +0 -0
  549. rasa/shared/nlu/constants.py +45 -0
  550. rasa/shared/nlu/interpreter.py +10 -0
  551. rasa/shared/nlu/training_data/__init__.py +0 -0
  552. rasa/shared/nlu/training_data/entities_parser.py +209 -0
  553. rasa/shared/nlu/training_data/features.py +374 -0
  554. rasa/shared/nlu/training_data/formats/__init__.py +10 -0
  555. rasa/shared/nlu/training_data/formats/dialogflow.py +162 -0
  556. rasa/shared/nlu/training_data/formats/luis.py +87 -0
  557. rasa/shared/nlu/training_data/formats/rasa.py +135 -0
  558. rasa/shared/nlu/training_data/formats/rasa_yaml.py +605 -0
  559. rasa/shared/nlu/training_data/formats/readerwriter.py +245 -0
  560. rasa/shared/nlu/training_data/formats/wit.py +52 -0
  561. rasa/shared/nlu/training_data/loading.py +137 -0
  562. rasa/shared/nlu/training_data/lookup_tables_parser.py +30 -0
  563. rasa/shared/nlu/training_data/message.py +477 -0
  564. rasa/shared/nlu/training_data/schemas/__init__.py +0 -0
  565. rasa/shared/nlu/training_data/schemas/data_schema.py +85 -0
  566. rasa/shared/nlu/training_data/schemas/nlu.yml +53 -0
  567. rasa/shared/nlu/training_data/schemas/responses.yml +70 -0
  568. rasa/shared/nlu/training_data/synonyms_parser.py +42 -0
  569. rasa/shared/nlu/training_data/training_data.py +732 -0
  570. rasa/shared/nlu/training_data/util.py +223 -0
  571. rasa/shared/providers/__init__.py +0 -0
  572. rasa/shared/providers/openai/__init__.py +0 -0
  573. rasa/shared/providers/openai/clients.py +43 -0
  574. rasa/shared/providers/openai/session_handler.py +110 -0
  575. rasa/shared/utils/__init__.py +0 -0
  576. rasa/shared/utils/cli.py +72 -0
  577. rasa/shared/utils/common.py +308 -0
  578. rasa/shared/utils/constants.py +1 -0
  579. rasa/shared/utils/io.py +403 -0
  580. rasa/shared/utils/llm.py +405 -0
  581. rasa/shared/utils/pykwalify_extensions.py +26 -0
  582. rasa/shared/utils/schemas/__init__.py +0 -0
  583. rasa/shared/utils/schemas/config.yml +2 -0
  584. rasa/shared/utils/schemas/domain.yml +142 -0
  585. rasa/shared/utils/schemas/events.py +212 -0
  586. rasa/shared/utils/schemas/model_config.yml +46 -0
  587. rasa/shared/utils/schemas/stories.yml +173 -0
  588. rasa/shared/utils/yaml.py +777 -0
  589. rasa/studio/__init__.py +0 -0
  590. rasa/studio/auth.py +252 -0
  591. rasa/studio/config.py +127 -0
  592. rasa/studio/constants.py +16 -0
  593. rasa/studio/data_handler.py +352 -0
  594. rasa/studio/download.py +350 -0
  595. rasa/studio/train.py +136 -0
  596. rasa/studio/upload.py +408 -0
  597. rasa/telemetry.py +1583 -0
  598. rasa/tracing/__init__.py +0 -0
  599. rasa/tracing/config.py +338 -0
  600. rasa/tracing/constants.py +38 -0
  601. rasa/tracing/instrumentation/__init__.py +0 -0
  602. rasa/tracing/instrumentation/attribute_extractors.py +663 -0
  603. rasa/tracing/instrumentation/instrumentation.py +939 -0
  604. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +142 -0
  605. rasa/tracing/instrumentation/metrics.py +206 -0
  606. rasa/tracing/metric_instrument_provider.py +125 -0
  607. rasa/utils/__init__.py +0 -0
  608. rasa/utils/beta.py +83 -0
  609. rasa/utils/cli.py +27 -0
  610. rasa/utils/common.py +635 -0
  611. rasa/utils/converter.py +53 -0
  612. rasa/utils/endpoints.py +303 -0
  613. rasa/utils/io.py +326 -0
  614. rasa/utils/licensing.py +319 -0
  615. rasa/utils/log_utils.py +174 -0
  616. rasa/utils/mapper.py +210 -0
  617. rasa/utils/ml_utils.py +145 -0
  618. rasa/utils/plotting.py +362 -0
  619. rasa/utils/singleton.py +23 -0
  620. rasa/utils/tensorflow/__init__.py +0 -0
  621. rasa/utils/tensorflow/callback.py +112 -0
  622. rasa/utils/tensorflow/constants.py +116 -0
  623. rasa/utils/tensorflow/crf.py +492 -0
  624. rasa/utils/tensorflow/data_generator.py +440 -0
  625. rasa/utils/tensorflow/environment.py +161 -0
  626. rasa/utils/tensorflow/exceptions.py +5 -0
  627. rasa/utils/tensorflow/layers.py +1565 -0
  628. rasa/utils/tensorflow/layers_utils.py +113 -0
  629. rasa/utils/tensorflow/metrics.py +281 -0
  630. rasa/utils/tensorflow/model_data.py +991 -0
  631. rasa/utils/tensorflow/model_data_utils.py +500 -0
  632. rasa/utils/tensorflow/models.py +936 -0
  633. rasa/utils/tensorflow/rasa_layers.py +1094 -0
  634. rasa/utils/tensorflow/transformer.py +640 -0
  635. rasa/utils/tensorflow/types.py +6 -0
  636. rasa/utils/train_utils.py +572 -0
  637. rasa/utils/yaml.py +54 -0
  638. rasa/validator.py +1035 -0
  639. rasa/version.py +3 -0
  640. rasa_pro-3.8.16.dist-info/METADATA +528 -0
  641. rasa_pro-3.8.16.dist-info/NOTICE +5 -0
  642. rasa_pro-3.8.16.dist-info/RECORD +644 -0
  643. rasa_pro-3.8.16.dist-info/WHEEL +4 -0
  644. rasa_pro-3.8.16.dist-info/entry_points.txt +3 -0
rasa/validator.py ADDED
@@ -0,0 +1,1035 @@
1
+ import logging
2
+ import structlog
3
+ import re
4
+ import string
5
+ from collections import defaultdict
6
+ from typing import Set, Text, Optional, Dict, Any, List, Tuple
7
+
8
+ from jinja2 import Template
9
+ from pypred import Predicate
10
+
11
+ import rasa.core.training.story_conflict
12
+ from rasa.dialogue_understanding.stack.frames import PatternFlowStackFrame
13
+ from rasa.shared.core.flows.flow_step_links import IfFlowStepLink
14
+ from rasa.shared.core.flows.steps.set_slots import SetSlotsFlowStep
15
+ from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
16
+ from rasa.shared.core.flows.steps.action import ActionFlowStep
17
+ from rasa.shared.core.flows.steps.link import LinkFlowStep
18
+ from rasa.shared.core.flows import FlowsList
19
+ import rasa.shared.nlu.constants
20
+ from rasa.shared.constants import (
21
+ ASSISTANT_ID_DEFAULT_VALUE,
22
+ ASSISTANT_ID_KEY,
23
+ CONFIG_MANDATORY_KEYS,
24
+ DOCS_URL_DOMAINS,
25
+ DOCS_URL_FORMS,
26
+ UTTER_PREFIX,
27
+ DOCS_URL_ACTIONS,
28
+ REQUIRED_SLOTS_KEY,
29
+ )
30
+ from rasa.shared.core import constants
31
+ from rasa.shared.core.constants import MAPPING_CONDITIONS, ACTIVE_LOOP
32
+ from rasa.shared.core.events import ActionExecuted, ActiveLoop
33
+ from rasa.shared.core.events import UserUttered
34
+ from rasa.shared.core.domain import (
35
+ Domain,
36
+ RESPONSE_KEYS_TO_INTERPOLATE,
37
+ )
38
+ from rasa.shared.core.generator import TrainingDataGenerator
39
+ from rasa.shared.core.constants import SlotMappingType, MAPPING_TYPE
40
+ from rasa.shared.core.slots import ListSlot, Slot
41
+ from rasa.shared.core.training_data.structures import StoryGraph
42
+ from rasa.shared.importers.importer import TrainingDataImporter
43
+ from rasa.shared.nlu.training_data.training_data import TrainingData
44
+ import rasa.shared.utils.cli
45
+ import rasa.shared.utils.io
46
+
47
+ logger = logging.getLogger(__name__)
48
+ structlogger = structlog.get_logger()
49
+
50
+
51
+ class Validator:
52
+ """A class used to verify usage of intents and utterances."""
53
+
54
+ def __init__(
55
+ self,
56
+ domain: Domain,
57
+ intents: TrainingData,
58
+ story_graph: StoryGraph,
59
+ flows: FlowsList,
60
+ config: Optional[Dict[Text, Any]],
61
+ ) -> None:
62
+ """Initializes the Validator object.
63
+
64
+ Args:
65
+ domain: The domain.
66
+ intents: Training data.
67
+ story_graph: The story graph.
68
+ flows: The flows.
69
+ config: The configuration.
70
+ """
71
+ self.domain = domain
72
+ self.intents = intents
73
+ self.story_graph = story_graph
74
+ self.flows = flows
75
+ self.config = config or {}
76
+
77
+ @classmethod
78
+ def from_importer(cls, importer: TrainingDataImporter) -> "Validator":
79
+ """Create an instance from the domain, nlu and story files."""
80
+ domain = importer.get_domain()
81
+ story_graph = importer.get_stories()
82
+ intents = importer.get_nlu_data()
83
+ config = importer.get_config()
84
+ flows = importer.get_flows()
85
+
86
+ return cls(domain, intents, story_graph, flows, config)
87
+
88
+ def _non_default_intents(self) -> List[Text]:
89
+ return [
90
+ item
91
+ for item in self.domain.intents
92
+ if item not in constants.DEFAULT_INTENTS
93
+ ]
94
+
95
+ def verify_intents(self, ignore_warnings: bool = True) -> bool:
96
+ """Compares list of intents in domain with intents in NLU training data."""
97
+ everything_is_alright = True
98
+
99
+ nlu_data_intents = {e.data["intent"] for e in self.intents.intent_examples}
100
+
101
+ for intent in self._non_default_intents():
102
+ if intent not in nlu_data_intents:
103
+ structlogger.warn(
104
+ "validator.verify_intents.not_in_nlu_training_data",
105
+ intent=intent,
106
+ event_info=(
107
+ f"The intent '{intent}' is listed "
108
+ f"in the domain file, but is not found "
109
+ f"in the NLU training data."
110
+ ),
111
+ )
112
+ everything_is_alright = ignore_warnings or everything_is_alright
113
+
114
+ for intent in nlu_data_intents:
115
+ if intent not in self.domain.intents:
116
+ structlogger.warn(
117
+ "validator.verify_intents.not_in_domain",
118
+ intent=intent,
119
+ event_info=(
120
+ f"There is a message in the training data "
121
+ f"labeled with intent '{intent}'. This "
122
+ f"intent is not listed in your domain. You "
123
+ f"should need to add that intent to your domain "
124
+ f"file!"
125
+ ),
126
+ docs=DOCS_URL_DOMAINS,
127
+ )
128
+ everything_is_alright = ignore_warnings
129
+
130
+ return everything_is_alright
131
+
132
+ def verify_example_repetition_in_intents(
133
+ self, ignore_warnings: bool = True
134
+ ) -> bool:
135
+ """Checks if there is no duplicated example in different intents."""
136
+ everything_is_alright = True
137
+
138
+ duplication_hash = defaultdict(set)
139
+ for example in self.intents.intent_examples:
140
+ text = example.get(rasa.shared.nlu.constants.TEXT)
141
+ duplication_hash[text].add(example.get("intent"))
142
+
143
+ for text, intents in duplication_hash.items():
144
+ if len(duplication_hash[text]) > 1:
145
+ everything_is_alright = ignore_warnings
146
+ intents_string = ", ".join(sorted(intents))
147
+ structlogger.warn(
148
+ "validator.verify_example_repetition_in_intents"
149
+ ".one_example_multiple_intents",
150
+ example=text,
151
+ intents=intents_string,
152
+ event_info=(
153
+ f"The example '{text}' was found labeled "
154
+ f"with multiple different intents in the "
155
+ f"training data. Each annotated message "
156
+ f"should only appear with one intent. "
157
+ f"You should fix that conflict The example is "
158
+ f"labeled with: {intents_string}."
159
+ ),
160
+ )
161
+ return everything_is_alright
162
+
163
+ def verify_intents_in_stories_or_flows(self, ignore_warnings: bool = True) -> bool:
164
+ """Checks intents used in stories.
165
+
166
+ Verifies if the intents used in the stories are valid, and whether
167
+ all valid intents are used in the stories.
168
+ """
169
+ everything_is_alright = self.verify_intents(ignore_warnings=ignore_warnings)
170
+
171
+ stories_intents = {
172
+ event.intent["name"]
173
+ for story in self.story_graph.story_steps
174
+ for event in story.events
175
+ if type(event) == UserUttered and event.intent_name is not None
176
+ }
177
+ flow_intents = {
178
+ trigger.intent
179
+ for flow in self.flows.underlying_flows
180
+ if flow.nlu_triggers is not None
181
+ for trigger in flow.nlu_triggers.trigger_conditions
182
+ }
183
+ used_intents = stories_intents.union(flow_intents)
184
+
185
+ for intent in used_intents:
186
+ if intent not in self.domain.intents:
187
+ structlogger.warn(
188
+ "validator.verify_intents_in_stories_or_flows.not_in_domain",
189
+ intent=intent,
190
+ event_info=(
191
+ f"The intent '{intent}' is used in a "
192
+ f"story or flow, but it is not listed in "
193
+ f"the domain file. You should add it to your "
194
+ f"domain file!"
195
+ ),
196
+ docs=DOCS_URL_DOMAINS,
197
+ )
198
+ everything_is_alright = ignore_warnings
199
+
200
+ for intent in self._non_default_intents():
201
+ if intent not in used_intents:
202
+ structlogger.warn(
203
+ "validator.verify_intents_in_stories_or_flows.not_used",
204
+ intent=intent,
205
+ event_info=(
206
+ f"The intent '{intent}' is not used "
207
+ f"in any story, rule or flow."
208
+ ),
209
+ )
210
+ everything_is_alright = ignore_warnings or everything_is_alright
211
+
212
+ return everything_is_alright
213
+
214
+ def _gather_utterance_actions(self) -> Set[Text]:
215
+ """Return all utterances which are actions.
216
+
217
+ Returns:
218
+ A set of response names found in the domain and data files, with the
219
+ response key stripped in the case of response selector responses.
220
+ """
221
+ domain_responses = {
222
+ response.split(rasa.shared.nlu.constants.RESPONSE_IDENTIFIER_DELIMITER)[0]
223
+ for response in self.domain.responses.keys()
224
+ if response in self.domain.action_names_or_texts
225
+ }
226
+ data_responses = {
227
+ response.split(rasa.shared.nlu.constants.RESPONSE_IDENTIFIER_DELIMITER)[0]
228
+ for response in self.intents.responses.keys()
229
+ }
230
+ return domain_responses.union(data_responses)
231
+
232
+ def _does_story_only_use_valid_actions(
233
+ self, used_utterances_in_stories: Set[str], utterance_actions: List[str]
234
+ ) -> bool:
235
+ """Checks if all utterances used in stories are valid."""
236
+ has_no_warnings = True
237
+ for used_utterance in used_utterances_in_stories:
238
+ if used_utterance not in utterance_actions:
239
+ structlogger.warn(
240
+ "validator.invalid_utterance_action",
241
+ action=used_utterance,
242
+ event_info=(
243
+ f"The action '{used_utterance}' is used in the stories, "
244
+ f"but is not a valid utterance action. Please make sure "
245
+ f"the action is listed in your domain and there is a "
246
+ f"template defined with its name."
247
+ ),
248
+ docs=DOCS_URL_ACTIONS + "#utterance-actions",
249
+ )
250
+ has_no_warnings = False
251
+ return has_no_warnings
252
+
253
+ def _utterances_used_in_stories(self) -> Set[str]:
254
+ """Return all utterances which are used in stories."""
255
+ stories_utterances = set()
256
+
257
+ for story in self.story_graph.story_steps:
258
+ for event in story.events:
259
+ if not isinstance(event, ActionExecuted):
260
+ continue
261
+
262
+ if not event.action_name:
263
+ continue
264
+
265
+ if not event.action_name.startswith(UTTER_PREFIX):
266
+ # we are only interested in utter actions
267
+ continue
268
+
269
+ if event.action_name in stories_utterances:
270
+ # we already processed this one before, we only want to warn once
271
+ continue
272
+
273
+ stories_utterances.add(event.action_name)
274
+ return stories_utterances
275
+
276
+ @classmethod
277
+ def check_for_placeholder(cls, value: Any) -> bool:
278
+ """Check if a value contains a placeholder."""
279
+ if isinstance(value, str):
280
+ return bool(re.search(r"{\s*}", value))
281
+ elif isinstance(value, dict):
282
+ return any(cls.check_for_placeholder(i) for i in value.values())
283
+ elif isinstance(value, list):
284
+ return any(cls.check_for_placeholder(i) for i in value)
285
+ return False
286
+
287
+ def check_for_no_empty_paranthesis_in_responses(self) -> bool:
288
+ """Checks if there are no empty parenthesis in utterances."""
289
+ everything_is_alright = True
290
+
291
+ for response_text, response_variations in self.domain.responses.items():
292
+ for response in response_variations:
293
+ if any(
294
+ self.check_for_placeholder(response.get(key))
295
+ for key in RESPONSE_KEYS_TO_INTERPOLATE
296
+ ):
297
+ structlogger.error(
298
+ "validator.empty_paranthesis_in_utterances",
299
+ response=response_text,
300
+ event_info=(
301
+ f"The response '{response_text}' in the domain file "
302
+ f"contains empty parenthesis, which is not permitted."
303
+ f" Please remove the empty parenthesis."
304
+ ),
305
+ )
306
+ everything_is_alright = False
307
+
308
+ return everything_is_alright
309
+
310
+ def verify_forms_in_stories_rules(self) -> bool:
311
+ """Verifies that forms referenced in active_loop directives are present."""
312
+ all_forms_exist = True
313
+ visited_loops = set()
314
+
315
+ for story in self.story_graph.story_steps:
316
+ for event in story.events:
317
+ if not isinstance(event, ActiveLoop):
318
+ continue
319
+
320
+ if event.name in visited_loops:
321
+ # We've seen this loop before, don't alert on it twice
322
+ continue
323
+
324
+ if not event.name:
325
+ # To support setting `active_loop` to `null`
326
+ continue
327
+
328
+ if event.name not in self.domain.action_names_or_texts:
329
+ structlogger.warn(
330
+ "validator.verify_forms_in_stories_rules.not_in_domain",
331
+ form=event.name,
332
+ block=story.block_name,
333
+ event_info=(
334
+ f"The form '{event.name}' is used in the "
335
+ f"'{story.block_name}' block, but it "
336
+ f"is not listed in the domain file. "
337
+ f"You should add it to your "
338
+ f"domain file!"
339
+ ),
340
+ docs=DOCS_URL_FORMS,
341
+ )
342
+ all_forms_exist = False
343
+ visited_loops.add(event.name)
344
+
345
+ return all_forms_exist
346
+
347
+ def verify_actions_in_stories_rules(self) -> bool:
348
+ """Verifies that actions used in stories and rules are present in the domain."""
349
+ everything_is_alright = True
350
+ visited = set()
351
+
352
+ for story in self.story_graph.story_steps:
353
+ for event in story.events:
354
+ if not isinstance(event, ActionExecuted):
355
+ continue
356
+
357
+ if not event.action_name:
358
+ continue
359
+
360
+ if not event.action_name.startswith("action_"):
361
+ continue
362
+
363
+ if event.action_name in visited:
364
+ # we already processed this one before, we only want to warn once
365
+ continue
366
+
367
+ if event.action_name not in self.domain.action_names_or_texts:
368
+ structlogger.warn(
369
+ "validator.verify_actions_in_stories_rules.not_in_domain",
370
+ action=event.action_name,
371
+ block=story.block_name,
372
+ event_info=(
373
+ f"The action '{event.action_name}' is used in the "
374
+ f"'{story.block_name}' block, but it "
375
+ f"is not listed in the domain file. You "
376
+ f"should add it to your domain file!"
377
+ ),
378
+ docs=DOCS_URL_DOMAINS,
379
+ )
380
+ everything_is_alright = False
381
+ visited.add(event.action_name)
382
+
383
+ return everything_is_alright
384
+
385
+ def verify_story_structure(
386
+ self, ignore_warnings: bool = True, max_history: Optional[int] = None
387
+ ) -> bool:
388
+ """Verifies that the bot behaviour in stories is deterministic.
389
+
390
+ Args:
391
+ ignore_warnings: When `True`, return `True` even if conflicts were found.
392
+ max_history: Maximal number of events to take into account for conflict
393
+ identification.
394
+
395
+ Returns:
396
+ `False` is a conflict was found and `ignore_warnings` is `False`.
397
+ `True` otherwise.
398
+ """
399
+ structlogger.info(
400
+ "validator.verify_story_structure.start",
401
+ event_info="Story structure validation...",
402
+ )
403
+
404
+ trackers = TrainingDataGenerator(
405
+ self.story_graph,
406
+ domain=self.domain,
407
+ remove_duplicates=False,
408
+ augmentation_factor=0,
409
+ ).generate_story_trackers()
410
+
411
+ # Create a list of `StoryConflict` objects
412
+ conflicts = rasa.core.training.story_conflict.find_story_conflicts(
413
+ trackers, self.domain, max_history
414
+ )
415
+
416
+ if not conflicts:
417
+ structlogger.info(
418
+ "validator.verify_story_structure.no_conflicts",
419
+ event_info="No story structure conflicts found.",
420
+ )
421
+ else:
422
+ for conflict in conflicts:
423
+ structlogger.warn(
424
+ "validator.verify_story_structure.conflicts",
425
+ event_info="Found story structure conflict",
426
+ conflict=str(conflict),
427
+ )
428
+
429
+ return ignore_warnings or not conflicts
430
+
431
+ def verify_nlu(self, ignore_warnings: bool = True) -> bool:
432
+ """Runs all the validations on intents and utterances."""
433
+ structlogger.info(
434
+ "validator.verify_intents_in_stories.start",
435
+ event_info="Validating intents...",
436
+ )
437
+ intents_are_valid = self.verify_intents_in_stories_or_flows(ignore_warnings)
438
+
439
+ structlogger.info(
440
+ "validator.verify_example_repetition_in_intents.start",
441
+ event_info="Validating uniqueness of intents and stories...",
442
+ )
443
+ there_is_no_duplication = self.verify_example_repetition_in_intents(
444
+ ignore_warnings
445
+ )
446
+
447
+ return intents_are_valid and there_is_no_duplication
448
+
449
+ def verify_form_slots(self) -> bool:
450
+ """Verifies that form slots match the slot mappings in domain."""
451
+ domain_slot_names = [slot.name for slot in self.domain.slots]
452
+ everything_is_alright = True
453
+
454
+ for form in self.domain.form_names:
455
+ form_slots = self.domain.required_slots_for_form(form)
456
+ for slot in form_slots:
457
+ if slot in domain_slot_names:
458
+ continue
459
+ else:
460
+ structlogger.warn(
461
+ "validator.verify_form_slots.not_in_domain",
462
+ slot=slot,
463
+ form=form,
464
+ event_info=(
465
+ f"The form slot '{slot}' in form '{form}' "
466
+ f"is not present in the domain slots."
467
+ f"Please add the correct slot or check for typos."
468
+ ),
469
+ docs=DOCS_URL_DOMAINS,
470
+ )
471
+ everything_is_alright = False
472
+
473
+ return everything_is_alright
474
+
475
+ def verify_slot_mappings(self) -> bool:
476
+ """Verifies that slot mappings match forms."""
477
+ everything_is_alright = True
478
+
479
+ for slot in self.domain.slots:
480
+ for mapping in slot.mappings:
481
+ for condition in mapping.get(MAPPING_CONDITIONS, []):
482
+ condition_active_loop = condition.get(ACTIVE_LOOP)
483
+ mapping_type = SlotMappingType(mapping.get(MAPPING_TYPE))
484
+ if (
485
+ condition_active_loop
486
+ and condition_active_loop not in self.domain.form_names
487
+ ):
488
+ structlogger.warn(
489
+ "validator.verify_slot_mappings.not_in_domain",
490
+ slot=slot.name,
491
+ form=condition_active_loop,
492
+ event_info=(
493
+ f"Slot '{slot.name}' has a mapping "
494
+ f"condition for form '{condition_active_loop}' "
495
+ f"which is not listed in domain forms. Please "
496
+ f"add this form to the forms section or check "
497
+ f"for typos."
498
+ ),
499
+ )
500
+ everything_is_alright = False
501
+
502
+ form_slots = self.domain.forms.get(condition_active_loop, {}).get(
503
+ REQUIRED_SLOTS_KEY, {}
504
+ )
505
+ if (
506
+ form_slots
507
+ and slot.name not in form_slots
508
+ and mapping_type != SlotMappingType.FROM_TRIGGER_INTENT
509
+ ):
510
+ structlogger.warn(
511
+ "validator.verify_slot_mappings.not_in_forms_key",
512
+ slot=slot.name,
513
+ form=condition_active_loop,
514
+ forms_key=REQUIRED_SLOTS_KEY,
515
+ event_info=(
516
+ f"Slot '{slot.name}' has a mapping condition "
517
+ f"for form '{condition_active_loop}', but it's "
518
+ f"not present in '{condition_active_loop}' "
519
+ f"form's '{REQUIRED_SLOTS_KEY}'. "
520
+ f"The slot needs to be added to this key."
521
+ ),
522
+ )
523
+ everything_is_alright = False
524
+
525
+ return everything_is_alright
526
+
527
+ def verify_domain_validity(self) -> bool:
528
+ """Checks whether the domain returned by the importer is empty.
529
+
530
+ An empty domain or one that uses deprecated Mapping Policy is invalid.
531
+ """
532
+ if self.domain.is_empty():
533
+ return False
534
+
535
+ for intent_key, intent_dict in self.domain.intent_properties.items():
536
+ if "triggers" in intent_dict:
537
+ structlogger.warn(
538
+ "validator.verify_domain_validity.mapping_policy_deprecation",
539
+ intent_key=intent_key,
540
+ event_info=(
541
+ f"The intent {intent_key} in the domain file "
542
+ f"is using the MappingPolicy format "
543
+ f"which has now been deprecated. "
544
+ f"Please migrate to RulePolicy."
545
+ ),
546
+ )
547
+ return False
548
+
549
+ return True
550
+
551
+ def warn_if_config_mandatory_keys_are_not_set(self) -> None:
552
+ """Raises a warning if mandatory keys are not present in the config.
553
+
554
+ Additionally, raises a UserWarning if the assistant_id key is filled with the
555
+ default placeholder value.
556
+ """
557
+ for key in set(CONFIG_MANDATORY_KEYS):
558
+ if key not in self.config:
559
+ structlogger.warn(
560
+ "validator.config_missing_mandatory_key",
561
+ key=key,
562
+ event_info=(
563
+ f"The config file is missing the " f"'{key}' mandatory key."
564
+ ),
565
+ )
566
+
567
+ assistant_id = self.config.get(ASSISTANT_ID_KEY)
568
+
569
+ if assistant_id is not None and assistant_id == ASSISTANT_ID_DEFAULT_VALUE:
570
+ structlogger.warn(
571
+ "validator.config_missing_unique_mandatory_key_value",
572
+ key=ASSISTANT_ID_KEY,
573
+ event_info=(
574
+ f"The config file is missing a unique value for the "
575
+ f"'{ASSISTANT_ID_KEY}' mandatory key. Please replace the default "
576
+ f"placeholder value with a unique identifier."
577
+ ),
578
+ )
579
+
580
+ def _log_error_if_either_action_or_utterance_are_not_defined(
581
+ self,
582
+ collect: CollectInformationFlowStep,
583
+ all_good: bool,
584
+ domain_slots: Dict[Text, Slot],
585
+ ) -> bool:
586
+ """Validates that a collect step can have either an action or an utterance.
587
+ Also logs an error if neither an action nor an utterance is defined.
588
+
589
+ Args:
590
+ collect: the name of the slot to collect
591
+ all_good: boolean value indicating the validation status
592
+
593
+ Returns:
594
+ False, if validation failed, true, otherwise
595
+ """
596
+ has_utterance_defined = any(
597
+ [u for u in self.domain.utterances_for_response if u == collect.utter]
598
+ )
599
+
600
+ has_action_defined = any(
601
+ [
602
+ a
603
+ for a in self.domain.action_names_or_texts
604
+ if a == collect.collect_action
605
+ ]
606
+ )
607
+
608
+ if has_utterance_defined and has_action_defined:
609
+ structlogger.error(
610
+ "validator.verify_flows_steps_against_domain.collect_step",
611
+ collect=collect.collect,
612
+ has_utterance_defined=has_utterance_defined,
613
+ has_action_defined=has_action_defined,
614
+ event_info=(
615
+ f"The collect step '{collect.collect}' has an utterance "
616
+ f"'{collect.utter}' as well as an action "
617
+ f"'{collect.collect_action}' defined. "
618
+ f"You can just have one of them! "
619
+ f"Please remove either the utterance or the action."
620
+ ),
621
+ )
622
+ all_good = False
623
+
624
+ slot = domain_slots.get(collect.collect)
625
+ slot_has_initial_value_defind = slot and slot.initial_value is not None
626
+
627
+ if (
628
+ not slot_has_initial_value_defind
629
+ and not has_utterance_defined
630
+ and not has_action_defined
631
+ ):
632
+ structlogger.error(
633
+ "validator.verify_flows_steps_against_domain.collect_step",
634
+ collect=collect.collect,
635
+ has_utterance_defined=has_utterance_defined,
636
+ has_action_defined=has_action_defined,
637
+ event_info=(
638
+ f"The collect step '{collect.collect}' has neither an utterance "
639
+ f"nor an action defined, or an initial value defined in the domain."
640
+ f"You need to define either an utterance or an action."
641
+ ),
642
+ )
643
+ all_good = False
644
+
645
+ return all_good
646
+
647
+ @staticmethod
648
+ def _log_error_if_slot_not_in_domain(
649
+ slot_name: str,
650
+ domain_slots: Dict[Text, Slot],
651
+ step_id: str,
652
+ flow_id: str,
653
+ all_good: bool,
654
+ ) -> bool:
655
+ if slot_name not in domain_slots:
656
+ structlogger.error(
657
+ "validator.verify_flows_steps_against_domain.slot_not_in_domain",
658
+ slot=slot_name,
659
+ step=step_id,
660
+ flow=flow_id,
661
+ event_info=(
662
+ f"The slot '{slot_name}' is used in the "
663
+ f"step '{step_id}' of flow id '{flow_id}', but it "
664
+ f"is not listed in the domain slots. "
665
+ f"You should add it to your domain file!"
666
+ ),
667
+ )
668
+ all_good = False
669
+
670
+ return all_good
671
+
672
+ @staticmethod
673
+ def _log_error_if_list_slot(
674
+ slot: Slot, step_id: str, flow_id: str, all_good: bool
675
+ ) -> bool:
676
+ if isinstance(slot, ListSlot):
677
+ structlogger.error(
678
+ "validator.verify_flows_steps_against_domain.use_of_list_slot_in_flow",
679
+ slot=slot.name,
680
+ step=step_id,
681
+ flow=flow_id,
682
+ event_info=(
683
+ f"The slot '{slot.name}' is used in the "
684
+ f"step '{step_id}' of flow id '{flow_id}', but it "
685
+ f"is a list slot. List slots are currently not "
686
+ f"supported in flows. You should change it to a "
687
+ f"text, boolean or float slot in your domain file!"
688
+ ),
689
+ )
690
+ all_good = False
691
+
692
+ return all_good
693
+
694
+ def verify_flows_steps_against_domain(self) -> bool:
695
+ """Checks flows steps' references against the domain file."""
696
+ all_good = True
697
+ domain_slots = {slot.name: slot for slot in self.domain.slots}
698
+ flow_ids = [flow.id for flow in self.flows.underlying_flows]
699
+
700
+ for flow in self.flows.underlying_flows:
701
+ for step in flow.steps_with_calls_resolved:
702
+ if isinstance(step, CollectInformationFlowStep):
703
+ all_good = (
704
+ self._log_error_if_either_action_or_utterance_are_not_defined(
705
+ step, all_good, domain_slots
706
+ )
707
+ )
708
+
709
+ all_good = self._log_error_if_slot_not_in_domain(
710
+ step.collect, domain_slots, step.id, flow.id, all_good
711
+ )
712
+
713
+ current_slot = domain_slots.get(step.collect)
714
+ if not current_slot:
715
+ continue
716
+
717
+ all_good = self._log_error_if_list_slot(
718
+ current_slot, step.id, flow.id, all_good
719
+ )
720
+
721
+ elif isinstance(step, SetSlotsFlowStep):
722
+ for slot in step.slots:
723
+ slot_name = slot["key"]
724
+ all_good = self._log_error_if_slot_not_in_domain(
725
+ slot_name, domain_slots, step.id, flow.id, all_good
726
+ )
727
+ current_slot = domain_slots.get(slot_name)
728
+ if not current_slot:
729
+ continue
730
+
731
+ all_good = self._log_error_if_list_slot(
732
+ current_slot, step.id, flow.id, all_good
733
+ )
734
+
735
+ elif isinstance(step, ActionFlowStep):
736
+ regex = r"{context\..+?}"
737
+ matches = re.findall(regex, step.action)
738
+ if matches:
739
+ structlogger.debug(
740
+ "validator.verify_flows_steps_against_domain"
741
+ ".interpolated_action",
742
+ action=step.action,
743
+ step=step.id,
744
+ flow=flow.id,
745
+ event_info=(
746
+ f"An interpolated action name '{step.action}' was "
747
+ f"found at step '{step.id}' of flow id '{flow.id}'. "
748
+ f"Skipping validation for this step. "
749
+ f"Please make sure that the action name is "
750
+ f"listed in your domain responses or actions."
751
+ ),
752
+ )
753
+ elif step.action not in self.domain.action_names_or_texts:
754
+ structlogger.error(
755
+ "validator.verify_flows_steps_against_domain"
756
+ ".action_not_in_domain",
757
+ action=step.action,
758
+ step=step.id,
759
+ flow=flow.id,
760
+ event_info=(
761
+ f"The action '{step.action}' is used in the "
762
+ f"step '{step.id}' of flow id '{flow.id}', "
763
+ f"but it is not listed in the domain file. "
764
+ f"You should add it to your domain file!"
765
+ ),
766
+ )
767
+ all_good = False
768
+
769
+ elif isinstance(step, LinkFlowStep):
770
+ if step.link not in flow_ids:
771
+ logger.error(
772
+ f"The flow '{step.link}' is used in the step "
773
+ f"'{step.id}' of flow id '{flow.id}', but it "
774
+ f"is not listed in the flows file. "
775
+ f"Did you make a typo?",
776
+ )
777
+ all_good = False
778
+ return all_good
779
+
780
+ def verify_unique_flows(self) -> bool:
781
+ """Checks if all flows have unique names and descriptions."""
782
+ all_good = True
783
+ flow_names = set()
784
+ flow_descriptions = set()
785
+ punctuation_table = str.maketrans({i: "" for i in string.punctuation})
786
+
787
+ for flow in self.flows.underlying_flows:
788
+ flow_description = flow.description
789
+ cleaned_description = flow_description.translate(punctuation_table) # type: ignore[union-attr] # noqa: E501
790
+ if cleaned_description in flow_descriptions:
791
+ structlogger.error(
792
+ "validator.verify_unique_flows.duplicate_description",
793
+ flow=flow.id,
794
+ event_info=(
795
+ f"Detected duplicate flow description for "
796
+ f"flow id '{flow.id}'. Flow descriptions must be "
797
+ f"unique. Please make sure that all flows have "
798
+ f"different descriptions."
799
+ ),
800
+ )
801
+ all_good = False
802
+
803
+ if flow.name in flow_names:
804
+ structlogger.error(
805
+ "validator.verify_unique_flows.duplicate_name",
806
+ flow=flow.id,
807
+ name=flow.name,
808
+ event_info=(
809
+ f"Detected duplicate flow name '{flow.name}' for flow "
810
+ f"id '{flow.id}'. Flow names must be unique. "
811
+ f"Please make sure that all flows have different names."
812
+ ),
813
+ )
814
+ all_good = False
815
+
816
+ flow_names.add(flow.name)
817
+ flow_descriptions.add(cleaned_description)
818
+
819
+ return all_good
820
+
821
+ def _build_context(self) -> Dict[str, Any]:
822
+ """Build context for jinja template rendering.
823
+
824
+ Returns:
825
+ A dictionary containing the allowed namespaces for jinja template rendering:
826
+ - `context`: The context mapping the attributes of every flow stack frame
827
+ to None values because this is only used for rendering the template
828
+ during validation.
829
+ - `slots`: The slots of the domain mapped to None values because this is
830
+ only used for rendering the template during validation and not for
831
+ evaluating the predicate at runtime.
832
+ """
833
+ subclasses = [subclass for subclass in PatternFlowStackFrame.__subclasses__()]
834
+ subclass_attrs = []
835
+ for subclass in subclasses:
836
+ subclass_attrs.extend(
837
+ [attr for attr in dir(subclass) if not attr.startswith("__")]
838
+ )
839
+
840
+ context = {
841
+ "context": {attr: None for attr in subclass_attrs},
842
+ "slots": {slot.name: None for slot in self.domain.slots},
843
+ }
844
+ return context
845
+
846
+ @staticmethod
847
+ def _construct_predicate(
848
+ predicate: Optional[str],
849
+ object_id: str,
850
+ context: Dict[str, Any],
851
+ is_step: bool,
852
+ all_good: bool = True,
853
+ ) -> Tuple[Optional[Predicate], bool]:
854
+ rendered_template = Template(predicate).render(context)
855
+ try:
856
+ pred = Predicate(rendered_template)
857
+ except (TypeError, Exception) as exception:
858
+ if is_step:
859
+ structlogger.error(
860
+ "validator.verify_predicates.step_predicate.error",
861
+ step=object_id,
862
+ exception=exception,
863
+ event_info=(
864
+ f"Could not initialize the predicate found under step "
865
+ f"'{object_id}': {exception}"
866
+ ),
867
+ )
868
+ else:
869
+ structlogger.error(
870
+ "validator.verify_predicates.flow_guard_predicate.error",
871
+ flow=object_id,
872
+ exception=exception,
873
+ event_info=(
874
+ f"Could not initialize the predicate found in flow guard "
875
+ f"for flow: '{object_id}': {exception}."
876
+ ),
877
+ )
878
+ pred = None
879
+ all_good = False
880
+
881
+ return pred, all_good
882
+
883
+ def verify_predicates(self) -> bool:
884
+ """Validate predicates used in flow step links and slot rejections."""
885
+ all_good = True
886
+ context = self._build_context()
887
+
888
+ for flow in self.flows.underlying_flows:
889
+ if flow.guard_condition:
890
+ predicate, all_good = self._construct_predicate(
891
+ flow.guard_condition,
892
+ flow.id,
893
+ context,
894
+ is_step=False,
895
+ all_good=all_good,
896
+ )
897
+ if predicate and not predicate.is_valid():
898
+ structlogger.error(
899
+ "validator.verify_predicates.flow_guard.invalid_condition",
900
+ flow=flow.id,
901
+ flow_guard=flow.guard_condition,
902
+ event_info=(
903
+ f"Detected invalid flow guard condition "
904
+ f"'{flow.guard_condition}' for flow id '{flow.id}'. "
905
+ f"Please make sure that all conditions are valid."
906
+ ),
907
+ )
908
+ all_good = False
909
+ for step in flow.steps_with_calls_resolved:
910
+ for link in step.next.links:
911
+ if isinstance(link, IfFlowStepLink):
912
+ all_good = self._verify_namespaces(
913
+ link.condition, step.id, flow.id, all_good
914
+ )
915
+
916
+ predicate, all_good = self._construct_predicate(
917
+ link.condition,
918
+ step.id,
919
+ context,
920
+ is_step=True,
921
+ all_good=all_good,
922
+ )
923
+ if predicate and not predicate.is_valid():
924
+ structlogger.error(
925
+ "validator.verify_predicates.link.invalid_condition",
926
+ step=step.id,
927
+ link=link.condition,
928
+ flow=flow.id,
929
+ event_info=(
930
+ f"Detected invalid condition '{link.condition}' "
931
+ f"at step '{step.id}' for flow id '{flow.id}'. "
932
+ f"Please make sure that all conditions are valid."
933
+ ),
934
+ )
935
+ all_good = False
936
+ if isinstance(step, CollectInformationFlowStep):
937
+ predicates = [predicate.if_ for predicate in step.rejections]
938
+ for predicate in predicates:
939
+ all_good = self._verify_namespaces(
940
+ predicate, step.id, flow.id, all_good
941
+ )
942
+
943
+ pred, all_good = self._construct_predicate(
944
+ predicate, step.id, context, is_step=True, all_good=all_good
945
+ )
946
+ if pred and not pred.is_valid():
947
+ structlogger.error(
948
+ "validator.verify_predicates.invalid_rejection",
949
+ step=step.id,
950
+ rejection=predicate,
951
+ flow=flow.id,
952
+ event_info=(
953
+ f"Detected invalid rejection '{predicate}' "
954
+ f"at `collect` step '{step.id}' "
955
+ f"for flow id '{flow.id}'. "
956
+ f"Please make sure that all conditions are valid."
957
+ ),
958
+ )
959
+ all_good = False
960
+ return all_good
961
+
962
+ def _verify_namespaces(
963
+ self, predicate: str, step_id: str, flow_id: str, all_good: bool
964
+ ) -> bool:
965
+ slots = re.findall(r"\bslots\.\w+", predicate)
966
+ results: List[bool] = [all_good]
967
+
968
+ if slots:
969
+ domain_slots = {slot.name: slot for slot in self.domain.slots}
970
+ for slot in slots:
971
+ slot_name = slot.split(".")[1]
972
+ if slot_name not in domain_slots:
973
+ structlogger.error(
974
+ "validator.verify_namespaces.invalid_slot",
975
+ slot=slot_name,
976
+ step=step_id,
977
+ flow=flow_id,
978
+ event_info=(
979
+ f"Detected invalid slot '{slot_name}' "
980
+ f"at step '{step_id}' "
981
+ f"for flow id '{flow_id}'. "
982
+ f"Please make sure that all slots are specified "
983
+ f"in the domain file."
984
+ ),
985
+ )
986
+ results.append(False)
987
+
988
+ if not slots:
989
+ # no slots found, check if context namespace is used
990
+ variables = re.findall(r"\bcontext\.\w+", predicate)
991
+ if not variables:
992
+ structlogger.error(
993
+ "validator.verify_namespaces"
994
+ ".referencing_variables_without_namespace",
995
+ step=step_id,
996
+ predicate=predicate,
997
+ flow=flow_id,
998
+ event_info=(
999
+ f"Predicate '{predicate}' at step '{step_id}' for flow id "
1000
+ f"'{flow_id}' references one or more variables without "
1001
+ f"the `slots.` or `context.` namespace prefix. "
1002
+ f"Please make sure that all variables reference the required "
1003
+ f"namespace."
1004
+ ),
1005
+ )
1006
+ results.append(False)
1007
+
1008
+ return all(results)
1009
+
1010
+ def verify_flows(self) -> bool:
1011
+ """Checks for inconsistencies across flows."""
1012
+ structlogger.info("validation.flows.started")
1013
+
1014
+ if self.flows.is_empty():
1015
+ structlogger.warn(
1016
+ "validator.verify_flows",
1017
+ event_info=(
1018
+ "No flows were found in the data files. "
1019
+ "Will not proceed with flow validation."
1020
+ ),
1021
+ )
1022
+ return True
1023
+
1024
+ # add all flow validation conditions here
1025
+ flow_validation_conditions = [
1026
+ self.verify_flows_steps_against_domain(),
1027
+ self.verify_unique_flows(),
1028
+ self.verify_predicates(),
1029
+ ]
1030
+
1031
+ all_good = all(flow_validation_conditions)
1032
+
1033
+ structlogger.info("validation.flows.ended")
1034
+
1035
+ return all_good