@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.js
CHANGED
|
@@ -46,7 +46,7 @@ __export(src_exports, {
|
|
|
46
46
|
module.exports = __toCommonJS(src_exports);
|
|
47
47
|
|
|
48
48
|
// src/components/ai-chat/index.tsx
|
|
49
|
-
var
|
|
49
|
+
var import_react21 = require("react");
|
|
50
50
|
var import_styled17 = __toESM(require("@emotion/styled"));
|
|
51
51
|
var import_compass_ui4 = require("@xinghunm/compass-ui");
|
|
52
52
|
|
|
@@ -100,7 +100,10 @@ var DEFAULT_AI_CHAT_LABELS = {
|
|
|
100
100
|
modelUnavailable: "No model available",
|
|
101
101
|
skillLoading: "Loading skills...",
|
|
102
102
|
skillEmpty: "No matching skills",
|
|
103
|
-
removeSkillAriaLabel: "Remove skill"
|
|
103
|
+
removeSkillAriaLabel: "Remove skill",
|
|
104
|
+
sessionHistoryLoading: "Loading conversations...",
|
|
105
|
+
sessionHistoryLoadFailed: "Failed to load conversations",
|
|
106
|
+
sessionHistoryEmpty: "No conversations yet"
|
|
104
107
|
};
|
|
105
108
|
|
|
106
109
|
// src/lib/chat-session.ts
|
|
@@ -128,6 +131,20 @@ var createDraftChatSession = ({
|
|
|
128
131
|
// src/store/chat-store.ts
|
|
129
132
|
var DEFAULT_CHAT_SESSION_TITLE = "New Chat";
|
|
130
133
|
var IMAGE_MESSAGE_SESSION_TITLE = "Image message";
|
|
134
|
+
var createHistoryMessagePaginationState = (page) => ({
|
|
135
|
+
previousCursor: page?.previousCursor ?? null,
|
|
136
|
+
hasMorePrevious: page?.hasMorePrevious ?? Boolean(page && page.previousCursor !== null),
|
|
137
|
+
isLoadingPrevious: false,
|
|
138
|
+
error: null
|
|
139
|
+
});
|
|
140
|
+
var normalizeHistoryMessages = (sessionId, messages) => messages.map((message) => ({ ...message, sessionId }));
|
|
141
|
+
var mergeOlderHistoryMessages = (sessionId, olderMessages, currentMessages) => {
|
|
142
|
+
const currentMessageIds = new Set(currentMessages.map((message) => message.id));
|
|
143
|
+
const uniqueOlderMessages = normalizeHistoryMessages(sessionId, olderMessages).filter(
|
|
144
|
+
(message) => !currentMessageIds.has(message.id)
|
|
145
|
+
);
|
|
146
|
+
return [...uniqueOlderMessages, ...currentMessages];
|
|
147
|
+
};
|
|
131
148
|
var resolveSessionTitleFromMessage = (message) => {
|
|
132
149
|
const trimmedContent = message.content.trim();
|
|
133
150
|
if (trimmedContent) {
|
|
@@ -230,6 +247,9 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
|
|
|
230
247
|
isStreamingBySession: {},
|
|
231
248
|
isStoppingBySession: {},
|
|
232
249
|
errorBySession: {},
|
|
250
|
+
sessionMessageLoadStatusBySession: {},
|
|
251
|
+
sessionMessageLoadErrorBySession: {},
|
|
252
|
+
historyMessagePaginationBySession: {},
|
|
233
253
|
// ---- Session management ------------------------------------------------
|
|
234
254
|
createSession: (session) => {
|
|
235
255
|
const state = get();
|
|
@@ -243,6 +263,15 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
|
|
|
243
263
|
const nextErrorBySession = { ...state.errorBySession };
|
|
244
264
|
const nextIsStreamingBySession = { ...state.isStreamingBySession };
|
|
245
265
|
const nextIsStoppingBySession = { ...state.isStoppingBySession };
|
|
266
|
+
const nextSessionMessageLoadStatusBySession = {
|
|
267
|
+
...state.sessionMessageLoadStatusBySession
|
|
268
|
+
};
|
|
269
|
+
const nextSessionMessageLoadErrorBySession = {
|
|
270
|
+
...state.sessionMessageLoadErrorBySession
|
|
271
|
+
};
|
|
272
|
+
const nextHistoryMessagePaginationBySession = {
|
|
273
|
+
...state.historyMessagePaginationBySession
|
|
274
|
+
};
|
|
246
275
|
const sid = session.sessionId;
|
|
247
276
|
if (nextMessagesBySession[sid] === void 0)
|
|
248
277
|
nextMessagesBySession[sid] = [];
|
|
@@ -252,13 +281,25 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
|
|
|
252
281
|
nextIsStreamingBySession[sid] = false;
|
|
253
282
|
if (nextIsStoppingBySession[sid] === void 0)
|
|
254
283
|
nextIsStoppingBySession[sid] = false;
|
|
284
|
+
if (nextSessionMessageLoadStatusBySession[sid] === void 0) {
|
|
285
|
+
nextSessionMessageLoadStatusBySession[sid] = "loaded";
|
|
286
|
+
}
|
|
287
|
+
if (nextSessionMessageLoadErrorBySession[sid] === void 0) {
|
|
288
|
+
nextSessionMessageLoadErrorBySession[sid] = null;
|
|
289
|
+
}
|
|
290
|
+
if (nextHistoryMessagePaginationBySession[sid] === void 0) {
|
|
291
|
+
nextHistoryMessagePaginationBySession[sid] = createHistoryMessagePaginationState();
|
|
292
|
+
}
|
|
255
293
|
set({
|
|
256
294
|
sessions: nextSessions,
|
|
257
295
|
activeSessionId: sid,
|
|
258
296
|
messagesBySession: nextMessagesBySession,
|
|
259
297
|
errorBySession: nextErrorBySession,
|
|
260
298
|
isStreamingBySession: nextIsStreamingBySession,
|
|
261
|
-
isStoppingBySession: nextIsStoppingBySession
|
|
299
|
+
isStoppingBySession: nextIsStoppingBySession,
|
|
300
|
+
sessionMessageLoadStatusBySession: nextSessionMessageLoadStatusBySession,
|
|
301
|
+
sessionMessageLoadErrorBySession: nextSessionMessageLoadErrorBySession,
|
|
302
|
+
historyMessagePaginationBySession: nextHistoryMessagePaginationBySession
|
|
262
303
|
});
|
|
263
304
|
},
|
|
264
305
|
startNewChat: () => {
|
|
@@ -313,6 +354,27 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
|
|
|
313
354
|
nextErrorBySession[nextSessionId] = nextErrorBySession[previousSessionId] ?? null;
|
|
314
355
|
delete nextErrorBySession[previousSessionId];
|
|
315
356
|
}
|
|
357
|
+
const nextSessionMessageLoadStatusBySession = {
|
|
358
|
+
...state.sessionMessageLoadStatusBySession
|
|
359
|
+
};
|
|
360
|
+
if (previousSessionId in nextSessionMessageLoadStatusBySession) {
|
|
361
|
+
nextSessionMessageLoadStatusBySession[nextSessionId] = nextSessionMessageLoadStatusBySession[previousSessionId] ?? "idle";
|
|
362
|
+
delete nextSessionMessageLoadStatusBySession[previousSessionId];
|
|
363
|
+
}
|
|
364
|
+
const nextSessionMessageLoadErrorBySession = {
|
|
365
|
+
...state.sessionMessageLoadErrorBySession
|
|
366
|
+
};
|
|
367
|
+
if (previousSessionId in nextSessionMessageLoadErrorBySession) {
|
|
368
|
+
nextSessionMessageLoadErrorBySession[nextSessionId] = nextSessionMessageLoadErrorBySession[previousSessionId] ?? null;
|
|
369
|
+
delete nextSessionMessageLoadErrorBySession[previousSessionId];
|
|
370
|
+
}
|
|
371
|
+
const nextHistoryMessagePaginationBySession = {
|
|
372
|
+
...state.historyMessagePaginationBySession
|
|
373
|
+
};
|
|
374
|
+
if (previousSessionId in nextHistoryMessagePaginationBySession) {
|
|
375
|
+
nextHistoryMessagePaginationBySession[nextSessionId] = nextHistoryMessagePaginationBySession[previousSessionId] ?? createHistoryMessagePaginationState();
|
|
376
|
+
delete nextHistoryMessagePaginationBySession[previousSessionId];
|
|
377
|
+
}
|
|
316
378
|
const nextActiveSessionId = state.activeSessionId === previousSessionId ? nextSessionId : state.activeSessionId;
|
|
317
379
|
set({
|
|
318
380
|
sessions: nextSessions,
|
|
@@ -321,6 +383,9 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
|
|
|
321
383
|
isStreamingBySession: nextIsStreamingBySession,
|
|
322
384
|
isStoppingBySession: nextIsStoppingBySession,
|
|
323
385
|
errorBySession: nextErrorBySession,
|
|
386
|
+
sessionMessageLoadStatusBySession: nextSessionMessageLoadStatusBySession,
|
|
387
|
+
sessionMessageLoadErrorBySession: nextSessionMessageLoadErrorBySession,
|
|
388
|
+
historyMessagePaginationBySession: nextHistoryMessagePaginationBySession,
|
|
324
389
|
activeSessionId: nextActiveSessionId
|
|
325
390
|
});
|
|
326
391
|
},
|
|
@@ -334,6 +399,61 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
|
|
|
334
399
|
);
|
|
335
400
|
set({ sessions: nextSessions });
|
|
336
401
|
},
|
|
402
|
+
hydrateHistorySessions: (sessions) => {
|
|
403
|
+
const state = get();
|
|
404
|
+
const localSessions = state.sessions.filter(
|
|
405
|
+
(session) => isDraftChatSessionId(session.sessionId)
|
|
406
|
+
);
|
|
407
|
+
const localSessionIds = new Set(localSessions.map((session) => session.sessionId));
|
|
408
|
+
const nextSessions = [
|
|
409
|
+
...localSessions,
|
|
410
|
+
...sessions.filter((session) => !localSessionIds.has(session.sessionId)).map((session) => ({
|
|
411
|
+
...session,
|
|
412
|
+
mode: session.mode ?? DEFAULT_CHAT_AGENT_MODE
|
|
413
|
+
}))
|
|
414
|
+
];
|
|
415
|
+
const nextMessagesBySession = { ...state.messagesBySession };
|
|
416
|
+
const nextErrorBySession = { ...state.errorBySession };
|
|
417
|
+
const nextIsStreamingBySession = { ...state.isStreamingBySession };
|
|
418
|
+
const nextIsStoppingBySession = { ...state.isStoppingBySession };
|
|
419
|
+
const nextSessionMessageLoadStatusBySession = {
|
|
420
|
+
...state.sessionMessageLoadStatusBySession
|
|
421
|
+
};
|
|
422
|
+
const nextSessionMessageLoadErrorBySession = {
|
|
423
|
+
...state.sessionMessageLoadErrorBySession
|
|
424
|
+
};
|
|
425
|
+
const nextHistoryMessagePaginationBySession = {
|
|
426
|
+
...state.historyMessagePaginationBySession
|
|
427
|
+
};
|
|
428
|
+
nextSessions.forEach((session) => {
|
|
429
|
+
const sid = session.sessionId;
|
|
430
|
+
if (nextErrorBySession[sid] === void 0)
|
|
431
|
+
nextErrorBySession[sid] = null;
|
|
432
|
+
if (nextIsStreamingBySession[sid] === void 0)
|
|
433
|
+
nextIsStreamingBySession[sid] = false;
|
|
434
|
+
if (nextIsStoppingBySession[sid] === void 0)
|
|
435
|
+
nextIsStoppingBySession[sid] = false;
|
|
436
|
+
if (nextSessionMessageLoadStatusBySession[sid] === void 0) {
|
|
437
|
+
nextSessionMessageLoadStatusBySession[sid] = "idle";
|
|
438
|
+
}
|
|
439
|
+
if (nextSessionMessageLoadErrorBySession[sid] === void 0) {
|
|
440
|
+
nextSessionMessageLoadErrorBySession[sid] = null;
|
|
441
|
+
}
|
|
442
|
+
if (nextHistoryMessagePaginationBySession[sid] === void 0) {
|
|
443
|
+
nextHistoryMessagePaginationBySession[sid] = createHistoryMessagePaginationState();
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
set({
|
|
447
|
+
sessions: nextSessions,
|
|
448
|
+
messagesBySession: nextMessagesBySession,
|
|
449
|
+
errorBySession: nextErrorBySession,
|
|
450
|
+
isStreamingBySession: nextIsStreamingBySession,
|
|
451
|
+
isStoppingBySession: nextIsStoppingBySession,
|
|
452
|
+
sessionMessageLoadStatusBySession: nextSessionMessageLoadStatusBySession,
|
|
453
|
+
sessionMessageLoadErrorBySession: nextSessionMessageLoadErrorBySession,
|
|
454
|
+
historyMessagePaginationBySession: nextHistoryMessagePaginationBySession
|
|
455
|
+
});
|
|
456
|
+
},
|
|
337
457
|
// ---- Message operations ------------------------------------------------
|
|
338
458
|
appendMessage: (sessionId, message) => {
|
|
339
459
|
const state = get();
|
|
@@ -360,6 +480,92 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
|
|
|
360
480
|
isStreamingBySession: nextIsStreamingBySession
|
|
361
481
|
});
|
|
362
482
|
},
|
|
483
|
+
hydrateHistorySessionMessages: (sessionId, messages) => {
|
|
484
|
+
const state = get();
|
|
485
|
+
set({
|
|
486
|
+
messagesBySession: {
|
|
487
|
+
...state.messagesBySession,
|
|
488
|
+
[sessionId]: normalizeHistoryMessages(sessionId, messages)
|
|
489
|
+
},
|
|
490
|
+
sessionMessageLoadStatusBySession: {
|
|
491
|
+
...state.sessionMessageLoadStatusBySession,
|
|
492
|
+
[sessionId]: "loaded"
|
|
493
|
+
},
|
|
494
|
+
sessionMessageLoadErrorBySession: {
|
|
495
|
+
...state.sessionMessageLoadErrorBySession,
|
|
496
|
+
[sessionId]: null
|
|
497
|
+
},
|
|
498
|
+
historyMessagePaginationBySession: {
|
|
499
|
+
...state.historyMessagePaginationBySession,
|
|
500
|
+
[sessionId]: createHistoryMessagePaginationState()
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
},
|
|
504
|
+
hydrateHistorySessionMessagesPage: (sessionId, page) => {
|
|
505
|
+
const state = get();
|
|
506
|
+
set({
|
|
507
|
+
messagesBySession: {
|
|
508
|
+
...state.messagesBySession,
|
|
509
|
+
[sessionId]: normalizeHistoryMessages(sessionId, page.messages)
|
|
510
|
+
},
|
|
511
|
+
sessionMessageLoadStatusBySession: {
|
|
512
|
+
...state.sessionMessageLoadStatusBySession,
|
|
513
|
+
[sessionId]: "loaded"
|
|
514
|
+
},
|
|
515
|
+
sessionMessageLoadErrorBySession: {
|
|
516
|
+
...state.sessionMessageLoadErrorBySession,
|
|
517
|
+
[sessionId]: null
|
|
518
|
+
},
|
|
519
|
+
historyMessagePaginationBySession: {
|
|
520
|
+
...state.historyMessagePaginationBySession,
|
|
521
|
+
[sessionId]: createHistoryMessagePaginationState(page)
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
},
|
|
525
|
+
prependHistorySessionMessagesPage: (sessionId, page) => {
|
|
526
|
+
const state = get();
|
|
527
|
+
set({
|
|
528
|
+
messagesBySession: {
|
|
529
|
+
...state.messagesBySession,
|
|
530
|
+
[sessionId]: mergeOlderHistoryMessages(
|
|
531
|
+
sessionId,
|
|
532
|
+
page.messages,
|
|
533
|
+
state.messagesBySession[sessionId] ?? []
|
|
534
|
+
)
|
|
535
|
+
},
|
|
536
|
+
historyMessagePaginationBySession: {
|
|
537
|
+
...state.historyMessagePaginationBySession,
|
|
538
|
+
[sessionId]: createHistoryMessagePaginationState(page)
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
},
|
|
542
|
+
setHistorySessionPreviousMessagesLoadStatus: (sessionId, isLoading, error2 = null) => {
|
|
543
|
+
const state = get();
|
|
544
|
+
const current = state.historyMessagePaginationBySession[sessionId] ?? createHistoryMessagePaginationState();
|
|
545
|
+
set({
|
|
546
|
+
historyMessagePaginationBySession: {
|
|
547
|
+
...state.historyMessagePaginationBySession,
|
|
548
|
+
[sessionId]: {
|
|
549
|
+
...current,
|
|
550
|
+
isLoadingPrevious: isLoading,
|
|
551
|
+
error: error2
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
},
|
|
556
|
+
setHistorySessionMessageLoadStatus: (sessionId, status, error2 = null) => {
|
|
557
|
+
const state = get();
|
|
558
|
+
set({
|
|
559
|
+
sessionMessageLoadStatusBySession: {
|
|
560
|
+
...state.sessionMessageLoadStatusBySession,
|
|
561
|
+
[sessionId]: status
|
|
562
|
+
},
|
|
563
|
+
sessionMessageLoadErrorBySession: {
|
|
564
|
+
...state.sessionMessageLoadErrorBySession,
|
|
565
|
+
[sessionId]: error2
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
},
|
|
363
569
|
startStreamingMessage: (sessionId, message) => {
|
|
364
570
|
const state = get();
|
|
365
571
|
set({
|
|
@@ -807,6 +1013,10 @@ var AiChatProvider = (props) => {
|
|
|
807
1013
|
handleQuestionnaireSubmit,
|
|
808
1014
|
handleConfirmationSubmit,
|
|
809
1015
|
messageRenderOrder,
|
|
1016
|
+
historySessionList,
|
|
1017
|
+
onLoadMoreSessions,
|
|
1018
|
+
onSelectHistorySession,
|
|
1019
|
+
onLoadMoreHistoryMessages,
|
|
810
1020
|
enableImageAttachments = true,
|
|
811
1021
|
children
|
|
812
1022
|
} = props;
|
|
@@ -883,7 +1093,11 @@ var AiChatProvider = (props) => {
|
|
|
883
1093
|
handleConfirmationSubmit,
|
|
884
1094
|
messageRenderOrder,
|
|
885
1095
|
transformStreamPacket: defaultTransformStreamPacket,
|
|
886
|
-
enableImageAttachments
|
|
1096
|
+
enableImageAttachments,
|
|
1097
|
+
historySessionList,
|
|
1098
|
+
onLoadMoreSessions,
|
|
1099
|
+
onSelectHistorySession,
|
|
1100
|
+
onLoadMoreHistoryMessages
|
|
887
1101
|
}),
|
|
888
1102
|
[
|
|
889
1103
|
axiosInstance,
|
|
@@ -893,8 +1107,12 @@ var AiChatProvider = (props) => {
|
|
|
893
1107
|
enableImageAttachments,
|
|
894
1108
|
handleConfirmationSubmit,
|
|
895
1109
|
handleQuestionnaireSubmit,
|
|
1110
|
+
historySessionList,
|
|
896
1111
|
labels,
|
|
897
1112
|
messageRenderOrder,
|
|
1113
|
+
onLoadMoreSessions,
|
|
1114
|
+
onLoadMoreHistoryMessages,
|
|
1115
|
+
onSelectHistorySession,
|
|
898
1116
|
renderMessageBlock,
|
|
899
1117
|
sendRef,
|
|
900
1118
|
retryRef,
|
|
@@ -1338,6 +1556,14 @@ var createTimelineAnchorState = ({
|
|
|
1338
1556
|
timelineBlockAnchors: {},
|
|
1339
1557
|
visibleTimelineBlockKeys: {}
|
|
1340
1558
|
});
|
|
1559
|
+
var createInitialTimelineAnchorState = ({
|
|
1560
|
+
messageId
|
|
1561
|
+
}) => ({
|
|
1562
|
+
messageId,
|
|
1563
|
+
previousBlockKeys: [],
|
|
1564
|
+
timelineBlockAnchors: {},
|
|
1565
|
+
visibleTimelineBlockKeys: {}
|
|
1566
|
+
});
|
|
1341
1567
|
var timelineAnchorReducer = (state, action) => {
|
|
1342
1568
|
switch (action.type) {
|
|
1343
1569
|
case "reset-message":
|
|
@@ -1427,7 +1653,7 @@ var useTimelineBlockAnchors = ({
|
|
|
1427
1653
|
messageId: message.id,
|
|
1428
1654
|
currentBlockKeys: currentTimelineBlockKeys
|
|
1429
1655
|
},
|
|
1430
|
-
|
|
1656
|
+
createInitialTimelineAnchorState
|
|
1431
1657
|
);
|
|
1432
1658
|
const effectiveTimelineBlockAnchors = (0, import_react6.useMemo)(() => {
|
|
1433
1659
|
if (messageRenderOrder !== "timeline" || !isAssistantStreaming) {
|
|
@@ -3198,15 +3424,11 @@ var Bubble = import_styled7.default.article`
|
|
|
3198
3424
|
|
|
3199
3425
|
&[data-role='user'] {
|
|
3200
3426
|
width: auto;
|
|
3201
|
-
max-width:
|
|
3427
|
+
max-width: 100%;
|
|
3202
3428
|
margin-left: auto;
|
|
3203
|
-
padding:
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
border: 1px solid rgba(255, 255, 255, 0.07);
|
|
3207
|
-
box-shadow:
|
|
3208
|
-
inset 0 1px 0 rgba(255, 255, 255, 0.03),
|
|
3209
|
-
0 12px 30px rgba(0, 0, 0, 0.18);
|
|
3429
|
+
padding: 8px 12px;
|
|
3430
|
+
background: #282825;
|
|
3431
|
+
border-radius: 16px;
|
|
3210
3432
|
}
|
|
3211
3433
|
`;
|
|
3212
3434
|
var Header2 = import_styled7.default.div`
|
|
@@ -3538,6 +3760,7 @@ var HeroSubtitle = import_styled8.default.p`
|
|
|
3538
3760
|
// src/components/chat-thread/index.tsx
|
|
3539
3761
|
var import_jsx_runtime10 = require("@emotion/react/jsx-runtime");
|
|
3540
3762
|
var CHAT_THREAD_PINNED_THRESHOLD_PX = 32;
|
|
3763
|
+
var CHAT_THREAD_LOAD_PREVIOUS_THRESHOLD_PX = 80;
|
|
3541
3764
|
var isThreadPinnedToBottom = (container) => container.scrollHeight - container.clientHeight - container.scrollTop <= CHAT_THREAD_PINNED_THRESHOLD_PX;
|
|
3542
3765
|
var renderChatMessage = ({
|
|
3543
3766
|
message,
|
|
@@ -3611,9 +3834,13 @@ var ChatThreadView = ({
|
|
|
3611
3834
|
historyMessages,
|
|
3612
3835
|
streamingMessage,
|
|
3613
3836
|
error: error2,
|
|
3837
|
+
isLoadingPreviousMessages = false,
|
|
3838
|
+
previousMessagesError,
|
|
3614
3839
|
retryButtonLabel,
|
|
3615
3840
|
scrollToLatestLabel,
|
|
3841
|
+
sessionHistoryLoadingLabel,
|
|
3616
3842
|
onRetry,
|
|
3843
|
+
onLoadPreviousMessages,
|
|
3617
3844
|
onConfirmationSubmit,
|
|
3618
3845
|
onQuestionnaireSubmit,
|
|
3619
3846
|
renderMessageBlock
|
|
@@ -3624,11 +3851,11 @@ var ChatThreadView = ({
|
|
|
3624
3851
|
[historyMessages, streamingMessage]
|
|
3625
3852
|
);
|
|
3626
3853
|
const latestTurn = conversationTurns[conversationTurns.length - 1];
|
|
3627
|
-
const previousTurns = conversationTurns.slice(0, -1);
|
|
3628
3854
|
const latestUserMessageId = latestTurn?.userMessage?.id;
|
|
3629
3855
|
const latestHistoryMessage = historyMessages[historyMessages.length - 1];
|
|
3630
3856
|
const latestTurnRef = (0, import_react11.useRef)(null);
|
|
3631
3857
|
const reservedSpaceFrameRef = (0, import_react11.useRef)(null);
|
|
3858
|
+
const isLoadingPreviousRef = (0, import_react11.useRef)(false);
|
|
3632
3859
|
const isPinnedRef = (0, import_react11.useRef)(true);
|
|
3633
3860
|
const lastHistoryMessageIdRef = (0, import_react11.useRef)(latestHistoryMessage?.id);
|
|
3634
3861
|
const lastStreamingMessageIdRef = (0, import_react11.useRef)(streamingMessage?.id);
|
|
@@ -3675,17 +3902,45 @@ var ChatThreadView = ({
|
|
|
3675
3902
|
},
|
|
3676
3903
|
[markThreadPinned, scrollToBottom]
|
|
3677
3904
|
);
|
|
3905
|
+
const handleLoadPreviousMessages = (0, import_react11.useCallback)(async () => {
|
|
3906
|
+
const container = containerRef.current;
|
|
3907
|
+
if (!container || !onLoadPreviousMessages || isLoadingPreviousMessages) {
|
|
3908
|
+
return;
|
|
3909
|
+
}
|
|
3910
|
+
if (isLoadingPreviousRef.current) {
|
|
3911
|
+
return;
|
|
3912
|
+
}
|
|
3913
|
+
isLoadingPreviousRef.current = true;
|
|
3914
|
+
const previousScrollHeight = container.scrollHeight;
|
|
3915
|
+
const previousScrollTop = container.scrollTop;
|
|
3916
|
+
try {
|
|
3917
|
+
await onLoadPreviousMessages();
|
|
3918
|
+
} catch {
|
|
3919
|
+
return;
|
|
3920
|
+
} finally {
|
|
3921
|
+
isLoadingPreviousRef.current = false;
|
|
3922
|
+
}
|
|
3923
|
+
window.requestAnimationFrame(() => {
|
|
3924
|
+
const nextContainer = containerRef.current;
|
|
3925
|
+
if (!nextContainer)
|
|
3926
|
+
return;
|
|
3927
|
+
nextContainer.scrollTop = nextContainer.scrollHeight - previousScrollHeight + previousScrollTop;
|
|
3928
|
+
});
|
|
3929
|
+
}, [isLoadingPreviousMessages, onLoadPreviousMessages]);
|
|
3678
3930
|
const handleContainerScroll = (0, import_react11.useCallback)(() => {
|
|
3679
3931
|
const container = containerRef.current;
|
|
3680
3932
|
if (!container)
|
|
3681
3933
|
return;
|
|
3934
|
+
if (onLoadPreviousMessages && container.scrollTop <= CHAT_THREAD_LOAD_PREVIOUS_THRESHOLD_PX) {
|
|
3935
|
+
void handleLoadPreviousMessages();
|
|
3936
|
+
}
|
|
3682
3937
|
const nextPinned = isThreadPinnedToBottom(container);
|
|
3683
3938
|
isPinnedRef.current = nextPinned;
|
|
3684
3939
|
setIsDetached(!nextPinned);
|
|
3685
3940
|
if (nextPinned) {
|
|
3686
3941
|
setPendingNewMessageCount(0);
|
|
3687
3942
|
}
|
|
3688
|
-
}, []);
|
|
3943
|
+
}, [handleLoadPreviousMessages, onLoadPreviousMessages]);
|
|
3689
3944
|
(0, import_react11.useLayoutEffect)(() => {
|
|
3690
3945
|
const nextHistoryMessageId = latestHistoryMessage?.id;
|
|
3691
3946
|
if (lastHistoryMessageIdRef.current === nextHistoryMessageId) {
|
|
@@ -3813,54 +4068,44 @@ var ChatThreadView = ({
|
|
|
3813
4068
|
}, [latestTurn, scrollToBottom]);
|
|
3814
4069
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(ThreadViewport, { children: [
|
|
3815
4070
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Container, { ref: containerRef, "data-testid": "chat-thread", onScroll: handleContainerScroll, children: [
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
{
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
message,
|
|
3855
|
-
mode: activeSessionMode,
|
|
3856
|
-
onConfirmationSubmit,
|
|
3857
|
-
onQuestionnaireSubmit,
|
|
3858
|
-
renderMessageBlock
|
|
3859
|
-
}) }, message.id)),
|
|
3860
|
-
error2 ? renderErrorState({ error: error2, onRetry, retryButtonLabel }) : null
|
|
3861
|
-
]
|
|
3862
|
-
}
|
|
3863
|
-
) : null,
|
|
4071
|
+
isLoadingPreviousMessages ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PreviousMessagesStateRow, { "data-testid": "chat-thread-loading-previous", children: sessionHistoryLoadingLabel }) : null,
|
|
4072
|
+
previousMessagesError ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PreviousMessagesStateRow, { "data-testid": "chat-thread-load-previous-error", children: previousMessagesError }) : null,
|
|
4073
|
+
conversationTurns.map((turn, turnIndex) => {
|
|
4074
|
+
const isLatestTurn = turnIndex === conversationTurns.length - 1;
|
|
4075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
4076
|
+
ConversationTurn,
|
|
4077
|
+
{
|
|
4078
|
+
ref: isLatestTurn ? latestTurnRef : null,
|
|
4079
|
+
"data-testid": isLatestTurn ? "chat-thread-latest-turn" : "chat-thread-turn",
|
|
4080
|
+
style: isLatestTurn && latestTurnMinHeight > 0 ? { minHeight: `${latestTurnMinHeight}px` } : void 0,
|
|
4081
|
+
children: [
|
|
4082
|
+
turn.userMessage ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4083
|
+
MessageSlot,
|
|
4084
|
+
{
|
|
4085
|
+
"data-testid": isLatestTurn ? "chat-latest-user-anchor" : void 0,
|
|
4086
|
+
style: isLatestTurn ? { scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px` } : void 0,
|
|
4087
|
+
children: renderChatMessage({
|
|
4088
|
+
message: turn.userMessage,
|
|
4089
|
+
mode: activeSessionMode,
|
|
4090
|
+
onConfirmationSubmit,
|
|
4091
|
+
onQuestionnaireSubmit,
|
|
4092
|
+
renderMessageBlock
|
|
4093
|
+
})
|
|
4094
|
+
}
|
|
4095
|
+
) : null,
|
|
4096
|
+
turn.responseMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageSlot, { children: renderChatMessage({
|
|
4097
|
+
message,
|
|
4098
|
+
mode: activeSessionMode,
|
|
4099
|
+
onConfirmationSubmit,
|
|
4100
|
+
onQuestionnaireSubmit,
|
|
4101
|
+
renderMessageBlock
|
|
4102
|
+
}) }, message.id)),
|
|
4103
|
+
isLatestTurn && error2 ? renderErrorState({ error: error2, onRetry, retryButtonLabel }) : null
|
|
4104
|
+
]
|
|
4105
|
+
},
|
|
4106
|
+
turn.id
|
|
4107
|
+
);
|
|
4108
|
+
}),
|
|
3864
4109
|
!latestTurn && error2 ? renderErrorState({ error: error2, onRetry, retryButtonLabel }) : null
|
|
3865
4110
|
] }),
|
|
3866
4111
|
isDetached ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScrollToLatestOverlay, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
@@ -3881,14 +4126,25 @@ var EMPTY_MESSAGES = [];
|
|
|
3881
4126
|
var ChatThread = () => {
|
|
3882
4127
|
const activeSessionId = useChatStore((s) => s.activeSessionId);
|
|
3883
4128
|
const hasSessions = useChatStore((s) => s.sessions.length > 0);
|
|
3884
|
-
const
|
|
3885
|
-
(s) => s.sessions.find((
|
|
4129
|
+
const activeSession = useChatStore(
|
|
4130
|
+
(s) => s.sessions.find((session) => session.sessionId === s.activeSessionId)
|
|
3886
4131
|
);
|
|
4132
|
+
const activeSessionMode = activeSession?.mode ?? DEFAULT_CHAT_AGENT_MODE;
|
|
3887
4133
|
const messages = useChatStore(
|
|
3888
4134
|
(s) => s.messagesBySession[s.activeSessionId ?? ""] ?? EMPTY_MESSAGES
|
|
3889
4135
|
);
|
|
4136
|
+
const sessionMessageLoadStatus = useChatStore(
|
|
4137
|
+
(s) => s.sessionMessageLoadStatusBySession[s.activeSessionId ?? ""]
|
|
4138
|
+
);
|
|
3890
4139
|
const streamingMessage = useChatStore((s) => s.streamingMessageBySession[s.activeSessionId ?? ""]);
|
|
3891
4140
|
const error2 = useChatStore((s) => s.errorBySession[s.activeSessionId ?? ""]);
|
|
4141
|
+
const historyMessagePagination = useChatStore(
|
|
4142
|
+
(s) => s.historyMessagePaginationBySession[s.activeSessionId ?? ""]
|
|
4143
|
+
);
|
|
4144
|
+
const prependHistorySessionMessagesPage = useChatStore((s) => s.prependHistorySessionMessagesPage);
|
|
4145
|
+
const setHistorySessionPreviousMessagesLoadStatus = useChatStore(
|
|
4146
|
+
(s) => s.setHistorySessionPreviousMessagesLoadStatus
|
|
4147
|
+
);
|
|
3892
4148
|
const updateQA = useChatStore((s) => s.updateQuestionnaireAnswers);
|
|
3893
4149
|
const clearSessionError = useChatStore((s) => s.clearSessionError);
|
|
3894
4150
|
const {
|
|
@@ -3897,6 +4153,7 @@ var ChatThread = () => {
|
|
|
3897
4153
|
renderMessageBlock,
|
|
3898
4154
|
handleQuestionnaireSubmit: customQuestionnaireSubmit,
|
|
3899
4155
|
handleConfirmationSubmit: customConfirmationSubmit,
|
|
4156
|
+
onLoadMoreHistoryMessages,
|
|
3900
4157
|
labels
|
|
3901
4158
|
} = useChatContext();
|
|
3902
4159
|
const handleRetry = (0, import_react11.useCallback)(() => {
|
|
@@ -3959,6 +4216,42 @@ var ChatThread = () => {
|
|
|
3959
4216
|
},
|
|
3960
4217
|
[activeSessionId, activeSessionMode, sendRef, customConfirmationSubmit]
|
|
3961
4218
|
);
|
|
4219
|
+
const handleLoadPreviousMessages = (0, import_react11.useCallback)(async () => {
|
|
4220
|
+
if (!activeSession || !onLoadMoreHistoryMessages || !historyMessagePagination?.hasMorePrevious || !historyMessagePagination.previousCursor || historyMessagePagination.isLoadingPrevious) {
|
|
4221
|
+
return;
|
|
4222
|
+
}
|
|
4223
|
+
setHistorySessionPreviousMessagesLoadStatus(activeSession.sessionId, true);
|
|
4224
|
+
try {
|
|
4225
|
+
const page = await onLoadMoreHistoryMessages({
|
|
4226
|
+
session: activeSession,
|
|
4227
|
+
cursor: historyMessagePagination.previousCursor
|
|
4228
|
+
});
|
|
4229
|
+
if (page) {
|
|
4230
|
+
prependHistorySessionMessagesPage(activeSession.sessionId, page);
|
|
4231
|
+
return;
|
|
4232
|
+
}
|
|
4233
|
+
setHistorySessionPreviousMessagesLoadStatus(activeSession.sessionId, false);
|
|
4234
|
+
} catch (error3) {
|
|
4235
|
+
setHistorySessionPreviousMessagesLoadStatus(
|
|
4236
|
+
activeSession.sessionId,
|
|
4237
|
+
false,
|
|
4238
|
+
error3 instanceof Error ? error3.message : String(error3)
|
|
4239
|
+
);
|
|
4240
|
+
throw error3;
|
|
4241
|
+
}
|
|
4242
|
+
}, [
|
|
4243
|
+
activeSession,
|
|
4244
|
+
historyMessagePagination,
|
|
4245
|
+
onLoadMoreHistoryMessages,
|
|
4246
|
+
prependHistorySessionMessagesPage,
|
|
4247
|
+
setHistorySessionPreviousMessagesLoadStatus
|
|
4248
|
+
]);
|
|
4249
|
+
const canLoadPreviousMessages = Boolean(
|
|
4250
|
+
activeSession && onLoadMoreHistoryMessages && historyMessagePagination?.hasMorePrevious && historyMessagePagination.previousCursor && !historyMessagePagination.isLoadingPrevious
|
|
4251
|
+
);
|
|
4252
|
+
if (hasSessions && sessionMessageLoadStatus === "loading" && messages.length === 0 && !streamingMessage) {
|
|
4253
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ThreadStateViewport, { "data-testid": "chat-thread-loading-state", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ThreadStateText, { children: labels.sessionHistoryLoading }) });
|
|
4254
|
+
}
|
|
3962
4255
|
if (!hasSessions || messages.length === 0 && !streamingMessage) {
|
|
3963
4256
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChatThreadEmptyState, {});
|
|
3964
4257
|
}
|
|
@@ -3969,9 +4262,13 @@ var ChatThread = () => {
|
|
|
3969
4262
|
historyMessages: messages,
|
|
3970
4263
|
streamingMessage,
|
|
3971
4264
|
error: error2,
|
|
4265
|
+
isLoadingPreviousMessages: historyMessagePagination?.isLoadingPrevious,
|
|
4266
|
+
previousMessagesError: historyMessagePagination?.error,
|
|
3972
4267
|
retryButtonLabel: labels.retryButton,
|
|
3973
4268
|
scrollToLatestLabel: labels.scrollToLatest,
|
|
4269
|
+
sessionHistoryLoadingLabel: labels.sessionHistoryLoading,
|
|
3974
4270
|
onRetry: handleRetry,
|
|
4271
|
+
onLoadPreviousMessages: canLoadPreviousMessages ? handleLoadPreviousMessages : void 0,
|
|
3975
4272
|
onConfirmationSubmit: handleConfirmation,
|
|
3976
4273
|
onQuestionnaireSubmit: handleQuestionnaireSubmit,
|
|
3977
4274
|
renderMessageBlock
|
|
@@ -3985,6 +4282,18 @@ var ThreadViewport = import_styled9.default.div`
|
|
|
3985
4282
|
flex: 1;
|
|
3986
4283
|
min-height: 0;
|
|
3987
4284
|
`;
|
|
4285
|
+
var ThreadStateViewport = import_styled9.default.div`
|
|
4286
|
+
display: flex;
|
|
4287
|
+
flex: 1;
|
|
4288
|
+
min-height: 0;
|
|
4289
|
+
align-items: center;
|
|
4290
|
+
justify-content: center;
|
|
4291
|
+
padding: 24px;
|
|
4292
|
+
`;
|
|
4293
|
+
var ThreadStateText = import_styled9.default.div`
|
|
4294
|
+
color: var(--text-secondary, rgba(255, 255, 255, 0.64));
|
|
4295
|
+
font-size: 14px;
|
|
4296
|
+
`;
|
|
3988
4297
|
var Container = import_styled9.default.div`
|
|
3989
4298
|
display: flex;
|
|
3990
4299
|
flex: 1;
|
|
@@ -3992,7 +4301,7 @@ var Container = import_styled9.default.div`
|
|
|
3992
4301
|
gap: 18px;
|
|
3993
4302
|
min-height: 0;
|
|
3994
4303
|
overflow: auto;
|
|
3995
|
-
padding: 24px
|
|
4304
|
+
padding: 24px 16px 88px;
|
|
3996
4305
|
overscroll-behavior: contain;
|
|
3997
4306
|
|
|
3998
4307
|
&::-webkit-scrollbar {
|
|
@@ -4011,10 +4320,23 @@ var Container = import_styled9.default.div`
|
|
|
4011
4320
|
var MessageSlot = import_styled9.default.div`
|
|
4012
4321
|
display: flex;
|
|
4013
4322
|
`;
|
|
4323
|
+
var PreviousMessagesStateRow = import_styled9.default.div`
|
|
4324
|
+
width: 100%;
|
|
4325
|
+
max-width: var(--chat-content-max-width, 48rem);
|
|
4326
|
+
margin-right: auto;
|
|
4327
|
+
margin-left: auto;
|
|
4328
|
+
color: var(--text-secondary, rgba(255, 255, 255, 0.64));
|
|
4329
|
+
font-size: 13px;
|
|
4330
|
+
text-align: center;
|
|
4331
|
+
`;
|
|
4014
4332
|
var ConversationTurn = import_styled9.default.div`
|
|
4015
4333
|
display: flex;
|
|
4016
4334
|
flex-direction: column;
|
|
4017
4335
|
gap: 18px;
|
|
4336
|
+
width: 100%;
|
|
4337
|
+
max-width: var(--chat-content-max-width, 48rem);
|
|
4338
|
+
margin-right: auto;
|
|
4339
|
+
margin-left: auto;
|
|
4018
4340
|
`;
|
|
4019
4341
|
var ErrorText = import_styled9.default.div`
|
|
4020
4342
|
color: #ff7b72;
|
|
@@ -7802,7 +8124,7 @@ var PrimaryButton = (0, import_styled13.default)(import_compass_ui3.Button)`
|
|
|
7802
8124
|
min-width: 24px;
|
|
7803
8125
|
width: 24px;
|
|
7804
8126
|
height: 24px;
|
|
7805
|
-
background: ${({ $canSend }) => $canSend ? "#fcfbf8" : "rgba(
|
|
8127
|
+
background: ${({ $canSend }) => $canSend ? "#fcfbf8" : "rgba(252,251,248,0.3);"};
|
|
7806
8128
|
color: ${({ $canSend }) => $canSend ? "#5b5448" : "rgba(255, 255, 255, 0.72)"};
|
|
7807
8129
|
border-radius: 12px;
|
|
7808
8130
|
border: 1px solid ${({ $canSend }) => $canSend ? "rgba(198, 188, 170, 0.38)" : "transparent"};
|
|
@@ -7813,7 +8135,7 @@ var PrimaryButton = (0, import_styled13.default)(import_compass_ui3.Button)`
|
|
|
7813
8135
|
}
|
|
7814
8136
|
|
|
7815
8137
|
&:hover:not(:disabled) {
|
|
7816
|
-
background: ${({ $canSend }) => $canSend ? "#f7f4ec" : "rgba(
|
|
8138
|
+
background: ${({ $canSend }) => $canSend ? "#f7f4ec" : "rgba(252,251,248,0.3);"};
|
|
7817
8139
|
color: ${({ $canSend }) => $canSend ? "#4f493f" : "rgba(255, 255, 255, 0.72)"};
|
|
7818
8140
|
border-color: ${({ $canSend }) => $canSend ? "rgba(198, 188, 170, 0.46)" : "transparent"};
|
|
7819
8141
|
}
|
|
@@ -7881,7 +8203,7 @@ var StopSpinner = import_styled13.default.span`
|
|
|
7881
8203
|
var import_jsx_runtime16 = require("@emotion/react/jsx-runtime");
|
|
7882
8204
|
var CHAT_COMPOSER_LINE_HEIGHT_PX = 20;
|
|
7883
8205
|
var CHAT_COMPOSER_MAX_ROWS = 7;
|
|
7884
|
-
var CHAT_COMPOSER_PADDING_TOP_PX =
|
|
8206
|
+
var CHAT_COMPOSER_PADDING_TOP_PX = 12;
|
|
7885
8207
|
var CHAT_COMPOSER_PADDING_BOTTOM_PX = 12;
|
|
7886
8208
|
var CHAT_COMPOSER_PADDING_BLOCK_PX = CHAT_COMPOSER_PADDING_TOP_PX + CHAT_COMPOSER_PADDING_BOTTOM_PX;
|
|
7887
8209
|
var CHAT_COMPOSER_MIN_ROWS = 4;
|
|
@@ -8116,6 +8438,10 @@ var ChatComposerView = ({
|
|
|
8116
8438
|
setActiveSkillNavigation({ queryKey: "", index: 0 });
|
|
8117
8439
|
};
|
|
8118
8440
|
const handleKeyDown = (event) => {
|
|
8441
|
+
const isImeComposing = event.nativeEvent.isComposing || event.keyCode === 229;
|
|
8442
|
+
if (event.key === "Enter" && isImeComposing) {
|
|
8443
|
+
return;
|
|
8444
|
+
}
|
|
8119
8445
|
if (skillQueryMatch) {
|
|
8120
8446
|
if (event.key === "ArrowDown" && filteredSkills.length > 0) {
|
|
8121
8447
|
event.preventDefault();
|
|
@@ -8393,7 +8719,7 @@ var Surface = import_styled14.default.div`
|
|
|
8393
8719
|
'input'
|
|
8394
8720
|
'footer';
|
|
8395
8721
|
width: 100%;
|
|
8396
|
-
max-width:
|
|
8722
|
+
max-width: var(--chat-content-max-width, 48rem);
|
|
8397
8723
|
margin: 0 auto;
|
|
8398
8724
|
background: var(--border-color);
|
|
8399
8725
|
border-radius: 20px;
|
|
@@ -8654,6 +8980,7 @@ var SkillButton = import_styled14.default.button`
|
|
|
8654
8980
|
`;
|
|
8655
8981
|
|
|
8656
8982
|
// src/components/chat-conversation-list/index.tsx
|
|
8983
|
+
var import_react20 = require("react");
|
|
8657
8984
|
var import_styled16 = __toESM(require("@emotion/styled"));
|
|
8658
8985
|
|
|
8659
8986
|
// src/components/chat-conversation-list/components/chat-session-item.tsx
|
|
@@ -8667,6 +8994,7 @@ var ChatSessionItem = (0, import_react19.memo)(
|
|
|
8667
8994
|
{
|
|
8668
8995
|
type: "button",
|
|
8669
8996
|
"data-active": isActive,
|
|
8997
|
+
"data-testid": `chat-session-item-${session.sessionId}`,
|
|
8670
8998
|
onClick: () => onClick(session.sessionId),
|
|
8671
8999
|
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(SessionMeta, { children: [
|
|
8672
9000
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SessionTitle, { children: session.title }),
|
|
@@ -8714,14 +9042,130 @@ var ModeBadge = import_styled15.default.span`
|
|
|
8714
9042
|
background: rgba(255, 255, 255, 0.04);
|
|
8715
9043
|
`;
|
|
8716
9044
|
|
|
9045
|
+
// src/components/chat-conversation-list/lib/history-session-selection.ts
|
|
9046
|
+
var shouldLoadHistorySessionMessages = ({
|
|
9047
|
+
sessionId,
|
|
9048
|
+
messagesBySession,
|
|
9049
|
+
loadStatusBySession,
|
|
9050
|
+
isStreamingBySession
|
|
9051
|
+
}) => {
|
|
9052
|
+
if (isStreamingBySession[sessionId])
|
|
9053
|
+
return false;
|
|
9054
|
+
if (loadStatusBySession[sessionId] === "loading")
|
|
9055
|
+
return false;
|
|
9056
|
+
if (loadStatusBySession[sessionId] === "error")
|
|
9057
|
+
return true;
|
|
9058
|
+
if (loadStatusBySession[sessionId] === "loaded")
|
|
9059
|
+
return false;
|
|
9060
|
+
return messagesBySession[sessionId] === void 0;
|
|
9061
|
+
};
|
|
9062
|
+
|
|
8717
9063
|
// src/components/chat-conversation-list/index.tsx
|
|
8718
9064
|
var import_jsx_runtime18 = require("@emotion/react/jsx-runtime");
|
|
9065
|
+
var SCROLL_LOAD_MORE_THRESHOLD_PX = 80;
|
|
9066
|
+
var shouldLoadMoreSessions = ({
|
|
9067
|
+
scrollTop,
|
|
9068
|
+
clientHeight,
|
|
9069
|
+
scrollHeight,
|
|
9070
|
+
threshold = SCROLL_LOAD_MORE_THRESHOLD_PX
|
|
9071
|
+
}) => scrollHeight - scrollTop - clientHeight <= threshold;
|
|
9072
|
+
var isHistorySessionMessagesPage = (value) => typeof value === "object" && value !== null && Array.isArray(value.messages);
|
|
8719
9073
|
var ChatConversationList = () => {
|
|
8720
|
-
const { labels } = useChatContext();
|
|
8721
|
-
const
|
|
9074
|
+
const { labels, historySessionList, onLoadMoreSessions, onSelectHistorySession, store } = useChatContext();
|
|
9075
|
+
const localSessions = useChatStore((s) => s.sessions);
|
|
8722
9076
|
const activeSessionId = useChatStore((s) => s.activeSessionId);
|
|
8723
9077
|
const startNewChat = useChatStore((s) => s.startNewChat);
|
|
8724
9078
|
const setActiveSession = useChatStore((s) => s.setActiveSession);
|
|
9079
|
+
const hydrateHistorySessions = useChatStore((s) => s.hydrateHistorySessions);
|
|
9080
|
+
const hydrateHistorySessionMessages = useChatStore((s) => s.hydrateHistorySessionMessages);
|
|
9081
|
+
const hydrateHistorySessionMessagesPage = useChatStore((s) => s.hydrateHistorySessionMessagesPage);
|
|
9082
|
+
const setHistorySessionMessageLoadStatus = useChatStore(
|
|
9083
|
+
(s) => s.setHistorySessionMessageLoadStatus
|
|
9084
|
+
);
|
|
9085
|
+
const isLoadingMoreRef = (0, import_react20.useRef)(false);
|
|
9086
|
+
const hasSeenLoadingMoreRef = (0, import_react20.useRef)(false);
|
|
9087
|
+
(0, import_react20.useEffect)(() => {
|
|
9088
|
+
if (!historySessionList)
|
|
9089
|
+
return;
|
|
9090
|
+
hydrateHistorySessions(historySessionList.sessions);
|
|
9091
|
+
}, [historySessionList, hydrateHistorySessions]);
|
|
9092
|
+
(0, import_react20.useEffect)(() => {
|
|
9093
|
+
if (historySessionList?.isLoading) {
|
|
9094
|
+
hasSeenLoadingMoreRef.current = true;
|
|
9095
|
+
return;
|
|
9096
|
+
}
|
|
9097
|
+
if (hasSeenLoadingMoreRef.current) {
|
|
9098
|
+
hasSeenLoadingMoreRef.current = false;
|
|
9099
|
+
isLoadingMoreRef.current = false;
|
|
9100
|
+
}
|
|
9101
|
+
}, [historySessionList?.isLoading]);
|
|
9102
|
+
(0, import_react20.useEffect)(() => {
|
|
9103
|
+
isLoadingMoreRef.current = false;
|
|
9104
|
+
hasSeenLoadingMoreRef.current = false;
|
|
9105
|
+
}, [historySessionList?.sessions.length, historySessionList?.hasMore]);
|
|
9106
|
+
const sessions = (0, import_react20.useMemo)(() => {
|
|
9107
|
+
if (!historySessionList) {
|
|
9108
|
+
return localSessions;
|
|
9109
|
+
}
|
|
9110
|
+
const localSessionIds = new Set(localSessions.map((session) => session.sessionId));
|
|
9111
|
+
return [
|
|
9112
|
+
...localSessions,
|
|
9113
|
+
...historySessionList.sessions.filter((session) => !localSessionIds.has(session.sessionId))
|
|
9114
|
+
];
|
|
9115
|
+
}, [historySessionList, localSessions]);
|
|
9116
|
+
const handleSessionListScroll = (event) => {
|
|
9117
|
+
if (!historySessionList?.hasMore || historySessionList.isLoading || !onLoadMoreSessions || isLoadingMoreRef.current) {
|
|
9118
|
+
return;
|
|
9119
|
+
}
|
|
9120
|
+
const target = event.currentTarget;
|
|
9121
|
+
if (shouldLoadMoreSessions({
|
|
9122
|
+
scrollTop: target.scrollTop,
|
|
9123
|
+
clientHeight: target.clientHeight,
|
|
9124
|
+
scrollHeight: target.scrollHeight
|
|
9125
|
+
})) {
|
|
9126
|
+
isLoadingMoreRef.current = true;
|
|
9127
|
+
void Promise.resolve(onLoadMoreSessions()).catch(() => {
|
|
9128
|
+
isLoadingMoreRef.current = false;
|
|
9129
|
+
hasSeenLoadingMoreRef.current = false;
|
|
9130
|
+
});
|
|
9131
|
+
}
|
|
9132
|
+
};
|
|
9133
|
+
const handleSelectSession = async (sessionId) => {
|
|
9134
|
+
setActiveSession(sessionId);
|
|
9135
|
+
const session = sessions.find((item) => item.sessionId === sessionId);
|
|
9136
|
+
if (!session || !onSelectHistorySession) {
|
|
9137
|
+
return;
|
|
9138
|
+
}
|
|
9139
|
+
const state = store.getState();
|
|
9140
|
+
const shouldLoad = shouldLoadHistorySessionMessages({
|
|
9141
|
+
sessionId,
|
|
9142
|
+
messagesBySession: state.messagesBySession,
|
|
9143
|
+
loadStatusBySession: state.sessionMessageLoadStatusBySession,
|
|
9144
|
+
isStreamingBySession: state.isStreamingBySession
|
|
9145
|
+
});
|
|
9146
|
+
if (!shouldLoad) {
|
|
9147
|
+
return;
|
|
9148
|
+
}
|
|
9149
|
+
setHistorySessionMessageLoadStatus(sessionId, "loading");
|
|
9150
|
+
try {
|
|
9151
|
+
const result = await onSelectHistorySession(session);
|
|
9152
|
+
if (Array.isArray(result)) {
|
|
9153
|
+
hydrateHistorySessionMessages(sessionId, result);
|
|
9154
|
+
return;
|
|
9155
|
+
}
|
|
9156
|
+
if (isHistorySessionMessagesPage(result)) {
|
|
9157
|
+
hydrateHistorySessionMessagesPage(sessionId, result);
|
|
9158
|
+
return;
|
|
9159
|
+
}
|
|
9160
|
+
setHistorySessionMessageLoadStatus(sessionId, "loaded");
|
|
9161
|
+
} catch (error2) {
|
|
9162
|
+
setHistorySessionMessageLoadStatus(
|
|
9163
|
+
sessionId,
|
|
9164
|
+
"error",
|
|
9165
|
+
error2 instanceof Error ? error2.message : String(error2)
|
|
9166
|
+
);
|
|
9167
|
+
}
|
|
9168
|
+
};
|
|
8725
9169
|
const modeLabels = {
|
|
8726
9170
|
ask: labels.modeLabelAsk,
|
|
8727
9171
|
plan: labels.modeLabelPlan,
|
|
@@ -8732,16 +9176,21 @@ var ChatConversationList = () => {
|
|
|
8732
9176
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Title3, { children: "Sessions" }),
|
|
8733
9177
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CreateButton, { type: "button", "data-testid": "chat-create-session", onClick: startNewChat, children: labels.newChat })
|
|
8734
9178
|
] }),
|
|
8735
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
|
|
9179
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(List2, { "data-testid": "chat-session-list", onScroll: handleSessionListScroll, children: [
|
|
9180
|
+
sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
9181
|
+
ChatSessionItem,
|
|
9182
|
+
{
|
|
9183
|
+
session,
|
|
9184
|
+
isActive: activeSessionId === session.sessionId,
|
|
9185
|
+
modeLabel: modeLabels[session.mode ?? DEFAULT_CHAT_AGENT_MODE] ?? "",
|
|
9186
|
+
onClick: (sessionId) => void handleSelectSession(sessionId)
|
|
9187
|
+
},
|
|
9188
|
+
session.sessionId
|
|
9189
|
+
)),
|
|
9190
|
+
historySessionList?.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StateRow, { "data-testid": "chat-session-history-loading", children: labels.sessionHistoryLoading }) : null,
|
|
9191
|
+
historySessionList?.error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StateRow, { "data-testid": "chat-session-history-error", children: historySessionList.error || labels.sessionHistoryLoadFailed }) : null,
|
|
9192
|
+
historySessionList && !historySessionList.isLoading && !historySessionList.error && sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StateRow, { "data-testid": "chat-session-history-empty", children: labels.sessionHistoryEmpty }) : null
|
|
9193
|
+
] })
|
|
8745
9194
|
] });
|
|
8746
9195
|
};
|
|
8747
9196
|
var Container3 = import_styled16.default.aside`
|
|
@@ -8779,6 +9228,11 @@ var List2 = import_styled16.default.div`
|
|
|
8779
9228
|
gap: 8px;
|
|
8780
9229
|
overflow: auto;
|
|
8781
9230
|
`;
|
|
9231
|
+
var StateRow = import_styled16.default.div`
|
|
9232
|
+
padding: 12px;
|
|
9233
|
+
font-size: 13px;
|
|
9234
|
+
color: var(--text-secondary);
|
|
9235
|
+
`;
|
|
8782
9236
|
|
|
8783
9237
|
// src/components/ai-chat/index.tsx
|
|
8784
9238
|
var import_jsx_runtime19 = require("@emotion/react/jsx-runtime");
|
|
@@ -8840,7 +9294,7 @@ var AiChatWorkspaceContent = ({
|
|
|
8840
9294
|
})
|
|
8841
9295
|
);
|
|
8842
9296
|
const shouldShowComposerOnly = showComposerOnlyBeforeFirstMessage && !showConversationList && !isConversationStarted;
|
|
8843
|
-
(0,
|
|
9297
|
+
(0, import_react21.useEffect)(() => {
|
|
8844
9298
|
onConversationStartedChange?.(isConversationStarted);
|
|
8845
9299
|
}, [isConversationStarted, onConversationStartedChange]);
|
|
8846
9300
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Root, { "data-testid": "ai-chat", children: [
|
|
@@ -8979,12 +9433,25 @@ var Root = import_styled17.default.div`
|
|
|
8979
9433
|
overflow: hidden;
|
|
8980
9434
|
`;
|
|
8981
9435
|
var Workspace = import_styled17.default.section`
|
|
9436
|
+
--chat-layout-rem: 16px;
|
|
9437
|
+
--chat-content-margin: calc(var(--chat-layout-rem) * 1);
|
|
9438
|
+
--chat-content-max-width: calc(var(--chat-layout-rem) * 40);
|
|
9439
|
+
|
|
8982
9440
|
flex: 1;
|
|
8983
9441
|
display: flex;
|
|
8984
9442
|
flex-direction: column;
|
|
8985
9443
|
gap: 12px;
|
|
8986
9444
|
min-height: 0;
|
|
8987
9445
|
overflow: hidden;
|
|
9446
|
+
|
|
9447
|
+
@media (min-width: 640px) {
|
|
9448
|
+
--chat-content-margin: calc(var(--chat-layout-rem) * 1.5);
|
|
9449
|
+
}
|
|
9450
|
+
|
|
9451
|
+
@media (min-width: 1024px) {
|
|
9452
|
+
--chat-content-margin: calc(var(--chat-layout-rem) * 4);
|
|
9453
|
+
--chat-content-max-width: calc(var(--chat-layout-rem) * 48);
|
|
9454
|
+
}
|
|
8988
9455
|
`;
|
|
8989
9456
|
var QuickActionsRow = import_styled17.default.div`
|
|
8990
9457
|
display: flex;
|