// src/trace/extract-usage.ts
import { SSEChunkParser } from "@tangle-network/agent-core/sse";
import {
  firstTokenCount,
  TOKEN_USAGE_INPUT_KEYS,
  TOKEN_USAGE_OUTPUT_KEYS,
  tokenUsageSource
} from "@tangle-network/agent-core/telemetry";
var INPUT_OTHER_KEYS = ["input_other"];
var EXCLUSIVE_REASONING_KEYS = ["reasoning", "reasoning_tokens", "reasoningTokens"];
var INCLUSIVE_REASONING_KEYS = ["reasoning_output_tokens", "reasoningOutputTokens"];
var INPUT_DETAIL_KEYS = ["prompt_tokens_details", "input_tokens_details"];
var OUTPUT_DETAIL_KEYS = ["completion_tokens_details", "output_tokens_details"];
var CACHED_KEYS = [
  "cache",
  "cached_tokens",
  "cached_input_tokens",
  "cache_read_tokens",
  "cache_read_input_tokens",
  "cachedTokens",
  "cachedInputTokens",
  "cacheReadTokens",
  "cacheReadInputTokens",
  "input_cache_read"
];
var CACHE_WRITE_KEYS = [
  "cache_creation_tokens",
  "cache_creation_input_tokens",
  "cacheCreationTokens",
  "cacheCreationInputTokens",
  "input_cache_creation"
];
function nestedRecord(source, key) {
  const value = source[key];
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
}
function nestedNumber(source, recordKeys, valueKeys) {
  for (const recordKey of recordKeys) {
    const value = firstTokenCount(nestedRecord(source, recordKey), valueKeys);
    if (value !== void 0) return value;
  }
  return void 0;
}
function extractUsage(body) {
  if (!body || typeof body !== "object") return null;
  const obj = body;
  const usage = tokenUsageSource(obj);
  const input = firstTokenCount(usage, TOKEN_USAGE_INPUT_KEYS);
  const inputOther = firstTokenCount(usage, INPUT_OTHER_KEYS);
  const output = firstTokenCount(usage, TOKEN_USAGE_OUTPUT_KEYS);
  const exclusiveReasoning = firstTokenCount(usage, EXCLUSIVE_REASONING_KEYS);
  const inclusiveReasoning = firstTokenCount(usage, INCLUSIVE_REASONING_KEYS) ?? nestedNumber(usage, OUTPUT_DETAIL_KEYS, ["reasoning_tokens", "reasoningTokens"]);
  const reasoning = exclusiveReasoning ?? inclusiveReasoning;
  const nestedCache = nestedRecord(usage, "cache");
  const cached = firstTokenCount(usage, CACHED_KEYS) ?? firstTokenCount(nestedCache, ["read"]) ?? nestedNumber(usage, INPUT_DETAIL_KEYS, ["cached_tokens", "cachedTokens"]);
  const cacheWrite = firstTokenCount(usage, CACHE_WRITE_KEYS) ?? firstTokenCount(nestedCache, ["write"]);
  if (input === void 0 && inputOther === void 0 && output === void 0 && reasoning === void 0 && cached === void 0 && cacheWrite === void 0)
    return null;
  const result = {
    input: (input ?? 0) + (inputOther ?? 0),
    output: (output ?? (inclusiveReasoning !== void 0 ? inclusiveReasoning : 0)) + (exclusiveReasoning ?? 0)
  };
  if (reasoning !== void 0) result.reasoning = reasoning;
  if (cached !== void 0) result.cached = cached;
  if (cacheWrite !== void 0) result.cacheWrite = cacheWrite;
  return result;
}
function extractUsageFromSse(text, options = {}) {
  const mode = options.mode ?? "cumulative";
  let input = 0;
  let output = 0;
  let reasoning = 0;
  let sawReasoning = false;
  let cached = 0;
  let sawCached = false;
  let cacheWrite = 0;
  let sawCacheWrite = false;
  let found = false;
  const parser = new SSEChunkParser({ transform: parseSseJson });
  const events = [...parser.push(text), ...parser.flush()];
  const merge = mode === "delta" ? (current, next) => current + next : Math.max;
  for (const event of events) {
    const usage = extractUsage(event.data);
    if (!usage) continue;
    input = merge(input, usage.input);
    output = merge(output, usage.output);
    if (usage.reasoning !== void 0) {
      reasoning = merge(reasoning, usage.reasoning);
      sawReasoning = true;
    }
    if (usage.cached !== void 0) {
      cached = merge(cached, usage.cached);
      sawCached = true;
    }
    if (usage.cacheWrite !== void 0) {
      cacheWrite = merge(cacheWrite, usage.cacheWrite);
      sawCacheWrite = true;
    }
    found = true;
  }
  if (!found) return null;
  return {
    input,
    output,
    ...sawReasoning ? { reasoning } : {},
    ...sawCached ? { cached } : {},
    ...sawCacheWrite ? { cacheWrite } : {}
  };
}
function parseSseJson(raw) {
  const payload = raw.trim();
  if (!payload || payload === "[DONE]") return null;
  try {
    return JSON.parse(payload);
  } catch {
    return null;
  }
}
async function extractUsageFromResponse(response, sseOptions) {
  let text;
  try {
    text = await response.clone().text();
  } catch {
    return null;
  }
  let json;
  try {
    json = JSON.parse(text);
  } catch {
    json = void 0;
  }
  return extractUsage(json) ?? extractUsageFromSse(text, sseOptions);
}

export {
  extractUsage,
  extractUsageFromSse,
  extractUsageFromResponse
};
//# sourceMappingURL=chunk-PXE2VKMX.js.map