rasa-pro 3.13.0.dev20250613__py3-none-any.whl → 3.13.0rc2__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 (160) hide show
  1. rasa/cli/e2e_test.py +0 -7
  2. rasa/cli/export.py +2 -0
  3. rasa/cli/project_templates/tutorial/config.yml +1 -1
  4. rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
  5. rasa/cli/studio/download.py +1 -23
  6. rasa/cli/studio/link.py +0 -17
  7. rasa/cli/studio/pull.py +3 -2
  8. rasa/cli/studio/push.py +1 -1
  9. rasa/cli/studio/train.py +1 -5
  10. rasa/cli/studio/upload.py +1 -1
  11. rasa/core/agent.py +6 -0
  12. rasa/core/channels/__init__.py +3 -0
  13. rasa/core/channels/development_inspector.py +1 -1
  14. rasa/core/channels/facebook.py +1 -4
  15. rasa/core/channels/inspector/README.md +3 -3
  16. rasa/core/channels/inspector/dist/assets/{arc-c4b064fc.js → arc-371401b1.js} +1 -1
  17. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-215b5026.js → blockDiagram-38ab4fdb-3f126156.js} +1 -1
  18. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-2b54a0a3.js → c4Diagram-3d4e48cf-12f22eb7.js} +1 -1
  19. rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +1 -0
  20. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-daacea5f.js → classDiagram-70f12bd4-03b1d386.js} +1 -1
  21. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-930d4dc2.js → classDiagram-v2-f2320105-84f69d63.js} +1 -1
  22. rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +1 -0
  23. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-83c206ba.js → createText-2e5e7dd3-ca47fd38.js} +1 -1
  24. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-b0eb01d0.js → edges-e0da2a9e-f837ca8a.js} +1 -1
  25. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-17586500.js → erDiagram-9861fffd-8717ac54.js} +1 -1
  26. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-be2a1776.js → flowDb-956e92f1-94f38b83.js} +1 -1
  27. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-c2120ebd.js → flowDiagram-66a62f08-b616f9fb.js} +1 -1
  28. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +1 -0
  29. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-a6ab5c48.js → flowchart-elk-definition-4a651766-f5d24bb8.js} +1 -1
  30. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-ef613457.js → ganttDiagram-c361ad54-b43ba8d9.js} +1 -1
  31. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-d59185b3.js → gitGraphDiagram-72cf32ee-c3aafaa5.js} +1 -1
  32. rasa/core/channels/inspector/dist/assets/{graph-0f155405.js → graph-0d0a2c10.js} +1 -1
  33. rasa/core/channels/inspector/dist/assets/{index-3862675e-d5f1d1b7.js → index-3862675e-58ea0305.js} +1 -1
  34. rasa/core/channels/inspector/dist/assets/{index-47737d3a.js → index-cce6f8a1.js} +3 -3
  35. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-b07d141f.js → infoDiagram-f8f76790-b8f60461.js} +1 -1
  36. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-1936d429.js → journeyDiagram-49397b02-95be5545.js} +1 -1
  37. rasa/core/channels/inspector/dist/assets/{layout-dde8d0f3.js → layout-da885b9b.js} +1 -1
  38. rasa/core/channels/inspector/dist/assets/{line-0c2c7ee0.js → line-f1c817d3.js} +1 -1
  39. rasa/core/channels/inspector/dist/assets/{linear-35dd89a4.js → linear-d42801e6.js} +1 -1
  40. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-56192851.js → mindmap-definition-fc14e90a-a38923a6.js} +1 -1
  41. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-fc21ed78.js → pieDiagram-8a3498a8-ca6e71e9.js} +1 -1
  42. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-25e98518.js → quadrantDiagram-120e2f19-b290dae9.js} +1 -1
  43. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-546ff1f5.js → requirementDiagram-deff3bca-03f02ceb.js} +1 -1
  44. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-02d8b82d.js → sankeyDiagram-04a897e0-c49eee40.js} +1 -1
  45. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3ca5a92e.js → sequenceDiagram-704730f1-b2cd6a3d.js} +1 -1
  46. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-128ea07c.js → stateDiagram-587899a1-e53a2028.js} +1 -1
  47. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-95f290af.js → stateDiagram-v2-d93cdb3a-e1982a03.js} +1 -1
  48. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-4984898a.js → styles-6aaf32cf-d0226ca5.js} +1 -1
  49. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1bf266ba.js → styles-9a916d00-0e21dc00.js} +1 -1
  50. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-60521c63.js → styles-c10674c1-9588494e.js} +1 -1
  51. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-a25b6e12.js → svgDrawCommon-08f97a94-be478d4f.js} +1 -1
  52. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-0fc086bf.js → timeline-definition-85554ec2-74631749.js} +1 -1
  53. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-44ee592e.js → xychartDiagram-e933f94c-a043552f.js} +1 -1
  54. rasa/core/channels/inspector/dist/index.html +1 -1
  55. rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +1 -1
  56. rasa/core/channels/socketio.py +56 -41
  57. rasa/core/channels/studio_chat.py +311 -8
  58. rasa/core/channels/voice_ready/audiocodes.py +1 -1
  59. rasa/core/channels/voice_ready/jambonz.py +5 -6
  60. rasa/core/channels/voice_ready/twilio_voice.py +13 -12
  61. rasa/core/channels/voice_ready/utils.py +22 -0
  62. rasa/core/channels/voice_stream/asr/azure.py +9 -0
  63. rasa/core/channels/voice_stream/audiocodes.py +5 -11
  64. rasa/core/channels/voice_stream/browser_audio.py +1 -1
  65. rasa/core/channels/voice_stream/genesys.py +35 -16
  66. rasa/core/channels/voice_stream/jambonz.py +232 -0
  67. rasa/core/channels/voice_stream/tts/__init__.py +8 -0
  68. rasa/core/channels/voice_stream/twilio_media_streams.py +12 -7
  69. rasa/core/channels/voice_stream/voice_channel.py +53 -15
  70. rasa/core/exporter.py +36 -0
  71. rasa/core/information_retrieval/faiss.py +18 -11
  72. rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
  73. rasa/core/nlg/contextual_response_rephraser.py +10 -1
  74. rasa/core/policies/enterprise_search_policy.py +189 -263
  75. rasa/core/policies/enterprise_search_policy_config.py +241 -0
  76. rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +6 -5
  77. rasa/core/policies/intentless_policy.py +47 -10
  78. rasa/core/processor.py +6 -0
  79. rasa/core/utils.py +11 -2
  80. rasa/dialogue_understanding/coexistence/llm_based_router.py +13 -11
  81. rasa/dialogue_understanding/commands/__init__.py +4 -0
  82. rasa/dialogue_understanding/commands/cancel_flow_command.py +4 -2
  83. rasa/dialogue_understanding/commands/clarify_command.py +2 -2
  84. rasa/dialogue_understanding/commands/correct_slots_command.py +5 -6
  85. rasa/dialogue_understanding/commands/error_command.py +1 -1
  86. rasa/dialogue_understanding/commands/human_handoff_command.py +1 -3
  87. rasa/dialogue_understanding/commands/set_slot_command.py +4 -4
  88. rasa/dialogue_understanding/commands/skip_question_command.py +1 -3
  89. rasa/dialogue_understanding/commands/start_flow_command.py +3 -3
  90. rasa/dialogue_understanding/generator/command_generator.py +11 -1
  91. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +3 -2
  92. rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
  93. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +0 -2
  94. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -0
  95. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +1 -0
  96. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +79 -0
  97. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +1 -0
  98. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +2 -2
  99. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +2 -18
  100. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +17 -11
  101. rasa/dialogue_understanding/patterns/cancel.py +1 -2
  102. rasa/dialogue_understanding/patterns/clarify.py +1 -1
  103. rasa/dialogue_understanding/patterns/correction.py +2 -2
  104. rasa/dialogue_understanding/processor/command_processor.py +11 -12
  105. rasa/dialogue_understanding/stack/utils.py +3 -1
  106. rasa/e2e_test/constants.py +1 -1
  107. rasa/e2e_test/e2e_test_coverage_report.py +1 -1
  108. rasa/engine/graph.py +2 -2
  109. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +2 -6
  110. rasa/model_manager/runner_service.py +20 -4
  111. rasa/model_manager/trainer_service.py +6 -0
  112. rasa/privacy/privacy_manager.py +26 -11
  113. rasa/shared/constants.py +14 -0
  114. rasa/shared/core/command_payload_reader.py +1 -5
  115. rasa/shared/core/events.py +1 -3
  116. rasa/shared/core/flows/constants.py +2 -0
  117. rasa/shared/core/flows/flow.py +126 -12
  118. rasa/shared/core/flows/flows_list.py +18 -1
  119. rasa/shared/core/flows/steps/link.py +7 -2
  120. rasa/shared/core/flows/validation.py +25 -5
  121. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
  122. rasa/shared/providers/_configs/azure_openai_client_config.py +2 -2
  123. rasa/shared/providers/_configs/default_litellm_client_config.py +1 -1
  124. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -1
  125. rasa/shared/providers/_configs/openai_client_config.py +1 -1
  126. rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -1
  127. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -1
  128. rasa/shared/providers/_configs/utils.py +0 -99
  129. rasa/shared/utils/common.py +1 -1
  130. rasa/shared/utils/configs.py +110 -0
  131. rasa/shared/utils/constants.py +0 -3
  132. rasa/shared/utils/llm.py +123 -8
  133. rasa/shared/utils/pykwalify_extensions.py +0 -9
  134. rasa/studio/constants.py +1 -0
  135. rasa/studio/data_handler.py +30 -9
  136. rasa/studio/download.py +171 -0
  137. rasa/studio/link.py +13 -2
  138. rasa/studio/prompts.py +221 -0
  139. rasa/studio/pull/__init__.py +0 -0
  140. rasa/studio/{download/flows.py → pull/data.py} +2 -131
  141. rasa/studio/{download → pull}/domains.py +1 -1
  142. rasa/studio/pull/pull.py +239 -0
  143. rasa/studio/push.py +7 -0
  144. rasa/studio/train.py +1 -1
  145. rasa/studio/upload.py +61 -5
  146. rasa/studio/utils.py +33 -0
  147. rasa/tracing/instrumentation/attribute_extractors.py +21 -7
  148. rasa/utils/common.py +11 -0
  149. rasa/version.py +1 -1
  150. {rasa_pro-3.13.0.dev20250613.dist-info → rasa_pro-3.13.0rc2.dist-info}/METADATA +4 -4
  151. {rasa_pro-3.13.0.dev20250613.dist-info → rasa_pro-3.13.0rc2.dist-info}/RECORD +155 -147
  152. rasa/core/channels/inspector/dist/assets/channel-3730f5fd.js +0 -1
  153. rasa/core/channels/inspector/dist/assets/clone-e847561e.js +0 -1
  154. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-efbbfe00.js +0 -1
  155. rasa/studio/download/download.py +0 -416
  156. rasa/studio/pull.py +0 -94
  157. /rasa/{studio/download → core/information_retrieval/ingestion}/__init__.py +0 -0
  158. {rasa_pro-3.13.0.dev20250613.dist-info → rasa_pro-3.13.0rc2.dist-info}/NOTICE +0 -0
  159. {rasa_pro-3.13.0.dev20250613.dist-info → rasa_pro-3.13.0rc2.dist-info}/WHEEL +0 -0
  160. {rasa_pro-3.13.0.dev20250613.dist-info → rasa_pro-3.13.0rc2.dist-info}/entry_points.txt +0 -0
