veryfront 0.1.1127 → 0.1.1132
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/esm/cli/commands/eval/command.d.ts +2 -70
- package/esm/cli/commands/eval/command.d.ts.map +1 -1
- package/esm/cli/commands/eval/command.js +207 -550
- package/esm/cli/templates/manifest.d.ts +1 -0
- package/esm/cli/templates/manifest.js +3 -2
- package/esm/deno.js +1 -1
- package/esm/src/agent/hosted/chat-execution-runtime.d.ts.map +1 -1
- package/esm/src/agent/hosted/chat-execution-runtime.js +16 -33
- package/esm/src/agent/hosted/child-fork-tool-sources.d.ts.map +1 -1
- package/esm/src/agent/hosted/child-fork-tool-sources.js +6 -38
- package/esm/src/agent/hosted/hosted-chat-finalization.d.ts +30 -0
- package/esm/src/agent/hosted/hosted-chat-finalization.d.ts.map +1 -0
- package/esm/src/agent/hosted/hosted-chat-finalization.js +249 -0
- package/esm/src/agent/hosted/project-remote-tool-source.d.ts.map +1 -1
- package/esm/src/agent/hosted/project-remote-tool-source.js +4 -23
- package/esm/src/agent/mcp-tool-policy.d.ts +19 -0
- package/esm/src/agent/mcp-tool-policy.d.ts.map +1 -0
- package/esm/src/agent/mcp-tool-policy.js +66 -0
- package/esm/src/agent/runtime/mcp-server-tool-sources.d.ts.map +1 -1
- package/esm/src/agent/runtime/mcp-server-tool-sources.js +8 -44
- package/esm/src/discovery/import-rewriter.d.ts.map +1 -1
- package/esm/src/discovery/import-rewriter.js +7 -90
- package/esm/src/eval/run-report.d.ts +189 -0
- package/esm/src/eval/run-report.d.ts.map +1 -0
- package/esm/src/eval/run-report.js +603 -0
- package/esm/src/html/hydration-script-builder/dev-client-renderer.js +1 -1
- package/esm/src/html/hydration-script-builder/prod-scripts.js +1 -1
- package/esm/src/html/hydration-script-builder/templates/router.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/templates/router.js +35 -11
- package/esm/src/html/utils.d.ts.map +1 -1
- package/esm/src/html/utils.js +19 -45
- package/esm/src/index.client.d.ts +6 -21
- package/esm/src/index.client.d.ts.map +1 -1
- package/esm/src/index.client.js +6 -21
- package/esm/src/modules/server/ssr-import-rewriter.d.ts +2 -26
- package/esm/src/modules/server/ssr-import-rewriter.d.ts.map +1 -1
- package/esm/src/modules/server/ssr-import-rewriter.js +1 -206
- package/esm/src/react/runtime/core.d.ts +22 -0
- package/esm/src/react/runtime/core.d.ts.map +1 -1
- package/esm/src/react/runtime/core.js +1 -1
- package/esm/src/rendering/orchestrator/module-collection.d.ts +8 -0
- package/esm/src/rendering/orchestrator/module-collection.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-collection.js +10 -0
- package/esm/src/rendering/orchestrator/pipeline.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/pipeline.js +2 -2
- package/esm/src/routing/api/context-builder.d.ts +7 -0
- package/esm/src/routing/api/context-builder.d.ts.map +1 -1
- package/esm/src/routing/api/context-builder.js +20 -2
- package/esm/src/routing/api/module-loader/external-import-rewriter.d.ts +2 -7
- package/esm/src/routing/api/module-loader/external-import-rewriter.d.ts.map +1 -1
- package/esm/src/routing/api/module-loader/external-import-rewriter.js +10 -209
- package/esm/src/server/dev-server/file-watch-setup.d.ts.map +1 -1
- package/esm/src/server/dev-server/file-watch-setup.js +11 -1
- package/esm/src/server/dev-server/middleware.d.ts.map +1 -1
- package/esm/src/server/dev-server/middleware.js +45 -11
- package/esm/src/server/handlers/dev/files/esbuild-plugins.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/files/esbuild-plugins.js +22 -0
- package/esm/src/server/handlers/request/module/page-data-endpoint-handler.js +24 -1
- package/esm/src/server/handlers/response/not-found.d.ts +0 -1
- package/esm/src/server/handlers/response/not-found.d.ts.map +1 -1
- package/esm/src/server/handlers/response/not-found.js +9 -110
- package/esm/src/server/runtime-handler/index.d.ts.map +1 -1
- package/esm/src/server/runtime-handler/index.js +66 -145
- package/esm/src/server/runtime-handler/project-runtime-context.d.ts +118 -0
- package/esm/src/server/runtime-handler/project-runtime-context.d.ts.map +1 -0
- package/esm/src/server/runtime-handler/project-runtime-context.js +181 -0
- package/esm/src/server/services/rsc/orchestrators/handler.d.ts +3 -1
- package/esm/src/server/services/rsc/orchestrators/handler.d.ts.map +1 -1
- package/esm/src/server/services/rsc/orchestrators/handler.js +13 -8
- package/esm/src/server/services/rsc/orchestrators/render-handler.d.ts +1 -1
- package/esm/src/server/services/rsc/orchestrators/render-handler.d.ts.map +1 -1
- package/esm/src/server/services/rsc/orchestrators/render-handler.js +2 -2
- package/esm/src/transforms/esm/http-cache.d.ts.map +1 -1
- package/esm/src/transforms/esm/http-cache.js +132 -46
- package/esm/src/transforms/esm/import-attributes.d.ts.map +1 -1
- package/esm/src/transforms/esm/import-attributes.js +2 -9
- package/esm/src/transforms/esm/in-flight-manager.d.ts +3 -2
- package/esm/src/transforms/esm/in-flight-manager.d.ts.map +1 -1
- package/esm/src/transforms/esm/in-flight-manager.js +6 -5
- package/esm/src/transforms/import-rewriter/core.d.ts +8 -0
- package/esm/src/transforms/import-rewriter/core.d.ts.map +1 -0
- package/esm/src/transforms/import-rewriter/core.js +27 -0
- package/esm/src/transforms/import-rewriter/import-edit.d.ts +57 -0
- package/esm/src/transforms/import-rewriter/import-edit.d.ts.map +1 -0
- package/esm/src/transforms/import-rewriter/import-edit.js +151 -0
- package/esm/src/transforms/import-rewriter/package-resolution.d.ts +12 -0
- package/esm/src/transforms/import-rewriter/package-resolution.d.ts.map +1 -0
- package/esm/src/transforms/import-rewriter/package-resolution.js +79 -0
- package/esm/src/transforms/import-rewriter/parse-cache.d.ts +4 -42
- package/esm/src/transforms/import-rewriter/parse-cache.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/parse-cache.js +3 -134
- package/esm/src/transforms/import-rewriter/route-adapter.d.ts +24 -0
- package/esm/src/transforms/import-rewriter/route-adapter.d.ts.map +1 -0
- package/esm/src/transforms/import-rewriter/route-adapter.js +235 -0
- package/esm/src/transforms/import-rewriter/ssr-adapter.d.ts +27 -0
- package/esm/src/transforms/import-rewriter/ssr-adapter.d.ts.map +1 -0
- package/esm/src/transforms/import-rewriter/ssr-adapter.js +206 -0
- package/esm/src/transforms/import-rewriter/strategies/bare-strategy.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/strategies/bare-strategy.js +16 -2
- package/esm/src/transforms/import-rewriter/unified-rewriter.d.ts +0 -4
- package/esm/src/transforms/import-rewriter/unified-rewriter.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/unified-rewriter.js +2 -39
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/esm/src/workflow/executor/workflow-executor.d.ts +0 -20
- package/esm/src/workflow/executor/workflow-executor.d.ts.map +1 -1
- package/esm/src/workflow/executor/workflow-executor.js +41 -320
- package/esm/src/workflow/runtime/approval-manager.d.ts.map +1 -1
- package/esm/src/workflow/runtime/approval-manager.js +20 -61
- package/esm/src/workflow/runtime/workflow-run-control.d.ts +95 -0
- package/esm/src/workflow/runtime/workflow-run-control.d.ts.map +1 -0
- package/esm/src/workflow/runtime/workflow-run-control.js +529 -0
- package/esm/src/workflow/worker/run-manager.d.ts.map +1 -1
- package/esm/src/workflow/worker/run-manager.js +18 -92
- package/esm/src/workflow/worker/shared.d.ts +1 -1
- package/esm/src/workflow/worker/shared.d.ts.map +1 -1
- package/esm/src/workflow/worker/shared.js +17 -15
- package/package.json +5 -5
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
* Eval command - Discover and run eval definitions from the evals/ directory.
|
|
3
3
|
*/
|
|
4
4
|
import * as dntShim from "../../../_dnt.shims.js";
|
|
5
|
-
import { dirname, isAbsolute,
|
|
5
|
+
import { dirname, isAbsolute, relative, resolve } from "../../../deps/jsr.io/@std/path/1.1.4/mod.js";
|
|
6
6
|
import { isErroredToolExecutionResult, } from "../../../src/tool/index.js";
|
|
7
7
|
import { orchestrateExtensions } from "../../../src/extensions/index.js";
|
|
8
8
|
import { createEvalReportExporterRegistry, EvalReportExporterRegistryName, } from "../../../src/extensions/eval/index.js";
|
|
9
9
|
import { createLLMProviderRegistry, LLMProviderRegistryName } from "../../../src/extensions/llm/index.js";
|
|
10
|
-
import {
|
|
10
|
+
import { exportEvalReport, resolveEvalRunProvenance, runEval } from "../../../src/eval/index.js";
|
|
11
11
|
import { getCurrentVeryfrontCloudContext, getVeryfrontCloudBootstrap, runWithVeryfrontCloudContextAsync, } from "../../../src/provider/index.js";
|
|
12
12
|
import { applyRuntimeAuthContext } from "../../shared/runtime-auth.js";
|
|
13
13
|
import { cliLogger, exitProcess, VERSION } from "../../utils/index.js";
|
|
14
14
|
import { discoverProjectAgentRuntime, runWithProjectAgentRuntime, } from "../../../src/agent/project/agent-runtime.js";
|
|
15
|
+
import { runEvalReport } from "../../../src/eval/run-report.js";
|
|
15
16
|
import { createErrorEnvelope, createSuccessEnvelope, isJsonMode, outputJson, } from "../../shared/json-output.js";
|
|
16
17
|
import { withProjectSourceContext } from "../../shared/project-source-context.js";
|
|
17
18
|
import { createEvalCliBuiltinExtensions } from "../../../src/extensions/builtin-extensions.js";
|
|
@@ -47,74 +48,14 @@ const MODEL_COMPARISON_METRICS = [
|
|
|
47
48
|
];
|
|
48
49
|
const MODEL_COMPARISON_METRIC_SET = new Set(MODEL_COMPARISON_METRICS);
|
|
49
50
|
const MODEL_COMPARISON_OBJECTIVE_DIRECTIONS = new Set(["minimize", "maximize"]);
|
|
50
|
-
function xmlEscape(value) {
|
|
51
|
-
return value
|
|
52
|
-
.replaceAll("&", "&")
|
|
53
|
-
.replaceAll("<", "<")
|
|
54
|
-
.replaceAll(">", ">")
|
|
55
|
-
.replaceAll('"', """)
|
|
56
|
-
.replaceAll("'", "'");
|
|
57
|
-
}
|
|
58
51
|
function stripFileProtocol(path) {
|
|
59
52
|
if (!path.startsWith("file://"))
|
|
60
53
|
return path;
|
|
61
54
|
return decodeURIComponent(new URL(path).pathname);
|
|
62
55
|
}
|
|
63
|
-
function createEvalReportDirTimestamp(runId) {
|
|
64
|
-
return runId.startsWith("evalrun_") ? runId.slice("evalrun_".length) : runId;
|
|
65
|
-
}
|
|
66
|
-
function sanitizeEvalReportDirLabel(label) {
|
|
67
|
-
const normalized = label.startsWith("eval:") ? label.slice("eval:".length) : label;
|
|
68
|
-
return normalized.trim().replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^[-._]+|[-._]+$/g, "");
|
|
69
|
-
}
|
|
70
|
-
export function createDefaultEvalReportDir(runId, label) {
|
|
71
|
-
const timestamp = createEvalReportDirTimestamp(runId);
|
|
72
|
-
const suffix = label ? sanitizeEvalReportDirLabel(label) : "";
|
|
73
|
-
return join(".veryfront", "evals", suffix ? `${timestamp}-${suffix}` : timestamp);
|
|
74
|
-
}
|
|
75
|
-
export function createEvalArtifactPaths(reportDir) {
|
|
76
|
-
return {
|
|
77
|
-
directory: reportDir,
|
|
78
|
-
summary: join(reportDir, "summary.json"),
|
|
79
|
-
results: join(reportDir, "results.jsonl"),
|
|
80
|
-
reportMarkdown: join(reportDir, "report.md"),
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
function createEvalSuiteArtifactPaths(reportDir) {
|
|
84
|
-
return {
|
|
85
|
-
directory: reportDir,
|
|
86
|
-
summary: join(reportDir, "summary.json"),
|
|
87
|
-
results: join(reportDir, "results.jsonl"),
|
|
88
|
-
reportMarkdown: join(reportDir, "report.md"),
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
56
|
function sortEvals(evals) {
|
|
92
57
|
return [...evals].sort((left, right) => left.id.localeCompare(right.id) || left.filePath.localeCompare(right.filePath));
|
|
93
58
|
}
|
|
94
|
-
function createEvalSuiteChildDirectory(suiteDirectory, index, evalId) {
|
|
95
|
-
return join(suiteDirectory, `${String(index + 1).padStart(3, "0")}-${sanitizeEvalReportDirLabel(evalId)}`);
|
|
96
|
-
}
|
|
97
|
-
function sanitizeModelIdForPath(model) {
|
|
98
|
-
return model.trim().replace(/[^A-Za-z0-9._-]+/g, "__").replace(/^_+|_+$/g, "") || "model";
|
|
99
|
-
}
|
|
100
|
-
export function createEvalModelArtifactPaths(reportDir, model) {
|
|
101
|
-
const directory = join(reportDir, "models", sanitizeModelIdForPath(model));
|
|
102
|
-
return {
|
|
103
|
-
directory,
|
|
104
|
-
summary: join(directory, "summary.json"),
|
|
105
|
-
results: join(directory, "results.jsonl"),
|
|
106
|
-
reportMarkdown: join(directory, "report.md"),
|
|
107
|
-
junit: join(directory, "junit.xml"),
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
function createEvalModelComparisonArtifactPaths(reportDir, models) {
|
|
111
|
-
return {
|
|
112
|
-
directory: reportDir,
|
|
113
|
-
comparisonJson: join(reportDir, "comparison.json"),
|
|
114
|
-
comparisonMarkdown: join(reportDir, "comparison.md"),
|
|
115
|
-
models: Object.fromEntries(models.map((model) => [model, createEvalModelArtifactPaths(reportDir, model)])),
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
59
|
function displaySourcePath(filePath, projectDir) {
|
|
119
60
|
const normalized = stripFileProtocol(filePath);
|
|
120
61
|
if (normalized.startsWith(projectDir)) {
|
|
@@ -122,26 +63,6 @@ function displaySourcePath(filePath, projectDir) {
|
|
|
122
63
|
}
|
|
123
64
|
return normalized;
|
|
124
65
|
}
|
|
125
|
-
function blockingResults(record) {
|
|
126
|
-
return [...(record.metrics ?? []), ...(record.checks ?? [])].filter((result) => !result.skipped && result.pass === false &&
|
|
127
|
-
(result.severity === "gate" || result.severity === "budget"));
|
|
128
|
-
}
|
|
129
|
-
function skippedResults(record) {
|
|
130
|
-
return [...(record.metrics ?? []), ...(record.checks ?? [])].filter((result) => result.skipped);
|
|
131
|
-
}
|
|
132
|
-
function testcaseName(record) {
|
|
133
|
-
return `${record.exampleId}#${record.repetition}`;
|
|
134
|
-
}
|
|
135
|
-
function failureMessage(result) {
|
|
136
|
-
return `${result.name} failed`;
|
|
137
|
-
}
|
|
138
|
-
function failureBody(result) {
|
|
139
|
-
if (result.explanation)
|
|
140
|
-
return result.explanation;
|
|
141
|
-
if (result.evidence)
|
|
142
|
-
return JSON.stringify(result.evidence);
|
|
143
|
-
return failureMessage(result);
|
|
144
|
-
}
|
|
145
66
|
export function normalizeEvalCliId(id) {
|
|
146
67
|
return id.startsWith("eval:") ? id : `eval:${id}`;
|
|
147
68
|
}
|
|
@@ -168,35 +89,6 @@ export function normalizeEvalInputForAgent(input) {
|
|
|
168
89
|
}
|
|
169
90
|
return JSON.stringify(input);
|
|
170
91
|
}
|
|
171
|
-
export function summarizeReportForCli(report) {
|
|
172
|
-
return {
|
|
173
|
-
runId: report.runId,
|
|
174
|
-
evalId: report.definitionId,
|
|
175
|
-
target: report.target,
|
|
176
|
-
records: report.summary.records,
|
|
177
|
-
passed: report.summary.passed,
|
|
178
|
-
failed: report.summary.failed,
|
|
179
|
-
passRate: report.summary.passRate,
|
|
180
|
-
metrics: report.summary.metrics,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
export function createSummaryArtifact(report, baseline) {
|
|
184
|
-
return {
|
|
185
|
-
kind: "eval-summary",
|
|
186
|
-
schemaVersion: report.schemaVersion ?? EVAL_REPORT_SCHEMA_VERSION,
|
|
187
|
-
runId: report.runId,
|
|
188
|
-
definitionId: report.definitionId,
|
|
189
|
-
targetKind: report.targetKind,
|
|
190
|
-
target: report.target,
|
|
191
|
-
...(report.dataset ? { dataset: report.dataset } : {}),
|
|
192
|
-
startedAt: report.startedAt,
|
|
193
|
-
endedAt: report.endedAt,
|
|
194
|
-
summary: report.summary,
|
|
195
|
-
...(report.metadata ? { metadata: report.metadata } : {}),
|
|
196
|
-
...(report.exports ? { exports: report.exports } : {}),
|
|
197
|
-
...(baseline ? { baseline } : {}),
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
92
|
function createEvalBaselineComparisonPolicy(options) {
|
|
201
93
|
return {
|
|
202
94
|
...(options.baselinePassRateDropThreshold !== undefined
|
|
@@ -490,199 +382,12 @@ export async function createResolvedEvalModelComparisonConfig(projectDir, option
|
|
|
490
382
|
const policy = await loadEvalModelComparisonPolicy(projectDir, config.comparisonPolicy);
|
|
491
383
|
return { config, policy };
|
|
492
384
|
}
|
|
493
|
-
export function createEvalModelComparisonArtifact(reports, baselineModel, policy = {}) {
|
|
494
|
-
return compareEvalModelReports(reports, { ...policy, baselineModel });
|
|
495
|
-
}
|
|
496
|
-
export function createEvalModelComparisonExitCode(reports, exportRequired = false) {
|
|
497
|
-
return reports.some((report) => createEvalExitCode(report, undefined, exportRequired) !== 0)
|
|
498
|
-
? 1
|
|
499
|
-
: 0;
|
|
500
|
-
}
|
|
501
|
-
export function createResultsJsonl(report) {
|
|
502
|
-
if (report.records.length === 0)
|
|
503
|
-
return "";
|
|
504
|
-
return `${report.records.map((record) => JSON.stringify(record)).join("\n")}\n`;
|
|
505
|
-
}
|
|
506
|
-
function markdownCell(value) {
|
|
507
|
-
return value.replaceAll("|", "\\|").replaceAll("\n", " ");
|
|
508
|
-
}
|
|
509
|
-
function numberCell(value) {
|
|
510
|
-
return value === undefined ? "-" : String(Math.round(value));
|
|
511
|
-
}
|
|
512
|
-
function decimalCell(value) {
|
|
513
|
-
if (value === undefined)
|
|
514
|
-
return "-";
|
|
515
|
-
if (Number.isInteger(value))
|
|
516
|
-
return String(value);
|
|
517
|
-
return value.toFixed(4).replace(/0+$/, "").replace(/\.$/, "");
|
|
518
|
-
}
|
|
519
|
-
function percentCell(value) {
|
|
520
|
-
return `${Math.round(value * 100)}%`;
|
|
521
|
-
}
|
|
522
|
-
function durationCell(valueMs) {
|
|
523
|
-
return valueMs === undefined ? "-" : `${(valueMs / 1000).toFixed(3)}s`;
|
|
524
|
-
}
|
|
525
|
-
function usdCell(value) {
|
|
526
|
-
if (value === undefined)
|
|
527
|
-
return "-";
|
|
528
|
-
const absolute = Math.abs(value);
|
|
529
|
-
if (absolute >= 0.01)
|
|
530
|
-
return `$${value.toFixed(2)}`;
|
|
531
|
-
return `$${value.toFixed(6).replace(/0+$/, "").replace(/\.$/, "")}`;
|
|
532
|
-
}
|
|
533
|
-
function isBlockingEvalResultFailure(result) {
|
|
534
|
-
return !result.skipped && result.pass === false &&
|
|
535
|
-
(result.severity === "gate" || result.severity === "budget");
|
|
536
|
-
}
|
|
537
|
-
function examplePassed(record) {
|
|
538
|
-
if (!record.completed || record.error)
|
|
539
|
-
return false;
|
|
540
|
-
return [...(record.metrics ?? []), ...(record.checks ?? [])].every((result) => !isBlockingEvalResultFailure(result));
|
|
541
|
-
}
|
|
542
|
-
function usageRows(usage) {
|
|
543
|
-
if (!usage)
|
|
544
|
-
return [];
|
|
545
|
-
const rows = [
|
|
546
|
-
["Input tokens", numberCell(usage.inputTokens)],
|
|
547
|
-
["Output tokens", numberCell(usage.outputTokens)],
|
|
548
|
-
["Total tokens", numberCell(usage.totalTokens)],
|
|
549
|
-
["Billable input tokens", numberCell(usage.billableInputTokens)],
|
|
550
|
-
["Billable output tokens", numberCell(usage.billableOutputTokens)],
|
|
551
|
-
["Provider input cost USD", usdCell(usage.providerInputCostUsd)],
|
|
552
|
-
["Provider output cost USD", usdCell(usage.providerOutputCostUsd)],
|
|
553
|
-
["Provider cost USD", usdCell(usage.providerCostUsd ?? usage.costUsd)],
|
|
554
|
-
["Veryfront input charge USD", usdCell(usage.veryfrontInputChargeUsd)],
|
|
555
|
-
["Veryfront output charge USD", usdCell(usage.veryfrontOutputChargeUsd)],
|
|
556
|
-
["Veryfront charge USD", usdCell(usage.veryfrontChargeUsd)],
|
|
557
|
-
["Veryfront billed USD", usdCell(usage.veryfrontBilledUsd)],
|
|
558
|
-
["Cost credits", decimalCell(usage.costCredits)],
|
|
559
|
-
["Cost source", usage.costSource ?? "-"],
|
|
560
|
-
["Billing mode", usage.billingMode ?? "-"],
|
|
561
|
-
["Usage capture status", usage.usageCaptureStatus ?? "-"],
|
|
562
|
-
];
|
|
563
|
-
return rows.filter(([, value]) => value !== "-");
|
|
564
|
-
}
|
|
565
|
-
/** Render a human-reviewable markdown report for a single eval run. */
|
|
566
|
-
export function createEvalMarkdownReport(report, baseline) {
|
|
567
|
-
const lines = [
|
|
568
|
-
`# Eval report: ${markdownCell(report.definitionId)}`,
|
|
569
|
-
"",
|
|
570
|
-
`Run: \`${markdownCell(report.runId)}\``,
|
|
571
|
-
`Target: \`${markdownCell(report.target)}\``,
|
|
572
|
-
...(report.metadata?.model ? [`Model: \`${markdownCell(report.metadata.model)}\``] : []),
|
|
573
|
-
`Result: \`${report.summary.passed}/${report.summary.records} passed (${percentCell(report.summary.passRate)})\``,
|
|
574
|
-
"",
|
|
575
|
-
"## Metrics",
|
|
576
|
-
"",
|
|
577
|
-
"| Metric | Severity | Passed | Failed | Pass rate |",
|
|
578
|
-
"| --- | --- | ---: | ---: | ---: |",
|
|
579
|
-
];
|
|
580
|
-
for (const metric of report.summary.metrics) {
|
|
581
|
-
lines.push(`| \`${markdownCell(metric.name)}\` | ${metric.severity} | ${metric.passed} | ${metric.failed} | ${percentCell(metric.passRate)} |`);
|
|
582
|
-
}
|
|
583
|
-
const rows = usageRows(report.summary.usage);
|
|
584
|
-
if (rows.length > 0) {
|
|
585
|
-
lines.push("", "## Usage", "", "| Usage | Value |", "| --- | ---: |");
|
|
586
|
-
for (const [label, value] of rows) {
|
|
587
|
-
lines.push(`| ${label} | ${value.startsWith("$") ? `\`${value}\`` : value} |`);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
lines.push("", "## Examples", "", "| Example | Result | Duration | Tokens | Billed USD | Credits |", "| --- | ---: | ---: | ---: | ---: | ---: |");
|
|
591
|
-
for (const record of report.records) {
|
|
592
|
-
lines.push(`| \`${markdownCell(record.id)}\` | ${examplePassed(record) ? "PASS" : "FAIL"} | ${durationCell(record.durationMs)} | ${numberCell(record.usage.totalTokens)} | ${record.usage.veryfrontBilledUsd === undefined
|
|
593
|
-
? "-"
|
|
594
|
-
: `\`${usdCell(record.usage.veryfrontBilledUsd)}\``} | ${decimalCell(record.usage.costCredits)} |`);
|
|
595
|
-
}
|
|
596
|
-
if (baseline) {
|
|
597
|
-
const direction = baseline.passRateDelta >= 0 ? "+" : "";
|
|
598
|
-
lines.push("", "## Baseline", "", `Status: \`${baseline.regressed ? "regressed" : "ok"}\``, `Pass rate delta: \`${direction}${Math.round(baseline.passRateDelta * 100)} pp\``);
|
|
599
|
-
if (baseline.newFailedExamples.length > 0) {
|
|
600
|
-
lines.push(`New failed examples: ${baseline.newFailedExamples.map(markdownCell).join(", ")}`);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
if (report.exports?.length) {
|
|
604
|
-
lines.push("", "## Exports", "");
|
|
605
|
-
for (const result of report.exports) {
|
|
606
|
-
lines.push(`- \`${markdownCell(result.exporterId)}\`: ${result.ok ? "ok" : `failed, ${markdownCell(result.error)}`}`);
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
lines.push("");
|
|
610
|
-
return lines.join("\n");
|
|
611
|
-
}
|
|
612
|
-
export function createJunitXml(report) {
|
|
613
|
-
const skipped = report.records.reduce((count, record) => count + skippedResults(record).length, 0);
|
|
614
|
-
const lines = [
|
|
615
|
-
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
616
|
-
`<testsuite name="${xmlEscape(report.definitionId)}" tests="${report.summary.records}" failures="${report.summary.failed}" skipped="${skipped}">`,
|
|
617
|
-
];
|
|
618
|
-
for (const record of report.records) {
|
|
619
|
-
const failures = blockingResults(record);
|
|
620
|
-
const skips = skippedResults(record);
|
|
621
|
-
const attrs = `classname="${xmlEscape(report.definitionId)}" name="${xmlEscape(testcaseName(record))}" time="${(record.durationMs / 1000).toFixed(3)}"`;
|
|
622
|
-
if (failures.length === 0 && skips.length === 0) {
|
|
623
|
-
lines.push(` <testcase ${attrs} />`);
|
|
624
|
-
continue;
|
|
625
|
-
}
|
|
626
|
-
lines.push(` <testcase ${attrs}>`);
|
|
627
|
-
for (const failure of failures) {
|
|
628
|
-
lines.push(` <failure message="${xmlEscape(failureMessage(failure))}">${xmlEscape(failureBody(failure))}</failure>`);
|
|
629
|
-
}
|
|
630
|
-
for (const skip of skips) {
|
|
631
|
-
lines.push(` <skipped message="${xmlEscape(skip.explanation ?? `${skip.name} skipped`)}" />`);
|
|
632
|
-
}
|
|
633
|
-
lines.push(" </testcase>");
|
|
634
|
-
}
|
|
635
|
-
lines.push("</testsuite>");
|
|
636
|
-
return `${lines.join("\n")}\n`;
|
|
637
|
-
}
|
|
638
|
-
function createEvalSuiteResultsJsonl(summary) {
|
|
639
|
-
return summary.results.map((result) => JSON.stringify(result)).join("\n") +
|
|
640
|
-
(summary.results.length > 0 ? "\n" : "");
|
|
641
|
-
}
|
|
642
|
-
export function createEvalSuiteJunitXml(summary) {
|
|
643
|
-
const lines = [
|
|
644
|
-
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
645
|
-
`<testsuites tests="${summary.total}" failures="${summary.failed}" skipped="0">`,
|
|
646
|
-
` <testsuite name="veryfront eval suite" tests="${summary.total}" failures="${summary.failed}" skipped="0">`,
|
|
647
|
-
];
|
|
648
|
-
for (const result of summary.results) {
|
|
649
|
-
const attrs = `classname="eval" name="${xmlEscape(result.id)}"`;
|
|
650
|
-
if (result.status === "passed") {
|
|
651
|
-
lines.push(` <testcase ${attrs} />`);
|
|
652
|
-
continue;
|
|
653
|
-
}
|
|
654
|
-
const message = result.error ??
|
|
655
|
-
(result.summary?.failed
|
|
656
|
-
? `${result.summary.failed} record(s) failed`
|
|
657
|
-
: "A required eval export failed.");
|
|
658
|
-
lines.push(` <testcase ${attrs}>`);
|
|
659
|
-
lines.push(` <failure message="${xmlEscape(message)}">${xmlEscape(message)}</failure>`);
|
|
660
|
-
lines.push(" </testcase>");
|
|
661
|
-
}
|
|
662
|
-
lines.push(" </testsuite>");
|
|
663
|
-
lines.push("</testsuites>");
|
|
664
|
-
return `${lines.join("\n")}\n`;
|
|
665
|
-
}
|
|
666
385
|
async function writeTextFileEnsuringDir(path, content) {
|
|
667
386
|
const dir = dirname(path);
|
|
668
387
|
if (dir && dir !== ".")
|
|
669
388
|
await dntShim.Deno.mkdir(dir, { recursive: true });
|
|
670
389
|
await dntShim.Deno.writeTextFile(path, content);
|
|
671
390
|
}
|
|
672
|
-
export async function writeEvalArtifacts(report, paths, baseline) {
|
|
673
|
-
await dntShim.Deno.mkdir(paths.directory, { recursive: true });
|
|
674
|
-
await dntShim.Deno.writeTextFile(paths.summary, JSON.stringify(createSummaryArtifact(report, baseline), null, 2));
|
|
675
|
-
await dntShim.Deno.writeTextFile(paths.results, createResultsJsonl(report));
|
|
676
|
-
await dntShim.Deno.writeTextFile(paths.reportMarkdown, createEvalMarkdownReport(report, baseline));
|
|
677
|
-
}
|
|
678
|
-
async function readEvalReport(path) {
|
|
679
|
-
return JSON.parse(await dntShim.Deno.readTextFile(path));
|
|
680
|
-
}
|
|
681
|
-
export function createEvalExitCode(report, baseline, exportRequired = false) {
|
|
682
|
-
const exportFailed = exportRequired &&
|
|
683
|
-
(!(report.exports?.length) || report.exports.some((result) => !result.ok));
|
|
684
|
-
return report.summary.failed === 0 && baseline?.regressed !== true && !exportFailed ? 0 : 1;
|
|
685
|
-
}
|
|
686
391
|
function resolveAgentTargetId(target) {
|
|
687
392
|
return target.startsWith("agent:") ? target.slice("agent:".length) : target;
|
|
688
393
|
}
|
|
@@ -894,38 +599,6 @@ function unsupportedEvalSuiteOption(options) {
|
|
|
894
599
|
return undefined;
|
|
895
600
|
return `${flags.join(", ")} require a named eval. Run \`veryfront eval <eval-id>\`.`;
|
|
896
601
|
}
|
|
897
|
-
function createEvalSuiteSummary(runId, startedAt, results) {
|
|
898
|
-
const passed = results.filter((result) => result.status === "passed").length;
|
|
899
|
-
return {
|
|
900
|
-
kind: "eval-suite-summary",
|
|
901
|
-
runId,
|
|
902
|
-
startedAt: startedAt.toISOString(),
|
|
903
|
-
endedAt: new Date().toISOString(),
|
|
904
|
-
total: results.length,
|
|
905
|
-
passed,
|
|
906
|
-
failed: results.length - passed,
|
|
907
|
-
results,
|
|
908
|
-
};
|
|
909
|
-
}
|
|
910
|
-
function createEvalSuiteMarkdown(summary) {
|
|
911
|
-
const rows = summary.results.map((result) => `| ${markdownCell(result.id)} | ${result.status} | ${result.summary ? `${result.summary.passed}/${result.summary.records}` : "n/a"} | ${result.error ? markdownCell(result.error) : ""} |`);
|
|
912
|
-
return [
|
|
913
|
-
"# Eval suite report",
|
|
914
|
-
"",
|
|
915
|
-
`Run: \`${markdownCell(summary.runId)}\``,
|
|
916
|
-
`Result: \`${summary.passed}/${summary.total} passed\``,
|
|
917
|
-
"",
|
|
918
|
-
"| Eval | Status | Records | Error |",
|
|
919
|
-
"| --- | --- | --- | --- |",
|
|
920
|
-
...rows,
|
|
921
|
-
"",
|
|
922
|
-
].join("\n");
|
|
923
|
-
}
|
|
924
|
-
async function writeEvalSuiteArtifacts(summary, artifacts) {
|
|
925
|
-
await writeTextFileEnsuringDir(artifacts.summary, JSON.stringify(summary, null, 2));
|
|
926
|
-
await writeTextFileEnsuringDir(artifacts.results, createEvalSuiteResultsJsonl(summary));
|
|
927
|
-
await writeTextFileEnsuringDir(artifacts.reportMarkdown, createEvalSuiteMarkdown(summary));
|
|
928
|
-
}
|
|
929
602
|
function getDiscoveredEvals(runtime) {
|
|
930
603
|
return [...runtime.evals.entries()].map(([id, definition]) => {
|
|
931
604
|
if (!definition.source) {
|
|
@@ -963,7 +636,7 @@ function printReport(report, baseline) {
|
|
|
963
636
|
}
|
|
964
637
|
}
|
|
965
638
|
}
|
|
966
|
-
|
|
639
|
+
function createEvalCliBaseExportConfig(options, registry, config) {
|
|
967
640
|
const exporterIds = resolveEvalExporterIds(options);
|
|
968
641
|
if (exporterIds.length === 0)
|
|
969
642
|
return undefined;
|
|
@@ -973,12 +646,7 @@ export function createEvalCliExportConfig(evalItem, options, projectDir, artifac
|
|
|
973
646
|
exporterIds,
|
|
974
647
|
required: resolveEvalExportRequired(options),
|
|
975
648
|
context: {
|
|
976
|
-
evalId: evalItem.definition.id,
|
|
977
649
|
...(projectReference ? { projectReference } : {}),
|
|
978
|
-
sourcePath: displaySourcePath(evalItem.filePath, projectDir),
|
|
979
|
-
reportPath: options.report ?? artifactPaths.summary,
|
|
980
|
-
tags: evalItem.definition.tags,
|
|
981
|
-
metadata: evalItem.definition.metadata,
|
|
982
650
|
redaction: resolveEvalExportRedactionFromEnv(),
|
|
983
651
|
},
|
|
984
652
|
};
|
|
@@ -1095,75 +763,6 @@ function resolveEvalModelComparisonConfig(options) {
|
|
|
1095
763
|
models: uniqueValues([baselineModel, ...candidateModels]),
|
|
1096
764
|
};
|
|
1097
765
|
}
|
|
1098
|
-
function createAgentAdapterForModel(agent, options, model) {
|
|
1099
|
-
return createAgentAdapter(agent, { ...options, model });
|
|
1100
|
-
}
|
|
1101
|
-
async function writeEvalModelComparisonArtifacts(comparison, paths) {
|
|
1102
|
-
await dntShim.Deno.mkdir(paths.directory, { recursive: true });
|
|
1103
|
-
await dntShim.Deno.writeTextFile(paths.comparisonJson, JSON.stringify(comparison, null, 2));
|
|
1104
|
-
await dntShim.Deno.writeTextFile(paths.comparisonMarkdown, createEvalModelComparisonMarkdown(comparison));
|
|
1105
|
-
}
|
|
1106
|
-
async function runEvalModelComparison(input) {
|
|
1107
|
-
const runId = createEvalRunId();
|
|
1108
|
-
const reportDir = input.options.reportDir ??
|
|
1109
|
-
createDefaultEvalReportDir(runId, input.evalItem.id);
|
|
1110
|
-
const paths = createEvalModelComparisonArtifactPaths(reportDir, input.config.models);
|
|
1111
|
-
const provenance = await resolveEvalRunProvenance({
|
|
1112
|
-
projectDir: input.projectDir,
|
|
1113
|
-
frameworkVersion: VERSION,
|
|
1114
|
-
});
|
|
1115
|
-
const reports = [];
|
|
1116
|
-
for (const model of input.config.models) {
|
|
1117
|
-
const modelPaths = paths.models[model];
|
|
1118
|
-
const modelOptions = { ...input.options, model, report: undefined };
|
|
1119
|
-
const modelRunId = `${runId}_${sanitizeModelIdForPath(model)}`;
|
|
1120
|
-
const exportConfig = createEvalCliExportConfig(input.evalItem, modelOptions, input.projectDir, modelPaths, input.exporterRegistry, input.projectReference ? { projectSlug: input.projectReference } : undefined);
|
|
1121
|
-
const finalizedReport = await runEvalWithGatewayBillingGroup(modelRunId, () => runEval(input.evalItem.definition, {
|
|
1122
|
-
baseDir: input.options.datasetBase ?? input.projectDir,
|
|
1123
|
-
runId: modelRunId,
|
|
1124
|
-
adapters: {
|
|
1125
|
-
agent: createAgentAdapterForModel(input.agent, input.options, model),
|
|
1126
|
-
},
|
|
1127
|
-
metadata: {
|
|
1128
|
-
model,
|
|
1129
|
-
provenance,
|
|
1130
|
-
},
|
|
1131
|
-
}));
|
|
1132
|
-
const report = await exportEvalReportForCli(finalizedReport, exportConfig);
|
|
1133
|
-
reports.push(report);
|
|
1134
|
-
await writeEvalArtifacts(report, modelPaths);
|
|
1135
|
-
await writeTextFileEnsuringDir(modelPaths.junit, createJunitXml(report));
|
|
1136
|
-
}
|
|
1137
|
-
const comparison = createEvalModelComparisonArtifact(reports, input.config.baselineModel, input.policy);
|
|
1138
|
-
await writeEvalModelComparisonArtifacts(comparison, paths);
|
|
1139
|
-
if (input.options.report) {
|
|
1140
|
-
await writeTextFileEnsuringDir(input.options.report, JSON.stringify(comparison, null, 2));
|
|
1141
|
-
}
|
|
1142
|
-
if (isJsonMode()) {
|
|
1143
|
-
await outputJson(createSuccessEnvelope("eval", {
|
|
1144
|
-
reports,
|
|
1145
|
-
comparison,
|
|
1146
|
-
artifacts: paths,
|
|
1147
|
-
}));
|
|
1148
|
-
}
|
|
1149
|
-
else {
|
|
1150
|
-
for (const report of reports) {
|
|
1151
|
-
const model = report.metadata?.model ?? report.runId;
|
|
1152
|
-
cliLogger.info(`Model: ${model}`);
|
|
1153
|
-
printReport(report);
|
|
1154
|
-
}
|
|
1155
|
-
cliLogger.info(`Recommendation: ${comparison.recommendation.decision}${comparison.recommendation.model ? ` (${comparison.recommendation.model})` : ""}`);
|
|
1156
|
-
for (const reason of comparison.recommendation.reasons) {
|
|
1157
|
-
cliLogger.info(` - ${reason}`);
|
|
1158
|
-
}
|
|
1159
|
-
cliLogger.info(`Report directory: ${paths.directory}`);
|
|
1160
|
-
cliLogger.info(`Comparison: ${paths.comparisonJson}`);
|
|
1161
|
-
cliLogger.info(`Comparison markdown: ${paths.comparisonMarkdown}`);
|
|
1162
|
-
if (input.options.report)
|
|
1163
|
-
cliLogger.info(`Report: ${input.options.report}`);
|
|
1164
|
-
}
|
|
1165
|
-
return createEvalModelComparisonExitCode(reports, resolveEvalExportRequired(input.options));
|
|
1166
|
-
}
|
|
1167
766
|
async function outputEvalNotFound(id, evals) {
|
|
1168
767
|
if (isJsonMode()) {
|
|
1169
768
|
await outputJson(createErrorEnvelope("eval", {
|
|
@@ -1225,88 +824,57 @@ async function outputEvalUsageError(message) {
|
|
|
1225
824
|
}
|
|
1226
825
|
return 2;
|
|
1227
826
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
}
|
|
1280
|
-
catch (error) {
|
|
1281
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1282
|
-
results.push({
|
|
1283
|
-
id: evalItem.id,
|
|
1284
|
-
name: evalItem.name,
|
|
1285
|
-
target: evalItem.definition.target,
|
|
1286
|
-
status: "error",
|
|
1287
|
-
artifacts: evalArtifacts,
|
|
1288
|
-
error: message,
|
|
1289
|
-
});
|
|
1290
|
-
if (!isJsonMode())
|
|
1291
|
-
cliLogger.error(`Eval ${evalItem.id}: ${message}`);
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
const summary = createEvalSuiteSummary(runId, startedAt, results);
|
|
1295
|
-
await writeEvalSuiteArtifacts(summary, artifacts);
|
|
1296
|
-
if (input.options.junit) {
|
|
1297
|
-
await writeTextFileEnsuringDir(input.options.junit, createEvalSuiteJunitXml(summary));
|
|
1298
|
-
}
|
|
1299
|
-
if (isJsonMode()) {
|
|
1300
|
-
await outputJson(createSuccessEnvelope("eval", { suite: summary, artifacts }));
|
|
1301
|
-
}
|
|
1302
|
-
else {
|
|
1303
|
-
cliLogger.info(`Eval suite: ${summary.passed}/${summary.total} passed`);
|
|
1304
|
-
cliLogger.info(`Report directory: ${artifacts.directory}`);
|
|
1305
|
-
cliLogger.info(`Suite report: ${artifacts.reportMarkdown}`);
|
|
1306
|
-
if (input.options.junit)
|
|
1307
|
-
cliLogger.info(`JUnit: ${input.options.junit}`);
|
|
1308
|
-
}
|
|
1309
|
-
return summary.failed === 0 ? 0 : 1;
|
|
827
|
+
function createEvalReportCommandAdapters(input) {
|
|
828
|
+
return {
|
|
829
|
+
targets: {
|
|
830
|
+
runEval: (evalItem, options) => runEval(evalItem.definition, {
|
|
831
|
+
baseDir: options.baseDir,
|
|
832
|
+
runId: options.runId,
|
|
833
|
+
adapters: options.targetKind === "tool"
|
|
834
|
+
? { tool: options.targetAdapter }
|
|
835
|
+
: { agent: options.targetAdapter },
|
|
836
|
+
metadata: options.metadata,
|
|
837
|
+
}),
|
|
838
|
+
resolveTarget: (evalItem) => {
|
|
839
|
+
const agentId = evalItem.definition.targetKind === "agent"
|
|
840
|
+
? resolveAgentTargetId(evalItem.definition.target)
|
|
841
|
+
: undefined;
|
|
842
|
+
const toolId = evalItem.definition.targetKind === "tool"
|
|
843
|
+
? resolveToolTargetId(evalItem.definition.target)
|
|
844
|
+
: undefined;
|
|
845
|
+
const agent = agentId ? input.projectRuntime.agents.get(agentId) : undefined;
|
|
846
|
+
const tool = toolId ? input.projectRuntime.tools.get(toolId) : undefined;
|
|
847
|
+
if (agentId && !agent)
|
|
848
|
+
throw new Error(`Agent "${agentId}" not found for eval target.`);
|
|
849
|
+
if (toolId && !tool)
|
|
850
|
+
throw new Error(`Tool "${toolId}" not found for eval target.`);
|
|
851
|
+
return {
|
|
852
|
+
targetKind: evalItem.definition.targetKind,
|
|
853
|
+
target: evalItem.definition.target,
|
|
854
|
+
targetAdapter: evalItem.definition.targetKind === "tool"
|
|
855
|
+
? createToolAdapter(tool, createEvalToolExecutionContext(input.config))
|
|
856
|
+
: createAgentAdapter(agent, input.options),
|
|
857
|
+
};
|
|
858
|
+
},
|
|
859
|
+
createModelTargetAdapter: (model) => {
|
|
860
|
+
const options = { ...input.options, model };
|
|
861
|
+
if (!input.modelComparisonAgent) {
|
|
862
|
+
throw new Error("Model comparison agent is not configured.");
|
|
863
|
+
}
|
|
864
|
+
return createAgentAdapter(input.modelComparisonAgent, options);
|
|
865
|
+
},
|
|
866
|
+
},
|
|
867
|
+
artifacts: {
|
|
868
|
+
readTextFile: (path) => dntShim.Deno.readTextFile(path),
|
|
869
|
+
writeTextFileEnsuringDir,
|
|
870
|
+
},
|
|
871
|
+
billing: {
|
|
872
|
+
runWithGatewayBillingGroup: runEvalWithGatewayBillingGroup,
|
|
873
|
+
},
|
|
874
|
+
exporters: {
|
|
875
|
+
exportReport: (report, config) => exportEvalReportForCli(report, config),
|
|
876
|
+
},
|
|
877
|
+
};
|
|
1310
878
|
}
|
|
1311
879
|
export async function runEvalCommand(options, dependencies = {}) {
|
|
1312
880
|
const projectDir = options.projectDir ?? dntShim.Deno.cwd();
|
|
@@ -1375,14 +943,52 @@ export async function runEvalCommand(options, dependencies = {}) {
|
|
|
1375
943
|
const selectedExporterIds = resolveEvalExporterIds(options);
|
|
1376
944
|
const extensionSetup = await setupEvalCliExtensions(projectDir, config, selectedExporterIds);
|
|
1377
945
|
try {
|
|
1378
|
-
return await runWithProjectAgentRuntime(projectRuntime, () =>
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
946
|
+
return await runWithProjectAgentRuntime(projectRuntime, async () => {
|
|
947
|
+
const outcome = await runEvalReport({
|
|
948
|
+
kind: "suite",
|
|
949
|
+
projectDir,
|
|
950
|
+
frameworkVersion: VERSION,
|
|
951
|
+
...(options.datasetBase ? { datasetBase: options.datasetBase } : {}),
|
|
952
|
+
...(options.reportDir ? { reportDir: options.reportDir } : {}),
|
|
953
|
+
...(options.junit ? { junit: options.junit } : {}),
|
|
954
|
+
exportConfig: createEvalCliBaseExportConfig(options, extensionSetup.exporterRegistry, config),
|
|
955
|
+
provenance: await resolveEvalRunProvenance({
|
|
956
|
+
projectDir,
|
|
957
|
+
frameworkVersion: VERSION,
|
|
958
|
+
}),
|
|
959
|
+
evalItems: evals,
|
|
960
|
+
}, createEvalReportCommandAdapters({
|
|
961
|
+
options,
|
|
962
|
+
config,
|
|
963
|
+
projectRuntime,
|
|
964
|
+
}));
|
|
965
|
+
if (outcome.kind !== "suite") {
|
|
966
|
+
throw new Error(`Unexpected eval report outcome: ${outcome.kind}`);
|
|
967
|
+
}
|
|
968
|
+
if (isJsonMode()) {
|
|
969
|
+
await outputJson(createSuccessEnvelope("eval", {
|
|
970
|
+
suite: outcome.suite,
|
|
971
|
+
artifacts: outcome.artifacts,
|
|
972
|
+
}));
|
|
973
|
+
}
|
|
974
|
+
else {
|
|
975
|
+
for (const child of outcome.outputHints.children ?? []) {
|
|
976
|
+
if (child.kind === "report") {
|
|
977
|
+
printReport(child.report);
|
|
978
|
+
cliLogger.info(`Report directory: ${child.reportDirectory}`);
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
cliLogger.error(`Eval ${child.evalId}: ${child.error}`);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
cliLogger.info(`Eval suite: ${outcome.suite.passed}/${outcome.suite.total} passed`);
|
|
985
|
+
cliLogger.info(`Report directory: ${outcome.outputHints.reportDirectory}`);
|
|
986
|
+
cliLogger.info(`Suite report: ${outcome.outputHints.reportMarkdown}`);
|
|
987
|
+
if (outcome.outputHints.junit)
|
|
988
|
+
cliLogger.info(`JUnit: ${outcome.outputHints.junit}`);
|
|
989
|
+
}
|
|
990
|
+
return outcome.exitCode;
|
|
991
|
+
});
|
|
1386
992
|
}
|
|
1387
993
|
finally {
|
|
1388
994
|
await extensionSetup.loader.teardownAll();
|
|
@@ -1426,72 +1032,123 @@ export async function runEvalCommand(options, dependencies = {}) {
|
|
|
1426
1032
|
return await outputToolNotFound(toolId);
|
|
1427
1033
|
}
|
|
1428
1034
|
if (modelComparisonConfig) {
|
|
1429
|
-
return await runWithProjectAgentRuntime(projectRuntime, () =>
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1035
|
+
return await runWithProjectAgentRuntime(projectRuntime, async () => {
|
|
1036
|
+
const outcome = await runEvalReport({
|
|
1037
|
+
kind: "model-comparison",
|
|
1038
|
+
projectDir,
|
|
1039
|
+
frameworkVersion: VERSION,
|
|
1040
|
+
...(options.datasetBase ? { datasetBase: options.datasetBase } : {}),
|
|
1041
|
+
...(options.reportDir ? { reportDir: options.reportDir } : {}),
|
|
1042
|
+
...(options.report ? { report: options.report } : {}),
|
|
1043
|
+
exportConfig: createEvalCliBaseExportConfig(options, extensionSetup.exporterRegistry, config),
|
|
1044
|
+
provenance: await resolveEvalRunProvenance({
|
|
1045
|
+
projectDir,
|
|
1046
|
+
frameworkVersion: VERSION,
|
|
1047
|
+
}),
|
|
1048
|
+
evalItem,
|
|
1049
|
+
target: evalItem.definition.target,
|
|
1050
|
+
baselineModel: modelComparisonConfig.config.baselineModel,
|
|
1051
|
+
candidateModels: modelComparisonConfig.config.candidateModels,
|
|
1052
|
+
comparisonPolicy: modelComparisonConfig.policy,
|
|
1053
|
+
...(options.maxOutputTokens !== undefined
|
|
1054
|
+
? { maxOutputTokens: options.maxOutputTokens }
|
|
1055
|
+
: {}),
|
|
1056
|
+
}, createEvalReportCommandAdapters({
|
|
1057
|
+
options,
|
|
1058
|
+
config,
|
|
1059
|
+
projectRuntime,
|
|
1060
|
+
modelComparisonAgent: agent,
|
|
1061
|
+
}));
|
|
1062
|
+
if (outcome.kind !== "model-comparison") {
|
|
1063
|
+
throw new Error(`Unexpected eval report outcome: ${outcome.kind}`);
|
|
1064
|
+
}
|
|
1065
|
+
if (isJsonMode()) {
|
|
1066
|
+
await outputJson(createSuccessEnvelope("eval", {
|
|
1067
|
+
reports: outcome.reports,
|
|
1068
|
+
comparison: outcome.comparison,
|
|
1069
|
+
artifacts: outcome.artifacts,
|
|
1070
|
+
}));
|
|
1071
|
+
}
|
|
1072
|
+
else {
|
|
1073
|
+
for (const model of outcome.outputHints.models ?? []) {
|
|
1074
|
+
cliLogger.info(`Model: ${model.model}`);
|
|
1075
|
+
printReport(model.report);
|
|
1076
|
+
}
|
|
1077
|
+
const recommendation = outcome.comparison.recommendation;
|
|
1078
|
+
cliLogger.info(`Recommendation: ${recommendation.decision}${recommendation.model ? ` (${recommendation.model})` : ""}`);
|
|
1079
|
+
for (const reason of recommendation.reasons) {
|
|
1080
|
+
cliLogger.info(` - ${reason}`);
|
|
1081
|
+
}
|
|
1082
|
+
cliLogger.info(`Report directory: ${outcome.outputHints.reportDirectory}`);
|
|
1083
|
+
if (outcome.outputHints.comparisonJson) {
|
|
1084
|
+
cliLogger.info(`Comparison: ${outcome.outputHints.comparisonJson}`);
|
|
1085
|
+
}
|
|
1086
|
+
if (outcome.outputHints.comparisonMarkdown) {
|
|
1087
|
+
cliLogger.info(`Comparison markdown: ${outcome.outputHints.comparisonMarkdown}`);
|
|
1088
|
+
}
|
|
1089
|
+
if (outcome.outputHints.report) {
|
|
1090
|
+
cliLogger.info(`Report: ${outcome.outputHints.report}`);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
return outcome.exitCode;
|
|
1094
|
+
});
|
|
1439
1095
|
}
|
|
1440
|
-
const
|
|
1441
|
-
|
|
1442
|
-
|
|
1096
|
+
const targetAdapter = evalItem.definition.targetKind === "tool"
|
|
1097
|
+
? createToolAdapter(tool, createEvalToolExecutionContext(config))
|
|
1098
|
+
: createAgentAdapter(agent, options);
|
|
1099
|
+
const outcome = await runWithProjectAgentRuntime(projectRuntime, async () => await runEvalReport({
|
|
1100
|
+
kind: "single",
|
|
1443
1101
|
projectDir,
|
|
1444
1102
|
frameworkVersion: VERSION,
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
?
|
|
1448
|
-
:
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
:
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1103
|
+
...(options.datasetBase ? { datasetBase: options.datasetBase } : {}),
|
|
1104
|
+
...(options.reportDir ? { reportDir: options.reportDir } : {}),
|
|
1105
|
+
...(options.report ? { report: options.report } : {}),
|
|
1106
|
+
...(options.junit ? { junit: options.junit } : {}),
|
|
1107
|
+
...(options.baseline ? { baseline: options.baseline } : {}),
|
|
1108
|
+
...(options.writeBaseline ? { writeBaseline: options.writeBaseline } : {}),
|
|
1109
|
+
baselinePolicy: createEvalBaselineComparisonPolicy(options),
|
|
1110
|
+
exportConfig: createEvalCliBaseExportConfig(options, extensionSetup.exporterRegistry, config),
|
|
1111
|
+
provenance: await resolveEvalRunProvenance({
|
|
1112
|
+
projectDir,
|
|
1113
|
+
frameworkVersion: VERSION,
|
|
1114
|
+
}),
|
|
1115
|
+
evalItem,
|
|
1116
|
+
targetKind: evalItem.definition.targetKind,
|
|
1117
|
+
target: evalItem.definition.target,
|
|
1118
|
+
targetAdapter,
|
|
1119
|
+
...(options.model ? { selectedModel: options.model } : {}),
|
|
1120
|
+
...(options.maxOutputTokens !== undefined
|
|
1121
|
+
? { maxOutputTokens: options.maxOutputTokens }
|
|
1122
|
+
: {}),
|
|
1123
|
+
}, createEvalReportCommandAdapters({
|
|
1124
|
+
options,
|
|
1125
|
+
config,
|
|
1126
|
+
projectRuntime,
|
|
1460
1127
|
})));
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
? compareEvalReports(report, await readEvalReport(options.baseline), createEvalBaselineComparisonPolicy(options))
|
|
1464
|
-
: undefined;
|
|
1465
|
-
await writeEvalArtifacts(report, artifactPaths, baseline);
|
|
1466
|
-
if (options.report) {
|
|
1467
|
-
await writeTextFileEnsuringDir(options.report, JSON.stringify(report, null, 2));
|
|
1468
|
-
}
|
|
1469
|
-
if (options.junit) {
|
|
1470
|
-
await writeTextFileEnsuringDir(options.junit, createJunitXml(report));
|
|
1471
|
-
}
|
|
1472
|
-
if (options.writeBaseline) {
|
|
1473
|
-
await writeTextFileEnsuringDir(options.writeBaseline, JSON.stringify(report, null, 2));
|
|
1128
|
+
if (outcome.kind !== "single") {
|
|
1129
|
+
throw new Error(`Unexpected eval report outcome: ${outcome.kind}`);
|
|
1474
1130
|
}
|
|
1475
1131
|
if (isJsonMode()) {
|
|
1476
1132
|
await outputJson(createSuccessEnvelope("eval", {
|
|
1477
|
-
report,
|
|
1478
|
-
summary:
|
|
1479
|
-
baseline,
|
|
1480
|
-
artifacts:
|
|
1133
|
+
report: outcome.report,
|
|
1134
|
+
summary: outcome.summary,
|
|
1135
|
+
baseline: outcome.baseline,
|
|
1136
|
+
artifacts: outcome.artifacts,
|
|
1481
1137
|
}));
|
|
1482
1138
|
}
|
|
1483
1139
|
else {
|
|
1484
|
-
printReport(report, baseline);
|
|
1485
|
-
cliLogger.info(`Report directory: ${
|
|
1486
|
-
cliLogger.info(`Report markdown: ${
|
|
1487
|
-
if (
|
|
1488
|
-
cliLogger.info(`Report: ${
|
|
1489
|
-
if (
|
|
1490
|
-
cliLogger.info(`JUnit: ${
|
|
1491
|
-
if (
|
|
1492
|
-
cliLogger.info(`Baseline written: ${
|
|
1140
|
+
printReport(outcome.report, outcome.baseline);
|
|
1141
|
+
cliLogger.info(`Report directory: ${outcome.outputHints.reportDirectory}`);
|
|
1142
|
+
cliLogger.info(`Report markdown: ${outcome.outputHints.reportMarkdown}`);
|
|
1143
|
+
if (outcome.outputHints.report)
|
|
1144
|
+
cliLogger.info(`Report: ${outcome.outputHints.report}`);
|
|
1145
|
+
if (outcome.outputHints.junit)
|
|
1146
|
+
cliLogger.info(`JUnit: ${outcome.outputHints.junit}`);
|
|
1147
|
+
if (outcome.outputHints.baselineWritten) {
|
|
1148
|
+
cliLogger.info(`Baseline written: ${outcome.outputHints.baselineWritten}`);
|
|
1149
|
+
}
|
|
1493
1150
|
}
|
|
1494
|
-
return
|
|
1151
|
+
return outcome.exitCode;
|
|
1495
1152
|
}
|
|
1496
1153
|
finally {
|
|
1497
1154
|
await extensionSetup.loader.teardownAll();
|