rasa-pro 3.12.0.dev2__py3-none-any.whl → 3.12.0.dev3__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 (502) hide show
  1. rasa/__main__.py +7 -7
  2. rasa/anonymization/anonymisation_rule_yaml_reader.py +1 -1
  3. rasa/anonymization/anonymization_pipeline.py +3 -3
  4. rasa/anonymization/anonymization_rule_executor.py +1 -1
  5. rasa/anonymization/anonymization_rule_orchestrator.py +2 -3
  6. rasa/cli/arguments/data.py +2 -2
  7. rasa/cli/arguments/evaluate.py +2 -1
  8. rasa/cli/arguments/interactive.py +1 -1
  9. rasa/cli/arguments/run.py +1 -1
  10. rasa/cli/arguments/test.py +7 -5
  11. rasa/cli/arguments/train.py +3 -3
  12. rasa/cli/arguments/visualize.py +2 -2
  13. rasa/cli/arguments/x.py +1 -0
  14. rasa/cli/data.py +4 -3
  15. rasa/cli/dialogue_understanding_test.py +116 -18
  16. rasa/cli/evaluate.py +1 -1
  17. rasa/cli/export.py +6 -6
  18. rasa/cli/interactive.py +4 -5
  19. rasa/cli/llm_fine_tuning.py +5 -5
  20. rasa/cli/markers.py +1 -2
  21. rasa/cli/project_templates/calm/actions/add_contact.py +1 -1
  22. rasa/cli/project_templates/tutorial/actions/actions.py +3 -2
  23. rasa/cli/shell.py +2 -3
  24. rasa/cli/studio/download.py +1 -2
  25. rasa/cli/studio/studio.py +2 -3
  26. rasa/cli/studio/train.py +0 -1
  27. rasa/cli/telemetry.py +2 -2
  28. rasa/cli/test.py +11 -11
  29. rasa/cli/utils.py +7 -5
  30. rasa/core/__init__.py +0 -1
  31. rasa/core/actions/action.py +42 -21
  32. rasa/core/actions/action_hangup.py +1 -1
  33. rasa/core/actions/action_repeat_bot_messages.py +2 -2
  34. rasa/core/actions/action_run_slot_rejections.py +2 -2
  35. rasa/core/actions/action_trigger_chitchat.py +1 -1
  36. rasa/core/actions/action_trigger_flow.py +5 -5
  37. rasa/core/actions/action_trigger_search.py +1 -1
  38. rasa/core/actions/forms.py +14 -12
  39. rasa/core/actions/http_custom_action_executor.py +8 -1
  40. rasa/core/actions/loops.py +3 -3
  41. rasa/core/actions/two_stage_fallback.py +13 -13
  42. rasa/core/auth_retry_tracker_store.py +1 -2
  43. rasa/core/brokers/broker.py +2 -1
  44. rasa/core/brokers/file.py +1 -1
  45. rasa/core/brokers/kafka.py +8 -8
  46. rasa/core/brokers/pika.py +8 -9
  47. rasa/core/brokers/sql.py +4 -3
  48. rasa/core/channels/__init__.py +3 -0
  49. rasa/core/channels/botframework.py +2 -2
  50. rasa/core/channels/callback.py +4 -4
  51. rasa/core/channels/channel.py +11 -11
  52. rasa/core/channels/console.py +0 -1
  53. rasa/core/channels/development_inspector.py +6 -6
  54. rasa/core/channels/facebook.py +5 -5
  55. rasa/core/channels/hangouts.py +7 -8
  56. rasa/core/channels/inspector/dist/assets/{arc-861ddd57.js → arc-632a63ec.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-921f02db.js → c4Diagram-d0fbc5ce-081e0df4.js} +1 -1
  58. rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-b436c4f8.js → classDiagram-936ed81e-3df0afc2.js} +1 -1
  59. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-511a23cb.js → classDiagram-v2-c3cb15f1-8c5ed31e.js} +1 -1
  60. rasa/core/channels/inspector/dist/assets/{createText-62fc7601-ef476ecd.js → createText-62fc7601-89c73b31.js} +1 -1
  61. rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-f1878e0a.js → edges-f2ad444c-4fc48c3e.js} +1 -1
  62. rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-fac75185.js → erDiagram-9d236eb7-907e0440.js} +1 -1
  63. rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-201c5bbc.js → flowDb-1972c806-9ec53a3c.js} +1 -1
  64. rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-f904ae41.js → flowDiagram-7ea5b25a-41da787a.js} +1 -1
  65. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-8bea338b.js +1 -0
  66. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-1813da66.js → flowchart-elk-definition-abe16c3d-ce370633.js} +1 -1
  67. rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-872af172.js → ganttDiagram-9b5ea136-90a36523.js} +1 -1
  68. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-34a0af5a.js → gitGraphDiagram-99d0ae7c-41e1aa3f.js} +1 -1
  69. rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-42ba3e3d.js → index-2c4b9a3b-e6f2af62.js} +1 -1
  70. rasa/core/channels/inspector/dist/assets/{index-37817b51.js → index-e793d777.js} +3 -3
  71. rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-6b731386.js → infoDiagram-736b4530-8ceba4db.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-e8579ac6.js → journeyDiagram-df861f2b-960d3809.js} +1 -1
  73. rasa/core/channels/inspector/dist/assets/{layout-89e6403a.js → layout-498807d8.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/{line-dc73d3fc.js → line-eeccc4e2.js} +1 -1
  75. rasa/core/channels/inspector/dist/assets/{linear-f5b1d2bc.js → linear-8a078617.js} +1 -1
  76. rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-82cb74fa.js → mindmap-definition-beec6740-396d17dd.js} +1 -1
  77. rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-bdf5f29b.js → pieDiagram-dbbf0591-dc9b5e1b.js} +1 -1
  78. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-c7a0cbe4.js → quadrantDiagram-4d7f4fd6-a08cba6d.js} +1 -1
  79. rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-7ec5410f.js → requirementDiagram-6fc4c22a-87242b9e.js} +1 -1
  80. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-caee5554.js → sankeyDiagram-8f13d901-53f6f391.js} +1 -1
  81. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-2935f8db.js → sequenceDiagram-b655622a-715c9c20.js} +1 -1
  82. rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-8f5d9693.js → stateDiagram-59f0c015-2e8fb31f.js} +1 -1
  83. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-d565d1de.js → stateDiagram-v2-2b26beab-7e2d2aa0.js} +1 -1
  84. rasa/core/channels/inspector/dist/assets/{styles-080da4f6-75ad421d.js → styles-080da4f6-4420cea6.js} +1 -1
  85. rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-7e764226.js → styles-3dcbcfbf-28676cf4.js} +1 -1
  86. rasa/core/channels/inspector/dist/assets/{styles-9c745c82-7a4e0e61.js → styles-9c745c82-cef936a6.js} +1 -1
  87. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-4019d1bf.js → svgDrawCommon-4835440b-151251e9.js} +1 -1
  88. rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-01ea12df.js → timeline-definition-5b62e21b-0d39bdb2.js} +1 -1
  89. rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-89407137.js → xychartDiagram-2b33534f-a03fa445.js} +1 -1
  90. rasa/core/channels/inspector/dist/index.html +3 -1
  91. rasa/core/channels/inspector/index.html +2 -0
  92. rasa/core/channels/inspector/src/App.tsx +1 -4
  93. rasa/core/channels/mattermost.py +4 -4
  94. rasa/core/channels/rasa_chat.py +4 -4
  95. rasa/core/channels/rest.py +11 -12
  96. rasa/core/channels/rocketchat.py +4 -3
  97. rasa/core/channels/slack.py +6 -5
  98. rasa/core/channels/socketio.py +7 -28
  99. rasa/core/channels/studio_chat.py +193 -0
  100. rasa/core/channels/telegram.py +73 -41
  101. rasa/core/channels/twilio.py +3 -3
  102. rasa/core/channels/vier_cvg.py +2 -2
  103. rasa/core/channels/voice_ready/audiocodes.py +8 -8
  104. rasa/core/channels/voice_ready/jambonz.py +5 -5
  105. rasa/core/channels/voice_ready/jambonz_protocol.py +3 -4
  106. rasa/core/channels/voice_ready/twilio_voice.py +9 -8
  107. rasa/core/channels/voice_ready/utils.py +1 -1
  108. rasa/core/channels/voice_stream/asr/asr_engine.py +2 -2
  109. rasa/core/channels/voice_stream/asr/azure.py +2 -2
  110. rasa/core/channels/voice_stream/asr/deepgram.py +57 -16
  111. rasa/core/channels/voice_stream/browser_audio.py +9 -6
  112. rasa/core/channels/voice_stream/call_state.py +2 -1
  113. rasa/core/channels/voice_stream/tts/azure.py +1 -2
  114. rasa/core/channels/voice_stream/tts/cartesia.py +5 -4
  115. rasa/core/channels/voice_stream/tts/tts_cache.py +3 -2
  116. rasa/core/channels/voice_stream/tts/tts_engine.py +1 -1
  117. rasa/core/channels/voice_stream/twilio_media_streams.py +10 -7
  118. rasa/core/channels/voice_stream/util.py +1 -1
  119. rasa/core/channels/voice_stream/voice_channel.py +15 -15
  120. rasa/core/channels/webexteams.py +3 -4
  121. rasa/core/evaluation/marker.py +7 -6
  122. rasa/core/evaluation/marker_base.py +15 -16
  123. rasa/core/evaluation/marker_stats.py +3 -4
  124. rasa/core/evaluation/marker_tracker_loader.py +5 -4
  125. rasa/core/exporter.py +4 -4
  126. rasa/core/featurizers/precomputation.py +8 -8
  127. rasa/core/featurizers/single_state_featurizer.py +7 -7
  128. rasa/core/featurizers/tracker_featurizers.py +13 -13
  129. rasa/core/http_interpreter.py +3 -4
  130. rasa/core/information_retrieval/__init__.py +1 -1
  131. rasa/core/information_retrieval/faiss.py +4 -4
  132. rasa/core/information_retrieval/information_retrieval.py +2 -2
  133. rasa/core/information_retrieval/milvus.py +3 -3
  134. rasa/core/information_retrieval/qdrant.py +3 -3
  135. rasa/core/jobs.py +1 -0
  136. rasa/core/lock.py +2 -3
  137. rasa/core/lock_store.py +3 -3
  138. rasa/core/migrate.py +11 -8
  139. rasa/core/nlg/__init__.py +1 -1
  140. rasa/core/nlg/callback.py +2 -3
  141. rasa/core/nlg/contextual_response_rephraser.py +63 -13
  142. rasa/core/nlg/generator.py +2 -2
  143. rasa/core/nlg/interpolator.py +4 -3
  144. rasa/core/nlg/response.py +3 -4
  145. rasa/core/nlg/summarize.py +1 -0
  146. rasa/core/persistor.py +3 -3
  147. rasa/core/policies/ensemble.py +10 -9
  148. rasa/core/policies/enterprise_search_policy.py +86 -21
  149. rasa/core/policies/flow_policy.py +13 -14
  150. rasa/core/policies/flows/flow_executor.py +35 -11
  151. rasa/core/policies/intentless_policy.py +6 -7
  152. rasa/core/policies/memoization.py +22 -20
  153. rasa/core/policies/policy.py +24 -22
  154. rasa/core/policies/rule_policy.py +37 -36
  155. rasa/core/policies/ted_policy.py +87 -85
  156. rasa/core/policies/unexpected_intent_policy.py +77 -75
  157. rasa/core/processor.py +96 -65
  158. rasa/core/run.py +1 -1
  159. rasa/core/secrets_manager/endpoints.py +2 -3
  160. rasa/core/secrets_manager/factory.py +2 -3
  161. rasa/core/secrets_manager/secret_manager.py +2 -3
  162. rasa/core/secrets_manager/vault.py +2 -2
  163. rasa/core/test.py +30 -30
  164. rasa/core/tracker_store.py +15 -15
  165. rasa/core/train.py +1 -1
  166. rasa/core/training/__init__.py +2 -2
  167. rasa/core/training/converters/responses_prefix_converter.py +1 -2
  168. rasa/core/training/interactive.py +13 -13
  169. rasa/core/training/story_conflict.py +4 -5
  170. rasa/core/training/training.py +3 -5
  171. rasa/core/utils.py +5 -5
  172. rasa/core/visualize.py +1 -1
  173. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -2
  174. rasa/dialogue_understanding/coexistence/llm_based_router.py +5 -5
  175. rasa/dialogue_understanding/commands/__init__.py +22 -22
  176. rasa/dialogue_understanding/commands/can_not_handle_command.py +20 -1
  177. rasa/dialogue_understanding/commands/cancel_flow_command.py +18 -7
  178. rasa/dialogue_understanding/commands/change_flow_command.py +18 -2
  179. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +18 -4
  180. rasa/dialogue_understanding/commands/clarify_command.py +19 -3
  181. rasa/dialogue_understanding/commands/command.py +19 -3
  182. rasa/dialogue_understanding/commands/correct_slots_command.py +3 -3
  183. rasa/dialogue_understanding/commands/error_command.py +1 -1
  184. rasa/dialogue_understanding/commands/free_form_answer_command.py +2 -1
  185. rasa/dialogue_understanding/commands/handle_code_change_command.py +2 -2
  186. rasa/dialogue_understanding/commands/human_handoff_command.py +16 -4
  187. rasa/dialogue_understanding/commands/knowledge_answer_command.py +18 -4
  188. rasa/dialogue_understanding/commands/noop_command.py +2 -1
  189. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +16 -4
  190. rasa/dialogue_understanding/commands/restart_command.py +2 -5
  191. rasa/dialogue_understanding/commands/session_end_command.py +3 -5
  192. rasa/dialogue_understanding/commands/session_start_command.py +3 -5
  193. rasa/dialogue_understanding/commands/set_slot_command.py +27 -3
  194. rasa/dialogue_understanding/commands/skip_question_command.py +16 -4
  195. rasa/dialogue_understanding/commands/start_flow_command.py +17 -2
  196. rasa/dialogue_understanding/commands/user_silence_command.py +3 -5
  197. rasa/dialogue_understanding/commands/utils.py +64 -45
  198. rasa/dialogue_understanding/constants.py +1 -0
  199. rasa/dialogue_understanding/generator/command_generator.py +2 -119
  200. rasa/dialogue_understanding/generator/command_parser.py +201 -0
  201. rasa/dialogue_understanding/generator/constants.py +2 -2
  202. rasa/dialogue_understanding/generator/flow_retrieval.py +7 -7
  203. rasa/dialogue_understanding/generator/llm_based_command_generator.py +11 -57
  204. rasa/dialogue_understanding/generator/llm_command_generator.py +2 -1
  205. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +67 -120
  206. rasa/dialogue_understanding/generator/nlu_command_adapter.py +8 -10
  207. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +32 -93
  208. rasa/dialogue_understanding/generator/utils.py +45 -0
  209. rasa/dialogue_understanding/patterns/cancel.py +2 -1
  210. rasa/dialogue_understanding/patterns/cannot_handle.py +1 -0
  211. rasa/dialogue_understanding/patterns/chitchat.py +1 -1
  212. rasa/dialogue_understanding/patterns/clarify.py +2 -1
  213. rasa/dialogue_understanding/patterns/code_change.py +2 -0
  214. rasa/dialogue_understanding/patterns/collect_information.py +6 -3
  215. rasa/dialogue_understanding/patterns/completed.py +1 -1
  216. rasa/dialogue_understanding/patterns/continue_interrupted.py +10 -1
  217. rasa/dialogue_understanding/patterns/correction.py +4 -2
  218. rasa/dialogue_understanding/patterns/human_handoff.py +1 -1
  219. rasa/dialogue_understanding/patterns/internal_error.py +1 -0
  220. rasa/dialogue_understanding/patterns/search.py +1 -1
  221. rasa/dialogue_understanding/patterns/session_start.py +1 -1
  222. rasa/dialogue_understanding/patterns/skip_question.py +1 -0
  223. rasa/dialogue_understanding/patterns/user_silence.py +1 -1
  224. rasa/dialogue_understanding/processor/command_processor.py +13 -9
  225. rasa/dialogue_understanding/processor/command_processor_component.py +1 -1
  226. rasa/dialogue_understanding/stack/dialogue_stack.py +4 -3
  227. rasa/dialogue_understanding/stack/frames/__init__.py +2 -2
  228. rasa/dialogue_understanding/stack/frames/chit_chat_frame.py +4 -1
  229. rasa/dialogue_understanding/stack/frames/dialogue_stack_frame.py +2 -3
  230. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +5 -2
  231. rasa/dialogue_understanding/stack/frames/search_frame.py +4 -1
  232. rasa/dialogue_understanding/stack/utils.py +8 -4
  233. rasa/dialogue_understanding/utils.py +121 -2
  234. rasa/dialogue_understanding_test/README.md +379 -0
  235. rasa/dialogue_understanding_test/command_comparison.py +60 -0
  236. rasa/dialogue_understanding_test/command_metric_calculation.py +110 -4
  237. rasa/dialogue_understanding_test/constants.py +6 -1
  238. rasa/dialogue_understanding_test/du_test_case.py +252 -38
  239. rasa/dialogue_understanding_test/du_test_result.py +281 -2
  240. rasa/dialogue_understanding_test/du_test_runner.py +239 -10
  241. rasa/dialogue_understanding_test/du_test_schema.yml +161 -0
  242. rasa/dialogue_understanding_test/io.py +338 -20
  243. rasa/dialogue_understanding_test/test_case_simulation/__init__.py +0 -0
  244. rasa/dialogue_understanding_test/test_case_simulation/exception.py +28 -0
  245. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +336 -0
  246. rasa/dialogue_understanding_test/utils.py +70 -0
  247. rasa/dialogue_understanding_test/validation.py +59 -4
  248. rasa/e2e_test/aggregate_test_stats_calculator.py +1 -1
  249. rasa/e2e_test/assertions.py +1 -1
  250. rasa/e2e_test/e2e_config.py +1 -1
  251. rasa/e2e_test/e2e_test_case.py +3 -4
  252. rasa/e2e_test/e2e_test_converter.py +2 -3
  253. rasa/e2e_test/e2e_test_coverage_report.py +6 -6
  254. rasa/e2e_test/e2e_test_result.py +1 -1
  255. rasa/e2e_test/e2e_test_runner.py +134 -31
  256. rasa/e2e_test/stub_custom_action.py +1 -1
  257. rasa/e2e_test/utils/e2e_yaml_utils.py +1 -1
  258. rasa/e2e_test/utils/io.py +132 -65
  259. rasa/e2e_test/utils/validation.py +1 -1
  260. rasa/engine/caching.py +5 -7
  261. rasa/engine/constants.py +1 -1
  262. rasa/engine/graph.py +2 -2
  263. rasa/engine/recipes/default_components.py +13 -15
  264. rasa/engine/recipes/recipe.py +2 -2
  265. rasa/engine/runner/dask.py +2 -2
  266. rasa/engine/runner/interface.py +1 -0
  267. rasa/engine/storage/local_model_storage.py +5 -4
  268. rasa/engine/storage/resource.py +2 -1
  269. rasa/engine/storage/storage.py +5 -3
  270. rasa/engine/training/components.py +2 -1
  271. rasa/engine/training/fingerprinting.py +4 -2
  272. rasa/engine/training/graph_trainer.py +4 -4
  273. rasa/engine/training/hooks.py +2 -2
  274. rasa/engine/validation.py +34 -33
  275. rasa/exceptions.py +3 -2
  276. rasa/graph_components/converters/nlu_message_converter.py +3 -3
  277. rasa/graph_components/providers/domain_for_core_training_provider.py +3 -3
  278. rasa/graph_components/providers/domain_provider.py +3 -2
  279. rasa/graph_components/providers/flows_provider.py +2 -3
  280. rasa/graph_components/providers/forms_provider.py +4 -4
  281. rasa/graph_components/providers/nlu_training_data_provider.py +5 -3
  282. rasa/graph_components/providers/responses_provider.py +4 -4
  283. rasa/graph_components/providers/rule_only_provider.py +3 -2
  284. rasa/graph_components/providers/story_graph_provider.py +8 -8
  285. rasa/graph_components/providers/training_tracker_provider.py +3 -2
  286. rasa/graph_components/validators/default_recipe_validator.py +16 -16
  287. rasa/graph_components/validators/finetuning_validator.py +10 -8
  288. rasa/hooks.py +18 -12
  289. rasa/jupyter.py +2 -2
  290. rasa/llm_fine_tuning/annotation_module.py +4 -4
  291. rasa/llm_fine_tuning/conversations.py +6 -6
  292. rasa/llm_fine_tuning/llm_data_preparation_module.py +1 -1
  293. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +4 -4
  294. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +1 -1
  295. rasa/llm_fine_tuning/paraphrasing_module.py +1 -1
  296. rasa/llm_fine_tuning/storage.py +3 -3
  297. rasa/markers/marker.py +2 -3
  298. rasa/markers/marker_base.py +1 -2
  299. rasa/markers/upload.py +2 -2
  300. rasa/markers/validate.py +2 -3
  301. rasa/model.py +3 -5
  302. rasa/model_manager/config.py +1 -1
  303. rasa/model_manager/model_api.py +5 -4
  304. rasa/model_manager/runner_service.py +6 -6
  305. rasa/model_manager/socket_bridge.py +8 -3
  306. rasa/model_manager/studio_jwt_auth.py +1 -0
  307. rasa/model_manager/trainer_service.py +9 -7
  308. rasa/model_manager/utils.py +1 -1
  309. rasa/model_manager/warm_rasa_process.py +14 -8
  310. rasa/model_service.py +5 -6
  311. rasa/model_testing.py +13 -15
  312. rasa/nlu/classifiers/diet_classifier.py +72 -73
  313. rasa/nlu/classifiers/fallback_classifier.py +9 -8
  314. rasa/nlu/classifiers/keyword_intent_classifier.py +7 -6
  315. rasa/nlu/classifiers/logistic_regression_classifier.py +3 -3
  316. rasa/nlu/classifiers/mitie_intent_classifier.py +5 -4
  317. rasa/nlu/classifiers/regex_message_handler.py +3 -2
  318. rasa/nlu/classifiers/sklearn_intent_classifier.py +2 -2
  319. rasa/nlu/convert.py +2 -2
  320. rasa/nlu/emulators/dialogflow.py +3 -3
  321. rasa/nlu/emulators/luis.py +5 -5
  322. rasa/nlu/emulators/no_emulator.py +1 -0
  323. rasa/nlu/emulators/wit.py +4 -4
  324. rasa/nlu/extractors/crf_entity_extractor.py +11 -11
  325. rasa/nlu/extractors/duckling_entity_extractor.py +7 -6
  326. rasa/nlu/extractors/entity_synonyms.py +10 -9
  327. rasa/nlu/extractors/extractor.py +16 -16
  328. rasa/nlu/extractors/mitie_entity_extractor.py +10 -9
  329. rasa/nlu/extractors/regex_entity_extractor.py +11 -10
  330. rasa/nlu/extractors/spacy_entity_extractor.py +2 -2
  331. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +15 -14
  332. rasa/nlu/featurizers/dense_featurizer/dense_featurizer.py +2 -1
  333. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +10 -9
  334. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +9 -7
  335. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +13 -12
  336. rasa/nlu/featurizers/featurizer.py +5 -4
  337. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +6 -6
  338. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -4
  339. rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +4 -4
  340. rasa/nlu/featurizers/sparse_featurizer/sparse_featurizer.py +2 -0
  341. rasa/nlu/model.py +0 -1
  342. rasa/nlu/selectors/response_selector.py +67 -68
  343. rasa/nlu/test.py +38 -38
  344. rasa/nlu/tokenizers/jieba_tokenizer.py +1 -2
  345. rasa/nlu/tokenizers/mitie_tokenizer.py +2 -2
  346. rasa/nlu/tokenizers/spacy_tokenizer.py +3 -3
  347. rasa/nlu/tokenizers/tokenizer.py +6 -7
  348. rasa/nlu/tokenizers/whitespace_tokenizer.py +1 -1
  349. rasa/nlu/utils/bilou_utils.py +7 -7
  350. rasa/nlu/utils/hugging_face/registry.py +22 -22
  351. rasa/nlu/utils/hugging_face/transformers_pre_post_processors.py +2 -1
  352. rasa/nlu/utils/mitie_utils.py +2 -1
  353. rasa/nlu/utils/pattern_utils.py +1 -1
  354. rasa/nlu/utils/spacy_utils.py +3 -3
  355. rasa/plugin.py +12 -1
  356. rasa/server.py +37 -1
  357. rasa/shared/constants.py +22 -2
  358. rasa/shared/core/command_payload_reader.py +15 -7
  359. rasa/shared/core/constants.py +4 -1
  360. rasa/shared/core/conversation.py +1 -2
  361. rasa/shared/core/events.py +47 -37
  362. rasa/shared/core/flows/__init__.py +0 -1
  363. rasa/shared/core/flows/flow.py +11 -11
  364. rasa/shared/core/flows/flow_step.py +19 -13
  365. rasa/shared/core/flows/flow_step_links.py +21 -14
  366. rasa/shared/core/flows/flow_step_sequence.py +6 -4
  367. rasa/shared/core/flows/flows_list.py +3 -3
  368. rasa/shared/core/flows/nlu_trigger.py +1 -1
  369. rasa/shared/core/flows/steps/__init__.py +2 -2
  370. rasa/shared/core/flows/steps/action.py +4 -3
  371. rasa/shared/core/flows/steps/call.py +4 -4
  372. rasa/shared/core/flows/steps/collect.py +7 -4
  373. rasa/shared/core/flows/steps/continuation.py +3 -1
  374. rasa/shared/core/flows/steps/end.py +3 -1
  375. rasa/shared/core/flows/steps/internal.py +3 -2
  376. rasa/shared/core/flows/steps/link.py +6 -4
  377. rasa/shared/core/flows/steps/no_operation.py +7 -5
  378. rasa/shared/core/flows/steps/set_slots.py +4 -3
  379. rasa/shared/core/flows/steps/start.py +3 -1
  380. rasa/shared/core/flows/utils.py +1 -0
  381. rasa/shared/core/flows/validation.py +3 -5
  382. rasa/shared/core/generator.py +20 -21
  383. rasa/shared/core/slot_mappings.py +15 -15
  384. rasa/shared/core/slots.py +3 -3
  385. rasa/shared/core/trackers.py +31 -31
  386. rasa/shared/core/training_data/loading.py +1 -1
  387. rasa/shared/core/training_data/story_reader/story_reader.py +3 -3
  388. rasa/shared/core/training_data/story_reader/story_step_builder.py +4 -4
  389. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +29 -31
  390. rasa/shared/core/training_data/story_writer/yaml_story_writer.py +22 -24
  391. rasa/shared/core/training_data/structures.py +11 -12
  392. rasa/shared/core/training_data/visualization.py +10 -10
  393. rasa/shared/data.py +6 -6
  394. rasa/shared/engine/caching.py +0 -1
  395. rasa/shared/exceptions.py +2 -2
  396. rasa/shared/importers/rasa.py +5 -6
  397. rasa/shared/importers/utils.py +1 -1
  398. rasa/shared/nlu/constants.py +3 -0
  399. rasa/shared/nlu/training_data/entities_parser.py +6 -6
  400. rasa/shared/nlu/training_data/features.py +3 -3
  401. rasa/shared/nlu/training_data/formats/__init__.py +1 -1
  402. rasa/shared/nlu/training_data/formats/dialogflow.py +4 -5
  403. rasa/shared/nlu/training_data/formats/luis.py +7 -8
  404. rasa/shared/nlu/training_data/formats/rasa.py +4 -5
  405. rasa/shared/nlu/training_data/formats/rasa_yaml.py +17 -16
  406. rasa/shared/nlu/training_data/formats/readerwriter.py +8 -11
  407. rasa/shared/nlu/training_data/formats/wit.py +3 -4
  408. rasa/shared/nlu/training_data/loading.py +4 -4
  409. rasa/shared/nlu/training_data/lookup_tables_parser.py +1 -1
  410. rasa/shared/nlu/training_data/message.py +13 -14
  411. rasa/shared/nlu/training_data/schemas/data_schema.py +1 -1
  412. rasa/shared/nlu/training_data/schemas/responses.yml +1 -0
  413. rasa/shared/nlu/training_data/synonyms_parser.py +3 -3
  414. rasa/shared/nlu/training_data/training_data.py +12 -13
  415. rasa/shared/nlu/training_data/util.py +11 -10
  416. rasa/shared/providers/_configs/azure_openai_client_config.py +3 -119
  417. rasa/shared/providers/_configs/client_config.py +1 -3
  418. rasa/shared/providers/_configs/default_litellm_client_config.py +1 -3
  419. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -3
  420. rasa/shared/providers/_configs/litellm_router_client_config.py +1 -3
  421. rasa/shared/providers/_configs/model_group_config.py +2 -7
  422. rasa/shared/providers/_configs/openai_client_config.py +1 -3
  423. rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -3
  424. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -3
  425. rasa/shared/providers/_configs/utils.py +1 -0
  426. rasa/shared/providers/_ssl_verification_utils.py +5 -6
  427. rasa/shared/providers/_utils.py +5 -5
  428. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +1 -1
  429. rasa/shared/providers/embedding/azure_openai_embedding_client.py +3 -26
  430. rasa/shared/providers/embedding/embedding_client.py +1 -1
  431. rasa/shared/providers/embedding/litellm_router_embedding_client.py +1 -3
  432. rasa/shared/providers/llm/_base_litellm_client.py +1 -3
  433. rasa/shared/providers/llm/azure_openai_llm_client.py +25 -79
  434. rasa/shared/providers/llm/default_litellm_llm_client.py +1 -3
  435. rasa/shared/providers/llm/litellm_router_llm_client.py +2 -21
  436. rasa/shared/providers/llm/llm_client.py +1 -3
  437. rasa/shared/providers/llm/llm_response.py +41 -2
  438. rasa/shared/providers/llm/openai_llm_client.py +3 -9
  439. rasa/shared/providers/llm/rasa_llm_client.py +6 -20
  440. rasa/shared/providers/llm/self_hosted_llm_client.py +3 -9
  441. rasa/shared/providers/mappings.py +18 -19
  442. rasa/shared/providers/router/_base_litellm_router_client.py +1 -3
  443. rasa/shared/providers/router/router_client.py +1 -3
  444. rasa/shared/utils/cli.py +1 -1
  445. rasa/shared/utils/common.py +1 -1
  446. rasa/shared/utils/health_check/embeddings_health_check_mixin.py +1 -1
  447. rasa/shared/utils/health_check/health_check.py +3 -3
  448. rasa/shared/utils/health_check/llm_health_check_mixin.py +1 -1
  449. rasa/shared/utils/io.py +1 -1
  450. rasa/shared/utils/llm.py +5 -9
  451. rasa/shared/utils/pykwalify_extensions.py +1 -1
  452. rasa/shared/utils/schemas/events.py +1 -1
  453. rasa/shared/utils/yaml.py +29 -26
  454. rasa/studio/auth.py +3 -3
  455. rasa/studio/config.py +1 -2
  456. rasa/studio/data_handler.py +3 -3
  457. rasa/studio/download.py +1 -1
  458. rasa/studio/results_logger.py +3 -3
  459. rasa/studio/upload.py +2 -0
  460. rasa/telemetry.py +31 -0
  461. rasa/tracing/config.py +3 -3
  462. rasa/tracing/instrumentation/attribute_extractors.py +2 -0
  463. rasa/tracing/instrumentation/instrumentation.py +4 -4
  464. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +1 -1
  465. rasa/tracing/instrumentation/metrics.py +11 -11
  466. rasa/tracing/metric_instrument_provider.py +14 -14
  467. rasa/utils/common.py +12 -9
  468. rasa/utils/endpoints.py +1 -1
  469. rasa/utils/io.py +7 -7
  470. rasa/utils/licensing.py +3 -4
  471. rasa/utils/log_utils.py +7 -6
  472. rasa/utils/ml_utils.py +1 -0
  473. rasa/utils/plotting.py +3 -3
  474. rasa/utils/sanic_error_handler.py +1 -1
  475. rasa/utils/tensorflow/callback.py +2 -2
  476. rasa/utils/tensorflow/crf.py +2 -2
  477. rasa/utils/tensorflow/data_generator.py +5 -5
  478. rasa/utils/tensorflow/environment.py +3 -3
  479. rasa/utils/tensorflow/feature_array.py +2 -3
  480. rasa/utils/tensorflow/layers.py +18 -12
  481. rasa/utils/tensorflow/layers_utils.py +2 -1
  482. rasa/utils/tensorflow/metrics.py +2 -2
  483. rasa/utils/tensorflow/model_data.py +7 -7
  484. rasa/utils/tensorflow/model_data_utils.py +10 -9
  485. rasa/utils/tensorflow/models.py +31 -32
  486. rasa/utils/tensorflow/rasa_layers.py +20 -19
  487. rasa/utils/tensorflow/types.py +2 -1
  488. rasa/utils/train_utils.py +23 -21
  489. rasa/utils/url_tools.py +1 -1
  490. rasa/validator.py +17 -1
  491. rasa/version.py +1 -1
  492. {rasa_pro-3.12.0.dev2.dist-info → rasa_pro-3.12.0.dev3.dist-info}/METADATA +8 -9
  493. rasa_pro-3.12.0.dev3.dist-info/RECORD +800 -0
  494. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-b080d6f2.js +0 -1
  495. rasa/shared/providers/_configs/azure_entra_id_client_creds.py +0 -40
  496. rasa/shared/providers/_configs/azure_entra_id_config.py +0 -533
  497. rasa/shared/providers/_configs/oauth_config.py +0 -33
  498. rasa/shared/providers/constants.py +0 -6
  499. rasa_pro-3.12.0.dev2.dist-info/RECORD +0 -793
  500. {rasa_pro-3.12.0.dev2.dist-info → rasa_pro-3.12.0.dev3.dist-info}/NOTICE +0 -0
  501. {rasa_pro-3.12.0.dev2.dist-info → rasa_pro-3.12.0.dev3.dist-info}/WHEEL +0 -0
  502. {rasa_pro-3.12.0.dev2.dist-info → rasa_pro-3.12.0.dev3.dist-info}/entry_points.txt +0 -0
