import {
  __require,
  __toESM
} from "../index-55gkckqf.js";

// src/react/index.tsx
import {
  createContext,
  useContext,
  useState,
  useCallback,
  useEffect,
  useMemo,
  useRef
} from "react";

// src/detect.ts
async function checkWebGPU() {
  if (typeof navigator === "undefined")
    return false;
  if (!("gpu" in navigator))
    return false;
  try {
    const gpu = navigator.gpu;
    if (!gpu)
      return false;
    const adapter = await gpu.requestAdapter();
    return adapter !== null;
  } catch {
    return false;
  }
}
function checkWasm() {
  if (typeof WebAssembly === "undefined")
    return false;
  try {
    return typeof WebAssembly.instantiateStreaming === "function" || typeof WebAssembly.instantiate === "function";
  } catch {
    return false;
  }
}
async function detectCapabilities() {
  const webgpu = await checkWebGPU();
  const wasm = checkWasm();
  let recommendedBackend = "transformers";
  let recommendedDevice = "wasm";
  if (webgpu) {
    recommendedBackend = "webllm";
    recommendedDevice = "webgpu";
  } else if (wasm) {
    recommendedBackend = "transformers";
    recommendedDevice = "wasm";
  }
  return {
    webgpu,
    wasm,
    recommendedBackend,
    recommendedDevice
  };
}
async function logCapabilities() {
  const caps = await detectCapabilities();
  console.log("[LocalLLM] Browser Capabilities:");
  console.log(`  WebGPU: ${caps.webgpu ? "✓ supported" : "✗ not available"}`);
  console.log(`  WASM: ${caps.wasm ? "✓ supported" : "✗ not available"}`);
  console.log(`  Recommended backend: ${caps.recommendedBackend}`);
  console.log(`  Recommended device: ${caps.recommendedDevice}`);
  return caps;
}
// src/backends/webllm.ts
var DEFAULT_WEBLLM_MODEL = "Phi-3.5-mini-instruct-q4f16_1-MLC";
var WEBLLM_MODELS = {
  "llama-3.2-1b": "Llama-3.2-1B-Instruct-q4f16_1-MLC",
  "llama-3.2-3b": "Llama-3.2-3B-Instruct-q4f16_1-MLC",
  "llama-3.1-8b": "Llama-3.1-8B-Instruct-q4f16_1-MLC",
  "llama-3.1-8b-1k": "Llama-3.1-8B-Instruct-q4f16_1-MLC-1k",
  "phi-3.5-mini": "Phi-3.5-mini-instruct-q4f16_1-MLC",
  "phi-3.5-mini-1k": "Phi-3.5-mini-instruct-q4f16_1-MLC-1k",
  "phi-3.5-vision": "Phi-3.5-vision-instruct-q4f16_1-MLC",
  "qwen-2.5-0.5b": "Qwen2.5-0.5B-Instruct-q4f16_1-MLC",
  "qwen-2.5-1.5b": "Qwen2.5-1.5B-Instruct-q4f16_1-MLC",
  "qwen-2.5-3b": "Qwen2.5-3B-Instruct-q4f16_1-MLC",
  "qwen-2.5-7b": "Qwen2.5-7B-Instruct-q4f16_1-MLC",
  "qwen-2.5-coder-0.5b": "Qwen2.5-Coder-0.5B-Instruct-q4f16_1-MLC",
  "qwen-2.5-coder-1.5b": "Qwen2.5-Coder-1.5B-Instruct-q4f16_1-MLC",
  "qwen-3-0.6b": "Qwen3-0.6B-q4f16_1-MLC",
  "qwen-3-1.7b": "Qwen3-1.7B-q4f16_1-MLC",
  "qwen-3-4b": "Qwen3-4B-q4f16_1-MLC",
  "qwen-3-8b": "Qwen3-8B-q4f16_1-MLC",
  "gemma-2-2b": "gemma-2-2b-it-q4f16_1-MLC",
  "gemma-2-2b-1k": "gemma-2-2b-it-q4f16_1-MLC-1k",
  "gemma-2-9b": "gemma-2-9b-it-q4f16_1-MLC",
  "smollm2-135m": "SmolLM2-135M-Instruct-q0f16-MLC",
  "smollm2-360m": "SmolLM2-360M-Instruct-q4f16_1-MLC",
  "smollm2-1.7b": "SmolLM2-1.7B-Instruct-q4f16_1-MLC",
  "mistral-7b": "Mistral-7B-Instruct-v0.3-q4f16_1-MLC",
  "deepseek-r1-qwen-7b": "DeepSeek-R1-Distill-Qwen-7B-q4f16_1-MLC",
  "deepseek-r1-llama-8b": "DeepSeek-R1-Distill-Llama-8B-q4f16_1-MLC",
  "hermes-3-llama-3.2-3b": "Hermes-3-Llama-3.2-3B-q4f16_1-MLC",
  "hermes-3-llama-3.1-8b": "Hermes-3-Llama-3.1-8B-q4f16_1-MLC"
};
function resolveModelId(model) {
  if (model in WEBLLM_MODELS) {
    return WEBLLM_MODELS[model];
  }
  return model;
}

