492 lines
16 KiB
JavaScript
492 lines
16 KiB
JavaScript
"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,
|
|
addToolResult: chatRef.current.addToolResult
|
|
};
|
|
}
|
|
|
|
// 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
|