niceeval 0.9.1 → 0.10.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.
- package/INDEX.md +31 -33
- package/dist/agents/types.d.ts +20 -17
- package/dist/context/types.d.ts +21 -21
- package/dist/i18n/en.d.ts +10 -2
- package/dist/i18n/zh-CN.d.ts +14 -6
- package/dist/o11y/execution-tree.d.ts +103 -0
- package/dist/o11y/otlp/select.d.ts +22 -0
- package/dist/report/{react → assets}/colors.d.ts +8 -0
- package/dist/report/{react → assets}/colors.js +23 -0
- package/dist/report/built-in/index.d.ts +2 -2
- package/dist/report/built-in/index.js +2 -2
- package/dist/report/built-in/standard.d.ts +8 -1
- package/dist/report/built-in/standard.js +17 -7
- package/dist/report/components/attempt-detail/AttemptAssertions.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptAssertions.js +17 -0
- package/dist/report/components/attempt-detail/AttemptConversation.d.ts +10 -0
- package/dist/report/components/attempt-detail/AttemptConversation.js +74 -0
- package/dist/report/components/attempt-detail/AttemptDiagnostics.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptDiagnostics.js +7 -0
- package/dist/report/components/attempt-detail/AttemptDiff.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptDiff.js +11 -0
- package/dist/report/components/attempt-detail/AttemptError.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptError.js +16 -0
- package/dist/report/components/attempt-detail/AttemptFixPrompt.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptFixPrompt.js +7 -0
- package/dist/report/components/attempt-detail/AttemptSource.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptSource.js +97 -0
- package/dist/report/components/attempt-detail/AttemptSummary.d.ts +8 -0
- package/dist/report/components/attempt-detail/AttemptSummary.js +20 -0
- package/dist/report/components/attempt-detail/AttemptTimeline.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptTimeline.js +28 -0
- package/dist/report/components/attempt-detail/AttemptTrace.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptTrace.js +29 -0
- package/dist/report/components/attempt-detail/AttemptUsage.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptUsage.js +20 -0
- package/dist/report/components/attempt-detail/compute.d.ts +24 -0
- package/dist/report/components/attempt-detail/compute.js +297 -0
- package/dist/report/components/attempt-detail/faces.d.ts +14 -0
- package/dist/report/components/attempt-detail/faces.js +239 -0
- package/dist/report/components/attempt-detail/index.d.ts +38 -0
- package/dist/report/components/attempt-detail/index.js +547 -0
- package/dist/report/{react → components}/cell.d.ts +5 -3
- package/dist/report/{react → components}/cell.js +3 -3
- package/dist/report/{react → components/entity-lists}/AttemptList.d.ts +8 -4
- package/dist/report/{react → components/entity-lists}/AttemptList.js +16 -10
- package/dist/report/{react → components/entity-lists}/EvalList.d.ts +3 -3
- package/dist/report/{react → components/entity-lists}/EvalList.js +0 -0
- package/dist/report/{react → components/entity-lists}/ExperimentList.d.ts +4 -5
- package/dist/report/{react → components/entity-lists}/ExperimentList.js +12 -11
- package/dist/report/components/entity-lists/compute.d.ts +23 -0
- package/dist/report/components/entity-lists/compute.js +171 -0
- package/dist/report/components/entity-lists/faces.d.ts +5 -0
- package/dist/report/components/entity-lists/faces.js +175 -0
- package/dist/report/components/entity-lists/index.d.ts +49 -0
- package/dist/report/components/entity-lists/index.js +169 -0
- package/dist/report/{react → components}/fixtures.d.ts +2 -2
- package/dist/report/{react → components}/fixtures.js +1 -1
- package/dist/report/{react → components/metric-views}/DeltaTable.d.ts +2 -2
- package/dist/report/{react → components/metric-views}/DeltaTable.js +4 -4
- package/dist/report/{react → components/metric-views}/MetricBars.d.ts +3 -3
- package/dist/report/{react → components/metric-views}/MetricBars.js +3 -3
- package/dist/report/{react → components/metric-views}/MetricLine.d.ts +2 -2
- package/dist/report/{react → components/metric-views}/MetricLine.js +8 -5
- package/dist/report/{react → components/metric-views}/MetricMatrix.d.ts +3 -3
- package/dist/report/{react → components/metric-views}/MetricMatrix.js +4 -4
- package/dist/report/components/metric-views/MetricScatter.d.ts +11 -0
- package/dist/report/{react → components/metric-views}/MetricScatter.js +27 -60
- package/dist/report/{react → components/metric-views}/MetricTable.d.ts +3 -3
- package/dist/report/{react → components/metric-views}/MetricTable.js +4 -4
- package/dist/report/{react → components/metric-views}/Scoreboard.d.ts +2 -2
- package/dist/report/{react → components/metric-views}/Scoreboard.js +3 -3
- package/dist/report/components/metric-views/compute.d.ts +89 -0
- package/dist/report/{compute.js → components/metric-views/compute.js} +32 -415
- package/dist/report/components/metric-views/faces.d.ts +13 -0
- package/dist/report/components/metric-views/faces.js +381 -0
- package/dist/report/components/metric-views/index.d.ts +50 -0
- package/dist/report/components/metric-views/index.js +273 -0
- package/dist/report/{text → components/metric-views}/plot.js +1 -1
- package/dist/report/components/shared-compute.d.ts +22 -0
- package/dist/report/components/shared-compute.js +47 -0
- package/dist/report/components/shared-faces.d.ts +9 -0
- package/dist/report/components/shared-faces.js +26 -0
- package/dist/report/components/shared.d.ts +68 -0
- package/dist/report/components/shared.js +125 -0
- package/dist/report/{react → components/site-components}/CopyFixPrompt.d.ts +2 -2
- package/dist/report/{react → components/site-components}/CopyFixPrompt.js +2 -2
- package/dist/report/{react → components/site-components}/HeroCard.d.ts +2 -2
- package/dist/report/{react → components/site-components}/HeroCard.js +2 -2
- package/dist/report/{react → components/site-components}/ScopeWarnings.d.ts +2 -2
- package/dist/report/{react → components/site-components}/ScopeWarnings.js +3 -3
- package/dist/report/{react → components/site-components}/TraceWaterfall.d.ts +3 -3
- package/dist/report/{react → components/site-components}/TraceWaterfall.js +5 -5
- package/dist/report/components/site-components/compute.d.ts +28 -0
- package/dist/report/components/site-components/compute.js +132 -0
- package/dist/report/components/site-components/faces.d.ts +21 -0
- package/dist/report/components/site-components/faces.js +75 -0
- package/dist/report/components/site-components/index.d.ts +74 -0
- package/dist/report/components/site-components/index.js +220 -0
- package/dist/report/{scope-warnings.d.ts → components/site-components/scope-warnings.d.ts} +2 -2
- package/dist/report/{scope-warnings.js → components/site-components/scope-warnings.js} +2 -2
- package/dist/report/{react → components/summaries}/ScopeSummary.d.ts +2 -2
- package/dist/report/{react → components/summaries}/ScopeSummary.js +17 -8
- package/dist/report/components/summaries/compute.d.ts +7 -0
- package/dist/report/components/summaries/compute.js +51 -0
- package/dist/report/components/summaries/faces.d.ts +7 -0
- package/dist/report/components/summaries/faces.js +38 -0
- package/dist/report/components/summaries/index.d.ts +27 -0
- package/dist/report/components/summaries/index.js +78 -0
- package/dist/report/definition/grid-layout.d.ts +50 -0
- package/dist/report/definition/grid-layout.js +89 -0
- package/dist/report/{primitives.d.ts → definition/primitives.d.ts} +34 -4
- package/dist/report/{primitives.js → definition/primitives.js} +101 -10
- package/dist/report/{report.d.ts → definition/report.d.ts} +36 -65
- package/dist/report/{report.js → definition/report.js} +58 -90
- package/dist/report/{text/table.d.ts → definition/table-text.d.ts} +2 -2
- package/dist/report/{text/table.js → definition/table-text.js} +2 -2
- package/dist/report/{tree.d.ts → definition/tree.d.ts} +43 -11
- package/dist/report/{tree.js → definition/tree.js} +9 -11
- package/dist/report/index.d.ts +33 -18
- package/dist/report/index.js +23 -14
- package/dist/report/{aggregate.d.ts → model/aggregate.d.ts} +12 -4
- package/dist/report/{aggregate.js → model/aggregate.js} +28 -8
- package/dist/report/{flag.d.ts → model/flag.d.ts} +14 -1
- package/dist/report/{flag.js → model/flag.js} +35 -0
- package/dist/report/{format.d.ts → model/format.d.ts} +13 -7
- package/dist/report/{format.js → model/format.js} +79 -9
- package/dist/report/{locale.d.ts → model/locale.d.ts} +17 -17
- package/dist/report/{locale.js → model/locale.js} +31 -33
- package/dist/report/{metrics.d.ts → model/metrics.d.ts} +2 -2
- package/dist/report/{metrics.js → model/metrics.js} +2 -2
- package/dist/report/{types.d.ts → model/types.d.ts} +154 -20
- package/dist/report/react/index.d.ts +32 -21
- package/dist/report/react/index.js +33 -21
- package/dist/report/{load.d.ts → runtime/load.d.ts} +1 -1
- package/dist/report/{load.js → runtime/load.js} +1 -1
- package/dist/report/runtime/text.d.ts +67 -0
- package/dist/report/runtime/text.js +114 -0
- package/dist/report/runtime/web.d.ts +35 -0
- package/dist/report/runtime/web.js +70 -0
- package/dist/results/annotated-source.d.ts +87 -0
- package/dist/results/attempt-evidence.d.ts +74 -0
- package/dist/results/attempt-source.d.ts +15 -0
- package/dist/results/select.d.ts +11 -1
- package/dist/results/select.js +27 -5
- package/dist/runner/eval-selection.d.ts +26 -0
- package/dist/runner/feedback/sink.d.ts +26 -1
- package/dist/runner/types.d.ts +151 -24
- package/dist/sandbox/docker.d.ts +6 -0
- package/dist/sandbox/e2b.d.ts +0 -1
- package/dist/sandbox/types.d.ts +23 -21
- package/dist/scoring/display.d.ts +7 -2
- package/dist/scoring/display.js +42 -4
- package/dist/scoring/types.d.ts +3 -3
- package/dist/shared/aggregate.d.ts +14 -0
- package/dist/shared/aggregate.js +31 -0
- package/dist/shared/types.d.ts +6 -1
- package/docs-site/images/logo-dark.svg +7 -0
- package/docs-site/images/logo.svg +6 -5
- package/docs-site/zh/README.md +8 -7
- package/docs-site/zh/examples/ai-agent-application.mdx +5 -5
- package/docs-site/zh/examples/coding-agent-extensions.mdx +4 -4
- package/docs-site/zh/examples/index.mdx +3 -3
- package/docs-site/zh/examples/integrations/ai-sdk-v7.mdx +6 -6
- package/docs-site/zh/examples/integrations/claude-sdk.mdx +3 -3
- package/docs-site/zh/examples/integrations/codex-sdk.mdx +3 -3
- package/docs-site/zh/examples/integrations/langgraph.mdx +3 -3
- package/docs-site/zh/examples/integrations/pi-sdk.mdx +2 -2
- package/docs-site/zh/explanation/adapter.mdx +19 -19
- package/docs-site/zh/explanation/assert.mdx +9 -9
- package/docs-site/zh/explanation/drive.mdx +4 -4
- package/docs-site/zh/explanation/evals.mdx +8 -8
- package/docs-site/zh/explanation/experiment.mdx +8 -8
- package/docs-site/zh/explanation/hitl.mdx +13 -13
- package/docs-site/zh/explanation/judge.mdx +3 -3
- package/docs-site/zh/explanation/overview.mdx +7 -7
- package/docs-site/zh/explanation/runner.mdx +17 -13
- package/docs-site/zh/explanation/tier.mdx +6 -6
- package/docs-site/zh/index.mdx +14 -14
- package/docs-site/zh/introduction.mdx +13 -16
- package/docs-site/zh/reference/builtin-agents.mdx +61 -28
- package/docs-site/zh/reference/capabilities.mdx +7 -27
- package/docs-site/zh/reference/cli.mdx +36 -33
- package/docs-site/zh/reference/define-agent.mdx +32 -31
- package/docs-site/zh/reference/define-config.mdx +6 -6
- package/docs-site/zh/reference/define-eval.mdx +33 -20
- package/docs-site/zh/reference/events.mdx +4 -4
- package/docs-site/zh/reference/expect.mdx +3 -3
- package/docs-site/zh/reference/official-adapters.mdx +17 -17
- package/docs-site/zh/reference/report-components.mdx +195 -121
- package/docs-site/zh/reference/results-data.mdx +13 -13
- package/docs-site/zh/troubleshooting/debug-sandbox.mdx +11 -11
- package/docs-site/zh/troubleshooting/debugging.mdx +40 -16
- package/docs-site/zh/{how-to → tutorials}/agent-feedback-loop.mdx +38 -38
- package/docs-site/zh/tutorials/agent-onboarding.mdx +100 -0
- package/docs-site/zh/tutorials/authoring.mdx +211 -0
- package/docs-site/zh/{how-to → tutorials}/ci-integration.mdx +8 -8
- package/docs-site/zh/{how-to → tutorials}/connect-otel.mdx +22 -22
- package/docs-site/zh/{how-to → tutorials}/connect-your-agent.mdx +58 -63
- package/docs-site/zh/tutorials/custom-reports.mdx +453 -0
- package/docs-site/zh/{how-to → tutorials}/dataset-fanout.mdx +4 -4
- package/docs-site/zh/tutorials/experiments.mdx +102 -0
- package/docs-site/zh/{how-to → tutorials}/fixtures.mdx +9 -9
- package/docs-site/zh/{how-to → tutorials}/publish-report.mdx +6 -6
- package/docs-site/zh/tutorials/quickstart.mdx +18 -18
- package/docs-site/zh/{how-to → tutorials}/reporters.mdx +6 -6
- package/docs-site/zh/{how-to → tutorials}/sandbox-agent.mdx +6 -6
- package/docs-site/zh/{how-to → tutorials}/sandbox-providers.mdx +41 -19
- package/docs-site/zh/{how-to → tutorials}/scoring-guide.mdx +4 -4
- package/docs-site/zh/{how-to → tutorials}/viewing-results.mdx +60 -57
- package/docs-site/zh/tutorials/write-experiment.mdx +353 -0
- package/docs-site/zh/{how-to → tutorials}/write-send.mdx +40 -40
- package/package.json +10 -7
- package/src/agents/bub.ts +21 -8
- package/src/agents/claude-code.ts +23 -10
- package/src/agents/codex.test.ts +22 -7
- package/src/agents/codex.ts +22 -9
- package/src/agents/index.ts +2 -2
- package/src/agents/openai-compat.ts +1 -1
- package/src/agents/post-setup.ts +45 -22
- package/src/agents/streaming.ts +1 -1
- package/src/agents/types.ts +20 -17
- package/src/agents/ui-message-stream.test.ts +10 -0
- package/src/agents/ui-message-stream.ts +12 -1
- package/src/cli.ts +75 -59
- package/src/context/types.ts +21 -21
- package/src/define.ts +13 -0
- package/src/i18n/en.ts +27 -12
- package/src/i18n/zh-CN.ts +27 -12
- package/src/index.ts +2 -0
- package/src/o11y/prices.json +176 -99
- package/src/report/{react → assets}/colors.ts +22 -0
- package/src/report/{react → assets}/enhance.js +1 -33
- package/src/report/assets/styles.css +1785 -0
- package/src/report/built-in/index.tsx +2 -2
- package/src/report/built-in/standard.tsx +18 -6
- package/src/report/components/attempt-detail/AttemptAssertions.tsx +67 -0
- package/src/report/components/attempt-detail/AttemptConversation.tsx +158 -0
- package/src/report/components/attempt-detail/AttemptDiagnostics.tsx +38 -0
- package/src/report/components/attempt-detail/AttemptDiff.tsx +35 -0
- package/src/report/components/attempt-detail/AttemptError.tsx +31 -0
- package/src/report/components/attempt-detail/AttemptFixPrompt.tsx +26 -0
- package/src/report/components/attempt-detail/AttemptSource.tsx +224 -0
- package/src/report/components/attempt-detail/AttemptSummary.tsx +74 -0
- package/src/report/components/attempt-detail/AttemptTimeline.tsx +108 -0
- package/src/report/components/attempt-detail/AttemptTrace.tsx +63 -0
- package/src/report/components/attempt-detail/AttemptUsage.tsx +29 -0
- package/src/report/components/attempt-detail/attempt-components.test.tsx +758 -0
- package/src/report/components/attempt-detail/compute.ts +336 -0
- package/src/report/components/attempt-detail/faces.ts +260 -0
- package/src/report/components/attempt-detail/index.tsx +600 -0
- package/src/report/components/attempt-detail/validate.test.ts +252 -0
- package/src/report/{react → components}/cell.tsx +6 -3
- package/src/report/{report.test.ts → components/compute.test.ts} +316 -46
- package/src/report/{react → components/entity-lists}/AttemptList.tsx +24 -16
- package/src/report/{react → components/entity-lists}/EvalList.tsx +0 -0
- package/src/report/{react → components/entity-lists}/ExperimentList.tsx +33 -27
- package/src/report/components/entity-lists/compute.ts +196 -0
- package/src/report/components/entity-lists/faces.ts +208 -0
- package/src/report/components/entity-lists/index.tsx +238 -0
- package/src/report/components/entity-lists/validate.test.ts +114 -0
- package/src/report/{react → components}/fixtures.ts +2 -2
- package/src/report/{react → components/metric-views}/DeltaTable.tsx +5 -5
- package/src/report/{react → components/metric-views}/MetricBars.tsx +5 -5
- package/src/report/{react → components/metric-views}/MetricLine.tsx +9 -6
- package/src/report/{react → components/metric-views}/MetricMatrix.tsx +6 -6
- package/src/report/{react → components/metric-views}/MetricScatter.tsx +42 -70
- package/src/report/{react → components/metric-views}/MetricTable.tsx +6 -6
- package/src/report/{react → components/metric-views}/Scoreboard.tsx +4 -4
- package/src/report/{compute.ts → components/metric-views/compute.ts} +51 -477
- package/src/report/components/metric-views/faces.ts +423 -0
- package/src/report/components/metric-views/index.tsx +352 -0
- package/src/report/{text → components/metric-views}/plot.ts +1 -1
- package/src/report/components/metric-views/validate.test.ts +211 -0
- package/src/report/{react → components}/render.test.tsx +66 -26
- package/src/report/components/shared-compute.ts +59 -0
- package/src/report/components/shared-faces.ts +30 -0
- package/src/report/components/shared.ts +192 -0
- package/src/report/{react → components/site-components}/CopyFixPrompt.tsx +3 -3
- package/src/report/{react → components/site-components}/HeroCard.tsx +3 -3
- package/src/report/{react → components/site-components}/ScopeWarnings.tsx +4 -4
- package/src/report/{react → components/site-components}/TraceWaterfall.tsx +13 -10
- package/src/report/components/site-components/compute.ts +144 -0
- package/src/report/components/site-components/faces.ts +80 -0
- package/src/report/components/site-components/index.tsx +265 -0
- package/src/report/{scope-warnings.ts → components/site-components/scope-warnings.ts} +3 -3
- package/src/report/{site-components.test.tsx → components/site-components/site-components.test.tsx} +23 -21
- package/src/report/components/site-components/validate.test.ts +89 -0
- package/src/report/{react → components/summaries}/ScopeSummary.tsx +26 -11
- package/src/report/components/summaries/compute.ts +56 -0
- package/src/report/components/summaries/faces.ts +48 -0
- package/src/report/components/summaries/index.tsx +127 -0
- package/src/report/components/summaries/validate.test.ts +49 -0
- package/src/report/definition/grid-layout.test.ts +124 -0
- package/src/report/definition/grid-layout.ts +146 -0
- package/src/report/{primitives.tsx → definition/primitives.tsx} +168 -18
- package/src/report/{report.ts → definition/report.ts} +98 -165
- package/src/report/{shell-head.test.ts → definition/shell-head.test.ts} +2 -2
- package/src/report/{text/table.ts → definition/table-text.ts} +4 -4
- package/src/report/{tree.ts → definition/tree.ts} +56 -20
- package/src/report/index.ts +128 -66
- package/src/report/{aggregate.ts → model/aggregate.ts} +31 -9
- package/src/report/{flag.ts → model/flag.ts} +39 -1
- package/src/report/{format.ts → model/format.ts} +89 -10
- package/src/report/{locale.ts → model/locale.ts} +34 -36
- package/src/report/{metrics.ts → model/metrics.ts} +3 -3
- package/src/report/{types.ts → model/types.ts} +159 -22
- package/src/report/react/index.tsx +54 -26
- package/src/report/{dual-render.test.tsx → runtime/dual-render.test.tsx} +601 -53
- package/src/report/runtime/host.test.ts +44 -0
- package/src/report/runtime/host.ts +138 -0
- package/src/report/{load.ts → runtime/load.ts} +1 -1
- package/src/report/runtime/text.ts +192 -0
- package/src/report/runtime/web.ts +106 -0
- package/src/results/attempt-evidence.ts +5 -1
- package/src/results/host-equivalence.test.ts +53 -2
- package/src/results/select.ts +29 -5
- package/src/runner/attempt.test.ts +48 -1
- package/src/runner/attempt.ts +62 -42
- package/src/runner/cleanup-timeout.test.ts +16 -0
- package/src/runner/cleanup-timeout.ts +23 -0
- package/src/runner/discover.ts +1 -2
- package/src/runner/eval-selection.test.ts +187 -0
- package/src/runner/eval-selection.ts +109 -0
- package/src/runner/experiment-cleanup-registry.test.ts +89 -0
- package/src/runner/experiment-cleanup-registry.ts +39 -0
- package/src/runner/experiment-labels.test.ts +71 -0
- package/src/runner/feedback/agent.test.ts +33 -1
- package/src/runner/feedback/agent.ts +12 -16
- package/src/runner/feedback/ci.test.ts +35 -1
- package/src/runner/feedback/ci.ts +16 -18
- package/src/runner/feedback/coordinator.ts +28 -0
- package/src/runner/feedback/human.test.ts +108 -1
- package/src/runner/feedback/human.ts +71 -21
- package/src/runner/feedback/reducer.test.ts +64 -0
- package/src/runner/feedback/reducer.ts +26 -0
- package/src/runner/feedback/sink.ts +40 -1
- package/src/runner/fingerprint.ts +2 -1
- package/src/runner/report.test.ts +14 -0
- package/src/runner/report.ts +3 -1
- package/src/runner/run.test.ts +390 -12
- package/src/runner/run.ts +259 -26
- package/src/runner/sandbox-selection.test.ts +13 -3
- package/src/runner/sandbox-selection.ts +4 -2
- package/src/runner/types.ts +160 -24
- package/src/sandbox/docker.ts +7 -0
- package/src/sandbox/e2b-reconcile.test.ts +125 -0
- package/src/sandbox/e2b.ts +47 -12
- package/src/sandbox/types.ts +23 -21
- package/src/scoring/display.test.ts +28 -2
- package/src/scoring/display.ts +38 -5
- package/src/scoring/types.ts +3 -3
- package/src/shared/aggregate.test.ts +52 -0
- package/src/shared/aggregate.ts +29 -0
- package/src/shared/types.ts +6 -1
- package/src/show/command.test.ts +34 -0
- package/src/show/command.ts +16 -0
- package/src/show/compose.ts +1 -1
- package/src/show/index.ts +56 -20
- package/src/show/render.ts +15 -239
- package/src/show/show.test.ts +127 -34
- package/src/view/app/App.test.tsx +1 -1
- package/src/view/app/App.tsx +119 -47
- package/src/view/app/i18n.ts +7 -147
- package/src/view/app/lib/attempt-dialog.test.ts +65 -0
- package/src/view/app/lib/attempt-dialog.ts +69 -0
- package/src/view/app/main.tsx +0 -1
- package/src/view/app/types.ts +3 -86
- package/src/view/artifact-serving.test.ts +22 -38
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +15 -22
- package/src/view/data.test.ts +48 -36
- package/src/view/data.ts +105 -83
- package/src/view/index.ts +1 -1
- package/src/view/server.ts +32 -2
- package/src/view/shared/types.ts +6 -31
- package/src/view/site-parity.test.ts +24 -1
- package/src/view/site.ts +144 -17
- package/src/view/styles.css +0 -805
- package/src/view/view-report.test.ts +143 -22
- package/dist/report/components.d.ts +0 -179
- package/dist/report/components.js +0 -544
- package/dist/report/compute.d.ts +0 -139
- package/dist/report/react/ExperimentComparison.d.ts +0 -10
- package/dist/report/react/ExperimentComparison.js +0 -12
- package/dist/report/react/MetricScatter.d.ts +0 -9
- package/dist/report/react/format.d.ts +0 -3
- package/dist/report/react/format.js +0 -7
- package/dist/report/text/faces.d.ts +0 -45
- package/dist/report/text/faces.js +0 -671
- package/dist/report/web.d.ts +0 -32
- package/dist/report/web.js +0 -48
- package/docs-site/zh/how-to/authoring.mdx +0 -162
- package/docs-site/zh/how-to/custom-reports.mdx +0 -414
- package/docs-site/zh/how-to/experiments.mdx +0 -86
- package/docs-site/zh/how-to/write-experiment.mdx +0 -164
- package/src/report/components.tsx +0 -925
- package/src/report/react/ExperimentComparison.tsx +0 -73
- package/src/report/react/format.ts +0 -9
- package/src/report/react/styles.css +0 -945
- package/src/report/text/faces.ts +0 -767
- package/src/report/web.ts +0 -77
- package/src/show/report-host.test.ts +0 -205
- package/src/show/report-host.ts +0 -389
- package/src/view/app/components/AttemptModal.tsx +0 -496
- package/src/view/app/components/CodeView.test.tsx +0 -142
- package/src/view/app/components/CodeView.tsx +0 -310
- package/src/view/app/components/CopyControls.tsx +0 -106
- package/src/view/app/components/Trace.tsx +0 -100
- package/src/view/app/components/Transcript.tsx +0 -157
- package/src/view/app/components/ui/badge.tsx +0 -21
- package/src/view/app/lib/artifact-url.ts +0 -17
- package/src/view/app/lib/attempt-route.test.ts +0 -80
- package/src/view/app/lib/attempt-route.ts +0 -52
- package/src/view/app/lib/format.ts +0 -70
- package/src/view/app/lib/guards.test.ts +0 -108
- package/src/view/app/lib/guards.ts +0 -71
- package/src/view/app/lib/rows.ts +0 -22
- package/src/view/app/lib/transcript-data.tsx +0 -151
- package/src/view/app/lib/verdict.ts +0 -23
- package/src/view/app/shared.ts +0 -8
- /package/dist/report/{react → components/metric-views}/chart-math.d.ts +0 -0
- /package/dist/report/{react → components/metric-views}/chart-math.js +0 -0
- /package/dist/report/{text → components/metric-views}/plot.d.ts +0 -0
- /package/dist/report/{react → components/site-components}/PoweredBy.d.ts +0 -0
- /package/dist/report/{react → components/site-components}/PoweredBy.js +0 -0
- /package/dist/report/{text/layout.d.ts → model/text-layout.d.ts} +0 -0
- /package/dist/report/{text/layout.js → model/text-layout.js} +0 -0
- /package/dist/report/{types.js → model/types.js} +0 -0
- /package/src/report/{react → components/metric-views}/chart-math.test.ts +0 -0
- /package/src/report/{react → components/metric-views}/chart-math.ts +0 -0
- /package/src/report/{react → components/site-components}/PoweredBy.tsx +0 -0
- /package/src/report/{text/layout.ts → model/text-layout.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// 计算函数(*Data):ReportInput → 一份组件数据。跑在 Node 侧,产物是算好的、可序列化的
|
|
2
|
-
// 普通 JSON(终值 + 渲染提示,不含公式);渲染面(web/text)
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// 普通 JSON(终值 + 渲染提示,不含公式);渲染面(web/text)只做展示。指标图形族
|
|
3
|
+
// (MetricTable / MetricMatrix / MetricBars / Scoreboard / MetricScatter / MetricLine /
|
|
4
|
+
// DeltaTable)的 *Data 与配套 Options 都住在这里(docs/feature/reports/library/metric-views.md)。
|
|
5
5
|
//
|
|
6
6
|
// 共同约定(docs/feature/reports/architecture.md「指标聚合不变量」):
|
|
7
7
|
// - 第一参收 ReportInput = Scope | readonly Snapshot[];warnings 不进组件数据(宿主统一显示);
|
|
@@ -12,19 +12,10 @@
|
|
|
12
12
|
// - core 中立:只认 Metric / Dimension 接口,不出现具体 agent 名的分支。
|
|
13
13
|
|
|
14
14
|
import type {
|
|
15
|
-
AttemptListItem,
|
|
16
|
-
AttemptLocator,
|
|
17
|
-
CopyFixPromptData,
|
|
18
15
|
DeltaData,
|
|
19
16
|
DeltaPair,
|
|
20
17
|
DimensionInput,
|
|
21
|
-
EvalListItem,
|
|
22
|
-
ExperimentComparisonData,
|
|
23
|
-
ExperimentComparisonGroupData,
|
|
24
|
-
ExperimentListEvalRow,
|
|
25
|
-
ExperimentListItem,
|
|
26
18
|
FlagPairs,
|
|
27
|
-
HeroData,
|
|
28
19
|
LineData,
|
|
29
20
|
MatrixData,
|
|
30
21
|
Metric,
|
|
@@ -32,19 +23,14 @@ import type {
|
|
|
32
23
|
NumericAxis,
|
|
33
24
|
ReportInput,
|
|
34
25
|
ScatterData,
|
|
35
|
-
ScopeSummaryData,
|
|
36
|
-
ScopeWarning,
|
|
37
26
|
ScoreboardData,
|
|
27
|
+
SeriesInput,
|
|
38
28
|
TableData,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
} from "
|
|
43
|
-
import
|
|
44
|
-
import type { Snapshot } from "../results/types.ts";
|
|
45
|
-
import { comparabilityConfigOf, deepEqualJson } from "../results/select.ts";
|
|
46
|
-
import { evalLevelStats, foldEvalVerdict } from "../shared/verdict.ts";
|
|
47
|
-
import { experimentGroupOf } from "../shared/aggregate.ts";
|
|
29
|
+
} from "../../model/types.ts";
|
|
30
|
+
import type { JsonValue } from "../../../types.ts";
|
|
31
|
+
import type { AttemptLocator } from "../../../results/locator.ts";
|
|
32
|
+
import type { Snapshot } from "../../../results/types.ts";
|
|
33
|
+
import { comparabilityConfigOf, deepEqualJson } from "../../../results/select.ts";
|
|
48
34
|
import {
|
|
49
35
|
assertUniqueMetricNames,
|
|
50
36
|
axisValueOf,
|
|
@@ -52,10 +38,8 @@ import {
|
|
|
52
38
|
computeCell,
|
|
53
39
|
dimensionKey,
|
|
54
40
|
dimensionName,
|
|
55
|
-
displayValue,
|
|
56
41
|
evalGroupOf,
|
|
57
42
|
evalIdOf,
|
|
58
|
-
evaluateMetric,
|
|
59
43
|
experimentIdOf,
|
|
60
44
|
filterItems,
|
|
61
45
|
fullEvalKey,
|
|
@@ -63,15 +47,15 @@ import {
|
|
|
63
47
|
locatorOf,
|
|
64
48
|
refDisplayKey,
|
|
65
49
|
resolveInput,
|
|
66
|
-
|
|
50
|
+
seriesKey,
|
|
51
|
+
seriesName,
|
|
67
52
|
toColumn,
|
|
68
53
|
type Item,
|
|
69
|
-
} from "
|
|
70
|
-
import {
|
|
71
|
-
import { formatMetricValue, formatPlainNumber, localizedDisplay } from "
|
|
72
|
-
import {
|
|
73
|
-
import {
|
|
74
|
-
import type { LocalizedText } from "./locale.ts";
|
|
54
|
+
} from "../../model/aggregate.ts";
|
|
55
|
+
import { examScore } from "../../model/metrics.ts";
|
|
56
|
+
import { formatMetricValue, formatPlainNumber, localizedDisplay } from "../../model/format.ts";
|
|
57
|
+
import type { LocalizedText } from "../../model/locale.ts";
|
|
58
|
+
import { selectedEvalsOnly } from "../shared-compute.ts";
|
|
75
59
|
|
|
76
60
|
// ───────────────────────── metricTableData ─────────────────────────
|
|
77
61
|
|
|
@@ -173,290 +157,6 @@ export async function metricMatrixData(input: ReportInput, options: MetricMatrix
|
|
|
173
157
|
};
|
|
174
158
|
}
|
|
175
159
|
|
|
176
|
-
// ───────────────────────── 实体列表(experimentListData / evalListData / attemptListData)─────────────────────────
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* 一次 attempt 的单行结果摘要(Scoring display 契约):failed 取主失败断言摘要(不含
|
|
180
|
-
* "+N more",N 单独进 moreFailures),errored 取结构化 error 的一层摘要
|
|
181
|
-
* (phase · code · message),passed / skipped 为 null。
|
|
182
|
-
*/
|
|
183
|
-
function failureSummaryOf(result: EvalResult): { summary: string | null; more: number } {
|
|
184
|
-
if (result.verdict === "errored" && result.error !== undefined) {
|
|
185
|
-
const parts = [result.error.phase, result.error.code, result.error.message].filter(
|
|
186
|
-
(part): part is string => typeof part === "string" && part.length > 0,
|
|
187
|
-
);
|
|
188
|
-
return { summary: summaryText(parts.join(" · ")), more: 0 };
|
|
189
|
-
}
|
|
190
|
-
if (result.verdict === "failed" || result.verdict === "errored") {
|
|
191
|
-
const primary = primaryAssertionSummary(result.assertions, result.verdict);
|
|
192
|
-
if (primary !== undefined) {
|
|
193
|
-
return {
|
|
194
|
-
summary: compactAssertionSummary({ ...primary, additionalFailures: 0 }),
|
|
195
|
-
more: primary.additionalFailures,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
if (result.verdict === "errored" && result.skipReason !== undefined) {
|
|
199
|
-
return { summary: summaryText(result.skipReason), more: 0 };
|
|
200
|
-
}
|
|
201
|
-
return { summary: null, more: 0 };
|
|
202
|
-
}
|
|
203
|
-
return { summary: null, more: 0 };
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/** AttemptList / ExperimentList / EvalList 共用的叶子构造:一个 Item → 一个 AttemptListItem。 */
|
|
207
|
-
async function attemptListItemOf(item: Item): Promise<AttemptListItem> {
|
|
208
|
-
const result = item.attempt.result;
|
|
209
|
-
const { summary, more } = failureSummaryOf(result);
|
|
210
|
-
return {
|
|
211
|
-
experimentId: experimentIdOf(item),
|
|
212
|
-
evalId: evalIdOf(item),
|
|
213
|
-
attempt: result.attempt,
|
|
214
|
-
agent: result.agent,
|
|
215
|
-
verdict: result.verdict,
|
|
216
|
-
failureSummary: summary,
|
|
217
|
-
moreFailures: more,
|
|
218
|
-
examScore: await computeCell(examScore, [item]),
|
|
219
|
-
durationMs: result.durationMs,
|
|
220
|
-
costUSD: attemptCostUSD(result),
|
|
221
|
-
locator: locatorOf(item),
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/** `attemptListData(input)`:每个 Attempt 一项,顺序取自 Scope 展平顺序(不重排)。 */
|
|
226
|
-
export async function attemptListData(input: ReportInput): Promise<AttemptListItem[]> {
|
|
227
|
-
const { snapshots } = resolveInput(input);
|
|
228
|
-
const items = collectItems(snapshots);
|
|
229
|
-
return Promise.all(items.map((item) => attemptListItemOf(item)));
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/** `evalListData(input)`:每个 `experimentId + evalId` 一项,按 evalId 再按 experimentId 升序。 */
|
|
233
|
-
export async function evalListData(input: ReportInput): Promise<EvalListItem[]> {
|
|
234
|
-
const { snapshots } = resolveInput(input);
|
|
235
|
-
const items = collectItems(snapshots);
|
|
236
|
-
const groups = new Map<string, Item[]>();
|
|
237
|
-
for (const item of items) {
|
|
238
|
-
const key = fullEvalKey(item);
|
|
239
|
-
const list = groups.get(key);
|
|
240
|
-
if (list) list.push(item);
|
|
241
|
-
else groups.set(key, [item]);
|
|
242
|
-
}
|
|
243
|
-
const out: EvalListItem[] = [];
|
|
244
|
-
for (const group of groups.values()) {
|
|
245
|
-
const sorted = [...group].sort((a, b) => a.attempt.result.attempt - b.attempt.result.attempt);
|
|
246
|
-
const verdict = foldEvalVerdict(sorted.map((item) => item.attempt.result));
|
|
247
|
-
const attempts = await Promise.all(sorted.map((item) => attemptListItemOf(item)));
|
|
248
|
-
out.push({
|
|
249
|
-
experimentId: experimentIdOf(sorted[0]!),
|
|
250
|
-
evalId: evalIdOf(sorted[0]!),
|
|
251
|
-
verdict,
|
|
252
|
-
examScore: await computeCell(examScore, sorted),
|
|
253
|
-
durationMs: await computeCell(durationMs, sorted),
|
|
254
|
-
costUSD: await computeCell(costUSD, sorted),
|
|
255
|
-
attempts,
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
out.sort((a, b) => a.evalId.localeCompare(b.evalId) || a.experimentId.localeCompare(b.experimentId));
|
|
259
|
-
return out;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* `experimentListData(input)`:每个 experiment 一项,展开到每道 Eval;初始按端到端成功率
|
|
264
|
-
* 从高到低(缺数据沉底,同分按 id)。一行只有一套 agent / model / flags 是输入约束:
|
|
265
|
-
* 宿主注入的 current() Scope 保证每个 experiment 只由可比性配置一致的快照拼成;作者自选
|
|
266
|
-
* Snapshot[] 时若同一 experiment 混入不一致的可比性配置,按完整用户反馈失败并指引——
|
|
267
|
-
* 看跨配置演化用 snapshot 维度或 MetricLine,不把两套配置拼成一行冒充单一配置。
|
|
268
|
-
*/
|
|
269
|
-
export async function experimentListData(input: ReportInput): Promise<ExperimentListItem[]> {
|
|
270
|
-
const { snapshots } = resolveInput(input);
|
|
271
|
-
|
|
272
|
-
// 可比性配置单义检查:同一 experiment 的输入快照必须共享一套可比性配置。
|
|
273
|
-
const configByExperiment = new Map<string, { snapshot: Snapshot; config: unknown }>();
|
|
274
|
-
for (const snapshot of snapshots) {
|
|
275
|
-
const config = comparabilityConfigOf(snapshot);
|
|
276
|
-
const existing = configByExperiment.get(snapshot.experimentId);
|
|
277
|
-
if (existing === undefined) {
|
|
278
|
-
configByExperiment.set(snapshot.experimentId, { snapshot, config });
|
|
279
|
-
} else if (!deepEqualJson(existing.config, config)) {
|
|
280
|
-
throw new Error(
|
|
281
|
-
`experimentListData got inconsistent comparability configs for experiment "${snapshot.experimentId}" ` +
|
|
282
|
-
`(snapshots ${existing.snapshot.startedAt} and ${snapshot.startedAt} differ in agent/model/reasoningEffort/flags/budget/timeoutMs/sandbox). ` +
|
|
283
|
-
"One row shows one configuration — it cannot honestly merge two. To chart evolution across configs, " +
|
|
284
|
-
'use the "snapshot" dimension or MetricLine; to show the current level, pass results.current() which selects a single config per experiment.',
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const items = collectItems(snapshots);
|
|
290
|
-
const groups = groupItems(items, "experiment");
|
|
291
|
-
const out: ExperimentListItem[] = [];
|
|
292
|
-
for (const [experimentId, group] of groups) {
|
|
293
|
-
const stats = summarizeItems(group);
|
|
294
|
-
const newest = [...group].sort((a, b) => b.snapshot.startedAt.localeCompare(a.snapshot.startedAt))[0]!;
|
|
295
|
-
const evalGroups = groupItems(group, "eval");
|
|
296
|
-
const evalRows: ExperimentListEvalRow[] = [];
|
|
297
|
-
for (const [evalId, evalItems] of evalGroups) {
|
|
298
|
-
const sorted = [...evalItems].sort((a, b) => a.attempt.result.attempt - b.attempt.result.attempt);
|
|
299
|
-
const verdict = foldEvalVerdict(sorted.map((item) => item.attempt.result));
|
|
300
|
-
const attempts = await Promise.all(sorted.map((item) => attemptListItemOf(item)));
|
|
301
|
-
evalRows.push({
|
|
302
|
-
evalId,
|
|
303
|
-
verdict,
|
|
304
|
-
durationMs: await computeCell(durationMs, sorted),
|
|
305
|
-
costUSD: await computeCell(costUSD, sorted),
|
|
306
|
-
attempts,
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
const experiment = newest.snapshot.experiment ?? newest.attempt.result.experiment;
|
|
310
|
-
const model = newest.attempt.result.model ?? newest.snapshot.model;
|
|
311
|
-
out.push({
|
|
312
|
-
experimentId,
|
|
313
|
-
agent: newest.snapshot.agent || newest.attempt.result.agent,
|
|
314
|
-
...(model !== undefined ? { model } : {}),
|
|
315
|
-
...(experiment?.flags ? { flags: experiment.flags } : {}),
|
|
316
|
-
evalVerdicts: stats.verdicts,
|
|
317
|
-
endToEndPassRate: await computeCell(endToEndPassRate, group),
|
|
318
|
-
costUSD: await computeCell(costUSD, group),
|
|
319
|
-
durationMs: await computeCell(durationMs, group),
|
|
320
|
-
tokens: await computeCell(tokens, group),
|
|
321
|
-
evals: stats.evals,
|
|
322
|
-
attempts: stats.attempts,
|
|
323
|
-
lastRunAt: stats.lastRunAt!,
|
|
324
|
-
evalRows,
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
// 初始态按端到端成功率(endToEndPassRate)从高到低,缺数据沉底;同分按 experiment id 稳定排序。
|
|
328
|
-
out.sort((a, b) => {
|
|
329
|
-
const va = a.endToEndPassRate.value;
|
|
330
|
-
const vb = b.endToEndPassRate.value;
|
|
331
|
-
if (va === null && vb === null) return a.experimentId.localeCompare(b.experimentId);
|
|
332
|
-
if (va === null) return 1;
|
|
333
|
-
if (vb === null) return -1;
|
|
334
|
-
return vb - va || a.experimentId.localeCompare(b.experimentId);
|
|
335
|
-
});
|
|
336
|
-
return out;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// ───────────────────────── scopeSummaryData ─────────────────────────
|
|
340
|
-
|
|
341
|
-
/** costUSD 的求和投影:两级都 sum(题内多轮求和 + 跨题求和 = 全量求和),display 走 $。 */
|
|
342
|
-
const totalCostMetric = defineMetric({
|
|
343
|
-
name: "total-cost",
|
|
344
|
-
label: costUSD.label,
|
|
345
|
-
unit: "$",
|
|
346
|
-
value: costUSD.value,
|
|
347
|
-
aggregate: { perEval: "sum", acrossEvals: "sum" },
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
function tallyOf(): VerdictTally {
|
|
351
|
-
return { passed: 0, failed: 0, errored: 0, skipped: 0 };
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/** 一批 Item 的组级统计(experimentListData / scopeSummaryData 共用)。 */
|
|
355
|
-
function summarizeItems(items: Item[]): {
|
|
356
|
-
experiments: number;
|
|
357
|
-
evals: number;
|
|
358
|
-
attempts: number;
|
|
359
|
-
verdicts: VerdictTally;
|
|
360
|
-
lastRunAt: string | undefined;
|
|
361
|
-
} {
|
|
362
|
-
const experimentIds = new Set<string>();
|
|
363
|
-
for (const item of items) experimentIds.add(experimentIdOf(item));
|
|
364
|
-
const stats = evalLevelStats(
|
|
365
|
-
items.map((item) => ({ verdict: item.attempt.result.verdict, key: fullEvalKey(item) })),
|
|
366
|
-
(r) => r.key,
|
|
367
|
-
);
|
|
368
|
-
let lastRunAt: string | undefined;
|
|
369
|
-
for (const item of items) {
|
|
370
|
-
const startedAt = item.snapshot.startedAt;
|
|
371
|
-
if (lastRunAt === undefined || startedAt > lastRunAt) lastRunAt = startedAt;
|
|
372
|
-
}
|
|
373
|
-
return {
|
|
374
|
-
experiments: experimentIds.size,
|
|
375
|
-
evals: stats.evals,
|
|
376
|
-
attempts: items.length,
|
|
377
|
-
verdicts: { passed: stats.passed, failed: stats.failed, errored: stats.errored, skipped: stats.skipped },
|
|
378
|
-
lastRunAt,
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* `scopeSummaryData(input)`:范围摘要——快照时间窗、experiment / eval / attempt 数、
|
|
384
|
-
* 两级判定计票、端到端成功率与总成本(docs/feature/reports/library/summaries.md)。
|
|
385
|
-
* data 恒携带两级计票;成功率来自官方两级指标引擎,不从任一计票重算。
|
|
386
|
-
*/
|
|
387
|
-
export async function scopeSummaryData(input: ReportInput): Promise<ScopeSummaryData> {
|
|
388
|
-
const { snapshots } = resolveInput(input);
|
|
389
|
-
const items = collectItems(snapshots);
|
|
390
|
-
|
|
391
|
-
let earliest: string | null = null;
|
|
392
|
-
let latest: string | null = null;
|
|
393
|
-
for (const snapshot of snapshots) {
|
|
394
|
-
if (earliest === null || snapshot.startedAt < earliest) earliest = snapshot.startedAt;
|
|
395
|
-
if (latest === null || snapshot.startedAt > latest) latest = snapshot.startedAt;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
const stats = summarizeItems(items);
|
|
399
|
-
const attemptVerdicts = tallyOf();
|
|
400
|
-
for (const item of items) attemptVerdicts[item.attempt.result.verdict] += 1;
|
|
401
|
-
|
|
402
|
-
return {
|
|
403
|
-
range: { earliestStartedAt: earliest, latestStartedAt: latest },
|
|
404
|
-
experiments: stats.experiments,
|
|
405
|
-
evals: stats.evals,
|
|
406
|
-
attempts: stats.attempts,
|
|
407
|
-
evalVerdicts: stats.verdicts,
|
|
408
|
-
attemptVerdicts,
|
|
409
|
-
endToEndPassRate: await computeCell(endToEndPassRate, items),
|
|
410
|
-
totalCostUSD: await computeCell(totalCostMetric, items),
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// ───────────────────────── experimentComparisonData ─────────────────────────
|
|
415
|
-
|
|
416
|
-
/** 完整父路径是组键;没有父路径的 experiment 不能互相比,自己形成单例组。 */
|
|
417
|
-
export function experimentComparisonGroupKey(experimentId: string): string {
|
|
418
|
-
return experimentGroupOf(experimentId) ?? experimentId;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
/** 每组散点的唯一口径:默认 definition 与公开计算共用,不各写一份。 */
|
|
422
|
-
const COMPARISON_SCATTER_OPTIONS: MetricScatterOptions = {
|
|
423
|
-
points: "experiment",
|
|
424
|
-
series: "agent",
|
|
425
|
-
x: costUSD,
|
|
426
|
-
y: endToEndPassRate,
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* `experimentComparisonData(input)`:先把 input 按可比组分区(experiment id 的完整父路径),
|
|
431
|
-
* 再为每组分别计算 ScopeSummary、成本 × 端到端成功率散点和 ExperimentList——分区发生在任何
|
|
432
|
-
* 指标计算之前,组外 attempt 不可能污染该组的坐标尺度、series、成功率、成本、排序或缺数据计数。
|
|
433
|
-
*/
|
|
434
|
-
export async function experimentComparisonData(input: ReportInput): Promise<ExperimentComparisonData> {
|
|
435
|
-
const { snapshots } = resolveInput(input);
|
|
436
|
-
const snapshotsByGroup = new Map<string, Snapshot[]>();
|
|
437
|
-
for (const snapshot of snapshots) {
|
|
438
|
-
const key = experimentComparisonGroupKey(snapshot.experimentId);
|
|
439
|
-
const group = snapshotsByGroup.get(key);
|
|
440
|
-
if (group) group.push(snapshot);
|
|
441
|
-
else snapshotsByGroup.set(key, [snapshot]);
|
|
442
|
-
}
|
|
443
|
-
const groups = await Promise.all(
|
|
444
|
-
[...snapshotsByGroup.entries()]
|
|
445
|
-
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
446
|
-
.map(async ([key, groupSnapshots]): Promise<ExperimentComparisonGroupData> => {
|
|
447
|
-
const [summary, scatter, experiments] = await Promise.all([
|
|
448
|
-
scopeSummaryData(groupSnapshots),
|
|
449
|
-
metricScatterData(groupSnapshots, COMPARISON_SCATTER_OPTIONS),
|
|
450
|
-
experimentListData(groupSnapshots),
|
|
451
|
-
]);
|
|
452
|
-
return { key, summary, scatter, experiments };
|
|
453
|
-
}),
|
|
454
|
-
);
|
|
455
|
-
return { groups };
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// ───────────────────────── scoreboardData ─────────────────────────
|
|
459
|
-
|
|
460
160
|
export interface ScoreboardOptions {
|
|
461
161
|
rows: DimensionInput;
|
|
462
162
|
/** 固定题集;eval id 必须唯一。元素引用运行时数据,类型放宽为普通数组,空数组在计算时报错。 */
|
|
@@ -644,13 +344,11 @@ function subjectDisplay(earned: number, possible: number): LocalizedText {
|
|
|
644
344
|
return `${formatPlainNumber(earned)}/${formatPlainNumber(possible)} (${formatMetricValue(ratio, "%")})`;
|
|
645
345
|
}
|
|
646
346
|
|
|
647
|
-
// ───────────────────────── metricScatterData ─────────────────────────
|
|
648
|
-
|
|
649
347
|
export interface MetricScatterOptions {
|
|
650
348
|
/** 点维度:每个点 = 该组 attempt 的聚合。 */
|
|
651
349
|
points: DimensionInput;
|
|
652
|
-
/**
|
|
653
|
-
series?:
|
|
350
|
+
/** 决定颜色和图例归类,默认不连线(连线是呈现 prop `connect`);数组形态解析为复合维度。 */
|
|
351
|
+
series?: SeriesInput;
|
|
654
352
|
x: Metric;
|
|
655
353
|
y: Metric;
|
|
656
354
|
/** eval id 前缀过滤,同 CLI 位置参数语义。 */
|
|
@@ -658,7 +356,7 @@ export interface MetricScatterOptions {
|
|
|
658
356
|
}
|
|
659
357
|
|
|
660
358
|
export async function metricScatterData(input: ReportInput, options: MetricScatterOptions): Promise<ScatterData> {
|
|
661
|
-
const
|
|
359
|
+
const snapshots = selectedEvalsOnly(resolveInput(input).snapshots);
|
|
662
360
|
const items = filterItems(collectItems(snapshots), options.evals);
|
|
663
361
|
const groups = groupItems(items, options.points);
|
|
664
362
|
const rows: ScatterData["rows"] = [];
|
|
@@ -666,26 +364,25 @@ export async function metricScatterData(input: ReportInput, options: MetricScatt
|
|
|
666
364
|
rows.push({
|
|
667
365
|
key,
|
|
668
366
|
// 组内取第一条解析系列:点维度细于系列维度时(experiment ⊂ agent)天然一致
|
|
669
|
-
...(options.series ? { series:
|
|
367
|
+
...(options.series ? { series: seriesKey(options.series, group[0]!) } : {}),
|
|
670
368
|
x: await computeCell(options.x, group),
|
|
671
369
|
y: await computeCell(options.y, group), // 任一轴 null 的点留在 rows 里:组件不画,但注脚要报的数就从这里数
|
|
672
370
|
});
|
|
673
371
|
}
|
|
674
372
|
return {
|
|
675
373
|
pointDimension: dimensionName(options.points),
|
|
676
|
-
...(options.series ? { seriesDimension:
|
|
374
|
+
...(options.series ? { seriesDimension: seriesName(options.series) } : {}),
|
|
677
375
|
x: toColumn(options.x),
|
|
678
376
|
y: toColumn(options.y),
|
|
679
377
|
rows,
|
|
680
378
|
};
|
|
681
379
|
}
|
|
682
380
|
|
|
683
|
-
// ───────────────────────── metricLineData ─────────────────────────
|
|
684
|
-
|
|
685
381
|
export interface MetricLineOptions {
|
|
686
|
-
/** x 轴:NumericAxis(numericFlag() / numericRunConfig() 或自定义 of),不解析 experiment 命名。 */
|
|
382
|
+
/** x 轴:NumericAxis(numericFlag() / numericLabel() / numericRunConfig() 或自定义 of),不解析 experiment 命名。 */
|
|
687
383
|
x: NumericAxis;
|
|
688
|
-
|
|
384
|
+
/** 数组形态解析为复合维度。 */
|
|
385
|
+
series?: SeriesInput;
|
|
689
386
|
y: Metric;
|
|
690
387
|
/** eval id 前缀过滤,同 CLI 位置参数语义。 */
|
|
691
388
|
evals?: string | readonly string[];
|
|
@@ -719,7 +416,7 @@ export async function metricLineData(input: ReportInput, options: MetricLineOpti
|
|
|
719
416
|
"Fix of() to read experiment-level configuration (numericFlag()/numericRunConfig() do this by construction).",
|
|
720
417
|
);
|
|
721
418
|
}
|
|
722
|
-
const series = options.series ?
|
|
419
|
+
const series = options.series ? seriesKey(options.series, item) : undefined;
|
|
723
420
|
const bucketKey = `${series ?? ""}${x === null ? "null" : String(x)}`;
|
|
724
421
|
const bucket = buckets.get(bucketKey);
|
|
725
422
|
if (bucket) bucket.items.push(item);
|
|
@@ -752,7 +449,7 @@ export async function metricLineData(input: ReportInput, options: MetricLineOpti
|
|
|
752
449
|
label: options.x.label ?? options.x.name,
|
|
753
450
|
...(options.x.unit !== undefined ? { unit: options.x.unit } : {}),
|
|
754
451
|
},
|
|
755
|
-
...(options.series ? { seriesDimension:
|
|
452
|
+
...(options.series ? { seriesDimension: seriesName(options.series) } : {}),
|
|
756
453
|
y: toColumn(options.y),
|
|
757
454
|
rows,
|
|
758
455
|
};
|
|
@@ -762,8 +459,10 @@ export async function metricLineData(input: ReportInput, options: MetricLineOpti
|
|
|
762
459
|
|
|
763
460
|
/**
|
|
764
461
|
* 按 flag 派生 A/B 对(docs/feature/reports/library/metric-views.md「DeltaTable」):
|
|
765
|
-
* 配对域 =
|
|
766
|
-
*
|
|
462
|
+
* 配对域 = input Scope 内删除该 flag 后可比性配置深相等(不额外按 experiment id 的目录前缀分组
|
|
463
|
+
* ——architecture.md「Scope 是默认报告的比较边界」同一条契约);a 取 baseline(缺省 = 未声明该
|
|
464
|
+
* flag),b 侧该 flag 的每个其它取值各成一对;label 自动 `<完整 a experiment id> · <flag>=<显示键>`,
|
|
465
|
+
* 排序仍按 a 的末段、再按 flag 显示键(不受完整 id 的字符串差异影响)。
|
|
767
466
|
*/
|
|
768
467
|
export function pairsByFlag(name: string, options?: { baseline?: JsonValue }): FlagPairs {
|
|
769
468
|
if (typeof name !== "string" || name.length === 0) {
|
|
@@ -790,13 +489,13 @@ function isFlagPairs(pairs: DeltaTableOptions["pairs"]): pairs is FlagPairs {
|
|
|
790
489
|
return typeof pairs === "object" && pairs !== null && !Array.isArray(pairs) && (pairs as FlagPairs).kind === "flagPairs";
|
|
791
490
|
}
|
|
792
491
|
|
|
793
|
-
/** experiment id
|
|
492
|
+
/** experiment id 的末段(最后一个 `/` 之后;无 `/` 时是完整 id)。 */
|
|
794
493
|
function experimentTail(experimentId: string): string {
|
|
795
494
|
const slash = experimentId.lastIndexOf("/");
|
|
796
495
|
return slash === -1 ? experimentId : experimentId.slice(slash + 1);
|
|
797
496
|
}
|
|
798
497
|
|
|
799
|
-
/**
|
|
498
|
+
/** 派生配对:input Scope 内删除该 flag 后可比性配置深相等。返回 pair 列表与配对域实验数。 */
|
|
800
499
|
function derivePairsByFlag(
|
|
801
500
|
snapshots: readonly Snapshot[],
|
|
802
501
|
spec: FlagPairs,
|
|
@@ -820,8 +519,9 @@ function derivePairsByFlag(
|
|
|
820
519
|
const flagValue = config.flags?.[spec.flag];
|
|
821
520
|
const reduced = { ...config, flags: { ...config.flags } };
|
|
822
521
|
delete reduced.flags[spec.flag];
|
|
823
|
-
|
|
824
|
-
|
|
522
|
+
// 配对域只是 input Scope + 删除该 flag 后的可比性配置深相等;不额外按 experiment id 的
|
|
523
|
+
// 目录前缀分组——组件不从路径猜比较边界(architecture.md「Scope 是默认报告的比较边界」)。
|
|
524
|
+
entries.push({ id, flagValue, bucket: JSON.stringify(sortedJson(reduced)) });
|
|
825
525
|
}
|
|
826
526
|
|
|
827
527
|
const baseline = spec.baseline; // undefined = 未声明该 flag 的实验作 a
|
|
@@ -832,28 +532,34 @@ function derivePairsByFlag(
|
|
|
832
532
|
else buckets.set(entry.bucket, [entry]);
|
|
833
533
|
}
|
|
834
534
|
|
|
835
|
-
|
|
535
|
+
interface DerivedPair {
|
|
536
|
+
a: string;
|
|
537
|
+
b: string;
|
|
538
|
+
label: string;
|
|
539
|
+
flagKey: string;
|
|
540
|
+
}
|
|
541
|
+
const derived: DerivedPair[] = [];
|
|
836
542
|
for (const bucket of buckets.values()) {
|
|
837
543
|
const aSide = bucket.filter((e) => deepEqualJson(e.flagValue, baseline));
|
|
838
544
|
const bSide = bucket.filter((e) => !deepEqualJson(e.flagValue, baseline));
|
|
839
545
|
for (const a of aSide) {
|
|
840
546
|
for (const b of bSide) {
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
});
|
|
547
|
+
const flagKey = refDisplayKey(b.flagValue)[0]!;
|
|
548
|
+
// label 用完整 a experiment id 自动命名,不截断成末段——目录前缀不同的两个实验
|
|
549
|
+
// 配成一对时,末段可能撞名,完整 id 才能唯一标识这一对来自哪个实验。
|
|
550
|
+
derived.push({ a: a.id, b: b.id, label: `${a.id} · ${spec.flag}=${flagKey}`, flagKey });
|
|
846
551
|
}
|
|
847
552
|
}
|
|
848
553
|
}
|
|
849
|
-
|
|
554
|
+
// 排序只看 a 的末段与 flag 显示键,不看完整 label 字符串——完整 a id 只服务显示,
|
|
555
|
+
// 不该让目录前缀的字符串差异打乱本该相邻的 a 末段分组。
|
|
556
|
+
derived.sort((p, q) => {
|
|
850
557
|
const ta = experimentTail(p.a);
|
|
851
558
|
const tb = experimentTail(q.a);
|
|
852
559
|
if (ta !== tb) return ta < tb ? -1 : 1;
|
|
853
|
-
|
|
854
|
-
const lb = q.label as string;
|
|
855
|
-
return la < lb ? -1 : la > lb ? 1 : 0;
|
|
560
|
+
return p.flagKey < q.flagKey ? -1 : p.flagKey > q.flagKey ? 1 : 0;
|
|
856
561
|
});
|
|
562
|
+
const pairs: DeltaPair[] = derived.map(({ a, b, label }) => ({ a, b, label }));
|
|
857
563
|
return { pairs, experiments: byExperiment.size };
|
|
858
564
|
}
|
|
859
565
|
|
|
@@ -974,135 +680,3 @@ function deltaOutcome(metric: Metric, delta: number | null): "improved" | "regre
|
|
|
974
680
|
const better = metric.better ?? "higher";
|
|
975
681
|
return (delta > 0) === (better === "higher") ? "improved" : "regressed";
|
|
976
682
|
}
|
|
977
|
-
|
|
978
|
-
// ───────────────────────── 站点组件的计算函数(hero / warnings / fix prompt / trace)─────────────────────────
|
|
979
|
-
|
|
980
|
-
/**
|
|
981
|
-
* `heroData(input)`:站点标题区的运行 meta——`latestStartedAt` 取范围内最新快照的开始时间
|
|
982
|
-
* (空范围为 null,不编造当前时间),`snapshots` 计贡献当前水位的快照数
|
|
983
|
-
* (docs/feature/reports/library/site-components.md「HeroCard」)。
|
|
984
|
-
*/
|
|
985
|
-
export async function heroData(input: ReportInput): Promise<HeroData> {
|
|
986
|
-
const { snapshots } = resolveInput(input);
|
|
987
|
-
let latest: string | null = null;
|
|
988
|
-
for (const snapshot of snapshots) {
|
|
989
|
-
if (latest === null || snapshot.startedAt > latest) latest = snapshot.startedAt;
|
|
990
|
-
}
|
|
991
|
-
return { latestStartedAt: latest, snapshots: snapshots.length };
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
/**
|
|
995
|
-
* `scopeWarningsData(input)`:Scope 携带的挑选警告原样透出;`input` 是裸 `Snapshot[]` 时
|
|
996
|
-
* 没有挑选过程、没有警告,返回空数组,也如实
|
|
997
|
-
* (docs/feature/reports/library/site-components.md「ScopeWarnings」)。
|
|
998
|
-
*/
|
|
999
|
-
export async function scopeWarningsData(input: ReportInput): Promise<readonly ScopeWarning[]> {
|
|
1000
|
-
return resolveInput(input).warnings;
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
/**
|
|
1004
|
-
* `copyFixPromptData(input)`:把范围内全部失败(verdict 为 failed / errored 的 attempt)
|
|
1005
|
-
* 整理成一段可交给 coding agent 的修复 prompt——逐失败含 eval id、主失败摘要与 attempt
|
|
1006
|
-
* 下钻命令(`niceeval show @<locator>`)。prompt 面向 agent,固定英文
|
|
1007
|
-
* (docs/feature/reports/library/site-components.md「CopyFixPrompt」)。
|
|
1008
|
-
*/
|
|
1009
|
-
export async function copyFixPromptData(input: ReportInput): Promise<CopyFixPromptData> {
|
|
1010
|
-
const items = await attemptListData(input);
|
|
1011
|
-
const failures = items.filter((item) => item.verdict === "failed" || item.verdict === "errored");
|
|
1012
|
-
if (failures.length === 0) return { prompt: "", failures: 0 };
|
|
1013
|
-
const lines = failures
|
|
1014
|
-
.map((item, i) => {
|
|
1015
|
-
const reason =
|
|
1016
|
-
item.failureSummary === null
|
|
1017
|
-
? null
|
|
1018
|
-
: item.moreFailures > 0
|
|
1019
|
-
? `${item.failureSummary} (+${item.moreFailures} more failures)`
|
|
1020
|
-
: item.failureSummary;
|
|
1021
|
-
return [
|
|
1022
|
-
`${i + 1}. eval "${item.evalId}" [experiment ${item.experimentId}] — ${item.verdict}`,
|
|
1023
|
-
reason ? ` reason: ${reason}` : null,
|
|
1024
|
-
` inspect: niceeval show ${item.locator}`,
|
|
1025
|
-
]
|
|
1026
|
-
.filter(Boolean)
|
|
1027
|
-
.join("\n");
|
|
1028
|
-
})
|
|
1029
|
-
.join("\n");
|
|
1030
|
-
const experiments = [...new Set(failures.map((item) => item.experimentId))].join(" / ");
|
|
1031
|
-
const prompt = [
|
|
1032
|
-
"Fix the failing evals from this niceeval run.",
|
|
1033
|
-
"",
|
|
1034
|
-
"## Failures",
|
|
1035
|
-
lines,
|
|
1036
|
-
"",
|
|
1037
|
-
"## Steps",
|
|
1038
|
-
"1. niceeval is NOT in your training data. Read the relevant guide in `node_modules/niceeval/docs-site/` (English at the top level, Chinese under `zh/`) before changing anything.",
|
|
1039
|
-
"2. For each failure, run its inspect command above to see the verdict and assertions; add `--execution` for the full agent transcript (tool calls included), `--timing` for the execution timeline, and `--diff` for the workspace diff.",
|
|
1040
|
-
"3. Decide which side the defect is on: the program under test, or the eval itself (over-tight assertion, wrong fixture, missing setup). Fix that side; do not weaken assertions just to turn the run green.",
|
|
1041
|
-
`4. Re-run: \`npx niceeval exp ${experiments || "<experiment>"} <eval-id-prefix>\`. Already-passing evals are skipped by the fingerprint cache; pass \`--force\` to re-run everything.`,
|
|
1042
|
-
"5. Run `npx niceeval show` and confirm these failures are gone.",
|
|
1043
|
-
].join("\n");
|
|
1044
|
-
return { prompt, failures: failures.length };
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
/** TraceSpan 的语义角色 → 瀑布摘要的 kind:turn 归入 agent(一轮就是一次 agent 调用),未识别落 other。 */
|
|
1048
|
-
function waterfallKindOf(kind: TraceSpan["kind"]): TraceSpanSummary["kind"] {
|
|
1049
|
-
switch (kind) {
|
|
1050
|
-
case "agent":
|
|
1051
|
-
case "turn":
|
|
1052
|
-
return "agent";
|
|
1053
|
-
case "model":
|
|
1054
|
-
return "model";
|
|
1055
|
-
case "tool":
|
|
1056
|
-
return "tool";
|
|
1057
|
-
default:
|
|
1058
|
-
return "other";
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
/**
|
|
1063
|
-
* `traceWaterfallData(input)`:每个 attempt 一行的执行时间瀑布摘要。span 事实只来自
|
|
1064
|
-
* trace artifact(经 AttemptHandle 懒加载的 canonical OTel span);runner 生命周期节点
|
|
1065
|
-
* (`result.phases`)不进瀑布。行内只汇总顶层 span(parentSpanId 缺失或不在本 trace 内),
|
|
1066
|
-
* 按 startOffsetMs 升序;trace 缺失或为空时 `durationMs` 为 null、行照常出现
|
|
1067
|
-
* (docs/feature/reports/library/site-components.md「TraceWaterfall」)。
|
|
1068
|
-
*/
|
|
1069
|
-
export async function traceWaterfallData(input: ReportInput): Promise<readonly TraceWaterfallRow[]> {
|
|
1070
|
-
const { snapshots } = resolveInput(input);
|
|
1071
|
-
const items = collectItems(snapshots);
|
|
1072
|
-
return Promise.all(
|
|
1073
|
-
items.map(async (item): Promise<TraceWaterfallRow> => {
|
|
1074
|
-
const spans = await item.attempt.trace();
|
|
1075
|
-
if (spans === null || spans.length === 0) {
|
|
1076
|
-
return {
|
|
1077
|
-
experimentId: experimentIdOf(item),
|
|
1078
|
-
evalId: evalIdOf(item),
|
|
1079
|
-
locator: locatorOf(item),
|
|
1080
|
-
durationMs: null,
|
|
1081
|
-
spans: [],
|
|
1082
|
-
};
|
|
1083
|
-
}
|
|
1084
|
-
const t0 = Math.min(...spans.map((s) => s.startMs));
|
|
1085
|
-
const t1 = Math.max(...spans.map((s) => s.endMs));
|
|
1086
|
-
const ids = new Set(spans.map((s) => s.spanId));
|
|
1087
|
-
const topLevel = spans.filter((s) => s.parentSpanId === undefined || !ids.has(s.parentSpanId));
|
|
1088
|
-
const summaries = topLevel
|
|
1089
|
-
.map(
|
|
1090
|
-
(s): TraceSpanSummary => ({
|
|
1091
|
-
name: s.name,
|
|
1092
|
-
kind: waterfallKindOf(s.kind),
|
|
1093
|
-
startOffsetMs: s.startMs - t0,
|
|
1094
|
-
durationMs: s.endMs - s.startMs,
|
|
1095
|
-
failed: s.status === "error",
|
|
1096
|
-
}),
|
|
1097
|
-
)
|
|
1098
|
-
.sort((a, b) => a.startOffsetMs - b.startOffsetMs);
|
|
1099
|
-
return {
|
|
1100
|
-
experimentId: experimentIdOf(item),
|
|
1101
|
-
evalId: evalIdOf(item),
|
|
1102
|
-
locator: locatorOf(item),
|
|
1103
|
-
durationMs: Math.max(0, t1 - t0),
|
|
1104
|
-
spans: summaries,
|
|
1105
|
-
};
|
|
1106
|
-
}),
|
|
1107
|
-
);
|
|
1108
|
-
}
|