rasa-pro 3.11.4__py3-none-any.whl → 3.12.0__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 (580) hide show
  1. README.md +10 -13
  2. rasa/__main__.py +7 -7
  3. rasa/anonymization/anonymisation_rule_yaml_reader.py +1 -1
  4. rasa/anonymization/anonymization_pipeline.py +3 -3
  5. rasa/anonymization/anonymization_rule_executor.py +17 -11
  6. rasa/anonymization/anonymization_rule_orchestrator.py +2 -3
  7. rasa/cli/arguments/data.py +2 -2
  8. rasa/cli/arguments/default_arguments.py +1 -1
  9. rasa/cli/arguments/evaluate.py +2 -1
  10. rasa/cli/arguments/interactive.py +1 -1
  11. rasa/cli/arguments/run.py +1 -1
  12. rasa/cli/arguments/test.py +7 -5
  13. rasa/cli/arguments/train.py +3 -3
  14. rasa/cli/arguments/visualize.py +2 -2
  15. rasa/cli/arguments/x.py +1 -0
  16. rasa/cli/data.py +20 -3
  17. rasa/cli/dialogue_understanding_test.py +386 -0
  18. rasa/cli/evaluate.py +1 -1
  19. rasa/cli/export.py +6 -6
  20. rasa/cli/inspect.py +20 -1
  21. rasa/cli/interactive.py +4 -5
  22. rasa/cli/llm_fine_tuning.py +51 -16
  23. rasa/cli/markers.py +1 -2
  24. rasa/cli/project_templates/calm/actions/add_contact.py +1 -1
  25. rasa/cli/project_templates/calm/config.yml +2 -2
  26. rasa/cli/project_templates/calm/domain/list_contacts.yml +1 -2
  27. rasa/cli/project_templates/calm/domain/remove_contact.yml +1 -2
  28. rasa/cli/project_templates/calm/domain/shared.yml +1 -4
  29. rasa/cli/project_templates/calm/endpoints.yml +2 -2
  30. rasa/cli/project_templates/tutorial/actions/actions.py +3 -2
  31. rasa/cli/shell.py +5 -6
  32. rasa/cli/studio/download.py +1 -2
  33. rasa/cli/studio/studio.py +2 -3
  34. rasa/cli/studio/train.py +0 -1
  35. rasa/cli/telemetry.py +2 -2
  36. rasa/cli/test.py +11 -11
  37. rasa/cli/train.py +3 -0
  38. rasa/cli/utils.py +25 -5
  39. rasa/constants.py +0 -1
  40. rasa/core/__init__.py +0 -1
  41. rasa/core/actions/action.py +137 -208
  42. rasa/core/actions/action_handle_digressions.py +164 -0
  43. rasa/core/actions/action_hangup.py +1 -1
  44. rasa/core/actions/action_repeat_bot_messages.py +2 -2
  45. rasa/core/actions/action_run_slot_rejections.py +18 -6
  46. rasa/core/actions/action_trigger_chitchat.py +1 -1
  47. rasa/core/actions/action_trigger_flow.py +5 -5
  48. rasa/core/actions/action_trigger_search.py +1 -1
  49. rasa/core/actions/custom_action_executor.py +1 -1
  50. rasa/core/actions/direct_custom_actions_executor.py +1 -0
  51. rasa/core/actions/forms.py +22 -15
  52. rasa/core/actions/http_custom_action_executor.py +8 -1
  53. rasa/core/actions/loops.py +3 -3
  54. rasa/core/actions/two_stage_fallback.py +13 -13
  55. rasa/core/auth_retry_tracker_store.py +1 -2
  56. rasa/core/brokers/broker.py +2 -1
  57. rasa/core/brokers/file.py +1 -1
  58. rasa/core/brokers/kafka.py +8 -8
  59. rasa/core/brokers/pika.py +8 -9
  60. rasa/core/brokers/sql.py +4 -3
  61. rasa/core/channels/__init__.py +7 -0
  62. rasa/core/channels/botframework.py +2 -2
  63. rasa/core/channels/callback.py +4 -4
  64. rasa/core/channels/channel.py +11 -11
  65. rasa/core/channels/console.py +0 -1
  66. rasa/core/channels/development_inspector.py +80 -24
  67. rasa/core/channels/facebook.py +5 -5
  68. rasa/core/channels/hangouts.py +7 -8
  69. rasa/core/channels/inspector/dist/assets/Tableau10-1b767f5e.js +1 -0
  70. rasa/core/channels/inspector/dist/assets/arc-9f1365dc.js +1 -0
  71. rasa/core/channels/inspector/dist/assets/blockDiagram-38ab4fdb-e0f81b12.js +118 -0
  72. rasa/core/channels/inspector/dist/assets/c4Diagram-3d4e48cf-9deaee1c.js +10 -0
  73. rasa/core/channels/inspector/dist/assets/channel-44956714.js +1 -0
  74. rasa/core/channels/inspector/dist/assets/classDiagram-70f12bd4-20450a96.js +2 -0
  75. rasa/core/channels/inspector/dist/assets/classDiagram-v2-f2320105-749d2abf.js +2 -0
  76. rasa/core/channels/inspector/dist/assets/clone-a9475142.js +1 -0
  77. rasa/core/channels/inspector/dist/assets/{createText-62fc7601-89c73b31.js → createText-2e5e7dd3-bef0b38c.js} +1 -1
  78. rasa/core/channels/inspector/dist/assets/edges-e0da2a9e-943801a7.js +4 -0
  79. rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-907e0440.js → erDiagram-9861fffd-d523a948.js} +4 -4
  80. rasa/core/channels/inspector/dist/assets/flowDb-956e92f1-54e4cf19.js +10 -0
  81. rasa/core/channels/inspector/dist/assets/flowDiagram-66a62f08-48bfbbe8.js +4 -0
  82. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-43fa749a.js +1 -0
  83. rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-4a651766-17c30827.js +139 -0
  84. rasa/core/channels/inspector/dist/assets/ganttDiagram-c361ad54-43086f2d.js +257 -0
  85. rasa/core/channels/inspector/dist/assets/gitGraphDiagram-72cf32ee-5c8b693e.js +70 -0
  86. rasa/core/channels/inspector/dist/assets/graph-41a90d26.js +1 -0
  87. rasa/core/channels/inspector/dist/assets/index-3862675e-b43eeae9.js +1 -0
  88. rasa/core/channels/inspector/dist/assets/{index-e793d777.js → index-e8affe45.js} +201 -196
  89. rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-8ceba4db.js → infoDiagram-f8f76790-0b20676b.js} +1 -1
  90. rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-960d3809.js → journeyDiagram-49397b02-39bce7b5.js} +4 -4
  91. rasa/core/channels/inspector/dist/assets/katex-498eb57e.js +261 -0
  92. rasa/core/channels/inspector/dist/assets/layout-dc8eeea4.js +1 -0
  93. rasa/core/channels/inspector/dist/assets/{line-eeccc4e2.js → line-c4d2e756.js} +1 -1
  94. rasa/core/channels/inspector/dist/assets/linear-86f6f2d9.js +1 -0
  95. rasa/core/channels/inspector/dist/assets/mindmap-definition-fc14e90a-4216f771.js +312 -0
  96. rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-dc9b5e1b.js → pieDiagram-8a3498a8-1a0cfa96.js} +7 -7
  97. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-a08cba6d.js → quadrantDiagram-120e2f19-f91e67cf.js} +1 -1
  98. rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-87242b9e.js → requirementDiagram-deff3bca-d4046bed.js} +2 -2
  99. rasa/core/channels/inspector/dist/assets/sankeyDiagram-04a897e0-2cf6d1d7.js +8 -0
  100. rasa/core/channels/inspector/dist/assets/sequenceDiagram-704730f1-751ac4f5.js +122 -0
  101. rasa/core/channels/inspector/dist/assets/stateDiagram-587899a1-f734f4d4.js +1 -0
  102. rasa/core/channels/inspector/dist/assets/stateDiagram-v2-d93cdb3a-91c65710.js +1 -0
  103. rasa/core/channels/inspector/dist/assets/{styles-9c745c82-cef936a6.js → styles-6aaf32cf-e0cff7be.js} +1 -1
  104. rasa/core/channels/inspector/dist/assets/styles-9a916d00-c8029e5d.js +160 -0
  105. rasa/core/channels/inspector/dist/assets/styles-c10674c1-114f312a.js +116 -0
  106. rasa/core/channels/inspector/dist/assets/svgDrawCommon-08f97a94-b7b9dc00.js +1 -0
  107. rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-0d39bdb2.js → timeline-definition-85554ec2-9536d189.js} +3 -3
  108. rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-a03fa445.js → xychartDiagram-e933f94c-bf3b0f36.js} +3 -3
  109. rasa/core/channels/inspector/dist/index.html +1 -1
  110. rasa/core/channels/inspector/package.json +11 -3
  111. rasa/core/channels/inspector/src/App.tsx +15 -2
  112. rasa/core/channels/inspector/src/components/RasaLogo.tsx +31 -0
  113. rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +68 -0
  114. rasa/core/channels/inspector/src/components/Welcome.tsx +19 -13
  115. rasa/core/channels/inspector/yarn.lock +94 -99
  116. rasa/core/channels/mattermost.py +4 -4
  117. rasa/core/channels/rasa_chat.py +4 -4
  118. rasa/core/channels/rest.py +11 -12
  119. rasa/core/channels/rocketchat.py +4 -3
  120. rasa/core/channels/slack.py +6 -5
  121. rasa/core/channels/socketio.py +8 -28
  122. rasa/core/channels/studio_chat.py +212 -0
  123. rasa/core/channels/telegram.py +105 -55
  124. rasa/core/channels/twilio.py +3 -3
  125. rasa/core/channels/vier_cvg.py +2 -2
  126. rasa/core/channels/voice_ready/audiocodes.py +51 -32
  127. rasa/core/channels/voice_ready/jambonz.py +5 -5
  128. rasa/core/channels/voice_ready/jambonz_protocol.py +3 -4
  129. rasa/core/channels/voice_ready/twilio_voice.py +9 -8
  130. rasa/core/channels/voice_ready/utils.py +2 -2
  131. rasa/core/channels/voice_stream/asr/asr_engine.py +12 -6
  132. rasa/core/channels/voice_stream/asr/asr_event.py +5 -0
  133. rasa/core/channels/voice_stream/asr/azure.py +16 -3
  134. rasa/core/channels/voice_stream/asr/deepgram.py +76 -19
  135. rasa/core/channels/voice_stream/audiocodes.py +292 -0
  136. rasa/core/channels/voice_stream/browser_audio.py +14 -7
  137. rasa/core/channels/voice_stream/call_state.py +6 -2
  138. rasa/core/channels/voice_stream/genesys.py +320 -0
  139. rasa/core/channels/voice_stream/tts/azure.py +13 -5
  140. rasa/core/channels/voice_stream/tts/cartesia.py +34 -14
  141. rasa/core/channels/voice_stream/tts/tts_cache.py +3 -2
  142. rasa/core/channels/voice_stream/tts/tts_engine.py +1 -1
  143. rasa/core/channels/voice_stream/twilio_media_streams.py +12 -8
  144. rasa/core/channels/voice_stream/util.py +1 -1
  145. rasa/core/channels/voice_stream/voice_channel.py +100 -56
  146. rasa/core/channels/webexteams.py +3 -4
  147. rasa/core/constants.py +2 -0
  148. rasa/core/evaluation/marker.py +7 -6
  149. rasa/core/evaluation/marker_base.py +15 -16
  150. rasa/core/evaluation/marker_stats.py +3 -4
  151. rasa/core/evaluation/marker_tracker_loader.py +5 -4
  152. rasa/core/exporter.py +4 -4
  153. rasa/core/featurizers/precomputation.py +8 -8
  154. rasa/core/featurizers/single_state_featurizer.py +7 -7
  155. rasa/core/featurizers/tracker_featurizers.py +13 -13
  156. rasa/core/http_interpreter.py +3 -4
  157. rasa/core/information_retrieval/__init__.py +1 -1
  158. rasa/core/information_retrieval/faiss.py +4 -4
  159. rasa/core/information_retrieval/information_retrieval.py +2 -2
  160. rasa/core/information_retrieval/milvus.py +3 -3
  161. rasa/core/information_retrieval/qdrant.py +3 -3
  162. rasa/core/jobs.py +1 -0
  163. rasa/core/lock.py +2 -3
  164. rasa/core/lock_store.py +3 -3
  165. rasa/core/migrate.py +12 -9
  166. rasa/core/nlg/__init__.py +1 -1
  167. rasa/core/nlg/callback.py +2 -3
  168. rasa/core/nlg/contextual_response_rephraser.py +82 -14
  169. rasa/core/nlg/generator.py +85 -17
  170. rasa/core/nlg/interpolator.py +4 -3
  171. rasa/core/nlg/response.py +9 -7
  172. rasa/core/nlg/summarize.py +1 -0
  173. rasa/core/nlg/translate.py +55 -0
  174. rasa/core/persistor.py +3 -3
  175. rasa/core/policies/ensemble.py +10 -9
  176. rasa/core/policies/enterprise_search_policy.py +87 -21
  177. rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +1 -1
  178. rasa/core/policies/flow_policy.py +13 -14
  179. rasa/core/policies/flows/flow_executor.py +85 -55
  180. rasa/core/policies/intentless_policy.py +6 -7
  181. rasa/core/policies/memoization.py +22 -20
  182. rasa/core/policies/policy.py +24 -22
  183. rasa/core/policies/rule_policy.py +37 -36
  184. rasa/core/policies/ted_policy.py +87 -85
  185. rasa/core/policies/unexpected_intent_policy.py +77 -75
  186. rasa/core/processor.py +167 -74
  187. rasa/core/run.py +5 -4
  188. rasa/core/secrets_manager/endpoints.py +2 -3
  189. rasa/core/secrets_manager/factory.py +2 -3
  190. rasa/core/secrets_manager/secret_manager.py +2 -3
  191. rasa/core/secrets_manager/vault.py +2 -2
  192. rasa/core/test.py +30 -30
  193. rasa/core/tracker_store.py +138 -49
  194. rasa/core/train.py +1 -1
  195. rasa/core/training/__init__.py +2 -2
  196. rasa/core/training/converters/responses_prefix_converter.py +1 -2
  197. rasa/core/training/interactive.py +13 -13
  198. rasa/core/training/story_conflict.py +4 -5
  199. rasa/core/training/training.py +3 -5
  200. rasa/core/utils.py +5 -5
  201. rasa/core/visualize.py +1 -1
  202. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -2
  203. rasa/dialogue_understanding/coexistence/llm_based_router.py +5 -5
  204. rasa/dialogue_understanding/commands/__init__.py +22 -22
  205. rasa/dialogue_understanding/commands/can_not_handle_command.py +38 -1
  206. rasa/dialogue_understanding/commands/cancel_flow_command.py +96 -9
  207. rasa/dialogue_understanding/commands/change_flow_command.py +36 -2
  208. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +36 -4
  209. rasa/dialogue_understanding/commands/clarify_command.py +46 -4
  210. rasa/dialogue_understanding/commands/command.py +3 -2
  211. rasa/dialogue_understanding/commands/command_syntax_manager.py +55 -0
  212. rasa/dialogue_understanding/commands/correct_slots_command.py +14 -5
  213. rasa/dialogue_understanding/commands/error_command.py +1 -1
  214. rasa/dialogue_understanding/commands/free_form_answer_command.py +2 -1
  215. rasa/dialogue_understanding/commands/handle_code_change_command.py +2 -2
  216. rasa/dialogue_understanding/commands/handle_digressions_command.py +144 -0
  217. rasa/dialogue_understanding/commands/human_handoff_command.py +34 -4
  218. rasa/dialogue_understanding/commands/knowledge_answer_command.py +36 -4
  219. rasa/dialogue_understanding/commands/noop_command.py +2 -1
  220. rasa/dialogue_understanding/commands/prompt_command.py +94 -0
  221. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +34 -4
  222. rasa/dialogue_understanding/commands/restart_command.py +2 -5
  223. rasa/dialogue_understanding/commands/session_end_command.py +3 -5
  224. rasa/dialogue_understanding/commands/session_start_command.py +3 -5
  225. rasa/dialogue_understanding/commands/set_slot_command.py +55 -16
  226. rasa/dialogue_understanding/commands/skip_question_command.py +34 -4
  227. rasa/dialogue_understanding/commands/start_flow_command.py +78 -2
  228. rasa/dialogue_understanding/commands/user_silence_command.py +3 -5
  229. rasa/dialogue_understanding/commands/utils.py +126 -43
  230. rasa/dialogue_understanding/constants.py +2 -0
  231. rasa/dialogue_understanding/generator/__init__.py +2 -0
  232. rasa/dialogue_understanding/generator/command_generator.py +120 -79
  233. rasa/dialogue_understanding/generator/command_parser.py +245 -0
  234. rasa/dialogue_understanding/generator/constants.py +12 -4
  235. rasa/dialogue_understanding/generator/flow_retrieval.py +7 -7
  236. rasa/dialogue_understanding/generator/llm_based_command_generator.py +187 -59
  237. rasa/dialogue_understanding/generator/llm_command_generator.py +6 -3
  238. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +106 -110
  239. rasa/dialogue_understanding/generator/nlu_command_adapter.py +53 -11
  240. rasa/dialogue_understanding/generator/prompt_templates/__init__.py +0 -0
  241. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +58 -0
  242. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +57 -0
  243. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +574 -0
  244. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +41 -386
  245. rasa/dialogue_understanding/generator/utils.py +76 -0
  246. rasa/dialogue_understanding/patterns/cancel.py +2 -1
  247. rasa/dialogue_understanding/patterns/cannot_handle.py +1 -0
  248. rasa/dialogue_understanding/patterns/chitchat.py +1 -1
  249. rasa/dialogue_understanding/patterns/clarify.py +2 -1
  250. rasa/dialogue_understanding/patterns/code_change.py +2 -0
  251. rasa/dialogue_understanding/patterns/collect_information.py +7 -4
  252. rasa/dialogue_understanding/patterns/completed.py +1 -1
  253. rasa/dialogue_understanding/patterns/continue_interrupted.py +1 -1
  254. rasa/dialogue_understanding/patterns/correction.py +17 -3
  255. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +78 -2
  256. rasa/dialogue_understanding/patterns/handle_digressions.py +81 -0
  257. rasa/dialogue_understanding/patterns/human_handoff.py +1 -1
  258. rasa/dialogue_understanding/patterns/internal_error.py +1 -0
  259. rasa/dialogue_understanding/patterns/search.py +1 -1
  260. rasa/dialogue_understanding/patterns/session_start.py +1 -1
  261. rasa/dialogue_understanding/patterns/skip_question.py +1 -0
  262. rasa/dialogue_understanding/patterns/user_silence.py +1 -1
  263. rasa/dialogue_understanding/patterns/validate_slot.py +65 -0
  264. rasa/dialogue_understanding/processor/command_processor.py +193 -43
  265. rasa/dialogue_understanding/processor/command_processor_component.py +1 -1
  266. rasa/dialogue_understanding/stack/dialogue_stack.py +4 -3
  267. rasa/dialogue_understanding/stack/frames/__init__.py +2 -2
  268. rasa/dialogue_understanding/stack/frames/chit_chat_frame.py +4 -1
  269. rasa/dialogue_understanding/stack/frames/dialogue_stack_frame.py +2 -3
  270. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +5 -2
  271. rasa/dialogue_understanding/stack/frames/search_frame.py +4 -1
  272. rasa/dialogue_understanding/stack/utils.py +56 -10
  273. rasa/dialogue_understanding/utils.py +164 -0
  274. rasa/dialogue_understanding_test/README.md +429 -0
  275. rasa/dialogue_understanding_test/__init__.py +0 -0
  276. rasa/dialogue_understanding_test/command_comparison.py +60 -0
  277. rasa/dialogue_understanding_test/command_metric_calculation.py +122 -0
  278. rasa/dialogue_understanding_test/constants.py +22 -0
  279. rasa/dialogue_understanding_test/du_test_case.py +448 -0
  280. rasa/dialogue_understanding_test/du_test_result.py +390 -0
  281. rasa/dialogue_understanding_test/du_test_runner.py +322 -0
  282. rasa/dialogue_understanding_test/du_test_schema.yml +161 -0
  283. rasa/dialogue_understanding_test/io.py +443 -0
  284. rasa/dialogue_understanding_test/test_case_simulation/__init__.py +0 -0
  285. rasa/dialogue_understanding_test/test_case_simulation/exception.py +28 -0
  286. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +336 -0
  287. rasa/dialogue_understanding_test/utils.py +70 -0
  288. rasa/dialogue_understanding_test/validation.py +77 -0
  289. rasa/e2e_test/aggregate_test_stats_calculator.py +1 -1
  290. rasa/e2e_test/assertions.py +202 -175
  291. rasa/e2e_test/assertions_schema.yml +6 -0
  292. rasa/e2e_test/constants.py +16 -1
  293. rasa/e2e_test/e2e_config.py +102 -41
  294. rasa/e2e_test/e2e_config_schema.yml +28 -10
  295. rasa/e2e_test/e2e_test_case.py +5 -5
  296. rasa/e2e_test/e2e_test_converter.py +2 -3
  297. rasa/e2e_test/e2e_test_coverage_report.py +6 -6
  298. rasa/e2e_test/e2e_test_result.py +1 -1
  299. rasa/e2e_test/e2e_test_runner.py +143 -38
  300. rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2 +93 -0
  301. rasa/e2e_test/llm_judge_prompts/groundedness_prompt_template.jinja2 +169 -0
  302. rasa/e2e_test/stub_custom_action.py +1 -1
  303. rasa/e2e_test/utils/generative_assertions.py +243 -0
  304. rasa/e2e_test/utils/io.py +123 -93
  305. rasa/e2e_test/utils/validation.py +101 -3
  306. rasa/engine/caching.py +5 -7
  307. rasa/engine/constants.py +1 -1
  308. rasa/engine/graph.py +3 -2
  309. rasa/engine/language.py +182 -0
  310. rasa/engine/recipes/config_files/default_config.yml +4 -0
  311. rasa/engine/recipes/default_components.py +13 -15
  312. rasa/engine/recipes/default_recipe.py +65 -49
  313. rasa/engine/recipes/graph_recipe.py +10 -7
  314. rasa/engine/recipes/recipe.py +2 -2
  315. rasa/engine/runner/dask.py +2 -2
  316. rasa/engine/runner/interface.py +1 -0
  317. rasa/engine/storage/local_model_storage.py +6 -4
  318. rasa/engine/storage/resource.py +2 -1
  319. rasa/engine/storage/storage.py +8 -3
  320. rasa/engine/training/components.py +2 -1
  321. rasa/engine/training/fingerprinting.py +4 -2
  322. rasa/engine/training/graph_trainer.py +4 -4
  323. rasa/engine/training/hooks.py +2 -2
  324. rasa/engine/validation.py +36 -33
  325. rasa/exceptions.py +3 -2
  326. rasa/graph_components/converters/nlu_message_converter.py +3 -3
  327. rasa/graph_components/providers/domain_for_core_training_provider.py +3 -3
  328. rasa/graph_components/providers/domain_provider.py +3 -2
  329. rasa/graph_components/providers/flows_provider.py +2 -3
  330. rasa/graph_components/providers/forms_provider.py +4 -4
  331. rasa/graph_components/providers/nlu_training_data_provider.py +5 -3
  332. rasa/graph_components/providers/responses_provider.py +4 -4
  333. rasa/graph_components/providers/rule_only_provider.py +3 -2
  334. rasa/graph_components/providers/story_graph_provider.py +8 -8
  335. rasa/graph_components/providers/training_tracker_provider.py +3 -2
  336. rasa/graph_components/validators/default_recipe_validator.py +16 -16
  337. rasa/graph_components/validators/finetuning_validator.py +10 -8
  338. rasa/hooks.py +19 -14
  339. rasa/jupyter.py +2 -2
  340. rasa/llm_fine_tuning/annotation_module.py +4 -4
  341. rasa/llm_fine_tuning/conversations.py +5 -33
  342. rasa/llm_fine_tuning/llm_data_preparation_module.py +6 -4
  343. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +4 -4
  344. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +18 -13
  345. rasa/llm_fine_tuning/paraphrasing_module.py +6 -2
  346. rasa/llm_fine_tuning/storage.py +3 -3
  347. rasa/llm_fine_tuning/train_test_split_module.py +27 -27
  348. rasa/llm_fine_tuning/utils.py +7 -0
  349. rasa/markers/marker.py +2 -3
  350. rasa/markers/marker_base.py +1 -2
  351. rasa/markers/upload.py +2 -2
  352. rasa/markers/validate.py +2 -3
  353. rasa/model.py +3 -5
  354. rasa/model_manager/config.py +1 -1
  355. rasa/model_manager/model_api.py +5 -4
  356. rasa/model_manager/runner_service.py +13 -10
  357. rasa/model_manager/socket_bridge.py +15 -9
  358. rasa/model_manager/studio_jwt_auth.py +1 -0
  359. rasa/model_manager/trainer_service.py +9 -7
  360. rasa/model_manager/utils.py +1 -1
  361. rasa/model_manager/warm_rasa_process.py +14 -9
  362. rasa/model_service.py +5 -6
  363. rasa/model_testing.py +13 -15
  364. rasa/model_training.py +29 -29
  365. rasa/nlu/classifiers/diet_classifier.py +72 -73
  366. rasa/nlu/classifiers/fallback_classifier.py +9 -8
  367. rasa/nlu/classifiers/keyword_intent_classifier.py +7 -6
  368. rasa/nlu/classifiers/logistic_regression_classifier.py +3 -3
  369. rasa/nlu/classifiers/mitie_intent_classifier.py +5 -4
  370. rasa/nlu/classifiers/regex_message_handler.py +3 -2
  371. rasa/nlu/classifiers/sklearn_intent_classifier.py +2 -2
  372. rasa/nlu/convert.py +2 -2
  373. rasa/nlu/emulators/dialogflow.py +3 -3
  374. rasa/nlu/emulators/luis.py +5 -5
  375. rasa/nlu/emulators/no_emulator.py +1 -0
  376. rasa/nlu/emulators/wit.py +4 -4
  377. rasa/nlu/extractors/crf_entity_extractor.py +11 -11
  378. rasa/nlu/extractors/duckling_entity_extractor.py +7 -6
  379. rasa/nlu/extractors/entity_synonyms.py +10 -9
  380. rasa/nlu/extractors/extractor.py +16 -16
  381. rasa/nlu/extractors/mitie_entity_extractor.py +10 -9
  382. rasa/nlu/extractors/regex_entity_extractor.py +11 -10
  383. rasa/nlu/extractors/spacy_entity_extractor.py +2 -2
  384. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +15 -14
  385. rasa/nlu/featurizers/dense_featurizer/dense_featurizer.py +2 -1
  386. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +10 -9
  387. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +9 -7
  388. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +13 -12
  389. rasa/nlu/featurizers/featurizer.py +5 -4
  390. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +6 -6
  391. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -4
  392. rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +4 -4
  393. rasa/nlu/featurizers/sparse_featurizer/sparse_featurizer.py +2 -0
  394. rasa/nlu/model.py +0 -1
  395. rasa/nlu/selectors/response_selector.py +67 -68
  396. rasa/nlu/test.py +38 -38
  397. rasa/nlu/tokenizers/jieba_tokenizer.py +1 -2
  398. rasa/nlu/tokenizers/mitie_tokenizer.py +2 -2
  399. rasa/nlu/tokenizers/spacy_tokenizer.py +3 -3
  400. rasa/nlu/tokenizers/tokenizer.py +6 -7
  401. rasa/nlu/tokenizers/whitespace_tokenizer.py +1 -1
  402. rasa/nlu/utils/bilou_utils.py +7 -7
  403. rasa/nlu/utils/hugging_face/registry.py +22 -22
  404. rasa/nlu/utils/hugging_face/transformers_pre_post_processors.py +2 -1
  405. rasa/nlu/utils/mitie_utils.py +2 -1
  406. rasa/nlu/utils/pattern_utils.py +1 -1
  407. rasa/nlu/utils/spacy_utils.py +3 -3
  408. rasa/plugin.py +12 -1
  409. rasa/server.py +6 -3
  410. rasa/shared/constants.py +45 -18
  411. rasa/shared/core/command_payload_reader.py +15 -7
  412. rasa/shared/core/constants.py +34 -4
  413. rasa/shared/core/conversation.py +1 -2
  414. rasa/shared/core/domain.py +19 -20
  415. rasa/shared/core/events.py +60 -39
  416. rasa/shared/core/flows/__init__.py +0 -1
  417. rasa/shared/core/flows/constants.py +11 -0
  418. rasa/shared/core/flows/flow.py +107 -26
  419. rasa/shared/core/flows/flow_step.py +4 -3
  420. rasa/shared/core/flows/flow_step_links.py +1 -2
  421. rasa/shared/core/flows/flow_step_sequence.py +1 -1
  422. rasa/shared/core/flows/flows_list.py +3 -3
  423. rasa/shared/core/flows/flows_yaml_schema.json +69 -3
  424. rasa/shared/core/flows/nlu_trigger.py +1 -1
  425. rasa/shared/core/flows/steps/__init__.py +2 -2
  426. rasa/shared/core/flows/steps/action.py +1 -1
  427. rasa/shared/core/flows/steps/call.py +1 -1
  428. rasa/shared/core/flows/steps/collect.py +22 -40
  429. rasa/shared/core/flows/steps/internal.py +1 -1
  430. rasa/shared/core/flows/steps/link.py +1 -1
  431. rasa/shared/core/flows/steps/no_operation.py +2 -2
  432. rasa/shared/core/flows/steps/set_slots.py +1 -1
  433. rasa/shared/core/flows/utils.py +44 -4
  434. rasa/shared/core/flows/validation.py +4 -6
  435. rasa/shared/core/generator.py +20 -21
  436. rasa/shared/core/slot_mappings.py +360 -121
  437. rasa/shared/core/slots.py +163 -6
  438. rasa/shared/core/trackers.py +108 -33
  439. rasa/shared/core/training_data/loading.py +1 -1
  440. rasa/shared/core/training_data/story_reader/story_reader.py +3 -3
  441. rasa/shared/core/training_data/story_reader/story_step_builder.py +4 -4
  442. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +29 -31
  443. rasa/shared/core/training_data/story_writer/yaml_story_writer.py +22 -24
  444. rasa/shared/core/training_data/structures.py +11 -12
  445. rasa/shared/core/training_data/visualization.py +10 -10
  446. rasa/shared/data.py +6 -6
  447. rasa/shared/engine/caching.py +0 -1
  448. rasa/shared/exceptions.py +2 -2
  449. rasa/shared/importers/importer.py +58 -2
  450. rasa/shared/importers/rasa.py +5 -6
  451. rasa/shared/importers/utils.py +1 -1
  452. rasa/shared/nlu/constants.py +9 -0
  453. rasa/shared/nlu/training_data/entities_parser.py +6 -6
  454. rasa/shared/nlu/training_data/features.py +3 -3
  455. rasa/shared/nlu/training_data/formats/__init__.py +1 -1
  456. rasa/shared/nlu/training_data/formats/dialogflow.py +4 -5
  457. rasa/shared/nlu/training_data/formats/luis.py +7 -8
  458. rasa/shared/nlu/training_data/formats/rasa.py +4 -5
  459. rasa/shared/nlu/training_data/formats/rasa_yaml.py +17 -16
  460. rasa/shared/nlu/training_data/formats/readerwriter.py +8 -11
  461. rasa/shared/nlu/training_data/formats/wit.py +3 -4
  462. rasa/shared/nlu/training_data/loading.py +4 -4
  463. rasa/shared/nlu/training_data/lookup_tables_parser.py +1 -1
  464. rasa/shared/nlu/training_data/message.py +13 -14
  465. rasa/shared/nlu/training_data/schemas/data_schema.py +1 -1
  466. rasa/shared/nlu/training_data/schemas/responses.yml +19 -11
  467. rasa/shared/nlu/training_data/synonyms_parser.py +3 -3
  468. rasa/shared/nlu/training_data/training_data.py +12 -13
  469. rasa/shared/nlu/training_data/util.py +11 -10
  470. rasa/shared/providers/_configs/azure_entra_id_config.py +541 -0
  471. rasa/shared/providers/_configs/azure_openai_client_config.py +150 -15
  472. rasa/shared/providers/_configs/client_config.py +3 -1
  473. rasa/shared/providers/_configs/default_litellm_client_config.py +9 -7
  474. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +13 -11
  475. rasa/shared/providers/_configs/litellm_router_client_config.py +12 -10
  476. rasa/shared/providers/_configs/model_group_config.py +8 -5
  477. rasa/shared/providers/_configs/oauth_config.py +33 -0
  478. rasa/shared/providers/_configs/openai_client_config.py +14 -12
  479. rasa/shared/providers/_configs/rasa_llm_client_config.py +5 -3
  480. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +12 -11
  481. rasa/shared/providers/_configs/utils.py +1 -0
  482. rasa/shared/providers/_ssl_verification_utils.py +5 -6
  483. rasa/shared/providers/_utils.py +5 -5
  484. rasa/shared/providers/constants.py +6 -0
  485. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +1 -1
  486. rasa/shared/providers/embedding/azure_openai_embedding_client.py +32 -7
  487. rasa/shared/providers/embedding/embedding_client.py +1 -1
  488. rasa/shared/providers/embedding/litellm_router_embedding_client.py +5 -2
  489. rasa/shared/providers/llm/_base_litellm_client.py +43 -18
  490. rasa/shared/providers/llm/azure_openai_llm_client.py +90 -34
  491. rasa/shared/providers/llm/default_litellm_llm_client.py +4 -2
  492. rasa/shared/providers/llm/litellm_router_llm_client.py +32 -9
  493. rasa/shared/providers/llm/llm_client.py +24 -8
  494. rasa/shared/providers/llm/llm_response.py +61 -2
  495. rasa/shared/providers/llm/openai_llm_client.py +11 -5
  496. rasa/shared/providers/llm/rasa_llm_client.py +17 -14
  497. rasa/shared/providers/llm/self_hosted_llm_client.py +35 -15
  498. rasa/shared/providers/mappings.py +18 -19
  499. rasa/shared/providers/router/_base_litellm_router_client.py +48 -15
  500. rasa/shared/providers/router/router_client.py +3 -1
  501. rasa/shared/utils/cli.py +1 -1
  502. rasa/shared/utils/common.py +15 -1
  503. rasa/shared/utils/constants.py +3 -0
  504. rasa/shared/utils/health_check/embeddings_health_check_mixin.py +1 -1
  505. rasa/shared/utils/health_check/health_check.py +3 -3
  506. rasa/shared/utils/health_check/llm_health_check_mixin.py +1 -1
  507. rasa/shared/utils/io.py +1 -1
  508. rasa/shared/utils/llm.py +100 -18
  509. rasa/shared/utils/pykwalify_extensions.py +25 -1
  510. rasa/shared/utils/schemas/domain.yml +26 -1
  511. rasa/shared/utils/schemas/events.py +1 -1
  512. rasa/shared/utils/yaml.py +24 -20
  513. rasa/studio/auth.py +3 -3
  514. rasa/studio/config.py +1 -2
  515. rasa/studio/data_handler.py +3 -3
  516. rasa/studio/download.py +1 -1
  517. rasa/studio/results_logger.py +3 -3
  518. rasa/studio/upload.py +21 -5
  519. rasa/telemetry.py +127 -48
  520. rasa/tracing/config.py +5 -3
  521. rasa/tracing/constants.py +12 -0
  522. rasa/tracing/instrumentation/attribute_extractors.py +92 -14
  523. rasa/tracing/instrumentation/instrumentation.py +61 -5
  524. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +1 -1
  525. rasa/tracing/instrumentation/metrics.py +52 -11
  526. rasa/tracing/metric_instrument_provider.py +54 -14
  527. rasa/utils/common.py +12 -24
  528. rasa/utils/endpoints.py +1 -1
  529. rasa/utils/io.py +7 -7
  530. rasa/utils/licensing.py +3 -4
  531. rasa/utils/log_utils.py +7 -6
  532. rasa/utils/ml_utils.py +1 -0
  533. rasa/utils/plotting.py +3 -3
  534. rasa/utils/sanic_error_handler.py +1 -1
  535. rasa/utils/tensorflow/callback.py +2 -2
  536. rasa/utils/tensorflow/crf.py +2 -2
  537. rasa/utils/tensorflow/data_generator.py +5 -5
  538. rasa/utils/tensorflow/environment.py +3 -3
  539. rasa/utils/tensorflow/feature_array.py +2 -3
  540. rasa/utils/tensorflow/layers.py +18 -12
  541. rasa/utils/tensorflow/layers_utils.py +2 -1
  542. rasa/utils/tensorflow/metrics.py +2 -2
  543. rasa/utils/tensorflow/model_data.py +7 -7
  544. rasa/utils/tensorflow/model_data_utils.py +10 -9
  545. rasa/utils/tensorflow/models.py +31 -32
  546. rasa/utils/tensorflow/rasa_layers.py +20 -19
  547. rasa/utils/tensorflow/types.py +2 -1
  548. rasa/utils/train_utils.py +23 -21
  549. rasa/utils/url_tools.py +1 -1
  550. rasa/validator.py +594 -115
  551. rasa/version.py +1 -1
  552. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/METADATA +23 -26
  553. rasa_pro-3.12.0.dist-info/RECORD +829 -0
  554. rasa/core/channels/inspector/dist/assets/arc-632a63ec.js +0 -1
  555. rasa/core/channels/inspector/dist/assets/c4Diagram-d0fbc5ce-081e0df4.js +0 -10
  556. rasa/core/channels/inspector/dist/assets/classDiagram-936ed81e-3df0afc2.js +0 -2
  557. rasa/core/channels/inspector/dist/assets/classDiagram-v2-c3cb15f1-8c5ed31e.js +0 -2
  558. rasa/core/channels/inspector/dist/assets/edges-f2ad444c-4fc48c3e.js +0 -4
  559. rasa/core/channels/inspector/dist/assets/flowDb-1972c806-9ec53a3c.js +0 -6
  560. rasa/core/channels/inspector/dist/assets/flowDiagram-7ea5b25a-41da787a.js +0 -4
  561. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-8bea338b.js +0 -1
  562. rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-abe16c3d-ce370633.js +0 -139
  563. rasa/core/channels/inspector/dist/assets/ganttDiagram-9b5ea136-90a36523.js +0 -266
  564. rasa/core/channels/inspector/dist/assets/gitGraphDiagram-99d0ae7c-41e1aa3f.js +0 -70
  565. rasa/core/channels/inspector/dist/assets/index-2c4b9a3b-e6f2af62.js +0 -1
  566. rasa/core/channels/inspector/dist/assets/layout-498807d8.js +0 -1
  567. rasa/core/channels/inspector/dist/assets/linear-8a078617.js +0 -1
  568. rasa/core/channels/inspector/dist/assets/mindmap-definition-beec6740-396d17dd.js +0 -109
  569. rasa/core/channels/inspector/dist/assets/sankeyDiagram-8f13d901-53f6f391.js +0 -8
  570. rasa/core/channels/inspector/dist/assets/sequenceDiagram-b655622a-715c9c20.js +0 -122
  571. rasa/core/channels/inspector/dist/assets/stateDiagram-59f0c015-2e8fb31f.js +0 -1
  572. rasa/core/channels/inspector/dist/assets/stateDiagram-v2-2b26beab-7e2d2aa0.js +0 -1
  573. rasa/core/channels/inspector/dist/assets/styles-080da4f6-4420cea6.js +0 -110
  574. rasa/core/channels/inspector/dist/assets/styles-3dcbcfbf-28676cf4.js +0 -159
  575. rasa/core/channels/inspector/dist/assets/svgDrawCommon-4835440b-151251e9.js +0 -1
  576. rasa_pro-3.11.4.dist-info/RECORD +0 -779
  577. /rasa/dialogue_understanding/generator/{single_step → prompt_templates}/command_prompt_template.jinja2 +0 -0
  578. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/NOTICE +0 -0
  579. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/WHEEL +0 -0
  580. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/entry_points.txt +0 -0
