vieval 0.0.1 → 0.0.4
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/README.md +8 -5
- package/dist/cli/index.d.mts +1 -1
- package/dist/cli/index.mjs +1232 -83
- package/dist/cli/index.mjs.map +1 -1
- package/dist/{config-D2fe1SnT.mjs → config-CHN24egi.mjs} +1 -1
- package/dist/{config-D2fe1SnT.mjs.map → config-CHN24egi.mjs.map} +1 -1
- package/dist/config.d.mts +2 -3
- package/dist/config.mjs +2 -2
- package/dist/core/assertions/index.d.mts +1 -1
- package/dist/core/inference-executors/index.d.mts +1 -45
- package/dist/core/inference-executors/index.mjs +1 -38
- package/dist/core/inference-executors/index.mjs.map +1 -1
- package/dist/core/processors/results/index.d.mts +1 -1
- package/dist/core/runner/index.d.mts +2 -2
- package/dist/core/runner/index.mjs +2 -2
- package/dist/env-C7X81PWa.mjs +41 -0
- package/dist/env-C7X81PWa.mjs.map +1 -0
- package/dist/env-DtpjACOW.d.mts +47 -0
- package/dist/expect-B2vaoRVZ.d.mts +10 -0
- package/dist/{expect-i9WZWGrA.mjs → expect-CaXiUkwY.mjs} +3 -3
- package/dist/expect-CaXiUkwY.mjs.map +1 -0
- package/dist/expect-extensions-BOzwV5EJ.mjs +197 -0
- package/dist/expect-extensions-BOzwV5EJ.mjs.map +1 -0
- package/dist/expect.d.mts +1 -1
- package/dist/expect.mjs +1 -1
- package/dist/{index-DP7jsORl.d.mts → index-BDMEAmf2.d.mts} +246 -3
- package/dist/{index-oSXhM1zx.d.mts → index-C3gPFmcR.d.mts} +2 -2
- package/dist/index.d.mts +326 -6
- package/dist/index.mjs +65 -23
- package/dist/index.mjs.map +1 -1
- package/dist/{models-D_MsBtYw.mjs → models-DIGdOUpJ.mjs} +1 -1
- package/dist/{models-D_MsBtYw.mjs.map → models-DIGdOUpJ.mjs.map} +1 -1
- package/dist/plugins/chat-models/index.d.mts +465 -6
- package/dist/plugins/chat-models/index.mjs +469 -6
- package/dist/plugins/chat-models/index.mjs.map +1 -1
- package/dist/{registry-ChOjjdEC.mjs → registry-CHJcTN2W.mjs} +75 -16
- package/dist/registry-CHJcTN2W.mjs.map +1 -0
- package/dist/{runner-4ZsOveoY.mjs → runner-Dpy-eivM.mjs} +177 -21
- package/dist/runner-Dpy-eivM.mjs.map +1 -0
- package/dist/testing/expect-extensions.d.mts +44 -38
- package/dist/testing/expect-extensions.mjs +1 -1
- package/package.json +11 -4
- package/dist/expect-0jPJ7Zio.d.mts +0 -2318
- package/dist/expect-extensions-CwPtgTz8.mjs +0 -13471
- package/dist/expect-extensions-CwPtgTz8.mjs.map +0 -1
- package/dist/expect-i9WZWGrA.mjs.map +0 -1
- package/dist/magic-string.es-CH1jwzMg.mjs +0 -1013
- package/dist/magic-string.es-CH1jwzMg.mjs.map +0 -1
- package/dist/plugin-DVaRZY2x.d.mts +0 -84
- package/dist/registry-ChOjjdEC.mjs.map +0 -1
- package/dist/runner-4ZsOveoY.mjs.map +0 -1
|
@@ -137,7 +137,7 @@ function normalizeMatrixLayerInput(matrix) {
|
|
|
137
137
|
if (isLayerMatrixDefinition(matrix)) return matrix;
|
|
138
138
|
return { extend: matrix };
|
|
139
139
|
}
|
|
140
|
-
function normalizeProjectConfig(project, cwd, inheritedModels) {
|
|
140
|
+
function normalizeProjectConfig(project, cwd, inheritedModels, inheritedReporterReferences) {
|
|
141
141
|
const include = project.include ?? [
|
|
142
142
|
"**/*.eval.ts",
|
|
143
143
|
"**/*.eval.mts",
|
|
@@ -152,8 +152,9 @@ function normalizeProjectConfig(project, cwd, inheritedModels) {
|
|
|
152
152
|
"**/.git/**"
|
|
153
153
|
];
|
|
154
154
|
const models = project.models ?? [...inheritedModels];
|
|
155
|
-
const inferenceExecutors = project.inferenceExecutors ??
|
|
155
|
+
const inferenceExecutors = project.inferenceExecutors ?? [{ id: "default" }];
|
|
156
156
|
const root = project.root == null ? cwd : isAbsolute(project.root) ? project.root : resolve(cwd, project.root);
|
|
157
|
+
const reporters = project.reporters ?? [...inheritedReporterReferences];
|
|
157
158
|
return {
|
|
158
159
|
exclude,
|
|
159
160
|
executor: project.executor,
|
|
@@ -162,14 +163,61 @@ function normalizeProjectConfig(project, cwd, inheritedModels) {
|
|
|
162
163
|
models,
|
|
163
164
|
name: project.name,
|
|
164
165
|
inferenceExecutors,
|
|
166
|
+
reporters,
|
|
165
167
|
runMatrix: normalizeMatrixLayerInput(project.runMatrix),
|
|
166
168
|
root
|
|
167
169
|
};
|
|
168
170
|
}
|
|
169
171
|
function normalizeConfig(config, cwd) {
|
|
172
|
+
if (config != null) {
|
|
173
|
+
const mode = detectCliConfigMode(config);
|
|
174
|
+
if (mode === "comparisons") throw new Error("vieval run requires project-mode config. Received comparison-mode config.");
|
|
175
|
+
if (mode === "workspaces") throw new Error("vieval run requires project-mode config. Received workspace-mode config.");
|
|
176
|
+
}
|
|
170
177
|
const projects = config?.projects ?? [{ name: "default" }];
|
|
171
178
|
const inheritedModels = config?.models ?? [];
|
|
172
|
-
|
|
179
|
+
const inheritedReporterReferences = config?.reporters ?? [];
|
|
180
|
+
return projects.map((project) => normalizeProjectConfig(project, cwd, inheritedModels, inheritedReporterReferences));
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Detects which top-level config mode is active.
|
|
184
|
+
*
|
|
185
|
+
* Expects:
|
|
186
|
+
* - exactly one of `projects`, `workspaces`, or `comparisons`
|
|
187
|
+
*
|
|
188
|
+
* Returns:
|
|
189
|
+
* - active top-level mode key
|
|
190
|
+
*/
|
|
191
|
+
function detectCliConfigMode(config) {
|
|
192
|
+
const declaredModes = [];
|
|
193
|
+
if (config.projects != null) declaredModes.push("projects");
|
|
194
|
+
if (config.workspaces != null) declaredModes.push("workspaces");
|
|
195
|
+
if (config.comparisons != null) declaredModes.push("comparisons");
|
|
196
|
+
if (declaredModes.length > 1) throw new Error(`Invalid vieval config: top-level keys are mutually exclusive. Found ${declaredModes.join(", ")}.`);
|
|
197
|
+
return declaredModes[0] ?? "projects";
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Loads nearest `vieval.config.*` without project normalization.
|
|
201
|
+
*/
|
|
202
|
+
async function loadRawVievalConfig(options = {}) {
|
|
203
|
+
const cwd = options.cwd ?? process.cwd();
|
|
204
|
+
try {
|
|
205
|
+
const loadedConfig = await resolveVievalConfig(cwd, options.configFilePath);
|
|
206
|
+
if (loadedConfig.configFilePath == null || loadedConfig.config == null) return {
|
|
207
|
+
config: null,
|
|
208
|
+
configFilePath: null
|
|
209
|
+
};
|
|
210
|
+
const config = await applyVievalPlugins(loadedConfig.config);
|
|
211
|
+
detectCliConfigMode(config);
|
|
212
|
+
return {
|
|
213
|
+
config,
|
|
214
|
+
configFilePath: loadedConfig.configFilePath
|
|
215
|
+
};
|
|
216
|
+
} catch (error) {
|
|
217
|
+
const errorMessage = errorMessageFrom(error) ?? "Unknown config loading error.";
|
|
218
|
+
const configFilePath = options.configFilePath == null ? "vieval.config" : isAbsolute(options.configFilePath) ? options.configFilePath : resolve(cwd, options.configFilePath);
|
|
219
|
+
throw new Error(`Failed to load vieval config "${configFilePath}": ${errorMessage}`, { cause: error });
|
|
220
|
+
}
|
|
173
221
|
}
|
|
174
222
|
/**
|
|
175
223
|
* Loads nearest `vieval.config.*` and returns normalized project definitions.
|
|
@@ -188,13 +236,13 @@ function normalizeConfig(config, cwd) {
|
|
|
188
236
|
async function loadVievalCliConfig(options = {}) {
|
|
189
237
|
const cwd = options.cwd ?? process.cwd();
|
|
190
238
|
try {
|
|
191
|
-
const loadedConfig = await
|
|
239
|
+
const loadedConfig = await loadRawVievalConfig(options);
|
|
192
240
|
if (loadedConfig.configFilePath == null || loadedConfig.config == null) return {
|
|
193
241
|
configFilePath: null,
|
|
194
242
|
env: {},
|
|
195
243
|
projects: normalizeConfig(null, cwd)
|
|
196
244
|
};
|
|
197
|
-
const config =
|
|
245
|
+
const config = loadedConfig.config;
|
|
198
246
|
return {
|
|
199
247
|
configFilePath: loadedConfig.configFilePath,
|
|
200
248
|
env: config.env ?? {},
|
|
@@ -208,38 +256,49 @@ async function loadVievalCliConfig(options = {}) {
|
|
|
208
256
|
}
|
|
209
257
|
//#endregion
|
|
210
258
|
//#region src/dsl/registry.ts
|
|
211
|
-
const
|
|
212
|
-
|
|
259
|
+
const registryStoreSymbol = Symbol.for("vieval.dsl.registry.store");
|
|
260
|
+
function getRegistryStore() {
|
|
261
|
+
const processWithStore = process;
|
|
262
|
+
processWithStore[registryStoreSymbol] ??= {
|
|
263
|
+
activeModuleHref: null,
|
|
264
|
+
registeredDefinitionsByModule: /* @__PURE__ */ new Map()
|
|
265
|
+
};
|
|
266
|
+
return processWithStore[registryStoreSymbol];
|
|
267
|
+
}
|
|
213
268
|
/**
|
|
214
269
|
* Starts module-scoped eval registration collection.
|
|
215
270
|
*/
|
|
216
271
|
function beginModuleRegistration(moduleHref) {
|
|
217
|
-
|
|
272
|
+
const store = getRegistryStore();
|
|
273
|
+
store.activeModuleHref = moduleHref;
|
|
218
274
|
}
|
|
219
275
|
/**
|
|
220
276
|
* Ends module-scoped eval registration collection.
|
|
221
277
|
*/
|
|
222
278
|
function endModuleRegistration() {
|
|
223
|
-
|
|
279
|
+
const store = getRegistryStore();
|
|
280
|
+
store.activeModuleHref = null;
|
|
224
281
|
}
|
|
225
282
|
/**
|
|
226
283
|
* Registers one eval definition against the currently active module.
|
|
227
284
|
*/
|
|
228
285
|
function registerEvalDefinition(definition) {
|
|
229
|
-
|
|
230
|
-
|
|
286
|
+
const store = getRegistryStore();
|
|
287
|
+
if (store.activeModuleHref == null) return;
|
|
288
|
+
const existing = store.registeredDefinitionsByModule.get(store.activeModuleHref) ?? [];
|
|
231
289
|
existing.push(definition);
|
|
232
|
-
registeredDefinitionsByModule.set(activeModuleHref, existing);
|
|
290
|
+
store.registeredDefinitionsByModule.set(store.activeModuleHref, existing);
|
|
233
291
|
}
|
|
234
292
|
/**
|
|
235
293
|
* Consumes registered definitions for one module and clears stored state.
|
|
236
294
|
*/
|
|
237
295
|
function consumeModuleRegistrations(moduleHref) {
|
|
238
|
-
const
|
|
239
|
-
registeredDefinitionsByModule.
|
|
296
|
+
const store = getRegistryStore();
|
|
297
|
+
const definitions = store.registeredDefinitionsByModule.get(moduleHref) ?? [];
|
|
298
|
+
store.registeredDefinitionsByModule.delete(moduleHref);
|
|
240
299
|
return definitions;
|
|
241
300
|
}
|
|
242
301
|
//#endregion
|
|
243
|
-
export { defineConfig as a, registerEvalDefinition as i, consumeModuleRegistrations as n,
|
|
302
|
+
export { defineConfig as a, loadRawVievalConfig as c, registerEvalDefinition as i, loadVievalCliConfig as l, consumeModuleRegistrations as n, detectCliConfigMode as o, endModuleRegistration as r, loadEnv$1 as s, beginModuleRegistration as t };
|
|
244
303
|
|
|
245
|
-
//# sourceMappingURL=registry-
|
|
304
|
+
//# sourceMappingURL=registry-CHJcTN2W.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-CHJcTN2W.mjs","names":["loadEnv","loadViteEnv"],"sources":["../src/cli/config.ts","../src/dsl/registry.ts"],"sourcesContent":["import type { ConfigHookPlugin, MatrixDefinition, MatrixLayer, TaskRunContext } from '../config'\nimport type { ModelDefinition } from '../config/models'\nimport type { RunResult, TaskExecutionContext } from '../core/runner'\nimport type { InferenceExecutor, ScheduledTask } from '../core/runner/schedule'\nimport type { VievalVitestCompatReporterReference } from './reporters/vitest-compat-reporter'\n\nimport process from 'node:process'\n\nimport { access, readFile } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { dirname, extname, isAbsolute, join, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\n\nimport { errorMessageFrom } from '@moeru/std'\nimport { createDefineConfig, loadConfig } from 'c12'\nimport { loadEnv as loadViteEnv } from 'vite'\n\nconst matrixLayerKeys = new Set(['disable', 'extend', 'override'])\nconst ambiguousMatrixDefinitionErrorMessage = 'Ambiguous matrix definition: cannot mix reserved layer keys (disable, extend, override) with matrix axis keys.'\nconst require = createRequire(import.meta.url)\n\n/**\n * CLI plugin shape bound to the full CLI config object.\n */\nexport type CliConfigPlugin = ConfigHookPlugin<CliConfig>\n\n/**\n * Defines one project block for `vieval run`.\n */\nexport interface CliProjectConfig {\n /**\n * Project label used in summary output.\n */\n name: string\n /**\n * Project root used for include/exclude glob matching.\n *\n * @default process cwd\n */\n root?: string\n /**\n * Glob patterns for eval file discovery.\n *\n * @default Common eval file globs for TypeScript and JavaScript module formats.\n */\n include?: string[]\n /**\n * Glob patterns excluded from discovery.\n *\n * @default Common exclusion globs for dependencies, build output, and VCS directories.\n */\n exclude?: string[]\n /**\n * Providers expanded by scheduler.\n *\n * @default [{ id: 'default' }]\n */\n inferenceExecutors?: InferenceExecutor[]\n /**\n * Model definitions available to project runtime execution.\n *\n * Inference executors control schedule fan-out, while models provide\n * runtime lookup metadata for `context.model(...)` during task execution.\n *\n * @default inherited from top-level config models\n */\n models?: ModelDefinition[]\n /**\n * Optional run-time matrix dimensions.\n */\n runMatrix?: MatrixDefinition | MatrixLayer\n /**\n * Optional eval-time matrix dimensions.\n */\n evalMatrix?: MatrixDefinition | MatrixLayer\n /**\n * Optional task executor.\n *\n * Use when this project should execute live inferenceExecutor requests.\n * If omitted, `vieval run` performs collection + scheduling only.\n */\n executor?: (task: ScheduledTask, context: CliProjectExecutorContext) => Promise<RunResult>\n /**\n * Optional project-local plugins.\n */\n plugins?: CliConfigPlugin[]\n /**\n * Optional vitest-compatible reporter modules.\n *\n * Use when:\n * - project runs should emit additional reporter callbacks using Vitest-style lifecycle names\n *\n * @default []\n */\n reporters?: VievalVitestCompatReporterReference[]\n}\n\n/**\n * One workspace descriptor for workspace-mode configs.\n */\nexport interface CliWorkspaceConfig {\n /**\n * Workspace identifier.\n */\n id: string\n /**\n * Workspace root path.\n */\n root: string\n}\n\n/**\n * One explicit comparison method descriptor.\n */\nexport interface CliComparisonMethodConfig {\n /**\n * Method identifier shown in compare reports.\n */\n id: string\n /**\n * Workspace path containing this method's `vieval.config.*`.\n */\n workspace: string\n /**\n * Project name to execute inside workspace config.\n */\n project: string\n /**\n * Optional explicit config file path for this workspace.\n */\n configFilePath?: string\n}\n\n/**\n * Benchmark identity and shared cache namespace.\n */\nexport interface CliComparisonBenchmarkConfig {\n /**\n * Benchmark identifier used in report artifacts.\n */\n id: string\n /**\n * Shared cache namespace reused across method runs.\n */\n sharedCaseNamespace: string\n}\n\n/**\n * One comparison entry loaded by `vieval compare`.\n */\nexport interface CliComparisonConfig {\n /**\n * Comparison id selected by `--comparison`.\n */\n id: string\n /**\n * Benchmark metadata for reporting and shared cache coordination.\n */\n benchmark: CliComparisonBenchmarkConfig\n /**\n * Optional explicit method list.\n */\n methods?: CliComparisonMethodConfig[]\n /**\n * Optional workspace glob(s) discovered relative to config directory.\n */\n includesWorkspaces?: string | string[]\n /**\n * Optional workspace exclude glob(s), also relative to config directory.\n */\n excludesWorkspaces?: string | string[]\n}\n\n/**\n * Execution context exposed to project-level `executor` implementations.\n *\n * Use when:\n * - a project executor needs the task-scoped model resolver plus case reporter hooks\n * - custom scheduling logic wants the same hook shape as `TaskRunContext`\n *\n * Expects:\n * - `model` resolves configured models for the current task\n * - `reporterHooks` follows `TaskRunContext['reporterHooks']`\n */\nexport interface CliProjectExecutorContext extends TaskExecutionContext {\n reporterHooks?: TaskRunContext['reporterHooks']\n}\n\n/**\n * Top-level CLI config loaded from `vieval.config.*`.\n */\ninterface CliConfigBase {\n /**\n * Global model definitions inherited by projects.\n *\n * @default []\n */\n models?: ModelDefinition[]\n /**\n * Global config plugins.\n *\n * @default []\n */\n plugins?: CliConfigPlugin[]\n /**\n * Global vitest-compatible reporter modules inherited by projects.\n *\n * @default []\n */\n reporters?: VievalVitestCompatReporterReference[]\n /**\n * Environment variables injected into `process.env` during `vieval run`.\n *\n * Use when:\n * - eval tasks depend on runtime env values (for example inferenceExecutor API keys)\n * - config wants deterministic env values without shell-level exports\n *\n * @default {}\n */\n env?: NodeJS.ProcessEnv\n}\n\n/**\n * Project mode config for `vieval run`.\n */\nexport interface CliProjectModeConfig extends CliConfigBase {\n /**\n * Project list expanded by `vieval run`.\n *\n * @default [{ name: 'default' }]\n */\n projects?: CliProjectConfig[]\n comparisons?: never\n workspaces?: never\n}\n\n/**\n * Workspace mode config placeholder for future workspace orchestration.\n */\nexport interface CliWorkspaceModeConfig extends CliConfigBase {\n workspaces: CliWorkspaceConfig[]\n projects?: never\n comparisons?: never\n}\n\n/**\n * Comparison mode config for `vieval compare`.\n */\nexport interface CliComparisonModeConfig extends CliConfigBase {\n comparisons: CliComparisonConfig[]\n projects?: never\n workspaces?: never\n}\n\n/**\n * Top-level CLI config loaded from `vieval.config.*`.\n *\n * Exactly one top-level mode is allowed:\n * - `projects`\n * - `workspaces`\n * - `comparisons`\n */\nexport type CliConfig = CliProjectModeConfig | CliWorkspaceModeConfig | CliComparisonModeConfig\n\nexport type CliConfigMode = 'comparisons' | 'projects' | 'workspaces'\n\nexport interface LoadedRawCliConfig {\n config: CliConfig | null\n configFilePath: string | null\n}\n\n/**\n * Normalized CLI project used by runtime orchestration.\n */\nexport interface NormalizedCliProjectConfig {\n exclude: string[]\n executor?: (task: ScheduledTask, context: CliProjectExecutorContext) => Promise<RunResult>\n include: string[]\n runMatrix?: MatrixLayer\n evalMatrix?: MatrixLayer\n models: ModelDefinition[]\n name: string\n inferenceExecutors: InferenceExecutor[]\n root: string\n reporters: VievalVitestCompatReporterReference[]\n}\n\n/**\n * Result of loading and normalizing a config file.\n */\nexport interface LoadedCliConfig {\n configFilePath: string | null\n env: NodeJS.ProcessEnv\n projects: NormalizedCliProjectConfig[]\n}\n\n/**\n * Runtime options for config loading.\n */\nexport interface LoadVievalCliConfigOptions {\n /**\n * Starting directory for config lookup.\n *\n * @default process.cwd()\n */\n cwd?: string\n /**\n * Explicit config file path.\n */\n configFilePath?: string\n}\n\n/**\n * Helper used by `vieval.config.*` for better type inference.\n */\nexport const defineConfig = createDefineConfig<CliConfig>()\n\n/**\n * Loads `.env*` files using Vite's env resolution behavior.\n *\n * Use when:\n * - `vieval.config.*` should mirror Vitest/Vite env loading semantics\n * - config wants to populate top-level `env` via file-based values\n *\n * Expects:\n * - `mode` to match the env file suffix (`.env.<mode>`)\n * - `envDir` to point at the directory containing `.env` files\n *\n * Returns:\n * - Key/value map compatible with `CliConfig['env']`\n */\nexport function loadEnv(mode: string, envDir: string, prefixes: string | string[] = ''): NodeJS.ProcessEnv {\n return loadViteEnv(mode, envDir, prefixes)\n}\n\nasync function applyVievalPlugins(config: CliConfig): Promise<CliConfig> {\n let currentConfig: CliConfig = config\n const plugins = currentConfig.plugins ?? []\n\n for (const plugin of plugins) {\n if (plugin.configVieval == null) {\n continue\n }\n\n const nextConfig = await plugin.configVieval(currentConfig)\n if (nextConfig != null) {\n currentConfig = {\n ...currentConfig,\n ...nextConfig,\n } as CliConfig\n }\n }\n\n for (const plugin of plugins) {\n await plugin.configVievalResolved?.(currentConfig)\n }\n\n return currentConfig\n}\n\nasync function isReadableFile(filePath: string): Promise<boolean> {\n try {\n await access(filePath)\n return true\n }\n catch {\n return false\n }\n}\n\nfunction isConfigFileExtensionUsingRequire(extension: string): boolean {\n return extension === '.cjs' || extension === '.cts'\n}\n\nfunction isConfigFileExtensionUsingJsonParse(extension: string): boolean {\n return extension === '.json'\n}\n\nasync function importVievalConfigModule(filePath: string): Promise<unknown> {\n const extension = extname(filePath)\n\n if (isConfigFileExtensionUsingJsonParse(extension)) {\n const raw = await readFile(filePath, 'utf-8')\n return JSON.parse(raw) as unknown\n }\n\n if (isConfigFileExtensionUsingRequire(extension)) {\n return require(filePath) as unknown\n }\n\n return import(pathToFileURL(filePath).href)\n}\n\nfunction resolveConfigExport(moduleValue: unknown): unknown {\n if (moduleValue == null) {\n return null\n }\n\n if (typeof moduleValue !== 'object') {\n return moduleValue\n }\n\n if ('default' in moduleValue) {\n return (moduleValue as { default: unknown }).default\n }\n\n return moduleValue\n}\n\nasync function findNearestConfigFile(startDirectory: string): Promise<string | null> {\n const supportedFileNames = [\n 'vieval.config.ts',\n 'vieval.config.mts',\n 'vieval.config.cts',\n 'vieval.config.js',\n 'vieval.config.mjs',\n 'vieval.config.cjs',\n 'vieval.config.json',\n ]\n\n let currentDirectory = resolve(startDirectory)\n\n while (true) {\n for (const fileName of supportedFileNames) {\n const candidatePath = join(currentDirectory, fileName)\n if (await isReadableFile(candidatePath)) {\n return candidatePath\n }\n }\n\n const parentDirectory = dirname(currentDirectory)\n if (parentDirectory === currentDirectory) {\n return null\n }\n currentDirectory = parentDirectory\n }\n}\n\nasync function resolveVievalConfig(\n cwd: string,\n explicitConfigFilePath: string | undefined,\n): Promise<{\n config: CliConfig | null\n configFilePath: string | null\n}> {\n const resolvedConfigFilePath = explicitConfigFilePath == null\n ? await findNearestConfigFile(cwd)\n : (isAbsolute(explicitConfigFilePath) ? explicitConfigFilePath : resolve(cwd, explicitConfigFilePath))\n\n if (explicitConfigFilePath != null && resolvedConfigFilePath != null && !await isReadableFile(resolvedConfigFilePath)) {\n throw new Error(`Config file does not exist or is not readable: ${resolvedConfigFilePath}`)\n }\n\n if (resolvedConfigFilePath == null) {\n return {\n config: null,\n configFilePath: null,\n }\n }\n\n const loaded = await loadConfig<CliConfig>({\n configFile: resolvedConfigFilePath,\n cwd,\n dotenv: false,\n envName: false,\n extend: false,\n import: importVievalConfigModule,\n packageJson: false,\n rcFile: false,\n resolveModule: resolveConfigExport,\n })\n return {\n config: loaded.config,\n configFilePath: resolvedConfigFilePath,\n }\n}\n\nfunction isLayerMatrixDefinition(matrix: MatrixDefinition | MatrixLayer): matrix is MatrixLayer {\n const matrixKeys = Object.keys(matrix)\n return (\n matrixKeys.length > 0\n && matrixKeys.every(key => matrixLayerKeys.has(key))\n )\n}\n\nfunction assertNonAmbiguousMatrixDefinition(matrix: MatrixDefinition | MatrixLayer): void {\n const matrixKeys = Object.keys(matrix)\n const hasReservedKeys = matrixKeys.some(key => matrixLayerKeys.has(key))\n const hasAxisKeys = matrixKeys.some(key => !matrixLayerKeys.has(key))\n\n if (hasReservedKeys && hasAxisKeys) {\n throw new TypeError(ambiguousMatrixDefinitionErrorMessage)\n }\n}\n\nfunction normalizeMatrixLayerInput(matrix: MatrixDefinition | MatrixLayer | undefined): MatrixLayer | undefined {\n if (matrix == null) {\n return undefined\n }\n\n assertNonAmbiguousMatrixDefinition(matrix)\n\n if (isLayerMatrixDefinition(matrix)) {\n return matrix\n }\n\n return {\n extend: matrix,\n }\n}\n\nfunction normalizeProjectConfig(\n project: CliProjectConfig,\n cwd: string,\n inheritedModels: readonly ModelDefinition[],\n inheritedReporterReferences: readonly VievalVitestCompatReporterReference[],\n): NormalizedCliProjectConfig {\n const include = project.include ?? [\n '**/*.eval.ts',\n '**/*.eval.mts',\n '**/*.eval.cts',\n '**/*.eval.js',\n '**/*.eval.mjs',\n '**/*.eval.cjs',\n ]\n const exclude = project.exclude ?? [\n '**/node_modules/**',\n '**/dist/**',\n '**/.git/**',\n ]\n const models = project.models ?? [...inheritedModels]\n const inferenceExecutors = project.inferenceExecutors ?? [{ id: 'default' }]\n const root = project.root == null\n ? cwd\n : (isAbsolute(project.root) ? project.root : resolve(cwd, project.root))\n const reporters = project.reporters ?? [...inheritedReporterReferences]\n\n return {\n exclude,\n executor: project.executor,\n include,\n evalMatrix: normalizeMatrixLayerInput(project.evalMatrix),\n models,\n name: project.name,\n inferenceExecutors,\n reporters,\n runMatrix: normalizeMatrixLayerInput(project.runMatrix),\n root,\n }\n}\n\nfunction normalizeConfig(config: CliConfig | null | undefined, cwd: string): NormalizedCliProjectConfig[] {\n if (config != null) {\n const mode = detectCliConfigMode(config)\n if (mode === 'comparisons') {\n throw new Error('vieval run requires project-mode config. Received comparison-mode config.')\n }\n if (mode === 'workspaces') {\n throw new Error('vieval run requires project-mode config. Received workspace-mode config.')\n }\n }\n\n const projects = config?.projects ?? [{ name: 'default' }]\n const inheritedModels = config?.models ?? []\n const inheritedReporterReferences = config?.reporters ?? []\n\n return projects.map(project => normalizeProjectConfig(project, cwd, inheritedModels, inheritedReporterReferences))\n}\n\n/**\n * Detects which top-level config mode is active.\n *\n * Expects:\n * - exactly one of `projects`, `workspaces`, or `comparisons`\n *\n * Returns:\n * - active top-level mode key\n */\nexport function detectCliConfigMode(config: CliConfig): CliConfigMode {\n const declaredModes: CliConfigMode[] = []\n if (config.projects != null) {\n declaredModes.push('projects')\n }\n if (config.workspaces != null) {\n declaredModes.push('workspaces')\n }\n if (config.comparisons != null) {\n declaredModes.push('comparisons')\n }\n\n if (declaredModes.length > 1) {\n throw new Error(`Invalid vieval config: top-level keys are mutually exclusive. Found ${declaredModes.join(', ')}.`)\n }\n\n return declaredModes[0] ?? 'projects'\n}\n\n/**\n * Loads nearest `vieval.config.*` without project normalization.\n */\nexport async function loadRawVievalConfig(options: LoadVievalCliConfigOptions = {}): Promise<LoadedRawCliConfig> {\n const cwd = options.cwd ?? process.cwd()\n\n try {\n const loadedConfig = await resolveVievalConfig(cwd, options.configFilePath)\n if (loadedConfig.configFilePath == null || loadedConfig.config == null) {\n return {\n config: null,\n configFilePath: null,\n }\n }\n\n const config = await applyVievalPlugins(loadedConfig.config)\n detectCliConfigMode(config)\n\n return {\n config,\n configFilePath: loadedConfig.configFilePath,\n }\n }\n catch (error) {\n const errorMessage = errorMessageFrom(error) ?? 'Unknown config loading error.'\n const configFilePath = options.configFilePath == null\n ? 'vieval.config'\n : (isAbsolute(options.configFilePath) ? options.configFilePath : resolve(cwd, options.configFilePath))\n throw new Error(`Failed to load vieval config \"${configFilePath}\": ${errorMessage}`, { cause: error })\n }\n}\n\n/**\n * Loads nearest `vieval.config.*` and returns normalized project definitions.\n *\n * Call stack:\n *\n * {@link loadVievalCliConfig}\n * -> {@link resolveVievalConfig}\n * -> {@link normalizeConfig}\n * -> {@link NormalizedCliProjectConfig}[]\n *\n * Use when:\n * - CLI orchestration needs project includes/excludes similar to Vitest\n * - callers want config auto-discovery without manual imports in eval files\n */\nexport async function loadVievalCliConfig(options: LoadVievalCliConfigOptions = {}): Promise<LoadedCliConfig> {\n const cwd = options.cwd ?? process.cwd()\n try {\n const loadedConfig = await loadRawVievalConfig(options)\n if (loadedConfig.configFilePath == null || loadedConfig.config == null) {\n return {\n configFilePath: null,\n env: {},\n projects: normalizeConfig(null, cwd),\n }\n }\n\n const config = loadedConfig.config\n\n return {\n configFilePath: loadedConfig.configFilePath,\n env: config.env ?? {},\n projects: normalizeConfig(config, dirname(loadedConfig.configFilePath)),\n }\n }\n catch (error) {\n const errorMessage = errorMessageFrom(error) ?? 'Unknown config loading error.'\n const configFilePath = options.configFilePath == null\n ? 'vieval.config'\n : (isAbsolute(options.configFilePath) ? options.configFilePath : resolve(cwd, options.configFilePath))\n throw new Error(`Failed to load vieval config \"${configFilePath}\": ${errorMessage}`, { cause: error })\n }\n}\n","import type { EvalDefinition } from '../config'\n\nimport process from 'node:process'\n\ninterface EvalDefinitionRegistryStore {\n activeModuleHref: string | null\n registeredDefinitionsByModule: Map<string, EvalDefinition[]>\n}\n\nconst registryStoreSymbol = Symbol.for('vieval.dsl.registry.store')\n\nfunction getRegistryStore(): EvalDefinitionRegistryStore {\n const processWithStore = process as NodeJS.Process & {\n [registryStoreSymbol]?: EvalDefinitionRegistryStore\n }\n\n processWithStore[registryStoreSymbol] ??= {\n activeModuleHref: null,\n registeredDefinitionsByModule: new Map<string, EvalDefinition[]>(),\n }\n\n return processWithStore[registryStoreSymbol]\n}\n\n/**\n * Starts module-scoped eval registration collection.\n */\nexport function beginModuleRegistration(moduleHref: string): void {\n const store = getRegistryStore()\n store.activeModuleHref = moduleHref\n}\n\n/**\n * Ends module-scoped eval registration collection.\n */\nexport function endModuleRegistration(): void {\n const store = getRegistryStore()\n store.activeModuleHref = null\n}\n\n/**\n * Registers one eval definition against the currently active module.\n */\nexport function registerEvalDefinition(definition: EvalDefinition): void {\n const store = getRegistryStore()\n\n if (store.activeModuleHref == null) {\n return\n }\n\n const existing = store.registeredDefinitionsByModule.get(store.activeModuleHref) ?? []\n existing.push(definition)\n store.registeredDefinitionsByModule.set(store.activeModuleHref, existing)\n}\n\n/**\n * Consumes registered definitions for one module and clears stored state.\n */\nexport function consumeModuleRegistrations(moduleHref: string): EvalDefinition[] {\n const store = getRegistryStore()\n const definitions = store.registeredDefinitionsByModule.get(moduleHref) ?? []\n store.registeredDefinitionsByModule.delete(moduleHref)\n return definitions\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,125 @@
|
|
|
1
|
-
import { t as resolveModelByName } from "./models-
|
|
1
|
+
import { t as resolveModelByName } from "./models-DIGdOUpJ.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import { access, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
5
|
+
import { basename, dirname, join, relative } from "node:path";
|
|
4
6
|
import { fileURLToPath } from "node:url";
|
|
5
7
|
import { errorMessageFrom } from "@moeru/std";
|
|
8
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
9
|
+
import { Buffer } from "node:buffer";
|
|
10
|
+
import { limitConcurrency } from "@vitest/runner/utils";
|
|
11
|
+
//#region src/core/cache/filesystem.ts
|
|
12
|
+
function sanitizePathSegment(value) {
|
|
13
|
+
const normalized = value.trim();
|
|
14
|
+
if (normalized.length === 0) return "default";
|
|
15
|
+
return normalized.replace(/[^\w.-]+/g, "-");
|
|
16
|
+
}
|
|
17
|
+
function normalizeExtension(extension, mediaType) {
|
|
18
|
+
if (extension != null && extension.length > 0) return extension.startsWith(".") ? extension.slice(1) : extension;
|
|
19
|
+
if (mediaType == null || mediaType.length === 0) return;
|
|
20
|
+
if (mediaType === "application/json") return "json";
|
|
21
|
+
if (mediaType === "text/plain") return "txt";
|
|
22
|
+
if (mediaType === "audio/wav") return "wav";
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Normalizes cache file options into deterministic relative path segments.
|
|
26
|
+
*
|
|
27
|
+
* Before:
|
|
28
|
+
* - `{ key: ['cases', 'dataset hash', 'v1'], ext: 'json' }`
|
|
29
|
+
*
|
|
30
|
+
* After:
|
|
31
|
+
* - `['cases', 'dataset-hash', 'v1.json']`
|
|
32
|
+
*/
|
|
33
|
+
function normalizeCacheFilePathSegments(options) {
|
|
34
|
+
const sanitizedKey = options.key.map((segment) => sanitizePathSegment(segment));
|
|
35
|
+
const extension = normalizeExtension(options.ext, options.mediaType);
|
|
36
|
+
if (sanitizedKey.length === 0) return extension == null ? ["artifact"] : [`artifact.${extension}`];
|
|
37
|
+
if (extension == null) return sanitizedKey;
|
|
38
|
+
const withoutTail = sanitizedKey.slice(0, Math.max(0, sanitizedKey.length - 1));
|
|
39
|
+
const tail = sanitizedKey[sanitizedKey.length - 1] ?? "artifact";
|
|
40
|
+
return [...withoutTail, `${tail}.${extension}`];
|
|
41
|
+
}
|
|
42
|
+
async function writeAtomically(path, content) {
|
|
43
|
+
const directory = dirname(path);
|
|
44
|
+
const temporaryPath = `${path}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
45
|
+
await mkdir(directory, { recursive: true });
|
|
46
|
+
await writeFile(temporaryPath, content);
|
|
47
|
+
await rename(temporaryPath, path);
|
|
48
|
+
}
|
|
49
|
+
function createCacheFileHandle(path) {
|
|
50
|
+
return {
|
|
51
|
+
path,
|
|
52
|
+
async exists() {
|
|
53
|
+
try {
|
|
54
|
+
await access(path);
|
|
55
|
+
return true;
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
openReadStream() {
|
|
61
|
+
return createReadStream(path);
|
|
62
|
+
},
|
|
63
|
+
async openWriteStream() {
|
|
64
|
+
await mkdir(dirname(path), { recursive: true });
|
|
65
|
+
return createWriteStream(path);
|
|
66
|
+
},
|
|
67
|
+
async readBuffer() {
|
|
68
|
+
return await readFile(path);
|
|
69
|
+
},
|
|
70
|
+
async writeBuffer(value) {
|
|
71
|
+
await writeAtomically(path, value);
|
|
72
|
+
},
|
|
73
|
+
async readText(encoding = "utf-8") {
|
|
74
|
+
return await readFile(path, encoding);
|
|
75
|
+
},
|
|
76
|
+
async writeText(value, encoding = "utf-8") {
|
|
77
|
+
await writeAtomically(path, Buffer.from(value, encoding));
|
|
78
|
+
},
|
|
79
|
+
async readJson() {
|
|
80
|
+
return JSON.parse(await readFile(path, "utf-8"));
|
|
81
|
+
},
|
|
82
|
+
async writeJson(value) {
|
|
83
|
+
await writeAtomically(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
84
|
+
},
|
|
85
|
+
async loadAsCasesInput() {
|
|
86
|
+
return await this.readJson();
|
|
87
|
+
},
|
|
88
|
+
async loadAsExpectFixture() {
|
|
89
|
+
return await this.readJson();
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function createCacheNamespace(baseDirectory, namespace) {
|
|
94
|
+
return { file(options) {
|
|
95
|
+
const relativePathSegments = normalizeCacheFilePathSegments(options);
|
|
96
|
+
return createCacheFileHandle(join(baseDirectory, sanitizePathSegment(namespace), ...relativePathSegments));
|
|
97
|
+
} };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Creates a deterministic filesystem-backed task cache runtime.
|
|
101
|
+
*
|
|
102
|
+
* Use when:
|
|
103
|
+
* - eval tasks need reproducible cache paths for expensive pre-processing outputs
|
|
104
|
+
* - benchmark adapters need one artifact-oriented API for text/json/binary reads and writes
|
|
105
|
+
*
|
|
106
|
+
* Expects:
|
|
107
|
+
* - `cacheRootDirectory` to be writable by the running process
|
|
108
|
+
* - `workspaceId` + `projectName` to stay stable for reproducible paths
|
|
109
|
+
*
|
|
110
|
+
* Returns:
|
|
111
|
+
* - task cache runtime that resolves namespaced file handles under:
|
|
112
|
+
* `<cacheRootDirectory>/<workspaceId>/<projectName>/<namespace>/...`
|
|
113
|
+
*/
|
|
114
|
+
function createFilesystemTaskCacheRuntime(options) {
|
|
115
|
+
const workspaceDirectory = sanitizePathSegment(options.workspaceId);
|
|
116
|
+
const projectDirectory = sanitizePathSegment(options.projectName);
|
|
117
|
+
const baseDirectory = join(options.cacheRootDirectory, workspaceDirectory, projectDirectory);
|
|
118
|
+
return { namespace(name) {
|
|
119
|
+
return createCacheNamespace(baseDirectory, name);
|
|
120
|
+
} };
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
6
123
|
//#region src/core/runner/aggregate.ts
|
|
7
124
|
function cloneScheduledTaskMatrix(matrix) {
|
|
8
125
|
return {
|
|
@@ -187,11 +304,19 @@ function collectEvalEntries(modules, context) {
|
|
|
187
304
|
//#endregion
|
|
188
305
|
//#region src/core/runner/run.ts
|
|
189
306
|
function createDefaultExecutionContext(task) {
|
|
190
|
-
return {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
307
|
+
return {
|
|
308
|
+
cache: { namespace(name) {
|
|
309
|
+
return { file(options) {
|
|
310
|
+
const key = options.key.join("/");
|
|
311
|
+
throw new Error(`Task cache runtime is not configured. Requested namespace "${name}" and key "${key}".`);
|
|
312
|
+
} };
|
|
313
|
+
} },
|
|
314
|
+
model(options) {
|
|
315
|
+
const requestedModelName = typeof options === "string" ? options : options?.name;
|
|
316
|
+
if (requestedModelName != null) throw new Error(`No model registry configured. Requested model: ${requestedModelName}`);
|
|
317
|
+
throw new Error(`No model registry configured for task inferenceExecutor id "${task.inferenceExecutor.id}".`);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
195
320
|
}
|
|
196
321
|
/**
|
|
197
322
|
* Error thrown when a scheduled run fails before producing a normalized result.
|
|
@@ -237,8 +362,7 @@ function createRunnerExecutionError(taskId, cause) {
|
|
|
237
362
|
*/
|
|
238
363
|
async function runScheduledTasks(tasks, executor, options = {}) {
|
|
239
364
|
if (tasks.length === 0) return aggregateRunResults([]);
|
|
240
|
-
|
|
241
|
-
for (const task of tasks) {
|
|
365
|
+
async function executeScheduledTask(task) {
|
|
242
366
|
let executionContext;
|
|
243
367
|
try {
|
|
244
368
|
executionContext = options.createExecutionContext?.(task) ?? createDefaultExecutionContext(task);
|
|
@@ -250,8 +374,9 @@ async function runScheduledTasks(tasks, executor, options = {}) {
|
|
|
250
374
|
} catch (error) {
|
|
251
375
|
throw createRunnerExecutionError(task.id, error);
|
|
252
376
|
}
|
|
377
|
+
let runResult;
|
|
253
378
|
try {
|
|
254
|
-
|
|
379
|
+
runResult = await executor(task, executionContext);
|
|
255
380
|
} catch (error) {
|
|
256
381
|
try {
|
|
257
382
|
options.onTaskEnd?.(task, "failed");
|
|
@@ -263,8 +388,21 @@ async function runScheduledTasks(tasks, executor, options = {}) {
|
|
|
263
388
|
} catch (error) {
|
|
264
389
|
throw createRunnerExecutionError(task.id, error);
|
|
265
390
|
}
|
|
391
|
+
return runResult;
|
|
266
392
|
}
|
|
267
|
-
|
|
393
|
+
const maxConcurrency = options.maxConcurrency ?? 1;
|
|
394
|
+
if (maxConcurrency <= 1) {
|
|
395
|
+
const results = [];
|
|
396
|
+
for (const task of tasks) results.push(await executeScheduledTask(task));
|
|
397
|
+
return aggregateRunResults(results);
|
|
398
|
+
}
|
|
399
|
+
const runWithLimit = limitConcurrency(maxConcurrency);
|
|
400
|
+
return aggregateRunResults((await Promise.all(tasks.map(async (task, index) => {
|
|
401
|
+
return {
|
|
402
|
+
index,
|
|
403
|
+
result: await runWithLimit(async () => executeScheduledTask(task))
|
|
404
|
+
};
|
|
405
|
+
}))).sort((left, right) => left.index - right.index).map((item) => item.result));
|
|
268
406
|
}
|
|
269
407
|
//#endregion
|
|
270
408
|
//#region src/core/runner/runtime-context.ts
|
|
@@ -440,6 +578,14 @@ function createRunnerSchedule(options) {
|
|
|
440
578
|
}
|
|
441
579
|
//#endregion
|
|
442
580
|
//#region src/core/runner/task-context.ts
|
|
581
|
+
function createNoopTaskCacheRuntime() {
|
|
582
|
+
return { namespace(name) {
|
|
583
|
+
return { file(options) {
|
|
584
|
+
const key = options.key.join("/");
|
|
585
|
+
throw new Error(`Task cache runtime is not configured. Requested namespace "${name}" and key "${key}".`);
|
|
586
|
+
} };
|
|
587
|
+
} };
|
|
588
|
+
}
|
|
443
589
|
function resolveDefaultTaskModel(models, task) {
|
|
444
590
|
const runMatrixModelName = task.matrix.run.model;
|
|
445
591
|
if (runMatrixModelName != null) {
|
|
@@ -449,7 +595,14 @@ function resolveDefaultTaskModel(models, task) {
|
|
|
449
595
|
}
|
|
450
596
|
const matched = resolveModelByName(models, task.inferenceExecutor.id);
|
|
451
597
|
if (matched != null) return matched;
|
|
452
|
-
if (models.length >
|
|
598
|
+
if (models.length > 1) throw new Error([
|
|
599
|
+
`Multiple configured models are available, but no default model is selected for inferenceExecutor "${task.inferenceExecutor.id}".`,
|
|
600
|
+
"Select one model explicitly by either:",
|
|
601
|
+
"- setting runMatrix.override.model (or task matrix run.model)",
|
|
602
|
+
"- setting project.inferenceExecutors to a matching model id",
|
|
603
|
+
"- calling context.model({ name: \"your-model-id-or-alias\" })"
|
|
604
|
+
].join("\n"));
|
|
605
|
+
if (models.length === 1) {
|
|
453
606
|
const firstModel = models[0];
|
|
454
607
|
if (firstModel != null) return firstModel;
|
|
455
608
|
}
|
|
@@ -466,15 +619,18 @@ function resolveDefaultTaskModel(models, task) {
|
|
|
466
619
|
* -> `task.model()` / `task.model({ name })`
|
|
467
620
|
*/
|
|
468
621
|
function createTaskExecutionContext(options) {
|
|
469
|
-
return {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
622
|
+
return {
|
|
623
|
+
cache: options.cache ?? createNoopTaskCacheRuntime(),
|
|
624
|
+
model(selection) {
|
|
625
|
+
if (selection == null) return resolveDefaultTaskModel(options.models, options.task);
|
|
626
|
+
const name = typeof selection === "string" ? selection : selection.name;
|
|
627
|
+
const namedModel = resolveModelByName(options.models, name);
|
|
628
|
+
if (namedModel == null) throw new Error(`Unknown configured model "${name}".`);
|
|
629
|
+
return namedModel;
|
|
630
|
+
}
|
|
631
|
+
};
|
|
476
632
|
}
|
|
477
633
|
//#endregion
|
|
478
|
-
export { runScheduledTasks as a, aggregateRunResults as c, RunnerExecutionError as i, createRunnerSchedule as n, asProjectRelativePath as o, createRunnerRuntimeContext as r, collectEvalEntries as s, createTaskExecutionContext as t };
|
|
634
|
+
export { runScheduledTasks as a, aggregateRunResults as c, RunnerExecutionError as i, createFilesystemTaskCacheRuntime as l, createRunnerSchedule as n, asProjectRelativePath as o, createRunnerRuntimeContext as r, collectEvalEntries as s, createTaskExecutionContext as t, normalizeCacheFilePathSegments as u };
|
|
479
635
|
|
|
480
|
-
//# sourceMappingURL=runner-
|
|
636
|
+
//# sourceMappingURL=runner-Dpy-eivM.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-Dpy-eivM.mjs","names":[],"sources":["../src/core/cache/filesystem.ts","../src/core/runner/aggregate.ts","../src/core/runner/collect.ts","../src/core/runner/run.ts","../src/core/runner/runtime-context.ts","../src/core/runner/schedule.ts","../src/core/runner/task-context.ts"],"sourcesContent":["import type { CacheFileHandle, CacheFileOptions, CacheNamespace, TaskCacheRuntime } from './types'\n\nimport process from 'node:process'\n\nimport { Buffer } from 'node:buffer'\nimport { createReadStream, createWriteStream } from 'node:fs'\nimport { access, mkdir, readFile, rename, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\n\n/**\n * Options for creating the filesystem-backed task cache runtime.\n */\nexport interface CreateFilesystemTaskCacheRuntimeOptions {\n /**\n * Absolute cache root directory.\n */\n cacheRootDirectory: string\n /**\n * Project identifier under one workspace cache scope.\n */\n projectName: string\n /**\n * Workspace identifier used to share cache roots across projects.\n */\n workspaceId: string\n}\n\nfunction sanitizePathSegment(value: string): string {\n const normalized = value.trim()\n if (normalized.length === 0) {\n return 'default'\n }\n\n return normalized.replace(/[^\\w.-]+/g, '-')\n}\n\nfunction normalizeExtension(extension: string | undefined, mediaType: string | undefined): string | undefined {\n if (extension != null && extension.length > 0) {\n return extension.startsWith('.') ? extension.slice(1) : extension\n }\n\n if (mediaType == null || mediaType.length === 0) {\n return undefined\n }\n\n if (mediaType === 'application/json') {\n return 'json'\n }\n\n if (mediaType === 'text/plain') {\n return 'txt'\n }\n\n if (mediaType === 'audio/wav') {\n return 'wav'\n }\n\n return undefined\n}\n\n/**\n * Normalizes cache file options into deterministic relative path segments.\n *\n * Before:\n * - `{ key: ['cases', 'dataset hash', 'v1'], ext: 'json' }`\n *\n * After:\n * - `['cases', 'dataset-hash', 'v1.json']`\n */\nexport function normalizeCacheFilePathSegments(options: CacheFileOptions): string[] {\n const sanitizedKey = options.key.map(segment => sanitizePathSegment(segment))\n const extension = normalizeExtension(options.ext, options.mediaType)\n\n if (sanitizedKey.length === 0) {\n return extension == null ? ['artifact'] : [`artifact.${extension}`]\n }\n\n if (extension == null) {\n return sanitizedKey\n }\n\n const withoutTail = sanitizedKey.slice(0, Math.max(0, sanitizedKey.length - 1))\n const tail = sanitizedKey[sanitizedKey.length - 1] ?? 'artifact'\n return [...withoutTail, `${tail}.${extension}`]\n}\n\nasync function writeAtomically(path: string, content: Buffer | string): Promise<void> {\n const directory = dirname(path)\n const temporaryPath = `${path}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`\n await mkdir(directory, { recursive: true })\n await writeFile(temporaryPath, content)\n await rename(temporaryPath, path)\n}\n\nfunction createCacheFileHandle(path: string): CacheFileHandle {\n return {\n path,\n async exists() {\n try {\n await access(path)\n return true\n }\n catch {\n return false\n }\n },\n openReadStream() {\n return createReadStream(path)\n },\n async openWriteStream() {\n await mkdir(dirname(path), { recursive: true })\n return createWriteStream(path)\n },\n async readBuffer() {\n return await readFile(path)\n },\n async writeBuffer(value) {\n await writeAtomically(path, value)\n },\n async readText(encoding = 'utf-8') {\n return await readFile(path, encoding)\n },\n async writeText(value, encoding = 'utf-8') {\n await writeAtomically(path, Buffer.from(value, encoding))\n },\n async readJson<T>() {\n return JSON.parse(await readFile(path, 'utf-8')) as T\n },\n async writeJson(value) {\n await writeAtomically(path, `${JSON.stringify(value, null, 2)}\\n`)\n },\n async loadAsCasesInput<T>() {\n return await this.readJson<T[]>()\n },\n async loadAsExpectFixture<T>() {\n return await this.readJson<T>()\n },\n }\n}\n\nfunction createCacheNamespace(baseDirectory: string, namespace: string): CacheNamespace {\n return {\n file(options) {\n const relativePathSegments = normalizeCacheFilePathSegments(options)\n return createCacheFileHandle(join(baseDirectory, sanitizePathSegment(namespace), ...relativePathSegments))\n },\n }\n}\n\n/**\n * Creates a deterministic filesystem-backed task cache runtime.\n *\n * Use when:\n * - eval tasks need reproducible cache paths for expensive pre-processing outputs\n * - benchmark adapters need one artifact-oriented API for text/json/binary reads and writes\n *\n * Expects:\n * - `cacheRootDirectory` to be writable by the running process\n * - `workspaceId` + `projectName` to stay stable for reproducible paths\n *\n * Returns:\n * - task cache runtime that resolves namespaced file handles under:\n * `<cacheRootDirectory>/<workspaceId>/<projectName>/<namespace>/...`\n */\nexport function createFilesystemTaskCacheRuntime(\n options: CreateFilesystemTaskCacheRuntimeOptions,\n): TaskCacheRuntime {\n const workspaceDirectory = sanitizePathSegment(options.workspaceId)\n const projectDirectory = sanitizePathSegment(options.projectName)\n const baseDirectory = join(options.cacheRootDirectory, workspaceDirectory, projectDirectory)\n\n return {\n namespace(name) {\n return createCacheNamespace(baseDirectory, name)\n },\n }\n}\n","import type { ScheduledTaskMatrix } from './schedule'\n\n/**\n * Identifies the scoring family for a single eval score.\n */\nexport type RunScoreKind = 'exact' | 'judge'\n\n/**\n * Represents one normalized score emitted by a completed eval run.\n */\nexport interface RunScore {\n /**\n * Score family used for aggregation.\n */\n kind: RunScoreKind\n /**\n * Normalized score in the `0..1` range.\n */\n score: number\n}\n\n/**\n * Captures the output of one scheduled runner task.\n */\nexport interface RunResult {\n /**\n * Stable run id, usually copied from the scheduled task id.\n */\n id: string\n /**\n * Collected eval entry id.\n */\n entryId: string\n /**\n * Stable inferenceExecutor id.\n */\n inferenceExecutorId: string\n /**\n * Concrete matrix selection used by the run.\n */\n matrix: ScheduledTaskMatrix\n /**\n * Raw scores emitted by the eval.\n */\n scores: readonly RunScore[]\n}\n\n/**\n * Stores the per-run score averages after normalization.\n */\nexport interface AggregatedRunSummary {\n /**\n * Stable run id.\n */\n id: string\n /**\n * Collected eval entry id.\n */\n entryId: string\n /**\n * Stable inferenceExecutor id.\n */\n inferenceExecutorId: string\n /**\n * Concrete matrix selection used by the run.\n */\n matrix: ScheduledTaskMatrix\n /**\n * Mean of exact-match scores or `null` when absent.\n */\n exactAverage: number | null\n /**\n * Mean of judge-based scores or `null` when absent.\n */\n judgeAverage: number | null\n /**\n * Hybrid average. Uses both families when present, otherwise falls back to the\n * single available family.\n */\n hybridAverage: number | null\n}\n\n/**\n * Stores inferenceExecutor-level score aggregates across multiple runs.\n */\nexport interface AggregatedProviderSummary {\n /**\n * Stable inferenceExecutor id.\n */\n inferenceExecutorId: string\n /**\n * Number of runs included in this inferenceExecutor bucket.\n */\n runCount: number\n /**\n * Mean of all exact-match scores or `null` when absent.\n */\n exactAverage: number | null\n /**\n * Mean of all judge-based scores or `null` when absent.\n */\n judgeAverage: number | null\n /**\n * Hybrid average derived from the inferenceExecutor exact and judge means.\n */\n hybridAverage: number | null\n}\n\n/**\n * Stores the final aggregation output for a batch of runner results.\n */\nexport interface AggregatedRunResults {\n /**\n * Per-run normalized score summaries.\n */\n runs: AggregatedRunSummary[]\n /**\n * Provider-level summaries sorted by inferenceExecutor id.\n */\n inferenceExecutors: AggregatedProviderSummary[]\n /**\n * Overall summary across every run.\n */\n overall: {\n exactAverage: number | null\n judgeAverage: number | null\n hybridAverage: number | null\n runCount: number\n }\n}\n\ninterface ScoreBuckets {\n exact: number[]\n judge: number[]\n}\n\nfunction cloneScheduledTaskMatrix(matrix: ScheduledTaskMatrix): ScheduledTaskMatrix {\n return {\n eval: {\n ...matrix.eval,\n },\n meta: {\n ...matrix.meta,\n },\n run: {\n ...matrix.run,\n },\n }\n}\n\nfunction assertKnownScoreKind(kind: string): RunScoreKind {\n if (kind === 'exact' || kind === 'judge') {\n return kind\n }\n\n throw new TypeError(`Unknown eval score kind \"${kind}\".`)\n}\n\nfunction average(scores: readonly number[]): number | null {\n if (scores.length === 0) {\n return null\n }\n\n const total = scores.reduce((sum, score) => sum + score, 0)\n return total / scores.length\n}\n\nfunction createHybridAverage(exactAverage: number | null, judgeAverage: number | null): number | null {\n if (exactAverage != null && judgeAverage != null) {\n return (exactAverage + judgeAverage) / 2\n }\n\n if (exactAverage != null) {\n return exactAverage\n }\n\n if (judgeAverage != null) {\n return judgeAverage\n }\n\n return null\n}\n\nfunction collectScoreBuckets(scores: readonly RunScore[]): ScoreBuckets {\n const buckets: ScoreBuckets = {\n exact: [],\n judge: [],\n }\n\n for (const score of scores) {\n const kind = assertKnownScoreKind(score.kind)\n\n if (kind === 'exact') {\n buckets.exact.push(score.score)\n continue\n }\n\n buckets.judge.push(score.score)\n }\n\n return buckets\n}\n\nfunction createRunSummary(result: RunResult): AggregatedRunSummary {\n const buckets = collectScoreBuckets(result.scores)\n const exactAverage = average(buckets.exact)\n const judgeAverage = average(buckets.judge)\n\n return {\n entryId: result.entryId,\n exactAverage,\n hybridAverage: createHybridAverage(exactAverage, judgeAverage),\n id: result.id,\n judgeAverage,\n matrix: cloneScheduledTaskMatrix(result.matrix),\n inferenceExecutorId: result.inferenceExecutorId,\n }\n}\n\nfunction createProviderSummary(inferenceExecutorId: string, results: readonly RunResult[]): AggregatedProviderSummary {\n const exactScores: number[] = []\n const judgeScores: number[] = []\n\n for (const result of results) {\n const buckets = collectScoreBuckets(result.scores)\n exactScores.push(...buckets.exact)\n judgeScores.push(...buckets.judge)\n }\n\n const exactAverage = average(exactScores)\n const judgeAverage = average(judgeScores)\n\n return {\n exactAverage,\n hybridAverage: createHybridAverage(exactAverage, judgeAverage),\n judgeAverage,\n inferenceExecutorId,\n runCount: results.length,\n }\n}\n\n/**\n * Aggregates exact-match and judge-based scores into hybrid runner summaries.\n *\n * Call stack:\n *\n * {@link runScheduledTasks}\n * -> {@link aggregateRunResults}\n * -> {@link createRunSummary}\n * -> {@link createProviderSummary}\n * -> `report output`\n *\n * Use when:\n * - a runner batch mixes deterministic exact checks with judge-based grading\n * - inferenceExecutor comparison should preserve both score families and one hybrid view\n *\n * Expects:\n * - each score to be normalized to the `0..1` range before aggregation\n * - `scores.kind` to use only `'exact'` or `'judge'`\n */\nexport function aggregateRunResults(results: readonly RunResult[]): AggregatedRunResults {\n const runs = results.map(createRunSummary)\n\n const inferenceExecutorIds = Array.from(new Set(results.map(result => result.inferenceExecutorId)))\n const inferenceExecutors = inferenceExecutorIds\n .map((inferenceExecutorId) => {\n const providerResults = results.filter(result => result.inferenceExecutorId === inferenceExecutorId)\n return createProviderSummary(inferenceExecutorId, providerResults)\n })\n .sort((left, right) => left.inferenceExecutorId.localeCompare(right.inferenceExecutorId))\n\n const overall = createProviderSummary(\n 'overall',\n results,\n )\n\n return {\n overall: {\n exactAverage: overall.exactAverage,\n hybridAverage: overall.hybridAverage,\n judgeAverage: overall.judgeAverage,\n runCount: overall.runCount,\n },\n inferenceExecutors,\n runs,\n }\n}\n","import type { CollectedEvalEntry, EvalModule, EvalModuleMap } from '../../config'\nimport type { RunnerRuntimeContext } from './runtime-context'\n\nimport { basename, dirname, relative } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst evalFileSuffix = '.eval.ts'\nconst absolutePathPattern = /^(?:[A-Z]:\\/|\\/|\\\\\\\\)/i\n\nfunction normalizePath(value: string): string {\n return value.replaceAll('\\\\', '/')\n}\n\n/**\n * Converts a file path into a project-relative path when possible.\n *\n * Before: `/repo/plugins/airi-plugin-game-chess/src/agent/evals/chess-commentary.eval.ts`\n * After: `plugins/airi-plugin-game-chess/src/agent/evals/chess-commentary.eval.ts`\n *\n * Before: `D:/repo/plugins/airi-plugin-game-chess/src/agent/evals/chess-commentary.eval.ts`\n * After: `D:/repo/plugins/airi-plugin-game-chess/src/agent/evals/chess-commentary.eval.ts`\n */\nexport function asProjectRelativePath(filePath: string, context: RunnerRuntimeContext): string {\n const normalizedFilePath = normalizePath(filePath)\n const normalizedProjectRootDirectory = normalizePath(context.projectRootDirectory)\n const filePathWindowsDrive = normalizedFilePath.match(/^[A-Z]:\\//i)?.[0]\n const projectRootWindowsDrive = normalizedProjectRootDirectory.match(/^[A-Z]:\\//i)?.[0]\n\n if (filePathWindowsDrive != null && projectRootWindowsDrive == null) {\n return normalizedFilePath\n }\n\n if (\n filePathWindowsDrive != null\n && projectRootWindowsDrive != null\n && filePathWindowsDrive.toLowerCase() !== projectRootWindowsDrive.toLowerCase()\n ) {\n return normalizedFilePath\n }\n\n const projectRootDirectory = context.projectRootDirectory\n const relativeFilePath = normalizePath(relative(projectRootDirectory, filePath))\n\n if (!absolutePathPattern.test(relativeFilePath)) {\n if (relativeFilePath === '..') {\n return normalizePath(filePath)\n }\n\n if (!relativeFilePath.startsWith('../')) {\n return relativeFilePath\n }\n }\n\n return normalizePath(filePath)\n}\n\nfunction resolveModuleFilePath(moduleHref: string): string | null {\n if (!moduleHref.startsWith('file:')) {\n return null\n }\n\n try {\n return fileURLToPath(moduleHref)\n }\n catch {\n return null\n }\n}\n\nfunction createCollectedEvalEntry(\n moduleHref: string,\n moduleDefinition: EvalModule,\n context: RunnerRuntimeContext,\n): CollectedEvalEntry | null {\n const filePath = resolveModuleFilePath(moduleHref)\n\n if (!filePath) {\n return null\n }\n\n const relativeFilePath = asProjectRelativePath(filePath, context)\n\n if (!relativeFilePath.endsWith(evalFileSuffix)) {\n return null\n }\n\n const entryName = basename(relativeFilePath, evalFileSuffix)\n\n if (entryName.length === 0) {\n return null\n }\n\n const relativeDirectory = dirname(relativeFilePath)\n const directory = relativeDirectory === '.' ? '' : relativeDirectory\n\n return {\n ...moduleDefinition.default,\n directory,\n filePath,\n id: directory.length === 0 ? entryName : `${directory}/${entryName}`,\n name: entryName,\n }\n}\n\n/**\n * Collects loaded vieval modules into sorted runner entries with stable ids.\n *\n * Call stack:\n *\n * `import.meta.glob(...)`\n * -> {@link collectEvalEntries}\n * -> {@link createCollectedEvalEntry}\n * -> {@link CollectedEvalEntry}[]\n *\n * Use when:\n * - the runner has already loaded candidate eval modules\n * - downstream scheduling needs stable entry ids and directory metadata\n */\nexport function collectEvalEntries(\n modules: EvalModuleMap,\n context: RunnerRuntimeContext,\n): CollectedEvalEntry[] {\n return Object.entries(modules)\n .flatMap(([moduleHref, moduleDefinition]) => {\n const entry = createCollectedEvalEntry(moduleHref, moduleDefinition, context)\n\n if (!entry) {\n return []\n }\n\n return [entry]\n })\n .sort((left, right) => left.id.localeCompare(right.id))\n}\n","import type { TaskCacheRuntime } from '../cache'\nimport type { AggregatedRunResults, RunResult } from './aggregate'\nimport type { ScheduledTask } from './schedule'\nimport type { TaskExecutionContext } from './task-context'\n\nimport { errorMessageFrom } from '@moeru/std'\nimport { limitConcurrency } from '@vitest/runner/utils'\n\nimport { aggregateRunResults } from './aggregate'\n\n/**\n * Executes one scheduled runner task and returns a normalized run result.\n *\n * Use when:\n * - a scheduler already selected the task and execution context\n * - the caller wants a typed executor contract for runner workers\n *\n * Expects:\n * - the task context to be ready for model resolution and task-scoped work\n *\n * Returns:\n * - a normalized run result with score entries ready for aggregation\n */\nexport type ScheduledTaskExecutor = (\n task: ScheduledTask,\n context: TaskExecutionContext,\n) => Promise<RunResult>\n\n/**\n * Terminal task state reported by runner lifecycle hooks.\n *\n * Use when:\n * - reporting the outcome of one scheduled task to lifecycle observers\n *\n * Expects:\n * - hooks treat the value as final for the completed task\n */\nexport type RunnerTaskState = 'passed' | 'failed'\n\n/**\n * Optional runner execution hooks used while processing scheduled tasks.\n *\n * Use when:\n * - callers want lifecycle visibility around sequential task execution\n * - task execution should remain deterministic while still observable\n *\n * Expects:\n * - hook functions are synchronous lifecycle observers\n */\nexport interface RunScheduledTasksOptions {\n /**\n * Creates per-task execution context.\n *\n * Use when:\n * - executor code needs per-task model resolution or other task-scoped data\n */\n createExecutionContext?: (task: ScheduledTask) => TaskExecutionContext\n /**\n * Runs before the executor starts handling a task.\n *\n * Use when:\n * - callers want to observe task activation before execution begins\n *\n * Expects:\n * - thrown errors abort the task before executor work starts\n */\n onTaskStart?: (task: ScheduledTask) => void\n /**\n * Runs after the executor settles for a task.\n *\n * Use when:\n * - callers want to observe successful and failed task completion\n *\n * Expects:\n * - thrown errors abort successful runs\n * - failed-task observers do not override the executor error for the task\n */\n onTaskEnd?: (task: ScheduledTask, state: RunnerTaskState) => void\n /**\n * Maximum number of tasks to execute concurrently.\n *\n * @default 1\n */\n maxConcurrency?: number\n}\n\nfunction createDefaultExecutionContext(task: ScheduledTask): TaskExecutionContext {\n const cache: TaskCacheRuntime = {\n namespace(name) {\n return {\n file(options) {\n const key = options.key.join('/')\n throw new Error(`Task cache runtime is not configured. Requested namespace \"${name}\" and key \"${key}\".`)\n },\n }\n },\n }\n\n return {\n cache,\n model(options) {\n const requestedModelName = typeof options === 'string' ? options : options?.name\n if (requestedModelName != null) {\n throw new Error(`No model registry configured. Requested model: ${requestedModelName}`)\n }\n\n throw new Error(`No model registry configured for task inferenceExecutor id \"${task.inferenceExecutor.id}\".`)\n },\n }\n}\n\n/**\n * Error thrown when a scheduled run fails before producing a normalized result.\n */\nexport class RunnerExecutionError extends Error {\n /**\n * Stable task id that failed.\n */\n taskId: string\n\n constructor(taskId: string, cause: unknown) {\n const message = errorMessageFrom(cause) ?? 'Unknown runner execution failure.'\n super(`Runner task \"${taskId}\" failed: ${message}`)\n this.name = 'RunnerExecutionError'\n this.taskId = taskId\n this.cause = cause\n }\n}\n\nfunction createRunnerExecutionError(taskId: string, cause: unknown): RunnerExecutionError {\n if (cause instanceof RunnerExecutionError && cause.taskId === taskId) {\n return cause\n }\n\n return new RunnerExecutionError(taskId, cause)\n}\n\n/**\n * Executes runner tasks sequentially and aggregates the normalized results.\n *\n * Call stack:\n *\n * {@link createRunnerSchedule}\n * -> {@link runScheduledTasks}\n * -> `executor(task)`\n * -> {@link aggregateRunResults}\n *\n * Use when:\n * - the caller already expanded the runner matrix\n * - task execution should stay deterministic and easy to debug\n *\n * Expects:\n * - `executor` to return normalized `0..1` scores\n * - callers to handle concurrency outside this helper when needed\n * - `onTaskStart` / `onTaskEnd` hooks to be synchronous lifecycle observers\n *\n * Throws:\n * - `RunnerExecutionError` when task setup, hooks, or the executor throws\n */\nexport async function runScheduledTasks(\n tasks: readonly ScheduledTask[],\n executor: ScheduledTaskExecutor,\n options: RunScheduledTasksOptions = {},\n): Promise<AggregatedRunResults> {\n if (tasks.length === 0) {\n return aggregateRunResults([])\n }\n\n async function executeScheduledTask(task: ScheduledTask): Promise<RunResult> {\n let executionContext: TaskExecutionContext\n\n try {\n executionContext = options.createExecutionContext?.(task) ?? createDefaultExecutionContext(task)\n }\n catch (error) {\n throw createRunnerExecutionError(task.id, error)\n }\n\n try {\n options.onTaskStart?.(task)\n }\n catch (error) {\n throw createRunnerExecutionError(task.id, error)\n }\n\n let runResult: RunResult\n try {\n runResult = await executor(task, executionContext)\n }\n catch (error) {\n try {\n options.onTaskEnd?.(task, 'failed')\n }\n catch {\n // Failed-task observers must not mask the task execution failure.\n }\n throw createRunnerExecutionError(task.id, error)\n }\n\n try {\n options.onTaskEnd?.(task, 'passed')\n }\n catch (error) {\n throw createRunnerExecutionError(task.id, error)\n }\n\n return runResult\n }\n\n const maxConcurrency = options.maxConcurrency ?? 1\n if (maxConcurrency <= 1) {\n const results: RunResult[] = []\n for (const task of tasks) {\n results.push(await executeScheduledTask(task))\n }\n return aggregateRunResults(results)\n }\n\n const runWithLimit = limitConcurrency(maxConcurrency)\n const resultPairs = await Promise.all(tasks.map(async (task, index) => {\n const result = await runWithLimit(async () => executeScheduledTask(task))\n return { index, result }\n }))\n\n const sortedResults = resultPairs\n .sort((left, right) => left.index - right.index)\n .map(item => item.result)\n\n return aggregateRunResults(sortedResults)\n}\n","import { createRequire } from 'node:module'\nimport { dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst require = createRequire(import.meta.url)\n\n/**\n * Shared runtime context used by the vieval runner.\n *\n * Use when:\n * - runner services need stable path resolution without module-level side effects\n * - call sites want deterministic control over workspace root detection\n */\nexport interface RunnerRuntimeContext {\n /**\n * Absolute project root directory used for path normalization.\n */\n projectRootDirectory: string\n}\n\n/**\n * Options used to construct the runner runtime context.\n */\nexport interface CreateVievalRunnerRuntimeContextOptions {\n /**\n * Directory used to search for the nearest pnpm workspace.\n *\n * @default directory of this module file\n */\n cwd?: string\n /**\n * Absolute fallback directory when a pnpm workspace root is not found.\n *\n * @default package root directory (`packages/vieval`)\n */\n fallbackProjectRootDirectory?: string\n}\n\n/**\n * Creates a side-effect-free runtime context for runner path normalization.\n *\n * Call stack:\n *\n * {@link createRunnerRuntimeContext}\n * -> `findWorkspaceDir(cwd)`\n * -> `resolve projectRootDirectory`\n * -> `{ projectRootDirectory }`\n *\n * Use when:\n * - initializing runner infrastructure before collecting eval modules\n * - tests need deterministic root resolution behavior\n */\nexport async function createRunnerRuntimeContext(\n options: CreateVievalRunnerRuntimeContextOptions = {},\n): Promise<RunnerRuntimeContext> {\n const cwd = options.cwd ?? dirname(fileURLToPath(import.meta.url))\n const fallbackProjectRootDirectory = options.fallbackProjectRootDirectory\n ?? fileURLToPath(new URL('../../../', import.meta.url))\n\n // NOTICE:\n // We use dynamic `require` here because `@pnpm/find-workspace-dir` is CommonJS.\n // Keeping this load inside the factory avoids module-level initialization side effects.\n const { findWorkspaceDir } = require('@pnpm/find-workspace-dir') as {\n findWorkspaceDir: (currentWorkingDirectory: string) => Promise<string | undefined>\n }\n\n // NOTICE:\n // Workspace discovery is required to keep collected eval ids stable when this\n // package is moved inside different monorepo layouts.\n const workspaceDirectory = await findWorkspaceDir(cwd)\n\n return {\n projectRootDirectory: workspaceDirectory ?? fallbackProjectRootDirectory,\n }\n}\n","import type { CollectedEvalEntry, MatrixDefinition, MatrixLayer, MatrixValue } from '../../config'\n\n/**\n * Describes the inferenceExecutor target for a scheduled eval run.\n */\nexport interface InferenceExecutor {\n /**\n * Stable inferenceExecutor identifier such as `openai:gpt-4.1-mini`.\n */\n id: string\n}\n\n/**\n * Stores the selected value for each matrix axis.\n */\nexport type RunnerMatrixSelection = Record<string, string>\n\n/**\n * Stores stable row ids for one resolved scheduled task matrix.\n */\nexport interface ScheduledTaskMatrixMeta {\n /**\n * Stable row id for the resolved run matrix selection.\n */\n runRowId: string\n /**\n * Stable row id for the resolved eval matrix selection.\n */\n evalRowId: string\n}\n\n/**\n * Stores the structured matrix payload for one scheduled task.\n */\nexport interface ScheduledTaskMatrix {\n /**\n * Runtime matrix selection visible to task code.\n */\n run: RunnerMatrixSelection\n /**\n * Eval-time matrix selection visible to task code.\n */\n eval: RunnerMatrixSelection\n /**\n * Stable row ids for both scopes.\n */\n meta: ScheduledTaskMatrixMeta\n}\n\n/**\n * Maps matrix axis names to the values that should be expanded.\n */\nexport type RunnerMatrixDefinition = MatrixDefinition\n\n/**\n * Accepts either flat axis definitions or one layered matrix object.\n */\nexport type RunnerMatrixInput = RunnerMatrixDefinition | MatrixLayer\n\nconst matrixLayerKeys = new Set(['disable', 'extend', 'override'])\nconst ambiguousMatrixDefinitionErrorMessage = 'Ambiguous matrix definition: cannot mix reserved layer keys (disable, extend, override) with matrix axis keys.'\n\n/**\n * Represents one fully expanded runner task.\n */\nexport interface ScheduledTask {\n /**\n * Stable task id derived from the entry, inferenceExecutor, and matrix selection.\n */\n id: string\n /**\n * The collected eval entry to execute.\n */\n entry: CollectedEvalEntry\n /**\n * The inferenceExecutor selected for this task.\n */\n inferenceExecutor: InferenceExecutor\n /**\n * The concrete scoped matrix selection for this task.\n */\n matrix: ScheduledTaskMatrix\n}\n\n/**\n * Configures how the runner should expand its execution matrix.\n */\nexport interface CreateRunnerScheduleOptions {\n /**\n * Collected eval entries that should be scheduled.\n */\n entries: readonly CollectedEvalEntry[]\n /**\n * Providers that should run each entry.\n */\n inferenceExecutors: readonly InferenceExecutor[]\n /**\n * Optional run-time matrix axes expanded as a cartesian product.\n */\n runMatrix?: RunnerMatrixInput\n /**\n * Optional eval-time matrix axes expanded as a cartesian product.\n */\n evalMatrix?: RunnerMatrixInput\n}\n\nfunction encodeTaskIdSegment(value: string): string {\n return encodeURIComponent(value)\n}\n\nfunction stringifyMatrixValue(value: MatrixValue): string {\n return String(value)\n}\n\nfunction cloneMatrixSelection(matrix: RunnerMatrixSelection): RunnerMatrixSelection {\n return { ...matrix }\n}\n\nfunction createScheduledTaskMatrix(\n runMatrix: RunnerMatrixSelection,\n evalMatrix: RunnerMatrixSelection,\n): ScheduledTaskMatrix {\n return {\n eval: cloneMatrixSelection(evalMatrix),\n meta: {\n evalRowId: createStableRowId(evalMatrix),\n runRowId: createStableRowId(runMatrix),\n },\n run: cloneMatrixSelection(runMatrix),\n }\n}\n\nfunction isMatrixLayer(matrix: RunnerMatrixInput): matrix is MatrixLayer {\n const matrixKeys = Object.keys(matrix)\n return (\n matrixKeys.length > 0\n && matrixKeys.every(key => matrixLayerKeys.has(key))\n )\n}\n\nfunction assertNonAmbiguousMatrixDefinition(matrix: RunnerMatrixInput): void {\n const matrixKeys = Object.keys(matrix)\n const hasReservedKeys = matrixKeys.some(key => matrixLayerKeys.has(key))\n const hasAxisKeys = matrixKeys.some(key => !matrixLayerKeys.has(key))\n\n if (hasReservedKeys && hasAxisKeys) {\n throw new TypeError(ambiguousMatrixDefinitionErrorMessage)\n }\n}\n\nfunction normalizeLayerInputToAxes(matrix: RunnerMatrixInput | undefined): MatrixLayer | undefined {\n if (matrix == null) {\n return undefined\n }\n\n assertNonAmbiguousMatrixDefinition(matrix)\n\n if (isMatrixLayer(matrix)) {\n return matrix\n }\n\n return {\n extend: matrix,\n }\n}\n\nfunction dedupeAxisValues(values: readonly MatrixValue[]): string[] {\n return Array.from(new Set(values.map(stringifyMatrixValue)))\n}\n\nfunction applyAxisValues(\n axes: Map<string, string[]>,\n definition: RunnerMatrixDefinition | undefined,\n mode: 'extend' | 'override',\n): void {\n if (definition == null) {\n return\n }\n\n for (const [axis, values] of Object.entries(definition)) {\n const nextValues = dedupeAxisValues(values)\n\n if (mode === 'extend') {\n const existingValues = axes.get(axis) ?? []\n axes.set(axis, Array.from(new Set([...existingValues, ...nextValues])))\n continue\n }\n\n axes.set(axis, nextValues)\n }\n}\n\nfunction applyLayer(\n baseAxes: ReadonlyMap<string, string[]>,\n layer: MatrixLayer | undefined,\n): Map<string, string[]> {\n const nextAxes = new Map<string, string[]>(\n Array.from(baseAxes.entries()).map(([axis, values]) => [axis, [...values]]),\n )\n\n for (const axis of layer?.disable ?? []) {\n nextAxes.delete(axis)\n }\n\n applyAxisValues(nextAxes, layer?.extend, 'extend')\n applyAxisValues(nextAxes, layer?.override, 'override')\n\n return nextAxes\n}\n\nfunction expandAxesToRows(axes: ReadonlyMap<string, readonly string[]>): RunnerMatrixSelection[] {\n if (axes.size === 0) {\n return [{}]\n }\n\n const dimensions = Array.from(axes.entries())\n\n let selections: RunnerMatrixSelection[] = [{}]\n\n for (const [axis, values] of dimensions) {\n if (values.length === 0) {\n return []\n }\n\n const nextSelections: RunnerMatrixSelection[] = []\n\n for (const selection of selections) {\n for (const value of values) {\n nextSelections.push({\n ...selection,\n [axis]: value,\n })\n }\n }\n\n selections = nextSelections\n }\n\n return selections\n}\n\nfunction createStableRowId(matrix: RunnerMatrixSelection): string {\n const segments = Object.entries(matrix)\n .sort(([leftAxis], [rightAxis]) => leftAxis.localeCompare(rightAxis))\n .map(([axis, value]) => `${encodeTaskIdSegment(axis)}=${encodeTaskIdSegment(value)}`)\n\n if (segments.length === 0) {\n return 'default'\n }\n\n return segments.join('&')\n}\n\nfunction createTaskId(entryId: string, inferenceExecutorId: string, runRowId: string, evalRowId: string): string {\n const encodedEntryId = encodeTaskIdSegment(entryId)\n const encodedProviderId = encodeTaskIdSegment(inferenceExecutorId)\n\n return [\n encodedEntryId,\n encodedProviderId,\n `run=${encodeTaskIdSegment(runRowId)}`,\n `eval=${encodeTaskIdSegment(evalRowId)}`,\n ].join('::')\n}\n\nfunction createResolvedRunAxes(\n entry: CollectedEvalEntry,\n runMatrix: RunnerMatrixInput | undefined,\n): Map<string, string[]> {\n let resolvedAxes = new Map<string, string[]>()\n\n for (const layerInput of [\n runMatrix,\n entry.matrix?.runMatrix,\n entry.task?.matrix?.runMatrix,\n ]) {\n resolvedAxes = applyLayer(resolvedAxes, normalizeLayerInputToAxes(layerInput))\n }\n\n return resolvedAxes\n}\n\nfunction createResolvedEvalAxes(\n entry: CollectedEvalEntry,\n evalMatrix: RunnerMatrixInput | undefined,\n): Map<string, string[]> {\n let resolvedAxes = new Map<string, string[]>()\n\n for (const layerInput of [\n evalMatrix,\n entry.matrix?.evalMatrix,\n entry.task?.matrix?.evalMatrix,\n ]) {\n resolvedAxes = applyLayer(resolvedAxes, normalizeLayerInputToAxes(layerInput))\n }\n\n return resolvedAxes\n}\n\n/**\n * Expands collected entries into a stable runner schedule.\n *\n * Call stack:\n *\n * {@link collectEvalEntries} (`../runner`)\n * -> {@link createRunnerSchedule}\n * -> {@link expandAxesToRows}\n * -> {@link ScheduledTask}[]\n *\n * Use when:\n * - the runner already knows which eval entries are available\n * - each entry must run against multiple inferenceExecutors or matrix variants\n *\n * Expects:\n * - `entries` and `inferenceExecutors` to be provided in the desired execution order\n * - matrix axes to use insertion order when generating combinations\n */\nexport function createRunnerSchedule(options: CreateRunnerScheduleOptions): ScheduledTask[] {\n if (options.entries.length === 0) {\n return []\n }\n\n if (options.inferenceExecutors.length === 0) {\n return []\n }\n\n const tasks: ScheduledTask[] = []\n\n for (const entry of options.entries) {\n const runSelections = expandAxesToRows(createResolvedRunAxes(entry, options.runMatrix))\n const evalSelections = expandAxesToRows(createResolvedEvalAxes(entry, options.evalMatrix))\n\n if (runSelections.length === 0 || evalSelections.length === 0) {\n continue\n }\n\n for (const inferenceExecutor of options.inferenceExecutors) {\n for (const runMatrix of runSelections) {\n for (const evalMatrix of evalSelections) {\n const isolatedMatrix = createScheduledTaskMatrix(runMatrix, evalMatrix)\n\n tasks.push({\n entry,\n id: createTaskId(\n entry.id,\n inferenceExecutor.id,\n isolatedMatrix.meta.runRowId,\n isolatedMatrix.meta.evalRowId,\n ),\n matrix: isolatedMatrix,\n inferenceExecutor,\n })\n }\n }\n }\n }\n\n return tasks\n}\n","import type { ModelDefinition } from '../../config/models'\nimport type { TaskCacheRuntime } from '../cache'\nimport type { ScheduledTask } from './schedule'\n\nimport { resolveModelByName } from '../../config/models'\n\n/**\n * Options for selecting a model from the execution context.\n */\nexport interface TaskModelSelectionOptions {\n /**\n * Model id or alias name.\n */\n name: string\n}\n\n/**\n * Task-scoped execution context exposed to runner executors.\n */\nexport interface TaskExecutionContext {\n /**\n * Deterministic cache runtime scoped to the current task project.\n */\n cache: TaskCacheRuntime\n /**\n * Resolves model configuration for the current task.\n *\n * Use when:\n * - no arguments are provided to use the model selected by run matrix/inferenceExecutor\n * - `name` is provided to resolve a specific model id or alias\n */\n model: (\n selection?: string | TaskModelSelectionOptions,\n ) => ModelDefinition\n}\n\n/**\n * Inputs used to build task execution context.\n */\nexport interface CreateTaskExecutionContextOptions {\n cache?: TaskCacheRuntime\n models: readonly ModelDefinition[]\n task: ScheduledTask\n}\n\nfunction createNoopTaskCacheRuntime(): TaskCacheRuntime {\n return {\n namespace(name) {\n return {\n file(options) {\n const key = options.key.join('/')\n throw new Error(`Task cache runtime is not configured. Requested namespace \"${name}\" and key \"${key}\".`)\n },\n }\n },\n }\n}\n\nfunction resolveDefaultTaskModel(\n models: readonly ModelDefinition[],\n task: ScheduledTask,\n): ModelDefinition {\n const runMatrixModelName = task.matrix.run.model\n if (runMatrixModelName != null) {\n const matrixSelectedModel = resolveModelByName(models, runMatrixModelName)\n if (matrixSelectedModel != null) {\n return matrixSelectedModel\n }\n\n throw new Error(`Unknown configured model \"${runMatrixModelName}\" from task.matrix.run.model.`)\n }\n\n const matched = resolveModelByName(models, task.inferenceExecutor.id)\n if (matched != null) {\n return matched\n }\n\n if (models.length > 1) {\n throw new Error(\n [\n `Multiple configured models are available, but no default model is selected for inferenceExecutor \"${task.inferenceExecutor.id}\".`,\n 'Select one model explicitly by either:',\n '- setting runMatrix.override.model (or task matrix run.model)',\n '- setting project.inferenceExecutors to a matching model id',\n '- calling context.model({ name: \"your-model-id-or-alias\" })',\n ].join('\\n'),\n )\n }\n\n if (models.length === 1) {\n const firstModel = models[0]\n if (firstModel != null) {\n return firstModel\n }\n }\n\n throw new Error(`No configured model found for inferenceExecutor id \"${task.inferenceExecutor.id}\".`)\n}\n\n/**\n * Creates task-scoped model resolver context for runner execution.\n *\n * Call stack:\n *\n * {@link runScheduledTasks}\n * -> {@link createTaskExecutionContext}\n * -> {@link resolveModelByName}\n * -> `task.model()` / `task.model({ name })`\n */\nexport function createTaskExecutionContext(options: CreateTaskExecutionContextOptions): TaskExecutionContext {\n return {\n cache: options.cache ?? createNoopTaskCacheRuntime(),\n model(selection) {\n if (selection == null) {\n return resolveDefaultTaskModel(options.models, options.task)\n }\n\n const name = typeof selection === 'string' ? selection : selection.name\n\n const namedModel = resolveModelByName(options.models, name)\n if (namedModel == null) {\n throw new Error(`Unknown configured model \"${name}\".`)\n }\n\n return namedModel\n },\n }\n}\n"],"mappings":"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"}
|