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.

Files changed (55) hide show
  1. rasa/agents/agent_manager.py +7 -5
  2. rasa/agents/protocol/a2a/a2a_agent.py +13 -11
  3. rasa/agents/protocol/mcp/mcp_base_agent.py +64 -12
  4. rasa/agents/validation.py +61 -6
  5. rasa/builder/copilot/constants.py +4 -0
  6. rasa/builder/copilot/copilot_templated_message_provider.py +24 -1
  7. rasa/builder/copilot/templated_messages/copilot_templated_responses.yml +3 -0
  8. rasa/builder/copilot/templated_messages/copilot_welcome_messages.yml +56 -0
  9. rasa/builder/jobs.py +162 -5
  10. rasa/builder/models.py +3 -0
  11. rasa/builder/validation_service.py +4 -0
  12. rasa/cli/arguments/data.py +9 -0
  13. rasa/cli/data.py +72 -6
  14. rasa/cli/interactive.py +3 -0
  15. rasa/cli/llm_fine_tuning.py +1 -0
  16. rasa/cli/project_templates/defaults.py +1 -0
  17. rasa/cli/validation/bot_config.py +4 -0
  18. rasa/constants.py +1 -1
  19. rasa/core/actions/action_exceptions.py +1 -1
  20. rasa/core/agent.py +4 -1
  21. rasa/core/available_agents.py +1 -1
  22. rasa/core/config/available_endpoints.py +6 -0
  23. rasa/core/exceptions.py +1 -1
  24. rasa/core/featurizers/tracker_featurizers.py +3 -2
  25. rasa/core/persistor.py +7 -7
  26. rasa/core/policies/flows/agent_executor.py +84 -4
  27. rasa/core/policies/flows/flow_exceptions.py +5 -2
  28. rasa/core/policies/flows/flow_executor.py +3 -2
  29. rasa/core/policies/flows/mcp_tool_executor.py +7 -1
  30. rasa/core/policies/rule_policy.py +1 -1
  31. rasa/dialogue_understanding/commands/cancel_flow_command.py +1 -1
  32. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +22 -20
  33. rasa/engine/validation.py +6 -2
  34. rasa/model_manager/runner_service.py +1 -1
  35. rasa/privacy/privacy_config.py +1 -1
  36. rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +4 -7
  37. rasa/shared/agents/auth/utils.py +85 -0
  38. rasa/shared/constants.py +3 -0
  39. rasa/shared/core/training_data/story_reader/story_reader.py +1 -1
  40. rasa/shared/exceptions.py +23 -2
  41. rasa/shared/providers/llm/litellm_router_llm_client.py +2 -2
  42. rasa/shared/utils/llm.py +54 -4
  43. rasa/shared/utils/mcp/server_connection.py +7 -4
  44. rasa/studio/download.py +3 -0
  45. rasa/studio/prompts.py +1 -0
  46. rasa/studio/upload.py +4 -0
  47. rasa/utils/log_utils.py +20 -1
  48. rasa/utils/pypred.py +7 -0
  49. rasa/validator.py +90 -2
  50. rasa/version.py +1 -1
  51. {rasa_pro-3.14.0rc3.dist-info → rasa_pro-3.14.1.dist-info}/METADATA +8 -7
  52. {rasa_pro-3.14.0rc3.dist-info → rasa_pro-3.14.1.dist-info}/RECORD +55 -53
  53. {rasa_pro-3.14.0rc3.dist-info → rasa_pro-3.14.1.dist-info}/NOTICE +0 -0
  54. {rasa_pro-3.14.0rc3.dist-info → rasa_pro-3.14.1.dist-info}/WHEEL +0 -0
  55. {rasa_pro-3.14.0rc3.dist-info → rasa_pro-3.14.1.dist-info}/entry_points.txt +0 -0
@@ -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, load the default resources
70
- and persist the agent to the manager in a ready-to-use state so that
71
- it can be used immediately to send messages to the agent.
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 for agent '{self._name}': {exception}"
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 the task status is terminal (i.e., completed, failed, etc.),
414
- return an AgentOutput.
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"Failed to connect to MCP servers after {self._max_retries} "
278
- f"attempts. Agent `{self._name}` failed to initialize."
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 = "Authentication error during agent initialization."
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(e) from e
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}`: {e!s}"
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
- raise e
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(tool_name, arguments)
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
- result = custom_tool.tool_executor(arguments)
645
- return await result if isawaitable(result) else result
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
- raise ValidationError(
164
- code="agent.validation.optional.prompt_template_not_found",
165
- event_info=f"Agent '{agent_name}' has prompt template that "
166
- f"does not exist: {prompt_path}",
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.