solace-agent-mesh 0.2.4__py3-none-any.whl → 1.0.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/__init__.py +5 -0
- solace_agent_mesh/agent/adk/adk_llm.txt +93 -0
- solace_agent_mesh/agent/adk/app_llm_agent.py +26 -0
- solace_agent_mesh/agent/adk/callbacks.py +1716 -0
- solace_agent_mesh/agent/adk/filesystem_artifact_service.py +381 -0
- solace_agent_mesh/agent/adk/invocation_monitor.py +295 -0
- solace_agent_mesh/agent/adk/models/lite_llm.py +872 -0
- solace_agent_mesh/agent/adk/models/models_llm.txt +94 -0
- solace_agent_mesh/agent/adk/runner.py +357 -0
- solace_agent_mesh/agent/adk/services.py +240 -0
- solace_agent_mesh/agent/adk/setup.py +751 -0
- solace_agent_mesh/agent/adk/stream_parser.py +214 -0
- solace_agent_mesh/agent/adk/tool_wrapper.py +139 -0
- solace_agent_mesh/agent/agent_llm.txt +41 -0
- solace_agent_mesh/agent/protocol/event_handlers.py +1444 -0
- solace_agent_mesh/agent/protocol/protocol_llm.txt +21 -0
- solace_agent_mesh/agent/sac/app.py +640 -0
- solace_agent_mesh/agent/sac/component.py +3496 -0
- solace_agent_mesh/agent/sac/patch_adk.py +111 -0
- solace_agent_mesh/agent/sac/sac_llm.txt +105 -0
- solace_agent_mesh/agent/sac/task_execution_context.py +185 -0
- solace_agent_mesh/agent/testing/__init__.py +3 -0
- solace_agent_mesh/agent/testing/debug_utils.py +135 -0
- solace_agent_mesh/agent/testing/testing_llm.txt +90 -0
- solace_agent_mesh/agent/tools/__init__.py +14 -0
- solace_agent_mesh/agent/tools/audio_tools.py +1622 -0
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +1954 -0
- solace_agent_mesh/agent/tools/builtin_data_analysis_tools.py +238 -0
- solace_agent_mesh/agent/tools/general_agent_tools.py +571 -0
- solace_agent_mesh/agent/tools/image_tools.py +1184 -0
- solace_agent_mesh/agent/tools/peer_agent_tool.py +290 -0
- solace_agent_mesh/agent/tools/registry.py +36 -0
- solace_agent_mesh/agent/tools/test_tools.py +135 -0
- solace_agent_mesh/agent/tools/tool_definition.py +45 -0
- solace_agent_mesh/agent/tools/tools_llm.txt +104 -0
- solace_agent_mesh/agent/tools/web_tools.py +381 -0
- solace_agent_mesh/agent/utils/artifact_helpers.py +927 -0
- solace_agent_mesh/agent/utils/config_parser.py +47 -0
- solace_agent_mesh/agent/utils/context_helpers.py +60 -0
- solace_agent_mesh/agent/utils/utils_llm.txt +153 -0
- solace_agent_mesh/assets/docs/404.html +16 -0
- solace_agent_mesh/assets/docs/assets/css/styles.906a1503.css +1 -0
- solace_agent_mesh/assets/docs/assets/images/Solace_AI_Framework_With_Broker-85f0a306a9bcdd20b390b7a949f6d862.png +0 -0
- solace_agent_mesh/assets/docs/assets/images/sac-flows-80d5b603c6aafd33e87945680ce0abf3.png +0 -0
- solace_agent_mesh/assets/docs/assets/images/sac_parts_of_a_component-cb3d0424b1d0c17734c5435cca6b4082.png +0 -0
- solace_agent_mesh/assets/docs/assets/js/04989206.674a8007.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/0e682baa.79f0ab22.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1001.0182a8bd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1023fc19.015679ca.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1039.0bd46aa1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/149.b797a808.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1523c6b4.91c7bc01.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/165.6a39807d.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/165.6a39807d.js.LICENSE.txt +9 -0
- solace_agent_mesh/assets/docs/assets/js/166ab619.7d97ccaf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js.LICENSE.txt +7 -0
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.a8c5ce5a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2130.ab9fd314.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/21ceee5f.614fa8dd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2237.5e477fc6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2334.622a6395.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2a9cab12.8909df92.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3219.adc1d663.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/332e10b5.7a103f42.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3624.b524e433.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/375.708d48db.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3834.b6cd790e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3d406171.f722eaf5.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4250.95455b28.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.36090198.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4356.d169ab5b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/442a8107.5ba94b65.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4458.518e66fa.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4488.c7cc3442.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4494.6ee23046.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4855.fc4444b6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4866.22daefc0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4950.ca4caeda.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4c2787c2.66ee00e9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5388.7a136447.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55f47984.c484bf96.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5607.081356f8.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5864.b0d0e9de.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5b4258a4.bda20761.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5e95c892.558d5167.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6143.0a1464c9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6395.e9c73649.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6796.51d2c9b7.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6976.379be23b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6978.ee0b945c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7040.cb436723.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7195.412f418a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7280.3fb73bdb.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/768e31b0.a12673db.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7845.e33e7c4c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7900.69516146.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8356.8a379c04.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/85387663.6bf41934.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8567.4732c6b7.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8573.cb04eda5.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8577.1d54e766.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8591.d7c16be6.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/8591.d7c16be6.js.LICENSE.txt +61 -0
- solace_agent_mesh/assets/docs/assets/js/8709.7ecd4047.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8731.49e930c2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8908.f9d1b506.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9157.b4093d07.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9278.a4fd875d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/945fb41e.74d728aa.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9616.b75c2f6d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9793.c6d16376.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.1bf8f61c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.26ca071f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a7bd4aaa.2204d2f7.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a94703ab.0438dbc2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/aba21aa0.c42a534c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/aba87c2f.d3e2dcc3.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ae4415af.8e279b5d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/b7006a3a.40b10c9d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/bac0be12.f50d9bac.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/bb2ef573.207e6990.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c2c06897.63b76e9e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cc969b05.954186d4.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cd3d4052.ca6eed8c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ced92a13.fb92e7ca.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cee5d587.f5b73ca1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.ecc3d195.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f897a61a.f8c53b0f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/fbfa3e75.aca209c9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.c6286d7c.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/main.c6286d7c.js.LICENSE.txt +81 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.d5133813.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +128 -0
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +91 -0
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +201 -0
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +91 -0
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +55 -0
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +82 -0
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +77 -0
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +48 -0
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +54 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +17 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +45 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +76 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +150 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +54 -0
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +267 -0
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +136 -0
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +116 -0
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +80 -0
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +164 -0
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +57 -0
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +72 -0
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +102 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +99 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +90 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +107 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +152 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +103 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +170 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +200 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +54 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +69 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +59 -0
- solace_agent_mesh/assets/docs/img/Solace_AI_Framework_README.png +0 -0
- solace_agent_mesh/assets/docs/img/Solace_AI_Framework_With_Broker.png +0 -0
- solace_agent_mesh/assets/docs/img/logo.png +0 -0
- solace_agent_mesh/assets/docs/img/sac-flows.png +0 -0
- solace_agent_mesh/assets/docs/img/sac_parts_of_a_component.png +0 -0
- solace_agent_mesh/assets/docs/img/solace-logo.png +0 -0
- solace_agent_mesh/assets/docs/lunr-index-1754075282978.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -0
- solace_agent_mesh/assets/docs/search-doc-1754075282978.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -0
- solace_agent_mesh/assets/docs/sitemap.xml +1 -0
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add_cmd/__init__.py +15 -0
- solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +250 -0
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +659 -0
- solace_agent_mesh/cli/commands/add_cmd/gateway_cmd.py +322 -0
- solace_agent_mesh/cli/commands/add_cmd/web_add_agent_step.py +93 -0
- solace_agent_mesh/cli/commands/add_cmd/web_add_gateway_step.py +118 -0
- solace_agent_mesh/cli/commands/docs_cmd.py +57 -0
- solace_agent_mesh/cli/commands/eval_cmd.py +64 -0
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +404 -0
- solace_agent_mesh/cli/commands/init_cmd/broker_step.py +201 -0
- solace_agent_mesh/cli/commands/init_cmd/directory_step.py +28 -0
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +205 -0
- solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +365 -0
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +407 -0
- solace_agent_mesh/cli/commands/init_cmd/project_files_step.py +38 -0
- solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +110 -0
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +183 -0
- solace_agent_mesh/cli/commands/plugin_cmd/__init__.py +18 -0
- solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +372 -0
- solace_agent_mesh/cli/commands/plugin_cmd/build_cmd.py +86 -0
- solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +139 -0
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +309 -0
- solace_agent_mesh/cli/commands/plugin_cmd/official_registry.py +175 -0
- solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +305 -0
- solace_agent_mesh/cli/commands/run_cmd.py +158 -0
- solace_agent_mesh/cli/main.py +17 -294
- solace_agent_mesh/cli/utils.py +135 -204
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-DvlO62me.js +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/client-bp6u3qVZ.js +49 -0
- solace_agent_mesh/client/webui/frontend/static/assets/favicon-BLgzUch9.ico +0 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-D11Lmy9p.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-Gfk3BYn5.js +663 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +14 -0
- solace_agent_mesh/client/webui/frontend/static/index.html +15 -0
- solace_agent_mesh/common/__init__.py +1 -0
- solace_agent_mesh/common/a2a_protocol.py +564 -0
- solace_agent_mesh/common/agent_registry.py +42 -0
- solace_agent_mesh/common/client/__init__.py +4 -0
- solace_agent_mesh/common/client/card_resolver.py +21 -0
- solace_agent_mesh/common/client/client.py +85 -0
- solace_agent_mesh/common/client/client_llm.txt +133 -0
- solace_agent_mesh/common/common_llm.txt +144 -0
- solace_agent_mesh/common/constants.py +1 -14
- solace_agent_mesh/common/middleware/__init__.py +12 -0
- solace_agent_mesh/common/middleware/config_resolver.py +130 -0
- solace_agent_mesh/common/middleware/middleware_llm.txt +174 -0
- solace_agent_mesh/common/middleware/registry.py +125 -0
- solace_agent_mesh/common/server/__init__.py +4 -0
- solace_agent_mesh/common/server/server.py +122 -0
- solace_agent_mesh/common/server/server_llm.txt +169 -0
- solace_agent_mesh/common/server/task_manager.py +291 -0
- solace_agent_mesh/common/server/utils.py +28 -0
- solace_agent_mesh/common/services/__init__.py +4 -0
- solace_agent_mesh/common/services/employee_service.py +162 -0
- solace_agent_mesh/common/services/identity_service.py +129 -0
- solace_agent_mesh/common/services/providers/__init__.py +4 -0
- solace_agent_mesh/common/services/providers/local_file_identity_service.py +148 -0
- solace_agent_mesh/common/services/providers/providers_llm.txt +113 -0
- solace_agent_mesh/common/services/services_llm.txt +132 -0
- solace_agent_mesh/common/types.py +411 -0
- solace_agent_mesh/common/utils/__init__.py +7 -0
- solace_agent_mesh/common/utils/asyncio_macos_fix.py +86 -0
- solace_agent_mesh/common/utils/embeds/__init__.py +33 -0
- solace_agent_mesh/common/utils/embeds/constants.py +55 -0
- solace_agent_mesh/common/utils/embeds/converter.py +452 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +124 -0
- solace_agent_mesh/common/utils/embeds/evaluators.py +394 -0
- solace_agent_mesh/common/utils/embeds/modifiers.py +816 -0
- solace_agent_mesh/common/utils/embeds/resolver.py +865 -0
- solace_agent_mesh/common/utils/embeds/types.py +14 -0
- solace_agent_mesh/common/utils/in_memory_cache.py +108 -0
- solace_agent_mesh/common/utils/initializer.py +51 -0
- solace_agent_mesh/common/utils/log_formatters.py +44 -0
- solace_agent_mesh/common/utils/mime_helpers.py +106 -0
- solace_agent_mesh/common/utils/push_notification_auth.py +134 -0
- solace_agent_mesh/common/utils/utils_llm.txt +67 -0
- solace_agent_mesh/config_portal/backend/common.py +66 -24
- solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +24 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/models.py +49 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/registry_manager.py +164 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/scraper.py +521 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog_server.py +217 -0
- solace_agent_mesh/config_portal/backend/server.py +551 -181
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-_7yox_eh.js +48 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/components-B7lKcHVY.js +140 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-DX1misIU.js → entry.client-CEumGClk.js} +3 -3
- solace_agent_mesh/config_portal/frontend/static/client/assets/index-DSo1AH_7.js +68 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-e5c3acfe.js +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{root-BApq5dPK.js → root-C4XmHinv.js} +2 -2
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-DxRwaWiE.css +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
- solace_agent_mesh/core_a2a/__init__.py +1 -0
- solace_agent_mesh/core_a2a/core_a2a_llm.txt +88 -0
- solace_agent_mesh/core_a2a/service.py +331 -0
- solace_agent_mesh/evaluation/config_loader.py +657 -0
- solace_agent_mesh/evaluation/evaluator.py +667 -0
- solace_agent_mesh/evaluation/message_organizer.py +568 -0
- solace_agent_mesh/evaluation/report/benchmark_info.html +35 -0
- solace_agent_mesh/evaluation/report/chart_section.html +141 -0
- solace_agent_mesh/evaluation/report/detailed_breakdown.html +28 -0
- solace_agent_mesh/evaluation/report/modal.html +59 -0
- solace_agent_mesh/evaluation/report/modal_chart_functions.js +411 -0
- solace_agent_mesh/evaluation/report/modal_script.js +296 -0
- solace_agent_mesh/evaluation/report/modal_styles.css +340 -0
- solace_agent_mesh/evaluation/report/performance_metrics_styles.css +93 -0
- solace_agent_mesh/evaluation/report/templates/footer.html +2 -0
- solace_agent_mesh/evaluation/report/templates/header.html +340 -0
- solace_agent_mesh/evaluation/report_data_processor.py +972 -0
- solace_agent_mesh/evaluation/report_generator.py +613 -0
- solace_agent_mesh/evaluation/run.py +613 -0
- solace_agent_mesh/evaluation/subscriber.py +872 -0
- solace_agent_mesh/evaluation/summary_builder.py +775 -0
- solace_agent_mesh/evaluation/test_case_loader.py +714 -0
- solace_agent_mesh/gateway/base/__init__.py +1 -0
- solace_agent_mesh/gateway/base/app.py +266 -0
- solace_agent_mesh/gateway/base/base_llm.txt +119 -0
- solace_agent_mesh/gateway/base/component.py +1542 -0
- solace_agent_mesh/gateway/base/task_context.py +74 -0
- solace_agent_mesh/gateway/gateway_llm.txt +125 -0
- solace_agent_mesh/gateway/http_sse/app.py +190 -0
- solace_agent_mesh/gateway/http_sse/component.py +1602 -0
- solace_agent_mesh/gateway/http_sse/components/__init__.py +7 -0
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +65 -0
- solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +108 -0
- solace_agent_mesh/gateway/http_sse/dependencies.py +316 -0
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +63 -0
- solace_agent_mesh/gateway/http_sse/main.py +442 -0
- solace_agent_mesh/gateway/http_sse/routers/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/routers/agents.py +41 -0
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +827 -0
- solace_agent_mesh/gateway/http_sse/routers/auth.py +212 -0
- solace_agent_mesh/gateway/http_sse/routers/config.py +55 -0
- solace_agent_mesh/gateway/http_sse/routers/people.py +69 -0
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +37 -0
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +80 -0
- solace_agent_mesh/gateway/http_sse/routers/sse.py +138 -0
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +294 -0
- solace_agent_mesh/gateway/http_sse/routers/users.py +59 -0
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +1131 -0
- solace_agent_mesh/gateway/http_sse/services/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/services/agent_service.py +69 -0
- solace_agent_mesh/gateway/http_sse/services/people_service.py +158 -0
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +179 -0
- solace_agent_mesh/gateway/http_sse/services/task_service.py +121 -0
- solace_agent_mesh/gateway/http_sse/session_manager.py +187 -0
- solace_agent_mesh/gateway/http_sse/sse_manager.py +328 -0
- solace_agent_mesh/llm.txt +228 -0
- solace_agent_mesh/llm_detail.txt +2835 -0
- solace_agent_mesh/templates/agent_template.yaml +53 -0
- solace_agent_mesh/templates/eval_backend_template.yaml +54 -0
- solace_agent_mesh/templates/gateway_app_template.py +73 -0
- solace_agent_mesh/templates/gateway_component_template.py +431 -0
- solace_agent_mesh/templates/gateway_config_template.yaml +43 -0
- solace_agent_mesh/templates/logging_config_template.ini +64 -0
- solace_agent_mesh/templates/main_orchestrator.yaml +55 -0
- solace_agent_mesh/templates/plugin_agent_config_template.yaml +122 -0
- solace_agent_mesh/templates/plugin_custom_config_template.yaml +27 -0
- solace_agent_mesh/templates/plugin_custom_template.py +10 -0
- solace_agent_mesh/templates/plugin_gateway_config_template.yaml +63 -0
- solace_agent_mesh/templates/plugin_pyproject_template.toml +33 -0
- solace_agent_mesh/templates/plugin_readme_template.md +34 -0
- solace_agent_mesh/templates/plugin_tools_template.py +224 -0
- solace_agent_mesh/templates/shared_config.yaml +66 -0
- solace_agent_mesh/templates/templates_llm.txt +147 -0
- solace_agent_mesh/templates/webui.yaml +53 -0
- solace_agent_mesh-1.0.2.dist-info/METADATA +432 -0
- solace_agent_mesh-1.0.2.dist-info/RECORD +361 -0
- solace_agent_mesh-1.0.2.dist-info/entry_points.txt +3 -0
- {solace_agent_mesh-0.2.4.dist-info → solace_agent_mesh-1.0.2.dist-info}/licenses/LICENSE +1 -1
- solace_agent_mesh/agents/base_agent_component.py +0 -256
- solace_agent_mesh/agents/global/actions/agent_state_change.py +0 -54
- solace_agent_mesh/agents/global/actions/clear_history.py +0 -32
- solace_agent_mesh/agents/global/actions/convert_file_to_markdown.py +0 -160
- solace_agent_mesh/agents/global/actions/create_file.py +0 -70
- solace_agent_mesh/agents/global/actions/error_action.py +0 -45
- solace_agent_mesh/agents/global/actions/plantuml_diagram.py +0 -163
- solace_agent_mesh/agents/global/actions/plotly_graph.py +0 -152
- solace_agent_mesh/agents/global/actions/retrieve_file.py +0 -51
- solace_agent_mesh/agents/global/global_agent_component.py +0 -38
- solace_agent_mesh/agents/image_processing/actions/create_image.py +0 -75
- solace_agent_mesh/agents/image_processing/actions/describe_image.py +0 -115
- solace_agent_mesh/agents/image_processing/image_processing_agent_component.py +0 -23
- solace_agent_mesh/agents/slack/__init__.py +0 -1
- solace_agent_mesh/agents/slack/actions/__init__.py +0 -1
- solace_agent_mesh/agents/slack/actions/post_message.py +0 -177
- solace_agent_mesh/agents/slack/slack_agent_component.py +0 -59
- solace_agent_mesh/agents/web_request/actions/do_image_search.py +0 -84
- solace_agent_mesh/agents/web_request/actions/do_news_search.py +0 -47
- solace_agent_mesh/agents/web_request/actions/do_suggestion_search.py +0 -34
- solace_agent_mesh/agents/web_request/actions/do_web_request.py +0 -135
- solace_agent_mesh/agents/web_request/actions/download_file.py +0 -69
- solace_agent_mesh/agents/web_request/web_request_agent_component.py +0 -33
- solace_agent_mesh/assets/web-visualizer/assets/index-D0qORgkg.css +0 -1
- solace_agent_mesh/assets/web-visualizer/assets/index-DnDr1pnu.js +0 -109
- solace_agent_mesh/assets/web-visualizer/index.html +0 -14
- solace_agent_mesh/assets/web-visualizer/vite.svg +0 -1
- solace_agent_mesh/cli/commands/add/__init__.py +0 -3
- solace_agent_mesh/cli/commands/add/add.py +0 -88
- solace_agent_mesh/cli/commands/add/agent.py +0 -110
- solace_agent_mesh/cli/commands/add/copy_from_plugin.py +0 -92
- solace_agent_mesh/cli/commands/add/gateway.py +0 -374
- solace_agent_mesh/cli/commands/build.py +0 -670
- solace_agent_mesh/cli/commands/chat/__init__.py +0 -3
- solace_agent_mesh/cli/commands/chat/chat.py +0 -361
- solace_agent_mesh/cli/commands/config.py +0 -29
- solace_agent_mesh/cli/commands/init/__init__.py +0 -3
- solace_agent_mesh/cli/commands/init/ai_provider_step.py +0 -93
- solace_agent_mesh/cli/commands/init/broker_step.py +0 -99
- solace_agent_mesh/cli/commands/init/builtin_agent_step.py +0 -83
- solace_agent_mesh/cli/commands/init/check_if_already_done.py +0 -13
- solace_agent_mesh/cli/commands/init/create_config_file_step.py +0 -65
- solace_agent_mesh/cli/commands/init/create_other_project_files_step.py +0 -147
- solace_agent_mesh/cli/commands/init/file_service_step.py +0 -73
- solace_agent_mesh/cli/commands/init/init.py +0 -92
- solace_agent_mesh/cli/commands/init/project_structure_step.py +0 -16
- solace_agent_mesh/cli/commands/init/web_init_step.py +0 -32
- solace_agent_mesh/cli/commands/plugin/__init__.py +0 -3
- solace_agent_mesh/cli/commands/plugin/add.py +0 -100
- solace_agent_mesh/cli/commands/plugin/build.py +0 -268
- solace_agent_mesh/cli/commands/plugin/create.py +0 -117
- solace_agent_mesh/cli/commands/plugin/plugin.py +0 -124
- solace_agent_mesh/cli/commands/plugin/remove.py +0 -73
- solace_agent_mesh/cli/commands/run.py +0 -68
- solace_agent_mesh/cli/commands/visualizer.py +0 -138
- solace_agent_mesh/cli/config.py +0 -85
- solace_agent_mesh/common/action.py +0 -91
- solace_agent_mesh/common/action_list.py +0 -37
- solace_agent_mesh/common/action_response.py +0 -340
- solace_agent_mesh/common/mysql_database.py +0 -40
- solace_agent_mesh/common/postgres_database.py +0 -85
- solace_agent_mesh/common/prompt_templates.py +0 -28
- solace_agent_mesh/common/stimulus_utils.py +0 -152
- solace_agent_mesh/common/time.py +0 -24
- solace_agent_mesh/common/utils.py +0 -712
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-a-zJ6rLx.js +0 -46
- solace_agent_mesh/config_portal/frontend/static/client/assets/components-ZIfdTbrV.js +0 -191
- solace_agent_mesh/config_portal/frontend/static/client/assets/index-BJHAE5s4.js +0 -17
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-44c41103.js +0 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-DX4gQ516.css +0 -1
- solace_agent_mesh/configs/agent_global.yaml +0 -74
- solace_agent_mesh/configs/agent_image_processing.yaml +0 -82
- solace_agent_mesh/configs/agent_slack.yaml +0 -64
- solace_agent_mesh/configs/agent_web_request.yaml +0 -75
- solace_agent_mesh/configs/conversation_to_file.yaml +0 -56
- solace_agent_mesh/configs/error_catcher.yaml +0 -56
- solace_agent_mesh/configs/monitor.yaml +0 -0
- solace_agent_mesh/configs/monitor_stim_and_errors_to_slack.yaml +0 -109
- solace_agent_mesh/configs/monitor_user_feedback.yaml +0 -58
- solace_agent_mesh/configs/orchestrator.yaml +0 -241
- solace_agent_mesh/configs/service_embedding.yaml +0 -81
- solace_agent_mesh/configs/service_llm.yaml +0 -265
- solace_agent_mesh/configs/visualize_websocket.yaml +0 -55
- solace_agent_mesh/gateway/components/gateway_base.py +0 -47
- solace_agent_mesh/gateway/components/gateway_input.py +0 -278
- solace_agent_mesh/gateway/components/gateway_output.py +0 -298
- solace_agent_mesh/gateway/identity/bamboohr_identity.py +0 -18
- solace_agent_mesh/gateway/identity/identity_base.py +0 -10
- solace_agent_mesh/gateway/identity/identity_provider.py +0 -60
- solace_agent_mesh/gateway/identity/no_identity.py +0 -9
- solace_agent_mesh/gateway/identity/passthru_identity.py +0 -9
- solace_agent_mesh/monitors/base_monitor_component.py +0 -26
- solace_agent_mesh/monitors/feedback/user_feedback_monitor.py +0 -75
- solace_agent_mesh/monitors/stim_and_errors/stim_and_error_monitor.py +0 -560
- solace_agent_mesh/orchestrator/__init__.py +0 -0
- solace_agent_mesh/orchestrator/action_manager.py +0 -237
- solace_agent_mesh/orchestrator/components/__init__.py +0 -0
- solace_agent_mesh/orchestrator/components/orchestrator_action_manager_timeout_component.py +0 -58
- solace_agent_mesh/orchestrator/components/orchestrator_action_response_component.py +0 -179
- solace_agent_mesh/orchestrator/components/orchestrator_register_component.py +0 -107
- solace_agent_mesh/orchestrator/components/orchestrator_stimulus_processor_component.py +0 -527
- solace_agent_mesh/orchestrator/components/orchestrator_streaming_output_component.py +0 -260
- solace_agent_mesh/orchestrator/orchestrator_main.py +0 -172
- solace_agent_mesh/orchestrator/orchestrator_prompt.py +0 -539
- solace_agent_mesh/services/__init__.py +0 -0
- solace_agent_mesh/services/authorization/providers/base_authorization_provider.py +0 -56
- solace_agent_mesh/services/bamboo_hr_service/__init__.py +0 -3
- solace_agent_mesh/services/bamboo_hr_service/bamboo_hr.py +0 -182
- solace_agent_mesh/services/common/__init__.py +0 -4
- solace_agent_mesh/services/common/auto_expiry.py +0 -45
- solace_agent_mesh/services/common/singleton.py +0 -18
- solace_agent_mesh/services/file_service/__init__.py +0 -14
- solace_agent_mesh/services/file_service/file_manager/__init__.py +0 -0
- solace_agent_mesh/services/file_service/file_manager/bucket_file_manager.py +0 -149
- solace_agent_mesh/services/file_service/file_manager/file_manager_base.py +0 -162
- solace_agent_mesh/services/file_service/file_manager/memory_file_manager.py +0 -64
- solace_agent_mesh/services/file_service/file_manager/volume_file_manager.py +0 -106
- solace_agent_mesh/services/file_service/file_service.py +0 -437
- solace_agent_mesh/services/file_service/file_service_constants.py +0 -54
- solace_agent_mesh/services/file_service/file_transformations.py +0 -141
- solace_agent_mesh/services/file_service/file_utils.py +0 -324
- solace_agent_mesh/services/file_service/transformers/__init__.py +0 -5
- solace_agent_mesh/services/history_service/__init__.py +0 -3
- solace_agent_mesh/services/history_service/history_providers/__init__.py +0 -0
- solace_agent_mesh/services/history_service/history_providers/base_history_provider.py +0 -54
- solace_agent_mesh/services/history_service/history_providers/file_history_provider.py +0 -74
- solace_agent_mesh/services/history_service/history_providers/index.py +0 -40
- solace_agent_mesh/services/history_service/history_providers/memory_history_provider.py +0 -33
- solace_agent_mesh/services/history_service/history_providers/mongodb_history_provider.py +0 -66
- solace_agent_mesh/services/history_service/history_providers/redis_history_provider.py +0 -66
- solace_agent_mesh/services/history_service/history_providers/sql_history_provider.py +0 -93
- solace_agent_mesh/services/history_service/history_service.py +0 -413
- solace_agent_mesh/services/history_service/long_term_memory/__init__.py +0 -0
- solace_agent_mesh/services/history_service/long_term_memory/long_term_memory.py +0 -399
- solace_agent_mesh/services/llm_service/components/llm_request_component.py +0 -340
- solace_agent_mesh/services/llm_service/components/llm_service_component_base.py +0 -152
- solace_agent_mesh/services/middleware_service/__init__.py +0 -0
- solace_agent_mesh/services/middleware_service/middleware_service.py +0 -20
- solace_agent_mesh/templates/action.py +0 -38
- solace_agent_mesh/templates/agent.py +0 -29
- solace_agent_mesh/templates/agent.yaml +0 -70
- solace_agent_mesh/templates/gateway-config-template.yaml +0 -6
- solace_agent_mesh/templates/gateway-default-config.yaml +0 -28
- solace_agent_mesh/templates/gateway-flows.yaml +0 -78
- solace_agent_mesh/templates/gateway-header.yaml +0 -16
- solace_agent_mesh/templates/gateway_base.py +0 -15
- solace_agent_mesh/templates/gateway_input.py +0 -98
- solace_agent_mesh/templates/gateway_output.py +0 -71
- solace_agent_mesh/templates/plugin-gateway-default-config.yaml +0 -29
- solace_agent_mesh/templates/plugin-pyproject.toml +0 -30
- solace_agent_mesh/templates/rest-api-default-config.yaml +0 -31
- solace_agent_mesh/templates/rest-api-flows.yaml +0 -81
- solace_agent_mesh/templates/slack-default-config.yaml +0 -16
- solace_agent_mesh/templates/slack-flows.yaml +0 -81
- solace_agent_mesh/templates/solace-agent-mesh-default.yaml +0 -86
- solace_agent_mesh/templates/solace-agent-mesh-plugin-default.yaml +0 -8
- solace_agent_mesh/templates/web-default-config.yaml +0 -10
- solace_agent_mesh/templates/web-flows.yaml +0 -76
- solace_agent_mesh/tools/__init__.py +0 -0
- solace_agent_mesh/tools/components/__init__.py +0 -0
- solace_agent_mesh/tools/components/conversation_formatter.py +0 -111
- solace_agent_mesh/tools/components/file_resolver_component.py +0 -58
- solace_agent_mesh/tools/config/runtime_config.py +0 -26
- solace_agent_mesh-0.2.4.dist-info/METADATA +0 -176
- solace_agent_mesh-0.2.4.dist-info/RECORD +0 -193
- solace_agent_mesh-0.2.4.dist-info/entry_points.txt +0 -3
- /solace_agent_mesh/{agents → agent}/__init__.py +0 -0
- /solace_agent_mesh/{agents/global → agent/adk}/__init__.py +0 -0
- /solace_agent_mesh/{agents/global/actions → agent/protocol}/__init__.py +0 -0
- /solace_agent_mesh/{agents/image_processing → agent/sac}/__init__.py +0 -0
- /solace_agent_mesh/{agents/image_processing/actions → agent/utils}/__init__.py +0 -0
- /solace_agent_mesh/{agents/web_request → config_portal/backend/plugin_catalog}/__init__.py +0 -0
- /solace_agent_mesh/{agents/web_request/actions → evaluation}/__init__.py +0 -0
- /solace_agent_mesh/gateway/{components → http_sse}/__init__.py +0 -0
- {solace_agent_mesh-0.2.4.dist-info → solace_agent_mesh-1.0.2.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,827 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FastAPI router for managing session-specific artifacts via REST endpoints.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import (
|
|
6
|
+
List,
|
|
7
|
+
Dict,
|
|
8
|
+
Optional,
|
|
9
|
+
Union,
|
|
10
|
+
Any,
|
|
11
|
+
TYPE_CHECKING,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from fastapi import (
|
|
15
|
+
APIRouter,
|
|
16
|
+
Depends,
|
|
17
|
+
HTTPException,
|
|
18
|
+
UploadFile,
|
|
19
|
+
File,
|
|
20
|
+
Path,
|
|
21
|
+
status,
|
|
22
|
+
Form,
|
|
23
|
+
)
|
|
24
|
+
from fastapi.responses import StreamingResponse, Response
|
|
25
|
+
from google.adk.artifacts import BaseArtifactService
|
|
26
|
+
import io
|
|
27
|
+
import json
|
|
28
|
+
from datetime import datetime, timezone
|
|
29
|
+
from urllib.parse import urlparse, parse_qs, quote
|
|
30
|
+
|
|
31
|
+
from ..dependencies import (
|
|
32
|
+
get_shared_artifact_service,
|
|
33
|
+
get_sac_component,
|
|
34
|
+
ensure_session_id,
|
|
35
|
+
get_user_id,
|
|
36
|
+
get_config_resolver,
|
|
37
|
+
get_user_config,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
from solace_ai_connector.common.log import log
|
|
41
|
+
|
|
42
|
+
from ....common.middleware import ConfigResolver
|
|
43
|
+
from ....common.types import ArtifactInfo
|
|
44
|
+
from ....common.utils.mime_helpers import is_text_based_mime_type
|
|
45
|
+
from ....common.utils.embeds import (
|
|
46
|
+
resolve_embeds_recursively_in_string,
|
|
47
|
+
evaluate_embed,
|
|
48
|
+
LATE_EMBED_TYPES,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if TYPE_CHECKING:
|
|
53
|
+
from ....gateway.http_sse.component import WebUIBackendComponent
|
|
54
|
+
from ....agent.utils.artifact_helpers import (
|
|
55
|
+
get_artifact_info_list,
|
|
56
|
+
save_artifact_with_metadata,
|
|
57
|
+
load_artifact_content_or_metadata,
|
|
58
|
+
DEFAULT_SCHEMA_MAX_KEYS,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
router = APIRouter()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@router.get(
|
|
65
|
+
"/{filename}/versions",
|
|
66
|
+
response_model=List[int],
|
|
67
|
+
summary="List Artifact Versions",
|
|
68
|
+
description="Retrieves a list of available version numbers for a specific artifact.",
|
|
69
|
+
)
|
|
70
|
+
async def list_artifact_versions(
|
|
71
|
+
filename: str = Path(..., title="Filename", description="The name of the artifact"),
|
|
72
|
+
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
73
|
+
user_id: str = Depends(get_user_id),
|
|
74
|
+
session_id: str = Depends(ensure_session_id),
|
|
75
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
76
|
+
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
77
|
+
user_config: dict = Depends(get_user_config),
|
|
78
|
+
):
|
|
79
|
+
"""
|
|
80
|
+
Lists the available integer versions for a given artifact filename
|
|
81
|
+
associated with the current user and session ID.
|
|
82
|
+
"""
|
|
83
|
+
if not config_resolver.is_feature_enabled(
|
|
84
|
+
user_config, {"required_scopes": ["tool:artifact:list"]}, {}
|
|
85
|
+
):
|
|
86
|
+
raise HTTPException(
|
|
87
|
+
status_code=403, detail="Not authorized to list artifact versions"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
log_prefix = f"[ArtifactRouter:ListVersions:{filename}] User={user_id}, Session={session_id} -"
|
|
91
|
+
log.info("%s Request received.", log_prefix)
|
|
92
|
+
|
|
93
|
+
if artifact_service is None:
|
|
94
|
+
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
95
|
+
raise HTTPException(
|
|
96
|
+
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
|
97
|
+
detail="Artifact service is not configured.",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
if not hasattr(artifact_service, "list_versions"):
|
|
101
|
+
log.warning(
|
|
102
|
+
"%s Configured artifact service (%s) does not support listing versions.",
|
|
103
|
+
log_prefix,
|
|
104
|
+
type(artifact_service).__name__,
|
|
105
|
+
)
|
|
106
|
+
raise HTTPException(
|
|
107
|
+
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
|
108
|
+
detail=f"Version listing not supported by the configured '{type(artifact_service).__name__}' artifact service.",
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
app_name = component.get_config("name", "A2A_WebUI_App")
|
|
113
|
+
|
|
114
|
+
versions = await artifact_service.list_versions(
|
|
115
|
+
app_name=app_name,
|
|
116
|
+
user_id=user_id,
|
|
117
|
+
session_id=session_id,
|
|
118
|
+
filename=filename,
|
|
119
|
+
)
|
|
120
|
+
log.info("%s Found versions: %s", log_prefix, versions)
|
|
121
|
+
return versions
|
|
122
|
+
except FileNotFoundError:
|
|
123
|
+
log.warning("%s Artifact not found.", log_prefix)
|
|
124
|
+
raise HTTPException(
|
|
125
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
126
|
+
detail=f"Artifact '{filename}' not found for this session.",
|
|
127
|
+
)
|
|
128
|
+
except Exception as e:
|
|
129
|
+
log.exception("%s Error listing artifact versions: %s", log_prefix, e)
|
|
130
|
+
raise HTTPException(
|
|
131
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
132
|
+
detail=f"Failed to list artifact versions: {str(e)}",
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@router.get(
|
|
137
|
+
"/",
|
|
138
|
+
response_model=List[ArtifactInfo],
|
|
139
|
+
summary="List Artifact Information",
|
|
140
|
+
description="Retrieves detailed information for artifacts available for the current user session.",
|
|
141
|
+
)
|
|
142
|
+
async def list_artifacts(
|
|
143
|
+
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
144
|
+
user_id: str = Depends(get_user_id),
|
|
145
|
+
session_id: str = Depends(ensure_session_id),
|
|
146
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
147
|
+
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
148
|
+
user_config: dict = Depends(get_user_config),
|
|
149
|
+
):
|
|
150
|
+
"""
|
|
151
|
+
Lists detailed information (filename, size, type, modified date, uri)
|
|
152
|
+
for all artifacts associated with the current user and session ID
|
|
153
|
+
by calling the artifact helper function.
|
|
154
|
+
"""
|
|
155
|
+
if not config_resolver.is_feature_enabled(
|
|
156
|
+
user_config, {"required_scopes": ["tool:artifact:list"]}, {}
|
|
157
|
+
):
|
|
158
|
+
raise HTTPException(status_code=403, detail="Not authorized to list artifacts")
|
|
159
|
+
|
|
160
|
+
log_prefix = f"[ArtifactRouter:ListInfo] User={user_id}, Session={session_id} -"
|
|
161
|
+
log.info("%s Request received.", log_prefix)
|
|
162
|
+
|
|
163
|
+
if artifact_service is None:
|
|
164
|
+
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
165
|
+
raise HTTPException(
|
|
166
|
+
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
|
167
|
+
detail="Artifact service is not configured.",
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
app_name = component.get_config("name", "A2A_WebUI_App")
|
|
172
|
+
|
|
173
|
+
artifact_info_list = await get_artifact_info_list(
|
|
174
|
+
artifact_service=artifact_service,
|
|
175
|
+
app_name=app_name,
|
|
176
|
+
user_id=user_id,
|
|
177
|
+
session_id=session_id,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
log.info(
|
|
181
|
+
"%s Returning %d artifact details.", log_prefix, len(artifact_info_list)
|
|
182
|
+
)
|
|
183
|
+
return artifact_info_list
|
|
184
|
+
|
|
185
|
+
except Exception as e:
|
|
186
|
+
log.exception(
|
|
187
|
+
"%s Error retrieving artifact details via helper: %s", log_prefix, e
|
|
188
|
+
)
|
|
189
|
+
raise HTTPException(
|
|
190
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
191
|
+
detail=f"Failed to retrieve artifact details: {str(e)}",
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@router.get(
|
|
196
|
+
"/{filename}",
|
|
197
|
+
summary="Get Latest Artifact Content",
|
|
198
|
+
description="Retrieves the content of the latest version of a specific artifact.",
|
|
199
|
+
)
|
|
200
|
+
async def get_latest_artifact(
|
|
201
|
+
filename: str = Path(..., title="Filename", description="The name of the artifact"),
|
|
202
|
+
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
203
|
+
user_id: str = Depends(get_user_id),
|
|
204
|
+
session_id: str = Depends(ensure_session_id),
|
|
205
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
206
|
+
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
207
|
+
user_config: dict = Depends(get_user_config),
|
|
208
|
+
):
|
|
209
|
+
"""
|
|
210
|
+
Retrieves the content of the latest version of the specified artifact
|
|
211
|
+
associated with the current user and session ID.
|
|
212
|
+
"""
|
|
213
|
+
if not config_resolver.is_feature_enabled(
|
|
214
|
+
user_config, {"required_scopes": ["tool:artifact:load"]}, {}
|
|
215
|
+
):
|
|
216
|
+
raise HTTPException(status_code=403, detail="Not authorized to load artifact")
|
|
217
|
+
log_prefix = (
|
|
218
|
+
f"[ArtifactRouter:GetLatest:{filename}] User={user_id}, Session={session_id} -"
|
|
219
|
+
)
|
|
220
|
+
log.info("%s Request received.", log_prefix)
|
|
221
|
+
|
|
222
|
+
if artifact_service is None:
|
|
223
|
+
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
224
|
+
raise HTTPException(
|
|
225
|
+
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
|
226
|
+
detail="Artifact service is not configured.",
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
try:
|
|
230
|
+
app_name = component.get_config("name", "A2A_WebUI_App")
|
|
231
|
+
artifact_part = await artifact_service.load_artifact(
|
|
232
|
+
app_name=app_name,
|
|
233
|
+
user_id=user_id,
|
|
234
|
+
session_id=session_id,
|
|
235
|
+
filename=filename,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
if artifact_part is None or artifact_part.inline_data is None:
|
|
239
|
+
log.warning("%s Artifact not found or has no data.", log_prefix)
|
|
240
|
+
raise HTTPException(
|
|
241
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
242
|
+
detail=f"Artifact '{filename}' not found or is empty.",
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
data_bytes = artifact_part.inline_data.data
|
|
246
|
+
mime_type = artifact_part.inline_data.mime_type or "application/octet-stream"
|
|
247
|
+
log.info(
|
|
248
|
+
"%s Artifact loaded successfully (%d bytes, %s).",
|
|
249
|
+
log_prefix,
|
|
250
|
+
len(data_bytes),
|
|
251
|
+
mime_type,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
if is_text_based_mime_type(mime_type) and component.enable_embed_resolution:
|
|
255
|
+
log.info(
|
|
256
|
+
"%s Artifact is text-based. Attempting recursive embed resolution.",
|
|
257
|
+
log_prefix,
|
|
258
|
+
)
|
|
259
|
+
try:
|
|
260
|
+
original_content_string = data_bytes.decode("utf-8")
|
|
261
|
+
|
|
262
|
+
context_for_resolver = {
|
|
263
|
+
"artifact_service": artifact_service,
|
|
264
|
+
"session_context": {
|
|
265
|
+
"app_name": component.gateway_id,
|
|
266
|
+
"user_id": user_id,
|
|
267
|
+
"session_id": session_id,
|
|
268
|
+
},
|
|
269
|
+
}
|
|
270
|
+
config_for_resolver = {
|
|
271
|
+
"gateway_max_artifact_resolve_size_bytes": component.gateway_max_artifact_resolve_size_bytes,
|
|
272
|
+
"gateway_recursive_embed_depth": component.gateway_recursive_embed_depth,
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
resolved_content_string = await resolve_embeds_recursively_in_string(
|
|
276
|
+
text=original_content_string,
|
|
277
|
+
context=context_for_resolver,
|
|
278
|
+
resolver_func=evaluate_embed,
|
|
279
|
+
types_to_resolve=LATE_EMBED_TYPES,
|
|
280
|
+
log_identifier=f"{log_prefix}[RecursiveResolve]",
|
|
281
|
+
config=config_for_resolver,
|
|
282
|
+
max_depth=component.gateway_recursive_embed_depth,
|
|
283
|
+
max_total_size=component.gateway_max_artifact_resolve_size_bytes,
|
|
284
|
+
)
|
|
285
|
+
data_bytes = resolved_content_string.encode("utf-8")
|
|
286
|
+
log.info(
|
|
287
|
+
"%s Recursive embed resolution complete. New size: %d bytes.",
|
|
288
|
+
log_prefix,
|
|
289
|
+
len(data_bytes),
|
|
290
|
+
)
|
|
291
|
+
except UnicodeDecodeError as ude:
|
|
292
|
+
log.warning(
|
|
293
|
+
"%s Failed to decode artifact for recursive resolution: %s. Serving original content.",
|
|
294
|
+
log_prefix,
|
|
295
|
+
ude,
|
|
296
|
+
)
|
|
297
|
+
except Exception as resolve_err:
|
|
298
|
+
log.exception(
|
|
299
|
+
"%s Error during recursive embed resolution: %s. Serving original content.",
|
|
300
|
+
log_prefix,
|
|
301
|
+
resolve_err,
|
|
302
|
+
)
|
|
303
|
+
else:
|
|
304
|
+
log.info(
|
|
305
|
+
"%s Artifact is not text-based or embed resolution is disabled. Serving original content.",
|
|
306
|
+
log_prefix,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
filename_encoded = quote(filename)
|
|
310
|
+
return StreamingResponse(
|
|
311
|
+
io.BytesIO(data_bytes),
|
|
312
|
+
media_type=mime_type,
|
|
313
|
+
headers={
|
|
314
|
+
"Content-Disposition": f"attachment; filename*=UTF-8''{filename_encoded}"
|
|
315
|
+
},
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
except FileNotFoundError:
|
|
319
|
+
log.warning("%s Artifact not found by service.", log_prefix)
|
|
320
|
+
raise HTTPException(
|
|
321
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
322
|
+
detail=f"Artifact '{filename}' not found.",
|
|
323
|
+
)
|
|
324
|
+
except Exception as e:
|
|
325
|
+
log.exception("%s Error loading artifact: %s", log_prefix, e)
|
|
326
|
+
raise HTTPException(
|
|
327
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
328
|
+
detail=f"Failed to load artifact: {str(e)}",
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
@router.get(
|
|
333
|
+
"/{filename}/versions/{version}",
|
|
334
|
+
summary="Get Specific Artifact Version Content",
|
|
335
|
+
description="Retrieves the content of a specific version of an artifact.",
|
|
336
|
+
)
|
|
337
|
+
async def get_specific_artifact_version(
|
|
338
|
+
filename: str = Path(..., title="Filename", description="The name of the artifact"),
|
|
339
|
+
version: Union[int, str] = Path(
|
|
340
|
+
...,
|
|
341
|
+
title="Version",
|
|
342
|
+
description="The specific version number to retrieve, or 'latest'",
|
|
343
|
+
),
|
|
344
|
+
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
345
|
+
user_id: str = Depends(get_user_id),
|
|
346
|
+
session_id: str = Depends(ensure_session_id),
|
|
347
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
348
|
+
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
349
|
+
user_config: dict = Depends(get_user_config),
|
|
350
|
+
):
|
|
351
|
+
"""
|
|
352
|
+
Retrieves the content of a specific version of the specified artifact
|
|
353
|
+
associated with the current user and session ID.
|
|
354
|
+
"""
|
|
355
|
+
if not config_resolver.is_feature_enabled(
|
|
356
|
+
user_config, {"required_scopes": ["tool:artifact:load"]}, {}
|
|
357
|
+
):
|
|
358
|
+
raise HTTPException(
|
|
359
|
+
status_code=403, detail="Not authorized to load artifact version"
|
|
360
|
+
)
|
|
361
|
+
log_prefix = f"[ArtifactRouter:GetVersion:{filename} v{version}] User={user_id}, Session={session_id} -"
|
|
362
|
+
log.info("%s Request received.", log_prefix)
|
|
363
|
+
|
|
364
|
+
if artifact_service is None:
|
|
365
|
+
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
366
|
+
raise HTTPException(
|
|
367
|
+
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
|
368
|
+
detail="Artifact service is not configured.",
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
try:
|
|
372
|
+
app_name = component.get_config("name", "A2A_WebUI_App")
|
|
373
|
+
|
|
374
|
+
load_result = await load_artifact_content_or_metadata(
|
|
375
|
+
artifact_service=artifact_service,
|
|
376
|
+
app_name=app_name,
|
|
377
|
+
user_id=user_id,
|
|
378
|
+
session_id=session_id,
|
|
379
|
+
filename=filename,
|
|
380
|
+
version=version,
|
|
381
|
+
load_metadata_only=False,
|
|
382
|
+
return_raw_bytes=True,
|
|
383
|
+
log_identifier_prefix=f"[ArtifactRouter:GetVersion]",
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
if load_result.get("status") != "success":
|
|
387
|
+
error_message = load_result.get(
|
|
388
|
+
"message", f"Failed to load artifact '{filename}' version '{version}'."
|
|
389
|
+
)
|
|
390
|
+
log.warning("%s %s", log_prefix, error_message)
|
|
391
|
+
if (
|
|
392
|
+
"not found" in error_message.lower()
|
|
393
|
+
or "no versions available" in error_message.lower()
|
|
394
|
+
):
|
|
395
|
+
status_code = status.HTTP_404_NOT_FOUND
|
|
396
|
+
elif "invalid version" in error_message.lower():
|
|
397
|
+
status_code = status.HTTP_400_BAD_REQUEST
|
|
398
|
+
else:
|
|
399
|
+
status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
400
|
+
raise HTTPException(status_code=status_code, detail=error_message)
|
|
401
|
+
|
|
402
|
+
data_bytes = load_result.get("raw_bytes")
|
|
403
|
+
mime_type = load_result.get("mime_type", "application/octet-stream")
|
|
404
|
+
resolved_version_from_helper = load_result.get("version")
|
|
405
|
+
if data_bytes is None:
|
|
406
|
+
|
|
407
|
+
log.error(
|
|
408
|
+
"%s Helper (with return_raw_bytes=True) returned success but no raw_bytes for '%s' v%s (resolved to %s).",
|
|
409
|
+
log_prefix,
|
|
410
|
+
filename,
|
|
411
|
+
version,
|
|
412
|
+
resolved_version_from_helper,
|
|
413
|
+
)
|
|
414
|
+
raise HTTPException(
|
|
415
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
416
|
+
detail="Internal error retrieving artifact content.",
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
log.info(
|
|
420
|
+
"%s Artifact '%s' version %s (resolved to %s) loaded successfully (%d bytes, %s). Streaming content.",
|
|
421
|
+
log_prefix,
|
|
422
|
+
filename,
|
|
423
|
+
version,
|
|
424
|
+
resolved_version_from_helper,
|
|
425
|
+
len(data_bytes),
|
|
426
|
+
mime_type,
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
if is_text_based_mime_type(mime_type) and component.enable_embed_resolution:
|
|
430
|
+
log.info(
|
|
431
|
+
"%s Artifact is text-based. Attempting recursive embed resolution.",
|
|
432
|
+
log_prefix,
|
|
433
|
+
)
|
|
434
|
+
try:
|
|
435
|
+
original_content_string = data_bytes.decode("utf-8")
|
|
436
|
+
|
|
437
|
+
context_for_resolver = {
|
|
438
|
+
"artifact_service": artifact_service,
|
|
439
|
+
"session_context": {
|
|
440
|
+
"app_name": component.gateway_id,
|
|
441
|
+
"user_id": user_id,
|
|
442
|
+
"session_id": session_id,
|
|
443
|
+
},
|
|
444
|
+
}
|
|
445
|
+
config_for_resolver = {
|
|
446
|
+
"gateway_max_artifact_resolve_size_bytes": component.gateway_max_artifact_resolve_size_bytes,
|
|
447
|
+
"gateway_recursive_embed_depth": component.gateway_recursive_embed_depth,
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
resolved_content_string = await resolve_embeds_recursively_in_string(
|
|
451
|
+
text=original_content_string,
|
|
452
|
+
context=context_for_resolver,
|
|
453
|
+
resolver_func=evaluate_embed,
|
|
454
|
+
types_to_resolve=LATE_EMBED_TYPES,
|
|
455
|
+
log_identifier=f"{log_prefix}[RecursiveResolve]",
|
|
456
|
+
config=config_for_resolver,
|
|
457
|
+
max_depth=component.gateway_recursive_embed_depth,
|
|
458
|
+
max_total_size=component.gateway_max_artifact_resolve_size_bytes,
|
|
459
|
+
)
|
|
460
|
+
data_bytes = resolved_content_string.encode("utf-8")
|
|
461
|
+
log.info(
|
|
462
|
+
"%s Recursive embed resolution complete. New size: %d bytes.",
|
|
463
|
+
log_prefix,
|
|
464
|
+
len(data_bytes),
|
|
465
|
+
)
|
|
466
|
+
except UnicodeDecodeError as ude:
|
|
467
|
+
log.warning(
|
|
468
|
+
"%s Failed to decode artifact for recursive resolution: %s. Serving original content.",
|
|
469
|
+
log_prefix,
|
|
470
|
+
ude,
|
|
471
|
+
)
|
|
472
|
+
except Exception as resolve_err:
|
|
473
|
+
log.exception(
|
|
474
|
+
"%s Error during recursive embed resolution: %s. Serving original content.",
|
|
475
|
+
log_prefix,
|
|
476
|
+
resolve_err,
|
|
477
|
+
)
|
|
478
|
+
else:
|
|
479
|
+
log.info(
|
|
480
|
+
"%s Artifact is not text-based or embed resolution is disabled. Serving original content.",
|
|
481
|
+
log_prefix,
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
filename_encoded = quote(filename)
|
|
485
|
+
return StreamingResponse(
|
|
486
|
+
io.BytesIO(data_bytes),
|
|
487
|
+
media_type=mime_type,
|
|
488
|
+
headers={
|
|
489
|
+
"Content-Disposition": f"attachment; filename*=UTF-8''{filename_encoded}"
|
|
490
|
+
},
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
except FileNotFoundError:
|
|
494
|
+
log.warning("%s Artifact version not found by service.", log_prefix)
|
|
495
|
+
raise HTTPException(
|
|
496
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
497
|
+
detail=f"Artifact '{filename}' version {version} not found.",
|
|
498
|
+
)
|
|
499
|
+
except ValueError as ve:
|
|
500
|
+
log.warning("%s Invalid request (e.g., version format): %s", log_prefix, ve)
|
|
501
|
+
raise HTTPException(
|
|
502
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
503
|
+
detail=f"Invalid request: {str(ve)}",
|
|
504
|
+
)
|
|
505
|
+
except Exception as e:
|
|
506
|
+
log.exception("%s Error loading artifact version: %s", log_prefix, e)
|
|
507
|
+
raise HTTPException(
|
|
508
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
509
|
+
detail=f"Failed to load artifact version: {str(e)}",
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
@router.get(
|
|
514
|
+
"/by-uri",
|
|
515
|
+
response_class=StreamingResponse,
|
|
516
|
+
summary="Get Artifact by URI",
|
|
517
|
+
description="Resolves a formal artifact:// URI and streams its content. This endpoint is secure and validates that the requesting user is authorized to access the specified artifact.",
|
|
518
|
+
)
|
|
519
|
+
async def get_artifact_by_uri(
|
|
520
|
+
uri: str,
|
|
521
|
+
requesting_user_id: str = Depends(get_user_id),
|
|
522
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
523
|
+
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
524
|
+
user_config: dict = Depends(get_user_config),
|
|
525
|
+
):
|
|
526
|
+
"""
|
|
527
|
+
Resolves an artifact:// URI and streams its content.
|
|
528
|
+
This allows fetching artifacts from any context, not just the current user's session,
|
|
529
|
+
after performing an authorization check.
|
|
530
|
+
"""
|
|
531
|
+
log_id_prefix = f"[ArtifactRouter:by-uri]"
|
|
532
|
+
log.info(
|
|
533
|
+
"%s Received request for URI: %s from user: %s",
|
|
534
|
+
log_id_prefix,
|
|
535
|
+
uri,
|
|
536
|
+
requesting_user_id,
|
|
537
|
+
)
|
|
538
|
+
artifact_service = component.get_shared_artifact_service()
|
|
539
|
+
if not artifact_service:
|
|
540
|
+
raise HTTPException(
|
|
541
|
+
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
542
|
+
detail="Artifact service not available.",
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
try:
|
|
546
|
+
parsed_uri = urlparse(uri)
|
|
547
|
+
if parsed_uri.scheme != "artifact":
|
|
548
|
+
raise ValueError("Invalid URI scheme, must be 'artifact'.")
|
|
549
|
+
|
|
550
|
+
app_name = parsed_uri.netloc
|
|
551
|
+
path_parts = parsed_uri.path.strip("/").split("/")
|
|
552
|
+
if not app_name or len(path_parts) != 3:
|
|
553
|
+
raise ValueError(
|
|
554
|
+
"Invalid URI path structure. Expected artifact://app_name/user_id/session_id/filename"
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
owner_user_id, session_id, filename = path_parts
|
|
558
|
+
|
|
559
|
+
query_params = parse_qs(parsed_uri.query)
|
|
560
|
+
version_list = query_params.get("version")
|
|
561
|
+
if not version_list or not version_list[0]:
|
|
562
|
+
raise ValueError("Version query parameter is required.")
|
|
563
|
+
version = version_list[0]
|
|
564
|
+
|
|
565
|
+
log.info(
|
|
566
|
+
"%s Parsed URI: app=%s, owner=%s, session=%s, file=%s, version=%s",
|
|
567
|
+
log_id_prefix,
|
|
568
|
+
app_name,
|
|
569
|
+
owner_user_id,
|
|
570
|
+
session_id,
|
|
571
|
+
filename,
|
|
572
|
+
version,
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
if not config_resolver.is_feature_enabled(
|
|
576
|
+
user_config, {"required_scopes": ["tool:artifact:load"]}, {}
|
|
577
|
+
):
|
|
578
|
+
raise HTTPException(
|
|
579
|
+
status_code=403, detail="Not authorized to load artifact by URI"
|
|
580
|
+
)
|
|
581
|
+
log.warning(
|
|
582
|
+
"%s Authorization denied for user '%s' to access artifact URI '%s'",
|
|
583
|
+
log_id_prefix,
|
|
584
|
+
requesting_user_id,
|
|
585
|
+
uri,
|
|
586
|
+
)
|
|
587
|
+
raise HTTPException(
|
|
588
|
+
status_code=403, detail="Permission denied to access this artifact."
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
log.info(
|
|
592
|
+
"%s User '%s' authorized to access artifact URI.",
|
|
593
|
+
log_id_prefix,
|
|
594
|
+
requesting_user_id,
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
loaded_artifact = await load_artifact_content_or_metadata(
|
|
598
|
+
artifact_service=artifact_service,
|
|
599
|
+
app_name=app_name,
|
|
600
|
+
user_id=owner_user_id,
|
|
601
|
+
session_id=session_id,
|
|
602
|
+
filename=filename,
|
|
603
|
+
version=int(version),
|
|
604
|
+
return_raw_bytes=True,
|
|
605
|
+
log_identifier_prefix=log_id_prefix,
|
|
606
|
+
component=component,
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
if loaded_artifact.get("status") != "success":
|
|
610
|
+
raise HTTPException(status_code=404, detail=loaded_artifact.get("message"))
|
|
611
|
+
|
|
612
|
+
content_bytes = loaded_artifact.get("raw_bytes")
|
|
613
|
+
mime_type = loaded_artifact.get("mime_type", "application/octet-stream")
|
|
614
|
+
|
|
615
|
+
filename_encoded = quote(filename)
|
|
616
|
+
return StreamingResponse(
|
|
617
|
+
io.BytesIO(content_bytes),
|
|
618
|
+
media_type=mime_type,
|
|
619
|
+
headers={
|
|
620
|
+
"Content-Disposition": f"attachment; filename*=UTF-8''{filename_encoded}"
|
|
621
|
+
},
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
except (ValueError, IndexError) as e:
|
|
625
|
+
raise HTTPException(status_code=400, detail=f"Invalid artifact URI: {e}")
|
|
626
|
+
except Exception as e:
|
|
627
|
+
log.exception("%s Error fetching artifact by URI: %s", log_id_prefix, e)
|
|
628
|
+
raise HTTPException(
|
|
629
|
+
status_code=500, detail="Internal server error fetching artifact by URI"
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
@router.post(
|
|
634
|
+
"/{filename}",
|
|
635
|
+
status_code=status.HTTP_201_CREATED,
|
|
636
|
+
response_model=Dict[str, Any],
|
|
637
|
+
summary="Upload Artifact (Create/Update Version with Metadata)",
|
|
638
|
+
description="Uploads file content and optional metadata to create or update an artifact version.",
|
|
639
|
+
)
|
|
640
|
+
async def upload_artifact(
|
|
641
|
+
filename: str = Path(
|
|
642
|
+
..., title="Filename", description="The name of the artifact to create/update"
|
|
643
|
+
),
|
|
644
|
+
upload_file: UploadFile = File(..., description="The file content to upload"),
|
|
645
|
+
metadata_json: Optional[str] = Form(
|
|
646
|
+
None, description="JSON string of artifact metadata (e.g., description, source)"
|
|
647
|
+
),
|
|
648
|
+
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
649
|
+
user_id: str = Depends(get_user_id),
|
|
650
|
+
session_id: str = Depends(ensure_session_id),
|
|
651
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
652
|
+
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
653
|
+
user_config: dict = Depends(get_user_config),
|
|
654
|
+
):
|
|
655
|
+
"""
|
|
656
|
+
Uploads a file to create a new version of the specified artifact
|
|
657
|
+
associated with the current user and session ID. Also saves associated metadata.
|
|
658
|
+
"""
|
|
659
|
+
if not config_resolver.is_feature_enabled(
|
|
660
|
+
user_config, {"required_scopes": ["tool:artifact:create"]}, {}
|
|
661
|
+
):
|
|
662
|
+
raise HTTPException(status_code=403, detail="Not authorized to upload artifact")
|
|
663
|
+
log_prefix = (
|
|
664
|
+
f"[ArtifactRouter:Post:{filename}] User={user_id}, Session={session_id} -"
|
|
665
|
+
)
|
|
666
|
+
log.info(
|
|
667
|
+
"%s Request received. Upload filename: '%s', content type: %s",
|
|
668
|
+
log_prefix,
|
|
669
|
+
upload_file.filename,
|
|
670
|
+
upload_file.content_type,
|
|
671
|
+
f"Metadata provided: {bool(metadata_json)}",
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
if artifact_service is None:
|
|
675
|
+
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
676
|
+
raise HTTPException(
|
|
677
|
+
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
|
678
|
+
detail="Artifact service is not configured.",
|
|
679
|
+
)
|
|
680
|
+
|
|
681
|
+
try:
|
|
682
|
+
content_bytes = await upload_file.read()
|
|
683
|
+
if not content_bytes:
|
|
684
|
+
log.warning("%s Uploaded file is empty.", log_prefix)
|
|
685
|
+
raise HTTPException(
|
|
686
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
687
|
+
detail="Uploaded file cannot be empty.",
|
|
688
|
+
)
|
|
689
|
+
|
|
690
|
+
mime_type = upload_file.content_type or "application/octet-stream"
|
|
691
|
+
|
|
692
|
+
parsed_metadata = {}
|
|
693
|
+
if metadata_json:
|
|
694
|
+
try:
|
|
695
|
+
parsed_metadata = json.loads(metadata_json)
|
|
696
|
+
if not isinstance(parsed_metadata, dict):
|
|
697
|
+
log.warning(
|
|
698
|
+
"%s Metadata JSON did not parse to a dictionary. Ignoring.",
|
|
699
|
+
log_prefix,
|
|
700
|
+
)
|
|
701
|
+
parsed_metadata = {}
|
|
702
|
+
except json.JSONDecodeError as json_err:
|
|
703
|
+
log.warning(
|
|
704
|
+
"%s Failed to parse metadata_json: %s. Proceeding without it.",
|
|
705
|
+
log_prefix,
|
|
706
|
+
json_err,
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
app_name = component.get_config("name", "A2A_WebUI_App")
|
|
710
|
+
current_timestamp = datetime.now(timezone.utc)
|
|
711
|
+
|
|
712
|
+
save_result = await save_artifact_with_metadata(
|
|
713
|
+
artifact_service=artifact_service,
|
|
714
|
+
app_name=app_name,
|
|
715
|
+
user_id=user_id,
|
|
716
|
+
session_id=session_id,
|
|
717
|
+
filename=filename,
|
|
718
|
+
content_bytes=content_bytes,
|
|
719
|
+
mime_type=mime_type,
|
|
720
|
+
metadata_dict=parsed_metadata,
|
|
721
|
+
timestamp=current_timestamp,
|
|
722
|
+
schema_max_keys=component.get_config(
|
|
723
|
+
"schema_max_keys", DEFAULT_SCHEMA_MAX_KEYS
|
|
724
|
+
),
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
if save_result["status"] in ["success", "partial_success"]:
|
|
728
|
+
log.info(
|
|
729
|
+
"%s Artifact and metadata processing completed. Data version: %s, Metadata version: %s. Message: %s",
|
|
730
|
+
log_prefix,
|
|
731
|
+
save_result.get("data_version"),
|
|
732
|
+
save_result.get("metadata_version"),
|
|
733
|
+
save_result.get("message"),
|
|
734
|
+
)
|
|
735
|
+
return {
|
|
736
|
+
"filename": filename,
|
|
737
|
+
"data_version": save_result.get("data_version"),
|
|
738
|
+
"metadata_version": save_result.get("metadata_version"),
|
|
739
|
+
"mime_type": mime_type,
|
|
740
|
+
"size": len(content_bytes),
|
|
741
|
+
"message": save_result.get("message"),
|
|
742
|
+
"status": save_result["status"],
|
|
743
|
+
}
|
|
744
|
+
else:
|
|
745
|
+
log.error(
|
|
746
|
+
"%s Failed to save artifact and metadata: %s",
|
|
747
|
+
log_prefix,
|
|
748
|
+
save_result.get("message"),
|
|
749
|
+
)
|
|
750
|
+
raise HTTPException(
|
|
751
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
752
|
+
detail=save_result.get(
|
|
753
|
+
"message", "Failed to save artifact with metadata."
|
|
754
|
+
),
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
except HTTPException:
|
|
758
|
+
raise
|
|
759
|
+
except Exception as e:
|
|
760
|
+
log.exception("%s Error saving artifact: %s", log_prefix, e)
|
|
761
|
+
raise HTTPException(
|
|
762
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
763
|
+
detail=f"Failed to save artifact: {str(e)}",
|
|
764
|
+
)
|
|
765
|
+
finally:
|
|
766
|
+
|
|
767
|
+
await upload_file.close()
|
|
768
|
+
log.debug("%s Upload file closed.", log_prefix)
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
@router.delete(
|
|
772
|
+
"/{filename}",
|
|
773
|
+
status_code=status.HTTP_204_NO_CONTENT,
|
|
774
|
+
summary="Delete Artifact",
|
|
775
|
+
description="Deletes an artifact and all its versions.",
|
|
776
|
+
)
|
|
777
|
+
async def delete_artifact(
|
|
778
|
+
filename: str = Path(
|
|
779
|
+
..., title="Filename", description="The name of the artifact to delete"
|
|
780
|
+
),
|
|
781
|
+
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
782
|
+
user_id: str = Depends(get_user_id),
|
|
783
|
+
session_id: str = Depends(ensure_session_id),
|
|
784
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
785
|
+
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
786
|
+
user_config: dict = Depends(get_user_config),
|
|
787
|
+
):
|
|
788
|
+
"""
|
|
789
|
+
Deletes the specified artifact (including all its versions)
|
|
790
|
+
associated with the current user and session ID.
|
|
791
|
+
"""
|
|
792
|
+
if not config_resolver.is_feature_enabled(
|
|
793
|
+
user_config, {"required_scopes": ["tool:artifact:delete"]}, {}
|
|
794
|
+
):
|
|
795
|
+
raise HTTPException(status_code=403, detail="Not authorized to delete artifact")
|
|
796
|
+
log_prefix = (
|
|
797
|
+
f"[ArtifactRouter:Delete:{filename}] User={user_id}, Session={session_id} -"
|
|
798
|
+
)
|
|
799
|
+
log.info("%s Request received.", log_prefix)
|
|
800
|
+
|
|
801
|
+
if artifact_service is None:
|
|
802
|
+
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
803
|
+
raise HTTPException(
|
|
804
|
+
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
|
805
|
+
detail="Artifact service is not configured.",
|
|
806
|
+
)
|
|
807
|
+
|
|
808
|
+
try:
|
|
809
|
+
app_name = component.get_config("name", "A2A_WebUI_App")
|
|
810
|
+
|
|
811
|
+
await artifact_service.delete_artifact(
|
|
812
|
+
app_name=app_name,
|
|
813
|
+
user_id=user_id,
|
|
814
|
+
session_id=session_id,
|
|
815
|
+
filename=filename,
|
|
816
|
+
)
|
|
817
|
+
|
|
818
|
+
log.info("%s Artifact deletion request processed successfully.", log_prefix)
|
|
819
|
+
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
|
820
|
+
|
|
821
|
+
except Exception as e:
|
|
822
|
+
|
|
823
|
+
log.exception("%s Error deleting artifact: %s", log_prefix, e)
|
|
824
|
+
raise HTTPException(
|
|
825
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
826
|
+
detail=f"Failed to delete artifact: {str(e)}",
|
|
827
|
+
)
|