const normalizeLine = line => {
  if (line.startsWith('Error: ')) {
    return line.slice('Error: '.length);
  }
  if (line.startsWith('VError: ')) {
    return line.slice('VError: '.length);
  }
  return line;
};
const getCombinedMessage = (error, message) => {
  const stringifiedError = normalizeLine(`${error}`);
  if (message) {
    return `${message}: ${stringifiedError}`;
  }
  return stringifiedError;
};
const NewLine$2 = '\n';
const getNewLineIndex$1 = (string, startIndex = undefined) => {
  return string.indexOf(NewLine$2, startIndex);
};
const mergeStacks = (parent, child) => {
  if (!child) {
    return parent;
  }
  const parentNewLineIndex = getNewLineIndex$1(parent);
  const childNewLineIndex = getNewLineIndex$1(child);
  if (childNewLineIndex === -1) {
    return parent;
  }
  const parentFirstLine = parent.slice(0, parentNewLineIndex);
  const childRest = child.slice(childNewLineIndex);
  const childFirstLine = normalizeLine(child.slice(0, childNewLineIndex));
  if (parentFirstLine.includes(childFirstLine)) {
    return parentFirstLine + childRest;
  }
  return child;
};
class VError extends Error {
  constructor(error, message) {
    const combinedMessage = getCombinedMessage(error, message);
    super(combinedMessage);
    this.name = 'VError';
    if (error instanceof Error) {
      this.stack = mergeStacks(this.stack, error.stack);
    }
    if (error.codeFrame) {
      // @ts-ignore
      this.codeFrame = error.codeFrame;
    }
    if (error.code) {
      // @ts-ignore
      this.code = error.code;
    }
  }
}

const isMessagePort = value => {
  return value && value instanceof MessagePort;
};
const isMessagePortMain = value => {
  return value && value.constructor && value.constructor.name === 'MessagePortMain';
};
const isOffscreenCanvas = value => {
  return typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas;
};
const isInstanceOf = (value, constructorName) => {
  return value?.constructor?.name === constructorName;
};
const isSocket = value => {
  return isInstanceOf(value, 'Socket');
};
const transferrables = [isMessagePort, isMessagePortMain, isOffscreenCanvas, isSocket];
const isTransferrable = value => {
  for (const fn of transferrables) {
    if (fn(value)) {
      return true;
    }
  }
  return false;
};
const walkValue = (value, transferrables, isTransferrable) => {
  if (!value) {
    return;
  }
  if (isTransferrable(value)) {
    transferrables.push(value);
    return;
  }
  if (Array.isArray(value)) {
    for (const item of value) {
      walkValue(item, transferrables, isTransferrable);
    }
    return;
  }
  if (typeof value === 'object') {
    for (const property of Object.values(value)) {
      walkValue(property, transferrables, isTransferrable);
    }
    return;
  }
};
const getTransferrables = value => {
  const transferrables = [];
  walkValue(value, transferrables, isTransferrable);
  return transferrables;
};
const attachEvents = that => {
  const handleMessage = (...args) => {
    const data = that.getData(...args);
    that.dispatchEvent(new MessageEvent('message', {
      data
    }));
  };
  that.onMessage(handleMessage);
  const handleClose = event => {
    that.dispatchEvent(new Event('close'));
  };
  that.onClose(handleClose);
};
class Ipc extends EventTarget {
  constructor(rawIpc) {
    super();
    this._rawIpc = rawIpc;
    attachEvents(this);
  }
}
const E_INCOMPATIBLE_NATIVE_MODULE = 'E_INCOMPATIBLE_NATIVE_MODULE';
const E_MODULES_NOT_SUPPORTED_IN_ELECTRON = 'E_MODULES_NOT_SUPPORTED_IN_ELECTRON';
const ERR_MODULE_NOT_FOUND = 'ERR_MODULE_NOT_FOUND';
const NewLine$1 = '\n';
const joinLines$1 = lines => {
  return lines.join(NewLine$1);
};
const RE_AT = /^\s+at/;
const RE_AT_PROMISE_INDEX = /^\s*at async Promise.all \(index \d+\)$/;
const isNormalStackLine = line => {
  return RE_AT.test(line) && !RE_AT_PROMISE_INDEX.test(line);
};
const getDetails = lines => {
  const index = lines.findIndex(isNormalStackLine);
  if (index === -1) {
    return {
      actualMessage: joinLines$1(lines),
      rest: []
    };
  }
  let lastIndex = index - 1;
  while (++lastIndex < lines.length) {
    if (!isNormalStackLine(lines[lastIndex])) {
      break;
    }
  }
  return {
    actualMessage: lines[index - 1],
    rest: lines.slice(index, lastIndex)
  };
};
const splitLines$1 = lines => {
  return lines.split(NewLine$1);
};
const RE_MESSAGE_CODE_BLOCK_START = /^Error: The module '.*'$/;
const RE_MESSAGE_CODE_BLOCK_END = /^\s* at/;
const isMessageCodeBlockStartIndex = line => {
  return RE_MESSAGE_CODE_BLOCK_START.test(line);
};
const isMessageCodeBlockEndIndex = line => {
  return RE_MESSAGE_CODE_BLOCK_END.test(line);
};
const getMessageCodeBlock = stderr => {
  const lines = splitLines$1(stderr);
  const startIndex = lines.findIndex(isMessageCodeBlockStartIndex);
  const endIndex = startIndex + lines.slice(startIndex).findIndex(isMessageCodeBlockEndIndex, startIndex);
  const relevantLines = lines.slice(startIndex, endIndex);
  const relevantMessage = relevantLines.join(' ').slice('Error: '.length);
  return relevantMessage;
};
const isModuleNotFoundMessage = line => {
  return line.includes('[ERR_MODULE_NOT_FOUND]');
};
const getModuleNotFoundError = stderr => {
  const lines = splitLines$1(stderr);
  const messageIndex = lines.findIndex(isModuleNotFoundMessage);
  const message = lines[messageIndex];
  return {
    code: ERR_MODULE_NOT_FOUND,
    message
  };
};
const isModuleNotFoundError = stderr => {
  if (!stderr) {
    return false;
  }
  return stderr.includes('ERR_MODULE_NOT_FOUND');
};
const isModulesSyntaxError = stderr => {
  if (!stderr) {
    return false;
  }
  return stderr.includes('SyntaxError: Cannot use import statement outside a module');
};
const RE_NATIVE_MODULE_ERROR = /^innerError Error: Cannot find module '.*.node'/;
const RE_NATIVE_MODULE_ERROR_2 = /was compiled against a different Node.js version/;
const isUnhelpfulNativeModuleError = stderr => {
  return RE_NATIVE_MODULE_ERROR.test(stderr) && RE_NATIVE_MODULE_ERROR_2.test(stderr);
};
const getNativeModuleErrorMessage = stderr => {
  const message = getMessageCodeBlock(stderr);
  return {
    code: E_INCOMPATIBLE_NATIVE_MODULE,
    message: `Incompatible native node module: ${message}`
  };
};
const getModuleSyntaxError = () => {
  return {
    code: E_MODULES_NOT_SUPPORTED_IN_ELECTRON,
    message: `ES Modules are not supported in electron`
  };
};
const getHelpfulChildProcessError = (stdout, stderr) => {
  if (isUnhelpfulNativeModuleError(stderr)) {
    return getNativeModuleErrorMessage(stderr);
  }
  if (isModulesSyntaxError(stderr)) {
    return getModuleSyntaxError();
  }
  if (isModuleNotFoundError(stderr)) {
    return getModuleNotFoundError(stderr);
  }
  const lines = splitLines$1(stderr);
  const {
    actualMessage,
    rest
  } = getDetails(lines);
  return {
    code: '',
    message: actualMessage,
    stack: rest
  };
};
class IpcError extends VError {
  // @ts-ignore
  constructor(betterMessage, stdout = '', stderr = '') {
    if (stdout || stderr) {
      // @ts-ignore
      const {
        code,
        message,
        stack
      } = getHelpfulChildProcessError(stdout, stderr);
      const cause = new Error(message);
      // @ts-ignore
      cause.code = code;
      cause.stack = stack;
      super(cause, betterMessage);
    } else {
      super(betterMessage);
    }
    // @ts-ignore
    this.name = 'IpcError';
    // @ts-ignore
    this.stdout = stdout;
    // @ts-ignore
    this.stderr = stderr;
  }
}
const readyMessage = 'ready';
const getData$2 = event => {
  return event.data;
};
const listen$7 = () => {
  // @ts-ignore
  if (typeof WorkerGlobalScope === 'undefined') {
    throw new TypeError('module is not in web worker scope');
  }
  return globalThis;
};
const signal$8 = global => {
  global.postMessage(readyMessage);
};
class IpcChildWithModuleWorker extends Ipc {
  getData(event) {
    return getData$2(event);
  }
  send(message) {
    // @ts-ignore
    this._rawIpc.postMessage(message);
  }
  sendAndTransfer(message) {
    const transfer = getTransferrables(message);
    // @ts-ignore
    this._rawIpc.postMessage(message, transfer);
  }
  dispose() {
    // ignore
  }
  onClose(callback) {
    // ignore
  }
  onMessage(callback) {
    this._rawIpc.addEventListener('message', callback);
  }
}
const wrap$f = global => {
  return new IpcChildWithModuleWorker(global);
};
const waitForFirstMessage = async port => {
  const {
    promise,
    resolve
  } = Promise.withResolvers();
  port.addEventListener('message', resolve, {
    once: true
  });
  const event = await promise;
  // @ts-ignore
  return event.data;
};
const listen$6 = async () => {
  const parentIpcRaw = listen$7();
  signal$8(parentIpcRaw);
  const parentIpc = wrap$f(parentIpcRaw);
  const firstMessage = await waitForFirstMessage(parentIpc);
  if (firstMessage.method !== 'initialize') {
    throw new IpcError('unexpected first message');
  }
  const type = firstMessage.params[0];
  if (type === 'message-port') {
    parentIpc.send({
      id: firstMessage.id,
      jsonrpc: '2.0',
      result: null
    });
    parentIpc.dispose();
    const port = firstMessage.params[1];
    return port;
  }
  return globalThis;
};
class IpcChildWithModuleWorkerAndMessagePort extends Ipc {
  getData(event) {
    return getData$2(event);
  }
  send(message) {
    this._rawIpc.postMessage(message);
  }
  sendAndTransfer(message) {
    const transfer = getTransferrables(message);
    this._rawIpc.postMessage(message, transfer);
  }
  dispose() {
    if (this._rawIpc.close) {
      this._rawIpc.close();
    }
  }
  onClose(callback) {
    // ignore
  }
  onMessage(callback) {
    this._rawIpc.addEventListener('message', callback);
    this._rawIpc.start();
  }
}
const wrap$e = port => {
  return new IpcChildWithModuleWorkerAndMessagePort(port);
};
const IpcChildWithModuleWorkerAndMessagePort$1 = {
  __proto__: null,
  listen: listen$6,
  wrap: wrap$e
};
const addListener = (emitter, type, callback) => {
  if ('addEventListener' in emitter) {
    emitter.addEventListener(type, callback);
  } else {
    emitter.on(type, callback);
  }
};
const removeListener = (emitter, type, callback) => {
  if ('removeEventListener' in emitter) {
    emitter.removeEventListener(type, callback);
  } else {
    emitter.off(type, callback);
  }
};
const getFirstEvent = (eventEmitter, eventMap) => {
  const {
    promise,
    resolve
  } = Promise.withResolvers();
  const listenerMap = Object.create(null);
  const cleanup = value => {
    for (const event of Object.keys(eventMap)) {
      removeListener(eventEmitter, event, listenerMap[event]);
    }
    resolve(value);
  };
  for (const [event, type] of Object.entries(eventMap)) {
    const listener = event => {
      cleanup({
        event,
        type
      });
    };
    addListener(eventEmitter, event, listener);
    listenerMap[event] = listener;
  }
  return promise;
};
const Message$1 = 3;
const create$5$1 = async ({
  isMessagePortOpen,
  messagePort
}) => {
  if (!isMessagePort(messagePort)) {
    throw new IpcError('port must be of type MessagePort');
  }
  if (isMessagePortOpen) {
    return messagePort;
  }
  const eventPromise = getFirstEvent(messagePort, {
    message: Message$1
  });
  messagePort.start();
  const {
    event,
    type
  } = await eventPromise;
  if (type !== Message$1) {
    throw new IpcError('Failed to wait for ipc message');
  }
  if (event.data !== readyMessage) {
    throw new IpcError('unexpected first message');
  }
  return messagePort;
};
const signal$1 = messagePort => {
  messagePort.start();
};
class IpcParentWithMessagePort extends Ipc {
  getData = getData$2;
  send(message) {
    this._rawIpc.postMessage(message);
  }
  sendAndTransfer(message) {
    const transfer = getTransferrables(message);
    this._rawIpc.postMessage(message, transfer);
  }
  dispose() {
    this._rawIpc.close();
  }
  onMessage(callback) {
    this._rawIpc.addEventListener('message', callback);
  }
  onClose(callback) {}
}
const wrap$5 = messagePort => {
  return new IpcParentWithMessagePort(messagePort);
};
const IpcParentWithMessagePort$1 = {
  __proto__: null,
  create: create$5$1,
  signal: signal$1,
  wrap: wrap$5
};

