rasa-pro 3.13.0rc1__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.
- rasa/cli/studio/link.py +0 -16
- rasa/cli/studio/train.py +1 -4
- rasa/cli/studio/upload.py +1 -1
- rasa/core/agent.py +6 -0
- rasa/core/channels/__init__.py +1 -0
- rasa/core/channels/voice_ready/jambonz.py +5 -6
- rasa/core/channels/voice_ready/twilio_voice.py +13 -12
- rasa/core/channels/voice_ready/utils.py +22 -0
- rasa/core/channels/voice_stream/audiocodes.py +4 -10
- rasa/core/channels/voice_stream/genesys.py +35 -16
- rasa/core/channels/voice_stream/jambonz.py +69 -3
- rasa/core/channels/voice_stream/twilio_media_streams.py +5 -7
- rasa/core/channels/voice_stream/voice_channel.py +39 -10
- rasa/core/policies/enterprise_search_policy.py +38 -2
- rasa/core/processor.py +6 -0
- rasa/dialogue_understanding/coexistence/llm_based_router.py +11 -0
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +3 -2
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +9 -0
- rasa/dialogue_understanding/processor/command_processor.py +3 -3
- rasa/e2e_test/constants.py +1 -1
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +1 -1
- rasa/model_manager/runner_service.py +20 -4
- rasa/model_manager/trainer_service.py +6 -0
- rasa/privacy/privacy_manager.py +26 -11
- rasa/shared/constants.py +2 -0
- rasa/shared/utils/llm.py +86 -2
- rasa/studio/data_handler.py +27 -13
- rasa/studio/download.py +5 -1
- rasa/studio/link.py +12 -1
- rasa/studio/prompts.py +5 -7
- rasa/studio/pull/pull.py +6 -2
- rasa/studio/push.py +2 -0
- rasa/studio/upload.py +61 -5
- rasa/studio/utils.py +33 -0
- rasa/tracing/instrumentation/attribute_extractors.py +1 -1
- rasa/version.py +1 -1
- {rasa_pro-3.13.0rc1.dist-info → rasa_pro-3.13.0rc2.dist-info}/METADATA +1 -1
- {rasa_pro-3.13.0rc1.dist-info → rasa_pro-3.13.0rc2.dist-info}/RECORD +41 -40
- {rasa_pro-3.13.0rc1.dist-info → rasa_pro-3.13.0rc2.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.0rc1.dist-info → rasa_pro-3.13.0rc2.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.0rc1.dist-info → rasa_pro-3.13.0rc2.dist-info}/entry_points.txt +0 -0
|
@@ -16,6 +16,7 @@ from rasa.shared.constants import (
|
|
|
16
16
|
PROMPT_CONFIG_KEY,
|
|
17
17
|
PROMPT_TEMPLATE_CONFIG_KEY,
|
|
18
18
|
)
|
|
19
|
+
from rasa.shared.utils.io import raise_deprecation_warning
|
|
19
20
|
from rasa.shared.utils.llm import (
|
|
20
21
|
check_prompt_config_keys_and_warn_if_deprecated,
|
|
21
22
|
get_prompt_template,
|
|
@@ -47,6 +48,14 @@ class SingleStepLLMCommandGenerator(SingleStepBasedLLMCommandGenerator):
|
|
|
47
48
|
prompt_template: Optional[Text] = None,
|
|
48
49
|
**kwargs: Any,
|
|
49
50
|
) -> None:
|
|
51
|
+
raise_deprecation_warning(
|
|
52
|
+
message=(
|
|
53
|
+
"Support for `SingleStepLLMCommandGenerator` will be removed in Rasa "
|
|
54
|
+
"`4.0.0`. Please modify your assistant's configuration to use the "
|
|
55
|
+
"`CompactLLMCommandGenerator` or `SearchReadyLLMCommandGenerator` "
|
|
56
|
+
"instead."
|
|
57
|
+
)
|
|
58
|
+
)
|
|
50
59
|
super().__init__(
|
|
51
60
|
config,
|
|
52
61
|
model_storage,
|
|
@@ -639,9 +639,9 @@ def clean_up_slot_command(
|
|
|
639
639
|
resulting_commands.append(command)
|
|
640
640
|
return resulting_commands
|
|
641
641
|
|
|
642
|
-
if (slot := tracker.slots.get(command.name)) is not None and
|
|
643
|
-
|
|
644
|
-
):
|
|
642
|
+
if (slot := tracker.slots.get(command.name)) is not None and str(
|
|
643
|
+
slot.value
|
|
644
|
+
) == str(command.value):
|
|
645
645
|
# the slot is already set, we don't need to set it again
|
|
646
646
|
structlogger.debug(
|
|
647
647
|
"command_processor.clean_up_slot_command.skip_command_slot_already_set",
|
rasa/e2e_test/constants.py
CHANGED
|
@@ -40,7 +40,7 @@ DEFAULT_GROUNDEDNESS_PROMPT_TEMPLATE_FILE_NAME = "groundedness_prompt_template.j
|
|
|
40
40
|
DEFAULT_ANSWER_RELEVANCE_PROMPT_TEMPLATE_FILE_NAME = (
|
|
41
41
|
"answer_relevance_prompt_template.jinja2"
|
|
42
42
|
)
|
|
43
|
-
DEFAULT_E2E_TESTING_MODEL = "gpt-
|
|
43
|
+
DEFAULT_E2E_TESTING_MODEL = "gpt-4.1-mini-2025-04-14"
|
|
44
44
|
KEY_SCORE = "score"
|
|
45
45
|
KEY_JUSTIFICATION = "justification"
|
|
46
46
|
KEY_EXTRA_PARAMETERS = "extra_parameters"
|
|
@@ -35,7 +35,7 @@ DEFAULT_REPHRASING_PROMPT_TEMPLATE = importlib.resources.read_text(
|
|
|
35
35
|
|
|
36
36
|
DEFAULT_LLM_CONFIG = {
|
|
37
37
|
PROVIDER_CONFIG_KEY: OPENAI_PROVIDER,
|
|
38
|
-
MODEL_CONFIG_KEY: "gpt-
|
|
38
|
+
MODEL_CONFIG_KEY: "gpt-4.1-mini-2025-04-14",
|
|
39
39
|
TIMEOUT_CONFIG_KEY: 7,
|
|
40
40
|
TEMPERATURE_CONFIG_KEY: 0.0,
|
|
41
41
|
MAX_COMPLETION_TOKENS_CONFIG_KEY: 4096,
|
|
@@ -2,7 +2,8 @@ import os
|
|
|
2
2
|
import shutil
|
|
3
3
|
import subprocess
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Dict, Optional, Union
|
|
6
7
|
|
|
7
8
|
import aiohttp
|
|
8
9
|
import structlog
|
|
@@ -18,6 +19,7 @@ from rasa.model_manager.utils import (
|
|
|
18
19
|
write_encoded_data_to_file,
|
|
19
20
|
)
|
|
20
21
|
from rasa.model_manager.warm_rasa_process import start_rasa_process
|
|
22
|
+
from rasa.studio.prompts import handle_prompts
|
|
21
23
|
|
|
22
24
|
structlogger = structlog.get_logger()
|
|
23
25
|
|
|
@@ -121,11 +123,25 @@ def get_open_port() -> int:
|
|
|
121
123
|
|
|
122
124
|
|
|
123
125
|
def write_encoded_config_data_to_files(
|
|
124
|
-
encoded_configs: Dict[str, bytes], base_path: str
|
|
126
|
+
encoded_configs: Dict[str, Union[bytes, Dict[str, str]]], base_path: str
|
|
125
127
|
) -> None:
|
|
126
128
|
"""Write the encoded config data to files."""
|
|
127
|
-
|
|
128
|
-
|
|
129
|
+
endpoints_encoded = encoded_configs.get("endpoints")
|
|
130
|
+
if endpoints_encoded:
|
|
131
|
+
write_encoded_data_to_file(
|
|
132
|
+
endpoints_encoded, subpath(base_path, "endpoints.yml")
|
|
133
|
+
)
|
|
134
|
+
config_encoded = encoded_configs.get("config")
|
|
135
|
+
if config_encoded:
|
|
136
|
+
write_encoded_data_to_file(config_encoded, subpath(base_path, "config.yml"))
|
|
137
|
+
credentials_encoded = encoded_configs.get("credentials")
|
|
138
|
+
if credentials_encoded:
|
|
139
|
+
write_encoded_data_to_file(
|
|
140
|
+
credentials_encoded, subpath(base_path, "credentials.yml")
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if prompts := encoded_configs.get("prompts"):
|
|
144
|
+
handle_prompts(prompts, Path(base_path))
|
|
129
145
|
|
|
130
146
|
|
|
131
147
|
def prepare_bot_directory(
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import shutil
|
|
3
3
|
import subprocess
|
|
4
4
|
from enum import Enum
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
from typing import Any, Dict, Optional
|
|
6
7
|
|
|
7
8
|
import structlog
|
|
@@ -20,6 +21,7 @@ from rasa.model_manager.warm_rasa_process import (
|
|
|
20
21
|
start_rasa_process,
|
|
21
22
|
)
|
|
22
23
|
from rasa.model_training import generate_random_model_name
|
|
24
|
+
from rasa.studio.prompts import handle_prompts
|
|
23
25
|
|
|
24
26
|
structlogger = structlog.get_logger()
|
|
25
27
|
|
|
@@ -208,6 +210,7 @@ def write_training_data_to_files(
|
|
|
208
210
|
"stories": "base64 encoded stories.yml",
|
|
209
211
|
"rules": "base64 encoded rules.yml",
|
|
210
212
|
"nlu": "base64 encoded nlu.yml"
|
|
213
|
+
"prompts": "dictionary with the prompts",
|
|
211
214
|
}
|
|
212
215
|
```
|
|
213
216
|
"""
|
|
@@ -230,6 +233,9 @@ def write_training_data_to_files(
|
|
|
230
233
|
subpath(training_base_path + "/" + parent_path, file_name),
|
|
231
234
|
)
|
|
232
235
|
|
|
236
|
+
if prompts := encoded_training_data.get("prompts"):
|
|
237
|
+
handle_prompts(prompts, Path(training_base_path))
|
|
238
|
+
|
|
233
239
|
|
|
234
240
|
def prepare_training_directory(
|
|
235
241
|
training_base_path: str, assistant_id: str, encoded_training_data: Dict[str, Any]
|
rasa/privacy/privacy_manager.py
CHANGED
|
@@ -12,7 +12,7 @@ import structlog
|
|
|
12
12
|
from apscheduler.schedulers.background import BackgroundScheduler
|
|
13
13
|
|
|
14
14
|
import rasa.shared.core.trackers
|
|
15
|
-
from rasa.core.tracker_stores.tracker_store import TrackerStore
|
|
15
|
+
from rasa.core.tracker_stores.tracker_store import FailSafeTrackerStore, TrackerStore
|
|
16
16
|
from rasa.privacy.constants import (
|
|
17
17
|
TEXT_KEY,
|
|
18
18
|
USER_CHAT_INACTIVITY_IN_MINUTES_ENV_VAR_NAME,
|
|
@@ -63,6 +63,7 @@ class BackgroundPrivacyManager:
|
|
|
63
63
|
self,
|
|
64
64
|
endpoints: Optional["AvailableEndpoints"],
|
|
65
65
|
event_loop: Optional["AbstractEventLoop"] = None,
|
|
66
|
+
in_memory_tracker_store: Optional[TrackerStore] = None,
|
|
66
67
|
):
|
|
67
68
|
self.config = (
|
|
68
69
|
PrivacyConfig.from_dict(endpoints.privacy)
|
|
@@ -76,15 +77,28 @@ class BackgroundPrivacyManager:
|
|
|
76
77
|
os.getenv(USER_CHAT_INACTIVITY_IN_MINUTES_ENV_VAR_NAME, 30)
|
|
77
78
|
)
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
if in_memory_tracker_store is not None:
|
|
81
|
+
# if an in-memory tracker store is provided,
|
|
82
|
+
# we need to keep the reference to it
|
|
83
|
+
# so that the background jobs can access it.
|
|
84
|
+
# We also set the event broker to None
|
|
85
|
+
# to prevent it from publishing events
|
|
86
|
+
# during the tracker store background jobs
|
|
87
|
+
in_memory_tracker_store.event_broker = None
|
|
88
|
+
tracker_store = in_memory_tracker_store
|
|
89
|
+
else:
|
|
90
|
+
# we recreate the tracker store here to ensure
|
|
91
|
+
# that this instance has no event brokers
|
|
92
|
+
# that could publish events during the tracker store
|
|
93
|
+
# background jobs
|
|
94
|
+
tracker_store = (
|
|
95
|
+
TrackerStore.create(endpoints.tracker_store)
|
|
96
|
+
if endpoints
|
|
97
|
+
else TrackerStore.create(None)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
self.tracker_store = FailSafeTrackerStore(tracker_store)
|
|
101
|
+
|
|
88
102
|
self.event_brokers: List["EventBroker"] = []
|
|
89
103
|
self.event_loop = event_loop
|
|
90
104
|
|
|
@@ -124,9 +138,10 @@ class BackgroundPrivacyManager:
|
|
|
124
138
|
cls,
|
|
125
139
|
endpoints: Optional["AvailableEndpoints"],
|
|
126
140
|
event_loop: Optional["AbstractEventLoop"] = None,
|
|
141
|
+
in_memory_tracker_store: Optional[TrackerStore] = None,
|
|
127
142
|
) -> BackgroundPrivacyManager:
|
|
128
143
|
"""Create an instance of BackgroundPrivacyManager."""
|
|
129
|
-
instance = cls(endpoints, event_loop)
|
|
144
|
+
instance = cls(endpoints, event_loop, in_memory_tracker_store)
|
|
130
145
|
return await instance.initialize(endpoints)
|
|
131
146
|
|
|
132
147
|
def stop(self) -> None:
|
rasa/shared/constants.py
CHANGED
|
@@ -104,6 +104,8 @@ UTTER_FREE_CHITCHAT_RESPONSE = "utter_free_chitchat_response"
|
|
|
104
104
|
ASSISTANT_ID_KEY = "assistant_id"
|
|
105
105
|
ASSISTANT_ID_DEFAULT_VALUE = "placeholder_default"
|
|
106
106
|
|
|
107
|
+
ENDPOINTS_NLG_KEY = "nlg"
|
|
108
|
+
|
|
107
109
|
CONFIG_MANDATORY_COMMON_KEYS = [ASSISTANT_ID_KEY]
|
|
108
110
|
CONFIG_NAME_KEY = "name"
|
|
109
111
|
CONFIG_POLICIES_KEY = "policies"
|
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,6 +35,7 @@ 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,
|
|
@@ -578,7 +583,7 @@ def embedder_factory(
|
|
|
578
583
|
```
|
|
579
584
|
{
|
|
580
585
|
"provider": "openai",
|
|
581
|
-
"model": "text-embedding-3-
|
|
586
|
+
"model": "text-embedding-3-large",
|
|
582
587
|
"timeout": 10,
|
|
583
588
|
"num_retries": 3,
|
|
584
589
|
}
|
|
@@ -591,7 +596,7 @@ def embedder_factory(
|
|
|
591
596
|
"models": [
|
|
592
597
|
{
|
|
593
598
|
"provider": "openai",
|
|
594
|
-
"model": "test-embedding-3-
|
|
599
|
+
"model": "test-embedding-3-large",
|
|
595
600
|
"api_key": "test"
|
|
596
601
|
},
|
|
597
602
|
],
|
|
@@ -1072,3 +1077,82 @@ def get_system_default_prompts(
|
|
|
1072
1077
|
enterprise_search=_get_enterprise_search_prompt(config),
|
|
1073
1078
|
contextual_response_rephraser=DEFAULT_RESPONSE_VARIATION_PROMPT_TEMPLATE,
|
|
1074
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
|
rasa/studio/data_handler.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import base64
|
|
2
|
-
import json
|
|
3
2
|
import logging
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
from typing import Any, Dict, List, Optional, Tuple
|
|
@@ -46,15 +45,33 @@ class StudioDataHandler:
|
|
|
46
45
|
intent_names: Optional[List[str]] = None,
|
|
47
46
|
entity_names: Optional[List[str]] = None,
|
|
48
47
|
) -> dict:
|
|
48
|
+
from rasa.studio.prompts import (
|
|
49
|
+
COMMAND_GENERATOR_NAME,
|
|
50
|
+
CONTEXTUAL_RESPONSE_REPHRASER_NAME,
|
|
51
|
+
ENTERPRISE_SEARCH_NAME,
|
|
52
|
+
)
|
|
53
|
+
|
|
49
54
|
request = {
|
|
50
|
-
"query": (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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",
|
|
58
75
|
"variables": {"input": {"assistantName": self.assistant_name}},
|
|
59
76
|
}
|
|
60
77
|
if intent_names or entity_names:
|
|
@@ -98,7 +115,6 @@ class StudioDataHandler:
|
|
|
98
115
|
},
|
|
99
116
|
verify=verify,
|
|
100
117
|
)
|
|
101
|
-
|
|
102
118
|
if res.status_code != 200:
|
|
103
119
|
raise RasaException(
|
|
104
120
|
f"Download from Studio with URL: "
|
|
@@ -203,9 +219,7 @@ class StudioDataHandler:
|
|
|
203
219
|
self.flows = self._decode_response(return_data.get("flows"))
|
|
204
220
|
self.config = self._decode_response(return_data.get("config"))
|
|
205
221
|
self.endpoints = self._decode_response(return_data.get("endpoints"))
|
|
206
|
-
|
|
207
|
-
prompts_string = self._decode_response(return_data.get("prompts"))
|
|
208
|
-
self.prompts = json.loads(prompts_string) if prompts_string else None
|
|
222
|
+
self.prompts = return_data.get("prompts")
|
|
209
223
|
|
|
210
224
|
if not self.has_nlu() and not self.has_flows():
|
|
211
225
|
raise RasaException("No nlu or flows data in Studio response.")
|
rasa/studio/download.py
CHANGED
|
@@ -25,6 +25,7 @@ from rasa.studio.constants import DOMAIN_FILENAME
|
|
|
25
25
|
from rasa.studio.data_handler import StudioDataHandler
|
|
26
26
|
from rasa.studio.prompts import handle_prompts
|
|
27
27
|
from rasa.studio.pull.data import _dump_flows_as_separate_files
|
|
28
|
+
from rasa.studio.utils import validate_argument_paths
|
|
28
29
|
|
|
29
30
|
structlogger = structlog.get_logger()
|
|
30
31
|
|
|
@@ -35,6 +36,7 @@ def handle_download(args: argparse.Namespace) -> None:
|
|
|
35
36
|
Args:
|
|
36
37
|
args: The command line arguments.
|
|
37
38
|
"""
|
|
39
|
+
validate_argument_paths(args)
|
|
38
40
|
assistant_name = args.assistant_name
|
|
39
41
|
target_root = _prepare_target_directory(assistant_name)
|
|
40
42
|
|
|
@@ -47,7 +49,9 @@ def handle_download(args: argparse.Namespace) -> None:
|
|
|
47
49
|
_handle_endpoints(handler, target_root)
|
|
48
50
|
_handle_domain(handler, target_root)
|
|
49
51
|
_handle_data(handler, target_root)
|
|
50
|
-
|
|
52
|
+
|
|
53
|
+
if prompts := handler.get_prompts():
|
|
54
|
+
handle_prompts(prompts, target_root)
|
|
51
55
|
|
|
52
56
|
structlogger.info(
|
|
53
57
|
"studio.download.success",
|
rasa/studio/link.py
CHANGED
|
@@ -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"
|
|
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(
|
rasa/studio/prompts.py
CHANGED
|
@@ -20,7 +20,6 @@ from rasa.shared.constants import (
|
|
|
20
20
|
from rasa.shared.utils.common import all_subclasses
|
|
21
21
|
from rasa.shared.utils.llm import get_system_default_prompts
|
|
22
22
|
from rasa.shared.utils.yaml import read_yaml, write_yaml
|
|
23
|
-
from rasa.studio.data_handler import StudioDataHandler
|
|
24
23
|
|
|
25
24
|
structlogger = structlog.get_logger()
|
|
26
25
|
|
|
@@ -29,14 +28,13 @@ COMMAND_GENERATOR_NAME = "command_generator"
|
|
|
29
28
|
ENTERPRISE_SEARCH_NAME = "enterprise_search"
|
|
30
29
|
|
|
31
30
|
|
|
32
|
-
def handle_prompts(
|
|
31
|
+
def handle_prompts(prompts: Dict[Text, Text], root: Path) -> None:
|
|
33
32
|
"""Handle prompts for the assistant.
|
|
34
33
|
|
|
35
34
|
Args:
|
|
36
|
-
|
|
35
|
+
prompts: A dict containing prompt names as keys and their content as values.
|
|
37
36
|
root: The root directory where the prompts should be saved.
|
|
38
37
|
"""
|
|
39
|
-
prompts = handler.get_prompts()
|
|
40
38
|
if not prompts:
|
|
41
39
|
return
|
|
42
40
|
|
|
@@ -85,7 +83,7 @@ def _handle_contextual_response_rephraser(
|
|
|
85
83
|
return
|
|
86
84
|
|
|
87
85
|
prompt_path = _save_prompt_file(
|
|
88
|
-
root, f"{CONTEXTUAL_RESPONSE_REPHRASER_NAME}.
|
|
86
|
+
root, f"{CONTEXTUAL_RESPONSE_REPHRASER_NAME}.jinja2", prompt_content
|
|
89
87
|
)
|
|
90
88
|
|
|
91
89
|
endpoints["nlg"] = endpoints.get("nlg") or {}
|
|
@@ -113,7 +111,7 @@ def _handle_command_generator(
|
|
|
113
111
|
return
|
|
114
112
|
|
|
115
113
|
prompt_path = _save_prompt_file(
|
|
116
|
-
root, f"{COMMAND_GENERATOR_NAME}.
|
|
114
|
+
root, f"{COMMAND_GENERATOR_NAME}.jinja2", prompt_content
|
|
117
115
|
)
|
|
118
116
|
|
|
119
117
|
command_generator_names: List[str] = [
|
|
@@ -149,7 +147,7 @@ def _handle_enterprise_search(
|
|
|
149
147
|
return
|
|
150
148
|
|
|
151
149
|
prompt_path = _save_prompt_file(
|
|
152
|
-
root, f"{ENTERPRISE_SEARCH_NAME}.
|
|
150
|
+
root, f"{ENTERPRISE_SEARCH_NAME}.jinja2", prompt_content
|
|
153
151
|
)
|
|
154
152
|
|
|
155
153
|
_add_prompt_to_config(
|
rasa/studio/pull/pull.py
CHANGED
|
@@ -22,6 +22,7 @@ from rasa.studio.data_handler import StudioDataHandler, import_data_from_studio
|
|
|
22
22
|
from rasa.studio.link import read_assistant_name
|
|
23
23
|
from rasa.studio.pull.data import merge_flows_in_directory, merge_nlu_in_directory
|
|
24
24
|
from rasa.studio.pull.domains import merge_domain
|
|
25
|
+
from rasa.studio.utils import validate_argument_paths
|
|
25
26
|
from rasa.utils.mapper import RasaPrimitiveStorageMapper
|
|
26
27
|
|
|
27
28
|
structlogger = structlog.get_logger(__name__)
|
|
@@ -33,6 +34,7 @@ def handle_pull(args: argparse.Namespace) -> None:
|
|
|
33
34
|
Args:
|
|
34
35
|
args: The command line arguments.
|
|
35
36
|
"""
|
|
37
|
+
validate_argument_paths(args)
|
|
36
38
|
handler = _create_studio_handler()
|
|
37
39
|
handler.request_all_data()
|
|
38
40
|
|
|
@@ -55,6 +57,7 @@ def handle_pull_config(args: argparse.Namespace) -> None:
|
|
|
55
57
|
Args:
|
|
56
58
|
args: The command line arguments.
|
|
57
59
|
"""
|
|
60
|
+
validate_argument_paths(args)
|
|
58
61
|
handler = _create_studio_handler()
|
|
59
62
|
handler.request_all_data()
|
|
60
63
|
|
|
@@ -73,6 +76,7 @@ def handle_pull_endpoints(args: argparse.Namespace) -> None:
|
|
|
73
76
|
Args:
|
|
74
77
|
args: The command line arguments.
|
|
75
78
|
"""
|
|
79
|
+
validate_argument_paths(args)
|
|
76
80
|
handler = _create_studio_handler()
|
|
77
81
|
handler.request_all_data()
|
|
78
82
|
|
|
@@ -149,10 +153,10 @@ def _prepare_data_and_domain_paths(args: argparse.Namespace) -> Tuple[Path, Path
|
|
|
149
153
|
domain_path = Path(domain_path)
|
|
150
154
|
|
|
151
155
|
data_path = rasa.cli.utils.get_validated_path(
|
|
152
|
-
args.data
|
|
156
|
+
args.data, "data", DEFAULT_DATA_PATH, none_is_valid=True
|
|
153
157
|
)
|
|
154
158
|
|
|
155
|
-
data_path = Path(data_path or args.data
|
|
159
|
+
data_path = Path(data_path or args.data)
|
|
156
160
|
if not (data_path.is_file() or data_path.is_dir()):
|
|
157
161
|
data_path.mkdir(parents=True, exist_ok=True)
|
|
158
162
|
|
rasa/studio/push.py
CHANGED
|
@@ -19,6 +19,7 @@ from rasa.studio.upload import (
|
|
|
19
19
|
make_request,
|
|
20
20
|
run_validation,
|
|
21
21
|
)
|
|
22
|
+
from rasa.studio.utils import validate_argument_paths
|
|
22
23
|
|
|
23
24
|
structlogger = structlog.get_logger(__name__)
|
|
24
25
|
|
|
@@ -62,6 +63,7 @@ def handle_push(args: argparse.Namespace) -> None:
|
|
|
62
63
|
Args:
|
|
63
64
|
args: The command line arguments.
|
|
64
65
|
"""
|
|
66
|
+
validate_argument_paths(args)
|
|
65
67
|
studio_cfg = get_studio_config()
|
|
66
68
|
|
|
67
69
|
run_validation(args)
|