rasa/validator.py CHANGED
@@ -3,70 +3,84 @@ import re
3
3
  import string
4
4
  import sys
5
5
  from collections import defaultdict
6
- from typing import Set, Text, Optional, Dict, Any, List, Tuple
6
+ from typing import Any, Dict, List, Optional, Set, Text, Tuple
7
7
 
8
8
  import structlog
9
9
  from jinja2 import Template
10
10
  from pypred import Predicate
11
- from pypred.ast import Literal, CompareOperator, NegateOperator
11
+ from pypred.ast import CompareOperator, Literal, NegateOperator
12
12
 
13
13
  import rasa.core.training.story_conflict
14
+ import rasa.shared.nlu.constants
15
+ import rasa.shared.utils.cli
16
+ import rasa.shared.utils.io
14
17
  from rasa.core.channels import UserMessage
15
18
  from rasa.dialogue_understanding.stack.frames import PatternFlowStackFrame
16
- from rasa.shared.core.command_payload_reader import (
17
- CommandPayloadReader,
18
- MAX_NUMBER_OF_SLOTS,
19
- )
20
- from rasa.shared.core.flows.flow_step_links import IfFlowStepLink
21
- from rasa.shared.core.flows.steps.set_slots import SetSlotsFlowStep
22
- from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
23
- from rasa.shared.core.flows.steps.action import ActionFlowStep
24
- from rasa.shared.core.flows.steps.link import LinkFlowStep
25
- from rasa.shared.core.flows import FlowsList
26
- from rasa.shared.core.flows.utils import (
27
- warn_deprecated_collect_step_config,
28
- get_duplicate_slot_persistence_config_error_message,
29
- get_invalid_slot_persistence_config_error_message,
30
- )
31
- import rasa.shared.nlu.constants
19
+ from rasa.engine.language import Language
32
20
  from rasa.shared.constants import (
33
21
  ASSISTANT_ID_DEFAULT_VALUE,
34
22
  ASSISTANT_ID_KEY,
23
+ CONFIG_ADDITIONAL_LANGUAGES_KEY,
24
+ CONFIG_LANGUAGE_KEY,
35
25
  CONFIG_MANDATORY_KEYS,
26
+ CONFIG_PIPELINE_KEY,
27
+ DOCS_URL_ACTIONS,
36
28
  DOCS_URL_DOMAIN,
37
29
  DOCS_URL_DOMAINS,
38
30
  DOCS_URL_FORMS,
39
31
  DOCS_URL_RESPONSES,
40
- UTTER_PREFIX,
41
- DOCS_URL_ACTIONS,
42
32
  REQUIRED_SLOTS_KEY,
33
+ RESPONSE_CONDITION,
34
+ UTTER_PREFIX,
43
35
  )
