'use strict';

var core = require('@agentskit/core');

// src/stream-errors.ts
function isAbortError(err) {
  if (err instanceof DOMException && err.name === "AbortError") return true;
  if (err instanceof Error && err.name === "AbortError") return true;
  return false;
}
function adapterErrorChunk(message, options) {
  const error = new core.AdapterError({
    code: options?.code ?? core.ErrorCodes.AK_ADAPTER_STREAM_FAILED,
    message,
    cause: options?.cause
  });
  return {
    type: "error",
    content: message,
    metadata: { error }
  };
}
function raceAbort(promise, signal) {
  if (signal.aborted) {
    return Promise.reject(new DOMException("Aborted", "AbortError"));
  }
  return new Promise((resolve, reject) => {
    let settled = false;
    const onAbort = () => {
      if (settled) return;
      settled = true;
      signal.removeEventListener("abort", onAbort);
      reject(new DOMException("Aborted", "AbortError"));
    };
    signal.addEventListener("abort", onAbort);
    promise.then(
      (value) => {
        if (settled) return;
        settled = true;
        signal.removeEventListener("abort", onAbort);
        resolve(value);
      },
      (err) => {
        if (settled) return;
        settled = true;
        signal.removeEventListener("abort", onAbort);
        reject(err);
      }
    );
  });
}

// src/createAdapter.ts
function createAdapter(config) {
  return {
    createSource: (request) => {
      const controller = new AbortController();
      let activeStream = null;
      let parseIter = null;
      const cleanup = () => {
        try {
          void activeStream?.cancel();
        } catch {
        }
        activeStream = null;
        if (parseIter && typeof parseIter.return === "function") {
          void parseIter.return(void 0).catch(() => {
          });
        }
        parseIter = null;
        try {
          config.abort?.();
        } catch {
        }
      };
      return {
        stream: async function* () {
          if (controller.signal.aborted) return;
          try {
            const result = await raceAbort(config.send(request, controller.signal), controller.signal);
            if (controller.signal.aborted) {
              if (result instanceof Response) {
                try {
                  await result.body?.cancel();
                } catch {
                }
              }
              return;
            }
            const stream = result instanceof Response ? result.body : result;
            if (!stream) {
              yield adapterErrorChunk("Adapter send() returned empty body");
              return;
            }
            activeStream = stream;
            const response = result instanceof Response ? result : void 0;
            const iterable = config.parse(stream, response);
            parseIter = iterable[Symbol.asyncIterator]();
            while (true) {
              if (controller.signal.aborted) {
                cleanup();
                return;
              }
              let next;
              try {
                next = await raceAbort(parseIter.next(), controller.signal);
              } catch (err) {
                if (isAbortError(err) || controller.signal.aborted) {
                  cleanup();
                  return;
                }
                throw err;
              }
              if (next.done) break;
              if (controller.signal.aborted) {
                cleanup();
                return;
              }
              yield next.value;
              if (next.value.type === "done" || next.value.type === "error") {
                if (typeof parseIter.return === "function") {
                  await parseIter.return(void 0).catch(() => {
                  });
                }
                parseIter = null;
                activeStream = null;
                return;
              }
            }
            yield adapterErrorChunk("Adapter parser ended without a terminal chunk");
            activeStream = null;
          } catch (err) {
            if (isAbortError(err) || controller.signal.aborted) return;
            const message = err instanceof Error ? err.message : String(err);
            yield adapterErrorChunk(message, { cause: err });
          } finally {
            if (controller.signal.aborted) cleanup();
          }
        },
        abort: () => {
          if (!controller.signal.aborted) controller.abort();
          cleanup();
        }
      };
    }
  };
}

exports.createAdapter = createAdapter;
//# sourceMappingURL=createAdapter.cjs.map
//# sourceMappingURL=createAdapter.cjs.map