class CommandNotFoundError extends Error {
  constructor(command) {
    super(`Command not found ${command}`);
    this.name = 'CommandNotFoundError';
  }
}
const commands = Object.create(null);
const register = commandMap => {
  Object.assign(commands, commandMap);
};
const getCommand = key => {
  return commands[key];
};
const execute$1 = (command, ...args) => {
  const fn = getCommand(command);
  if (!fn) {
    throw new CommandNotFoundError(command);
  }
  return fn(...args);
};

const Two$1 = '2.0';
const callbacks = Object.create(null);
const get$1 = id => {
  return callbacks[id];
};
const remove$1 = id => {
  delete callbacks[id];
};
class JsonRpcError extends Error {
  constructor(message) {
    super(message);
    this.name = 'JsonRpcError';
  }
}
const NewLine = '\n';
const DomException = 'DOMException';
const ReferenceError$1 = 'ReferenceError';
const SyntaxError$1 = 'SyntaxError';
const TypeError$1 = 'TypeError';
const getErrorConstructor = (message, type) => {
  if (type) {
    switch (type) {
      case DomException:
        return DOMException;
      case ReferenceError$1:
        return ReferenceError;
      case SyntaxError$1:
        return SyntaxError;
      case TypeError$1:
        return TypeError;
      default:
        return Error;
    }
  }
  if (message.startsWith('TypeError: ')) {
    return TypeError;
  }
  if (message.startsWith('SyntaxError: ')) {
    return SyntaxError;
  }
  if (message.startsWith('ReferenceError: ')) {
    return ReferenceError;
  }
  return Error;
};
const constructError = (message, type, name) => {
  const ErrorConstructor = getErrorConstructor(message, type);
  if (ErrorConstructor === DOMException && name) {
    return new ErrorConstructor(message, name);
  }
  if (ErrorConstructor === Error) {
    const error = new Error(message);
    if (name && name !== 'VError') {
      error.name = name;
    }
    return error;
  }
  return new ErrorConstructor(message);
};
const joinLines = lines => {
  return lines.join(NewLine);
};
const splitLines = lines => {
  return lines.split(NewLine);
};
const getCurrentStack = () => {
  const stackLinesToSkip = 3;
  const currentStack = joinLines(splitLines(new Error().stack || '').slice(stackLinesToSkip));
  return currentStack;
};
const getNewLineIndex = (string, startIndex = undefined) => {
  return string.indexOf(NewLine, startIndex);
};
const getParentStack = error => {
  let parentStack = error.stack || error.data || error.message || '';
  if (parentStack.startsWith('    at')) {
    parentStack = error.message + NewLine + parentStack;
  }
  return parentStack;
};
const MethodNotFound = -32601;
const Custom = -32001;
const restoreJsonRpcError = error => {
  const currentStack = getCurrentStack();
  if (error && error instanceof Error) {
    if (typeof error.stack === 'string') {
      error.stack = error.stack + NewLine + currentStack;
    }
    return error;
  }
  if (error && error.code && error.code === MethodNotFound) {
    const restoredError = new JsonRpcError(error.message);
    const parentStack = getParentStack(error);
    restoredError.stack = parentStack + NewLine + currentStack;
    return restoredError;
  }
  if (error && error.message) {
    const restoredError = constructError(error.message, error.type, error.name);
    if (error.data) {
      if (error.data.stack && error.data.type && error.message) {
        restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
      } else if (error.data.stack) {
        restoredError.stack = error.data.stack;
      }
      if (error.data.codeFrame) {
        // @ts-ignore
        restoredError.codeFrame = error.data.codeFrame;
      }
      if (error.data.code) {
        // @ts-ignore
        restoredError.code = error.data.code;
      }
      if (error.data.type) {
        // @ts-ignore
        restoredError.name = error.data.type;
      }
    } else {
      if (error.stack) {
        const lowerStack = restoredError.stack || '';
        // @ts-ignore
        const indexNewLine = getNewLineIndex(lowerStack);
        const parentStack = getParentStack(error);
        // @ts-ignore
        restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
      }
      if (error.codeFrame) {
        // @ts-ignore
        restoredError.codeFrame = error.codeFrame;
      }
    }
    return restoredError;
  }
  if (typeof error === 'string') {
    return new Error(`JsonRpc Error: ${error}`);
  }
  return new Error(`JsonRpc Error: ${error}`);
};
const unwrapJsonRpcResult = responseMessage => {
  if ('error' in responseMessage) {
    const restoredError = restoreJsonRpcError(responseMessage.error);
    throw restoredError;
  }
  if ('result' in responseMessage) {
    return responseMessage.result;
  }
  throw new JsonRpcError('unexpected response message');
};
const warn = (...args) => {
  console.warn(...args);
};
const resolve = (id, response) => {
  const fn = get$1(id);
  if (!fn) {
    console.log(response);
    warn(`callback ${id} may already be disposed`);
    return;
  }
  fn(response);
  remove$1(id);
};
const E_COMMAND_NOT_FOUND = 'E_COMMAND_NOT_FOUND';
const getErrorType = prettyError => {
  if (prettyError && prettyError.type) {
    return prettyError.type;
  }
  if (prettyError && prettyError.constructor && prettyError.constructor.name) {
    return prettyError.constructor.name;
  }
  return undefined;
};
const isAlreadyStack = line => {
  return line.trim().startsWith('at ');
};
const getStack = prettyError => {
  const stackString = prettyError.stack || '';
  const newLineIndex = stackString.indexOf('\n');
  if (newLineIndex !== -1 && !isAlreadyStack(stackString.slice(0, newLineIndex))) {
    return stackString.slice(newLineIndex + 1);
  }
  return stackString;
};
const getErrorProperty = (error, prettyError) => {
  if (error && error.code === E_COMMAND_NOT_FOUND) {
    return {
      code: MethodNotFound,
      data: error.stack,
      message: error.message
    };
  }
  return {
    code: Custom,
    data: {
      code: prettyError.code,
      codeFrame: prettyError.codeFrame,
      name: prettyError.name,
      stack: getStack(prettyError),
      type: getErrorType(prettyError)
    },
    message: prettyError.message
  };
};
const create$1$1 = (id, error) => {
  return {
    error,
    id,
    jsonrpc: Two$1
  };
};
const getErrorResponse = (id, error, preparePrettyError, logError) => {
  const prettyError = preparePrettyError(error);
  logError(error, prettyError);
  const errorProperty = getErrorProperty(error, prettyError);
  return create$1$1(id, errorProperty);
};
const create$8 = (message, result) => {
  return {
    id: message.id,
    jsonrpc: Two$1,
    result: result ?? null
  };
};
const getSuccessResponse = (message, result) => {
  const resultProperty = result ?? null;
  return create$8(message, resultProperty);
};
const getErrorResponseSimple = (id, error) => {
  return {
    error: {
      code: Custom,
      data: error,
      // @ts-ignore
      message: error.message
    },
    id,
    jsonrpc: Two$1
  };
};
const getResponse = async (message, ipc, execute, preparePrettyError, logError, requiresSocket) => {
  try {
    const result = requiresSocket(message.method) ? await execute(message.method, ipc, ...message.params) : await execute(message.method, ...message.params);
    return getSuccessResponse(message, result);
  } catch (error) {
    if (ipc.canUseSimpleErrorResponse) {
      return getErrorResponseSimple(message.id, error);
    }
    return getErrorResponse(message.id, error, preparePrettyError, logError);
  }
};
const defaultPreparePrettyError = error => {
  return error;
};
const defaultLogError = () => {
  // ignore
};
const defaultRequiresSocket = () => {
  return false;
};
const defaultResolve = resolve;

// TODO maybe remove this in v6 or v7, only accept options object to simplify the code
const normalizeParams = args => {
  if (args.length === 1) {
    const options = args[0];
    return {
      execute: options.execute,
      ipc: options.ipc,
      logError: options.logError || defaultLogError,
      message: options.message,
      preparePrettyError: options.preparePrettyError || defaultPreparePrettyError,
      requiresSocket: options.requiresSocket || defaultRequiresSocket,
      resolve: options.resolve || defaultResolve
    };
  }
  return {
    execute: args[2],
    ipc: args[0],
    logError: args[5],
    message: args[1],
    preparePrettyError: args[4],
    requiresSocket: args[6],
    resolve: args[3]
  };
};
const handleJsonRpcMessage = async (...args) => {
  const options = normalizeParams(args);
  const {
    execute,
    ipc,
    logError,
    message,
    preparePrettyError,
    requiresSocket,
    resolve
  } = options;
  if ('id' in message) {
    if ('method' in message) {
      const response = await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
      try {
        ipc.send(response);
      } catch (error) {
        const errorResponse = getErrorResponse(message.id, error, preparePrettyError, logError);
        ipc.send(errorResponse);
      }
      return;
    }
    resolve(message.id, message);
    return;
  }
  if ('method' in message) {
    await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
    return;
  }
  throw new JsonRpcError('unexpected message');
};

const Two = '2.0';

const create$7 = (method, params) => {
  return {
    jsonrpc: Two,
    method,
    params
  };
};

const create$6 = (id, method, params) => {
  const message = {
    id,
    jsonrpc: Two,
    method,
    params
  };
  return message;
};

let id = 0;
const create$5 = () => {
  return ++id;
};

const registerPromise = map => {
  const id = create$5();
  const {
    promise,
    resolve
  } = Promise.withResolvers();
  map[id] = resolve;
  return {
    id,
    promise
  };
};