44
36
  from rasa.shared.core import constants
45
- from rasa.shared.core.constants import MAPPING_CONDITIONS, ACTIVE_LOOP
46
- from rasa.shared.core.events import ActionExecuted, ActiveLoop
47
- from rasa.shared.core.events import UserUttered
37
+ from rasa.shared.core.command_payload_reader import (
38
+ MAX_NUMBER_OF_SLOTS,
39
+ CommandPayloadReader,
40
+ )
41
+ from rasa.shared.core.constants import (
42
+ KEY_ALLOW_NLU_CORRECTION,
43
+ SLOTS,
44
+ SlotMappingType,
45
+ )
48
46
  from rasa.shared.core.domain import (
49
- Domain,
50
47
  RESPONSE_KEYS_TO_INTERPOLATE,
48
+ Domain,
49
+ )
50
+ from rasa.shared.core.events import ActionExecuted, ActiveLoop, UserUttered
51
+ from rasa.shared.core.flows import Flow, FlowsList
52
+ from rasa.shared.core.flows.constants import KEY_NAME, KEY_TRANSLATION
53
+ from rasa.shared.core.flows.flow_step_links import IfFlowStepLink
54
+ from rasa.shared.core.flows.steps.action import ActionFlowStep
55
+ from rasa.shared.core.flows.steps.collect import CollectInformationFlowStep
56
+ from rasa.shared.core.flows.steps.link import LinkFlowStep
57
+ from rasa.shared.core.flows.steps.set_slots import SetSlotsFlowStep
58
+ from rasa.shared.core.flows.utils import (
59
+ ALL_LABEL,
60
+ get_duplicate_slot_persistence_config_error_message,
61
+ get_invalid_slot_persistence_config_error_message,
62
+ warn_deprecated_collect_step_config,
51
63
  )
