solace-agent-mesh 1.6.1__py3-none-any.whl → 1.13.2__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (481) hide show
  1. solace_agent_mesh/agent/adk/alembic/README +74 -0
  2. solace_agent_mesh/agent/adk/alembic/env.py +77 -0
  3. solace_agent_mesh/agent/adk/alembic/script.py.mako +28 -0
  4. solace_agent_mesh/agent/adk/alembic/versions/e2902798564d_adk_session_db_upgrade.py +52 -0
  5. solace_agent_mesh/agent/adk/alembic.ini +112 -0
  6. solace_agent_mesh/agent/adk/app_llm_agent.py +26 -0
  7. solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +165 -1
  8. solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +163 -0
  9. solace_agent_mesh/agent/adk/callbacks.py +852 -109
  10. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +234 -36
  11. solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +52 -5
  12. solace_agent_mesh/agent/adk/mcp_content_processor.py +1 -1
  13. solace_agent_mesh/agent/adk/models/lite_llm.py +77 -21
  14. solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +24 -137
  15. solace_agent_mesh/agent/adk/runner.py +85 -20
  16. solace_agent_mesh/agent/adk/schema_migration.py +88 -0
  17. solace_agent_mesh/agent/adk/services.py +94 -18
  18. solace_agent_mesh/agent/adk/setup.py +281 -65
  19. solace_agent_mesh/agent/adk/stream_parser.py +231 -37
  20. solace_agent_mesh/agent/adk/tool_wrapper.py +3 -0
  21. solace_agent_mesh/agent/protocol/event_handlers.py +472 -137
  22. solace_agent_mesh/agent/proxies/a2a/app.py +3 -2
  23. solace_agent_mesh/agent/proxies/a2a/component.py +572 -75
  24. solace_agent_mesh/agent/proxies/a2a/config.py +80 -4
  25. solace_agent_mesh/agent/proxies/base/app.py +3 -2
  26. solace_agent_mesh/agent/proxies/base/component.py +188 -22
  27. solace_agent_mesh/agent/proxies/base/proxy_task_context.py +3 -1
  28. solace_agent_mesh/agent/sac/app.py +91 -3
  29. solace_agent_mesh/agent/sac/component.py +591 -157
  30. solace_agent_mesh/agent/sac/patch_adk.py +8 -16
  31. solace_agent_mesh/agent/sac/task_execution_context.py +146 -4
  32. solace_agent_mesh/agent/tools/__init__.py +3 -0
  33. solace_agent_mesh/agent/tools/audio_tools.py +3 -3
  34. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +710 -171
  35. solace_agent_mesh/agent/tools/deep_research_tools.py +2161 -0
  36. solace_agent_mesh/agent/tools/dynamic_tool.py +2 -0
  37. solace_agent_mesh/agent/tools/peer_agent_tool.py +82 -15
  38. solace_agent_mesh/agent/tools/time_tools.py +126 -0
  39. solace_agent_mesh/agent/tools/tool_config_types.py +57 -2
  40. solace_agent_mesh/agent/tools/web_search_tools.py +279 -0
  41. solace_agent_mesh/agent/tools/web_tools.py +125 -17
  42. solace_agent_mesh/agent/utils/artifact_helpers.py +248 -6
  43. solace_agent_mesh/agent/utils/context_helpers.py +17 -0
  44. solace_agent_mesh/assets/docs/404.html +6 -6
  45. solace_agent_mesh/assets/docs/assets/css/{styles.906a1503.css → styles.8162edfb.css} +1 -1
  46. solace_agent_mesh/assets/docs/assets/js/05749d90.19ac4f35.js +1 -0
  47. solace_agent_mesh/assets/docs/assets/js/15ba94aa.e186750d.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/15e40e79.434bb30f.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/17896441.e612dfb4.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js +2 -0
  51. solace_agent_mesh/assets/docs/assets/js/{17896441.a5e82f9b.js.LICENSE.txt → 2279.550aa580.js.LICENSE.txt} +6 -0
  52. solace_agent_mesh/assets/docs/assets/js/240a0364.83e37aa8.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/2987107d.a80604f9.js +1 -0
  54. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.2f0db237.js +1 -0
  55. solace_agent_mesh/assets/docs/assets/js/3a6c6137.7e61915d.js +1 -0
  56. solace_agent_mesh/assets/docs/assets/js/3ac1795d.7f7ab1c1.js +1 -0
  57. solace_agent_mesh/assets/docs/assets/js/3ff0015d.e53c9b78.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/41adc471.0e95b87c.js +1 -0
  59. solace_agent_mesh/assets/docs/assets/js/4667dc50.bf2ad456.js +1 -0
  60. solace_agent_mesh/assets/docs/assets/js/49eed117.493d6f99.js +1 -0
  61. solace_agent_mesh/assets/docs/assets/js/{509e993c.4c7a1a6d.js → 509e993c.a1fbf45a.js} +1 -1
  62. solace_agent_mesh/assets/docs/assets/js/547e15cc.8e6da617.js +1 -0
  63. solace_agent_mesh/assets/docs/assets/js/55b7b518.29d6e75d.js +1 -0
  64. solace_agent_mesh/assets/docs/assets/js/5b8d9c11.d4eb37b8.js +1 -0
  65. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.1ee87753.js +1 -0
  66. solace_agent_mesh/assets/docs/assets/js/60702c0e.a8bdd79b.js +1 -0
  67. solace_agent_mesh/assets/docs/assets/js/631738c7.fa471607.js +1 -0
  68. solace_agent_mesh/assets/docs/assets/js/64195356.09dbd087.js +1 -0
  69. solace_agent_mesh/assets/docs/assets/js/66d4869e.30340bd3.js +1 -0
  70. solace_agent_mesh/assets/docs/assets/js/6a520c9d.b6e3f2ce.js +1 -0
  71. solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
  72. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
  73. solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
  74. solace_agent_mesh/assets/docs/assets/js/71da7b71.374b9d54.js +1 -0
  75. solace_agent_mesh/assets/docs/assets/js/729898df.7249e9fd.js +1 -0
  76. solace_agent_mesh/assets/docs/assets/js/7e294c01.7c5f6906.js +1 -0
  77. solace_agent_mesh/assets/docs/assets/js/8024126c.e3467286.js +1 -0
  78. solace_agent_mesh/assets/docs/assets/js/81a99df0.7ed65d45.js +1 -0
  79. solace_agent_mesh/assets/docs/assets/js/82fbfb93.161823a5.js +1 -0
  80. solace_agent_mesh/assets/docs/assets/js/8b032486.91a91afc.js +1 -0
  81. solace_agent_mesh/assets/docs/assets/js/924ffdeb.975e428a.js +1 -0
  82. solace_agent_mesh/assets/docs/assets/js/94e8668d.16083b3f.js +1 -0
  83. solace_agent_mesh/assets/docs/assets/js/9bb13469.4523ae20.js +1 -0
  84. solace_agent_mesh/assets/docs/assets/js/a7d42657.a956689d.js +1 -0
  85. solace_agent_mesh/assets/docs/assets/js/a94703ab.3e5fbcb3.js +1 -0
  86. solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e563275.js +1 -0
  87. solace_agent_mesh/assets/docs/assets/js/ad87452a.9d73dad6.js +1 -0
  88. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.0e0d8baf.js +1 -0
  89. solace_agent_mesh/assets/docs/assets/js/cab03b5b.6a073091.js +1 -0
  90. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.07e170dd.js +1 -0
  91. solace_agent_mesh/assets/docs/assets/js/da0b5bad.b62f7b08.js +1 -0
  92. solace_agent_mesh/assets/docs/assets/js/dd817ffc.c37a755e.js +1 -0
  93. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
  94. solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.js +1 -0
  95. solace_agent_mesh/assets/docs/assets/js/e04b235d.06d23db6.js +1 -0
  96. solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.deb2b62e.js +1 -0
  97. solace_agent_mesh/assets/docs/assets/js/e3d9abda.1476f570.js +1 -0
  98. solace_agent_mesh/assets/docs/assets/js/e6f9706b.acc800d3.js +1 -0
  99. solace_agent_mesh/assets/docs/assets/js/e92d0134.c147a429.js +1 -0
  100. solace_agent_mesh/assets/docs/assets/js/ee0c2fe7.94d0a351.js +1 -0
  101. solace_agent_mesh/assets/docs/assets/js/f284c35a.cc97854c.js +1 -0
  102. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.74710fc1.js +1 -0
  103. solace_agent_mesh/assets/docs/assets/js/main.d634009f.js +2 -0
  104. solace_agent_mesh/assets/docs/assets/js/runtime~main.27bb82a7.js +1 -0
  105. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +68 -68
  106. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +50 -50
  107. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +42 -42
  108. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +55 -55
  109. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +82 -68
  110. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/image-tools/index.html +81 -0
  111. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +67 -50
  112. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/research-tools/index.html +136 -0
  113. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +178 -144
  114. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +43 -42
  115. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +20 -18
  116. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +23 -23
  117. solace_agent_mesh/assets/docs/docs/documentation/components/platform-service/index.html +33 -0
  118. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +45 -45
  119. solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +182 -0
  120. solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +147 -0
  121. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +208 -125
  122. solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +52 -0
  123. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +28 -49
  124. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +29 -30
  125. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +14 -14
  126. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/index.html +47 -0
  127. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/kubernetes-deployment-guide/index.html +197 -0
  128. solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +90 -0
  129. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +17 -16
  130. solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +49 -0
  131. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +38 -38
  132. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +162 -171
  133. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +67 -49
  134. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +17 -17
  135. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +51 -51
  136. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +22 -22
  137. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +27 -27
  138. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +135 -135
  139. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +66 -66
  140. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +51 -51
  141. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +50 -38
  142. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +86 -86
  143. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +51 -51
  144. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +24 -24
  145. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +30 -30
  146. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +44 -44
  147. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +115 -0
  148. solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +86 -0
  149. solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +67 -0
  150. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +23 -19
  151. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +40 -37
  152. solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +324 -0
  153. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +112 -87
  154. solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
  155. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +87 -64
  156. solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +62 -0
  157. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +44 -44
  158. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +39 -37
  159. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +30 -30
  160. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +18 -18
  161. solace_agent_mesh/assets/docs/docs/documentation/getting-started/vibe_coding/index.html +62 -0
  162. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +311 -0
  163. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +39 -42
  164. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +14 -14
  165. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +27 -25
  166. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +69 -69
  167. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +72 -72
  168. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +251 -0
  169. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +88 -0
  170. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +42 -42
  171. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +20 -20
  172. solace_agent_mesh/assets/docs/docs/documentation/migrations/platform-service-split/index.html +85 -0
  173. solace_agent_mesh/assets/docs/lunr-index-1768329217460.json +1 -0
  174. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  175. solace_agent_mesh/assets/docs/search-doc-1768329217460.json +1 -0
  176. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  177. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  178. solace_agent_mesh/cli/__init__.py +1 -1
  179. solace_agent_mesh/cli/commands/add_cmd/__init__.py +3 -1
  180. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +6 -1
  181. solace_agent_mesh/cli/commands/add_cmd/proxy_cmd.py +100 -0
  182. solace_agent_mesh/cli/commands/docs_cmd.py +4 -1
  183. solace_agent_mesh/cli/commands/eval_cmd.py +1 -1
  184. solace_agent_mesh/cli/commands/init_cmd/__init__.py +15 -0
  185. solace_agent_mesh/cli/commands/init_cmd/directory_step.py +1 -1
  186. solace_agent_mesh/cli/commands/init_cmd/env_step.py +30 -3
  187. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +3 -4
  188. solace_agent_mesh/cli/commands/init_cmd/platform_service_step.py +85 -0
  189. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +16 -3
  190. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +2 -1
  191. solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +1 -0
  192. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +3 -3
  193. solace_agent_mesh/cli/commands/run_cmd.py +64 -49
  194. solace_agent_mesh/cli/commands/tools_cmd.py +315 -0
  195. solace_agent_mesh/cli/main.py +15 -0
  196. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-BTf6dqwp.js → authCallback-KnKMP_vb.js} +1 -1
  197. solace_agent_mesh/client/webui/frontend/static/assets/client-DpBL2stg.js +25 -0
  198. solace_agent_mesh/client/webui/frontend/static/assets/main-Cd498TV2.js +435 -0
  199. solace_agent_mesh/client/webui/frontend/static/assets/main-rSf8Vu29.css +1 -0
  200. solace_agent_mesh/client/webui/frontend/static/assets/vendor-CGk8Suyh.js +565 -0
  201. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  202. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  203. solace_agent_mesh/client/webui/frontend/static/mockServiceWorker.js +336 -0
  204. solace_agent_mesh/client/webui/frontend/static/ui-version.json +6 -0
  205. solace_agent_mesh/common/a2a/events.py +2 -1
  206. solace_agent_mesh/common/a2a/protocol.py +5 -0
  207. solace_agent_mesh/common/a2a/types.py +2 -1
  208. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +23 -6
  209. solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
  210. solace_agent_mesh/common/agent_registry.py +38 -11
  211. solace_agent_mesh/common/data_parts.py +144 -4
  212. solace_agent_mesh/common/error_handlers.py +83 -0
  213. solace_agent_mesh/common/exceptions.py +24 -0
  214. solace_agent_mesh/common/oauth/__init__.py +17 -0
  215. solace_agent_mesh/common/oauth/oauth_client.py +408 -0
  216. solace_agent_mesh/common/oauth/utils.py +50 -0
  217. solace_agent_mesh/common/rag_dto.py +156 -0
  218. solace_agent_mesh/common/sac/sam_component_base.py +97 -19
  219. solace_agent_mesh/common/sam_events/event_service.py +2 -2
  220. solace_agent_mesh/common/services/employee_service.py +1 -1
  221. solace_agent_mesh/common/utils/embeds/constants.py +1 -0
  222. solace_agent_mesh/common/utils/embeds/converter.py +1 -8
  223. solace_agent_mesh/common/utils/embeds/modifiers.py +4 -28
  224. solace_agent_mesh/common/utils/embeds/resolver.py +152 -31
  225. solace_agent_mesh/common/utils/embeds/types.py +9 -0
  226. solace_agent_mesh/common/utils/log_formatters.py +20 -0
  227. solace_agent_mesh/common/utils/mime_helpers.py +12 -5
  228. solace_agent_mesh/common/utils/pydantic_utils.py +90 -3
  229. solace_agent_mesh/common/utils/rbac_utils.py +69 -0
  230. solace_agent_mesh/common/utils/templates/__init__.py +8 -0
  231. solace_agent_mesh/common/utils/templates/liquid_renderer.py +210 -0
  232. solace_agent_mesh/common/utils/templates/template_resolver.py +161 -0
  233. solace_agent_mesh/config_portal/backend/common.py +12 -0
  234. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-CljP4_mv.js +103 -0
  235. solace_agent_mesh/config_portal/frontend/static/client/assets/{components-Rk0n-9cK.js → components-CaC6hG8d.js} +22 -22
  236. solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-mvZjNKiz.js → entry.client-H_TM0YBt.js} +3 -3
  237. solace_agent_mesh/config_portal/frontend/static/client/assets/{index-DzNKzXrc.js → index-CnFykb2v.js} +16 -16
  238. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-f8439d40.js +1 -0
  239. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BIMqslJB.css +1 -0
  240. solace_agent_mesh/config_portal/frontend/static/client/assets/root-mJmTIdIk.js +10 -0
  241. solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
  242. solace_agent_mesh/core_a2a/service.py +3 -2
  243. solace_agent_mesh/gateway/adapter/__init__.py +1 -0
  244. solace_agent_mesh/gateway/adapter/base.py +170 -0
  245. solace_agent_mesh/gateway/adapter/types.py +230 -0
  246. solace_agent_mesh/gateway/base/app.py +39 -2
  247. solace_agent_mesh/gateway/base/auth_interface.py +103 -0
  248. solace_agent_mesh/gateway/base/component.py +1027 -151
  249. solace_agent_mesh/gateway/generic/__init__.py +1 -0
  250. solace_agent_mesh/gateway/generic/app.py +50 -0
  251. solace_agent_mesh/gateway/generic/component.py +894 -0
  252. solace_agent_mesh/gateway/http_sse/alembic/env.py +0 -7
  253. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_project_users_table.py +72 -0
  254. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +109 -0
  255. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +26 -0
  256. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_projects_table.py +135 -0
  257. solace_agent_mesh/gateway/http_sse/alembic/versions/20251108_create_prompt_tables_with_sharing.py +154 -0
  258. solace_agent_mesh/gateway/http_sse/alembic/versions/20251115_add_parent_task_id.py +32 -0
  259. solace_agent_mesh/gateway/http_sse/alembic/versions/20251126_add_background_task_fields.py +47 -0
  260. solace_agent_mesh/gateway/http_sse/alembic/versions/20251202_add_versioned_fields_to_prompts.py +52 -0
  261. solace_agent_mesh/gateway/http_sse/alembic.ini +0 -36
  262. solace_agent_mesh/gateway/http_sse/app.py +40 -11
  263. solace_agent_mesh/gateway/http_sse/component.py +285 -160
  264. solace_agent_mesh/gateway/http_sse/dependencies.py +149 -114
  265. solace_agent_mesh/gateway/http_sse/main.py +68 -450
  266. solace_agent_mesh/gateway/http_sse/repository/__init__.py +19 -1
  267. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +2 -2
  268. solace_agent_mesh/gateway/http_sse/repository/entities/project.py +81 -0
  269. solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +47 -0
  270. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +26 -3
  271. solace_agent_mesh/gateway/http_sse/repository/entities/task.py +7 -0
  272. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +47 -0
  273. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +114 -6
  274. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +13 -0
  275. solace_agent_mesh/gateway/http_sse/repository/models/project_model.py +51 -0
  276. solace_agent_mesh/gateway/http_sse/repository/models/project_user_model.py +75 -0
  277. solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +159 -0
  278. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +8 -2
  279. solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +8 -1
  280. solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
  281. solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
  282. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +177 -11
  283. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +86 -2
  284. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +38 -7
  285. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +256 -58
  286. solace_agent_mesh/gateway/http_sse/routers/auth.py +168 -134
  287. solace_agent_mesh/gateway/http_sse/routers/config.py +302 -8
  288. solace_agent_mesh/gateway/http_sse/routers/dto/project_dto.py +69 -0
  289. solace_agent_mesh/gateway/http_sse/routers/dto/prompt_dto.py +255 -0
  290. solace_agent_mesh/gateway/http_sse/routers/dto/requests/project_requests.py +48 -0
  291. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +14 -1
  292. solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +1 -1
  293. solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +31 -0
  294. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +5 -2
  295. solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
  296. solace_agent_mesh/gateway/http_sse/routers/feedback.py +133 -2
  297. solace_agent_mesh/gateway/http_sse/routers/people.py +2 -2
  298. solace_agent_mesh/gateway/http_sse/routers/projects.py +768 -0
  299. solace_agent_mesh/gateway/http_sse/routers/prompts.py +1416 -0
  300. solace_agent_mesh/gateway/http_sse/routers/sessions.py +167 -7
  301. solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
  302. solace_agent_mesh/gateway/http_sse/routers/sse.py +131 -8
  303. solace_agent_mesh/gateway/http_sse/routers/tasks.py +670 -18
  304. solace_agent_mesh/gateway/http_sse/routers/users.py +1 -1
  305. solace_agent_mesh/gateway/http_sse/routers/version.py +343 -0
  306. solace_agent_mesh/gateway/http_sse/routers/visualization.py +92 -9
  307. solace_agent_mesh/gateway/http_sse/services/audio_service.py +1227 -0
  308. solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +186 -0
  309. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +1 -1
  310. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +1 -1
  311. solace_agent_mesh/gateway/http_sse/services/project_service.py +930 -0
  312. solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
  313. solace_agent_mesh/gateway/http_sse/services/session_service.py +361 -12
  314. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +354 -4
  315. solace_agent_mesh/gateway/http_sse/session_manager.py +15 -15
  316. solace_agent_mesh/gateway/http_sse/sse_manager.py +286 -166
  317. solace_agent_mesh/gateway/http_sse/utils/artifact_copy_utils.py +370 -0
  318. solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +41 -1
  319. solace_agent_mesh/services/__init__.py +0 -0
  320. solace_agent_mesh/services/platform/__init__.py +29 -0
  321. solace_agent_mesh/services/platform/alembic/env.py +85 -0
  322. solace_agent_mesh/services/platform/alembic/script.py.mako +28 -0
  323. solace_agent_mesh/services/platform/alembic.ini +109 -0
  324. solace_agent_mesh/services/platform/api/__init__.py +3 -0
  325. solace_agent_mesh/services/platform/api/dependencies.py +154 -0
  326. solace_agent_mesh/services/platform/api/main.py +314 -0
  327. solace_agent_mesh/services/platform/api/middleware.py +51 -0
  328. solace_agent_mesh/services/platform/api/routers/__init__.py +33 -0
  329. solace_agent_mesh/services/platform/api/routers/health_router.py +31 -0
  330. solace_agent_mesh/services/platform/app.py +215 -0
  331. solace_agent_mesh/services/platform/component.py +777 -0
  332. solace_agent_mesh/shared/__init__.py +14 -0
  333. solace_agent_mesh/shared/api/__init__.py +42 -0
  334. solace_agent_mesh/shared/auth/__init__.py +26 -0
  335. solace_agent_mesh/shared/auth/dependencies.py +204 -0
  336. solace_agent_mesh/shared/auth/middleware.py +347 -0
  337. solace_agent_mesh/shared/database/__init__.py +20 -0
  338. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/base_repository.py +1 -1
  339. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_exceptions.py +1 -1
  340. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_helpers.py +1 -1
  341. solace_agent_mesh/shared/exceptions/__init__.py +36 -0
  342. solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exception_handlers.py +19 -5
  343. solace_agent_mesh/shared/utils/__init__.py +21 -0
  344. solace_agent_mesh/templates/logging_config_template.yaml +48 -0
  345. solace_agent_mesh/templates/main_orchestrator.yaml +12 -1
  346. solace_agent_mesh/templates/platform.yaml +49 -0
  347. solace_agent_mesh/templates/plugin_readme_template.md +3 -25
  348. solace_agent_mesh/templates/plugin_tool_config_template.yaml +109 -0
  349. solace_agent_mesh/templates/proxy_template.yaml +62 -0
  350. solace_agent_mesh/templates/webui.yaml +148 -6
  351. solace_agent_mesh/tools/web_search/__init__.py +18 -0
  352. solace_agent_mesh/tools/web_search/base.py +84 -0
  353. solace_agent_mesh/tools/web_search/google_search.py +247 -0
  354. solace_agent_mesh/tools/web_search/models.py +99 -0
  355. {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/METADATA +31 -12
  356. solace_agent_mesh-1.13.2.dist-info/RECORD +591 -0
  357. {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/WHEEL +1 -1
  358. solace_agent_mesh/agent/adk/adk_llm.txt +0 -232
  359. solace_agent_mesh/agent/adk/adk_llm_detail.txt +0 -566
  360. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +0 -171
  361. solace_agent_mesh/agent/adk/models/models_llm.txt +0 -142
  362. solace_agent_mesh/agent/agent_llm.txt +0 -378
  363. solace_agent_mesh/agent/agent_llm_detail.txt +0 -1702
  364. solace_agent_mesh/agent/protocol/protocol_llm.txt +0 -81
  365. solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +0 -92
  366. solace_agent_mesh/agent/sac/sac_llm.txt +0 -189
  367. solace_agent_mesh/agent/sac/sac_llm_detail.txt +0 -200
  368. solace_agent_mesh/agent/testing/testing_llm.txt +0 -57
  369. solace_agent_mesh/agent/testing/testing_llm_detail.txt +0 -68
  370. solace_agent_mesh/agent/tools/tools_llm.txt +0 -263
  371. solace_agent_mesh/agent/tools/tools_llm_detail.txt +0 -274
  372. solace_agent_mesh/agent/utils/utils_llm.txt +0 -138
  373. solace_agent_mesh/agent/utils/utils_llm_detail.txt +0 -149
  374. solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +0 -1
  375. solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +0 -2
  376. solace_agent_mesh/assets/docs/assets/js/240a0364.7eac6021.js +0 -1
  377. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +0 -1
  378. solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +0 -1
  379. solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +0 -1
  380. solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +0 -1
  381. solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +0 -1
  382. solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +0 -1
  383. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +0 -1
  384. solace_agent_mesh/assets/docs/assets/js/631738c7.a8b1ef8b.js +0 -1
  385. solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +0 -1
  386. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +0 -1
  387. solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +0 -1
  388. solace_agent_mesh/assets/docs/assets/js/71da7b71.38583438.js +0 -1
  389. solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.js +0 -1
  390. solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +0 -1
  391. solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +0 -1
  392. solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +0 -1
  393. solace_agent_mesh/assets/docs/assets/js/94e8668d.b5ddb7a1.js +0 -1
  394. solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +0 -1
  395. solace_agent_mesh/assets/docs/assets/js/a94703ab.0438dbc2.js +0 -1
  396. solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e6dd091.js +0 -1
  397. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +0 -1
  398. solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +0 -1
  399. solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +0 -1
  400. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +0 -1
  401. solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +0 -1
  402. solace_agent_mesh/assets/docs/assets/js/e3d9abda.6b9493d0.js +0 -1
  403. solace_agent_mesh/assets/docs/assets/js/e6f9706b.e74a984d.js +0 -1
  404. solace_agent_mesh/assets/docs/assets/js/e92d0134.cf6d6522.js +0 -1
  405. solace_agent_mesh/assets/docs/assets/js/f284c35a.42f59cdd.js +0 -1
  406. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +0 -1
  407. solace_agent_mesh/assets/docs/assets/js/main.b12eac43.js +0 -2
  408. solace_agent_mesh/assets/docs/assets/js/runtime~main.e268214e.js +0 -1
  409. solace_agent_mesh/assets/docs/lunr-index-1761248203150.json +0 -1
  410. solace_agent_mesh/assets/docs/search-doc-1761248203150.json +0 -1
  411. solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +0 -250
  412. solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +0 -365
  413. solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +0 -305
  414. solace_agent_mesh/client/webui/frontend/static/assets/client-CaY59VuC.js +0 -25
  415. solace_agent_mesh/client/webui/frontend/static/assets/main-B32noGmR.js +0 -342
  416. solace_agent_mesh/client/webui/frontend/static/assets/main-DHJKSW1S.css +0 -1
  417. solace_agent_mesh/client/webui/frontend/static/assets/vendor-BEmvJSYz.js +0 -405
  418. solace_agent_mesh/common/a2a/a2a_llm.txt +0 -182
  419. solace_agent_mesh/common/a2a/a2a_llm_detail.txt +0 -193
  420. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +0 -407
  421. solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +0 -736
  422. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +0 -313
  423. solace_agent_mesh/common/common_llm.txt +0 -251
  424. solace_agent_mesh/common/common_llm_detail.txt +0 -2562
  425. solace_agent_mesh/common/middleware/middleware_llm.txt +0 -174
  426. solace_agent_mesh/common/middleware/middleware_llm_detail.txt +0 -185
  427. solace_agent_mesh/common/sac/sac_llm.txt +0 -71
  428. solace_agent_mesh/common/sac/sac_llm_detail.txt +0 -82
  429. solace_agent_mesh/common/sam_events/sam_events_llm.txt +0 -104
  430. solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +0 -115
  431. solace_agent_mesh/common/services/providers/providers_llm.txt +0 -80
  432. solace_agent_mesh/common/services/services_llm.txt +0 -363
  433. solace_agent_mesh/common/services/services_llm_detail.txt +0 -459
  434. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +0 -220
  435. solace_agent_mesh/common/utils/utils_llm.txt +0 -336
  436. solace_agent_mesh/common/utils/utils_llm_detail.txt +0 -572
  437. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +0 -98
  438. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-61038fc6.js +0 -1
  439. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BWvk5-gF.js +0 -10
  440. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DxRwaWiE.css +0 -1
  441. solace_agent_mesh/core_a2a/core_a2a_llm.txt +0 -90
  442. solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +0 -101
  443. solace_agent_mesh/gateway/base/base_llm.txt +0 -224
  444. solace_agent_mesh/gateway/base/base_llm_detail.txt +0 -235
  445. solace_agent_mesh/gateway/gateway_llm.txt +0 -373
  446. solace_agent_mesh/gateway/gateway_llm_detail.txt +0 -3885
  447. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +0 -295
  448. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +0 -155
  449. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +0 -105
  450. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +0 -299
  451. solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +0 -3278
  452. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +0 -263
  453. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +0 -266
  454. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +0 -340
  455. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +0 -346
  456. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +0 -83
  457. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +0 -107
  458. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +0 -314
  459. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +0 -297
  460. solace_agent_mesh/gateway/http_sse/shared/__init__.py +0 -146
  461. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +0 -285
  462. solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +0 -47
  463. solace_agent_mesh/llm.txt +0 -228
  464. solace_agent_mesh/llm_detail.txt +0 -2835
  465. solace_agent_mesh/solace_agent_mesh_llm.txt +0 -362
  466. solace_agent_mesh/solace_agent_mesh_llm_detail.txt +0 -8599
  467. solace_agent_mesh/templates/logging_config_template.ini +0 -45
  468. solace_agent_mesh/templates/templates_llm.txt +0 -147
  469. solace_agent_mesh-1.6.1.dist-info/RECORD +0 -525
  470. /solace_agent_mesh/assets/docs/assets/js/{main.b12eac43.js.LICENSE.txt → main.d634009f.js.LICENSE.txt} +0 -0
  471. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/auth_utils.py +0 -0
  472. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/pagination.py +0 -0
  473. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/response_utils.py +0 -0
  474. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/error_dto.py +0 -0
  475. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exceptions.py +0 -0
  476. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/enums.py +0 -0
  477. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/timestamp_utils.py +0 -0
  478. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/types.py +0 -0
  479. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/utils.py +0 -0
  480. {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/entry_points.txt +0 -0
  481. {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/licenses/LICENSE +0 -0
@@ -2,6 +2,7 @@
2
2
  Collection of Python tools for web-related tasks, such as making HTTP requests.
3
3
  """
4
4
 
5
+ import asyncio
5
6
  import logging
6
7
  import json
7
8
  import uuid
@@ -32,6 +33,10 @@ log = logging.getLogger(__name__)
32
33
  CATEGORY_NAME = "Web Access"
33
34
  CATEGORY_DESCRIPTION = "Access the web to find information to complete user requests."
34
35
 
36
+ # Response size limits (in bytes)
37
+ DEFAULT_MAX_RESPONSE_SIZE = 10 * 1024 * 1024 # 10 MB default
38
+ ABSOLUTE_MAX_RESPONSE_SIZE = 50 * 1024 * 1024 # 50 MB hard cap (cannot be exceeded even via config)
39
+
35
40
  def _is_safe_url(url: str) -> bool:
36
41
  """
37
42
  Checks if a URL is safe to request by resolving its hostname and checking
@@ -70,9 +75,10 @@ async def web_request(
70
75
  output_artifact_filename: Optional[str] = None,
71
76
  tool_context: ToolContext = None,
72
77
  tool_config: Optional[Dict[str, Any]] = None,
78
+ max_retries: int = 2,
73
79
  ) -> Dict[str, Any]:
74
80
  """
75
- Makes an HTTP request to the specified URL, processes the content (e.g., HTML to Markdown),
81
+ Makes an HTTP request to the specified URL with retry logic, processes the content (e.g., HTML to Markdown),
76
82
  and saves the result as an artifact.
77
83
 
78
84
  Args:
@@ -82,7 +88,10 @@ async def web_request(
82
88
  body: Optional request body string for methods like POST/PUT. If sending JSON, this should be a valid JSON string.
83
89
  output_artifact_filename: Optional. Desired filename for the output artifact.
84
90
  tool_context: The context provided by the ADK framework.
85
- tool_config: Optional. Configuration passed by the ADK, generally not used by this simplified tool.
91
+ tool_config: Optional. Configuration passed by the ADK. Supports:
92
+ - allow_loopback: bool - Allow requests to loopback addresses (for testing)
93
+ - max_response_size_bytes: int - Maximum response size in bytes (default: 10MB, max: 50MB)
94
+ max_retries: Maximum number of retry attempts for failed requests. Defaults to 2.
86
95
 
87
96
  Returns:
88
97
  A dictionary with status, message, and artifact details if successful.
@@ -94,8 +103,15 @@ async def web_request(
94
103
 
95
104
  # Check if loopback URLs are allowed (for testing)
96
105
  allow_loopback = False
106
+ max_response_size = DEFAULT_MAX_RESPONSE_SIZE
107
+
97
108
  if tool_config:
98
109
  allow_loopback = tool_config.get("allow_loopback", False)
110
+ # Get max response size from config, but enforce hard cap
111
+ configured_size = tool_config.get("max_response_size_bytes")
112
+ if configured_size is not None:
113
+ max_response_size = min(int(configured_size), ABSOLUTE_MAX_RESPONSE_SIZE)
114
+ log.debug(f"{log_identifier} Using configured max_response_size: {max_response_size} bytes")
99
115
 
100
116
  if not allow_loopback and not _is_safe_url(url):
101
117
  log.error(f"{log_identifier} URL is not safe to request: {url}")
@@ -140,19 +156,108 @@ async def web_request(
140
156
  if body:
141
157
  request_body_bytes = body.encode("utf-8")
142
158
 
143
- async with httpx.AsyncClient(timeout=30.0) as client:
144
- log.debug(
145
- f"{log_identifier} Making {method} request to {url} with headers: {headers}"
146
- )
147
- response = await client.request(
148
- method=method.upper(),
149
- url=url,
150
- headers=headers,
151
- content=request_body_bytes,
152
- )
153
- log.debug(
154
- f"{log_identifier} Received response with status code: {response.status_code}"
155
- )
159
+ # Retry logic with exponential backoff
160
+ last_error = None
161
+ response = None
162
+ for attempt in range(1, max_retries + 1):
163
+ try:
164
+ async with httpx.AsyncClient(timeout=30.0, follow_redirects=True) as client:
165
+ log.info(
166
+ f"{log_identifier} Attempt {attempt}/{max_retries}: Making {method} request to {url}"
167
+ )
168
+
169
+ # Use streaming to check Content-Length and limit response size
170
+ async with client.stream(
171
+ method=method.upper(),
172
+ url=url,
173
+ headers=headers,
174
+ content=request_body_bytes,
175
+ ) as stream_response:
176
+ # Check Content-Length header if available
177
+ content_length = stream_response.headers.get("content-length")
178
+ if content_length:
179
+ content_length_int = int(content_length)
180
+ if content_length_int > max_response_size:
181
+ log.warning(
182
+ f"{log_identifier} Response Content-Length ({content_length_int} bytes) exceeds "
183
+ f"max_response_size ({max_response_size} bytes). Rejecting request."
184
+ )
185
+ return {
186
+ "status": "error",
187
+ "message": f"Response too large: {content_length_int} bytes exceeds limit of {max_response_size} bytes ({max_response_size // (1024*1024)} MB). "
188
+ f"Consider using a more specific URL or a different approach."
189
+ }
190
+
191
+ # Read response with size limit using streaming
192
+ chunks = []
193
+ total_size = 0
194
+ async for chunk in stream_response.aiter_bytes():
195
+ total_size += len(chunk)
196
+ if total_size > max_response_size:
197
+ log.warning(
198
+ f"{log_identifier} Response size ({total_size} bytes) exceeded "
199
+ f"max_response_size ({max_response_size} bytes) during streaming. Truncating."
200
+ )
201
+ # Keep what we have so far but stop reading
202
+ break
203
+ chunks.append(chunk)
204
+
205
+ # Create a response-like object with the data we need
206
+ class StreamedResponse:
207
+ def __init__(self, stream_resp, content_bytes):
208
+ self.status_code = stream_resp.status_code
209
+ self.headers = stream_resp.headers
210
+ self.content = content_bytes
211
+
212
+ response = StreamedResponse(stream_response, b"".join(chunks))
213
+
214
+ log.info(
215
+ f"{log_identifier} Received response with status code: {response.status_code}, "
216
+ f"size: {len(response.content)} bytes"
217
+ )
218
+
219
+ # Success - break out of retry loop
220
+ break
221
+
222
+ except (httpx.ReadTimeout, httpx.ConnectTimeout) as timeout_error:
223
+ last_error = timeout_error
224
+ log.warning(
225
+ f"{log_identifier} Attempt {attempt}/{max_retries} timed out: {timeout_error}"
226
+ )
227
+
228
+ if attempt < max_retries:
229
+ # Exponential backoff with jitter
230
+ import random
231
+ base_delay = 3.0 * (2 ** (attempt - 1)) # 3s, 6s, 12s...
232
+ jitter = random.uniform(0, 1.0)
233
+ delay = base_delay + jitter
234
+ log.info(f"{log_identifier} Waiting {delay:.1f}s before retry {attempt + 1}/{max_retries}")
235
+ await asyncio.sleep(delay)
236
+ else:
237
+ # Final attempt failed
238
+ error_message = f"Request timed out after {max_retries} attempts (30s timeout per attempt)"
239
+ log.error(f"{log_identifier} {error_message}")
240
+ return {
241
+ "status": "error",
242
+ "message": f"{error_message}. The website may be slow or blocking automated requests."
243
+ }
244
+
245
+ except httpx.RequestError as req_error:
246
+ last_error = req_error
247
+ log.warning(
248
+ f"{log_identifier} Attempt {attempt}/{max_retries} failed with request error: {req_error}"
249
+ )
250
+
251
+ if attempt < max_retries:
252
+ import random
253
+ base_delay = 3.0 * (2 ** (attempt - 1))
254
+ jitter = random.uniform(0, 1.0)
255
+ delay = base_delay + jitter
256
+ log.info(f"{log_identifier} Waiting {delay:.1f}s before retry {attempt + 1}/{max_retries}")
257
+ await asyncio.sleep(delay)
258
+ else:
259
+ # Will be handled by the outer exception handler
260
+ raise
156
261
 
157
262
  response_content_bytes = response.content
158
263
  response_status_code = response.status_code
@@ -335,9 +440,12 @@ async def web_request(
335
440
  return {"status": "error", "message": error_message}
336
441
 
337
442
  except httpx.RequestError as re:
338
- error_message = f"Request error while fetching {url}: {re}"
443
+ error_message = f"Request error while fetching {url} after {max_retries} attempts: {re}"
339
444
  log.error(f"{log_identifier} {error_message}", exc_info=True)
340
- return {"status": "error", "message": error_message}
445
+ return {
446
+ "status": "error",
447
+ "message": f"{error_message}. The website may be unreachable or blocking requests."
448
+ }
341
449
  except ValueError as ve:
342
450
  log.error(f"{log_identifier} Value error: {ve}", exc_info=True)
343
451
  return {"status": "error", "message": str(ve)}
@@ -33,6 +33,7 @@ log = logging.getLogger(__name__)
33
33
 
34
34
  METADATA_SUFFIX = ".metadata.json"
35
35
  DEFAULT_SCHEMA_MAX_KEYS = 20
36
+ DEFAULT_SCHEMA_INFERENCE_DEPTH = 4
36
37
 
37
38
 
38
39
  def is_filename_safe(filename: str) -> bool:
@@ -67,6 +68,67 @@ def is_filename_safe(filename: str) -> bool:
67
68
  return True
68
69
 
69
70
 
71
+ def sanitize_to_filename(
72
+ text: str,
73
+ max_length: int = 50,
74
+ suffix: str = "",
75
+ replacement_char: str = "_"
76
+ ) -> str:
77
+ """
78
+ Sanitizes arbitrary text into a safe filename.
79
+
80
+ Converts text (like a research question or title) into a filesystem-safe
81
+ filename by:
82
+ 1. Converting to lowercase
83
+ 2. Removing non-word characters (except spaces and hyphens)
84
+ 3. Replacing spaces and hyphens with the replacement character
85
+ 4. Limiting length to max_length
86
+ 5. Optionally appending a suffix
87
+
88
+ Args:
89
+ text: The text to convert into a filename (e.g., research question, title)
90
+ max_length: Maximum length of the base filename (before suffix). Default: 50
91
+ suffix: Optional suffix to append (e.g., "_report.md"). Default: ""
92
+ replacement_char: Character to replace spaces/hyphens with. Default: "_"
93
+
94
+ Returns:
95
+ A sanitized filename string safe for filesystem use.
96
+
97
+ Examples:
98
+ >>> sanitize_to_filename("What is AI?")
99
+ 'what_is_ai'
100
+ >>> sanitize_to_filename("Research: Deep Learning!", suffix="_report.md")
101
+ 'research_deep_learning_report.md'
102
+ >>> sanitize_to_filename("A very long research question about many topics", max_length=20)
103
+ 'a_very_long_research'
104
+ """
105
+ import re
106
+
107
+ if not text:
108
+ return f"unnamed{suffix}"
109
+
110
+ # Convert to lowercase and remove non-word characters except spaces and hyphens
111
+ safe_name = re.sub(r'[^\w\s-]', '', text.lower())
112
+
113
+ # Replace spaces and hyphens with the replacement character
114
+ safe_name = re.sub(r'[-\s]+', replacement_char, safe_name)
115
+
116
+ # Strip leading/trailing replacement chars
117
+ safe_name = safe_name.strip(replacement_char)
118
+
119
+ # Limit length
120
+ if max_length > 0:
121
+ safe_name = safe_name[:max_length]
122
+ # Strip trailing replacement char if we cut in the middle
123
+ safe_name = safe_name.rstrip(replacement_char)
124
+
125
+ # Handle empty result
126
+ if not safe_name:
127
+ safe_name = "unnamed"
128
+
129
+ return f"{safe_name}{suffix}"
130
+
131
+
70
132
  def ensure_correct_extension(filename_from_llm: str, desired_extension: str) -> str:
71
133
  """
72
134
  Ensures a filename has the correct extension, handling cases where the LLM
@@ -129,6 +191,34 @@ def parse_artifact_uri(uri: str) -> Dict[str, Any]:
129
191
  }
130
192
 
131
193
 
194
+ def _clean_metadata_for_output(metadata: Dict[str, Any]) -> Dict[str, Any]:
195
+ """
196
+ Remove null, False, and empty values from metadata to reduce token usage.
197
+ Recursively cleans nested dictionaries.
198
+
199
+ Args:
200
+ metadata: The metadata dictionary to clean
201
+
202
+ Returns:
203
+ A cleaned dictionary with unnecessary fields removed
204
+ """
205
+ cleaned = {}
206
+ for key, value in metadata.items():
207
+ # Skip None, False, and empty collections
208
+ if value is None or value is False or value == {} or value == []:
209
+ continue
210
+
211
+ # Recursively clean nested dictionaries
212
+ if isinstance(value, dict):
213
+ cleaned_nested = _clean_metadata_for_output(value)
214
+ if cleaned_nested: # Only include if not empty after cleaning
215
+ cleaned[key] = cleaned_nested
216
+ else:
217
+ cleaned[key] = value
218
+
219
+ return cleaned
220
+
221
+
132
222
  def _inspect_structure(
133
223
  data: Any, max_depth: int, max_keys: int, current_depth: int = 0
134
224
  ) -> Any:
@@ -234,15 +324,40 @@ async def save_artifact_with_metadata(
234
324
  metadata_dict: Dict[str, Any],
235
325
  timestamp: datetime,
236
326
  explicit_schema: Optional[Dict] = None,
237
- schema_inference_depth: int = 2,
327
+ schema_inference_depth: Optional[int] = None,
238
328
  schema_max_keys: int = DEFAULT_SCHEMA_MAX_KEYS,
239
329
  tool_context: Optional["ToolContext"] = None,
330
+ suppress_visualization_signal: bool = False,
240
331
  ) -> Dict[str, Any]:
241
332
  """
242
333
  Saves a data artifact and its corresponding metadata artifact using BaseArtifactService.
243
334
  """
244
335
  log_identifier = f"[ArtifactHelper:save:{filename}]"
245
336
  log.debug("%s Saving artifact and metadata (async)...", log_identifier)
337
+
338
+ # Resolve schema_inference_depth from artifact service wrapper if not provided
339
+ if schema_inference_depth is None:
340
+ # Use duck typing to check for ScopedArtifactServiceWrapper capability
341
+ # (avoids dynamic class loading issues with isinstance)
342
+ if hasattr(artifact_service, "component") and hasattr(
343
+ artifact_service.component, "get_config"
344
+ ):
345
+ schema_inference_depth = artifact_service.component.get_config(
346
+ "schema_inference_depth", DEFAULT_SCHEMA_INFERENCE_DEPTH
347
+ )
348
+ log.debug(
349
+ "%s Resolved schema_inference_depth from agent config: %d",
350
+ log_identifier,
351
+ schema_inference_depth,
352
+ )
353
+ else:
354
+ schema_inference_depth = DEFAULT_SCHEMA_INFERENCE_DEPTH
355
+ log.debug(
356
+ "%s Using default schema_inference_depth: %d",
357
+ log_identifier,
358
+ schema_inference_depth,
359
+ )
360
+
246
361
  data_version = None
247
362
  metadata_version = None
248
363
  metadata_filename = f"{filename}{METADATA_SUFFIX}"
@@ -306,6 +421,59 @@ async def save_artifact_with_metadata(
306
421
  data_version,
307
422
  )
308
423
 
424
+ # Always attempt to publish artifact saved notification for workflow visualization
425
+ # This works independently of artifact_delta and should succeed if we have
426
+ # the necessary context (host_component and a2a_context)
427
+ # Skip if suppress_visualization_signal is True (e.g., when called from fenced block callback)
428
+ if not suppress_visualization_signal:
429
+ try:
430
+ # Try to get context from tool_context if available
431
+ host_component = None
432
+ a2a_context = None
433
+ function_call_id = None
434
+
435
+ if tool_context:
436
+ try:
437
+ inv_context = tool_context._invocation_context
438
+ agent = getattr(inv_context, "agent", None)
439
+ host_component = getattr(agent, "host_component", None)
440
+ a2a_context = tool_context.state.get("a2a_context")
441
+ # Get function_call_id if this was created by a tool
442
+ # Try state first (legacy), then the ADK attribute
443
+ function_call_id = tool_context.state.get("function_call_id") or getattr(tool_context, "function_call_id", None)
444
+ except Exception as ctx_err:
445
+ log.info(
446
+ "%s Could not extract context from tool_context: %s",
447
+ log_identifier,
448
+ ctx_err,
449
+ )
450
+
451
+ # Only proceed if we have both required components
452
+ if host_component and a2a_context:
453
+ # Create ArtifactInfo object
454
+ artifact_info = ArtifactInfo(
455
+ filename=filename,
456
+ version=data_version,
457
+ mime_type=mime_type,
458
+ size=len(content_bytes),
459
+ description=metadata_dict.get("description") if metadata_dict else None,
460
+ version_count=None, # Count not available in save context
461
+ )
462
+
463
+ # Publish artifact saved notification via component method
464
+ await host_component.notify_artifact_saved(
465
+ artifact_info=artifact_info,
466
+ a2a_context=a2a_context,
467
+ function_call_id=function_call_id,
468
+ )
469
+ except Exception as signal_err:
470
+ # Don't fail artifact save if notification publishing fails
471
+ log.warning(
472
+ "%s Failed to publish artifact saved notification (non-critical): %s",
473
+ log_identifier,
474
+ signal_err,
475
+ )
476
+
309
477
  final_metadata = {
310
478
  "filename": filename,
311
479
  "mime_type": mime_type,
@@ -636,12 +804,15 @@ async def generate_artifact_metadata_summary(
636
804
  metadata.pop("filename", None)
637
805
  metadata.pop("version", None)
638
806
 
807
+ # Clean metadata to remove null/false/empty values for token efficiency
808
+ cleaned_metadata = _clean_metadata_for_output(metadata)
809
+
639
810
  TRUNCATION_LIMIT_BYTES = 1024
640
811
  TRUNCATION_MESSAGE = "\n... [truncated] ..."
641
812
 
642
813
  try:
643
814
  formatted_metadata_str = yaml.safe_dump(
644
- metadata,
815
+ cleaned_metadata,
645
816
  default_flow_style=False,
646
817
  sort_keys=False,
647
818
  allow_unicode=True,
@@ -796,6 +967,51 @@ async def get_latest_artifact_version(
796
967
  return None
797
968
 
798
969
 
970
+ async def get_artifact_counts_batch(
971
+ artifact_service: BaseArtifactService,
972
+ app_name: str,
973
+ user_id: str,
974
+ session_ids: List[str],
975
+ ) -> Dict[str, int]:
976
+ """
977
+ Get artifact counts for multiple sessions in a batch operation.
978
+
979
+ Args:
980
+ artifact_service: The artifact service instance.
981
+ app_name: The application name.
982
+ user_id: The user ID.
983
+ session_ids: List of session IDs to get counts for.
984
+
985
+ Returns:
986
+ Dict mapping session_id to artifact_count (excluding metadata files)
987
+ """
988
+ log_prefix = f"[ArtifactHelper:get_counts_batch] App={app_name}, User={user_id} -"
989
+ counts: Dict[str, int] = {}
990
+
991
+ try:
992
+ list_keys_method = getattr(artifact_service, "list_artifact_keys")
993
+
994
+ for session_id in session_ids:
995
+ try:
996
+ keys = await list_keys_method(
997
+ app_name=app_name, user_id=user_id, session_id=session_id
998
+ )
999
+ # Count only non-metadata files
1000
+ count = sum(1 for key in keys if not key.endswith(METADATA_SUFFIX))
1001
+ counts[session_id] = count
1002
+ log.debug("%s Session %s has %d artifacts", log_prefix, session_id, count)
1003
+ except Exception as e:
1004
+ log.warning("%s Failed to get count for session %s: %s", log_prefix, session_id, e)
1005
+ counts[session_id] = 0
1006
+
1007
+ except Exception as e:
1008
+ log.exception("%s Error in batch count operation: %s", log_prefix, e)
1009
+ # Return 0 for all sessions on error
1010
+ return {session_id: 0 for session_id in session_ids}
1011
+
1012
+ return counts
1013
+
1014
+
799
1015
  async def get_artifact_info_list(
800
1016
  artifact_service: BaseArtifactService,
801
1017
  app_name: str,
@@ -822,7 +1038,7 @@ async def get_artifact_info_list(
822
1038
  keys = await list_keys_method(
823
1039
  app_name=app_name, user_id=user_id, session_id=session_id
824
1040
  )
825
- log.info(
1041
+ log.debug(
826
1042
  "%s Found %d artifact keys. Fetching details...", log_prefix, len(keys)
827
1043
  )
828
1044
 
@@ -882,6 +1098,9 @@ async def get_artifact_info_list(
882
1098
  else None
883
1099
  )
884
1100
 
1101
+ # Extract source from metadata
1102
+ source = metadata.get("source")
1103
+
885
1104
  artifact_info_list.append(
886
1105
  ArtifactInfo(
887
1106
  filename=filename,
@@ -892,6 +1111,7 @@ async def get_artifact_info_list(
892
1111
  description=description,
893
1112
  version=loaded_version_num,
894
1113
  version_count=version_count,
1114
+ source=source,
895
1115
  )
896
1116
  )
897
1117
  log.debug(
@@ -939,6 +1159,7 @@ async def load_artifact_content_or_metadata(
939
1159
  load_metadata_only: bool = False,
940
1160
  return_raw_bytes: bool = False,
941
1161
  max_content_length: Optional[int] = None,
1162
+ include_line_numbers: bool = False,
942
1163
  component: Optional[Any] = None,
943
1164
  log_identifier_prefix: str = "[ArtifactHelper:load]",
944
1165
  encoding: str = "utf-8",
@@ -1125,28 +1346,49 @@ async def load_artifact_content_or_metadata(
1125
1346
  if is_text:
1126
1347
  try:
1127
1348
  content_str = data_bytes.decode(encoding, errors=error_handling)
1349
+ original_content_str = content_str # Save for line count calculation
1350
+
1351
+ # Add line numbers if requested (before truncation)
1352
+ if include_line_numbers:
1353
+ lines = content_str.split('\n')
1354
+ numbered_lines = [f"{i+1}\t{line}" for i, line in enumerate(lines)]
1355
+ content_str = '\n'.join(numbered_lines)
1356
+ log.debug(
1357
+ "%s Added line numbers to %d lines.",
1358
+ log_identifier,
1359
+ len(lines)
1360
+ )
1361
+
1128
1362
  message_to_llm = ""
1129
1363
  if len(content_str) > max_content_length:
1130
1364
  truncated_content = content_str[:max_content_length] + "..."
1131
1365
 
1366
+ # Calculate line range if line numbers are included
1367
+ line_range_msg = ""
1368
+ if include_line_numbers:
1369
+ visible_line_count = truncated_content.count('\n') + 1
1370
+ total_line_count = original_content_str.count('\n') + 1
1371
+ line_range_msg = f" Lines 1-{visible_line_count} of {total_line_count} total."
1372
+
1132
1373
  if (
1133
1374
  max_content_length
1134
1375
  < TEXT_ARTIFACT_CONTEXT_MAX_LENGTH_CAPACITY
1135
1376
  ):
1136
- message_to_llm = f"""This artifact content has been truncated to {max_content_length} characters.
1377
+ message_to_llm = f"""This artifact content has been truncated to {max_content_length} characters.{line_range_msg}
1137
1378
  The artifact is larger ({len(content_str)} characters).
1138
1379
  Please request again with larger max size up to {TEXT_ARTIFACT_CONTEXT_MAX_LENGTH_CAPACITY} for the full artifact."""
1139
1380
  else:
1140
- message_to_llm = f"""This artifact content has been truncated to {max_content_length} characters.
1381
+ message_to_llm = f"""This artifact content has been truncated to {max_content_length} characters.{line_range_msg}
1141
1382
  The artifact content met the maximum allowed size of {TEXT_ARTIFACT_CONTEXT_MAX_LENGTH_CAPACITY} characters.
1142
1383
  Please continue with this truncated content as the full artifact cannot be provided."""
1143
1384
  log.info(
1144
- "%s Loaded and decoded text artifact '%s' v%d. Returning truncated content (%d chars, limit: %d).",
1385
+ "%s Loaded and decoded text artifact '%s' v%d. Returning truncated content (%d chars, limit: %d).%s",
1145
1386
  log_identifier,
1146
1387
  filename,
1147
1388
  version_to_load,
1148
1389
  len(truncated_content),
1149
1390
  max_content_length,
1391
+ line_range_msg,
1150
1392
  )
1151
1393
  else:
1152
1394
  truncated_content = content_str
@@ -58,3 +58,20 @@ def get_original_session_id(invocation_context: Any) -> str:
58
58
  else:
59
59
  raw_session_id = invocation_context.session.id
60
60
  return raw_session_id.split(":", 1)[0] if ":" in raw_session_id else raw_session_id
61
+
62
+
63
+ def get_user_timezone(invocation_context: Any) -> str:
64
+ """
65
+ Extract the user's timezone from an invocation context.
66
+
67
+ Args:
68
+ invocation_context: The invocation context object from tool_context.
69
+ Typically accessed via `tool_context._invocation_context`.
70
+
71
+ Returns:
72
+ str: The user's timezone (e.g., "America/Toronto").
73
+ Returns "UTC" if timezone is not available in the context.
74
+ """
75
+ if hasattr(invocation_context, "user_timezone"):
76
+ return invocation_context.user_timezone or "UTC"
77
+ return "UTC"