solace-agent-mesh 0.2.4__py3-none-any.whl → 1.0.1__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/adk_llm.txt +93 -0
- solace_agent_mesh/agent/adk/app_llm_agent.py +26 -0
- solace_agent_mesh/agent/adk/callbacks.py +1694 -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 +353 -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 +1469 -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 +3388 -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 +176 -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 +569 -0
- solace_agent_mesh/agent/tools/image_tools.py +1184 -0
- solace_agent_mesh/agent/tools/peer_agent_tool.py +289 -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.23bccffb.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.2c2e152c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/fbfa3e75.aca209c9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.7ed3319f.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/main.7ed3319f.js.LICENSE.txt +81 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.d9520ae2.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 +60 -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-1753813536522.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -0
- solace_agent_mesh/assets/docs/search-doc-1753813536522.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 +197 -0
- solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +365 -0
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +387 -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 +138 -0
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +309 -0
- solace_agent_mesh/cli/commands/plugin_cmd/official_registry.py +174 -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-An0a5j5k.js +663 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-Bu5-4Bac.css +1 -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/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 +23 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/models.py +49 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/registry_manager.py +160 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/scraper.py +525 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog_server.py +216 -0
- solace_agent_mesh/config_portal/backend/server.py +550 -181
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-DNxCwAGB.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-d2b54a97.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 +821 -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 +400 -0
- solace_agent_mesh/templates/gateway_config_template.yaml +43 -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.1.dist-info/METADATA +432 -0
- solace_agent_mesh-1.0.1.dist-info/RECORD +359 -0
- solace_agent_mesh-1.0.1.dist-info/entry_points.txt +3 -0
- {solace_agent_mesh-0.2.4.dist-info → solace_agent_mesh-1.0.1.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.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,927 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Helper functions for artifact management, including metadata handling and schema inference.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import base64
|
|
6
|
+
import binascii
|
|
7
|
+
import json
|
|
8
|
+
import csv
|
|
9
|
+
import io
|
|
10
|
+
import inspect
|
|
11
|
+
import datetime
|
|
12
|
+
import os
|
|
13
|
+
from typing import Any, Dict, Optional, Tuple, List, Union, TYPE_CHECKING
|
|
14
|
+
from datetime import timezone
|
|
15
|
+
from google.adk.artifacts import BaseArtifactService
|
|
16
|
+
from google.genai import types as adk_types
|
|
17
|
+
from solace_ai_connector.common.log import log
|
|
18
|
+
from ...common.utils.mime_helpers import is_text_based_mime_type, is_text_based_file
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from google.adk.tools import ToolContext
|
|
22
|
+
|
|
23
|
+
METADATA_SUFFIX = ".metadata.json"
|
|
24
|
+
DEFAULT_SCHEMA_MAX_KEYS = 20
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def is_filename_safe(filename: str) -> bool:
|
|
28
|
+
"""
|
|
29
|
+
Checks if a filename is safe for artifact creation.
|
|
30
|
+
- Must not be empty or just whitespace.
|
|
31
|
+
- Must not contain path traversal sequences ('..').
|
|
32
|
+
- Must not contain path separators ('/' or '\\').
|
|
33
|
+
- Must not be a reserved name like '.' or '..'.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
filename: The filename to validate.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
True if the filename is safe, False otherwise.
|
|
40
|
+
"""
|
|
41
|
+
if not filename or not filename.strip():
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
# Check for path traversal
|
|
45
|
+
if ".." in filename:
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
# Check for path separators
|
|
49
|
+
if "/" in filename or "\\" in filename:
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
# Check for reserved names
|
|
53
|
+
if filename.strip() in [".", ".."]:
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def ensure_correct_extension(filename_from_llm: str, desired_extension: str) -> str:
|
|
60
|
+
"""
|
|
61
|
+
Ensures a filename has the correct extension, handling cases where the LLM
|
|
62
|
+
might provide a filename with or without an extension, or with the wrong one.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
filename_from_llm: The filename string provided by the LLM.
|
|
66
|
+
desired_extension: The correct extension for the file (e.g., 'png', 'md').
|
|
67
|
+
Should be provided without a leading dot.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
A string with the correctly formatted filename.
|
|
71
|
+
"""
|
|
72
|
+
if not filename_from_llm:
|
|
73
|
+
return f"unnamed.{desired_extension.lower()}"
|
|
74
|
+
filename_stripped = filename_from_llm.strip()
|
|
75
|
+
desired_ext_clean = desired_extension.lower().strip().lstrip(".")
|
|
76
|
+
base_name, current_ext = os.path.splitext(filename_stripped)
|
|
77
|
+
current_ext_clean = current_ext.lower().lstrip(".")
|
|
78
|
+
if current_ext_clean == desired_ext_clean:
|
|
79
|
+
return filename_stripped
|
|
80
|
+
else:
|
|
81
|
+
return f"{base_name}.{desired_ext_clean}"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _inspect_structure(
|
|
85
|
+
data: Any, max_depth: int, max_keys: int, current_depth: int = 0
|
|
86
|
+
) -> Any:
|
|
87
|
+
"""
|
|
88
|
+
Recursively inspects data structure up to max_depth and max_keys for dictionaries.
|
|
89
|
+
"""
|
|
90
|
+
if current_depth >= max_depth:
|
|
91
|
+
return type(data).__name__
|
|
92
|
+
if isinstance(data, dict):
|
|
93
|
+
if not data:
|
|
94
|
+
return {}
|
|
95
|
+
inspected_dict = {}
|
|
96
|
+
keys = list(data.keys())
|
|
97
|
+
keys_to_inspect = keys[:max_keys]
|
|
98
|
+
for key in keys_to_inspect:
|
|
99
|
+
inspected_dict[key] = _inspect_structure(
|
|
100
|
+
data[key], max_depth, max_keys, current_depth + 1
|
|
101
|
+
)
|
|
102
|
+
if len(keys) > max_keys:
|
|
103
|
+
inspected_dict["..."] = f"{len(keys) - max_keys} more keys"
|
|
104
|
+
return inspected_dict
|
|
105
|
+
elif isinstance(data, list):
|
|
106
|
+
if not data:
|
|
107
|
+
return []
|
|
108
|
+
return [_inspect_structure(data[0], max_depth, max_keys, current_depth + 1)]
|
|
109
|
+
else:
|
|
110
|
+
return type(data).__name__
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _infer_schema(
|
|
114
|
+
content_bytes: bytes,
|
|
115
|
+
mime_type: str,
|
|
116
|
+
depth: int = 3,
|
|
117
|
+
max_keys: int = DEFAULT_SCHEMA_MAX_KEYS,
|
|
118
|
+
) -> Dict[str, Any]:
|
|
119
|
+
"""
|
|
120
|
+
Infers basic schema information for common text-based types.
|
|
121
|
+
Args:
|
|
122
|
+
content_bytes: The raw byte content.
|
|
123
|
+
mime_type: The MIME type.
|
|
124
|
+
depth: Maximum recursion depth for nested structures.
|
|
125
|
+
max_keys: Maximum number of dictionary keys to inspect at each level.
|
|
126
|
+
Returns:
|
|
127
|
+
A dictionary representing the inferred schema, including an 'inferred' flag
|
|
128
|
+
and potential 'error' field.
|
|
129
|
+
"""
|
|
130
|
+
schema_info = {"type": mime_type, "inferred": False, "error": None}
|
|
131
|
+
normalized_mime_type = mime_type.lower() if mime_type else ""
|
|
132
|
+
try:
|
|
133
|
+
if normalized_mime_type == "text/csv":
|
|
134
|
+
try:
|
|
135
|
+
text_content = io.TextIOWrapper(
|
|
136
|
+
io.BytesIO(content_bytes), encoding="utf-8"
|
|
137
|
+
)
|
|
138
|
+
reader = csv.reader(text_content)
|
|
139
|
+
header = next(reader)
|
|
140
|
+
schema_info["columns"] = header
|
|
141
|
+
schema_info["inferred"] = True
|
|
142
|
+
except (StopIteration, csv.Error, UnicodeDecodeError) as e:
|
|
143
|
+
schema_info["error"] = f"CSV header inference failed: {e}"
|
|
144
|
+
elif normalized_mime_type in ["application/json", "text/json"]:
|
|
145
|
+
try:
|
|
146
|
+
data = json.loads(content_bytes.decode("utf-8"))
|
|
147
|
+
schema_info["structure"] = _inspect_structure(data, depth, max_keys)
|
|
148
|
+
schema_info["inferred"] = True
|
|
149
|
+
except (json.JSONDecodeError, UnicodeDecodeError) as e:
|
|
150
|
+
schema_info["error"] = f"JSON structure inference failed: {e}"
|
|
151
|
+
elif normalized_mime_type in [
|
|
152
|
+
"application/yaml",
|
|
153
|
+
"text/yaml",
|
|
154
|
+
"application/x-yaml",
|
|
155
|
+
"text/x-yaml",
|
|
156
|
+
]:
|
|
157
|
+
try:
|
|
158
|
+
import yaml
|
|
159
|
+
|
|
160
|
+
data = yaml.safe_load(content_bytes)
|
|
161
|
+
schema_info["structure"] = _inspect_structure(data, depth, max_keys)
|
|
162
|
+
schema_info["inferred"] = True
|
|
163
|
+
except ImportError:
|
|
164
|
+
schema_info["error"] = "YAML inference skipped: PyYAML not installed."
|
|
165
|
+
except (yaml.YAMLError, UnicodeDecodeError) as e:
|
|
166
|
+
schema_info["error"] = f"YAML structure inference failed: {e}"
|
|
167
|
+
except Exception as e:
|
|
168
|
+
schema_info["error"] = f"Unexpected error during schema inference: {e}"
|
|
169
|
+
if schema_info["error"]:
|
|
170
|
+
log.warning(
|
|
171
|
+
"Schema inference for mime_type '%s' encountered error: %s",
|
|
172
|
+
mime_type,
|
|
173
|
+
schema_info["error"],
|
|
174
|
+
)
|
|
175
|
+
elif not schema_info["inferred"]:
|
|
176
|
+
log.debug(
|
|
177
|
+
"No specific schema inference logic applied for mime_type '%s'.", mime_type
|
|
178
|
+
)
|
|
179
|
+
return schema_info
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
async def save_artifact_with_metadata(
|
|
183
|
+
artifact_service: BaseArtifactService,
|
|
184
|
+
app_name: str,
|
|
185
|
+
user_id: str,
|
|
186
|
+
session_id: str,
|
|
187
|
+
filename: str,
|
|
188
|
+
content_bytes: bytes,
|
|
189
|
+
mime_type: str,
|
|
190
|
+
metadata_dict: Dict[str, Any],
|
|
191
|
+
timestamp: datetime.datetime,
|
|
192
|
+
explicit_schema: Optional[Dict] = None,
|
|
193
|
+
schema_inference_depth: int = 2,
|
|
194
|
+
schema_max_keys: int = DEFAULT_SCHEMA_MAX_KEYS,
|
|
195
|
+
tool_context: Optional["ToolContext"] = None,
|
|
196
|
+
) -> Dict[str, Any]:
|
|
197
|
+
"""
|
|
198
|
+
Saves a data artifact and its corresponding metadata artifact using BaseArtifactService.
|
|
199
|
+
"""
|
|
200
|
+
log_identifier = f"[ArtifactHelper:save:{filename}]"
|
|
201
|
+
log.debug("%s Saving artifact and metadata (async)...", log_identifier)
|
|
202
|
+
data_version = None
|
|
203
|
+
metadata_version = None
|
|
204
|
+
metadata_filename = f"{filename}{METADATA_SUFFIX}"
|
|
205
|
+
status = "error"
|
|
206
|
+
status_message = "Initialization error"
|
|
207
|
+
try:
|
|
208
|
+
data_artifact_part = adk_types.Part.from_bytes(
|
|
209
|
+
data=content_bytes, mime_type=mime_type
|
|
210
|
+
)
|
|
211
|
+
log.debug(
|
|
212
|
+
f"{log_identifier} artifact_service object type: {type(artifact_service)}"
|
|
213
|
+
)
|
|
214
|
+
log.debug(
|
|
215
|
+
f"{log_identifier} artifact_service object dir: {dir(artifact_service)}"
|
|
216
|
+
)
|
|
217
|
+
if hasattr(artifact_service, "save_artifact"):
|
|
218
|
+
save_artifact_method = getattr(artifact_service, "save_artifact")
|
|
219
|
+
log.debug(
|
|
220
|
+
f"{log_identifier} type of artifact_service.save_artifact: {type(save_artifact_method)}"
|
|
221
|
+
)
|
|
222
|
+
log.debug(
|
|
223
|
+
f"{log_identifier} Is save_artifact a coroutine function? {inspect.iscoroutinefunction(save_artifact_method)}"
|
|
224
|
+
)
|
|
225
|
+
log.debug(
|
|
226
|
+
f"{log_identifier} Is save_artifact an async generator function? {inspect.isasyncgenfunction(save_artifact_method)}"
|
|
227
|
+
)
|
|
228
|
+
if callable(save_artifact_method):
|
|
229
|
+
try:
|
|
230
|
+
sig = inspect.signature(save_artifact_method)
|
|
231
|
+
log.debug(f"{log_identifier} Signature of save_artifact: {sig}")
|
|
232
|
+
except Exception as e_inspect:
|
|
233
|
+
log.debug(
|
|
234
|
+
f"{log_identifier} Could not get signature of save_artifact: {e_inspect}"
|
|
235
|
+
)
|
|
236
|
+
save_data_method = getattr(artifact_service, "save_artifact")
|
|
237
|
+
data_version = await save_data_method(
|
|
238
|
+
app_name=app_name,
|
|
239
|
+
user_id=user_id,
|
|
240
|
+
session_id=session_id,
|
|
241
|
+
filename=filename,
|
|
242
|
+
artifact=data_artifact_part,
|
|
243
|
+
)
|
|
244
|
+
log.info(
|
|
245
|
+
"%s Saved data artifact '%s' as version %s.",
|
|
246
|
+
log_identifier,
|
|
247
|
+
filename,
|
|
248
|
+
data_version,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# Populate artifact_delta for ADK callbacks if tool_context is provided
|
|
252
|
+
if (
|
|
253
|
+
tool_context
|
|
254
|
+
and hasattr(tool_context, "actions")
|
|
255
|
+
and hasattr(tool_context.actions, "artifact_delta")
|
|
256
|
+
):
|
|
257
|
+
tool_context.actions.artifact_delta[filename] = data_version
|
|
258
|
+
log.debug(
|
|
259
|
+
"%s Populated artifact_delta for ADK callbacks: %s -> %s",
|
|
260
|
+
log_identifier,
|
|
261
|
+
filename,
|
|
262
|
+
data_version,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
final_metadata = {
|
|
266
|
+
"filename": filename,
|
|
267
|
+
"mime_type": mime_type,
|
|
268
|
+
"size_bytes": len(content_bytes),
|
|
269
|
+
"timestamp_utc": (
|
|
270
|
+
timestamp
|
|
271
|
+
if isinstance(timestamp, (int, float))
|
|
272
|
+
else timestamp.timestamp()
|
|
273
|
+
),
|
|
274
|
+
**(metadata_dict or {}),
|
|
275
|
+
}
|
|
276
|
+
if explicit_schema:
|
|
277
|
+
final_metadata["schema"] = {
|
|
278
|
+
"type": mime_type,
|
|
279
|
+
"inferred": False,
|
|
280
|
+
**explicit_schema,
|
|
281
|
+
}
|
|
282
|
+
log.debug("%s Using explicit schema provided by caller.", log_identifier)
|
|
283
|
+
else:
|
|
284
|
+
inferred_schema = _infer_schema(
|
|
285
|
+
content_bytes, mime_type, schema_inference_depth, schema_max_keys
|
|
286
|
+
)
|
|
287
|
+
final_metadata["schema"] = inferred_schema
|
|
288
|
+
if inferred_schema.get("inferred"):
|
|
289
|
+
log.debug(
|
|
290
|
+
"%s Added inferred schema (max_keys=%d).",
|
|
291
|
+
log_identifier,
|
|
292
|
+
schema_max_keys,
|
|
293
|
+
)
|
|
294
|
+
elif inferred_schema.get("error"):
|
|
295
|
+
log.warning(
|
|
296
|
+
"%s Schema inference failed: %s",
|
|
297
|
+
log_identifier,
|
|
298
|
+
inferred_schema["error"],
|
|
299
|
+
)
|
|
300
|
+
try:
|
|
301
|
+
metadata_bytes = json.dumps(final_metadata, indent=2).encode("utf-8")
|
|
302
|
+
metadata_artifact_part = adk_types.Part.from_bytes(
|
|
303
|
+
data=metadata_bytes, mime_type="application/json"
|
|
304
|
+
)
|
|
305
|
+
save_metadata_method = getattr(artifact_service, "save_artifact")
|
|
306
|
+
metadata_version = await save_metadata_method(
|
|
307
|
+
app_name=app_name,
|
|
308
|
+
user_id=user_id,
|
|
309
|
+
session_id=session_id,
|
|
310
|
+
filename=metadata_filename,
|
|
311
|
+
artifact=metadata_artifact_part,
|
|
312
|
+
)
|
|
313
|
+
log.info(
|
|
314
|
+
"%s Saved metadata artifact '%s' as version %s.",
|
|
315
|
+
log_identifier,
|
|
316
|
+
metadata_filename,
|
|
317
|
+
metadata_version,
|
|
318
|
+
)
|
|
319
|
+
status = "success"
|
|
320
|
+
status_message = "Artifact and metadata saved successfully."
|
|
321
|
+
except Exception as meta_save_err:
|
|
322
|
+
log.exception(
|
|
323
|
+
"%s Failed to save metadata artifact '%s': %s",
|
|
324
|
+
log_identifier,
|
|
325
|
+
metadata_filename,
|
|
326
|
+
meta_save_err,
|
|
327
|
+
)
|
|
328
|
+
status = "partial_success"
|
|
329
|
+
status_message = f"Data artifact saved (v{data_version}), but failed to save metadata: {meta_save_err}"
|
|
330
|
+
except Exception as data_save_err:
|
|
331
|
+
log.exception(
|
|
332
|
+
"%s Failed to save data artifact '%s': %s",
|
|
333
|
+
log_identifier,
|
|
334
|
+
filename,
|
|
335
|
+
data_save_err,
|
|
336
|
+
)
|
|
337
|
+
status = "error"
|
|
338
|
+
status_message = f"Failed to save data artifact: {data_save_err}"
|
|
339
|
+
return {
|
|
340
|
+
"status": status,
|
|
341
|
+
"data_filename": filename,
|
|
342
|
+
"data_version": data_version,
|
|
343
|
+
"metadata_filename": metadata_filename,
|
|
344
|
+
"metadata_version": metadata_version,
|
|
345
|
+
"message": status_message,
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def format_metadata_for_llm(metadata: Dict[str, Any]) -> str:
|
|
350
|
+
"""Formats loaded metadata into an LLM-friendly text block."""
|
|
351
|
+
lines = []
|
|
352
|
+
filename = metadata.get("filename", "Unknown Filename")
|
|
353
|
+
version = metadata.get("version", "N/A")
|
|
354
|
+
lines.append(f"--- Metadata for artifact '{filename}' (v{version}) ---")
|
|
355
|
+
lines.append("**Artifact Metadata:**")
|
|
356
|
+
if "description" in metadata:
|
|
357
|
+
lines.append(f"* **Description:** {metadata['description']}")
|
|
358
|
+
if "source" in metadata:
|
|
359
|
+
lines.append(f"* **Source:** {metadata['source']}")
|
|
360
|
+
if "mime_type" in metadata:
|
|
361
|
+
lines.append(f"* **Type:** {metadata['mime_type']}")
|
|
362
|
+
if "size_bytes" in metadata:
|
|
363
|
+
lines.append(f"* **Size:** {metadata['size_bytes']} bytes")
|
|
364
|
+
schema = metadata.get("schema", {})
|
|
365
|
+
schema_type = schema.get("type", metadata.get("mime_type", "unknown"))
|
|
366
|
+
schema_details = []
|
|
367
|
+
if schema.get("inferred"):
|
|
368
|
+
schema_details.append("(Inferred)")
|
|
369
|
+
if "columns" in schema:
|
|
370
|
+
schema_details.append(f"Columns: {','.join(schema['columns'])}")
|
|
371
|
+
if "structure" in schema:
|
|
372
|
+
schema_details.append(f"Structure: {json.dumps(schema['structure'])}")
|
|
373
|
+
if schema.get("error"):
|
|
374
|
+
schema_details.append(f"Schema Error: {schema['error']}")
|
|
375
|
+
if schema_details:
|
|
376
|
+
lines.append(f"* **Schema:** {schema_type} {' '.join(schema_details)}")
|
|
377
|
+
elif schema_type != "unknown":
|
|
378
|
+
lines.append(f"* **Schema Type:** {schema_type}")
|
|
379
|
+
custom_fields = {
|
|
380
|
+
k: v
|
|
381
|
+
for k, v in metadata.items()
|
|
382
|
+
if k
|
|
383
|
+
not in [
|
|
384
|
+
"filename",
|
|
385
|
+
"mime_type",
|
|
386
|
+
"size_bytes",
|
|
387
|
+
"timestamp_utc",
|
|
388
|
+
"schema",
|
|
389
|
+
"version",
|
|
390
|
+
"description",
|
|
391
|
+
"source",
|
|
392
|
+
]
|
|
393
|
+
}
|
|
394
|
+
if custom_fields:
|
|
395
|
+
lines.append("* **Other:**")
|
|
396
|
+
for k, v in custom_fields.items():
|
|
397
|
+
lines.append(f" * {k}: {v}")
|
|
398
|
+
lines.append("--- End Metadata ---")
|
|
399
|
+
return "\n".join(lines)
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def decode_and_get_bytes(
|
|
403
|
+
content_str: str, mime_type: str, log_identifier: str
|
|
404
|
+
) -> Tuple[bytes, str]:
|
|
405
|
+
"""
|
|
406
|
+
Decodes content if necessary (based on mime_type) and returns bytes and final mime_type.
|
|
407
|
+
Args:
|
|
408
|
+
content_str: The input content string (potentially base64).
|
|
409
|
+
mime_type: The provided MIME type.
|
|
410
|
+
log_identifier: Identifier for logging.
|
|
411
|
+
Returns:
|
|
412
|
+
A tuple containing (content_bytes, final_mime_type).
|
|
413
|
+
"""
|
|
414
|
+
file_bytes: bytes
|
|
415
|
+
final_mime_type = mime_type
|
|
416
|
+
normalized_mime_type = mime_type.lower() if mime_type else ""
|
|
417
|
+
if is_text_based_mime_type(normalized_mime_type):
|
|
418
|
+
file_bytes = content_str.encode("utf-8")
|
|
419
|
+
log.debug(
|
|
420
|
+
"%s Encoded text content for text mimeType '%s'.",
|
|
421
|
+
log_identifier,
|
|
422
|
+
mime_type,
|
|
423
|
+
)
|
|
424
|
+
else:
|
|
425
|
+
try:
|
|
426
|
+
file_bytes = base64.b64decode(content_str, validate=True)
|
|
427
|
+
log.debug(
|
|
428
|
+
"%s Decoded base64 content for non-text mimeType '%s'.",
|
|
429
|
+
log_identifier,
|
|
430
|
+
mime_type,
|
|
431
|
+
)
|
|
432
|
+
except (binascii.Error, ValueError) as decode_error:
|
|
433
|
+
log.warning(
|
|
434
|
+
"%s Failed to base64 decode content for mimeType '%s'. Treating as text/plain. Error: %s",
|
|
435
|
+
log_identifier,
|
|
436
|
+
mime_type,
|
|
437
|
+
decode_error,
|
|
438
|
+
)
|
|
439
|
+
file_bytes = content_str.encode("utf-8")
|
|
440
|
+
final_mime_type = "text/plain"
|
|
441
|
+
return file_bytes, final_mime_type
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
from google.adk.artifacts import BaseArtifactService
|
|
445
|
+
from datetime import datetime, timezone
|
|
446
|
+
import traceback
|
|
447
|
+
from ...common.types import ArtifactInfo
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
async def get_latest_artifact_version(
|
|
451
|
+
artifact_service: BaseArtifactService,
|
|
452
|
+
app_name: str,
|
|
453
|
+
user_id: str,
|
|
454
|
+
session_id: str,
|
|
455
|
+
filename: str,
|
|
456
|
+
) -> Optional[int]:
|
|
457
|
+
"""
|
|
458
|
+
Retrieves the latest version number for a given artifact.
|
|
459
|
+
|
|
460
|
+
Args:
|
|
461
|
+
artifact_service: The artifact service instance.
|
|
462
|
+
app_name: The application name.
|
|
463
|
+
user_id: The user ID.
|
|
464
|
+
session_id: The session ID.
|
|
465
|
+
filename: The name of the artifact.
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
The latest version number as an integer, or None if no versions exist.
|
|
469
|
+
"""
|
|
470
|
+
log_identifier = f"[ArtifactHelper:get_latest_version:{filename}]"
|
|
471
|
+
try:
|
|
472
|
+
if not hasattr(artifact_service, "list_versions"):
|
|
473
|
+
log.warning(
|
|
474
|
+
"%s Artifact service does not support 'list_versions'.", log_identifier
|
|
475
|
+
)
|
|
476
|
+
return None
|
|
477
|
+
|
|
478
|
+
versions = await artifact_service.list_versions(
|
|
479
|
+
app_name=app_name, user_id=user_id, session_id=session_id, filename=filename
|
|
480
|
+
)
|
|
481
|
+
if not versions:
|
|
482
|
+
log.debug("%s No versions found for artifact.", log_identifier)
|
|
483
|
+
return None
|
|
484
|
+
|
|
485
|
+
latest_version = max(versions)
|
|
486
|
+
log.debug("%s Resolved latest version to %d.", log_identifier, latest_version)
|
|
487
|
+
return latest_version
|
|
488
|
+
except Exception as e:
|
|
489
|
+
log.error("%s Error resolving latest version: %s", log_identifier, e)
|
|
490
|
+
return None
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
async def get_artifact_info_list(
|
|
494
|
+
artifact_service: BaseArtifactService,
|
|
495
|
+
app_name: str,
|
|
496
|
+
user_id: str,
|
|
497
|
+
session_id: str,
|
|
498
|
+
) -> List[ArtifactInfo]:
|
|
499
|
+
"""
|
|
500
|
+
Retrieves detailed information for all artifacts using the artifact service.
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
artifact_service: The artifact service instance.
|
|
504
|
+
app_name: The application name.
|
|
505
|
+
user_id: The user ID.
|
|
506
|
+
session_id: The session ID.
|
|
507
|
+
|
|
508
|
+
Returns:
|
|
509
|
+
A list of ArtifactInfo objects.
|
|
510
|
+
"""
|
|
511
|
+
log_prefix = f"[ArtifactHelper:get_info_list] App={app_name}, User={user_id}, Session={session_id} -"
|
|
512
|
+
artifact_info_list: List[ArtifactInfo] = []
|
|
513
|
+
|
|
514
|
+
try:
|
|
515
|
+
list_keys_method = getattr(artifact_service, "list_artifact_keys")
|
|
516
|
+
keys = await list_keys_method(
|
|
517
|
+
app_name=app_name, user_id=user_id, session_id=session_id
|
|
518
|
+
)
|
|
519
|
+
log.info(
|
|
520
|
+
"%s Found %d artifact keys. Fetching details...", log_prefix, len(keys)
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
for filename in keys:
|
|
524
|
+
if filename.endswith(METADATA_SUFFIX):
|
|
525
|
+
continue
|
|
526
|
+
|
|
527
|
+
log_identifier_item = f"{log_prefix} [{filename}]"
|
|
528
|
+
try:
|
|
529
|
+
|
|
530
|
+
version_count: int = 0
|
|
531
|
+
latest_version_num: Optional[int] = await get_latest_artifact_version(
|
|
532
|
+
artifact_service, app_name, user_id, session_id, filename
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
if hasattr(artifact_service, "list_versions"):
|
|
536
|
+
try:
|
|
537
|
+
available_versions = await artifact_service.list_versions(
|
|
538
|
+
app_name=app_name,
|
|
539
|
+
user_id=user_id,
|
|
540
|
+
session_id=session_id,
|
|
541
|
+
filename=filename,
|
|
542
|
+
)
|
|
543
|
+
version_count = len(available_versions)
|
|
544
|
+
except Exception as list_ver_err:
|
|
545
|
+
log.error(
|
|
546
|
+
"%s Error listing versions for count: %s.",
|
|
547
|
+
log_identifier_item,
|
|
548
|
+
list_ver_err,
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
data = await load_artifact_content_or_metadata(
|
|
552
|
+
artifact_service=artifact_service,
|
|
553
|
+
app_name=app_name,
|
|
554
|
+
user_id=user_id,
|
|
555
|
+
session_id=session_id,
|
|
556
|
+
filename=filename,
|
|
557
|
+
version="latest",
|
|
558
|
+
load_metadata_only=True,
|
|
559
|
+
log_identifier_prefix=log_identifier_item,
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
metadata = data.get("metadata", {})
|
|
563
|
+
mime_type = metadata.get("mime_type", "application/data")
|
|
564
|
+
size = metadata.get("size_bytes", 0)
|
|
565
|
+
schema_definition = metadata.get("schema", {})
|
|
566
|
+
description = metadata.get("description", "No description provided")
|
|
567
|
+
loaded_version_num = data.get("version", latest_version_num)
|
|
568
|
+
|
|
569
|
+
last_modified_ts = metadata.get("timestamp_utc")
|
|
570
|
+
last_modified_ts = metadata.get("timestamp_utc")
|
|
571
|
+
last_modified_iso = (
|
|
572
|
+
datetime.fromtimestamp(
|
|
573
|
+
last_modified_ts, tz=timezone.utc
|
|
574
|
+
).isoformat()
|
|
575
|
+
if last_modified_ts
|
|
576
|
+
else None
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
artifact_info_list.append(
|
|
580
|
+
ArtifactInfo(
|
|
581
|
+
filename=filename,
|
|
582
|
+
mime_type=mime_type,
|
|
583
|
+
size=size,
|
|
584
|
+
last_modified=last_modified_iso,
|
|
585
|
+
schema_definition=schema_definition,
|
|
586
|
+
description=description,
|
|
587
|
+
version=loaded_version_num,
|
|
588
|
+
version_count=version_count,
|
|
589
|
+
)
|
|
590
|
+
)
|
|
591
|
+
log.debug(
|
|
592
|
+
"%s Successfully processed artifact info.", log_identifier_item
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
except FileNotFoundError:
|
|
596
|
+
log.warning(
|
|
597
|
+
"%s Artifact file not found by service for key '%s'. Skipping.",
|
|
598
|
+
log_prefix,
|
|
599
|
+
filename,
|
|
600
|
+
)
|
|
601
|
+
except Exception as detail_e:
|
|
602
|
+
log.error(
|
|
603
|
+
"%s Error processing details for artifact '%s': %s\n%s",
|
|
604
|
+
log_prefix,
|
|
605
|
+
filename,
|
|
606
|
+
detail_e,
|
|
607
|
+
traceback.format_exc(),
|
|
608
|
+
)
|
|
609
|
+
artifact_info_list.append(
|
|
610
|
+
ArtifactInfo(
|
|
611
|
+
filename=filename,
|
|
612
|
+
size=0,
|
|
613
|
+
description=f"Error loading details: {detail_e}",
|
|
614
|
+
mime_type="application/octet-stream",
|
|
615
|
+
)
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
except Exception as e:
|
|
619
|
+
log.exception(
|
|
620
|
+
"%s Error listing artifact keys or processing list: %s", log_prefix, e
|
|
621
|
+
)
|
|
622
|
+
return []
|
|
623
|
+
return artifact_info_list
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
async def load_artifact_content_or_metadata(
|
|
627
|
+
artifact_service: BaseArtifactService,
|
|
628
|
+
app_name: str,
|
|
629
|
+
user_id: str,
|
|
630
|
+
session_id: str,
|
|
631
|
+
filename: str,
|
|
632
|
+
version: Union[int, str],
|
|
633
|
+
load_metadata_only: bool = False,
|
|
634
|
+
return_raw_bytes: bool = False,
|
|
635
|
+
max_content_length: Optional[int] = None,
|
|
636
|
+
component: Optional[Any] = None,
|
|
637
|
+
log_identifier_prefix: str = "[ArtifactHelper:load]",
|
|
638
|
+
encoding: str = "utf-8",
|
|
639
|
+
error_handling: str = "strict",
|
|
640
|
+
) -> Dict[str, Any]:
|
|
641
|
+
"""
|
|
642
|
+
Loads the content or metadata of a specific artifact version using the artifact service.
|
|
643
|
+
"""
|
|
644
|
+
log_identifier_req = f"{log_identifier_prefix}:{filename}:{version}"
|
|
645
|
+
log.debug(
|
|
646
|
+
"%s Processing request (load_metadata_only=%s, return_raw_bytes=%s) (async).",
|
|
647
|
+
log_identifier_req,
|
|
648
|
+
load_metadata_only,
|
|
649
|
+
return_raw_bytes,
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
if max_content_length is None and component:
|
|
653
|
+
max_content_length = component.get_config(
|
|
654
|
+
"text_artifact_content_max_length", 1000
|
|
655
|
+
)
|
|
656
|
+
if max_content_length < 100:
|
|
657
|
+
log.warning(
|
|
658
|
+
"%s text_artifact_content_max_length too small (%d), using minimum: 100",
|
|
659
|
+
log_identifier_req,
|
|
660
|
+
max_content_length,
|
|
661
|
+
)
|
|
662
|
+
max_content_length = 100
|
|
663
|
+
elif max_content_length > 100000:
|
|
664
|
+
log.warning(
|
|
665
|
+
"%s text_artifact_content_max_length too large (%d), using maximum: 100000",
|
|
666
|
+
log_identifier_req,
|
|
667
|
+
max_content_length,
|
|
668
|
+
)
|
|
669
|
+
max_content_length = 100000
|
|
670
|
+
elif max_content_length is None:
|
|
671
|
+
max_content_length = 1000
|
|
672
|
+
|
|
673
|
+
log.debug(
|
|
674
|
+
"%s Using max_content_length: %d characters (from %s).",
|
|
675
|
+
log_identifier_req,
|
|
676
|
+
max_content_length,
|
|
677
|
+
"app config" if component else "default",
|
|
678
|
+
)
|
|
679
|
+
|
|
680
|
+
try:
|
|
681
|
+
actual_version: int
|
|
682
|
+
if isinstance(version, str) and version.lower() == "latest":
|
|
683
|
+
log.debug(
|
|
684
|
+
"%s Requested version is 'latest', resolving...", log_identifier_req
|
|
685
|
+
)
|
|
686
|
+
try:
|
|
687
|
+
list_versions_method = getattr(artifact_service, "list_versions")
|
|
688
|
+
available_versions = await list_versions_method(
|
|
689
|
+
app_name=app_name,
|
|
690
|
+
user_id=user_id,
|
|
691
|
+
session_id=session_id,
|
|
692
|
+
filename=filename,
|
|
693
|
+
)
|
|
694
|
+
if not available_versions:
|
|
695
|
+
raise FileNotFoundError(
|
|
696
|
+
f"Artifact '{filename}' has no versions available to determine 'latest'."
|
|
697
|
+
)
|
|
698
|
+
actual_version = max(available_versions)
|
|
699
|
+
log.info(
|
|
700
|
+
"%s Resolved 'latest' to version %d.",
|
|
701
|
+
log_identifier_req,
|
|
702
|
+
actual_version,
|
|
703
|
+
)
|
|
704
|
+
except Exception as list_err:
|
|
705
|
+
log.error(
|
|
706
|
+
"%s Failed to list versions for '%s' to resolve 'latest': %s",
|
|
707
|
+
log_identifier_req,
|
|
708
|
+
filename,
|
|
709
|
+
list_err,
|
|
710
|
+
)
|
|
711
|
+
raise FileNotFoundError(
|
|
712
|
+
f"Could not determine latest version for '{filename}': {list_err}"
|
|
713
|
+
) from list_err
|
|
714
|
+
elif isinstance(version, int):
|
|
715
|
+
actual_version = version
|
|
716
|
+
elif isinstance(version, str):
|
|
717
|
+
try:
|
|
718
|
+
actual_version = int(version)
|
|
719
|
+
except ValueError:
|
|
720
|
+
raise ValueError(
|
|
721
|
+
f"Invalid version specified: '{version}'. Must be a positive integer string or 'latest'."
|
|
722
|
+
)
|
|
723
|
+
else:
|
|
724
|
+
raise ValueError(
|
|
725
|
+
f"Invalid version type: '{type(version).__name__}'. Must be an integer or 'latest'."
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
if actual_version < 0:
|
|
729
|
+
raise ValueError(
|
|
730
|
+
f"Version number must be a positive integer. Got: {actual_version}"
|
|
731
|
+
)
|
|
732
|
+
|
|
733
|
+
target_filename = (
|
|
734
|
+
f"{filename}{METADATA_SUFFIX}" if load_metadata_only else filename
|
|
735
|
+
)
|
|
736
|
+
version_to_load = actual_version
|
|
737
|
+
|
|
738
|
+
log_identifier = f"{log_identifier_prefix}:{filename}:{version_to_load}"
|
|
739
|
+
|
|
740
|
+
log.debug(
|
|
741
|
+
"%s Attempting to load '%s' v%d (async)",
|
|
742
|
+
log_identifier,
|
|
743
|
+
target_filename,
|
|
744
|
+
version_to_load,
|
|
745
|
+
)
|
|
746
|
+
|
|
747
|
+
load_artifact_method = getattr(artifact_service, "load_artifact")
|
|
748
|
+
artifact_part = await load_artifact_method(
|
|
749
|
+
app_name=app_name,
|
|
750
|
+
user_id=user_id,
|
|
751
|
+
session_id=session_id,
|
|
752
|
+
filename=target_filename,
|
|
753
|
+
version=version_to_load,
|
|
754
|
+
)
|
|
755
|
+
|
|
756
|
+
if not artifact_part or not artifact_part.inline_data:
|
|
757
|
+
raise FileNotFoundError(
|
|
758
|
+
f"Artifact '{target_filename}' version {version_to_load} not found or has no data."
|
|
759
|
+
)
|
|
760
|
+
|
|
761
|
+
mime_type = artifact_part.inline_data.mime_type
|
|
762
|
+
data_bytes = artifact_part.inline_data.data
|
|
763
|
+
size_bytes = len(data_bytes)
|
|
764
|
+
|
|
765
|
+
if load_metadata_only:
|
|
766
|
+
if mime_type != "application/json":
|
|
767
|
+
log.warning(
|
|
768
|
+
"%s Expected metadata file '%s' v%d to be application/json, but got '%s'. Attempting parse anyway.",
|
|
769
|
+
log_identifier,
|
|
770
|
+
target_filename,
|
|
771
|
+
version_to_load,
|
|
772
|
+
mime_type,
|
|
773
|
+
)
|
|
774
|
+
try:
|
|
775
|
+
metadata_dict = json.loads(data_bytes.decode("utf-8"))
|
|
776
|
+
log.info(
|
|
777
|
+
"%s Successfully loaded and parsed metadata for '%s' v%d.",
|
|
778
|
+
log_identifier,
|
|
779
|
+
filename,
|
|
780
|
+
version_to_load,
|
|
781
|
+
)
|
|
782
|
+
return {
|
|
783
|
+
"status": "success",
|
|
784
|
+
"filename": filename,
|
|
785
|
+
"version": version_to_load,
|
|
786
|
+
"metadata": metadata_dict,
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
except (json.JSONDecodeError, UnicodeDecodeError) as parse_err:
|
|
790
|
+
raise ValueError(
|
|
791
|
+
f"Failed to parse metadata file '{target_filename}' v{version_to_load}: {parse_err}"
|
|
792
|
+
) from parse_err
|
|
793
|
+
|
|
794
|
+
else:
|
|
795
|
+
if return_raw_bytes:
|
|
796
|
+
log.info(
|
|
797
|
+
"%s Loaded artifact '%s' v%d (%d bytes, type: %s). Returning raw_bytes.",
|
|
798
|
+
log_identifier,
|
|
799
|
+
filename,
|
|
800
|
+
version_to_load,
|
|
801
|
+
size_bytes,
|
|
802
|
+
mime_type,
|
|
803
|
+
)
|
|
804
|
+
return {
|
|
805
|
+
"status": "success",
|
|
806
|
+
"filename": filename,
|
|
807
|
+
"version": version_to_load,
|
|
808
|
+
"mime_type": mime_type,
|
|
809
|
+
"raw_bytes": data_bytes,
|
|
810
|
+
"size_bytes": size_bytes,
|
|
811
|
+
}
|
|
812
|
+
else:
|
|
813
|
+
is_text = is_text_based_file(mime_type, data_bytes)
|
|
814
|
+
|
|
815
|
+
if is_text:
|
|
816
|
+
try:
|
|
817
|
+
content_str = data_bytes.decode(encoding, errors=error_handling)
|
|
818
|
+
if len(content_str) > max_content_length:
|
|
819
|
+
truncated_content = content_str[:max_content_length] + "..."
|
|
820
|
+
log.info(
|
|
821
|
+
"%s Loaded and decoded text artifact '%s' v%d. Returning truncated content (%d chars, limit: %d).",
|
|
822
|
+
log_identifier,
|
|
823
|
+
filename,
|
|
824
|
+
version_to_load,
|
|
825
|
+
len(truncated_content),
|
|
826
|
+
max_content_length,
|
|
827
|
+
)
|
|
828
|
+
else:
|
|
829
|
+
truncated_content = content_str
|
|
830
|
+
log.info(
|
|
831
|
+
"%s Loaded and decoded text artifact '%s' v%d. Returning full content (%d chars).",
|
|
832
|
+
log_identifier,
|
|
833
|
+
filename,
|
|
834
|
+
version_to_load,
|
|
835
|
+
len(content_str),
|
|
836
|
+
)
|
|
837
|
+
return {
|
|
838
|
+
"status": "success",
|
|
839
|
+
"filename": filename,
|
|
840
|
+
"version": version_to_load,
|
|
841
|
+
"mime_type": mime_type,
|
|
842
|
+
"content": truncated_content,
|
|
843
|
+
"size_bytes": size_bytes,
|
|
844
|
+
}
|
|
845
|
+
except UnicodeDecodeError as decode_err:
|
|
846
|
+
log.error(
|
|
847
|
+
"%s Failed to decode text artifact '%s' v%d with encoding '%s': %s",
|
|
848
|
+
log_identifier,
|
|
849
|
+
filename,
|
|
850
|
+
version_to_load,
|
|
851
|
+
mime_type,
|
|
852
|
+
decode_err,
|
|
853
|
+
)
|
|
854
|
+
raise ValueError(
|
|
855
|
+
f"Failed to decode artifact '{filename}' v{version_to_load} as {encoding}."
|
|
856
|
+
) from decode_err
|
|
857
|
+
else:
|
|
858
|
+
log.info(
|
|
859
|
+
"%s Loaded binary/unknown artifact '%s' v%d. Returning metadata summary.",
|
|
860
|
+
log_identifier,
|
|
861
|
+
filename,
|
|
862
|
+
version_to_load,
|
|
863
|
+
)
|
|
864
|
+
|
|
865
|
+
metadata_for_binary = {}
|
|
866
|
+
if not filename.endswith(METADATA_SUFFIX):
|
|
867
|
+
try:
|
|
868
|
+
metadata_filename_for_binary = (
|
|
869
|
+
f"{filename}{METADATA_SUFFIX}"
|
|
870
|
+
)
|
|
871
|
+
log.debug(
|
|
872
|
+
"%s Attempting to load linked metadata file '%s' for binary artifact '%s' v%d.",
|
|
873
|
+
log_identifier,
|
|
874
|
+
metadata_filename_for_binary,
|
|
875
|
+
filename,
|
|
876
|
+
version_to_load,
|
|
877
|
+
)
|
|
878
|
+
metadata_data = await load_artifact_content_or_metadata(
|
|
879
|
+
artifact_service=artifact_service,
|
|
880
|
+
app_name=app_name,
|
|
881
|
+
user_id=user_id,
|
|
882
|
+
session_id=session_id,
|
|
883
|
+
filename=f"{filename}{METADATA_SUFFIX}",
|
|
884
|
+
version=version,
|
|
885
|
+
load_metadata_only=True,
|
|
886
|
+
log_identifier_prefix=f"{log_identifier}[meta_for_binary]",
|
|
887
|
+
)
|
|
888
|
+
if metadata_data.get("status") == "success":
|
|
889
|
+
metadata_for_binary = metadata_data.get("metadata", {})
|
|
890
|
+
except Exception as e_meta_bin:
|
|
891
|
+
log.warning(
|
|
892
|
+
f"{log_identifier} Could not load metadata for binary artifact {filename}: {e_meta_bin}"
|
|
893
|
+
)
|
|
894
|
+
metadata_for_binary = {
|
|
895
|
+
"error": f"Could not load metadata: {e_meta_bin}"
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
return {
|
|
899
|
+
"status": "success",
|
|
900
|
+
"filename": filename,
|
|
901
|
+
"version": version_to_load,
|
|
902
|
+
"mime_type": mime_type,
|
|
903
|
+
"size_bytes": size_bytes,
|
|
904
|
+
"metadata": metadata_for_binary,
|
|
905
|
+
"content": f"Binary data of type {mime_type}. Content not displayed.",
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
except FileNotFoundError as fnf_err:
|
|
909
|
+
log.warning("%s Artifact not found: %s", log_identifier_req, fnf_err)
|
|
910
|
+
return {"status": "not_found", "message": str(fnf_err)}
|
|
911
|
+
except ValueError as val_err:
|
|
912
|
+
log.error(
|
|
913
|
+
"%s Value error during artifact load: %s", log_identifier_req, val_err
|
|
914
|
+
)
|
|
915
|
+
return {"status": "error", "message": str(val_err)}
|
|
916
|
+
except Exception as e:
|
|
917
|
+
log.exception(
|
|
918
|
+
"%s Unexpected error loading artifact '%s' version '%s': %s",
|
|
919
|
+
log_identifier_req,
|
|
920
|
+
filename,
|
|
921
|
+
version,
|
|
922
|
+
e,
|
|
923
|
+
)
|
|
924
|
+
return {
|
|
925
|
+
"status": "error",
|
|
926
|
+
"message": f"Unexpected error loading artifact: {e}",
|
|
927
|
+
}
|