// @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/gemini.ts
var DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com";
var SSE_DATA_PREFIX_LENGTH = 6;
var isRecord = (value) => typeof value === "object" && value !== null;
var isRecordArray = (value) => Array.isArray(value) && value.length > 0 && isRecord(value[0]);
var mapRole = (role) => {
  if (role === "assistant" || role === "system")
    return "model";
  return "user";
};
var mapContentBlock = (block) => {
  switch (block.type) {
    case "text":
      return { text: block.content };
    case "image":
      return {
        inlineData: {
          data: block.source.data,
          mimeType: block.source.media_type
        }
      };
    case "document":
      return {
        inlineData: {
          data: block.source.data,
          mimeType: block.source.media_type
        }
      };
    case "tool_use":
      return {
        functionCall: {
          args: typeof block.input === "string" ? JSON.parse(block.input) : block.input,
          name: block.name
        }
      };
    case "tool_result":
      return {
        functionResponse: {
          name: block.tool_use_id,
          response: { result: block.content }
        }
      };
    default:
      return null;
  }
};
var convertMessageContent = (content) => {
  if (typeof content === "string") {
    return [{ text: content }];
  }
  return content.map(mapContentBlock).filter((mapped) => mapped !== null);
};
var hasFunctionResponse = (content) => content.some((block) => block.type === "tool_result");
var convertSingleMessage = (msg) => {
  if (typeof msg.content !== "string" && hasFunctionResponse(msg.content)) {
    return { parts: convertMessageContent(msg.content), role: "user" };
  }
  return {
    parts: convertMessageContent(msg.content),
    role: mapRole(msg.role)
  };
};
var convertMessages = (messages) => messages.map(convertSingleMessage);
var mapToolDefinitions = (tools) => tools.map((tool) => ({
  description: tool.description,
  name: tool.name,
  parameters: tool.input_schema
}));
var buildRequestBody = (params, isImageModel) => {
  const body = {
    contents: convertMessages(params.messages)
  };
  if (isImageModel) {
    body.generationConfig = {
      responseModalities: ["TEXT", "IMAGE"]
    };
  }
  if (params.systemPrompt) {
    body.systemInstruction = {
      parts: [{ text: params.systemPrompt }]
    };
  }
  if (params.tools && params.tools.length > 0) {
    body.tools = [
      { functionDeclarations: mapToolDefinitions(params.tools) }
    ];
  }
  return body;
};
var extractMimeFormat = (mimeType) => {
  if (typeof mimeType !== "string") {
    return "png";
  }
  if (mimeType.includes("jpeg") || mimeType.includes("jpg"))
    return "jpeg";
  if (mimeType.includes("webp"))
    return "webp";
  return "png";
};
var processTextPart = function* (part) {
  if (typeof part.text === "string" && part.text) {
    yield { content: part.text, type: "text" };
  }
};
var processInlineDataPart = function* (inlineData) {
  const data = typeof inlineData.data === "string" ? inlineData.data : "";
  const { mimeType } = inlineData;
  if (!data) {
    return;
  }
  yield {
    data,
    format: extractMimeFormat(mimeType),
    isPartial: false,
    type: "image"
  };
};
var processFunctionCallPart = function* (functionCall) {
  const name = typeof functionCall.name === "string" ? functionCall.name : "";
  const args = functionCall.args ?? {};
  yield {
    id: `gemini-${name}-${Date.now()}`,
    input: args,
    name,
    type: "tool_use"
  };
};
var processPart = function* (part) {
  if ("text" in part) {
    yield* processTextPart(part);
  }
  if (isRecord(part.inlineData)) {
    yield* processInlineDataPart(part.inlineData);
  }
  if (isRecord(part.functionCall)) {
    yield* processFunctionCallPart(part.functionCall);
  }
};
var extractUsage = (parsed) => {
  if (!isRecord(parsed.usageMetadata)) {
    return;
  }
  const { usageMetadata } = parsed;
  return {
    inputTokens: typeof usageMetadata.promptTokenCount === "number" ? usageMetadata.promptTokenCount : 0,
    outputTokens: typeof usageMetadata.candidatesTokenCount === "number" ? usageMetadata.candidatesTokenCount : 0
  };
};
var processChunk = function* (parsed, state) {
  const usage = extractUsage(parsed);
  if (usage) {
    state.usage = usage;
  }
  if (!isRecordArray(parsed.candidates)) {
    return;
  }
  const [candidate] = parsed.candidates;
  if (!candidate || !isRecord(candidate.content)) {
    return;
  }
  const { content } = candidate;
  if (!isRecordArray(content.parts)) {
    return;
  }
  for (const part of content.parts) {
    yield* processPart(part);
  }
};
var processSSELine = function* (line, state) {
  const trimmed = line.trim();
  if (!trimmed || !trimmed.startsWith("data: ")) {
    return;
  }
  const data = trimmed.slice(SSE_DATA_PREFIX_LENGTH);
  let parsed;
  try {
    parsed = JSON.parse(data);
  } catch {
    return;
  }
  yield* processChunk(parsed, state);
};
var processSSEBuffer = function* (lines, state) {
  for (const line of lines) {
    yield* processSSELine(line, state);
  }
};
var drainReader = async function* (reader, decoder, state, signal) {
  let textBuffer = "";
  for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
    textBuffer += decoder.decode(result.value, { stream: true });
    const lines = textBuffer.split(`
`);
    textBuffer = lines.pop() ?? "";
    yield* processSSEBuffer(lines, state);
  }
  if (textBuffer.trim()) {
    yield* processSSELine(textBuffer, state);
  }
  yield { type: "done", usage: state.usage };
};
var parseSSEStream = async function* (body, signal) {
  const reader = body.getReader();
  const decoder = new TextDecoder;
  const state = {
    buffer: "",
    usage: undefined
  };
  try {
    yield* drainReader(reader, decoder, state, signal);
  } finally {
    reader.releaseLock();
  }
};
var fetchGeminiStream = async function* (baseUrl, apiKey, model, body, signal) {
  const url = `${baseUrl}/v1beta/models/${model}:streamGenerateContent?alt=sse&key=${apiKey}`;
  const response = await fetch(url, {
    body: JSON.stringify(body),
    headers: {
      "Content-Type": "application/json"
    },
    method: "POST",
    signal
  });
  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`Gemini API error ${response.status}: ${errorText}`);
  }
  if (!response.body) {
    throw new Error("Gemini API returned no response body");
  }
  yield* parseSSEStream(response.body, signal);
};
var resolveImageModels = (raw) => {
  if (!raw) {
    return new Set;
  }
  if (raw instanceof Set) {
    return raw;
  }
  return new Set(raw);
};
var gemini = (config) => {
  const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
  const imageModels = resolveImageModels(config.imageModels);
  return {
    stream: (params) => {
      const isImageModel = imageModels.has(params.model);
      const body = buildRequestBody(params, isImageModel);
      return fetchGeminiStream(baseUrl, config.apiKey, params.model, body, params.signal);
    }
  };
};
export {
  gemini
};

//# debugId=894B53B8FBF179F864756E2164756E21
//# sourceMappingURL=gemini.js.map