const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer) => {
  const {
    id,
    promise
  } = registerPromise(callbacks);
  const message = create$6(id, method, params);
  if (useSendAndTransfer && ipc.sendAndTransfer) {
    ipc.sendAndTransfer(message);
  } else {
    ipc.send(message);
  }
  const responseMessage = await promise;
  return unwrapJsonRpcResult(responseMessage);
};
const createRpc = ipc => {
  const callbacks = Object.create(null);
  ipc._resolve = (id, response) => {
    const fn = callbacks[id];
    if (!fn) {
      console.warn(`callback ${id} may already be disposed`);
      return;
    }
    fn(response);
    delete callbacks[id];
  };
  const rpc = {
    async dispose() {
      await ipc?.dispose();
    },
    invoke(method, ...params) {
      return invokeHelper(callbacks, ipc, method, params, false);
    },
    invokeAndTransfer(method, ...params) {
      return invokeHelper(callbacks, ipc, method, params, true);
    },
    // @ts-ignore
    ipc,
    /**
     * @deprecated
     */
    send(method, ...params) {
      const message = create$7(method, params);
      ipc.send(message);
    }
  };
  return rpc;
};

const requiresSocket = () => {
  return false;
};
const preparePrettyError = error => {
  return error;
};
const logError = () => {
  // handled by renderer worker
};
const handleMessage = event => {
  const actualRequiresSocket = event?.target?.requiresSocket || requiresSocket;
  const actualExecute = event?.target?.execute || execute$1;
  return handleJsonRpcMessage(event.target, event.data, actualExecute, event.target._resolve, preparePrettyError, logError, actualRequiresSocket);
};

const handleIpc = ipc => {
  if ('addEventListener' in ipc) {
    ipc.addEventListener('message', handleMessage);
  } else if ('on' in ipc) {
    // deprecated
    ipc.on('message', handleMessage);
  }
};

const listen$1 = async (module, options) => {
  const rawIpc = await module.listen(options);
  if (module.signal) {
    module.signal(rawIpc);
  }
  const ipc = module.wrap(rawIpc);
  return ipc;
};

const create$4 = async ({
  commandMap,
  isMessagePortOpen = true,
  messagePort
}) => {
  // TODO create a commandMap per rpc instance
  register(commandMap);
  const rawIpc = await IpcParentWithMessagePort$1.create({
    isMessagePortOpen,
    messagePort
  });
  const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
  handleIpc(ipc);
  const rpc = createRpc(ipc);
  messagePort.start();
  return rpc;
};

const create$3 = async ({
  commandMap,
  isMessagePortOpen,
  send
}) => {
  const {
    port1,
    port2
  } = new MessageChannel();
  await send(port1);
  return create$4({
    commandMap,
    isMessagePortOpen,
    messagePort: port2
  });
};

const createSharedLazyRpc = factory => {
  let rpcPromise;
  const getOrCreate = () => {
    if (!rpcPromise) {
      rpcPromise = factory();
    }
    return rpcPromise;
  };
  return {
    async dispose() {
      const rpc = await getOrCreate();
      await rpc.dispose();
    },
    async invoke(method, ...params) {
      const rpc = await getOrCreate();
      return rpc.invoke(method, ...params);
    },
    async invokeAndTransfer(method, ...params) {
      const rpc = await getOrCreate();
      return rpc.invokeAndTransfer(method, ...params);
    },
    async send(method, ...params) {
      const rpc = await getOrCreate();
      rpc.send(method, ...params);
    }
  };
};

const create$2 = async ({
  commandMap,
  isMessagePortOpen,
  send
}) => {
  return createSharedLazyRpc(() => {
    return create$3({
      commandMap,
      isMessagePortOpen,
      send
    });
  });
};

const create$1 = async ({
  commandMap
}) => {
  // TODO create a commandMap per rpc instance
  register(commandMap);
  const ipc = await listen$1(IpcChildWithModuleWorkerAndMessagePort$1);
  handleIpc(ipc);
  const rpc = createRpc(ipc);
  return rpc;
};

const createMockRpc = ({
  commandMap
}) => {
  const invocations = [];
  const invoke = (method, ...params) => {
    invocations.push([method, ...params]);
    const command = commandMap[method];
    if (!command) {
      throw new Error(`command ${method} not found`);
    }
    return command(...params);
  };
  const mockRpc = {
    invocations,
    invoke,
    invokeAndTransfer: invoke
  };
  return mockRpc;
};

const rpcs = Object.create(null);
const set$4 = (id, rpc) => {
  rpcs[id] = rpc;
};
const get = id => {
  return rpcs[id];
};
const remove = id => {
  delete rpcs[id];
};

/* eslint-disable  @typescript-eslint/explicit-function-return-type */
const create = rpcId => {
  return {
    async dispose() {
      const rpc = get(rpcId);
      await rpc.dispose();
    },
    // @ts-ignore
    invoke(method, ...params) {
      const rpc = get(rpcId);
      // @ts-ignore
      return rpc.invoke(method, ...params);
    },
    // @ts-ignore
    invokeAndTransfer(method, ...params) {
      const rpc = get(rpcId);
      // @ts-ignore
      return rpc.invokeAndTransfer(method, ...params);
    },
    registerMockRpc(commandMap) {
      const mockRpc = createMockRpc({
        commandMap
      });
      set$4(rpcId, mockRpc);
      // @ts-ignore
      mockRpc[Symbol.dispose] = () => {
        remove(rpcId);
      };
      // @ts-ignore
      return mockRpc;
    },
    set(rpc) {
      set$4(rpcId, rpc);
    }
  };
};

const {
  invoke: invoke$2,
  set: set$3
} = create(6010);

const Web = 1;

const ChatStorageWorker = 6003;
const ChatToolWorker = 6005;
const RendererWorker = 1;

const {
  invoke: invoke$1,
  set: set$2
} = create(ChatStorageWorker);
const appendEvent = async event => {
  return invoke$1('ChatStorage.appendEvent', event);
};

const {
  invoke,
  set: set$1
} = create(ChatToolWorker);
const execute = async (name, rawArguments, options) => {
  return invoke('ChatTool.execute', name, rawArguments, options);
};

const {
  invokeAndTransfer,
  set
} = create(RendererWorker);
const sendMessagePortToAuthWorker$1 = async (port, rpcId) => {
  const command = 'HandleMessagePort.handleMessagePort';
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToAuthWorker', port, command, rpcId);
};
const sendMessagePortToChatToolWorker = async port => {
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatToolWorker', port, 'HandleMessagePort.handleMessagePort');
};
const sendMessagePortToChatStorageWorker = async (port, rpcId) => {
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatStorageWorker', port, 'HandleMessagePort.handleMessagePort', rpcId);
};

const createSession = async options => {
  const {
    sessionId,
    timestamp,
    title
  } = options;
  await invoke$1('ChatStorage.createSession', {
    sessionId,
    timestamp,
    title
  });
};

const handleMessagePort = async port => {
  await create$4({
    commandMap: commandMap,
    isMessagePortOpen: true,
    messagePort: port
  });
};

const Message = 'message';
const AiRequest = 'ai-request';
const AiResponse = 'ai-response';
const ToolCallStarted = 'tool-call-started';
const ToolCallFinished = 'tool-call-finished';
const ToolCallsFinished = 'tool-calls-finished';

const isRawMessageEvent = event => {
  if (!event || typeof event !== 'object') {
    return false;
  }
  const value = event;
  return value.type === Message && typeof value.id === 'string' && typeof value.sessionId === 'string' && typeof value.timestamp === 'string';
};
const getMessageContent = message => {
  return (message.content || []).filter(part => {
    if ((part.type === 'text' || part.type === 'input_text') && typeof part.text === 'string') {
      return true;
    }
    return part.type === 'function_call' && typeof part.arguments === 'string' && typeof part.call_id === 'string' && typeof part.name === 'string';
  });
};
const getMessageText = message => {
  return (message.content || []).filter(part => (part.type === 'text' || part.type === 'input_text') && typeof part.text === 'string').map(part => part.text || '').join('');
};
const getMessageToolCalls = message => {
  return (message.content || []).filter(part => part.type === 'function_call' && typeof part.arguments === 'string' && typeof part.call_id === 'string' && typeof part.name === 'string').map(part => ({
    arguments: part.arguments,
    id: part.call_id,
    name: part.name
  }));
};
const appendChatEvent = async event => {
  if (isRawMessageEvent(event)) {
    const content = getMessageContent(event.message);
    const text = getMessageText(event.message);
    const toolCalls = getMessageToolCalls(event.message);
    await invoke$1('ChatStorage.appendEvent', {
      message: {
        ...(event.message.attachments && event.message.attachments.length > 0 ? {
          attachments: event.message.attachments
        } : {}),
        ...(content.length > 0 ? {
          content
        } : {}),
        ...(toolCalls.length > 0 ? {
          ...(text ? {
            text
          } : {}),
          time: event.timestamp,
          toolCalls
        } : {}),
        id: event.id,
        role: event.message.role || 'assistant'
      },
      sessionId: event.sessionId,
      timestamp: event.timestamp,
      type: 'chat-message-added'
    });
    return;
  }
  await appendEvent(event);
};

const getAttachmentTextPart = attachment => {
  switch (attachment.displayType) {
    case 'file':
      return {
        text: `Attached file "${attachment.name}" (${attachment.mimeType || 'application/octet-stream'}, ${attachment.size} bytes).`,
        type: 'input_text'
      };
    case 'image':
      return {
        text: `Attached image "${attachment.name}" could not be encoded for the AI request.`,
        type: 'input_text'
      };
    case 'invalid-image':
      return {
        text: `Attached file "${attachment.name}" could not be processed as a valid image.`,
        type: 'input_text'
      };
    case 'text-file':
      return {
        text: attachment.textContent ? `Attached text file "${attachment.name}" (${attachment.mimeType || 'text/plain'}):\n\n${attachment.textContent}` : `Attached text file "${attachment.name}" (${attachment.mimeType || 'text/plain'}).`,
        type: 'input_text'
      };
  }
};
const getAttachmentParts = attachments => {
  const parts = [];
  for (const attachment of attachments) {
    if (attachment.displayType === 'image' && attachment.previewSrc) {
      parts.push({
        image_url: attachment.previewSrc,
        type: 'input_image'
      });
      continue;
    }
    parts.push(getAttachmentTextPart(attachment));
  }
  return parts;
};

const pendingSessionIds = [];
const pendingSessionWorkBySessionId = new Map();
let pendingWorkPromise;
const setPendingWorkPromise = value => {
  pendingWorkPromise = value;
};

const enqueueSessionId = (sessionId, pendingSessionWork) => {
  if (pendingSessionWork.queued) {
    return;
  }
  pendingSessionIds.push(sessionId);
  pendingSessionWork.queued = true;
};

const getComparableInput = input => {
  return JSON.stringify(input);
};
const getAiRequestInputs = value => {
  if (typeof value !== 'string') {
    return value;
  }
  return [{
    content: value,
    role: 'user'
  }];
};
const getFirstMissingIndex = (baseInputs, fallbackInputs) => {
  let baseIndex = 0;
  for (let fallbackIndex = 0; fallbackIndex < fallbackInputs.length; fallbackIndex += 1) {
    const comparableFallback = getComparableInput(fallbackInputs[fallbackIndex]);
    while (baseIndex < baseInputs.length && getComparableInput(baseInputs[baseIndex]) !== comparableFallback) {
      baseIndex += 1;
    }
    if (baseIndex === baseInputs.length) {
      return fallbackIndex;
    }
    baseIndex += 1;
  }
  return fallbackInputs.length;
};
const appendMissingAiRequestInputTail = (baseValue, fallbackValue) => {
  const baseInputs = getAiRequestInputs(baseValue);
  const fallbackInputs = getAiRequestInputs(fallbackValue);
  const firstMissingIndex = getFirstMissingIndex(baseInputs, fallbackInputs);
  return [...baseInputs, ...fallbackInputs.slice(firstMissingIndex)];
};

