niceeval 0.6.1 → 0.7.0
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.
- package/INDEX.md +23 -23
- package/README.zh.md +6 -6
- package/dist/agents/types.d.ts +69 -7
- package/dist/context/types.d.ts +32 -12
- package/dist/i18n/en.d.ts +54 -0
- package/dist/i18n/zh-CN.d.ts +57 -3
- package/dist/o11y/types.d.ts +16 -2
- package/dist/report/aggregate.d.ts +32 -24
- package/dist/report/aggregate.js +158 -50
- package/dist/report/built-in/index.d.ts +2 -0
- package/dist/report/built-in/index.js +8 -0
- package/dist/report/components.d.ts +93 -160
- package/dist/report/components.js +377 -114
- package/dist/report/compute.d.ts +87 -81
- package/dist/report/compute.js +597 -417
- package/dist/report/flag.d.ts +32 -6
- package/dist/report/flag.js +92 -4
- package/dist/report/format.d.ts +19 -11
- package/dist/report/format.js +30 -13
- package/dist/report/index.d.ts +16 -16
- package/dist/report/index.js +20 -21
- package/dist/report/load.js +3 -2
- package/dist/report/locale.d.ts +57 -33
- package/dist/report/locale.js +122 -56
- package/dist/report/metrics.d.ts +23 -4
- package/dist/report/metrics.js +110 -25
- package/dist/report/primitives.d.ts +48 -15
- package/dist/report/primitives.js +135 -26
- package/dist/report/react/AttemptList.d.ts +9 -7
- package/dist/report/react/AttemptList.js +17 -10
- package/dist/report/react/DeltaTable.js +19 -18
- package/dist/report/react/EvalList.d.ts +4 -4
- package/dist/report/react/EvalList.js +0 -0
- package/dist/report/react/ExperimentComparison.d.ts +10 -0
- package/dist/report/react/ExperimentComparison.js +12 -0
- package/dist/report/react/ExperimentList.d.ts +4 -3
- package/dist/report/react/ExperimentList.js +17 -18
- package/dist/report/react/MetricBars.js +5 -4
- package/dist/report/react/MetricLine.js +12 -5
- package/dist/report/react/MetricMatrix.js +1 -1
- package/dist/report/react/MetricScatter.js +59 -28
- package/dist/report/react/MetricTable.js +2 -12
- package/dist/report/react/ScopeSummary.d.ts +10 -0
- package/dist/report/react/ScopeSummary.js +17 -0
- package/dist/report/react/Scoreboard.js +6 -6
- package/dist/report/react/cell.js +2 -2
- package/dist/report/react/chart-math.d.ts +23 -6
- package/dist/report/react/chart-math.js +71 -19
- package/dist/report/react/fixtures.d.ts +5 -9
- package/dist/report/react/fixtures.js +110 -147
- package/dist/report/react/index.d.ts +15 -5
- package/dist/report/react/index.js +18 -7
- package/dist/report/report.d.ts +137 -16
- package/dist/report/report.js +259 -28
- package/dist/report/text/faces.d.ts +17 -19
- package/dist/report/text/faces.js +253 -184
- package/dist/report/text/plot.js +1 -1
- package/dist/report/text/table.js +38 -7
- package/dist/report/tree.d.ts +90 -40
- package/dist/report/tree.js +252 -94
- package/dist/report/types.d.ts +247 -284
- package/dist/report/types.js +4 -3
- package/dist/report/web.d.ts +21 -5
- package/dist/report/web.js +42 -16
- package/dist/results/select.d.ts +38 -16
- package/dist/results/select.js +73 -25
- package/dist/results/types.d.ts +49 -14
- package/dist/runner/feedback/sink.d.ts +110 -0
- package/dist/runner/types.d.ts +513 -22
- package/dist/sandbox/docker.d.ts +23 -2
- package/dist/sandbox/e2b.d.ts +15 -1
- package/dist/sandbox/errors.d.ts +30 -3
- package/dist/sandbox/io-retry.d.ts +17 -0
- package/dist/sandbox/registry.d.ts +2 -0
- package/dist/sandbox/resolve.d.ts +18 -5
- package/dist/sandbox/retry.d.ts +11 -1
- package/dist/sandbox/types.d.ts +39 -5
- package/dist/sandbox/vercel.d.ts +7 -1
- package/dist/scoring/coverage.d.ts +30 -0
- package/dist/scoring/display.d.ts +21 -0
- package/dist/scoring/display.js +120 -0
- package/dist/scoring/types.d.ts +103 -20
- package/dist/shared/aggregate.d.ts +4 -2
- package/dist/shared/aggregate.js +8 -7
- package/dist/shared/types.d.ts +28 -0
- package/dist/tty-line.d.ts +0 -4
- package/dist/util.d.ts +23 -0
- package/docs-site/zh/README.md +44 -0
- package/docs-site/zh/examples/ai-agent-application.mdx +63 -0
- package/docs-site/zh/examples/coding-agent-extensions.mdx +57 -0
- package/docs-site/zh/examples/index.mdx +50 -0
- package/docs-site/zh/{concepts → explanation}/adapter.mdx +31 -13
- package/docs-site/zh/{concepts → explanation}/assert.mdx +7 -7
- package/docs-site/zh/{concepts → explanation}/drive.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/evals.mdx +4 -4
- package/docs-site/zh/{concepts → explanation}/experiment.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/hitl.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/judge.mdx +5 -5
- package/docs-site/zh/{concepts → explanation}/overview.mdx +11 -11
- package/docs-site/zh/{guides → explanation}/runner.mdx +18 -8
- package/docs-site/zh/{concepts → explanation}/tier.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/agent-feedback-loop.mdx +35 -33
- package/docs-site/zh/{guides → how-to}/authoring.mdx +35 -2
- package/docs-site/zh/{guides → how-to}/ci-integration.mdx +23 -12
- package/docs-site/zh/{guides → how-to}/connect-otel.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/connect-your-agent.mdx +47 -21
- package/docs-site/zh/{guides → how-to}/custom-reports.mdx +34 -39
- package/docs-site/zh/{guides → how-to}/dataset-fanout.mdx +25 -3
- package/docs-site/zh/{guides → how-to}/experiments.mdx +12 -5
- package/docs-site/zh/how-to/publish-report.mdx +105 -0
- package/docs-site/zh/{guides → how-to}/reporters.mdx +2 -2
- package/docs-site/zh/{guides → how-to}/sandbox-agent.mdx +56 -7
- package/docs-site/zh/how-to/sandbox-providers.mdx +350 -0
- package/docs-site/zh/{guides → how-to}/scoring-guide.mdx +4 -4
- package/docs-site/zh/{guides → how-to}/viewing-results.mdx +82 -39
- package/docs-site/zh/{guides → how-to}/write-experiment.mdx +6 -4
- package/docs-site/zh/{guides → how-to}/write-send.mdx +30 -14
- package/docs-site/zh/index.mdx +24 -26
- package/docs-site/zh/introduction.mdx +8 -8
- package/docs-site/zh/reference/builtin-agents.mdx +32 -5
- package/docs-site/zh/reference/capabilities.mdx +8 -8
- package/docs-site/zh/reference/cli.mdx +40 -12
- package/docs-site/zh/reference/define-agent.mdx +58 -5
- package/docs-site/zh/reference/define-config.mdx +1 -1
- package/docs-site/zh/reference/define-eval.mdx +42 -9
- package/docs-site/zh/reference/events.mdx +3 -3
- package/docs-site/zh/reference/expect.mdx +26 -1
- package/docs-site/zh/{guides → reference}/official-adapters.mdx +32 -8
- package/docs-site/zh/{guides → reference}/report-components.mdx +45 -33
- package/docs-site/zh/{guides → reference}/results-data.mdx +21 -13
- package/docs-site/zh/troubleshooting/debug-sandbox.mdx +57 -0
- package/docs-site/zh/troubleshooting/debugging.mdx +212 -0
- package/docs-site/zh/{quickstart.mdx → tutorials/quickstart.mdx} +5 -17
- package/package.json +10 -2
- package/src/agents/ai-sdk-otel.test.ts +1 -0
- package/src/agents/ai-sdk.test.ts +3 -0
- package/src/agents/ai-sdk.ts +3 -0
- package/src/agents/bub-install-spec.test.ts +34 -0
- package/src/agents/bub-install-spec.ts +32 -0
- package/src/agents/bub.ts +31 -32
- package/src/agents/claude-code.test.ts +130 -9
- package/src/agents/claude-code.ts +76 -4
- package/src/agents/codex.test.ts +189 -40
- package/src/agents/codex.ts +155 -14
- package/src/agents/coding-cli-versions.test.ts +15 -0
- package/src/agents/coding-cli-versions.ts +3 -0
- package/src/agents/index.ts +13 -2
- package/src/agents/langgraph.test.ts +204 -0
- package/src/agents/langgraph.ts +495 -0
- package/src/agents/marketplace.ts +85 -0
- package/src/agents/native-config.test.ts +179 -0
- package/src/agents/native-config.ts +267 -0
- package/src/agents/openai-compat.test.ts +1 -0
- package/src/agents/openai-compat.ts +1 -1
- package/src/agents/openclaw.test.ts +31 -0
- package/src/agents/openclaw.ts +171 -0
- package/src/agents/plugin-config.test.ts +1 -0
- package/src/agents/sdk-streams.test.ts +79 -0
- package/src/agents/sdk-streams.ts +55 -10
- package/src/agents/skills.test.ts +1 -0
- package/src/agents/streaming.test.ts +3 -9
- package/src/agents/streaming.ts +2 -2
- package/src/agents/types.ts +71 -8
- package/src/agents/ui-message-stream.test.ts +3 -0
- package/src/cli.ts +446 -124
- package/src/context/context.test.ts +51 -12
- package/src/context/context.ts +162 -30
- package/src/context/session.test.ts +2 -1
- package/src/context/session.ts +115 -7
- package/src/context/types.ts +30 -12
- package/src/define.test.ts +13 -8
- package/src/define.ts +25 -4
- package/src/expect/index.ts +53 -23
- package/src/i18n/en.ts +81 -17
- package/src/i18n/zh-CN.ts +80 -17
- package/src/o11y/cost.test.ts +1 -0
- package/src/o11y/execution-tree.test.ts +1 -20
- package/src/o11y/otlp/mappers/claude-code.test.ts +1 -0
- package/src/o11y/otlp/parse.test.ts +1 -0
- package/src/o11y/otlp/turn-otel.test.ts +1 -0
- package/src/o11y/parsers/bub.test.ts +1 -0
- package/src/o11y/parsers/claude-code.test.ts +1 -34
- package/src/o11y/parsers/openclaw.test.ts +154 -0
- package/src/o11y/parsers/openclaw.ts +310 -0
- package/src/o11y/prices.json +746 -311
- package/src/o11y/tool-names.test.ts +1 -0
- package/src/o11y/types.ts +16 -2
- package/src/report/aggregate.ts +178 -61
- package/src/report/built-in/index.tsx +9 -0
- package/src/report/components.tsx +625 -279
- package/src/report/compute.ts +723 -491
- package/src/report/dual-render.test.tsx +741 -1024
- package/src/report/flag.ts +104 -12
- package/src/report/format.ts +32 -12
- package/src/report/index.ts +119 -46
- package/src/report/load.ts +3 -2
- package/src/report/locale.ts +136 -65
- package/src/report/metrics.ts +108 -25
- package/src/report/primitives.tsx +196 -45
- package/src/report/react/AttemptList.tsx +30 -43
- package/src/report/react/DeltaTable.tsx +63 -45
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentComparison.tsx +73 -0
- package/src/report/react/ExperimentList.tsx +50 -32
- package/src/report/react/MetricBars.tsx +5 -4
- package/src/report/react/MetricLine.tsx +13 -8
- package/src/report/react/MetricMatrix.tsx +2 -2
- package/src/report/react/MetricScatter.tsx +86 -34
- package/src/report/react/MetricTable.tsx +4 -76
- package/src/report/react/ScopeSummary.tsx +86 -0
- package/src/report/react/Scoreboard.tsx +28 -10
- package/src/report/react/cell.tsx +2 -2
- package/src/report/react/chart-math.test.ts +85 -0
- package/src/report/react/chart-math.ts +101 -22
- package/src/report/react/enhance.js +89 -5
- package/src/report/react/fixtures.ts +114 -154
- package/src/report/react/index.tsx +24 -39
- package/src/report/react/render.test.tsx +138 -158
- package/src/report/react/styles.css +243 -82
- package/src/report/report.test.ts +779 -841
- package/src/report/report.ts +423 -41
- package/src/report/text/faces.ts +290 -193
- package/src/report/text/plot.ts +1 -1
- package/src/report/text/table.ts +44 -7
- package/src/report/tree.ts +362 -104
- package/src/report/types.ts +261 -271
- package/src/report/web.ts +63 -20
- package/src/results/annotated-source.test.ts +62 -9
- package/src/results/annotated-source.ts +64 -6
- package/src/results/attempt-evidence.test.ts +13 -11
- package/src/results/attempt-evidence.ts +20 -13
- package/src/results/attempt-source.ts +6 -3
- package/src/results/copy.ts +150 -60
- package/src/results/host-equivalence.test.ts +34 -20
- package/src/results/index.ts +12 -4
- package/src/results/locator.test.ts +1 -22
- package/src/results/open.ts +15 -5
- package/src/results/publish.ts +149 -0
- package/src/results/results.test.ts +89 -54
- package/src/results/select.ts +104 -34
- package/src/results/truncate.ts +90 -0
- package/src/results/types.ts +43 -14
- package/src/results/writer.ts +31 -13
- package/src/runner/attempt.test.ts +138 -7
- package/src/runner/attempt.ts +603 -104
- package/src/runner/discover.test.ts +47 -0
- package/src/runner/discover.ts +36 -2
- package/src/runner/eval-source.test.ts +1 -27
- package/src/runner/feedback/agent.test.ts +504 -0
- package/src/runner/feedback/agent.ts +409 -0
- package/src/runner/feedback/ci.test.ts +562 -0
- package/src/runner/feedback/ci.ts +401 -0
- package/src/runner/feedback/coordinator.test.ts +317 -0
- package/src/runner/feedback/coordinator.ts +397 -0
- package/src/runner/feedback/failure.ts +40 -0
- package/src/runner/feedback/human.test.ts +616 -0
- package/src/runner/feedback/human.ts +535 -0
- package/src/runner/feedback/index.ts +66 -0
- package/src/runner/feedback/io.ts +78 -0
- package/src/runner/feedback/profile.test.ts +50 -0
- package/src/runner/feedback/profile.ts +58 -0
- package/src/runner/feedback/reducer.test.ts +395 -0
- package/src/runner/feedback/reducer.ts +260 -0
- package/src/runner/feedback/renderer.ts +82 -0
- package/src/runner/feedback/sink.ts +203 -0
- package/src/runner/feedback/testing.ts +106 -0
- package/src/runner/ledger.test.ts +230 -0
- package/src/runner/ledger.ts +329 -0
- package/src/runner/report.test.ts +128 -3
- package/src/runner/report.ts +33 -9
- package/src/runner/reporters/artifacts.ts +8 -2
- package/src/runner/reporters/braintrust.test.ts +8 -7
- package/src/runner/reporters/braintrust.ts +9 -2
- package/src/runner/reporters/index.ts +2 -2
- package/src/runner/reporters/json.test.ts +162 -0
- package/src/runner/reporters/json.ts +35 -8
- package/src/runner/reporters/shared.ts +1 -5
- package/src/runner/run.test.ts +760 -3
- package/src/runner/run.ts +243 -37
- package/src/runner/sandbox-prep.ts +3 -42
- package/src/runner/timing.ts +158 -0
- package/src/runner/types.ts +518 -22
- package/src/sandbox/checkpoint.test.ts +55 -0
- package/src/sandbox/checkpoint.ts +29 -8
- package/src/sandbox/cli-commands.ts +407 -0
- package/src/sandbox/docker.ts +115 -16
- package/src/sandbox/e2b-agent-template.test.ts +56 -0
- package/src/sandbox/e2b-agent-template.ts +94 -0
- package/src/sandbox/e2b.ts +74 -9
- package/src/sandbox/errors.ts +111 -4
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/io-retry.test.ts +58 -0
- package/src/sandbox/io-retry.ts +45 -0
- package/src/sandbox/keep-registry.test.ts +86 -0
- package/src/sandbox/keep-registry.ts +142 -0
- package/src/sandbox/keep.ts +178 -0
- package/src/sandbox/paths.test.ts +1 -0
- package/src/sandbox/paths.ts +19 -8
- package/src/sandbox/registry.ts +20 -3
- package/src/sandbox/resolve.ts +76 -11
- package/src/sandbox/retry.test.ts +70 -0
- package/src/sandbox/retry.ts +46 -4
- package/src/sandbox/types.ts +44 -6
- package/src/sandbox/vercel.ts +43 -20
- package/src/scoring/collector.ts +60 -17
- package/src/scoring/coverage.ts +95 -0
- package/src/scoring/diff.ts +81 -0
- package/src/scoring/display.test.ts +121 -0
- package/src/scoring/display.ts +133 -0
- package/src/scoring/evidence.test.ts +189 -0
- package/src/scoring/judge.test.ts +142 -0
- package/src/scoring/judge.ts +15 -18
- package/src/scoring/scoped.ts +217 -50
- package/src/scoring/types.ts +117 -20
- package/src/scoring/verdict.ts +16 -4
- package/src/shared/aggregate.ts +8 -6
- package/src/shared/types.ts +31 -0
- package/src/show/compose.ts +50 -67
- package/src/show/index.ts +127 -56
- package/src/show/render.ts +662 -131
- package/src/show/report-host.test.ts +188 -0
- package/src/show/report-host.ts +375 -0
- package/src/show/show.test.ts +320 -54
- package/src/tty-line.ts +8 -26
- package/src/util.test.ts +1 -0
- package/src/util.ts +41 -0
- package/src/view/app/App.test.tsx +69 -0
- package/src/view/app/App.tsx +144 -48
- package/src/view/app/components/AttemptModal.tsx +423 -11
- package/src/view/app/components/CodeView.tsx +41 -14
- package/src/view/app/components/CopyControls.tsx +2 -2
- package/src/view/app/i18n.ts +37 -17
- package/src/view/app/lib/attempt-route.test.ts +1 -0
- package/src/view/app/lib/verdict.ts +7 -9
- package/src/view/app/main.tsx +13 -8
- package/src/view/app/pages/{RunsPage.tsx → AttemptsPage.tsx} +6 -6
- package/src/view/app/types.ts +4 -1
- package/src/view/artifact-serving.test.ts +2 -1
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +17 -17
- package/src/view/data.test.ts +10 -3
- package/src/view/data.ts +155 -49
- package/src/view/index.ts +56 -41
- package/src/view/server.ts +37 -15
- package/src/view/shared/types.ts +34 -5
- package/src/view/styles.css +227 -0
- package/src/view/view-report.test.ts +167 -62
- package/dist/report/built-ins/experiment-comparison.d.ts +0 -1
- package/dist/report/built-ins/experiment-comparison.js +0 -13
- package/dist/report/built-ins/index.d.ts +0 -1
- package/dist/report/built-ins/index.js +0 -2
- package/dist/report/react/GroupSummary.d.ts +0 -8
- package/dist/report/react/GroupSummary.js +0 -8
- package/dist/report/react/RunOverview.d.ts +0 -8
- package/dist/report/react/RunOverview.js +0 -12
- package/docs-site/zh/example/ai-agent-application.mdx +0 -152
- package/docs-site/zh/example/claude-code-codex-plugin.mdx +0 -167
- package/docs-site/zh/example/claude-code-codex-skill.mdx +0 -152
- package/docs-site/zh/example/showcase.mdx +0 -39
- package/docs-site/zh/guides/publish-report.mdx +0 -91
- package/docs-site/zh/guides/sandbox-providers.mdx +0 -102
- package/src/report/built-in-user-parity.test.tsx +0 -640
- package/src/report/built-ins/experiment-comparison.tsx +0 -19
- package/src/report/built-ins/index.ts +0 -2
- package/src/report/react/GroupSummary.tsx +0 -66
- package/src/report/react/RunOverview.tsx +0 -109
- package/src/runner/reporters/console.ts +0 -70
- package/src/runner/reporters/live.test.ts +0 -56
- package/src/runner/reporters/live.ts +0 -247
- package/src/runner/reporters/quiet.test.ts +0 -66
- package/src/runner/reporters/quiet.ts +0 -49
- package/src/runner/reporters/table.ts +0 -277
- /package/docs-site/zh/{example/tier1-ai-sdk-v7.mdx → examples/integrations/ai-sdk-v7.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-claude-sdk.mdx → examples/integrations/claude-sdk.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-codex-sdk.mdx → examples/integrations/codex-sdk.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-langgraph.mdx → examples/integrations/langgraph.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-pi-sdk.mdx → examples/integrations/pi-sdk.mdx} +0 -0
- /package/docs-site/zh/{guides → how-to}/fixtures.mdx +0 -0
package/dist/report/types.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// niceeval/report 的公开类型:指标(Metric)、维度(Dimension / flag())
|
|
2
|
-
//
|
|
3
|
-
// 这些不是持久化格式,没有 format / schemaVersion 信封,兼容性跟随 npm
|
|
1
|
+
// niceeval/report 的公开类型:指标(Metric)、维度(Dimension / flag() / runConfig())与
|
|
2
|
+
// 计算函数产物(即组件的 data)。数据契约照 docs/feature/reports/library/ 各分篇;
|
|
3
|
+
// 这些不是持久化格式,没有 format / schemaVersion 信封,兼容性跟随 npm 版本
|
|
4
|
+
// (组件消费 data 时校验结构,不符按完整用户反馈报错并提示版本漂移)。
|
|
4
5
|
export {};
|
package/dist/report/web.d.ts
CHANGED
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
import type { AttemptLocator } from "../results/locator.ts";
|
|
2
|
+
import type { Scope } from "../results/types.ts";
|
|
2
3
|
import { type ReportLocale } from "./locale.ts";
|
|
3
|
-
import
|
|
4
|
+
import { type ReportDefinition, type ReportHostContext } from "./report.ts";
|
|
4
5
|
export interface StaticHtmlOptions {
|
|
6
|
+
/** 渲染哪一页;缺省第一页。未命中抛 ReportPageNotFoundError。 */
|
|
7
|
+
pageId?: string;
|
|
5
8
|
/** 证据室深链;缺省用 view 的 attempt 路由 `#/attempt/@<locator>`(单段、不透明)。 */
|
|
6
9
|
attemptHref?: (locator: AttemptLocator) => string;
|
|
7
10
|
/** 官方组件 chrome 文案的 locale;默认 "en"。 */
|
|
8
11
|
locale?: ReportLocale;
|
|
9
12
|
}
|
|
10
13
|
/**
|
|
11
|
-
*
|
|
12
|
-
* web 面;
|
|
13
|
-
*
|
|
14
|
+
* web 宿主的装载语义:选页 → resolve(组合展开 + spec 取数,唯一的 await 边界)→
|
|
15
|
+
* 树校验(与 text 宿主同一遍)→ 静态渲染 web 面;Scope 有挑选警告时在报告顶部前置
|
|
16
|
+
* 一块警告 HTML(宿主是 warning 的唯一呈现者,组件数据不复制 warning)。
|
|
14
17
|
*/
|
|
15
|
-
export declare function renderReportToStaticHtml(definition: ReportDefinition, ctx:
|
|
18
|
+
export declare function renderReportToStaticHtml(definition: ReportDefinition, ctx: ReportHostContext, options?: StaticHtmlOptions): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* 渲染一页报告树的 web 面(宿主逐页调用;页选择归宿主):resolve → validate → 静态渲染。
|
|
21
|
+
* Scope 有挑选警告时在页顶前置警告块(带 command 的警告渲染为可复制命令)——宿主是
|
|
22
|
+
* warning 的唯一呈现者,组件数据不复制 warning。ctx.report 是宿主规范化后的声明。
|
|
23
|
+
*/
|
|
24
|
+
export declare function renderReportTreeToStaticHtml(tree: import("./tree.ts").ReportNode, ctx: {
|
|
25
|
+
scope: Scope;
|
|
26
|
+
results: import("../results/types.ts").Results;
|
|
27
|
+
report: import("./report.ts").ReportMeta;
|
|
28
|
+
}, options?: {
|
|
29
|
+
attemptHref?: (locator: AttemptLocator) => string;
|
|
30
|
+
locale?: ReportLocale;
|
|
31
|
+
}): Promise<string>;
|
package/dist/report/web.js
CHANGED
|
@@ -3,35 +3,61 @@
|
|
|
3
3
|
// 所以本文件不从 niceeval/report 的入口 re-export —— 宿主与测试按源路径 import。
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
6
|
-
import { resolveReportTree, runWithWebContext, validateReportTree } from "./tree.js";
|
|
6
|
+
import { resolveReportTree, runWithWebContext, validateReportTree, ResolveMemo, } from "./tree.js";
|
|
7
7
|
import { DEFAULT_REPORT_LOCALE } from "./locale.js";
|
|
8
|
+
import { buildReportMeta, pickReportPage } from "./report.js";
|
|
8
9
|
/**
|
|
9
|
-
* 挑选警告的 HTML
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* message
|
|
10
|
+
* 挑选警告的 HTML 形态:宿主级前置块(`.nre nre-report-warnings` 外壳内一个
|
|
11
|
+
* `ul.nre-warnings` + `li.nre-warning[data-kind]`,复用 styles.css 已有样式)。
|
|
12
|
+
* 带 `command` 的警告把命令渲染为可复制块(`.nre-warning-command`);无 command 的
|
|
13
|
+
* 只显示 message,不硬造动作。经 renderToStaticMarkup 走 React,文本自动转义。
|
|
13
14
|
*/
|
|
14
|
-
function
|
|
15
|
-
return renderToStaticMarkup(React.createElement("div", { className: "nre nre-report-warnings" }, React.createElement("ul", { className: "nre-warnings" }, warnings.map((w, i) => React.createElement("li", { key: i, className: "nre-warning", "data-kind": w.kind }, w.message
|
|
15
|
+
function renderScopeWarningsHtml(scope) {
|
|
16
|
+
return renderToStaticMarkup(React.createElement("div", { className: "nre nre-report-warnings" }, React.createElement("ul", { className: "nre-warnings" }, scope.warnings.map((w, i) => React.createElement("li", { key: i, className: "nre-warning", "data-kind": w.kind }, w.message, "command" in w && w.command
|
|
17
|
+
? React.createElement("code", { className: "nre-warning-command", "data-nre-copy": w.command }, w.command)
|
|
18
|
+
: null)))));
|
|
16
19
|
}
|
|
17
20
|
/**
|
|
18
|
-
*
|
|
19
|
-
* web 面;
|
|
20
|
-
*
|
|
21
|
+
* web 宿主的装载语义:选页 → resolve(组合展开 + spec 取数,唯一的 await 边界)→
|
|
22
|
+
* 树校验(与 text 宿主同一遍)→ 静态渲染 web 面;Scope 有挑选警告时在报告顶部前置
|
|
23
|
+
* 一块警告 HTML(宿主是 warning 的唯一呈现者,组件数据不复制 warning)。
|
|
21
24
|
*/
|
|
22
25
|
export async function renderReportToStaticHtml(definition, ctx, options) {
|
|
23
|
-
const
|
|
24
|
-
const
|
|
26
|
+
const page = pickReportPage(definition, options?.pageId);
|
|
27
|
+
const meta = buildReportMeta(definition, ctx.scope, page.id);
|
|
28
|
+
const resolved = await resolveReportTree(page.content, {
|
|
29
|
+
scope: ctx.scope,
|
|
30
|
+
results: ctx.results,
|
|
31
|
+
report: meta,
|
|
32
|
+
memo: new ResolveMemo(),
|
|
33
|
+
});
|
|
25
34
|
validateReportTree(resolved);
|
|
26
35
|
const webCtx = {
|
|
27
36
|
attemptHref: options?.attemptHref ?? ((locator) => `#/attempt/${locator}`),
|
|
28
37
|
locale: options?.locale ?? DEFAULT_REPORT_LOCALE,
|
|
29
38
|
};
|
|
30
39
|
const body = runWithWebContext(webCtx, () => renderToStaticMarkup(resolved));
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
const warnings = ctx.scope.warnings.length > 0 ? renderScopeWarningsHtml(ctx.scope) : "";
|
|
41
|
+
return warnings + body;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 渲染一页报告树的 web 面(宿主逐页调用;页选择归宿主):resolve → validate → 静态渲染。
|
|
45
|
+
* Scope 有挑选警告时在页顶前置警告块(带 command 的警告渲染为可复制命令)——宿主是
|
|
46
|
+
* warning 的唯一呈现者,组件数据不复制 warning。ctx.report 是宿主规范化后的声明。
|
|
47
|
+
*/
|
|
48
|
+
export async function renderReportTreeToStaticHtml(tree, ctx, options) {
|
|
49
|
+
const resolved = await resolveReportTree(tree, {
|
|
50
|
+
scope: ctx.scope,
|
|
51
|
+
results: ctx.results,
|
|
52
|
+
report: ctx.report,
|
|
53
|
+
memo: new ResolveMemo(),
|
|
34
54
|
});
|
|
35
|
-
|
|
55
|
+
validateReportTree(resolved);
|
|
56
|
+
const webCtx = {
|
|
57
|
+
attemptHref: options?.attemptHref ?? ((locator) => `#/attempt/${locator}`),
|
|
58
|
+
locale: options?.locale ?? DEFAULT_REPORT_LOCALE,
|
|
59
|
+
};
|
|
60
|
+
const body = runWithWebContext(webCtx, () => renderToStaticMarkup(resolved));
|
|
61
|
+
const warnings = ctx.scope.warnings.length > 0 ? renderScopeWarningsHtml(ctx.scope) : "";
|
|
36
62
|
return warnings + body;
|
|
37
63
|
}
|
package/dist/results/select.d.ts
CHANGED
|
@@ -1,37 +1,59 @@
|
|
|
1
|
-
import type { AttemptHandle, DedupeWarning, Experiment, Results,
|
|
1
|
+
import type { AttemptHandle, DedupeWarning, Experiment, Results, Scope, ScopeWarning, Snapshot } from "./types.ts";
|
|
2
|
+
import type { ExperimentRunInfo, JsonValue } from "../types.ts";
|
|
2
3
|
/** Results.latest() 的实现:每个实验取最新一次快照(= exp.snapshots[0]),生成挑选警告。 */
|
|
3
4
|
export declare function selectLatest(experiments: Experiment[], opts?: {
|
|
4
5
|
experiments?: string | string[];
|
|
5
|
-
}):
|
|
6
|
+
}): Scope;
|
|
6
7
|
/** selectCurrentResults 的范围输入:experiment id 前缀与 eval id 前缀,都可缺省。 */
|
|
7
8
|
export interface ResultScope {
|
|
8
9
|
/** experiment id 前缀(--experiment),分段匹配语义同 filterExperiments。 */
|
|
9
|
-
experiment?: string;
|
|
10
|
-
/** eval id 前缀(位置参数),收窄
|
|
10
|
+
experiment?: string | string[];
|
|
11
|
+
/** eval id 前缀(位置参数),收窄 Scope 覆盖的 eval;覆盖警告分母同步收窄到范围内。 */
|
|
11
12
|
patterns?: string[];
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
* current() 跨快照拼接的可比性前提所比较的字段集(docs/feature/results/library.md
|
|
16
|
+
* 「官方现刻水位」):会改变单题被测行为或判定的字段。runs / earlyExit / maxConcurrency /
|
|
17
|
+
* selectedEvalIds / evalFilterFingerprint / description 是编排与选题字段,不参与比较。
|
|
18
|
+
*/
|
|
19
|
+
export interface ComparabilityConfig {
|
|
20
|
+
agent: string;
|
|
21
|
+
model?: string;
|
|
22
|
+
reasoningEffort?: string;
|
|
23
|
+
flags?: Record<string, JsonValue>;
|
|
24
|
+
budget?: number;
|
|
25
|
+
timeoutMs?: number;
|
|
26
|
+
sandbox?: ExperimentRunInfo["sandbox"];
|
|
27
|
+
}
|
|
28
|
+
/** 一个快照的可比性配置投影;pairsByFlag 与 experimentListData 复用同一字段集。 */
|
|
29
|
+
export declare function comparabilityConfigOf(snapshot: Snapshot): ComparabilityConfig;
|
|
30
|
+
/** 可序列化值的深相等(对象键序无关;undefined 字段与缺席字段等价)。 */
|
|
31
|
+
export declare function deepEqualJson(a: unknown, b: unknown): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* 两个宿主(show / view)共用的现刻水位选择器:每个 experiment × eval 取「包含该 eval 的
|
|
34
|
+
* 最新快照」里的全部 attempt,跨 run 合成。results.latest() 只挑「每实验最新快照」,带 eval
|
|
35
|
+
* 前缀的局部重跑会产出残缺快照;现刻水位承诺「不会因为一次局部重跑变残缺」,所以在实验的
|
|
36
|
+
* 历史快照上逐 eval 向更早的 run 补齐,再把合成好的 Scope 交给宿主注入报告槽。
|
|
37
|
+
*
|
|
38
|
+
* **可比性前提**:每个 experiment 以最新快照的可比性配置(agent / model / reasoningEffort /
|
|
39
|
+
* flags / budget / timeoutMs / sandbox)为基准,只有配置与基准深相等的历史快照才参与补齐;
|
|
40
|
+
* 改过配置后只补跑部分 eval 时,旧配置快照覆盖的其余题不冒充新配置的水位,按 partial-coverage
|
|
41
|
+
* 如实告警。这保证 current() 产出的每个 experiment 只对应一套配置。
|
|
19
42
|
*
|
|
20
43
|
* 同一 eval 的全部 attempts 必须整批取自包含它的最新快照,不把历史快照的 attempts 平铺后
|
|
21
44
|
* 按 eval 聚合——否则会把不同运行的重试混成一次虚构运行。合成快照的 dir/元数据只服务报告
|
|
22
45
|
* 分组与来源展示,证据身份一律来自 attempt 自己的 ref。
|
|
23
|
-
* 警告随 Selection 重算:partial-coverage 的分母 = 已知并集 ∩ 范围(范围收窄时分母同步收窄,
|
|
24
|
-
* 不让范围外的缺口刷屏);stale / unfinished 与 results.latest() 同口径。
|
|
25
46
|
*/
|
|
26
|
-
export declare function selectCurrentResults(results: Results, scope?: ResultScope):
|
|
47
|
+
export declare function selectCurrentResults(results: Results, scope?: ResultScope): Scope;
|
|
27
48
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
49
|
+
* Scope 构造:attempts 按口径物化(快照 attempts 的平铺);filter 只删不换 —— 快照删减,
|
|
50
|
+
* attempts 随之同步修剪,warnings 修剪规则是「experimentId 不在幸存快照中的丢弃,
|
|
51
|
+
* 非实验作用域的保留」(为将来非 per-experiment 的 kind 留位置)。
|
|
30
52
|
*/
|
|
31
|
-
export declare function
|
|
53
|
+
export declare function makeScope(mode: Scope["mode"], snapshots: Snapshot[], warnings: ScopeWarning[]): Scope;
|
|
32
54
|
/**
|
|
33
55
|
* 跨快照聚合前的身份键去重:(experimentId, evalId, attempt, startedAt)。
|
|
34
|
-
*
|
|
56
|
+
* 携带合入会把上一轮已通过的结果原样合入新快照,同一 attempt 因此存在于多份落盘;
|
|
35
57
|
* 重复时保留最新快照里的那份(内容相同,取新快照的副本让 ref 落在最新落盘上;
|
|
36
58
|
* 位置取首次出现处,顺序稳定)。startedAt 缺失时宁可不去重也不误删,记入 warnings。
|
|
37
59
|
*/
|
package/dist/results/select.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
// 快照
|
|
1
|
+
// 快照 Scope 与 attempt 去重(定稿见 docs/feature/results/library.md「选择快照」「官方现刻水位」「身份键与去重」)。
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
// 选择器必须诚实:残缺、落后、未收尾都被算出来,以结构化 warnings 随
|
|
5
|
-
// 渲染与否在消费方(message
|
|
3
|
+
// 选择器长在集合上(results.latest() / results.current()),不是 DSL,只是最常用的两种口径。
|
|
4
|
+
// 选择器必须诚实:残缺、落后、未收尾都被算出来,以结构化 warnings 随 Scope 走 ——
|
|
5
|
+
// 渲染与否在消费方(message 是渲染好的英文句子,以下一步收尾),但缺口不静默。
|
|
6
6
|
import { evalPrefixPredicate } from "../shared/aggregate.js";
|
|
7
7
|
/** Results.latest() 的实现:每个实验取最新一次快照(= exp.snapshots[0]),生成挑选警告。 */
|
|
8
8
|
export function selectLatest(experiments, opts) {
|
|
9
9
|
const selected = filterExperiments(experiments, opts?.experiments);
|
|
10
10
|
const snapshots = selected.map((exp) => exp.latest);
|
|
11
11
|
const warnings = [];
|
|
12
|
-
// stale 的基准:
|
|
12
|
+
// stale 的基准:Scope 中最新的落盘(无阈值,如实触发;要阈值消费方按字段自比)。
|
|
13
13
|
let latestStartedAt = "";
|
|
14
14
|
for (const snapshot of snapshots) {
|
|
15
15
|
if (snapshot.startedAt > latestStartedAt)
|
|
@@ -28,6 +28,7 @@ export function selectLatest(experiments, opts) {
|
|
|
28
28
|
covered,
|
|
29
29
|
total,
|
|
30
30
|
message: `snapshot covers ${covered} of ${total} evals seen in history; re-run \`niceeval exp ${exp.id}\` for a full snapshot`,
|
|
31
|
+
command: `niceeval exp ${exp.id}`,
|
|
31
32
|
});
|
|
32
33
|
}
|
|
33
34
|
if (snapshot.startedAt < latestStartedAt) {
|
|
@@ -36,7 +37,8 @@ export function selectLatest(experiments, opts) {
|
|
|
36
37
|
experimentId: exp.id,
|
|
37
38
|
startedAt: snapshot.startedAt,
|
|
38
39
|
latestStartedAt,
|
|
39
|
-
message: `snapshot "${exp.id}" (${snapshot.startedAt}) predates the latest run in this
|
|
40
|
+
message: `snapshot "${exp.id}" (${snapshot.startedAt}) predates the latest run in this scope by ${humanizeGap(snapshot.startedAt, latestStartedAt)}; re-run \`niceeval exp ${exp.id}\` to align, or ignore if evals, agent and model are unchanged between the runs`,
|
|
41
|
+
command: `niceeval exp ${exp.id}`,
|
|
40
42
|
});
|
|
41
43
|
}
|
|
42
44
|
if (!snapshot.completedAt) {
|
|
@@ -45,24 +47,58 @@ export function selectLatest(experiments, opts) {
|
|
|
45
47
|
experimentId: exp.id,
|
|
46
48
|
startedAt: snapshot.startedAt,
|
|
47
49
|
dir: snapshot.dir,
|
|
48
|
-
message: `snapshot "${exp.id}" (${snapshot.startedAt}) has no completedAt — the run was interrupted;
|
|
50
|
+
message: `snapshot "${exp.id}" (${snapshot.startedAt}) has no completedAt — the run was interrupted; re-run \`niceeval exp ${exp.id}\` for a complete snapshot`,
|
|
51
|
+
command: `niceeval exp ${exp.id}`,
|
|
49
52
|
});
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
|
-
return
|
|
55
|
+
return makeScope("latest-snapshots", snapshots, warnings);
|
|
56
|
+
}
|
|
57
|
+
/** 一个快照的可比性配置投影;pairsByFlag 与 experimentListData 复用同一字段集。 */
|
|
58
|
+
export function comparabilityConfigOf(snapshot) {
|
|
59
|
+
const info = snapshot.experiment;
|
|
60
|
+
return {
|
|
61
|
+
agent: snapshot.agent,
|
|
62
|
+
...(snapshot.model !== undefined ? { model: snapshot.model } : {}),
|
|
63
|
+
...(info?.reasoningEffort !== undefined ? { reasoningEffort: info.reasoningEffort } : {}),
|
|
64
|
+
...(info?.flags !== undefined ? { flags: info.flags } : {}),
|
|
65
|
+
...(info?.budget !== undefined ? { budget: info.budget } : {}),
|
|
66
|
+
...(info?.timeoutMs !== undefined ? { timeoutMs: info.timeoutMs } : {}),
|
|
67
|
+
...(info?.sandbox !== undefined ? { sandbox: info.sandbox } : {}),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** 可序列化值的深相等(对象键序无关;undefined 字段与缺席字段等价)。 */
|
|
71
|
+
export function deepEqualJson(a, b) {
|
|
72
|
+
if (a === b)
|
|
73
|
+
return true;
|
|
74
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
75
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)
|
|
76
|
+
return false;
|
|
77
|
+
return a.every((item, i) => deepEqualJson(item, b[i]));
|
|
78
|
+
}
|
|
79
|
+
if (typeof a === "object" && typeof b === "object" && a !== null && b !== null) {
|
|
80
|
+
const keysA = Object.keys(a).filter((k) => a[k] !== undefined);
|
|
81
|
+
const keysB = Object.keys(b).filter((k) => b[k] !== undefined);
|
|
82
|
+
if (keysA.length !== keysB.length)
|
|
83
|
+
return false;
|
|
84
|
+
return keysA.every((k) => deepEqualJson(a[k], b[k]));
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
53
87
|
}
|
|
54
88
|
/**
|
|
55
|
-
* 两个宿主(show / view)共用的现刻水位选择器:每个 experiment × eval
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* 向更早的 run 补齐,再把合成好的
|
|
59
|
-
*
|
|
89
|
+
* 两个宿主(show / view)共用的现刻水位选择器:每个 experiment × eval 取「包含该 eval 的
|
|
90
|
+
* 最新快照」里的全部 attempt,跨 run 合成。results.latest() 只挑「每实验最新快照」,带 eval
|
|
91
|
+
* 前缀的局部重跑会产出残缺快照;现刻水位承诺「不会因为一次局部重跑变残缺」,所以在实验的
|
|
92
|
+
* 历史快照上逐 eval 向更早的 run 补齐,再把合成好的 Scope 交给宿主注入报告槽。
|
|
93
|
+
*
|
|
94
|
+
* **可比性前提**:每个 experiment 以最新快照的可比性配置(agent / model / reasoningEffort /
|
|
95
|
+
* flags / budget / timeoutMs / sandbox)为基准,只有配置与基准深相等的历史快照才参与补齐;
|
|
96
|
+
* 改过配置后只补跑部分 eval 时,旧配置快照覆盖的其余题不冒充新配置的水位,按 partial-coverage
|
|
97
|
+
* 如实告警。这保证 current() 产出的每个 experiment 只对应一套配置。
|
|
60
98
|
*
|
|
61
99
|
* 同一 eval 的全部 attempts 必须整批取自包含它的最新快照,不把历史快照的 attempts 平铺后
|
|
62
100
|
* 按 eval 聚合——否则会把不同运行的重试混成一次虚构运行。合成快照的 dir/元数据只服务报告
|
|
63
101
|
* 分组与来源展示,证据身份一律来自 attempt 自己的 ref。
|
|
64
|
-
* 警告随 Selection 重算:partial-coverage 的分母 = 已知并集 ∩ 范围(范围收窄时分母同步收窄,
|
|
65
|
-
* 不让范围外的缺口刷屏);stale / unfinished 与 results.latest() 同口径。
|
|
66
102
|
*/
|
|
67
103
|
export function selectCurrentResults(results, scope = {}) {
|
|
68
104
|
const match = scope.patterns && scope.patterns.length > 0 ? evalPrefixPredicate(scope.patterns) : () => true;
|
|
@@ -70,9 +106,13 @@ export function selectCurrentResults(results, scope = {}) {
|
|
|
70
106
|
const snapshots = [];
|
|
71
107
|
const warnings = [];
|
|
72
108
|
for (const exp of experiments) {
|
|
109
|
+
// 可比性基准 = 该实验最新快照的可比性配置;不一致的旧快照整份跳过,不贡献 attempt。
|
|
110
|
+
const baseline = comparabilityConfigOf(exp.latest);
|
|
73
111
|
// 逐题取最新:快照按最新在前,首个出现即最新判定
|
|
74
112
|
const taken = new Map();
|
|
75
113
|
for (const snapshot of exp.snapshots) {
|
|
114
|
+
if (!deepEqualJson(comparabilityConfigOf(snapshot), baseline))
|
|
115
|
+
continue;
|
|
76
116
|
for (const ev of snapshot.evals) {
|
|
77
117
|
if (!match(ev.id) || taken.has(ev.id))
|
|
78
118
|
continue;
|
|
@@ -97,6 +137,8 @@ export function selectCurrentResults(results, scope = {}) {
|
|
|
97
137
|
startedAt,
|
|
98
138
|
agent: base.agent,
|
|
99
139
|
...(base.model !== undefined ? { model: base.model } : {}),
|
|
140
|
+
...(base.experiment !== undefined ? { experiment: base.experiment } : {}),
|
|
141
|
+
...(base.name !== undefined ? { name: base.name } : {}),
|
|
100
142
|
producer: base.producer,
|
|
101
143
|
schemaVersion: base.schemaVersion,
|
|
102
144
|
evals,
|
|
@@ -105,8 +147,8 @@ export function selectCurrentResults(results, scope = {}) {
|
|
|
105
147
|
...(newest.completedAt !== undefined ? { completedAt: newest.completedAt } : {}),
|
|
106
148
|
...(base.knownEvalIds ? { knownEvalIds: [...base.knownEvalIds] } : {}),
|
|
107
149
|
});
|
|
108
|
-
//
|
|
109
|
-
//
|
|
150
|
+
// 残缺检测:跨快照补齐后仍缺,来自「历史上见过却从未在可比配置的可读落盘里出现」的题
|
|
151
|
+
// (含改配置后未补跑的题)—— 分母收窄到范围内,不让范围外的缺口刷屏。
|
|
110
152
|
const total = exp.evalIds.filter(match).length;
|
|
111
153
|
if (evals.length < total) {
|
|
112
154
|
warnings.push({
|
|
@@ -115,6 +157,7 @@ export function selectCurrentResults(results, scope = {}) {
|
|
|
115
157
|
covered: evals.length,
|
|
116
158
|
total,
|
|
117
159
|
message: `verdicts cover ${evals.length} of ${total} evals seen in history; re-run \`niceeval exp ${exp.id}\` for a full snapshot`,
|
|
160
|
+
command: `niceeval exp ${exp.id}`,
|
|
118
161
|
});
|
|
119
162
|
}
|
|
120
163
|
}
|
|
@@ -130,7 +173,8 @@ export function selectCurrentResults(results, scope = {}) {
|
|
|
130
173
|
experimentId: snapshot.experimentId,
|
|
131
174
|
startedAt: snapshot.startedAt,
|
|
132
175
|
latestStartedAt,
|
|
133
|
-
message: `verdicts for "${snapshot.experimentId}" were produced at ${snapshot.startedAt}, before the latest run in this
|
|
176
|
+
message: `verdicts for "${snapshot.experimentId}" were produced at ${snapshot.startedAt}, ${humanizeGap(snapshot.startedAt, latestStartedAt)} before the latest run in this scope; re-run \`niceeval exp ${snapshot.experimentId}\` to align, or ignore if evals, agent and model are unchanged between the runs`,
|
|
177
|
+
command: `niceeval exp ${snapshot.experimentId}`,
|
|
134
178
|
});
|
|
135
179
|
}
|
|
136
180
|
if (snapshot.completedAt === undefined) {
|
|
@@ -139,19 +183,23 @@ export function selectCurrentResults(results, scope = {}) {
|
|
|
139
183
|
experimentId: snapshot.experimentId,
|
|
140
184
|
startedAt: snapshot.startedAt,
|
|
141
185
|
dir: snapshot.dir,
|
|
142
|
-
message: `snapshot "${snapshot.experimentId}" (${snapshot.startedAt}) is unfinished (the process was interrupted); completed attempts are read as-is, but the set may be incomplete`,
|
|
186
|
+
message: `snapshot "${snapshot.experimentId}" (${snapshot.startedAt}) is unfinished (the process was interrupted); completed attempts are read as-is, but the set may be incomplete — re-run \`niceeval exp ${snapshot.experimentId}\` for a complete snapshot`,
|
|
187
|
+
command: `niceeval exp ${snapshot.experimentId}`,
|
|
143
188
|
});
|
|
144
189
|
}
|
|
145
190
|
}
|
|
146
|
-
return
|
|
191
|
+
return makeScope("current-evals", snapshots, warnings);
|
|
147
192
|
}
|
|
148
193
|
/**
|
|
149
|
-
*
|
|
150
|
-
*
|
|
194
|
+
* Scope 构造:attempts 按口径物化(快照 attempts 的平铺);filter 只删不换 —— 快照删减,
|
|
195
|
+
* attempts 随之同步修剪,warnings 修剪规则是「experimentId 不在幸存快照中的丢弃,
|
|
196
|
+
* 非实验作用域的保留」(为将来非 per-experiment 的 kind 留位置)。
|
|
151
197
|
*/
|
|
152
|
-
export function
|
|
198
|
+
export function makeScope(mode, snapshots, warnings) {
|
|
153
199
|
return {
|
|
200
|
+
mode,
|
|
154
201
|
snapshots,
|
|
202
|
+
attempts: snapshots.flatMap((s) => s.attempts),
|
|
155
203
|
warnings,
|
|
156
204
|
filter(predicate) {
|
|
157
205
|
const kept = snapshots.filter(predicate);
|
|
@@ -160,13 +208,13 @@ export function makeSelection(snapshots, warnings) {
|
|
|
160
208
|
const scope = w.experimentId;
|
|
161
209
|
return typeof scope !== "string" || survivors.has(scope);
|
|
162
210
|
});
|
|
163
|
-
return
|
|
211
|
+
return makeScope(mode, kept, keptWarnings);
|
|
164
212
|
},
|
|
165
213
|
};
|
|
166
214
|
}
|
|
167
215
|
/**
|
|
168
216
|
* 跨快照聚合前的身份键去重:(experimentId, evalId, attempt, startedAt)。
|
|
169
|
-
*
|
|
217
|
+
* 携带合入会把上一轮已通过的结果原样合入新快照,同一 attempt 因此存在于多份落盘;
|
|
170
218
|
* 重复时保留最新快照里的那份(内容相同,取新快照的副本让 ref 落在最新落盘上;
|
|
171
219
|
* 位置取首次出现处,顺序稳定)。startedAt 缺失时宁可不去重也不误删,记入 warnings。
|
|
172
220
|
*/
|
package/dist/results/types.d.ts
CHANGED
|
@@ -33,6 +33,13 @@ export interface SnapshotMeta {
|
|
|
33
33
|
completedAt?: string;
|
|
34
34
|
/** 写入时刻该实验已知的 eval 并集 —— 残缺检测的分母随数据走(copySnapshots 自动补记,writer 可声明)。 */
|
|
35
35
|
knownEvalIds?: string[];
|
|
36
|
+
/**
|
|
37
|
+
* 发布拷贝的自描述标记:copySnapshots 补记,消毒函数 → "applied"、redact: false → "none";
|
|
38
|
+
* 本地事实根没有此字段。只声明流程,不证明无秘密;view --out 据此分级防呆。
|
|
39
|
+
*/
|
|
40
|
+
publish?: {
|
|
41
|
+
redaction: "applied" | "none";
|
|
42
|
+
};
|
|
36
43
|
/** 项目名(来自 config.name),透传给 `niceeval view` 顶部 hero 显示。 */
|
|
37
44
|
name?: LocalizedText;
|
|
38
45
|
}
|
|
@@ -110,6 +117,10 @@ export interface Snapshot {
|
|
|
110
117
|
dir: string;
|
|
111
118
|
/** 写入时刻该实验已知的 eval 并集(可选);copySnapshots 自动补记,writer.snapshot() 也可声明。 */
|
|
112
119
|
knownEvalIds?: string[];
|
|
120
|
+
/** 发布拷贝的自描述标记(见 SnapshotMeta.publish);本地事实根没有此字段。 */
|
|
121
|
+
publish?: {
|
|
122
|
+
redaction: "applied" | "none";
|
|
123
|
+
};
|
|
113
124
|
}
|
|
114
125
|
/** 一个实验的全部历史:同一 experiment id 的历次快照归在一起。 */
|
|
115
126
|
export interface Experiment {
|
|
@@ -146,46 +157,68 @@ export interface Results {
|
|
|
146
157
|
experiments: Experiment[];
|
|
147
158
|
skipped: SkippedDir[];
|
|
148
159
|
/**
|
|
149
|
-
* 每个实验取最新一次快照,返回
|
|
160
|
+
* 每个实验取最新一次快照,返回 Scope(快照与挑选警告绑在一起走)。
|
|
150
161
|
* `experiments` 是 experiment id 前缀过滤(string | string[]),同 CLI 位置参数语义。
|
|
151
162
|
*/
|
|
152
163
|
latest(opts?: {
|
|
153
164
|
experiments?: string | string[];
|
|
154
|
-
}):
|
|
165
|
+
}): Scope;
|
|
166
|
+
/**
|
|
167
|
+
* 官方现刻水位:每个 experiment × eval 取「包含该 eval 的最新快照」里的全部 attempt,
|
|
168
|
+
* 跨历史拼出当前判定水位。可比性前提:每个 experiment 以最新快照的可比性配置
|
|
169
|
+
* (agent / model / reasoningEffort / flags / budget / timeoutMs / sandbox)为基准,
|
|
170
|
+
* 配置不一致的旧快照不贡献 attempt,缺口走 partial-coverage
|
|
171
|
+
* (见 docs/feature/results/library.md「官方现刻水位」)。
|
|
172
|
+
*/
|
|
173
|
+
current(opts?: {
|
|
174
|
+
experiments?: string | string[];
|
|
175
|
+
}): Scope;
|
|
155
176
|
}
|
|
156
177
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
178
|
+
* Scope(范围):选出的快照 + 口径 + 已按口径物化的 attempt 全集 + 挑选警告。
|
|
179
|
+
* 渲染与否在消费方,但缺口永远被算出来。下游(Reports 计算函数、copySnapshots)收
|
|
180
|
+
* `Scope | readonly Snapshot[]`;手工挑的裸数组没有挑选过程,自然没有 warnings 可带,也如实。
|
|
160
181
|
*/
|
|
161
|
-
export interface
|
|
182
|
+
export interface Scope {
|
|
183
|
+
/** 这份 Scope 的口径,字面写在数据上。 */
|
|
184
|
+
mode: "latest-snapshots" | "current-evals";
|
|
162
185
|
snapshots: Snapshot[];
|
|
163
|
-
warnings: SelectionWarning[];
|
|
164
186
|
/**
|
|
165
|
-
*
|
|
166
|
-
*
|
|
187
|
+
* 按口径物化的 attempt 全集:消费 attempts 就自动正确,不需要自己 flatten snapshots,
|
|
188
|
+
* 也就不可能算错口径。官方计算函数同样只消费它。
|
|
189
|
+
*/
|
|
190
|
+
attempts: AttemptHandle[];
|
|
191
|
+
warnings: ScopeWarning[];
|
|
192
|
+
/**
|
|
193
|
+
* 只删不换:返回新 Scope,快照删减,attempts 与 warnings 随之同步修剪 ——
|
|
194
|
+
* experimentId 不在幸存快照中的警告丢弃,非实验作用域的警告保留。
|
|
167
195
|
* 「换成上一个完整快照」这类替换式重挑不给方法,回 exp.snapshots 自己挑。
|
|
168
196
|
*/
|
|
169
|
-
filter(predicate: (snapshot: Snapshot) => boolean):
|
|
197
|
+
filter(predicate: (snapshot: Snapshot) => boolean): Scope;
|
|
170
198
|
}
|
|
171
199
|
/**
|
|
172
|
-
* 挑选警告:每种带 kind、可判断的结构化字段和渲染好的英文 message
|
|
173
|
-
* kind
|
|
200
|
+
* 挑选警告:每种带 kind、可判断的结构化字段和渲染好的英文 message;能用一条命令直接推进的
|
|
201
|
+
* kind 同时带 `command`(已替换真实 id,复制即跑)。kind 是契约的一部分,全集与触发条件见
|
|
202
|
+
* docs/feature/results/library.md「警告 kind 全集」。
|
|
174
203
|
*/
|
|
175
|
-
export type
|
|
204
|
+
export type ScopeWarning = {
|
|
176
205
|
/** 选中快照的覆盖 < 该实验已知 eval 并集(本地历史 ∪ knownEvalIds)。 */
|
|
177
206
|
kind: "partial-coverage";
|
|
178
207
|
experimentId: string;
|
|
179
208
|
covered: number;
|
|
180
209
|
total: number;
|
|
181
210
|
message: string;
|
|
211
|
+
/** 一条可复制即跑的推进命令:`niceeval exp <experimentId>`。 */
|
|
212
|
+
command: string;
|
|
182
213
|
} | {
|
|
183
|
-
/** 该实验选中的快照早于
|
|
214
|
+
/** 该实验选中的快照早于 Scope 中最新的落盘;无阈值,如实触发,要阈值消费方按字段自比。 */
|
|
184
215
|
kind: "stale-snapshot";
|
|
185
216
|
experimentId: string;
|
|
186
217
|
startedAt: string;
|
|
187
218
|
latestStartedAt: string;
|
|
188
219
|
message: string;
|
|
220
|
+
/** 一条可复制即跑的推进命令:`niceeval exp <experimentId>`。 */
|
|
221
|
+
command: string;
|
|
189
222
|
} | {
|
|
190
223
|
/** 选中快照缺 completedAt(进程中断,未收尾);已落盘 attempt 照常读出,警告提示集合可能不完整。 */
|
|
191
224
|
kind: "unfinished-snapshot";
|
|
@@ -194,6 +227,8 @@ export type SelectionWarning = {
|
|
|
194
227
|
/** 该快照目录的绝对路径。 */
|
|
195
228
|
dir: string;
|
|
196
229
|
message: string;
|
|
230
|
+
/** 一条可复制即跑的推进命令:`niceeval exp <experimentId>`。 */
|
|
231
|
+
command: string;
|
|
197
232
|
};
|
|
198
233
|
/** dedupeAttempts 的警告:身份键缺 startedAt,宁可不去重也不误删。 */
|
|
199
234
|
export interface DedupeWarning {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { AttemptLifecycleEvent, AttemptRef, FailureDetail } from "../types.ts";
|
|
2
|
+
import type { Verdict } from "../../scoring/types.ts";
|
|
3
|
+
import type { JsonValue } from "../../shared/types.ts";
|
|
4
|
+
import type { AttemptLocator } from "../../results/locator.ts";
|
|
5
|
+
/** `sink.diagnostic()` 的输入 —— 与 `DurableFeedbackEvent` 的 "diagnostic" 变体字段一致,
|
|
6
|
+
* 只是省略 `type`/`at`(由 coordinator 补上)。 */
|
|
7
|
+
export interface DiagnosticInput {
|
|
8
|
+
/** 稳定去重 key —— 同一种 warning/error 用同一个 key(见 cli.md「同一 dedupeKey 并发出现时
|
|
9
|
+
* 只留一条并显示次数」),不要把可变的实例细节(如具体 sandbox id)编进 key 本身,
|
|
10
|
+
* 那些细节放 `data`。 */
|
|
11
|
+
key: string;
|
|
12
|
+
severity: "warning" | "error";
|
|
13
|
+
/** 一句话人类可读摘要;renderer 的 appendDurable 直接展示,不需要再解析。 */
|
|
14
|
+
message: string;
|
|
15
|
+
identity?: AttemptRef;
|
|
16
|
+
data?: Readonly<Record<string, JsonValue>>;
|
|
17
|
+
}
|
|
18
|
+
/** `sink.failure()` 的输入 —— 与 `DurableFeedbackEvent` 的 "failure" 变体字段一致,只省略
|
|
19
|
+
* `type`/`at`(由 coordinator 补上)。`locator` 只有在 attempt 挂靠 experiment 时才存在
|
|
20
|
+
* (见 `results/locator.ts` 的 `encodeAttemptLocator`);调用方(run.ts)只在拿到 locator 之后
|
|
21
|
+
* 才应该调用这个函数——没有 locator 的裸 run 不产出这类永久失败通知。 */
|
|
22
|
+
export type FailureInput = FailureDetail;
|
|
23
|
+
/** `sink.budgetExhausted()` 的输入 —— 与 `DurableFeedbackEvent` 的 "budget-exhausted" 变体字段
|
|
24
|
+
* 一致,只省略 `type`/`at`。调用方(run.ts)对每一个因预算到顶而不派发的 attempt 各调一次
|
|
25
|
+
* (与 `AttemptLifecycleEvent` 的 "attempt:early-exit" 同构);`unstarted` 是调用方自己维护的、
|
|
26
|
+
* 发出这条时的累计未派发数,不是 reducer 能推导的值(见 reducer.ts 对应事件的注释)。 */
|
|
27
|
+
export interface BudgetExhaustedInput {
|
|
28
|
+
experimentId: string;
|
|
29
|
+
spent: number;
|
|
30
|
+
unstarted: number;
|
|
31
|
+
}
|
|
32
|
+
/** `sink.kept()` 的输入 —— 与 `DurableFeedbackEvent` 的 "kept" 变体字段一致,省略 type/at。 */
|
|
33
|
+
export interface KeptInput {
|
|
34
|
+
locator: AttemptLocator;
|
|
35
|
+
identity: AttemptRef;
|
|
36
|
+
who: string;
|
|
37
|
+
verdict: Verdict;
|
|
38
|
+
provider: string;
|
|
39
|
+
sandboxId: string;
|
|
40
|
+
enter?: string;
|
|
41
|
+
}
|
|
42
|
+
/** `sink.ts` façade 函数实际转发到的最小接口 —— `FeedbackCoordinator`(coordinator.ts)实现它。
|
|
43
|
+
* 定义在这里(而不是从 coordinator.ts 导入)是为了让 sink.ts 不必在运行时依赖 coordinator.ts,
|
|
44
|
+
* 避免两个模块互相 import 造成的循环依赖 —— coordinator.ts 反过来 `import type` 这个接口。 */
|
|
45
|
+
export interface FeedbackSink {
|
|
46
|
+
activity(text: string): void;
|
|
47
|
+
diagnostic(input: DiagnosticInput): void;
|
|
48
|
+
interrupted(): void;
|
|
49
|
+
reporterError(input: {
|
|
50
|
+
reporter: string;
|
|
51
|
+
required: boolean;
|
|
52
|
+
message: string;
|
|
53
|
+
}): void;
|
|
54
|
+
/** 一次失败/errored attempt 的永久通知(见 `FailureInput`)。 */
|
|
55
|
+
failure(input: FailureInput): void;
|
|
56
|
+
/** 一个因预算到顶而未被派发的 attempt(见 `BudgetExhaustedInput`)。 */
|
|
57
|
+
budgetExhausted(input: BudgetExhaustedInput): void;
|
|
58
|
+
/** 一次留存授予(--keep-sandbox);见 `KeptInput` 与 docs/feature/sandbox/cli.md。 */
|
|
59
|
+
kept(input: KeptInput): void;
|
|
60
|
+
/** attempt 生命周期事件(queued/start/phase/progress/complete/early-exit),见
|
|
61
|
+
* `AttemptLifecycleEvent`。只驱动 human dashboard 的 active slot,不落 RunSummary/结果文件,
|
|
62
|
+
* 所以没有活跃 coordinator 时(见 `reportAttemptLifecycle`)静默丢弃是安全的 —— 这类信息
|
|
63
|
+
* 本身就只服务「正在画着的 dashboard」,不是必须留痕的诊断。 */
|
|
64
|
+
lifecycle(event: AttemptLifecycleEvent): void;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* coordinator 进入「活跃」阶段时调用一次(见 coordinator.ts 的 start()),把自己注册为当前
|
|
68
|
+
* reportXxx() 调用的目的地。返回的函数用于退出活跃状态(见 coordinator.ts 的 finish())——
|
|
69
|
+
* 调用一次即失效,重复调用是安全的 no-op。
|
|
70
|
+
*/
|
|
71
|
+
export declare function activateFeedbackSink(sink: FeedbackSink): () => void;
|
|
72
|
+
/** 仅供测试:断言没有遗留未退出的活跃 coordinator(避免一个测试忘记 finish() 污染下一个)。 */
|
|
73
|
+
export declare function activeFeedbackSinkCount(): number;
|
|
74
|
+
/** 不需要去重、不进入 RunFeedbackState 的瞬时活动文本(docker 镜像拉取进度、vercel session
|
|
75
|
+
* rotate 成功通知……)。没有活跃 coordinator 时退回一行 stderr,与迁移前的裸写视觉效果一致。 */
|
|
76
|
+
export declare function reportActivity(text: string): void;
|
|
77
|
+
/** 需要去重、要出现在三种 profile 永久事件流里的一条 warning/error。 */
|
|
78
|
+
export declare function reportDiagnostic(input: DiagnosticInput): void;
|
|
79
|
+
/** 一次失败/errored attempt 的永久通知(见 `FailureInput`)。与 `reportDiagnostic` 同级别的
|
|
80
|
+
* 「必须留痕」信号 —— 没有活跃 coordinator 时退回一行 stderr,不像 `reportAttemptLifecycle`
|
|
81
|
+
* 那样静默丢弃(定位一次真实失败不该因为没接 coordinator 就彻底没有出口)。 */
|
|
82
|
+
export declare function reportFailure(input: FailureInput): void;
|
|
83
|
+
/** 一个因预算到顶而未被派发的 attempt(见 `BudgetExhaustedInput`)。没有活跃 coordinator 时的
|
|
84
|
+
* 兜底文案与 coordinator.ts 的 `fallbackTextFor` 对 "budget-exhausted" 事件的格式化保持一致。 */
|
|
85
|
+
/** 一次留存授予的永久通知(--keep-sandbox);没有活跃 coordinator 时退回一行 stderr。 */
|
|
86
|
+
export declare function reportKept(input: KeptInput): void;
|
|
87
|
+
export declare function reportBudgetExhausted(input: BudgetExhaustedInput): void;
|
|
88
|
+
/** 用户中断(Ctrl+C)。没有活跃 coordinator 时的兜底文案与迁移前的 `runner.interrupted` 完全
|
|
89
|
+
* 相同 —— 调用方(run.ts)不再需要自己持有这段 i18n 文案。 */
|
|
90
|
+
export declare function reportInterrupted(): void;
|
|
91
|
+
/**
|
|
92
|
+
* runner 自己驱动的 attempt 生命周期投影(见 docs/feature/experiments/cli.md「Attempt 阶段」)——
|
|
93
|
+
* `src/runner/attempt.ts`(phase/progress)与 `src/runner/run.ts`(start/complete/early-exit)是
|
|
94
|
+
* 目前仅有的两个调用方。没有活跃 coordinator 时(今天:CLI 还没接入 --output)静默 no-op ——
|
|
95
|
+
* 与其它 reportXxx() 不同,这里不退回 `writeStderrLine` 兜底:这类事件只服务尚不存在的
|
|
96
|
+
* dashboard,不是需要留痕的诊断,现有可观察行为(直到 CLI 接入真正的 coordinator 之前)因此
|
|
97
|
+
* 完全不变。
|
|
98
|
+
*/
|
|
99
|
+
export declare function reportAttemptLifecycle(event: AttemptLifecycleEvent): void;
|
|
100
|
+
/** 一个 reporter 的某次回调抛错(见 `runner/report.ts` 的 `runReporter`)。`reporter`/`required`
|
|
101
|
+
* 来自调用方注册这个 reporter 时的 `ReporterRegistration`(见其字段注释)——默认 artifacts、
|
|
102
|
+
* 显式 `--json`/`--junit` 传 `required: true`,用户 `config.reporters`/`EvalDef.reporters`
|
|
103
|
+
* 传 `required: false`。coordinator 把它折进 `RunFeedbackState.diagnostics`(reducer 按
|
|
104
|
+
* `reporter-error:<reporter>` 去重),调用方(`cli.ts` 的 `assembleRunCompletion`)据此把
|
|
105
|
+
* `required` 为真的失败折进 `RunCompletion.reporterErrors`,让 completion/CI 退出码判红。 */
|
|
106
|
+
export declare function reportReporterError(input: {
|
|
107
|
+
reporter: string;
|
|
108
|
+
required: boolean;
|
|
109
|
+
message: string;
|
|
110
|
+
}): void;
|