rasa-pro 3.11.5__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 (559) 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 +135 -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/{arc-f0f8bd46.js → arc-9f1365dc.js} +1 -1
  70. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7162c77d.js → blockDiagram-38ab4fdb-e0f81b12.js} +1 -1
  71. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-b1d0d098.js → c4Diagram-3d4e48cf-9deaee1c.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/channel-44956714.js +1 -0
  73. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-807a1b27.js → classDiagram-70f12bd4-20450a96.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-5238dcdb.js → classDiagram-v2-f2320105-749d2abf.js} +1 -1
  75. rasa/core/channels/inspector/dist/assets/clone-a9475142.js +1 -0
  76. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-75dfaa67.js → createText-2e5e7dd3-bef0b38c.js} +1 -1
  77. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-df20501d.js → edges-e0da2a9e-943801a7.js} +1 -1
  78. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-13cf4797.js → erDiagram-9861fffd-d523a948.js} +1 -1
  79. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-a4991264.js → flowDb-956e92f1-54e4cf19.js} +1 -1
  80. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-ccecf773.js → flowDiagram-66a62f08-48bfbbe8.js} +1 -1
  81. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-43fa749a.js +1 -0
  82. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b5801783.js → flowchart-elk-definition-4a651766-17c30827.js} +1 -1
  83. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-161e079a.js → ganttDiagram-c361ad54-43086f2d.js} +1 -1
  84. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-f38e86a4.js → gitGraphDiagram-72cf32ee-5c8b693e.js} +1 -1
  85. rasa/core/channels/inspector/dist/assets/{graph-be6ef5d8.js → graph-41a90d26.js} +1 -1
  86. rasa/core/channels/inspector/dist/assets/{index-3862675e-d9ce8994.js → index-3862675e-b43eeae9.js} +1 -1
  87. rasa/core/channels/inspector/dist/assets/{index-7794b245.js → index-e8affe45.js} +155 -155
  88. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-5000a3dc.js → infoDiagram-f8f76790-0b20676b.js} +1 -1
  89. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-8ef0a17a.js → journeyDiagram-49397b02-39bce7b5.js} +1 -1
  90. rasa/core/channels/inspector/dist/assets/{layout-d649bc98.js → layout-dc8eeea4.js} +1 -1
  91. rasa/core/channels/inspector/dist/assets/{line-95add810.js → line-c4d2e756.js} +1 -1
  92. rasa/core/channels/inspector/dist/assets/{linear-f6025094.js → linear-86f6f2d9.js} +1 -1
  93. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-2e8531c4.js → mindmap-definition-fc14e90a-4216f771.js} +1 -1
  94. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-918adfdb.js → pieDiagram-8a3498a8-1a0cfa96.js} +1 -1
  95. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-cbd01797.js → quadrantDiagram-120e2f19-f91e67cf.js} +1 -1
  96. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-6a8b877b.js → requirementDiagram-deff3bca-d4046bed.js} +1 -1
  97. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-c377c3fe.js → sankeyDiagram-04a897e0-2cf6d1d7.js} +1 -1
  98. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-ab9e9b7f.js → sequenceDiagram-704730f1-751ac4f5.js} +1 -1
  99. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-5e6ae67d.js → stateDiagram-587899a1-f734f4d4.js} +1 -1
  100. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-40643476.js → stateDiagram-v2-d93cdb3a-91c65710.js} +1 -1
  101. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-afb8d108.js → styles-6aaf32cf-e0cff7be.js} +1 -1
  102. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-7edc9423.js → styles-9a916d00-c8029e5d.js} +1 -1
  103. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-c1d8f7e9.js → styles-c10674c1-114f312a.js} +1 -1
  104. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f494b2ef.js → svgDrawCommon-08f97a94-b7b9dc00.js} +1 -1
  105. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-11c7cdd0.js → timeline-definition-85554ec2-9536d189.js} +1 -1
  106. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-3f191ec1.js → xychartDiagram-e933f94c-bf3b0f36.js} +1 -1
  107. rasa/core/channels/inspector/dist/index.html +1 -1
  108. rasa/core/channels/inspector/package.json +1 -0
  109. rasa/core/channels/inspector/src/App.tsx +15 -2
  110. rasa/core/channels/inspector/src/components/RasaLogo.tsx +31 -0
  111. rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +68 -0
  112. rasa/core/channels/inspector/src/components/Welcome.tsx +19 -13
  113. rasa/core/channels/inspector/yarn.lock +5 -0
  114. rasa/core/channels/mattermost.py +4 -4
  115. rasa/core/channels/rasa_chat.py +4 -4
  116. rasa/core/channels/rest.py +11 -12
  117. rasa/core/channels/rocketchat.py +4 -3
  118. rasa/core/channels/slack.py +6 -5
  119. rasa/core/channels/socketio.py +8 -28
  120. rasa/core/channels/studio_chat.py +212 -0
  121. rasa/core/channels/telegram.py +105 -55
  122. rasa/core/channels/twilio.py +3 -3
  123. rasa/core/channels/vier_cvg.py +2 -2
  124. rasa/core/channels/voice_ready/audiocodes.py +9 -9
  125. rasa/core/channels/voice_ready/jambonz.py +5 -5
  126. rasa/core/channels/voice_ready/jambonz_protocol.py +3 -4
  127. rasa/core/channels/voice_ready/twilio_voice.py +9 -8
  128. rasa/core/channels/voice_ready/utils.py +2 -2
  129. rasa/core/channels/voice_stream/asr/asr_engine.py +12 -6
  130. rasa/core/channels/voice_stream/asr/asr_event.py +5 -0
  131. rasa/core/channels/voice_stream/asr/azure.py +16 -3
  132. rasa/core/channels/voice_stream/asr/deepgram.py +76 -19
  133. rasa/core/channels/voice_stream/audiocodes.py +292 -0
  134. rasa/core/channels/voice_stream/browser_audio.py +14 -7
  135. rasa/core/channels/voice_stream/call_state.py +6 -2
  136. rasa/core/channels/voice_stream/genesys.py +320 -0
  137. rasa/core/channels/voice_stream/tts/azure.py +13 -5
  138. rasa/core/channels/voice_stream/tts/cartesia.py +34 -14
  139. rasa/core/channels/voice_stream/tts/tts_cache.py +3 -2
  140. rasa/core/channels/voice_stream/tts/tts_engine.py +1 -1
  141. rasa/core/channels/voice_stream/twilio_media_streams.py +12 -8
  142. rasa/core/channels/voice_stream/util.py +1 -1
  143. rasa/core/channels/voice_stream/voice_channel.py +100 -56
  144. rasa/core/channels/webexteams.py +3 -4
  145. rasa/core/constants.py +2 -0
  146. rasa/core/evaluation/marker.py +7 -6
  147. rasa/core/evaluation/marker_base.py +15 -16
  148. rasa/core/evaluation/marker_stats.py +3 -4
  149. rasa/core/evaluation/marker_tracker_loader.py +5 -4
  150. rasa/core/exporter.py +4 -4
  151. rasa/core/featurizers/precomputation.py +8 -8
  152. rasa/core/featurizers/single_state_featurizer.py +7 -7
  153. rasa/core/featurizers/tracker_featurizers.py +13 -13
  154. rasa/core/http_interpreter.py +3 -4
  155. rasa/core/information_retrieval/__init__.py +1 -1
  156. rasa/core/information_retrieval/faiss.py +4 -4
  157. rasa/core/information_retrieval/information_retrieval.py +2 -2
  158. rasa/core/information_retrieval/milvus.py +3 -3
  159. rasa/core/information_retrieval/qdrant.py +3 -3
  160. rasa/core/jobs.py +1 -0
  161. rasa/core/lock.py +2 -3
  162. rasa/core/lock_store.py +3 -3
  163. rasa/core/migrate.py +12 -9
  164. rasa/core/nlg/__init__.py +1 -1
  165. rasa/core/nlg/callback.py +2 -3
  166. rasa/core/nlg/contextual_response_rephraser.py +82 -14
  167. rasa/core/nlg/generator.py +85 -17
  168. rasa/core/nlg/interpolator.py +4 -3
  169. rasa/core/nlg/response.py +9 -7
  170. rasa/core/nlg/summarize.py +1 -0
  171. rasa/core/nlg/translate.py +55 -0
  172. rasa/core/persistor.py +3 -3
  173. rasa/core/policies/ensemble.py +10 -9
  174. rasa/core/policies/enterprise_search_policy.py +87 -21
  175. rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +1 -1
  176. rasa/core/policies/flow_policy.py +13 -14
  177. rasa/core/policies/flows/flow_executor.py +85 -55
  178. rasa/core/policies/intentless_policy.py +6 -7
  179. rasa/core/policies/memoization.py +22 -20
  180. rasa/core/policies/policy.py +24 -22
  181. rasa/core/policies/rule_policy.py +37 -36
  182. rasa/core/policies/ted_policy.py +87 -85
  183. rasa/core/policies/unexpected_intent_policy.py +77 -75
  184. rasa/core/processor.py +167 -74
  185. rasa/core/run.py +5 -4
  186. rasa/core/secrets_manager/endpoints.py +2 -3
  187. rasa/core/secrets_manager/factory.py +2 -3
  188. rasa/core/secrets_manager/secret_manager.py +2 -3
  189. rasa/core/secrets_manager/vault.py +2 -2
  190. rasa/core/test.py +30 -30
  191. rasa/core/tracker_store.py +138 -49
  192. rasa/core/train.py +1 -1
  193. rasa/core/training/__init__.py +2 -2
  194. rasa/core/training/converters/responses_prefix_converter.py +1 -2
  195. rasa/core/training/interactive.py +13 -13
  196. rasa/core/training/story_conflict.py +4 -5
  197. rasa/core/training/training.py +3 -5
  198. rasa/core/utils.py +5 -5
  199. rasa/core/visualize.py +1 -1
  200. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -2
  201. rasa/dialogue_understanding/coexistence/llm_based_router.py +5 -5
  202. rasa/dialogue_understanding/commands/__init__.py +22 -22
  203. rasa/dialogue_understanding/commands/can_not_handle_command.py +38 -1
  204. rasa/dialogue_understanding/commands/cancel_flow_command.py +96 -9
  205. rasa/dialogue_understanding/commands/change_flow_command.py +36 -2
  206. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +36 -4
  207. rasa/dialogue_understanding/commands/clarify_command.py +46 -4
  208. rasa/dialogue_understanding/commands/command.py +3 -2
  209. rasa/dialogue_understanding/commands/command_syntax_manager.py +55 -0
  210. rasa/dialogue_understanding/commands/correct_slots_command.py +14 -5
  211. rasa/dialogue_understanding/commands/error_command.py +1 -1
  212. rasa/dialogue_understanding/commands/free_form_answer_command.py +2 -1
  213. rasa/dialogue_understanding/commands/handle_code_change_command.py +2 -2
  214. rasa/dialogue_understanding/commands/handle_digressions_command.py +144 -0
  215. rasa/dialogue_understanding/commands/human_handoff_command.py +34 -4
  216. rasa/dialogue_understanding/commands/knowledge_answer_command.py +36 -4
  217. rasa/dialogue_understanding/commands/noop_command.py +2 -1
  218. rasa/dialogue_understanding/commands/prompt_command.py +94 -0
  219. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +34 -4
  220. rasa/dialogue_understanding/commands/restart_command.py +2 -5
  221. rasa/dialogue_understanding/commands/session_end_command.py +3 -5
  222. rasa/dialogue_understanding/commands/session_start_command.py +3 -5
  223. rasa/dialogue_understanding/commands/set_slot_command.py +55 -16
  224. rasa/dialogue_understanding/commands/skip_question_command.py +34 -4
  225. rasa/dialogue_understanding/commands/start_flow_command.py +78 -2
  226. rasa/dialogue_understanding/commands/user_silence_command.py +3 -5
  227. rasa/dialogue_understanding/commands/utils.py +126 -43
  228. rasa/dialogue_understanding/constants.py +2 -0
  229. rasa/dialogue_understanding/generator/__init__.py +2 -0
  230. rasa/dialogue_understanding/generator/command_generator.py +120 -79
  231. rasa/dialogue_understanding/generator/command_parser.py +245 -0
  232. rasa/dialogue_understanding/generator/constants.py +12 -4
  233. rasa/dialogue_understanding/generator/flow_retrieval.py +7 -7
  234. rasa/dialogue_understanding/generator/llm_based_command_generator.py +187 -59
  235. rasa/dialogue_understanding/generator/llm_command_generator.py +6 -3
  236. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +106 -110
  237. rasa/dialogue_understanding/generator/nlu_command_adapter.py +53 -11
  238. rasa/dialogue_understanding/generator/prompt_templates/__init__.py +0 -0
  239. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +58 -0
  240. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +57 -0
  241. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +574 -0
  242. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +41 -386
  243. rasa/dialogue_understanding/generator/utils.py +76 -0
  244. rasa/dialogue_understanding/patterns/cancel.py +2 -1
  245. rasa/dialogue_understanding/patterns/cannot_handle.py +1 -0
  246. rasa/dialogue_understanding/patterns/chitchat.py +1 -1
  247. rasa/dialogue_understanding/patterns/clarify.py +2 -1
  248. rasa/dialogue_understanding/patterns/code_change.py +2 -0
  249. rasa/dialogue_understanding/patterns/collect_information.py +7 -4
  250. rasa/dialogue_understanding/patterns/completed.py +1 -1
  251. rasa/dialogue_understanding/patterns/continue_interrupted.py +1 -1
  252. rasa/dialogue_understanding/patterns/correction.py +17 -3
  253. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +78 -2
  254. rasa/dialogue_understanding/patterns/handle_digressions.py +81 -0
  255. rasa/dialogue_understanding/patterns/human_handoff.py +1 -1
  256. rasa/dialogue_understanding/patterns/internal_error.py +1 -0
  257. rasa/dialogue_understanding/patterns/search.py +1 -1
  258. rasa/dialogue_understanding/patterns/session_start.py +1 -1
  259. rasa/dialogue_understanding/patterns/skip_question.py +1 -0
  260. rasa/dialogue_understanding/patterns/user_silence.py +1 -1
  261. rasa/dialogue_understanding/patterns/validate_slot.py +65 -0
  262. rasa/dialogue_understanding/processor/command_processor.py +193 -43
  263. rasa/dialogue_understanding/processor/command_processor_component.py +1 -1
  264. rasa/dialogue_understanding/stack/dialogue_stack.py +4 -3
  265. rasa/dialogue_understanding/stack/frames/__init__.py +2 -2
  266. rasa/dialogue_understanding/stack/frames/chit_chat_frame.py +4 -1
  267. rasa/dialogue_understanding/stack/frames/dialogue_stack_frame.py +2 -3
  268. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +5 -2
  269. rasa/dialogue_understanding/stack/frames/search_frame.py +4 -1
  270. rasa/dialogue_understanding/stack/utils.py +56 -10
  271. rasa/dialogue_understanding/utils.py +164 -0
  272. rasa/dialogue_understanding_test/README.md +429 -0
  273. rasa/dialogue_understanding_test/__init__.py +0 -0
  274. rasa/dialogue_understanding_test/command_comparison.py +60 -0
  275. rasa/dialogue_understanding_test/command_metric_calculation.py +122 -0
  276. rasa/dialogue_understanding_test/constants.py +22 -0
  277. rasa/dialogue_understanding_test/du_test_case.py +448 -0
  278. rasa/dialogue_understanding_test/du_test_result.py +390 -0
  279. rasa/dialogue_understanding_test/du_test_runner.py +322 -0
  280. rasa/dialogue_understanding_test/du_test_schema.yml +161 -0
  281. rasa/dialogue_understanding_test/io.py +443 -0
  282. rasa/dialogue_understanding_test/test_case_simulation/__init__.py +0 -0
  283. rasa/dialogue_understanding_test/test_case_simulation/exception.py +28 -0
  284. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +336 -0
  285. rasa/dialogue_understanding_test/utils.py +70 -0
  286. rasa/dialogue_understanding_test/validation.py +77 -0
  287. rasa/e2e_test/aggregate_test_stats_calculator.py +1 -1
  288. rasa/e2e_test/assertions.py +202 -175
  289. rasa/e2e_test/assertions_schema.yml +6 -0
  290. rasa/e2e_test/constants.py +16 -1
  291. rasa/e2e_test/e2e_config.py +102 -41
  292. rasa/e2e_test/e2e_config_schema.yml +28 -10
  293. rasa/e2e_test/e2e_test_case.py +5 -5
  294. rasa/e2e_test/e2e_test_converter.py +2 -3
  295. rasa/e2e_test/e2e_test_coverage_report.py +6 -6
  296. rasa/e2e_test/e2e_test_result.py +1 -1
  297. rasa/e2e_test/e2e_test_runner.py +143 -38
  298. rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2 +93 -0
  299. rasa/e2e_test/llm_judge_prompts/groundedness_prompt_template.jinja2 +169 -0
  300. rasa/e2e_test/stub_custom_action.py +1 -1
  301. rasa/e2e_test/utils/generative_assertions.py +243 -0
  302. rasa/e2e_test/utils/io.py +123 -93
  303. rasa/e2e_test/utils/validation.py +101 -3
  304. rasa/engine/caching.py +5 -7
  305. rasa/engine/constants.py +1 -1
  306. rasa/engine/graph.py +3 -2
  307. rasa/engine/language.py +182 -0
  308. rasa/engine/recipes/config_files/default_config.yml +4 -0
  309. rasa/engine/recipes/default_components.py +13 -15
  310. rasa/engine/recipes/default_recipe.py +65 -49
  311. rasa/engine/recipes/graph_recipe.py +10 -7
  312. rasa/engine/recipes/recipe.py +2 -2
  313. rasa/engine/runner/dask.py +2 -2
  314. rasa/engine/runner/interface.py +1 -0
  315. rasa/engine/storage/local_model_storage.py +6 -4
  316. rasa/engine/storage/resource.py +2 -1
  317. rasa/engine/storage/storage.py +8 -3
  318. rasa/engine/training/components.py +2 -1
  319. rasa/engine/training/fingerprinting.py +4 -2
  320. rasa/engine/training/graph_trainer.py +4 -4
  321. rasa/engine/training/hooks.py +2 -2
  322. rasa/engine/validation.py +36 -33
  323. rasa/exceptions.py +3 -2
  324. rasa/graph_components/converters/nlu_message_converter.py +3 -3
  325. rasa/graph_components/providers/domain_for_core_training_provider.py +3 -3
  326. rasa/graph_components/providers/domain_provider.py +3 -2
  327. rasa/graph_components/providers/flows_provider.py +2 -3
  328. rasa/graph_components/providers/forms_provider.py +4 -4
  329. rasa/graph_components/providers/nlu_training_data_provider.py +5 -3
  330. rasa/graph_components/providers/responses_provider.py +4 -4
  331. rasa/graph_components/providers/rule_only_provider.py +3 -2
  332. rasa/graph_components/providers/story_graph_provider.py +8 -8
  333. rasa/graph_components/providers/training_tracker_provider.py +3 -2
  334. rasa/graph_components/validators/default_recipe_validator.py +16 -16
  335. rasa/graph_components/validators/finetuning_validator.py +10 -8
  336. rasa/hooks.py +19 -14
  337. rasa/jupyter.py +2 -2
  338. rasa/llm_fine_tuning/annotation_module.py +4 -4
  339. rasa/llm_fine_tuning/conversations.py +5 -33
  340. rasa/llm_fine_tuning/llm_data_preparation_module.py +6 -4
  341. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +4 -4
  342. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +18 -13
  343. rasa/llm_fine_tuning/paraphrasing_module.py +6 -2
  344. rasa/llm_fine_tuning/storage.py +3 -3
  345. rasa/llm_fine_tuning/train_test_split_module.py +27 -27
  346. rasa/llm_fine_tuning/utils.py +7 -0
  347. rasa/markers/marker.py +2 -3
  348. rasa/markers/marker_base.py +1 -2
  349. rasa/markers/upload.py +2 -2
  350. rasa/markers/validate.py +2 -3
  351. rasa/model.py +3 -5
  352. rasa/model_manager/config.py +1 -1
  353. rasa/model_manager/model_api.py +5 -4
  354. rasa/model_manager/runner_service.py +13 -10
  355. rasa/model_manager/socket_bridge.py +15 -9
  356. rasa/model_manager/studio_jwt_auth.py +1 -0
  357. rasa/model_manager/trainer_service.py +9 -7
  358. rasa/model_manager/utils.py +1 -1
  359. rasa/model_manager/warm_rasa_process.py +14 -9
  360. rasa/model_service.py +5 -6
  361. rasa/model_testing.py +13 -15
  362. rasa/model_training.py +29 -29
  363. rasa/nlu/classifiers/diet_classifier.py +72 -73
  364. rasa/nlu/classifiers/fallback_classifier.py +9 -8
  365. rasa/nlu/classifiers/keyword_intent_classifier.py +7 -6
  366. rasa/nlu/classifiers/logistic_regression_classifier.py +3 -3
  367. rasa/nlu/classifiers/mitie_intent_classifier.py +5 -4
  368. rasa/nlu/classifiers/regex_message_handler.py +3 -2
  369. rasa/nlu/classifiers/sklearn_intent_classifier.py +2 -2
  370. rasa/nlu/convert.py +2 -2
  371. rasa/nlu/emulators/dialogflow.py +3 -3
  372. rasa/nlu/emulators/luis.py +5 -5
  373. rasa/nlu/emulators/no_emulator.py +1 -0
  374. rasa/nlu/emulators/wit.py +4 -4
  375. rasa/nlu/extractors/crf_entity_extractor.py +11 -11
  376. rasa/nlu/extractors/duckling_entity_extractor.py +7 -6
  377. rasa/nlu/extractors/entity_synonyms.py +10 -9
  378. rasa/nlu/extractors/extractor.py +16 -16
  379. rasa/nlu/extractors/mitie_entity_extractor.py +10 -9
  380. rasa/nlu/extractors/regex_entity_extractor.py +11 -10
  381. rasa/nlu/extractors/spacy_entity_extractor.py +2 -2
  382. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +15 -14
  383. rasa/nlu/featurizers/dense_featurizer/dense_featurizer.py +2 -1
  384. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +10 -9
  385. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +9 -7
  386. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +13 -12
  387. rasa/nlu/featurizers/featurizer.py +5 -4
  388. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +6 -6
  389. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -4
  390. rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +4 -4
  391. rasa/nlu/featurizers/sparse_featurizer/sparse_featurizer.py +2 -0
  392. rasa/nlu/model.py +0 -1
  393. rasa/nlu/selectors/response_selector.py +67 -68
  394. rasa/nlu/test.py +38 -38
  395. rasa/nlu/tokenizers/jieba_tokenizer.py +1 -2
  396. rasa/nlu/tokenizers/mitie_tokenizer.py +2 -2
  397. rasa/nlu/tokenizers/spacy_tokenizer.py +3 -3
  398. rasa/nlu/tokenizers/tokenizer.py +6 -7
  399. rasa/nlu/tokenizers/whitespace_tokenizer.py +1 -1
  400. rasa/nlu/utils/bilou_utils.py +7 -7
  401. rasa/nlu/utils/hugging_face/registry.py +22 -22
  402. rasa/nlu/utils/hugging_face/transformers_pre_post_processors.py +2 -1
  403. rasa/nlu/utils/mitie_utils.py +2 -1
  404. rasa/nlu/utils/pattern_utils.py +1 -1
  405. rasa/nlu/utils/spacy_utils.py +3 -3
  406. rasa/plugin.py +12 -1
  407. rasa/server.py +3 -2
  408. rasa/shared/constants.py +45 -18
  409. rasa/shared/core/command_payload_reader.py +15 -7
  410. rasa/shared/core/constants.py +34 -4
  411. rasa/shared/core/conversation.py +1 -2
  412. rasa/shared/core/domain.py +19 -20
  413. rasa/shared/core/events.py +60 -39
  414. rasa/shared/core/flows/__init__.py +0 -1
  415. rasa/shared/core/flows/constants.py +11 -0
  416. rasa/shared/core/flows/flow.py +107 -26
  417. rasa/shared/core/flows/flow_step.py +4 -3
  418. rasa/shared/core/flows/flow_step_links.py +1 -2
  419. rasa/shared/core/flows/flow_step_sequence.py +1 -1
  420. rasa/shared/core/flows/flows_list.py +3 -3
  421. rasa/shared/core/flows/flows_yaml_schema.json +69 -3
  422. rasa/shared/core/flows/nlu_trigger.py +1 -1
  423. rasa/shared/core/flows/steps/__init__.py +2 -2
  424. rasa/shared/core/flows/steps/action.py +1 -1
  425. rasa/shared/core/flows/steps/call.py +1 -1
  426. rasa/shared/core/flows/steps/collect.py +22 -40
  427. rasa/shared/core/flows/steps/internal.py +1 -1
  428. rasa/shared/core/flows/steps/link.py +1 -1
  429. rasa/shared/core/flows/steps/no_operation.py +2 -2
  430. rasa/shared/core/flows/steps/set_slots.py +1 -1
  431. rasa/shared/core/flows/utils.py +44 -4
  432. rasa/shared/core/flows/validation.py +4 -6
  433. rasa/shared/core/generator.py +20 -21
  434. rasa/shared/core/slot_mappings.py +360 -121
  435. rasa/shared/core/slots.py +163 -6
  436. rasa/shared/core/trackers.py +108 -33
  437. rasa/shared/core/training_data/loading.py +1 -1
  438. rasa/shared/core/training_data/story_reader/story_reader.py +3 -3
  439. rasa/shared/core/training_data/story_reader/story_step_builder.py +4 -4
  440. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +29 -31
  441. rasa/shared/core/training_data/story_writer/yaml_story_writer.py +22 -24
  442. rasa/shared/core/training_data/structures.py +11 -12
  443. rasa/shared/core/training_data/visualization.py +10 -10
  444. rasa/shared/data.py +6 -6
  445. rasa/shared/engine/caching.py +0 -1
  446. rasa/shared/exceptions.py +2 -2
  447. rasa/shared/importers/importer.py +58 -2
  448. rasa/shared/importers/rasa.py +5 -6
  449. rasa/shared/importers/utils.py +1 -1
  450. rasa/shared/nlu/constants.py +9 -0
  451. rasa/shared/nlu/training_data/entities_parser.py +6 -6
  452. rasa/shared/nlu/training_data/features.py +3 -3
  453. rasa/shared/nlu/training_data/formats/__init__.py +1 -1
  454. rasa/shared/nlu/training_data/formats/dialogflow.py +4 -5
  455. rasa/shared/nlu/training_data/formats/luis.py +7 -8
  456. rasa/shared/nlu/training_data/formats/rasa.py +4 -5
  457. rasa/shared/nlu/training_data/formats/rasa_yaml.py +17 -16
  458. rasa/shared/nlu/training_data/formats/readerwriter.py +8 -11
  459. rasa/shared/nlu/training_data/formats/wit.py +3 -4
  460. rasa/shared/nlu/training_data/loading.py +4 -4
  461. rasa/shared/nlu/training_data/lookup_tables_parser.py +1 -1
  462. rasa/shared/nlu/training_data/message.py +13 -14
  463. rasa/shared/nlu/training_data/schemas/data_schema.py +1 -1
  464. rasa/shared/nlu/training_data/schemas/responses.yml +19 -11
  465. rasa/shared/nlu/training_data/synonyms_parser.py +3 -3
  466. rasa/shared/nlu/training_data/training_data.py +12 -13
  467. rasa/shared/nlu/training_data/util.py +11 -10
  468. rasa/shared/providers/_configs/azure_entra_id_config.py +541 -0
  469. rasa/shared/providers/_configs/azure_openai_client_config.py +150 -15
  470. rasa/shared/providers/_configs/client_config.py +3 -1
  471. rasa/shared/providers/_configs/default_litellm_client_config.py +9 -7
  472. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +13 -11
  473. rasa/shared/providers/_configs/litellm_router_client_config.py +12 -10
  474. rasa/shared/providers/_configs/model_group_config.py +8 -5
  475. rasa/shared/providers/_configs/oauth_config.py +33 -0
  476. rasa/shared/providers/_configs/openai_client_config.py +14 -12
  477. rasa/shared/providers/_configs/rasa_llm_client_config.py +5 -3
  478. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +12 -11
  479. rasa/shared/providers/_configs/utils.py +1 -0
  480. rasa/shared/providers/_ssl_verification_utils.py +5 -6
  481. rasa/shared/providers/_utils.py +5 -5
  482. rasa/shared/providers/constants.py +6 -0
  483. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +1 -1
  484. rasa/shared/providers/embedding/azure_openai_embedding_client.py +32 -7
  485. rasa/shared/providers/embedding/embedding_client.py +1 -1
  486. rasa/shared/providers/embedding/litellm_router_embedding_client.py +5 -2
  487. rasa/shared/providers/llm/_base_litellm_client.py +43 -18
  488. rasa/shared/providers/llm/azure_openai_llm_client.py +90 -34
  489. rasa/shared/providers/llm/default_litellm_llm_client.py +4 -2
  490. rasa/shared/providers/llm/litellm_router_llm_client.py +32 -9
  491. rasa/shared/providers/llm/llm_client.py +24 -8
  492. rasa/shared/providers/llm/llm_response.py +61 -2
  493. rasa/shared/providers/llm/openai_llm_client.py +11 -5
  494. rasa/shared/providers/llm/rasa_llm_client.py +17 -14
  495. rasa/shared/providers/llm/self_hosted_llm_client.py +35 -15
  496. rasa/shared/providers/mappings.py +18 -19
  497. rasa/shared/providers/router/_base_litellm_router_client.py +48 -15
  498. rasa/shared/providers/router/router_client.py +3 -1
  499. rasa/shared/utils/cli.py +1 -1
  500. rasa/shared/utils/common.py +15 -1
  501. rasa/shared/utils/constants.py +3 -0
  502. rasa/shared/utils/health_check/embeddings_health_check_mixin.py +1 -1
  503. rasa/shared/utils/health_check/health_check.py +3 -3
  504. rasa/shared/utils/health_check/llm_health_check_mixin.py +1 -1
  505. rasa/shared/utils/io.py +1 -1
  506. rasa/shared/utils/llm.py +100 -18
  507. rasa/shared/utils/pykwalify_extensions.py +25 -1
  508. rasa/shared/utils/schemas/domain.yml +26 -1
  509. rasa/shared/utils/schemas/events.py +1 -1
  510. rasa/shared/utils/yaml.py +24 -20
  511. rasa/studio/auth.py +3 -3
  512. rasa/studio/config.py +1 -2
  513. rasa/studio/data_handler.py +3 -3
  514. rasa/studio/download.py +1 -1
  515. rasa/studio/results_logger.py +3 -3
  516. rasa/studio/upload.py +21 -5
  517. rasa/telemetry.py +127 -48
  518. rasa/tracing/config.py +5 -3
  519. rasa/tracing/constants.py +12 -0
  520. rasa/tracing/instrumentation/attribute_extractors.py +92 -14
  521. rasa/tracing/instrumentation/instrumentation.py +61 -5
  522. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +1 -1
  523. rasa/tracing/instrumentation/metrics.py +52 -11
  524. rasa/tracing/metric_instrument_provider.py +54 -14
  525. rasa/utils/common.py +12 -24
  526. rasa/utils/endpoints.py +1 -1
  527. rasa/utils/io.py +7 -7
  528. rasa/utils/licensing.py +3 -4
  529. rasa/utils/log_utils.py +7 -6
  530. rasa/utils/ml_utils.py +1 -0
  531. rasa/utils/plotting.py +3 -3
  532. rasa/utils/sanic_error_handler.py +1 -1
  533. rasa/utils/tensorflow/callback.py +2 -2
  534. rasa/utils/tensorflow/crf.py +2 -2
  535. rasa/utils/tensorflow/data_generator.py +5 -5
  536. rasa/utils/tensorflow/environment.py +3 -3
  537. rasa/utils/tensorflow/feature_array.py +2 -3
  538. rasa/utils/tensorflow/layers.py +18 -12
  539. rasa/utils/tensorflow/layers_utils.py +2 -1
  540. rasa/utils/tensorflow/metrics.py +2 -2
  541. rasa/utils/tensorflow/model_data.py +7 -7
  542. rasa/utils/tensorflow/model_data_utils.py +10 -9
  543. rasa/utils/tensorflow/models.py +31 -32
  544. rasa/utils/tensorflow/rasa_layers.py +20 -19
  545. rasa/utils/tensorflow/types.py +2 -1
  546. rasa/utils/train_utils.py +23 -21
  547. rasa/utils/url_tools.py +1 -1
  548. rasa/validator.py +594 -115
  549. rasa/version.py +1 -1
  550. {rasa_pro-3.11.5.dist-info → rasa_pro-3.12.0.dist-info}/METADATA +23 -26
  551. rasa_pro-3.12.0.dist-info/RECORD +829 -0
  552. rasa/core/channels/inspector/dist/assets/channel-e265ea59.js +0 -1
  553. rasa/core/channels/inspector/dist/assets/clone-21f8a43d.js +0 -1
  554. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-5c8ce12d.js +0 -1
  555. rasa_pro-3.11.5.dist-info/RECORD +0 -785
  556. /rasa/dialogue_understanding/generator/{single_step → prompt_templates}/command_prompt_template.jinja2 +0 -0
  557. {rasa_pro-3.11.5.dist-info → rasa_pro-3.12.0.dist-info}/NOTICE +0 -0
  558. {rasa_pro-3.11.5.dist-info → rasa_pro-3.12.0.dist-info}/WHEEL +0 -0
  559. {rasa_pro-3.11.5.dist-info → rasa_pro-3.12.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,122 @@
1
+ from collections import defaultdict
2
+ from typing import Dict, List
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
+ )
10
+ from rasa.dialogue_understanding_test.du_test_result import (
11
+ DialogueUnderstandingTestResult,
12
+ )
13
+
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
+
50
+ def calculate_command_metrics(
51
+ test_results: List[DialogueUnderstandingTestResult],
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 _get_command_name(command: Command) -> str:
83
+ return command.command().replace(" ", "_")
84
+
85
+
86
+ def _increase_total_count(
87
+ commands: List[Command],
88
+ metrics: Dict[str, CommandMetrics],
89
+ ) -> None:
90
+ for command in commands:
91
+ metrics[_get_command_name(command)].total_count += 1
92
+
93
+
94
+ def _increase_tp(
95
+ commands: List[Command],
96
+ metrics: Dict[str, CommandMetrics],
97
+ ) -> None:
98
+ for command in commands:
99
+ metrics[_get_command_name(command)].tp += 1
100
+
101
+
102
+ def _update_metrics_true_positive_and_false_negative(
103
+ expected_commands: List[Command],
104
+ predicted_commands: List[Command],
105
+ metrics: Dict[str, CommandMetrics],
106
+ ) -> None:
107
+ for expected_command in expected_commands:
108
+ command_name = _get_command_name(expected_command)
109
+ if is_command_present_in_list(expected_command, predicted_commands):
110
+ metrics[command_name].tp += 1
111
+ else:
112
+ metrics[command_name].fn += 1
113
+
114
+
115
+ def _update_metrics_false_positive(
116
+ expected_commands: List[Command],
117
+ predicted_commands: List[Command],
118
+ metrics: Dict[str, CommandMetrics],
119
+ ) -> None:
120
+ for predicted_command in predicted_commands:
121
+ if not is_command_present_in_list(predicted_command, expected_commands):
122
+ metrics[_get_command_name(predicted_command)].fp += 1
@@ -0,0 +1,22 @@
1
+ import rasa.e2e_test.constants as constants
2
+
3
+ KEY_FIXTURES = constants.KEY_FIXTURES
4
+ KEY_METADATA = constants.KEY_METADATA
5
+ KEY_STUB_CUSTOM_ACTIONS = constants.KEY_STUB_CUSTOM_ACTIONS
6
+ KEY_USER_INPUT = constants.KEY_USER_INPUT
7
+ KEY_BOT_INPUT = constants.KEY_BOT_INPUT
8
+ KEY_BOT_UTTERED = constants.KEY_BOT_UTTERED
9
+ KEY_STEPS = constants.KEY_STEPS
10
+ KEY_TEST_CASE = constants.KEY_TEST_CASE
11
+ KEY_TEST_CASES = constants.KEY_TEST_CASES
12
+ KEY_COMMANDS = "commands"
13
+ KEY_ADDITIONAL_COMMANDS = "additional_commands"
14
+ KEY_REMOVE_DEFAULT_COMMANDS = "remove_default_commands"
15
+
16
+ ACTOR_USER = "user"
17
+ ACTOR_BOT = "bot"
18
+
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"
@@ -0,0 +1,448 @@
1
+ from typing import Any, Dict, Iterator, List, Optional, Tuple
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from rasa.dialogue_understanding.commands.prompt_command import PromptCommand
6
+ from rasa.dialogue_understanding.generator.command_parser import parse_commands
7
+ from rasa.dialogue_understanding_test.command_comparison import are_command_lists_equal
8
+ from rasa.dialogue_understanding_test.constants import (
9
+ ACTOR_BOT,
10
+ ACTOR_USER,
11
+ KEY_BOT_INPUT,
12
+ KEY_BOT_UTTERED,
13
+ KEY_COMMANDS,
14
+ KEY_FIXTURES,
15
+ KEY_METADATA,
16
+ KEY_STEPS,
17
+ KEY_TEST_CASE,
18
+ KEY_USER_INPUT,
19
+ )
20
+ from rasa.shared.core.flows import FlowsList
21
+ from rasa.shared.nlu.constants import (
22
+ KEY_COMPONENT_NAME,
23
+ KEY_LATENCY,
24
+ KEY_LLM_RESPONSE_METADATA,
25
+ KEY_PROMPT_NAME,
26
+ KEY_SYSTEM_PROMPT,
27
+ KEY_USER_PROMPT,
28
+ )
29
+
30
+ KEY_USAGE = "usage"
31
+ KEY_PROMPT_TOKENS = "prompt_tokens"
32
+ KEY_COMPLETION_TOKENS = "completion_tokens"
33
+ KEY_CHOICES = "choices"
34
+
35
+
36
+ class DialogueUnderstandingOutput(BaseModel):
37
+ """Output containing prompts and generated commands by component.
38
+
39
+ Example of commands:
40
+ {
41
+ "MultiStepLLMCommandGenerator": [
42
+ SetSlotCommand(name="slot_name", value="slot_value"),
43
+ ],
44
+ "NLUCommandAdapter": [
45
+ StartFlowCommand("test_flow"),
46
+ ]
47
+ }
48
+
49
+ Example of prompts:
50
+ [
51
+ {
52
+ "component_name": "MultiStepLLMCommandGenerator",
53
+ "prompt_name": "fill_slots_prompt",
54
+ "user_prompt": "...",
55
+ "system_prompt": "...",
56
+ "llm_response_metadata": { ... }
57
+ },
58
+ {
59
+ "component_name": "MultiStepLLMCommandGenerator",
60
+ "prompt_name": "handle_flows_prompt",
61
+ "user_prompt": "...",
62
+ "system_prompt": "...",
63
+ "llm_response_metadata": { ... }
64
+ },
65
+ ]
66
+ """
67
+
68
+ # Dict with component name as key and list of commands as value
69
+ commands: Dict[str, List[PromptCommand]]
70
+ # List of prompts
71
+ prompts: Optional[List[Dict[str, Any]]] = None
72
+
73
+ class Config:
74
+ """Skip validation for PromptCommand protocol as pydantic does not know how to
75
+ serialize or handle instances of a protocol.
76
+ """
77
+
78
+ arbitrary_types_allowed = True
79
+
80
+ def get_predicted_commands(self) -> List[PromptCommand]:
81
+ """Get all commands from the output."""
82
+ return [
83
+ command
84
+ for predicted_commands in self.commands.values()
85
+ for command in predicted_commands
86
+ ]
87
+
88
+ def get_component_names_that_predicted_commands_or_have_llm_response(
89
+ self,
90
+ ) -> List[str]:
91
+ """Get all component names that have predicted commands or recieved
92
+ non-empty response from LLM.
93
+ """
94
+ component_names_that_predicted_commands = (
95
+ [
96
+ component_name
97
+ for component_name, predicted_commands in self.commands.items()
98
+ if predicted_commands
99
+ ]
100
+ if self.commands
101
+ else []
102
+ )
103
+ components_with_prompts = (
104
+ [
105
+ str(prompt.get(KEY_COMPONENT_NAME, None))
106
+ for prompt in self.prompts
107
+ if prompt.get(KEY_LLM_RESPONSE_METADATA, None)
108
+ ]
109
+ if self.prompts
110
+ else []
111
+ )
112
+ return list(
113
+ set(component_names_that_predicted_commands + components_with_prompts)
114
+ )
115
+
116
+ def get_component_name_to_prompt_info(self) -> Dict[str, List[Dict[str, Any]]]:
117
+ """Return a dictionary of component names to prompt information.
118
+
119
+ The prompt information includes the prompt name, user prompt, system prompt,
120
+ latency, and usage information.
121
+ The return dict is of the form:
122
+ {
123
+ "component_name": [
124
+ {
125
+ "prompt_name": "...",
126
+ "user_prompt": "...",
127
+ "system_prompt": "...",
128
+ "latency": 0.1,
129
+ "prompt_tokens": 10,
130
+ "completion_tokens": 20
131
+ },
132
+ ...
133
+ ],
134
+ ...
135
+ }
136
+ """
137
+ if self.prompts is None:
138
+ return {}
139
+
140
+ data: Dict[str, List[Dict[str, Any]]] = {}
141
+ relevant_component_names = (
142
+ self.get_component_names_that_predicted_commands_or_have_llm_response()
143
+ )
144
+
145
+ for prompt_data in self.prompts:
146
+ component_name = prompt_data[KEY_COMPONENT_NAME]
147
+
148
+ if component_name not in relevant_component_names:
149
+ continue
150
+
151
+ if component_name not in data:
152
+ data[component_name] = []
153
+
154
+ prompt_info = {
155
+ KEY_PROMPT_NAME: prompt_data[KEY_PROMPT_NAME],
156
+ KEY_USER_PROMPT: prompt_data[KEY_USER_PROMPT],
157
+ }
158
+
159
+ latency = prompt_data.get(KEY_LLM_RESPONSE_METADATA, {}).get(KEY_LATENCY)
160
+ if latency:
161
+ prompt_info[KEY_LATENCY] = latency
162
+
163
+ if prompt_data.get(KEY_SYSTEM_PROMPT):
164
+ prompt_info[KEY_SYSTEM_PROMPT] = prompt_data[KEY_SYSTEM_PROMPT]
165
+
166
+ usage_object = prompt_data.get(KEY_LLM_RESPONSE_METADATA, {}).get(KEY_USAGE)
167
+ if usage_object:
168
+ if usage_object.get(KEY_PROMPT_TOKENS):
169
+ prompt_info[KEY_PROMPT_TOKENS] = usage_object.get(KEY_PROMPT_TOKENS)
170
+ if usage_object.get(KEY_COMPLETION_TOKENS):
171
+ prompt_info[KEY_COMPLETION_TOKENS] = usage_object.get(
172
+ KEY_COMPLETION_TOKENS
173
+ )
174
+
175
+ choices = prompt_data.get(KEY_LLM_RESPONSE_METADATA, {}).get(KEY_CHOICES)
176
+ if choices and len(choices) > 0:
177
+ # Add the action list returned by the LLM to the prompt_info
178
+ prompt_info[KEY_CHOICES] = choices[0]
179
+
180
+ data[component_name].append(prompt_info)
181
+
182
+ return data
183
+
184
+
185
+ class DialogueUnderstandingTestStep(BaseModel):
186
+ actor: str
187
+ text: Optional[str] = None
188
+ template: Optional[str] = None
189
+ line: Optional[int] = None
190
+ metadata_name: Optional[str] = None
191
+ commands: Optional[List[PromptCommand]] = None
192
+ dialogue_understanding_output: Optional[DialogueUnderstandingOutput] = None
193
+
194
+ class Config:
195
+ """Skip validation for PromptCommand protocol as pydantic does not know how to
196
+ serialize or handle instances of a protocol.
197
+ """
198
+
199
+ arbitrary_types_allowed = True
200
+
201
+ def as_dict(self) -> Dict[str, Any]:
202
+ if self.actor == ACTOR_USER:
203
+ if self.commands:
204
+ return {
205
+ KEY_USER_INPUT: self.text,
206
+ KEY_COMMANDS: [command.to_dsl() for command in self.commands],
207
+ }
208
+ return {ACTOR_USER: self.text}
209
+ elif self.actor == ACTOR_BOT:
210
+ if self.template is not None:
211
+ return {KEY_BOT_UTTERED: self.template}
212
+ elif self.text is not None:
213
+ return {KEY_BOT_INPUT: self.text}
214
+
215
+ return {}
216
+
217
+ @staticmethod
218
+ def from_dict(
219
+ step: Dict[str, Any],
220
+ flows: FlowsList,
221
+ custom_command_classes: List[PromptCommand] = [],
222
+ remove_default_commands: List[str] = [],
223
+ ) -> "DialogueUnderstandingTestStep":
224
+ """Creates a DialogueUnderstandingTestStep from a dictionary.
225
+
226
+ Example:
227
+ >>> DialogueUnderstandingTestStep.from_dict({"user": "hello"})
228
+
229
+ Args:
230
+ step: Dictionary containing the step.
231
+ flows: List of flows.
232
+ custom_command_classes: Custom commands to use in the test case.
233
+ remove_default_commands: Default commands to remove from the test case.
234
+
235
+ Returns:
236
+ DialogueUnderstandingTestStep: The constructed test step.
237
+
238
+ Raises:
239
+ ValueError: If the step has invalid commands that are not parseable.
240
+ """
241
+ # Safely extract commands from the step.
242
+ commands = []
243
+ for command in step.get(KEY_COMMANDS, []):
244
+ try:
245
+ commands.extend(
246
+ parse_commands(
247
+ command,
248
+ flows,
249
+ clarify_options_optional=True,
250
+ additional_commands=custom_command_classes,
251
+ default_commands_to_remove=remove_default_commands,
252
+ )
253
+ )
254
+ except (IndexError, ValueError) as e:
255
+ raise ValueError(f"Failed to parse command '{command}': {e}") from e
256
+
257
+ # Construct the DialogueUnderstandingTestStep
258
+ return DialogueUnderstandingTestStep(
259
+ actor=ACTOR_USER if ACTOR_USER in step else ACTOR_BOT,
260
+ text=step.get(KEY_USER_INPUT) or step.get(KEY_BOT_INPUT),
261
+ template=step.get(KEY_BOT_UTTERED),
262
+ line=step.lc.line + 1 if hasattr(step, "lc") else None,
263
+ metadata_name=step.get(KEY_METADATA, ""),
264
+ commands=commands,
265
+ )
266
+
267
+ def get_predicted_commands(self) -> List[PromptCommand]:
268
+ """Get all predicted commands from the test case."""
269
+ if self.dialogue_understanding_output is None:
270
+ return []
271
+
272
+ return self.dialogue_understanding_output.get_predicted_commands()
273
+
274
+ def has_passed(self) -> bool:
275
+ expected_commands = self.commands or []
276
+ predicted_commands = self.get_predicted_commands()
277
+
278
+ return are_command_lists_equal(expected_commands, predicted_commands)
279
+
280
+ def to_str(self) -> str:
281
+ """Converts the test step to a readable output string."""
282
+ if self.actor == ACTOR_BOT:
283
+ if self.text:
284
+ return f"{KEY_BOT_INPUT}: {self.text}"
285
+ elif self.template:
286
+ return f"{KEY_BOT_UTTERED}: {self.template}"
287
+
288
+ if self.actor == ACTOR_USER:
289
+ return f"{KEY_USER_INPUT}: {self.text}"
290
+
291
+ return ""
292
+
293
+ def get_latencies(self) -> List[float]:
294
+ if self.dialogue_understanding_output is None:
295
+ return []
296
+
297
+ prompts = self.dialogue_understanding_output.get_component_name_to_prompt_info()
298
+
299
+ return [
300
+ prompt_data.get(KEY_LATENCY, 0.0)
301
+ for prompt in prompts.values()
302
+ for prompt_data in prompt
303
+ ]
304
+
305
+ def get_completion_tokens(self) -> List[int]:
306
+ if self.dialogue_understanding_output is None:
307
+ return []
308
+
309
+ prompts = self.dialogue_understanding_output.get_component_name_to_prompt_info()
310
+
311
+ return [
312
+ prompt_data.get(KEY_COMPLETION_TOKENS, 0)
313
+ for prompt in prompts.values()
314
+ for prompt_data in prompt
315
+ ]
316
+
317
+ def get_prompt_tokens(self) -> List[int]:
318
+ if self.dialogue_understanding_output is None:
319
+ return []
320
+
321
+ prompts = self.dialogue_understanding_output.get_component_name_to_prompt_info()
322
+
323
+ return [
324
+ prompt_data.get(KEY_PROMPT_TOKENS, 0)
325
+ for prompt in prompts.values()
326
+ for prompt_data in prompt
327
+ ]
328
+
329
+
330
+ class DialogueUnderstandingTestCase(BaseModel):
331
+ name: str
332
+ steps: List[DialogueUnderstandingTestStep] = Field(min_length=1)
333
+ file: Optional[str] = None
334
+ line: Optional[int] = None
335
+ fixture_names: Optional[List[str]] = None
336
+ metadata_name: Optional[str] = None
337
+
338
+ def full_name(self) -> str:
339
+ return f"{self.file}::{self.name}"
340
+
341
+ def as_dict(self) -> Dict[str, Any]:
342
+ result = {
343
+ KEY_TEST_CASE: self.name,
344
+ KEY_STEPS: [step.as_dict() for step in self.steps],
345
+ }
346
+ if self.fixture_names:
347
+ result[KEY_FIXTURES] = self.fixture_names
348
+ if self.metadata_name:
349
+ result[KEY_METADATA] = self.metadata_name
350
+ return result
351
+
352
+ @staticmethod
353
+ def from_dict(
354
+ input_test_case: Dict[str, Any],
355
+ flows: FlowsList,
356
+ file: Optional[str] = None,
357
+ custom_command_classes: List[PromptCommand] = [],
358
+ remove_default_commands: List[str] = [],
359
+ ) -> "DialogueUnderstandingTestCase":
360
+ """Creates a DialogueUnderstandingTestCase from a dictionary.
361
+
362
+ Example:
363
+ >>> DialogueUnderstandingTestCase.from_dict({
364
+ "test_case": "test",
365
+ "steps": [{"user": "hello"}]
366
+ })
367
+
368
+ Args:
369
+ input_test_case: Dictionary containing the test case.
370
+ flows: List of flows.
371
+ file: File name of the test case.
372
+ custom_command_classes: Custom command classes to use in the test case.
373
+ remove_default_commands: Default commands to remove from the test case.
374
+
375
+ Returns:
376
+ DialogueUnderstandingTestCase object.
377
+ """
378
+ steps = [
379
+ DialogueUnderstandingTestStep.from_dict(
380
+ step, flows, custom_command_classes, remove_default_commands
381
+ )
382
+ for step in input_test_case.get(KEY_STEPS, [])
383
+ ]
384
+
385
+ return DialogueUnderstandingTestCase(
386
+ name=input_test_case.get(KEY_TEST_CASE, "default"),
387
+ steps=steps,
388
+ file=file,
389
+ line=(
390
+ input_test_case.lc.line + 1 if hasattr(input_test_case, "lc") else None
391
+ ),
392
+ fixture_names=input_test_case.get(KEY_FIXTURES),
393
+ metadata_name=input_test_case.get(KEY_METADATA),
394
+ )
395
+
396
+ def to_readable_conversation(self, until_step: Optional[int] = None) -> List[str]:
397
+ if until_step:
398
+ steps = self.steps[:until_step]
399
+ else:
400
+ steps = self.steps
401
+
402
+ return [step.to_str() for step in steps]
403
+
404
+ def get_expected_commands(self) -> List[PromptCommand]:
405
+ """Get all commands from the test steps."""
406
+ return [
407
+ command
408
+ for step in self.iterate_over_user_steps()
409
+ for command in (step.commands or [])
410
+ ]
411
+
412
+ def iterate_over_user_steps(self) -> Iterator[DialogueUnderstandingTestStep]:
413
+ """Iterate over user steps, i.e. steps with commands."""
414
+ for step in self.steps:
415
+ if step.commands:
416
+ yield step
417
+
418
+ def get_next_user_and_bot_steps(
419
+ self, from_index: int
420
+ ) -> Tuple[
421
+ Optional[DialogueUnderstandingTestStep], List[DialogueUnderstandingTestStep]
422
+ ]:
423
+ """Get the next user step and all following bot steps."""
424
+ user_step = None
425
+ bot_steps = []
426
+
427
+ for step in self.steps[from_index:]:
428
+ if user_step is not None and step.actor == ACTOR_USER:
429
+ return user_step, bot_steps
430
+
431
+ if step.actor == ACTOR_USER:
432
+ user_step = step
433
+ elif step.actor == ACTOR_BOT:
434
+ bot_steps.append(step)
435
+
436
+ return user_step, bot_steps
437
+
438
+ def failed_user_steps(self) -> List[DialogueUnderstandingTestStep]:
439
+ return [
440
+ step
441
+ for step in self.steps
442
+ if not step.has_passed() and step.actor == ACTOR_USER
443
+ ]
444
+
445
+
446
+ # Update forward references
447
+ DialogueUnderstandingTestStep.model_rebuild()
448
+ DialogueUnderstandingTestCase.model_rebuild()