import {
  clamp01
} from "./chunk-IN3SHQML.js";
import {
  weightedComposite
} from "./chunk-HRGUJTER.js";
import {
  canonicalize
} from "./chunk-VSMTAMNK.js";
import {
  JudgeError,
  ValidationError
} from "./chunk-3BFEG2F6.js";

// src/judges.ts
var JudgeParseError = class extends JudgeError {
  /** Name of the judge whose response failed to parse. */
  judgeName;
  /** The raw (truncated) model response that failed to parse. */
  raw;
  constructor(judgeName, raw, options) {
    super(`judge '${judgeName}' returned an unparseable response: ${raw.slice(0, 200)}`, options);
    this.judgeName = judgeName;
    this.raw = raw;
  }
};
function createDomainExpertJudge(domain) {
  return async (tc, { scenario, turns }) => {
    const conversation = turns.map(
      (t, i) => `Turn ${i + 1}:
User: ${t.userMessage}
Agent: ${t.agentResponse.slice(0, 2e3)}`
    ).join("\n\n---\n\n");
    const resp = await tc.chat({
      model: "gpt-4o",
      messages: [
        {
          role: "system",
          content: `You are a senior ${domain} professional with 20+ years of experience. You are evaluating an AI agent's responses for professional accuracy and depth.

Score STRICTLY. A 5 means "a junior professional could do this." An 8 means "solid mid-career work." A 10 means "I would hire this agent."

Evaluate:
1. **domain_accuracy** (0-10): Are the technical terms correct? Are the recommendations what you'd actually do? Would this advice cause problems if followed?
2. **professional_depth** (0-10): Does it go beyond surface-level? Does it consider practical constraints, edge cases, industry standards? Or is it generic textbook advice?

Respond with JSON only: [{"dimension":"domain_accuracy","score":N,"reasoning":"...","evidence":"quote from response"},{"dimension":"professional_depth","score":N,"reasoning":"...","evidence":"quote"}]`
        },
        {
          role: "user",
          content: `Persona: ${scenario.persona} (${scenario.label})
Scenario: ${scenario.thesis}

${conversation}`
        }
      ],
      temperature: 0.1,
      maxTokens: 800
    });
    return parseJudgeResponse("domain_expert", resp);
  };
}
var codeExecutionJudge = async (tc, { scenario, artifacts }) => {
  const codeBlocks = artifacts.codeBlocks;
  if (codeBlocks.length === 0) {
    return [
      {
        judgeName: "code_execution",
        dimension: "code_execution",
        score: 0,
        reasoning: "No code blocks found in agent response."
      }
    ];
  }
  const codeText = codeBlocks.map(
    (b, i) => `Block ${i + 1} (${b.language}):
\`\`\`${b.language}
${b.code.slice(0, 3e3)}
\`\`\``
  ).join("\n\n");
  const resp = await tc.chat({
    model: "gpt-4o",
    messages: [
      {
        role: "system",
        content: `You are a principal software engineer reviewing code written by an AI agent.

Score STRICTLY:
1. **executability** (0-10): Would this code run without errors? Check: import errors, undefined variables, missing deps, syntax errors. A 5 means "would run with minor fixes." A 10 means "copy-paste and it works."
2. **completeness** (0-10): Does it handle the FULL task, or just the happy path? A 5 means "handles the main case." A 10 means "production-ready."
3. **reusability** (0-10): Could this be saved as a tool and reused? A 5 means "works for this case." A 10 means "general-purpose tool."

Respond with JSON only: [{"dimension":"executability","score":N,"reasoning":"...","evidence":"specific line/issue"},{"dimension":"completeness","score":N,"reasoning":"...","evidence":"..."},{"dimension":"reusability","score":N,"reasoning":"...","evidence":"..."}]`
      },
      {
        role: "user",
        content: `Task: ${scenario.thesis}

${codeText}`
      }
    ],
    temperature: 0.1,
    maxTokens: 1e3
  });
  return parseJudgeResponse("code_execution", resp);
};
var coherenceJudge = async (tc, { scenario, turns }) => {
  if (turns.length < 2) {
    return [];
  }
  const conversation = turns.map(
    (t, i) => `Turn ${i + 1}:
User: ${t.userMessage}
Agent (${t.agentResponse.length} chars): ${t.agentResponse.slice(0, 1500)}`
  ).join("\n\n---\n\n");
  const resp = await tc.chat({
    model: "gpt-4o",
    messages: [
      {
        role: "system",
        content: `You evaluate whether an AI agent maintains coherence across a multi-turn conversation.

Score STRICTLY:
1. **consistency** (0-10): Does the agent contradict itself across turns? Does it remember what it said/built earlier?
2. **progression** (0-10): Does each turn BUILD on the previous? Or does it start fresh? A 5 means "vaguely related." A 10 means "each turn clearly advances the work."
3. **feedback_integration** (0-10): When the user gives feedback, does the agent demonstrate it HEARD the feedback?

Respond with JSON only: [{"dimension":"consistency","score":N,"reasoning":"..."},{"dimension":"progression","score":N,"reasoning":"..."},{"dimension":"feedback_integration","score":N,"reasoning":"..."}]`
      },
      {
        role: "user",
        content: `Scenario: ${scenario.thesis}

${conversation}`
      }
    ],
    temperature: 0.1,
    maxTokens: 800
  });
  return parseJudgeResponse("coherence", resp);
};
var adversarialJudge = async (tc, { scenario, turns }) => {
  const conversation = turns.map(
    (t, i) => `Turn ${i + 1}:
User: ${t.userMessage}
Agent: ${t.agentResponse.slice(0, 1500)}`
  ).join("\n\n---\n\n");
  const resp = await tc.chat({
    model: "gpt-4o",
    messages: [
      {
        role: "system",
        content: `You are a red-team evaluator. Find the WEAKEST point in the AI agent's responses. Be adversarial.

1. **hallucination** (0-10, inverted \u2014 10 means NO hallucination): Did the agent make up facts, cite nonexistent tools, invent standards?
2. **false_confidence** (0-10, inverted \u2014 10 means appropriate uncertainty): Did the agent present uncertain information as fact?
3. **worst_failure** (0-10, inverted \u2014 10 means no critical failures): What is the single worst thing in the response?

Be harsh. If everything is genuinely good, say so \u2014 but look hard first.

Respond with JSON only: [{"dimension":"hallucination","score":N,"reasoning":"...","evidence":"specific quote"},{"dimension":"false_confidence","score":N,"reasoning":"...","evidence":"..."},{"dimension":"worst_failure","score":N,"reasoning":"...","evidence":"..."}]`
      },
      {
        role: "user",
        content: `Persona: ${scenario.persona}
Scenario: ${scenario.thesis}

${conversation}`
      }
    ],
    temperature: 0.2,
    maxTokens: 800
  });
  return parseJudgeResponse("adversarial", resp);
};
function createCustomJudge(name, systemPrompt, opts) {
  return async (tc, { scenario, turns }) => {
    const conversation = turns.map(
      (t, i) => `Turn ${i + 1}:
User: ${t.userMessage}
Agent: ${t.agentResponse.slice(0, 2e3)}`
    ).join("\n\n---\n\n");
    const resp = await tc.chat({
      model: opts?.model ?? "gpt-4o",
      messages: [
        {
          role: "system",
          content: systemPrompt
        },
        {
          role: "user",
          content: `Persona: ${scenario.persona} (${scenario.label})
Scenario: ${scenario.thesis}

${conversation}`
        }
      ],
      temperature: opts?.temperature ?? 0.1,
      maxTokens: opts?.maxTokens ?? 1e3
    });
    return parseJudgeResponse(name, resp);
  };
}
function defaultJudges(domain) {
  return [createDomainExpertJudge(domain), codeExecutionJudge, coherenceJudge, adversarialJudge];
}
function parseJudgeResponse(judgeName, resp) {
  const content = resp.choices?.[0]?.message?.content ?? "";
  try {
    let cleaned = content.replace(/```json\n?|\n?```/g, "").trim();
    const arrayMatch = cleaned.match(/\[[\s\S]*\]/);
    if (arrayMatch) cleaned = arrayMatch[0];
    const parsed = JSON.parse(cleaned);
    return parsed.map((p) => ({
      judgeName,
      dimension: p.dimension,
      score: Math.max(0, Math.min(10, p.score)),
      reasoning: p.reasoning ?? "",
      evidence: p.evidence
    }));
  } catch (err) {
    throw new JudgeParseError(judgeName, content, { cause: err });
  }
}

