solace-agent-mesh 0.2.4__py3-none-any.whl → 1.0.2__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 (521) hide show
  1. solace_agent_mesh/__init__.py +5 -0
  2. solace_agent_mesh/agent/adk/adk_llm.txt +93 -0
  3. solace_agent_mesh/agent/adk/app_llm_agent.py +26 -0
  4. solace_agent_mesh/agent/adk/callbacks.py +1716 -0
  5. solace_agent_mesh/agent/adk/filesystem_artifact_service.py +381 -0
  6. solace_agent_mesh/agent/adk/invocation_monitor.py +295 -0
  7. solace_agent_mesh/agent/adk/models/lite_llm.py +872 -0
  8. solace_agent_mesh/agent/adk/models/models_llm.txt +94 -0
  9. solace_agent_mesh/agent/adk/runner.py +357 -0
  10. solace_agent_mesh/agent/adk/services.py +240 -0
  11. solace_agent_mesh/agent/adk/setup.py +751 -0
  12. solace_agent_mesh/agent/adk/stream_parser.py +214 -0
  13. solace_agent_mesh/agent/adk/tool_wrapper.py +139 -0
  14. solace_agent_mesh/agent/agent_llm.txt +41 -0
  15. solace_agent_mesh/agent/protocol/event_handlers.py +1444 -0
  16. solace_agent_mesh/agent/protocol/protocol_llm.txt +21 -0
  17. solace_agent_mesh/agent/sac/app.py +640 -0
  18. solace_agent_mesh/agent/sac/component.py +3496 -0
  19. solace_agent_mesh/agent/sac/patch_adk.py +111 -0
  20. solace_agent_mesh/agent/sac/sac_llm.txt +105 -0
  21. solace_agent_mesh/agent/sac/task_execution_context.py +185 -0
  22. solace_agent_mesh/agent/testing/__init__.py +3 -0
  23. solace_agent_mesh/agent/testing/debug_utils.py +135 -0
  24. solace_agent_mesh/agent/testing/testing_llm.txt +90 -0
  25. solace_agent_mesh/agent/tools/__init__.py +14 -0
  26. solace_agent_mesh/agent/tools/audio_tools.py +1622 -0
  27. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +1954 -0
  28. solace_agent_mesh/agent/tools/builtin_data_analysis_tools.py +238 -0
  29. solace_agent_mesh/agent/tools/general_agent_tools.py +571 -0
  30. solace_agent_mesh/agent/tools/image_tools.py +1184 -0
  31. solace_agent_mesh/agent/tools/peer_agent_tool.py +290 -0
  32. solace_agent_mesh/agent/tools/registry.py +36 -0
  33. solace_agent_mesh/agent/tools/test_tools.py +135 -0
  34. solace_agent_mesh/agent/tools/tool_definition.py +45 -0
  35. solace_agent_mesh/agent/tools/tools_llm.txt +104 -0
  36. solace_agent_mesh/agent/tools/web_tools.py +381 -0
  37. solace_agent_mesh/agent/utils/artifact_helpers.py +927 -0
  38. solace_agent_mesh/agent/utils/config_parser.py +47 -0
  39. solace_agent_mesh/agent/utils/context_helpers.py +60 -0
  40. solace_agent_mesh/agent/utils/utils_llm.txt +153 -0
  41. solace_agent_mesh/assets/docs/404.html +16 -0
  42. solace_agent_mesh/assets/docs/assets/css/styles.906a1503.css +1 -0
  43. solace_agent_mesh/assets/docs/assets/images/Solace_AI_Framework_With_Broker-85f0a306a9bcdd20b390b7a949f6d862.png +0 -0
  44. solace_agent_mesh/assets/docs/assets/images/sac-flows-80d5b603c6aafd33e87945680ce0abf3.png +0 -0
  45. solace_agent_mesh/assets/docs/assets/images/sac_parts_of_a_component-cb3d0424b1d0c17734c5435cca6b4082.png +0 -0
  46. solace_agent_mesh/assets/docs/assets/js/04989206.674a8007.js +1 -0
  47. solace_agent_mesh/assets/docs/assets/js/0e682baa.79f0ab22.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/1001.0182a8bd.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/1023fc19.015679ca.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/1039.0bd46aa1.js +1 -0
  51. solace_agent_mesh/assets/docs/assets/js/149.b797a808.js +1 -0
  52. solace_agent_mesh/assets/docs/assets/js/1523c6b4.91c7bc01.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/165.6a39807d.js +2 -0
  54. solace_agent_mesh/assets/docs/assets/js/165.6a39807d.js.LICENSE.txt +9 -0
  55. solace_agent_mesh/assets/docs/assets/js/166ab619.7d97ccaf.js +1 -0
  56. solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +2 -0
  57. solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js.LICENSE.txt +7 -0
  58. solace_agent_mesh/assets/docs/assets/js/1c6e87d2.a8c5ce5a.js +1 -0
  59. solace_agent_mesh/assets/docs/assets/js/2130.ab9fd314.js +1 -0
  60. solace_agent_mesh/assets/docs/assets/js/21ceee5f.614fa8dd.js +1 -0
  61. solace_agent_mesh/assets/docs/assets/js/2237.5e477fc6.js +1 -0
  62. solace_agent_mesh/assets/docs/assets/js/2334.622a6395.js +1 -0
  63. solace_agent_mesh/assets/docs/assets/js/2a9cab12.8909df92.js +1 -0
  64. solace_agent_mesh/assets/docs/assets/js/3219.adc1d663.js +1 -0
  65. solace_agent_mesh/assets/docs/assets/js/332e10b5.7a103f42.js +1 -0
  66. solace_agent_mesh/assets/docs/assets/js/3624.b524e433.js +1 -0
  67. solace_agent_mesh/assets/docs/assets/js/375.708d48db.js +1 -0
  68. solace_agent_mesh/assets/docs/assets/js/3834.b6cd790e.js +1 -0
  69. solace_agent_mesh/assets/docs/assets/js/3d406171.f722eaf5.js +1 -0
  70. solace_agent_mesh/assets/docs/assets/js/4250.95455b28.js +1 -0
  71. solace_agent_mesh/assets/docs/assets/js/42b3f8d8.36090198.js +1 -0
  72. solace_agent_mesh/assets/docs/assets/js/4356.d169ab5b.js +1 -0
  73. solace_agent_mesh/assets/docs/assets/js/442a8107.5ba94b65.js +1 -0
  74. solace_agent_mesh/assets/docs/assets/js/4458.518e66fa.js +1 -0
  75. solace_agent_mesh/assets/docs/assets/js/4488.c7cc3442.js +1 -0
  76. solace_agent_mesh/assets/docs/assets/js/4494.6ee23046.js +1 -0
  77. solace_agent_mesh/assets/docs/assets/js/4855.fc4444b6.js +1 -0
  78. solace_agent_mesh/assets/docs/assets/js/4866.22daefc0.js +1 -0
  79. solace_agent_mesh/assets/docs/assets/js/4950.ca4caeda.js +1 -0
  80. solace_agent_mesh/assets/docs/assets/js/4c2787c2.66ee00e9.js +1 -0
  81. solace_agent_mesh/assets/docs/assets/js/5388.7a136447.js +1 -0
  82. solace_agent_mesh/assets/docs/assets/js/55f47984.c484bf96.js +1 -0
  83. solace_agent_mesh/assets/docs/assets/js/5607.081356f8.js +1 -0
  84. solace_agent_mesh/assets/docs/assets/js/5864.b0d0e9de.js +1 -0
  85. solace_agent_mesh/assets/docs/assets/js/5b4258a4.bda20761.js +1 -0
  86. solace_agent_mesh/assets/docs/assets/js/5e95c892.558d5167.js +1 -0
  87. solace_agent_mesh/assets/docs/assets/js/6143.0a1464c9.js +1 -0
  88. solace_agent_mesh/assets/docs/assets/js/6395.e9c73649.js +1 -0
  89. solace_agent_mesh/assets/docs/assets/js/6796.51d2c9b7.js +1 -0
  90. solace_agent_mesh/assets/docs/assets/js/6976.379be23b.js +1 -0
  91. solace_agent_mesh/assets/docs/assets/js/6978.ee0b945c.js +1 -0
  92. solace_agent_mesh/assets/docs/assets/js/7040.cb436723.js +1 -0
  93. solace_agent_mesh/assets/docs/assets/js/7195.412f418a.js +1 -0
  94. solace_agent_mesh/assets/docs/assets/js/7280.3fb73bdb.js +1 -0
  95. solace_agent_mesh/assets/docs/assets/js/768e31b0.a12673db.js +1 -0
  96. solace_agent_mesh/assets/docs/assets/js/7845.e33e7c4c.js +1 -0
  97. solace_agent_mesh/assets/docs/assets/js/7900.69516146.js +1 -0
  98. solace_agent_mesh/assets/docs/assets/js/8356.8a379c04.js +1 -0
  99. solace_agent_mesh/assets/docs/assets/js/85387663.6bf41934.js +1 -0
  100. solace_agent_mesh/assets/docs/assets/js/8567.4732c6b7.js +1 -0
  101. solace_agent_mesh/assets/docs/assets/js/8573.cb04eda5.js +1 -0
  102. solace_agent_mesh/assets/docs/assets/js/8577.1d54e766.js +1 -0
  103. solace_agent_mesh/assets/docs/assets/js/8591.d7c16be6.js +2 -0
  104. solace_agent_mesh/assets/docs/assets/js/8591.d7c16be6.js.LICENSE.txt +61 -0
  105. solace_agent_mesh/assets/docs/assets/js/8709.7ecd4047.js +1 -0
  106. solace_agent_mesh/assets/docs/assets/js/8731.49e930c2.js +1 -0
  107. solace_agent_mesh/assets/docs/assets/js/8908.f9d1b506.js +1 -0
  108. solace_agent_mesh/assets/docs/assets/js/9157.b4093d07.js +1 -0
  109. solace_agent_mesh/assets/docs/assets/js/9278.a4fd875d.js +1 -0
  110. solace_agent_mesh/assets/docs/assets/js/945fb41e.74d728aa.js +1 -0
  111. solace_agent_mesh/assets/docs/assets/js/9616.b75c2f6d.js +1 -0
  112. solace_agent_mesh/assets/docs/assets/js/9793.c6d16376.js +1 -0
  113. solace_agent_mesh/assets/docs/assets/js/9eff14a2.1bf8f61c.js +1 -0
  114. solace_agent_mesh/assets/docs/assets/js/a3a92b25.26ca071f.js +1 -0
  115. solace_agent_mesh/assets/docs/assets/js/a7bd4aaa.2204d2f7.js +1 -0
  116. solace_agent_mesh/assets/docs/assets/js/a94703ab.0438dbc2.js +1 -0
  117. solace_agent_mesh/assets/docs/assets/js/aba21aa0.c42a534c.js +1 -0
  118. solace_agent_mesh/assets/docs/assets/js/aba87c2f.d3e2dcc3.js +1 -0
  119. solace_agent_mesh/assets/docs/assets/js/ae4415af.8e279b5d.js +1 -0
  120. solace_agent_mesh/assets/docs/assets/js/b7006a3a.40b10c9d.js +1 -0
  121. solace_agent_mesh/assets/docs/assets/js/bac0be12.f50d9bac.js +1 -0
  122. solace_agent_mesh/assets/docs/assets/js/bb2ef573.207e6990.js +1 -0
  123. solace_agent_mesh/assets/docs/assets/js/c2c06897.63b76e9e.js +1 -0
  124. solace_agent_mesh/assets/docs/assets/js/cc969b05.954186d4.js +1 -0
  125. solace_agent_mesh/assets/docs/assets/js/cd3d4052.ca6eed8c.js +1 -0
  126. solace_agent_mesh/assets/docs/assets/js/ced92a13.fb92e7ca.js +1 -0
  127. solace_agent_mesh/assets/docs/assets/js/cee5d587.f5b73ca1.js +1 -0
  128. solace_agent_mesh/assets/docs/assets/js/f284c35a.ecc3d195.js +1 -0
  129. solace_agent_mesh/assets/docs/assets/js/f897a61a.f8c53b0f.js +1 -0
  130. solace_agent_mesh/assets/docs/assets/js/fbfa3e75.aca209c9.js +1 -0
  131. solace_agent_mesh/assets/docs/assets/js/main.c6286d7c.js +2 -0
  132. solace_agent_mesh/assets/docs/assets/js/main.c6286d7c.js.LICENSE.txt +81 -0
  133. solace_agent_mesh/assets/docs/assets/js/runtime~main.d5133813.js +1 -0
  134. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +128 -0
  135. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +91 -0
  136. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +201 -0
  137. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +91 -0
  138. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +55 -0
  139. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +82 -0
  140. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +77 -0
  141. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +48 -0
  142. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +54 -0
  143. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +17 -0
  144. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +45 -0
  145. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +76 -0
  146. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +150 -0
  147. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +54 -0
  148. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +267 -0
  149. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +136 -0
  150. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +116 -0
  151. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +80 -0
  152. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +164 -0
  153. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +57 -0
  154. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +72 -0
  155. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +102 -0
  156. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +99 -0
  157. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +90 -0
  158. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +107 -0
  159. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +152 -0
  160. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +103 -0
  161. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +170 -0
  162. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +200 -0
  163. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +54 -0
  164. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +69 -0
  165. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +59 -0
  166. solace_agent_mesh/assets/docs/img/Solace_AI_Framework_README.png +0 -0
  167. solace_agent_mesh/assets/docs/img/Solace_AI_Framework_With_Broker.png +0 -0
  168. solace_agent_mesh/assets/docs/img/logo.png +0 -0
  169. solace_agent_mesh/assets/docs/img/sac-flows.png +0 -0
  170. solace_agent_mesh/assets/docs/img/sac_parts_of_a_component.png +0 -0
  171. solace_agent_mesh/assets/docs/img/solace-logo.png +0 -0
  172. solace_agent_mesh/assets/docs/lunr-index-1754075282978.json +1 -0
  173. solace_agent_mesh/assets/docs/lunr-index.json +1 -0
  174. solace_agent_mesh/assets/docs/search-doc-1754075282978.json +1 -0
  175. solace_agent_mesh/assets/docs/search-doc.json +1 -0
  176. solace_agent_mesh/assets/docs/sitemap.xml +1 -0
  177. solace_agent_mesh/cli/__init__.py +1 -1
  178. solace_agent_mesh/cli/commands/add_cmd/__init__.py +15 -0
  179. solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +250 -0
  180. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +659 -0
  181. solace_agent_mesh/cli/commands/add_cmd/gateway_cmd.py +322 -0
  182. solace_agent_mesh/cli/commands/add_cmd/web_add_agent_step.py +93 -0
  183. solace_agent_mesh/cli/commands/add_cmd/web_add_gateway_step.py +118 -0
  184. solace_agent_mesh/cli/commands/docs_cmd.py +57 -0
  185. solace_agent_mesh/cli/commands/eval_cmd.py +64 -0
  186. solace_agent_mesh/cli/commands/init_cmd/__init__.py +404 -0
  187. solace_agent_mesh/cli/commands/init_cmd/broker_step.py +201 -0
  188. solace_agent_mesh/cli/commands/init_cmd/directory_step.py +28 -0
  189. solace_agent_mesh/cli/commands/init_cmd/env_step.py +205 -0
  190. solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +365 -0
  191. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +407 -0
  192. solace_agent_mesh/cli/commands/init_cmd/project_files_step.py +38 -0
  193. solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +110 -0
  194. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +183 -0
  195. solace_agent_mesh/cli/commands/plugin_cmd/__init__.py +18 -0
  196. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +372 -0
  197. solace_agent_mesh/cli/commands/plugin_cmd/build_cmd.py +86 -0
  198. solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +139 -0
  199. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +309 -0
  200. solace_agent_mesh/cli/commands/plugin_cmd/official_registry.py +175 -0
  201. solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +305 -0
  202. solace_agent_mesh/cli/commands/run_cmd.py +158 -0
  203. solace_agent_mesh/cli/main.py +17 -294
  204. solace_agent_mesh/cli/utils.py +135 -204
  205. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-DvlO62me.js +1 -0
  206. solace_agent_mesh/client/webui/frontend/static/assets/client-bp6u3qVZ.js +49 -0
  207. solace_agent_mesh/client/webui/frontend/static/assets/favicon-BLgzUch9.ico +0 -0
  208. solace_agent_mesh/client/webui/frontend/static/assets/main-D11Lmy9p.css +1 -0
  209. solace_agent_mesh/client/webui/frontend/static/assets/main-Gfk3BYn5.js +663 -0
  210. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +14 -0
  211. solace_agent_mesh/client/webui/frontend/static/index.html +15 -0
  212. solace_agent_mesh/common/__init__.py +1 -0
  213. solace_agent_mesh/common/a2a_protocol.py +564 -0
  214. solace_agent_mesh/common/agent_registry.py +42 -0
  215. solace_agent_mesh/common/client/__init__.py +4 -0
  216. solace_agent_mesh/common/client/card_resolver.py +21 -0
  217. solace_agent_mesh/common/client/client.py +85 -0
  218. solace_agent_mesh/common/client/client_llm.txt +133 -0
  219. solace_agent_mesh/common/common_llm.txt +144 -0
  220. solace_agent_mesh/common/constants.py +1 -14
  221. solace_agent_mesh/common/middleware/__init__.py +12 -0
  222. solace_agent_mesh/common/middleware/config_resolver.py +130 -0
  223. solace_agent_mesh/common/middleware/middleware_llm.txt +174 -0
  224. solace_agent_mesh/common/middleware/registry.py +125 -0
  225. solace_agent_mesh/common/server/__init__.py +4 -0
  226. solace_agent_mesh/common/server/server.py +122 -0
  227. solace_agent_mesh/common/server/server_llm.txt +169 -0
  228. solace_agent_mesh/common/server/task_manager.py +291 -0
  229. solace_agent_mesh/common/server/utils.py +28 -0
  230. solace_agent_mesh/common/services/__init__.py +4 -0
  231. solace_agent_mesh/common/services/employee_service.py +162 -0
  232. solace_agent_mesh/common/services/identity_service.py +129 -0
  233. solace_agent_mesh/common/services/providers/__init__.py +4 -0
  234. solace_agent_mesh/common/services/providers/local_file_identity_service.py +148 -0
  235. solace_agent_mesh/common/services/providers/providers_llm.txt +113 -0
  236. solace_agent_mesh/common/services/services_llm.txt +132 -0
  237. solace_agent_mesh/common/types.py +411 -0
  238. solace_agent_mesh/common/utils/__init__.py +7 -0
  239. solace_agent_mesh/common/utils/asyncio_macos_fix.py +86 -0
  240. solace_agent_mesh/common/utils/embeds/__init__.py +33 -0
  241. solace_agent_mesh/common/utils/embeds/constants.py +55 -0
  242. solace_agent_mesh/common/utils/embeds/converter.py +452 -0
  243. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +124 -0
  244. solace_agent_mesh/common/utils/embeds/evaluators.py +394 -0
  245. solace_agent_mesh/common/utils/embeds/modifiers.py +816 -0
  246. solace_agent_mesh/common/utils/embeds/resolver.py +865 -0
  247. solace_agent_mesh/common/utils/embeds/types.py +14 -0
  248. solace_agent_mesh/common/utils/in_memory_cache.py +108 -0
  249. solace_agent_mesh/common/utils/initializer.py +51 -0
  250. solace_agent_mesh/common/utils/log_formatters.py +44 -0
  251. solace_agent_mesh/common/utils/mime_helpers.py +106 -0
  252. solace_agent_mesh/common/utils/push_notification_auth.py +134 -0
  253. solace_agent_mesh/common/utils/utils_llm.txt +67 -0
  254. solace_agent_mesh/config_portal/backend/common.py +66 -24
  255. solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +24 -0
  256. solace_agent_mesh/config_portal/backend/plugin_catalog/models.py +49 -0
  257. solace_agent_mesh/config_portal/backend/plugin_catalog/registry_manager.py +164 -0
  258. solace_agent_mesh/config_portal/backend/plugin_catalog/scraper.py +521 -0
  259. solace_agent_mesh/config_portal/backend/plugin_catalog_server.py +217 -0
  260. solace_agent_mesh/config_portal/backend/server.py +551 -181
  261. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-_7yox_eh.js +48 -0
  262. solace_agent_mesh/config_portal/frontend/static/client/assets/components-B7lKcHVY.js +140 -0
  263. solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-DX1misIU.js → entry.client-CEumGClk.js} +3 -3
  264. solace_agent_mesh/config_portal/frontend/static/client/assets/index-DSo1AH_7.js +68 -0
  265. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-e5c3acfe.js +1 -0
  266. solace_agent_mesh/config_portal/frontend/static/client/assets/{root-BApq5dPK.js → root-C4XmHinv.js} +2 -2
  267. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DxRwaWiE.css +1 -0
  268. solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
  269. solace_agent_mesh/core_a2a/__init__.py +1 -0
  270. solace_agent_mesh/core_a2a/core_a2a_llm.txt +88 -0
  271. solace_agent_mesh/core_a2a/service.py +331 -0
  272. solace_agent_mesh/evaluation/config_loader.py +657 -0
  273. solace_agent_mesh/evaluation/evaluator.py +667 -0
  274. solace_agent_mesh/evaluation/message_organizer.py +568 -0
  275. solace_agent_mesh/evaluation/report/benchmark_info.html +35 -0
  276. solace_agent_mesh/evaluation/report/chart_section.html +141 -0
  277. solace_agent_mesh/evaluation/report/detailed_breakdown.html +28 -0
  278. solace_agent_mesh/evaluation/report/modal.html +59 -0
  279. solace_agent_mesh/evaluation/report/modal_chart_functions.js +411 -0
  280. solace_agent_mesh/evaluation/report/modal_script.js +296 -0
  281. solace_agent_mesh/evaluation/report/modal_styles.css +340 -0
  282. solace_agent_mesh/evaluation/report/performance_metrics_styles.css +93 -0
  283. solace_agent_mesh/evaluation/report/templates/footer.html +2 -0
  284. solace_agent_mesh/evaluation/report/templates/header.html +340 -0
  285. solace_agent_mesh/evaluation/report_data_processor.py +972 -0
  286. solace_agent_mesh/evaluation/report_generator.py +613 -0
  287. solace_agent_mesh/evaluation/run.py +613 -0
  288. solace_agent_mesh/evaluation/subscriber.py +872 -0
  289. solace_agent_mesh/evaluation/summary_builder.py +775 -0
  290. solace_agent_mesh/evaluation/test_case_loader.py +714 -0
  291. solace_agent_mesh/gateway/base/__init__.py +1 -0
  292. solace_agent_mesh/gateway/base/app.py +266 -0
  293. solace_agent_mesh/gateway/base/base_llm.txt +119 -0
  294. solace_agent_mesh/gateway/base/component.py +1542 -0
  295. solace_agent_mesh/gateway/base/task_context.py +74 -0
  296. solace_agent_mesh/gateway/gateway_llm.txt +125 -0
  297. solace_agent_mesh/gateway/http_sse/app.py +190 -0
  298. solace_agent_mesh/gateway/http_sse/component.py +1602 -0
  299. solace_agent_mesh/gateway/http_sse/components/__init__.py +7 -0
  300. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +65 -0
  301. solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +108 -0
  302. solace_agent_mesh/gateway/http_sse/dependencies.py +316 -0
  303. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +63 -0
  304. solace_agent_mesh/gateway/http_sse/main.py +442 -0
  305. solace_agent_mesh/gateway/http_sse/routers/__init__.py +4 -0
  306. solace_agent_mesh/gateway/http_sse/routers/agents.py +41 -0
  307. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +827 -0
  308. solace_agent_mesh/gateway/http_sse/routers/auth.py +212 -0
  309. solace_agent_mesh/gateway/http_sse/routers/config.py +55 -0
  310. solace_agent_mesh/gateway/http_sse/routers/people.py +69 -0
  311. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +37 -0
  312. solace_agent_mesh/gateway/http_sse/routers/sessions.py +80 -0
  313. solace_agent_mesh/gateway/http_sse/routers/sse.py +138 -0
  314. solace_agent_mesh/gateway/http_sse/routers/tasks.py +294 -0
  315. solace_agent_mesh/gateway/http_sse/routers/users.py +59 -0
  316. solace_agent_mesh/gateway/http_sse/routers/visualization.py +1131 -0
  317. solace_agent_mesh/gateway/http_sse/services/__init__.py +4 -0
  318. solace_agent_mesh/gateway/http_sse/services/agent_service.py +69 -0
  319. solace_agent_mesh/gateway/http_sse/services/people_service.py +158 -0
  320. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +179 -0
  321. solace_agent_mesh/gateway/http_sse/services/task_service.py +121 -0
  322. solace_agent_mesh/gateway/http_sse/session_manager.py +187 -0
  323. solace_agent_mesh/gateway/http_sse/sse_manager.py +328 -0
  324. solace_agent_mesh/llm.txt +228 -0
  325. solace_agent_mesh/llm_detail.txt +2835 -0
  326. solace_agent_mesh/templates/agent_template.yaml +53 -0
  327. solace_agent_mesh/templates/eval_backend_template.yaml +54 -0
  328. solace_agent_mesh/templates/gateway_app_template.py +73 -0
  329. solace_agent_mesh/templates/gateway_component_template.py +431 -0
  330. solace_agent_mesh/templates/gateway_config_template.yaml +43 -0
  331. solace_agent_mesh/templates/logging_config_template.ini +64 -0
  332. solace_agent_mesh/templates/main_orchestrator.yaml +55 -0
  333. solace_agent_mesh/templates/plugin_agent_config_template.yaml +122 -0
  334. solace_agent_mesh/templates/plugin_custom_config_template.yaml +27 -0
  335. solace_agent_mesh/templates/plugin_custom_template.py +10 -0
  336. solace_agent_mesh/templates/plugin_gateway_config_template.yaml +63 -0
  337. solace_agent_mesh/templates/plugin_pyproject_template.toml +33 -0
  338. solace_agent_mesh/templates/plugin_readme_template.md +34 -0
  339. solace_agent_mesh/templates/plugin_tools_template.py +224 -0
  340. solace_agent_mesh/templates/shared_config.yaml +66 -0
  341. solace_agent_mesh/templates/templates_llm.txt +147 -0
  342. solace_agent_mesh/templates/webui.yaml +53 -0
  343. solace_agent_mesh-1.0.2.dist-info/METADATA +432 -0
  344. solace_agent_mesh-1.0.2.dist-info/RECORD +361 -0
  345. solace_agent_mesh-1.0.2.dist-info/entry_points.txt +3 -0
  346. {solace_agent_mesh-0.2.4.dist-info → solace_agent_mesh-1.0.2.dist-info}/licenses/LICENSE +1 -1
  347. solace_agent_mesh/agents/base_agent_component.py +0 -256
  348. solace_agent_mesh/agents/global/actions/agent_state_change.py +0 -54
  349. solace_agent_mesh/agents/global/actions/clear_history.py +0 -32
  350. solace_agent_mesh/agents/global/actions/convert_file_to_markdown.py +0 -160
  351. solace_agent_mesh/agents/global/actions/create_file.py +0 -70
  352. solace_agent_mesh/agents/global/actions/error_action.py +0 -45
  353. solace_agent_mesh/agents/global/actions/plantuml_diagram.py +0 -163
  354. solace_agent_mesh/agents/global/actions/plotly_graph.py +0 -152
  355. solace_agent_mesh/agents/global/actions/retrieve_file.py +0 -51
  356. solace_agent_mesh/agents/global/global_agent_component.py +0 -38
  357. solace_agent_mesh/agents/image_processing/actions/create_image.py +0 -75
  358. solace_agent_mesh/agents/image_processing/actions/describe_image.py +0 -115
  359. solace_agent_mesh/agents/image_processing/image_processing_agent_component.py +0 -23
  360. solace_agent_mesh/agents/slack/__init__.py +0 -1
  361. solace_agent_mesh/agents/slack/actions/__init__.py +0 -1
  362. solace_agent_mesh/agents/slack/actions/post_message.py +0 -177
  363. solace_agent_mesh/agents/slack/slack_agent_component.py +0 -59
  364. solace_agent_mesh/agents/web_request/actions/do_image_search.py +0 -84
  365. solace_agent_mesh/agents/web_request/actions/do_news_search.py +0 -47
  366. solace_agent_mesh/agents/web_request/actions/do_suggestion_search.py +0 -34
  367. solace_agent_mesh/agents/web_request/actions/do_web_request.py +0 -135
  368. solace_agent_mesh/agents/web_request/actions/download_file.py +0 -69
  369. solace_agent_mesh/agents/web_request/web_request_agent_component.py +0 -33
  370. solace_agent_mesh/assets/web-visualizer/assets/index-D0qORgkg.css +0 -1
  371. solace_agent_mesh/assets/web-visualizer/assets/index-DnDr1pnu.js +0 -109
  372. solace_agent_mesh/assets/web-visualizer/index.html +0 -14
  373. solace_agent_mesh/assets/web-visualizer/vite.svg +0 -1
  374. solace_agent_mesh/cli/commands/add/__init__.py +0 -3
  375. solace_agent_mesh/cli/commands/add/add.py +0 -88
  376. solace_agent_mesh/cli/commands/add/agent.py +0 -110
  377. solace_agent_mesh/cli/commands/add/copy_from_plugin.py +0 -92
  378. solace_agent_mesh/cli/commands/add/gateway.py +0 -374
  379. solace_agent_mesh/cli/commands/build.py +0 -670
  380. solace_agent_mesh/cli/commands/chat/__init__.py +0 -3
  381. solace_agent_mesh/cli/commands/chat/chat.py +0 -361
  382. solace_agent_mesh/cli/commands/config.py +0 -29
  383. solace_agent_mesh/cli/commands/init/__init__.py +0 -3
  384. solace_agent_mesh/cli/commands/init/ai_provider_step.py +0 -93
  385. solace_agent_mesh/cli/commands/init/broker_step.py +0 -99
  386. solace_agent_mesh/cli/commands/init/builtin_agent_step.py +0 -83
  387. solace_agent_mesh/cli/commands/init/check_if_already_done.py +0 -13
  388. solace_agent_mesh/cli/commands/init/create_config_file_step.py +0 -65
  389. solace_agent_mesh/cli/commands/init/create_other_project_files_step.py +0 -147
  390. solace_agent_mesh/cli/commands/init/file_service_step.py +0 -73
  391. solace_agent_mesh/cli/commands/init/init.py +0 -92
  392. solace_agent_mesh/cli/commands/init/project_structure_step.py +0 -16
  393. solace_agent_mesh/cli/commands/init/web_init_step.py +0 -32
  394. solace_agent_mesh/cli/commands/plugin/__init__.py +0 -3
  395. solace_agent_mesh/cli/commands/plugin/add.py +0 -100
  396. solace_agent_mesh/cli/commands/plugin/build.py +0 -268
  397. solace_agent_mesh/cli/commands/plugin/create.py +0 -117
  398. solace_agent_mesh/cli/commands/plugin/plugin.py +0 -124
  399. solace_agent_mesh/cli/commands/plugin/remove.py +0 -73
  400. solace_agent_mesh/cli/commands/run.py +0 -68
  401. solace_agent_mesh/cli/commands/visualizer.py +0 -138
  402. solace_agent_mesh/cli/config.py +0 -85
  403. solace_agent_mesh/common/action.py +0 -91
  404. solace_agent_mesh/common/action_list.py +0 -37
  405. solace_agent_mesh/common/action_response.py +0 -340
  406. solace_agent_mesh/common/mysql_database.py +0 -40
  407. solace_agent_mesh/common/postgres_database.py +0 -85
  408. solace_agent_mesh/common/prompt_templates.py +0 -28
  409. solace_agent_mesh/common/stimulus_utils.py +0 -152
  410. solace_agent_mesh/common/time.py +0 -24
  411. solace_agent_mesh/common/utils.py +0 -712
  412. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-a-zJ6rLx.js +0 -46
  413. solace_agent_mesh/config_portal/frontend/static/client/assets/components-ZIfdTbrV.js +0 -191
  414. solace_agent_mesh/config_portal/frontend/static/client/assets/index-BJHAE5s4.js +0 -17
  415. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-44c41103.js +0 -1
  416. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DX4gQ516.css +0 -1
  417. solace_agent_mesh/configs/agent_global.yaml +0 -74
  418. solace_agent_mesh/configs/agent_image_processing.yaml +0 -82
  419. solace_agent_mesh/configs/agent_slack.yaml +0 -64
  420. solace_agent_mesh/configs/agent_web_request.yaml +0 -75
  421. solace_agent_mesh/configs/conversation_to_file.yaml +0 -56
  422. solace_agent_mesh/configs/error_catcher.yaml +0 -56
  423. solace_agent_mesh/configs/monitor.yaml +0 -0
  424. solace_agent_mesh/configs/monitor_stim_and_errors_to_slack.yaml +0 -109
  425. solace_agent_mesh/configs/monitor_user_feedback.yaml +0 -58
  426. solace_agent_mesh/configs/orchestrator.yaml +0 -241
  427. solace_agent_mesh/configs/service_embedding.yaml +0 -81
  428. solace_agent_mesh/configs/service_llm.yaml +0 -265
  429. solace_agent_mesh/configs/visualize_websocket.yaml +0 -55
  430. solace_agent_mesh/gateway/components/gateway_base.py +0 -47
  431. solace_agent_mesh/gateway/components/gateway_input.py +0 -278
  432. solace_agent_mesh/gateway/components/gateway_output.py +0 -298
  433. solace_agent_mesh/gateway/identity/bamboohr_identity.py +0 -18
  434. solace_agent_mesh/gateway/identity/identity_base.py +0 -10
  435. solace_agent_mesh/gateway/identity/identity_provider.py +0 -60
  436. solace_agent_mesh/gateway/identity/no_identity.py +0 -9
  437. solace_agent_mesh/gateway/identity/passthru_identity.py +0 -9
  438. solace_agent_mesh/monitors/base_monitor_component.py +0 -26
  439. solace_agent_mesh/monitors/feedback/user_feedback_monitor.py +0 -75
  440. solace_agent_mesh/monitors/stim_and_errors/stim_and_error_monitor.py +0 -560
  441. solace_agent_mesh/orchestrator/__init__.py +0 -0
  442. solace_agent_mesh/orchestrator/action_manager.py +0 -237
  443. solace_agent_mesh/orchestrator/components/__init__.py +0 -0
  444. solace_agent_mesh/orchestrator/components/orchestrator_action_manager_timeout_component.py +0 -58
  445. solace_agent_mesh/orchestrator/components/orchestrator_action_response_component.py +0 -179
  446. solace_agent_mesh/orchestrator/components/orchestrator_register_component.py +0 -107
  447. solace_agent_mesh/orchestrator/components/orchestrator_stimulus_processor_component.py +0 -527
  448. solace_agent_mesh/orchestrator/components/orchestrator_streaming_output_component.py +0 -260
  449. solace_agent_mesh/orchestrator/orchestrator_main.py +0 -172
  450. solace_agent_mesh/orchestrator/orchestrator_prompt.py +0 -539
  451. solace_agent_mesh/services/__init__.py +0 -0
  452. solace_agent_mesh/services/authorization/providers/base_authorization_provider.py +0 -56
  453. solace_agent_mesh/services/bamboo_hr_service/__init__.py +0 -3
  454. solace_agent_mesh/services/bamboo_hr_service/bamboo_hr.py +0 -182
  455. solace_agent_mesh/services/common/__init__.py +0 -4
  456. solace_agent_mesh/services/common/auto_expiry.py +0 -45
  457. solace_agent_mesh/services/common/singleton.py +0 -18
  458. solace_agent_mesh/services/file_service/__init__.py +0 -14
  459. solace_agent_mesh/services/file_service/file_manager/__init__.py +0 -0
  460. solace_agent_mesh/services/file_service/file_manager/bucket_file_manager.py +0 -149
  461. solace_agent_mesh/services/file_service/file_manager/file_manager_base.py +0 -162
  462. solace_agent_mesh/services/file_service/file_manager/memory_file_manager.py +0 -64
  463. solace_agent_mesh/services/file_service/file_manager/volume_file_manager.py +0 -106
  464. solace_agent_mesh/services/file_service/file_service.py +0 -437
  465. solace_agent_mesh/services/file_service/file_service_constants.py +0 -54
  466. solace_agent_mesh/services/file_service/file_transformations.py +0 -141
  467. solace_agent_mesh/services/file_service/file_utils.py +0 -324
  468. solace_agent_mesh/services/file_service/transformers/__init__.py +0 -5
  469. solace_agent_mesh/services/history_service/__init__.py +0 -3
  470. solace_agent_mesh/services/history_service/history_providers/__init__.py +0 -0
  471. solace_agent_mesh/services/history_service/history_providers/base_history_provider.py +0 -54
  472. solace_agent_mesh/services/history_service/history_providers/file_history_provider.py +0 -74
  473. solace_agent_mesh/services/history_service/history_providers/index.py +0 -40
  474. solace_agent_mesh/services/history_service/history_providers/memory_history_provider.py +0 -33
  475. solace_agent_mesh/services/history_service/history_providers/mongodb_history_provider.py +0 -66
  476. solace_agent_mesh/services/history_service/history_providers/redis_history_provider.py +0 -66
  477. solace_agent_mesh/services/history_service/history_providers/sql_history_provider.py +0 -93
  478. solace_agent_mesh/services/history_service/history_service.py +0 -413
  479. solace_agent_mesh/services/history_service/long_term_memory/__init__.py +0 -0
  480. solace_agent_mesh/services/history_service/long_term_memory/long_term_memory.py +0 -399
  481. solace_agent_mesh/services/llm_service/components/llm_request_component.py +0 -340
  482. solace_agent_mesh/services/llm_service/components/llm_service_component_base.py +0 -152
  483. solace_agent_mesh/services/middleware_service/__init__.py +0 -0
  484. solace_agent_mesh/services/middleware_service/middleware_service.py +0 -20
  485. solace_agent_mesh/templates/action.py +0 -38
  486. solace_agent_mesh/templates/agent.py +0 -29
  487. solace_agent_mesh/templates/agent.yaml +0 -70
  488. solace_agent_mesh/templates/gateway-config-template.yaml +0 -6
  489. solace_agent_mesh/templates/gateway-default-config.yaml +0 -28
  490. solace_agent_mesh/templates/gateway-flows.yaml +0 -78
  491. solace_agent_mesh/templates/gateway-header.yaml +0 -16
  492. solace_agent_mesh/templates/gateway_base.py +0 -15
  493. solace_agent_mesh/templates/gateway_input.py +0 -98
  494. solace_agent_mesh/templates/gateway_output.py +0 -71
  495. solace_agent_mesh/templates/plugin-gateway-default-config.yaml +0 -29
  496. solace_agent_mesh/templates/plugin-pyproject.toml +0 -30
  497. solace_agent_mesh/templates/rest-api-default-config.yaml +0 -31
  498. solace_agent_mesh/templates/rest-api-flows.yaml +0 -81
  499. solace_agent_mesh/templates/slack-default-config.yaml +0 -16
  500. solace_agent_mesh/templates/slack-flows.yaml +0 -81
  501. solace_agent_mesh/templates/solace-agent-mesh-default.yaml +0 -86
  502. solace_agent_mesh/templates/solace-agent-mesh-plugin-default.yaml +0 -8
  503. solace_agent_mesh/templates/web-default-config.yaml +0 -10
  504. solace_agent_mesh/templates/web-flows.yaml +0 -76
  505. solace_agent_mesh/tools/__init__.py +0 -0
  506. solace_agent_mesh/tools/components/__init__.py +0 -0
  507. solace_agent_mesh/tools/components/conversation_formatter.py +0 -111
  508. solace_agent_mesh/tools/components/file_resolver_component.py +0 -58
  509. solace_agent_mesh/tools/config/runtime_config.py +0 -26
  510. solace_agent_mesh-0.2.4.dist-info/METADATA +0 -176
  511. solace_agent_mesh-0.2.4.dist-info/RECORD +0 -193
  512. solace_agent_mesh-0.2.4.dist-info/entry_points.txt +0 -3
  513. /solace_agent_mesh/{agents → agent}/__init__.py +0 -0
  514. /solace_agent_mesh/{agents/global → agent/adk}/__init__.py +0 -0
  515. /solace_agent_mesh/{agents/global/actions → agent/protocol}/__init__.py +0 -0
  516. /solace_agent_mesh/{agents/image_processing → agent/sac}/__init__.py +0 -0
  517. /solace_agent_mesh/{agents/image_processing/actions → agent/utils}/__init__.py +0 -0
  518. /solace_agent_mesh/{agents/web_request → config_portal/backend/plugin_catalog}/__init__.py +0 -0
  519. /solace_agent_mesh/{agents/web_request/actions → evaluation}/__init__.py +0 -0
  520. /solace_agent_mesh/gateway/{components → http_sse}/__init__.py +0 -0
  521. {solace_agent_mesh-0.2.4.dist-info → solace_agent_mesh-1.0.2.dist-info}/WHEEL +0 -0
