niceeval 0.9.0 → 0.10.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 +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 +15 -7
- 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 +6 -0
- package/dist/report/components/attempt-detail/AttemptConversation.js +34 -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 +27 -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 +254 -0
- package/dist/report/components/attempt-detail/faces.d.ts +14 -0
- package/dist/report/components/attempt-detail/faces.js +235 -0
- package/dist/report/components/attempt-detail/index.d.ts +38 -0
- package/dist/report/components/attempt-detail/index.js +527 -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 +3 -3
- package/dist/report/{react → components/entity-lists}/ExperimentList.js +10 -10
- 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 +174 -0
- package/dist/report/components/entity-lists/index.d.ts +51 -0
- package/dist/report/components/entity-lists/index.js +165 -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 +26 -23
- 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} +44 -12
- package/dist/report/{tree.js → definition/tree.js} +10 -12
- 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} +11 -5
- package/dist/report/{format.js → model/format.js} +48 -4
- 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} +140 -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 +12 -2
- 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 +149 -23
- package/dist/sandbox/docker.d.ts +6 -0
- 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 +15 -1
- package/dist/shared/aggregate.js +32 -1
- 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 +1 -1
- 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 +11 -11
- 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 +35 -32
- 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 +193 -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 +43 -19
- 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 +103 -0
- package/docs-site/zh/{how-to → tutorials}/fixtures.mdx +9 -9
- package/docs-site/zh/{how-to → tutorials}/publish-report.mdx +11 -5
- 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 +59 -50
- package/docs-site/zh/tutorials/write-experiment.mdx +355 -0
- package/docs-site/zh/{how-to → tutorials}/write-send.mdx +40 -40
- package/package.json +8 -4
- 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 +77 -64
- package/src/context/types.ts +21 -21
- package/src/define.ts +13 -0
- package/src/i18n/en.ts +30 -15
- package/src/i18n/zh-CN.ts +30 -15
- package/src/index.ts +2 -0
- package/src/report/{react → assets}/colors.ts +22 -0
- package/src/report/{react → assets}/enhance.js +1 -33
- package/src/report/{react → assets}/styles.css +136 -112
- 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 +110 -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 +80 -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 +680 -0
- package/src/report/components/attempt-detail/compute.ts +287 -0
- package/src/report/components/attempt-detail/faces.ts +257 -0
- package/src/report/components/attempt-detail/index.tsx +583 -0
- package/src/report/components/attempt-detail/validate.test.ts +235 -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 +23 -20
- package/src/report/components/entity-lists/compute.ts +196 -0
- package/src/report/components/entity-lists/faces.ts +207 -0
- package/src/report/components/entity-lists/index.tsx +241 -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 +41 -33
- 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 +47 -17
- 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} +58 -22
- package/src/report/index.ts +126 -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} +59 -5
- 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} +143 -22
- package/src/report/react/index.tsx +52 -26
- package/src/report/{dual-render.test.tsx → runtime/dual-render.test.tsx} +564 -49
- 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 +54 -3
- package/src/results/select.ts +30 -6
- 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 +158 -23
- package/src/sandbox/docker.ts +7 -0
- package/src/sandbox/e2b.ts +12 -13
- 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 +30 -1
- 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 +58 -22
- package/src/show/render.ts +16 -240
- package/src/show/show.test.ts +128 -35
- package/src/view/app/App.test.tsx +8 -7
- package/src/view/app/App.tsx +135 -51
- 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 +122 -89
- package/src/view/index.ts +3 -13
- package/src/view/server.ts +36 -6
- 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 +18 -806
- package/src/view/view-report.test.ts +182 -34
- 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/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
package/src/runner/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// runner 域类型:结果 / 汇总 / reporter 契约,eval / experiment / config 定义,
|
|
2
2
|
// 以及调度器的编排类型(AgentRun / RunOptions / Attempt)。
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { JsonValue, LocalizedText, ScopedFeedback, SourceArtifact } from "../shared/types.ts";
|
|
5
5
|
import type { O11ySummary, StreamEvent, TraceSpan, Usage } from "../o11y/types.ts";
|
|
6
6
|
import type { Agent, AgentSetupManifest } from "../agents/types.ts";
|
|
7
7
|
import type { Sandbox, SandboxHookContext, SandboxOption } from "../sandbox/types.ts";
|
|
@@ -21,6 +21,8 @@ export interface ExperimentRunInfo {
|
|
|
21
21
|
description?: string;
|
|
22
22
|
reasoningEffort?: string;
|
|
23
23
|
flags?: Record<string, JsonValue>;
|
|
24
|
+
/** 报告归类标注(ExperimentDef.labels 原样投影);不透传运行时,不参与可比性配置。 */
|
|
25
|
+
labels?: Record<string, string | number>;
|
|
24
26
|
runs: number;
|
|
25
27
|
earlyExit: boolean;
|
|
26
28
|
timeoutMs?: number;
|
|
@@ -50,6 +52,10 @@ export interface SandboxRunInfo {
|
|
|
50
52
|
* provider / 用户 hook 能直接设置的公共字段。
|
|
51
53
|
*/
|
|
52
54
|
export type LifecyclePhase =
|
|
55
|
+
// 实验级(整场一次,宿主机侧):只用于错误/诊断归因,不属于任何单个 attempt,
|
|
56
|
+
// 永不出现在 phases[] 计时里(见 docs/feature/experiments/architecture.md「实验级生命周期」)
|
|
57
|
+
| "experiment.setup" // ExperimentDef.setup;setup 抛错时本实验所有 attempt 的 error.phase
|
|
58
|
+
| "experiment.teardown" // ExperimentDef.teardown;失败只产生运行级 diagnostic
|
|
53
59
|
// 主链:从排队到 trace collect,覆盖到判定与主证据收集完成,按执行序
|
|
54
60
|
| "sandbox.queue" // 等待并发信号量(调度等待,唯一不属于某个 owner 的成员)
|
|
55
61
|
| "sandbox.create" // provider 起沙箱
|
|
@@ -64,7 +70,7 @@ export type LifecyclePhase =
|
|
|
64
70
|
| "scoring.evaluate" // 断言 finalize + 判定,含 judge 调用
|
|
65
71
|
| "telemetry.collect" // OTLP receiver settle / collect
|
|
66
72
|
// 收尾段:无论主链成败都执行,不计入 durationMs 口径,按执行序
|
|
67
|
-
| "eval.teardown" // EvalDef.
|
|
73
|
+
| "eval.teardown" // EvalDef.teardown
|
|
68
74
|
| "agent.teardown"
|
|
69
75
|
| "sandbox.teardown" // SandboxSpec.teardown() 钩子链
|
|
70
76
|
| "sandbox.suspend" // 留存提交后 provider 把现场转入休眠(docker stop / e2b pause)
|
|
@@ -320,32 +326,41 @@ export interface EvalDef {
|
|
|
320
326
|
description?: string;
|
|
321
327
|
/** 标签,供 CLI `--tag` 过滤和 view 分类;与 id 前缀过滤是两套独立的筛选维度。 */
|
|
322
328
|
tags?: string[];
|
|
323
|
-
/**
|
|
329
|
+
/** 这条评估用例需要的环境 profile id(provider-neutral,如 `"python-3.9-astropy-4.2"`);由 sandbox spec 的 `environments` 表翻译成该 provider 的预制产物。 */
|
|
324
330
|
environment?: string;
|
|
325
|
-
/** 覆盖项目级 Config.judge
|
|
331
|
+
/** 覆盖项目级 Config.judge,只对这一条评估用例生效(如换个更贵的评审模型)。 */
|
|
326
332
|
judge?: JudgeConfig;
|
|
327
|
-
/** 覆盖 / 追加项目级 Config.reporters
|
|
333
|
+
/** 覆盖 / 追加项目级 Config.reporters,只对这一条评估用例生效。 */
|
|
328
334
|
reporters?: Reporter[];
|
|
329
|
-
/** 覆盖项目级 / CLI 的单次 attempt 超时(毫秒)
|
|
335
|
+
/** 覆盖项目级 / CLI 的单次 attempt 超时(毫秒),只对这一条评估用例生效。 */
|
|
330
336
|
timeoutMs?: number;
|
|
331
337
|
/** 任意附加元数据,原样透传进 EvalResult,不参与调度或打分;供自定义 reporter 消费。 */
|
|
332
338
|
metadata?: Record<string, unknown>;
|
|
333
339
|
/**
|
|
334
|
-
* 调整 agent diff 的归因排除清单(
|
|
340
|
+
* 调整 agent diff 的归因排除清单(仅 Sandbox 型;见 docs/feature/eval/README.md):两个数组都是
|
|
335
341
|
* gitignore 风格 glob(workdir 相对)。默认排除 .git/node_modules/构建产物/包管理器缓存;
|
|
336
342
|
* `ignore` 在默认清单上追加排除;`include` 优先级最高,把匹配路径显式加回。
|
|
337
343
|
* 合成规则固定为「默认 ∪ ignore,再被 include 打洞」,清单在分类账锚点时冻结。
|
|
338
344
|
*/
|
|
339
345
|
diff?: { include?: string[]; ignore?: string[] };
|
|
340
346
|
/**
|
|
341
|
-
*
|
|
347
|
+
* 评估用例级预置:拿到 Sandbox(已上传 workspace + git 基线 + 装好依赖前)。
|
|
342
348
|
* 默认命令以非 root 跑(agent 的自然环境);装系统依赖时给 `runCommand` 传 `{ root: true }`
|
|
343
349
|
* (如 `runCommand("apt-get", ["install", …], { root: true })`),跨 provider 语义一致。
|
|
344
350
|
* 第二个参数是绑定到 `eval.setup` 的窄上下文(`ctx.progress` / `ctx.diagnostic`,
|
|
345
|
-
* 见 docs/feature/eval/README.md)
|
|
351
|
+
* 见 docs/feature/eval/README.md)。setup 不返回值;要把产物传给 teardown,
|
|
352
|
+
* 以 `sandbox` 实例作键存取(并发 attempt 共享同一模块,普通模块变量会互相覆写)。
|
|
346
353
|
*/
|
|
347
|
-
setup?: (sandbox: Sandbox, ctx: SandboxHookContext) => Promise<void
|
|
348
|
-
/**
|
|
354
|
+
setup?: (sandbox: Sandbox, ctx: SandboxHookContext) => Promise<void> | void;
|
|
355
|
+
/**
|
|
356
|
+
* 评估用例级收尾:attempt 收尾链的第一段(`eval.teardown` → `agent.teardown` →
|
|
357
|
+
* `sandbox.teardown`),Sandbox 此刻还活着。当且仅当 `eval.setup` 时点走到过才执行——
|
|
358
|
+
* `setup` / `test` 抛错都不豁免,未声明 `setup` 不影响触发;抛错或超 30s 清理上限
|
|
359
|
+
* 只记 `teardown-failed` 诊断,不改判定。管 Sandbox 外的临时 Fixture(临时 repo / bucket),
|
|
360
|
+
* Sandbox 内的东西随销毁自动回收、不需要它。
|
|
361
|
+
*/
|
|
362
|
+
teardown?: (sandbox: Sandbox, ctx: SandboxHookContext) => Promise<void> | void;
|
|
363
|
+
/** 评估用例主体:拿到 TestContext,驱动对话 / Sandbox 操作并就地断言。 */
|
|
349
364
|
test(t: TestContext): Promise<void> | void;
|
|
350
365
|
}
|
|
351
366
|
|
|
@@ -363,6 +378,21 @@ export interface DiscoveredEval extends EvalDef {
|
|
|
363
378
|
source: CapturedEvalSource;
|
|
364
379
|
}
|
|
365
380
|
|
|
381
|
+
/**
|
|
382
|
+
* `ExperimentDef.setup` / `teardown` 拿到的窄上下文。`progress` 更新本实验运行级
|
|
383
|
+
* active 行的次要文本(短命状态,agent/ci profile 不逐条输出),`diagnostic` 进运行级永久
|
|
384
|
+
* 事件流(实验级钩子不属于任何单个 attempt,诊断不落 attempt 的 `result.json`;setup 抛错
|
|
385
|
+
* 以每条 attempt 的结构化 `error` 落盘,失败仍可回顾)。钩子的起止本身由 runner 直接发布为
|
|
386
|
+
* 运行级反馈,不依赖这里的 `progress`(见 docs/feature/experiments/cli.md「实验级钩子的显示」)。
|
|
387
|
+
*/
|
|
388
|
+
export interface ExperimentHookContext extends ScopedFeedback {
|
|
389
|
+
readonly experimentId: string;
|
|
390
|
+
/** 本实验解析后实际选中的 eval id 全集(evals 过滤器的求值结果)。 */
|
|
391
|
+
readonly selectedEvalIds: readonly string[];
|
|
392
|
+
/** 用户中断(Ctrl+C / kill)时 abort;长启动的 setup 应观察它提前退出。 */
|
|
393
|
+
readonly signal?: AbortSignal;
|
|
394
|
+
}
|
|
395
|
+
|
|
366
396
|
export interface ExperimentDef {
|
|
367
397
|
/** 路径推导,定义里禁止手写(defineExperiment 会拒绝显式传入)。 */
|
|
368
398
|
id?: string;
|
|
@@ -381,12 +411,27 @@ export interface ExperimentDef {
|
|
|
381
411
|
* (defineExperiment 解析时校验,非 JSON 直接报错),经 ctx.flags 透传给 adapter、
|
|
382
412
|
* t.flags 暴露给 eval,并原样进入结果快照的 ExperimentRunInfo.flags。 */
|
|
383
413
|
flags?: Record<string, JsonValue>;
|
|
414
|
+
/**
|
|
415
|
+
* 报告归类标注:实验在各对比轴上的坐标(如 `{ line: "codex", memory: "mempal" }`)。
|
|
416
|
+
* 值域 string | number(解析时校验)。与 `flags` 的分界是「会不会改变 attempt 里发生的事」:
|
|
417
|
+
* labels 不透传 ctx / t(agent 和 eval 看不见)、不参与可比性配置(改它不作废已有结果),
|
|
418
|
+
* 只原样投影进快照的 `ExperimentRunInfo.labels` 供报告维度(`label()` / `numericLabel()`)
|
|
419
|
+
* 分组。`line` 键被默认报告识别:组内任一实验声明了它,散点按线归类并连线。
|
|
420
|
+
* 见 docs/feature/experiments/library.md「labels」。
|
|
421
|
+
*/
|
|
422
|
+
labels?: Record<string, string | number>;
|
|
384
423
|
/** 同一 eval 重复跑几次(结果各计一条 attempt);省略/CLI `--runs` 覆盖时默认 1。 */
|
|
385
424
|
runs?: number;
|
|
386
425
|
/** 一次重复(runs > 1)里某次 attempt 失败后是否跳过剩余重复;省略默认 true(提前退出省钱)。 */
|
|
387
426
|
earlyExit?: boolean;
|
|
388
|
-
/**
|
|
389
|
-
|
|
427
|
+
/**
|
|
428
|
+
* 这个实验覆盖哪些 eval:`"*"` 全部、字符串数组按 id 前缀、或自定义谓词(逐条收到发现并扇出后的
|
|
429
|
+
* 只读 `EvalDescriptor`,不暴露路径 / 执行字段);省略等价于 `"*"`。谓词对本次 invocation 的
|
|
430
|
+
* 候选 eval 各求值一次,解析结果作为 `selectedEvalIds` 落进快照——不是运行时反复调用的过滤器
|
|
431
|
+
* (见 docs/feature/eval/library.md「EvalDescriptor」、docs/feature/experiments/library.md
|
|
432
|
+
* 「evals:遍历发现结果,自定义选择」)。
|
|
433
|
+
*/
|
|
434
|
+
evals?: "*" | readonly string[] | ((e: EvalDescriptor) => boolean);
|
|
390
435
|
/** 覆盖项目级 / CLI 的单次 attempt 超时(毫秒),只对这个实验生效。 */
|
|
391
436
|
timeoutMs?: number;
|
|
392
437
|
/**
|
|
@@ -406,11 +451,42 @@ export interface ExperimentDef {
|
|
|
406
451
|
* 或给撞 provider 限额的实验单独降速。
|
|
407
452
|
*/
|
|
408
453
|
maxConcurrency?: number;
|
|
454
|
+
/**
|
|
455
|
+
* 实验级生命周期钩子对的 setup 侧:整场至多一次、宿主机侧,管「每实验一份、所有 attempt
|
|
456
|
+
* 共享」的宿主机资源(隧道、mock server、license 租约)。本实验第一个通过派发许可的
|
|
457
|
+
* attempt 触发(memoized,并发 attempt 等同一个结果;全部结果被 carry 携入时不执行)。
|
|
458
|
+
* setup 不返回值;产物写模块级变量,`teardown` 与同文件 agent / sandbox 钩子从闭包读,
|
|
459
|
+
* runner 不做值的中介。setup 抛错 → 本实验所有 attempt 记 `errored`
|
|
460
|
+
* (code `"experiment-setup-failed"`、phase `"experiment.setup"`),同批其它实验不受影响。
|
|
461
|
+
* 函数体不进 fingerprint,改了钩子逻辑用 `--force` 强制重跑。
|
|
462
|
+
* 见 docs/feature/experiments/architecture.md「实验级生命周期」。
|
|
463
|
+
*/
|
|
464
|
+
setup?: (ctx: ExperimentHookContext) => void | Promise<void>;
|
|
465
|
+
/**
|
|
466
|
+
* 实验级生命周期钩子对的 teardown 侧:本实验全部 attempt 收尾后执行(运行被中断也执行),
|
|
467
|
+
* 当且仅当 setup 时点走到过——setup 抛错不豁免(半初始化现场同样要扫尾,teardown 对可能
|
|
468
|
+
* 未赋值的闭包变量做防御),未声明 setup 不影响触发;一个 attempt 都不派发则跳过。
|
|
469
|
+
* 抛错或超 30s 清理上限只记运行级 diagnostic(`experiment-teardown-failed`),不改判定。
|
|
470
|
+
*/
|
|
471
|
+
teardown?: (ctx: ExperimentHookContext) => void | Promise<void>;
|
|
409
472
|
}
|
|
410
473
|
|
|
411
474
|
export interface DiscoveredExperiment extends ExperimentDef {
|
|
412
475
|
id: string;
|
|
413
|
-
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* 用户谓词(`ExperimentDef.evals`)能看到的唯一形状——发现并扇出后的显式白名单投影,不透传
|
|
480
|
+
* `DiscoveredEval` 原对象(不暴露 `sourcePath` / `baseDir` / `test` / hooks 等内部路径与执行字段)。
|
|
481
|
+
* `tags` 缺省为冻结空数组;`metadata` 原样引用作者声明的对象(至少浅冻结),供 `tags.includes(...)` /
|
|
482
|
+
* `environment` / `metadata.<key>` 判断(见 docs/feature/eval/library.md「EvalDescriptor」)。
|
|
483
|
+
*/
|
|
484
|
+
export interface EvalDescriptor {
|
|
485
|
+
readonly id: string;
|
|
486
|
+
readonly description?: string;
|
|
487
|
+
readonly tags: readonly string[];
|
|
488
|
+
readonly environment?: string;
|
|
489
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
414
490
|
}
|
|
415
491
|
|
|
416
492
|
export interface Config {
|
|
@@ -419,11 +495,11 @@ export interface Config {
|
|
|
419
495
|
* 可传字符串,或按 locale 提供多语言(如 `{ en: "...", "zh-CN": "..." }`),随 view 语言切换。
|
|
420
496
|
*/
|
|
421
497
|
name?: LocalizedText;
|
|
422
|
-
/**
|
|
498
|
+
/** 项目级默认 Sandbox provider(docker / vercel / e2b / custom);experiment 可覆盖。 */
|
|
423
499
|
sandbox?: SandboxOption;
|
|
424
|
-
/**
|
|
500
|
+
/** 上传进 Sandbox 的工作区根目录,省略则用项目根;评估用例的 sandbox 视图从这里起步。 */
|
|
425
501
|
workspace?: string;
|
|
426
|
-
/** 项目级默认 judge 配置(model / baseUrl / apiKeyEnv);EvalDef.judge
|
|
502
|
+
/** 项目级默认 judge 配置(model / baseUrl / apiKeyEnv);EvalDef.judge 可按评估用例覆盖。 */
|
|
427
503
|
judge?: JudgeConfig;
|
|
428
504
|
/** 项目级默认 reporter 列表(如落盘 / 上传结果);EvalDef.reporters 会与它合并。 */
|
|
429
505
|
reporters?: Reporter[];
|
|
@@ -434,11 +510,11 @@ export interface Config {
|
|
|
434
510
|
/**
|
|
435
511
|
* OTLP 接收配置,niceeval 项目内唯一入口(不读 NICEEVAL_OTLP_* 环境变量)。
|
|
436
512
|
* `port` 钉住接收端口(固定端口模式:长驻服务把 OTEL_EXPORTER_OTLP_ENDPOINT 一次性指到
|
|
437
|
-
* http://localhost:<port>/v1/traces
|
|
513
|
+
* http://localhost:<port>/v1/traces,跑多少次评估用例都不用改)。省略 = 每次运行动态分配
|
|
438
514
|
* 临时端口(经 ctx.telemetry 交给 adapter)。代价:固定端口下同机同时只能跑一个 niceeval 进程,
|
|
439
515
|
* 且该端口被别的进程占用时会报错——换一个空闲端口写回这里即可。
|
|
440
516
|
* `host` 是报给 adapter 的接收端 hostname(而非监听地址,监听地址恒为 0.0.0.0):默认
|
|
441
|
-
* "127.0.0.1";docker
|
|
517
|
+
* "127.0.0.1";docker Sandbox 型 tracing 需要 "host.docker.internal" 之类的场景,或配了隧道
|
|
442
518
|
* 的远程接入,在这里覆盖。
|
|
443
519
|
*/
|
|
444
520
|
telemetry?: { host?: string; port?: number };
|
|
@@ -496,18 +572,29 @@ export interface AgentRun {
|
|
|
496
572
|
resolvedSandboxes?: Map<string, SandboxOption>;
|
|
497
573
|
timeoutMs?: number;
|
|
498
574
|
budget?: number;
|
|
499
|
-
evalFilter: (id: string) => boolean;
|
|
500
575
|
experimentId?: string;
|
|
501
576
|
/** 实验的一句话描述(ExperimentDef.description),进结果快照的 ExperimentRunInfo。 */
|
|
502
577
|
description?: string;
|
|
578
|
+
/** 报告归类标注(ExperimentDef.labels),原样进 ExperimentRunInfo.labels;不透传 ctx / t。 */
|
|
579
|
+
labels?: Record<string, string | number>;
|
|
503
580
|
/** evals 过滤器的指纹(数组内容 / 函数体哈希),进 ExperimentRunInfo.evalFilterFingerprint。 */
|
|
504
581
|
evalFilterFingerprint?: string;
|
|
505
|
-
/**
|
|
506
|
-
|
|
582
|
+
/**
|
|
583
|
+
* 本次 invocation 解析后实际选中的 eval id 全集——CLI 在构造 AgentRun 时对候选 eval 各求值
|
|
584
|
+
* 一次算好(见 `eval-selection.ts` 的 `resolveExperimentEvals()`),下游(dry-run、sandbox 查表、
|
|
585
|
+
* fingerprint/carry、attempt 展开、hook ctx、落盘)只消费这份已解析结果,不重新调用用户谓词。
|
|
586
|
+
* 保持顺序 = discovery 稳定顺序,去重。
|
|
587
|
+
*/
|
|
588
|
+
selectedEvalIds: readonly string[];
|
|
507
589
|
strict?: boolean;
|
|
508
590
|
/** 本配置自己的并发上限(来自 ExperimentDef.maxConcurrency):调度器为它单建信号量,
|
|
509
591
|
* attempt 先过这道闸再占全局并发位;省略则只受全局并发约束。 */
|
|
510
592
|
maxConcurrency?: number;
|
|
593
|
+
/** 实验级生命周期钩子对(来自 ExperimentDef.setup / .teardown):setup 整场至多一次,
|
|
594
|
+
* 调度器 memoize 执行;teardown 在全部 attempt 收尾后执行,当且仅当 setup 时点走到过
|
|
595
|
+
* (语义见 ExperimentDef 对应字段)。 */
|
|
596
|
+
setup?: (ctx: ExperimentHookContext) => void | Promise<void>;
|
|
597
|
+
teardown?: (ctx: ExperimentHookContext) => void | Promise<void>;
|
|
511
598
|
}
|
|
512
599
|
|
|
513
600
|
export interface RunOptions {
|
|
@@ -621,6 +708,25 @@ export interface ActiveAttempt {
|
|
|
621
708
|
detail?: string;
|
|
622
709
|
}
|
|
623
710
|
|
|
711
|
+
/** 实验级钩子只有 setup 与它返回的 teardown 两员,同一实验内两者永不并发
|
|
712
|
+
* (teardown 在全部 attempt 收尾后才触发),所以运行级行按 experimentId 建 key 就够。 */
|
|
713
|
+
export type ExperimentHookName = "setup" | "teardown";
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* dashboard 当前可见的一个实验级钩子运行级行(见 docs/feature/experiments/cli.md
|
|
717
|
+
* 「实验级钩子的显示」)。与 `ActiveAttempt` 分开建模:钩子不属于任何单个 attempt、不占并发位,
|
|
718
|
+
* 也不参与 `total = reused + running + queued + completed` 的计数不变量——等待 setup 的
|
|
719
|
+
* attempt 保持 `queued`,这行就是「为什么它们还在排队」的解释。`detail` 来自实验级
|
|
720
|
+
* `ctx.progress`,后一条覆盖前一条。
|
|
721
|
+
*/
|
|
722
|
+
export interface ActiveExperimentHook {
|
|
723
|
+
experimentId: string;
|
|
724
|
+
hook: ExperimentHookName;
|
|
725
|
+
/** 钩子开始的墙钟时间(epoch ms),用于渲染运行级行的耗时。 */
|
|
726
|
+
startedAt: number;
|
|
727
|
+
detail?: string;
|
|
728
|
+
}
|
|
729
|
+
|
|
624
730
|
/**
|
|
625
731
|
* 一次失败/错误的永久通知:human 撤下 dashboard 后追加一行、agent/ci 立即追加一行,都读它。
|
|
626
732
|
* 字段全部结构化(locator / identity / verdict / phase 都是具名字段),profile renderer 不需要
|
|
@@ -703,6 +809,9 @@ export interface RunFeedbackState {
|
|
|
703
809
|
newTokenCount?: number;
|
|
704
810
|
estimatedCostUSD?: number;
|
|
705
811
|
active: ReadonlyMap<AttemptKey, ActiveAttempt>;
|
|
812
|
+
/** 在飞的实验级钩子(experimentId → 运行级行状态),由 "experiment-hook" 事件增删、
|
|
813
|
+
* "experiment:progress" 更新 detail(见 docs/feature/experiments/cli.md「实验级钩子的显示」)。 */
|
|
814
|
+
experimentHooks: ReadonlyMap<string, ActiveExperimentHook>;
|
|
706
815
|
failures: readonly FailureNotice[];
|
|
707
816
|
/** 本次实际派发后产生的去重失败数;复用失败不消耗 profile 的流式输出上限。 */
|
|
708
817
|
freshFailureCount: number;
|
|
@@ -755,6 +864,17 @@ export type AttemptLifecycleEvent =
|
|
|
755
864
|
}
|
|
756
865
|
| { type: "attempt:early-exit"; at: number; identity: AttemptRef; who: string };
|
|
757
866
|
|
|
867
|
+
/**
|
|
868
|
+
* 实验级 `ctx.progress` 的短命投影:只覆盖对应运行级行的 `detail`,不追加永久行——与
|
|
869
|
+
* `attempt:progress` 同一判断标准(新值使旧值失去意义)。对应的运行级行不存在时静默忽略。
|
|
870
|
+
*/
|
|
871
|
+
export interface ExperimentProgressEvent {
|
|
872
|
+
type: "experiment:progress";
|
|
873
|
+
at: number;
|
|
874
|
+
experimentId: string;
|
|
875
|
+
detail: string;
|
|
876
|
+
}
|
|
877
|
+
|
|
758
878
|
/**
|
|
759
879
|
* 运行级时钟 tick:唯一允许更新 `RunFeedbackState.elapsedMs` 的事件,由 coordinator 的定时器产出
|
|
760
880
|
*(见 plan 的可注入 `FeedbackIO` clock)。reducer 保持纯函数,不自己读 `Date.now()`,elapsedMs
|
|
@@ -812,6 +932,21 @@ export type DurableFeedbackEvent =
|
|
|
812
932
|
sandboxId: string;
|
|
813
933
|
enter?: string;
|
|
814
934
|
}
|
|
935
|
+
/**
|
|
936
|
+
* 实验级钩子(`ExperimentDef.setup` / 它返回的 teardown)的起止,由 runner 在钩子真正
|
|
937
|
+
* 开始/结束时各发一次(见 docs/feature/experiments/cli.md「实验级钩子的显示」)。`failed`
|
|
938
|
+
* 只标记钩子自身的结局——setup 失败的每条 attempt 仍以 "failure" 事件逐条给出。human TTY
|
|
939
|
+
* 用它维护运行级 active 行(不写 scrollback),append-only profile 起止各追加一行。
|
|
940
|
+
*/
|
|
941
|
+
| {
|
|
942
|
+
type: "experiment-hook";
|
|
943
|
+
at: number;
|
|
944
|
+
experimentId: string;
|
|
945
|
+
hook: ExperimentHookName;
|
|
946
|
+
status: "started" | "done" | "failed";
|
|
947
|
+
/** 只在 done / failed 上出现:钩子从开始到结束的耗时。 */
|
|
948
|
+
durationMs?: number;
|
|
949
|
+
}
|
|
815
950
|
| { type: "interrupted"; at: number }
|
|
816
951
|
| { type: "reporter-error"; at: number; reporter: string; required: boolean; message: string }
|
|
817
952
|
| { type: "summary"; at: number; summary: RunSummary; completion: RunCompletion }
|
|
@@ -836,4 +971,4 @@ export type DurableFeedbackEvent =
|
|
|
836
971
|
* profile renderer 只消费这里的具名字段,不解析 `ReporterEvent` 里的 i18n 文案或表格列宽
|
|
837
972
|
*(见 docs/feature/experiments/cli.md「输出流和落盘节奏」)。
|
|
838
973
|
*/
|
|
839
|
-
export type RunFeedbackEvent = AttemptLifecycleEvent | FeedbackTickEvent | DurableFeedbackEvent;
|
|
974
|
+
export type RunFeedbackEvent = AttemptLifecycleEvent | ExperimentProgressEvent | FeedbackTickEvent | DurableFeedbackEvent;
|
package/src/sandbox/docker.ts
CHANGED
|
@@ -535,12 +535,19 @@ export class DockerSandbox implements Sandbox {
|
|
|
535
535
|
/**
|
|
536
536
|
* 向容器任意路径写文件(二进制)。
|
|
537
537
|
* 打成单文件 tar → putArchive 到目标目录,与 uploadFiles 同一机制但目标路径自由。
|
|
538
|
+
*
|
|
539
|
+
* 修正属主:putArchive 以 root 解包,不 chown 的话文件在容器里保持 root 属主——非 root
|
|
540
|
+
* 沙箱用户不仅不能编辑它,后续对它做 `mv`/`rm` 这类改动它所在目录项的操作,只要目标目录带
|
|
541
|
+
* sticky bit(如 `/tmp`),也会因为「非属主不能改别人的目录项」被内核拒成
|
|
542
|
+
* `Operation not permitted`(与 uploadFiles() 对整个目标目录 chown 是同一个属主问题,
|
|
543
|
+
* 这里只需精确 chown 这一个文件;真机复现见 memory/docker-uploadfile-tmp-mv-eperm.md)。
|
|
538
544
|
*/
|
|
539
545
|
async uploadFile(destPath: string, content: Buffer): Promise<void> {
|
|
540
546
|
if (!this.container) throw new Error(t("docker.containerNotInitialized"));
|
|
541
547
|
const absPath = resolveSandboxPath(this.workdir, destPath);
|
|
542
548
|
const pack = packFilesToTar([{ name: basename(absPath), content }]);
|
|
543
549
|
await (this.container as Docker.Container).putArchive(pack, { path: dirname(absPath) });
|
|
550
|
+
await this.chownToSandboxUser(absPath);
|
|
544
551
|
}
|
|
545
552
|
|
|
546
553
|
/** 销毁容器:显式 stop + remove(创建时不带 AutoRemove,见 createContainer 的注释)。 */
|
package/src/sandbox/e2b.ts
CHANGED
|
@@ -38,19 +38,18 @@ const SESSION_TIMEOUT_MS = 1_800_000;
|
|
|
38
38
|
*/
|
|
39
39
|
export async function reconcileProvision(token: string): Promise<void> {
|
|
40
40
|
const apiKey = process.env.E2B_API_KEY;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (!(e instanceof NotFoundError)) throw e;
|
|
41
|
+
// Sandbox.list() 是同步方法,返回分页器(SandboxPaginator),不是 Promise<数组>——用
|
|
42
|
+
// hasNext/nextItems() 翻页,不能直接 for...of。metadata 过滤走服务端 query,一次 token
|
|
43
|
+
// 命中的实例数极少,通常一页打完。
|
|
44
|
+
const paginator = E2BSdkSandbox.list({ apiKey, query: { metadata: { "niceeval-provision-token": token } } });
|
|
45
|
+
while (paginator.hasNext) {
|
|
46
|
+
const sandboxes = await paginator.nextItems();
|
|
47
|
+
for (const info of sandboxes) {
|
|
48
|
+
try {
|
|
49
|
+
await E2BSdkSandbox.kill(info.sandboxId, { apiKey });
|
|
50
|
+
} catch (e) {
|
|
51
|
+
if (!(e instanceof NotFoundError)) throw e;
|
|
52
|
+
}
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
55
|
}
|
package/src/sandbox/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// sandbox 域类型:Sandbox 接口、provider spec(可辨识联合)、命令与文件 IO 的形状。
|
|
2
2
|
// 「在哪里跑、如何隔离」的全部契约在这里;provider 实现见本目录各文件,分发见 resolve.ts。
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { ScopedFeedback } from "../shared/types.ts";
|
|
5
5
|
|
|
6
6
|
export interface CommandResult {
|
|
7
7
|
stdout: string;
|
|
@@ -76,15 +76,16 @@ export type SandboxRuntime = "node20" | "node24";
|
|
|
76
76
|
* **执行顺序**:沙箱就绪 → `sandbox.setup` 钩子 → workspace 上传 / git 基线 / `eval.setup` →
|
|
77
77
|
* `agent.setup` → `agent.tracing.configure` → 逐轮 `send`。`sandbox.setup` 特意排在 git
|
|
78
78
|
* 基线之前——它的改动会被提交进基线,不会被误算进 agent 产出的 diff。收尾按 LIFO:
|
|
79
|
-
*
|
|
79
|
+
* `agent.teardown` 先跑,`sandbox.teardown` 钩子最后跑(沙箱销毁前)。
|
|
80
80
|
*
|
|
81
81
|
* **多钩子**:`.setup(a).setup(b)` 按追加顺序依次执行(a 先 b 后);`.teardown(x).teardown(y)`
|
|
82
82
|
* 按追加的**逆序**执行(y 先 x 后)。每次调用都返回一个新 spec(不改变原对象),可继续链式。
|
|
83
|
+
* `setup` 链中途抛错时后续 `setup` 不再执行,`teardown` 链仍完整走完。
|
|
83
84
|
*
|
|
84
85
|
* **失败语义**:`setup` 钩子抛错按执行错误计——与 `eval.setup` / `agent.setup` 抛错走同一条
|
|
85
|
-
* 路径,不新增错误分类;但不阻断该 attempt 已进入的收尾(
|
|
86
|
-
*
|
|
87
|
-
*
|
|
86
|
+
* 路径,不新增错误分类;但不阻断该 attempt 已进入的收尾(已挂载的 `teardown` 钩子仍会在
|
|
87
|
+
* finally 里跑)。`teardown` 钩子报错只作诊断(吞掉 / 记 log),不改变已产出的结果——与
|
|
88
|
+
* `agent.teardown` 现状一致。
|
|
88
89
|
*/
|
|
89
90
|
export interface SandboxHooks<Self> {
|
|
90
91
|
/** 已挂载的 setup 钩子,按追加顺序保存(内部读取,一般用不到)。 */
|
|
@@ -109,11 +110,12 @@ export interface SandboxHookContext extends ScopedFeedback {
|
|
|
109
110
|
readonly signal: AbortSignal;
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
/** 沙箱级生命周期钩子(`.setup()` / `.teardown()` 链式挂载);`setup`
|
|
113
|
+
/** 沙箱级生命周期钩子(`.setup()` / `.teardown()` 链式挂载);`setup` 不返回值——要把 `setup`
|
|
114
|
+
* 创建的句柄传给 `teardown`,以 `sandbox` 实例为键存取(见 {@link SandboxHooks})。 */
|
|
113
115
|
export type SandboxHook = (
|
|
114
116
|
sandbox: Sandbox,
|
|
115
117
|
ctx: SandboxHookContext,
|
|
116
|
-
) => void |
|
|
118
|
+
) => void | Promise<void>;
|
|
117
119
|
|
|
118
120
|
/**
|
|
119
121
|
* Sandbox 的「数据结构」定义 —— 与 agent 一样可带参数(见 docs/feature/sandbox/library.md)。
|
|
@@ -170,12 +172,12 @@ export type SandboxSpec = DockerSandboxSpec | VercelSandboxSpec | E2BSandboxSpec
|
|
|
170
172
|
export type SandboxOption = SandboxSpec;
|
|
171
173
|
|
|
172
174
|
export interface CommandOptions {
|
|
173
|
-
/** 追加/覆盖本命令的环境变量(
|
|
175
|
+
/** 追加/覆盖本命令的环境变量(与 Sandbox 默认环境叠加,不清空默认值;各 provider 会保留自己固定的 `PATH` 等变量,不保证能被这里覆盖)。 */
|
|
174
176
|
env?: Record<string, string>;
|
|
175
177
|
/** 本命令的工作目录;省略时落到 `Sandbox.workdir`。相对路径按 workdir 解析,绝对路径原样使用。 */
|
|
176
178
|
cwd?: string;
|
|
177
179
|
/**
|
|
178
|
-
*
|
|
180
|
+
* 把本命令的输出也送进 Sandbox 的「原生日志流」(于是 `docker logs` / Docker UI 的 Logs
|
|
179
181
|
* 标签页能实时看到它)。给 agent 命令(codex exec / bub run / claude)开它,就能在容器
|
|
180
182
|
* 日志里看到 agent 的【原始输出】。provider 各自实现(docker:tee 到 PID1 tail 的文件;
|
|
181
183
|
* 不支持的 provider 忽略)—— 日志怎么浮现是 provider 的事,adapter 只声明意图。
|
|
@@ -190,7 +192,7 @@ export interface CommandOptions {
|
|
|
190
192
|
/** `onStdout` 的 stderr 对应物;完整 stderr 仍保留在 `CommandResult`。 */
|
|
191
193
|
onStderr?: (chunk: string) => void | Promise<void>;
|
|
192
194
|
/**
|
|
193
|
-
* 以 root 跑本命令。默认 `false` ——
|
|
195
|
+
* 以 root 跑本命令。默认 `false` —— 命令以 Sandbox 的标准**非 root** 用户跑(agent 的自然环境)。
|
|
194
196
|
* 给 setup 阶段装系统依赖用(`apt-get install …`、`pip install --break-system-packages …`)。
|
|
195
197
|
*
|
|
196
198
|
* 语义跨 provider 一致:"本命令以 root 跑,否则以标准非 root 用户跑"。各 provider 映射到自己的原生机制
|
|
@@ -202,7 +204,7 @@ export interface CommandOptions {
|
|
|
202
204
|
}
|
|
203
205
|
|
|
204
206
|
export interface Sandbox {
|
|
205
|
-
/**
|
|
207
|
+
/** Sandbox 内项目/工作区根目录的绝对路径(agent 命令的默认 cwd,也是 git baseline 提交的位置)。各方法的相对路径都以此为基准解析,省略 `cwd`/`targetDir` 时也落到这里。 */
|
|
206
208
|
readonly workdir: string;
|
|
207
209
|
/**
|
|
208
210
|
* 执行单个命令,`args` 作为独立 argv 传递、不经 shell 解释(无 `&&`、管道、通配符展开)。
|
|
@@ -214,29 +216,29 @@ export interface Sandbox {
|
|
|
214
216
|
* 需要拼多条命令或做条件判断时用它。
|
|
215
217
|
*/
|
|
216
218
|
runShell(script: string, opts?: CommandOptions): Promise<CommandResult>;
|
|
217
|
-
/**
|
|
219
|
+
/** 读取 Sandbox 内文件的文本内容(UTF-8)。文件不存在时抛错,不返回空字符串——需要容错请自行 `.catch()`。 */
|
|
218
220
|
readFile(path: string): Promise<string>;
|
|
219
|
-
/**
|
|
221
|
+
/** 检查 Sandbox 内路径是否存在。跨 provider 语义不完全一致:仅保证对普通文件可靠,对目录路径的行为不同 provider 不保证一致。 */
|
|
220
222
|
fileExists(path: string): Promise<boolean>;
|
|
221
223
|
/**
|
|
222
224
|
* 一次 shell 往返读全部源码文件(按扩展名收、按目录/文件名忽略)。
|
|
223
|
-
*
|
|
225
|
+
* 取代每个评估用例目录里手写的 find + 逐文件 readFile。
|
|
224
226
|
*/
|
|
225
227
|
readSourceFiles(opts?: ReadSourceFilesOptions): Promise<SourceFiles>;
|
|
226
228
|
/** 写入若干文本文件(内容已在内存里的字符串);是 `uploadFiles` 的文本特化,省略 `targetDir` 落到 workdir。 */
|
|
227
229
|
writeFiles(files: Record<string, string>, targetDir?: string): Promise<void>;
|
|
228
230
|
/** 批量写入若干文件,内容可以是文本或二进制 Buffer;省略 `targetDir` 落到 workdir。 */
|
|
229
231
|
uploadFiles(files: SandboxFile[], targetDir?: string): Promise<void>;
|
|
230
|
-
/**
|
|
232
|
+
/** 把本地磁盘上的一个目录整体上传进 Sandbox(递归读取本地文件后按 `uploadFiles` 写入);`opts.ignore` 是排除规则,省略 `targetDir` 落到 workdir。 */
|
|
231
233
|
uploadDirectory(localDir: string, targetDir?: string, opts?: { ignore?: string[] }): Promise<void>;
|
|
232
|
-
/**
|
|
234
|
+
/** 销毁 Sandbox 占用的计算资源(容器/microVM)。调用后 Sandbox 不可再用;是否可安全重复调用因 provider 而异,不要依赖这一点。 */
|
|
233
235
|
stop(): Promise<void>;
|
|
234
|
-
/**
|
|
236
|
+
/** 本 Sandbox 的稳定标识(各 provider 原生 ID,如 Docker 容器 ID 前缀);用于跨调用关联同一 Sandbox 的会话状态,也用于日志展示。 */
|
|
235
237
|
readonly sandboxId: string;
|
|
236
238
|
/**
|
|
237
239
|
* 本地 OTLP 接收器的目标 host。
|
|
238
|
-
* - `string
|
|
239
|
-
* - `null
|
|
240
|
+
* - `string`:Sandbox 内可通过该 hostname 回连宿主 OTLP 端口(如 docker 的 `host.docker.internal`)。
|
|
241
|
+
* - `null`:Sandbox 运行在远程云端(如 e2b/vercel),无法访问宿主本地端口 → 跳过 tracing。
|
|
240
242
|
* 可通过环境变量 `NICEEVAL_OTLP_HOST` 强制覆盖(如配置 tunnel 时)。
|
|
241
243
|
*/
|
|
242
244
|
readonly otlpHost: string | null;
|
|
@@ -248,13 +250,13 @@ export interface Sandbox {
|
|
|
248
250
|
appendLog?(line: string): Promise<void>;
|
|
249
251
|
|
|
250
252
|
/**
|
|
251
|
-
*
|
|
253
|
+
* 从 Sandbox 内任意路径读取文件,返回二进制 Buffer。
|
|
252
254
|
* 对应各 provider:Docker getArchive / Vercel readFileToBuffer / e2b files.read(bytes) / …
|
|
253
255
|
*/
|
|
254
256
|
downloadFile(path: string): Promise<Buffer>;
|
|
255
257
|
|
|
256
258
|
/**
|
|
257
|
-
*
|
|
259
|
+
* 向 Sandbox 内任意路径写入文件(二进制)。
|
|
258
260
|
* 对应各 provider:Docker putArchive / Vercel fs.writeFile(Buffer) / e2b files.write / …
|
|
259
261
|
*/
|
|
260
262
|
uploadFile(path: string, content: Buffer): Promise<void>;
|
|
@@ -35,7 +35,8 @@ describe("primaryAssertionSummary", () => {
|
|
|
35
35
|
});
|
|
36
36
|
expect(assertionSummaryLines(summary!)).toEqual([
|
|
37
37
|
"gate: Issue 15193: selected proposal matches the accepted proposal",
|
|
38
|
-
"equals(4) · expected 4 · received 3
|
|
38
|
+
"equals(4) · expected 4 · received 3",
|
|
39
|
+
"+1 more failures",
|
|
39
40
|
]);
|
|
40
41
|
expect(compactAssertionSummary(summary!)).toBe(
|
|
41
42
|
"gate: Issue 15193: selected proposal matches the accepted proposal · equals(4) · expected 4 · received 3 · +1 more failures",
|
|
@@ -78,8 +79,33 @@ describe("primaryAssertionSummary", () => {
|
|
|
78
79
|
expect(summary.received!.length).toBeLessThanOrEqual(240);
|
|
79
80
|
expect(summary.received).toMatch(/…$/);
|
|
80
81
|
const lines = assertionSummaryLines(summary);
|
|
81
|
-
expect(lines).toHaveLength(2);
|
|
82
82
|
expect(lines.every((line) => !line.includes("\n"))).toBe(true);
|
|
83
|
+
// matcher · expected 放不下大值 received 时各自另起一行
|
|
84
|
+
expect(lines).toEqual([
|
|
85
|
+
"gate: includes(/updateTag/)",
|
|
86
|
+
expect.stringContaining("expected matches /updateTag/"),
|
|
87
|
+
expect.stringMatching(/^received: .*…$/),
|
|
88
|
+
]);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("received 大值单独截断一行时,+N more failures 仍是独立尾行、不与被截断的值粘连", () => {
|
|
92
|
+
const assertions: AssertionResult[] = [
|
|
93
|
+
{
|
|
94
|
+
name: "includes(/updateTag/)",
|
|
95
|
+
severity: "gate",
|
|
96
|
+
outcome: "failed",
|
|
97
|
+
score: 0,
|
|
98
|
+
expected: "matches /updateTag/",
|
|
99
|
+
received: `// app/actions/posts.ts\n'use server';\n${"const source = 1;\n".repeat(80)}`,
|
|
100
|
+
},
|
|
101
|
+
{ name: "matches(schema)", severity: "gate", outcome: "failed", score: 0 },
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const summary = primaryAssertionSummary(assertions, "failed")!;
|
|
105
|
+
const lines = assertionSummaryLines(summary);
|
|
106
|
+
expect(lines.at(-1)).toBe("+1 more failures");
|
|
107
|
+
const receivedLine = lines.find((line) => line.startsWith("received:"))!;
|
|
108
|
+
expect(receivedLine).not.toContain("more failures");
|
|
83
109
|
});
|
|
84
110
|
});
|
|
85
111
|
|
package/src/scoring/display.ts
CHANGED
|
@@ -9,6 +9,13 @@ import type { AssertionResult, PrimaryAssertionSummary, Verdict } from "./types.
|
|
|
9
9
|
*/
|
|
10
10
|
const SUMMARY_TEXT_MAX_CHARS = 240;
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Human/Agent 永久行的单行事实预算,与 SUMMARY_TEXT_MAX_CHARS(单值上限)分开计:一条
|
|
14
|
+
* `matcher · expected · received` 拼起来很容易超过一屏宽,这里给的是「一行」的上限,不依赖
|
|
15
|
+
* 终端 columns——agent profile 的 handoff 不是 TTY,不能按运行时宽度变化。
|
|
16
|
+
*/
|
|
17
|
+
const DETAIL_LINE_MAX_CHARS = 100;
|
|
18
|
+
|
|
12
19
|
/** 摘要面的单值收口:折单行 + 240 字符上限。任何把断言事实放进「行」里的面共用这一条。 */
|
|
13
20
|
export function summaryText(value: string): string {
|
|
14
21
|
const singleLine = value.replace(/\s+/g, " ").trim();
|
|
@@ -80,11 +87,37 @@ export function assertionSummaryDetail(summary: PrimaryAssertionSummary): string
|
|
|
80
87
|
return parts.length > 0 ? parts.join(" · ") : undefined;
|
|
81
88
|
}
|
|
82
89
|
|
|
83
|
-
/**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Human/Agent 永久行的排版:标题独占一行;`matcher · expected`(含 score/threshold/reason)
|
|
92
|
+
* 独占下一行;`received` 能跟这行拼在一起仍在 DETAIL_LINE_MAX_CHARS 内就合并,放不下就单独
|
|
93
|
+
* 再起一行并硬截断。`+N more failures` 永远是独立尾行,不参与截断,也不拼进被截断的值——
|
|
94
|
+
* 截断处的 `…` 后面只会是值本身,不会被人误读成计数的一部分。
|
|
95
|
+
*/
|
|
96
|
+
export function assertionSummaryLines(summary: PrimaryAssertionSummary): string[] {
|
|
97
|
+
const lines: string[] = [`${summary.severity}: ${summary.assertion}`];
|
|
98
|
+
|
|
99
|
+
const factParts: string[] = [];
|
|
100
|
+
if (summary.matcher !== undefined) factParts.push(summary.matcher);
|
|
101
|
+
if (summary.expected !== undefined) factParts.push(`expected ${summary.expected}`);
|
|
102
|
+
if (summary.score !== undefined) factParts.push(`score ${summary.score}`);
|
|
103
|
+
if (summary.threshold !== undefined) factParts.push(`threshold ${summary.threshold}`);
|
|
104
|
+
if (summary.reason !== undefined) factParts.push(`reason ${summary.reason}`);
|
|
105
|
+
const facts = factParts.length > 0 ? factParts.join(" · ") : undefined;
|
|
106
|
+
|
|
107
|
+
if (summary.received !== undefined) {
|
|
108
|
+
const combined = facts !== undefined ? `${facts} · received ${summary.received}` : `received ${summary.received}`;
|
|
109
|
+
if (combined.length <= DETAIL_LINE_MAX_CHARS) {
|
|
110
|
+
lines.push(combined);
|
|
111
|
+
} else {
|
|
112
|
+
if (facts !== undefined) lines.push(facts);
|
|
113
|
+
lines.push(shrinkTo(`received: ${summary.received}`, DETAIL_LINE_MAX_CHARS));
|
|
114
|
+
}
|
|
115
|
+
} else if (facts !== undefined) {
|
|
116
|
+
lines.push(facts);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (summary.additionalFailures > 0) lines.push(`+${summary.additionalFailures} more failures`);
|
|
120
|
+
return lines;
|
|
88
121
|
}
|
|
89
122
|
|
|
90
123
|
/** 比较列表的单元格投影;无 group 时不重复 `gate:` 前缀。 */
|
package/src/scoring/types.ts
CHANGED
|
@@ -22,11 +22,11 @@ export interface ValueAssertion {
|
|
|
22
22
|
/** 期望条件的有界文本描述(如 `contains "Brooklyn"`),失败时进 AssertionResult.expected。 */
|
|
23
23
|
readonly expected?: string;
|
|
24
24
|
score(value: unknown): number | Promise<number>;
|
|
25
|
-
/** 转成硬门槛断言:未达阈值(省略 threshold 则按 score > 0 判定)
|
|
25
|
+
/** 转成硬门槛断言:未达阈值(省略 threshold 则按 score > 0 判定)整条评估用例判为 failed。返回新实例,不改原对象。 */
|
|
26
26
|
gate(threshold?: number): ValueAssertion;
|
|
27
27
|
/**
|
|
28
|
-
* 转成软阈值断言:未达 threshold 时该条记为 failed
|
|
29
|
-
* `--strict`
|
|
28
|
+
* 转成软阈值断言:未达 threshold 时该条记为 failed,但默认不拖累整条评估用例的 verdict;
|
|
29
|
+
* `--strict` 运行下,软阈值失败也会把整条评估用例的 verdict 计为 failed。返回新实例,不改原对象。
|
|
30
30
|
*/
|
|
31
31
|
atLeast(threshold: number): ValueAssertion;
|
|
32
32
|
/**
|