@@ -1,12 +1,118 @@
1
- from typing import List, Dict
1
+ from collections import defaultdict
2
+ from typing import Dict, List
2
3
 
4
+ from pydantic import BaseModel
5
+
6
+ from rasa.dialogue_understanding.commands import Command
7
+ from rasa.dialogue_understanding_test.command_comparison import (
8
+ is_command_present_in_list,
9
+ )
3
10
  from rasa.dialogue_understanding_test.du_test_result import (
4
11
  DialogueUnderstandingTestResult,
5
12
  )
6
13
 
7
14
 
15
+ class CommandMetrics(BaseModel):
16
+ tp: int
17
+ fp: int
18
+ fn: int
19
+ total_count: int
20
+
21
+ @staticmethod
22
+ def _safe_divide(numerator: float, denominator: float) -> float:
23
+ """Safely perform division, returning 0.0 if the denominator is zero."""
24
+ return numerator / denominator if denominator > 0 else 0.0
25
+
26
+ def get_precision(self) -> float:
27
+ return self._safe_divide(self.tp, self.tp + self.fp)
28
+
29
+ def get_recall(self) -> float:
30
+ return self._safe_divide(self.tp, self.tp + self.fn)
31
+
32
+ def get_f1_score(self) -> float:
33
+ precision = self.get_precision()
34
+ recall = self.get_recall()
35
+
36
+ return self._safe_divide(2 * precision * recall, precision + recall)
37
+
38
+ def as_dict(self) -> Dict[str, float]:
39
+ return {
40
+ "tp": self.tp,
41
+ "fp": self.fp,
42
+ "fn": self.fn,
43
+ "precision": self.get_precision(),
44
+ "recall": self.get_recall(),
45
+ "f1_score": self.get_f1_score(),
46
+ "total_count": self.total_count,
47
+ }
48
+
49
+
8
50
  def calculate_command_metrics(
9
51
  test_results: List[DialogueUnderstandingTestResult],
10
- ) -> Dict[str, Dict[str, float]]:
11
- """Calculate the metrics for the commands."""
12
- return {}
52
+ ) -> Dict[str, CommandMetrics]:
53
+ """Calculate the command metrics for the test result."""
54
+ metrics: Dict[str, CommandMetrics] = defaultdict(
55
+ lambda: CommandMetrics(tp=0, fp=0, fn=0, total_count=0)
56
+ )
57
+
58
+ for test_result in test_results:
59
+ _increase_total_count(test_result.get_expected_commands(), metrics)
60
+
61
+ # if the test case passed, count all commands as tp
62
+ if test_result.passed:
63
+ _increase_tp(test_result.get_expected_commands(), metrics)
64
+ continue
65
+
66
+ # in case the test case failed, we need to compare
67
+ # the expected and actual commands for each step
68
+ for step in test_result.test_case.iterate_over_user_steps():
69
+ expected_commands = step.commands
70
+ predicted_commands = step.get_predicted_commands()
71
+
72
+ _update_metrics_true_positive_and_false_negative(
73
+ expected_commands, predicted_commands, metrics
74
+ )
75
+ _update_metrics_false_positive(
76
+ expected_commands, predicted_commands, metrics
77
+ )
78
+
79
+ return metrics
80
+
81
+
82
+ def _increase_total_count(
83
+ commands: List[Command],
84
+ metrics: Dict[str, CommandMetrics],
85
+ ) -> None:
86
+ for command in commands:
87
+ metrics[command.command()].total_count += 1
88
+
89
+
90
+ def _increase_tp(
91
+ commands: List[Command],
92
+ metrics: Dict[str, CommandMetrics],
93
+ ) -> None:
94
+ for command in commands:
95
+ metrics[command.command()].tp += 1
96
+
97
+
98
+ def _update_metrics_true_positive_and_false_negative(
99
+ expected_commands: List[Command],
100
+ predicted_commands: List[Command],
101
+ metrics: Dict[str, CommandMetrics],
102
+ ) -> None:
103
+ for expected_command in expected_commands:
104
+ command_name = expected_command.command()
105
+ if is_command_present_in_list(expected_command, predicted_commands):
106
+ metrics[command_name].tp += 1
107
+ else:
108
+ metrics[command_name].fn += 1
109
+
110
+
111
+ def _update_metrics_false_positive(
112
+ expected_commands: List[Command],
113
+ predicted_commands: List[Command],
114
+ metrics: Dict[str, CommandMetrics],
115
+ ) -> None:
116
+ for predicted_command in predicted_commands:
117
+ if not is_command_present_in_list(predicted_command, expected_commands):
118
+ metrics[predicted_command.command()].fp += 1
@@ -10,8 +10,13 @@ KEY_STEPS = constants.KEY_STEPS
10
10
  KEY_TEST_CASE = constants.KEY_TEST_CASE
