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.
- solace_agent_mesh/agent/adk/alembic/README +74 -0
- solace_agent_mesh/agent/adk/alembic/env.py +77 -0
- solace_agent_mesh/agent/adk/alembic/script.py.mako +28 -0
- solace_agent_mesh/agent/adk/alembic/versions/e2902798564d_adk_session_db_upgrade.py +52 -0
- solace_agent_mesh/agent/adk/alembic.ini +112 -0
- solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +164 -0
- solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +163 -0
- solace_agent_mesh/agent/adk/callbacks.py +752 -127
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +99 -7
- solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +52 -5
- solace_agent_mesh/agent/adk/mcp_content_processor.py +1 -1
- solace_agent_mesh/agent/adk/models/lite_llm.py +34 -16
- solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +24 -137
- solace_agent_mesh/agent/adk/runner.py +66 -8
- solace_agent_mesh/agent/adk/schema_migration.py +88 -0
- solace_agent_mesh/agent/adk/services.py +41 -1
- solace_agent_mesh/agent/adk/setup.py +220 -32
- solace_agent_mesh/agent/adk/stream_parser.py +229 -40
- solace_agent_mesh/agent/protocol/event_handlers.py +219 -33
- solace_agent_mesh/agent/proxies/a2a/component.py +572 -75
- solace_agent_mesh/agent/proxies/a2a/config.py +80 -4
- solace_agent_mesh/agent/proxies/base/component.py +188 -22
- solace_agent_mesh/agent/proxies/base/proxy_task_context.py +3 -1
- solace_agent_mesh/agent/sac/app.py +37 -12
- solace_agent_mesh/agent/sac/component.py +322 -52
- solace_agent_mesh/agent/sac/patch_adk.py +8 -16
- solace_agent_mesh/agent/sac/task_execution_context.py +90 -0
- solace_agent_mesh/agent/tools/__init__.py +3 -0
- solace_agent_mesh/agent/tools/audio_tools.py +3 -3
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +698 -24
- solace_agent_mesh/agent/tools/deep_research_tools.py +2161 -0
- solace_agent_mesh/agent/tools/peer_agent_tool.py +82 -15
- solace_agent_mesh/agent/tools/time_tools.py +126 -0
- solace_agent_mesh/agent/tools/tool_config_types.py +54 -2
- solace_agent_mesh/agent/tools/web_search_tools.py +279 -0
- solace_agent_mesh/agent/tools/web_tools.py +125 -17
- solace_agent_mesh/agent/utils/artifact_helpers.py +243 -5
- solace_agent_mesh/agent/utils/context_helpers.py +17 -0
- solace_agent_mesh/assets/docs/404.html +6 -6
- solace_agent_mesh/assets/docs/assets/css/{styles.906a1503.css → styles.8162edfb.css} +1 -1
- solace_agent_mesh/assets/docs/assets/js/05749d90.19ac4f35.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.e186750d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15e40e79.434bb30f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/17896441.e612dfb4.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/{17896441.a5e82f9b.js.LICENSE.txt → 2279.550aa580.js.LICENSE.txt} +6 -0
- solace_agent_mesh/assets/docs/assets/js/240a0364.83e37aa8.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2e32b5e0.2f0db237.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3a6c6137.7e61915d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.7f7ab1c1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.e53c9b78.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/41adc471.0e95b87c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4667dc50.bf2ad456.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/49eed117.493d6f99.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{509e993c.4c7a1a6d.js → 509e993c.a1fbf45a.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/547e15cc.8e6da617.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55b7b518.29d6e75d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5b8d9c11.d4eb37b8.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.1ee87753.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/60702c0e.a8bdd79b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/64195356.09dbd087.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/66d4869e.30340bd3.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/729898df.7249e9fd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7e294c01.7c5f6906.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8024126c.e3467286.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/81a99df0.7ed65d45.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/82fbfb93.161823a5.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/924ffdeb.975e428a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/94e8668d.16083b3f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9bb13469.4523ae20.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a7d42657.a956689d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a94703ab.3e5fbcb3.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e563275.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c93cbaa0.0e0d8baf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cab03b5b.6a073091.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.07e170dd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e04b235d.06d23db6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.deb2b62e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.1476f570.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e6f9706b.acc800d3.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e92d0134.c147a429.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ee0c2fe7.94d0a351.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.cc97854c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.d634009f.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.27bb82a7.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +68 -68
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +50 -50
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +42 -42
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +55 -55
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +75 -75
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/image-tools/index.html +81 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +67 -50
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/research-tools/index.html +136 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +178 -144
- solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +43 -42
- solace_agent_mesh/assets/docs/docs/documentation/components/index.html +20 -18
- solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +23 -23
- solace_agent_mesh/assets/docs/docs/documentation/components/platform-service/index.html +33 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +45 -45
- solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +98 -112
- solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +147 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +208 -125
- solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +52 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +28 -28
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +29 -29
- solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +14 -14
- solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/index.html +47 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/kubernetes-deployment-guide/index.html +197 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +67 -53
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +17 -17
- solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +49 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +38 -38
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +87 -87
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +67 -49
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +17 -17
- solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +51 -51
- solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +22 -22
- solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +27 -27
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +135 -135
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +66 -66
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +51 -51
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +50 -38
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +86 -86
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +51 -51
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +24 -24
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +30 -30
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +44 -44
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +115 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +50 -23
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +29 -24
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +21 -21
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +40 -37
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +324 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +96 -66
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +181 -181
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +75 -75
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +27 -27
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +44 -44
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +39 -38
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +30 -30
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +18 -18
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/vibe_coding/index.html +62 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +135 -114
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +37 -37
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +14 -14
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +27 -25
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +69 -69
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +72 -72
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +112 -112
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +28 -28
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +42 -42
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +20 -20
- solace_agent_mesh/assets/docs/docs/documentation/migrations/platform-service-split/index.html +85 -0
- solace_agent_mesh/assets/docs/lunr-index-1768329217460.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1768329217460.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/assets/docs/sitemap.xml +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add_cmd/__init__.py +3 -1
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +6 -1
- solace_agent_mesh/cli/commands/add_cmd/proxy_cmd.py +100 -0
- solace_agent_mesh/cli/commands/eval_cmd.py +1 -1
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +15 -0
- solace_agent_mesh/cli/commands/init_cmd/directory_step.py +1 -1
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +30 -3
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +3 -4
- solace_agent_mesh/cli/commands/init_cmd/platform_service_step.py +85 -0
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +16 -3
- solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +2 -1
- solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +1 -0
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +3 -3
- solace_agent_mesh/cli/commands/run_cmd.py +64 -49
- solace_agent_mesh/cli/commands/tools_cmd.py +315 -0
- solace_agent_mesh/cli/main.py +15 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-tcIFZLis.js → authCallback-KnKMP_vb.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/client-DpBL2stg.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-Cd498TV2.js +435 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-rSf8Vu29.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CINwxvwV.js → vendor-CGk8Suyh.js} +189 -94
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
- solace_agent_mesh/client/webui/frontend/static/mockServiceWorker.js +336 -0
- solace_agent_mesh/client/webui/frontend/static/ui-version.json +6 -0
- solace_agent_mesh/common/a2a/types.py +1 -1
- solace_agent_mesh/common/agent_registry.py +38 -11
- solace_agent_mesh/common/data_parts.py +124 -0
- solace_agent_mesh/common/error_handlers.py +83 -0
- solace_agent_mesh/common/exceptions.py +24 -0
- solace_agent_mesh/common/oauth/__init__.py +17 -0
- solace_agent_mesh/common/oauth/oauth_client.py +408 -0
- solace_agent_mesh/common/oauth/utils.py +50 -0
- solace_agent_mesh/common/rag_dto.py +156 -0
- solace_agent_mesh/common/sac/sam_component_base.py +73 -1
- solace_agent_mesh/common/sam_events/event_service.py +2 -2
- solace_agent_mesh/common/utils/embeds/converter.py +1 -8
- solace_agent_mesh/common/utils/embeds/modifiers.py +2 -27
- solace_agent_mesh/common/utils/embeds/resolver.py +94 -25
- solace_agent_mesh/common/utils/embeds/types.py +1 -0
- solace_agent_mesh/common/utils/log_formatters.py +20 -0
- solace_agent_mesh/common/utils/mime_helpers.py +12 -5
- solace_agent_mesh/common/utils/rbac_utils.py +69 -0
- solace_agent_mesh/common/utils/templates/__init__.py +8 -0
- solace_agent_mesh/common/utils/templates/liquid_renderer.py +210 -0
- solace_agent_mesh/common/utils/templates/template_resolver.py +161 -0
- solace_agent_mesh/config_portal/backend/common.py +12 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-CljP4_mv.js +103 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{components-Rk0n-9cK.js → components-CaC6hG8d.js} +22 -22
- solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-mvZjNKiz.js → entry.client-H_TM0YBt.js} +3 -3
- solace_agent_mesh/config_portal/frontend/static/client/assets/{index-DzNKzXrc.js → index-CnFykb2v.js} +16 -16
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-f8439d40.js +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-BIMqslJB.css +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-mJmTIdIk.js +10 -0
- solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
- solace_agent_mesh/core_a2a/service.py +3 -2
- solace_agent_mesh/gateway/adapter/base.py +28 -1
- solace_agent_mesh/gateway/adapter/types.py +9 -0
- solace_agent_mesh/gateway/base/app.py +10 -0
- solace_agent_mesh/gateway/base/auth_interface.py +103 -0
- solace_agent_mesh/gateway/base/component.py +451 -10
- solace_agent_mesh/gateway/generic/component.py +274 -30
- solace_agent_mesh/gateway/http_sse/alembic/env.py +0 -7
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +2 -43
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +2 -2
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251108_create_prompt_tables_with_sharing.py +154 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251115_add_parent_task_id.py +32 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251126_add_background_task_fields.py +47 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251202_add_versioned_fields_to_prompts.py +52 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +0 -36
- solace_agent_mesh/gateway/http_sse/app.py +23 -6
- solace_agent_mesh/gateway/http_sse/component.py +158 -73
- solace_agent_mesh/gateway/http_sse/dependencies.py +50 -57
- solace_agent_mesh/gateway/http_sse/main.py +58 -482
- solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +2 -2
- solace_agent_mesh/gateway/http_sse/repository/entities/project.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/entities/session.py +3 -2
- solace_agent_mesh/gateway/http_sse/repository/entities/task.py +7 -0
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +2 -2
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +2 -2
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +5 -0
- solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +159 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +8 -1
- solace_agent_mesh/gateway/http_sse/repository/project_repository.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +12 -107
- solace_agent_mesh/gateway/http_sse/repository/task_repository.py +86 -2
- solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +38 -7
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +113 -7
- solace_agent_mesh/gateway/http_sse/routers/auth.py +69 -132
- solace_agent_mesh/gateway/http_sse/routers/config.py +235 -10
- solace_agent_mesh/gateway/http_sse/routers/dto/project_dto.py +69 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/prompt_dto.py +255 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +1 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +3 -2
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
- solace_agent_mesh/gateway/http_sse/routers/feedback.py +2 -2
- solace_agent_mesh/gateway/http_sse/routers/people.py +2 -2
- solace_agent_mesh/gateway/http_sse/routers/projects.py +250 -24
- solace_agent_mesh/gateway/http_sse/routers/prompts.py +1416 -0
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +14 -5
- solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
- solace_agent_mesh/gateway/http_sse/routers/sse.py +117 -4
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +509 -149
- solace_agent_mesh/gateway/http_sse/routers/users.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/version.py +343 -0
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +2 -1
- solace_agent_mesh/gateway/http_sse/services/audio_service.py +1227 -0
- solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +186 -0
- solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +1 -1
- solace_agent_mesh/gateway/http_sse/services/feedback_service.py +1 -1
- solace_agent_mesh/gateway/http_sse/services/project_service.py +539 -12
- solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
- solace_agent_mesh/gateway/http_sse/services/session_service.py +198 -21
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +354 -4
- solace_agent_mesh/gateway/http_sse/sse_manager.py +280 -169
- solace_agent_mesh/gateway/http_sse/utils/artifact_copy_utils.py +370 -0
- solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +41 -1
- solace_agent_mesh/services/__init__.py +0 -0
- solace_agent_mesh/services/platform/__init__.py +29 -0
- solace_agent_mesh/services/platform/alembic/env.py +85 -0
- solace_agent_mesh/services/platform/alembic/script.py.mako +28 -0
- solace_agent_mesh/services/platform/alembic.ini +109 -0
- solace_agent_mesh/services/platform/api/__init__.py +3 -0
- solace_agent_mesh/services/platform/api/dependencies.py +154 -0
- solace_agent_mesh/services/platform/api/main.py +314 -0
- solace_agent_mesh/services/platform/api/middleware.py +51 -0
- solace_agent_mesh/services/platform/api/routers/__init__.py +33 -0
- solace_agent_mesh/services/platform/api/routers/health_router.py +31 -0
- solace_agent_mesh/services/platform/app.py +215 -0
- solace_agent_mesh/services/platform/component.py +777 -0
- solace_agent_mesh/shared/__init__.py +14 -0
- solace_agent_mesh/shared/api/__init__.py +42 -0
- solace_agent_mesh/shared/auth/__init__.py +26 -0
- solace_agent_mesh/shared/auth/dependencies.py +204 -0
- solace_agent_mesh/shared/auth/middleware.py +347 -0
- solace_agent_mesh/shared/database/__init__.py +20 -0
- solace_agent_mesh/{gateway/http_sse/shared → shared/database}/base_repository.py +1 -1
- solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_exceptions.py +1 -1
- solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_helpers.py +1 -1
- solace_agent_mesh/shared/exceptions/__init__.py +36 -0
- solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exception_handlers.py +1 -1
- solace_agent_mesh/shared/utils/__init__.py +21 -0
- solace_agent_mesh/templates/logging_config_template.yaml +48 -0
- solace_agent_mesh/templates/main_orchestrator.yaml +12 -1
- solace_agent_mesh/templates/platform.yaml +49 -0
- solace_agent_mesh/templates/plugin_readme_template.md +3 -25
- solace_agent_mesh/templates/plugin_tool_config_template.yaml +109 -0
- solace_agent_mesh/templates/proxy_template.yaml +62 -0
- solace_agent_mesh/templates/webui.yaml +148 -6
- solace_agent_mesh/tools/web_search/__init__.py +18 -0
- solace_agent_mesh/tools/web_search/base.py +84 -0
- solace_agent_mesh/tools/web_search/google_search.py +247 -0
- solace_agent_mesh/tools/web_search/models.py +99 -0
- {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/METADATA +29 -8
- {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/RECORD +334 -313
- {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/WHEEL +1 -1
- solace_agent_mesh/agent/adk/adk_llm.txt +0 -226
- solace_agent_mesh/agent/adk/adk_llm_detail.txt +0 -566
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +0 -171
- solace_agent_mesh/agent/adk/models/models_llm.txt +0 -189
- solace_agent_mesh/agent/agent_llm.txt +0 -369
- solace_agent_mesh/agent/agent_llm_detail.txt +0 -1702
- solace_agent_mesh/agent/protocol/protocol_llm.txt +0 -81
- solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +0 -92
- solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +0 -190
- solace_agent_mesh/agent/proxies/base/base_llm.txt +0 -148
- solace_agent_mesh/agent/proxies/proxies_llm.txt +0 -283
- solace_agent_mesh/agent/sac/sac_llm.txt +0 -189
- solace_agent_mesh/agent/sac/sac_llm_detail.txt +0 -200
- solace_agent_mesh/agent/testing/testing_llm.txt +0 -58
- solace_agent_mesh/agent/testing/testing_llm_detail.txt +0 -68
- solace_agent_mesh/agent/tools/tools_llm.txt +0 -276
- solace_agent_mesh/agent/tools/tools_llm_detail.txt +0 -275
- solace_agent_mesh/agent/utils/utils_llm.txt +0 -152
- solace_agent_mesh/agent/utils/utils_llm_detail.txt +0 -149
- solace_agent_mesh/assets/docs/assets/js/05749d90.c70b2be9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/15e40e79.36003774.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/240a0364.c39f8388.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.e4870a49.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.b63ee53a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.45b32c2b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/66d4869e.830d443f.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/94e8668d.09ed9234.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/a94703ab.0438dbc2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ab9708a8.245ae0ef.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.f902fad8.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e04b235d.c9c50c7b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.d11c67a7.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e6f9706b.045d0fa1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.5099c51e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.f213fe0c.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.d9606d6a.js +0 -1
- solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +0 -47
- solace_agent_mesh/assets/docs/lunr-index-1762283454666.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1762283454666.json +0 -1
- solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +0 -250
- solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +0 -365
- solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +0 -305
- solace_agent_mesh/client/webui/frontend/static/assets/client-CRYdKo2Q.js +0 -25
- solace_agent_mesh/client/webui/frontend/static/assets/main-CojeY_1w.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-ILja9MCG.js +0 -353
- solace_agent_mesh/common/a2a/a2a_llm.txt +0 -175
- solace_agent_mesh/common/a2a/a2a_llm_detail.txt +0 -193
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +0 -445
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +0 -736
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +0 -330
- solace_agent_mesh/common/common_llm.txt +0 -230
- solace_agent_mesh/common/common_llm_detail.txt +0 -2562
- solace_agent_mesh/common/middleware/middleware_llm.txt +0 -174
- solace_agent_mesh/common/middleware/middleware_llm_detail.txt +0 -185
- solace_agent_mesh/common/sac/sac_llm.txt +0 -71
- solace_agent_mesh/common/sac/sac_llm_detail.txt +0 -82
- solace_agent_mesh/common/sam_events/sam_events_llm.txt +0 -104
- solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +0 -115
- solace_agent_mesh/common/services/providers/providers_llm.txt +0 -81
- solace_agent_mesh/common/services/services_llm.txt +0 -368
- solace_agent_mesh/common/services/services_llm_detail.txt +0 -459
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +0 -220
- solace_agent_mesh/common/utils/utils_llm.txt +0 -335
- solace_agent_mesh/common/utils/utils_llm_detail.txt +0 -572
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +0 -98
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-61038fc6.js +0 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-BWvk5-gF.js +0 -10
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-DxRwaWiE.css +0 -1
- solace_agent_mesh/core_a2a/core_a2a_llm.txt +0 -90
- solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +0 -101
- solace_agent_mesh/gateway/base/base_llm.txt +0 -226
- solace_agent_mesh/gateway/base/base_llm_detail.txt +0 -235
- solace_agent_mesh/gateway/gateway_llm.txt +0 -369
- solace_agent_mesh/gateway/gateway_llm_detail.txt +0 -3885
- solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +0 -345
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_fulltext_search_indexes.py +0 -92
- solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +0 -161
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +0 -105
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +0 -299
- solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +0 -3278
- solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +0 -221
- solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +0 -257
- solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +0 -308
- solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +0 -450
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +0 -133
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +0 -123
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +0 -312
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +0 -303
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +0 -146
- solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +0 -319
- solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +0 -47
- solace_agent_mesh/llm.txt +0 -228
- solace_agent_mesh/llm_detail.txt +0 -2835
- solace_agent_mesh/solace_agent_mesh_llm.txt +0 -362
- solace_agent_mesh/solace_agent_mesh_llm_detail.txt +0 -8599
- solace_agent_mesh/templates/logging_config_template.ini +0 -45
- solace_agent_mesh/templates/templates_llm.txt +0 -147
- /solace_agent_mesh/assets/docs/assets/js/{main.f213fe0c.js.LICENSE.txt → main.d634009f.js.LICENSE.txt} +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/auth_utils.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/pagination.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/response_utils.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/error_dto.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exceptions.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/enums.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/timestamp_utils.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/types.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/utils.py +0 -0
- {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/entry_points.txt +0 -0
- {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
|
|
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:
|
|
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
|
-
|
|
1775
|
-
"
|
|
1776
|
-
"
|
|
1777
|
-
|
|
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
|
-
"
|
|
1798
|
-
"message": f"Artifact '{filename}'
|
|
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
|
|
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="
|
|
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)
|