niceeval 0.6.1 → 0.6.2

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 (296) hide show
  1. package/dist/agents/types.d.ts +67 -5
  2. package/dist/context/types.d.ts +32 -12
  3. package/dist/i18n/en.d.ts +54 -0
  4. package/dist/i18n/zh-CN.d.ts +55 -1
  5. package/dist/o11y/types.d.ts +16 -2
  6. package/dist/report/aggregate.d.ts +5 -3
  7. package/dist/report/aggregate.js +32 -5
  8. package/dist/report/built-ins/experiment-comparison.d.ts +39 -1
  9. package/dist/report/built-ins/experiment-comparison.js +116 -10
  10. package/dist/report/built-ins/index.d.ts +1 -0
  11. package/dist/report/built-ins/index.js +1 -1
  12. package/dist/report/components.d.ts +8 -2
  13. package/dist/report/components.js +3 -3
  14. package/dist/report/compute.d.ts +11 -18
  15. package/dist/report/compute.js +54 -34
  16. package/dist/report/flag.d.ts +16 -1
  17. package/dist/report/flag.js +19 -1
  18. package/dist/report/format.d.ts +16 -8
  19. package/dist/report/format.js +27 -12
  20. package/dist/report/index.d.ts +4 -3
  21. package/dist/report/index.js +5 -4
  22. package/dist/report/locale.d.ts +11 -2
  23. package/dist/report/locale.js +23 -5
  24. package/dist/report/metrics.d.ts +13 -1
  25. package/dist/report/metrics.js +65 -14
  26. package/dist/report/primitives.d.ts +6 -0
  27. package/dist/report/react/AttemptList.d.ts +2 -2
  28. package/dist/report/react/AttemptList.js +5 -6
  29. package/dist/report/react/EvalList.d.ts +1 -1
  30. package/dist/report/react/EvalList.js +0 -0
  31. package/dist/report/react/ExperimentComparison.d.ts +8 -0
  32. package/dist/report/react/ExperimentComparison.js +11 -0
  33. package/dist/report/react/ExperimentList.d.ts +2 -1
  34. package/dist/report/react/ExperimentList.js +8 -10
  35. package/dist/report/react/MetricScatter.js +5 -11
  36. package/dist/report/react/chart-math.d.ts +23 -6
  37. package/dist/report/react/chart-math.js +71 -19
  38. package/dist/report/react/fixtures.d.ts +3 -3
  39. package/dist/report/react/fixtures.js +21 -14
  40. package/dist/report/report.d.ts +5 -1
  41. package/dist/report/report.js +6 -2
  42. package/dist/report/text/faces.d.ts +1 -1
  43. package/dist/report/text/faces.js +42 -41
  44. package/dist/report/text/table.js +36 -5
  45. package/dist/report/types.d.ts +39 -21
  46. package/dist/results/types.d.ts +11 -0
  47. package/dist/runner/feedback/sink.d.ts +110 -0
  48. package/dist/runner/types.d.ts +513 -22
  49. package/dist/sandbox/docker.d.ts +23 -2
  50. package/dist/sandbox/e2b.d.ts +15 -1
  51. package/dist/sandbox/errors.d.ts +30 -3
  52. package/dist/sandbox/io-retry.d.ts +17 -0
  53. package/dist/sandbox/registry.d.ts +2 -0
  54. package/dist/sandbox/resolve.d.ts +18 -5
  55. package/dist/sandbox/retry.d.ts +11 -1
  56. package/dist/sandbox/types.d.ts +39 -5
  57. package/dist/sandbox/vercel.d.ts +7 -1
  58. package/dist/scoring/coverage.d.ts +30 -0
  59. package/dist/scoring/display.d.ts +21 -0
  60. package/dist/scoring/display.js +120 -0
  61. package/dist/scoring/types.d.ts +103 -20
  62. package/dist/shared/aggregate.d.ts +1 -0
  63. package/dist/shared/aggregate.js +3 -3
  64. package/dist/shared/types.d.ts +28 -0
  65. package/dist/tty-line.d.ts +0 -4
  66. package/dist/util.d.ts +23 -0
  67. package/docs-site/zh/concepts/adapter.mdx +22 -4
  68. package/docs-site/zh/concepts/experiment.mdx +1 -1
  69. package/docs-site/zh/concepts/overview.mdx +6 -6
  70. package/docs-site/zh/guides/agent-feedback-loop.mdx +28 -26
  71. package/docs-site/zh/guides/authoring.mdx +33 -0
  72. package/docs-site/zh/guides/ci-integration.mdx +23 -12
  73. package/docs-site/zh/guides/connect-your-agent.mdx +29 -3
  74. package/docs-site/zh/guides/custom-reports.mdx +29 -34
  75. package/docs-site/zh/guides/dataset-fanout.mdx +25 -3
  76. package/docs-site/zh/guides/debug-sandbox.mdx +57 -0
  77. package/docs-site/zh/guides/debugging.mdx +210 -0
  78. package/docs-site/zh/guides/experiments.mdx +10 -3
  79. package/docs-site/zh/guides/official-adapters.mdx +26 -2
  80. package/docs-site/zh/guides/publish-report.mdx +30 -16
  81. package/docs-site/zh/guides/report-components.mdx +42 -30
  82. package/docs-site/zh/guides/reporters.mdx +2 -2
  83. package/docs-site/zh/guides/results-data.mdx +17 -9
  84. package/docs-site/zh/guides/runner.mdx +17 -7
  85. package/docs-site/zh/guides/sandbox-agent.mdx +56 -7
  86. package/docs-site/zh/guides/sandbox-providers.mdx +257 -9
  87. package/docs-site/zh/guides/scoring-guide.mdx +4 -4
  88. package/docs-site/zh/guides/viewing-results.mdx +79 -36
  89. package/docs-site/zh/guides/write-experiment.mdx +5 -3
  90. package/docs-site/zh/guides/write-send.mdx +17 -1
  91. package/docs-site/zh/index.mdx +1 -1
  92. package/docs-site/zh/reference/builtin-agents.mdx +27 -0
  93. package/docs-site/zh/reference/capabilities.mdx +2 -2
  94. package/docs-site/zh/reference/cli.mdx +33 -7
  95. package/docs-site/zh/reference/define-agent.mdx +57 -4
  96. package/docs-site/zh/reference/define-config.mdx +1 -1
  97. package/docs-site/zh/reference/define-eval.mdx +42 -9
  98. package/docs-site/zh/reference/expect.mdx +26 -1
  99. package/package.json +5 -1
  100. package/src/agents/ai-sdk-otel.test.ts +1 -0
  101. package/src/agents/ai-sdk.test.ts +3 -0
  102. package/src/agents/ai-sdk.ts +3 -0
  103. package/src/agents/bub-install-spec.test.ts +34 -0
  104. package/src/agents/bub-install-spec.ts +32 -0
  105. package/src/agents/bub.ts +31 -32
  106. package/src/agents/claude-code.test.ts +130 -9
  107. package/src/agents/claude-code.ts +76 -4
  108. package/src/agents/codex.test.ts +189 -40
  109. package/src/agents/codex.ts +155 -14
  110. package/src/agents/coding-cli-versions.test.ts +15 -0
  111. package/src/agents/coding-cli-versions.ts +3 -0
  112. package/src/agents/index.ts +11 -0
  113. package/src/agents/langgraph.test.ts +204 -0
  114. package/src/agents/langgraph.ts +495 -0
  115. package/src/agents/marketplace.ts +85 -0
  116. package/src/agents/native-config.test.ts +179 -0
  117. package/src/agents/native-config.ts +267 -0
  118. package/src/agents/openai-compat.test.ts +1 -0
  119. package/src/agents/openclaw.test.ts +31 -0
  120. package/src/agents/openclaw.ts +171 -0
  121. package/src/agents/plugin-config.test.ts +1 -0
  122. package/src/agents/sdk-streams.test.ts +79 -0
  123. package/src/agents/sdk-streams.ts +55 -10
  124. package/src/agents/skills.test.ts +1 -0
  125. package/src/agents/streaming.test.ts +3 -9
  126. package/src/agents/types.ts +68 -5
  127. package/src/agents/ui-message-stream.test.ts +3 -0
  128. package/src/cli.ts +411 -108
  129. package/src/context/context.test.ts +51 -12
  130. package/src/context/context.ts +161 -29
  131. package/src/context/session.test.ts +1 -0
  132. package/src/context/session.ts +114 -6
  133. package/src/context/types.ts +30 -12
  134. package/src/define.test.ts +13 -8
  135. package/src/define.ts +25 -4
  136. package/src/expect/index.ts +53 -23
  137. package/src/i18n/en.ts +64 -2
  138. package/src/i18n/zh-CN.ts +65 -3
  139. package/src/o11y/cost.test.ts +1 -0
  140. package/src/o11y/execution-tree.test.ts +1 -20
  141. package/src/o11y/otlp/mappers/claude-code.test.ts +1 -0
  142. package/src/o11y/otlp/parse.test.ts +1 -0
  143. package/src/o11y/otlp/turn-otel.test.ts +1 -0
  144. package/src/o11y/parsers/bub.test.ts +1 -0
  145. package/src/o11y/parsers/claude-code.test.ts +1 -34
  146. package/src/o11y/parsers/openclaw.test.ts +154 -0
  147. package/src/o11y/parsers/openclaw.ts +310 -0
  148. package/src/o11y/prices.json +746 -311
  149. package/src/o11y/tool-names.test.ts +1 -0
  150. package/src/o11y/types.ts +16 -2
  151. package/src/report/aggregate.ts +34 -5
  152. package/src/report/built-in-user-parity.test.tsx +110 -153
  153. package/src/report/built-ins/experiment-comparison.tsx +173 -13
  154. package/src/report/built-ins/index.ts +6 -1
  155. package/src/report/components.tsx +9 -3
  156. package/src/report/compute.ts +70 -40
  157. package/src/report/dual-render.test.tsx +194 -67
  158. package/src/report/flag.ts +30 -2
  159. package/src/report/format.ts +35 -11
  160. package/src/report/index.ts +22 -4
  161. package/src/report/locale.ts +25 -5
  162. package/src/report/metrics.ts +67 -14
  163. package/src/report/primitives.tsx +6 -0
  164. package/src/report/react/AttemptList.tsx +6 -31
  165. package/src/report/react/EvalList.tsx +0 -0
  166. package/src/report/react/ExperimentComparison.tsx +68 -0
  167. package/src/report/react/ExperimentList.tsx +15 -9
  168. package/src/report/react/MetricScatter.tsx +12 -14
  169. package/src/report/react/chart-math.test.ts +85 -0
  170. package/src/report/react/chart-math.ts +101 -22
  171. package/src/report/react/enhance.js +33 -1
  172. package/src/report/react/fixtures.ts +24 -17
  173. package/src/report/react/render.test.tsx +9 -64
  174. package/src/report/react/styles.css +73 -2
  175. package/src/report/report.test.ts +306 -98
  176. package/src/report/report.ts +6 -2
  177. package/src/report/text/faces.ts +47 -43
  178. package/src/report/text/table.ts +42 -5
  179. package/src/report/types.ts +41 -21
  180. package/src/results/annotated-source.test.ts +62 -9
  181. package/src/results/annotated-source.ts +64 -6
  182. package/src/results/attempt-evidence.test.ts +9 -7
  183. package/src/results/attempt-evidence.ts +15 -8
  184. package/src/results/attempt-source.ts +6 -3
  185. package/src/results/copy.ts +145 -55
  186. package/src/results/host-equivalence.test.ts +8 -6
  187. package/src/results/index.ts +2 -0
  188. package/src/results/locator.test.ts +1 -22
  189. package/src/results/open.ts +7 -1
  190. package/src/results/publish.ts +149 -0
  191. package/src/results/results.test.ts +85 -51
  192. package/src/results/truncate.ts +90 -0
  193. package/src/results/types.ts +7 -0
  194. package/src/results/writer.ts +31 -13
  195. package/src/runner/attempt.test.ts +138 -7
  196. package/src/runner/attempt.ts +603 -104
  197. package/src/runner/discover.test.ts +47 -0
  198. package/src/runner/discover.ts +36 -2
  199. package/src/runner/eval-source.test.ts +1 -27
  200. package/src/runner/feedback/agent.test.ts +504 -0
  201. package/src/runner/feedback/agent.ts +409 -0
  202. package/src/runner/feedback/ci.test.ts +562 -0
  203. package/src/runner/feedback/ci.ts +401 -0
  204. package/src/runner/feedback/coordinator.test.ts +317 -0
  205. package/src/runner/feedback/coordinator.ts +397 -0
  206. package/src/runner/feedback/failure.ts +40 -0
  207. package/src/runner/feedback/human.test.ts +616 -0
  208. package/src/runner/feedback/human.ts +535 -0
  209. package/src/runner/feedback/index.ts +66 -0
  210. package/src/runner/feedback/io.ts +78 -0
  211. package/src/runner/feedback/profile.test.ts +50 -0
  212. package/src/runner/feedback/profile.ts +58 -0
  213. package/src/runner/feedback/reducer.test.ts +395 -0
  214. package/src/runner/feedback/reducer.ts +260 -0
  215. package/src/runner/feedback/renderer.ts +82 -0
  216. package/src/runner/feedback/sink.ts +203 -0
  217. package/src/runner/feedback/testing.ts +106 -0
  218. package/src/runner/ledger.test.ts +230 -0
  219. package/src/runner/ledger.ts +329 -0
  220. package/src/runner/report.test.ts +128 -3
  221. package/src/runner/report.ts +33 -9
  222. package/src/runner/reporters/artifacts.ts +8 -2
  223. package/src/runner/reporters/braintrust.test.ts +8 -7
  224. package/src/runner/reporters/braintrust.ts +9 -2
  225. package/src/runner/reporters/index.ts +2 -2
  226. package/src/runner/reporters/json.test.ts +162 -0
  227. package/src/runner/reporters/json.ts +35 -8
  228. package/src/runner/reporters/shared.ts +1 -5
  229. package/src/runner/run.test.ts +760 -3
  230. package/src/runner/run.ts +242 -36
  231. package/src/runner/sandbox-prep.ts +3 -42
  232. package/src/runner/timing.ts +158 -0
  233. package/src/runner/types.ts +518 -22
  234. package/src/sandbox/checkpoint.test.ts +55 -0
  235. package/src/sandbox/checkpoint.ts +29 -8
  236. package/src/sandbox/cli-commands.ts +407 -0
  237. package/src/sandbox/docker.ts +115 -16
  238. package/src/sandbox/e2b-agent-template.test.ts +56 -0
  239. package/src/sandbox/e2b-agent-template.ts +94 -0
  240. package/src/sandbox/e2b.ts +74 -9
  241. package/src/sandbox/errors.ts +111 -4
  242. package/src/sandbox/index.ts +2 -0
  243. package/src/sandbox/io-retry.test.ts +58 -0
  244. package/src/sandbox/io-retry.ts +45 -0
  245. package/src/sandbox/keep-registry.test.ts +86 -0
  246. package/src/sandbox/keep-registry.ts +142 -0
  247. package/src/sandbox/keep.ts +178 -0
  248. package/src/sandbox/paths.test.ts +1 -0
  249. package/src/sandbox/paths.ts +19 -8
  250. package/src/sandbox/registry.ts +20 -3
  251. package/src/sandbox/resolve.ts +76 -11
  252. package/src/sandbox/retry.test.ts +70 -0
  253. package/src/sandbox/retry.ts +46 -4
  254. package/src/sandbox/types.ts +44 -6
  255. package/src/sandbox/vercel.ts +43 -20
  256. package/src/scoring/collector.ts +60 -17
  257. package/src/scoring/coverage.ts +95 -0
  258. package/src/scoring/diff.ts +81 -0
  259. package/src/scoring/display.test.ts +121 -0
  260. package/src/scoring/display.ts +133 -0
  261. package/src/scoring/evidence.test.ts +189 -0
  262. package/src/scoring/judge.test.ts +142 -0
  263. package/src/scoring/judge.ts +15 -18
  264. package/src/scoring/scoped.ts +217 -50
  265. package/src/scoring/types.ts +117 -20
  266. package/src/scoring/verdict.ts +16 -4
  267. package/src/shared/aggregate.ts +3 -2
  268. package/src/shared/types.ts +31 -0
  269. package/src/show/compose.ts +2 -2
  270. package/src/show/index.ts +21 -1
  271. package/src/show/render.ts +619 -104
  272. package/src/show/show.test.ts +235 -19
  273. package/src/tty-line.ts +8 -26
  274. package/src/util.test.ts +1 -0
  275. package/src/util.ts +41 -0
  276. package/src/view/app/components/AttemptModal.tsx +153 -2
  277. package/src/view/app/components/CodeView.tsx +32 -11
  278. package/src/view/app/components/CopyControls.tsx +2 -2
  279. package/src/view/app/i18n.ts +6 -0
  280. package/src/view/app/lib/attempt-route.test.ts +1 -0
  281. package/src/view/app/lib/verdict.ts +7 -9
  282. package/src/view/artifact-serving.test.ts +2 -1
  283. package/src/view/client-dist/app.css +1 -1
  284. package/src/view/client-dist/app.js +17 -17
  285. package/src/view/data.test.ts +1 -0
  286. package/src/view/data.ts +11 -1
  287. package/src/view/index.ts +11 -0
  288. package/src/view/server.ts +2 -0
  289. package/src/view/styles.css +3 -0
  290. package/src/view/view-report.test.ts +6 -5
  291. package/src/runner/reporters/console.ts +0 -70
  292. package/src/runner/reporters/live.test.ts +0 -56
  293. package/src/runner/reporters/live.ts +0 -247
  294. package/src/runner/reporters/quiet.test.ts +0 -66
  295. package/src/runner/reporters/quiet.ts +0 -49
  296. package/src/runner/reporters/table.ts +0 -277
