@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
JavaScript
;
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