const addPendingSessionWork = options => {
  const existingPendingSessionWork = pendingSessionWorkBySessionId.get(options.sessionId);
  if (existingPendingSessionWork) {
    existingPendingSessionWork.options = {
      ...options,
      text: appendMissingAiRequestInputTail(existingPendingSessionWork.options.text, options.text)
    };
    existingPendingSessionWork.pendingVersion += 1;
    enqueueSessionId(options.sessionId, existingPendingSessionWork);
    return;
  }
  const pendingSessionWork = {
    options,
    pendingVersion: 1,
    processedVersion: 0,
    queued: false,
    waiters: []
  };
  pendingSessionWorkBySessionId.set(options.sessionId, pendingSessionWork);
  enqueueSessionId(options.sessionId, pendingSessionWork);
};

const appendChatDebugEvent = async event => {
  await invoke$1('ChatStorage.appendDebugEvent', event);
};

const getOutputText = outputText => {
  if (typeof outputText === 'string') {
    return outputText || undefined;
  }
  if (Array.isArray(outputText)) {
    const joinedOutputText = outputText.filter(part => typeof part === 'string').join('');
    return joinedOutputText || undefined;
  }
  return undefined;
};
const getOutputItemText = item => {
  const {
    content = []
  } = item;
  return content.filter(part => typeof part.text === 'string').map(part => part.text).join('');
};
const getToolCallArgs = serializedArguments => {
  try {
    return JSON.parse(serializedArguments);
  } catch {
    return serializedArguments;
  }
};
const isResponseToolCallItem = item => {
  return item.type === 'function_call' && typeof item.arguments === 'string' && typeof item.name === 'string' && (typeof item.call_id === 'string' || typeof item.id === 'string');
};
const getToolCall = item => {
  if (!isResponseToolCallItem(item)) {
    return undefined;
  }
  return {
    args: getToolCallArgs(item.arguments),
    id: item.call_id || item.id || '',
    name: item.name
  };
};
const extractAiResponse = data => {
  if (!data || typeof data !== 'object') {
    return {
      newToolCalls: [],
      text: undefined
    };
  }
  const response = data;
  const outputText = getOutputText(response.output_text);
  if (outputText) {
    return {
      newToolCalls: [],
      text: outputText
    };
  }
  if (!Array.isArray(response.output)) {
    return {
      newToolCalls: [],
      text: undefined
    };
  }
  const text = response.output.map(getOutputItemText).join('');
  const toolCalls = response.output.map(getToolCall).filter(toolCall => !!toolCall);
  return {
    newToolCalls: toolCalls,
    text: text || undefined
  };
};

const normalizeAssistantMessage = message => {
  if (message.role !== 'assistant') {
    return message;
  }
  if (typeof message.content === 'string') {
    return {
      content: [{
        text: message.content,
        type: 'output_text'
      }],
      role: 'assistant'
    };
  }
  return {
    content: message.content.map(part => {
      if ('text' in part && part.type === 'input_text') {
        return {
          text: part.text,
          type: 'output_text'
        };
      }
      return part;
    }),
    role: 'assistant'
  };
};
const normalizeMessage = message => {
  if ('role' in message && 'content' in message) {
    return normalizeAssistantMessage(message);
  }
  return message;
};
const isAiRequestInput = value => {
  return !!value && typeof value === 'object' && ('content' in value && 'role' in value || 'call_id' in value);
};
const serializeToolCallOutput = value => {
  if (typeof value === 'string') {
    return value;
  }
  if (typeof value === 'number' || typeof value === 'boolean' || value === null) {
    return JSON.stringify(value);
  }
  if (typeof value === 'bigint') {
    return value.toString();
  }
  if (value === undefined) {
    return 'null';
  }
  if (typeof value === 'symbol') {
    return value.description ? `Symbol(${value.description})` : 'Symbol()';
  }
  if (typeof value === 'function') {
    return '[function]';
  }
  const serialized = JSON.stringify(value);
  if (typeof serialized === 'string') {
    return serialized;
  }
  return '[unserializable]';
};
const getToolCallOutput = toolCallResult => {
  if (toolCallResult.type === 'success') {
    return serializeToolCallOutput(toolCallResult.value);
  }
  return serializeToolCallOutput({
    error: toolCallResult.error
  });
};
const getAiRequestBody = (systemPrompt, text, toolCallResults = []) => {
  const messages = typeof text === 'string' ? [{
    content: text,
    role: 'user'
  }] : text.map(message => isAiRequestInput(message) ? normalizeMessage(message) : {
    content: message,
    role: 'user'
  });
  const outputs = toolCallResults.map(toolCallResult => ({
    call_id: toolCallResult.callId,
    output: getToolCallOutput(toolCallResult),
    type: 'function_call_output'
  }));
  return {
    input: [{
      content: systemPrompt,
      role: 'system'
    }, ...messages, ...outputs]
  };
};

const getOpenAiTools = tools => {
  return tools.map(tool => ({
    description: tool.function.description,
    name: tool.function.name,
    parameters: tool.function.parameters,
    type: tool.type
  }));
};
const getAiRequestOptions = options => {
  const {
    headers,
    maxToolCalls,
    modelId,
    providerId,
    systemPrompt,
    text: inputText,
    toolCallResults,
    tools,
    url
  } = options;
  const openAiTools = getOpenAiTools(tools);
  return {
    body: {
      ...getAiRequestBody(systemPrompt, inputText, toolCallResults),
      max_tool_calls: maxToolCalls,
      model: modelId,
      tool_choice: 'auto',
      tools: openAiTools
    },
    headers,
    method: 'POST',
    providerId,
    url
  };
};

const backendCompletionFailedMessage = 'Backend completion request failed.';
const getBackendModelNotAllowedForFreePlanMessage = statusCode => {
  if (typeof statusCode === 'number') {
    return `Backend completion request failed (status ${statusCode}). The selected model is not available on the Free plan. Choose a lower-cost LVCE model such as Claude Haiku or GPT-5.4 Mini, or upgrade your plan and try again.`;
  }
  return 'Backend completion request failed. The selected model is not available on the Free plan. Choose a lower-cost LVCE model such as Claude Haiku or GPT-5.4 Mini, or upgrade your plan and try again.';
};
const getBackendHttpErrorDetails = (errorCode, errorMessage) => {
  const trimmedErrorCode = errorCode?.trim();
  const trimmedErrorMessage = errorMessage?.trim();
  if (trimmedErrorCode && trimmedErrorMessage) {
    return `Error code: ${trimmedErrorCode}. ${trimmedErrorMessage}`;
  }
  if (trimmedErrorCode) {
    return `Error code: ${trimmedErrorCode}.`;
  }
  return trimmedErrorMessage;
};
const getBackendErrorMessage = errorResult => {
  switch (errorResult.details) {
    case 'http-error':
      {
        if (errorResult.errorCode === 'E_LVCE_MODEL_NOT_ALLOWED_FOR_FREE_PLAN') {
          return getBackendModelNotAllowedForFreePlanMessage(errorResult.statusCode);
        }
        const details = getBackendHttpErrorDetails(errorResult.errorCode, errorResult.errorMessage);
        if (typeof errorResult.statusCode === 'number') {
          const prefix = `Backend completion request failed (status ${errorResult.statusCode}).`;
          if (!details) {
            return prefix;
          }
          return `${prefix} ${details}`;
        }
        if (details) {
          return `Backend completion request failed. ${details}`;
        }
        return backendCompletionFailedMessage;
      }
    case 'invalid-response':
      {
        const errorMessage = errorResult.errorMessage?.trim();
        if (errorMessage) {
          return `Backend completion request failed. ${errorMessage}`;
        }
        return 'Backend completion request failed. Unexpected backend response format.';
      }
    case 'request-failed':
      {
        const errorMessage = errorResult.errorMessage?.trim();
        if (errorMessage) {
          return `Backend completion request failed. ${errorMessage}`;
        }
        return backendCompletionFailedMessage;
      }
  }
};

const getError = error => {
  if (error instanceof Error) {
    return error;
  }
  return new Error(String(error));
};

const getRedactedHeaders = headers => {
  const redactedHeaders = {};
  for (const [headerName, headerValue] of Object.entries(headers)) {
    if (headerName.toLowerCase() === 'authorization') {
      redactedHeaders[headerName] = headerValue.toLowerCase().startsWith('bearer ') ? 'Bearer [redacted]' : '[redacted]';
    } else {
      redactedHeaders[headerName] = headerValue;
    }
  }
  return redactedHeaders;
};

const getStatusCodeMessage = statusCode => {
  switch (statusCode) {
    case 401:
      return 'The AI request was rejected. Check the API key and try again.';
    case 403:
      return 'The AI request was rejected. Check your permissions and try again.';
    case 408:
      return 'The AI request timed out. Please try again.';
    case 429:
      return 'The AI request was rate limited. Please try again.';
    default:
      if (statusCode >= 500) {
        return 'The AI provider is temporarily unavailable. Please try again.';
      }
      return 'The AI request failed. Please try again.';
  }
};
const getBackendErrorCodeFromBody = body => {
  if (!body || typeof body !== 'object') {
    return undefined;
  }
  const code = Reflect.get(body, 'code');
  return typeof code === 'string' ? code : undefined;
};
const getBackendErrorMessageFromBody = body => {
  if (!body || typeof body !== 'object') {
    return undefined;
  }
  const error = Reflect.get(body, 'error');
  return typeof error === 'string' ? error : undefined;
};
const getVisibleAiErrorMessage = (_error, statusCode, providerId = 'openai') => {
  if (providerId === 'backend') {
    const errorCode = getBackendErrorCodeFromBody(_error);
    const errorMessage = _error instanceof Error ? _error.message : typeof _error === 'object' && _error ? getBackendErrorMessageFromBody(_error) : undefined;
    if (typeof statusCode === 'number') {
      return getBackendErrorMessage({
        details: 'http-error',
        ...(errorCode ? {
          errorCode
        } : {}),
        ...(errorMessage ? {
          errorMessage
        } : {}),
        statusCode
      });
    }
    return getBackendErrorMessage({
      details: 'request-failed',
      ...(errorMessage ? {
        errorMessage
      } : {})
    });
  }
  if (typeof statusCode === 'number') {
    return getStatusCodeMessage(statusCode);
  }
  return 'The AI request failed. Please try again.';
};

const getInitData = options => {
  const {
    body,
    headers,
    method
  } = options;
  const requestInit = {
    method
  };
  if (body !== undefined) {
    requestInit.body = JSON.stringify(body);
  }
  if (headers !== undefined) {
    requestInit.headers = headers;
  }
  return requestInit;
};

// cspell:ignore logprobs