@@ -0,0 +1,1444 @@
1
+ """
2
+ Contains event handling logic for the A2A_ADK_HostComponent.
3
+ """
4
+
5
+ import json
6
+ import yaml
7
+ import asyncio
8
+ from typing import Union, TYPE_CHECKING, List, Dict, Any
9
+ import fnmatch
10
+ from solace_ai_connector.common.log import log
11
+ from solace_ai_connector.common.message import Message as SolaceMessage
12
+ from solace_ai_connector.common.event import Event, EventType
13
+ from ...common.types import (
14
+ Message as A2AMessage,
15
+ SendTaskRequest,
16
+ SendTaskStreamingRequest,
17
+ CancelTaskRequest,
18
+ GetTaskRequest,
19
+ SetTaskPushNotificationRequest,
20
+ GetTaskPushNotificationRequest,
21
+ TaskResubscriptionRequest,
22
+ TaskIdParams,
23
+ JSONParseError,
24
+ InvalidRequestError,
25
+ InternalError,
26
+ JSONRPCResponse,
27
+ AgentCard,
28
+ AgentCapabilities,
29
+ Task,
30
+ TaskStatusUpdateEvent,
31
+ TaskArtifactUpdateEvent,
32
+ TaskStatus,
33
+ TaskState,
34
+ DataPart,
35
+ A2ARequest,
36
+ )
37
+ from ...common.a2a_protocol import (
38
+ get_agent_request_topic,
39
+ get_discovery_topic,
40
+ translate_a2a_to_adk_content,
41
+ get_client_response_topic,
42
+ get_agent_response_subscription_topic,
43
+ get_agent_status_subscription_topic,
44
+ _extract_text_from_parts,
45
+ )
46
+ from ...agent.utils.artifact_helpers import (
47
+ load_artifact_content_or_metadata,
48
+ )
49
+ from ...agent.adk.runner import run_adk_async_task_thread_wrapper
50
+ from ..sac.task_execution_context import TaskExecutionContext
51
+ from google.adk.agents import RunConfig
52
+
53
+ if TYPE_CHECKING:
54
+ from ..sac.component import SamAgentComponent
55
+ from google.adk.agents.run_config import StreamingMode
56
+ from google.adk.events import Event as ADKEvent
57
+ from google.genai import types as adk_types
58
+
59
+
60
+ async def _format_artifact_summary_from_manifest(
61
+ component: "SamAgentComponent",
62
+ produced_artifacts: List[Dict[str, Any]],
63
+ peer_agent_name: str,
64
+ correlation_data: Dict[str, Any],
65
+ ) -> str:
66
+ """
67
+ Loads metadata for a list of produced artifacts and formats it into a
68
+ human-readable YAML summary string.
69
+ """
70
+ if not produced_artifacts:
71
+ return ""
72
+
73
+ artifact_summary_lines = [
74
+ f"Peer agent `{peer_agent_name}` created {len(produced_artifacts)} artifact(s):"
75
+ ]
76
+
77
+ original_task_context = correlation_data.get("original_task_context", {})
78
+ user_id = original_task_context.get("user_id")
79
+ session_id = original_task_context.get("session_id")
80
+
81
+ if not (component.artifact_service and user_id and session_id):
82
+ log.warning(
83
+ "%s Cannot load artifact metadata: missing artifact_service or context.",
84
+ component.log_identifier,
85
+ )
86
+ for artifact_ref in produced_artifacts:
87
+ artifact_summary_lines.append(
88
+ f"- `{artifact_ref.get('filename')}` (v{artifact_ref.get('version')})"
89
+ )
90
+ return "\n".join(artifact_summary_lines)
91
+
92
+ peer_agent_name_for_artifact = peer_agent_name
93
+ if (
94
+ not peer_agent_name_for_artifact
95
+ or peer_agent_name_for_artifact == "A peer agent"
96
+ ):
97
+ log.warning(
98
+ "%s Peer agent name not in task metadata, using self agent name for artifact loading.",
99
+ component.log_identifier,
100
+ )
101
+ peer_agent_name_for_artifact = component.agent_name
102
+
103
+ for artifact_ref in produced_artifacts:
104
+ filename = artifact_ref.get("filename")
105
+ version = artifact_ref.get("version")
106
+ if not filename or version is None:
107
+ continue
108
+
109
+ try:
110
+ metadata_result = await load_artifact_content_or_metadata(
111
+ artifact_service=component.artifact_service,
112
+ app_name=peer_agent_name_for_artifact,
113
+ user_id=user_id,
114
+ session_id=session_id,
115
+ filename=filename,
116
+ version=version,
117
+ load_metadata_only=True,
118
+ )
119
+ if metadata_result.get("status") == "success":
120
+ metadata = metadata_result.get("metadata", {})
121
+ TRUNCATION_LIMIT_BYTES = 1024
122
+ TRUNCATION_MESSAGE = "\n... [truncated] ..."
123
+
124
+ try:
125
+ formatted_metadata_str = yaml.safe_dump(
126
+ metadata,
127
+ default_flow_style=False,
128
+ sort_keys=False,
129
+ allow_unicode=True,
130
+ )
131
+
132
+ if (
133
+ len(formatted_metadata_str.encode("utf-8"))
134
+ > TRUNCATION_LIMIT_BYTES
135
+ ):
136
+ cutoff = TRUNCATION_LIMIT_BYTES - len(
137
+ TRUNCATION_MESSAGE.encode("utf-8")
138
+ )
139
+ formatted_metadata_str = (
140
+ formatted_metadata_str[:cutoff] + TRUNCATION_MESSAGE
141
+ )
142
+
143
+ summary_line = f"- `{filename}` (v{version}):\n ```yaml\n{formatted_metadata_str}\n ```"
144
+ artifact_summary_lines.append(summary_line)
145
+ except Exception as e_format:
146
+ log.error(
147
+ "Error formatting metadata for %s v%s: %s",
148
+ filename,
149
+ version,
150
+ e_format,
151
+ )
152
+ artifact_summary_lines.append(
153
+ f"- `{filename}` (v{version}): Error formatting metadata."
154
+ )
155
+ else:
156
+ artifact_summary_lines.append(
157
+ f"- `{filename}` (v{version}): Could not load metadata."
158
+ )
159
+ except Exception as e_meta:
160
+ log.error(
161
+ "Error loading metadata for %s v%s: %s", filename, version, e_meta
162
+ )
163
+ artifact_summary_lines.append(
164
+ f"- `{filename}` (v{version}): Error loading metadata."
165
+ )
166
+
167
+ return "\n".join(artifact_summary_lines)
168
+
169
+
170
+ def _register_peer_artifacts_in_parent_context(
171
+ parent_task_context: "TaskExecutionContext",
172
+ peer_task_object: Task,
173
+ log_identifier: str,
174
+ ):
175
+ """
176
+ Registers artifacts produced by a peer agent in the parent agent's
177
+ task execution context, allowing them to be "bubbled up".
178
+ """
179
+ if not parent_task_context:
180
+ return
181
+
182
+ if peer_task_object.metadata and "produced_artifacts" in peer_task_object.metadata:
183
+ peer_artifacts = peer_task_object.metadata.get("produced_artifacts", [])
184
+ if not peer_artifacts:
185
+ return
186
+
187
+ log.debug(
188
+ "%s Registering %d artifacts from peer response into parent task context.",
189
+ log_identifier,
190
+ len(peer_artifacts),
191
+ )
192
+ for artifact_ref in peer_artifacts:
193
+ filename = artifact_ref.get("filename")
194
+ version = artifact_ref.get("version")
195
+ if filename and version is not None:
196
+ parent_task_context.register_produced_artifact(
197
+ filename=filename,
198
+ version=version,
199
+ )
200
+
201
+
202
+ async def process_event(component, event: Event):
203
+ """
204
+ Processes incoming events (Messages, Timers, etc.). Routes to specific handlers.
205
+ Args:
206
+ component: The A2A_ADK_HostComponent instance.
207
+ event: The event object received from the SAC framework.
208
+ """
209
+ try:
210
+ if event.event_type == EventType.MESSAGE:
211
+ message = event.data
212
+ topic = message.get_topic()
213
+ if not topic:
214
+ log.warning(
215
+ "%s Received message without topic. Ignoring.",
216
+ component.log_identifier,
217
+ )
218
+ return
219
+ if component.invocation_monitor:
220
+ component.invocation_monitor.log_message_event(
221
+ direction="RECEIVED",
222
+ topic=topic,
223
+ payload=message.get_payload(),
224
+ component_identifier=component.log_identifier,
225
+ )
226
+ else:
227
+ log.warning(
228
+ f"{component.log_identifier} InvocationMonitor not available in component for event on topic {topic}"
229
+ )
230
+ namespace = component.get_config("namespace")
231
+ agent_name = component.get_config("agent_name")
232
+ agent_request_topic = get_agent_request_topic(namespace, agent_name)
233
+ discovery_topic = get_discovery_topic(namespace)
234
+ agent_response_sub_prefix = (
235
+ get_agent_response_subscription_topic(namespace, agent_name)[:-2] + "/"
236
+ )
237
+ agent_status_sub_prefix = (
238
+ get_agent_status_subscription_topic(namespace, agent_name)[:-2] + "/"
239
+ )
240
+ if topic == agent_request_topic:
241
+ await handle_a2a_request(component, message)
242
+ elif topic == discovery_topic:
243
+ payload = message.get_payload()
244
+ if isinstance(payload, dict) and payload.get("name") != agent_name:
245
+ handle_agent_card_message(component, message)
246
+ else:
247
+ message.call_acknowledgements()
248
+ elif topic.startswith(agent_response_sub_prefix) or topic.startswith(
249
+ agent_status_sub_prefix
250
+ ):
251
+ await handle_a2a_response(component, message)
252
+ else:
253
+ log.warning(
254
+ "%s Received message on unhandled topic: %s",
255
+ component.log_identifier,
256
+ topic,
257
+ )
258
+ message.call_acknowledgements()
259
+ elif event.event_type == EventType.TIMER:
260
+ timer_data = event.data
261
+ log.debug(
262
+ "%s Received timer event: %s", component.log_identifier, timer_data
263
+ )
264
+ if timer_data.get("timer_id") == component._card_publish_timer_id:
265
+ publish_agent_card(component)
266
+ elif event.event_type == EventType.CACHE_EXPIRY:
267
+ # Delegate cache expiry handling to the component itself.
268
+ await component.handle_cache_expiry_event(event.data)
269
+ else:
270
+ log.warning(
271
+ "%s Received unknown event type: %s",
272
+ component.log_identifier,
273
+ event.event_type,
274
+ )
275
+ except Exception as e:
276
+ log.exception(
277
+ "%s Unhandled error in process_event: %s", component.log_identifier, e
278
+ )
279
+ if event.event_type == EventType.MESSAGE:
280
+ try:
281
+ event.data.call_negative_acknowledgements()
282
+ log.warning(
283
+ "%s NACKed message due to error in process_event.",
284
+ component.log_identifier,
285
+ )
286
+ except Exception as nack_e:
287
+ log.error(
288
+ "%s Failed to NACK message after error in process_event: %s",
289
+ component.log_identifier,
290
+ nack_e,
291
+ )
292
+ component.handle_error(e, event)
293
+
294
+
295
+ async def handle_a2a_request(component, message: SolaceMessage):
296
+ """
297
+ Handles an incoming A2A request message.
298
+ Starts the ADK runner for SendTask/SendTaskStreaming requests.
299
+ Handles CancelTask requests directly.
300
+ Stores the original SolaceMessage in context for the ADK runner to ACK/NACK.
301
+ """
302
+ log.info(
303
+ "%s Received new A2A request on topic: %s",
304
+ component.log_identifier,
305
+ message.get_topic(),
306
+ )
307
+ a2a_context = {}
308
+ adk_session = None
309
+ jsonrpc_request_id = None
310
+ logical_task_id = None
311
+ client_id = message.get_user_properties().get("clientId", "default_client")
312
+ status_topic_from_peer = message.get_user_properties().get("a2aStatusTopic")
313
+ reply_topic_from_peer = message.get_user_properties().get("replyTo")
314
+ namespace = component.get_config("namespace")
315
+ a2a_user_config = message.get_user_properties().get("a2aUserConfig", {})
316
+ if not isinstance(a2a_user_config, dict):
317
+ log.warning(
318
+ "%s 'a2aUserConfig' user property is not a dictionary, received: %s. Defaulting to empty dict.",
319
+ component.log_identifier,
320
+ type(a2a_user_config),
321
+ )
322
+ a2a_user_config = {}
323
+ log.debug(
324
+ "%s Extracted 'a2aUserConfig': %s",
325
+ component.log_identifier,
326
+ a2a_user_config,
327
+ )
328
+ try:
329
+ payload_dict = message.get_payload()
330
+ if not isinstance(payload_dict, dict):
331
+ raise ValueError("Payload is not a dictionary.")
332
+ jsonrpc_request_id = payload_dict.get("id")
333
+ a2a_request: Union[
334
+ SendTaskRequest,
335
+ SendTaskStreamingRequest,
336
+ CancelTaskRequest,
337
+ GetTaskRequest,
338
+ SetTaskPushNotificationRequest,
339
+ GetTaskPushNotificationRequest,
340
+ TaskResubscriptionRequest,
341
+ ] = A2ARequest.validate_python(payload_dict)
342
+ jsonrpc_request_id = a2a_request.id
343
+ logical_task_id = a2a_request.params.id
344
+ if isinstance(a2a_request, CancelTaskRequest):
345
+ log.info(
346
+ "%s Received CancelTaskRequest for Task ID: %s.",
347
+ component.log_identifier,
348
+ logical_task_id,
349
+ )
350
+ task_context = None
351
+ with component.active_tasks_lock:
352
+ task_context = component.active_tasks.get(logical_task_id)
353
+
354
+ if task_context:
355
+ task_context.cancel()
356
+ log.info(
357
+ "%s Sent cancellation signal to ADK task %s.",
358
+ component.log_identifier,
359
+ logical_task_id,
360
+ )
361
+
362
+ peer_sub_tasks = task_context.peer_sub_tasks
363
+ if peer_sub_tasks:
364
+ for sub_task_info in peer_sub_tasks:
365
+ sub_task_id = sub_task_info.get("sub_task_id")
366
+ target_peer_agent_name = sub_task_info.get("peer_agent_name")
367
+ if sub_task_id and target_peer_agent_name:
368
+ log.info(
369
+ "%s Attempting to cancel peer sub-task %s for agent %s (main task %s).",
370
+ component.log_identifier,
371
+ sub_task_id,
372
+ target_peer_agent_name,
373
+ logical_task_id,
374
+ )
375
+ try:
376
+ peer_cancel_params = TaskIdParams(id=sub_task_id)
377
+ peer_cancel_request = CancelTaskRequest(
378
+ params=peer_cancel_params
379
+ )
380
+ peer_cancel_user_props = {
381
+ "clientId": component.agent_name
382
+ }
383
+ component._publish_a2a_message(
384
+ payload=peer_cancel_request.model_dump(
385
+ exclude_none=True
386
+ ),
387
+ topic=component._get_agent_request_topic(
388
+ target_peer_agent_name
389
+ ),
390
+ user_properties=peer_cancel_user_props,
391
+ )
392
+ log.info(
393
+ "%s Sent CancelTaskRequest to peer %s for sub-task %s.",
394
+ component.log_identifier,
395
+ target_peer_agent_name,
396
+ sub_task_id,
397
+ )
398
+ except Exception as e_peer_cancel:
399
+ log.error(
400
+ "%s Failed to send CancelTaskRequest to peer %s for sub-task %s: %s",
401
+ component.log_identifier,
402
+ target_peer_agent_name,
403
+ sub_task_id,
404
+ e_peer_cancel,
405
+ )
406
+ else:
407
+ log.warning(
408
+ "%s Peer info for main task %s incomplete, cannot cancel peer task. Info: %s",
409
+ component.log_identifier,
410
+ logical_task_id,
411
+ sub_task_info,
412
+ )
413
+ else:
414
+ log.info(
415
+ "%s No active task found for cancellation (ID: %s) or task already completed. Ignoring signal.",
416
+ component.log_identifier,
417
+ logical_task_id,
418
+ )
419
+ try:
420
+ message.call_acknowledgements()
421
+ log.debug(
422
+ "%s ACKed CancelTaskRequest for Task ID: %s.",
423
+ component.log_identifier,
424
+ logical_task_id,
425
+ )
426
+ except Exception as ack_e:
427
+ log.error(
428
+ "%s Failed to ACK CancelTaskRequest for Task ID %s: %s",
429
+ component.log_identifier,
430
+ logical_task_id,
431
+ ack_e,
432
+ )
433
+ return None
434
+ elif isinstance(a2a_request, (SendTaskRequest, SendTaskStreamingRequest)):
435
+ original_session_id = a2a_request.params.sessionId
436
+ task_id = a2a_request.params.id
437
+ task_metadata = a2a_request.params.metadata or {}
438
+ system_purpose = task_metadata.get("system_purpose")
439
+ response_format = task_metadata.get("response_format")
440
+ session_behavior_from_meta = task_metadata.get("sessionBehavior")
441
+ if session_behavior_from_meta:
442
+ session_behavior = str(session_behavior_from_meta).upper()
443
+ if session_behavior not in ["PERSISTENT", "RUN_BASED"]:
444
+ log.warning(
445
+ "%s Invalid 'sessionBehavior' in task metadata: '%s'. Using component default: '%s'.",
446
+ component.log_identifier,
447
+ session_behavior,
448
+ component.default_session_behavior,
449
+ )
450
+ session_behavior = component.default_session_behavior
451
+ else:
452
+ log.info(
453
+ "%s Using 'sessionBehavior' from task metadata: '%s'.",
454
+ component.log_identifier,
455
+ session_behavior,
456
+ )
457
+ else:
458
+ session_behavior = component.default_session_behavior
459
+ log.info(
460
+ "%s No 'sessionBehavior' in task metadata. Using component default: '%s'.",
461
+ component.log_identifier,
462
+ session_behavior,
463
+ )
464
+ user_id = message.get_user_properties().get("userId", "default_user")
465
+ agent_name = component.get_config("agent_name")
466
+ is_streaming_request = isinstance(a2a_request, SendTaskStreamingRequest)
467
+ host_supports_streaming = component.get_config("supports_streaming", False)
468
+ if is_streaming_request and not host_supports_streaming:
469
+ raise ValueError(
470
+ "Host does not support streaming (tasks/sendSubscribe) requests."
471
+ )
472
+ effective_session_id = original_session_id
473
+ is_run_based_session = False
474
+ temporary_run_session_id_for_cleanup = None
475
+ if session_behavior == "RUN_BASED":
476
+ is_run_based_session = True
477
+ effective_session_id = f"{original_session_id}:{task_id}:run"
478
+ temporary_run_session_id_for_cleanup = effective_session_id
479
+ log.info(
480
+ "%s Session behavior is RUN_BASED. OriginalID='%s', EffectiveID for this run='%s', TaskID='%s'.",
481
+ component.log_identifier,
482
+ original_session_id,
483
+ effective_session_id,
484
+ task_id,
485
+ )
486
+ else:
487
+ is_run_based_session = False
488
+ effective_session_id = original_session_id
489
+ temporary_run_session_id_for_cleanup = None
490
+ log.info(
491
+ "%s Session behavior is PERSISTENT. EffectiveID='%s' for TaskID='%s'.",
492
+ component.log_identifier,
493
+ effective_session_id,
494
+ task_id,
495
+ )
496
+ adk_session_for_run = await component.session_service.get_session(
497
+ app_name=agent_name, user_id=user_id, session_id=effective_session_id
498
+ )
499
+ if adk_session_for_run is None:
500
+ adk_session_for_run = await component.session_service.create_session(
501
+ app_name=agent_name,
502
+ user_id=user_id,
503
+ session_id=effective_session_id,
504
+ )
505
+ log.info(
506
+ "%s Created new ADK session '%s' for task '%s'.",
507
+ component.log_identifier,
508
+ effective_session_id,
509
+ task_id,
510
+ )
511
+ else:
512
+ log.info(
513
+ "%s Reusing existing ADK session '%s' for task '%s'.",
514
+ component.log_identifier,
515
+ effective_session_id,
516
+ task_id,
517
+ )
518
+ if is_run_based_session:
519
+ try:
520
+ original_adk_session_data = (
521
+ await component.session_service.get_session(
522
+ app_name=agent_name,
523
+ user_id=user_id,
524
+ session_id=original_session_id,
525
+ )
526
+ )
527
+ if original_adk_session_data and hasattr(
528
+ original_adk_session_data, "history"
529
+ ):
530
+ original_history_events = original_adk_session_data.history
531
+ if original_history_events:
532
+ log.debug(
533
+ "%s Copying %d events from original session '%s' to run-based session '%s'.",
534
+ component.log_identifier,
535
+ len(original_history_events),
536
+ original_session_id,
537
+ effective_session_id,
538
+ )
539
+ run_based_adk_session_for_copy = (
540
+ await component.session_service.create_session(
541
+ app_name=agent_name,
542
+ user_id=user_id,
543
+ session_id=effective_session_id,
544
+ )
545
+ )
546
+ for event_to_copy in original_history_events:
547
+ await component.session_service.append_event(
548
+ session=run_based_adk_session_for_copy,
549
+ event=event_to_copy,
550
+ )
551
+ else:
552
+ log.debug(
553
+ "%s No history to copy from original session '%s' for run-based task '%s'.",
554
+ component.log_identifier,
555
+ original_session_id,
556
+ task_id,
557
+ )
558
+ else:
559
+ log.debug(
560
+ "%s Original session '%s' not found or has no history, cannot copy for run-based task '%s'.",
561
+ component.log_identifier,
562
+ original_session_id,
563
+ task_id,
564
+ )
565
+ except Exception as e_copy:
566
+ log.error(
567
+ "%s Error copying history for run-based session '%s' (task '%s'): %s. Proceeding with empty session.",
568
+ component.log_identifier,
569
+ effective_session_id,
570
+ task_id,
571
+ e_copy,
572
+ )
573
+ a2a_context = {
574
+ "jsonrpc_request_id": jsonrpc_request_id,
575
+ "logical_task_id": logical_task_id,
576
+ "session_id": original_session_id,
577
+ "user_id": user_id,
578
+ "client_id": client_id,
579
+ "is_streaming": is_streaming_request,
580
+ "statusTopic": status_topic_from_peer,
581
+ "replyToTopic": reply_topic_from_peer,
582
+ "original_solace_message": message,
583
+ "a2a_user_config": a2a_user_config,
584
+ "effective_session_id": effective_session_id,
585
+ "is_run_based_session": is_run_based_session,
586
+ "temporary_run_session_id_for_cleanup": temporary_run_session_id_for_cleanup,
587
+ "agent_name_for_session": (
588
+ agent_name if is_run_based_session else None
589
+ ),
590
+ "user_id_for_session": user_id if is_run_based_session else None,
591
+ "system_purpose": system_purpose,
592
+ "response_format": response_format,
593
+ "host_agent_name": agent_name,
594
+ }
595
+ log.debug(
596
+ "%s A2A Context (shared service model): %s",
597
+ component.log_identifier,
598
+ a2a_context,
599
+ )
600
+
601
+ # Create and store the execution context for this task
602
+ task_context = TaskExecutionContext(
603
+ task_id=logical_task_id, a2a_context=a2a_context
604
+ )
605
+ with component.active_tasks_lock:
606
+ component.active_tasks[logical_task_id] = task_context
607
+ log.info(
608
+ "%s Created and stored new TaskExecutionContext for task %s.",
609
+ component.log_identifier,
610
+ logical_task_id,
611
+ )
612
+
613
+ adk_content = translate_a2a_to_adk_content(
614
+ a2a_request.params.message, component.log_identifier
615
+ )
616
+
617
+ adk_session = await component.session_service.get_session(
618
+ app_name=agent_name, user_id=user_id, session_id=effective_session_id
619
+ )
620
+ if adk_session is None:
621
+ log.info(
622
+ "%s ADK session '%s' not found in component.session_service, creating new one.",
623
+ component.log_identifier,
624
+ effective_session_id,
625
+ )
626
+ adk_session = await component.session_service.create_session(
627
+ app_name=agent_name,
628
+ user_id=user_id,
629
+ session_id=effective_session_id,
630
+ )
631
+ else:
632
+ log.info(
633
+ "%s Reusing existing ADK session '%s' from component.session_service.",
634
+ component.log_identifier,
635
+ effective_session_id,
636
+ )
637
+
638
+ # Always use SSE streaming mode for the ADK runner.
639
+ # This ensures that real-time callbacks (e.g., for fenced artifact
640
+ # progress) can function correctly for all task types. The component's
641
+ # internal logic uses the 'is_run_based_session' flag to differentiate
642
+ # between aggregating a final response and streaming partial updates.
643
+ streaming_mode = StreamingMode.SSE
644
+
645
+ max_llm_calls_per_task = component.get_config("max_llm_calls_per_task", 20)
646
+ log.info(
647
+ "%s Using max_llm_calls_per_task: %s",
648
+ component.log_identifier,
649
+ max_llm_calls_per_task,
650
+ )
651
+
652
+ run_config = RunConfig(
653
+ streaming_mode=streaming_mode, max_llm_calls=max_llm_calls_per_task
654
+ )
655
+ log.info(
656
+ "%s Setting ADK RunConfig streaming_mode to: %s, max_llm_calls to: %s",
657
+ component.log_identifier,
658
+ streaming_mode,
659
+ max_llm_calls_per_task,
660
+ )
661
+
662
+ log.info(
663
+ "%s Starting ADK runner task for request %s (Task ID: %s)",
664
+ component.log_identifier,
665
+ jsonrpc_request_id,
666
+ logical_task_id,
667
+ )
668
+
669
+ await run_adk_async_task_thread_wrapper(
670
+ component,
671
+ adk_session,
672
+ adk_content,
673
+ run_config,
674
+ a2a_context,
675
+ )
676
+
677
+ log.info(
678
+ "%s ADK task execution awaited for Task ID %s.",
679
+ component.log_identifier,
680
+ logical_task_id,
681
+ )
682
+
683
+ else:
684
+ log.warning(
685
+ "%s Received unhandled A2A request type: %s. Acknowledging.",
686
+ component.log_identifier,
687
+ type(a2a_request).__name__,
688
+ )
689
+ try:
690
+ message.call_acknowledgements()
691
+ except Exception as ack_e:
692
+ log.error(
693
+ "%s Failed to ACK unhandled request type %s: %s",
694
+ component.log_identifier,
695
+ type(a2a_request).__name__,
696
+ ack_e,
697
+ )
698
+ return None
699
+
700
+ except (json.JSONDecodeError, ValueError, TypeError) as e:
701
+ log.error(
702
+ "%s Failed to parse, validate, or start ADK task for A2A request: %s",
703
+ component.log_identifier,
704
+ e,
705
+ )
706
+ error_data = {"taskId": logical_task_id} if logical_task_id else None
707
+ if isinstance(e, ValueError):
708
+ error_response = JSONRPCResponse(
709
+ id=jsonrpc_request_id,
710
+ error=InvalidRequestError(message=str(e), data=error_data),
711
+ )
712
+ else:
713
+ error_response = JSONRPCResponse(
714
+ id=jsonrpc_request_id,
715
+ error=JSONParseError(message=str(e), data=error_data),
716
+ )
717
+
718
+ target_topic = reply_topic_from_peer or (
719
+ get_client_response_topic(namespace, client_id) if client_id else None
720
+ )
721
+ if target_topic:
722
+ component._publish_a2a_message(
723
+ error_response.model_dump(exclude_none=True),
724
+ target_topic,
725
+ )
726
+
727
+ try:
728
+ message.call_negative_acknowledgements()
729
+ log.warning(
730
+ "%s NACKed original A2A request due to parsing/validation/start error.",
731
+ component.log_identifier,
732
+ )
733
+ except Exception as nack_e:
734
+ log.error(
735
+ "%s Failed to NACK message after pre-start error: %s",
736
+ component.log_identifier,
737
+ nack_e,
738
+ )
739
+
740
+ component.handle_error(e, Event(EventType.MESSAGE, message))
741
+ return None
742
+
743
+ except Exception as e:
744
+ log.exception(
745
+ "%s Unexpected error handling A2A request: %s", component.log_identifier, e
746
+ )
747
+ error_response = JSONRPCResponse(
748
+ id=jsonrpc_request_id,
749
+ error=InternalError(
750
+ message=f"Unexpected server error: {e}",
751
+ data={"taskId": logical_task_id},
752
+ ),
753
+ )
754
+ target_topic = reply_topic_from_peer or (
755
+ get_client_response_topic(namespace, client_id) if client_id else None
756
+ )
757
+ if target_topic:
758
+ component._publish_a2a_message(
759
+ error_response.model_dump(exclude_none=True),
760
+ target_topic,
761
+ )
762
+
763
+ try:
764
+ message.call_negative_acknowledgements()
765
+ log.warning(
766
+ "%s NACKed original A2A request due to unexpected error.",
767
+ component.log_identifier,
768
+ )
769
+ except Exception as nack_e:
770
+ log.error(
771
+ "%s Failed to NACK message after unexpected error: %s",
772
+ component.log_identifier,
773
+ nack_e,
774
+ )
775
+
776
+ component.handle_error(e, Event(EventType.MESSAGE, message))
777
+ return None
778
+
779
+
780
+ def handle_agent_card_message(component, message: SolaceMessage):
781
+ """Handles incoming Agent Card messages."""
782
+ try:
783
+ payload = message.get_payload()
784
+ if not isinstance(payload, dict):
785
+ log.warning(
786
+ "%s Received agent card with non-dict payload. Ignoring.",
787
+ component.log_identifier,
788
+ )
789
+ message.call_acknowledgements()
790
+ return
791
+
792
+ agent_card = AgentCard(**payload)
793
+ agent_name = agent_card.name
794
+ self_agent_name = component.get_config("agent_name")
795
+
796
+ if agent_name == self_agent_name:
797
+ message.call_acknowledgements()
798
+ return
799
+
800
+ agent_discovery = component.get_config("agent_discovery", {})
801
+ if agent_discovery.get("enabled", False) is False:
802
+ message.call_acknowledgements()
803
+ return
804
+
805
+ inter_agent_config = component.get_config("inter_agent_communication", {})
806
+ allow_list = inter_agent_config.get("allow_list", ["*"])
807
+ deny_list = inter_agent_config.get("deny_list", [])
808
+ is_allowed = False
809
+ for pattern in allow_list:
810
+ if fnmatch.fnmatch(agent_name, pattern):
811
+ is_allowed = True
812
+ break
813
+
814
+ if is_allowed:
815
+ for pattern in deny_list:
816
+ if fnmatch.fnmatch(agent_name, pattern):
817
+ is_allowed = False
818
+ break
819
+
820
+ if is_allowed:
821
+ agent_card.peer_agents = {}
822
+ component.peer_agents[agent_name] = agent_card
823
+
824
+ message.call_acknowledgements()
825
+
826
+ except Exception as e:
827
+ log.exception(
828
+ "%s Error processing agent card message: %s", component.log_identifier, e
829
+ )
830
+ message.call_acknowledgements()
831
+ component.handle_error(e, Event(EventType.MESSAGE, message))
832
+
833
+
834
+ async def handle_a2a_response(component, message: SolaceMessage):
835
+ """Handles incoming responses/status updates from peer agents."""
836
+ sub_task_id = None
837
+ payload_to_queue = None
838
+ is_final_response = False
839
+
840
+ try:
841
+ topic = message.get_topic()
842
+ topic_parts = topic.split("/")
843
+ if len(topic_parts) > 0:
844
+ sub_task_id = topic_parts[-1]
845
+ if not sub_task_id.startswith(component.CORRELATION_DATA_PREFIX):
846
+ log.warning(
847
+ "%s Topic %s does not end with expected sub-task ID format. Ignoring.",
848
+ component.log_identifier,
849
+ topic,
850
+ )
851
+ message.call_acknowledgements()
852
+ return
853
+ else:
854
+ log.error(
855
+ "%s Could not extract sub-task ID from topic: %s",
856
+ component.log_identifier,
857
+ topic,
858
+ )
859
+ message.call_negative_acknowledgements()
860
+ return
861
+
862
+ log.debug("%s Extracted sub-task ID: %s", component.log_identifier, sub_task_id)
863
+
864
+ payload_dict = message.get_payload()
865
+ if not isinstance(payload_dict, dict):
866
+ log.error(
867
+ "%s Received non-dict payload for sub-task %s. Payload: %s",
868
+ component.log_identifier,
869
+ sub_task_id,
870
+ payload_dict,
871
+ )
872
+ payload_to_queue = {
873
+ "error": "Received invalid payload format from peer.",
874
+ "code": "PEER_PAYLOAD_ERROR",
875
+ }
876
+ is_final_response = True
877
+ else:
878
+ try:
879
+ a2a_response = JSONRPCResponse(**payload_dict)
880
+
881
+ if a2a_response.result and isinstance(a2a_response.result, dict):
882
+ payload_data = a2a_response.result
883
+ parsed_successfully = False
884
+ is_final_response = False
885
+ payload_to_queue = None
886
+
887
+ if (
888
+ "final" in payload_data
889
+ and "status" in payload_data
890
+ and isinstance(payload_data.get("final"), bool)
891
+ ):
892
+ try:
893
+ status_event = TaskStatusUpdateEvent(**payload_data)
894
+
895
+ if (
896
+ status_event.status
897
+ and status_event.status.message
898
+ and status_event.status.message.parts
899
+ ):
900
+ for part_from_peer in status_event.status.message.parts:
901
+ if (
902
+ isinstance(part_from_peer, DataPart)
903
+ and part_from_peer.data.get("a2a_signal_type")
904
+ == "agent_status_message"
905
+ ):
906
+ log.info(
907
+ "%s Received agent_status_message signal from peer for sub-task %s.",
908
+ component.log_identifier,
909
+ sub_task_id,
910
+ )
911
+ correlation_data = await component._get_correlation_data_for_sub_task(
912
+ sub_task_id
913
+ )
914
+ if not correlation_data:
915
+ log.warning(
916
+ "%s Correlation data not found for sub-task %s. Cannot forward status signal.",
917
+ component.log_identifier,
918
+ sub_task_id,
919
+ )
920
+ message.call_acknowledgements()
921
+ return
922
+
923
+ original_task_context = correlation_data.get(
924
+ "original_task_context"
925
+ )
926
+ if not original_task_context:
927
+ log.warning(
928
+ "%s original_task_context not found in correlation data for sub-task %s. Cannot forward status signal.",
929
+ component.log_identifier,
930
+ sub_task_id,
931
+ )
932
+ message.call_acknowledgements()
933
+ return
934
+
935
+ main_logical_task_id = (
936
+ original_task_context.get("logical_task_id")
937
+ )
938
+ original_jsonrpc_request_id = (
939
+ original_task_context.get(
940
+ "jsonrpc_request_id"
941
+ )
942
+ )
943
+
944
+ target_topic_for_forward = (
945
+ original_task_context.get("statusTopic")
946
+ )
947
+
948
+ if (
949
+ not main_logical_task_id
950
+ or not original_jsonrpc_request_id
951
+ or not target_topic_for_forward
952
+ ):
953
+ log.error(
954
+ "%s Missing critical info (main_task_id, original_rpc_id, or target_status_topic) in context for sub-task %s. Cannot forward. Context: %s",
955
+ component.log_identifier,
956
+ sub_task_id,
957
+ original_task_context,
958
+ )
959
+ message.call_acknowledgements()
960
+ return
961
+
962
+ peer_agent_name = (
963
+ status_event.metadata.get(
964
+ "agent_name", "UnknownPeer"
965
+ )
966
+ if status_event.metadata
967
+ else "UnknownPeer"
968
+ )
969
+
970
+ forwarded_message = A2AMessage(
971
+ role="agent",
972
+ parts=[part_from_peer],
973
+ metadata={
974
+ "agent_name": component.agent_name,
975
+ "forwarded_from_peer": peer_agent_name,
976
+ "original_peer_event_id": status_event.id,
977
+ "original_peer_event_timestamp": (
978
+ status_event.status.timestamp.isoformat()
979
+ if status_event.status
980
+ and status_event.status.timestamp
981
+ else None
982
+ ),
983
+ "function_call_id": correlation_data.get(
984
+ "adk_function_call_id", None
985
+ ),
986
+ },
987
+ )
988
+ forwarded_status = TaskStatus(
989
+ state=TaskState.WORKING,
990
+ message=forwarded_message,
991
+ timestamp=status_event.status.timestamp,
992
+ )
993
+ forwarded_event = TaskStatusUpdateEvent(
994
+ id=main_logical_task_id,
995
+ status=forwarded_status,
996
+ final=False,
997
+ )
998
+ forwarded_rpc_response = JSONRPCResponse(
999
+ id=original_jsonrpc_request_id,
1000
+ result=forwarded_event,
1001
+ )
1002
+ payload_to_publish = (
1003
+ forwarded_rpc_response.model_dump(
1004
+ exclude_none=True
1005
+ )
1006
+ )
1007
+
1008
+ try:
1009
+ component._publish_a2a_message(
1010
+ payload_to_publish,
1011
+ target_topic_for_forward,
1012
+ )
1013
+ log.info(
1014
+ "%s Forwarded agent_status_message signal for main task %s (from peer %s) to %s.",
1015
+ component.log_identifier,
1016
+ main_logical_task_id,
1017
+ peer_agent_name,
1018
+ target_topic_for_forward,
1019
+ )
1020
+ except Exception as pub_err:
1021
+ log.exception(
1022
+ "%s Failed to publish forwarded status signal for main task %s: %s",
1023
+ component.log_identifier,
1024
+ main_logical_task_id,
1025
+ pub_err,
1026
+ )
1027
+ message.call_acknowledgements()
1028
+ return
1029
+
1030
+ payload_to_queue = status_event.model_dump(
1031
+ exclude_none=True
1032
+ )
1033
+ if status_event.final:
1034
+ log.debug(
1035
+ "%s Parsed TaskStatusUpdateEvent(final=True) from peer for sub-task %s. This is an intermediate update for PeerAgentTool.",
1036
+ component.log_identifier,
1037
+ sub_task_id,
1038
+ )
1039
+
1040
+ if (
1041
+ status_event.status
1042
+ and status_event.status.message
1043
+ and status_event.status.message.parts
1044
+ ):
1045
+ response_parts_data = []
1046
+ for part in status_event.status.message.parts:
1047
+ if (
1048
+ hasattr(part, "text")
1049
+ and part.text is not None
1050
+ ):
1051
+ response_parts_data.append(str(part.text))
1052
+ elif (
1053
+ hasattr(part, "data")
1054
+ and part.data is not None
1055
+ ):
1056
+ try:
1057
+ response_parts_data.append(
1058
+ json.dumps(part.data)
1059
+ )
1060
+ except TypeError:
1061
+ response_parts_data.append(
1062
+ str(part.data)
1063
+ )
1064
+
1065
+ payload_to_queue = {
1066
+ "result": "\n".join(response_parts_data)
1067
+ }
1068
+ log.debug(
1069
+ "%s Extracted content for TaskStatusUpdateEvent(final=True) for sub-task %s: %s",
1070
+ component.log_identifier,
1071
+ sub_task_id,
1072
+ payload_to_queue,
1073
+ )
1074
+ else:
1075
+ log.debug(
1076
+ "%s TaskStatusUpdateEvent(final=True) for sub-task %s has no message parts to extract. Sending event object.",
1077
+ component.log_identifier,
1078
+ sub_task_id,
1079
+ )
1080
+ else:
1081
+ log.debug(
1082
+ "%s Parsed TaskStatusUpdateEvent(final=False) from peer for sub-task %s. This is an intermediate update.",
1083
+ component.log_identifier,
1084
+ sub_task_id,
1085
+ )
1086
+ parsed_successfully = True
1087
+ except Exception as e:
1088
+ log.warning(
1089
+ "%s Failed to parse payload as TaskStatusUpdateEvent for sub-task %s. Payload: %s. Error: %s",
1090
+ component.log_identifier,
1091
+ sub_task_id,
1092
+ payload_data,
1093
+ e,
1094
+ )
1095
+ payload_to_queue = None
1096
+
1097
+ if (
1098
+ not parsed_successfully
1099
+ and "artifact" in payload_data
1100
+ and isinstance(payload_data.get("artifact"), dict)
1101
+ ):
1102
+ try:
1103
+ artifact_event = TaskArtifactUpdateEvent(**payload_data)
1104
+ payload_to_queue = artifact_event.model_dump(
1105
+ exclude_none=True
1106
+ )
1107
+ is_final_response = False
1108
+ log.debug(
1109
+ "%s Parsed TaskArtifactUpdateEvent from peer for sub-task %s. This is an intermediate update.",
1110
+ component.log_identifier,
1111
+ sub_task_id,
1112
+ )
1113
+ parsed_successfully = True
1114
+ except Exception as e:
1115
+ log.warning(
1116
+ "%s Failed to parse payload as TaskArtifactUpdateEvent for sub-task %s. Payload: %s. Error: %s",
1117
+ component.log_identifier,
1118
+ sub_task_id,
1119
+ payload_data,
1120
+ e,
1121
+ )
1122
+ payload_to_queue = None
1123
+
1124
+ if not parsed_successfully:
1125
+ try:
1126
+ final_task = Task(**payload_data)
1127
+ payload_to_queue = final_task.model_dump(exclude_none=True)
1128
+ is_final_response = True
1129
+ log.debug(
1130
+ "%s Parsed final Task object from peer for sub-task %s.",
1131
+ component.log_identifier,
1132
+ sub_task_id,
1133
+ )
1134
+ parsed_successfully = True
1135
+ except Exception as task_parse_error:
1136
+ log.error(
1137
+ "%s Failed to parse peer response for sub-task %s as any known type. Payload: %s. Error: %s",
1138
+ component.log_identifier,
1139
+ sub_task_id,
1140
+ payload_data,
1141
+ task_parse_error,
1142
+ )
1143
+ if not a2a_response.error:
1144
+ a2a_response.error = InternalError(
1145
+ message=f"Failed to parse response from peer agent for sub-task {sub_task_id}",
1146
+ data={
1147
+ "original_payload": payload_data,
1148
+ "error": str(task_parse_error),
1149
+ },
1150
+ )
1151
+ payload_to_queue = None
1152
+ is_final_response = True
1153
+
1154
+ if (
1155
+ not parsed_successfully
1156
+ and not a2a_response.error
1157
+ and payload_to_queue is None
1158
+ ):
1159
+ log.error(
1160
+ "%s Unhandled payload structure from peer for sub-task %s: %s.",
1161
+ component.log_identifier,
1162
+ sub_task_id,
1163
+ payload_data,
1164
+ )
1165
+ a2a_response.error = InternalError(
1166
+ message=f"Unknown response structure from peer agent for sub-task {sub_task_id}",
1167
+ data={"original_payload": payload_data},
1168
+ )
1169
+ is_final_response = True
1170
+
1171
+ elif a2a_response.error:
1172
+ log.warning(
1173
+ "%s Received error response from peer for sub-task %s: %s",
1174
+ component.log_identifier,
1175
+ sub_task_id,
1176
+ a2a_response.error,
1177
+ )
1178
+ payload_to_queue = {
1179
+ "error": a2a_response.error.message,
1180
+ "code": a2a_response.error.code,
1181
+ "data": a2a_response.error.data,
1182
+ }
1183
+ is_final_response = True
1184
+ else:
1185
+ log.warning(
1186
+ "%s Received JSONRPCResponse with no result or error for sub-task %s.",
1187
+ component.log_identifier,
1188
+ sub_task_id,
1189
+ )
1190
+ payload_to_queue = {"result": "Peer responded with empty message."}
1191
+ is_final_response = True
1192
+
1193
+ except Exception as parse_error:
1194
+ log.error(
1195
+ "%s Failed to parse A2A response payload for sub-task %s: %s",
1196
+ component.log_identifier,
1197
+ sub_task_id,
1198
+ parse_error,
1199
+ )
1200
+ payload_to_queue = {
1201
+ "error": f"Failed to parse response from peer: {parse_error}",
1202
+ "code": "PEER_PARSE_ERROR",
1203
+ }
1204
+ # Print out the stack trace for debugging
1205
+ log.exception(
1206
+ "%s Exception stack trace: %s",
1207
+ component.log_identifier,
1208
+ parse_error,
1209
+ )
1210
+
1211
+ if not is_final_response:
1212
+ # This is an intermediate status update for monitoring.
1213
+ # Log it, acknowledge it, but do not aggregate its content.
1214
+ log.debug(
1215
+ "%s Received and ignored intermediate status update from peer for sub-task %s.",
1216
+ component.log_identifier,
1217
+ sub_task_id,
1218
+ )
1219
+ message.call_acknowledgements()
1220
+ return
1221
+
1222
+ correlation_data = await component._claim_peer_sub_task_completion(sub_task_id)
1223
+ if not correlation_data:
1224
+ # The helper method logs the reason (timeout, already claimed, etc.)
1225
+ message.call_acknowledgements()
1226
+ return
1227
+
1228
+ async def _handle_final_peer_response():
1229
+ """
1230
+ Handles a final peer response by updating the completion counter and,
1231
+ if all peer tasks are complete, calling the re-trigger logic.
1232
+ """
1233
+ logical_task_id = correlation_data.get("logical_task_id")
1234
+ invocation_id = correlation_data.get("invocation_id")
1235
+
1236
+ if not logical_task_id or not invocation_id:
1237
+ log.error(
1238
+ "%s 'logical_task_id' or 'invocation_id' not found in correlation data for sub-task %s. Cannot proceed.",
1239
+ component.log_identifier,
1240
+ sub_task_id,
1241
+ )
1242
+ return
1243
+
1244
+ log_retrigger = (
1245
+ f"{component.log_identifier}[RetriggerManager:{logical_task_id}]"
1246
+ )
1247
+
1248
+ with component.active_tasks_lock:
1249
+ task_context = component.active_tasks.get(logical_task_id)
1250
+
1251
+ if not task_context:
1252
+ log.error(
1253
+ "%s TaskExecutionContext not found for task %s. Cannot process final peer response.",
1254
+ log_retrigger,
1255
+ logical_task_id,
1256
+ )
1257
+ return
1258
+
1259
+ final_text = ""
1260
+ artifact_summary = ""
1261
+ if isinstance(payload_to_queue, dict):
1262
+ if "result" in payload_to_queue:
1263
+ final_text = payload_to_queue["result"]
1264
+ elif "error" in payload_to_queue:
1265
+ final_text = (
1266
+ f"Peer agent returned an error: {payload_to_queue['error']}"
1267
+ )
1268
+ elif "status" in payload_to_queue: # It's a Task object
1269
+ try:
1270
+ task_obj = Task(**payload_to_queue)
1271
+ if task_obj.status and task_obj.status.message:
1272
+ final_text = _extract_text_from_parts(
1273
+ task_obj.status.message.parts
1274
+ )
1275
+
1276
+ if (
1277
+ task_obj.metadata
1278
+ and "produced_artifacts" in task_obj.metadata
1279
+ ):
1280
+ produced_artifacts = task_obj.metadata.get(
1281
+ "produced_artifacts", []
1282
+ )
1283
+ if produced_artifacts:
1284
+ peer_agent_name = task_obj.metadata.get(
1285
+ "agent_name", "A peer agent"
1286
+ )
1287
+ artifact_summary = (
1288
+ await _format_artifact_summary_from_manifest(
1289
+ component,
1290
+ produced_artifacts,
1291
+ peer_agent_name,
1292
+ correlation_data,
1293
+ )
1294
+ )
1295
+ # Bubble up the peer's artifacts to the parent context
1296
+ _register_peer_artifacts_in_parent_context(
1297
+ task_context, task_obj, log_retrigger
1298
+ )
1299
+
1300
+ except Exception:
1301
+ final_text = json.dumps(payload_to_queue)
1302
+ else:
1303
+ final_text = json.dumps(payload_to_queue)
1304
+ elif isinstance(payload_to_queue, str):
1305
+ final_text = payload_to_queue
1306
+ else:
1307
+ final_text = str(payload_to_queue)
1308
+
1309
+ full_response_text = final_text
1310
+ if artifact_summary:
1311
+ full_response_text = f"{artifact_summary}\n\n{full_response_text}"
1312
+
1313
+ current_result = {
1314
+ "adk_function_call_id": correlation_data.get("adk_function_call_id"),
1315
+ "peer_tool_name": correlation_data.get("peer_tool_name"),
1316
+ "payload": {"result": full_response_text},
1317
+ }
1318
+
1319
+ all_sub_tasks_completed = task_context.record_parallel_result(
1320
+ current_result, invocation_id
1321
+ )
1322
+ log.info(
1323
+ "%s Updated parallel counter for task %s: %s",
1324
+ log_retrigger,
1325
+ logical_task_id,
1326
+ task_context.parallel_tool_calls.get(invocation_id),
1327
+ )
1328
+
1329
+ if not all_sub_tasks_completed:
1330
+ log.info(
1331
+ "%s Waiting for more peer responses for task %s.",
1332
+ log_retrigger,
1333
+ logical_task_id,
1334
+ )
1335
+ return
1336
+
1337
+ log.info(
1338
+ "%s All peer responses received for task %s. Retriggering agent.",
1339
+ log_retrigger,
1340
+ logical_task_id,
1341
+ )
1342
+ results_to_inject = task_context.parallel_tool_calls.get(
1343
+ invocation_id, {}
1344
+ ).get("results", [])
1345
+
1346
+ await component._retrigger_agent_with_peer_responses(
1347
+ results_to_inject, correlation_data, task_context
1348
+ )
1349
+
1350
+ loop = component.get_async_loop()
1351
+ if loop and loop.is_running():
1352
+ asyncio.run_coroutine_threadsafe(_handle_final_peer_response(), loop)
1353
+ else:
1354
+ log.error(
1355
+ "%s Async loop not available. Cannot handle final peer response for sub-task %s.",
1356
+ component.log_identifier,
1357
+ sub_task_id,
1358
+ )
1359
+
1360
+ message.call_acknowledgements()
1361
+ log.info(
1362
+ "%s Acknowledged final peer response message for sub-task %s.",
1363
+ component.log_identifier,
1364
+ sub_task_id,
1365
+ )
1366
+
1367
+ except Exception as e:
1368
+ log.exception(
1369
+ "%s Unexpected error handling A2A response for sub-task %s: %s",
1370
+ component.log_identifier,
1371
+ sub_task_id,
1372
+ e,
1373
+ )
1374
+ try:
1375
+ message.call_negative_acknowledgements()
1376
+ log.warning(
1377
+ "%s NACKed peer response message for sub-task %s due to unexpected error.",
1378
+ component.log_identifier,
1379
+ sub_task_id,
1380
+ )
1381
+ except Exception as nack_e:
1382
+ log.error(
1383
+ "%s Failed to NACK peer response message for sub-task %s after error: %s",
1384
+ component.log_identifier,
1385
+ sub_task_id,
1386
+ nack_e,
1387
+ )
1388
+ component.handle_error(e, Event(EventType.MESSAGE, message))
1389
+
1390
+
1391
+ def publish_agent_card(component):
1392
+ """Publishes the agent's card to the discovery topic."""
1393
+ try:
1394
+ card_config = component.get_config("agent_card", {})
1395
+ agent_name = component.get_config("agent_name")
1396
+ display_name = component.get_config("display_name")
1397
+ namespace = component.get_config("namespace")
1398
+ supports_streaming = component.get_config("supports_streaming", False)
1399
+ peer_agents = component.peer_agents
1400
+
1401
+ agent_request_topic = get_agent_request_topic(namespace, agent_name)
1402
+ dynamic_url = f"solace:{agent_request_topic}"
1403
+
1404
+ capabilities = AgentCapabilities(
1405
+ streaming=supports_streaming,
1406
+ pushNotifications=False,
1407
+ stateTransitionHistory=False,
1408
+ )
1409
+
1410
+ skills = card_config.get("skills", [])
1411
+ dynamic_tools = getattr(component, "agent_card_tool_manifest", [])
1412
+
1413
+ agent_card = AgentCard(
1414
+ name=agent_name,
1415
+ display_name=display_name,
1416
+ version=component.HOST_COMPONENT_VERSION,
1417
+ url=dynamic_url,
1418
+ capabilities=capabilities,
1419
+ description=card_config.get("description", ""),
1420
+ skills=skills,
1421
+ tools=dynamic_tools,
1422
+ defaultInputModes=card_config.get("defaultInputModes", ["text"]),
1423
+ defaultOutputModes=card_config.get("defaultOutputModes", ["text"]),
1424
+ documentationUrl=card_config.get("documentationUrl"),
1425
+ provider=card_config.get("provider"),
1426
+ peer_agents=peer_agents,
1427
+ )
1428
+
1429
+ discovery_topic = get_discovery_topic(namespace)
1430
+
1431
+ component._publish_a2a_message(
1432
+ agent_card.model_dump(exclude_none=True), discovery_topic
1433
+ )
1434
+ log.debug(
1435
+ "%s Successfully published Agent Card to %s",
1436
+ component.log_identifier,
1437
+ discovery_topic,
1438
+ )
1439
+
1440
+ except Exception as e:
1441
+ log.exception(
1442
+ "%s Failed to publish Agent Card: %s", component.log_identifier, e
1443
+ )
1444
+ component.handle_error(e, None)