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/core/processor.py ADDED
@@ -0,0 +1,1331 @@
1
+ import inspect
2
+ import copy
3
+ import logging
4
+ import structlog
5
+ import os
6
+ import re
7
+ from pathlib import Path
8
+ import tarfile
9
+ import time
10
+ from types import LambdaType
11
+ from typing import Any, Dict, List, Optional, TYPE_CHECKING, Text, Tuple, Union
12
+
13
+ from rasa.core.http_interpreter import RasaNLUHttpInterpreter
14
+ from rasa.dialogue_understanding.commands import SetSlotCommand, CannotHandleCommand
15
+ from rasa.engine import loader
16
+ from rasa.engine.constants import (
17
+ PLACEHOLDER_MESSAGE,
18
+ PLACEHOLDER_TRACKER,
19
+ PLACEHOLDER_ENDPOINTS,
20
+ )
21
+ from rasa.engine.runner.dask import DaskGraphRunner
22
+ from rasa.engine.storage.local_model_storage import LocalModelStorage
23
+ from rasa.engine.storage.storage import ModelMetadata
24
+ from rasa.model import get_latest_model
25
+ from rasa.plugin import plugin_manager
26
+ from rasa.shared.core.flows import FlowsList
27
+ from rasa.shared.data import TrainingType
28
+ import rasa.shared.utils.io
29
+ import rasa.core.actions.action
30
+ from rasa.core import jobs
31
+ from rasa.core.actions.action import Action
32
+ from rasa.core.channels.channel import (
33
+ CollectingOutputChannel,
34
+ OutputChannel,
35
+ UserMessage,
36
+ )
37
+ import rasa.core.utils
38
+ from rasa.core.policies.policy import PolicyPrediction
39
+ from rasa.engine.runner.interface import GraphRunner
40
+ from rasa.exceptions import ActionLimitReached, ModelNotFound
41
+ from rasa.shared.core.constants import (
42
+ ACTION_CORRECT_FLOW_SLOT,
43
+ USER_INTENT_RESTART,
44
+ ACTION_LISTEN_NAME,
45
+ ACTION_SESSION_START_NAME,
46
+ FOLLOWUP_ACTION,
47
+ SESSION_START_METADATA_SLOT,
48
+ ACTION_EXTRACT_SLOTS,
49
+ )
50
+ from rasa.shared.core.events import (
51
+ ActionExecutionRejected,
52
+ BotUttered,
53
+ Event,
54
+ ReminderCancelled,
55
+ ReminderScheduled,
56
+ SlotSet,
57
+ UserUttered,
58
+ ActionExecuted,
59
+ )
60
+ from rasa.shared.constants import (
61
+ ASSISTANT_ID_KEY,
62
+ DOCS_URL_DOMAINS,
63
+ DEFAULT_SENDER_ID,
64
+ ROUTE_TO_CALM_SLOT,
65
+ DOCS_URL_NLU_BASED_POLICIES,
66
+ UTTER_PREFIX,
67
+ RASA_PATTERN_CANNOT_HANDLE_INVALID_INTENT,
68
+ )
69
+ from rasa.core.nlg import NaturalLanguageGenerator
70
+ from rasa.core.lock_store import LockStore
71
+ from rasa.utils.common import TempDirectoryPath, get_temp_dir_name
72
+ import rasa.core.tracker_store
73
+ import rasa.core.actions.action
74
+ import rasa.shared.core.trackers
75
+ from rasa.shared.core.trackers import DialogueStateTracker, EventVerbosity
76
+ from rasa.shared.core.training_data.story_reader.yaml_story_reader import (
77
+ YAMLStoryReader,
78
+ )
79
+ from rasa.shared.nlu.constants import (
80
+ COMMANDS,
81
+ ENTITIES,
82
+ INTENT,
83
+ INTENT_NAME_KEY,
84
+ INTENT_RESPONSE_KEY,
85
+ PREDICTED_CONFIDENCE_KEY,
86
+ FULL_RETRIEVAL_INTENT_NAME_KEY,
87
+ RESPONSE_SELECTOR,
88
+ RESPONSE,
89
+ TEXT,
90
+ )
91
+ from rasa.shared.nlu.training_data.message import Message
92
+ from rasa.utils.endpoints import EndpointConfig
93
+
94
+ if TYPE_CHECKING:
95
+ from rasa.core.utils import AvailableEndpoints
96
+
97
+ logger = logging.getLogger(__name__)
98
+ structlogger = structlog.get_logger()
99
+
100
+ MAX_NUMBER_OF_PREDICTIONS = int(os.environ.get("MAX_NUMBER_OF_PREDICTIONS", "10"))
101
+
102
+
103
+ class MessageProcessor:
104
+ """The message processor is interface for communicating with a bot model."""
105
+
106
+ def __init__(
107
+ self,
108
+ model_path: Union[Text, Path],
109
+ tracker_store: rasa.core.tracker_store.TrackerStore,
110
+ lock_store: LockStore,
111
+ generator: NaturalLanguageGenerator,
112
+ action_endpoint: Optional[EndpointConfig] = None,
113
+ max_number_of_predictions: int = MAX_NUMBER_OF_PREDICTIONS,
114
+ on_circuit_break: Optional[LambdaType] = None,
115
+ http_interpreter: Optional[RasaNLUHttpInterpreter] = None,
116
+ endpoints: Optional["AvailableEndpoints"] = None,
117
+ ) -> None:
118
+ """Initializes a `MessageProcessor`."""
119
+ self.nlg = generator
120
+ self.tracker_store = tracker_store
121
+ self.lock_store = lock_store
122
+ self.max_number_of_predictions = max_number_of_predictions
123
+ self.on_circuit_break = on_circuit_break
124
+ self.action_endpoint = action_endpoint
125
+ self.model_filename, self.model_metadata, self.graph_runner = self._load_model(
126
+ model_path
127
+ )
128
+ self.endpoints = endpoints
129
+
130
+ if self.model_metadata.assistant_id is None:
131
+ rasa.shared.utils.io.raise_warning(
132
+ f"The model metadata does not contain a value for the "
133
+ f"'{ASSISTANT_ID_KEY}' attribute. Check that 'config.yml' "
134
+ f"file contains a value for the '{ASSISTANT_ID_KEY}' key "
135
+ f"and re-train the model. Failure to do so will result in "
136
+ f"streaming events without a unique assistant identifier.",
137
+ UserWarning,
138
+ )
139
+
140
+ self.model_path = Path(model_path)
141
+ self.domain = self.model_metadata.domain
142
+ self.http_interpreter = http_interpreter
143
+
144
+ @staticmethod
145
+ def _load_model(
146
+ model_path: Union[Text, Path]
147
+ ) -> Tuple[Text, ModelMetadata, GraphRunner]:
148
+ """Unpacks a model from a given path using the graph model loader."""
149
+ try:
150
+ if os.path.isfile(model_path):
151
+ model_tar = model_path
152
+ else:
153
+ model_file_path = get_latest_model(model_path)
154
+ if not model_file_path:
155
+ raise ModelNotFound(f"No model found at path '{model_path}'.")
156
+ model_tar = model_file_path
157
+ except TypeError:
158
+ raise ModelNotFound(f"Model {model_path} can not be loaded.")
159
+
160
+ logger.info(f"Loading model {model_tar}...")
161
+ with TempDirectoryPath(get_temp_dir_name()) as temporary_directory:
162
+ try:
163
+ metadata, runner = loader.load_predict_graph_runner(
164
+ Path(temporary_directory),
165
+ Path(model_tar),
166
+ LocalModelStorage,
167
+ DaskGraphRunner,
168
+ )
169
+ return os.path.basename(model_tar), metadata, runner
170
+ except tarfile.ReadError:
171
+ raise ModelNotFound(f"Model {model_path} can not be loaded.")
172
+
173
+ async def handle_message(
174
+ self, message: UserMessage
175
+ ) -> Optional[List[Dict[Text, Any]]]:
176
+ """Handle a single message with this processor."""
177
+ # preprocess message if necessary
178
+ tracker = await self.log_message(message, should_save_tracker=False)
179
+
180
+ if self.model_metadata.training_type == TrainingType.NLU:
181
+ await self.save_tracker(tracker)
182
+ rasa.shared.utils.io.raise_warning(
183
+ "No core model. Skipping action prediction and execution.",
184
+ docs=DOCS_URL_NLU_BASED_POLICIES,
185
+ )
186
+ return None
187
+
188
+ tracker = await self.run_action_extract_slots(message.output_channel, tracker)
189
+
190
+ await self._run_prediction_loop(message.output_channel, tracker)
191
+
192
+ await self.run_anonymization_pipeline(tracker)
193
+
194
+ await self.save_tracker(tracker)
195
+
196
+ if isinstance(message.output_channel, CollectingOutputChannel):
197
+ return message.output_channel.messages
198
+
199
+ return None
200
+
201
+ async def run_action_extract_slots(
202
+ self, output_channel: OutputChannel, tracker: DialogueStateTracker
203
+ ) -> DialogueStateTracker:
204
+ """Run action to extract slots and update the tracker accordingly.
205
+
206
+ Args:
207
+ output_channel: Output channel associated with the incoming user message.
208
+ tracker: A tracker representing a conversation state.
209
+
210
+ Returns:
211
+ the given (updated) tracker
212
+ """
213
+ action_extract_slots = rasa.core.actions.action.action_for_name_or_text(
214
+ ACTION_EXTRACT_SLOTS, self.domain, self.action_endpoint
215
+ )
216
+ extraction_events = await action_extract_slots.run(
217
+ output_channel, self.nlg, tracker, self.domain
218
+ )
219
+
220
+ await self._send_bot_messages(extraction_events, tracker, output_channel)
221
+
222
+ tracker.update_with_events(extraction_events)
223
+
224
+ structlogger.debug(
225
+ "processor.extract.slots",
226
+ action_extract_slot=ACTION_EXTRACT_SLOTS,
227
+ len_extraction_events=len(extraction_events),
228
+ rasa_events=copy.deepcopy(extraction_events),
229
+ )
230
+
231
+ return tracker
232
+
233
+ async def run_anonymization_pipeline(self, tracker: DialogueStateTracker) -> None:
234
+ """Run the anonymization pipeline on the new tracker events.
235
+
236
+ Args:
237
+ tracker: A tracker representing a conversation state.
238
+ """
239
+ anonymization_pipeline = plugin_manager().hook.get_anonymization_pipeline()
240
+ if anonymization_pipeline is None:
241
+ return None
242
+
243
+ old_tracker = await self.tracker_store.retrieve(tracker.sender_id)
244
+ new_events = rasa.shared.core.trackers.TrackerEventDiffEngine.event_difference(
245
+ old_tracker, tracker
246
+ )
247
+
248
+ for event in new_events:
249
+ body = {"sender_id": tracker.sender_id}
250
+ body.update(event.as_dict())
251
+ anonymization_pipeline.run(body)
252
+
253
+ async def predict_next_for_sender_id(
254
+ self, sender_id: Text
255
+ ) -> Optional[Dict[Text, Any]]:
256
+ """Predict the next action for the given sender_id.
257
+
258
+ Args:
259
+ sender_id: Conversation ID.
260
+
261
+ Returns:
262
+ The prediction for the next action. `None` if no domain or policies loaded.
263
+ """
264
+ tracker = await self.fetch_tracker_and_update_session(sender_id)
265
+ result = await self.predict_next_with_tracker(tracker)
266
+
267
+ # save tracker state to continue conversation from this state
268
+ await self.save_tracker(tracker)
269
+
270
+ return result
271
+
272
+ async def predict_next_with_tracker(
273
+ self,
274
+ tracker: DialogueStateTracker,
275
+ verbosity: EventVerbosity = EventVerbosity.AFTER_RESTART,
276
+ ) -> Optional[Dict[Text, Any]]:
277
+ """Predict the next action for a given conversation state.
278
+
279
+ Args:
280
+ tracker: A tracker representing a conversation state.
281
+ verbosity: Verbosity for the returned conversation state.
282
+
283
+ Returns:
284
+ The prediction for the next action. `None` if no domain or policies loaded.
285
+ """
286
+ if self.model_metadata.training_type == TrainingType.NLU:
287
+ rasa.shared.utils.io.raise_warning(
288
+ "No core model. Skipping action prediction and execution.",
289
+ docs=DOCS_URL_NLU_BASED_POLICIES,
290
+ )
291
+ return None
292
+
293
+ prediction = await self._predict_next_with_tracker(tracker)
294
+
295
+ scores = [
296
+ {"action": a, "score": p}
297
+ for a, p in zip(self.domain.action_names_or_texts, prediction.probabilities)
298
+ ]
299
+ return {
300
+ "scores": scores,
301
+ "policy": prediction.policy_name,
302
+ "confidence": prediction.max_confidence,
303
+ "tracker": tracker.current_state(verbosity),
304
+ }
305
+
306
+ async def _update_tracker_session(
307
+ self,
308
+ tracker: DialogueStateTracker,
309
+ output_channel: OutputChannel,
310
+ metadata: Optional[Dict] = None,
311
+ ) -> None:
312
+ """Check the current session in `tracker` and update it if expired.
313
+
314
+ An 'action_session_start' is run if the latest tracker session has expired,
315
+ or if the tracker does not yet contain any events (only those after the last
316
+ restart are considered).
317
+
318
+ Args:
319
+ metadata: Data sent from client associated with the incoming user message.
320
+ tracker: Tracker to inspect.
321
+ output_channel: Output channel for potential utterances in a custom
322
+ `ActionSessionStart`.
323
+ """
324
+ if not tracker.applied_events() or self._has_session_expired(tracker):
325
+ logger.debug(
326
+ f"Starting a new session for conversation ID '{tracker.sender_id}'."
327
+ )
328
+
329
+ action_session_start = self._get_action(ACTION_SESSION_START_NAME)
330
+
331
+ if metadata:
332
+ tracker.update(
333
+ SlotSet(SESSION_START_METADATA_SLOT, metadata), self.domain
334
+ )
335
+
336
+ await self._run_action(
337
+ action=action_session_start,
338
+ tracker=tracker,
339
+ output_channel=output_channel,
340
+ nlg=self.nlg,
341
+ prediction=PolicyPrediction.for_action_name(
342
+ self.domain, ACTION_SESSION_START_NAME
343
+ ),
344
+ )
345
+
346
+ async def fetch_tracker_and_update_session(
347
+ self,
348
+ sender_id: Text,
349
+ output_channel: Optional[OutputChannel] = None,
350
+ metadata: Optional[Dict] = None,
351
+ ) -> DialogueStateTracker:
352
+ """Fetches tracker for `sender_id` and updates its conversation session.
353
+
354
+ If a new tracker is created, `action_session_start` is run.
355
+
356
+ Args:
357
+ metadata: Data sent from client associated with the incoming user message.
358
+ output_channel: Output channel associated with the incoming user message.
359
+ sender_id: Conversation ID for which to fetch the tracker.
360
+
361
+ Returns:
362
+ Tracker for `sender_id`.
363
+ """
364
+ tracker = await self.get_tracker(sender_id)
365
+
366
+ await self._update_tracker_session(tracker, output_channel, metadata)
367
+
368
+ return tracker
369
+
370
+ async def fetch_tracker_with_initial_session(
371
+ self,
372
+ sender_id: Text,
373
+ output_channel: Optional[OutputChannel] = None,
374
+ metadata: Optional[Dict] = None,
375
+ ) -> DialogueStateTracker:
376
+ """Fetches tracker for `sender_id` and runs a session start on a new one.
377
+
378
+ Args:
379
+ metadata: Data sent from client associated with the incoming user message.
380
+ output_channel: Output channel associated with the incoming user message.
381
+ sender_id: Conversation ID for which to fetch the tracker.
382
+
383
+ Returns:
384
+ Tracker for `sender_id`.
385
+ """
386
+ tracker = await self.get_tracker(sender_id)
387
+
388
+ # run session start only if the tracker is empty
389
+ if not tracker.events:
390
+ await self._update_tracker_session(tracker, output_channel, metadata)
391
+
392
+ return tracker
393
+
394
+ async def get_tracker(self, conversation_id: Text) -> DialogueStateTracker:
395
+ """Get the tracker for a conversation.
396
+
397
+ In contrast to `fetch_tracker_and_update_session` this does not add any
398
+ `action_session_start` or `session_start` events at the beginning of a
399
+ conversation.
400
+
401
+ Args:
402
+ conversation_id: The ID of the conversation for which the history should be
403
+ retrieved.
404
+
405
+ Returns:
406
+ Tracker for the conversation. Creates an empty tracker in case it's a new
407
+ conversation.
408
+ """
409
+ conversation_id = conversation_id or DEFAULT_SENDER_ID
410
+
411
+ tracker = await self.tracker_store.get_or_create_tracker(
412
+ conversation_id, append_action_listen=False
413
+ )
414
+ tracker.model_id = self.model_metadata.model_id
415
+ if tracker.assistant_id is None:
416
+ tracker.assistant_id = self.model_metadata.assistant_id
417
+ return tracker
418
+
419
+ async def fetch_full_tracker_with_initial_session(
420
+ self,
421
+ conversation_id: Text,
422
+ output_channel: Optional[OutputChannel] = None,
423
+ metadata: Optional[Dict] = None,
424
+ ) -> DialogueStateTracker:
425
+ """Get the full tracker for a conversation, including events after a restart.
426
+
427
+ Args:
428
+ conversation_id: The ID of the conversation for which the history should be
429
+ retrieved.
430
+ output_channel: Output channel associated with the incoming user message.
431
+ metadata: Data sent from client associated with the incoming user message.
432
+
433
+ Returns:
434
+ Tracker for the conversation. Creates an empty tracker with a new session
435
+ initialized in case it's a new conversation.
436
+ """
437
+ conversation_id = conversation_id or DEFAULT_SENDER_ID
438
+
439
+ tracker = await self.tracker_store.get_or_create_full_tracker(
440
+ conversation_id, False
441
+ )
442
+ tracker.model_id = self.model_metadata.model_id
443
+
444
+ if tracker.assistant_id is None:
445
+ tracker.assistant_id = self.model_metadata.assistant_id
446
+
447
+ if not tracker.events:
448
+ await self._update_tracker_session(tracker, output_channel, metadata)
449
+
450
+ return tracker
451
+
452
+ async def get_trackers_for_all_conversation_sessions(
453
+ self, conversation_id: Text
454
+ ) -> List[DialogueStateTracker]:
455
+ """Fetches all trackers for a conversation.
456
+
457
+ Individual trackers are returned for each conversation session found
458
+ for `conversation_id`.
459
+
460
+ Args:
461
+ conversation_id: The ID of the conversation for which the trackers should
462
+ be retrieved.
463
+
464
+ Returns:
465
+ Trackers for the conversation.
466
+ """
467
+ conversation_id = conversation_id or DEFAULT_SENDER_ID
468
+
469
+ tracker = await self.tracker_store.retrieve_full_tracker(conversation_id)
470
+
471
+ return rasa.shared.core.trackers.get_trackers_for_conversation_sessions(tracker)
472
+
473
+ async def log_message(
474
+ self, message: UserMessage, should_save_tracker: bool = True
475
+ ) -> DialogueStateTracker:
476
+ """Log `message` on tracker belonging to the message's conversation_id.
477
+
478
+ Optionally save the tracker if `should_save_tracker` is `True`. Tracker saving
479
+ can be skipped if the tracker returned by this method is used for further
480
+ processing and saved at a later stage.
481
+ """
482
+ tracker = await self.fetch_tracker_and_update_session(
483
+ message.sender_id, message.output_channel, message.metadata
484
+ )
485
+
486
+ await self._handle_message_with_tracker(message, tracker)
487
+
488
+ if should_save_tracker:
489
+ await self.save_tracker(tracker)
490
+
491
+ return tracker
492
+
493
+ async def execute_action(
494
+ self,
495
+ sender_id: Text,
496
+ action_name: Text,
497
+ output_channel: OutputChannel,
498
+ nlg: NaturalLanguageGenerator,
499
+ prediction: PolicyPrediction,
500
+ ) -> Optional[DialogueStateTracker]:
501
+ """Execute an action for a conversation.
502
+
503
+ Note that this might lead to unexpected bot behavior. Rather use an intent
504
+ to execute certain behavior within a conversation (e.g. by using
505
+ `trigger_external_user_uttered`).
506
+
507
+ Args:
508
+ sender_id: The ID of the conversation.
509
+ action_name: The name of the action which should be executed.
510
+ output_channel: The output channel which should be used for bot responses.
511
+ nlg: The response generator.
512
+ prediction: The prediction for the action.
513
+
514
+ Returns:
515
+ The new conversation state. Note that the new state is also persisted.
516
+ """
517
+ # we have a Tracker instance for each user
518
+ # which maintains conversation state
519
+ tracker = await self.fetch_tracker_and_update_session(sender_id, output_channel)
520
+
521
+ action = self._get_action(action_name)
522
+ await self._run_action(action, tracker, output_channel, nlg, prediction)
523
+
524
+ # save tracker state to continue conversation from this state
525
+ await self.save_tracker(tracker)
526
+
527
+ return tracker
528
+
529
+ async def predict_next_with_tracker_if_should(
530
+ self, tracker: DialogueStateTracker
531
+ ) -> Tuple[rasa.core.actions.action.Action, PolicyPrediction]:
532
+ """Predicts the next action the bot should take after seeing x.
533
+
534
+ This should be overwritten by more advanced policies to use
535
+ ML to predict the action.
536
+
537
+ Returns:
538
+ The index of the next action and prediction of the policy.
539
+
540
+ Raises:
541
+ ActionLimitReached if the limit of actions to predict has been reached.
542
+ """
543
+ should_predict_another_action = self.should_predict_another_action(
544
+ tracker.latest_action_name
545
+ )
546
+
547
+ if self.is_action_limit_reached(tracker, should_predict_another_action):
548
+ raise ActionLimitReached(
549
+ "The limit of actions to predict has been reached."
550
+ )
551
+
552
+ prediction = await self._predict_next_with_tracker(tracker)
553
+
554
+ action = rasa.core.actions.action.action_for_index(
555
+ prediction.max_confidence_index, self.domain, self.action_endpoint
556
+ )
557
+
558
+ logger.debug(
559
+ f"Predicted next action '{action.name()}' with confidence "
560
+ f"{prediction.max_confidence:.2f}."
561
+ )
562
+
563
+ return action, prediction
564
+
565
+ @staticmethod
566
+ def _is_reminder(e: Event, name: Text) -> bool:
567
+ return isinstance(e, ReminderScheduled) and e.name == name
568
+
569
+ @staticmethod
570
+ def _is_reminder_still_valid(
571
+ tracker: DialogueStateTracker, reminder_event: ReminderScheduled
572
+ ) -> bool:
573
+ """Check if the conversation has been restarted after reminder."""
574
+ for e in reversed(tracker.applied_events()):
575
+ if MessageProcessor._is_reminder(e, reminder_event.name):
576
+ return True
577
+ return False # not found in applied events --> has been restarted
578
+
579
+ @staticmethod
580
+ def _has_message_after_reminder(
581
+ tracker: DialogueStateTracker, reminder_event: ReminderScheduled
582
+ ) -> bool:
583
+ """Check if the user sent a message after the reminder."""
584
+ for e in reversed(tracker.events):
585
+ if MessageProcessor._is_reminder(e, reminder_event.name):
586
+ return False
587
+
588
+ if isinstance(e, UserUttered) and e.text:
589
+ return True
590
+
591
+ return True # tracker has probably been restarted
592
+
593
+ async def handle_reminder(
594
+ self,
595
+ reminder_event: ReminderScheduled,
596
+ sender_id: Text,
597
+ output_channel: OutputChannel,
598
+ ) -> None:
599
+ """Handle a reminder that is triggered asynchronously."""
600
+ async with self.lock_store.lock(sender_id):
601
+ tracker = await self.fetch_tracker_and_update_session(
602
+ sender_id, output_channel
603
+ )
604
+
605
+ if (
606
+ reminder_event.kill_on_user_message
607
+ and self._has_message_after_reminder(tracker, reminder_event)
608
+ or not self._is_reminder_still_valid(tracker, reminder_event)
609
+ ):
610
+ logger.debug(
611
+ f"Canceled reminder because it is outdated ({reminder_event})."
612
+ )
613
+ else:
614
+ intent = reminder_event.intent
615
+ entities: Union[List[Dict], Dict] = reminder_event.entities or {}
616
+ await self.trigger_external_user_uttered(
617
+ intent, entities, tracker, output_channel
618
+ )
619
+
620
+ async def trigger_external_user_uttered(
621
+ self,
622
+ intent_name: Text,
623
+ entities: Optional[Union[List[Dict[Text, Any]], Dict[Text, Text]]],
624
+ tracker: DialogueStateTracker,
625
+ output_channel: OutputChannel,
626
+ ) -> None:
627
+ """Triggers an external message.
628
+
629
+ Triggers an external message (like a user message, but invisible;
630
+ used, e.g., by a reminder or the trigger_intent endpoint).
631
+
632
+ Args:
633
+ intent_name: Name of the intent to be triggered.
634
+ entities: Entities to be passed on.
635
+ tracker: The tracker to which the event should be added.
636
+ output_channel: The output channel.
637
+ """
638
+ if isinstance(entities, list):
639
+ entity_list = entities
640
+ elif isinstance(entities, dict):
641
+ # Allow for a short-hand notation {"ent1": "val1", "ent2": "val2", ...}.
642
+ # Useful if properties like 'start', 'end', or 'extractor' are not given,
643
+ # e.g. for external events.
644
+ entity_list = [
645
+ {"entity": ent, "value": val} for ent, val in entities.items()
646
+ ]
647
+ elif not entities:
648
+ entity_list = []
649
+ else:
650
+ rasa.shared.utils.io.raise_warning(
651
+ f"Invalid entity specification: {entities}. Assuming no entities."
652
+ )
653
+ entity_list = []
654
+
655
+ # Set the new event's input channel to the latest input channel, so
656
+ # that we don't lose this property.
657
+ input_channel = tracker.get_latest_input_channel()
658
+
659
+ tracker.update(
660
+ UserUttered.create_external(intent_name, entity_list, input_channel),
661
+ self.domain,
662
+ )
663
+
664
+ tracker = await self.run_action_extract_slots(output_channel, tracker)
665
+
666
+ await self._run_prediction_loop(output_channel, tracker)
667
+ # save tracker state to continue conversation from this state
668
+ await self.save_tracker(tracker)
669
+
670
+ @staticmethod
671
+ def _log_slots(tracker: DialogueStateTracker) -> None:
672
+ # Log currently set slots
673
+ slots = {s.name: s.value for s in tracker.slots.values() if s.value is not None}
674
+
675
+ structlogger.debug("processor.slots.log", slots=slots)
676
+
677
+ def _check_for_unseen_features(self, parse_data: Dict[Text, Any]) -> None:
678
+ """Warns the user if the NLU parse data contains unrecognized features.
679
+
680
+ Checks intents and entities picked up by the NLU parsing
681
+ against the domain and warns the user of those that don't match.
682
+ Also considers a list of default intents that are valid but don't
683
+ need to be listed in the domain.
684
+
685
+ Args:
686
+ parse_data: Message parse data to check against the domain.
687
+ """
688
+ if not self.domain or self.domain.is_empty():
689
+ return
690
+
691
+ intent = parse_data["intent"][INTENT_NAME_KEY]
692
+ if intent and intent not in self.domain.intents:
693
+ rasa.shared.utils.io.raise_warning(
694
+ f"Parsed an intent '{intent}' "
695
+ f"which is not defined in the domain. "
696
+ f"Please make sure all intents are listed in the domain.",
697
+ docs=DOCS_URL_DOMAINS,
698
+ )
699
+
700
+ entities = parse_data["entities"] or []
701
+ for element in entities:
702
+ entity = element["entity"]
703
+ if entity and entity not in self.domain.entities:
704
+ rasa.shared.utils.io.raise_warning(
705
+ f"Parsed an entity '{entity}' "
706
+ f"which is not defined in the domain. "
707
+ f"Please make sure all entities are listed in the domain.",
708
+ docs=DOCS_URL_DOMAINS,
709
+ )
710
+
711
+ def _get_action(
712
+ self, action_name: Text
713
+ ) -> Optional[rasa.core.actions.action.Action]:
714
+ return rasa.core.actions.action.action_for_name_or_text(
715
+ action_name, self.domain, self.action_endpoint
716
+ )
717
+
718
+ async def parse_message(
719
+ self,
720
+ message: UserMessage,
721
+ tracker: Optional[DialogueStateTracker] = None,
722
+ only_output_properties: bool = True,
723
+ ) -> Dict[Text, Any]:
724
+ """Interprets the passed message.
725
+
726
+ Args:
727
+ message: Message to handle.
728
+ tracker: Tracker to use.
729
+ only_output_properties: If `True`, restrict the output to
730
+ Message.only_output_properties.
731
+
732
+ Returns:
733
+ Parsed data extracted from the message.
734
+ """
735
+ if self.http_interpreter:
736
+ parse_data = await self.http_interpreter.parse(message)
737
+ else:
738
+ msg = YAMLStoryReader.unpack_regex_message(
739
+ message=Message({TEXT: message.text}), domain=self.domain
740
+ )
741
+
742
+ # Invalid use of slash syntax, sanitize the message before passing
743
+ # it to the graph
744
+ if (
745
+ msg.data.get(TEXT, "").strip().startswith("/")
746
+ and msg.data.get(INTENT) is None
747
+ ):
748
+ message = self._sanitize_message(message)
749
+
750
+ # No intent trigger used. Pass message to graph.
751
+ if msg.data.get(INTENT) is None:
752
+ parse_data = await self._parse_message_with_graph(
753
+ message, tracker, only_output_properties
754
+ )
755
+
756
+ # Intent trigger is used.
757
+ else:
758
+ parse_data = await self._parse_message_with_intent_trigger(
759
+ msg, tracker, only_output_properties
760
+ )
761
+
762
+ self._update_full_retrieval_intent(parse_data)
763
+ structlogger.debug(
764
+ "processor.message.parse",
765
+ parse_data_text=copy.deepcopy(parse_data["text"]),
766
+ parse_data_intent=parse_data["intent"],
767
+ parse_data_entities=copy.deepcopy(parse_data["entities"]),
768
+ )
769
+
770
+ self._check_for_unseen_features(parse_data)
771
+
772
+ return parse_data
773
+
774
+ def _sanitize_message(self, message: UserMessage) -> UserMessage:
775
+ """Sanitize user message by removing prepended slashes before the
776
+ actual content.
777
+ """
778
+ # Regex pattern to match leading slashes and any whitespace before
779
+ # actual content
780
+ pattern = r"^[/\s]+"
781
+ # Remove the matched pattern from the beginning of the message
782
+ message.text = re.sub(pattern, "", message.text).strip()
783
+ return message
784
+
785
+ async def _parse_message_with_intent_trigger(
786
+ self,
787
+ message: Message,
788
+ tracker: Optional[DialogueStateTracker] = None,
789
+ only_output_properties: bool = True,
790
+ ) -> Dict[Text, Any]:
791
+ """Parses a message with intent triggers."""
792
+ parse_data: Dict[Text, Any] = {
793
+ TEXT: "",
794
+ INTENT: {INTENT_NAME_KEY: None, PREDICTED_CONFIDENCE_KEY: 0.0},
795
+ ENTITIES: [],
796
+ COMMANDS: [],
797
+ }
798
+ parse_data.update(
799
+ message.as_dict(only_output_properties=only_output_properties)
800
+ )
801
+
802
+ if tracker:
803
+ commands = await self._nlu_to_commands(parse_data, tracker)
804
+ if (
805
+ tracker.has_coexistence_routing_slot
806
+ and tracker.get_slot(ROUTE_TO_CALM_SLOT) is None
807
+ ):
808
+ # if we are currently not routing to either CALM or dm1
809
+ # we make a sticky routing to CALM if there are any commands
810
+ # from the trigger intent parsing
811
+ # or a sticky routing to dm1 if there are no commands
812
+ commands.append(
813
+ SetSlotCommand(ROUTE_TO_CALM_SLOT, len(commands) > 0).as_dict()
814
+ )
815
+ parse_data[COMMANDS] = commands
816
+
817
+ return parse_data
818
+
819
+ def _update_full_retrieval_intent(self, parse_data: Dict[Text, Any]) -> None:
820
+ """Update the parse data with the full retrieval intent.
821
+
822
+ Args:
823
+ parse_data: Message parse data to update.
824
+ """
825
+ intent_name = parse_data.get(INTENT, {}).get(INTENT_NAME_KEY)
826
+ response_selector = parse_data.get(RESPONSE_SELECTOR, {})
827
+ all_retrieval_intents = response_selector.get("all_retrieval_intents", [])
828
+ if intent_name and intent_name in all_retrieval_intents:
829
+ retrieval_intent = (
830
+ response_selector.get(intent_name, {})
831
+ .get(RESPONSE, {})
832
+ .get(INTENT_RESPONSE_KEY)
833
+ )
834
+ parse_data[INTENT][FULL_RETRIEVAL_INTENT_NAME_KEY] = retrieval_intent
835
+
836
+ async def _nlu_to_commands(
837
+ self, parse_data: Dict[str, Any], tracker: DialogueStateTracker
838
+ ) -> List[Dict[str, Any]]:
839
+ """Converts the NLU parse data to commands using the adaptor.
840
+
841
+ This is used if we receive intents/entities directly using `/intent{...}`
842
+ syntax. In this case, the nlu graph is not run. Therefore, we need to
843
+ convert the parse data to commands outside the graph.
844
+ """
845
+ from rasa.dialogue_understanding.generator.nlu_command_adapter import (
846
+ NLUCommandAdapter,
847
+ )
848
+
849
+ commands = NLUCommandAdapter.convert_nlu_to_commands(
850
+ Message(parse_data), tracker, await self.get_flows()
851
+ )
852
+
853
+ # if there are no converted commands and parsed data contains invalid intent
854
+ # add CannotHandleCommand as fallback
855
+ if len(commands) == 0 and self._contains_undefined_intent(Message(parse_data)):
856
+ structlogger.warning(
857
+ "processor.message.nlu_to_commands.invalid_intent",
858
+ event_info=(
859
+ f"No NLU commands converted and parsed data contains"
860
+ f"invalid intent: {parse_data[INTENT]['name']}. "
861
+ f"Returning CannotHandleCommand() as a fallback."
862
+ ),
863
+ invalid_intent=parse_data[INTENT]["name"],
864
+ )
865
+ commands.append(
866
+ CannotHandleCommand(RASA_PATTERN_CANNOT_HANDLE_INVALID_INTENT)
867
+ )
868
+
869
+ return [command.as_dict() for command in commands]
870
+
871
+ def _contains_undefined_intent(self, message: Message) -> bool:
872
+ """Checks if the message contains an intent that is undefined
873
+ in the domain.
874
+ """
875
+ intent_name = message.get(INTENT, {}).get("name")
876
+ return intent_name is not None and intent_name not in self.domain.intents
877
+
878
+ async def _parse_message_with_graph(
879
+ self,
880
+ message: UserMessage,
881
+ tracker: Optional[DialogueStateTracker] = None,
882
+ only_output_properties: bool = True,
883
+ ) -> Dict[Text, Any]:
884
+ """Interprets the passed message.
885
+
886
+ Arguments:
887
+ message: Message to handle
888
+ tracker: Tracker to use
889
+ only_output_properties: If `True`, restrict the output to
890
+ Message.only_output_properties.
891
+
892
+ Returns:
893
+ Parsed data extracted from the message.
894
+ """
895
+ results = await self.graph_runner.run(
896
+ inputs={PLACEHOLDER_MESSAGE: [message], PLACEHOLDER_TRACKER: tracker},
897
+ targets=[self.model_metadata.nlu_target],
898
+ )
899
+ parsed_messages = results[self.model_metadata.nlu_target]
900
+ parsed_message = parsed_messages[0]
901
+ parse_data = {
902
+ TEXT: "",
903
+ INTENT: {INTENT_NAME_KEY: None, PREDICTED_CONFIDENCE_KEY: 0.0},
904
+ ENTITIES: [],
905
+ COMMANDS: [],
906
+ }
907
+ parse_data.update(
908
+ parsed_message.as_dict(only_output_properties=only_output_properties)
909
+ )
910
+ return parse_data
911
+
912
+ async def _handle_message_with_tracker(
913
+ self, message: UserMessage, tracker: DialogueStateTracker
914
+ ) -> None:
915
+
916
+ if message.parse_data:
917
+ parse_data = message.parse_data
918
+ else:
919
+ parse_data = await self.parse_message(message, tracker)
920
+
921
+ # don't ever directly mutate the tracker
922
+ # - instead pass its events to log
923
+ tracker.update(
924
+ UserUttered(
925
+ message.text,
926
+ parse_data["intent"],
927
+ parse_data["entities"],
928
+ parse_data,
929
+ input_channel=message.input_channel,
930
+ message_id=message.message_id,
931
+ metadata=message.metadata,
932
+ ),
933
+ self.domain,
934
+ )
935
+
936
+ if parse_data["entities"]:
937
+ self._log_slots(tracker)
938
+
939
+ logger.debug(
940
+ f"Logged UserUtterance - tracker now has {len(tracker.events)} events."
941
+ )
942
+
943
+ @staticmethod
944
+ def _should_handle_message(tracker: DialogueStateTracker) -> bool:
945
+ return not tracker.is_paused() or (
946
+ tracker.latest_message is not None
947
+ and tracker.latest_message.intent.get(INTENT_NAME_KEY)
948
+ == USER_INTENT_RESTART
949
+ )
950
+
951
+ def _tracker_state_specific_action_limit(
952
+ self, tracker: DialogueStateTracker
953
+ ) -> int:
954
+ """Select the action limit based on the tracker state.
955
+
956
+ Usually, we want to limit the number of predictions to the number of actions
957
+ that have been executed in the conversation so far. However, if the
958
+ conversation is currently in a state where the user is correcting the flow
959
+ we want to allow for more predictions to be made as we might be traversing
960
+ through a long flow.
961
+
962
+ Args:
963
+ tracker: instance of DialogueStateTracker.
964
+
965
+ Returns:
966
+ The maximum number of predictions to make.
967
+ """
968
+ reversed_events = list(tracker.events)[::-1]
969
+ is_conversation_in_flow_correction = False
970
+ for e in reversed_events:
971
+ if isinstance(e, ActionExecuted):
972
+ if e.action_name in (ACTION_LISTEN_NAME, ACTION_SESSION_START_NAME):
973
+ break
974
+ elif e.action_name == ACTION_CORRECT_FLOW_SLOT:
975
+ is_conversation_in_flow_correction = True
976
+ break
977
+
978
+ if is_conversation_in_flow_correction:
979
+ # allow for more predictions to be made as we might be traversing through
980
+ # a long flow. We multiply the number of predictions by 10 to allow for
981
+ # more predictions to be made - the factor is a best guess.
982
+ return self.max_number_of_predictions * 5
983
+ return self.max_number_of_predictions
984
+
985
+ def is_action_limit_reached(
986
+ self, tracker: DialogueStateTracker, should_predict_another_action: bool
987
+ ) -> bool:
988
+ """Check whether the maximum number of predictions has been met.
989
+
990
+ Args:
991
+ tracker: instance of DialogueStateTracker.
992
+ should_predict_another_action: Whether the last executed action allows
993
+ for more actions to be predicted or not.
994
+
995
+ Returns:
996
+ `True` if the limit of actions to predict has been reached.
997
+ """
998
+ reversed_events = list(tracker.events)[::-1]
999
+ num_predicted_actions = 0
1000
+ state_specific_action_limit = self._tracker_state_specific_action_limit(tracker)
1001
+
1002
+ for e in reversed_events:
1003
+ if isinstance(e, ActionExecuted):
1004
+ if e.action_name in (ACTION_LISTEN_NAME, ACTION_SESSION_START_NAME):
1005
+ break
1006
+ num_predicted_actions += 1
1007
+
1008
+ return (
1009
+ num_predicted_actions >= state_specific_action_limit
1010
+ and should_predict_another_action
1011
+ )
1012
+
1013
+ async def _run_prediction_loop(
1014
+ self, output_channel: OutputChannel, tracker: DialogueStateTracker
1015
+ ) -> None:
1016
+ # keep taking actions decided by the policy until it chooses to 'listen'
1017
+ should_predict_another_action = True
1018
+
1019
+ tracker = await self.run_command_processor(tracker)
1020
+
1021
+ # action loop. predicts actions until we hit action listen
1022
+ while should_predict_another_action and self._should_handle_message(tracker):
1023
+ # this actually just calls the policy's method by the same name
1024
+ try:
1025
+ action, prediction = await self.predict_next_with_tracker_if_should(
1026
+ tracker
1027
+ )
1028
+ except ActionLimitReached:
1029
+ logger.warning(
1030
+ "Circuit breaker tripped. Stopped predicting "
1031
+ f"more actions for sender '{tracker.sender_id}'."
1032
+ )
1033
+ if self.on_circuit_break:
1034
+ # call a registered callback
1035
+ self.on_circuit_break(tracker, output_channel, self.nlg)
1036
+ break
1037
+
1038
+ if prediction.is_end_to_end_prediction:
1039
+ logger.debug(
1040
+ f"An end-to-end prediction was made which has triggered the 2nd "
1041
+ f"execution of the default action '{ACTION_EXTRACT_SLOTS}'."
1042
+ )
1043
+ tracker = await self.run_action_extract_slots(output_channel, tracker)
1044
+
1045
+ should_predict_another_action = await self._run_action(
1046
+ action, tracker, output_channel, self.nlg, prediction
1047
+ )
1048
+
1049
+ @staticmethod
1050
+ def should_predict_another_action(action_name: Text) -> bool:
1051
+ """Determine whether the processor should predict another action.
1052
+
1053
+ Args:
1054
+ action_name: Name of the latest executed action.
1055
+
1056
+ Returns:
1057
+ `False` if `action_name` is `ACTION_LISTEN_NAME` or
1058
+ `ACTION_SESSION_START_NAME`, otherwise `True`.
1059
+ """
1060
+ return action_name not in (ACTION_LISTEN_NAME, ACTION_SESSION_START_NAME)
1061
+
1062
+ async def execute_side_effects(
1063
+ self,
1064
+ events: List[Event],
1065
+ tracker: DialogueStateTracker,
1066
+ output_channel: Optional[OutputChannel],
1067
+ ) -> None:
1068
+ """Attach tracker, send bot messages, schedule and cancel reminders."""
1069
+ if output_channel:
1070
+ output_channel.attach_tracker_state(tracker)
1071
+ await self._send_bot_messages(events, tracker, output_channel)
1072
+ await self._schedule_reminders(events, tracker, output_channel)
1073
+ await self._cancel_reminders(events, tracker)
1074
+
1075
+ @staticmethod
1076
+ async def _send_bot_messages(
1077
+ events: List[Event],
1078
+ tracker: DialogueStateTracker,
1079
+ output_channel: OutputChannel,
1080
+ ) -> None:
1081
+ """Send all the bot messages that are logged in the events array."""
1082
+ for e in events:
1083
+ if not isinstance(e, BotUttered):
1084
+ continue
1085
+
1086
+ await output_channel.send_response(tracker.sender_id, e.message())
1087
+
1088
+ async def _schedule_reminders(
1089
+ self,
1090
+ events: List[Event],
1091
+ tracker: DialogueStateTracker,
1092
+ output_channel: OutputChannel,
1093
+ ) -> None:
1094
+ """Uses the scheduler to time a job to trigger the passed reminder.
1095
+
1096
+ Reminders with the same `id` property will overwrite one another
1097
+ (i.e. only one of them will eventually run).
1098
+ """
1099
+ for e in events:
1100
+ if not isinstance(e, ReminderScheduled):
1101
+ continue
1102
+
1103
+ (await jobs.scheduler()).add_job(
1104
+ self.handle_reminder,
1105
+ "date",
1106
+ run_date=e.trigger_date_time,
1107
+ args=[e, tracker.sender_id, output_channel],
1108
+ id=e.name,
1109
+ replace_existing=True,
1110
+ name=e.scheduled_job_name(tracker.sender_id),
1111
+ )
1112
+
1113
+ @staticmethod
1114
+ async def _cancel_reminders(
1115
+ events: List[Event], tracker: DialogueStateTracker
1116
+ ) -> None:
1117
+ """Cancel reminders that match the `ReminderCancelled` event."""
1118
+ # All Reminders specified by ReminderCancelled events will be cancelled
1119
+ for event in events:
1120
+ if isinstance(event, ReminderCancelled):
1121
+ scheduler = await jobs.scheduler()
1122
+ for scheduled_job in scheduler.get_jobs():
1123
+ if event.cancels_job_with_name(
1124
+ scheduled_job.name, tracker.sender_id
1125
+ ):
1126
+ scheduler.remove_job(scheduled_job.id)
1127
+
1128
+ async def run_command_processor(
1129
+ self, tracker: DialogueStateTracker
1130
+ ) -> DialogueStateTracker:
1131
+ """Run the command processor to apply commands to the stack.
1132
+
1133
+ The command processor applies all the commands from the NLU pipeline to the
1134
+ dialogue stack. The dialogue stack then acts as base for decision making for
1135
+ the policies that can use it.
1136
+
1137
+ Args:
1138
+ tracker: the dialogue state tracker
1139
+
1140
+ Returns:
1141
+ An updated tracker after commands have been applied
1142
+ """
1143
+ target = "command_processor"
1144
+ results = await self.graph_runner.run(
1145
+ inputs={PLACEHOLDER_TRACKER: tracker.copy()}, targets=[target]
1146
+ )
1147
+ events = results[target]
1148
+ tracker.update_with_events(events)
1149
+ return tracker
1150
+
1151
+ async def get_flows(self) -> FlowsList:
1152
+ """Get the list of flows from the graph."""
1153
+ target = "flows_provider"
1154
+ results = await self.graph_runner.run(inputs={}, targets=[target])
1155
+ return results[target]
1156
+
1157
+ async def _run_action(
1158
+ self,
1159
+ action: rasa.core.actions.action.Action,
1160
+ tracker: DialogueStateTracker,
1161
+ output_channel: OutputChannel,
1162
+ nlg: NaturalLanguageGenerator,
1163
+ prediction: PolicyPrediction,
1164
+ ) -> bool:
1165
+ # events and return values are used to update
1166
+ # the tracker state after an action has been taken
1167
+ try:
1168
+ # Use temporary tracker as we might need to discard the policy events in
1169
+ # case of a rejection.
1170
+ temporary_tracker = tracker.copy()
1171
+ temporary_tracker.update_with_events(prediction.events)
1172
+
1173
+ run_args = inspect.getfullargspec(action.run).args
1174
+ if "metadata" in run_args:
1175
+ events = await action.run(
1176
+ output_channel,
1177
+ nlg,
1178
+ temporary_tracker,
1179
+ self.domain,
1180
+ metadata=prediction.action_metadata,
1181
+ )
1182
+ else:
1183
+ events = await action.run(
1184
+ output_channel, nlg, temporary_tracker, self.domain
1185
+ )
1186
+ except rasa.core.actions.action.ActionExecutionRejection:
1187
+ events = [
1188
+ ActionExecutionRejected(
1189
+ action.name(), prediction.policy_name, prediction.max_confidence
1190
+ )
1191
+ ]
1192
+ tracker.update(events[0])
1193
+ return self.should_predict_another_action(action.name())
1194
+ except Exception:
1195
+ logger.exception(
1196
+ f"Encountered an exception while running action '{action.name()}'."
1197
+ "Bot will continue, but the actions events are lost. "
1198
+ "Please check the logs of your action server for "
1199
+ "more information."
1200
+ )
1201
+ events = []
1202
+
1203
+ self._log_action_on_tracker(tracker, action, events, prediction)
1204
+
1205
+ if any(isinstance(e, UserUttered) for e in events):
1206
+ logger.debug(
1207
+ f"A `UserUttered` event was returned by executing "
1208
+ f"action '{action.name()}'. This will run the default action "
1209
+ f"'{ACTION_EXTRACT_SLOTS}'."
1210
+ )
1211
+ tracker = await self.run_action_extract_slots(output_channel, tracker)
1212
+
1213
+ if action.name() != ACTION_LISTEN_NAME and not action.name().startswith(
1214
+ UTTER_PREFIX
1215
+ ):
1216
+ self._log_slots(tracker)
1217
+
1218
+ await self.execute_side_effects(events, tracker, output_channel)
1219
+
1220
+ return self.should_predict_another_action(action.name())
1221
+
1222
+ def _log_action_on_tracker(
1223
+ self,
1224
+ tracker: DialogueStateTracker,
1225
+ action: Action,
1226
+ events: Optional[List[Event]],
1227
+ prediction: PolicyPrediction,
1228
+ ) -> None:
1229
+ # Ensures that the code still works even if a lazy programmer missed
1230
+ # to type `return []` at the end of an action or the run method
1231
+ # returns `None` for some other reason.
1232
+ if events is None:
1233
+ events = []
1234
+
1235
+ action_was_rejected_manually = any(
1236
+ isinstance(event, ActionExecutionRejected) for event in events
1237
+ )
1238
+ if not action_was_rejected_manually:
1239
+ structlogger.debug(
1240
+ "processor.actions.policy_prediction",
1241
+ prediction_events=copy.deepcopy(prediction.events),
1242
+ policy_name=prediction.policy_name,
1243
+ action_name=action.name(),
1244
+ )
1245
+ tracker.update_with_events(prediction.events)
1246
+
1247
+ # log the action and its produced events
1248
+ tracker.update(action.event_for_successful_execution(prediction))
1249
+
1250
+ structlogger.debug(
1251
+ "processor.actions.log",
1252
+ action_name=action.name(),
1253
+ rasa_events=copy.deepcopy(events),
1254
+ )
1255
+ tracker.update_with_events(events)
1256
+
1257
+ def _has_session_expired(self, tracker: DialogueStateTracker) -> bool:
1258
+ """Determine whether the latest session in `tracker` has expired.
1259
+
1260
+ Args:
1261
+ tracker: Tracker to inspect.
1262
+
1263
+ Returns:
1264
+ `True` if the session in `tracker` has expired, `False` otherwise.
1265
+ """
1266
+ if not self.domain.session_config.are_sessions_enabled():
1267
+ # tracker has never expired if sessions are disabled
1268
+ return False
1269
+
1270
+ user_uttered_event: Optional[UserUttered] = tracker.get_last_event_for(
1271
+ UserUttered
1272
+ )
1273
+
1274
+ if not user_uttered_event:
1275
+ # there is no user event so far so the session should not be considered
1276
+ # expired
1277
+ return False
1278
+
1279
+ time_delta_in_seconds = time.time() - user_uttered_event.timestamp
1280
+ has_expired = (
1281
+ time_delta_in_seconds / 60
1282
+ > self.domain.session_config.session_expiration_time
1283
+ )
1284
+ if has_expired:
1285
+ logger.debug(
1286
+ f"The latest session for conversation ID '{tracker.sender_id}' has "
1287
+ f"expired."
1288
+ )
1289
+
1290
+ return has_expired
1291
+
1292
+ async def save_tracker(self, tracker: DialogueStateTracker) -> None:
1293
+ """Save the given tracker to the tracker store.
1294
+
1295
+ Args:
1296
+ tracker: Tracker to be saved.
1297
+ """
1298
+ await self.tracker_store.save(tracker)
1299
+
1300
+ async def _predict_next_with_tracker(
1301
+ self, tracker: DialogueStateTracker
1302
+ ) -> PolicyPrediction:
1303
+ """Collect predictions from ensemble and return action and predictions."""
1304
+ followup_action = tracker.followup_action
1305
+ if followup_action:
1306
+ tracker.clear_followup_action()
1307
+ if followup_action in self.domain.action_names_or_texts:
1308
+ prediction = PolicyPrediction.for_action_name(
1309
+ self.domain, followup_action, FOLLOWUP_ACTION
1310
+ )
1311
+ return prediction
1312
+
1313
+ logger.error(
1314
+ f"Trying to run unknown follow-up action '{followup_action}'. "
1315
+ "Instead of running that, Rasa Open Source will ignore the action "
1316
+ "and predict the next action."
1317
+ )
1318
+
1319
+ target = self.model_metadata.core_target
1320
+ if not target:
1321
+ raise ValueError("Cannot predict next action if there is no core target.")
1322
+
1323
+ results = await self.graph_runner.run(
1324
+ inputs={
1325
+ PLACEHOLDER_TRACKER: tracker,
1326
+ PLACEHOLDER_ENDPOINTS: self.endpoints,
1327
+ },
1328
+ targets=[target],
1329
+ )
1330
+ policy_prediction = results[target]
1331
+ return policy_prediction