@xinghunm/ai-chat 1.4.3 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/components/ai-chat/index.tsx
2
- import { useEffect as useEffect11 } from "react";
2
+ import { useEffect as useEffect12 } from "react";
3
3
  import styled17 from "@emotion/styled";
4
4
  import { ConfigProvider } from "@xinghunm/compass-ui";
5
5
 
@@ -49,6 +49,7 @@ var DEFAULT_AI_CHAT_LABELS = {
49
49
  questionnaireMultiSelectHint: "Multiple choice",
50
50
  questionnaireOtherOptionLabel: "Other",
51
51
  questionnaireOtherPlaceholder: "Other",
52
+ questionnaireExpired: "Selection expired.",
52
53
  modelLoading: "Loading models...",
53
54
  modelLoadFailed: "Failed to load models",
54
55
  modelUnavailable: "No model available",
@@ -57,7 +58,9 @@ var DEFAULT_AI_CHAT_LABELS = {
57
58
  removeSkillAriaLabel: "Remove skill",
58
59
  sessionHistoryLoading: "Loading conversations...",
59
60
  sessionHistoryLoadFailed: "Failed to load conversations",
60
- sessionHistoryEmpty: "No conversations yet"
61
+ sessionHistoryEmpty: "No conversations yet",
62
+ questionnaireTitle: "Plan Options",
63
+ questionnaireConfirmInTime: "Please confirm within {{seconds}} seconds"
61
64
  };
62
65
 
63
66
  // src/lib/chat-session.ts
@@ -97,6 +100,42 @@ var mergeOlderHistoryMessages = (sessionId, olderMessages, currentMessages) => {
97
100
  );
98
101
  return [...uniqueOlderMessages, ...currentMessages];
99
102
  };
