rasa-pro 3.13.0.dev20250612__py3-none-any.whl → 3.13.0rc1__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 (252) hide show
  1. rasa/__main__.py +0 -3
  2. rasa/api.py +1 -1
  3. rasa/cli/dialogue_understanding_test.py +1 -1
  4. rasa/cli/e2e_test.py +1 -8
  5. rasa/cli/evaluate.py +1 -1
  6. rasa/cli/export.py +3 -1
  7. rasa/cli/llm_fine_tuning.py +12 -11
  8. rasa/cli/project_templates/defaults.py +133 -0
  9. rasa/cli/project_templates/tutorial/config.yml +1 -1
  10. rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
  11. rasa/cli/run.py +1 -1
  12. rasa/cli/studio/download.py +1 -23
  13. rasa/cli/studio/link.py +52 -0
  14. rasa/cli/studio/pull.py +79 -0
  15. rasa/cli/studio/push.py +78 -0
  16. rasa/cli/studio/studio.py +12 -0
  17. rasa/cli/studio/train.py +0 -1
  18. rasa/cli/studio/upload.py +8 -0
  19. rasa/cli/train.py +1 -1
  20. rasa/cli/utils.py +1 -1
  21. rasa/cli/x.py +1 -1
  22. rasa/constants.py +2 -0
  23. rasa/core/__init__.py +0 -16
  24. rasa/core/actions/action.py +5 -1
  25. rasa/core/actions/action_repeat_bot_messages.py +18 -22
  26. rasa/core/actions/action_run_slot_rejections.py +0 -1
  27. rasa/core/agent.py +16 -1
  28. rasa/core/available_endpoints.py +146 -0
  29. rasa/core/brokers/pika.py +1 -2
  30. rasa/core/channels/__init__.py +2 -0
  31. rasa/core/channels/botframework.py +2 -2
  32. rasa/core/channels/channel.py +2 -2
  33. rasa/core/channels/development_inspector.py +1 -1
  34. rasa/core/channels/facebook.py +1 -4
  35. rasa/core/channels/hangouts.py +8 -5
  36. rasa/core/channels/inspector/README.md +3 -3
  37. rasa/core/channels/inspector/dist/assets/{arc-c4b064fc.js → arc-371401b1.js} +1 -1
  38. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-215b5026.js → blockDiagram-38ab4fdb-3f126156.js} +1 -1
  39. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-2b54a0a3.js → c4Diagram-3d4e48cf-12f22eb7.js} +1 -1
  40. rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +1 -0
  41. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-daacea5f.js → classDiagram-70f12bd4-03b1d386.js} +1 -1
  42. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-930d4dc2.js → classDiagram-v2-f2320105-84f69d63.js} +1 -1
  43. rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +1 -0
  44. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-83c206ba.js → createText-2e5e7dd3-ca47fd38.js} +1 -1
  45. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-b0eb01d0.js → edges-e0da2a9e-f837ca8a.js} +1 -1
  46. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-17586500.js → erDiagram-9861fffd-8717ac54.js} +1 -1
  47. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-be2a1776.js → flowDb-956e92f1-94f38b83.js} +1 -1
  48. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-c2120ebd.js → flowDiagram-66a62f08-b616f9fb.js} +1 -1
  49. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +1 -0
  50. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-a6ab5c48.js → flowchart-elk-definition-4a651766-f5d24bb8.js} +1 -1
  51. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-ef613457.js → ganttDiagram-c361ad54-b43ba8d9.js} +1 -1
  52. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-d59185b3.js → gitGraphDiagram-72cf32ee-c3aafaa5.js} +1 -1
  53. rasa/core/channels/inspector/dist/assets/{graph-0f155405.js → graph-0d0a2c10.js} +1 -1
  54. rasa/core/channels/inspector/dist/assets/{index-3862675e-d5f1d1b7.js → index-3862675e-58ea0305.js} +1 -1
  55. rasa/core/channels/inspector/dist/assets/{index-47737d3a.js → index-cce6f8a1.js} +3 -3
  56. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-b07d141f.js → infoDiagram-f8f76790-b8f60461.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-1936d429.js → journeyDiagram-49397b02-95be5545.js} +1 -1
  58. rasa/core/channels/inspector/dist/assets/{layout-dde8d0f3.js → layout-da885b9b.js} +1 -1
  59. rasa/core/channels/inspector/dist/assets/{line-0c2c7ee0.js → line-f1c817d3.js} +1 -1
  60. rasa/core/channels/inspector/dist/assets/{linear-35dd89a4.js → linear-d42801e6.js} +1 -1
  61. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-56192851.js → mindmap-definition-fc14e90a-a38923a6.js} +1 -1
  62. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-fc21ed78.js → pieDiagram-8a3498a8-ca6e71e9.js} +1 -1
  63. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-25e98518.js → quadrantDiagram-120e2f19-b290dae9.js} +1 -1
  64. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-546ff1f5.js → requirementDiagram-deff3bca-03f02ceb.js} +1 -1
  65. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-02d8b82d.js → sankeyDiagram-04a897e0-c49eee40.js} +1 -1
  66. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3ca5a92e.js → sequenceDiagram-704730f1-b2cd6a3d.js} +1 -1
  67. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-128ea07c.js → stateDiagram-587899a1-e53a2028.js} +1 -1
  68. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-95f290af.js → stateDiagram-v2-d93cdb3a-e1982a03.js} +1 -1
  69. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-4984898a.js → styles-6aaf32cf-d0226ca5.js} +1 -1
  70. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1bf266ba.js → styles-9a916d00-0e21dc00.js} +1 -1
  71. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-60521c63.js → styles-c10674c1-9588494e.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-a25b6e12.js → svgDrawCommon-08f97a94-be478d4f.js} +1 -1
  73. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-0fc086bf.js → timeline-definition-85554ec2-74631749.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-44ee592e.js → xychartDiagram-e933f94c-a043552f.js} +1 -1
  75. rasa/core/channels/inspector/dist/index.html +1 -1
  76. rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +1 -1
  77. rasa/core/channels/mattermost.py +1 -1
  78. rasa/core/channels/rasa_chat.py +2 -4
  79. rasa/core/channels/rest.py +5 -4
  80. rasa/core/channels/socketio.py +56 -41
  81. rasa/core/channels/studio_chat.py +314 -10
  82. rasa/core/channels/vier_cvg.py +1 -2
  83. rasa/core/channels/voice_ready/audiocodes.py +2 -9
  84. rasa/core/channels/voice_stream/asr/azure.py +9 -0
  85. rasa/core/channels/voice_stream/audiocodes.py +8 -5
  86. rasa/core/channels/voice_stream/browser_audio.py +1 -1
  87. rasa/core/channels/voice_stream/genesys.py +2 -2
  88. rasa/core/channels/voice_stream/jambonz.py +166 -0
  89. rasa/core/channels/voice_stream/tts/__init__.py +8 -0
  90. rasa/core/channels/voice_stream/twilio_media_streams.py +17 -5
  91. rasa/core/channels/voice_stream/voice_channel.py +44 -24
  92. rasa/core/exporter.py +36 -0
  93. rasa/core/http_interpreter.py +3 -7
  94. rasa/core/information_retrieval/faiss.py +18 -11
  95. rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
  96. rasa/core/jobs.py +2 -1
  97. rasa/core/nlg/contextual_response_rephraser.py +48 -12
  98. rasa/core/nlg/generator.py +0 -1
  99. rasa/core/nlg/interpolator.py +2 -3
  100. rasa/core/nlg/summarize.py +39 -5
  101. rasa/core/policies/enterprise_search_policy.py +298 -184
  102. rasa/core/policies/enterprise_search_policy_config.py +241 -0
  103. rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +64 -0
  104. rasa/core/policies/flow_policy.py +1 -1
  105. rasa/core/policies/flows/flow_executor.py +96 -17
  106. rasa/core/policies/intentless_policy.py +71 -26
  107. rasa/core/processor.py +104 -51
  108. rasa/core/run.py +33 -11
  109. rasa/core/tracker_stores/tracker_store.py +1 -1
  110. rasa/core/training/interactive.py +1 -1
  111. rasa/core/utils.py +35 -99
  112. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
  113. rasa/dialogue_understanding/coexistence/llm_based_router.py +13 -17
  114. rasa/dialogue_understanding/commands/__init__.py +4 -0
  115. rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
  116. rasa/dialogue_understanding/commands/cancel_flow_command.py +6 -2
  117. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
  118. rasa/dialogue_understanding/commands/clarify_command.py +7 -3
  119. rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
  120. rasa/dialogue_understanding/commands/correct_slots_command.py +5 -6
  121. rasa/dialogue_understanding/commands/error_command.py +1 -1
  122. rasa/dialogue_understanding/commands/human_handoff_command.py +3 -3
  123. rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
  124. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
  125. rasa/dialogue_understanding/commands/set_slot_command.py +15 -5
  126. rasa/dialogue_understanding/commands/skip_question_command.py +3 -3
  127. rasa/dialogue_understanding/commands/start_flow_command.py +7 -3
  128. rasa/dialogue_understanding/commands/utils.py +26 -2
  129. rasa/dialogue_understanding/generator/__init__.py +7 -1
  130. rasa/dialogue_understanding/generator/command_generator.py +15 -3
  131. rasa/dialogue_understanding/generator/command_parser.py +2 -2
  132. rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
  133. rasa/dialogue_understanding/generator/constants.py +2 -2
  134. rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
  135. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +0 -2
  136. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -0
  137. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +1 -0
  138. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +79 -0
  139. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +79 -0
  140. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +28 -463
  141. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
  142. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +461 -0
  143. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +11 -64
  144. rasa/dialogue_understanding/patterns/cancel.py +1 -2
  145. rasa/dialogue_understanding/patterns/clarify.py +1 -1
  146. rasa/dialogue_understanding/patterns/correction.py +2 -2
  147. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +37 -25
  148. rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
  149. rasa/dialogue_understanding/processor/command_processor.py +11 -12
  150. rasa/dialogue_understanding/processor/command_processor_component.py +3 -3
  151. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
  152. rasa/dialogue_understanding/stack/utils.py +3 -1
  153. rasa/dialogue_understanding/utils.py +68 -12
  154. rasa/dialogue_understanding_test/du_test_case.py +1 -1
  155. rasa/dialogue_understanding_test/du_test_runner.py +4 -22
  156. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +2 -6
  157. rasa/e2e_test/e2e_test_coverage_report.py +1 -1
  158. rasa/e2e_test/e2e_test_runner.py +1 -1
  159. rasa/engine/constants.py +1 -1
  160. rasa/engine/graph.py +2 -2
  161. rasa/engine/recipes/default_recipe.py +26 -2
  162. rasa/engine/validation.py +3 -2
  163. rasa/hooks.py +0 -28
  164. rasa/llm_fine_tuning/annotation_module.py +39 -9
  165. rasa/llm_fine_tuning/conversations.py +3 -0
  166. rasa/llm_fine_tuning/llm_data_preparation_module.py +66 -49
  167. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +5 -7
  168. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +52 -44
  169. rasa/llm_fine_tuning/paraphrasing_module.py +10 -12
  170. rasa/llm_fine_tuning/storage.py +4 -4
  171. rasa/llm_fine_tuning/utils.py +63 -1
  172. rasa/model_manager/model_api.py +88 -0
  173. rasa/model_manager/trainer_service.py +4 -4
  174. rasa/plugin.py +1 -11
  175. rasa/privacy/__init__.py +0 -0
  176. rasa/privacy/constants.py +83 -0
  177. rasa/privacy/event_broker_utils.py +77 -0
  178. rasa/privacy/privacy_config.py +281 -0
  179. rasa/privacy/privacy_config_schema.json +86 -0
  180. rasa/privacy/privacy_filter.py +340 -0
  181. rasa/privacy/privacy_manager.py +576 -0
  182. rasa/server.py +23 -2
  183. rasa/shared/constants.py +18 -0
  184. rasa/shared/core/command_payload_reader.py +1 -5
  185. rasa/shared/core/constants.py +4 -3
  186. rasa/shared/core/domain.py +7 -0
  187. rasa/shared/core/events.py +38 -10
  188. rasa/shared/core/flows/constants.py +2 -0
  189. rasa/shared/core/flows/flow.py +127 -14
  190. rasa/shared/core/flows/flows_list.py +18 -1
  191. rasa/shared/core/flows/flows_yaml_schema.json +3 -0
  192. rasa/shared/core/flows/steps/collect.py +46 -2
  193. rasa/shared/core/flows/steps/link.py +7 -2
  194. rasa/shared/core/flows/validation.py +25 -5
  195. rasa/shared/core/slots.py +28 -0
  196. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
  197. rasa/shared/exceptions.py +4 -0
  198. rasa/shared/providers/_configs/azure_openai_client_config.py +6 -2
  199. rasa/shared/providers/_configs/default_litellm_client_config.py +1 -1
  200. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -1
  201. rasa/shared/providers/_configs/openai_client_config.py +5 -1
  202. rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -1
  203. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -1
  204. rasa/shared/providers/_configs/utils.py +0 -99
  205. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +3 -0
  206. rasa/shared/providers/llm/_base_litellm_client.py +5 -2
  207. rasa/shared/utils/common.py +1 -1
  208. rasa/shared/utils/configs.py +110 -0
  209. rasa/shared/utils/constants.py +0 -3
  210. rasa/shared/utils/llm.py +195 -9
  211. rasa/shared/utils/pykwalify_extensions.py +0 -9
  212. rasa/shared/utils/yaml.py +32 -0
  213. rasa/studio/constants.py +1 -0
  214. rasa/studio/data_handler.py +11 -4
  215. rasa/studio/download.py +167 -0
  216. rasa/studio/link.py +200 -0
  217. rasa/studio/prompts.py +223 -0
  218. rasa/studio/pull/__init__.py +0 -0
  219. rasa/studio/{download/flows.py → pull/data.py} +23 -160
  220. rasa/studio/{download → pull}/domains.py +1 -1
  221. rasa/studio/pull/pull.py +235 -0
  222. rasa/studio/push.py +136 -0
  223. rasa/studio/train.py +1 -1
  224. rasa/studio/upload.py +117 -67
  225. rasa/telemetry.py +82 -25
  226. rasa/tracing/config.py +3 -4
  227. rasa/tracing/constants.py +19 -1
  228. rasa/tracing/instrumentation/attribute_extractors.py +30 -8
  229. rasa/tracing/instrumentation/instrumentation.py +53 -2
  230. rasa/tracing/instrumentation/metrics.py +98 -15
  231. rasa/tracing/metric_instrument_provider.py +75 -3
  232. rasa/utils/common.py +7 -22
  233. rasa/utils/log_utils.py +1 -45
  234. rasa/validator.py +2 -8
  235. rasa/version.py +1 -1
  236. {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/METADATA +8 -9
  237. {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/RECORD +241 -220
  238. rasa/anonymization/__init__.py +0 -2
  239. rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
  240. rasa/anonymization/anonymization_pipeline.py +0 -286
  241. rasa/anonymization/anonymization_rule_executor.py +0 -266
  242. rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
  243. rasa/anonymization/schemas/config.yml +0 -47
  244. rasa/anonymization/utils.py +0 -118
  245. rasa/core/channels/inspector/dist/assets/channel-3730f5fd.js +0 -1
  246. rasa/core/channels/inspector/dist/assets/clone-e847561e.js +0 -1
  247. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-efbbfe00.js +0 -1
  248. rasa/studio/download/download.py +0 -439
  249. /rasa/{studio/download → core/information_retrieval/ingestion}/__init__.py +0 -0
  250. {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/NOTICE +0 -0
  251. {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/WHEEL +0 -0
  252. {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,235 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+ from typing import Any, Tuple
6
+
7
+ import structlog
8
+
9
+ import rasa.cli.utils
10
+ import rasa.shared.utils.cli
11
+ from rasa.shared.constants import (
12
+ DEFAULT_CONFIG_PATH,
13
+ DEFAULT_DATA_PATH,
14
+ DEFAULT_DOMAIN_PATH,
15
+ DEFAULT_DOMAIN_PATHS,
16
+ DEFAULT_ENDPOINTS_PATH,
17
+ )
18
+ from rasa.shared.importers.importer import TrainingDataImporter
19
+ from rasa.shared.utils.io import write_text_file
20
+ from rasa.studio.config import StudioConfig
21
+ from rasa.studio.data_handler import StudioDataHandler, import_data_from_studio
22
+ from rasa.studio.link import read_assistant_name
23
+ from rasa.studio.pull.data import merge_flows_in_directory, merge_nlu_in_directory
24
+ from rasa.studio.pull.domains import merge_domain
25
+ from rasa.utils.mapper import RasaPrimitiveStorageMapper
26
+
27
+ structlogger = structlog.get_logger(__name__)
28
+
29
+
30
+ def handle_pull(args: argparse.Namespace) -> None:
31
+ """Pull the complete assistant and overwrite all local files.
32
+
33
+ Args:
34
+ args: The command line arguments.
35
+ """
36
+ handler = _create_studio_handler()
37
+ handler.request_all_data()
38
+
39
+ _pull_config_file(handler, args.config or DEFAULT_CONFIG_PATH)
40
+ _pull_endpoints_file(handler, args.endpoints or DEFAULT_ENDPOINTS_PATH)
41
+
42
+ domain_path, data_path = _prepare_data_and_domain_paths(args)
43
+ _merge_domain_and_data(handler, domain_path, data_path)
44
+
45
+ structlogger.info(
46
+ "studio.push.success",
47
+ event_info="Pulled assistant data from Studio.",
48
+ )
49
+ rasa.shared.utils.cli.print_success("Pulled assistant data from Studio.")
50
+
51
+
52
+ def handle_pull_config(args: argparse.Namespace) -> None:
53
+ """Pull nothing but the assistant's `config.yml`.
54
+
55
+ Args:
56
+ args: The command line arguments.
57
+ """
58
+ handler = _create_studio_handler()
59
+ handler.request_all_data()
60
+
61
+ _pull_config_file(handler, args.config or DEFAULT_CONFIG_PATH)
62
+
63
+ structlogger.info(
64
+ "studio.push.success",
65
+ event_info="Pulled assistant data from Studio.",
66
+ )
67
+ rasa.shared.utils.cli.print_success("Pulled assistant data from Studio.")
68
+
69
+
70
+ def handle_pull_endpoints(args: argparse.Namespace) -> None:
71
+ """Pull nothing but the assistant's `endpoints.yml`.
72
+
73
+ Args:
74
+ args: The command line arguments.
75
+ """
76
+ handler = _create_studio_handler()
77
+ handler.request_all_data()
78
+
79
+ _pull_endpoints_file(handler, args.endpoints or DEFAULT_ENDPOINTS_PATH)
80
+ structlogger.info(
81
+ "studio.push.success",
82
+ event_info="Pulled assistant data from Studio.",
83
+ )
84
+ rasa.shared.utils.cli.print_success("Pulled assistant data from Studio.")
85
+
86
+
87
+ def _create_studio_handler() -> StudioDataHandler:
88
+ """Return an initialised StudioDataHandler for the linked assistant.
89
+
90
+ Returns:
91
+ An instance of `StudioDataHandler` for the linked assistant.
92
+ """
93
+ assistant_name = read_assistant_name()
94
+ return StudioDataHandler(
95
+ studio_config=StudioConfig.read_config(), assistant_name=assistant_name
96
+ )
97
+
98
+
99
+ def _pull_config_file(handler: StudioDataHandler, target_path: str | Path) -> None:
100
+ """Pull the assistant's `config.yml` file and write it to the specified path.
101
+
102
+ Args:
103
+ handler: The data handler to retrieve the config from.
104
+ target_path: The path where the config file should be written.
105
+ """
106
+ config_yaml = handler.get_config()
107
+ if not config_yaml:
108
+ rasa.shared.utils.cli.print_error_and_exit("No config data found in assistant.")
109
+
110
+ _write_text(config_yaml, target_path)
111
+
112
+
113
+ def _pull_endpoints_file(handler: StudioDataHandler, target_path: str | Path) -> None:
114
+ """Pull the assistant's `endpoints.yml` file and write it to the specified path.
115
+
116
+ Args:
117
+ handler: The data handler to retrieve the endpoints from.
118
+ target_path: The path where the endpoints file should be written.
119
+ """
120
+ endpoints_yaml = handler.get_endpoints()
121
+ if not endpoints_yaml:
122
+ rasa.shared.utils.cli.print_error_and_exit(
123
+ "No endpoints data found in assistant."
124
+ )
125
+
126
+ _write_text(endpoints_yaml, target_path)
127
+
128
+
129
+ def _prepare_data_and_domain_paths(args: argparse.Namespace) -> Tuple[Path, Path]:
130
+ """Prepars the domain and data paths based on the provided arguments.
131
+
132
+ Args:
133
+ args: The command line arguments.
134
+
135
+ Returns:
136
+ A tuple containing the domain path and a data path.
137
+ """
138
+ # Prepare domain path.
139
+ domain_path = rasa.cli.utils.get_validated_path(
140
+ args.domain, "domain", DEFAULT_DOMAIN_PATHS, none_is_valid=True
141
+ )
142
+ domain_or_default_path = args.domain or DEFAULT_DOMAIN_PATH
143
+
144
+ if domain_path is None:
145
+ domain_path = Path(domain_or_default_path)
146
+ domain_path.touch()
147
+
148
+ if isinstance(domain_path, str):
149
+ domain_path = Path(domain_path)
150
+
151
+ data_path = rasa.cli.utils.get_validated_path(
152
+ args.data[0], "data", DEFAULT_DATA_PATH, none_is_valid=True
153
+ )
154
+
155
+ data_path = Path(data_path or args.data[0])
156
+ if not (data_path.is_file() or data_path.is_dir()):
157
+ data_path.mkdir(parents=True, exist_ok=True)
158
+
159
+ return domain_path, data_path
160
+
161
+
162
+ def _merge_domain_and_data(
163
+ handler: StudioDataHandler, domain_path: Path, data_path: Path
164
+ ) -> None:
165
+ """Merge local assistant data with Studio assistant data.
166
+
167
+ Args:
168
+ handler: The data handler to retrieve the assistant data from.
169
+ domain_path: The path to the local domain file or directory.
170
+ data_path: The path to the local training data file or directory.
171
+ """
172
+ data_from_studio, data_local = import_data_from_studio(
173
+ handler, domain_path, data_path
174
+ )
175
+ mapper = RasaPrimitiveStorageMapper(
176
+ domain_path=domain_path, training_data_paths=[data_path]
177
+ )
178
+
179
+ merge_domain(data_from_studio, data_local, domain_path)
180
+ merge_data(data_path, handler, data_from_studio, data_local, mapper)
181
+
182
+
183
+ def merge_data(
184
+ data_path: Path,
185
+ handler: Any,
186
+ data_from_studio: TrainingDataImporter,
187
+ data_local: TrainingDataImporter,
188
+ mapper: RasaPrimitiveStorageMapper,
189
+ ) -> None:
190
+ """
191
+ Merges flows data from a file or directory.
192
+
193
+ Args:
194
+ data_path: List of paths to the training data.
195
+ handler: The StudioDataHandler instance.
196
+ data_from_studio: The TrainingDataImporter instance for Studio data.
197
+ data_local: The TrainingDataImporter instance for local data.
198
+ mapper: The RasaPrimitiveStorageMapper instance for mapping.
199
+ """
200
+ if not data_path.is_file() and not data_path.is_dir():
201
+ raise ValueError("Provided data path is neither a file nor a directory.")
202
+
203
+ if handler.has_nlu():
204
+ if data_path.is_file():
205
+ nlu_data_merged = data_from_studio.get_nlu_data().merge(
206
+ data_local.get_nlu_data()
207
+ )
208
+ nlu_data_merged.persist_nlu(data_path)
209
+ else:
210
+ merge_nlu_in_directory(
211
+ data_from_studio,
212
+ data_local,
213
+ data_path,
214
+ mapper,
215
+ )
216
+
217
+ if handler.has_flows():
218
+ flows_root = data_path.parent if data_path.is_file() else data_path
219
+ merge_flows_in_directory(
220
+ data_from_studio,
221
+ flows_root,
222
+ mapper,
223
+ )
224
+
225
+
226
+ def _write_text(content: str, target: str | Path) -> None:
227
+ """Write `content` to `target`, ensuring parent directories exist.
228
+
229
+ Args:
230
+ content: The content to write to the file.
231
+ target: The path where the content should be written.
232
+ """
233
+ path = Path(target)
234
+ path.parent.mkdir(parents=True, exist_ok=True)
235
+ write_text_file(content, path, encoding="utf-8")
rasa/studio/push.py ADDED
@@ -0,0 +1,136 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+ from typing import Dict, Text
6
+
7
+ import structlog
8
+
9
+ import rasa.shared.utils.cli
10
+ from rasa.shared.core.flows.yaml_flows_io import YamlFlowsWriter
11
+ from rasa.shared.importers.importer import TrainingDataImporter
12
+ from rasa.shared.nlu.training_data.formats.rasa_yaml import RasaYAMLWriter
13
+ from rasa.shared.utils.io import read_file
14
+ from rasa.shared.utils.yaml import dump_obj_as_yaml_to_string
15
+ from rasa.studio.config import StudioConfig
16
+ from rasa.studio.link import get_studio_config, read_assistant_name
17
+ from rasa.studio.upload import (
18
+ build_import_request,
19
+ make_request,
20
+ run_validation,
21
+ )
22
+
23
+ structlogger = structlog.get_logger(__name__)
24
+
25
+
26
+ def _send_to_studio(
27
+ assistant_name: Text,
28
+ payload_parts: Dict[Text, Text],
29
+ studio_cfg: StudioConfig,
30
+ ) -> None:
31
+ """Build the GraphQL request and send it.
32
+
33
+ Args:
34
+ assistant_name: The name of the assistant.
35
+ payload_parts: The parts of the payload to send.
36
+ studio_cfg: The StudioConfig object.
37
+ """
38
+ graphql_req = build_import_request(
39
+ assistant_name=assistant_name,
40
+ flows_yaml=payload_parts.get("flows"),
41
+ domain_yaml=payload_parts.get("domain"),
42
+ config_yaml=payload_parts.get("config"),
43
+ endpoints=payload_parts.get("endpoints"),
44
+ nlu_yaml=payload_parts.get("nlu"),
45
+ )
46
+ verify = not studio_cfg.disable_verify
47
+ result = make_request(studio_cfg.studio_url, graphql_req, verify)
48
+ if not result.was_successful:
49
+ rasa.shared.utils.cli.print_error_and_exit(result.message)
50
+
51
+ structlogger.info(
52
+ "studio.push.success",
53
+ event_info=f"Pushed data to assistant '{assistant_name}'.",
54
+ assistant_name=assistant_name,
55
+ )
56
+ rasa.shared.utils.cli.print_success(f"Pushed data to assistant '{assistant_name}'.")
57
+
58
+
59
+ def handle_push(args: argparse.Namespace) -> None:
60
+ """Push the entire assistant.
61
+
62
+ Args:
63
+ args: The command line arguments.
64
+ """
65
+ studio_cfg = get_studio_config()
66
+
67
+ run_validation(args)
68
+
69
+ importer = TrainingDataImporter.load_from_dict(
70
+ domain_path=args.domain,
71
+ config_path=args.config,
72
+ expand_env_vars=False,
73
+ )
74
+
75
+ domain_yaml = dump_obj_as_yaml_to_string(importer.get_user_domain().as_dict())
76
+ config_yaml = read_file(Path(args.config))
77
+ endpoints_yaml = read_file(Path(args.endpoints))
78
+
79
+ flow_importer = TrainingDataImporter.load_from_dict(
80
+ training_data_paths=args.data, expand_env_vars=False
81
+ )
82
+ flows_yaml = YamlFlowsWriter().dumps(flow_importer.get_user_flows())
83
+
84
+ nlu_importer = TrainingDataImporter.load_from_dict(
85
+ training_data_paths=args.data, expand_env_vars=False
86
+ )
87
+ nlu_yaml = RasaYAMLWriter().dumps(nlu_importer.get_nlu_data())
88
+
89
+ assistant_name = read_assistant_name()
90
+ _send_to_studio(
91
+ assistant_name,
92
+ {
93
+ "flows": flows_yaml,
94
+ "domain": domain_yaml,
95
+ "config": config_yaml,
96
+ "endpoints": endpoints_yaml,
97
+ "nlu": nlu_yaml,
98
+ },
99
+ studio_cfg,
100
+ )
101
+
102
+
103
+ def handle_push_config(args: argparse.Namespace) -> None:
104
+ """Push only the assistant configuration (config.yml).
105
+
106
+ Args:
107
+ args: The command line arguments.
108
+ """
109
+ studio_cfg = get_studio_config()
110
+ assistant_name = read_assistant_name()
111
+
112
+ config_yaml = read_file(Path(args.config))
113
+ if not config_yaml:
114
+ rasa.shared.utils.cli.print_error_and_exit(
115
+ "No configuration data was found in the assistant."
116
+ )
117
+
118
+ _send_to_studio(assistant_name, {"config": config_yaml}, studio_cfg)
119
+
120
+
121
+ def handle_push_endpoints(args: argparse.Namespace) -> None:
122
+ """Push only the endpoints configuration (endpoints.yml).
123
+
124
+ Args:
125
+ args: The command line arguments.
126
+ """
127
+ studio_cfg = get_studio_config()
128
+ assistant_name = read_assistant_name()
129
+
130
+ endpoints_yaml = read_file(Path(args.endpoints))
131
+ if not endpoints_yaml:
132
+ rasa.shared.utils.cli.print_error_and_exit(
133
+ "No endpoints data was found in the assistant."
134
+ )
135
+
136
+ _send_to_studio(assistant_name, {"endpoints": endpoints_yaml}, studio_cfg)
rasa/studio/train.py CHANGED
@@ -34,7 +34,7 @@ def handle_train(args: argparse.Namespace) -> Optional[str]:
34
34
  from rasa.api import train as train_all
35
35
 
36
36
  handler = StudioDataHandler(
37
- studio_config=StudioConfig.read_config(), assistant_name=args.assistant_name[0]
37
+ studio_config=StudioConfig.read_config(), assistant_name=args.assistant_name
38
38
  )
39
39
  if args.entities or args.intents:
40
40
  handler.request_data(args.intents, args.entities)
rasa/studio/upload.py CHANGED
@@ -2,11 +2,12 @@ import argparse
2
2
  import base64
3
3
  import re
4
4
  import sys
5
- from typing import Any, Dict, Iterable, List, Set, Text, Tuple, Union
5
+ from typing import Any, Dict, Iterable, List, Optional, Set, Text, Tuple, Union
6
6
 
7
7
  import questionary
8
8
  import requests
9
9
  import structlog
10
+ from pydantic import BaseModel, Field
10
11
 
11
12
  import rasa.cli.telemetry
12
13
  import rasa.cli.utils
@@ -32,6 +33,7 @@ from rasa.shared.nlu.training_data.formats.rasa_yaml import (
32
33
  )
33
34
  from rasa.shared.utils.yaml import (
34
35
  dump_obj_as_yaml_to_string,
36
+ read_yaml,
35
37
  read_yaml_file,
36
38
  )
37
39
  from rasa.studio import results_logger
@@ -64,6 +66,16 @@ DOMAIN_KEYS = [
64
66
  ]
65
67
 
66
68
 
69
+ class CALMImportParts(BaseModel):
70
+ """All pieces that will be uploaded to Rasa Studio."""
71
+
72
+ flows: Dict[str, Any]
73
+ domain: Dict[str, Any]
74
+ config: Dict[str, Any]
75
+ endpoints: Dict[str, Any]
76
+ nlu: Dict[str, Any] = Field(default_factory=dict)
77
+
78
+
67
79
  def _get_selected_entities_and_intents(
68
80
  args: argparse.Namespace,
69
81
  intents_from_files: Set[Text],
@@ -208,79 +220,93 @@ def _get_assistant_name(config: Dict[Text, Any]) -> str:
208
220
  return assistant_name
209
221
 
210
222
 
211
- @with_studio_error_handler
212
- def upload_calm_assistant(
213
- args: argparse.Namespace, endpoint: str, verify: bool = True
214
- ) -> StudioResult:
215
- """Validates and uploads the CALM assistant data to Rasa Studio.
223
+ def build_calm_import_parts(
224
+ data_path: Union[Text, List[Text]],
225
+ domain_path: Text,
226
+ config_path: Text,
227
+ endpoints_path: Optional[Text] = None,
228
+ assistant_name: Optional[Text] = None,
229
+ ) -> Tuple[str, CALMImportParts]:
230
+ """Builds the parts of the assistant to be uploaded to Studio.
216
231
 
217
232
  Args:
218
- args: The command line arguments
219
- - data: The path to the training data
220
- - domain: The path to the domain
221
- - flows: The path to the flows
222
- - endpoints: The path to the endpoints
223
- - config: The path to the config
224
- endpoint: The studio endpoint
225
- verify: Whether to verify SSL
233
+ data_path: The path to the training data
234
+ domain_path: The path to the domain
235
+ config_path: The path to the config
236
+ endpoints_path: The path to the endpoints
237
+ assistant_name: The name of the assistant
238
+
226
239
  Returns:
227
- None
240
+ The assistant name and the parts to be uploaded
228
241
  """
229
- run_validation(args)
230
-
231
- structlogger.info(
232
- "rasa.studio.upload.loading_data", event_info="Parsing CALM assistant data..."
233
- )
234
-
235
242
  importer = TrainingDataImporter.load_from_dict(
236
- domain_path=args.domain,
237
- config_path=args.config,
243
+ domain_path=domain_path,
244
+ config_path=config_path,
238
245
  expand_env_vars=False,
239
246
  )
240
247
 
241
- # Prepare config and domain
242
- config = importer.get_config()
243
- assistant_name = _get_assistant_name(config)
248
+ config = read_yaml_file(config_path, expand_env_vars=False)
249
+ endpoints = read_yaml_file(endpoints_path, expand_env_vars=False)
250
+ assistant_name = assistant_name or _get_assistant_name(config)
244
251
 
245
- config_from_files = read_yaml_file(args.config, expand_env_vars=False)
246
252
  domain_from_files = importer.get_user_domain().as_dict()
247
-
248
- # Extract domain and config values
249
253
  domain = extract_values(domain_from_files, DOMAIN_KEYS)
250
254
 
251
- # Prepare flows
252
255
  flow_importer = FlowSyncImporter.load_from_dict(
253
- training_data_paths=args.data, expand_env_vars=False
256
+ training_data_paths=data_path, expand_env_vars=False
254
257
  )
258
+
255
259
  flows = list(flow_importer.get_user_flows())
260
+ flows_yaml = YamlFlowsWriter().dumps(flows)
261
+ flows = read_yaml(flows_yaml, expand_env_vars=False)
256
262
 
257
- # We instantiate the TrainingDataImporter again on purpose to avoid
258
- # adding patterns to domain's actions. More info https://t.ly/W8uuc
259
263
  nlu_importer = TrainingDataImporter.load_from_dict(
260
- training_data_paths=args.data, expand_env_vars=False
264
+ training_data_paths=data_path, expand_env_vars=False
261
265
  )
262
266
  nlu_data = nlu_importer.get_nlu_data()
263
267
  nlu_examples = nlu_data.filter_training_examples(
264
268
  lambda ex: ex.get("intent") in nlu_data.intents
265
269
  )
266
270
  nlu_examples_yaml = RasaYAMLWriter().dumps(nlu_examples)
271
+ nlu = read_yaml(nlu_examples_yaml, expand_env_vars=False)
272
+
273
+ parts = CALMImportParts(
274
+ flows=flows,
275
+ domain=domain,
276
+ config=config,
277
+ endpoints=endpoints,
278
+ nlu=nlu,
279
+ )
280
+
281
+ return assistant_name, parts
282
+
283
+
284
+ @with_studio_error_handler
285
+ def upload_calm_assistant(
286
+ args: argparse.Namespace, endpoint: str, verify: bool = True
287
+ ) -> StudioResult:
288
+ def yaml_or_empty(part: Dict[Text, Any]) -> Optional[str]:
289
+ return dump_obj_as_yaml_to_string(part) if part else None
267
290
 
268
- # Prepare endpoints
269
- endpoints_from_files = read_yaml_file(args.endpoints, expand_env_vars=False)
270
- endpoints_str = dump_obj_as_yaml_to_string(
271
- endpoints_from_files, transform=remove_quotes
291
+ run_validation(args)
292
+ structlogger.info(
293
+ "rasa.studio.upload.loading_data", event_info="Parsing CALM assistant data..."
294
+ )
295
+ assistant_name, parts = build_calm_import_parts(
296
+ data_path=args.data,
297
+ domain_path=args.domain,
298
+ config_path=args.config,
299
+ endpoints_path=args.endpoints,
272
300
  )
273
301
 
274
- # Build GraphQL request
275
302
  graphql_req = build_import_request(
276
303
  assistant_name,
277
- flows_yaml=YamlFlowsWriter().dumps(flows),
278
- domain_yaml=dump_obj_as_yaml_to_string(domain),
279
- config_yaml=dump_obj_as_yaml_to_string(config_from_files),
280
- endpoints=endpoints_str,
281
- nlu_yaml=nlu_examples_yaml,
304
+ flows_yaml=yaml_or_empty(parts.flows),
305
+ domain_yaml=yaml_or_empty(parts.domain),
306
+ config_yaml=yaml_or_empty(parts.config),
307
+ endpoints=yaml_or_empty(parts.endpoints),
308
+ nlu_yaml=yaml_or_empty(parts.nlu),
282
309
  )
283
-
284
310
  structlogger.info(
285
311
  "rasa.studio.upload.calm", event_info="Uploading to Rasa Studio..."
286
312
  )
@@ -393,7 +419,6 @@ def make_request(endpoint: str, graphql_req: Dict, verify: bool = True) -> Studi
393
419
  },
394
420
  verify=verify,
395
421
  )
396
-
397
422
  if results_logger.response_has_errors(res.json()):
398
423
  track_upload_to_studio_failed(res.json())
399
424
  return StudioResult.error(res.json())
@@ -421,39 +446,64 @@ def _add_missing_entities(
421
446
 
422
447
  def build_import_request(
423
448
  assistant_name: str,
424
- flows_yaml: str,
425
- domain_yaml: str,
426
- config_yaml: str,
427
- endpoints: str,
428
- nlu_yaml: str = "",
449
+ flows_yaml: Optional[str] = None,
450
+ domain_yaml: Optional[str] = None,
451
+ config_yaml: Optional[str] = None,
452
+ endpoints: Optional[str] = None,
453
+ nlu_yaml: Optional[str] = None,
429
454
  ) -> Dict:
430
- # b64encode expects bytes and returns bytes so we need to decode to string
431
- base64_domain = base64.b64encode(domain_yaml.encode("utf-8")).decode("utf-8")
432
- base64_flows = base64.b64encode(flows_yaml.encode("utf-8")).decode("utf-8")
433
- base64_config = base64.b64encode(config_yaml.encode("utf-8")).decode("utf-8")
434
- base64_nlu = base64.b64encode(nlu_yaml.encode("utf-8")).decode("utf-8")
435
- base64_endpoints = base64.b64encode(endpoints.encode("utf-8")).decode("utf-8")
455
+ """Builds the GraphQL request for uploading a modern assistant.
456
+
457
+ Args:
458
+ assistant_name: The name of the assistant
459
+ flows_yaml: The YAML representation of the flows
460
+ domain_yaml: The YAML representation of the domain
461
+ config_yaml: The YAML representation of the config
462
+ endpoints: The YAML representation of the endpoints
463
+ nlu_yaml: The YAML representation of the NLU data
464
+
465
+ Returns:
466
+ A dictionary representing the GraphQL request for uploading the assistant.
467
+ """
468
+ inputs_map = {
469
+ "domain": domain_yaml,
470
+ "flows": flows_yaml,
471
+ "config": config_yaml,
472
+ "endpoints": endpoints,
473
+ "nlu": nlu_yaml,
474
+ }
475
+
476
+ payload = {
477
+ field: convert_string_to_base64(value)
478
+ for field, value in inputs_map.items()
479
+ if value is not None
480
+ }
481
+
482
+ variables_input = {"assistantName": assistant_name, **payload}
436
483
 
437
484
  graphql_req = {
438
485
  "query": (
439
486
  "mutation UploadModernAssistant($input: UploadModernAssistantInput!)"
440
487
  "{\n uploadModernAssistant(input: $input)\n}"
441
488
  ),
442
- "variables": {
443
- "input": {
444
- "assistantName": assistant_name,
445
- "domain": base64_domain,
446
- "flows": base64_flows,
447
- "nlu": base64_nlu,
448
- "config": base64_config,
449
- "endpoints": base64_endpoints,
450
- }
451
- },
489
+ "variables": {"input": variables_input},
452
490
  }
453
491
 
454
492
  return graphql_req
455
493
 
456
494
 
495
+ def convert_string_to_base64(string: str) -> str:
496
+ """Converts a string to base64.
497
+
498
+ Args:
499
+ string: The string to convert
500
+
501
+ Returns:
502
+ The base64 encoded string
503
+ """
504
+ return base64.b64encode(string.encode("utf-8")).decode("utf-8")
505
+
506
+
457
507
  def build_request(
458
508
  assistant_name: str, nlu_examples_yaml: str, domain_yaml: str
459
509
  ) -> Dict: