solace-agent-mesh 1.5.1__py3-none-any.whl → 1.6.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of solace-agent-mesh might be problematic. Click here for more details.

Files changed (184) hide show
  1. solace_agent_mesh/agent/adk/callbacks.py +0 -5
  2. solace_agent_mesh/agent/adk/models/lite_llm.py +123 -8
  3. solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +245 -0
  4. solace_agent_mesh/agent/protocol/event_handlers.py +213 -31
  5. solace_agent_mesh/agent/proxies/__init__.py +0 -0
  6. solace_agent_mesh/agent/proxies/a2a/__init__.py +3 -0
  7. solace_agent_mesh/agent/proxies/a2a/app.py +55 -0
  8. solace_agent_mesh/agent/proxies/a2a/component.py +1115 -0
  9. solace_agent_mesh/agent/proxies/a2a/config.py +140 -0
  10. solace_agent_mesh/agent/proxies/a2a/oauth_token_cache.py +104 -0
  11. solace_agent_mesh/agent/proxies/base/__init__.py +3 -0
  12. solace_agent_mesh/agent/proxies/base/app.py +99 -0
  13. solace_agent_mesh/agent/proxies/base/component.py +650 -0
  14. solace_agent_mesh/agent/proxies/base/config.py +85 -0
  15. solace_agent_mesh/agent/proxies/base/proxy_task_context.py +17 -0
  16. solace_agent_mesh/agent/sac/app.py +58 -5
  17. solace_agent_mesh/agent/sac/component.py +238 -75
  18. solace_agent_mesh/agent/sac/task_execution_context.py +46 -0
  19. solace_agent_mesh/agent/tools/audio_tools.py +125 -8
  20. solace_agent_mesh/agent/tools/web_tools.py +10 -5
  21. solace_agent_mesh/agent/utils/artifact_helpers.py +141 -3
  22. solace_agent_mesh/assets/docs/404.html +3 -3
  23. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +1 -0
  24. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +1 -0
  25. solace_agent_mesh/assets/docs/assets/js/71da7b71.38583438.js +1 -0
  26. solace_agent_mesh/assets/docs/assets/js/77cf947d.48cb18a2.js +1 -0
  27. solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +1 -0
  28. solace_agent_mesh/assets/docs/assets/js/9e9d0a82.570c057b.js +1 -0
  29. solace_agent_mesh/assets/docs/assets/js/{ad71b5ed.60668e9e.js → ad71b5ed.af3ecfd1.js} +1 -1
  30. solace_agent_mesh/assets/docs/assets/js/ceb2a7a6.5d92d7d0.js +1 -0
  31. solace_agent_mesh/assets/docs/assets/js/{da0b5bad.9d369087.js → da0b5bad.d08a9466.js} +1 -1
  32. solace_agent_mesh/assets/docs/assets/js/db924877.e98d12a1.js +1 -0
  33. solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +1 -0
  34. solace_agent_mesh/assets/docs/assets/js/{e3d9abda.2b916f9e.js → e3d9abda.6b9493d0.js} +1 -1
  35. solace_agent_mesh/assets/docs/assets/js/e6f9706b.e74a984d.js +1 -0
  36. solace_agent_mesh/assets/docs/assets/js/f284c35a.42f59cdd.js +1 -0
  37. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +1 -0
  38. solace_agent_mesh/assets/docs/assets/js/{main.bd3c34f3.js → main.b12eac43.js} +2 -2
  39. solace_agent_mesh/assets/docs/assets/js/runtime~main.e268214e.js +1 -0
  40. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +15 -4
  41. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +4 -4
  43. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +4 -4
  44. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +4 -4
  45. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +4 -4
  47. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +4 -4
  48. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +4 -4
  49. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +4 -4
  50. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +4 -4
  51. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +262 -0
  52. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +3 -3
  53. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +31 -3
  54. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +3 -3
  55. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +3 -3
  56. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +4 -4
  57. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +5 -5
  58. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +4 -4
  59. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +4 -4
  60. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +135 -0
  61. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +6 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +4 -4
  64. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +4 -4
  65. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +5 -5
  66. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +4 -4
  67. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +4 -4
  68. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +4 -4
  69. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +4 -4
  70. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +4 -4
  71. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +4 -4
  72. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +3 -3
  73. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +3 -3
  74. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +3 -3
  75. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +3 -3
  76. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +3 -3
  77. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +3 -3
  78. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
  79. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +3 -3
  80. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +6 -5
  81. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +3 -3
  82. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +3 -3
  83. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +100 -3
  84. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +3 -3
  85. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
  86. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +3 -3
  87. solace_agent_mesh/assets/docs/lunr-index-1761248203150.json +1 -0
  88. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  89. solace_agent_mesh/assets/docs/search-doc-1761248203150.json +1 -0
  90. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  91. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  92. solace_agent_mesh/cli/__init__.py +1 -1
  93. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +2 -69
  94. solace_agent_mesh/cli/commands/eval_cmd.py +11 -49
  95. solace_agent_mesh/cli/commands/init_cmd/__init__.py +0 -5
  96. solace_agent_mesh/cli/commands/init_cmd/env_step.py +10 -12
  97. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +9 -61
  98. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +9 -49
  99. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +1 -2
  100. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-DwrxZE0E.js → authCallback-BTf6dqwp.js} +1 -1
  101. solace_agent_mesh/client/webui/frontend/static/assets/{client-DarGQzyw.js → client-CaY59VuC.js} +1 -1
  102. solace_agent_mesh/client/webui/frontend/static/assets/main-B32noGmR.js +342 -0
  103. solace_agent_mesh/client/webui/frontend/static/assets/main-DHJKSW1S.css +1 -0
  104. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-BKIeiHj_.js → vendor-BEmvJSYz.js} +1 -1
  105. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  106. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  107. solace_agent_mesh/common/a2a/__init__.py +24 -0
  108. solace_agent_mesh/common/a2a/artifact.py +39 -0
  109. solace_agent_mesh/common/a2a/events.py +29 -0
  110. solace_agent_mesh/common/a2a/message.py +68 -0
  111. solace_agent_mesh/common/a2a/protocol.py +151 -1
  112. solace_agent_mesh/common/agent_registry.py +83 -3
  113. solace_agent_mesh/common/constants.py +3 -1
  114. solace_agent_mesh/common/sac/sam_component_base.py +383 -4
  115. solace_agent_mesh/common/utils/pydantic_utils.py +12 -0
  116. solace_agent_mesh/config_portal/backend/common.py +1 -1
  117. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +98 -0
  118. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-44d62be6.js → manifest-61038fc6.js} +1 -1
  119. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  120. solace_agent_mesh/evaluation/evaluator.py +128 -104
  121. solace_agent_mesh/evaluation/message_organizer.py +116 -110
  122. solace_agent_mesh/evaluation/report_data_processor.py +84 -86
  123. solace_agent_mesh/evaluation/report_generator.py +73 -79
  124. solace_agent_mesh/evaluation/run.py +421 -235
  125. solace_agent_mesh/evaluation/shared/__init__.py +92 -0
  126. solace_agent_mesh/evaluation/shared/constants.py +47 -0
  127. solace_agent_mesh/evaluation/shared/exceptions.py +50 -0
  128. solace_agent_mesh/evaluation/shared/helpers.py +35 -0
  129. solace_agent_mesh/evaluation/shared/test_case_loader.py +167 -0
  130. solace_agent_mesh/evaluation/shared/test_suite_loader.py +280 -0
  131. solace_agent_mesh/evaluation/subscriber.py +111 -232
  132. solace_agent_mesh/evaluation/summary_builder.py +227 -117
  133. solace_agent_mesh/gateway/base/app.py +16 -1
  134. solace_agent_mesh/gateway/base/component.py +112 -39
  135. solace_agent_mesh/gateway/http_sse/alembic/versions/20251015_add_session_performance_indexes.py +70 -0
  136. solace_agent_mesh/gateway/http_sse/component.py +99 -3
  137. solace_agent_mesh/gateway/http_sse/dependencies.py +4 -4
  138. solace_agent_mesh/gateway/http_sse/main.py +1 -0
  139. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +12 -13
  140. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +15 -18
  141. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +25 -18
  142. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +30 -26
  143. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +35 -44
  144. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +4 -3
  145. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +95 -203
  146. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +4 -3
  147. solace_agent_mesh/gateway/http_sse/routers/sessions.py +2 -2
  148. solace_agent_mesh/gateway/http_sse/routers/tasks.py +33 -41
  149. solace_agent_mesh/gateway/http_sse/routers/users.py +47 -1
  150. solace_agent_mesh/gateway/http_sse/routers/visualization.py +17 -11
  151. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +4 -4
  152. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +51 -43
  153. solace_agent_mesh/gateway/http_sse/services/session_service.py +20 -20
  154. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +8 -8
  155. solace_agent_mesh/gateway/http_sse/shared/base_repository.py +45 -71
  156. solace_agent_mesh/gateway/http_sse/shared/types.py +0 -18
  157. solace_agent_mesh/templates/gateway_config_template.yaml +0 -5
  158. solace_agent_mesh/templates/logging_config_template.ini +10 -6
  159. solace_agent_mesh/templates/plugin_gateway_config_template.yaml +0 -3
  160. solace_agent_mesh/templates/shared_config.yaml +40 -0
  161. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.1.dist-info}/METADATA +47 -21
  162. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.1.dist-info}/RECORD +166 -145
  163. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.e49689dd.js +0 -1
  164. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.39d5851d.js +0 -1
  165. solace_agent_mesh/assets/docs/assets/js/71da7b71.804d6567.js +0 -1
  166. solace_agent_mesh/assets/docs/assets/js/77cf947d.64c9bd6c.js +0 -1
  167. solace_agent_mesh/assets/docs/assets/js/9e9d0a82.dd810042.js +0 -1
  168. solace_agent_mesh/assets/docs/assets/js/db924877.cbc66f02.js +0 -1
  169. solace_agent_mesh/assets/docs/assets/js/de915948.139b4b9c.js +0 -1
  170. solace_agent_mesh/assets/docs/assets/js/e6f9706b.582a78ca.js +0 -1
  171. solace_agent_mesh/assets/docs/assets/js/f284c35a.5766a13d.js +0 -1
  172. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.9c0297a6.js +0 -1
  173. solace_agent_mesh/assets/docs/assets/js/runtime~main.18dc45dd.js +0 -1
  174. solace_agent_mesh/assets/docs/lunr-index-1760121512891.json +0 -1
  175. solace_agent_mesh/assets/docs/search-doc-1760121512891.json +0 -1
  176. solace_agent_mesh/client/webui/frontend/static/assets/main-2nd1gbaH.js +0 -339
  177. solace_agent_mesh/client/webui/frontend/static/assets/main-DoKXctCM.css +0 -1
  178. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-BNuqpWDc.js +0 -98
  179. solace_agent_mesh/evaluation/config_loader.py +0 -657
  180. solace_agent_mesh/evaluation/test_case_loader.py +0 -714
  181. /solace_agent_mesh/assets/docs/assets/js/{main.bd3c34f3.js.LICENSE.txt → main.b12eac43.js.LICENSE.txt} +0 -0
  182. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.1.dist-info}/WHEEL +0 -0
  183. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.1.dist-info}/entry_points.txt +0 -0
  184. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.1.dist-info}/licenses/LICENSE +0 -0