52
64
  from rasa.shared.core.generator import TrainingDataGenerator
53
- from rasa.shared.core.constants import SlotMappingType, MAPPING_TYPE
65
+ from rasa.shared.core.slot_mappings import CoexistenceSystemType
54
66
  from rasa.shared.core.slots import BooleanSlot, CategoricalSlot, ListSlot, Slot
55
67
  from rasa.shared.core.training_data.story_reader.yaml_story_reader import (
56
68
  YAMLStoryReader,
57
69
  )
58
70
  from rasa.shared.core.training_data.structures import StoryGraph
59
71
  from rasa.shared.data import create_regex_pattern_reader
72
+ from rasa.shared.exceptions import RasaException
60
73
  from rasa.shared.importers.importer import TrainingDataImporter
61
74
  from rasa.shared.nlu.constants import COMMANDS
62
75
  from rasa.shared.nlu.training_data.message import Message
63
76
  from rasa.shared.nlu.training_data.training_data import TrainingData
64
-
65
- import rasa.shared.utils.cli
66
- import rasa.shared.utils.io
77
+ from rasa.telemetry import track_validation_error_log
67
78
 
68
79
  logger = logging.getLogger(__name__)
69
- structlogger = structlog.get_logger()
80
+
81
+ structlog_processors = structlog.get_config()["processors"]
82
+ updated_processors = [track_validation_error_log] + structlog_processors
83
+ structlogger = structlog.get_logger(processors=updated_processors)
70
84
 
