/**
 * define* identity helpers — typed configuration authoring functions.
 *
 * Each function is a **pure identity function** that returns its input
 * unchanged. The value is purely at the type level: TypeScript narrows
 * the parameter type so authors get full IDE autocomplete and compile-
 * time validation when writing configuration files.
 *
 * Runtime validation is NOT performed here — it happens later in the
 * pipeline via Zod schemas. This separation keeps the authoring
 * experience fast (no schema import overhead at edit time) and lets
 * the pipeline control when and how validation errors are surfaced.
 *
 * Usage:
 * ```typescript
 * import { defineTask, env } from "@sanity/ailf"
 *
 * export default defineTask({
 *   id: "groq-projection-basics",
 *   mode: "literacy",
 *   title: "GROQ Projection Basics",
 *   // ... full autocomplete here
 * })
 * ```
 *
 * @see docs/design-docs/architecture-overhaul/typescript-configuration.md (canonical)
 */
import { CANONICAL_EVAL_MODES } from "../ailf-shared/index.js";
// ---------------------------------------------------------------------------
// Config-level helpers
// ---------------------------------------------------------------------------
/**
 * Define a full AILF evaluation configuration (`EvalConfig`).
 *
 * This is the advanced, standalone config passed via `ailf run --config
 * <path>`. For the repo-level `.ailf/ailf.config.ts` that `ailf init`
 * scaffolds and `ailf run` auto-loads, use {@link defineRepoConfig} instead —
 * its shape is `RepoConfig` (with repo-only `triggers`/`owner` blocks),
 * not `EvalConfig`.
 */
export function defineConfig(config) {
    return config;
}
/**
 * Define an AILF repo configuration — the `.ailf/ailf.config.ts` file that
 * `ailf init` scaffolds and `ailf run` auto-loads.
 *
 * Narrows the parameter to `RepoConfig` so authors get full IDE autocomplete
 * for `source`, `triggers`, `execution`, `owner`, etc. Like the other
 * `define*` helpers this is a pure identity function — runtime validation
 * happens later via `RepoConfigSchema` when the pipeline loads the file.
 *
 * ```typescript
 * import { defineRepoConfig } from "@sanity/ailf"
 *
 * export default defineRepoConfig({
 *   source: { projectId: "abc123", dataset: "production" },
 * })
 * ```
 */
export function defineRepoConfig(config) {
    return config;
}
// ---------------------------------------------------------------------------
// Task-level helpers
// ---------------------------------------------------------------------------
/**
 * Define an evaluation task with full type narrowing by mode.
 *
 * Setting `mode: "literacy"` narrows available fields to literacy-specific
 * options; `mode: "mcp-server"` narrows to MCP-specific options; etc.
 *
 * The returned value is the input unchanged — this is a type-only helper.
 */
export function defineTask(task) {
    return task;
}
// ---------------------------------------------------------------------------
// Model registry helpers
// ---------------------------------------------------------------------------
/**
 * OpenAI Responses-API-only fields. The agentic provider's OpenAI loop
 * routes everything through `/v1/chat/completions` and would silently drop
 * these. We surface the misconfiguration at config-load time instead.
 *
 * @see docs/work-items/W0131-honor-openai-responses-provider.json
 */
const RESPONSES_ONLY_FIELDS = ["reasoning", "summary", "verbosity"];
/**
 * Whether a model would be assembled into agentic-naive or agentic-optimized
 * literacy variants. These are the variants that route through the in-house
 * agentic provider (which speaks chat completions only); baseline routes
 * through Promptfoo's native handling, which honors `openai:responses:` ids.
 *
 * Note: variant names mirror the literacy mode base in
 * `packages/eval/src/pipeline/compiler/mode-bases/literacy.ts`.
 */
function participatesInAgenticLiteracy(model) {
    const enrolledInLiteracy = !model.modes || model.modes.includes("literacy");
    if (!enrolledInLiteracy)
        return false;
    const literacyVariants = model.variants?.literacy;
    if (!literacyVariants)
        return true;
    return (literacyVariants.includes("agentic-naive") ||
        literacyVariants.includes("agentic-optimized"));
}
/**
 * Define the model registry (models to evaluate and grader model).
 *
 * Used in `config/models.ts` for typed model configuration.
 *
 * Validates:
 * - Every `modes` entry is a canonical eval mode name
 * - Every `variants` key is a mode the model is enrolled in
 * - `openai:responses:` model ids are not used for agentic literacy variants
 *   (the in-house agentic loop dispatches to chat completions only)
 * - Responses-API-only fields (`reasoning`, `summary`, `verbosity`) are not
 *   set on a model that routes through the agentic provider — they would be
 *   silently dropped.
 *
 * @throws {Error} On invalid mode names, mismatched variant keys, or
 *                 misconfigured OpenAI Responses-API fields.
 */
