@red-hat-developer-hub/backstage-plugin-lightspeed 2.5.0 → 2.6.0
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/CHANGELOG.md +16 -0
- package/README.md +6 -2
- package/dist/alpha.d.ts +5 -0
- package/dist/components/LightSpeedChat.esm.js +92 -21
- package/dist/components/LightSpeedChat.esm.js.map +1 -1
- package/dist/components/LightspeedDrawerContext.esm.js.map +1 -1
- package/dist/components/notebooks/AddDocumentModal.esm.js +122 -23
- package/dist/components/notebooks/AddDocumentModal.esm.js.map +1 -1
- package/dist/components/notebooks/DocumentSidebar.esm.js +19 -1
- package/dist/components/notebooks/DocumentSidebar.esm.js.map +1 -1
- package/dist/components/notebooks/FileListItem.esm.js +94 -0
- package/dist/components/notebooks/FileListItem.esm.js.map +1 -0
- package/dist/components/notebooks/NotebookView.esm.js +46 -26
- package/dist/components/notebooks/NotebookView.esm.js.map +1 -1
- package/dist/components/notebooks/OverwriteConfirmModal.esm.js +2 -1
- package/dist/components/notebooks/OverwriteConfirmModal.esm.js.map +1 -1
- package/dist/components/notebooks/SidebarCollapseIcon.esm.js +5 -2
- package/dist/components/notebooks/SidebarCollapseIcon.esm.js.map +1 -1
- package/dist/hooks/toolCallsCacheStore.esm.js +61 -0
- package/dist/hooks/toolCallsCacheStore.esm.js.map +1 -0
- package/dist/hooks/useConversationMessages.esm.js +359 -325
- package/dist/hooks/useConversationMessages.esm.js.map +1 -1
- package/dist/hooks/useDeleteConversation.esm.js +2 -0
- package/dist/hooks/useDeleteConversation.esm.js.map +1 -1
- package/dist/hooks/useLightspeedProviderState.esm.js +35 -8
- package/dist/hooks/useLightspeedProviderState.esm.js.map +1 -1
- package/dist/translations/de.esm.js +5 -0
- package/dist/translations/de.esm.js.map +1 -1
- package/dist/translations/es.esm.js +5 -0
- package/dist/translations/es.esm.js.map +1 -1
- package/dist/translations/fr.esm.js +5 -0
- package/dist/translations/fr.esm.js.map +1 -1
- package/dist/translations/it.esm.js +5 -0
- package/dist/translations/it.esm.js.map +1 -1
- package/dist/translations/ja.esm.js +5 -0
- package/dist/translations/ja.esm.js.map +1 -1
- package/dist/translations/ref.esm.js +5 -0
- package/dist/translations/ref.esm.js.map +1 -1
- package/package.json +2 -2
|
@@ -6,6 +6,7 @@ import { TEMP_CONVERSATION_ID } from '../const.esm.js';
|
|
|
6
6
|
import botAvatar from '../images/bot-avatar.svg';
|
|
7
7
|
import userAvatar from '../images/user-avatar.svg';
|
|
8
8
|
import { getConversationsData, createUserMessage, createBotMessage, transformDocumentsToSources, getTimestamp } from '../utils/lightspeed-chatbox-utils.esm.js';
|
|
9
|
+
import { getSharedToolCallsCache, setSharedToolCallsCache, migrateSharedToolCallsCacheSessionPrefixToConversation, clearSharedToolCallsCacheSessionPrefix } from './toolCallsCacheStore.esm.js';
|
|
9
10
|
import { useCreateConversationMessage } from './useCreateCoversationMessage.esm.js';
|
|
10
11
|
|
|
11
12
|
const toolCallIdKey = (id) => {
|
|
@@ -18,6 +19,11 @@ const isMcpStyleToolCallPayload = (data) => {
|
|
|
18
19
|
const isLegacyToolResultToken = (token) => {
|
|
19
20
|
return !!token && typeof token === "object" && !Array.isArray(token) && typeof token.tool_name === "string" && token.tool_name.length > 0;
|
|
20
21
|
};
|
|
22
|
+
let tempToolCallsCachePrefixFallbackSeq = 0;
|
|
23
|
+
function createTempToolCallsCacheSessionPrefix() {
|
|
24
|
+
const suffix = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${++tempToolCallsCachePrefixFallbackSeq}`;
|
|
25
|
+
return `lightspeed-temp:${suffix}`;
|
|
26
|
+
}
|
|
21
27
|
const legacyToolResultToString = (response) => {
|
|
22
28
|
if (!response) return "";
|
|
23
29
|
if (typeof response === "string") return response;
|
|
@@ -49,13 +55,17 @@ const useConversationMessages = (conversationId, userName, selectedModel, select
|
|
|
49
55
|
const streamingConversations = useRef({
|
|
50
56
|
[currentConversation]: []
|
|
51
57
|
});
|
|
58
|
+
const isTempStreamInProgressRef = useRef(false);
|
|
59
|
+
const [streamingConversationId, setStreamingConversationId] = useState(null);
|
|
52
60
|
const pendingToolCalls = useRef({});
|
|
53
|
-
const toolCallsCache = useRef({});
|
|
54
61
|
useEffect(() => {
|
|
55
62
|
if (currentConversation !== conversationId) {
|
|
56
63
|
setCurrentConversation(conversationId);
|
|
57
64
|
setConversations((prev) => {
|
|
58
65
|
if (conversationId === TEMP_CONVERSATION_ID) {
|
|
66
|
+
if (isTempStreamInProgressRef.current && (prev[TEMP_CONVERSATION_ID]?.length ?? 0) > 0) {
|
|
67
|
+
return prev;
|
|
68
|
+
}
|
|
59
69
|
return { ...prev, [TEMP_CONVERSATION_ID]: [] };
|
|
60
70
|
}
|
|
61
71
|
if (prev[conversationId]) return prev;
|
|
@@ -95,7 +105,7 @@ const useConversationMessages = (conversationId, userName, selectedModel, select
|
|
|
95
105
|
)
|
|
96
106
|
});
|
|
97
107
|
const cacheKey = `${currentConversation}-${i}`;
|
|
98
|
-
const cachedToolCalls =
|
|
108
|
+
const cachedToolCalls = getSharedToolCallsCache(cacheKey);
|
|
99
109
|
if (cachedToolCalls && cachedToolCalls.length > 0) {
|
|
100
110
|
botMsg.toolCalls = cachedToolCalls;
|
|
101
111
|
}
|
|
@@ -106,7 +116,10 @@ const useConversationMessages = (conversationId, userName, selectedModel, select
|
|
|
106
116
|
...streamingConversations.current[currentConversation]
|
|
107
117
|
);
|
|
108
118
|
}
|
|
109
|
-
setConversations(
|
|
119
|
+
setConversations((prev) => ({
|
|
120
|
+
...prev,
|
|
121
|
+
..._conversations
|
|
122
|
+
}));
|
|
110
123
|
}
|
|
111
124
|
}, [
|
|
112
125
|
conversationsData,
|
|
@@ -118,116 +131,254 @@ const useConversationMessages = (conversationId, userName, selectedModel, select
|
|
|
118
131
|
]);
|
|
119
132
|
const handleInputPrompt = useCallback(
|
|
120
133
|
async (prompt, attachments = []) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
avatar,
|
|
126
|
-
name: userName,
|
|
127
|
-
content: prompt,
|
|
128
|
-
timestamp: getTimestamp(Date.now()) ?? ""
|
|
129
|
-
}),
|
|
130
|
-
createBotMessage({
|
|
131
|
-
avatar: botAvatar,
|
|
132
|
-
isLoading: true,
|
|
133
|
-
name: selectedModel,
|
|
134
|
-
content: "",
|
|
135
|
-
timestamp: ""
|
|
136
|
-
})
|
|
137
|
-
];
|
|
138
|
-
streamingConversations.current = {
|
|
139
|
-
...streamingConversations.current,
|
|
140
|
-
[currentConversation]: conversationTuple
|
|
141
|
-
};
|
|
142
|
-
setConversations((prevConv) => {
|
|
143
|
-
return {
|
|
144
|
-
...prevConv,
|
|
145
|
-
[currentConversation]: [
|
|
146
|
-
...prevConv?.[currentConversation] ?? [],
|
|
147
|
-
...conversationTuple
|
|
148
|
-
]
|
|
149
|
-
};
|
|
150
|
-
});
|
|
151
|
-
setTimeout(() => {
|
|
152
|
-
scrollToBottomRef.current?.scrollToBottom();
|
|
153
|
-
}, 0);
|
|
154
|
-
const finalMessages = [];
|
|
155
|
-
let buffer = "";
|
|
134
|
+
const streamStartedOnTemp = currentConversation === TEMP_CONVERSATION_ID;
|
|
135
|
+
if (streamStartedOnTemp) {
|
|
136
|
+
isTempStreamInProgressRef.current = true;
|
|
137
|
+
}
|
|
156
138
|
try {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
139
|
+
let newConversationId = "";
|
|
140
|
+
let requestId = "";
|
|
141
|
+
setStreamingConversationId(currentConversation);
|
|
142
|
+
const toolCallsCacheKeyPrefix = currentConversation === TEMP_CONVERSATION_ID ? createTempToolCallsCacheSessionPrefix() : currentConversation;
|
|
143
|
+
const conversationTuple = [
|
|
144
|
+
createUserMessage({
|
|
145
|
+
avatar,
|
|
146
|
+
name: userName,
|
|
147
|
+
content: prompt,
|
|
148
|
+
timestamp: getTimestamp(Date.now()) ?? ""
|
|
149
|
+
}),
|
|
150
|
+
createBotMessage({
|
|
151
|
+
avatar: botAvatar,
|
|
152
|
+
isLoading: true,
|
|
153
|
+
name: selectedModel,
|
|
154
|
+
content: "",
|
|
155
|
+
timestamp: ""
|
|
156
|
+
})
|
|
157
|
+
];
|
|
158
|
+
streamingConversations.current = {
|
|
159
|
+
...streamingConversations.current,
|
|
160
|
+
[currentConversation]: conversationTuple
|
|
161
|
+
};
|
|
162
|
+
setConversations((prevConv) => {
|
|
163
|
+
return {
|
|
164
|
+
...prevConv,
|
|
165
|
+
[currentConversation]: [
|
|
166
|
+
...prevConv?.[currentConversation] ?? [],
|
|
167
|
+
...conversationTuple
|
|
168
|
+
]
|
|
169
|
+
};
|
|
163
170
|
});
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
171
|
+
setTimeout(() => {
|
|
172
|
+
scrollToBottomRef.current?.scrollToBottom();
|
|
173
|
+
}, 0);
|
|
174
|
+
const finalMessages = [];
|
|
175
|
+
let buffer = "";
|
|
176
|
+
try {
|
|
177
|
+
const reader = await createMessage({
|
|
178
|
+
prompt,
|
|
179
|
+
selectedModel,
|
|
180
|
+
selectedProvider,
|
|
181
|
+
currentConversation,
|
|
182
|
+
attachments
|
|
183
|
+
});
|
|
184
|
+
const decoder = new TextDecoder("utf-8");
|
|
185
|
+
let streamEnded = false;
|
|
186
|
+
while (!streamEnded) {
|
|
187
|
+
const { value, done } = await reader.read();
|
|
188
|
+
if (done) {
|
|
189
|
+
streamEnded = true;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
buffer += decoder.decode(value, { stream: true });
|
|
193
|
+
const parts = buffer.split("\n\n");
|
|
194
|
+
buffer = parts.pop();
|
|
195
|
+
for (const part of parts) {
|
|
196
|
+
const lines = part.split("\n").filter((line) => line.startsWith("data:"));
|
|
197
|
+
const jsonString = lines.map((line) => line.trim().slice(5).trim()).join("");
|
|
198
|
+
try {
|
|
199
|
+
const { event, data } = JSON.parse(jsonString);
|
|
200
|
+
if (event === "start") {
|
|
201
|
+
requestId = data?.request_id;
|
|
202
|
+
onRequestIdReady?.(requestId);
|
|
203
|
+
if (currentConversation === TEMP_CONVERSATION_ID) {
|
|
204
|
+
newConversationId = data?.conversation_id;
|
|
205
|
+
}
|
|
185
206
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
207
|
+
if (event === "tool_call") {
|
|
208
|
+
const toolCallData = data?.token;
|
|
209
|
+
const legacyObjectCall = typeof toolCallData === "object" && toolCallData !== null && !Array.isArray(toolCallData) && toolCallData.tool_name;
|
|
210
|
+
const mcpStyle = isMcpStyleToolCallPayload(data);
|
|
211
|
+
const rawArgs = data?.args ?? data?.arguments;
|
|
212
|
+
const mcpArgs = rawArgs && typeof rawArgs === "object" && !Array.isArray(rawArgs) ? rawArgs : {};
|
|
213
|
+
let toolCall;
|
|
214
|
+
if (legacyObjectCall && data.id !== null) {
|
|
215
|
+
toolCall = {
|
|
216
|
+
id: data.id,
|
|
217
|
+
toolName: toolCallData.tool_name,
|
|
218
|
+
arguments: toolCallData.arguments || {},
|
|
219
|
+
startTime: Date.now(),
|
|
220
|
+
isLoading: true
|
|
221
|
+
};
|
|
222
|
+
} else if (mcpStyle) {
|
|
223
|
+
toolCall = {
|
|
224
|
+
id: data.id,
|
|
225
|
+
toolName: data.name.trim(),
|
|
226
|
+
description: typeof data.type === "string" && data.type !== data.name ? data.type : void 0,
|
|
227
|
+
arguments: mcpArgs,
|
|
228
|
+
startTime: Date.now(),
|
|
229
|
+
isLoading: true
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (toolCall && data.id !== null) {
|
|
233
|
+
const newToolCall = toolCall;
|
|
234
|
+
pendingToolCalls.current[toolCallIdKey(data.id)] = newToolCall;
|
|
235
|
+
setConversations((prevConversations) => {
|
|
236
|
+
const conversation = prevConversations[currentConversation] ?? [];
|
|
237
|
+
const lastMessageIndex = conversation.length - 1;
|
|
238
|
+
if (lastMessageIndex < 0) return prevConversations;
|
|
239
|
+
const lastMessage = { ...conversation[lastMessageIndex] };
|
|
240
|
+
const existingToolCalls = normalizeToolCalls(
|
|
241
|
+
lastMessage.toolCalls
|
|
242
|
+
);
|
|
243
|
+
const nextToolCalls = [
|
|
244
|
+
...existingToolCalls,
|
|
245
|
+
newToolCall
|
|
246
|
+
];
|
|
247
|
+
lastMessage.toolCalls = nextToolCalls;
|
|
248
|
+
const messageIndex = Math.floor(lastMessageIndex / 2);
|
|
249
|
+
const cacheKey = `${toolCallsCacheKeyPrefix}-${messageIndex}`;
|
|
250
|
+
setSharedToolCallsCache(cacheKey, nextToolCalls);
|
|
251
|
+
const updatedConversation = [
|
|
252
|
+
...conversation.slice(0, lastMessageIndex),
|
|
253
|
+
lastMessage
|
|
254
|
+
];
|
|
255
|
+
return {
|
|
256
|
+
...prevConversations,
|
|
257
|
+
[currentConversation]: updatedConversation
|
|
258
|
+
};
|
|
259
|
+
});
|
|
260
|
+
const [humanMessage, aiMessage] = streamingConversations.current[currentConversation] || [];
|
|
261
|
+
if (aiMessage) {
|
|
262
|
+
const existingStreamingToolCalls = normalizeToolCalls(
|
|
263
|
+
aiMessage.toolCalls
|
|
264
|
+
);
|
|
265
|
+
streamingConversations.current[currentConversation] = [
|
|
266
|
+
humanMessage,
|
|
267
|
+
{
|
|
268
|
+
...aiMessage,
|
|
269
|
+
toolCalls: [
|
|
270
|
+
...existingStreamingToolCalls,
|
|
271
|
+
newToolCall
|
|
272
|
+
]
|
|
273
|
+
}
|
|
274
|
+
];
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (event === "tool_result") {
|
|
279
|
+
const tokenResult = data?.token;
|
|
280
|
+
const legacyResult = isLegacyToolResultToken(tokenResult);
|
|
281
|
+
const mcpHasContent = data?.id !== null && data.content !== void 0 && !legacyResult;
|
|
282
|
+
let responsePayload;
|
|
283
|
+
let matchToolName;
|
|
284
|
+
let toolIdKey;
|
|
285
|
+
if (legacyResult) {
|
|
286
|
+
responsePayload = legacyToolResultToString(
|
|
287
|
+
tokenResult.response
|
|
288
|
+
);
|
|
289
|
+
matchToolName = tokenResult.tool_name;
|
|
290
|
+
toolIdKey = data?.id !== null ? toolCallIdKey(data.id) : void 0;
|
|
291
|
+
} else if (mcpHasContent) {
|
|
292
|
+
toolIdKey = toolCallIdKey(data.id);
|
|
293
|
+
responsePayload = typeof data.content === "string" ? data.content : JSON.stringify(data.content);
|
|
294
|
+
if (typeof data.status === "string" && data.status !== "success") {
|
|
295
|
+
responsePayload = `[${data.status}] ${responsePayload}`;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (responsePayload !== void 0 && toolIdKey !== void 0) {
|
|
299
|
+
const pendingCall = pendingToolCalls.current[toolIdKey];
|
|
300
|
+
const endTime = Date.now();
|
|
301
|
+
const executionTime = pendingCall ? (endTime - pendingCall.startTime) / 1e3 : 0;
|
|
302
|
+
setConversations((prevConversations) => {
|
|
303
|
+
const conversation = prevConversations[currentConversation] ?? [];
|
|
304
|
+
const lastMessageIndex = conversation.length - 1;
|
|
305
|
+
if (lastMessageIndex < 0) return prevConversations;
|
|
306
|
+
const lastMessage = { ...conversation[lastMessageIndex] };
|
|
307
|
+
const toolCalls = lastMessage.toolCalls || [];
|
|
308
|
+
const updatedToolCalls = toolCalls.map((tc) => {
|
|
309
|
+
const idMatches = toolCallIdKey(tc.id) === toolIdKey || matchToolName !== void 0 && tc.toolName === matchToolName;
|
|
310
|
+
if (idMatches) {
|
|
311
|
+
return {
|
|
312
|
+
...tc,
|
|
313
|
+
response: responsePayload,
|
|
314
|
+
endTime,
|
|
315
|
+
executionTime,
|
|
316
|
+
isLoading: false
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
return tc;
|
|
320
|
+
});
|
|
321
|
+
lastMessage.toolCalls = updatedToolCalls;
|
|
322
|
+
const messageIndex = Math.floor(lastMessageIndex / 2);
|
|
323
|
+
const cacheKey = `${toolCallsCacheKeyPrefix}-${messageIndex}`;
|
|
324
|
+
setSharedToolCallsCache(cacheKey, updatedToolCalls);
|
|
325
|
+
const updatedConversation = [
|
|
326
|
+
...conversation.slice(0, lastMessageIndex),
|
|
327
|
+
lastMessage
|
|
328
|
+
];
|
|
329
|
+
return {
|
|
330
|
+
...prevConversations,
|
|
331
|
+
[currentConversation]: updatedConversation
|
|
332
|
+
};
|
|
333
|
+
});
|
|
334
|
+
const [humanMessage, aiMessage] = streamingConversations.current[currentConversation] || [];
|
|
335
|
+
if (aiMessage) {
|
|
336
|
+
const toolCalls = aiMessage.toolCalls || [];
|
|
337
|
+
const updatedToolCalls = toolCalls.map((tc) => {
|
|
338
|
+
const idMatches = toolCallIdKey(tc.id) === toolIdKey || matchToolName !== void 0 && tc.toolName === matchToolName;
|
|
339
|
+
if (idMatches) {
|
|
340
|
+
return {
|
|
341
|
+
...tc,
|
|
342
|
+
response: responsePayload,
|
|
343
|
+
endTime,
|
|
344
|
+
executionTime,
|
|
345
|
+
isLoading: false
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
return tc;
|
|
349
|
+
});
|
|
350
|
+
streamingConversations.current[currentConversation] = [
|
|
351
|
+
humanMessage,
|
|
352
|
+
{ ...aiMessage, toolCalls: updatedToolCalls }
|
|
353
|
+
];
|
|
354
|
+
}
|
|
355
|
+
delete pendingToolCalls.current[toolIdKey];
|
|
356
|
+
}
|
|
211
357
|
}
|
|
212
|
-
if (
|
|
213
|
-
const
|
|
214
|
-
|
|
358
|
+
if (event === "token") {
|
|
359
|
+
const content = data?.token || "";
|
|
360
|
+
finalMessages.push(content);
|
|
361
|
+
const [humanMessage, aiMessage] = streamingConversations.current[currentConversation];
|
|
362
|
+
streamingConversations.current[currentConversation] = [
|
|
363
|
+
humanMessage,
|
|
364
|
+
{ ...aiMessage, content: aiMessage.content + content }
|
|
365
|
+
];
|
|
215
366
|
setConversations((prevConversations) => {
|
|
216
367
|
const conversation = prevConversations[currentConversation] ?? [];
|
|
217
368
|
const lastMessageIndex = conversation.length - 1;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
369
|
+
const lastMessage = conversation.length === 0 ? createBotMessage({
|
|
370
|
+
content: "",
|
|
371
|
+
timestamp: getTimestamp(Date.now())
|
|
372
|
+
}) : { ...conversation[lastMessageIndex] };
|
|
373
|
+
if ((lastMessage?.content ?? "").trim().length > 0) {
|
|
374
|
+
lastMessage.isLoading = false;
|
|
375
|
+
}
|
|
376
|
+
lastMessage.content += content;
|
|
377
|
+
lastMessage.name = data?.response_metadata?.model || selectedModel;
|
|
378
|
+
lastMessage.timestamp = getTimestamp(
|
|
379
|
+
// TODO: To be fixed in the query response
|
|
380
|
+
data?.response_metadata?.created_at || Date.now()
|
|
222
381
|
);
|
|
223
|
-
const nextToolCalls = [
|
|
224
|
-
...existingToolCalls,
|
|
225
|
-
newToolCall
|
|
226
|
-
];
|
|
227
|
-
lastMessage.toolCalls = nextToolCalls;
|
|
228
|
-
const messageIndex = Math.floor(lastMessageIndex / 2);
|
|
229
|
-
const cacheKey = `${currentConversation}-${messageIndex}`;
|
|
230
|
-
toolCallsCache.current[cacheKey] = nextToolCalls;
|
|
231
382
|
const updatedConversation = [
|
|
232
383
|
...conversation.slice(0, lastMessageIndex),
|
|
233
384
|
lastMessage
|
|
@@ -237,68 +388,22 @@ const useConversationMessages = (conversationId, userName, selectedModel, select
|
|
|
237
388
|
[currentConversation]: updatedConversation
|
|
238
389
|
};
|
|
239
390
|
});
|
|
240
|
-
const [humanMessage, aiMessage] = streamingConversations.current[currentConversation] || [];
|
|
241
|
-
if (aiMessage) {
|
|
242
|
-
const existingStreamingToolCalls = normalizeToolCalls(
|
|
243
|
-
aiMessage.toolCalls
|
|
244
|
-
);
|
|
245
|
-
streamingConversations.current[currentConversation] = [
|
|
246
|
-
humanMessage,
|
|
247
|
-
{
|
|
248
|
-
...aiMessage,
|
|
249
|
-
toolCalls: [...existingStreamingToolCalls, newToolCall]
|
|
250
|
-
}
|
|
251
|
-
];
|
|
252
|
-
}
|
|
253
391
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const legacyResult = isLegacyToolResultToken(tokenResult);
|
|
258
|
-
const mcpHasContent = data?.id !== null && data.content !== void 0 && !legacyResult;
|
|
259
|
-
let responsePayload;
|
|
260
|
-
let matchToolName;
|
|
261
|
-
let toolIdKey;
|
|
262
|
-
if (legacyResult) {
|
|
263
|
-
responsePayload = legacyToolResultToString(
|
|
264
|
-
tokenResult.response
|
|
265
|
-
);
|
|
266
|
-
matchToolName = tokenResult.tool_name;
|
|
267
|
-
toolIdKey = data?.id !== null ? toolCallIdKey(data.id) : void 0;
|
|
268
|
-
} else if (mcpHasContent) {
|
|
269
|
-
toolIdKey = toolCallIdKey(data.id);
|
|
270
|
-
responsePayload = typeof data.content === "string" ? data.content : JSON.stringify(data.content);
|
|
271
|
-
if (typeof data.status === "string" && data.status !== "success") {
|
|
272
|
-
responsePayload = `[${data.status}] ${responsePayload}`;
|
|
392
|
+
if (event === "interrupted") {
|
|
393
|
+
if (currentConversation === TEMP_CONVERSATION_ID && data?.conversation_id) {
|
|
394
|
+
newConversationId = data.conversation_id;
|
|
273
395
|
}
|
|
274
|
-
}
|
|
275
|
-
if (responsePayload !== void 0 && toolIdKey !== void 0) {
|
|
276
|
-
const pendingCall = pendingToolCalls.current[toolIdKey];
|
|
277
|
-
const endTime = Date.now();
|
|
278
|
-
const executionTime = pendingCall ? (endTime - pendingCall.startTime) / 1e3 : 0;
|
|
279
396
|
setConversations((prevConversations) => {
|
|
280
397
|
const conversation = prevConversations[currentConversation] ?? [];
|
|
281
398
|
const lastMessageIndex = conversation.length - 1;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
response: responsePayload,
|
|
291
|
-
endTime,
|
|
292
|
-
executionTime,
|
|
293
|
-
isLoading: false
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
return tc;
|
|
297
|
-
});
|
|
298
|
-
lastMessage.toolCalls = updatedToolCalls;
|
|
299
|
-
const messageIndex = Math.floor(lastMessageIndex / 2);
|
|
300
|
-
const cacheKey = `${currentConversation}-${messageIndex}`;
|
|
301
|
-
toolCallsCache.current[cacheKey] = updatedToolCalls;
|
|
399
|
+
const lastMessage = conversation.length === 0 ? createBotMessage({
|
|
400
|
+
content: "",
|
|
401
|
+
isLoading: false,
|
|
402
|
+
timestamp: getTimestamp(Date.now())
|
|
403
|
+
}) : {
|
|
404
|
+
...conversation[lastMessageIndex],
|
|
405
|
+
isLoading: false
|
|
406
|
+
};
|
|
302
407
|
const updatedConversation = [
|
|
303
408
|
...conversation.slice(0, lastMessageIndex),
|
|
304
409
|
lastMessage
|
|
@@ -308,177 +413,105 @@ const useConversationMessages = (conversationId, userName, selectedModel, select
|
|
|
308
413
|
[currentConversation]: updatedConversation
|
|
309
414
|
};
|
|
310
415
|
});
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
416
|
+
streamEnded = true;
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
if (event === "end") {
|
|
420
|
+
const documents = data?.referenced_documents || [];
|
|
421
|
+
setConversations((prevConversations) => {
|
|
422
|
+
const conversation = prevConversations[currentConversation] ?? [];
|
|
423
|
+
const lastMessageIndex = conversation.length - 1;
|
|
424
|
+
const lastMessage = conversation.length === 0 ? createBotMessage({
|
|
425
|
+
content: "",
|
|
426
|
+
isLoading: false,
|
|
427
|
+
timestamp: getTimestamp(Date.now())
|
|
428
|
+
}) : {
|
|
429
|
+
...conversation[lastMessageIndex],
|
|
430
|
+
isLoading: false
|
|
431
|
+
};
|
|
432
|
+
if (documents.length) {
|
|
433
|
+
lastMessage.sources = {
|
|
434
|
+
sources: documents.map((doc) => ({
|
|
435
|
+
title: doc.doc_title,
|
|
436
|
+
link: doc.doc_url,
|
|
437
|
+
body: doc.doc_description
|
|
438
|
+
}))
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
const updatedConversation = [
|
|
442
|
+
...conversation.slice(0, lastMessageIndex),
|
|
443
|
+
lastMessage
|
|
330
444
|
];
|
|
331
|
-
|
|
332
|
-
|
|
445
|
+
return {
|
|
446
|
+
...prevConversations,
|
|
447
|
+
[currentConversation]: updatedConversation
|
|
448
|
+
};
|
|
449
|
+
});
|
|
333
450
|
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const [humanMessage, aiMessage] = streamingConversations.current[currentConversation];
|
|
339
|
-
streamingConversations.current[currentConversation] = [
|
|
340
|
-
humanMessage,
|
|
341
|
-
{ ...aiMessage, content: aiMessage.content + content }
|
|
342
|
-
];
|
|
343
|
-
setConversations((prevConversations) => {
|
|
344
|
-
const conversation = prevConversations[currentConversation] ?? [];
|
|
345
|
-
const lastMessageIndex = conversation.length - 1;
|
|
346
|
-
const lastMessage = conversation.length === 0 ? createBotMessage({
|
|
347
|
-
content: "",
|
|
348
|
-
timestamp: getTimestamp(Date.now())
|
|
349
|
-
}) : { ...conversation[lastMessageIndex] };
|
|
350
|
-
if ((lastMessage?.content ?? "").trim().length > 0) {
|
|
351
|
-
lastMessage.isLoading = false;
|
|
352
|
-
}
|
|
353
|
-
lastMessage.content += content;
|
|
354
|
-
lastMessage.name = data?.response_metadata?.model || selectedModel;
|
|
355
|
-
lastMessage.timestamp = getTimestamp(
|
|
356
|
-
// TODO: To be fixed in the query response
|
|
357
|
-
data?.response_metadata?.created_at || Date.now()
|
|
358
|
-
);
|
|
359
|
-
const updatedConversation = [
|
|
360
|
-
...conversation.slice(0, lastMessageIndex),
|
|
361
|
-
lastMessage
|
|
362
|
-
];
|
|
363
|
-
return {
|
|
364
|
-
...prevConversations,
|
|
365
|
-
[currentConversation]: updatedConversation
|
|
366
|
-
};
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
if (event === "interrupted") {
|
|
370
|
-
if (currentConversation === TEMP_CONVERSATION_ID && data?.conversation_id) {
|
|
371
|
-
newConversationId = data.conversation_id;
|
|
451
|
+
} catch (error) {
|
|
452
|
+
console.warn("Error parsing JSON:", error);
|
|
453
|
+
if (typeof onComplete === "function") {
|
|
454
|
+
onComplete("Invalid JSON received");
|
|
372
455
|
}
|
|
373
|
-
setConversations((prevConversations) => {
|
|
374
|
-
const conversation = prevConversations[currentConversation] ?? [];
|
|
375
|
-
const lastMessageIndex = conversation.length - 1;
|
|
376
|
-
const lastMessage = conversation.length === 0 ? createBotMessage({
|
|
377
|
-
content: "",
|
|
378
|
-
isLoading: false,
|
|
379
|
-
timestamp: getTimestamp(Date.now())
|
|
380
|
-
}) : { ...conversation[lastMessageIndex], isLoading: false };
|
|
381
|
-
const updatedConversation = [
|
|
382
|
-
...conversation.slice(0, lastMessageIndex),
|
|
383
|
-
lastMessage
|
|
384
|
-
];
|
|
385
|
-
return {
|
|
386
|
-
...prevConversations,
|
|
387
|
-
[currentConversation]: updatedConversation
|
|
388
|
-
};
|
|
389
|
-
});
|
|
390
|
-
streamEnded = true;
|
|
391
|
-
break;
|
|
392
|
-
}
|
|
393
|
-
if (event === "end") {
|
|
394
|
-
const documents = data?.referenced_documents || [];
|
|
395
|
-
setConversations((prevConversations) => {
|
|
396
|
-
const conversation = prevConversations[currentConversation] ?? [];
|
|
397
|
-
const lastMessageIndex = conversation.length - 1;
|
|
398
|
-
const lastMessage = conversation.length === 0 ? createBotMessage({
|
|
399
|
-
content: "",
|
|
400
|
-
isLoading: false,
|
|
401
|
-
timestamp: getTimestamp(Date.now())
|
|
402
|
-
}) : { ...conversation[lastMessageIndex], isLoading: false };
|
|
403
|
-
if (documents.length) {
|
|
404
|
-
lastMessage.sources = {
|
|
405
|
-
sources: documents.map((doc) => ({
|
|
406
|
-
title: doc.doc_title,
|
|
407
|
-
link: doc.doc_url,
|
|
408
|
-
body: doc.doc_description
|
|
409
|
-
}))
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
const updatedConversation = [
|
|
413
|
-
...conversation.slice(0, lastMessageIndex),
|
|
414
|
-
lastMessage
|
|
415
|
-
];
|
|
416
|
-
return {
|
|
417
|
-
...prevConversations,
|
|
418
|
-
[currentConversation]: updatedConversation
|
|
419
|
-
};
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
} catch (error) {
|
|
423
|
-
console.warn("Error parsing JSON:", error);
|
|
424
|
-
if (typeof onComplete === "function") {
|
|
425
|
-
onComplete("Invalid JSON received");
|
|
426
456
|
}
|
|
427
457
|
}
|
|
458
|
+
if (streamEnded) break;
|
|
428
459
|
}
|
|
429
|
-
|
|
460
|
+
} catch (e) {
|
|
461
|
+
setConversations((prevConversations) => {
|
|
462
|
+
const conversation = prevConversations[currentConversation] ?? [];
|
|
463
|
+
const lastMessageIndex = conversation.length - 1;
|
|
464
|
+
const lastMessage = conversation.length === 0 ? createBotMessage({
|
|
465
|
+
content: "",
|
|
466
|
+
timestamp: getTimestamp(Date.now())
|
|
467
|
+
}) : { ...conversation[lastMessageIndex] };
|
|
468
|
+
lastMessage.isLoading = false;
|
|
469
|
+
lastMessage.content += e;
|
|
470
|
+
lastMessage.error = {
|
|
471
|
+
title: e.message
|
|
472
|
+
};
|
|
473
|
+
lastMessage.timestamp = getTimestamp(Date.now());
|
|
474
|
+
const updatedConversation = [
|
|
475
|
+
...conversation.slice(0, lastMessageIndex),
|
|
476
|
+
lastMessage
|
|
477
|
+
];
|
|
478
|
+
finalMessages.push(`${e}`);
|
|
479
|
+
return {
|
|
480
|
+
...prevConversations,
|
|
481
|
+
[newConversationId.length > 0 ? newConversationId : currentConversation]: updatedConversation
|
|
482
|
+
};
|
|
483
|
+
});
|
|
430
484
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const updatedConversation = [
|
|
446
|
-
...conversation.slice(0, lastMessageIndex),
|
|
447
|
-
lastMessage
|
|
448
|
-
];
|
|
449
|
-
finalMessages.push(`${e}`);
|
|
450
|
-
return {
|
|
451
|
-
...prevConversations,
|
|
452
|
-
[newConversationId.length > 0 ? newConversationId : currentConversation]: updatedConversation
|
|
453
|
-
};
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
streamingConversations.current[currentConversation] = [];
|
|
457
|
-
if (typeof onComplete === "function") {
|
|
458
|
-
onComplete(finalMessages.join(""));
|
|
459
|
-
}
|
|
460
|
-
if (currentConversation === TEMP_CONVERSATION_ID && newConversationId) {
|
|
461
|
-
Object.keys(toolCallsCache.current).forEach((key) => {
|
|
462
|
-
if (key.startsWith(`${TEMP_CONVERSATION_ID}-`)) {
|
|
463
|
-
const messageIndex = key.replace(`${TEMP_CONVERSATION_ID}-`, "");
|
|
464
|
-
const newKey = `${newConversationId}-${messageIndex}`;
|
|
465
|
-
toolCallsCache.current[newKey] = toolCallsCache.current[key];
|
|
466
|
-
delete toolCallsCache.current[key];
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
setConversations((prevConversations) => {
|
|
470
|
-
return {
|
|
471
|
-
...prevConversations,
|
|
472
|
-
[newConversationId]: prevConversations[TEMP_CONVERSATION_ID]
|
|
473
|
-
};
|
|
474
|
-
});
|
|
475
|
-
onStart?.(newConversationId);
|
|
476
|
-
setTimeout(() => {
|
|
477
|
-
setConversations((prev) => {
|
|
478
|
-
const { [TEMP_CONVERSATION_ID]: _, ...rest } = prev;
|
|
479
|
-
return rest;
|
|
485
|
+
streamingConversations.current[currentConversation] = [];
|
|
486
|
+
if (typeof onComplete === "function") {
|
|
487
|
+
onComplete(finalMessages.join(""));
|
|
488
|
+
}
|
|
489
|
+
if (currentConversation === TEMP_CONVERSATION_ID && newConversationId) {
|
|
490
|
+
migrateSharedToolCallsCacheSessionPrefixToConversation(
|
|
491
|
+
toolCallsCacheKeyPrefix,
|
|
492
|
+
newConversationId
|
|
493
|
+
);
|
|
494
|
+
setConversations((prevConversations) => {
|
|
495
|
+
return {
|
|
496
|
+
...prevConversations,
|
|
497
|
+
[newConversationId]: prevConversations[TEMP_CONVERSATION_ID]
|
|
498
|
+
};
|
|
480
499
|
});
|
|
481
|
-
|
|
500
|
+
onStart?.(newConversationId);
|
|
501
|
+
setTimeout(() => {
|
|
502
|
+
setConversations((prev) => {
|
|
503
|
+
const { [TEMP_CONVERSATION_ID]: _, ...rest } = prev;
|
|
504
|
+
return rest;
|
|
505
|
+
});
|
|
506
|
+
}, 0);
|
|
507
|
+
} else if (currentConversation === TEMP_CONVERSATION_ID) {
|
|
508
|
+
clearSharedToolCallsCacheSessionPrefix(toolCallsCacheKeyPrefix);
|
|
509
|
+
}
|
|
510
|
+
} finally {
|
|
511
|
+
if (streamStartedOnTemp) {
|
|
512
|
+
isTempStreamInProgressRef.current = false;
|
|
513
|
+
}
|
|
514
|
+
setStreamingConversationId(null);
|
|
482
515
|
}
|
|
483
516
|
},
|
|
484
517
|
[
|
|
@@ -498,6 +531,7 @@ const useConversationMessages = (conversationId, userName, selectedModel, select
|
|
|
498
531
|
handleInputPrompt,
|
|
499
532
|
conversations,
|
|
500
533
|
scrollToBottomRef,
|
|
534
|
+
streamingConversationId,
|
|
501
535
|
...queryProps
|
|
502
536
|
};
|
|
503
537
|
};
|