solace-agent-mesh 1.11.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (624) hide show
  1. solace_agent_mesh/__init__.py +0 -0
  2. solace_agent_mesh/agent/__init__.py +0 -0
  3. solace_agent_mesh/agent/adk/__init__.py +0 -0
  4. solace_agent_mesh/agent/adk/adk_llm.txt +226 -0
  5. solace_agent_mesh/agent/adk/adk_llm_detail.txt +566 -0
  6. solace_agent_mesh/agent/adk/alembic/README +74 -0
  7. solace_agent_mesh/agent/adk/alembic/env.py +77 -0
  8. solace_agent_mesh/agent/adk/alembic/script.py.mako +28 -0
  9. solace_agent_mesh/agent/adk/alembic/versions/e2902798564d_adk_session_db_upgrade.py +52 -0
  10. solace_agent_mesh/agent/adk/alembic.ini +112 -0
  11. solace_agent_mesh/agent/adk/app_llm_agent.py +52 -0
  12. solace_agent_mesh/agent/adk/artifacts/__init__.py +1 -0
  13. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +171 -0
  14. solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +545 -0
  15. solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +609 -0
  16. solace_agent_mesh/agent/adk/callbacks.py +2318 -0
  17. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +406 -0
  18. solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +415 -0
  19. solace_agent_mesh/agent/adk/mcp_content_processor.py +666 -0
  20. solace_agent_mesh/agent/adk/models/lite_llm.py +1026 -0
  21. solace_agent_mesh/agent/adk/models/models_llm.txt +189 -0
  22. solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +132 -0
  23. solace_agent_mesh/agent/adk/runner.py +390 -0
  24. solace_agent_mesh/agent/adk/schema_migration.py +88 -0
  25. solace_agent_mesh/agent/adk/services.py +468 -0
  26. solace_agent_mesh/agent/adk/setup.py +1325 -0
  27. solace_agent_mesh/agent/adk/stream_parser.py +415 -0
  28. solace_agent_mesh/agent/adk/tool_wrapper.py +165 -0
  29. solace_agent_mesh/agent/agent_llm.txt +369 -0
  30. solace_agent_mesh/agent/agent_llm_detail.txt +1702 -0
  31. solace_agent_mesh/agent/protocol/__init__.py +0 -0
  32. solace_agent_mesh/agent/protocol/event_handlers.py +2041 -0
  33. solace_agent_mesh/agent/protocol/protocol_llm.txt +81 -0
  34. solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +92 -0
  35. solace_agent_mesh/agent/proxies/__init__.py +0 -0
  36. solace_agent_mesh/agent/proxies/a2a/__init__.py +3 -0
  37. solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +190 -0
  38. solace_agent_mesh/agent/proxies/a2a/app.py +56 -0
  39. solace_agent_mesh/agent/proxies/a2a/component.py +1585 -0
  40. solace_agent_mesh/agent/proxies/a2a/config.py +216 -0
  41. solace_agent_mesh/agent/proxies/a2a/oauth_token_cache.py +104 -0
  42. solace_agent_mesh/agent/proxies/base/__init__.py +3 -0
  43. solace_agent_mesh/agent/proxies/base/app.py +100 -0
  44. solace_agent_mesh/agent/proxies/base/base_llm.txt +148 -0
  45. solace_agent_mesh/agent/proxies/base/component.py +816 -0
  46. solace_agent_mesh/agent/proxies/base/config.py +85 -0
  47. solace_agent_mesh/agent/proxies/base/proxy_task_context.py +19 -0
  48. solace_agent_mesh/agent/proxies/proxies_llm.txt +283 -0
  49. solace_agent_mesh/agent/sac/__init__.py +0 -0
  50. solace_agent_mesh/agent/sac/app.py +595 -0
  51. solace_agent_mesh/agent/sac/component.py +3668 -0
  52. solace_agent_mesh/agent/sac/patch_adk.py +103 -0
  53. solace_agent_mesh/agent/sac/sac_llm.txt +189 -0
  54. solace_agent_mesh/agent/sac/sac_llm_detail.txt +200 -0
  55. solace_agent_mesh/agent/sac/task_execution_context.py +415 -0
  56. solace_agent_mesh/agent/testing/__init__.py +3 -0
  57. solace_agent_mesh/agent/testing/debug_utils.py +135 -0
  58. solace_agent_mesh/agent/testing/testing_llm.txt +58 -0
  59. solace_agent_mesh/agent/testing/testing_llm_detail.txt +68 -0
  60. solace_agent_mesh/agent/tools/__init__.py +16 -0
  61. solace_agent_mesh/agent/tools/audio_tools.py +1740 -0
  62. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +2500 -0
  63. solace_agent_mesh/agent/tools/builtin_data_analysis_tools.py +244 -0
  64. solace_agent_mesh/agent/tools/dynamic_tool.py +396 -0
  65. solace_agent_mesh/agent/tools/general_agent_tools.py +572 -0
  66. solace_agent_mesh/agent/tools/image_tools.py +1185 -0
  67. solace_agent_mesh/agent/tools/peer_agent_tool.py +363 -0
  68. solace_agent_mesh/agent/tools/registry.py +38 -0
  69. solace_agent_mesh/agent/tools/test_tools.py +136 -0
  70. solace_agent_mesh/agent/tools/time_tools.py +126 -0
  71. solace_agent_mesh/agent/tools/tool_config_types.py +93 -0
  72. solace_agent_mesh/agent/tools/tool_definition.py +53 -0
  73. solace_agent_mesh/agent/tools/tools_llm.txt +276 -0
  74. solace_agent_mesh/agent/tools/tools_llm_detail.txt +275 -0
  75. solace_agent_mesh/agent/tools/web_tools.py +392 -0
  76. solace_agent_mesh/agent/utils/__init__.py +0 -0
  77. solace_agent_mesh/agent/utils/artifact_helpers.py +1353 -0
  78. solace_agent_mesh/agent/utils/config_parser.py +49 -0
  79. solace_agent_mesh/agent/utils/context_helpers.py +77 -0
  80. solace_agent_mesh/agent/utils/utils_llm.txt +152 -0
  81. solace_agent_mesh/agent/utils/utils_llm_detail.txt +149 -0
  82. solace_agent_mesh/assets/docs/404.html +16 -0
  83. solace_agent_mesh/assets/docs/assets/css/styles.8162edfb.css +1 -0
  84. solace_agent_mesh/assets/docs/assets/images/Solace_AI_Framework_With_Broker-85f0a306a9bcdd20b390b7a949f6d862.png +0 -0
  85. solace_agent_mesh/assets/docs/assets/images/sam-enterprise-credentials-b269f095349473118b2b33bdfcc40122.png +0 -0
  86. solace_agent_mesh/assets/docs/assets/js/032c2d61.f3d37824.js +1 -0
  87. solace_agent_mesh/assets/docs/assets/js/05749d90.19ac4f35.js +1 -0
  88. solace_agent_mesh/assets/docs/assets/js/0bcf40b7.c019ad46.js +1 -0
  89. solace_agent_mesh/assets/docs/assets/js/1001.0182a8bd.js +1 -0
  90. solace_agent_mesh/assets/docs/assets/js/1039.0bd46aa1.js +1 -0
  91. solace_agent_mesh/assets/docs/assets/js/149.b797a808.js +1 -0
  92. solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +1 -0
  93. solace_agent_mesh/assets/docs/assets/js/15e40e79.434bb30f.js +1 -0
  94. solace_agent_mesh/assets/docs/assets/js/165.6a39807d.js +2 -0
  95. solace_agent_mesh/assets/docs/assets/js/165.6a39807d.js.LICENSE.txt +9 -0
  96. solace_agent_mesh/assets/docs/assets/js/17896441.e612dfb4.js +1 -0
  97. solace_agent_mesh/assets/docs/assets/js/2130.ab9fd314.js +1 -0
  98. solace_agent_mesh/assets/docs/assets/js/2131ec11.5c7a1f6e.js +1 -0
  99. solace_agent_mesh/assets/docs/assets/js/2237.5e477fc6.js +1 -0
  100. solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js +2 -0
  101. solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js.LICENSE.txt +13 -0
  102. solace_agent_mesh/assets/docs/assets/js/2334.1cf50a20.js +1 -0
  103. solace_agent_mesh/assets/docs/assets/js/240a0364.9ad94d1b.js +1 -0
  104. solace_agent_mesh/assets/docs/assets/js/2987107d.a80604f9.js +1 -0
  105. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +1 -0
  106. solace_agent_mesh/assets/docs/assets/js/3219.adc1d663.js +1 -0
  107. solace_agent_mesh/assets/docs/assets/js/341393d4.0fac2613.js +1 -0
  108. solace_agent_mesh/assets/docs/assets/js/3624.0eaa1fd0.js +1 -0
  109. solace_agent_mesh/assets/docs/assets/js/375.708d48db.js +1 -0
  110. solace_agent_mesh/assets/docs/assets/js/3834.b6cd790e.js +1 -0
  111. solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +1 -0
  112. solace_agent_mesh/assets/docs/assets/js/3ac1795d.28b7c67b.js +1 -0
  113. solace_agent_mesh/assets/docs/assets/js/3ff0015d.2ddc75c0.js +1 -0
  114. solace_agent_mesh/assets/docs/assets/js/41adc471.48b12a4e.js +1 -0
  115. solace_agent_mesh/assets/docs/assets/js/4250.95455b28.js +1 -0
  116. solace_agent_mesh/assets/docs/assets/js/4356.d169ab5b.js +1 -0
  117. solace_agent_mesh/assets/docs/assets/js/4458.518e66fa.js +1 -0
  118. solace_agent_mesh/assets/docs/assets/js/4488.c7cc3442.js +1 -0
  119. solace_agent_mesh/assets/docs/assets/js/4494.6ee23046.js +1 -0
  120. solace_agent_mesh/assets/docs/assets/js/4855.fc4444b6.js +1 -0
  121. solace_agent_mesh/assets/docs/assets/js/4866.22daefc0.js +1 -0
  122. solace_agent_mesh/assets/docs/assets/js/4950.ca4caeda.js +1 -0
  123. solace_agent_mesh/assets/docs/assets/js/509e993c.a1fbf45a.js +1 -0
  124. solace_agent_mesh/assets/docs/assets/js/5388.7a136447.js +1 -0
  125. solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +1 -0
  126. solace_agent_mesh/assets/docs/assets/js/55b7b518.29d6e75d.js +1 -0
  127. solace_agent_mesh/assets/docs/assets/js/5607.081356f8.js +1 -0
  128. solace_agent_mesh/assets/docs/assets/js/5864.b0d0e9de.js +1 -0
  129. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.90a87880.js +1 -0
  130. solace_agent_mesh/assets/docs/assets/js/5e95c892.558d5167.js +1 -0
  131. solace_agent_mesh/assets/docs/assets/js/6063ff4c.ef84f702.js +1 -0
  132. solace_agent_mesh/assets/docs/assets/js/60702c0e.a8bdd79b.js +1 -0
  133. solace_agent_mesh/assets/docs/assets/js/6143.0a1464c9.js +1 -0
  134. solace_agent_mesh/assets/docs/assets/js/631738c7.fa471607.js +1 -0
  135. solace_agent_mesh/assets/docs/assets/js/6395.e9c73649.js +1 -0
  136. solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +1 -0
  137. solace_agent_mesh/assets/docs/assets/js/66d4869e.b77431fc.js +1 -0
  138. solace_agent_mesh/assets/docs/assets/js/6796.51d2c9b7.js +1 -0
  139. solace_agent_mesh/assets/docs/assets/js/6976.379be23b.js +1 -0
  140. solace_agent_mesh/assets/docs/assets/js/6978.ee0b945c.js +1 -0
  141. solace_agent_mesh/assets/docs/assets/js/6a520c9d.b6e3f2ce.js +1 -0
  142. solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
  143. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
  144. solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
  145. solace_agent_mesh/assets/docs/assets/js/6fdfefc7.99de744e.js +1 -0
  146. solace_agent_mesh/assets/docs/assets/js/7040.cb436723.js +1 -0
  147. solace_agent_mesh/assets/docs/assets/js/7195.412f418a.js +1 -0
  148. solace_agent_mesh/assets/docs/assets/js/71da7b71.374b9d54.js +1 -0
  149. solace_agent_mesh/assets/docs/assets/js/722f809d.965da774.js +1 -0
  150. solace_agent_mesh/assets/docs/assets/js/7280.3fb73bdb.js +1 -0
  151. solace_agent_mesh/assets/docs/assets/js/742f027b.46c07808.js +1 -0
  152. solace_agent_mesh/assets/docs/assets/js/77cf947d.48cb18a2.js +1 -0
  153. solace_agent_mesh/assets/docs/assets/js/7845.e33e7c4c.js +1 -0
  154. solace_agent_mesh/assets/docs/assets/js/7900.69516146.js +1 -0
  155. solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +1 -0
  156. solace_agent_mesh/assets/docs/assets/js/81a99df0.2484b8d9.js +1 -0
  157. solace_agent_mesh/assets/docs/assets/js/82fbfb93.161823a5.js +1 -0
  158. solace_agent_mesh/assets/docs/assets/js/8356.8a379c04.js +1 -0
  159. solace_agent_mesh/assets/docs/assets/js/8567.4732c6b7.js +1 -0
  160. solace_agent_mesh/assets/docs/assets/js/8573.cb04eda5.js +1 -0
  161. solace_agent_mesh/assets/docs/assets/js/8577.1d54e766.js +1 -0
  162. solace_agent_mesh/assets/docs/assets/js/8591.5d015485.js +2 -0
  163. solace_agent_mesh/assets/docs/assets/js/8591.5d015485.js.LICENSE.txt +61 -0
  164. solace_agent_mesh/assets/docs/assets/js/8709.7ecd4047.js +1 -0
  165. solace_agent_mesh/assets/docs/assets/js/8731.6c1dbf0c.js +1 -0
  166. solace_agent_mesh/assets/docs/assets/js/8908.f9d1b506.js +1 -0
  167. solace_agent_mesh/assets/docs/assets/js/8b032486.91a91afc.js +1 -0
  168. solace_agent_mesh/assets/docs/assets/js/9157.b4093d07.js +1 -0
  169. solace_agent_mesh/assets/docs/assets/js/924ffdeb.975e428a.js +1 -0
  170. solace_agent_mesh/assets/docs/assets/js/9278.a4fd875d.js +1 -0
  171. solace_agent_mesh/assets/docs/assets/js/945fb41e.6f4cdffd.js +1 -0
  172. solace_agent_mesh/assets/docs/assets/js/94e8668d.16083b3f.js +1 -0
  173. solace_agent_mesh/assets/docs/assets/js/9616.b75c2f6d.js +1 -0
  174. solace_agent_mesh/assets/docs/assets/js/9793.c6d16376.js +1 -0
  175. solace_agent_mesh/assets/docs/assets/js/9bb13469.b2333011.js +1 -0
  176. solace_agent_mesh/assets/docs/assets/js/9e9d0a82.570c057b.js +1 -0
  177. solace_agent_mesh/assets/docs/assets/js/a7bd4aaa.2204d2f7.js +1 -0
  178. solace_agent_mesh/assets/docs/assets/js/a94703ab.3e5fbcb3.js +1 -0
  179. solace_agent_mesh/assets/docs/assets/js/ab9708a8.245ae0ef.js +1 -0
  180. solace_agent_mesh/assets/docs/assets/js/aba21aa0.c42a534c.js +1 -0
  181. solace_agent_mesh/assets/docs/assets/js/ad71b5ed.af3ecfd1.js +1 -0
  182. solace_agent_mesh/assets/docs/assets/js/ad87452a.9d73dad6.js +1 -0
  183. solace_agent_mesh/assets/docs/assets/js/c198a0dc.8f31f867.js +1 -0
  184. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.0e0d8baf.js +1 -0
  185. solace_agent_mesh/assets/docs/assets/js/cab03b5b.6a073091.js +1 -0
  186. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.07e170dd.js +1 -0
  187. solace_agent_mesh/assets/docs/assets/js/ceb2a7a6.5d92d7d0.js +1 -0
  188. solace_agent_mesh/assets/docs/assets/js/da0b5bad.b62f7b08.js +1 -0
  189. solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +1 -0
  190. solace_agent_mesh/assets/docs/assets/js/db924877.e98d12a1.js +1 -0
  191. solace_agent_mesh/assets/docs/assets/js/dd817ffc.c37a755e.js +1 -0
  192. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
  193. solace_agent_mesh/assets/docs/assets/js/de5f4c65.e8241890.js +1 -0
  194. solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.js +1 -0
  195. solace_agent_mesh/assets/docs/assets/js/e04b235d.52cb25ed.js +1 -0
  196. solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.b1068f9b.js +1 -0
  197. solace_agent_mesh/assets/docs/assets/js/e3d9abda.1476f570.js +1 -0
  198. solace_agent_mesh/assets/docs/assets/js/e6f9706b.4488e34c.js +1 -0
  199. solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +1 -0
  200. solace_agent_mesh/assets/docs/assets/js/f284c35a.250993bf.js +1 -0
  201. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.74710fc1.js +1 -0
  202. solace_agent_mesh/assets/docs/assets/js/main.7acf7ace.js +2 -0
  203. solace_agent_mesh/assets/docs/assets/js/main.7acf7ace.js.LICENSE.txt +81 -0
  204. solace_agent_mesh/assets/docs/assets/js/runtime~main.9e0813a2.js +1 -0
  205. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +154 -0
  206. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +99 -0
  207. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +90 -0
  208. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +107 -0
  209. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +166 -0
  210. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +101 -0
  211. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +219 -0
  212. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +92 -0
  213. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +29 -0
  214. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +55 -0
  215. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +110 -0
  216. solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +182 -0
  217. solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +147 -0
  218. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +345 -0
  219. solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +52 -0
  220. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +83 -0
  221. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +84 -0
  222. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +25 -0
  223. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +47 -0
  224. solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +85 -0
  225. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +60 -0
  226. solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +49 -0
  227. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +144 -0
  228. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +191 -0
  229. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +128 -0
  230. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +54 -0
  231. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +135 -0
  232. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +34 -0
  233. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +55 -0
  234. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +267 -0
  235. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +142 -0
  236. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +116 -0
  237. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +86 -0
  238. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +164 -0
  239. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +140 -0
  240. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +57 -0
  241. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +72 -0
  242. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +102 -0
  243. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +115 -0
  244. solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +86 -0
  245. solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +67 -0
  246. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +37 -0
  247. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +86 -0
  248. solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +324 -0
  249. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +247 -0
  250. solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
  251. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +184 -0
  252. solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +62 -0
  253. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +75 -0
  254. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +54 -0
  255. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +85 -0
  256. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +41 -0
  257. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +290 -0
  258. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +78 -0
  259. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +25 -0
  260. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +78 -0
  261. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +160 -0
  262. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +142 -0
  263. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +251 -0
  264. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +88 -0
  265. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +100 -0
  266. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +52 -0
  267. solace_agent_mesh/assets/docs/img/Solace_AI_Framework_With_Broker.png +0 -0
  268. solace_agent_mesh/assets/docs/img/logo.png +0 -0
  269. solace_agent_mesh/assets/docs/img/sac-flows.png +0 -0
  270. solace_agent_mesh/assets/docs/img/sac_parts_of_a_component.png +0 -0
  271. solace_agent_mesh/assets/docs/img/sam-enterprise-credentials.png +0 -0
  272. solace_agent_mesh/assets/docs/img/solace-logo-text.svg +18 -0
  273. solace_agent_mesh/assets/docs/img/solace-logo.png +0 -0
  274. solace_agent_mesh/assets/docs/lunr-index-1765810064709.json +1 -0
  275. solace_agent_mesh/assets/docs/lunr-index.json +1 -0
  276. solace_agent_mesh/assets/docs/search-doc-1765810064709.json +1 -0
  277. solace_agent_mesh/assets/docs/search-doc.json +1 -0
  278. solace_agent_mesh/assets/docs/sitemap.xml +1 -0
  279. solace_agent_mesh/cli/__init__.py +1 -0
  280. solace_agent_mesh/cli/commands/__init__.py +0 -0
  281. solace_agent_mesh/cli/commands/add_cmd/__init__.py +15 -0
  282. solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +250 -0
  283. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +729 -0
  284. solace_agent_mesh/cli/commands/add_cmd/gateway_cmd.py +322 -0
  285. solace_agent_mesh/cli/commands/add_cmd/web_add_agent_step.py +102 -0
  286. solace_agent_mesh/cli/commands/add_cmd/web_add_gateway_step.py +114 -0
  287. solace_agent_mesh/cli/commands/docs_cmd.py +60 -0
  288. solace_agent_mesh/cli/commands/eval_cmd.py +46 -0
  289. solace_agent_mesh/cli/commands/init_cmd/__init__.py +439 -0
  290. solace_agent_mesh/cli/commands/init_cmd/broker_step.py +201 -0
  291. solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
  292. solace_agent_mesh/cli/commands/init_cmd/directory_step.py +28 -0
  293. solace_agent_mesh/cli/commands/init_cmd/env_step.py +238 -0
  294. solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +365 -0
  295. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +464 -0
  296. solace_agent_mesh/cli/commands/init_cmd/project_files_step.py +38 -0
  297. solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +119 -0
  298. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +215 -0
  299. solace_agent_mesh/cli/commands/plugin_cmd/__init__.py +20 -0
  300. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +137 -0
  301. solace_agent_mesh/cli/commands/plugin_cmd/build_cmd.py +86 -0
  302. solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +144 -0
  303. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +306 -0
  304. solace_agent_mesh/cli/commands/plugin_cmd/install_cmd.py +283 -0
  305. solace_agent_mesh/cli/commands/plugin_cmd/official_registry.py +175 -0
  306. solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +305 -0
  307. solace_agent_mesh/cli/commands/run_cmd.py +215 -0
  308. solace_agent_mesh/cli/main.py +52 -0
  309. solace_agent_mesh/cli/utils.py +262 -0
  310. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-Dj3JtK42.js +1 -0
  311. solace_agent_mesh/client/webui/frontend/static/assets/client-ZKk9kEJ5.js +25 -0
  312. solace_agent_mesh/client/webui/frontend/static/assets/favicon-BLgzUch9.ico +0 -0
  313. solace_agent_mesh/client/webui/frontend/static/assets/main-BcUaNZ-Q.css +1 -0
  314. solace_agent_mesh/client/webui/frontend/static/assets/main-vjch4RYc.js +435 -0
  315. solace_agent_mesh/client/webui/frontend/static/assets/vendor-BNV4kZN0.js +535 -0
  316. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +15 -0
  317. solace_agent_mesh/client/webui/frontend/static/index.html +16 -0
  318. solace_agent_mesh/client/webui/frontend/static/mockServiceWorker.js +336 -0
  319. solace_agent_mesh/client/webui/frontend/static/ui-version.json +6 -0
  320. solace_agent_mesh/common/__init__.py +1 -0
  321. solace_agent_mesh/common/a2a/__init__.py +241 -0
  322. solace_agent_mesh/common/a2a/a2a_llm.txt +175 -0
  323. solace_agent_mesh/common/a2a/a2a_llm_detail.txt +193 -0
  324. solace_agent_mesh/common/a2a/artifact.py +368 -0
  325. solace_agent_mesh/common/a2a/events.py +213 -0
  326. solace_agent_mesh/common/a2a/message.py +375 -0
  327. solace_agent_mesh/common/a2a/protocol.py +689 -0
  328. solace_agent_mesh/common/a2a/task.py +127 -0
  329. solace_agent_mesh/common/a2a/translation.py +655 -0
  330. solace_agent_mesh/common/a2a/types.py +55 -0
  331. solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
  332. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +445 -0
  333. solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +736 -0
  334. solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
  335. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +48 -0
  336. solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
  337. solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +41 -0
  338. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +330 -0
  339. solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
  340. solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +48 -0
  341. solace_agent_mesh/common/agent_registry.py +122 -0
  342. solace_agent_mesh/common/common_llm.txt +230 -0
  343. solace_agent_mesh/common/common_llm_detail.txt +2562 -0
  344. solace_agent_mesh/common/constants.py +6 -0
  345. solace_agent_mesh/common/data_parts.py +150 -0
  346. solace_agent_mesh/common/exceptions.py +49 -0
  347. solace_agent_mesh/common/middleware/__init__.py +12 -0
  348. solace_agent_mesh/common/middleware/config_resolver.py +132 -0
  349. solace_agent_mesh/common/middleware/middleware_llm.txt +174 -0
  350. solace_agent_mesh/common/middleware/middleware_llm_detail.txt +185 -0
  351. solace_agent_mesh/common/middleware/registry.py +127 -0
  352. solace_agent_mesh/common/oauth/__init__.py +17 -0
  353. solace_agent_mesh/common/oauth/oauth_client.py +408 -0
  354. solace_agent_mesh/common/oauth/utils.py +50 -0
  355. solace_agent_mesh/common/sac/__init__.py +0 -0
  356. solace_agent_mesh/common/sac/sac_llm.txt +71 -0
  357. solace_agent_mesh/common/sac/sac_llm_detail.txt +82 -0
  358. solace_agent_mesh/common/sac/sam_component_base.py +730 -0
  359. solace_agent_mesh/common/sam_events/__init__.py +9 -0
  360. solace_agent_mesh/common/sam_events/event_service.py +208 -0
  361. solace_agent_mesh/common/sam_events/sam_events_llm.txt +104 -0
  362. solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +115 -0
  363. solace_agent_mesh/common/services/__init__.py +4 -0
  364. solace_agent_mesh/common/services/employee_service.py +164 -0
  365. solace_agent_mesh/common/services/identity_service.py +134 -0
  366. solace_agent_mesh/common/services/providers/__init__.py +4 -0
  367. solace_agent_mesh/common/services/providers/local_file_identity_service.py +151 -0
  368. solace_agent_mesh/common/services/providers/providers_llm.txt +81 -0
  369. solace_agent_mesh/common/services/services_llm.txt +368 -0
  370. solace_agent_mesh/common/services/services_llm_detail.txt +459 -0
  371. solace_agent_mesh/common/utils/__init__.py +7 -0
  372. solace_agent_mesh/common/utils/artifact_utils.py +31 -0
  373. solace_agent_mesh/common/utils/asyncio_macos_fix.py +88 -0
  374. solace_agent_mesh/common/utils/embeds/__init__.py +33 -0
  375. solace_agent_mesh/common/utils/embeds/constants.py +56 -0
  376. solace_agent_mesh/common/utils/embeds/converter.py +447 -0
  377. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +220 -0
  378. solace_agent_mesh/common/utils/embeds/evaluators.py +395 -0
  379. solace_agent_mesh/common/utils/embeds/modifiers.py +793 -0
  380. solace_agent_mesh/common/utils/embeds/resolver.py +967 -0
  381. solace_agent_mesh/common/utils/embeds/types.py +23 -0
  382. solace_agent_mesh/common/utils/in_memory_cache.py +108 -0
  383. solace_agent_mesh/common/utils/initializer.py +52 -0
  384. solace_agent_mesh/common/utils/log_formatters.py +64 -0
  385. solace_agent_mesh/common/utils/message_utils.py +80 -0
  386. solace_agent_mesh/common/utils/mime_helpers.py +172 -0
  387. solace_agent_mesh/common/utils/push_notification_auth.py +135 -0
  388. solace_agent_mesh/common/utils/pydantic_utils.py +159 -0
  389. solace_agent_mesh/common/utils/rbac_utils.py +69 -0
  390. solace_agent_mesh/common/utils/templates/__init__.py +8 -0
  391. solace_agent_mesh/common/utils/templates/liquid_renderer.py +210 -0
  392. solace_agent_mesh/common/utils/templates/template_resolver.py +161 -0
  393. solace_agent_mesh/common/utils/type_utils.py +28 -0
  394. solace_agent_mesh/common/utils/utils_llm.txt +335 -0
  395. solace_agent_mesh/common/utils/utils_llm_detail.txt +572 -0
  396. solace_agent_mesh/config_portal/__init__.py +0 -0
  397. solace_agent_mesh/config_portal/backend/__init__.py +0 -0
  398. solace_agent_mesh/config_portal/backend/common.py +77 -0
  399. solace_agent_mesh/config_portal/backend/plugin_catalog/__init__.py +0 -0
  400. solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +24 -0
  401. solace_agent_mesh/config_portal/backend/plugin_catalog/models.py +49 -0
  402. solace_agent_mesh/config_portal/backend/plugin_catalog/registry_manager.py +166 -0
  403. solace_agent_mesh/config_portal/backend/plugin_catalog/scraper.py +521 -0
  404. solace_agent_mesh/config_portal/backend/plugin_catalog_server.py +217 -0
  405. solace_agent_mesh/config_portal/backend/server.py +644 -0
  406. solace_agent_mesh/config_portal/frontend/static/client/Solace_community_logo.png +0 -0
  407. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-DiOiAjzL.js +103 -0
  408. solace_agent_mesh/config_portal/frontend/static/client/assets/components-Rk0n-9cK.js +140 -0
  409. solace_agent_mesh/config_portal/frontend/static/client/assets/entry.client-mvZjNKiz.js +19 -0
  410. solace_agent_mesh/config_portal/frontend/static/client/assets/index-DzNKzXrc.js +68 -0
  411. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-ba77705e.js +1 -0
  412. solace_agent_mesh/config_portal/frontend/static/client/assets/root-B17tZKK7.css +1 -0
  413. solace_agent_mesh/config_portal/frontend/static/client/assets/root-V2BeTIUc.js +10 -0
  414. solace_agent_mesh/config_portal/frontend/static/client/favicon.ico +0 -0
  415. solace_agent_mesh/config_portal/frontend/static/client/index.html +7 -0
  416. solace_agent_mesh/core_a2a/__init__.py +1 -0
  417. solace_agent_mesh/core_a2a/core_a2a_llm.txt +90 -0
  418. solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +101 -0
  419. solace_agent_mesh/core_a2a/service.py +307 -0
  420. solace_agent_mesh/evaluation/__init__.py +0 -0
  421. solace_agent_mesh/evaluation/evaluator.py +691 -0
  422. solace_agent_mesh/evaluation/message_organizer.py +553 -0
  423. solace_agent_mesh/evaluation/report/benchmark_info.html +35 -0
  424. solace_agent_mesh/evaluation/report/chart_section.html +141 -0
  425. solace_agent_mesh/evaluation/report/detailed_breakdown.html +28 -0
  426. solace_agent_mesh/evaluation/report/modal.html +59 -0
  427. solace_agent_mesh/evaluation/report/modal_chart_functions.js +411 -0
  428. solace_agent_mesh/evaluation/report/modal_script.js +296 -0
  429. solace_agent_mesh/evaluation/report/modal_styles.css +340 -0
  430. solace_agent_mesh/evaluation/report/performance_metrics_styles.css +93 -0
  431. solace_agent_mesh/evaluation/report/templates/footer.html +2 -0
  432. solace_agent_mesh/evaluation/report/templates/header.html +340 -0
  433. solace_agent_mesh/evaluation/report_data_processor.py +970 -0
  434. solace_agent_mesh/evaluation/report_generator.py +607 -0
  435. solace_agent_mesh/evaluation/run.py +954 -0
  436. solace_agent_mesh/evaluation/shared/__init__.py +92 -0
  437. solace_agent_mesh/evaluation/shared/constants.py +47 -0
  438. solace_agent_mesh/evaluation/shared/exceptions.py +50 -0
  439. solace_agent_mesh/evaluation/shared/helpers.py +35 -0
  440. solace_agent_mesh/evaluation/shared/test_case_loader.py +167 -0
  441. solace_agent_mesh/evaluation/shared/test_suite_loader.py +280 -0
  442. solace_agent_mesh/evaluation/subscriber.py +776 -0
  443. solace_agent_mesh/evaluation/summary_builder.py +880 -0
  444. solace_agent_mesh/gateway/__init__.py +0 -0
  445. solace_agent_mesh/gateway/adapter/__init__.py +1 -0
  446. solace_agent_mesh/gateway/adapter/base.py +143 -0
  447. solace_agent_mesh/gateway/adapter/types.py +221 -0
  448. solace_agent_mesh/gateway/base/__init__.py +1 -0
  449. solace_agent_mesh/gateway/base/app.py +345 -0
  450. solace_agent_mesh/gateway/base/base_llm.txt +226 -0
  451. solace_agent_mesh/gateway/base/base_llm_detail.txt +235 -0
  452. solace_agent_mesh/gateway/base/component.py +2030 -0
  453. solace_agent_mesh/gateway/base/task_context.py +75 -0
  454. solace_agent_mesh/gateway/gateway_llm.txt +369 -0
  455. solace_agent_mesh/gateway/gateway_llm_detail.txt +3885 -0
  456. solace_agent_mesh/gateway/generic/__init__.py +1 -0
  457. solace_agent_mesh/gateway/generic/app.py +50 -0
  458. solace_agent_mesh/gateway/generic/component.py +727 -0
  459. solace_agent_mesh/gateway/http_sse/__init__.py +0 -0
  460. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +345 -0
  461. solace_agent_mesh/gateway/http_sse/alembic/env.py +87 -0
  462. solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
  463. solace_agent_mesh/gateway/http_sse/alembic/versions/20250910_d5b3f8f2e9a0_create_initial_database.py +58 -0
  464. solace_agent_mesh/gateway/http_sse/alembic/versions/20250911_b1c2d3e4f5g6_add_database_indexes.py +83 -0
  465. solace_agent_mesh/gateway/http_sse/alembic/versions/20250916_f6e7d8c9b0a1_convert_timestamps_to_epoch_and_align_columns.py +412 -0
  466. solace_agent_mesh/gateway/http_sse/alembic/versions/20251006_98882922fa59_add_tasks_events_feedback_chat_tasks.py +190 -0
  467. solace_agent_mesh/gateway/http_sse/alembic/versions/20251015_add_session_performance_indexes.py +70 -0
  468. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_project_users_table.py +72 -0
  469. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +109 -0
  470. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +26 -0
  471. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_projects_table.py +135 -0
  472. solace_agent_mesh/gateway/http_sse/alembic/versions/20251108_create_prompt_tables_with_sharing.py +154 -0
  473. solace_agent_mesh/gateway/http_sse/alembic/versions/20251115_add_parent_task_id.py +32 -0
  474. solace_agent_mesh/gateway/http_sse/alembic/versions/20251126_add_background_task_fields.py +47 -0
  475. solace_agent_mesh/gateway/http_sse/alembic/versions/20251202_add_versioned_fields_to_prompts.py +52 -0
  476. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +161 -0
  477. solace_agent_mesh/gateway/http_sse/alembic.ini +109 -0
  478. solace_agent_mesh/gateway/http_sse/app.py +351 -0
  479. solace_agent_mesh/gateway/http_sse/component.py +2360 -0
  480. solace_agent_mesh/gateway/http_sse/components/__init__.py +7 -0
  481. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +105 -0
  482. solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +109 -0
  483. solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +110 -0
  484. solace_agent_mesh/gateway/http_sse/dependencies.py +653 -0
  485. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +299 -0
  486. solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +3278 -0
  487. solace_agent_mesh/gateway/http_sse/main.py +789 -0
  488. solace_agent_mesh/gateway/http_sse/repository/__init__.py +46 -0
  489. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +102 -0
  490. solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +11 -0
  491. solace_agent_mesh/gateway/http_sse/repository/entities/chat_task.py +75 -0
  492. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +221 -0
  493. solace_agent_mesh/gateway/http_sse/repository/entities/feedback.py +20 -0
  494. solace_agent_mesh/gateway/http_sse/repository/entities/project.py +81 -0
  495. solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +47 -0
  496. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +66 -0
  497. solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +0 -0
  498. solace_agent_mesh/gateway/http_sse/repository/entities/task.py +32 -0
  499. solace_agent_mesh/gateway/http_sse/repository/entities/task_event.py +21 -0
  500. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +125 -0
  501. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +239 -0
  502. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +34 -0
  503. solace_agent_mesh/gateway/http_sse/repository/models/base.py +7 -0
  504. solace_agent_mesh/gateway/http_sse/repository/models/chat_task_model.py +31 -0
  505. solace_agent_mesh/gateway/http_sse/repository/models/feedback_model.py +21 -0
  506. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +257 -0
  507. solace_agent_mesh/gateway/http_sse/repository/models/project_model.py +51 -0
  508. solace_agent_mesh/gateway/http_sse/repository/models/project_user_model.py +75 -0
  509. solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +159 -0
  510. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +53 -0
  511. solace_agent_mesh/gateway/http_sse/repository/models/task_event_model.py +25 -0
  512. solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +39 -0
  513. solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
  514. solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
  515. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +308 -0
  516. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +268 -0
  517. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +248 -0
  518. solace_agent_mesh/gateway/http_sse/routers/__init__.py +4 -0
  519. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +74 -0
  520. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +1137 -0
  521. solace_agent_mesh/gateway/http_sse/routers/auth.py +311 -0
  522. solace_agent_mesh/gateway/http_sse/routers/config.py +371 -0
  523. solace_agent_mesh/gateway/http_sse/routers/dto/__init__.py +10 -0
  524. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +450 -0
  525. solace_agent_mesh/gateway/http_sse/routers/dto/project_dto.py +69 -0
  526. solace_agent_mesh/gateway/http_sse/routers/dto/prompt_dto.py +255 -0
  527. solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +15 -0
  528. solace_agent_mesh/gateway/http_sse/routers/dto/requests/project_requests.py +48 -0
  529. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +133 -0
  530. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +33 -0
  531. solace_agent_mesh/gateway/http_sse/routers/dto/requests/task_requests.py +58 -0
  532. solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +18 -0
  533. solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +42 -0
  534. solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +31 -0
  535. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +123 -0
  536. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +33 -0
  537. solace_agent_mesh/gateway/http_sse/routers/dto/responses/task_responses.py +30 -0
  538. solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
  539. solace_agent_mesh/gateway/http_sse/routers/feedback.py +168 -0
  540. solace_agent_mesh/gateway/http_sse/routers/people.py +38 -0
  541. solace_agent_mesh/gateway/http_sse/routers/projects.py +767 -0
  542. solace_agent_mesh/gateway/http_sse/routers/prompts.py +1415 -0
  543. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +312 -0
  544. solace_agent_mesh/gateway/http_sse/routers/sessions.py +634 -0
  545. solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
  546. solace_agent_mesh/gateway/http_sse/routers/sse.py +230 -0
  547. solace_agent_mesh/gateway/http_sse/routers/tasks.py +1089 -0
  548. solace_agent_mesh/gateway/http_sse/routers/users.py +83 -0
  549. solace_agent_mesh/gateway/http_sse/routers/version.py +343 -0
  550. solace_agent_mesh/gateway/http_sse/routers/visualization.py +1220 -0
  551. solace_agent_mesh/gateway/http_sse/services/__init__.py +4 -0
  552. solace_agent_mesh/gateway/http_sse/services/agent_card_service.py +71 -0
  553. solace_agent_mesh/gateway/http_sse/services/audio_service.py +1227 -0
  554. solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +186 -0
  555. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +273 -0
  556. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +250 -0
  557. solace_agent_mesh/gateway/http_sse/services/people_service.py +78 -0
  558. solace_agent_mesh/gateway/http_sse/services/project_service.py +930 -0
  559. solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
  560. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +303 -0
  561. solace_agent_mesh/gateway/http_sse/services/session_service.py +702 -0
  562. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +593 -0
  563. solace_agent_mesh/gateway/http_sse/services/task_service.py +119 -0
  564. solace_agent_mesh/gateway/http_sse/session_manager.py +219 -0
  565. solace_agent_mesh/gateway/http_sse/shared/__init__.py +146 -0
  566. solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
  567. solace_agent_mesh/gateway/http_sse/shared/base_repository.py +252 -0
  568. solace_agent_mesh/gateway/http_sse/shared/database_exceptions.py +274 -0
  569. solace_agent_mesh/gateway/http_sse/shared/database_helpers.py +43 -0
  570. solace_agent_mesh/gateway/http_sse/shared/enums.py +40 -0
  571. solace_agent_mesh/gateway/http_sse/shared/error_dto.py +107 -0
  572. solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +217 -0
  573. solace_agent_mesh/gateway/http_sse/shared/exceptions.py +192 -0
  574. solace_agent_mesh/gateway/http_sse/shared/pagination.py +138 -0
  575. solace_agent_mesh/gateway/http_sse/shared/response_utils.py +134 -0
  576. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +319 -0
  577. solace_agent_mesh/gateway/http_sse/shared/timestamp_utils.py +97 -0
  578. solace_agent_mesh/gateway/http_sse/shared/types.py +50 -0
  579. solace_agent_mesh/gateway/http_sse/shared/utils.py +22 -0
  580. solace_agent_mesh/gateway/http_sse/sse_event_buffer.py +88 -0
  581. solace_agent_mesh/gateway/http_sse/sse_manager.py +491 -0
  582. solace_agent_mesh/gateway/http_sse/utils/__init__.py +1 -0
  583. solace_agent_mesh/gateway/http_sse/utils/artifact_copy_utils.py +370 -0
  584. solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +72 -0
  585. solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +47 -0
  586. solace_agent_mesh/llm.txt +228 -0
  587. solace_agent_mesh/llm_detail.txt +2835 -0
  588. solace_agent_mesh/services/__init__.py +0 -0
  589. solace_agent_mesh/services/platform/__init__.py +18 -0
  590. solace_agent_mesh/services/platform/alembic/env.py +85 -0
  591. solace_agent_mesh/services/platform/alembic/script.py.mako +28 -0
  592. solace_agent_mesh/services/platform/alembic.ini +109 -0
  593. solace_agent_mesh/services/platform/api/__init__.py +3 -0
  594. solace_agent_mesh/services/platform/api/dependencies.py +147 -0
  595. solace_agent_mesh/services/platform/api/main.py +280 -0
  596. solace_agent_mesh/services/platform/api/middleware.py +51 -0
  597. solace_agent_mesh/services/platform/api/routers/__init__.py +24 -0
  598. solace_agent_mesh/services/platform/app.py +114 -0
  599. solace_agent_mesh/services/platform/component.py +235 -0
  600. solace_agent_mesh/solace_agent_mesh_llm.txt +362 -0
  601. solace_agent_mesh/solace_agent_mesh_llm_detail.txt +8599 -0
  602. solace_agent_mesh/templates/agent_template.yaml +53 -0
  603. solace_agent_mesh/templates/eval_backend_template.yaml +54 -0
  604. solace_agent_mesh/templates/gateway_app_template.py +75 -0
  605. solace_agent_mesh/templates/gateway_component_template.py +484 -0
  606. solace_agent_mesh/templates/gateway_config_template.yaml +38 -0
  607. solace_agent_mesh/templates/logging_config_template.yaml +48 -0
  608. solace_agent_mesh/templates/main_orchestrator.yaml +66 -0
  609. solace_agent_mesh/templates/plugin_agent_config_template.yaml +122 -0
  610. solace_agent_mesh/templates/plugin_custom_config_template.yaml +27 -0
  611. solace_agent_mesh/templates/plugin_custom_template.py +10 -0
  612. solace_agent_mesh/templates/plugin_gateway_config_template.yaml +60 -0
  613. solace_agent_mesh/templates/plugin_pyproject_template.toml +32 -0
  614. solace_agent_mesh/templates/plugin_readme_template.md +12 -0
  615. solace_agent_mesh/templates/plugin_tool_config_template.yaml +109 -0
  616. solace_agent_mesh/templates/plugin_tools_template.py +224 -0
  617. solace_agent_mesh/templates/shared_config.yaml +112 -0
  618. solace_agent_mesh/templates/templates_llm.txt +147 -0
  619. solace_agent_mesh/templates/webui.yaml +177 -0
  620. solace_agent_mesh-1.11.2.dist-info/METADATA +504 -0
  621. solace_agent_mesh-1.11.2.dist-info/RECORD +624 -0
  622. solace_agent_mesh-1.11.2.dist-info/WHEEL +4 -0
  623. solace_agent_mesh-1.11.2.dist-info/entry_points.txt +3 -0
  624. solace_agent_mesh-1.11.2.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,1353 @@
