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,1185 @@
1
+ """
2
+ Collection of Python tools for image generation, manipulation, and multimodal content analysis.
3
+ Includes tools for image description and audio description using vision and audio APIs.
4
+ """
5
+
6
+ import logging
7
+ import asyncio
8
+ import base64
9
+ import inspect
10
+ import json
11
+ import os
12
+ import uuid
13
+ from datetime import datetime, timezone
14
+ from typing import Any, Dict, Optional
15
+
16
+ import httpx
17
+ from google.adk.tools import ToolContext
18
+
19
+ from ..utils.artifact_helpers import (
20
+ save_artifact_with_metadata,
21
+ DEFAULT_SCHEMA_MAX_KEYS,
22
+ )
23
+ from ..utils.context_helpers import get_original_session_id
24
+
25
+ from google.genai import types as adk_types
26
+ from .tool_definition import BuiltinTool
27
+ from .registry import tool_registry
28
+
29
+ log = logging.getLogger(__name__)
30
+
31
+ async def create_image_from_description(
32
+ image_description: str,
33
+ output_filename: Optional[str] = None,
34
+ tool_context: ToolContext = None,
35
+ tool_config: Optional[Dict[str, Any]] = None,
36
+ ) -> Dict[str, Any]:
37
+ """
38
+ Generates an image based on a textual description using LiteLLM and saves it as a PNG artifact.
39
+ Configuration for LiteLLM (model, api_key, etc.) is expected in `tool_config`.
40
+
41
+ Args:
42
+ image_description: The textual prompt to use for image generation.
43
+ output_filename: Optional. The desired filename for the output PNG image.
44
+ If not provided, a unique name like 'generated_image_<uuid>.png' will be used.
45
+ tool_context: The context provided by the ADK framework.
46
+ tool_config: Optional dictionary containing specific configuration for this tool.
47
+
48
+ Returns:
49
+ A dictionary containing:
50
+ - "status": "success" or "error".
51
+ - "message": A descriptive message about the outcome.
52
+ - "output_filename": The name of the saved image artifact (if successful).
53
+ - "output_version": The version of the saved image artifact (if successful).
54
+ - "result_preview": A brief preview message (if successful).
55
+ """
56
+ log_identifier = f"[ImageTools:create_image_from_description]"
57
+ if not tool_context:
58
+ log.error(f"{log_identifier} ToolContext is missing.")
59
+ return {"status": "error", "message": "ToolContext is missing."}
60
+
61
+ try:
62
+ inv_context = tool_context._invocation_context
63
+ if not inv_context:
64
+ raise ValueError("InvocationContext is not available.")
65
+
66
+ app_name = getattr(inv_context, "app_name", None)
67
+ user_id = getattr(inv_context, "user_id", None)
68
+ session_id = get_original_session_id(inv_context)
69
+ artifact_service = getattr(inv_context, "artifact_service", None)
70
+
71
+ if not all([app_name, user_id, session_id, artifact_service]):
72
+ missing_parts = [
73
+ part
74
+ for part, val in [
75
+ ("app_name", app_name),
76
+ ("user_id", user_id),
77
+ ("session_id", session_id),
78
+ ("artifact_service", artifact_service),
79
+ ]
80
+ if not val
81
+ ]
82
+ raise ValueError(
83
+ f"Missing required context parts: {', '.join(missing_parts)}"
84
+ )
85
+
86
+ log.info(f"{log_identifier} Processing request for session {session_id}.")
87
+
88
+ current_tool_config = tool_config if tool_config is not None else {}
89
+
90
+ if not current_tool_config:
91
+ log.warning(
92
+ f"{log_identifier} Tool-specific configuration (tool_config) is empty."
93
+ )
94
+
95
+ model_name = current_tool_config.get("model")
96
+ api_key = current_tool_config.get("api_key")
97
+ api_base = current_tool_config.get("api_base")
98
+ extra_params = current_tool_config.get("extra_params", {})
99
+
100
+ if not model_name:
101
+ raise ValueError("'model' configuration is missing in tool_config.")
102
+ if not api_key:
103
+ raise ValueError("'api_key' configuration is missing in tool_config.")
104
+ if not api_base:
105
+ raise ValueError("'api_base' configuration is missing in tool_config.")
106
+
107
+ if "/" in model_name:
108
+ original_model_name = model_name
109
+ model_name = model_name.split("/", 1)[-1]
110
+ log.debug(
111
+ f"{log_identifier} Original model name '{original_model_name}' processed to '{model_name}' for API call."
112
+ )
113
+
114
+ log.debug(
115
+ f"{log_identifier} Using image generation model: {model_name} via direct API call to: {api_base}"
116
+ )
117
+
118
+ api_url = f"{api_base.rstrip('/')}/v1/images/generations"
119
+ headers = {
120
+ "Content-Type": "application/json",
121
+ "Authorization": f"Bearer {api_key}",
122
+ }
123
+ payload = {"model": model_name, "prompt": image_description, **extra_params}
124
+
125
+ log.debug(
126
+ f"{log_identifier} Calling image generation API with prompt: '{image_description[:100]}...' and payload: {json.dumps(payload)}"
127
+ )
128
+
129
+ try:
130
+ async with httpx.AsyncClient(timeout=60.0) as client:
131
+ http_response = await client.post(
132
+ api_url, headers=headers, json=payload
133
+ )
134
+ http_response.raise_for_status()
135
+ response_data = http_response.json()
136
+ except httpx.HTTPStatusError as hse:
137
+ log.error(
138
+ f"{log_identifier} HTTP error calling image generation API {hse.request.url}: {hse.response.status_code} - {hse.response.text}"
139
+ )
140
+ return {
141
+ "status": "error",
142
+ "message": f"API error generating image: {hse.response.status_code} - {hse.response.text}",
143
+ }
144
+ except httpx.RequestError as re:
145
+ log.error(
146
+ f"{log_identifier} Request error calling image generation API {re.request.url}: {re}"
147
+ )
148
+ return {
149
+ "status": "error",
150
+ "message": f"Request error generating image: {re}",
151
+ }
152
+ except Exception as e:
153
+ log.error(f"{log_identifier} Error calling image generation API: {e}")
154
+ return {"status": "error", "message": f"Error generating image: {e}"}
155
+
156
+ log.debug(f"{log_identifier} Image generation API response received.")
157
+
158
+ if (
159
+ not response_data
160
+ or not response_data.get("data")
161
+ or not response_data["data"][0]
162
+ ):
163
+ log.error(
164
+ f"{log_identifier} API did not return valid image data. Response: {json.dumps(response_data)}"
165
+ )
166
+ raise ValueError("Image generation API did not return valid image data.")
167
+
168
+ image_data_item = response_data["data"][0]
169
+ image_bytes = None
170
+
171
+ if image_data_item.get("url"):
172
+ image_url = image_data_item["url"]
173
+ log.info(f"{log_identifier} Fetching image from URL: {image_url}")
174
+ async with httpx.AsyncClient() as client:
175
+ http_response = await client.get(image_url, timeout=30.0)
176
+ http_response.raise_for_status()
177
+ image_bytes = http_response.content
178
+ log.info(f"{log_identifier} Image fetched successfully from URL.")
179
+ elif image_data_item.get("b64_json"):
180
+ log.info(f"{log_identifier} Decoding image from b64_json.")
181
+ image_bytes = base64.b64decode(image_data_item["b64_json"])
182
+ log.info(f"{log_identifier} Image decoded successfully from b64_json.")
183
+ else:
184
+ raise ValueError(
185
+ "No valid image data (URL or b64_json) found in LiteLLM response."
186
+ )
187
+
188
+ if not image_bytes:
189
+ raise ValueError("Failed to retrieve image bytes.")
190
+
191
+ final_output_filename = ""
192
+ if output_filename:
193
+ if not output_filename.lower().endswith(".png"):
194
+ final_output_filename = f"{output_filename}.png"
195
+ else:
196
+ final_output_filename = output_filename
197
+ else:
198
+ final_output_filename = f"generated_image_{uuid.uuid4()}.png"
199
+ log.debug(
200
+ f"{log_identifier} Determined output filename: {final_output_filename}"
201
+ )
202
+
203
+ output_mime_type = "image/png"
204
+ current_timestamp_iso = datetime.now(timezone.utc).isoformat()
205
+
206
+ metadata_dict = {
207
+ "description": f"Image generated from prompt: {image_description}",
208
+ "source_prompt": image_description,
209
+ "generation_tool": "direct_api",
210
+ "generation_model": model_name,
211
+ "request_timestamp": current_timestamp_iso,
212
+ "original_requested_filename": (
213
+ output_filename if output_filename else "N/A"
214
+ ),
215
+ }
216
+ if extra_params:
217
+ metadata_dict["api_request_params"] = json.dumps(extra_params)
218
+
219
+ log.info(
220
+ f"{log_identifier} Saving artifact '{final_output_filename}' with mime_type '{output_mime_type}'."
221
+ )
222
+ save_result = await save_artifact_with_metadata(
223
+ artifact_service=artifact_service,
224
+ app_name=app_name,
225
+ user_id=user_id,
226
+ session_id=session_id,
227
+ filename=final_output_filename,
228
+ content_bytes=image_bytes,
229
+ mime_type=output_mime_type,
230
+ metadata_dict=metadata_dict,
231
+ timestamp=datetime.now(timezone.utc),
232
+ schema_max_keys=DEFAULT_SCHEMA_MAX_KEYS,
233
+ tool_context=tool_context,
234
+ )
235
+
236
+ if save_result.get("status") == "error":
237
+ raise IOError(
238
+ f"Failed to save image artifact: {save_result.get('message', 'Unknown error')}"
239
+ )
240
+
241
+ log.info(
242
+ f"{log_identifier} Artifact '{final_output_filename}' v{save_result['data_version']} saved successfully."
243
+ )
244
+
245
+ return {
246
+ "status": "success",
247
+ "message": "Image generated and saved successfully.",
248
+ "output_filename": final_output_filename,
249
+ "output_version": save_result["data_version"],
250
+ "result_preview": f"Image '{final_output_filename}' (v{save_result['data_version']}) created from prompt: \"{image_description[:50]}...\"",
251
+ }
252
+
253
+ except ValueError as ve:
254
+ log.error(f"{log_identifier} Value error: {ve}")
255
+ return {"status": "error", "message": str(ve)}
256
+ except httpx.HTTPStatusError as hse:
257
+ log.error(
258
+ f"{log_identifier} HTTP error fetching image from URL {hse.request.url}: {hse.response.status_code} - {hse.response.text}"
259
+ )
260
+ return {
261
+ "status": "error",
262
+ "message": f"HTTP error fetching image: {hse.response.status_code}",
263
+ }
264
+ except httpx.RequestError as re:
265
+ log.error(
266
+ f"{log_identifier} Request error fetching image from URL {re.request.url}: {re}"
267
+ )
268
+ return {"status": "error", "message": f"Request error fetching image: {re}"}
269
+ except IOError as ioe:
270
+ log.error(f"{log_identifier} IO error: {ioe}")
271
+ return {"status": "error", "message": str(ioe)}
272
+ except Exception as e:
273
+ log.exception(
274
+ f"{log_identifier} Unexpected error in create_image_from_description: {e}"
275
+ )
276
+ return {"status": "error", "message": f"An unexpected error occurred: {e}"}
277
+
278
+
279
+ def _get_image_mime_type(filename: str) -> str:
280
+ """Get MIME type from file extension."""
281
+ ext = os.path.splitext(filename)[1].lower()
282
+ mime_mapping = {
283
+ ".jpg": "image/jpeg",
284
+ ".jpeg": "image/jpeg",
285
+ ".png": "image/png",
286
+ ".webp": "image/webp",
287
+ ".gif": "image/gif",
288
+ }
289
+ return mime_mapping.get(ext, "application/octet-stream")
290
+
291
+
292
+ def _is_supported_image_format(filename: str) -> bool:
293
+ """Check if the image format is supported."""
294
+ ext = os.path.splitext(filename)[1].lower()
295
+ supported_formats = {".jpg", ".jpeg", ".png", ".webp", ".gif"}
296
+ return ext in supported_formats
297
+
298
+
299
+ def _create_data_url(image_bytes: bytes, mime_type: str) -> str:
300
+ """Create base64 data URL from image bytes."""
301
+ base64_data = base64.b64encode(image_bytes).decode("utf-8")
302
+ return f"data:{mime_type};base64,{base64_data}"
303
+
304
+
305
+ async def describe_image(
306
+ image_filename: str,
307
+ prompt: str = "What is in this image?",
308
+ tool_context: ToolContext = None,
309
+ tool_config: Optional[Dict[str, Any]] = None,
310
+ ) -> Dict[str, Any]:
311
+ """
312
+ Describes an image using an OpenAI-compatible vision API.
313
+
314
+ Args:
315
+ image_filename: The filename (and optional :version) of the input image artifact.
316
+ prompt: Custom prompt for image analysis (default: "What is in this image?").
317
+ tool_context: The context provided by the ADK framework.
318
+ tool_config: Configuration dictionary containing model, api_base, api_key.
319
+
320
+ Returns:
321
+ A dictionary containing:
322
+ - "status": "success" or "error".
323
+ - "message": A descriptive message about the outcome.
324
+ - "description": The image description from the API (if successful).
325
+ - "image_filename": The name of the input image artifact (if successful).
326
+ - "image_version": The version of the input image artifact (if successful).
327
+ - "tokens_used": Token usage information from the API (if available).
328
+ """
329
+ log_identifier = f"[ImageTools:describe_image:{image_filename}]"
330
+ if not tool_context:
331
+ log.error(f"{log_identifier} ToolContext is missing.")
332
+ return {"status": "error", "message": "ToolContext is missing."}
333
+
334
+ try:
335
+ inv_context = tool_context._invocation_context
336
+ if not inv_context:
337
+ raise ValueError("InvocationContext is not available.")
338
+
339
+ app_name = getattr(inv_context, "app_name", None)
340
+ user_id = getattr(inv_context, "user_id", None)
341
+ session_id = get_original_session_id(inv_context)
342
+ artifact_service = getattr(inv_context, "artifact_service", None)
343
+
344
+ if not all([app_name, user_id, session_id, artifact_service]):
345
+ missing_parts = [
346
+ part
347
+ for part, val in [
348
+ ("app_name", app_name),
349
+ ("user_id", user_id),
350
+ ("session_id", session_id),
351
+ ("artifact_service", artifact_service),
352
+ ]
353
+ if not val
354
+ ]
355
+ raise ValueError(
356
+ f"Missing required context parts: {', '.join(missing_parts)}"
357
+ )
358
+
359
+ log.info(f"{log_identifier} Processing request for session {session_id}.")
360
+
361
+ current_tool_config = tool_config if tool_config is not None else {}
362
+
363
+ if not current_tool_config:
364
+ log.warning(
365
+ f"{log_identifier} Tool-specific configuration (tool_config) is empty."
366
+ )
367
+
368
+ model_name = current_tool_config.get("model")
369
+ api_key = current_tool_config.get("api_key")
370
+ api_base = current_tool_config.get("api_base")
371
+
372
+ if not model_name:
373
+ raise ValueError("'model' configuration is missing in tool_config.")
374
+ if not api_key:
375
+ raise ValueError("'api_key' configuration is missing in tool_config.")
376
+ if not api_base:
377
+ raise ValueError("'api_base' configuration is missing in tool_config.")
378
+
379
+ log.debug(f"{log_identifier} Using model: {model_name}, API base: {api_base}")
380
+
381
+ parts = image_filename.rsplit(":", 1)
382
+ filename_base_for_load = parts[0]
383
+ version_str = parts[1] if len(parts) > 1 else None
384
+ version_to_load = int(version_str) if version_str else None
385
+
386
+ if not _is_supported_image_format(filename_base_for_load):
387
+ raise ValueError(
388
+ f"Unsupported image format. Supported formats: .png, .jpg, .jpeg, .webp, .gif"
389
+ )
390
+
391
+ if version_to_load is None:
392
+ list_versions_method = getattr(artifact_service, "list_versions")
393
+ if inspect.iscoroutinefunction(list_versions_method):
394
+ versions = await list_versions_method(
395
+ app_name=app_name,
396
+ user_id=user_id,
397
+ session_id=session_id,
398
+ filename=filename_base_for_load,
399
+ )
400
+ else:
401
+ versions = await asyncio.to_thread(
402
+ list_versions_method,
403
+ app_name=app_name,
404
+ user_id=user_id,
405
+ session_id=session_id,
406
+ filename=filename_base_for_load,
407
+ )
408
+ if not versions:
409
+ raise FileNotFoundError(
410
+ f"Image artifact '{filename_base_for_load}' not found."
411
+ )
412
+ version_to_load = max(versions)
413
+ log.debug(
414
+ f"{log_identifier} Using latest version for input: {version_to_load}"
415
+ )
416
+
417
+ load_artifact_method = getattr(artifact_service, "load_artifact")
418
+ if inspect.iscoroutinefunction(load_artifact_method):
419
+ image_artifact_part = await load_artifact_method(
420
+ app_name=app_name,
421
+ user_id=user_id,
422
+ session_id=session_id,
423
+ filename=filename_base_for_load,
424
+ version=version_to_load,
425
+ )
426
+ else:
427
+ image_artifact_part = await asyncio.to_thread(
428
+ load_artifact_method,
429
+ app_name=app_name,
430
+ user_id=user_id,
431
+ session_id=session_id,
432
+ filename=filename_base_for_load,
433
+ version=version_to_load,
434
+ )
435
+
436
+ if not image_artifact_part or not image_artifact_part.inline_data:
437
+ raise FileNotFoundError(
438
+ f"Content for image artifact '{filename_base_for_load}' v{version_to_load} not found."
439
+ )
440
+
441
+ image_bytes = image_artifact_part.inline_data.data
442
+ log.debug(f"{log_identifier} Loaded image artifact: {len(image_bytes)} bytes")
443
+
444
+ mime_type = _get_image_mime_type(filename_base_for_load)
445
+ data_url = _create_data_url(image_bytes, mime_type)
446
+ log.debug(f"{log_identifier} Created data URL with MIME type: {mime_type}")
447
+
448
+ api_url = f"{api_base.rstrip('/')}/v1/chat/completions"
449
+ headers = {
450
+ "Content-Type": "application/json",
451
+ "Authorization": f"Bearer {api_key}",
452
+ }
453
+
454
+ request_data = {
455
+ "model": model_name,
456
+ "messages": [
457
+ {
458
+ "role": "user",
459
+ "content": [
460
+ {"type": "text", "text": prompt},
461
+ {"type": "image_url", "image_url": {"url": data_url}},
462
+ ],
463
+ }
464
+ ],
465
+ }
466
+
467
+ log.debug(
468
+ f"{log_identifier} Calling vision API with prompt: '{prompt[:100]}...'"
469
+ )
470
+
471
+ async with httpx.AsyncClient(timeout=60.0) as client:
472
+ response = await client.post(api_url, headers=headers, json=request_data)
473
+ response.raise_for_status()
474
+ response_data = response.json()
475
+ log.debug(f"{log_identifier} Vision API response received.")
476
+
477
+ if not response_data.get("choices") or not response_data["choices"]:
478
+ raise ValueError("API response does not contain valid choices.")
479
+
480
+ choice = response_data["choices"][0]
481
+ if not choice.get("message") or not choice["message"].get("content"):
482
+ raise ValueError("API response does not contain valid message content.")
483
+
484
+ description = choice["message"]["content"]
485
+
486
+ tokens_used = response_data.get("usage", {})
487
+
488
+ log.info(
489
+ f"{log_identifier} Image described successfully. Description length: {len(description)} characters"
490
+ )
491
+
492
+ return {
493
+ "status": "success",
494
+ "message": "Image described successfully",
495
+ "description": description,
496
+ "image_filename": filename_base_for_load,
497
+ "image_version": version_to_load,
498
+ "tokens_used": tokens_used,
499
+ }
500
+
501
+ except FileNotFoundError as e:
502
+ log.warning(f"{log_identifier} File not found error: {e}")
503
+ return {"status": "error", "message": str(e)}
504
+ except ValueError as ve:
505
+ log.error(f"{log_identifier} Value error: {ve}")
506
+ return {"status": "error", "message": str(ve)}
507
+ except httpx.HTTPStatusError as hse:
508
+ log.error(
509
+ f"{log_identifier} HTTP error calling vision API: {hse.response.status_code} - {hse.response.text}"
510
+ )
511
+ return {"status": "error", "message": f"API error: {hse.response.status_code}"}
512
+ except httpx.RequestError as re:
513
+ log.error(f"{log_identifier} Request error calling vision API: {re}")
514
+ return {"status": "error", "message": f"Request error: {re}"}
515
+ except json.JSONDecodeError as jde:
516
+ log.error(f"{log_identifier} JSON decode error: {jde}")
517
+ return {"status": "error", "message": "Invalid JSON response from API"}
518
+ except Exception as e:
519
+ log.exception(f"{log_identifier} Unexpected error in describe_image: {e}")
520
+ return {"status": "error", "message": f"An unexpected error occurred: {e}"}
521
+
522
+
523
+ def _get_audio_format(filename: str) -> str:
524
+ """Get audio format from file extension."""
525
+ ext = os.path.splitext(filename)[1].lower()
526
+ format_mapping = {".wav": "wav", ".mp3": "mp3"}
527
+ return format_mapping.get(ext, "wav")
528
+
529
+
530
+ def _is_supported_audio_format(filename: str) -> bool:
531
+ """Check if the audio format is supported."""
532
+ ext = os.path.splitext(filename)[1].lower()
533
+ supported_formats = {".wav", ".mp3"}
534
+ return ext in supported_formats
535
+
536
+
537
+ def _encode_audio_to_base64(audio_bytes: bytes) -> str:
538
+ """Encode audio bytes to base64 string."""
539
+ return base64.b64encode(audio_bytes).decode("utf-8")
540
+
541
+
542
+ async def describe_audio(
543
+ audio_filename: str,
544
+ prompt: str = "What is in this recording?",
545
+ tool_context: ToolContext = None,
546
+ tool_config: Optional[Dict[str, Any]] = None,
547
+ ) -> Dict[str, Any]:
548
+ """
549
+ Describes an audio recording using an OpenAI-compatible audio API.
550
+
551
+ Args:
552
+ audio_filename: The filename (and optional :version) of the input audio artifact.
553
+ prompt: Custom prompt for audio analysis (default: "What is in this recording?").
554
+ tool_context: The context provided by the ADK framework.
555
+ tool_config: Configuration dictionary containing model, api_base, api_key.
556
+
557
+ Returns:
558
+ A dictionary containing:
559
+ - "status": "success" or "error".
560
+ - "message": A descriptive message about the outcome.
561
+ - "description": The audio description from the API (if successful).
562
+ - "audio_filename": The name of the input audio artifact (if successful).
563
+ - "audio_version": The version of the input audio artifact (if successful).
564
+ - "tokens_used": Token usage information from the API (if available).
565
+ """
566
+ log_identifier = f"[ImageTools:describe_audio:{audio_filename}]"
567
+ if not tool_context:
568
+ log.error(f"{log_identifier} ToolContext is missing.")
569
+ return {"status": "error", "message": "ToolContext is missing."}
570
+
571
+ try:
572
+ inv_context = tool_context._invocation_context
573
+ if not inv_context:
574
+ raise ValueError("InvocationContext is not available.")
575
+
576
+ app_name = getattr(inv_context, "app_name", None)
577
+ user_id = getattr(inv_context, "user_id", None)
578
+ session_id = get_original_session_id(inv_context)
579
+ artifact_service = getattr(inv_context, "artifact_service", None)
580
+
581
+ if not all([app_name, user_id, session_id, artifact_service]):
582
+ missing_parts = [
583
+ part
584
+ for part, val in [
585
+ ("app_name", app_name),
586
+ ("user_id", user_id),
587
+ ("session_id", session_id),
588
+ ("artifact_service", artifact_service),
589
+ ]
590
+ if not val
591
+ ]
592
+ raise ValueError(
593
+ f"Missing required context parts: {', '.join(missing_parts)}"
594
+ )
595
+
596
+ log.info(f"{log_identifier} Processing request for session {session_id}.")
597
+
598
+ current_tool_config = tool_config if tool_config is not None else {}
599
+
600
+ if not current_tool_config:
601
+ log.warning(
602
+ f"{log_identifier} Tool-specific configuration (tool_config) is empty."
603
+ )
604
+
605
+ model_name = current_tool_config.get("model")
606
+ api_key = current_tool_config.get("api_key")
607
+ api_base = current_tool_config.get("api_base")
608
+
609
+ if not model_name:
610
+ raise ValueError("'model' configuration is missing in tool_config.")
611
+ if not api_key:
612
+ raise ValueError("'api_key' configuration is missing in tool_config.")
613
+ if not api_base:
614
+ raise ValueError("'api_base' configuration is missing in tool_config.")
615
+
616
+ log.debug(f"{log_identifier} Using model: {model_name}, API base: {api_base}")
617
+
618
+ parts = audio_filename.rsplit(":", 1)
619
+ filename_base_for_load = parts[0]
620
+ version_str = parts[1] if len(parts) > 1 else None
621
+ version_to_load = int(version_str) if version_str else None
622
+
623
+ if not _is_supported_audio_format(filename_base_for_load):
624
+ raise ValueError(f"Unsupported audio format. Supported formats: .wav, .mp3")
625
+
626
+ if version_to_load is None:
627
+ list_versions_method = getattr(artifact_service, "list_versions")
628
+ if inspect.iscoroutinefunction(list_versions_method):
629
+ versions = await list_versions_method(
630
+ app_name=app_name,
631
+ user_id=user_id,
632
+ session_id=session_id,
633
+ filename=filename_base_for_load,
634
+ )
635
+ else:
636
+ versions = await asyncio.to_thread(
637
+ list_versions_method,
638
+ app_name=app_name,
639
+ user_id=user_id,
640
+ session_id=session_id,
641
+ filename=filename_base_for_load,
642
+ )
643
+ if not versions:
644
+ raise FileNotFoundError(
645
+ f"Audio artifact '{filename_base_for_load}' not found."
646
+ )
647
+ version_to_load = max(versions)
648
+ log.debug(
649
+ f"{log_identifier} Using latest version for input: {version_to_load}"
650
+ )
651
+
652
+ load_artifact_method = getattr(artifact_service, "load_artifact")
653
+ if inspect.iscoroutinefunction(load_artifact_method):
654
+ audio_artifact_part = await load_artifact_method(
655
+ app_name=app_name,
656
+ user_id=user_id,
657
+ session_id=session_id,
658
+ filename=filename_base_for_load,
659
+ version=version_to_load,
660
+ )
661
+ else:
662
+ audio_artifact_part = await asyncio.to_thread(
663
+ load_artifact_method,
664
+ app_name=app_name,
665
+ user_id=user_id,
666
+ session_id=session_id,
667
+ filename=filename_base_for_load,
668
+ version=version_to_load,
669
+ )
670
+
671
+ if not audio_artifact_part or not audio_artifact_part.inline_data:
672
+ raise FileNotFoundError(
673
+ f"Content for audio artifact '{filename_base_for_load}' v{version_to_load} not found."
674
+ )
675
+
676
+ audio_bytes = audio_artifact_part.inline_data.data
677
+ log.debug(f"{log_identifier} Loaded audio artifact: {len(audio_bytes)} bytes")
678
+
679
+ audio_format = _get_audio_format(filename_base_for_load)
680
+ base64_audio = _encode_audio_to_base64(audio_bytes)
681
+ log.debug(
682
+ f"{log_identifier} Encoded audio to base64 with format: {audio_format}"
683
+ )
684
+
685
+ api_url = f"{api_base.rstrip('/')}/v1/chat/completions"
686
+ headers = {
687
+ "Content-Type": "application/json",
688
+ "Authorization": f"Bearer {api_key}",
689
+ }
690
+
691
+ request_data = {
692
+ "model": model_name,
693
+ "modalities": ["audio", "text"],
694
+ "audio": {"voice": "alloy", "format": audio_format},
695
+ "messages": [
696
+ {
697
+ "role": "user",
698
+ "content": [
699
+ {"type": "text", "text": prompt},
700
+ {
701
+ "type": "input_audio",
702
+ "input_audio": {
703
+ "data": base64_audio,
704
+ "format": audio_format,
705
+ },
706
+ },
707
+ ],
708
+ }
709
+ ],
710
+ }
711
+
712
+ log.debug(
713
+ f"{log_identifier} Calling audio API with prompt: '{prompt[:100]}...'"
714
+ )
715
+
716
+ async with httpx.AsyncClient(timeout=60.0) as client:
717
+ response = await client.post(api_url, headers=headers, json=request_data)
718
+ response.raise_for_status()
719
+ response_data = response.json()
720
+
721
+ log.debug(f"{log_identifier} Audio API response received.")
722
+
723
+ if not response_data.get("choices") or not response_data["choices"]:
724
+ raise ValueError("API response does not contain valid choices.")
725
+
726
+ choice = response_data["choices"][0]
727
+ if not choice.get("message") or not choice["message"].get("content"):
728
+ raise ValueError("API response does not contain valid message content.")
729
+
730
+ description = choice["message"]["content"]
731
+
732
+ tokens_used = response_data.get("usage", {})
733
+
734
+ log.info(
735
+ f"{log_identifier} Audio described successfully. Description length: {len(description)} characters"
736
+ )
737
+
738
+ return {
739
+ "status": "success",
740
+ "message": "Audio described successfully",
741
+ "description": description,
742
+ "audio_filename": filename_base_for_load,
743
+ "audio_version": version_to_load,
744
+ "tokens_used": tokens_used,
745
+ }
746
+
747
+ except FileNotFoundError as e:
748
+ log.warning(f"{log_identifier} File not found error: {e}")
749
+ return {"status": "error", "message": str(e)}
750
+ except ValueError as ve:
751
+ log.error(f"{log_identifier} Value error: {ve}")
752
+ return {"status": "error", "message": str(ve)}
753
+ except httpx.HTTPStatusError as hse:
754
+ log.error(
755
+ f"{log_identifier} HTTP error calling audio API: {hse.response.status_code} - {hse.response.text}"
756
+ )
757
+ return {"status": "error", "message": f"API error: {hse.response.status_code}"}
758
+ except httpx.RequestError as re:
759
+ log.error(f"{log_identifier} Request error calling audio API: {re}")
760
+ return {"status": "error", "message": f"Request error: {re}"}
761
+ except json.JSONDecodeError as jde:
762
+ log.error(f"{log_identifier} JSON decode error: {jde}")
763
+ return {"status": "error", "message": "Invalid JSON response from API"}
764
+ except Exception as e:
765
+ log.exception(f"{log_identifier} Unexpected error in describe_audio: {e}")
766
+ return {"status": "error", "message": f"An unexpected error occurred: {e}"}
767
+
768
+
769
+ async def edit_image_with_gemini(
770
+ image_filename: str,
771
+ edit_prompt: str,
772
+ output_filename: Optional[str] = None,
773
+ tool_context: ToolContext = None,
774
+ tool_config: Optional[Dict[str, Any]] = None,
775
+ ) -> Dict[str, Any]:
776
+ """
777
+ Edits an existing image based on a text prompt using Google's Gemini 2.0 Flash Preview Image Generation model.
778
+
779
+ Args:
780
+ image_filename: The filename (and optional :version) of the input image artifact.
781
+ edit_prompt: Text description of the desired edits to apply to the image.
782
+ output_filename: Optional. The desired filename for the output edited image.
783
+ If not provided, a unique name like 'edited_image_<uuid>.jpg' will be used.
784
+ tool_context: The context provided by the ADK framework.
785
+ tool_config: Configuration dictionary containing gemini_api_key and model.
786
+
787
+ Returns:
788
+ A dictionary containing:
789
+ - "status": "success" or "error".
790
+ - "message": A descriptive message about the outcome.
791
+ - "output_filename": The name of the saved edited image artifact (if successful).
792
+ - "output_version": The version of the saved edited image artifact (if successful).
793
+ - "result_preview": A brief preview message (if successful).
794
+ - "original_filename": The name of the input image artifact (if successful).
795
+ - "original_version": The version of the input image artifact (if successful).
796
+ """
797
+ log_identifier = f"[ImageTools:edit_image_with_gemini:{image_filename}]"
798
+ if not tool_context:
799
+ log.error(f"{log_identifier} ToolContext is missing.")
800
+ return {"status": "error", "message": "ToolContext is missing."}
801
+
802
+ try:
803
+ try:
804
+ from google import genai
805
+ from google.genai import types
806
+ from PIL import Image as PILImage
807
+ from io import BytesIO
808
+ except ImportError as ie:
809
+ log.error(f"{log_identifier} Required dependencies not available: {ie}")
810
+ return {
811
+ "status": "error",
812
+ "message": f"Required dependencies not available: {ie}",
813
+ }
814
+
815
+ inv_context = tool_context._invocation_context
816
+ if not inv_context:
817
+ raise ValueError("InvocationContext is not available.")
818
+
819
+ app_name = getattr(inv_context, "app_name", None)
820
+ user_id = getattr(inv_context, "user_id", None)
821
+ session_id = get_original_session_id(inv_context)
822
+ artifact_service = getattr(inv_context, "artifact_service", None)
823
+
824
+ if not all([app_name, user_id, session_id, artifact_service]):
825
+ missing_parts = [
826
+ part
827
+ for part, val in [
828
+ ("app_name", app_name),
829
+ ("user_id", user_id),
830
+ ("session_id", session_id),
831
+ ("artifact_service", artifact_service),
832
+ ]
833
+ if not val
834
+ ]
835
+ raise ValueError(
836
+ f"Missing required context parts: {', '.join(missing_parts)}"
837
+ )
838
+
839
+ log.info(
840
+ f"{log_identifier} Processing image edit request for session {session_id}."
841
+ )
842
+
843
+ current_tool_config = tool_config if tool_config is not None else {}
844
+
845
+ if not current_tool_config:
846
+ log.warning(
847
+ f"{log_identifier} Tool-specific configuration (tool_config) is empty."
848
+ )
849
+
850
+ gemini_api_key = current_tool_config.get("gemini_api_key")
851
+ model_name = current_tool_config.get(
852
+ "model", "gemini-2.0-flash-preview-image-generation"
853
+ )
854
+
855
+ if not gemini_api_key:
856
+ raise ValueError(
857
+ "'gemini_api_key' configuration is missing in tool_config."
858
+ )
859
+
860
+ log.debug(f"{log_identifier} Using Gemini model: {model_name}")
861
+
862
+ parts = image_filename.rsplit(":", 1)
863
+ filename_base_for_load = parts[0]
864
+ version_str = parts[1] if len(parts) > 1 else None
865
+ version_to_load = int(version_str) if version_str else None
866
+
867
+ if not _is_supported_image_format(filename_base_for_load):
868
+ raise ValueError(
869
+ f"Unsupported image format. Supported formats: .png, .jpg, .jpeg, .webp, .gif"
870
+ )
871
+
872
+ if version_to_load is None:
873
+ list_versions_method = getattr(artifact_service, "list_versions")
874
+ if inspect.iscoroutinefunction(list_versions_method):
875
+ versions = await list_versions_method(
876
+ app_name=app_name,
877
+ user_id=user_id,
878
+ session_id=session_id,
879
+ filename=filename_base_for_load,
880
+ )
881
+ else:
882
+ versions = await asyncio.to_thread(
883
+ list_versions_method,
884
+ app_name=app_name,
885
+ user_id=user_id,
886
+ session_id=session_id,
887
+ filename=filename_base_for_load,
888
+ )
889
+ if not versions:
890
+ raise FileNotFoundError(
891
+ f"Image artifact '{filename_base_for_load}' not found."
892
+ )
893
+ version_to_load = max(versions)
894
+ log.debug(
895
+ f"{log_identifier} Using latest version for input: {version_to_load}"
896
+ )
897
+
898
+ load_artifact_method = getattr(artifact_service, "load_artifact")
899
+ if inspect.iscoroutinefunction(load_artifact_method):
900
+ image_artifact_part = await load_artifact_method(
901
+ app_name=app_name,
902
+ user_id=user_id,
903
+ session_id=session_id,
904
+ filename=filename_base_for_load,
905
+ version=version_to_load,
906
+ )
907
+ else:
908
+ image_artifact_part = await asyncio.to_thread(
909
+ load_artifact_method,
910
+ app_name=app_name,
911
+ user_id=user_id,
912
+ session_id=session_id,
913
+ filename=filename_base_for_load,
914
+ version=version_to_load,
915
+ )
916
+
917
+ if not image_artifact_part or not image_artifact_part.inline_data:
918
+ raise FileNotFoundError(
919
+ f"Content for image artifact '{filename_base_for_load}' v{version_to_load} not found."
920
+ )
921
+
922
+ image_bytes = image_artifact_part.inline_data.data
923
+ log.debug(f"{log_identifier} Loaded image artifact: {len(image_bytes)} bytes")
924
+
925
+ try:
926
+ from PIL import UnidentifiedImageError
927
+
928
+ pil_image = PILImage.open(BytesIO(image_bytes))
929
+ log.debug(
930
+ f"{log_identifier} Converted to PIL Image: {pil_image.size}, mode: {pil_image.mode}"
931
+ )
932
+ except UnidentifiedImageError as e:
933
+ log.error(f"{log_identifier} Unidentified image error: {e}")
934
+ raise ValueError(f"Cannot identify image file: {e}")
935
+ except IOError as e:
936
+ log.error(f"{log_identifier} IO error: {e}")
937
+ raise ValueError(f"Cannot identify image file: {e}")
938
+ except Exception as e:
939
+ raise ValueError(f"Failed to process image data: {e}")
940
+
941
+ try:
942
+ client = genai.Client(api_key=gemini_api_key)
943
+ log.debug(f"{log_identifier} Initialized Gemini client")
944
+ except Exception as e:
945
+ raise ValueError(f"Failed to initialize Gemini client: {e}")
946
+
947
+ text_input = (edit_prompt,)
948
+
949
+ log.debug(
950
+ f"{log_identifier} Calling Gemini API with edit prompt: '{edit_prompt[:100]}...'"
951
+ )
952
+
953
+ try:
954
+ response = await asyncio.to_thread(
955
+ client.models.generate_content,
956
+ model=model_name,
957
+ contents=[text_input, pil_image],
958
+ config=types.GenerateContentConfig(
959
+ response_modalities=["TEXT", "IMAGE"]
960
+ ),
961
+ )
962
+ log.debug(f"{log_identifier} Gemini API response received.")
963
+ except Exception as e:
964
+ raise ValueError(f"Gemini API call failed: {e}")
965
+
966
+ edited_image_bytes = None
967
+ response_text = None
968
+
969
+ if not response.candidates or not response.candidates[0].content.parts:
970
+ raise ValueError("Gemini API did not return valid content.")
971
+
972
+ for part in response.candidates[0].content.parts:
973
+ if part.text is not None:
974
+ response_text = part.text
975
+ log.debug(
976
+ f"{log_identifier} Received text response: {response_text[:100]}..."
977
+ )
978
+ elif part.inline_data is not None:
979
+ edited_pil_image = PILImage.open(BytesIO(part.inline_data.data))
980
+ output_buffer = BytesIO()
981
+ if edited_pil_image.mode == "RGBA":
982
+ rgb_image = PILImage.new(
983
+ "RGB", edited_pil_image.size, (255, 255, 255)
984
+ )
985
+ rgb_image.paste(edited_pil_image, mask=edited_pil_image.split()[-1])
986
+ rgb_image.save(output_buffer, format="JPEG", quality=95)
987
+ else:
988
+ edited_pil_image.save(output_buffer, format="JPEG", quality=95)
989
+ edited_image_bytes = output_buffer.getvalue()
990
+ log.debug(
991
+ f"{log_identifier} Processed edited image: {len(edited_image_bytes)} bytes"
992
+ )
993
+
994
+ if not edited_image_bytes:
995
+ raise ValueError("No edited image data received from Gemini API.")
996
+
997
+ final_output_filename = ""
998
+ if output_filename:
999
+ sane_filename = os.path.basename(output_filename)
1000
+ if not sane_filename.lower().endswith((".jpg", ".jpeg")):
1001
+ final_output_filename = f"{sane_filename}.jpg"
1002
+ else:
1003
+ final_output_filename = sane_filename
1004
+ else:
1005
+ base_name = os.path.splitext(filename_base_for_load)[0]
1006
+ final_output_filename = f"edited_{base_name}_{uuid.uuid4().hex[:8]}.jpg"
1007
+
1008
+ log.debug(
1009
+ f"{log_identifier} Determined output filename: {final_output_filename}"
1010
+ )
1011
+
1012
+ output_mime_type = "image/jpeg"
1013
+ current_timestamp_iso = datetime.now(timezone.utc).isoformat()
1014
+
1015
+ metadata_dict = {
1016
+ "description": f"Image edited with prompt: {edit_prompt}",
1017
+ "original_image": filename_base_for_load,
1018
+ "original_version": version_to_load,
1019
+ "edit_prompt": edit_prompt,
1020
+ "editing_tool": "gemini",
1021
+ "editing_model": model_name,
1022
+ "request_timestamp": current_timestamp_iso,
1023
+ "original_requested_filename": (
1024
+ output_filename if output_filename else "N/A"
1025
+ ),
1026
+ }
1027
+ if response_text:
1028
+ metadata_dict["gemini_response_text"] = response_text
1029
+
1030
+ log.info(
1031
+ f"{log_identifier} Saving edited image artifact '{final_output_filename}' with mime_type '{output_mime_type}'."
1032
+ )
1033
+ save_result = await save_artifact_with_metadata(
1034
+ artifact_service=artifact_service,
1035
+ app_name=app_name,
1036
+ user_id=user_id,
1037
+ session_id=session_id,
1038
+ filename=final_output_filename,
1039
+ content_bytes=edited_image_bytes,
1040
+ mime_type=output_mime_type,
1041
+ metadata_dict=metadata_dict,
1042
+ timestamp=datetime.now(timezone.utc),
1043
+ schema_max_keys=DEFAULT_SCHEMA_MAX_KEYS,
1044
+ tool_context=tool_context,
1045
+ )
1046
+
1047
+ if save_result.get("status") == "error":
1048
+ raise IOError(
1049
+ f"Failed to save edited image artifact: {save_result.get('message', 'Unknown error')}"
1050
+ )
1051
+
1052
+ log.info(
1053
+ f"{log_identifier} Edited image artifact '{final_output_filename}' v{save_result['data_version']} saved successfully."
1054
+ )
1055
+
1056
+ return {
1057
+ "status": "success",
1058
+ "message": "Image edited and saved successfully.",
1059
+ "output_filename": final_output_filename,
1060
+ "output_version": save_result["data_version"],
1061
+ "result_preview": f"Edited image '{final_output_filename}' (v{save_result['data_version']}) created from '{filename_base_for_load}' with prompt: \"{edit_prompt[:50]}...\"",
1062
+ "original_filename": filename_base_for_load,
1063
+ "original_version": version_to_load,
1064
+ }
1065
+
1066
+ except FileNotFoundError as e:
1067
+ log.warning(f"{log_identifier} File not found error: {e}")
1068
+ return {"status": "error", "message": str(e)}
1069
+ except ValueError as ve:
1070
+ log.error(f"{log_identifier} Value error: {ve}")
1071
+ return {"status": "error", "message": str(ve)}
1072
+ except IOError as ioe:
1073
+ log.error(f"{log_identifier} IO error: {ioe}")
1074
+ return {"status": "error", "message": str(ioe)}
1075
+ except Exception as e:
1076
+ log.exception(
1077
+ f"{log_identifier} Unexpected error in edit_image_with_gemini: {e}"
1078
+ )
1079
+ return {"status": "error", "message": f"An unexpected error occurred: {e}"}
1080
+
1081
+
1082
+ create_image_from_description_tool_def = BuiltinTool(
1083
+ name="create_image_from_description",
1084
+ implementation=create_image_from_description,
1085
+ description="Generates an image based on a textual description using a configured image generation model (e.g., via LiteLLM) and saves it as a PNG artifact.",
1086
+ category="image",
1087
+ required_scopes=["tool:image:create"],
1088
+ parameters=adk_types.Schema(
1089
+ type=adk_types.Type.OBJECT,
1090
+ properties={
1091
+ "image_description": adk_types.Schema(
1092
+ type=adk_types.Type.STRING,
1093
+ description="The textual prompt to use for image generation.",
1094
+ ),
1095
+ "output_filename": adk_types.Schema(
1096
+ type=adk_types.Type.STRING,
1097
+ description="Optional. The desired filename for the output PNG image.",
1098
+ nullable=True,
1099
+ ),
1100
+ },
1101
+ required=["image_description"],
1102
+ ),
1103
+ examples=[],
1104
+ )
1105
+
1106
+ describe_image_tool_def = BuiltinTool(
1107
+ name="describe_image",
1108
+ implementation=describe_image,
1109
+ description="Describes an image using an OpenAI-compatible vision API.",
1110
+ category="image",
1111
+ required_scopes=["tool:image:describe"],
1112
+ parameters=adk_types.Schema(
1113
+ type=adk_types.Type.OBJECT,
1114
+ properties={
1115
+ "image_filename": adk_types.Schema(
1116
+ type=adk_types.Type.STRING,
1117
+ description="The filename (and optional :version) of the input image artifact.",
1118
+ ),
1119
+ "prompt": adk_types.Schema(
1120
+ type=adk_types.Type.STRING,
1121
+ description="Custom prompt for image analysis.",
1122
+ nullable=True,
1123
+ ),
1124
+ },
1125
+ required=["image_filename"],
1126
+ ),
1127
+ examples=[],
1128
+ )
1129
+
1130
+ describe_audio_tool_def = BuiltinTool(
1131
+ name="describe_audio",
1132
+ implementation=describe_audio,
1133
+ description="Describes an audio recording using a multimodal API.",
1134
+ category="image",
1135
+ required_scopes=["tool:audio:describe"],
1136
+ parameters=adk_types.Schema(
1137
+ type=adk_types.Type.OBJECT,
1138
+ properties={
1139
+ "audio_filename": adk_types.Schema(
1140
+ type=adk_types.Type.STRING,
1141
+ description="The filename (and optional :version) of the input audio artifact.",
1142
+ ),
1143
+ "prompt": adk_types.Schema(
1144
+ type=adk_types.Type.STRING,
1145
+ description="Custom prompt for audio analysis.",
1146
+ nullable=True,
1147
+ ),
1148
+ },
1149
+ required=["audio_filename"],
1150
+ ),
1151
+ examples=[],
1152
+ )
1153
+
1154
+ edit_image_with_gemini_tool_def = BuiltinTool(
1155
+ name="edit_image_with_gemini",
1156
+ implementation=edit_image_with_gemini,
1157
+ description="Edits an existing image based on a text prompt using Google's Gemini 2.0 Flash Preview Image Generation model.",
1158
+ category="image",
1159
+ required_scopes=["tool:image:edit"],
1160
+ parameters=adk_types.Schema(
1161
+ type=adk_types.Type.OBJECT,
1162
+ properties={
1163
+ "image_filename": adk_types.Schema(
1164
+ type=adk_types.Type.STRING,
1165
+ description="The filename (and optional :version) of the input image artifact.",
1166
+ ),
1167
+ "edit_prompt": adk_types.Schema(
1168
+ type=adk_types.Type.STRING,
1169
+ description="Text description of the desired edits to apply to the image.",
1170
+ ),
1171
+ "output_filename": adk_types.Schema(
1172
+ type=adk_types.Type.STRING,
1173
+ description="Optional. The desired filename for the output edited image.",
1174
+ nullable=True,
1175
+ ),
1176
+ },
1177
+ required=["image_filename", "edit_prompt"],
1178
+ ),
1179
+ examples=[],
1180
+ )
1181
+
1182
+ tool_registry.register(create_image_from_description_tool_def)
1183
+ tool_registry.register(describe_image_tool_def)
1184
+ tool_registry.register(describe_audio_tool_def)
1185
+ tool_registry.register(edit_image_with_gemini_tool_def)