class WebLLMProvider {
  backend = "webllm";
  engine = null;
  currentModel = null;
  get isReady() {
    return this.engine !== null && this.currentModel !== null;
  }
  get modelId() {
    return this.currentModel;
  }
  async load(modelId, onProgress) {
    const resolvedModel = resolveModelId(modelId);
    const { CreateMLCEngine } = await import("../index-yyxm9rp0.js");
    const initProgressCallback = (report) => {
      if (onProgress) {
        const progress = {
          progress: Math.round(report.progress * 100),
          status: report.text
        };
        onProgress(progress);
      }
    };
    this.engine = await CreateMLCEngine(resolvedModel, {
      initProgressCallback
    });
    this.currentModel = resolvedModel;
  }
  async chat(messages, options) {
    if (!this.engine) {
      throw new Error("Model not loaded. Call load() first.");
    }
    const response = await this.engine.chat.completions.create({
      messages: messages.map((m) => ({
        role: m.role,
        content: m.content
      })),
      temperature: options?.temperature ?? 0.7,
      max_tokens: options?.maxTokens ?? 512,
      top_p: options?.topP ?? 0.95,
      stop: options?.stopSequences
    });
    return response.choices[0]?.message?.content ?? "";
  }
  async stream(messages, onToken, options) {
    if (!this.engine) {
      throw new Error("Model not loaded. Call load() first.");
    }
    const chunks = await this.engine.chat.completions.create({
      messages: messages.map((m) => ({
        role: m.role,
        content: m.content
      })),
      temperature: options?.temperature ?? 0.7,
      max_tokens: options?.maxTokens ?? 512,
      top_p: options?.topP ?? 0.95,
      stop: options?.stopSequences,
      stream: true
    });
    let fullText = "";
    for await (const chunk of chunks) {
      const token = chunk.choices[0]?.delta?.content ?? "";
      if (token) {
        fullText += token;
        onToken(token, fullText);
      }
    }
    return fullText;
  }
  async unload() {
    if (this.engine) {
      await this.engine.unload();
      this.engine = null;
      this.currentModel = null;
    }
  }
}
function createWebLLMProvider() {
  return new WebLLMProvider;
}
// src/backends/transformers.ts
var DEFAULT_TRANSFORMERS_MODEL = "onnx-community/Qwen2.5-0.5B-Instruct";
var TRANSFORMERS_MODELS = {
  "qwen-2.5-0.5b": "onnx-community/Qwen2.5-0.5B-Instruct",
  "qwen-2.5-1.5b": "onnx-community/Qwen2.5-1.5B-Instruct",
  "qwen-2.5-coder-0.5b": "onnx-community/Qwen2.5-Coder-0.5B-Instruct",
  "qwen-2.5-coder-1.5b": "onnx-community/Qwen2.5-Coder-1.5B-Instruct",
  "qwen-3-0.6b": "onnx-community/Qwen3-0.6B-ONNX",
  "smollm2-135m": "HuggingFaceTB/SmolLM2-135M-Instruct",
  "smollm2-360m": "HuggingFaceTB/SmolLM2-360M-Instruct",
  "smollm2-1.7b": "HuggingFaceTB/SmolLM2-1.7B-Instruct",
  "phi-3-mini": "Xenova/Phi-3-mini-4k-instruct",
  tinyllama: "Xenova/TinyLlama-1.1B-Chat-v1.0"
};
function detectChatFormat(modelId) {
  const lower = modelId.toLowerCase();
  if (lower.includes("qwen") || lower.includes("smollm")) {
    return "chatml";
  }
  if (lower.includes("llama") || lower.includes("tinyllama")) {
    return "llama";
  }
  if (lower.includes("phi")) {
    return "phi";
  }
  return "generic";
}
function formatPrompt(messages, modelId) {
  const format = detectChatFormat(modelId);
  switch (format) {
    case "chatml": {
      let prompt = "";
      for (const msg of messages) {
        prompt += `<|im_start|>${msg.role}
${msg.content}<|im_end|>
`;
      }
      prompt += `<|im_start|>assistant
`;
      return prompt;
    }
    case "llama": {
      let prompt = "";
      for (const msg of messages) {
        if (msg.role === "system") {
          prompt += `<s>[INST] <<SYS>>
${msg.content}
<</SYS>>

`;
        } else if (msg.role === "user") {
          if (!prompt.includes("[INST]")) {
            prompt += `<s>[INST] ${msg.content} [/INST]`;
          } else {
            prompt += `<s>[INST] ${msg.content} [/INST]`;
          }
        } else if (msg.role === "assistant") {
          prompt += ` ${msg.content} </s>`;
        }
      }
      return prompt;
    }
    case "phi": {
      let prompt = "";
      for (const msg of messages) {
        if (msg.role === "system") {
          prompt += `<|system|>
${msg.content}<|end|>
`;
        } else if (msg.role === "user") {
          prompt += `<|user|>
${msg.content}<|end|>
`;
        } else if (msg.role === "assistant") {
          prompt += `<|assistant|>
${msg.content}<|end|>
`;
        }
      }
      prompt += `<|assistant|>
`;
      return prompt;
    }
    case "generic":
    default: {
      let prompt = "";
      for (const msg of messages) {
        prompt += `${msg.role}: ${msg.content}
`;
      }
      prompt += "assistant: ";
      return prompt;
    }
  }
}
function mapQuantization(quantization) {
  const map = {
    q4: "q4",
    q8: "q8",
    fp16: "fp16",
    fp32: "fp32"
  };
  return map[quantization] ?? "q4";
}