@@ -384,7 +384,7 @@ def display_research_study_prompt() -> None:
384
384
  {separator}
385
385
  Want to help shape the future of Rasa Pro?
386
386
  Share your feedback in a short conversation with our team.
387
- Sign up at: https://calendly.com/alvaro-rasa/rasa-pro-installation
387
+ Sign up at: https://feedback.rasa.com
388
388
  {separator}
389
389
  """
390
390
  print_success(message)
@@ -0,0 +1,110 @@
1
+ from typing import Optional
2
+
3
+ import structlog
4
+
5
+ from rasa.shared.utils.io import raise_deprecation_warning
6
+
7
+ structlogger = structlog.get_logger()
8
+
9
+
10
+ def resolve_aliases(config: dict, deprecated_alias_mapping: dict) -> dict:
11
+ """
12
+ Resolve aliases in the configuration to standard keys.
13
+
14
+ Args:
15
+ config: Dictionary containing the configuration.
16
+ deprecated_alias_mapping: Dictionary mapping aliases to
17
+ their standard keys.
18
+
19
+ Returns:
20
+ New dictionary containing the processed configuration.
21
+ """
22
+ config = config.copy()
23
+
24
+ for alias, standard_key in deprecated_alias_mapping.items():
25
+ # We check for the alias instead of the standard key because our goal is to
26
+ # update the standard key when the alias is found. Since the standard key is
27
+ # always included in the default component configurations, we overwrite it
28
+ # with the alias value if the alias exists.
29
+ if alias in config:
30
+ config[standard_key] = config.pop(alias)
31
+
32
+ return config
33
+
34
+
35
+ def raise_deprecation_warnings(
36
+ config: dict,
37
+ deprecated_alias_mapping: dict,
38
+ source: Optional[str] = None,
39
+ ) -> None:
40
+ """
41
+ Raises warnings for deprecated keys in the configuration.
42
+
43
+ Args:
44
+ config: Dictionary containing the configuration.
45
+ deprecated_alias_mapping: Dictionary mapping deprecated keys to
46
+ their standard keys.
47
+
48
+ Raises:
49
+ DeprecationWarning: If any deprecated key is found in the config.
50
+ """
51
+ for alias, standard_key in deprecated_alias_mapping.items():
52
+ if alias in config:
53
+ source = f"{source}: " or ""
54
+ raise_deprecation_warning(
55
+ message=(
56
+ f"{source}"
57
+ f"'{alias}' is deprecated and will be removed in "
58
+ f"4.0.0. Use '{standard_key}' instead."
59
+ )
60
+ )
61
+
62
+
63
+ def validate_required_keys(config: dict, required_keys: list) -> None:
64
+ """
65
+ Validates that the passed config contains all the required keys.
66
+
67
+ Args:
68
+ config: Dictionary containing the configuration.
69
+ required_keys: List of keys that must be present in the config.
70
+
71
+ Raises:
72
+ ValueError: If any required key is missing.
73
+ """
74
+ missing_keys = [key for key in required_keys if key not in config]
75
+ if missing_keys:
76
+ message = f"Missing required keys '{missing_keys}' for configuration."
77
+ structlogger.error(
78
+ "validate_required_keys",
79
+ message=message,
80
+ missing_keys=missing_keys,
81
+ config=config,
82
+ )
83
+ raise ValueError(message)
84
+
85
+
86
+ def validate_forbidden_keys(config: dict, forbidden_keys: list) -> None:
87
+ """
88
+ Validates that the passed config doesn't contain any forbidden keys.
89
+
90
+ Args:
91
+ config: Dictionary containing the configuration.
92
+ forbidden_keys: List of keys that are forbidden in the config.
93
+
94
+ Raises:
95
+ ValueError: If any forbidden key is present.
96
+ """
97
+ forbidden_keys_in_config = set(config.keys()).intersection(set(forbidden_keys))
98
+
99
+ if forbidden_keys_in_config:
100
+ message = (
101
+ f"Forbidden keys '{forbidden_keys_in_config}' present "
102
+ f"in the configuration."
103
+ )
104
+ structlogger.error(
105
+ "validate_forbidden_keys",
106
+ message=message,
107
+ forbidden_keys=forbidden_keys_in_config,
108
+ config=config,
109
+ )
110
+ raise ValueError(message)
@@ -2,9 +2,6 @@ DEFAULT_ENCODING = "utf-8"
2
2
 
3
3
  READ_YAML_FILE_CACHE_MAXSIZE_ENV_VAR = "READ_YAML_FILE_CACHE_MAXSIZE"
4
4
  DEFAULT_READ_YAML_FILE_CACHE_MAXSIZE = 256
5
- RASA_PRO_BETA_PREDICATES_IN_RESPONSE_CONDITIONS_ENV_VAR_NAME = (
6
- "RASA_PRO_BETA_PREDICATES_IN_RESPONSE_CONDITIONS"
7
- )
8
5
 
9
6
  LOG_COMPONENT_SOURCE_METHOD_INIT = "init"
10
7
  LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON = "fingerprint_addon"
rasa/shared/utils/llm.py CHANGED
@@ -6,6 +6,7 @@ import logging
6
6
  from copy import deepcopy
7
7
  from datetime import datetime
8
8
  from functools import wraps
9
+ from pathlib import Path
9
10
  from typing import (
10
11
  TYPE_CHECKING,
11
12
  Any,
@@ -24,6 +25,9 @@ from typing import (
24
25
  import structlog
25
26
  from pydantic import BaseModel, Field
26
27
 
28
+ import rasa.cli.telemetry
29
+ import rasa.cli.utils
30
+ import rasa.shared.utils.cli
27
31
  import rasa.shared.utils.io
28
32
  from rasa.core.available_endpoints import AvailableEndpoints
29
33
  from rasa.shared.constants import (
@@ -31,12 +35,15 @@ from rasa.shared.constants import (
31
35
  CONFIG_PIPELINE_KEY,
32
36
  CONFIG_POLICIES_KEY,
33
37
  DEFAULT_PROMPT_PACKAGE_NAME,
38
+ ENDPOINTS_NLG_KEY,
34
39
  LLM_CONFIG_KEY,
35
40
  MODEL_CONFIG_KEY,
36
41
  MODEL_GROUP_CONFIG_KEY,
37
42
  MODEL_GROUP_ID_CONFIG_KEY,
38
43
  MODEL_GROUPS_CONFIG_KEY,
39
44
  MODELS_CONFIG_KEY,
45
+ PROMPT_CONFIG_KEY,
46
+ PROMPT_TEMPLATE_CONFIG_KEY,
40
47
  PROVIDER_CONFIG_KEY,
41
48
  RASA_PATTERN_INTERNAL_ERROR_USER_INPUT_EMPTY,
42
49
  RASA_PATTERN_INTERNAL_ERROR_USER_INPUT_TOO_LONG,
@@ -85,13 +92,15 @@ USER = "USER"
85
92
 
86
93
  AI = "AI"
87
94
 
88
- DEFAULT_OPENAI_GENERATE_MODEL_NAME = "gpt-3.5-turbo"
95
+ DEFAULT_OPENAI_GENERATE_MODEL_NAME = "gpt-4o-2024-11-20"
89
96
 
90
- DEFAULT_OPENAI_CHAT_MODEL_NAME = "gpt-3.5-turbo"
97
+ DEFAULT_OPENAI_CHAT_MODEL_NAME = "gpt-4o-2024-11-20"
98
+
99
+ DEFAULT_ENTERPRISE_SEARCH_POLICY_MODEL_NAME = "gpt-4.1-mini-2025-04-14"
91
100
 
92
101
  DEFAULT_OPENAI_CHAT_MODEL_NAME_ADVANCED = "gpt-4-0613"
93
102
 
94
- DEFAULT_OPENAI_EMBEDDING_MODEL_NAME = "text-embedding-ada-002"
103
+ DEFAULT_OPENAI_EMBEDDING_MODEL_NAME = "text-embedding-3-large"
95
104
 
96
105
  DEFAULT_OPENAI_TEMPERATURE = 0.7
97
106
 
@@ -574,7 +583,7 @@ def embedder_factory(
574
583
  ```
575
584
  {
576
585
  "provider": "openai",
577
- "model": "text-embedding-3-small",
586
+ "model": "text-embedding-3-large",
578
587
  "timeout": 10,
579
588
  "num_retries": 3,
580
589
  }
@@ -587,7 +596,7 @@ def embedder_factory(
587
596
  "models": [
588
597
  {
589
598
  "provider": "openai",
590
- "model": "test-embedding-3-small",
599
+ "model": "test-embedding-3-large",
591
600
  "api_key": "test"
592
601
  },
593
602
  ],
@@ -950,6 +959,34 @@ async def create_tracker_for_user_step(
950
959
  await agent.tracker_store.save(tracker)
951
960
 
952
961
 
962
+ def check_prompt_config_keys_and_warn_if_deprecated(
963
+ config: dict, component_source: str
964
+ ) -> None:
965
+ """Checks and warns about deprecated config parameters."""
966
+ if PROMPT_CONFIG_KEY in config and PROMPT_TEMPLATE_CONFIG_KEY in config:
967
+ structlogger.warning(
968
+ f"{component_source}.init"
969
+ ".both_deprecated_and_non_deprecated_config_keys_used_at_the_same_time",
970
+ event_info=(
971
+ f"Both '{PROMPT_CONFIG_KEY}' and '{PROMPT_TEMPLATE_CONFIG_KEY}' "
972
+ f"are present in the config. '{PROMPT_CONFIG_KEY}' will be ignored "
973
+ f"in favor of {PROMPT_TEMPLATE_CONFIG_KEY}."
974
+ ),
975
+ )
976
+
977
+ # 'prompt' config key is deprecated in favor of 'prompt_template'
978
+ if PROMPT_CONFIG_KEY in config:
979
+ structlogger.warning(
980
+ f"{component_source}.init.deprecated_config_key",
981
+ event_info=(
982
+ f"The config parameter '{PROMPT_CONFIG_KEY}' is deprecated "
983
+ "and will be removed in Rasa 4.0.0. "
984
+ f"Please use the config parameter '{PROMPT_TEMPLATE_CONFIG_KEY}'"
985
+ f" instead. "
986
+ ),
987
+ )
988
+
989
+
953
990
  def _get_llm_command_generator_config(
954
991
  config: Dict[Text, Any],
955
992
  ) -> Optional[Dict[Text, Any]]:
@@ -994,7 +1031,7 @@ def _get_command_generator_prompt(
994
1031
  model_groups=endpoints.get(MODEL_GROUPS_CONFIG_KEY),
995
1032
  )
996
1033
  return get_default_prompt_template_based_on_model(
997
- llm_config=llm_config,
1034
+ llm_config=llm_config or {},
998
1035
  model_prompt_mapping=MODEL_PROMPT_MAPPER,
999
1036
  default_prompt_path=DEFAULT_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
1000
1037
  fallback_prompt_path=FALLBACK_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
@@ -1022,8 +1059,7 @@ def _get_enterprise_search_prompt(config: Dict[Text, Any]) -> Text:
1022
1059
  def get_system_default_prompts(
1023
1060
  config: Dict[Text, Any], endpoints: Dict[Text, Any]
1024
1061
  ) -> SystemPrompts:
1025
- """
1026
- Returns the system default prompts for the component.
1062
+ """Returns the system default prompts for the component.
1027
1063
 
1028
1064
  Args:
1029
1065
  config: The config.yml file data.
@@ -1041,3 +1077,82 @@ def get_system_default_prompts(
1041
1077
  enterprise_search=_get_enterprise_search_prompt(config),
1042
1078
  contextual_response_rephraser=DEFAULT_RESPONSE_VARIATION_PROMPT_TEMPLATE,
1043
1079
  )
1080
+
1081
+
1082
+ def collect_custom_prompts(
1083
+ config: Dict[Text, Any],
1084
+ endpoints: Dict[Text, Any],
1085
+ project_root: Optional[Path] = None,
1086
+ ) -> Dict[Text, Text]:
1087
+ """Collects custom prompts from the project configuration and endpoints.
1088
+
1089
+ Args:
1090
+ config: The configuration dictionary of the project.
1091
+ endpoints: The endpoints configuration dictionary.
1092
+ project_root: The root directory of the project.
1093
+
1094
+ Returns:
1095
+ A dictionary containing custom prompts.
1096
+ The keys are:
1097
+ - 'contextual_response_rephraser'
1098
+ - 'command_generator'
1099
+ - 'enterprise_search'
1100
+ """
1101
+ from rasa.core.policies.enterprise_search_policy import EnterpriseSearchPolicy
1102
+ from rasa.dialogue_understanding.generator.llm_based_command_generator import (
1103
+ LLMBasedCommandGenerator,
1104
+ )
1105
+ from rasa.studio.prompts import (
1106
+ COMMAND_GENERATOR_NAME,
1107
+ CONTEXTUAL_RESPONSE_REPHRASER_NAME,
1108
+ ENTERPRISE_SEARCH_NAME,
1109
+ )
1110
+
1111
+ prompts: Dict[Text, Text] = {}
1112
+ project_root = project_root or Path(".").resolve()
1113
+
1114
+ def _read_prompt(root: Path, path_in_yaml: Text) -> Optional[Text]:
1115
+ if not path_in_yaml:
1116
+ return None
1117
+
1118
+ prompt_path = (
1119
+ (root / path_in_yaml).resolve()
1120
+ if not Path(path_in_yaml).is_absolute()
1121
+ else Path(path_in_yaml)
1122
+ )
1123
+ if prompt_path.exists():
1124
+ return prompt_path.read_text(encoding="utf-8")
1125
+
1126
+ structlogger.warning(
1127
+ "utils.llm.collect_custom_prompts.prompt_not_found",
1128
+ event_info=(f"Prompt file '{prompt_path}' not found. "),
1129
+ prompt_path=prompt_path,
1130
+ project_root=root,
1131
+ )
1132
+ return None
1133
+
1134
+ # contextual_response_rephraser
1135
+ nlg_conf = endpoints.get(ENDPOINTS_NLG_KEY) or {}
1136
+ if prompt_text := _read_prompt(project_root, nlg_conf.get(PROMPT_CONFIG_KEY)):
1137
+ prompts[CONTEXTUAL_RESPONSE_REPHRASER_NAME] = prompt_text
1138
+
1139
+ # command_generator
1140
+ command_generator_classes = {
1141
+ cls.__name__ for cls in all_subclasses(LLMBasedCommandGenerator)
1142
+ }
1143
+ for component in config.get(CONFIG_PIPELINE_KEY, []):
1144
+ if component.get(CONFIG_NAME_KEY) in command_generator_classes:
1145
+ if prompt_text := _read_prompt(
1146
+ project_root, component.get(PROMPT_TEMPLATE_CONFIG_KEY)
1147
+ ):
1148
+ prompts[COMMAND_GENERATOR_NAME] = prompt_text
1149
+ break
1150
+
1151
+ # enterprise_search
1152
+ for policy in config.get(CONFIG_POLICIES_KEY, []):
1153
+ if policy.get(CONFIG_NAME_KEY) == EnterpriseSearchPolicy.__name__:
1154
+ if prompt_text := _read_prompt(project_root, policy.get(PROMPT_CONFIG_KEY)):
1155
+ prompts[ENTERPRISE_SEARCH_NAME] = prompt_text
1156
+ break
1157
+
1158
+ return prompts
@@ -8,11 +8,6 @@ from typing import Any, Dict, List, Text, Union
8
8
 
9
9
  from pykwalify.errors import SchemaError
10
10
 
11
- from rasa.shared.utils.constants import (
12
- RASA_PRO_BETA_PREDICATES_IN_RESPONSE_CONDITIONS_ENV_VAR_NAME,
13
- )
14
- from rasa.utils.beta import ensure_beta_feature_is_enabled
15
-
16
11
 
17
12
  def require_response_keys(
18
13
  responses: List[Dict[Text, Any]], _: Dict, __: Text
@@ -31,10 +26,6 @@ def require_response_keys(
31
26
 
32
27
  conditions = response.get("condition", [])
33
28
  if isinstance(conditions, str):
34
- ensure_beta_feature_is_enabled(
35
- "predicates in response conditions",
36
- RASA_PRO_BETA_PREDICATES_IN_RESPONSE_CONDITIONS_ENV_VAR_NAME,
37
- )
38
29
  continue
39
30
 
40
31
  for condition in conditions:
rasa/studio/constants.py CHANGED
@@ -14,6 +14,7 @@ RASA_STUDIO_CLI_DISABLE_VERIFY_KEY_ENV = "RASA_STUDIO_CLI_DISABLE_VERIFY_KEY"
14
14
 
15
15
  STUDIO_NLU_FILENAME = "studio_nlu.yml"
16
16
  STUDIO_DOMAIN_FILENAME = "studio_domain.yml"
17
+ DOMAIN_FILENAME = "domain.yml"
17
18
  STUDIO_FLOWS_FILENAME = "studio_flows.yml"
18
19
  STUDIO_CONFIG_FILENAME = "studio_config.yml"
19
20
  STUDIO_ENDPOINTS_FILENAME = "studio_endpoints.yml"
@@ -45,15 +45,33 @@ class StudioDataHandler:
45
45
  intent_names: Optional[List[str]] = None,
46
46
  entity_names: Optional[List[str]] = None,
47
47
  ) -> dict:
48
+ from rasa.studio.prompts import (
49
+ COMMAND_GENERATOR_NAME,
50
+ CONTEXTUAL_RESPONSE_REPHRASER_NAME,
51
+ ENTERPRISE_SEARCH_NAME,
52
+ )
53
+
48
54
  request = {
49
- "query": (
50
- "query ExportAsEncodedYaml($input: ExportAsEncodedYamlInput!) "
51
- "{ exportAsEncodedYaml(input: $input) "
52
- "{ ... on ExportModernAsEncodedYamlOutput "
53
- "{ nlu flows domain endpoints config } "
54
- "... on ExportClassicAsEncodedYamlOutput "
55
- "{ nlu domain }}}"
56
- ),
55
+ "query": "query ExportAsEncodedYaml($input: ExportAsEncodedYamlInput!) {\n"
56
+ " exportAsEncodedYaml(input: $input) {\n"
57
+ " ... on ExportModernAsEncodedYamlOutput {\n"
58
+ " nlu\n"
59
+ " flows\n"
60
+ " domain\n"
61
+ " endpoints\n"
62
+ " config\n"
63
+ " prompts {\n"
64
+ f" {COMMAND_GENERATOR_NAME}\n"
65
+ f" {CONTEXTUAL_RESPONSE_REPHRASER_NAME}\n"
66
+ f" {ENTERPRISE_SEARCH_NAME}\n"
67
+ " }\n"
68
+ " }\n"
69
+ " ... on ExportClassicAsEncodedYamlOutput {\n"
70
+ " nlu\n"
71
+ " domain\n"
72
+ " }\n"
73
+ " }\n"
74
+ "}\n",
57
75
  "variables": {"input": {"assistantName": self.assistant_name}},
58
76
  }
59
77
  if intent_names or entity_names:
@@ -97,7 +115,6 @@ class StudioDataHandler:
97
115
  },
98
116
  verify=verify,
99
117
  )
100
-
101
118
  if res.status_code != 200:
102
119
  raise RasaException(
103
120
  f"Download from Studio with URL: "
@@ -161,6 +178,9 @@ class StudioDataHandler:
161
178
  def get_endpoints(self) -> Optional[str]:
162
179
  return self.endpoints
163
180
 
181
+ def get_prompts(self) -> Optional[dict]:
182
+ return self.prompts
183
+
164
184
  def _validate_response(self, response: dict) -> bool:
165
185
  """Validates the response from Rasa Studio.