const lastRequestSummaryToken = '__MOCK_OPENAPI_LAST_REQUEST_SUMMARY__';
const mockCreatedAtBase = 1_778_610_258;
const getHashRound = value => {
  let hash = 2_166_136_261;
  for (const character of value) {
    hash ^= character.codePointAt(0) ?? 0;
    hash = Math.imul(hash, 16_777_619);
  }
  return (hash >>> 0).toString(16).padStart(8, '0');
};
const getDeterministicHex = (seed, length) => {
  let result = '';
  let index = 0;
  while (result.length < length) {
    result += getHashRound(`${seed}:${index}`);
    index++;
  }
  return result.slice(0, length);
};
const getInputTexts = body => {
  if (!body || typeof body !== 'object') {
    return [];
  }
  const input = Reflect.get(body, 'input');
  if (!Array.isArray(input)) {
    return [];
  }
  const parts = [];
  for (const item of input) {
    if (typeof item === 'string') {
      parts.push(item);
      continue;
    }
    if (!item || typeof item !== 'object') {
      continue;
    }
    const content = Reflect.get(item, 'content');
    if (typeof content === 'string') {
      parts.push(content);
      continue;
    }
    if (!Array.isArray(content)) {
      continue;
    }
    for (const contentPart of content) {
      if (typeof contentPart === 'string') {
        parts.push(contentPart);
        continue;
      }
      if (!contentPart || typeof contentPart !== 'object') {
        continue;
      }
      const text = Reflect.get(contentPart, 'text');
      if (typeof text !== 'string' || !text) {
        continue;
      }
      const type = Reflect.get(contentPart, 'type');
      if (type === undefined || type === 'input_text' || type === 'output_text') {
        parts.push(text);
      }
    }
  }
  return parts;
};
const estimateTokens = text => {
  const trimmedText = text.trim();
  if (!trimmedText) {
    return 0;
  }
  return Math.max(1, Math.ceil(trimmedText.length / 5));
};
const getUsage = (body, outputText) => {
  const inputText = getInputTexts(body).join('\n');
  const inputTokens = estimateTokens(inputText);
  const outputTokens = estimateTokens(outputText);
  return {
    input_tokens: inputTokens,
    input_tokens_details: {
      cached_tokens: 0
    },
    output_tokens: outputTokens,
    output_tokens_details: {
      reasoning_tokens: 0
    },
    total_tokens: inputTokens + outputTokens
  };
};
const getResponseSeed = (body, text) => {
  const serializedBody = body === undefined ? 'undefined' : JSON.stringify(body);
  return `${serializedBody}:${text}`;
};
const getResponseId = seed => {
  const responseSeed = `response:${seed}`;
  return `resp_${getDeterministicHex(responseSeed, 32)}`;
};
const getMessageId = seed => {
  const messageSeed = `message:${seed}`;
  return `msg_${getDeterministicHex(messageSeed, 32)}`;
};
const getCreatedAt = seed => {
  const suffix = Number.parseInt(getDeterministicHex(`created:${seed}`, 6), 16);
  return mockCreatedAtBase + suffix % 1000;
};
const getFunctionCallId = (seed, index) => {
  return `fc_${getDeterministicHex(`function-call:${seed}:${index}`, 24)}`;
};
const getCallId = (seed, index) => {
  return `call_${getDeterministicHex(`call:${seed}:${index}`, 24)}`;
};
const getLastRequestSummary = body => {
  if (!body || typeof body !== 'object') {
    return 'mock-request-summary images=0 text-files=0';
  }
  const input = Reflect.get(body, 'input');
  if (!Array.isArray(input) || input.length === 0) {
    return 'mock-request-summary images=0 text-files=0';
  }
  let imageCount = 0;
  let textFileCount = 0;
  for (const item of input) {
    if (!item || typeof item !== 'object') {
      continue;
    }
    const content = Reflect.get(item, 'content');
    if (!Array.isArray(content)) {
      continue;
    }
    for (const part of content) {
      if (!part || typeof part !== 'object') {
        continue;
      }
      const type = Reflect.get(part, 'type');
      if (type === 'input_image') {
        imageCount++;
        continue;
      }
      if (type !== 'input_text') {
        continue;
      }
      const text = Reflect.get(part, 'text');
      if (typeof text === 'string' && text.startsWith('Attached text file "')) {
        textFileCount++;
      }
    }
  }
  return `mock-request-summary images=${imageCount} text-files=${textFileCount}`;
};
const getModel = body => {
  if (!body || typeof body !== 'object') {
    return 'mock-model';
  }
  const model = Reflect.get(body, 'model');
  if (typeof model !== 'string') {
    return 'mock-model';
  }
  return model;
};
const getToolCallArguments = value => {
  if (typeof value === 'string') {
    return value;
  }
  return JSON.stringify(value ?? {});
};
const parseToolCallDescriptor = value => {
  if (!value || typeof value !== 'object') {
    return undefined;
  }
  const name = Reflect.get(value, 'name');
  if (typeof name !== 'string' || !name) {
    return undefined;
  }
  const argumentsValue = Reflect.get(value, 'arguments');
  const id = Reflect.get(value, 'id');
  const callId = Reflect.get(value, 'call_id');
  return {
    arguments: argumentsValue ?? {},
    ...(typeof callId === 'string' && callId ? {
      callId
    } : {}),
    ...(typeof id === 'string' && id ? {
      id
    } : {}),
    name
  };
};
const parseMockResponseDescriptor = text => {
  let parsed;
  try {
    parsed = JSON.parse(text);
  } catch {
    return undefined;
  }
  if (!parsed || typeof parsed !== 'object') {
    return undefined;
  }
  const parsedText = Reflect.get(parsed, 'text');
  const rawToolCall = Reflect.get(parsed, 'toolCall');
  const rawToolCalls = Reflect.get(parsed, 'toolCalls');
  const toolCalls = [];
  const toolCall = parseToolCallDescriptor(rawToolCall);
  if (toolCall) {
    toolCalls.push(toolCall);
  }
  if (Array.isArray(rawToolCalls)) {
    for (const rawToolCall of rawToolCalls) {
      const parsedToolCall = parseToolCallDescriptor(rawToolCall);
      if (parsedToolCall) {
        toolCalls.push(parsedToolCall);
      }
    }
  }
  if (typeof parsedText !== 'string' && toolCalls.length === 0) {
    return undefined;
  }
  return {
    ...(typeof parsedText === 'string' ? {
      text: parsedText
    } : {}),
    ...(toolCalls.length > 0 ? {
      toolCalls
    } : {})
  };
};
const getResponseOutputItems = (seed, outputText, descriptor) => {
  const outputItems = [];
  if (descriptor?.toolCalls) {
    for (let index = 0; index < descriptor.toolCalls.length; index += 1) {
      const toolCall = descriptor.toolCalls[index];
      outputItems.push({
        arguments: getToolCallArguments(toolCall.arguments),
        call_id: toolCall.callId || getCallId(seed, index),
        id: toolCall.id || getFunctionCallId(seed, index),
        name: toolCall.name,
        status: 'completed',
        type: 'function_call'
      });
    }
  }
  if (descriptor?.text !== undefined || outputItems.length === 0) {
    outputItems.push({
      content: [{
        annotations: [],
        logprobs: [],
        text: outputText,
        type: 'output_text'
      }],
      id: getMessageId(seed),
      role: 'assistant',
      status: 'completed',
      type: 'message'
    });
  }
  return outputItems;
};
const parseSseDataLines = text => {
  const rawEvents = text.split('\n\n');
  const dataLines = [];
  for (const rawEvent of rawEvents) {
    if (!rawEvent) {
      continue;
    }
    const lines = rawEvent.split('\n');
    for (const line of lines) {
      if (!line.startsWith('data:')) {
        continue;
      }
      dataLines.push(line.slice(5).trimStart());
    }
  }
  return dataLines;
};
const isSseMockResponse = text => {
  return text.includes('\ndata:') || text.startsWith('data:');
};
const parseSseMockResponse = (body, text) => {
  const dataLines = parseSseDataLines(text);
  if (dataLines.length === 0) {
    return undefined;
  }
  let accumulatedText = '';
  let completedResponse;
  for (const line of dataLines) {
    if (line === '[DONE]') {
      continue;
    }
    let parsed;
    try {
      parsed = JSON.parse(line);
    } catch {
      continue;
    }
    if (!parsed || typeof parsed !== 'object') {
      continue;
    }
    const eventType = Reflect.get(parsed, 'type');
    if (eventType === 'response.output_text.delta') {
      const delta = Reflect.get(parsed, 'delta');
      if (typeof delta === 'string') {
        accumulatedText += delta;
      }
      continue;
    }
    if (eventType === 'response.completed') {
      const response = Reflect.get(parsed, 'response');
      if (response && typeof response === 'object') {
        completedResponse = response;
      }
    }
  }
  if (completedResponse) {
    return completedResponse;
  }
  if (accumulatedText) {
    return createMockOpenAiResponse(body, accumulatedText);
  }
  return undefined;
};
const createMockOpenAiResponse = (body, text) => {
  if (isSseMockResponse(text)) {
    const parsedSseResponse = parseSseMockResponse(body, text);
    if (parsedSseResponse) {
      return parsedSseResponse;
    }
  }
  const descriptor = parseMockResponseDescriptor(text);
  const model = getModel(body);
  const resolvedText = text === lastRequestSummaryToken ? getLastRequestSummary(body) : descriptor?.text || text;
  const seed = getResponseSeed(body, descriptor ? JSON.stringify(descriptor) : resolvedText);
  const createdAt = getCreatedAt(seed);
  return {
    background: false,
    billing: {
      payer: 'openai'
    },
    completed_at: createdAt + 2,
    created_at: createdAt,
    error: null,
    frequency_penalty: 0,
    id: getResponseId(seed),
    incomplete_details: null,
    instructions: null,
    max_output_tokens: null,
    max_tool_calls: null,
    metadata: {},
    model,
    moderation: null,
    object: 'response',
    output: getResponseOutputItems(seed, resolvedText, descriptor),
    parallel_tool_calls: true,
    presence_penalty: 0,
    previous_response_id: null,
    prompt_cache_key: null,
    prompt_cache_retention: 'in_memory',
    reasoning: {
      effort: null,
      summary: null
    },
    safety_identifier: null,
    service_tier: 'default',
    status: 'completed',
    store: true,
    temperature: 1,
    text: {
      format: {
        type: 'text'
      },
      verbosity: 'medium'
    },
    tool_choice: 'auto',
    tools: [],
    top_logprobs: 0,
    top_p: 1,
    truncation: 'disabled',
    usage: getUsage(body, resolvedText),
    user: null
  };
};

let errorResponse;
let successResponse;
const setHttpErrorResponse = (statusCode, body) => {
  errorResponse = {
    body,
    statusCode,
    type: 'http-error'
  };
};
const setResponse = body => {
  successResponse = {
    body,
    type: 'success'
  };
};
const takeErrorResponse = () => {
  const response = errorResponse;
  errorResponse = undefined;
  return response;
};
const takeResponse = () => {
  const response = successResponse;
  successResponse = undefined;
  return response;
};

