// @bun
var __create = Object.create;
var __getProtoOf = Object.getPrototypeOf;
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __hasOwnProp = Object.prototype.hasOwnProperty;
function __accessProp(key) {
  return this[key];
}
var __toESMCache_node;
var __toESMCache_esm;
var __toESM = (mod, isNodeMode, target) => {
  var canCache = mod != null && typeof mod === "object";
  if (canCache) {
    var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
    var cached = cache.get(mod);
    if (cached)
      return cached;
  }
  target = mod != null ? __create(__getProtoOf(mod)) : {};
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
  for (let key of __getOwnPropNames(mod))
    if (!__hasOwnProp.call(to, key))
      __defProp(to, key, {
        get: __accessProp.bind(mod, key),
        enumerable: true
      });
  if (canCache)
    cache.set(mod, to);
  return to;
};
var __toCommonJS = (from) => {
  var entry = (__moduleCache ??= new WeakMap).get(from), desc;
  if (entry)
    return entry;
  entry = __defProp({}, "__esModule", { value: true });
  if (from && typeof from === "object" || typeof from === "function") {
    for (var key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(entry, key))
        __defProp(entry, key, {
          get: __accessProp.bind(from, key),
          enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
        });
  }
  __moduleCache.set(from, entry);
  return entry;
};
var __moduleCache;
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
var __returnValue = (v) => v;
function __exportSetter(name, newValue) {
  this[name] = __returnValue.bind(null, newValue);
}
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, {
      get: all[name],
      enumerable: true,
      configurable: true,
      set: __exportSetter.bind(all, name)
    });
};
var __legacyDecorateClassTS = function(decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
    r = Reflect.decorate(decorators, target, key, desc);
  else
    for (var i = decorators.length - 1;i >= 0; i--)
      if (d = decorators[i])
        r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __legacyMetadataTS = (k, v) => {
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
    return Reflect.metadata(k, v);
};
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
var __require = import.meta.require;

// src/ai/providers/openai.ts
var DEFAULT_BASE_URL = "https://api.openai.com";
var SSE_DATA_PREFIX_LENGTH = 6;
var DONE_SENTINEL = "[DONE]";
var NOT_FOUND = -1;
var isRecord = (value) => typeof value === "object" && value !== null;
var isRecordArray = (value) => Array.isArray(value) && value.length > 0 && isRecord(value[0]);
var hasArrayContent = (msg) => typeof msg.content !== "string" && Array.isArray(msg.content);
var buildToolMessages = (blocks) => {
  const toolUseBlocks = blocks.filter((block) => block.type === "tool_use");
  const toolResultBlocks = blocks.filter((block) => block.type === "tool_result");
  const messages = [];
  if (toolUseBlocks.length > 0) {
    messages.push({
      content: null,
      role: "assistant",
      tool_calls: toolUseBlocks.map((block) => ({
        function: {
          arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
          name: block.name
        },
        id: block.id,
        type: "function"
      }))
    });
  }
  for (const result of toolResultBlocks) {
    messages.push({
      content: typeof result.content === "string" ? result.content : "",
      role: "tool",
      tool_call_id: result.tool_use_id
    });
  }
  return messages;
};
var processMessageAtIndex = (result, msg, idx) => {
  if (!hasArrayContent(msg)) {
    return;
  }
  const hasToolBlocks = msg.content.some((block) => block.type === "tool_use" || block.type === "tool_result");
  if (!hasToolBlocks) {
    return;
  }
  const toolMessages = buildToolMessages(msg.content);
  result.splice(idx, 1, ...toolMessages);
};
var convertSingleMessage = (result, msg, idx) => {
  if (!msg) {
    return;
  }
  processMessageAtIndex(result, msg, idx);
};
var convertToolResultMessages = (messages, params) => {
  const result = [...messages];
  for (let idx = 0;idx < params.messages.length; idx++) {
    convertSingleMessage(result, params.messages[idx], idx);
  }
  return result;
};
var mapToolDefinitions = (tools) => tools.map((tool) => ({
  function: {
    description: tool.description,
    name: tool.name,
    parameters: tool.input_schema
  },
  type: "function"
}));
var mapContentBlockToOpenAI = (block) => {
  if (block.type === "image") {
    return {
      image_url: {
        url: `data:${block.source.media_type};base64,${block.source.data}`
      },
      type: "image_url"
    };
  }
  if (block.type === "document") {
    return {
      file: {
        file_data: `data:${block.source.media_type};base64,${block.source.data}`,
        filename: block.name ?? "document.pdf"
      },
      type: "file"
    };
  }
  if (block.type === "text") {
    return { text: block.content, type: "text" };
  }
  return null;
};
var mapOpenAIContent = (msg) => {
  if (typeof msg.content === "string") {
    return msg.content;
  }
  const hasMedia = msg.content.some((block) => block.type === "image" || block.type === "document");
  if (!hasMedia) {
    return null;
  }
  return msg.content.map(mapContentBlockToOpenAI).filter((mapped) => mapped !== null);
};
var buildRequestBody = (params) => {
  const messages = convertToolResultMessages(params.messages.map((msg) => ({
    content: mapOpenAIContent(msg),
    role: msg.role
  })), params);
  const body = {
    messages,
    model: params.model,
    stream: true,
    stream_options: { include_usage: true }
  };
  if (params.tools && params.tools.length > 0) {
    body.tools = mapToolDefinitions(params.tools);
  }
  return body;
};
var parseToolInput = (rawArguments) => {
  try {
    return JSON.parse(rawArguments);
  } catch {
    return rawArguments;
  }
};
var flushPendingToolCalls = function* (pendingToolCalls) {
  for (const [, tool] of pendingToolCalls) {
    const input = parseToolInput(tool.arguments);
    yield {
      id: tool.id,
      input,
      name: tool.name,
      type: "tool_use"
    };
  }
  pendingToolCalls.clear();
};
var extractUsage = (parsedUsage) => ({
  inputTokens: parsedUsage.prompt_tokens ?? 0,
  outputTokens: parsedUsage.completion_tokens ?? 0
});
var resolveToolCallIndex = (toolCall) => {
  const raw = typeof toolCall.index === "number" ? toolCall.index : NOT_FOUND;
  return raw < 0 ? undefined : raw;
};
var initPendingToolCall = (toolCall, func, index, pendingToolCalls) => {
  if (pendingToolCalls.has(index)) {
    return;
  }
  const toolId = typeof toolCall.id === "string" ? toolCall.id : "";
  const toolName = func && typeof func.name === "string" ? func.name : "";
  pendingToolCalls.set(index, {
    arguments: "",
    id: toolId,
    name: toolName
  });
};
var updatePendingToolCall = (toolCall, func, pending) => {
  if (typeof toolCall.id === "string") {
    pending.id = toolCall.id;
  }
  if (func && typeof func.name === "string") {
    pending.name = func.name;
  }
  if (func && typeof func.arguments === "string") {
    pending.arguments += func.arguments;
  }
};
var processToolCallDelta = (toolCall, pendingToolCalls) => {
  const index = resolveToolCallIndex(toolCall);
  if (index === undefined) {
    return;
  }
  const func = isRecord(toolCall.function) ? toolCall.function : null;
  initPendingToolCall(toolCall, func, index, pendingToolCalls);
  const pending = pendingToolCalls.get(index);
  if (!pending) {
    return;
  }
  updatePendingToolCall(toolCall, func, pending);
};
var processToolCallDeltas = (toolCalls, pendingToolCalls) => {
  for (const toolCall of toolCalls) {
    processToolCallDelta(toolCall, pendingToolCalls);
  }
};
var processDelta = function* (delta, pendingToolCalls) {
  if (typeof delta.content === "string") {
    yield { content: delta.content, type: "text" };
  }
  if (isRecordArray(delta.tool_calls)) {
    processToolCallDeltas(delta.tool_calls, pendingToolCalls);
  }
};
var processChoice = function* (choice, pendingToolCalls) {
  const delta = isRecord(choice.delta) ? choice.delta : null;
  if (delta) {
    yield* processDelta(delta, pendingToolCalls);
  }
  if (choice.finish_reason === "tool_calls") {
    yield* flushPendingToolCalls(pendingToolCalls);
  }
};
var narrowUsageRecord = (parsed) => {
  if (!isRecord(parsed.usage)) {
    return;
  }
  const { usage } = parsed;
  const promptTokens = typeof usage.prompt_tokens === "number" ? usage.prompt_tokens : 0;
  const completionTokens = typeof usage.completion_tokens === "number" ? usage.completion_tokens : 0;
  return extractUsage({
    completion_tokens: completionTokens,
    prompt_tokens: promptTokens
  });
};
var processSSELine = function* (line, pendingToolCalls, currentUsage) {
  const trimmed = line.trim();
  if (!trimmed || !trimmed.startsWith("data: ")) {
    return;
  }
  const data = trimmed.slice(SSE_DATA_PREFIX_LENGTH);
  if (data === DONE_SENTINEL) {
    yield* flushPendingToolCalls(pendingToolCalls);
    yield { type: "done", usage: currentUsage };
    return;
  }
  let parsed;
  try {
    parsed = JSON.parse(data);
  } catch {
    return;
  }
  const usageUpdate = narrowUsageRecord(parsed);
  if (usageUpdate) {
    yield { type: "usage_update", usage: usageUpdate };
  }
  const { choices } = parsed;
  if (!isRecordArray(choices)) {
    return;
  }
  const [firstChoice] = choices;
  if (!firstChoice) {
    return;
  }
  yield* processChoice(firstChoice, pendingToolCalls);
};
var isUsageUpdate = (chunk) => chunk.type === "usage_update";
var collectYieldableChunks = (line, pendingToolCalls, usageRef) => {
  const allChunks = Array.from(processSSELine(line, pendingToolCalls, usageRef.current));
  const usageChunks = allChunks.filter(isUsageUpdate);
  const lastUsage = usageChunks.at(NOT_FOUND);
  if (lastUsage) {
    usageRef.current = lastUsage.usage;
  }
  return allChunks.filter((chunk) => !isUsageUpdate(chunk));
};
var processSSELines = function* (lines, pendingToolCalls, usageRef) {
  for (const line of lines) {
    yield* collectYieldableChunks(line, pendingToolCalls, usageRef);
  }
};
var processStreamValue = (value, decoder, state) => {
  state.buffer += decoder.decode(value, { stream: true });
  const lines = state.buffer.split(`
`);
  state.buffer = lines.pop() ?? "";
  return lines;
};
var drainReader = async function* (reader, decoder, state, signal) {
  for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
    const lines = processStreamValue(result.value, decoder, state);
    yield* processSSELines(lines, state.pendingToolCalls, state.usageRef);
  }
};
var parseSSEStream = async function* (body, signal) {
  const reader = body.getReader();
  const decoder = new TextDecoder;
  const state = {
    buffer: "",
    pendingToolCalls: new Map,
    usageRef: { current: undefined }
  };
  try {
    yield* drainReader(reader, decoder, state, signal);
    yield { type: "done", usage: state.usageRef.current };
  } finally {
    reader.releaseLock();
  }
};
var fetchOpenAIStream = async function* (baseUrl, apiKey, body, signal) {
  const response = await fetch(`${baseUrl}/v1/chat/completions`, {
    body: JSON.stringify(body),
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json"
    },
    method: "POST",
    signal
  });
  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`OpenAI API error ${response.status}: ${errorText}`);
  }
  if (!response.body) {
    throw new Error("OpenAI API returned no response body");
  }
  yield* parseSSEStream(response.body, signal);
};
var openai = (config) => {
  const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
  return {
    stream: (params) => {
      const body = buildRequestBody(params);
      return fetchOpenAIStream(baseUrl, config.apiKey, body, params.signal);
    }
  };
};
export {
  openai
};

//# debugId=7DDBC3EC2735DE5764756E2164756E21
//# sourceMappingURL=openai.js.map
