solace-agent-mesh 0.2.4__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 -181
  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.4.dist-info → solace_agent_mesh-1.0.1.dist-info}/licenses/LICENSE +1 -1
  344. solace_agent_mesh/agents/base_agent_component.py +0 -256
  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-a-zJ6rLx.js +0 -46
  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-44c41103.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.4.dist-info/METADATA +0 -176
  508. solace_agent_mesh-0.2.4.dist-info/RECORD +0 -193
  509. solace_agent_mesh-0.2.4.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.4.dist-info → solace_agent_mesh-1.0.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,821 @@
1
+ """
2
+ FastAPI router for managing session-specific artifacts via REST endpoints.
3
+ """
4
+
5
+ from typing import (
6
+ List,
7
+ Dict,
8
+ Optional,
9
+ Union,
10
+ Any,
11
+ TYPE_CHECKING,
12
+ )
13
+
14
+ from fastapi import (
15
+ APIRouter,
16
+ Depends,
17
+ HTTPException,
18
+ UploadFile,
19
+ File,
20
+ Path,
21
+ status,
22
+ Form,
23
+ )
24
+ from fastapi.responses import StreamingResponse, Response
25
+ from google.adk.artifacts import BaseArtifactService
26
+ import io
27
+ import json
28
+ from datetime import datetime, timezone
29
+ from urllib.parse import urlparse, parse_qs, quote
30
+
31
+ from ..dependencies import (
32
+ get_shared_artifact_service,
33
+ get_sac_component,
34
+ ensure_session_id,
35
+ get_user_id,
36
+ get_config_resolver,
37
+ get_user_config,
38
+ )
39
+
40
+ from solace_ai_connector.common.log import log
41
+
42
+ from ....common.middleware import ConfigResolver
43
+ from ....common.types import ArtifactInfo
44
+ from ....common.utils.mime_helpers import is_text_based_mime_type
45
+ from ....common.utils.embeds import (
46
+ resolve_embeds_recursively_in_string,
47
+ evaluate_embed,
48
+ LATE_EMBED_TYPES,
49
+ )
50
+
51
+
52
+ if TYPE_CHECKING:
53
+ from ....gateway.http_sse.component import WebUIBackendComponent
54
+ from ....agent.utils.artifact_helpers import (
55
+ get_artifact_info_list,
56
+ save_artifact_with_metadata,
57
+ load_artifact_content_or_metadata,
58
+ DEFAULT_SCHEMA_MAX_KEYS,
59
+ )
60
+
61
+ router = APIRouter()
62
+
63
+
64
+ @router.get(
65
+ "/{filename}/versions",
66
+ response_model=List[int],
67
+ summary="List Artifact Versions",
68
+ description="Retrieves a list of available version numbers for a specific artifact.",
69
+ )
70
+ async def list_artifact_versions(
71
+ filename: str = Path(..., title="Filename", description="The name of the artifact"),
72
+ artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
73
+ user_id: str = Depends(get_user_id),
74
+ session_id: str = Depends(ensure_session_id),
75
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
76
+ config_resolver: ConfigResolver = Depends(get_config_resolver),
77
+ user_config: dict = Depends(get_user_config),
78
+ ):
79
+ """
80
+ Lists the available integer versions for a given artifact filename
81
+ associated with the current user and session ID.
82
+ """
83
+ if not config_resolver.is_feature_enabled(
84
+ user_config, {"required_scopes": ["tool:artifact:list"]}, {}
85
+ ):
86
+ raise HTTPException(
87
+ status_code=403, detail="Not authorized to list artifact versions"
88
+ )
89
+
90
+ log_prefix = f"[ArtifactRouter:ListVersions:{filename}] User={user_id}, Session={session_id} -"
91
+ log.info("%s Request received.", log_prefix)
92
+
93
+ if artifact_service is None:
94
+ log.error("%s Artifact service is not configured or available.", log_prefix)
95
+ raise HTTPException(
96
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
97
+ detail="Artifact service is not configured.",
98
+ )
99
+
100
+ if not hasattr(artifact_service, "list_versions"):
101
+ log.warning(
102
+ "%s Configured artifact service (%s) does not support listing versions.",
103
+ log_prefix,
104
+ type(artifact_service).__name__,
105
+ )
106
+ raise HTTPException(
107
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
108
+ detail=f"Version listing not supported by the configured '{type(artifact_service).__name__}' artifact service.",
109
+ )
110
+
111
+ try:
112
+ app_name = component.get_config("name", "A2A_WebUI_App")
113
+
114
+ versions = await artifact_service.list_versions(
115
+ app_name=app_name,
116
+ user_id=user_id,
117
+ session_id=session_id,
118
+ filename=filename,
119
+ )
120
+ log.info("%s Found versions: %s", log_prefix, versions)
121
+ return versions
122
+ except FileNotFoundError:
123
+ log.warning("%s Artifact not found.", log_prefix)
124
+ raise HTTPException(
125
+ status_code=status.HTTP_404_NOT_FOUND,
126
+ detail=f"Artifact '{filename}' not found for this session.",
127
+ )
128
+ except Exception as e:
129
+ log.exception("%s Error listing artifact versions: %s", log_prefix, e)
130
+ raise HTTPException(
131
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
132
+ detail=f"Failed to list artifact versions: {str(e)}",
133
+ )
134
+
135
+
136
+ @router.get(
137
+ "/",
138
+ response_model=List[ArtifactInfo],
139
+ summary="List Artifact Information",
140
+ description="Retrieves detailed information for artifacts available for the current user session.",
141
+ )
142
+ async def list_artifacts(
143
+ artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
144
+ user_id: str = Depends(get_user_id),
145
+ session_id: str = Depends(ensure_session_id),
146
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
147
+ config_resolver: ConfigResolver = Depends(get_config_resolver),
148
+ user_config: dict = Depends(get_user_config),
149
+ ):
150
+ """
151
+ Lists detailed information (filename, size, type, modified date, uri)
152
+ for all artifacts associated with the current user and session ID
153
+ by calling the artifact helper function.
154
+ """
155
+ if not config_resolver.is_feature_enabled(
156
+ user_config, {"required_scopes": ["tool:artifact:list"]}, {}
157
+ ):
158
+ raise HTTPException(status_code=403, detail="Not authorized to list artifacts")
159
+
160
+ log_prefix = f"[ArtifactRouter:ListInfo] User={user_id}, Session={session_id} -"
161
+ log.info("%s Request received.", log_prefix)
162
+
163
+ if artifact_service is None:
164
+ log.error("%s Artifact service is not configured or available.", log_prefix)
165
+ raise HTTPException(
166
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
167
+ detail="Artifact service is not configured.",
168
+ )
169
+
170
+ try:
171
+ app_name = component.get_config("name", "A2A_WebUI_App")
172
+
173
+ artifact_info_list = await get_artifact_info_list(
174
+ artifact_service=artifact_service,
175
+ app_name=app_name,
176
+ user_id=user_id,
177
+ session_id=session_id,
178
+ )
179
+
180
+ log.info(
181
+ "%s Returning %d artifact details.", log_prefix, len(artifact_info_list)
182
+ )
183
+ return artifact_info_list
184
+
185
+ except Exception as e:
186
+ log.exception(
187
+ "%s Error retrieving artifact details via helper: %s", log_prefix, e
188
+ )
189
+ raise HTTPException(
190
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
191
+ detail=f"Failed to retrieve artifact details: {str(e)}",
192
+ )
193
+
194
+
195
+ @router.get(
196
+ "/{filename}",
197
+ summary="Get Latest Artifact Content",
198
+ description="Retrieves the content of the latest version of a specific artifact.",
199
+ )
200
+ async def get_latest_artifact(
201
+ filename: str = Path(..., title="Filename", description="The name of the artifact"),
202
+ artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
203
+ user_id: str = Depends(get_user_id),
204
+ session_id: str = Depends(ensure_session_id),
205
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
206
+ config_resolver: ConfigResolver = Depends(get_config_resolver),
207
+ user_config: dict = Depends(get_user_config),
208
+ ):
209
+ """
210
+ Retrieves the content of the latest version of the specified artifact
211
+ associated with the current user and session ID.
212
+ """
213
+ if not config_resolver.is_feature_enabled(
214
+ user_config, {"required_scopes": ["tool:artifact:load"]}, {}
215
+ ):
216
+ raise HTTPException(status_code=403, detail="Not authorized to load artifact")
217
+ log_prefix = (
218
+ f"[ArtifactRouter:GetLatest:{filename}] User={user_id}, Session={session_id} -"
219
+ )
220
+ log.info("%s Request received.", log_prefix)
221
+
222
+ if artifact_service is None:
223
+ log.error("%s Artifact service is not configured or available.", log_prefix)
224
+ raise HTTPException(
225
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
226
+ detail="Artifact service is not configured.",
227
+ )
228
+
229
+ try:
230
+ app_name = component.get_config("name", "A2A_WebUI_App")
231
+ artifact_part = await artifact_service.load_artifact(
232
+ app_name=app_name,
233
+ user_id=user_id,
234
+ session_id=session_id,
235
+ filename=filename,
236
+ )
237
+
238
+ if artifact_part is None or artifact_part.inline_data is None:
239
+ log.warning("%s Artifact not found or has no data.", log_prefix)
240
+ raise HTTPException(
241
+ status_code=status.HTTP_404_NOT_FOUND,
242
+ detail=f"Artifact '{filename}' not found or is empty.",
243
+ )
244
+
245
+ data_bytes = artifact_part.inline_data.data
246
+ mime_type = artifact_part.inline_data.mime_type or "application/octet-stream"
247
+ log.info(
248
+ "%s Artifact loaded successfully (%d bytes, %s).",
249
+ log_prefix,
250
+ len(data_bytes),
251
+ mime_type,
252
+ )
253
+
254
+ if is_text_based_mime_type(mime_type) and component.enable_embed_resolution:
255
+ log.info(
256
+ "%s Artifact is text-based. Attempting recursive embed resolution.",
257
+ log_prefix,
258
+ )
259
+ try:
260
+ original_content_string = data_bytes.decode("utf-8")
261
+
262
+ context_for_resolver = {
263
+ "artifact_service": artifact_service,
264
+ "session_context": {
265
+ "app_name": component.gateway_id,
266
+ "user_id": user_id,
267
+ "session_id": session_id,
268
+ },
269
+ }
270
+ config_for_resolver = {
271
+ "gateway_max_artifact_resolve_size_bytes": component.gateway_max_artifact_resolve_size_bytes,
272
+ "gateway_recursive_embed_depth": component.gateway_recursive_embed_depth,
273
+ }
274
+
275
+ resolved_content_string = await resolve_embeds_recursively_in_string(
276
+ text=original_content_string,
277
+ context=context_for_resolver,
278
+ resolver_func=evaluate_embed,
279
+ types_to_resolve=LATE_EMBED_TYPES,
280
+ log_identifier=f"{log_prefix}[RecursiveResolve]",
281
+ config=config_for_resolver,
282
+ max_depth=component.gateway_recursive_embed_depth,
283
+ max_total_size=component.gateway_max_artifact_resolve_size_bytes,
284
+ )
285
+ data_bytes = resolved_content_string.encode("utf-8")
286
+ log.info(
287
+ "%s Recursive embed resolution complete. New size: %d bytes.",
288
+ log_prefix,
289
+ len(data_bytes),
290
+ )
291
+ except UnicodeDecodeError as ude:
292
+ log.warning(
293
+ "%s Failed to decode artifact for recursive resolution: %s. Serving original content.",
294
+ log_prefix,
295
+ ude,
296
+ )
297
+ except Exception as resolve_err:
298
+ log.exception(
299
+ "%s Error during recursive embed resolution: %s. Serving original content.",
300
+ log_prefix,
301
+ resolve_err,
302
+ )
303
+ else:
304
+ log.info(
305
+ "%s Artifact is not text-based or embed resolution is disabled. Serving original content.",
306
+ log_prefix,
307
+ )
308
+
309
+ filename_encoded = quote(filename)
310
+ return StreamingResponse(
311
+ io.BytesIO(data_bytes),
312
+ media_type=mime_type,
313
+ headers={"Content-Disposition": f"attachment; filename*=UTF-8''{filename_encoded}"}
314
+ )
315
+
316
+ except FileNotFoundError:
317
+ log.warning("%s Artifact not found by service.", log_prefix)
318
+ raise HTTPException(
319
+ status_code=status.HTTP_404_NOT_FOUND,
320
+ detail=f"Artifact '{filename}' not found.",
321
+ )
322
+ except Exception as e:
323
+ log.exception("%s Error loading artifact: %s", log_prefix, e)
324
+ raise HTTPException(
325
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
326
+ detail=f"Failed to load artifact: {str(e)}",
327
+ )
328
+
329
+
330
+ @router.get(
331
+ "/{filename}/versions/{version}",
332
+ summary="Get Specific Artifact Version Content",
333
+ description="Retrieves the content of a specific version of an artifact.",
334
+ )
335
+ async def get_specific_artifact_version(
336
+ filename: str = Path(..., title="Filename", description="The name of the artifact"),
337
+ version: Union[int, str] = Path(
338
+ ...,
339
+ title="Version",
340
+ description="The specific version number to retrieve, or 'latest'",
341
+ ),
342
+ artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
343
+ user_id: str = Depends(get_user_id),
344
+ session_id: str = Depends(ensure_session_id),
345
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
346
+ config_resolver: ConfigResolver = Depends(get_config_resolver),
347
+ user_config: dict = Depends(get_user_config),
348
+ ):
349
+ """
350
+ Retrieves the content of a specific version of the specified artifact
351
+ associated with the current user and session ID.
352
+ """
353
+ if not config_resolver.is_feature_enabled(
354
+ user_config, {"required_scopes": ["tool:artifact:load"]}, {}
355
+ ):
356
+ raise HTTPException(
357
+ status_code=403, detail="Not authorized to load artifact version"
358
+ )
359
+ log_prefix = f"[ArtifactRouter:GetVersion:{filename} v{version}] User={user_id}, Session={session_id} -"
360
+ log.info("%s Request received.", log_prefix)
361
+
362
+ if artifact_service is None:
363
+ log.error("%s Artifact service is not configured or available.", log_prefix)
364
+ raise HTTPException(
365
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
366
+ detail="Artifact service is not configured.",
367
+ )
368
+
369
+ try:
370
+ app_name = component.get_config("name", "A2A_WebUI_App")
371
+
372
+ load_result = await load_artifact_content_or_metadata(
373
+ artifact_service=artifact_service,
374
+ app_name=app_name,
375
+ user_id=user_id,
376
+ session_id=session_id,
377
+ filename=filename,
378
+ version=version,
379
+ load_metadata_only=False,
380
+ return_raw_bytes=True,
381
+ log_identifier_prefix=f"[ArtifactRouter:GetVersion]",
382
+ )
383
+
384
+ if load_result.get("status") != "success":
385
+ error_message = load_result.get(
386
+ "message", f"Failed to load artifact '{filename}' version '{version}'."
387
+ )
388
+ log.warning("%s %s", log_prefix, error_message)
389
+ if (
390
+ "not found" in error_message.lower()
391
+ or "no versions available" in error_message.lower()
392
+ ):
393
+ status_code = status.HTTP_404_NOT_FOUND
394
+ elif "invalid version" in error_message.lower():
395
+ status_code = status.HTTP_400_BAD_REQUEST
396
+ else:
397
+ status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
398
+ raise HTTPException(status_code=status_code, detail=error_message)
399
+
400
+ data_bytes = load_result.get("raw_bytes")
401
+ mime_type = load_result.get("mime_type", "application/octet-stream")
402
+ resolved_version_from_helper = load_result.get("version")
403
+ if data_bytes is None:
404
+
405
+ log.error(
406
+ "%s Helper (with return_raw_bytes=True) returned success but no raw_bytes for '%s' v%s (resolved to %s).",
407
+ log_prefix,
408
+ filename,
409
+ version,
410
+ resolved_version_from_helper,
411
+ )
412
+ raise HTTPException(
413
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
414
+ detail="Internal error retrieving artifact content.",
415
+ )
416
+
417
+ log.info(
418
+ "%s Artifact '%s' version %s (resolved to %s) loaded successfully (%d bytes, %s). Streaming content.",
419
+ log_prefix,
420
+ filename,
421
+ version,
422
+ resolved_version_from_helper,
423
+ len(data_bytes),
424
+ mime_type,
425
+ )
426
+
427
+ if is_text_based_mime_type(mime_type) and component.enable_embed_resolution:
428
+ log.info(
429
+ "%s Artifact is text-based. Attempting recursive embed resolution.",
430
+ log_prefix,
431
+ )
432
+ try:
433
+ original_content_string = data_bytes.decode("utf-8")
434
+
435
+ context_for_resolver = {
436
+ "artifact_service": artifact_service,
437
+ "session_context": {
438
+ "app_name": component.gateway_id,
439
+ "user_id": user_id,
440
+ "session_id": session_id,
441
+ },
442
+ }
443
+ config_for_resolver = {
444
+ "gateway_max_artifact_resolve_size_bytes": component.gateway_max_artifact_resolve_size_bytes,
445
+ "gateway_recursive_embed_depth": component.gateway_recursive_embed_depth,
446
+ }
447
+
448
+ resolved_content_string = await resolve_embeds_recursively_in_string(
449
+ text=original_content_string,
450
+ context=context_for_resolver,
451
+ resolver_func=evaluate_embed,
452
+ types_to_resolve=LATE_EMBED_TYPES,
453
+ log_identifier=f"{log_prefix}[RecursiveResolve]",
454
+ config=config_for_resolver,
455
+ max_depth=component.gateway_recursive_embed_depth,
456
+ max_total_size=component.gateway_max_artifact_resolve_size_bytes,
457
+ )
458
+ data_bytes = resolved_content_string.encode("utf-8")
459
+ log.info(
460
+ "%s Recursive embed resolution complete. New size: %d bytes.",
461
+ log_prefix,
462
+ len(data_bytes),
463
+ )
464
+ except UnicodeDecodeError as ude:
465
+ log.warning(
466
+ "%s Failed to decode artifact for recursive resolution: %s. Serving original content.",
467
+ log_prefix,
468
+ ude,
469
+ )
470
+ except Exception as resolve_err:
471
+ log.exception(
472
+ "%s Error during recursive embed resolution: %s. Serving original content.",
473
+ log_prefix,
474
+ resolve_err,
475
+ )
476
+ else:
477
+ log.info(
478
+ "%s Artifact is not text-based or embed resolution is disabled. Serving original content.",
479
+ log_prefix,
480
+ )
481
+
482
+ filename_encoded = quote(filename)
483
+ return StreamingResponse(
484
+ io.BytesIO(data_bytes),
485
+ media_type=mime_type,
486
+ headers={"Content-Disposition": f"attachment; filename*=UTF-8''{filename_encoded}"}
487
+ )
488
+
489
+ except FileNotFoundError:
490
+ log.warning("%s Artifact version not found by service.", log_prefix)
491
+ raise HTTPException(
492
+ status_code=status.HTTP_404_NOT_FOUND,
493
+ detail=f"Artifact '{filename}' version {version} not found.",
494
+ )
495
+ except ValueError as ve:
496
+ log.warning("%s Invalid request (e.g., version format): %s", log_prefix, ve)
497
+ raise HTTPException(
498
+ status_code=status.HTTP_400_BAD_REQUEST,
499
+ detail=f"Invalid request: {str(ve)}",
500
+ )
501
+ except Exception as e:
502
+ log.exception("%s Error loading artifact version: %s", log_prefix, e)
503
+ raise HTTPException(
504
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
505
+ detail=f"Failed to load artifact version: {str(e)}",
506
+ )
507
+
508
+
509
+ @router.get(
510
+ "/by-uri",
511
+ response_class=StreamingResponse,
512
+ summary="Get Artifact by URI",
513
+ description="Resolves a formal artifact:// URI and streams its content. This endpoint is secure and validates that the requesting user is authorized to access the specified artifact.",
514
+ )
515
+ async def get_artifact_by_uri(
516
+ uri: str,
517
+ requesting_user_id: str = Depends(get_user_id),
518
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
519
+ config_resolver: ConfigResolver = Depends(get_config_resolver),
520
+ user_config: dict = Depends(get_user_config),
521
+ ):
522
+ """
523
+ Resolves an artifact:// URI and streams its content.
524
+ This allows fetching artifacts from any context, not just the current user's session,
525
+ after performing an authorization check.
526
+ """
527
+ log_id_prefix = f"[ArtifactRouter:by-uri]"
528
+ log.info(
529
+ "%s Received request for URI: %s from user: %s",
530
+ log_id_prefix,
531
+ uri,
532
+ requesting_user_id,
533
+ )
534
+ artifact_service = component.get_shared_artifact_service()
535
+ if not artifact_service:
536
+ raise HTTPException(
537
+ status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
538
+ detail="Artifact service not available.",
539
+ )
540
+
541
+ try:
542
+ parsed_uri = urlparse(uri)
543
+ if parsed_uri.scheme != "artifact":
544
+ raise ValueError("Invalid URI scheme, must be 'artifact'.")
545
+
546
+ app_name = parsed_uri.netloc
547
+ path_parts = parsed_uri.path.strip("/").split("/")
548
+ if not app_name or len(path_parts) != 3:
549
+ raise ValueError(
550
+ "Invalid URI path structure. Expected artifact://app_name/user_id/session_id/filename"
551
+ )
552
+
553
+ owner_user_id, session_id, filename = path_parts
554
+
555
+ query_params = parse_qs(parsed_uri.query)
556
+ version_list = query_params.get("version")
557
+ if not version_list or not version_list[0]:
558
+ raise ValueError("Version query parameter is required.")
559
+ version = version_list[0]
560
+
561
+ log.info(
562
+ "%s Parsed URI: app=%s, owner=%s, session=%s, file=%s, version=%s",
563
+ log_id_prefix,
564
+ app_name,
565
+ owner_user_id,
566
+ session_id,
567
+ filename,
568
+ version,
569
+ )
570
+
571
+ if not config_resolver.is_feature_enabled(
572
+ user_config, {"required_scopes": ["tool:artifact:load"]}, {}
573
+ ):
574
+ raise HTTPException(
575
+ status_code=403, detail="Not authorized to load artifact by URI"
576
+ )
577
+ log.warning(
578
+ "%s Authorization denied for user '%s' to access artifact URI '%s'",
579
+ log_id_prefix,
580
+ requesting_user_id,
581
+ uri,
582
+ )
583
+ raise HTTPException(
584
+ status_code=403, detail="Permission denied to access this artifact."
585
+ )
586
+
587
+ log.info(
588
+ "%s User '%s' authorized to access artifact URI.",
589
+ log_id_prefix,
590
+ requesting_user_id,
591
+ )
592
+
593
+ loaded_artifact = await load_artifact_content_or_metadata(
594
+ artifact_service=artifact_service,
595
+ app_name=app_name,
596
+ user_id=owner_user_id,
597
+ session_id=session_id,
598
+ filename=filename,
599
+ version=int(version),
600
+ return_raw_bytes=True,
601
+ log_identifier_prefix=log_id_prefix,
602
+ component=component,
603
+ )
604
+
605
+ if loaded_artifact.get("status") != "success":
606
+ raise HTTPException(status_code=404, detail=loaded_artifact.get("message"))
607
+
608
+ content_bytes = loaded_artifact.get("raw_bytes")
609
+ mime_type = loaded_artifact.get("mime_type", "application/octet-stream")
610
+
611
+ filename_encoded = quote(filename)
612
+ return StreamingResponse(
613
+ io.BytesIO(content_bytes),
614
+ media_type=mime_type,
615
+ headers={"Content-Disposition": f"attachment; filename*=UTF-8''{filename_encoded}"}
616
+ )
617
+
618
+ except (ValueError, IndexError) as e:
619
+ raise HTTPException(status_code=400, detail=f"Invalid artifact URI: {e}")
620
+ except Exception as e:
621
+ log.exception("%s Error fetching artifact by URI: %s", log_id_prefix, e)
622
+ raise HTTPException(
623
+ status_code=500, detail="Internal server error fetching artifact by URI"
624
+ )
625
+
626
+
627
+ @router.post(
628
+ "/{filename}",
629
+ status_code=status.HTTP_201_CREATED,
630
+ response_model=Dict[str, Any],
631
+ summary="Upload Artifact (Create/Update Version with Metadata)",
632
+ description="Uploads file content and optional metadata to create or update an artifact version.",
633
+ )
634
+ async def upload_artifact(
635
+ filename: str = Path(
636
+ ..., title="Filename", description="The name of the artifact to create/update"
637
+ ),
638
+ upload_file: UploadFile = File(..., description="The file content to upload"),
639
+ metadata_json: Optional[str] = Form(
640
+ None, description="JSON string of artifact metadata (e.g., description, source)"
641
+ ),
642
+ artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
643
+ user_id: str = Depends(get_user_id),
644
+ session_id: str = Depends(ensure_session_id),
645
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
646
+ config_resolver: ConfigResolver = Depends(get_config_resolver),
647
+ user_config: dict = Depends(get_user_config),
648
+ ):
649
+ """
650
+ Uploads a file to create a new version of the specified artifact
651
+ associated with the current user and session ID. Also saves associated metadata.
652
+ """
653
+ if not config_resolver.is_feature_enabled(
654
+ user_config, {"required_scopes": ["tool:artifact:create"]}, {}
655
+ ):
656
+ raise HTTPException(status_code=403, detail="Not authorized to upload artifact")
657
+ log_prefix = (
658
+ f"[ArtifactRouter:Post:{filename}] User={user_id}, Session={session_id} -"
659
+ )
660
+ log.info(
661
+ "%s Request received. Upload filename: '%s', content type: %s",
662
+ log_prefix,
663
+ upload_file.filename,
664
+ upload_file.content_type,
665
+ f"Metadata provided: {bool(metadata_json)}",
666
+ )
667
+
668
+ if artifact_service is None:
669
+ log.error("%s Artifact service is not configured or available.", log_prefix)
670
+ raise HTTPException(
671
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
672
+ detail="Artifact service is not configured.",
673
+ )
674
+
675
+ try:
676
+ content_bytes = await upload_file.read()
677
+ if not content_bytes:
678
+ log.warning("%s Uploaded file is empty.", log_prefix)
679
+ raise HTTPException(
680
+ status_code=status.HTTP_400_BAD_REQUEST,
681
+ detail="Uploaded file cannot be empty.",
682
+ )
683
+
684
+ mime_type = upload_file.content_type or "application/octet-stream"
685
+
686
+ parsed_metadata = {}
687
+ if metadata_json:
688
+ try:
689
+ parsed_metadata = json.loads(metadata_json)
690
+ if not isinstance(parsed_metadata, dict):
691
+ log.warning(
692
+ "%s Metadata JSON did not parse to a dictionary. Ignoring.",
693
+ log_prefix,
694
+ )
695
+ parsed_metadata = {}
696
+ except json.JSONDecodeError as json_err:
697
+ log.warning(
698
+ "%s Failed to parse metadata_json: %s. Proceeding without it.",
699
+ log_prefix,
700
+ json_err,
701
+ )
702
+
703
+ app_name = component.get_config("name", "A2A_WebUI_App")
704
+ current_timestamp = datetime.now(timezone.utc)
705
+
706
+ save_result = await save_artifact_with_metadata(
707
+ artifact_service=artifact_service,
708
+ app_name=app_name,
709
+ user_id=user_id,
710
+ session_id=session_id,
711
+ filename=filename,
712
+ content_bytes=content_bytes,
713
+ mime_type=mime_type,
714
+ metadata_dict=parsed_metadata,
715
+ timestamp=current_timestamp,
716
+ schema_max_keys=component.get_config(
717
+ "schema_max_keys", DEFAULT_SCHEMA_MAX_KEYS
718
+ ),
719
+ )
720
+
721
+ if save_result["status"] in ["success", "partial_success"]:
722
+ log.info(
723
+ "%s Artifact and metadata processing completed. Data version: %s, Metadata version: %s. Message: %s",
724
+ log_prefix,
725
+ save_result.get("data_version"),
726
+ save_result.get("metadata_version"),
727
+ save_result.get("message"),
728
+ )
729
+ return {
730
+ "filename": filename,
731
+ "data_version": save_result.get("data_version"),
732
+ "metadata_version": save_result.get("metadata_version"),
733
+ "mime_type": mime_type,
734
+ "size": len(content_bytes),
735
+ "message": save_result.get("message"),
736
+ "status": save_result["status"],
737
+ }
738
+ else:
739
+ log.error(
740
+ "%s Failed to save artifact and metadata: %s",
741
+ log_prefix,
742
+ save_result.get("message"),
743
+ )
744
+ raise HTTPException(
745
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
746
+ detail=save_result.get(
747
+ "message", "Failed to save artifact with metadata."
748
+ ),
749
+ )
750
+
751
+ except HTTPException:
752
+ raise
753
+ except Exception as e:
754
+ log.exception("%s Error saving artifact: %s", log_prefix, e)
755
+ raise HTTPException(
756
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
757
+ detail=f"Failed to save artifact: {str(e)}",
758
+ )
759
+ finally:
760
+
761
+ await upload_file.close()
762
+ log.debug("%s Upload file closed.", log_prefix)
763
+
764
+
765
+ @router.delete(
766
+ "/{filename}",
767
+ status_code=status.HTTP_204_NO_CONTENT,
768
+ summary="Delete Artifact",
769
+ description="Deletes an artifact and all its versions.",
770
+ )
771
+ async def delete_artifact(
772
+ filename: str = Path(
773
+ ..., title="Filename", description="The name of the artifact to delete"
774
+ ),
775
+ artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
776
+ user_id: str = Depends(get_user_id),
777
+ session_id: str = Depends(ensure_session_id),
778
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
779
+ config_resolver: ConfigResolver = Depends(get_config_resolver),
780
+ user_config: dict = Depends(get_user_config),
781
+ ):
782
+ """
783
+ Deletes the specified artifact (including all its versions)
784
+ associated with the current user and session ID.
785
+ """
786
+ if not config_resolver.is_feature_enabled(
787
+ user_config, {"required_scopes": ["tool:artifact:delete"]}, {}
788
+ ):
789
+ raise HTTPException(status_code=403, detail="Not authorized to delete artifact")
790
+ log_prefix = (
791
+ f"[ArtifactRouter:Delete:{filename}] User={user_id}, Session={session_id} -"
792
+ )
793
+ log.info("%s Request received.", log_prefix)
794
+
795
+ if artifact_service is None:
796
+ log.error("%s Artifact service is not configured or available.", log_prefix)
797
+ raise HTTPException(
798
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
799
+ detail="Artifact service is not configured.",
800
+ )
801
+
802
+ try:
803
+ app_name = component.get_config("name", "A2A_WebUI_App")
804
+
805
+ await artifact_service.delete_artifact(
806
+ app_name=app_name,
807
+ user_id=user_id,
808
+ session_id=session_id,
809
+ filename=filename,
810
+ )
811
+
812
+ log.info("%s Artifact deletion request processed successfully.", log_prefix)
813
+ return Response(status_code=status.HTTP_204_NO_CONTENT)
814
+
815
+ except Exception as e:
816
+
817
+ log.exception("%s Error deleting artifact: %s", log_prefix, e)
818
+ raise HTTPException(
819
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
820
+ detail=f"Failed to delete artifact: {str(e)}",
821
+ )