import {
  ROLLOUT_SCHEMA
} from "./chunk-MAX3TN3C.js";
import {
  buildTrajectory
} from "./chunk-RZTMDUO7.js";

// src/rollout/mint.ts
var asText = (v, scrub) => {
  const s = typeof v === "string" ? v : JSON.stringify(v);
  return scrub(s ?? "");
};
function projectStep(span, scrub) {
  const base = {
    kind: span.kind,
    name: scrub(span.name),
    status: span.status,
    durationMs: span.endedAt !== void 0 ? span.endedAt - span.startedAt : void 0
  };
  if (span.kind === "llm") {
    const llm = span;
    const last = llm.messages[llm.messages.length - 1];
    if (last) base.input = scrub(last.content);
    if (llm.output !== void 0) base.output = scrub(llm.output);
  } else if (span.kind === "tool") {
    const tool = span;
    base.input = asText(tool.args, scrub);
    if (tool.result !== void 0) base.output = asText(tool.result, scrub);
  }
  return base;
}
function finalConversation(spans, scrub) {
  const llms = spans.filter((s) => s.kind === "llm");
  const last = llms[llms.length - 1];
  if (!last) return [];
  const messages = last.messages.map((m) => ({
    role: m.role,
    content: scrub(m.content)
  }));
  if (last.output !== void 0 && last.output !== "") {
    messages.push({ role: "assistant", content: scrub(last.output) });
  }
  return messages;
}
function rolloutReward(record) {
  const gated = record.outcome.realness?.gated === true;
  const raw = record.outcome.holdoutScore ?? record.outcome.searchScore ?? 0;
  return { reward: gated ? 0 : raw, gated };
}
function rewardSource(record) {
  if (record.outcome.holdoutScore !== void 0) return "run-record/holdout-score";
  if (record.outcome.searchScore !== void 0) return "run-record/search-score";
  return "run-record/unscored";
}
var SPLIT_FROM_TAG = {
  search: "search",
  dev: "dev",
  holdout: "holdout"
};
function mintLine(record, steps, messages, options, capturedAt, gap) {
  const { reward, gated } = rolloutReward(record);
  const uncaptured = record.costProvenance?.kind === "uncaptured";
  return {
    schema: ROLLOUT_SCHEMA,
    rollout_id: record.runId,
    parent_rollout_id: null,
    run_id: record.runId,
    experiment_id: record.experimentId,
    candidate_id: record.candidateId,
    generation: null,
    candidate_index: null,
    role: options.role ?? "agent",
    task: {
      suite: options.suite ?? record.experimentId,
      instance_id: record.scenarioId ?? record.experimentId,
      split: SPLIT_FROM_TAG[record.splitTag],
      seed: record.seed,
      rep: 0
    },
    policy: {
      harness: null,
      harness_version: null,
      model: record.model,
      provider: null,
      profile_commit: record.commitSha,
      prompt_hash: record.promptHash,
      config_hash: record.configHash,
      agent_profile_cell_id: record.agentProfile?.cellId ?? null,
      sampling: null
    },
    messages,
    tool_defs: [],
    ...steps.length > 0 ? { steps } : {},
    outcome: {
      reward,
      reward_source: rewardSource(record),
      verdict: null,
      metrics: { ...record.outcome.raw },
      is_completed: true,
      is_truncated: false,
      error: null,
      realness_gated: gated
    },
    cost: {
      usd: uncaptured ? null : record.costUsd,
      tokens_in: record.tokenUsage.input,
      tokens_out: record.tokenUsage.output,
      tokens_reasoning: record.tokenUsage.reasoning ?? null,
      cache_read: record.tokenUsage.cached ?? null,
      cache_write: record.tokenUsage.cacheWrite ?? null,
      wall_s: Math.round(record.wallMs / 1e3)
    },
    artifacts: { patch_path: null, run_dir: null, transcript_ref: null },
    provenance: {
      captured_at: capturedAt,
      capture: "mint",
      ...gap !== void 0 ? { gap } : {}
    }
  };
}
async function mintRolloutRows(records, store, options = {}) {
  const scrub = options.scrub ?? ((t) => t);
  const capturedAt = (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
  const rows = [];
  const missingTraces = [];
  for (const record of records) {
    const trajectory = await buildTrajectory(store, record.runId);
    if (trajectory.steps.length === 0) {
      missingTraces.push(record.runId);
      rows.push(
        mintLine(record, [], [], options, capturedAt, "no trace spans recorded for this runId")
      );
      continue;
    }
    let steps = trajectory.steps.map((s) => projectStep(s.span, scrub));
    if (options.maxSteps !== void 0 && steps.length > options.maxSteps) {
      const head = Math.ceil(options.maxSteps / 2);
      const tail = options.maxSteps - head;
      steps = [...steps.slice(0, head), ...steps.slice(steps.length - tail)];
    }
    const conversation = finalConversation(
      trajectory.steps.map((s) => s.span),
      scrub
    );
    const gap = conversation.length === 0 ? "trace has no llm spans \u2014 no conversation to inline" : void 0;
    rows.push(mintLine(record, steps, conversation, options, capturedAt, gap));
  }
  return { rows, missingTraces };
}

export {
  rolloutReward,
  mintRolloutRows
};
//# sourceMappingURL=chunk-M7AH34KV.js.map