@xinghunm/ai-chat 0.2.0 → 0.2.2

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.
Files changed (3) hide show
  1. package/dist/index.js +471 -334
  2. package/dist/index.mjs +443 -306
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/components/ai-chat/index.tsx
2
- import styled18 from "@emotion/styled";
2
+ import styled17 from "@emotion/styled";
3
3
  import { ConfigProvider } from "@xinghunm/compass-ui";
4
4
 
5
5
  // src/components/ai-chat-provider/index.tsx
@@ -590,8 +590,8 @@ var AiChatProvider = (props) => {
590
590
  };
591
591
 
592
592
  // src/components/chat-thread/index.tsx
593
- import { useCallback as useCallback2, useLayoutEffect, useMemo as useMemo3, useRef as useRef4, useState as useState5 } from "react";
594
- import styled10 from "@emotion/styled";
593
+ import { useCallback as useCallback2, useLayoutEffect, useMemo as useMemo3, useRef as useRef4, useState as useState4 } from "react";
594
+ import styled9 from "@emotion/styled";
595
595
 
596
596
  // src/context/use-chat-context.ts
597
597
  import { useContext } from "react";
@@ -609,25 +609,9 @@ var useChatStore = (selector) => {
609
609
 
610
610
  // src/components/chat-thread/lib/chat-thread.ts
611
611
  var CHAT_THREAD_SCROLL_TOP_GAP = 16;
612
- var findLatestUserMessageId = (historyMessages) => {
613
- for (let index = historyMessages.length - 1; index >= 0; index -= 1) {
614
- if (historyMessages[index]?.role === "user") {
615
- return historyMessages[index]?.id;
616
- }
617
- }
618
- return void 0;
619
- };
620
- var calculateChatThreadScrollSpacerHeight = ({
621
- containerClientHeight,
622
- containerScrollHeight,
623
- targetOffsetTop
624
- }) => Math.max(
625
- 0,
626
- targetOffsetTop - CHAT_THREAD_SCROLL_TOP_GAP - (containerScrollHeight - containerClientHeight)
627
- );
628
612
 
629
613
  // src/components/chat-thread/components/chat-message-item.tsx
630
- import { Fragment, memo, useState as useState4 } from "react";
614
+ import { Fragment, memo, useState as useState3 } from "react";
631
615
  import styled7 from "@emotion/styled";
632
616
  import { keyframes } from "@emotion/react";
633
617
  import ReactMarkdown from "react-markdown";
@@ -636,7 +620,7 @@ import remarkMath from "remark-math";
636
620
  import rehypeKatex from "rehype-katex";
637
621
 
638
622
  // src/components/chat-thread/hooks/use-chat-message-reveal.ts
639
- import { useCallback, useEffect, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
623
+ import { useCallback, useEffect, useMemo as useMemo2, useReducer, useRef as useRef2 } from "react";
640
624
 
641
625
  // src/components/chat-thread/lib/message-reveal.ts
642
626
  var STREAM_REVEAL_TICK_MS = 36;
@@ -683,6 +667,64 @@ var getNextDisplayedUnitCount = ({
683
667
  var splitMarkdownBlocks = (content) => content.split(/\n{2,}/).map((block) => block.trim()).filter(Boolean);
684
668
 
685
669
  // src/components/chat-thread/hooks/use-chat-message-reveal.ts
670
+ var createRevealState = ({
671
+ isAssistantStreaming,
672
+ targetUnitCount
673
+ }) => {
674
+ const initialDisplayedUnitCount = isAssistantStreaming ? 0 : targetUnitCount;
675
+ return {
676
+ batchedTargetUnitCount: initialDisplayedUnitCount,
677
+ displayedUnitCount: initialDisplayedUnitCount,
678
+ isFreshBlockActive: false
679
+ };
680
+ };
681
+ var revealReducer = (state, action) => {
682
+ switch (action.type) {
683
+ case "reset-message":
684
+ return createRevealState(action);
685
+ case "commit-batched-target": {
686
+ const nextDisplayedUnitCount = action.role === "assistant" ? getNextDisplayedUnitCount({
687
+ currentUnits: state.displayedUnitCount,
688
+ targetUnits: action.nextTargetUnitCount,
689
+ isStreaming: action.isAssistantStreaming,
690
+ minimumStep: state.displayedUnitCount > 0 && action.isAssistantStreaming ? 2 : 1
691
+ }) : action.nextTargetUnitCount;
692
+ return {
693
+ ...state,
694
+ batchedTargetUnitCount: action.nextTargetUnitCount,
695
+ displayedUnitCount: nextDisplayedUnitCount
696
+ };
697
+ }
698
+ case "set-fresh-block-active":
699
+ return state.isFreshBlockActive === action.isActive ? state : {
700
+ ...state,
701
+ isFreshBlockActive: action.isActive
702
+ };
703
+ case "sync-displayed-target":
704
+ return state.displayedUnitCount === state.batchedTargetUnitCount ? state : {
705
+ ...state,
706
+ displayedUnitCount: state.batchedTargetUnitCount
707
+ };
708
+ case "advance-reveal": {
709
+ if (state.displayedUnitCount >= state.batchedTargetUnitCount) {
710
+ return state;
711
+ }
712
+ return {
713
+ ...state,
714
+ displayedUnitCount: Math.min(
715
+ state.batchedTargetUnitCount,
716
+ getNextDisplayedUnitCount({
717
+ currentUnits: state.displayedUnitCount,
718
+ targetUnits: state.batchedTargetUnitCount,
719
+ isStreaming: action.isAssistantStreaming
720
+ })
721
+ )
722
+ };
723
+ }
724
+ default:
725
+ return state;
726
+ }
727
+ };
686
728
  var useChatMessageReveal = (message) => {
687
729
  const isAssistantStreaming = message.role === "assistant" && message.status === "streaming";
688
730
  const targetContent = message.content || "";
@@ -690,41 +732,47 @@ var useChatMessageReveal = (message) => {
690
732
  const pendingTargetUnitCountRef = useRef2(targetUnits.length);
691
733
  const batchedTargetUnitCountRef = useRef2(isAssistantStreaming ? 0 : targetUnits.length);
692
734
  const inputBatchTimeoutRef = useRef2(null);
693
- const [batchedTargetUnitCount, setBatchedTargetUnitCount] = useState2(
694
- () => isAssistantStreaming ? 0 : targetUnits.length
695
- );
696
735
  const lastDisplayedBlockCountRef = useRef2(0);
697
- const [displayedUnitCount, setDisplayedUnitCount] = useState2(
698
- () => isAssistantStreaming ? 0 : targetUnits.length
736
+ const previousMessageIdRef = useRef2(message.id);
737
+ const [state, dispatch] = useReducer(
738
+ revealReducer,
739
+ {
740
+ isAssistantStreaming,
741
+ targetUnitCount: targetUnits.length
742
+ },
743
+ createRevealState
699
744
  );
700
- const [isFreshBlockActive, setIsFreshBlockActive] = useState2(false);
745
+ const { batchedTargetUnitCount, displayedUnitCount, isFreshBlockActive } = state;
701
746
  const commitBatchedTargetUnitCount = useCallback(
702
747
  (nextTargetUnitCount) => {
703
748
  batchedTargetUnitCountRef.current = nextTargetUnitCount;
704
- setBatchedTargetUnitCount(nextTargetUnitCount);
705
- setDisplayedUnitCount(
706
- (current) => message.role === "assistant" ? getNextDisplayedUnitCount({
707
- currentUnits: current,
708
- targetUnits: nextTargetUnitCount,
709
- isStreaming: isAssistantStreaming,
710
- minimumStep: current > 0 && isAssistantStreaming ? 2 : 1
711
- }) : nextTargetUnitCount
712
- );
749
+ dispatch({
750
+ type: "commit-batched-target",
751
+ isAssistantStreaming,
752
+ nextTargetUnitCount,
753
+ role: message.role
754
+ });
713
755
  },
714
756
  [isAssistantStreaming, message.role]
715
757
  );
716
758
  useEffect(() => {
759
+ if (previousMessageIdRef.current === message.id) {
760
+ return;
761
+ }
762
+ previousMessageIdRef.current = message.id;
717
763
  pendingTargetUnitCountRef.current = targetUnits.length;
718
764
  batchedTargetUnitCountRef.current = isAssistantStreaming ? 0 : targetUnits.length;
719
- setBatchedTargetUnitCount(batchedTargetUnitCountRef.current);
720
- setDisplayedUnitCount(isAssistantStreaming ? 0 : targetUnits.length);
721
765
  lastDisplayedBlockCountRef.current = 0;
722
766
  if (inputBatchTimeoutRef.current !== null) {
723
767
  window.clearTimeout(inputBatchTimeoutRef.current);
724
768
  inputBatchTimeoutRef.current = null;
725
769
  }
726
- setIsFreshBlockActive(false);
727
- }, [message.id, isAssistantStreaming, targetUnits.length]);
770
+ dispatch({
771
+ type: "reset-message",
772
+ isAssistantStreaming,
773
+ targetUnitCount: targetUnits.length
774
+ });
775
+ }, [isAssistantStreaming, message.id, targetUnits.length]);
728
776
  useEffect(() => {
729
777
  pendingTargetUnitCountRef.current = targetUnits.length;
730
778
  if (message.role !== "assistant" || !isAssistantStreaming) {
@@ -767,9 +815,9 @@ var useChatMessageReveal = (message) => {
767
815
  if (!hasNewDisplayedBlock) {
768
816
  return;
769
817
  }
770
- setIsFreshBlockActive(true);
818
+ dispatch({ type: "set-fresh-block-active", isActive: true });
771
819
  const timer = window.setTimeout(() => {
772
- setIsFreshBlockActive(false);
820
+ dispatch({ type: "set-fresh-block-active", isActive: false });
773
821
  }, STREAM_FRESH_BLOCK_SETTLE_MS);
774
822
  return () => {
775
823
  window.clearTimeout(timer);
@@ -779,37 +827,34 @@ var useChatMessageReveal = (message) => {
779
827
  const shouldAnimateReveal = message.role === "assistant" && displayedUnitCount < batchedTargetUnitCount && (isAssistantStreaming || displayedUnitCount > 0);
780
828
  if (!shouldAnimateReveal) {
781
829
  if (displayedUnitCount !== batchedTargetUnitCount) {
782
- setDisplayedUnitCount(batchedTargetUnitCount);
830
+ dispatch({ type: "sync-displayed-target" });
783
831
  }
784
832
  return;
785
833
  }
786
834
  const timer = window.setInterval(() => {
787
- setDisplayedUnitCount((current) => {
788
- if (current >= batchedTargetUnitCount) {
789
- window.clearInterval(timer);
790
- return current;
791
- }
792
- return Math.min(
793
- batchedTargetUnitCount,
794
- getNextDisplayedUnitCount({
795
- currentUnits: current,
796
- targetUnits: batchedTargetUnitCount,
797
- isStreaming: isAssistantStreaming
798
- })
799
- );
800
- });
835
+ dispatch({ type: "advance-reveal", isAssistantStreaming });
801
836
  }, STREAM_REVEAL_TICK_MS);
802
837
  return () => {
803
838
  window.clearInterval(timer);
804
839
  };
805
840
  }, [batchedTargetUnitCount, displayedUnitCount, isAssistantStreaming, message.role]);
806
841
  const settledContent = isFreshBlockActive ? contentBlocks.slice(0, -1).join("\n\n") : displayedContent;
807
- const freshContent = isFreshBlockActive ? contentBlocks.at(-1) ?? "" : "";
842
+ const freshContent = isFreshBlockActive ? contentBlocks[contentBlocks.length - 1] ?? "" : "";
843
+ const displayedBlocks = isAssistantStreaming && contentBlocks.length > 1 ? contentBlocks.map((content, index) => ({
844
+ content,
845
+ tone: isFreshBlockActive && index === contentBlocks.length - 1 ? "fresh" : "settled"
846
+ })) : [
847
+ {
848
+ content: displayedContent,
849
+ tone: "settled"
850
+ }
851
+ ];
808
852
  return {
809
853
  isAssistantStreaming,
810
854
  displayedContent,
811
855
  settledContent,
812
- freshContent
856
+ freshContent,
857
+ displayedBlocks
813
858
  };
814
859
  };
815
860
 
@@ -1023,7 +1068,7 @@ var Value = styled3.span`
1023
1068
  `;
1024
1069
 
1025
1070
  // src/components/chat-thread/components/pde-ai-questionnaire-card.tsx
1026
- import { useState as useState3 } from "react";
1071
+ import { useState as useState2 } from "react";
1027
1072
  import styled4 from "@emotion/styled";
1028
1073
  import { jsx as jsx5, jsxs as jsxs3 } from "@emotion/react/jsx-runtime";
1029
1074
  var OTHER_OPTION_VALUE = "__other__";
@@ -1125,10 +1170,10 @@ var PDEAIQuestionnaireCardInner = ({
1125
1170
  interactive = false,
1126
1171
  onSubmit
1127
1172
  }) => {
1128
- const [answers, setAnswers] = useState3(
1173
+ const [answers, setAnswers] = useState2(
1129
1174
  () => createInitialAnswers(questionnaire)
1130
1175
  );
1131
- const [errorMessage, setErrorMessage] = useState3(null);
1176
+ const [errorMessage, setErrorMessage] = useState2(null);
1132
1177
  const handleSubmit = () => {
1133
1178
  const missingQuestions = questionnaire.questions.filter(
1134
1179
  (question) => question.required && isMissingRequiredAnswer(question, answers)
@@ -1756,17 +1801,19 @@ var ChatMessageItemView = ({
1756
1801
  renderMessageBlock
1757
1802
  }) => {
1758
1803
  const { labels } = useChatContext();
1759
- const [activeImage, setActiveImage] = useState4(void 0);
1760
- const { displayedContent, freshContent, isAssistantStreaming, settledContent } = useChatMessageReveal(message);
1804
+ const [activeImage, setActiveImage] = useState3(void 0);
1805
+ const { displayedBlocks, displayedContent, freshContent, isAssistantStreaming, settledContent } = useChatMessageReveal(message);
1761
1806
  const isStoppedAssistant = message.role === "assistant" && message.status === "stopped";
1762
1807
  const attachments = message.attachments ?? [];
1763
1808
  const blocks = message.blocks ?? [];
1764
1809
  const hasStructuredBlocks = blocks.length > 0;
1810
+ const hasMarkdownOnlyBlocks = hasStructuredBlocks && blocks.every((block) => block.type === "markdown");
1765
1811
  const hasTextContent = Boolean(settledContent || freshContent || displayedContent);
1812
+ const shouldRenderStructuredBlocks = hasStructuredBlocks && !(isAssistantStreaming && hasMarkdownOnlyBlocks && hasTextContent);
1766
1813
  const isPlanMode = mode === "plan";
1767
1814
  const canSubmitConfirmation = isPlanMode && typeof onConfirmationSubmit === "function";
1768
1815
  const canSubmitQuestionnaire = isPlanMode && typeof onQuestionnaireSubmit === "function";
1769
- const shouldShowStreamingCaret = isAssistantStreaming && (!hasStructuredBlocks || hasTextContent);
1816
+ const shouldShowStreamingCaret = isAssistantStreaming && (!shouldRenderStructuredBlocks || hasTextContent);
1770
1817
  const renderChatMessageBlock = (block, index) => {
1771
1818
  switch (block.type) {
1772
1819
  case "markdown":
@@ -1824,9 +1871,17 @@ var ChatMessageItemView = ({
1824
1871
  }
1825
1872
  };
1826
1873
  const renderTextContent = () => /* @__PURE__ */ jsxs5(Fragment2, { children: [
1827
- settledContent ? /* @__PURE__ */ jsx8(ContentBlock, { "data-testid": "chat-message-settled-block", "data-block-tone": "settled", children: renderMarkdownContent(settledContent) }) : null,
1828
- freshContent ? /* @__PURE__ */ jsx8(ContentBlock, { "data-testid": "chat-message-fresh-block", "data-block-tone": "fresh", children: renderMarkdownContent(freshContent) }) : null,
1829
- !settledContent && !freshContent && hasTextContent ? /* @__PURE__ */ jsx8(ContentBlock, { "data-testid": "chat-message-settled-block", "data-block-tone": "settled", children: renderMarkdownContent(displayedContent) }) : null
1874
+ displayedBlocks.filter((block) => block.content).map((block, index) => /* @__PURE__ */ jsx8(
1875
+ ContentBlock,
1876
+ {
1877
+ "data-testid": block.tone === "fresh" ? "chat-message-fresh-block" : "chat-message-settled-block",
1878
+ "data-block-tone": block.tone,
1879
+ "data-block-index": index,
1880
+ children: renderMarkdownContent(block.content)
1881
+ },
1882
+ `${block.tone}-${index}`
1883
+ )),
1884
+ !displayedBlocks.some((block) => block.content) && !settledContent && !freshContent && hasTextContent ? /* @__PURE__ */ jsx8(ContentBlock, { "data-testid": "chat-message-settled-block", "data-block-tone": "settled", children: renderMarkdownContent(displayedContent) }) : null
1830
1885
  ] });
1831
1886
  return /* @__PURE__ */ jsxs5(Fragment2, { children: [
1832
1887
  /* @__PURE__ */ jsxs5(Bubble, { "data-role": message.role, "data-status": message.status ?? "done", children: [
@@ -1846,8 +1901,8 @@ var ChatMessageItemView = ({
1846
1901
  isStoppedAssistant ? /* @__PURE__ */ jsx8(StatusTag, { "data-testid": "chat-message-stopped-tag", children: labels.stoppedResponse }) : null
1847
1902
  ] }),
1848
1903
  /* @__PURE__ */ jsxs5(Content, { "data-testid": "chat-message-content", children: [
1849
- hasStructuredBlocks || hasTextContent ? /* @__PURE__ */ jsxs5(ContentStack, { "data-testid": "chat-message-body-stack", children: [
1850
- hasStructuredBlocks ? blocks.map((block, index) => /* @__PURE__ */ jsx8(
1904
+ shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ jsxs5(ContentStack, { "data-testid": "chat-message-body-stack", children: [
1905
+ shouldRenderStructuredBlocks ? blocks.map((block, index) => /* @__PURE__ */ jsx8(
1851
1906
  ContentSegment,
1852
1907
  {
1853
1908
  "data-testid": "chat-message-content-segment",
@@ -2090,65 +2145,21 @@ var StreamingCaret = styled7.span`
2090
2145
  animation: ${caretBlink} 0.9s steps(1) infinite;
2091
2146
  `;
2092
2147
 
2093
- // src/components/chat-thread/components/chat-thread-history-list.tsx
2094
- import { memo as memo2 } from "react";
2095
- import styled8 from "@emotion/styled";
2096
- import { jsx as jsx9 } from "@emotion/react/jsx-runtime";
2097
- var ChatThreadHistoryList = memo2(
2098
- ({
2099
- mode,
2100
- historyMessages,
2101
- latestUserMessageId,
2102
- latestUserMessageRef,
2103
- onConfirmationSubmit,
2104
- onQuestionnaireSubmit,
2105
- renderMessageBlock
2106
- }) => /* @__PURE__ */ jsx9(HistoryGroup, { "data-testid": "chat-thread-history", children: historyMessages.map((message) => /* @__PURE__ */ jsx9(
2107
- MessageSlot,
2108
- {
2109
- ref: message.id === latestUserMessageId ? latestUserMessageRef : null,
2110
- "data-testid": message.id === latestUserMessageId ? "chat-latest-user-anchor" : void 0,
2111
- style: message.id === latestUserMessageId ? {
2112
- scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px`
2113
- } : void 0,
2114
- children: /* @__PURE__ */ jsx9(
2115
- ChatMessageItem,
2116
- {
2117
- mode,
2118
- message,
2119
- onConfirmationSubmit,
2120
- onQuestionnaireSubmit,
2121
- renderMessageBlock
2122
- }
2123
- )
2124
- },
2125
- message.id
2126
- )) })
2127
- );
2128
- ChatThreadHistoryList.displayName = "ChatThreadHistoryList";
2129
- var HistoryGroup = styled8.div`
2130
- display: contents;
2131
- `;
2132
- var MessageSlot = styled8.div`
2133
- display: flex;
2134
- align-items: flex-start;
2135
- `;
2136
-
2137
2148
  // src/components/chat-thread/components/chat-thread-empty-state.tsx
2138
- import styled9 from "@emotion/styled";
2139
- import { jsx as jsx10, jsxs as jsxs6 } from "@emotion/react/jsx-runtime";
2149
+ import styled8 from "@emotion/styled";
2150
+ import { jsx as jsx9, jsxs as jsxs6 } from "@emotion/react/jsx-runtime";
2140
2151
  var ChatThreadEmptyState = () => {
2141
2152
  const { labels } = useChatContext();
2142
2153
  return /* @__PURE__ */ jsxs6(EmptyShell, { "data-testid": "chat-empty-hero", children: [
2143
2154
  /* @__PURE__ */ jsxs6(HeroMark, { children: [
2144
- /* @__PURE__ */ jsx10(HeroOrbit, {}),
2145
- /* @__PURE__ */ jsx10(HeroCore, { children: "AI" })
2155
+ /* @__PURE__ */ jsx9(HeroOrbit, {}),
2156
+ /* @__PURE__ */ jsx9(HeroCore, { children: "AI" })
2146
2157
  ] }),
2147
- /* @__PURE__ */ jsx10(HeroTitle, { children: labels.emptyStateTitle }),
2148
- /* @__PURE__ */ jsx10(HeroSubtitle, { children: labels.emptyStateSubtitle })
2158
+ /* @__PURE__ */ jsx9(HeroTitle, { children: labels.emptyStateTitle }),
2159
+ /* @__PURE__ */ jsx9(HeroSubtitle, { children: labels.emptyStateSubtitle })
2149
2160
  ] });
2150
2161
  };
2151
- var EmptyShell = styled9.div`
2162
+ var EmptyShell = styled8.div`
2152
2163
  flex: 1;
2153
2164
  min-height: 0;
2154
2165
  display: flex;
@@ -2158,7 +2169,7 @@ var EmptyShell = styled9.div`
2158
2169
  gap: 16px;
2159
2170
  padding: 48px 24px 24px;
2160
2171
  `;
2161
- var HeroMark = styled9.div`
2172
+ var HeroMark = styled8.div`
2162
2173
  position: relative;
2163
2174
  width: 108px;
2164
2175
  height: 108px;
@@ -2166,7 +2177,7 @@ var HeroMark = styled9.div`
2166
2177
  display: grid;
2167
2178
  place-items: center;
2168
2179
  `;
2169
- var HeroOrbit = styled9.div`
2180
+ var HeroOrbit = styled8.div`
2170
2181
  position: absolute;
2171
2182
  inset: 20px;
2172
2183
  border-radius: 50%;
@@ -2189,7 +2200,7 @@ var HeroOrbit = styled9.div`
2189
2200
  transform: rotate(-22deg);
2190
2201
  }
2191
2202
  `;
2192
- var HeroCore = styled9.div`
2203
+ var HeroCore = styled8.div`
2193
2204
  position: relative;
2194
2205
  z-index: 1;
2195
2206
  font-size: 28px;
@@ -2199,13 +2210,13 @@ var HeroCore = styled9.div`
2199
2210
  color: rgba(242, 244, 255, 0.96);
2200
2211
  text-shadow: 0 0 16px rgba(98, 116, 255, 0.65);
2201
2212
  `;
2202
- var HeroTitle = styled9.p`
2213
+ var HeroTitle = styled8.p`
2203
2214
  margin: 0;
2204
2215
  color: rgba(255, 255, 255, 0.88);
2205
2216
  font-size: 16px;
2206
2217
  line-height: 24px;
2207
2218
  `;
2208
- var HeroSubtitle = styled9.p`
2219
+ var HeroSubtitle = styled8.p`
2209
2220
  margin: 0;
2210
2221
  color: rgba(255, 255, 255, 0.72);
2211
2222
  font-size: 14px;
@@ -2213,7 +2224,74 @@ var HeroSubtitle = styled9.p`
2213
2224
  `;
2214
2225
 
2215
2226
  // src/components/chat-thread/index.tsx
2216
- import { jsx as jsx11, jsxs as jsxs7 } from "@emotion/react/jsx-runtime";
2227
+ import { jsx as jsx10, jsxs as jsxs7 } from "@emotion/react/jsx-runtime";
2228
+ var renderChatMessage = ({
2229
+ message,
2230
+ mode,
2231
+ onConfirmationSubmit,
2232
+ onQuestionnaireSubmit,
2233
+ renderMessageBlock
2234
+ }) => /* @__PURE__ */ jsx10(
2235
+ ChatMessageItem,
2236
+ {
2237
+ mode,
2238
+ message,
2239
+ onConfirmationSubmit,
2240
+ onQuestionnaireSubmit,
2241
+ renderMessageBlock
2242
+ }
2243
+ );
2244
+ var renderErrorState = ({
2245
+ error,
2246
+ onRetry,
2247
+ retryButtonLabel
2248
+ }) => /* @__PURE__ */ jsxs7(ErrorState, { "data-testid": "chat-thread-error-state", children: [
2249
+ /* @__PURE__ */ jsx10(ErrorText, { children: error }),
2250
+ onRetry ? /* @__PURE__ */ jsx10(ErrorActions, { children: /* @__PURE__ */ jsx10(RetryButton, { type: "button", "data-testid": "chat-thread-retry", onClick: onRetry, children: retryButtonLabel }) }) : null
2251
+ ] });
2252
+ var groupConversationTurns = (historyMessages, streamingMessage) => {
2253
+ const turns = [];
2254
+ let currentTurn = null;
2255
+ historyMessages.forEach((message) => {
2256
+ if (message.role === "user") {
2257
+ currentTurn = {
2258
+ id: message.id,
2259
+ userMessage: message,
2260
+ responseMessages: []
2261
+ };
2262
+ turns.push(currentTurn);
2263
+ return;
2264
+ }
2265
+ if (!currentTurn) {
2266
+ currentTurn = {
2267
+ id: `assistant-turn-${message.id}`,
2268
+ responseMessages: [message]
2269
+ };
2270
+ turns.push(currentTurn);
2271
+ return;
2272
+ }
2273
+ currentTurn.responseMessages.push(message);
2274
+ });
2275
+ if (!streamingMessage) {
2276
+ return turns;
2277
+ }
2278
+ const lastTurn = turns[turns.length - 1];
2279
+ if (lastTurn) {
2280
+ return [
2281
+ ...turns.slice(0, -1),
2282
+ {
2283
+ ...lastTurn,
2284
+ responseMessages: [...lastTurn.responseMessages, streamingMessage]
2285
+ }
2286
+ ];
2287
+ }
2288
+ return [
2289
+ {
2290
+ id: `assistant-turn-${streamingMessage.id}`,
2291
+ responseMessages: [streamingMessage]
2292
+ }
2293
+ ];
2294
+ };
2217
2295
  var ChatThreadView = ({
2218
2296
  activeSessionMode = DEFAULT_CHAT_AGENT_MODE,
2219
2297
  historyMessages,
@@ -2226,31 +2304,45 @@ var ChatThreadView = ({
2226
2304
  renderMessageBlock
2227
2305
  }) => {
2228
2306
  const containerRef = useRef4(null);
2229
- const latestUserMessageId = useMemo3(
2230
- () => findLatestUserMessageId(historyMessages),
2231
- [historyMessages]
2307
+ const conversationTurns = useMemo3(
2308
+ () => groupConversationTurns(historyMessages, streamingMessage),
2309
+ [historyMessages, streamingMessage]
2232
2310
  );
2311
+ const latestTurn = conversationTurns[conversationTurns.length - 1];
2312
+ const previousTurns = conversationTurns.slice(0, -1);
2313
+ const latestUserMessageId = latestTurn?.userMessage?.id;
2233
2314
  const latestUserMessageRef = useRef4(null);
2234
- const pendingScrollUserMessageIdRef = useRef4(void 0);
2235
2315
  const reservedSpaceFrameRef = useRef4(null);
2236
- const [latestUserMessageReservedSpace, setLatestUserMessageReservedSpace] = useState5({ messageId: void 0, value: 0 });
2237
- const reservedPaddingBottom = 24 + (latestUserMessageReservedSpace.messageId === latestUserMessageId ? latestUserMessageReservedSpace.value : 0);
2238
- const measureLatestUserMessageReservedSpace = useCallback2((messageId) => {
2316
+ const [latestTurnMinHeight, setLatestTurnMinHeight] = useState4(0);
2317
+ const measureLatestTurnMinHeight = useCallback2(() => {
2318
+ const container = containerRef.current;
2319
+ if (!container)
2320
+ return;
2321
+ const computedStyle = window.getComputedStyle(container);
2322
+ const paddingTop = Number.parseFloat(computedStyle.paddingTop || "0") || 0;
2323
+ const paddingBottom = Number.parseFloat(computedStyle.paddingBottom || "0") || 0;
2324
+ const nextMinHeight = Math.max(0, container.clientHeight - paddingTop - paddingBottom);
2325
+ setLatestTurnMinHeight((current) => current === nextMinHeight ? current : nextMinHeight);
2326
+ }, []);
2327
+ const scrollLatestUserMessageToTop = useCallback2(() => {
2239
2328
  const container = containerRef.current;
2240
2329
  const target = latestUserMessageRef.current;
2241
2330
  if (!container || !target)
2242
2331
  return;
2243
- const reservedHeight = calculateChatThreadScrollSpacerHeight({
2244
- containerClientHeight: container.clientHeight,
2245
- containerScrollHeight: container.scrollHeight,
2246
- targetOffsetTop: target.offsetTop
2247
- });
2248
- setLatestUserMessageReservedSpace((current) => {
2249
- const next = reservedHeight > 0 ? reservedHeight : 0;
2250
- if (current.messageId === messageId && current.value === next)
2251
- return current;
2252
- return { messageId, value: next };
2253
- });
2332
+ const containerRect = container.getBoundingClientRect();
2333
+ const targetRect = target.getBoundingClientRect();
2334
+ const nextScrollTop = Math.max(
2335
+ 0,
2336
+ container.scrollTop + (targetRect.top - containerRect.top) - CHAT_THREAD_SCROLL_TOP_GAP
2337
+ );
2338
+ if (typeof container.scrollTo === "function") {
2339
+ container.scrollTo({
2340
+ top: nextScrollTop,
2341
+ behavior: "auto"
2342
+ });
2343
+ return;
2344
+ }
2345
+ container.scrollTop = nextScrollTop;
2254
2346
  }, []);
2255
2347
  useLayoutEffect(() => {
2256
2348
  if (reservedSpaceFrameRef.current !== null) {
@@ -2258,12 +2350,9 @@ var ChatThreadView = ({
2258
2350
  reservedSpaceFrameRef.current = null;
2259
2351
  }
2260
2352
  if (!latestUserMessageId) {
2261
- pendingScrollUserMessageIdRef.current = void 0;
2262
2353
  reservedSpaceFrameRef.current = window.requestAnimationFrame(() => {
2263
2354
  reservedSpaceFrameRef.current = null;
2264
- setLatestUserMessageReservedSpace(
2265
- (current) => current.messageId === void 0 && current.value === 0 ? current : { messageId: void 0, value: 0 }
2266
- );
2355
+ setLatestTurnMinHeight((current) => current === 0 ? current : 0);
2267
2356
  });
2268
2357
  return () => {
2269
2358
  if (reservedSpaceFrameRef.current !== null) {
@@ -2272,10 +2361,10 @@ var ChatThreadView = ({
2272
2361
  }
2273
2362
  };
2274
2363
  }
2275
- pendingScrollUserMessageIdRef.current = latestUserMessageId;
2276
2364
  reservedSpaceFrameRef.current = window.requestAnimationFrame(() => {
2277
2365
  reservedSpaceFrameRef.current = null;
2278
- measureLatestUserMessageReservedSpace(latestUserMessageId);
2366
+ measureLatestTurnMinHeight();
2367
+ scrollLatestUserMessageToTop();
2279
2368
  });
2280
2369
  return () => {
2281
2370
  if (reservedSpaceFrameRef.current !== null) {
@@ -2283,51 +2372,79 @@ var ChatThreadView = ({
2283
2372
  reservedSpaceFrameRef.current = null;
2284
2373
  }
2285
2374
  };
2286
- }, [latestUserMessageId, measureLatestUserMessageReservedSpace]);
2375
+ }, [latestUserMessageId, measureLatestTurnMinHeight, scrollLatestUserMessageToTop]);
2287
2376
  useLayoutEffect(() => {
2288
- if (!latestUserMessageId || pendingScrollUserMessageIdRef.current !== latestUserMessageId)
2289
- return;
2290
- if (latestUserMessageReservedSpace.messageId !== latestUserMessageId)
2377
+ if (!latestUserMessageId)
2291
2378
  return;
2292
- latestUserMessageRef.current?.scrollIntoView({ block: "start", behavior: "smooth" });
2293
- pendingScrollUserMessageIdRef.current = void 0;
2294
- }, [latestUserMessageId, latestUserMessageReservedSpace]);
2295
- return /* @__PURE__ */ jsxs7(
2296
- Container,
2297
- {
2298
- ref: containerRef,
2299
- "data-testid": "chat-thread",
2300
- style: { paddingBottom: `${reservedPaddingBottom}px` },
2301
- children: [
2302
- /* @__PURE__ */ jsx11(
2303
- ChatThreadHistoryList,
2304
- {
2305
- mode: activeSessionMode,
2306
- historyMessages,
2307
- latestUserMessageId,
2308
- latestUserMessageRef,
2309
- onConfirmationSubmit,
2310
- onQuestionnaireSubmit,
2311
- renderMessageBlock
2312
- }
2313
- ),
2314
- streamingMessage ? /* @__PURE__ */ jsx11(StreamingGroup, { "data-testid": "chat-thread-streaming", children: /* @__PURE__ */ jsx11(MessageSlot2, { children: /* @__PURE__ */ jsx11(
2315
- ChatMessageItem,
2316
- {
2379
+ const handleResize = () => {
2380
+ measureLatestTurnMinHeight();
2381
+ scrollLatestUserMessageToTop();
2382
+ };
2383
+ const container = containerRef.current;
2384
+ let resizeObserver = null;
2385
+ if (container && typeof ResizeObserver !== "undefined") {
2386
+ resizeObserver = new ResizeObserver(() => {
2387
+ handleResize();
2388
+ });
2389
+ resizeObserver.observe(container);
2390
+ }
2391
+ window.addEventListener("resize", handleResize);
2392
+ return () => {
2393
+ resizeObserver?.disconnect();
2394
+ window.removeEventListener("resize", handleResize);
2395
+ };
2396
+ }, [latestUserMessageId, measureLatestTurnMinHeight, scrollLatestUserMessageToTop]);
2397
+ return /* @__PURE__ */ jsxs7(Container, { ref: containerRef, "data-testid": "chat-thread", children: [
2398
+ previousTurns.map((turn) => /* @__PURE__ */ jsxs7(ConversationTurn, { "data-testid": "chat-thread-turn", children: [
2399
+ turn.userMessage ? /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
2400
+ message: turn.userMessage,
2401
+ mode: activeSessionMode,
2402
+ onConfirmationSubmit,
2403
+ onQuestionnaireSubmit,
2404
+ renderMessageBlock
2405
+ }) }) : null,
2406
+ turn.responseMessages.map((message) => /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
2407
+ message,
2408
+ mode: activeSessionMode,
2409
+ onConfirmationSubmit,
2410
+ onQuestionnaireSubmit,
2411
+ renderMessageBlock
2412
+ }) }, message.id))
2413
+ ] }, turn.id)),
2414
+ latestTurn ? /* @__PURE__ */ jsxs7(
2415
+ ConversationTurn,
2416
+ {
2417
+ "data-testid": "chat-thread-latest-turn",
2418
+ style: latestTurnMinHeight > 0 ? { minHeight: `${latestTurnMinHeight}px` } : void 0,
2419
+ children: [
2420
+ latestTurn.userMessage ? /* @__PURE__ */ jsx10(
2421
+ MessageSlot,
2422
+ {
2423
+ ref: latestUserMessageRef,
2424
+ "data-testid": "chat-latest-user-anchor",
2425
+ style: { scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px` },
2426
+ children: renderChatMessage({
2427
+ message: latestTurn.userMessage,
2428
+ mode: activeSessionMode,
2429
+ onConfirmationSubmit,
2430
+ onQuestionnaireSubmit,
2431
+ renderMessageBlock
2432
+ })
2433
+ }
2434
+ ) : null,
2435
+ latestTurn.responseMessages.map((message) => /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
2436
+ message,
2317
2437
  mode: activeSessionMode,
2318
- message: streamingMessage,
2319
2438
  onConfirmationSubmit,
2320
2439
  onQuestionnaireSubmit,
2321
2440
  renderMessageBlock
2322
- }
2323
- ) }) }) : null,
2324
- error ? /* @__PURE__ */ jsxs7(ErrorState, { "data-testid": "chat-thread-error-state", children: [
2325
- /* @__PURE__ */ jsx11(ErrorText, { children: error }),
2326
- onRetry ? /* @__PURE__ */ jsx11(ErrorActions, { children: /* @__PURE__ */ jsx11(RetryButton, { type: "button", "data-testid": "chat-thread-retry", onClick: onRetry, children: retryButtonLabel }) }) : null
2327
- ] }) : null
2328
- ]
2329
- }
2330
- );
2441
+ }) }, message.id)),
2442
+ error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
2443
+ ]
2444
+ }
2445
+ ) : null,
2446
+ !latestTurn && error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
2447
+ ] });
2331
2448
  };
2332
2449
  var EMPTY_MESSAGES = [];
2333
2450
  var ChatThread = () => {
@@ -2371,9 +2488,9 @@ var ChatThread = () => {
2371
2488
  [sendRef]
2372
2489
  );
2373
2490
  if (!hasSessions || messages.length === 0 && !streamingMessage) {
2374
- return /* @__PURE__ */ jsx11(ChatThreadEmptyState, {});
2491
+ return /* @__PURE__ */ jsx10(ChatThreadEmptyState, {});
2375
2492
  }
2376
- return /* @__PURE__ */ jsx11(
2493
+ return /* @__PURE__ */ jsx10(
2377
2494
  ChatThreadView,
2378
2495
  {
2379
2496
  activeSessionMode,
@@ -2388,7 +2505,7 @@ var ChatThread = () => {
2388
2505
  }
2389
2506
  );
2390
2507
  };
2391
- var Container = styled10.div`
2508
+ var Container = styled9.div`
2392
2509
  display: flex;
2393
2510
  flex: 1;
2394
2511
  flex-direction: column;
@@ -2411,27 +2528,29 @@ var Container = styled10.div`
2411
2528
  background: transparent;
2412
2529
  }
2413
2530
  `;
2414
- var MessageSlot2 = styled10.div`
2531
+ var MessageSlot = styled9.div`
2415
2532
  display: flex;
2416
2533
  `;
2417
- var StreamingGroup = styled10.div`
2418
- display: contents;
2534
+ var ConversationTurn = styled9.div`
2535
+ display: flex;
2536
+ flex-direction: column;
2537
+ gap: 18px;
2419
2538
  `;
2420
- var ErrorText = styled10.div`
2539
+ var ErrorText = styled9.div`
2421
2540
  color: #ff7b72;
2422
2541
  font-size: 14px;
2423
2542
  `;
2424
- var ErrorState = styled10.div`
2543
+ var ErrorState = styled9.div`
2425
2544
  display: flex;
2426
2545
  flex-direction: column;
2427
2546
  align-items: flex-start;
2428
2547
  gap: 10px;
2429
2548
  `;
2430
- var ErrorActions = styled10.div`
2549
+ var ErrorActions = styled9.div`
2431
2550
  display: flex;
2432
2551
  align-items: center;
2433
2552
  `;
2434
- var RetryButton = styled10.button`
2553
+ var RetryButton = styled9.button`
2435
2554
  border: 1px solid rgba(255, 255, 255, 0.14);
2436
2555
  border-radius: 999px;
2437
2556
  background: rgba(255, 255, 255, 0.04);
@@ -2448,7 +2567,7 @@ var RetryButton = styled10.button`
2448
2567
 
2449
2568
  // src/components/chat-composer/index.tsx
2450
2569
  import { useEffect as useEffect5, useRef as useRef7 } from "react";
2451
- import styled15 from "@emotion/styled";
2570
+ import styled14 from "@emotion/styled";
2452
2571
 
2453
2572
  // src/components/chat-composer/lib/chat-composer.ts
2454
2573
  var DRAFT_CHAT_SESSION_ID_PREFIX = "draft-session-";
@@ -2559,10 +2678,10 @@ var resolveSendSession = ({
2559
2678
  };
2560
2679
 
2561
2680
  // src/components/chat-composer/hooks/use-chat-composer.ts
2562
- import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef6, useState as useState7 } from "react";
2681
+ import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef6, useState as useState6 } from "react";
2563
2682
 
2564
2683
  // src/components/chat-composer/hooks/use-composer-attachments.ts
2565
- import { useEffect as useEffect3, useRef as useRef5, useState as useState6 } from "react";
2684
+ import { useEffect as useEffect3, useRef as useRef5, useState as useState5 } from "react";
2566
2685
  var SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
2567
2686
  var MAX_COMPOSER_ATTACHMENTS = 10;
2568
2687
  var createObjectUrl = (file) => typeof URL !== "undefined" && typeof URL.createObjectURL === "function" ? URL.createObjectURL(file) : "";
@@ -2576,7 +2695,7 @@ var releaseComposerAttachments = (attachments) => {
2576
2695
  attachments.forEach((attachment) => revokeObjectUrl(attachment.previewUrl));
2577
2696
  };
2578
2697
  var useComposerAttachments = () => {
2579
- const [attachments, setAttachments] = useState6([]);
2698
+ const [attachments, setAttachments] = useState5([]);
2580
2699
  const attachmentsRef = useRef5([]);
2581
2700
  useEffect3(() => {
2582
2701
  attachmentsRef.current = attachments;
@@ -2694,9 +2813,9 @@ var useChatComposer = () => {
2694
2813
  const clearSessionError = useChatStore((s) => s.clearSessionError);
2695
2814
  const setPreferredMode = useChatStore((s) => s.setPreferredMode);
2696
2815
  const setSessionMode = useChatStore((s) => s.setSessionMode);
2697
- const [availableModels, setAvailableModels] = useState7([]);
2698
- const [isModelsLoading, setIsModelsLoading] = useState7(true);
2699
- const [isModelsError, setIsModelsError] = useState7(false);
2816
+ const [availableModels, setAvailableModels] = useState6([]);
2817
+ const [isModelsLoading, setIsModelsLoading] = useState6(true);
2818
+ const [isModelsError, setIsModelsError] = useState6(false);
2700
2819
  const fetchModels = useCallback3(async () => {
2701
2820
  setIsModelsLoading(true);
2702
2821
  setIsModelsError(false);
@@ -2713,10 +2832,10 @@ var useChatComposer = () => {
2713
2832
  void fetchModels();
2714
2833
  }, [fetchModels]);
2715
2834
  const hasModels = availableModels.length > 0;
2716
- const [value, setValue] = useState7("");
2717
- const [selectedModel, setSelectedModel] = useState7("");
2718
- const [selectedMode, setSelectedModeLocal] = useState7(DEFAULT_CHAT_AGENT_MODE);
2719
- const [attachmentNotice, setAttachmentNotice] = useState7(null);
2835
+ const [value, setValue] = useState6("");
2836
+ const [selectedModel, setSelectedModel] = useState6("");
2837
+ const [selectedMode, setSelectedModeLocal] = useState6(DEFAULT_CHAT_AGENT_MODE);
2838
+ const [attachmentNotice, setAttachmentNotice] = useState6(null);
2720
2839
  const { attachments, appendFiles, removeAttachment, takeMessageAttachments } = useComposerAttachments();
2721
2840
  const abortControllerRef = useRef6(null);
2722
2841
  const stopRequestRef = useRef6(null);
@@ -3012,29 +3131,29 @@ var useChatComposer = () => {
3012
3131
  };
3013
3132
 
3014
3133
  // src/components/chat-composer/components/chat-composer-attachment-list.tsx
3015
- import { useState as useState8 } from "react";
3016
- import styled11 from "@emotion/styled";
3017
- import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs8 } from "@emotion/react/jsx-runtime";
3134
+ import { useState as useState7 } from "react";
3135
+ import styled10 from "@emotion/styled";
3136
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs8 } from "@emotion/react/jsx-runtime";
3018
3137
  var ChatComposerAttachmentList = ({
3019
3138
  attachments,
3020
3139
  onRemoveAttachment
3021
3140
  }) => {
3022
- const [activeImage, setActiveImage] = useState8(null);
3141
+ const [activeImage, setActiveImage] = useState7(null);
3023
3142
  if (!attachments.length) {
3024
3143
  return null;
3025
3144
  }
3026
3145
  return /* @__PURE__ */ jsxs8(Fragment3, { children: [
3027
- /* @__PURE__ */ jsx12(AttachmentList, { "data-testid": "chat-composer-attachment-list", children: attachments.map((attachment) => /* @__PURE__ */ jsxs8(AttachmentCard, { children: [
3028
- /* @__PURE__ */ jsx12(
3146
+ /* @__PURE__ */ jsx11(AttachmentList, { "data-testid": "chat-composer-attachment-list", children: attachments.map((attachment) => /* @__PURE__ */ jsxs8(AttachmentCard, { children: [
3147
+ /* @__PURE__ */ jsx11(
3029
3148
  AttachmentPreviewButton,
3030
3149
  {
3031
3150
  type: "button",
3032
3151
  "aria-label": `${attachment.name} preview`,
3033
3152
  onClick: () => setActiveImage(attachment),
3034
- children: /* @__PURE__ */ jsx12(AttachmentThumb, { src: attachment.previewUrl, alt: attachment.name })
3153
+ children: /* @__PURE__ */ jsx11(AttachmentThumb, { src: attachment.previewUrl, alt: attachment.name })
3035
3154
  }
3036
3155
  ),
3037
- /* @__PURE__ */ jsx12(
3156
+ /* @__PURE__ */ jsx11(
3038
3157
  AttachmentRemoveButton,
3039
3158
  {
3040
3159
  type: "button",
@@ -3043,11 +3162,11 @@ var ChatComposerAttachmentList = ({
3043
3162
  event.stopPropagation();
3044
3163
  onRemoveAttachment(attachment.id);
3045
3164
  },
3046
- children: /* @__PURE__ */ jsx12(CloseGlyph, { "aria-hidden": "true" })
3165
+ children: /* @__PURE__ */ jsx11(CloseGlyph, { "aria-hidden": "true" })
3047
3166
  }
3048
3167
  )
3049
3168
  ] }, attachment.id)) }),
3050
- activeImage ? /* @__PURE__ */ jsx12(
3169
+ activeImage ? /* @__PURE__ */ jsx11(
3051
3170
  ImageViewer,
3052
3171
  {
3053
3172
  src: activeImage.previewUrl,
@@ -3057,7 +3176,7 @@ var ChatComposerAttachmentList = ({
3057
3176
  ) : null
3058
3177
  ] });
3059
3178
  };
3060
- var AttachmentList = styled11.div`
3179
+ var AttachmentList = styled10.div`
3061
3180
  display: flex;
3062
3181
  flex-wrap: wrap;
3063
3182
  gap: 10px;
@@ -3079,7 +3198,7 @@ var AttachmentList = styled11.div`
3079
3198
  background: transparent;
3080
3199
  }
3081
3200
  `;
3082
- var AttachmentCard = styled11.div`
3201
+ var AttachmentCard = styled10.div`
3083
3202
  position: relative;
3084
3203
  width: 108px;
3085
3204
  height: 72px;
@@ -3088,7 +3207,7 @@ var AttachmentCard = styled11.div`
3088
3207
  border: 1px solid rgba(255, 255, 255, 0.12);
3089
3208
  background: rgba(255, 255, 255, 0.04);
3090
3209
  `;
3091
- var AttachmentPreviewButton = styled11.button`
3210
+ var AttachmentPreviewButton = styled10.button`
3092
3211
  width: 100%;
3093
3212
  height: 100%;
3094
3213
  padding: 0;
@@ -3096,13 +3215,13 @@ var AttachmentPreviewButton = styled11.button`
3096
3215
  background: transparent;
3097
3216
  cursor: zoom-in;
3098
3217
  `;
3099
- var AttachmentThumb = styled11.img`
3218
+ var AttachmentThumb = styled10.img`
3100
3219
  width: 100%;
3101
3220
  height: 100%;
3102
3221
  object-fit: cover;
3103
3222
  display: block;
3104
3223
  `;
3105
- var AttachmentRemoveButton = styled11.button`
3224
+ var AttachmentRemoveButton = styled10.button`
3106
3225
  position: absolute;
3107
3226
  top: 6px;
3108
3227
  right: 6px;
@@ -3140,7 +3259,7 @@ var AttachmentRemoveButton = styled11.button`
3140
3259
  background: rgba(30, 30, 35, 0.98);
3141
3260
  }
3142
3261
  `;
3143
- var CloseGlyph = styled11.span`
3262
+ var CloseGlyph = styled10.span`
3144
3263
  position: relative;
3145
3264
  width: 11px;
3146
3265
  height: 11px;
@@ -3169,9 +3288,9 @@ var CloseGlyph = styled11.span`
3169
3288
  `;
3170
3289
 
3171
3290
  // src/components/chat-composer/components/chat-model-control.tsx
3172
- import styled12 from "@emotion/styled";
3291
+ import styled11 from "@emotion/styled";
3173
3292
  import { Select } from "@xinghunm/compass-ui";
3174
- import { jsx as jsx13, jsxs as jsxs9 } from "@emotion/react/jsx-runtime";
3293
+ import { jsx as jsx12, jsxs as jsxs9 } from "@emotion/react/jsx-runtime";
3175
3294
  var ChatModelControl = ({
3176
3295
  selectedModel,
3177
3296
  availableModels,
@@ -3190,7 +3309,7 @@ var ChatModelControl = ({
3190
3309
  "aria-label": "Reload",
3191
3310
  onClick: onReloadModels,
3192
3311
  children: [
3193
- /* @__PURE__ */ jsx13("span", { children: "Failed to load models" }),
3312
+ /* @__PURE__ */ jsx12("span", { children: "Failed to load models" }),
3194
3313
  /* @__PURE__ */ jsxs9(
3195
3314
  ReloadIcon,
3196
3315
  {
@@ -3202,8 +3321,8 @@ var ChatModelControl = ({
3202
3321
  fill: "currentColor",
3203
3322
  xmlns: "http://www.w3.org/2000/svg",
3204
3323
  children: [
3205
- /* @__PURE__ */ jsx13("path", { d: "M895.469672 511.745197c0-146.498562-82.099856-273.805016-202.788589-338.470805l22.072715-46.630017c-4.50664-12.609179-18.382673-19.176758-30.991852-14.670118l-92.436272 33.040511c-12.609179 4.50664-19.176758 18.382673-14.670118 30.991852l33.040511 92.436272c4.50664 12.609179 18.382673 19.176758 30.991852 14.670118l24.581861-51.92972c99.069343 54.335513 166.240185 159.596881 166.240185 280.561907 0 165.56685-125.817544 301.747415-287.057855 318.14692l0 0.022513c-17.730826 0-32.105209 14.374382-32.105209 32.105209 0 17.730826 14.374382 32.105209 32.105209 32.105209 2.098801 0 4.149507-0.207731 6.135744-0.592494C744.270041 874.039593 895.469672 710.564381 895.469672 511.745197z" }),
3206
- /* @__PURE__ */ jsx13("path", { d: "M480.616222 129.23948c-0.041956 0-0.082888 0.00307-0.124843 0.00307l0-0.00307c-0.01535 0.001023-0.031722 0.00307-0.047072 0.004093-1.892093 0.010233-3.744277 0.189312-5.545296 0.5137-194.674794 18.529005-346.957083 182.459588-346.957083 381.987924 0 147.431817 83.146699 275.42798 205.097168 339.700819l-24.814152 52.419883c4.50664 12.609179 18.382673 19.176758 30.991852 14.670118l92.436272-33.040511c12.609179-4.50664 19.176758-18.382673 14.670118-30.991852l-33.040511-92.436272c-4.50664-12.609179-18.382673-19.176758-30.991852-14.670118l-21.853727 46.167482c-100.326986-53.964052-168.535461-159.920246-168.535461-281.81955 0-166.089759 126.616746-302.591643 288.588721-318.284043l0-0.014326c0.041956 0 0.082888 0.00307 0.124843 0.00307 17.730826 0 32.105209-14.374382 32.105209-32.105209C512.721431 143.613862 498.347049 129.23948 480.616222 129.23948z" })
3324
+ /* @__PURE__ */ jsx12("path", { d: "M895.469672 511.745197c0-146.498562-82.099856-273.805016-202.788589-338.470805l22.072715-46.630017c-4.50664-12.609179-18.382673-19.176758-30.991852-14.670118l-92.436272 33.040511c-12.609179 4.50664-19.176758 18.382673-14.670118 30.991852l33.040511 92.436272c4.50664 12.609179 18.382673 19.176758 30.991852 14.670118l24.581861-51.92972c99.069343 54.335513 166.240185 159.596881 166.240185 280.561907 0 165.56685-125.817544 301.747415-287.057855 318.14692l0 0.022513c-17.730826 0-32.105209 14.374382-32.105209 32.105209 0 17.730826 14.374382 32.105209 32.105209 32.105209 2.098801 0 4.149507-0.207731 6.135744-0.592494C744.270041 874.039593 895.469672 710.564381 895.469672 511.745197z" }),
3325
+ /* @__PURE__ */ jsx12("path", { d: "M480.616222 129.23948c-0.041956 0-0.082888 0.00307-0.124843 0.00307l0-0.00307c-0.01535 0.001023-0.031722 0.00307-0.047072 0.004093-1.892093 0.010233-3.744277 0.189312-5.545296 0.5137-194.674794 18.529005-346.957083 182.459588-346.957083 381.987924 0 147.431817 83.146699 275.42798 205.097168 339.700819l-24.814152 52.419883c4.50664 12.609179 18.382673 19.176758 30.991852 14.670118l92.436272-33.040511c12.609179-4.50664 19.176758-18.382673 14.670118-30.991852l-33.040511-92.436272c-4.50664-12.609179-18.382673-19.176758-30.991852-14.670118l-21.853727 46.167482c-100.326986-53.964052-168.535461-159.920246-168.535461-281.81955 0-166.089759 126.616746-302.591643 288.588721-318.284043l0-0.014326c0.041956 0 0.082888 0.00307 0.124843 0.00307 17.730826 0 32.105209-14.374382 32.105209-32.105209C512.721431 143.613862 498.347049 129.23948 480.616222 129.23948z" })
3207
3326
  ]
3208
3327
  }
3209
3328
  )
@@ -3212,11 +3331,11 @@ var ChatModelControl = ({
3212
3331
  );
3213
3332
  }
3214
3333
  if (isModelsLoading) {
3215
- return /* @__PURE__ */ jsx13(ModelBadge, { children: "Loading models..." });
3334
+ return /* @__PURE__ */ jsx12(ModelBadge, { children: "Loading models..." });
3216
3335
  }
3217
3336
  if (hasModels && selectedModel) {
3218
3337
  if (availableModels.length > 1) {
3219
- return /* @__PURE__ */ jsx13(
3338
+ return /* @__PURE__ */ jsx12(
3220
3339
  ModelSelect,
3221
3340
  {
3222
3341
  "data-testid": "chat-model-select",
@@ -3230,11 +3349,11 @@ var ChatModelControl = ({
3230
3349
  }
3231
3350
  );
3232
3351
  }
3233
- return /* @__PURE__ */ jsx13(ModelBadge, { children: selectedModel });
3352
+ return /* @__PURE__ */ jsx12(ModelBadge, { children: selectedModel });
3234
3353
  }
3235
- return /* @__PURE__ */ jsx13(ModelBadge, { children: "No model available" });
3354
+ return /* @__PURE__ */ jsx12(ModelBadge, { children: "No model available" });
3236
3355
  };
3237
- var ModelBadge = styled12.span`
3356
+ var ModelBadge = styled11.span`
3238
3357
  border-radius: 999px;
3239
3358
  border: 1px solid var(--border-hover);
3240
3359
  padding: 5px 12px;
@@ -3243,7 +3362,7 @@ var ModelBadge = styled12.span`
3243
3362
  color: var(--text-secondary);
3244
3363
  line-height: 12px;
3245
3364
  `;
3246
- var ModelReloadButton = styled12.button`
3365
+ var ModelReloadButton = styled11.button`
3247
3366
  display: inline-flex;
3248
3367
  align-items: center;
3249
3368
  gap: 8px;
@@ -3268,10 +3387,10 @@ var ModelReloadButton = styled12.button`
3268
3387
  color: rgba(255, 255, 255, 0.88);
3269
3388
  }
3270
3389
  `;
3271
- var ReloadIcon = styled12.svg`
3390
+ var ReloadIcon = styled11.svg`
3272
3391
  flex-shrink: 0;
3273
3392
  `;
3274
- var ModelSelect = styled12(Select)`
3393
+ var ModelSelect = styled11(Select)`
3275
3394
  && {
3276
3395
  width: auto;
3277
3396
  min-width: 0;
@@ -3291,16 +3410,16 @@ var ModelSelect = styled12(Select)`
3291
3410
  `;
3292
3411
 
3293
3412
  // src/components/chat-composer/components/chat-mode-control.tsx
3294
- import styled13 from "@emotion/styled";
3413
+ import styled12 from "@emotion/styled";
3295
3414
  import { Select as Select2 } from "@xinghunm/compass-ui";
3296
- import { jsx as jsx14 } from "@emotion/react/jsx-runtime";
3415
+ import { jsx as jsx13 } from "@emotion/react/jsx-runtime";
3297
3416
  var ChatModeControl = ({
3298
3417
  value,
3299
3418
  disabled = false,
3300
3419
  labels,
3301
3420
  onChange
3302
3421
  }) => {
3303
- return /* @__PURE__ */ jsx14(
3422
+ return /* @__PURE__ */ jsx13(
3304
3423
  ModeSelect,
3305
3424
  {
3306
3425
  "data-testid": "chat-mode-select",
@@ -3315,7 +3434,7 @@ var ChatModeControl = ({
3315
3434
  }
3316
3435
  );
3317
3436
  };
3318
- var ModeSelect = styled13(Select2)`
3437
+ var ModeSelect = styled12(Select2)`
3319
3438
  && {
3320
3439
  flex: 0 1 auto;
3321
3440
  width: auto;
@@ -3336,10 +3455,10 @@ var ModeSelect = styled13(Select2)`
3336
3455
  `;
3337
3456
 
3338
3457
  // src/components/chat-composer/components/chat-send-actions.tsx
3339
- import styled14 from "@emotion/styled";
3458
+ import styled13 from "@emotion/styled";
3340
3459
  import { Button } from "@xinghunm/compass-ui";
3341
- import { Fragment as Fragment4, jsx as jsx15 } from "@emotion/react/jsx-runtime";
3342
- var ArrowUpIcon = () => /* @__PURE__ */ jsx15(
3460
+ import { Fragment as Fragment4, jsx as jsx14 } from "@emotion/react/jsx-runtime";
3461
+ var ArrowUpIcon = () => /* @__PURE__ */ jsx14(
3343
3462
  "svg",
3344
3463
  {
3345
3464
  "aria-hidden": "true",
@@ -3348,7 +3467,7 @@ var ArrowUpIcon = () => /* @__PURE__ */ jsx15(
3348
3467
  viewBox: "0 0 12 12",
3349
3468
  fill: "none",
3350
3469
  xmlns: "http://www.w3.org/2000/svg",
3351
- children: /* @__PURE__ */ jsx15(
3470
+ children: /* @__PURE__ */ jsx14(
3352
3471
  "path",
3353
3472
  {
3354
3473
  d: "M6 10V2M6 2L2 6M6 2L10 6",
@@ -3366,7 +3485,7 @@ var ChatSendActions = ({
3366
3485
  isStopping,
3367
3486
  onStop,
3368
3487
  onSend
3369
- }) => /* @__PURE__ */ jsx15(Fragment4, { children: isStreaming ? /* @__PURE__ */ jsx15(
3488
+ }) => /* @__PURE__ */ jsx14(Fragment4, { children: isStreaming ? /* @__PURE__ */ jsx14(
3370
3489
  StopButton,
3371
3490
  {
3372
3491
  type: "button",
@@ -3376,14 +3495,14 @@ var ChatSendActions = ({
3376
3495
  disabled: isStopping,
3377
3496
  shape: "circle",
3378
3497
  onClick: () => void onStop(),
3379
- children: /* @__PURE__ */ jsx15(StopGlyph, { "aria-hidden": "true" })
3498
+ children: isStopping ? /* @__PURE__ */ jsx14(StopSpinner, { "aria-hidden": "true", "data-testid": "chat-composer-stop-spinner" }) : /* @__PURE__ */ jsx14(StopGlyph, { "aria-hidden": "true", "data-testid": "chat-composer-stop-glyph" })
3380
3499
  }
3381
- ) : /* @__PURE__ */ jsx15(
3500
+ ) : /* @__PURE__ */ jsx14(
3382
3501
  PrimaryButton,
3383
3502
  {
3384
3503
  $canSend: canSend,
3385
3504
  type: "button",
3386
- icon: /* @__PURE__ */ jsx15(ArrowUpIcon, {}),
3505
+ icon: /* @__PURE__ */ jsx14(ArrowUpIcon, {}),
3387
3506
  "aria-label": "Send",
3388
3507
  "data-testid": "chat-composer-send",
3389
3508
  disabled: !canSend,
@@ -3391,7 +3510,7 @@ var ChatSendActions = ({
3391
3510
  onClick: () => void onSend()
3392
3511
  }
3393
3512
  ) });
3394
- var PrimaryButton = styled14(Button)`
3513
+ var PrimaryButton = styled13(Button)`
3395
3514
  && {
3396
3515
  min-width: 24px;
3397
3516
  width: 24px;
@@ -3417,7 +3536,7 @@ var PrimaryButton = styled14(Button)`
3417
3536
  }
3418
3537
  }
3419
3538
  `;
3420
- var StopButton = styled14(Button)`
3539
+ var StopButton = styled13(Button)`
3421
3540
  && {
3422
3541
  min-width: 24px;
3423
3542
  width: 24px;
@@ -3445,17 +3564,35 @@ var StopButton = styled14(Button)`
3445
3564
  }
3446
3565
  }
3447
3566
  `;
3448
- var StopGlyph = styled14.span`
3567
+ var StopGlyph = styled13.span`
3449
3568
  width: 8px;
3450
3569
  height: 8px;
3451
3570
  border-radius: 2px;
3452
3571
  background: #1b1b1b;
3453
3572
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
3454
3573
  `;
3574
+ var StopSpinner = styled13.span`
3575
+ width: 10px;
3576
+ height: 10px;
3577
+ border-radius: 999px;
3578
+ border: 1.5px solid rgba(27, 27, 27, 0.2);
3579
+ border-top-color: #1b1b1b;
3580
+ animation: chat-composer-stop-spin 0.7s linear infinite;
3581
+
3582
+ @keyframes chat-composer-stop-spin {
3583
+ from {
3584
+ transform: rotate(0deg);
3585
+ }
3586
+
3587
+ to {
3588
+ transform: rotate(360deg);
3589
+ }
3590
+ }
3591
+ `;
3455
3592
 
3456
3593
  // src/components/chat-composer/index.tsx
3457
- import { jsx as jsx16, jsxs as jsxs10 } from "@emotion/react/jsx-runtime";
3458
- var PlusIcon = () => /* @__PURE__ */ jsx16(
3594
+ import { jsx as jsx15, jsxs as jsxs10 } from "@emotion/react/jsx-runtime";
3595
+ var PlusIcon = () => /* @__PURE__ */ jsx15(
3459
3596
  "svg",
3460
3597
  {
3461
3598
  "aria-hidden": "true",
@@ -3464,7 +3601,7 @@ var PlusIcon = () => /* @__PURE__ */ jsx16(
3464
3601
  viewBox: "0 0 16 16",
3465
3602
  fill: "none",
3466
3603
  xmlns: "http://www.w3.org/2000/svg",
3467
- children: /* @__PURE__ */ jsx16("path", { d: "M8 3v10M3 8h10", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" })
3604
+ children: /* @__PURE__ */ jsx15("path", { d: "M8 3v10M3 8h10", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" })
3468
3605
  }
3469
3606
  );
3470
3607
  var ChatComposerView = ({
@@ -3524,8 +3661,8 @@ var ChatComposerView = ({
3524
3661
  event.preventDefault();
3525
3662
  onPasteImages(imageFiles);
3526
3663
  };
3527
- return /* @__PURE__ */ jsx16(Container2, { children: /* @__PURE__ */ jsxs10(Surface, { "data-testid": "chat-composer-surface", children: [
3528
- enableImageAttachments ? /* @__PURE__ */ jsx16(
3664
+ return /* @__PURE__ */ jsx15(Container2, { children: /* @__PURE__ */ jsxs10(Surface, { "data-testid": "chat-composer-surface", children: [
3665
+ enableImageAttachments ? /* @__PURE__ */ jsx15(
3529
3666
  "input",
3530
3667
  {
3531
3668
  ref: imageInputRef,
@@ -3537,15 +3674,15 @@ var ChatComposerView = ({
3537
3674
  onChange: handlePickImages
3538
3675
  }
3539
3676
  ) : null,
3540
- /* @__PURE__ */ jsx16(
3677
+ /* @__PURE__ */ jsx15(
3541
3678
  ChatComposerAttachmentList,
3542
3679
  {
3543
3680
  attachments,
3544
3681
  onRemoveAttachment
3545
3682
  }
3546
3683
  ),
3547
- attachmentNotice === "limit_reached" ? /* @__PURE__ */ jsx16(AttachmentNotice, { "data-testid": "chat-composer-attachment-notice", children: attachmentLimitNotice }) : null,
3548
- /* @__PURE__ */ jsx16(
3684
+ attachmentNotice === "limit_reached" ? /* @__PURE__ */ jsx15(AttachmentNotice, { "data-testid": "chat-composer-attachment-notice", children: attachmentLimitNotice }) : null,
3685
+ /* @__PURE__ */ jsx15(
3549
3686
  Input,
3550
3687
  {
3551
3688
  "data-testid": "chat-composer-input",
@@ -3556,18 +3693,18 @@ var ChatComposerView = ({
3556
3693
  placeholder
3557
3694
  }
3558
3695
  ),
3559
- /* @__PURE__ */ jsx16(Footer, { children: /* @__PURE__ */ jsxs10(Actions2, { "data-testid": "chat-composer-actions", children: [
3560
- enableImageAttachments ? /* @__PURE__ */ jsx16(
3696
+ /* @__PURE__ */ jsx15(Footer, { children: /* @__PURE__ */ jsxs10(Actions2, { "data-testid": "chat-composer-actions", children: [
3697
+ enableImageAttachments ? /* @__PURE__ */ jsx15(
3561
3698
  AttachButton,
3562
3699
  {
3563
3700
  type: "button",
3564
3701
  "data-testid": "chat-composer-attach-image",
3565
3702
  "aria-label": "Attach image",
3566
3703
  onClick: () => imageInputRef.current?.click(),
3567
- children: /* @__PURE__ */ jsx16(PlusIcon, {})
3704
+ children: /* @__PURE__ */ jsx15(PlusIcon, {})
3568
3705
  }
3569
3706
  ) : null,
3570
- /* @__PURE__ */ jsx16(
3707
+ /* @__PURE__ */ jsx15(
3571
3708
  ChatModeControl,
3572
3709
  {
3573
3710
  value: selectedMode,
@@ -3576,7 +3713,7 @@ var ChatComposerView = ({
3576
3713
  onChange: onSelectedModeChange
3577
3714
  }
3578
3715
  ),
3579
- /* @__PURE__ */ jsx16(
3716
+ /* @__PURE__ */ jsx15(
3580
3717
  ChatModelControl,
3581
3718
  {
3582
3719
  selectedModel,
@@ -3588,7 +3725,7 @@ var ChatComposerView = ({
3588
3725
  onReloadModels
3589
3726
  }
3590
3727
  ),
3591
- /* @__PURE__ */ jsx16(
3728
+ /* @__PURE__ */ jsx15(
3592
3729
  ChatSendActions,
3593
3730
  {
3594
3731
  canSend,
@@ -3616,7 +3753,7 @@ var ChatComposer = () => {
3616
3753
  plan: labels.modeLabelPlan,
3617
3754
  agent: labels.modeLabelAgent
3618
3755
  };
3619
- return /* @__PURE__ */ jsx16(
3756
+ return /* @__PURE__ */ jsx15(
3620
3757
  ChatComposerView,
3621
3758
  {
3622
3759
  value: state.value,
@@ -3646,10 +3783,10 @@ var ChatComposer = () => {
3646
3783
  }
3647
3784
  );
3648
3785
  };
3649
- var Container2 = styled15.div`
3786
+ var Container2 = styled14.div`
3650
3787
  padding: 0 16px 16px;
3651
3788
  `;
3652
- var Surface = styled15.div`
3789
+ var Surface = styled14.div`
3653
3790
  background: var(--border-color);
3654
3791
  border-radius: 20px;
3655
3792
  border: 1px solid var(--border-hover);
@@ -3658,7 +3795,7 @@ var Surface = styled15.div`
3658
3795
  0 12px 36px rgba(0, 0, 0, 0.3);
3659
3796
  backdrop-filter: blur(10px);
3660
3797
  `;
3661
- var AttachmentNotice = styled15.div`
3798
+ var AttachmentNotice = styled14.div`
3662
3799
  margin: 10px 12px 0;
3663
3800
  padding: 8px 10px;
3664
3801
  border-radius: 10px;
@@ -3668,7 +3805,7 @@ var AttachmentNotice = styled15.div`
3668
3805
  font-size: 12px;
3669
3806
  line-height: 1.4;
3670
3807
  `;
3671
- var Input = styled15.textarea`
3808
+ var Input = styled14.textarea`
3672
3809
  width: 100%;
3673
3810
  min-height: 96px;
3674
3811
  resize: none;
@@ -3690,14 +3827,14 @@ var Input = styled15.textarea`
3690
3827
  display: none;
3691
3828
  }
3692
3829
  `;
3693
- var Footer = styled15.div`
3830
+ var Footer = styled14.div`
3694
3831
  display: flex;
3695
3832
  align-items: flex-end;
3696
3833
  justify-content: stretch;
3697
3834
  gap: 16px;
3698
3835
  padding: 0 14px 14px;
3699
3836
  `;
3700
- var Actions2 = styled15.div`
3837
+ var Actions2 = styled14.div`
3701
3838
  display: flex;
3702
3839
  align-items: center;
3703
3840
  flex-wrap: wrap;
@@ -3706,7 +3843,7 @@ var Actions2 = styled15.div`
3706
3843
  justify-content: flex-end;
3707
3844
  gap: 8px;
3708
3845
  `;
3709
- var AttachButton = styled15.button`
3846
+ var AttachButton = styled14.button`
3710
3847
  width: 28px;
3711
3848
  height: 28px;
3712
3849
  display: grid;
@@ -3723,42 +3860,42 @@ var AttachButton = styled15.button`
3723
3860
  `;
3724
3861
 
3725
3862
  // src/components/chat-conversation-list/index.tsx
3726
- import styled17 from "@emotion/styled";
3863
+ import styled16 from "@emotion/styled";
3727
3864
 
3728
3865
  // src/components/chat-conversation-list/components/chat-session-item.tsx
3729
- import { memo as memo3 } from "react";
3730
- import styled16 from "@emotion/styled";
3731
- import { jsx as jsx17, jsxs as jsxs11 } from "@emotion/react/jsx-runtime";
3732
- var ChatSessionItem = memo3(
3866
+ import { memo as memo2 } from "react";
3867
+ import styled15 from "@emotion/styled";
3868
+ import { jsx as jsx16, jsxs as jsxs11 } from "@emotion/react/jsx-runtime";
3869
+ var ChatSessionItem = memo2(
3733
3870
  ({ session, isActive, modeLabel, onClick }) => {
3734
- return /* @__PURE__ */ jsx17(
3871
+ return /* @__PURE__ */ jsx16(
3735
3872
  SessionButton,
3736
3873
  {
3737
3874
  type: "button",
3738
3875
  "data-active": isActive,
3739
3876
  onClick: () => onClick(session.sessionId),
3740
3877
  children: /* @__PURE__ */ jsxs11(SessionMeta, { children: [
3741
- /* @__PURE__ */ jsx17(SessionTitle, { children: session.title }),
3742
- /* @__PURE__ */ jsx17(ModeBadge, { children: modeLabel })
3878
+ /* @__PURE__ */ jsx16(SessionTitle, { children: session.title }),
3879
+ /* @__PURE__ */ jsx16(ModeBadge, { children: modeLabel })
3743
3880
  ] })
3744
3881
  }
3745
3882
  );
3746
3883
  }
3747
3884
  );
3748
3885
  ChatSessionItem.displayName = "ChatSessionItem";
3749
- var SessionMeta = styled16.div`
3886
+ var SessionMeta = styled15.div`
3750
3887
  display: flex;
3751
3888
  align-items: center;
3752
3889
  justify-content: space-between;
3753
3890
  gap: 8px;
3754
3891
  `;
3755
- var SessionTitle = styled16.span`
3892
+ var SessionTitle = styled15.span`
3756
3893
  min-width: 0;
3757
3894
  overflow: hidden;
3758
3895
  text-overflow: ellipsis;
3759
3896
  white-space: nowrap;
3760
3897
  `;
3761
- var SessionButton = styled16.button`
3898
+ var SessionButton = styled15.button`
3762
3899
  border: 1px solid transparent;
3763
3900
  border-radius: 12px;
3764
3901
  padding: 12px;
@@ -3772,7 +3909,7 @@ var SessionButton = styled16.button`
3772
3909
  background: rgba(255, 255, 255, 0.08);
3773
3910
  }
3774
3911
  `;
3775
- var ModeBadge = styled16.span`
3912
+ var ModeBadge = styled15.span`
3776
3913
  flex-shrink: 0;
3777
3914
  border-radius: 999px;
3778
3915
  border: 1px solid rgba(255, 255, 255, 0.1);
@@ -3784,7 +3921,7 @@ var ModeBadge = styled16.span`
3784
3921
  `;
3785
3922
 
3786
3923
  // src/components/chat-conversation-list/index.tsx
3787
- import { jsx as jsx18, jsxs as jsxs12 } from "@emotion/react/jsx-runtime";
3924
+ import { jsx as jsx17, jsxs as jsxs12 } from "@emotion/react/jsx-runtime";
3788
3925
  var ChatConversationList = () => {
3789
3926
  const { labels } = useChatContext();
3790
3927
  const sessions = useChatStore((s) => s.sessions);
@@ -3809,10 +3946,10 @@ var ChatConversationList = () => {
3809
3946
  };
3810
3947
  return /* @__PURE__ */ jsxs12(Container3, { children: [
3811
3948
  /* @__PURE__ */ jsxs12(Toolbar, { children: [
3812
- /* @__PURE__ */ jsx18(Title4, { children: "Sessions" }),
3813
- /* @__PURE__ */ jsx18(CreateButton, { type: "button", "data-testid": "chat-create-session", onClick: handleCreateSession, children: labels.newChat })
3949
+ /* @__PURE__ */ jsx17(Title4, { children: "Sessions" }),
3950
+ /* @__PURE__ */ jsx17(CreateButton, { type: "button", "data-testid": "chat-create-session", onClick: handleCreateSession, children: labels.newChat })
3814
3951
  ] }),
3815
- /* @__PURE__ */ jsx18(List2, { "data-testid": "chat-session-list", children: sessions.map((session) => /* @__PURE__ */ jsx18(
3952
+ /* @__PURE__ */ jsx17(List2, { "data-testid": "chat-session-list", children: sessions.map((session) => /* @__PURE__ */ jsx17(
3816
3953
  ChatSessionItem,
3817
3954
  {
3818
3955
  session,
@@ -3824,7 +3961,7 @@ var ChatConversationList = () => {
3824
3961
  )) })
3825
3962
  ] });
3826
3963
  };
3827
- var Container3 = styled17.aside`
3964
+ var Container3 = styled16.aside`
3828
3965
  width: 280px;
3829
3966
  min-width: 280px;
3830
3967
  border-right: 1px solid var(--border-default, rgba(255, 255, 255, 0.08));
@@ -3832,18 +3969,18 @@ var Container3 = styled17.aside`
3832
3969
  flex-direction: column;
3833
3970
  background: rgba(255, 255, 255, 0.02);
3834
3971
  `;
3835
- var Toolbar = styled17.div`
3972
+ var Toolbar = styled16.div`
3836
3973
  padding: 20px 16px 12px;
3837
3974
  display: flex;
3838
3975
  flex-direction: column;
3839
3976
  gap: 12px;
3840
3977
  `;
3841
- var Title4 = styled17.h2`
3978
+ var Title4 = styled16.h2`
3842
3979
  margin: 0;
3843
3980
  font-size: 14px;
3844
3981
  color: var(--text-secondary);
3845
3982
  `;
3846
- var CreateButton = styled17.button`
3983
+ var CreateButton = styled16.button`
3847
3984
  border: none;
3848
3985
  border-radius: 12px;
3849
3986
  padding: 12px 14px;
@@ -3852,7 +3989,7 @@ var CreateButton = styled17.button`
3852
3989
  text-align: left;
3853
3990
  cursor: pointer;
3854
3991
  `;
3855
- var List2 = styled17.div`
3992
+ var List2 = styled16.div`
3856
3993
  padding: 0 12px 16px;
3857
3994
  display: flex;
3858
3995
  flex-direction: column;
@@ -3861,8 +3998,8 @@ var List2 = styled17.div`
3861
3998
  `;
3862
3999
 
3863
4000
  // src/components/ai-chat/index.tsx
3864
- import { jsx as jsx19, jsxs as jsxs13 } from "@emotion/react/jsx-runtime";
3865
- var AiChat = ({ showConversationList = false, ...providerProps }) => /* @__PURE__ */ jsx19(
4001
+ import { jsx as jsx18, jsxs as jsxs13 } from "@emotion/react/jsx-runtime";
4002
+ var AiChat = ({ showConversationList = false, ...providerProps }) => /* @__PURE__ */ jsx18(
3866
4003
  ConfigProvider,
3867
4004
  {
3868
4005
  theme: {
@@ -3897,23 +4034,23 @@ var AiChat = ({ showConversationList = false, ...providerProps }) => /* @__PURE_
3897
4034
  }
3898
4035
  }
3899
4036
  },
3900
- children: /* @__PURE__ */ jsx19(AiChatProvider, { ...providerProps, children: /* @__PURE__ */ jsxs13(Root, { "data-testid": "ai-chat", children: [
3901
- showConversationList ? /* @__PURE__ */ jsx19(ChatConversationList, {}) : null,
4037
+ children: /* @__PURE__ */ jsx18(AiChatProvider, { ...providerProps, children: /* @__PURE__ */ jsxs13(Root, { "data-testid": "ai-chat", children: [
4038
+ showConversationList ? /* @__PURE__ */ jsx18(ChatConversationList, {}) : null,
3902
4039
  /* @__PURE__ */ jsxs13(Workspace, { children: [
3903
- /* @__PURE__ */ jsx19(ChatThread, {}),
3904
- /* @__PURE__ */ jsx19(ChatComposer, {})
4040
+ /* @__PURE__ */ jsx18(ChatThread, {}),
4041
+ /* @__PURE__ */ jsx18(ChatComposer, {})
3905
4042
  ] })
3906
4043
  ] }) })
3907
4044
  }
3908
4045
  );
3909
- var Root = styled18.div`
4046
+ var Root = styled17.div`
3910
4047
  display: flex;
3911
4048
  width: 100%;
3912
4049
  height: 100%;
3913
4050
  min-height: 0;
3914
4051
  overflow: hidden;
3915
4052
  `;
3916
- var Workspace = styled18.section`
4053
+ var Workspace = styled17.section`
3917
4054
  flex: 1;
3918
4055
  display: flex;
3919
4056
  flex-direction: column;