solace-agent-mesh 1.3.2__py3-none-any.whl → 1.4.0__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 solace-agent-mesh might be problematic. Click here for more details.
- solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +16 -8
- solace_agent_mesh/agent/adk/setup.py +183 -8
- solace_agent_mesh/agent/sac/app.py +337 -622
- solace_agent_mesh/agent/sac/component.py +47 -1
- solace_agent_mesh/agent/tools/dynamic_tool.py +36 -5
- solace_agent_mesh/agent/tools/tool_config_types.py +58 -0
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/0e682baa.da822665.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1023fc19.8a8a9309.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1523c6b4.2645ef68.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.43771adc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2a9cab12.2afaee76.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/332e10b5.f7629851.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3d406171.5560fdf9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.508ae8db.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/442a8107.b5c2532a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/483cef9a.8d318c2f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55f47984.bcd00a86.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5b4258a4.dff11eca.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/664b740a.ba305a89.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/75384d09.abdf9cf9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/768e31b0.9abcdc48.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/945fb41e.abf2be91.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.92de8cf5.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.d62aad71.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.1d029b81.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{aba87c2f.071e2d94.js → aba87c2f.4ddf32f2.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.abca774a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ae4415af.24cdc514.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/bac0be12.27ee2c26.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c2c06897.87cb1f47.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c835a94d.ce21f0bf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cc969b05.feef7dcc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cd3d4052.a19e7d78.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{cee5d587.f5b73ca1.js → cee5d587.f1e1ca86.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.cad4dbf2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f897a61a.bc634a3e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{main.4adc477a.js → main.1de3da6a.js} +2 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.3188e049.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +18 -18
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +9 -9
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +23 -23
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +9 -9
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +8 -8
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +9 -9
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +19 -19
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +73 -8
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
- solace_agent_mesh/assets/docs/lunr-index-1757991496554.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757991496554.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/run_cmd.py +4 -7
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-CAX9u8a7.js → authCallback-j1LW-wlq.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-DXU9SPI5.js → client-B9p_nFNA.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-B9s_V9tJ.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-Dq4AJNvn.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-B0BEKoAR.js → vendor-CS5YMf8a.js} +74 -69
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
- solace_agent_mesh/common/utils/pydantic_utils.py +56 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/registry_manager.py +6 -4
- solace_agent_mesh/gateway/base/app.py +58 -120
- solace_agent_mesh/gateway/http_sse/app.py +99 -150
- solace_agent_mesh/gateway/http_sse/component.py +57 -30
- solace_agent_mesh/gateway/http_sse/sse_event_buffer.py +87 -0
- solace_agent_mesh/gateway/http_sse/sse_manager.py +44 -23
- {solace_agent_mesh-1.3.2.dist-info → solace_agent_mesh-1.4.0.dist-info}/METADATA +1 -1
- {solace_agent_mesh-1.3.2.dist-info → solace_agent_mesh-1.4.0.dist-info}/RECORD +103 -100
- solace_agent_mesh/assets/docs/assets/js/0e682baa.b3bbde9a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1023fc19.364235d5.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1523c6b4.1b0ec6f9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.a8c5ce5a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/2a9cab12.8909df92.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/332e10b5.7a103f42.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3d406171.0b9eeed1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.d97b8e94.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/442a8107.b3159bb2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/483cef9a.03d5dceb.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55f47984.cf3781c4.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5b4258a4.0d080cd9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/664b740a.1b744a32.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/75384d09.c193a8f0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/768e31b0.8b51cd70.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/945fb41e.c63791d1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.d6607c56.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.472b0310.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.4b7fa6a2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.4d8dda10.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae4415af.7a2f0bbf.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/bac0be12.f50d9bac.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c2c06897.587b4af5.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c835a94d.146e3186.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cc969b05.bd3e0d6c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cd3d4052.b6535013.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.7334119c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f897a61a.0aa29dbb.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/runtime~main.cf0229ea.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1757704179464.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1757704179464.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-DjoMeldu.js +0 -339
- /solace_agent_mesh/assets/docs/assets/js/{main.4adc477a.js.LICENSE.txt → main.1de3da6a.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.3.2.dist-info → solace_agent_mesh-1.4.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.3.2.dist-info → solace_agent_mesh-1.4.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.3.2.dist-info → solace_agent_mesh-1.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[3520],{8100:(e,a,n)=>{n.r(a),n.d(a,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>t,toc:()=>c});const t=JSON.parse('{"id":"documentation/tutorials/sql-database","title":"SQL Database Integration","description":"This tutorial sets up a SQL database agent in Solace Agent Mesh (SAM), which allows the SAM agent to answer natural language queries about a sample coffee company database. This tutorial provides some sample data to set up an SQLite database, but you can use the same approach to connect to other database types, such as MySQL or PostgreSQL.","source":"@site/docs/documentation/tutorials/sql-database.md","sourceDirName":"documentation/tutorials","slug":"/documentation/tutorials/sql-database","permalink":"/solace-agent-mesh/docs/documentation/tutorials/sql-database","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/tutorials/sql-database.md","tags":[],"version":"current","sidebarPosition":40,"frontMatter":{"title":"SQL Database Integration","sidebar_position":40},"sidebar":"docSidebar","previous":{"title":"Amazon Bedrock Agents","permalink":"/solace-agent-mesh/docs/documentation/tutorials/bedrock-agents"},"next":{"title":"MongoDB Integration","permalink":"/solace-agent-mesh/docs/documentation/tutorials/mongodb-integration"}}');var s=n(4848),i=n(8453);const o={title:"SQL Database Integration",sidebar_position:40},r="SQL Database Integration",l={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Adding the SQL Database Plugin",id:"adding-the-sql-database-plugin",level:2},{value:"Downloading Example Data",id:"downloading-example-data",level:2},{value:"Using wget",id:"using-wget",level:4},{value:"Using curl",id:"using-curl",level:4},{value:"Configuring the Agent",id:"configuring-the-agent",level:2},{value:"Setting the Environment Variables",id:"setting-the-environment-variables",level:2},{value:"Running the Agent",id:"running-the-agent",level:2},{value:"Interacting with the Database",id:"interacting-with-the-database",level:2},{value:"Advanced Configuration",id:"advanced-configuration",level:2},{value:"Customizing the Agent Card",id:"customizing-the-agent-card",level:2},{value:"Key Agent Card Elements",id:"key-agent-card-elements",level:3},{value:"Example of a Well-Configured Agent Card",id:"example-of-a-well-configured-agent-card",level:3}];function d(e){const a={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.header,{children:(0,s.jsx)(a.h1,{id:"sql-database-integration",children:"SQL Database Integration"})}),"\n",(0,s.jsx)(a.p,{children:"This tutorial sets up a SQL database agent in Solace Agent Mesh (SAM), which allows the SAM agent to answer natural language queries about a sample coffee company database. This tutorial provides some sample data to set up an SQLite database, but you can use the same approach to connect to other database types, such as MySQL or PostgreSQL."}),"\n",(0,s.jsx)(a.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,s.jsx)(a.p,{children:"Before starting this tutorial, ensure that you have installed and configured Solace Agent Mesh:"}),"\n",(0,s.jsxs)(a.ul,{children:["\n",(0,s.jsx)(a.li,{children:(0,s.jsx)(a.a,{href:"/solace-agent-mesh/docs/documentation/getting-started/installation",children:"Installed Solace Agent Mesh and the SAM CLI"})}),"\n",(0,s.jsx)(a.li,{children:(0,s.jsx)(a.a,{href:"/solace-agent-mesh/docs/documentation/getting-started/quick-start",children:"Created a new Solace Agent Mesh project"})}),"\n",(0,s.jsx)(a.li,{children:"Access to a SQL database (local or remote)"}),"\n"]}),"\n",(0,s.jsx)(a.h2,{id:"adding-the-sql-database-plugin",children:"Adding the SQL Database Plugin"}),"\n",(0,s.jsx)(a.p,{children:"Add the SQL Database plugin to your SAM project:"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-sh",children:"sam plugin add abc-coffee-info --plugin sam-sql-database\n"})}),"\n",(0,s.jsxs)(a.p,{children:["You can use any name for your agent, in this tutorial we use ",(0,s.jsx)(a.code,{children:"abc-coffee-info"}),"."]}),"\n",(0,s.jsx)(a.p,{children:"This command:"}),"\n",(0,s.jsxs)(a.ul,{children:["\n",(0,s.jsxs)(a.li,{children:["Installs the ",(0,s.jsx)(a.code,{children:"sam-sql-database"})," plugin"]}),"\n",(0,s.jsxs)(a.li,{children:["Creates a new agent configuration file at ",(0,s.jsx)(a.code,{children:"configs/agents/abc-coffee-info.yaml"})]}),"\n"]}),"\n",(0,s.jsx)(a.h2,{id:"downloading-example-data",children:"Downloading Example Data"}),"\n",(0,s.jsx)(a.p,{children:"For this tutorial, you can use a sample SQLite database for a fictional coffee company called ABC Coffee Co."}),"\n",(0,s.jsx)(a.p,{children:"First, download the example data."}),"\n",(0,s.jsx)(a.p,{children:"You can either visit this link to download with your browser:"}),"\n",(0,s.jsx)(a.p,{children:(0,s.jsx)(a.a,{href:"https://github.com/SolaceLabs/solace-agent-mesh-core-plugins/raw/refs/heads/main/sam-sql-database/example-data/abc_coffee_co.zip",children:"https://github.com/SolaceLabs/solace-agent-mesh-core-plugins/raw/refs/heads/main/sam-sql-database/example-data/abc_coffee_co.zip"})}),"\n",(0,s.jsx)(a.p,{children:"Or you can use the command line to download the ZIP file:"}),"\n",(0,s.jsx)(a.h4,{id:"using-wget",children:"Using wget"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-sh",children:"wget https://github.com/SolaceLabs/solace-agent-mesh-core-plugins/raw/refs/heads/main/sam-sql-database/example-data/abc_coffee_co.zip\n"})}),"\n",(0,s.jsx)(a.h4,{id:"using-curl",children:"Using curl"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-sh",children:"curl -LO https://github.com/SolaceLabs/solace-agent-mesh-core-plugins/raw/refs/heads/main/sam-sql-database/example-data/abc_coffee_co.zip\n"})}),"\n",(0,s.jsx)(a.p,{children:"After downloading the ZIP file, extract it to a directory of your choice. You can use the following command to extract the ZIP file:"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-sh",children:"unzip abc_coffee_co.zip\n"})}),"\n",(0,s.jsx)(a.h2,{id:"configuring-the-agent",children:"Configuring the Agent"}),"\n",(0,s.jsxs)(a.p,{children:["Now, update the agent configuration to use the SQLite database and import the CSV files.\nOpen the ",(0,s.jsx)(a.code,{children:"configs/agents/abc-coffee-info.yaml"})," file and modify the ",(0,s.jsx)(a.code,{children:"agent_init_function.config"})," section to specify the CSV directory."]}),"\n",(0,s.jsx)(a.p,{children:"Here is what you need to modify in the configuration file:"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-yaml",children:'# Find the agent_init_function section and update the config:\nagent_init_function:\n module: "sam_sql_database.lifecycle"\n name: "initialize_sql_agent"\n config:\n db_type: "${ABC_COFFEE_INFO_DB_TYPE}"\n db_name: "${ABC_COFFEE_INFO_DB_NAME}"\n database_purpose: "${ABC_COFFEE_INFO_DB_PURPOSE}"\n data_description: "${ABC_COFFEE_INFO_DB_DESCRIPTION}"\n # Add the CSV directory path\n csv_directories:\n - /path/to/your/unzipped/data\n'})}),"\n",(0,s.jsxs)(a.p,{children:["Ensure you replace ",(0,s.jsx)(a.code,{children:"/path/to/your/unzipped/data"})," with the path where you extracted the example data. For example, if you put the ZIP file in the root directory of your Solace Agent Mesh project, you can use ",(0,s.jsx)(a.code,{children:"abc_coffee_co"}),"."]}),"\n",(0,s.jsx)(a.h2,{id:"setting-the-environment-variables",children:"Setting the Environment Variables"}),"\n",(0,s.jsxs)(a.p,{children:["The SQL Database agent requires that you configure several environment variables. You must create or update your ",(0,s.jsx)(a.code,{children:".env"})," file with the following variables for this tutorial:"]}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-bash",children:'ABC_COFFEE_INFO_DB_TYPE=sqlite\nABC_COFFEE_INFO_DB_NAME=abc_coffee.db\nABC_COFFEE_INFO_DB_PURPOSE="ABC Coffee Co. sales and operations database"\nABC_COFFEE_INFO_DB_DESCRIPTION="Contains information about ABC Coffee Co. products, sales, customers, employees, and store locations."\n# You can leave other environment variables as unset or empty\n'})}),"\n",(0,s.jsx)(a.p,{children:"SQLite stores the database in a local file and doesn't require a username or password for access. If you're using a database such as MySQL or PostgreSQL, you'll need to provide the appropriate environment variables for them."}),"\n",(0,s.jsx)(a.h2,{id:"running-the-agent",children:"Running the Agent"}),"\n",(0,s.jsx)(a.p,{children:"Now, you can start your SQL database agent:"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-sh",children:"sam run configs/agents/abc-coffee-info.yaml\n"})}),"\n",(0,s.jsx)(a.p,{children:"The agent:"}),"\n",(0,s.jsxs)(a.ol,{children:["\n",(0,s.jsx)(a.li,{children:"Connects to the A2A control plane"}),"\n",(0,s.jsx)(a.li,{children:"Initializes the SQLite database and imports CSV data from the specified directory"}),"\n",(0,s.jsx)(a.li,{children:"Detects the database schema automatically"}),"\n",(0,s.jsx)(a.li,{children:"Registers its capabilities with the agent discovery system"}),"\n"]}),"\n",(0,s.jsx)(a.h2,{id:"interacting-with-the-database",children:"Interacting with the Database"}),"\n",(0,s.jsxs)(a.p,{children:["After your SQL database agent is running, you can interact with the ABC Coffee database through any gateway in your SAM project (such as the Web UI gateway at ",(0,s.jsx)(a.code,{children:"http://localhost:8000"}),")."]}),"\n",(0,s.jsx)(a.p,{children:"You can ask natural language questions about the ABC Coffee Co. database, such as:"}),"\n",(0,s.jsxs)(a.ul,{children:["\n",(0,s.jsx)(a.li,{children:'"How many customers does ABC Coffee have?"'}),"\n",(0,s.jsx)(a.li,{children:'"What are the top-selling products?"'}),"\n",(0,s.jsx)(a.li,{children:'"Show me the sales by region"'}),"\n",(0,s.jsx)(a.li,{children:'"List all orders from the last 30 days"'}),"\n",(0,s.jsx)(a.li,{children:'"What products are currently low in inventory?"'}),"\n"]}),"\n",(0,s.jsx)(a.p,{children:"Try creating reports by asking questions such as:"}),"\n",(0,s.jsxs)(a.ul,{children:["\n",(0,s.jsx)(a.li,{children:'"Create a report of our sales in 2024"'}),"\n",(0,s.jsx)(a.li,{children:'"Generate a summary of customer demographics"'}),"\n"]}),"\n",(0,s.jsx)(a.p,{children:"The SQL Database agent converts your natural language questions into SQL queries, executes them against the database, and returns the results. For large result sets, the agent automatically saves the results as artifacts that you can download."}),"\n",(0,s.jsx)(a.h2,{id:"advanced-configuration",children:"Advanced Configuration"}),"\n",(0,s.jsx)(a.p,{children:"The SQL Database plugin supports many advanced configuration options. Here is a complete example based on the plugin structure:"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-yaml",children:'log:\n stdout_log_level: INFO\n log_file_level: DEBUG\n log_file: abc-coffee-info.log\n\n!include ../shared_config.yaml\n\napps:\n - name: abc-coffee-info-app\n app_module: solace_agent_mesh.agent.sac.app \n broker:\n <<: *broker_connection\n\n app_config:\n namespace: ${NAMESPACE}\n agent_name: "AbcCoffeeInfo"\n display_name: "ABC Coffee Database Agent"\n supports_streaming: false\n model: *general_model\n\n instruction: |\n You are an expert SQL assistant for the ABC Coffee Co. database.\n The database schema and query examples are provided to you.\n Your primary goal is to translate user questions into accurate SQL queries.\n If a user asks to query the database, generate the SQL and call the \'execute_sql_query\' tool.\n If the \'execute_sql_query\' tool returns an error, analyze the error message and the original SQL,\n then try to correct the SQL query and call the tool again.\n If the results are large and the tool indicates they were saved as an artifact, inform the user about the artifact.\n Always use the \'execute_sql_query\' tool to interact with the database.\n\n # Agent initialization with database setup\n agent_init_function:\n module: "sam_sql_database.lifecycle"\n name: "initialize_sql_agent"\n config:\n db_type: "${ABC_COFFEE_INFO_DB_TYPE}"\n db_name: "${ABC_COFFEE_INFO_DB_NAME}"\n database_purpose: "${ABC_COFFEE_INFO_DB_PURPOSE}"\n data_description: "${ABC_COFFEE_INFO_DB_DESCRIPTION}"\n auto_detect_schema: true\n csv_directories:\n - "abc_coffee_co" # Path to your extracted data\n query_examples:\n - natural_language: "Show all customers from New York"\n sql_query: "SELECT * FROM customers WHERE city = \'New York\';"\n - natural_language: "What are the top 5 best-selling products?"\n sql_query: "SELECT product_name, SUM(quantity) as total_sold FROM order_items JOIN products ON order_items.product_id = products.id GROUP BY product_name ORDER BY total_sold DESC LIMIT 5;"\n\n agent_cleanup_function:\n module: "sam_sql_database.lifecycle"\n name: "cleanup_sql_agent_resources"\n\n # SQL query tool\n tools:\n - tool_type: python\n component_module: "sam_sql_database.tools"\n function_name: "execute_sql_query"\n\n session_service: *default_session_service\n artifact_service: *default_artifact_service\n\n # Agent capabilities - This is what other agents see during discovery\n agent_card:\n description: "ABC Coffee Co. Database Agent - Access to comprehensive coffee shop data including customers, orders, products, inventory, and sales history. Can answer questions about business metrics, customer analytics, product performance, and operational data."\n defaultInputModes: ["text"]\n defaultOutputModes: ["text", "file"]\n skills:\n - id: "sql_query"\n name: "Coffee Shop Database Query"\n description: "Queries ABC Coffee Co. database containing customer orders, product catalog, inventory levels, sales history, and employee data."\n\n # A2A Protocol settings\n agent_card_publishing: { interval_seconds: 30 }\n agent_discovery: { enabled: true }\n inter_agent_communication:\n allow_list: ["*"]\n request_timeout_seconds: 60\n'})}),"\n",(0,s.jsx)(a.h2,{id:"customizing-the-agent-card",children:"Customizing the Agent Card"}),"\n",(0,s.jsxs)(a.p,{children:["The ",(0,s.jsx)(a.code,{children:"agent_card"})," section is crucial as it defines how other agents in your SAM ecosystem discover and understand this database agent's capabilities. When other agents use agent discovery, they can see this information to decide whether to delegate tasks to your database agent."]}),"\n",(0,s.jsx)(a.h3,{id:"key-agent-card-elements",children:"Key Agent Card Elements"}),"\n",(0,s.jsxs)(a.ol,{children:["\n",(0,s.jsxs)(a.li,{children:[(0,s.jsx)(a.strong,{children:"Description"}),": Clearly describe what data the agent has access to and what types of questions it can answer"]}),"\n",(0,s.jsxs)(a.li,{children:[(0,s.jsx)(a.strong,{children:"Skills"}),": List specific capabilities with concrete examples that show the scope of data available"]}),"\n",(0,s.jsxs)(a.li,{children:[(0,s.jsx)(a.strong,{children:"Data Context"}),": Mention the business domain, data types, and scope of information available"]}),"\n"]}),"\n",(0,s.jsx)(a.h3,{id:"example-of-a-well-configured-agent-card",children:"Example of a Well-Configured Agent Card"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-yaml",children:'agent_card:\n description: "ABC Coffee Co. Database Agent - Access to comprehensive coffee shop data including customers, orders, products, inventory, and sales history. Can answer questions about business metrics, customer analytics, product performance, and operational data."\n defaultInputModes: ["text"]\n defaultOutputModes: ["text", "file"]\n skills:\n - id: "sql_query"\n name: "Coffee Shop Database Query"\n description: "Queries ABC Coffee Co. database containing customer orders, product catalog, inventory levels, sales history, and employee data."\n'})}),"\n",(0,s.jsx)(a.p,{children:"This detailed information helps other agents understand:"}),"\n",(0,s.jsxs)(a.ul,{children:["\n",(0,s.jsx)(a.li,{children:"What business domain this agent covers (coffee shop operations)"}),"\n",(0,s.jsx)(a.li,{children:"What types of data are available (customers, orders, products, inventory, sales)"}),"\n",(0,s.jsx)(a.li,{children:"What kinds of questions can be answered (metrics, analytics, performance data)"}),"\n",(0,s.jsx)(a.li,{children:"Specific examples of queries that work well"}),"\n"]}),"\n",(0,s.jsx)(a.p,{children:"When configuring your own database agent, customize the description and examples to match your specific data and use cases."})]})}function h(e={}){const{wrapper:a}={...(0,i.R)(),...e.components};return a?(0,s.jsx)(a,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,a,n)=>{n.d(a,{R:()=>o,x:()=>r});var t=n(6540);const s={},i=t.createContext(s);function o(e){const a=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(a):{...a,...e}}),[a,e])}function r(e){let a;return a=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),t.createElement(i.Provider,{value:a},e.children)}}}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[9150],{4897:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>a,contentTitle:()=>l,default:()=>h,frontMatter:()=>r,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"documentation/tutorials/bedrock-agents","title":"Amazon Bedrock Agents","description":"This tutorial walks you through the process of integrating Amazon Bedrock Agents and Flows into Solace Agent Mesh (SAM). This integration allows you to create agents that can interact with one or multiple Bedrock Agents or Flows, extending your SAM project with powerful AI capabilities from AWS.","source":"@site/docs/documentation/tutorials/bedrock-agents.md","sourceDirName":"documentation/tutorials","slug":"/documentation/tutorials/bedrock-agents","permalink":"/solace-agent-mesh/docs/documentation/tutorials/bedrock-agents","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/tutorials/bedrock-agents.md","tags":[],"version":"current","sidebarPosition":30,"frontMatter":{"title":"Amazon Bedrock Agents","sidebar_position":30,"toc_max_heading_level":4},"sidebar":"docSidebar","previous":{"title":"Event Mesh Gateway","permalink":"/solace-agent-mesh/docs/documentation/tutorials/event-mesh-gateway"},"next":{"title":"SQL Database Integration","permalink":"/solace-agent-mesh/docs/documentation/tutorials/sql-database"}}');var s=o(4848),t=o(8453);const r={title:"Amazon Bedrock Agents",sidebar_position:30,toc_max_heading_level:4},l="Amazon Bedrock Agents Integration",a={},c=[{value:"What are Amazon Bedrock Agents and Flows?",id:"what-are-amazon-bedrock-agents-and-flows",level:2},{value:"Setting Up the Environment",id:"setting-up-the-environment",level:2},{value:"Create Bedrock Agents and Flows",id:"create-bedrock-agents-and-flows",level:3},{value:"Create a SAM Project",id:"create-a-sam-project",level:3},{value:"Integrating Bedrock with SAM",id:"integrating-bedrock-with-sam",level:2},{value:"Adding the Bedrock Agent Plugin",id:"adding-the-bedrock-agent-plugin",level:3},{value:"Configuring the Bedrock Agent",id:"configuring-the-bedrock-agent",level:2},{value:"Understanding the Configuration Structure",id:"understanding-the-configuration-structure",level:3},{value:"Example Configuration",id:"example-configuration",level:3},{value:"Customizing Your Configuration",id:"customizing-your-configuration",level:3},{value:"Environment Variables",id:"environment-variables",level:3},{value:"Required Solace Variables:",id:"required-solace-variables",level:4},{value:"Optional AWS Variables:",id:"optional-aws-variables",level:4},{value:"Running and Testing Your Integration",id:"running-and-testing-your-integration",level:2},{value:"Starting Your SAM Project",id:"starting-your-sam-project",level:3},{value:"Testing the Integration",id:"testing-the-integration",level:3},{value:"Using the Web UI Gateway",id:"using-the-web-ui-gateway",level:4},{value:"Testing with File Uploads",id:"testing-with-file-uploads",level:4},{value:"Troubleshooting",id:"troubleshooting",level:2},{value:"Common Issues and Solutions",id:"common-issues-and-solutions",level:3},{value:"Authentication Errors",id:"authentication-errors",level:4},{value:"Configuration Errors",id:"configuration-errors",level:4},{value:"Connection Issues",id:"connection-issues",level:4},{value:"File Upload Issues",id:"file-upload-issues",level:4}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"amazon-bedrock-agents-integration",children:"Amazon Bedrock Agents Integration"})}),"\n",(0,s.jsx)(n.p,{children:"This tutorial walks you through the process of integrating Amazon Bedrock Agents and Flows into Solace Agent Mesh (SAM). This integration allows you to create agents that can interact with one or multiple Bedrock Agents or Flows, extending your SAM project with powerful AI capabilities from AWS."}),"\n",(0,s.jsx)(n.h2,{id:"what-are-amazon-bedrock-agents-and-flows",children:"What are Amazon Bedrock Agents and Flows?"}),"\n",(0,s.jsx)(n.p,{children:"Amazon Bedrock Agents are AI assistants that can be customized to perform specific tasks using foundation models (FMs). They can connect to enterprise systems and data sources, allowing them to take actions on behalf of users."}),"\n",(0,s.jsx)(n.p,{children:"Amazon Bedrock Flows are visual workflows that orchestrate multiple foundation models to solve complex problems. They allow you to chain together different AI capabilities without writing code."}),"\n",(0,s.jsx)(n.p,{children:"By integrating these services with SAM, you can:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Use the extensible SAM framework to combine Bedrock agents and flows with other agents."}),"\n",(0,s.jsx)(n.li,{children:"Create conversational interfaces that leverage Bedrock agents and flows."}),"\n",(0,s.jsx)(n.li,{children:"Connect your SAM agents to enterprise data sources through Bedrock."}),"\n",(0,s.jsx)(n.li,{children:"Maintain a consistent experience across different agent providers by centralizing them in SAM."}),"\n"]}),"\n",(0,s.jsx)(n.admonition,{title:"Learn about Bedrock Agents and Flows",type:"info",children:(0,s.jsxs)(n.p,{children:["Check the official documentation for ",(0,s.jsx)(n.a,{href:"https://aws.amazon.com/bedrock/agents/",children:"Amazon Bedrock Agents"})," and ",(0,s.jsx)(n.a,{href:"https://aws.amazon.com/bedrock/flows/",children:"Amazon Bedrock Flows"})," to learn more about these features."]})}),"\n",(0,s.jsx)(n.h2,{id:"setting-up-the-environment",children:"Setting Up the Environment"}),"\n",(0,s.jsx)(n.h3,{id:"create-bedrock-agents-and-flows",children:"Create Bedrock Agents and Flows"}),"\n",(0,s.jsx)(n.p,{children:"Follow these steps to create your Bedrock resources:"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Log in to your AWS console"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Navigate to the Amazon Bedrock service"}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Create Bedrock Agents"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Go to the ",(0,s.jsx)(n.strong,{children:"Agents"})," tab in the Bedrock console"]}),"\n",(0,s.jsx)(n.li,{children:'Click "Create agent"'}),"\n",(0,s.jsxs)(n.li,{children:["Follow the wizard to configure your agent:","\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Select a foundation model"}),"\n",(0,s.jsx)(n.li,{children:"Define the agent's instructions"}),"\n",(0,s.jsx)(n.li,{children:"Configure knowledge bases (optional)"}),"\n",(0,s.jsx)(n.li,{children:"Set up action groups (if needed)"}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["Once created, ",(0,s.jsx)(n.strong,{children:"create an alias"}),' for your agent by selecting it and clicking "Create alias"']}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Copy the Agent ID and Alias ID"})," from the agent details page - you'll need these for the SAM configuration"]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Create Bedrock Flows"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Go to the ",(0,s.jsx)(n.strong,{children:"Flows"})," tab in the Bedrock console"]}),"\n",(0,s.jsx)(n.li,{children:'Click "Create flow"'}),"\n",(0,s.jsx)(n.li,{children:"Use the visual editor to design your flow"}),"\n",(0,s.jsx)(n.li,{children:"Connect nodes to create your workflow"}),"\n",(0,s.jsx)(n.li,{children:"Test and publish your flow"}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Create an alias"})," for your flow"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Copy the Flow ID and Alias ID"})," - you'll need these for the SAM configuration"]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Set up IAM permissions"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Ensure your IAM user or role has the following permissions:","\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.code,{children:"bedrock:InvokeAgent"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.code,{children:"bedrock:InvokeFlow"})}),"\n",(0,s.jsx)(n.li,{children:"Any other permissions required by your specific Bedrock configuration"}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"create-a-sam-project",children:"Create a SAM Project"}),"\n",(0,s.jsxs)(n.p,{children:["You must ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/getting-started/installation",children:"install Solace Agent Mesh and Solace Mesh Agent (SAM) CLI"}),", and then you'll want to ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/getting-started/quick-start",children:"create a new Solace Agent Mesh project"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"integrating-bedrock-with-sam",children:"Integrating Bedrock with SAM"}),"\n",(0,s.jsx)(n.h3,{id:"adding-the-bedrock-agent-plugin",children:"Adding the Bedrock Agent Plugin"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"sam-bedrock-agent"})," plugin from the ",(0,s.jsx)(n.a,{href:"https://github.com/SolaceLabs/solace-agent-mesh-core-plugins/tree/main/sam-bedrock-agent",children:"solace-agent-mesh-core-plugins"})," repository creates a bridge between SAM and Amazon Bedrock services. This plugin allows your SAM agents to invoke Bedrock Agents and Flows as tools."]}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Add the plugin to your SAM project"}),":"]}),"\n"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"sam plugin add aws-agent --plugin sam-bedrock-agent\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Replace ",(0,s.jsx)(n.code,{children:"aws-agent"})," with a descriptive name for your agent, such as ",(0,s.jsx)(n.code,{children:"bedrock-summarizer"})," or ",(0,s.jsx)(n.code,{children:"bedrock-customer-service"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"This command:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Installs the ",(0,s.jsx)(n.code,{children:"sam-bedrock-agent"})," plugin"]}),"\n",(0,s.jsxs)(n.li,{children:["Creates a new agent configuration file in ",(0,s.jsx)(n.code,{children:"configs/agents/aws-agent.yaml"})]}),"\n"]}),"\n",(0,s.jsxs)(n.ol,{start:"2",children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Locate the configuration file"}),":"]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["The command creates an ",(0,s.jsx)(n.code,{children:"aws-agent.yaml"})," file in the ",(0,s.jsx)(n.code,{children:"configs/agents/"})," directory of your SAM project."]}),"\n",(0,s.jsx)(n.admonition,{title:"Naming Convention",type:"tip",children:(0,s.jsx)(n.p,{children:"Choose a descriptive name that reflects the purpose of your Bedrock integration. This name is used to reference the agent in your SAM project."})}),"\n",(0,s.jsx)(n.h2,{id:"configuring-the-bedrock-agent",children:"Configuring the Bedrock Agent"}),"\n",(0,s.jsx)(n.p,{children:"The configuration file you created needs to be edited to connect to your specific Amazon Bedrock resources. This section explains each part of the configuration and how to customize it."}),"\n",(0,s.jsx)(n.h3,{id:"understanding-the-configuration-structure",children:"Understanding the Configuration Structure"}),"\n",(0,s.jsxs)(n.p,{children:["Open the ",(0,s.jsx)(n.code,{children:"aws-agent.yaml"})," file in your editor. The core of the agent's configuration consists of:"]}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"amazon_bedrock_runtime_config"}),": AWS connection settings"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"tools"}),": List of Bedrock agents and flows to expose as tools"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"agent_card"}),": Agent capabilities and skills definition"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"example-configuration",children:"Example Configuration"}),"\n",(0,s.jsx)(n.p,{children:"Here's an annotated example based on the actual plugin structure:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:'log:\n stdout_log_level: INFO\n log_file_level: DEBUG\n log_file: aws-agent.log\n\n!include ../shared_config.yaml\n\napps:\n - name: aws-agent-app\n app_base_path: . \n app_module: solace_agent_mesh.agent.sac.app \n broker:\n <<: *broker_connection\n\n app_config:\n namespace: ${NAMESPACE} \n supports_streaming: true \n agent_name: "AwsAgent" \n display_name: "AwsAgent Component" \n model: *general_model \n\n instruction: |\n You\'re AwsAgent responsible for handling user queries by \n interacting with Amazon Bedrock agents or flows.\n\n # AWS Connection Configuration\n amazon_bedrock_runtime_config: &amazon_bedrock_runtime_config\n endpoint_url: # Optional: Custom AWS endpoint URL\n boto3_config:\n region_name: "us-east-1" # AWS region where your Bedrock resources are located\n aws_access_key_id: # Your AWS access key (or use profiles/env vars)\n aws_secret_access_key: # Your AWS secret key\n\n tools:\n # Bedrock Agent Tool\n - tool_type: python\n component_module: sam_bedrock_agent.bedrock_agent\n component_base_path: . \n function_name: invoke_bedrock_agent\n tool_name: "text_transformer" # Customizable, Name exposed to the LLM\n tool_description: "Transforms text using the Text Transformer agent which summarizes the given text and extracts key points." # Customizable, Optional description\n tool_config:\n amazon_bedrock_runtime_config: *amazon_bedrock_runtime_config\n bedrock_agent_id: "XXXXXXXXXX" # Your actual Bedrock agent ID\n bedrock_agent_alias_id: "XXXXXXXXXX" # Your actual Bedrock agent alias ID\n allow_files: true # Whether to allow file uploads (5 files, 10MB total max)\n\n # Bedrock Flow Tool\n - tool_type: python\n component_module: sam_bedrock_agent.bedrock_flow\n component_base_path: .\n function_name: invoke_bedrock_flow\n tool_name: "poem_writer" # Name exposed to the LLM\n tool_config: \n amazon_bedrock_runtime_config: *amazon_bedrock_runtime_config\n bedrock_flow_id: "XXXXXXXXXX" # Your actual Bedrock flow ID\n bedrock_flow_alias_id: "XXXXXXXXXX" # Your actual Bedrock flow alias ID\n\n # Agent capabilities\n agent_card:\n description: "Agent that integrates with Amazon Bedrock agents and flows for various AI tasks."\n defaultInputModes: ["text"]\n defaultOutputModes: ["text"]\n skills: \n - id: "text_transformer"\n name: "Text Transformer"\n description: "Transforms text using the Text Transformer agent."\n - id: "poem_writer"\n name: "Poem Writer"\n description: "Generates poems based on user input."\n\n # A2A Protocol settings\n agent_card_publishing: { interval_seconds: 10 }\n agent_discovery: { enabled: true }\n inter_agent_communication:\n allow_list: ["*"]\n request_timeout_seconds: 30\n'})}),"\n",(0,s.jsx)(n.h3,{id:"customizing-your-configuration",children:"Customizing Your Configuration"}),"\n",(0,s.jsx)(n.p,{children:"Follow these steps to customize your configuration:"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Configure AWS Connection"}),":","\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Set the ",(0,s.jsx)(n.code,{children:"region_name"})," to the AWS region where your Bedrock resources are located"]}),"\n",(0,s.jsxs)(n.li,{children:["Choose one of these authentication methods:","\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Set ",(0,s.jsx)(n.code,{children:"aws_access_key_id"})," and ",(0,s.jsx)(n.code,{children:"aws_secret_access_key"})," directly in the config."]}),"\n",(0,s.jsx)(n.li,{children:"Use AWS profiles by removing these fields and configuring your AWS CLI profile."}),"\n",(0,s.jsx)(n.li,{children:"Use environment variables (see Environment Variables section below)."}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["Check the ",(0,s.jsx)(n.a,{href:"https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html",children:"boto3 documentation"})," for more details."]}),"\n",(0,s.jsxs)(n.ol,{start:"2",children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Configure Bedrock Agent Tools"}),":"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["For each Bedrock agent you want to expose, add a tool entry:","\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Set a descriptive ",(0,s.jsx)(n.code,{children:"tool_name"})," (for example, ",(0,s.jsx)(n.code,{children:"text_summarizer"}),", ",(0,s.jsx)(n.code,{children:"content_generator"}),")."]}),"\n",(0,s.jsxs)(n.li,{children:["Provide a clear ",(0,s.jsx)(n.code,{children:"tool_description"})," of what the agent does."]}),"\n",(0,s.jsxs)(n.li,{children:["Replace ",(0,s.jsx)(n.code,{children:"bedrock_agent_id"})," with your actual Bedrock agent ID."]}),"\n",(0,s.jsxs)(n.li,{children:["Replace ",(0,s.jsx)(n.code,{children:"bedrock_agent_alias_id"})," with your actual Bedrock agent alias ID."]}),"\n",(0,s.jsxs)(n.li,{children:["Set ",(0,s.jsx)(n.code,{children:"allow_files"})," to ",(0,s.jsx)(n.code,{children:"true"})," if your agent can process file uploads."]}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Configure Bedrock Flow Tools"}),":"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["For each Bedrock flow you want to expose, add a tool entry:","\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Set a descriptive ",(0,s.jsx)(n.code,{children:"tool_name"})," for the flow."]}),"\n",(0,s.jsxs)(n.li,{children:["Provide a clear ",(0,s.jsx)(n.code,{children:"tool_description"})," of what the flow does (optional)."]}),"\n",(0,s.jsxs)(n.li,{children:["Replace ",(0,s.jsx)(n.code,{children:"bedrock_flow_id"})," with your actual Bedrock flow ID."]}),"\n",(0,s.jsxs)(n.li,{children:["Replace ",(0,s.jsx)(n.code,{children:"bedrock_flow_alias_id"})," with your actual Bedrock flow alias ID."]}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Update Agent Card Skills"}),":"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Update the ",(0,s.jsx)(n.code,{children:"agent_card.description"})," to reflect the purpose of your Bedrock agent (This is what other agents see)."]}),"\n",(0,s.jsxs)(n.li,{children:["For each tool you add, create a corresponding skill entry in the ",(0,s.jsx)(n.code,{children:"agent_card.skills"})," section."]}),"\n",(0,s.jsxs)(n.li,{children:["Use the same ",(0,s.jsx)(n.code,{children:"id"})," as the ",(0,s.jsx)(n.code,{children:"tool_name"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["Provide a user-friendly ",(0,s.jsx)(n.code,{children:"name"})," and ",(0,s.jsx)(n.code,{children:"description"}),"."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Update Agent Instructions"}),":"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Modify the ",(0,s.jsx)(n.code,{children:"instruction"})," field to provide clear guidance on how the agent should respond to user queries."]}),"\n",(0,s.jsx)(n.li,{children:"This instruction is used by the Agent's LLM to understand its role and capabilities."}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"You must provide at least one Bedrock agent or flow tool. You can mix and match agents and flows in the same configuration."})}),"\n",(0,s.jsx)(n.h3,{id:"environment-variables",children:"Environment Variables"}),"\n",(0,s.jsx)(n.p,{children:"The Bedrock agent integration requires standard Solace connection variables and can use AWS environment variables for authentication."}),"\n",(0,s.jsx)(n.h4,{id:"required-solace-variables",children:"Required Solace Variables:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"SOLACE_BROKER_URL"}),": URL of your Solace broker"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"SOLACE_BROKER_USERNAME"}),": Username for Solace broker authentication"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"SOLACE_BROKER_PASSWORD"}),": Password for Solace broker authentication"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"SOLACE_BROKER_VPN"}),": Solace message VPN name"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"SOLACE_AGENT_MESH_NAMESPACE"}),": Namespace for your SAM project"]}),"\n"]}),"\n",(0,s.jsx)(n.h4,{id:"optional-aws-variables",children:"Optional AWS Variables:"}),"\n",(0,s.jsx)(n.p,{children:"If you prefer to use environment variables for AWS authentication instead of configuration in the YAML file:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"AWS_ACCESS_KEY_ID"}),": Your AWS access key"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"AWS_SECRET_ACCESS_KEY"}),": Your AWS secret key"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"AWS_SESSION_TOKEN"}),": If using temporary credentials"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"AWS_REGION"})," or ",(0,s.jsx)(n.strong,{children:"AWS_DEFAULT_REGION"}),": AWS region for Bedrock services"]}),"\n"]}),"\n",(0,s.jsxs)(n.admonition,{title:"AWS Credentials Precedence",type:"tip",children:[(0,s.jsx)(n.p,{children:"AWS credentials are loaded in this order:"}),(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsx)(n.li,{children:"Explicit credentials in the YAML configuration"}),"\n",(0,s.jsx)(n.li,{children:"Environment variables"}),"\n",(0,s.jsx)(n.li,{children:"AWS configuration files (~/.aws/credentials)"}),"\n",(0,s.jsx)(n.li,{children:"EC2/ECS instance profiles (if running on AWS)"}),"\n"]})]}),"\n",(0,s.jsx)(n.h2,{id:"running-and-testing-your-integration",children:"Running and Testing Your Integration"}),"\n",(0,s.jsx)(n.h3,{id:"starting-your-sam-project",children:"Starting Your SAM Project"}),"\n",(0,s.jsx)(n.p,{children:"After configuring your Bedrock agent integration, run your SAM project:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"sam run configs/agents/aws-agent.yaml\n"})}),"\n",(0,s.jsx)(n.p,{children:"This command starts the Bedrock agent with your specific configuration."}),"\n",(0,s.jsx)(n.h3,{id:"testing-the-integration",children:"Testing the Integration"}),"\n",(0,s.jsx)(n.p,{children:"You can test your Bedrock agent integration through any gateway in your SAM project:"}),"\n",(0,s.jsx)(n.h4,{id:"using-the-web-ui-gateway",children:"Using the Web UI Gateway"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["Ensure you have a Web UI gateway running (typically at ",(0,s.jsx)(n.a,{href:"http://localhost:8000",children:"http://localhost:8000"}),")"]}),"\n",(0,s.jsx)(n.li,{children:"Start a conversation with your agent"}),"\n",(0,s.jsx)(n.li,{children:"Ask a question that would trigger your Bedrock agent or flow"}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Example"}),": If you configured a Bedrock agent for text transformation:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:'Transform this text: "The quick brown fox jumps over the lazy dog. The lazy dog did not chase the fox. The fox was brown and quick, while the dog was lazy and slow. Despite their differences, they both enjoyed the sunny day in the meadow."\n'})}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Example"}),": If you configured a Bedrock flow for poem writing:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"Write a poem about a sunset over the ocean.\n"})}),"\n",(0,s.jsx)(n.h4,{id:"testing-with-file-uploads",children:"Testing with File Uploads"}),"\n",(0,s.jsxs)(n.p,{children:["If you have enabled file uploads for your Bedrock agent (",(0,s.jsx)(n.code,{children:"allow_files: true"}),"), you can test file processing:"]}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsx)(n.li,{children:"In the Web UI, use the file upload button to attach a supported file"}),"\n",(0,s.jsx)(n.li,{children:'Include a prompt that references the file, such as "Analyze this document" or "Summarize the content of this file"'}),"\n",(0,s.jsx)(n.li,{children:"The file is sent to the Bedrock agent along with your prompt"}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Example with file upload"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"Please analyze the attached document and provide key insights.\n"})}),"\n",(0,s.jsxs)(n.admonition,{title:"Supported File Types",type:"info",children:[(0,s.jsx)(n.p,{children:"Bedrock agents support these file types for uploads:"}),(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"PDF documents (.pdf)"}),"\n",(0,s.jsx)(n.li,{children:"Text files (.txt)"}),"\n",(0,s.jsx)(n.li,{children:"Word documents (.doc, .docx)"}),"\n",(0,s.jsx)(n.li,{children:"CSV files (.csv)"}),"\n",(0,s.jsx)(n.li,{children:"Excel spreadsheets (.xls, .xlsx)"}),"\n"]}),(0,s.jsx)(n.p,{children:"There's a limit of 5 files with a total size of 10MB per request."})]}),"\n",(0,s.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,s.jsx)(n.h3,{id:"common-issues-and-solutions",children:"Common Issues and Solutions"}),"\n",(0,s.jsx)(n.h4,{id:"authentication-errors",children:"Authentication Errors"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Issue"}),': "Unable to locate credentials" or "Access denied" errors\n',(0,s.jsx)(n.strong,{children:"Solution"}),":"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Verify your AWS credentials are correctly configured"}),"\n",(0,s.jsx)(n.li,{children:"Check that your IAM user/role has the necessary permissions"}),"\n",(0,s.jsxs)(n.li,{children:["Try using AWS CLI to test your credentials: ",(0,s.jsx)(n.code,{children:"aws bedrock list-foundation-models"})]}),"\n"]}),"\n",(0,s.jsx)(n.h4,{id:"configuration-errors",children:"Configuration Errors"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Issue"}),': "Invalid agent ID" or "Invalid flow ID" errors\n',(0,s.jsx)(n.strong,{children:"Solution"}),":"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Double-check your Bedrock agent and flow IDs in the configuration"}),"\n",(0,s.jsx)(n.li,{children:"Ensure you've created aliases for your agents and flows"}),"\n",(0,s.jsx)(n.li,{children:"Verify the region in your configuration matches where your Bedrock resources are located"}),"\n"]}),"\n",(0,s.jsx)(n.h4,{id:"connection-issues",children:"Connection Issues"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Issue"}),": SAM can't connect to Bedrock services\n",(0,s.jsx)(n.strong,{children:"Solution"}),":"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Check your network connectivity"}),"\n",(0,s.jsx)(n.li,{children:"Verify that Bedrock services are available in your configured region"}),"\n",(0,s.jsx)(n.li,{children:"Check for any VPC or firewall restrictions"}),"\n"]}),"\n",(0,s.jsx)(n.h4,{id:"file-upload-issues",children:"File Upload Issues"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Issue"}),": Files aren't being processed by the Bedrock agent\n",(0,s.jsx)(n.strong,{children:"Solution"}),":"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Verify ",(0,s.jsx)(n.code,{children:"allow_files"})," is set to ",(0,s.jsx)(n.code,{children:"true"})," in your configuration"]}),"\n",(0,s.jsx)(n.li,{children:"Check that your file type is supported"}),"\n",(0,s.jsx)(n.li,{children:"Ensure the file size is under the 10MB limit"}),"\n",(0,s.jsx)(n.li,{children:"Check the model context length"}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,n,o)=>{o.d(n,{R:()=>r,x:()=>l});var i=o(6540);const s={},t=i.createContext(s);function r(e){const n=i.useContext(t);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[8357],{3960:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>a,toc:()=>l});const a=JSON.parse('{"id":"documentation/tutorials/custom-agent","title":"Build Your Own Agent","description":"This tutorial shows you how to build a sophisticated weather agent using the Solace Agent Mesh framework. Learn how to integrate with external APIs, manage resources properly, and create production-ready agents.","source":"@site/docs/documentation/tutorials/custom-agent.md","sourceDirName":"documentation/tutorials","slug":"/documentation/tutorials/custom-agent","permalink":"/solace-agent-mesh/docs/documentation/tutorials/custom-agent","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/tutorials/custom-agent.md","tags":[],"version":"current","sidebarPosition":5,"frontMatter":{"title":"Build Your Own Agent","sidebar_position":5},"sidebar":"docSidebar","previous":{"title":"Debugging","permalink":"/solace-agent-mesh/docs/documentation/deployment/debugging"},"next":{"title":"MCP Integration","permalink":"/solace-agent-mesh/docs/documentation/tutorials/mcp-integration"}}');var r=t(4848),o=t(8453);const i={title:"Build Your Own Agent",sidebar_position:5},s="Build Your Own Agent",c={},l=[{value:"Overview",id:"overview",level:2},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Planning the Weather Agent",id:"planning-the-weather-agent",level:2},{value:"Step 1: Project Structure",id:"step-1-project-structure",level:2},{value:"Step 2: Weather Service Implementation",id:"step-2-weather-service-implementation",level:2},{value:"Step 3: Weather Tools Implementation",id:"step-3-weather-tools-implementation",level:2},{value:"Step 4: Lifecycle Functions",id:"step-4-lifecycle-functions",level:2},{value:"Step 5: Agent Configuration",id:"step-5-agent-configuration",level:2},{value:"Step 6: Environment Setup",id:"step-6-environment-setup",level:2},{value:"Step 7: Running the Agent",id:"step-7-running-the-agent",level:2},{value:"Step 8: Testing the Weather Agent",id:"step-8-testing-the-weather-agent",level:2},{value:"Key Features Demonstrated",id:"key-features-demonstrated",level:2},{value:"1. External API Integration",id:"1-external-api-integration",level:3},{value:"2. Resource Management",id:"2-resource-management",level:3},{value:"3. Configuration Management",id:"3-configuration-management",level:3},{value:"4. Error Handling",id:"4-error-handling",level:3},{value:"5. Artifact Management",id:"5-artifact-management",level:3}];function d(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components},{Details:t}=n;return t||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"build-your-own-agent",children:"Build Your Own Agent"})}),"\n",(0,r.jsx)(n.p,{children:"This tutorial shows you how to build a sophisticated weather agent using the Solace Agent Mesh framework. Learn how to integrate with external APIs, manage resources properly, and create production-ready agents."}),"\n",(0,r.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,r.jsx)(n.p,{children:"Our weather agent will demonstrate:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"External API integration (OpenWeatherMap)"}),"\n",(0,r.jsx)(n.li,{children:"Professional service layer architecture"}),"\n",(0,r.jsx)(n.li,{children:"Multiple sophisticated tools"}),"\n",(0,r.jsx)(n.li,{children:"Proper lifecycle management"}),"\n",(0,r.jsx)(n.li,{children:"Error handling and validation"}),"\n",(0,r.jsx)(n.li,{children:"Artifact creation and management"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsx)(n.p,{children:"Before starting this tutorial, make sure you have:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Read the ",(0,r.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/user-guide/create-agents",children:"Create Agent"})," tutorial"]}),"\n",(0,r.jsxs)(n.li,{children:["An OpenWeatherMap API key (free at ",(0,r.jsx)(n.a,{href:"https://openweathermap.org/api",children:"openweathermap.org"}),")"]}),"\n",(0,r.jsx)(n.li,{children:"Basic understanding of Python async/await"}),"\n",(0,r.jsx)(n.li,{children:"Familiarity with HTTP APIs"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"planning-the-weather-agent",children:"Planning the Weather Agent"}),"\n",(0,r.jsx)(n.p,{children:"Our weather agent will have the following capabilities:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Get Current Weather"}),": Fetch current weather conditions for a specified location"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Get Weather Forecast"}),": Retrieve a multi-day weather forecast"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Save Weather Reports"}),": Store weather data as artifacts"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"The agent will demonstrate:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"External API integration"}),"\n",(0,r.jsx)(n.li,{children:"Error handling and validation"}),"\n",(0,r.jsx)(n.li,{children:"Configuration management"}),"\n",(0,r.jsx)(n.li,{children:"Artifact creation"}),"\n",(0,r.jsx)(n.li,{children:"Resource lifecycle management"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"step-1-project-structure",children:"Step 1: Project Structure"}),"\n",(0,r.jsx)(n.p,{children:"Run the following command to create a new custom agent:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"sam add agent --gui\n"})}),"\n",(0,r.jsxs)(n.admonition,{type:"tip",children:[(0,r.jsxs)(n.p,{children:["You can create an agent either by using the ",(0,r.jsx)(n.code,{children:"sam add agent"})," command or by creating a new plugin of type agent, ",(0,r.jsx)(n.code,{children:"sam plugin create my-hello-agent --type agent"}),"."]}),(0,r.jsxs)(n.p,{children:["For information and recommendations about these options, see ",(0,r.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/concepts/plugins#agent-or-plugin-which-to-use",children:(0,r.jsx)(n.code,{children:"Agent or Plugin: Which To use?"})}),"."]}),(0,r.jsxs)(n.p,{children:["For an example of plugin agents, see the ",(0,r.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/user-guide/create-agents#step-1-initialize-your-agent",children:"Create Agents"})," guide."]})]}),"\n",(0,r.jsx)(n.p,{children:'Follow the steps on the GUI to create a new agent named "Weather Agent". We can update the tools/skills section directly in the configuration file later.'}),"\n",(0,r.jsxs)(n.admonition,{title:"Important Notice",type:"warning",children:[(0,r.jsx)(n.p,{children:"This tutorial is intentionally comprehensive to demonstrate the full flexibility and advanced features available in Solace Agent Mesh agents. For most straightforward use cases, you only need a simple Python function and a corresponding reference in your YAML configuration file."}),(0,r.jsxs)(t,{children:[(0,r.jsx)("summary",{children:"Simple Weather Agent Example"}),(0,r.jsxs)(n.p,{children:["After going through the add agent wizard from ",(0,r.jsx)(n.code,{children:"sam add agent --gui"}),", create the following file under ",(0,r.jsx)(n.code,{children:"src/weather_agent/tools.py"})," directory:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-py",children:'# src/weather_agent/tools.py\nimport httpx\nfrom typing import Any, Dict, Optional\nfrom google.adk.tools import ToolContext\nfrom solace_ai_connector.common.log import log\n\n\nasync def get_current_weather(\n location: str,\n units: str = "metric",\n tool_context: Optional[ToolContext] = None,\n tool_config: Optional[Dict[str, Any]] = None\n) -> Dict[str, Any]:\n """\n Get current weather conditions for a specified location.\n \n Args:\n location: City name, state, and country (for example, "New York, NY, US")\n units: Temperature units - "metric" (Celsius), "imperial" (Fahrenheit), or "kelvin"\n """\n log.info("[GetCurrentWeather] Getting current weather for: %s", location)\n base_url = "https://api.openweathermap.org/data/2.5"\n api_key = tool_config.get("api_key") if tool_config else None\n\n url = f"{base_url}/weather"\n params = {\n "q": location,\n "appid": api_key,\n "units": units\n }\n\n try:\n # Fetch weather data\n async with httpx.AsyncClient() as client:\n response = await client.get(url, params=params)\n response.raise_for_status()\n weather_data = response.json()\n \n result = {\n "status": "success",\n "location": location,\n "units": units,\n "data": weather_data\n }\n return result\n \n except Exception as e:\n log.error(f"[GetCurrentWeather] Error getting weather: {e}")\n return {\n "status": "error",\n "message": f"Weather service error: {str(e)}"\n }\n\n\nasync def get_weather_forecast(\n location: str,\n days: int = 5,\n units: str = "metric",\n tool_context: Optional[ToolContext] = None,\n tool_config: Optional[Dict[str, Any]] = None\n) -> Dict[str, Any]:\n """\n Get weather forecast for a specified location.\n \n Args:\n location: City name, state, and country\n days: Number of days for forecast (1-5)\n units: Temperature units\n """\n log.info("[GetWeatherForecast] Getting %d-day forecast for: %s", days, location)\n base_url = "https://api.openweathermap.org/data/2.5"\n api_key = tool_config.get("api_key") if tool_config else None\n\n url = f"{base_url}/forecast"\n params = {\n "q": location,\n "appid": api_key,\n "units": units,\n "cnt": min(days * 8, 40) \n }\n\n try:\n # Fetch forecast data\n async with httpx.AsyncClient() as client:\n response = await client.get(url, params=params)\n response.raise_for_status()\n forecast_data = response.json()\n\n result = {\n "status": "success",\n "location": forecast_data["location"],\n "days": days,\n "units": units,\n "data": forecast_data\n }\n return result\n except Exception as e:\n log.error(f"[GetWeatherForecast] Error getting forecast: {e}")\n return {\n "status": "error",\n "message": f"Weather service error: {str(e)}"\n }\n\n'})}),(0,r.jsxs)(n.p,{children:["And update the weather agent config file's tool section under ",(0,r.jsx)(n.code,{children:"configs/agent/weather-agent.yaml"})," as follows:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:' # Tools configuration\n tools:\n # Current weather tool\n - tool_type: python\n component_module: "src.weather_agent.tools"\n component_base_path: .\n function_name: "get_current_weather"\n tool_description: "Get current weather conditions for a specified location"\n tool_config:\n api_key: ${OPENWEATHER_API_KEY}\n\n # Weather forecast tool\n - tool_type: python\n component_module: "src.weather_agent.tools"\n function_name: "get_weather_forecast"\n component_base_path: .\n tool_description: "Get weather forecast for up to 5 days for a specified location"\n tool_config:\n api_key: ${OPENWEATHER_API_KEY}\n\n'})}),(0,r.jsxs)(n.p,{children:["For better discoverability, update the ",(0,r.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/concepts/agents#agent-card",children:"agent card"})," section in the same YAML file as follows:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:' # Agent card\n agent_card:\n description: "Professional weather agent providing current conditions, forecasts, and weather comparisons"\n defaultInputModes: ["text"]\n defaultOutputModes: ["text"]\n skills:\n - id: "get_current_weather"\n name: "Get Current Weather"\n description: "Retrieve current weather conditions for any location worldwide"\n - id: "get_weather_forecast"\n name: "Get Weather Forecast"\n description: "Provide detailed weather forecasts up to 5 days ahead"\n'})}),(0,r.jsxs)(n.p,{children:["To run the agent, you can continue following documentation from ",(0,r.jsx)(n.a,{href:"#step-6-environment-setup",children:"Step 6"})," of this tutorial."]})]}),(0,r.jsx)(n.p,{children:"Other concepts mentioned in this page such as lifecycle, services, artifacts are just to showcase more advanced patterns."})]}),"\n",(0,r.jsx)(n.p,{children:"Create the directory structure for the weather agent:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"sam-project/\n\u251c\u2500\u2500 src/\n\u2502 \u2514\u2500\u2500 weather_agent/\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 tools.py\n\u2502 \u251c\u2500\u2500 lifecycle.py\n\u2502 \u2514\u2500\u2500 services/\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u2514\u2500\u2500 weather_service.py\n\u251c\u2500\u2500 configs\n\u2502 \u2514\u2500\u2500 shared_config.yaml\n\u2502 \u2514\u2500\u2500 agents/\n\u2502 \u2514\u2500\u2500 weather_agent.yaml\n...\n"})}),"\n",(0,r.jsxs)(n.admonition,{type:"tip",children:[(0,r.jsxs)(n.p,{children:["IN SAM, you can create an agent either by using the ",(0,r.jsx)(n.code,{children:"sam add agent"})," command or by creating a new plugin of type agent, ",(0,r.jsx)(n.code,{children:"sam plugin create your-agent --type agent"}),"."]}),(0,r.jsxs)(n.p,{children:["This tutorial uses the ",(0,r.jsx)(n.code,{children:"sam add agent"}),' command to create a new agent named "Weather Agent", for an example of creating a custom agent plugin, see the ',(0,r.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/user-guide/create-agents",children:"Create Agents"})," tutorial."]})]}),"\n",(0,r.jsx)(n.h2,{id:"step-2-weather-service-implementation",children:"Step 2: Weather Service Implementation"}),"\n",(0,r.jsx)(n.p,{children:"First, create a service class to handle weather API interactions:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:[(0,r.jsx)(n.code,{children:"src/weather_agent/services/weather_service.py"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'"""\nWeather service for interacting with external weather APIs.\n"""\n\nimport aiohttp\nfrom typing import Dict, Any, Optional, List\nfrom datetime import datetime, timezone\nfrom solace_ai_connector.common.log import log\n\n\nclass WeatherService:\n """Service for fetching weather data from external APIs."""\n \n def __init__(self, api_key: str, base_url: str = "https://api.openweathermap.org/data/2.5"):\n self.api_key = api_key\n self.base_url = base_url\n self.session: Optional[aiohttp.ClientSession] = None\n self.log_identifier = "[WeatherService]"\n \n async def _get_session(self) -> aiohttp.ClientSession:\n """Get or create an HTTP session."""\n if self.session is None or self.session.closed:\n self.session = aiohttp.ClientSession()\n return self.session\n \n async def close(self):\n """Close the HTTP session."""\n if self.session and not self.session.closed:\n await self.session.close()\n log.info(f"{self.log_identifier} HTTP session closed")\n \n async def get_current_weather(self, location: str, units: str = "metric") -> Dict[str, Any]:\n """\n Get current weather for a location.\n \n Args:\n location: City name, state code, and country code (for example, "London,UK")\n units: Temperature units (metric, imperial, kelvin)\n \n Returns:\n Dictionary containing current weather data\n """\n log.info(f"{self.log_identifier} Fetching current weather for: {location}")\n \n session = await self._get_session()\n url = f"{self.base_url}/weather"\n params = {\n "q": location,\n "appid": self.api_key,\n "units": units\n }\n \n try:\n async with session.get(url, params=params) as response:\n if response.status == 200:\n data = await response.json()\n log.info(f"{self.log_identifier} Successfully fetched weather for {location}")\n return self._format_current_weather(data)\n elif response.status == 404:\n raise ValueError(f"Location \'{location}\' not found")\n else:\n error_data = await response.json()\n raise Exception(f"Weather API error: {error_data.get(\'message\', \'Unknown error\')}")\n \n except aiohttp.ClientError as e:\n log.error(f"{self.log_identifier} Network error fetching weather: {e}")\n raise Exception(f"Network error: {str(e)}")\n \n async def get_weather_forecast(self, location: str, days: int = 5, units: str = "metric") -> Dict[str, Any]:\n """\n Get weather forecast for a location.\n \n Args:\n location: City name, state code, and country code\n days: Number of days for forecast (1-5)\n units: Temperature units\n \n Returns:\n Dictionary containing forecast data\n """\n log.info(f"{self.log_identifier} Fetching {days}-day forecast for: {location}")\n \n session = await self._get_session()\n url = f"{self.base_url}/forecast"\n params = {\n "q": location,\n "appid": self.api_key,\n "units": units,\n "cnt": min(days * 8, 40) # API returns 3-hour intervals, max 40 entries\n }\n \n try:\n async with session.get(url, params=params) as response:\n if response.status == 200:\n data = await response.json()\n log.info(f"{self.log_identifier} Successfully fetched forecast for {location}")\n return self._format_forecast_data(data, days)\n elif response.status == 404:\n raise ValueError(f"Location \'{location}\' not found")\n else:\n error_data = await response.json()\n raise Exception(f"Weather API error: {error_data.get(\'message\', \'Unknown error\')}")\n \n except aiohttp.ClientError as e:\n log.error(f"{self.log_identifier} Network error fetching forecast: {e}")\n raise Exception(f"Network error: {str(e)}")\n \n def _format_current_weather(self, data: Dict) -> Dict[str, Any]:\n """Format current weather data for consistent output."""\n return {\n "location": f"{data[\'name\']}, {data[\'sys\'][\'country\']}",\n "temperature": data[\'main\'][\'temp\'],\n "feels_like": data[\'main\'][\'feels_like\'],\n "humidity": data[\'main\'][\'humidity\'],\n "pressure": data[\'main\'][\'pressure\'],\n "description": data[\'weather\'][0][\'description\'].title(),\n "wind_speed": data.get(\'wind\', {}).get(\'speed\', 0),\n "wind_direction": data.get(\'wind\', {}).get(\'deg\', 0),\n "visibility": data.get(\'visibility\', 0) / 1000, # Convert to km\n "timestamp": datetime.fromtimestamp(data[\'dt\']).isoformat(),\n "sunrise": datetime.fromtimestamp(data[\'sys\'][\'sunrise\']).isoformat(),\n "sunset": datetime.fromtimestamp(data[\'sys\'][\'sunset\']).isoformat()\n }\n \n def _format_forecast_data(self, data: Dict, days: int) -> Dict[str, Any]:\n """Format forecast data for consistent output."""\n forecasts = []\n current_date = None\n daily_data = []\n \n for item in data[\'list\'][:days * 8]:\n forecast_date = datetime.fromtimestamp(item[\'dt\']).date()\n \n if current_date != forecast_date:\n if daily_data:\n forecasts.append(self._aggregate_daily_forecast(daily_data))\n current_date = forecast_date\n daily_data = []\n \n daily_data.append(item)\n \n # Add the last day\'s data\n if daily_data:\n forecasts.append(self._aggregate_daily_forecast(daily_data))\n \n return {\n "location": f"{data[\'city\'][\'name\']}, {data[\'city\'][\'country\']}",\n "forecasts": forecasts[:days]\n }\n \n def _aggregate_daily_forecast(self, daily_data: List[Dict]) -> Dict[str, Any]:\n """Aggregate 3-hour forecasts into daily summary."""\n if not daily_data:\n return {}\n \n # Get temperatures for min/max calculation\n temps = [item[\'main\'][\'temp\'] for item in daily_data]\n \n # Use the forecast closest to noon for general conditions\n noon_forecast = min(daily_data, key=lambda x: abs(\n datetime.fromtimestamp(x[\'dt\']).hour - 12\n ))\n \n return {\n "date": datetime.fromtimestamp(daily_data[0][\'dt\']).date().isoformat(),\n "temperature_min": min(temps),\n "temperature_max": max(temps),\n "description": noon_forecast[\'weather\'][0][\'description\'].title(),\n "humidity": noon_forecast[\'main\'][\'humidity\'],\n "wind_speed": noon_forecast.get(\'wind\', {}).get(\'speed\', 0),\n "precipitation_probability": noon_forecast.get(\'pop\', 0) * 100\n }\n'})}),"\n",(0,r.jsx)(n.h2,{id:"step-3-weather-tools-implementation",children:"Step 3: Weather Tools Implementation"}),"\n",(0,r.jsx)(n.p,{children:"Now create the tool functions:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:[(0,r.jsx)(n.code,{children:"src/weather_agent/tools.py"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'"""\nWeather agent tools for fetching and processing weather data.\n"""\n\nimport json\nfrom typing import Any, Dict, Optional\nfrom datetime import datetime, timezone\nfrom google.adk.tools import ToolContext\nfrom solace_ai_connector.common.log import log\nfrom solace_agent_mesh.agent.utils.artifact_helpers import save_artifact_with_metadata\n\nasync def get_current_weather(\n location: str,\n units: str = "metric",\n save_to_file: bool = False,\n tool_context: Optional[ToolContext] = None,\n tool_config: Optional[Dict[str, Any]] = None\n) -> Dict[str, Any]:\n """\n Get current weather conditions for a specified location.\n \n Args:\n location: City name, state, and country (for example, "New York, NY, US")\n units: Temperature units - "metric" (Celsius), "imperial" (Fahrenheit), or "kelvin"\n save_to_file: Whether to save the weather report as an artifact\n \n Returns:\n Dictionary containing current weather information\n """\n log_identifier = "[GetCurrentWeather]"\n log.info(f"{log_identifier} Getting current weather for: {location}")\n \n if not tool_context:\n return {\n "status": "error",\n "message": "Tool context is required for weather operations"\n }\n \n try:\n # Get weather service from agent state\n host_component = getattr(tool_context._invocation_context, "agent", None)\n if host_component:\n host_component = getattr(host_component, "host_component", None)\n \n if not host_component:\n return {\n "status": "error",\n "message": "Could not access agent host component"\n }\n \n weather_service = host_component.get_agent_specific_state("weather_service")\n if not weather_service:\n return {\n "status": "error",\n "message": "Weather service not initialized"\n }\n \n # Fetch weather data\n weather_data = await weather_service.get_current_weather(location, units)\n \n # Create human-readable summary\n summary = _create_weather_summary(weather_data)\n \n result = {\n "status": "success",\n "location": weather_data["location"],\n "summary": summary,\n "data": weather_data\n }\n \n # Save to artifact if requested\n if save_to_file:\n artifact_result = await _save_weather_artifact(\n weather_data, f"current_weather_{location}", tool_context\n )\n result["artifact"] = artifact_result\n \n log.info(f"{log_identifier} Successfully retrieved weather for {location}")\n return result\n \n except ValueError as e:\n log.warning(f"{log_identifier} Invalid location: {e}")\n return {\n "status": "error",\n "message": f"Location error: {str(e)}"\n }\n except Exception as e:\n log.error(f"{log_identifier} Error getting weather: {e}")\n return {\n "status": "error",\n "message": f"Weather service error: {str(e)}"\n }\n\n\nasync def get_weather_forecast(\n location: str,\n days: int = 5,\n units: str = "metric",\n save_to_file: bool = False,\n tool_context: Optional[ToolContext] = None,\n tool_config: Optional[Dict[str, Any]] = None\n) -> Dict[str, Any]:\n """\n Get weather forecast for a specified location.\n \n Args:\n location: City name, state, and country\n days: Number of days for forecast (1-5)\n units: Temperature units\n save_to_file: Whether to save the forecast as an artifact\n \n Returns:\n Dictionary containing weather forecast information\n """\n log_identifier = "[GetWeatherForecast]"\n log.info(f"{log_identifier} Getting {days}-day forecast for: {location}")\n \n if not tool_context:\n return {\n "status": "error",\n "message": "Tool context is required for weather operations"\n }\n \n # Validate days parameter\n if not 1 <= days <= 5:\n return {\n "status": "error",\n "message": "Days must be between 1 and 5"\n }\n \n try:\n # Get weather service from agent state\n host_component = getattr(tool_context._invocation_context, "agent", None)\n if host_component:\n host_component = getattr(host_component, "host_component", None)\n \n if not host_component:\n return {\n "status": "error",\n "message": "Could not access agent host component"\n }\n \n weather_service = host_component.get_agent_specific_state("weather_service")\n if not weather_service:\n return {\n "status": "error",\n "message": "Weather service not initialized"\n }\n \n # Fetch forecast data\n forecast_data = await weather_service.get_weather_forecast(location, days, units)\n \n # Create human-readable summary\n summary = _create_forecast_summary(forecast_data)\n \n result = {\n "status": "success",\n "location": forecast_data["location"],\n "summary": summary,\n "data": forecast_data\n }\n \n # Save to artifact if requested\n if save_to_file:\n artifact_result = await _save_weather_artifact(\n forecast_data, f"forecast_{location}_{days}day", tool_context\n )\n result["artifact"] = artifact_result\n \n log.info(f"{log_identifier} Successfully retrieved forecast for {location}")\n return result\n \n except ValueError as e:\n log.warning(f"{log_identifier} Invalid location: {e}")\n return {\n "status": "error",\n "message": f"Location error: {str(e)}"\n }\n except Exception as e:\n log.error(f"{log_identifier} Error getting forecast: {e}")\n return {\n "status": "error",\n "message": f"Weather service error: {str(e)}"\n }\n\n\ndef _create_weather_summary(weather_data: Dict[str, Any]) -> str:\n """Create a human-readable weather summary."""\n temp_unit = "\xb0C" # Assuming metric units for summary\n \n summary = f"Current weather in {weather_data[\'location\']}:\\n"\n summary += f"\u2022 Temperature: {weather_data[\'temperature\']}{temp_unit} (feels like {weather_data[\'feels_like\']}{temp_unit})\\n"\n summary += f"\u2022 Conditions: {weather_data[\'description\']}\\n"\n summary += f"\u2022 Humidity: {weather_data[\'humidity\']}%\\n"\n summary += f"\u2022 Wind: {weather_data[\'wind_speed\']} m/s\\n"\n summary += f"\u2022 Visibility: {weather_data[\'visibility\']} km"\n \n return summary\n\n\ndef _create_forecast_summary(forecast_data: Dict[str, Any]) -> str:\n """Create a human-readable forecast summary."""\n summary = f"Weather forecast for {forecast_data[\'location\']}:\\n\\n"\n \n for forecast in forecast_data[\'forecasts\']:\n date = datetime.fromisoformat(forecast[\'date\']).strftime(\'%A, %B %d\')\n summary += f"\u2022 {date}: {forecast[\'description\']}\\n"\n summary += f" High: {forecast[\'temperature_max\']:.1f}\xb0C, Low: {forecast[\'temperature_min\']:.1f}\xb0C\\n"\n if forecast[\'precipitation_probability\'] > 0:\n summary += f" Precipitation: {forecast[\'precipitation_probability\']:.0f}% chance\\n"\n summary += "\\n"\n \n return summary.strip()\n\n\nasync def _save_weather_artifact(\n weather_data: Dict[str, Any],\n filename_base: str,\n tool_context: ToolContext\n) -> Dict[str, Any]:\n """Save weather data as an artifact."""\n try:\n # Prepare content\n content = json.dumps(weather_data, indent=2, default=str)\n timestamp = datetime.now(timezone.utc)\n filename = f"{filename_base}_{timestamp.strftime(\'%Y%m%d_%H%M%S\')}.json"\n \n # Save artifact\n artifact_service = tool_context._invocation_context.artifact_service\n result = await save_artifact_with_metadata(\n artifact_service=artifact_service,\n app_name=tool_context._invocation_context.app_name,\n user_id=tool_context._invocation_context.user_id,\n session_id=tool_context._invocation_context.session.id,\n filename=filename,\n content_bytes=content.encode(\'utf-8\'),\n mime_type="application/json",\n metadata_dict={\n "description": "Weather data report",\n "source": "Weather Agent"\n },\n timestamp=timestamp\n )\n \n return {\n "filename": filename,\n "status": result.get("status", "success")\n }\n \n except Exception as e:\n log.error(f"[WeatherArtifact] Error saving artifact: {e}")\n return {\n "status": "error",\n "message": f"Failed to save artifact: {str(e)}"\n }\n'})}),"\n",(0,r.jsx)(n.h2,{id:"step-4-lifecycle-functions",children:"Step 4: Lifecycle Functions"}),"\n",(0,r.jsx)(n.p,{children:"Create the lifecycle management:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:[(0,r.jsx)(n.code,{children:"src/weather_agent/lifecycle.py"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'"""\nLifecycle functions for the Weather Agent.\n"""\n\nfrom typing import Any\nimport asyncio\nfrom pydantic import BaseModel, Field, SecretStr\nfrom solace_ai_connector.common.log import log\nfrom .services.weather_service import WeatherService\n\n\nclass WeatherAgentInitConfig(BaseModel):\n """\n Configuration model for Weather Agent initialization.\n """\n api_key: SecretStr = Field(description="OpenWeatherMap API key")\n base_url: str = Field(\n default="https://api.openweathermap.org/data/2.5",\n description="Weather API base URL"\n )\n startup_message: str = Field(\n default="Weather Agent is ready to provide weather information!",\n description="Message to log on startup"\n )\n\n\ndef initialize_weather_agent(host_component: Any, init_config: WeatherAgentInitConfig):\n """\n Initialize the Weather Agent with weather service.\n \n Args:\n host_component: The agent host component\n init_config: Validated initialization configuration\n """\n log_identifier = f"[{host_component.agent_name}:init]"\n log.info(f"{log_identifier} Starting Weather Agent initialization...")\n \n try:\n # Initialize weather service\n weather_service = WeatherService(\n api_key=init_config.api_key.get_secret_value(),\n base_url=init_config.base_url\n )\n \n # Store service in agent state\n host_component.set_agent_specific_state("weather_service", weather_service)\n \n # Log startup message\n log.info(f"{log_identifier} {init_config.startup_message}")\n \n # Store initialization metadata\n host_component.set_agent_specific_state("initialized_at", "2024-01-01T00:00:00Z")\n host_component.set_agent_specific_state("weather_requests_count", 0)\n \n log.info(f"{log_identifier} Weather Agent initialization completed successfully")\n \n except Exception as e:\n log.error(f"{log_identifier} Failed to initialize Weather Agent: {e}")\n raise\n\n\ndef cleanup_weather_agent(host_component: Any):\n """\n Clean up Weather Agent resources.\n \n Args:\n host_component: The agent host component\n """\n log_identifier = f"[{host_component.agent_name}:cleanup]"\n log.info(f"{log_identifier} Starting Weather Agent cleanup...")\n\n async def cleanup_async(host_component: Any):\n try:\n # Get and close weather service\n weather_service = host_component.get_agent_specific_state("weather_service")\n if weather_service:\n await weather_service.close()\n log.info(f"{log_identifier} Weather service closed successfully")\n \n # Log final statistics\n request_count = host_component.get_agent_specific_state("weather_requests_count", 0)\n log.info(f"{log_identifier} Agent processed {request_count} weather requests during its lifetime")\n \n log.info(f"{log_identifier} Weather Agent cleanup completed")\n \n except Exception as e:\n log.error(f"{log_identifier} Error during cleanup: {e}")\n \n # run cleanup in the event loop\n loop = asyncio.get_event_loop()\n loop.run_until_complete(cleanup_async(host_component))\n log.info(f"{log_identifier} Weather Agent cleanup completed successfully")\n'})}),"\n",(0,r.jsx)(n.h2,{id:"step-5-agent-configuration",children:"Step 5: Agent Configuration"}),"\n",(0,r.jsx)(n.p,{children:"Create the comprehensive YAML configuration:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'# Weather Agent Configuration\nlog:\n stdout_log_level: INFO\n log_file_level: DEBUG\n log_file: weather-agent.log\n\n!include ../shared_config.yaml\n\napps:\n - name: weather-agent\n # Broker configuration\n app_module: solace_agent_mesh.agent.sac.app\n broker:\n <<: *broker_connection\n\n app_config:\n namespace: "${NAMESPACE}"\n agent_name: "WeatherAgent"\n display_name: "Weather Information Agent"\n supports_streaming: true\n \n # LLM model configuration\n model: *general_model\n \n # Agent instructions\n instruction: |\n You are a professional weather agent that provides accurate, up-to-date weather information.\n \n Your capabilities include:\n 1. Getting current weather conditions for any location worldwide\n 2. Providing detailed weather forecasts up to 5 days\n 3. Saving weather reports as files for future reference\n \n Guidelines:\n - Always specify the location clearly when providing weather information\n - Include relevant details like temperature, conditions, humidity, and wind\n - Offer to save weather reports when providing detailed information\n - Be helpful in suggesting appropriate clothing or activities based on weather\n - If a location is ambiguous, ask for clarification (city, state/province, country)\n \n When users ask about weather, use the appropriate tools to fetch real-time data.\n Present information in a clear, organized manner that\'s easy to understand.\n \n # Lifecycle functions\n agent_init_function:\n module: "src.weather_agent.lifecycle"\n name: "initialize_weather_agent"\n base_path: .\n config:\n api_key: ${OPENWEATHER_API_KEY}\n base_url: "https://api.openweathermap.org/data/2.5"\n startup_message: "Weather Agent is ready to provide weather information!"\n \n agent_cleanup_function:\n module: "src.weather_agent.lifecycle"\n base_path: .\n name: "cleanup_weather_agent"\n \n # Tools configuration\n tools:\n # Current weather tool\n - tool_type: python\n component_module: "src.weather_agent.tools"\n component_base_path: .\n function_name: "get_current_weather"\n tool_description: "Get current weather conditions for a specified location"\n \n # Weather forecast tool\n - tool_type: python\n component_module: "src.weather_agent.tools"\n component_base_path: .\n function_name: "get_weather_forecast"\n tool_description: "Get weather forecast for up to 5 days for a specified location"\n \n # Built-in artifact tools for file operations\n - tool_type: builtin-group\n group_name: "artifact_management"\n \n session_service: *default_session_service\n artifact_service: *default_artifact_service\n\n artifact_handling_mode: "reference"\n enable_embed_resolution: true\n enable_artifact_content_instruction: true\n # Agent card\n agent_card:\n description: "Professional weather agent providing current conditions, forecasts, and weather comparisons"\n defaultInputModes: ["text"]\n defaultOutputModes: ["text", "file"]\n skills:\n - id: "get_current_weather"\n name: "Get Current Weather"\n description: "Retrieve current weather conditions for any location worldwide"\n - id: "get_weather_forecast"\n name: "Get Weather Forecast"\n description: "Provide detailed weather forecasts up to 5 days ahead"\n \n agent_card_publishing:\n interval_seconds: 30\n\n agent_discovery:\n enabled: false\n\n inter_agent_communication:\n allow_list: []\n request_timeout_seconds: 30\n'})}),"\n",(0,r.jsxs)(n.p,{children:["For more details on agent cards, see the ",(0,r.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/concepts/agents#agent-card",children:"Agent Card Concepts"})," documentation."]}),"\n",(0,r.jsx)(n.h2,{id:"step-6-environment-setup",children:"Step 6: Environment Setup"}),"\n",(0,r.jsx)(n.p,{children:"Before running your weather agent, you'll need to:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Get an OpenWeatherMap API key"}),":"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Sign up at ",(0,r.jsx)(n.a,{href:"https://openweathermap.org/api",children:"OpenWeatherMap"})]}),"\n",(0,r.jsx)(n.li,{children:"Get your free API key"}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Set environment variables"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'export OPENWEATHER_API_KEY="your_api_key_here"\n# Other environment variables as needed\n'})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"step-7-running-the-agent",children:"Step 7: Running the Agent"}),"\n",(0,r.jsxs)(n.p,{children:["To start the agent, it is preferred to build the plugin and then install it with your agent name. But for debugging or isolated development testing, you can run your agent from the ",(0,r.jsx)(n.code,{children:"src"})," directory directly using the SAM CLI."]}),"\n",(0,r.jsx)(n.p,{children:"Start your weather agent for development purposes run:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"sam run\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["To solely run the agent, use ",(0,r.jsx)(n.code,{children:"sam run configs/agents/weather_agent.yaml"})]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"step-8-testing-the-weather-agent",children:"Step 8: Testing the Weather Agent"}),"\n",(0,r.jsx)(n.p,{children:"You can test your weather agent with these example requests:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Current Weather:"})}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsx)(n.p,{children:'"What\'s the current weather in New York City?"'}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Weather Forecast:"})}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsx)(n.p,{children:'"Can you give me a 5-day forecast for London, UK and save it to a file?"'}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Weather with File Save:"})}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsx)(n.p,{children:'"Get the current weather for Tokyo, Japan and save the report"'}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"key-features-demonstrated",children:"Key Features Demonstrated"}),"\n",(0,r.jsx)(n.h3,{id:"1-external-api-integration",children:"1. External API Integration"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Proper HTTP session management"}),"\n",(0,r.jsx)(n.li,{children:"Error handling for network issues"}),"\n",(0,r.jsx)(n.li,{children:"API response transformation"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"2-resource-management",children:"2. Resource Management"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Lifecycle functions for initialization and cleanup"}),"\n",(0,r.jsx)(n.li,{children:"Shared service instances across tool calls"}),"\n",(0,r.jsx)(n.li,{children:"Proper resource disposal"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"3-configuration-management",children:"3. Configuration Management"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Pydantic models for type-safe configuration"}),"\n",(0,r.jsx)(n.li,{children:"Environment variable integration"}),"\n",(0,r.jsx)(n.li,{children:"Flexible tool configuration"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"4-error-handling",children:"4. Error Handling"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Comprehensive exception handling"}),"\n",(0,r.jsx)(n.li,{children:"User-friendly error messages"}),"\n",(0,r.jsx)(n.li,{children:"Logging for debugging"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"5-artifact-management",children:"5. Artifact Management"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Saving structured data as files"}),"\n",(0,r.jsx)(n.li,{children:"Metadata enrichment"}),"\n",(0,r.jsx)(n.li,{children:"File format handling"}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>s});var a=t(6540);const r={},o=a.createContext(r);function i(e){const n=a.useContext(o);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),a.createElement(o.Provider,{value:n},e.children)}}}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[3974],{6145:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>g,frontMatter:()=>l,metadata:()=>o,toc:()=>c});const o=JSON.parse('{"id":"documentation/user-guide/create-agents","title":"Create Agents","description":"Introduction","source":"@site/docs/documentation/user-guide/create-agents.md","sourceDirName":"documentation/user-guide","slug":"/documentation/user-guide/create-agents","permalink":"/solace-agent-mesh/docs/documentation/user-guide/create-agents","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/user-guide/create-agents.md","tags":[],"version":"current","sidebarPosition":30,"frontMatter":{"title":"Create Agents","sidebar_position":30},"sidebar":"docSidebar","previous":{"title":"Structure","permalink":"/solace-agent-mesh/docs/documentation/user-guide/structure"},"next":{"title":"Creating Python Tools","permalink":"/solace-agent-mesh/docs/documentation/user-guide/creating-python-tools"}}');var i=t(4848),s=t(8453);const l={title:"Create Agents",sidebar_position:30},r="Creating Agents",a={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Quick Start: Creating Your First Agent",id:"quick-start-creating-your-first-agent",level:2},{value:"CLI Options",id:"cli-options",level:3},{value:"Core Concepts",id:"core-concepts",level:2},{value:"Tools",id:"tools",level:3},{value:"Configuration File",id:"configuration-file",level:3},{value:"Tool Configuration",id:"tool-configuration",level:3},{value:"ToolContext",id:"toolcontext",level:3},{value:"Lifecycle Functions",id:"lifecycle-functions",level:3},{value:"Step-by-Step Guide",id:"step-by-step-guide",level:2},{value:"Step 1: Initialize your Agent",id:"step-1-initialize-your-agent",level:3},{value:"Step 2: The Tool Function",id:"step-2-the-tool-function",level:3},{value:"Step 3: The Agent Configuration",id:"step-3-the-agent-configuration",level:3},{value:"Step 4: The Lifecycle Function",id:"step-4-the-lifecycle-function",level:3},{value:"Advanced Concepts",id:"advanced-concepts",level:2},{value:"Working with Artifacts",id:"working-with-artifacts",level:3},{value:"Using Multiple Tool Configurations",id:"using-multiple-tool-configurations",level:3},{value:"Running Your Agent",id:"running-your-agent",level:2},{value:"Architecture Overview",id:"architecture-overview",level:2},{value:"Best Practices",id:"best-practices",level:2},{value:"Tool Design",id:"tool-design",level:3},{value:"Configuration",id:"configuration",level:3},{value:"Testing",id:"testing",level:3}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",mermaid:"mermaid",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"creating-agents",children:"Creating Agents"})}),"\n",(0,i.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["For a more comprehensive tutorial example, see the ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/tutorials/custom-agent",children:"Build Your Own Agent"})," guide.\nThis page provides an in-depth theoretical overview of creating agents in Solace Agent Mesh."]})}),"\n",(0,i.jsxs)(n.p,{children:["Solace Agent Mesh (SAM) is a powerful platform that enables you to create intelligent agents that can communicate with each other and perform complex tasks. At its core, SAM uses a ",(0,i.jsx)(n.strong,{children:"tool-based architecture"})," where LLM-powered agents are equipped with specific capabilities (tools) that they can use to accomplish user requests."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsxs)(n.strong,{children:["Before continuing with this tutorial, make sure you are familiar with the basic ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/concepts/agents",children:"agent concept"}),"."]})}),"\n",(0,i.jsx)(n.p,{children:"This tutorial guides you through creating your first SAM agent from scratch. You will learn how to:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Define tools as Python functions"}),"\n",(0,i.jsx)(n.li,{children:"Configure an agent using YAML"}),"\n",(0,i.jsx)(n.li,{children:"Set up agent lifecycle functions"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:'By the end of this tutorial, you should have a working "Hello World" agent that demonstrates the fundamental concepts of SAM agent development.'}),"\n",(0,i.jsx)(n.h2,{id:"quick-start-creating-your-first-agent",children:"Quick Start: Creating Your First Agent"}),"\n",(0,i.jsxs)(n.p,{children:["You can create an agent directly using the SAM CLI ",(0,i.jsx)(n.code,{children:"sam add agent"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam add agent my-first-agent\n"})}),"\n",(0,i.jsx)(n.p,{children:"This command:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Launches an interactive setup (or use ",(0,i.jsx)(n.code,{children:"--gui"})," for browser-based configuration)"]}),"\n",(0,i.jsx)(n.li,{children:"Generates the necessary files and configuration"}),"\n",(0,i.jsx)(n.li,{children:"Sets up the basic agent structure"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Note that create agent as plugin is preferred over create agent directly."}),"\n",(0,i.jsx)(n.h3,{id:"cli-options",children:"CLI Options"}),"\n",(0,i.jsx)(n.p,{children:"You can customize the agent creation with provided CLI options."}),"\n",(0,i.jsx)(n.p,{children:"For a complete list of options, run:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam add agent --help\n"})}),"\n",(0,i.jsx)(n.h2,{id:"core-concepts",children:"Core Concepts"}),"\n",(0,i.jsx)(n.p,{children:"Before diving into the implementation, it is important to understand the key concepts that make SAM agents work:"}),"\n",(0,i.jsx)(n.h3,{id:"tools",children:"Tools"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Tools are the fundamental building blocks of SAM agents."})," Each tool is implemented as a Python function that performs a specific task. Tools can:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Process text and data"}),"\n",(0,i.jsx)(n.li,{children:"Interact with external APIs"}),"\n",(0,i.jsx)(n.li,{children:"Create and manipulate files"}),"\n",(0,i.jsx)(n.li,{children:"Communicate with other agents"}),"\n",(0,i.jsx)(n.li,{children:"Access databases and services"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"The LLM (Large Language Model) orchestrating your agent decides which tools to use based on the user's request and the tool descriptions you provide."}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Solace Agent Mesh provides a set of ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/user-guide/builtin-tools/",children:"built-in tools"})," plus support for ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/tutorials/mcp-integration",children:"model context protocol (MCP)"})," servers, which can be configured in the tools list of your agent configuration."]})}),"\n",(0,i.jsx)(n.h3,{id:"configuration-file",children:"Configuration File"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"config.yaml"})," (for plugin template) or ",(0,i.jsx)(n.code,{children:"agent-name.yaml"})," (for agent instances) file is the blueprint of your agent. It defines:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Agent identity"}),": Name, description, and capabilities"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Model configuration"}),": Which LLM to use"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Tools list"}),": Defines which tools the agent can access and how they're configured"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Lifecycle functions"}),": Setup and cleanup procedures"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Framework services"}),": Session management, artifact storage, and so on."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/concepts/agents#agent-card",children:"Agent card"})}),": Metadata describing the agent capabilities, skills and its visibility in the system"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"tool-configuration",children:"Tool Configuration"}),"\n",(0,i.jsxs)(n.p,{children:["Within the ",(0,i.jsx)(n.code,{children:"tools"})," list in your YAML config, each tool can have its own ",(0,i.jsx)(n.code,{children:"tool_config"})," section. This allows you to:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Configure the same tool function for different purposes"}),"\n",(0,i.jsx)(n.li,{children:"Pass specific parameters to tool instances"}),"\n",(0,i.jsx)(n.li,{children:"Customize tool behavior per agent"}),"\n"]}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsxs)(n.p,{children:['For tools of type "python", you can also use the ',(0,i.jsx)(n.code,{children:"tool_name"})," and ",(0,i.jsx)(n.code,{children:"tool_description"})," to overwrite the function name and description in the tool docstring."]}),(0,i.jsx)(n.p,{children:"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."})]}),"\n",(0,i.jsx)(n.h3,{id:"toolcontext",children:"ToolContext"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"ToolContext"})," object (passed as one of the arguments to your tool function) provides your tools with access to SAM core services:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Logging"}),": Structured logging for debugging and monitoring"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Artifact Service"}),": File storage and retrieval"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Session Information"}),": Current user and session context"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Agent State"}),": Shared data between tool calls"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"lifecycle-functions",children:"Lifecycle Functions"}),"\n",(0,i.jsx)(n.p,{children:"Lifecycle functions allow you to manage resources that should persist for the agent's lifetime:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"agent_init_function"})}),": Runs when the agent starts (for example, database connections)"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"agent_cleanup_function"})}),": Runs when the agent shuts down (for example, closing connections)"]}),"\n"]}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsx)(n.p,{children:"Lifecycle functions are optional but recommended for managing resources effectively."})}),"\n",(0,i.jsx)(n.h2,{id:"step-by-step-guide",children:"Step-by-Step Guide"}),"\n",(0,i.jsx)(n.p,{children:"Create a simple agent that can greet users and demonstrate the core concepts."}),"\n",(0,i.jsxs)(n.p,{children:["You can create an agent either by using the ",(0,i.jsx)(n.code,{children:"sam add agent"})," command or by creating a new plugin of type agent, ",(0,i.jsx)(n.code,{children:"sam plugin create my-hello-agent --type agent"}),"."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["For information and recommendations about these options, see ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/concepts/plugins#agent-or-plugin-which-to-use",children:(0,i.jsx)(n.code,{children:"Agent or Plugin: Which To use?"})}),"."]})}),"\n",(0,i.jsx)(n.h3,{id:"step-1-initialize-your-agent",children:"Step 1: Initialize your Agent"}),"\n",(0,i.jsxs)(n.p,{children:["In this tutorial, you create a new agent by creating a new plugin of type agent.\nFor an example of custom agents, see ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/tutorials/custom-agent",children:"Build Your Own Agent"})," guide."]}),"\n",(0,i.jsx)(n.p,{children:"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."}),"\n",(0,i.jsx)(n.p,{children:"To create a new agent plugin, run the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam plugin create my-hello-agent --type agent\n"})}),"\n",(0,i.jsx)(n.p,{children:"And follow the prompts to set up your agent. The prompts create a new directory structure for your agent."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"my-hello-agent/\n\u251c\u2500\u2500 src/\n\u2502 \u2514\u2500\u2500 my_hello_agent/\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 tools.py\n\u2502 \u2514\u2500\u2500 lifecycle.py # This file won't be automatically created\n\u251c\u2500\u2500 config.yaml\n\u251c\u2500\u2500 pyproject.toml\n\u2514\u2500\u2500 README.md\n"})}),"\n",(0,i.jsx)(n.mermaid,{value:"graph TD\n A[my-hello-agent/] --\x3e B[src/]\n A --\x3e C[config.yaml]\n A --\x3e D[pyproject.toml]\n A --\x3e E[README.md]\n \n B --\x3e F[my_hello_agent/]\n F --\x3e G[__init__.py]\n F --\x3e H[tools.py]\n F --\x3e I[lifecycle.py]\n \n style C fill:#b60000,stroke:#333,stroke-width:2px\n style H fill:#b60000,stroke:#333,stroke-width:2px\n style I fill:#007000,stroke:#333,stroke-width:2px"}),"\n",(0,i.jsx)(n.h3,{id:"step-2-the-tool-function",children:"Step 2: The Tool Function"}),"\n",(0,i.jsx)(n.p,{children:"Create your first tool function:\nThe following arguments are provided by the framework:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"tool_context: SAM framework context"}),"\n",(0,i.jsx)(n.li,{children:"tool_config: Tool-specific configuration (from config.yaml)"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["For a complete guide on creating python tools, see our ",(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/user-guide/creating-python-tools",children:"Creating Python Tools"})})," documentation."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'# src/my_hello_agent/tools.py\n"""\nTools for the Hello World agent.\n"""\n\nfrom typing import Any, Dict, Optional\nfrom google.adk.tools import ToolContext\nfrom solace_ai_connector.common.log import log\n\n\nasync def hello_tool(\n name: str,\n tool_context: Optional[ToolContext] = None,\n tool_config: Optional[Dict[str, Any]] = None\n) -> Dict[str, Any]:\n """\n Greets a user with a personalized message.\n \n Args:\n name: The name of the person to greet\n \n Returns:\n A dictionary with the greeting message\n """\n log_identifier = "[HelloTool]"\n log.info(f"{log_identifier} Greeting user: {name}")\n \n # Get configuration from tool_config\n greeting_prefix = "Hello"\n if tool_config:\n greeting_prefix = tool_config.get("greeting_prefix", "Hello")\n \n # Create the greeting message\n greeting_message = f"{greeting_prefix}, {name}! Welcome to Solace Agent Mesh!"\n \n log.info(f"{log_identifier} Generated greeting: {greeting_message}")\n \n return {\n "status": "success",\n "message": greeting_message,\n "greeted_name": name\n }\n\n\nasync def farewell_tool(\n name: str,\n tool_context: Optional[ToolContext] = None,\n tool_config: Optional[Dict[str, Any]] = None\n) -> Dict[str, Any]:\n """\n Says goodbye to a user.\n \n Args:\n name: The name of the person to say goodbye to\n \n Returns:\n A dictionary with the farewell message\n """\n log_identifier = "[FarewellTool]"\n log.info(f"{log_identifier} Saying goodbye to user: {name}")\n \n # Get configuration from tool_config\n farewell_prefix = "Goodbye"\n if tool_config:\n farewell_prefix = tool_config.get("farewell_prefix", "Goodbye")\n \n # Create the farewell message\n farewell_message = f"{farewell_prefix}, {name}! Thanks for using Solace Agent Mesh!"\n \n log.info(f"{log_identifier} Generated farewell: {farewell_message}")\n \n return {\n "status": "success",\n "message": farewell_message,\n "farewell_name": name\n }\n'})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Key Points:"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Function Signature"}),": All tool functions should be ",(0,i.jsx)(n.code,{children:"async"})," and accept ",(0,i.jsx)(n.code,{children:"tool_context"})," and ",(0,i.jsx)(n.code,{children:"tool_config"})," parameters"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Return Format"}),": Return a dictionary with at least a ",(0,i.jsx)(n.code,{children:"status"})," field"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Logging"}),": Use the SAM logger for consistent logging"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Configuration"}),": Access tool-specific config via the ",(0,i.jsx)(n.code,{children:"tool_config"})," parameter"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"step-3-the-agent-configuration",children:"Step 3: The Agent Configuration"}),"\n",(0,i.jsx)(n.p,{children:"Create the main configuration file for your agent:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# ... (additional services and configurations)\n\napps:\n - name: my-hello-agent\n app_module: solace_agent_mesh.agent.sac.app \n broker:\n <<: *broker_connection\n \n # Agent-specific configuration\n app_config:\n # Basic agent identity\n namespace: ${NAMESPACE} \n supports_streaming: true \n agent_name: "HelloAgent"\n display_name: "Hello World Agent"\n \n # LLM model configuration\n model: *general_model \n \n # Agent instructions (system prompt)\n instruction: |\n You are a friendly Hello World agent. Your purpose is to greet users and \n demonstrate the capabilities of Solace Agent Mesh. You can:\n \n 1. Greet users with personalized messages using the hello_tool\n 2. Say goodbye to users using the farewell_tool\n \n Always be polite and helpful. When greeting someone, ask for their name \n if they haven\'t provided it.\n \n # Lifecycle functions\n agent_init_function:\n module: "my_hello_agent.lifecycle" # This should point to your lifecycle python module\n name: "initialize_hello_agent"\n base_path: .\n config:\n startup_message: "Hello Agent is starting up!"\n log_level: "INFO"\n \n agent_cleanup_function:\n module: "my_hello_agent.lifecycle"\n base_path: .\n name: "cleanup_hello_agent"\n \n # Tools configuration\n tools:\n # Hello tool with custom greeting\n - tool_type: python\n component_module: "my_hello_agent.tools"\n component_base_path: .\n function_name: "hello_tool"\n tool_name: "greet_user" # Renaming the tool, must use this name in the agent card\n tool_config:\n greeting_prefix: "Hello there"\n \n # Farewell tool with custom farewell\n - tool_type: python\n component_module: "my_hello_agent.tools"\n component_base_path: .\n function_name: "farewell_tool"\n tool_name: "say_goodbye"\n tool_config:\n farewell_prefix: "See you later"\n \n # Built-in artifact tools for file operations\n - tool_type: builtin-group\n group_name: "artifact_management"\n \n # Agent card (describes the agent\'s capabilities)\n agent_card:\n description: "A friendly Hello World agent that demonstrates SAM capabilities"\n defaultInputModes: ["text"]\n defaultOutputModes: ["text"]\n skills:\n - id: "greet_user"\n name: "Greet User"\n description: "Greets users with personalized messages"\n - id: "say_goodbye"\n name: "Say Goodbye"\n description: "Says goodbye to users"\n - id: "file_operations"\n name: "File Operations"\n description: "Create, read, and manage files and artifacts"\n \n # Session and artifact services\n session_service: *default_session_service\n artifact_service: *default_artifact_service\n# ... (additional services and configurations)\n'})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Key Sections Explained:"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"namespace"})}),": Unique identifier for your agent in the mesh"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"model"})}),": LLM configuration (can be a string or detailed config)"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"instruction"})}),": The system prompt that defines your agent's behavior"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"tools"})}),": List of tools your agent can use, with their configurations"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"agent_card"})}),": Metadata describing your agent's capabilities"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"step-4-the-lifecycle-function",children:"Step 4: The Lifecycle Function"}),"\n",(0,i.jsx)(n.p,{children:"Lifecycle functions are completely optional but useful for managing resources. They run when the agent starts and stops."}),"\n",(0,i.jsx)(n.p,{children:"The lifecycle file is not automatically created, so you need to create it manually:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"touch src/my_hello_agent/lifecycle.py\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'# src/my_hello_agent/lifecycle.py\n"""\nLifecycle functions for the Hello World agent.\n"""\n\nfrom typing import Any, Dict\nfrom pydantic import BaseModel, Field\nfrom solace_ai_connector.common.log import log\n\n\nclass HelloAgentInitConfig(BaseModel):\n """\n Configuration model for the Hello Agent initialization.\n """\n startup_message: str = Field(description="Message to log on startup")\n log_level: str = Field(default="INFO", description="Logging level for the agent")\n\n\ndef initialize_hello_agent(host_component: Any, init_config: HelloAgentInitConfig):\n """\n Initializes the Hello World agent.\n \n Args:\n host_component: The agent host component\n init_config: Validated initialization configuration\n """\n log_identifier = f"[{host_component.agent_name}:init]"\n log.info(f"{log_identifier} Starting Hello Agent initialization...")\n \n # Log the startup message from config\n log.info(f"{log_identifier} {init_config.startup_message}")\n \n # You could initialize shared resources here, such as:\n # - Database connections\n # - API clients\n # - Caches or shared data structures\n \n # Store any shared state in the agent\n host_component.set_agent_specific_state("initialized_at", "2024-01-01T00:00:00Z")\n host_component.set_agent_specific_state("greeting_count", 0)\n \n log.info(f"{log_identifier} Hello Agent initialization completed successfully")\n\n\ndef cleanup_hello_agent(host_component: Any):\n """\n Cleans up resources when the Hello World agent shuts down.\n \n Args:\n host_component: The agent host component\n """\n log_identifier = f"[{host_component.agent_name}:cleanup]"\n log.info(f"{log_identifier} Starting Hello Agent cleanup...")\n \n # Retrieve any shared state\n greeting_count = host_component.get_agent_specific_state("greeting_count", 0)\n log.info(f"{log_identifier} Agent processed {greeting_count} greetings during its lifetime")\n \n # Clean up resources here, such as:\n # - Closing database connections\n # - Shutting down background tasks\n # - Saving final state\n \n log.info(f"{log_identifier} Hello Agent cleanup completed")\n'})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Key Points:"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Pydantic Models"}),": Use Pydantic for configuration validation"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Shared State"}),": Store data that persists across tool calls"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Resource Management"}),": Initialize connections in ",(0,i.jsx)(n.code,{children:"init"}),", clean up in ",(0,i.jsx)(n.code,{children:"cleanup"})]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"advanced-concepts",children:"Advanced Concepts"}),"\n",(0,i.jsx)(n.h3,{id:"working-with-artifacts",children:"Working with Artifacts"}),"\n",(0,i.jsx)(n.p,{children:"You can enhance our hello tool to save greetings to a file using SAM's artifact service:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'\nfrom datetime import datetime\nfrom solace_agent_mesh.agent.utils.artifact_helpers import save_artifact_with_metadata\n\nasync def hello_tool_with_artifact(\n name: str,\n save_to_file: bool = False,\n tool_context: Optional[ToolContext] = None,\n tool_config: Optional[Dict[str, Any]] = None\n) -> Dict[str, Any]:\n """\n Greets a user and optionally saves the greeting to a file.\n """\n log_identifier = "[HelloToolWithArtifact]"\n \n # Generate greeting (same as before)\n greeting_prefix = tool_config.get("greeting_prefix", "Hello") if tool_config else "Hello"\n greeting_message = f"{greeting_prefix}, {name}! Welcome to Solace Agent Mesh!"\n \n result = {\n "status": "success",\n "message": greeting_message,\n "greeted_name": name\n }\n \n # Save to artifact if requested\n if save_to_file and tool_context:\n try:\n # Prepare content\n timestamp = datetime.now(timezone.utc)\n filename = f"greeting_{name}_{timestamp}.txt"\n content = f"Greeting: {greeting_message}\\nTimestamp: {timestamp}\\n"\n \n # Save artifact\n artifact_service = tool_context._invocation_context.artifact_service\n await save_artifact_with_metadata(\n artifact_service=artifact_service,\n app_name=tool_context._invocation_context.app_name,\n user_id=tool_context._invocation_context.user_id,\n session_id=tool_context._invocation_context.session.id,\n filename=filename,\n content_bytes=content.encode(\'utf-8\'),\n mime_type="application/json",\n metadata_dict={\n "description": "Greeting message",\n "source": "Greeting Agent",\n },\n timestamp=timestamp\n )\n \n result["artifact_saved"] = filename\n log.info(f"{log_identifier} Saved greeting to artifact: {filename}")\n \n except Exception as e:\n log.error(f"{log_identifier} Failed to save artifact: {e}")\n result["artifact_error"] = str(e)\n \n return result\n'})}),"\n",(0,i.jsx)(n.h3,{id:"using-multiple-tool-configurations",children:"Using Multiple Tool Configurations"}),"\n",(0,i.jsx)(n.p,{children:"You can configure the same tool function multiple times with different settings:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'tools:\n # Formal greeting\n - tool_type: python\n component_module: "my_hello_agent.tools"\n function_name: "hello_tool"\n tool_name: "formal_greeting"\n tool_config:\n greeting_prefix: "Good day"\n \n # Casual greeting\n - tool_type: python\n component_module: "my_hello_agent.tools"\n function_name: "hello_tool"\n tool_name: "casual_greeting"\n tool_config:\n greeting_prefix: "Hey there"\n \n # Enthusiastic greeting\n - tool_type: python\n component_module: "my_hello_agent.tools"\n function_name: "hello_tool"\n tool_name: "enthusiastic_greeting"\n tool_config:\n greeting_prefix: "Hello and welcome"\n'})}),"\n",(0,i.jsx)(n.p,{children:"This gives your agent multiple greeting styles to choose from based on the context."}),"\n",(0,i.jsx)(n.h2,{id:"running-your-agent",children:"Running Your Agent"}),"\n",(0,i.jsx)(n.p,{children:"To run a plugin agent, you first need to package and install it as a plugin."}),"\n",(0,i.jsxs)(n.admonition,{title:"Quick Debug",type:"tip",children:[(0,i.jsxs)(n.p,{children:["For debugging or isolated development testing, you can run your agent from the ",(0,i.jsx)(n.code,{children:"src"})," directory directly using the SAM CLI."]}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cd src\nsam run ../config.yaml\n"})}),(0,i.jsx)(n.p,{children:"Changing to the src directory allows the module path to be set correctly so that SAM can find your functions without your having to install them in your python environment as a plugin package."})]}),"\n",(0,i.jsxs)(n.p,{children:["To properly instantiate your plugin agent, first build the plugin.\nThe following command will produce a python wheel file under ",(0,i.jsx)(n.code,{children:"dist"})," directory:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam plugin build\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Check into ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/getting-started/quick-start#create-a-project",children:"your SAM project directory"}),", and add the plugin wheel with a given name:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"sam plugin add my-first-weather-agent --plugin PATH/TO/weather-agent/dist/weather-agent.whl\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Using the ",(0,i.jsx)(n.code,{children:"sam plugin add"})," command installs your plugin as a python dependency into your python environment.\nThis also means changing the source code without reinstalling the plugin will not reflect the changes."]})}),"\n",(0,i.jsx)(n.p,{children:"Now, you can run the complete SAM application along with your newly added agent:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"sam run\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Alternatively, only run the newly added agent using ",(0,i.jsx)(n.code,{children:"sam run configs/agents/my-first-weather-agent.yaml"})]}),"\n",(0,i.jsx)(n.h2,{id:"architecture-overview",children:"Architecture Overview"}),"\n",(0,i.jsx)(n.p,{children:"Here is how all the pieces fit together:"}),"\n",(0,i.jsx)(n.mermaid,{value:"graph TD\n subgraph Agent Configuration\n direction LR\n A[config.yaml] --\x3e|Defines| B(Agent Properties);\n A --\x3e|Lists & Configures| C(Tools);\n end\n\n subgraph Agent Host\n direction TB\n D[SAM Host] --\x3e|Loads| A;\n D --\x3e|Instantiates| E[Agent];\n E --\x3e|Initializes with| F[Lifecycle Functions];\n end\n\n subgraph Tool Implementation\n direction LR\n G[Python Module tools.py] --\x3e|Contains| H[Tool Functions];\n end\n\n subgraph Execution Flow\n direction TB\n I[User Request] --\x3e J[LLM Orchestrator];\n J --\x3e|Selects Tool| K{ADKToolWrapper};\n K --\x3e|Calls| H;\n H --\x3e|Accesses| L[ToolContext];\n H --\x3e|Uses| M[tool_config];\n H --\x3e|Returns Result| J;\n end\n\n C --\x3e|Wrapped by| K;\n\n style A fill:#b60000,stroke:#faa,stroke-width:2px\n style H fill:#b60000,stroke:#faa,stroke-width:2px\n style F fill:#007000,stroke:#faa,stroke-width:2px"}),"\n",(0,i.jsx)(n.h2,{id:"best-practices",children:"Best Practices"}),"\n",(0,i.jsx)(n.h3,{id:"tool-design",children:"Tool Design"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Single Responsibility"}),": Each tool should do one thing well"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Clear Documentation"}),": Write detailed docstrings for your tools"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Error Handling"}),": Always return structured error responses"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Logging"}),": Use consistent logging for debugging and monitoring"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"configuration",children:"Configuration"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Environment Variables"}),": Use environment variables for sensitive data"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Validation"}),": Use Pydantic models for configuration validation"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Documentation"}),": Comment your configuration files thoroughly"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"testing",children:"Testing"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Unit Tests"}),": Test your tool functions independently"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Integration Tests"}),": Test your agent with real SAM infrastructure"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Mock Dependencies"}),": Mock external services for reliable testing"]}),"\n"]})]})}function g(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>l,x:()=>r});var o=t(6540);const i={},s=o.createContext(i);function l(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[1442],{8376:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"documentation/concepts/plugins","title":"Plugins","description":"Plugins","source":"@site/docs/documentation/concepts/plugins.md","sourceDirName":"documentation/concepts","slug":"/documentation/concepts/plugins","permalink":"/solace-agent-mesh/docs/documentation/concepts/plugins","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/concepts/plugins.md","tags":[],"version":"current","sidebarPosition":60,"frontMatter":{"title":"Plugins","sidebar_position":60},"sidebar":"docSidebar","previous":{"title":"Orchestrator","permalink":"/solace-agent-mesh/docs/documentation/concepts/orchestrator"},"next":{"title":"Solace AI Event Connector","permalink":"/solace-agent-mesh/docs/documentation/user-guide/solace-ai-connector"}}');var s=t(4848),l=t(8453);const a={title:"Plugins",sidebar_position:60},o=void 0,r={},c=[{value:"Plugins",id:"plugins",level:2},{value:"Official Core Plugins",id:"official-core-plugins",level:3},{value:"Create a Plugin",id:"create-a-plugin",level:2},{value:"Build the Plugin",id:"build-the-plugin",level:3},{value:"Share the Plugin",id:"share-the-plugin",level:3},{value:"Use a Plugin",id:"use-a-plugin",level:2},{value:"Plugin Catalog Dashboard",id:"plugin-catalog-dashboard",level:2},{value:"Agent or Plugin: Which To Use?",id:"agent-or-plugin-which-to-use",level:2},{value:"When To Use a Standalone Agent",id:"when-to-use-a-standalone-agent",level:3},{value:"When To Use an Agent Plugin",id:"when-to-use-an-agent-plugin",level:3},{value:"Recommendation",id:"recommendation",level:3}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h2,{id:"plugins",children:"Plugins"}),"\n",(0,s.jsx)(n.p,{children:"Plugins provide a mechanism to extend the functionality of Solace Agent Mesh in a modular, shareable, and reusable way. The current plugin ecosystem includes agents, gateways, and specialized integrations."}),"\n",(0,s.jsx)(n.admonition,{title:"In one sentence",type:"tip",children:(0,s.jsx)(n.p,{children:"Plugins are modular Python packages that extend SAM's capabilities through agents, gateways, and specialized integrations."})}),"\n",(0,s.jsxs)(n.p,{children:["Plugins are packaged as Python modules that can be installed using various package managers (",(0,s.jsx)(n.code,{children:"pip"}),", ",(0,s.jsx)(n.code,{children:"uv"}),", ",(0,s.jsx)(n.code,{children:"poetry"}),", ",(0,s.jsx)(n.code,{children:"conda"}),"). They integrate seamlessly with the A2A protocol and can provide:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Agent Plugins"}),": Specialized agents with domain-specific capabilities"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Gateway Plugins"}),": New interface types for external system integration"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Custom Plugins"}),": Custom integrations such as HR providers."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"All plugin interactions (create, build, add) are managed through the SAM CLI."}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["Run ",(0,s.jsx)(n.code,{children:"sam plugin --help"})," to see the list of available commands for plugins."]})}),"\n",(0,s.jsx)(n.h3,{id:"official-core-plugins",children:"Official Core Plugins"}),"\n",(0,s.jsxs)(n.p,{children:["Solace Agent Mesh comes with a set of official core plugins that can be used to extend the functionality of the system. You can find the repository of the official core plugins ",(0,s.jsx)(n.a,{href:"https://github.com/SolaceLabs/solace-agent-mesh-core-plugins",children:"here \ud83d\udd17"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["For more information about how to use the official core plugins, see ",(0,s.jsx)(n.a,{href:"#use-a-plugin",children:"Use Plugins"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"create-a-plugin",children:"Create a Plugin"}),"\n",(0,s.jsxs)(n.p,{children:["To get started, ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/getting-started/installation",children:"install the SAM CLI"})," and run the following command:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"solace-agent-mesh plugin create <plugin-name>\n"})}),"\n",(0,s.jsx)(n.p,{children:"Follow the prompts to create a new plugin. A plugin can be one of the following types:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Agent Plugin"}),": Contains custom agents that can be used in a Solace Agent Mesh project."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Gateway Plugin"}),": Contains custom gateways that can be used in a Solace Agent Mesh project."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Custom Plugin"}),": Contains custom integrations such as HR providers or other specialized functionality."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Solace Agent Mesh (SAM) CLI creates a directory with the provided name and the following structure:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"plugin-name/\n\u251c\u2500 config.yaml\n\u251c\u2500 src/\n\u2502 \u251c\u2500 __init__.py\n\u2502 \u251c\u2500 [...Other type specific python files]\n\u251c\u2500 .gitignore\n\u251c\u2500 pyproject.toml\n\u251c\u2500 README.md\n"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["The ",(0,s.jsx)(n.code,{children:"src"})," directory contains the python source code."]}),"\n",(0,s.jsxs)(n.li,{children:["The ",(0,s.jsx)(n.code,{children:"config.yaml"})," file holds the configuration for the plugin, and how to be used in a SAM application."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Once the plugin is created, you can start customizing the config.yaml or the python files."}),"\n",(0,s.jsx)(n.h3,{id:"build-the-plugin",children:"Build the Plugin"}),"\n",(0,s.jsxs)(n.p,{children:["Building the plugin creates a Python wheel package that can be installed using ",(0,s.jsx)(n.code,{children:"pip"})," or other package managers."]}),"\n",(0,s.jsxs)(n.p,{children:["Python ",(0,s.jsx)(n.code,{children:"build"})," package must be installed already since ",(0,s.jsx)(n.code,{children:"sam plugin build"})," command uses ",(0,s.jsx)(n.code,{children:"build"})," package, if not, run ",(0,s.jsx)(n.code,{children:"pip install build"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"To build the plugin, run the following SAM CLI command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"solace-agent-mesh plugin build\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The plugin uses the standard ",(0,s.jsx)(n.code,{children:"pyproject.toml"})," file to build the package."]}),"\n",(0,s.jsx)(n.h3,{id:"share-the-plugin",children:"Share the Plugin"}),"\n",(0,s.jsxs)(n.p,{children:["To share the plugin, you can upload the wheel package to a package repository or share the wheel package directly, or any other valid way to share a ",(0,s.jsx)(n.code,{children:"pyproject"})," project."]}),"\n",(0,s.jsx)(n.h2,{id:"use-a-plugin",children:"Use a Plugin"}),"\n",(0,s.jsxs)(n.p,{children:["To use a plugin in your project, use the ",(0,s.jsx)(n.code,{children:"plugin add"})," command, which performs two steps under-the-hood:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Locates the plugin or installs the plugin package using a Python package manager (like ",(0,s.jsx)(n.code,{children:"pip"})," or ",(0,s.jsx)(n.code,{children:"uv"}),")"]}),"\n",(0,s.jsx)(n.li,{children:"Creates a component instance based on the plugin"}),"\n"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"solace-agent-mesh plugin add <COMPONENT_NAME> --plugin <PLUGIN_NAME>\n"})}),"\n",(0,s.jsx)(n.p,{children:"where:"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"<COMPONENT_NAME>"})," is the name you choose for the component instance in your project."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"<PLUGIN_NAME>"}),", you can use:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Name of the plugin as published to a package manager like ",(0,s.jsx)(n.code,{children:"pypi"}),", for example ",(0,s.jsx)(n.code,{children:"my-plugin"})]}),"\n",(0,s.jsx)(n.li,{children:"Name of the plugin that has been already installed into your Python environment."}),"\n",(0,s.jsxs)(n.li,{children:["A local path to the plugin directory, for example ",(0,s.jsx)(n.code,{children:"./my-plugin"})]}),"\n",(0,s.jsxs)(n.li,{children:["A path to a wheel package, for example ",(0,s.jsx)(n.code,{children:"./my-plugin/dist/my_plugin-0.1.0-py3-none-any.whl"})]}),"\n",(0,s.jsxs)(n.li,{children:["A URL to a git repository, for example ",(0,s.jsx)(n.code,{children:"git+https://github.com/<USERNAME>/<REPOSITORY>"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["If the plugin is in a subdirectory of the repository, you can specify the subdirectory using the ",(0,s.jsx)(n.code,{children:"git+https://github.com/<USERNAME>/<REPOSITORY>#subdirectory=<PLUGIN_NAME>"})," syntax."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"The CLI handles both steps automatically, or you can manage the plugin installation yourself using your preferred Python package manager."}),"\n",(0,s.jsxs)(n.admonition,{type:"tip",children:[(0,s.jsxs)(n.p,{children:["You can also customize the python package manager command used to install the plugin by setting the ",(0,s.jsx)(n.code,{children:"SAM_PLUGIN_INSTALL_COMMAND"})," environment variable or passing the ",(0,s.jsx)(n.code,{children:"--install-command"})," option to the ",(0,s.jsx)(n.code,{children:"plugin add"})," command.\nFor example, to use ",(0,s.jsx)(n.code,{children:"uv"})," as the package manager, you can run:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'export SAM_PLUGIN_INSTALL_COMMAND="uv pip install {package}"\n'})}),(0,s.jsx)(n.p,{children:"or"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'solace-agent-mesh plugin add <COMPONENT_NAME> --plugin <PLUGIN_NAME> --install-command "uv pip install {package}"\n'})})]}),"\n",(0,s.jsxs)(n.p,{children:["This command adds the plugin instance configuration to your ",(0,s.jsx)(n.code,{children:"configs"})," directory."]}),"\n",(0,s.jsx)(n.p,{children:"Depending on the plugin, you may need to update the newly added plugin configuration file. Follow the instructions provided by the plugin author for any specific configurations."}),"\n",(0,s.jsx)(n.h2,{id:"plugin-catalog-dashboard",children:"Plugin Catalog Dashboard"}),"\n",(0,s.jsxs)(n.p,{children:["You can manage available plugins with the ",(0,s.jsx)(n.code,{children:"plugin catalog"})," command, which launches a user-friendly interface."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"solace-agent-mesh plugin catalog\n"})}),"\n",(0,s.jsx)(n.h2,{id:"agent-or-plugin-which-to-use",children:"Agent or Plugin: Which To Use?"}),"\n",(0,s.jsx)(n.p,{children:"In simple terms, plugins of type agent are just packaged agents. However, there are distinct advantages to each approach, and choosing the right one depends on your use case."}),"\n",(0,s.jsx)(n.p,{children:"Here\u2019s a detailed comparison to help you decide."}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{style:{textAlign:"left"},children:"Feature"}),(0,s.jsxs)(n.th,{style:{textAlign:"left"},children:["Standalone Agent (",(0,s.jsx)(n.code,{children:"sam add agent"}),")"]}),(0,s.jsxs)(n.th,{style:{textAlign:"left"},children:["Agent Plugin (",(0,s.jsx)(n.code,{children:"sam plugin create"}),")"]})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{style:{textAlign:"left"},children:(0,s.jsx)(n.strong,{children:"Creation"})}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"A single command creates a configuration file in your project."}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"Creates a complete, standard Python project structure."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{style:{textAlign:"left"},children:(0,s.jsx)(n.strong,{children:"Structure"})}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"Consists of a YAML configuration file and associated Python tool files within a SAM project."}),(0,s.jsxs)(n.td,{style:{textAlign:"left"},children:["A self-contained Python package with ",(0,s.jsx)(n.code,{children:"pyproject.toml"}),", a ",(0,s.jsx)(n.code,{children:"src"})," directory, and configuration templates."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{style:{textAlign:"left"},children:(0,s.jsx)(n.strong,{children:"Packaging"})}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"Not packaged. It exists as a component within a larger SAM project."}),(0,s.jsxs)(n.td,{style:{textAlign:"left"},children:["Packaged into a standard Python wheel (",(0,s.jsx)(n.code,{children:".whl"}),") file using ",(0,s.jsx)(n.code,{children:"sam plugin build"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{style:{textAlign:"left"},children:(0,s.jsx)(n.strong,{children:"Distribution"})}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"Shared by copying files or sharing the entire project."}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"Easily distributed as a wheel file, via a Git repository, or published to a package index like PyPI."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{style:{textAlign:"left"},children:(0,s.jsx)(n.strong,{children:"Reusability"})}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"Primarily for use within the project where it was created."}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"Designed for high reusability across different projects, teams, and communities."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{style:{textAlign:"left"},children:(0,s.jsx)(n.strong,{children:"Installation"})}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"No installation needed. The agent is configured and run as part of the main project."}),(0,s.jsxs)(n.td,{style:{textAlign:"left"},children:["Installed into the Python environment using ",(0,s.jsx)(n.code,{children:"sam plugin add"}),", which handles the package installation."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{style:{textAlign:"left"},children:(0,s.jsx)(n.strong,{children:"Versioning"})}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"Versioned along with the main project."}),(0,s.jsxs)(n.td,{style:{textAlign:"left"},children:["Can be versioned independently according to Python packaging standards (e.g., ",(0,s.jsx)(n.code,{children:"v0.1.0"}),", ",(0,s.jsx)(n.code,{children:"v0.2.0"}),")."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{style:{textAlign:"left"},children:(0,s.jsx)(n.strong,{children:"Development"})}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"Simple and direct. Edit files and run. Ideal for rapid prototyping."}),(0,s.jsx)(n.td,{style:{textAlign:"left"},children:"Involves a build/install cycle. Better for structured, long-term development."})]})]})]}),"\n",(0,s.jsx)(n.h3,{id:"when-to-use-a-standalone-agent",children:"When To Use a Standalone Agent"}),"\n",(0,s.jsx)(n.p,{children:"Create a standalone agent when:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"You need to quickly test an idea or build a proof-of-concept."}),"\n",(0,s.jsx)(n.li,{children:"The agent is tightly coupled to a single project and is not intended for reuse."}),"\n",(0,s.jsx)(n.li,{children:"You want the most straightforward path to adding a simple agent without the overhead of a full package structure."}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"when-to-use-an-agent-plugin",children:"When To Use an Agent Plugin"}),"\n",(0,s.jsx)(n.p,{children:"Create an agent as a plugin when:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"You plan to use the same agent in multiple projects."}),"\n",(0,s.jsx)(n.li,{children:"You want to share your agent with other developers, teams, or the open-source community."}),"\n",(0,s.jsx)(n.li,{children:"You are building a robust, production-ready agent that benefits from a formal package structure, dependency management, and versioning."}),"\n",(0,s.jsx)(n.li,{children:"You are building a collection of standardized agents for your organization."}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"recommendation",children:"Recommendation"}),"\n",(0,s.jsx)(n.p,{children:"The choice of how to build your agent depends on your goals and the requirements of your project:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Standalone Agents"})," should be viewed as tactical tools for rapid, isolated prototyping. They serve immediate, project-specific needs but do not contribute to a scalable, long-term asset library."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Agent Plugins"})," are the foundation for building a robust, governable, and reusable AI ecosystem. This model treats AI capabilities as enterprise assets, promoting standardization, reducing redundant development costs, and accelerating innovation across the organization. For any capability intended for broader use or long-term value, the plugin framework is the mandated path to maximize return on investment and ensure architectural integrity."]}),"\n"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>o});var i=t(6540);const s={},l=i.createContext(s);function a(e){const n=i.useContext(l);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(l.Provider,{value:n},e.children)}}}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[2274],{4700:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>x,frontMatter:()=>r,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"documentation/Enterprise/single-sign-on","title":"SSO","description":"How to enable SSO","source":"@site/docs/documentation/Enterprise/single-sign-on.md","sourceDirName":"documentation/Enterprise","slug":"/documentation/Enterprise/single-sign-on","permalink":"/solace-agent-mesh/docs/documentation/Enterprise/single-sign-on","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/Enterprise/single-sign-on.md","tags":[],"version":"current","sidebarPosition":10,"frontMatter":{"title":"SSO","sidebar_position":10},"sidebar":"docSidebar","previous":{"title":"Installation","permalink":"/solace-agent-mesh/docs/documentation/Enterprise/installation"}}');var i=t(4848),s=t(8453);const r={title:"SSO",sidebar_position:10},a=void 0,c={},l=[{value:"How to enable SSO",id:"how-to-enable-sso",level:2},{value:"Running SAM Enterprise with SSO enabled",id:"running-sam-enterprise-with-sso-enabled",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",p:"p",pre:"pre",strong:"strong",...(0,s.R)(),...e.components},{Details:t}=n;return t||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h2,{id:"how-to-enable-sso",children:"How to enable SSO"}),"\n",(0,i.jsx)(n.p,{children:"Before running the Docker container, create two configuration files for SSO under the root directory in your Named Docker Volume. Use the content provided below for each file:"}),"\n",(0,i.jsxs)(t,{children:[(0,i.jsx)("summary",{children:"Configuration files for SSO"}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"oauth2_server.yaml"})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'---\n# Example gateway configuration with OAuth2 service integration\n# This shows how to configure a gateway to use the OAuth2 authentication service\n\nlog:\n stdout_log_level: INFO\n log_file_level: DEBUG\n log_file: oauth_server.log\n\n!include ../shared_config.yaml\n\nshared_config:\n # OAuth2 service configuration\n - oauth2_config: &oauth2_config\n enabled: true\n config_file: "config/sso_vol/oauth2_config.yaml"\n host: ${OAUTH2_HOST, localhost}\n port: ${OAUTH2_PORT, 9000}\n ssl_cert: "" # Optional: path to SSL certificate\n ssl_key: "" # Optional: path to SSL private key\n\nflows:\n # Initialize OAuth2 service\n - name: oauth2_service\n components:\n - component_name: oauth2_auth_service\n component_module: src.components.oauth2_component\n component_config:\n <<: *oauth2_config\n'})}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"oauth2_config.yaml"})}),(0,i.jsx)(n.p,{children:"In the oauth2_config.yaml file, uncomment the authentication provider you want to use.\nNote that the Azure provider is configured as the default option."}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'---\n# OAuth2 Service Configuration\n# This file configures the OAuth2 authentication service that supports multiple providers\n# All providers now use the unified OIDC approach with automatic endpoint discovery\n\n# Enable or disable the OAuth2 service\nenabled: ${OAUTH2_ENABLED:false}\n\n# Development mode - enables insecure transport and relaxed token scope for local development\n# Set OAUTH2_DEV_MODE=true for local development (NEVER use in production!)\ndevelopment_mode: ${OAUTH2_DEV_MODE:false}\n\n# OAuth2 providers configuration\n# All providers now use the unified OIDCProvider with automatic endpoint discovery\nproviders:\n # Google OAuth2 provider\n # google:\n # # OIDC issuer URL - endpoints will be discovered automatically\n # issuer: "https://accounts.google.com"\n # client_id: ${GOOGLE_CLIENT_ID}\n # client_secret: ${GOOGLE_CLIENT_SECRET}\n # redirect_uri: ${GOOGLE_REDIRECT_URI:http://localhost:8080/callback}\n # scope: "openid email profile"\n\n # Azure/Microsoft OAuth2 provider\n azure:\n # Azure OIDC issuer URL includes tenant ID\n issuer: https://login.microsoftonline.com/${AZURE_TENANT_ID}/v2.0\n client_id: ${AZURE_CLIENT_ID}\n client_secret: ${AZURE_CLIENT_SECRET}\n redirect_uri: ${AZURE_REDIRECT_URI:http://localhost:8080/callback}\n scope: "openid email profile offline_access"\n\n # Auth0 OAuth2 provider\n # auth0:\n # # Auth0 issuer URL\n # issuer: ${AUTH0_ISSUER:https://your-domain.auth0.com/}\n # client_id: ${AUTH0_CLIENT_ID}\n # client_secret: ${AUTH0_CLIENT_SECRET}\n # redirect_uri: ${AUTH0_REDIRECT_URI:http://localhost:8080/callback}\n # scope: "openid email profile"\n # # Optional: Auth0 audience for API access\n # audience: ${AUTH0_AUDIENCE:}\n\n # # Okta OAuth2 provider (example)\n # okta:\n # issuer: ${OKTA_ISSUER:https://your-okta-domain.okta.com/oauth2/default}\n # client_id: ${OKTA_CLIENT_ID}\n # client_secret: ${OKTA_CLIENT_SECRET}\n # redirect_uri: ${OKTA_REDIRECT_URI:http://localhost:8080/callback}\n # scope: "openid email profile"\n\n # # Keycloak OAuth2 provider (example)\n # keycloak:\n # issuer: ${KEYCLOAK_ISSUER:https://your-keycloak.com/auth/realms/your-realm}\n # client_id: ${KEYCLOAK_CLIENT_ID}\n # client_secret: ${KEYCLOAK_CLIENT_SECRET}\n # redirect_uri: ${KEYCLOAK_REDIRECT_URI:http://localhost:8080/callback}\n # scope: "openid email profile"\n\n # # Generic OIDC provider (for any standard OIDC-compliant provider)\n # custom_oidc:\n # # Just provide the issuer URL and the service will discover all endpoints\n # issuer: ${CUSTOM_OIDC_ISSUER:https://your-provider.com}\n # client_id: ${CUSTOM_OIDC_CLIENT_ID}\n # client_secret: ${CUSTOM_OIDC_CLIENT_SECRET}\n # redirect_uri: ${CUSTOM_OIDC_REDIRECT_URI:http://localhost:8080/callback}\n # scope: "openid email profile"\n\n# Logging configuration\nlogging:\n level: ${OAUTH2_LOG_LEVEL:INFO}\n\n# Session configuration\nsession:\n # Session timeout in seconds (default: 1 hour)\n timeout: ${OAUTH2_SESSION_TIMEOUT:3600}\n\n# Security configuration\nsecurity:\n # CORS settings\n cors:\n enabled: ${OAUTH2_CORS_ENABLED:true}\n origins: ${OAUTH2_CORS_ORIGINS:*}\n\n # Rate limiting\n rate_limit:\n enabled: ${OAUTH2_RATE_LIMIT_ENABLED:true}\n requests_per_minute: ${OAUTH2_RATE_LIMIT_RPM:60}\n'})})]}),"\n",(0,i.jsx)(n.h2,{id:"running-sam-enterprise-with-sso-enabled",children:"Running SAM Enterprise with SSO enabled"}),"\n",(0,i.jsx)(n.p,{children:"Here is an example of Docker run command with Azure SSO provider for production use case:"}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["You may need to include ",(0,i.jsx)(n.code,{children:"--platform linux/amd64"})," depending on the host machine you\u2019re using."]})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'docker run -itd -p 8000:8000 -p 9000:9000 \\\n -e LLM_SERVICE_API_KEY="<YOUR_LLM_TOKEN>" \\\n -e LLM_SERVICE_ENDPOINT="<YOUR_LLM_SERVICE_ENDPOINT>" \\\n -e LLM_SERVICE_PLANNING_MODEL_NAME="<YOUR_MODEL_NAME>" \\\n -e LLM_SERVICE_GENERAL_MODEL_NAME="<YOUR_MODEL_NAME>" \\\n -e NAMESPACE="<YOUR_NAMESPACE>" \\\n -e SOLACE_DEV_MODE="false" \\\n -e SOLACE_BROKER_URL="<YOUR_BROKER_URL>" \\\n -e SOLACE_BROKER_VPN="<YOUR_BROKER_VPN>" \\\n -e SOLACE_BROKER_USERNAME="<YOUR_BROKER_USERNAME>" \\\n -e SOLACE_BROKER_PASSWORD="<YOUR_BROKER_PASSWORD>" \\\n -e FASTAPI_HOST="0.0.0.0" \\\n -e FASTAPI_PORT="8000" \\\n -e AZURE_TENANT_ID="xxxxxxxxx-xxxxxx-xxxxxxxx-xxxxxxxxxx" \\\n -e AZURE_CLIENT_ID="xxxxxxxxx-xxxxxx-xxxxxxxx-xxxxxxxxxx" \\\n -e AZURE_CLIENT_SECRET="xxxxxxxxx-xxxxxx-xxxxxxxx-xxxxxxxxxx" \\\n -e OAUTH2_ENABLED="true" \\\n -e OAUTH2_LOG_LEVEL="DEBUG" \\\n -e OAUTH2_DEV_MODE="true" \\\n -e OAUTH2_HOST="0.0.0.0" \\\n -e OAUTH2_PORT="9000" \\\n -e FRONTEND_USE_AUTHORIZATION="true" \\\n -e FRONTEND_REDIRECT_URL="http://localhost:8000" \\\n -e FRONTEND_AUTH_LOGIN_URL="http://localhost:8000/api/v1/auth/login" \\\n -e EXTERNAL_AUTH_SERVICE_URL="http://localhost:9000" \\\n -e EXTERNAL_AUTH_PROVIDER="azure" \\\n -e EXTERNAL_AUTH_CALLBACK="http://localhost:8000/api/v1/auth/callback" \\\n -v <YOUR_NAMED_DOCKER_VOLUME>:/app/config/sso_vol/ \\\n --name sam-ent-prod-sso \\\nsolace-agent-mesh-enterprise:<tag> run config/sso_vol/oauth2_server.yaml config/webui_backend.yaml config/a2a_orchestrator.yaml config/a2a_agents.yaml\n'})}),"\n",(0,i.jsxs)(n.p,{children:["You can then access SAM Enterprise UI through ",(0,i.jsx)(n.a,{href:"http://localhost:8000",children:"http://localhost:8000"})]}),"\n",(0,i.jsxs)(t,{children:[(0,i.jsx)("summary",{children:"Configuration Options"}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Specify the hostname and port for the UI running in the docker container. The main UI runs on port 8000 by default. Using 0.0.0.0 as the host allows external access to the container."})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'-e FASTAPI_HOST="0.0.0.0" \\\n-e FASTAPI_PORT="8000" \\ \n'})}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Enable single sign-on processing on the frontend."})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'-e FRONTEND_USE_AUTHORIZATION="true" \\\n'})}),(0,i.jsx)(n.p,{children:(0,i.jsxs)(n.strong,{children:["Specify the main URL of the UI. For instance, this could be ",(0,i.jsx)(n.a,{href:"https://www.example.com",children:"https://www.example.com"})]})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'-e FRONTEND_REDIRECT_URL="http://localhost:8000" \\\n'})}),(0,i.jsx)(n.p,{children:(0,i.jsxs)(n.strong,{children:["Set the login URL used by the main UI. For instance, this could be ",(0,i.jsx)(n.a,{href:"https://www.example.com/api/v1/auth/login",children:"https://www.example.com/api/v1/auth/login"})]})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'-e FRONTEND_AUTH_LOGIN_URL="http://localhost:8000/api/v1/auth/login" \\\n'})}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Enable the OAUTH2 server and set the log level"})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'-e OAUTH2_ENABLED="true" \\\n-e OAUTH2_LOG_LEVEL="DEBUG" \\\n'})}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Specify the hostname and port for the authorization server running in the docker container. Using 0.0.0.0 as the host allows external access to the container."})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'-e OAUTH2_HOST="0.0.0.0" \\\n-e OAUTH2_PORT="9000" \\\n'})}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Specify whether the Oauth2 checks use dev mode. When dev mode is true the following environment variables are added to allow http access and relax the token scope. This MUST be set false in a production environment."})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'-e OAUTH2_DEV_MODE="true" \\\n'})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'OAUTHLIB_RELAX_TOKEN_SCOPE="1"\nOAUTHLIB_INSECURE_TRANSPORT="1"\n'})}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Configure the environment variables for your chosen authentication provider. Refer to the oauth2_config.yaml file to identify the required variables. For example, with Azure set the following"})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'-e AZURE_TENANT_ID="xxxxxxxxx-xxxxxx-xxxxxxxx-xxxxxxxxxx" \\\n-e AZURE_CLIENT_ID="xxxxxxxxx-xxxxxx-xxxxxxxx-xxxxxxxxxx" \\\n-e AZURE_CLIENT_SECRET="xxxxxxxxx-xxxxxx-xxxxxxxx-xxxxxxxxxx" \\\n'})}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Configure the authorization server's public URL (accessible from outside the Docker container) and specify the OAuth2 provider\u2019s name from oauth2_config.yaml (this example uses the azure profile):"})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'-e EXTERNAL_AUTH_SERVICE_URL="http://localhost:9000" \\\n-e EXTERNAL_AUTH_PROVIDER="azure" \\\n'})}),(0,i.jsx)(n.p,{children:(0,i.jsxs)(n.strong,{children:["Lastly, set the callback URL that your auth provider will use to redirect with the auth code. For instance, this could be ",(0,i.jsx)(n.a,{href:"https://www.example.com/api/v1/auth/callback",children:"https://www.example.com/api/v1/auth/callback"})]})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'-e EXTERNAL_AUTH_CALLBACK="http://localhost:8000/api/v1/auth/callback" \\\n'})}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Note that both the main UI and authorization server ports must be mapped to the host machine, as shown in the Docker run command above:"})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"-p 8000:8000 -p 9000:9000 \\\n"})}),(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"The oauth 2 configuration files must be mounted inside the container:"})}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"-v <YOUR_NAMED_DOCKER_VOLUME>:/app/config/sso_vol/ \\\n"})})]})]})}function x(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var o=t(6540);const i={},s=o.createContext(i);function r(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]);
|