71
85
 
72
86
  class Validator:
@@ -511,9 +525,9 @@ class Validator:
511
525
 
512
526
  for slot in self.domain.slots:
513
527
  for mapping in slot.mappings:
514
- for condition in mapping.get(MAPPING_CONDITIONS, []):
515
- condition_active_loop = condition.get(ACTIVE_LOOP)
516
- mapping_type = SlotMappingType(mapping.get(MAPPING_TYPE))
528
+ for condition in mapping.conditions:
529
+ condition_active_loop = condition.active_loop
530
+ mapping_type = mapping.type
517
531
  if (
518
532
  condition_active_loop
519
533
  and condition_active_loop not in self.domain.form_names
@@ -901,6 +915,16 @@ class Validator:
901
915
  f"'{object_id}': {exception}"
902
916
  ),
903
917
  )
918
+ elif object_id.startswith("utter_"):
919
+ structlogger.error(
920
+ "validator.validate_conditional_response_variation_predicates.error",
921
+ utter=object_id,
922
+ exception=exception,
923
+ event_info=(
924
+ f"Could not initialize the predicate found under response "
925
+ f"variation '{object_id}': {exception}"
926
+ ),
927
+ )
904
928
  else:
905
929
  structlogger.error(
906
930
  "validator.verify_predicates.flow_guard_predicate.error",
@@ -932,7 +956,7 @@ class Validator:
932
956
  def _extract_slot_name_and_slot_value(
933
957
  self,
934
958
  predicate_syntax_tree: Any,
935
- ) -> tuple:
959
+ ) -> Tuple[Optional[List[str]], Optional[Any]]:
936
960
  """Extract the slot name and slot value from the predicate syntax tree.
937
961
 
938
962
  Args:
@@ -1037,15 +1061,15 @@ class Validator:
1037
1061
  False, if validation failed, previous value of all_good, otherwise
1038
1062
  """
1039
1063
  predicate_syntax_tree = self._extract_predicate_syntax_tree(predicate)
