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.
Files changed (410) hide show
  1. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/.coverage +0 -0
  2. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/.gitignore +3 -0
  3. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/CHANGELOG.md +22 -0
  4. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/CLAUDE.md +4 -0
  5. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/PKG-INFO +1 -1
  6. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/__init__.py +1 -1
  7. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/agent.py +126 -4
  8. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/memory.py +19 -3
  9. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/messages.py +28 -0
  10. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/context.py +86 -10
  11. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/protocol.py +12 -0
  12. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/request.py +48 -6
  13. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/response.py +4 -2
  14. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/server.py +22 -1
  15. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/specs.py +7 -2
  16. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/tokens.py +59 -0
  17. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/tools.py +251 -13
  18. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/configs/workbench_agent_prompts.yaml +93 -49
  19. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/_common.py +8 -5
  20. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/auth.py +11 -2
  21. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/workbench_agent.py +95 -49
  22. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/agent_stream.py +111 -3
  23. ai_eval_scope-0.3.4/agent_eval/cli/console/markdown_lite.py +122 -0
  24. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/registry.py +37 -1
  25. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/pyproject.toml +1 -1
  26. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/report/mypy-results.xml +2 -2
  27. ai_eval_scope-0.3.4/report/test-results.xml +1 -0
  28. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_auth.py +22 -0
  29. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_commands.py +50 -0
  30. ai_eval_scope-0.3.4/tests/unit/test_markdown_lite.py +113 -0
  31. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_sut_probe.py +359 -0
  32. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_sut_registry.py +117 -0
  33. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_workbench_agent.py +931 -1
  34. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/uv.lock +1 -1
  35. ai_eval_scope-0.3.2/report/test-results.xml +0 -1
  36. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/LICENSE +0 -0
  37. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/README.md +0 -0
  38. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/__init__.py +0 -0
  39. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/__init__.py +0 -0
  40. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/budget.py +0 -0
  41. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/callbacks.py +0 -0
  42. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/model_bridge.py +0 -0
  43. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/session.py +0 -0
  44. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/session_log.py +0 -0
  45. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/tool_filter.py +0 -0
  46. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/core/tools.py +0 -0
  47. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/__init__.py +0 -0
  48. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/agent.py +0 -0
  49. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/briefing.py +0 -0
  50. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/http_tools.py +0 -0
  51. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/ledger.py +0 -0
  52. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/package_writer.py +0 -0
  53. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/policy.py +0 -0
  54. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/prompts.py +0 -0
  55. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/protocol_tools.py +0 -0
  56. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/sut_tools.py +0 -0
  57. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/executor/transcript.py +0 -0
  58. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/__init__.py +0 -0
  59. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/gates.py +0 -0
  60. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/prompts.py +0 -0
  61. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/__init__.py +0 -0
  62. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/ask_user.py +0 -0
  63. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/discovery.py +0 -0
  64. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/helpers.py +0 -0
  65. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/sut_probe/search.py +0 -0
  66. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/tool_filter.py +0 -0
  67. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/agent/workbench/types.py +0 -0
  68. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/configs/execution_agent_prompts.yaml +0 -0
  69. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/configs/summary_prompt.yaml +0 -0
  70. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/configs/sut_config.example.yaml +0 -0
  71. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/datasets/dataset_index.yaml +0 -0
  72. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/guides/scenario-package-format.md +0 -0
  73. {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
  74. {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
  75. {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
  76. {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
  77. {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
  78. {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
  79. {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
  80. {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
  81. {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
  82. {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
  83. {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
  84. {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
  85. {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
  86. {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
  87. {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
  88. {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
  89. {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
  90. {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
  91. {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
  92. {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
  93. {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
  94. {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
  95. {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
  96. {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
  97. {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
  98. {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
  99. {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
  100. {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
  101. {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
  102. {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
  103. {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
  104. {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
  105. {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
  106. {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
  107. {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
  108. {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
  109. {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
  110. {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
  111. {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
  112. {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
  113. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/schemas/dataset_index_schema.json +0 -0
  114. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/schemas/dataset_schema.json +0 -0
  115. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/schemas/rule_set_schema.json +0 -0
  116. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/assets/schemas/task_set_schema.json +0 -0
  117. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/__init__.py +0 -0
  118. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/_env_file.py +0 -0
  119. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/_stages.py +0 -0
  120. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/__init__.py +0 -0
  121. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/dataset.py +0 -0
  122. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/doctor.py +0 -0
  123. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/evaluate.py +0 -0
  124. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/execute.py +0 -0
  125. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/knowledge.py +0 -0
  126. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/models.py +0 -0
  127. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/open_url.py +0 -0
  128. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/pack.py +0 -0
  129. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/rule_set.py +0 -0
  130. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/runs.py +0 -0
  131. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/scenario.py +0 -0
  132. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/secrets.py +0 -0
  133. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/suite.py +0 -0
  134. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/cmds/upload.py +0 -0
  135. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/__init__.py +0 -0
  136. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/equiv.py +0 -0
  137. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/output.py +0 -0
  138. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/prompts.py +0 -0
  139. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/console/render.py +0 -0
  140. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/main.py +0 -0
  141. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/__init__.py +0 -0
  142. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/domains/__init__.py +0 -0
  143. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/domains/account.py +0 -0
  144. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/domains/exec.py +0 -0
  145. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/domains/runs.py +0 -0
  146. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/domains/scn.py +0 -0
  147. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/cli/workbench/session.py +0 -0
  148. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/__init__.py +0 -0
  149. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/evaluation.py +0 -0
  150. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/execution.py +0 -0
  151. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/llm.py +0 -0
  152. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/llm_file.py +0 -0
  153. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/llm_resolution.py +0 -0
  154. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/loader.py +0 -0
  155. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/observability.py +0 -0
  156. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/paths.py +0 -0
  157. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/platform_file.py +0 -0
  158. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/config/reporting.py +0 -0
  159. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/core/__init__.py +0 -0
  160. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/core/exceptions.py +0 -0
  161. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/core/logging.py +0 -0
  162. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/core/types.py +0 -0
  163. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/datasets/__init__.py +0 -0
  164. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/datasets/downloader.py +0 -0
  165. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/datasets/manager.py +0 -0
  166. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/datasets/registry.py +0 -0
  167. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/__init__.py +0 -0
  168. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/base.py +0 -0
  169. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/capability.py +0 -0
  170. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/engine.py +0 -0
  171. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/__init__.py +0 -0
  172. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/commonsense_evaluators.py +0 -0
  173. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/content_completeness.py +0 -0
  174. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/format_evaluators.py +0 -0
  175. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/formula_normalizer.py +0 -0
  176. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/plugins/__init__.py +0 -0
  177. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/quality_evaluators.py +0 -0
  178. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/scenario/__init__.py +0 -0
  179. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/scenario/chat.py +0 -0
  180. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/scenario/code.py +0 -0
  181. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/evaluators/vision_evaluators.py +0 -0
  182. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/models.py +0 -0
  183. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/registry.py +0 -0
  184. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/rule_refs.py +0 -0
  185. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/__init__.py +0 -0
  186. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/aggregator.py +0 -0
  187. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/defaults.py +0 -0
  188. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/expr.py +0 -0
  189. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/metrics.py +0 -0
  190. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/scenario/models.py +0 -0
  191. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/stage.py +0 -0
  192. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/summary.py +0 -0
  193. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/text_utils.py +0 -0
  194. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/vision/__init__.py +0 -0
  195. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/evaluation/vision/renderer.py +0 -0
  196. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/__init__.py +0 -0
  197. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/auth/__init__.py +0 -0
  198. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/auth/credentials.py +0 -0
  199. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/auth/provider.py +0 -0
  200. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/auth/secrets_store.py +0 -0
  201. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/auth/session.py +0 -0
  202. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/__init__.py +0 -0
  203. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/agent_protocol.py +0 -0
  204. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/base.py +0 -0
  205. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/commands_stream.py +0 -0
  206. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/generic_http.py +0 -0
  207. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/http_steps.py +0 -0
  208. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/interrupts.py +0 -0
  209. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/message_digest.py +0 -0
  210. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/sse.py +0 -0
  211. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/channels/thread_commands.py +0 -0
  212. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/models.py +0 -0
  213. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/task_builder.py +0 -0
  214. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/execution/utils.py +0 -0
  215. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/__init__.py +0 -0
  216. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/auditor.py +0 -0
  217. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/base.py +0 -0
  218. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/converters/__init__.py +0 -0
  219. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/converters/math_reference.py +0 -0
  220. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/converters/periodic_table.py +0 -0
  221. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/converters/physics_reference.py +0 -0
  222. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/exceptions.py +0 -0
  223. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/extractors/__init__.py +0 -0
  224. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/extractors/llm_extractor.py +0 -0
  225. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/extractors/parsers.py +0 -0
  226. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/manager.py +0 -0
  227. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/merger.py +0 -0
  228. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/models.py +0 -0
  229. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/pipeline.py +0 -0
  230. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/registry.py +0 -0
  231. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/sources/__init__.py +0 -0
  232. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/sources/eval_sources.py +0 -0
  233. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/sources/math_reference.py +0 -0
  234. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/sources/physics_reference.py +0 -0
  235. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/knowledge/sources/table_sources.py +0 -0
  236. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/__init__.py +0 -0
  237. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/client.py +0 -0
  238. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/factory.py +0 -0
  239. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/__init__.py +0 -0
  240. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/file_prompt_store.py +0 -0
  241. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/orchestrator.py +0 -0
  242. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/prompt_store.py +0 -0
  243. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/recorder.py +0 -0
  244. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/stability.py +0 -0
  245. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/structured_output.py +0 -0
  246. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/judge/template_manager.py +0 -0
  247. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/models.py +0 -0
  248. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/pool.py +0 -0
  249. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/providers/__init__.py +0 -0
  250. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/providers/anthropic.py +0 -0
  251. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/providers/openai_compat.py +0 -0
  252. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/llm/tracing.py +0 -0
  253. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/__init__.py +0 -0
  254. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/client.py +0 -0
  255. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/config.py +0 -0
  256. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/events.py +0 -0
  257. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/queue.py +0 -0
  258. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/schemas/ingest.event.v1.json +0 -0
  259. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/sink.py +0 -0
  260. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/observability/snapshot.py +0 -0
  261. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/orchestrator/__init__.py +0 -0
  262. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/orchestrator/orchestrator.py +0 -0
  263. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/__init__.py +0 -0
  264. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/assets.py +0 -0
  265. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/manager.py +0 -0
  266. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/manifest.py +0 -0
  267. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/remote_client.py +0 -0
  268. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/packages/store.py +0 -0
  269. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/reporting/__init__.py +0 -0
  270. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/reporting/gate.py +0 -0
  271. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/reporting/junit_renderer.py +0 -0
  272. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/reporting/report_generator.py +0 -0
  273. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/reporting/summary_text.py +0 -0
  274. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/rules/__init__.py +0 -0
  275. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/rules/models.py +0 -0
  276. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/rules/template.py +0 -0
  277. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/rules/validation.py +0 -0
  278. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/sdk/__init__.py +0 -0
  279. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/sdk/rules.py +0 -0
  280. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/storage/__init__.py +0 -0
  281. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/storage/builder.py +0 -0
  282. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/storage/collector.py +0 -0
  283. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/storage/package.py +0 -0
  284. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/agent_eval/storage/workspace.py +0 -0
  285. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/report/ruff-results.xml +0 -0
  286. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/__init__.py +0 -0
  287. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/config/test_evaluation_config.py +0 -0
  288. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/config/test_execution_config.py +0 -0
  289. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/config/test_llm_config.py +0 -0
  290. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/config/test_reporting_config.py +0 -0
  291. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/conftest.py +0 -0
  292. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/e2e/__init__.py +0 -0
  293. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/e2e/test_eval_e2e.py +0 -0
  294. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluation/test_vision_renderer.py +0 -0
  295. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/__init__.py +0 -0
  296. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_cascade_metrics.py +0 -0
  297. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_cascade_vision_integration.py +0 -0
  298. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_format_and_commonsense.py +0 -0
  299. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_format_evaluators.py +0 -0
  300. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_llm_judge_evaluators.py +0 -0
  301. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_quality_evaluators.py +0 -0
  302. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/evaluators/test_vision_evaluator.py +0 -0
  303. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/__init__.py +0 -0
  304. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/configs/invalid_rule_set.yaml +0 -0
  305. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/configs/rule_set.yaml +0 -0
  306. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/configs/task_set.yaml +0 -0
  307. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/golden/commonsense_error/output/index.md +0 -0
  308. {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
  309. {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
  310. {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
  311. {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
  312. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/golden/valid_docset/output/chapter_01.md +0 -0
  313. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/golden/valid_docset/output/index.md +0 -0
  314. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/metrics/policy.yaml +0 -0
  315. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/fixtures/prompts/test_template.yaml +0 -0
  316. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/golden/__init__.py +0 -0
  317. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/integration/__init__.py +0 -0
  318. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/integration/test_observability_e2e.py +0 -0
  319. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/__init__.py +0 -0
  320. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/conftest.py +0 -0
  321. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_anthropic_client.py +0 -0
  322. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_client.py +0 -0
  323. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_factory.py +0 -0
  324. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_judge_orchestrator_vision.py +0 -0
  325. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_models.py +0 -0
  326. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_openai_compat_client.py +0 -0
  327. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_orchestrator.py +0 -0
  328. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_pool.py +0 -0
  329. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_prompt_store.py +0 -0
  330. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_recorder.py +0 -0
  331. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_stability.py +0 -0
  332. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_structured_output.py +0 -0
  333. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_template_manager.py +0 -0
  334. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/llm/test_tracing.py +0 -0
  335. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/orchestrator/__init__.py +0 -0
  336. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/orchestrator/conftest.py +0 -0
  337. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/orchestrator/test_eval_flow.py +0 -0
  338. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/orchestrator/test_orchestrator.py +0 -0
  339. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/reporting/__init__.py +0 -0
  340. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/reporting/test_gate.py +0 -0
  341. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/reporting/test_junit_renderer.py +0 -0
  342. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/reporting/test_report_generator.py +0 -0
  343. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/reporting/test_summary_text.py +0 -0
  344. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/__init__.py +0 -0
  345. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_agent_module.py +0 -0
  346. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_agent_protocol_channel.py +0 -0
  347. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_anthropic_provider.py +0 -0
  348. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_briefing.py +0 -0
  349. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_callbacks.py +0 -0
  350. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_capability.py +0 -0
  351. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_chat_evaluators.py +0 -0
  352. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_console.py +0 -0
  353. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_dataset.py +0 -0
  354. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_llm_check.py +0 -0
  355. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_pack.py +0 -0
  356. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_pipeline.py +0 -0
  357. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_run.py +0 -0
  358. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_run_mode.py +0 -0
  359. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_secrets.py +0 -0
  360. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_stages.py +0 -0
  361. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_cli_workbench.py +0 -0
  362. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_collector.py +0 -0
  363. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_config_loader.py +0 -0
  364. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_content_completeness.py +0 -0
  365. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_core_types.py +0 -0
  366. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_data_models.py +0 -0
  367. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_env_file.py +0 -0
  368. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_eval_engine.py +0 -0
  369. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_execution_agent.py +0 -0
  370. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_execution_utils.py +0 -0
  371. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_generic_http_channel.py +0 -0
  372. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_http_steps.py +0 -0
  373. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_interaction_policy.py +0 -0
  374. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_judge_coerce.py +0 -0
  375. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_judge_dim_details.py +0 -0
  376. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_knowledge_auditor.py +0 -0
  377. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_knowledge_manager.py +0 -0
  378. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_llm_config_file.py +0 -0
  379. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_logging.py +0 -0
  380. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_model_bridge.py +0 -0
  381. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_observability_config_client_queue.py +0 -0
  382. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_observability_events.py +0 -0
  383. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_observability_sink.py +0 -0
  384. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_package.py +0 -0
  385. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_package_assets.py +0 -0
  386. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_package_builder.py +0 -0
  387. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_package_writer.py +0 -0
  388. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_packages.py +0 -0
  389. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_pipeline_build.py +0 -0
  390. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_platform_file.py +0 -0
  391. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_plugin_discovery.py +0 -0
  392. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_protocol_tools.py +0 -0
  393. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_quality_evaluator_details.py +0 -0
  394. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_remote_client.py +0 -0
  395. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_resource_ledger.py +0 -0
  396. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_rule_refs.py +0 -0
  397. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_rule_sdk.py +0 -0
  398. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_scenario_aggregation.py +0 -0
  399. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_scenario_packaging.py +0 -0
  400. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_secrets.py +0 -0
  401. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_session.py +0 -0
  402. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_sink_artifacts.py +0 -0
  403. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_source_files_attribution.py +0 -0
  404. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_sut_auth.py +0 -0
  405. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_sut_tools.py +0 -0
  406. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_task_builder.py +0 -0
  407. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_task_selection.py +0 -0
  408. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_thread_commands.py +0 -0
  409. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_workbench_tool_filter.py +0 -0
  410. {ai_eval_scope-0.3.2 → ai_eval_scope-0.3.4}/tests/unit/test_workspace.py +0 -0
@@ -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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ai-eval-scope
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Agent 能力评估系统 — 基于 Agent-Driven 架构的评测框架
5
5
  Author: Agent Eval Team
6
6
  License-Expression: MIT
@@ -1,3 +1,3 @@
1
1
  """Agent 能力评估系统"""
2
2
 
3
- __version__ = "0.3.2"
3
+ __version__ = "0.3.4"
@@ -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(user_text, reply, str(self.server.root))
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
- tools = self.server.to_langchain_tools() + self.probe.to_langchain_tools()
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(self, user_text: str, reply: str, root: str) -> None:
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(懒建):连接池复用 + cookie jar 跨请求保持。
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
- if self._client_instance is None:
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
- self._client_instance = self.http_client_factory()
316
+ new_client = self.http_client_factory()
252
317
  else:
253
318
  import httpx
254
319
 
255
- self._client_instance = httpx.AsyncClient(
256
- timeout=self.timeout_s, follow_redirects=False
257
- )
258
- return self._client_instance
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
@@ -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
- rendered_headers = {k: rendered_map[str(i + 1)] for i, k in enumerate(header_names)}
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(text/plain 等原始报文探测)不适用本校验;数组 body 合法放行
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
- self.ctx.log("request", method=verb, url=url, event="failed", error=net_err(e)[:200])
248
- return {"status": 0, "error": f"请求失败: {net_err(e)}"}
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
- return structure_response(
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