@xinghunm/ai-chat 0.2.1 → 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 +378 -294
  2. package/dist/index.mjs +331 -247
  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
@@ -591,7 +591,7 @@ var AiChatProvider = (props) => {
591
591
 
592
592
  // src/components/chat-thread/index.tsx
593
593
  import { useCallback as useCallback2, useLayoutEffect, useMemo as useMemo3, useRef as useRef4, useState as useState4 } from "react";
594
- import styled10 from "@emotion/styled";
594
+ import styled9 from "@emotion/styled";
595
595
 
596
596
  // src/context/use-chat-context.ts
597
597
  import { useContext } from "react";
@@ -609,22 +609,6 @@ 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
614
  import { Fragment, memo, useState as useState3 } from "react";
@@ -856,11 +840,21 @@ var useChatMessageReveal = (message) => {
856
840
  }, [batchedTargetUnitCount, displayedUnitCount, isAssistantStreaming, message.role]);
857
841
  const settledContent = isFreshBlockActive ? contentBlocks.slice(0, -1).join("\n\n") : displayedContent;
858
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
+ ];
859
852
  return {
860
853
  isAssistantStreaming,
861
854
  displayedContent,
862
855
  settledContent,
863
- freshContent
856
+ freshContent,
857
+ displayedBlocks
864
858
  };
865
859
  };
866
860
 