export function defineModels(models) {
    const validModes = new Set(CANONICAL_EVAL_MODES);
    for (const model of models.models) {
        if (model.modes) {
            for (const mode of model.modes) {
                if (!validModes.has(mode)) {
                    throw new Error(`Model "${model.label ?? model.id}": unknown mode "${mode}". ` +
                        `Valid modes: ${CANONICAL_EVAL_MODES.join(", ")}`);
                }
            }
        }
        if (model.variants) {
            const enrolledModes = new Set(model.modes ?? []);
            for (const variantMode of Object.keys(model.variants)) {
                if (!enrolledModes.has(variantMode)) {
                    throw new Error(`Model "${model.label ?? model.id}": variants specified for ` +
                        `mode "${variantMode}" but model does not include "${variantMode}" ` +
                        `in its modes array. Add "${variantMode}" to modes or remove ` +
                        `the variants entry.`);
                }
            }
        }
        const usesAgentic = participatesInAgenticLiteracy(model);
        if (usesAgentic && model.id.startsWith("openai:responses:")) {
            throw new Error(`Model "${model.label ?? model.id}": the in-house agentic provider ` +
                `does not implement the OpenAI Responses API endpoint — requests would ` +
                `be silently downgraded to chat completions. Either restrict variants to ` +
                `["baseline"] (Promptfoo's native handling honors openai:responses:) or ` +
                `change the id to "openai:chat:..." for agentic evaluation. ` +
                `See W0131 for context.`);
        }
        if (usesAgentic && model.config) {
            const droppedFields = RESPONSES_ONLY_FIELDS.filter((f) => f in model.config);
            if (droppedFields.length > 0) {
                throw new Error(`Model "${model.label ?? model.id}": configured fields ` +
                    `${droppedFields.map((f) => `"${f}"`).join(", ")} are only honored ` +
                    `by the OpenAI Responses API. The agentic provider's chat-completions ` +
                    `path would silently drop them. Either remove these fields or restrict ` +
                    `variants to ["baseline"] so the model is evaluated only through ` +
                    `Promptfoo's native Responses-API handler. See W0131 for context.`);
            }
        }
    }
    return models;
}
// ---------------------------------------------------------------------------
// Package-surface helpers
// ---------------------------------------------------------------------------
/**
 * Define the framework-level package-surface manifest consumed by the
 * W0198 symbol-resolution preflight.
 *
 * Validates the obviously author-time errors:
 * - Each entry has a non-empty `pkg` and `semverPin`.
 * - `semverPin` is a single-major caret range (`^MAJOR.MINOR.PATCH`).
 *   Other range syntaxes (`>=`, `~`, `*`) are rejected because the
 *   resolver's stability commitment is "pinned to one major"; non-caret
 *   ranges either widen past a major (reintroducing churn) or are
 *   stricter than needed for an editorial pin.
 * - No duplicate `pkg` entries.
 *
 * @throws {Error} On invalid entries or duplicates.
 *
 * @see docs/design-docs/two-stage-grader-symbol-preflight.md
 */
export function definePackageSurface(config) {
    const seen = new Set();
    for (const entry of config.packages) {
        if (!entry.pkg) {
            throw new Error(`definePackageSurface: every entry must declare a non-empty \`pkg\`.`);
        }
        if (!entry.semverPin) {
            throw new Error(`definePackageSurface: entry "${entry.pkg}" is missing \`semverPin\`.`);
        }
        if (!/^\^\d+\.\d+\.\d+(?:[-+].*)?$/.test(entry.semverPin)) {
            throw new Error(`definePackageSurface: entry "${entry.pkg}" has \`semverPin\` ` +
                `"${entry.semverPin}". Pins must be single-major caret ranges ` +
                `(e.g. "^2.0.0"); other range syntaxes are not allowed.`);
        }
        if (seen.has(entry.pkg)) {
            throw new Error(`definePackageSurface: duplicate entry for "${entry.pkg}". ` +
                `Each package may appear at most once in the manifest.`);
        }
        seen.add(entry.pkg);
    }
    return config;
}
// ---------------------------------------------------------------------------
// Preflight-scoring helpers
// ---------------------------------------------------------------------------
/**
 * Define the preflight-scoring config consumed by the W0198 two-stage
 * grader's score merge.
 *
 * The single knob is `codeCorrectnessWeight` — preflight's share of the
 * `code-correctness` dimension (`[0, 1]`). The complementary share belongs
 * to the LLM rubric. Validates the obviously author-time errors:
 *
 * - `codeCorrectnessWeight` is a finite number in `[0, 1]`. Weights outside
 *   that range either disable one lane entirely (use `0` / `1`) or land in
 *   nonsense territory (negative, > 1).
 *
 * @throws {Error} On out-of-range weights.
 */
