solace-agent-mesh 1.11.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.
- solace_agent_mesh/__init__.py +0 -0
- solace_agent_mesh/agent/__init__.py +0 -0
- solace_agent_mesh/agent/adk/__init__.py +0 -0
- solace_agent_mesh/agent/adk/adk_llm.txt +226 -0
- solace_agent_mesh/agent/adk/adk_llm_detail.txt +566 -0
- solace_agent_mesh/agent/adk/alembic/README +74 -0
- solace_agent_mesh/agent/adk/alembic/env.py +77 -0
- solace_agent_mesh/agent/adk/alembic/script.py.mako +28 -0
- solace_agent_mesh/agent/adk/alembic/versions/e2902798564d_adk_session_db_upgrade.py +52 -0
- solace_agent_mesh/agent/adk/alembic.ini +112 -0
- solace_agent_mesh/agent/adk/app_llm_agent.py +52 -0
- solace_agent_mesh/agent/adk/artifacts/__init__.py +1 -0
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +171 -0
- solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +545 -0
- solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +609 -0
- solace_agent_mesh/agent/adk/callbacks.py +2318 -0
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +406 -0
- solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +415 -0
- solace_agent_mesh/agent/adk/mcp_content_processor.py +666 -0
- solace_agent_mesh/agent/adk/models/lite_llm.py +1026 -0
- solace_agent_mesh/agent/adk/models/models_llm.txt +189 -0
- solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +132 -0
- solace_agent_mesh/agent/adk/runner.py +390 -0
- solace_agent_mesh/agent/adk/schema_migration.py +88 -0
- solace_agent_mesh/agent/adk/services.py +468 -0
- solace_agent_mesh/agent/adk/setup.py +1325 -0
- solace_agent_mesh/agent/adk/stream_parser.py +415 -0
- solace_agent_mesh/agent/adk/tool_wrapper.py +165 -0
- solace_agent_mesh/agent/agent_llm.txt +369 -0
- solace_agent_mesh/agent/agent_llm_detail.txt +1702 -0
- solace_agent_mesh/agent/protocol/__init__.py +0 -0
- solace_agent_mesh/agent/protocol/event_handlers.py +2041 -0
- solace_agent_mesh/agent/protocol/protocol_llm.txt +81 -0
- solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +92 -0
- solace_agent_mesh/agent/proxies/__init__.py +0 -0
- solace_agent_mesh/agent/proxies/a2a/__init__.py +3 -0
- solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +190 -0
- solace_agent_mesh/agent/proxies/a2a/app.py +56 -0
- solace_agent_mesh/agent/proxies/a2a/component.py +1585 -0
- solace_agent_mesh/agent/proxies/a2a/config.py +216 -0
- solace_agent_mesh/agent/proxies/a2a/oauth_token_cache.py +104 -0
- solace_agent_mesh/agent/proxies/base/__init__.py +3 -0
- solace_agent_mesh/agent/proxies/base/app.py +100 -0
- solace_agent_mesh/agent/proxies/base/base_llm.txt +148 -0
- solace_agent_mesh/agent/proxies/base/component.py +816 -0
- solace_agent_mesh/agent/proxies/base/config.py +85 -0
- solace_agent_mesh/agent/proxies/base/proxy_task_context.py +19 -0
- solace_agent_mesh/agent/proxies/proxies_llm.txt +283 -0
- solace_agent_mesh/agent/sac/__init__.py +0 -0
- solace_agent_mesh/agent/sac/app.py +595 -0
- solace_agent_mesh/agent/sac/component.py +3668 -0
- solace_agent_mesh/agent/sac/patch_adk.py +103 -0
- solace_agent_mesh/agent/sac/sac_llm.txt +189 -0
- solace_agent_mesh/agent/sac/sac_llm_detail.txt +200 -0
- solace_agent_mesh/agent/sac/task_execution_context.py +415 -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 +58 -0
- solace_agent_mesh/agent/testing/testing_llm_detail.txt +68 -0
- solace_agent_mesh/agent/tools/__init__.py +16 -0
- solace_agent_mesh/agent/tools/audio_tools.py +1740 -0
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +2500 -0
- solace_agent_mesh/agent/tools/builtin_data_analysis_tools.py +244 -0
- solace_agent_mesh/agent/tools/dynamic_tool.py +396 -0
- solace_agent_mesh/agent/tools/general_agent_tools.py +572 -0
- solace_agent_mesh/agent/tools/image_tools.py +1185 -0
- solace_agent_mesh/agent/tools/peer_agent_tool.py +363 -0
- solace_agent_mesh/agent/tools/registry.py +38 -0
- solace_agent_mesh/agent/tools/test_tools.py +136 -0
- solace_agent_mesh/agent/tools/time_tools.py +126 -0
- solace_agent_mesh/agent/tools/tool_config_types.py +93 -0
- solace_agent_mesh/agent/tools/tool_definition.py +53 -0
- solace_agent_mesh/agent/tools/tools_llm.txt +276 -0
- solace_agent_mesh/agent/tools/tools_llm_detail.txt +275 -0
- solace_agent_mesh/agent/tools/web_tools.py +392 -0
- solace_agent_mesh/agent/utils/__init__.py +0 -0
- solace_agent_mesh/agent/utils/artifact_helpers.py +1353 -0
- solace_agent_mesh/agent/utils/config_parser.py +49 -0
- solace_agent_mesh/agent/utils/context_helpers.py +77 -0
- solace_agent_mesh/agent/utils/utils_llm.txt +152 -0
- solace_agent_mesh/agent/utils/utils_llm_detail.txt +149 -0
- solace_agent_mesh/assets/docs/404.html +16 -0
- solace_agent_mesh/assets/docs/assets/css/styles.8162edfb.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/sam-enterprise-credentials-b269f095349473118b2b33bdfcc40122.png +0 -0
- solace_agent_mesh/assets/docs/assets/js/032c2d61.f3d37824.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/05749d90.19ac4f35.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/0bcf40b7.c019ad46.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1001.0182a8bd.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/15ba94aa.92fea363.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15e40e79.434bb30f.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/17896441.e612dfb4.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2130.ab9fd314.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2131ec11.5c7a1f6e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2237.5e477fc6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js.LICENSE.txt +13 -0
- solace_agent_mesh/assets/docs/assets/js/2334.1cf50a20.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/240a0364.9ad94d1b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2987107d.a80604f9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3219.adc1d663.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/341393d4.0fac2613.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3624.0eaa1fd0.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/3a6c6137.f5940cfa.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.28b7c67b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.2ddc75c0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/41adc471.48b12a4e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4250.95455b28.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4356.d169ab5b.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/509e993c.a1fbf45a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5388.7a136447.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55b7b518.29d6e75d.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/5c2bd65f.90a87880.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5e95c892.558d5167.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6063ff4c.ef84f702.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/60702c0e.a8bdd79b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6143.0a1464c9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/631738c7.fa471607.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6395.e9c73649.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/66d4869e.b77431fc.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/6a520c9d.b6e3f2ce.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6fdfefc7.99de744e.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/71da7b71.374b9d54.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/722f809d.965da774.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7280.3fb73bdb.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/742f027b.46c07808.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/77cf947d.48cb18a2.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/8024126c.fa0e7186.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/81a99df0.2484b8d9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/82fbfb93.161823a5.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8356.8a379c04.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.5d015485.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/8591.5d015485.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.6c1dbf0c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8908.f9d1b506.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8b032486.91a91afc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9157.b4093d07.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/924ffdeb.975e428a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9278.a4fd875d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/945fb41e.6f4cdffd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/94e8668d.16083b3f.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/9bb13469.b2333011.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9e9d0a82.570c057b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a7bd4aaa.2204d2f7.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a94703ab.3e5fbcb3.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ab9708a8.245ae0ef.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/aba21aa0.c42a534c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ad71b5ed.af3ecfd1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ad87452a.9d73dad6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c198a0dc.8f31f867.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c93cbaa0.0e0d8baf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cab03b5b.6a073091.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.07e170dd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ceb2a7a6.5d92d7d0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/da0b5bad.b62f7b08.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/db924877.e98d12a1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd817ffc.c37a755e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de5f4c65.e8241890.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e04b235d.52cb25ed.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.b1068f9b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.1476f570.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e6f9706b.4488e34c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.250993bf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ff4d71f2.74710fc1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.7acf7ace.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/main.7acf7ace.js.LICENSE.txt +81 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.9e0813a2.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +154 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +99 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +90 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +107 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +166 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +101 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +219 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +92 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/index.html +29 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +55 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +110 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +182 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +147 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +345 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +52 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +83 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +84 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +25 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +47 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +85 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +60 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +49 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +144 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +191 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +128 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +54 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +135 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +34 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +55 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +267 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +142 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +116 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +86 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +164 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +140 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +57 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +72 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +102 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +115 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +86 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +67 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +37 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +86 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +324 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +247 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +184 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +62 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +75 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +54 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +85 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +41 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +290 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +78 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +25 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +78 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +160 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +142 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +251 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +88 -0
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +100 -0
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +52 -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/sam-enterprise-credentials.png +0 -0
- solace_agent_mesh/assets/docs/img/solace-logo-text.svg +18 -0
- solace_agent_mesh/assets/docs/img/solace-logo.png +0 -0
- solace_agent_mesh/assets/docs/lunr-index-1765810064709.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -0
- solace_agent_mesh/assets/docs/search-doc-1765810064709.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 -0
- solace_agent_mesh/cli/commands/__init__.py +0 -0
- 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 +729 -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 +102 -0
- solace_agent_mesh/cli/commands/add_cmd/web_add_gateway_step.py +114 -0
- solace_agent_mesh/cli/commands/docs_cmd.py +60 -0
- solace_agent_mesh/cli/commands/eval_cmd.py +46 -0
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +439 -0
- solace_agent_mesh/cli/commands/init_cmd/broker_step.py +201 -0
- solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
- solace_agent_mesh/cli/commands/init_cmd/directory_step.py +28 -0
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +238 -0
- solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +365 -0
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +464 -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 +119 -0
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +215 -0
- solace_agent_mesh/cli/commands/plugin_cmd/__init__.py +20 -0
- solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +137 -0
- solace_agent_mesh/cli/commands/plugin_cmd/build_cmd.py +86 -0
- solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +144 -0
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +306 -0
- solace_agent_mesh/cli/commands/plugin_cmd/install_cmd.py +283 -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 +215 -0
- solace_agent_mesh/cli/main.py +52 -0
- solace_agent_mesh/cli/utils.py +262 -0
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-Dj3JtK42.js +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/client-ZKk9kEJ5.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/favicon-BLgzUch9.ico +0 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-BcUaNZ-Q.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-vjch4RYc.js +435 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-BNV4kZN0.js +535 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +15 -0
- solace_agent_mesh/client/webui/frontend/static/index.html +16 -0
- solace_agent_mesh/client/webui/frontend/static/mockServiceWorker.js +336 -0
- solace_agent_mesh/client/webui/frontend/static/ui-version.json +6 -0
- solace_agent_mesh/common/__init__.py +1 -0
- solace_agent_mesh/common/a2a/__init__.py +241 -0
- solace_agent_mesh/common/a2a/a2a_llm.txt +175 -0
- solace_agent_mesh/common/a2a/a2a_llm_detail.txt +193 -0
- solace_agent_mesh/common/a2a/artifact.py +368 -0
- solace_agent_mesh/common/a2a/events.py +213 -0
- solace_agent_mesh/common/a2a/message.py +375 -0
- solace_agent_mesh/common/a2a/protocol.py +689 -0
- solace_agent_mesh/common/a2a/task.py +127 -0
- solace_agent_mesh/common/a2a/translation.py +655 -0
- solace_agent_mesh/common/a2a/types.py +55 -0
- solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +445 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +736 -0
- solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
- solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +48 -0
- solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
- solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +41 -0
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +330 -0
- solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
- solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +48 -0
- solace_agent_mesh/common/agent_registry.py +122 -0
- solace_agent_mesh/common/common_llm.txt +230 -0
- solace_agent_mesh/common/common_llm_detail.txt +2562 -0
- solace_agent_mesh/common/constants.py +6 -0
- solace_agent_mesh/common/data_parts.py +150 -0
- solace_agent_mesh/common/exceptions.py +49 -0
- solace_agent_mesh/common/middleware/__init__.py +12 -0
- solace_agent_mesh/common/middleware/config_resolver.py +132 -0
- solace_agent_mesh/common/middleware/middleware_llm.txt +174 -0
- solace_agent_mesh/common/middleware/middleware_llm_detail.txt +185 -0
- solace_agent_mesh/common/middleware/registry.py +127 -0
- solace_agent_mesh/common/oauth/__init__.py +17 -0
- solace_agent_mesh/common/oauth/oauth_client.py +408 -0
- solace_agent_mesh/common/oauth/utils.py +50 -0
- solace_agent_mesh/common/sac/__init__.py +0 -0
- solace_agent_mesh/common/sac/sac_llm.txt +71 -0
- solace_agent_mesh/common/sac/sac_llm_detail.txt +82 -0
- solace_agent_mesh/common/sac/sam_component_base.py +730 -0
- solace_agent_mesh/common/sam_events/__init__.py +9 -0
- solace_agent_mesh/common/sam_events/event_service.py +208 -0
- solace_agent_mesh/common/sam_events/sam_events_llm.txt +104 -0
- solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +115 -0
- solace_agent_mesh/common/services/__init__.py +4 -0
- solace_agent_mesh/common/services/employee_service.py +164 -0
- solace_agent_mesh/common/services/identity_service.py +134 -0
- solace_agent_mesh/common/services/providers/__init__.py +4 -0
- solace_agent_mesh/common/services/providers/local_file_identity_service.py +151 -0
- solace_agent_mesh/common/services/providers/providers_llm.txt +81 -0
- solace_agent_mesh/common/services/services_llm.txt +368 -0
- solace_agent_mesh/common/services/services_llm_detail.txt +459 -0
- solace_agent_mesh/common/utils/__init__.py +7 -0
- solace_agent_mesh/common/utils/artifact_utils.py +31 -0
- solace_agent_mesh/common/utils/asyncio_macos_fix.py +88 -0
- solace_agent_mesh/common/utils/embeds/__init__.py +33 -0
- solace_agent_mesh/common/utils/embeds/constants.py +56 -0
- solace_agent_mesh/common/utils/embeds/converter.py +447 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +220 -0
- solace_agent_mesh/common/utils/embeds/evaluators.py +395 -0
- solace_agent_mesh/common/utils/embeds/modifiers.py +793 -0
- solace_agent_mesh/common/utils/embeds/resolver.py +967 -0
- solace_agent_mesh/common/utils/embeds/types.py +23 -0
- solace_agent_mesh/common/utils/in_memory_cache.py +108 -0
- solace_agent_mesh/common/utils/initializer.py +52 -0
- solace_agent_mesh/common/utils/log_formatters.py +64 -0
- solace_agent_mesh/common/utils/message_utils.py +80 -0
- solace_agent_mesh/common/utils/mime_helpers.py +172 -0
- solace_agent_mesh/common/utils/push_notification_auth.py +135 -0
- solace_agent_mesh/common/utils/pydantic_utils.py +159 -0
- solace_agent_mesh/common/utils/rbac_utils.py +69 -0
- solace_agent_mesh/common/utils/templates/__init__.py +8 -0
- solace_agent_mesh/common/utils/templates/liquid_renderer.py +210 -0
- solace_agent_mesh/common/utils/templates/template_resolver.py +161 -0
- solace_agent_mesh/common/utils/type_utils.py +28 -0
- solace_agent_mesh/common/utils/utils_llm.txt +335 -0
- solace_agent_mesh/common/utils/utils_llm_detail.txt +572 -0
- solace_agent_mesh/config_portal/__init__.py +0 -0
- solace_agent_mesh/config_portal/backend/__init__.py +0 -0
- solace_agent_mesh/config_portal/backend/common.py +77 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/__init__.py +0 -0
- 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 +166 -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 +644 -0
- solace_agent_mesh/config_portal/frontend/static/client/Solace_community_logo.png +0 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-DiOiAjzL.js +103 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/components-Rk0n-9cK.js +140 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/entry.client-mvZjNKiz.js +19 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/index-DzNKzXrc.js +68 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-ba77705e.js +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-B17tZKK7.css +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-V2BeTIUc.js +10 -0
- solace_agent_mesh/config_portal/frontend/static/client/favicon.ico +0 -0
- solace_agent_mesh/config_portal/frontend/static/client/index.html +7 -0
- solace_agent_mesh/core_a2a/__init__.py +1 -0
- solace_agent_mesh/core_a2a/core_a2a_llm.txt +90 -0
- solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +101 -0
- solace_agent_mesh/core_a2a/service.py +307 -0
- solace_agent_mesh/evaluation/__init__.py +0 -0
- solace_agent_mesh/evaluation/evaluator.py +691 -0
- solace_agent_mesh/evaluation/message_organizer.py +553 -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 +970 -0
- solace_agent_mesh/evaluation/report_generator.py +607 -0
- solace_agent_mesh/evaluation/run.py +954 -0
- solace_agent_mesh/evaluation/shared/__init__.py +92 -0
- solace_agent_mesh/evaluation/shared/constants.py +47 -0
- solace_agent_mesh/evaluation/shared/exceptions.py +50 -0
- solace_agent_mesh/evaluation/shared/helpers.py +35 -0
- solace_agent_mesh/evaluation/shared/test_case_loader.py +167 -0
- solace_agent_mesh/evaluation/shared/test_suite_loader.py +280 -0
- solace_agent_mesh/evaluation/subscriber.py +776 -0
- solace_agent_mesh/evaluation/summary_builder.py +880 -0
- solace_agent_mesh/gateway/__init__.py +0 -0
- solace_agent_mesh/gateway/adapter/__init__.py +1 -0
- solace_agent_mesh/gateway/adapter/base.py +143 -0
- solace_agent_mesh/gateway/adapter/types.py +221 -0
- solace_agent_mesh/gateway/base/__init__.py +1 -0
- solace_agent_mesh/gateway/base/app.py +345 -0
- solace_agent_mesh/gateway/base/base_llm.txt +226 -0
- solace_agent_mesh/gateway/base/base_llm_detail.txt +235 -0
- solace_agent_mesh/gateway/base/component.py +2030 -0
- solace_agent_mesh/gateway/base/task_context.py +75 -0
- solace_agent_mesh/gateway/gateway_llm.txt +369 -0
- solace_agent_mesh/gateway/gateway_llm_detail.txt +3885 -0
- solace_agent_mesh/gateway/generic/__init__.py +1 -0
- solace_agent_mesh/gateway/generic/app.py +50 -0
- solace_agent_mesh/gateway/generic/component.py +727 -0
- solace_agent_mesh/gateway/http_sse/__init__.py +0 -0
- solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +345 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +87 -0
- solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20250910_d5b3f8f2e9a0_create_initial_database.py +58 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20250911_b1c2d3e4f5g6_add_database_indexes.py +83 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20250916_f6e7d8c9b0a1_convert_timestamps_to_epoch_and_align_columns.py +412 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251006_98882922fa59_add_tasks_events_feedback_chat_tasks.py +190 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251015_add_session_performance_indexes.py +70 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_project_users_table.py +72 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +109 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +26 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_projects_table.py +135 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251108_create_prompt_tables_with_sharing.py +154 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251115_add_parent_task_id.py +32 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251126_add_background_task_fields.py +47 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251202_add_versioned_fields_to_prompts.py +52 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +161 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +109 -0
- solace_agent_mesh/gateway/http_sse/app.py +351 -0
- solace_agent_mesh/gateway/http_sse/component.py +2360 -0
- solace_agent_mesh/gateway/http_sse/components/__init__.py +7 -0
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +105 -0
- solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +109 -0
- solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +110 -0
- solace_agent_mesh/gateway/http_sse/dependencies.py +653 -0
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +299 -0
- solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +3278 -0
- solace_agent_mesh/gateway/http_sse/main.py +789 -0
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +46 -0
- solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +102 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +11 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/chat_task.py +75 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +221 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/feedback.py +20 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/project.py +81 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +47 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session.py +66 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +0 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/task.py +32 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/task_event.py +21 -0
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +125 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +239 -0
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +34 -0
- solace_agent_mesh/gateway/http_sse/repository/models/base.py +7 -0
- solace_agent_mesh/gateway/http_sse/repository/models/chat_task_model.py +31 -0
- solace_agent_mesh/gateway/http_sse/repository/models/feedback_model.py +21 -0
- solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +257 -0
- solace_agent_mesh/gateway/http_sse/repository/models/project_model.py +51 -0
- solace_agent_mesh/gateway/http_sse/repository/models/project_user_model.py +75 -0
- solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +159 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +53 -0
- solace_agent_mesh/gateway/http_sse/repository/models/task_event_model.py +25 -0
- solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +39 -0
- solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
- solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
- solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +308 -0
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +268 -0
- solace_agent_mesh/gateway/http_sse/repository/task_repository.py +248 -0
- solace_agent_mesh/gateway/http_sse/routers/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +74 -0
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +1137 -0
- solace_agent_mesh/gateway/http_sse/routers/auth.py +311 -0
- solace_agent_mesh/gateway/http_sse/routers/config.py +371 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/__init__.py +10 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +450 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/project_dto.py +69 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/prompt_dto.py +255 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +15 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/project_requests.py +48 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +133 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +33 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/task_requests.py +58 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +18 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +42 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +31 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +123 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +33 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/task_responses.py +30 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
- solace_agent_mesh/gateway/http_sse/routers/feedback.py +168 -0
- solace_agent_mesh/gateway/http_sse/routers/people.py +38 -0
- solace_agent_mesh/gateway/http_sse/routers/projects.py +767 -0
- solace_agent_mesh/gateway/http_sse/routers/prompts.py +1415 -0
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +312 -0
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +634 -0
- solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
- solace_agent_mesh/gateway/http_sse/routers/sse.py +230 -0
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +1089 -0
- solace_agent_mesh/gateway/http_sse/routers/users.py +83 -0
- solace_agent_mesh/gateway/http_sse/routers/version.py +343 -0
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +1220 -0
- solace_agent_mesh/gateway/http_sse/services/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/services/agent_card_service.py +71 -0
- solace_agent_mesh/gateway/http_sse/services/audio_service.py +1227 -0
- solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +186 -0
- solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +273 -0
- solace_agent_mesh/gateway/http_sse/services/feedback_service.py +250 -0
- solace_agent_mesh/gateway/http_sse/services/people_service.py +78 -0
- solace_agent_mesh/gateway/http_sse/services/project_service.py +930 -0
- solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +303 -0
- solace_agent_mesh/gateway/http_sse/services/session_service.py +702 -0
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +593 -0
- solace_agent_mesh/gateway/http_sse/services/task_service.py +119 -0
- solace_agent_mesh/gateway/http_sse/session_manager.py +219 -0
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +146 -0
- solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
- solace_agent_mesh/gateway/http_sse/shared/base_repository.py +252 -0
- solace_agent_mesh/gateway/http_sse/shared/database_exceptions.py +274 -0
- solace_agent_mesh/gateway/http_sse/shared/database_helpers.py +43 -0
- solace_agent_mesh/gateway/http_sse/shared/enums.py +40 -0
- solace_agent_mesh/gateway/http_sse/shared/error_dto.py +107 -0
- solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +217 -0
- solace_agent_mesh/gateway/http_sse/shared/exceptions.py +192 -0
- solace_agent_mesh/gateway/http_sse/shared/pagination.py +138 -0
- solace_agent_mesh/gateway/http_sse/shared/response_utils.py +134 -0
- solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +319 -0
- solace_agent_mesh/gateway/http_sse/shared/timestamp_utils.py +97 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +50 -0
- solace_agent_mesh/gateway/http_sse/shared/utils.py +22 -0
- solace_agent_mesh/gateway/http_sse/sse_event_buffer.py +88 -0
- solace_agent_mesh/gateway/http_sse/sse_manager.py +491 -0
- solace_agent_mesh/gateway/http_sse/utils/__init__.py +1 -0
- solace_agent_mesh/gateway/http_sse/utils/artifact_copy_utils.py +370 -0
- solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +72 -0
- solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +47 -0
- solace_agent_mesh/llm.txt +228 -0
- solace_agent_mesh/llm_detail.txt +2835 -0
- solace_agent_mesh/services/__init__.py +0 -0
- solace_agent_mesh/services/platform/__init__.py +18 -0
- solace_agent_mesh/services/platform/alembic/env.py +85 -0
- solace_agent_mesh/services/platform/alembic/script.py.mako +28 -0
- solace_agent_mesh/services/platform/alembic.ini +109 -0
- solace_agent_mesh/services/platform/api/__init__.py +3 -0
- solace_agent_mesh/services/platform/api/dependencies.py +147 -0
- solace_agent_mesh/services/platform/api/main.py +280 -0
- solace_agent_mesh/services/platform/api/middleware.py +51 -0
- solace_agent_mesh/services/platform/api/routers/__init__.py +24 -0
- solace_agent_mesh/services/platform/app.py +114 -0
- solace_agent_mesh/services/platform/component.py +235 -0
- solace_agent_mesh/solace_agent_mesh_llm.txt +362 -0
- solace_agent_mesh/solace_agent_mesh_llm_detail.txt +8599 -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 +75 -0
- solace_agent_mesh/templates/gateway_component_template.py +484 -0
- solace_agent_mesh/templates/gateway_config_template.yaml +38 -0
- solace_agent_mesh/templates/logging_config_template.yaml +48 -0
- solace_agent_mesh/templates/main_orchestrator.yaml +66 -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 +60 -0
- solace_agent_mesh/templates/plugin_pyproject_template.toml +32 -0
- solace_agent_mesh/templates/plugin_readme_template.md +12 -0
- solace_agent_mesh/templates/plugin_tool_config_template.yaml +109 -0
- solace_agent_mesh/templates/plugin_tools_template.py +224 -0
- solace_agent_mesh/templates/shared_config.yaml +112 -0
- solace_agent_mesh/templates/templates_llm.txt +147 -0
- solace_agent_mesh/templates/webui.yaml +177 -0
- solace_agent_mesh-1.11.2.dist-info/METADATA +504 -0
- solace_agent_mesh-1.11.2.dist-info/RECORD +624 -0
- solace_agent_mesh-1.11.2.dist-info/WHEEL +4 -0
- solace_agent_mesh-1.11.2.dist-info/entry_points.txt +3 -0
- solace_agent_mesh-1.11.2.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,954 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Refactored evaluation runner with improved structure and readability.
|
|
3
|
+
This module orchestrates the evaluation of AI models against test cases.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
import mimetypes
|
|
9
|
+
import os
|
|
10
|
+
import shutil
|
|
11
|
+
import subprocess
|
|
12
|
+
import sys
|
|
13
|
+
import threading
|
|
14
|
+
import time
|
|
15
|
+
import uuid
|
|
16
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from importlib import metadata
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
import click
|
|
22
|
+
import requests
|
|
23
|
+
from dotenv import load_dotenv
|
|
24
|
+
|
|
25
|
+
from .evaluator import EvaluationOrchestrator
|
|
26
|
+
from .message_organizer import MessageOrganizer
|
|
27
|
+
from .report_generator import ReportGenerator
|
|
28
|
+
from .shared import (
|
|
29
|
+
DEFAULT_STARTUP_WAIT_TIME,
|
|
30
|
+
DEFAULT_TEST_TIMEOUT,
|
|
31
|
+
EVALUATION_DIR,
|
|
32
|
+
MAX_ARTIFACT_SIZE_MB,
|
|
33
|
+
EvaluationConfigLoader,
|
|
34
|
+
TestSuiteConfiguration,
|
|
35
|
+
get_local_base_url,
|
|
36
|
+
)
|
|
37
|
+
from .subscriber import Subscriber
|
|
38
|
+
from .summary_builder import SummaryBuilder
|
|
39
|
+
|
|
40
|
+
log = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _error_exit(message: str):
|
|
44
|
+
"""Logs an error message and exits."""
|
|
45
|
+
log.error(message)
|
|
46
|
+
sys.exit(1)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _ensure_eval_backend_config_exists():
|
|
50
|
+
"""Checks for eval_backend.yaml and creates it from a template if missing."""
|
|
51
|
+
project_root = Path.cwd()
|
|
52
|
+
configs_dir = project_root / "configs"
|
|
53
|
+
eval_backend_config_path = configs_dir / "eval_backend.yaml"
|
|
54
|
+
|
|
55
|
+
if eval_backend_config_path.exists():
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
click.echo(
|
|
59
|
+
f"'{eval_backend_config_path.relative_to(project_root)}' not found. Creating it..."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
if not (configs_dir / "shared_config.yaml").exists():
|
|
63
|
+
_error_exit(
|
|
64
|
+
"Error: 'configs/shared_config.yaml' not found. Please run 'sam init' first."
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
# This is a simplified way to get the template content.
|
|
69
|
+
# In a real CLI, you'd use a more robust method like `importlib.resources`.
|
|
70
|
+
template_path = Path(__file__).parent.parent / "templates" / "eval_backend_template.yaml"
|
|
71
|
+
with open(template_path, encoding="utf-8") as f:
|
|
72
|
+
template_content = f.read()
|
|
73
|
+
|
|
74
|
+
with open(eval_backend_config_path, "w", encoding="utf-8") as f:
|
|
75
|
+
f.write(template_content)
|
|
76
|
+
click.echo(
|
|
77
|
+
click.style(
|
|
78
|
+
f"Successfully created '{eval_backend_config_path.relative_to(project_root)}'.",
|
|
79
|
+
fg="green",
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
except Exception as e:
|
|
83
|
+
_error_exit(f"Failed to create eval_backend.yaml: {e}")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _ensure_sam_rest_gateway_installed():
|
|
87
|
+
"""Checks if the sam-rest-gateway package is installed for local evaluation."""
|
|
88
|
+
try:
|
|
89
|
+
metadata.distribution("sam-rest-gateway")
|
|
90
|
+
except metadata.PackageNotFoundError:
|
|
91
|
+
_error_exit(
|
|
92
|
+
"Error: 'sam-rest-gateway' is not installed. "
|
|
93
|
+
"Please install it using: "
|
|
94
|
+
'pip install "sam-rest-gateway @ git+https://github.com/SolaceLabs/solace-agent-mesh-core-plugins#subdirectory=sam-rest-gateway"'
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass
|
|
99
|
+
class TestRun:
|
|
100
|
+
"""Represents a single test execution with all necessary parameters."""
|
|
101
|
+
|
|
102
|
+
agent: str
|
|
103
|
+
query: str
|
|
104
|
+
artifacts: list[str]
|
|
105
|
+
wait_time: int
|
|
106
|
+
test_case_file: str
|
|
107
|
+
run_num: int
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def test_case_id(self) -> str:
|
|
111
|
+
"""Extract test case ID from filename."""
|
|
112
|
+
return Path(self.test_case_file).stem.replace(".test", "")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class ProcessManager:
|
|
116
|
+
"""Manages subprocess lifecycle for the Solace AI Connector."""
|
|
117
|
+
|
|
118
|
+
def __init__(self, config: TestSuiteConfiguration, verbose: bool = False):
|
|
119
|
+
self.config = config
|
|
120
|
+
self.process: subprocess.Popen | None = None
|
|
121
|
+
self.namespace: str | None = None
|
|
122
|
+
self.verbose = verbose
|
|
123
|
+
|
|
124
|
+
def start_services(self) -> tuple[subprocess.Popen, str]:
|
|
125
|
+
"""Start the Solace AI Connector and return process and namespace."""
|
|
126
|
+
load_dotenv()
|
|
127
|
+
self.namespace = f"eval-{uuid.uuid4()}"
|
|
128
|
+
os.environ["NAMESPACE"] = self.namespace
|
|
129
|
+
|
|
130
|
+
# Set broker environment variables from the required configuration
|
|
131
|
+
log.info("Setting broker configuration from test suite...")
|
|
132
|
+
for key, value in self.config.broker.dict().items():
|
|
133
|
+
if value is not None:
|
|
134
|
+
env_key = f"SOLACE_BROKER_{key.upper()}"
|
|
135
|
+
os.environ[env_key] = str(value)
|
|
136
|
+
log.info(f" - Set {env_key}")
|
|
137
|
+
|
|
138
|
+
agent_files = self.config.agent_configs
|
|
139
|
+
|
|
140
|
+
command = [sys.executable, "-m", "solace_ai_connector.main", *agent_files]
|
|
141
|
+
|
|
142
|
+
log.info("Starting Solace AI Connector as a subprocess...")
|
|
143
|
+
project_root = Path(EVALUATION_DIR).parent.resolve()
|
|
144
|
+
|
|
145
|
+
self.process = subprocess.Popen(
|
|
146
|
+
command, stdout=sys.stdout, stderr=sys.stderr, cwd=project_root
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
log.info("Waiting for server to become healthy...")
|
|
150
|
+
self._wait_for_server_ready(get_local_base_url())
|
|
151
|
+
|
|
152
|
+
return self.process, self.namespace
|
|
153
|
+
|
|
154
|
+
def _wait_for_server_ready(self, base_url: str):
|
|
155
|
+
"""Poll the health endpoint until the server is ready."""
|
|
156
|
+
start_time = time.time()
|
|
157
|
+
health_url = f"{base_url}/health"
|
|
158
|
+
|
|
159
|
+
while time.time() - start_time < DEFAULT_STARTUP_WAIT_TIME:
|
|
160
|
+
try:
|
|
161
|
+
response = requests.get(health_url)
|
|
162
|
+
if response.status_code == 200:
|
|
163
|
+
log.info("Server is healthy.")
|
|
164
|
+
time.sleep(5)
|
|
165
|
+
return
|
|
166
|
+
except requests.ConnectionError:
|
|
167
|
+
# Server is not yet available, wait and retry
|
|
168
|
+
time.sleep(1)
|
|
169
|
+
except Exception as e:
|
|
170
|
+
log.error(f"An unexpected error occurred during health check: {e}")
|
|
171
|
+
time.sleep(1)
|
|
172
|
+
|
|
173
|
+
raise RuntimeError(
|
|
174
|
+
f"Server did not become healthy within {DEFAULT_STARTUP_WAIT_TIME} seconds."
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
def stop_services(self, subscriber: Subscriber | None = None):
|
|
178
|
+
"""Clean up running processes."""
|
|
179
|
+
if subscriber:
|
|
180
|
+
log.info("Terminating subscriber")
|
|
181
|
+
subscriber.stop()
|
|
182
|
+
subscriber.join()
|
|
183
|
+
log.info("Subscriber terminated.")
|
|
184
|
+
|
|
185
|
+
if self.process:
|
|
186
|
+
log.info("Terminating subprocess")
|
|
187
|
+
self.process.terminate()
|
|
188
|
+
try:
|
|
189
|
+
self.process.wait(timeout=5)
|
|
190
|
+
log.info("Subprocess terminated.")
|
|
191
|
+
except subprocess.TimeoutExpired:
|
|
192
|
+
log.info("Subprocess did not terminate gracefully, killing.")
|
|
193
|
+
self.process.kill()
|
|
194
|
+
|
|
195
|
+
log.info("Process cleanup completed.")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class TaskService:
|
|
199
|
+
"""Handles task submission and tracking."""
|
|
200
|
+
|
|
201
|
+
def __init__(self, config: TestSuiteConfiguration, verbose: bool = False):
|
|
202
|
+
self.verbose = verbose
|
|
203
|
+
self.config = config
|
|
204
|
+
if config.remote:
|
|
205
|
+
self.base_url = config.remote.environment.get("EVAL_REMOTE_URL")
|
|
206
|
+
else:
|
|
207
|
+
self.base_url = get_local_base_url()
|
|
208
|
+
|
|
209
|
+
def submit_task(
|
|
210
|
+
self, agent_name: str, message: str, artifact_paths: list[str] | None = None
|
|
211
|
+
) -> str | None:
|
|
212
|
+
"""Submit a test case to the agent and return the task ID."""
|
|
213
|
+
log.info("Sending test request")
|
|
214
|
+
url = f"{self.base_url}/api/v2/tasks"
|
|
215
|
+
data = {
|
|
216
|
+
"agent_name": agent_name,
|
|
217
|
+
"prompt": message,
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
headers = {}
|
|
221
|
+
if self.config.remote:
|
|
222
|
+
auth_token = self.config.remote.environment.get("EVAL_AUTH_TOKEN")
|
|
223
|
+
if auth_token:
|
|
224
|
+
headers["Authorization"] = f"Bearer {auth_token}"
|
|
225
|
+
|
|
226
|
+
files_to_upload = []
|
|
227
|
+
if artifact_paths:
|
|
228
|
+
files_to_upload = self._prepare_file_uploads(artifact_paths)
|
|
229
|
+
|
|
230
|
+
try:
|
|
231
|
+
with requests.Session() as session:
|
|
232
|
+
response = session.post(url, data=data, files=files_to_upload, headers=headers)
|
|
233
|
+
|
|
234
|
+
response.raise_for_status()
|
|
235
|
+
task_id = response.json()["taskId"]
|
|
236
|
+
log.info(f"Task submitted with ID: {task_id}")
|
|
237
|
+
return task_id
|
|
238
|
+
|
|
239
|
+
except requests.RequestException as e:
|
|
240
|
+
log.error(f"Failed to submit task: {e}")
|
|
241
|
+
return None
|
|
242
|
+
finally:
|
|
243
|
+
self._close_file_uploads(files_to_upload)
|
|
244
|
+
|
|
245
|
+
def _prepare_file_uploads(self, artifact_paths: list[str]) -> list[tuple]:
|
|
246
|
+
"""Prepare file uploads for the request."""
|
|
247
|
+
files_to_upload = []
|
|
248
|
+
for path_str in artifact_paths:
|
|
249
|
+
path = Path(path_str)
|
|
250
|
+
# Check file size before reading
|
|
251
|
+
try:
|
|
252
|
+
file_size_mb = path.stat().st_size / (1024 * 1024)
|
|
253
|
+
if file_size_mb > MAX_ARTIFACT_SIZE_MB:
|
|
254
|
+
log.warning(
|
|
255
|
+
f"Artifact '{path.name}' is {file_size_mb:.2f} MB, "
|
|
256
|
+
f"which is larger than the recommended maximum of {MAX_ARTIFACT_SIZE_MB} MB. "
|
|
257
|
+
"This may cause memory issues."
|
|
258
|
+
)
|
|
259
|
+
except OSError as e:
|
|
260
|
+
log.error(f"Could not get size of artifact {path}: {e}")
|
|
261
|
+
continue
|
|
262
|
+
|
|
263
|
+
mimetype, _ = mimetypes.guess_type(path)
|
|
264
|
+
if mimetype is None:
|
|
265
|
+
mimetype = "text/plain"
|
|
266
|
+
# Read file content with context manager
|
|
267
|
+
with path.open("rb") as f:
|
|
268
|
+
file_content = f.read()
|
|
269
|
+
files_to_upload.append(("files", (path.name, file_content, mimetype)))
|
|
270
|
+
return files_to_upload
|
|
271
|
+
|
|
272
|
+
def _close_file_uploads(self, files_to_upload: list[tuple]):
|
|
273
|
+
"""Close file handles after upload (no longer needed)."""
|
|
274
|
+
# No longer needed
|
|
275
|
+
pass
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class FileService:
|
|
279
|
+
"""Handles file operations and path management."""
|
|
280
|
+
|
|
281
|
+
@staticmethod
|
|
282
|
+
def ensure_directory(path: Path):
|
|
283
|
+
"""Ensure directory exists, create if necessary."""
|
|
284
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
285
|
+
|
|
286
|
+
@staticmethod
|
|
287
|
+
def remove_directory(path: Path):
|
|
288
|
+
"""Remove directory and all contents."""
|
|
289
|
+
if path.exists():
|
|
290
|
+
shutil.rmtree(path)
|
|
291
|
+
|
|
292
|
+
@staticmethod
|
|
293
|
+
def save_json(data: any, filepath: Path):
|
|
294
|
+
"""Save data as JSON to file."""
|
|
295
|
+
with filepath.open("w") as f:
|
|
296
|
+
json.dump(data, f, indent=4)
|
|
297
|
+
|
|
298
|
+
@staticmethod
|
|
299
|
+
def load_json(filepath: Path) -> any:
|
|
300
|
+
"""Load JSON data from file."""
|
|
301
|
+
with filepath.open() as f:
|
|
302
|
+
return json.load(f)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class TestRunBuilder:
|
|
306
|
+
"""Builds test run configurations from test cases."""
|
|
307
|
+
|
|
308
|
+
def __init__(self, config: TestSuiteConfiguration):
|
|
309
|
+
self.config = config
|
|
310
|
+
|
|
311
|
+
def build_test_runs(self) -> list[TestRun]:
|
|
312
|
+
"""Build all test runs from configuration."""
|
|
313
|
+
test_runs = []
|
|
314
|
+
|
|
315
|
+
for test_case_path in self.config.test_case_files:
|
|
316
|
+
test_case = FileService.load_json(Path(test_case_path))
|
|
317
|
+
|
|
318
|
+
artifact_paths = self._get_artifact_paths(test_case, test_case_path)
|
|
319
|
+
|
|
320
|
+
for run_num in range(1, self.config.run_count + 1):
|
|
321
|
+
test_run = TestRun(
|
|
322
|
+
agent=test_case["target_agent"],
|
|
323
|
+
query=test_case["query"],
|
|
324
|
+
artifacts=artifact_paths,
|
|
325
|
+
wait_time=test_case.get("wait_time", DEFAULT_TEST_TIMEOUT),
|
|
326
|
+
test_case_file=test_case_path,
|
|
327
|
+
run_num=run_num,
|
|
328
|
+
)
|
|
329
|
+
test_runs.append(test_run)
|
|
330
|
+
|
|
331
|
+
return test_runs
|
|
332
|
+
|
|
333
|
+
def _get_artifact_paths(self, test_case: dict, test_case_path: str) -> list[str]:
|
|
334
|
+
"""Extract artifact paths from test case."""
|
|
335
|
+
artifact_paths = []
|
|
336
|
+
if "artifacts" in test_case:
|
|
337
|
+
test_case_dir = Path(test_case_path).parent
|
|
338
|
+
for artifact in test_case["artifacts"]:
|
|
339
|
+
if artifact.get("type") == "file":
|
|
340
|
+
artifact_paths.append(str(test_case_dir / artifact["path"]))
|
|
341
|
+
return artifact_paths
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
class TestExecutor:
|
|
345
|
+
"""Executes individual test runs."""
|
|
346
|
+
|
|
347
|
+
def __init__(self, task_service: TaskService, file_service: FileService, verbose: bool = False):
|
|
348
|
+
self.task_service = task_service
|
|
349
|
+
self.file_service = file_service
|
|
350
|
+
self.verbose = verbose
|
|
351
|
+
|
|
352
|
+
def execute_test(
|
|
353
|
+
self,
|
|
354
|
+
test_run: TestRun,
|
|
355
|
+
model_results_path: Path,
|
|
356
|
+
task_mappings: dict[str, str],
|
|
357
|
+
subscriber: Subscriber,
|
|
358
|
+
task_mappings_lock: threading.Lock,
|
|
359
|
+
) -> bool:
|
|
360
|
+
"""Execute a single test case and wait for completion."""
|
|
361
|
+
log.info(
|
|
362
|
+
f"Starting test: {test_run.test_case_file} (run {test_run.run_num})"
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
# Submit the task
|
|
366
|
+
task_id = self.task_service.submit_task(
|
|
367
|
+
test_run.agent, test_run.query, test_run.artifacts
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
if not task_id:
|
|
371
|
+
log.error(
|
|
372
|
+
f"Failed to start test case: {test_run.test_case_file} (run {test_run.run_num})"
|
|
373
|
+
)
|
|
374
|
+
return False
|
|
375
|
+
|
|
376
|
+
# Set up result directory
|
|
377
|
+
test_case_name = Path(test_run.test_case_file).stem.replace(".test", "")
|
|
378
|
+
run_dir = model_results_path / test_case_name / f"run_{test_run.run_num}"
|
|
379
|
+
self.file_service.ensure_directory(run_dir)
|
|
380
|
+
|
|
381
|
+
# Save test case path for summary builder
|
|
382
|
+
test_info = {"path": test_run.test_case_file}
|
|
383
|
+
self.file_service.save_json(test_info, run_dir / "test_case_info.json")
|
|
384
|
+
|
|
385
|
+
# Track the task
|
|
386
|
+
with task_mappings_lock:
|
|
387
|
+
task_mappings[task_id] = str(run_dir)
|
|
388
|
+
subscriber.active_tasks.add(task_id)
|
|
389
|
+
|
|
390
|
+
# Wait for completion
|
|
391
|
+
return self._wait_for_completion(task_id, test_run.wait_time, subscriber)
|
|
392
|
+
|
|
393
|
+
def _wait_for_completion(
|
|
394
|
+
self, task_id: str, wait_time: int, subscriber: Subscriber
|
|
395
|
+
) -> bool:
|
|
396
|
+
"""Wait for task completion with timeout."""
|
|
397
|
+
log.info(
|
|
398
|
+
f"Waiting for task {task_id} to complete (timeout: {wait_time} seconds)..."
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
start_time = time.time()
|
|
402
|
+
while task_id in subscriber.active_tasks:
|
|
403
|
+
if time.time() - start_time > wait_time:
|
|
404
|
+
log.warning(f"Task {task_id} timed out after {wait_time} seconds")
|
|
405
|
+
subscriber.active_tasks.discard(task_id)
|
|
406
|
+
return False
|
|
407
|
+
time.sleep(1)
|
|
408
|
+
|
|
409
|
+
log.info(f"Task {task_id} completed successfully")
|
|
410
|
+
return True
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
class ModelEvaluator:
|
|
414
|
+
"""Handles the evaluation of a single model."""
|
|
415
|
+
|
|
416
|
+
def __init__(self, config: TestSuiteConfiguration, verbose: bool = False):
|
|
417
|
+
self.config = config
|
|
418
|
+
self.process_manager = ProcessManager(config, verbose=verbose)
|
|
419
|
+
self.task_service = TaskService(config, verbose=verbose)
|
|
420
|
+
self.file_service = FileService()
|
|
421
|
+
self.test_builder = TestRunBuilder(config)
|
|
422
|
+
self.test_executor = TestExecutor(self.task_service, self.file_service, verbose=verbose)
|
|
423
|
+
self.verbose = verbose
|
|
424
|
+
self._task_mappings_lock = threading.Lock()
|
|
425
|
+
|
|
426
|
+
def evaluate_model(
|
|
427
|
+
self, model_config: dict[str, any], base_results_path: Path
|
|
428
|
+
) -> float:
|
|
429
|
+
"""Evaluate a single model and return execution time."""
|
|
430
|
+
model_name = model_config.name
|
|
431
|
+
log.info(f"Starting evaluation for model: {model_name}")
|
|
432
|
+
start_time = time.time()
|
|
433
|
+
|
|
434
|
+
# Set environment variables for the model
|
|
435
|
+
self._set_model_environment(model_config)
|
|
436
|
+
|
|
437
|
+
# Set up paths
|
|
438
|
+
model_results_path = base_results_path / model_name
|
|
439
|
+
self.file_service.ensure_directory(model_results_path)
|
|
440
|
+
|
|
441
|
+
# Start services
|
|
442
|
+
app_process, namespace = self.process_manager.start_services()
|
|
443
|
+
|
|
444
|
+
# Set up subscriber
|
|
445
|
+
subscriber = self._setup_subscriber(namespace, model_results_path)
|
|
446
|
+
|
|
447
|
+
try:
|
|
448
|
+
# Execute tests
|
|
449
|
+
successful_tests = self._execute_all_tests(model_results_path, subscriber)
|
|
450
|
+
log.info(f"Completed {successful_tests} tests successfully")
|
|
451
|
+
|
|
452
|
+
except Exception as e:
|
|
453
|
+
log.error(f"Error during test case execution for model {model_name}: {e}")
|
|
454
|
+
finally:
|
|
455
|
+
# Cleanup
|
|
456
|
+
task_mappings = getattr(self, "_task_mappings", {})
|
|
457
|
+
self._cleanup_model_evaluation(
|
|
458
|
+
app_process, subscriber, model_results_path, task_mappings
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
end_time = time.time()
|
|
462
|
+
execution_time = end_time - start_time
|
|
463
|
+
log.info(
|
|
464
|
+
f"Evaluation for model: {model_name} complete in {execution_time:.2f} seconds"
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
return execution_time
|
|
468
|
+
|
|
469
|
+
def _set_model_environment(self, model_config: dict[str, any]):
|
|
470
|
+
"""Set environment variables for the model."""
|
|
471
|
+
for key, value in model_config.environment.variables.items():
|
|
472
|
+
if value is not None:
|
|
473
|
+
os.environ[key] = value
|
|
474
|
+
|
|
475
|
+
def _setup_subscriber(self, namespace: str, model_results_path: Path) -> Subscriber:
|
|
476
|
+
"""Set up and start the subscriber."""
|
|
477
|
+
subscription_ready_event = threading.Event()
|
|
478
|
+
subscriber = Subscriber(
|
|
479
|
+
self.config.broker,
|
|
480
|
+
namespace,
|
|
481
|
+
set(),
|
|
482
|
+
None,
|
|
483
|
+
subscription_ready_event,
|
|
484
|
+
model_results_path,
|
|
485
|
+
)
|
|
486
|
+
subscriber.start()
|
|
487
|
+
|
|
488
|
+
log.info("Waiting for subscriber to be ready...")
|
|
489
|
+
subscription_ready_event.wait()
|
|
490
|
+
log.info("Subscriber is ready.")
|
|
491
|
+
|
|
492
|
+
return subscriber
|
|
493
|
+
|
|
494
|
+
def _execute_all_tests(
|
|
495
|
+
self, model_results_path: Path, subscriber: Subscriber
|
|
496
|
+
) -> int:
|
|
497
|
+
"""Execute all test cases in parallel and return count of successful tests."""
|
|
498
|
+
test_runs = self.test_builder.build_test_runs()
|
|
499
|
+
|
|
500
|
+
self._task_mappings = {}
|
|
501
|
+
total_tests = len(test_runs)
|
|
502
|
+
successful_tests = 0
|
|
503
|
+
|
|
504
|
+
log.info(
|
|
505
|
+
f"Starting parallel execution of {total_tests} tests with {self.config.workers} workers."
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
with ThreadPoolExecutor(max_workers=self.config.workers) as executor:
|
|
509
|
+
# Create a dictionary to map futures to their test_run
|
|
510
|
+
future_to_run = {
|
|
511
|
+
executor.submit(
|
|
512
|
+
self.test_executor.execute_test,
|
|
513
|
+
test_run,
|
|
514
|
+
model_results_path,
|
|
515
|
+
self._task_mappings,
|
|
516
|
+
subscriber,
|
|
517
|
+
self._task_mappings_lock, # Pass the lock to the worker
|
|
518
|
+
): test_run
|
|
519
|
+
for test_run in test_runs
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
# Process results as they complete
|
|
523
|
+
for i, future in enumerate(as_completed(future_to_run), 1):
|
|
524
|
+
test_run = future_to_run[future]
|
|
525
|
+
log.info(
|
|
526
|
+
f"Processing result for test {i}/{total_tests}: {test_run.test_case_id}"
|
|
527
|
+
)
|
|
528
|
+
try:
|
|
529
|
+
success = future.result()
|
|
530
|
+
if success:
|
|
531
|
+
successful_tests += 1
|
|
532
|
+
else:
|
|
533
|
+
log.warning(
|
|
534
|
+
f"Test {test_run.test_case_id} (run {test_run.run_num}) failed or timed out."
|
|
535
|
+
)
|
|
536
|
+
except Exception as e:
|
|
537
|
+
log.error(
|
|
538
|
+
f"Test {test_run.test_case_id} (run {test_run.run_num}) generated an exception: {e}",
|
|
539
|
+
exc_info=True,
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
return successful_tests
|
|
543
|
+
|
|
544
|
+
def _cleanup_model_evaluation(
|
|
545
|
+
self,
|
|
546
|
+
app_process: subprocess.Popen,
|
|
547
|
+
subscriber: Subscriber,
|
|
548
|
+
model_results_path: Path,
|
|
549
|
+
task_mappings: dict[str, str],
|
|
550
|
+
):
|
|
551
|
+
"""Clean up after model evaluation."""
|
|
552
|
+
self.process_manager.stop_services(subscriber)
|
|
553
|
+
|
|
554
|
+
# Save task mappings
|
|
555
|
+
mappings_file = model_results_path / "task_mappings.json"
|
|
556
|
+
self.file_service.save_json(task_mappings, mappings_file)
|
|
557
|
+
log.info(f"Task mappings saved to {mappings_file}")
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
class ResultsProcessor:
|
|
561
|
+
"""Handles post-processing of evaluation results."""
|
|
562
|
+
|
|
563
|
+
def __init__(self, file_service: FileService, verbose: bool = False):
|
|
564
|
+
self.file_service = file_service
|
|
565
|
+
self.summary_builder: SummaryBuilder | None = None
|
|
566
|
+
self.verbose = verbose
|
|
567
|
+
|
|
568
|
+
def summarize_results(self, base_results_path: Path, config: TestSuiteConfiguration):
|
|
569
|
+
"""Generate summaries for all test results."""
|
|
570
|
+
log.info("Summarizing results")
|
|
571
|
+
|
|
572
|
+
self.summary_builder = SummaryBuilder(config)
|
|
573
|
+
|
|
574
|
+
for model_path in base_results_path.iterdir():
|
|
575
|
+
if not model_path.is_dir():
|
|
576
|
+
continue
|
|
577
|
+
self._process_model_results(model_path)
|
|
578
|
+
|
|
579
|
+
def _process_model_results(self, model_path: Path):
|
|
580
|
+
"""Process results for a single model."""
|
|
581
|
+
for test_case_path in model_path.iterdir():
|
|
582
|
+
if not test_case_path.is_dir():
|
|
583
|
+
continue
|
|
584
|
+
self._process_test_case_results(test_case_path)
|
|
585
|
+
|
|
586
|
+
def _process_test_case_results(self, test_case_path: Path):
|
|
587
|
+
"""Process results for a single test case."""
|
|
588
|
+
for run_path in test_case_path.iterdir():
|
|
589
|
+
if not run_path.is_dir():
|
|
590
|
+
continue
|
|
591
|
+
|
|
592
|
+
messages_file = run_path / "messages.json"
|
|
593
|
+
if messages_file.exists():
|
|
594
|
+
summary_data = self.summary_builder.summarize_run(messages_file)
|
|
595
|
+
summary_file = run_path / "summary.json"
|
|
596
|
+
self.file_service.save_json(summary_data, summary_file)
|
|
597
|
+
log.info(f"Summary created for {run_path}")
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
class EvaluationRunner:
|
|
601
|
+
"""Main orchestrator that coordinates the entire evaluation process."""
|
|
602
|
+
|
|
603
|
+
def __init__(self, verbose: bool = False):
|
|
604
|
+
self.config: TestSuiteConfiguration | None = None
|
|
605
|
+
self.file_service = FileService()
|
|
606
|
+
self.results_processor = ResultsProcessor(self.file_service, verbose=verbose)
|
|
607
|
+
self.report_generator: ReportGenerator | None = None
|
|
608
|
+
self.verbose = verbose
|
|
609
|
+
|
|
610
|
+
def run_evaluation(self, config_path: str):
|
|
611
|
+
"""Main entry point for the evaluation process."""
|
|
612
|
+
start_time = time.time()
|
|
613
|
+
|
|
614
|
+
try:
|
|
615
|
+
# Load and validate configuration
|
|
616
|
+
self._load_configuration(config_path)
|
|
617
|
+
|
|
618
|
+
# Set up results directory in the current working directory
|
|
619
|
+
base_results_path = Path.cwd() / "results" / self.config.results_directory
|
|
620
|
+
self._setup_results_directory(base_results_path)
|
|
621
|
+
|
|
622
|
+
# Run model evaluations
|
|
623
|
+
if self.config.remote:
|
|
624
|
+
model_execution_times = self._run_remote_evaluation(base_results_path)
|
|
625
|
+
else:
|
|
626
|
+
model_execution_times = self._run_local_evaluation(base_results_path)
|
|
627
|
+
|
|
628
|
+
# Post-process results
|
|
629
|
+
self._post_process_results(
|
|
630
|
+
base_results_path, model_execution_times, config_path
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
# Save overall statistics
|
|
634
|
+
self._save_execution_stats(base_results_path, start_time)
|
|
635
|
+
|
|
636
|
+
# Generate reports
|
|
637
|
+
self._generate_reports(config_path, base_results_path)
|
|
638
|
+
|
|
639
|
+
# Display summary
|
|
640
|
+
self._display_summary(base_results_path)
|
|
641
|
+
|
|
642
|
+
except Exception as e:
|
|
643
|
+
log.error(f"Evaluation failed: {e}")
|
|
644
|
+
raise
|
|
645
|
+
|
|
646
|
+
def _load_configuration(self, config_path: str):
|
|
647
|
+
"""Load and validate the evaluation configuration."""
|
|
648
|
+
config_loader = EvaluationConfigLoader(config_path)
|
|
649
|
+
self.config = config_loader.load_configuration()
|
|
650
|
+
self.report_generator = ReportGenerator(config_path)
|
|
651
|
+
log.info("Configuration loaded and validated successfully.")
|
|
652
|
+
|
|
653
|
+
def _setup_results_directory(self, base_results_path: Path):
|
|
654
|
+
"""Set up the results directory."""
|
|
655
|
+
# Clean up existing results
|
|
656
|
+
self.file_service.remove_directory(base_results_path)
|
|
657
|
+
self.file_service.ensure_directory(base_results_path)
|
|
658
|
+
|
|
659
|
+
log.info(f"Results directory set up at: {base_results_path}")
|
|
660
|
+
|
|
661
|
+
def _run_local_evaluation(self, base_results_path: Path) -> dict[str, float]:
|
|
662
|
+
"""Run the full local evaluation with service management."""
|
|
663
|
+
_ensure_eval_backend_config_exists()
|
|
664
|
+
_ensure_sam_rest_gateway_installed()
|
|
665
|
+
log.info("Starting local evaluation")
|
|
666
|
+
model_execution_times = {}
|
|
667
|
+
|
|
668
|
+
# This loop iterates through the models defined in the config
|
|
669
|
+
for model_config in self.config.model_configurations:
|
|
670
|
+
# ModelEvaluator manages the lifecycle of local services for each model
|
|
671
|
+
model_evaluator = ModelEvaluator(self.config, verbose=self.verbose)
|
|
672
|
+
execution_time = model_evaluator.evaluate_model(
|
|
673
|
+
model_config, base_results_path
|
|
674
|
+
)
|
|
675
|
+
model_execution_times[model_config.name] = execution_time
|
|
676
|
+
|
|
677
|
+
return model_execution_times
|
|
678
|
+
|
|
679
|
+
def _run_remote_evaluation(self, base_results_path: Path) -> dict[str, float]:
|
|
680
|
+
"""Run evaluation against a remote endpoint in parallel."""
|
|
681
|
+
remote_url = self.config.remote.environment.get("EVAL_REMOTE_URL")
|
|
682
|
+
log.info(f"Starting remote evaluation against: {remote_url}")
|
|
683
|
+
start_time = time.time()
|
|
684
|
+
|
|
685
|
+
# Check if the remote server is healthy before proceeding
|
|
686
|
+
process_manager = ProcessManager(self.config, self.verbose)
|
|
687
|
+
process_manager._wait_for_server_ready(remote_url)
|
|
688
|
+
|
|
689
|
+
# Instantiate services with the remote configuration
|
|
690
|
+
task_service = TaskService(self.config, self.verbose)
|
|
691
|
+
test_builder = TestRunBuilder(self.config)
|
|
692
|
+
test_executor = TestExecutor(task_service, self.file_service, self.verbose)
|
|
693
|
+
|
|
694
|
+
# In remote mode, there's no model loop. We create a single "remote" results directory.
|
|
695
|
+
remote_results_path = base_results_path / "remote"
|
|
696
|
+
self.file_service.ensure_directory(remote_results_path)
|
|
697
|
+
|
|
698
|
+
# The subscriber needs to be configured for remote use.
|
|
699
|
+
subscriber = self._setup_remote_subscriber(str(remote_results_path))
|
|
700
|
+
|
|
701
|
+
task_mappings = {}
|
|
702
|
+
try:
|
|
703
|
+
test_runs = test_builder.build_test_runs()
|
|
704
|
+
successful_tests = 0
|
|
705
|
+
task_mappings_lock = threading.Lock()
|
|
706
|
+
|
|
707
|
+
log.info(
|
|
708
|
+
f"Starting parallel execution of {len(test_runs)} remote tests with {self.config.workers} workers."
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
with ThreadPoolExecutor(max_workers=self.config.workers) as executor:
|
|
712
|
+
future_to_run = {
|
|
713
|
+
executor.submit(
|
|
714
|
+
test_executor.execute_test,
|
|
715
|
+
test_run,
|
|
716
|
+
remote_results_path,
|
|
717
|
+
task_mappings,
|
|
718
|
+
subscriber,
|
|
719
|
+
task_mappings_lock,
|
|
720
|
+
): test_run
|
|
721
|
+
for test_run in test_runs
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
for i, future in enumerate(as_completed(future_to_run), 1):
|
|
725
|
+
test_run = future_to_run[future]
|
|
726
|
+
log.info(
|
|
727
|
+
f"Processing result for remote test {i}/{len(test_runs)}: {test_run.test_case_id}"
|
|
728
|
+
)
|
|
729
|
+
try:
|
|
730
|
+
success = future.result()
|
|
731
|
+
if success:
|
|
732
|
+
successful_tests += 1
|
|
733
|
+
except Exception as e:
|
|
734
|
+
log.error(
|
|
735
|
+
f"Remote test {test_run.test_case_id} generated an exception: {e}",
|
|
736
|
+
exc_info=True,
|
|
737
|
+
)
|
|
738
|
+
|
|
739
|
+
log.info(f"Completed {successful_tests} remote tests successfully")
|
|
740
|
+
|
|
741
|
+
finally:
|
|
742
|
+
if subscriber:
|
|
743
|
+
subscriber.stop()
|
|
744
|
+
subscriber.join()
|
|
745
|
+
|
|
746
|
+
# Save task mappings for remote run
|
|
747
|
+
mappings_file = remote_results_path / "task_mappings.json"
|
|
748
|
+
self.file_service.save_json(task_mappings, mappings_file)
|
|
749
|
+
|
|
750
|
+
execution_time = time.time() - start_time
|
|
751
|
+
return {"remote": execution_time}
|
|
752
|
+
|
|
753
|
+
def _setup_remote_subscriber(self, results_path: str) -> Subscriber:
|
|
754
|
+
"""Set up a subscriber for remote evaluation."""
|
|
755
|
+
subscription_ready_event = threading.Event()
|
|
756
|
+
namespace = self.config.remote.environment.get("EVAL_NAMESPACE")
|
|
757
|
+
subscriber = Subscriber(
|
|
758
|
+
self.config.broker,
|
|
759
|
+
namespace,
|
|
760
|
+
set(),
|
|
761
|
+
None,
|
|
762
|
+
subscription_ready_event,
|
|
763
|
+
results_path,
|
|
764
|
+
)
|
|
765
|
+
subscriber.start()
|
|
766
|
+
subscription_ready_event.wait()
|
|
767
|
+
log.info("Remote subscriber is ready.")
|
|
768
|
+
return subscriber
|
|
769
|
+
|
|
770
|
+
def _post_process_results(
|
|
771
|
+
self,
|
|
772
|
+
base_results_path: Path,
|
|
773
|
+
model_execution_times: dict[str, float],
|
|
774
|
+
config_path: str,
|
|
775
|
+
):
|
|
776
|
+
"""Post-process evaluation results."""
|
|
777
|
+
# Categorize messages using the refactored categorizer
|
|
778
|
+
log.info("Categorizing messages")
|
|
779
|
+
message_organizer = MessageOrganizer()
|
|
780
|
+
message_organizer.categorize_all_messages(base_results_path)
|
|
781
|
+
log.info("Message categorization finished")
|
|
782
|
+
|
|
783
|
+
# Generate summaries
|
|
784
|
+
self.results_processor.summarize_results(base_results_path, self.config)
|
|
785
|
+
|
|
786
|
+
# Run evaluation
|
|
787
|
+
log.info("Starting evaluation of results")
|
|
788
|
+
evaluation_orchestrator = EvaluationOrchestrator(config_path)
|
|
789
|
+
evaluation_orchestrator.run_evaluation(
|
|
790
|
+
base_results_path, model_execution_times
|
|
791
|
+
)
|
|
792
|
+
log.info("Evaluation of results finished")
|
|
793
|
+
|
|
794
|
+
def _generate_reports(self, config_path: str, base_results_path: Path):
|
|
795
|
+
"""Generate evaluation reports."""
|
|
796
|
+
if self.report_generator:
|
|
797
|
+
self.report_generator.generate_report(base_results_path)
|
|
798
|
+
|
|
799
|
+
def _display_summary(self, base_results_path: Path):
|
|
800
|
+
"""Display a summary of the evaluation results in the terminal."""
|
|
801
|
+
|
|
802
|
+
# Pre-process data to find column widths
|
|
803
|
+
summary_data = []
|
|
804
|
+
max_model_len = 0
|
|
805
|
+
max_test_case_len = 0
|
|
806
|
+
|
|
807
|
+
for model_dir in sorted(base_results_path.iterdir()):
|
|
808
|
+
if not model_dir.is_dir():
|
|
809
|
+
continue
|
|
810
|
+
|
|
811
|
+
results_file = model_dir / "results.json"
|
|
812
|
+
if not results_file.exists():
|
|
813
|
+
continue
|
|
814
|
+
|
|
815
|
+
try:
|
|
816
|
+
results_data = self.file_service.load_json(results_file)
|
|
817
|
+
model_name = results_data.get("model_name", model_dir.name)
|
|
818
|
+
max_model_len = max(max_model_len, len(model_name))
|
|
819
|
+
|
|
820
|
+
for test_case in results_data.get("test_cases", []):
|
|
821
|
+
test_case_id = test_case.get("test_case_id")
|
|
822
|
+
if not test_case_id:
|
|
823
|
+
continue
|
|
824
|
+
|
|
825
|
+
max_test_case_len = max(max_test_case_len, len(test_case_id))
|
|
826
|
+
|
|
827
|
+
scores = {}
|
|
828
|
+
tool_match = test_case.get("tool_match_scores", {}).get("average")
|
|
829
|
+
if tool_match is not None:
|
|
830
|
+
scores["Tool Match"] = f"{tool_match:.2f}"
|
|
831
|
+
|
|
832
|
+
response_match = test_case.get("response_match_scores", {}).get("average")
|
|
833
|
+
if response_match is not None:
|
|
834
|
+
scores["Response Match"] = f"{response_match:.2f}"
|
|
835
|
+
|
|
836
|
+
llm_eval = test_case.get("llm_eval_scores", {}).get("average")
|
|
837
|
+
if llm_eval is not None:
|
|
838
|
+
scores["LLM Eval"] = f"{llm_eval:.2f}"
|
|
839
|
+
|
|
840
|
+
if scores:
|
|
841
|
+
summary_data.append((model_name, test_case_id, scores))
|
|
842
|
+
|
|
843
|
+
except Exception as e:
|
|
844
|
+
log.error(f"Error processing results for {model_dir.name}: {e}")
|
|
845
|
+
|
|
846
|
+
if not summary_data:
|
|
847
|
+
log.warning("No summary data to display.")
|
|
848
|
+
return
|
|
849
|
+
|
|
850
|
+
# Define header line
|
|
851
|
+
header_line = (
|
|
852
|
+
f"{'Model':<{max_model_len}} | {'Test Case':<{max_test_case_len}} | "
|
|
853
|
+
f"{'Tool Match':<12} | {'Response Match':<16} | {'LLM Eval':<10}"
|
|
854
|
+
)
|
|
855
|
+
click.echo(click.style(header_line, fg="white", bold=True))
|
|
856
|
+
click.echo(click.style("-" * len(header_line), fg="white", bold=True))
|
|
857
|
+
|
|
858
|
+
for model_name, test_case_id, scores in summary_data:
|
|
859
|
+
tool_score = scores.get("Tool Match", "N/A")
|
|
860
|
+
response_score = scores.get("Response Match", "N/A")
|
|
861
|
+
llm_score = scores.get("LLM Eval", "N/A")
|
|
862
|
+
|
|
863
|
+
click.echo(
|
|
864
|
+
click.style(
|
|
865
|
+
f"{model_name:<{max_model_len}} | {test_case_id:<{max_test_case_len}} | "
|
|
866
|
+
f"{tool_score:<12} | {response_score:<16} | {llm_score:<10}",
|
|
867
|
+
fg="white",
|
|
868
|
+
)
|
|
869
|
+
)
|
|
870
|
+
|
|
871
|
+
def _get_model_stats(self, model_path: Path) -> dict[str, any]:
|
|
872
|
+
"""Process results for a single model and return stats."""
|
|
873
|
+
model_stats = {}
|
|
874
|
+
results_file = model_path / "results.json"
|
|
875
|
+
if not results_file.exists():
|
|
876
|
+
return model_stats
|
|
877
|
+
|
|
878
|
+
results_data = self.file_service.load_json(results_file)
|
|
879
|
+
model_name = results_data.get("model_name", model_path.name)
|
|
880
|
+
model_stats[model_name] = {}
|
|
881
|
+
|
|
882
|
+
for test_case in results_data.get("test_cases", []):
|
|
883
|
+
test_case_id = test_case.get("test_case_id")
|
|
884
|
+
if not test_case_id:
|
|
885
|
+
continue
|
|
886
|
+
|
|
887
|
+
scores = {}
|
|
888
|
+
tool_match = test_case.get("tool_match_scores", {}).get("average")
|
|
889
|
+
if tool_match is not None:
|
|
890
|
+
scores["avg_tool_match"] = tool_match
|
|
891
|
+
|
|
892
|
+
response_match = test_case.get("response_match_scores", {}).get("average")
|
|
893
|
+
if response_match is not None:
|
|
894
|
+
scores["avg_response_match"] = response_match
|
|
895
|
+
|
|
896
|
+
llm_eval = test_case.get("llm_eval_scores", {}).get("average")
|
|
897
|
+
if llm_eval is not None:
|
|
898
|
+
scores["avg_llm_eval"] = llm_eval
|
|
899
|
+
|
|
900
|
+
if scores:
|
|
901
|
+
model_stats[model_name][test_case_id] = scores
|
|
902
|
+
return model_stats
|
|
903
|
+
|
|
904
|
+
def _save_execution_stats(self, base_results_path: Path, start_time: float):
|
|
905
|
+
"""Save overall execution statistics."""
|
|
906
|
+
end_time = time.time()
|
|
907
|
+
total_execution_time = end_time - start_time
|
|
908
|
+
stats = {"total_execution_time": total_execution_time, "models": {}}
|
|
909
|
+
|
|
910
|
+
try:
|
|
911
|
+
for model_path in base_results_path.iterdir():
|
|
912
|
+
if not model_path.is_dir():
|
|
913
|
+
continue
|
|
914
|
+
model_stats = self._get_model_stats(model_path)
|
|
915
|
+
stats["models"].update(model_stats)
|
|
916
|
+
|
|
917
|
+
except Exception as e:
|
|
918
|
+
log.error(f"Error processing results for stats: {e}")
|
|
919
|
+
|
|
920
|
+
stats_path = base_results_path / "stats.json"
|
|
921
|
+
self.file_service.save_json(stats, stats_path)
|
|
922
|
+
|
|
923
|
+
log.info(f"Overall stats written to {stats_path}")
|
|
924
|
+
log.info(f"Total execution time: {total_execution_time:.2f} seconds")
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
def main(config_path: str, verbose: bool = False):
|
|
928
|
+
"""Main entry point for the evaluation script."""
|
|
929
|
+
if verbose:
|
|
930
|
+
logging.basicConfig(level=logging.INFO)
|
|
931
|
+
log.info("Verbose logging enabled.")
|
|
932
|
+
|
|
933
|
+
orchestrator = EvaluationRunner(verbose=verbose)
|
|
934
|
+
orchestrator.run_evaluation(config_path)
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
if __name__ == "__main__":
|
|
938
|
+
# This allows the script to be run standalone with a config path argument
|
|
939
|
+
import argparse
|
|
940
|
+
|
|
941
|
+
parser = argparse.ArgumentParser(description="Run the SAM evaluation suite.")
|
|
942
|
+
parser.add_argument(
|
|
943
|
+
"test_suite_config_path",
|
|
944
|
+
type=str,
|
|
945
|
+
help="Path to the evaluation test_suite_config.json file.",
|
|
946
|
+
)
|
|
947
|
+
parser.add_argument(
|
|
948
|
+
"-v",
|
|
949
|
+
"--verbose",
|
|
950
|
+
action="store_true",
|
|
951
|
+
help="Enable verbose output.",
|
|
952
|
+
)
|
|
953
|
+
args = parser.parse_args()
|
|
954
|
+
main(args.test_suite_config_path, args.verbose)
|