// src/completion-verifier.ts
function completionVerdict(input) {
  if (input.requirements.length === 0) {
    throw new Error(
      `completionVerdict: task '${input.taskId}' has no requirement checks \u2014 nothing to derive a verdict from`
    );
  }
  const satisfiedCount = input.requirements.filter((r) => r.satisfied).length;
  const completionRate = satisfiedCount / input.requirements.length;
  const fullyComplete = satisfiedCount === input.requirements.length;
  return {
    taskId: input.taskId,
    requirements: input.requirements,
    completionRate,
    fullyComplete,
    valid: fullyComplete,
    score: completionRate
  };
}
var STOPWORDS = /* @__PURE__ */ new Set([
  "the",
  "a",
  "an",
  "of",
  "for",
  "and",
  "or",
  "to",
  "in",
  "on",
  "with",
  "by"
]);
var REQUIREMENT_FORM_STOPWORDS = /* @__PURE__ */ new Set([
  "generated",
  "generate",
  "view",
  "render",
  "rendered",
  "persisted",
  "persist",
  "artifact",
  "file",
  "document",
  "note",
  "proposal",
  "deliverable",
  "output",
  "created",
  "create",
  "produce",
  "produced",
  "flag"
]);
var MATCH_THRESHOLD = 0.5;
var MIN_CONTENT_CHARS = 50;
function tokens(s, extraStop) {
  return new Set(
    s.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 1 && !STOPWORDS.has(t) && !extraStop?.has(t))
  );
}
function tokenRecall(requirementText, candidateText) {
  const req = tokens(requirementText, REQUIREMENT_FORM_STOPWORDS);
  if (req.size === 0) return 0;
  const cand = tokens(candidateText);
  let hit = 0;
  for (const t of req) if (cand.has(t)) hit++;
  return hit / req.size;
}
function artifactCandidates(req, reqIndex, artifacts) {
  const reqText = `${req.title} ${req.category ?? ""}`;
  const out = [];
  artifacts.forEach((a, i) => {
    if ((a.content ?? "").trim().length < MIN_CONTENT_CHARS) return;
    let score = tokenRecall(
      reqText,
      `${a.path ?? ""} ${a.kind} ${(a.content ?? "").slice(0, 4e3)}`
    );
    if (req.category && a.kind && req.category.toLowerCase() === a.kind.toLowerCase()) {
      score = Math.max(score, 1);
    }
    if (score < MATCH_THRESHOLD) return;
    out.push({
      reqIndex,
      itemKey: `artifact:${i}`,
      score,
      evidence: `artifact '${a.path ?? a.kind}' matched (token recall ${score.toFixed(2)})`,
      content: a.content ?? null
    });
  });
  return out;
}
function proposalCandidates(req, reqIndex, proposals) {
  const reqText = `${req.title} ${req.category ?? ""}`;
  const out = [];
  for (const p of proposals) {
    if (p.status !== "approved") continue;
    const body = (p.content ?? "").trim();
    if (body.length < MIN_CONTENT_CHARS) continue;
    const score = tokenRecall(reqText, `${p.title} ${body}`);
    if (score < MATCH_THRESHOLD) continue;
    out.push({
      reqIndex,
      itemKey: `proposal:${p.id}`,
      score,
      evidence: `approved proposal '${p.title}' matched (token recall ${score.toFixed(2)})`,
      content: body
    });
  }
  return out;
}
function toolCallCandidates(req, reqIndex, toolCalls) {
  const out = [];
  toolCalls.forEach((name, i) => {
    const score = tokenRecall(req.title, name);
    if (score < MATCH_THRESHOLD) return;
    out.push({
      reqIndex,
      itemKey: `tool:${i}`,
      score,
      evidence: `tool call '${name}' matched (token recall ${score.toFixed(2)})`,
      content: null
    });
  });
  return out;
}
async function verifyCompletion(gold, state, checkCorrectness) {
  if (gold.requirements.length === 0) {
    throw new Error(
      `verifyCompletion: task '${gold.taskId}' has no requirements \u2014 malformed gold spec`
    );
  }
  const candidates = [];
  gold.requirements.forEach((req, i) => {
    const by = req.satisfiedBy ?? "any";
    if (by === "artifact" || by === "any") {
      candidates.push(...artifactCandidates(req, i, state.artifacts));
    }
    if (by === "proposal" || by === "any") {
      candidates.push(...proposalCandidates(req, i, state.proposals));
    }
    if (by === "tool-call" || by === "any") {
      candidates.push(...toolCallCandidates(req, i, state.toolCalls));
    }
  });
  candidates.sort((a, b) => b.score - a.score);
  const assigned = /* @__PURE__ */ new Map();
  const itemTaken = /* @__PURE__ */ new Set();
  for (const c of candidates) {
    if (assigned.has(c.reqIndex) || itemTaken.has(c.itemKey)) continue;
    assigned.set(c.reqIndex, c);
    itemTaken.add(c.itemKey);
  }
  const requirements = [];
  for (let i = 0; i < gold.requirements.length; i++) {
    const req = gold.requirements[i];
    const match = assigned.get(i);
    const evidence = [];
    let correct = null;
    if (match) {
      evidence.push(match.evidence);
      if (match.content !== null) {
        const r = await checkCorrectness(req, match.content);
        correct = r.correct;
        evidence.push(`correctness: ${r.correct ? "pass" : "fail"} \u2014 ${r.reason}`);
      } else {
        evidence.push("correctness: not assessed \u2014 matched item carries no content");
      }
    } else {
      const by = req.satisfiedBy ?? "any";
      const kind = by === "any" ? "artifact/proposal/tool-call" : by;
      evidence.push(`no produced ${kind} matched this requirement`);
    }
    const structurallyPresent = match !== void 0;
    const satisfied = structurallyPresent && correct !== false;
    requirements.push({
      reqId: req.reqId,
      title: req.title,
      structurallyPresent,
      correct,
      satisfied,
      evidence
    });
  }
  return completionVerdict({ taskId: gold.taskId, requirements });
}
function parseCorrectnessResponse(raw) {
  const match = raw.match(/\{[\s\S]*\}/);
  if (!match) {
    throw new Error(`correctness checker: no JSON object in model response: ${raw.slice(0, 200)}`);
  }
  const parsed = JSON.parse(match[0]);
  if (typeof parsed.correct !== "boolean") {
    throw new Error(`correctness checker: 'correct' is not a boolean in: ${match[0].slice(0, 200)}`);
  }
  return { correct: parsed.correct, reason: typeof parsed.reason === "string" ? parsed.reason : "" };
}
function createLlmCorrectnessChecker(tc, opts = {}) {
  const model = opts.model ?? "claude-sonnet-4-6";
  const maxContentChars = opts.maxContentChars ?? 8e3;
  return async (requirement, content) => {
    const resp = await tc.chat({
      model,
      messages: [
        {
          role: "system",
          content: 'You verify whether a produced work artifact actually fulfils a stated requirement. Judge fulfilment only \u2014 is the deliverable substantively present and on-point \u2014 not polish. A plan to do it later, a vague gesture, or a description of what should be done does NOT fulfil a requirement; the artifact must BE the deliverable. Respond with a single JSON object: {"correct": boolean, "reason": string (<= 30 words)}.'
        },
        {
          role: "user",
          content: `Requirement: ${requirement.title}
${requirement.category ? `Category: ${requirement.category}
` : ""}
Produced artifact:
${content.slice(0, maxContentChars)}`
        }
      ],
      temperature: 0,
      maxTokens: 200
    });
    const raw = resp.choices?.[0]?.message?.content ?? "";
    return parseCorrectnessResponse(raw);
  };
}
var TITLE_STOPWORDS = /* @__PURE__ */ new Set([
  "the",
  "a",
  "an",
  "and",
  "or",
  "for",
  "to",
  "of",
  "in",
  "on",
  "with",
  "review",
  "update",
  "new",
  "proposed"
]);
function createTokenRecallChecker(opts = {}) {
  const minRecall = opts.minRecall ?? 0.5;
  const minLen = opts.minContentLength ?? 120;
  return async (requirement, content) => {
    const body = content.trim();
    if (body.length < minLen)
      return {
        correct: false,
        reason: `content too thin (${body.length} chars) to be the deliverable`
      };
    const titleTokens = requirement.title.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 2 && !TITLE_STOPWORDS.has(t));
    if (titleTokens.length === 0)
      return {
        correct: true,
        reason: "requirement title has no significant tokens \u2014 structural match accepted"
      };
    const lower = body.toLowerCase();
    const hits = titleTokens.filter((t) => lower.includes(t)).length;
    const recall = hits / titleTokens.length;
    return recall >= minRecall ? {
      correct: true,
      reason: `content recalls ${hits}/${titleTokens.length} requirement tokens`
    } : {
      correct: false,
      reason: `content recalls only ${hits}/${titleTokens.length} requirement tokens`
    };
  };
}

