@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/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/components/ai-chat/index.tsx
2
- import { useEffect as useEffect10 } from "react";
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
- createTimelineAnchorState
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: min(760px, 100%);
3384
+ max-width: 100%;
3159
3385
  margin-left: auto;
3160
- padding: 14px 16px;
3161
- border-radius: 22px;
3162
- background: linear-gradient(180deg, rgba(59, 59, 63, 0.9) 0%, rgba(42, 43, 46, 0.92) 100%);
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
- previousTurns.map((turn) => /* @__PURE__ */ jsxs7(ConversationTurn, { "data-testid": "chat-thread-turn", children: [
3774
- turn.userMessage ? /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
3775
- message: turn.userMessage,
3776
- mode: activeSessionMode,
3777
- onConfirmationSubmit,
3778
- onQuestionnaireSubmit,
3779
- renderMessageBlock
3780
- }) }) : null,
3781
- turn.responseMessages.map((message) => /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
3782
- message,
3783
- mode: activeSessionMode,
3784
- onConfirmationSubmit,
3785
- onQuestionnaireSubmit,
3786
- renderMessageBlock
3787
- }) }, message.id))
3788
- ] }, turn.id)),
3789
- latestTurn ? /* @__PURE__ */ jsxs7(
3790
- ConversationTurn,
3791
- {
3792
- ref: latestTurnRef,
3793
- "data-testid": "chat-thread-latest-turn",
3794
- style: latestTurnMinHeight > 0 ? { minHeight: `${latestTurnMinHeight}px` } : void 0,
3795
- children: [
3796
- latestTurn.userMessage ? /* @__PURE__ */ jsx10(
3797
- MessageSlot,
3798
- {
3799
- "data-testid": "chat-latest-user-anchor",
3800
- style: { scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px` },
3801
- children: renderChatMessage({
3802
- message: latestTurn.userMessage,
3803
- mode: activeSessionMode,
3804
- onConfirmationSubmit,
3805
- onQuestionnaireSubmit,
3806
- renderMessageBlock
3807
- })
3808
- }
3809
- ) : null,
3810
- latestTurn.responseMessages.map((message) => /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
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 activeSessionMode = useChatStore(
3842
- (s) => s.sessions.find((x) => x.sessionId === s.activeSessionId)?.mode ?? DEFAULT_CHAT_AGENT_MODE
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 24px 88px;
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(255, 255, 255, 0.3)"};
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(255, 255, 255, 0.3)"};
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 = 8;
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: 760px;
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 sessions = useChatStore((s) => s.sessions);
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__ */ jsx18(List2, { "data-testid": "chat-session-list", children: sessions.map((session) => /* @__PURE__ */ jsx18(
8693
- ChatSessionItem,
8694
- {
8695
- session,
8696
- isActive: activeSessionId === session.sessionId,
8697
- modeLabel: modeLabels[session.mode ?? DEFAULT_CHAT_AGENT_MODE] ?? "",
8698
- onClick: setActiveSession
8699
- },
8700
- session.sessionId
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
- useEffect10(() => {
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;