const defaultRequestId = 'default';
let streamStates = new Map();
let preparedRequestIds = [];
const createState = () => {
  return {
    errorResult: undefined,
    finished: false,
    queue: [],
    waiters: []
  };
};
const getOrCreateState = requestId => {
  const existing = streamStates.get(requestId);
  if (existing) {
    return existing;
  }
  const state = createState();
  streamStates.set(requestId, state);
  return state;
};
const enqueuePreparedRequest = requestId => {
  if (preparedRequestIds.includes(requestId)) {
    return;
  }
  preparedRequestIds.push(requestId);
};
const getNextPreparedRequestId = () => {
  return preparedRequestIds.shift() || defaultRequestId;
};
const reset = (requestId = defaultRequestId) => {
  if (requestId === defaultRequestId) {
    streamStates = new Map();
    preparedRequestIds = [];
    streamStates.set(defaultRequestId, createState());
    return;
  }
  streamStates.set(requestId, createState());
  enqueuePreparedRequest(requestId);
};
const pushChunk = (chunk, requestId = defaultRequestId) => {
  const state = getOrCreateState(requestId);
  if (state.waiters.length > 0) {
    const resolve = state.waiters.shift();
    resolve?.(chunk);
    return;
  }
  state.queue.push(chunk);
};
const finish = (requestId = defaultRequestId) => {
  const state = getOrCreateState(requestId);
  state.finished = true;
  if (state.waiters.length === 0) {
    return;
  }
  const activeWaiters = [...state.waiters];
  state.waiters.length = 0;
  for (const resolve of activeWaiters) {
    resolve(undefined);
  }
};
const readNextChunk = async (requestId = defaultRequestId) => {
  const state = getOrCreateState(requestId);
  if (state.queue.length > 0) {
    return state.queue.shift();
  }
  if (state.finished) {
    return undefined;
  }
  const {
    promise,
    resolve
  } = Promise.withResolvers();
  state.waiters.push(resolve);
  return promise;
};
const consumeResponseText = async () => {
  const requestId = getNextPreparedRequestId();
  const state = getOrCreateState(requestId);
  if (state.queue.length === 0 && !state.finished) {
    return undefined;
  }
  const chunks = [];
  while (true) {
    const chunk = await readNextChunk(requestId);
    if (chunk === undefined) {
      break;
    }
    chunks.push(chunk);
  }
  streamStates.delete(requestId);
  return chunks.join('');
};

const parseContentLength = headers => {
  const contentLength = headers.get('content-length');
  if (!contentLength) {
    return -1;
  }
  const parsed = Number.parseInt(contentLength, 10);
  if (!Number.isFinite(parsed) || parsed < 0) {
    return -1;
  }
  return parsed;
};
const getResponseSize = async response => {
  const parsedContentLength = parseContentLength(response.headers);
  if (parsedContentLength !== -1) {
    return parsedContentLength;
  }
  try {
    const blob = await response.clone().blob();
    return blob.size;
  } catch {
    return 0;
  }
};
const createParsedResponse = (ok, status, body) => {
  return {
    headers: new Headers(),
    json: async () => body,
    ok,
    size: 0,
    status
  };
};
const getNetworkResponse = async (options, requestInit) => {
  const {
    body,
    providerId,
    url
  } = options;
  if (providerId === 'backend') {
    const mockErrorResponse = takeErrorResponse();
    if (mockErrorResponse) {
      return createParsedResponse(false, mockErrorResponse.statusCode, mockErrorResponse.body);
    }
    const mockResponse = takeResponse();
    if (mockResponse) {
      return createParsedResponse(true, 200, mockResponse.body);
    }
  }
  const mockResponseText = await consumeResponseText();
  if (mockResponseText !== undefined) {
    const data = createMockOpenAiResponse(body, mockResponseText);
    return createParsedResponse(true, 200, data);
  }
  const response = await fetch(url, requestInit);
  const size = await getResponseSize(response);
  return {
    headers: response.headers,
    json: response.json.bind(response),
    ok: response.ok,
    size,
    status: response.status
  };
};

const serializeHeaders = headers => {
  return Object.fromEntries(headers.entries());
};

const parseNetworkResponse = async response => {
  const json = await response.json();
  if (!response.ok) {
    return {
      error: json,
      headers: serializeHeaders(response.headers),
      size: response.size,
      statusCode: response.status,
      type: 'error'
    };
  }
  return {
    data: json,
    headers: serializeHeaders(response.headers),
    size: response.size,
    statusCode: response.status,
    type: 'success'
  };
};

const makeNetworkRequest = async options => {
  const requestInit = getInitData(options);
  const response = await getNetworkResponse(options, requestInit);
  return parseNetworkResponse(response);
};

const backendResponsesPath = '/v1/responses';
const getBackendUrl = url => {
  if (url.endsWith(backendResponsesPath)) {
    return url.slice(0, -backendResponsesPath.length);
  }
  return url;
};
const resolveAiRequestHeaders = async options => {
  const {
    headers,
    providerId,
    url
  } = options;
  if (providerId !== 'backend') {
    return headers;
  }
  const backendUrl = getBackendUrl(url);
  const authState = await invoke$2('Auth.syncBackendAuth', backendUrl);
  if (!authState.authAccessToken) {
    return headers;
  }
  return {
    ...headers,
    Authorization: `Bearer ${authState.authAccessToken}`
  };
};

const makeAiRequest = async options => {
  const {
    headers,
    maxToolCalls,
    modelId,
    providerId,
    systemPrompt,
    text: inputText,
    toolCallResults,
    tools,
    url
  } = options;
  const resolvedHeaders = await resolveAiRequestHeaders({
    headers,
    providerId,
    url
  });
  const requestOptions = getAiRequestOptions({
    headers: resolvedHeaders,
    maxToolCalls,
    modelId,
    providerId,
    systemPrompt,
    text: inputText,
    toolCallResults,
    tools,
    url
  });
  const response = await makeNetworkRequest(requestOptions);
  if (response.type === 'error') {
    return {
      error: response.error,
      size: response.size,
      statusCode: response.statusCode,
      type: 'error'
    };
  }
  return {
    data: response.data,
    headers: response.headers,
    size: response.size,
    statusCode: response.statusCode,
    type: 'success'
  };
};

const serializeToolCallArguments = value => {
  if (typeof value === 'string') {
    return value;
  }
  const serialized = JSON.stringify(value);
  return typeof serialized === 'string' ? serialized : 'null';
};
const appendVisibleAiErrorMessage = async options => {
  const {
    error,
    providerId,
    requestId,
    sessionId,
    statusCode,
    timestamp
  } = options;
  const text = getVisibleAiErrorMessage(error, statusCode, providerId);
  await appendChatEvent({
    id: requestId,
    message: {
      content: [{
        text,
        type: 'text'
      }],
      role: 'assistant'
    },
    requestId,
    sessionId,
    timestamp,
    type: Message
  });
};
const getBackendInvalidResponseDetails = data => {
  if (!data || typeof data !== 'object') {
    return 'Unexpected backend response format: no assistant text or tool calls were returned.';
  }
  const output = Reflect.get(data, 'output');
  if (Array.isArray(output) && output.length === 0) {
    return 'Unexpected backend response format: no assistant text or tool calls were returned.';
  }
  return 'Unexpected backend response format.';
};
const appendAiErrorResponse = async options => {
  const {
    error,
    requestId,
    sessionId,
    size = 0,
    statusCode,
    timestamp,
    turnId
  } = options;
  await appendChatDebugEvent({
    ...(typeof statusCode === 'number' ? {
      statusCode
    } : {}),
    requestId,
    sessionId,
    size,
    timestamp,
    turnId,
    type: AiResponse,
    value: error
  });
};
const aiLoopIterationAiRequest = async options => {
  const {
    headers,
    maxToolCalls,
    messages,
    modelId,
    providerId,
    requestId,
    sessionId,
    systemPrompt,
    timestamp,
    toolCallResults,
    toolCalls,
    tools,
    turnId,
    url
  } = options;
  const resolvedHeaders = await resolveAiRequestHeaders({
    headers,
    providerId,
    url
  });
  const requestOptions = getAiRequestOptions({
    headers: resolvedHeaders,
    maxToolCalls,
    modelId,
    providerId,
    systemPrompt,
    text: messages,
    toolCallResults,
    tools,
    url
  });
  await appendChatDebugEvent({
    body: requestOptions.body,
    headers: getRedactedHeaders(resolvedHeaders),
    method: 'POST',
    requestId,
    sessionId,
    timestamp,
    turnId,
    type: AiRequest,
    url
  });
  let result;
  try {
    result = await makeAiRequest({
      headers: resolvedHeaders,
      maxToolCalls,
      modelId,
      providerId,
      systemPrompt,
      text: messages,
      toolCallResults,
      toolCalls,
      tools,
      url
    });
  } catch (error) {
    const endTimestamp = new Date().toISOString();
    const normalizedError = getError(error);
    await appendVisibleAiErrorMessage({
      error: normalizedError,
      providerId,
      requestId,
      sessionId,
      timestamp: endTimestamp
    });
    await appendAiErrorResponse({
      error: normalizedError,
      requestId,
      sessionId,
      timestamp: endTimestamp,
      turnId
    });
    return {
      error: normalizedError,
      type: 'error'
    };
  }
  const endTimestamp = new Date().toISOString();
  if (result.type === 'error') {
    // TODO do this in parallel
    await appendVisibleAiErrorMessage({
      error: result.error,
      providerId,
      requestId,
      sessionId,
      statusCode: result.statusCode,
      timestamp: endTimestamp
    });
    await appendAiErrorResponse({
      error: result.error,
      requestId,
      sessionId,
      statusCode: result.statusCode,
      timestamp: endTimestamp,
      turnId
    });
    return {
      error: result.error,
      type: 'error'
    };
  }
  const {
    newToolCalls,
    text
  } = extractAiResponse(result.data);
  if (!text && newToolCalls.length === 0 && providerId === 'backend') {
    const error = new Error(getBackendErrorMessage({
      details: 'invalid-response',
      errorMessage: getBackendInvalidResponseDetails(result.data)
    }));
    await appendChatEvent({
      id: requestId,
      message: {
        content: [{
          text: error.message,
          type: 'text'
        }],
        role: 'assistant'
      },
      requestId,
      sessionId,
      timestamp: endTimestamp,
      type: Message
    });
    await appendChatDebugEvent({
      headers: result.headers,
      requestId,
      sessionId,
      size: result.size,
      statusCode: result.statusCode,
      timestamp: endTimestamp,
      toolCalls: newToolCalls,
      turnId,
      type: AiResponse,
      value: result.data
    });
    return {
      error,
      type: 'error'
    };
  }
  if (text || newToolCalls.length > 0) {
    await appendChatEvent({
      id: requestId,
      message: {
        content: [...(text ? [{
          text,
          type: 'text'
        }] : []), ...newToolCalls.map(toolCall => ({
          arguments: serializeToolCallArguments(toolCall.args),
          call_id: toolCall.id,
          name: toolCall.name,
          type: 'function_call'
        }))],
        role: 'assistant'
      },
      requestId,
      sessionId,
      timestamp: endTimestamp,
      type: Message
    });
  }
  await appendChatDebugEvent({
    headers: result.headers,
    requestId,
    sessionId,
    size: result.size,
    statusCode: result.statusCode,
    timestamp: endTimestamp,
    toolCalls: newToolCalls,
    turnId,
    type: AiResponse,
    value: result.data
  });
  return {
    data: result.data,
    toolCallResults: [],
    toolCalls: newToolCalls,
    type: 'success'
  };
};

const getTimeStamp = () => {
  return new Date().toISOString();
};

