"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var llm_exports = {};
__export(llm_exports, {
  LLM: () => LLM,
  LLMStream: () => LLMStream
});
module.exports = __toCommonJS(llm_exports);
var import_openai = __toESM(require("openai"), 1);
var import_exceptions = require("../_exceptions.cjs");
var llm = __toESM(require("../llm/index.cjs"), 1);
var import_types = require("../types.cjs");
var import_utils = require("../utils.cjs");
var import_utils2 = require("./utils.cjs");
const REASONING_UNSUPPORTED_PARAMS = /* @__PURE__ */ new Set([
  "temperature",
  "top_p",
  "presence_penalty",
  "frequency_penalty",
  "logit_bias",
  "logprobs",
  "top_logprobs",
  "n"
]);
const XAI_REASONING_UNSUPPORTED_PARAMS = /* @__PURE__ */ new Set(["presence_penalty", "frequency_penalty", "stop"]);
const UNSUPPORTED_PARAMS = {
  o1: REASONING_UNSUPPORTED_PARAMS,
  o3: REASONING_UNSUPPORTED_PARAMS,
  o4: REASONING_UNSUPPORTED_PARAMS,
  "gpt-5": REASONING_UNSUPPORTED_PARAMS,
  "grok-4-1-fast-reasoning": XAI_REASONING_UNSUPPORTED_PARAMS,
  "grok-4.20-0309-reasoning": XAI_REASONING_UNSUPPORTED_PARAMS,
  "grok-4.20-multi-agent": XAI_REASONING_UNSUPPORTED_PARAMS
};
const REASONING_EFFORT_TOOL_INCOMPATIBLE_PREFIXES = /* @__PURE__ */ new Set(["gpt-5.2", "gpt-5.4"]);
function dropUnsupportedParams(model, params, tools) {
  const modelName = model.includes("/") ? model.split("/").pop() : model;
  let result = { ...params };
  for (const [prefix, unsupported] of Object.entries(UNSUPPORTED_PARAMS)) {
    if (modelName.startsWith(prefix)) {
      result = Object.fromEntries(Object.entries(result).filter(([k]) => !unsupported.has(k)));
      break;
    }
  }
  if (tools && tools.length > 0 && Array.from(REASONING_EFFORT_TOOL_INCOMPATIBLE_PREFIXES).some((p) => modelName.startsWith(p))) {
    const { reasoning_effort: _, ...rest } = result;
    result = rest;
  }
  return result;
}
class LLM extends llm.LLM {
  client;
  opts;
  constructor(opts) {
    super();
    const {
      model,
      provider,
      baseURL,
      apiKey,
      apiSecret,
      modelOptions,
      strictToolSchema = false,
      inferenceClass
    } = opts;
    const lkBaseURL = baseURL || (0, import_utils2.getDefaultInferenceUrl)();
    const lkApiKey = apiKey || process.env.LIVEKIT_INFERENCE_API_KEY || process.env.LIVEKIT_API_KEY;
    if (!lkApiKey) {
      throw new Error("apiKey is required: pass apiKey or set LIVEKIT_API_KEY");
    }
    const lkApiSecret = apiSecret || process.env.LIVEKIT_INFERENCE_API_SECRET || process.env.LIVEKIT_API_SECRET;
    if (!lkApiSecret) {
      throw new Error("apiSecret is required: pass apiSecret or set LIVEKIT_API_SECRET");
    }
    this.opts = {
      model,
      provider,
      baseURL: lkBaseURL,
      apiKey: lkApiKey,
      apiSecret: lkApiSecret,
      modelOptions: modelOptions || {},
      strictToolSchema,
      inferenceClass
    };
    this.client = new import_openai.default({
      baseURL: this.opts.baseURL,
      // Non-empty placeholder; replaced with a fresh access token before each
      // request (see LLMStream.run). openai >= 6.36.0 rejects an empty apiKey.
      apiKey: "placeholder"
    });
  }
  label() {
    return "inference.LLM";
  }
  get model() {
    return this.opts.model;
  }
  get provider() {
    return "livekit";
  }
  static fromModelString(modelString) {
    return new LLM({ model: modelString });
  }
  /**
   * Update LLM configuration options used by the next chat call.
   *
   * `modelOptions` replaces the persistent options object instead of merging;
   * pass `{}` to clear it.
   */
  updateOptions({
    model,
    modelOptions
  }) {
    if (model !== void 0) {
      this.opts.model = model;
    }
    if (modelOptions !== void 0) {
      this.opts.modelOptions = { ...modelOptions };
    }
  }
  chat({
    chatCtx,
    toolCtx,
    connOptions = import_types.DEFAULT_API_CONNECT_OPTIONS,
    parallelToolCalls,
    toolChoice,
    inferenceClass,
    extraKwargs
  }) {
    let modelOptions = { ...extraKwargs || {} };
    parallelToolCalls = parallelToolCalls !== void 0 ? parallelToolCalls : this.opts.modelOptions.parallel_tool_calls;
    if (toolCtx && Object.keys(toolCtx).length > 0 && parallelToolCalls !== void 0) {
      modelOptions.parallel_tool_calls = parallelToolCalls;
    }
    toolChoice = toolChoice !== void 0 ? toolChoice : this.opts.modelOptions.tool_choice;
    if (toolChoice) {
      modelOptions.tool_choice = toolChoice;
    }
    const resolvedInferenceClass = inferenceClass !== void 0 ? inferenceClass : this.opts.inferenceClass;
    modelOptions = { ...modelOptions, ...this.opts.modelOptions };
    return new LLMStream(this, {
      model: this.opts.model,
      provider: this.opts.provider,
      client: this.client,
      chatCtx,
      toolCtx,
      connOptions,
      modelOptions,
      strictToolSchema: this.opts.strictToolSchema ?? false,
      // default to false if not set
      gatewayOptions: {
        apiKey: this.opts.apiKey,
        apiSecret: this.opts.apiSecret
      },
      inferenceClass: resolvedInferenceClass
    });
  }
}
class LLMStream extends llm.LLMStream {
  model;
  provider;
  providerFmt;
  client;
  modelOptions;
  strictToolSchema;
  inferenceClass;
  gatewayOptions;
  toolCallId;
  toolIndex;
  fncName;
  fncRawArguments;
  toolExtra;
  constructor(llm2, {
    model,
    provider,
    client,
    chatCtx,
    toolCtx,
    gatewayOptions,
    connOptions,
    modelOptions,
    providerFmt,
    strictToolSchema,
    inferenceClass
  }) {
    super(llm2, { chatCtx, toolCtx, connOptions });
    this.client = client;
    this.gatewayOptions = gatewayOptions;
    this.provider = provider;
    this.providerFmt = providerFmt || "openai";
    this.modelOptions = modelOptions;
    this.model = model;
    this.strictToolSchema = strictToolSchema;
    this.inferenceClass = inferenceClass;
  }
  async run() {
    var _a;
    let retryable = true;
    this.toolCallId = this.fncName = this.fncRawArguments = this.toolIndex = void 0;
    this.toolExtra = void 0;
    try {
      const messages = await this.chatCtx.toProviderFormat(
        this.providerFmt
      );
      const tools = this.toolCtx ? llm.sortedToolEntries(this.toolCtx).map(([name, func]) => {
        const oaiParams = {
          type: "function",
          function: {
            name,
            description: func.description,
            parameters: llm.toJsonSchema(
              func.parameters,
              true,
              this.strictToolSchema
            )
          }
        };
        if (this.strictToolSchema) {
          oaiParams.function.strict = true;
        }
        return oaiParams;
      }) : void 0;
      const requestOptions = dropUnsupportedParams(
        this.model,
        { ...this.modelOptions },
        tools
      );
      if (!tools) {
        delete requestOptions.tool_choice;
      }
      if (this.gatewayOptions) {
        this.client.apiKey = await (0, import_utils2.createAccessToken)(
          this.gatewayOptions.apiKey,
          this.gatewayOptions.apiSecret
        );
      }
      const extraHeaders = {
        ...(0, import_utils2.buildMetadataHeaders)(),
        ...requestOptions.extra_headers ?? {}
      };
      const extraBody = requestOptions.extra_body;
      const extraQuery = requestOptions.extra_query;
      if (this.provider) {
        extraHeaders[import_utils2.INFERENCE_PROVIDER_HEADER] = this.provider;
      }
      if (this.inferenceClass !== void 0) {
        extraHeaders[import_utils2.INFERENCE_PRIORITY_HEADER] = this.inferenceClass;
      }
      delete requestOptions.extra_headers;
      delete requestOptions.extra_body;
      delete requestOptions.extra_query;
      const stream = await this.client.chat.completions.create(
        {
          model: this.model,
          messages,
          tools,
          stream: true,
          stream_options: { include_usage: true },
          ...requestOptions,
          ...extraBody
        },
        {
          headers: extraHeaders,
          query: extraQuery,
          timeout: this.connOptions.timeoutMs,
          signal: this.abortController.signal
        }
      );
      if (this.abortController.signal.aborted) {
        return;
      }
      for await (const chunk of stream) {
        if (this.abortController.signal.aborted) {
          break;
        }
        for (const choice of chunk.choices) {
          const chatChunk = this.parseChoice(chunk.id, choice);
          if (chatChunk) {
            retryable = false;
            this.queue.put(chatChunk);
          }
        }
        if (chunk.usage) {
          const usage = chunk.usage;
          retryable = false;
          this.queue.put({
            id: chunk.id,
            usage: {
              completionTokens: usage.completion_tokens,
              promptTokens: usage.prompt_tokens,
              promptCachedTokens: ((_a = usage.prompt_tokens_details) == null ? void 0 : _a.cached_tokens) || 0,
              totalTokens: usage.total_tokens
            }
          });
        }
      }
    } catch (error) {
      if (this.abortController.signal.aborted) {
        return;
      }
      if (error instanceof import_openai.default.APIConnectionTimeoutError) {
        throw new import_exceptions.APITimeoutError({ options: { retryable } });
      } else if (error instanceof import_openai.default.APIError) {
        throw new import_exceptions.APIStatusError({
          message: error.message,
          options: {
            statusCode: error.status,
            body: error.error,
            requestId: error.requestID,
            retryable
          }
        });
      } else {
        throw new import_exceptions.APIConnectionError({
          message: (0, import_utils.toError)(error).message,
          options: { retryable }
        });
      }
    }
  }
  parseChoice(id, choice) {
    const delta = choice.delta;
    if (delta === void 0) return void 0;
    if (delta.tool_calls) {
      for (const tool of delta.tool_calls) {
        if (!tool.function) {
          continue;
        }
        let callChunk;
        if (this.toolCallId && tool.id && tool.index !== this.toolIndex) {
          callChunk = this.createRunningToolCallChunk(id, delta);
          this.toolCallId = this.fncName = this.fncRawArguments = void 0;
        }
        if (tool.function.name) {
          this.toolIndex = tool.index;
          this.toolCallId = tool.id;
          this.fncName = tool.function.name;
          this.fncRawArguments = tool.function.arguments || "";
          const newToolExtra = (
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            tool.extra_content ?? void 0
          );
          if (newToolExtra) {
            this.toolExtra = newToolExtra;
          }
        } else if (tool.function.arguments) {
          this.fncRawArguments = (this.fncRawArguments || "") + tool.function.arguments;
        }
        if (callChunk) {
          return callChunk;
        }
      }
    }
    if (choice.finish_reason && ["tool_calls", "stop"].includes(choice.finish_reason) && this.toolCallId !== void 0) {
      const callChunk = this.createRunningToolCallChunk(id, delta);
      this.toolCallId = this.fncName = this.fncRawArguments = void 0;
      this.toolExtra = void 0;
      return callChunk;
    }
    const deltaExtra = (
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      delta.extra_content ?? void 0
    );
    if (!delta.content && !deltaExtra) {
      return void 0;
    }
    return {
      id,
      delta: {
        role: "assistant",
        content: delta.content || void 0,
        extra: deltaExtra
      }
    };
  }
  createRunningToolCallChunk(id, delta) {
    const toolExtra = this.toolExtra ? { ...this.toolExtra } : {};
    const thoughtSignature = this.extractThoughtSignature(toolExtra);
    const deltaExtra = (
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      delta.extra_content ?? void 0
    );
    return {
      id,
      delta: {
        role: "assistant",
        extra: deltaExtra,
        toolCalls: [
          llm.FunctionCall.create({
            callId: this.toolCallId || "",
            name: this.fncName || "",
            args: this.fncRawArguments || "",
            extra: toolExtra,
            thoughtSignature
          })
        ]
      }
    };
  }
  extractThoughtSignature(extra) {
    const googleExtra = extra == null ? void 0 : extra.google;
    if (googleExtra && typeof googleExtra === "object") {
      return googleExtra.thoughtSignature || googleExtra.thought_signature;
    }
    return void 0;
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  LLM,
  LLMStream
});
//# sourceMappingURL=llm.cjs.map