1040
- slot_name, slot_value = self._extract_slot_name_and_slot_value(
1064
+ slot_namespace, slot_value = self._extract_slot_name_and_slot_value(
1041
1065
  predicate_syntax_tree
1042
1066
  )
1043
1067
 
1044
- if slot_name is None:
1068
+ if slot_namespace is None:
1045
1069
  return all_good
1046
1070
 
1047
- if slot_name[0] == "slots":
1048
- slot_name = slot_name[1]
1071
+ if slot_namespace[0] == "slots":
1072
+ slot_name = slot_namespace[1]
1049
1073
  # slots.{{context.variable}} gets evaluated to `slots.None`,
1050
1074
  # these predicates can only be validated during runtime
1051
1075
  if slot_name == "None":
@@ -1257,6 +1281,7 @@ class Validator:
1257
1281
  self.verify_unique_flows(),
1258
1282
  self.verify_predicates(),
1259
1283
  self.verify_slot_persistence_configuration(),
1284
+ self.verify_digression_configuration(),
1260
1285
  ]
1261
1286
 
1262
1287
  all_good = all(flow_validation_conditions)
@@ -1265,6 +1290,165 @@ class Validator:
1265
1290
 
1266
1291
  return all_good
1267
1292
 
1293
+ def _get_response_translation_warnings(self) -> list:
1294
+ """Collect warnings for responses missing translations.
1295
+
1296
+ Returns:
1297
+ List of warnings for responses missing translations.
1298
+ """
1299
+ additional_languages = self.config.get(CONFIG_ADDITIONAL_LANGUAGES_KEY) or []
1300
+ response_warnings = []
1301
+
1302
+ for response_name, responses in self.domain.responses.items():
1303
+ provided_languages = set()
1304
+ # For each response variation, we check if the additional
1305
+ # languages are available in at least on variation
1306
+ for response in responses:
1307
+ translation = response.get(KEY_TRANSLATION) or {}
1308
+ for language_code in additional_languages:
1309
+ if translation.get(language_code):
1310
+ provided_languages.add(language_code)
1311
+
1312
+ missing_languages = [
1313
+ lang for lang in additional_languages if lang not in provided_languages
1314
+ ]
1315
+ if missing_languages:
1316
+ language_code_str = ", ".join(missing_languages)
1317
+ response_warnings.append(
1318
+ {
1319
+ "event": (
1320
+ "validator.verify_translations.missing_response_translation"
1321
+ ),
1322
+ "response": response_name,
1323
+ "missing_languages": missing_languages,
1324
+ "event_info": (
1325
+ f"The response '{response_name}' is "
1326
+ f"missing a translation for the following "
1327
+ f"languages: {language_code_str}."
1328
+ ),
1329
+ }
1330
+ )
1331
+ return response_warnings
1332
+
1333
+ def _get_flow_translation_warnings(self) -> list:
1334
+ """Collect warnings for flows missing translations.
1335
+
1336
+ Returns:
1337
+ List of warnings for flows missing translations.
1338
+ """
1339
+ additional_languages = self.config.get(CONFIG_ADDITIONAL_LANGUAGES_KEY) or []
1340
+
1341
+ flow_warnings = []
1342
+ for flow in self.flows.underlying_flows:
1343
+ required_field_translation = [KEY_NAME]
1344
+ missing_languages = []
1345
+ for language_code in additional_languages:
1346
+ translation = flow.translation.get(language_code)
1347
+ # If translation for the language code doesn't exist,
1348
+ # or the required fields are not set properly,
1349
+ # we add the language code to the list.
1350
+ if not translation or not all(
1351
+ getattr(translation, field, None)
1352
+ for field in required_field_translation
1353
+ ):
1354
+ missing_languages.append(language_code)
1355
+
1356
+ if missing_languages:
1357
+ language_code_str = ", ".join(missing_languages)
1358
+ flow_warnings.append(
1359
+ {
1360
+ "event": (
1361
+ "validator.verify_translations.missing_flow_translation"
1362
+ ),
1363
+ "flow": flow.id,
1364
+ "missing_languages": missing_languages,
1365
+ "event_info": (
1366
+ f"The flow '{flow.id}' is missing the translation for "
1367
+ f"the following languages: {language_code_str}."
1368
+ ),
1369
+ }
1370
+ )
1371
+ return flow_warnings
1372
+
1373
+ def verify_config_language(self) -> bool:
1374
+ """Verify that config languages are properly set up.
1375
+
1376
+ Returns:
1377
+ `True` if all languages are properly set up, `False` otherwise.
1378
+
1379
+ Raises:
1380
+ RasaException: If the default language is listed as an
1381
+ additional language or if the language code is invalid.
1382
+ """
1383
+ language = self.config.get(CONFIG_LANGUAGE_KEY)
1384
+ additional_languages = self.config.get(CONFIG_ADDITIONAL_LANGUAGES_KEY, [])
1385
+
1386
+ # Check if the default language is in the additional languages.
1387
+ if language in additional_languages:
1388
+ raise RasaException(
1389
+ f"The default language '{language}' is listed as an additional "
1390
+ f"language in the configuration file. Please remove it from "
1391
+ f"the list of additional languages."
1392
+ )
1393
+
1394
+ # Verify the language codes by initializing the Language class.
1395
+ for language_code in [language] + additional_languages:
1396
+ Language.from_language_code(language_code=language_code)
1397
+
1398
+ return True
1399
+
1400
+ def verify_translations(self, summary_mode: bool = False) -> bool:
1401
+ """Checks for inconsistencies in translations.
1402
+
1403
+ Args:
1404
+ summary_mode: If True, logs a single aggregated warning per category;
1405
+ otherwise, logs each warning individually.
1406
+
1407
+ Returns:
1408
+ `True` if no inconsistencies were found, `False` otherwise.
1409
+
1410
+ Raises:
1411
+ Warning: Single warning per response or flow missing translations
1412
+ if `summary_mode` is `True`, otherwise one warning per missing translation.
1413
+ """
1414
+ all_good = self.verify_config_language()
1415
+
1416
+ additional_languages = self.config.get(CONFIG_ADDITIONAL_LANGUAGES_KEY, [])
1417
+ if not additional_languages:
1418
+ return all_good
1419
+
1420
+ response_warnings = self._get_response_translation_warnings()
1421
+ flow_warnings = self._get_flow_translation_warnings()
1422
+
1423
+ if summary_mode:
1424
+ if response_warnings:
1425
+ count = len(response_warnings)
1426
+ structlogger.warn(
1427
+ "validator.verify_translations.missing_response_translation_summary",
1428
+ count=count,
1429
+ event_info=(
1430
+ f"{count} response{' is' if count == 1 else 's are'} "
1431
+ f"missing translations for some languages. "
1432
+ "Run 'rasa data validate translations' for details."
1433
+ ),
1434
+ )
1435
+ if flow_warnings:
1436
+ count = len(flow_warnings)
1437
+ structlogger.warn(
1438
+ "validator.verify_translations.missing_flow_translation_summary",
1439
+ count=count,
1440
+ event_info=(
1441
+ f"{count} flow{' is' if count == 1 else 's are'} "
1442
+ f"missing translations for some languages. "
1443
+ "Run 'rasa data validate translations' for details."
1444
+ ),
1445
+ )
1446
+ else:
1447
+ for warning in response_warnings + flow_warnings:
1448
+ structlogger.warn(**warning)
1449
+
1450
+ return all_good
1451
+
1268
1452
  def validate_button_payloads(self) -> bool:
1269
1453
  """Check if the response button payloads are valid."""
1270
1454
  all_good = True
@@ -1385,36 +1569,26 @@ class Validator:
1385
1569
 
1386
1570
  for slot in self.domain._user_slots:
1387
1571
  nlu_mappings = any(
1388
- [
1389
- SlotMappingType(
1390
- mapping.get("type", SlotMappingType.FROM_LLM.value)
1391
- ).is_predefined_type()
1392
- for mapping in slot.mappings
1393
- ]
1572
+ [mapping.type.is_predefined_type() for mapping in slot.mappings]
1394
1573
  )
1395
1574
  llm_mappings = any(
1396
- [
1397
- SlotMappingType(mapping.get("type", SlotMappingType.FROM_LLM.value))
1398
- == SlotMappingType.FROM_LLM
1399
- for mapping in slot.mappings
1400
- ]
1575
+ [mapping.type == SlotMappingType.FROM_LLM for mapping in slot.mappings]
1401
1576
  )
