solace-agent-mesh 1.3.2__py3-none-any.whl → 1.3.3__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.

Files changed (114) hide show
  1. solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +16 -8
  2. solace_agent_mesh/assets/docs/404.html +3 -3
  3. solace_agent_mesh/assets/docs/assets/js/0e682baa.da822665.js +1 -0
  4. solace_agent_mesh/assets/docs/assets/js/1023fc19.8a8a9309.js +1 -0
  5. solace_agent_mesh/assets/docs/assets/js/1523c6b4.2645ef68.js +1 -0
  6. solace_agent_mesh/assets/docs/assets/js/1c6e87d2.43771adc.js +1 -0
  7. solace_agent_mesh/assets/docs/assets/js/2a9cab12.2afaee76.js +1 -0
  8. solace_agent_mesh/assets/docs/assets/js/332e10b5.f7629851.js +1 -0
  9. solace_agent_mesh/assets/docs/assets/js/3d406171.5560fdf9.js +1 -0
  10. solace_agent_mesh/assets/docs/assets/js/42b3f8d8.3f34bf76.js +1 -0
  11. solace_agent_mesh/assets/docs/assets/js/442a8107.b5c2532a.js +1 -0
  12. solace_agent_mesh/assets/docs/assets/js/483cef9a.8d318c2f.js +1 -0
  13. solace_agent_mesh/assets/docs/assets/js/55f47984.bcd00a86.js +1 -0
  14. solace_agent_mesh/assets/docs/assets/js/5b4258a4.dff11eca.js +1 -0
  15. solace_agent_mesh/assets/docs/assets/js/664b740a.ba305a89.js +1 -0
  16. solace_agent_mesh/assets/docs/assets/js/75384d09.abdf9cf9.js +1 -0
  17. solace_agent_mesh/assets/docs/assets/js/768e31b0.9abcdc48.js +1 -0
  18. solace_agent_mesh/assets/docs/assets/js/945fb41e.abf2be91.js +1 -0
  19. solace_agent_mesh/assets/docs/assets/js/9a09e75d.5a319fd4.js +1 -0
  20. solace_agent_mesh/assets/docs/assets/js/9eff14a2.d62aad71.js +1 -0
  21. solace_agent_mesh/assets/docs/assets/js/a3a92b25.1d029b81.js +1 -0
  22. solace_agent_mesh/assets/docs/assets/js/{aba87c2f.071e2d94.js → aba87c2f.4ddf32f2.js} +1 -1
  23. solace_agent_mesh/assets/docs/assets/js/ae0e903d.abca774a.js +1 -0
  24. solace_agent_mesh/assets/docs/assets/js/ae4415af.24cdc514.js +1 -0
  25. solace_agent_mesh/assets/docs/assets/js/bac0be12.27ee2c26.js +1 -0
  26. solace_agent_mesh/assets/docs/assets/js/c2c06897.87cb1f47.js +1 -0
  27. solace_agent_mesh/assets/docs/assets/js/c835a94d.ce21f0bf.js +1 -0
  28. solace_agent_mesh/assets/docs/assets/js/cc969b05.feef7dcc.js +1 -0
  29. solace_agent_mesh/assets/docs/assets/js/cd3d4052.a19e7d78.js +1 -0
  30. solace_agent_mesh/assets/docs/assets/js/{cee5d587.f5b73ca1.js → cee5d587.f1e1ca86.js} +1 -1
  31. solace_agent_mesh/assets/docs/assets/js/f284c35a.cad4dbf2.js +1 -0
  32. solace_agent_mesh/assets/docs/assets/js/f897a61a.bc634a3e.js +1 -0
  33. solace_agent_mesh/assets/docs/assets/js/{main.4adc477a.js → main.e82b32e6.js} +2 -2
  34. solace_agent_mesh/assets/docs/assets/js/runtime~main.aad1f874.js +1 -0
  35. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +4 -4
  36. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +5 -5
  37. 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
  38. solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html +6 -6
  39. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +6 -6
  40. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +3 -3
  41. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +18 -18
  42. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +3 -3
  43. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +3 -3
  44. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +10 -10
  45. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +3 -3
  47. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +3 -3
  48. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +7 -7
  49. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +3 -3
  50. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +9 -9
  51. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +6 -6
  52. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +7 -7
  53. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +23 -23
  54. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +5 -5
  55. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +5 -5
  56. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
  57. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +9 -9
  58. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +10 -10
  59. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +8 -8
  60. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +6 -6
  61. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +9 -9
  62. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +3 -3
  63. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +5 -5
  64. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +5 -5
  65. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +3 -3
  66. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +5 -5
  67. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +18 -18
  68. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +7 -7
  69. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +8 -8
  70. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +10 -10
  71. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +3 -3
  72. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
  73. solace_agent_mesh/assets/docs/lunr-index-1757873594308.json +1 -0
  74. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  75. solace_agent_mesh/assets/docs/search-doc-1757873594308.json +1 -0
  76. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  77. solace_agent_mesh/cli/__init__.py +1 -1
  78. {solace_agent_mesh-1.3.2.dist-info → solace_agent_mesh-1.3.3.dist-info}/METADATA +1 -1
  79. {solace_agent_mesh-1.3.2.dist-info → solace_agent_mesh-1.3.3.dist-info}/RECORD +83 -83
  80. solace_agent_mesh/assets/docs/assets/js/0e682baa.b3bbde9a.js +0 -1
  81. solace_agent_mesh/assets/docs/assets/js/1023fc19.364235d5.js +0 -1
  82. solace_agent_mesh/assets/docs/assets/js/1523c6b4.1b0ec6f9.js +0 -1
  83. solace_agent_mesh/assets/docs/assets/js/1c6e87d2.a8c5ce5a.js +0 -1
  84. solace_agent_mesh/assets/docs/assets/js/2a9cab12.8909df92.js +0 -1
  85. solace_agent_mesh/assets/docs/assets/js/332e10b5.7a103f42.js +0 -1
  86. solace_agent_mesh/assets/docs/assets/js/3d406171.0b9eeed1.js +0 -1
  87. solace_agent_mesh/assets/docs/assets/js/42b3f8d8.d97b8e94.js +0 -1
  88. solace_agent_mesh/assets/docs/assets/js/442a8107.b3159bb2.js +0 -1
  89. solace_agent_mesh/assets/docs/assets/js/483cef9a.03d5dceb.js +0 -1
  90. solace_agent_mesh/assets/docs/assets/js/55f47984.cf3781c4.js +0 -1
  91. solace_agent_mesh/assets/docs/assets/js/5b4258a4.0d080cd9.js +0 -1
  92. solace_agent_mesh/assets/docs/assets/js/664b740a.1b744a32.js +0 -1
  93. solace_agent_mesh/assets/docs/assets/js/75384d09.c193a8f0.js +0 -1
  94. solace_agent_mesh/assets/docs/assets/js/768e31b0.8b51cd70.js +0 -1
  95. solace_agent_mesh/assets/docs/assets/js/945fb41e.c63791d1.js +0 -1
  96. solace_agent_mesh/assets/docs/assets/js/9a09e75d.d6607c56.js +0 -1
  97. solace_agent_mesh/assets/docs/assets/js/9eff14a2.472b0310.js +0 -1
  98. solace_agent_mesh/assets/docs/assets/js/a3a92b25.4b7fa6a2.js +0 -1
  99. solace_agent_mesh/assets/docs/assets/js/ae0e903d.4d8dda10.js +0 -1
  100. solace_agent_mesh/assets/docs/assets/js/ae4415af.7a2f0bbf.js +0 -1
  101. solace_agent_mesh/assets/docs/assets/js/bac0be12.f50d9bac.js +0 -1
  102. solace_agent_mesh/assets/docs/assets/js/c2c06897.587b4af5.js +0 -1
  103. solace_agent_mesh/assets/docs/assets/js/c835a94d.146e3186.js +0 -1
  104. solace_agent_mesh/assets/docs/assets/js/cc969b05.bd3e0d6c.js +0 -1
  105. solace_agent_mesh/assets/docs/assets/js/cd3d4052.b6535013.js +0 -1
  106. solace_agent_mesh/assets/docs/assets/js/f284c35a.7334119c.js +0 -1
  107. solace_agent_mesh/assets/docs/assets/js/f897a61a.0aa29dbb.js +0 -1
  108. solace_agent_mesh/assets/docs/assets/js/runtime~main.cf0229ea.js +0 -1
  109. solace_agent_mesh/assets/docs/lunr-index-1757704179464.json +0 -1
  110. solace_agent_mesh/assets/docs/search-doc-1757704179464.json +0 -1
  111. /solace_agent_mesh/assets/docs/assets/js/{main.4adc477a.js.LICENSE.txt → main.e82b32e6.js.LICENSE.txt} +0 -0
  112. {solace_agent_mesh-1.3.2.dist-info → solace_agent_mesh-1.3.3.dist-info}/WHEEL +0 -0
  113. {solace_agent_mesh-1.3.2.dist-info → solace_agent_mesh-1.3.3.dist-info}/entry_points.txt +0 -0
  114. {solace_agent_mesh-1.3.2.dist-info → solace_agent_mesh-1.3.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1 @@
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 is a powerful platform that enables you to create intelligent agents that can communicate with each other and perform complex tasks. At its core, Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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: Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh'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 Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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)}}}]);
@@ -0,0 +1 @@
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 Solace Agent Mesh'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 Solace Agent Mesh 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 Solace Agent Mesh 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 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 Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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 Solace Agent Mesh 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)}}}]);
@@ -0,0 +1 @@
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 Solace Agent Mesh Enterprise with SSO enabled",id:"running-solace-agent-mesh-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-solace-agent-mesh-enterprise-with-sso-enabled",children:"Running Solace Agent Mesh 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 Solace Agent Mesh 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)}}}]);
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[5627],{5232:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>_,frontMatter:()=>r,metadata:()=>a,toc:()=>c});const a=JSON.parse('{"id":"documentation/user-guide/create-gateways","title":"Create Gateways","description":"Gateways in Solace Agent Mesh serve as bridges between external systems and the A2A (Agent-to-Agent) ecosystem. They enable your agents to receive information from and send responses to diverse external platforms like chat systems, web applications, IoT devices, APIs, and file systems.","source":"@site/docs/documentation/user-guide/create-gateways.md","sourceDirName":"documentation/user-guide","slug":"/documentation/user-guide/create-gateways","permalink":"/solace-agent-mesh/docs/documentation/user-guide/create-gateways","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/user-guide/create-gateways.md","tags":[],"version":"current","sidebarPosition":40,"frontMatter":{"title":"Create Gateways","sidebar_position":40},"sidebar":"docSidebar","previous":{"title":"Creating Python Tools","permalink":"/solace-agent-mesh/docs/documentation/user-guide/creating-python-tools"},"next":{"title":"Creating Service Providers","permalink":"/solace-agent-mesh/docs/documentation/user-guide/creating-service-providers"}}');var i=t(4848),s=t(8453);const r={title:"Create Gateways",sidebar_position:40},o="Create Gateways",l={},c=[{value:"What Are Gateways?",id:"what-are-gateways",level:2},{value:"Quick Start: Creating Your First Gateway",id:"quick-start-creating-your-first-gateway",level:2},{value:"CLI Options",id:"cli-options",level:3},{value:"Gateway Architecture",id:"gateway-architecture",level:2},{value:"Gateway App",id:"gateway-app",level:3},{value:"Gateway Component",id:"gateway-component",level:3},{value:"Step-by-Step Tutorial",id:"step-by-step-tutorial",level:2},{value:"Step 1: Generate the Gateway Structure",id:"step-1-generate-the-gateway-structure",level:3},{value:"Step 2: Define Configuration Schema",id:"step-2-define-configuration-schema",level:3},{value:"Step 3: Implement Core Logic",id:"step-3-implement-core-logic",level:3},{value:"Step 4: Configure the Gateway",id:"step-4-configure-the-gateway",level:3},{value:"Step 5: Install Dependencies",id:"step-5-install-dependencies",level:3},{value:"Step 6: Run Your Gateway",id:"step-6-run-your-gateway",level:3},{value:"Advanced Gateway Patterns",id:"advanced-gateway-patterns",level:2},{value:"Authentication and Authorization",id:"authentication-and-authorization",level:3},{value:"File Handling with Artifacts",id:"file-handling-with-artifacts",level:3},{value:"Streaming Responses",id:"streaming-responses",level:3},{value:"Error Handling and Retry Logic",id:"error-handling-and-retry-logic",level:3},{value:"Best Practices",id:"best-practices",level:2},{value:"1. Configuration Management",id:"1-configuration-management",level:3},{value:"2. Error Handling",id:"2-error-handling",level:3},{value:"3. Security",id:"3-security",level:3},{value:"4. Performance",id:"4-performance",level:3},{value:"5. Monitoring and Logging",id:"5-monitoring-and-logging",level:3},{value:"Common Gateway Patterns",id:"common-gateway-patterns",level:2},{value:"HTTP/REST API Gateway",id:"httprest-api-gateway",level:3},{value:"WebSocket Gateway",id:"websocket-gateway",level:3},{value:"Message Queue Gateway",id:"message-queue-gateway",level:3},{value:"Packaging as a Plugin",id:"packaging-as-a-plugin",level:2},{value:"1. Create Plugin Structure",id:"1-create-plugin-structure",level:3},{value:"2. Configure <code>pyproject.toml</code>",id:"2-configure-pyprojecttoml",level:3},{value:"3. Build and Install",id:"3-build-and-install",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2},{value:"Common Issues",id:"common-issues",level:3},{value:"Gateway Fails to Start",id:"gateway-fails-to-start",level:4},{value:"Tasks Not Reaching Agents",id:"tasks-not-reaching-agents",level:4},{value:"Authentication Failures",id:"authentication-failures",level:4},{value:"File/Artifact Issues",id:"fileartifact-issues",level:4},{value:"Debugging Tips",id:"debugging-tips",level:3}];function d(e){const n={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,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"create-gateways",children:"Create Gateways"})}),"\n",(0,i.jsx)(n.p,{children:"Gateways in Solace Agent Mesh serve as bridges between external systems and the A2A (Agent-to-Agent) ecosystem. They enable your agents to receive information from and send responses to diverse external platforms like chat systems, web applications, IoT devices, APIs, and file systems."}),"\n",(0,i.jsx)(n.p,{children:"This guide walks you through the steps of creating custom gateways, from basic concepts to advanced implementations."}),"\n",(0,i.jsx)(n.h2,{id:"what-are-gateways",children:"What Are Gateways?"}),"\n",(0,i.jsx)(n.p,{children:"A gateway acts as a translator and coordinator that:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Receives"})," events, messages, or data from external systems"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Authenticates"})," and authorizes external interactions"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Translates"})," external data into standardized A2A ",(0,i.jsx)(n.code,{children:"Task"})," format"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Submits"})," tasks to target A2A agents for processing"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Receives"})," responses and status updates from agents"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Translates"})," A2A responses back to external system format"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Sends"})," results back to the originating external system"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"quick-start-creating-your-first-gateway",children:"Quick Start: Creating Your First Gateway"}),"\n",(0,i.jsxs)(n.p,{children:["You can create a gateway directly using the Solace Agent Mesh CLI ",(0,i.jsx)(n.code,{children:"sam add gateway"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam add gateway my-custom-gateway\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 gateway structure"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"cli-options",children:"CLI Options"}),"\n",(0,i.jsx)(n.p,{children:"You can customize the gateway creation with these options:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'sam add gateway my-gateway \\\n --namespace "myorg/dev" \\\n --gateway-id "my-custom-gw-id" \\\n --artifact-service-type "filesystem" \\\n --artifact-service-base-path "var/data/my-gateway-artifacts" \\\n --system-purpose "This gateway processes external data feeds" \\\n --response-format "Agents should respond with structured JSON"\n'})}),"\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 gateway --help\n"})}),"\n",(0,i.jsx)(n.h2,{id:"gateway-architecture",children:"Gateway Architecture"}),"\n",(0,i.jsx)(n.p,{children:"Every Solace Agent Mesh gateway consists of two main components:"}),"\n",(0,i.jsx)(n.h3,{id:"gateway-app",children:"Gateway App"}),"\n",(0,i.jsxs)(n.p,{children:["Gateway App (",(0,i.jsx)(n.code,{children:"app.py"}),"):"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Defines configuration schema"}),"\n",(0,i.jsx)(n.li,{children:"Manages gateway-level settings"}),"\n",(0,i.jsx)(n.li,{children:"Links to the gateway component"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"gateway-component",children:"Gateway Component"}),"\n",(0,i.jsxs)(n.p,{children:["Gateway Component (",(0,i.jsx)(n.code,{children:"component.py"}),"):"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Contains the core business logic"}),"\n",(0,i.jsx)(n.li,{children:"Handles external system integration"}),"\n",(0,i.jsx)(n.li,{children:"Implements required abstract methods"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"step-by-step-tutorial",children:"Step-by-Step Tutorial"}),"\n",(0,i.jsxs)(n.p,{children:["Let's create a practical example, ",(0,i.jsx)(n.strong,{children:"Directory Monitor Gateway"}),", a gateway that monitors a directory for new files and sends them to agents for processing."]}),"\n",(0,i.jsxs)(n.p,{children:["You can create a gateway using either ",(0,i.jsx)(n.code,{children:"sam add gateway <your_gateway_name>"})," command directly or ",(0,i.jsx)(n.code,{children:"sam plugin create <your_gateway_plugin_name> --type gateway"})," command as gateway plugin."]}),"\n",(0,i.jsxs)(n.admonition,{title:"Gateway as plugin",type:"tip",children:[(0,i.jsx)(n.p,{children:"Gateways can also be implemented as plugins. This allows you to easily package your gateway logic and reuse it across different projects."}),(0,i.jsxs)(n.p,{children:["To create a plugin of type gateway, use the ",(0,i.jsx)(n.code,{children:"sam plugin create <your_gateway_plugin_name> --type gateway"})," command."]}),(0,i.jsx)(n.p,{children:"For a complete list of options, run:"}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam plugin create --help\n"})}),(0,i.jsxs)(n.p,{children:["To create a gateway instance based on a plugin, use the ",(0,i.jsx)(n.code,{children:"sam plugin add <your_gateway_name> --plugin <your_gateway_plugin>"})," command."]}),(0,i.jsx)(n.p,{children:"For a complete list of options, run:"}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam plugin add --help\n"})}),(0,i.jsx)(n.p,{children:"Although the specific directory structure may differ from standalone gateways, the core concepts remain the same. The core files remain the same: app.py, component.py, and the YAML configuration file."})]}),"\n",(0,i.jsx)(n.h3,{id:"step-1-generate-the-gateway-structure",children:"Step 1: Generate the Gateway Structure"}),"\n",(0,i.jsxs)(n.p,{children:["This tutorial shows you how to create a new gateway with the ",(0,i.jsx)(n.code,{children:"sam add gateway"})," command."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam add gateway dir-monitor\n"})}),"\n",(0,i.jsx)(n.p,{children:"This creates:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"configs/gateways/dir_monitor_config.yaml"})," - Configuration file"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"src/dir_monitor/app.py"})," - Gateway app class"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"src/dir_monitor/component.py"})," - Gateway component class"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"step-2-define-configuration-schema",children:"Step 2: Define Configuration Schema"}),"\n",(0,i.jsxs)(n.p,{children:["Define Configuration Schema (",(0,i.jsx)(n.code,{children:"app.py"}),")"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'# src/dir_monitor/app.py\nfrom typing import Any, Dict, List, Type\nfrom solace_ai_connector.common.log import log\nfrom solace_agent_mesh.gateway.base.app import BaseGatewayApp\nfrom solace_agent_mesh.gateway.base.component import BaseGatewayComponent\nfrom .component import DirMonitorGatewayComponent\n\n# Module info required by SAC\ninfo = {\n "class_name": "DirMonitorGatewayApp",\n "description": "Custom App class for the A2A DirMonitor Gateway.",\n}\n\nclass DirMonitorGatewayApp(BaseGatewayApp):\n """\n Directory Monitor Gateway App\n Extends BaseGatewayApp with directory monitoring specific configuration.\n """\n\n # Define gateway-specific configuration parameters\n SPECIFIC_APP_SCHEMA_PARAMS: List[Dict[str, Any]] = [\n {\n "name": "directory_path",\n "required": True,\n "type": "string",\n "description": "The directory path to monitor for changes.",\n },\n {\n "name": "target_agent_name",\n "required": False,\n "type": "string",\n "default": "OrchestratorAgent",\n "description": "The A2A agent to send tasks to.",\n },\n {\n "name": "default_user_identity",\n "required": False,\n "type": "string",\n "default": "dir_monitor_user",\n "description": "Default user identity for A2A tasks.",\n },\n {\n "name": "error_directory_path",\n "required": True,\n "type": "string",\n "description": "Directory to move files if processing fails.",\n },\n ]\n\n def __init__(self, app_info: Dict[str, Any], **kwargs):\n log_prefix = app_info.get("name", "DirMonitorGatewayApp")\n log.info("[%s] Initializing Directory Monitor Gateway App...", log_prefix)\n super().__init__(app_info=app_info, **kwargs)\n log.info("[%s] Directory Monitor Gateway App initialized.", self.name)\n\n def _get_gateway_component_class(self) -> Type[BaseGatewayComponent]:\n """Returns the gateway component class for this app."""\n return DirMonitorGatewayComponent\n'})}),"\n",(0,i.jsx)(n.h3,{id:"step-3-implement-core-logic",children:"Step 3: Implement Core Logic"}),"\n",(0,i.jsxs)(n.p,{children:["Implement Core Logic (",(0,i.jsx)(n.code,{children:"component.py"}),")"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'# src/dir_monitor/component.py\nimport asyncio\nimport os\nimport shutil\nimport mimetypes\nimport threading\nfrom typing import Any, Dict, List, Optional, Tuple, Union\nfrom datetime import datetime, timezone\n\nfrom solace_ai_connector.common.log import log\n\n# Import watchdog for file system monitoring\ntry:\n from watchdog.observers import Observer\n from watchdog.events import FileSystemEventHandler\n WATCHDOG_AVAILABLE = True\nexcept ImportError:\n WATCHDOG_AVAILABLE = False\n Observer = None\n FileSystemEventHandler = None\n\nfrom solace_agent_mesh.gateway.base.component import BaseGatewayComponent\nfrom solace_agent_mesh.common.types import (\n Part as A2APart,\n TextPart,\n FilePart,\n Task,\n TaskStatusUpdateEvent,\n TaskArtifactUpdateEvent,\n JSONRPCError,\n FileContent,\n)\nfrom solace_agent_mesh.agent.utils.artifact_helpers import save_artifact_with_metadata\n\n# Component info\ninfo = {\n "class_name": "DirMonitorGatewayComponent",\n "description": "Monitors directories for new files and processes them via A2A agents.",\n}\n\nclass DirMonitorGatewayComponent(BaseGatewayComponent):\n """\n Directory Monitor Gateway Component\n Watches a directory and creates A2A tasks for new files.\n """\n\n def __init__(self, **kwargs: Any):\n super().__init__(**kwargs)\n log.info("%s Initializing Directory Monitor Gateway Component...", self.log_identifier)\n\n # Check if watchdog is available\n if not WATCHDOG_AVAILABLE:\n log.error("%s Watchdog library not found. Install with: pip install watchdog", \n self.log_identifier)\n raise ImportError("Watchdog library required for directory monitoring")\n\n # Load configuration\n try:\n self.directory_path = self.get_config("directory_path")\n self.target_agent_name = self.get_config("target_agent_name", "OrchestratorAgent")\n self.default_user_identity_id = self.get_config("default_user_identity", "dir_monitor_user")\n self.error_directory_path = self.get_config("error_directory_path")\n\n # Validate directories\n if not os.path.isdir(self.directory_path):\n raise ValueError(f"Monitor directory not found: {self.directory_path}")\n \n os.makedirs(self.error_directory_path, exist_ok=True)\n log.info("%s Monitoring: %s, Error dir: %s", \n self.log_identifier, self.directory_path, self.error_directory_path)\n\n except Exception as e:\n log.error("%s Configuration error: %s", self.log_identifier, e)\n raise\n\n # Initialize monitoring components\n self.observer: Optional[Observer] = None\n self.watchdog_thread: Optional[threading.Thread] = None\n\n log.info("%s Directory Monitor Gateway Component initialized.", self.log_identifier)\n\n class DirWatchEventHandler(FileSystemEventHandler):\n """Handles file system events from Watchdog."""\n \n def __init__(self, component_ref: \'DirMonitorGatewayComponent\'):\n super().__init__()\n self.component_ref = component_ref\n self.log_identifier = f"{component_ref.log_identifier}[FileHandler]"\n\n def on_created(self, event):\n if event.is_directory:\n return\n\n file_path = event.src_path\n log.info("%s New file detected: %s", self.log_identifier, file_path)\n\n # Bridge to async loop\n if self.component_ref.async_loop and self.component_ref.async_loop.is_running():\n asyncio.run_coroutine_threadsafe(\n self.component_ref._process_new_file(file_path),\n self.component_ref.async_loop\n )\n else:\n log.error("%s Async loop not available for file: %s", \n self.log_identifier, file_path)\n\n def generate_uuid(self) -> str:\n """Generate a unique identifier."""\n import uuid\n return str(uuid.uuid4())\n\n def _start_listener(self) -> None:\n """Start the directory monitoring listener."""\n log_id_prefix = f"{self.log_identifier}[StartListener]"\n log.info("%s Starting directory monitor for: %s", log_id_prefix, self.directory_path)\n\n if not WATCHDOG_AVAILABLE:\n log.error("%s Watchdog not available", log_id_prefix)\n self.stop_signal.set()\n return\n\n # Set up file system observer\n self.observer = Observer()\n event_handler = self.DirWatchEventHandler(self)\n self.observer.schedule(event_handler, self.directory_path, recursive=False)\n\n # Start observer in separate thread\n self.watchdog_thread = threading.Thread(\n target=self._run_observer,\n name=f"{self.name}_WatchdogThread",\n daemon=True\n )\n self.watchdog_thread.start()\n log.info("%s Directory monitor started", log_id_prefix)\n\n def _run_observer(self):\n """Run the watchdog observer."""\n if not self.observer:\n return\n \n log_id_prefix = f"{self.log_identifier}[Observer]"\n try:\n log.info("%s Starting file system observer...", log_id_prefix)\n self.observer.start()\n \n # Wait for stop signal\n while not self.stop_signal.is_set() and self.observer.is_alive():\n self.stop_signal.wait(timeout=1)\n \n log.info("%s Observer loop exiting", log_id_prefix)\n except Exception as e:\n log.exception("%s Observer error: %s", log_id_prefix, e)\n self.stop_signal.set()\n finally:\n if self.observer.is_alive():\n self.observer.stop()\n self.observer.join()\n log.info("%s Observer stopped", log_id_prefix)\n\n def _stop_listener(self) -> None:\n """Stop the directory monitoring listener."""\n log_id_prefix = f"{self.log_identifier}[StopListener]"\n log.info("%s Stopping directory monitor...", log_id_prefix)\n \n if self.observer and self.observer.is_alive():\n log.info("%s Stopping observer...", log_id_prefix)\n self.observer.stop()\n \n if self.watchdog_thread and self.watchdog_thread.is_alive():\n log.info("%s Joining observer thread...", log_id_prefix)\n self.watchdog_thread.join(timeout=5)\n if self.watchdog_thread.is_alive():\n log.warning("%s Observer thread did not join cleanly", log_id_prefix)\n \n log.info("%s Directory monitor stopped", log_id_prefix)\n\n async def _process_new_file(self, file_path: str):\n """Process a newly detected file."""\n log_id_prefix = f"{self.log_identifier}[ProcessFile:{os.path.basename(file_path)}]"\n log.info("%s Processing new file: %s", log_id_prefix, file_path)\n \n error_context = {\n "file_path": file_path,\n "a2a_session_id": f"dir_monitor-error-{self.generate_uuid()}"\n }\n\n try:\n # Step 1: Authenticate and enrich user\n user_identity_profile = await self.authenticate_and_enrich_user(file_path)\n if not user_identity_profile:\n log.error("%s Authentication failed for file: %s", log_id_prefix, file_path)\n error_obj = JSONRPCError(code=-32001, message="Authentication failed")\n await self._send_error_to_external(error_context, error_obj)\n return\n\n # Step 2: Translate external input to A2A format\n target_agent_name, a2a_parts, external_request_context = await self._translate_external_input(\n file_path, user_identity_profile\n )\n\n if not target_agent_name or not a2a_parts:\n log.error("%s Failed to translate file to A2A task: %s", log_id_prefix, file_path)\n error_obj = JSONRPCError(code=-32002, message="Failed to translate file to A2A task")\n final_error_context = {**error_context, **external_request_context}\n await self._send_error_to_external(final_error_context, error_obj)\n return\n\n # Step 3: Submit A2A task\n log.info("%s Submitting A2A task for file: %s to agent: %s", \n log_id_prefix, file_path, target_agent_name)\n await self.submit_a2a_task(\n target_agent_name=target_agent_name,\n a2a_parts=a2a_parts,\n external_request_context=external_request_context,\n user_identity=user_identity_profile\n )\n log.info("%s A2A task submitted for file: %s", log_id_prefix, file_path)\n\n except FileNotFoundError:\n log.error("%s File not found during processing: %s", log_id_prefix, file_path)\n except Exception as e:\n log.exception("%s Unexpected error processing file %s: %s", log_id_prefix, file_path, e)\n error_obj = JSONRPCError(code=-32000, message=f"Unexpected error: {e}")\n await self._send_error_to_external(error_context, error_obj)\n\n async def _extract_initial_claims(self, external_event_data: Any) -> Optional[Dict[str, Any]]:\n """Extract user identity claims from file event."""\n file_path = str(external_event_data)\n log_id_prefix = f"{self.log_identifier}[ExtractClaims:{os.path.basename(file_path)}]"\n \n claims = {\n "id": self.default_user_identity_id,\n "source": "dir_monitor",\n "file_path": file_path\n }\n log.debug("%s Extracted claims for file %s: %s", log_id_prefix, file_path, claims)\n return claims\n\n async def _translate_external_input(\n self, external_event_data: Any, authenticated_user_identity: Dict[str, Any]\n ) -> Tuple[Optional[str], List[A2APart], Dict[str, Any]]:\n """Translate file event to A2A task format."""\n file_path = str(external_event_data)\n log_id_prefix = f"{self.log_identifier}[TranslateInput:{os.path.basename(file_path)}]"\n\n user_id_for_a2a = authenticated_user_identity.get("id", self.default_user_identity_id)\n a2a_session_id = f"dir_monitor-session-{self.generate_uuid()}"\n \n # Prepare external request context\n external_request_context: Dict[str, Any] = {\n "file_path": file_path,\n "user_id_for_a2a": user_id_for_a2a,\n "app_name_for_artifacts": self.gateway_id,\n "user_id_for_artifacts": user_id_for_a2a,\n "a2a_session_id": a2a_session_id,\n }\n a2a_parts: List[A2APart] = []\n\n try:\n # Check if file exists\n if not os.path.exists(file_path):\n log.error("%s File does not exist: %s", log_id_prefix, file_path)\n raise FileNotFoundError(f"File not found: {file_path}")\n\n # Read file content\n with open(file_path, "rb") as f:\n content_bytes = f.read()\n \n # Determine MIME type\n mime_type, _ = mimetypes.guess_type(file_path)\n if mime_type is None:\n mime_type = "application/octet-stream"\n\n # Save file as artifact\n if not self.shared_artifact_service:\n log.error("%s Artifact service not available for file: %s", \n log_id_prefix, os.path.basename(file_path))\n return None, [], external_request_context\n\n artifact_metadata = {\n "source": "dir_monitor_gateway",\n "original_filename": os.path.basename(file_path),\n "detected_mime_type": mime_type,\n "processing_timestamp_utc": datetime.now(timezone.utc).isoformat(),\n }\n\n log.debug("%s Saving artifact for file: %s", log_id_prefix, file_path)\n save_result = await save_artifact_with_metadata(\n artifact_service=self.shared_artifact_service,\n app_name=self.gateway_id,\n user_id=str(user_id_for_a2a),\n session_id=a2a_session_id,\n filename=os.path.basename(file_path),\n content_bytes=content_bytes,\n mime_type=mime_type,\n metadata_dict=artifact_metadata,\n timestamp=datetime.now(timezone.utc),\n )\n\n if save_result["status"] not in ["success", "partial_success"]:\n log.error("%s Failed to save file as artifact: %s", \n log_id_prefix, save_result.get("message"))\n return None, [], external_request_context\n\n # Create artifact URI\n data_version = save_result.get("data_version", 0)\n artifact_uri = f"artifact://{self.gateway_id}/{str(user_id_for_a2a)}/{a2a_session_id}/{os.path.basename(file_path)}?version={data_version}"\n \n log.info("%s Saved file as artifact: %s", log_id_prefix, artifact_uri)\n\n # Create A2A parts\n file_content_obj = FileContent(\n name=os.path.basename(file_path),\n uri=artifact_uri,\n mimeType=mime_type\n )\n a2a_parts.append(FilePart(file=file_content_obj))\n a2a_parts.append(TextPart(\n text=f"Please analyze and summarize the content of: {os.path.basename(file_path)}"\n ))\n\n log.info("%s Successfully translated file %s into A2A parts", log_id_prefix, file_path)\n return self.target_agent_name, a2a_parts, external_request_context\n\n except Exception as e:\n log.exception("%s Error translating file %s: %s", log_id_prefix, file_path, e)\n return None, [], external_request_context\n\n async def _send_final_response_to_external(\n self, external_request_context: Dict[str, Any], task_data: Task\n ) -> None:\n """Handle final response from A2A agent."""\n log_id_prefix = f"{self.log_identifier}[SendFinalResponse]"\n file_path = external_request_context.get("file_path", "Unknown file")\n task_id = task_data.id\n\n # Extract summary from response\n summary_text = "Summary not available."\n if task_data.status and task_data.status.message and task_data.status.message.parts:\n for part in task_data.status.message.parts:\n if isinstance(part, TextPart):\n summary_text = part.text\n break\n \n log.info("%s Task %s completed for file \'%s\'. Status: %s", \n log_id_prefix, task_id, os.path.basename(file_path), \n task_data.status.state if task_data.status else "Unknown")\n log.info("%s Summary: %s", log_id_prefix, summary_text[:200] + "..." if len(summary_text) > 200 else summary_text)\n\n async def _send_error_to_external(\n self, external_request_context: Dict[str, Any], error_data: JSONRPCError\n ) -> None:\n """Handle errors by moving files to error directory."""\n log_id_prefix = f"{self.log_identifier}[SendError]"\n file_path = external_request_context.get("file_path")\n \n log.error("%s A2A Error for file \'%s\'. Code: %s, Message: %s",\n log_id_prefix, \n os.path.basename(file_path) if file_path else "Unknown file",\n error_data.code, error_data.message)\n\n # Move problematic file to error directory\n if file_path and os.path.exists(file_path):\n try:\n os.makedirs(self.error_directory_path, exist_ok=True)\n base_name = os.path.basename(file_path)\n error_file_path = os.path.join(self.error_directory_path, base_name)\n \n # Handle filename conflicts\n counter = 0\n while os.path.exists(error_file_path):\n counter += 1\n name, ext = os.path.splitext(base_name)\n error_file_path = os.path.join(self.error_directory_path, f"{name}_error_{counter}{ext}")\n\n shutil.move(file_path, error_file_path)\n log.info("%s Moved problematic file %s to %s", log_id_prefix, file_path, error_file_path)\n except Exception as e:\n log.exception("%s Failed to move file %s to error directory: %s",\n log_id_prefix, file_path, e)\n\n async def _send_update_to_external(\n self,\n external_request_context: Dict[str, Any],\n event_data: Union[TaskStatusUpdateEvent, TaskArtifactUpdateEvent],\n is_final_chunk_of_update: bool,\n ) -> None:\n """Handle intermediate updates (optional for this gateway)."""\n log_id_prefix = f"{self.log_identifier}[SendUpdate]"\n task_id = event_data.id\n file_path = external_request_context.get("file_path", "Unknown file")\n \n log.debug("%s Received update for task %s (file %s). Updates not processed by this gateway.",\n log_id_prefix, task_id, os.path.basename(file_path))\n\n def cleanup(self):\n """Clean up resources."""\n log.info("%s Cleaning up Directory Monitor Gateway Component...", self.log_identifier)\n super().cleanup()\n log.info("%s Directory Monitor Gateway Component cleanup finished.", self.log_identifier)\n'})}),"\n",(0,i.jsx)(n.h3,{id:"step-4-configure-the-gateway",children:"Step 4: Configure the Gateway"}),"\n",(0,i.jsxs)(n.p,{children:["Configure the Gateway (",(0,i.jsx)(n.code,{children:"dir_monitor_config.yaml"}),")"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# configs/gateways/dir_monitor_config.yaml\nlog:\n stdout_log_level: INFO\n log_file_level: DEBUG\n log_file: "dir_monitor_gateway.log"\n\n!include ../shared_config.yaml\n\napps:\n - name: dir_monitor_gateway_app\n app_base_path: .\n app_module: src.dir_monitor.app\n\n broker:\n <<: *broker_connection\n\n app_config:\n namespace: ${NAMESPACE}\n gateway_id: dir-monitor-gateway\n \n # Artifact service configuration\n artifact_service: *default_artifact_service\n\n # Authorization service\n authorization_service:\n type: "none"\n\n # System purpose for A2A context\n system_purpose: >\n This system monitors directories for new files and processes them automatically.\n Analyze and summarize file contents. Always provide useful insights about the files.\n Your external name is Directory Monitor Agent.\n\n response_format: >\n Responses should be clear, concise, and professionally formatted.\n Provide structured analysis of file contents in Markdown format.\n\n # Gateway-specific configuration\n directory_path: /path/to/monitor/directory\n error_directory_path: /path/to/error/directory\n target_agent_name: "OrchestratorAgent"\n default_user_identity: "dir_monitor_system"\n'})}),"\n",(0,i.jsx)(n.h3,{id:"step-5-install-dependencies",children:"Step 5: Install Dependencies"}),"\n",(0,i.jsx)(n.p,{children:"Add required dependencies to your project:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"pip install watchdog\n"})}),"\n",(0,i.jsx)(n.h3,{id:"step-6-run-your-gateway",children:"Step 6: Run Your Gateway"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam run configs/gateways/dir_monitor_config.yaml\n"})}),"\n",(0,i.jsx)(n.h2,{id:"advanced-gateway-patterns",children:"Advanced Gateway Patterns"}),"\n",(0,i.jsx)(n.h3,{id:"authentication-and-authorization",children:"Authentication and Authorization"}),"\n",(0,i.jsx)(n.p,{children:"Gateways can implement sophisticated authentication:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'async def _extract_initial_claims(self, external_event_data: Any) -> Optional[Dict[str, Any]]:\n """Extract user claims with API key validation."""\n request = external_event_data.get("request")\n \n # Validate API key\n api_key = request.headers.get("X-API-Key")\n if not api_key or not self._validate_api_key(api_key):\n return None\n \n # Extract user information\n user_id = request.headers.get("X-User-ID", "anonymous")\n \n return {\n "id": user_id,\n "source": "api_gateway",\n "api_key_hash": hashlib.sha256(api_key.encode()).hexdigest()[:8],\n "roles": self._get_user_roles(user_id)\n }\n'})}),"\n",(0,i.jsx)(n.h3,{id:"file-handling-with-artifacts",children:"File Handling with Artifacts"}),"\n",(0,i.jsx)(n.p,{children:"For gateways that handle files:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'async def _save_file_as_artifact(self, file_content: bytes, filename: str, \n mime_type: str, session_id: str) -> Optional[str]:\n """Save file content as artifact and return URI."""\n if not self.shared_artifact_service:\n return None\n \n try:\n save_result = await save_artifact_with_metadata(\n artifact_service=self.shared_artifact_service,\n app_name=self.gateway_id,\n user_id="system",\n session_id=session_id,\n filename=filename,\n content_bytes=file_content,\n mime_type=mime_type,\n metadata_dict={\n "source": "my_gateway",\n "upload_timestamp": datetime.now(timezone.utc).isoformat()\n },\n timestamp=datetime.now(timezone.utc)\n )\n \n if save_result["status"] in ["success", "partial_success"]:\n version = save_result.get("data_version", 0)\n return f"artifact://{self.gateway_id}/system/{session_id}/{filename}?version={version}"\n \n except Exception as e:\n log.error("Failed to save artifact: %s", e)\n \n return None\n'})}),"\n",(0,i.jsx)(n.h3,{id:"streaming-responses",children:"Streaming Responses"}),"\n",(0,i.jsx)(n.p,{children:"Handle streaming responses from agents:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'async def _send_update_to_external(\n self, external_request_context: Dict[str, Any],\n event_data: Union[TaskStatusUpdateEvent, TaskArtifactUpdateEvent],\n is_final_chunk_of_update: bool\n) -> None:\n """Send streaming updates to external system."""\n if isinstance(event_data, TaskStatusUpdateEvent):\n if event_data.status and event_data.status.message:\n for part in event_data.status.message.parts:\n if isinstance(part, TextPart):\n # Send partial text to external system\n await self._send_partial_response(\n external_request_context,\n part.text,\n is_final=is_final_chunk_of_update\n )\n'})}),"\n",(0,i.jsx)(n.h3,{id:"error-handling-and-retry-logic",children:"Error Handling and Retry Logic"}),"\n",(0,i.jsx)(n.p,{children:"Implement robust error handling:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'async def _process_with_retry(self, data: Any, max_retries: int = 3):\n """Process data with retry logic."""\n for attempt in range(max_retries):\n try:\n return await self._process_data(data)\n except TemporaryError as e:\n if attempt < max_retries - 1:\n wait_time = 2 ** attempt # Exponential backoff\n log.warning("Attempt %d failed, retrying in %ds: %s", \n attempt + 1, wait_time, e)\n await asyncio.sleep(wait_time)\n else:\n raise\n except PermanentError:\n # Don\'t retry permanent errors\n raise\n'})}),"\n",(0,i.jsx)(n.h2,{id:"best-practices",children:"Best Practices"}),"\n",(0,i.jsx)(n.h3,{id:"1-configuration-management",children:"1. Configuration Management"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Use environment variables for sensitive data"}),"\n",(0,i.jsx)(n.li,{children:"Provide sensible defaults"}),"\n",(0,i.jsx)(n.li,{children:"Validate configuration at startup"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"2-error-handling",children:"2. Error Handling"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Implement comprehensive error handling"}),"\n",(0,i.jsx)(n.li,{children:"Use appropriate HTTP status codes"}),"\n",(0,i.jsx)(n.li,{children:"Log errors with sufficient context"}),"\n",(0,i.jsx)(n.li,{children:"Provide meaningful error messages"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"3-security",children:"3. Security"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Validate all external inputs"}),"\n",(0,i.jsx)(n.li,{children:"Use secure authentication methods"}),"\n",(0,i.jsx)(n.li,{children:"Implement rate limiting where appropriate"}),"\n",(0,i.jsx)(n.li,{children:"Store secrets securely (use environment variables)"}),"\n",(0,i.jsx)(n.li,{children:"Follow principle of least privilege"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"4-performance",children:"4. Performance"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Use async/await for I/O operations"}),"\n",(0,i.jsx)(n.li,{children:"Implement connection pooling for external APIs"}),"\n",(0,i.jsx)(n.li,{children:"Monitor resource usage"}),"\n",(0,i.jsx)(n.li,{children:"Handle backpressure appropriately"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"5-monitoring-and-logging",children:"5. Monitoring and Logging"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Use structured logging"}),"\n",(0,i.jsx)(n.li,{children:"Include correlation IDs"}),"\n",(0,i.jsx)(n.li,{children:"Monitor key metrics (latency, error rates, throughput)"}),"\n",(0,i.jsx)(n.li,{children:"Set up health checks"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"common-gateway-patterns",children:"Common Gateway Patterns"}),"\n",(0,i.jsx)(n.h3,{id:"httprest-api-gateway",children:"HTTP/REST API Gateway"}),"\n",(0,i.jsx)(n.p,{children:"For HTTP-based integrations:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'from fastapi import FastAPI, HTTPException, Depends\nfrom fastapi.security import HTTPBearer\n\nclass HTTPAPIGatewayComponent(BaseGatewayComponent):\n def __init__(self, **kwargs):\n super().__init__(**kwargs)\n self.app = FastAPI()\n self.security = HTTPBearer()\n self._setup_routes()\n \n def _setup_routes(self):\n @self.app.post("/webhook/{endpoint_id}")\n async def webhook_handler(endpoint_id: str, request: Request,\n token: str = Depends(self.security)):\n # Authenticate request\n user_identity = await self.authenticate_and_enrich_user({\n "token": token,\n "endpoint_id": endpoint_id,\n "request": request\n })\n \n if not user_identity:\n raise HTTPException(status_code=401, detail="Unauthorized")\n \n # Process webhook\n body = await request.json()\n target_agent, parts, context = await self._translate_external_input(\n body, user_identity\n )\n \n task_id = await self.submit_a2a_task(\n target_agent_name=target_agent,\n a2a_parts=parts,\n external_request_context=context,\n user_identity=user_identity\n )\n \n return {"task_id": task_id, "status": "accepted"}\n'})}),"\n",(0,i.jsx)(n.h3,{id:"websocket-gateway",children:"WebSocket Gateway"}),"\n",(0,i.jsx)(n.p,{children:"For real-time bidirectional communication:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'import websockets\nimport json\n\nclass WebSocketGatewayComponent(BaseGatewayComponent):\n def __init__(self, **kwargs):\n super().__init__(**kwargs)\n self.connections = {}\n \n async def _start_listener(self):\n """Start WebSocket server."""\n self.server = await websockets.serve(\n self.handle_websocket,\n self.get_config("websocket_host", "localhost"),\n self.get_config("websocket_port", 8765)\n )\n log.info("%s WebSocket server started", self.log_identifier)\n \n async def handle_websocket(self, websocket, path):\n """Handle WebSocket connections."""\n connection_id = self.generate_uuid()\n self.connections[connection_id] = websocket\n \n try:\n async for message in websocket:\n data = json.loads(message)\n await self.process_websocket_message(connection_id, data)\n except websockets.exceptions.ConnectionClosed:\n log.info("%s WebSocket connection closed: %s", self.log_identifier, connection_id)\n finally:\n self.connections.pop(connection_id, None)\n \n async def process_websocket_message(self, connection_id: str, data: dict):\n """Process incoming WebSocket message."""\n user_identity = await self.authenticate_and_enrich_user({\n "connection_id": connection_id,\n "data": data\n })\n \n if user_identity:\n target_agent, parts, context = await self._translate_external_input(\n data, user_identity\n )\n context["connection_id"] = connection_id\n \n await self.submit_a2a_task(\n target_agent_name=target_agent,\n a2a_parts=parts,\n external_request_context=context,\n user_identity=user_identity\n )\n \n async def _send_final_response_to_external(self, context: Dict[str, Any], task_data: Task):\n """Send response back via WebSocket."""\n connection_id = context.get("connection_id")\n websocket = self.connections.get(connection_id)\n \n if websocket:\n response = {\n "task_id": task_data.id,\n "status": task_data.status.state.value if task_data.status else "unknown",\n "result": self._extract_text_from_task(task_data)\n }\n await websocket.send(json.dumps(response))\n'})}),"\n",(0,i.jsx)(n.h3,{id:"message-queue-gateway",children:"Message Queue Gateway"}),"\n",(0,i.jsx)(n.p,{children:"For integration with message queues:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'import asyncio\nimport aio_pika\n\nclass MessageQueueGatewayComponent(BaseGatewayComponent):\n def __init__(self, **kwargs):\n super().__init__(**kwargs)\n self.connection = None\n self.channel = None\n \n async def _start_listener(self):\n """Connect to message queue and start consuming."""\n connection_url = self.get_config("rabbitmq_url")\n queue_name = self.get_config("input_queue_name")\n \n self.connection = await aio_pika.connect_robust(connection_url)\n self.channel = await self.connection.channel()\n \n queue = await self.channel.declare_queue(queue_name, durable=True)\n await queue.consume(self.process_message)\n \n log.info("%s Started consuming from queue: %s", self.log_identifier, queue_name)\n \n async def process_message(self, message: aio_pika.IncomingMessage):\n """Process incoming queue message."""\n async with message.process():\n try:\n data = json.loads(message.body.decode())\n \n user_identity = await self.authenticate_and_enrich_user(data)\n if not user_identity:\n log.warning("%s Authentication failed for message", self.log_identifier)\n return\n \n target_agent, parts, context = await self._translate_external_input(\n data, user_identity\n )\n context["message_id"] = message.message_id\n context["reply_to"] = message.reply_to\n \n await self.submit_a2a_task(\n target_agent_name=target_agent,\n a2a_parts=parts,\n external_request_context=context,\n user_identity=user_identity\n )\n \n except Exception as e:\n log.exception("%s Error processing message: %s", self.log_identifier, e)\n \n async def _send_final_response_to_external(self, context: Dict[str, Any], task_data: Task):\n """Send response back to reply queue."""\n reply_to = context.get("reply_to")\n if reply_to and self.channel:\n response = {\n "task_id": task_data.id,\n "status": task_data.status.state.value if task_data.status else "unknown",\n "result": self._extract_text_from_task(task_data)\n }\n \n await self.channel.default_exchange.publish(\n aio_pika.Message(json.dumps(response).encode()),\n routing_key=reply_to\n )\n'})}),"\n",(0,i.jsx)(n.h2,{id:"packaging-as-a-plugin",children:"Packaging as a Plugin"}),"\n",(0,i.jsx)(n.p,{children:"For distribution and reusability, package your gateway as a plugin:"}),"\n",(0,i.jsx)(n.h3,{id:"1-create-plugin-structure",children:"1. Create Plugin Structure"}),"\n",(0,i.jsxs)(n.p,{children:["The following structure is created when running the ",(0,i.jsx)(n.code,{children:"sam plugin create my-gateway-plugin --type gateway"})," command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"my-gateway-plugin/\n\u251c\u2500\u2500 pyproject.toml\n\u251c\u2500\u2500 README.md\n\u251c\u2500\u2500 src/\n\u2502 \u2514\u2500\u2500 sam_my_gateway/\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 app.py\n\u2502 \u251c\u2500\u2500 component.py\n\u251c\u2500\u2500 config.yaml\n\u2514\u2500\u2500 examples/\n \u2514\u2500\u2500 my_gateway_example.yaml\n"})}),"\n",(0,i.jsxs)(n.h3,{id:"2-configure-pyprojecttoml",children:["2. Configure ",(0,i.jsx)(n.code,{children:"pyproject.toml"})]}),"\n",(0,i.jsxs)(n.p,{children:["Update the ",(0,i.jsx)(n.code,{children:"pyproject.toml"})," file to include your gateway dependencies:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-toml",children:'...\ndependencies = [\n "watchdog>=3.0.0", # Add your specific dependencies\n]\n...\n'})}),"\n",(0,i.jsx)(n.h3,{id:"3-build-and-install",children:"3. Build and Install"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# Build the plugin\nsam plugin build\n\n# Install plugin from local wheel file\nsam plugin add my-gateway --plugin dist/sam_my_gateway-0.1.0-py3-none-any.whl\n"})}),"\n",(0,i.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,i.jsx)(n.h3,{id:"common-issues",children:"Common Issues"}),"\n",(0,i.jsx)(n.h4,{id:"gateway-fails-to-start",children:"Gateway Fails to Start"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Check configuration schema validation"}),"\n",(0,i.jsx)(n.li,{children:"Verify all required parameters are provided"}),"\n",(0,i.jsx)(n.li,{children:"Ensure external dependencies are installed"}),"\n"]}),"\n",(0,i.jsx)(n.h4,{id:"tasks-not-reaching-agents",children:"Tasks Not Reaching Agents"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Verify namespace configuration matches agents"}),"\n",(0,i.jsx)(n.li,{children:"Check Solace broker connectivity"}),"\n",(0,i.jsx)(n.li,{children:"Confirm agent names are correct"}),"\n"]}),"\n",(0,i.jsx)(n.h4,{id:"authentication-failures",children:"Authentication Failures"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Validate user identity extraction logic"}),"\n",(0,i.jsx)(n.li,{children:"Check authorization service configuration"}),"\n",(0,i.jsx)(n.li,{children:"Verify claims format matches expectations"}),"\n"]}),"\n",(0,i.jsx)(n.h4,{id:"fileartifact-issues",children:"File/Artifact Issues"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Ensure artifact service is properly configured"}),"\n",(0,i.jsx)(n.li,{children:"Check file permissions and paths"}),"\n",(0,i.jsx)(n.li,{children:"Verify artifact URI construction"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"debugging-tips",children:"Debugging Tips"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Enable Debug Logging"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"log:\n stdout_log_level: DEBUG\n log_file_level: DEBUG\n"})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Use Test Agents"}),":\nCreate simple echo agents for testing gateway integration"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Monitor Solace Topics"}),":\nUse Solace monitoring tools to trace message flow"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Add Correlation IDs"}),":\nInclude unique identifiers in logs for request tracing"]}),"\n"]}),"\n"]})]})}function _(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:()=>r,x:()=>o});var a=t(6540);const i={},s=a.createContext(i);function r(e){const n=a.useContext(s);return a.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(i):e.components||i:r(e.components),a.createElement(s.Provider,{value:n},e.children)}}}]);
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[7132],{8097:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>l});const a=JSON.parse('{"id":"documentation/tutorials/rest-gateway","title":"REST Gateway","description":"Solace Agent Mesh REST API Gateway provides a standard, robust, and secure HTTP-based entry point for programmatic and system-to-system integrations. It allows external clients to submit tasks to Solace Agent Mesh agents, manage files, and discover agent capabilities using a familiar RESTful interface.","source":"@site/docs/documentation/tutorials/rest-gateway.md","sourceDirName":"documentation/tutorials","slug":"/documentation/tutorials/rest-gateway","permalink":"/solace-agent-mesh/docs/documentation/tutorials/rest-gateway","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/tutorials/rest-gateway.md","tags":[],"version":"current","sidebarPosition":15,"frontMatter":{"title":"REST Gateway","sidebar_position":15},"sidebar":"docSidebar","previous":{"title":"MCP Integration","permalink":"/solace-agent-mesh/docs/documentation/tutorials/mcp-integration"},"next":{"title":"Event Mesh Gateway","permalink":"/solace-agent-mesh/docs/documentation/tutorials/event-mesh-gateway"}}');var s=t(4848),i=t(8453);const o={title:"REST Gateway",sidebar_position:15},r=void 0,c={},l=[{value:"Key Features",id:"key-features",level:2},{value:"Setting Up the Environment",id:"setting-up-the-environment",level:2},{value:"Adding the REST Gateway Plugin",id:"adding-the-rest-gateway-plugin",level:2},{value:"Configuring the REST Gateway",id:"configuring-the-rest-gateway",level:3},{value:"Running the REST Gateway",id:"running-the-rest-gateway",level:2},{value:"Sending a Request via REST API",id:"sending-a-request-via-rest-api",level:2},{value:"Modern API (v2) - Asynchronous",id:"modern-api-v2---asynchronous",level:3},{value:"Legacy API (v1) - Synchronous",id:"legacy-api-v1---synchronous",level:3}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",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)(n.p,{children:"Solace Agent Mesh REST API Gateway provides a standard, robust, and secure HTTP-based entry point for programmatic and system-to-system integrations. It allows external clients to submit tasks to Solace Agent Mesh agents, manage files, and discover agent capabilities using a familiar RESTful interface."}),"\n",(0,s.jsx)(n.p,{children:"The gateway is designed to be highly configurable and supports two distinct operational modes to cater to both modern, asynchronous workflows and legacy, synchronous systems."}),"\n",(0,s.jsx)(n.h2,{id:"key-features",children:"Key Features"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Dual API Versions"}),": Supports both a modern asynchronous API (v2) and a deprecated synchronous API (v1) for backward compatibility."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Asynchronous by Default"}),': The v2 API uses a "202 Accepted + Poll" pattern, ideal for long-running agent tasks.']}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Delegated Authentication"}),": Integrates with an external authentication service via bearer tokens for secure access."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"File Handling"}),": Supports file uploads for tasks and provides download URLs for generated artifacts."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Dynamic Configuration"}),": All gateway behaviors, including server settings and authentication, are configured via the main Solace Agent Mesh Host YAML file."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"setting-up-the-environment",children:"Setting Up the Environment"}),"\n",(0,s.jsxs)(n.p,{children:["First, you need to ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/getting-started/installation",children:"install Solace Agent Mesh and the Solace Agent Mesh CLI"}),", and then ",(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:"adding-the-rest-gateway-plugin",children:"Adding the REST Gateway Plugin"}),"\n",(0,s.jsx)(n.p,{children:"Once you have your project set up, add the REST Gateway plugin:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"sam plugin add my-http-rest --plugin sam-rest-gateway\n"})}),"\n",(0,s.jsxs)(n.p,{children:["You can use any name for your agent, in this tutorial we use ",(0,s.jsx)(n.code,{children:"my-http-rest"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"This command:"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["Installs the ",(0,s.jsx)(n.code,{children:"sam-rest-gateway"})," plugin"]}),"\n",(0,s.jsxs)(n.li,{children:["Creates a new gateway configuration named ",(0,s.jsx)(n.code,{children:"my-http-rest"})," in your ",(0,s.jsx)(n.code,{children:"configs/gateways/"})," directory"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"configuring-the-rest-gateway",children:"Configuring the REST Gateway"}),"\n",(0,s.jsxs)(n.p,{children:["For further configuration, you can edit the ",(0,s.jsx)(n.code,{children:"configs/gateways/my-http-rest.yaml"})," file. This file contains the gateway configuration that can be customized for your use case."]}),"\n",(0,s.jsxs)(n.admonition,{title:"Using local Solace PubSub+ Broker container",type:"info",children:[(0,s.jsxs)(n.p,{children:["Solace PubSub+ Broker container uses port 8080. You need to edit the ",(0,s.jsx)(n.code,{children:"rest_api_server_port"})," field and ",(0,s.jsx)(n.code,{children:"external_auth_service_url"})," field in the ",(0,s.jsx)(n.code,{children:"configs/gateways/my-http-rest.yaml"})," file to a free port other than 8080 (for example: 8081)."]}),(0,s.jsxs)(n.p,{children:["You can edit the YAML file directly or add environment variables ",(0,s.jsx)(n.code,{children:"REST_API_PORT=8081"})," and ",(0,s.jsx)(n.code,{children:"EXTERNAL_AUTH_SERVICE_URL=http://localhost:8081"}),"."]}),(0,s.jsx)(n.p,{children:"Make sure you change the REST API gateway to your new port in the following request examples."})]}),"\n",(0,s.jsx)(n.h2,{id:"running-the-rest-gateway",children:"Running the REST Gateway"}),"\n",(0,s.jsx)(n.p,{children:"To run the REST Gateway, use the following command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"sam run configs/gateways/my-http-rest.yaml\n"})}),"\n",(0,s.jsx)(n.h2,{id:"sending-a-request-via-rest-api",children:"Sending a Request via REST API"}),"\n",(0,s.jsxs)(n.p,{children:["You can also interact with Solace Agent Mesh via the ",(0,s.jsx)(n.strong,{children:"REST API"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The REST API gateway runs on ",(0,s.jsx)(n.code,{children:"http://localhost:8080"})," by default. You can use either the legacy v1 API or the modern async v2 API."]}),"\n",(0,s.jsx)(n.h3,{id:"modern-api-v2---asynchronous",children:"Modern API (v2) - Asynchronous"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"# Submit task\ncurl --location 'http://localhost:8080/api/v2/tasks' \\\n--header 'Authorization: Bearer token' \\\n--form 'agent_name=\"OrchestratorAgent\"' \\\n--form 'prompt=\"Hi\\!\"'\n\n# Poll for result using returned task ID\ncurl --location 'http://localhost:8080/api/v2/tasks/{taskId}' \\\n--header 'Authorization: Bearer token'\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["It might take a while for the system to respond. See the ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/deployment/observability",children:"observability"})," page for more information about monitoring the system while it processes the request."]})}),"\n",(0,s.jsx)(n.p,{children:"Sample output:"}),"\n",(0,s.jsxs)(n.p,{children:["From ",(0,s.jsx)(n.code,{children:"api/v2/tasks"})]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "taskId":"task-6a0e682f4f6c4927a5997e4fd06eea83"\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["From ",(0,s.jsx)(n.code,{children:"api/v2/tasks/{taskId}"})]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "id": "task-6a0e682f4f6c4927a5997e4fd06eea83",\n "sessionId": "rest-session-4df0c24fcecc45fcb69692db9876bc5c",\n "status": {\n "state": "completed",\n "message": {\n "role": "agent",\n "parts": [{ "type": "text", "text": "Outdoor Activities in London: Spring Edition. Today\'s Perfect Activities (13\xb0C, Light Cloud): - Royal Parks Exploration : Hyde Park and Kensington Gardens..." }]\n },\n "timestamp": "2025-07-03T16:54:15.273085"\n },\n "artifacts": [],\n "metadata": { "agent_name": "OrchestratorAgent" }\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"legacy-api-v1---synchronous",children:"Legacy API (v1) - Synchronous"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"curl --location 'http://localhost:8080/api/v1/invoke' \\\n--header 'Authorization: Bearer None' \\\n--form 'prompt=\"Suggest some good outdoor activities in London given the season and current weather conditions.\"' \\\n--form 'agent_name=\"OrchestratorAgent\"' \\\n--form 'stream=\"false\"'\n"})}),"\n",(0,s.jsx)(n.p,{children:"Sample output:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "id": "task-9f7d5f465f5a4f1ca799e8e5ecb35a43",\n "sessionId": "rest-session-36b36eeb69b04da7b67708f90e5512dc",\n "status": {\n "state": "completed",\n "message": {\n "role": "agent",\n "parts": [\n { "type": "text", "text": "Outdoor Activities in London: Spring Edition. Today\'s Perfect Activities (13\xb0C, Light Cloud): - Royal Parks Exploration : Hyde Park and Kensington Gardens..." }\n ]\n },\n "timestamp": "2025-07-03T16:59:37.486480"\n },\n "artifacts": [],\n "metadata": { "agent_name": "OrchestratorAgent" }\n}\n'})})]})}function h(e={}){const{wrapper:n}={...(0,i.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:()=>o,x:()=>r});var a=t(6540);const s={},i=a.createContext(s);function o(e){const n=a.useContext(i);return a.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(s):e.components||s:o(e.components),a.createElement(i.Provider,{value:n},e.children)}}}]);
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[1257],{6060:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>a,toc:()=>c});const a=JSON.parse('{"id":"documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0","title":"Solace Agent Mesh Gateway Migration Guide: Upgrading to the A2A SDK","description":"This guide is for developers who have built or are maintaining a custom Solace Agent Mesh gateway. A recent architectural update has aligned Solace Agent Mesh with the official Agent-to-Agent (A2A) protocol","source":"@site/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0.md","sourceDirName":"documentation/Migrations/A2A Upgrade To 0.3.0","slug":"/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0","permalink":"/solace-agent-mesh/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docSidebar","previous":{"title":"RAG Integration","permalink":"/solace-agent-mesh/docs/documentation/tutorials/rag-integration"},"next":{"title":"A2A Technical Migration Map","permalink":"/solace-agent-mesh/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map"}}');var s=n(4848),r=n(8453);const i={},o="Solace Agent Mesh Gateway Migration Guide: Upgrading to the A2A SDK",l={},c=[{value:"1. Why the Change?",id:"1-why-the-change",level:2},{value:"2. Core Conceptual Changes",id:"2-core-conceptual-changes",level:2},{value:"The <code>a2a</code> Helper Layer: The New Best Practice",id:"the-a2a-helper-layer-the-new-best-practice",level:3},{value:"Type System Migration",id:"type-system-migration",level:3},{value:"Accessing Object Properties",id:"accessing-object-properties",level:3},{value:"Changes to <code>BaseGatewayComponent</code>",id:"changes-to-basegatewaycomponent",level:3},{value:"3. Practical Migration Checklist",id:"3-practical-migration-checklist",level:2},{value:"4. Code Examples: Before &amp; After",id:"4-code-examples-before--after",level:2},{value:"Example 1: Translating External Input",id:"example-1-translating-external-input",level:3},{value:"Example 2: Sending a Final Response",id:"example-2-sending-a-final-response",level:3}];function d(e){const t={br:"br",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,r.R)(),...e.components},{Details:n}=t;return n||function(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"solace-agent-mesh-gateway-migration-guide-upgrading-to-the-a2a-sdk",children:"Solace Agent Mesh Gateway Migration Guide: Upgrading to the A2A SDK"})}),"\n",(0,s.jsxs)(t.p,{children:["This guide is for developers who have built or are maintaining a custom Solace Agent Mesh gateway. A recent architectural update has aligned Solace Agent Mesh with the official Agent-to-Agent (A2A) protocol",(0,s.jsx)(t.br,{}),"\n","specification by adopting the ",(0,s.jsx)(t.code,{children:"a2a-sdk"}),". This migration requires some changes to your gateway code to ensure compatibility."]}),"\n",(0,s.jsx)(t.p,{children:"This document provides a high-level overview of the conceptual changes and a practical checklist to guide you through the upgrade process."}),"\n",(0,s.jsx)(t.h2,{id:"1-why-the-change",children:"1. Why the Change?"}),"\n",(0,s.jsxs)(t.p,{children:["The migration from our legacy A2A implementation to the official ",(0,s.jsx)(t.code,{children:"a2a-sdk"})," is a foundational improvement with several key benefits:"]}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Protocol Compliance:"})," Ensures your gateway is fully interoperable with any A2A-compliant agent or system."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Standardization:"})," Replaces bespoke code with a community-supported standard, reducing technical debt."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Improved Maintainability:"})," Insulates your gateway from future A2A specification changes. The ",(0,s.jsx)(t.code,{children:"a2a-sdk"})," will be updated, not your core logic."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Future-Proofing:"})," Positions your gateway to easily adopt new features as the A2A protocol evolves."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"2-core-conceptual-changes",children:"2. Core Conceptual Changes"}),"\n",(0,s.jsx)(t.p,{children:"The upgrade introduces a few key changes in how you interact with A2A objects."}),"\n",(0,s.jsxs)(t.h3,{id:"the-a2a-helper-layer-the-new-best-practice",children:["The ",(0,s.jsx)(t.code,{children:"a2a"})," Helper Layer: The New Best Practice"]}),"\n",(0,s.jsxs)(t.p,{children:["The most significant change is the introduction of a new abstraction layer located at ",(0,s.jsx)(t.code,{children:"solace_agent_mesh.common.a2a"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["You should ",(0,s.jsxs)(t.strong,{children:["no longer instantiate ",(0,s.jsx)(t.code,{children:"a2a.types"})," models directly"]})," or access their properties by hand. Instead, use the provided helper functions. This layer is designed to simplify development and",(0,s.jsx)(t.br,{}),"\n","protect your code from future SDK changes."]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-python",children:'# BEFORE: Direct instantiation and property access \nfrom solace_agent_mesh.common.types import TextPart, Task \nmy_part = TextPart(text="Hello") \ntask_id = my_task.id \n \n# AFTER: Using the a2a helper layer \nfrom solace_agent_mesh.common import a2a \nmy_part = a2a.create_text_part(text="Hello") \ntask_id = a2a.get_task_id(my_task) \n'})}),"\n",(0,s.jsx)(t.h3,{id:"type-system-migration",children:"Type System Migration"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["The legacy types in ",(0,s.jsx)(t.code,{children:"solace_agent_mesh.common.types"})," (like ",(0,s.jsx)(t.code,{children:"A2APart"}),", ",(0,s.jsx)(t.code,{children:"FileContent"}),") are deprecated."]}),"\n",(0,s.jsxs)(t.li,{children:["All A2A models now come from the ",(0,s.jsx)(t.code,{children:"a2a.types"})," library."]}),"\n",(0,s.jsxs)(t.li,{children:["The type hint for a list of message parts has changed from ",(0,s.jsx)(t.code,{children:"List[A2APart]"})," to ",(0,s.jsx)(t.code,{children:"List[ContentPart]"}),". ",(0,s.jsx)(t.code,{children:"ContentPart"})," is a simple alias for the union of ",(0,s.jsx)(t.code,{children:"TextPart"}),", ",(0,s.jsx)(t.code,{children:"DataPart"}),", and ",(0,s.jsx)(t.code,{children:"FilePart"}),"."]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"accessing-object-properties",children:"Accessing Object Properties"}),"\n",(0,s.jsxs)(t.p,{children:["Field names on many A2A objects have changed. Always use the ",(0,s.jsx)(t.code,{children:"a2a"})," helper functions for safe and future-proof access."]}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{style:{textAlign:"left"},children:"Action"}),(0,s.jsx)(t.th,{style:{textAlign:"left"},children:"Old Pattern"}),(0,s.jsx)(t.th,{style:{textAlign:"left"},children:"New Pattern (Recommended)"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{style:{textAlign:"left"},children:"Get Task ID"}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"task.id"})}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"a2a.get_task_id(task)"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{style:{textAlign:"left"},children:"Get Task Status"}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"task.status.state"})}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"a2a.get_task_status(task)"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{style:{textAlign:"left"},children:"Get Event's Task ID"}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"event.id"})}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"event.task_id"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{style:{textAlign:"left"},children:"Get Message Parts"}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"message.parts"})}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"a2a.get_parts_from_message(message)"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{style:{textAlign:"left"},children:"Get Error Message"}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"error.message"})}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"a2a.get_error_message(error)"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{style:{textAlign:"left"},children:"Get Error Code"}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"error.code"})}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"a2a.get_error_code(error)"})})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{style:{textAlign:"left"},children:"Get Error Data"}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"error.data"})}),(0,s.jsx)(t.td,{style:{textAlign:"left"},children:(0,s.jsx)(t.code,{children:"a2a.get_error_data(error)"})})]})]})]}),"\n",(0,s.jsxs)(t.h3,{id:"changes-to-basegatewaycomponent",children:["Changes to ",(0,s.jsx)(t.code,{children:"BaseGatewayComponent"})]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"BaseGatewayComponent"})," has been significantly improved. It now handles more of the A2A protocol complexity, simplifying gateway implementations."]}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Artifact Handling:"})," The base class can now automatically handle artifact URIs, converting them to embedded bytes before sending them to your gateway's ",(0,s.jsx)(t.code,{children:"_send_..."})," methods. This is controlled by",(0,s.jsx)(t.br,{}),"\n","the ",(0,s.jsx)(t.code,{children:"resolve_artifact_uris_in_gateway"})," parameter in the constructor."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Message Publishing:"})," The base class now manages the details of preparing and publishing the A2A request message in ",(0,s.jsx)(t.code,{children:"submit_a2a_task"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Asynchronous Model:"})," The underlying threading model has been removed in favor of a more direct ",(0,s.jsx)(t.code,{children:"asyncio"})," implementation, simplifying the component lifecycle."]}),"\n"]}),"\n",(0,s.jsxs)(t.p,{children:["It is highly recommended to review the latest ",(0,s.jsx)(t.code,{children:"BaseGatewayComponent"})," and re-base your custom gateway on it to inherit these benefits and reduce boilerplate code."]}),"\n",(0,s.jsx)(t.h2,{id:"3-practical-migration-checklist",children:"3. Practical Migration Checklist"}),"\n",(0,s.jsx)(t.p,{children:"Follow these steps to update your gateway code."}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Update Imports:"})}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["Remove imports from ",(0,s.jsx)(t.code,{children:"solace_agent_mesh.common.types"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["Add imports from ",(0,s.jsx)(t.code,{children:"a2a.types"})," for specific models if needed."]}),"\n",(0,s.jsxs)(t.li,{children:["Add ",(0,s.jsx)(t.code,{children:"from solace_agent_mesh.common import a2a"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["Add ",(0,s.jsx)(t.code,{children:"from solace_agent_mesh.common.a2a import ContentPart"}),"."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Update Type Hints:"})}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["Find all instances of ",(0,s.jsx)(t.code,{children:"List[A2APart]"})," and change them to ",(0,s.jsx)(t.code,{children:"List[ContentPart]"}),"."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Refactor Object Creation:"})}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["Replace direct model instantiation like ",(0,s.jsx)(t.code,{children:"TextPart(...)"})," or ",(0,s.jsx)(t.code,{children:"FilePart(...)"})," with their corresponding helper functions: ",(0,s.jsx)(t.code,{children:"a2a.create_text_part(...)"}),", ",(0,s.jsx)(t.code,{children:"a2a.create_file_part_from_uri(...)"}),", etc."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Refactor Property Access:"})}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["Replace direct property access (",(0,s.jsx)(t.code,{children:"task.id"}),", ",(0,s.jsx)(t.code,{children:"error.message"}),") with calls to the ",(0,s.jsx)(t.code,{children:"a2a"})," helper functions (",(0,s.jsx)(t.code,{children:"a2a.get_task_id(task)"}),", ",(0,s.jsx)(t.code,{children:"a2a.get_error_message(error)"}),")."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Review Base Class Integration:"})}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["If you have a custom gateway, compare it against the latest ",(0,s.jsx)(t.code,{children:"BaseGatewayComponent"}),". Consider refactoring to delegate more responsibility (like artifact handling and message submission) to the",(0,s.jsx)(t.br,{}),"\n","base class."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Test Thoroughly:"})}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Once refactored, run your integration tests to ensure the gateway correctly translates inputs and processes outputs in the new format."}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"4-code-examples-before--after",children:"4. Code Examples: Before & After"}),"\n",(0,s.jsx)(t.p,{children:"Here are some common patterns you will encounter during the migration."}),"\n",(0,s.jsx)(t.h3,{id:"example-1-translating-external-input",children:"Example 1: Translating External Input"}),"\n",(0,s.jsx)(t.p,{children:"This example shows how to create A2A parts from an external event."}),"\n",(0,s.jsxs)(n,{children:[(0,s.jsx)("summary",{children:(0,s.jsx)("strong",{children:"_translate_external_input"})}),(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Before:"})}),(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-python",children:'from solace_agent_mesh.common.types import Part as A2APart, TextPart, FilePart, FileContent \n \nasync def _translate_external_input(self, external_event: Any) -> Tuple[str, List[A2APart], Dict[str, Any]]: \n # ... \n a2a_parts: List[A2APart] = [] \n \n # Create a file part with a URI \n uri = "artifact://..." \n a2a_parts.append( \n FilePart( \n file=FileContent(name="report.pdf", uri=uri) \n ) \n ) \n \n # Create a text part \n prompt = "Summarize the attached file." \n a2a_parts.append(TextPart(text=prompt)) \n \n return "summary_agent", a2a_parts, {} \n'})}),(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"After:"})}),(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-python",children:'from solace_agent_mesh.common import a2a \nfrom solace_agent_mesh.common.a2a import ContentPart \n \nasync def _translate_external_input(self, external_event: Any) -> Tuple[str, List[ContentPart], Dict[str, Any]]: \n # ... \n a2a_parts: List[ContentPart] = [] \n \n # Create a file part with a URI using the helper \n uri = "artifact://..." \n file_part = a2a.create_file_part_from_uri(uri=uri, name="report.pdf") \n a2a_parts.append(file_part) \n \n # Create a text part using the helper \n prompt = "Summarize the attached file." \n text_part = a2a.create_text_part(text=prompt) \n a2a_parts.append(text_part) \n \n return "summary_agent", a2a_parts, {} \n'})})]}),"\n",(0,s.jsx)(t.h3,{id:"example-2-sending-a-final-response",children:"Example 2: Sending a Final Response"}),"\n",(0,s.jsxs)(t.p,{children:["This example shows how to process a final ",(0,s.jsx)(t.code,{children:"Task"})," object."]}),"\n",(0,s.jsxs)(n,{children:[(0,s.jsx)("summary",{children:(0,s.jsx)("strong",{children:"_send_final_response_to_external"})}),(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Before:"})}),(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-python",children:'from solace_agent_mesh.common.types import Task, TaskState, TextPart \n \nasync def _send_final_response_to_external(self, context: Dict, task_data: Task) -> None: \n task_id = task_data.id \n final_status_text = ":checkered_flag: Task complete." \n \n if task_data.status.state == TaskState.FAILED: \n error_message_text = "" \n if task_data.status.message and task_data.status.message.parts: \n for part in task_data.status.message.parts: \n if isinstance(part, TextPart): \n error_message_text = part.text \n break \n final_status_text = f":x: Error: Task failed. {error_message_text}".strip() \n \n # ... use final_status_text and task_id \n'})}),(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"After:"})}),(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-python",children:'from solace_agent_mesh.common import a2a \nfrom a2a.types import Task, TaskState \n \nasync def _send_final_response_to_external(self, context: Dict, task_data: Task) -> None: \n # Use helpers to safely access properties \n task_id = a2a.get_task_id(task_data) \n task_status = a2a.get_task_status(task_data) \n \n final_status_text = ":checkered_flag: Task complete." \n \n if task_status == TaskState.failed: \n error_message_text = "" \n if task_data.status and task_data.status.message: \n # Use helper to extract all text from the message \n error_message_text = a2a.get_text_from_message(task_data.status.message) \n final_status_text = f":x: Error: Task failed. {error_message_text}".strip() \n \n # ... use final_status_text and task_id \n'})})]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var a=n(6540);const s={},r=a.createContext(s);function i(e){const t=a.useContext(r);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),a.createElement(r.Provider,{value:t},e.children)}}}]);
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[8055],{5343:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"documentation/tutorials/rag-integration","title":"RAG Integration","description":"This tutorial guides you through setting up and configuring Solace Agent Mesh Retrieval Augmented Generation (RAG) plugin. The RAG plugin enables your agents to answer questions by retrieving information from a knowledge base of your documents.","source":"@site/docs/documentation/tutorials/rag-integration.md","sourceDirName":"documentation/tutorials","slug":"/documentation/tutorials/rag-integration","permalink":"/solace-agent-mesh/docs/documentation/tutorials/rag-integration","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/tutorials/rag-integration.md","tags":[],"version":"current","sidebarPosition":70,"frontMatter":{"title":"RAG Integration","sidebar_position":70,"toc_max_heading_level":4},"sidebar":"docSidebar","previous":{"title":"Slack Integration","permalink":"/solace-agent-mesh/docs/documentation/tutorials/slack-integration"},"next":{"title":"Solace Agent Mesh Gateway Migration Guide: Upgrading to the A2A SDK","permalink":"/solace-agent-mesh/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0"}}');var a=t(4848),r=t(8453);const o={title:"RAG Integration",sidebar_position:70,toc_max_heading_level:4},s="RAG Integration",l={},c=[{value:"What is Solace Agent Mesh RAG?",id:"what-is-solace-agent-mesh-rag",level:2},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Adding the RAG Plugin",id:"adding-the-rag-plugin",level:2},{value:"Configuring the RAG Agent",id:"configuring-the-rag-agent",level:2},{value:"Shared Configuration",id:"shared-configuration",level:3},{value:"RAG Pipeline Configuration",id:"rag-pipeline-configuration",level:3},{value:"1. Scanner Configuration",id:"1-scanner-configuration",level:4},{value:"2. Preprocessor Configuration",id:"2-preprocessor-configuration",level:4},{value:"3. Splitter Configuration",id:"3-splitter-configuration",level:4},{value:"4. Embedding Configuration",id:"4-embedding-configuration",level:4},{value:"5. Vector Database Configuration",id:"5-vector-database-configuration",level:4},{value:"6. LLM Configuration",id:"6-llm-configuration",level:4},{value:"7. Retrieval Configuration",id:"7-retrieval-configuration",level:4},{value:"Environment Variables",id:"environment-variables",level:3},{value:"Running the RAG Agent",id:"running-the-rag-agent",level:2},{value:"Testing the RAG Agent",id:"testing-the-rag-agent",level:2},{value:"Ingesting Documents",id:"ingesting-documents",level:3},{value:"Option 1: Automatic Scanning (Batch Ingestion)",id:"option-1-automatic-scanning-batch-ingestion",level:4},{value:"Option 2: Manual Upload via Gateway",id:"option-2-manual-upload-via-gateway",level:4},{value:"Querying the Knowledge Base",id:"querying-the-knowledge-base",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2}];function d(e){const n={a:"a",blockquote:"blockquote",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,r.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"rag-integration",children:"RAG Integration"})}),"\n",(0,a.jsx)(n.p,{children:"This tutorial guides you through setting up and configuring Solace Agent Mesh Retrieval Augmented Generation (RAG) plugin. The RAG plugin enables your agents to answer questions by retrieving information from a knowledge base of your documents."}),"\n",(0,a.jsx)(n.h2,{id:"what-is-solace-agent-mesh-rag",children:"What is Solace Agent Mesh RAG?"}),"\n",(0,a.jsx)(n.p,{children:"The Solace Agent Mesh RAG plugin enhances your agents with the ability to perform retrieval-augmented generation. This means the agent can:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"Scan"})," documents from various sources (local filesystem, Google Drive, etc.)."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"Preprocess"})," and ",(0,a.jsx)(n.strong,{children:"split"})," the text into manageable chunks."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"Embed"})," these chunks into vectors and store them in a vector database."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"Retrieve"})," relevant chunks of text based on a user's query."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"Generate"})," an answer using a large language model (LLM) augmented with the retrieved information."]}),"\n"]}),"\n",(0,a.jsx)(n.p,{children:"This allows you to build agents that can answer questions about your own private data."}),"\n",(0,a.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,a.jsx)(n.p,{children:"Before you begin, ensure you have:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/getting-started/installation",children:"Installed Solace Agent Mesh and the Solace Agent Mesh CLI"}),"."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/getting-started/quick-start",children:"Created a new Solace Agent Mesh project"}),"."]}),"\n",(0,a.jsx)(n.li,{children:"Access to a vector database (for example, Qdrant, Chroma, and Pinecone)."}),"\n",(0,a.jsx)(n.li,{children:"Access to an LLM for generation and an embedding model."}),"\n",(0,a.jsx)(n.li,{children:"A directory with some documents for the agent to ingest."}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"adding-the-rag-plugin",children:"Adding the RAG Plugin"}),"\n",(0,a.jsx)(n.p,{children:"To add the RAG plugin to your Solace Agent Mesh project, run the following command:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sh",children:"sam plugin add my-rag-agent --plugin sam-rag\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Replace ",(0,a.jsx)(n.code,{children:"my-rag-agent"})," with your preferred agent name. This command:"]}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:["Installs the ",(0,a.jsx)(n.code,{children:"sam-rag"})," plugin."]}),"\n",(0,a.jsxs)(n.li,{children:["Creates a new agent configuration file at ",(0,a.jsx)(n.code,{children:"configs/agents/my-rag-agent.yaml"}),"."]}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"configuring-the-rag-agent",children:"Configuring the RAG Agent"}),"\n",(0,a.jsxs)(n.p,{children:["The RAG agent requires a detailed configuration. Open ",(0,a.jsx)(n.code,{children:"configs/agents/my-rag-agent.yaml"})," to configure the following sections:"]}),"\n",(0,a.jsx)(n.h3,{id:"shared-configuration",children:"Shared Configuration"}),"\n",(0,a.jsxs)(n.p,{children:["Like other agents, the RAG agent needs a connection to the Solace broker and a configured LLM. This is typically done in a ",(0,a.jsx)(n.code,{children:"shared_config.yaml"})," file."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:"# configs/shared_config.yaml\nshared_config:\n - broker_connection: &broker_connection\n dev_mode: ${SOLACE_DEV_MODE, false}\n broker_url: ${SOLACE_BROKER_URL, ws://localhost:8080}\n broker_username: ${SOLACE_BROKER_USERNAME, default}\n broker_password: ${SOLACE_BROKER_PASSWORD, default}\n broker_vpn: ${SOLACE_BROKER_VPN, default}\n temporary_queue: ${USE_TEMPORARY_QUEUES, true}\n\n - models:\n general: &general_model\n model: ${LLM_SERVICE_GENERAL_MODEL_NAME}\n api_base: ${LLM_SERVICE_ENDPOINT}\n api_key: ${LLM_SERVICE_API_KEY}\n"})}),"\n",(0,a.jsx)(n.h3,{id:"rag-pipeline-configuration",children:"RAG Pipeline Configuration"}),"\n",(0,a.jsxs)(n.p,{children:["The RAG pipeline has several stages, each with its own configuration block within the ",(0,a.jsx)(n.code,{children:"app_config"})," section of your ",(0,a.jsx)(n.code,{children:"my-rag-agent.yaml"})," file."]}),"\n",(0,a.jsx)(n.h4,{id:"1-scanner-configuration",children:"1. Scanner Configuration"}),"\n",(0,a.jsx)(n.p,{children:"The scanner discovers documents to be ingested. You can configure it to scan a local filesystem or cloud sources."}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Local Filesystem Example:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:'scanner:\n batch: true\n use_memory_storage: true\n source:\n type: filesystem\n directories:\n - "/path/to/your/documents" # Important: Replace with your actual document directory path\n filters:\n file_formats:\n - ".txt"\n - ".pdf"\n - ".md"\n'})}),"\n",(0,a.jsxs)(n.p,{children:[(0,a.jsx)(n.strong,{children:"Multi-Cloud Source Example:"}),"\nYou can also configure multiple sources, including Google Drive, OneDrive, and S3."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:'scanner:\n batch: true\n use_memory_storage: true\n sources:\n - type: filesystem\n directories: ["${LOCAL_DOCUMENTS_PATH}"]\n - type: google_drive\n credentials_path: "${GOOGLE_DRIVE_CREDENTIALS_PATH}"\n folders:\n - folder_id: "${GOOGLE_DRIVE_FOLDER_ID_1}"\n name: "Documents"\n recursive: true\n'})}),"\n",(0,a.jsx)(n.h4,{id:"2-preprocessor-configuration",children:"2. Preprocessor Configuration"}),"\n",(0,a.jsx)(n.p,{children:"The preprocessor cleans the text extracted from documents."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:"preprocessor:\n default_preprocessor:\n type: enhanced\n params:\n lowercase: true\n normalize_whitespace: true\n remove_urls: true\n preprocessors:\n pdf: \n type: document\n params:\n lowercase: true\n normalize_whitespace: true\n remove_non_ascii: true\n remove_urls: true\n"})}),"\n",(0,a.jsx)(n.h4,{id:"3-splitter-configuration",children:"3. Splitter Configuration"}),"\n",(0,a.jsx)(n.p,{children:"The splitter breaks down large documents into smaller chunks. Different splitters are available for different file types."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:"splitter:\n default_splitter:\n type: recursive_character\n params:\n chunk_size: 2048\n chunk_overlap: 400\n splitters:\n markdown:\n type: markdown\n params:\n chunk_size: 2048\n chunk_overlap: 400\n pdf:\n type: token\n params:\n chunk_size: 500\n chunk_overlap: 100\n"})}),"\n",(0,a.jsx)(n.h4,{id:"4-embedding-configuration",children:"4. Embedding Configuration"}),"\n",(0,a.jsx)(n.p,{children:"This section defines the model used to create vector embeddings from the text chunks."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:'embedding:\n embedder_type: "openai"\n embedder_params:\n model: "${OPENAI_EMBEDDING_MODEL}"\n api_key: "${OPENAI_API_KEY}"\n api_base: "${OPENAI_API_ENDPOINT}"\n normalize_embeddings: true\n'})}),"\n",(0,a.jsx)(n.h4,{id:"5-vector-database-configuration",children:"5. Vector Database Configuration"}),"\n",(0,a.jsx)(n.p,{children:"Configure the connection to your vector database where the embeddings are stored."}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Qdrant Example:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:'vector_db:\n db_type: "qdrant"\n db_params:\n url: "${QDRANT_URL}"\n api_key: "${QDRANT_API_KEY}"\n collection_name: "${QDRANT_COLLECTION}"\n embedding_dimension: ${QDRANT_EMBEDDING_DIMENSION}\n'})}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Chroma Example:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:'vector_db:\n db_type: "chroma"\n db_params:\n host: "${CHROMA_HOST}"\n port: "${CHROMA_PORT}"\n collection_name: "${CHROMA_COLLECTION}"\n'})}),"\n",(0,a.jsx)(n.h4,{id:"6-llm-configuration",children:"6. LLM Configuration"}),"\n",(0,a.jsx)(n.p,{children:"Configure the LLM that is used to generate answers based on the retrieved context."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:'llm:\n load_balancer:\n - model_name: "gpt-4o"\n litellm_params:\n model: "openai/${OPENAI_MODEL_NAME}"\n api_key: "${OPENAI_API_KEY}"\n api_base: "${OPENAI_API_ENDPOINT}"\n'})}),"\n",(0,a.jsx)(n.h4,{id:"7-retrieval-configuration",children:"7. Retrieval Configuration"}),"\n",(0,a.jsx)(n.p,{children:"This defines how many document chunks are retrieved to answer a query."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:"retrieval:\n top_k: 7\n"})}),"\n",(0,a.jsx)(n.h3,{id:"environment-variables",children:"Environment Variables"}),"\n",(0,a.jsxs)(n.p,{children:["The RAG agent relies heavily on environment variables. Here are some of the most important ones you'll need to set in your ",(0,a.jsx)(n.code,{children:".env"})," file:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:'# Solace Connection\nSOLACE_BROKER_URL=ws://localhost:8080\nSOLACE_BROKER_VPN=default\nSOLACE_BROKER_USERNAME=default\nSOLACE_BROKER_PASSWORD=default\nNAMESPACE=my-org/dev\n\n# LLM and Embedding Models\nOPENAI_API_KEY="your-openai-api-key"\nOPENAI_API_ENDPOINT="your-openai-api-endpoint"\nOPENAI_MODEL_NAME="model name. E.g., gpt-4o"\nOPENAI_EMBEDDING_MODEL="embedding model name. E.g., text-embedding-3-small"\n\n# Vector Database (Qdrant example)\nQDRANT_URL="Qdrant url"\nQDRANT_API_KEY="API key"\nQDRANT_COLLECTION="my-rag-collection"\nQDRANT_EMBEDDING_DIMENSION=1536 # Depends on your embedding model\n\n# Scanner\nLOCAL_DOCUMENTS_PATH="./my_documents" # Relative path to your documents folder\n'})}),"\n",(0,a.jsxs)(n.p,{children:["Create a directory named ",(0,a.jsx)(n.code,{children:"my_documents"})," in your project root and place some text or markdown files inside it."]}),"\n",(0,a.jsx)(n.h2,{id:"running-the-rag-agent",children:"Running the RAG Agent"}),"\n",(0,a.jsx)(n.p,{children:"Once you have configured your agent and set the environment variables, you can run it:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sh",children:"sam run configs/agents/my-rag-agent.yaml\n"})}),"\n",(0,a.jsx)(n.p,{children:"When the agent starts, it begins scanning the documents in the configured source, processing and ingesting them into your vector database. This process may take some time, depending on the number and size of your documents."}),"\n",(0,a.jsx)(n.h2,{id:"testing-the-rag-agent",children:"Testing the RAG Agent"}),"\n",(0,a.jsx)(n.p,{children:"Once your agent is running, you can test its retrieval capabilities and ingest new documents."}),"\n",(0,a.jsx)(n.h3,{id:"ingesting-documents",children:"Ingesting Documents"}),"\n",(0,a.jsx)(n.p,{children:"There are two primary ways to ingest documents into your RAG agent's knowledge base:"}),"\n",(0,a.jsx)(n.h4,{id:"option-1-automatic-scanning-batch-ingestion",children:"Option 1: Automatic Scanning (Batch Ingestion)"}),"\n",(0,a.jsxs)(n.p,{children:["This method uses the configured ",(0,a.jsx)(n.code,{children:"scanner"})," component. The agent automatically ingests documents from the directories specified in your configuration upon startup."]}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Step 1: Create a Document"})}),"\n",(0,a.jsxs)(n.p,{children:["First, create a simple text file named ",(0,a.jsx)(n.code,{children:"sam_features.txt"})," and add some content to it. For example:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-text",children:"Solace Agent Mesh is a powerful framework for building AI agents.\nKey features of Solace Agent Mesh include:\n- A flexible plugin architecture.\n- Integration with various LLMs and vector databases.\n- Scalable gateways for different communication protocols.\n- An event-driven design based on Solace PubSub+.\n"})}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Step 2: Place the Document in the Scanned Directory"})}),"\n",(0,a.jsxs)(n.p,{children:['In the "Environment Variables" section, we configured ',(0,a.jsx)(n.code,{children:"LOCAL_DOCUMENTS_PATH"})," to point to a directory (e.g., ",(0,a.jsx)(n.code,{children:"./my_documents"}),")."]}),"\n",(0,a.jsxs)(n.p,{children:["Create this directory in your project's root folder if you haven't already, and move your ",(0,a.jsx)(n.code,{children:"sam_features.txt"})," file into it."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sh",children:"mkdir -p my_documents\nmv sam_features.txt my_documents/\n"})}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Step 3: Run the Agent to Trigger Ingestion"})}),"\n",(0,a.jsx)(n.p,{children:"If your agent is already running, you'll need to restart it to trigger the batch scan. If it's not running, start it now:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sh",children:"sam run configs/agents/my-rag-agent.yaml\n"})}),"\n",(0,a.jsx)(n.p,{children:"You will see logs indicating that the file is being processed. Once the agent is running and the initial scan is complete, the document is successfully ingested and ready for retrieval."}),"\n",(0,a.jsx)(n.h4,{id:"option-2-manual-upload-via-gateway",children:"Option 2: Manual Upload via Gateway"}),"\n",(0,a.jsx)(n.p,{children:"You can also ingest documents dynamically by uploading them directly through a gateway, like the Web UI. This is useful for adding single documents without restarting the agent. The RAG agent exposes a tool for this purpose."}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Step 1: Start the RAG Agent and Web UI"})}),"\n",(0,a.jsx)(n.p,{children:"Ensure both your RAG agent and the Web UI gateway are running."}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Step 2: Upload a Document in the Web UI"})}),"\n",(0,a.jsxs)(n.ol,{children:["\n",(0,a.jsxs)(n.li,{children:["Open the Web UI (usually at ",(0,a.jsx)(n.a,{href:"http://localhost:8000",children:"http://localhost:8000"}),", or check your gateway configuration for the correct URL) and start a chat with your RAG agent."]}),"\n",(0,a.jsx)(n.li,{children:"Use the file attachment button to select a document from your local machine."}),"\n",(0,a.jsxs)(n.li,{children:["Send a prompt along with the file, instructing the agent to ingest it. For example:","\n",(0,a.jsxs)(n.blockquote,{children:["\n",(0,a.jsx)(n.p,{children:'"Please ingest the attached document into your knowledge base."'}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,a.jsxs)(n.p,{children:["The RAG agent uses its ",(0,a.jsx)(n.code,{children:"built-in"})," ingest_document tool to process the file you uploaded. The file goes through the same preprocessing, splitting, and embedding pipeline as the documents from the automatic scan."]}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Step 3: Confirm Ingestion"})}),"\n",(0,a.jsx)(n.p,{children:"After the agent confirms that the document has been ingested, you can immediately ask questions about its content."}),"\n",(0,a.jsx)(n.h3,{id:"querying-the-knowledge-base",children:"Querying the Knowledge Base"}),"\n",(0,a.jsx)(n.p,{children:"You can interact with your RAG agent through any gateway, such as the Web UI gateway."}),"\n",(0,a.jsxs)(n.ol,{children:["\n",(0,a.jsx)(n.li,{children:"Make sure you have a Web UI gateway running (or add one to your project)."}),"\n",(0,a.jsxs)(n.li,{children:["Open the Web UI (usually at ",(0,a.jsx)(n.code,{children:"http://localhost:8000"}),")."]}),"\n",(0,a.jsxs)(n.li,{children:["Start a conversation with ",(0,a.jsx)(n.code,{children:"my-rag-agent"}),"."]}),"\n",(0,a.jsx)(n.li,{children:"Ask a question related to the content of the documents you provided during the initial scan."}),"\n"]}),"\n",(0,a.jsx)(n.p,{children:"For example, if you have a document about product features, you could ask:"}),"\n",(0,a.jsxs)(n.blockquote,{children:["\n",(0,a.jsx)(n.p,{children:'"What are the key features of Product X?"'}),"\n"]}),"\n",(0,a.jsx)(n.p,{children:"The agent searches its knowledge base, finds the relevant information, and generates an answer based on the content of your documents."}),"\n",(0,a.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"Connection Errors"}),": Double-check all your URLs, API keys, and credentials for your LLM and vector database."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"Ingestion Issues"}),": Check the agent logs for errors during the scanning, preprocessing, or embedding stages. Ensure the file formats are supported and the paths are correct."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"No Answers"}),": If the agent can't answer, it might be because the information is not in the documents, or the ",(0,a.jsx)(n.code,{children:"top_k"})," retrieval setting is too low."]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>s});var i=t(6540);const a={},r=i.createContext(a);function o(e){const n=i.useContext(r);return i.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(a):e.components||a:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]);
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[1095],{6871:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>o,toc:()=>d});const o=JSON.parse('{"id":"documentation/user-guide/builtin-tools/builtin-tools","title":"Configuring Built-in Tools","description":"This guide provides instructions for enabling and configuring the built-in tools provided by Solace Agent Mesh framework.","source":"@site/docs/documentation/user-guide/builtin-tools/builtin-tools.md","sourceDirName":"documentation/user-guide/builtin-tools","slug":"/documentation/user-guide/builtin-tools/","permalink":"/solace-agent-mesh/docs/documentation/user-guide/builtin-tools/","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/user-guide/builtin-tools/builtin-tools.md","tags":[],"version":"current","sidebarPosition":60,"frontMatter":{"title":"Configuring Built-in Tools","sidebar_position":60},"sidebar":"docSidebar","previous":{"title":"Creating Service Providers","permalink":"/solace-agent-mesh/docs/documentation/user-guide/creating-service-providers"},"next":{"title":"Artifact Management Tools","permalink":"/solace-agent-mesh/docs/documentation/user-guide/builtin-tools/artifact-management"}}');var l=i(4848),t=i(8453);const s={title:"Configuring Built-in Tools",sidebar_position:60},r="Configuring Built-in Tools",a={},d=[{value:"Overview",id:"overview",level:2},{value:"Configuration Methods",id:"configuration-methods",level:2},{value:"Method 1: Enabling Tool Groups (Recommended)",id:"method-1-enabling-tool-groups-recommended",level:3},{value:"Method 2: Enabling Individual Tools",id:"method-2-enabling-individual-tools",level:3},{value:"Available Tool Groups and Tools",id:"available-tool-groups-and-tools",level:2},{value:"Artifact Management",id:"artifact-management",level:3},{value:"Data Analysis",id:"data-analysis",level:3},{value:"Web",id:"web",level:3},{value:"Audio",id:"audio",level:3},{value:"Image",id:"image",level:3},{value:"General",id:"general",level:3},{value:"Complete Configuration Example",id:"complete-configuration-example",level:2}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(n.header,{children:(0,l.jsx)(n.h1,{id:"configuring-built-in-tools",children:"Configuring Built-in Tools"})}),"\n",(0,l.jsx)(n.p,{children:"This guide provides instructions for enabling and configuring the built-in tools provided by Solace Agent Mesh framework."}),"\n",(0,l.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,l.jsx)(n.p,{children:"Built-in tools are pre-packaged functionalities that can be granted to agents without requiring custom Python code. These tools address common operations such as file management, data analysis, web requests, and multi-modal generation."}),"\n",(0,l.jsxs)(n.p,{children:["The Solace Agent Mesh framework manages these tools through a central ",(0,l.jsx)(n.code,{children:"tool_registry"}),", which is responsible for loading the tools, generating instructional prompts for the Large Language Model (LLM), and handling their execution in a consistent manner."]}),"\n",(0,l.jsx)(n.h2,{id:"configuration-methods",children:"Configuration Methods"}),"\n",(0,l.jsxs)(n.p,{children:["Tool configuration is managed within the ",(0,l.jsx)(n.code,{children:"tools"})," list in an agent's ",(0,l.jsx)(n.code,{children:"app_config"})," block in the corresponding YAML configuration file."]}),"\n",(0,l.jsx)(n.h3,{id:"method-1-enabling-tool-groups-recommended",children:"Method 1: Enabling Tool Groups (Recommended)"}),"\n",(0,l.jsx)(n.p,{children:"For efficient configuration, built-in tools are organized into logical groups. An entire group of related tools can be enabled with a single entry. This is the recommended approach for standard functionalities."}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:(0,l.jsx)(n.code,{children:"tool_type"})}),": ",(0,l.jsx)(n.code,{children:"builtin-group"})]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:(0,l.jsx)(n.code,{children:"group_name"})}),": The unique identifier for the tool category."]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Example:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-yaml",children:'# In your agent\'s app_config:\ntools:\n - tool_type: builtin-group\n group_name: "artifact_management"\n - tool_type: builtin-group\n group_name: "data_analysis"\n'})}),"\n",(0,l.jsx)(n.h3,{id:"method-2-enabling-individual-tools",children:"Method 2: Enabling Individual Tools"}),"\n",(0,l.jsx)(n.p,{children:"For more granular control over an agent's capabilities, specific tools can be enabled individually."}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:(0,l.jsx)(n.code,{children:"tool_type"})}),": ",(0,l.jsx)(n.code,{children:"builtin"})]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:(0,l.jsx)(n.code,{children:"tool_name"})}),": The unique, registered name of the tool."]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Example:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-yaml",children:'# In your agent\'s app_config:\ntools:\n - tool_type: builtin\n tool_name: "web_request"\n - tool_type: builtin\n tool_name: "time_delay"\n'})}),"\n",(0,l.jsx)(n.admonition,{title:"Note",type:"info",children:(0,l.jsx)(n.p,{children:"The Solace Agent Mesh framework automatically handles duplicate tool registrations. If a tool group is enabled and a tool from that group is also listed individually, the tool is only loaded once."})}),"\n",(0,l.jsx)(n.h2,{id:"available-tool-groups-and-tools",children:"Available Tool Groups and Tools"}),"\n",(0,l.jsx)(n.p,{children:"The following sections detail the available tool groups and the individual tools they contain."}),"\n",(0,l.jsx)(n.h3,{id:"artifact-management",children:"Artifact Management"}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Group Name"}),": ",(0,l.jsx)(n.code,{children:"artifact_management"})]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Description"}),": Tools for creating, loading, and managing file artifacts."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Individual Tools"}),":"]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"create_artifact"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"append_to_artifact"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"list_artifacts"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"load_artifact"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"signal_artifact_for_return"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"apply_embed_and_create_artifact"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"extract_content_from_artifact"})}),"\n"]}),"\n",(0,l.jsx)(n.admonition,{type:"info",children:(0,l.jsxs)(n.p,{children:["For a more in-depth guide on using artifact management tools, refer to the ",(0,l.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/user-guide/builtin-tools/artifact-management",children:"Artifact Management"})," documentation."]})}),"\n",(0,l.jsx)(n.h3,{id:"data-analysis",children:"Data Analysis"}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Group Name"}),": ",(0,l.jsx)(n.code,{children:"data_analysis"})]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Description"}),": Tools for querying, transforming, and visualizing data."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Individual Tools"}),":"]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"query_data_with_sql"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"create_sqlite_db"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"transform_data_with_jq"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"create_chart_from_plotly_config"})}),"\n"]}),"\n",(0,l.jsx)(n.admonition,{type:"info",children:(0,l.jsxs)(n.p,{children:["For a more in-depth guide on using Data Analysis tools, refer to the ",(0,l.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/user-guide/builtin-tools/data-analysis-tools",children:"Data Analysis Tools"})," documentation."]})}),"\n",(0,l.jsx)(n.h3,{id:"web",children:"Web"}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Group Name"}),": ",(0,l.jsx)(n.code,{children:"web"})]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Description"}),": Tools for interacting with web resources."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Individual Tools"}),":"]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"web_request"})}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"audio",children:"Audio"}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Group Name"}),": ",(0,l.jsx)(n.code,{children:"audio"})]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Description"}),": Tools for generating and transcribing audio content."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Individual Tools"}),":"]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"text_to_speech"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"multi_speaker_text_to_speech"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"transcribe_audio"})}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"image",children:"Image"}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Group Name"}),": ",(0,l.jsx)(n.code,{children:"image"})]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Description"}),": Tools for generating and analyzing images."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Individual Tools"}),":"]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"create_image_from_description"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"describe_image"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"edit_image_with_gemini"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"describe_audio"})}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"general",children:"General"}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Group Name"}),": ",(0,l.jsx)(n.code,{children:"general"})]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Description"}),": General-purpose utility tools."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Individual Tools"}),":"]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"convert_file_to_markdown"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"mermaid_diagram_generator"})}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"complete-configuration-example",children:"Complete Configuration Example"}),"\n",(0,l.jsxs)(n.p,{children:["Below is a comprehensive example of a well-formed ",(0,l.jsx)(n.code,{children:"app_config"})," that uses the unified method to enable a mix of tool groups and individual tools."]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-yaml",children:'# In your agent\'s YAML file:\napp_config:\n namespace: "myorg/dev"\n agent_name: "DataAndWebAgent"\n model: "gemini-1.5-pro"\n instruction: "You are an agent that can analyze data and browse the web."\n\n # --- Unified Tool Configuration ---\n tools:\n # Enable a group of tools\n - tool_type: builtin-group\n group_name: "data_analysis"\n\n # Enable another group\n - tool_type: builtin-group\n group_name: "artifact_management"\n\n # Enable a single, specific tool\n - tool_type: builtin\n tool_name: "web_request"\n\n # Enable a custom Python tool\n - tool_type: python\n component_module: "my_company.tools.custom_calculators"\n function_name: "calculate_roi"\n\n # ... other service configurations (session_service, artifact_service, etc.)\n'})})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,l.jsx)(n,{...e,children:(0,l.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>s,x:()=>r});var o=i(6540);const l={},t=o.createContext(l);function s(e){const n=o.useContext(t);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(l):e.components||l:s(e.components),o.createElement(t.Provider,{value:n},e.children)}}}]);