export function definePreflightScoring(config) {
    const w = config.codeCorrectnessWeight;
    if (!Number.isFinite(w) || w < 0 || w > 1) {
        throw new Error(`definePreflightScoring: \`codeCorrectnessWeight\` must be a finite ` +
            `number in [0, 1] — got ${String(w)}.`);
    }
    return config;
}
// ---------------------------------------------------------------------------
// Rubric helpers
// ---------------------------------------------------------------------------
/**
 * Define rubric templates and scoring profiles.
 *
 * Used in `config/rubrics.ts` for typed rubric configuration.
 */
export function defineRubrics(rubrics) {
    return rubrics;
}
// ---------------------------------------------------------------------------
// Threshold helpers
// ---------------------------------------------------------------------------
/**
 * Define quality thresholds for readiness gates and regression alerts.
 *
 * Used in `config/thresholds.ts` for typed threshold configuration.
 */
export function defineThresholds(thresholds) {
    return thresholds;
}
// ---------------------------------------------------------------------------
// Feature registry helpers
// ---------------------------------------------------------------------------
/**
 * Define the product feature coverage registry.
 *
 * Used in `config/features.ts` for typed feature tracking.
 */
export function defineFeatures(features) {
    return features;
}
// ---------------------------------------------------------------------------
// Sink helpers
// ---------------------------------------------------------------------------
/**
 * Define report delivery sinks (Slack, BigQuery, webhooks).
 *
 * Used in `config/sinks.ts` for typed sink configuration.
 */
export function defineSinks(sinks) {
    return sinks;
}
// ---------------------------------------------------------------------------
// Schedule helpers
// ---------------------------------------------------------------------------
/**
 * Define scheduled evaluation cron jobs and digest config.
 *
 * Used in `config/schedules.ts` for typed schedule configuration.
 */
export function defineSchedules(schedules) {
    return schedules;
}
// ---------------------------------------------------------------------------
// Test-budget helpers
// ---------------------------------------------------------------------------
/**
 * Define per-provider daily USD spend caps for Tier 3 (live-LLM) CI runs.
 *
 * Used in `config/test-budgets.ts` for typed budget configuration.
 *
 * @see docs/design-docs/testing-strategy.md — "Tier 3 — Live LLMs"
 */
export function defineTestBudgets(budgets) {
    return budgets;
}
// ---------------------------------------------------------------------------
// Canary task-set helpers
// ---------------------------------------------------------------------------
/**
 * Define the curated canary task set for the Tier 3 nightly workflow.
 *
 * Used in `config/canary-tasks.ts`. Validation against the live task
 * inventory happens in `scripts/check-canary-tasks.ts`, not here.
 *
 * @see docs/design-docs/testing-strategy.md — "Tier 3 — Live LLMs"
 */
export function defineCanaryTasks(canary) {
    return canary;
}
// ---------------------------------------------------------------------------
// Source helpers
// ---------------------------------------------------------------------------
/**
 * Define documentation source configurations.
 *
 * Used in `config/sources.ts` for typed source configuration. Accepts any
 * `DocSourceConfig`-shaped entry — Sanity-shaped entries are valid (every
 * field is optional), and adapter-specific source types narrow `kind` to
 * a literal (e.g. `defineGoogleDriveSource({...})`).
 */
export function defineSources(sources) {
    return sources;
}
/**
 * Define prompt templates.
 *
 * Used in `config/prompts.ts` for typed prompt configuration.
 */
export function definePrompts(prompts) {
    return prompts;
}
// ---------------------------------------------------------------------------
// Preset helpers
// ---------------------------------------------------------------------------
/**
 * Define a domain preset — targets a mode base and adds domain-specific config.
 *
 * A domain preset declares which mode it targets (by ID), provides domain
 * configuration (sources, features, doc fetcher), and can optionally override
 * mode base defaults (rubrics, scoring profiles, prompt templates).
 *
 * Used in `.ailf/preset.ts` or npm packages for typed preset authoring.
 */
export function definePreset(preset) {
    return preset;
}
// ---------------------------------------------------------------------------
// Mode base helpers
// ---------------------------------------------------------------------------
/**
 * Define a mode base — shared evaluation methodology for a mode.
 *
 * A mode base defines HOW you evaluate (rubrics, scoring, prompts)
 * independently of WHAT you're evaluating. Domain presets target a mode
 * base and inherit its defaults.
 */
export function defineModeBase(base) {
    return base;
}
/**
 * Define a pricing table for cost estimation.
 *
 * Used in `config/pricing.ts` for typed pricing configuration.
 */
export function definePricingTable(entries) {
    return entries;
}
