ai-eval-scope 0.3.2__tar.gz → 0.3.4__tar.gz
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.
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/.coverage +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/.gitignore +3 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/CHANGELOG.md +22 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/CLAUDE.md +4 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/PKG-INFO +1 -1
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/__init__.py +1 -1
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/agent.py +126 -4
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/memory.py +19 -3
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/messages.py +28 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/context.py +86 -10
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/protocol.py +12 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/request.py +48 -6
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/response.py +4 -2
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/server.py +22 -1
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/specs.py +7 -2
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/tokens.py +59 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/tools.py +251 -13
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/configs/workbench_agent_prompts.yaml +93 -49
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/_common.py +8 -5
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/auth.py +11 -2
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/workbench_agent.py +95 -49
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/agent_stream.py +111 -3
- ai_eval_scope-0.3.4/agent_eval/cli/console/markdown_lite.py +122 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/registry.py +37 -1
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/pyproject.toml +1 -1
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/report/mypy-results.xml +2 -2
- ai_eval_scope-0.3.4/report/test-results.xml +1 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_auth.py +22 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_commands.py +50 -0
- ai_eval_scope-0.3.4/tests/unit/test_markdown_lite.py +113 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_sut_probe.py +359 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_sut_registry.py +117 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_workbench_agent.py +931 -1
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/uv.lock +1 -1
- ai_eval_scope-0.3.2/report/test-results.xml +0 -1
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/LICENSE +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/README.md +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/budget.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/callbacks.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/model_bridge.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/session.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/session_log.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/tool_filter.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/tools.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/agent.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/briefing.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/http_tools.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/ledger.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/package_writer.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/policy.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/prompts.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/protocol_tools.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/sut_tools.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/transcript.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/gates.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/prompts.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/ask_user.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/discovery.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/helpers.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/search.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/tool_filter.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/types.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/configs/execution_agent_prompts.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/configs/summary_prompt.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/configs/sut_config.example.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/datasets/dataset_index.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/guides/scenario-package-format.md +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/chat/1.0.0/agent_eval.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/chat/1.0.0/metrics/policy.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/chat/1.0.0/prompts/chat_answer_consistency.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/chat/1.0.0/prompts/chat_answer_extract.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/chat/1.0.0/prompts/chat_answer_quality.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/chat/1.0.0/rules/chat-quality.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/chat/1.0.0/sut_configs/sasan-agent.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/chat/1.0.0/task_sets/default.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/code/1.0.0/agent_eval.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/code/1.0.0/metrics/policy.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/code/1.0.0/prompts/code_correctness.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/code/1.0.0/prompts/code_style.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/code/1.0.0/rules/code-quality.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/agent_eval.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/datasets/_defaults.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/datasets/biology.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/datasets/chemistry.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/datasets/chinese.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/datasets/geography.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/datasets/history.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/datasets/math.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/datasets/morality.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/datasets/physics.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/metrics/policy.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/chronological_order.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/content_diversity.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/content_verdict.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/depth_preference.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/fact_verdict.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/info_accuracy.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/knowledge_extract.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/knowledge_extract_constants.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/logical_consistency.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/pedagogical_logic.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/request_fulfillment.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/style_preference.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/prompts/visual_quality.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/rules/coursework-gate.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/rules/coursework-quality.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/packages/courseware/1.0.0/rules/coursework-vision.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/schemas/dataset_index_schema.json +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/schemas/dataset_schema.json +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/schemas/rule_set_schema.json +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/schemas/task_set_schema.json +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/_env_file.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/_stages.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/dataset.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/doctor.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/evaluate.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/execute.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/knowledge.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/models.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/open_url.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/pack.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/rule_set.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/runs.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/scenario.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/secrets.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/suite.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/upload.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/equiv.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/output.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/prompts.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/render.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/main.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/domains/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/domains/account.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/domains/exec.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/domains/runs.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/domains/scn.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/session.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/evaluation.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/execution.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/llm.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/llm_file.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/llm_resolution.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/loader.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/observability.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/paths.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/platform_file.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/reporting.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/core/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/core/exceptions.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/core/logging.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/core/types.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/datasets/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/datasets/downloader.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/datasets/manager.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/datasets/registry.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/base.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/capability.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/engine.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/commonsense_evaluators.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/content_completeness.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/format_evaluators.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/formula_normalizer.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/plugins/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/quality_evaluators.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/scenario/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/scenario/chat.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/scenario/code.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/vision_evaluators.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/models.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/registry.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/rule_refs.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/aggregator.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/defaults.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/expr.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/metrics.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/models.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/stage.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/summary.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/text_utils.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/vision/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/vision/renderer.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/auth/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/auth/credentials.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/auth/provider.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/auth/secrets_store.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/auth/session.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/agent_protocol.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/base.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/commands_stream.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/generic_http.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/http_steps.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/interrupts.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/message_digest.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/sse.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/thread_commands.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/models.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/task_builder.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/utils.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/auditor.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/base.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/converters/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/converters/math_reference.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/converters/periodic_table.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/converters/physics_reference.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/exceptions.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/extractors/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/extractors/llm_extractor.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/extractors/parsers.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/manager.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/merger.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/models.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/pipeline.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/registry.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/sources/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/sources/eval_sources.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/sources/math_reference.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/sources/physics_reference.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/sources/table_sources.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/client.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/factory.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/file_prompt_store.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/orchestrator.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/prompt_store.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/recorder.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/stability.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/structured_output.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/template_manager.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/models.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/pool.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/providers/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/providers/anthropic.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/providers/openai_compat.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/tracing.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/client.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/config.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/events.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/queue.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/schemas/ingest.event.v1.json +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/sink.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/snapshot.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/orchestrator/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/orchestrator/orchestrator.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/assets.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/manager.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/manifest.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/remote_client.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/store.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/reporting/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/reporting/gate.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/reporting/junit_renderer.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/reporting/report_generator.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/reporting/summary_text.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/rules/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/rules/models.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/rules/template.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/rules/validation.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/sdk/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/sdk/rules.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/storage/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/storage/builder.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/storage/collector.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/storage/package.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/storage/workspace.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/report/ruff-results.xml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/config/test_evaluation_config.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/config/test_execution_config.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/config/test_llm_config.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/config/test_reporting_config.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/conftest.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/e2e/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/e2e/test_eval_e2e.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluation/test_vision_renderer.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_cascade_metrics.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_cascade_vision_integration.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_format_and_commonsense.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_format_evaluators.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_llm_judge_evaluators.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_quality_evaluators.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_vision_evaluator.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/configs/invalid_rule_set.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/configs/rule_set.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/configs/task_set.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/golden/commonsense_error/output/index.md +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/golden/directory_sample/M1 /345/244/247/345/215/225/345/205/203/346/246/202/350/277/260//345/244/247/345/215/225/345/205/203/346/246/202/350/277/260//345/273/272/346/236/204/346/200/247/345/257/274/345/255/246//345/273/272/346/236/204/346/200/247/345/257/274/345/255/246.html" +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/golden/directory_sample/M1 /345/244/247/345/215/225/345/205/203/346/246/202/350/277/260//345/244/247/345/215/225/345/205/203/346/246/202/350/277/260//346/225/264/344/275/223/345/256/232/344/275/215//346/225/264/344/275/223/345/256/232/344/275/215.html" +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/golden/directory_sample/M2 /345/255/246/344/271/240/346/226/260/347/237/245//346/226/260/347/237/245/346/216/242/347/264/242//346/267/261/345/272/246/347/220/206/350/247/243//346/267/261/345/272/246/347/220/206/350/247/243.html" +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/golden/directory_sample/M2 /345/255/246/344/271/240/346/226/260/347/237/245//346/226/260/347/237/245/346/216/242/347/264/242//347/237/245/350/257/206/345/274/225/345/205/245//347/237/245/350/257/206/345/274/225/345/205/245.html" +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/golden/valid_docset/output/chapter_01.md +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/golden/valid_docset/output/index.md +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/metrics/policy.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/prompts/test_template.yaml +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/golden/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/integration/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/integration/test_observability_e2e.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/conftest.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_anthropic_client.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_client.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_factory.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_judge_orchestrator_vision.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_models.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_openai_compat_client.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_orchestrator.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_pool.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_prompt_store.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_recorder.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_stability.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_structured_output.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_template_manager.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_tracing.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/orchestrator/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/orchestrator/conftest.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/orchestrator/test_eval_flow.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/orchestrator/test_orchestrator.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/reporting/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/reporting/test_gate.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/reporting/test_junit_renderer.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/reporting/test_report_generator.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/reporting/test_summary_text.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/__init__.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_agent_module.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_agent_protocol_channel.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_anthropic_provider.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_briefing.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_callbacks.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_capability.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_chat_evaluators.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_console.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_dataset.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_llm_check.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_pack.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_pipeline.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_run.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_run_mode.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_secrets.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_stages.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_workbench.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_collector.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_config_loader.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_content_completeness.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_core_types.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_data_models.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_env_file.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_eval_engine.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_execution_agent.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_execution_utils.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_generic_http_channel.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_http_steps.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_interaction_policy.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_judge_coerce.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_judge_dim_details.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_knowledge_auditor.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_knowledge_manager.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_llm_config_file.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_logging.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_model_bridge.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_observability_config_client_queue.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_observability_events.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_observability_sink.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_package.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_package_assets.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_package_builder.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_package_writer.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_packages.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_pipeline_build.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_platform_file.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_plugin_discovery.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_protocol_tools.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_quality_evaluator_details.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_remote_client.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_resource_ledger.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_rule_refs.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_rule_sdk.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_scenario_aggregation.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_scenario_packaging.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_secrets.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_session.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_sink_artifacts.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_source_files_attribution.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_sut_auth.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_sut_tools.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_task_builder.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_task_selection.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_thread_commands.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_workbench_tool_filter.py +0 -0
- {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_workspace.py +0 -0
|
Binary file
|
|
@@ -85,5 +85,8 @@ web/backend/public/
|
|
|
85
85
|
# evaluator/agent_eval/assets/guides/(仓库规则优先级高于全局 excludesFile)
|
|
86
86
|
!evaluator/agent_eval/assets/guides/
|
|
87
87
|
!evaluator/agent_eval/assets/guides/*.md
|
|
88
|
+
# README / 文档引用的平台截图(部分协作者 ~/.gitignore_global 含 `*.png` 全忽略)
|
|
89
|
+
!docs/assets/
|
|
90
|
+
!docs/assets/*.png
|
|
88
91
|
*.env.local
|
|
89
92
|
|
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## v0.3.4 (2026-09-17)
|
|
2
|
+
|
|
3
|
+
### Feat
|
|
4
|
+
|
|
5
|
+
- **workbench**: 写包链路系统性修复——机械防线 + 跨进程续跑(arch/15 v4.10)
|
|
6
|
+
- **workbench**: 场景包首次确认落盘即归位 + 沙盒重定向续改
|
|
7
|
+
- **workbench**: 骨架驱动五阶段创建 + write_sut_config 机械物化
|
|
8
|
+
- **registry**: sut_config 结构白名单校验双层卡口
|
|
9
|
+
- **workbench**: 流式正文 markdown-lite 渲染 + Agent 任务清单
|
|
10
|
+
|
|
11
|
+
### Fix
|
|
12
|
+
|
|
13
|
+
- **workbench**: write_sut_config 接受裸文件名并机械归位 sut_configs/
|
|
14
|
+
- **workbench**: 登录探测 422/事件循环/超时三根因修复 + 静态 token 注入通道
|
|
15
|
+
- **cli**: auth 探测对非 JSON 响应体归一为 ProbeError,修端口被占用时裸崩
|
|
16
|
+
|
|
17
|
+
## v0.3.3 (2026-09-15)
|
|
18
|
+
|
|
19
|
+
### Fix
|
|
20
|
+
|
|
21
|
+
- **evaluator**: 观测推送队列目录随 run workspace——容器只读 CWD 吞掉整个上传
|
|
22
|
+
|
|
1
23
|
## v0.3.2 (2026-09-15)
|
|
2
24
|
|
|
3
25
|
### Feat
|
|
@@ -46,6 +46,10 @@ uv run ruff format --check agent_eval tests
|
|
|
46
46
|
uv run pytest tests/unit -q
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
## 场景包配置校验(强制)
|
|
50
|
+
|
|
51
|
+
- **手改 `sut_configs/**` 后必跑** `uv run agent-eval scenario validate <包路径>`:sut_config 以执行器 Pydantic 模型为白名单(`extra="allow"` 会**静默丢弃**未知字段),未知键校验递归覆盖 `request_template.steps[i]` 与 `steps[i].poll`;手写幻觉字段(如 GitHub Actions 风格的 `kind`/`depends_on`/`until`)不经校验会在运行时无声消失,任务集体 run_error。`SUTRegistry.load` 装载时同源复检兜底(违例 raise `SUTChannelError`)。
|
|
52
|
+
|
|
49
53
|
> 上述为快门禁(仅 `tests/unit`)。功能分支**合入前 / 发布前**跑全量 `make test`(`pytest tests/`,与 Jenkins 质量门禁同口径,含 e2e/golden 慢测试)。
|
|
50
54
|
|
|
51
55
|
## 版本发布(PyPI,distribution 名 ai-eval-scope)
|
|
@@ -76,6 +76,14 @@ __all__ = [
|
|
|
76
76
|
"run_turn",
|
|
77
77
|
]
|
|
78
78
|
|
|
79
|
+
# 任务清单纪律(注入 TodoListMiddleware 的 system_prompt,替代其过长默认版):
|
|
80
|
+
# 单一事实源在中间件(工具与纪律同源注入),域提示词资产不重复维护
|
|
81
|
+
_TODO_SYSTEM_PROMPT = (
|
|
82
|
+
"面对多步复杂任务(约 ≥3 步或跨多文件),先用 write_todos 建任务清单再动手:"
|
|
83
|
+
"每项一句话、可独立验证;保持恰好一项 in_progress;每完成一项立即把整份清单"
|
|
84
|
+
"重写更新状态;过程中发现的新子任务随时补录;简单任务(一两步)不必建清单。"
|
|
85
|
+
)
|
|
86
|
+
|
|
79
87
|
|
|
80
88
|
class WorkbenchAgent:
|
|
81
89
|
"""工作台会话 Agent(一个实例 = 一次 REPL 会话,跨轮共享历史与暂存)。
|
|
@@ -97,14 +105,20 @@ class WorkbenchAgent:
|
|
|
97
105
|
self.config = config or WorkbenchAgentConfig()
|
|
98
106
|
self.domain = domain # 域档位:选择提示词段与门禁策略
|
|
99
107
|
self.server = PackageToolServer(Path(pkg_root), ask_fn=ask_fn)
|
|
100
|
-
# SUT
|
|
108
|
+
# SUT 接入调试工具面:与文件沙盒并列;凭证域隔离到密钥区。
|
|
109
|
+
# fact_sink:探测验证成功的事实由服务端机械回填进创建骨架(五阶段流程,
|
|
110
|
+
# arch/15)——事实不经 LLM 转述,「验证过了又来一遍」从源头消失
|
|
101
111
|
self.probe = SUTProbeToolServer(
|
|
102
112
|
ask_fn=ask_fn,
|
|
103
113
|
credential_store=CredentialStore(),
|
|
104
114
|
budgets=self.config.probe_budgets,
|
|
105
115
|
timeout_s=self.config.probe_timeout_s,
|
|
106
116
|
log_path=None, # 探测证据随 agent_logs 统一落盘,见 _log_path
|
|
117
|
+
fact_sink=self.server.append_skeleton_fact,
|
|
107
118
|
)
|
|
119
|
+
# 机械物化通道:write_sut_config 从探测账本原样注入 auth(两 server 构造
|
|
120
|
+
# 互需对方能力,probe 先带 fact_sink 装配,账本在此回绑包沙盒)
|
|
121
|
+
self.server.ledger = self.probe
|
|
108
122
|
self.llm_role = llm_role
|
|
109
123
|
self._messages: list[Any] = []
|
|
110
124
|
# 预算护栏会话级累计(跨段/跨轮不清零);内存检查点仅作事故现场保存器
|
|
@@ -118,6 +132,23 @@ class WorkbenchAgent:
|
|
|
118
132
|
paths.default_workspace / "agent_sessions" / session_key(Path(pkg_root)),
|
|
119
133
|
max_entries=self.config.max_dialogue_entries,
|
|
120
134
|
)
|
|
135
|
+
# 进度恢复(跨进程续作,v4.10):上次会话的暂存 + 骨架留档 + 证据账本
|
|
136
|
+
# 随会话记录持久化,重启即恢复——五阶段流程的中间进度不再「跨进程蒸发」
|
|
137
|
+
# (实测事故:代理超时后建议用户重启续作,暂存与账本实际全丢)。账本
|
|
138
|
+
# 独立于暂存恢复:已落盘包的续改会话同样免重探
|
|
139
|
+
restored = self.server.import_staging_snapshot(self._session_store.last_snapshot)
|
|
140
|
+
ledger_payload = (self._session_store.last_snapshot or {}).get("ledger")
|
|
141
|
+
restored_logins = self.probe.restore_ledgers(ledger_payload)
|
|
142
|
+
protocols = (
|
|
143
|
+
len(ledger_payload.get("verified_protocols", {}))
|
|
144
|
+
if isinstance(ledger_payload, dict)
|
|
145
|
+
else 0
|
|
146
|
+
)
|
|
147
|
+
self.restored_progress = {
|
|
148
|
+
"staged": restored,
|
|
149
|
+
"logins": restored_logins,
|
|
150
|
+
"protocols": protocols,
|
|
151
|
+
}
|
|
121
152
|
self._graph: Any | None = None
|
|
122
153
|
self._log_path = (
|
|
123
154
|
log_dir
|
|
@@ -139,9 +170,56 @@ class WorkbenchAgent:
|
|
|
139
170
|
"""已续接的此前会话对话条数(0 = 全新会话),宿主据此显示续作提示。"""
|
|
140
171
|
return len(self._session_store.dialogue)
|
|
141
172
|
|
|
173
|
+
def _progress_snapshot(self) -> dict[str, Any]:
|
|
174
|
+
"""组装进度快照(暂存 + 骨架留档 + 证据账本,仅事实数据无凭证值)。"""
|
|
175
|
+
return {
|
|
176
|
+
**self.server.export_staging_snapshot(),
|
|
177
|
+
"ledger": self.probe.ledger_snapshot(),
|
|
178
|
+
}
|
|
179
|
+
|
|
142
180
|
def _record_turn(self, user_text: str, reply: str) -> None:
|
|
143
181
|
"""记录本轮对话要点并持久化(仅 user/assistant 文本,不含工具流量)。"""
|
|
144
|
-
self._session_store.record(
|
|
182
|
+
self._session_store.record(
|
|
183
|
+
user_text, reply, str(self.server.root), snapshot=self._progress_snapshot()
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
def relocate_root(self, final_root: Path) -> None:
|
|
187
|
+
"""包归位后重绑沙盒根:server 重定向 + 提示词重建 + 会话记录迁移。
|
|
188
|
+
|
|
189
|
+
首次确认落盘即归位(v4.9)后由宿主调用——同一会话的后续轮次直接自然语言
|
|
190
|
+
修改已归位的包。图在下一次 ``_invoke`` 时重建(系统提示的 ``{pkg_root}`` 在
|
|
191
|
+
建图时烘焙;对话消息由宿主持有,重建不丢上下文)。会话记录文件迁移到新
|
|
192
|
+
session_key——归位后跨进程续作(``--output`` 指回)命中同一记录,上下文不
|
|
193
|
+
因归位断裂。文件迁移失败仅丢跨进程续作(key 仍切换,后续记录落新位),
|
|
194
|
+
会话内不受影响。
|
|
195
|
+
"""
|
|
196
|
+
final = Path(final_root).resolve()
|
|
197
|
+
previous = self.server.root
|
|
198
|
+
if final == previous:
|
|
199
|
+
return
|
|
200
|
+
old_file = self._session_store.session_file
|
|
201
|
+
self.server.rebind_root(final)
|
|
202
|
+
self._graph = None # 系统提示烘焙了 {pkg_root}——下次调用重建
|
|
203
|
+
new_file = old_file.parent / session_key(final)
|
|
204
|
+
try:
|
|
205
|
+
if old_file.exists():
|
|
206
|
+
old_file.replace(new_file)
|
|
207
|
+
skeleton = old_file.with_suffix(".SKELETON.md")
|
|
208
|
+
if skeleton.exists():
|
|
209
|
+
skeleton.replace(new_file.with_suffix(".SKELETON.md"))
|
|
210
|
+
except OSError:
|
|
211
|
+
pass # 迁移失败仅影响跨进程续作;key 仍切换,后续记录落新位
|
|
212
|
+
self._session_store.session_file = new_file
|
|
213
|
+
self._log("relocate_root", previous=str(previous), final=str(final))
|
|
214
|
+
# 归位事实进对话(沙盒根变了,Agent 须知道以新位置为准)——同放弃回滚的
|
|
215
|
+
# 系统注记形态,防 Agent 仍引用旧草稿路径
|
|
216
|
+
self._messages.append(
|
|
217
|
+
(
|
|
218
|
+
"user",
|
|
219
|
+
f"(包已归位:沙盒根从 {previous} 迁移到 {final},包内容不变。"
|
|
220
|
+
"此后的文件读写、校验、落盘以新位置为准)",
|
|
221
|
+
)
|
|
222
|
+
)
|
|
145
223
|
|
|
146
224
|
# ─── 组装 ─────────────────────────────────────────────────────
|
|
147
225
|
|
|
@@ -179,13 +257,24 @@ class WorkbenchAgent:
|
|
|
179
257
|
"WorkbenchAgent 需要 deepagents(DeepAgents 底座)。请执行: uv sync --extra agent",
|
|
180
258
|
details={"missing_module": "deepagents"},
|
|
181
259
|
) from None
|
|
260
|
+
from langchain.agents.middleware import TodoListMiddleware
|
|
182
261
|
from langgraph.checkpoint.memory import MemorySaver
|
|
183
262
|
|
|
184
263
|
from agent_eval.agent.core.model_bridge import build_chat_model
|
|
185
264
|
|
|
186
265
|
# 内存检查点无 IO、实例销毁即释放(不用文件版检查器:全量读写空转)
|
|
187
266
|
self._checkpointer = MemorySaver()
|
|
188
|
-
|
|
267
|
+
# 任务清单中间件(Claude Code TodoWrite 同款语义):复杂任务先拆解再逐步
|
|
268
|
+
# 执行;todos 走 langgraph state + 检查点,跨段续跑 / 会话续作自然保留。
|
|
269
|
+
# deepagents 默认栈不含它(其默认 system_prompt 过长,见 deepagents
|
|
270
|
+
# graph.py 注释)——此处传精简版;其注入的 write_todos 必须并入工具面
|
|
271
|
+
# 白名单,否则被下方 ToolsetFilter 复位过滤掉(按实例 id 过滤)
|
|
272
|
+
todo_mw = TodoListMiddleware(system_prompt=_TODO_SYSTEM_PROMPT)
|
|
273
|
+
tools = [
|
|
274
|
+
*self.server.to_langchain_tools(),
|
|
275
|
+
*self.probe.to_langchain_tools(),
|
|
276
|
+
*todo_mw.tools,
|
|
277
|
+
]
|
|
189
278
|
return create_deep_agent(
|
|
190
279
|
model=build_chat_model(self.llm_role),
|
|
191
280
|
tools=tools,
|
|
@@ -194,7 +283,7 @@ class WorkbenchAgent:
|
|
|
194
283
|
# 复位模型可见工具面 = 宿主装配清单:deepagents 内置 ls/glob 跑
|
|
195
284
|
# StateBackend 虚拟 FS(与磁盘无关),曾致「没有场景包」误判
|
|
196
285
|
# (arch/15 v4.4;为何不用全局 harness profile 见 tool_filter 模块注释)
|
|
197
|
-
middleware=[build_toolset_filter(tools)],
|
|
286
|
+
middleware=[build_toolset_filter(tools), todo_mw],
|
|
198
287
|
)
|
|
199
288
|
|
|
200
289
|
# ─── 会话(宿主循环调用) ──────────────────────────────────────
|
|
@@ -221,6 +310,22 @@ class WorkbenchAgent:
|
|
|
221
310
|
self.probe.new_turn() # 重置 SUT 探测轮内预算(轮内总量约束)
|
|
222
311
|
if not self._messages and self._dialogue: # 跨进程续作:注入此前对话要点
|
|
223
312
|
self._messages.extend(_resume_messages(self._dialogue, self.config))
|
|
313
|
+
# 进度恢复注记(v4.10):暂存与证据账本已在 __init__ 恢复——Agent 须
|
|
314
|
+
# 知道进度在手上,勿从头重探/重写(实测事故:重启续作把全部进度重做)
|
|
315
|
+
prog = self.restored_progress
|
|
316
|
+
if prog["staged"] or prog["logins"] or prog["protocols"]:
|
|
317
|
+
parts = [f"暂存 {prog['staged']} 个文件"] if prog["staged"] else []
|
|
318
|
+
if prog["logins"]:
|
|
319
|
+
parts.append(f"已验证登录 {prog['logins']} 项")
|
|
320
|
+
if prog["protocols"]:
|
|
321
|
+
parts.append(f"已验证协议 {prog['protocols']} 项")
|
|
322
|
+
self._messages.append(
|
|
323
|
+
(
|
|
324
|
+
"user",
|
|
325
|
+
f"(已恢复上次会话进度:{'、'.join(parts)}"
|
|
326
|
+
"——这些已写内容与已验证事实均有效,无需重新探测或重写,直接继续)",
|
|
327
|
+
)
|
|
328
|
+
)
|
|
224
329
|
self._messages.append(("user", user_text))
|
|
225
330
|
segment = 1
|
|
226
331
|
while True: # 自动分段续跑:同一对话/预算池/暂存,撞线开新段
|
|
@@ -338,6 +443,7 @@ class WorkbenchAgent:
|
|
|
338
443
|
errors = [*validation["errors"], *sut_evidence_gate(self.server, self.probe)]
|
|
339
444
|
if not errors:
|
|
340
445
|
files = self.server.commit()
|
|
446
|
+
self._archive_skeleton()
|
|
341
447
|
self._log("commit", files=files)
|
|
342
448
|
return {"committed": True, "files": files}
|
|
343
449
|
self._log("validate_failed", round=round_no, errors=errors)
|
|
@@ -355,6 +461,22 @@ class WorkbenchAgent:
|
|
|
355
461
|
self._messages = list(state.get("messages", self._messages))
|
|
356
462
|
return {"committed": False, "errors": ["校验轮次耗尽"], "reason": "max_fix_rounds"}
|
|
357
463
|
|
|
464
|
+
def _archive_skeleton(self) -> None:
|
|
465
|
+
"""创建骨架归档为审计产物(过程事实与证据链不入包,但留档可查)。
|
|
466
|
+
|
|
467
|
+
落会话记录同目录(按包根摘要命名,不与其它包撞):包目录是源资产、会话
|
|
468
|
+
结束要归位 cwd,过程产物跟进会污染包;写失败不影响提交(同 _log 容错)。
|
|
469
|
+
"""
|
|
470
|
+
text = self.server.skeleton_archive
|
|
471
|
+
if not text:
|
|
472
|
+
return
|
|
473
|
+
try:
|
|
474
|
+
dest = self._session_store.session_file.with_suffix(".SKELETON.md")
|
|
475
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
476
|
+
dest.write_text(text, encoding="utf-8")
|
|
477
|
+
except OSError:
|
|
478
|
+
pass # 归档失败不影响提交
|
|
479
|
+
|
|
358
480
|
async def _invoke(
|
|
359
481
|
self,
|
|
360
482
|
messages: list[Any],
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import json
|
|
6
6
|
import time
|
|
7
7
|
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
8
9
|
|
|
9
10
|
from agent_eval.agent.workbench.types import WorkbenchAgentConfig
|
|
10
11
|
|
|
@@ -30,29 +31,44 @@ class SessionStore:
|
|
|
30
31
|
def __init__(self, session_file: Path, *, max_entries: int) -> None:
|
|
31
32
|
self.session_file = session_file
|
|
32
33
|
self.max_entries = max_entries
|
|
34
|
+
self.last_snapshot: dict[str, Any] | None = None
|
|
33
35
|
self.dialogue = self._load()
|
|
34
36
|
|
|
35
37
|
def _load(self) -> list[dict[str, str]]:
|
|
38
|
+
self.last_snapshot = None
|
|
36
39
|
try:
|
|
37
40
|
data = json.loads(self.session_file.read_text(encoding="utf-8"))
|
|
38
41
|
dialogue = data.get("dialogue", [])
|
|
42
|
+
snapshot = data.get("snapshot")
|
|
43
|
+
if isinstance(snapshot, dict):
|
|
44
|
+
self.last_snapshot = snapshot
|
|
39
45
|
except (OSError, ValueError):
|
|
40
46
|
return []
|
|
41
47
|
return [d for d in dialogue if isinstance(d, dict) and d.get("role") and d.get("text")]
|
|
42
48
|
|
|
43
|
-
def record(
|
|
44
|
-
|
|
49
|
+
def record(
|
|
50
|
+
self, user_text: str, reply: str, root: str, *, snapshot: dict[str, Any] | None = None
|
|
51
|
+
) -> None:
|
|
52
|
+
"""追加本轮对话要点并落盘(超出上限从头部丢弃)。
|
|
53
|
+
|
|
54
|
+
``snapshot`` 为当前进度快照(暂存 + 骨架留档 + 证据账本,调用方组装),
|
|
55
|
+
每轮整体覆写——快照即「当前进度态」而非历史,重启据此续作不丢进度。
|
|
56
|
+
"""
|
|
45
57
|
self.dialogue.append({"role": "user", "text": user_text})
|
|
46
58
|
if reply:
|
|
47
59
|
self.dialogue.append({"role": "assistant", "text": reply})
|
|
48
60
|
self.dialogue = self.dialogue[-self.max_entries :]
|
|
61
|
+
if snapshot is not None:
|
|
62
|
+
self.last_snapshot = snapshot
|
|
49
63
|
try:
|
|
50
64
|
self.session_file.parent.mkdir(parents=True, exist_ok=True)
|
|
51
|
-
payload = {
|
|
65
|
+
payload: dict[str, Any] = {
|
|
52
66
|
"root": root,
|
|
53
67
|
"updated": time.strftime("%Y-%m-%dT%H:%M:%S"),
|
|
54
68
|
"dialogue": self.dialogue,
|
|
55
69
|
}
|
|
70
|
+
if self.last_snapshot is not None:
|
|
71
|
+
payload["snapshot"] = self.last_snapshot
|
|
56
72
|
self.session_file.write_text(
|
|
57
73
|
json.dumps(payload, ensure_ascii=False, indent=1), encoding="utf-8"
|
|
58
74
|
)
|
|
@@ -113,6 +113,24 @@ def emit_tool_events(updates: dict[str, Any], emit: Callable[[dict[str, Any]], N
|
|
|
113
113
|
)
|
|
114
114
|
|
|
115
115
|
|
|
116
|
+
def _todo_items(raw: Any) -> list[dict[str, str]]:
|
|
117
|
+
"""todos 状态 → 规范化清单(dict / Todo TypedDict 兼容,缺字段补空串)。"""
|
|
118
|
+
items: list[dict[str, str]] = []
|
|
119
|
+
for todo in raw or []:
|
|
120
|
+
if isinstance(todo, dict):
|
|
121
|
+
items.append(
|
|
122
|
+
{"content": str(todo.get("content", "")), "status": str(todo.get("status", ""))}
|
|
123
|
+
)
|
|
124
|
+
else:
|
|
125
|
+
items.append(
|
|
126
|
+
{
|
|
127
|
+
"content": str(getattr(todo, "content", "")),
|
|
128
|
+
"status": str(getattr(todo, "status", "")),
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
return items
|
|
132
|
+
|
|
133
|
+
|
|
116
134
|
async def stream_collect(
|
|
117
135
|
graph: Any,
|
|
118
136
|
messages: list[Any],
|
|
@@ -159,6 +177,16 @@ async def stream_collect(
|
|
|
159
177
|
elif block.get("type") == "thinking" and block.get("thinking"):
|
|
160
178
|
on_event({"type": "thinking", "text": str(block["thinking"])})
|
|
161
179
|
elif mode == "updates" and payload:
|
|
180
|
+
# write_todos 落状态的增量(TodoListMiddleware 维护的 todos 键)——
|
|
181
|
+
# 提取成独立事件交宿主渲染任务清单;无该键(普通工具增量)不受影响
|
|
182
|
+
for delta in payload.values():
|
|
183
|
+
if isinstance(delta, dict) and "todos" in delta:
|
|
184
|
+
on_event(
|
|
185
|
+
{
|
|
186
|
+
"type": "todos",
|
|
187
|
+
"todos": _todo_items(delta.get("todos") or []),
|
|
188
|
+
}
|
|
189
|
+
)
|
|
162
190
|
emit_tool_events(payload, on_event)
|
|
163
191
|
elif mode == "values" and isinstance(payload, dict):
|
|
164
192
|
final = payload
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
- **总量约束**:单探测 10s 超时、轮内预算按工具分池、发现阶梯路径清单 ≤10。
|
|
13
13
|
|
|
14
14
|
状态全部公开名(各域工具类经 ``ctx`` 跨模块协作——下划线私有名跨模块引用是
|
|
15
|
-
反模式);唯 ``_client_instance`` 为懒建句柄私有。
|
|
15
|
+
反模式);唯 ``_client_instance``/``_client_loop`` 为懒建句柄私有。
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
+
import asyncio
|
|
20
21
|
import json
|
|
21
22
|
import time
|
|
22
23
|
from pathlib import Path
|
|
@@ -44,6 +45,7 @@ class ProbeContext:
|
|
|
44
45
|
http_client_factory: Any = None,
|
|
45
46
|
budgets: dict[str, int] | None = None, # 轮内预算按工具分池(缺省 TOOL_BUDGETS)
|
|
46
47
|
timeout_s: float = PROBE_TIMEOUT_S,
|
|
48
|
+
fact_sink: Any = None, # (fact_line: str) -> None——验证事实机械回填骨架
|
|
47
49
|
) -> None:
|
|
48
50
|
self.allowed_hosts = {h.lower() for h in (allowed_hosts or {})}
|
|
49
51
|
# 拒绝拉黑账本(与 workbench_tools._ensure_grant 的 _denied 同款):被拒
|
|
@@ -55,6 +57,9 @@ class ProbeContext:
|
|
|
55
57
|
self.http_client_factory = http_client_factory
|
|
56
58
|
self.budgets = dict(budgets) if budgets is not None else dict(TOOL_BUDGETS)
|
|
57
59
|
self.timeout_s = timeout_s
|
|
60
|
+
# 验证事实机械回填骨架的出口(装配壳注入,本包不反向依赖 workbench 文件
|
|
61
|
+
# 沙盒)——探测成功的事实行由此直达 SKELETON.md,不经 LLM 转述
|
|
62
|
+
self.fact_sink = fact_sink
|
|
58
63
|
self.turn_calls: dict[str, int] = {}
|
|
59
64
|
# 抓取缓存(url → 完整内容):前端包分析的存储侧,会话内跨轮有效
|
|
60
65
|
# (预算按轮重置但分析状态不丢——新轮可直接检索续查)
|
|
@@ -83,8 +88,11 @@ class ProbeContext:
|
|
|
83
88
|
# {{ stepN.路径 }} 引用其值(值服务端流动,不经对话)
|
|
84
89
|
self.step_responses: dict[str, Any] = {}
|
|
85
90
|
# 会话级共享 AsyncClient(与执行器 channels/base.py 同构:连接池 +
|
|
86
|
-
# cookie jar——cookie 型凭证与会话粘性靠它),会话结束 aclose()
|
|
91
|
+
# cookie jar——cookie 型凭证与会话粘性靠它),会话结束 aclose()。
|
|
92
|
+
# _client_loop 记录建实例时的事件循环:REPL 每轮 asyncio.run 换循环,
|
|
93
|
+
# client() 据此废弃绑死旧循环的实例(Event loop is closed 实测事故)
|
|
87
94
|
self._client_instance: Any = None
|
|
95
|
+
self._client_loop: Any = None
|
|
88
96
|
|
|
89
97
|
# ── 会话挂点与日志 ────────────────────────────────────────────
|
|
90
98
|
|
|
@@ -117,6 +125,19 @@ class ProbeContext:
|
|
|
117
125
|
self.verified_protocols[host.lower()] = {"flavor": flavor, "steps": steps}
|
|
118
126
|
self.log("protocol_probed", host=host, flavor=flavor, steps=steps)
|
|
119
127
|
|
|
128
|
+
def emit_fact(self, fact_line: str) -> None:
|
|
129
|
+
"""验证成功的事实机械回填创建骨架(fact_sink 注入;失败不阻断探测结论)。
|
|
130
|
+
|
|
131
|
+
五阶段创建流程(arch/15)的「进度即回填骨架」:事实行由探测工具服务端
|
|
132
|
+
写就,落 SKELETON.md「机械实测事实」节,Agent 据此闭合对应开槽。
|
|
133
|
+
"""
|
|
134
|
+
if self.fact_sink is None:
|
|
135
|
+
return
|
|
136
|
+
try:
|
|
137
|
+
self.fact_sink(fact_line)
|
|
138
|
+
except Exception: # noqa: BLE001 — 回填失败不影响账本与工具返回(事实已登记)
|
|
139
|
+
self.log("fact_sink_error", fact=fact_line[:120])
|
|
140
|
+
|
|
120
141
|
def verified_login(self, ref: str) -> dict[str, str] | None:
|
|
121
142
|
"""查登录实测事实(落盘对账门禁用)。"""
|
|
122
143
|
return self.verified_logins.get(ref.lower())
|
|
@@ -125,6 +146,40 @@ class ProbeContext:
|
|
|
125
146
|
"""查协议矩阵事实(落盘对账门禁用)。"""
|
|
126
147
|
return self.verified_protocols.get(host.lower())
|
|
127
148
|
|
|
149
|
+
# ── 证据账本跨进程续作(快照/恢复,与 record_* 对称) ─────────
|
|
150
|
+
|
|
151
|
+
def ledger_snapshot(self) -> dict[str, Any]:
|
|
152
|
+
"""导出证据账本(纯事实数据,随 SessionStore 每轮持久化)。
|
|
153
|
+
|
|
154
|
+
红线:只含实测事实(url/body_template/auth_snippet 均为 credential_ref
|
|
155
|
+
占位形态)——session_tokens / credential_grants / last_credential_request
|
|
156
|
+
等凭证态绝不入快照。
|
|
157
|
+
"""
|
|
158
|
+
return {
|
|
159
|
+
"verified_logins": self.verified_logins,
|
|
160
|
+
"verified_protocols": self.verified_protocols,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
def restore_ledgers(self, verified_logins: Any, verified_protocols: Any) -> int:
|
|
164
|
+
"""恢复账本(类型容错:非 dict 静默置空),返回恢复的登录事实条数。
|
|
165
|
+
|
|
166
|
+
会话凭证(session_tokens)不恢复——重启后重新 declare_token 才有值;
|
|
167
|
+
账本恢复的意义是 write_sut_config 免重探 + 门禁对账有事实源。
|
|
168
|
+
"""
|
|
169
|
+
if isinstance(verified_logins, dict):
|
|
170
|
+
self.verified_logins = {
|
|
171
|
+
ref: fact
|
|
172
|
+
for ref, fact in verified_logins.items()
|
|
173
|
+
if isinstance(ref, str) and isinstance(fact, dict)
|
|
174
|
+
}
|
|
175
|
+
if isinstance(verified_protocols, dict):
|
|
176
|
+
self.verified_protocols = {
|
|
177
|
+
host: fact
|
|
178
|
+
for host, fact in verified_protocols.items()
|
|
179
|
+
if isinstance(host, str) and isinstance(fact, dict)
|
|
180
|
+
}
|
|
181
|
+
return len(self.verified_logins)
|
|
182
|
+
|
|
128
183
|
@property
|
|
129
184
|
def login_hosts(self) -> set[str]:
|
|
130
185
|
"""本会话登录实测成功过的接口域(小写)——协议探测的候选证据源。"""
|
|
@@ -240,22 +295,42 @@ class ProbeContext:
|
|
|
240
295
|
# ── 会话级共享 client ────────────────────────────────────────
|
|
241
296
|
|
|
242
297
|
async def client(self) -> Any:
|
|
243
|
-
"""会话级共享 AsyncClient
|
|
298
|
+
"""会话级共享 AsyncClient(懒建,绑定创建时的事件循环)。
|
|
244
299
|
|
|
245
300
|
与执行器通道同构(channels/base.py):登录态 cookie、会话粘性都靠共享
|
|
246
301
|
client 的 jar——每请求新建 client 丢 cookie 的宽度裂缝在此消灭。
|
|
247
|
-
会话结束经 aclose() 释放。
|
|
302
|
+
会话结束经 aclose() 释放。WorkbenchAgent 每用户轮经 asyncio.run 新建
|
|
303
|
+
事件循环(agent.py),旧 client 的连接池绑定已关闭的循环——跨轮复用的
|
|
304
|
+
首个请求即 ``RuntimeError: Event loop is closed``(实测事故:暂停恢复/
|
|
305
|
+
新指令后的轮首必炸,偶发性取决于池中是否有存活连接)。故取用时校验
|
|
306
|
+
循环一致性:不一致即废弃旧实例换新,cookie jar 同步搬运(纯数据可跨
|
|
307
|
+
循环转移——cookie 型凭证与会话粘性跨轮不丢),旧实例交 GC 回收。
|
|
248
308
|
"""
|
|
249
|
-
|
|
309
|
+
loop = asyncio.get_running_loop()
|
|
310
|
+
cached = self._client_instance
|
|
311
|
+
stale = cached is not None and self._client_loop is not loop
|
|
312
|
+
if stale:
|
|
313
|
+
self._client_instance = None
|
|
314
|
+
if cached is None or stale:
|
|
250
315
|
if self.http_client_factory is not None:
|
|
251
|
-
|
|
316
|
+
new_client = self.http_client_factory()
|
|
252
317
|
else:
|
|
253
318
|
import httpx
|
|
254
319
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
320
|
+
new_client = httpx.AsyncClient(timeout=self.timeout_s, follow_redirects=False)
|
|
321
|
+
if stale:
|
|
322
|
+
# 跨轮废弃旧实例:旧 jar 搬进新实例(cookie 型凭证与会话粘性
|
|
323
|
+
# 跨轮不丢;非 httpx 形态的测试替身无 cookies 属性,静默跳过)
|
|
324
|
+
old_jar = getattr(cached, "cookies", None)
|
|
325
|
+
if old_jar is not None:
|
|
326
|
+
try:
|
|
327
|
+
new_client.cookies.update(old_jar)
|
|
328
|
+
except Exception: # noqa: BLE001 — jar 形态不兼容时宁缺勿错
|
|
329
|
+
pass
|
|
330
|
+
cached = new_client
|
|
331
|
+
self._client_instance = cached
|
|
332
|
+
self._client_loop = loop
|
|
333
|
+
return cached
|
|
259
334
|
|
|
260
335
|
def borrow_client(self) -> Any:
|
|
261
336
|
"""``async with`` 形态借用共享 client(退出时不关闭——归会话统一释放)。
|
|
@@ -279,3 +354,4 @@ class ProbeContext:
|
|
|
279
354
|
except Exception: # noqa: BLE001 — 释放失败不阻断收尾
|
|
280
355
|
pass
|
|
281
356
|
self._client_instance = None
|
|
357
|
+
self._client_loop = None
|
{ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/protocol.py
RENAMED
|
@@ -244,6 +244,18 @@ class ProtocolTool:
|
|
|
244
244
|
flavor,
|
|
245
245
|
{m["step"]: m["ok"] for m in matrix if m["step"] != "skipped"},
|
|
246
246
|
)
|
|
247
|
+
# 骨架机械回填:协议矩阵结论(正反都是事实——「探测过但未支持」同样是
|
|
248
|
+
# channel 决策的关闭证据)由服务端写进 SKELETON.md,不经 LLM 转述
|
|
249
|
+
verdict = (
|
|
250
|
+
f"核心端点 {core} ✅(可声明 channel: agent_protocol)"
|
|
251
|
+
if core_ok
|
|
252
|
+
else f"核心端点 {core} ❌(不支持 agent_protocol 的实测证据——改走其他"
|
|
253
|
+
"通道须先经用户确认)"
|
|
254
|
+
)
|
|
255
|
+
self.ctx.emit_fact(
|
|
256
|
+
f"事实槽:协议矩阵 {host} flavor={flavor},{verdict}"
|
|
257
|
+
f"(证据:probe_protocol 实测 {len(matrix)} 个端点)"
|
|
258
|
+
)
|
|
247
259
|
self.ctx.log("probe_protocol", base_url=base_url, steps=len(matrix))
|
|
248
260
|
result: dict[str, Any] = {
|
|
249
261
|
"matrix": matrix,
|
|
@@ -161,8 +161,14 @@ class RequestTool:
|
|
|
161
161
|
)
|
|
162
162
|
}
|
|
163
163
|
rendered_body = rendered_map["0"]
|
|
164
|
-
# 渲染值必须压过 req_headers 的模板原文(原文含 {{ 变量 }}
|
|
165
|
-
|
|
164
|
+
# 渲染值必须压过 req_headers 的模板原文(原文含 {{ 变量 }},直发即泄漏)。
|
|
165
|
+
# 模板源是整行 "Key: Value"(渲染可落在行内任意位置),回填前须再切出
|
|
166
|
+
# 值——直接整行回填会把 wire 头发成 "Key: Key: Value"(实测事故:显式
|
|
167
|
+
# Content-Type 因此从未真正生效,FastAPI 靠子串匹配侥幸解析 JSON)
|
|
168
|
+
rendered_headers: dict[str, str] = {}
|
|
169
|
+
for i, name in enumerate(header_names):
|
|
170
|
+
_, _, rendered_value = rendered_map[str(i + 1)].partition(":")
|
|
171
|
+
rendered_headers[name] = rendered_value.strip()
|
|
166
172
|
cred_in_headers = any(f in h for h in raw_headers for f in cred_fields)
|
|
167
173
|
if residual := _UNRENDERED_PLACEHOLDER_RE.findall(rendered_body):
|
|
168
174
|
return {
|
|
@@ -176,8 +182,10 @@ class RequestTool:
|
|
|
176
182
|
# 含 " / \ 破坏模板拼接,SUT 都只回一句 422——把我方参数变形伪装成「后端
|
|
177
183
|
# 格式不明」,实测烧掉整轮探测预算(jxb-server 422 误诊事故)。与占位符
|
|
178
184
|
# 守卫同哲学:凡可机械判定的变形不发给 SUT 让 Agent 瞎猜。显式非 JSON
|
|
179
|
-
# Content-Type
|
|
185
|
+
# Content-Type 的 JSON 对象 body 走下方机械归一化(标签修正);原始
|
|
186
|
+
# 标量/非 JSON 报文探测不适用本校验;数组 body 合法放行
|
|
180
187
|
content_type = next((v for k, v in req_headers.items() if k.lower() == "content-type"), "")
|
|
188
|
+
content_type_normalized = ""
|
|
181
189
|
if rendered_body and "json" in content_type.lower():
|
|
182
190
|
try:
|
|
183
191
|
parsed_body = json.loads(rendered_body)
|
|
@@ -198,6 +206,25 @@ class RequestTool:
|
|
|
198
206
|
"外层引号层以单层对象形态重传;body 直接传 dict 参数会机械序列化"
|
|
199
207
|
)
|
|
200
208
|
}
|
|
209
|
+
elif rendered_body and content_type:
|
|
210
|
+
# 显式非 JSON Content-Type 会同时旁路上面的 auto 补齐与双重编码门禁:
|
|
211
|
+
# 实测事故(jxb-server 422 误诊)——正确的 JSON 报文顶着 text/plain/
|
|
212
|
+
# form-urlencoded 标签上 wire,FastAPI 不做 JSON 解析,Pydantic 把
|
|
213
|
+
# body 原文当字符串校验回 422 model_attributes_type(input 回显原文
|
|
214
|
+
# 带引号,形似双重编码),LLM「换格式重试」烧光探测预算。body 实为
|
|
215
|
+
# JSON 对象/数组时机械归一化标签(凡可机械归一的变形不经 LLM 转述);
|
|
216
|
+
# 标量/非 JSON 的原始报文探测原样放行
|
|
217
|
+
try:
|
|
218
|
+
raw_parsed = json.loads(rendered_body)
|
|
219
|
+
except ValueError:
|
|
220
|
+
raw_parsed = None
|
|
221
|
+
if isinstance(raw_parsed, (dict, list)):
|
|
222
|
+
ct_key = next(k for k in req_headers if k.lower() == "content-type")
|
|
223
|
+
req_headers[ct_key] = "application/json"
|
|
224
|
+
if ct_key in rendered_headers:
|
|
225
|
+
rendered_headers[ct_key] = "application/json"
|
|
226
|
+
content_type_normalized = content_type
|
|
227
|
+
self.ctx.log("request", event="content_type_normalized", original=content_type)
|
|
201
228
|
# 凭证注入请求的门禁面(非凭证请求只过 host 门禁)
|
|
202
229
|
if cred_fields:
|
|
203
230
|
if not ref.strip():
|
|
@@ -244,8 +271,17 @@ class RequestTool:
|
|
|
244
271
|
content=rendered_body.encode() if rendered_body else None,
|
|
245
272
|
)
|
|
246
273
|
except Exception as e: # noqa: BLE001 — 网络面异常统一转错误数据
|
|
247
|
-
|
|
248
|
-
|
|
274
|
+
err = net_err(e)
|
|
275
|
+
if "timeout" in err.lower():
|
|
276
|
+
# 实测事故:本机代理(http_proxy→Clash)把 0.3s 的请求拖到 11.7s,
|
|
277
|
+
# 顶爆 10s 探测超时,Agent 误判「服务不可用」转向换格式瞎试。
|
|
278
|
+
# SUT 可能在内网须走用户代理,工具不擅改 trust_env——指引自查
|
|
279
|
+
err += (
|
|
280
|
+
"(超时常见于本机代理劫持:http_proxy/https_proxy 经 Clash 等代理会"
|
|
281
|
+
"把 10s 探测超时顶爆——为 SUT 域配置 NO_PROXY 直连或临时 unset 代理后重试)"
|
|
282
|
+
)
|
|
283
|
+
self.ctx.log("request", method=verb, url=url, event="failed", error=err[:200])
|
|
284
|
+
return {"status": 0, "error": f"请求失败: {err}"}
|
|
249
285
|
elapsed_ms = round((time.monotonic() - started) * 1000)
|
|
250
286
|
status = response.status_code
|
|
251
287
|
# 防锁红线(认证层拒绝语义):带凭证组合被 4xx/5xx 拒绝即入锁不自动重发;
|
|
@@ -283,7 +319,7 @@ class RequestTool:
|
|
|
283
319
|
},
|
|
284
320
|
}
|
|
285
321
|
self.ctx.log("request", method=verb, url=url, status=status, ref=ref, step=step)
|
|
286
|
-
|
|
322
|
+
result = structure_response(
|
|
287
323
|
self.ctx,
|
|
288
324
|
verb,
|
|
289
325
|
url,
|
|
@@ -293,3 +329,9 @@ class RequestTool:
|
|
|
293
329
|
credentialed=bool(cred_fields),
|
|
294
330
|
ref=ref.lower(),
|
|
295
331
|
)
|
|
332
|
+
if content_type_normalized:
|
|
333
|
+
result["content_type_normalized"] = (
|
|
334
|
+
f"{content_type_normalized} → application/json(body 实为 JSON 对象,"
|
|
335
|
+
"标签已机械归一化——422 若再现与此无关)"
|
|
336
|
+
)
|
|
337
|
+
return result
|