1402
- custom_mappings = any(
1577
+ controlled_mappings = any(
1403
1578
  [
1404
- SlotMappingType(mapping.get("type", SlotMappingType.FROM_LLM.value))
1405
- == SlotMappingType.CUSTOM
1579
+ mapping.type == SlotMappingType.CONTROLLED
1406
1580
  for mapping in slot.mappings
1407
1581
  ]
1408
1582
  )
1409
1583
 
1410
- all_good = self._slot_contains_all_mappings_types(
1411
- llm_mappings, nlu_mappings, custom_mappings, slot.name, all_good
1412
- )
1584
+ all_good = self._allow_nlu_correction_is_valid(slot, nlu_mappings, all_good)
1413
1585
 
1414
1586
  all_good = self._custom_action_name_is_defined_in_the_domain(
1415
- custom_mappings, slot, all_good
1587
+ controlled_mappings, slot, all_good
1416
1588
  )
1417
1589
 
1590
+ all_good = self._validate_controlled_mappings(slot, all_good)
1591
+
1418
1592
  all_good = self._config_contains_nlu_command_adapter(
1419
1593
  nlu_mappings, slot.name, all_good
1420
1594
  )
@@ -1426,23 +1600,45 @@ class Validator:
1426
1600
  return all_good
1427
1601
 
1428
1602
  @staticmethod
1429
- def _slot_contains_all_mappings_types(
1430
- llm_mappings: bool,
1431
- nlu_mappings: bool,
1432
- custom_mappings: bool,
1433
- slot_name: str,
1434
- all_good: bool,
1603
+ def _allow_nlu_correction_is_valid(
1604
+ slot: Slot, nlu_mappings: bool, all_good: bool
1435
1605
  ) -> bool:
1436
- if llm_mappings and (nlu_mappings or custom_mappings):
1606
+ """Verify that `allow_nlu_correction` property is used correctly in a `from_llm` mappings only.""" # noqa: E501
1607
+ if not slot.mappings:
1608
+ return all_good
1609
+
1610
+ invalid_usage = False
1611
+
1612
+ for mapping in slot.mappings:
1613
+ allow_nlu_correction = mapping.allow_nlu_correction
1614
+ if allow_nlu_correction and mapping.type != SlotMappingType.FROM_LLM:
1615
+ invalid_usage = True
1616
+
1617
+ if allow_nlu_correction and not nlu_mappings:
1618
+ structlogger.error(
1619
+ "validator.validate_slot_mappings_in_CALM.nlu_mappings_not_present",
1620
+ slot_name=slot.name,
1621
+ event_info=(
1622
+ f"The slot '{slot.name}' does not have any "
1623
+ f"NLU-based slot mappings. "
1624
+ f"The property `allow_nlu_correction` is only "
1625
+ f"applicable when the slot "
1626
+ f"contains both NLU-based and LLM-based slot mappings."
1627
+ ),
1628
+ )
1629
+ all_good = False
1630
+
1631
+ if invalid_usage:
1437
1632
  structlogger.error(
1438
- "validator.validate_slot_mappings_in_CALM.llm_and_nlu_mappings",
1439
- slot_name=slot_name,
1633
+ "validator.validate_slot_mappings_in_CALM.allow_nlu_correction",
1634
+ slot_name=slot.name,
1440
1635
  event_info=(
1441
- f"The slot '{slot_name}' has both LLM and "
1442
- f"NLU or custom slot mappings. "
1443
- f"Please make sure that the slot has only one type of mapping."
1636
+ f"The slot '{slot.name}' has at least 1 slot mapping with "
1637
+ f"'{KEY_ALLOW_NLU_CORRECTION}' set to 'true', but "
1638
+ f"the slot mapping type is not 'from_llm'. "
1639
+ f"Please set the slot mapping type to 'from_llm' "
1640
+ f"to allow the LLM to correct this slot."
1444
1641
  ),
1445
- docs_link=DOCS_URL_DOMAIN + "#calm-slot-mappings",
1446
1642
  )
1447
1643
  all_good = False
1448
1644
 
@@ -1450,55 +1646,32 @@ class Validator:
1450
1646
 
1451
1647
  def _custom_action_name_is_defined_in_the_domain(
1452
1648
  self,
1453
- custom_mappings: bool,
1649
+ controlled_mappings: bool,
1454
1650
  slot: Slot,
1455
1651
  all_good: bool,
1456
1652
  ) -> bool:
1457
- if not custom_mappings:
1653
+ if not controlled_mappings:
1458
1654
  return all_good
1459
1655
 
1460
- if not self.flows:
1461
- return all_good
1462
-
1463
- is_custom_action_defined = any(
1464
- [
1465
- mapping.get("action") is not None
1466
- and mapping.get("action") in self.domain.action_names_or_texts
1467
- for mapping in slot.mappings
1468
- ]
1469
- )
1470
-
1471
- if is_custom_action_defined:
1472
- return all_good
1473
-
1474
- slot_collected_by_flows = any(
1475
- [
1476
- step.collect == slot.name
1477
- for flow in self.flows.underlying_flows
1478
- for step in flow.steps
1479
- if isinstance(step, CollectInformationFlowStep)
1480
- ]
1481
- )
1482
-
1483
- if not slot_collected_by_flows:
1484
- # if the slot is not collected by any flow,
1485
- # it could be a DM1 custom slot
1486
- return all_good
1487
-
1488
- custom_action_ask_name = f"action_ask_{slot.name}"
1489
- if custom_action_ask_name not in self.domain.action_names_or_texts:
1490
- structlogger.error(
1491
- "validator.validate_slot_mappings_in_CALM.custom_action_not_in_domain",
1492
- slot_name=slot.name,
1493
- event_info=(
1494
- f"The slot '{slot.name}' has a custom slot mapping, but "
1495
- f"neither the action '{custom_action_ask_name}' nor "
1496
- f"another custom action are defined in the domain file. "
1497
- f"Please add one of the actions to your domain file."
1498
- ),
1499
- docs_link=DOCS_URL_DOMAIN + "#custom-slot-mappings",
1500
- )
1501
- all_good = False
1656
+ for mapping in slot.mappings:
1657
+ if (
1658
+ mapping.run_action_every_turn is not None
1659
+ and mapping.run_action_every_turn
1660
+ not in self.domain.action_names_or_texts
1661
+ ):
1662
+ structlogger.error(
1663
+ "validator.validate_slot_mappings_in_CALM.custom_action_not_in_domain",
1664
+ slot_name=slot.name,
1665
+ action_name=mapping.run_action_every_turn,
1666
+ event_info=(
1667
+ f"The slot '{slot.name}' has a custom action "
1668
+ f"'{mapping.run_action_every_turn}' "
1669
+ f"defined in its slot mappings, "
1670
+ f"but the action is not listed in the domain actions. "
1671
+ f"Please add the action to your domain file."
1672
+ ),
1673
+ )
1674
+ all_good = False
1502
1675
 
1503
1676
  return all_good
1504
1677
 
@@ -1514,7 +1687,7 @@ class Validator:
1514
1687
  contains_nlu_command_adapter = any(
1515
1688
  [
1516
1689
  component.get("name") == "NLUCommandAdapter"
1517
- for component in self.config.get("pipeline", [])
1690
+ for component in self.config.get(CONFIG_PIPELINE_KEY, [])
1518
1691
  ]
1519
1692
  )
1520
1693
 
@@ -1583,7 +1756,7 @@ class Validator:
1583
1756
  collect_step = step.collect
1584
1757
  flow_slots.add(collect_step)
1585
1758
  if not step.reset_after_flow_ends:
1586
- warn_deprecated_collect_step_config(flow_id, collect_step)
1759
+ warn_deprecated_collect_step_config()
1587
1760
 
1588
1761
  if has_flow_level_persistence:
1589
1762
  structlogger.error(
@@ -1644,10 +1817,316 @@ class Validator:
1644
1817
  self.verify_predicates(),
1645
1818
  ]
1646
1819
  )
1820
+ valid_translations = self.verify_translations(summary_mode=True)
1647
1821
  valid_calm_slot_mappings = self.validate_CALM_slot_mappings()
1648
1822
 
1649
1823
  all_good = (
1650
- valid_responses and valid_nlu and valid_flows and valid_calm_slot_mappings
1824
+ valid_responses
1825
+ and valid_nlu
1826
+ and valid_flows
1827
+ and valid_translations
1828
+ and valid_calm_slot_mappings
1651
1829
  )
1652
1830
 
1653
1831
  return all_good
1832
+
1833
+ def verify_digression_configuration(self) -> bool:
1834
+ """Validates the digression configuration in flows."""
1835
+ all_good = True
1836
+
1837
+ for flow in self.flows.underlying_flows:
1838
+ all_good = self._validate_ask_confirm_digressions(flow, all_good)
1839
+ all_good = self._validate_block_digressions(flow, all_good)
1840
+
1841
+ return all_good
1842
+
1843
+ def _validate_ask_confirm_digressions(self, flow: Flow, all_good: bool) -> bool:
1844
+ """Validates the ask_confirm_digressions configuration in a flow."""
1845
+ for flow_id in flow.ask_confirm_digressions:
1846
+ if flow_id == ALL_LABEL:
1847
+ continue
1848
+ if flow_id not in self.flows.flow_ids:
1849
+ structlogger.error(
1850
+ "validator.verify_digression_configuration.ask_confirm_digressions",
1851
+ flow=flow.id,
1852
+ event_info=(
1853
+ f"The flow '{flow_id}' is listed in the "
1854
+ f"`ask_confirm_digressions` configuration of flow "
1855
+ f"'{flow.id}', but it is not found in the "
1856
+ f"flows file. Please make sure that the flow id is correct."
1857
+ ),
1858
+ )
1859
+ all_good = False
1860
+
1861
+ if flow_id in flow.block_digressions:
1862
+ structlogger.error(
1863
+ "validator.verify_digression_configuration.overlap_digressions",
1864
+ flow=flow.id,
1865
+ event_info=(
1866
+ f"The flow '{flow_id}' is listed in both the "
1867
+ f"`ask_confirm_digressions` and `block_digressions` "
1868
+ f"configuration of flow '{flow.id}'. "
1869
+ f"Please make sure that the flow id is not listed in both "
1870
+ f"configurations."
1871
+ ),
1872
+ )
1873
+ all_good = False
1874
+
1875
+ for step in flow.get_collect_steps():
1876
+ for flow_id in step.ask_confirm_digressions:
1877
+ if flow_id == ALL_LABEL:
1878
+ continue
1879
+
1880
+ if flow_id not in self.flows.flow_ids:
1881
+ structlogger.error(
1882
+ "validator.verify_digression_configuration.ask_confirm_digressions",
1883
+ flow=flow.id,
1884
+ step_id=step.id,
1885
+ event_info=(
1886
+ f"The flow '{flow_id}' is listed in the "
1887
+ f"`ask_confirm_digressions` configuration of step "
1888
+ f"'{step.id}' in flow '{flow.id}', but it is "
1889
+ f"not found in the flows file. "
1890
+ f"Please make sure that the flow id is correct."
1891
+ ),
1892
+ )
1893
+ all_good = False
1894
+
1895
+ if flow_id in step.block_digressions:
1896
+ structlogger.error(
1897
+ "validator.verify_digression_configuration.overlap_digressions",
1898
+ flow=flow.id,
1899
+ step_id=step.id,
1900
+ event_info=(
1901
+ f"The flow '{flow_id}' is listed in both the "
1902
+ f"`ask_confirm_digressions` and `block_digressions` "
1903
+ f"configuration of step '{step.id}' in flow '{flow.id}'. "
1904
+ f"Please make sure that the flow id is not listed in both "
1905
+ f"configurations."
1906
+ ),
1907
+ )
1908
+ all_good = False
1909
+
1910
+ return all_good
1911
+
1912
+ def _validate_block_digressions(self, flow: Flow, all_good: bool) -> bool:
1913
+ """Validates the block_digressions configuration in a flow."""
1914
+ for flow_id in flow.block_digressions:
1915
+ if flow_id == ALL_LABEL:
1916
+ continue
1917
+
1918
+ if flow_id not in self.flows.flow_ids:
1919
+ structlogger.error(
1920
+ "validator.verify_digression_configuration.block_digressions",
1921
+ flow=flow.id,
1922
+ event_info=(
1923
+ f"The flow '{flow_id}' is listed in the `block_digressions` "
1924
+ f"configuration of flow '{flow.id}', but it is not found "
1925
+ f"in the flows file. Please make sure that the flow id "
1926
+ f"is correct."
1927
+ ),
1928
+ )
1929
+ all_good = False
1930
+
1931
+ for step in flow.get_collect_steps():
1932
+ for flow_id in step.block_digressions:
1933
+ if flow_id == ALL_LABEL:
1934
+ continue
1935
+
1936
+ if flow_id not in self.flows.flow_ids:
1937
+ structlogger.error(
1938
+ "validator.verify_digression_configuration.block_digressions",
1939
+ flow=flow.id,
1940
+ step_id=step.id,
1941
+ event_info=(
1942
+ f"The flow '{flow_id}' is listed in the "
1943
+ f"`block_digressions` configuration of step "
1944
+ f"'{step.id}' in flow '{flow.id}', but it is "
1945
+ f"not found in the flows file. "
1946
+ f"Please make sure that the flow id is correct."
1947
+ ),
1948
+ )
1949
+ all_good = False
1950
+
1951
+ return all_good
1952
+
1953
+ def verify_slot_validation(self) -> bool:
1954
+ """Validates the slot validation configuration in the domain file."""
1955
+ all_good = True
1956
+
1957
+ for slot in self.domain._user_slots:
1958
+ if slot.requires_validation():
1959
+ refill_utter = slot.validation.refill_utter # type: ignore[union-attr]
1960
+ if refill_utter and refill_utter not in self.domain.responses:
1961
+ self._log_slot_validation_error(
1962
+ slot.name, "refill utterance", refill_utter
1963
+ )
1964
+ all_good = False
1965
+ rejections = slot.validation.rejections # type: ignore[union-attr]
1966
+ for rejection in rejections:
1967
+ if rejection.utter not in self.domain.responses:
1968
+ self._log_slot_validation_error(
1969
+ slot.name, "rejection utterance", rejection.utter
1970
+ )
1971
+ all_good = False
1972
+
1973
+ return all_good
1974
+
1975
+ def _log_slot_validation_error(self, slot_name: str, key: str, value: str) -> None:
1976
+ structlogger.error(
1977
+ "validator.verify_slot_validation.response_not_in_domain",
1978
+ slot=slot_name,
1979
+ event_info=(
1980
+ f"The slot '{slot_name}' requires validation, "
1981
+ f"but the {key} '{value}' "
1982
+ f"is not listed in the domain responses. "
1983
+ f"Please add it to your domain file."
1984
+ ),
1985
+ )
1986
+
1987
+ @staticmethod
1988
+ def _validate_controlled_mappings(slot: Slot, all_good: bool) -> bool:
1989
+ for mapping in slot.mappings:
1990
+ if (
1991
+ mapping.run_action_every_turn is not None
1992
+ and mapping.type != SlotMappingType.CONTROLLED
1993
+ ):
1994
+ structlogger.error(
1995
+ "validator.validate_slot_mappings_in_CALM.run_action_every_turn_invalid",
1996
+ slot_name=slot.name,
1997
+ event_info=(
1998
+ f"The slot '{slot.name}' has a custom action "
1999
+ f"'{mapping.run_action_every_turn}' "
2000
+ f"defined in its slot mapping, "
2001
+ f"but the slot mapping type is not 'controlled'. "
2002
+ ),
2003
+ )
2004
+ all_good = False
2005
+
2006
+ if (
2007
+ mapping.coexistence_system is not None
2008
+ and mapping.type != SlotMappingType.CONTROLLED
2009
+ ):
2010
+ structlogger.error(
2011
+ "validator.validate_slot_mappings_in_CALM.coexistence_system_invalid",
2012
+ slot_name=slot.name,
2013
+ event_info=(
2014
+ f"The slot '{slot.name}' has a coexistence system "
2015
+ f"'{mapping.coexistence_system.value}' "
2016
+ f"defined in its slot mapping, "
2017
+ f"but the slot mapping type is not 'controlled'. "
2018
+ ),
2019
+ )
2020
+ all_good = False
2021
+
2022
+ if (
2023
+ mapping.coexistence_system is not None
2024
+ and mapping.coexistence_system != CoexistenceSystemType.SHARED
2025
+ and slot.shared_for_coexistence
2026
+ ):
2027
+ structlogger.error(
2028
+ "validator.validate_slot_mappings_in_CALM.shared_for_coexistence_invalid",
2029
+ slot_name=slot.name,
2030
+ event_info=(
2031
+ f"The slot '{slot.name}' has the `shared_for_coexistence` "
2032
+ f"property set to `True`, but the slot mapping `controlled` "
2033
+ f"type defines the `coexistence_system` property with a "
2034
+ f"value different to the expected `SHARED` value. "
2035
+ ),
2036
+ )
2037
+ all_good = False
2038
+
2039
+ multiple_controlled_mappings = {
2040
+ mapping.coexistence_system.value
2041
+ for mapping in slot.mappings
2042
+ if mapping.type == SlotMappingType.CONTROLLED
2043
+ and mapping.coexistence_system is not None
2044
+ }
2045
+ contains_inconsistent_coexistence_system = len(multiple_controlled_mappings) > 1
2046
+
2047
+ if contains_inconsistent_coexistence_system:
2048
+ structlogger.error(
2049
+ "validator.validate_slot_mappings_in_CALM.inconsistent_multiple_mappings",
2050
+ slot_name=slot.name,
2051
+ event_info=(
2052
+ f"The slot '{slot.name}' has multiple `controlled` mappings "
2053
+ f"with different coexistence systems defined: "
2054
+ f"'{sorted(list(multiple_controlled_mappings))}'. "
2055
+ f"Please only define one coexistence system for the slot. "
2056
+ ),
2057
+ )
2058
+ all_good = False
2059
+
2060
+ return all_good
2061
+
2062
+ def validate_conditional_response_variation_predicates(self) -> bool:
2063
+ """Validate the conditional response variation predicates."""
2064
+ context = {SLOTS: {slot.name: None for slot in self.domain.slots}}
2065
+ all_good = True
2066
+
2067
+ for utter_name, variations in self.domain.responses.items():
2068
+ for variation in variations:
2069
+ condition = variation.get(RESPONSE_CONDITION)
2070
+ if not isinstance(condition, str):
2071
+ continue
2072
+
2073
+ predicate, all_good = self._construct_predicate(
2074
+ condition,
2075
+ utter_name,
2076
+ context,
2077
+ is_step=False,
2078
+ all_good=all_good,
2079
+ )
2080
+ if not predicate:
2081
+ continue
2082
+
2083
+ if not predicate.is_valid():
2084
+ structlogger.error(
2085
+ "validator.validate_conditional_response_variation_predicates.invalid_condition",
2086
+ utter=utter_name,
2087
+ event_info=(
2088
+ f"Detected invalid condition '{condition}' "
2089
+ f"for response variation '{utter_name}'. "
2090
+ f"Please make sure that all conditions are valid."
2091
+ ),
2092
+ )
2093
+ all_good = False
2094
+ continue
2095
+
2096
+ predicate_syntax_tree = self._extract_predicate_syntax_tree(predicate)
2097
+ slot_namespace, _ = self._extract_slot_name_and_slot_value(
2098
+ predicate_syntax_tree
2099
+ )
2100
+
2101
+ if slot_namespace is not None and slot_namespace[0] != SLOTS:
2102
+ structlogger.error(
2103
+ "validator.validate_conditional_response_variation_predicates.invalid_namespace",
2104
+ utter=utter_name,
2105
+ event_info=(
2106
+ f"Detected invalid namespace '{slot_namespace[0]}' in "
2107
+ f"condition '{condition}' for response variation "
2108
+ f"'{utter_name}'. Please make sure that you're "
2109
+ f"using a valid namespace. "
2110
+ f"The current supported option is: 'slots'."
2111
+ ),
2112
+ )
2113
+ all_good = False
2114
+ continue
2115
+
2116
+ if (
2117
+ slot_namespace is not None
2118
+ and slot_namespace[1] not in context[SLOTS]
2119
+ ):
2120
+ structlogger.error(
2121
+ "validator.validate_conditional_response_variation_predicates.invalid_slot",
2122
+ utter=utter_name,
2123
+ event_info=(
2124
+ f"Detected invalid slot '{slot_namespace[1]}' in "
2125
+ f"condition '{condition}' for response variation "
2126
+ f"'{utter_name}'. Please make sure that all slots "
2127
+ f"are specified in the domain file."
2128
+ ),
2129
+ )
2130
+ all_good = False
2131
+
2132
+ return all_good