solace-agent-mesh 1.5.0__py3-none-any.whl → 1.6.0__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/callbacks.py +14 -17
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +3 -1
- solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +2 -1
- solace_agent_mesh/agent/adk/mcp_content_processor.py +2 -1
- solace_agent_mesh/agent/adk/models/lite_llm.py +123 -8
- solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +245 -0
- solace_agent_mesh/agent/adk/runner.py +3 -1
- solace_agent_mesh/agent/adk/services.py +4 -1
- solace_agent_mesh/agent/adk/setup.py +3 -1
- solace_agent_mesh/agent/adk/tool_wrapper.py +2 -2
- solace_agent_mesh/agent/protocol/event_handlers.py +42 -2
- 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/app.py +55 -0
- solace_agent_mesh/agent/proxies/a2a/component.py +1115 -0
- solace_agent_mesh/agent/proxies/a2a/config.py +140 -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 +99 -0
- solace_agent_mesh/agent/proxies/base/component.py +619 -0
- solace_agent_mesh/agent/proxies/base/config.py +85 -0
- solace_agent_mesh/agent/proxies/base/proxy_task_context.py +17 -0
- solace_agent_mesh/agent/sac/app.py +12 -4
- solace_agent_mesh/agent/sac/component.py +164 -9
- solace_agent_mesh/agent/tools/audio_tools.py +127 -9
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +3 -1
- solace_agent_mesh/agent/tools/builtin_data_analysis_tools.py +3 -1
- solace_agent_mesh/agent/tools/dynamic_tool.py +2 -1
- solace_agent_mesh/agent/tools/general_agent_tools.py +2 -1
- solace_agent_mesh/agent/tools/image_tools.py +2 -1
- solace_agent_mesh/agent/tools/peer_agent_tool.py +2 -1
- solace_agent_mesh/agent/tools/registry.py +3 -1
- solace_agent_mesh/agent/tools/test_tools.py +2 -1
- solace_agent_mesh/agent/tools/web_tools.py +12 -6
- solace_agent_mesh/agent/utils/artifact_helpers.py +144 -4
- solace_agent_mesh/agent/utils/config_parser.py +3 -1
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/{b7006a3a.73a79653.js → 032c2d61.f3d37824.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/0bcf40b7.c019ad46.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2131ec11.5c7a1f6e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{2334.622a6395.js → 2334.1cf50a20.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/240a0364.7eac6021.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/341393d4.0fac2613.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{3624.b524e433.js → 3624.0eaa1fd0.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/509e993c.4c7a1a6d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6063ff4c.ef84f702.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/631738c7.a8b1ef8b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6fdfefc7.99de744e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/71da7b71.38583438.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/722f809d.965da774.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/8024126c.56e59919.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{8591.d7c16be6.js → 8591.5d015485.js} +2 -2
- solace_agent_mesh/assets/docs/assets/js/{8731.49e930c2.js → 8731.6c1dbf0c.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/945fb41e.6f4cdffd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/94e8668d.b5ddb7a1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9e9d0a82.570c057b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e6dd091.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ad71b5ed.af3ecfd1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c198a0dc.8f31f867.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ceb2a7a6.5d92d7d0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/db924877.e98d12a1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de5f4c65.e8241890.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.2b916f9e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e6f9706b.e74a984d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e92d0134.cf6d6522.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.42f59cdd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.20feee82.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.0d198646.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +154 -0
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/artifact-management/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/audio-tools/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/data-analysis-tools/index.html +8 -8
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/embeds/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/index.html +11 -11
- solace_agent_mesh/assets/docs/docs/documentation/{concepts → components}/cli/index.html +25 -25
- solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +91 -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/proxies/index.html +262 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +104 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +85 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +25 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +59 -0
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/create-agents/index.html +113 -152
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/create-gateways/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/creating-python-tools/index.html +12 -12
- 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/{tutorials → developing/tutorials}/bedrock-agents/index.html +25 -25
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/custom-agent/index.html +13 -13
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/event-mesh-gateway/index.html +12 -12
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/mcp-integration/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/mongodb-integration/index.html +13 -13
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/rag-integration/index.html +13 -13
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/rest-gateway/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +72 -0
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/sql-database/index.html +14 -14
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +33 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +83 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +222 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +161 -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 +53 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +35 -100
- 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/configurations/index.html +81 -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 +76 -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/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +100 -0
- solace_agent_mesh/assets/docs/docs/documentation/{Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html → migrations/a2a-upgrade/a2a-technical-migration-map/index.html} +10 -11
- solace_agent_mesh/assets/docs/img/solace-logo.png +0 -0
- solace_agent_mesh/assets/docs/lunr-index-1761165361160.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1761165361160.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/assets/docs/sitemap.xml +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +2 -69
- solace_agent_mesh/cli/commands/eval_cmd.py +11 -49
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +0 -5
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +10 -12
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +9 -61
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +9 -49
- solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +1 -2
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-DwrxZE0E.js → authCallback-BTf6dqwp.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-DarGQzyw.js → client-CaY59VuC.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-BGTaW0uv.js +342 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-DHJKSW1S.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-BKIeiHj_.js → vendor-BEmvJSYz.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
- solace_agent_mesh/common/a2a/__init__.py +24 -0
- solace_agent_mesh/common/a2a/artifact.py +41 -1
- solace_agent_mesh/common/a2a/events.py +29 -0
- solace_agent_mesh/common/a2a/message.py +68 -0
- solace_agent_mesh/common/a2a/protocol.py +76 -3
- solace_agent_mesh/common/a2a/translation.py +3 -1
- solace_agent_mesh/common/agent_registry.py +83 -3
- solace_agent_mesh/common/constants.py +3 -1
- solace_agent_mesh/common/middleware/config_resolver.py +3 -1
- solace_agent_mesh/common/middleware/registry.py +3 -1
- solace_agent_mesh/common/sac/sam_component_base.py +2 -1
- solace_agent_mesh/common/sam_events/event_service.py +3 -2
- solace_agent_mesh/common/services/employee_service.py +3 -1
- solace_agent_mesh/common/services/identity_service.py +2 -1
- solace_agent_mesh/common/services/providers/local_file_identity_service.py +2 -1
- solace_agent_mesh/common/utils/artifact_utils.py +3 -1
- solace_agent_mesh/common/utils/asyncio_macos_fix.py +3 -1
- solace_agent_mesh/common/utils/embeds/converter.py +3 -1
- solace_agent_mesh/common/utils/embeds/evaluators.py +2 -1
- solace_agent_mesh/common/utils/embeds/modifiers.py +3 -2
- solace_agent_mesh/common/utils/embeds/resolver.py +2 -1
- solace_agent_mesh/common/utils/initializer.py +3 -1
- solace_agent_mesh/common/utils/message_utils.py +2 -1
- solace_agent_mesh/common/utils/push_notification_auth.py +3 -2
- solace_agent_mesh/common/utils/pydantic_utils.py +12 -0
- solace_agent_mesh/config_portal/backend/common.py +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +98 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-44d62be6.js → manifest-61038fc6.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
- solace_agent_mesh/core_a2a/service.py +2 -2
- solace_agent_mesh/evaluation/evaluator.py +128 -104
- solace_agent_mesh/evaluation/message_organizer.py +116 -110
- solace_agent_mesh/evaluation/report_data_processor.py +84 -86
- solace_agent_mesh/evaluation/report_generator.py +73 -79
- solace_agent_mesh/evaluation/run.py +421 -235
- 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 +111 -232
- solace_agent_mesh/evaluation/summary_builder.py +227 -117
- solace_agent_mesh/gateway/base/app.py +3 -2
- solace_agent_mesh/gateway/base/component.py +11 -2
- solace_agent_mesh/gateway/base/task_context.py +2 -1
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251015_add_session_performance_indexes.py +70 -0
- solace_agent_mesh/gateway/http_sse/app.py +2 -1
- solace_agent_mesh/gateway/http_sse/component.py +102 -3
- solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +3 -2
- solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +3 -1
- solace_agent_mesh/gateway/http_sse/dependencies.py +7 -5
- solace_agent_mesh/gateway/http_sse/main.py +5 -2
- solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +12 -13
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +15 -18
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +25 -18
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +30 -26
- solace_agent_mesh/gateway/http_sse/repository/task_repository.py +35 -44
- solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +7 -5
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +97 -205
- solace_agent_mesh/gateway/http_sse/routers/auth.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/config.py +3 -2
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +4 -3
- solace_agent_mesh/gateway/http_sse/routers/people.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +5 -3
- solace_agent_mesh/gateway/http_sse/routers/sse.py +3 -2
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +35 -42
- solace_agent_mesh/gateway/http_sse/routers/users.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +19 -12
- solace_agent_mesh/gateway/http_sse/services/agent_card_service.py +3 -1
- solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +6 -5
- solace_agent_mesh/gateway/http_sse/services/feedback_service.py +53 -44
- solace_agent_mesh/gateway/http_sse/services/people_service.py +2 -2
- solace_agent_mesh/gateway/http_sse/services/session_service.py +23 -21
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +10 -9
- solace_agent_mesh/gateway/http_sse/services/task_service.py +3 -2
- solace_agent_mesh/gateway/http_sse/session_manager.py +2 -1
- solace_agent_mesh/gateway/http_sse/shared/base_repository.py +45 -71
- solace_agent_mesh/gateway/http_sse/shared/types.py +0 -18
- solace_agent_mesh/gateway/http_sse/sse_event_buffer.py +2 -1
- solace_agent_mesh/gateway/http_sse/sse_manager.py +2 -2
- solace_agent_mesh/templates/gateway_app_template.py +4 -2
- solace_agent_mesh/templates/gateway_component_template.py +3 -1
- solace_agent_mesh/templates/gateway_config_template.yaml +0 -5
- solace_agent_mesh/templates/logging_config_template.ini +27 -46
- solace_agent_mesh/templates/plugin_gateway_config_template.yaml +0 -3
- solace_agent_mesh/templates/plugin_tools_template.py +2 -2
- solace_agent_mesh/templates/shared_config.yaml +40 -0
- {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/METADATA +47 -21
- {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/RECORD +254 -225
- 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.a248f00c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/0e682baa.d54b8668.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1023fc19.8a8a9309.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1523c6b4.2645ef68.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/166ab619.e27886d9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.e056b7e0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/21ceee5f.3bf39250.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/2a9cab12.2afaee76.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/332e10b5.f7629851.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3d406171.5560fdf9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.508ae8db.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/442a8107.b5c2532a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/453a82a6.3c6bb61d.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/483cef9a.bf9398af.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/4c2787c2.c1290a40.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55f47984.bcd00a86.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5b4258a4.fdfd2325.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/664b740a.ba305a89.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/75384d09.c19e8b51.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/768e31b0.9abcdc48.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/85387663.be2bc838.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/945fb41e.16e00776.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.92de8cf5.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.d62aad71.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/a12a4955.25fbed32.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.af35e313.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/aba87c2f.4ddf32f2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.5fe5203f.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae4415af.16cc58d3.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/bac0be12.17de4316.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c2c06897.87cb1f47.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c835a94d.ce21f0bf.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cc969b05.feef7dcc.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cd3d4052.a19e7d78.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ced92a13.fb92e7ca.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cee5d587.47904f5e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/d6a81ee7.829198f1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.ed8dd236.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f897a61a.126663fe.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/fbfa3e75.e144b16c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.0c149855.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.c66557e4.js +0 -1
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +0 -46
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/rbac-setup-guilde/index.html +0 -201
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +0 -29
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +0 -105
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +0 -144
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +0 -91
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +0 -91
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +0 -55
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +0 -111
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +0 -77
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +0 -48
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +0 -54
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +0 -45
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +0 -74
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/litellm_models/index.html +0 -49
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +0 -76
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +0 -73
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +0 -72
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +0 -54
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +0 -69
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +0 -59
- solace_agent_mesh/assets/docs/lunr-index-1760032255022.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1760032255022.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-CZbpmwfA.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-C__uuUkB.js +0 -339
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-BNuqpWDc.js +0 -98
- solace_agent_mesh/evaluation/config_loader.py +0 -657
- solace_agent_mesh/evaluation/test_case_loader.py +0 -714
- /solace_agent_mesh/assets/docs/assets/js/{8591.d7c16be6.js.LICENSE.txt → 8591.5d015485.js.LICENSE.txt} +0 -0
- /solace_agent_mesh/assets/docs/assets/js/{main.0c149855.js.LICENSE.txt → main.20feee82.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,714 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Refactored test case loader with comprehensive validation and error handling.
|
|
3
|
-
This module provides robust test case loading with validation for every field.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import json
|
|
7
|
-
import os
|
|
8
|
-
import sys
|
|
9
|
-
from dataclasses import dataclass, field
|
|
10
|
-
from typing import Dict, List, Optional, Any, Union
|
|
11
|
-
from enum import Enum
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
import logging
|
|
14
|
-
|
|
15
|
-
# Set up logging
|
|
16
|
-
logging.basicConfig(level=logging.INFO)
|
|
17
|
-
logger = logging.getLogger(__name__)
|
|
18
|
-
|
|
19
|
-
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class ValidationLevel(Enum):
|
|
23
|
-
"""Defines the validation level for test case fields."""
|
|
24
|
-
|
|
25
|
-
REQUIRED = "required"
|
|
26
|
-
OPTIONAL = "optional"
|
|
27
|
-
CONDITIONAL = "conditional"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class TestCaseError(Exception):
|
|
31
|
-
"""Base exception for test case-related errors."""
|
|
32
|
-
|
|
33
|
-
pass
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class TestCaseFileNotFoundError(TestCaseError):
|
|
37
|
-
"""Raised when the test case file is not found."""
|
|
38
|
-
|
|
39
|
-
pass
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class TestCaseParseError(TestCaseError):
|
|
43
|
-
"""Raised when the test case file cannot be parsed."""
|
|
44
|
-
|
|
45
|
-
pass
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class TestCaseValidationError(TestCaseError):
|
|
49
|
-
"""Raised when test case validation fails."""
|
|
50
|
-
|
|
51
|
-
pass
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class ArtifactValidationError(TestCaseError):
|
|
55
|
-
"""Raised when artifact validation fails."""
|
|
56
|
-
|
|
57
|
-
pass
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@dataclass
|
|
61
|
-
class ValidationReport:
|
|
62
|
-
"""Detailed validation report with all errors and warnings."""
|
|
63
|
-
|
|
64
|
-
def __init__(self):
|
|
65
|
-
self.errors: List[str] = []
|
|
66
|
-
self.warnings: List[str] = []
|
|
67
|
-
|
|
68
|
-
def add_error(self, field: str, message: str):
|
|
69
|
-
"""Add a validation error."""
|
|
70
|
-
self.errors.append(f"Field '{field}': {message}")
|
|
71
|
-
|
|
72
|
-
def add_warning(self, field: str, message: str):
|
|
73
|
-
"""Add a validation warning."""
|
|
74
|
-
self.warnings.append(f"Field '{field}': {message}")
|
|
75
|
-
|
|
76
|
-
def has_errors(self) -> bool:
|
|
77
|
-
"""Check if there are any validation errors."""
|
|
78
|
-
return len(self.errors) > 0
|
|
79
|
-
|
|
80
|
-
def get_summary(self) -> str:
|
|
81
|
-
"""Get human-readable validation summary."""
|
|
82
|
-
summary = []
|
|
83
|
-
if self.errors:
|
|
84
|
-
summary.append("ERRORS:")
|
|
85
|
-
summary.extend([f" - {error}" for error in self.errors])
|
|
86
|
-
if self.warnings:
|
|
87
|
-
summary.append("WARNINGS:")
|
|
88
|
-
summary.extend([f" - {warning}" for warning in self.warnings])
|
|
89
|
-
return "\n".join(summary) if summary else "Test case validation passed."
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
@dataclass
|
|
93
|
-
class FieldValidator:
|
|
94
|
-
"""Defines validation rules for a test case field."""
|
|
95
|
-
|
|
96
|
-
name: str
|
|
97
|
-
validation_level: ValidationLevel
|
|
98
|
-
field_type: type
|
|
99
|
-
default_value: Any = None
|
|
100
|
-
min_length: Optional[int] = None
|
|
101
|
-
max_length: Optional[int] = None
|
|
102
|
-
min_value: Optional[Union[int, float]] = None
|
|
103
|
-
max_value: Optional[Union[int, float]] = None
|
|
104
|
-
allowed_values: Optional[List[Any]] = None
|
|
105
|
-
pattern: Optional[str] = None
|
|
106
|
-
custom_validator: Optional[str] = None
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@dataclass
|
|
110
|
-
class ArtifactConfig:
|
|
111
|
-
"""Individual artifact configuration with validation."""
|
|
112
|
-
|
|
113
|
-
artifact_type: str
|
|
114
|
-
path: str
|
|
115
|
-
|
|
116
|
-
def __post_init__(self):
|
|
117
|
-
"""Validate artifact configuration after initialization."""
|
|
118
|
-
if not self.artifact_type or self.artifact_type.strip() == "":
|
|
119
|
-
raise ArtifactValidationError("Artifact type cannot be empty")
|
|
120
|
-
|
|
121
|
-
if not self.path or self.path.strip() == "":
|
|
122
|
-
raise ArtifactValidationError("Artifact path cannot be empty")
|
|
123
|
-
|
|
124
|
-
# Validate artifact type
|
|
125
|
-
allowed_types = ["file", "url", "text"]
|
|
126
|
-
if self.artifact_type not in allowed_types:
|
|
127
|
-
raise ArtifactValidationError(
|
|
128
|
-
f"Artifact type must be one of {allowed_types}, got '{self.artifact_type}'"
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
# Validate file path security (prevent directory traversal)
|
|
132
|
-
if self.artifact_type == "file":
|
|
133
|
-
normalized_path = os.path.normpath(self.path)
|
|
134
|
-
if normalized_path.startswith("..") or os.path.isabs(normalized_path):
|
|
135
|
-
raise ArtifactValidationError(
|
|
136
|
-
f"Artifact path '{self.path}' is not safe (no absolute paths or directory traversal)"
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
@dataclass
|
|
141
|
-
class EvaluationConfig:
|
|
142
|
-
"""Evaluation criteria configuration with validation."""
|
|
143
|
-
|
|
144
|
-
expected_tools: List[str] = field(default_factory=list)
|
|
145
|
-
expected_response: str = ""
|
|
146
|
-
criterion: str = ""
|
|
147
|
-
|
|
148
|
-
def __post_init__(self):
|
|
149
|
-
"""Validate evaluation configuration after initialization."""
|
|
150
|
-
# Validate expected_tools
|
|
151
|
-
if not isinstance(self.expected_tools, list):
|
|
152
|
-
raise TestCaseValidationError("expected_tools must be a list")
|
|
153
|
-
|
|
154
|
-
# Validate tool names format
|
|
155
|
-
for tool in self.expected_tools:
|
|
156
|
-
if not isinstance(tool, str) or not tool.strip():
|
|
157
|
-
raise TestCaseValidationError(
|
|
158
|
-
f"Tool name must be a non-empty string, got '{tool}'"
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
# Validate strings
|
|
162
|
-
if not isinstance(self.expected_response, str):
|
|
163
|
-
raise TestCaseValidationError("expected_response must be a string")
|
|
164
|
-
|
|
165
|
-
if not isinstance(self.criterion, str):
|
|
166
|
-
raise TestCaseValidationError("criterion must be a string")
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
@dataclass
|
|
170
|
-
class TestCase:
|
|
171
|
-
"""Complete test case configuration with validation."""
|
|
172
|
-
|
|
173
|
-
test_case_id: str
|
|
174
|
-
query: str
|
|
175
|
-
target_agent: str
|
|
176
|
-
category: str = "Other"
|
|
177
|
-
description: str = "No description provided."
|
|
178
|
-
wait_time: int = 60
|
|
179
|
-
artifacts: List[ArtifactConfig] = field(default_factory=list)
|
|
180
|
-
evaluation: EvaluationConfig = field(default_factory=EvaluationConfig)
|
|
181
|
-
|
|
182
|
-
def __post_init__(self):
|
|
183
|
-
"""Validate the complete test case after initialization."""
|
|
184
|
-
# Validate required string fields
|
|
185
|
-
if not self.test_case_id or not self.test_case_id.strip():
|
|
186
|
-
raise TestCaseValidationError("test_case_id cannot be empty")
|
|
187
|
-
|
|
188
|
-
if not self.query or not self.query.strip():
|
|
189
|
-
raise TestCaseValidationError("query cannot be empty")
|
|
190
|
-
|
|
191
|
-
if not self.target_agent or not self.target_agent.strip():
|
|
192
|
-
raise TestCaseValidationError("target_agent cannot be empty")
|
|
193
|
-
|
|
194
|
-
# Validate wait_time
|
|
195
|
-
if not isinstance(self.wait_time, int) or self.wait_time < 1:
|
|
196
|
-
raise TestCaseValidationError("wait_time must be a positive integer")
|
|
197
|
-
|
|
198
|
-
if self.wait_time > 300: # 5 minutes max
|
|
199
|
-
raise TestCaseValidationError("wait_time cannot exceed 300 seconds")
|
|
200
|
-
|
|
201
|
-
# Validate artifacts
|
|
202
|
-
if not isinstance(self.artifacts, list):
|
|
203
|
-
raise TestCaseValidationError("artifacts must be a list")
|
|
204
|
-
|
|
205
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
206
|
-
"""Convert test case to dictionary format for JSON serialization."""
|
|
207
|
-
return {
|
|
208
|
-
"test_case_id": self.test_case_id,
|
|
209
|
-
"category": self.category,
|
|
210
|
-
"description": self.description,
|
|
211
|
-
"query": self.query,
|
|
212
|
-
"target_agent": self.target_agent,
|
|
213
|
-
"wait_time": self.wait_time,
|
|
214
|
-
"artifacts": [
|
|
215
|
-
{"type": artifact.artifact_type, "path": artifact.path}
|
|
216
|
-
for artifact in self.artifacts
|
|
217
|
-
],
|
|
218
|
-
"evaluation": {
|
|
219
|
-
"expected_tools": self.evaluation.expected_tools,
|
|
220
|
-
"expected_response": self.evaluation.expected_response,
|
|
221
|
-
"criterion": self.evaluation.criterion,
|
|
222
|
-
},
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
class TestCaseValidator:
|
|
227
|
-
"""Comprehensive test case validator with detailed error reporting."""
|
|
228
|
-
|
|
229
|
-
# Validation rules for root-level fields
|
|
230
|
-
ROOT_LEVEL_RULES = {
|
|
231
|
-
"test_case_id": FieldValidator(
|
|
232
|
-
name="test_case_id",
|
|
233
|
-
validation_level=ValidationLevel.REQUIRED,
|
|
234
|
-
field_type=str,
|
|
235
|
-
min_length=1,
|
|
236
|
-
max_length=100,
|
|
237
|
-
),
|
|
238
|
-
"query": FieldValidator(
|
|
239
|
-
name="query",
|
|
240
|
-
validation_level=ValidationLevel.REQUIRED,
|
|
241
|
-
field_type=str,
|
|
242
|
-
min_length=1,
|
|
243
|
-
max_length=2000,
|
|
244
|
-
),
|
|
245
|
-
"target_agent": FieldValidator(
|
|
246
|
-
name="target_agent",
|
|
247
|
-
validation_level=ValidationLevel.REQUIRED,
|
|
248
|
-
field_type=str,
|
|
249
|
-
min_length=1,
|
|
250
|
-
max_length=100,
|
|
251
|
-
),
|
|
252
|
-
"category": FieldValidator(
|
|
253
|
-
name="category",
|
|
254
|
-
validation_level=ValidationLevel.OPTIONAL,
|
|
255
|
-
field_type=str,
|
|
256
|
-
default_value="Other",
|
|
257
|
-
max_length=100,
|
|
258
|
-
),
|
|
259
|
-
"description": FieldValidator(
|
|
260
|
-
name="description",
|
|
261
|
-
validation_level=ValidationLevel.OPTIONAL,
|
|
262
|
-
field_type=str,
|
|
263
|
-
default_value="No description provided.",
|
|
264
|
-
max_length=1000,
|
|
265
|
-
),
|
|
266
|
-
"wait_time": FieldValidator(
|
|
267
|
-
name="wait_time",
|
|
268
|
-
validation_level=ValidationLevel.OPTIONAL,
|
|
269
|
-
field_type=int,
|
|
270
|
-
default_value=60,
|
|
271
|
-
min_value=1,
|
|
272
|
-
max_value=300,
|
|
273
|
-
),
|
|
274
|
-
"artifacts": FieldValidator(
|
|
275
|
-
name="artifacts",
|
|
276
|
-
validation_level=ValidationLevel.OPTIONAL,
|
|
277
|
-
field_type=list,
|
|
278
|
-
default_value=[],
|
|
279
|
-
),
|
|
280
|
-
"evaluation": FieldValidator(
|
|
281
|
-
name="evaluation",
|
|
282
|
-
validation_level=ValidationLevel.OPTIONAL,
|
|
283
|
-
field_type=dict,
|
|
284
|
-
default_value={},
|
|
285
|
-
),
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
# Validation rules for evaluation fields
|
|
289
|
-
EVALUATION_RULES = {
|
|
290
|
-
"expected_tools": FieldValidator(
|
|
291
|
-
name="expected_tools",
|
|
292
|
-
validation_level=ValidationLevel.OPTIONAL,
|
|
293
|
-
field_type=list,
|
|
294
|
-
default_value=[],
|
|
295
|
-
),
|
|
296
|
-
"expected_response": FieldValidator(
|
|
297
|
-
name="expected_response",
|
|
298
|
-
validation_level=ValidationLevel.OPTIONAL,
|
|
299
|
-
field_type=str,
|
|
300
|
-
default_value="",
|
|
301
|
-
max_length=2000,
|
|
302
|
-
),
|
|
303
|
-
"criterion": FieldValidator(
|
|
304
|
-
name="criterion",
|
|
305
|
-
validation_level=ValidationLevel.OPTIONAL,
|
|
306
|
-
field_type=str,
|
|
307
|
-
default_value="",
|
|
308
|
-
max_length=1000,
|
|
309
|
-
),
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
# Validation rules for artifact fields
|
|
313
|
-
ARTIFACT_RULES = {
|
|
314
|
-
"type": FieldValidator(
|
|
315
|
-
name="type",
|
|
316
|
-
validation_level=ValidationLevel.REQUIRED,
|
|
317
|
-
field_type=str,
|
|
318
|
-
allowed_values=["file", "url", "text"],
|
|
319
|
-
),
|
|
320
|
-
"path": FieldValidator(
|
|
321
|
-
name="path",
|
|
322
|
-
validation_level=ValidationLevel.REQUIRED,
|
|
323
|
-
field_type=str,
|
|
324
|
-
min_length=1,
|
|
325
|
-
max_length=500,
|
|
326
|
-
),
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
def __init__(self, test_cases_dir: str):
|
|
330
|
-
self.test_cases_dir = test_cases_dir
|
|
331
|
-
self.report = ValidationReport()
|
|
332
|
-
|
|
333
|
-
def validate_field(
|
|
334
|
-
self,
|
|
335
|
-
field_name: str,
|
|
336
|
-
value: Any,
|
|
337
|
-
rules: Dict[str, FieldValidator],
|
|
338
|
-
context: str = "",
|
|
339
|
-
) -> Any:
|
|
340
|
-
"""Validate individual field with comprehensive checks."""
|
|
341
|
-
rule = rules.get(field_name)
|
|
342
|
-
if not rule:
|
|
343
|
-
self.report.add_warning(
|
|
344
|
-
f"{context}.{field_name}" if context else field_name,
|
|
345
|
-
"Unknown field in test case",
|
|
346
|
-
)
|
|
347
|
-
return value
|
|
348
|
-
|
|
349
|
-
full_field_name = f"{context}.{field_name}" if context else field_name
|
|
350
|
-
|
|
351
|
-
# Handle missing required fields
|
|
352
|
-
if value is None:
|
|
353
|
-
if rule.validation_level == ValidationLevel.REQUIRED:
|
|
354
|
-
self.report.add_error(full_field_name, "Required field is missing")
|
|
355
|
-
return None
|
|
356
|
-
else:
|
|
357
|
-
return rule.default_value
|
|
358
|
-
|
|
359
|
-
# Type validation
|
|
360
|
-
if not isinstance(value, rule.field_type):
|
|
361
|
-
self.report.add_error(
|
|
362
|
-
full_field_name,
|
|
363
|
-
f"Expected {rule.field_type.__name__}, got {type(value).__name__}",
|
|
364
|
-
)
|
|
365
|
-
return rule.default_value
|
|
366
|
-
|
|
367
|
-
# Length validation for lists and strings
|
|
368
|
-
if rule.min_length is not None:
|
|
369
|
-
if hasattr(value, "__len__") and len(value) < rule.min_length:
|
|
370
|
-
self.report.add_error(
|
|
371
|
-
full_field_name,
|
|
372
|
-
f"Minimum length is {rule.min_length}, got {len(value)}",
|
|
373
|
-
)
|
|
374
|
-
return rule.default_value
|
|
375
|
-
|
|
376
|
-
if rule.max_length is not None:
|
|
377
|
-
if hasattr(value, "__len__") and len(value) > rule.max_length:
|
|
378
|
-
self.report.add_error(
|
|
379
|
-
full_field_name,
|
|
380
|
-
f"Maximum length is {rule.max_length}, got {len(value)}",
|
|
381
|
-
)
|
|
382
|
-
# Truncate for strings, return default for lists
|
|
383
|
-
if isinstance(value, str):
|
|
384
|
-
return value[: rule.max_length]
|
|
385
|
-
else:
|
|
386
|
-
return rule.default_value
|
|
387
|
-
|
|
388
|
-
# Value range validation for numbers
|
|
389
|
-
if rule.min_value is not None and isinstance(value, (int, float)):
|
|
390
|
-
if value < rule.min_value:
|
|
391
|
-
self.report.add_error(
|
|
392
|
-
full_field_name, f"Minimum value is {rule.min_value}, got {value}"
|
|
393
|
-
)
|
|
394
|
-
return rule.default_value
|
|
395
|
-
|
|
396
|
-
if rule.max_value is not None and isinstance(value, (int, float)):
|
|
397
|
-
if value > rule.max_value:
|
|
398
|
-
self.report.add_error(
|
|
399
|
-
full_field_name, f"Maximum value is {rule.max_value}, got {value}"
|
|
400
|
-
)
|
|
401
|
-
return rule.default_value
|
|
402
|
-
|
|
403
|
-
# Allowed values validation
|
|
404
|
-
if rule.allowed_values is not None and value not in rule.allowed_values:
|
|
405
|
-
self.report.add_error(
|
|
406
|
-
full_field_name,
|
|
407
|
-
f"Value must be one of {rule.allowed_values}, got '{value}'",
|
|
408
|
-
)
|
|
409
|
-
return rule.default_value
|
|
410
|
-
|
|
411
|
-
return value
|
|
412
|
-
|
|
413
|
-
def validate_artifact(
|
|
414
|
-
self, artifact_data: Dict[str, Any], index: int
|
|
415
|
-
) -> Optional[ArtifactConfig]:
|
|
416
|
-
"""Validate individual artifact configuration."""
|
|
417
|
-
context = f"artifacts[{index}]"
|
|
418
|
-
|
|
419
|
-
# Validate required fields
|
|
420
|
-
artifact_type = self.validate_field(
|
|
421
|
-
"type", artifact_data.get("type"), self.ARTIFACT_RULES, context
|
|
422
|
-
)
|
|
423
|
-
path = self.validate_field(
|
|
424
|
-
"path", artifact_data.get("path"), self.ARTIFACT_RULES, context
|
|
425
|
-
)
|
|
426
|
-
|
|
427
|
-
if not artifact_type or not path:
|
|
428
|
-
self.report.add_error(context, "Invalid artifact configuration")
|
|
429
|
-
return None
|
|
430
|
-
|
|
431
|
-
try:
|
|
432
|
-
artifact = ArtifactConfig(artifact_type=artifact_type, path=path)
|
|
433
|
-
|
|
434
|
-
# Additional file existence check for file artifacts
|
|
435
|
-
if artifact.artifact_type == "file":
|
|
436
|
-
full_path = os.path.join(self.test_cases_dir, artifact.path)
|
|
437
|
-
if not os.path.exists(full_path):
|
|
438
|
-
self.report.add_warning(
|
|
439
|
-
f"{context}.path", f"Artifact file does not exist: {full_path}"
|
|
440
|
-
)
|
|
441
|
-
|
|
442
|
-
return artifact
|
|
443
|
-
|
|
444
|
-
except ArtifactValidationError as e:
|
|
445
|
-
self.report.add_error(context, str(e))
|
|
446
|
-
return None
|
|
447
|
-
|
|
448
|
-
def validate_evaluation(self, eval_data: Dict[str, Any]) -> EvaluationConfig:
|
|
449
|
-
"""Validate evaluation configuration."""
|
|
450
|
-
context = "evaluation"
|
|
451
|
-
|
|
452
|
-
# Validate evaluation fields
|
|
453
|
-
expected_tools = self.validate_field(
|
|
454
|
-
"expected_tools",
|
|
455
|
-
eval_data.get("expected_tools"),
|
|
456
|
-
self.EVALUATION_RULES,
|
|
457
|
-
context,
|
|
458
|
-
)
|
|
459
|
-
expected_response = self.validate_field(
|
|
460
|
-
"expected_response",
|
|
461
|
-
eval_data.get("expected_response"),
|
|
462
|
-
self.EVALUATION_RULES,
|
|
463
|
-
context,
|
|
464
|
-
)
|
|
465
|
-
criterion = self.validate_field(
|
|
466
|
-
"criterion", eval_data.get("criterion"), self.EVALUATION_RULES, context
|
|
467
|
-
)
|
|
468
|
-
|
|
469
|
-
try:
|
|
470
|
-
return EvaluationConfig(
|
|
471
|
-
expected_tools=expected_tools or [],
|
|
472
|
-
expected_response=expected_response or "",
|
|
473
|
-
criterion=criterion or "",
|
|
474
|
-
)
|
|
475
|
-
except TestCaseValidationError as e:
|
|
476
|
-
self.report.add_error(context, str(e))
|
|
477
|
-
# Return default evaluation config if validation fails
|
|
478
|
-
return EvaluationConfig()
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
class TestCaseLoader:
|
|
482
|
-
"""Loads test case files with comprehensive error handling."""
|
|
483
|
-
|
|
484
|
-
def __init__(self, test_cases_dir: str):
|
|
485
|
-
self.test_cases_dir = test_cases_dir
|
|
486
|
-
|
|
487
|
-
def load_file(self, test_case_id: str) -> Dict[str, Any]:
|
|
488
|
-
"""Load test case file with comprehensive error handling."""
|
|
489
|
-
# Normalize test case ID
|
|
490
|
-
if test_case_id.endswith(".test.json"):
|
|
491
|
-
test_case_id = test_case_id.replace(".test.json", "")
|
|
492
|
-
|
|
493
|
-
test_case_path = os.path.join(self.test_cases_dir, f"{test_case_id}.test.json")
|
|
494
|
-
|
|
495
|
-
try:
|
|
496
|
-
with open(test_case_path, "r") as f:
|
|
497
|
-
return json.load(f)
|
|
498
|
-
except FileNotFoundError:
|
|
499
|
-
raise TestCaseFileNotFoundError(
|
|
500
|
-
f"Test case file not found: {test_case_path}"
|
|
501
|
-
)
|
|
502
|
-
except json.JSONDecodeError as e:
|
|
503
|
-
raise TestCaseParseError(
|
|
504
|
-
f"Invalid JSON in test case file {test_case_path}: {e}"
|
|
505
|
-
)
|
|
506
|
-
except Exception as e:
|
|
507
|
-
raise TestCaseError(f"Error reading test case file {test_case_path}: {e}")
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
class TestCaseProcessor:
|
|
511
|
-
"""Main orchestrator for test case processing with comprehensive validation."""
|
|
512
|
-
|
|
513
|
-
def __init__(self, test_cases_dir: str):
|
|
514
|
-
self.loader = TestCaseLoader(test_cases_dir)
|
|
515
|
-
self.validator = TestCaseValidator(test_cases_dir)
|
|
516
|
-
|
|
517
|
-
def load_and_process(self, test_case_id: str) -> Dict[str, Any]:
|
|
518
|
-
"""Load and process test case, returning the same format as original."""
|
|
519
|
-
try:
|
|
520
|
-
# Load raw test case
|
|
521
|
-
raw_test_case = self.loader.load_file(test_case_id)
|
|
522
|
-
|
|
523
|
-
# Process and validate
|
|
524
|
-
processed_test_case = self._process_test_case(raw_test_case, test_case_id)
|
|
525
|
-
|
|
526
|
-
# Check for validation errors
|
|
527
|
-
if self.validator.report.has_errors():
|
|
528
|
-
error_summary = self.validator.report.get_summary()
|
|
529
|
-
print(
|
|
530
|
-
f"Test case validation failed for '{test_case_id}':\n{error_summary}"
|
|
531
|
-
)
|
|
532
|
-
sys.exit(1)
|
|
533
|
-
|
|
534
|
-
# Log warnings if any
|
|
535
|
-
if self.validator.report.warnings:
|
|
536
|
-
for warning in self.validator.report.warnings:
|
|
537
|
-
logger.warning(f"Test case '{test_case_id}': {warning}")
|
|
538
|
-
|
|
539
|
-
return processed_test_case
|
|
540
|
-
|
|
541
|
-
except TestCaseFileNotFoundError:
|
|
542
|
-
print(
|
|
543
|
-
f"Error: Test case file not found for '{test_case_id}' in {self.loader.test_cases_dir}"
|
|
544
|
-
)
|
|
545
|
-
sys.exit(1)
|
|
546
|
-
except TestCaseParseError as e:
|
|
547
|
-
print(f"Error: Could not decode JSON from test case '{test_case_id}': {e}")
|
|
548
|
-
sys.exit(1)
|
|
549
|
-
except Exception as e:
|
|
550
|
-
print(f"Error loading test case '{test_case_id}': {e}")
|
|
551
|
-
sys.exit(1)
|
|
552
|
-
|
|
553
|
-
def _process_test_case(
|
|
554
|
-
self, raw_test_case: Dict[str, Any], test_case_id: str
|
|
555
|
-
) -> Dict[str, Any]:
|
|
556
|
-
"""Process and validate the raw test case."""
|
|
557
|
-
# Validate and set defaults for root-level fields
|
|
558
|
-
validated_test_case_id = self.validator.validate_field(
|
|
559
|
-
"test_case_id",
|
|
560
|
-
raw_test_case.get("test_case_id"),
|
|
561
|
-
self.validator.ROOT_LEVEL_RULES,
|
|
562
|
-
)
|
|
563
|
-
|
|
564
|
-
query = self.validator.validate_field(
|
|
565
|
-
"query", raw_test_case.get("query"), self.validator.ROOT_LEVEL_RULES
|
|
566
|
-
)
|
|
567
|
-
|
|
568
|
-
target_agent = self.validator.validate_field(
|
|
569
|
-
"target_agent",
|
|
570
|
-
raw_test_case.get("target_agent"),
|
|
571
|
-
self.validator.ROOT_LEVEL_RULES,
|
|
572
|
-
)
|
|
573
|
-
|
|
574
|
-
category = self.validator.validate_field(
|
|
575
|
-
"category", raw_test_case.get("category"), self.validator.ROOT_LEVEL_RULES
|
|
576
|
-
)
|
|
577
|
-
|
|
578
|
-
description = self.validator.validate_field(
|
|
579
|
-
"description",
|
|
580
|
-
raw_test_case.get("description"),
|
|
581
|
-
self.validator.ROOT_LEVEL_RULES,
|
|
582
|
-
)
|
|
583
|
-
|
|
584
|
-
wait_time = self.validator.validate_field(
|
|
585
|
-
"wait_time", raw_test_case.get("wait_time"), self.validator.ROOT_LEVEL_RULES
|
|
586
|
-
)
|
|
587
|
-
|
|
588
|
-
# Process artifacts with validation
|
|
589
|
-
artifacts_data = raw_test_case.get("artifacts", [])
|
|
590
|
-
processed_artifacts = []
|
|
591
|
-
|
|
592
|
-
if artifacts_data and isinstance(artifacts_data, list):
|
|
593
|
-
for i, artifact_data in enumerate(artifacts_data):
|
|
594
|
-
artifact = self.validator.validate_artifact(artifact_data, i)
|
|
595
|
-
if artifact:
|
|
596
|
-
processed_artifacts.append(
|
|
597
|
-
{"type": artifact.artifact_type, "path": artifact.path}
|
|
598
|
-
)
|
|
599
|
-
|
|
600
|
-
# Process evaluation with validation
|
|
601
|
-
evaluation_data = raw_test_case.get("evaluation", {})
|
|
602
|
-
evaluation = self.validator.validate_evaluation(evaluation_data)
|
|
603
|
-
|
|
604
|
-
processed_evaluation = {
|
|
605
|
-
"expected_tools": evaluation.expected_tools,
|
|
606
|
-
"expected_response": evaluation.expected_response,
|
|
607
|
-
"criterion": evaluation.criterion,
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
# Return processed test case in original format
|
|
611
|
-
return {
|
|
612
|
-
"test_case_id": validated_test_case_id or test_case_id,
|
|
613
|
-
"category": category or "Other",
|
|
614
|
-
"description": description or "No description provided.",
|
|
615
|
-
"query": query or "",
|
|
616
|
-
"target_agent": target_agent or "",
|
|
617
|
-
"wait_time": wait_time or 60,
|
|
618
|
-
"artifacts": processed_artifacts,
|
|
619
|
-
"evaluation": processed_evaluation,
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
# Main API function - same interface as original
|
|
624
|
-
def load_test_case(test_case_path: str) -> Dict[str, Any]:
|
|
625
|
-
"""
|
|
626
|
-
Load test case from a JSON file with comprehensive validation.
|
|
627
|
-
Returns the same format as the original function.
|
|
628
|
-
|
|
629
|
-
Args:
|
|
630
|
-
test_case_path: The full path to the test case file.
|
|
631
|
-
|
|
632
|
-
Returns:
|
|
633
|
-
Dictionary containing the validated test case data
|
|
634
|
-
|
|
635
|
-
Raises:
|
|
636
|
-
SystemExit: If validation fails or file cannot be loaded
|
|
637
|
-
"""
|
|
638
|
-
test_case_dir = str(Path(test_case_path).parent)
|
|
639
|
-
test_case_filename = Path(test_case_path).name
|
|
640
|
-
processor = TestCaseProcessor(test_cases_dir=test_case_dir)
|
|
641
|
-
return processor.load_and_process(test_case_filename)
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
def validate_test_case_file(test_case_path: str) -> ValidationReport:
|
|
645
|
-
"""
|
|
646
|
-
Validate a test case file and return detailed validation report.
|
|
647
|
-
|
|
648
|
-
Args:
|
|
649
|
-
test_case_path: The full path to the test case file.
|
|
650
|
-
|
|
651
|
-
Returns:
|
|
652
|
-
ValidationReport with errors and warnings
|
|
653
|
-
"""
|
|
654
|
-
try:
|
|
655
|
-
test_case_dir = str(Path(test_case_path).parent)
|
|
656
|
-
test_case_filename = Path(test_case_path).name
|
|
657
|
-
processor = TestCaseProcessor(test_cases_dir=test_case_dir)
|
|
658
|
-
processor.load_and_process(test_case_filename)
|
|
659
|
-
return processor.validator.report
|
|
660
|
-
except SystemExit:
|
|
661
|
-
# Capture the validation report even if processing failed
|
|
662
|
-
return processor.validator.report
|
|
663
|
-
except Exception as e:
|
|
664
|
-
report = ValidationReport()
|
|
665
|
-
report.add_error("general", f"Unexpected error: {str(e)}")
|
|
666
|
-
return report
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
def main():
|
|
670
|
-
"""Main entry point for command-line usage and testing."""
|
|
671
|
-
import sys
|
|
672
|
-
|
|
673
|
-
if len(sys.argv) != 2:
|
|
674
|
-
print("Usage: python test_case_loader.py <test_case_id>")
|
|
675
|
-
print("Example: python test_case_loader.py hello_world")
|
|
676
|
-
sys.exit(1)
|
|
677
|
-
|
|
678
|
-
test_case_id = sys.argv[1]
|
|
679
|
-
|
|
680
|
-
try:
|
|
681
|
-
# Load and validate test case
|
|
682
|
-
test_case = load_test_case(test_case_id)
|
|
683
|
-
|
|
684
|
-
# Print results
|
|
685
|
-
print(f"Successfully loaded test case: {test_case_id}")
|
|
686
|
-
print(f"Target Agent: {test_case['target_agent']}")
|
|
687
|
-
print(f"Category: {test_case['category']}")
|
|
688
|
-
print(
|
|
689
|
-
f"Query: {test_case['query'][:100]}{'...' if len(test_case['query']) > 100 else ''}"
|
|
690
|
-
)
|
|
691
|
-
print(f"Wait Time: {test_case['wait_time']} seconds")
|
|
692
|
-
print(f"Artifacts: {len(test_case['artifacts'])} artifact(s)")
|
|
693
|
-
print(
|
|
694
|
-
f"Expected Tools: {len(test_case['evaluation']['expected_tools'])} tool(s)"
|
|
695
|
-
)
|
|
696
|
-
|
|
697
|
-
# Show validation report
|
|
698
|
-
processor = TestCaseProcessor()
|
|
699
|
-
report = validate_test_case_file(test_case_id)
|
|
700
|
-
if report.warnings:
|
|
701
|
-
print("\nWarnings:")
|
|
702
|
-
for warning in report.warnings:
|
|
703
|
-
print(f" - {warning}")
|
|
704
|
-
|
|
705
|
-
except SystemExit:
|
|
706
|
-
# Error already printed by load_test_case
|
|
707
|
-
pass
|
|
708
|
-
except Exception as e:
|
|
709
|
-
print(f"Unexpected error: {e}")
|
|
710
|
-
sys.exit(1)
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
if __name__ == "__main__":
|
|
714
|
-
main()
|