rasa-pro 3.13.0.dev9__py3-none-any.whl → 3.13.0.dev11__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 (45) hide show
  1. rasa/cli/export.py +2 -0
  2. rasa/cli/studio/download.py +3 -9
  3. rasa/cli/studio/link.py +1 -2
  4. rasa/cli/studio/pull.py +3 -2
  5. rasa/cli/studio/push.py +1 -1
  6. rasa/cli/studio/train.py +0 -1
  7. rasa/core/exporter.py +36 -0
  8. rasa/core/policies/enterprise_search_policy.py +151 -240
  9. rasa/core/policies/enterprise_search_policy_config.py +242 -0
  10. rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +6 -5
  11. rasa/core/utils.py +11 -2
  12. rasa/dialogue_understanding/commands/__init__.py +4 -0
  13. rasa/dialogue_understanding/generator/command_generator.py +11 -1
  14. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +78 -0
  15. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +2 -2
  16. rasa/dialogue_understanding/processor/command_processor.py +5 -5
  17. rasa/shared/core/flows/validation.py +9 -2
  18. rasa/shared/providers/_configs/azure_openai_client_config.py +2 -2
  19. rasa/shared/providers/_configs/default_litellm_client_config.py +1 -1
  20. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -1
  21. rasa/shared/providers/_configs/openai_client_config.py +1 -1
  22. rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -1
  23. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -1
  24. rasa/shared/providers/_configs/utils.py +0 -99
  25. rasa/shared/utils/configs.py +110 -0
  26. rasa/shared/utils/constants.py +0 -3
  27. rasa/shared/utils/pykwalify_extensions.py +0 -9
  28. rasa/studio/constants.py +1 -0
  29. rasa/studio/download.py +164 -0
  30. rasa/studio/link.py +1 -1
  31. rasa/studio/{download/flows.py → pull/data.py} +2 -131
  32. rasa/studio/{download → pull}/domains.py +1 -1
  33. rasa/studio/pull/pull.py +235 -0
  34. rasa/studio/push.py +5 -0
  35. rasa/studio/train.py +1 -1
  36. rasa/tracing/instrumentation/attribute_extractors.py +10 -5
  37. rasa/version.py +1 -1
  38. {rasa_pro-3.13.0.dev9.dist-info → rasa_pro-3.13.0.dev11.dist-info}/METADATA +1 -1
  39. {rasa_pro-3.13.0.dev9.dist-info → rasa_pro-3.13.0.dev11.dist-info}/RECORD +43 -40
  40. rasa/studio/download/download.py +0 -416
  41. rasa/studio/pull.py +0 -94
  42. /rasa/studio/{download → pull}/__init__.py +0 -0
  43. {rasa_pro-3.13.0.dev9.dist-info → rasa_pro-3.13.0.dev11.dist-info}/NOTICE +0 -0
  44. {rasa_pro-3.13.0.dev9.dist-info → rasa_pro-3.13.0.dev11.dist-info}/WHEEL +0 -0
  45. {rasa_pro-3.13.0.dev9.dist-info → rasa_pro-3.13.0.dev11.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,242 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import asdict, dataclass
4
+ from typing import Any, Dict, List, Optional
5
+
6
+ import structlog
7
+
8
+ from rasa.core.constants import (
9
+ POLICY_MAX_HISTORY,
10
+ POLICY_PRIORITY,
11
+ SEARCH_POLICY_PRIORITY,
12
+ )
13
+ from rasa.shared.constants import (
14
+ EMBEDDINGS_CONFIG_KEY,
15
+ LLM_CONFIG_KEY,
16
+ MAX_COMPLETION_TOKENS_CONFIG_KEY,
17
+ MAX_RETRIES_CONFIG_KEY,
18
+ MODEL_CONFIG_KEY,
19
+ OPENAI_PROVIDER,
20
+ PROMPT_CONFIG_KEY,
21
+ PROMPT_TEMPLATE_CONFIG_KEY,
22
+ PROVIDER_CONFIG_KEY,
23
+ TEMPERATURE_CONFIG_KEY,
24
+ TIMEOUT_CONFIG_KEY,
25
+ )
26
+ from rasa.shared.utils.configs import (
27
+ raise_deprecation_warnings,
28
+ resolve_aliases,
29
+ validate_forbidden_keys,
30
+ validate_required_keys,
31
+ )
32
+ from rasa.shared.utils.llm import (
33
+ DEFAULT_OPENAI_CHAT_MODEL_NAME,
34
+ DEFAULT_OPENAI_EMBEDDING_MODEL_NAME,
35
+ resolve_model_client_config,
36
+ )
37
+
38
+ structlogger = structlog.get_logger()
39
+
40
+
41
+ SOURCE_PROPERTY = "source"
42
+ VECTOR_STORE_TYPE_PROPERTY = "type"
43
+ VECTOR_STORE_PROPERTY = "vector_store"
44
+ VECTOR_STORE_THRESHOLD_PROPERTY = "threshold"
45
+ TRACE_TOKENS_PROPERTY = "trace_prompt_tokens"
46
+ CITATION_ENABLED_PROPERTY = "citation_enabled"
47
+ USE_LLM_PROPERTY = "use_generative_llm"
48
+ CHECK_RELEVANCY_PROPERTY = "check_relevancy"
49
+ MAX_MESSAGES_IN_QUERY_KEY = "max_messages_in_query"
50
+
51
+ DEFAULT_VECTOR_STORE_TYPE = "faiss"
52
+ DEFAULT_VECTOR_STORE_THRESHOLD = 0.0
53
+ DEFAULT_VECTOR_STORE = {
54
+ VECTOR_STORE_TYPE_PROPERTY: DEFAULT_VECTOR_STORE_TYPE,
55
+ SOURCE_PROPERTY: "./docs",
56
+ VECTOR_STORE_THRESHOLD_PROPERTY: DEFAULT_VECTOR_STORE_THRESHOLD,
57
+ }
58
+
59
+ DEFAULT_CHECK_RELEVANCY_PROPERTY = False
60
+ DEFAULT_USE_LLM_PROPERTY = True
61
+ DEFAULT_CITATION_ENABLED_PROPERTY = False
62
+ DEFAULT_TRACE_PROMPT_TOKEN_PROPERTY = False
63
+
64
+ DEFAULT_MAX_MESSAGES_IN_QUERY = 2
65
+
66
+ DEFAULT_LLM_CONFIG = {
67
+ PROVIDER_CONFIG_KEY: OPENAI_PROVIDER,
68
+ MODEL_CONFIG_KEY: DEFAULT_OPENAI_CHAT_MODEL_NAME,
69
+ TIMEOUT_CONFIG_KEY: 10,
70
+ TEMPERATURE_CONFIG_KEY: 0.0,
71
+ MAX_COMPLETION_TOKENS_CONFIG_KEY: 256,
72
+ MAX_RETRIES_CONFIG_KEY: 1,
73
+ }
74
+
75
+ DEFAULT_EMBEDDINGS_CONFIG = {
76
+ PROVIDER_CONFIG_KEY: OPENAI_PROVIDER,
77
+ MODEL_CONFIG_KEY: DEFAULT_OPENAI_EMBEDDING_MODEL_NAME,
78
+ }
79
+
80
+ DEFAULT_ENTERPRISE_SEARCH_CONFIG = {
81
+ POLICY_PRIORITY: SEARCH_POLICY_PRIORITY,
82
+ VECTOR_STORE_PROPERTY: DEFAULT_VECTOR_STORE,
83
+ }
84
+
85
+ REQUIRED_KEYS: List[str] = []
86
+
87
+ FORBIDDEN_KEYS: List[str] = []
88
+
89
+ DEPRECATED_ALIASES_TO_STANDARD_KEY_MAPPING = {
90
+ PROMPT_CONFIG_KEY: PROMPT_TEMPLATE_CONFIG_KEY
91
+ }
92
+
93
+
94
+ @dataclass
95
+ class EnterpriseSearchPolicyConfig:
96
+ """Parses configuration for Enterprise Search Policy."""
97
+
98
+ # TODO: llm_config, embeddings_config, and vector_store_config should also be parsed
99
+ # as "Config" objects. Likely part of a broader Rasa 4.0 rewrite where all
100
+ # components rely on configuration parser. So, for example, llm_config and
101
+ # embeddings_config should be parsed as ClientConfig objects, and
102
+ # vector_store_config parsed as VectorStoreConfig object.
103
+ llm_config: dict
104
+ embeddings_config: dict
105
+ vector_store_config: dict
106
+
107
+ prompt_template: str
108
+
109
+ use_generative_llm: bool = DEFAULT_USE_LLM_PROPERTY
110
+ enable_citation: bool = DEFAULT_CITATION_ENABLED_PROPERTY
111
+ check_relevancy: bool = DEFAULT_CHECK_RELEVANCY_PROPERTY
112
+
113
+ max_history: Optional[int] = None
114
+ max_messages_in_query: int = DEFAULT_MAX_MESSAGES_IN_QUERY
115
+ trace_prompt_tokens: bool = DEFAULT_TRACE_PROMPT_TOKEN_PROPERTY
116
+
117
+ @property
118
+ def vector_store_type(self) -> str:
119
+ # TODO: In the future this should ideally be part of the Vector config
120
+ # and not the property of the EnterpriseSearch config
121
+ return (
122
+ self.vector_store_config.get(VECTOR_STORE_TYPE_PROPERTY)
123
+ or DEFAULT_VECTOR_STORE_TYPE
124
+ )
125
+
126
+ @property
127
+ def vector_store_threshold(self) -> float:
128
+ # TODO: In the future this should ideally be part of the Vector config
129
+ # and not the property of the EnterpriseSearch config
130
+ return (
131
+ self.vector_store_config.get(VECTOR_STORE_THRESHOLD_PROPERTY)
132
+ or DEFAULT_VECTOR_STORE_THRESHOLD
133
+ )
134
+
135
+ @property
136
+ def vector_store_source(self) -> Optional[str]:
137
+ # TODO: In the future this should ideally be part of the Vector config
138
+ # and not the property of the EnterpriseSearch config
139
+ return self.vector_store_config.get(SOURCE_PROPERTY)
140
+
141
+ def __post_init__(self) -> None:
142
+ if self.check_relevancy and not self.use_generative_llm:
143
+ structlogger.warning(
144
+ "enterprise_search_policy"
145
+ ".relevancy_check_enabled_with_disabled_generative_search",
146
+ event_info=(
147
+ f"The config parameter '{CHECK_RELEVANCY_PROPERTY}' is set to"
148
+ f"'True', but the generative search is disabled (config"
149
+ f"parameter '{USE_LLM_PROPERTY}' is set to 'False'). As a result, "
150
+ "the relevancy check for the generative search will be disabled. "
151
+ f"To use this check, set the config parameter '{USE_LLM_PROPERTY}' "
152
+ f"to `True`."
153
+ ),
154
+ )
155
+ if self.enable_citation and not self.use_generative_llm:
156
+ structlogger.warning(
157
+ "enterprise_search_policy"
158
+ ".citation_enabled_with_disabled_generative_search",
159
+ event_info=(
160
+ f"The config parameter '{CITATION_ENABLED_PROPERTY}' is set to"
161
+ f"'True', but the generative search is disabled (config"
162
+ f"parameter '{USE_LLM_PROPERTY}' is set to 'False'). As a result, "
163
+ "the citation for the generative search will be disabled. "
164
+ f"To use this check, set the config parameter '{USE_LLM_PROPERTY}' "
165
+ f"to `True`."
166
+ ),
167
+ )
168
+
169
+ @classmethod
170
+ def from_dict(cls, config: dict) -> EnterpriseSearchPolicyConfig:
171
+ """
172
+ Initializes a dataclass from the passed config.
173
+
174
+ Args:
175
+ config: (dict) The config from which to initialize.
176
+
177
+ Raises:
178
+ ValueError: Config is missing required keys.
179
+
180
+ Returns:
181
+ AzureOpenAIClientConfig
182
+ """
183
+ # Resolve LLM config
184
+ llm_config = (
185
+ resolve_model_client_config(
186
+ config.get(LLM_CONFIG_KEY), EnterpriseSearchPolicyConfig.__name__
187
+ )
188
+ or DEFAULT_LLM_CONFIG
189
+ )
190
+
191
+ # Resolve embeddings config
192
+ embeddings_config = (
193
+ resolve_model_client_config(
194
+ config.get(EMBEDDINGS_CONFIG_KEY), EnterpriseSearchPolicyConfig.__name__
195
+ )
196
+ or DEFAULT_EMBEDDINGS_CONFIG
197
+ )
198
+
199
+ # Vector store config
200
+ vector_store_config = config.get(VECTOR_STORE_PROPERTY, DEFAULT_VECTOR_STORE)
201
+
202
+ # Check for deprecated keys
203
+ raise_deprecation_warnings(
204
+ config, DEPRECATED_ALIASES_TO_STANDARD_KEY_MAPPING, "EnterpriseSearchPolicy"
205
+ )
206
+ # Resolve any potential aliases (e.g. 'prompt_template' vs 'prompt')
207
+ config = cls.resolve_config_aliases(config)
208
+
209
+ # Validate that the required keys are present
210
+ validate_required_keys(config, REQUIRED_KEYS)
211
+ # Validate that the forbidden keys are not present
212
+ validate_forbidden_keys(config, FORBIDDEN_KEYS)
213
+
214
+ this = EnterpriseSearchPolicyConfig(
215
+ llm_config=llm_config,
216
+ embeddings_config=embeddings_config,
217
+ vector_store_config=vector_store_config,
218
+ prompt_template=config.get(PROMPT_TEMPLATE_CONFIG_KEY),
219
+ use_generative_llm=config.get(USE_LLM_PROPERTY, DEFAULT_USE_LLM_PROPERTY),
220
+ enable_citation=config.get(
221
+ CITATION_ENABLED_PROPERTY, DEFAULT_CITATION_ENABLED_PROPERTY
222
+ ),
223
+ check_relevancy=config.get(
224
+ CHECK_RELEVANCY_PROPERTY, DEFAULT_CHECK_RELEVANCY_PROPERTY
225
+ ),
226
+ max_history=config.get(POLICY_MAX_HISTORY),
227
+ max_messages_in_query=config.get(
228
+ MAX_MESSAGES_IN_QUERY_KEY, DEFAULT_MAX_MESSAGES_IN_QUERY
229
+ ),
230
+ trace_prompt_tokens=config.get(
231
+ TRACE_TOKENS_PROPERTY, DEFAULT_TRACE_PROMPT_TOKEN_PROPERTY
232
+ ),
233
+ )
234
+ return this
235
+
236
+ def to_dict(self) -> dict:
237
+ """Converts the config instance into a dictionary."""
238
+ return asdict(self)
239
+
240
+ @staticmethod
241
+ def resolve_config_aliases(config: Dict[str, Any]) -> Dict[str, Any]:
242
+ return resolve_aliases(config, DEPRECATED_ALIASES_TO_STANDARD_KEY_MAPPING)
@@ -1,5 +1,9 @@
1
- Given the following information, please provide an answer based on the provided documents and the context of the recent conversation.
2
- If the answer is not known or cannot be determined from the provided documents or context, please state that you do not know to the user.
1
+ Based on the provided documents and the recent conversation context, answer the following question.
2
+ Before responding, ensure the answer is directly supported by the documents or context.
3
+ Do not make assumptions or infer beyond the given information.
4
+ Only answer if you are more than 80% confident that the response is fully supported.
5
+ If the answer cannot be determined, respond with: [NO_RAG_ANSWER]
6
+
3
7
  ### Relevant Documents
4
8
  Use the following documents to answer the question:
5
9
  {% for doc in docs %}
@@ -57,7 +61,4 @@ Avoid speculating or making assumptions beyond the given information and keep yo
57
61
  If you are unable to find an answer in the given relevant documents, do not cite sources from elsewhere in the conversation context.
58
62
  {% endif %}
59
63
 
60
- {% if check_relevancy %}
61
- If answer is not relevant output: "[NO_RELEVANT_ANSWER_FOUND]"
62
- {% endif %}
63
64
  Your answer:
rasa/core/utils.py CHANGED
@@ -318,16 +318,25 @@ def should_force_slot_filling(
318
318
  and the name of the slot if applicable.
319
319
  """
320
320
  from rasa.dialogue_understanding.processor.command_processor import (
321
+ find_updated_flows,
321
322
  get_current_collect_step,
322
323
  )
323
324
 
324
325
  if tracker is None:
325
- structlogger.error(
326
- "slot.force_slot_filling.error",
326
+ structlogger.debug(
327
+ "slot.force_slot_filling.no_found_tracker",
327
328
  event_info="Tracker is None. Cannot force slot filling.",
328
329
  )
329
330
  return False, None
330
331
 
332
+ updated_flows = find_updated_flows(tracker, flows)
333
+ if updated_flows:
334
+ structlogger.debug(
335
+ "slot.force_slot_filling.running_flows_were_updated",
336
+ updated_flow_ids=updated_flows,
337
+ )
338
+ return False, None
339
+
331
340
  stack = tracker.stack
332
341
  step = get_current_collect_step(stack, flows)
333
342
  if step is None or not step.force_slot_filling:
@@ -16,6 +16,9 @@ from rasa.dialogue_understanding.commands.error_command import ErrorCommand
16
16
  from rasa.dialogue_understanding.commands.free_form_answer_command import (
17
17
  FreeFormAnswerCommand,
18
18
  )
19
+ from rasa.dialogue_understanding.commands.handle_code_change_command import (
20
+ HandleCodeChangeCommand,
21
+ )
19
22
  from rasa.dialogue_understanding.commands.human_handoff_command import (
20
23
  HumanHandoffCommand,
21
24
  )
@@ -49,6 +52,7 @@ __all__ = [
49
52
  "SetSlotCommand",
50
53
  "StartFlowCommand",
51
54
  "HumanHandoffCommand",
55
+ "HandleCodeChangeCommand",
52
56
  "CorrectSlotsCommand",
53
57
  "CorrectedSlot",
54
58
  "ErrorCommand",
@@ -8,6 +8,7 @@ from rasa.dialogue_understanding.commands import (
8
8
  Command,
9
9
  CorrectSlotsCommand,
10
10
  ErrorCommand,
11
+ HandleCodeChangeCommand,
11
12
  SetSlotCommand,
12
13
  StartFlowCommand,
13
14
  )
@@ -398,15 +399,24 @@ class CommandGenerator:
398
399
  The filtered commands.
399
400
  """
400
401
  from rasa.dialogue_understanding.processor.command_processor import (
402
+ find_updated_flows,
401
403
  get_current_collect_step,
402
404
  )
403
405
 
404
406
  if tracker is None:
405
- structlogger.error(
407
+ structlogger.debug(
406
408
  "command_generator.filter_commands_during_force_slot_filling.tracker_not_found",
407
409
  )
408
410
  return commands
409
411
 
412
+ updated_flows = find_updated_flows(tracker, available_flows)
413
+ if updated_flows:
414
+ structlogger.debug(
415
+ "command_generator.filter_commands_during_force_slot_filling.running_flows_were_updated",
416
+ updated_flow_ids=updated_flows,
417
+ )
418
+ return [HandleCodeChangeCommand()]
419
+
410
420
  stack = tracker.stack
411
421
  step = get_current_collect_step(stack, available_flows)
412
422
 
@@ -0,0 +1,78 @@
1
+ ## Task Description
2
+ Your task is to analyze the current conversation context and generate a list of actions to start new business processes that we call flows, to extract slots, or respond to off-topic and knowledge requests.
3
+
4
+ ---
5
+
6
+ ## Available Actions:
7
+ * `start flow flow_name`: Start a flow. For example, `start flow transfer_money` or `start flow list_contacts`.
8
+ * `set slot slot_name slot_value`: Set a slot for the active flow. For example, `set slot transfer_money_recipient Freddy`. Can be used to correct and change previously set values.
9
+ * `disambiguate flows flow_name1 flow_name2 ... flow_name_n`: When a message could refer to multiple flows, list the possible flows as options to clarify. Example: `disambiguate flows list_contacts add_contact remove_contact`.
10
+ * `search and reply`: Provide a response from the knowledge base to address the user's inquiry when no flows fit, including domain knowledge, FAQs, and all off-topic or social messages.
11
+ * `cancel flow`: Cancel the current flow if the user requests it.
12
+
13
+ ---
14
+
15
+ ## General Instructions
16
+ ### Start Flow
17
+ * Only start a flow if the user's message is clear and fully addressed by that flow's description and purpose.
18
+ * Pay close attention to exact wording and scope in the flow description — do not assume or “stretch” the intended use of a flow.
19
+ ### Set Slot
20
+ * Do not fill slots with abstract values or placeholders.
21
+ * For categorical slots, try to match the user message with allowed slot values. Use "other" if you cannot match it.
22
+ * Set the boolean slots based on the user's response. Map positive responses to `True`, and negative to `False`.
23
+ * Extract text slot values exactly as provided by the user. Avoid assumptions, format changes, or partial extractions.
24
+ ### Disambiguate Flows
25
+ * Use `disambiguate flows` when the user's message matches multiple flows and you cannot decide which flow is most appropriate.
26
+ * If the user message is short and not precise enough to start a flow or `search and reply`, disambiguate.
27
+ * If a single flow is a strong/plausible fit, prefer starting that flow directly.
28
+ * If a user's message unambiguously and distinctly matches multiple flows, start all relevant flows at once (rather than disambiguating).
29
+ ### Search and Reply
30
+ * Only start `search and reply` if the user intent is clear.
31
+ * Flow Priority: If you are unsure between starting a flow or `search and reply`, always prioritize starting a flow.
32
+ ### Cancel Flow
33
+ * Do not cancel any flow unless the user explicitly requests it.
34
+ * Multiple flows can be started without cancelling the previous, if the user wants to pursue multiple processes.
35
+ ### General Tips
36
+ * Only use information provided by the user.
37
+ * Strictly adhere to the provided action format.
38
+ * Focus on the last message and take it one step at a time.
39
+ * Use the previous conversation steps only to aid understanding.
40
+
41
+ ---
42
+
43
+ ## Decision Rule Table
44
+ | Condition | Action |
45
+ |-------------------------------------------------------|--------------------|
46
+ | Flow perfectly matches user's message | start flow |
47
+ | Multiple flows are equally strong, relevant matches | disambiguate flows |
48
+ | User's message is unclear or imprecise | disambiguate flows |
49
+ | No flow fits at all, but knowledge base may help | search and reply |
50
+
51
+ ---
52
+
53
+ ## Available Flows and Slots
54
+ Use the following structured data:
55
+ ```json
56
+ {"flows":[{% for flow in available_flows %}{"name":"{{ flow.name }}","description":{{ flow.description | to_json_escaped_string }}{% if flow.slots %},"slots":[{% for slot in flow.slots %}{"name":"{{ slot.name }}"{% if slot.description %},"description":{{ slot.description | to_json_escaped_string }}{% endif %}{% if slot.allowed_values %},"allowed_values":{{ slot.allowed_values }}{% endif %}}{% if not loop.last %},{% endif %}{% endfor %}]{% endif %}}{% if not loop.last %},{% endif %}{% endfor %}]}
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Current State
62
+ {% if current_flow != None %}Use the following structured data:
63
+ ```json
64
+ {"active_flow":"{{ current_flow }}","current_step":{"requested_slot":"{{ current_slot }}","requested_slot_description":{{ current_slot_description | to_json_escaped_string }}},"slots":[{% for slot in flow_slots %}{"name":"{{ slot.name }}","value":"{{ slot.value }}","type":"{{ slot.type }}"{% if slot.description %},"description":{{ slot.description | to_json_escaped_string }}{% endif %}{% if slot.allowed_values %},"allowed_values":"{{ slot.allowed_values }}"{% endif %}}{% if not loop.last %},{% endif %}{% endfor %}]}
65
+ ```{% else %}
66
+ You are currently not inside any flow.{% endif %}
67
+
68
+ ---
69
+
70
+ ## Conversation History
71
+ {{ current_conversation }}
72
+
73
+ ---
74
+
75
+ ## Task
76
+ Create an action list with one action per line in response to the user's last message: """{{ user_message }}""".
77
+
78
+ Your action list:
@@ -59,10 +59,10 @@ MODEL_PROMPT_MAPPER = {
59
59
  ),
60
60
  f"{AWS_BEDROCK_PROVIDER}/anthropic."
61
61
  f"{MODEL_NAME_CLAUDE_3_5_SONNET_20240620}-v1:0": (
62
- "command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2"
62
+ "command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2"
63
63
  ),
64
64
  f"{ANTHROPIC_PROVIDER}/{MODEL_NAME_CLAUDE_3_5_SONNET_20240620}": (
65
- "command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2"
65
+ "command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2"
66
66
  ),
67
67
  }
68
68
 
@@ -214,18 +214,18 @@ def execute_commands(
214
214
  commands: List[Command] = get_commands_from_tracker(tracker)
215
215
  original_tracker = tracker.copy()
216
216
 
217
- commands = clean_up_commands(
218
- commands, tracker, all_flows, execution_context, story_graph, domain
219
- )
220
-
221
217
  updated_flows = find_updated_flows(tracker, all_flows)
222
218
  if updated_flows:
223
- # Override commands
219
+ # if there are updated flows, we need to handle the code change
224
220
  structlogger.debug(
225
221
  "command_processor.execute_commands.running_flows_were_updated",
226
222
  updated_flow_ids=updated_flows,
227
223
  )
228
224
  commands = [HandleCodeChangeCommand()]
225
+ else:
226
+ commands = clean_up_commands(
227
+ commands, tracker, all_flows, execution_context, story_graph, domain
228
+ )
229
229
 
230
230
  # store current flow hashes if they changed
231
231
  new_hashes = calculate_flow_fingerprints(all_flows)
@@ -581,11 +581,18 @@ def validate_linked_flows_exists(flows: "FlowsList") -> None:
581
581
  continue
582
582
 
583
583
  # It might be that the flows do not contain the default rasa patterns, but
584
- # only the user flows. Manually check for `pattern_human_handoff` as this
585
- # pattern can be linked to and it is part of the default patterns of rasa.
584
+ # only the user flows. Manually check for `pattern_human_handoff` and
585
+ # 'pattern_chitchat' as these patterns can be linked to and are part of the
586
+ # default patterns of rasa.
586
587
  if (
587
588
  flows.flow_by_id(step.link) is None
589
+ # Allow linking to human-handoff from both patterns
590
+ # and user-defined flows
588
591
  and step.link != RASA_PATTERN_HUMAN_HANDOFF
592
+ # Allow linking to 'pattern_chitchat' only from other patterns
593
+ and not (
594
+ flow.is_rasa_default_flow and step.link == RASA_PATTERN_CHITCHAT
595
+ )
589
596
  ):
590
597
  raise UnresolvedFlowException(step.link, flow.id, step.id)
591
598
 
@@ -46,13 +46,13 @@ from rasa.shared.providers._configs.oauth_config import (
46
46
  OAUTH_TYPE_FIELD,
47
47
  OAuth,
48
48
  )
49
- from rasa.shared.providers._configs.utils import (
49
+ from rasa.shared.utils.common import class_from_module_path
50
+ from rasa.shared.utils.configs import (
50
51
  raise_deprecation_warnings,
51
52
  resolve_aliases,
52
53
  validate_forbidden_keys,
53
54
  validate_required_keys,
54
55
  )
55
- from rasa.shared.utils.common import class_from_module_path
56
56
 
57
57
  structlogger = structlog.get_logger()
58
58
 
@@ -15,7 +15,7 @@ from rasa.shared.constants import (
15
15
  STREAM_CONFIG_KEY,
16
16
  TIMEOUT_CONFIG_KEY,
17
17
  )
18
- from rasa.shared.providers._configs.utils import (
18
+ from rasa.shared.utils.configs import (
19
19
  raise_deprecation_warnings,
20
20
  resolve_aliases,
21
21
  validate_forbidden_keys,
@@ -21,7 +21,7 @@ from rasa.shared.constants import (
21
21
  REQUEST_TIMEOUT_CONFIG_KEY,
22
22
  TIMEOUT_CONFIG_KEY,
23
23
  )
24
- from rasa.shared.providers._configs.utils import (
24
+ from rasa.shared.utils.configs import (
25
25
  raise_deprecation_warnings,
26
26
  resolve_aliases,
27
27
  validate_required_keys,
@@ -26,7 +26,7 @@ from rasa.shared.constants import (
26
26
  STREAM_CONFIG_KEY,
27
27
  TIMEOUT_CONFIG_KEY,
28
28
  )
29
- from rasa.shared.providers._configs.utils import (
29
+ from rasa.shared.utils.configs import (
30
30
  raise_deprecation_warnings,
31
31
  resolve_aliases,
32
32
  validate_forbidden_keys,
@@ -11,7 +11,7 @@ from rasa.shared.constants import (
11
11
  PROVIDER_CONFIG_KEY,
12
12
  RASA_PROVIDER,
13
13
  )
14
- from rasa.shared.providers._configs.utils import (
14
+ from rasa.shared.utils.configs import (
15
15
  validate_required_keys,
16
16
  )
17
17
 
@@ -25,7 +25,7 @@ from rasa.shared.constants import (
25
25
  TIMEOUT_CONFIG_KEY,
26
26
  USE_CHAT_COMPLETIONS_ENDPOINT_CONFIG_KEY,
27
27
  )
28
- from rasa.shared.providers._configs.utils import (
28
+ from rasa.shared.utils.configs import (
29
29
  raise_deprecation_warnings,
30
30
  resolve_aliases,
31
31
  validate_forbidden_keys,
@@ -1,107 +1,8 @@
1
1
  import structlog
2
2
 
3
- from rasa.shared.utils.io import raise_deprecation_warning
4
-
5
3
  structlogger = structlog.get_logger()
6
4
 
7
5
 
8
- def resolve_aliases(config: dict, deprecated_alias_mapping: dict) -> dict:
9
- """
10
- Resolve aliases in the configuration to standard keys.
11
-
12
- Args:
13
- config: Dictionary containing the configuration.
14
- deprecated_alias_mapping: Dictionary mapping aliases to
15
- their standard keys.
16
-
17
- Returns:
18
- New dictionary containing the processed configuration.
19
- """
20
- config = config.copy()
21
-
22
- for alias, standard_key in deprecated_alias_mapping.items():
23
- # We check for the alias instead of the standard key because our goal is to
24
- # update the standard key when the alias is found. Since the standard key is
25
- # always included in the default component configurations, we overwrite it
26
- # with the alias value if the alias exists.
27
- if alias in config:
28
- config[standard_key] = config.pop(alias)
29
-
30
- return config
31
-
32
-
33
- def raise_deprecation_warnings(config: dict, deprecated_alias_mapping: dict) -> None:
34
- """
35
- Raises warnings for deprecated keys in the configuration.
36
-
37
- Args:
38
- config: Dictionary containing the configuration.
39
- deprecated_alias_mapping: Dictionary mapping deprecated keys to
40
- their standard keys.
41
-
42
- Raises:
43
- DeprecationWarning: If any deprecated key is found in the config.
44
- """
45
- for alias, standard_key in deprecated_alias_mapping.items():
46
- if alias in config:
47
- raise_deprecation_warning(
48
- message=(
49
- f"'{alias}' is deprecated and will be removed in "
50
- f"4.0.0. Use '{standard_key}' instead."
51
- )
52
- )
53
-
54
-
55
- def validate_required_keys(config: dict, required_keys: list) -> None:
56
- """
57
- Validates that the passed config contains all the required keys.
58
-
59
- Args:
60
- config: Dictionary containing the configuration.
61
- required_keys: List of keys that must be present in the config.
62
-
63
- Raises:
64
- ValueError: If any required key is missing.
65
- """
66
- missing_keys = [key for key in required_keys if key not in config]
67
- if missing_keys:
68
- message = f"Missing required keys '{missing_keys}' for configuration."
69
- structlogger.error(
70
- "validate_required_keys",
71
- message=message,
72
- missing_keys=missing_keys,
73
- config=config,
74
- )
75
- raise ValueError(message)
76
-
77
-
78
- def validate_forbidden_keys(config: dict, forbidden_keys: list) -> None:
79
- """
80
- Validates that the passed config doesn't contain any forbidden keys.
81
-
82
- Args:
83
- config: Dictionary containing the configuration.
84
- forbidden_keys: List of keys that are forbidden in the config.
85
-
86
- Raises:
87
- ValueError: If any forbidden key is present.
88
- """
89
- forbidden_keys_in_config = set(config.keys()).intersection(set(forbidden_keys))
90
-
91
- if forbidden_keys_in_config:
92
- message = (
93
- f"Forbidden keys '{forbidden_keys_in_config}' present "
94
- f"in the configuration."
95
- )
96
- structlogger.error(
97
- "validate_forbidden_keys",
98
- message=message,
99
- forbidden_keys=forbidden_keys_in_config,
100
- config=config,
101
- )
102
- raise ValueError(message)
103
-
104
-
105
6
  def get_provider_prefixed_model_name(provider: str, model: str) -> str:
106
7
  """
107
8
  Returns the model name with the provider prefixed.