class TransformersProvider {
  backend = "transformers";
  pipeline = null;
  currentModel = null;
  device;
  quantization;
  constructor(config = {}) {
    this.device = config.device ?? "auto";
    this.quantization = config.quantization ?? "q4";
  }
  get isReady() {
    return this.pipeline !== null && this.currentModel !== null;
  }
  get modelId() {
    return this.currentModel;
  }
  async load(modelId, onProgress) {
    const resolvedModel = modelId in TRANSFORMERS_MODELS ? TRANSFORMERS_MODELS[modelId] : modelId;
    const { pipeline, env } = await import("../transformers.web-1qr6h84s.js");
    env.allowLocalModels = false;
    env.useBrowserCache = true;
    let deviceOption = "wasm";
    if (this.device === "auto" || this.device === "webgpu") {
      if (typeof navigator !== "undefined" && "gpu" in navigator) {
        try {
          const gpu = navigator.gpu;
          const adapter = await gpu.requestAdapter();
          if (adapter) {
            deviceOption = "webgpu";
          }
        } catch {}
      }
    }
    const dtype = mapQuantization(this.quantization);
    this.pipeline = await pipeline("text-generation", resolvedModel, {
      dtype,
      device: deviceOption,
      progress_callback: (progress) => {
        if (onProgress) {
          const loadProgress = {
            progress: Math.round((progress.progress ?? 0) * 100),
            status: progress.status
          };
          onProgress(loadProgress);
        }
      }
    });
    this.currentModel = resolvedModel;
  }
  async chat(messages, options) {
    if (!this.pipeline || !this.currentModel) {
      throw new Error("Model not loaded. Call load() first.");
    }
    const prompt = formatPrompt(messages, this.currentModel);
    const result = await this.pipeline(prompt, {
      max_new_tokens: options?.maxTokens ?? 512,
      temperature: options?.temperature ?? 0.7,
      top_p: options?.topP ?? 0.95,
      do_sample: true,
      return_full_text: false
    });
    const output = Array.isArray(result) ? result[0] : result;
    return output.generated_text ?? "";
  }
  async stream(messages, onToken, options) {
    if (!this.pipeline || !this.currentModel) {
      throw new Error("Model not loaded. Call load() first.");
    }
    const prompt = formatPrompt(messages, this.currentModel);
    const { TextStreamer } = await import("../transformers.web-1qr6h84s.js");
    let fullText = "";
    const streamer = new TextStreamer(this.pipeline.tokenizer, {
      skip_prompt: true,
      callback_function: (token) => {
        fullText += token;
        onToken(token, fullText);
      }
    });
    await this.pipeline(prompt, {
      max_new_tokens: options?.maxTokens ?? 512,
      temperature: options?.temperature ?? 0.7,
      top_p: options?.topP ?? 0.95,
      do_sample: true,
      return_full_text: false,
      streamer
    });
    return fullText;
  }
  async unload() {
    this.pipeline = null;
    this.currentModel = null;
  }
}
function createTransformersProvider(config) {
  return new TransformersProvider(config);
}
// src/helpers.ts
function getElement(selector) {
  if (typeof selector === "string") {
    const el = document.querySelector(selector);
    if (!el) {
      throw new Error(`Element not found: ${selector}`);
    }
    return el;
  }
  return selector;
}
function createOutputStreamer(outputSelector, options) {
  const output = getElement(outputSelector);
  const append = options?.append ?? false;
  const scrollToBottom = options?.scrollToBottom ?? true;
  let baseContent = append ? output.textContent ?? "" : "";
  return (_token, fullText) => {
    if (output instanceof HTMLInputElement || output instanceof HTMLTextAreaElement) {
      output.value = baseContent + fullText;
    } else {
      output.textContent = baseContent + fullText;
    }
    if (scrollToBottom) {
      output.scrollTop = output.scrollHeight;
    }
  };
}
function attachToElements(inputSelector, outputSelector, generateFn, options) {
  const input = getElement(inputSelector);
  const output = getElement(outputSelector);
  const triggerOnEnter = options?.triggerOnEnter ?? true;
  const clearOnSend = options?.clearOnSend ?? true;
  const showLoading = options?.showLoading ?? true;
  const loadingText = options?.loadingText ?? "Thinking...";
  let isGenerating = false;
  const handleGenerate = async () => {
    if (isGenerating)
      return;
    const text = input.value.trim();
    if (!text)
      return;
    isGenerating = true;
    if (clearOnSend) {
      input.value = "";
    }
    if (showLoading) {
      if (output instanceof HTMLInputElement || output instanceof HTMLTextAreaElement) {
        output.value = loadingText;
      } else {
        output.textContent = loadingText;
      }
    }
    try {
      const streamer = createOutputStreamer(output);
      await generateFn(text, streamer);
    } catch (error) {
      const errorMsg = error instanceof Error ? error.message : "Generation failed";
      if (output instanceof HTMLInputElement || output instanceof HTMLTextAreaElement) {
        output.value = `Error: ${errorMsg}`;
      } else {
        output.textContent = `Error: ${errorMsg}`;
      }
    } finally {
      isGenerating = false;
    }
  };
  const keydownHandler = (e) => {
    if (triggerOnEnter && e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      handleGenerate();
    }
  };
  input.addEventListener("keydown", keydownHandler);
  return () => {
    input.removeEventListener("keydown", keydownHandler);
  };
}
function createChatUI(containerSelector) {
  const container = getElement(containerSelector);
  container.innerHTML = `
    <div class="llm-chat" style="display: flex; flex-direction: column; height: 100%; font-family: system-ui, sans-serif;">
      <div class="llm-chat-output" style="flex: 1; overflow-y: auto; padding: 1rem; border: 1px solid #e5e7eb; border-radius: 8px; margin-bottom: 1rem; min-height: 200px; background: #fafafa;">
        <p style="color: #9ca3af; margin: 0;">Start chatting...</p>
      </div>
      <div class="llm-chat-input-row" style="display: flex; gap: 0.5rem;">
        <textarea class="llm-chat-input" placeholder="Type a message..." style="flex: 1; padding: 0.75rem; border: 1px solid #e5e7eb; border-radius: 8px; resize: none; font-size: 1rem; font-family: inherit;"></textarea>
        <button class="llm-chat-send" style="padding: 0.75rem 1.5rem; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 1rem; font-weight: 500;">Send</button>
      </div>
    </div>
  `;
  const input = container.querySelector(".llm-chat-input");
  const output = container.querySelector(".llm-chat-output");
  const sendButton = container.querySelector(".llm-chat-send");
  const cleanup = () => {
    container.innerHTML = "";
  };
  return { input, output, sendButton, cleanup };
}
function createLoadingIndicator(containerSelector) {
  const container = getElement(containerSelector);
  const indicator = document.createElement("div");
  indicator.className = "llm-loading";
  indicator.style.cssText = `
    display: none;
    padding: 1rem;
    background: #f3f4f6;
    border-radius: 8px;
    text-align: center;
    font-family: system-ui, sans-serif;
  `;
  indicator.innerHTML = `
    <div class="llm-loading-progress" style="height: 4px; background: #e5e7eb; border-radius: 2px; overflow: hidden; margin-bottom: 0.5rem;">
      <div class="llm-loading-bar" style="height: 100%; width: 0%; background: #3b82f6; transition: width 0.2s;"></div>
    </div>
    <div class="llm-loading-status" style="font-size: 0.875rem; color: #6b7280;">Loading...</div>
  `;
  container.appendChild(indicator);
  const bar = indicator.querySelector(".llm-loading-bar");
  const status = indicator.querySelector(".llm-loading-status");
  return {
    show: () => {
      indicator.style.display = "block";
    },
    hide: () => {
      indicator.style.display = "none";
    },
    setProgress: (percent, statusText) => {
      bar.style.width = `${Math.min(100, Math.max(0, percent))}%`;
      if (statusText !== undefined) {
        status.textContent = statusText;
      }
    },
    element: indicator
  };
}
// src/core.ts
function normalizeMessages(input, systemPrompt) {
  const messages = [];
  if (systemPrompt) {
    messages.push({ role: "system", content: systemPrompt });
  }
  if (typeof input === "string") {
    messages.push({ role: "user", content: input });
  } else {
    messages.push(...input);
  }
  return messages;
}
async function createLLM(config = {}) {
  const {
    backend: requestedBackend = "auto",
    device = "auto",
    quantization = "q4",
    systemPrompt,
    onLoadProgress
  } = config;
  const capabilities = await detectCapabilities();
  let useBackend;
  if (requestedBackend === "auto") {
    useBackend = capabilities.webgpu ? "webllm" : "transformers";
  } else if (requestedBackend === "webllm") {
    if (!capabilities.webgpu) {
      console.warn("[LocalLLM] WebLLM requested but WebGPU not available. Falling back to Transformers.js");
      useBackend = "transformers";
    } else {
      useBackend = "webllm";
    }
  } else {
    useBackend = "transformers";
  }
  const model = config.model ?? (useBackend === "webllm" ? DEFAULT_WEBLLM_MODEL : DEFAULT_TRANSFORMERS_MODEL);
  console.log(`[LocalLLM] Using ${useBackend} backend with model: ${model}`);
  let provider;
  if (useBackend === "webllm") {
    provider = new WebLLMProvider;
  } else {
    provider = new TransformersProvider({ device, quantization });
  }
  await provider.load(model, onLoadProgress);
  const llm = {
    get isReady() {
      return provider.isReady;
    },
    get modelId() {
      return provider.modelId;
    },
    get backend() {
      return useBackend;
    },
    async chat(messages, options) {
      const normalizedMessages = normalizeMessages(messages, systemPrompt);
      return provider.chat(normalizedMessages, options);
    },
    async stream(messages, onToken, options) {
      const normalizedMessages = normalizeMessages(messages, systemPrompt);
      return provider.stream(normalizedMessages, onToken, options);
    },
    attachToInput(inputSelector, outputSelector, options) {
      return attachToElements(inputSelector, outputSelector, async (input, onToken) => {
        const normalizedMessages = normalizeMessages(input, systemPrompt);
        return provider.stream(normalizedMessages, onToken);
      }, options);
    },
    async unload() {
      await provider.unload();
    }
  };
  return llm;
}
async function isWebGPUSupported() {
  const caps = await detectCapabilities();
  return caps.webgpu;
}

