UNPKG

@axflow/models

Version:

Zero-dependency, modular SDK for building robust natural language applications

287 lines (281 loc) 9.34 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/shared/index.ts var shared_exports = {}; __export(shared_exports, { HttpError: () => HttpError, IterableToStream: () => IterableToStream, NdJsonStream: () => NdJsonStream, POST: () => POST, StreamToIterable: () => StreamToIterable, StreamingJsonResponse: () => StreamingJsonResponse, createMessage: () => createMessage, isHttpError: () => isHttpError, toolCallWithDefaults: () => toolCallWithDefaults }); module.exports = __toCommonJS(shared_exports); // src/shared/http.ts var HttpError = class extends Error { code; response; constructor(message, response) { super(message); this.code = response.status; this.response = response; } }; function isHttpError(e) { return e instanceof HttpError; } async function POST(url, options) { const _fetch = options?.fetch ?? fetch; if (typeof _fetch === "undefined") { throw new Error( "Environment does not support fetch (https://developer.mozilla.org/en-US/docs/Web/API/fetch)" ); } const init = { ...options, method: "POST" }; delete init.fetch; const response = await _fetch(url, init); if (!response.ok) { throw new HttpError(`Request failed with status code ${response.status}`, response); } return response; } // src/shared/stream.ts function IterableToStream(iterable) { if (typeof ReadableStream.from === "function") { return ReadableStream.from(iterable); } const iterator = iterable[Symbol.asyncIterator](); return new ReadableStream({ async pull(controller) { const { done, value } = await iterator.next(); if (done) { controller.close(); } else { controller.enqueue(value); } } }); } function StreamToIterable(stream) { return stream[Symbol.asyncIterator] ? stream[Symbol.asyncIterator]() : createIterable(stream); } async function* createIterable(stream) { const reader = stream.getReader(); try { while (true) { const { done, value } = await reader.read(); if (done) { return; } yield value; } } finally { reader.releaseLock(); } } var NdJsonStream = class { /** * These are the proper headers for newline-delimited JSON streams. * * @see http://ndjson.org */ static headers = Object.freeze({ "content-type": "application/x-ndjson; charset=utf-8" }); /** * Transforms a stream of JSON-serializable objects to stream of newline-delimited JSON. * * Each object is wrapped with an object that specifies the `type` and references * the `value`. The `type` is one of `chunk` or `data`. A type of `chunk` means that * the `value` corresponds to chunks from the input stream. A type of `data` means * that the `value` corresponds to the additional data provided as the second argument * to this function. * * * Example WITHOUT additional data: * * const chunk = { key: 'value' }; * const stream = new ReadableStream({start(con) { con.enqueue(chunk); con.close() }}); * const ndJsonStream = NdJsonStream.encode(stream); * const entries = []; * for await (const chunk of stream) { * entry.push(new TextDecoder().decode(chunk)); * } * console.log(entries); // [ "{\"type\":\"chunk\",\"value\":{\"key\":\"value\"}}\n" ] * * * Example WITH additional data: * * const chunk = { key: 'value' }; * const stream = new ReadableStream({start(con) { con.enqueue(chunk); con.close() }}); * const ndJsonStream = NdJsonStream.encode(stream, { data: [{ extra: 'data' }] }); * const entries = []; * for await (const chunk of stream) { * entry.push(new TextDecoder().decode(chunk)); * } * console.log(entries); // [ "{\"type\":\"data\",\"value\":{\"extra\":\"data\"}}\n", "{\"type\":\"chunk\",\"value\":{\"key\":\"value\"}}\n" ] * * @see http://ndjson.org * * @param stream A readable stream of chunks to encode as newline-delimited JSON. * @param options * @param options.data Additional data to enqueue to the output stream. If data is a `Promise`, the stream will wait for it to resolve and enqueue its resolved values before closing. * @returns A readable stream of newline-delimited JSON. */ static encode(stream, options) { const data = options?.data ?? []; const dataIsPromise = data instanceof Promise; const encoder = new TextEncoder(); function serialize(obj) { const serialized = JSON.stringify(obj); return encoder.encode(`${serialized} `); } const ndJsonEncode = new TransformStream({ start(controller) { if (dataIsPromise) { return; } if (!Array.isArray(data)) { throw new Error( `Expected options.data to be an array of JSON-serializable objects but it was ${typeof data}` ); } for (const value of data) { controller.enqueue(serialize({ type: "data", value })); } }, async transform(value, controller) { controller.enqueue(serialize({ type: "chunk", value })); }, async flush(controller) { if (!dataIsPromise) { return; } const result = await Promise.resolve(data); if (!Array.isArray(result)) { throw new Error( `Expected options.data to resolve to an array of JSON-serializable objects but it was ${typeof result}` ); } for (const value of result) { controller.enqueue(serialize({ type: "data", value })); } } }); return stream.pipeThrough(ndJsonEncode); } /** * Transforms a stream of newline-delimited JSON to a stream of objects. * * @see http://ndjson.org * * @param stream A readable stream of newline-delimited JSON objects. * @returns A readable stream of objects. */ static decode(stream) { let buffer = []; const decoder = new TextDecoder(); const parser = new TransformStream({ transform(bytes, controller) { const chunk = decoder.decode(bytes); for (let i = 0, len = chunk.length; i < len; ++i) { const isChunkSeparator = chunk[i] === "\n"; if (!isChunkSeparator) { buffer.push(chunk[i]); continue; } const line = buffer.join("").trimEnd(); controller.enqueue(JSON.parse(line)); buffer = []; } } }); return stream.pipeThrough(parser); } }; var StreamingJsonResponse = class extends Response { /** * Create a `Response` object that streams newline-delimited JSON objects. * * Example * * export async function POST(request: Request) { * const req = await request.json(); * const stream = await OpenAIChat.stream(req, { apiKey: OPENAI_API_KEY }); * return new StreamingJsonResponse(stream, { * map: (chunk) => chunk.choices[0].delta.content ?? '' * data: [{ stream: "additional" }, { data: "here" }] * }); * } * * @see http://ndjson.org * * @param stream A readable stream of chunks to encode as newline-delimited JSON. * @param options * @param options.status HTTP response status. * @param options.statusText HTTP response status text. * @param options.headers HTTP response headers. * @param options.data Additional data to enqueue to the output stream. If data is a `Promise`, the stream will wait for it to resolve and enqueue its resolved values before closing. */ constructor(stream, options) { options ??= {}; const ndjson = NdJsonStream.encode(stream, { data: options.data }); super(ndjson, { status: options.status, statusText: options.statusText, headers: { ...options.headers, ...NdJsonStream.headers } }); } }; // src/shared/types.ts var toolCallWithDefaults = (toolCall) => ({ index: toolCall.index ?? 0, id: toolCall.id ?? "", type: "function", function: { name: toolCall.function?.name ?? "", arguments: toolCall.function?.arguments ?? "" } }); // src/shared/message.ts var createMessage = (message) => { const defaults = { id: crypto.randomUUID(), role: "user", created: Date.now(), content: "" }; return Object.assign(defaults, message); }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { HttpError, IterableToStream, NdJsonStream, POST, StreamToIterable, StreamingJsonResponse, createMessage, isHttpError, toolCallWithDefaults });