solace-agent-mesh 1.6.3__py3-none-any.whl → 1.7.0__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (244) hide show
  1. solace_agent_mesh/agent/adk/adk_llm.txt +12 -18
  2. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +1 -1
  3. solace_agent_mesh/agent/adk/callbacks.py +138 -20
  4. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +2 -0
  5. solace_agent_mesh/agent/adk/models/lite_llm.py +38 -5
  6. solace_agent_mesh/agent/adk/models/models_llm.txt +82 -35
  7. solace_agent_mesh/agent/adk/runner.py +9 -0
  8. solace_agent_mesh/agent/adk/stream_parser.py +6 -1
  9. solace_agent_mesh/agent/adk/tool_wrapper.py +3 -0
  10. solace_agent_mesh/agent/agent_llm.txt +61 -70
  11. solace_agent_mesh/agent/protocol/event_handlers.py +29 -1
  12. solace_agent_mesh/agent/protocol/protocol_llm.txt +1 -1
  13. solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +190 -0
  14. solace_agent_mesh/agent/proxies/base/base_llm.txt +148 -0
  15. solace_agent_mesh/agent/proxies/proxies_llm.txt +283 -0
  16. solace_agent_mesh/agent/sac/app.py +22 -0
  17. solace_agent_mesh/agent/sac/component.py +76 -40
  18. solace_agent_mesh/agent/sac/sac_llm.txt +1 -1
  19. solace_agent_mesh/agent/sac/task_execution_context.py +21 -0
  20. solace_agent_mesh/agent/testing/testing_llm.txt +2 -1
  21. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +13 -148
  22. solace_agent_mesh/agent/tools/dynamic_tool.py +2 -0
  23. solace_agent_mesh/agent/tools/tools_llm.txt +93 -80
  24. solace_agent_mesh/agent/tools/tools_llm_detail.txt +3 -2
  25. solace_agent_mesh/agent/utils/artifact_helpers.py +4 -0
  26. solace_agent_mesh/agent/utils/utils_llm.txt +16 -2
  27. solace_agent_mesh/assets/docs/404.html +3 -3
  28. solace_agent_mesh/assets/docs/assets/js/05749d90.c70b2be9.js +1 -0
  29. solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +1 -0
  30. solace_agent_mesh/assets/docs/assets/js/15e40e79.36003774.js +1 -0
  31. solace_agent_mesh/assets/docs/assets/js/2987107d.a80604f9.js +1 -0
  32. solace_agent_mesh/assets/docs/assets/js/3ac1795d.e4870a49.js +1 -0
  33. solace_agent_mesh/assets/docs/assets/js/3ff0015d.b63ee53a.js +1 -0
  34. solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +1 -0
  35. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.45b32c2b.js +1 -0
  36. solace_agent_mesh/assets/docs/assets/js/631738c7.fa471607.js +1 -0
  37. solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +1 -0
  38. solace_agent_mesh/assets/docs/assets/js/6a520c9d.b6e3f2ce.js +1 -0
  39. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
  40. solace_agent_mesh/assets/docs/assets/js/71da7b71.374b9d54.js +1 -0
  41. solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +1 -0
  42. solace_agent_mesh/assets/docs/assets/js/8b032486.91a91afc.js +1 -0
  43. solace_agent_mesh/assets/docs/assets/js/94e8668d.09ed9234.js +1 -0
  44. solace_agent_mesh/assets/docs/assets/js/{ab9708a8.3e6dd091.js → ab9708a8.245ae0ef.js} +1 -1
  45. solace_agent_mesh/assets/docs/assets/js/ad87452a.9d73dad6.js +1 -0
  46. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.f902fad8.js +1 -0
  47. solace_agent_mesh/assets/docs/assets/js/da0b5bad.b62f7b08.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/dd817ffc.c37a755e.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
  51. solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.js +1 -0
  52. solace_agent_mesh/assets/docs/assets/js/e04b235d.c9c50c7b.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/e3d9abda.d11c67a7.js +1 -0
  54. solace_agent_mesh/assets/docs/assets/js/{e6f9706b.e74a984d.js → e6f9706b.045d0fa1.js} +1 -1
  55. solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +1 -0
  56. solace_agent_mesh/assets/docs/assets/js/f284c35a.5099c51e.js +1 -0
  57. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.74710fc1.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/main.e6488e8b.js +2 -0
  59. solace_agent_mesh/assets/docs/assets/js/runtime~main.d9606d6a.js +1 -0
  60. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +4 -4
  61. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +4 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +4 -4
  64. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +18 -4
  65. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +4 -4
  66. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +4 -4
  67. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +5 -5
  68. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +4 -4
  69. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +4 -4
  70. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +4 -4
  71. solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +196 -0
  72. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +4 -4
  73. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +5 -5
  74. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +6 -7
  75. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +4 -4
  76. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +47 -0
  77. solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +4 -4
  78. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +4 -4
  79. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +4 -4
  80. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +160 -169
  81. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +4 -4
  82. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +4 -4
  83. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +4 -4
  84. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +4 -4
  85. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +4 -4
  86. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +4 -4
  87. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +5 -5
  88. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +4 -4
  89. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +4 -4
  90. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +4 -4
  91. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +4 -4
  92. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +4 -4
  93. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +4 -4
  94. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +4 -4
  95. solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +59 -0
  96. solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +62 -0
  97. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +10 -6
  98. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +4 -4
  99. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +4 -4
  100. solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
  101. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +27 -4
  102. solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +62 -0
  103. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +4 -4
  104. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +5 -4
  105. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
  106. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +3 -3
  107. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +290 -0
  108. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +9 -9
  109. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +4 -4
  110. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +4 -4
  111. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +4 -4
  112. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +4 -4
  113. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +251 -0
  114. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +88 -0
  115. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
  116. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +3 -3
  117. solace_agent_mesh/assets/docs/lunr-index-1762189824009.json +1 -0
  118. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  119. solace_agent_mesh/assets/docs/search-doc-1762189824009.json +1 -0
  120. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  121. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  122. solace_agent_mesh/cli/__init__.py +1 -1
  123. solace_agent_mesh/cli/commands/docs_cmd.py +4 -1
  124. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +1 -1
  125. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-D4_RMYRh.js → authCallback-tcIFZLis.js} +1 -1
  126. solace_agent_mesh/client/webui/frontend/static/assets/{client-UZ3qU6Bq.js → client-CRYdKo2Q.js} +3 -3
  127. solace_agent_mesh/client/webui/frontend/static/assets/main-CojeY_1w.css +1 -0
  128. solace_agent_mesh/client/webui/frontend/static/assets/main-ILja9MCG.js +353 -0
  129. solace_agent_mesh/client/webui/frontend/static/assets/vendor-CINwxvwV.js +470 -0
  130. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  131. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  132. solace_agent_mesh/common/a2a/a2a_llm.txt +13 -20
  133. solace_agent_mesh/common/a2a/protocol.py +5 -0
  134. solace_agent_mesh/common/a2a/types.py +1 -0
  135. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +49 -11
  136. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +23 -6
  137. solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
  138. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +26 -9
  139. solace_agent_mesh/common/common_llm.txt +13 -34
  140. solace_agent_mesh/common/data_parts.py +20 -4
  141. solace_agent_mesh/common/middleware/middleware_llm.txt +1 -1
  142. solace_agent_mesh/common/sac/sac_llm.txt +1 -1
  143. solace_agent_mesh/common/sam_events/sam_events_llm.txt +1 -1
  144. solace_agent_mesh/common/services/employee_service.py +1 -1
  145. solace_agent_mesh/common/services/providers/providers_llm.txt +3 -2
  146. solace_agent_mesh/common/services/services_llm.txt +9 -4
  147. solace_agent_mesh/common/utils/embeds/constants.py +1 -0
  148. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +1 -1
  149. solace_agent_mesh/common/utils/embeds/modifiers.py +2 -1
  150. solace_agent_mesh/common/utils/embeds/resolver.py +58 -6
  151. solace_agent_mesh/common/utils/embeds/types.py +8 -0
  152. solace_agent_mesh/common/utils/utils_llm.txt +5 -6
  153. solace_agent_mesh/core_a2a/core_a2a_llm.txt +1 -1
  154. solace_agent_mesh/gateway/adapter/__init__.py +1 -0
  155. solace_agent_mesh/gateway/adapter/base.py +143 -0
  156. solace_agent_mesh/gateway/adapter/types.py +221 -0
  157. solace_agent_mesh/gateway/base/app.py +29 -2
  158. solace_agent_mesh/gateway/base/base_llm.txt +10 -8
  159. solace_agent_mesh/gateway/base/component.py +573 -142
  160. solace_agent_mesh/gateway/gateway_llm.txt +55 -59
  161. solace_agent_mesh/gateway/generic/__init__.py +1 -0
  162. solace_agent_mesh/gateway/generic/app.py +50 -0
  163. solace_agent_mesh/gateway/generic/component.py +650 -0
  164. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +99 -49
  165. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_fulltext_search_indexes.py +92 -0
  166. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_project_users_table.py +72 -0
  167. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +150 -0
  168. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +26 -0
  169. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_projects_table.py +135 -0
  170. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +26 -20
  171. solace_agent_mesh/gateway/http_sse/app.py +0 -14
  172. solace_agent_mesh/gateway/http_sse/component.py +17 -56
  173. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +1 -1
  174. solace_agent_mesh/gateway/http_sse/dependencies.py +21 -3
  175. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +8 -8
  176. solace_agent_mesh/gateway/http_sse/main.py +23 -5
  177. solace_agent_mesh/gateway/http_sse/repository/__init__.py +19 -1
  178. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +56 -98
  179. solace_agent_mesh/gateway/http_sse/repository/entities/project.py +81 -0
  180. solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +47 -0
  181. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +23 -1
  182. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +47 -0
  183. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +112 -4
  184. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -1
  185. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +51 -60
  186. solace_agent_mesh/gateway/http_sse/repository/models/project_model.py +51 -0
  187. solace_agent_mesh/gateway/http_sse/repository/models/project_user_model.py +75 -0
  188. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +7 -1
  189. solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
  190. solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
  191. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +125 -157
  192. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +269 -8
  193. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +143 -51
  194. solace_agent_mesh/gateway/http_sse/routers/config.py +69 -0
  195. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +198 -94
  196. solace_agent_mesh/gateway/http_sse/routers/dto/requests/project_requests.py +48 -0
  197. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +68 -18
  198. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +13 -0
  199. solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +30 -0
  200. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +51 -35
  201. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +2 -0
  202. solace_agent_mesh/gateway/http_sse/routers/feedback.py +133 -2
  203. solace_agent_mesh/gateway/http_sse/routers/projects.py +542 -0
  204. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +9 -11
  205. solace_agent_mesh/gateway/http_sse/routers/sessions.py +154 -3
  206. solace_agent_mesh/gateway/http_sse/routers/tasks.py +296 -4
  207. solace_agent_mesh/gateway/http_sse/services/project_service.py +403 -0
  208. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +16 -10
  209. solace_agent_mesh/gateway/http_sse/services/session_service.py +178 -6
  210. solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +2 -3
  211. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +48 -14
  212. solace_agent_mesh/solace_agent_mesh_llm.txt +1 -1
  213. {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.0.dist-info}/METADATA +3 -5
  214. {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.0.dist-info}/RECORD +218 -175
  215. solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +0 -1
  216. solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +0 -1
  217. solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +0 -1
  218. solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +0 -1
  219. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +0 -1
  220. solace_agent_mesh/assets/docs/assets/js/631738c7.7c4594c9.js +0 -1
  221. solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +0 -1
  222. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +0 -1
  223. solace_agent_mesh/assets/docs/assets/js/71da7b71.ddbdfbe2.js +0 -1
  224. solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.js +0 -1
  225. solace_agent_mesh/assets/docs/assets/js/94e8668d.3b883666.js +0 -1
  226. solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +0 -1
  227. solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +0 -1
  228. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +0 -1
  229. solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +0 -1
  230. solace_agent_mesh/assets/docs/assets/js/e3d9abda.6b9493d0.js +0 -1
  231. solace_agent_mesh/assets/docs/assets/js/e92d0134.4f395c6b.js +0 -1
  232. solace_agent_mesh/assets/docs/assets/js/f284c35a.720d2ef2.js +0 -1
  233. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +0 -1
  234. solace_agent_mesh/assets/docs/assets/js/main.ed05b14d.js +0 -2
  235. solace_agent_mesh/assets/docs/assets/js/runtime~main.a8a75e0b.js +0 -1
  236. solace_agent_mesh/assets/docs/lunr-index-1761744323675.json +0 -1
  237. solace_agent_mesh/assets/docs/search-doc-1761744323675.json +0 -1
  238. solace_agent_mesh/client/webui/frontend/static/assets/main--3yJYl7S.css +0 -1
  239. solace_agent_mesh/client/webui/frontend/static/assets/main-DojKHS49.js +0 -342
  240. solace_agent_mesh/client/webui/frontend/static/assets/vendor-DSqhjwq_.js +0 -405
  241. /solace_agent_mesh/assets/docs/assets/js/{main.ed05b14d.js.LICENSE.txt → main.e6488e8b.js.LICENSE.txt} +0 -0
  242. {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.0.dist-info}/WHEEL +0 -0
  243. {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.0.dist-info}/entry_points.txt +0 -0
  244. {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -5,6 +5,7 @@ Contains the main embed resolution functions, including the chain executor.
5
5
  import logging
6
6
  import asyncio
7
7
  import json
8
+ import uuid
8
9
  from typing import Any, Callable, Dict, Optional, Set, Tuple, List, Union
9
10
  from .constants import (
10
11
  EMBED_REGEX,
@@ -20,7 +21,7 @@ from .converter import (
20
21
  serialize_data,
21
22
  _parse_string_to_list_of_dicts,
22
23
  )
23
- from .types import DataFormat
24
+ from .types import DataFormat, ResolutionMode
24
25
  from ..mime_helpers import is_text_based_mime_type
25
26
 
26
27
  log = logging.getLogger(__name__)
@@ -85,10 +86,11 @@ async def _evaluate_artifact_content_embed_with_chain(
85
86
  output_format_from_directive: Optional[str],
86
87
  context: Any,
87
88
  log_identifier: str,
89
+ resolution_mode: "ResolutionMode",
88
90
  config: Optional[Dict] = None,
89
91
  current_depth: int = 0,
90
92
  visited_artifacts: Optional[Set[Tuple[str, int]]] = None,
91
- ) -> Tuple[str, Optional[str], int]:
93
+ ) -> Union[Tuple[str, Optional[str], int], Tuple[None, str, Any]]:
92
94
  """
93
95
  Loads artifact content, recursively resolves its internal embeds if text-based,
94
96
  applies a chain of modifiers, and serializes the final result.
@@ -167,6 +169,7 @@ async def _evaluate_artifact_content_embed_with_chain(
167
169
  context=context,
168
170
  resolver_func=evaluate_embed,
169
171
  types_to_resolve=EARLY_EMBED_TYPES.union(LATE_EMBED_TYPES),
172
+ resolution_mode=ResolutionMode.RECURSIVE_ARTIFACT_CONTENT,
170
173
  log_identifier=log_identifier,
171
174
  config=config,
172
175
  max_depth=config.get("gateway_recursive_embed_depth", 12),
@@ -422,6 +425,26 @@ async def _evaluate_artifact_content_embed_with_chain(
422
425
  err_msg = f"Unexpected error in modifier '{prefix}': {mod_err}"
423
426
  return f"[Error: {err_msg}]", err_msg, 0
424
427
 
428
+ if (
429
+ current_format == DataFormat.BYTES
430
+ and resolution_mode == ResolutionMode.A2A_MESSAGE_TO_USER
431
+ ):
432
+ log.info(
433
+ "%s [Depth:%d] Result is binary data in A2A_MESSAGE_TO_USER mode. Signaling for inline binary content.",
434
+ log_identifier,
435
+ current_depth,
436
+ )
437
+ filename_for_signal = artifact_spec_from_directive.split(":", 1)[0]
438
+ return (
439
+ None,
440
+ "SIGNAL_INLINE_BINARY_CONTENT",
441
+ {
442
+ "bytes": current_data,
443
+ "mime_type": original_mime_type,
444
+ "name": filename_for_signal,
445
+ },
446
+ )
447
+
425
448
  target_string_format = output_format_from_directive
426
449
  if target_string_format is None:
427
450
  log.warning(
@@ -486,9 +509,10 @@ async def resolve_embeds_in_string(
486
509
  ..., Union[Tuple[str, Optional[str], int], Tuple[None, str, Any]]
487
510
  ],
488
511
  types_to_resolve: Set[str],
512
+ resolution_mode: "ResolutionMode",
489
513
  log_identifier: str = "[EmbedUtil]",
490
514
  config: Optional[Dict[str, Any]] = None,
491
- ) -> Tuple[str, int, List[Tuple[int, Any]]]:
515
+ ) -> Tuple[str, int, List[Tuple[int, Any, str]]]:
492
516
  """
493
517
  Resolves specified embed types within a string using a provided resolver function.
494
518
  This is the TOP-LEVEL resolver called by gateways. It handles signals and buffering.
@@ -520,7 +544,7 @@ async def resolve_embeds_in_string(
520
544
  The index corresponds to the start index of the embed directive in the original string.
521
545
  """
522
546
  resolved_parts = []
523
- signals_found: List[Tuple[int, Any]] = []
547
+ signals_found: List[Tuple[int, Any, str]] = []
524
548
  last_end = 0
525
549
  original_length = len(text)
526
550
 
@@ -550,6 +574,7 @@ async def resolve_embeds_in_string(
550
574
  format_spec,
551
575
  context,
552
576
  log_identifier,
577
+ resolution_mode,
553
578
  config,
554
579
  )
555
580
 
@@ -566,10 +591,13 @@ async def resolve_embeds_in_string(
566
591
  signal_type,
567
592
  start,
568
593
  )
594
+ placeholder = f"__EMBED_SIGNAL_{uuid.uuid4().hex}__"
595
+ resolved_parts.append(placeholder)
569
596
  signals_found.append(
570
597
  (
571
598
  start,
572
599
  resolved_value,
600
+ placeholder,
573
601
  )
574
602
  )
575
603
  elif (
@@ -657,6 +685,7 @@ async def resolve_embeds_recursively_in_string(
657
685
  context: Any,
658
686
  resolver_func: Callable[..., Tuple[str, Optional[str], int]],
659
687
  types_to_resolve: Set[str],
688
+ resolution_mode: "ResolutionMode",
660
689
  log_identifier: str,
661
690
  config: Optional[Dict],
662
691
  max_depth: int,
@@ -709,6 +738,7 @@ async def resolve_embeds_recursively_in_string(
709
738
  format_spec,
710
739
  context,
711
740
  log_identifier,
741
+ resolution_mode,
712
742
  config,
713
743
  current_depth,
714
744
  visited_artifacts,
@@ -776,6 +806,7 @@ async def evaluate_embed(
776
806
  format_spec: Optional[str],
777
807
  context: Dict[str, Any],
778
808
  log_identifier: str,
809
+ resolution_mode: "ResolutionMode",
779
810
  config: Optional[Dict] = None,
780
811
  current_depth: int = 0,
781
812
  visited_artifacts: Optional[Set[Tuple[str, int]]] = None,
@@ -812,6 +843,26 @@ async def evaluate_embed(
812
843
  log.info("%s Detected 'status_update' embed. Signaling.", log_identifier)
813
844
  return (None, "SIGNAL_STATUS_UPDATE", status_text)
814
845
 
846
+ elif embed_type == "artifact_return":
847
+ if resolution_mode == ResolutionMode.A2A_MESSAGE_TO_USER:
848
+ parts = expression.strip().split(":", 1)
849
+ filename = parts[0]
850
+ version = parts[1] if len(parts) > 1 else "latest"
851
+ log.info("%s Detected 'artifact_return' embed. Signaling.", log_identifier)
852
+ return (
853
+ None,
854
+ "SIGNAL_ARTIFACT_RETURN",
855
+ {"filename": filename, "version": version},
856
+ )
857
+ else:
858
+ log.warning(
859
+ "%s Ignoring 'artifact_return' embed in unsupported context: %s",
860
+ log_identifier,
861
+ resolution_mode.name,
862
+ )
863
+ original_embed_text = f"«{embed_type}:{expression}»"
864
+ return original_embed_text, None, len(original_embed_text.encode("utf-8"))
865
+
815
866
  elif embed_type == "artifact_content":
816
867
  artifact_spec, modifiers, output_format = _parse_modifier_chain(expression)
817
868
  if output_format is None and format_spec is not None:
@@ -822,17 +873,18 @@ async def evaluate_embed(
822
873
  )
823
874
  output_format = format_spec
824
875
 
825
- final_string, error, size = await _evaluate_artifact_content_embed_with_chain(
876
+ result = await _evaluate_artifact_content_embed_with_chain(
826
877
  artifact_spec_from_directive=artifact_spec,
827
878
  modifiers_from_directive=modifiers,
828
879
  output_format_from_directive=output_format,
829
880
  context=context,
830
881
  log_identifier=log_identifier,
882
+ resolution_mode=resolution_mode,
831
883
  config=config,
832
884
  current_depth=current_depth,
833
885
  visited_artifacts=visited_artifacts or set(),
834
886
  )
835
- return final_string, error, size
887
+ return result
836
888
 
837
889
  else:
838
890
  evaluator = EMBED_EVALUATORS.get(embed_type)
@@ -5,6 +5,14 @@ Defines types used within the embed processing system, like DataFormat.
5
5
  from enum import Enum, auto
6
6
 
7
7
 
8
+ class ResolutionMode(Enum):
9
+ """Defines the context in which embed resolution is occurring."""
10
+
11
+ A2A_MESSAGE_TO_USER = auto()
12
+ TOOL_PARAMETER = auto()
13
+ RECURSIVE_ARTIFACT_CONTENT = auto()
14
+
15
+
8
16
  class DataFormat(Enum):
9
17
  """Represents internal data formats during modifier chain execution."""
10
18
 
@@ -1,3 +1,5 @@
1
+ # DEVELOPER GUIDE: utils
2
+
1
3
  ## Quick Summary
2
4
  The `utils` directory provides essential utility functions and tools for the Solace Agent Mesh system. It contains both direct utility files for common operations (MIME type handling, caching, message validation, authentication) and a sophisticated `embeds` subdirectory that implements a dynamic expression evaluation system. The utilities work together to provide platform compatibility, security features, data processing capabilities, and dynamic content generation for agent workflows.
3
5
 
@@ -119,6 +121,7 @@ The `utils` directory provides essential utility functions and tools for the Sol
119
121
  - `__setitem__(key: str, value: Any)` - Dict-like ['key'] = value assignment
120
122
  - `__contains__(key: str) -> bool` - Dict-like 'in' support
121
123
  - `keys()`, `values()`, `items()`, `__iter__()` - Dict-like iteration methods
124
+ - `pop(key: str, default: Any = None) -> Any` - Dict-like .pop() method
122
125
 
123
126
  #### type_utils.py
124
127
  **Purpose:** Utilities for robust type checking, especially in development environments
@@ -327,10 +330,6 @@ async def webhook_handler(request: Request):
327
330
  data = await request.json()
328
331
  # Process authenticated notification
329
332
  print(f"Received verified notification: {data}")
330
- return Response("OK")
331
- else:
332
- return Response("Unauthorized", status_code=401)
333
- except Exception as e:
334
- print(f"
333
+ return Response
335
334
 
336
- # content_hash: d80ffe631ca180ea5aacca592313af42838960a949c8664559a957c2492fa86f
335
+ # content_hash: c5bd94fc53429706fd6649d3dcf489665da150cfed54fd6961472c7b57dfc910
@@ -87,4 +87,4 @@ agent_card = AgentCard(name="new_agent", description="A new agent")
87
87
  service.process_discovery_message(agent_card)
88
88
  ```
89
89
 
90
- # content_hash: fcc947b32fa06db11f6cdf1064dfd9a68ee152373677a574602c182fc8c62f56
90
+ # content_hash: 64e02756b1b097e39257e8e52df701d758df0f8d022ea6d6b088057f7025a6d9
@@ -0,0 +1 @@
1
+ """Abstract base classes and types for the Generic Gateway Adapter Framework."""
@@ -0,0 +1,143 @@
1
+ """
2
+ Defines the abstract base class for Generic Gateway Adapters.
3
+ """
4
+
5
+ from abc import ABC, abstractmethod
6
+ from typing import Any, Dict, Generic, Optional, Type, TypeVar
7
+
8
+ from pydantic import BaseModel
9
+
10
+ from .types import (
11
+ AuthClaims,
12
+ GatewayContext,
13
+ ResponseContext,
14
+ SamDataPart,
15
+ SamError,
16
+ SamFilePart,
17
+ SamTask,
18
+ SamTextPart,
19
+ SamUpdate,
20
+ )
21
+
22
+ T_ExternalInput = TypeVar("T_ExternalInput", bound=Any)
23
+ T_PlatformContext = TypeVar("T_PlatformContext", bound=Dict[str, Any])
24
+ T_AdapterConfig = TypeVar("T_AdapterConfig", bound=BaseModel)
25
+
26
+
27
+ class GatewayAdapter(
28
+ ABC, Generic[T_ExternalInput, T_PlatformContext, T_AdapterConfig]
29
+ ):
30
+ """
31
+ Abstract base class for gateway adapter plugins.
32
+
33
+ Gateway adapters handle platform-specific communication while the
34
+ GenericGatewayComponent manages A2A protocol complexity.
35
+ """
36
+
37
+ ConfigModel: Optional[Type[BaseModel]] = None
38
+
39
+ # --- Lifecycle ---
40
+ async def init(self, context: GatewayContext) -> None:
41
+ """
42
+ Initialize the gateway adapter.
43
+
44
+ This is where you should:
45
+ - Start platform listeners (WebSocket, HTTP server, stdin reader, etc.)
46
+ - Connect to external services and store the context for later use.
47
+ """
48
+ pass
49
+
50
+ async def cleanup(self) -> None:
51
+ """
52
+ Clean up resources on shutdown.
53
+
54
+ This is where you should:
55
+ - Stop platform listeners, close connections, and release resources.
56
+ """
57
+ pass
58
+
59
+ # --- Authentication ---
60
+ async def extract_auth_claims(
61
+ self,
62
+ external_input: T_ExternalInput,
63
+ endpoint_context: Optional[Dict[str, Any]] = None,
64
+ ) -> Optional[AuthClaims]:
65
+ """
66
+ Extract authentication claims from platform input.
67
+
68
+ Return AuthClaims with user info/tokens, or None to use config-based auth.
69
+ """
70
+ return None
71
+
72
+ # --- Inbound: Platform -> A2A ---
73
+ @abstractmethod
74
+ async def prepare_task(
75
+ self,
76
+ external_input: T_ExternalInput,
77
+ endpoint_context: Optional[Dict[str, Any]] = None,
78
+ ) -> SamTask:
79
+ """
80
+ Prepare a task from platform input.
81
+
82
+ This method is called after authentication succeeds. Convert your
83
+ platform's event format into a SamTask with parts.
84
+ """
85
+ pass
86
+
87
+ # --- Outbound: A2A -> Platform ---
88
+ async def handle_update(self, update: SamUpdate, context: ResponseContext) -> None:
89
+ """
90
+ Handle an update from the agent (batch handler).
91
+
92
+ By default, this method dispatches to individual part handlers.
93
+ Override for custom batch processing.
94
+ """
95
+ for part in update.parts:
96
+ if isinstance(part, SamTextPart):
97
+ await self.handle_text_chunk(part.text, context)
98
+ elif isinstance(part, SamFilePart):
99
+ await self.handle_file(part, context)
100
+ elif isinstance(part, SamDataPart):
101
+ # Check for special data part types that have their own handlers
102
+ if part.data.get("type") == "agent_progress_update":
103
+ status_text = part.data.get("status_text")
104
+ if status_text:
105
+ await self.handle_status_update(status_text, context)
106
+ else:
107
+ # Fallback to the generic data part handler
108
+ await self.handle_data_part(part, context)
109
+
110
+ async def handle_text_chunk(self, text: str, context: ResponseContext) -> None:
111
+ """
112
+ Handle streaming text chunk from the agent.
113
+
114
+ This is called by the default `handle_update` implementation.
115
+ An adapter can override this method to process text parts individually.
116
+ """
117
+ pass
118
+
119
+ async def handle_file(
120
+ self, file_part: SamFilePart, context: ResponseContext
121
+ ) -> None:
122
+ """Handle file/artifact from the agent."""
123
+ pass
124
+
125
+ async def handle_data_part(
126
+ self, data_part: SamDataPart, context: ResponseContext
127
+ ) -> None:
128
+ """Handle structured data part from the agent."""
129
+ pass
130
+
131
+ async def handle_status_update(
132
+ self, status_text: str, context: ResponseContext
133
+ ) -> None:
134
+ """Handle agent status update (progress indicator)."""
135
+ pass
136
+
137
+ async def handle_task_complete(self, context: ResponseContext) -> None:
138
+ """Handle task completion notification."""
139
+ pass
140
+
141
+ async def handle_error(self, error: SamError, context: ResponseContext) -> None:
142
+ """Handle error from the agent or gateway."""
143
+ pass
@@ -0,0 +1,221 @@
1
+ """
2
+ Defines the Pydantic models for the Generic Gateway Adapter framework.
3
+
4
+ These types create a stable abstraction layer, decoupling gateway adapters from the
5
+ underlying A2A protocol specifics.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional, Union
11
+
12
+ from pydantic import BaseModel, Field, model_validator
13
+
14
+ if TYPE_CHECKING:
15
+ from google.adk.artifacts import BaseArtifactService
16
+ from ...common.a2a.types import ArtifactInfo
17
+
18
+
19
+ # --- Content Part Models ---
20
+
21
+
22
+ class SamTextPart(BaseModel):
23
+ """Text content in a SAM task."""
24
+
25
+ type: Literal["text"] = "text"
26
+ text: str
27
+
28
+
29
+ class SamFilePart(BaseModel):
30
+ """File content in a SAM task, with either inline bytes or a URI."""
31
+
32
+ type: Literal["file"] = "file"
33
+ name: str
34
+ content_bytes: Optional[bytes] = None
35
+ uri: Optional[str] = None
36
+ mime_type: Optional[str] = None
37
+
38
+ @model_validator(mode="after")
39
+ def validate_content_or_uri(self) -> "SamFilePart":
40
+ """Ensures that either content_bytes or uri is set, but not both."""
41
+ if not self.content_bytes and not self.uri:
42
+ raise ValueError("SamFilePart must have either 'content_bytes' or 'uri'.")
43
+ if self.content_bytes and self.uri:
44
+ raise ValueError("SamFilePart cannot have both 'content_bytes' and 'uri'.")
45
+ return self
46
+
47
+
48
+ class SamDataPart(BaseModel):
49
+ """Structured data in a SAM task."""
50
+
51
+ type: Literal["data"] = "data"
52
+ data: Dict[str, Any]
53
+ metadata: Optional[Dict[str, Any]] = None
54
+
55
+
56
+ SamContentPart = Union[SamTextPart, SamFilePart, SamDataPart]
57
+
58
+
59
+ # --- Task and Update Models ---
60
+
61
+
62
+ class SamTask(BaseModel):
63
+ """A task prepared for submission to the SAM agent mesh."""
64
+
65
+ parts: List[SamContentPart]
66
+ session_id: Optional[str] = None
67
+ target_agent: str = Field(..., description="Target agent name (required).")
68
+ is_streaming: bool = Field(default=True, description="Enable streaming responses.")
69
+ platform_context: Dict[str, Any] = Field(
70
+ default_factory=dict,
71
+ description="Platform-specific data for response routing.",
72
+ )
73
+
74
+
75
+ class SamUpdate(BaseModel):
76
+ """An update event from the agent containing one or more parts."""
77
+
78
+ parts: List[SamContentPart] = Field(default_factory=list)
79
+ is_final: bool = Field(
80
+ default=False,
81
+ description="True if this is the final update before task completion.",
82
+ )
83
+
84
+
85
+ # --- Auth and Error Models ---
86
+
87
+
88
+ class AuthClaims(BaseModel):
89
+ """Authentication claims extracted from a platform event."""
90
+
91
+ id: Optional[str] = Field(
92
+ default=None,
93
+ description="Primary user identifier. If None, generic gateway uses auth_config default.",
94
+ )
95
+ email: Optional[str] = None
96
+ token: Optional[str] = Field(
97
+ default=None, description="Bearer token or API key for token-based auth flows."
98
+ )
99
+ token_type: Optional[Literal["bearer", "api_key"]] = None
100
+ source: str = Field(default="platform", description="Authentication source.")
101
+ raw_context: Dict[str, Any] = Field(
102
+ default_factory=dict, description="Platform-specific auth context."
103
+ )
104
+
105
+
106
+ class SamError(BaseModel):
107
+ """A structured error object for outbound error handling."""
108
+
109
+ message: str
110
+ code: int
111
+ category: Literal[
112
+ "FAILED", "CANCELED", "TIMED_OUT", "PROTOCOL_ERROR", "GATEWAY_ERROR"
113
+ ]
114
+
115
+
116
+ class SamFeedback(BaseModel):
117
+ """A structured model for submitting user feedback."""
118
+
119
+ task_id: str
120
+ session_id: str
121
+ rating: Literal["up", "down"]
122
+ comment: Optional[str] = None
123
+ user_id: str
124
+
125
+
126
+ # --- Context Models ---
127
+
128
+
129
+ class ResponseContext(BaseModel):
130
+ """Context provided with each outbound response callback."""
131
+
132
+ task_id: str
133
+ session_id: Optional[str]
134
+ user_id: str
135
+ platform_context: Dict[str, Any]
136
+
137
+
138
+ class GatewayContext:
139
+ """
140
+ Context provided to gateway adapter during initialization.
141
+
142
+ Provides access to gateway services and helper methods.
143
+ This is an abstract class definition; the concrete implementation is the
144
+ GenericGatewayComponent.
145
+ """
146
+
147
+ gateway_id: str
148
+ namespace: str
149
+ config: Dict[str, Any]
150
+ adapter_config: Any # Can be a Pydantic model or a dict
151
+ artifact_service: "BaseArtifactService"
152
+
153
+ async def handle_external_input(
154
+ self, external_input: Any, endpoint_context: Optional[Dict[str, Any]] = None
155
+ ) -> str:
156
+ raise NotImplementedError
157
+
158
+ async def cancel_task(self, task_id: str) -> None:
159
+ raise NotImplementedError
160
+
161
+ async def submit_feedback(self, feedback: "SamFeedback") -> None:
162
+ """Submits user feedback related to a task."""
163
+ raise NotImplementedError
164
+
165
+ async def load_artifact_content(
166
+ self, context: "ResponseContext", filename: str, version: Union[int, str] = "latest"
167
+ ) -> Optional[bytes]:
168
+ """Loads the raw byte content of an artifact."""
169
+ raise NotImplementedError
170
+
171
+ async def list_artifacts(
172
+ self, context: "ResponseContext"
173
+ ) -> List["ArtifactInfo"]:
174
+ """Lists all artifacts available in the user's context."""
175
+ raise NotImplementedError
176
+
177
+ def add_timer(
178
+ self, delay_ms: int, callback: "Callable", interval_ms: Optional[int] = None
179
+ ) -> str:
180
+ raise NotImplementedError
181
+
182
+ def cancel_timer(self, timer_id: str) -> None:
183
+ raise NotImplementedError
184
+
185
+ def get_task_state(self, task_id: str, key: str, default: Any = None) -> Any:
186
+ raise NotImplementedError
187
+
188
+ def set_task_state(self, task_id: str, key: str, value: Any) -> None:
189
+ raise NotImplementedError
190
+
191
+ def get_session_state(self, session_id: str, key: str, default: Any = None) -> Any:
192
+ raise NotImplementedError
193
+
194
+ def set_session_state(self, session_id: str, key: str, value: Any) -> None:
195
+ raise NotImplementedError
196
+
197
+ def create_text_part(self, text: str) -> SamTextPart:
198
+ return SamTextPart(text=text)
199
+
200
+ def create_file_part_from_bytes(
201
+ self, name: str, content_bytes: bytes, mime_type: str
202
+ ) -> SamFilePart:
203
+ return SamFilePart(name=name, content_bytes=content_bytes, mime_type=mime_type)
204
+
205
+ def create_file_part_from_uri(
206
+ self, uri: str, name: str, mime_type: Optional[str] = None
207
+ ) -> SamFilePart:
208
+ return SamFilePart(name=name, uri=uri, mime_type=mime_type)
209
+
210
+ def create_data_part(self, data: Dict[str, Any]) -> SamDataPart:
211
+ return SamDataPart(data=data)
212
+
213
+ def process_sac_template(
214
+ self,
215
+ template: str,
216
+ payload: Any = None,
217
+ headers: Optional[Dict[str, str]] = None,
218
+ query_params: Optional[Dict[str, str]] = None,
219
+ user_data: Optional[Dict[str, Any]] = None,
220
+ ) -> str:
221
+ raise NotImplementedError
@@ -39,6 +39,27 @@ BASE_GATEWAY_APP_SCHEMA: Dict[str, List[Dict[str, Any]]] = {
39
39
  "default": None,
40
40
  "description": "Unique ID for this gateway instance. Auto-generated if omitted.",
41
41
  },
42
+ {
43
+ "name": "default_agent_name",
44
+ "required": False,
45
+ "type": "string",
46
+ "default": None,
47
+ "description": "Default agent to route messages to if not specified by the platform or user.",
48
+ },
49
+ {
50
+ "name": "system_purpose",
51
+ "required": False,
52
+ "type": "string",
53
+ "default": "",
54
+ "description": "Detailed description of the system's overall purpose, to be optionally used by agents.",
55
+ },
56
+ {
57
+ "name": "response_format",
58
+ "required": False,
59
+ "type": "string",
60
+ "default": "",
61
+ "description": "General guidelines on how agent responses should be structured, to be optionally used by agents.",
62
+ },
42
63
  {
43
64
  "name": "artifact_service",
44
65
  "required": True,
@@ -144,8 +165,14 @@ class BaseGatewayApp(App):
144
165
 
145
166
  base_params = BaseGatewayApp.app_schema.get("config_parameters", [])
146
167
 
147
- merged_config_parameters = list(base_params)
148
- merged_config_parameters.extend(specific_params)
168
+ # Start with the child's parameters to give them precedence.
169
+ merged_config_parameters = list(specific_params)
170
+ specific_param_names = {p["name"] for p in specific_params}
171
+
172
+ # Add base parameters only if they are not already defined in the child.
173
+ for base_param in base_params:
174
+ if base_param["name"] not in specific_param_names:
175
+ merged_config_parameters.append(base_param)
149
176
 
150
177
  cls.app_schema = {"config_parameters": merged_config_parameters}
151
178
  log.debug(