1
+ """
2
+ Helper functions for artifact management, including metadata handling and schema inference.
3
+ """
4
+
5
+ import logging
6
+ import base64
7
+ import binascii
8
+ import json
9
+ import csv
10
+ import io
11
+ import inspect
12
+ import os
13
+ import yaml
14
+ import traceback
15
+ from datetime import datetime, timezone
16
+ from typing import Any, Dict, Optional, Tuple, List, Union, TYPE_CHECKING
17
+ from urllib.parse import urlparse, parse_qs, urlunparse, urlencode
18
+ from google.adk.artifacts import BaseArtifactService
19
+ from google.genai import types as adk_types
20
+ from ...common.a2a.types import ArtifactInfo
21
+ from ...common.utils.mime_helpers import is_text_based_mime_type, is_text_based_file
22
+ from ...common.constants import (
23
+ TEXT_ARTIFACT_CONTEXT_MAX_LENGTH_CAPACITY,
24
+ TEXT_ARTIFACT_CONTEXT_DEFAULT_LENGTH,
25
+ )
26
+ from ...agent.utils.context_helpers import get_original_session_id
27
+
28
+ if TYPE_CHECKING:
29
+ from google.adk.tools import ToolContext
30
+ from ...agent.sac.component import SamAgentComponent
31
+
32
+ log = logging.getLogger(__name__)
33
+
34
+ METADATA_SUFFIX = ".metadata.json"
35
+ DEFAULT_SCHEMA_MAX_KEYS = 20
36
+
37
+
38
+ def is_filename_safe(filename: str) -> bool:
39
+ """
40
+ Checks if a filename is safe for artifact creation.
41
+ - Must not be empty or just whitespace.
42
+ - Must not contain path traversal sequences ('..').
43
+ - Must not contain path separators ('/' or '\\').
44
+ - Must not be a reserved name like '.' or '..'.
45
+
46
+ Args:
47
+ filename: The filename to validate.
48
+
49
+ Returns:
50
+ True if the filename is safe, False otherwise.
51
+ """
52
+ if not filename or not filename.strip():
53
+ return False
54
+
55
+ # Check for path traversal
56
+ if ".." in filename:
57
+ return False
58
+
59
+ # Check for path separators
60
+ if "/" in filename or "\\" in filename:
61
+ return False
62
+
63
+ # Check for reserved names
64
+ if filename.strip() in [".", ".."]:
65
+ return False
66
+
67
+ return True
68
+
69
+
70
+ def ensure_correct_extension(filename_from_llm: str, desired_extension: str) -> str:
71
+ """
72
+ Ensures a filename has the correct extension, handling cases where the LLM
73
+ might provide a filename with or without an extension, or with the wrong one.
74
+
75
+ Args:
76
+ filename_from_llm: The filename string provided by the LLM.
77
+ desired_extension: The correct extension for the file (e.g., 'png', 'md').
78
+ Should be provided without a leading dot.
79
+
80
+ Returns:
81
+ A string with the correctly formatted filename.
82
+ """
83
+ if not filename_from_llm:
84
+ return f"unnamed.{desired_extension.lower()}"
85
+ filename_stripped = filename_from_llm.strip()
86
+ desired_ext_clean = desired_extension.lower().strip().lstrip(".")
87
+ base_name, current_ext = os.path.splitext(filename_stripped)
88
+ current_ext_clean = current_ext.lower().lstrip(".")
89
+ if current_ext_clean == desired_ext_clean:
90
+ return filename_stripped
91
+ else:
92
+ return f"{base_name}.{desired_ext_clean}"
93
+
94
+
95
+ def format_artifact_uri(
96
+ app_name: str,
97
+ user_id: str,
98
+ session_id: str,
99
+ filename: str,
100
+ version: Union[int, str],
101
+ ) -> str:
102
+ """Formats the components into a standard artifact:// URI."""
103
+ path = f"/{user_id}/{session_id}/{filename}"
104
+ query = urlencode({"version": str(version)})
105
+ return urlunparse(("artifact", app_name, path, "", query, ""))
106
+
107
+
108
+ def parse_artifact_uri(uri: str) -> Dict[str, Any]:
109
+ """Parses an artifact:// URI into its constituent parts."""
110
+ parsed = urlparse(uri)
111
+ if parsed.scheme != "artifact":
112
+ raise ValueError("Invalid URI scheme, must be 'artifact'.")
113
+
114
+ path_parts = parsed.path.strip("/").split("/")
115
+ if len(path_parts) != 3:
116
+ raise ValueError("Invalid URI path. Expected /user_id/session_id/filename")
117
+
118
+ query_params = parse_qs(parsed.query)
119
+ version = query_params.get("version", [None])[0]
120
+ if not version:
121
+ raise ValueError("Version is missing from URI query parameters.")
122
+
123
+ return {
124
+ "app_name": parsed.netloc,
125
+ "user_id": path_parts[0],
126
+ "session_id": path_parts[1],
127
+ "filename": path_parts[2],
128
+ "version": int(version) if version.isdigit() else version,
129
+ }
130
+
131
+
132
+ def _clean_metadata_for_output(metadata: Dict[str, Any]) -> Dict[str, Any]:
133
+ """
134
+ Remove null, False, and empty values from metadata to reduce token usage.
135
+ Recursively cleans nested dictionaries.
136
+
137
+ Args:
138
+ metadata: The metadata dictionary to clean
139
+
140
+ Returns:
141
+ A cleaned dictionary with unnecessary fields removed
142
+ """
143
+ cleaned = {}
144
+ for key, value in metadata.items():
145
+ # Skip None, False, and empty collections
146
+ if value is None or value is False or value == {} or value == []:
147
+ continue
148
+
149
+ # Recursively clean nested dictionaries
150
+ if isinstance(value, dict):
151
+ cleaned_nested = _clean_metadata_for_output(value)
152
+ if cleaned_nested: # Only include if not empty after cleaning
153
+ cleaned[key] = cleaned_nested
154
+ else:
155
+ cleaned[key] = value
156
+
157
+ return cleaned
158
+
159
+
160
+ def _inspect_structure(
161
+ data: Any, max_depth: int, max_keys: int, current_depth: int = 0
162
+ ) -> Any:
163
+ """
164
+ Recursively inspects data structure up to max_depth and max_keys for dictionaries.
165
+ """
166
+ if current_depth >= max_depth:
167
+ return type(data).__name__
168
+ if isinstance(data, dict):
169
+ if not data:
170
+ return {}
171
+ inspected_dict = {}
172
+ keys = list(data.keys())
173
+ keys_to_inspect = keys[:max_keys]
174
+ for key in keys_to_inspect:
175
+ inspected_dict[key] = _inspect_structure(
176
+ data[key], max_depth, max_keys, current_depth + 1
177
+ )
178
+ if len(keys) > max_keys:
179
+ inspected_dict["..."] = f"{len(keys) - max_keys} more keys"
180
+ return inspected_dict
181
+ elif isinstance(data, list):
182
+ if not data:
183
+ return []
184
+ return [_inspect_structure(data[0], max_depth, max_keys, current_depth + 1)]
185
+ else:
186
+ return type(data).__name__
187
+
188
+
189
+ def _infer_schema(
190
+ content_bytes: bytes,
191
+ mime_type: str,
192
+ depth: int = 3,
193
+ max_keys: int = DEFAULT_SCHEMA_MAX_KEYS,
194
+ ) -> Dict[str, Any]:
195
+ """
196
+ Infers basic schema information for common text-based types.
197
+ Args:
198
+ content_bytes: The raw byte content.
199
+ mime_type: The MIME type.
200
+ depth: Maximum recursion depth for nested structures.
201
+ max_keys: Maximum number of dictionary keys to inspect at each level.
202
+ Returns:
203
+ A dictionary representing the inferred schema, including an 'inferred' flag
204
+ and potential 'error' field.
205
+ """
206
+ schema_info = {"type": mime_type, "inferred": False, "error": None}
207
+ normalized_mime_type = mime_type.lower() if mime_type else ""
208
+ try:
209
+ if normalized_mime_type == "text/csv":
210
+ try:
211
+ text_content = io.TextIOWrapper(
212
+ io.BytesIO(content_bytes), encoding="utf-8"
213
+ )
214
+ reader = csv.reader(text_content)
215
+ header = next(reader)
216
+ schema_info["columns"] = header
217
+ schema_info["inferred"] = True
218
+ except (StopIteration, csv.Error, UnicodeDecodeError) as e:
219
+ schema_info["error"] = f"CSV header inference failed: {e}"
220
+ elif normalized_mime_type in ["application/json", "text/json"]:
221
+ try:
222
+ data = json.loads(content_bytes.decode("utf-8"))
223
+ schema_info["structure"] = _inspect_structure(data, depth, max_keys)
224
+ schema_info["inferred"] = True
225
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
226
+ schema_info["error"] = f"JSON structure inference failed: {e}"
227
+ elif normalized_mime_type in [
228
+ "application/yaml",
229
+ "text/yaml",
230
+ "application/x-yaml",
231
+ "text/x-yaml",
232
+ ]:
233
+ try:
234
+ data = yaml.safe_load(content_bytes)
235
+ schema_info["structure"] = _inspect_structure(data, depth, max_keys)
236
+ schema_info["inferred"] = True
237
+ except (yaml.YAMLError, UnicodeDecodeError) as e:
238
+ schema_info["error"] = f"YAML structure inference failed: {e}"
239
+ except Exception as e:
240
+ schema_info["error"] = f"Unexpected error during schema inference: {e}"
241
+ if schema_info["error"]:
242
+ log.warning(
243
+ "Schema inference for mime_type '%s' encountered error: %s",
244
+ mime_type,
245
+ schema_info["error"],
246
+ )
247
+ elif not schema_info["inferred"]:
248
+ log.debug(
249
+ "No specific schema inference logic applied for mime_type '%s'.", mime_type
250
+ )
251
+ return schema_info
252
+
253
+
254
+ async def save_artifact_with_metadata(
255
+ artifact_service: BaseArtifactService,
256
+ app_name: str,
257
+ user_id: str,
258
+ session_id: str,
259
+ filename: str,
260
+ content_bytes: bytes,
261
+ mime_type: str,
262
+ metadata_dict: Dict[str, Any],
263
+ timestamp: datetime,
264
+ explicit_schema: Optional[Dict] = None,
265
+ schema_inference_depth: int = 2,
266
+ schema_max_keys: int = DEFAULT_SCHEMA_MAX_KEYS,
267
+ tool_context: Optional["ToolContext"] = None,
268
+ ) -> Dict[str, Any]:
269
+ """
270
+ Saves a data artifact and its corresponding metadata artifact using BaseArtifactService.
271
+ """
272
+ log_identifier = f"[ArtifactHelper:save:{filename}]"
273
+ log.debug("%s Saving artifact and metadata (async)...", log_identifier)
274
+ data_version = None
275
+ metadata_version = None
276
+ metadata_filename = f"{filename}{METADATA_SUFFIX}"
277
+ status = "error"
278
+ status_message = "Initialization error"
279
+ try:
280
+ data_artifact_part = adk_types.Part.from_bytes(
281
+ data=content_bytes, mime_type=mime_type
282
+ )
283
+ log.debug(
284
+ f"{log_identifier} artifact_service object type: {type(artifact_service)}"
285
+ )
286
+ log.debug(
287
+ f"{log_identifier} artifact_service object dir: {dir(artifact_service)}"
288
+ )
289
+ if hasattr(artifact_service, "save_artifact"):
290
+ save_artifact_method = getattr(artifact_service, "save_artifact")
291
+ log.debug(
292
+ f"{log_identifier} type of artifact_service.save_artifact: {type(save_artifact_method)}"
293
+ )
294
+ log.debug(
295
+ f"{log_identifier} Is save_artifact a coroutine function? {inspect.iscoroutinefunction(save_artifact_method)}"
296
+ )
297
+ log.debug(
298
+ f"{log_identifier} Is save_artifact an async generator function? {inspect.isasyncgenfunction(save_artifact_method)}"
299
+ )
300
+ if callable(save_artifact_method):
301
+ try:
302
+ sig = inspect.signature(save_artifact_method)
303
+ log.debug(f"{log_identifier} Signature of save_artifact: {sig}")
304
+ except Exception as e_inspect:
305
+ log.debug(
306
+ f"{log_identifier} Could not get signature of save_artifact: {e_inspect}"
307
+ )
308
+ save_data_method = getattr(artifact_service, "save_artifact")
309
+ data_version = await save_data_method(
310
+ app_name=app_name,
311
+ user_id=user_id,
312
+ session_id=session_id,
313
+ filename=filename,
314
+ artifact=data_artifact_part,
315
+ )
316
+ log.info(
317
+ "%s Saved data artifact '%s' as version %s.",
318
+ log_identifier,
319
+ filename,
320
+ data_version,
321
+ )
322
+
323
+ # Populate artifact_delta for ADK callbacks if tool_context is provided
324
+ if (
325
+ tool_context
326
+ and hasattr(tool_context, "actions")
327
+ and hasattr(tool_context.actions, "artifact_delta")
328
+ ):
329
+ tool_context.actions.artifact_delta[filename] = data_version
330
+ log.debug(
331
+ "%s Populated artifact_delta for ADK callbacks: %s -> %s",
332
+ log_identifier,
333
+ filename,
334
+ data_version,
335
+ )
336
+
337
+ final_metadata = {
338
+ "filename": filename,
339
+ "mime_type": mime_type,
340
+ "size_bytes": len(content_bytes),
341
+ "timestamp_utc": (
342
+ timestamp
343
+ if isinstance(timestamp, (int, float))
344
+ else timestamp.timestamp()
345
+ ),
346
+ **(metadata_dict or {}),
347
+ }
348
+ if explicit_schema:
349
+ final_metadata["schema"] = {
350
+ "type": mime_type,
351
+ "inferred": False,
352
+ **explicit_schema,
353
+ }
354
+ log.debug("%s Using explicit schema provided by caller.", log_identifier)
355
+ else:
356
+ inferred_schema = _infer_schema(
357
+ content_bytes, mime_type, schema_inference_depth, schema_max_keys
358
+ )
359
+ final_metadata["schema"] = inferred_schema
360
+ if inferred_schema.get("inferred"):
361
+ log.debug(
362
+ "%s Added inferred schema (max_keys=%d).",
363
+ log_identifier,
364
+ schema_max_keys,
365
+ )
366
+ elif inferred_schema.get("error"):
367
+ log.warning(
368
+ "%s Schema inference failed: %s",
369
+ log_identifier,
370
+ inferred_schema["error"],
371
+ )
372
+ try:
373
+ metadata_bytes = json.dumps(final_metadata, indent=2).encode("utf-8")
374
+ metadata_artifact_part = adk_types.Part.from_bytes(
375
+ data=metadata_bytes, mime_type="application/json"
376
+ )
377
+ save_metadata_method = getattr(artifact_service, "save_artifact")
378
+ metadata_version = await save_metadata_method(
379
+ app_name=app_name,
380
+ user_id=user_id,
381
+ session_id=session_id,
382
+ filename=metadata_filename,
383
+ artifact=metadata_artifact_part,
384
+ )
385
+ log.info(
386
+ "%s Saved metadata artifact '%s' as version %s.",
387
+ log_identifier,
388
+ metadata_filename,
389
+ metadata_version,
390
+ )
391
+ status = "success"
392
+ status_message = "Artifact and metadata saved successfully."
393
+ except Exception as meta_save_err:
394
+ log.exception(
395
+ "%s Failed to save metadata artifact '%s': %s",
396
+ log_identifier,
397
+ metadata_filename,
398
+ meta_save_err,
399
+ )
400
+ status = "partial_success"
401
+ status_message = f"Data artifact saved (v{data_version}), but failed to save metadata: {meta_save_err}"
402
+ except Exception as data_save_err:
403
+ log.exception(
404
+ "%s Failed to save data artifact '%s': %s",
405
+ log_identifier,
406
+ filename,
407
+ data_save_err,
408
+ )
409
+ status = "error"
410
+ status_message = f"Failed to save data artifact: {data_save_err}"
411
+ return {
412
+ "status": status,
413
+ "data_filename": filename,
414
+ "data_version": data_version,
415
+ "metadata_filename": metadata_filename,
416
+ "metadata_version": metadata_version,
417
+ "message": status_message,
418
+ }
419
+
420
+
421
+ async def process_artifact_upload(
422
+ artifact_service: BaseArtifactService,
423
+ component: Any,
424
+ user_id: str,
425
+ session_id: str,
426
+ filename: str,
427
+ content_bytes: bytes,
428
+ mime_type: str,
429
+ metadata_json: Optional[str] = None,
430
+ log_prefix: str = "[ArtifactUpload]",
431
+ ) -> Dict[str, Any]:
432
+ """
433
+ Common logic for processing artifact uploads.
434
+
435
+ Handles filename validation, metadata parsing, artifact storage, and URI generation.
436
+
437
+ Args:
438
+ artifact_service: The artifact service instance to use for storage.
439
+ component: The component instance (agent or gateway) for configuration.
440
+ user_id: The user ID associated with the artifact.
441
+ session_id: The session ID associated with the artifact.
442
+ filename: The name of the artifact file.
443
+ content_bytes: The raw bytes of the artifact content.
444
+ mime_type: The MIME type of the artifact.
445
+ metadata_json: Optional JSON string containing artifact metadata.
446
+ log_prefix: Prefix for log messages.
447
+
448
+ Returns:
449
+ Dict with keys:
450
+ - status: "success" or "error"
451
+ - artifact_uri: The URI of the stored artifact (on success)
452
+ - version: The version number of the stored artifact (on success)
453
+ - message: Status message
454
+ - error: Error details (on error)
455
+ """
456
+ log.debug("%s Processing artifact upload for '%s'", log_prefix, filename)
457
+
458
+ # Validate filename
459
+ if not is_filename_safe(filename):
460
+ error_msg = f"Invalid filename: '{filename}'. Filename must not contain path separators or traversal sequences."
461
+ log.warning("%s %s", log_prefix, error_msg)
462
+ return {"status": "error", "message": error_msg, "error": "invalid_filename"}
463
+
464
+ # Validate content
465
+ if not content_bytes:
466
+ error_msg = "Uploaded file cannot be empty."
467
+ log.warning("%s %s", log_prefix, error_msg)
468
+ return {"status": "error", "message": error_msg, "error": "empty_file"}
469
+
470
+ # Parse metadata JSON if provided
471
+ metadata_dict = {}
472
+ if metadata_json and metadata_json.strip():
473
+ try:
474
+ metadata_dict = json.loads(metadata_json.strip())
475
+ if not isinstance(metadata_dict, dict):
476
+ log.warning(
477
+ "%s Metadata JSON did not parse to a dictionary. Ignoring.",
478
+ log_prefix,
479
+ )
480
+ metadata_dict = {}
481
+ except json.JSONDecodeError as json_err:
482
+ log.warning(
483
+ "%s Failed to parse metadata_json: %s. Proceeding without it.",
484
+ log_prefix,
485
+ json_err,
486
+ )
487
+ metadata_dict = {}
488
+
489
+ # Get app_name from component configuration
490
+ app_name = component.get_config("name", "A2A_WebUI_App")
491
+ current_timestamp = datetime.now(timezone.utc)
492
+
493
+ # Save artifact with metadata
494
+ try:
495
+ save_result = await save_artifact_with_metadata(
496
+ artifact_service=artifact_service,
497
+ app_name=app_name,
498
+ user_id=user_id,
499
+ session_id=session_id,
500
+ filename=filename,
501
+ content_bytes=content_bytes,
502
+ mime_type=mime_type,
503
+ metadata_dict=metadata_dict,
504
+ timestamp=current_timestamp,
505
+ schema_max_keys=component.get_config(
506
+ "schema_max_keys", DEFAULT_SCHEMA_MAX_KEYS
507
+ ),
508
+ )
509
+
510
+ if save_result["status"] == "success":
511
+ saved_version = save_result.get("data_version")
512
+ artifact_uri = format_artifact_uri(
513
+ app_name=app_name,
514
+ user_id=user_id,
515
+ session_id=session_id,
516
+ filename=filename,
517
+ version=saved_version,
518
+ )
519
+
520
+ log.info(
521
+ "%s Artifact '%s' uploaded successfully. URI: %s, Version: %s",
522
+ log_prefix,
523
+ filename,
524
+ artifact_uri,
525
+ saved_version,
526
+ )
527
+
528
+ return {
529
+ "status": "success",
530
+ "artifact_uri": artifact_uri,
531
+ "version": saved_version,
532
+ "message": save_result.get(
533
+ "message", "Artifact uploaded successfully."
534
+ ),
535
+ "data_version": saved_version,
536
+ "metadata_version": save_result.get("metadata_version"),
537
+ }
538
+ else:
539
+ error_msg = save_result.get("message", "Failed to save artifact.")
540
+ log.error("%s %s", log_prefix, error_msg)
541
+ return {"status": "error", "message": error_msg, "error": "save_failed"}
542
+
543
+ except Exception as e:
544
+ error_msg = f"Unexpected error storing artifact: {str(e)}"
545
+ log.exception("%s %s", log_prefix, error_msg)
546
+ return {"status": "error", "message": error_msg, "error": "unexpected_error"}
547
+
548
+
549
+ def format_metadata_for_llm(metadata: Dict[str, Any]) -> str:
550
+ """Formats loaded metadata into an LLM-friendly text block."""
551
+ lines = []
552
+ filename = metadata.get("filename", "Unknown Filename")
553
+ version = metadata.get("version", "N/A")
554
+ lines.append(f"--- Metadata for artifact '{filename}' (v{version}) ---")
555
+ lines.append("**Artifact Metadata:**")
556
+ if "description" in metadata:
557
+ lines.append(f"* **Description:** {metadata['description']}")
558
+ if "source" in metadata:
559
+ lines.append(f"* **Source:** {metadata['source']}")
560
+ if "mime_type" in metadata:
561
+ lines.append(f"* **Type:** {metadata['mime_type']}")
562
+ if "size_bytes" in metadata:
563
+ lines.append(f"* **Size:** {metadata['size_bytes']} bytes")
564
+ schema = metadata.get("schema", {})
565
+ schema_type = schema.get("type", metadata.get("mime_type", "unknown"))
566
+ schema_details = []
567
+ if schema.get("inferred"):
568
+ schema_details.append("(Inferred)")
569
+ if "columns" in schema:
570
+ schema_details.append(f"Columns: {','.join(schema['columns'])}")
571
+ if "structure" in schema:
572
+ schema_details.append(f"Structure: {json.dumps(schema['structure'])}")
573
+ if schema.get("error"):
574
+ schema_details.append(f"Schema Error: {schema['error']}")
575
+ if schema_details:
576
+ lines.append(f"* **Schema:** {schema_type} {' '.join(schema_details)}")
577
+ elif schema_type != "unknown":
578
+ lines.append(f"* **Schema Type:** {schema_type}")
579
+ custom_fields = {
580
+ k: v
581
+ for k, v in metadata.items()
582
+ if k
583
+ not in [
584
+ "filename",
585
+ "mime_type",
586
+ "size_bytes",
587
+ "timestamp_utc",
588
+ "schema",
589
+ "version",
590
+ "description",
591
+ "source",
592
+ ]
593
+ }
594
+ if custom_fields:
595
+ lines.append("* **Other:**")
596
+ for k, v in custom_fields.items():
597
+ lines.append(f" * {k}: {v}")
598
+ lines.append("--- End Metadata ---")
599
+ return "\n".join(lines)
600
+
601
+
602
+ async def generate_artifact_metadata_summary(
603
+ component: "SamAgentComponent",
604
+ artifact_identifiers: List[Dict[str, Any]],
605
+ user_id: str,
606
+ session_id: str,
607
+ app_name: str,
608
+ header_text: Optional[str] = None,
609
+ ) -> str:
610
+ """
611
+ Loads metadata for a list of artifacts and formats it into a human-readable
612
+ YAML summary string, suitable for LLM context.
613
+ """
614
+ if not artifact_identifiers:
615
+ return ""
616
+
617
+ log_identifier = f"{component.log_identifier}[ArtifactSummary]"
618
+ summary_parts = []
619
+ if header_text:
620
+ summary_parts.append(header_text)
621
+
622
+ if not (component.artifact_service and user_id and session_id):
623
+ log.warning(
624
+ "%s Cannot load artifact metadata: missing artifact_service or context.",
625
+ log_identifier,
626
+ )
627
+ for artifact_ref in artifact_identifiers:
628
+ filename = artifact_ref.get("filename", "unknown")
629
+ version = artifact_ref.get("version", "latest")
630
+ summary_parts.append(
631
+ f"---\nArtifact: '{filename}' (version: {version})\nError: Could not load metadata. Host component context missing."
632
+ )
633
+ return "\n\n".join(summary_parts)
634
+
635
+ for artifact_ref in artifact_identifiers:
636
+ filename = artifact_ref.get("filename")
637
+ version = artifact_ref.get("version", "latest")
638
+ if not filename:
639
+ log.warning(
640
+ "%s Skipping artifact with no filename in identifier: %s",
641
+ log_identifier,
642
+ artifact_ref,
643
+ )
644
+ continue
645
+
646
+ try:
647
+ metadata_result = await load_artifact_content_or_metadata(
648
+ artifact_service=component.artifact_service,
649
+ app_name=app_name,
650
+ user_id=user_id,
651
+ session_id=get_original_session_id(session_id),
652
+ filename=filename,
653
+ version=version,
654
+ load_metadata_only=True,
655
+ )
656
+ if metadata_result.get("status") == "success":
657
+ metadata = metadata_result.get("metadata", {})
658
+ resolved_version = metadata_result.get("version", version)
659
+ artifact_header = (
660
+ f"Artifact: '{filename}' (version: {resolved_version})"
661
+ )
662
+
663
+ # Remove redundant fields before dumping to YAML
664
+ metadata.pop("filename", None)
665
+ metadata.pop("version", None)
666
+
667
+ # Clean metadata to remove null/false/empty values for token efficiency
668
+ cleaned_metadata = _clean_metadata_for_output(metadata)
669
+
670
+ TRUNCATION_LIMIT_BYTES = 1024
671
+ TRUNCATION_MESSAGE = "\n... [truncated] ..."
672
+
673
+ try:
674
+ formatted_metadata_str = yaml.safe_dump(
675
+ cleaned_metadata,
676
+ default_flow_style=False,
677
+ sort_keys=False,
678
+ allow_unicode=True,
679
+ )
680
+
681
+ if (
682
+ len(formatted_metadata_str.encode("utf-8"))
683
+ > TRUNCATION_LIMIT_BYTES
684
+ ):
685
+ cutoff = TRUNCATION_LIMIT_BYTES - len(
686
+ TRUNCATION_MESSAGE.encode("utf-8")
687
+ )
688
+ # Ensure we don't cut in the middle of a multi-byte character
689
+ encoded_str = formatted_metadata_str.encode("utf-8")
690
+ if cutoff > 0:
691
+ truncated_encoded = encoded_str[:cutoff]
692
+ formatted_metadata_str = (
693
+ truncated_encoded.decode("utf-8", "ignore")
694
+ + TRUNCATION_MESSAGE
695
+ )
696
+ else:
697
+ formatted_metadata_str = TRUNCATION_MESSAGE
698
+
699
+ summary_parts.append(
700
+ f"---\n{artifact_header}\n{formatted_metadata_str}"
701
+ )
702
+ except Exception as e_format:
703
+ log.error(
704
+ "%s Error formatting metadata for %s v%s: %s",
705
+ log_identifier,
706
+ filename,
707
+ version,
708
+ e_format,
709
+ )
710
+ summary_parts.append(
711
+ f"---\n{artifact_header}\nError: Could not format metadata."
712
+ )
713
+ else:
714
+ error_message = metadata_result.get(
715
+ "message", "Could not load metadata."
716
+ )
717
+ log.warning(
718
+ "%s Failed to load metadata for %s v%s: %s",
719
+ log_identifier,
720
+ filename,
721
+ version,
722
+ error_message,
723
+ )
724
+ artifact_header = f"Artifact: '{filename}' (version: {version})"
725
+ summary_parts.append(f"---\n{artifact_header}\nError: {error_message}")
726
+ except Exception as e_meta:
727
+ log.error(
728
+ "%s Unexpected error loading metadata for %s v%s: %s",
729
+ log_identifier,
730
+ filename,
731
+ version,
732
+ e_meta,
733
+ )
734
+ artifact_header = f"Artifact: '{filename}' (version: {version})"
735
+ summary_parts.append(
736
+ f"---\n{artifact_header}\nError: An unexpected error occurred while loading metadata."
737
+ )
738
+
739
+ return "\n\n".join(summary_parts)
740
+
741
+
742
+ def decode_and_get_bytes(
743
+ content_str: str, mime_type: str, log_identifier: str
744
+ ) -> Tuple[bytes, str]:
745
+ """
746
+ Decodes content if necessary (based on mime_type) and returns bytes and final mime_type.
747
+ Args:
748
+ content_str: The input content string (potentially base64).
749
+ mime_type: The provided MIME type.
750
+ log_identifier: Identifier for logging.
751
+ Returns:
752
+ A tuple containing (content_bytes, final_mime_type).
753
+ """
754
+ file_bytes: bytes
755
+ final_mime_type = mime_type
756
+ normalized_mime_type = mime_type.lower() if mime_type else ""
757
+ if is_text_based_mime_type(normalized_mime_type):
758
+ file_bytes = content_str.encode("utf-8")
759
+ log.debug(
760
+ "%s Encoded text content for text mimeType '%s'.",
761
+ log_identifier,
762
+ mime_type,
763
+ )
764
+ else:
765
+ try:
766
+ file_bytes = base64.b64decode(content_str, validate=True)
767
+ log.debug(
768
+ "%s Decoded base64 content for non-text mimeType '%s'.",
769
+ log_identifier,
770
+ mime_type,
771
+ )
772
+ except (binascii.Error, ValueError) as decode_error:
773
+ log.warning(
774
+ "%s Failed to base64 decode content for mimeType '%s'. Treating as text/plain. Error: %s",
775
+ log_identifier,
776
+ mime_type,
777
+ decode_error,
778
+ )
779
+ file_bytes = content_str.encode("utf-8")
780
+ final_mime_type = "text/plain"
781
+ return file_bytes, final_mime_type
782
+
783
+
784
+ async def get_latest_artifact_version(
785
+ artifact_service: BaseArtifactService,
786
+ app_name: str,
787
+ user_id: str,
788
+ session_id: str,
789
+ filename: str,
790
+ ) -> Optional[int]:
791
+ """
792
+ Retrieves the latest version number for a given artifact.
793
+
794
+ Args:
795
+ artifact_service: The artifact service instance.
796
+ app_name: The application name.
797
+ user_id: The user ID.
798
+ session_id: The session ID.
799
+ filename: The name of the artifact.
800
+
801
+ Returns:
802
+ The latest version number as an integer, or None if no versions exist.
803
+ """
804
+ log_identifier = f"[ArtifactHelper:get_latest_version:{filename}]"
805
+ try:
806
+ if not hasattr(artifact_service, "list_versions"):
807
+ log.warning(
808
+ "%s Artifact service does not support 'list_versions'.", log_identifier
809
+ )
810
+ return None
811
+
812
+ versions = await artifact_service.list_versions(
813
+ app_name=app_name,
814
+ user_id=user_id,
815
+ session_id=session_id,
816
+ filename=filename,
817
+ )
818
+ if not versions:
819
+ log.debug("%s No versions found for artifact.", log_identifier)
820
+ return None
821
+
822
+ latest_version = max(versions)
823
+ log.debug("%s Resolved latest version to %d.", log_identifier, latest_version)
824
+ return latest_version
825
+ except Exception as e:
826
+ log.error("%s Error resolving latest version: %s", log_identifier, e)
827
+ return None
828
+
829
+
830
+ async def get_artifact_counts_batch(
831
+ artifact_service: BaseArtifactService,
832
+ app_name: str,
833
+ user_id: str,
834
+ session_ids: List[str],
835
+ ) -> Dict[str, int]:
836
+ """
837
+ Get artifact counts for multiple sessions in a batch operation.
838
+
839
+ Args:
840
+ artifact_service: The artifact service instance.
841
+ app_name: The application name.
842
+ user_id: The user ID.
843
+ session_ids: List of session IDs to get counts for.
844
+
845
+ Returns:
846
+ Dict mapping session_id to artifact_count (excluding metadata files)
847
+ """
848
+ log_prefix = f"[ArtifactHelper:get_counts_batch] App={app_name}, User={user_id} -"
849
+ counts: Dict[str, int] = {}
850
+
851
+ try:
852
+ list_keys_method = getattr(artifact_service, "list_artifact_keys")
853
+
854
+ for session_id in session_ids:
855
+ try:
856
+ keys = await list_keys_method(
857
+ app_name=app_name, user_id=user_id, session_id=session_id
858
+ )
859
+ # Count only non-metadata files
860
+ count = sum(1 for key in keys if not key.endswith(METADATA_SUFFIX))
861
+ counts[session_id] = count
862
+ log.debug("%s Session %s has %d artifacts", log_prefix, session_id, count)
863
+ except Exception as e:
864
+ log.warning("%s Failed to get count for session %s: %s", log_prefix, session_id, e)
865
+ counts[session_id] = 0
866
+
867
+ except Exception as e:
868
+ log.exception("%s Error in batch count operation: %s", log_prefix, e)
869
+ # Return 0 for all sessions on error
870
+ return {session_id: 0 for session_id in session_ids}
871
+
872
+ return counts
873
+
874
+
875
+ async def get_artifact_info_list(
876
+ artifact_service: BaseArtifactService,
877
+ app_name: str,
878
+ user_id: str,
879
+ session_id: str,
880
+ ) -> List[ArtifactInfo]:
881
+ """
882
+ Retrieves detailed information for all artifacts using the artifact service.
883
+
884
+ Args:
885
+ artifact_service: The artifact service instance.
886
+ app_name: The application name.
887
+ user_id: The user ID.
888
+ session_id: The session ID.
889
+
890
+ Returns:
891
+ A list of ArtifactInfo objects.
892
+ """
893
+ log_prefix = f"[ArtifactHelper:get_info_list] App={app_name}, User={user_id}, Session={session_id} -"
894
+ artifact_info_list: List[ArtifactInfo] = []
895
+
896
+ try:
897
+ list_keys_method = getattr(artifact_service, "list_artifact_keys")
898
+ keys = await list_keys_method(
899
+ app_name=app_name, user_id=user_id, session_id=session_id
900
+ )
901
+ log.debug(
902
+ "%s Found %d artifact keys. Fetching details...", log_prefix, len(keys)
903
+ )
904
+
905
+ for filename in keys:
906
+ if filename.endswith(METADATA_SUFFIX):
907
+ continue
908
+
909
+ log_identifier_item = f"{log_prefix} [{filename}]"
910
+ try:
911
+
912
+ version_count: int = 0
913
+ latest_version_num: Optional[int] = await get_latest_artifact_version(
914
+ artifact_service, app_name, user_id, session_id, filename
915
+ )
916
+
917
+ if hasattr(artifact_service, "list_versions"):
918
+ try:
919
+ available_versions = await artifact_service.list_versions(
920
+ app_name=app_name,
921
+ user_id=user_id,
922
+ session_id=session_id,
923
+ filename=filename,
924
+ )
925
+ version_count = len(available_versions)
926
+ except Exception as list_ver_err:
927
+ log.error(
928
+ "%s Error listing versions for count: %s.",
929
+ log_identifier_item,
930
+ list_ver_err,
931
+ )
932
+
933
+ data = await load_artifact_content_or_metadata(
934
+ artifact_service=artifact_service,
935
+ app_name=app_name,
936
+ user_id=user_id,
937
+ session_id=session_id,
938
+ filename=filename,
939
+ version="latest",
940
+ load_metadata_only=True,
941
+ log_identifier_prefix=log_identifier_item,
942
+ )
943
+
944
+ metadata = data.get("metadata", {})
945
+ mime_type = metadata.get("mime_type", "application/data")
946
+ size = metadata.get("size_bytes", 0)
947
+ schema_definition = metadata.get("schema", {})
948
+ description = metadata.get("description", "No description provided")
949
+ loaded_version_num = data.get("version", latest_version_num)
950
+
951
+ last_modified_ts = metadata.get("timestamp_utc")
952
+ last_modified_ts = metadata.get("timestamp_utc")
953
+ last_modified_iso = (
954
+ datetime.fromtimestamp(
955
+ last_modified_ts, tz=timezone.utc
956
+ ).isoformat()
957
+ if last_modified_ts
958
+ else None
959
+ )
960
+
961
+ # Extract source from metadata
962
+ source = metadata.get("source")
963
+
964
+ artifact_info_list.append(
965
+ ArtifactInfo(
966
+ filename=filename,
967
+ mime_type=mime_type,
968
+ size=size,
969
+ last_modified=last_modified_iso,
970
+ schema_definition=schema_definition,
971
+ description=description,
972
+ version=loaded_version_num,
973
+ version_count=version_count,
974
+ source=source,
975
+ )
976
+ )
977
+ log.debug(
978
+ "%s Successfully processed artifact info.", log_identifier_item
979
+ )
980
+
981
+ except FileNotFoundError:
982
+ log.warning(
983
+ "%s Artifact file not found by service for key '%s'. Skipping.",
984
+ log_prefix,
985
+ filename,
986
+ )
987
+ except Exception as detail_e:
988
+ log.error(
989
+ "%s Error processing details for artifact '%s': %s\n%s",
990
+ log_prefix,
991
+ filename,
992
+ detail_e,
993
+ traceback.format_exc(),
994
+ )
995
+ artifact_info_list.append(
996
+ ArtifactInfo(
997
+ filename=filename,
998
+ size=0,
999
+ description=f"Error loading details: {detail_e}",
1000
+ mime_type="application/octet-stream",
1001
+ )
1002
+ )
1003
+
1004
+ except Exception as e:
1005
+ log.exception(
1006
+ "%s Error listing artifact keys or processing list: %s", log_prefix, e
1007
+ )
1008
+ return []
1009
+ return artifact_info_list
1010
+
1011
+
1012
+ async def load_artifact_content_or_metadata(
1013
+ artifact_service: BaseArtifactService,
1014
+ app_name: str,
1015
+ user_id: str,
1016
+ session_id: str,
1017
+ filename: str,
1018
+ version: Union[int, str],
1019
+ load_metadata_only: bool = False,
1020
+ return_raw_bytes: bool = False,
1021
+ max_content_length: Optional[int] = None,
1022
+ include_line_numbers: bool = False,
1023
+ component: Optional[Any] = None,
1024
+ log_identifier_prefix: str = "[ArtifactHelper:load]",
1025
+ encoding: str = "utf-8",
1026
+ error_handling: str = "strict",
1027
+ ) -> Dict[str, Any]:
1028
+ """
1029
+ Loads the content or metadata of a specific artifact version using the artifact service.
1030
+ """
1031
+ log_identifier_req = f"{log_identifier_prefix}:{filename}:{version}"
1032
+ log.debug(
1033
+ "%s Processing request (load_metadata_only=%s, return_raw_bytes=%s) (async).",
1034
+ log_identifier_req,
1035
+ load_metadata_only,
1036
+ return_raw_bytes,
1037
+ )
1038
+
1039
+ if max_content_length is None and component:
1040
+ max_content_length = component.get_config("text_artifact_content_max_length")
1041
+ if max_content_length is None:
1042
+ raise ValueError(
1043
+ f"{log_identifier_req} Component config 'text_artifact_content_max_length' is not set."
1044
+ )
1045
+
1046
+ if max_content_length < 100:
1047
+ log.warning(
1048
+ "%s text_artifact_content_max_length too small (%d), using minimum: 100",
1049
+ log_identifier_req,
1050
+ max_content_length,
1051
+ )
1052
+ max_content_length = 100
1053
+ elif max_content_length > TEXT_ARTIFACT_CONTEXT_MAX_LENGTH_CAPACITY:
1054
+ log.warning(
1055
+ "%s text_artifact_content_max_length too large (%d), using maximum: %d",
1056
+ log_identifier_req,
1057
+ max_content_length,
1058
+ TEXT_ARTIFACT_CONTEXT_MAX_LENGTH_CAPACITY,
1059
+ )
1060
+ max_content_length = TEXT_ARTIFACT_CONTEXT_MAX_LENGTH_CAPACITY
1061
+ elif max_content_length is None:
1062
+ max_content_length = TEXT_ARTIFACT_CONTEXT_DEFAULT_LENGTH
1063
+
1064
+ log.debug(
1065
+ "%s Using max_content_length: %d characters (from %s).",
1066
+ log_identifier_req,
1067
+ max_content_length,
1068
+ "app config" if component else "default",
1069
+ )
1070
+
1071
+ try:
1072
+ actual_version: int
1073
+ if isinstance(version, str) and version.lower() == "latest":
1074
+ log.debug(
1075
+ "%s Requested version is 'latest', resolving...", log_identifier_req
1076
+ )
1077
+ try:
1078
+ list_versions_method = getattr(artifact_service, "list_versions")
1079
+ available_versions = await list_versions_method(
1080
+ app_name=app_name,
1081
+ user_id=user_id,
1082
+ session_id=session_id,
1083
+ filename=filename,
1084
+ )
1085
+ if not available_versions:
1086
+ raise FileNotFoundError(
1087
+ f"Artifact '{filename}' has no versions available to determine 'latest'."
1088
+ )
1089
+ actual_version = max(available_versions)
1090
+ log.info(
1091
+ "%s Resolved 'latest' to version %d.",
1092
+ log_identifier_req,
1093
+ actual_version,
1094
+ )
1095
+ except Exception as list_err:
1096
+ log.error(
1097
+ "%s Failed to list versions for '%s' to resolve 'latest': %s",
1098
+ log_identifier_req,
1099
+ filename,
1100
+ list_err,
1101
+ )
1102
+ raise FileNotFoundError(
1103
+ f"Could not determine latest version for '{filename}': {list_err}"
1104
+ ) from list_err
1105
+ elif isinstance(version, int):
1106
+ actual_version = version
1107
+ elif isinstance(version, str):
1108
+ try:
1109
+ actual_version = int(version)
1110
+ except ValueError:
1111
+ raise ValueError(
1112
+ f"Invalid version specified: '{version}'. Must be a positive integer string or 'latest'."
1113
+ )
1114
+ else:
1115
+ raise ValueError(
1116
+ f"Invalid version type: '{type(version).__name__}'. Must be an integer or 'latest'."
1117
+ )
1118
+
1119
+ if actual_version < 0:
1120
+ raise ValueError(
1121
+ f"Version number must be a positive integer. Got: {actual_version}"
1122
+ )
1123
+
1124
+ target_filename = (
1125
+ f"{filename}{METADATA_SUFFIX}" if load_metadata_only else filename
1126
+ )
1127
+ version_to_load = actual_version
1128
+
1129
+ log_identifier = f"{log_identifier_prefix}:{filename}:{version_to_load}"
1130
+
1131
+ log.debug(
1132
+ "%s Attempting to load '%s' v%d (async)",
1133
+ log_identifier,
1134
+ target_filename,
1135
+ version_to_load,
1136
+ )
1137
+
1138
+ load_artifact_method = getattr(artifact_service, "load_artifact")
1139
+ artifact_part = await load_artifact_method(
1140
+ app_name=app_name,
1141
+ user_id=user_id,
1142
+ session_id=session_id,
1143
+ filename=target_filename,
1144
+ version=version_to_load,
1145
+ )
1146
+
1147
+ if not artifact_part or not artifact_part.inline_data:
1148
+ raise FileNotFoundError(
1149
+ f"Artifact '{target_filename}' version {version_to_load} not found or has no data."
1150
+ )
1151
+
1152
+ mime_type = artifact_part.inline_data.mime_type
1153
+ data_bytes = artifact_part.inline_data.data
1154
+ size_bytes = len(data_bytes)
1155
+
1156
+ if load_metadata_only:
1157
+ if mime_type != "application/json":
1158
+ log.warning(
1159
+ "%s Expected metadata file '%s' v%d to be application/json, but got '%s'. Attempting parse anyway.",
1160
+ log_identifier,
1161
+ target_filename,
1162
+ version_to_load,
1163
+ mime_type,
1164
+ )
1165
+ try:
1166
+ metadata_dict = json.loads(data_bytes.decode("utf-8"))
1167
+ log.info(
1168
+ "%s Successfully loaded and parsed metadata for '%s' v%d.",
1169
+ log_identifier,
1170
+ filename,
1171
+ version_to_load,
1172
+ )
1173
+ return {
1174
+ "status": "success",
1175
+ "filename": filename,
1176
+ "version": version_to_load,
1177
+ "metadata": metadata_dict,
1178
+ }
1179
+
1180
+ except (json.JSONDecodeError, UnicodeDecodeError) as parse_err:
1181
+ raise ValueError(
1182
+ f"Failed to parse metadata file '{target_filename}' v{version_to_load}: {parse_err}"
1183
+ ) from parse_err
1184
+
1185
+ else:
1186
+ if return_raw_bytes:
1187
+ log.info(
1188
+ "%s Loaded artifact '%s' v%d (%d bytes, type: %s). Returning raw_bytes.",
1189
+ log_identifier,
1190
+ filename,
1191
+ version_to_load,
1192
+ size_bytes,
1193
+ mime_type,
1194
+ )
1195
+ return {
1196
+ "status": "success",
1197
+ "filename": filename,
1198
+ "version": version_to_load,
1199
+ "mime_type": mime_type,
1200
+ "raw_bytes": data_bytes,
1201
+ "size_bytes": size_bytes,
1202
+ }
1203
+ else:
1204
+ is_text = is_text_based_file(mime_type, data_bytes)
1205
+
1206
+ if is_text:
1207
+ try:
1208
+ content_str = data_bytes.decode(encoding, errors=error_handling)
1209
+ original_content_str = content_str # Save for line count calculation
1210
+
1211
+ # Add line numbers if requested (before truncation)
1212
+ if include_line_numbers:
1213
+ lines = content_str.split('\n')
1214
+ numbered_lines = [f"{i+1}\t{line}" for i, line in enumerate(lines)]
1215
+ content_str = '\n'.join(numbered_lines)
1216
+ log.debug(
1217
+ "%s Added line numbers to %d lines.",
1218
+ log_identifier,
1219
+ len(lines)
1220
+ )
1221
+
1222
+ message_to_llm = ""
1223
+ if len(content_str) > max_content_length:
1224
+ truncated_content = content_str[:max_content_length] + "..."
1225
+
1226
+ # Calculate line range if line numbers are included
1227
+ line_range_msg = ""
1228
+ if include_line_numbers:
1229
+ visible_line_count = truncated_content.count('\n') + 1
1230
+ total_line_count = original_content_str.count('\n') + 1
1231
+ line_range_msg = f" Lines 1-{visible_line_count} of {total_line_count} total."
1232
+
1233
+ if (
1234
+ max_content_length
1235
+ < TEXT_ARTIFACT_CONTEXT_MAX_LENGTH_CAPACITY
1236
+ ):
1237
+ message_to_llm = f"""This artifact content has been truncated to {max_content_length} characters.{line_range_msg}
1238
+ The artifact is larger ({len(content_str)} characters).
1239
+ Please request again with larger max size up to {TEXT_ARTIFACT_CONTEXT_MAX_LENGTH_CAPACITY} for the full artifact."""
1240
+ else:
1241
+ message_to_llm = f"""This artifact content has been truncated to {max_content_length} characters.{line_range_msg}
1242
+ The artifact content met the maximum allowed size of {TEXT_ARTIFACT_CONTEXT_MAX_LENGTH_CAPACITY} characters.
1243
+ Please continue with this truncated content as the full artifact cannot be provided."""
1244
+ log.info(
1245
+ "%s Loaded and decoded text artifact '%s' v%d. Returning truncated content (%d chars, limit: %d).%s",
1246
+ log_identifier,
1247
+ filename,
1248
+ version_to_load,
1249
+ len(truncated_content),
1250
+ max_content_length,
1251
+ line_range_msg,
1252
+ )
1253
+ else:
1254
+ truncated_content = content_str
1255
+ log.info(
1256
+ "%s Loaded and decoded text artifact '%s' v%d. Returning full content (%d chars).",
1257
+ log_identifier,
1258
+ filename,
1259
+ version_to_load,
1260
+ len(content_str),
1261
+ )
1262
+ return {
1263
+ "status": "success",
1264
+ "filename": filename,
1265
+ "version": version_to_load,
1266
+ "mime_type": mime_type,
1267
+ "content": truncated_content,
1268
+ "message_to_llm": message_to_llm,
1269
+ "size_bytes": size_bytes,
1270
+ }
1271
+ except UnicodeDecodeError as decode_err:
1272
+ log.error(
1273
+ "%s Failed to decode text artifact '%s' v%d with encoding '%s': %s",
1274
+ log_identifier,
1275
+ filename,
1276
+ version_to_load,
1277
+ mime_type,
1278
+ decode_err,
1279
+ )
1280
+ raise ValueError(
1281
+ f"Failed to decode artifact '{filename}' v{version_to_load} as {encoding}."
1282
+ ) from decode_err
1283
+ else:
1284
+ log.info(
1285
+ "%s Loaded binary/unknown artifact '%s' v%d. Returning metadata summary.",
1286
+ log_identifier,
1287
+ filename,
1288
+ version_to_load,
1289
+ )
1290
+
1291
+ metadata_for_binary = {}
1292
+ if not filename.endswith(METADATA_SUFFIX):
1293
+ try:
1294
+ metadata_filename_for_binary = (
1295
+ f"{filename}{METADATA_SUFFIX}"
1296
+ )
1297
+ log.debug(
1298
+ "%s Attempting to load linked metadata file '%s' for binary artifact '%s' v%d.",
1299
+ log_identifier,
1300
+ metadata_filename_for_binary,
1301
+ filename,
1302
+ version_to_load,
1303
+ )
1304
+ metadata_data = await load_artifact_content_or_metadata(
1305
+ artifact_service=artifact_service,
1306
+ app_name=app_name,
1307
+ user_id=user_id,
1308
+ session_id=session_id,
1309
+ filename=f"{filename}{METADATA_SUFFIX}",
1310
+ version=version,
1311
+ load_metadata_only=True,
1312
+ log_identifier_prefix=f"{log_identifier}[meta_for_binary]",
1313
+ )
1314
+ if metadata_data.get("status") == "success":
1315
+ metadata_for_binary = metadata_data.get("metadata", {})
1316
+ except Exception as e_meta_bin:
1317
+ log.warning(
1318
+ f"{log_identifier} Could not load metadata for binary artifact {filename}: {e_meta_bin}"
1319
+ )
1320
+ metadata_for_binary = {
1321
+ "error": f"Could not load metadata: {e_meta_bin}"
1322
+ }
1323
+
1324
+ return {
1325
+ "status": "success",
1326
+ "filename": filename,
1327
+ "version": version_to_load,
1328
+ "mime_type": mime_type,
1329
+ "size_bytes": size_bytes,
1330
+ "metadata": metadata_for_binary,
1331
+ "content": f"Binary data of type {mime_type}. Content not displayed.",
1332
+ }
1333
+
1334
+ except FileNotFoundError as fnf_err:
1335
+ log.warning("%s Artifact not found: %s", log_identifier_req, fnf_err)
1336
+ return {"status": "not_found", "message": str(fnf_err)}
1337
+ except ValueError as val_err:
1338
+ log.error(
1339
+ "%s Value error during artifact load: %s", log_identifier_req, val_err
1340
+ )
1341
+ return {"status": "error", "message": str(val_err)}
1342
+ except Exception as e:
1343
+ log.exception(
1344
+ "%s Unexpected error loading artifact '%s' version '%s': %s",
1345
+ log_identifier_req,
1346
+ filename,
1347
+ version,
1348
+ e,
1349
+ )
1350
+ return {
1351
+ "status": "error",
1352
+ "message": f"Unexpected error loading artifact: {e}",
1353
+ }