create-agents.md
1 --- 2 title: Creating Agents 3 sidebar_position: 420 4 --- 5 6 :::tip 7 For a more comprehensive tutorial example, see the [Build Your Own Agent](tutorials/custom-agent.md) guide. 8 This page walks through the fundamental concepts for creating agents in Agent Mesh. 9 ::: 10 11 Agent Mesh is a powerful platform that enables you to create intelligent agents that can communicate with each other and perform complex tasks. At its core, Agent Mesh uses a tool-based architecture where LLM-powered agents are equipped with specific capabilities (tools) that they can use to accomplish user requests. 12 13 Before continuing with this tutorial, make sure you are familiar with the basic [agent concept](../components/agents.md). 14 15 This tutorial guides you through creating your first Agent Mesh agent from scratch. You will learn how to define tools as Python functions, configure an agent using YAML, and set up agent lifecycle functions. By the end of this tutorial, you should have a working "Hello World" agent that demonstrates the fundamental concepts of Agent Mesh agent development. 16 17 ## Understanding the Architecture 18 19 Before diving into implementation, you need to understand how the different components of an Agent Mesh agent work together. This architectural overview will help you see the big picture before you start building. 20 21 ```mermaid 22 graph TD 23 subgraph Agent Configuration 24 direction LR 25 A[config.yaml] -->|Defines| B(Agent Properties); 26 A -->|Lists & Configures| C(Tools); 27 end 28 29 subgraph Agent Host 30 direction TB 31 D[Agent Mesh Host] -->|Loads| A; 32 D -->|Instantiates| E[Agent]; 33 E -->|Initializes with| F[Lifecycle Functions]; 34 end 35 36 subgraph Tool Implementation 37 direction LR 38 G[Python Module tools.py] -->|Contains| H[Tool Functions]; 39 end 40 41 subgraph Execution Flow 42 direction TB 43 I[User Request] --> J[LLM Orchestrator]; 44 J -->|Selects Tool| K{ADKToolWrapper}; 45 K -->|Calls| H; 46 H -->|Accesses| L[ToolContext]; 47 H -->|Uses| M[tool_config]; 48 H -->|Returns Result| J; 49 end 50 51 C -->|Wrapped by| K; 52 53 style A fill:#b60000,stroke:#faa,stroke-width:2px 54 style H fill:#b60000,stroke:#faa,stroke-width:2px 55 style F fill:#007000,stroke:#faa,stroke-width:2px 56 ``` 57 58 When a user sends a request to your agent, the LLM orchestrator analyzes the request and decides which tool to use. The framework wraps your tool functions and provides them with context and configuration. Your tool executes its logic and returns results to the LLM, which then formulates a response to the user. 59 60 ## Core Concepts 61 62 Understanding these fundamental concepts will help you build effective agents. 63 64 ### Tools: The Building Blocks 65 66 Tools are the fundamental building blocks of Agent Mesh agents. Each tool is implemented as a Python function that performs a specific task. The LLM orchestrating your agent decides which tools to use based on the user's request and the tool descriptions you provide. 67 68 Tools can process text and data, interact with external APIs, create and manipulate files, communicate with other agents, and access databases and services. You write tools as standard Python functions, and the framework handles the integration with the LLM. 69 70 :::tip 71 Agent Mesh provides a set of [built-in tools](../components/builtin-tools/builtin-tools.md) plus support for [model context protocol (MCP)](tutorials/mcp-integration.md) servers, which can be configured in the tools list of your agent configuration. 72 ::: 73 74 ### Configuration File: The Blueprint 75 76 The `config.yaml` (for plugin template) or `agent-name.yaml` (for agent instances) file is the blueprint of your agent. This YAML file defines your agent's identity (name, description, and capabilities), model configuration (which LLM to use), tools list (which tools the agent can access and how they're configured), lifecycle functions (setup and cleanup procedures), framework services (session management, artifact storage, and so on), and [agent card](../components/agents.md#agent-card) (metadata describing the agent capabilities, skills and its visibility in the system). 77 78 The configuration file connects all the pieces together. It tells the framework where to find your tool functions, how to configure them, and what instructions to give the LLM about your agent's purpose. 79 80 ### Tool Configuration: Customizing Behavior 81 82 Within the `tools` list in your YAML config, each tool can have its own `tool_config` section. This allows you to configure the same tool function for different purposes, pass specific parameters to tool instances, and customize tool behavior per agent. 83 84 This design pattern enables code reuse. You can write a single generic tool function and configure it multiple times with different parameters to serve different purposes within the same agent. 85 86 :::info 87 For tools of type "python", you can also use the `tool_name` and `tool_description` to overwrite the function name and description in the tool docstring. 88 89 This is useful when using a generic tool function for multiple purposes, allowing you to provide a more descriptive name and description for each instance. 90 ::: 91 92 ### ToolContext: Accessing Framework Services 93 94 The `ToolContext` object (passed as one of the arguments to your tool function) provides your tools with access to Agent Mesh core services. Through this context object, your tools can access structured logging for debugging and monitoring, the artifact service for file storage and retrieval, session information about the current user and session context, and agent state for sharing data between tool calls. 95 96 The framework automatically provides this context to your tool functions. You don't need to create or manage it yourself. 97 98 ### Lifecycle Functions: Managing Resources 99 100 Lifecycle functions allow you to manage resources that should persist for the agent's lifetime. The `agent_init_function` runs when the agent starts (for example, to establish database connections), and the `agent_cleanup_function` runs when the agent shuts down (for example, to close connections gracefully). 101 102 These functions are optional but recommended for managing resources effectively. They ensure that your agent properly initializes any required resources and cleans them up when shutting down. 103 104 :::note 105 Lifecycle functions are optional but recommended for managing resources effectively. 106 ::: 107 108 ## Creating Your First Agent: Step-by-Step 109 110 Now that you understand the core concepts, you can create a simple agent that demonstrates how these pieces work together. You will build a "Hello World" agent that can greet users and say goodbye. 111 112 ### Step 1: Initialize Your Agent Plugin 113 114 You can create an agent either by using the `sam add agent` command or by creating a new plugin of type agent with `sam plugin create my-hello-agent --type agent`. 115 116 :::tip 117 For information and recommendations about these options, see [`Agent or Plugin: Which To use?`](../components/plugins.md#agent-or-plugin-which-to-use). 118 ::: 119 120 In this tutorial, you create a new agent by creating a new plugin of type agent. For an example of custom agents, see [Build Your Own Agent](tutorials/custom-agent.md) guide. 121 122 Although the directory structure for plugins is slightly different than the one for agents, both require a YAML configuration file, and a python module with the tools and lifecycle functions you want. 123 124 To create a new agent plugin, run the following command: 125 126 ```bash 127 sam plugin create my-hello-agent --type agent 128 ``` 129 130 Follow the prompts to set up your agent. The prompts create a new directory structure for your agent: 131 132 ``` 133 my-hello-agent/ 134 ├── src/ 135 │ └── my_hello_agent/ 136 │ ├── __init__.py 137 │ ├── tools.py 138 │ └── lifecycle.py # This file won't be automatically created 139 ├── config.yaml 140 ├── pyproject.toml 141 └── README.md 142 ``` 143 144 ```mermaid 145 graph TD 146 A[my-hello-agent/] --> B[src/] 147 A --> C[config.yaml] 148 A --> D[pyproject.toml] 149 A --> E[README.md] 150 151 B --> F[my_hello_agent/] 152 F --> G[__init__.py] 153 F --> H[tools.py] 154 F --> I[lifecycle.py] 155 156 style C fill:#b60000,stroke:#333,stroke-width:2px 157 style H fill:#b60000,stroke:#333,stroke-width:2px 158 style I fill:#007000,stroke:#333,stroke-width:2px 159 ``` 160 161 The `config.yaml` file will contain your agent configuration, `tools.py` will contain your tool functions, and `lifecycle.py` (which you'll create manually) will contain your lifecycle functions. The `pyproject.toml` file manages your plugin's dependencies and metadata. 162 163 ### Step 2: Create Your Tool Functions 164 165 Tools are where your agent's actual capabilities live. You will create two simple tools: one to greet users and one to say goodbye. 166 167 Create your tool functions in the `src/my_hello_agent/tools.py` file. For a complete guide on creating python tools, see our [Creating Python Tools](./creating-python-tools.md) documentation. 168 169 ```python 170 # src/my_hello_agent/tools.py 171 """ 172 Tools for the Hello World agent. 173 """ 174 175 from typing import Any, Dict, Optional 176 from google.adk.tools import ToolContext 177 from solace_ai_connector.common.log import log 178 179 180 async def hello_tool( 181 name: str, 182 tool_context: Optional[ToolContext] = None, 183 tool_config: Optional[Dict[str, Any]] = None 184 ) -> Dict[str, Any]: 185 """ 186 Greets a user with a personalized message. 187 188 Args: 189 name: The name of the person to greet 190 191 Returns: 192 A dictionary with the greeting message 193 """ 194 log_identifier = "[HelloTool]" 195 log.info(f"{log_identifier} Greeting user: {name}") 196 197 # Get configuration from tool_config 198 greeting_prefix = "Hello" 199 if tool_config: 200 greeting_prefix = tool_config.get("greeting_prefix", "Hello") 201 202 # Create the greeting message 203 greeting_message = f"{greeting_prefix}, {name}! Welcome to Agent Mesh!" 204 205 log.info(f"{log_identifier} Generated greeting: {greeting_message}") 206 207 return { 208 "status": "success", 209 "message": greeting_message, 210 "greeted_name": name 211 } 212 213 214 async def farewell_tool( 215 name: str, 216 tool_context: Optional[ToolContext] = None, 217 tool_config: Optional[Dict[str, Any]] = None 218 ) -> Dict[str, Any]: 219 """ 220 Says goodbye to a user. 221 222 Args: 223 name: The name of the person to say goodbye to 224 225 Returns: 226 A dictionary with the farewell message 227 """ 228 log_identifier = "[FarewellTool]" 229 log.info(f"{log_identifier} Saying goodbye to user: {name}") 230 231 # Get configuration from tool_config 232 farewell_prefix = "Goodbye" 233 if tool_config: 234 farewell_prefix = tool_config.get("farewell_prefix", "Goodbye") 235 236 # Create the farewell message 237 farewell_message = f"{farewell_prefix}, {name}! Thanks for using Agent Mesh!" 238 239 log.info(f"{log_identifier} Generated farewell: {farewell_message}") 240 241 return { 242 "status": "success", 243 "message": farewell_message, 244 "farewell_name": name 245 } 246 ``` 247 248 Let's examine what makes these tool functions work. All tool functions must be asynchronous (defined with `async def`) because the framework uses asynchronous execution. The framework automatically provides two special parameters: `tool_context` gives you access to framework services like logging and artifact storage, and `tool_config` contains any custom configuration you define in your YAML file. 249 250 The function signature includes regular parameters (like `name`) that the LLM will provide when calling the tool. The docstring is important because the LLM uses it to understand what the tool does and when to use it. You should always write clear, descriptive docstrings. 251 252 The tool retrieves its configuration from the `tool_config` dictionary. This allows you to customize the tool's behavior without changing the code. In this example, you can configure different greeting prefixes for different use cases. 253 254 The tool returns a dictionary with at least a `status` field. This structured format makes it easy for the LLM to understand the result. You can include any additional data that might be useful for the LLM or for debugging. 255 256 The logging statements help you track what your tool is doing. The framework provides a logger that you should use for consistent logging across your agent. 257 258 ### Step 3: Configure Your Agent 259 260 Now you need to tell the framework about your agent and its tools. Create the main configuration file for your agent in `config.yaml`: 261 262 ```yaml 263 # File: config.yaml (at root of project directory) 264 # ... (additional services and configurations) 265 266 apps: 267 - name: my-hello-agent 268 app_module: solace_agent_mesh.agent.sac.app 269 broker: 270 # Can be found in configs/shared_config.yaml after running sam init 271 <<: *broker_connection 272 273 # Agent-specific configuration 274 app_config: 275 # Basic agent identity 276 namespace: ${NAMESPACE} 277 supports_streaming: true 278 agent_name: "HelloAgent" 279 display_name: "Hello World Agent" 280 281 # LLM model configuration 282 model: *general_model 283 model_provider: 284 - "general" 285 286 # Agent instructions (system prompt) 287 instruction: | 288 You are a friendly Hello World agent. Your purpose is to greet users and 289 demonstrate the capabilities of Agent Mesh. You can: 290 291 1. Greet users with personalized messages using the hello_tool 292 2. Say goodbye to users using the farewell_tool 293 294 Always be polite and helpful. When greeting someone, ask for their name 295 if they haven't provided it. 296 297 # Lifecycle functions 298 agent_init_function: 299 module: "my_hello_agent.lifecycle" # This should point to your lifecycle python module 300 name: "initialize_hello_agent" 301 base_path: . 302 config: 303 startup_message: "Hello Agent is starting up!" 304 log_level: "INFO" 305 306 agent_cleanup_function: 307 module: "my_hello_agent.lifecycle" 308 base_path: . 309 name: "cleanup_hello_agent" 310 311 # Tools configuration 312 tools: 313 # Hello tool with custom greeting 314 - tool_type: python 315 component_module: "my_hello_agent.tools" 316 component_base_path: . 317 function_name: "hello_tool" 318 tool_name: "greet_user" # Renaming the tool, must use this name in the agent card 319 tool_config: 320 greeting_prefix: "Hello there" 321 322 # Farewell tool with custom farewell 323 - tool_type: python 324 component_module: "my_hello_agent.tools" 325 component_base_path: . 326 function_name: "farewell_tool" 327 tool_name: "say_goodbye" 328 tool_config: 329 farewell_prefix: "See you later" 330 331 # Built-in artifact tools for file operations 332 - tool_type: builtin-group 333 group_name: "artifact_management" 334 335 # Agent card (describes the agent's capabilities) 336 agent_card: 337 description: "A friendly Hello World agent that demonstrates Agent Mesh capabilities" 338 defaultInputModes: ["text"] 339 defaultOutputModes: ["text"] 340 skills: 341 - id: "greet_user" 342 name: "Greet User" 343 description: "Greets users with personalized messages" 344 - id: "say_goodbye" 345 name: "Say Goodbye" 346 description: "Says goodbye to users" 347 - id: "file_operations" 348 name: "File Operations" 349 description: "Create, read, and manage files and artifacts" 350 351 # Session and artifact services 352 session_service: *default_session_service 353 artifact_service: *default_artifact_service 354 # ... (additional services and configurations) 355 ``` 356 357 This configuration file connects all the pieces of your agent. Let's examine each section to understand its purpose. 358 359 The `namespace` uniquely identifies your agent in the mesh. This allows multiple agents to coexist and communicate. The `agent_name` and `display_name` provide human-readable identifiers for your agent. 360 361 The `model` section specifies which LLM to use. The `*general_model` reference points to a model configuration defined elsewhere in your configuration files (typically in `shared_config.yaml`). Alternatively, you can use the `model_provider` field to reference a model configured through the Agent Mesh UI, which is the recommended approach for most deployments. For details on both approaches, see [Model Configurations](../installing-and-configuring/model_configurations.md#using-model-configurations-in-agents). 362 363 The `instruction` field contains the system prompt that defines your agent's personality and behavior. This text tells the LLM what role it should play and what capabilities it has. You 364 should write clear, specific instructions that help the LLM understand its role. 365 366 The `tools` section lists all the tools your agent can use. Each tool entry specifies the `tool_type` (python for custom functions, builtin-group for built-in tools), the `component_module` that contains the function, the `function_name` to call, and optionally a `tool_name` to rename the tool for the LLM. The `tool_config` section passes custom configuration to each tool instance. This is where you provide the `greeting_prefix` and `farewell_prefix` values that your tool functions read. 367 368 Notice that you can configure the same function multiple times with different names and configurations. The `hello_tool` function is configured as `greet_user` with one greeting prefix, but you could add another configuration with a different prefix for formal greetings. 369 370 The `agent_card` section describes your agent's capabilities to other parts of the system. The `skills` list should match the tools you've configured. Each skill has an `id` that corresponds to a tool name, making it discoverable by other agents and the user interface. 371 372 The `session_service` and `artifact_service` references connect your agent to framework services for managing user sessions and storing files. These services are typically defined in your shared configuration. 373 374 ### Step 4: Create Lifecycle Functions 375 376 Lifecycle functions manage resources that should persist for your agent's lifetime. Although these functions are optional, they demonstrate how to properly initialize and clean up resources. 377 378 The lifecycle file is not automatically created, so you need to create it manually: 379 380 ```bash 381 touch src/my_hello_agent/lifecycle.py 382 ``` 383 384 Now add your lifecycle functions: 385 386 ```python 387 # src/my_hello_agent/lifecycle.py 388 """ 389 Lifecycle functions for the Hello World agent. 390 """ 391 392 from typing import Any, Dict 393 from pydantic import BaseModel, Field 394 from solace_ai_connector.common.log import log 395 396 397 class HelloAgentInitConfig(BaseModel): 398 """ 399 Configuration model for the Hello Agent initialization. 400 """ 401 startup_message: str = Field(description="Message to log on startup") 402 log_level: str = Field(default="INFO", description="Logging level for the agent") 403 404 405 def initialize_hello_agent(host_component: Any, init_config: HelloAgentInitConfig): 406 """ 407 Initializes the Hello World agent. 408 409 Args: 410 host_component: The agent host component 411 init_config: Validated initialization configuration 412 """ 413 log_identifier = f"[{host_component.agent_name}:init]" 414 log.info(f"{log_identifier} Starting Hello Agent initialization...") 415 416 # Log the startup message from config 417 log.info(f"{log_identifier} {init_config.startup_message}") 418 419 # You could initialize shared resources here, such as: 420 # - Database connections 421 # - API clients 422 # - Caches or shared data structures 423 424 # Store any shared state in the agent 425 host_component.set_agent_specific_state("initialized_at", "2024-01-01T00:00:00Z") 426 host_component.set_agent_specific_state("greeting_count", 0) 427 428 log.info(f"{log_identifier} Hello Agent initialization completed successfully") 429 430 431 def cleanup_hello_agent(host_component: Any): 432 """ 433 Cleans up resources when the Hello World agent shuts down. 434 435 Args: 436 host_component: The agent host component 437 """ 438 log_identifier = f"[{host_component.agent_name}:cleanup]" 439 log.info(f"{log_identifier} Starting Hello Agent cleanup...") 440 441 # Retrieve any shared state 442 greeting_count = host_component.get_agent_specific_state("greeting_count", 0) 443 log.info(f"{log_identifier} Agent processed {greeting_count} greetings during its lifetime") 444 445 # Clean up resources here, such as: 446 # - Closing database connections 447 # - Shutting down background tasks 448 # - Saving final state 449 450 log.info(f"{log_identifier} Hello Agent cleanup completed") 451 ``` 452 453 The lifecycle functions follow a specific pattern. The `initialize_hello_agent` function receives two parameters: `host_component` provides access to the agent instance and its methods, and `init_config` contains the validated configuration from your YAML file's `agent_init_function.config` section. 454 455 Using a Pydantic model for `init_config` provides automatic validation. The framework validates your configuration against this model when the agent starts, catching configuration errors early. This is better than manually checking configuration values in your code. 456 457 The `host_component` object provides methods for managing agent state. The `set_agent_specific_state` method stores data that persists across tool calls within the same agent instance. This is useful for tracking statistics, caching data, or maintaining connections. The state is specific to this agent instance and is not shared with other agents. 458 459 The `cleanup_hello_agent` function runs when the agent shuts down. This is your opportunity to gracefully close connections, save final state, or perform any other cleanup tasks. The function receives only the `host_component` parameter because cleanup typically doesn't need additional configuration. 460 461 In this example, you retrieve the greeting count from the agent state and log it. In a real application, you might close database connections, flush caches to disk, or notify other services that the agent is shutting down. 462 463 ## Running Your Agent 464 465 Now that you have created all the necessary components, you can run your agent. The process involves building your plugin and adding it to your Agent Mesh project. 466 467 ### Building and Installing the Plugin 468 469 To properly instantiate your plugin agent, first build the plugin. The following command will produce a python wheel file under `dist` directory: 470 471 ```bash 472 sam plugin build 473 ``` 474 475 This command packages your agent code, configuration, and dependencies into a distributable wheel file. The wheel file is a standard Python package format that can be installed into any Python environment. 476 477 Check into [your Agent Mesh project directory](../getting-started/try-agent-mesh.md), and add the plugin wheel with a given name: 478 479 ```bash 480 sam plugin add my-first-weather-agent --plugin PATH/TO/weather-agent/dist/weather-agent.whl 481 ``` 482 483 :::note 484 Using the `sam plugin add` command installs your plugin as a python dependency into your python environment. 485 This also means changing the source code without reinstalling the plugin will not reflect the changes. 486 ::: 487 488 The `sam plugin add` command does several things. It installs your plugin package into your Python environment, making your tool functions and lifecycle functions importable. It also creates a configuration file in your project's `configs/agents/` directory that references your plugin. This configuration file is what the framework loads when you run your agent. 489 490 Now, you can run the complete Agent Mesh application along with your newly added agent: 491 492 ```bash 493 sam run 494 ``` 495 496 Alternatively, only run the newly added agent using `sam run configs/agents/my-first-weather-agent.yaml` 497 498 ### Quick Debug Mode 499 500 :::tip[Quick Debug] 501 502 For debugging or isolated development testing, you can run your agent from the `src` directory directly using the Agent Mesh CLI. 503 504 ```bash 505 cd src 506 sam run ../config.yaml 507 ``` 508 509 Changing to the src directory allows the module path to be set correctly so that Agent Mesh can find your functions without your having to install them in your python environment as a plugin package. 510 ::: 511 512 This quick debug mode is useful during development because you can make changes to your code and immediately test them without rebuilding and reinstalling the plugin. However, you should always test with the full plugin installation process before deploying to production. 513 514 ## Advanced Concepts 515 516 Once you understand the basics, you can explore more advanced patterns for building sophisticated agents. 517 518 ### Working with Artifacts 519 520 The artifact service allows your tools to create, store, and retrieve files. You can enhance your hello tool to save greetings to a file using the artifact service: 521 522 ```python 523 524 from datetime import datetime 525 from solace_agent_mesh.agent.utils.artifact_helpers import save_artifact_with_metadata 526 527 async def hello_tool_with_artifact( 528 name: str, 529 save_to_file: bool = False, 530 tool_context: Optional[ToolContext] = None, 531 tool_config: Optional[Dict[str, Any]] = None 532 ) -> Dict[str, Any]: 533 """ 534 Greets a user and optionally saves the greeting to a file. 535 """ 536 log_identifier = "[HelloToolWithArtifact]" 537 538 # Generate greeting (same as before) 539 greeting_prefix = tool_config.get("greeting_prefix", "Hello") if tool_config else "Hello" 540 greeting_message = f"{greeting_prefix}, {name}! Welcome to Agent Mesh!" 541 542 result = { 543 "status": "success", 544 "message": greeting_message, 545 "greeted_name": name 546 } 547 548 # Save to artifact if requested 549 if save_to_file and tool_context: 550 try: 551 # Prepare content 552 timestamp = datetime.now(timezone.utc) 553 filename = f"greeting_{name}_{timestamp}.txt" 554 content = f"Greeting: {greeting_message}\nTimestamp: {timestamp}\n" 555 556 # Save artifact 557 artifact_service = tool_context._invocation_context.artifact_service 558 await save_artifact_with_metadata( 559 artifact_service=artifact_service, 560 app_name=tool_context._invocation_context.app_name, 561 user_id=tool_context._invocation_context.user_id, 562 session_id=tool_context._invocation_context.session.id, 563 filename=filename, 564 content_bytes=content.encode('utf-8'), 565 mime_type="application/json", 566 metadata_dict={ 567 "description": "Greeting message", 568 "source": "Greeting Agent", 569 }, 570 timestamp=timestamp 571 ) 572 573 result["artifact_saved"] = filename 574 log.info(f"{log_identifier} Saved greeting to artifact: {filename}") 575 576 except Exception as e: 577 log.error(f"{log_identifier} Failed to save artifact: {e}") 578 result["artifact_error"] = str(e) 579 580 return result 581 ``` 582 583 This enhanced tool demonstrates several important concepts. The `save_to_file` parameter allows the LLM to decide whether to save the greeting based on the user's request. This gives your agent flexibility in how it uses the tool. 584 585 The `tool_context` object provides access to the artifact service through its `_invocation_context` property. The invocation context contains information about the current execution environment, including the user ID, session ID, and app name. These identifiers are necessary for properly organizing and retrieving artifacts. 586 587 The `save_artifact_with_metadata` helper function handles the details of saving files to the artifact service. You provide the content as bytes, specify a MIME type, and include metadata that describes the artifact. The metadata makes it easier to search for and manage artifacts later. 588 589 Error handling is important when working with external services. The try-except block ensures that if artifact saving fails, your tool can still return a successful greeting. The error is logged and included in the result, allowing the LLM to inform the user about the issue. 590 591 ### Using Multiple Tool Configurations 592 593 You can configure the same tool function multiple times with different settings. This pattern is useful when you want to provide the LLM with multiple variations of the same capability: 594 595 ```yaml 596 tools: 597 # Formal greeting 598 - tool_type: python 599 component_module: "my_hello_agent.tools" 600 function_name: "hello_tool" 601 tool_name: "formal_greeting" 602 tool_config: 603 greeting_prefix: "Good day" 604 605 # Casual greeting 606 - tool_type: python 607 component_module: "my_hello_agent.tools" 608 function_name: "hello_tool" 609 tool_name: "casual_greeting" 610 tool_config: 611 greeting_prefix: "Hey there" 612 613 # Enthusiastic greeting 614 - tool_type: python 615 component_module: "my_hello_agent.tools" 616 function_name: "hello_tool" 617 tool_name: "enthusiastic_greeting" 618 tool_config: 619 greeting_prefix: "Hello and welcome" 620 ``` 621 622 This configuration creates three different tools from the same function. The LLM sees these as distinct capabilities and can choose the appropriate greeting style based on the context of the conversation. For example, it might use the formal greeting for business contexts and the casual greeting for friendly conversations. 623 624 Each tool configuration should have a unique `tool_name` and should be listed in your agent card's skills section. This makes each variation discoverable and allows you to provide specific descriptions for each greeting style. 625 626 ## Quick Start: Using the CLI 627 628 If you want to get started quickly without manually creating all the files, you can use the Agent Mesh CLI to generate the basic structure: 629 630 ```bash 631 sam add agent my-first-agent 632 ``` 633 634 This command launches an interactive setup (or use `--gui` for browser-based configuration) that generates the necessary files and configuration, and sets up the basic agent structure. 635 636 Note that creating an agent as a plugin is preferred over creating an agent directly because plugins are more portable and easier to share. 637 638 ### CLI Options 639 640 You can customize the agent creation with provided CLI options. For a complete list of options, run: 641 642 ```bash 643 sam add agent --help 644 ``` 645 646 The CLI tool is useful for quickly scaffolding new agents, but understanding the manual process helps you customize and troubleshoot your agents more effectively. 647 648 ## Best Practices 649 650 Following these best practices will help you create robust, maintainable agents. 651 652 ### Tool Design 653 654 Each tool should do one thing well. This single responsibility principle makes your tools easier to test, debug, and reuse. Instead of creating one large tool that handles multiple tasks, create several focused tools that each handle a specific task. 655 656 Write detailed docstrings for your tools. The LLM uses these docstrings to understand what each tool does and when to use it. Include descriptions of all parameters, return values, and any important behavior or limitations. 657 658 Always return structured error responses. When something goes wrong, your tool should return a dictionary with a status field indicating failure and a message explaining what went wrong. This allows the LLM to understand the error and potentially retry with different parameters or inform the user about the issue. 659 660 Use consistent logging for debugging and monitoring. Log important events, parameter values, and results. This makes it much easier to troubleshoot issues when your agent is running in production. 661 662 ### Configuration 663 664 Use environment variables for sensitive data like API keys, database passwords, and other credentials. Never hardcode sensitive information in your configuration files or source code. 665 666 Use Pydantic models for configuration validation. This catches configuration errors early and provides clear error messages when something is wrong. It also serves as documentation for what configuration options are available. 667 668 Comment your configuration files thoroughly. YAML files can become complex, and clear comments help other developers (and your future self) understand what each section does and why it's configured that way. 669 670 ### Testing 671 672 Write unit tests for your tool functions independently. Test them with various inputs, including edge cases and error conditions. Mock the `tool_context` and `tool_config` parameters to isolate your tool logic from the framework. 673 674 Write integration tests that test your agent with real Agent Mesh infrastructure. These tests verify that your configuration is correct and that your tools work properly when called by the LLM. 675 676 Mock external dependencies for reliable testing. If your tools call external APIs or databases, create mock versions for testing. This makes your tests faster and more reliable because they don't depend on external services being available.