const isRecord = value => {
  return !!value && typeof value === 'object';
};
const getErrorMessage = error => {
  if (error instanceof Error) {
    return error.message;
  }
  return String(error);
};
const defaultToolOptions = {
  assetDir: '',
  platform: Web
};
const serializeToolArguments = args => {
  const serialized = JSON.stringify(args);
  if (typeof serialized === 'string') {
    return serialized;
  }
  return '{}';
};
const getToolResponseError = value => {
  if (!isRecord(value)) {
    return undefined;
  }
  if (typeof value.error === 'string' && value.error) {
    return value.error;
  }
  if (typeof value.errorMessage === 'string' && value.errorMessage) {
    return value.errorMessage;
  }
  return undefined;
};
const executeToolCall = async toolCall => {
  const rawArguments = serializeToolArguments(toolCall.args);
  return execute(toolCall.name, rawArguments, defaultToolOptions);
};
const getToolCallResults = async (toolCalls, options = {}) => {
  const {
    onToolCallFinished,
    onToolCallStarted
  } = options;
  return Promise.all(toolCalls.map(async toolCall => {
    await onToolCallStarted?.(toolCall);
    let result;
    try {
      const value = await executeToolCall(toolCall);
      const error = getToolResponseError(value);
      if (error) {
        result = {
          callId: toolCall.id,
          error,
          type: 'error'
        };
      } else {
        result = {
          callId: toolCall.id,
          type: 'success',
          value
        };
      }
    } catch (error) {
      result = {
        callId: toolCall.id,
        error: getErrorMessage(error),
        type: 'error'
      };
    }
    await onToolCallFinished?.(toolCall, result);
    return result;
  }));
};

const serializeToolCallValue = value => {
  if (typeof value === 'string') {
    return value;
  }
  const serialized = JSON.stringify(value);
  return typeof serialized === 'string' ? serialized : 'null';
};
const isToolCallNotFoundError = error => {
  if (typeof error !== 'string') {
    return false;
  }
  return error.startsWith('Error: File not found') || error.startsWith('File not found');
};
const getToolCallStatusCode = toolCallResult => {
  if (toolCallResult.type === 'success') {
    return 200;
  }
  if (isToolCallNotFoundError(toolCallResult.error)) {
    return 404;
  }
  return 500;
};
const getStoredToolCallStatus = toolCallResult => {
  if (toolCallResult.type === 'success') {
    return 'success';
  }
  if (isToolCallNotFoundError(toolCallResult.error)) {
    return 'not-found';
  }
  return 'error';
};
const hasPendingToolCall = event => {
  return !!event.message?.toolCalls?.some(toolCall => toolCall.status === undefined);
};
const getStoredMessageEvent = async (sessionId, requestId) => {
  const events = await invoke$1('ChatStorage.getMessages', sessionId);
  const storedEvents = events;
  const matchingEvent = storedEvents.find(event => event.type === 'chat-message-added' && event.message?.id === requestId);
  if (matchingEvent) {
    return matchingEvent;
  }
  return storedEvents.toReversed().find(event => event.type === 'chat-message-added' && hasPendingToolCall(event));
};
const getUpdatedToolCalls = (storedToolCalls, toolCallResults) => {
  const toolCallResultsById = new Map(toolCallResults.map(toolCallResult => [toolCallResult.callId, toolCallResult]));
  return storedToolCalls.map(storedToolCall => {
    if (!storedToolCall.id) {
      return storedToolCall;
    }
    const toolCallResult = toolCallResultsById.get(storedToolCall.id);
    if (!toolCallResult) {
      return storedToolCall;
    }
    if (toolCallResult.type === 'success') {
      return {
        ...storedToolCall,
        result: serializeToolCallValue(toolCallResult.value),
        status: 'success',
        statusCode: getToolCallStatusCode(toolCallResult)
      };
    }
    return {
      ...storedToolCall,
      errorMessage: serializeToolCallValue({
        error: toolCallResult.error
      }),
      status: getStoredToolCallStatus(toolCallResult),
      statusCode: getToolCallStatusCode(toolCallResult)
    };
  });
};
const appendStoredToolCallResults = async (requestId, sessionId, timestamp, toolCallResults) => {
  const storedMessageEvent = await getStoredMessageEvent(sessionId, requestId);
  const storedToolCalls = storedMessageEvent?.message?.toolCalls || [];
  if (storedToolCalls.length === 0) {
    return;
  }
  await invoke$1('ChatStorage.appendEvent', {
    inProgress: false,
    messageId: storedMessageEvent?.message?.id || requestId,
    sessionId,
    text: storedMessageEvent?.message?.text || '',
    time: storedMessageEvent?.message?.time || timestamp,
    timestamp,
    toolCalls: getUpdatedToolCalls(storedToolCalls, toolCallResults),
    type: 'chat-message-updated'
  });
};
const aiLoopIterationToolCall = async options => {
  const {
    requestId,
    sessionId,
    timestamp,
    toolCalls,
    turnId
  } = options;
  const resolvedToolCallResults = await getToolCallResults(toolCalls, {
    onToolCallFinished: async (toolCall, toolCallResult) => {
      await appendChatDebugEvent({
        callId: toolCall.id,
        name: toolCall.name,
        requestId,
        sessionId,
        statusCode: getToolCallStatusCode(toolCallResult),
        timestamp: getTimeStamp(),
        toolCallResult,
        turnId,
        type: ToolCallFinished
      });
    },
    onToolCallStarted: async toolCall => {
      await appendChatDebugEvent({
        args: toolCall.args,
        callId: toolCall.id,
        name: toolCall.name,
        requestId,
        sessionId,
        timestamp: getTimeStamp(),
        turnId,
        type: ToolCallStarted
      });
    }
  });
  await appendStoredToolCallResults(requestId, sessionId, timestamp, resolvedToolCallResults);
  return {
    data: undefined,
    toolCallResults: resolvedToolCallResults,
    toolCalls: [],
    type: 'success'
  };
};

const getRequestId = () => {
  return crypto.randomUUID();
};

const serializeStoredValue = value => {
  if (typeof value === 'string') {
    return value;
  }
  const serialized = JSON.stringify(value);
  return typeof serialized === 'string' ? serialized : 'null';
};
const getStoredMessageText = message => {
  const contentText = (message.content || []).filter(part => (part.type === 'text' || part.type === 'input_text') && typeof part.text === 'string' && part.text.length > 0).map(part => part.text).join('');
  if (contentText) {
    return contentText;
  }
  if (typeof message.text === 'string') {
    return message.text;
  }
  return '';
};
const getStoredMessageParts = message => {
  const text = getStoredMessageText(message);
  if (!text) {
    return [];
  }
  return [{
    text,
    type: 'input_text'
  }];
};
const getStoredFunctionCalls = message => {
  if (message.toolCalls && message.toolCalls.length > 0) {
    return message.toolCalls.filter(toolCall => typeof toolCall.id === 'string').map(toolCall => ({
      arguments: toolCall.arguments,
      call_id: toolCall.id,
      name: toolCall.name,
      type: 'function_call'
    }));
  }
  return (message.content || []).filter(part => part.type === 'function_call' && typeof part.arguments === 'string' && typeof part.call_id === 'string' && typeof part.name === 'string').map(part => ({
    arguments: part.arguments,
    call_id: part.call_id,
    name: part.name,
    type: 'function_call'
  }));
};
const getStoredFunctionCallOutputs = message => {
  return (message.toolCalls || []).filter(toolCall => typeof toolCall.id === 'string' && typeof toolCall.status === 'string').map(toolCall => ({
    call_id: toolCall.id,
    output: toolCall.status === 'success' ? toolCall.result || 'null' : toolCall.errorMessage || JSON.stringify({
      error: 'Tool call failed.'
    }),
    type: 'function_call_output'
  }));
};
const parseToolCallArguments = argumentsText => {
  try {
    return JSON.parse(argumentsText);
  } catch {
    return argumentsText;
  }
};
const getPendingToolCalls = message => {
  return (message.toolCalls || []).filter(toolCall => typeof toolCall.id === 'string' && toolCall.status === undefined).map(toolCall => ({
    args: parseToolCallArguments(toolCall.arguments),
    id: toolCall.id,
    name: toolCall.name
  }));
};
const getToolCallInputs = toolCalls => {
  return toolCalls.map(toolCall => ({
    arguments: serializeStoredValue(toolCall.args),
    call_id: toolCall.id,
    name: toolCall.name,
    type: 'function_call'
  }));
};
const getToolCallOutputInputs = toolCallResults => {
  return toolCallResults.map(toolCallResult => ({
    call_id: toolCallResult.callId,
    output: serializeStoredValue(toolCallResult.type === 'success' ? toolCallResult.value : {
      error: toolCallResult.error
    }),
    type: 'function_call_output'
  }));
};
const isKnownStoredEventType = type => {
  return type === Message || type === 'chat-message-added' || type === 'handle-submit' || type === AiResponse || type === ToolCallsFinished;
};
const getNormalizedStoredEvent = event => {
  if (!event || typeof event !== 'object') {
    return undefined;
  }
  const type = Reflect.get(event, 'type');
  if (isKnownStoredEventType(type)) {
    return event;
  }
  const nestedMessage = Reflect.get(event, 'message');
  if (!nestedMessage || typeof nestedMessage !== 'object' || nestedMessage === event) {
    return undefined;
  }
  return getNormalizedStoredEvent(nestedMessage);
};
const isStoredMessageEvent = event => {
  return event.type === Message || event.type === 'chat-message-added' || event.type === 'handle-submit';
};
const getStoredMessage = event => {
  if ('value' in event && typeof event.value === 'string') {
    return [{
      content: [{
        text: event.value,
        type: 'input_text'
      }],
      role: 'user'
    }];
  }
  if (!('message' in event)) {
    return [];
  }
  const {
    attachments = [],
    role
  } = event.message;
  if (role !== 'assistant' && role !== 'user') {
    return [];
  }
  const textParts = getStoredMessageParts(event.message);
  const functionCalls = role === 'assistant' ? getStoredFunctionCalls(event.message) : [];
  const functionCallOutputs = role === 'assistant' ? getStoredFunctionCallOutputs(event.message) : [];
  const inputs = [];
  if (attachments.length === 0) {
    if (textParts.length > 0) {
      inputs.push({
        content: textParts,
        role
      });
    }
  } else {
    const parts = [...textParts, ...getAttachmentParts(attachments)];
    if (parts.length > 0) {
      inputs.push({
        content: parts,
        role
      });
    }
  }
  inputs.push(...functionCalls);
  inputs.push(...functionCallOutputs);
  return inputs;
};
const isAiResponseSuccessEvent = event => {
  return event.type === AiResponse;
};
const isToolCallsFinishedEvent = event => {
  return event.type === ToolCallsFinished;
};
const isFunctionCallInput = input => {
  return 'type' in input && input.type === 'function_call';
};
const getStoredAiLoopState = async (sessionId, fallbackText, fallbackToolCalls, fallbackToolCallResults) => {
  const events = await invoke$1('ChatStorage.getMessages', sessionId);
  const messages = [];
  const seenFunctionCallIds = new Set();
  let toolCalls = fallbackToolCalls;
  let toolCallResults = fallbackToolCallResults;
  for (const storedEvent of events) {
    const event = getNormalizedStoredEvent(storedEvent);
    if (!event) {
      continue;
    }
    if (isStoredMessageEvent(event)) {
      const storedMessages = getStoredMessage(event);
      messages.push(...storedMessages);
      if ('message' in event && event.message && typeof event.message === 'object') {
        const pendingToolCalls = getPendingToolCalls(event.message);
        if (pendingToolCalls.length > 0) {
          toolCalls = pendingToolCalls;
          toolCallResults = [];
        } else if (event.message.toolCalls && event.message.toolCalls.length > 0) {
          toolCalls = [];
          toolCallResults = [];
        }
      }
      for (const storedMessage of storedMessages) {
        if (isFunctionCallInput(storedMessage)) {
          seenFunctionCallIds.add(storedMessage.call_id);
        }
      }
      continue;
    }
    if (isAiResponseSuccessEvent(event)) {
      toolCalls = event.toolCalls || [];
      const storedToolCallInputs = getToolCallInputs(toolCalls).filter(toolCall => !seenFunctionCallIds.has(toolCall.call_id));
      messages.push(...storedToolCallInputs);
      for (const storedToolCallInput of storedToolCallInputs) {
        seenFunctionCallIds.add(storedToolCallInput.call_id);
      }
      toolCallResults = [];
      continue;
    }
    if (isToolCallsFinishedEvent(event)) {
      const {
        toolCallResults: eventToolCallResults
      } = event;
      messages.push(...getToolCallOutputInputs(eventToolCallResults));
      toolCalls = [];
      toolCallResults = [];
    }
  }
  if (typeof fallbackText === 'string') {
    if (messages.length === 0) {
      messages.push({
        content: [{
          text: fallbackText,
          type: 'input_text'
        }],
        role: 'user'
      });
    }
  } else {
    return {
      messages: appendMissingAiRequestInputTail(messages, fallbackText),
      toolCallResults,
      toolCalls
    };
  }
  return {
    messages,
    toolCallResults,
    toolCalls
  };
};

