@antdv-next/x-sdk 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/_util/resolveMaybeRef.d.ts +2 -0
- package/dist/_util/resolveMaybeRef.js +7 -0
- package/dist/_util/types.js +0 -0
- package/dist/chat-providers/AbstractChatProvider.d.ts +2 -2
- package/dist/chat-providers/AbstractChatProvider.js +42 -0
- package/dist/chat-providers/DeepSeekChatProvider.d.ts +2 -2
- package/dist/chat-providers/DeepSeekChatProvider.js +59 -0
- package/dist/chat-providers/DefaultChatProvider.d.ts +2 -2
- package/dist/chat-providers/DefaultChatProvider.js +26 -0
- package/dist/chat-providers/OpenAIChatProvider.d.ts +2 -2
- package/dist/chat-providers/OpenAIChatProvider.js +49 -0
- package/dist/chat-providers/index.js +4 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -3
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/expect/index.js +1467 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/pretty-format/index.js +884 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/runner/chunk-artifact.js +1513 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/snapshot/index.js +661 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/spy/index.js +384 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/utils/chunk-pathe.M-eThtNZ.js +80 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/utils/diff.js +1304 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/utils/display.js +556 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/utils/error.js +27 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/utils/helpers.js +179 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/utils/offset.js +25 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/utils/serialize.js +75 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/utils/source-map.js +371 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/utils/timers.js +35 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/chunks/_commonjsHelpers.D26ty3Ew.js +4 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/chunks/rpc.MzXet3jl.js +50 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/chunks/test.CBQUpOM3.js +2645 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/chunks/utils.BX5Fg8C4.js +42 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/vendor/chai.js +2872 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/vendor/magic-string.js +1009 -0
- package/dist/node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/vendor/tinyrainbow.js +84 -0
- package/dist/x-chat/__tests__/index.test.d.ts +1 -0
- package/dist/x-chat/__tests__/index.test.js +258 -0
- package/dist/x-chat/index.d.ts +14 -23
- package/dist/x-chat/index.js +85 -67
- package/dist/x-chat/store.d.ts +2 -0
- package/dist/{store-C1diHqNH.js → x-chat/store.js} +15 -9
- package/dist/x-conversations/__tests__/index.test.d.ts +1 -0
- package/dist/x-conversations/__tests__/index.test.js +36 -0
- package/dist/x-conversations/index.d.ts +4 -4
- package/dist/x-conversations/index.js +37 -1
- package/dist/{x-conversations-BrKWhj5r.js → x-conversations/store.js} +2 -31
- package/dist/x-request/__tests__/index.test.d.ts +1 -0
- package/dist/x-request/__tests__/index.test.js +90 -0
- package/dist/x-request/index.d.ts +36 -11
- package/dist/x-request/index.js +246 -1
- package/dist/x-request/x-fetch.js +18 -0
- package/dist/x-stream/__tests__/index.test.d.ts +1 -0
- package/dist/x-stream/__tests__/index.test.js +62 -0
- package/dist/x-stream/index.js +16 -5
- package/package.json +2 -1
- package/dist/chat-providers-5x9Va7p5.js +0 -167
- package/dist/x-request-BSFGaKND.js +0 -234
package/dist/x-chat/index.js
CHANGED
|
@@ -1,28 +1,49 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import resolveMaybeRef from "../_util/resolveMaybeRef.js";
|
|
2
|
+
import "../chat-providers/index.js";
|
|
3
|
+
import "../x-request/index.js";
|
|
4
|
+
import { ChatMessagesStore, chatMessagesStoreHelper } from "./store.js";
|
|
5
|
+
import { computed, isRef, onScopeDispose, reactive, readonly, ref, shallowRef, watch } from "vue";
|
|
3
6
|
//#region src/x-chat/index.ts
|
|
4
7
|
function toArray(item) {
|
|
5
8
|
return Array.isArray(item) ? item : [item];
|
|
6
9
|
}
|
|
7
|
-
function resolveMaybeRef(value) {
|
|
8
|
-
return isRef(value) ? value.value : value;
|
|
9
|
-
}
|
|
10
10
|
var IsRequestingMap = reactive(/* @__PURE__ */ new Map());
|
|
11
11
|
var generateConversationKey = () => Symbol("ConversationKey");
|
|
12
12
|
function useXChat(config) {
|
|
13
|
-
const { defaultMessages, requestFallback, requestPlaceholder, parser, provider } = config;
|
|
14
13
|
const idRef = ref(0);
|
|
15
14
|
const requestHandlerRef = shallowRef();
|
|
15
|
+
const providerRef = isRef(config.provider) ? config.provider : shallowRef(config.provider);
|
|
16
|
+
let provider = providerRef.value;
|
|
16
17
|
const conversationKey = ref((config.conversationKey ? resolveMaybeRef(config.conversationKey) : void 0) ?? generateConversationKey());
|
|
17
18
|
if (config.conversationKey && isRef(config.conversationKey)) watch(config.conversationKey, (value) => {
|
|
18
19
|
if (value !== void 0 && value !== null) conversationKey.value = value;
|
|
19
20
|
});
|
|
20
21
|
const messageQueueMap = /* @__PURE__ */ new Map();
|
|
21
22
|
const activeStore = shallowRef();
|
|
22
|
-
const messages =
|
|
23
|
-
const
|
|
23
|
+
const messages = shallowRef([]);
|
|
24
|
+
const isDefaultMessagesRequestingRef = shallowRef(false);
|
|
25
|
+
const parsedMessages = computed(() => {
|
|
26
|
+
const parser = config.parser;
|
|
27
|
+
const list = [];
|
|
28
|
+
messages.value.forEach((agentMsg) => {
|
|
29
|
+
const sourceMessage = agentMsg.message;
|
|
30
|
+
const bubbleMsgs = toArray(parser ? parser(sourceMessage) : sourceMessage);
|
|
31
|
+
bubbleMsgs.forEach((bubbleMsg, bubbleMsgIndex) => {
|
|
32
|
+
let key = agentMsg.id;
|
|
33
|
+
if (bubbleMsgs.length > 1) key = `${key}_${bubbleMsgIndex}`;
|
|
34
|
+
list.push({
|
|
35
|
+
id: key,
|
|
36
|
+
message: bubbleMsg,
|
|
37
|
+
status: agentMsg.status
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
return list;
|
|
42
|
+
});
|
|
24
43
|
let unsubscribeStore = null;
|
|
25
44
|
const resolveDefaultMessages = async (currentConversationKey) => {
|
|
45
|
+
const sourceDefaultMessages = config.defaultMessages;
|
|
46
|
+
const defaultMessages = typeof sourceDefaultMessages === "function" ? sourceDefaultMessages : resolveMaybeRef(sourceDefaultMessages);
|
|
26
47
|
return ((typeof defaultMessages === "function" ? await defaultMessages({ conversationKey: currentConversationKey }) : defaultMessages) || []).map((info, index) => ({
|
|
27
48
|
id: `default_${index}`,
|
|
28
49
|
status: "local",
|
|
@@ -37,12 +58,12 @@ function useXChat(config) {
|
|
|
37
58
|
const syncStoreSnapshot = () => {
|
|
38
59
|
if (!activeStore.value) {
|
|
39
60
|
messages.value = [];
|
|
40
|
-
|
|
61
|
+
isDefaultMessagesRequestingRef.value = false;
|
|
41
62
|
return;
|
|
42
63
|
}
|
|
43
64
|
const snapshot = activeStore.value.getSnapshot();
|
|
44
65
|
messages.value = snapshot.messages;
|
|
45
|
-
|
|
66
|
+
isDefaultMessagesRequestingRef.value = snapshot.isDefaultMessagesRequesting;
|
|
46
67
|
};
|
|
47
68
|
const bindStore = (currentConversationKey) => {
|
|
48
69
|
if (unsubscribeStore) {
|
|
@@ -85,38 +106,32 @@ function useXChat(config) {
|
|
|
85
106
|
idRef.value += 1;
|
|
86
107
|
return msg;
|
|
87
108
|
};
|
|
88
|
-
const parsedMessages = computed(() => {
|
|
89
|
-
const list = [];
|
|
90
|
-
messages.value.forEach((agentMsg) => {
|
|
91
|
-
const sourceMessage = agentMsg.message;
|
|
92
|
-
const bubbleMsgs = toArray(parser ? parser(sourceMessage) : sourceMessage);
|
|
93
|
-
bubbleMsgs.forEach((bubbleMsg, bubbleMsgIndex) => {
|
|
94
|
-
let key = agentMsg.id;
|
|
95
|
-
if (bubbleMsgs.length > 1) key = `${key}_${bubbleMsgIndex}`;
|
|
96
|
-
list.push({
|
|
97
|
-
id: key,
|
|
98
|
-
message: bubbleMsg,
|
|
99
|
-
status: agentMsg.status
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
return list;
|
|
104
|
-
});
|
|
105
109
|
const getFilteredMessages = (msgs) => msgs.filter((info) => info.status !== "loading").map((info) => info.message);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
const setupProvider = (nextProvider) => {
|
|
111
|
+
provider = nextProvider;
|
|
112
|
+
if (nextProvider) {
|
|
113
|
+
nextProvider.injectGetMessages(() => {
|
|
114
|
+
return getFilteredMessages(getMessages());
|
|
115
|
+
});
|
|
116
|
+
requestHandlerRef.value = nextProvider.request;
|
|
117
|
+
} else requestHandlerRef.value = void 0;
|
|
118
|
+
};
|
|
119
|
+
setupProvider(provider);
|
|
120
|
+
watch(providerRef, setupProvider);
|
|
111
121
|
const innerOnRequest = (requestParams, opts) => {
|
|
112
122
|
if (!provider) return;
|
|
123
|
+
const activeProvider = provider;
|
|
124
|
+
const requestKey = conversationKey.value;
|
|
125
|
+
const requestStore = createStore(requestKey);
|
|
113
126
|
const { updatingId, reload } = opts || {};
|
|
114
127
|
let loadingMsgId = null;
|
|
115
|
-
const
|
|
128
|
+
const sourceRequestPlaceholder = config.requestPlaceholder;
|
|
129
|
+
const requestPlaceholder = typeof sourceRequestPlaceholder === "function" ? sourceRequestPlaceholder : resolveMaybeRef(sourceRequestPlaceholder);
|
|
130
|
+
const localMessage = activeProvider.transformLocalMessage(requestParams);
|
|
116
131
|
const localMessages = (Array.isArray(localMessage) ? localMessage : [localMessage]).map((message) => createMessage(message, "local", opts?.extraInfo));
|
|
117
132
|
if (reload) {
|
|
118
133
|
loadingMsgId = updatingId;
|
|
119
|
-
setMessages((ori) => {
|
|
134
|
+
requestStore.setMessages((ori) => {
|
|
120
135
|
const nextMessages = [...ori];
|
|
121
136
|
if (requestPlaceholder) {
|
|
122
137
|
let placeholderMsg;
|
|
@@ -132,7 +147,7 @@ function useXChat(config) {
|
|
|
132
147
|
}
|
|
133
148
|
return nextMessages;
|
|
134
149
|
});
|
|
135
|
-
} else setMessages((ori) => {
|
|
150
|
+
} else requestStore.setMessages((ori) => {
|
|
136
151
|
let nextMessages = [...ori, ...localMessages];
|
|
137
152
|
if (requestPlaceholder) {
|
|
138
153
|
let placeholderMsg;
|
|
@@ -146,38 +161,39 @@ function useXChat(config) {
|
|
|
146
161
|
});
|
|
147
162
|
let updatingMsgId = null;
|
|
148
163
|
const updateMessage = (status, chunk, chunks, responseHeaders) => {
|
|
149
|
-
let msg = getMessages().find((info) => info.id === updatingMsgId);
|
|
164
|
+
let msg = requestStore.getMessages().find((info) => info.id === updatingMsgId);
|
|
150
165
|
if (!msg) if (reload && updatingId) {
|
|
151
|
-
msg = getMessages().find((info) => info.id === updatingId);
|
|
166
|
+
msg = requestStore.getMessages().find((info) => info.id === updatingId);
|
|
152
167
|
if (msg) {
|
|
153
168
|
msg.status = status;
|
|
154
|
-
msg.message =
|
|
169
|
+
msg.message = activeProvider.transformMessage({
|
|
155
170
|
chunk,
|
|
156
171
|
status,
|
|
157
172
|
chunks,
|
|
158
173
|
responseHeaders
|
|
159
174
|
});
|
|
160
|
-
setMessages((ori) => {
|
|
175
|
+
requestStore.setMessages((ori) => {
|
|
161
176
|
return [...ori];
|
|
162
177
|
});
|
|
163
178
|
updatingMsgId = msg.id;
|
|
164
179
|
}
|
|
165
180
|
} else {
|
|
166
|
-
|
|
181
|
+
const transformData = activeProvider.transformMessage({
|
|
167
182
|
chunk,
|
|
168
183
|
status,
|
|
169
184
|
chunks,
|
|
170
185
|
responseHeaders
|
|
171
|
-
})
|
|
172
|
-
|
|
186
|
+
});
|
|
187
|
+
msg = createMessage(transformData, status);
|
|
188
|
+
requestStore.setMessages((ori) => {
|
|
173
189
|
return [...ori.filter((info) => info.id !== loadingMsgId), msg];
|
|
174
190
|
});
|
|
175
191
|
updatingMsgId = msg.id;
|
|
176
192
|
}
|
|
177
|
-
else setMessages((ori) => {
|
|
193
|
+
else requestStore.setMessages((ori) => {
|
|
178
194
|
return ori.map((info) => {
|
|
179
195
|
if (info.id === updatingMsgId) {
|
|
180
|
-
const transformData =
|
|
196
|
+
const transformData = activeProvider.transformMessage({
|
|
181
197
|
originMessage: info.message,
|
|
182
198
|
chunk,
|
|
183
199
|
chunks,
|
|
@@ -193,34 +209,36 @@ function useXChat(config) {
|
|
|
193
209
|
return info;
|
|
194
210
|
});
|
|
195
211
|
});
|
|
196
|
-
msg = getMessages().find((info) => info.id === updatingMsgId) || msg;
|
|
212
|
+
msg = requestStore.getMessages().find((info) => info.id === updatingMsgId) || msg;
|
|
197
213
|
return msg;
|
|
198
214
|
};
|
|
199
|
-
|
|
215
|
+
activeProvider.injectRequest({
|
|
200
216
|
onUpdate: (chunk, headers) => {
|
|
201
217
|
return updateMessage("updating", chunk, [], headers);
|
|
202
218
|
},
|
|
203
219
|
onSuccess: (chunks, headers) => {
|
|
204
|
-
if (
|
|
220
|
+
if (requestKey) IsRequestingMap.delete(requestKey);
|
|
205
221
|
return updateMessage("success", void 0, chunks, headers);
|
|
206
222
|
},
|
|
207
223
|
onError: async (error, errorInfo) => {
|
|
208
|
-
if (
|
|
224
|
+
if (requestKey) IsRequestingMap.delete(requestKey);
|
|
209
225
|
let fallbackMsg;
|
|
226
|
+
const sourceRequestFallback = config.requestFallback;
|
|
227
|
+
const requestFallback = typeof sourceRequestFallback === "function" ? sourceRequestFallback : resolveMaybeRef(sourceRequestFallback);
|
|
210
228
|
if (requestFallback) {
|
|
211
229
|
if (typeof requestFallback === "function") {
|
|
212
|
-
const currentMessages =
|
|
230
|
+
const currentMessages = getFilteredMessages(requestStore.getMessages());
|
|
213
231
|
fallbackMsg = await requestFallback(requestParams, {
|
|
214
232
|
error,
|
|
215
233
|
errorInfo,
|
|
216
|
-
messageInfo: getMessages().find((info) => info.id === loadingMsgId || info.id === updatingMsgId),
|
|
234
|
+
messageInfo: requestStore.getMessages().find((info) => info.id === loadingMsgId || info.id === updatingMsgId),
|
|
217
235
|
messages: currentMessages
|
|
218
236
|
});
|
|
219
237
|
} else fallbackMsg = requestFallback;
|
|
220
|
-
setMessages((ori) => [...ori.filter((info) => info.id !== loadingMsgId && info.id !== updatingMsgId), createMessage(fallbackMsg, error.name === "AbortError" ? "abort" : "error")]);
|
|
238
|
+
requestStore.setMessages((ori) => [...ori.filter((info) => info.id !== loadingMsgId && info.id !== updatingMsgId), createMessage(fallbackMsg, error.name === "AbortError" ? "abort" : "error")]);
|
|
221
239
|
} else {
|
|
222
|
-
fallbackMsg = getMessages().find((info) => info.id !== loadingMsgId && info.id !== updatingMsgId);
|
|
223
|
-
setMessages((ori) => {
|
|
240
|
+
fallbackMsg = requestStore.getMessages().find((info) => info.id !== loadingMsgId && info.id !== updatingMsgId)?.message;
|
|
241
|
+
requestStore.setMessages((ori) => {
|
|
224
242
|
return ori.map((info) => {
|
|
225
243
|
if (info.id === loadingMsgId || info.id === updatingMsgId) return {
|
|
226
244
|
...info,
|
|
@@ -233,15 +251,15 @@ function useXChat(config) {
|
|
|
233
251
|
return fallbackMsg;
|
|
234
252
|
}
|
|
235
253
|
});
|
|
236
|
-
if (
|
|
237
|
-
|
|
254
|
+
if (requestKey) IsRequestingMap.set(requestKey, true);
|
|
255
|
+
activeProvider.request.run(activeProvider.transformParams(requestParams, activeProvider.request.options));
|
|
238
256
|
};
|
|
239
257
|
const onRequest = (requestParams, opts) => {
|
|
240
|
-
if (!
|
|
258
|
+
if (!providerRef.value) throw new Error("provider is required");
|
|
241
259
|
innerOnRequest(requestParams, opts);
|
|
242
260
|
};
|
|
243
261
|
const onReload = (id, requestParams, opts) => {
|
|
244
|
-
if (!
|
|
262
|
+
if (!providerRef.value) throw new Error("provider is required");
|
|
245
263
|
if (!id || !getMessages().find((info) => info.id === id)) throw new Error(`message [${id}] is not found`);
|
|
246
264
|
innerOnRequest(requestParams, {
|
|
247
265
|
updatingId: id,
|
|
@@ -251,19 +269,19 @@ function useXChat(config) {
|
|
|
251
269
|
};
|
|
252
270
|
const processMessageQueue = () => {
|
|
253
271
|
const requestParamsList = messageQueueMap.get(conversationKey.value);
|
|
254
|
-
if (requestParamsList && requestParamsList.length > 0) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
requestParamsList.forEach(({ requestParams, opts }) => {
|
|
258
|
-
onRequest(requestParams, opts);
|
|
259
|
-
});
|
|
260
|
-
messageQueueMap.delete(conversationKey.value);
|
|
272
|
+
if (requestParamsList && requestParamsList.length > 0) setTimeout(() => {
|
|
273
|
+
requestParamsList.forEach(({ requestParams, opts }) => {
|
|
274
|
+
onRequest(requestParams, opts);
|
|
261
275
|
});
|
|
262
|
-
|
|
276
|
+
messageQueueMap.delete(conversationKey.value);
|
|
277
|
+
});
|
|
263
278
|
};
|
|
264
|
-
watch(
|
|
279
|
+
watch(isDefaultMessagesRequestingRef, (requesting) => {
|
|
265
280
|
if (!requesting) processMessageQueue();
|
|
266
281
|
});
|
|
282
|
+
if (config.defaultMessages && isRef(config.defaultMessages)) watch(config.defaultMessages, () => {
|
|
283
|
+
activeStore.value?.refreshDefaultMessages();
|
|
284
|
+
}, { deep: true });
|
|
267
285
|
const queueRequest = (currentConversationKey, requestParams, opts) => {
|
|
268
286
|
if (!messageQueueMap.has(currentConversationKey)) messageQueueMap.set(currentConversationKey, []);
|
|
269
287
|
messageQueueMap.get(currentConversationKey).push({
|
|
@@ -273,7 +291,7 @@ function useXChat(config) {
|
|
|
273
291
|
};
|
|
274
292
|
return {
|
|
275
293
|
onRequest,
|
|
276
|
-
isDefaultMessagesRequesting,
|
|
294
|
+
isDefaultMessagesRequesting: readonly(isDefaultMessagesRequestingRef),
|
|
277
295
|
messages,
|
|
278
296
|
parsedMessages,
|
|
279
297
|
setMessages,
|
package/dist/x-chat/store.d.ts
CHANGED
|
@@ -20,10 +20,12 @@ export declare class ChatMessagesStore<T extends {
|
|
|
20
20
|
private pendingEmit;
|
|
21
21
|
private readonly throttleInterval;
|
|
22
22
|
private isDestroyed;
|
|
23
|
+
private defaultMessagesLoader;
|
|
23
24
|
private emitListeners;
|
|
24
25
|
private throttledEmitListeners;
|
|
25
26
|
constructor(defaultMessages: () => Promise<T[]>, conversationKey?: ConversationKey);
|
|
26
27
|
private initializeMessages;
|
|
28
|
+
refreshDefaultMessages: () => boolean;
|
|
27
29
|
private setSnapshotResult;
|
|
28
30
|
private setMessagesInternal;
|
|
29
31
|
setMessages: (messages: T[] | ((ori: T[]) => T[])) => boolean;
|
|
@@ -25,6 +25,7 @@ var ChatMessagesStore = class {
|
|
|
25
25
|
pendingEmit = false;
|
|
26
26
|
throttleInterval = 50;
|
|
27
27
|
isDestroyed = false;
|
|
28
|
+
defaultMessagesLoader;
|
|
28
29
|
emitListeners() {
|
|
29
30
|
this.listeners.forEach((listener) => {
|
|
30
31
|
listener();
|
|
@@ -44,27 +45,32 @@ var ChatMessagesStore = class {
|
|
|
44
45
|
} else this.pendingEmit = true;
|
|
45
46
|
}
|
|
46
47
|
constructor(defaultMessages, conversationKey) {
|
|
47
|
-
this.
|
|
48
|
-
|
|
49
|
-
this.emitListeners();
|
|
50
|
-
});
|
|
48
|
+
this.defaultMessagesLoader = defaultMessages;
|
|
49
|
+
this.initializeMessages();
|
|
51
50
|
if (conversationKey) {
|
|
52
51
|
this.conversationKey = conversationKey;
|
|
53
52
|
chatMessagesStoreHelper.set(this.conversationKey, this);
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
|
-
async initializeMessages(
|
|
55
|
+
async initializeMessages() {
|
|
57
56
|
try {
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
this.setSnapshotResult("isDefaultMessagesRequesting", true);
|
|
58
|
+
this.emitListeners();
|
|
59
|
+
const messages = await this.defaultMessagesLoader();
|
|
60
60
|
if (!this.isDestroyed) this.setMessagesInternal(messages, false);
|
|
61
61
|
} catch (error) {
|
|
62
62
|
console.warn("Failed to initialize messages:", error);
|
|
63
63
|
if (!this.isDestroyed) this.setMessagesInternal([], false);
|
|
64
64
|
} finally {
|
|
65
|
-
|
|
65
|
+
this.setSnapshotResult("isDefaultMessagesRequesting", false);
|
|
66
|
+
this.emitListeners();
|
|
66
67
|
}
|
|
67
68
|
}
|
|
69
|
+
refreshDefaultMessages = () => {
|
|
70
|
+
if (this.isDestroyed) return false;
|
|
71
|
+
this.initializeMessages();
|
|
72
|
+
return true;
|
|
73
|
+
};
|
|
68
74
|
setSnapshotResult = (key, value) => {
|
|
69
75
|
this.snapshotResult = {
|
|
70
76
|
...this.snapshotResult,
|
|
@@ -142,4 +148,4 @@ var ChatMessagesStore = class {
|
|
|
142
148
|
};
|
|
143
149
|
};
|
|
144
150
|
//#endregion
|
|
145
|
-
export {
|
|
151
|
+
export { ChatMessagesStore, chatMessagesStoreHelper };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import useXConversations from "../index.js";
|
|
2
|
+
import { h as describe, m as it } from "../../node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/runner/chunk-artifact.js";
|
|
3
|
+
import { g as globalExpect } from "../../node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/chunks/test.CBQUpOM3.js";
|
|
4
|
+
import { effectScope, nextTick, ref } from "vue";
|
|
5
|
+
//#region src/x-conversations/__tests__/index.test.ts
|
|
6
|
+
describe("useXConversations", () => {
|
|
7
|
+
it("syncs default conversations and active key from refs", async () => {
|
|
8
|
+
const defaultConversations = ref([{
|
|
9
|
+
key: "session_1",
|
|
10
|
+
label: "Session 1"
|
|
11
|
+
}, {
|
|
12
|
+
key: "session_2",
|
|
13
|
+
label: "Session 2"
|
|
14
|
+
}]);
|
|
15
|
+
const defaultActiveConversationKey = ref("session_1");
|
|
16
|
+
const scope = effectScope();
|
|
17
|
+
const conversationsHandler = scope.run(() => useXConversations({
|
|
18
|
+
defaultConversations,
|
|
19
|
+
defaultActiveConversationKey
|
|
20
|
+
}));
|
|
21
|
+
globalExpect(conversationsHandler).toBeTruthy();
|
|
22
|
+
if (!conversationsHandler) return;
|
|
23
|
+
globalExpect(conversationsHandler.conversations.value.map((item) => item.key)).toEqual(["session_1", "session_2"]);
|
|
24
|
+
globalExpect(conversationsHandler.activeConversationKey.value).toBe("session_1");
|
|
25
|
+
defaultConversations.value = [{
|
|
26
|
+
key: "session_3",
|
|
27
|
+
label: "Session 3"
|
|
28
|
+
}];
|
|
29
|
+
defaultActiveConversationKey.value = "session_3";
|
|
30
|
+
await nextTick();
|
|
31
|
+
globalExpect(conversationsHandler.conversations.value.map((item) => item.key)).toEqual(["session_3"]);
|
|
32
|
+
globalExpect(conversationsHandler.activeConversationKey.value).toBe("session_3");
|
|
33
|
+
scope.stop();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
//#endregion
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { MaybeRef } from 'vue';
|
|
1
2
|
import { AnyObject } from '../_util/types';
|
|
2
3
|
export interface ConversationData extends AnyObject {
|
|
3
4
|
key: string;
|
|
4
5
|
}
|
|
5
|
-
interface XConversationConfig {
|
|
6
|
-
defaultConversations?: ConversationData[]
|
|
7
|
-
defaultActiveConversationKey?: string
|
|
6
|
+
export interface XConversationConfig {
|
|
7
|
+
defaultConversations?: MaybeRef<ConversationData[]>;
|
|
8
|
+
defaultActiveConversationKey?: MaybeRef<string>;
|
|
8
9
|
}
|
|
9
10
|
export default function useXConversations(config: XConversationConfig): {
|
|
10
11
|
conversations: import('vue').ShallowRef<ConversationData[], ConversationData[]>;
|
|
@@ -17,4 +18,3 @@ export default function useXConversations(config: XConversationConfig): {
|
|
|
17
18
|
setConversations: (list: ConversationData[]) => boolean;
|
|
18
19
|
getMessages: (key: ConversationData["key"]) => any[] | undefined;
|
|
19
20
|
};
|
|
20
|
-
export {};
|
|
@@ -1,2 +1,38 @@
|
|
|
1
|
-
import
|
|
1
|
+
import resolveMaybeRef from "../_util/resolveMaybeRef.js";
|
|
2
|
+
import { ConversationStore } from "./store.js";
|
|
3
|
+
import { isRef, onScopeDispose, ref, shallowRef, watch } from "vue";
|
|
4
|
+
//#region src/x-conversations/index.ts
|
|
5
|
+
function useXConversations(config) {
|
|
6
|
+
const store = new ConversationStore(resolveMaybeRef(config?.defaultConversations) || [], resolveMaybeRef(config?.defaultActiveConversationKey) || "");
|
|
7
|
+
const conversations = shallowRef(store.getSnapshot());
|
|
8
|
+
const activeConversationKey = ref(store.getActiveConversationKey());
|
|
9
|
+
const syncStore = () => {
|
|
10
|
+
conversations.value = store.getSnapshot();
|
|
11
|
+
activeConversationKey.value = store.getActiveConversationKey();
|
|
12
|
+
};
|
|
13
|
+
const unsubscribe = store.subscribe(syncStore);
|
|
14
|
+
syncStore();
|
|
15
|
+
if (config?.defaultConversations && isRef(config.defaultConversations)) watch(config.defaultConversations, (list) => {
|
|
16
|
+
store.setConversations(list || []);
|
|
17
|
+
}, { deep: true });
|
|
18
|
+
if (config?.defaultActiveConversationKey && isRef(config.defaultActiveConversationKey)) watch(config.defaultActiveConversationKey, (key) => {
|
|
19
|
+
if (typeof key === "string") store.setActiveConversationKey(key);
|
|
20
|
+
});
|
|
21
|
+
onScopeDispose(() => {
|
|
22
|
+
unsubscribe();
|
|
23
|
+
store.destroy();
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
conversations,
|
|
27
|
+
activeConversationKey,
|
|
28
|
+
setActiveConversationKey: store.setActiveConversationKey,
|
|
29
|
+
addConversation: store.addConversation,
|
|
30
|
+
removeConversation: store.removeConversation,
|
|
31
|
+
setConversation: store.setConversation,
|
|
32
|
+
getConversation: store.getConversation,
|
|
33
|
+
setConversations: store.setConversations,
|
|
34
|
+
getMessages: store.getMessages
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
2
38
|
export { useXConversations as default };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { onScopeDispose, ref, shallowRef } from "vue";
|
|
1
|
+
import { chatMessagesStoreHelper } from "../x-chat/store.js";
|
|
3
2
|
//#region src/x-conversations/store.ts
|
|
4
3
|
var conversationStoreHelper = {
|
|
5
4
|
_allConversationStores: /* @__PURE__ */ new Map(),
|
|
@@ -91,32 +90,4 @@ var ConversationStore = class {
|
|
|
91
90
|
};
|
|
92
91
|
};
|
|
93
92
|
//#endregion
|
|
94
|
-
|
|
95
|
-
function useXConversations(config) {
|
|
96
|
-
const store = new ConversationStore(config?.defaultConversations || [], config?.defaultActiveConversationKey || "");
|
|
97
|
-
const conversations = shallowRef(store.getSnapshot());
|
|
98
|
-
const activeConversationKey = ref(store.getActiveConversationKey());
|
|
99
|
-
const syncStore = () => {
|
|
100
|
-
conversations.value = store.getSnapshot();
|
|
101
|
-
activeConversationKey.value = store.getActiveConversationKey();
|
|
102
|
-
};
|
|
103
|
-
const unsubscribe = store.subscribe(syncStore);
|
|
104
|
-
syncStore();
|
|
105
|
-
onScopeDispose(() => {
|
|
106
|
-
unsubscribe();
|
|
107
|
-
store.destroy();
|
|
108
|
-
});
|
|
109
|
-
return {
|
|
110
|
-
conversations,
|
|
111
|
-
activeConversationKey,
|
|
112
|
-
setActiveConversationKey: store.setActiveConversationKey,
|
|
113
|
-
addConversation: store.addConversation,
|
|
114
|
-
removeConversation: store.removeConversation,
|
|
115
|
-
setConversation: store.setConversation,
|
|
116
|
-
getConversation: store.getConversation,
|
|
117
|
-
setConversations: store.setConversations,
|
|
118
|
-
getMessages: store.getMessages
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
//#endregion
|
|
122
|
-
export { useXConversations as t };
|
|
93
|
+
export { ConversationStore, conversationStoreHelper };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import XRequest from "../index.js";
|
|
2
|
+
import { h as describe, m as it } from "../../node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/runner/chunk-artifact.js";
|
|
3
|
+
import { g as globalExpect, v as vi } from "../../node_modules/.pnpm/@voidzero-dev_vite-plus-test@0.1.14_@types_node@24.12.0_@voidzero-dev_vite-plus-core@0._0c620f79340a656256b2ffe23b3e6dd1/node_modules/@voidzero-dev/vite-plus-test/dist/chunks/test.CBQUpOM3.js";
|
|
4
|
+
import { ref } from "vue";
|
|
5
|
+
//#region src/x-request/__tests__/index.test.ts
|
|
6
|
+
describe("XRequest", () => {
|
|
7
|
+
it("uses reactive baseURL / params / headers refs on each run", async () => {
|
|
8
|
+
const baseURL = ref("https://example.com/api/v1");
|
|
9
|
+
const params = ref({ a: 1 });
|
|
10
|
+
const headers = ref({ Authorization: "Bearer token-1" });
|
|
11
|
+
const fetchMock = vi.fn(async (_url, _options) => {
|
|
12
|
+
return new Response(JSON.stringify({ success: true }), {
|
|
13
|
+
status: 200,
|
|
14
|
+
headers: { "content-type": "application/json" }
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
const request = XRequest(baseURL, {
|
|
18
|
+
manual: true,
|
|
19
|
+
params,
|
|
20
|
+
headers,
|
|
21
|
+
fetch: fetchMock
|
|
22
|
+
});
|
|
23
|
+
request.run({ b: 2 });
|
|
24
|
+
await request.asyncHandler;
|
|
25
|
+
globalExpect(fetchMock).toHaveBeenCalledTimes(1);
|
|
26
|
+
const firstCall = fetchMock.mock.calls[0];
|
|
27
|
+
const firstUrl = firstCall[0];
|
|
28
|
+
const firstOptions = firstCall[1];
|
|
29
|
+
globalExpect(firstUrl).toBe("https://example.com/api/v1");
|
|
30
|
+
globalExpect(JSON.parse(firstOptions.body)).toEqual({
|
|
31
|
+
a: 1,
|
|
32
|
+
b: 2
|
|
33
|
+
});
|
|
34
|
+
globalExpect(firstOptions.headers.Authorization).toBe("Bearer token-1");
|
|
35
|
+
baseURL.value = "https://example.com/api/v2";
|
|
36
|
+
params.value = { a: 3 };
|
|
37
|
+
headers.value = { Authorization: "Bearer token-2" };
|
|
38
|
+
request.run({ b: 4 });
|
|
39
|
+
await request.asyncHandler;
|
|
40
|
+
globalExpect(fetchMock).toHaveBeenCalledTimes(2);
|
|
41
|
+
const secondCall = fetchMock.mock.calls[1];
|
|
42
|
+
const secondUrl = secondCall[0];
|
|
43
|
+
const secondOptions = secondCall[1];
|
|
44
|
+
globalExpect(secondUrl).toBe("https://example.com/api/v2");
|
|
45
|
+
globalExpect(JSON.parse(secondOptions.body)).toEqual({
|
|
46
|
+
a: 3,
|
|
47
|
+
b: 4
|
|
48
|
+
});
|
|
49
|
+
globalExpect(secondOptions.headers.Authorization).toBe("Bearer token-2");
|
|
50
|
+
});
|
|
51
|
+
it("tracks reactive manual option", () => {
|
|
52
|
+
const manual = ref(true);
|
|
53
|
+
const request = XRequest("https://example.com/manual", {
|
|
54
|
+
manual,
|
|
55
|
+
fetch: vi.fn()
|
|
56
|
+
});
|
|
57
|
+
globalExpect(request.manual).toBe(true);
|
|
58
|
+
manual.value = false;
|
|
59
|
+
globalExpect(request.manual).toBe(false);
|
|
60
|
+
manual.value = true;
|
|
61
|
+
globalExpect(request.manual).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
it("supports plain middlewares object", async () => {
|
|
64
|
+
const onRequest = vi.fn(async (baseURL, options) => {
|
|
65
|
+
return [`${baseURL.toString()}?mw=1`, options];
|
|
66
|
+
});
|
|
67
|
+
const onResponse = vi.fn(async (response) => response);
|
|
68
|
+
const fetchMock = vi.fn(async (_url) => {
|
|
69
|
+
return new Response(JSON.stringify({ success: true }), {
|
|
70
|
+
status: 200,
|
|
71
|
+
headers: { "content-type": "application/json" }
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
const request = XRequest("https://example.com/middlewares", {
|
|
75
|
+
manual: true,
|
|
76
|
+
fetch: fetchMock,
|
|
77
|
+
middlewares: {
|
|
78
|
+
onRequest,
|
|
79
|
+
onResponse
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
request.run();
|
|
83
|
+
await request.asyncHandler;
|
|
84
|
+
globalExpect(onRequest).toHaveBeenCalledTimes(1);
|
|
85
|
+
globalExpect(onResponse).toHaveBeenCalledTimes(1);
|
|
86
|
+
globalExpect(fetchMock).toHaveBeenCalledTimes(1);
|
|
87
|
+
globalExpect(fetchMock.mock.calls[0]?.[0]).toBe("https://example.com/middlewares?mw=1");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//#endregion
|