vieval 0.0.10 → 0.0.12

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.
Files changed (53) hide show
  1. package/README.md +31 -31
  2. package/dist/bin/vieval.mjs +1 -1
  3. package/dist/bin/vieval.mjs.map +1 -1
  4. package/dist/cli/index.d.mts +1 -1
  5. package/dist/cli/index.mjs +1 -1
  6. package/dist/{cli-DTDgaqeI.mjs → cli-uzS81IPd.mjs} +1483 -1483
  7. package/dist/cli-uzS81IPd.mjs.map +1 -0
  8. package/dist/config.d.mts +1 -1
  9. package/dist/config.mjs +1 -1
  10. package/dist/config.mjs.map +1 -1
  11. package/dist/core/assertions/index.d.mts +156 -156
  12. package/dist/core/assertions/index.mjs +82 -82
  13. package/dist/core/assertions/index.mjs.map +1 -1
  14. package/dist/core/inference-executors/index.d.mts +37 -37
  15. package/dist/core/inference-executors/index.mjs +54 -53
  16. package/dist/core/inference-executors/index.mjs.map +1 -1
  17. package/dist/core/processors/results/index.d.mts +18 -18
  18. package/dist/core/processors/results/index.mjs.map +1 -1
  19. package/dist/core/runner/index.d.mts +2 -2
  20. package/dist/core/runner/index.mjs +259 -259
  21. package/dist/core/runner/index.mjs.map +1 -1
  22. package/dist/core/scheduler/index.d.mts +1 -1
  23. package/dist/core/scheduler/index.mjs +65 -65
  24. package/dist/core/scheduler/index.mjs.map +1 -1
  25. package/dist/{env-DfWZy_n4.d.mts → env-Br6jaWGL.d.mts} +9 -9
  26. package/dist/{env-nV5rVErX.mjs → env-egxaJtNn.mjs} +8 -8
  27. package/dist/env-egxaJtNn.mjs.map +1 -0
  28. package/dist/{expect-extensions-DCSqlneN.mjs → expect-extensions-BKdEPt3h.mjs} +46 -46
  29. package/dist/expect-extensions-BKdEPt3h.mjs.map +1 -0
  30. package/dist/expect.d.mts +1 -3
  31. package/dist/expect.mjs +1 -1
  32. package/dist/expect.mjs.map +1 -1
  33. package/dist/{index-D_aMeWqO.d.mts → index-BLIlhiWT.d.mts} +565 -565
  34. package/dist/{index-Bg0atWBF.d.mts → index-CIaJClcC.d.mts} +48 -48
  35. package/dist/index.d.mts +208 -197
  36. package/dist/index.mjs +148 -148
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/{models-pBSRUZhY.mjs → models-CaCOUPZw.mjs} +1 -1
  39. package/dist/{models-pBSRUZhY.mjs.map → models-CaCOUPZw.mjs.map} +1 -1
  40. package/dist/plugins/chat-models/index.d.mts +279 -279
  41. package/dist/plugins/chat-models/index.mjs +360 -360
  42. package/dist/plugins/chat-models/index.mjs.map +1 -1
  43. package/dist/{queue-DsZQkZO_.mjs → queue-BL86z2W_.mjs} +1 -1
  44. package/dist/{queue-DsZQkZO_.mjs.map → queue-BL86z2W_.mjs.map} +1 -1
  45. package/dist/{registry-DMnwE_mY.mjs → registry-BK7k6X81.mjs} +294 -294
  46. package/dist/registry-BK7k6X81.mjs.map +1 -0
  47. package/dist/testing/expect-extensions.d.mts +27 -27
  48. package/dist/testing/expect-extensions.mjs +1 -1
  49. package/package.json +12 -12
  50. package/dist/cli-DTDgaqeI.mjs.map +0 -1
  51. package/dist/env-nV5rVErX.mjs.map +0 -1
  52. package/dist/expect-extensions-DCSqlneN.mjs.map +0 -1
  53. package/dist/registry-DMnwE_mY.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.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 models, cache, 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(): 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 models: [],\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()\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\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 * Configured model registrations available to model plugins.\n */\n models: readonly 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\n/**\n * Creates task-scoped context data for runner execution.\n *\n * Call stack:\n *\n * {@link runScheduledTasks}\n * -> {@link createTaskExecutionContext}\n * -> `TaskExecutionContext`\n */\nexport function createTaskExecutionContext(options: CreateTaskExecutionContextOptions): TaskExecutionContext {\n return {\n cache: options.cache ?? createNoopTaskCacheRuntime(),\n models: options.models,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.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\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\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\nfunction createCacheFileHandle(path: string): CacheFileHandle {\n return {\n async exists() {\n try {\n await access(path)\n return true\n }\n catch {\n return false\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 openReadStream() {\n return createReadStream(path)\n },\n async openWriteStream() {\n await mkdir(dirname(path), { recursive: true })\n return createWriteStream(path)\n },\n path,\n async readBuffer() {\n return await readFile(path)\n },\n async readJson<T>() {\n return JSON.parse(await readFile(path, 'utf-8')) as T\n },\n async readText(encoding = 'utf-8') {\n return await readFile(path, encoding)\n },\n async writeBuffer(value) {\n await writeAtomically(path, value)\n },\n async writeJson(value) {\n await writeAtomically(path, `${JSON.stringify(value, null, 2)}\\n`)\n },\n async writeText(value, encoding = 'utf-8') {\n await writeAtomically(path, Buffer.from(value, encoding))\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\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\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\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","import type { ScheduledTaskMatrix } from './schedule'\n\n/**\n * Stores inferenceExecutor-level score aggregates across multiple runs.\n */\nexport interface AggregatedProviderSummary {\n /**\n * Mean of all exact-match scores or `null` when absent.\n */\n exactAverage: null | number\n /**\n * Hybrid average derived from the inferenceExecutor exact and judge means.\n */\n hybridAverage: null | number\n /**\n * Stable inferenceExecutor id.\n */\n inferenceExecutorId: string\n /**\n * Mean of all judge-based scores or `null` when absent.\n */\n judgeAverage: null | number\n /**\n * Number of runs included in this inferenceExecutor bucket.\n */\n runCount: number\n}\n\n/**\n * Stores the final aggregation output for a batch of runner results.\n */\nexport interface AggregatedRunResults {\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: null | number\n hybridAverage: null | number\n judgeAverage: null | number\n runCount: number\n }\n /**\n * Per-run normalized score summaries.\n */\n runs: AggregatedRunSummary[]\n}\n\n/**\n * Stores the per-run score averages after normalization.\n */\nexport interface AggregatedRunSummary {\n /**\n * Collected eval entry id.\n */\n entryId: string\n /**\n * Mean of exact-match scores or `null` when absent.\n */\n exactAverage: null | number\n /**\n * Hybrid average. Uses both families when present, otherwise falls back to the\n * single available family.\n */\n hybridAverage: null | number\n /**\n * Stable run id.\n */\n id: string\n /**\n * Stable inferenceExecutor id.\n */\n inferenceExecutorId: string\n /**\n * Mean of judge-based scores or `null` when absent.\n */\n judgeAverage: null | number\n /**\n * Concrete matrix selection used by the run.\n */\n matrix: ScheduledTaskMatrix\n}\n\n/**\n * Captures the output of one scheduled runner task.\n */\nexport interface RunResult {\n /**\n * Collected eval entry id.\n */\n entryId: string\n /**\n * Stable run id, usually copied from the scheduled task id.\n */\n id: 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 * 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 * Identifies the scoring family for a single eval score.\n */\nexport type RunScoreKind = 'exact' | 'judge'\n\ninterface ScoreBuckets {\n exact: number[]\n judge: number[]\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 inferenceExecutors,\n overall: {\n exactAverage: overall.exactAverage,\n hybridAverage: overall.hybridAverage,\n judgeAverage: overall.judgeAverage,\n runCount: overall.runCount,\n },\n runs,\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[]): null | number {\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 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 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 createHybridAverage(exactAverage: null | number, judgeAverage: null | number): null | number {\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 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 inferenceExecutorId,\n judgeAverage,\n runCount: results.length,\n }\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 inferenceExecutorId: result.inferenceExecutorId,\n judgeAverage,\n matrix: cloneScheduledTaskMatrix(result.matrix),\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\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\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\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\nfunction normalizePath(value: string): string {\n return value.replaceAll('\\\\', '/')\n}\n\nfunction resolveModuleFilePath(moduleHref: string): null | string {\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","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 * 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 = 'failed' | 'passed'\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 models, cache, or other task-scoped data\n */\n createExecutionContext?: (task: ScheduledTask) => TaskExecutionContext\n /**\n * Maximum number of tasks to execute concurrently.\n *\n * @default 1\n */\n maxConcurrency?: number\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 * 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\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 * 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\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()\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\nfunction createDefaultExecutionContext(): 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 models: [],\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","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 * 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 * 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 * 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 * 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 = MatrixLayer | RunnerMatrixDefinition\n\n/**\n * Stores the selected value for each matrix axis.\n */\nexport type RunnerMatrixSelection = Record<string, string>\n\n/**\n * Stores the structured matrix payload for one scheduled task.\n */\nexport interface ScheduledTaskMatrix {\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 * Runtime matrix selection visible to task code.\n */\n run: RunnerMatrixSelection\n}\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 eval matrix selection.\n */\n evalRowId: string\n /**\n * Stable row id for the resolved run matrix selection.\n */\n runRowId: string\n}\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 * 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 * Optional eval-time matrix axes expanded as a cartesian product.\n */\n evalMatrix?: RunnerMatrixInput\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\n/**\n * Represents one fully expanded runner task.\n */\nexport interface ScheduledTask {\n /**\n * The collected eval entry to execute.\n */\n entry: CollectedEvalEntry\n /**\n * Stable task id derived from the entry, inferenceExecutor, and matrix selection.\n */\n id: string\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 * 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 inferenceExecutor,\n matrix: isolatedMatrix,\n })\n }\n }\n }\n }\n\n return tasks\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 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 cloneMatrixSelection(matrix: RunnerMatrixSelection): RunnerMatrixSelection {\n return { ...matrix }\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\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 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 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 dedupeAxisValues(values: readonly MatrixValue[]): string[] {\n return Array.from(new Set(values.map(stringifyMatrixValue)))\n}\n\nfunction encodeTaskIdSegment(value: string): string {\n return encodeURIComponent(value)\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 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 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 stringifyMatrixValue(value: MatrixValue): string {\n return String(value)\n}\n","import type { ModelDefinition } from '../../config/models'\nimport type { TaskCacheRuntime } from '../cache'\nimport type { ScheduledTask } from './schedule'\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\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 * Configured model registrations available to model plugins.\n */\n models: readonly ModelDefinition[]\n}\n\n/**\n * Creates task-scoped context data for runner execution.\n *\n * Call stack:\n *\n * {@link runScheduledTasks}\n * -> {@link createTaskExecutionContext}\n * -> `TaskExecutionContext`\n */\nexport function createTaskExecutionContext(options: CreateTaskExecutionContextOptions): TaskExecutionContext {\n return {\n cache: options.cache ?? createNoopTaskCacheRuntime(),\n models: options.models,\n }\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"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { a as SchedulerMiddleware, c as SchedulerScopeContext, i as SchedulerConcurrencyConfig, n as getActiveScopes, o as SchedulerRuntime, r as CreateSchedulerRuntimeOptions, s as SchedulerScope, t as createSchedulerRuntime } from "../../index-Bg0atWBF.mjs";
1
+ import { a as SchedulerMiddleware, c as SchedulerScopeContext, i as SchedulerConcurrencyConfig, n as getActiveScopes, o as SchedulerRuntime, r as CreateSchedulerRuntimeOptions, s as SchedulerScope, t as createSchedulerRuntime } from "../../index-CIaJClcC.mjs";
2
2
  export { CreateSchedulerRuntimeOptions, SchedulerConcurrencyConfig, SchedulerMiddleware, SchedulerRuntime, SchedulerScope, SchedulerScopeContext, createSchedulerRuntime, getActiveScopes };
@@ -1,4 +1,4 @@
1
- import { t as createSchedulerQueue } from "../../queue-DsZQkZO_.mjs";
1
+ import { t as createSchedulerQueue } from "../../queue-BL86z2W_.mjs";
2
2
  //#region src/core/scheduler/runtime.ts
3
3
  const schedulerScopeOrder = [
4
4
  "workspace",
@@ -68,22 +68,42 @@ function createRuntimeQueues(concurrency) {
68
68
  }
69
69
  return queues;
70
70
  }
71
- async function runWithQueues(scopes, context, queues, execute, index = 0) {
72
- const scope = scopes[index];
73
- if (scope === void 0) return execute();
74
- const queue = getScopeQueue(scope, context, queues);
75
- if (queue === void 0) return runWithQueues(scopes, context, queues, execute, index + 1);
76
- return queue.run(() => runWithQueues(scopes, context, queues, execute, index + 1));
71
+ async function createSchedulerExecutionResult(releaseStack, execute) {
72
+ try {
73
+ return {
74
+ outcome: {
75
+ status: "succeeded",
76
+ value: await execute()
77
+ },
78
+ releaseStack
79
+ };
80
+ } catch (error) {
81
+ return {
82
+ outcome: {
83
+ error,
84
+ status: "failed"
85
+ },
86
+ releaseStack
87
+ };
88
+ }
77
89
  }
78
- function getScopeQueue(scope, context, queues) {
79
- const queueRegistry = queues.get(scope);
80
- if (queueRegistry === void 0) return;
81
- const scopeKey = getSchedulerScopeInstanceKey(scope, context);
82
- const existingQueue = queueRegistry.instances.get(scopeKey);
83
- if (existingQueue !== void 0) return existingQueue;
84
- const queue = createSchedulerQueue(queueRegistry.concurrency);
85
- queueRegistry.instances.set(scopeKey, queue);
86
- return queue;
90
+ function createSchedulerFailureResult(releaseStack, error) {
91
+ return {
92
+ outcome: {
93
+ error,
94
+ status: "failed"
95
+ },
96
+ releaseStack
97
+ };
98
+ }
99
+ function createSchedulerShortCircuitError() {
100
+ return /* @__PURE__ */ new Error("Scheduler middleware short-circuited execution.");
101
+ }
102
+ function createSchedulerShortCircuitResult() {
103
+ return {
104
+ outcome: { status: "skipped" },
105
+ releaseStack: []
106
+ };
87
107
  }
88
108
  function getSchedulerScopeInstanceKey(scope, context) {
89
109
  const workspaceKey = `workspace:${context.workspaceId}`;
@@ -91,24 +111,22 @@ function getSchedulerScopeInstanceKey(scope, context) {
91
111
  const taskKey = `${projectKey}:task:${context.taskId ?? "(missing-task)"}`;
92
112
  const attemptKey = `${taskKey}:attempt:${context.attemptIndex ?? "(missing-attempt)"}`;
93
113
  switch (scope) {
94
- case "workspace": return workspaceKey;
95
- case "project": return projectKey;
96
- case "task": return taskKey;
97
114
  case "attempt": return attemptKey;
98
115
  case "case": return attemptKey;
116
+ case "project": return projectKey;
117
+ case "task": return taskKey;
118
+ case "workspace": return workspaceKey;
99
119
  }
100
120
  }
101
- async function runWithMiddlewareEnvelope(middleware, context, execute) {
102
- const result = await runAcquireMiddleware(middleware, context, execute, 0);
103
- try {
104
- switch (result.outcome.status) {
105
- case "succeeded": return result.outcome.value;
106
- case "failed": throw result.outcome.error;
107
- case "skipped": throw createSchedulerShortCircuitError();
108
- }
109
- } finally {
110
- await runReleaseMiddleware(result.releaseStack, context, result.releaseStack.length - 1);
111
- }
121
+ function getScopeQueue(scope, context, queues) {
122
+ const queueRegistry = queues.get(scope);
123
+ if (queueRegistry === void 0) return;
124
+ const scopeKey = getSchedulerScopeInstanceKey(scope, context);
125
+ const existingQueue = queueRegistry.instances.get(scopeKey);
126
+ if (existingQueue !== void 0) return existingQueue;
127
+ const queue = createSchedulerQueue(queueRegistry.concurrency);
128
+ queueRegistry.instances.set(scopeKey, queue);
129
+ return queue;
112
130
  }
113
131
  async function runAcquireMiddleware(middleware, context, execute, index) {
114
132
  const currentMiddleware = middleware[index];
@@ -127,8 +145,8 @@ async function runAcquireMiddleware(middleware, context, execute, index) {
127
145
  return createSchedulerFailureResult([currentMiddleware, ...nextResult.releaseStack], error);
128
146
  }
129
147
  return {
130
- releaseStack: [currentMiddleware, ...nextResult.releaseStack],
131
- outcome: nextResult.outcome
148
+ outcome: nextResult.outcome,
149
+ releaseStack: [currentMiddleware, ...nextResult.releaseStack]
132
150
  };
133
151
  }
134
152
  async function runReleaseMiddleware(releaseStack, context, index) {
@@ -142,46 +160,28 @@ async function runReleaseMiddleware(releaseStack, context, index) {
142
160
  await runReleaseMiddleware(releaseStack, context, index - 1);
143
161
  });
144
162
  }
145
- async function createSchedulerExecutionResult(releaseStack, execute) {
163
+ async function runWithMiddlewareEnvelope(middleware, context, execute) {
164
+ const result = await runAcquireMiddleware(middleware, context, execute, 0);
146
165
  try {
147
- return {
148
- releaseStack,
149
- outcome: {
150
- status: "succeeded",
151
- value: await execute()
152
- }
153
- };
154
- } catch (error) {
155
- return {
156
- releaseStack,
157
- outcome: {
158
- status: "failed",
159
- error
160
- }
161
- };
162
- }
163
- }
164
- function createSchedulerFailureResult(releaseStack, error) {
165
- return {
166
- releaseStack,
167
- outcome: {
168
- status: "failed",
169
- error
166
+ switch (result.outcome.status) {
167
+ case "succeeded": return result.outcome.value;
168
+ case "failed": throw result.outcome.error;
169
+ case "skipped": throw createSchedulerShortCircuitError();
170
170
  }
171
- };
171
+ } finally {
172
+ await runReleaseMiddleware(result.releaseStack, context, result.releaseStack.length - 1);
173
+ }
172
174
  }
173
- function createSchedulerShortCircuitResult() {
174
- return {
175
- releaseStack: [],
176
- outcome: { status: "skipped" }
177
- };
175
+ async function runWithQueues(scopes, context, queues, execute, index = 0) {
176
+ const scope = scopes[index];
177
+ if (scope === void 0) return execute();
178
+ const queue = getScopeQueue(scope, context, queues);
179
+ if (queue === void 0) return runWithQueues(scopes, context, queues, execute, index + 1);
180
+ return queue.run(() => runWithQueues(scopes, context, queues, execute, index + 1));
178
181
  }
179
182
  function validateSchedulerConcurrency(scope, concurrency) {
180
183
  if (!Number.isFinite(concurrency) || !Number.isInteger(concurrency) || concurrency <= 0) throw new Error(`Invalid scheduler concurrency for "${scope}": ${String(concurrency)}`);
181
184
  }
182
- function createSchedulerShortCircuitError() {
183
- return /* @__PURE__ */ new Error("Scheduler middleware short-circuited execution.");
184
- }
185
185
  //#endregion
186
186
  export { createSchedulerRuntime, getActiveScopes };
187
187
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/core/scheduler/runtime.ts"],"sourcesContent":["import type {\n CreateSchedulerRuntimeOptions,\n SchedulerConcurrencyConfig,\n SchedulerMiddleware,\n SchedulerRuntime,\n SchedulerScope,\n SchedulerScopeContext,\n} from './types'\n\nimport { createSchedulerQueue } from './queue'\n\nconst schedulerScopeOrder: SchedulerScope[] = [\n 'workspace',\n 'project',\n 'task',\n 'attempt',\n 'case',\n]\n\n/**\n * Creates the core scheduler runtime used to serialize work by scope.\n *\n * Call stack:\n *\n * {@link createSchedulerRuntime}\n * -> `createRuntimeQueues`\n * -> `runtime.runCase(context, execute)`\n * -> `runWithQueues`\n * -> `runAcquireMiddleware`\n * -> `execute`\n * -> `runReleaseMiddleware`\n *\n * Use when:\n * - runner code needs concurrency caps for queued case execution\n * - middleware should wrap work with acquire/release lifecycle hooks\n *\n * Expects:\n * - middleware is ordered from outermost to innermost concern\n * - concurrency caps are positive integers when provided\n *\n * Returns:\n * - a scheduler runtime with case execution support\n */\nexport function createSchedulerRuntime(\n options: CreateSchedulerRuntimeOptions = {},\n): SchedulerRuntime {\n const middleware = options.middleware ?? []\n const queues = createRuntimeQueues(options.concurrency ?? {})\n\n return {\n runCase<T>(context: SchedulerScopeContext, execute: () => Promise<T>) {\n const activeScopes = getActiveScopes(context)\n\n return runWithQueues(activeScopes, context, queues, () => {\n if (middleware.length === 0) {\n return execute()\n }\n\n return runWithMiddlewareEnvelope(middleware, context, execute)\n })\n },\n }\n}\n\n/**\n * Resolves the scheduler scopes that apply to a context.\n *\n * Before:\n * - `{ scope: 'case', workspaceId: 'ws', projectName: 'project', caseId: 'case-1' }`\n *\n * After:\n * - `['workspace', 'project', 'task', 'attempt', 'case']` up to the requested scope\n */\nexport function getActiveScopes(context: SchedulerScopeContext): SchedulerScope[] {\n const targetScopeIndex = schedulerScopeOrder.indexOf(context.scope)\n\n if (targetScopeIndex < 0) {\n return []\n }\n\n return schedulerScopeOrder.slice(0, targetScopeIndex + 1)\n}\n\nfunction createRuntimeQueues(concurrency: SchedulerConcurrencyConfig) {\n const queues = new Map<SchedulerScope, SchedulerScopeQueueRegistry>()\n\n for (const scope of schedulerScopeOrder) {\n const scopeConcurrency = concurrency[scope]\n\n if (scopeConcurrency === undefined) {\n continue\n }\n\n validateSchedulerConcurrency(scope, scopeConcurrency)\n\n queues.set(scope, {\n concurrency: scopeConcurrency,\n instances: new Map<string, ReturnType<typeof createSchedulerQueue>>(),\n })\n }\n\n return queues\n}\n\nasync function runWithQueues<T>(\n scopes: SchedulerScope[],\n context: SchedulerScopeContext,\n queues: Map<SchedulerScope, SchedulerScopeQueueRegistry>,\n execute: () => Promise<T>,\n index = 0,\n): Promise<T> {\n const scope = scopes[index]\n\n if (scope === undefined) {\n return execute()\n }\n\n const queue = getScopeQueue(scope, context, queues)\n\n if (queue === undefined) {\n return runWithQueues(scopes, context, queues, execute, index + 1)\n }\n\n return queue.run(() => runWithQueues(scopes, context, queues, execute, index + 1))\n}\n\ninterface SchedulerScopeQueueRegistry {\n concurrency: number\n instances: Map<string, ReturnType<typeof createSchedulerQueue>>\n}\n\ninterface SchedulerEnvelopeResult<T> {\n releaseStack: SchedulerMiddleware[]\n outcome: SchedulerExecutionOutcome<T>\n}\n\ninterface SchedulerExecutionFailure {\n error: unknown\n status: 'failed'\n}\n\ninterface SchedulerExecutionSkipped {\n status: 'skipped'\n}\n\ninterface SchedulerExecutionSuccess<T> {\n status: 'succeeded'\n value: T\n}\n\ntype SchedulerExecutionOutcome<T>\n = | SchedulerExecutionFailure\n | SchedulerExecutionSkipped\n | SchedulerExecutionSuccess<T>\n\nfunction getScopeQueue(\n scope: SchedulerScope,\n context: SchedulerScopeContext,\n queues: Map<SchedulerScope, SchedulerScopeQueueRegistry>,\n) {\n const queueRegistry = queues.get(scope)\n\n if (queueRegistry === undefined) {\n return undefined\n }\n\n const scopeKey = getSchedulerScopeInstanceKey(scope, context)\n const existingQueue = queueRegistry.instances.get(scopeKey)\n\n if (existingQueue !== undefined) {\n return existingQueue\n }\n\n const queue = createSchedulerQueue(queueRegistry.concurrency)\n queueRegistry.instances.set(scopeKey, queue)\n return queue\n}\n\nfunction getSchedulerScopeInstanceKey(\n scope: SchedulerScope,\n context: SchedulerScopeContext,\n): string {\n const workspaceKey = `workspace:${context.workspaceId}`\n const projectKey = `${workspaceKey}:project:${context.projectName ?? '(missing-project)'}`\n const taskKey = `${projectKey}:task:${context.taskId ?? '(missing-task)'}`\n const attemptKey = `${taskKey}:attempt:${context.attemptIndex ?? '(missing-attempt)'}`\n\n switch (scope) {\n case 'workspace':\n return workspaceKey\n case 'project':\n return projectKey\n case 'task':\n return taskKey\n case 'attempt':\n return attemptKey\n case 'case':\n return attemptKey\n }\n}\n\nasync function runWithMiddlewareEnvelope<T>(\n middleware: SchedulerMiddleware[],\n context: SchedulerScopeContext,\n execute: () => Promise<T>,\n): Promise<T> {\n const result = await runAcquireMiddleware(middleware, context, execute, 0)\n\n try {\n switch (result.outcome.status) {\n case 'succeeded':\n return result.outcome.value\n case 'failed':\n throw result.outcome.error\n case 'skipped':\n throw createSchedulerShortCircuitError()\n }\n }\n finally {\n await runReleaseMiddleware(result.releaseStack, context, result.releaseStack.length - 1)\n }\n}\n\nasync function runAcquireMiddleware<T>(\n middleware: SchedulerMiddleware[],\n context: SchedulerScopeContext,\n execute: () => Promise<T>,\n index: number,\n): Promise<SchedulerEnvelopeResult<T>> {\n const currentMiddleware = middleware[index]\n\n if (currentMiddleware === undefined) {\n return createSchedulerExecutionResult([], execute)\n }\n\n let nextResult = createSchedulerShortCircuitResult<T>()\n let didCallNext = false\n\n const next = async () => {\n didCallNext = true\n nextResult = await runAcquireMiddleware(middleware, context, execute, index + 1)\n }\n\n try {\n if (currentMiddleware.onAcquire === undefined) {\n await next()\n }\n else {\n await currentMiddleware.onAcquire(context, next)\n }\n }\n catch (error) {\n if (!didCallNext) {\n return createSchedulerFailureResult([], error)\n }\n\n return createSchedulerFailureResult(\n [currentMiddleware, ...nextResult.releaseStack],\n error,\n )\n }\n\n return {\n releaseStack: [currentMiddleware, ...nextResult.releaseStack],\n outcome: nextResult.outcome,\n }\n}\n\nasync function runReleaseMiddleware(\n releaseStack: SchedulerMiddleware[],\n context: SchedulerScopeContext,\n index: number,\n): Promise<void> {\n const currentMiddleware = releaseStack[index]\n\n if (currentMiddleware === undefined) {\n return\n }\n\n if (currentMiddleware.onRelease === undefined) {\n await runReleaseMiddleware(releaseStack, context, index - 1)\n return\n }\n\n await currentMiddleware.onRelease(context, async () => {\n await runReleaseMiddleware(releaseStack, context, index - 1)\n })\n}\n\nasync function createSchedulerExecutionResult<T>(\n releaseStack: SchedulerMiddleware[],\n execute: () => Promise<T>,\n): Promise<SchedulerEnvelopeResult<T>> {\n try {\n return {\n releaseStack,\n outcome: {\n status: 'succeeded',\n value: await execute(),\n },\n }\n }\n catch (error) {\n return {\n releaseStack,\n outcome: {\n status: 'failed',\n error,\n },\n }\n }\n}\n\nfunction createSchedulerFailureResult<T>(\n releaseStack: SchedulerMiddleware[],\n error: unknown,\n): SchedulerEnvelopeResult<T> {\n return {\n releaseStack,\n outcome: {\n status: 'failed',\n error,\n },\n }\n}\n\nfunction createSchedulerShortCircuitResult<T>(): SchedulerEnvelopeResult<T> {\n return {\n releaseStack: [],\n outcome: {\n status: 'skipped',\n },\n }\n}\n\nfunction validateSchedulerConcurrency(scope: SchedulerScope, concurrency: number): void {\n if (!Number.isFinite(concurrency) || !Number.isInteger(concurrency) || concurrency <= 0) {\n throw new Error(`Invalid scheduler concurrency for \"${scope}\": ${String(concurrency)}`)\n }\n}\n\nfunction createSchedulerShortCircuitError(): Error {\n return new Error('Scheduler middleware short-circuited execution.')\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/core/scheduler/runtime.ts"],"sourcesContent":["import type {\n CreateSchedulerRuntimeOptions,\n SchedulerConcurrencyConfig,\n SchedulerMiddleware,\n SchedulerRuntime,\n SchedulerScope,\n SchedulerScopeContext,\n} from './types'\n\nimport { createSchedulerQueue } from './queue'\n\nconst schedulerScopeOrder: SchedulerScope[] = [\n 'workspace',\n 'project',\n 'task',\n 'attempt',\n 'case',\n]\n\ninterface SchedulerEnvelopeResult<T> {\n outcome: SchedulerExecutionOutcome<T>\n releaseStack: SchedulerMiddleware[]\n}\n\ninterface SchedulerExecutionFailure {\n error: unknown\n status: 'failed'\n}\n\ntype SchedulerExecutionOutcome<T>\n = | SchedulerExecutionFailure\n | SchedulerExecutionSkipped\n | SchedulerExecutionSuccess<T>\n\ninterface SchedulerExecutionSkipped {\n status: 'skipped'\n}\n\ninterface SchedulerExecutionSuccess<T> {\n status: 'succeeded'\n value: T\n}\n\ninterface SchedulerScopeQueueRegistry {\n concurrency: number\n instances: Map<string, ReturnType<typeof createSchedulerQueue>>\n}\n\n/**\n * Creates the core scheduler runtime used to serialize work by scope.\n *\n * Call stack:\n *\n * {@link createSchedulerRuntime}\n * -> `createRuntimeQueues`\n * -> `runtime.runCase(context, execute)`\n * -> `runWithQueues`\n * -> `runAcquireMiddleware`\n * -> `execute`\n * -> `runReleaseMiddleware`\n *\n * Use when:\n * - runner code needs concurrency caps for queued case execution\n * - middleware should wrap work with acquire/release lifecycle hooks\n *\n * Expects:\n * - middleware is ordered from outermost to innermost concern\n * - concurrency caps are positive integers when provided\n *\n * Returns:\n * - a scheduler runtime with case execution support\n */\nexport function createSchedulerRuntime(\n options: CreateSchedulerRuntimeOptions = {},\n): SchedulerRuntime {\n const middleware = options.middleware ?? []\n const queues = createRuntimeQueues(options.concurrency ?? {})\n\n return {\n runCase<T>(context: SchedulerScopeContext, execute: () => Promise<T>) {\n const activeScopes = getActiveScopes(context)\n\n return runWithQueues(activeScopes, context, queues, () => {\n if (middleware.length === 0) {\n return execute()\n }\n\n return runWithMiddlewareEnvelope(middleware, context, execute)\n })\n },\n }\n}\n\n/**\n * Resolves the scheduler scopes that apply to a context.\n *\n * Before:\n * - `{ scope: 'case', workspaceId: 'ws', projectName: 'project', caseId: 'case-1' }`\n *\n * After:\n * - `['workspace', 'project', 'task', 'attempt', 'case']` up to the requested scope\n */\nexport function getActiveScopes(context: SchedulerScopeContext): SchedulerScope[] {\n const targetScopeIndex = schedulerScopeOrder.indexOf(context.scope)\n\n if (targetScopeIndex < 0) {\n return []\n }\n\n return schedulerScopeOrder.slice(0, targetScopeIndex + 1)\n}\n\nfunction createRuntimeQueues(concurrency: SchedulerConcurrencyConfig) {\n const queues = new Map<SchedulerScope, SchedulerScopeQueueRegistry>()\n\n for (const scope of schedulerScopeOrder) {\n const scopeConcurrency = concurrency[scope]\n\n if (scopeConcurrency === undefined) {\n continue\n }\n\n validateSchedulerConcurrency(scope, scopeConcurrency)\n\n queues.set(scope, {\n concurrency: scopeConcurrency,\n instances: new Map<string, ReturnType<typeof createSchedulerQueue>>(),\n })\n }\n\n return queues\n}\n\nasync function createSchedulerExecutionResult<T>(\n releaseStack: SchedulerMiddleware[],\n execute: () => Promise<T>,\n): Promise<SchedulerEnvelopeResult<T>> {\n try {\n return {\n outcome: {\n status: 'succeeded',\n value: await execute(),\n },\n releaseStack,\n }\n }\n catch (error) {\n return {\n outcome: {\n error,\n status: 'failed',\n },\n releaseStack,\n }\n }\n}\n\nfunction createSchedulerFailureResult<T>(\n releaseStack: SchedulerMiddleware[],\n error: unknown,\n): SchedulerEnvelopeResult<T> {\n return {\n outcome: {\n error,\n status: 'failed',\n },\n releaseStack,\n }\n}\n\nfunction createSchedulerShortCircuitError(): Error {\n return new Error('Scheduler middleware short-circuited execution.')\n}\n\nfunction createSchedulerShortCircuitResult<T>(): SchedulerEnvelopeResult<T> {\n return {\n outcome: {\n status: 'skipped',\n },\n releaseStack: [],\n }\n}\n\nfunction getSchedulerScopeInstanceKey(\n scope: SchedulerScope,\n context: SchedulerScopeContext,\n): string {\n const workspaceKey = `workspace:${context.workspaceId}`\n const projectKey = `${workspaceKey}:project:${context.projectName ?? '(missing-project)'}`\n const taskKey = `${projectKey}:task:${context.taskId ?? '(missing-task)'}`\n const attemptKey = `${taskKey}:attempt:${context.attemptIndex ?? '(missing-attempt)'}`\n\n switch (scope) {\n case 'attempt':\n return attemptKey\n case 'case':\n return attemptKey\n case 'project':\n return projectKey\n case 'task':\n return taskKey\n case 'workspace':\n return workspaceKey\n }\n}\n\nfunction getScopeQueue(\n scope: SchedulerScope,\n context: SchedulerScopeContext,\n queues: Map<SchedulerScope, SchedulerScopeQueueRegistry>,\n) {\n const queueRegistry = queues.get(scope)\n\n if (queueRegistry === undefined) {\n return undefined\n }\n\n const scopeKey = getSchedulerScopeInstanceKey(scope, context)\n const existingQueue = queueRegistry.instances.get(scopeKey)\n\n if (existingQueue !== undefined) {\n return existingQueue\n }\n\n const queue = createSchedulerQueue(queueRegistry.concurrency)\n queueRegistry.instances.set(scopeKey, queue)\n return queue\n}\n\nasync function runAcquireMiddleware<T>(\n middleware: SchedulerMiddleware[],\n context: SchedulerScopeContext,\n execute: () => Promise<T>,\n index: number,\n): Promise<SchedulerEnvelopeResult<T>> {\n const currentMiddleware = middleware[index]\n\n if (currentMiddleware === undefined) {\n return createSchedulerExecutionResult([], execute)\n }\n\n let nextResult = createSchedulerShortCircuitResult<T>()\n let didCallNext = false\n\n const next = async () => {\n didCallNext = true\n nextResult = await runAcquireMiddleware(middleware, context, execute, index + 1)\n }\n\n try {\n if (currentMiddleware.onAcquire === undefined) {\n await next()\n }\n else {\n await currentMiddleware.onAcquire(context, next)\n }\n }\n catch (error) {\n if (!didCallNext) {\n return createSchedulerFailureResult([], error)\n }\n\n return createSchedulerFailureResult(\n [currentMiddleware, ...nextResult.releaseStack],\n error,\n )\n }\n\n return {\n outcome: nextResult.outcome,\n releaseStack: [currentMiddleware, ...nextResult.releaseStack],\n }\n}\n\nasync function runReleaseMiddleware(\n releaseStack: SchedulerMiddleware[],\n context: SchedulerScopeContext,\n index: number,\n): Promise<void> {\n const currentMiddleware = releaseStack[index]\n\n if (currentMiddleware === undefined) {\n return\n }\n\n if (currentMiddleware.onRelease === undefined) {\n await runReleaseMiddleware(releaseStack, context, index - 1)\n return\n }\n\n await currentMiddleware.onRelease(context, async () => {\n await runReleaseMiddleware(releaseStack, context, index - 1)\n })\n}\n\nasync function runWithMiddlewareEnvelope<T>(\n middleware: SchedulerMiddleware[],\n context: SchedulerScopeContext,\n execute: () => Promise<T>,\n): Promise<T> {\n const result = await runAcquireMiddleware(middleware, context, execute, 0)\n\n try {\n switch (result.outcome.status) {\n case 'succeeded':\n return result.outcome.value\n case 'failed':\n throw result.outcome.error\n case 'skipped':\n throw createSchedulerShortCircuitError()\n }\n }\n finally {\n await runReleaseMiddleware(result.releaseStack, context, result.releaseStack.length - 1)\n }\n}\n\nasync function runWithQueues<T>(\n scopes: SchedulerScope[],\n context: SchedulerScopeContext,\n queues: Map<SchedulerScope, SchedulerScopeQueueRegistry>,\n execute: () => Promise<T>,\n index = 0,\n): Promise<T> {\n const scope = scopes[index]\n\n if (scope === undefined) {\n return execute()\n }\n\n const queue = getScopeQueue(scope, context, queues)\n\n if (queue === undefined) {\n return runWithQueues(scopes, context, queues, execute, index + 1)\n }\n\n return queue.run(() => runWithQueues(scopes, context, queues, execute, index + 1))\n}\n\nfunction validateSchedulerConcurrency(scope: SchedulerScope, concurrency: number): void {\n if (!Number.isFinite(concurrency) || !Number.isInteger(concurrency) || concurrency <= 0) {\n throw new Error(`Invalid scheduler concurrency for \"${scope}\": ${String(concurrency)}`)\n }\n}\n"],"mappings":"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"}
@@ -1,8 +1,4 @@
1
1
  //#region src/core/inference-executors/env.d.ts
2
- /**
3
- * Supported env value coercion types.
4
- */
5
- type EnvValueType = 'string';
6
2
  /**
7
3
  * Common options for env readers.
8
4
  */
@@ -11,17 +7,21 @@ interface EnvFromOptions {
11
7
  * Env key to read and use in error messages.
12
8
  */
13
9
  name: string;
14
- /**
15
- * Expected env value type.
16
- */
17
- type: EnvValueType;
18
10
  /**
19
11
  * Whether an empty or missing value should throw.
20
12
  *
21
13
  * @default false
22
14
  */
23
15
  required?: boolean;
16
+ /**
17
+ * Expected env value type.
18
+ */
19
+ type: EnvValueType;
24
20
  }
21
+ /**
22
+ * Supported env value coercion types.
23
+ */
24
+ type EnvValueType = 'string';
25
25
  /**
26
26
  * Env options used by the required helper.
27
27
  *
@@ -49,4 +49,4 @@ declare function requiredEnvFrom<TEnv extends EnvSource>(env: TEnv, options: Req
49
49
  }): string;
50
50
  //#endregion
51
51
  export { requiredEnvFrom as a, envFrom as i, EnvValueType as n, RequiredEnvFromOptions as r, EnvFromOptions as t };
52
- //# sourceMappingURL=env-DfWZy_n4.d.mts.map
52
+ //# sourceMappingURL=env-Br6jaWGL.d.mts.map
@@ -1,11 +1,4 @@
1
1
  //#region src/core/inference-executors/env.ts
2
- function assertNonEmptyString(value, options) {
3
- if (value == null || value.trim().length === 0) {
4
- if (options.required === true) throw new Error(`Missing required ${options.name}.`);
5
- return;
6
- }
7
- return value;
8
- }
9
2
  /**
10
3
  * Parses one env value with optional required behavior.
11
4
  *
@@ -29,7 +22,14 @@ function requiredEnvFrom(env, options) {
29
22
  if (parsed == null) throw new Error(`Missing required ${options.name}.`);
30
23
  return parsed;
31
24
  }
25
+ function assertNonEmptyString(value, options) {
26
+ if (value == null || value.trim().length === 0) {
27
+ if (options.required === true) throw new Error(`Missing required ${options.name}.`);
28
+ return;
29
+ }
30
+ return value;
31
+ }
32
32
  //#endregion
33
33
  export { requiredEnvFrom as n, envFrom as t };
34
34
 
35
- //# sourceMappingURL=env-nV5rVErX.mjs.map
35
+ //# sourceMappingURL=env-egxaJtNn.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-egxaJtNn.mjs","names":[],"sources":["../src/core/inference-executors/env.ts"],"sourcesContent":["/**\n * Common options for env readers.\n */\nexport interface EnvFromOptions {\n /**\n * Env key to read and use in error messages.\n */\n name: string\n /**\n * Whether an empty or missing value should throw.\n *\n * @default false\n */\n required?: boolean\n /**\n * Expected env value type.\n */\n type: EnvValueType\n}\n\n/**\n * Supported env value coercion types.\n */\nexport type EnvValueType = 'string'\n\n/**\n * Env options used by the required helper.\n *\n * `required` is intentionally omitted because this helper is always required.\n */\nexport type RequiredEnvFromOptions = Omit<EnvFromOptions, 'required'>\n\ntype EnvSource = Record<string, string | undefined>\n\n/**\n * Parses one env value with optional required behavior.\n *\n * Example:\n * `const apiKey = envFrom(process.env, { type: 'string', required: true, name: 'OPENAI_API_KEY' })`\n */\nexport function envFrom<TEnv extends EnvSource>(\n env: TEnv,\n options: EnvFromOptions & { name: keyof TEnv & string },\n): string | undefined {\n if (options.type === 'string') {\n return assertNonEmptyString(env[options.name], options)\n }\n\n return undefined\n}\n\n/**\n * Parses one required env value.\n *\n * Example:\n * `const apiKey = requiredEnvFrom(process.env, { type: 'string', name: 'OPENAI_API_KEY' })`\n */\nexport function requiredEnvFrom<TEnv extends EnvSource>(\n env: TEnv,\n options: RequiredEnvFromOptions & { name: keyof TEnv & string },\n): string {\n const parsed = envFrom(env, {\n ...options,\n required: true,\n })\n\n if (parsed == null) {\n throw new Error(`Missing required ${options.name}.`)\n }\n\n return parsed\n}\n\nfunction assertNonEmptyString(value: string | undefined, options: EnvFromOptions): string | undefined {\n if (value == null || value.trim().length === 0) {\n if (options.required === true) {\n throw new Error(`Missing required ${options.name}.`)\n }\n\n return undefined\n }\n\n return value\n}\n"],"mappings":";;;;;;;AAwCA,SAAgB,QACd,KACA,SACoB;CACpB,IAAI,QAAQ,SAAS,UACnB,OAAO,qBAAqB,IAAI,QAAQ,OAAO,OAAO;AAI1D;;;;;;;AAQA,SAAgB,gBACd,KACA,SACQ;CACR,MAAM,SAAS,QAAQ,KAAK;EAC1B,GAAG;EACH,UAAU;CACZ,CAAC;CAED,IAAI,UAAU,MACZ,MAAM,IAAI,MAAM,oBAAoB,QAAQ,KAAK,EAAE;CAGrD,OAAO;AACT;AAEA,SAAS,qBAAqB,OAA2B,SAA6C;CACpG,IAAI,SAAS,QAAQ,MAAM,KAAK,CAAC,CAAC,WAAW,GAAG;EAC9C,IAAI,QAAQ,aAAa,MACvB,MAAM,IAAI,MAAM,oBAAoB,QAAQ,KAAK,EAAE;EAGrD;CACF;CAEA,OAAO;AACT"}