solace-agent-mesh 0.2.3__py3-none-any.whl → 1.0.1__py3-none-any.whl

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

Potentially problematic release.


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

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