@@ -1808,7 +1802,7 @@ var ChatMessageItemView = ({
1808
1802
  }) => {
1809
1803
  const { labels } = useChatContext();
1810
1804
  const [activeImage, setActiveImage] = useState3(void 0);
1811
- const { displayedContent, freshContent, isAssistantStreaming, settledContent } = useChatMessageReveal(message);
1805
+ const { displayedBlocks, displayedContent, freshContent, isAssistantStreaming, settledContent } = useChatMessageReveal(message);
1812
1806
  const isStoppedAssistant = message.role === "assistant" && message.status === "stopped";
1813
1807
  const attachments = message.attachments ?? [];
1814
1808
  const blocks = message.blocks ?? [];
@@ -1877,9 +1871,17 @@ var ChatMessageItemView = ({
1877
1871
  }
1878
1872
  };
1879
1873
  const renderTextContent = () => /* @__PURE__ */ jsxs5(Fragment2, { children: [
1880
- settledContent ? /* @__PURE__ */ jsx8(ContentBlock, { "data-testid": "chat-message-settled-block", "data-block-tone": "settled", children: renderMarkdownContent(settledContent) }) : null,
1881
- freshContent ? /* @__PURE__ */ jsx8(ContentBlock, { "data-testid": "chat-message-fresh-block", "data-block-tone": "fresh", children: renderMarkdownContent(freshContent) }) : null,
1882
- !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
1883
1885
  ] });
1884
1886
  return /* @__PURE__ */ jsxs5(Fragment2, { children: [
1885
1887
  /* @__PURE__ */ jsxs5(Bubble, { "data-role": message.role, "data-status": message.status ?? "done", children: [
@@ -2143,65 +2145,21 @@ var StreamingCaret = styled7.span`
2143
2145
  animation: ${caretBlink} 0.9s steps(1) infinite;
2144
2146
  `;
2145
2147
 
2146
- // src/components/chat-thread/components/chat-thread-history-list.tsx
2147
- import { memo as memo2 } from "react";
2148
- import styled8 from "@emotion/styled";
2149
- import { jsx as jsx9 } from "@emotion/react/jsx-runtime";
2150
- var ChatThreadHistoryList = memo2(
2151
- ({
2152
- mode,
2153
- historyMessages,
2154
- latestUserMessageId,
2155
- latestUserMessageRef,
2156
- onConfirmationSubmit,
2157
- onQuestionnaireSubmit,
2158
- renderMessageBlock
2159
- }) => /* @__PURE__ */ jsx9(HistoryGroup, { "data-testid": "chat-thread-history", children: historyMessages.map((message) => /* @__PURE__ */ jsx9(
2160
- MessageSlot,
2161
- {
2162
- ref: message.id === latestUserMessageId ? latestUserMessageRef : null,
2163
- "data-testid": message.id === latestUserMessageId ? "chat-latest-user-anchor" : void 0,
2164
- style: message.id === latestUserMessageId ? {
2165
- scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px`
2166
- } : void 0,
2167
- children: /* @__PURE__ */ jsx9(
2168
- ChatMessageItem,
2169
- {
2170
- mode,
2171
- message,
2172
- onConfirmationSubmit,
2173
- onQuestionnaireSubmit,
2174
- renderMessageBlock
2175
- }
2176
- )
2177
- },
2178
- message.id
2179
- )) })
2180
- );
2181
- ChatThreadHistoryList.displayName = "ChatThreadHistoryList";
2182
- var HistoryGroup = styled8.div`
2183
- display: contents;
2184
- `;
2185
- var MessageSlot = styled8.div`
2186
- display: flex;
2187
- align-items: flex-start;
2188
- `;
2189
-
2190
2148
  // src/components/chat-thread/components/chat-thread-empty-state.tsx
2191
- import styled9 from "@emotion/styled";
2192
- 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";
2193
2151
  var ChatThreadEmptyState = () => {
2194
2152
  const { labels } = useChatContext();
2195
2153
  return /* @__PURE__ */ jsxs6(EmptyShell, { "data-testid": "chat-empty-hero", children: [
2196
2154
  /* @__PURE__ */ jsxs6(HeroMark, { children: [
2197
- /* @__PURE__ */ jsx10(HeroOrbit, {}),
2198
- /* @__PURE__ */ jsx10(HeroCore, { children: "AI" })
2155
+ /* @__PURE__ */ jsx9(HeroOrbit, {}),
2156
+ /* @__PURE__ */ jsx9(HeroCore, { children: "AI" })
2199
2157
  ] }),
2200
- /* @__PURE__ */ jsx10(HeroTitle, { children: labels.emptyStateTitle }),
2201
- /* @__PURE__ */ jsx10(HeroSubtitle, { children: labels.emptyStateSubtitle })
2158
+ /* @__PURE__ */ jsx9(HeroTitle, { children: labels.emptyStateTitle }),
2159
+ /* @__PURE__ */ jsx9(HeroSubtitle, { children: labels.emptyStateSubtitle })
2202
2160
  ] });
2203
2161
  };
2204
- var EmptyShell = styled9.div`
2162
+ var EmptyShell = styled8.div`
2205
2163
  flex: 1;
2206
2164
  min-height: 0;
2207
2165
  display: flex;
@@ -2211,7 +2169,7 @@ var EmptyShell = styled9.div`
2211
2169
  gap: 16px;
2212
2170
  padding: 48px 24px 24px;
2213
2171
  `;
2214
- var HeroMark = styled9.div`
2172
+ var HeroMark = styled8.div`
2215
2173
  position: relative;
2216
2174
  width: 108px;
2217
2175
  height: 108px;
@@ -2219,7 +2177,7 @@ var HeroMark = styled9.div`
2219
2177
  display: grid;
2220
2178
  place-items: center;
2221
2179
  `;
2222
- var HeroOrbit = styled9.div`
2180
+ var HeroOrbit = styled8.div`
2223
2181
  position: absolute;
2224
2182
  inset: 20px;
2225
2183
  border-radius: 50%;
@@ -2242,7 +2200,7 @@ var HeroOrbit = styled9.div`
2242
2200
  transform: rotate(-22deg);
2243
2201
  }
2244
2202
  `;
2245
- var HeroCore = styled9.div`
2203
+ var HeroCore = styled8.div`
2246
2204
  position: relative;
2247
2205
  z-index: 1;
2248
2206
  font-size: 28px;
@@ -2252,13 +2210,13 @@ var HeroCore = styled9.div`
2252
2210
  color: rgba(242, 244, 255, 0.96);
2253
2211
  text-shadow: 0 0 16px rgba(98, 116, 255, 0.65);
2254
2212
  `;
2255
- var HeroTitle = styled9.p`
2213
+ var HeroTitle = styled8.p`
2256
2214
  margin: 0;
2257
2215
  color: rgba(255, 255, 255, 0.88);
2258
2216
  font-size: 16px;
2259
2217
  line-height: 24px;
2260
2218
  `;
2261
- var HeroSubtitle = styled9.p`
2219
+ var HeroSubtitle = styled8.p`
2262
2220
  margin: 0;
2263
2221
  color: rgba(255, 255, 255, 0.72);
2264
2222
  font-size: 14px;
@@ -2266,7 +2224,74 @@ var HeroSubtitle = styled9.p`
2266
2224
  `;
2267
2225
 
2268
2226
  // src/components/chat-thread/index.tsx
2269
- 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
+ };
2270
2295
  var ChatThreadView = ({
2271
2296
  activeSessionMode = DEFAULT_CHAT_AGENT_MODE,
2272
2297
  historyMessages,
@@ -2279,31 +2304,45 @@ var ChatThreadView = ({
2279
2304
  renderMessageBlock
2280
2305
  }) => {
2281
2306
  const containerRef = useRef4(null);
2282
- const latestUserMessageId = useMemo3(
2283
- () => findLatestUserMessageId(historyMessages),
2284
- [historyMessages]
2307
+ const conversationTurns = useMemo3(
2308
+ () => groupConversationTurns(historyMessages, streamingMessage),
2309
+ [historyMessages, streamingMessage]
2285
2310
  );
2311
+ const latestTurn = conversationTurns[conversationTurns.length - 1];
2312
+ const previousTurns = conversationTurns.slice(0, -1);
2313
+ const latestUserMessageId = latestTurn?.userMessage?.id;
2286
2314
  const latestUserMessageRef = useRef4(null);
2287
- const pendingScrollUserMessageIdRef = useRef4(void 0);
2288
2315
  const reservedSpaceFrameRef = useRef4(null);
2289
- const [latestUserMessageReservedSpace, setLatestUserMessageReservedSpace] = useState4({ messageId: void 0, value: 0 });
2290
- const reservedPaddingBottom = 24 + (latestUserMessageReservedSpace.messageId === latestUserMessageId ? latestUserMessageReservedSpace.value : 0);
2291
- 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(() => {
2292
2328
  const container = containerRef.current;
2293
2329
  const target = latestUserMessageRef.current;
2294
2330
  if (!container || !target)
2295
2331
  return;
2296
- const reservedHeight = calculateChatThreadScrollSpacerHeight({
2297
- containerClientHeight: container.clientHeight,
2298
- containerScrollHeight: container.scrollHeight,
2299
- targetOffsetTop: target.offsetTop
2300
- });
2301
- setLatestUserMessageReservedSpace((current) => {
2302
- const next = reservedHeight > 0 ? reservedHeight : 0;
2303
- if (current.messageId === messageId && current.value === next)
2304
- return current;
2305
- return { messageId, value: next };
2306
- });
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;
2307
2346
  }, []);
2308
2347
  useLayoutEffect(() => {
2309
2348
  if (reservedSpaceFrameRef.current !== null) {
@@ -2311,12 +2350,9 @@ var ChatThreadView = ({
2311
2350
  reservedSpaceFrameRef.current = null;
2312
2351
  }
2313
2352
  if (!latestUserMessageId) {
2314
- pendingScrollUserMessageIdRef.current = void 0;
2315
2353
  reservedSpaceFrameRef.current = window.requestAnimationFrame(() => {
2316
2354
  reservedSpaceFrameRef.current = null;
2317
- setLatestUserMessageReservedSpace(
2318
- (current) => current.messageId === void 0 && current.value === 0 ? current : { messageId: void 0, value: 0 }
2319
- );
2355
+ setLatestTurnMinHeight((current) => current === 0 ? current : 0);
2320
2356
  });
2321
2357
  return () => {
2322
2358
  if (reservedSpaceFrameRef.current !== null) {
@@ -2325,10 +2361,10 @@ var ChatThreadView = ({
2325
2361
  }
2326
2362
  };
2327
2363
  }
2328
- pendingScrollUserMessageIdRef.current = latestUserMessageId;
2329
2364
  reservedSpaceFrameRef.current = window.requestAnimationFrame(() => {
2330
2365
  reservedSpaceFrameRef.current = null;
2331
- measureLatestUserMessageReservedSpace(latestUserMessageId);
2366
+ measureLatestTurnMinHeight();
2367
+ scrollLatestUserMessageToTop();
2332
2368
  });
2333
2369
  return () => {
2334
2370
  if (reservedSpaceFrameRef.current !== null) {
@@ -2336,51 +2372,79 @@ var ChatThreadView = ({
2336
2372
  reservedSpaceFrameRef.current = null;
2337
2373
  }
2338
2374
  };
2339
- }, [latestUserMessageId, measureLatestUserMessageReservedSpace]);
2375
+ }, [latestUserMessageId, measureLatestTurnMinHeight, scrollLatestUserMessageToTop]);
2340
2376
  useLayoutEffect(() => {
2341
- if (!latestUserMessageId || pendingScrollUserMessageIdRef.current !== latestUserMessageId)
2377
+ if (!latestUserMessageId)
2342
2378
  return;
2343
- if (latestUserMessageReservedSpace.messageId !== latestUserMessageId)
2344
- return;
2345
- latestUserMessageRef.current?.scrollIntoView({ block: "start", behavior: "smooth" });
2346
- pendingScrollUserMessageIdRef.current = void 0;
2347
- }, [latestUserMessageId, latestUserMessageReservedSpace]);
2348
- return /* @__PURE__ */ jsxs7(
2349
- Container,
2350
- {
2351
- ref: containerRef,
2352
- "data-testid": "chat-thread",
2353
- style: { paddingBottom: `${reservedPaddingBottom}px` },
2354
- children: [
2355
- /* @__PURE__ */ jsx11(
2356
- ChatThreadHistoryList,
2357
- {
2358
- mode: activeSessionMode,
2359
- historyMessages,
2360
- latestUserMessageId,
2361
- latestUserMessageRef,
2362
- onConfirmationSubmit,
2363
- onQuestionnaireSubmit,
2364
- renderMessageBlock
2365
- }
2366
- ),
2367
- streamingMessage ? /* @__PURE__ */ jsx11(StreamingGroup, { "data-testid": "chat-thread-streaming", children: /* @__PURE__ */ jsx11(MessageSlot2, { children: /* @__PURE__ */ jsx11(
2368
- ChatMessageItem,
2369
- {
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,
2370
2437
  mode: activeSessionMode,
2371
- message: streamingMessage,
2372
2438
  onConfirmationSubmit,
2373
2439
  onQuestionnaireSubmit,
2374
2440
  renderMessageBlock
2375
- }
2376
- ) }) }) : null,
2377
- error ? /* @__PURE__ */ jsxs7(ErrorState, { "data-testid": "chat-thread-error-state", children: [
2378
- /* @__PURE__ */ jsx11(ErrorText, { children: error }),
2379
- onRetry ? /* @__PURE__ */ jsx11(ErrorActions, { children: /* @__PURE__ */ jsx11(RetryButton, { type: "button", "data-testid": "chat-thread-retry", onClick: onRetry, children: retryButtonLabel }) }) : null
2380
- ] }) : null
2381
- ]
2382
- }
2383
- );
2441
+ }) }, message.id)),
2442
+ error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
2443
+ ]
2444
+ }
2445
+ ) : null,
2446
+ !latestTurn && error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
2447
+ ] });
2384
2448
  };
2385
2449
  var EMPTY_MESSAGES = [];
2386
2450
  var ChatThread = () => {
@@ -2424,9 +2488,9 @@ var ChatThread = () => {
2424
2488
  [sendRef]
2425
2489
  );
2426
2490
  if (!hasSessions || messages.length === 0 && !streamingMessage) {
2427
- return /* @__PURE__ */ jsx11(ChatThreadEmptyState, {});
2491
+ return /* @__PURE__ */ jsx10(ChatThreadEmptyState, {});
2428
2492
  }
2429
- return /* @__PURE__ */ jsx11(
2493
+ return /* @__PURE__ */ jsx10(
2430
2494
  ChatThreadView,
2431
2495
  {
2432
2496
  activeSessionMode,
@@ -2441,7 +2505,7 @@ var ChatThread = () => {
2441
2505
  }
2442
2506
  );
2443
2507
  };
2444
- var Container = styled10.div`
2508
+ var Container = styled9.div`
2445
2509
  display: flex;
2446
2510
  flex: 1;
2447
2511
  flex-direction: column;
@@ -2464,27 +2528,29 @@ var Container = styled10.div`
2464
2528
  background: transparent;
2465
2529
  }
2466
2530
  `;
2467
- var MessageSlot2 = styled10.div`
2531
+ var MessageSlot = styled9.div`
2468
2532
  display: flex;
2469
2533
  `;
2470
- var StreamingGroup = styled10.div`
2471
- display: contents;
2534
+ var ConversationTurn = styled9.div`
2535
+ display: flex;
2536
+ flex-direction: column;
2537
+ gap: 18px;
2472
2538
  `;
2473
- var ErrorText = styled10.div`
2539
+ var ErrorText = styled9.div`
2474
2540
  color: #ff7b72;
2475
2541
  font-size: 14px;
2476
2542
  `;
2477
- var ErrorState = styled10.div`
2543
+ var ErrorState = styled9.div`
2478
2544
  display: flex;
2479
2545
  flex-direction: column;
2480
2546
  align-items: flex-start;
2481
2547
  gap: 10px;
2482
2548
  `;
2483
- var ErrorActions = styled10.div`
2549
+ var ErrorActions = styled9.div`
2484
2550
  display: flex;
2485
2551
  align-items: center;
2486
2552
  `;
2487
- var RetryButton = styled10.button`
2553
+ var RetryButton = styled9.button`
2488
2554
  border: 1px solid rgba(255, 255, 255, 0.14);
2489
2555
  border-radius: 999px;
2490
2556
  background: rgba(255, 255, 255, 0.04);
@@ -2501,7 +2567,7 @@ var RetryButton = styled10.button`
2501
2567
 
2502
2568
  // src/components/chat-composer/index.tsx
2503
2569
  import { useEffect as useEffect5, useRef as useRef7 } from "react";
2504
- import styled15 from "@emotion/styled";
2570
+ import styled14 from "@emotion/styled";
2505
2571
 
2506
2572
  // src/components/chat-composer/lib/chat-composer.ts
2507
2573
  var DRAFT_CHAT_SESSION_ID_PREFIX = "draft-session-";
@@ -3066,8 +3132,8 @@ var useChatComposer = () => {
3066
3132
 
3067
3133
  // src/components/chat-composer/components/chat-composer-attachment-list.tsx
3068
3134
  import { useState as useState7 } from "react";
3069
- import styled11 from "@emotion/styled";
3070
- import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs8 } from "@emotion/react/jsx-runtime";
3135
+ import styled10 from "@emotion/styled";
3136
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs8 } from "@emotion/react/jsx-runtime";
3071
3137
  var ChatComposerAttachmentList = ({
3072
3138
  attachments,
3073
3139
  onRemoveAttachment
@@ -3077,17 +3143,17 @@ var ChatComposerAttachmentList = ({
3077
3143
  return null;
3078
3144
  }
3079
3145
  return /* @__PURE__ */ jsxs8(Fragment3, { children: [
3080
- /* @__PURE__ */ jsx12(AttachmentList, { "data-testid": "chat-composer-attachment-list", children: attachments.map((attachment) => /* @__PURE__ */ jsxs8(AttachmentCard, { children: [
3081
- /* @__PURE__ */ jsx12(
3146
+ /* @__PURE__ */ jsx11(AttachmentList, { "data-testid": "chat-composer-attachment-list", children: attachments.map((attachment) => /* @__PURE__ */ jsxs8(AttachmentCard, { children: [
3147
+ /* @__PURE__ */ jsx11(
3082
3148
  AttachmentPreviewButton,
3083
3149
  {
3084
3150
  type: "button",
3085
3151
  "aria-label": `${attachment.name} preview`,
3086
3152
  onClick: () => setActiveImage(attachment),
3087
- children: /* @__PURE__ */ jsx12(AttachmentThumb, { src: attachment.previewUrl, alt: attachment.name })
3153
+ children: /* @__PURE__ */ jsx11(AttachmentThumb, { src: attachment.previewUrl, alt: attachment.name })
3088
3154
  }
3089
3155
  ),
3090
- /* @__PURE__ */ jsx12(
3156
+ /* @__PURE__ */ jsx11(
3091
3157
  AttachmentRemoveButton,
3092
3158
  {
3093
3159
  type: "button",
@@ -3096,11 +3162,11 @@ var ChatComposerAttachmentList = ({
3096
3162
  event.stopPropagation();
3097
3163
  onRemoveAttachment(attachment.id);
3098
3164
  },
3099
- children: /* @__PURE__ */ jsx12(CloseGlyph, { "aria-hidden": "true" })
3165
+ children: /* @__PURE__ */ jsx11(CloseGlyph, { "aria-hidden": "true" })
3100
3166
  }
3101
3167
  )
3102
3168
  ] }, attachment.id)) }),
3103
- activeImage ? /* @__PURE__ */ jsx12(
3169
+ activeImage ? /* @__PURE__ */ jsx11(
3104
3170
  ImageViewer,
3105
3171
  {
3106
3172
  src: activeImage.previewUrl,
@@ -3110,7 +3176,7 @@ var ChatComposerAttachmentList = ({
3110
3176
  ) : null
3111
3177
  ] });
3112
3178
  };
3113
- var AttachmentList = styled11.div`
3179
+ var AttachmentList = styled10.div`
3114
3180
  display: flex;
3115
3181
  flex-wrap: wrap;
3116
3182
  gap: 10px;
@@ -3132,7 +3198,7 @@ var AttachmentList = styled11.div`
3132
3198
  background: transparent;
3133
3199
  }
3134
3200
  `;
3135
- var AttachmentCard = styled11.div`
3201
+ var AttachmentCard = styled10.div`
3136
3202
  position: relative;
3137
3203
  width: 108px;
3138
3204
  height: 72px;
@@ -3141,7 +3207,7 @@ var AttachmentCard = styled11.div`
3141
3207
  border: 1px solid rgba(255, 255, 255, 0.12);
3142
3208
  background: rgba(255, 255, 255, 0.04);
3143
3209
  `;
3144
- var AttachmentPreviewButton = styled11.button`
3210
+ var AttachmentPreviewButton = styled10.button`
3145
3211
  width: 100%;
3146
3212
  height: 100%;
3147
3213
  padding: 0;
@@ -3149,13 +3215,13 @@ var AttachmentPreviewButton = styled11.button`
3149
3215
  background: transparent;
3150
3216
  cursor: zoom-in;
3151
3217
  `;
3152
- var AttachmentThumb = styled11.img`
3218
+ var AttachmentThumb = styled10.img`
3153
3219
  width: 100%;
3154
3220
  height: 100%;
3155
3221
  object-fit: cover;
3156
3222
  display: block;
3157
3223
  `;
3158
- var AttachmentRemoveButton = styled11.button`
3224
+ var AttachmentRemoveButton = styled10.button`
3159
3225
  position: absolute;
3160
3226
  top: 6px;
3161
3227
  right: 6px;
@@ -3193,7 +3259,7 @@ var AttachmentRemoveButton = styled11.button`
3193
3259
  background: rgba(30, 30, 35, 0.98);
3194
3260
  }
3195
3261
  `;
3196
- var CloseGlyph = styled11.span`
3262
+ var CloseGlyph = styled10.span`
3197
3263
  position: relative;
3198
3264
  width: 11px;
3199
3265
  height: 11px;
@@ -3222,9 +3288,9 @@ var CloseGlyph = styled11.span`
3222
3288
  `;
3223
3289
 
3224
3290
  // src/components/chat-composer/components/chat-model-control.tsx
3225
- import styled12 from "@emotion/styled";
3291
+ import styled11 from "@emotion/styled";
3226
3292
  import { Select } from "@xinghunm/compass-ui";
3227
- 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";
3228
3294
  var ChatModelControl = ({
3229
3295
  selectedModel,
3230
3296
  availableModels,
@@ -3243,7 +3309,7 @@ var ChatModelControl = ({
3243
3309
  "aria-label": "Reload",
3244
3310
  onClick: onReloadModels,
3245
3311
  children: [
3246
- /* @__PURE__ */ jsx13("span", { children: "Failed to load models" }),
3312
+ /* @__PURE__ */ jsx12("span", { children: "Failed to load models" }),
3247
3313
  /* @__PURE__ */ jsxs9(
3248
3314
  ReloadIcon,
3249
3315
  {
@@ -3255,8 +3321,8 @@ var ChatModelControl = ({
3255
3321
  fill: "currentColor",
3256
3322
  xmlns: "http://www.w3.org/2000/svg",
3257
3323
  children: [
3258
- /* @__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" }),
3259
- /* @__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" })
3260
3326
  ]
3261
3327
  }
3262
3328
  )
@@ -3265,11 +3331,11 @@ var ChatModelControl = ({
3265
3331
  );
3266
3332
  }
3267
3333
  if (isModelsLoading) {
3268
- return /* @__PURE__ */ jsx13(ModelBadge, { children: "Loading models..." });
3334
+ return /* @__PURE__ */ jsx12(ModelBadge, { children: "Loading models..." });
3269
3335
  }
3270
3336
  if (hasModels && selectedModel) {
3271
3337
  if (availableModels.length > 1) {
3272
- return /* @__PURE__ */ jsx13(
3338
+ return /* @__PURE__ */ jsx12(
3273
3339
  ModelSelect,
3274
3340
  {
3275
3341
  "data-testid": "chat-model-select",
@@ -3283,11 +3349,11 @@ var ChatModelControl = ({
3283
3349
  }
3284
3350
  );
3285
3351
  }
3286
- return /* @__PURE__ */ jsx13(ModelBadge, { children: selectedModel });
3352
+ return /* @__PURE__ */ jsx12(ModelBadge, { children: selectedModel });
3287
3353
  }
3288
- return /* @__PURE__ */ jsx13(ModelBadge, { children: "No model available" });
3354
+ return /* @__PURE__ */ jsx12(ModelBadge, { children: "No model available" });
3289
3355
  };
3290
- var ModelBadge = styled12.span`
3356
+ var ModelBadge = styled11.span`
3291
3357
  border-radius: 999px;
3292
3358
  border: 1px solid var(--border-hover);
3293
3359
  padding: 5px 12px;
@@ -3296,7 +3362,7 @@ var ModelBadge = styled12.span`
3296
3362
  color: var(--text-secondary);
3297
3363
  line-height: 12px;
3298
3364
  `;
3299
- var ModelReloadButton = styled12.button`
3365
+ var ModelReloadButton = styled11.button`
3300
3366
  display: inline-flex;
3301
3367
  align-items: center;
3302
3368
  gap: 8px;
@@ -3321,10 +3387,10 @@ var ModelReloadButton = styled12.button`
3321
3387
  color: rgba(255, 255, 255, 0.88);
3322
3388
  }
3323
3389
  `;
3324
- var ReloadIcon = styled12.svg`
3390
+ var ReloadIcon = styled11.svg`
3325
3391
  flex-shrink: 0;
3326
3392
  `;
3327
- var ModelSelect = styled12(Select)`
3393
+ var ModelSelect = styled11(Select)`
3328
3394
  && {
3329
3395
  width: auto;
3330
3396
  min-width: 0;
@@ -3344,16 +3410,16 @@ var ModelSelect = styled12(Select)`
3344
3410
  `;
3345
3411
 
3346
3412
  // src/components/chat-composer/components/chat-mode-control.tsx
3347
- import styled13 from "@emotion/styled";
3413
+ import styled12 from "@emotion/styled";
3348
3414
  import { Select as Select2 } from "@xinghunm/compass-ui";
3349
- import { jsx as jsx14 } from "@emotion/react/jsx-runtime";
3415
+ import { jsx as jsx13 } from "@emotion/react/jsx-runtime";
3350
3416
  var ChatModeControl = ({
3351
3417
  value,
3352
3418
  disabled = false,
3353
3419
  labels,
3354
3420
  onChange
3355
3421
  }) => {
3356
- return /* @__PURE__ */ jsx14(
3422
+ return /* @__PURE__ */ jsx13(
3357
3423
  ModeSelect,
3358
3424
  {
3359
3425
  "data-testid": "chat-mode-select",
@@ -3368,7 +3434,7 @@ var ChatModeControl = ({
3368
3434
  }
3369
3435
  );
3370
3436
  };
3371
- var ModeSelect = styled13(Select2)`
3437
+ var ModeSelect = styled12(Select2)`
3372
3438
  && {
3373
3439
  flex: 0 1 auto;
3374
3440
  width: auto;
@@ -3389,10 +3455,10 @@ var ModeSelect = styled13(Select2)`
3389
3455
  `;
3390
3456
 
3391
3457
  // src/components/chat-composer/components/chat-send-actions.tsx
3392
- import styled14 from "@emotion/styled";
3458
+ import styled13 from "@emotion/styled";
3393
3459
  import { Button } from "@xinghunm/compass-ui";
3394
- import { Fragment as Fragment4, jsx as jsx15 } from "@emotion/react/jsx-runtime";
3395
- var ArrowUpIcon = () => /* @__PURE__ */ jsx15(
3460
+ import { Fragment as Fragment4, jsx as jsx14 } from "@emotion/react/jsx-runtime";
3461
+ var ArrowUpIcon = () => /* @__PURE__ */ jsx14(
3396
3462
  "svg",
3397
3463
  {
3398
3464
  "aria-hidden": "true",
@@ -3401,7 +3467,7 @@ var ArrowUpIcon = () => /* @__PURE__ */ jsx15(
3401
3467
  viewBox: "0 0 12 12",
3402
3468
  fill: "none",
3403
3469
  xmlns: "http://www.w3.org/2000/svg",
3404
- children: /* @__PURE__ */ jsx15(
3470
+ children: /* @__PURE__ */ jsx14(
3405
3471
  "path",
3406
3472
  {
3407
3473
  d: "M6 10V2M6 2L2 6M6 2L10 6",
@@ -3419,7 +3485,7 @@ var ChatSendActions = ({
3419
3485
  isStopping,
3420
3486
  onStop,
3421
3487
  onSend
3422
- }) => /* @__PURE__ */ jsx15(Fragment4, { children: isStreaming ? /* @__PURE__ */ jsx15(
3488
+ }) => /* @__PURE__ */ jsx14(Fragment4, { children: isStreaming ? /* @__PURE__ */ jsx14(
3423
3489
  StopButton,
3424
3490
  {
3425
3491
  type: "button",
@@ -3429,14 +3495,14 @@ var ChatSendActions = ({
3429
3495
  disabled: isStopping,
3430
3496
  shape: "circle",
3431
3497
  onClick: () => void onStop(),
3432
- 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" })
3433
3499
  }
3434
- ) : /* @__PURE__ */ jsx15(
3500
+ ) : /* @__PURE__ */ jsx14(
3435
3501
  PrimaryButton,
3436
3502
  {
3437
3503
  $canSend: canSend,
3438
3504
  type: "button",
3439
- icon: /* @__PURE__ */ jsx15(ArrowUpIcon, {}),
3505
+ icon: /* @__PURE__ */ jsx14(ArrowUpIcon, {}),
3440
3506
  "aria-label": "Send",
3441
3507
  "data-testid": "chat-composer-send",
3442
3508
  disabled: !canSend,
@@ -3444,7 +3510,7 @@ var ChatSendActions = ({
3444
3510
  onClick: () => void onSend()
3445
3511
  }
3446
3512
  ) });
3447
- var PrimaryButton = styled14(Button)`
3513
+ var PrimaryButton = styled13(Button)`
3448
3514
  && {
3449
3515
  min-width: 24px;
3450
3516
  width: 24px;
@@ -3470,7 +3536,7 @@ var PrimaryButton = styled14(Button)`
3470
3536
  }
3471
3537
  }
3472
3538
  `;
3473
- var StopButton = styled14(Button)`
3539
+ var StopButton = styled13(Button)`
3474
3540
  && {
3475
3541
  min-width: 24px;
3476
3542
  width: 24px;
@@ -3498,17 +3564,35 @@ var StopButton = styled14(Button)`
3498
3564
  }
3499
3565
  }
3500
3566
  `;
3501
- var StopGlyph = styled14.span`
3567
+ var StopGlyph = styled13.span`
3502
3568
  width: 8px;
3503
3569
  height: 8px;
3504
3570
  border-radius: 2px;
3505
3571
  background: #1b1b1b;
3506
3572
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
3507
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
+ `;
3508
3592
 
3509
3593
  // src/components/chat-composer/index.tsx
3510
- import { jsx as jsx16, jsxs as jsxs10 } from "@emotion/react/jsx-runtime";
3511
- var PlusIcon = () => /* @__PURE__ */ jsx16(
3594
+ import { jsx as jsx15, jsxs as jsxs10 } from "@emotion/react/jsx-runtime";
3595
+ var PlusIcon = () => /* @__PURE__ */ jsx15(
3512
3596
  "svg",
3513
3597
  {
3514
3598
  "aria-hidden": "true",
@@ -3517,7 +3601,7 @@ var PlusIcon = () => /* @__PURE__ */ jsx16(
3517
3601
  viewBox: "0 0 16 16",
3518
3602
  fill: "none",
3519
3603
  xmlns: "http://www.w3.org/2000/svg",
3520
- 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" })
3521
3605
  }
3522
3606
  );
3523
3607
  var ChatComposerView = ({
@@ -3577,8 +3661,8 @@ var ChatComposerView = ({
3577
3661
  event.preventDefault();
3578
3662
  onPasteImages(imageFiles);
3579
3663
  };
3580
- return /* @__PURE__ */ jsx16(Container2, { children: /* @__PURE__ */ jsxs10(Surface, { "data-testid": "chat-composer-surface", children: [
3581
- enableImageAttachments ? /* @__PURE__ */ jsx16(
3664
+ return /* @__PURE__ */ jsx15(Container2, { children: /* @__PURE__ */ jsxs10(Surface, { "data-testid": "chat-composer-surface", children: [
3665
+ enableImageAttachments ? /* @__PURE__ */ jsx15(
3582
3666
  "input",
3583
3667
  {
3584
3668
  ref: imageInputRef,
@@ -3590,15 +3674,15 @@ var ChatComposerView = ({
3590
3674
  onChange: handlePickImages
3591
3675
  }
3592
3676
  ) : null,
3593
- /* @__PURE__ */ jsx16(
3677
+ /* @__PURE__ */ jsx15(
3594
3678
  ChatComposerAttachmentList,
3595
3679
  {
3596
3680
  attachments,
3597
3681
  onRemoveAttachment
3598
3682
  }
3599
3683
  ),
3600
- attachmentNotice === "limit_reached" ? /* @__PURE__ */ jsx16(AttachmentNotice, { "data-testid": "chat-composer-attachment-notice", children: attachmentLimitNotice }) : null,
3601
- /* @__PURE__ */ jsx16(
3684
+ attachmentNotice === "limit_reached" ? /* @__PURE__ */ jsx15(AttachmentNotice, { "data-testid": "chat-composer-attachment-notice", children: attachmentLimitNotice }) : null,
3685
+ /* @__PURE__ */ jsx15(
3602
3686
  Input,
3603
3687
  {
3604
3688
  "data-testid": "chat-composer-input",
@@ -3609,18 +3693,18 @@ var ChatComposerView = ({
3609
3693
  placeholder
3610
3694
  }
3611
3695
  ),
3612
- /* @__PURE__ */ jsx16(Footer, { children: /* @__PURE__ */ jsxs10(Actions2, { "data-testid": "chat-composer-actions", children: [
3613
- enableImageAttachments ? /* @__PURE__ */ jsx16(
3696
+ /* @__PURE__ */ jsx15(Footer, { children: /* @__PURE__ */ jsxs10(Actions2, { "data-testid": "chat-composer-actions", children: [
3697
+ enableImageAttachments ? /* @__PURE__ */ jsx15(
3614
3698
  AttachButton,
3615
3699
  {
3616
3700
  type: "button",
3617
3701
  "data-testid": "chat-composer-attach-image",
3618
3702
  "aria-label": "Attach image",
3619
3703
  onClick: () => imageInputRef.current?.click(),
3620
- children: /* @__PURE__ */ jsx16(PlusIcon, {})
3704
+ children: /* @__PURE__ */ jsx15(PlusIcon, {})
3621
3705
  }
3622
3706
  ) : null,
3623
- /* @__PURE__ */ jsx16(
3707
+ /* @__PURE__ */ jsx15(
3624
3708
  ChatModeControl,
3625
3709
  {
3626
3710
  value: selectedMode,
@@ -3629,7 +3713,7 @@ var ChatComposerView = ({
3629
3713
  onChange: onSelectedModeChange
3630
3714
  }
3631
3715
  ),
3632
- /* @__PURE__ */ jsx16(
3716
+ /* @__PURE__ */ jsx15(
3633
3717
  ChatModelControl,
3634
3718
  {
3635
3719
  selectedModel,
@@ -3641,7 +3725,7 @@ var ChatComposerView = ({
3641
3725
  onReloadModels
3642
3726
  }
3643
3727
  ),
3644
- /* @__PURE__ */ jsx16(
3728
+ /* @__PURE__ */ jsx15(
3645
3729
  ChatSendActions,
3646
3730
  {
3647
3731
  canSend,
@@ -3669,7 +3753,7 @@ var ChatComposer = () => {
3669
3753
  plan: labels.modeLabelPlan,
3670
3754
  agent: labels.modeLabelAgent
3671
3755
  };
3672
- return /* @__PURE__ */ jsx16(
3756
+ return /* @__PURE__ */ jsx15(
3673
3757
  ChatComposerView,
3674
3758
  {
3675
3759
  value: state.value,
@@ -3699,10 +3783,10 @@ var ChatComposer = () => {
3699
3783
  }
3700
3784
  );
3701
3785
  };
3702
- var Container2 = styled15.div`
3786
+ var Container2 = styled14.div`
3703
3787
  padding: 0 16px 16px;
3704
3788
  `;
3705
- var Surface = styled15.div`
3789
+ var Surface = styled14.div`
3706
3790
  background: var(--border-color);
3707
3791
  border-radius: 20px;
3708
3792
  border: 1px solid var(--border-hover);
@@ -3711,7 +3795,7 @@ var Surface = styled15.div`
3711
3795
  0 12px 36px rgba(0, 0, 0, 0.3);
3712
3796
  backdrop-filter: blur(10px);
3713
3797
  `;
3714
- var AttachmentNotice = styled15.div`
3798
+ var AttachmentNotice = styled14.div`
3715
3799
  margin: 10px 12px 0;
3716
3800
  padding: 8px 10px;
3717
3801
  border-radius: 10px;
@@ -3721,7 +3805,7 @@ var AttachmentNotice = styled15.div`
3721
3805
  font-size: 12px;
3722
3806
  line-height: 1.4;
3723
3807
  `;
3724
- var Input = styled15.textarea`
3808
+ var Input = styled14.textarea`
3725
3809
  width: 100%;
3726
3810
  min-height: 96px;
3727
3811
  resize: none;
@@ -3743,14 +3827,14 @@ var Input = styled15.textarea`
3743
3827
  display: none;
3744
3828
  }
3745
3829
  `;
3746
- var Footer = styled15.div`
3830
+ var Footer = styled14.div`
3747
3831
  display: flex;
3748
3832
  align-items: flex-end;
3749
3833
  justify-content: stretch;
3750
3834
  gap: 16px;
3751
3835
  padding: 0 14px 14px;
3752
3836
  `;
3753
- var Actions2 = styled15.div`
3837
+ var Actions2 = styled14.div`
3754
3838
  display: flex;
3755
3839
  align-items: center;
3756
3840
  flex-wrap: wrap;
@@ -3759,7 +3843,7 @@ var Actions2 = styled15.div`
3759
3843
  justify-content: flex-end;
3760
3844
  gap: 8px;
3761
3845
  `;
3762
- var AttachButton = styled15.button`
3846
+ var AttachButton = styled14.button`
3763
3847
  width: 28px;
3764
3848
  height: 28px;
3765
3849
  display: grid;
@@ -3776,42 +3860,42 @@ var AttachButton = styled15.button`
3776
3860
  `;
3777
3861
 
3778
3862
  // src/components/chat-conversation-list/index.tsx
3779
- import styled17 from "@emotion/styled";
3863
+ import styled16 from "@emotion/styled";
3780
3864
 
3781
3865
  // src/components/chat-conversation-list/components/chat-session-item.tsx
3782
- import { memo as memo3 } from "react";
3783
- import styled16 from "@emotion/styled";
3784
- import { jsx as jsx17, jsxs as jsxs11 } from "@emotion/react/jsx-runtime";
3785
- 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(
3786
3870
  ({ session, isActive, modeLabel, onClick }) => {
3787
- return /* @__PURE__ */ jsx17(
3871
+ return /* @__PURE__ */ jsx16(
3788
3872
  SessionButton,
3789
3873
  {
3790
3874
  type: "button",
3791
3875
  "data-active": isActive,
3792
3876
  onClick: () => onClick(session.sessionId),
3793
3877
  children: /* @__PURE__ */ jsxs11(SessionMeta, { children: [
3794
- /* @__PURE__ */ jsx17(SessionTitle, { children: session.title }),
3795
- /* @__PURE__ */ jsx17(ModeBadge, { children: modeLabel })
3878
+ /* @__PURE__ */ jsx16(SessionTitle, { children: session.title }),
3879
+ /* @__PURE__ */ jsx16(ModeBadge, { children: modeLabel })
3796
3880
  ] })
3797
3881
  }
3798
3882
  );
3799
3883
  }
3800
3884
  );
3801
3885
  ChatSessionItem.displayName = "ChatSessionItem";
3802
- var SessionMeta = styled16.div`
3886
+ var SessionMeta = styled15.div`
3803
3887
  display: flex;
3804
3888
  align-items: center;
3805
3889
  justify-content: space-between;
3806
3890
  gap: 8px;
3807
3891
  `;
3808
- var SessionTitle = styled16.span`
3892
+ var SessionTitle = styled15.span`
3809
3893
  min-width: 0;
3810
3894
  overflow: hidden;
3811
3895
  text-overflow: ellipsis;
3812
3896
  white-space: nowrap;
3813
3897
  `;
3814
- var SessionButton = styled16.button`
3898
+ var SessionButton = styled15.button`
3815
3899
  border: 1px solid transparent;
3816
3900
  border-radius: 12px;
3817
3901
  padding: 12px;
@@ -3825,7 +3909,7 @@ var SessionButton = styled16.button`
3825
3909
  background: rgba(255, 255, 255, 0.08);
3826
3910
  }
3827
3911
  `;
3828
- var ModeBadge = styled16.span`
3912
+ var ModeBadge = styled15.span`
3829
3913
  flex-shrink: 0;
3830
3914
  border-radius: 999px;
3831
3915
  border: 1px solid rgba(255, 255, 255, 0.1);
@@ -3837,7 +3921,7 @@ var ModeBadge = styled16.span`
3837
3921
  `;
3838
3922
 
3839
3923
  // src/components/chat-conversation-list/index.tsx
3840
- 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";
3841
3925
  var ChatConversationList = () => {
3842
3926
  const { labels } = useChatContext();
3843
3927
  const sessions = useChatStore((s) => s.sessions);
@@ -3862,10 +3946,10 @@ var ChatConversationList = () => {
3862
3946
  };
3863
3947
  return /* @__PURE__ */ jsxs12(Container3, { children: [
3864
3948
  /* @__PURE__ */ jsxs12(Toolbar, { children: [
3865
- /* @__PURE__ */ jsx18(Title4, { children: "Sessions" }),
3866
- /* @__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 })
3867
3951
  ] }),
3868
- /* @__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(
3869
3953
  ChatSessionItem,
3870
3954
  {
3871
3955
  session,
@@ -3877,7 +3961,7 @@ var ChatConversationList = () => {
3877
3961
  )) })
3878
3962
  ] });
3879
3963
  };
3880
- var Container3 = styled17.aside`
3964
+ var Container3 = styled16.aside`
3881
3965
  width: 280px;
3882
3966
  min-width: 280px;
3883
3967
  border-right: 1px solid var(--border-default, rgba(255, 255, 255, 0.08));
@@ -3885,18 +3969,18 @@ var Container3 = styled17.aside`
3885
3969
  flex-direction: column;
3886
3970
  background: rgba(255, 255, 255, 0.02);
3887
3971
  `;
3888
- var Toolbar = styled17.div`
3972
+ var Toolbar = styled16.div`
3889
3973
  padding: 20px 16px 12px;
3890
3974
  display: flex;
3891
3975
  flex-direction: column;
3892
3976
  gap: 12px;
3893
3977
  `;
3894
- var Title4 = styled17.h2`
3978
+ var Title4 = styled16.h2`
3895
3979
  margin: 0;
3896
3980
  font-size: 14px;
3897
3981
  color: var(--text-secondary);
3898
3982
  `;
3899
- var CreateButton = styled17.button`
3983
+ var CreateButton = styled16.button`
3900
3984
  border: none;
3901
3985
  border-radius: 12px;
3902
3986
  padding: 12px 14px;
@@ -3905,7 +3989,7 @@ var CreateButton = styled17.button`
3905
3989
  text-align: left;
3906
3990
  cursor: pointer;
3907
3991
  `;
3908
- var List2 = styled17.div`
3992
+ var List2 = styled16.div`
3909
3993
  padding: 0 12px 16px;
3910
3994
  display: flex;
3911
3995
  flex-direction: column;
@@ -3914,8 +3998,8 @@ var List2 = styled17.div`
3914
3998
  `;
3915
3999
 
3916
4000
  // src/components/ai-chat/index.tsx
3917
- import { jsx as jsx19, jsxs as jsxs13 } from "@emotion/react/jsx-runtime";
3918
- 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(
3919
4003
  ConfigProvider,
3920
4004
  {
3921
4005
  theme: {
@@ -3950,23 +4034,23 @@ var AiChat = ({ showConversationList = false, ...providerProps }) => /* @__PURE_
3950
4034
  }
3951
4035
  }
3952
4036
  },
3953
- children: /* @__PURE__ */ jsx19(AiChatProvider, { ...providerProps, children: /* @__PURE__ */ jsxs13(Root, { "data-testid": "ai-chat", children: [
3954
- 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,
3955
4039
  /* @__PURE__ */ jsxs13(Workspace, { children: [
3956
- /* @__PURE__ */ jsx19(ChatThread, {}),
3957
- /* @__PURE__ */ jsx19(ChatComposer, {})
4040
+ /* @__PURE__ */ jsx18(ChatThread, {}),
4041
+ /* @__PURE__ */ jsx18(ChatComposer, {})
3958
4042
  ] })
3959
4043
  ] }) })
3960
4044
  }
3961
4045
  );
3962
- var Root = styled18.div`
4046
+ var Root = styled17.div`
3963
4047
  display: flex;
3964
4048
  width: 100%;
3965
4049
  height: 100%;
3966
4050
  min-height: 0;
3967
4051
  overflow: hidden;
3968
4052
  `;
3969
- var Workspace = styled18.section`
4053
+ var Workspace = styled17.section`
3970
4054
  flex: 1;
3971
4055
  display: flex;
3972
4056
  flex-direction: column;