rasa-pro 3.14.0rc3__py3-none-any.whl → 3.14.1__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/agents/agent_manager.py +7 -5
- rasa/agents/protocol/a2a/a2a_agent.py +13 -11
- rasa/agents/protocol/mcp/mcp_base_agent.py +64 -12
- rasa/agents/validation.py +61 -6
- rasa/builder/copilot/constants.py +4 -0
- rasa/builder/copilot/copilot_templated_message_provider.py +24 -1
- rasa/builder/copilot/templated_messages/copilot_templated_responses.yml +3 -0
- rasa/builder/copilot/templated_messages/copilot_welcome_messages.yml +56 -0
- rasa/builder/jobs.py +162 -5
- rasa/builder/models.py +3 -0
- rasa/builder/validation_service.py +4 -0
- rasa/cli/arguments/data.py +9 -0
- rasa/cli/data.py +72 -6
- rasa/cli/interactive.py +3 -0
- rasa/cli/llm_fine_tuning.py +1 -0
- rasa/cli/project_templates/defaults.py +1 -0
- rasa/cli/validation/bot_config.py +4 -0
- rasa/constants.py +1 -1
- rasa/core/actions/action_exceptions.py +1 -1
- rasa/core/agent.py +4 -1
- rasa/core/available_agents.py +1 -1
- rasa/core/config/available_endpoints.py +6 -0
- rasa/core/exceptions.py +1 -1
- rasa/core/featurizers/tracker_featurizers.py +3 -2
- rasa/core/persistor.py +7 -7
- rasa/core/policies/flows/agent_executor.py +84 -4
- rasa/core/policies/flows/flow_exceptions.py +5 -2
- rasa/core/policies/flows/flow_executor.py +3 -2
- rasa/core/policies/flows/mcp_tool_executor.py +7 -1
- rasa/core/policies/rule_policy.py +1 -1
- rasa/dialogue_understanding/commands/cancel_flow_command.py +1 -1
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +22 -20
- rasa/engine/validation.py +6 -2
- rasa/model_manager/runner_service.py +1 -1
- rasa/privacy/privacy_config.py +1 -1
- rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +4 -7
- rasa/shared/agents/auth/utils.py +85 -0
- rasa/shared/constants.py +3 -0
- rasa/shared/core/training_data/story_reader/story_reader.py +1 -1
- rasa/shared/exceptions.py +23 -2
- rasa/shared/providers/llm/litellm_router_llm_client.py +2 -2
- rasa/shared/utils/llm.py +54 -4
- rasa/shared/utils/mcp/server_connection.py +7 -4
- rasa/studio/download.py +3 -0
- rasa/studio/prompts.py +1 -0
- rasa/studio/upload.py +4 -0
- rasa/utils/log_utils.py +20 -1
- rasa/utils/pypred.py +7 -0
- rasa/validator.py +90 -2
- rasa/version.py +1 -1
- {rasa_pro-3.14.0rc3.dist-info → rasa_pro-3.14.1.dist-info}/METADATA +8 -7
- {rasa_pro-3.14.0rc3.dist-info → rasa_pro-3.14.1.dist-info}/RECORD +55 -53
- {rasa_pro-3.14.0rc3.dist-info → rasa_pro-3.14.1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.14.0rc3.dist-info → rasa_pro-3.14.1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.14.0rc3.dist-info → rasa_pro-3.14.1.dist-info}/entry_points.txt +0 -0
rasa/agents/agent_manager.py
CHANGED
|
@@ -15,7 +15,7 @@ structlogger = structlog.get_logger()
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class AgentManager(metaclass=Singleton):
|
|
18
|
-
"""High-level agent management with protocol abstraction"""
|
|
18
|
+
"""High-level agent management with protocol abstraction."""
|
|
19
19
|
|
|
20
20
|
agents: ClassVar[Dict[AgentIdentifier, AgentProtocol]] = {}
|
|
21
21
|
|
|
@@ -66,9 +66,11 @@ class AgentManager(metaclass=Singleton):
|
|
|
66
66
|
async def connect_agent(
|
|
67
67
|
self, agent_name: str, protocol_type: ProtocolType, config: AgentConfig
|
|
68
68
|
) -> None:
|
|
69
|
-
"""Connect to agent using specified protocol
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
"""Connect to agent using specified protocol.
|
|
70
|
+
|
|
71
|
+
Also, load the default resources and persist the agent to the manager
|
|
72
|
+
in a ready-to-use state so that it can be used immediately
|
|
73
|
+
to send messages to the agent.
|
|
72
74
|
|
|
73
75
|
Args:
|
|
74
76
|
agent_name: The name of the agent.
|
|
@@ -109,7 +111,7 @@ class AgentManager(metaclass=Singleton):
|
|
|
109
111
|
agent_id=str(agent_identifier),
|
|
110
112
|
event_info=event_info,
|
|
111
113
|
)
|
|
112
|
-
raise AgentInitializationException(e) from e
|
|
114
|
+
raise AgentInitializationException(e, suppress_stack_trace=True) from e
|
|
113
115
|
|
|
114
116
|
async def run_agent(
|
|
115
117
|
self, agent_name: str, protocol_type: ProtocolType, context: AgentInput
|
|
@@ -65,7 +65,7 @@ structlogger = structlog.get_logger()
|
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
class A2AAgent(AgentProtocol):
|
|
68
|
-
"""A2A client implementation"""
|
|
68
|
+
"""A2A client implementation."""
|
|
69
69
|
|
|
70
70
|
__SUPPORTED_OUTPUT_MODES: ClassVar[list[str]] = [
|
|
71
71
|
"text",
|
|
@@ -169,7 +169,8 @@ class A2AAgent(AgentProtocol):
|
|
|
169
169
|
error=str(exception),
|
|
170
170
|
)
|
|
171
171
|
raise AgentInitializationException(
|
|
172
|
-
f"Failed to initialize A2A client
|
|
172
|
+
f"Failed to initialize A2A client "
|
|
173
|
+
f"for agent '{self._name}': {exception}",
|
|
173
174
|
) from exception
|
|
174
175
|
|
|
175
176
|
await self._perform_health_check()
|
|
@@ -180,7 +181,7 @@ class A2AAgent(AgentProtocol):
|
|
|
180
181
|
)
|
|
181
182
|
|
|
182
183
|
async def disconnect(self) -> None:
|
|
183
|
-
"""We don't need to explicitly disconnect the A2A client"""
|
|
184
|
+
"""We don't need to explicitly disconnect the A2A client."""
|
|
184
185
|
return
|
|
185
186
|
|
|
186
187
|
# ============================================================================
|
|
@@ -297,7 +298,7 @@ class A2AAgent(AgentProtocol):
|
|
|
297
298
|
def _handle_send_message_response(
|
|
298
299
|
self, agent_input: AgentInput, response: ClientEvent | Message
|
|
299
300
|
) -> Optional[AgentOutput]:
|
|
300
|
-
"""Handle possible response types from the A2A client
|
|
301
|
+
"""Handle possible response types from the A2A client.
|
|
301
302
|
|
|
302
303
|
In case of streaming, the response can be either exactly *one* Message,
|
|
303
304
|
or a *series* of tuples of (Task, Optional[TaskUpdateEvent]).
|
|
@@ -410,8 +411,8 @@ class A2AAgent(AgentProtocol):
|
|
|
410
411
|
agent_input: AgentInput,
|
|
411
412
|
task: Task,
|
|
412
413
|
) -> Optional[AgentOutput]:
|
|
413
|
-
"""If
|
|
414
|
-
|
|
414
|
+
"""If task status is terminal (e.g. completed, failed) return AgentOutput.
|
|
415
|
+
|
|
415
416
|
If the task is still in progress (i.e., submitted, working), return None,
|
|
416
417
|
so that the streaming or pooling agent can continue to wait for updates.
|
|
417
418
|
"""
|
|
@@ -655,6 +656,7 @@ class A2AAgent(AgentProtocol):
|
|
|
655
656
|
@staticmethod
|
|
656
657
|
def _generate_completed_response_message(task: Task) -> str:
|
|
657
658
|
"""Generate a response message for a completed task.
|
|
659
|
+
|
|
658
660
|
In case of completed tasks, the final message might be in
|
|
659
661
|
the task status message or in the artifacts (or both).
|
|
660
662
|
"""
|
|
@@ -728,19 +730,19 @@ class A2AAgent(AgentProtocol):
|
|
|
728
730
|
|
|
729
731
|
except FileNotFoundError as e:
|
|
730
732
|
raise AgentInitializationException(
|
|
731
|
-
f"Agent card file not found: {agent_card_path}"
|
|
733
|
+
f"Agent card file not found: {agent_card_path}",
|
|
732
734
|
) from e
|
|
733
735
|
except (IOError, PermissionError) as e:
|
|
734
736
|
raise AgentInitializationException(
|
|
735
|
-
f"Error reading agent card file {agent_card_path}: {e}"
|
|
737
|
+
f"Error reading agent card file {agent_card_path}: {e}",
|
|
736
738
|
) from e
|
|
737
739
|
except json.JSONDecodeError as e:
|
|
738
740
|
raise AgentInitializationException(
|
|
739
|
-
f"Invalid JSON in agent card file {agent_card_path}: {e}"
|
|
741
|
+
f"Invalid JSON in agent card file {agent_card_path}: {e}",
|
|
740
742
|
) from e
|
|
741
743
|
except ValidationError as e:
|
|
742
744
|
raise AgentInitializationException(
|
|
743
|
-
f"Failed to load agent card from {agent_card_path}: {e}"
|
|
745
|
+
f"Failed to load agent card from {agent_card_path}: {e}",
|
|
744
746
|
) from e
|
|
745
747
|
|
|
746
748
|
@staticmethod
|
|
@@ -798,7 +800,7 @@ class A2AAgent(AgentProtocol):
|
|
|
798
800
|
|
|
799
801
|
raise AgentInitializationException(
|
|
800
802
|
f"Failed to resolve agent card from {agent_card_path} after "
|
|
801
|
-
f"{max_retries} attempts."
|
|
803
|
+
f"{max_retries} attempts.",
|
|
802
804
|
)
|
|
803
805
|
|
|
804
806
|
# ============================================================================
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from abc import abstractmethod
|
|
3
|
-
from datetime import datetime
|
|
3
|
+
from datetime import datetime, timedelta
|
|
4
4
|
from inspect import isawaitable
|
|
5
5
|
from typing import Any, Dict, List, Optional, Tuple
|
|
6
6
|
|
|
7
|
+
import anyio
|
|
7
8
|
import structlog
|
|
8
9
|
from jinja2 import Template
|
|
9
10
|
from mcp import ListToolsResult
|
|
@@ -71,10 +72,12 @@ structlogger = structlog.get_logger()
|
|
|
71
72
|
|
|
72
73
|
|
|
73
74
|
class MCPBaseAgent(AgentProtocol):
|
|
74
|
-
"""MCP protocol implementation"""
|
|
75
|
+
"""MCP protocol implementation."""
|
|
75
76
|
|
|
76
77
|
MAX_ITERATIONS = 10
|
|
77
78
|
|
|
79
|
+
TOOL_CALL_DEFAULT_TIMEOUT = 10 # seconds
|
|
80
|
+
|
|
78
81
|
# ============================================================================
|
|
79
82
|
# Initialization & Setup
|
|
80
83
|
# ============================================================================
|
|
@@ -135,6 +138,20 @@ class MCPBaseAgent(AgentProtocol):
|
|
|
135
138
|
@classmethod
|
|
136
139
|
def from_config(cls, config: AgentConfig) -> "MCPBaseAgent":
|
|
137
140
|
"""Initialize the MCP Open Agent with the given configuration."""
|
|
141
|
+
# Warn if configuration.timeout is set for MCP agents
|
|
142
|
+
if config.configuration and config.configuration.timeout is not None:
|
|
143
|
+
structlogger.warning(
|
|
144
|
+
"mcp_agent.configuration.timeout.not_implemented",
|
|
145
|
+
event_info="configuration.timeout is not implemented for MCP agents. "
|
|
146
|
+
"MCP agents do not establish external connections, "
|
|
147
|
+
"so agent-level timeout is not used. "
|
|
148
|
+
"To set timeout for LLM requests, "
|
|
149
|
+
"configure 'timeout' in the model_group "
|
|
150
|
+
"in endpoints.yml and reference it via configuration.llm.model_group.",
|
|
151
|
+
agent_name=config.agent.name,
|
|
152
|
+
timeout_value=config.configuration.timeout,
|
|
153
|
+
)
|
|
154
|
+
|
|
138
155
|
return cls(
|
|
139
156
|
name=config.agent.name,
|
|
140
157
|
description=config.agent.description,
|
|
@@ -274,14 +291,16 @@ class MCPBaseAgent(AgentProtocol):
|
|
|
274
291
|
event_info="All connection attempts failed.",
|
|
275
292
|
)
|
|
276
293
|
raise AgentInitializationException(
|
|
277
|
-
f"
|
|
278
|
-
f"
|
|
294
|
+
f"Agent `{self._name}` failed to initialize. Failed to connect "
|
|
295
|
+
f"to MCP servers after {self._max_retries} attempts. {ce!s}"
|
|
279
296
|
) from ce
|
|
280
297
|
except (Exception, AuthenticationError) as e:
|
|
281
298
|
if isinstance(e, AuthenticationError):
|
|
282
|
-
event_info =
|
|
299
|
+
event_info = (
|
|
300
|
+
f"Authentication error during agent initialization. {e!s}"
|
|
301
|
+
)
|
|
283
302
|
else:
|
|
284
|
-
event_info = "Unexpected error during agent initialization."
|
|
303
|
+
event_info = f"Unexpected error during agent initialization. {e!s}"
|
|
285
304
|
structlogger.error(
|
|
286
305
|
"mcp_agent.connect.unexpected_exception",
|
|
287
306
|
event_info=event_info,
|
|
@@ -289,7 +308,7 @@ class MCPBaseAgent(AgentProtocol):
|
|
|
289
308
|
agent_name=self._name,
|
|
290
309
|
agent_id=str(make_agent_identifier(self._name, self.protocol_type)),
|
|
291
310
|
)
|
|
292
|
-
raise AgentInitializationException(
|
|
311
|
+
raise AgentInitializationException(event_info) from e
|
|
293
312
|
|
|
294
313
|
async def connect_to_server(self, server_config: AgentMCPServerConfig) -> None:
|
|
295
314
|
server_name = server_config.name
|
|
@@ -311,7 +330,7 @@ class MCPBaseAgent(AgentProtocol):
|
|
|
311
330
|
except Exception as e:
|
|
312
331
|
event_info = (
|
|
313
332
|
f"Agent `{self._name}` failed to connect to MCP server - "
|
|
314
|
-
f"`{server_name}` @ `{server_config.url}
|
|
333
|
+
f"`{server_name}` @ `{server_config.url}`"
|
|
315
334
|
)
|
|
316
335
|
structlogger.error(
|
|
317
336
|
"mcp_agent.connect.failed_to_connect",
|
|
@@ -321,7 +340,9 @@ class MCPBaseAgent(AgentProtocol):
|
|
|
321
340
|
agent_name=self._name,
|
|
322
341
|
agent_id=str(make_agent_identifier(self._name, self.protocol_type)),
|
|
323
342
|
)
|
|
324
|
-
|
|
343
|
+
|
|
344
|
+
# Wrap exceptions with extra info and raise the same type of exception.
|
|
345
|
+
raise type(e)(f"{event_info} : {e!s}") from e
|
|
325
346
|
|
|
326
347
|
async def connect_to_servers(self) -> None:
|
|
327
348
|
"""Connect to MCP servers."""
|
|
@@ -610,7 +631,11 @@ class MCPBaseAgent(AgentProtocol):
|
|
|
610
631
|
connection = self._server_connections[server_id]
|
|
611
632
|
try:
|
|
612
633
|
session = await connection.ensure_active_session()
|
|
613
|
-
result = await session.call_tool(
|
|
634
|
+
result = await session.call_tool(
|
|
635
|
+
tool_name,
|
|
636
|
+
arguments,
|
|
637
|
+
read_timeout_seconds=timedelta(seconds=self.TOOL_CALL_DEFAULT_TIMEOUT),
|
|
638
|
+
)
|
|
614
639
|
return AgentToolResult.from_mcp_tool_result(tool_name, result)
|
|
615
640
|
except Exception as e:
|
|
616
641
|
return AgentToolResult(
|
|
@@ -623,6 +648,21 @@ class MCPBaseAgent(AgentProtocol):
|
|
|
623
648
|
),
|
|
624
649
|
)
|
|
625
650
|
|
|
651
|
+
async def _run_custom_tool(
|
|
652
|
+
self, custom_tool: CustomToolSchema, arguments: Dict[str, Any]
|
|
653
|
+
) -> AgentToolResult:
|
|
654
|
+
"""Run a custom tool and return the result.
|
|
655
|
+
|
|
656
|
+
Args:
|
|
657
|
+
custom_tool: The custom tool schema containing the tool executor.
|
|
658
|
+
arguments: The arguments to pass to the tool executor.
|
|
659
|
+
|
|
660
|
+
Returns:
|
|
661
|
+
The result of the tool execution as an AgentToolResult.
|
|
662
|
+
"""
|
|
663
|
+
result = custom_tool.tool_executor(arguments)
|
|
664
|
+
return await result if isawaitable(result) else result
|
|
665
|
+
|
|
626
666
|
async def _execute_tool_call(
|
|
627
667
|
self, tool_name: str, arguments: Dict[str, Any]
|
|
628
668
|
) -> AgentToolResult:
|
|
@@ -641,8 +681,20 @@ class MCPBaseAgent(AgentProtocol):
|
|
|
641
681
|
try:
|
|
642
682
|
for custom_tool in self._custom_tools:
|
|
643
683
|
if custom_tool.tool_name == tool_name:
|
|
644
|
-
|
|
645
|
-
|
|
684
|
+
try:
|
|
685
|
+
with anyio.fail_after(self.TOOL_CALL_DEFAULT_TIMEOUT):
|
|
686
|
+
return await self._run_custom_tool(custom_tool, arguments)
|
|
687
|
+
|
|
688
|
+
except TimeoutError:
|
|
689
|
+
return AgentToolResult(
|
|
690
|
+
tool_name=tool_name,
|
|
691
|
+
result=None,
|
|
692
|
+
is_error=True,
|
|
693
|
+
error_message=(
|
|
694
|
+
f"Built-in tool `{tool_name}` timed out after "
|
|
695
|
+
f"{self.TOOL_CALL_DEFAULT_TIMEOUT} seconds."
|
|
696
|
+
),
|
|
697
|
+
)
|
|
646
698
|
except Exception as e:
|
|
647
699
|
return AgentToolResult(
|
|
648
700
|
tool_name=tool_name,
|
rasa/agents/validation.py
CHANGED
|
@@ -5,6 +5,8 @@ import urllib.parse
|
|
|
5
5
|
from collections import Counter
|
|
6
6
|
from typing import Any, Dict, List, NoReturn, Set
|
|
7
7
|
|
|
8
|
+
import jinja2.exceptions
|
|
9
|
+
import structlog
|
|
8
10
|
from pydantic import ValidationError as PydanticValidationError
|
|
9
11
|
|
|
10
12
|
from rasa.agents.exceptions import (
|
|
@@ -23,8 +25,13 @@ from rasa.core.available_agents import (
|
|
|
23
25
|
from rasa.core.config.available_endpoints import AvailableEndpoints
|
|
24
26
|
from rasa.core.config.configuration import Configuration
|
|
25
27
|
from rasa.exceptions import ValidationError
|
|
28
|
+
from rasa.shared.agents.auth.utils import validate_secrets_in_params
|
|
29
|
+
from rasa.shared.utils.llm import get_prompt_template, validate_jinja2_template
|
|
26
30
|
from rasa.shared.utils.yaml import read_config_file
|
|
27
31
|
|
|
32
|
+
# Initialize logger
|
|
33
|
+
structlogger = structlog.get_logger()
|
|
34
|
+
|
|
28
35
|
# Centralized allowed keys configuration to eliminate duplication
|
|
29
36
|
ALLOWED_KEYS = {
|
|
30
37
|
"agent": {"name", "protocol", "description"},
|
|
@@ -151,6 +158,41 @@ def _validate_a2a_config(agent_config: AgentConfig) -> None:
|
|
|
151
158
|
f"exist: {agent_card}",
|
|
152
159
|
)
|
|
153
160
|
|
|
161
|
+
# Validate right use of secrets in auth configuration
|
|
162
|
+
if agent_config.configuration.auth:
|
|
163
|
+
validate_secrets_in_params(
|
|
164
|
+
agent_config.configuration.auth, f"agent '{agent_name}'"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _validate_prompt_template_syntax(prompt_path: str, agent_name: str) -> None:
|
|
169
|
+
"""Validate Jinja2 syntax of a prompt template file."""
|
|
170
|
+
try:
|
|
171
|
+
# Use a simple default template, as we're assuming
|
|
172
|
+
# that the default templates are valid
|
|
173
|
+
default_template = "{{ content }}"
|
|
174
|
+
template_content = get_prompt_template(
|
|
175
|
+
prompt_path,
|
|
176
|
+
default_template,
|
|
177
|
+
log_source_component=f"agent.validation.{agent_name}",
|
|
178
|
+
log_source_method="init",
|
|
179
|
+
)
|
|
180
|
+
validate_jinja2_template(template_content)
|
|
181
|
+
|
|
182
|
+
except jinja2.exceptions.TemplateSyntaxError as e:
|
|
183
|
+
raise ValidationError(
|
|
184
|
+
code="agent.validation.prompt_template_syntax_error",
|
|
185
|
+
event_info=(
|
|
186
|
+
f"Agent '{agent_name}' has invalid Jinja2 template syntax at line "
|
|
187
|
+
f"{e.lineno}: {e.message}"
|
|
188
|
+
),
|
|
189
|
+
) from e
|
|
190
|
+
except Exception as e:
|
|
191
|
+
raise ValidationError(
|
|
192
|
+
code="agent.validation.optional.prompt_template_error",
|
|
193
|
+
event_info=(f"Agent '{agent_name}' has error reading prompt template: {e}"),
|
|
194
|
+
) from e
|
|
195
|
+
|
|
154
196
|
|
|
155
197
|
def _validate_optional_keys(agent_config: AgentConfig) -> None:
|
|
156
198
|
"""Validate optional keys in agent configuration."""
|
|
@@ -160,11 +202,22 @@ def _validate_optional_keys(agent_config: AgentConfig) -> None:
|
|
|
160
202
|
if agent_config.configuration and agent_config.configuration.prompt_template:
|
|
161
203
|
prompt_path = agent_config.configuration.prompt_template
|
|
162
204
|
if not os.path.exists(prompt_path):
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
205
|
+
# If reading the custom prompt fails,
|
|
206
|
+
# allow fallback to default prompt template
|
|
207
|
+
structlogger.warning(
|
|
208
|
+
"agent.validation.optional.prompt_template_file_not_found",
|
|
209
|
+
agent_name=agent_name,
|
|
210
|
+
prompt_path=prompt_path,
|
|
211
|
+
event_info=(
|
|
212
|
+
f"Prompt template file not found: {prompt_path}. "
|
|
213
|
+
f"Agent will use default template."
|
|
214
|
+
),
|
|
167
215
|
)
|
|
216
|
+
# Don't raise ValidationError, allow fallback to default template
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
# Validate Jinja2 syntax
|
|
220
|
+
_validate_prompt_template_syntax(prompt_path, agent_name)
|
|
168
221
|
|
|
169
222
|
# Validate module if present
|
|
170
223
|
if agent_config.configuration and agent_config.configuration.module:
|
|
@@ -294,9 +347,11 @@ def _handle_pydantic_validation_error(
|
|
|
294
347
|
def _validate_endpoint_references(agent_config: AgentConfig) -> None:
|
|
295
348
|
"""Validate that LLM and MCP server references in agent config are valid."""
|
|
296
349
|
agent_name = agent_config.agent.name
|
|
297
|
-
|
|
298
|
-
# Get available endpoints
|
|
299
350
|
endpoints = Configuration.get_instance().endpoints
|
|
351
|
+
if not endpoints.config_file_path:
|
|
352
|
+
# If no endpoints were loaded (e.g., `data validate` without --endpoints), skip
|
|
353
|
+
# endpoint reference checks
|
|
354
|
+
return
|
|
300
355
|
|
|
301
356
|
# Validate LLM configuration references
|
|
302
357
|
if agent_config.configuration and agent_config.configuration.llm:
|
|
@@ -14,6 +14,7 @@ COPILOT_TRAINING_ERROR_HANDLER_PROMPT_FILE = (
|
|
|
14
14
|
COPILOT_MESSAGE_TEMPLATES_DIR = "builder.copilot.templated_messages"
|
|
15
15
|
RASA_INTERNAL_MESSAGES_TEMPLATES_FILE = "copilot_internal_messages_templates.yml"
|
|
16
16
|
COPILOT_HANDLER_RESPONSES_FILE = "copilot_templated_responses.yml"
|
|
17
|
+
COPILOT_WELCOME_MESSAGES_FILE = "copilot_welcome_messages.yml"
|
|
17
18
|
|
|
18
19
|
# OpenAI roles copilot utilizes - Use literal types to avoid type errors with OpenAI
|
|
19
20
|
ROLE_USER: Literal["user"] = "user"
|
|
@@ -32,3 +33,6 @@ COPILOT_SEGMENT_WRITE_KEY_ENV_VAR = "COPILOT_SEGMENT_WRITE_KEY"
|
|
|
32
33
|
|
|
33
34
|
# Copilot signing
|
|
34
35
|
SIGNATURE_VERSION_V1 = "v1"
|
|
36
|
+
|
|
37
|
+
# Welcome message key for prompt-to-bot (not a template enum)
|
|
38
|
+
PROMPT_TO_BOT_KEY = "prompt_to_bot"
|
|
@@ -2,11 +2,12 @@ import importlib.resources
|
|
|
2
2
|
from typing import Dict
|
|
3
3
|
|
|
4
4
|
import structlog
|
|
5
|
-
import yaml # type: ignore
|
|
5
|
+
import yaml # type: ignore[import-untyped]
|
|
6
6
|
|
|
7
7
|
from rasa.builder.copilot.constants import (
|
|
8
8
|
COPILOT_HANDLER_RESPONSES_FILE,
|
|
9
9
|
COPILOT_MESSAGE_TEMPLATES_DIR,
|
|
10
|
+
COPILOT_WELCOME_MESSAGES_FILE,
|
|
10
11
|
RASA_INTERNAL_MESSAGES_TEMPLATES_FILE,
|
|
11
12
|
)
|
|
12
13
|
from rasa.shared.constants import PACKAGE_NAME
|
|
@@ -56,3 +57,25 @@ def load_copilot_handler_default_responses() -> Dict[str, str]:
|
|
|
56
57
|
error=e,
|
|
57
58
|
)
|
|
58
59
|
return dict()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def load_copilot_welcome_messages() -> Dict[str, str]:
|
|
63
|
+
"""Load welcome message templates from the YAML configuration file.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Dictionary mapping template names to welcome message text.
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
config = yaml.safe_load(
|
|
70
|
+
importlib.resources.read_text(
|
|
71
|
+
f"{PACKAGE_NAME}.{COPILOT_MESSAGE_TEMPLATES_DIR}",
|
|
72
|
+
COPILOT_WELCOME_MESSAGES_FILE,
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
return config.get("welcome_messages", {})
|
|
76
|
+
except Exception as e:
|
|
77
|
+
structlogger.error(
|
|
78
|
+
"copilot_templated_message_provider.failed_to_load_welcome_messages",
|
|
79
|
+
error=e,
|
|
80
|
+
)
|
|
81
|
+
return dict()
|
|
@@ -36,3 +36,6 @@ responses:
|
|
|
36
36
|
guardrail_blocked_project_response: |
|
|
37
37
|
Your Copilot access has been temporarily blocked due to repeated policy violations.
|
|
38
38
|
If you believe this is an error or would like to request a review, please reach out to support@rasa.com.
|
|
39
|
+
|
|
40
|
+
training_success_response: |
|
|
41
|
+
Your changes have been saved successfully.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
welcome_messages:
|
|
2
|
+
copilot_intro: |
|
|
3
|
+
👋 Welcome to Hello Rasa!
|
|
4
|
+
|
|
5
|
+
I'm your **Copilot** — here to help you explore Rasa and start customizing your agent.
|
|
6
|
+
You can ask me how your agent works, how to add new skills, or how to connect integrations.
|
|
7
|
+
|
|
8
|
+
finance: |
|
|
9
|
+
👋 Welcome to Hello Rasa!
|
|
10
|
+
|
|
11
|
+
I'm your **Copilot** — here to help you explore Rasa and start customizing your agent.
|
|
12
|
+
You can ask me how your agent works, how to add new skills, or how to connect integrations.
|
|
13
|
+
|
|
14
|
+
Your **Banking Agent template** is now live.
|
|
15
|
+
|
|
16
|
+
### ▶️ **First step: try it out**
|
|
17
|
+
Ask your agent (in the chat preview on the right):
|
|
18
|
+
- *What's my current balance?*
|
|
19
|
+
- *Send 100 dollars to James.*
|
|
20
|
+
|
|
21
|
+
telco: |
|
|
22
|
+
👋 Welcome to Hello Rasa!
|
|
23
|
+
|
|
24
|
+
I'm your **Copilot** — here to help you explore Rasa and start customizing your agent.
|
|
25
|
+
You can ask me how your agent works, how to add new skills, or how to connect integrations.
|
|
26
|
+
|
|
27
|
+
Your **Telecom Support Agent template** is now live.
|
|
28
|
+
|
|
29
|
+
### ▶️ **First step: try it out**
|
|
30
|
+
Ask your agent (in the chat preview on the right):
|
|
31
|
+
- *Why is my internet slow?*
|
|
32
|
+
- *How do i reboot my router?*
|
|
33
|
+
|
|
34
|
+
basic: |
|
|
35
|
+
👋 Welcome to Hello Rasa!
|
|
36
|
+
|
|
37
|
+
I'm your **Copilot** — here to help you explore Rasa and start customizing your agent.
|
|
38
|
+
You can ask me how your agent works, how to add new skills, or how to connect integrations.
|
|
39
|
+
|
|
40
|
+
Your **Starter Agent template** is now live.
|
|
41
|
+
|
|
42
|
+
### ▶️ **First step: try it out**
|
|
43
|
+
Ask your agent (in the chat preview on the right):
|
|
44
|
+
- *What can you do?*
|
|
45
|
+
- *Can I talk to a human?*
|
|
46
|
+
|
|
47
|
+
prompt_to_bot: |
|
|
48
|
+
👋 Welcome to Hello Rasa!
|
|
49
|
+
|
|
50
|
+
I'm your **Copilot** — here to help you explore Rasa and start customizing your agent.
|
|
51
|
+
You can ask me how your agent works, how to add new skills, or how to connect integrations.
|
|
52
|
+
|
|
53
|
+
Your custom agent has been created and trained successfully.
|
|
54
|
+
|
|
55
|
+
### ▶️ **First step: try it out**
|
|
56
|
+
Test your agent in the chat preview on the right to see how it responds to your users.
|