solace-agent-mesh 1.7.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 (447) 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/artifacts/filesystem_artifact_service.py +164 -0
  7. solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +163 -0
  8. solace_agent_mesh/agent/adk/callbacks.py +752 -127
  9. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +99 -7
  10. solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +52 -5
  11. solace_agent_mesh/agent/adk/mcp_content_processor.py +1 -1
  12. solace_agent_mesh/agent/adk/models/lite_llm.py +34 -16
  13. solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +24 -137
  14. solace_agent_mesh/agent/adk/runner.py +66 -8
  15. solace_agent_mesh/agent/adk/schema_migration.py +88 -0
  16. solace_agent_mesh/agent/adk/services.py +41 -1
  17. solace_agent_mesh/agent/adk/setup.py +220 -32
  18. solace_agent_mesh/agent/adk/stream_parser.py +229 -40
  19. solace_agent_mesh/agent/protocol/event_handlers.py +219 -33
  20. solace_agent_mesh/agent/proxies/a2a/component.py +572 -75
  21. solace_agent_mesh/agent/proxies/a2a/config.py +80 -4
  22. solace_agent_mesh/agent/proxies/base/component.py +188 -22
  23. solace_agent_mesh/agent/proxies/base/proxy_task_context.py +3 -1
  24. solace_agent_mesh/agent/sac/app.py +37 -12
  25. solace_agent_mesh/agent/sac/component.py +322 -52
  26. solace_agent_mesh/agent/sac/patch_adk.py +8 -16
  27. solace_agent_mesh/agent/sac/task_execution_context.py +90 -0
  28. solace_agent_mesh/agent/tools/__init__.py +3 -0
  29. solace_agent_mesh/agent/tools/audio_tools.py +3 -3
  30. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +698 -24
  31. solace_agent_mesh/agent/tools/deep_research_tools.py +2161 -0
  32. solace_agent_mesh/agent/tools/peer_agent_tool.py +82 -15
  33. solace_agent_mesh/agent/tools/time_tools.py +126 -0
  34. solace_agent_mesh/agent/tools/tool_config_types.py +54 -2
  35. solace_agent_mesh/agent/tools/web_search_tools.py +279 -0
  36. solace_agent_mesh/agent/tools/web_tools.py +125 -17
  37. solace_agent_mesh/agent/utils/artifact_helpers.py +243 -5
  38. solace_agent_mesh/agent/utils/context_helpers.py +17 -0
  39. solace_agent_mesh/assets/docs/404.html +6 -6
  40. solace_agent_mesh/assets/docs/assets/css/{styles.906a1503.css → styles.8162edfb.css} +1 -1
  41. solace_agent_mesh/assets/docs/assets/js/05749d90.19ac4f35.js +1 -0
  42. solace_agent_mesh/assets/docs/assets/js/15ba94aa.e186750d.js +1 -0
  43. solace_agent_mesh/assets/docs/assets/js/15e40e79.434bb30f.js +1 -0
  44. solace_agent_mesh/assets/docs/assets/js/17896441.e612dfb4.js +1 -0
  45. solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js +2 -0
  46. solace_agent_mesh/assets/docs/assets/js/{17896441.a5e82f9b.js.LICENSE.txt → 2279.550aa580.js.LICENSE.txt} +6 -0
  47. solace_agent_mesh/assets/docs/assets/js/240a0364.83e37aa8.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.2f0db237.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/3a6c6137.7e61915d.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/3ac1795d.7f7ab1c1.js +1 -0
  51. solace_agent_mesh/assets/docs/assets/js/3ff0015d.e53c9b78.js +1 -0
  52. solace_agent_mesh/assets/docs/assets/js/41adc471.0e95b87c.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/4667dc50.bf2ad456.js +1 -0
  54. solace_agent_mesh/assets/docs/assets/js/49eed117.493d6f99.js +1 -0
  55. solace_agent_mesh/assets/docs/assets/js/{509e993c.4c7a1a6d.js → 509e993c.a1fbf45a.js} +1 -1
  56. solace_agent_mesh/assets/docs/assets/js/547e15cc.8e6da617.js +1 -0
  57. solace_agent_mesh/assets/docs/assets/js/55b7b518.29d6e75d.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/5b8d9c11.d4eb37b8.js +1 -0
  59. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.1ee87753.js +1 -0
  60. solace_agent_mesh/assets/docs/assets/js/60702c0e.a8bdd79b.js +1 -0
  61. solace_agent_mesh/assets/docs/assets/js/64195356.09dbd087.js +1 -0
  62. solace_agent_mesh/assets/docs/assets/js/66d4869e.30340bd3.js +1 -0
  63. solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
  64. solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
  65. solace_agent_mesh/assets/docs/assets/js/729898df.7249e9fd.js +1 -0
  66. solace_agent_mesh/assets/docs/assets/js/7e294c01.7c5f6906.js +1 -0
  67. solace_agent_mesh/assets/docs/assets/js/8024126c.e3467286.js +1 -0
  68. solace_agent_mesh/assets/docs/assets/js/81a99df0.7ed65d45.js +1 -0
  69. solace_agent_mesh/assets/docs/assets/js/82fbfb93.161823a5.js +1 -0
  70. solace_agent_mesh/assets/docs/assets/js/924ffdeb.975e428a.js +1 -0
  71. solace_agent_mesh/assets/docs/assets/js/94e8668d.16083b3f.js +1 -0
  72. solace_agent_mesh/assets/docs/assets/js/9bb13469.4523ae20.js +1 -0
  73. solace_agent_mesh/assets/docs/assets/js/a7d42657.a956689d.js +1 -0
  74. solace_agent_mesh/assets/docs/assets/js/a94703ab.3e5fbcb3.js +1 -0
  75. solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e563275.js +1 -0
  76. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.0e0d8baf.js +1 -0
  77. solace_agent_mesh/assets/docs/assets/js/cab03b5b.6a073091.js +1 -0
  78. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.07e170dd.js +1 -0
  79. solace_agent_mesh/assets/docs/assets/js/e04b235d.06d23db6.js +1 -0
  80. solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.deb2b62e.js +1 -0
  81. solace_agent_mesh/assets/docs/assets/js/e3d9abda.1476f570.js +1 -0
  82. solace_agent_mesh/assets/docs/assets/js/e6f9706b.acc800d3.js +1 -0
  83. solace_agent_mesh/assets/docs/assets/js/e92d0134.c147a429.js +1 -0
  84. solace_agent_mesh/assets/docs/assets/js/ee0c2fe7.94d0a351.js +1 -0
  85. solace_agent_mesh/assets/docs/assets/js/f284c35a.cc97854c.js +1 -0
  86. solace_agent_mesh/assets/docs/assets/js/main.d634009f.js +2 -0
  87. solace_agent_mesh/assets/docs/assets/js/runtime~main.27bb82a7.js +1 -0
  88. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +68 -68
  89. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +50 -50
  90. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +42 -42
  91. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +55 -55
  92. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +75 -75
  93. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/image-tools/index.html +81 -0
  94. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +67 -50
  95. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/research-tools/index.html +136 -0
  96. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +178 -144
  97. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +43 -42
  98. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +20 -18
  99. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +23 -23
  100. solace_agent_mesh/assets/docs/docs/documentation/components/platform-service/index.html +33 -0
  101. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +45 -45
  102. solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +98 -112
  103. solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +147 -0
  104. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +208 -125
  105. solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +52 -0
  106. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +28 -28
  107. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +29 -29
  108. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +14 -14
  109. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/index.html +47 -0
  110. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/kubernetes-deployment-guide/index.html +197 -0
  111. solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +67 -53
  112. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +17 -17
  113. solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +49 -0
  114. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +38 -38
  115. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +87 -87
  116. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +67 -49
  117. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +17 -17
  118. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +51 -51
  119. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +22 -22
  120. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +27 -27
  121. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +135 -135
  122. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +66 -66
  123. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +51 -51
  124. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +50 -38
  125. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +86 -86
  126. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +51 -51
  127. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +24 -24
  128. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +30 -30
  129. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +44 -44
  130. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +115 -0
  131. solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +50 -23
  132. solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +29 -24
  133. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +21 -21
  134. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +40 -37
  135. solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +324 -0
  136. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +96 -66
  137. solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +181 -181
  138. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +75 -75
  139. solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +27 -27
  140. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +44 -44
  141. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +39 -38
  142. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +30 -30
  143. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +18 -18
  144. solace_agent_mesh/assets/docs/docs/documentation/getting-started/vibe_coding/index.html +62 -0
  145. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +135 -114
  146. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +37 -37
  147. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +14 -14
  148. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +27 -25
  149. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +69 -69
  150. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +72 -72
  151. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +112 -112
  152. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +28 -28
  153. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +42 -42
  154. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +20 -20
  155. solace_agent_mesh/assets/docs/docs/documentation/migrations/platform-service-split/index.html +85 -0
  156. solace_agent_mesh/assets/docs/lunr-index-1768329217460.json +1 -0
  157. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  158. solace_agent_mesh/assets/docs/search-doc-1768329217460.json +1 -0
  159. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  160. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  161. solace_agent_mesh/cli/__init__.py +1 -1
  162. solace_agent_mesh/cli/commands/add_cmd/__init__.py +3 -1
  163. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +6 -1
  164. solace_agent_mesh/cli/commands/add_cmd/proxy_cmd.py +100 -0
  165. solace_agent_mesh/cli/commands/eval_cmd.py +1 -1
  166. solace_agent_mesh/cli/commands/init_cmd/__init__.py +15 -0
  167. solace_agent_mesh/cli/commands/init_cmd/directory_step.py +1 -1
  168. solace_agent_mesh/cli/commands/init_cmd/env_step.py +30 -3
  169. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +3 -4
  170. solace_agent_mesh/cli/commands/init_cmd/platform_service_step.py +85 -0
  171. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +16 -3
  172. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +2 -1
  173. solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +1 -0
  174. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +3 -3
  175. solace_agent_mesh/cli/commands/run_cmd.py +64 -49
  176. solace_agent_mesh/cli/commands/tools_cmd.py +315 -0
  177. solace_agent_mesh/cli/main.py +15 -0
  178. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-tcIFZLis.js → authCallback-KnKMP_vb.js} +1 -1
  179. solace_agent_mesh/client/webui/frontend/static/assets/client-DpBL2stg.js +25 -0
  180. solace_agent_mesh/client/webui/frontend/static/assets/main-Cd498TV2.js +435 -0
  181. solace_agent_mesh/client/webui/frontend/static/assets/main-rSf8Vu29.css +1 -0
  182. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CINwxvwV.js → vendor-CGk8Suyh.js} +189 -94
  183. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  184. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  185. solace_agent_mesh/client/webui/frontend/static/mockServiceWorker.js +336 -0
  186. solace_agent_mesh/client/webui/frontend/static/ui-version.json +6 -0
  187. solace_agent_mesh/common/a2a/types.py +1 -1
  188. solace_agent_mesh/common/agent_registry.py +38 -11
  189. solace_agent_mesh/common/data_parts.py +124 -0
  190. solace_agent_mesh/common/error_handlers.py +83 -0
  191. solace_agent_mesh/common/exceptions.py +24 -0
  192. solace_agent_mesh/common/oauth/__init__.py +17 -0
  193. solace_agent_mesh/common/oauth/oauth_client.py +408 -0
  194. solace_agent_mesh/common/oauth/utils.py +50 -0
  195. solace_agent_mesh/common/rag_dto.py +156 -0
  196. solace_agent_mesh/common/sac/sam_component_base.py +73 -1
  197. solace_agent_mesh/common/sam_events/event_service.py +2 -2
  198. solace_agent_mesh/common/utils/embeds/converter.py +1 -8
  199. solace_agent_mesh/common/utils/embeds/modifiers.py +2 -27
  200. solace_agent_mesh/common/utils/embeds/resolver.py +94 -25
  201. solace_agent_mesh/common/utils/embeds/types.py +1 -0
  202. solace_agent_mesh/common/utils/log_formatters.py +20 -0
  203. solace_agent_mesh/common/utils/mime_helpers.py +12 -5
  204. solace_agent_mesh/common/utils/rbac_utils.py +69 -0
  205. solace_agent_mesh/common/utils/templates/__init__.py +8 -0
  206. solace_agent_mesh/common/utils/templates/liquid_renderer.py +210 -0
  207. solace_agent_mesh/common/utils/templates/template_resolver.py +161 -0
  208. solace_agent_mesh/config_portal/backend/common.py +12 -0
  209. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-CljP4_mv.js +103 -0
  210. solace_agent_mesh/config_portal/frontend/static/client/assets/{components-Rk0n-9cK.js → components-CaC6hG8d.js} +22 -22
  211. solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-mvZjNKiz.js → entry.client-H_TM0YBt.js} +3 -3
  212. solace_agent_mesh/config_portal/frontend/static/client/assets/{index-DzNKzXrc.js → index-CnFykb2v.js} +16 -16
  213. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-f8439d40.js +1 -0
  214. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BIMqslJB.css +1 -0
  215. solace_agent_mesh/config_portal/frontend/static/client/assets/root-mJmTIdIk.js +10 -0
  216. solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
  217. solace_agent_mesh/core_a2a/service.py +3 -2
  218. solace_agent_mesh/gateway/adapter/base.py +28 -1
  219. solace_agent_mesh/gateway/adapter/types.py +9 -0
  220. solace_agent_mesh/gateway/base/app.py +10 -0
  221. solace_agent_mesh/gateway/base/auth_interface.py +103 -0
  222. solace_agent_mesh/gateway/base/component.py +451 -10
  223. solace_agent_mesh/gateway/generic/component.py +274 -30
  224. solace_agent_mesh/gateway/http_sse/alembic/env.py +0 -7
  225. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +2 -43
  226. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +2 -2
  227. solace_agent_mesh/gateway/http_sse/alembic/versions/20251108_create_prompt_tables_with_sharing.py +154 -0
  228. solace_agent_mesh/gateway/http_sse/alembic/versions/20251115_add_parent_task_id.py +32 -0
  229. solace_agent_mesh/gateway/http_sse/alembic/versions/20251126_add_background_task_fields.py +47 -0
  230. solace_agent_mesh/gateway/http_sse/alembic/versions/20251202_add_versioned_fields_to_prompts.py +52 -0
  231. solace_agent_mesh/gateway/http_sse/alembic.ini +0 -36
  232. solace_agent_mesh/gateway/http_sse/app.py +23 -6
  233. solace_agent_mesh/gateway/http_sse/component.py +158 -73
  234. solace_agent_mesh/gateway/http_sse/dependencies.py +50 -57
  235. solace_agent_mesh/gateway/http_sse/main.py +58 -482
  236. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +2 -2
  237. solace_agent_mesh/gateway/http_sse/repository/entities/project.py +1 -1
  238. solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +1 -1
  239. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +3 -2
  240. solace_agent_mesh/gateway/http_sse/repository/entities/task.py +7 -0
  241. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +2 -2
  242. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +2 -2
  243. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +5 -0
  244. solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +159 -0
  245. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +1 -1
  246. solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +8 -1
  247. solace_agent_mesh/gateway/http_sse/repository/project_repository.py +1 -1
  248. solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +1 -1
  249. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +12 -107
  250. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +86 -2
  251. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +38 -7
  252. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +113 -7
  253. solace_agent_mesh/gateway/http_sse/routers/auth.py +69 -132
  254. solace_agent_mesh/gateway/http_sse/routers/config.py +235 -10
  255. solace_agent_mesh/gateway/http_sse/routers/dto/project_dto.py +69 -0
  256. solace_agent_mesh/gateway/http_sse/routers/dto/prompt_dto.py +255 -0
  257. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +1 -1
  258. solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +1 -1
  259. solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +1 -0
  260. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +3 -2
  261. solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
  262. solace_agent_mesh/gateway/http_sse/routers/feedback.py +2 -2
  263. solace_agent_mesh/gateway/http_sse/routers/people.py +2 -2
  264. solace_agent_mesh/gateway/http_sse/routers/projects.py +250 -24
  265. solace_agent_mesh/gateway/http_sse/routers/prompts.py +1416 -0
  266. solace_agent_mesh/gateway/http_sse/routers/sessions.py +14 -5
  267. solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
  268. solace_agent_mesh/gateway/http_sse/routers/sse.py +117 -4
  269. solace_agent_mesh/gateway/http_sse/routers/tasks.py +509 -149
  270. solace_agent_mesh/gateway/http_sse/routers/users.py +1 -1
  271. solace_agent_mesh/gateway/http_sse/routers/version.py +343 -0
  272. solace_agent_mesh/gateway/http_sse/routers/visualization.py +2 -1
  273. solace_agent_mesh/gateway/http_sse/services/audio_service.py +1227 -0
  274. solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +186 -0
  275. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +1 -1
  276. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +1 -1
  277. solace_agent_mesh/gateway/http_sse/services/project_service.py +539 -12
  278. solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
  279. solace_agent_mesh/gateway/http_sse/services/session_service.py +198 -21
  280. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +354 -4
  281. solace_agent_mesh/gateway/http_sse/sse_manager.py +280 -169
  282. solace_agent_mesh/gateway/http_sse/utils/artifact_copy_utils.py +370 -0
  283. solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +41 -1
  284. solace_agent_mesh/services/__init__.py +0 -0
  285. solace_agent_mesh/services/platform/__init__.py +29 -0
  286. solace_agent_mesh/services/platform/alembic/env.py +85 -0
  287. solace_agent_mesh/services/platform/alembic/script.py.mako +28 -0
  288. solace_agent_mesh/services/platform/alembic.ini +109 -0
  289. solace_agent_mesh/services/platform/api/__init__.py +3 -0
  290. solace_agent_mesh/services/platform/api/dependencies.py +154 -0
  291. solace_agent_mesh/services/platform/api/main.py +314 -0
  292. solace_agent_mesh/services/platform/api/middleware.py +51 -0
  293. solace_agent_mesh/services/platform/api/routers/__init__.py +33 -0
  294. solace_agent_mesh/services/platform/api/routers/health_router.py +31 -0
  295. solace_agent_mesh/services/platform/app.py +215 -0
  296. solace_agent_mesh/services/platform/component.py +777 -0
  297. solace_agent_mesh/shared/__init__.py +14 -0
  298. solace_agent_mesh/shared/api/__init__.py +42 -0
  299. solace_agent_mesh/shared/auth/__init__.py +26 -0
  300. solace_agent_mesh/shared/auth/dependencies.py +204 -0
  301. solace_agent_mesh/shared/auth/middleware.py +347 -0
  302. solace_agent_mesh/shared/database/__init__.py +20 -0
  303. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/base_repository.py +1 -1
  304. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_exceptions.py +1 -1
  305. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_helpers.py +1 -1
  306. solace_agent_mesh/shared/exceptions/__init__.py +36 -0
  307. solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exception_handlers.py +1 -1
  308. solace_agent_mesh/shared/utils/__init__.py +21 -0
  309. solace_agent_mesh/templates/logging_config_template.yaml +48 -0
  310. solace_agent_mesh/templates/main_orchestrator.yaml +12 -1
  311. solace_agent_mesh/templates/platform.yaml +49 -0
  312. solace_agent_mesh/templates/plugin_readme_template.md +3 -25
  313. solace_agent_mesh/templates/plugin_tool_config_template.yaml +109 -0
  314. solace_agent_mesh/templates/proxy_template.yaml +62 -0
  315. solace_agent_mesh/templates/webui.yaml +148 -6
  316. solace_agent_mesh/tools/web_search/__init__.py +18 -0
  317. solace_agent_mesh/tools/web_search/base.py +84 -0
  318. solace_agent_mesh/tools/web_search/google_search.py +247 -0
  319. solace_agent_mesh/tools/web_search/models.py +99 -0
  320. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/METADATA +29 -8
  321. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/RECORD +334 -313
  322. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/WHEEL +1 -1
  323. solace_agent_mesh/agent/adk/adk_llm.txt +0 -226
  324. solace_agent_mesh/agent/adk/adk_llm_detail.txt +0 -566
  325. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +0 -171
  326. solace_agent_mesh/agent/adk/models/models_llm.txt +0 -189
  327. solace_agent_mesh/agent/agent_llm.txt +0 -369
  328. solace_agent_mesh/agent/agent_llm_detail.txt +0 -1702
  329. solace_agent_mesh/agent/protocol/protocol_llm.txt +0 -81
  330. solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +0 -92
  331. solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +0 -190
  332. solace_agent_mesh/agent/proxies/base/base_llm.txt +0 -148
  333. solace_agent_mesh/agent/proxies/proxies_llm.txt +0 -283
  334. solace_agent_mesh/agent/sac/sac_llm.txt +0 -189
  335. solace_agent_mesh/agent/sac/sac_llm_detail.txt +0 -200
  336. solace_agent_mesh/agent/testing/testing_llm.txt +0 -58
  337. solace_agent_mesh/agent/testing/testing_llm_detail.txt +0 -68
  338. solace_agent_mesh/agent/tools/tools_llm.txt +0 -276
  339. solace_agent_mesh/agent/tools/tools_llm_detail.txt +0 -275
  340. solace_agent_mesh/agent/utils/utils_llm.txt +0 -152
  341. solace_agent_mesh/agent/utils/utils_llm_detail.txt +0 -149
  342. solace_agent_mesh/assets/docs/assets/js/05749d90.c70b2be9.js +0 -1
  343. solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +0 -1
  344. solace_agent_mesh/assets/docs/assets/js/15e40e79.36003774.js +0 -1
  345. solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +0 -2
  346. solace_agent_mesh/assets/docs/assets/js/240a0364.c39f8388.js +0 -1
  347. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +0 -1
  348. solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +0 -1
  349. solace_agent_mesh/assets/docs/assets/js/3ac1795d.e4870a49.js +0 -1
  350. solace_agent_mesh/assets/docs/assets/js/3ff0015d.b63ee53a.js +0 -1
  351. solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +0 -1
  352. solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +0 -1
  353. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.45b32c2b.js +0 -1
  354. solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +0 -1
  355. solace_agent_mesh/assets/docs/assets/js/66d4869e.830d443f.js +0 -1
  356. solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +0 -1
  357. solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +0 -1
  358. solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +0 -1
  359. solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +0 -1
  360. solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +0 -1
  361. solace_agent_mesh/assets/docs/assets/js/94e8668d.09ed9234.js +0 -1
  362. solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +0 -1
  363. solace_agent_mesh/assets/docs/assets/js/a94703ab.0438dbc2.js +0 -1
  364. solace_agent_mesh/assets/docs/assets/js/ab9708a8.245ae0ef.js +0 -1
  365. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +0 -1
  366. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.f902fad8.js +0 -1
  367. solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +0 -1
  368. solace_agent_mesh/assets/docs/assets/js/e04b235d.c9c50c7b.js +0 -1
  369. solace_agent_mesh/assets/docs/assets/js/e3d9abda.d11c67a7.js +0 -1
  370. solace_agent_mesh/assets/docs/assets/js/e6f9706b.045d0fa1.js +0 -1
  371. solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +0 -1
  372. solace_agent_mesh/assets/docs/assets/js/f284c35a.5099c51e.js +0 -1
  373. solace_agent_mesh/assets/docs/assets/js/main.f213fe0c.js +0 -2
  374. solace_agent_mesh/assets/docs/assets/js/runtime~main.d9606d6a.js +0 -1
  375. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +0 -47
  376. solace_agent_mesh/assets/docs/lunr-index-1762283454666.json +0 -1
  377. solace_agent_mesh/assets/docs/search-doc-1762283454666.json +0 -1
  378. solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +0 -250
  379. solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +0 -365
  380. solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +0 -305
  381. solace_agent_mesh/client/webui/frontend/static/assets/client-CRYdKo2Q.js +0 -25
  382. solace_agent_mesh/client/webui/frontend/static/assets/main-CojeY_1w.css +0 -1
  383. solace_agent_mesh/client/webui/frontend/static/assets/main-ILja9MCG.js +0 -353
  384. solace_agent_mesh/common/a2a/a2a_llm.txt +0 -175
  385. solace_agent_mesh/common/a2a/a2a_llm_detail.txt +0 -193
  386. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +0 -445
  387. solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +0 -736
  388. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +0 -330
  389. solace_agent_mesh/common/common_llm.txt +0 -230
  390. solace_agent_mesh/common/common_llm_detail.txt +0 -2562
  391. solace_agent_mesh/common/middleware/middleware_llm.txt +0 -174
  392. solace_agent_mesh/common/middleware/middleware_llm_detail.txt +0 -185
  393. solace_agent_mesh/common/sac/sac_llm.txt +0 -71
  394. solace_agent_mesh/common/sac/sac_llm_detail.txt +0 -82
  395. solace_agent_mesh/common/sam_events/sam_events_llm.txt +0 -104
  396. solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +0 -115
  397. solace_agent_mesh/common/services/providers/providers_llm.txt +0 -81
  398. solace_agent_mesh/common/services/services_llm.txt +0 -368
  399. solace_agent_mesh/common/services/services_llm_detail.txt +0 -459
  400. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +0 -220
  401. solace_agent_mesh/common/utils/utils_llm.txt +0 -335
  402. solace_agent_mesh/common/utils/utils_llm_detail.txt +0 -572
  403. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +0 -98
  404. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-61038fc6.js +0 -1
  405. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BWvk5-gF.js +0 -10
  406. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DxRwaWiE.css +0 -1
  407. solace_agent_mesh/core_a2a/core_a2a_llm.txt +0 -90
  408. solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +0 -101
  409. solace_agent_mesh/gateway/base/base_llm.txt +0 -226
  410. solace_agent_mesh/gateway/base/base_llm_detail.txt +0 -235
  411. solace_agent_mesh/gateway/gateway_llm.txt +0 -369
  412. solace_agent_mesh/gateway/gateway_llm_detail.txt +0 -3885
  413. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +0 -345
  414. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_fulltext_search_indexes.py +0 -92
  415. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +0 -161
  416. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +0 -105
  417. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +0 -299
  418. solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +0 -3278
  419. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +0 -221
  420. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +0 -257
  421. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +0 -308
  422. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +0 -450
  423. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +0 -133
  424. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +0 -123
  425. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +0 -312
  426. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +0 -303
  427. solace_agent_mesh/gateway/http_sse/shared/__init__.py +0 -146
  428. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +0 -319
  429. solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +0 -47
  430. solace_agent_mesh/llm.txt +0 -228
  431. solace_agent_mesh/llm_detail.txt +0 -2835
  432. solace_agent_mesh/solace_agent_mesh_llm.txt +0 -362
  433. solace_agent_mesh/solace_agent_mesh_llm_detail.txt +0 -8599
  434. solace_agent_mesh/templates/logging_config_template.ini +0 -45
  435. solace_agent_mesh/templates/templates_llm.txt +0 -147
  436. /solace_agent_mesh/assets/docs/assets/js/{main.f213fe0c.js.LICENSE.txt → main.d634009f.js.LICENSE.txt} +0 -0
  437. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/auth_utils.py +0 -0
  438. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/pagination.py +0 -0
  439. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/response_utils.py +0 -0
  440. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/error_dto.py +0 -0
  441. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exceptions.py +0 -0
  442. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/enums.py +0 -0
  443. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/timestamp_utils.py +0 -0
  444. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/types.py +0 -0
  445. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/utils.py +0 -0
  446. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/entry_points.txt +0 -0
  447. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/licenses/LICENSE +0 -0
@@ -10,7 +10,7 @@ import uuid
10
10
  import json
11
11
  import re
12
12
  import fnmatch
13
- from typing import Any, Dict, Optional, Union, TYPE_CHECKING
13
+ from typing import Any, Dict, List, Optional, Tuple, Union, TYPE_CHECKING
14
14
  from datetime import datetime, timezone
15
15
  from google.adk.tools import ToolContext
16
16
 
@@ -175,6 +175,7 @@ async def _internal_create_artifact(
175
175
  timestamp=timestamp_for_artifact,
176
176
  schema_max_keys=max_keys_to_use,
177
177
  tool_context=tool_context,
178
+ suppress_visualization_signal=True, # Fenced blocks handle their own visualization signals
178
179
  )
179
180
  log.info(
180
181
  "%s Result from save_artifact_with_metadata: %s", log_identifier, result
@@ -362,6 +363,7 @@ async def load_artifact(
362
363
  version: int,
363
364
  load_metadata_only: bool = False,
364
365
  max_content_length: Optional[int] = None,
366
+ include_line_numbers: bool = False,
365
367
  tool_context: ToolContext = None,
366
368
  ) -> Dict[str, Any]:
367
369
  """
@@ -377,6 +379,9 @@ async def load_artifact(
377
379
  load_metadata_only (bool): If True, load only the metadata JSON. Default False.
378
380
  max_content_length (Optional[int]): Maximum character length for text content.
379
381
  If None, uses app configuration. Range: 100-100,000.
382
+ include_line_numbers (bool): If True, prefix each line with its 1-based line number
383
+ followed by a TAB character for LLM viewing. Line numbers
384
+ are not stored in the artifact. Default False.
380
385
  tool_context: The context provided by the ADK framework.
381
386
 
382
387
  Returns:
@@ -415,6 +420,7 @@ async def load_artifact(
415
420
  version=version,
416
421
  load_metadata_only=load_metadata_only,
417
422
  max_content_length=max_content_length,
423
+ include_line_numbers=include_line_numbers,
418
424
  component=host_component,
419
425
  log_identifier_prefix="[BuiltinArtifactTool:load_artifact]",
420
426
  )
@@ -1621,7 +1627,7 @@ list_artifacts_tool_def = BuiltinTool(
1621
1627
  load_artifact_tool_def = BuiltinTool(
1622
1628
  name="load_artifact",
1623
1629
  implementation=load_artifact,
1624
- description="Loads the content or metadata of a specific artifact version. If load_metadata_only is True, loads the full metadata dictionary. Otherwise, loads text content (potentially truncated) or a summary for binary types.",
1630
+ description="Loads the content or metadata of a specific artifact version. If load_metadata_only is True, loads the full metadata dictionary. Otherwise, loads text content (potentially truncated) or a summary for binary types. Line numbers can be optionally included for precise line range identification.",
1625
1631
  category="artifact_management",
1626
1632
  category_name=CATEGORY_NAME,
1627
1633
  category_description=CATEGORY_DESCRIPTION,
@@ -1647,6 +1653,11 @@ load_artifact_tool_def = BuiltinTool(
1647
1653
  description="Optional. Maximum character length for text content. If None, uses app configuration. Range: 100-100,000.",
1648
1654
  nullable=True,
1649
1655
  ),
1656
+ "include_line_numbers": adk_types.Schema(
1657
+ type=adk_types.Type.BOOLEAN,
1658
+ description="If True, prefix each line with its 1-based line number followed by a TAB character. Line numbers are for LLM viewing only and are not stored in the artifact. Default False.",
1659
+ nullable=True,
1660
+ ),
1650
1661
  },
1651
1662
  required=["filename", "version"],
1652
1663
  ),
@@ -1730,18 +1741,20 @@ tool_registry.register(extract_content_from_artifact_tool_def)
1730
1741
  async def delete_artifact(
1731
1742
  filename: str,
1732
1743
  version: Optional[int] = None,
1744
+ confirm_delete: bool = False,
1733
1745
  tool_context: ToolContext = None,
1734
1746
  ) -> Dict[str, Any]:
1735
1747
  """
1736
- Deletes a specific version of an artifact, or all versions if no version is specified.
1748
+ Deletes all versions of an artifact. Version-specific deletion is not currently supported.
1737
1749
 
1738
1750
  Args:
1739
1751
  filename: The name of the artifact to delete.
1740
- version: The specific version number to delete. If not provided, all versions will be deleted.
1752
+ version: Reserved for future use. Currently not supported - returns error if specified.
1753
+ confirm_delete: Must be set to True to confirm deletion. If False, returns confirmation prompt.
1741
1754
  tool_context: The context provided by the ADK framework.
1742
1755
 
1743
1756
  Returns:
1744
- A dictionary indicating the result of the deletion.
1757
+ A dictionary indicating the result of the deletion or requesting confirmation.
1745
1758
  """
1746
1759
  if not tool_context:
1747
1760
  return {
@@ -1750,9 +1763,7 @@ async def delete_artifact(
1750
1763
  "message": "ToolContext is missing, cannot delete artifact.",
1751
1764
  }
1752
1765
 
1753
- log_identifier = (
1754
- f"[BuiltinArtifactTool:delete_artifact:{filename}:{version or 'all'}]"
1755
- )
1766
+ log_identifier = f"[BuiltinArtifactTool:delete_artifact:{filename}]"
1756
1767
  log.debug("%s Processing request.", log_identifier)
1757
1768
 
1758
1769
  try:
@@ -1770,14 +1781,32 @@ async def delete_artifact(
1770
1781
  "ArtifactService does not support deleting artifacts."
1771
1782
  )
1772
1783
 
1784
+ # Error if version-specific deletion requested (not currently supported)
1773
1785
  if version is not None:
1774
- log.warning(
1775
- "%s Deleting a specific version (%s) is not supported by the current artifact service interface. "
1776
- "All versions of the artifact will be deleted.",
1777
- log_identifier,
1778
- version,
1779
- )
1786
+ return {
1787
+ "status": "error",
1788
+ "filename": filename,
1789
+ "version_requested": version,
1790
+ "message": f"Deleting a specific version ({version}) is not currently supported. Only deletion of ALL versions is supported. To delete all versions, omit 'version' and set confirm_delete=True.",
1791
+ }
1792
+
1793
+ # Get version list for confirmation message
1794
+ versions = await artifact_service.list_versions(
1795
+ app_name=app_name, user_id=user_id, session_id=session_id, filename=filename
1796
+ )
1797
+
1798
+ # Require confirmation before deleting
1799
+ if not confirm_delete:
1800
+ count = len(versions) if versions else "unknown number of"
1801
+ return {
1802
+ "status": "confirmation_required",
1803
+ "filename": filename,
1804
+ "version_count": len(versions) if versions else None,
1805
+ "versions": versions,
1806
+ "message": f"WARNING: This operation is irreversible and will permanently delete artifact '{filename}' and ALL {count} version(s). To proceed, call this tool again with confirm_delete=True.",
1807
+ }
1780
1808
 
1809
+ # Proceed with deletion
1781
1810
  await artifact_service.delete_artifact(
1782
1811
  app_name=app_name,
1783
1812
  user_id=user_id,
@@ -1785,17 +1814,12 @@ async def delete_artifact(
1785
1814
  filename=filename,
1786
1815
  )
1787
1816
 
1788
- log.info(
1789
- "%s Successfully deleted artifact '%s' version '%s'.",
1790
- log_identifier,
1791
- filename,
1792
- version or "all",
1793
- )
1817
+ log.info("%s Successfully deleted artifact '%s'.", log_identifier, filename)
1794
1818
  return {
1795
1819
  "status": "success",
1796
1820
  "filename": filename,
1797
- "version": version or "all",
1798
- "message": f"Artifact '{filename}' version '{version or 'all'}' deleted successfully.",
1821
+ "versions_deleted": len(versions) if versions else None,
1822
+ "message": f"Artifact '{filename}' deleted successfully.",
1799
1823
  }
1800
1824
 
1801
1825
  except FileNotFoundError as e:
@@ -1819,7 +1843,7 @@ async def delete_artifact(
1819
1843
  delete_artifact_tool_def = BuiltinTool(
1820
1844
  name="delete_artifact",
1821
1845
  implementation=delete_artifact,
1822
- description="Deletes a specific version of an artifact, or all versions if no version is specified.",
1846
+ description="Deletes all versions of an artifact. IMPORTANT: Requires explicit confirmation via confirm_delete=True parameter. The first call without confirmation will return details about what will be deleted.",
1823
1847
  category="artifact_management",
1824
1848
  category_name=CATEGORY_NAME,
1825
1849
  category_description=CATEGORY_DESCRIPTION,
@@ -1833,7 +1857,12 @@ delete_artifact_tool_def = BuiltinTool(
1833
1857
  ),
1834
1858
  "version": adk_types.Schema(
1835
1859
  type=adk_types.Type.INTEGER,
1836
- description="The specific version number to delete. If not provided, all versions will be deleted.",
1860
+ description="Reserved for future use. Version-specific deletion is not currently supported - will return error if specified.",
1861
+ nullable=True,
1862
+ ),
1863
+ "confirm_delete": adk_types.Schema(
1864
+ type=adk_types.Type.BOOLEAN,
1865
+ description="Must be set to True to actually perform the deletion. If False or omitted, returns a confirmation prompt with details about what will be deleted (including version count).",
1837
1866
  nullable=True,
1838
1867
  ),
1839
1868
  },
@@ -1843,3 +1872,648 @@ delete_artifact_tool_def = BuiltinTool(
1843
1872
  )
1844
1873
 
1845
1874
  tool_registry.register(delete_artifact_tool_def)
1875
+
1876
+
1877
+ def _perform_single_replacement(
1878
+ content: str,
1879
+ search_expr: str,
1880
+ replace_expr: str,
1881
+ is_regex: bool,
1882
+ regex_flags: str,
1883
+ log_identifier: str,
1884
+ strict_match_validation: bool = False,
1885
+ ) -> Tuple[str, int, Optional[str]]:
1886
+ """
1887
+ Performs a single search-and-replace operation.
1888
+
1889
+ Args:
1890
+ content: The text content to search/replace in
1891
+ search_expr: The search pattern (literal or regex)
1892
+ replace_expr: The replacement text
1893
+ is_regex: If True, search_expr is treated as regex
1894
+ regex_flags: Flags for regex behavior ('g', 'i', 'm', 's')
1895
+ log_identifier: Logging prefix
1896
+ strict_match_validation: If True, error on multiple matches without 'g' flag (for batch mode)
1897
+
1898
+ Returns:
1899
+ tuple: (new_content, match_count, error_message)
1900
+ error_message is None on success
1901
+ """
1902
+ match_count = 0
1903
+ new_content = content
1904
+
1905
+ if is_regex:
1906
+ # Parse regex flags
1907
+ flags_value = 0
1908
+ global_replace = False
1909
+
1910
+ if regex_flags:
1911
+ for flag_char in regex_flags.lower():
1912
+ if flag_char == "g":
1913
+ global_replace = True
1914
+ elif flag_char == "i":
1915
+ flags_value |= re.IGNORECASE
1916
+ elif flag_char == "m":
1917
+ flags_value |= re.MULTILINE
1918
+ elif flag_char == "s":
1919
+ flags_value |= re.DOTALL
1920
+ else:
1921
+ log.warning(
1922
+ "%s Ignoring unrecognized regexp flag: '%s'",
1923
+ log_identifier,
1924
+ flag_char,
1925
+ )
1926
+
1927
+ # Convert JavaScript-style capture groups ($1, $2) to Python style (\1, \2)
1928
+ # Also handle escaped dollar signs ($$) -> literal $
1929
+ python_replace_expr = replace_expr
1930
+ # First, protect escaped dollars: $$ -> a placeholder
1931
+ python_replace_expr = python_replace_expr.replace("$$", "\x00DOLLAR\x00")
1932
+ # Convert capture groups: $1 -> \1
1933
+ python_replace_expr = re.sub(r"\$(\d+)", r"\\\1", python_replace_expr)
1934
+ # Restore escaped dollars: placeholder -> $
1935
+ python_replace_expr = python_replace_expr.replace("\x00DOLLAR\x00", "$")
1936
+
1937
+ try:
1938
+ # Compile the regex pattern
1939
+ pattern = re.compile(search_expr, flags_value)
1940
+
1941
+ # Count matches first
1942
+ match_count = len(pattern.findall(content))
1943
+
1944
+ if match_count == 0:
1945
+ return content, 0, f"No matches found"
1946
+
1947
+ # Check for multiple matches without global flag (only in strict mode for batch operations)
1948
+ if strict_match_validation and match_count > 1 and not global_replace:
1949
+ return (
1950
+ content,
1951
+ match_count,
1952
+ f"Multiple matches found ({match_count}) but global flag 'g' not set",
1953
+ )
1954
+
1955
+ # Perform replacement
1956
+ count_limit = 0 if global_replace else 1
1957
+ new_content = pattern.sub(python_replace_expr, content, count=count_limit)
1958
+
1959
+ return new_content, match_count, None
1960
+
1961
+ except re.error as regex_err:
1962
+ return content, 0, f"Invalid regular expression: {regex_err}"
1963
+
1964
+ else:
1965
+ # Literal string replacement
1966
+ match_count = content.count(search_expr)
1967
+
1968
+ if match_count == 0:
1969
+ return content, 0, f"No matches found"
1970
+
1971
+ # Replace all occurrences for literal mode
1972
+ new_content = content.replace(search_expr, replace_expr)
1973
+ return new_content, match_count, None
1974
+
1975
+
1976
+ async def artifact_search_and_replace_regex(
1977
+ filename: str,
1978
+ search_expression: Optional[str] = None,
1979
+ replace_expression: Optional[str] = None,
1980
+ is_regexp: bool = False,
1981
+ version: Optional[str] = "latest",
1982
+ regexp_flags: Optional[str] = "",
1983
+ new_filename: Optional[str] = None,
1984
+ new_description: Optional[str] = None,
1985
+ replacements: Optional[List[Dict[str, Any]]] = None,
1986
+ tool_context: ToolContext = None,
1987
+ ) -> Dict[str, Any]:
1988
+ """
1989
+ Performs search and replace on an artifact's text content using either
1990
+ literal string matching or regular expressions. Note that this is run once across the entire artifact.
1991
+ If multiple replacements are needed, then set the 'g' flag in regexp_flags.
1992
+
1993
+ Handling Multi-line Search and Replace:
1994
+
1995
+ When searching for or replacing text that spans multiple lines:
1996
+
1997
+ - In literal mode (is_regexp=false): Include actual newline characters directly in your search_expression
1998
+ and replace_expression parameters. Do NOT use escape sequences like \n - the tool will search for those
1999
+ literal characters. Multi-line parameter values are fully supported in the XML parameter format.
2000
+
2001
+ - In regex mode (is_regexp=true): Use the regex pattern \n to match newline characters in your pattern.
2002
+
2003
+ For multiple independent replacements:
2004
+
2005
+ Use the replacements array parameter to perform all replacements atomically in a single tool call, which is more efficient than multiple sequential calls.
2006
+
2007
+ Args:
2008
+ filename: The name of the artifact to search/replace in.
2009
+ search_expression: The pattern to search for (regex if is_regexp=true, literal otherwise).
2010
+ replace_expression: The replacement text. For regex mode, supports capture groups ($1, $2, etc.). Use $$ to insert a literal dollar sign
2011
+ is_regexp: If True, treat search_expression as a regular expression. If False, treat as literal string.
2012
+ version: The version of the artifact to operate on. Can be an integer version number as a string or 'latest'. Defaults to 'latest'.
2013
+ regexp_flags: Flags for regex behavior (only used when is_regexp=true).
2014
+ String of letters: 'g' (global/replace-all), 'i' (case-insensitive), 'm' (multiline), 's' (dotall).
2015
+ Defaults to empty string (no flags).
2016
+ new_filename: Optional. If provided, saves the result as a new artifact with this name.
2017
+ new_description: Optional. Description for the new/updated artifact.
2018
+
2019
+ Returns:
2020
+ A dictionary containing the result status, filename, version, match count, and any error messages.
2021
+ """
2022
+ if not tool_context:
2023
+ return {
2024
+ "status": "error",
2025
+ "filename": filename,
2026
+ "message": "ToolContext is missing, cannot perform search and replace.",
2027
+ }
2028
+
2029
+ log_identifier = (
2030
+ f"[BuiltinArtifactTool:artifact_search_and_replace_regex:{filename}:{version}]"
2031
+ )
2032
+ log.debug("%s Processing request.", log_identifier)
2033
+
2034
+ # Validate parameter combinations
2035
+ if replacements is not None and (
2036
+ search_expression is not None or replace_expression is not None
2037
+ ):
2038
+ return {
2039
+ "status": "error",
2040
+ "filename": filename,
2041
+ "message": "Cannot provide both 'replacements' array and individual 'search_expression'/'replace_expression'. Use one or the other.",
2042
+ }
2043
+
2044
+ if replacements is None and (
2045
+ search_expression is None or replace_expression is None
2046
+ ):
2047
+ return {
2048
+ "status": "error",
2049
+ "filename": filename,
2050
+ "message": "Must provide either 'replacements' array or both 'search_expression' and 'replace_expression'.",
2051
+ }
2052
+
2053
+ if replacements is not None:
2054
+ if not isinstance(replacements, list) or len(replacements) == 0:
2055
+ return {
2056
+ "status": "error",
2057
+ "filename": filename,
2058
+ "message": "replacements must be a non-empty array.",
2059
+ }
2060
+
2061
+ # Validate each replacement entry
2062
+ for idx, repl in enumerate(replacements):
2063
+ if not isinstance(repl, dict):
2064
+ return {
2065
+ "status": "error",
2066
+ "filename": filename,
2067
+ "message": f"Replacement at index {idx} must be a dictionary.",
2068
+ }
2069
+ if "search" not in repl or "replace" not in repl or "is_regexp" not in repl:
2070
+ return {
2071
+ "status": "error",
2072
+ "filename": filename,
2073
+ "message": f"Replacement at index {idx} missing required fields: 'search', 'replace', 'is_regexp'.",
2074
+ }
2075
+
2076
+ # Validate inputs for single replacement mode
2077
+ if replacements is None and not search_expression:
2078
+ return {
2079
+ "status": "error",
2080
+ "filename": filename,
2081
+ "message": "search_expression cannot be empty.",
2082
+ }
2083
+
2084
+ # Determine output filename
2085
+ output_filename = new_filename if new_filename else filename
2086
+
2087
+ if new_filename and not is_filename_safe(new_filename):
2088
+ return {
2089
+ "status": "error",
2090
+ "filename": filename,
2091
+ "message": f"Invalid new_filename: '{new_filename}'. Filename must not contain path separators or traversal sequences.",
2092
+ }
2093
+
2094
+ try:
2095
+ inv_context = tool_context._invocation_context
2096
+ artifact_service = inv_context.artifact_service
2097
+ if not artifact_service:
2098
+ raise ValueError("ArtifactService is not available in the context.")
2099
+
2100
+ app_name = inv_context.app_name
2101
+ user_id = inv_context.user_id
2102
+ session_id = get_original_session_id(inv_context)
2103
+ host_component = getattr(inv_context.agent, "host_component", None)
2104
+
2105
+ # Load the source artifact
2106
+ log.debug(
2107
+ "%s Loading artifact '%s' version '%s'.", log_identifier, filename, version
2108
+ )
2109
+ load_result = await load_artifact_content_or_metadata(
2110
+ artifact_service=artifact_service,
2111
+ app_name=app_name,
2112
+ user_id=user_id,
2113
+ session_id=session_id,
2114
+ filename=filename,
2115
+ version=version,
2116
+ return_raw_bytes=True,
2117
+ component=host_component,
2118
+ log_identifier_prefix=log_identifier,
2119
+ )
2120
+
2121
+ if load_result.get("status") != "success":
2122
+ return {
2123
+ "status": "error",
2124
+ "filename": filename,
2125
+ "version": version,
2126
+ "message": f"Failed to load artifact: {load_result.get('message', 'Unknown error')}",
2127
+ }
2128
+
2129
+ source_bytes = load_result.get("raw_bytes")
2130
+ source_mime_type = load_result.get("mime_type", "application/octet-stream")
2131
+ actual_version = load_result.get("version", version)
2132
+
2133
+ # Verify it's a text-based artifact
2134
+ if not is_text_based_file(source_mime_type, source_bytes):
2135
+ return {
2136
+ "status": "error",
2137
+ "filename": filename,
2138
+ "version": actual_version,
2139
+ "message": f"Cannot perform search and replace on binary artifact of type '{source_mime_type}'. This tool only works with text-based content.",
2140
+ }
2141
+
2142
+ # Decode the content
2143
+ try:
2144
+ original_content = source_bytes.decode("utf-8")
2145
+ except UnicodeDecodeError as decode_err:
2146
+ log.error(
2147
+ "%s Failed to decode artifact content as UTF-8: %s",
2148
+ log_identifier,
2149
+ decode_err,
2150
+ )
2151
+ return {
2152
+ "status": "error",
2153
+ "filename": filename,
2154
+ "version": actual_version,
2155
+ "message": f"Failed to decode artifact content as UTF-8: {decode_err}",
2156
+ }
2157
+
2158
+ # Perform the search and replace
2159
+ if replacements:
2160
+ # Batch mode
2161
+ log.info(
2162
+ "%s Processing batch of %d replacements.",
2163
+ log_identifier,
2164
+ len(replacements),
2165
+ )
2166
+
2167
+ current_content = original_content
2168
+ replacement_results = []
2169
+ total_matches = 0
2170
+
2171
+ for idx, repl in enumerate(replacements):
2172
+ search_expr = repl["search"]
2173
+ replace_expr = repl["replace"]
2174
+ is_regex = repl["is_regexp"]
2175
+ regex_flags = repl.get("regexp_flags", "")
2176
+
2177
+ # Perform replacement on current state (with strict validation for batch mode)
2178
+ new_content, match_count, error_msg = _perform_single_replacement(
2179
+ current_content,
2180
+ search_expr,
2181
+ replace_expr,
2182
+ is_regex,
2183
+ regex_flags,
2184
+ log_identifier,
2185
+ strict_match_validation=True,
2186
+ )
2187
+
2188
+ if error_msg:
2189
+ # Rollback - return error with details
2190
+ log.warning(
2191
+ "%s Batch replacement failed at index %d: %s",
2192
+ log_identifier,
2193
+ idx,
2194
+ error_msg,
2195
+ )
2196
+
2197
+ # Mark all as skipped
2198
+ all_results = replacement_results + [
2199
+ {
2200
+ "search": repl["search"],
2201
+ "match_count": match_count,
2202
+ "status": "error",
2203
+ "error": error_msg,
2204
+ }
2205
+ ]
2206
+ # Add remaining as skipped
2207
+ for i in range(idx + 1, len(replacements)):
2208
+ all_results.append(
2209
+ {
2210
+ "search": replacements[i]["search"],
2211
+ "match_count": 0,
2212
+ "status": "skipped",
2213
+ }
2214
+ )
2215
+
2216
+ return {
2217
+ "status": "error",
2218
+ "filename": filename,
2219
+ "version": actual_version,
2220
+ "message": f"Batch replacement failed: No changes applied due to error in replacement {idx + 1}",
2221
+ "replacement_results": all_results,
2222
+ "failed_replacement": {
2223
+ "index": idx,
2224
+ "search": search_expr,
2225
+ "error": error_msg,
2226
+ },
2227
+ }
2228
+
2229
+ # Success - update state and continue
2230
+ current_content = new_content
2231
+ total_matches += match_count
2232
+ replacement_results.append(
2233
+ {
2234
+ "search": search_expr,
2235
+ "match_count": match_count,
2236
+ "status": "success",
2237
+ }
2238
+ )
2239
+
2240
+ log.debug(
2241
+ "%s Replacement %d/%d succeeded: %d matches",
2242
+ log_identifier,
2243
+ idx + 1,
2244
+ len(replacements),
2245
+ match_count,
2246
+ )
2247
+
2248
+ # All replacements succeeded
2249
+ final_content = current_content
2250
+ total_replacements = len(replacements)
2251
+
2252
+ log.info(
2253
+ "%s Batch replacement succeeded: %d operations, %d total matches",
2254
+ log_identifier,
2255
+ total_replacements,
2256
+ total_matches,
2257
+ )
2258
+
2259
+ else:
2260
+ # Single replacement mode (backward compatible)
2261
+ final_content, match_count, error_msg = _perform_single_replacement(
2262
+ original_content,
2263
+ search_expression,
2264
+ replace_expression,
2265
+ is_regexp,
2266
+ regexp_flags,
2267
+ log_identifier,
2268
+ )
2269
+
2270
+ if error_msg:
2271
+ # Check if it's a "no matches" error specifically
2272
+ if match_count == 0 and "No matches found" in error_msg:
2273
+ return {
2274
+ "status": "no_matches",
2275
+ "filename": filename,
2276
+ "version": actual_version,
2277
+ "match_count": 0,
2278
+ "message": f"No matches found for pattern '{search_expression}'. Artifact not modified.",
2279
+ }
2280
+ else:
2281
+ return {
2282
+ "status": "error",
2283
+ "filename": filename,
2284
+ "version": actual_version,
2285
+ "message": error_msg,
2286
+ }
2287
+
2288
+ total_replacements = 1
2289
+ total_matches = match_count
2290
+ replacement_results = None
2291
+
2292
+ # Prepare metadata for the new/updated artifact
2293
+ if replacements:
2294
+ new_metadata = {
2295
+ "source": f"artifact_search_and_replace_regex (batch) from '{filename}' v{actual_version}",
2296
+ "total_replacements": total_replacements,
2297
+ "total_matches": total_matches,
2298
+ }
2299
+ else:
2300
+ new_metadata = {
2301
+ "source": f"artifact_search_and_replace_regex from '{filename}' v{actual_version}",
2302
+ "search_expression": search_expression,
2303
+ "replace_expression": replace_expression,
2304
+ "is_regexp": is_regexp,
2305
+ "match_count": match_count,
2306
+ }
2307
+
2308
+ if regexp_flags and is_regexp:
2309
+ new_metadata["regexp_flags"] = regexp_flags
2310
+
2311
+ if new_description:
2312
+ new_metadata["description"] = new_description
2313
+ elif not new_filename:
2314
+ # If updating the same artifact, preserve original description if available
2315
+ try:
2316
+ metadata_load_result = await load_artifact_content_or_metadata(
2317
+ artifact_service=artifact_service,
2318
+ app_name=app_name,
2319
+ user_id=user_id,
2320
+ session_id=session_id,
2321
+ filename=filename,
2322
+ version=actual_version,
2323
+ load_metadata_only=True,
2324
+ component=host_component,
2325
+ log_identifier_prefix=log_identifier,
2326
+ )
2327
+ if metadata_load_result.get("status") == "success":
2328
+ original_metadata = metadata_load_result.get("metadata", {})
2329
+ if "description" in original_metadata:
2330
+ new_metadata["description"] = original_metadata["description"]
2331
+ except Exception as meta_err:
2332
+ log.warning(
2333
+ "%s Could not load original metadata to preserve description: %s",
2334
+ log_identifier,
2335
+ meta_err,
2336
+ )
2337
+
2338
+ # Save the result
2339
+ new_content_bytes = final_content.encode("utf-8")
2340
+ schema_max_keys = (
2341
+ host_component.get_config("schema_max_keys", DEFAULT_SCHEMA_MAX_KEYS)
2342
+ if host_component
2343
+ else DEFAULT_SCHEMA_MAX_KEYS
2344
+ )
2345
+
2346
+ save_result = await save_artifact_with_metadata(
2347
+ artifact_service=artifact_service,
2348
+ app_name=app_name,
2349
+ user_id=user_id,
2350
+ session_id=session_id,
2351
+ filename=output_filename,
2352
+ content_bytes=new_content_bytes,
2353
+ mime_type=source_mime_type,
2354
+ metadata_dict=new_metadata,
2355
+ timestamp=datetime.now(timezone.utc),
2356
+ schema_max_keys=schema_max_keys,
2357
+ tool_context=tool_context,
2358
+ )
2359
+
2360
+ if save_result.get("status") not in ["success", "partial_success"]:
2361
+ log.error(
2362
+ "%s Failed to save modified artifact: %s",
2363
+ log_identifier,
2364
+ save_result.get("message"),
2365
+ )
2366
+ return {
2367
+ "status": "error",
2368
+ "filename": filename,
2369
+ "version": actual_version,
2370
+ "message": f"Search and replace succeeded, but failed to save result: {save_result.get('message')}",
2371
+ }
2372
+
2373
+ result_version = save_result.get("data_version")
2374
+ log.info(
2375
+ "%s Successfully saved modified artifact '%s' as version %s.",
2376
+ log_identifier,
2377
+ output_filename,
2378
+ result_version,
2379
+ )
2380
+
2381
+ # Return appropriate response based on mode
2382
+ if replacements:
2383
+ return {
2384
+ "status": "success",
2385
+ "source_filename": filename,
2386
+ "source_version": actual_version,
2387
+ "output_filename": output_filename,
2388
+ "output_version": result_version,
2389
+ "total_replacements": total_replacements,
2390
+ "replacement_results": replacement_results,
2391
+ "total_matches": total_matches,
2392
+ "message": f"Batch replacement completed: {total_replacements} operations, {total_matches} total matches",
2393
+ }
2394
+ else:
2395
+ # Compute replacements_made for backward compatibility
2396
+ # For literal replacements, all matches are replaced
2397
+ # For regex without 'g' flag, only first match is replaced
2398
+ global_replace = "g" in (regexp_flags or "")
2399
+ replacements_made = (
2400
+ match_count if not is_regexp or global_replace else min(match_count, 1)
2401
+ )
2402
+
2403
+ return {
2404
+ "status": "success",
2405
+ "source_filename": filename,
2406
+ "source_version": actual_version,
2407
+ "output_filename": output_filename,
2408
+ "output_version": result_version,
2409
+ "match_count": match_count,
2410
+ "replacements_made": replacements_made,
2411
+ "message": f"Successfully performed {'regex' if is_regexp else 'literal'} search and replace. "
2412
+ f"Found {match_count} match(es), saved result as '{output_filename}' v{result_version}.",
2413
+ }
2414
+
2415
+ except FileNotFoundError as fnf_err:
2416
+ log.warning("%s Artifact not found: %s", log_identifier, fnf_err)
2417
+ return {
2418
+ "status": "error",
2419
+ "filename": filename,
2420
+ "version": version,
2421
+ "message": f"Artifact not found: {fnf_err}",
2422
+ }
2423
+ except Exception as e:
2424
+ log.exception(
2425
+ "%s Unexpected error during search and replace: %s", log_identifier, e
2426
+ )
2427
+ return {
2428
+ "status": "error",
2429
+ "filename": filename,
2430
+ "version": version,
2431
+ "message": f"Unexpected error: {e}",
2432
+ }
2433
+
2434
+
2435
+ artifact_search_and_replace_regex_tool_def = BuiltinTool(
2436
+ name="artifact_search_and_replace_regex",
2437
+ implementation=artifact_search_and_replace_regex,
2438
+ description="Performs search and replace on an artifact's text content using either literal string matching or regular expressions. Supports both single replacements and atomic batch replacements for efficiency.",
2439
+ category="artifact_management",
2440
+ category_name=CATEGORY_NAME,
2441
+ category_description=CATEGORY_DESCRIPTION,
2442
+ required_scopes=["tool:artifact:load", "tool:artifact:create"],
2443
+ parameters=adk_types.Schema(
2444
+ type=adk_types.Type.OBJECT,
2445
+ properties={
2446
+ "filename": adk_types.Schema(
2447
+ type=adk_types.Type.STRING,
2448
+ description="The name of the artifact to search/replace in.",
2449
+ ),
2450
+ "search_expression": adk_types.Schema(
2451
+ type=adk_types.Type.STRING,
2452
+ description="The pattern to search for (single replacement mode). If is_regexp is true, this is treated as a regular expression. Otherwise, it's a literal string. Do not use if 'replacements' is provided.",
2453
+ nullable=True,
2454
+ ),
2455
+ "replace_expression": adk_types.Schema(
2456
+ type=adk_types.Type.STRING,
2457
+ description="The replacement text (single replacement mode). For regex mode, supports capture group references using $1, $2, etc. Use $$ to insert a literal dollar sign. Do not use if 'replacements' is provided.",
2458
+ nullable=True,
2459
+ ),
2460
+ "is_regexp": adk_types.Schema(
2461
+ type=adk_types.Type.BOOLEAN,
2462
+ description="If true, treat search_expression as a regular expression. If false, treat as literal string. Only used in single replacement mode.",
2463
+ nullable=True,
2464
+ ),
2465
+ "version": adk_types.Schema(
2466
+ type=adk_types.Type.STRING,
2467
+ description="The version of the artifact to operate on. Can be an integer version number or 'latest'. Defaults to 'latest'.",
2468
+ nullable=True,
2469
+ ),
2470
+ "regexp_flags": adk_types.Schema(
2471
+ type=adk_types.Type.STRING,
2472
+ description="Flags for regex behavior (only used when is_regexp=true in single mode). String of letters: 'g' (global/replace all), 'i' (case-insensitive), 'm' (multiline), 's' (dotall). Example: 'gim'. Defaults to empty string.",
2473
+ nullable=True,
2474
+ ),
2475
+ "new_filename": adk_types.Schema(
2476
+ type=adk_types.Type.STRING,
2477
+ description="Optional. If provided, saves the result as a new artifact with this name instead of creating a new version of the original.",
2478
+ nullable=True,
2479
+ ),
2480
+ "new_description": adk_types.Schema(
2481
+ type=adk_types.Type.STRING,
2482
+ description="Optional. Description for the new/updated artifact.",
2483
+ nullable=True,
2484
+ ),
2485
+ "replacements": adk_types.Schema(
2486
+ type=adk_types.Type.ARRAY,
2487
+ items=adk_types.Schema(
2488
+ type=adk_types.Type.OBJECT,
2489
+ properties={
2490
+ "search": adk_types.Schema(
2491
+ type=adk_types.Type.STRING,
2492
+ description="The search pattern (literal string or regex).",
2493
+ ),
2494
+ "replace": adk_types.Schema(
2495
+ type=adk_types.Type.STRING,
2496
+ description="The replacement text. For regex mode, supports $1, $2, etc. Use $$ for literal $.",
2497
+ ),
2498
+ "is_regexp": adk_types.Schema(
2499
+ type=adk_types.Type.BOOLEAN,
2500
+ description="If true, 'search' is a regex pattern. If false, literal string.",
2501
+ ),
2502
+ "regexp_flags": adk_types.Schema(
2503
+ type=adk_types.Type.STRING,
2504
+ description="Flags for regex: 'g' (global), 'i' (case-insensitive), 'm' (multiline), 's' (dotall). Default: ''.",
2505
+ nullable=True,
2506
+ ),
2507
+ },
2508
+ required=["search", "replace", "is_regexp"],
2509
+ ),
2510
+ description="Optional. Array of replacement operations to perform atomically. Each operation is processed sequentially on the cumulative result. If any operation fails, all changes are rolled back. Do not use with 'search_expression' or 'replace_expression'.",
2511
+ nullable=True,
2512
+ ),
2513
+ },
2514
+ required=["filename"],
2515
+ ),
2516
+ examples=[],
2517
+ )
2518
+
2519
+ tool_registry.register(artifact_search_and_replace_regex_tool_def)