@xinghunm/ai-chat 1.3.2 → 1.4.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/README.md +86 -30
- package/dist/index.d.mts +72 -1
- package/dist/index.d.ts +72 -1
- package/dist/index.js +550 -83
- package/dist/index.mjs +550 -83
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/ai-chat/index.tsx
|
|
2
|
-
import { useEffect as
|
|
2
|
+
import { useEffect as useEffect11 } from "react";
|
|
3
3
|
import styled17 from "@emotion/styled";
|
|
4
4
|
import { ConfigProvider } from "@xinghunm/compass-ui";
|
|
5
5
|
|
|
@@ -53,7 +53,10 @@ var DEFAULT_AI_CHAT_LABELS = {
|
|
|
53
53
|
modelUnavailable: "No model available",
|
|
54
54
|
skillLoading: "Loading skills...",
|
|
55
55
|
skillEmpty: "No matching skills",
|
|
56
|
-
removeSkillAriaLabel: "Remove skill"
|
|
56
|
+
removeSkillAriaLabel: "Remove skill",
|
|
57
|
+
sessionHistoryLoading: "Loading conversations...",
|
|
58
|
+
sessionHistoryLoadFailed: "Failed to load conversations",
|
|
59
|
+
sessionHistoryEmpty: "No conversations yet"
|
|
57
60
|
};
|
|
58
61
|
|
|
59
62
|
// src/lib/chat-session.ts
|
|
@@ -81,6 +84,20 @@ var createDraftChatSession = ({
|
|
|
81
84
|
// src/store/chat-store.ts
|
|
82
85
|
var DEFAULT_CHAT_SESSION_TITLE = "New Chat";
|
|
83
86
|
var IMAGE_MESSAGE_SESSION_TITLE = "Image message";
|
|
87
|
+
var createHistoryMessagePaginationState = (page) => ({
|
|
88
|
+
previousCursor: page?.previousCursor ?? null,
|
|
89
|
+
hasMorePrevious: page?.hasMorePrevious ?? Boolean(page && page.previousCursor !== null),
|
|
90
|
+
isLoadingPrevious: false,
|
|
91
|
+
error: null
|
|
92
|
+
});
|
|
93
|
+
var normalizeHistoryMessages = (sessionId, messages) => messages.map((message) => ({ ...message, sessionId }));
|
|
94
|
+
var mergeOlderHistoryMessages = (sessionId, olderMessages, currentMessages) => {
|
|
95
|
+
const currentMessageIds = new Set(currentMessages.map((message) => message.id));
|
|
96
|
+
const uniqueOlderMessages = normalizeHistoryMessages(sessionId, olderMessages).filter(
|
|
97
|
+
(message) => !currentMessageIds.has(message.id)
|
|
98
|
+
);
|
|
99
|
+
return [...uniqueOlderMessages, ...currentMessages];
|
|
100
|
+
};
|
|
84
101
|
var resolveSessionTitleFromMessage = (message) => {
|
|
85
102
|
const trimmedContent = message.content.trim();
|
|
86
103
|
if (trimmedContent) {
|
|
@@ -183,6 +200,9 @@ var createChatStore = (initialState) => createStore((set, get) => ({
|
|
|
183
200
|
isStreamingBySession: {},
|
|
184
201
|
isStoppingBySession: {},
|
|
185
202
|
errorBySession: {},
|
|
203
|
+
sessionMessageLoadStatusBySession: {},
|
|
204
|
+
sessionMessageLoadErrorBySession: {},
|
|
205
|
+
historyMessagePaginationBySession: {},
|
|
186
206
|
// ---- Session management ------------------------------------------------
|
|
187
207
|
createSession: (session) => {
|
|
188
208
|
const state = get();
|
|
@@ -196,6 +216,15 @@ var createChatStore = (initialState) => createStore((set, get) => ({
|
|
|
196
216
|
const nextErrorBySession = { ...state.errorBySession };
|
|
197
217
|
const nextIsStreamingBySession = { ...state.isStreamingBySession };
|
|
198
218
|
const nextIsStoppingBySession = { ...state.isStoppingBySession };
|
|
219
|
+
const nextSessionMessageLoadStatusBySession = {
|
|
220
|
+
...state.sessionMessageLoadStatusBySession
|
|
221
|
+
};
|
|
222
|
+
const nextSessionMessageLoadErrorBySession = {
|
|
223
|
+
...state.sessionMessageLoadErrorBySession
|
|
224
|
+
};
|
|
225
|
+
const nextHistoryMessagePaginationBySession = {
|
|
226
|
+
...state.historyMessagePaginationBySession
|
|
227
|
+
};
|
|
199
228
|
const sid = session.sessionId;
|
|
200
229
|
if (nextMessagesBySession[sid] === void 0)
|
|
201
230
|
nextMessagesBySession[sid] = [];
|
|
@@ -205,13 +234,25 @@ var createChatStore = (initialState) => createStore((set, get) => ({
|
|
|
205
234
|
nextIsStreamingBySession[sid] = false;
|
|
206
235
|
if (nextIsStoppingBySession[sid] === void 0)
|
|
207
236
|
nextIsStoppingBySession[sid] = false;
|
|
237
|
+
if (nextSessionMessageLoadStatusBySession[sid] === void 0) {
|
|
238
|
+
nextSessionMessageLoadStatusBySession[sid] = "loaded";
|
|
239
|
+
}
|
|
240
|
+
if (nextSessionMessageLoadErrorBySession[sid] === void 0) {
|
|
241
|
+
nextSessionMessageLoadErrorBySession[sid] = null;
|
|
242
|
+
}
|
|
243
|
+
if (nextHistoryMessagePaginationBySession[sid] === void 0) {
|
|
244
|
+
nextHistoryMessagePaginationBySession[sid] = createHistoryMessagePaginationState();
|
|
245
|
+
}
|
|
208
246
|
set({
|
|
209
247
|
sessions: nextSessions,
|
|
210
248
|
activeSessionId: sid,
|
|
211
249
|
messagesBySession: nextMessagesBySession,
|
|
212
250
|
errorBySession: nextErrorBySession,
|
|
213
251
|
isStreamingBySession: nextIsStreamingBySession,
|
|
214
|
-
isStoppingBySession: nextIsStoppingBySession
|
|
252
|
+
isStoppingBySession: nextIsStoppingBySession,
|
|
253
|
+
sessionMessageLoadStatusBySession: nextSessionMessageLoadStatusBySession,
|
|
254
|
+
sessionMessageLoadErrorBySession: nextSessionMessageLoadErrorBySession,
|
|
255
|
+
historyMessagePaginationBySession: nextHistoryMessagePaginationBySession
|
|
215
256
|
});
|
|
216
257
|
},
|
|
217
258
|
startNewChat: () => {
|
|
@@ -266,6 +307,27 @@ var createChatStore = (initialState) => createStore((set, get) => ({
|
|
|
266
307
|
nextErrorBySession[nextSessionId] = nextErrorBySession[previousSessionId] ?? null;
|
|
267
308
|
delete nextErrorBySession[previousSessionId];
|
|
268
309
|
}
|
|
310
|
+
const nextSessionMessageLoadStatusBySession = {
|
|
311
|
+
...state.sessionMessageLoadStatusBySession
|
|
312
|
+
};
|
|
313
|
+
if (previousSessionId in nextSessionMessageLoadStatusBySession) {
|
|
314
|
+
nextSessionMessageLoadStatusBySession[nextSessionId] = nextSessionMessageLoadStatusBySession[previousSessionId] ?? "idle";
|
|
315
|
+
delete nextSessionMessageLoadStatusBySession[previousSessionId];
|
|
316
|
+
}
|
|
317
|
+
const nextSessionMessageLoadErrorBySession = {
|
|
318
|
+
...state.sessionMessageLoadErrorBySession
|
|
319
|
+
};
|
|
320
|
+
if (previousSessionId in nextSessionMessageLoadErrorBySession) {
|
|
321
|
+
nextSessionMessageLoadErrorBySession[nextSessionId] = nextSessionMessageLoadErrorBySession[previousSessionId] ?? null;
|
|
322
|
+
delete nextSessionMessageLoadErrorBySession[previousSessionId];
|
|
323
|
+
}
|
|
324
|
+
const nextHistoryMessagePaginationBySession = {
|
|
325
|
+
...state.historyMessagePaginationBySession
|
|
326
|
+
};
|
|
327
|
+
if (previousSessionId in nextHistoryMessagePaginationBySession) {
|
|
328
|
+
nextHistoryMessagePaginationBySession[nextSessionId] = nextHistoryMessagePaginationBySession[previousSessionId] ?? createHistoryMessagePaginationState();
|
|
329
|
+
delete nextHistoryMessagePaginationBySession[previousSessionId];
|
|
330
|
+
}
|
|
269
331
|
const nextActiveSessionId = state.activeSessionId === previousSessionId ? nextSessionId : state.activeSessionId;
|
|
270
332
|
set({
|
|
271
333
|
sessions: nextSessions,
|
|
@@ -274,6 +336,9 @@ var createChatStore = (initialState) => createStore((set, get) => ({
|
|
|
274
336
|
isStreamingBySession: nextIsStreamingBySession,
|
|
275
337
|
isStoppingBySession: nextIsStoppingBySession,
|
|
276
338
|
errorBySession: nextErrorBySession,
|
|
339
|
+
sessionMessageLoadStatusBySession: nextSessionMessageLoadStatusBySession,
|
|
340
|
+
sessionMessageLoadErrorBySession: nextSessionMessageLoadErrorBySession,
|
|
341
|
+
historyMessagePaginationBySession: nextHistoryMessagePaginationBySession,
|
|
277
342
|
activeSessionId: nextActiveSessionId
|
|
278
343
|
});
|
|
279
344
|
},
|
|
@@ -287,6 +352,61 @@ var createChatStore = (initialState) => createStore((set, get) => ({
|
|
|
287
352
|
);
|
|
288
353
|
set({ sessions: nextSessions });
|
|
289
354
|
},
|
|
355
|
+
hydrateHistorySessions: (sessions) => {
|
|
356
|
+
const state = get();
|
|
357
|
+
const localSessions = state.sessions.filter(
|
|
358
|
+
(session) => isDraftChatSessionId(session.sessionId)
|
|
359
|
+
);
|
|
360
|
+
const localSessionIds = new Set(localSessions.map((session) => session.sessionId));
|
|
361
|
+
const nextSessions = [
|
|
362
|
+
...localSessions,
|
|
363
|
+
...sessions.filter((session) => !localSessionIds.has(session.sessionId)).map((session) => ({
|
|
364
|
+
...session,
|
|
365
|
+
mode: session.mode ?? DEFAULT_CHAT_AGENT_MODE
|
|
366
|
+
}))
|
|
367
|
+
];
|
|
368
|
+
const nextMessagesBySession = { ...state.messagesBySession };
|
|
369
|
+
const nextErrorBySession = { ...state.errorBySession };
|
|
370
|
+
const nextIsStreamingBySession = { ...state.isStreamingBySession };
|
|
371
|
+
const nextIsStoppingBySession = { ...state.isStoppingBySession };
|
|
372
|
+
const nextSessionMessageLoadStatusBySession = {
|
|
373
|
+
...state.sessionMessageLoadStatusBySession
|
|
374
|
+
};
|
|
375
|
+
const nextSessionMessageLoadErrorBySession = {
|
|
376
|
+
...state.sessionMessageLoadErrorBySession
|
|
377
|
+
};
|
|
378
|
+
const nextHistoryMessagePaginationBySession = {
|
|
379
|
+
...state.historyMessagePaginationBySession
|
|
380
|
+
};
|
|
381
|
+
nextSessions.forEach((session) => {
|
|
382
|
+
const sid = session.sessionId;
|
|
383
|
+
if (nextErrorBySession[sid] === void 0)
|
|
384
|
+
nextErrorBySession[sid] = null;
|
|
385
|
+
if (nextIsStreamingBySession[sid] === void 0)
|
|
386
|
+
nextIsStreamingBySession[sid] = false;
|
|
387
|
+
if (nextIsStoppingBySession[sid] === void 0)
|
|
388
|
+
nextIsStoppingBySession[sid] = false;
|
|
389
|
+
if (nextSessionMessageLoadStatusBySession[sid] === void 0) {
|
|
390
|
+
nextSessionMessageLoadStatusBySession[sid] = "idle";
|
|
391
|
+
}
|
|
392
|
+
if (nextSessionMessageLoadErrorBySession[sid] === void 0) {
|
|
393
|
+
nextSessionMessageLoadErrorBySession[sid] = null;
|
|
394
|
+
}
|
|
395
|
+
if (nextHistoryMessagePaginationBySession[sid] === void 0) {
|
|
396
|
+
nextHistoryMessagePaginationBySession[sid] = createHistoryMessagePaginationState();
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
set({
|
|
400
|
+
sessions: nextSessions,
|
|
401
|
+
messagesBySession: nextMessagesBySession,
|
|
402
|
+
errorBySession: nextErrorBySession,
|
|
403
|
+
isStreamingBySession: nextIsStreamingBySession,
|
|
404
|
+
isStoppingBySession: nextIsStoppingBySession,
|
|
405
|
+
sessionMessageLoadStatusBySession: nextSessionMessageLoadStatusBySession,
|
|
406
|
+
sessionMessageLoadErrorBySession: nextSessionMessageLoadErrorBySession,
|
|
407
|
+
historyMessagePaginationBySession: nextHistoryMessagePaginationBySession
|
|
408
|
+
});
|
|
409
|
+
},
|
|
290
410
|
// ---- Message operations ------------------------------------------------
|
|
291
411
|
appendMessage: (sessionId, message) => {
|
|
292
412
|
const state = get();
|
|
@@ -313,6 +433,92 @@ var createChatStore = (initialState) => createStore((set, get) => ({
|
|
|
313
433
|
isStreamingBySession: nextIsStreamingBySession
|
|
314
434
|
});
|
|
315
435
|
},
|
|
436
|
+
hydrateHistorySessionMessages: (sessionId, messages) => {
|
|
437
|
+
const state = get();
|
|
438
|
+
set({
|
|
439
|
+
messagesBySession: {
|
|
440
|
+
...state.messagesBySession,
|
|
441
|
+
[sessionId]: normalizeHistoryMessages(sessionId, messages)
|
|
442
|
+
},
|
|
443
|
+
sessionMessageLoadStatusBySession: {
|
|
444
|
+
...state.sessionMessageLoadStatusBySession,
|
|
445
|
+
[sessionId]: "loaded"
|
|
446
|
+
},
|
|
447
|
+
sessionMessageLoadErrorBySession: {
|
|
448
|
+
...state.sessionMessageLoadErrorBySession,
|
|
449
|
+
[sessionId]: null
|
|
450
|
+
},
|
|
451
|
+
historyMessagePaginationBySession: {
|
|
452
|
+
...state.historyMessagePaginationBySession,
|
|
453
|
+
[sessionId]: createHistoryMessagePaginationState()
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
},
|
|
457
|
+
hydrateHistorySessionMessagesPage: (sessionId, page) => {
|
|
458
|
+
const state = get();
|
|
459
|
+
set({
|
|
460
|
+
messagesBySession: {
|
|
461
|
+
...state.messagesBySession,
|
|
462
|
+
[sessionId]: normalizeHistoryMessages(sessionId, page.messages)
|
|
463
|
+
},
|
|
464
|
+
sessionMessageLoadStatusBySession: {
|
|
465
|
+
...state.sessionMessageLoadStatusBySession,
|
|
466
|
+
[sessionId]: "loaded"
|
|
467
|
+
},
|
|
468
|
+
sessionMessageLoadErrorBySession: {
|
|
469
|
+
...state.sessionMessageLoadErrorBySession,
|
|
470
|
+
[sessionId]: null
|
|
471
|
+
},
|
|
472
|
+
historyMessagePaginationBySession: {
|
|
473
|
+
...state.historyMessagePaginationBySession,
|
|
474
|
+
[sessionId]: createHistoryMessagePaginationState(page)
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
},
|
|
478
|
+
prependHistorySessionMessagesPage: (sessionId, page) => {
|
|
479
|
+
const state = get();
|
|
480
|
+
set({
|
|
481
|
+
messagesBySession: {
|
|
482
|
+
...state.messagesBySession,
|
|
483
|
+
[sessionId]: mergeOlderHistoryMessages(
|
|
484
|
+
sessionId,
|
|
485
|
+
page.messages,
|
|
486
|
+
state.messagesBySession[sessionId] ?? []
|
|
487
|
+
)
|
|
488
|
+
},
|
|
489
|
+
historyMessagePaginationBySession: {
|
|
490
|
+
...state.historyMessagePaginationBySession,
|
|
491
|
+
[sessionId]: createHistoryMessagePaginationState(page)
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
},
|
|
495
|
+
setHistorySessionPreviousMessagesLoadStatus: (sessionId, isLoading, error2 = null) => {
|
|
496
|
+
const state = get();
|
|
497
|
+
const current = state.historyMessagePaginationBySession[sessionId] ?? createHistoryMessagePaginationState();
|
|
498
|
+
set({
|
|
499
|
+
historyMessagePaginationBySession: {
|
|
500
|
+
...state.historyMessagePaginationBySession,
|
|
501
|
+
[sessionId]: {
|
|
502
|
+
...current,
|
|
503
|
+
isLoadingPrevious: isLoading,
|
|
504
|
+
error: error2
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
},
|
|
509
|
+
setHistorySessionMessageLoadStatus: (sessionId, status, error2 = null) => {
|
|
510
|
+
const state = get();
|
|
511
|
+
set({
|
|
512
|
+
sessionMessageLoadStatusBySession: {
|
|
513
|
+
...state.sessionMessageLoadStatusBySession,
|
|
514
|
+
[sessionId]: status
|
|
515
|
+
},
|
|
516
|
+
sessionMessageLoadErrorBySession: {
|
|
517
|
+
...state.sessionMessageLoadErrorBySession,
|
|
518
|
+
[sessionId]: error2
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
},
|
|
316
522
|
startStreamingMessage: (sessionId, message) => {
|
|
317
523
|
const state = get();
|
|
318
524
|
set({
|
|
@@ -760,6 +966,10 @@ var AiChatProvider = (props) => {
|
|
|
760
966
|
handleQuestionnaireSubmit,
|
|
761
967
|
handleConfirmationSubmit,
|
|
762
968
|
messageRenderOrder,
|
|
969
|
+
historySessionList,
|
|
970
|
+
onLoadMoreSessions,
|
|
971
|
+
onSelectHistorySession,
|
|
972
|
+
onLoadMoreHistoryMessages,
|
|
763
973
|
enableImageAttachments = true,
|
|
764
974
|
children
|
|
765
975
|
} = props;
|
|
@@ -836,7 +1046,11 @@ var AiChatProvider = (props) => {
|
|
|
836
1046
|
handleConfirmationSubmit,
|
|
837
1047
|
messageRenderOrder,
|
|
838
1048
|
transformStreamPacket: defaultTransformStreamPacket,
|
|
839
|
-
enableImageAttachments
|
|
1049
|
+
enableImageAttachments,
|
|
1050
|
+
historySessionList,
|
|
1051
|
+
onLoadMoreSessions,
|
|
1052
|
+
onSelectHistorySession,
|
|
1053
|
+
onLoadMoreHistoryMessages
|
|
840
1054
|
}),
|
|
841
1055
|
[
|
|
842
1056
|
axiosInstance,
|
|
@@ -846,8 +1060,12 @@ var AiChatProvider = (props) => {
|
|
|
846
1060
|
enableImageAttachments,
|
|
847
1061
|
handleConfirmationSubmit,
|
|
848
1062
|
handleQuestionnaireSubmit,
|
|
1063
|
+
historySessionList,
|
|
849
1064
|
labels,
|
|
850
1065
|
messageRenderOrder,
|
|
1066
|
+
onLoadMoreSessions,
|
|
1067
|
+
onLoadMoreHistoryMessages,
|
|
1068
|
+
onSelectHistorySession,
|
|
851
1069
|
renderMessageBlock,
|
|
852
1070
|
sendRef,
|
|
853
1071
|
retryRef,
|
|
@@ -1291,6 +1509,14 @@ var createTimelineAnchorState = ({
|
|
|
1291
1509
|
timelineBlockAnchors: {},
|
|
1292
1510
|
visibleTimelineBlockKeys: {}
|
|
1293
1511
|
});
|
|
1512
|
+
var createInitialTimelineAnchorState = ({
|
|
1513
|
+
messageId
|
|
1514
|
+
}) => ({
|
|
1515
|
+
messageId,
|
|
1516
|
+
previousBlockKeys: [],
|
|
1517
|
+
timelineBlockAnchors: {},
|
|
1518
|
+
visibleTimelineBlockKeys: {}
|
|
1519
|
+
});
|
|
1294
1520
|
var timelineAnchorReducer = (state, action) => {
|
|
1295
1521
|
switch (action.type) {
|
|
1296
1522
|
case "reset-message":
|
|
@@ -1380,7 +1606,7 @@ var useTimelineBlockAnchors = ({
|
|
|
1380
1606
|
messageId: message.id,
|
|
1381
1607
|
currentBlockKeys: currentTimelineBlockKeys
|
|
1382
1608
|
},
|
|
1383
|
-
|
|
1609
|
+
createInitialTimelineAnchorState
|
|
1384
1610
|
);
|
|
1385
1611
|
const effectiveTimelineBlockAnchors = useMemo3(() => {
|
|
1386
1612
|
if (messageRenderOrder !== "timeline" || !isAssistantStreaming) {
|
|
@@ -3155,15 +3381,11 @@ var Bubble = styled7.article`
|
|
|
3155
3381
|
|
|
3156
3382
|
&[data-role='user'] {
|
|
3157
3383
|
width: auto;
|
|
3158
|
-
max-width:
|
|
3384
|
+
max-width: 100%;
|
|
3159
3385
|
margin-left: auto;
|
|
3160
|
-
padding:
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
border: 1px solid rgba(255, 255, 255, 0.07);
|
|
3164
|
-
box-shadow:
|
|
3165
|
-
inset 0 1px 0 rgba(255, 255, 255, 0.03),
|
|
3166
|
-
0 12px 30px rgba(0, 0, 0, 0.18);
|
|
3386
|
+
padding: 8px 12px;
|
|
3387
|
+
background: #282825;
|
|
3388
|
+
border-radius: 16px;
|
|
3167
3389
|
}
|
|
3168
3390
|
`;
|
|
3169
3391
|
var Header2 = styled7.div`
|
|
@@ -3495,6 +3717,7 @@ var HeroSubtitle = styled8.p`
|
|
|
3495
3717
|
// src/components/chat-thread/index.tsx
|
|
3496
3718
|
import { jsx as jsx10, jsxs as jsxs7 } from "@emotion/react/jsx-runtime";
|
|
3497
3719
|
var CHAT_THREAD_PINNED_THRESHOLD_PX = 32;
|
|
3720
|
+
var CHAT_THREAD_LOAD_PREVIOUS_THRESHOLD_PX = 80;
|
|
3498
3721
|
var isThreadPinnedToBottom = (container) => container.scrollHeight - container.clientHeight - container.scrollTop <= CHAT_THREAD_PINNED_THRESHOLD_PX;
|
|
3499
3722
|
var renderChatMessage = ({
|
|
3500
3723
|
message,
|
|
@@ -3568,9 +3791,13 @@ var ChatThreadView = ({
|
|
|
3568
3791
|
historyMessages,
|
|
3569
3792
|
streamingMessage,
|
|
3570
3793
|
error: error2,
|
|
3794
|
+
isLoadingPreviousMessages = false,
|
|
3795
|
+
previousMessagesError,
|
|
3571
3796
|
retryButtonLabel,
|
|
3572
3797
|
scrollToLatestLabel,
|
|
3798
|
+
sessionHistoryLoadingLabel,
|
|
3573
3799
|
onRetry,
|
|
3800
|
+
onLoadPreviousMessages,
|
|
3574
3801
|
onConfirmationSubmit,
|
|
3575
3802
|
onQuestionnaireSubmit,
|
|
3576
3803
|
renderMessageBlock
|
|
@@ -3581,11 +3808,11 @@ var ChatThreadView = ({
|
|
|
3581
3808
|
[historyMessages, streamingMessage]
|
|
3582
3809
|
);
|
|
3583
3810
|
const latestTurn = conversationTurns[conversationTurns.length - 1];
|
|
3584
|
-
const previousTurns = conversationTurns.slice(0, -1);
|
|
3585
3811
|
const latestUserMessageId = latestTurn?.userMessage?.id;
|
|
3586
3812
|
const latestHistoryMessage = historyMessages[historyMessages.length - 1];
|
|
3587
3813
|
const latestTurnRef = useRef5(null);
|
|
3588
3814
|
const reservedSpaceFrameRef = useRef5(null);
|
|
3815
|
+
const isLoadingPreviousRef = useRef5(false);
|
|
3589
3816
|
const isPinnedRef = useRef5(true);
|
|
3590
3817
|
const lastHistoryMessageIdRef = useRef5(latestHistoryMessage?.id);
|
|
3591
3818
|
const lastStreamingMessageIdRef = useRef5(streamingMessage?.id);
|
|
@@ -3632,17 +3859,45 @@ var ChatThreadView = ({
|
|
|
3632
3859
|
},
|
|
3633
3860
|
[markThreadPinned, scrollToBottom]
|
|
3634
3861
|
);
|
|
3862
|
+
const handleLoadPreviousMessages = useCallback3(async () => {
|
|
3863
|
+
const container = containerRef.current;
|
|
3864
|
+
if (!container || !onLoadPreviousMessages || isLoadingPreviousMessages) {
|
|
3865
|
+
return;
|
|
3866
|
+
}
|
|
3867
|
+
if (isLoadingPreviousRef.current) {
|
|
3868
|
+
return;
|
|
3869
|
+
}
|
|
3870
|
+
isLoadingPreviousRef.current = true;
|
|
3871
|
+
const previousScrollHeight = container.scrollHeight;
|
|
3872
|
+
const previousScrollTop = container.scrollTop;
|
|
3873
|
+
try {
|
|
3874
|
+
await onLoadPreviousMessages();
|
|
3875
|
+
} catch {
|
|
3876
|
+
return;
|
|
3877
|
+
} finally {
|
|
3878
|
+
isLoadingPreviousRef.current = false;
|
|
3879
|
+
}
|
|
3880
|
+
window.requestAnimationFrame(() => {
|
|
3881
|
+
const nextContainer = containerRef.current;
|
|
3882
|
+
if (!nextContainer)
|
|
3883
|
+
return;
|
|
3884
|
+
nextContainer.scrollTop = nextContainer.scrollHeight - previousScrollHeight + previousScrollTop;
|
|
3885
|
+
});
|
|
3886
|
+
}, [isLoadingPreviousMessages, onLoadPreviousMessages]);
|
|
3635
3887
|
const handleContainerScroll = useCallback3(() => {
|
|
3636
3888
|
const container = containerRef.current;
|
|
3637
3889
|
if (!container)
|
|
3638
3890
|
return;
|
|
3891
|
+
if (onLoadPreviousMessages && container.scrollTop <= CHAT_THREAD_LOAD_PREVIOUS_THRESHOLD_PX) {
|
|
3892
|
+
void handleLoadPreviousMessages();
|
|
3893
|
+
}
|
|
3639
3894
|
const nextPinned = isThreadPinnedToBottom(container);
|
|
3640
3895
|
isPinnedRef.current = nextPinned;
|
|
3641
3896
|
setIsDetached(!nextPinned);
|
|
3642
3897
|
if (nextPinned) {
|
|
3643
3898
|
setPendingNewMessageCount(0);
|
|
3644
3899
|
}
|
|
3645
|
-
}, []);
|
|
3900
|
+
}, [handleLoadPreviousMessages, onLoadPreviousMessages]);
|
|
3646
3901
|
useLayoutEffect3(() => {
|
|
3647
3902
|
const nextHistoryMessageId = latestHistoryMessage?.id;
|
|
3648
3903
|
if (lastHistoryMessageIdRef.current === nextHistoryMessageId) {
|
|
@@ -3770,54 +4025,44 @@ var ChatThreadView = ({
|
|
|
3770
4025
|
}, [latestTurn, scrollToBottom]);
|
|
3771
4026
|
return /* @__PURE__ */ jsxs7(ThreadViewport, { children: [
|
|
3772
4027
|
/* @__PURE__ */ jsxs7(Container, { ref: containerRef, "data-testid": "chat-thread", onScroll: handleContainerScroll, children: [
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
{
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
message,
|
|
3812
|
-
mode: activeSessionMode,
|
|
3813
|
-
onConfirmationSubmit,
|
|
3814
|
-
onQuestionnaireSubmit,
|
|
3815
|
-
renderMessageBlock
|
|
3816
|
-
}) }, message.id)),
|
|
3817
|
-
error2 ? renderErrorState({ error: error2, onRetry, retryButtonLabel }) : null
|
|
3818
|
-
]
|
|
3819
|
-
}
|
|
3820
|
-
) : null,
|
|
4028
|
+
isLoadingPreviousMessages ? /* @__PURE__ */ jsx10(PreviousMessagesStateRow, { "data-testid": "chat-thread-loading-previous", children: sessionHistoryLoadingLabel }) : null,
|
|
4029
|
+
previousMessagesError ? /* @__PURE__ */ jsx10(PreviousMessagesStateRow, { "data-testid": "chat-thread-load-previous-error", children: previousMessagesError }) : null,
|
|
4030
|
+
conversationTurns.map((turn, turnIndex) => {
|
|
4031
|
+
const isLatestTurn = turnIndex === conversationTurns.length - 1;
|
|
4032
|
+
return /* @__PURE__ */ jsxs7(
|
|
4033
|
+
ConversationTurn,
|
|
4034
|
+
{
|
|
4035
|
+
ref: isLatestTurn ? latestTurnRef : null,
|
|
4036
|
+
"data-testid": isLatestTurn ? "chat-thread-latest-turn" : "chat-thread-turn",
|
|
4037
|
+
style: isLatestTurn && latestTurnMinHeight > 0 ? { minHeight: `${latestTurnMinHeight}px` } : void 0,
|
|
4038
|
+
children: [
|
|
4039
|
+
turn.userMessage ? /* @__PURE__ */ jsx10(
|
|
4040
|
+
MessageSlot,
|
|
4041
|
+
{
|
|
4042
|
+
"data-testid": isLatestTurn ? "chat-latest-user-anchor" : void 0,
|
|
4043
|
+
style: isLatestTurn ? { scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px` } : void 0,
|
|
4044
|
+
children: renderChatMessage({
|
|
4045
|
+
message: turn.userMessage,
|
|
4046
|
+
mode: activeSessionMode,
|
|
4047
|
+
onConfirmationSubmit,
|
|
4048
|
+
onQuestionnaireSubmit,
|
|
4049
|
+
renderMessageBlock
|
|
4050
|
+
})
|
|
4051
|
+
}
|
|
4052
|
+
) : null,
|
|
4053
|
+
turn.responseMessages.map((message) => /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
|
|
4054
|
+
message,
|
|
4055
|
+
mode: activeSessionMode,
|
|
4056
|
+
onConfirmationSubmit,
|
|
4057
|
+
onQuestionnaireSubmit,
|
|
4058
|
+
renderMessageBlock
|
|
4059
|
+
}) }, message.id)),
|
|
4060
|
+
isLatestTurn && error2 ? renderErrorState({ error: error2, onRetry, retryButtonLabel }) : null
|
|
4061
|
+
]
|
|
4062
|
+
},
|
|
4063
|
+
turn.id
|
|
4064
|
+
);
|
|
4065
|
+
}),
|
|
3821
4066
|
!latestTurn && error2 ? renderErrorState({ error: error2, onRetry, retryButtonLabel }) : null
|
|
3822
4067
|
] }),
|
|
3823
4068
|
isDetached ? /* @__PURE__ */ jsx10(ScrollToLatestOverlay, { children: /* @__PURE__ */ jsxs7(
|
|
@@ -3838,14 +4083,25 @@ var EMPTY_MESSAGES = [];
|
|
|
3838
4083
|
var ChatThread = () => {
|
|
3839
4084
|
const activeSessionId = useChatStore((s) => s.activeSessionId);
|
|
3840
4085
|
const hasSessions = useChatStore((s) => s.sessions.length > 0);
|
|
3841
|
-
const
|
|
3842
|
-
(s) => s.sessions.find((
|
|
4086
|
+
const activeSession = useChatStore(
|
|
4087
|
+
(s) => s.sessions.find((session) => session.sessionId === s.activeSessionId)
|
|
3843
4088
|
);
|
|
4089
|
+
const activeSessionMode = activeSession?.mode ?? DEFAULT_CHAT_AGENT_MODE;
|
|
3844
4090
|
const messages = useChatStore(
|
|
3845
4091
|
(s) => s.messagesBySession[s.activeSessionId ?? ""] ?? EMPTY_MESSAGES
|
|
3846
4092
|
);
|
|
4093
|
+
const sessionMessageLoadStatus = useChatStore(
|
|
4094
|
+
(s) => s.sessionMessageLoadStatusBySession[s.activeSessionId ?? ""]
|
|
4095
|
+
);
|
|
3847
4096
|
const streamingMessage = useChatStore((s) => s.streamingMessageBySession[s.activeSessionId ?? ""]);
|
|
3848
4097
|
const error2 = useChatStore((s) => s.errorBySession[s.activeSessionId ?? ""]);
|
|
4098
|
+
const historyMessagePagination = useChatStore(
|
|
4099
|
+
(s) => s.historyMessagePaginationBySession[s.activeSessionId ?? ""]
|
|
4100
|
+
);
|
|
4101
|
+
const prependHistorySessionMessagesPage = useChatStore((s) => s.prependHistorySessionMessagesPage);
|
|
4102
|
+
const setHistorySessionPreviousMessagesLoadStatus = useChatStore(
|
|
4103
|
+
(s) => s.setHistorySessionPreviousMessagesLoadStatus
|
|
4104
|
+
);
|
|
3849
4105
|
const updateQA = useChatStore((s) => s.updateQuestionnaireAnswers);
|
|
3850
4106
|
const clearSessionError = useChatStore((s) => s.clearSessionError);
|
|
3851
4107
|
const {
|
|
@@ -3854,6 +4110,7 @@ var ChatThread = () => {
|
|
|
3854
4110
|
renderMessageBlock,
|
|
3855
4111
|
handleQuestionnaireSubmit: customQuestionnaireSubmit,
|
|
3856
4112
|
handleConfirmationSubmit: customConfirmationSubmit,
|
|
4113
|
+
onLoadMoreHistoryMessages,
|
|
3857
4114
|
labels
|
|
3858
4115
|
} = useChatContext();
|
|
3859
4116
|
const handleRetry = useCallback3(() => {
|
|
@@ -3916,6 +4173,42 @@ var ChatThread = () => {
|
|
|
3916
4173
|
},
|
|
3917
4174
|
[activeSessionId, activeSessionMode, sendRef, customConfirmationSubmit]
|
|
3918
4175
|
);
|
|
4176
|
+
const handleLoadPreviousMessages = useCallback3(async () => {
|
|
4177
|
+
if (!activeSession || !onLoadMoreHistoryMessages || !historyMessagePagination?.hasMorePrevious || !historyMessagePagination.previousCursor || historyMessagePagination.isLoadingPrevious) {
|
|
4178
|
+
return;
|
|
4179
|
+
}
|
|
4180
|
+
setHistorySessionPreviousMessagesLoadStatus(activeSession.sessionId, true);
|
|
4181
|
+
try {
|
|
4182
|
+
const page = await onLoadMoreHistoryMessages({
|
|
4183
|
+
session: activeSession,
|
|
4184
|
+
cursor: historyMessagePagination.previousCursor
|
|
4185
|
+
});
|
|
4186
|
+
if (page) {
|
|
4187
|
+
prependHistorySessionMessagesPage(activeSession.sessionId, page);
|
|
4188
|
+
return;
|
|
4189
|
+
}
|
|
4190
|
+
setHistorySessionPreviousMessagesLoadStatus(activeSession.sessionId, false);
|
|
4191
|
+
} catch (error3) {
|
|
4192
|
+
setHistorySessionPreviousMessagesLoadStatus(
|
|
4193
|
+
activeSession.sessionId,
|
|
4194
|
+
false,
|
|
4195
|
+
error3 instanceof Error ? error3.message : String(error3)
|
|
4196
|
+
);
|
|
4197
|
+
throw error3;
|
|
4198
|
+
}
|
|
4199
|
+
}, [
|
|
4200
|
+
activeSession,
|
|
4201
|
+
historyMessagePagination,
|
|
4202
|
+
onLoadMoreHistoryMessages,
|
|
4203
|
+
prependHistorySessionMessagesPage,
|
|
4204
|
+
setHistorySessionPreviousMessagesLoadStatus
|
|
4205
|
+
]);
|
|
4206
|
+
const canLoadPreviousMessages = Boolean(
|
|
4207
|
+
activeSession && onLoadMoreHistoryMessages && historyMessagePagination?.hasMorePrevious && historyMessagePagination.previousCursor && !historyMessagePagination.isLoadingPrevious
|
|
4208
|
+
);
|
|
4209
|
+
if (hasSessions && sessionMessageLoadStatus === "loading" && messages.length === 0 && !streamingMessage) {
|
|
4210
|
+
return /* @__PURE__ */ jsx10(ThreadStateViewport, { "data-testid": "chat-thread-loading-state", children: /* @__PURE__ */ jsx10(ThreadStateText, { children: labels.sessionHistoryLoading }) });
|
|
4211
|
+
}
|
|
3919
4212
|
if (!hasSessions || messages.length === 0 && !streamingMessage) {
|
|
3920
4213
|
return /* @__PURE__ */ jsx10(ChatThreadEmptyState, {});
|
|
3921
4214
|
}
|
|
@@ -3926,9 +4219,13 @@ var ChatThread = () => {
|
|
|
3926
4219
|
historyMessages: messages,
|
|
3927
4220
|
streamingMessage,
|
|
3928
4221
|
error: error2,
|
|
4222
|
+
isLoadingPreviousMessages: historyMessagePagination?.isLoadingPrevious,
|
|
4223
|
+
previousMessagesError: historyMessagePagination?.error,
|
|
3929
4224
|
retryButtonLabel: labels.retryButton,
|
|
3930
4225
|
scrollToLatestLabel: labels.scrollToLatest,
|
|
4226
|
+
sessionHistoryLoadingLabel: labels.sessionHistoryLoading,
|
|
3931
4227
|
onRetry: handleRetry,
|
|
4228
|
+
onLoadPreviousMessages: canLoadPreviousMessages ? handleLoadPreviousMessages : void 0,
|
|
3932
4229
|
onConfirmationSubmit: handleConfirmation,
|
|
3933
4230
|
onQuestionnaireSubmit: handleQuestionnaireSubmit,
|
|
3934
4231
|
renderMessageBlock
|
|
@@ -3942,6 +4239,18 @@ var ThreadViewport = styled9.div`
|
|
|
3942
4239
|
flex: 1;
|
|
3943
4240
|
min-height: 0;
|
|
3944
4241
|
`;
|
|
4242
|
+
var ThreadStateViewport = styled9.div`
|
|
4243
|
+
display: flex;
|
|
4244
|
+
flex: 1;
|
|
4245
|
+
min-height: 0;
|
|
4246
|
+
align-items: center;
|
|
4247
|
+
justify-content: center;
|
|
4248
|
+
padding: 24px;
|
|
4249
|
+
`;
|
|
4250
|
+
var ThreadStateText = styled9.div`
|
|
4251
|
+
color: var(--text-secondary, rgba(255, 255, 255, 0.64));
|
|
4252
|
+
font-size: 14px;
|
|
4253
|
+
`;
|
|
3945
4254
|
var Container = styled9.div`
|
|
3946
4255
|
display: flex;
|
|
3947
4256
|
flex: 1;
|
|
@@ -3949,7 +4258,7 @@ var Container = styled9.div`
|
|
|
3949
4258
|
gap: 18px;
|
|
3950
4259
|
min-height: 0;
|
|
3951
4260
|
overflow: auto;
|
|
3952
|
-
padding: 24px
|
|
4261
|
+
padding: 24px 16px 88px;
|
|
3953
4262
|
overscroll-behavior: contain;
|
|
3954
4263
|
|
|
3955
4264
|
&::-webkit-scrollbar {
|
|
@@ -3968,10 +4277,23 @@ var Container = styled9.div`
|
|
|
3968
4277
|
var MessageSlot = styled9.div`
|
|
3969
4278
|
display: flex;
|
|
3970
4279
|
`;
|
|
4280
|
+
var PreviousMessagesStateRow = styled9.div`
|
|
4281
|
+
width: 100%;
|
|
4282
|
+
max-width: var(--chat-content-max-width, 48rem);
|
|
4283
|
+
margin-right: auto;
|
|
4284
|
+
margin-left: auto;
|
|
4285
|
+
color: var(--text-secondary, rgba(255, 255, 255, 0.64));
|
|
4286
|
+
font-size: 13px;
|
|
4287
|
+
text-align: center;
|
|
4288
|
+
`;
|
|
3971
4289
|
var ConversationTurn = styled9.div`
|
|
3972
4290
|
display: flex;
|
|
3973
4291
|
flex-direction: column;
|
|
3974
4292
|
gap: 18px;
|
|
4293
|
+
width: 100%;
|
|
4294
|
+
max-width: var(--chat-content-max-width, 48rem);
|
|
4295
|
+
margin-right: auto;
|
|
4296
|
+
margin-left: auto;
|
|
3975
4297
|
`;
|
|
3976
4298
|
var ErrorText = styled9.div`
|
|
3977
4299
|
color: #ff7b72;
|
|
@@ -7759,7 +8081,7 @@ var PrimaryButton = styled13(Button)`
|
|
|
7759
8081
|
min-width: 24px;
|
|
7760
8082
|
width: 24px;
|
|
7761
8083
|
height: 24px;
|
|
7762
|
-
background: ${({ $canSend }) => $canSend ? "#fcfbf8" : "rgba(
|
|
8084
|
+
background: ${({ $canSend }) => $canSend ? "#fcfbf8" : "rgba(252,251,248,0.3);"};
|
|
7763
8085
|
color: ${({ $canSend }) => $canSend ? "#5b5448" : "rgba(255, 255, 255, 0.72)"};
|
|
7764
8086
|
border-radius: 12px;
|
|
7765
8087
|
border: 1px solid ${({ $canSend }) => $canSend ? "rgba(198, 188, 170, 0.38)" : "transparent"};
|
|
@@ -7770,7 +8092,7 @@ var PrimaryButton = styled13(Button)`
|
|
|
7770
8092
|
}
|
|
7771
8093
|
|
|
7772
8094
|
&:hover:not(:disabled) {
|
|
7773
|
-
background: ${({ $canSend }) => $canSend ? "#f7f4ec" : "rgba(
|
|
8095
|
+
background: ${({ $canSend }) => $canSend ? "#f7f4ec" : "rgba(252,251,248,0.3);"};
|
|
7774
8096
|
color: ${({ $canSend }) => $canSend ? "#4f493f" : "rgba(255, 255, 255, 0.72)"};
|
|
7775
8097
|
border-color: ${({ $canSend }) => $canSend ? "rgba(198, 188, 170, 0.46)" : "transparent"};
|
|
7776
8098
|
}
|
|
@@ -7838,7 +8160,7 @@ var StopSpinner = styled13.span`
|
|
|
7838
8160
|
import { jsx as jsx16, jsxs as jsxs11 } from "@emotion/react/jsx-runtime";
|
|
7839
8161
|
var CHAT_COMPOSER_LINE_HEIGHT_PX = 20;
|
|
7840
8162
|
var CHAT_COMPOSER_MAX_ROWS = 7;
|
|
7841
|
-
var CHAT_COMPOSER_PADDING_TOP_PX =
|
|
8163
|
+
var CHAT_COMPOSER_PADDING_TOP_PX = 12;
|
|
7842
8164
|
var CHAT_COMPOSER_PADDING_BOTTOM_PX = 12;
|
|
7843
8165
|
var CHAT_COMPOSER_PADDING_BLOCK_PX = CHAT_COMPOSER_PADDING_TOP_PX + CHAT_COMPOSER_PADDING_BOTTOM_PX;
|
|
7844
8166
|
var CHAT_COMPOSER_MIN_ROWS = 4;
|
|
@@ -8073,6 +8395,10 @@ var ChatComposerView = ({
|
|
|
8073
8395
|
setActiveSkillNavigation({ queryKey: "", index: 0 });
|
|
8074
8396
|
};
|
|
8075
8397
|
const handleKeyDown = (event) => {
|
|
8398
|
+
const isImeComposing = event.nativeEvent.isComposing || event.keyCode === 229;
|
|
8399
|
+
if (event.key === "Enter" && isImeComposing) {
|
|
8400
|
+
return;
|
|
8401
|
+
}
|
|
8076
8402
|
if (skillQueryMatch) {
|
|
8077
8403
|
if (event.key === "ArrowDown" && filteredSkills.length > 0) {
|
|
8078
8404
|
event.preventDefault();
|
|
@@ -8350,7 +8676,7 @@ var Surface = styled14.div`
|
|
|
8350
8676
|
'input'
|
|
8351
8677
|
'footer';
|
|
8352
8678
|
width: 100%;
|
|
8353
|
-
max-width:
|
|
8679
|
+
max-width: var(--chat-content-max-width, 48rem);
|
|
8354
8680
|
margin: 0 auto;
|
|
8355
8681
|
background: var(--border-color);
|
|
8356
8682
|
border-radius: 20px;
|
|
@@ -8611,6 +8937,7 @@ var SkillButton = styled14.button`
|
|
|
8611
8937
|
`;
|
|
8612
8938
|
|
|
8613
8939
|
// src/components/chat-conversation-list/index.tsx
|
|
8940
|
+
import { useEffect as useEffect10, useMemo as useMemo7, useRef as useRef12 } from "react";
|
|
8614
8941
|
import styled16 from "@emotion/styled";
|
|
8615
8942
|
|
|
8616
8943
|
// src/components/chat-conversation-list/components/chat-session-item.tsx
|
|
@@ -8624,6 +8951,7 @@ var ChatSessionItem = memo2(
|
|
|
8624
8951
|
{
|
|
8625
8952
|
type: "button",
|
|
8626
8953
|
"data-active": isActive,
|
|
8954
|
+
"data-testid": `chat-session-item-${session.sessionId}`,
|
|
8627
8955
|
onClick: () => onClick(session.sessionId),
|
|
8628
8956
|
children: /* @__PURE__ */ jsxs12(SessionMeta, { children: [
|
|
8629
8957
|
/* @__PURE__ */ jsx17(SessionTitle, { children: session.title }),
|
|
@@ -8671,14 +8999,130 @@ var ModeBadge = styled15.span`
|
|
|
8671
8999
|
background: rgba(255, 255, 255, 0.04);
|
|
8672
9000
|
`;
|
|
8673
9001
|
|
|
9002
|
+
// src/components/chat-conversation-list/lib/history-session-selection.ts
|
|
9003
|
+
var shouldLoadHistorySessionMessages = ({
|
|
9004
|
+
sessionId,
|
|
9005
|
+
messagesBySession,
|
|
9006
|
+
loadStatusBySession,
|
|
9007
|
+
isStreamingBySession
|
|
9008
|
+
}) => {
|
|
9009
|
+
if (isStreamingBySession[sessionId])
|
|
9010
|
+
return false;
|
|
9011
|
+
if (loadStatusBySession[sessionId] === "loading")
|
|
9012
|
+
return false;
|
|
9013
|
+
if (loadStatusBySession[sessionId] === "error")
|
|
9014
|
+
return true;
|
|
9015
|
+
if (loadStatusBySession[sessionId] === "loaded")
|
|
9016
|
+
return false;
|
|
9017
|
+
return messagesBySession[sessionId] === void 0;
|
|
9018
|
+
};
|
|
9019
|
+
|
|
8674
9020
|
// src/components/chat-conversation-list/index.tsx
|
|
8675
9021
|
import { jsx as jsx18, jsxs as jsxs13 } from "@emotion/react/jsx-runtime";
|
|
9022
|
+
var SCROLL_LOAD_MORE_THRESHOLD_PX = 80;
|
|
9023
|
+
var shouldLoadMoreSessions = ({
|
|
9024
|
+
scrollTop,
|
|
9025
|
+
clientHeight,
|
|
9026
|
+
scrollHeight,
|
|
9027
|
+
threshold = SCROLL_LOAD_MORE_THRESHOLD_PX
|
|
9028
|
+
}) => scrollHeight - scrollTop - clientHeight <= threshold;
|
|
9029
|
+
var isHistorySessionMessagesPage = (value) => typeof value === "object" && value !== null && Array.isArray(value.messages);
|
|
8676
9030
|
var ChatConversationList = () => {
|
|
8677
|
-
const { labels } = useChatContext();
|
|
8678
|
-
const
|
|
9031
|
+
const { labels, historySessionList, onLoadMoreSessions, onSelectHistorySession, store } = useChatContext();
|
|
9032
|
+
const localSessions = useChatStore((s) => s.sessions);
|
|
8679
9033
|
const activeSessionId = useChatStore((s) => s.activeSessionId);
|
|
8680
9034
|
const startNewChat = useChatStore((s) => s.startNewChat);
|
|
8681
9035
|
const setActiveSession = useChatStore((s) => s.setActiveSession);
|
|
9036
|
+
const hydrateHistorySessions = useChatStore((s) => s.hydrateHistorySessions);
|
|
9037
|
+
const hydrateHistorySessionMessages = useChatStore((s) => s.hydrateHistorySessionMessages);
|
|
9038
|
+
const hydrateHistorySessionMessagesPage = useChatStore((s) => s.hydrateHistorySessionMessagesPage);
|
|
9039
|
+
const setHistorySessionMessageLoadStatus = useChatStore(
|
|
9040
|
+
(s) => s.setHistorySessionMessageLoadStatus
|
|
9041
|
+
);
|
|
9042
|
+
const isLoadingMoreRef = useRef12(false);
|
|
9043
|
+
const hasSeenLoadingMoreRef = useRef12(false);
|
|
9044
|
+
useEffect10(() => {
|
|
9045
|
+
if (!historySessionList)
|
|
9046
|
+
return;
|
|
9047
|
+
hydrateHistorySessions(historySessionList.sessions);
|
|
9048
|
+
}, [historySessionList, hydrateHistorySessions]);
|
|
9049
|
+
useEffect10(() => {
|
|
9050
|
+
if (historySessionList?.isLoading) {
|
|
9051
|
+
hasSeenLoadingMoreRef.current = true;
|
|
9052
|
+
return;
|
|
9053
|
+
}
|
|
9054
|
+
if (hasSeenLoadingMoreRef.current) {
|
|
9055
|
+
hasSeenLoadingMoreRef.current = false;
|
|
9056
|
+
isLoadingMoreRef.current = false;
|
|
9057
|
+
}
|
|
9058
|
+
}, [historySessionList?.isLoading]);
|
|
9059
|
+
useEffect10(() => {
|
|
9060
|
+
isLoadingMoreRef.current = false;
|
|
9061
|
+
hasSeenLoadingMoreRef.current = false;
|
|
9062
|
+
}, [historySessionList?.sessions.length, historySessionList?.hasMore]);
|
|
9063
|
+
const sessions = useMemo7(() => {
|
|
9064
|
+
if (!historySessionList) {
|
|
9065
|
+
return localSessions;
|
|
9066
|
+
}
|
|
9067
|
+
const localSessionIds = new Set(localSessions.map((session) => session.sessionId));
|
|
9068
|
+
return [
|
|
9069
|
+
...localSessions,
|
|
9070
|
+
...historySessionList.sessions.filter((session) => !localSessionIds.has(session.sessionId))
|
|
9071
|
+
];
|
|
9072
|
+
}, [historySessionList, localSessions]);
|
|
9073
|
+
const handleSessionListScroll = (event) => {
|
|
9074
|
+
if (!historySessionList?.hasMore || historySessionList.isLoading || !onLoadMoreSessions || isLoadingMoreRef.current) {
|
|
9075
|
+
return;
|
|
9076
|
+
}
|
|
9077
|
+
const target = event.currentTarget;
|
|
9078
|
+
if (shouldLoadMoreSessions({
|
|
9079
|
+
scrollTop: target.scrollTop,
|
|
9080
|
+
clientHeight: target.clientHeight,
|
|
9081
|
+
scrollHeight: target.scrollHeight
|
|
9082
|
+
})) {
|
|
9083
|
+
isLoadingMoreRef.current = true;
|
|
9084
|
+
void Promise.resolve(onLoadMoreSessions()).catch(() => {
|
|
9085
|
+
isLoadingMoreRef.current = false;
|
|
9086
|
+
hasSeenLoadingMoreRef.current = false;
|
|
9087
|
+
});
|
|
9088
|
+
}
|
|
9089
|
+
};
|
|
9090
|
+
const handleSelectSession = async (sessionId) => {
|
|
9091
|
+
setActiveSession(sessionId);
|
|
9092
|
+
const session = sessions.find((item) => item.sessionId === sessionId);
|
|
9093
|
+
if (!session || !onSelectHistorySession) {
|
|
9094
|
+
return;
|
|
9095
|
+
}
|
|
9096
|
+
const state = store.getState();
|
|
9097
|
+
const shouldLoad = shouldLoadHistorySessionMessages({
|
|
9098
|
+
sessionId,
|
|
9099
|
+
messagesBySession: state.messagesBySession,
|
|
9100
|
+
loadStatusBySession: state.sessionMessageLoadStatusBySession,
|
|
9101
|
+
isStreamingBySession: state.isStreamingBySession
|
|
9102
|
+
});
|
|
9103
|
+
if (!shouldLoad) {
|
|
9104
|
+
return;
|
|
9105
|
+
}
|
|
9106
|
+
setHistorySessionMessageLoadStatus(sessionId, "loading");
|
|
9107
|
+
try {
|
|
9108
|
+
const result = await onSelectHistorySession(session);
|
|
9109
|
+
if (Array.isArray(result)) {
|
|
9110
|
+
hydrateHistorySessionMessages(sessionId, result);
|
|
9111
|
+
return;
|
|
9112
|
+
}
|
|
9113
|
+
if (isHistorySessionMessagesPage(result)) {
|
|
9114
|
+
hydrateHistorySessionMessagesPage(sessionId, result);
|
|
9115
|
+
return;
|
|
9116
|
+
}
|
|
9117
|
+
setHistorySessionMessageLoadStatus(sessionId, "loaded");
|
|
9118
|
+
} catch (error2) {
|
|
9119
|
+
setHistorySessionMessageLoadStatus(
|
|
9120
|
+
sessionId,
|
|
9121
|
+
"error",
|
|
9122
|
+
error2 instanceof Error ? error2.message : String(error2)
|
|
9123
|
+
);
|
|
9124
|
+
}
|
|
9125
|
+
};
|
|
8682
9126
|
const modeLabels = {
|
|
8683
9127
|
ask: labels.modeLabelAsk,
|
|
8684
9128
|
plan: labels.modeLabelPlan,
|
|
@@ -8689,16 +9133,21 @@ var ChatConversationList = () => {
|
|
|
8689
9133
|
/* @__PURE__ */ jsx18(Title3, { children: "Sessions" }),
|
|
8690
9134
|
/* @__PURE__ */ jsx18(CreateButton, { type: "button", "data-testid": "chat-create-session", onClick: startNewChat, children: labels.newChat })
|
|
8691
9135
|
] }),
|
|
8692
|
-
/* @__PURE__ */
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
9136
|
+
/* @__PURE__ */ jsxs13(List2, { "data-testid": "chat-session-list", onScroll: handleSessionListScroll, children: [
|
|
9137
|
+
sessions.map((session) => /* @__PURE__ */ jsx18(
|
|
9138
|
+
ChatSessionItem,
|
|
9139
|
+
{
|
|
9140
|
+
session,
|
|
9141
|
+
isActive: activeSessionId === session.sessionId,
|
|
9142
|
+
modeLabel: modeLabels[session.mode ?? DEFAULT_CHAT_AGENT_MODE] ?? "",
|
|
9143
|
+
onClick: (sessionId) => void handleSelectSession(sessionId)
|
|
9144
|
+
},
|
|
9145
|
+
session.sessionId
|
|
9146
|
+
)),
|
|
9147
|
+
historySessionList?.isLoading ? /* @__PURE__ */ jsx18(StateRow, { "data-testid": "chat-session-history-loading", children: labels.sessionHistoryLoading }) : null,
|
|
9148
|
+
historySessionList?.error ? /* @__PURE__ */ jsx18(StateRow, { "data-testid": "chat-session-history-error", children: historySessionList.error || labels.sessionHistoryLoadFailed }) : null,
|
|
9149
|
+
historySessionList && !historySessionList.isLoading && !historySessionList.error && sessions.length === 0 ? /* @__PURE__ */ jsx18(StateRow, { "data-testid": "chat-session-history-empty", children: labels.sessionHistoryEmpty }) : null
|
|
9150
|
+
] })
|
|
8702
9151
|
] });
|
|
8703
9152
|
};
|
|
8704
9153
|
var Container3 = styled16.aside`
|
|
@@ -8736,6 +9185,11 @@ var List2 = styled16.div`
|
|
|
8736
9185
|
gap: 8px;
|
|
8737
9186
|
overflow: auto;
|
|
8738
9187
|
`;
|
|
9188
|
+
var StateRow = styled16.div`
|
|
9189
|
+
padding: 12px;
|
|
9190
|
+
font-size: 13px;
|
|
9191
|
+
color: var(--text-secondary);
|
|
9192
|
+
`;
|
|
8739
9193
|
|
|
8740
9194
|
// src/components/ai-chat/index.tsx
|
|
8741
9195
|
import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs14 } from "@emotion/react/jsx-runtime";
|
|
@@ -8797,7 +9251,7 @@ var AiChatWorkspaceContent = ({
|
|
|
8797
9251
|
})
|
|
8798
9252
|
);
|
|
8799
9253
|
const shouldShowComposerOnly = showComposerOnlyBeforeFirstMessage && !showConversationList && !isConversationStarted;
|
|
8800
|
-
|
|
9254
|
+
useEffect11(() => {
|
|
8801
9255
|
onConversationStartedChange?.(isConversationStarted);
|
|
8802
9256
|
}, [isConversationStarted, onConversationStartedChange]);
|
|
8803
9257
|
return /* @__PURE__ */ jsxs14(Root, { "data-testid": "ai-chat", children: [
|
|
@@ -8936,12 +9390,25 @@ var Root = styled17.div`
|
|
|
8936
9390
|
overflow: hidden;
|
|
8937
9391
|
`;
|
|
8938
9392
|
var Workspace = styled17.section`
|
|
9393
|
+
--chat-layout-rem: 16px;
|
|
9394
|
+
--chat-content-margin: calc(var(--chat-layout-rem) * 1);
|
|
9395
|
+
--chat-content-max-width: calc(var(--chat-layout-rem) * 40);
|
|
9396
|
+
|
|
8939
9397
|
flex: 1;
|
|
8940
9398
|
display: flex;
|
|
8941
9399
|
flex-direction: column;
|
|
8942
9400
|
gap: 12px;
|
|
8943
9401
|
min-height: 0;
|
|
8944
9402
|
overflow: hidden;
|
|
9403
|
+
|
|
9404
|
+
@media (min-width: 640px) {
|
|
9405
|
+
--chat-content-margin: calc(var(--chat-layout-rem) * 1.5);
|
|
9406
|
+
}
|
|
9407
|
+
|
|
9408
|
+
@media (min-width: 1024px) {
|
|
9409
|
+
--chat-content-margin: calc(var(--chat-layout-rem) * 4);
|
|
9410
|
+
--chat-content-max-width: calc(var(--chat-layout-rem) * 48);
|
|
9411
|
+
}
|
|
8945
9412
|
`;
|
|
8946
9413
|
var QuickActionsRow = styled17.div`
|
|
8947
9414
|
display: flex;
|