166
186
 
@@ -199,6 +219,7 @@ class StudioDataHandler:
199
219
  self.flows = self._decode_response(return_data.get("flows"))
200
220
  self.config = self._decode_response(return_data.get("config"))
201
221
  self.endpoints = self._decode_response(return_data.get("endpoints"))
222
+ self.prompts = return_data.get("prompts")
202
223
 
203
224
  if not self.has_nlu() and not self.has_flows():
204
225
  raise RasaException("No nlu or flows data in Studio response.")
@@ -0,0 +1,171 @@
1
+ import argparse
2
+ import shutil
3
+ from pathlib import Path
4
+ from typing import Dict
5
+
6
+ import questionary
7
+ import structlog
8
+ from ruamel import yaml
9
+ from ruamel.yaml.scalarstring import LiteralScalarString
10
+
11
+ import rasa.cli.utils
12
+ import rasa.shared.utils.cli
13
+ from rasa.shared.constants import (
14
+ DEFAULT_CONFIG_PATH,
15
+ DEFAULT_DATA_PATH,
16
+ DEFAULT_ENDPOINTS_PATH,
17
+ )
18
+ from rasa.shared.core.flows.yaml_flows_io import FlowsList
19
+ from rasa.shared.nlu.training_data.training_data import (
20
+ DEFAULT_TRAINING_DATA_OUTPUT_PATH,
21
+ )
22
+ from rasa.shared.utils.yaml import read_yaml, write_yaml
23
+ from rasa.studio.config import StudioConfig
24
+ from rasa.studio.constants import DOMAIN_FILENAME
25
+ from rasa.studio.data_handler import StudioDataHandler
26
+ from rasa.studio.prompts import handle_prompts
27
+ from rasa.studio.pull.data import _dump_flows_as_separate_files
28
+ from rasa.studio.utils import validate_argument_paths
29
+
30
+ structlogger = structlog.get_logger()
31
+
32
+
33
+ def handle_download(args: argparse.Namespace) -> None:
34
+ """Download an assistant from Studio and store it in `<assistant_name>/`.
35
+
36
+ Args:
37
+ args: The command line arguments.
38
+ """
39
+ validate_argument_paths(args)
40
+ assistant_name = args.assistant_name
41
+ target_root = _prepare_target_directory(assistant_name)
42
+
43
+ handler = StudioDataHandler(
44
+ studio_config=StudioConfig.read_config(), assistant_name=assistant_name
45
+ )
46
+ handler.request_all_data()
47
+
48
+ _handle_config(handler, target_root)
49
+ _handle_endpoints(handler, target_root)
50
+ _handle_domain(handler, target_root)
51
+ _handle_data(handler, target_root)
52
+
53
+ if prompts := handler.get_prompts():
54
+ handle_prompts(prompts, target_root)
55
+
56
+ structlogger.info(
57
+ "studio.download.success",
58
+ event_info=f"Downloaded assistant '{assistant_name}' from Studio.",
59
+ assistant_name=assistant_name,
60
+ )
61
+ rasa.shared.utils.cli.print_success(
62
+ f"Downloaded assistant '{assistant_name}' from Studio."
63
+ )
64
+
65
+
66
+ def _prepare_target_directory(assistant_name: str) -> Path:
67
+ """Create (or overwrite) the directory where everything is stored.
68
+
69
+ Args:
70
+ assistant_name: The name of the assistant to download.
71
+
72
+ Returns:
73
+ The path to the target directory where the assistant will be stored.
74
+ """
75
+ target_root = Path(assistant_name)
76
+
77
+ if target_root.exists():
78
+ overwrite = questionary.confirm(
79
+ f"Directory '{assistant_name}' already exists. Overwrite it?"
80
+ ).ask()
81
+ if not overwrite:
82
+ rasa.shared.utils.cli.print_error_and_exit("Download cancelled.")
83
+
84
+ shutil.rmtree(target_root)
85
+
86
+ target_root.mkdir(parents=True, exist_ok=True)
87
+ return target_root
88
+
89
+
90
+ def _handle_config(handler: StudioDataHandler, root: Path) -> None:
91
+ """Download and persist the assistant’s config file.
92
+
93
+ Args:
94
+ handler: The data handler to retrieve the config from.
95
+ root: The root directory where the config file will be stored.
96
+ """
97
+ config_data = handler.get_config()
98
+ if not config_data:
99
+ rasa.shared.utils.cli.print_error_and_exit("No config data found.")
100
+
101
+ config_path = root / DEFAULT_CONFIG_PATH
102
+ config_path.write_text(config_data, encoding="utf-8")
103
+
104
+
105
+ def _handle_endpoints(handler: StudioDataHandler, root: Path) -> None:
106
+ """Download and persist the assistant’s endpoints file.
107
+
108
+ Args:
109
+ handler: The data handler to retrieve the endpoints from.
110
+ root: The root directory where the endpoints file will be stored.
111
+ """
112
+ endpoints_data = handler.get_endpoints()
113
+ if not endpoints_data:
114
+ rasa.shared.utils.cli.print_error_and_exit("No endpoints data found.")
115
+
116
+ endpoints_path = root / DEFAULT_ENDPOINTS_PATH
117
+ endpoints_path.write_text(endpoints_data, encoding="utf-8")
118
+
119
+
120
+ def _handle_domain(handler: StudioDataHandler, root: Path) -> None:
121
+ """Persist the assistant’s domain file.
122
+
123
+ Args:
124
+ handler: The data handler to retrieve the domain from.
125
+ root: The root directory where the domain file will be stored.
126
+ """
127
+ domain_yaml = handler.domain
128
+ data = read_yaml(domain_yaml)
129
+ target = root / DOMAIN_FILENAME
130
+ write_yaml(
131
+ data=data,
132
+ target=target,
133
+ should_preserve_key_order=True,
134
+ )
135
+
136
+
137
+ def _handle_data(handler: StudioDataHandler, root: Path) -> None:
138
+ """Persist NLU data and flows.
139
+
140
+ Args:
141
+ handler: The data handler to retrieve the NLU data and flows from.
142
+ root: The root directory where the NLU data and flows will be stored.
143
+ """
144
+ data_path = root / DEFAULT_DATA_PATH
145
+ data_path.mkdir(parents=True, exist_ok=True)
146
+
147
+ if handler.has_nlu():
148
+ nlu_yaml = handler.nlu
149
+ nlu_data = read_yaml(nlu_yaml)
150
+ if nlu_data.get("nlu"):
151
+ pretty_write_nlu_yaml(
152
+ nlu_data, data_path / DEFAULT_TRAINING_DATA_OUTPUT_PATH
153
+ )
154
+
155
+ if handler.has_flows():
156
+ flows_yaml = handler.flows
157
+ data = read_yaml(flows_yaml)
158
+ flows_data = data.get("flows", {})
159
+ flows_list = FlowsList.from_json(flows_data)
160
+ _dump_flows_as_separate_files(flows_list.underlying_flows, data_path)
161
+
162
+
163
+ def pretty_write_nlu_yaml(data: Dict, file: Path) -> None:
164
+ """Writes the NLU YAML in a pretty way."""
165
+ dumper = yaml.YAML()
166
+ if nlu_data := data.get("nlu"):
167
+ for item in nlu_data:
168
+ if item.get("examples"):
169
+ item["examples"] = LiteralScalarString(item["examples"])
170
+ with file.open("w", encoding="utf-8") as outfile:
171
+ dumper.dump(data, outfile)
rasa/studio/link.py CHANGED
@@ -167,7 +167,7 @@ def handle_link(args: argparse.Namespace) -> None:
167
167
  Args:
168
168
  args: The command line arguments.
169
169
  """
170
- assistant_name: Text = args.assistant_name[0]
170
+ assistant_name: Text = args.assistant_name
171
171
  studio_cfg = get_studio_config()
172
172
  assistant_exists = _ensure_assistant_exists(assistant_name, studio_cfg, args)
173
173
  if not assistant_exists:
@@ -179,8 +179,19 @@ def handle_link(args: argparse.Namespace) -> None:
179
179
  link_file = _link_file(project_root)
180
180
 
181
181
  if link_file.exists():
182
+ linked_assistant_name = read_assistant_name(project_root)
183
+ if linked_assistant_name == assistant_name:
184
+ rasa.shared.utils.cli.print_info(
185
+ f"Project is already linked to assistant '{assistant_name}'."
186
+ )
187
+ sys.exit(0)
188
+
182
189
  overwrite = questionary.confirm(
183
- f"This project is already linked " f"(link file '{link_file}').\nOverwrite?"
190
+ f"Project is currently linked to the following Rasa Studio assistant:\n\n"
191
+ f" Assistant name: {linked_assistant_name}\n"
192
+ f" Studio URL: {studio_cfg.studio_url}\n"
193
+ f" Keycloak Auth URL: {studio_cfg.authentication_server_url}\n\n"
194
+ f"Do you want to overwrite it with the new assistant '{assistant_name}'?"
184
195
  ).ask()
185
196
  if not overwrite:
186
197
  rasa.shared.utils.cli.print_info(