@@ -2,12 +2,25 @@
2
2
 
3
3
  import type { Severity, SourceLoc } from "../shared/types.ts";
4
4
  import type { DerivedFacts, StreamEvent, Usage } from "../o11y/types.ts";
5
+ import type { ResolvedCoverage } from "./coverage.ts";
5
6
 
6
- /** 值断言(expect 匹配器)。纯函数 score + 可链式改严重度 / 阈值。 */
7
+ // 覆盖代数(解析 / 降级 / 聚合)住在 coverage.ts;类型经这里进聚合 facade(src/types.ts)。
8
+ export type {
9
+ CoverageChannel,
10
+ ResolvedCoverage,
11
+ ResolvedCoverageChannel,
12
+ ResolvedCoverageStatus,
13
+ } from "./coverage.ts";
14
+
15
+ /** 值断言(expect 匹配器)。纯函数 score + 可链式改严重度 / 阈值 / optional。 */
7
16
  export interface ValueAssertion {
8
17
  readonly name: string;
9
18
  readonly severity: Severity;
10
19
  readonly threshold?: number;
20
+ /** `.optional()` 链过的标记:评不了只记 unavailable,不把 attempt 拖成 errored。 */
21
+ readonly isOptional?: boolean;
22
+ /** 期望条件的有界文本描述(如 `contains "Brooklyn"`),失败时进 AssertionResult.expected。 */
23
+ readonly expected?: string;
11
24
  score(value: unknown): number | Promise<number>;
12
25
  /** 转成硬门槛断言:未达阈值(省略 threshold 则按 score > 0 判定)整条 eval 判为 failed。返回新实例,不改原对象。 */
13
26
  gate(threshold?: number): ValueAssertion;
@@ -16,37 +29,82 @@ export interface ValueAssertion {
16
29
  * `--strict` 运行下,软阈值失败也会把整条 eval 的 verdict 计为 failed。返回新实例,不改原对象。
17
30
  */
18
31
  atLeast(threshold: number): ValueAssertion;
32
+ /**
33
+ * 允许这条断言证据缺席:评不了时只记录 `outcome: "unavailable"`,不影响判定。
34
+ * 与 severity 正交(severity 说影不影响质量判定,optional 说证据允不允许缺席)。返回新实例,不改原对象。
35
+ */
36
+ optional(): ValueAssertion;
19
37
  }
20
38
 
21
- /** 收集到 collector 里的一条断言记录(评估前)。 */
22
- export interface AssertionSpec {
39
+ /**
40
+ * 断言记录的公共字段(见 docs/feature/scoring/architecture.md「断言记录」——字段契约的单点定义)。
41
+ */
42
+ export interface AssertionBase {
43
+ /** 断言标题:t.group 内是该断言自己的摘要,组外是 matcher 摘要或 judge 问题;show/view 失败行的标题。 */
23
44
  name: string;
45
+ /** 所属分组路径:外层在前的 t.group 标题数组;无分组省略。纯报告用,不影响判定。 */
46
+ groupPath?: string[];
24
47
  severity: Severity;
25
- threshold?: number;
26
- /** 延迟评估:final 时拿到完整运行结果再算分。 */
27
- evaluate(ctx: ScoringContext): Promise<number> | number;
48
+ /** 作者用 .optional() 显式允许该断言缺席;只改变 unavailable 的折叠方式(见 Severity 与 Verdict),不改变 severity 语义。 */
49
+ optional?: true;
50
+ /** matcher / judge 摘要,如 `equals(4)`、`closedQA("…")`;与 name 分开,供 show/view 同时展示分组标题与检查方式。 */
51
+ detail?: string;
52
+ /** 断言在 eval 源码中的调用点,`--eval` 把结果标回源码行的锚。 */
53
+ loc?: SourceLoc;
28
54
  }
29
55
 
30
- /** 断言评估完的结果(进判定 / 报告)。 */
31
- export interface AssertionResult {
32
- name: string;
56
+ /**
57
+ * 断言评估完的结果(进判定 / 报告)。判别键是 `outcome`——`unavailable` 是没有分数的独立态,
58
+ * 普通聚合代码按 `outcome` 分支就不可能把证据缺口算成零分。判定只消费
59
+ * `severity` / `outcome` / `optional` / `score` / `threshold`。
60
+ */
61
+ export type AssertionResult =
62
+ | (AssertionBase & {
63
+ outcome: "passed" | "failed";
64
+ /** 归一化得分:值断言 0/1,judge 等打分断言 0..1。 */
65
+ score: number;
66
+ /** soft 断言的 .atLeast(x) 阈值;没有设阈值则省略。 */
67
+ threshold?: number;
68
+ /** 失败证据摘要:期望值的有界文本预览,供 show/view 直接展示。 */
69
+ expected?: string;
70
+ /** 失败证据摘要:实际值的有界文本预览。 */
71
+ received?: string;
72
+ /** 这条分数看着什么材料算出(judge 输入或被检查值预览);view 展开排查用,默认不展示。 */
73
+ evidence?: string;
74
+ })
75
+ | (AssertionBase & {
76
+ outcome: "unavailable";
77
+ /** 机器可读原因,如 "judge-model-unresolved"、"coverage:actions=partial"。 */
78
+ reason: string;
79
+ });
80
+
81
+ /**
82
+ * 摘要面从完整 `AssertionResult[]` 选出的一条主失败断言。它只负责展示,不参与 verdict;
83
+ * `show @locator` / view Attempt 详情仍读取完整断言数组。字段保持结构化,使 CI 不必解析
84
+ * Human 的 `gate: …` 文案。
85
+ */
86
+ export interface PrimaryAssertionSummary {
33
87
  severity: Severity;
88
+ /** `groupPath.join(" > ")`,无 group 时回退到断言 name。 */
89
+ assertion: string;
90
+ /** `detail ?? name`;与 assertion 相同时省略,避免重复。 */
91
+ matcher?: string;
92
+ expected?: string;
93
+ received?: string;
94
+ score?: number;
34
95
  threshold?: number;
35
- score: number;
36
- passed: boolean;
37
- detail?: string;
38
- /** 这条分数是看着什么材料算出来的(judge 收到的输入,或 t.check 失败时实际被检查的值)。view 展开排查「为什么是这个分」,默认不展示。 */
39
- evidence?: string;
40
- /** 所属分组(t.group 标题)。纯报告用,不影响 passed/score。 */
41
- group?: string;
42
- /** 断言在 eval 源码里的调用点(栈回溯抠出);view 把判定叠回这一行。 */
43
- loc?: SourceLoc;
96
+ /** unavailable 断言的结构化原因。 */
97
+ reason?: string;
98
+ /** 同类因果失败中除主失败外的条数。 */
99
+ additionalFailures: number;
44
100
  }
45
101
 
46
102
  /** eval 作者拿到的可链式句柄(t.judge.autoevals.closedQA(...).atLeast(0.7))。 */
47
103
  export interface AssertionHandle {
48
104
  atLeast(threshold: number): AssertionHandle;
49
105
  gate(threshold?: number): AssertionHandle;
106
+ /** 允许这条断言证据缺席:unavailable 只保留在记录里,不影响判定(见 Severity 与 Verdict)。 */
107
+ optional(): AssertionHandle;
50
108
  }
51
109
 
52
110
  /** scoped / judge 断言在 final 评估时拿到的运行结果。 */
@@ -57,6 +115,8 @@ export interface ScoringContext {
57
115
  readonly scripts: Record<string, ScriptResult>;
58
116
  readonly usage: Usage;
59
117
  readonly status: "completed" | "failed" | "waiting";
118
+ /** 当前作用域(turn / session / attempt)解析后的证据覆盖;断言按它做三值折叠(见 scoped.ts)。 */
119
+ readonly coverage: ResolvedCoverage;
60
120
  /** 读沙箱里某文件的最终内容(judge / file 断言用)。 */
61
121
  readFile(path: string): Promise<string | undefined>;
62
122
  }
@@ -66,9 +126,46 @@ export interface ScriptResult {
66
126
  output: string;
67
127
  }
68
128
 
129
+ // ── agent 归因增量(见 docs/feature/results/architecture.md「diff.json」与
130
+ // docs/feature/sandbox/architecture.md「变更归因:send 窗口与分类账」)──
131
+
132
+ /** diff.json 的落盘形状:按时序的窗口数组(逐窗口 delta 序列,不做跨窗口压缩)。 */
133
+ export type DiffArtifact = DiffWindow[];
134
+
135
+ export interface DiffWindow {
136
+ /** send 窗口标签,与时间树 turn 节点、--execution 轮次同源(如 "s1/t2")。 */
137
+ window: string;
138
+ /** 该窗口内 agent 改动的文件;窗口内没有 workspace 变化时窗口仍落一条、changes 为空对象。 */
139
+ changes: Record<string, WindowChange>;
140
+ }
141
+
142
+ export interface WindowChange {
143
+ status: "added" | "modified" | "deleted";
144
+ /** 窗口开始时的内容;added 无此字段。 */
145
+ before?: string;
146
+ /** 窗口结束时的内容;deleted 无此字段。 */
147
+ after?: string;
148
+ /** 二进制文件不内联内容,只记字节数。 */
149
+ binary?: { beforeBytes?: number; afterBytes?: number };
150
+ }
151
+
152
+ /** 读取面在窗口序列之上派生的文件级视图(派生物可随时重算,不落盘)。 */
153
+ export interface DiffFileSummary {
154
+ /** 净效果:首个触及窗口的起点 vs 最后触及窗口的终点;"none" = 动过但净无变化(创建又删除、改回原样)。 */
155
+ net: "added" | "modified" | "deleted" | "none";
156
+ /** 触及该文件的窗口标签,按时序。 */
157
+ windows: string[];
158
+ binary?: true;
159
+ }
160
+
161
+ /** agent 归因 diff 的消费视图:窗口序列(落盘事实)+ 派生的文件级摘要与终态读取。 */
69
162
  export interface DiffData {
70
- generatedFiles: Record<string, string>;
71
- deletedFiles: string[];
163
+ /** 落盘事实,原样。 */
164
+ windows: DiffWindow[];
165
+ /** 派生:每个被 agent 触及的文件一条。 */
166
+ files: Record<string, DiffFileSummary>;
167
+ /** 该文件最后一个触及窗口结束时的内容;净删除或从未触及返回 undefined。t.sandbox.diff.get 同一语义。 */
168
+ get(path: string): string | undefined;
72
169
  }
73
170
 
74
171
  export type Verdict = "passed" | "failed" | "errored" | "skipped";
@@ -1,17 +1,29 @@
1
- // 判定:把执行结果 + 断言 + 跳过原因折叠成一个 Verdict(见 docs/feature/scoring/README.md)。
1
+ // 判定:把执行结果 + 断言 + 跳过原因折叠成一个 Verdict
2
+ // (见 docs/feature/scoring/architecture/severity-and-verdict.md)。固定优先级取第一个成立项:
3
+ // 执行异常 / 任一非 optional 断言 unavailable → errored
4
+ // 任一 gate 不通过,或 strict 下 soft 低于阈值 → failed
5
+ // 显式 t.skip(reason) → skipped
6
+ // 否则 → passed
7
+ // errored 压过一切(执行证据已不可信);failed 压过 skipped(t.skip 不掩盖已记录的硬失败)。
2
8
 
3
- import type { AssertionResult, Verdict } from "../types.ts";
9
+ import type { AssertionResult, AttemptError, Verdict } from "../types.ts";
4
10
 
5
11
  export function computeVerdict(input: {
6
- error?: string;
12
+ error?: AttemptError;
7
13
  assertions: readonly AssertionResult[];
8
14
  skipReason?: string;
9
15
  strict?: boolean;
10
16
  }): Verdict {
11
17
  if (input.error !== undefined) return "errored";
12
18
 
19
+ // 作者写下的每条断言默认都要求可评估:非 optional 的 unavailable 使 attempt errored,
20
+ // 不分 gate / soft——「soft 全部评不了但 attempt 还绿着」是没有测量的绿,不允许出现。
13
21
  for (const a of input.assertions) {
14
- if (a.passed) continue;
22
+ if (a.outcome === "unavailable" && !a.optional) return "errored";
23
+ }
24
+
25
+ for (const a of input.assertions) {
26
+ if (a.outcome !== "failed") continue;
15
27
  if (a.severity === "gate" || input.strict) return "failed";
16
28
  }
17
29
 
@@ -1,4 +1,4 @@
1
- // CLI 表格(runner/reporters/table.ts)与 view 榜单(view/aggregate.ts)共用的聚合小工具。
1
+ // report 聚合(report/aggregate.ts)与 view 榜单(view/app/lib/rows.ts)共用的聚合小工具。
2
2
  // 实验标签推导、token/成本求和、verdict 排序各只有一份 —— 否则同一个实验在终端和网页上
3
3
  // 会显示成两个名字 / 两组数。保持环境无关(纯函数,只 type import)。
4
4
 
@@ -56,11 +56,12 @@ export function evalPrefixPredicate(evals?: string | string[]): (id: string) =>
56
56
 
57
57
  /** 无 experimentId 时的兜底标签。 */
58
58
  export function fallbackExperimentLabel(result: {
59
+ experimentId?: string;
59
60
  experiment?: ExperimentRunInfo;
60
61
  agent: string;
61
62
  model?: string;
62
63
  }): string {
63
- if (result.experiment?.id) return displayExperimentName(result.experiment.id) ?? result.experiment.id;
64
+ if (result.experimentId) return displayExperimentName(result.experimentId) ?? result.experimentId;
64
65
  if (result.model) return `${result.agent}/${result.model}`;
65
66
  return result.agent || "ad hoc run";
66
67
  }
@@ -33,6 +33,37 @@ export interface SourceArtifact {
33
33
  /** 通用清理闭包(setup 返回值 / teardown 的形状),异步同步皆可,统一在 finally 里执行。 */
34
34
  export type Cleanup = () => Promise<void> | void;
35
35
 
36
+ /** `ScopedFeedback.progress` 的入参:此刻正在做什么(短命状态,可被后续更新覆盖)。 */
37
+ export interface ProgressUpdate {
38
+ message: string;
39
+ current?: number;
40
+ total?: number;
41
+ }
42
+
43
+ /** `ScopedFeedback.diagnostic` 的入参:运行结束后仍应保留的问题(永久事件)。 */
44
+ export interface DiagnosticInput {
45
+ code: string;
46
+ level: "warning" | "error";
47
+ message: string;
48
+ data?: Readonly<Record<string, JsonValue>>;
49
+ /** 并发 attempt 产生同一问题时的去重键;相同 key 折叠成一条并累计次数。 */
50
+ dedupeKey?: string;
51
+ }
52
+
53
+ /**
54
+ * 作用域反馈 API(见 docs/feature/experiments/library.md「生命周期代码怎样向这次运行反馈」):
55
+ * sandbox provider、sandbox hook、eval 与 Agent Adapter 从 runner 注入的上下文获得同一套入口。
56
+ * - `progress` 是短命状态:Human profile 更新 active 行,Agent/CI 不逐条打印,不进最终结果;
57
+ * - `diagnostic` 是永久事件:进 Human/Agent/CI 的永久输出流并落进 attempt 的 diagnostics;
58
+ * 即使 level 为 "error" 也不自动改变 verdict(要 errored 抛异常,要 failed 用断言)。
59
+ * 两个方法都不接受 phase / scope / 颜色 / 输出流——runner 知道当前回调属于哪个生命周期阶段,
60
+ * 调用方不能冒充其它阶段。
61
+ */
62
+ export interface ScopedFeedback {
63
+ progress(update: ProgressUpdate): void;
64
+ diagnostic(input: DiagnosticInput): void;
65
+ }
66
+
36
67
  /**
37
68
  * 可本地化文案:纯字符串,或按 locale 代码(如 "en"、"zh-CN")映射多语言。
38
69
  * view 按当前界面语言挑一条,挑不到回退到 en / 第一条。
@@ -58,14 +58,14 @@ export function evalHistory(exp: Experiment, evalId: string): EvalHistoryRow[] {
58
58
  if (c !== null) cost = (cost ?? 0) + c;
59
59
  }
60
60
  const latest = fresh[fresh.length - 1];
61
- const failed = latest.result.assertions.find((a) => !a.passed);
61
+ const failed = latest.result.assertions.find((a) => a.outcome !== "passed");
62
62
  rows.push({
63
63
  startedAt: snapshot.startedAt,
64
64
  verdict: foldEvalVerdict(fresh.map((a) => a.result)),
65
65
  attempts: fresh.length,
66
66
  costUSD: cost,
67
67
  ...(failed ? { failedAssertion: `${failed.severity} ${failed.name}` } : {}),
68
- ...(latest.result.error !== undefined ? { error: latest.result.error } : {}),
68
+ ...(latest.result.error !== undefined ? { error: latest.result.error.message } : {}),
69
69
  });
70
70
  }
71
71
  return rows.reverse();
package/src/show/index.ts CHANGED
@@ -50,6 +50,7 @@ import {
50
50
  evalSourceText,
51
51
  executionText,
52
52
  experimentHistoryText,
53
+ timingText,
53
54
  pickDetailAttempt,
54
55
  skippedRunsText,
55
56
  verdictReasonLine,
@@ -60,6 +61,8 @@ export interface ShowFlags {
60
61
  eval?: boolean;
61
62
  /** 该 attempt 的标准执行事件流 + OTel enrichment(证据切面)。 */
62
63
  execution?: boolean;
64
+ /** --timing:默认有界诊断投影;full 逐节点展开。boolean 仅供库调用兼容,等价 summary。 */
65
+ timing?: boolean | "summary" | "full";
63
66
  /** --diff(文件级摘要)。 */
64
67
  diff?: boolean;
65
68
  /** --diff=<路径>(单个文件的完整改动;路径必须 = 连写,位置参数永远留给 eval id 前缀)。 */
@@ -120,7 +123,12 @@ async function show(
120
123
  flags: ShowFlags,
121
124
  io: { out: (s: string) => void; err: (s: string) => void; width: number; now: number },
122
125
  ): Promise<void> {
123
- const evidence = flags.eval === true || flags.execution === true || flags.diff === true || flags.diffPath !== undefined;
126
+ const evidence =
127
+ flags.eval === true ||
128
+ flags.execution === true ||
129
+ (flags.timing !== undefined && flags.timing !== false) ||
130
+ flags.diff === true ||
131
+ flags.diffPath !== undefined;
124
132
 
125
133
  // 组合语义矩阵(docs/feature/reports/show.md「选择结果范围」):--history 与 --report 互斥,先于任何 IO 报出来。
126
134
  if (flags.history && flags.report !== undefined) {
@@ -165,6 +173,12 @@ async function show(
165
173
  const blocks: string[] = [];
166
174
  if (flags.eval) blocks.push(evalSourceText(attemptEvidence, { header, artifactPath, width: io.width }));
167
175
  if (flags.execution) blocks.push(executionText(attemptEvidence, { header, artifactPath, width: io.width }));
176
+ if (flags.timing) blocks.push(timingText(attemptEvidence, {
177
+ header,
178
+ artifactPath,
179
+ width: io.width,
180
+ mode: flags.timing === "full" ? "full" : "summary",
181
+ }));
168
182
  if (flags.diff || flags.diffPath !== undefined) {
169
183
  blocks.push(diffText({ header, diff: attemptEvidence.diff, artifactPath, file: flags.diffPath }));
170
184
  }
@@ -228,6 +242,12 @@ async function show(
228
242
  const blocks: string[] = [];
229
243
  if (flags.eval) blocks.push(evalSourceText(attemptEvidence, { header, artifactPath, width: io.width }));
230
244
  if (flags.execution) blocks.push(executionText(attemptEvidence, { header, artifactPath, width: io.width }));
245
+ if (flags.timing) blocks.push(timingText(attemptEvidence, {
246
+ header,
247
+ artifactPath,
248
+ width: io.width,
249
+ mode: flags.timing === "full" ? "full" : "summary",
250
+ }));
231
251
  if (flags.diff || flags.diffPath !== undefined) {
232
252
  blocks.push(diffText({ header, diff: attemptEvidence.diff, artifactPath, file: flags.diffPath }));
233
253
  }