UNPKG

@ai-sdk/react

Version:

[React](https://react.dev/) UI components for the [AI SDK](https://ai-sdk.dev/docs):

496 lines (488 loc) 16.2 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; 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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __accessCheck = (obj, member, msg) => { if (!member.has(obj)) throw TypeError("Cannot " + msg); }; var __privateGet = (obj, member, getter) => { __accessCheck(obj, member, "read from private field"); return getter ? getter.call(obj) : member.get(obj); }; var __privateAdd = (obj, member, value) => { if (member.has(obj)) throw TypeError("Cannot add the same private member more than once"); member instanceof WeakSet ? member.add(obj) : member.set(obj, value); }; var __privateSet = (obj, member, value, setter) => { __accessCheck(obj, member, "write to private field"); setter ? setter.call(obj, value) : member.set(obj, value); return value; }; // src/index.ts var src_exports = {}; __export(src_exports, { Chat: () => Chat, experimental_useObject: () => experimental_useObject, useChat: () => useChat, useCompletion: () => useCompletion }); module.exports = __toCommonJS(src_exports); // src/use-chat.ts var import_react = require("react"); // src/chat.react.ts var import_ai = require("ai"); // src/throttle.ts var import_throttleit = __toESM(require("throttleit")); function throttle(fn, waitMs) { return waitMs != null ? (0, import_throttleit.default)(fn, waitMs) : fn; } // src/chat.react.ts var _messages, _status, _error, _messagesCallbacks, _statusCallbacks, _errorCallbacks, _callMessagesCallbacks, _callStatusCallbacks, _callErrorCallbacks; var ReactChatState = class { constructor(initialMessages = []) { __privateAdd(this, _messages, void 0); __privateAdd(this, _status, "ready"); __privateAdd(this, _error, void 0); __privateAdd(this, _messagesCallbacks, /* @__PURE__ */ new Set()); __privateAdd(this, _statusCallbacks, /* @__PURE__ */ new Set()); __privateAdd(this, _errorCallbacks, /* @__PURE__ */ new Set()); this.pushMessage = (message) => { __privateSet(this, _messages, __privateGet(this, _messages).concat(message)); __privateGet(this, _callMessagesCallbacks).call(this); }; this.popMessage = () => { __privateSet(this, _messages, __privateGet(this, _messages).slice(0, -1)); __privateGet(this, _callMessagesCallbacks).call(this); }; this.replaceMessage = (index, message) => { __privateSet(this, _messages, [ ...__privateGet(this, _messages).slice(0, index), // We deep clone the message here to ensure the new React Compiler (currently in RC) detects deeply nested parts/metadata changes: this.snapshot(message), ...__privateGet(this, _messages).slice(index + 1) ]); __privateGet(this, _callMessagesCallbacks).call(this); }; this.snapshot = (value) => structuredClone(value); this["~registerMessagesCallback"] = (onChange, throttleWaitMs) => { const callback = throttleWaitMs ? throttle(onChange, throttleWaitMs) : onChange; __privateGet(this, _messagesCallbacks).add(callback); return () => { __privateGet(this, _messagesCallbacks).delete(callback); }; }; this["~registerStatusCallback"] = (onChange) => { __privateGet(this, _statusCallbacks).add(onChange); return () => { __privateGet(this, _statusCallbacks).delete(onChange); }; }; this["~registerErrorCallback"] = (onChange) => { __privateGet(this, _errorCallbacks).add(onChange); return () => { __privateGet(this, _errorCallbacks).delete(onChange); }; }; __privateAdd(this, _callMessagesCallbacks, () => { __privateGet(this, _messagesCallbacks).forEach((callback) => callback()); }); __privateAdd(this, _callStatusCallbacks, () => { __privateGet(this, _statusCallbacks).forEach((callback) => callback()); }); __privateAdd(this, _callErrorCallbacks, () => { __privateGet(this, _errorCallbacks).forEach((callback) => callback()); }); __privateSet(this, _messages, initialMessages); } get status() { return __privateGet(this, _status); } set status(newStatus) { __privateSet(this, _status, newStatus); __privateGet(this, _callStatusCallbacks).call(this); } get error() { return __privateGet(this, _error); } set error(newError) { __privateSet(this, _error, newError); __privateGet(this, _callErrorCallbacks).call(this); } get messages() { return __privateGet(this, _messages); } set messages(newMessages) { __privateSet(this, _messages, [...newMessages]); __privateGet(this, _callMessagesCallbacks).call(this); } }; _messages = new WeakMap(); _status = new WeakMap(); _error = new WeakMap(); _messagesCallbacks = new WeakMap(); _statusCallbacks = new WeakMap(); _errorCallbacks = new WeakMap(); _callMessagesCallbacks = new WeakMap(); _callStatusCallbacks = new WeakMap(); _callErrorCallbacks = new WeakMap(); var _state; var Chat = class extends import_ai.AbstractChat { constructor({ messages, ...init }) { const state = new ReactChatState(messages); super({ ...init, state }); __privateAdd(this, _state, void 0); this["~registerMessagesCallback"] = (onChange, throttleWaitMs) => __privateGet(this, _state)["~registerMessagesCallback"](onChange, throttleWaitMs); this["~registerStatusCallback"] = (onChange) => __privateGet(this, _state)["~registerStatusCallback"](onChange); this["~registerErrorCallback"] = (onChange) => __privateGet(this, _state)["~registerErrorCallback"](onChange); __privateSet(this, _state, state); } }; _state = new WeakMap(); // src/use-chat.ts function useChat({ experimental_throttle: throttleWaitMs, resume = false, ...options } = {}) { const chatRef = (0, import_react.useRef)( "chat" in options ? options.chat : new Chat(options) ); const shouldRecreateChat = "chat" in options && options.chat !== chatRef.current || "id" in options && chatRef.current.id !== options.id; if (shouldRecreateChat) { chatRef.current = "chat" in options ? options.chat : new Chat(options); } const optionsId = "id" in options ? options.id : null; const subscribeToMessages = (0, import_react.useCallback)( (update) => chatRef.current["~registerMessagesCallback"](update, throttleWaitMs), // optionsId is required to trigger re-subscription when the chat ID changes // eslint-disable-next-line react-hooks/exhaustive-deps [throttleWaitMs, optionsId] ); const messages = (0, import_react.useSyncExternalStore)( subscribeToMessages, () => chatRef.current.messages, () => chatRef.current.messages ); const status = (0, import_react.useSyncExternalStore)( chatRef.current["~registerStatusCallback"], () => chatRef.current.status, () => chatRef.current.status ); const error = (0, import_react.useSyncExternalStore)( chatRef.current["~registerErrorCallback"], () => chatRef.current.error, () => chatRef.current.error ); const setMessages = (0, import_react.useCallback)( (messagesParam) => { if (typeof messagesParam === "function") { messagesParam = messagesParam(chatRef.current.messages); } chatRef.current.messages = messagesParam; }, [chatRef] ); (0, import_react.useEffect)(() => { if (resume) { chatRef.current.resumeStream(); } }, [resume, chatRef]); return { id: chatRef.current.id, messages, setMessages, sendMessage: chatRef.current.sendMessage, regenerate: chatRef.current.regenerate, clearError: chatRef.current.clearError, stop: chatRef.current.stop, error, resumeStream: chatRef.current.resumeStream, status, /** * @deprecated Use `addToolOutput` instead. */ addToolResult: chatRef.current.addToolOutput, addToolOutput: chatRef.current.addToolOutput }; } // src/use-completion.ts var import_ai2 = require("ai"); var import_react2 = require("react"); var import_swr = __toESM(require("swr")); function useCompletion({ api = "/api/completion", id, initialCompletion = "", initialInput = "", credentials, headers, body, streamProtocol = "data", fetch: fetch2, onFinish, onError, experimental_throttle: throttleWaitMs } = {}) { const hookId = (0, import_react2.useId)(); const completionId = id || hookId; const { data, mutate } = (0, import_swr.default)([api, completionId], null, { fallbackData: initialCompletion }); const { data: isLoading = false, mutate: mutateLoading } = (0, import_swr.default)( [completionId, "loading"], null ); const [error, setError] = (0, import_react2.useState)(void 0); const completion = data; const [abortController, setAbortController] = (0, import_react2.useState)(null); const extraMetadataRef = (0, import_react2.useRef)({ credentials, headers, body }); (0, import_react2.useEffect)(() => { extraMetadataRef.current = { credentials, headers, body }; }, [credentials, headers, body]); const triggerRequest = (0, import_react2.useCallback)( async (prompt, options) => (0, import_ai2.callCompletionApi)({ api, prompt, credentials: extraMetadataRef.current.credentials, headers: { ...extraMetadataRef.current.headers, ...options == null ? void 0 : options.headers }, body: { ...extraMetadataRef.current.body, ...options == null ? void 0 : options.body }, streamProtocol, fetch: fetch2, // throttle streamed ui updates: setCompletion: throttle( (completion2) => mutate(completion2, false), throttleWaitMs ), setLoading: mutateLoading, setError, setAbortController, onFinish, onError }), [ mutate, mutateLoading, api, extraMetadataRef, setAbortController, onFinish, onError, setError, streamProtocol, fetch2, throttleWaitMs ] ); const stop = (0, import_react2.useCallback)(() => { if (abortController) { abortController.abort(); setAbortController(null); } }, [abortController]); const setCompletion = (0, import_react2.useCallback)( (completion2) => { mutate(completion2, false); }, [mutate] ); const complete = (0, import_react2.useCallback)( async (prompt, options) => { return triggerRequest(prompt, options); }, [triggerRequest] ); const [input, setInput] = (0, import_react2.useState)(initialInput); const handleSubmit = (0, import_react2.useCallback)( (event) => { var _a; (_a = event == null ? void 0 : event.preventDefault) == null ? void 0 : _a.call(event); return input ? complete(input) : void 0; }, [input, complete] ); const handleInputChange = (0, import_react2.useCallback)( (e) => { setInput(e.target.value); }, [setInput] ); return { completion, complete, error, setCompletion, stop, input, setInput, handleInputChange, handleSubmit, isLoading }; } // src/use-object.ts var import_provider_utils = require("@ai-sdk/provider-utils"); var import_ai3 = require("ai"); var import_react3 = require("react"); var import_swr2 = __toESM(require("swr")); var getOriginalFetch = () => fetch; function useObject({ api, id, schema, // required, in the future we will use it for validation initialValue, fetch: fetch2, onError, onFinish, headers, credentials }) { const hookId = (0, import_react3.useId)(); const completionId = id != null ? id : hookId; const { data, mutate } = (0, import_swr2.default)( [api, completionId], null, { fallbackData: initialValue } ); const [error, setError] = (0, import_react3.useState)(void 0); const [isLoading, setIsLoading] = (0, import_react3.useState)(false); const abortControllerRef = (0, import_react3.useRef)(null); const stop = (0, import_react3.useCallback)(() => { var _a; try { (_a = abortControllerRef.current) == null ? void 0 : _a.abort(); } catch (ignored) { } finally { setIsLoading(false); abortControllerRef.current = null; } }, []); const submit = async (input) => { var _a; try { clearObject(); setIsLoading(true); const abortController = new AbortController(); abortControllerRef.current = abortController; const actualFetch = fetch2 != null ? fetch2 : getOriginalFetch(); const response = await actualFetch(api, { method: "POST", headers: { "Content-Type": "application/json", ...headers }, credentials, signal: abortController.signal, body: JSON.stringify(input) }); if (!response.ok) { throw new Error( (_a = await response.text()) != null ? _a : "Failed to fetch the response." ); } if (response.body == null) { throw new Error("The response body is empty."); } let accumulatedText = ""; let latestObject = void 0; await response.body.pipeThrough(new TextDecoderStream()).pipeTo( new WritableStream({ async write(chunk) { accumulatedText += chunk; const { value } = await (0, import_ai3.parsePartialJson)(accumulatedText); const currentObject = value; if (!(0, import_ai3.isDeepEqualData)(latestObject, currentObject)) { latestObject = currentObject; mutate(currentObject); } }, async close() { setIsLoading(false); abortControllerRef.current = null; if (onFinish != null) { const validationResult = await (0, import_provider_utils.safeValidateTypes)({ value: latestObject, schema: (0, import_ai3.asSchema)(schema) }); onFinish( validationResult.success ? { object: validationResult.value, error: void 0 } : { object: void 0, error: validationResult.error } ); } } }) ); } catch (error2) { if ((0, import_provider_utils.isAbortError)(error2)) { return; } if (onError && error2 instanceof Error) { onError(error2); } setIsLoading(false); setError(error2 instanceof Error ? error2 : new Error(String(error2))); } }; const clear = () => { stop(); clearObject(); }; const clearObject = () => { setError(void 0); setIsLoading(false); mutate(void 0); }; return { submit, object: data, error, isLoading, stop, clear }; } var experimental_useObject = useObject; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Chat, experimental_useObject, useChat, useCompletion }); //# sourceMappingURL=index.js.map