103
+ var mergeLocalQuestionnaireState = (localMessages, incomingMessages) => {
104
+ if (!localMessages?.length)
105
+ return incomingMessages;
106
+ return incomingMessages.map((incomingMsg) => {
107
+ const localMsg = localMessages.find((lm) => lm.id === incomingMsg.id);
108
+ if (!localMsg)
109
+ return incomingMsg;
110
+ if (localMsg.blocks && !incomingMsg.blocks) {
111
+ return {
112
+ ...incomingMsg,
113
+ blocks: localMsg.blocks
114
+ };
115
+ }
116
+ if (localMsg.blocks && incomingMsg.blocks) {
117
+ const nextBlocks = incomingMsg.blocks.map((incomingBlock, index3) => {
118
+ const localBlock = localMsg.blocks?.[index3];
119
+ const isSameQuestionnaire = incomingBlock.type === "questionnaire" && localBlock?.type === "questionnaire" && (localBlock.questionnaire.questionnaireId === incomingBlock.questionnaire.questionnaireId || Boolean(localBlock.questionnaire.blockKey) && localBlock.questionnaire.blockKey === incomingBlock.questionnaire.blockKey);
120
+ if (isSameQuestionnaire) {
121
+ return {
122
+ ...incomingBlock,
123
+ questionnaire: {
124
+ ...incomingBlock.questionnaire,
125
+ questionnaireId: localBlock.questionnaire.questionnaireId ?? incomingBlock.questionnaire.questionnaireId,
126
+ answers: localBlock.questionnaire.answers ?? incomingBlock.questionnaire.answers,
127
+ status: localBlock.questionnaire.status ?? incomingBlock.questionnaire.status,
128
+ statusMessage: localBlock.questionnaire.statusMessage ?? incomingBlock.questionnaire.statusMessage
129
+ }
130
+ };
131
+ }
132
+ return incomingBlock;
133
+ });
134
+ return { ...incomingMsg, blocks: nextBlocks };
135
+ }
136
+ return incomingMsg;
137
+ });
138
+ };
100
139
  var resolveSessionTitleFromMessage = (message) => {
101
140
  const trimmedContent = message.content.trim();
102
141
  if (trimmedContent) {
@@ -215,6 +254,7 @@ var createChatStore = (initialState) => createStore((set, get) => ({
215
254
  sessionMessageLoadErrorBySession: {},
216
255
  historyMessagePaginationBySession: {},
217
256
  timelineAnchorStateBySession: {},
257
+ newlyCreatedSessionIds: [],
218
258
  // ---- Session management ------------------------------------------------
219
259
  createSession: (session) => {
220
260
  const state = get();
@@ -346,6 +386,7 @@ var createChatStore = (initialState) => createStore((set, get) => ({
346
386
  delete nextTimelineAnchorStateBySession[previousSessionId];
347
387
  }
348
388
  const nextActiveSessionId = state.activeSessionId === previousSessionId ? nextSessionId : state.activeSessionId;
389
+ const nextNewlyCreatedSessionIds = state.newlyCreatedSessionIds.includes(nextSessionId) ? state.newlyCreatedSessionIds : [...state.newlyCreatedSessionIds.filter((id) => id !== previousSessionId), nextSessionId];
349
390
  set({
350
391
  sessions: nextSessions,
351
392
  messagesBySession: nextMessagesBySession,
@@ -357,7 +398,8 @@ var createChatStore = (initialState) => createStore((set, get) => ({
357
398
  sessionMessageLoadErrorBySession: nextSessionMessageLoadErrorBySession,
358
399
  historyMessagePaginationBySession: nextHistoryMessagePaginationBySession,
359
400
  timelineAnchorStateBySession: nextTimelineAnchorStateBySession,
360
- activeSessionId: nextActiveSessionId
401
+ activeSessionId: nextActiveSessionId,
402
+ newlyCreatedSessionIds: nextNewlyCreatedSessionIds
361
403
  });
362
404
  },
363
405
  setPreferredMode: (mode) => {
@@ -374,15 +416,28 @@ var createChatStore = (initialState) => createStore((set, get) => ({
374
416
  const hasActiveInIncoming = sessions.some(
375
417
  (session) => session.sessionId === state.activeSessionId
376
418
  );
377
- const keepActiveSession = activePersistedSession && !hasActiveInIncoming ? [activePersistedSession] : [];
419
+ let prependActiveSession = [];
420
+ let appendActiveSession = [];
421
+ if (activePersistedSession && !hasActiveInIncoming) {
422
+ const isNewlyCreated = state.newlyCreatedSessionIds.includes(
423
+ activePersistedSession.sessionId
424
+ );
425
+ if (isNewlyCreated) {
426
+ prependActiveSession = [activePersistedSession];
427
+ } else {
428
+ appendActiveSession = [activePersistedSession];
429
+ }
430
+ }
378
431
  const excludeIds = /* @__PURE__ */ new Set([
379
432
  ...draftSessions.map((s) => s.sessionId),
380
- ...keepActiveSession.map((s) => s.sessionId)
433
+ ...prependActiveSession.map((s) => s.sessionId),
434
+ ...appendActiveSession.map((s) => s.sessionId)
381
435
  ]);
382
436
  const nextSessions = [
383
437
  ...draftSessions,
438
+ ...prependActiveSession,
384
439
  ...sessions.filter((session) => !excludeIds.has(session.sessionId)),
385
- ...keepActiveSession
440
+ ...appendActiveSession
386
441
  ];
387
442
  const nextMessagesBySession = { ...state.messagesBySession };
388
443
  const nextErrorBySession = { ...state.errorBySession };
@@ -418,6 +473,10 @@ var createChatStore = (initialState) => createStore((set, get) => ({
418
473
  nextHistoryMessagePaginationBySession[sid] = createHistoryMessagePaginationState();
419
474
  }
420
475
  });
476
+ const incomingSessionIds = new Set(sessions.map((s) => s.sessionId));
477
+ const nextNewlyCreatedSessionIds = state.newlyCreatedSessionIds.filter(
478
+ (id) => !incomingSessionIds.has(id)
479
+ );
421
480
  set({
422
481
  sessions: nextSessions,
423
482
  messagesBySession: nextMessagesBySession,
@@ -427,7 +486,8 @@ var createChatStore = (initialState) => createStore((set, get) => ({
427
486
  sessionMessageLoadStatusBySession: nextSessionMessageLoadStatusBySession,
428
487
  sessionMessageLoadErrorBySession: nextSessionMessageLoadErrorBySession,
429
488
  historyMessagePaginationBySession: nextHistoryMessagePaginationBySession,
430
- timelineAnchorStateBySession: nextTimelineAnchorStateBySession
489
+ timelineAnchorStateBySession: nextTimelineAnchorStateBySession,
490
+ newlyCreatedSessionIds: nextNewlyCreatedSessionIds
431
491
  });
432
492
  },
433
493
  // ---- Message operations ------------------------------------------------
@@ -458,10 +518,12 @@ var createChatStore = (initialState) => createStore((set, get) => ({
458
518
  },
459
519
  hydrateHistorySessionMessages: (sessionId, messages) => {
460
520
  const state = get();
521
+ const localMessages = state.messagesBySession[sessionId] ?? [];
522
+ const nextMessages = mergeLocalQuestionnaireState(localMessages, messages);
461
523
  set({
462
524
  messagesBySession: {
463
525
  ...state.messagesBySession,
464
- [sessionId]: normalizeHistoryMessages(sessionId, messages)
526
+ [sessionId]: normalizeHistoryMessages(sessionId, nextMessages)
465
527
  },
466
528
  sessionMessageLoadStatusBySession: {
467
529
  ...state.sessionMessageLoadStatusBySession,
@@ -479,10 +541,12 @@ var createChatStore = (initialState) => createStore((set, get) => ({
479
541
  },
480
542
  hydrateHistorySessionMessagesPage: (sessionId, page) => {
481
543
  const state = get();
544
+ const localMessages = state.messagesBySession[sessionId] ?? [];
545
+ const nextMessages = mergeLocalQuestionnaireState(localMessages, page.messages);
482
546
  set({
483
547
  messagesBySession: {
484
548
  ...state.messagesBySession,
485
- [sessionId]: normalizeHistoryMessages(sessionId, page.messages)
549
+ [sessionId]: normalizeHistoryMessages(sessionId, nextMessages)
486
550
  },
487
551
  sessionMessageLoadStatusBySession: {
488
552
  ...state.sessionMessageLoadStatusBySession,
@@ -641,7 +705,11 @@ var createChatStore = (initialState) => createStore((set, get) => ({
641
705
  hasUpdatedBlock = true;
642
706
  return {
643
707
  ...block,
644
- questionnaire: { ...block.questionnaire, answers: { ...answers } }
708
+ questionnaire: {
709
+ ...block.questionnaire,
710
+ answers: { ...answers },
711
+ status: "submitted"
712
+ }
645
713
  };
646
714
  });
647
715
  if (!hasUpdatedBlock)
@@ -1118,7 +1186,7 @@ var AiChatProvider = (props) => {
1118
1186
  };
1119
1187
 
1120
1188
  // src/components/chat-thread/index.tsx
1121
- import { useCallback as useCallback3, useLayoutEffect as useLayoutEffect3, useMemo as useMemo4, useRef as useRef5, useState as useState4 } from "react";
1189
+ import { useCallback as useCallback3, useLayoutEffect as useLayoutEffect3, useMemo as useMemo4, useRef as useRef5, useState as useState5 } from "react";
1122
1190
  import styled9 from "@emotion/styled";
1123
1191
 
1124
1192
  // src/context/use-chat-context.ts
@@ -1139,7 +1207,7 @@ var useChatStore = (selector) => {
1139
1207
  var CHAT_THREAD_SCROLL_TOP_GAP = 16;
1140
1208
 
1141
1209
  // src/components/chat-thread/components/chat-message-item.tsx
1142
- import { Fragment, memo, useCallback as useCallback2, useLayoutEffect as useLayoutEffect2, useState as useState3 } from "react";
1210
+ import { Fragment, memo, useCallback as useCallback2, useLayoutEffect as useLayoutEffect2, useState as useState4 } from "react";
1143
1211
  import styled7 from "@emotion/styled";
1144
1212
  import { keyframes } from "@emotion/react";
1145
1213
  import ReactMarkdown from "react-markdown";
@@ -1195,11 +1263,23 @@ var getNextDisplayedUnitCount = ({
1195
1263
  var splitMarkdownBlocks = (content) => content.split(/\n{2,}/).map((block) => block.trim()).filter(Boolean);
1196
1264
 
1197
1265
  // src/components/chat-thread/hooks/use-chat-message-reveal.ts
1266
+ var revealedStreamingMessages = /* @__PURE__ */ new Set();
1267
+ var markMessageAsRevealed = (id) => {
1268
+ if (revealedStreamingMessages.size > 500) {
1269
+ const firstKey = revealedStreamingMessages.keys().next().value;
1270
+ if (firstKey !== void 0) {
1271
+ revealedStreamingMessages.delete(firstKey);
1272
+ }
1273
+ }
1274
+ revealedStreamingMessages.add(id);
1275
+ };
1198
1276
  var createRevealState = ({
1199
1277
  isAssistantStreaming,
1200
- targetUnitCount
1278
+ targetUnitCount,
1279
+ messageId
1201
1280
  }) => {
1202
- const initialDisplayedUnitCount = isAssistantStreaming ? 0 : targetUnitCount;
1281
+ const hasBeenRevealed = revealedStreamingMessages.has(messageId);
1282
+ const initialDisplayedUnitCount = isAssistantStreaming && !hasBeenRevealed ? 0 : targetUnitCount;
1203
1283
  return {
1204
1284
  batchedTargetUnitCount: initialDisplayedUnitCount,
1205
1285
  displayedUnitCount: initialDisplayedUnitCount,
@@ -1209,7 +1289,11 @@ var createRevealState = ({
1209
1289
  var revealReducer = (state, action) => {
1210
1290
  switch (action.type) {
1211
1291
  case "reset-message":
1212
- return createRevealState(action);
1292
+ return createRevealState({
1293
+ isAssistantStreaming: action.isAssistantStreaming,
1294
+ targetUnitCount: action.targetUnitCount,
1295
+ messageId: action.messageId
1296
+ });
1213
1297
  case "commit-batched-target": {
1214
1298
  const nextDisplayedUnitCount = action.role === "assistant" ? getNextDisplayedUnitCount({
1215
1299
  currentUnits: state.displayedUnitCount,
@@ -1266,7 +1350,8 @@ var useChatMessageReveal = (message) => {
1266
1350
  revealReducer,
1267
1351
  {
1268
1352
  isAssistantStreaming,
1269
- targetUnitCount: targetUnits.length
1353
+ targetUnitCount: targetUnits.length,
1354
+ messageId: message.id
1270
1355
  },
1271
1356
  createRevealState
1272
1357
  );
@@ -1298,7 +1383,8 @@ var useChatMessageReveal = (message) => {
1298
1383
  dispatch({
1299
1384
  type: "reset-message",
1300
1385
  isAssistantStreaming,
1301
- targetUnitCount: targetUnits.length
1386
+ targetUnitCount: targetUnits.length,
1387
+ messageId: message.id
1302
1388
  });
1303
1389
  }, [isAssistantStreaming, message.id, targetUnits.length]);
1304
1390
  useEffect2(() => {
@@ -1377,6 +1463,11 @@ var useChatMessageReveal = (message) => {
1377
1463
  tone: "settled"
1378
1464
  }
1379
1465
  ];
1466
+ useEffect2(() => {
1467
+ if (isAssistantStreaming && displayedUnitCount > 0) {
1468
+ markMessageAsRevealed(message.id);
1469
+ }
1470
+ }, [isAssistantStreaming, displayedUnitCount, message.id]);
1380
1471
  return {
1381
1472
  isAssistantStreaming,
1382
1473
  isFreshBlockActive,
@@ -1968,12 +2059,99 @@ var Value = styled3.span`
1968
2059
 
1969
2060
  // src/components/chat-thread/components/questionnaire-card.tsx
1970
2061
  import {
1971
- useEffect as useEffect4,
2062
+ useEffect as useEffect5,
1972
2063
  useRef as useRef3,
1973
- useState as useState2
2064
+ useState as useState3
1974
2065
  } from "react";
1975
2066
  import styled4 from "@emotion/styled";
1976
2067
 
2068
+ // src/components/chat-thread/components/use-countdown-seconds.ts
2069
+ import { useEffect as useEffect4, useState as useState2 } from "react";
2070
+ var countdownDeadlineByKey = /* @__PURE__ */ new Map();
2071
+ var countdownCleanupTimerByKey = /* @__PURE__ */ new Map();
2072
+ var countdownMountCountByKey = /* @__PURE__ */ new Map();
2073
+ var clearCountdownEntry = (storageKey) => {
2074
+ const cleanupTimerId = countdownCleanupTimerByKey.get(storageKey);
2075
+ if (cleanupTimerId !== void 0) {
2076
+ window.clearTimeout(cleanupTimerId);
2077
+ countdownCleanupTimerByKey.delete(storageKey);
2078
+ }
2079
+ countdownDeadlineByKey.delete(storageKey);
2080
+ };
2081
+ var scheduleCountdownCleanup = (storageKey, deadline) => {
2082
+ const existingCleanupTimerId = countdownCleanupTimerByKey.get(storageKey);
2083
+ if (existingCleanupTimerId !== void 0) {
2084
+ return;
2085
+ }
2086
+ const delayMs = Math.max(0, deadline - Date.now());
2087
+ const cleanupTimerId = window.setTimeout(() => {
2088
+ if ((countdownMountCountByKey.get(storageKey) ?? 0) > 0) {
2089
+ countdownCleanupTimerByKey.delete(storageKey);
2090
+ return;
2091
+ }
2092
+ clearCountdownEntry(storageKey);
2093
+ }, delayMs);
2094
+ countdownCleanupTimerByKey.set(storageKey, cleanupTimerId);
2095
+ };
2096
+ var getCountdownDeadline = (storageKey, initialSeconds) => {
2097
+ const existingDeadline = countdownDeadlineByKey.get(storageKey);
2098
+ if (existingDeadline !== void 0) {
2099
+ return existingDeadline;
2100
+ }
2101
+ const nextDeadline = Date.now() + Math.max(0, initialSeconds) * 1e3;
2102
+ countdownDeadlineByKey.set(storageKey, nextDeadline);
2103
+ scheduleCountdownCleanup(storageKey, nextDeadline);
2104
+ return nextDeadline;
2105
+ };
2106
+ var getRemainingSeconds = (deadline) => Math.max(0, Math.ceil((deadline - Date.now()) / 1e3));
2107
+ var useCountdownSeconds = ({
2108
+ storageKey,
2109
+ initialSeconds,
2110
+ active
2111
+ }) => {
2112
+ const [remainingSeconds, setRemainingSeconds] = useState2(
2113
+ () => getRemainingSeconds(getCountdownDeadline(storageKey, initialSeconds))
2114
+ );
2115
+ useEffect4(() => {
2116
+ countdownMountCountByKey.set(storageKey, (countdownMountCountByKey.get(storageKey) ?? 0) + 1);
2117
+ return () => {
2118
+ const nextCount = (countdownMountCountByKey.get(storageKey) ?? 1) - 1;
2119
+ if (nextCount <= 0) {
2120
+ countdownMountCountByKey.delete(storageKey);
2121
+ return;
2122
+ }
2123
+ countdownMountCountByKey.set(storageKey, nextCount);
2124
+ };
2125
+ }, [storageKey]);
2126
+ useEffect4(() => {
2127
+ setRemainingSeconds(getRemainingSeconds(getCountdownDeadline(storageKey, initialSeconds)));
2128
+ }, [initialSeconds, storageKey]);
2129
+ useEffect4(() => {
2130
+ if (active) {
2131
+ return;
2132
+ }
2133
+ clearCountdownEntry(storageKey);
2134
+ }, [active, storageKey]);
2135
+ useEffect4(() => {
2136
+ if (remainingSeconds > 0) {
2137
+ return;
2138
+ }
2139
+ clearCountdownEntry(storageKey);
2140
+ }, [remainingSeconds, storageKey]);
2141
+ useEffect4(() => {
2142
+ if (!active || remainingSeconds <= 0) {
2143
+ return;
2144
+ }
2145
+ const timeoutId = window.setTimeout(() => {
2146
+ setRemainingSeconds(getRemainingSeconds(getCountdownDeadline(storageKey, initialSeconds)));
2147
+ }, 1e3);
2148
+ return () => {
2149
+ window.clearTimeout(timeoutId);
2150
+ };
2151
+ }, [active, initialSeconds, remainingSeconds, storageKey]);
2152
+ return remainingSeconds;
2153
+ };
2154
+
1977
2155
  // src/components/chat-thread/components/questionnaire-card-helpers.ts
1978
2156
  var OTHER_OPTION_VALUE = "__other__";
1979
2157
  var getQuestionnaireQuestion = (questionnaire) => questionnaire.question;
@@ -2280,7 +2458,10 @@ var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
2280
2458
  submitFailed: "Failed to submit. Please try again.",
2281
2459
  multiSelectHint: "Multiple choice",
2282
2460
  otherOptionLabel: "Other",
2283
- otherPlaceholder: "Other"
2461
+ otherPlaceholder: "Other",
2462
+ expired: "Selection expired.",
2463
+ questionnaireTitle: "Plan Options",
2464
+ questionnaireConfirmInTime: "Please confirm within {{seconds}} seconds"
2284
2465
  };
2285
2466
  var stopInputClickPropagation = (event) => {
2286
2467
  event.stopPropagation();
@@ -2342,30 +2523,39 @@ var QuestionnaireCardInner = ({
2342
2523
  }) => {
2343
2524
  const questionnaireRef = useRef3(questionnaire);
2344
2525
  const otherInputRefs = useRef3({});
2345
- const [answers, setAnswers] = useState2(
2526
+ const [answers, setAnswers] = useState3(
2346
2527
  () => createInitialAnswers(questionnaire)
2347
2528
  );
2348
- const [otherDrafts, setOtherDrafts] = useState2(
2529
+ const [otherDrafts, setOtherDrafts] = useState3(
2349
2530
  () => createInitialOtherDrafts(questionnaire)
2350
2531
  );
2351
- const [errorMessage, setErrorMessage] = useState2(null);
2352
- const [isSubmitting, setIsSubmitting] = useState2(false);
2353
- const [isSubmitted, setIsSubmitted] = useState2(false);
2354
- const [pendingFocusQuestionId, setPendingFocusQuestionId] = useState2(null);
2532
+ const [errorMessage, setErrorMessage] = useState3(null);
2533
+ const [isSubmitting, setIsSubmitting] = useState3(false);
2534
+ const [isSubmitted, setIsSubmitted] = useState3(() => questionnaire.status === "submitted");
2535
+ const [pendingFocusQuestionId, setPendingFocusQuestionId] = useState3(null);
2355
2536
  const resolvedLabels = {
2356
2537
  ...DEFAULT_QUESTIONNAIRE_CARD_LABELS,
2357
2538
  ...labels
2358
2539
  };
2359
- const hasExternalFailureStatus = questionnaire.status === "expired" || questionnaire.status === "failed";
2540
+ const remainingSeconds = useCountdownSeconds({
2541
+ storageKey: questionnaire.blockKey ?? `questionnaire:${questionnaire.questionnaireId}`,
2542
+ initialSeconds: questionnaire.timeoutSec ?? 0,
2543
+ active: questionnaire.timeoutSec !== void 0 && questionnaire.timeoutSec > 0 && !isSubmitted && questionnaire.status !== "expired" && questionnaire.status !== "failed" && interactive
2544
+ });
2545
+ const isExpired = questionnaire.status === "expired" || questionnaire.timeoutSec !== void 0 && questionnaire.timeoutSec > 0 && remainingSeconds <= 0;
2546
+ const hasExternalFailureStatus = isExpired || questionnaire.status === "failed";
2360
2547
  const question = getQuestionnaireQuestion(questionnaire);
2361
- const visibleErrorMessage = questionnaire.statusMessage ?? errorMessage;
2362
- const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus;
2548
+ const visibleErrorMessage = questionnaire.statusMessage ?? (isExpired ? null : errorMessage);
2549
+ const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus || questionnaire.status === "submitted";
2363
2550
  questionnaireRef.current = questionnaire;
2364
- useEffect4(() => {
2551
+ useEffect5(() => {
2365
2552
  setAnswers(createInitialAnswers(questionnaireRef.current));
2366
2553
  setOtherDrafts(createInitialOtherDrafts(questionnaireRef.current));
2367
- }, [questionnaire.answers]);
2368
- useEffect4(() => {
2554
+ if (questionnaireRef.current.status === "submitted") {
2555
+ setIsSubmitted(true);
2556
+ }
2557
+ }, [questionnaire.answers, questionnaire.status]);
2558
+ useEffect5(() => {
2369
2559
  if (!pendingFocusQuestionId || isInteractionLocked) {
2370
2560
  return;
2371
2561
  }
@@ -2615,42 +2805,69 @@ var QuestionnaireCardInner = ({
2615
2805
  }
2616
2806
  };
2617
2807
  return /* @__PURE__ */ jsxs3(Card4, { "data-testid": "questionnaire-card", children: [
2618
- questionnaire.description ? /* @__PURE__ */ jsx5(Description, { children: questionnaire.description }) : null,
2619
- /* @__PURE__ */ jsx5(QuestionList, { children: /* @__PURE__ */ jsxs3(QuestionCard, { children: [
2620
- /* @__PURE__ */ jsxs3(QuestionLabel, { children: [
2621
- question.label,
2622
- question.required ? /* @__PURE__ */ jsx5(Required, { children: "*" }) : null
2623
- ] }),
2624
- question.kind === "multi_select" ? /* @__PURE__ */ jsx5(QuestionHint, { children: resolvedLabels.multiSelectHint }) : null,
2625
- renderQuestion(question)
2626
- ] }, question.id) }),
2627
- visibleErrorMessage ? /* @__PURE__ */ jsx5(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
2628
- isSubmitted ? /* @__PURE__ */ jsx5(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : interactive && !hasExternalFailureStatus ? /* @__PURE__ */ jsx5(
2629
- SubmitButton,
2630
- {
2631
- type: "button",
2632
- "data-testid": "questionnaire-submit",
2633
- disabled: isInteractionLocked,
2634
- onClick: () => {
2635
- void handleSubmit();
2636
- },
2637
- children: isSubmitting ? resolvedLabels.submitting : questionnaire.submitLabel ?? "Submit"
2638
- }
2639
- ) : null
2808
+ /* @__PURE__ */ jsx5(Header2, { children: /* @__PURE__ */ jsx5(Eyebrow2, { children: resolvedLabels.questionnaireTitle }) }),
2809
+ /* @__PURE__ */ jsxs3(Content, { children: [
2810
+ questionnaire.description ? /* @__PURE__ */ jsx5(Description, { children: questionnaire.description }) : null,
2811
+ /* @__PURE__ */ jsx5(QuestionList, { children: /* @__PURE__ */ jsxs3(QuestionCard, { children: [
2812
+ /* @__PURE__ */ jsxs3(QuestionLabel, { children: [
2813
+ question.label,
2814
+ question.required ? /* @__PURE__ */ jsx5(Required, { children: "*" }) : null
2815
+ ] }),
2816
+ question.kind === "multi_select" ? /* @__PURE__ */ jsx5(QuestionHint, { children: resolvedLabels.multiSelectHint }) : null,
2817
+ renderQuestion(question)
2818
+ ] }, question.id) }),
2819
+ visibleErrorMessage ? /* @__PURE__ */ jsx5(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
2820
+ /* @__PURE__ */ jsx5(Footer, { children: isSubmitted ? /* @__PURE__ */ jsx5(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : isExpired ? /* @__PURE__ */ jsx5(ExpiredTag, { "data-testid": "questionnaire-expired", children: resolvedLabels.expired }) : interactive ? /* @__PURE__ */ jsxs3(FooterActionRow, { "data-testid": "questionnaire-card-actions", children: [
2821
+ remainingSeconds > 0 && /* @__PURE__ */ jsx5(MetaText, { "data-testid": "questionnaire-countdown", children: resolvedLabels.questionnaireConfirmInTime?.replace(
2822
+ "{{seconds}}",
2823
+ String(remainingSeconds)
2824
+ ) ?? `\u8BF7\u5728 ${remainingSeconds} \u79D2\u5185\u786E\u8BA4` }),
2825
+ /* @__PURE__ */ jsx5(
2826
+ SubmitButton,
2827
+ {
2828
+ type: "button",
2829
+ "data-testid": "questionnaire-submit",
2830
+ disabled: isInteractionLocked,
2831
+ onClick: () => {
2832
+ void handleSubmit();
2833
+ },
2834
+ children: isSubmitting ? resolvedLabels.submitting : questionnaire.submitLabel ?? "Submit"
2835
+ }
2836
+ )
2837
+ ] }) : null })
2838
+ ] })
2640
2839
  ] });
2641
2840
  };
2642
2841
  var QuestionnaireCard = (props) => /* @__PURE__ */ jsx5(QuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
2643
2842
  var Card4 = styled4.section`
2644
- display: grid;
2645
- gap: 14px;
2646
- padding: 16px;
2647
- border-radius: 20px;
2648
- border: 1px solid rgba(255, 255, 255, 0.08);
2649
- background: rgba(255, 255, 255, 0.03);
2843
+ overflow: hidden;
2844
+ background: var(--bg-primary);
2845
+ border-radius: 16px;
2846
+ border: 1px solid var(--border-hover);
2847
+ `;
2848
+ var Header2 = styled4.div`
2849
+ display: flex;
2850
+ flex-wrap: wrap;
2851
+ align-items: center;
2852
+ gap: 10px;
2853
+ padding: 22px 12px 16px;
2854
+ border-bottom: 1px solid var(--border-hover);
2855
+ `;
2856
+ var Eyebrow2 = styled4.div`
2857
+ font-weight: 500;
2858
+ font-size: 16px;
2859
+ color: var(--text-primary);
2860
+ line-height: 22px;
2861
+ `;
2862
+ var Content = styled4.div`
2863
+ display: flex;
2864
+ flex-direction: column;
2865
+ gap: 16px;
2866
+ padding: 16px 12px;
2650
2867
  `;
2651
2868
  var Description = styled4.p`
2652
2869
  margin: 0;
2653
- color: rgba(255, 255, 255, 0.72);
2870
+ color: var(--text-secondary);
2654
2871
  font-size: 13px;
2655
2872
  `;
2656
2873
  var QuestionList = styled4.div`
@@ -2661,11 +2878,11 @@ var QuestionCard = styled4.div`
2661
2878
  display: grid;
2662
2879
  gap: 10px;
2663
2880
  padding: 12px;
2664
- border-radius: 16px;
2665
- background: rgba(255, 255, 255, 0.04);
2881
+ border-radius: 8px;
2882
+ background: rgba(255, 255, 255, 0.02);
2666
2883
  `;
2667
2884
  var QuestionLabel = styled4.div`
2668
- color: rgba(255, 255, 255, 0.9);
2885
+ color: var(--text-primary);
2669
2886
  font-size: 14px;
2670
2887
  font-weight: 600;
2671
2888
  `;
@@ -2692,11 +2909,11 @@ var OptionChoiceItem = styled4.div`
2692
2909
  gap: 12px;
2693
2910
  width: 100%;
2694
2911
  text-align: left;
2695
- border: 1px solid rgba(255, 255, 255, 0.1);
2696
- border-radius: 14px;
2697
- background: rgba(255, 255, 255, 0.03);
2912
+ border: 1px solid var(--border-hover);
2913
+ border-radius: 8px;
2914
+ background: rgba(255, 255, 255, 0.02);
2698
2915
  padding: 2px 12px;
2699
- color: rgba(255, 255, 255, 0.9);
2916
+ color: var(--text-primary);
2700
2917
  cursor: pointer;
2701
2918
  transition:
2702
2919
  border-color 140ms ease,
@@ -2705,8 +2922,8 @@ var OptionChoiceItem = styled4.div`
2705
2922
  outline: none;
2706
2923
 
2707
2924
  &[data-selected='true'] {
2708
- border-color: rgba(126, 160, 255, 0.42);
2709
- background: linear-gradient(180deg, rgba(82, 114, 255, 0.18) 0%, rgba(82, 114, 255, 0.1) 100%);
2925
+ border-color: rgba(51, 133, 255, 0.42);
2926
+ background: linear-gradient(180deg, rgba(51, 133, 255, 0.18) 0%, rgba(51, 133, 255, 0.1) 100%);
2710
2927
  transform: translateY(-1px);
2711
2928
  }
2712
2929
 
@@ -2715,8 +2932,8 @@ var OptionChoiceItem = styled4.div`
2715
2932
  }
2716
2933
 
2717
2934
  &:focus-visible {
2718
- border-color: rgba(126, 160, 255, 0.52);
2719
- box-shadow: 0 0 0 1px rgba(126, 160, 255, 0.18);
2935
+ border-color: rgba(51, 133, 255, 0.52);
2936
+ box-shadow: 0 0 0 1px rgba(51, 133, 255, 0.18);
2720
2937
  }
2721
2938
 
2722
2939
  &[tabindex='-1'] {
@@ -2733,16 +2950,16 @@ var OptionChoiceMarker = styled4.span`
2733
2950
  width: 28px;
2734
2951
  height: 28px;
2735
2952
  border-radius: 8px;
2736
- border: 1px solid rgba(255, 255, 255, 0.14);
2737
- background: rgba(255, 255, 255, 0.04);
2738
- color: rgba(255, 255, 255, 0.65);
2953
+ border: 1px solid var(--border-hover);
2954
+ background: rgba(255, 255, 255, 0.02);
2955
+ color: var(--text-secondary);
2739
2956
  font-size: 12px;
2740
2957
  font-weight: 700;
2741
2958
 
2742
2959
  &[data-selected='true'] {
2743
- border-color: rgba(126, 160, 255, 0.38);
2744
- background: rgba(126, 160, 255, 0.2);
2745
- color: rgba(255, 255, 255, 0.96);
2960
+ border-color: rgba(51, 133, 255, 0.38);
2961
+ background: rgba(51, 133, 255, 0.2);
2962
+ color: var(--text-primary);
2746
2963
  }
2747
2964
  `;
2748
2965
  var OptionChoiceContent = styled4.span`
@@ -2762,47 +2979,41 @@ var OptionChoiceLabel = styled4.span`
2762
2979
  `;
2763
2980
  var TextInput = styled4.input`
2764
2981
  width: 100%;
2765
- border: 1px solid rgba(255, 255, 255, 0.1);
2766
- border-radius: 12px;
2982
+ border: 1px solid var(--border-hover);
2983
+ border-radius: 8px;
2767
2984
  background: rgba(13, 15, 21, 0.55);
2768
- color: rgba(255, 255, 255, 0.92);
2985
+ color: var(--text-primary);
2769
2986
  font-size: 13px;
2770
2987
  padding: 10px 12px;
2771
2988
 
2772
2989
  &::placeholder {
2773
- color: rgba(255, 255, 255, 0.34);
2990
+ color: var(--text-secondary);
2991
+ opacity: 0.5;
2774
2992
  }
2775
2993
  `;
2776
2994
  var InlineOtherInput = styled4.input`
2777
2995
  width: 100%;
2778
- margin-top: 0;
2779
-
2780
- .compass-input-wrapper {
2781
- min-height: 30px;
2782
- border: 1px solid rgba(255, 255, 255, 0.1);
2783
- border-radius: 10px;
2784
- background: rgba(13, 15, 21, 0.55);
2785
- box-shadow: none;
2786
- padding: 2px 9px;
2787
- }
2788
-
2789
- .compass-input-wrapper:hover {
2790
- border-color: rgba(126, 160, 255, 0.28);
2791
- }
2996
+ border: 1px solid var(--border-hover);
2997
+ border-radius: 6px;
2998
+ background: rgba(13, 15, 21, 0.45);
2999
+ color: var(--text-primary);
3000
+ font-size: 13px;
3001
+ padding: 6px 10px;
3002
+ outline: none;
3003
+ transition: border-color 140ms ease;
2792
3004
 
2793
- .compass-input-wrapper:focus-within {
2794
- border-color: rgba(126, 160, 255, 0.42);
2795
- box-shadow: 0 0 0 1px rgba(126, 160, 255, 0.14);
3005
+ &:hover {
3006
+ border-color: rgba(51, 133, 255, 0.28);
2796
3007
  }
2797
3008
 
2798
- .compass-input-input {
2799
- color: rgba(255, 255, 255, 0.92);
2800
- font-size: 13px;
2801
- line-height: 1.2;
3009
+ &:focus {
3010
+ border-color: rgba(51, 133, 255, 0.42);
3011
+ box-shadow: 0 0 0 1px rgba(51, 133, 255, 0.14);
2802
3012
  }
2803
3013
 
2804
- .compass-input-input::placeholder {
2805
- color: rgba(255, 255, 255, 0.34);
3014
+ &::placeholder {
3015
+ color: var(--text-secondary);
3016
+ opacity: 0.5;
2806
3017
  }
2807
3018
  `;
2808
3019
  var NumberInputRow = styled4.div`
@@ -2811,32 +3022,80 @@ var NumberInputRow = styled4.div`
2811
3022
  gap: 10px;
2812
3023
  `;
2813
3024
  var Unit = styled4.span`
2814
- color: rgba(255, 255, 255, 0.58);
3025
+ color: var(--text-secondary);
2815
3026
  font-size: 12px;
2816
3027
  white-space: nowrap;
2817
3028
  `;
2818
3029
  var ErrorMessage = styled4.div`
2819
- color: rgba(255, 145, 145, 0.96);
3030
+ font-size: 13px;
3031
+ line-height: 1.5;
3032
+ color: rgba(255, 207, 207, 0.92);
3033
+ `;
3034
+ var Footer = styled4.div`
3035
+ display: flex;
3036
+ flex-wrap: wrap;
3037
+ align-items: center;
3038
+ justify-content: flex-start;
3039
+ gap: 12px;
3040
+ `;
3041
+ var FooterActionRow = styled4.div`
3042
+ display: flex;
3043
+ align-items: center;
3044
+ flex-wrap: wrap;
3045
+ gap: 8px;
3046
+ margin-left: auto;
3047
+ justify-content: flex-end;
3048
+ `;
3049
+ var MetaText = styled4.span`
3050
+ font-weight: 500;
2820
3051
  font-size: 12px;
3052
+ color: var(--text-secondary);
3053
+ line-height: 17px;
3054
+ `;
3055
+ var ExpiredTag = styled4.span`
3056
+ display: inline-flex;
3057
+ align-items: center;
3058
+ padding: 8px 12px;
3059
+ border-radius: 8px;
3060
+ font-size: 13px;
3061
+ font-weight: 600;
3062
+ background: rgba(255, 255, 255, 0.05);
3063
+ border: 1px solid rgba(255, 255, 255, 0.12);
3064
+ color: rgba(214, 224, 236, 0.9);
2821
3065
  `;
2822
3066
  var SuccessMessage = styled4.div`
2823
- color: rgba(164, 255, 210, 0.96);
2824
- font-size: 12px;
3067
+ display: inline-flex;
3068
+ align-items: center;
3069
+ padding: 8px 12px;
3070
+ border-radius: 8px;
3071
+ font-size: 13px;
3072
+ font-weight: 600;
3073
+ background: rgba(190, 246, 202, 0.14);
3074
+ border: 1px solid rgba(190, 246, 202, 0.24);
3075
+ color: rgba(227, 255, 233, 0.94);
2825
3076
  `;
2826
3077
  var SubmitButton = styled4.button`
2827
- justify-self: flex-start;
2828
- border: none;
2829
- border-radius: 999px;
2830
- background: linear-gradient(180deg, #7ea0ff 0%, #4a6fff 100%);
2831
- color: #081127;
2832
- font-size: 12px;
2833
- font-weight: 700;
2834
- padding: 10px 14px;
3078
+ padding: 9px 16px;
3079
+ border-radius: 8px;
3080
+ border: 1px solid transparent;
3081
+ font-weight: 500;
3082
+ font-size: 14px;
3083
+ color: rgba(255, 255, 255, 0.96);
3084
+ background: linear-gradient(180deg, #3385ff 0%, #1f6ef2 100%);
3085
+ line-height: 14px;
2835
3086
  cursor: pointer;
3087
+ transition:
3088
+ transform 160ms ease,
3089
+ opacity 160ms ease;
2836
3090
 
2837
3091
  &:disabled {
2838
- cursor: default;
2839
- opacity: 0.72;
3092
+ cursor: progress;
3093
+ opacity: 0.68;
3094
+ transform: none;
3095
+ }
3096
+
3097
+ &:not(:disabled):hover {
3098
+ transform: translateY(-1px);
2840
3099
  }
2841
3100
  `;
2842
3101
 
@@ -2844,7 +3103,7 @@ var SubmitButton = styled4.button`
2844
3103
  import styled5 from "@emotion/styled";
2845
3104
  import { jsx as jsx6, jsxs as jsxs4 } from "@emotion/react/jsx-runtime";
2846
3105
  var ResultSummaryCard = ({ summary }) => /* @__PURE__ */ jsxs4(Card5, { "data-testid": "result-summary-card", "data-status": summary.status, children: [
2847
- /* @__PURE__ */ jsx6(Eyebrow2, { children: summary.status }),
3106
+ /* @__PURE__ */ jsx6(Eyebrow3, { children: summary.status }),
2848
3107
  /* @__PURE__ */ jsx6(Headline, { children: summary.headline }),
2849
3108
  /* @__PURE__ */ jsx6(Details, { children: summary.details.map((detail) => /* @__PURE__ */ jsx6(Detail, { children: detail }, detail)) })
2850
3109
  ] });
@@ -2864,7 +3123,7 @@ var Card5 = styled5.section`
2864
3123
  border-color: rgba(255, 122, 122, 0.24);
2865
3124
  }
2866
3125
  `;
2867
- var Eyebrow2 = styled5.span`
3126
+ var Eyebrow3 = styled5.span`
2868
3127
  color: rgba(255, 255, 255, 0.58);
2869
3128
  font-size: 11px;
2870
3129
  font-weight: 700;
@@ -2889,7 +3148,7 @@ var Detail = styled5.li`
2889
3148
 
2890
3149
  // src/components/chat-thread/components/image-viewer.tsx
2891
3150
  import styled6 from "@emotion/styled";
2892
- import { useEffect as useEffect5, useRef as useRef4 } from "react";
3151
+ import { useEffect as useEffect6, useRef as useRef4 } from "react";
2893
3152
  import { jsx as jsx7 } from "@emotion/react/jsx-runtime";
2894
3153
  var Overlay = styled6.div`
2895
3154
  position: fixed;
@@ -2909,7 +3168,7 @@ var Img = styled6.img`
2909
3168
  `;
2910
3169
  var ImageViewer = ({ src, alt, onClose }) => {
2911
3170
  const overlayRef = useRef4(null);
2912
- useEffect5(() => {
3171
+ useEffect6(() => {
2913
3172
  const handleKey = (e) => {
2914
3173
  if (e.key === "Escape")
2915
3174
  onClose();
@@ -2917,7 +3176,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
2917
3176
  document.addEventListener("keydown", handleKey);
2918
3177
  return () => document.removeEventListener("keydown", handleKey);
2919
3178
  }, [onClose]);
2920
- useEffect5(() => {
3179
+ useEffect6(() => {
2921
3180
  overlayRef.current?.focus();
2922
3181
  }, []);
2923
3182
  const stopPropagation = (e) => e.stopPropagation();
@@ -2983,9 +3242,9 @@ var useUserMessageCollapse = ({
2983
3242
  freshContent,
2984
3243
  settledContent
2985
3244
  }) => {
2986
- const [isCollapsible, setIsCollapsible] = useState3(false);
2987
- const [isExpanded, setIsExpanded] = useState3(false);
2988
- const [bodyStackElement, setBodyStackElement] = useState3(null);
3245
+ const [isCollapsible, setIsCollapsible] = useState4(false);
3246
+ const [isExpanded, setIsExpanded] = useState4(false);
3247
+ const [bodyStackElement, setBodyStackElement] = useState4(null);
2989
3248
  const syncCollapseState = useCallback2(
2990
3249
  (element) => {
2991
3250
  const nextCollapsible = enabled && (element?.scrollHeight ?? 0) > USER_MESSAGE_COLLAPSE_HEIGHT_PX;
@@ -3171,7 +3430,7 @@ var ChatMessageItemView = ({
3171
3430
  renderMessageBlock
3172
3431
  }) => {
3173
3432
  const { labels, messageRenderOrder = "blocks-first" } = useChatContext();
3174
- const [activeImage, setActiveImage] = useState3(void 0);
3433
+ const [activeImage, setActiveImage] = useState4(void 0);
3175
3434
  const {
3176
3435
  displayedBlocks,
3177
3436
  displayedContent,
@@ -3188,8 +3447,9 @@ var ChatMessageItemView = ({
3188
3447
  const hasMarkdownOnlyBlocks = hasStructuredBlocks && blocks.every((block) => block.type === "markdown");
3189
3448
  const hasTextContent = Boolean(settledContent || freshContent || displayedContent);
3190
3449
  const shouldRenderStructuredBlocks = hasStructuredBlocks && !(isAssistantStreaming && hasMarkdownOnlyBlocks && hasTextContent);
3191
- const canSubmitConfirmation = typeof onConfirmationSubmit === "function";
3192
- const canSubmitQuestionnaire = typeof onQuestionnaireSubmit === "function";
3450
+ const isInteractionDisabled = message.status === "stopped" || message.status === "error";
3451
+ const canSubmitConfirmation = typeof onConfirmationSubmit === "function" && !isInteractionDisabled;
3452
+ const canSubmitQuestionnaire = typeof onQuestionnaireSubmit === "function" && !isInteractionDisabled;
3193
3453
  const shouldShowStreamingCaret = isAssistantStreaming && (!shouldRenderStructuredBlocks || hasTextContent);
3194
3454
  const isUserMessage = message.role === "user";
3195
3455
  const messageRenderMode = isUserMessage ? "plain-text" : "markdown";
@@ -3270,7 +3530,10 @@ var ChatMessageItemView = ({
3270
3530
  submitFailed: labels.questionnaireSubmitFailed,
3271
3531
  multiSelectHint: labels.questionnaireMultiSelectHint,
3272
3532
  otherOptionLabel: labels.questionnaireOtherOptionLabel,
3273
- otherPlaceholder: labels.questionnaireOtherPlaceholder
3533
+ otherPlaceholder: labels.questionnaireOtherPlaceholder,
3534
+ expired: labels.questionnaireExpired,
3535
+ questionnaireTitle: labels.questionnaireTitle,
3536
+ questionnaireConfirmInTime: labels.questionnaireConfirmInTime
3274
3537
  },
3275
3538
  onSubmit: canSubmitQuestionnaire ? (submission) => onQuestionnaireSubmit({
3276
3539
  ...submission,
@@ -3373,7 +3636,7 @@ var ChatMessageItemView = ({
3373
3636
  })();
3374
3637
  return /* @__PURE__ */ jsxs5(Fragment2, { children: [
3375
3638
  /* @__PURE__ */ jsxs5(Bubble, { "data-role": message.role, "data-status": message.status ?? "done", children: [
3376
- shouldRenderHeader ? /* @__PURE__ */ jsxs5(Header2, { children: [
3639
+ shouldRenderHeader ? /* @__PURE__ */ jsxs5(Header3, { children: [
3377
3640
  isAssistantStreaming ? /* @__PURE__ */ jsxs5(
3378
3641
  StreamingIndicator,
3379
3642
  {
@@ -3398,7 +3661,7 @@ var ChatMessageItemView = ({
3398
3661
  ) : null,
3399
3662
  isStoppedAssistant ? /* @__PURE__ */ jsx8(StatusTag, { "data-testid": "chat-message-stopped-tag", children: labels.stoppedResponse }) : null
3400
3663
  ] }) : null,
3401
- /* @__PURE__ */ jsxs5(Content, { "data-testid": "chat-message-content", children: [
3664
+ /* @__PURE__ */ jsxs5(Content2, { "data-testid": "chat-message-content", children: [
3402
3665
  skills.length ? /* @__PURE__ */ jsx8(SkillTagList, { "data-testid": "chat-message-skill-tags", children: skills.map((skill) => /* @__PURE__ */ jsx8(SkillTag, { children: skill }, skill)) }) : null,
3403
3666
  shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ jsx8(
3404
3667
  ContentStack,
@@ -3478,7 +3741,7 @@ var Bubble = styled7.article`
3478
3741
  border-radius: 16px;
3479
3742
  }
3480
3743
  `;
3481
- var Header2 = styled7.div`
3744
+ var Header3 = styled7.div`
3482
3745
  display: flex;
3483
3746
  align-items: center;
3484
3747
  gap: 10px;
@@ -3520,7 +3783,7 @@ var CollapseToggle = styled7.button`
3520
3783
  color: rgba(255, 255, 255, 0.92);
3521
3784
  }
3522
3785
  `;
3523
- var Content = styled7.div`
3786
+ var Content2 = styled7.div`
3524
3787
  color: rgba(255, 255, 255, 0.92);
3525
3788
  font-size: 14px;
3526
3789
  line-height: 1.6;
@@ -3906,9 +4169,9 @@ var ChatThreadView = ({
3906
4169
  const isPinnedRef = useRef5(true);
3907
4170
  const lastHistoryMessageIdRef = useRef5(latestHistoryMessage?.id);
3908
4171
  const lastStreamingMessageIdRef = useRef5(streamingMessage?.id);
3909
- const [latestTurnMinHeight, setLatestTurnMinHeight] = useState4(0);
3910
- const [isDetached, setIsDetached] = useState4(false);
3911
- const [pendingNewMessageCount, setPendingNewMessageCount] = useState4(0);
4172
+ const [latestTurnMinHeight, setLatestTurnMinHeight] = useState5(0);
4173
+ const [isDetached, setIsDetached] = useState5(false);
4174
+ const [pendingNewMessageCount, setPendingNewMessageCount] = useState5(0);
3912
4175
  const measureLatestTurnMinHeight = useCallback3(() => {
3913
4176
  const container = containerRef.current;
3914
4177
  if (!container)
@@ -4302,13 +4565,14 @@ var ChatThread = () => {
4302
4565
  if (!hasSessions || messages.length === 0 && !streamingMessage) {
4303
4566
  return /* @__PURE__ */ jsx10(ChatThreadEmptyState, {});
4304
4567
  }
4568
+ const displayError = error2 && !(error2.toLowerCase().includes("plan option timeout") || error2.toLowerCase().includes("plan_option_timeout") || error2.toLowerCase().includes("selection expired") || labels.questionnaireExpired && error2.includes(labels.questionnaireExpired)) ? error2 : void 0;
4305
4569
  return /* @__PURE__ */ jsx10(
4306
4570
  ChatThreadView,
4307
4571
  {
4308
4572
  activeMode: preferredMode,
4309
4573
  historyMessages: messages,
4310
4574
  streamingMessage,
4311
- error: error2,
4575
+ error: displayError,
4312
4576
  isLoadingPreviousMessages: historyMessagePagination?.isLoadingPrevious,
4313
4577
  previousMessagesError: historyMessagePagination?.error,
4314
4578
  retryButtonLabel: labels.retryButton,
@@ -4457,7 +4721,7 @@ var ScrollToLatestBadge = styled9.span`
4457
4721
  `;
4458
4722
 
4459
4723
  // src/components/chat-composer/index.tsx
4460
- import { useCallback as useCallback8, useEffect as useEffect9, useLayoutEffect as useLayoutEffect6, useRef as useRef11, useState as useState10 } from "react";
4724
+ import { useCallback as useCallback8, useEffect as useEffect10, useLayoutEffect as useLayoutEffect6, useRef as useRef11, useState as useState11 } from "react";
4461
4725
  import styled14 from "@emotion/styled";
4462
4726
 
4463
4727
  // ../../node_modules/.pnpm/@floating-ui+react@0.27.16_react-dom@18.3.1_react@18.3.1/node_modules/@floating-ui/react/dist/floating-ui.react.mjs
@@ -7055,10 +7319,10 @@ var resolveSendSession = ({
7055
7319
  };
7056
7320
 
7057
7321
  // src/components/chat-composer/hooks/use-chat-composer.ts
7058
- import { useCallback as useCallback7, useEffect as useEffect8, useRef as useRef10, useState as useState8 } from "react";
7322
+ import { useCallback as useCallback7, useEffect as useEffect9, useRef as useRef10, useState as useState9 } from "react";
7059
7323
 
7060
7324
  // src/components/chat-composer/hooks/use-composer-attachments.ts
7061
- import { useEffect as useEffect7, useRef as useRef9, useState as useState7 } from "react";
7325
+ import { useEffect as useEffect8, useRef as useRef9, useState as useState8 } from "react";
7062
7326
  var SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
7063
7327
  var MAX_COMPOSER_ATTACHMENTS = 10;
7064
7328
  var createObjectUrl = (file) => typeof URL !== "undefined" && typeof URL.createObjectURL === "function" ? URL.createObjectURL(file) : "";
@@ -7072,12 +7336,12 @@ var releaseComposerAttachments = (attachments) => {
7072
7336
  attachments.forEach((attachment) => revokeObjectUrl(attachment.previewUrl));
7073
7337
  };
7074
7338
  var useComposerAttachments = () => {
7075
- const [attachments, setAttachments] = useState7([]);
7339
+ const [attachments, setAttachments] = useState8([]);
7076
7340
  const attachmentsRef = useRef9([]);
7077
- useEffect7(() => {
7341
+ useEffect8(() => {
7078
7342
  attachmentsRef.current = attachments;
7079
7343
  }, [attachments]);
7080
- useEffect7(
7344
+ useEffect8(
7081
7345
  () => () => {
7082
7346
  releaseComposerAttachments(attachmentsRef.current);
7083
7347
  },
@@ -7225,13 +7489,13 @@ var useChatComposer = () => {
7225
7489
  const setSessionError = useChatStore((s) => s.setSessionError);
7226
7490
  const clearSessionError = useChatStore((s) => s.clearSessionError);
7227
7491
  const setPreferredMode = useChatStore((s) => s.setPreferredMode);
7228
- const [availableModels, setAvailableModels] = useState8([]);
7229
- const [isModelsLoading, setIsModelsLoading] = useState8(true);
7230
- const [isModelsError, setIsModelsError] = useState8(false);
7231
- const [availableSkills, setAvailableSkills] = useState8(
7492
+ const [availableModels, setAvailableModels] = useState9([]);
7493
+ const [isModelsLoading, setIsModelsLoading] = useState9(true);
7494
+ const [isModelsError, setIsModelsError] = useState9(false);
7495
+ const [availableSkills, setAvailableSkills] = useState9(
7232
7496
  () => getCachedSkills(skillsLoader).skills
7233
7497
  );
7234
- const [isSkillsLoading, setIsSkillsLoading] = useState8(
7498
+ const [isSkillsLoading, setIsSkillsLoading] = useState9(
7235
7499
  () => Boolean(skillsLoader) && !getCachedSkills(skillsLoader).resolved
7236
7500
  );
7237
7501
  const fetchModels = useCallback7(async () => {
@@ -7246,10 +7510,10 @@ var useChatComposer = () => {
7246
7510
  setIsModelsLoading(false);
7247
7511
  }
7248
7512
  }, [modelsLoader]);
7249
- useEffect8(() => {
7513
+ useEffect9(() => {
7250
7514
  void fetchModels();
7251
7515
  }, [fetchModels]);
7252
- useEffect8(() => {
7516
+ useEffect9(() => {
7253
7517
  activeSkillsLoaderRef.current = skillsLoader;
7254
7518
  const cachedSkills = getCachedSkills(skillsLoader);
7255
7519
  setAvailableSkills(cachedSkills.skills);
@@ -7285,35 +7549,35 @@ var useChatComposer = () => {
7285
7549
  }
7286
7550
  }
7287
7551
  }, [skillsLoader]);
7288
- useEffect8(() => {
7552
+ useEffect9(() => {
7289
7553
  void fetchSkills();
7290
7554
  }, [fetchSkills]);
7291
7555
  const hasModels = availableModels.length > 0;
7292
- const [value, setValue] = useState8("");
7293
- const [selectedModel, setSelectedModel] = useState8("");
7294
- const [selectedMode, setSelectedModeLocal] = useState8(DEFAULT_CHAT_AGENT_MODE);
7295
- const [selectedSkills, setSelectedSkills] = useState8([]);
7296
- const [attachmentNotice, setAttachmentNotice] = useState8(null);
7556
+ const [value, setValue] = useState9("");
7557
+ const [selectedModel, setSelectedModel] = useState9("");
7558
+ const [selectedMode, setSelectedModeLocal] = useState9(DEFAULT_CHAT_AGENT_MODE);
7559
+ const [selectedSkills, setSelectedSkills] = useState9([]);
7560
+ const [attachmentNotice, setAttachmentNotice] = useState9(null);
7297
7561
  const { attachments, appendFiles, removeAttachment, takeMessageAttachments } = useComposerAttachments();
7298
7562
  const abortControllerBySessionRef = useRef10(/* @__PURE__ */ new Map());
7299
7563
  const stopRequestBySessionRef = useRef10(/* @__PURE__ */ new Map());
7300
7564
  const lastRequestBySessionRef = useRef10(/* @__PURE__ */ new Map());
7301
7565
  const previousActiveSessionIdRef = useRef10(activeSessionId);
7302
- useEffect8(() => {
7566
+ useEffect9(() => {
7303
7567
  setSelectedModel(
7304
7568
  (current) => resolveSelectedChatModel({ currentModel: current, availableModels, isModelsLoading })
7305
7569
  );
7306
7570
  }, [availableModels, isModelsLoading]);
7307
- useEffect8(() => {
7571
+ useEffect9(() => {
7308
7572
  setSelectedModeLocal(preferredMode ?? DEFAULT_CHAT_AGENT_MODE);
7309
7573
  }, [preferredMode]);
7310
- useEffect8(() => {
7574
+ useEffect9(() => {
7311
7575
  if (previousActiveSessionIdRef.current !== activeSessionId) {
7312
7576
  setSelectedSkills([]);
7313
7577
  previousActiveSessionIdRef.current = activeSessionId;
7314
7578
  }
7315
7579
  }, [activeSessionId]);
7316
- useEffect8(() => {
7580
+ useEffect9(() => {
7317
7581
  if (!attachmentNotice)
7318
7582
  return;
7319
7583
  const timeoutId = window.setTimeout(
@@ -7697,14 +7961,14 @@ var useChatComposer = () => {
7697
7961
  };
7698
7962
 
7699
7963
  // src/components/chat-composer/components/chat-composer-attachment-list.tsx
7700
- import { useState as useState9 } from "react";
7964
+ import { useState as useState10 } from "react";
7701
7965
  import styled10 from "@emotion/styled";
7702
7966
  import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs9 } from "@emotion/react/jsx-runtime";
7703
7967
  var ChatComposerAttachmentList = ({
7704
7968
  attachments,
7705
7969
  onRemoveAttachment
7706
7970
  }) => {
7707
- const [activeImage, setActiveImage] = useState9(null);
7971
+ const [activeImage, setActiveImage] = useState10(null);
7708
7972
  if (!attachments.length) {
7709
7973
  return null;
7710
7974
  }
@@ -8385,9 +8649,9 @@ var ChatComposerView = ({
8385
8649
  }) => {
8386
8650
  const imageInputRef = useRef11(null);
8387
8651
  const inputRef = useRef11(null);
8388
- const [isComposerExpandable, setIsComposerExpandable] = useState10(false);
8389
- const [isComposerExpanded, setIsComposerExpanded] = useState10(false);
8390
- const [activeSkillNavigation, setActiveSkillNavigation] = useState10({
8652
+ const [isComposerExpandable, setIsComposerExpandable] = useState11(false);
8653
+ const [isComposerExpanded, setIsComposerExpanded] = useState11(false);
8654
+ const [activeSkillNavigation, setActiveSkillNavigation] = useState11({
8391
8655
  queryKey: "",
8392
8656
  index: 0
8393
8657
  });
@@ -8593,7 +8857,7 @@ var ChatComposerView = ({
8593
8857
  }
8594
8858
  )
8595
8859
  ] }),
8596
- /* @__PURE__ */ jsxs11(Footer, { children: [
8860
+ /* @__PURE__ */ jsxs11(Footer2, { children: [
8597
8861
  /* @__PURE__ */ jsxs11(LeadingActions, { "data-testid": "chat-composer-leading-actions", children: [
8598
8862
  enableImageAttachments ? /* @__PURE__ */ jsx16(
8599
8863
  AttachButton,
@@ -8685,7 +8949,7 @@ var ChatComposer = () => {
8685
8949
  const { labels, sendRef, retryRef, stopRef, enableImageAttachments } = useChatContext();
8686
8950
  const { state, actions } = useChatComposer();
8687
8951
  const { send, retry } = actions;
8688
- useEffect9(() => {
8952
+ useEffect10(() => {
8689
8953
  sendRef.current = send;
8690
8954
  retryRef.current = async (sessionId) => {
8691
8955
  retry(sessionId);
@@ -8933,7 +9197,7 @@ var ComposerExpandButton = styled14.button`
8933
9197
  color: rgba(255, 255, 255, 0.92);
8934
9198
  }
8935
9199
  `;
8936
- var Footer = styled14.div`
9200
+ var Footer2 = styled14.div`
8937
9201
  grid-area: footer;
8938
9202
  display: flex;
8939
9203
  align-items: center;
@@ -9014,7 +9278,7 @@ var SkillButton = styled14.button`
9014
9278
  `;
9015
9279
 
9016
9280
  // src/components/chat-conversation-list/index.tsx
9017
- import { useEffect as useEffect10, useRef as useRef12 } from "react";
9281
+ import { useEffect as useEffect11, useRef as useRef12 } from "react";
9018
9282
  import styled16 from "@emotion/styled";
9019
9283
 
9020
9284
  // src/components/chat-conversation-list/components/chat-session-item.tsx
@@ -9117,12 +9381,12 @@ var ChatConversationList = () => {
9117
9381
  );
9118
9382
  const isLoadingMoreRef = useRef12(false);
9119
9383
  const hasSeenLoadingMoreRef = useRef12(false);
9120
- useEffect10(() => {
9384
+ useEffect11(() => {
9121
9385
  if (!historySessionList)
9122
9386
  return;
9123
9387
  hydrateHistorySessions(historySessionList.sessions);
9124
9388
  }, [historySessionList, hydrateHistorySessions]);
9125
- useEffect10(() => {
9389
+ useEffect11(() => {
9126
9390
  if (historySessionList?.isLoading) {
9127
9391
  hasSeenLoadingMoreRef.current = true;
9128
9392
  return;
@@ -9132,7 +9396,7 @@ var ChatConversationList = () => {
9132
9396
  isLoadingMoreRef.current = false;
9133
9397
  }
9134
9398
  }, [historySessionList?.isLoading]);
9135
- useEffect10(() => {
9399
+ useEffect11(() => {
9136
9400
  isLoadingMoreRef.current = false;
9137
9401
  hasSeenLoadingMoreRef.current = false;
9138
9402
  }, [historySessionList?.sessions.length, historySessionList?.hasMore]);
@@ -9331,7 +9595,7 @@ var AiChatWorkspaceContent = ({
9331
9595
  })
9332
9596
  );
9333
9597
  const shouldShowComposerOnly = showComposerOnlyBeforeFirstMessage && !showConversationList && !isConversationStarted;
9334
- useEffect11(() => {
9598
+ useEffect12(() => {
9335
9599
  onConversationStartedChange?.(isConversationStarted);
9336
9600
  }, [isConversationStarted, onConversationStartedChange]);
9337
9601
  return /* @__PURE__ */ jsxs13(Root, { "data-testid": "ai-chat", children: [