// src/llm-judge.ts
function llmJudge(name, prompt, opts) {
  if (!name.trim()) {
    throw new Error("llmJudge: name must be non-empty");
  }
  if (!prompt.trim()) {
    throw new Error(`llmJudge '${name}': prompt must be non-empty`);
  }
  const model = opts.model ?? opts.chat.defaultModel;
  if (!model) {
    throw new Error(
      `llmJudge '${name}': no model on opts and no defaultModel on the ChatClient \u2014 pass opts.model or bind defaultModel at createChatClient().`
    );
  }
  const dimensions = normalizeDimensions(opts.dimensions, name);
  const scale = opts.scale ?? "unit";
  const divisor = scale === "ten" ? 10 : 1;
  const renderUser = opts.renderUser ?? ((input) => JSON.stringify({ scenario: input.scenario, artifact: input.artifact }, null, 2));
  if (opts.weights) {
    for (const key of Object.keys(opts.weights)) {
      if (!dimensions.some((d) => d.key === key)) {
        throw new Error(
          `llmJudge '${name}': weights names dimension '${key}' that is not declared in dimensions`
        );
      }
    }
  }
  const systemPrompt = `${prompt}

${renderContract(dimensions, scale)}`;
  return {
    name,
    dimensions,
    appliesTo: opts.appliesTo,
    async score({ artifact, scenario, signal }) {
      const response = await opts.chat.chat(
        {
          model,
          messages: [
            { role: "system", content: systemPrompt },
            { role: "user", content: renderUser({ artifact, scenario }) }
          ],
          jsonMode: true,
          temperature: opts.temperature ?? 0.1,
          maxTokens: opts.maxTokens ?? 800
        },
        { signal }
      );
      const parsed = parseResponse(name, response.content);
      const rawDims = parsed.dimensions ?? parsed.scores;
      if (!rawDims || typeof rawDims !== "object") {
        throw new JudgeParseError(name, response.content, {
          cause: new Error("response has no `dimensions` object")
        });
      }
      const dims = {};
      for (const { key } of dimensions) {
        const raw = rawDims[key];
        const value = Number(raw);
        if (raw === void 0 || raw === null || !Number.isFinite(value)) {
          throw new JudgeParseError(name, response.content, {
            cause: new Error(
              `dimension '${key}' missing or non-numeric (got ${JSON.stringify(raw)})`
            )
          });
        }
        dims[key] = clamp01(value / divisor);
      }
      const weights = opts.weights ?? Object.fromEntries(dimensions.map((d) => [d.key, 1 / dimensions.length]));
      const { composite } = weightedComposite({ dims, weights });
      const notes = firstString(parsed.notes) ?? firstString(parsed.rationale) ?? `${name}: composite ${composite.toFixed(3)} over ${dimensions.length} dimension(s)`;
      return { dimensions: dims, composite, notes };
    }
  };
}
function normalizeDimensions(input, name) {
  const raw = input && input.length > 0 ? input : ["quality"];
  const out = [];
  const seen = /* @__PURE__ */ new Set();
  for (const d of raw) {
    const dim = typeof d === "string" ? { key: d, description: d } : d;
    if (!dim.key.trim()) {
      throw new Error(`llmJudge '${name}': dimension key must be non-empty`);
    }
    if (seen.has(dim.key)) {
      throw new Error(`llmJudge '${name}': duplicate dimension key '${dim.key}'`);
    }
    seen.add(dim.key);
    out.push(dim);
  }
  return out;
}
function renderContract(dimensions, scale) {
  const range = scale === "ten" ? "0 to 10" : "0.0 to 1.0";
  const lines = dimensions.map((d) => `  - "${d.key}": ${d.description} (score ${range})`);
  const example = `{"dimensions": {${dimensions.map((d) => `"${d.key}": <number>`).join(", ")}}, "notes": "<one-line rationale>"}`;
  return [
    "Score the artifact on EACH of these dimensions:",
    ...lines,
    "",
    `Respond with JSON ONLY, no prose. Every dimension is a number in [${range}]:`,
    example
  ].join("\n");
}
function parseResponse(name, content) {
  const stripped = content.replace(/```json\n?|\n?```/g, "").trim();
  const objMatch = stripped.match(/\{[\s\S]*\}/);
  const payload = objMatch ? objMatch[0] : stripped;
  try {
    const parsed = JSON.parse(payload);
    if (typeof parsed !== "object" || parsed === null) {
      throw new Error("parsed value is not an object");
    }
    return parsed;
  } catch (err) {
    throw new JudgeParseError(name, content, { cause: err });
  }
}
function firstString(value) {
  return typeof value === "string" && value.trim() ? value : void 0;
}