// src/react/index.tsx
import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
var LLMContext = createContext(null);
function LLMProvider({
  children,
  autoLoad = true,
  onLoad,
  onProgress,
  onError,
  ...config
}) {
  const [llm, setLLM] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [loadProgress, setLoadProgress] = useState(null);
  const [error, setError] = useState(null);
  const hasLoadedRef = useRef(false);
  const configRef = useRef(config);
  configRef.current = config;
  const load = useCallback(async () => {
    if (isLoading)
      return;
    setIsLoading(true);
    setError(null);
    setLoadProgress({ progress: 0, status: "Initializing..." });
    try {
      const instance = await createLLM({
        ...configRef.current,
        onLoadProgress: (progress) => {
          setLoadProgress(progress);
          onProgress?.(progress);
        }
      });
      setLLM(instance);
      setLoadProgress({ progress: 100, status: "Ready" });
      onLoad?.(instance);
    } catch (err) {
      const error2 = err instanceof Error ? err : new Error(String(err));
      setError(error2);
      onError?.(error2);
    } finally {
      setIsLoading(false);
    }
  }, [isLoading, onLoad, onProgress, onError]);
  const unload = useCallback(async () => {
    if (llm) {
      await llm.unload();
      setLLM(null);
      setLoadProgress(null);
      hasLoadedRef.current = false;
    }
  }, [llm]);
  const reload = useCallback(async () => {
    await unload();
    await load();
  }, [unload, load]);
  useEffect(() => {
    if (autoLoad && !hasLoadedRef.current && !llm && !isLoading) {
      hasLoadedRef.current = true;
      load();
    }
  }, [autoLoad, llm, isLoading, load]);
  useEffect(() => {
    return () => {
      if (llm) {
        llm.unload().catch(console.error);
      }
    };
  }, [llm]);
  const value = useMemo(() => ({
    llm,
    isLoading,
    isReady: llm?.isReady ?? false,
    loadProgress,
    error,
    modelId: llm?.modelId ?? null,
    backend: llm?.backend ?? null,
    reload,
    unload
  }), [llm, isLoading, loadProgress, error, reload, unload]);
  return /* @__PURE__ */ jsxDEV(LLMContext.Provider, {
    value,
    children
  }, undefined, false, undefined, this);
}
function useLLM() {
  const context = useContext(LLMContext);
  if (!context) {
    throw new Error("useLLM must be used within an LLMProvider");
  }
  return context;
}
function useChat(options = {}) {
  const { llm, isReady, isLoading } = useLLM();
  const {
    initialMessages = [],
    systemPrompt,
    generateOptions,
    queueWhileLoading = true,
    onStart,
    onToken,
    onFinish,
    onError
  } = options;
  const [messages, setMessages] = useState(initialMessages);
  const [input, setInput] = useState("");
  const [isGenerating, setIsGenerating] = useState(false);
  const [streamingText, setStreamingText] = useState("");
  const [pendingMessage, setPendingMessage] = useState(null);
  const abortRef = useRef(false);
  const isProcessingRef = useRef(false);
  const generateResponse = useCallback(async (userContent, currentMessages) => {
    if (!llm || !isReady || isProcessingRef.current) {
      return "";
    }
    isProcessingRef.current = true;
    const userMessage = { role: "user", content: userContent };
    setMessages((prev) => [...prev, userMessage]);
    const apiMessages = [];
    if (systemPrompt) {
      apiMessages.push({ role: "system", content: systemPrompt });
    }
    apiMessages.push(...currentMessages, userMessage);
    setIsGenerating(true);
    setStreamingText("");
    abortRef.current = false;
    onStart?.();
    try {
      const response = await llm.stream(apiMessages, (token, fullText) => {
        if (abortRef.current)
          return;
        setStreamingText(fullText);
        onToken?.(token, fullText);
      }, generateOptions);
      if (!abortRef.current) {
        const assistantMessage = {
          role: "assistant",
          content: response
        };
        setMessages((prev) => [...prev, assistantMessage]);
        setStreamingText("");
        onFinish?.(response);
      }
      return response;
    } catch (err) {
      const error = err instanceof Error ? err : new Error(String(err));
      onError?.(error);
      return "";
    } finally {
      setIsGenerating(false);
      isProcessingRef.current = false;
    }
  }, [llm, isReady, systemPrompt, generateOptions, onStart, onToken, onFinish, onError]);
  useEffect(() => {
    if (isReady && pendingMessage && !isProcessingRef.current) {
      const messageToProcess = pendingMessage;
      setPendingMessage(null);
      generateResponse(messageToProcess, messages);
    }
  }, [isReady, pendingMessage, messages, generateResponse]);
  const send = useCallback(async (content) => {
    const messageContent = content ?? input;
    if (!messageContent.trim()) {
      return "";
    }
    if (!content) {
      setInput("");
    }
    if (llm && isReady) {
      return generateResponse(messageContent, messages);
    }
    if (isLoading && queueWhileLoading) {
      const userMessage = { role: "user", content: messageContent };
      setMessages((prev) => [...prev, userMessage]);
      setPendingMessage(messageContent);
      return "";
    }
    return "";
  }, [input, llm, isReady, isLoading, queueWhileLoading, messages, generateResponse]);
  const stop = useCallback(() => {
    abortRef.current = true;
    setIsGenerating(false);
    setPendingMessage(null);
    if (streamingText) {
      setMessages((prev) => [
        ...prev,
        { role: "assistant", content: streamingText + "..." }
      ]);
      setStreamingText("");
    }
  }, [streamingText]);
  const clear = useCallback(() => {
    setMessages(initialMessages);
    setStreamingText("");
    setInput("");
    setPendingMessage(null);
  }, [initialMessages]);
  const append = useCallback((message) => {
    setMessages((prev) => [...prev, message]);
  }, []);
  const reload = useCallback(async () => {
    if (messages.length === 0)
      return "";
    const lastUserIndex = messages.findLastIndex((m) => m.role === "user");
    if (lastUserIndex === -1)
      return "";
    const previousMessages = messages.slice(0, lastUserIndex);
    const lastUserMessage = messages[lastUserIndex];
    if (!lastUserMessage)
      return "";
    setMessages(previousMessages);
    return send(lastUserMessage.content);
  }, [messages, send]);
  return {
    messages,
    input,
    setInput,
    isGenerating,
    isPending: pendingMessage !== null,
    streamingText,
    send,
    stop,
    clear,
    append,
    reload
  };
}
function useStream(options = {}) {
  const { llm, isReady } = useLLM();
  const { generateOptions, onToken, onFinish, onError } = options;
  const [text, setText] = useState("");
  const [isStreaming, setIsStreaming] = useState(false);
  const abortRef = useRef(false);
  const stream = useCallback(async (input) => {
    if (!llm || !isReady) {
      return "";
    }
    setIsStreaming(true);
    setText("");
    abortRef.current = false;
    try {
      const response = await llm.stream(input, (token, fullText) => {
        if (abortRef.current)
          return;
        setText(fullText);
        onToken?.(token, fullText);
      }, generateOptions);
      onFinish?.(response);
      return response;
    } catch (err) {
      const error = err instanceof Error ? err : new Error(String(err));
      onError?.(error);
      return "";
    } finally {
      setIsStreaming(false);
    }
  }, [llm, isReady, generateOptions, onToken, onFinish, onError]);
  const stop = useCallback(() => {
    abortRef.current = true;
    setIsStreaming(false);
  }, []);
  const clear = useCallback(() => {
    setText("");
  }, []);
  return {
    text,
    isStreaming,
    stream,
    stop,
    clear
  };
}
function useCompletion(options = {}) {
  const { llm, isReady } = useLLM();
  const { generateOptions } = options;
  const [completion, setCompletion] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const complete = useCallback(async (prompt) => {
    if (!llm || !isReady) {
      return "";
    }
    setIsLoading(true);
    try {
      const response = await llm.chat(prompt, generateOptions);
      setCompletion(response);
      return response;
    } catch (err) {
      console.error("[useCompletion] Error:", err);
      return "";
    } finally {
      setIsLoading(false);
    }
  }, [llm, isReady, generateOptions]);
  const clear = useCallback(() => {
    setCompletion("");
  }, []);
  return {
    completion,
    isLoading,
    complete,
    clear
  };
}
function LLMLoading({ children, className }) {
  const { isLoading, loadProgress } = useLLM();
  if (!isLoading)
    return null;
  if (children) {
    return /* @__PURE__ */ jsxDEV("div", {
      className,
      children
    }, undefined, false, undefined, this);
  }
  return /* @__PURE__ */ jsxDEV("div", {
    className,
    children: [
      /* @__PURE__ */ jsxDEV("p", {
        children: [
          "Loading model... ",
          loadProgress?.progress ?? 0,
          "%"
        ]
      }, undefined, true, undefined, this),
      /* @__PURE__ */ jsxDEV("p", {
        children: loadProgress?.status
      }, undefined, false, undefined, this)
    ]
  }, undefined, true, undefined, this);
}
function LLMReady({ children, fallback = null }) {
  const { isReady, isLoading } = useLLM();
  if (isLoading || !isReady) {
    return /* @__PURE__ */ jsxDEV(Fragment, {
      children: fallback
    }, undefined, false, undefined, this);
  }
  return /* @__PURE__ */ jsxDEV(Fragment, {
    children
  }, undefined, false, undefined, this);
}
export {
  useStream,
  useLLM,
  useCompletion,
  useChat,
  LLMReady,
  LLMProvider,
  LLMLoading
};

export { checkWebGPU, checkWasm, detectCapabilities, logCapabilities, DEFAULT_WEBLLM_MODEL, WEBLLM_MODELS, WebLLMProvider, createWebLLMProvider, DEFAULT_TRANSFORMERS_MODEL, TRANSFORMERS_MODELS, TransformersProvider, createTransformersProvider, createOutputStreamer, attachToElements, createChatUI, createLoadingIndicator, createLLM, isWebGPUSupported, LLMProvider, useLLM, useChat, useStream, useCompletion, LLMLoading, LLMReady };

//# debugId=654DAC199C2102F264756E2164756E21
//# sourceMappingURL=index.js.map
