{"version":3,"sources":["jsdelivr-header.js","/npm/@browser-ai/web-llm@2.1.7/src/index.ts","/node_modules/@ai-sdk/provider/src/errors/ai-sdk-error.ts","/node_modules/@ai-sdk/provider/src/errors/api-call-error.ts","/node_modules/@ai-sdk/provider/src/errors/empty-response-body-error.ts","/node_modules/@ai-sdk/provider/src/errors/get-error-message.ts","/node_modules/@ai-sdk/provider/src/errors/invalid-argument-error.ts","/node_modules/@ai-sdk/provider/src/errors/invalid-prompt-error.ts","/node_modules/@ai-sdk/provider/src/errors/invalid-response-data-error.ts","/node_modules/@ai-sdk/provider/src/errors/json-parse-error.ts","/node_modules/@ai-sdk/provider/src/errors/load-api-key-error.ts","/node_modules/@ai-sdk/provider/src/errors/load-setting-error.ts","/node_modules/@ai-sdk/provider/src/errors/no-content-generated-error.ts","/node_modules/@ai-sdk/provider/src/errors/no-such-model-error.ts","/node_modules/@ai-sdk/provider/src/errors/too-many-embedding-values-for-call-error.ts","/node_modules/@ai-sdk/provider/src/errors/type-validation-error.ts","/node_modules/@ai-sdk/provider/src/errors/unsupported-functionality-error.ts","/npm/@browser-ai/shared/src/utils/tool-utils.ts","/npm/@browser-ai/shared/src/utils/warnings.ts","/npm/@browser-ai/shared/src/tool-calling/build-json-system-prompt.ts","/npm/@browser-ai/shared/src/tool-calling/format-tool-results.ts","/npm/@browser-ai/shared/src/tool-calling/parse-json-function-calls.ts","/npm/@browser-ai/shared/src/streaming/tool-call-detector.ts","/npm/@browser-ai/shared/src/streaming/tool-call-stream-utils.ts","/npm/@browser-ai/shared/src/streaming/stream-processor.ts","/npm/@browser-ai/web-llm@2.1.7/src/utils/convert-to-webllm-messages.tsx","/npm/@browser-ai/web-llm@2.1.7/src/chat/web-llm-language-model.ts","/npm/@browser-ai/web-llm@2.1.7/src/utils/prompt-utils.ts","/npm/@browser-ai/web-llm@2.1.7/src/utils/browser.ts","/npm/@browser-ai/web-llm@2.1.7/src/embedding/web-llm-embedding-model.ts","/npm/@browser-ai/web-llm@2.1.7/src/web-llm-provider.ts"],"names":[],"mappings":"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","file":"/npm/@browser-ai/web-llm@2.1.7/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@browser-ai/web-llm@2.1.7/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","export {\n  WebLLMLanguageModel,\n  doesBrowserSupportWebLLM,\n} from \"./chat/web-llm-language-model\";\nexport type {\n  WebLLMModelId,\n  WebLLMSettings,\n} from \"./chat/web-llm-language-model\";\n\nexport { WebLLMEmbeddingModel } from \"./embedding/web-llm-embedding-model\";\nexport type {\n  WebLLMEmbeddingModelId,\n  WebLLMEmbeddingSettings,\n} from \"./embedding/web-llm-embedding-model\";\n\nexport type { WebLLMUIMessage, WebLLMProgress } from \"./types\";\n\nexport { WebWorkerMLCEngineHandler } from \"@mlc-ai/web-llm\";\n\nexport { webLLM, createWebLLM } from \"./web-llm-provider\";\nexport type { WebLLMProvider } from \"./web-llm-provider\";\n","/**\n * Symbol used for identifying AI SDK Error instances.\n * Enables checking if an error is an instance of AISDKError across package versions.\n */\nconst marker = 'vercel.ai.error';\nconst symbol = Symbol.for(marker);\n\n/**\n * Custom error class for AI SDK related errors.\n * @extends Error\n */\nexport class AISDKError extends Error {\n  private readonly [symbol] = true; // used in isInstance\n\n  /**\n   * The underlying cause of the error, if any.\n   */\n  readonly cause?: unknown;\n\n  /**\n   * Creates an AI SDK Error.\n   *\n   * @param {Object} params - The parameters for creating the error.\n   * @param {string} params.name - The name of the error.\n   * @param {string} params.message - The error message.\n   * @param {unknown} [params.cause] - The underlying cause of the error.\n   */\n  constructor({\n    name,\n    message,\n    cause,\n  }: {\n    name: string;\n    message: string;\n    cause?: unknown;\n  }) {\n    super(message);\n\n    this.name = name;\n    this.cause = cause;\n  }\n\n  /**\n   * Checks if the given error is an AI SDK Error.\n   * @param {unknown} error - The error to check.\n   * @returns {boolean} True if the error is an AI SDK Error, false otherwise.\n   */\n  static isInstance(error: unknown): error is AISDKError {\n    return AISDKError.hasMarker(error, marker);\n  }\n\n  protected static hasMarker(error: unknown, marker: string): boolean {\n    const markerSymbol = Symbol.for(marker);\n    return (\n      error != null &&\n      typeof error === 'object' &&\n      markerSymbol in error &&\n      typeof error[markerSymbol] === 'boolean' &&\n      error[markerSymbol] === true\n    );\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_APICallError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport class APICallError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  readonly url: string;\n  readonly requestBodyValues: unknown;\n  readonly statusCode?: number;\n\n  readonly responseHeaders?: Record<string, string>;\n  readonly responseBody?: string;\n\n  readonly isRetryable: boolean;\n  readonly data?: unknown;\n\n  constructor({\n    message,\n    url,\n    requestBodyValues,\n    statusCode,\n    responseHeaders,\n    responseBody,\n    cause,\n    isRetryable = statusCode != null &&\n      (statusCode === 408 || // request timeout\n        statusCode === 409 || // conflict\n        statusCode === 429 || // too many requests\n        statusCode >= 500), // server error\n    data,\n  }: {\n    message: string;\n    url: string;\n    requestBodyValues: unknown;\n    statusCode?: number;\n    responseHeaders?: Record<string, string>;\n    responseBody?: string;\n    cause?: unknown;\n    isRetryable?: boolean;\n    data?: unknown;\n  }) {\n    super({ name, message, cause });\n\n    this.url = url;\n    this.requestBodyValues = requestBodyValues;\n    this.statusCode = statusCode;\n    this.responseHeaders = responseHeaders;\n    this.responseBody = responseBody;\n    this.isRetryable = isRetryable;\n    this.data = data;\n  }\n\n  static isInstance(error: unknown): error is APICallError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_EmptyResponseBodyError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport class EmptyResponseBodyError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  constructor({ message = 'Empty response body' }: { message?: string } = {}) {\n    super({ name, message });\n  }\n\n  static isInstance(error: unknown): error is EmptyResponseBodyError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","export function getErrorMessage(error: unknown | undefined) {\n  if (error == null) {\n    return 'unknown error';\n  }\n\n  if (typeof error === 'string') {\n    return error;\n  }\n\n  if (error instanceof Error) {\n    return error.message;\n  }\n\n  return JSON.stringify(error);\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_InvalidArgumentError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * A function argument is invalid.\n */\nexport class InvalidArgumentError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  readonly argument: string;\n\n  constructor({\n    message,\n    cause,\n    argument,\n  }: {\n    argument: string;\n    message: string;\n    cause?: unknown;\n  }) {\n    super({ name, message, cause });\n\n    this.argument = argument;\n  }\n\n  static isInstance(error: unknown): error is InvalidArgumentError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_InvalidPromptError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * A prompt is invalid. This error should be thrown by providers when they cannot\n * process a prompt.\n */\nexport class InvalidPromptError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  readonly prompt: unknown;\n\n  constructor({\n    prompt,\n    message,\n    cause,\n  }: {\n    prompt: unknown;\n    message: string;\n    cause?: unknown;\n  }) {\n    super({ name, message: `Invalid prompt: ${message}`, cause });\n\n    this.prompt = prompt;\n  }\n\n  static isInstance(error: unknown): error is InvalidPromptError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_InvalidResponseDataError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * Server returned a response with invalid data content.\n * This should be thrown by providers when they cannot parse the response from the API.\n */\nexport class InvalidResponseDataError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  readonly data: unknown;\n\n  constructor({\n    data,\n    message = `Invalid response data: ${JSON.stringify(data)}.`,\n  }: {\n    data: unknown;\n    message?: string;\n  }) {\n    super({ name, message });\n\n    this.data = data;\n  }\n\n  static isInstance(error: unknown): error is InvalidResponseDataError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\nimport { getErrorMessage } from './get-error-message';\n\nconst name = 'AI_JSONParseError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport class JSONParseError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  readonly text: string;\n\n  constructor({ text, cause }: { text: string; cause: unknown }) {\n    super({\n      name,\n      message:\n        `JSON parsing failed: ` +\n        `Text: ${text}.\\n` +\n        `Error message: ${getErrorMessage(cause)}`,\n      cause,\n    });\n\n    this.text = text;\n  }\n\n  static isInstance(error: unknown): error is JSONParseError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_LoadAPIKeyError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport class LoadAPIKeyError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  constructor({ message }: { message: string }) {\n    super({ name, message });\n  }\n\n  static isInstance(error: unknown): error is LoadAPIKeyError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_LoadSettingError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport class LoadSettingError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  constructor({ message }: { message: string }) {\n    super({ name, message });\n  }\n\n  static isInstance(error: unknown): error is LoadSettingError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_NoContentGeneratedError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\nThrown when the AI provider fails to generate any content.\n */\nexport class NoContentGeneratedError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  constructor({\n    message = 'No content generated.',\n  }: { message?: string } = {}) {\n    super({ name, message });\n  }\n\n  static isInstance(error: unknown): error is NoContentGeneratedError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_NoSuchModelError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport class NoSuchModelError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  readonly modelId: string;\n  readonly modelType:\n    | 'languageModel'\n    | 'embeddingModel'\n    | 'imageModel'\n    | 'transcriptionModel'\n    | 'speechModel'\n    | 'rerankingModel';\n\n  constructor({\n    errorName = name,\n    modelId,\n    modelType,\n    message = `No such ${modelType}: ${modelId}`,\n  }: {\n    errorName?: string;\n    modelId: string;\n    modelType:\n      | 'languageModel'\n      | 'embeddingModel'\n      | 'imageModel'\n      | 'transcriptionModel'\n      | 'speechModel'\n      | 'rerankingModel';\n    message?: string;\n  }) {\n    super({ name: errorName, message });\n\n    this.modelId = modelId;\n    this.modelType = modelType;\n  }\n\n  static isInstance(error: unknown): error is NoSuchModelError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_TooManyEmbeddingValuesForCallError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport class TooManyEmbeddingValuesForCallError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  readonly provider: string;\n  readonly modelId: string;\n  readonly maxEmbeddingsPerCall: number;\n  readonly values: Array<unknown>;\n\n  constructor(options: {\n    provider: string;\n    modelId: string;\n    maxEmbeddingsPerCall: number;\n    values: Array<unknown>;\n  }) {\n    super({\n      name,\n      message:\n        `Too many values for a single embedding call. ` +\n        `The ${options.provider} model \"${options.modelId}\" can only embed up to ` +\n        `${options.maxEmbeddingsPerCall} values per call, but ${options.values.length} values were provided.`,\n    });\n\n    this.provider = options.provider;\n    this.modelId = options.modelId;\n    this.maxEmbeddingsPerCall = options.maxEmbeddingsPerCall;\n    this.values = options.values;\n  }\n\n  static isInstance(\n    error: unknown,\n  ): error is TooManyEmbeddingValuesForCallError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\nimport { getErrorMessage } from './get-error-message';\n\nconst name = 'AI_TypeValidationError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport class TypeValidationError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  readonly value: unknown;\n\n  constructor({ value, cause }: { value: unknown; cause: unknown }) {\n    super({\n      name,\n      message:\n        `Type validation failed: ` +\n        `Value: ${JSON.stringify(value)}.\\n` +\n        `Error message: ${getErrorMessage(cause)}`,\n      cause,\n    });\n\n    this.value = value;\n  }\n\n  static isInstance(error: unknown): error is TypeValidationError {\n    return AISDKError.hasMarker(error, marker);\n  }\n\n  /**\n   * Wraps an error into a TypeValidationError.\n   * If the cause is already a TypeValidationError with the same value, it returns the cause.\n   * Otherwise, it creates a new TypeValidationError.\n   *\n   * @param {Object} params - The parameters for wrapping the error.\n   * @param {unknown} params.value - The value that failed validation.\n   * @param {unknown} params.cause - The original error or cause of the validation failure.\n   * @returns {TypeValidationError} A TypeValidationError instance.\n   */\n  static wrap({\n    value,\n    cause,\n  }: {\n    value: unknown;\n    cause: unknown;\n  }): TypeValidationError {\n    return TypeValidationError.isInstance(cause) && cause.value === value\n      ? cause\n      : new TypeValidationError({ value, cause });\n  }\n}\n","import { AISDKError } from './ai-sdk-error';\n\nconst name = 'AI_UnsupportedFunctionalityError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport class UnsupportedFunctionalityError extends AISDKError {\n  private readonly [symbol] = true; // used in isInstance\n\n  readonly functionality: string;\n\n  constructor({\n    functionality,\n    message = `'${functionality}' functionality not supported.`,\n  }: {\n    functionality: string;\n    message?: string;\n  }) {\n    super({ name, message });\n    this.functionality = functionality;\n  }\n\n  static isInstance(error: unknown): error is UnsupportedFunctionalityError {\n    return AISDKError.hasMarker(error, marker);\n  }\n}\n","/**\n * Utilities for working with AI SDK tools\n */\n\nimport type {\n  LanguageModelV3FunctionTool,\n  LanguageModelV3ProviderTool,\n} from \"@ai-sdk/provider\";\n\n/**\n * Type guard to check if a tool is a function tool\n *\n * @param tool - The tool to check\n * @returns true if the tool is a LanguageModelV3FunctionTool\n */\nexport function isFunctionTool(\n  tool: LanguageModelV3FunctionTool | LanguageModelV3ProviderTool,\n): tool is LanguageModelV3FunctionTool {\n  return tool.type === \"function\";\n}\n","/**\n * Warning generation utilities for unsupported settings and tools\n */\n\nimport type {\n  SharedV3Warning,\n  LanguageModelV3ProviderTool,\n} from \"@ai-sdk/provider\";\n\n/**\n * Creates a warning for an unsupported setting\n *\n * @param setting - Name of the setting that is not supported\n * @param details - Additional details about why it's not supported\n * @returns A call warning object\n *\n * @example\n * ```typescript\n * const warning = createUnsupportedSettingWarning(\n *   \"maxOutputTokens\",\n *   \"maxOutputTokens is not supported by this provider\"\n * );\n * ```\n */\nexport function createUnsupportedSettingWarning(\n  feature: string,\n  details: string,\n): SharedV3Warning {\n  return {\n    type: \"unsupported\",\n    feature,\n    details,\n  };\n}\n\n/**\n * Creates a warning for an unsupported tool type\n *\n * @param tool - The provider-defined tool that is not supported\n * @param details - Additional details about why it's not supported\n * @returns A call warning object\n *\n * @example\n * ```typescript\n * const warning = createUnsupportedToolWarning(\n *   providerTool,\n *   \"Only function tools are supported\"\n * );\n * ```\n */\nexport function createUnsupportedToolWarning(\n  tool: LanguageModelV3ProviderTool,\n  details: string,\n): SharedV3Warning {\n  return {\n    type: \"unsupported\",\n    feature: `tool:${tool.name}`,\n    details,\n  };\n}\n","import type {\n  JSONSchema7,\n  LanguageModelV3FunctionTool,\n} from \"@ai-sdk/provider\";\nimport type { ToolDefinition } from \"../types\";\n\n/**\n * Builds an enhanced system prompt for JSON-based tool calling.\n * The model receives JSON schemas and is expected to return JSON tool calls.\n *\n * @param originalSystemPrompt - The original system prompt (if any)\n * @param tools - Array of available tool definitions\n * @param options - Configuration options for tool calling behavior (unused, kept for backwards compatibility)\n * @returns Enhanced system prompt with JSON tool calling instructions\n */\nexport function buildJsonToolSystemPrompt(\n  originalSystemPrompt: string | undefined,\n  tools: Array<ToolDefinition | LanguageModelV3FunctionTool>,\n  options?: { allowParallelToolCalls?: boolean },\n): string {\n  if (!tools || tools.length === 0) {\n    return originalSystemPrompt || \"\";\n  }\n\n  const parallelInstruction =\n    \"Only request one tool call at a time. Wait for tool results before asking for another tool.\";\n\n  const toolSchemas = tools.map((tool) => {\n    const schema = getParameters(tool);\n    return {\n      name: tool.name,\n      description: tool.description ?? \"No description provided.\",\n      parameters: schema || { type: \"object\", properties: {} },\n    };\n  });\n\n  const toolsJson = JSON.stringify(toolSchemas, null, 2);\n\n  const instructionBody = `You are a helpful AI assistant with access to tools.\n\n# Available Tools\n${toolsJson}\n\n# Tool Calling Instructions\n${parallelInstruction}\n\nTo call a tool, output JSON in this exact format inside a \\`\\`\\`tool_call code fence:\n\n\\`\\`\\`tool_call\n{\"name\": \"tool_name\", \"arguments\": {\"param1\": \"value1\", \"param2\": \"value2\"}}\n\\`\\`\\`\n\nTool responses will be provided in \\`\\`\\`tool_result fences. Each line contains JSON like:\n\\`\\`\\`tool_result\n{\"id\": \"call_123\", \"name\": \"tool_name\", \"result\": {...}, \"error\": false}\n\\`\\`\\`\nUse the \\`result\\` payload (and treat \\`error\\` as a boolean flag) when continuing the conversation.\n\nImportant:\n- Use exact tool and parameter names from the schema above\n- Arguments must be a valid JSON object matching the tool's parameters\n- You can include brief reasoning before or after the tool call\n- If no tool is needed, respond directly without tool_call fences`;\n\n  if (originalSystemPrompt?.trim()) {\n    return `${originalSystemPrompt.trim()}\\n\\n${instructionBody}`;\n  }\n\n  return instructionBody;\n}\n\n/**\n * Extracts the parameters/input schema from a tool definition.\n * Handles both ToolDefinition (parameters field) and LanguageModelV3FunctionTool (inputSchema field).\n *\n * @param tool - The tool definition to extract parameters from\n * @returns The JSON Schema for the tool's parameters, or undefined if not present\n */\nfunction getParameters(\n  tool: ToolDefinition | LanguageModelV3FunctionTool,\n): JSONSchema7 | undefined {\n  if (\"parameters\" in tool) {\n    return tool.parameters;\n  }\n\n  return tool.inputSchema as JSONSchema7 | undefined;\n}\n","import type { ToolResult } from \"../types\";\n\n/**\n * Builds a JSON-serializable payload for a single tool result.\n * Includes tool name, result data, error flag, and optional call ID.\n *\n * @param result - The tool execution result to format\n * @returns Object containing formatted result data ready for JSON serialization\n */\nfunction buildResultPayload(result: ToolResult): Record<string, unknown> {\n  const payload: Record<string, unknown> = {\n    name: result.toolName,\n    result: result.result ?? null,\n    error: Boolean(result.isError),\n  };\n\n  if (result.toolCallId) {\n    payload.id = result.toolCallId;\n  }\n\n  return payload;\n}\n\n/**\n * Formats tool execution results as JSON for continuation in the conversation.\n *\n * Each result is serialized as a single JSON object. Multiple results (for parallel\n * execution scenarios) are emitted on separate lines within a ```tool_result code fence.\n *\n * @param results - Array of tool execution results to format\n * @returns Formatted string with results in tool_result code fence, or empty string if no results\n * @example\n * ```typescript\n * formatToolResults([\n *   { toolCallId: \"call_123\", toolName: \"search\", result: { data: \"...\" } }\n * ])\n * // Returns: ```tool_result\\n{\"id\":\"call_123\",\"name\":\"search\",\"result\":{...},\"error\":false}\\n```\n * ```\n */\nexport function formatToolResults(results: ToolResult[]): string {\n  if (!results || results.length === 0) {\n    return \"\";\n  }\n\n  const payloads = results.map((result) =>\n    JSON.stringify(buildResultPayload(result)),\n  );\n\n  return `\\`\\`\\`tool_result\n${payloads.join(\"\\n\")}\n\\`\\`\\``;\n}\n\n/**\n * Formats a single tool result.\n * Convenience wrapper around formatToolResults for single result scenarios.\n *\n * @param result - The tool execution result to format\n * @returns Formatted string with result in tool_result code fence\n */\nexport function formatSingleToolResult(result: ToolResult): string {\n  return formatToolResults([result]);\n}\n","import type { ParsedResponse, ParsedToolCall } from \"../types\";\n\n/**\n * Options for configuring the JSON function call parser\n */\nexport interface ParseJsonFunctionCallsOptions {\n  /** Support XML-style tags: <tool_call>...</tool_call> */\n  supportXmlTags?: boolean;\n  /** Support Python-style: [functionName(arg=\"value\")] */\n  supportPythonStyle?: boolean;\n  /** Support \"parameters\" as alias for \"arguments\" (Llama format) */\n  supportParametersField?: boolean;\n}\n\nconst DEFAULT_OPTIONS: ParseJsonFunctionCallsOptions = {\n  supportXmlTags: true,\n  supportPythonStyle: true,\n  supportParametersField: true,\n};\n\nfunction generateToolCallId(): string {\n  return `call_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\n}\n\nfunction buildRegex(options: ParseJsonFunctionCallsOptions): RegExp {\n  const patterns: string[] = [];\n\n  // Always support markdown fences\n  patterns.push(\"```tool[_-]?call\\\\s*([\\\\s\\\\S]*?)```\");\n\n  if (options.supportXmlTags) {\n    patterns.push(\"<tool_call>\\\\s*([\\\\s\\\\S]*?)\\\\s*</tool_call>\");\n  }\n\n  if (options.supportPythonStyle) {\n    patterns.push(\"\\\\[(\\\\w+)\\\\(([^)]*)\\\\)\\\\]\");\n  }\n\n  return new RegExp(patterns.join(\"|\"), \"gi\");\n}\n\n/**\n * Parses JSON-formatted tool calls from model response.\n * Supports multiple formats:\n * 1. Single object: {\"name\": \"tool\", \"arguments\": {...}} or {\"name\": \"tool\", \"parameters\": {...}}\n * 2. Array: [{\"name\": \"tool1\", ...}, {\"name\": \"tool2\", ...}]\n * 3. Newline-separated objects:\n *    {\"name\": \"tool1\", \"arguments\": {...}}\n *    {\"name\": \"tool2\", \"arguments\": {...}}\n *\n * Note: Handles both \"arguments\" (OpenAI/Mistral format) and \"parameters\" (Llama format)\n *\n * @param response - The model's response text to parse\n * @param options - Configuration options for parsing\n * @returns Object containing parsed tool calls and remaining text content\n */\nexport function parseJsonFunctionCalls(\n  response: string,\n  options: ParseJsonFunctionCallsOptions = DEFAULT_OPTIONS,\n): ParsedResponse {\n  const mergedOptions = { ...DEFAULT_OPTIONS, ...options };\n  const regex = buildRegex(mergedOptions);\n\n  const matches = Array.from(response.matchAll(regex));\n  regex.lastIndex = 0;\n\n  if (matches.length === 0) {\n    return { toolCalls: [], textContent: response };\n  }\n\n  const toolCalls: ParsedToolCall[] = [];\n  let textContent = response;\n\n  for (const match of matches) {\n    const fullMatch = match[0];\n    textContent = textContent.replace(fullMatch, \"\");\n\n    try {\n      // Check for Python-style match: [functionName(args)]\n      if (mergedOptions.supportPythonStyle && match[0].startsWith(\"[\")) {\n        const pythonMatch = /\\[(\\w+)\\(([^)]*)\\)\\]/.exec(match[0]);\n        if (pythonMatch) {\n          const [, funcName, pythonArgs] = pythonMatch;\n          const args: Record<string, unknown> = {};\n\n          if (pythonArgs && pythonArgs.trim()) {\n            const argPairs = pythonArgs.split(\",\").map((s) => s.trim());\n            for (const pair of argPairs) {\n              const equalIndex = pair.indexOf(\"=\");\n              if (equalIndex > 0) {\n                const key = pair.substring(0, equalIndex).trim();\n                let value = pair.substring(equalIndex + 1).trim();\n                if (\n                  (value.startsWith('\"') && value.endsWith('\"')) ||\n                  (value.startsWith(\"'\") && value.endsWith(\"'\"))\n                ) {\n                  value = value.substring(1, value.length - 1);\n                }\n                args[key] = value;\n              }\n            }\n          }\n\n          toolCalls.push({\n            type: \"tool-call\",\n            toolCallId: generateToolCallId(),\n            toolName: funcName,\n            args: args,\n          });\n          continue;\n        }\n      }\n\n      // Get the captured content from the first capturing group\n      const innerContent = match[1] || match[2] || \"\";\n      const trimmed = innerContent.trim();\n\n      if (!trimmed) continue;\n\n      // Try parsing as a single JSON value first (object or array)\n      try {\n        const parsed = JSON.parse(trimmed);\n        const callsArray = Array.isArray(parsed) ? parsed : [parsed];\n\n        for (const call of callsArray) {\n          if (!call.name) continue;\n\n          let args =\n            call.arguments ||\n            (mergedOptions.supportParametersField ? call.parameters : null) ||\n            {};\n\n          // If args is a string, try to parse it as JSON\n          if (typeof args === \"string\") {\n            try {\n              args = JSON.parse(args);\n            } catch {\n              // If parsing fails, keep it as string\n            }\n          }\n\n          toolCalls.push({\n            type: \"tool-call\",\n            toolCallId: call.id || generateToolCallId(),\n            toolName: call.name,\n            args: args,\n          });\n        }\n      } catch {\n        // If single JSON parsing fails, try parsing as newline-separated JSON objects\n        const lines = trimmed.split(\"\\n\").filter((line) => line.trim());\n\n        for (const line of lines) {\n          try {\n            const call = JSON.parse(line.trim());\n            if (!call.name) continue;\n\n            let args =\n              call.arguments ||\n              (mergedOptions.supportParametersField ? call.parameters : null) ||\n              {};\n\n            if (typeof args === \"string\") {\n              try {\n                args = JSON.parse(args);\n              } catch {\n                // If parsing fails, keep it as string\n              }\n            }\n\n            toolCalls.push({\n              type: \"tool-call\",\n              toolCallId: call.id || generateToolCallId(),\n              toolName: call.name,\n              args: args,\n            });\n          } catch {\n            // Skip invalid JSON lines\n            continue;\n          }\n        }\n      }\n    } catch (error) {\n      console.warn(\"Failed to parse JSON tool call:\", error);\n      continue;\n    }\n  }\n\n  textContent = textContent.replace(/\\n{2,}/g, \"\\n\");\n\n  return { toolCalls, textContent: textContent.trim() };\n}\n\n/**\n * Checks if a response contains JSON function calls\n */\nexport function hasJsonFunctionCalls(\n  response: string,\n  options: ParseJsonFunctionCallsOptions = DEFAULT_OPTIONS,\n): boolean {\n  const regex = buildRegex({ ...DEFAULT_OPTIONS, ...options });\n  const hasMatch = regex.test(response);\n  regex.lastIndex = 0;\n  return hasMatch;\n}\n\n/**\n * Extracts the first JSON function call block from a response\n */\nexport function extractJsonFunctionCallsBlock(\n  response: string,\n  options: ParseJsonFunctionCallsOptions = DEFAULT_OPTIONS,\n): string | null {\n  const regex = buildRegex({ ...DEFAULT_OPTIONS, ...options });\n  const match = regex.exec(response);\n  regex.lastIndex = 0;\n  return match ? match[0] : null;\n}\n","/**\n * ToolCallFenceDetector - Detects and extracts tool call fences from streaming text\n *\n * This module handles the complex task of detecting tool call fences in a stream\n * where fences might be split across multiple chunks. It uses overlap detection\n * to avoid emitting text that might be the beginning of a fence.\n */\n\n/**\n * Result of fence detection operation\n */\nexport interface FenceDetectionResult {\n  fence: string | null;\n  prefixText: string;\n  remainingText: string;\n  /** Length of potential partial fence at buffer end */\n  overlapLength: number;\n}\n\n/**\n * Result of streaming fence content detection\n */\nexport interface StreamingFenceResult {\n  inFence: boolean;\n  /** Content that can be safely emitted (either as text or tool-input-delta) */\n  safeContent: string;\n  completeFence: string | null;\n  textAfterFence: string;\n}\n\n/**\n * Fence pattern configuration\n */\nexport interface FencePattern {\n  start: string;\n  end: string;\n  reconstructStart: string;\n  isRegex?: boolean;\n  matchedStart?: string;\n}\n\n/**\n * Options for configuring the ToolCallFenceDetector\n */\nexport interface ToolCallFenceDetectorOptions {\n  /** Custom fence patterns to use instead of defaults */\n  patterns?: FencePattern[];\n  /** Enable Python-style function call detection: [functionName(args)] */\n  enablePythonStyle?: boolean;\n}\n\n/**\n * Default fence patterns for tool call detection\n */\nexport const DEFAULT_FENCE_PATTERNS: FencePattern[] = [\n  { start: \"```tool_call\", end: \"```\", reconstructStart: \"```tool_call\\n\" },\n  { start: \"```tool-call\", end: \"```\", reconstructStart: \"```tool-call\\n\" },\n];\n\n/**\n * Extended fence patterns including XML-style tags\n */\nexport const EXTENDED_FENCE_PATTERNS: FencePattern[] = [\n  ...DEFAULT_FENCE_PATTERNS,\n  {\n    start: \"<tool_call>\",\n    end: \"</tool_call>\",\n    reconstructStart: \"<tool_call>\",\n  },\n];\n\n/**\n * Detects tool call fences in streaming text with support for partial matches\n */\nexport class ToolCallFenceDetector {\n  private readonly fencePatterns: FencePattern[];\n  private readonly enablePythonStyle: boolean;\n  private readonly pythonStyleRegex = /\\[(\\w+)\\(/g;\n  private readonly fenceStarts: string[];\n  private buffer = \"\";\n\n  private inFence = false;\n  private fenceStartBuffer = \"\"; // Accumulated fence content\n  private currentFencePattern: FencePattern | null = null;\n\n  constructor(options: ToolCallFenceDetectorOptions = {}) {\n    this.fencePatterns = options.patterns ?? EXTENDED_FENCE_PATTERNS;\n    this.enablePythonStyle = options.enablePythonStyle ?? true;\n    this.fenceStarts = this.fencePatterns.map((p) => p.start);\n  }\n\n  addChunk(chunk: string): void {\n    this.buffer += chunk;\n  }\n\n  getBuffer(): string {\n    return this.buffer;\n  }\n\n  clearBuffer(): void {\n    this.buffer = \"\";\n  }\n\n  /**\n   * Detects if there's a complete fence in the buffer\n   * @returns Detection result with fence info and safe text\n   */\n  detectFence(): FenceDetectionResult {\n    const {\n      index: startIdx,\n      prefix: matchedPrefix,\n      pattern,\n    } = this.findFenceStart(this.buffer);\n\n    // No fence start found\n    if (startIdx === -1) {\n      // Compute how much of the buffer end might be a partial fence start\n      const overlap = this.computeOverlapLength(this.buffer, this.fenceStarts);\n      const safeTextLength = this.buffer.length - overlap;\n\n      const prefixText =\n        safeTextLength > 0 ? this.buffer.slice(0, safeTextLength) : \"\";\n      const remaining = overlap > 0 ? this.buffer.slice(-overlap) : \"\";\n\n      // Update buffer to keep only the overlap\n      this.buffer = remaining;\n\n      return {\n        fence: null,\n        prefixText,\n        remainingText: \"\",\n        overlapLength: overlap,\n      };\n    }\n\n    const prefixText = this.buffer.slice(0, startIdx);\n    this.buffer = this.buffer.slice(startIdx);\n\n    // Look for closing fence using the matched pattern's end marker\n    const prefixLength = matchedPrefix?.length ?? 0;\n    const fenceEnd = pattern?.end ?? \"```\";\n    const closingIdx = this.buffer.indexOf(fenceEnd, prefixLength);\n\n    // Fence not complete yet\n    if (closingIdx === -1) {\n      // Keep the buffer as-is, waiting for more data\n      return {\n        fence: null,\n        prefixText,\n        remainingText: \"\",\n        overlapLength: 0,\n      };\n    }\n\n    // Complete fence found!\n    const endPos = closingIdx + fenceEnd.length;\n    const fence = this.buffer.slice(0, endPos);\n    const remainingText = this.buffer.slice(endPos);\n\n    // Clear the buffer since we extracted everything\n    this.buffer = \"\";\n\n    return {\n      fence,\n      prefixText,\n      remainingText,\n      overlapLength: 0,\n    };\n  }\n\n  /**\n   * Finds the first occurrence of any fence start marker\n   *\n   * @param text - Text to search in\n   * @returns Index of first fence start and which pattern matched\n   * @private\n   */\n  private findFenceStart(text: string): {\n    index: number;\n    prefix: string | null;\n    pattern: FencePattern | null;\n  } {\n    let bestIndex = -1;\n    let matchedPrefix: string | null = null;\n    let matchedPattern: FencePattern | null = null;\n\n    for (const pattern of this.fencePatterns) {\n      const idx = text.indexOf(pattern.start);\n      if (idx !== -1 && (bestIndex === -1 || idx < bestIndex)) {\n        bestIndex = idx;\n        matchedPrefix = pattern.start;\n        matchedPattern = pattern;\n      }\n    }\n\n    if (this.enablePythonStyle) {\n      this.pythonStyleRegex.lastIndex = 0;\n      const pythonMatch = this.pythonStyleRegex.exec(text);\n      if (pythonMatch && (bestIndex === -1 || pythonMatch.index < bestIndex)) {\n        bestIndex = pythonMatch.index;\n        matchedPrefix = pythonMatch[0];\n        matchedPattern = {\n          start: pythonMatch[0],\n          end: \")]\",\n          reconstructStart: pythonMatch[0],\n          isRegex: true,\n        };\n      }\n    }\n\n    return { index: bestIndex, prefix: matchedPrefix, pattern: matchedPattern };\n  }\n\n  /**\n   * Computes the maximum overlap between the end of text and the start of any prefix\n   * @param text - Text to check for overlap\n   * @param prefixes - List of prefixes to check against\n   * @returns Length of the maximum overlap found\n   */\n  private computeOverlapLength(text: string, prefixes: string[]): number {\n    let overlap = 0;\n\n    for (const prefix of prefixes) {\n      const maxLength = Math.min(text.length, prefix.length - 1);\n\n      for (let size = maxLength; size > 0; size -= 1) {\n        // Check if the last 'size' characters of text match the first 'size' characters of prefix\n        if (prefix.startsWith(text.slice(-size))) {\n          overlap = Math.max(overlap, size);\n          break;\n        }\n      }\n    }\n\n    return overlap;\n  }\n\n  /**\n   * Checks if the buffer currently contains any text\n   */\n  hasContent(): boolean {\n    return this.buffer.length > 0;\n  }\n\n  /**\n   * Gets the buffer size\n   */\n  getBufferSize(): number {\n    return this.buffer.length;\n  }\n\n  /**\n   * Detect and stream fence content in real-time for true incremental streaming\n   * @returns Streaming result with current state and safe content to emit\n   */\n  detectStreamingFence(): StreamingFenceResult {\n    if (!this.inFence) {\n      // Look for fence start\n      const {\n        index: startIdx,\n        prefix: matchedPrefix,\n        pattern,\n      } = this.findFenceStart(this.buffer);\n\n      if (startIdx === -1) {\n        // No fence start found - emit safe text\n        const overlap = this.computeOverlapLength(\n          this.buffer,\n          this.fenceStarts,\n        );\n        const safeTextLength = this.buffer.length - overlap;\n        const safeContent =\n          safeTextLength > 0 ? this.buffer.slice(0, safeTextLength) : \"\";\n        this.buffer = this.buffer.slice(safeTextLength);\n\n        return {\n          inFence: false,\n          safeContent,\n          completeFence: null,\n          textAfterFence: \"\",\n        };\n      }\n\n      // Found fence start!\n      const prefixText = this.buffer.slice(0, startIdx);\n      const fenceStartLength = matchedPrefix?.length ?? 0;\n\n      // Move buffer past the fence start marker\n      this.buffer = this.buffer.slice(startIdx + fenceStartLength);\n\n      if (\n        pattern &&\n        pattern.start.startsWith(\"```\") &&\n        this.buffer.startsWith(\"\\n\")\n      ) {\n        this.buffer = this.buffer.slice(1);\n      }\n\n      this.inFence = true;\n      this.fenceStartBuffer = \"\";\n      this.currentFencePattern = pattern;\n\n      return {\n        inFence: true,\n        safeContent: prefixText, // Emit any text before the fence\n        completeFence: null,\n        textAfterFence: \"\",\n      };\n    }\n\n    // We're inside a fence - look for fence end using the current pattern\n    const fenceEnd = this.currentFencePattern?.end ?? \"```\";\n    const closingIdx = this.buffer.indexOf(fenceEnd);\n\n    if (closingIdx === -1) {\n      // No fence end yet - emit safe content (leaving potential fence end marker)\n      const overlap = this.computeOverlapLength(this.buffer, [fenceEnd]);\n      const safeContentLength = this.buffer.length - overlap;\n\n      if (safeContentLength > 0) {\n        const safeContent = this.buffer.slice(0, safeContentLength);\n        this.fenceStartBuffer += safeContent;\n        this.buffer = this.buffer.slice(safeContentLength);\n\n        return {\n          inFence: true,\n          safeContent,\n          completeFence: null,\n          textAfterFence: \"\",\n        };\n      }\n\n      // Nothing safe to emit yet\n      return {\n        inFence: true,\n        safeContent: \"\",\n        completeFence: null,\n        textAfterFence: \"\",\n      };\n    }\n\n    // Found fence end!\n    const fenceContent = this.buffer.slice(0, closingIdx);\n    this.fenceStartBuffer += fenceContent;\n\n    // Reconstruct complete fence using the current pattern\n    const reconstructStart =\n      this.currentFencePattern?.reconstructStart ?? \"```tool_call\\n\";\n    const completeFence = `${reconstructStart}${this.fenceStartBuffer}${fenceEnd}`;\n\n    // Get text after fence\n    const textAfterFence = this.buffer.slice(closingIdx + fenceEnd.length);\n\n    // Reset state\n    this.inFence = false;\n    this.fenceStartBuffer = \"\";\n    this.currentFencePattern = null;\n    this.buffer = textAfterFence;\n\n    return {\n      inFence: false,\n      safeContent: fenceContent, // Emit the last bit of fence content\n      completeFence,\n      textAfterFence,\n    };\n  }\n\n  isInFence(): boolean {\n    return this.inFence;\n  }\n\n  resetStreamingState(): void {\n    this.inFence = false;\n    this.fenceStartBuffer = \"\";\n    this.currentFencePattern = null;\n  }\n}\n\n/**\n * Creates a basic ToolCallFenceDetector with default markdown fence patterns\n */\nexport function createBasicDetector(): ToolCallFenceDetector {\n  return new ToolCallFenceDetector({\n    patterns: DEFAULT_FENCE_PATTERNS,\n    enablePythonStyle: false,\n  });\n}\n\n/**\n * Creates an extended ToolCallFenceDetector with all fence patterns\n */\nexport function createExtendedDetector(): ToolCallFenceDetector {\n  return new ToolCallFenceDetector({\n    patterns: EXTENDED_FENCE_PATTERNS,\n    enablePythonStyle: true,\n  });\n}\n","/**\n * Extracts tool name from partial fence content for early tool-input-start emission.\n * Expects a JSON fragment like: {\"name\":\"toolName\"\n */\nexport function extractToolName(content: string): string | null {\n  const jsonMatch = content.match(/\\{\\s*\"name\"\\s*:\\s*\"([^\"]+)\"/);\n  if (jsonMatch) {\n    return jsonMatch[1];\n  }\n  return null;\n}\n\nexport interface ArgumentsStreamState {\n  searchFrom: number;\n  valueStartIndex: number | null;\n  parseIndex: number;\n  started: boolean;\n  depth: number;\n  inString: boolean;\n  escaped: boolean;\n  complete: boolean;\n}\n\nconst ARGUMENTS_FIELD_REGEX = /\"arguments\"\\s*:\\s*/g;\nconst ARGUMENTS_SEARCH_OVERLAP = 32;\n\nexport function createArgumentsStreamState(): ArgumentsStreamState {\n  return {\n    searchFrom: 0,\n    valueStartIndex: null,\n    parseIndex: 0,\n    started: false,\n    depth: 0,\n    inString: false,\n    escaped: false,\n    complete: false,\n  };\n}\n\n/**\n * Incrementally extracts only new argument content from a streaming tool call fence.\n */\nexport function extractArgumentsDelta(\n  content: string,\n  state: ArgumentsStreamState,\n): string {\n  if (state.complete) {\n    return \"\";\n  }\n\n  if (state.valueStartIndex === null) {\n    ARGUMENTS_FIELD_REGEX.lastIndex = state.searchFrom;\n    const match = ARGUMENTS_FIELD_REGEX.exec(content);\n    ARGUMENTS_FIELD_REGEX.lastIndex = 0;\n\n    if (!match || match.index === undefined) {\n      state.searchFrom = Math.max(0, content.length - ARGUMENTS_SEARCH_OVERLAP);\n      return \"\";\n    }\n\n    state.valueStartIndex = match.index + match[0].length;\n    state.parseIndex = state.valueStartIndex;\n    state.searchFrom = state.valueStartIndex;\n  }\n\n  if (state.parseIndex >= content.length) {\n    return \"\";\n  }\n\n  let delta = \"\";\n  for (let i = state.parseIndex; i < content.length; i++) {\n    const char = content[i];\n    delta += char;\n\n    if (!state.started) {\n      if (!/\\s/.test(char)) {\n        state.started = true;\n        if (char === \"{\" || char === \"[\") {\n          state.depth = 1;\n        }\n      }\n      continue;\n    }\n\n    if (state.escaped) {\n      state.escaped = false;\n      continue;\n    }\n\n    if (char === \"\\\\\") {\n      state.escaped = true;\n      continue;\n    }\n\n    if (char === '\"') {\n      state.inString = !state.inString;\n      continue;\n    }\n\n    if (!state.inString) {\n      if (char === \"{\" || char === \"[\") {\n        state.depth += 1;\n      } else if (char === \"}\" || char === \"]\") {\n        if (state.depth > 0) {\n          state.depth -= 1;\n          if (state.depth === 0) {\n            state.parseIndex = i + 1;\n            state.complete = true;\n            return delta;\n          }\n        }\n      }\n    }\n  }\n\n  state.parseIndex = content.length;\n  return delta;\n}\n","import type { LanguageModelV3StreamPart } from \"@ai-sdk/provider\";\nimport { ToolCallFenceDetector } from \"./tool-call-detector\";\nimport {\n  createArgumentsStreamState,\n  extractArgumentsDelta,\n  extractToolName,\n} from \"./tool-call-stream-utils\";\nimport { parseJsonFunctionCalls } from \"../tool-calling/parse-json-function-calls\";\nimport type { ParsedToolCall } from \"../types\";\n\nexport interface ToolCallStreamResult {\n  toolCallDetected: boolean;\n  toolCalls: ParsedToolCall[];\n  /** Text appearing after the tool call fence — caller decides when to emit it */\n  trailingText: string;\n}\n\nexport function generateToolCallId(): string {\n  return `call_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\n}\n\n/**\n * Processes an async iterable of string chunks, detecting tool call fences and\n * emitting the appropriate stream events via `controller` and `emitTextDelta`.\n *\n * When `stopEarlyOnToolCall` is true the function stops consuming chunks as soon as\n * a tool call is detected (useful when the caller needs to cancel the source).\n * When false (the default) the function continues draining remaining chunks without\n * processing them, allowing the underlying stream/engine to conclude normally.\n */\nexport async function processToolCallStream(\n  chunks: AsyncIterable<string>,\n  emitTextDelta: (delta: string) => void,\n  controller: ReadableStreamDefaultController<LanguageModelV3StreamPart>,\n  options?: { stopEarlyOnToolCall?: boolean },\n): Promise<ToolCallStreamResult> {\n  const fenceDetector = new ToolCallFenceDetector();\n\n  let currentToolCallId: string | null = null;\n  let toolInputStartEmitted = false;\n  let accumulatedFenceContent = \"\";\n  let argumentsStreamState = createArgumentsStreamState();\n  let insideFence = false;\n\n  let toolCallDetected = false;\n  let toolCalls: ParsedToolCall[] = [];\n  let trailingText = \"\";\n\n  const resetFenceState = () => {\n    currentToolCallId = null;\n    toolInputStartEmitted = false;\n    accumulatedFenceContent = \"\";\n    argumentsStreamState = createArgumentsStreamState();\n    insideFence = false;\n  };\n\n  for await (const chunk of chunks) {\n    if (toolCallDetected) {\n      // Drain without processing so the underlying stream/engine can conclude.\n      continue;\n    }\n\n    fenceDetector.addChunk(chunk);\n\n    while (fenceDetector.hasContent()) {\n      const wasInsideFence = insideFence;\n      const result = fenceDetector.detectStreamingFence();\n      insideFence = result.inFence;\n\n      let madeProgress = false;\n\n      if (!wasInsideFence && result.inFence) {\n        if (result.safeContent) {\n          emitTextDelta(result.safeContent);\n          madeProgress = true;\n        }\n\n        currentToolCallId = generateToolCallId();\n        toolInputStartEmitted = false;\n        accumulatedFenceContent = \"\";\n        argumentsStreamState = createArgumentsStreamState();\n        insideFence = true;\n\n        continue;\n      }\n\n      if (result.completeFence) {\n        madeProgress = true;\n        if (result.safeContent) {\n          accumulatedFenceContent += result.safeContent;\n        }\n\n        if (toolInputStartEmitted && currentToolCallId) {\n          const delta = extractArgumentsDelta(\n            accumulatedFenceContent,\n            argumentsStreamState,\n          );\n          if (delta.length > 0) {\n            controller.enqueue({\n              type: \"tool-input-delta\",\n              id: currentToolCallId,\n              delta,\n            });\n          }\n        }\n\n        const parsed = parseJsonFunctionCalls(result.completeFence);\n        const selectedToolCalls = parsed.toolCalls.slice(0, 1);\n\n        if (selectedToolCalls.length === 0) {\n          emitTextDelta(result.completeFence);\n          if (result.textAfterFence) {\n            emitTextDelta(result.textAfterFence);\n          }\n          resetFenceState();\n          continue;\n        }\n\n        if (currentToolCallId) {\n          selectedToolCalls[0].toolCallId = currentToolCallId;\n        }\n\n        for (const [index, call] of selectedToolCalls.entries()) {\n          const toolCallId =\n            index === 0 && currentToolCallId\n              ? currentToolCallId\n              : call.toolCallId;\n          const toolName = call.toolName;\n          const argsJson = JSON.stringify(call.args ?? {});\n\n          if (toolCallId === currentToolCallId) {\n            if (!toolInputStartEmitted) {\n              controller.enqueue({\n                type: \"tool-input-start\",\n                id: toolCallId,\n                toolName,\n              });\n              toolInputStartEmitted = true;\n            }\n\n            const delta = extractArgumentsDelta(\n              accumulatedFenceContent,\n              argumentsStreamState,\n            );\n            if (delta.length > 0) {\n              controller.enqueue({\n                type: \"tool-input-delta\",\n                id: toolCallId,\n                delta,\n              });\n            }\n          } else {\n            controller.enqueue({\n              type: \"tool-input-start\",\n              id: toolCallId,\n              toolName,\n            });\n            if (argsJson.length > 0) {\n              controller.enqueue({\n                type: \"tool-input-delta\",\n                id: toolCallId,\n                delta: argsJson,\n              });\n            }\n          }\n\n          controller.enqueue({ type: \"tool-input-end\", id: toolCallId });\n          controller.enqueue({\n            type: \"tool-call\",\n            toolCallId,\n            toolName,\n            input: argsJson,\n            providerExecuted: false,\n          });\n        }\n\n        trailingText = result.textAfterFence ?? \"\";\n        toolCalls = selectedToolCalls;\n        toolCallDetected = true;\n        resetFenceState();\n        break; // stop processing inner buffer\n      }\n\n      if (insideFence) {\n        if (result.safeContent) {\n          accumulatedFenceContent += result.safeContent;\n          madeProgress = true;\n\n          const toolName = extractToolName(accumulatedFenceContent);\n          if (toolName && !toolInputStartEmitted && currentToolCallId) {\n            controller.enqueue({\n              type: \"tool-input-start\",\n              id: currentToolCallId,\n              toolName,\n            });\n            toolInputStartEmitted = true;\n          }\n\n          if (toolInputStartEmitted && currentToolCallId) {\n            const delta = extractArgumentsDelta(\n              accumulatedFenceContent,\n              argumentsStreamState,\n            );\n            if (delta.length > 0) {\n              controller.enqueue({\n                type: \"tool-input-delta\",\n                id: currentToolCallId,\n                delta,\n              });\n            }\n          }\n        }\n\n        continue;\n      }\n\n      if (!insideFence && result.safeContent) {\n        emitTextDelta(result.safeContent);\n        madeProgress = true;\n      }\n\n      if (!madeProgress) {\n        break;\n      }\n    }\n\n    if (toolCallDetected && options?.stopEarlyOnToolCall) {\n      break; // caller will cancel/drain the underlying source\n    }\n  }\n\n  // Flush any remaining buffer when no tool call was detected\n  if (!toolCallDetected && fenceDetector.hasContent()) {\n    emitTextDelta(fenceDetector.getBuffer());\n    fenceDetector.clearBuffer();\n  }\n\n  return { toolCallDetected, toolCalls, trailingText };\n}\n","import {\n  LanguageModelV3Prompt,\n  LanguageModelV3ToolResultPart,\n  LanguageModelV3ToolResultOutput,\n  UnsupportedFunctionalityError,\n} from \"@ai-sdk/provider\";\nimport * as webllm from \"@mlc-ai/web-llm\";\nimport { formatToolResults, type ToolResult } from \"@browser-ai/shared\";\n\n/**\n * Converts the AI SDK ToolResultOutput format to a simple value + error flag\n */\nfunction convertToolResultOutput(output: LanguageModelV3ToolResultOutput): {\n  value: unknown;\n  isError: boolean;\n} {\n  switch (output.type) {\n    case \"text\":\n      return { value: output.value, isError: false };\n    case \"json\":\n      return { value: output.value, isError: false };\n    case \"error-text\":\n      return { value: output.value, isError: true };\n    case \"error-json\":\n      return { value: output.value, isError: true };\n    case \"content\":\n      return { value: output.value, isError: false };\n    case \"execution-denied\":\n      return { value: output.reason, isError: true };\n    default: {\n      const exhaustiveCheck: never = output;\n      return { value: exhaustiveCheck, isError: false };\n    }\n  }\n}\n\n/**\n * Converts a ToolResultPart to our internal ToolResult format\n */\nfunction toToolResult(part: LanguageModelV3ToolResultPart): ToolResult {\n  const { value, isError } = convertToolResultOutput(part.output);\n  return {\n    toolCallId: part.toolCallId,\n    toolName: part.toolName,\n    result: value,\n    isError,\n  };\n}\n\nfunction uint8ArrayToBase64(uint8array: Uint8Array): string {\n  const binary = Array.from(uint8array, (byte) =>\n    String.fromCharCode(byte),\n  ).join(\"\");\n  return btoa(binary);\n}\n\nfunction convertDataToURL(\n  data:\n    | string\n    | Buffer\n    | URL\n    | Uint8Array\n    | ArrayBuffer\n    | ReadableStream\n    | undefined,\n  mediaType: string,\n): string {\n  if (data instanceof URL) {\n    return data.toString();\n  }\n\n  if (typeof data === \"string\") {\n    // AI SDK provides base64 string\n    return `data:${mediaType};base64,${data}`;\n  }\n\n  if (data instanceof Uint8Array) {\n    return `data:${mediaType};base64,${uint8ArrayToBase64(data)}`;\n  }\n\n  if (data instanceof ArrayBuffer) {\n    return `data:${mediaType};base64,${uint8ArrayToBase64(\n      new Uint8Array(data),\n    )}`;\n  }\n\n  if (typeof Buffer !== \"undefined\" && data instanceof Buffer) {\n    return `data:${mediaType};base64,${data.toString(\"base64\")}`;\n  }\n\n  throw new UnsupportedFunctionalityError({\n    functionality: `file data type: ${typeof data}`,\n  });\n}\n\nexport function convertToWebLLMMessages(\n  prompt: LanguageModelV3Prompt,\n): webllm.ChatCompletionMessageParam[] {\n  const messages: webllm.ChatCompletionMessageParam[] = [];\n\n  for (const message of prompt) {\n    switch (message.role) {\n      case \"system\":\n        messages.push({\n          role: \"system\",\n          content: message.content,\n        });\n        break;\n\n      case \"user\":\n        const hasFileContent = message.content.some(\n          (part) => part.type === \"file\",\n        );\n\n        if (!hasFileContent) {\n          const userContent: string[] = [];\n          for (const part of message.content) {\n            if (part.type === \"text\") {\n              userContent.push(part.text);\n            }\n          }\n          messages.push({\n            role: \"user\",\n            content: userContent.join(\"\\n\"),\n          });\n          break;\n        }\n\n        const content: webllm.ChatCompletionContentPart[] = [];\n        for (const part of message.content) {\n          if (part.type === \"text\") {\n            content.push({ type: \"text\", text: part.text });\n          } else if (part.type === \"file\") {\n            if (!part.mediaType?.startsWith(\"image/\")) {\n              throw new UnsupportedFunctionalityError({\n                functionality: `file input with media type '${part.mediaType}'`,\n              });\n            }\n            content.push({\n              type: \"image_url\",\n              image_url: {\n                url: convertDataToURL(part.data, part.mediaType),\n              },\n            });\n          }\n        }\n        messages.push({ role: \"user\", content });\n        break;\n\n      case \"assistant\":\n        let assistantContent = \"\";\n        const toolCallsInMessage: Array<{\n          toolCallId: string;\n          toolName: string;\n        }> = [];\n\n        for (const part of message.content) {\n          if (part.type === \"text\") {\n            assistantContent += part.text;\n          } else if (part.type === \"tool-call\") {\n            // Store tool call info but don't include in content\n            // Tool calls will be tracked separately\n            toolCallsInMessage.push({\n              toolCallId: part.toolCallId,\n              toolName: part.toolName,\n            });\n          }\n        }\n\n        // Only add assistant message if there's text content\n        // Tool calls are handled via the JSON fence format in the text\n        if (assistantContent) {\n          messages.push({\n            role: \"assistant\",\n            content: assistantContent,\n          });\n        }\n        break;\n\n      case \"tool\":\n        // Collect tool results and format them\n        // filter for tool-result parts only\n        // not sure how to support tool-approval-response parts yet\n        const toolResults: ToolResult[] = message.content\n          .filter((part) => part.type === \"tool-result\")\n          .map(toToolResult);\n\n        // Format tool results as user message with JSON fence format\n        const formattedResults = formatToolResults(toolResults);\n        messages.push({\n          role: \"user\",\n          content: formattedResults,\n        });\n        break;\n    }\n  }\n\n  return messages;\n}\n","import {\n  LanguageModelV3,\n  LanguageModelV3CallOptions,\n  SharedV3Warning,\n  LanguageModelV3Content,\n  LanguageModelV3FinishReason,\n  LanguageModelV3ProviderTool,\n  LanguageModelV3StreamPart,\n  LanguageModelV3ToolCall,\n  LoadSettingError,\n  LanguageModelV3GenerateResult,\n  LanguageModelV3StreamResult,\n} from \"@ai-sdk/provider\";\nimport { convertToWebLLMMessages } from \"../utils/convert-to-webllm-messages\";\n\nimport {\n  AppConfig,\n  ChatCompletionRequestNonStreaming,\n  ChatCompletionRequestStreaming,\n  CreateWebWorkerMLCEngine,\n  InitProgressReport,\n  MLCEngine,\n  MLCEngineConfig,\n  MLCEngineInterface,\n} from \"@mlc-ai/web-llm\";\nimport { Availability } from \"../types\";\nimport {\n  buildJsonToolSystemPrompt,\n  parseJsonFunctionCalls,\n  createUnsupportedSettingWarning,\n  createUnsupportedToolWarning,\n  isFunctionTool,\n  processToolCallStream,\n  type ToolDefinition,\n  type DownloadProgressCallback,\n} from \"@browser-ai/shared\";\nimport {\n  prependSystemPromptToMessages,\n  extractSystemPrompt,\n} from \"../utils/prompt-utils\";\nimport {\n  isMobile,\n  checkWebGPU,\n  doesBrowserSupportWebLLM,\n} from \"../utils/browser\";\n\nexport { doesBrowserSupportWebLLM };\n\nexport type WebLLMModelId = string;\n\nexport interface WebLLMSettings {\n  /**\n   * Custom app configuration for WebLLM\n   */\n  appConfig?: AppConfig;\n  /**\n   * Progress callback for model initialization\n   */\n  initProgressCallback?: (progress: InitProgressReport) => void;\n  /**\n   * Engine configuration options\n   */\n  engineConfig?: MLCEngineConfig;\n  /**\n   * A web worker instance to run the model in.\n   * When provided, the model will run in a separate thread.\n   *\n   * @default undefined\n   */\n  worker?: Worker;\n}\n\ntype WebLLMConfig = {\n  provider: string;\n  modelId: WebLLMModelId;\n  options: WebLLMSettings;\n};\n\nexport class WebLLMLanguageModel implements LanguageModelV3 {\n  readonly specificationVersion = \"v3\";\n  readonly modelId: WebLLMModelId;\n  readonly provider = \"web-llm\";\n\n  private readonly config: WebLLMConfig;\n  private engine?: MLCEngineInterface;\n  private isInitialized = false;\n  private initializationPromise?: Promise<void>;\n\n  constructor(modelId: WebLLMModelId, options: WebLLMSettings = {}) {\n    this.modelId = modelId;\n    this.config = {\n      provider: this.provider,\n      modelId,\n      options,\n    };\n  }\n\n  readonly supportedUrls: Record<string, RegExp[]> = {\n    // WebLLM doesn't support URLs natively\n  };\n\n  /**\n   * Check if the model is initialized and ready to use\n   * @returns true if the model is initialized, false otherwise\n   */\n  get isModelInitialized(): boolean {\n    return this.isInitialized;\n  }\n\n  private async getEngine(\n    options?: MLCEngineConfig,\n    onInitProgress?: (progress: InitProgressReport) => void,\n  ): Promise<MLCEngineInterface> {\n    const availability = await this.availability();\n    if (availability === \"unavailable\") {\n      throw new LoadSettingError({\n        message:\n          \"WebLLM is not available. This library requires a browser with WebGPU support.\",\n      });\n    }\n\n    if (this.engine && this.isInitialized) return this.engine;\n\n    // If initialization is already in progress, wait for it\n    if (this.initializationPromise) {\n      await this.initializationPromise;\n      if (this.engine) return this.engine;\n    }\n\n    this.initializationPromise = this._initializeEngine(\n      options,\n      onInitProgress,\n    );\n    await this.initializationPromise;\n\n    if (!this.engine) {\n      throw new LoadSettingError({\n        message: \"Engine initialization failed\",\n      });\n    }\n\n    return this.engine;\n  }\n\n  private async _initializeEngine(\n    options?: MLCEngineConfig,\n    onInitProgress?: (progress: InitProgressReport) => void,\n  ): Promise<void> {\n    try {\n      // Create engine instance\n      const engineConfig = {\n        ...this.config.options.engineConfig,\n        ...options,\n        initProgressCallback:\n          onInitProgress || this.config.options.initProgressCallback,\n      };\n\n      if (this.config.options.worker) {\n        this.engine = await CreateWebWorkerMLCEngine(\n          this.config.options.worker,\n          this.modelId,\n          engineConfig,\n        );\n      } else {\n        this.engine = new MLCEngine(engineConfig);\n        // Load the model\n        await this.engine.reload(this.modelId);\n      }\n\n      this.isInitialized = true;\n    } catch (error) {\n      // Reset state on error so we can retry\n      this.engine = undefined;\n      this.isInitialized = false;\n      this.initializationPromise = undefined;\n\n      throw new LoadSettingError({\n        message: `Failed to initialize WebLLM engine: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n      });\n    }\n  }\n\n  private getArgs({\n    prompt,\n    maxOutputTokens,\n    temperature,\n    topP,\n    topK,\n    frequencyPenalty,\n    presencePenalty,\n    stopSequences,\n    responseFormat,\n    seed,\n    tools,\n    toolChoice,\n    providerOptions,\n  }: Parameters<LanguageModelV3[\"doGenerate\"]>[0]) {\n    const warnings: SharedV3Warning[] = [];\n\n    const functionTools: ToolDefinition[] = (tools ?? [])\n      .filter(isFunctionTool)\n      .map((tool) => ({\n        name: tool.name,\n        description: tool.description,\n        parameters: tool.inputSchema,\n      }));\n\n    const unsupportedTools = (tools ?? []).filter(\n      (tool): tool is LanguageModelV3ProviderTool => !isFunctionTool(tool),\n    );\n\n    for (const tool of unsupportedTools) {\n      warnings.push(\n        createUnsupportedToolWarning(\n          tool,\n          \"Only function tools are supported by WebLLM\",\n        ),\n      );\n    }\n\n    if (topK != null) {\n      warnings.push(\n        createUnsupportedSettingWarning(\n          \"topK\",\n          \"topK is not supported by WebLLM\",\n        ),\n      );\n    }\n\n    if (stopSequences != null) {\n      warnings.push(\n        createUnsupportedSettingWarning(\n          \"stopSequences\",\n          \"Stop sequences may not be fully implemented\",\n        ),\n      );\n    }\n\n    if (presencePenalty != null) {\n      warnings.push(\n        createUnsupportedSettingWarning(\n          \"presencePenalty\",\n          \"Presence penalty is not fully implemented\",\n        ),\n      );\n    }\n\n    if (frequencyPenalty != null) {\n      warnings.push(\n        createUnsupportedSettingWarning(\n          \"frequencyPenalty\",\n          \"Frequency penalty is not fully implemented\",\n        ),\n      );\n    }\n\n    if (toolChoice != null) {\n      warnings.push(\n        createUnsupportedSettingWarning(\n          \"toolChoice\",\n          \"toolChoice is not supported by WebLLM\",\n        ),\n      );\n    }\n\n    // Convert messages to WebLLM format\n    const messages = convertToWebLLMMessages(prompt);\n\n    // Build request options\n    const requestOptions: ChatCompletionRequestNonStreaming = {\n      messages,\n      temperature,\n      max_tokens: maxOutputTokens,\n      top_p: topP,\n      seed,\n    };\n\n    const webLLMOptions = providerOptions?.[this.provider];\n    const extraBody = webLLMOptions?.extra_body as\n      | Record<string, unknown>\n      | undefined;\n    if (extraBody) {\n      // https://webllm.mlc.ai/docs/user/api_reference.html#generationconfig\n      requestOptions.extra_body = {\n        enable_thinking: extraBody.enable_thinking as boolean | undefined,\n        enable_latency_breakdown: extraBody.enable_latency_breakdown as\n          | boolean\n          | undefined,\n      };\n    }\n\n    // Handle response format\n    if (responseFormat?.type === \"json\") {\n      requestOptions.response_format = {\n        type: \"json_object\",\n        ...(responseFormat.schema && {\n          schema: JSON.stringify(responseFormat.schema),\n        }),\n      };\n    }\n\n    return {\n      messages,\n      warnings,\n      requestOptions,\n      functionTools,\n    };\n  }\n\n  /**\n   * Generates a complete text response using WebLLM\n   * @param options\n   * @returns Promise resolving to the generated content with finish reason, usage stats, and any warnings\n   * @throws {LoadSettingError} When WebLLM is not available or model needs to be downloaded\n   * @throws {UnsupportedFunctionalityError} When unsupported features like file input are used\n   */\n  public async doGenerate(\n    options: LanguageModelV3CallOptions,\n  ): Promise<LanguageModelV3GenerateResult> {\n    const converted = this.getArgs(options);\n    const { messages, warnings, requestOptions, functionTools } = converted;\n\n    // Extract system prompt and build tool calling prompt\n    const {\n      systemPrompt: originalSystemPrompt,\n      messages: messagesWithoutSystem,\n    } = extractSystemPrompt(messages);\n\n    const systemPrompt = buildJsonToolSystemPrompt(\n      originalSystemPrompt,\n      functionTools,\n      {\n        allowParallelToolCalls: false,\n      },\n    );\n\n    // Prepend system prompt to messages\n    const promptMessages = prependSystemPromptToMessages(\n      messagesWithoutSystem,\n      systemPrompt,\n    );\n\n    const engine = await this.getEngine();\n\n    const abortHandler = async () => {\n      await engine.interruptGenerate();\n    };\n\n    if (options.abortSignal) {\n      options.abortSignal.addEventListener(\"abort\", abortHandler);\n    }\n\n    try {\n      const response = await engine.chat.completions.create({\n        ...requestOptions,\n        messages: promptMessages,\n        stream: false,\n        ...(options.abortSignal &&\n          !this.config.options.worker && { signal: options.abortSignal }),\n      });\n\n      const choice = response.choices[0];\n      if (!choice) {\n        throw new Error(\"No response choice returned from WebLLM\");\n      }\n\n      const rawResponse = choice.message.content || \"\";\n\n      // Parse JSON tool calls from response\n      const { toolCalls, textContent } = parseJsonFunctionCalls(rawResponse);\n\n      if (toolCalls.length > 0) {\n        const toolCallsToEmit = toolCalls.slice(0, 1);\n\n        const parts: LanguageModelV3Content[] = [];\n\n        if (textContent) {\n          parts.push({\n            type: \"text\",\n            text: textContent,\n          });\n        }\n\n        for (const call of toolCallsToEmit) {\n          parts.push({\n            type: \"tool-call\",\n            toolCallId: call.toolCallId,\n            toolName: call.toolName,\n            input: JSON.stringify(call.args ?? {}),\n          } satisfies LanguageModelV3ToolCall);\n        }\n\n        return {\n          content: parts,\n          finishReason: { unified: \"tool-calls\", raw: \"tool-calls\" },\n          usage: {\n            inputTokens: {\n              total: response.usage?.prompt_tokens,\n              noCache: undefined,\n              cacheRead: undefined,\n              cacheWrite: undefined,\n            },\n            outputTokens: {\n              total: response.usage?.completion_tokens,\n              text: undefined,\n              reasoning: undefined,\n            },\n          },\n          request: { body: { ...requestOptions, messages: promptMessages } },\n          warnings,\n        };\n      }\n\n      const content: LanguageModelV3Content[] = [\n        {\n          type: \"text\",\n          text: textContent || rawResponse,\n        },\n      ];\n\n      let finishReason: LanguageModelV3FinishReason = {\n        unified: \"stop\",\n        raw: choice.finish_reason,\n      };\n      if (choice.finish_reason === \"abort\") {\n        finishReason = { unified: \"other\", raw: choice.finish_reason };\n      }\n\n      return {\n        content,\n        finishReason,\n        usage: {\n          inputTokens: {\n            total: response.usage?.prompt_tokens,\n            noCache: undefined,\n            cacheRead: undefined,\n            cacheWrite: undefined,\n          },\n          outputTokens: {\n            total: response.usage?.completion_tokens,\n            text: undefined,\n            reasoning: undefined,\n          },\n          raw: {\n            total: response.usage?.total_tokens,\n          },\n        },\n        request: { body: { ...requestOptions, messages: promptMessages } },\n        warnings,\n      };\n    } catch (error) {\n      throw new Error(\n        `WebLLM generation failed: ${\n          error instanceof Error ? error.message : \"Unknown error\"\n        }`,\n      );\n    } finally {\n      if (options.abortSignal) {\n        options.abortSignal.removeEventListener(\"abort\", abortHandler);\n      }\n    }\n  }\n\n  /**\n   * Check the availability of the WebLLM model.\n   * Note: On mobile devices with a worker, WebGPU detection is skipped since it\n   * can't be done reliably. The actual availability will be determined at init.\n   * @returns Promise resolving to \"unavailable\", \"available\", or \"downloadable\"\n   */\n  public async availability(): Promise<Availability> {\n    if (this.isInitialized) {\n      return \"available\";\n    }\n\n    // Skip on mobile if using a worker, since detecting GPU is unreliable.\n    // Let worker initialization handle it and return an error if unavailable.\n    if (this.config.options.worker && isMobile()) {\n      return \"downloadable\";\n    }\n\n    const supported = checkWebGPU();\n    return supported ? \"downloadable\" : \"unavailable\";\n  }\n\n  /**\n   * Creates an engine session with download progress monitoring.\n   *\n   * @example\n   * ```typescript\n   * const model = await model.createSessionWithProgress(\n   *   (progress) => {\n   *     console.log(`Download progress: ${Math.round(progress * 100)}%`);\n   *   }\n   * );\n   * ```\n   *\n   * @param onDownloadProgress Optional callback receiving progress values from 0 to 1\n   * @returns Promise resolving to the model instance\n   * @throws {LoadSettingError} When WebLLM is not available or model is unavailable\n   */\n  public async createSessionWithProgress(\n    onDownloadProgress?: DownloadProgressCallback,\n  ): Promise<WebLLMLanguageModel> {\n    const adaptedCallback = onDownloadProgress\n      ? (report: InitProgressReport) => {\n          onDownloadProgress(report.progress);\n        }\n      : undefined;\n    await this.getEngine(undefined, adaptedCallback);\n    return this;\n  }\n\n  /**\n   * Generates a streaming text response using WebLLM\n   * @param options\n   * @returns Promise resolving to a readable stream of text chunks and request metadata\n   * @throws {LoadSettingError} When WebLLM is not available or model needs to be downloaded\n   * @throws {UnsupportedFunctionalityError} When unsupported features like file input are used\n   */\n  public async doStream(\n    options: LanguageModelV3CallOptions,\n  ): Promise<LanguageModelV3StreamResult> {\n    const converted = this.getArgs(options);\n    const { messages, warnings, requestOptions, functionTools } = converted;\n\n    // Extract system prompt and build tool calling prompt\n    const {\n      systemPrompt: originalSystemPrompt,\n      messages: messagesWithoutSystem,\n    } = extractSystemPrompt(messages);\n\n    const systemPrompt = buildJsonToolSystemPrompt(\n      originalSystemPrompt,\n      functionTools,\n      {\n        allowParallelToolCalls: false,\n      },\n    );\n\n    // Prepend system prompt to messages\n    const promptMessages = prependSystemPromptToMessages(\n      messagesWithoutSystem,\n      systemPrompt,\n    );\n\n    const engine = await this.getEngine();\n    const useWorker = this.config.options.worker != null;\n\n    const abortHandler = async () => {\n      await engine.interruptGenerate();\n    };\n\n    if (options.abortSignal) {\n      options.abortSignal.addEventListener(\"abort\", abortHandler);\n    }\n\n    const textId = \"text-0\";\n\n    const stream = new ReadableStream<LanguageModelV3StreamPart>({\n      async start(controller) {\n        controller.enqueue({\n          type: \"stream-start\",\n          warnings,\n        });\n\n        let textStarted = false;\n        let finished = false;\n\n        const ensureTextStart = () => {\n          if (!textStarted) {\n            controller.enqueue({\n              type: \"text-start\",\n              id: textId,\n            });\n            textStarted = true;\n          }\n        };\n\n        const emitTextDelta = (delta: string) => {\n          if (!delta) return;\n          ensureTextStart();\n          controller.enqueue({\n            type: \"text-delta\",\n            id: textId,\n            delta,\n          });\n        };\n\n        const emitTextEndIfNeeded = () => {\n          if (!textStarted) return;\n          controller.enqueue({\n            type: \"text-end\",\n            id: textId,\n          });\n          textStarted = false;\n        };\n\n        const finishStream = (\n          finishReason: LanguageModelV3FinishReason,\n          usage?: {\n            prompt_tokens?: number;\n            completion_tokens?: number;\n            total_tokens?: number;\n          },\n        ) => {\n          if (finished) return;\n          finished = true;\n          emitTextEndIfNeeded();\n          controller.enqueue({\n            type: \"finish\",\n            finishReason,\n            usage: {\n              inputTokens: {\n                total: usage?.prompt_tokens,\n                noCache: undefined,\n                cacheRead: undefined,\n                cacheWrite: undefined,\n              },\n              outputTokens: {\n                total: usage?.completion_tokens,\n                text: undefined,\n                reasoning: undefined,\n              },\n              raw: {\n                total: usage?.total_tokens,\n              },\n            },\n          });\n          controller.close();\n        };\n\n        try {\n          const streamingRequest: ChatCompletionRequestStreaming = {\n            ...requestOptions,\n            messages: promptMessages,\n            stream: true,\n            stream_options: { include_usage: true },\n            ...(options.abortSignal &&\n              !useWorker && { signal: options.abortSignal }),\n          };\n\n          const response =\n            await engine.chat.completions.create(streamingRequest);\n\n          let lastUsage:\n            | {\n                prompt_tokens?: number;\n                completion_tokens?: number;\n                total_tokens?: number;\n              }\n            | undefined;\n          let isAbort = false;\n\n          const chunks = (async function* () {\n            for await (const chunk of response) {\n              const choice = chunk.choices[0];\n              if (!choice) continue;\n              if (choice.delta.content) yield choice.delta.content;\n              if (chunk.usage) lastUsage = chunk.usage;\n              if (choice.finish_reason === \"abort\") isAbort = true;\n            }\n          })();\n\n          const result = await processToolCallStream(\n            chunks,\n            emitTextDelta,\n            controller,\n          );\n\n          if (result.trailingText) {\n            emitTextDelta(result.trailingText);\n          }\n\n          const finishReason: LanguageModelV3FinishReason = isAbort\n            ? { unified: \"other\", raw: \"abort\" }\n            : result.toolCallDetected\n              ? { unified: \"tool-calls\", raw: \"tool-calls\" }\n              : { unified: \"stop\", raw: \"stop\" };\n\n          finishStream(finishReason, lastUsage);\n        } catch (error) {\n          // Propagate all other errors.\n          controller.error(error);\n        } finally {\n          if (options.abortSignal) {\n            options.abortSignal.removeEventListener(\"abort\", abortHandler);\n          }\n          if (!finished) {\n            controller.close();\n          }\n        }\n      },\n    });\n\n    return {\n      stream,\n      request: { body: { ...requestOptions, messages: promptMessages } },\n    };\n  }\n}\n","import type { ChatCompletionMessageParam } from \"@mlc-ai/web-llm\";\n\n/**\n * Extracts the system prompt from a message array and returns both the system prompt\n * and the remaining messages without the system message.\n *\n * @param messages - Array of chat messages\n * @returns Object with systemPrompt string and messages array without system messages\n */\nexport function extractSystemPrompt(messages: ChatCompletionMessageParam[]): {\n  systemPrompt: string | undefined;\n  messages: ChatCompletionMessageParam[];\n} {\n  const systemMessages = messages.filter((msg) => msg.role === \"system\");\n  const nonSystemMessages = messages.filter((msg) => msg.role !== \"system\");\n\n  if (systemMessages.length === 0) {\n    return { systemPrompt: undefined, messages };\n  }\n\n  // Combine all system messages into one\n  const systemPrompt = systemMessages\n    .map((msg) => msg.content)\n    .filter((content): content is string => typeof content === \"string\")\n    .join(\"\\n\\n\");\n\n  return {\n    systemPrompt: systemPrompt || undefined,\n    messages: nonSystemMessages,\n  };\n}\n\n/**\n * Prepends a system prompt to the messages array.\n * If there's already a system message, it prepends to it.\n * Otherwise, creates a new system message at the start.\n *\n * @param messages - Array of chat messages\n * @param systemPrompt - System prompt to prepend\n * @returns New messages array with system prompt prepended\n */\nexport function prependSystemPromptToMessages(\n  messages: ChatCompletionMessageParam[],\n  systemPrompt: string,\n): ChatCompletionMessageParam[] {\n  if (!systemPrompt.trim()) {\n    return messages;\n  }\n\n  const systemMessageIndex = messages.findIndex((msg) => msg.role === \"system\");\n\n  if (systemMessageIndex !== -1) {\n    const newMessages = [...messages];\n    const existingSystemMessage = messages[systemMessageIndex];\n    const existingContent =\n      typeof existingSystemMessage.content === \"string\"\n        ? existingSystemMessage.content\n        : \"\";\n\n    newMessages[systemMessageIndex] = {\n      ...existingSystemMessage,\n      content: systemPrompt + (existingContent ? `\\n\\n${existingContent}` : \"\"),\n    };\n\n    return newMessages;\n  }\n\n  return [\n    {\n      role: \"system\",\n      content: systemPrompt,\n    },\n    ...messages,\n  ];\n}\n","declare global {\n  interface Navigator {\n    gpu?: GPU;\n  }\n}\n\nexport function isMobile(): boolean {\n  if (typeof navigator === \"undefined\") return false;\n  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(\n    navigator.userAgent,\n  );\n}\n\nexport function checkWebGPU(): boolean {\n  try {\n    return !!globalThis?.navigator?.gpu;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Check if the browser supports WebLLM (WebGPU)\n */\nexport function doesBrowserSupportWebLLM(): boolean {\n  return checkWebGPU();\n}\n","import {\n  EmbeddingModelV3,\n  EmbeddingModelV3CallOptions,\n  EmbeddingModelV3Result,\n  TooManyEmbeddingValuesForCallError,\n  LoadSettingError,\n} from \"@ai-sdk/provider\";\nimport {\n  AppConfig,\n  CreateWebWorkerMLCEngine,\n  InitProgressReport,\n  MLCEngine,\n  MLCEngineConfig,\n  MLCEngineInterface,\n} from \"@mlc-ai/web-llm\";\nimport { Availability } from \"../types\";\nimport { isMobile, checkWebGPU } from \"../utils/browser\";\n\nexport type WebLLMEmbeddingModelId = string;\n\nexport interface WebLLMEmbeddingSettings {\n  /**\n   * Custom app configuration for WebLLM\n   */\n  appConfig?: AppConfig;\n  /**\n   * Progress callback for model initialization\n   */\n  initProgressCallback?: (progress: InitProgressReport) => void;\n  /**\n   * Engine configuration options\n   */\n  engineConfig?: MLCEngineConfig;\n  /**\n   * A web worker instance to run the model in.\n   * When provided, the model will run in a separate thread.\n   *\n   * @default undefined\n   */\n  worker?: Worker;\n  /**\n   * Maximum number of texts to embed in a single call.\n   * @default 100\n   */\n  maxEmbeddingsPerCall?: number;\n}\n\ntype WebLLMEmbeddingConfig = {\n  provider: string;\n  modelId: WebLLMEmbeddingModelId;\n  options: WebLLMEmbeddingSettings;\n};\n\nexport class WebLLMEmbeddingModel implements EmbeddingModelV3 {\n  readonly specificationVersion = \"v3\";\n  readonly provider = \"web-llm\";\n  readonly modelId: WebLLMEmbeddingModelId;\n  readonly maxEmbeddingsPerCall: number;\n  readonly supportsParallelCalls = false;\n\n  private readonly config: WebLLMEmbeddingConfig;\n  private engine?: MLCEngineInterface;\n  private isInitialized = false;\n  private initializationPromise?: Promise<void>;\n\n  constructor(\n    modelId: WebLLMEmbeddingModelId,\n    options: WebLLMEmbeddingSettings = {},\n  ) {\n    this.modelId = modelId;\n    this.maxEmbeddingsPerCall = options.maxEmbeddingsPerCall ?? 100;\n    this.config = {\n      provider: this.provider,\n      modelId,\n      options,\n    };\n  }\n\n  /**\n   * Check if the model is initialized and ready to use\n   */\n  get isModelInitialized(): boolean {\n    return this.isInitialized;\n  }\n\n  private async getEngine(\n    options?: MLCEngineConfig,\n    onInitProgress?: (progress: InitProgressReport) => void,\n  ): Promise<MLCEngineInterface> {\n    const availability = await this.availability();\n    if (availability === \"unavailable\") {\n      throw new LoadSettingError({\n        message:\n          \"WebLLM is not available. This library requires a browser with WebGPU support.\",\n      });\n    }\n\n    if (this.engine && this.isInitialized) return this.engine;\n\n    if (this.initializationPromise) {\n      await this.initializationPromise;\n      if (this.engine) return this.engine;\n    }\n\n    this.initializationPromise = this._initializeEngine(\n      options,\n      onInitProgress,\n    );\n    await this.initializationPromise;\n\n    if (!this.engine) {\n      throw new LoadSettingError({\n        message: \"Engine initialization failed\",\n      });\n    }\n\n    return this.engine;\n  }\n\n  private async _initializeEngine(\n    options?: MLCEngineConfig,\n    onInitProgress?: (progress: InitProgressReport) => void,\n  ): Promise<void> {\n    try {\n      const engineConfig = {\n        ...this.config.options.engineConfig,\n        ...options,\n        initProgressCallback:\n          onInitProgress || this.config.options.initProgressCallback,\n      };\n\n      if (this.config.options.worker) {\n        this.engine = await CreateWebWorkerMLCEngine(\n          this.config.options.worker,\n          this.modelId,\n          engineConfig,\n        );\n      } else {\n        this.engine = new MLCEngine(engineConfig);\n        await this.engine.reload(this.modelId);\n      }\n\n      this.isInitialized = true;\n    } catch (error) {\n      this.engine = undefined;\n      this.isInitialized = false;\n      this.initializationPromise = undefined;\n\n      throw new LoadSettingError({\n        message: `Failed to initialize WebLLM embedding engine: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n      });\n    }\n  }\n\n  /**\n   * Check the availability of the WebLLM embedding model\n   * @returns Promise resolving to \"unavailable\", \"available\", or \"downloadable\"\n   */\n  public async availability(): Promise<Availability> {\n    if (this.isInitialized) {\n      return \"available\";\n    }\n\n    if (this.config.options.worker && isMobile()) {\n      return \"downloadable\";\n    }\n\n    const supported = checkWebGPU();\n    return supported ? \"downloadable\" : \"unavailable\";\n  }\n\n  /**\n   * Creates an engine session with download progress monitoring.\n   *\n   * @example\n   * ```typescript\n   * const engine = await model.createSessionWithProgress(\n   *   (progress) => {\n   *     console.log(`Download progress: ${Math.round(progress.progress * 100)}%`);\n   *   }\n   * );\n   * ```\n   *\n   * @param onInitProgress Optional callback receiving progress reports during model download\n   * @returns Promise resolving to a configured WebLLM engine\n   * @throws {LoadSettingError} When WebLLM isn't available or model is unavailable\n   */\n  public async createSessionWithProgress(\n    onInitProgress?: (progress: InitProgressReport) => void,\n  ): Promise<MLCEngineInterface> {\n    return this.getEngine(undefined, onInitProgress);\n  }\n\n  /**\n   * Embed texts using the WebLLM embedding model\n   */\n  public async doEmbed(\n    options: EmbeddingModelV3CallOptions,\n  ): Promise<EmbeddingModelV3Result> {\n    const { values, abortSignal } = options;\n\n    if (values.length > this.maxEmbeddingsPerCall) {\n      throw new TooManyEmbeddingValuesForCallError({\n        provider: this.provider,\n        modelId: this.modelId,\n        maxEmbeddingsPerCall: this.maxEmbeddingsPerCall,\n        values,\n      });\n    }\n\n    if (abortSignal?.aborted) {\n      throw new Error(\"Operation was aborted\");\n    }\n\n    const engine = await this.getEngine();\n\n    const abortHandler = () => {\n      engine.interruptGenerate();\n    };\n\n    if (abortSignal) {\n      abortSignal.addEventListener(\"abort\", abortHandler);\n    }\n\n    try {\n      const response = await engine.embeddings.create({\n        input: values,\n        model: this.modelId,\n        ...(abortSignal &&\n          !this.config.options.worker && { signal: abortSignal }),\n      });\n\n      const sortedEmbeddings = response.data\n        .sort((a, b) => a.index - b.index)\n        .map((e) => e.embedding);\n\n      return {\n        embeddings: sortedEmbeddings,\n        usage: {\n          tokens: response.usage.total_tokens,\n        },\n        providerMetadata: {\n          webllm: {\n            model: response.model,\n            promptTokens: response.usage.prompt_tokens,\n            totalTokens: response.usage.total_tokens,\n            prefillTokensPerSecond: response.usage.extra?.prefill_tokens_per_s,\n          },\n        },\n        warnings: [],\n      };\n    } catch (error) {\n      throw new Error(\n        `WebLLM embedding failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n      );\n    } finally {\n      if (abortSignal) {\n        abortSignal.removeEventListener(\"abort\", abortHandler);\n      }\n    }\n  }\n}\n","import {\n  EmbeddingModelV3,\n  NoSuchModelError,\n  ProviderV3,\n} from \"@ai-sdk/provider\";\nimport {\n  WebLLMLanguageModel,\n  WebLLMModelId,\n  WebLLMSettings,\n} from \"./chat/web-llm-language-model\";\nimport {\n  WebLLMEmbeddingModel,\n  WebLLMEmbeddingModelId,\n  WebLLMEmbeddingSettings,\n} from \"./embedding/web-llm-embedding-model\";\n\nexport interface WebLLMProvider extends ProviderV3 {\n  (modelId: WebLLMModelId, settings?: WebLLMSettings): WebLLMLanguageModel;\n\n  /**\n   * Creates a model for text generation.\n   */\n  languageModel(\n    modelId: WebLLMModelId,\n    settings?: WebLLMSettings,\n  ): WebLLMLanguageModel;\n\n  /**\n   * Creates a model for text generation.\n   */\n  chat(modelId: WebLLMModelId, settings?: WebLLMSettings): WebLLMLanguageModel;\n\n  /**\n   * Creates a model for text embeddings.\n   */\n  embedding(\n    modelId: WebLLMEmbeddingModelId,\n    settings?: WebLLMEmbeddingSettings,\n  ): EmbeddingModelV3;\n\n  /**\n   * Creates a model for text embeddings.\n   */\n  embeddingModel: (\n    modelId: WebLLMEmbeddingModelId,\n    settings?: WebLLMEmbeddingSettings,\n  ) => EmbeddingModelV3;\n}\n\n/**\n * Create a WebLLM provider instance.\n */\nexport function createWebLLM(): WebLLMProvider {\n  const createLanguageModel = (\n    modelId: WebLLMModelId,\n    settings?: WebLLMSettings,\n  ) => {\n    return new WebLLMLanguageModel(modelId, settings);\n  };\n\n  const createEmbeddingModel = (\n    modelId: WebLLMEmbeddingModelId,\n    settings?: WebLLMEmbeddingSettings,\n  ) => {\n    return new WebLLMEmbeddingModel(modelId, settings);\n  };\n\n  const provider = function (\n    modelId: WebLLMModelId,\n    settings?: WebLLMSettings,\n  ) {\n    if (new.target) {\n      throw new Error(\n        \"The WebLLM model function cannot be called with the new keyword.\",\n      );\n    }\n\n    return createLanguageModel(modelId, settings);\n  };\n\n  provider.specificationVersion = \"v3\" as const;\n  provider.languageModel = createLanguageModel;\n  provider.chat = createLanguageModel;\n  provider.embedding = createEmbeddingModel;\n  provider.embeddingModel = createEmbeddingModel;\n\n  provider.imageModel = (modelId: string) => {\n    throw new NoSuchModelError({ modelId, modelType: \"imageModel\" });\n  };\n\n  provider.speechModel = (modelId: string) => {\n    throw new NoSuchModelError({ modelId, modelType: \"speechModel\" });\n  };\n\n  provider.transcriptionModel = (modelId: string) => {\n    throw new NoSuchModelError({ modelId, modelType: \"transcriptionModel\" });\n  };\n\n  return provider as WebLLMProvider;\n}\n\n/**\n * Default WebLLM provider instance\n *\n * @example\n * ```typescript\n * import { webLLM } from \"@browser-ai/web-llm\";\n *\n * // Language model\n * const chat = webLLM(\"Llama-3.2-3B-Instruct-q4f16_1-MLC\");\n *\n * // Embedding model\n * const embed = webLLM.embeddingModel(\"snowflake-arctic-embed-m-q0f32-MLC-b32\");\n * ```\n */\nexport const webLLM = createWebLLM();\n"]}