import {
  estimateCost,
  isModelPriced,
  resolveModelPricing
} from "./chunk-VI2UW6B6.js";
import {
  ValidationError
} from "./chunk-ONWEPEDO.js";

// src/cost-ledger.ts
import { z } from "zod";
var CostCeilingReachedError = class extends ValidationError {
  constructor(ceilingUsd, committedAndReservedUsd, requestedUsd, phase, actor) {
    super(
      `CostLedger: reserving ${requestedUsd} for '${actor}' during '${phase}' would exceed ceiling ${ceilingUsd} with ${committedAndReservedUsd} already committed or reserved`
    );
  }
};
var CostAccountingIncompleteError = class extends ValidationError {
};
var CostReservationExceededError = class extends ValidationError {
  constructor(actor, actualUsd, maximumUsd) {
    super(
      `CostLedger: '${actor}' charged ${actualUsd}, exceeding its enforced maximum ${maximumUsd}`
    );
  }
};
var CostCallConflictError = class extends ValidationError {
  callId;
  receipt;
  constructor(message, options = {}) {
    super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
    this.callId = options.callId;
    this.receipt = options.receipt ? cloneReceipt(options.receipt) : void 0;
  }
};
var CostLedgerPersistenceError = class extends ValidationError {
  callId;
  receipt;
  constructor(cause, callId, receipt) {
    super(
      `CostLedger: failed to persist${callId ? ` call '${callId}'` : ""}: ${toError(cause).message}`,
      { cause }
    );
    this.callId = callId;
    this.receipt = receipt ? cloneReceipt(receipt) : void 0;
  }
};
var CostReceiptCaptureError = class extends ValidationError {
  callId;
  receipt;
  receiptError;
  constructor(callId, cause, receiptError, receipt) {
    super(`CostLedger: could not capture the provider receipt for call '${callId}'`, { cause });
    this.callId = callId;
    this.receipt = receipt ? cloneReceipt(receipt) : void 0;
    this.receiptError = toError(receiptError);
  }
};
var CostLedger = class {
  records = /* @__PURE__ */ new Map();
  activeCallIds = /* @__PURE__ */ new Set();
  lateCallIds = /* @__PURE__ */ new Set();
  idleWaiters = /* @__PURE__ */ new Set();
  completedTasks = 0;
  revision = "memory";
  costLimitPersisted = false;
  costCeilingUsd;
  persistence;
  constructor(input) {
    const options = typeof input === "number" ? { costCeilingUsd: input } : input ?? {};
    this.persistence = options.persistence;
    if (options.costCeilingUsd !== void 0) {
      assertNonNegative(options.costCeilingUsd, "costCeilingUsd");
    }
    let persistedCostCeilingUsd;
    if (this.persistence) {
      let stored;
      try {
        stored = this.persistence.read();
      } catch (cause) {
        throw new CostLedgerPersistenceError(cause);
      }
      assertString(stored.revision, "persistence revision");
      this.revision = stored.revision;
      const restored = parseEvents(stored.events);
      for (const record of restored.records) this.records.set(record.callId, record);
      this.completedTasks = restored.completedTasks;
      persistedCostCeilingUsd = restored.costCeilingUsd;
    }
    if (options.costCeilingUsd !== void 0 && persistedCostCeilingUsd !== void 0 && options.costCeilingUsd !== persistedCostCeilingUsd) {
      throw new ValidationError(
        `CostLedger: requested cost ceiling ${options.costCeilingUsd} does not match persisted ceiling ${persistedCostCeilingUsd}`
      );
    }
    this.costCeilingUsd = persistedCostCeilingUsd ?? options.costCeilingUsd;
    this.costLimitPersisted = !this.persistence || this.costCeilingUsd === void 0 || persistedCostCeilingUsd !== void 0;
    if (this.costCeilingUsd !== void 0 && [...this.records.values()].some(
      (record) => record.status === "pending" && record.maximumCostUsd === void 0
    )) {
      throw new ValidationError("CostLedger: capped event log contains an unbounded pending call");
    }
    if (options.receipts?.length) {
      const imported = options.receipts.map(
        (receipt, index) => parseImportedReceipt(receipt, `imported receipt ${index + 1}`)
      );
      this.ensureCostLimitPersisted();
      for (const receipt of imported) this.appendRecord(receipt);
    }
  }
  async runPaidCall(input) {
    let callId;
    let pending;
    try {
      callId = resolveCallId(input.callId);
      validateAttribution(input);
      if (input.signal?.aborted) {
        return { succeeded: false, callId, error: abortError(input.signal) };
      }
      if (this.records.has(callId)) {
        return {
          succeeded: false,
          callId,
          error: new CostCallConflictError(`CostLedger: callId '${callId}' already exists`)
        };
      }
      this.ensureCostLimitPersisted(callId);
      const summary = this.summary();
      if (summary.unresolvedCalls > 0) {
        return {
          succeeded: false,
          callId,
          error: new CostAccountingIncompleteError(
            `CostLedger: ${summary.unresolvedCalls} unresolved call(s) must be reconciled before new paid work`
          )
        };
      }
      const maximumCostUsd = this.resolveMaximum(input.maximumCharge);
      if (this.costCeilingUsd !== void 0 && this.hasIncompleteSettledCall()) {
        return {
          succeeded: false,
          callId,
          error: new CostAccountingIncompleteError(
            `CostLedger: accounting is incomplete; refusing paid call '${input.actor}' during '${input.phase}'`
          )
        };
      }
      if (this.costCeilingUsd !== void 0) {
        const committedAndReserved = summary.totalCostUsd + summary.reservedCostUsd;
        if (committedAndReserved + maximumCostUsd > this.costCeilingUsd) {
          return {
            succeeded: false,
            callId,
            error: new CostCeilingReachedError(
              this.costCeilingUsd,
              committedAndReserved,
              maximumCostUsd,
              input.phase,
              input.actor
            )
          };
        }
      }
      pending = {
        status: "pending",
        callId,
        channel: input.channel,
        phase: input.phase,
        actor: input.actor,
        model: pendingModel(input),
        ...maximumCostUsd === void 0 ? {} : { maximumCostUsd },
        ...input.tags ? { tags: { ...input.tags } } : {},
        timestamp: Date.now()
      };
      this.appendRecord(pending);
      this.activeCallIds.add(callId);
    } catch (error) {
      return { succeeded: false, ...callId ? { callId } : {}, error: toError(error) };
    }
    try {
      return await this.execute(input, pending);
    } catch (error) {
      return { succeeded: false, callId: pending.callId, error: toError(error) };
    } finally {
      if (!this.lateCallIds.has(pending.callId)) this.releaseActiveCall(pending.callId);
    }
  }
  /** Wait until every call started by this ledger has produced a durable outcome. */
  async waitForIdle(options = {}) {
    if (this.activeCallIds.size === 0) return true;
    const timeoutMs = options.timeoutMs ?? 5e3;
    assertTimeout(timeoutMs, "waitForIdle.timeoutMs");
    return new Promise((resolve) => {
      let timer;
      const finish = (settled) => {
        this.idleWaiters.delete(onIdle);
        if (timer !== void 0) clearTimeout(timer);
        resolve(settled);
      };
      const onIdle = () => finish(true);
      this.idleWaiters.add(onIdle);
      timer = setTimeout(() => finish(false), timeoutMs);
      if (this.activeCallIds.size === 0) onIdle();
    });
  }
  /** Settle a call left pending by a crashed process after reconciling with the provider. */
  reconcile(callId, observed, options = {}) {
    const pending = [...this.records.values()].find(
      (record) => record.callId === callId && record.status === "pending"
    );
    if (!pending) throw new CostCallConflictError(`CostLedger: no pending call '${callId}'`);
    if (this.activeCallIds.has(callId)) {
      throw new CostCallConflictError(`CostLedger: call '${callId}' is still active`);
    }
    this.ensureCostLimitPersisted(callId);
    return this.commitReceipt(pending, observed, options.error);
  }
  list(filter) {
    return [...this.records.values()].filter((record) => record.status === "settled").filter((receipt) => matches(receipt, filter)).map(cloneReceipt);
  }
  summary(filter) {
    const records = [...this.records.values()].filter((record) => matches(record, filter));
    const pending = records.filter(
      (record) => record.status === "pending"
    );
    const receipts = records.filter((record) => record.status === "settled");
    const byChannel = /* @__PURE__ */ new Map();
    const unpriced = /* @__PURE__ */ new Set();
    const incompleteReasons = pending.map(
      (record) => `call '${record.callId}' for '${record.actor}' is pending`
    );
    let inputTokens = 0;
    let outputTokens = 0;
    let reasoningTokens = 0;
    let cachedTokens = 0;
    let cacheWriteTokens = 0;
    let totalCostUsd = 0;
    for (const receipt of receipts) {
      inputTokens += receipt.inputTokens;
      outputTokens += receipt.outputTokens;
      reasoningTokens += receipt.reasoningTokens ?? 0;
      cachedTokens += receipt.cachedTokens ?? 0;
      cacheWriteTokens += receipt.cacheWriteTokens ?? 0;
      totalCostUsd += receipt.costUsd;
      if (receipt.costUnknown) {
        unpriced.add(receipt.model);
        incompleteReasons.push(
          receipt.error ?? `cost unknown for '${receipt.actor}' using '${receipt.model}'`
        );
      }
      if (receipt.usageUnknown) {
        incompleteReasons.push(
          `token usage unknown for '${receipt.actor}' using '${receipt.model}'`
        );
      }
      if (receipt.maximumCostUsd !== void 0 && receipt.costUsd > receipt.maximumCostUsd) {
        incompleteReasons.push(
          `'${receipt.actor}' charged ${receipt.costUsd}, exceeding its enforced maximum ${receipt.maximumCostUsd}`
        );
      }
      const rollup = byChannel.get(receipt.channel) ?? emptyRollup(receipt.channel);
      rollup.calls += 1;
      rollup.inputTokens += receipt.inputTokens;
      rollup.outputTokens += receipt.outputTokens;
      rollup.reasoningTokens = (rollup.reasoningTokens ?? 0) + (receipt.reasoningTokens ?? 0);
      rollup.cachedTokens += receipt.cachedTokens ?? 0;
      rollup.cacheWriteTokens = (rollup.cacheWriteTokens ?? 0) + (receipt.cacheWriteTokens ?? 0);
      rollup.costUsd += receipt.costUsd;
      if (receipt.costUnknown) rollup.unpricedCalls += 1;
      if (receipt.usageUnknown) rollup.unknownUsageCalls += 1;
      byChannel.set(receipt.channel, rollup);
    }
    return {
      totalCalls: receipts.length,
      pendingCalls: pending.length,
      unresolvedCalls: pending.filter(
        (record) => !this.activeCallIds.has(record.callId) || this.lateCallIds.has(record.callId)
      ).length,
      reservedCostUsd: pending.reduce((sum, record) => sum + (record.maximumCostUsd ?? 0), 0),
      inputTokens,
      outputTokens,
      reasoningTokens,
      cachedTokens,
      cacheWriteTokens,
      totalCostUsd,
      byChannel: [...byChannel.values()].sort((a, b) => a.channel.localeCompare(b.channel)),
      unpricedModels: [...unpriced].sort(),
      fullyPriced: unpriced.size === 0,
      usageComplete: pending.length === 0 && receipts.every((receipt) => !receipt.usageUnknown),
      accountingComplete: incompleteReasons.length === 0,
      incompleteReasons: [...new Set(incompleteReasons)]
    };
  }
  markCompleted(count = 1) {
    if (!Number.isInteger(count) || count < 0) {
      throw new ValidationError(
        `CostLedger.markCompleted: count must be a non-negative integer, got ${count}`
      );
    }
    if (count === 0) return;
    this.ensureCostLimitPersisted();
    this.appendEvent({ version: 1, completedTasks: count });
    this.completedTasks += count;
  }
  costPerCompletedTask() {
    return this.completedTasks === 0 ? null : this.summary().totalCostUsd / this.completedTasks;
  }
  async execute(input, pending) {
    const signal = input.signal ?? new AbortController().signal;
    if (signal.aborted) {
      return this.commitOutcome(pending, abortError(signal), {
        model: pending.model,
        inputTokens: 0,
        outputTokens: 0,
        actualCostUsd: 0
      });
    }
    const operation = Promise.resolve().then(() => input.execute(signal, pending.callId));
    const settled = await settle(operation, signal);
    if (settled.kind === "aborted") {
      this.lateCallIds.add(pending.callId);
      this.captureLateOutcome(input, pending, operation);
      return paidFailure(pending.callId, abortError(signal));
    }
    if (settled.kind === "error") {
      let observed;
      try {
        observed = input.receiptFromError?.(settled.error);
      } catch (receiptError) {
        return this.captureFailure(pending, settled.error, receiptError);
      }
      return this.commitOutcome(pending, settled.error, observed ?? unknownReceipt(pending.model));
    }
    try {
      const receipt = this.commitReceipt(pending, input.receipt(settled.value));
      if (receipt.maximumCostUsd !== void 0 && receipt.costUsd > receipt.maximumCostUsd) {
        return paidFailure(
          pending.callId,
          new CostReservationExceededError(pending.actor, receipt.costUsd, receipt.maximumCostUsd),
          receipt
        );
      }
      return { succeeded: true, callId: pending.callId, value: settled.value, receipt };
    } catch (receiptError) {
      if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) {
        return paidFailure(pending.callId, receiptError);
      }
      return this.captureFailure(pending, receiptError, receiptError);
    }
  }
  captureLateOutcome(input, pending, operation) {
    void operation.then(
      (value) => {
        if (this.records.get(pending.callId)?.status !== "pending") return;
        try {
          this.commitReceipt(pending, input.receipt(value));
        } catch {
        }
      },
      (cause) => {
        if (this.records.get(pending.callId)?.status !== "pending") return;
        const error = toError(cause);
        try {
          const observed = input.receiptFromError?.(error);
          this.commitReceipt(pending, observed ?? unknownReceipt(pending.model), error.message);
        } catch (receiptError) {
          if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) {
            return;
          }
          this.captureFailure(pending, error, receiptError);
        }
      }
    ).finally(() => {
      this.lateCallIds.delete(pending.callId);
      this.releaseActiveCall(pending.callId);
    });
  }
  releaseActiveCall(callId) {
    this.activeCallIds.delete(callId);
    if (this.activeCallIds.size > 0) return;
    for (const resolve of this.idleWaiters) resolve();
    this.idleWaiters.clear();
  }
  commitOutcome(pending, error, observed) {
    try {
      const receipt = this.commitReceipt(pending, observed, error.message);
      return paidFailure(pending.callId, error, receipt);
    } catch (receiptError) {
      if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) {
        return paidFailure(pending.callId, receiptError);
      }
      return this.captureFailure(pending, error, receiptError);
    }
  }
  captureFailure(pending, cause, receiptError) {
    try {
      const receipt = this.commitReceipt(
        pending,
        unknownReceipt(pending.model),
        toError(receiptError).message
      );
      return paidFailure(
        pending.callId,
        new CostReceiptCaptureError(pending.callId, cause, receiptError, receipt),
        receipt
      );
    } catch (error) {
      const typed = error instanceof Error ? error : toError(error);
      return paidFailure(pending.callId, typed);
    }
  }
  commitReceipt(pending, observed, error) {
    const receipt = buildReceipt(pending, observed, error);
    if (this.records.get(pending.callId)?.status !== "pending") {
      throw new CostCallConflictError(`CostLedger: call '${pending.callId}' is not pending`);
    }
    this.appendRecord(receipt);
    return cloneReceipt(receipt);
  }
  resolveMaximum(maximum) {
    if (!maximum) {
      if (this.costCeilingUsd !== void 0) {
        throw new CostAccountingIncompleteError(
          "CostLedger: capped paid calls require a hard maximumCharge before execution"
        );
      }
      return void 0;
    }
    if ("externallyEnforcedMaximumUsd" in maximum) {
      assertNonNegative(
        maximum.externallyEnforcedMaximumUsd,
        "maximumCharge.externallyEnforcedMaximumUsd"
      );
      return maximum.externallyEnforcedMaximumUsd;
    }
    const priced = costForUsage(maximum.model, maximum);
    if (priced.costUnknown) {
      if (this.costCeilingUsd !== void 0) {
        throw new CostAccountingIncompleteError(
          `CostLedger: cannot reserve unpriced model '${maximum.model}' in a capped run`
        );
      }
      return void 0;
    }
    return priced.costUsd;
  }
  hasIncompleteSettledCall() {
    return [...this.records.values()].some(
      (record) => record.status === "settled" && (record.costUnknown || record.usageUnknown || record.maximumCostUsd !== void 0 && record.costUsd > record.maximumCostUsd)
    );
  }
  appendRecord(record) {
    const callId = record.callId;
    const receipt = record.status === "settled" ? record : void 0;
    validateTransition(this.records, record);
    const event = record.status === "settled" && (record.reasoningTokens !== void 0 || record.cacheWriteTokens !== void 0) ? { version: 2, record: cloneReceipt(record) } : { version: 1, record: cloneRecord(record) };
    this.appendEvent(event, callId, receipt);
    this.records.set(callId, cloneRecord(record));
  }
  ensureCostLimitPersisted(callId) {
    if (this.costLimitPersisted || this.costCeilingUsd === void 0) return;
    this.appendEvent({ version: 1, costCeilingUsd: this.costCeilingUsd }, callId);
    this.costLimitPersisted = true;
  }
  appendEvent(event, callId, receipt) {
    try {
      if (this.persistence) {
        const nextRevision = this.persistence.append(this.revision, `${JSON.stringify(event)}
`);
        if (nextRevision === void 0) {
          throw new CostCallConflictError(
            `CostLedger: persisted revision changed while writing call '${callId}'`,
            { callId, receipt }
          );
        }
        assertString(nextRevision, "persistence revision");
        this.revision = nextRevision;
      }
    } catch (cause) {
      if (cause instanceof CostCallConflictError) throw cause;
      throw new CostLedgerPersistenceError(cause, callId, receipt);
    }
  }
};
function modelPriceKey(model) {
  return isModelPriced(model) ? model : null;
}
function costForUsage(model, usage) {
  assertUsage(usage);
  if (!resolveModelPricing(model)) return { costUsd: 0, costUnknown: true };
  return {
    costUsd: estimateCost(
      usage.inputTokens + (usage.cachedTokens ?? 0) + (usage.cacheWriteTokens ?? 0),
      usage.outputTokens,
      model
    ),
    costUnknown: false
  };
}
async function settle(promise, signal) {
  return await new Promise((resolve) => {
    let done = false;
    const finish = (value) => {
      if (done) return;
      done = true;
      signal.removeEventListener("abort", onAbort);
      resolve(value);
    };
    const onAbort = () => finish({ kind: "aborted" });
    signal.addEventListener("abort", onAbort, { once: true });
    if (signal.aborted) onAbort();
    promise.then(
      (value) => finish({ kind: "value", value }),
      (error) => finish({ kind: "error", error: toError(error) })
    );
  });
}
function buildReceipt(pending, observed, error) {
  assertUsage(observed);
  assertString(observed.model, "receipt.model");
  const estimated = costForUsage(observed.model, observed);
  const hasActual = observed.actualCostUsd !== void 0;
  if (hasActual && observed.costUnknown === true) {
    throw new ValidationError(
      "CostLedger: a receipt cannot have both actualCostUsd and costUnknown=true"
    );
  }
  if (hasActual) assertNonNegative(observed.actualCostUsd, "actualCostUsd");
  const usageUnknown = observed.usageUnknown === true;
  const costUnknown = observed.costUnknown === true || !hasActual && (usageUnknown || estimated.costUnknown);
  const resolvedPricing = !hasActual && !costUnknown ? resolveModelPricing(observed.model) : null;
  return parseReceipt(
    {
      status: "settled",
      callId: pending.callId,
      channel: pending.channel,
      phase: pending.phase,
      actor: pending.actor,
      model: observed.model,
      inputTokens: observed.inputTokens,
      outputTokens: observed.outputTokens,
      ...observed.reasoningTokens === void 0 ? {} : { reasoningTokens: observed.reasoningTokens },
      ...observed.cachedTokens === void 0 ? {} : { cachedTokens: observed.cachedTokens },
      ...observed.cacheWriteTokens === void 0 ? {} : { cacheWriteTokens: observed.cacheWriteTokens },
      costUsd: costUnknown ? 0 : hasActual ? observed.actualCostUsd : estimated.costUsd,
      costUnknown,
      usageUnknown,
      ...resolvedPricing ? {
        pricing: {
          inputUsdPerThousand: resolvedPricing.input,
          outputUsdPerThousand: resolvedPricing.output
        }
      } : {},
      ...hasActual ? { actualCostUsd: observed.actualCostUsd } : {},
      ...pending.maximumCostUsd === void 0 ? {} : { maximumCostUsd: pending.maximumCostUsd },
      ...error ? { error } : {},
      ...pending.tags ? { tags: { ...pending.tags } } : {},
      timestamp: pending.timestamp
    },
    "provider receipt"
  );
}
var NonEmptyString = z.string().refine((value) => value.trim().length > 0, "must be non-empty");
var TokenCount = z.number().int().nonnegative().finite();
var NonNegative = z.number().nonnegative().finite();
var Positive = z.number().positive().finite();
var Tags = z.record(NonEmptyString, z.string());
var CostPricingSchema = z.strictObject({
  inputUsdPerThousand: Positive,
  outputUsdPerThousand: Positive
});
var CostCallBaseShape = {
  callId: NonEmptyString,
  channel: NonEmptyString,
  phase: NonEmptyString,
  actor: NonEmptyString,
  model: NonEmptyString,
  maximumCostUsd: NonNegative.optional(),
  tags: Tags.optional(),
  timestamp: NonNegative
};
var PendingCostCallSchema = z.strictObject({
  status: z.literal("pending"),
  ...CostCallBaseShape
});
var CostReceiptBaseShape = {
  status: z.literal("settled"),
  ...CostCallBaseShape,
  inputTokens: TokenCount,
  outputTokens: TokenCount,
  cachedTokens: TokenCount.optional(),
  costUsd: NonNegative,
  costUnknown: z.boolean(),
  usageUnknown: z.boolean().default(false),
  pricing: CostPricingSchema.optional(),
  actualCostUsd: NonNegative.optional(),
  error: z.string().optional()
};
var LegacyCostReceiptSchema = z.strictObject(CostReceiptBaseShape).superRefine((receipt, ctx) => validateCostReceipt(receipt, ctx));
var CostReceiptSchema = z.strictObject({
  ...CostReceiptBaseShape,
  reasoningTokens: TokenCount.optional(),
  cacheWriteTokens: TokenCount.optional()
}).superRefine((receipt, ctx) => validateCostReceipt(receipt, ctx));
function validateCostReceipt(receipt, ctx) {
  if (receipt.reasoningTokens !== void 0 && receipt.reasoningTokens > receipt.outputTokens) {
    ctx.addIssue({ code: "custom", message: "reasoningTokens must not exceed outputTokens" });
  }
  if (receipt.actualCostUsd !== void 0) {
    if (receipt.costUnknown || receipt.costUsd !== receipt.actualCostUsd) {
      ctx.addIssue({ code: "custom", message: "actual cost must be known and equal costUsd" });
    }
    if (receipt.pricing !== void 0) {
      ctx.addIssue({ code: "custom", message: "actual cost must not include estimated pricing" });
    }
    return;
  }
  if (receipt.costUnknown) {
    if (receipt.costUsd !== 0) {
      ctx.addIssue({ code: "custom", message: "unknown cost must have costUsd 0" });
    }
    if (receipt.pricing !== void 0) {
      ctx.addIssue({ code: "custom", message: "unknown cost must not include estimated pricing" });
    }
    return;
  }
  if (receipt.usageUnknown) {
    ctx.addIssue({ code: "custom", message: "known estimated cost requires known usage" });
  }
  if (!receipt.pricing) {
    ctx.addIssue({ code: "custom", message: "known estimated cost requires a pricing snapshot" });
    return;
  }
  const expected = costFromPricing(receipt, receipt.pricing);
  if (receipt.costUsd !== expected) {
    ctx.addIssue({
      code: "custom",
      message: `estimated cost ${receipt.costUsd} does not match pricing snapshot ${expected}`
    });
  }
}
var CostLedgerEventSchema = z.union([
  z.strictObject({
    version: z.literal(1),
    record: z.union([PendingCostCallSchema, LegacyCostReceiptSchema])
  }),
  z.strictObject({
    version: z.literal(2),
    record: CostReceiptSchema
  }),
  z.strictObject({
    version: z.literal(1),
    completedTasks: TokenCount
  }),
  z.strictObject({
    version: z.literal(1),
    costCeilingUsd: NonNegative
  })
]);
function parseEvents(serialized) {
  const records = /* @__PURE__ */ new Map();
  let completedTasks = 0;
  let costCeilingUsd;
  let lineNumber = 0;
  try {
    for (const line of serialized.split("\n")) {
      if (!line.trim()) continue;
      lineNumber += 1;
      const event = CostLedgerEventSchema.parse(JSON.parse(line));
      if ("record" in event) {
        const record = event.record;
        validateTransition(records, record);
        records.set(record.callId, cloneRecord(record));
      } else if ("completedTasks" in event) {
        completedTasks += event.completedTasks;
        if (!Number.isSafeInteger(completedTasks)) {
          throw new ValidationError("CostLedger: completed task count exceeds safe integer range");
        }
      } else {
        if (costCeilingUsd !== void 0) {
          throw new ValidationError("CostLedger: duplicate persisted cost ceiling");
        }
        costCeilingUsd = event.costCeilingUsd;
      }
    }
    return {
      records: [...records.values()],
      completedTasks,
      ...costCeilingUsd === void 0 ? {} : { costCeilingUsd }
    };
  } catch (cause) {
    throw new ValidationError(
      `CostLedger: invalid persisted event ${lineNumber || 1}: ${validationMessage(cause)}`,
      { cause }
    );
  }
}
function validateTransition(records, record) {
  const current = records.get(record.callId);
  if (!current) return;
  if (record.status === "pending" || current.status === "settled") {
    throw new CostCallConflictError(`CostLedger: duplicate callId '${record.callId}'`);
  }
  if (!sameAttribution(current, record)) {
    throw new ValidationError(`CostLedger: receipt attribution changed for call '${record.callId}'`);
  }
}
function sameAttribution(before, after) {
  return before.channel === after.channel && before.phase === after.phase && before.actor === after.actor && before.maximumCostUsd === after.maximumCostUsd && before.timestamp === after.timestamp && JSON.stringify(before.tags ?? {}) === JSON.stringify(after.tags ?? {});
}
function parseReceipt(value, path) {
  try {
    return CostReceiptSchema.parse(value);
  } catch (cause) {
    throw new ValidationError(`CostLedger: invalid ${path}: ${validationMessage(cause)}`, { cause });
  }
}
function parseImportedReceipt(value, path) {
  if (typeof value !== "object" || value === null) return parseReceipt(value, path);
  const candidate = { ...value };
  if (candidate.status === "settled" && candidate.actualCostUsd === void 0 && candidate.costUnknown === false && candidate.pricing === void 0 && typeof candidate.model === "string") {
    const pricing = resolveModelPricing(candidate.model);
    if (pricing) {
      candidate.pricing = {
        inputUsdPerThousand: pricing.input,
        outputUsdPerThousand: pricing.output
      };
    }
  }
  return parseReceipt(candidate, path);
}
function validateAttribution(input) {
  assertString(input.channel, "channel");
  assertString(input.phase, "phase");
  assertString(input.actor, "actor");
  if (input.model !== void 0) assertString(input.model, "model");
  if (input.tags !== void 0) {
    const parsed = Tags.safeParse(input.tags);
    if (!parsed.success)
      throw new ValidationError(`CostLedger: invalid tags: ${parsed.error.message}`);
  }
}
function matches(record, filter) {
  if (!filter) return true;
  if (filter.channel !== void 0 && record.channel !== filter.channel) return false;
  if (filter.phase !== void 0 && record.phase !== filter.phase) return false;
  return Object.entries(filter.tags ?? {}).every(([key, value]) => record.tags?.[key] === value);
}
function cloneRecord(record) {
  if (record.status === "settled") return cloneReceipt(record);
  const { tags, ...rest } = record;
  return { ...rest, ...tags ? { tags: { ...tags } } : {} };
}
function cloneReceipt(receipt) {
  const { pricing, tags, ...rest } = receipt;
  return {
    ...rest,
    ...tags ? { tags: { ...tags } } : {},
    ...pricing ? { pricing: { ...pricing } } : {}
  };
}
function costFromPricing(usage, pricing) {
  return (usage.inputTokens + (usage.cachedTokens ?? 0) + (usage.cacheWriteTokens ?? 0)) / 1e3 * pricing.inputUsdPerThousand + usage.outputTokens / 1e3 * pricing.outputUsdPerThousand;
}
function emptyRollup(channel) {
  return {
    channel,
    calls: 0,
    inputTokens: 0,
    outputTokens: 0,
    reasoningTokens: 0,
    cachedTokens: 0,
    cacheWriteTokens: 0,
    costUsd: 0,
    unpricedCalls: 0,
    unknownUsageCalls: 0
  };
}
function pendingModel(input) {
  if (input.model) return input.model;
  if (input.maximumCharge && "model" in input.maximumCharge) return input.maximumCharge.model;
  return "unknown";
}
function unknownReceipt(model) {
  return { model, inputTokens: 0, outputTokens: 0, costUnknown: true, usageUnknown: true };
}
function resolveCallId(input) {
  if (input !== void 0) {
    assertString(input, "callId");
    return input;
  }
  if (typeof globalThis.crypto?.randomUUID !== "function") {
    throw new ValidationError("CostLedger: crypto.randomUUID is required when callId is omitted");
  }
  return globalThis.crypto.randomUUID();
}
function abortError(signal) {
  const reason = signal.reason;
  if (reason instanceof Error) return reason;
  const error = new Error("CostLedger: paid call aborted");
  error.name = "AbortError";
  return error;
}
function toError(value) {
  return value instanceof Error ? value : new Error(String(value));
}
function paidFailure(callId, error, receipt) {
  return {
    succeeded: false,
    callId,
    error,
    ...receipt ? { receipt: cloneReceipt(receipt) } : {}
  };
}
function validationMessage(cause) {
  return cause instanceof z.ZodError ? z.prettifyError(cause) : toError(cause).message;
}
function assertUsage(usage) {
  assertTokenCount(usage.inputTokens, "inputTokens");
  assertTokenCount(usage.outputTokens, "outputTokens");
  if (usage.reasoningTokens !== void 0) {
    assertTokenCount(usage.reasoningTokens, "reasoningTokens");
    if (usage.reasoningTokens > usage.outputTokens) {
      throw new ValidationError("CostLedger: reasoningTokens must not exceed outputTokens");
    }
  }
  if (usage.cachedTokens !== void 0) assertTokenCount(usage.cachedTokens, "cachedTokens");
  if (usage.cacheWriteTokens !== void 0) {
    assertTokenCount(usage.cacheWriteTokens, "cacheWriteTokens");
  }
}
function assertTokenCount(value, name) {
  if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
    throw new ValidationError(
      `CostLedger: ${name} must be a non-negative integer, got ${String(value)}`
    );
  }
}
function assertNonNegative(value, name) {
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
    throw new ValidationError(
      `CostLedger: ${name} must be a non-negative finite number, got ${String(value)}`
    );
  }
}
function assertTimeout(value, name) {
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > 2147483647) {
    throw new ValidationError(
      `CostLedger: ${name} must be a non-negative safe integer no greater than 2147483647, got ${String(value)}`
    );
  }
}
function assertString(value, name) {
  if (typeof value !== "string" || value.trim().length === 0) {
    throw new ValidationError(`CostLedger: ${name} must be a non-empty string`);
  }
}

export {
  CostCeilingReachedError,
  CostAccountingIncompleteError,
  CostReservationExceededError,
  CostCallConflictError,
  CostLedgerPersistenceError,
  CostReceiptCaptureError,
  CostLedger,
  modelPriceKey,
  costForUsage
};
//# sourceMappingURL=chunk-ZMXDQ4K7.js.map