const aiLoopIteration = async loopOptions => {
  const {
    headers,
    maxToolCalls,
    modelId,
    providerId,
    sessionId,
    systemPrompt,
    text,
    toolCallResults: fallbackToolCallResults,
    toolCalls: fallbackToolCalls,
    tools,
    turnId,
    url
  } = loopOptions;
  const requestId = getRequestId();
  const timestamp = getTimeStamp();
  const storedState = await getStoredAiLoopState(sessionId, text, fallbackToolCalls, fallbackToolCallResults);
  const {
    messages,
    toolCallResults,
    toolCalls
  } = storedState;
  if (toolCallResults.length === 0 && toolCalls.length > 0) {
    return aiLoopIterationToolCall({
      requestId,
      sessionId,
      timestamp,
      toolCalls,
      turnId
    });
  }
  return aiLoopIterationAiRequest({
    headers,
    maxToolCalls,
    messages,
    modelId,
    providerId,
    requestId,
    sessionId,
    systemPrompt,
    timestamp,
    toolCallResults,
    toolCalls,
    tools,
    turnId,
    url
  });
};

/* eslint-disable prefer-destructuring */

const aiLoop = async loopOptions => {
  const {
    headers,
    maxToolCalls,
    modelId,
    providerId,
    sessionId,
    systemPrompt,
    text,
    tools,
    turnId,
    url
  } = loopOptions;
  let toolCalls = [];
  let toolCallResults = [];
  do {
    const result = await aiLoopIteration({
      headers,
      maxToolCalls,
      modelId,
      providerId,
      sessionId,
      systemPrompt,
      text,
      toolCallResults,
      toolCalls,
      tools,
      turnId,
      url
    });
    if (result.type === 'error') {
      return {
        error: result.error,
        type: 'error'
      };
    }
    if (result.toolCallResults.length > 0) {
      return {
        type: 'reschedule'
      };
    }
    toolCalls = result.toolCalls;
    toolCallResults = result.toolCallResults;
  } while (toolCalls.length > 0);
  return {
    type: 'success'
  };
};

const settleRejectedWaiters = (pendingSessionWork, processedVersion, error) => {
  const remainingWaiters = [];
  for (const waiter of pendingSessionWork.waiters) {
    if (waiter.targetVersion <= processedVersion) {
      waiter.reject(error);
      continue;
    }
    remainingWaiters.push(waiter);
  }
  pendingSessionWork.waiters = remainingWaiters;
};

const settleResolvedWaiters = (pendingSessionWork, processedVersion) => {
  const remainingWaiters = [];
  for (const waiter of pendingSessionWork.waiters) {
    if (waiter.targetVersion <= processedVersion) {
      waiter.resolve();
      continue;
    }
    remainingWaiters.push(waiter);
  }
  pendingSessionWork.waiters = remainingWaiters;
};

const runQueue = async () => {
  while (pendingSessionIds.length > 0) {
    const sessionId = pendingSessionIds.shift();
    if (!sessionId) {
      continue;
    }
    const pendingSessionWork = pendingSessionWorkBySessionId.get(sessionId);
    if (!pendingSessionWork) {
      continue;
    }
    pendingSessionWork.queued = false;
    const targetVersion = pendingSessionWork.pendingVersion;
    try {
      const result = await aiLoop(pendingSessionWork.options);
      if (result.type === 'reschedule') {
        enqueueSessionId(sessionId, pendingSessionWork);
        continue;
      }
      pendingSessionWork.processedVersion = targetVersion;
      if (result.type === 'error') {
        settleResolvedWaiters(pendingSessionWork, targetVersion);
      } else {
        settleResolvedWaiters(pendingSessionWork, targetVersion);
      }
    } catch (error) {
      const normalizedError = getError(error);
      pendingSessionWork.processedVersion = targetVersion;
      settleRejectedWaiters(pendingSessionWork, targetVersion, normalizedError);
    }
    if (pendingSessionWork.pendingVersion > pendingSessionWork.processedVersion) {
      enqueueSessionId(sessionId, pendingSessionWork);
      continue;
    }
    if (pendingSessionWork.waiters.length === 0) {
      pendingSessionWorkBySessionId.delete(sessionId);
    }
  }
  setPendingWorkPromise(undefined);
};

const processQueue = async sessionId => {
  const pendingSessionWork = pendingSessionWorkBySessionId.get(sessionId);
  if (!pendingSessionWork) {
    return;
  }
  if (pendingSessionWork.pendingVersion <= pendingSessionWork.processedVersion) {
    return;
  }
  const targetVersion = pendingSessionWork.pendingVersion;
  const promise = new Promise((resolve, reject) => {
    pendingSessionWork.waiters.push({
      reject,
      resolve,
      targetVersion
    });
  });
  if (!pendingWorkPromise) {
    setPendingWorkPromise(runQueue());
  }
  await promise;
};

const openApiApiKeyRequiredMessage = 'OpenAI API key is not configured. Enter your OpenAI API key below and click Save.';
const defaultMaxToolCalls = 100;
const getBackendResponsesEndpoint = backendUrl => {
  return backendUrl.endsWith('/') ? `${backendUrl}v1/responses` : `${backendUrl}/v1/responses`;
};
const normalizeOpenAiModelId = modelId => {
  const normalizedModelId = modelId.toLowerCase();
  if (normalizedModelId.startsWith('openapi/')) {
    return modelId.slice('openapi/'.length);
  }
  if (normalizedModelId.startsWith('openai/')) {
    return modelId.slice('openai/'.length);
  }
  return modelId;
};
const isTestModel = modelId => {
  return modelId === 'test';
};
const getQueuedText = (text, role, attachments) => {
  const content = [];
  if (text) {
    content.push({
      text,
      type: 'input_text'
    });
  }
  content.push(...getAttachmentParts(attachments));
  return [{
    content,
    role
  }];
};
const handleSubmit = async options => {
  const {
    attachments = [],
    authAccessToken = '',
    backendUrl = '',
    id,
    maxToolCalls = defaultMaxToolCalls,
    modelId,
    openAiKey,
    requestId,
    role,
    sessionId,
    systemPrompt,
    text,
    tools = [],
    useOwnBackend = false
  } = options;
  const date = new Date();
  const timestamp = date.toISOString();
  await appendChatEvent({
    id,
    message: {
      ...(attachments.length > 0 ? {
        attachments
      } : {}),
      content: [{
        text,
        type: 'text'
      }],
      role
    },
    requestId,
    sessionId,
    timestamp,
    type: Message
  });
  if (!isTestModel(modelId) && !useOwnBackend && !openAiKey.trim()) {
    await appendChatEvent({
      id: requestId,
      message: {
        content: [{
          text: openApiApiKeyRequiredMessage,
          type: 'text'
        }],
        role: 'assistant'
      },
      requestId,
      sessionId,
      timestamp,
      type: Message
    });
    return;
  }
  addPendingSessionWork({
    headers: {
      Authorization: `Bearer ${useOwnBackend ? authAccessToken : openAiKey}`,
      'Content-Type': 'application/json'
    },
    maxToolCalls,
    modelId: normalizeOpenAiModelId(modelId),
    providerId: useOwnBackend ? 'backend' : 'openai',
    sessionId,
    systemPrompt,
    text: getQueuedText(text, role, attachments),
    tools,
    turnId: requestId,
    url: useOwnBackend ? getBackendResponsesEndpoint(backendUrl) : 'https://api.openai.com/v1/responses'
  });
  await processQueue(sessionId);
};

const mockBackendSetHttpErrorResponse = (statusCode, body) => {
  setHttpErrorResponse(statusCode, body);
};

const mockBackendSetResponse = body => {
  setResponse(body);
};

const mockOpenApiSetResponse = body => {
  const responses = Array.isArray(body) ? body : [body];
  if (responses.length === 1) {
    const serialized = typeof responses[0] === 'string' ? responses[0] : JSON.stringify(responses[0]) || 'null';
    reset();
    pushChunk(serialized);
    finish();
    return;
  }
  reset();
  for (let index = 0; index < responses.length; index += 1) {
    const response = responses[index];
    const requestId = `mock-response-${index + 1}`;
    const serialized = typeof response === 'string' ? response : JSON.stringify(response) || 'null';
    reset(requestId);
    pushChunk(serialized, requestId);
    finish(requestId);
  }
};

const registerMockResponse = mockResponse => {
  reset();
  pushChunk(mockResponse.text);
  finish();
};

const commandMap = {
  'ChatCoordinator.createSession': createSession,
  'ChatCoordinator.handleSubmit': handleSubmit,
  'ChatCoordinator.mockBackendSetHttpErrorResponse': mockBackendSetHttpErrorResponse,
  'ChatCoordinator.mockBackendSetResponse': mockBackendSetResponse,
  'ChatCoordinator.mockOpenApiSetResponse': mockOpenApiSetResponse,
  'ChatCoordinator.mockOpenApiStreamFinish': finish,
  'ChatCoordinator.mockOpenApiStreamPushChunk': pushChunk,
  'ChatCoordinator.mockOpenApiStreamReset': reset,
  'ChatCoordinator.registerMockResponse': registerMockResponse,
  'ChatCoordinator.submit': handleSubmit,
  'HandleMessagePort.handleMessagePort': handleMessagePort,
  initialize: (_, port) => handleMessagePort(port)
};

const sendMessagePortToAuthWorker = async port => {
  await sendMessagePortToAuthWorker$1(port, 0);
};
const initializeAuthWorker = async () => {
  const rpc = await create$2({
    commandMap: {},
    send: sendMessagePortToAuthWorker
  });
  set$3(rpc);
};

const listen = async () => {
  const r = await create$1({
    commandMap: commandMap
  });
  set(r);
  const s = await create$2({
    commandMap: {},
    send(port) {
      return sendMessagePortToChatStorageWorker(port);
    }
  });
  set$2(s);
  const t = await create$2({
    commandMap: {},
    send(port) {
      return sendMessagePortToChatToolWorker(port);
    }
  });
  set$1(t);
  await initializeAuthWorker();
};

const main = async () => {
  await listen();
};

main();