@@ -1 +1 @@
1
- "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[582],{4415:(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/developing/create-gateways","title":"Create Gateways","description":"Gateways in 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/developing/create-gateways.md","sourceDirName":"documentation/developing","slug":"/documentation/developing/create-gateways","permalink":"/solace-agent-mesh/docs/documentation/developing/create-gateways","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/developing/create-gateways.md","tags":[],"version":"current","sidebarPosition":430,"frontMatter":{"title":"Create Gateways","sidebar_position":430},"sidebar":"docSidebar","previous":{"title":"Creating Agents","permalink":"/solace-agent-mesh/docs/documentation/developing/create-agents"},"next":{"title":"Creating Python Tools","permalink":"/solace-agent-mesh/docs/documentation/developing/creating-python-tools"}}');var i=t(4848),s=t(8453);const r={title:"Create Gateways",sidebar_position:430},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 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 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 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)}}}]);
1
+ "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[582],{4415:(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/developing/create-gateways","title":"Create Gateways","description":"Gateways in 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/developing/create-gateways.md","sourceDirName":"documentation/developing","slug":"/documentation/developing/create-gateways","permalink":"/solace-agent-mesh/docs/documentation/developing/create-gateways","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/developing/create-gateways.md","tags":[],"version":"current","sidebarPosition":430,"frontMatter":{"title":"Create Gateways","sidebar_position":430},"sidebar":"docSidebar","previous":{"title":"Creating Agents","permalink":"/solace-agent-mesh/docs/documentation/developing/create-agents"},"next":{"title":"Creating Python Tools","permalink":"/solace-agent-mesh/docs/documentation/developing/creating-python-tools"}}');var i=t(4848),s=t(8453);const r={title:"Create Gateways",sidebar_position:430},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 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 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 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 # 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([[9066],{7517:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"documentation/developing/creating-service-providers","title":"Creating Service Providers","description":"This guide details the process for developers to create service provider plugins for integrating backend systems (for example, HR platforms, CRMs) with Agent Mesh.","source":"@site/docs/documentation/developing/creating-service-providers.md","sourceDirName":"documentation/developing","slug":"/documentation/developing/creating-service-providers","permalink":"/solace-agent-mesh/docs/documentation/developing/creating-service-providers","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/developing/creating-service-providers.md","tags":[],"version":"current","sidebarPosition":450,"frontMatter":{"title":"Creating Service Providers","sidebar_position":450},"sidebar":"docSidebar","previous":{"title":"Creating Python Tools","permalink":"/solace-agent-mesh/docs/documentation/developing/creating-python-tools"},"next":{"title":"Evaluating Agents","permalink":"/solace-agent-mesh/docs/documentation/developing/evaluations"}}');var t=r(4848),s=r(8453);const o={title:"Creating Service Providers",sidebar_position:450},d="Creating Service Providers",c={},l=[{value:"Understanding Service Providers",id:"understanding-service-providers",level:2},{value:"The &quot;Dual-Role Provider&quot; Pattern",id:"the-dual-role-provider-pattern",level:2},{value:"Step-by-Step Implementation Guide",id:"step-by-step-implementation-guide",level:2},{value:"Step 1: Establish the Plugin Structure",id:"step-1-establish-the-plugin-structure",level:3},{value:"Step 2: Define the Provider Class",id:"step-2-define-the-provider-class",level:3},{value:"Step 3: Map to the Canonical Employee Schema",id:"step-3-map-to-the-canonical-employee-schema",level:3},{value:"Step 4: Register the Plugin",id:"step-4-register-the-plugin",level:3},{value:"Configuring the Provider",id:"configuring-the-provider",level:2}];function a(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"creating-service-providers",children:"Creating Service Providers"})}),"\n",(0,t.jsx)(n.p,{children:"This guide details the process for developers to create service provider plugins for integrating backend systems (for example, HR platforms, CRMs) with Agent Mesh."}),"\n",(0,t.jsx)(n.h2,{id:"understanding-service-providers",children:"Understanding Service Providers"}),"\n",(0,t.jsx)(n.p,{children:"Service Providers function as the abstraction layer between Agent Mesh and enterprise data sources. They are implemented as Python classes that adhere to a specific abstract base class, enabling standardized interaction between Agent Mesh components (Gateways and Agents) and the underlying data."}),"\n",(0,t.jsx)(n.p,{children:"There are two primary service provider interfaces:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"BaseIdentityService"})}),": Responsible for ",(0,t.jsx)(n.strong,{children:"identity enrichment"}),". This service is utilized by Gateways to augment the profile of an authenticated user with additional details (for example, full name, job title) based on their initial authentication claims."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"BaseEmployeeService"})}),": Responsible for ",(0,t.jsx)(n.strong,{children:"general directory querying"}),". This service is utilized by agents (for example, the ",(0,t.jsx)(n.code,{children:"EmployeeAgent"}),") to execute lookups across the entire employee directory."]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"the-dual-role-provider-pattern",children:'The "Dual-Role Provider" Pattern'}),"\n",(0,t.jsx)(n.p,{children:'In many enterprise systems, particularly HR platforms, the data source for identity enrichment and general employee queries is identical. To optimize development, Agent Mesh promotes a "Dual-Role Provider" pattern.'}),"\n",(0,t.jsxs)(n.p,{children:["This pattern involves creating a single class that inherits from both ",(0,t.jsx)(n.code,{children:"BaseIdentityService"})," and ",(0,t.jsx)(n.code,{children:"BaseEmployeeService"}),". This consolidated class can then be configured to fulfill either or both roles, thereby reducing code duplication."]}),"\n",(0,t.jsx)(n.h2,{id:"step-by-step-implementation-guide",children:"Step-by-Step Implementation Guide"}),"\n",(0,t.jsx)(n.p,{children:'This section provides a walkthrough for creating a new provider for a fictional "CorpHR" system.'}),"\n",(0,t.jsx)(n.h3,{id:"step-1-establish-the-plugin-structure",children:"Step 1: Establish the Plugin Structure"}),"\n",(0,t.jsxs)(n.p,{children:["The recommended structure for a custom service provider plugin should include a ",(0,t.jsx)(n.code,{children:"pyproject.toml"})," for packaging and a ",(0,t.jsx)(n.code,{children:"src"})," directory for the source code."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"sam plugin create my_corp_hr_provider --type custom\n"})}),"\n",(0,t.jsx)(n.h3,{id:"step-2-define-the-provider-class",children:"Step 2: Define the Provider Class"}),"\n",(0,t.jsxs)(n.p,{children:["Create a ",(0,t.jsx)(n.code,{children:"provider.py"})," module and define the provider class, ensuring it inherits from both base service classes."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-python",children:'# my_corp_hr_provider/provider.py\n\n# Import base classes from the Agent Mesh framework\ntry:\n from solace_agent_mesh.common.services.identity_service import BaseIdentityService\n from solace_agent_mesh.common.services.employee_service import BaseEmployeeService\nexcept ImportError:\n # Fallback for local development environments\n from src.solace_agent_mesh.common.services.identity_service import BaseIdentityService\n from src.solace_agent_mesh.common.services.employee_service import BaseEmployeeService\n\n# Import any other necessary libraries, such as \'requests\' or a proprietary SDK\n# from .corp_hr_sdk import CorpHR_SDK\n\nclass CorpHRProvider(BaseIdentityService, BaseEmployeeService):\n """\n A dual-role provider for the CorpHR system, implementing methods\n for both identity enrichment and employee directory services.\n """\n def __init__(self, config):\n super().__init__(config)\n # Initialize the backend service/SDK client here.\n # It is best practice to implement this as a singleton to share\n # connection pools and cache.\n # self.corp_hr_sdk = CorpHR_SDK(api_key=config.get("api_key"))\n\n # --- BaseIdentityService Method Implementations ---\n\n async def get_user_profile(self, auth_claims):\n """Enrich the current user\'s profile based on their auth claims."""\n # TODO: Implement logic to fetch user data from CorpHR\n pass\n\n async def search_users(self, query, limit=10):\n """Search for users, for features like @-mentions."""\n # TODO: Implement user search logic against CorpHR\n pass\n\n # --- BaseEmployeeService Method Implementations ---\n\n async def get_employee_dataframe(self):\n """Return all employees as a pandas DataFrame for directory-wide queries."""\n # TODO: Fetch all employee data and return as a DataFrame\n pass\n\n async def get_employee_profile(self, employee_id):\n """Get a single employee\'s full profile by their ID."""\n # Note: This is a general directory lookup, distinct from get_user_profile.\n # TODO: Implement single employee lookup\n pass\n\n async def get_time_off_data(self, employee_id):\n """Get an employee\'s raw time off data."""\n # Example return format:\n # return [{\'start\': \'2025-07-04\', \'end\': \'2025-07-04\', \'type\': \'Holiday\'}]\n # TODO: Implement time off data retrieval\n pass\n\n async def get_employee_profile_picture(self, employee_id):\n """Fetch a profile picture as a data URI string."""\n # Example return format: "data:image/jpeg;base64,..."\n # TODO: Implement profile picture fetching\n pass\n'})}),"\n",(0,t.jsx)(n.h3,{id:"step-3-map-to-the-canonical-employee-schema",children:"Step 3: Map to the Canonical Employee Schema"}),"\n",(0,t.jsxs)(n.p,{children:["When implementing the service methods, it is ",(0,t.jsx)(n.strong,{children:"mandatory"})," to map the data from the source system to the ",(0,t.jsx)(n.strong,{children:"canonical employee schema"})," of Agent Mesh. This ensures data consistency and interoperability with all tools and components across the mesh."]}),"\n",(0,t.jsxs)(n.table,{children:[(0,t.jsx)(n.thead,{children:(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.th,{children:"Field Name"}),(0,t.jsx)(n.th,{children:"Data Type"}),(0,t.jsx)(n.th,{children:"Description"})]})}),(0,t.jsxs)(n.tbody,{children:[(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"id"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsxs)(n.td,{children:["A unique, stable, and ",(0,t.jsx)(n.strong,{children:"lowercase"})," identifier (e.g., email, GUID)."]})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"displayName"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The employee's full name for display purposes."})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"workEmail"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The employee's primary work email address."})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"jobTitle"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The employee's official job title."})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"department"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The department to which the employee belongs."})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"location"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The physical or regional location of the employee."})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"supervisorId"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsxs)(n.td,{children:["The unique ",(0,t.jsx)(n.code,{children:"id"})," of the employee's direct manager."]})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"hireDate"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsxs)(n.td,{children:["The date the employee was hired (ISO 8601: ",(0,t.jsx)(n.code,{children:"YYYY-MM-DD"}),")."]})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"mobilePhone"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The employee's mobile phone number (optional)."})]})]})]}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["If a field is not available in the source system, return ",(0,t.jsx)(n.code,{children:"None"})," or omit the key from the returned dictionary."]})}),"\n",(0,t.jsx)(n.h3,{id:"step-4-register-the-plugin",children:"Step 4: Register the Plugin"}),"\n",(0,t.jsx)(n.p,{children:"To make the provider discoverable by Agent Mesh, it must be registered as a plugin via entry points."}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsxs)(n.strong,{children:["1. Add an entry point in ",(0,t.jsx)(n.code,{children:"pyproject.toml"}),":"]}),"\nThe key assigned here (",(0,t.jsx)(n.code,{children:"corphr"}),") is used as the ",(0,t.jsx)(n.code,{children:"type"})," identifier in YAML configurations."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-toml",children:'[project.entry-points."solace_agent_mesh.plugins"]\ncorphr = "my_corp_hr_provider:info"\n'})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsxs)(n.strong,{children:["2. Define the ",(0,t.jsx)(n.code,{children:"info"})," object in the plugin's ",(0,t.jsx)(n.code,{children:"__init__.py"}),":"]}),"\nThis object points to the provider's class path and provides a brief description."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-python",children:'# my_corp_hr_provider/__init__.py\ninfo = {\n "class_path": "my_corp_hr_provider.provider.CorpHRProvider",\n "description": "Identity and People Service provider for CorpHR.",\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"configuring-the-provider",children:"Configuring the Provider"}),"\n",(0,t.jsxs)(n.p,{children:["Once the plugin is created and installed (for example, via ",(0,t.jsx)(n.code,{children:"pip install ."}),"), it can be configured in any Gateway or Agent ",(0,t.jsx)(n.code,{children:"app_config.yml"}),"."]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"For a Gateway (Identity Service Role):"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-yaml",children:'app_config:\n identity_service:\n type: "corphr" # Matches the key in pyproject.toml\n api_key: "${CORPHR_API_KEY}"\n lookup_key: "email" # The field from auth_claims to use for lookup\n'})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"For an Agent (Employee Service Role):"}),"\nThis example demonstrates configuring the provider for the ",(0,t.jsx)(n.code,{children:"employee_tools"})," group."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-yaml",children:'app_config:\n tools:\n - tool_type: builtin-group\n group_name: "employee_tools"\n config:\n type: "corphr" # Same provider, different role\n api_key: "${CORPHR_API_KEY}"\n'})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(a,{...e})}):a(e)}},8453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>d});var i=r(6540);const t={},s=i.createContext(t);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]);
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[6426],{1007:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>t,toc:()=>l});const t=JSON.parse('{"id":"documentation/installing-and-configuring/large_language_models","title":"Configuring LLMs","description":"Large Language Models (LLMs) serve as the intelligence foundation for Agent Mesh, powering everything from natural language understanding to complex reasoning and decision-making. The system provides flexible configuration options that allow you to connect with various LLM providers through a unified interface, making it easy to switch between providers or use multiple models for different purposes.","source":"@site/docs/documentation/installing-and-configuring/large_language_models.md","sourceDirName":"documentation/installing-and-configuring","slug":"/documentation/installing-and-configuring/large_language_models","permalink":"/solace-agent-mesh/docs/documentation/installing-and-configuring/large_language_models","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/installing-and-configuring/large_language_models.md","tags":[],"version":"current","sidebarPosition":340,"frontMatter":{"title":"Configuring LLMs","sidebar_position":340},"sidebar":"docSidebar","previous":{"title":"Configuring Agent Mesh","permalink":"/solace-agent-mesh/docs/documentation/installing-and-configuring/configurations"},"next":{"title":"Developing with Agent Mesh","permalink":"/solace-agent-mesh/docs/documentation/developing/"}}');var r=i(4848),s=i(8453);const o={title:"Configuring LLMs",sidebar_position:340},a=void 0,c={},l=[{value:"Understanding LiteLLM Integration",id:"understanding-litellm-integration",level:2},{value:"Provider-Specific Configurations",id:"provider-specific-configurations",level:2},{value:"OpenAI",id:"openai",level:3},{value:"Azure OpenAI",id:"azure-openai",level:3},{value:"Google Vertex AI",id:"google-vertex-ai",level:3},{value:"Amazon Bedrock",id:"amazon-bedrock",level:3},{value:"Anthropic",id:"anthropic",level:3},{value:"Additional Providers",id:"additional-providers",level:3},{value:"Prompt Caching",id:"prompt-caching",level:2},{value:"How Prompt Caching Works",id:"how-prompt-caching-works",level:3},{value:"Supported Providers",id:"supported-providers",level:3},{value:"Cache Strategy Configuration",id:"cache-strategy-configuration",level:3},{value:"Configuration Examples",id:"configuration-examples",level:3},{value:"Cache Strategy Selection Guidelines",id:"cache-strategy-selection-guidelines",level:3},{value:"What Gets Cached",id:"what-gets-cached",level:3},{value:"Cache Invalidation",id:"cache-invalidation",level:3},{value:"OAuth 2.0 Authentication",id:"oauth-20-authentication",level:2},{value:"Overview",id:"overview",level:3},{value:"Configuration Parameters",id:"configuration-parameters",level:3},{value:"Environment Variables",id:"environment-variables",level:3},{value:"YAML Configuration",id:"yaml-configuration",level:3},{value:"Error Handling and Fallback",id:"error-handling-and-fallback",level:3},{value:"Security Considerations",id:"security-considerations",level:3},{value:"Troubleshooting OAuth Issues",id:"troubleshooting-oauth-issues",level:3},{value:"Supported Providers",id:"supported-providers-1",level:3},{value:"Security and SSL/TLS Configuration",id:"security-and-ssltls-configuration",level:2},{value:"Example Environment Configuration",id:"example-environment-configuration",level:3}];function d(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",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,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.p,{children:"Large Language Models (LLMs) serve as the intelligence foundation for Agent Mesh, powering everything from natural language understanding to complex reasoning and decision-making. The system provides flexible configuration options that allow you to connect with various LLM providers through a unified interface, making it easy to switch between providers or use multiple models for different purposes."}),"\n",(0,r.jsxs)(n.p,{children:["You can configure LLM settings in two locations within your Agent Mesh deployment. The ",(0,r.jsx)(n.code,{children:"apps.app_config.model"})," field allows you to specify model settings for individual agents or gateways, providing fine-grained control over which models specific components use. Alternatively, you can define models globally in the ",(0,r.jsx)(n.code,{children:"shared_config.yaml"})," file under the ",(0,r.jsx)(n.code,{children:"models"})," section, creating reusable configurations that multiple components can reference. For detailed information about the overall configuration structure and shared configuration management, see the ",(0,r.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/installing-and-configuring/configurations",children:"Configuring Agent Mesh"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"understanding-litellm-integration",children:"Understanding LiteLLM Integration"}),"\n",(0,r.jsxs)(n.p,{children:["Agent Mesh leverages ",(0,r.jsx)(n.a,{href:"https://docs.litellm.ai/docs/providers",children:"LiteLLM"})," to provide seamless integration with numerous LLM providers. This integration layer abstracts the differences between various provider APIs, allowing you to use a consistent configuration format regardless of whether you're connecting to OpenAI, Anthropic, Google, Amazon, or other supported providers."]}),"\n",(0,r.jsxs)(n.p,{children:["The configuration system passes all fields from the ",(0,r.jsx)(n.code,{children:"models"})," section directly to LiteLLM, giving you access to the full range of provider-specific options and features. This approach ensures that you can take advantage of advanced capabilities offered by different providers while maintaining a consistent configuration experience across your deployment."]}),"\n",(0,r.jsxs)(n.p,{children:["Environment variables provide a secure and flexible way to manage sensitive information such as API keys and endpoint URLs. The configuration system supports environment variable substitution using the format ",(0,r.jsx)(n.code,{children:"${ENV_VAR_NAME, default_value}"}),", allowing you to keep secrets out of your configuration files while providing sensible defaults for development environments."]}),"\n",(0,r.jsx)(n.h2,{id:"provider-specific-configurations",children:"Provider-Specific Configurations"}),"\n",(0,r.jsx)(n.h3,{id:"openai",children:"OpenAI"}),"\n",(0,r.jsx)(n.p,{children:"OpenAI provides some of the most widely-used language models, including the GPT series. The configuration requires minimal setup, needing only the model name and your API key. The system uses OpenAI's default endpoints automatically, simplifying the configuration process."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"model: gpt-5\napi_key: ${OPENAI_API_KEY}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["If your organization belongs to multiple OpenAI organizations, you can specify which organization to use by adding the ",(0,r.jsx)(n.code,{children:"organization"})," parameter. This parameter helps ensure billing and usage tracking align with your organizational structure."]}),"\n",(0,r.jsxs)(n.p,{children:["For comprehensive details about OpenAI-specific configuration options and advanced features, see the ",(0,r.jsx)(n.a,{href:"https://docs.litellm.ai/docs/providers/openai",children:"OpenAI documentation"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"azure-openai",children:"Azure OpenAI"}),"\n",(0,r.jsx)(n.p,{children:"Azure OpenAI Service provides OpenAI models through Microsoft's cloud infrastructure, offering additional enterprise features such as private networking and enhanced security controls. The configuration requires specifying your custom Azure endpoint, API key, and API version."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'model: azure/gpt-5\napi_base: ${AZURE_API_BASE,"https://your-custom-endpoint.openai.azure.com/"}\napi_key: ${AZURE_API_KEY}\napi_version: ${AZURE_API_VERSION,"2024-12-01-preview"}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The model name must include the ",(0,r.jsx)(n.code,{children:"azure/"})," prefix to indicate you're using Azure OpenAI rather than the standard OpenAI service. The API base URL points to your specific Azure OpenAI resource, which you configure during the Azure setup process."]}),"\n",(0,r.jsxs)(n.p,{children:["For detailed information about Azure-specific configuration options, deployment models, and enterprise features, see the ",(0,r.jsx)(n.a,{href:"https://docs.litellm.ai/docs/providers/azure/",children:"Azure OpenAI documentation"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"google-vertex-ai",children:"Google Vertex AI"}),"\n",(0,r.jsx)(n.p,{children:"Google Vertex AI provides access to both Google's own models and third-party models through a unified platform. This service offers enterprise-grade features including fine-tuning capabilities, model versioning, and integration with other Google Cloud services."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'model: vertex_ai/claude-sonnet-4@20250514\nvertex_project: ${VERTEX_PROJECT}\nvertex_location: ${VERTEX_LOCATION,"us-east5"}\nvertex_credentials: ${VERTEX_CREDENTIALS}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"vertex_credentials"})," parameter requires a JSON string containing your Google Cloud service account key. This credential provides the necessary authentication for accessing Vertex AI services. You can obtain this key from the Google Cloud Console by creating a service account with appropriate Vertex AI permissions."]}),"\n",(0,r.jsx)(n.p,{children:"An example of the credential structure follows this format:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'export VERTEX_CREDENTIALS=\'{"type": "", "project_id": "", "private_key_id": "", "private_key": "", "client_email": "", "client_id": "", "auth_uri": "", "token_uri": "", "auth_provider_x509_cert_url": "", "client_x509_cert_url": "", "universe_domain": ""}\'\n'})}),"\n",(0,r.jsxs)(n.p,{children:["For comprehensive information about Vertex AI configuration, available models, and advanced features, see the ",(0,r.jsx)(n.a,{href:"https://docs.litellm.ai/docs/providers/vertex",children:"Vertex AI documentation"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"amazon-bedrock",children:"Amazon Bedrock"}),"\n",(0,r.jsx)(n.p,{children:"Amazon Bedrock provides access to foundation models from various providers through AWS infrastructure. This service offers enterprise features such as private VPC connectivity, AWS IAM integration, and comprehensive logging through AWS CloudTrail."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0\naws_region_name: ${AWS_REGION_NAME,"us-east-1"}\naws_access_key_id: ${AWS_ACCESS_KEY_ID}\naws_secret_access_key: ${AWS_SECRET_ACCESS_KEY}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The model name includes the ",(0,r.jsx)(n.code,{children:"bedrock/"})," prefix followed by the specific model identifier as defined in the Bedrock service. AWS credentials follow standard AWS authentication patterns, allowing you to use IAM roles, environment variables, or credential files depending on your deployment environment."]}),"\n",(0,r.jsxs)(n.p,{children:["For detailed information about Bedrock-specific configuration options, available models, and AWS integration features, see the ",(0,r.jsx)(n.a,{href:"https://docs.litellm.ai/docs/providers/bedrock",children:"AWS Bedrock documentation"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"anthropic",children:"Anthropic"}),"\n",(0,r.jsx)(n.p,{children:"Anthropic provides the Claude family of models, known for their strong reasoning capabilities and helpful, harmless, and honest behavior. The direct Anthropic API offers the most up-to-date model versions and features."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"model: claude-4\napi_key: ${ANTHROPIC_API_KEY}\n"})}),"\n",(0,r.jsx)(n.p,{children:"The configuration requires only the model name and your Anthropic API key, making it straightforward to integrate Claude models into your agent workflows. Anthropic regularly updates their models with improved capabilities, and the direct API typically provides access to the latest versions first."}),"\n",(0,r.jsxs)(n.p,{children:["For comprehensive details about Anthropic-specific configuration options and model capabilities, see the ",(0,r.jsx)(n.a,{href:"https://docs.litellm.ai/docs/providers/anthropic",children:"Anthropic documentation"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"additional-providers",children:"Additional Providers"}),"\n",(0,r.jsx)(n.p,{children:"LiteLLM supports numerous other providers including Cohere, Hugging Face, Together AI, and many more. Each provider may have specific configuration requirements and capabilities, but the general pattern of specifying model names, endpoints, and authentication credentials remains consistent."}),"\n",(0,r.jsxs)(n.p,{children:["For a complete list of supported providers and their specific configuration requirements, see the ",(0,r.jsx)(n.a,{href:"https://docs.litellm.ai/docs/providers",children:"LiteLLM providers documentation"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"prompt-caching",children:"Prompt Caching"}),"\n",(0,r.jsx)(n.p,{children:"Agent Mesh supports prompt caching to significantly reduce costs and latency when using LLM providers that support this feature. Prompt caching allows frequently-used content such as system instructions and tool definitions to be cached by the LLM provider, reducing both processing time and token costs on subsequent requests."}),"\n",(0,r.jsx)(n.h3,{id:"how-prompt-caching-works",children:"How Prompt Caching Works"}),"\n",(0,r.jsx)(n.p,{children:"When you configure prompt caching, the system marks specific portions of each request for caching by the LLM provider. These cached portions persist for a provider-defined duration (typically 5 minutes to 1 hour) and can be reused across multiple requests without re-processing. This approach provides substantial cost savings for agents with large system instructions or extensive tool definitions."}),"\n",(0,r.jsx)(n.h3,{id:"supported-providers",children:"Supported Providers"}),"\n",(0,r.jsx)(n.p,{children:"The caching mechanism operates transparently through LiteLLM's provider-agnostic interface. Prompt caching support varies by provider:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Anthropic Claude"}),": Full support with explicit cache control, 90% cost reduction on cache hits"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"OpenAI"}),": Automatic caching for content exceeding 1,024 tokens"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Azure OpenAI"}),": Automatic caching following OpenAI behavior"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"AWS Bedrock"}),": Native caching support via LiteLLM translation"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Deepseek"}),": Native caching support via LiteLLM translation"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Providers without caching support safely ignore cache control markers, ensuring backward compatibility across all providers."}),"\n",(0,r.jsx)(n.h3,{id:"cache-strategy-configuration",children:"Cache Strategy Configuration"}),"\n",(0,r.jsx)(n.p,{children:"Agent Mesh provides three cache strategies that you can configure per model to optimize costs based on usage patterns:"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Strategy"}),(0,r.jsx)(n.th,{children:"Description"}),(0,r.jsx)(n.th,{children:"Cache Duration"}),(0,r.jsx)(n.th,{children:"Best For"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:'"5m"'})}),(0,r.jsx)(n.td,{children:"5-minute ephemeral cache"}),(0,r.jsx)(n.td,{children:"5 minutes"}),(0,r.jsx)(n.td,{children:"High-frequency agents (10+ calls/hour)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:'"1h"'})}),(0,r.jsx)(n.td,{children:"1-hour extended cache"}),(0,r.jsx)(n.td,{children:"1 hour"}),(0,r.jsx)(n.td,{children:"Burst patterns with gaps (3-10 calls/hour)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:'"none"'})}),(0,r.jsx)(n.td,{children:"Disable caching"}),(0,r.jsx)(n.td,{children:"N/A"}),(0,r.jsx)(n.td,{children:"Rarely-used agents (less than 2 calls/hour)"})]})]})]}),"\n",(0,r.jsxs)(n.p,{children:["The default strategy is ",(0,r.jsx)(n.code,{children:'"5m"'})," when not explicitly specified, providing optimal performance for most use cases without requiring configuration changes."]}),"\n",(0,r.jsx)(n.h3,{id:"configuration-examples",children:"Configuration Examples"}),"\n",(0,r.jsxs)(n.p,{children:["Configure prompt caching in your model settings using the ",(0,r.jsx)(n.code,{children:"cache_strategy"})," parameter:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'models:\n # High-frequency orchestrator with 5-minute cache\n planning:\n model: anthropic/claude-sonnet-4-5-20250929\n api_key: ${ANTHROPIC_API_KEY}\n cache_strategy: "5m"\n temperature: 0.1\n\n # Burst-pattern agent with 1-hour cache\n analysis:\n model: anthropic/claude-sonnet-4-5-20250929\n api_key: ${ANTHROPIC_API_KEY}\n cache_strategy: "1h"\n temperature: 0.7\n\n # Low-frequency agent with caching disabled\n maintenance:\n model: anthropic/claude-sonnet-4-5-20250929\n api_key: ${ANTHROPIC_API_KEY}\n cache_strategy: "none"\n'})}),"\n",(0,r.jsx)(n.h3,{id:"cache-strategy-selection-guidelines",children:"Cache Strategy Selection Guidelines"}),"\n",(0,r.jsx)(n.p,{children:"Choose your cache strategy based on agent usage patterns:"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:'Use "5m" strategy'})," when:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Agent receives 10 or more requests per hour"}),"\n",(0,r.jsx)(n.li,{children:"Requests arrive in steady streams rather than isolated bursts"}),"\n",(0,r.jsx)(n.li,{children:"Cache remains warm through continuous use"}),"\n",(0,r.jsx)(n.li,{children:"Example: Primary orchestrator agents handling user interactions"}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:'Use "1h" strategy'})," when:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Agent receives 3-10 requests per hour in burst patterns"}),"\n",(0,r.jsx)(n.li,{children:"Gaps between request bursts exceed 5 minutes"}),"\n",(0,r.jsx)(n.li,{children:"Extended cache duration bridges usage gaps"}),"\n",(0,r.jsx)(n.li,{children:"Example: Development and testing scenarios, periodic analysis agents"}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:'Use "none" strategy'})," when:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Agent receives fewer than 2 requests per hour"}),"\n",(0,r.jsx)(n.li,{children:"Cache write premium exceeds potential savings"}),"\n",(0,r.jsx)(n.li,{children:"System instructions change frequently"}),"\n",(0,r.jsx)(n.li,{children:"Example: Maintenance agents, backup handlers, rarely-used specialized agents"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"what-gets-cached",children:"What Gets Cached"}),"\n",(0,r.jsx)(n.p,{children:"The caching system optimizes two primary components of LLM requests:"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"System Instructions"}),": The complete agent system prompt, including capabilities, guidelines, and any static context. System instructions typically represent the largest cacheable content and provide the most significant cost savings."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Tool Definitions"}),": All tool declarations available to the agent, including peer agent communication tools. Agent Mesh ensures tool order stability through alphabetical sorting, maintaining cache validity across requests."]}),"\n",(0,r.jsx)(n.p,{children:"Conversation history and user messages are never cached, as these components change with each request and represent the unique context for each interaction."}),"\n",(0,r.jsx)(n.h3,{id:"cache-invalidation",children:"Cache Invalidation"}),"\n",(0,r.jsx)(n.p,{children:"The system automatically handles cache invalidation, requiring no manual intervention. When the cache expires or invalidates, the next request writes new cache content, and subsequent requests benefit from the refreshed cache."}),"\n",(0,r.jsx)(n.h2,{id:"oauth-20-authentication",children:"OAuth 2.0 Authentication"}),"\n",(0,r.jsx)(n.p,{children:"Agent Mesh supports OAuth 2.0 Client Credentials authentication for LLM providers that require OAuth-based authentication instead of traditional API keys. This authentication method provides enhanced security through automatic token management, secure credential handling, and seamless integration with OAuth-enabled LLM endpoints."}),"\n",(0,r.jsx)(n.h3,{id:"overview",children:"Overview"}),"\n",(0,r.jsxs)(n.p,{children:["The OAuth 2.0 Client Credentials flow is a machine-to-machine authentication method defined in ",(0,r.jsx)(n.a,{href:"https://tools.ietf.org/html/rfc6749#section-4.4",children:"RFC 6749"}),". Agent Mesh handles the complete OAuth lifecycle automatically, including token acquisition, caching, refresh, and injection into LLM requests. This implementation ensures secure and efficient authentication without requiring manual token management."]}),"\n",(0,r.jsx)(n.h3,{id:"configuration-parameters",children:"Configuration Parameters"}),"\n",(0,r.jsx)(n.p,{children:"OAuth authentication requires several configuration parameters that you can specify through environment variables and YAML configuration:"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Parameter"}),(0,r.jsx)(n.th,{children:"Required"}),(0,r.jsx)(n.th,{children:"Description"}),(0,r.jsx)(n.th,{children:"Default"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"oauth_token_url"})}),(0,r.jsx)(n.td,{children:"Yes"}),(0,r.jsx)(n.td,{children:"OAuth token endpoint URL"}),(0,r.jsx)(n.td,{children:"-"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"oauth_client_id"})}),(0,r.jsx)(n.td,{children:"Yes"}),(0,r.jsx)(n.td,{children:"OAuth client identifier"}),(0,r.jsx)(n.td,{children:"-"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"oauth_client_secret"})}),(0,r.jsx)(n.td,{children:"Yes"}),(0,r.jsx)(n.td,{children:"OAuth client secret"}),(0,r.jsx)(n.td,{children:"-"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"oauth_scope"})}),(0,r.jsx)(n.td,{children:"No"}),(0,r.jsx)(n.td,{children:"OAuth scope (space-separated)"}),(0,r.jsx)(n.td,{children:"None"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"oauth_ca_cert"})}),(0,r.jsx)(n.td,{children:"No"}),(0,r.jsx)(n.td,{children:"Custom CA certificate path for OAuth endpoint"}),(0,r.jsx)(n.td,{children:"None"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"oauth_token_refresh_buffer_seconds"})}),(0,r.jsx)(n.td,{children:"No"}),(0,r.jsx)(n.td,{children:"Seconds before expiration to refresh token"}),(0,r.jsx)(n.td,{children:"300"})]})]})]}),"\n",(0,r.jsx)(n.h3,{id:"environment-variables",children:"Environment Variables"}),"\n",(0,r.jsxs)(n.p,{children:["Configure OAuth credentials securely using environment variables in your ",(0,r.jsx)(n.code,{children:".env"})," file:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'# Required OAuth Configuration\nOAUTH_TOKEN_URL="https://auth.example.com/oauth/token"\nOAUTH_CLIENT_ID="your_client_id"\nOAUTH_CLIENT_SECRET="your_client_secret"\n\n# Optional OAuth Configuration\nOAUTH_SCOPE="llm.read llm.write"\nOAUTH_CA_CERT_PATH="/path/to/ca.crt"\nOAUTH_TOKEN_REFRESH_BUFFER_SECONDS="300"\n\n# LLM Endpoint Configuration\nOAUTH_LLM_API_BASE="https://api.example.com/v1"\n'})}),"\n",(0,r.jsx)(n.h3,{id:"yaml-configuration",children:"YAML Configuration"}),"\n",(0,r.jsxs)(n.p,{children:["Configure OAuth-authenticated models in your ",(0,r.jsx)(n.code,{children:"shared_config.yaml"})," file:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"models:\n # OAuth-authenticated planning model\n planning:\n model: ${OAUTH_LLM_PLANNING_MODEL_NAME}\n api_base: ${OAUTH_LLM_API_BASE}\n \n # OAuth 2.0 Client Credentials configuration\n oauth_token_url: ${OAUTH_TOKEN_URL}\n oauth_client_id: ${OAUTH_CLIENT_ID}\n oauth_client_secret: ${OAUTH_CLIENT_SECRET}\n oauth_scope: ${OAUTH_SCOPE}\n oauth_ca_cert: ${OAUTH_CA_CERT_PATH}\n oauth_token_refresh_buffer_seconds: ${OAUTH_TOKEN_REFRESH_BUFFER_SECONDS, 300}\n \n parallel_tool_calls: true\n temperature: 0.1\n\n # OAuth-authenticated general model\n general:\n model: ${OAUTH_LLM_GENERAL_MODEL_NAME}\n api_base: ${OAUTH_LLM_API_BASE}\n \n # OAuth 2.0 Client Credentials configuration\n oauth_token_url: ${OAUTH_TOKEN_URL}\n oauth_client_id: ${OAUTH_CLIENT_ID}\n oauth_client_secret: ${OAUTH_CLIENT_SECRET}\n oauth_scope: ${OAUTH_SCOPE}\n oauth_ca_cert: ${OAUTH_CA_CERT_PATH}\n oauth_token_refresh_buffer_seconds: ${OAUTH_TOKEN_REFRESH_BUFFER_SECONDS, 300}\n"})}),"\n",(0,r.jsx)(n.h3,{id:"error-handling-and-fallback",children:"Error Handling and Fallback"}),"\n",(0,r.jsx)(n.p,{children:"The OAuth system implements robust error handling:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"4xx Errors"}),": Client configuration errors result in no retries, as these indicate credential or configuration issues"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"5xx Errors"}),": Server errors trigger exponential backoff with jitter for up to 3 retry attempts"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Network Errors"}),": Connection issues trigger exponential backoff with jitter for up to 3 retry attempts"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["If OAuth authentication fails and an ",(0,r.jsx)(n.code,{children:"api_key"})," is configured in the model settings, the system automatically falls back to API key authentication and logs the OAuth failure. If no fallback is available, the request fails with the OAuth error."]}),"\n",(0,r.jsx)(n.h3,{id:"security-considerations",children:"Security Considerations"}),"\n",(0,r.jsx)(n.p,{children:"When implementing OAuth authentication, follow these security best practices:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Credential Storage"}),": Always store OAuth credentials securely using environment variables, never hardcode them in configuration files"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Token Caching"}),": Tokens are cached in memory only and never persisted to disk"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"SSL/TLS"}),": Always use HTTPS for OAuth endpoints to protect credentials in transit"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Custom CA Certificates"}),": Use the ",(0,r.jsx)(n.code,{children:"oauth_ca_cert"})," parameter for private or internal OAuth servers with custom certificate authorities"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Scope Limitation"}),": Request only the minimal OAuth scopes required for your LLM operations"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"troubleshooting-oauth-issues",children:"Troubleshooting OAuth Issues"}),"\n",(0,r.jsx)(n.p,{children:"Common OAuth authentication issues and their solutions:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Invalid Client Credentials"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"ERROR: OAuth token request failed with status 401: Invalid client credentials\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Verify that ",(0,r.jsx)(n.code,{children:"OAUTH_CLIENT_ID"})," and ",(0,r.jsx)(n.code,{children:"OAUTH_CLIENT_SECRET"})," are correct and properly URL-encoded if they contain special characters."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Invalid Scope"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"ERROR: OAuth token request failed with status 400: Invalid scope\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Verify that ",(0,r.jsx)(n.code,{children:"OAUTH_SCOPE"})," matches your provider's requirements and that scope values are space-separated."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"SSL Certificate Issues"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"ERROR: OAuth token request failed: SSL certificate verification failed\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Set ",(0,r.jsx)(n.code,{children:"OAUTH_CA_CERT_PATH"})," to point to your custom CA certificate file and verify the certificate chain is complete."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Token Refresh Issues"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"WARNING: OAuth token request failed (attempt 1/4): Connection timeout\n"})}),"\n",(0,r.jsx)(n.p,{children:"Check network connectivity to the OAuth endpoint, verify the OAuth endpoint URL is correct, and consider increasing timeout values if needed."}),"\n",(0,r.jsx)(n.h3,{id:"supported-providers-1",children:"Supported Providers"}),"\n",(0,r.jsxs)(n.p,{children:["This OAuth implementation works with any LLM provider that supports OAuth 2.0 Client Credentials flow, accepts Bearer tokens in the ",(0,r.jsx)(n.code,{children:"Authorization"})," header, and is compatible with LiteLLM's request format. Examples include Azure OpenAI with OAuth-enabled endpoints, custom enterprise LLM deployments, and third-party LLM services with OAuth support."]}),"\n",(0,r.jsx)(n.h2,{id:"security-and-ssltls-configuration",children:"Security and SSL/TLS Configuration"}),"\n",(0,r.jsx)(n.p,{children:"Agent Mesh provides comprehensive security controls for connections to LLM endpoints, allowing you to fine-tune SSL/TLS behavior to meet your organization's security requirements. These settings help ensure secure communication with LLM providers while providing flexibility for various network environments and security policies."}),"\n",(0,r.jsx)(n.p,{children:"The SSL verification setting controls whether the system validates SSL certificates when connecting to LLM endpoints. Although disabling verification can resolve connectivity issues in development environments, production deployments should always use proper SSL verification to maintain security."}),"\n",(0,r.jsx)(n.p,{children:"SSL security levels determine the cryptographic standards required for connections. Higher security levels enforce stricter requirements but may cause compatibility issues with older endpoints. The default level provides a good balance between security and compatibility for most deployments."}),"\n",(0,r.jsx)(n.p,{children:"Custom SSL certificates allow you to specify additional trusted certificate authorities or use self-signed certificates in controlled environments. You can provide certificates either as file paths or as direct certificate content in PEM format."}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Parameter"}),(0,r.jsx)(n.th,{children:"Type"}),(0,r.jsx)(n.th,{children:"Description"}),(0,r.jsx)(n.th,{children:"Default"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"SSL_VERIFY"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"boolean"})}),(0,r.jsx)(n.td,{children:"Controls SSL certificate verification for outbound connections."}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"true"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"SSL_SECURITY_LEVEL"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"integer"})}),(0,r.jsx)(n.td,{children:"Sets the SSL security level (higher values enforce stricter checks)."}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"2"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"SSL_CERT_FILE"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"string"})}),(0,r.jsx)(n.td,{children:"Path to a custom SSL certificate file to use for verification."}),(0,r.jsx)(n.td,{children:"(none)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"SSL_CERTIFICATE"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"string"})}),(0,r.jsx)(n.td,{children:"Direct content of the SSL certificate (PEM format)."}),(0,r.jsx)(n.td,{children:"(none)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"DISABLE_AIOHTTP_TRANSPORT"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"boolean"})}),(0,r.jsx)(n.td,{children:"Flag to disable the use of aiohttp transport for HTTP requests."}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"false"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"AIOHTTP_TRUST_ENV"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"boolean"})}),(0,r.jsx)(n.td,{children:"Flag to enable aiohttp to trust environment proxy settings."}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"false"})})]})]})]}),"\n",(0,r.jsx)(n.p,{children:"The HTTP transport settings control how the system makes network requests to LLM endpoints. The aiohttp transport provides efficient asynchronous HTTP handling, although some environments may require disabling it for compatibility reasons. The trust environment setting allows the HTTP client to use proxy settings from environment variables, which can be useful in corporate networks."}),"\n",(0,r.jsxs)(n.p,{children:["For detailed information about each security setting and specific use cases, see the ",(0,r.jsx)(n.a,{href:"https://docs.litellm.ai/docs/guides/security_settings",children:"LiteLLM security documentation"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"example-environment-configuration",children:"Example Environment Configuration"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'# SSL Configuration\nSSL_VERIFY=true\nSSL_SECURITY_LEVEL=2\nSSL_CERT_FILE=/path/to/your/certificate.pem\nSSL_CERTIFICATE="-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAg...T2u3V4w5X6y7Z8\n-----END CERTIFICATE-----"\n\n# HTTP Transport Configuration\nDISABLE_AIOHTTP_TRANSPORT=false\nAIOHTTP_TRUST_ENV=false\n'})}),"\n",(0,r.jsx)(n.p,{children:"This example demonstrates how to configure SSL settings through environment variables, providing a secure foundation for LLM communications while maintaining flexibility for different deployment scenarios. The certificate content should be replaced with your actual certificate data, and file paths should point to your specific certificate locations."})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>o,x:()=>a});var t=i(6540);const r={},s=t.createContext(r);function o(e){const n=t.useContext(s);return t.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(r):e.components||r:o(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]);
@@ -1 +1 @@
1
- "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[7798],{7098:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"documentation/enterprise/installation","title":"Installing Agent Mesh Enterprise","description":"This guide walks you through installing and running Agent Mesh Enterprise using Docker. You will download the enterprise image, load it into Docker, and launch a container configured for either development or production use.","source":"@site/docs/documentation/enterprise/installation.md","sourceDirName":"documentation/enterprise","slug":"/documentation/enterprise/installation","permalink":"/solace-agent-mesh/docs/documentation/enterprise/installation","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/enterprise/installation.md","tags":[],"version":"current","sidebarPosition":5,"frontMatter":{"title":"Installing Agent Mesh Enterprise","sidebar_position":5},"sidebar":"docSidebar","previous":{"title":"Agent Mesh Enterprise","permalink":"/solace-agent-mesh/docs/documentation/enterprise/"},"next":{"title":"Setting Up RBAC","permalink":"/solace-agent-mesh/docs/documentation/enterprise/rbac-setup-guide"}}');var o=t(4848),r=t(8453);const s={title:"Installing Agent Mesh Enterprise",sidebar_position:5},a=void 0,d={},l=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Understanding the Installation Process",id:"understanding-the-installation-process",level:2},{value:"Step 1: Download and Load the Enterprise Image",id:"step-1-download-and-load-the-enterprise-image",level:2},{value:"Step 2: Identify the Image Name",id:"step-2-identify-the-image-name",level:2},{value:"Step 3: Run the Container",id:"step-3-run-the-container",level:2},{value:"Running in Development Mode",id:"running-in-development-mode",level:3},{value:"Running in Production Mode",id:"running-in-production-mode",level:3},{value:"Accessing the Web UI",id:"accessing-the-web-ui",level:2},{value:"Troubleshooting and Debugging",id:"troubleshooting-and-debugging",level:2}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components},{Details:i}=n;return i||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,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.p,{children:"This guide walks you through installing and running Agent Mesh Enterprise using Docker. You will download the enterprise image, load it into Docker, and launch a container configured for either development or production use."}),"\n",(0,o.jsx)(n.admonition,{type:"tip",children:(0,o.jsxs)(n.p,{children:["All the ",(0,o.jsx)(n.code,{children:"docker"})," commands can also be run using any Docker-compatible tool, such as ",(0,o.jsx)(n.a,{href:"https://podman.io/",children:"Podman"}),"."]})}),"\n",(0,o.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,o.jsx)(n.p,{children:"Before you begin, ensure you have the following:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Docker installed on your system"}),"\n",(0,o.jsxs)(n.li,{children:["Access to the ",(0,o.jsx)(n.a,{href:"https://products.solace.com/prods/Agent_Mesh/Enterprise/",children:"Solace Product Portal"})]}),"\n",(0,o.jsx)(n.li,{children:"An LLM service API key and endpoint"}),"\n",(0,o.jsx)(n.li,{children:"For production deployments, Solace broker credentials"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"understanding-the-installation-process",children:"Understanding the Installation Process"}),"\n",(0,o.jsx)(n.p,{children:"The installation process consists of three main steps. First, you download and load the Docker image into your local Docker environment. This makes the Agent Mesh Enterprise software available on your system. Second, you identify the exact image name and tag that Docker assigned during the load process. You need this information to reference the correct image when starting your container. Finally, you run the container with the appropriate configuration for your use case\u2014either development mode with an embedded broker or production mode connected to an external Solace broker."}),"\n",(0,o.jsx)(n.h2,{id:"step-1-download-and-load-the-enterprise-image",children:"Step 1: Download and Load the Enterprise Image"}),"\n",(0,o.jsx)(n.p,{children:"You need to obtain the Agent Mesh Enterprise Docker image from the Solace Product Portal and load it into your Docker environment."}),"\n",(0,o.jsxs)(n.p,{children:["Download the latest enterprise docker image tarball from the ",(0,o.jsx)(n.a,{href:"https://products.solace.com/prods/Agent_Mesh/Enterprise/",children:"Solace Product Portal"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"After downloading the tarball, load the image into Docker. This command extracts the image from the compressed archive and makes it available in your local Docker image repository."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"docker load -i solace-agent-mesh-enterprise-<tag>.tar.gz\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Ensure you replace ",(0,o.jsx)(n.code,{children:"<tag>"})," with the appropriate version number from your downloaded file."]}),"\n",(0,o.jsx)(n.h2,{id:"step-2-identify-the-image-name",children:"Step 2: Identify the Image Name"}),"\n",(0,o.jsx)(n.p,{children:"After loading the image, you need to identify its full name and tag. Docker assigns a repository name and tag to the image during the load process, and you will use this information when running the container."}),"\n",(0,o.jsx)(n.p,{children:"Run the following command to list all Docker images on your system:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"docker images\n"})}),"\n",(0,o.jsx)(n.p,{children:"The output displays all available images with their repository names, tags, image IDs, creation dates, and sizes. Look for the Agent Mesh Enterprise image in the list."}),"\n",(0,o.jsx)(n.p,{children:"Example output:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"REPOSITORY TAG IMAGE ID CREATED SIZE\n868978040651.dkr.ecr.us-east-1.amazonaws.com/solace-agent-mesh-enterprise 1.0.37-c8890c7f31 2589d25d0917 9 days ago 5.25 GB\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Take note of the complete repository name and tag. You will need this full identifier when starting the container. In the example above, the complete image name is ",(0,o.jsx)(n.code,{children:"868978040651.dkr.ecr.us-east-1.amazonaws.com/solace-agent-mesh-enterprise:1.0.37-c8890c7f31"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["The numeric hashes at the beginning and end of the repository name (such as ",(0,o.jsx)(n.code,{children:"868978040651"})," and ",(0,o.jsx)(n.code,{children:"c8890c7f31"}),") vary between versions and builds. Your image will have different hash values."]}),"\n",(0,o.jsx)(n.h2,{id:"step-3-run-the-container",children:"Step 3: Run the Container"}),"\n",(0,o.jsx)(n.p,{children:"You can run Agent Mesh Enterprise in two different modes depending on your needs. Development mode uses an embedded Solace broker for quick testing and experimentation, while production mode connects to an external Solace broker for enterprise deployments."}),"\n",(0,o.jsx)(n.admonition,{type:"tip",children:(0,o.jsxs)(n.p,{children:["You may need to include ",(0,o.jsx)(n.code,{children:"--platform linux/amd64"})," depending on the host machine you're using."]})}),"\n",(0,o.jsx)(n.h3,{id:"running-in-development-mode",children:"Running in Development Mode"}),"\n",(0,o.jsx)(n.p,{children:"Development mode simplifies getting started by using an embedded Solace broker. This configuration requires fewer parameters and allows you to test Agent Mesh Enterprise without setting up external infrastructure. Use this mode for local development, testing, and evaluation."}),"\n",(0,o.jsxs)(n.p,{children:["The following command starts a container in development mode. The ",(0,o.jsx)(n.code,{children:"-itd"})," flags run the container in interactive mode with a pseudo-TTY, detached in the background. The ",(0,o.jsx)(n.code,{children:"-p 8001:8000"})," flag maps port 8000 inside the container to port 8001 on your host machine, making the web UI accessible at ",(0,o.jsx)(n.code,{children:"http://localhost:8001"}),"."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'docker run -itd -p 8001:8000 \\\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="true" \\\n --name sam-ent-dev \\\n solace-agent-mesh-enterprise:<tag>\n'})}),"\n",(0,o.jsx)(n.p,{children:"Replace the placeholder values with your actual configuration:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_LLM_TOKEN>"}),": Your API key for the LLM service"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_LLM_SERVICE_ENDPOINT>"}),": The URL endpoint for your LLM service"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_MODEL_NAME>"}),": The name of the LLM model you want to use (you can specify the same model for both planning and general tasks, or use different models)"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_NAMESPACE>"}),': A unique identifier for your deployment (such as "sam-dev")']}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<tag>"}),": The image tag you identified in Step 2"]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:'SOLACE_DEV_MODE="true"'})," environment variable tells the container to use the embedded broker instead of connecting to an external one."]}),"\n",(0,o.jsxs)(i,{children:[(0,o.jsx)("summary",{children:"Example"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'docker run -itd -p 8001:8000 \\\n -e LLM_SERVICE_API_KEY="<YOUR_LLM_TOKEN>" \\\n -e LLM_SERVICE_ENDPOINT="https://lite-llm.mymaas.net/" \\\n -e LLM_SERVICE_PLANNING_MODEL_NAME="openai/vertex-claude-4-sonnet" \\\n -e LLM_SERVICE_GENERAL_MODEL_NAME="openai/vertex-claude-4-sonnet" \\\n -e NAMESPACE="sam-dev" \\\n -e SOLACE_DEV_MODE="true" \\\n --name sam-ent-dev \\\n 868978040651.dkr.ecr.us-east-1.amazonaws.com/solace-agent-mesh-enterprise:1.0.37-c8890c7f31\n'})})]}),"\n",(0,o.jsx)(n.h3,{id:"running-in-production-mode",children:"Running in Production Mode"}),"\n",(0,o.jsx)(n.p,{children:"Production mode connects to an external Solace broker, which provides enterprise-grade messaging capabilities including high availability, disaster recovery, and scalability. Use this mode when deploying Agent Mesh Enterprise in production environments."}),"\n",(0,o.jsx)(n.p,{children:"The production configuration requires additional environment variables to specify the Solace broker connection details. These credentials allow the container to connect to your Solace Cloud service or on-premises broker."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'docker run -itd -p 8001:8000 \\\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 --name sam-ent-prod \\\n solace-agent-mesh-enterprise:<tag>\n'})}),"\n",(0,o.jsx)(n.p,{children:"Replace the placeholder values with your actual configuration. In addition to the LLM service parameters described in the development mode section, you need to provide:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_BROKER_URL>"}),": The secured SMF URI for your Solace broker"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_BROKER_VPN>"}),": The Message VPN name for your Solace service"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_BROKER_USERNAME>"}),": The username for broker authentication"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_BROKER_PASSWORD>"}),": The password for broker authentication"]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:'SOLACE_DEV_MODE="false"'})," environment variable tells the container to connect to the external broker specified by the other SOLACE_BROKER parameters instead of using the embedded broker."]}),"\n",(0,o.jsxs)(i,{children:[(0,o.jsx)("summary",{children:"How to find your credentials"}),(0,o.jsx)(n.p,{children:"Go to Solace Cloud."}),(0,o.jsx)(n.p,{children:"Cluster manager > Your Service > Connect"}),(0,o.jsx)(n.p,{children:"Switch dropdown to View by Language"}),(0,o.jsx)(n.p,{children:"Open the connect with Python dropdown"}),(0,o.jsx)(n.p,{children:"Click Solace Python with smf as the protocol."}),(0,o.jsx)(n.p,{children:"Copy:"}),(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Username for SOLACE_BROKER_USERNAME,"}),"\n",(0,o.jsx)(n.li,{children:"Password for SOLACE_BROKER_PASSWORD,"}),"\n",(0,o.jsx)(n.li,{children:"Message VPN for SOLACE_BROKER_VPN"}),"\n",(0,o.jsx)(n.li,{children:"Secured SMF URI for SOLACE_BROKER_URL"}),"\n"]}),(0,o.jsx)(n.p,{children:(0,o.jsx)(n.img,{alt:"How to get credentials",src:t(5981).A+"",width:"3456",height:"1916"})})]}),"\n",(0,o.jsx)(n.h2,{id:"accessing-the-web-ui",children:"Accessing the Web UI"}),"\n",(0,o.jsx)(n.p,{children:"After starting the container in either development or production mode, you can access the Agent Mesh Enterprise web interface through your browser. The UI provides a graphical interface for managing agents, monitoring activity, and configuring your deployment."}),"\n",(0,o.jsxs)(n.p,{children:["Navigate to ",(0,o.jsx)(n.code,{children:"http://localhost:8001"})," in your web browser. The port number corresponds to the host port you specified in the ",(0,o.jsx)(n.code,{children:"-p 8001:8000"})," flag when running the container."]}),"\n",(0,o.jsx)(n.h2,{id:"troubleshooting-and-debugging",children:"Troubleshooting and Debugging"}),"\n",(0,o.jsx)(n.p,{children:"If you encounter issues or need to investigate the behavior of your Agent Mesh Enterprise deployment, you can examine the log files generated by the container. These logs provide detailed information about system operations, errors, and debugging information."}),"\n",(0,o.jsxs)(n.p,{children:["To view logs, check the ",(0,o.jsx)(n.code,{children:".log"})," files in your container. For information about changing debug levels and advanced debugging techniques, see the debugging documentation at ",(0,o.jsx)(n.a,{href:"https://solacelabs.github.io/solace-agent-mesh/docs/documentation/deployment/debugging/",children:"https://solacelabs.github.io/solace-agent-mesh/docs/documentation/deployment/debugging/"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(c,{...e})}):c(e)}},5981:(e,n,t)=>{t.d(n,{A:()=>i});const i=t.p+"assets/images/sam-enterprise-credentials-b269f095349473118b2b33bdfcc40122.png"},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>a});var i=t(6540);const o={},r=i.createContext(o);function s(e){const n=i.useContext(r);return i.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(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]);
1
+ "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[7798],{7098:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>t,toc:()=>l});const t=JSON.parse('{"id":"documentation/enterprise/installation","title":"Installing Agent Mesh Enterprise","description":"This guide walks you through installing and running Agent Mesh Enterprise using Docker. You will download the enterprise image, load it into Docker, and launch a container configured for either development or production use.","source":"@site/docs/documentation/enterprise/installation.md","sourceDirName":"documentation/enterprise","slug":"/documentation/enterprise/installation","permalink":"/solace-agent-mesh/docs/documentation/enterprise/installation","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/enterprise/installation.md","tags":[],"version":"current","sidebarPosition":5,"frontMatter":{"title":"Installing Agent Mesh Enterprise","sidebar_position":5},"sidebar":"docSidebar","previous":{"title":"Agent Mesh Enterprise","permalink":"/solace-agent-mesh/docs/documentation/enterprise/"},"next":{"title":"Setting Up RBAC","permalink":"/solace-agent-mesh/docs/documentation/enterprise/rbac-setup-guide"}}');var o=i(4848),r=i(8453);const s={title:"Installing Agent Mesh Enterprise",sidebar_position:5},a=void 0,d={},l=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Understanding the Installation Process",id:"understanding-the-installation-process",level:2},{value:"Step 1: Download and Load the Enterprise Image",id:"step-1-download-and-load-the-enterprise-image",level:2},{value:"Step 2: Identify the Image Name",id:"step-2-identify-the-image-name",level:2},{value:"Step 3: Run the Container",id:"step-3-run-the-container",level:2},{value:"Running in Development Mode",id:"running-in-development-mode",level:3},{value:"Running in Production Mode",id:"running-in-production-mode",level:3},{value:"Accessing the Web UI",id:"accessing-the-web-ui",level:2},{value:"Troubleshooting and Debugging",id:"troubleshooting-and-debugging",level:2}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.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,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.p,{children:"This guide walks you through installing and running Agent Mesh Enterprise using Docker. You will download the enterprise image, load it into Docker, and launch a container configured for either development or production use."}),"\n",(0,o.jsx)(n.admonition,{type:"tip",children:(0,o.jsxs)(n.p,{children:["All the ",(0,o.jsx)(n.code,{children:"docker"})," commands can also be run using any Docker-compatible tool, such as ",(0,o.jsx)(n.a,{href:"https://podman.io/",children:"Podman"}),"."]})}),"\n",(0,o.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,o.jsx)(n.p,{children:"Before you begin, ensure you have the following:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Docker installed on your system"}),"\n",(0,o.jsxs)(n.li,{children:["Access to the ",(0,o.jsx)(n.a,{href:"https://products.solace.com/prods/Agent_Mesh/Enterprise/",children:"Solace Product Portal"})]}),"\n",(0,o.jsx)(n.li,{children:"An LLM service API key and endpoint"}),"\n",(0,o.jsx)(n.li,{children:"For production deployments, Solace broker credentials"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"understanding-the-installation-process",children:"Understanding the Installation Process"}),"\n",(0,o.jsx)(n.p,{children:"The installation process consists of three main steps. First, you download and load the Docker image into your local Docker environment. This makes the Agent Mesh Enterprise software available on your system. Second, you identify the exact image name and tag that Docker assigned during the load process. You need this information to reference the correct image when starting your container. Finally, you run the container with the appropriate configuration for your use case\u2014either development mode with an embedded broker or production mode connected to an external Solace broker."}),"\n",(0,o.jsx)(n.h2,{id:"step-1-download-and-load-the-enterprise-image",children:"Step 1: Download and Load the Enterprise Image"}),"\n",(0,o.jsx)(n.p,{children:"You need to obtain the Agent Mesh Enterprise Docker image from the Solace Product Portal and load it into your Docker environment."}),"\n",(0,o.jsxs)(n.p,{children:["Download the latest enterprise docker image tarball from the ",(0,o.jsx)(n.a,{href:"https://products.solace.com/prods/Agent_Mesh/Enterprise/",children:"Solace Product Portal"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"After downloading the tarball, load the image into Docker. This command extracts the image from the compressed archive and makes it available in your local Docker image repository."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"docker load -i solace-agent-mesh-enterprise-<tag>.tar.gz\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Ensure you replace ",(0,o.jsx)(n.code,{children:"<tag>"})," with the appropriate version number from your downloaded file."]}),"\n",(0,o.jsx)(n.h2,{id:"step-2-identify-the-image-name",children:"Step 2: Identify the Image Name"}),"\n",(0,o.jsx)(n.p,{children:"After loading the image, you need to identify its full name and tag. Docker assigns a repository name and tag to the image during the load process, and you will use this information when running the container."}),"\n",(0,o.jsx)(n.p,{children:"Run the following command to list all Docker images on your system:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"docker images\n"})}),"\n",(0,o.jsx)(n.p,{children:"The output displays all available images with their repository names, tags, image IDs, creation dates, and sizes. Look for the Agent Mesh Enterprise image in the list."}),"\n",(0,o.jsx)(n.p,{children:"Example output:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"REPOSITORY TAG IMAGE ID CREATED SIZE\n868978040651.dkr.ecr.us-east-1.amazonaws.com/solace-agent-mesh-enterprise 1.0.37-c8890c7f31 2589d25d0917 9 days ago 5.25 GB\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Take note of the complete repository name and tag. You will need this full identifier when starting the container. In the example above, the complete image name is ",(0,o.jsx)(n.code,{children:"868978040651.dkr.ecr.us-east-1.amazonaws.com/solace-agent-mesh-enterprise:1.0.37-c8890c7f31"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["The numeric hashes at the beginning and end of the repository name (such as ",(0,o.jsx)(n.code,{children:"868978040651"})," and ",(0,o.jsx)(n.code,{children:"c8890c7f31"}),") vary between versions and builds. Your image will have different hash values."]}),"\n",(0,o.jsx)(n.h2,{id:"step-3-run-the-container",children:"Step 3: Run the Container"}),"\n",(0,o.jsx)(n.p,{children:"You can run Agent Mesh Enterprise in two different modes depending on your needs. Development mode uses an embedded Solace broker for quick testing and experimentation, while production mode connects to an external Solace broker for enterprise deployments."}),"\n",(0,o.jsx)(n.admonition,{type:"tip",children:(0,o.jsxs)(n.p,{children:["You may need to include ",(0,o.jsx)(n.code,{children:"--platform linux/amd64"})," depending on the host machine you're using."]})}),"\n",(0,o.jsx)(n.h3,{id:"running-in-development-mode",children:"Running in Development Mode"}),"\n",(0,o.jsx)(n.p,{children:"Development mode simplifies getting started by using an embedded Solace broker. This configuration requires fewer parameters and allows you to test Agent Mesh Enterprise without setting up external infrastructure. Use this mode for local development, testing, and evaluation."}),"\n",(0,o.jsxs)(n.p,{children:["The following command starts a container in development mode. The ",(0,o.jsx)(n.code,{children:"-itd"})," flags run the container in interactive mode with a pseudo-TTY, detached in the background. The ",(0,o.jsx)(n.code,{children:"-p 8001:8000"})," flag maps port 8000 inside the container to port 8001 on your host machine, making the web UI accessible at ",(0,o.jsx)(n.code,{children:"http://localhost:8001"}),"."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'docker run -itd -p 8001:8000 \\\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="true" \\\n --name sam-ent-dev \\\n solace-agent-mesh-enterprise:<tag>\n'})}),"\n",(0,o.jsx)(n.p,{children:"Replace the placeholder values with your actual configuration:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_LLM_TOKEN>"}),": Your API key for the LLM service"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_LLM_SERVICE_ENDPOINT>"}),": The URL endpoint for your LLM service"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_MODEL_NAME>"}),": The name of the LLM model you want to use (you can specify the same model for both planning and general tasks, or use different models)"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_NAMESPACE>"}),': A unique identifier for your deployment (such as "sam-dev")']}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<tag>"}),": The image tag you identified in Step 2"]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:'SOLACE_DEV_MODE="true"'})," environment variable tells the container to use the embedded broker instead of connecting to an external one."]}),"\n",(0,o.jsxs)(t,{children:[(0,o.jsx)("summary",{children:"Example"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'docker run -itd -p 8001:8000 \\\n -e LLM_SERVICE_API_KEY="<YOUR_LLM_TOKEN>" \\\n -e LLM_SERVICE_ENDPOINT="https://lite-llm.mymaas.net/" \\\n -e LLM_SERVICE_PLANNING_MODEL_NAME="openai/vertex-claude-4-sonnet" \\\n -e LLM_SERVICE_GENERAL_MODEL_NAME="openai/vertex-claude-4-sonnet" \\\n -e NAMESPACE="sam-dev" \\\n -e SOLACE_DEV_MODE="true" \\\n --name sam-ent-dev \\\n 868978040651.dkr.ecr.us-east-1.amazonaws.com/solace-agent-mesh-enterprise:1.0.37-c8890c7f31\n'})})]}),"\n",(0,o.jsx)(n.h3,{id:"running-in-production-mode",children:"Running in Production Mode"}),"\n",(0,o.jsx)(n.p,{children:"Production mode connects to an external Solace broker, which provides enterprise-grade messaging capabilities including high availability, disaster recovery, and scalability. Use this mode when deploying Agent Mesh Enterprise in production environments."}),"\n",(0,o.jsx)(n.p,{children:"The production configuration requires additional environment variables to specify the Solace broker connection details. These credentials allow the container to connect to your Solace Cloud service or on-premises broker."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'docker run -itd -p 8001:8000 \\\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 --name sam-ent-prod \\\n solace-agent-mesh-enterprise:<tag>\n'})}),"\n",(0,o.jsx)(n.p,{children:"Replace the placeholder values with your actual configuration. In addition to the LLM service parameters described in the development mode section, you need to provide:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_BROKER_URL>"}),": The secured SMF URI for your Solace broker"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_BROKER_VPN>"}),": The Message VPN name for your Solace service"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_BROKER_USERNAME>"}),": The username for broker authentication"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"<YOUR_BROKER_PASSWORD>"}),": The password for broker authentication"]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:'SOLACE_DEV_MODE="false"'})," environment variable tells the container to connect to the external broker specified by the other SOLACE_BROKER parameters instead of using the embedded broker."]}),"\n",(0,o.jsxs)(t,{children:[(0,o.jsx)("summary",{children:"How to find your credentials"}),(0,o.jsx)(n.p,{children:"Go to Solace Cloud."}),(0,o.jsx)(n.p,{children:"Cluster manager > Your Service > Connect"}),(0,o.jsx)(n.p,{children:"Switch dropdown to View by Language"}),(0,o.jsx)(n.p,{children:"Open the connect with Python dropdown"}),(0,o.jsx)(n.p,{children:"Click Solace Python with smf as the protocol."}),(0,o.jsx)(n.p,{children:"Copy:"}),(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Username for SOLACE_BROKER_USERNAME,"}),"\n",(0,o.jsx)(n.li,{children:"Password for SOLACE_BROKER_PASSWORD,"}),"\n",(0,o.jsx)(n.li,{children:"Message VPN for SOLACE_BROKER_VPN"}),"\n",(0,o.jsx)(n.li,{children:"Secured SMF URI for SOLACE_BROKER_URL"}),"\n"]}),(0,o.jsx)(n.p,{children:(0,o.jsx)(n.img,{alt:"How to get credentials",src:i(5981).A+"",width:"3456",height:"1916"})})]}),"\n",(0,o.jsx)(n.h2,{id:"accessing-the-web-ui",children:"Accessing the Web UI"}),"\n",(0,o.jsx)(n.p,{children:"After starting the container in either development or production mode, you can access the Agent Mesh Enterprise web interface through your browser. The UI provides a graphical interface for managing agents, monitoring activity, and configuring your deployment."}),"\n",(0,o.jsxs)(n.p,{children:["Navigate to ",(0,o.jsx)(n.code,{children:"http://localhost:8001"})," in your web browser. The port number corresponds to the host port you specified in the ",(0,o.jsx)(n.code,{children:"-p 8001:8000"})," flag when running the container."]}),"\n",(0,o.jsx)(n.h2,{id:"troubleshooting-and-debugging",children:"Troubleshooting and Debugging"}),"\n",(0,o.jsx)(n.p,{children:"If you encounter issues or need to investigate the behavior of your Agent Mesh Enterprise deployment, you can examine the log files generated by the container. These logs provide detailed information about system operations, errors, and debugging information."}),"\n",(0,o.jsxs)(n.p,{children:["To view logs, check the ",(0,o.jsx)(n.code,{children:".log"})," files in your container. For information about changing debug levels and advanced debugging techniques, see ",(0,o.jsx)(n.a,{href:"../deploying/debugging",children:"Diagnosing and Resolving Problems"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(c,{...e})}):c(e)}},5981:(e,n,i)=>{i.d(n,{A:()=>t});const t=i.p+"assets/images/sam-enterprise-credentials-b269f095349473118b2b33bdfcc40122.png"},8453:(e,n,i)=>{i.d(n,{R:()=>s,x:()=>a});var t=i(6540);const o={},r=t.createContext(o);function s(e){const n=t.useContext(r);return t.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(o):e.components||o:s(e.components),t.createElement(r.Provider,{value:n},e.children)}}}]);
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[520],{2104:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>a,toc:()=>c});const a=JSON.parse('{"id":"documentation/components/gateways","title":"Gateways","description":"Gateways are a crucial component of the Agent Mesh framework that expose the agent mesh to external systems through various protocols. Built on a common base gateway architecture, they provide the following functions:","source":"@site/docs/documentation/components/gateways.md","sourceDirName":"documentation/components","slug":"/documentation/components/gateways","permalink":"/solace-agent-mesh/docs/documentation/components/gateways","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/components/gateways.md","tags":[],"version":"current","sidebarPosition":260,"frontMatter":{"title":"Gateways","sidebar_position":260},"sidebar":"docSidebar","previous":{"title":"Proxies","permalink":"/solace-agent-mesh/docs/documentation/components/proxies"},"next":{"title":"Plugins","permalink":"/solace-agent-mesh/docs/documentation/components/plugins"}}');var s=t(4848),o=t(8453);const i={title:"Gateways",sidebar_position:260},r="Gateways",l={},c=[{value:"Key Functions",id:"key-functions",level:2},{value:"How Gateways Work",id:"how-gateways-work",level:2},{value:"Available Gateways",id:"available-gateways",level:2},{value:"Core Gateways",id:"core-gateways",level:3},{value:"Plugin Gateways",id:"plugin-gateways",level:3},{value:"Create a Gateway",id:"create-a-gateway",level:2},{value:"Gateway from Scratch",id:"gateway-from-scratch",level:3}];function h(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",mermaid:"mermaid",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"gateways",children:"Gateways"})}),"\n",(0,s.jsx)(n.p,{children:"Gateways are a crucial component of the Agent Mesh framework that expose the agent mesh to external systems through various protocols. Built on a common base gateway architecture, they provide the following functions:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"serve as the primary interface between Agent Mesh and the outside world"}),"\n",(0,s.jsx)(n.li,{children:"manage the flow of information in and out of the system through the A2A protocol"}),"\n",(0,s.jsx)(n.li,{children:"handle authentication, user enrichment, and message processing"}),"\n",(0,s.jsx)(n.li,{children:"support multiple interface types including REST, HTTP SSE, webhooks, and event mesh connectivity"}),"\n"]}),"\n",(0,s.jsx)(n.admonition,{title:"In one sentence",type:"tip",children:(0,s.jsx)(n.p,{children:"Gateways are the external interfaces that connect various systems to the A2A agent mesh through standardized protocols."})}),"\n",(0,s.jsx)(n.h2,{id:"key-functions",children:"Key Functions"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Entry Points"}),": Gateways act as the entry points from the outside world and translate external requests into A2A protocol messages and route them through the Solace event mesh to appropriate agents."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Authentication & Authorization"}),": Common authentication and user enrichment flow across all gateway types, with pluggable identity providers."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Configurable System Purpose"}),": Each gateway has a configurable system purpose that sets the context for all stimuli entering Agent Mesh through that gateway. This design allows for tailored processing based on the specific use case or domain."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Customizable Output Formatting"}),": Gateways have a configurable output description that controls how stimuli responses are formatted when sent back to the outside world. This configurable output description ensures that the output meets the requirements of the receiving system or user interface."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Multiple Interface Types"}),": Gateways can have different interfaces to accommodate various communication protocols and systems. Some examples include REST APIs, event meshes, Slack integrations, browser-based interfaces, and so on."]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"how-gateways-work",children:"How Gateways Work"}),"\n",(0,s.jsx)(n.p,{children:"The following diagram illustrates the complete flow of information through a gateway in Agent Mesh:"}),"\n",(0,s.jsx)(n.mermaid,{value:"sequenceDiagram\n participant External as External System/User\n participant Gateway\n participant Mesh as Agent Mesh\n\n rect rgba(234, 234, 234, 1)\n Note over External,Gateway: Authentication Phase [Optional]\n External->>Gateway: Send Request\n Gateway->> Gateway: Authenticate Request\n alt Authentication Failed\n Gateway--\x3e>External: Return Error\n end\n end\n\n rect rgba(234, 234, 234, 1)\n Note over Gateway: Authorization Phase [Optional]\n end\n\n rect rgba(234, 234, 234, 1)\n Note over Gateway,Mesh: Processing Phase\n Gateway->>Gateway: Apply System Purpose\n Gateway->>Gateway: Attach Format Rules\n Gateway->>Gateway: Format Response\n Gateway->>Gateway: Transform to Stimulus\n Gateway->>Mesh: Send Stimulus\n\n alt Response Expected\n Mesh--\x3e>Gateway: Return Response\n Gateway--\x3e>External: Send Formatted Response\n end\n end\n\n %%{init: {\n 'theme': 'base',\n 'themeVariables': {\n 'actorBkg': '#00C895',\n 'actorBorder': '#00C895',\n 'actorTextColor': '#000000',\n 'noteBkgColor': '#FFF7C2',\n 'noteTextColor': '#000000',\n 'noteBorderColor': '#FFF7C2'\n }\n }}%%\n"}),"\n",(0,s.jsx)(n.h2,{id:"available-gateways",children:"Available Gateways"}),"\n",(0,s.jsx)(n.p,{children:"Agent Mesh comes with several built-in gateway types:"}),"\n",(0,s.jsx)(n.h3,{id:"core-gateways",children:"Core Gateways"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"HTTP SSE Gateway"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Real-time web interface with streaming responses"}),"\n",(0,s.jsx)(n.li,{children:"Server-sent events for live updates"}),"\n",(0,s.jsx)(n.li,{children:"Agent discovery API"}),"\n",(0,s.jsx)(n.li,{children:"File upload and download handling"}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"REST Gateway"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Task submission with immediate task ID return"}),"\n",(0,s.jsx)(n.li,{children:"Polling-based result retrieval"}),"\n",(0,s.jsx)(n.li,{children:"Authentication integration"}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Webhook Gateway"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Handles incoming webhook requests"}),"\n",(0,s.jsx)(n.li,{children:"Transforms webhook payloads to A2A messages"}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"plugin-gateways",children:"Plugin Gateways"}),"\n",(0,s.jsx)(n.p,{children:"Additional gateway types are available through the plugin ecosystem:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Event Mesh Gateway"}),": External event mesh connectivity with message transformation"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Slack Gateway"}),": Slack bot integration for team collaboration"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Custom Gateways"}),": Create your own gateway implementations"]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["For more information about plugins and how to configure them, see ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/components/plugins",children:"Plugins"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["One of the official core plugin gateway interfaces is the ",(0,s.jsx)(n.a,{href:"https://github.com/SolaceLabs/solace-agent-mesh-core-plugins/tree/main/sam-event-mesh-gateway",children:"Solace Event Mesh Gateway"}),", which enables communication with the PubSub+ event broker directly as an input interface."]}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsx)(n.p,{children:"Each gateway type has its own configuration options and specific features. See the individual gateway documentation pages for detailed information on setup and usage."})}),"\n",(0,s.jsx)(n.h2,{id:"create-a-gateway",children:"Create a Gateway"}),"\n",(0,s.jsxs)(n.p,{children:["To create a gateway, you can either ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/components/plugins#use-a-plugin",children:"use one of the pre-existing plugins"})," or create yours from scratch."]}),"\n",(0,s.jsx)(n.h3,{id:"gateway-from-scratch",children:"Gateway from Scratch"}),"\n",(0,s.jsxs)(n.p,{children:["To create a gateway from scratch, you need to use the CLI ",(0,s.jsx)(n.code,{children:"add gateway"})," command without any interfaces. This command creates a ",(0,s.jsx)(n.em,{children:"python gateway template file"})," which you can then customize to your needs."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"sam add gateway my-interface\n"})}),"\n",(0,s.jsxs)(n.p,{children:["To learn more about creating your own gateway, see ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/developing/create-gateways",children:"Create Custom Gateways"}),"."]}),"\n",(0,s.jsx)(n.admonition,{title:"Share and Reuse",type:"tip",children:(0,s.jsxs)(n.p,{children:["If you would like to share your custom gateway with the community or re-use it within other projects, you can create a plugin for it. For more information, see ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/components/plugins#create-a-plugin",children:"Create Plugins"}),"."]})})]})}function d(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>r});var a=t(6540);const s={},o=a.createContext(s);function i(e){const n=a.useContext(o);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:i(e.components),a.createElement(o.Provider,{value:n},e.children)}}}]);