11
11
  KEY_TEST_CASES = constants.KEY_TEST_CASES
12
12
  KEY_COMMANDS = "commands"
13
+ KEY_ADDITIONAL_COMMANDS = "additional_commands"
14
+ KEY_REMOVE_DEFAULT_COMMANDS = "remove_default_commands"
13
15
 
14
16
  ACTOR_USER = "user"
15
17
  ACTOR_BOT = "bot"
16
18
 
17
- DEFAULT_INPUT_TESTS_PATH = "du_tests/"
19
+ DEFAULT_INPUT_TESTS_PATH = "dialogue_understanding_tests/"
20
+ SCHEMA_FILE_PATH = "dialogue_understanding_test/du_test_schema.yml"
21
+
22
+ PLACEHOLDER_GENERATED_ANSWER_TEMPLATE = "placeholder_generated_answer"
@@ -1,19 +1,27 @@
1
- from typing import List, Optional, Dict, Any
1
+ from typing import Any, Dict, Iterator, List, Optional, Tuple
2
2
 
3
3
  from pydantic import BaseModel, ConfigDict, Field
4
4
 
5
5
  from rasa.dialogue_understanding.commands import Command
6
+ from rasa.dialogue_understanding.generator.command_parser import parse_commands
7
+ from rasa.dialogue_understanding_test.command_comparison import are_command_lists_equal
6
8
  from rasa.dialogue_understanding_test.constants import (
9
+ ACTOR_BOT,
7
10
  ACTOR_USER,
11
+ KEY_BOT_INPUT,
12
+ KEY_BOT_UTTERED,
8
13
  KEY_COMMANDS,
9
- ACTOR_BOT,
10
- KEY_TEST_CASE,
11
- KEY_STEPS,
12
14
  KEY_FIXTURES,
13
15
  KEY_METADATA,
16
+ KEY_STEPS,
17
+ KEY_TEST_CASE,
14
18
  KEY_USER_INPUT,
15
- KEY_BOT_INPUT,
16
- KEY_BOT_UTTERED,
19
+ )
20
+ from rasa.shared.core.flows import FlowsList
21
+ from rasa.shared.nlu.constants import (
22
+ KEY_COMPONENT_NAME,
23
+ KEY_PROMPT_NAME,
24
+ KEY_USER_PROMPT,
17
25
  )