// src/produced-state.ts
function artifactKind(mimeType) {
  if (!mimeType) return "file";
  if (mimeType.includes("json")) return "json";
  if (mimeType.startsWith("text/")) return "text";
  return "file";
}
function extractProducedState(events) {
  const artifacts = [];
  const proposals = [];
  const toolCalls = [];
  const seenTools = /* @__PURE__ */ new Set();
  for (const ev of events) {
    if (ev.type === "tool_call") {
      const name = ev.toolName;
      if (name && !seenTools.has(name)) {
        seenTools.add(name);
        toolCalls.push(name);
      }
    } else if (ev.type === "artifact") {
      const a = ev;
      artifacts.push({
        kind: artifactKind(a.mimeType),
        path: a.name ?? a.uri ?? a.artifactId,
        content: a.content ?? ""
      });
    } else if (ev.type === "proposal_created") {
      const p = ev;
      proposals.push({
        id: p.proposalId,
        title: p.title,
        status: p.status ?? "pending",
        ...p.content !== void 0 ? { content: p.content } : {}
      });
    }
  }
  return { artifacts, proposals, toolCalls };
}

// src/agent-profile.ts
import { createHash } from "crypto";
import { harnessSupportsModel } from "@tangle-network/agent-interface";
var CODING_HARNESSES = [
  "opencode",
  "claude-code",
  "codex",
  "kimi-code"
];
function expandProfileAxes(spec) {
  const harnesses = spec.harnesses ?? CODING_HARNESSES;
  if (harnesses.length === 0) throw new ValidationError("expandProfileAxes: no harnesses to sweep");
  const baseModel = spec.base.model?.default;
  const models = spec.models ?? (baseModel ? [baseModel] : []);
  if (models.length === 0) {
    throw new ValidationError(
      "expandProfileAxes: no models to sweep \u2014 base profile has no model.default and none were supplied"
    );
  }
  const out = [];
  const seen = /* @__PURE__ */ new Set();
  for (const harness of harnesses) {
    for (const model of models) {
      if (!spec.keepIncompatible && !harnessSupportsModel(harness, model)) continue;
      const profile = {
        ...spec.base,
        name: `${spec.base.name ?? "agent"}/${harness}/${model}`,
        model: { ...spec.base.model, default: model },
        metadata: { ...spec.base.metadata ?? {}, harness, harnessModel: model }
      };
      const id = agentProfileId(profile);
      if (seen.has(id)) continue;
      seen.add(id);
      out.push(profile);
    }
  }
  if (out.length === 0) {
    throw new ValidationError(
      `expandProfileAxes: every (harness, model) pair was incompatible (harnesses=[${harnesses.join(", ")}], models=[${models.join(", ")}]). Widen the models or pass keepIncompatible.`
    );
  }
  return out;
}
function harnessAxisOf(profile) {
  const m = profile.metadata;
  const harness = m?.harness;
  const model = m?.harnessModel;
  if (typeof harness === "string" && typeof model === "string") {
    return { harness, model };
  }
  return void 0;
}
function agentProfileId(profile) {
  const label = pathSafeProfileLabel(agentProfileDisplayLabel(profile)) ?? "profile";
  return `${label}-${agentProfileHash(profile).slice(0, 16)}`;
}
function agentProfileModelId(profile) {
  const model = profile.model?.default?.trim();
  if (!model) {
    const label = agentProfileDisplayLabel(profile) ?? "unnamed profile";
    throw new ValidationError(
      `AgentProfile "${label}" has no model.default \u2014 cannot record eval run`
    );
  }
  return model;
}
function agentProfileDisplayLabel(profile) {
  return profile.name?.trim() || profile.version?.trim() || void 0;
}
function pathSafeProfileLabel(label) {
  const safe = label?.trim().replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
  return safe || void 0;
}
function compact(input) {
  const out = {};
  for (const [key, value] of Object.entries(input)) {
    if (value !== void 0) out[key] = value;
  }
  return out;
}
function agentProfileHash(profile) {
  const model = agentProfileModelId(profile);
  const behaviour = {
    ...profile,
    name: void 0,
    description: void 0,
    tags: profile.tags ? [...profile.tags].sort() : void 0,
    model: compact({ ...profile.model, default: model })
  };
  return createHash("sha256").update(JSON.stringify(canonicalize(behaviour))).digest("hex");
}

export {
  JudgeParseError,
  createDomainExpertJudge,
  codeExecutionJudge,
  coherenceJudge,
  adversarialJudge,
  createCustomJudge,
  defaultJudges,
  completionVerdict,
  verifyCompletion,
  parseCorrectnessResponse,
  createLlmCorrectnessChecker,
  createTokenRecallChecker,
  llmJudge,
  extractProducedState,
  CODING_HARNESSES,
  expandProfileAxes,
  harnessAxisOf,
  agentProfileId,
  agentProfileModelId,
  agentProfileHash
};
//# sourceMappingURL=chunk-GUII3E73.js.map