18
26
 
19
27
 
@@ -23,44 +31,82 @@ class DialogueUnderstandingOutput(BaseModel):
23
31
  Example of commands:
24
32
  {
25
33
  "MultiStepLLMCommandGenerator": [
26
- {"command": "set_slot", "name": "slot_name", "value": "slot_value"},
34
+ SetSlotCommand(name="slot_name", value="slot_value"),
27
35
  ],
28
36
  "NLUCommandAdapter": [
29
- {"command": "start_flow", "name": "test_flow"},
37
+ StartFlowCommand("test_flow"),
30
38
  ]
31
39
  }
32
40
 
33
41
  Example of prompts:
34
- {
35
- "MultiStepLLMCommandGenerator": [
36
- (
37
- "fill_slots_prompt",
38
- {
39
- "user_prompt": "<prompt content>",
40
- "system_prompt": "<prompt content>"
41
- }
42
- ),
43
- (
44
- "handle_flows_prompt",
45
- {
46
- "user_prompt": "<prompt content>",
47
- "system_prompt": "<prompt content>"
48
- }
49
- ),
50
- ],
51
- }
42
+ [
43
+ {
44
+ "component_name": "MultiStepLLMCommandGenerator",
45
+ "prompt_name": "fill_slots_prompt",
46
+ "user_prompt": "...",
47
+ "system_prompt": "...",
48
+ "llm_response_metadata": { ... }
49
+ },
50
+ {
51
+ "component_name": "MultiStepLLMCommandGenerator",
52
+ "prompt_name": "handle_flows_prompt",
53
+ "user_prompt": "...",
54
+ "system_prompt": "...",
55
+ "llm_response_metadata": { ... }
56
+ },
57
+ ]
52
58
  """
53
59
 
54
- prompts: Dict[str, tuple[str, Dict[str, str]]]
60
+ # Dict with component name as key and list of commands as value
55
61
  commands: Dict[str, List[Command]]
62
+ # List of prompts
63
+ prompts: Optional[List[Dict[str, Any]]] = None
56
64
 
57
65
  model_config = ConfigDict(frozen=True)
58
66
 
59
- def get_component_data(
60
- self, component_name: str
61
- ) -> tuple[Optional[tuple[str, Dict[str, str]]], List[Command]]:
62
- """Get both the prompts and commands for a specific component."""
63
- return self.prompts.get(component_name), self.commands.get(component_name, [])
67
+ def get_predicted_commands(self) -> List[Command]:
68
+ """Get all commands from the output."""
69
+ return [
70
+ command
71
+ for predicted_commands in self.commands.values()
72
+ for command in predicted_commands
73
+ ]
74
+
75
+ def get_component_names_that_predicted_commands(self) -> List[str]:
76
+ """Get all component names that have predicted commands."""
77
+ if self.commands is None:
78
+ return []
79
+ return [
80
+ component_name
81
+ for component_name, predicted_commands in self.commands.items()
82
+ if predicted_commands
83
+ ]
84
+
85
+ def get_component_name_to_user_prompts(self) -> Dict[str, List[Tuple[str, str]]]:
86
+ """Return a dictionary of component names to a list of prompts.
87
+
88
+ The prompts are represented as tuples of (prompt_name, user_prompt).
89
+ """
90
+ if self.prompts is None:
91
+ return {}
92
+
93
+ data: Dict[str, List[Tuple[str, str]]] = {}
94
+ relevant_component_names = self.get_component_names_that_predicted_commands()
95
+
96
+ for prompt_data in self.prompts:
97
+ component_name = prompt_data[KEY_COMPONENT_NAME]
98
+
99
+ if component_name not in relevant_component_names:
100
+ continue
101
+
102
+ prompt_name = prompt_data[KEY_PROMPT_NAME]
103
+ user_prompt = prompt_data[KEY_USER_PROMPT]
104
+
105
+ if component_name not in data:
106
+ data[component_name] = []
107
+ data[component_name].append((prompt_name, user_prompt))
108
+
109
+ return data
64
110
 
65
111
 
66
112
  class DialogueUnderstandingTestStep(BaseModel):
@@ -77,22 +123,97 @@ class DialogueUnderstandingTestStep(BaseModel):
77
123
  if self.commands:
78
124
  return {
79
125
  KEY_USER_INPUT: self.text,
80
- # TODO: The command should be converted into our DSL
81
- KEY_COMMANDS: [command.as_dict() for command in self.commands],
126
+ KEY_COMMANDS: [command.to_dsl() for command in self.commands],
82
127
  }
83
128
  return {ACTOR_USER: self.text}
84
129
  elif self.actor == ACTOR_BOT:
85
- if self.text is not None:
86
- return {KEY_BOT_INPUT: self.text}
87
- elif self.template is not None:
130
+ if self.template is not None:
88
131
  return {KEY_BOT_UTTERED: self.template}
132
+ elif self.text is not None:
133
+ return {KEY_BOT_INPUT: self.text}
89
134
 
90
135
  return {}
91
136
 
137
+ @staticmethod
138
+ def from_dict(
139
+ step: Dict[str, Any],
140
+ flows: FlowsList,
141
+ custom_command_classes: List[Command] = [],
142
+ remove_default_commands: List[str] = [],
143
+ ) -> "DialogueUnderstandingTestStep":
144
+ """Creates a DialogueUnderstandingTestStep from a dictionary.
145
+
146
+ Example:
147
+ >>> DialogueUnderstandingTestStep.from_dict({"user": "hello"})
148
+
149
+ Args:
150
+ step: Dictionary containing the step.
151
+ flows: List of flows.
152
+ custom_commands: Custom commands to use in the test case.
153
+ remove_default_commands: Default commands to remove from the test case.
154
+
155
+ Returns:
156
+ DialogueUnderstandingTestStep: The constructed test step.
157
+
158
+ Raises:
159
+ ValueError: If the step has invalid commands that are not parseable.
160
+ """
161
+ # Safely extract commands from the step.
162
+ commands = []
163
+ for command in step.get(KEY_COMMANDS, []):
164
+ try:
165
+ commands.extend(
166
+ parse_commands(
167
+ command,
168
+ flows,
169
+ clarify_options_optional=True,
170
+ additional_commands=custom_command_classes,
171
+ default_commands_to_remove=remove_default_commands,
172
+ )
173
+ )
174
+ except (IndexError, ValueError) as e:
175
+ raise ValueError(f"Failed to parse command '{command}': {e}") from e
176
+
177
+ # Construct the DialogueUnderstandingTestStep
178
+ return DialogueUnderstandingTestStep(
179
+ actor=ACTOR_USER if ACTOR_USER in step else ACTOR_BOT,
180
+ text=step.get(KEY_USER_INPUT) or step.get(KEY_BOT_INPUT),
181
+ template=step.get(KEY_BOT_UTTERED),
182
+ line=step.lc.line + 1 if hasattr(step, "lc") else None,
183
+ metadata_name=step.get(KEY_METADATA, ""),
184
+ commands=commands,
185
+ )
186
+
187
+ def get_predicted_commands(self) -> List[Command]:
188
+ """Get all predicted commands from the test case."""
189
+ if self.dialogue_understanding_output is None:
190
+ return []
191
+
192
+ return self.dialogue_understanding_output.get_predicted_commands()
193
+
194
+ def has_passed(self) -> bool:
195
+ expected_commands = self.commands or []
196
+ predicted_commands = self.get_predicted_commands()
197
+
198
+ return are_command_lists_equal(expected_commands, predicted_commands)
199
+
200
+ def to_str(self) -> str:
201
+ """Converts the test step to a readable output string."""
202
+ if self.actor == ACTOR_BOT:
203
+ if self.text:
204
+ return f"{KEY_BOT_INPUT}: {self.text}"
205
+ elif self.template:
206
+ return f"{KEY_BOT_UTTERED}: {self.template}"
207
+
208
+ if self.actor == ACTOR_USER:
209
+ return f"{KEY_USER_INPUT}: {self.text}"
210
+
211
+ return ""
212
+
92
213
 
93
214
  class DialogueUnderstandingTestCase(BaseModel):
94
215
  name: str
95
- steps: list[DialogueUnderstandingTestStep] = Field(min_length=1)
216
+ steps: List[DialogueUnderstandingTestStep] = Field(min_length=1)
96
217
  file: Optional[str] = None
97
218
  line: Optional[int] = None
98
219
  fixture_names: Optional[List[str]] = None
@@ -112,6 +233,99 @@ class DialogueUnderstandingTestCase(BaseModel):
112
233
  result[KEY_METADATA] = self.metadata_name
113
234
  return result
114
235
 
236
+ @staticmethod
237
+ def from_dict(
238
+ input_test_case: Dict[str, Any],
239
+ flows: FlowsList,
240
+ file: Optional[str] = None,
241
+ custom_command_classes: List[Command] = [],
242
+ remove_default_commands: List[str] = [],
243
+ ) -> "DialogueUnderstandingTestCase":
244
+ """Creates a DialogueUnderstandingTestCase from a dictionary.
245
+
246
+ Example:
247
+ >>> DialogueUnderstandingTestCase.from_dict({
248
+ "test_case": "test",
249
+ "steps": [{"user": "hello"}]
250
+ })
251
+
252
+ Args:
253
+ input_test_case: Dictionary containing the test case.
254
+ flows: List of flows.
255
+ file: File name of the test case.
256
+ custom_command_classes: Custom command classes to use in the test case.
257
+ remove_default_commands: Default commands to remove from the test case.
258
+
259
+ Returns:
260
+ DialogueUnderstandingTestCase object.
261
+ """
262
+ steps = [
263
+ DialogueUnderstandingTestStep.from_dict(
264
+ step, flows, custom_command_classes, remove_default_commands
265
+ )
266
+ for step in input_test_case.get(KEY_STEPS, [])
267
+ ]
268
+
269
+ return DialogueUnderstandingTestCase(
270
+ name=input_test_case.get(KEY_TEST_CASE, "default"),
271
+ steps=steps,
272
+ file=file,
273
+ line=(
274
+ input_test_case.lc.line + 1 if hasattr(input_test_case, "lc") else None
275
+ ),
276
+ fixture_names=input_test_case.get(KEY_FIXTURES),
277
+ metadata_name=input_test_case.get(KEY_METADATA),
278
+ )
279
+
280
+ def to_readable_conversation(self, until_step: Optional[int] = None) -> List[str]:
281
+ if until_step:
282
+ steps = self.steps[:until_step]
283
+ else:
284
+ steps = self.steps
285
+
286
+ return [step.to_str() for step in steps]
287
+
288
+ def get_expected_commands(self) -> List[Command]:
289
+ """Get all commands from the test steps."""
290
+ return [
291
+ command
292
+ for step in self.iterate_over_user_steps()
293
+ for command in (step.commands or [])
294
+ ]
295
+
296
+ def iterate_over_user_steps(self) -> Iterator[DialogueUnderstandingTestStep]:
297
+ """Iterate over user steps, i.e. steps with commands."""
298
+ for step in self.steps:
299
+ if step.commands:
300
+ yield step
301
+
302
+ def get_next_user_and_bot_steps(
303
+ self, from_index: int
304
+ ) -> Tuple[
305
+ Optional[DialogueUnderstandingTestStep], List[DialogueUnderstandingTestStep]
306
+ ]:
307
+ """Get the next user step and all following bot steps."""
308
+ user_step = None
309
+ bot_steps = []
310
+
311
+ for step in self.steps[from_index:]:
312
+ if user_step is not None and step.actor == ACTOR_USER:
313
+ return user_step, bot_steps
314
+
315
+ if step.actor == ACTOR_USER:
316
+ user_step = step
317
+ elif step.actor == ACTOR_BOT:
318
+ bot_steps.append(step)
319
+
320
+ return user_step, bot_steps
321
+
322
+ def failed_user_steps(self) -> List[DialogueUnderstandingTestStep]:
323
+ return [
324
+ step
325
+ for step in self.steps
326
+ if not step.has_passed() and step.actor == ACTOR_USER
327
+ ]
328
+
115
329
 
116
330
  # Update forward references
117
331
  DialogueUnderstandingTestStep.model_rebuild()