@xinghunm/ai-chat 1.4.4 → 1.6.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.js CHANGED
@@ -46,7 +46,7 @@ __export(src_exports, {
46
46
  module.exports = __toCommonJS(src_exports);
47
47
 
48
48
  // src/components/ai-chat/index.tsx
49
- var import_react21 = require("react");
49
+ var import_react22 = require("react");
50
50
  var import_styled17 = __toESM(require("@emotion/styled"));
51
51
  var import_compass_ui4 = require("@xinghunm/compass-ui");
52
52
 
@@ -96,6 +96,7 @@ var DEFAULT_AI_CHAT_LABELS = {
96
96
  questionnaireMultiSelectHint: "Multiple choice",
97
97
  questionnaireOtherOptionLabel: "Other",
98
98
  questionnaireOtherPlaceholder: "Other",
99
+ questionnaireExpired: "Selection expired.",
99
100
  modelLoading: "Loading models...",
100
101
  modelLoadFailed: "Failed to load models",
101
102
  modelUnavailable: "No model available",
@@ -104,7 +105,9 @@ var DEFAULT_AI_CHAT_LABELS = {
104
105
  removeSkillAriaLabel: "Remove skill",
105
106
  sessionHistoryLoading: "Loading conversations...",
106
107
  sessionHistoryLoadFailed: "Failed to load conversations",
107
- sessionHistoryEmpty: "No conversations yet"
108
+ sessionHistoryEmpty: "No conversations yet",
109
+ questionnaireTitle: "Plan Options",
110
+ questionnaireConfirmInTime: "Please confirm within {{seconds}} seconds"
108
111
  };
109
112
 
110
113
  // src/lib/chat-session.ts
@@ -144,6 +147,42 @@ var mergeOlderHistoryMessages = (sessionId, olderMessages, currentMessages) => {
144
147
  );
145
148
  return [...uniqueOlderMessages, ...currentMessages];
146
149
  };
150
+ var mergeLocalQuestionnaireState = (localMessages, incomingMessages) => {
151
+ if (!localMessages?.length)
152
+ return incomingMessages;
153
+ return incomingMessages.map((incomingMsg) => {
154
+ const localMsg = localMessages.find((lm) => lm.id === incomingMsg.id);
155
+ if (!localMsg)
156
+ return incomingMsg;
157
+ if (localMsg.blocks && !incomingMsg.blocks) {
158
+ return {
159
+ ...incomingMsg,
160
+ blocks: localMsg.blocks
161
+ };
162
+ }
163
+ if (localMsg.blocks && incomingMsg.blocks) {
164
+ const nextBlocks = incomingMsg.blocks.map((incomingBlock, index3) => {
165
+ const localBlock = localMsg.blocks?.[index3];
166
+ const isSameQuestionnaire = incomingBlock.type === "questionnaire" && localBlock?.type === "questionnaire" && (localBlock.questionnaire.questionnaireId === incomingBlock.questionnaire.questionnaireId || Boolean(localBlock.questionnaire.blockKey) && localBlock.questionnaire.blockKey === incomingBlock.questionnaire.blockKey);
167
+ if (isSameQuestionnaire) {
168
+ return {
169
+ ...incomingBlock,
170
+ questionnaire: {
171
+ ...incomingBlock.questionnaire,
172
+ questionnaireId: localBlock.questionnaire.questionnaireId ?? incomingBlock.questionnaire.questionnaireId,
173
+ answers: localBlock.questionnaire.answers ?? incomingBlock.questionnaire.answers,
174
+ status: localBlock.questionnaire.status ?? incomingBlock.questionnaire.status,
175
+ statusMessage: localBlock.questionnaire.statusMessage ?? incomingBlock.questionnaire.statusMessage
176
+ }
177
+ };
178
+ }
179
+ return incomingBlock;
180
+ });
181
+ return { ...incomingMsg, blocks: nextBlocks };
182
+ }
183
+ return incomingMsg;
184
+ });
185
+ };
147
186
  var resolveSessionTitleFromMessage = (message) => {
148
187
  const trimmedContent = message.content.trim();
149
188
  if (trimmedContent) {
@@ -526,10 +565,12 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
526
565
  },
527
566
  hydrateHistorySessionMessages: (sessionId, messages) => {
528
567
  const state = get();
568
+ const localMessages = state.messagesBySession[sessionId] ?? [];
569
+ const nextMessages = mergeLocalQuestionnaireState(localMessages, messages);
529
570
  set({
530
571
  messagesBySession: {
531
572
  ...state.messagesBySession,
532
- [sessionId]: normalizeHistoryMessages(sessionId, messages)
573
+ [sessionId]: normalizeHistoryMessages(sessionId, nextMessages)
533
574
  },
534
575
  sessionMessageLoadStatusBySession: {
535
576
  ...state.sessionMessageLoadStatusBySession,
@@ -547,10 +588,12 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
547
588
  },
548
589
  hydrateHistorySessionMessagesPage: (sessionId, page) => {
549
590
  const state = get();
591
+ const localMessages = state.messagesBySession[sessionId] ?? [];
592
+ const nextMessages = mergeLocalQuestionnaireState(localMessages, page.messages);
550
593
  set({
551
594
  messagesBySession: {
552
595
  ...state.messagesBySession,
553
- [sessionId]: normalizeHistoryMessages(sessionId, page.messages)
596
+ [sessionId]: normalizeHistoryMessages(sessionId, nextMessages)
554
597
  },
555
598
  sessionMessageLoadStatusBySession: {
556
599
  ...state.sessionMessageLoadStatusBySession,
@@ -709,7 +752,11 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
709
752
  hasUpdatedBlock = true;
710
753
  return {
711
754
  ...block,
712
- questionnaire: { ...block.questionnaire, answers: { ...answers } }
755
+ questionnaire: {
756
+ ...block.questionnaire,
757
+ answers: { ...answers },
758
+ status: "submitted"
759
+ }
713
760
  };
714
761
  });
715
762
  if (!hasUpdatedBlock)
@@ -1078,6 +1125,7 @@ var AiChatProvider = (props) => {
1078
1125
  onLoadMoreSessions,
1079
1126
  onSelectHistorySession,
1080
1127
  onLoadMoreHistoryMessages,
1128
+ renderSessionItemActions,
1081
1129
  enableImageAttachments = true,
1082
1130
  children
1083
1131
  } = props;
@@ -1090,6 +1138,17 @@ var AiChatProvider = (props) => {
1090
1138
  });
1091
1139
  const stopRef = (0, import_react2.useRef)(async (_sessionId) => {
1092
1140
  });
1141
+ const [stopSession, setStopSession] = (0, import_react2.useState)(
1142
+ () => async (_sessionId) => {
1143
+ }
1144
+ );
1145
+ const registerStopSession = (0, import_react2.useCallback)(
1146
+ (handler) => {
1147
+ stopRef.current = handler;
1148
+ setStopSession(() => handler);
1149
+ },
1150
+ []
1151
+ );
1093
1152
  const defaultApiBaseUrl = "apiBaseUrl" in props ? props.apiBaseUrl : void 0;
1094
1153
  const defaultAuthToken = "authToken" in props ? props.authToken : void 0;
1095
1154
  const defaultTransformStreamPacket = "transformStreamPacket" in props ? props.transformStreamPacket : void 0;
@@ -1149,6 +1208,8 @@ var AiChatProvider = (props) => {
1149
1208
  sendRef,
1150
1209
  retryRef,
1151
1210
  stopRef,
1211
+ stopSession,
1212
+ registerStopSession,
1152
1213
  renderMessageBlock,
1153
1214
  handleQuestionnaireSubmit,
1154
1215
  handleConfirmationSubmit,
@@ -1158,7 +1219,8 @@ var AiChatProvider = (props) => {
1158
1219
  historySessionList,
1159
1220
  onLoadMoreSessions,
1160
1221
  onSelectHistorySession,
1161
- onLoadMoreHistoryMessages
1222
+ onLoadMoreHistoryMessages,
1223
+ renderSessionItemActions
1162
1224
  }),
1163
1225
  [
1164
1226
  axiosInstance,
@@ -1174,10 +1236,13 @@ var AiChatProvider = (props) => {
1174
1236
  onLoadMoreSessions,
1175
1237
  onLoadMoreHistoryMessages,
1176
1238
  onSelectHistorySession,
1239
+ renderSessionItemActions,
1177
1240
  renderMessageBlock,
1178
1241
  sendRef,
1179
1242
  retryRef,
1180
1243
  stopRef,
1244
+ stopSession,
1245
+ registerStopSession,
1181
1246
  store,
1182
1247
  transport
1183
1248
  ]
@@ -1186,7 +1251,7 @@ var AiChatProvider = (props) => {
1186
1251
  };
1187
1252
 
1188
1253
  // src/components/chat-thread/index.tsx
1189
- var import_react11 = require("react");
1254
+ var import_react12 = require("react");
1190
1255
  var import_styled9 = __toESM(require("@emotion/styled"));
1191
1256
 
1192
1257
  // src/context/use-chat-context.ts
@@ -1207,9 +1272,9 @@ var useChatStore = (selector) => {
1207
1272
  var CHAT_THREAD_SCROLL_TOP_GAP = 16;
1208
1273
 
1209
1274
  // src/components/chat-thread/components/chat-message-item.tsx
1210
- var import_react9 = require("react");
1275
+ var import_react10 = require("react");
1211
1276
  var import_styled7 = __toESM(require("@emotion/styled"));
1212
- var import_react10 = require("@emotion/react");
1277
+ var import_react11 = require("@emotion/react");
1213
1278
  var import_react_markdown = __toESM(require("react-markdown"));
1214
1279
  var import_remark_gfm = __toESM(require("remark-gfm"));
1215
1280
  var import_remark_math = __toESM(require("remark-math"));
@@ -1263,11 +1328,23 @@ var getNextDisplayedUnitCount = ({
1263
1328
  var splitMarkdownBlocks = (content) => content.split(/\n{2,}/).map((block) => block.trim()).filter(Boolean);
1264
1329
 
1265
1330
  // src/components/chat-thread/hooks/use-chat-message-reveal.ts
1331
+ var revealedStreamingMessages = /* @__PURE__ */ new Set();
1332
+ var markMessageAsRevealed = (id) => {
1333
+ if (revealedStreamingMessages.size > 500) {
1334
+ const firstKey = revealedStreamingMessages.keys().next().value;
1335
+ if (firstKey !== void 0) {
1336
+ revealedStreamingMessages.delete(firstKey);
1337
+ }
1338
+ }
1339
+ revealedStreamingMessages.add(id);
1340
+ };
1266
1341
  var createRevealState = ({
1267
1342
  isAssistantStreaming,
1268
- targetUnitCount
1343
+ targetUnitCount,
1344
+ messageId
1269
1345
  }) => {
1270
- const initialDisplayedUnitCount = isAssistantStreaming ? 0 : targetUnitCount;
1346
+ const hasBeenRevealed = revealedStreamingMessages.has(messageId);
1347
+ const initialDisplayedUnitCount = isAssistantStreaming && !hasBeenRevealed ? 0 : targetUnitCount;
1271
1348
  return {
1272
1349
  batchedTargetUnitCount: initialDisplayedUnitCount,
1273
1350
  displayedUnitCount: initialDisplayedUnitCount,
@@ -1277,7 +1354,11 @@ var createRevealState = ({
1277
1354
  var revealReducer = (state, action) => {
1278
1355
  switch (action.type) {
1279
1356
  case "reset-message":
1280
- return createRevealState(action);
1357
+ return createRevealState({
1358
+ isAssistantStreaming: action.isAssistantStreaming,
1359
+ targetUnitCount: action.targetUnitCount,
1360
+ messageId: action.messageId
1361
+ });
1281
1362
  case "commit-batched-target": {
1282
1363
  const nextDisplayedUnitCount = action.role === "assistant" ? getNextDisplayedUnitCount({
1283
1364
  currentUnits: state.displayedUnitCount,
@@ -1334,7 +1415,8 @@ var useChatMessageReveal = (message) => {
1334
1415
  revealReducer,
1335
1416
  {
1336
1417
  isAssistantStreaming,
1337
- targetUnitCount: targetUnits.length
1418
+ targetUnitCount: targetUnits.length,
1419
+ messageId: message.id
1338
1420
  },
1339
1421
  createRevealState
1340
1422
  );
@@ -1366,7 +1448,8 @@ var useChatMessageReveal = (message) => {
1366
1448
  dispatch({
1367
1449
  type: "reset-message",
1368
1450
  isAssistantStreaming,
1369
- targetUnitCount: targetUnits.length
1451
+ targetUnitCount: targetUnits.length,
1452
+ messageId: message.id
1370
1453
  });
1371
1454
  }, [isAssistantStreaming, message.id, targetUnits.length]);
1372
1455
  (0, import_react5.useEffect)(() => {
@@ -1445,6 +1528,11 @@ var useChatMessageReveal = (message) => {
1445
1528
  tone: "settled"
1446
1529
  }
1447
1530
  ];
1531
+ (0, import_react5.useEffect)(() => {
1532
+ if (isAssistantStreaming && displayedUnitCount > 0) {
1533
+ markMessageAsRevealed(message.id);
1534
+ }
1535
+ }, [isAssistantStreaming, displayedUnitCount, message.id]);
1448
1536
  return {
1449
1537
  isAssistantStreaming,
1450
1538
  isFreshBlockActive,
@@ -2035,9 +2123,96 @@ var Value = import_styled3.default.span`
2035
2123
  `;
2036
2124
 
2037
2125
  // src/components/chat-thread/components/questionnaire-card.tsx
2038
- var import_react7 = require("react");
2126
+ var import_react8 = require("react");
2039
2127
  var import_styled4 = __toESM(require("@emotion/styled"));
2040
2128
 
2129
+ // src/components/chat-thread/components/use-countdown-seconds.ts
2130
+ var import_react7 = require("react");
2131
+ var countdownDeadlineByKey = /* @__PURE__ */ new Map();
2132
+ var countdownCleanupTimerByKey = /* @__PURE__ */ new Map();
2133
+ var countdownMountCountByKey = /* @__PURE__ */ new Map();
2134
+ var clearCountdownEntry = (storageKey) => {
2135
+ const cleanupTimerId = countdownCleanupTimerByKey.get(storageKey);
2136
+ if (cleanupTimerId !== void 0) {
2137
+ window.clearTimeout(cleanupTimerId);
2138
+ countdownCleanupTimerByKey.delete(storageKey);
2139
+ }
2140
+ countdownDeadlineByKey.delete(storageKey);
2141
+ };
2142
+ var scheduleCountdownCleanup = (storageKey, deadline) => {
2143
+ const existingCleanupTimerId = countdownCleanupTimerByKey.get(storageKey);
2144
+ if (existingCleanupTimerId !== void 0) {
2145
+ return;
2146
+ }
2147
+ const delayMs = Math.max(0, deadline - Date.now());
2148
+ const cleanupTimerId = window.setTimeout(() => {
2149
+ if ((countdownMountCountByKey.get(storageKey) ?? 0) > 0) {
2150
+ countdownCleanupTimerByKey.delete(storageKey);
2151
+ return;
2152
+ }
2153
+ clearCountdownEntry(storageKey);
2154
+ }, delayMs);
2155
+ countdownCleanupTimerByKey.set(storageKey, cleanupTimerId);
2156
+ };
2157
+ var getCountdownDeadline = (storageKey, initialSeconds) => {
2158
+ const existingDeadline = countdownDeadlineByKey.get(storageKey);
2159
+ if (existingDeadline !== void 0) {
2160
+ return existingDeadline;
2161
+ }
2162
+ const nextDeadline = Date.now() + Math.max(0, initialSeconds) * 1e3;
2163
+ countdownDeadlineByKey.set(storageKey, nextDeadline);
2164
+ scheduleCountdownCleanup(storageKey, nextDeadline);
2165
+ return nextDeadline;
2166
+ };
2167
+ var getRemainingSeconds = (deadline) => Math.max(0, Math.ceil((deadline - Date.now()) / 1e3));
2168
+ var useCountdownSeconds = ({
2169
+ storageKey,
2170
+ initialSeconds,
2171
+ active
2172
+ }) => {
2173
+ const [remainingSeconds, setRemainingSeconds] = (0, import_react7.useState)(
2174
+ () => getRemainingSeconds(getCountdownDeadline(storageKey, initialSeconds))
2175
+ );
2176
+ (0, import_react7.useEffect)(() => {
2177
+ countdownMountCountByKey.set(storageKey, (countdownMountCountByKey.get(storageKey) ?? 0) + 1);
2178
+ return () => {
2179
+ const nextCount = (countdownMountCountByKey.get(storageKey) ?? 1) - 1;
2180
+ if (nextCount <= 0) {
2181
+ countdownMountCountByKey.delete(storageKey);
2182
+ return;
2183
+ }
2184
+ countdownMountCountByKey.set(storageKey, nextCount);
2185
+ };
2186
+ }, [storageKey]);
2187
+ (0, import_react7.useEffect)(() => {
2188
+ setRemainingSeconds(getRemainingSeconds(getCountdownDeadline(storageKey, initialSeconds)));
2189
+ }, [initialSeconds, storageKey]);
2190
+ (0, import_react7.useEffect)(() => {
2191
+ if (active) {
2192
+ return;
2193
+ }
2194
+ clearCountdownEntry(storageKey);
2195
+ }, [active, storageKey]);
2196
+ (0, import_react7.useEffect)(() => {
2197
+ if (remainingSeconds > 0) {
2198
+ return;
2199
+ }
2200
+ clearCountdownEntry(storageKey);
2201
+ }, [remainingSeconds, storageKey]);
2202
+ (0, import_react7.useEffect)(() => {
2203
+ if (!active || remainingSeconds <= 0) {
2204
+ return;
2205
+ }
2206
+ const timeoutId = window.setTimeout(() => {
2207
+ setRemainingSeconds(getRemainingSeconds(getCountdownDeadline(storageKey, initialSeconds)));
2208
+ }, 1e3);
2209
+ return () => {
2210
+ window.clearTimeout(timeoutId);
2211
+ };
2212
+ }, [active, initialSeconds, remainingSeconds, storageKey]);
2213
+ return remainingSeconds;
2214
+ };
2215
+
2041
2216
  // src/components/chat-thread/components/questionnaire-card-helpers.ts
2042
2217
  var OTHER_OPTION_VALUE = "__other__";
2043
2218
  var getQuestionnaireQuestion = (questionnaire) => questionnaire.question;
@@ -2344,7 +2519,10 @@ var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
2344
2519
  submitFailed: "Failed to submit. Please try again.",
2345
2520
  multiSelectHint: "Multiple choice",
2346
2521
  otherOptionLabel: "Other",
2347
- otherPlaceholder: "Other"
2522
+ otherPlaceholder: "Other",
2523
+ expired: "Selection expired.",
2524
+ questionnaireTitle: "Plan Options",
2525
+ questionnaireConfirmInTime: "Please confirm within {{seconds}} seconds"
2348
2526
  };
2349
2527
  var stopInputClickPropagation = (event) => {
2350
2528
  event.stopPropagation();
@@ -2404,32 +2582,41 @@ var QuestionnaireCardInner = ({
2404
2582
  onSubmit,
2405
2583
  labels
2406
2584
  }) => {
2407
- const questionnaireRef = (0, import_react7.useRef)(questionnaire);
2408
- const otherInputRefs = (0, import_react7.useRef)({});
2409
- const [answers, setAnswers] = (0, import_react7.useState)(
2585
+ const questionnaireRef = (0, import_react8.useRef)(questionnaire);
2586
+ const otherInputRefs = (0, import_react8.useRef)({});
2587
+ const [answers, setAnswers] = (0, import_react8.useState)(
2410
2588
  () => createInitialAnswers(questionnaire)
2411
2589
  );
2412
- const [otherDrafts, setOtherDrafts] = (0, import_react7.useState)(
2590
+ const [otherDrafts, setOtherDrafts] = (0, import_react8.useState)(
2413
2591
  () => createInitialOtherDrafts(questionnaire)
2414
2592
  );
2415
- const [errorMessage, setErrorMessage] = (0, import_react7.useState)(null);
2416
- const [isSubmitting, setIsSubmitting] = (0, import_react7.useState)(false);
2417
- const [isSubmitted, setIsSubmitted] = (0, import_react7.useState)(false);
2418
- const [pendingFocusQuestionId, setPendingFocusQuestionId] = (0, import_react7.useState)(null);
2593
+ const [errorMessage, setErrorMessage] = (0, import_react8.useState)(null);
2594
+ const [isSubmitting, setIsSubmitting] = (0, import_react8.useState)(false);
2595
+ const [isSubmitted, setIsSubmitted] = (0, import_react8.useState)(() => questionnaire.status === "submitted");
2596
+ const [pendingFocusQuestionId, setPendingFocusQuestionId] = (0, import_react8.useState)(null);
2419
2597
  const resolvedLabels = {
2420
2598
  ...DEFAULT_QUESTIONNAIRE_CARD_LABELS,
2421
2599
  ...labels
2422
2600
  };
2423
- const hasExternalFailureStatus = questionnaire.status === "expired" || questionnaire.status === "failed";
2601
+ const remainingSeconds = useCountdownSeconds({
2602
+ storageKey: questionnaire.blockKey ?? `questionnaire:${questionnaire.questionnaireId}`,
2603
+ initialSeconds: questionnaire.timeoutSec ?? 0,
2604
+ active: questionnaire.timeoutSec !== void 0 && questionnaire.timeoutSec > 0 && !isSubmitted && questionnaire.status !== "expired" && questionnaire.status !== "failed" && interactive
2605
+ });
2606
+ const isExpired = questionnaire.status === "expired" || questionnaire.timeoutSec !== void 0 && questionnaire.timeoutSec > 0 && remainingSeconds <= 0;
2607
+ const hasExternalFailureStatus = isExpired || questionnaire.status === "failed";
2424
2608
  const question = getQuestionnaireQuestion(questionnaire);
2425
- const visibleErrorMessage = questionnaire.statusMessage ?? errorMessage;
2426
- const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus;
2609
+ const visibleErrorMessage = questionnaire.statusMessage ?? (isExpired ? null : errorMessage);
2610
+ const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus || questionnaire.status === "submitted";
2427
2611
  questionnaireRef.current = questionnaire;
2428
- (0, import_react7.useEffect)(() => {
2612
+ (0, import_react8.useEffect)(() => {
2429
2613
  setAnswers(createInitialAnswers(questionnaireRef.current));
2430
2614
  setOtherDrafts(createInitialOtherDrafts(questionnaireRef.current));
2431
- }, [questionnaire.answers]);
2432
- (0, import_react7.useEffect)(() => {
2615
+ if (questionnaireRef.current.status === "submitted") {
2616
+ setIsSubmitted(true);
2617
+ }
2618
+ }, [questionnaire.answers, questionnaire.status]);
2619
+ (0, import_react8.useEffect)(() => {
2433
2620
  if (!pendingFocusQuestionId || isInteractionLocked) {
2434
2621
  return;
2435
2622
  }
@@ -2679,42 +2866,69 @@ var QuestionnaireCardInner = ({
2679
2866
  }
2680
2867
  };
2681
2868
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Card4, { "data-testid": "questionnaire-card", children: [
2682
- questionnaire.description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Description, { children: questionnaire.description }) : null,
2683
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionList, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(QuestionCard, { children: [
2684
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(QuestionLabel, { children: [
2685
- question.label,
2686
- question.required ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Required, { children: "*" }) : null
2687
- ] }),
2688
- question.kind === "multi_select" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionHint, { children: resolvedLabels.multiSelectHint }) : null,
2689
- renderQuestion(question)
2690
- ] }, question.id) }),
2691
- visibleErrorMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
2692
- isSubmitted ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : interactive && !hasExternalFailureStatus ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2693
- SubmitButton,
2694
- {
2695
- type: "button",
2696
- "data-testid": "questionnaire-submit",
2697
- disabled: isInteractionLocked,
2698
- onClick: () => {
2699
- void handleSubmit();
2700
- },
2701
- children: isSubmitting ? resolvedLabels.submitting : questionnaire.submitLabel ?? "Submit"
2702
- }
2703
- ) : null
2869
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Header2, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Eyebrow2, { children: resolvedLabels.questionnaireTitle }) }),
2870
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Content, { children: [
2871
+ questionnaire.description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Description, { children: questionnaire.description }) : null,
2872
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionList, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(QuestionCard, { children: [
2873
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(QuestionLabel, { children: [
2874
+ question.label,
2875
+ question.required ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Required, { children: "*" }) : null
2876
+ ] }),
2877
+ question.kind === "multi_select" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionHint, { children: resolvedLabels.multiSelectHint }) : null,
2878
+ renderQuestion(question)
2879
+ ] }, question.id) }),
2880
+ visibleErrorMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
2881
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Footer, { children: isSubmitted ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : isExpired ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpiredTag, { "data-testid": "questionnaire-expired", children: resolvedLabels.expired }) : interactive ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(FooterActionRow, { "data-testid": "questionnaire-card-actions", children: [
2882
+ remainingSeconds > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MetaText, { "data-testid": "questionnaire-countdown", children: resolvedLabels.questionnaireConfirmInTime?.replace(
2883
+ "{{seconds}}",
2884
+ String(remainingSeconds)
2885
+ ) ?? `\u8BF7\u5728 ${remainingSeconds} \u79D2\u5185\u786E\u8BA4` }),
2886
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2887
+ SubmitButton,
2888
+ {
2889
+ type: "button",
2890
+ "data-testid": "questionnaire-submit",
2891
+ disabled: isInteractionLocked,
2892
+ onClick: () => {
2893
+ void handleSubmit();
2894
+ },
2895
+ children: isSubmitting ? resolvedLabels.submitting : questionnaire.submitLabel ?? "Submit"
2896
+ }
2897
+ )
2898
+ ] }) : null })
2899
+ ] })
2704
2900
  ] });
2705
2901
  };
2706
2902
  var QuestionnaireCard = (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
2707
2903
  var Card4 = import_styled4.default.section`
2708
- display: grid;
2709
- gap: 14px;
2710
- padding: 16px;
2711
- border-radius: 20px;
2712
- border: 1px solid rgba(255, 255, 255, 0.08);
2713
- background: rgba(255, 255, 255, 0.03);
2904
+ overflow: hidden;
2905
+ background: var(--bg-primary);
2906
+ border-radius: 16px;
2907
+ border: 1px solid var(--border-hover);
2908
+ `;
2909
+ var Header2 = import_styled4.default.div`
2910
+ display: flex;
2911
+ flex-wrap: wrap;
2912
+ align-items: center;
2913
+ gap: 10px;
2914
+ padding: 22px 12px 16px;
2915
+ border-bottom: 1px solid var(--border-hover);
2916
+ `;
2917
+ var Eyebrow2 = import_styled4.default.div`
2918
+ font-weight: 500;
2919
+ font-size: 16px;
2920
+ color: var(--text-primary);
2921
+ line-height: 22px;
2922
+ `;
2923
+ var Content = import_styled4.default.div`
2924
+ display: flex;
2925
+ flex-direction: column;
2926
+ gap: 16px;
2927
+ padding: 16px 12px;
2714
2928
  `;
2715
2929
  var Description = import_styled4.default.p`
2716
2930
  margin: 0;
2717
- color: rgba(255, 255, 255, 0.72);
2931
+ color: var(--text-secondary);
2718
2932
  font-size: 13px;
2719
2933
  `;
2720
2934
  var QuestionList = import_styled4.default.div`
@@ -2725,11 +2939,11 @@ var QuestionCard = import_styled4.default.div`
2725
2939
  display: grid;
2726
2940
  gap: 10px;
2727
2941
  padding: 12px;
2728
- border-radius: 16px;
2729
- background: rgba(255, 255, 255, 0.04);
2942
+ border-radius: 8px;
2943
+ background: rgba(255, 255, 255, 0.02);
2730
2944
  `;
2731
2945
  var QuestionLabel = import_styled4.default.div`
2732
- color: rgba(255, 255, 255, 0.9);
2946
+ color: var(--text-primary);
2733
2947
  font-size: 14px;
2734
2948
  font-weight: 600;
2735
2949
  `;
@@ -2756,11 +2970,11 @@ var OptionChoiceItem = import_styled4.default.div`
2756
2970
  gap: 12px;
2757
2971
  width: 100%;
2758
2972
  text-align: left;
2759
- border: 1px solid rgba(255, 255, 255, 0.1);
2760
- border-radius: 14px;
2761
- background: rgba(255, 255, 255, 0.03);
2973
+ border: 1px solid var(--border-hover);
2974
+ border-radius: 8px;
2975
+ background: rgba(255, 255, 255, 0.02);
2762
2976
  padding: 2px 12px;
2763
- color: rgba(255, 255, 255, 0.9);
2977
+ color: var(--text-primary);
2764
2978
  cursor: pointer;
2765
2979
  transition:
2766
2980
  border-color 140ms ease,
@@ -2769,8 +2983,8 @@ var OptionChoiceItem = import_styled4.default.div`
2769
2983
  outline: none;
2770
2984
 
2771
2985
  &[data-selected='true'] {
2772
- border-color: rgba(126, 160, 255, 0.42);
2773
- background: linear-gradient(180deg, rgba(82, 114, 255, 0.18) 0%, rgba(82, 114, 255, 0.1) 100%);
2986
+ border-color: rgba(51, 133, 255, 0.42);
2987
+ background: linear-gradient(180deg, rgba(51, 133, 255, 0.18) 0%, rgba(51, 133, 255, 0.1) 100%);
2774
2988
  transform: translateY(-1px);
2775
2989
  }
2776
2990
 
@@ -2779,8 +2993,8 @@ var OptionChoiceItem = import_styled4.default.div`
2779
2993
  }
2780
2994
 
2781
2995
  &:focus-visible {
2782
- border-color: rgba(126, 160, 255, 0.52);
2783
- box-shadow: 0 0 0 1px rgba(126, 160, 255, 0.18);
2996
+ border-color: rgba(51, 133, 255, 0.52);
2997
+ box-shadow: 0 0 0 1px rgba(51, 133, 255, 0.18);
2784
2998
  }
2785
2999
 
2786
3000
  &[tabindex='-1'] {
@@ -2797,16 +3011,16 @@ var OptionChoiceMarker = import_styled4.default.span`
2797
3011
  width: 28px;
2798
3012
  height: 28px;
2799
3013
  border-radius: 8px;
2800
- border: 1px solid rgba(255, 255, 255, 0.14);
2801
- background: rgba(255, 255, 255, 0.04);
2802
- color: rgba(255, 255, 255, 0.65);
3014
+ border: 1px solid var(--border-hover);
3015
+ background: rgba(255, 255, 255, 0.02);
3016
+ color: var(--text-secondary);
2803
3017
  font-size: 12px;
2804
3018
  font-weight: 700;
2805
3019
 
2806
3020
  &[data-selected='true'] {
2807
- border-color: rgba(126, 160, 255, 0.38);
2808
- background: rgba(126, 160, 255, 0.2);
2809
- color: rgba(255, 255, 255, 0.96);
3021
+ border-color: rgba(51, 133, 255, 0.38);
3022
+ background: rgba(51, 133, 255, 0.2);
3023
+ color: var(--text-primary);
2810
3024
  }
2811
3025
  `;
2812
3026
  var OptionChoiceContent = import_styled4.default.span`
@@ -2826,47 +3040,41 @@ var OptionChoiceLabel = import_styled4.default.span`
2826
3040
  `;
2827
3041
  var TextInput = import_styled4.default.input`
2828
3042
  width: 100%;
2829
- border: 1px solid rgba(255, 255, 255, 0.1);
2830
- border-radius: 12px;
3043
+ border: 1px solid var(--border-hover);
3044
+ border-radius: 8px;
2831
3045
  background: rgba(13, 15, 21, 0.55);
2832
- color: rgba(255, 255, 255, 0.92);
3046
+ color: var(--text-primary);
2833
3047
  font-size: 13px;
2834
3048
  padding: 10px 12px;
2835
3049
 
2836
3050
  &::placeholder {
2837
- color: rgba(255, 255, 255, 0.34);
3051
+ color: var(--text-secondary);
3052
+ opacity: 0.5;
2838
3053
  }
2839
3054
  `;
2840
3055
  var InlineOtherInput = import_styled4.default.input`
2841
3056
  width: 100%;
2842
- margin-top: 0;
2843
-
2844
- .compass-input-wrapper {
2845
- min-height: 30px;
2846
- border: 1px solid rgba(255, 255, 255, 0.1);
2847
- border-radius: 10px;
2848
- background: rgba(13, 15, 21, 0.55);
2849
- box-shadow: none;
2850
- padding: 2px 9px;
2851
- }
2852
-
2853
- .compass-input-wrapper:hover {
2854
- border-color: rgba(126, 160, 255, 0.28);
2855
- }
3057
+ border: 1px solid var(--border-hover);
3058
+ border-radius: 6px;
3059
+ background: rgba(13, 15, 21, 0.45);
3060
+ color: var(--text-primary);
3061
+ font-size: 13px;
3062
+ padding: 6px 10px;
3063
+ outline: none;
3064
+ transition: border-color 140ms ease;
2856
3065
 
2857
- .compass-input-wrapper:focus-within {
2858
- border-color: rgba(126, 160, 255, 0.42);
2859
- box-shadow: 0 0 0 1px rgba(126, 160, 255, 0.14);
3066
+ &:hover {
3067
+ border-color: rgba(51, 133, 255, 0.28);
2860
3068
  }
2861
3069
 
2862
- .compass-input-input {
2863
- color: rgba(255, 255, 255, 0.92);
2864
- font-size: 13px;
2865
- line-height: 1.2;
3070
+ &:focus {
3071
+ border-color: rgba(51, 133, 255, 0.42);
3072
+ box-shadow: 0 0 0 1px rgba(51, 133, 255, 0.14);
2866
3073
  }
2867
3074
 
2868
- .compass-input-input::placeholder {
2869
- color: rgba(255, 255, 255, 0.34);
3075
+ &::placeholder {
3076
+ color: var(--text-secondary);
3077
+ opacity: 0.5;
2870
3078
  }
2871
3079
  `;
2872
3080
  var NumberInputRow = import_styled4.default.div`
@@ -2875,32 +3083,80 @@ var NumberInputRow = import_styled4.default.div`
2875
3083
  gap: 10px;
2876
3084
  `;
2877
3085
  var Unit = import_styled4.default.span`
2878
- color: rgba(255, 255, 255, 0.58);
3086
+ color: var(--text-secondary);
2879
3087
  font-size: 12px;
2880
3088
  white-space: nowrap;
2881
3089
  `;
2882
3090
  var ErrorMessage = import_styled4.default.div`
2883
- color: rgba(255, 145, 145, 0.96);
3091
+ font-size: 13px;
3092
+ line-height: 1.5;
3093
+ color: rgba(255, 207, 207, 0.92);
3094
+ `;
3095
+ var Footer = import_styled4.default.div`
3096
+ display: flex;
3097
+ flex-wrap: wrap;
3098
+ align-items: center;
3099
+ justify-content: flex-start;
3100
+ gap: 12px;
3101
+ `;
3102
+ var FooterActionRow = import_styled4.default.div`
3103
+ display: flex;
3104
+ align-items: center;
3105
+ flex-wrap: wrap;
3106
+ gap: 8px;
3107
+ margin-left: auto;
3108
+ justify-content: flex-end;
3109
+ `;
3110
+ var MetaText = import_styled4.default.span`
3111
+ font-weight: 500;
2884
3112
  font-size: 12px;
3113
+ color: var(--text-secondary);
3114
+ line-height: 17px;
3115
+ `;
3116
+ var ExpiredTag = import_styled4.default.span`
3117
+ display: inline-flex;
3118
+ align-items: center;
3119
+ padding: 8px 12px;
3120
+ border-radius: 8px;
3121
+ font-size: 13px;
3122
+ font-weight: 600;
3123
+ background: rgba(255, 255, 255, 0.05);
3124
+ border: 1px solid rgba(255, 255, 255, 0.12);
3125
+ color: rgba(214, 224, 236, 0.9);
2885
3126
  `;
2886
3127
  var SuccessMessage = import_styled4.default.div`
2887
- color: rgba(164, 255, 210, 0.96);
2888
- font-size: 12px;
3128
+ display: inline-flex;
3129
+ align-items: center;
3130
+ padding: 8px 12px;
3131
+ border-radius: 8px;
3132
+ font-size: 13px;
3133
+ font-weight: 600;
3134
+ background: rgba(190, 246, 202, 0.14);
3135
+ border: 1px solid rgba(190, 246, 202, 0.24);
3136
+ color: rgba(227, 255, 233, 0.94);
2889
3137
  `;
2890
3138
  var SubmitButton = import_styled4.default.button`
2891
- justify-self: flex-start;
2892
- border: none;
2893
- border-radius: 999px;
2894
- background: linear-gradient(180deg, #7ea0ff 0%, #4a6fff 100%);
2895
- color: #081127;
2896
- font-size: 12px;
2897
- font-weight: 700;
2898
- padding: 10px 14px;
3139
+ padding: 9px 16px;
3140
+ border-radius: 8px;
3141
+ border: 1px solid transparent;
3142
+ font-weight: 500;
3143
+ font-size: 14px;
3144
+ color: rgba(255, 255, 255, 0.96);
3145
+ background: linear-gradient(180deg, #3385ff 0%, #1f6ef2 100%);
3146
+ line-height: 14px;
2899
3147
  cursor: pointer;
3148
+ transition:
3149
+ transform 160ms ease,
3150
+ opacity 160ms ease;
2900
3151
 
2901
3152
  &:disabled {
2902
- cursor: default;
2903
- opacity: 0.72;
3153
+ cursor: progress;
3154
+ opacity: 0.68;
3155
+ transform: none;
3156
+ }
3157
+
3158
+ &:not(:disabled):hover {
3159
+ transform: translateY(-1px);
2904
3160
  }
2905
3161
  `;
2906
3162
 
@@ -2908,7 +3164,7 @@ var SubmitButton = import_styled4.default.button`
2908
3164
  var import_styled5 = __toESM(require("@emotion/styled"));
2909
3165
  var import_jsx_runtime6 = require("@emotion/react/jsx-runtime");
2910
3166
  var ResultSummaryCard = ({ summary }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Card5, { "data-testid": "result-summary-card", "data-status": summary.status, children: [
2911
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Eyebrow2, { children: summary.status }),
3167
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Eyebrow3, { children: summary.status }),
2912
3168
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Headline, { children: summary.headline }),
2913
3169
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Details, { children: summary.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Detail, { children: detail }, detail)) })
2914
3170
  ] });
@@ -2928,7 +3184,7 @@ var Card5 = import_styled5.default.section`
2928
3184
  border-color: rgba(255, 122, 122, 0.24);
2929
3185
  }
2930
3186
  `;
2931
- var Eyebrow2 = import_styled5.default.span`
3187
+ var Eyebrow3 = import_styled5.default.span`
2932
3188
  color: rgba(255, 255, 255, 0.58);
2933
3189
  font-size: 11px;
2934
3190
  font-weight: 700;
@@ -2953,7 +3209,7 @@ var Detail = import_styled5.default.li`
2953
3209
 
2954
3210
  // src/components/chat-thread/components/image-viewer.tsx
2955
3211
  var import_styled6 = __toESM(require("@emotion/styled"));
2956
- var import_react8 = require("react");
3212
+ var import_react9 = require("react");
2957
3213
  var import_jsx_runtime7 = require("@emotion/react/jsx-runtime");
2958
3214
  var Overlay = import_styled6.default.div`
2959
3215
  position: fixed;
@@ -2972,8 +3228,8 @@ var Img = import_styled6.default.img`
2972
3228
  border-radius: 4px;
2973
3229
  `;
2974
3230
  var ImageViewer = ({ src, alt, onClose }) => {
2975
- const overlayRef = (0, import_react8.useRef)(null);
2976
- (0, import_react8.useEffect)(() => {
3231
+ const overlayRef = (0, import_react9.useRef)(null);
3232
+ (0, import_react9.useEffect)(() => {
2977
3233
  const handleKey = (e) => {
2978
3234
  if (e.key === "Escape")
2979
3235
  onClose();
@@ -2981,7 +3237,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
2981
3237
  document.addEventListener("keydown", handleKey);
2982
3238
  return () => document.removeEventListener("keydown", handleKey);
2983
3239
  }, [onClose]);
2984
- (0, import_react8.useEffect)(() => {
3240
+ (0, import_react9.useEffect)(() => {
2985
3241
  overlayRef.current?.focus();
2986
3242
  }, []);
2987
3243
  const stopPropagation = (e) => e.stopPropagation();
@@ -3047,10 +3303,10 @@ var useUserMessageCollapse = ({
3047
3303
  freshContent,
3048
3304
  settledContent
3049
3305
  }) => {
3050
- const [isCollapsible, setIsCollapsible] = (0, import_react9.useState)(false);
3051
- const [isExpanded, setIsExpanded] = (0, import_react9.useState)(false);
3052
- const [bodyStackElement, setBodyStackElement] = (0, import_react9.useState)(null);
3053
- const syncCollapseState = (0, import_react9.useCallback)(
3306
+ const [isCollapsible, setIsCollapsible] = (0, import_react10.useState)(false);
3307
+ const [isExpanded, setIsExpanded] = (0, import_react10.useState)(false);
3308
+ const [bodyStackElement, setBodyStackElement] = (0, import_react10.useState)(null);
3309
+ const syncCollapseState = (0, import_react10.useCallback)(
3054
3310
  (element) => {
3055
3311
  const nextCollapsible = enabled && (element?.scrollHeight ?? 0) > USER_MESSAGE_COLLAPSE_HEIGHT_PX;
3056
3312
  setIsCollapsible(nextCollapsible);
@@ -3060,14 +3316,14 @@ var useUserMessageCollapse = ({
3060
3316
  },
3061
3317
  [enabled]
3062
3318
  );
3063
- const bodyStackRef = (0, import_react9.useCallback)(
3319
+ const bodyStackRef = (0, import_react10.useCallback)(
3064
3320
  (node) => {
3065
3321
  setBodyStackElement(node);
3066
3322
  syncCollapseState(node);
3067
3323
  },
3068
3324
  [syncCollapseState]
3069
3325
  );
3070
- (0, import_react9.useLayoutEffect)(() => {
3326
+ (0, import_react10.useLayoutEffect)(() => {
3071
3327
  if (!bodyStackElement) {
3072
3328
  return;
3073
3329
  }
@@ -3087,7 +3343,7 @@ var useUserMessageCollapse = ({
3087
3343
  settledContent,
3088
3344
  syncCollapseState
3089
3345
  ]);
3090
- (0, import_react9.useLayoutEffect)(() => {
3346
+ (0, import_react10.useLayoutEffect)(() => {
3091
3347
  if (!bodyStackElement || !enabled || typeof ResizeObserver === "undefined") {
3092
3348
  return;
3093
3349
  }
@@ -3235,7 +3491,7 @@ var ChatMessageItemView = ({
3235
3491
  renderMessageBlock
3236
3492
  }) => {
3237
3493
  const { labels, messageRenderOrder = "blocks-first" } = useChatContext();
3238
- const [activeImage, setActiveImage] = (0, import_react9.useState)(void 0);
3494
+ const [activeImage, setActiveImage] = (0, import_react10.useState)(void 0);
3239
3495
  const {
3240
3496
  displayedBlocks,
3241
3497
  displayedContent,
@@ -3252,8 +3508,9 @@ var ChatMessageItemView = ({
3252
3508
  const hasMarkdownOnlyBlocks = hasStructuredBlocks && blocks.every((block) => block.type === "markdown");
3253
3509
  const hasTextContent = Boolean(settledContent || freshContent || displayedContent);
3254
3510
  const shouldRenderStructuredBlocks = hasStructuredBlocks && !(isAssistantStreaming && hasMarkdownOnlyBlocks && hasTextContent);
3255
- const canSubmitConfirmation = typeof onConfirmationSubmit === "function";
3256
- const canSubmitQuestionnaire = typeof onQuestionnaireSubmit === "function";
3511
+ const isInteractionDisabled = message.status === "stopped" || message.status === "error";
3512
+ const canSubmitConfirmation = typeof onConfirmationSubmit === "function" && !isInteractionDisabled;
3513
+ const canSubmitQuestionnaire = typeof onQuestionnaireSubmit === "function" && !isInteractionDisabled;
3257
3514
  const shouldShowStreamingCaret = isAssistantStreaming && (!shouldRenderStructuredBlocks || hasTextContent);
3258
3515
  const isUserMessage = message.role === "user";
3259
3516
  const messageRenderMode = isUserMessage ? "plain-text" : "markdown";
@@ -3303,11 +3560,11 @@ var ChatMessageItemView = ({
3303
3560
  `markdown-${index3}`
3304
3561
  );
3305
3562
  case "notice":
3306
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NoticeCard, { text: block.text, tone: block.tone }) }, `notice-${index3}`);
3563
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react10.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NoticeCard, { text: block.text, tone: block.tone }) }, `notice-${index3}`);
3307
3564
  case "parameter_summary":
3308
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ParameterSummaryCard, { items: block.items }) }, `parameter-summary-${index3}`);
3565
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react10.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ParameterSummaryCard, { items: block.items }) }, `parameter-summary-${index3}`);
3309
3566
  case "confirmation_card":
3310
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3567
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react10.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3311
3568
  ExecutionConfirmationCard,
3312
3569
  {
3313
3570
  proposal: block.proposal,
@@ -3320,9 +3577,9 @@ var ChatMessageItemView = ({
3320
3577
  }
3321
3578
  ) }, `confirmation-card-${index3}`);
3322
3579
  case "result_summary":
3323
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ResultSummaryCard, { summary: block.summary }) }, `result-summary-${index3}`);
3580
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react10.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ResultSummaryCard, { summary: block.summary }) }, `result-summary-${index3}`);
3324
3581
  case "questionnaire":
3325
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3582
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react10.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3326
3583
  QuestionnaireCard,
3327
3584
  {
3328
3585
  questionnaire: block.questionnaire,
@@ -3334,7 +3591,10 @@ var ChatMessageItemView = ({
3334
3591
  submitFailed: labels.questionnaireSubmitFailed,
3335
3592
  multiSelectHint: labels.questionnaireMultiSelectHint,
3336
3593
  otherOptionLabel: labels.questionnaireOtherOptionLabel,
3337
- otherPlaceholder: labels.questionnaireOtherPlaceholder
3594
+ otherPlaceholder: labels.questionnaireOtherPlaceholder,
3595
+ expired: labels.questionnaireExpired,
3596
+ questionnaireTitle: labels.questionnaireTitle,
3597
+ questionnaireConfirmInTime: labels.questionnaireConfirmInTime
3338
3598
  },
3339
3599
  onSubmit: canSubmitQuestionnaire ? (submission) => onQuestionnaireSubmit({
3340
3600
  ...submission,
@@ -3343,7 +3603,7 @@ var ChatMessageItemView = ({
3343
3603
  }
3344
3604
  ) }, block.questionnaire.blockKey ?? `questionnaire-${index3}`);
3345
3605
  case "custom":
3346
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: renderMessageBlock?.({
3606
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react10.Fragment, { children: renderMessageBlock?.({
3347
3607
  block,
3348
3608
  index: index3,
3349
3609
  message,
@@ -3437,7 +3697,7 @@ var ChatMessageItemView = ({
3437
3697
  })();
3438
3698
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
3439
3699
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Bubble, { "data-role": message.role, "data-status": message.status ?? "done", children: [
3440
- shouldRenderHeader ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Header2, { children: [
3700
+ shouldRenderHeader ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Header3, { children: [
3441
3701
  isAssistantStreaming ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3442
3702
  StreamingIndicator,
3443
3703
  {
@@ -3462,7 +3722,7 @@ var ChatMessageItemView = ({
3462
3722
  ) : null,
3463
3723
  isStoppedAssistant ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StatusTag, { "data-testid": "chat-message-stopped-tag", children: labels.stoppedResponse }) : null
3464
3724
  ] }) : null,
3465
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Content, { "data-testid": "chat-message-content", children: [
3725
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Content2, { "data-testid": "chat-message-content", children: [
3466
3726
  skills.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SkillTagList, { "data-testid": "chat-message-skill-tags", children: skills.map((skill) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SkillTag, { children: skill }, skill)) }) : null,
3467
3727
  shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3468
3728
  ContentStack,
@@ -3510,7 +3770,7 @@ var ChatMessageItemView = ({
3510
3770
  ) : null
3511
3771
  ] });
3512
3772
  };
3513
- var ChatMessageItem = (0, import_react9.memo)(
3773
+ var ChatMessageItem = (0, import_react10.memo)(
3514
3774
  ChatMessageItemView,
3515
3775
  (previousProps, nextProps) => isSameMessage(
3516
3776
  previousProps.message,
@@ -3542,7 +3802,7 @@ var Bubble = import_styled7.default.article`
3542
3802
  border-radius: 16px;
3543
3803
  }
3544
3804
  `;
3545
- var Header2 = import_styled7.default.div`
3805
+ var Header3 = import_styled7.default.div`
3546
3806
  display: flex;
3547
3807
  align-items: center;
3548
3808
  gap: 10px;
@@ -3584,7 +3844,7 @@ var CollapseToggle = import_styled7.default.button`
3584
3844
  color: rgba(255, 255, 255, 0.92);
3585
3845
  }
3586
3846
  `;
3587
- var Content = import_styled7.default.div`
3847
+ var Content2 = import_styled7.default.div`
3588
3848
  color: rgba(255, 255, 255, 0.92);
3589
3849
  font-size: 14px;
3590
3850
  line-height: 1.6;
@@ -3728,7 +3988,7 @@ var AttachmentImage = import_styled7.default.img`
3728
3988
  var TableWrapper = import_styled7.default.div`
3729
3989
  overflow-x: auto;
3730
3990
  `;
3731
- var caretBlink = import_react10.keyframes`
3991
+ var caretBlink = import_react11.keyframes`
3732
3992
  0%, 49% {
3733
3993
  opacity: 1;
3734
3994
  }
@@ -3737,7 +3997,7 @@ var caretBlink = import_react10.keyframes`
3737
3997
  opacity: 0.2;
3738
3998
  }
3739
3999
  `;
3740
- var shimmer = import_react10.keyframes`
4000
+ var shimmer = import_react11.keyframes`
3741
4001
  0%, 100% {
3742
4002
  transform: scale(0.9) rotate(0deg);
3743
4003
  opacity: 0.55;
@@ -3956,24 +4216,24 @@ var ChatThreadView = ({
3956
4216
  onQuestionnaireSubmit,
3957
4217
  renderMessageBlock
3958
4218
  }) => {
3959
- const containerRef = (0, import_react11.useRef)(null);
3960
- const conversationTurns = (0, import_react11.useMemo)(
4219
+ const containerRef = (0, import_react12.useRef)(null);
4220
+ const conversationTurns = (0, import_react12.useMemo)(
3961
4221
  () => groupConversationTurns(historyMessages, streamingMessage),
3962
4222
  [historyMessages, streamingMessage]
3963
4223
  );
3964
4224
  const latestTurn = conversationTurns[conversationTurns.length - 1];
3965
4225
  const latestUserMessageId = latestTurn?.userMessage?.id;
3966
4226
  const latestHistoryMessage = historyMessages[historyMessages.length - 1];
3967
- const latestTurnRef = (0, import_react11.useRef)(null);
3968
- const reservedSpaceFrameRef = (0, import_react11.useRef)(null);
3969
- const isLoadingPreviousRef = (0, import_react11.useRef)(false);
3970
- const isPinnedRef = (0, import_react11.useRef)(true);
3971
- const lastHistoryMessageIdRef = (0, import_react11.useRef)(latestHistoryMessage?.id);
3972
- const lastStreamingMessageIdRef = (0, import_react11.useRef)(streamingMessage?.id);
3973
- const [latestTurnMinHeight, setLatestTurnMinHeight] = (0, import_react11.useState)(0);
3974
- const [isDetached, setIsDetached] = (0, import_react11.useState)(false);
3975
- const [pendingNewMessageCount, setPendingNewMessageCount] = (0, import_react11.useState)(0);
3976
- const measureLatestTurnMinHeight = (0, import_react11.useCallback)(() => {
4227
+ const latestTurnRef = (0, import_react12.useRef)(null);
4228
+ const reservedSpaceFrameRef = (0, import_react12.useRef)(null);
4229
+ const isLoadingPreviousRef = (0, import_react12.useRef)(false);
4230
+ const isPinnedRef = (0, import_react12.useRef)(true);
4231
+ const lastHistoryMessageIdRef = (0, import_react12.useRef)(latestHistoryMessage?.id);
4232
+ const lastStreamingMessageIdRef = (0, import_react12.useRef)(streamingMessage?.id);
4233
+ const [latestTurnMinHeight, setLatestTurnMinHeight] = (0, import_react12.useState)(0);
4234
+ const [isDetached, setIsDetached] = (0, import_react12.useState)(false);
4235
+ const [pendingNewMessageCount, setPendingNewMessageCount] = (0, import_react12.useState)(0);
4236
+ const measureLatestTurnMinHeight = (0, import_react12.useCallback)(() => {
3977
4237
  const container = containerRef.current;
3978
4238
  if (!container)
3979
4239
  return;
@@ -3983,7 +4243,7 @@ var ChatThreadView = ({
3983
4243
  const nextMinHeight = Math.max(0, container.clientHeight - paddingTop - paddingBottom);
3984
4244
  setLatestTurnMinHeight((current) => current === nextMinHeight ? current : nextMinHeight);
3985
4245
  }, []);
3986
- const scrollToBottom = (0, import_react11.useCallback)((force = false) => {
4246
+ const scrollToBottom = (0, import_react12.useCallback)((force = false) => {
3987
4247
  const container = containerRef.current;
3988
4248
  if (!container)
3989
4249
  return false;
@@ -3999,12 +4259,12 @@ var ChatThreadView = ({
3999
4259
  }
4000
4260
  return true;
4001
4261
  }, []);
4002
- const markThreadPinned = (0, import_react11.useCallback)(() => {
4262
+ const markThreadPinned = (0, import_react12.useCallback)(() => {
4003
4263
  isPinnedRef.current = true;
4004
4264
  setIsDetached(false);
4005
4265
  setPendingNewMessageCount(0);
4006
4266
  }, []);
4007
- const scrollToBottomAndPin = (0, import_react11.useCallback)(
4267
+ const scrollToBottomAndPin = (0, import_react12.useCallback)(
4008
4268
  (force = false) => {
4009
4269
  const didScroll = scrollToBottom(force);
4010
4270
  if (!didScroll)
@@ -4013,7 +4273,7 @@ var ChatThreadView = ({
4013
4273
  },
4014
4274
  [markThreadPinned, scrollToBottom]
4015
4275
  );
4016
- const handleLoadPreviousMessages = (0, import_react11.useCallback)(async () => {
4276
+ const handleLoadPreviousMessages = (0, import_react12.useCallback)(async () => {
4017
4277
  const container = containerRef.current;
4018
4278
  if (!container || !onLoadPreviousMessages || isLoadingPreviousMessages) {
4019
4279
  return;
@@ -4038,7 +4298,7 @@ var ChatThreadView = ({
4038
4298
  nextContainer.scrollTop = nextContainer.scrollHeight - previousScrollHeight + previousScrollTop;
4039
4299
  });
4040
4300
  }, [isLoadingPreviousMessages, onLoadPreviousMessages]);
4041
- const handleContainerScroll = (0, import_react11.useCallback)(() => {
4301
+ const handleContainerScroll = (0, import_react12.useCallback)(() => {
4042
4302
  const container = containerRef.current;
4043
4303
  if (!container)
4044
4304
  return;
@@ -4052,7 +4312,7 @@ var ChatThreadView = ({
4052
4312
  setPendingNewMessageCount(0);
4053
4313
  }
4054
4314
  }, [handleLoadPreviousMessages, onLoadPreviousMessages]);
4055
- (0, import_react11.useLayoutEffect)(() => {
4315
+ (0, import_react12.useLayoutEffect)(() => {
4056
4316
  const nextHistoryMessageId = latestHistoryMessage?.id;
4057
4317
  if (lastHistoryMessageIdRef.current === nextHistoryMessageId) {
4058
4318
  return;
@@ -4076,7 +4336,7 @@ var ChatThreadView = ({
4076
4336
  });
4077
4337
  }
4078
4338
  }, [latestHistoryMessage, markThreadPinned, scrollToBottom]);
4079
- (0, import_react11.useLayoutEffect)(() => {
4339
+ (0, import_react12.useLayoutEffect)(() => {
4080
4340
  const nextStreamingMessageId = streamingMessage?.id;
4081
4341
  if (lastStreamingMessageIdRef.current === nextStreamingMessageId) {
4082
4342
  return;
@@ -4091,7 +4351,7 @@ var ChatThreadView = ({
4091
4351
  });
4092
4352
  }
4093
4353
  }, [streamingMessage]);
4094
- (0, import_react11.useLayoutEffect)(() => {
4354
+ (0, import_react12.useLayoutEffect)(() => {
4095
4355
  if (reservedSpaceFrameRef.current !== null) {
4096
4356
  window.cancelAnimationFrame(reservedSpaceFrameRef.current);
4097
4357
  reservedSpaceFrameRef.current = null;
@@ -4121,7 +4381,7 @@ var ChatThreadView = ({
4121
4381
  }
4122
4382
  };
4123
4383
  }, [latestTurn, latestUserMessageId, error2, measureLatestTurnMinHeight, scrollToBottom]);
4124
- (0, import_react11.useLayoutEffect)(() => {
4384
+ (0, import_react12.useLayoutEffect)(() => {
4125
4385
  if (!latestTurn)
4126
4386
  return;
4127
4387
  const handleResize = () => {
@@ -4147,7 +4407,7 @@ var ChatThreadView = ({
4147
4407
  window.removeEventListener("resize", handleResize);
4148
4408
  };
4149
4409
  }, [latestTurn, latestUserMessageId, measureLatestTurnMinHeight, scrollToBottom]);
4150
- (0, import_react11.useLayoutEffect)(() => {
4410
+ (0, import_react12.useLayoutEffect)(() => {
4151
4411
  const latestTurnElement = latestTurnRef.current;
4152
4412
  if (!latestTurnElement || typeof ResizeObserver === "undefined") {
4153
4413
  return;
@@ -4160,7 +4420,7 @@ var ChatThreadView = ({
4160
4420
  observer.disconnect();
4161
4421
  };
4162
4422
  }, [latestTurn, scrollToBottom]);
4163
- (0, import_react11.useLayoutEffect)(() => {
4423
+ (0, import_react12.useLayoutEffect)(() => {
4164
4424
  const latestTurnElement = latestTurnRef.current;
4165
4425
  if (!latestTurnElement || typeof MutationObserver === "undefined") {
4166
4426
  return;
@@ -4267,13 +4527,13 @@ var ChatThread = () => {
4267
4527
  onLoadMoreHistoryMessages,
4268
4528
  labels
4269
4529
  } = useChatContext();
4270
- const handleRetry = (0, import_react11.useCallback)(() => {
4530
+ const handleRetry = (0, import_react12.useCallback)(() => {
4271
4531
  if (!activeSessionId)
4272
4532
  return;
4273
4533
  clearSessionError(activeSessionId);
4274
4534
  void retryRef.current(activeSessionId);
4275
4535
  }, [activeSessionId, clearSessionError, retryRef]);
4276
- const handleQuestionnaireSubmit = (0, import_react11.useCallback)(
4536
+ const handleQuestionnaireSubmit = (0, import_react12.useCallback)(
4277
4537
  async (submission) => {
4278
4538
  const sourceSessionId = activeSessionId;
4279
4539
  if (customQuestionnaireSubmit) {
@@ -4308,7 +4568,7 @@ var ChatThread = () => {
4308
4568
  },
4309
4569
  [activeSessionId, customQuestionnaireSubmit, preferredMode, sendRef, updateQA]
4310
4570
  );
4311
- const handleConfirmation = (0, import_react11.useCallback)(
4571
+ const handleConfirmation = (0, import_react12.useCallback)(
4312
4572
  async (submission) => {
4313
4573
  const sourceSessionId = activeSessionId;
4314
4574
  if (customConfirmationSubmit) {
@@ -4327,7 +4587,7 @@ var ChatThread = () => {
4327
4587
  },
4328
4588
  [activeSessionId, customConfirmationSubmit, preferredMode, sendRef]
4329
4589
  );
4330
- const handleLoadPreviousMessages = (0, import_react11.useCallback)(async () => {
4590
+ const handleLoadPreviousMessages = (0, import_react12.useCallback)(async () => {
4331
4591
  if (!activeSession || !onLoadMoreHistoryMessages || !historyMessagePagination?.hasMorePrevious || !historyMessagePagination.previousCursor || historyMessagePagination.isLoadingPrevious) {
4332
4592
  return;
4333
4593
  }
@@ -4366,13 +4626,14 @@ var ChatThread = () => {
4366
4626
  if (!hasSessions || messages.length === 0 && !streamingMessage) {
4367
4627
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChatThreadEmptyState, {});
4368
4628
  }
4629
+ 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;
4369
4630
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4370
4631
  ChatThreadView,
4371
4632
  {
4372
4633
  activeMode: preferredMode,
4373
4634
  historyMessages: messages,
4374
4635
  streamingMessage,
4375
- error: error2,
4636
+ error: displayError,
4376
4637
  isLoadingPreviousMessages: historyMessagePagination?.isLoadingPrevious,
4377
4638
  previousMessagesError: historyMessagePagination?.error,
4378
4639
  retryButtonLabel: labels.retryButton,
@@ -4521,7 +4782,7 @@ var ScrollToLatestBadge = import_styled9.default.span`
4521
4782
  `;
4522
4783
 
4523
4784
  // src/components/chat-composer/index.tsx
4524
- var import_react17 = require("react");
4785
+ var import_react18 = require("react");
4525
4786
  var import_styled14 = __toESM(require("@emotion/styled"));
4526
4787
 
4527
4788
  // ../../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
@@ -4683,7 +4944,7 @@ function getFrameElement(win) {
4683
4944
 
4684
4945
  // ../../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.utils.mjs
4685
4946
  var React = __toESM(require("react"), 1);
4686
- var import_react12 = require("react");
4947
+ var import_react13 = require("react");
4687
4948
 
4688
4949
  // ../../node_modules/.pnpm/@floating-ui+utils@0.2.10/node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs
4689
4950
  var min = Math.min;
@@ -5170,7 +5431,7 @@ function getDocument(node) {
5170
5431
  var isClient = typeof document !== "undefined";
5171
5432
  var noop = function noop2() {
5172
5433
  };
5173
- var index = isClient ? import_react12.useLayoutEffect : noop;
5434
+ var index = isClient ? import_react13.useLayoutEffect : noop;
5174
5435
  var SafeReact = {
5175
5436
  ...React
5176
5437
  };
@@ -6379,12 +6640,12 @@ var computePosition2 = (reference, floating, options) => {
6379
6640
 
6380
6641
  // ../../node_modules/.pnpm/@floating-ui+react-dom@2.1.6_react-dom@18.3.1_react@18.3.1/node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.mjs
6381
6642
  var React2 = __toESM(require("react"), 1);
6382
- var import_react13 = require("react");
6643
+ var import_react14 = require("react");
6383
6644
  var ReactDOM = __toESM(require("react-dom"), 1);
6384
6645
  var isClient2 = typeof document !== "undefined";
6385
6646
  var noop3 = function noop4() {
6386
6647
  };
6387
- var index2 = isClient2 ? import_react13.useLayoutEffect : noop3;
6648
+ var index2 = isClient2 ? import_react14.useLayoutEffect : noop3;
6388
6649
  function deepEqual(a, b) {
6389
6650
  if (a === b) {
6390
6651
  return true;
@@ -7119,10 +7380,10 @@ var resolveSendSession = ({
7119
7380
  };
7120
7381
 
7121
7382
  // src/components/chat-composer/hooks/use-chat-composer.ts
7122
- var import_react15 = require("react");
7383
+ var import_react16 = require("react");
7123
7384
 
7124
7385
  // src/components/chat-composer/hooks/use-composer-attachments.ts
7125
- var import_react14 = require("react");
7386
+ var import_react15 = require("react");
7126
7387
  var SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
7127
7388
  var MAX_COMPOSER_ATTACHMENTS = 10;
7128
7389
  var createObjectUrl = (file) => typeof URL !== "undefined" && typeof URL.createObjectURL === "function" ? URL.createObjectURL(file) : "";
@@ -7136,12 +7397,12 @@ var releaseComposerAttachments = (attachments) => {
7136
7397
  attachments.forEach((attachment) => revokeObjectUrl(attachment.previewUrl));
7137
7398
  };
7138
7399
  var useComposerAttachments = () => {
7139
- const [attachments, setAttachments] = (0, import_react14.useState)([]);
7140
- const attachmentsRef = (0, import_react14.useRef)([]);
7141
- (0, import_react14.useEffect)(() => {
7400
+ const [attachments, setAttachments] = (0, import_react15.useState)([]);
7401
+ const attachmentsRef = (0, import_react15.useRef)([]);
7402
+ (0, import_react15.useEffect)(() => {
7142
7403
  attachmentsRef.current = attachments;
7143
7404
  }, [attachments]);
7144
- (0, import_react14.useEffect)(
7405
+ (0, import_react15.useEffect)(
7145
7406
  () => () => {
7146
7407
  releaseComposerAttachments(attachmentsRef.current);
7147
7408
  },
@@ -7267,7 +7528,7 @@ var useChatComposer = () => {
7267
7528
  const { transport, enableImageAttachments, labels, store } = useChatContext();
7268
7529
  const modelsLoader = transport.getModels;
7269
7530
  const skillsLoader = transport.getSkills;
7270
- const activeSkillsLoaderRef = (0, import_react15.useRef)(skillsLoader);
7531
+ const activeSkillsLoaderRef = (0, import_react16.useRef)(skillsLoader);
7271
7532
  const activeSessionId = useChatStore((s) => s.activeSessionId);
7272
7533
  const preferredMode = useChatStore((s) => s.preferredMode);
7273
7534
  const streamingSessionId = useChatStore(
@@ -7289,16 +7550,16 @@ var useChatComposer = () => {
7289
7550
  const setSessionError = useChatStore((s) => s.setSessionError);
7290
7551
  const clearSessionError = useChatStore((s) => s.clearSessionError);
7291
7552
  const setPreferredMode = useChatStore((s) => s.setPreferredMode);
7292
- const [availableModels, setAvailableModels] = (0, import_react15.useState)([]);
7293
- const [isModelsLoading, setIsModelsLoading] = (0, import_react15.useState)(true);
7294
- const [isModelsError, setIsModelsError] = (0, import_react15.useState)(false);
7295
- const [availableSkills, setAvailableSkills] = (0, import_react15.useState)(
7553
+ const [availableModels, setAvailableModels] = (0, import_react16.useState)([]);
7554
+ const [isModelsLoading, setIsModelsLoading] = (0, import_react16.useState)(true);
7555
+ const [isModelsError, setIsModelsError] = (0, import_react16.useState)(false);
7556
+ const [availableSkills, setAvailableSkills] = (0, import_react16.useState)(
7296
7557
  () => getCachedSkills(skillsLoader).skills
7297
7558
  );
7298
- const [isSkillsLoading, setIsSkillsLoading] = (0, import_react15.useState)(
7559
+ const [isSkillsLoading, setIsSkillsLoading] = (0, import_react16.useState)(
7299
7560
  () => Boolean(skillsLoader) && !getCachedSkills(skillsLoader).resolved
7300
7561
  );
7301
- const fetchModels = (0, import_react15.useCallback)(async () => {
7562
+ const fetchModels = (0, import_react16.useCallback)(async () => {
7302
7563
  setIsModelsLoading(true);
7303
7564
  setIsModelsError(false);
7304
7565
  try {
@@ -7310,16 +7571,16 @@ var useChatComposer = () => {
7310
7571
  setIsModelsLoading(false);
7311
7572
  }
7312
7573
  }, [modelsLoader]);
7313
- (0, import_react15.useEffect)(() => {
7574
+ (0, import_react16.useEffect)(() => {
7314
7575
  void fetchModels();
7315
7576
  }, [fetchModels]);
7316
- (0, import_react15.useEffect)(() => {
7577
+ (0, import_react16.useEffect)(() => {
7317
7578
  activeSkillsLoaderRef.current = skillsLoader;
7318
7579
  const cachedSkills = getCachedSkills(skillsLoader);
7319
7580
  setAvailableSkills(cachedSkills.skills);
7320
7581
  setIsSkillsLoading(Boolean(skillsLoader) && !cachedSkills.resolved);
7321
7582
  }, [skillsLoader]);
7322
- const fetchSkills = (0, import_react15.useCallback)(async () => {
7583
+ const fetchSkills = (0, import_react16.useCallback)(async () => {
7323
7584
  if (!skillsLoader) {
7324
7585
  setAvailableSkills([]);
7325
7586
  setIsSkillsLoading(false);
@@ -7349,35 +7610,35 @@ var useChatComposer = () => {
7349
7610
  }
7350
7611
  }
7351
7612
  }, [skillsLoader]);
7352
- (0, import_react15.useEffect)(() => {
7613
+ (0, import_react16.useEffect)(() => {
7353
7614
  void fetchSkills();
7354
7615
  }, [fetchSkills]);
7355
7616
  const hasModels = availableModels.length > 0;
7356
- const [value, setValue] = (0, import_react15.useState)("");
7357
- const [selectedModel, setSelectedModel] = (0, import_react15.useState)("");
7358
- const [selectedMode, setSelectedModeLocal] = (0, import_react15.useState)(DEFAULT_CHAT_AGENT_MODE);
7359
- const [selectedSkills, setSelectedSkills] = (0, import_react15.useState)([]);
7360
- const [attachmentNotice, setAttachmentNotice] = (0, import_react15.useState)(null);
7617
+ const [value, setValue] = (0, import_react16.useState)("");
7618
+ const [selectedModel, setSelectedModel] = (0, import_react16.useState)("");
7619
+ const [selectedMode, setSelectedModeLocal] = (0, import_react16.useState)(DEFAULT_CHAT_AGENT_MODE);
7620
+ const [selectedSkills, setSelectedSkills] = (0, import_react16.useState)([]);
7621
+ const [attachmentNotice, setAttachmentNotice] = (0, import_react16.useState)(null);
7361
7622
  const { attachments, appendFiles, removeAttachment, takeMessageAttachments } = useComposerAttachments();
7362
- const abortControllerBySessionRef = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
7363
- const stopRequestBySessionRef = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
7364
- const lastRequestBySessionRef = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
7365
- const previousActiveSessionIdRef = (0, import_react15.useRef)(activeSessionId);
7366
- (0, import_react15.useEffect)(() => {
7623
+ const abortControllerBySessionRef = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
7624
+ const stopRequestBySessionRef = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
7625
+ const lastRequestBySessionRef = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
7626
+ const previousActiveSessionIdRef = (0, import_react16.useRef)(activeSessionId);
7627
+ (0, import_react16.useEffect)(() => {
7367
7628
  setSelectedModel(
7368
7629
  (current) => resolveSelectedChatModel({ currentModel: current, availableModels, isModelsLoading })
7369
7630
  );
7370
7631
  }, [availableModels, isModelsLoading]);
7371
- (0, import_react15.useEffect)(() => {
7632
+ (0, import_react16.useEffect)(() => {
7372
7633
  setSelectedModeLocal(preferredMode ?? DEFAULT_CHAT_AGENT_MODE);
7373
7634
  }, [preferredMode]);
7374
- (0, import_react15.useEffect)(() => {
7635
+ (0, import_react16.useEffect)(() => {
7375
7636
  if (previousActiveSessionIdRef.current !== activeSessionId) {
7376
7637
  setSelectedSkills([]);
7377
7638
  previousActiveSessionIdRef.current = activeSessionId;
7378
7639
  }
7379
7640
  }, [activeSessionId]);
7380
- (0, import_react15.useEffect)(() => {
7641
+ (0, import_react16.useEffect)(() => {
7381
7642
  if (!attachmentNotice)
7382
7643
  return;
7383
7644
  const timeoutId = window.setTimeout(
@@ -7394,11 +7655,11 @@ var useChatComposer = () => {
7394
7655
  window.clearTimeout(stopRequest.timeoutId);
7395
7656
  stopRequest.timeoutId = null;
7396
7657
  };
7397
- const clearStopRequest = (0, import_react15.useCallback)((sessionId) => {
7658
+ const clearStopRequest = (0, import_react16.useCallback)((sessionId) => {
7398
7659
  clearStopTimeout(sessionId);
7399
7660
  stopRequestBySessionRef.current.delete(sessionId);
7400
7661
  }, []);
7401
- const moveSessionRuntimeState = (0, import_react15.useCallback)(
7662
+ const moveSessionRuntimeState = (0, import_react16.useCallback)(
7402
7663
  (previousSessionId, nextSessionId) => {
7403
7664
  if (previousSessionId === nextSessionId) {
7404
7665
  return;
@@ -7416,7 +7677,7 @@ var useChatComposer = () => {
7416
7677
  },
7417
7678
  []
7418
7679
  );
7419
- const finalizeStop = (0, import_react15.useCallback)(
7680
+ const finalizeStop = (0, import_react16.useCallback)(
7420
7681
  (sessionId) => {
7421
7682
  const stopRequest = stopRequestBySessionRef.current.get(sessionId);
7422
7683
  if (stopRequest) {
@@ -7433,7 +7694,7 @@ var useChatComposer = () => {
7433
7694
  },
7434
7695
  [clearStopRequest, finalizeStoppedStreamingMessage]
7435
7696
  );
7436
- const runStream = (0, import_react15.useCallback)(
7697
+ const runStream = (0, import_react16.useCallback)(
7437
7698
  async ({
7438
7699
  localSessionId,
7439
7700
  sessionId,
@@ -7558,7 +7819,7 @@ var useChatComposer = () => {
7558
7819
  store
7559
7820
  ]
7560
7821
  );
7561
- const send = (0, import_react15.useCallback)(
7822
+ const send = (0, import_react16.useCallback)(
7562
7823
  async (contentOverride, options) => {
7563
7824
  const content = (contentOverride ?? value).trim();
7564
7825
  const includeComposerAttachments = options?.includeComposerAttachments ?? true;
@@ -7638,7 +7899,7 @@ var useChatComposer = () => {
7638
7899
  store
7639
7900
  ]
7640
7901
  );
7641
- const openSkillPicker = (0, import_react15.useCallback)(() => {
7902
+ const openSkillPicker = (0, import_react16.useCallback)(() => {
7642
7903
  setValue((current) => {
7643
7904
  const matchedSkillQuery = current.match(/(^|\s)\/([^\s/]*)$/);
7644
7905
  if (matchedSkillQuery && matchedSkillQuery.index !== void 0) {
@@ -7651,7 +7912,7 @@ var useChatComposer = () => {
7651
7912
  return /\s$/.test(current) ? `${current}/` : `${current} /`;
7652
7913
  });
7653
7914
  }, []);
7654
- const stopSession = (0, import_react15.useCallback)(
7915
+ const stopSession = (0, import_react16.useCallback)(
7655
7916
  async (sessionId) => {
7656
7917
  const storeState = store.getState();
7657
7918
  const isSessionStreaming = storeState.isStreamingBySession[sessionId] ?? false;
@@ -7761,14 +8022,14 @@ var useChatComposer = () => {
7761
8022
  };
7762
8023
 
7763
8024
  // src/components/chat-composer/components/chat-composer-attachment-list.tsx
7764
- var import_react16 = require("react");
8025
+ var import_react17 = require("react");
7765
8026
  var import_styled10 = __toESM(require("@emotion/styled"));
7766
8027
  var import_jsx_runtime12 = require("@emotion/react/jsx-runtime");
7767
8028
  var ChatComposerAttachmentList = ({
7768
8029
  attachments,
7769
8030
  onRemoveAttachment
7770
8031
  }) => {
7771
- const [activeImage, setActiveImage] = (0, import_react16.useState)(null);
8032
+ const [activeImage, setActiveImage] = (0, import_react17.useState)(null);
7772
8033
  if (!attachments.length) {
7773
8034
  return null;
7774
8035
  }
@@ -8434,6 +8695,7 @@ var ChatComposerView = ({
8434
8695
  modelLoadingLabel,
8435
8696
  modelLoadFailedLabel,
8436
8697
  modelUnavailableLabel,
8698
+ modeAccessory,
8437
8699
  onValueChange,
8438
8700
  onPickImages,
8439
8701
  onPasteImages,
@@ -8447,11 +8709,11 @@ var ChatComposerView = ({
8447
8709
  onStop,
8448
8710
  onSend
8449
8711
  }) => {
8450
- const imageInputRef = (0, import_react17.useRef)(null);
8451
- const inputRef = (0, import_react17.useRef)(null);
8452
- const [isComposerExpandable, setIsComposerExpandable] = (0, import_react17.useState)(false);
8453
- const [isComposerExpanded, setIsComposerExpanded] = (0, import_react17.useState)(false);
8454
- const [activeSkillNavigation, setActiveSkillNavigation] = (0, import_react17.useState)({
8712
+ const imageInputRef = (0, import_react18.useRef)(null);
8713
+ const inputRef = (0, import_react18.useRef)(null);
8714
+ const [isComposerExpandable, setIsComposerExpandable] = (0, import_react18.useState)(false);
8715
+ const [isComposerExpanded, setIsComposerExpanded] = (0, import_react18.useState)(false);
8716
+ const [activeSkillNavigation, setActiveSkillNavigation] = (0, import_react18.useState)({
8455
8717
  queryKey: "",
8456
8718
  index: 0
8457
8719
  });
@@ -8494,20 +8756,20 @@ var ChatComposerView = ({
8494
8756
  ],
8495
8757
  whileElementsMounted: autoUpdate
8496
8758
  });
8497
- const setSkillMenuReference = (0, import_react17.useCallback)(
8759
+ const setSkillMenuReference = (0, import_react18.useCallback)(
8498
8760
  (element) => {
8499
8761
  refs.setReference(element);
8500
8762
  },
8501
8763
  [refs]
8502
8764
  );
8503
- const setSkillMenuFloating = (0, import_react17.useCallback)(
8765
+ const setSkillMenuFloating = (0, import_react18.useCallback)(
8504
8766
  (element) => {
8505
8767
  refs.setFloating(element);
8506
8768
  },
8507
8769
  [refs]
8508
8770
  );
8509
8771
  const activeSkillIndex = activeSkillNavigation.queryKey === activeSkillQueryKey ? activeSkillNavigation.index : 0;
8510
- (0, import_react17.useLayoutEffect)(() => {
8772
+ (0, import_react18.useLayoutEffect)(() => {
8511
8773
  const element = inputRef.current;
8512
8774
  if (!element) {
8513
8775
  return;
@@ -8657,7 +8919,7 @@ var ChatComposerView = ({
8657
8919
  }
8658
8920
  )
8659
8921
  ] }),
8660
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Footer, { children: [
8922
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Footer2, { children: [
8661
8923
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(LeadingActions, { "data-testid": "chat-composer-leading-actions", children: [
8662
8924
  enableImageAttachments ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8663
8925
  AttachButton,
@@ -8687,7 +8949,8 @@ var ChatComposerView = ({
8687
8949
  labels: modeLabels,
8688
8950
  onChange: onSelectedModeChange
8689
8951
  }
8690
- )
8952
+ ),
8953
+ modeAccessory
8691
8954
  ] }),
8692
8955
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(TrailingActions, { "data-testid": "chat-composer-trailing-actions", children: [
8693
8956
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -8745,22 +9008,35 @@ var ChatComposerView = ({
8745
9008
  ) }) : null
8746
9009
  ] });
8747
9010
  };
8748
- var ChatComposer = () => {
8749
- const { labels, sendRef, retryRef, stopRef, enableImageAttachments } = useChatContext();
9011
+ var ChatComposer = ({
9012
+ renderModeAccessory
9013
+ } = {}) => {
9014
+ const {
9015
+ labels,
9016
+ sendRef,
9017
+ retryRef,
9018
+ registerStopSession = () => {
9019
+ },
9020
+ enableImageAttachments
9021
+ } = useChatContext();
8750
9022
  const { state, actions } = useChatComposer();
8751
9023
  const { send, retry } = actions;
8752
- (0, import_react17.useEffect)(() => {
9024
+ (0, import_react18.useEffect)(() => {
8753
9025
  sendRef.current = send;
8754
9026
  retryRef.current = async (sessionId) => {
8755
9027
  retry(sessionId);
8756
9028
  };
8757
- stopRef.current = actions.stopSession;
8758
- }, [actions.stopSession, retry, retryRef, send, sendRef, stopRef]);
9029
+ registerStopSession(actions.stopSession);
9030
+ }, [actions.stopSession, registerStopSession, retry, retryRef, send, sendRef]);
8759
9031
  const modeLabels = {
8760
9032
  ask: labels.modeLabelAsk,
8761
9033
  plan: labels.modeLabelPlan,
8762
9034
  agent: labels.modeLabelAgent
8763
9035
  };
9036
+ const modeAccessory = renderModeAccessory?.({
9037
+ selectedMode: state.selectedMode,
9038
+ disabled: state.isStreaming
9039
+ });
8764
9040
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8765
9041
  ChatComposerView,
8766
9042
  {
@@ -8790,6 +9066,7 @@ var ChatComposer = () => {
8790
9066
  modelLoadingLabel: labels.modelLoading,
8791
9067
  modelLoadFailedLabel: labels.modelLoadFailed,
8792
9068
  modelUnavailableLabel: labels.modelUnavailable,
9069
+ modeAccessory,
8793
9070
  onValueChange: actions.setValue,
8794
9071
  onPickImages: actions.pickImages,
8795
9072
  onPasteImages: actions.pasteImages,
@@ -8997,7 +9274,7 @@ var ComposerExpandButton = import_styled14.default.button`
8997
9274
  color: rgba(255, 255, 255, 0.92);
8998
9275
  }
8999
9276
  `;
9000
- var Footer = import_styled14.default.div`
9277
+ var Footer2 = import_styled14.default.div`
9001
9278
  grid-area: footer;
9002
9279
  display: flex;
9003
9280
  align-items: center;
@@ -9078,26 +9355,37 @@ var SkillButton = import_styled14.default.button`
9078
9355
  `;
9079
9356
 
9080
9357
  // src/components/chat-conversation-list/index.tsx
9081
- var import_react20 = require("react");
9358
+ var import_react21 = require("react");
9082
9359
  var import_styled16 = __toESM(require("@emotion/styled"));
9083
9360
 
9084
9361
  // src/components/chat-conversation-list/components/chat-session-item.tsx
9085
- var import_react19 = require("react");
9362
+ var import_react20 = require("react");
9086
9363
  var import_styled15 = __toESM(require("@emotion/styled"));
9087
9364
  var import_jsx_runtime17 = require("@emotion/react/jsx-runtime");
9088
- var ChatSessionItem = (0, import_react19.memo)(({ session, isActive, onClick }) => {
9089
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9090
- SessionButton,
9091
- {
9092
- type: "button",
9093
- "data-active": isActive,
9094
- "data-testid": `chat-session-item-${session.sessionId}`,
9095
- onClick: () => onClick(session.sessionId),
9096
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SessionTitle, { children: session.title })
9097
- }
9098
- );
9099
- });
9365
+ var ChatSessionItem = (0, import_react20.memo)(
9366
+ ({ session, isActive, onClick, actions }) => {
9367
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(SessionRow, { "data-active": isActive, children: [
9368
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9369
+ SessionButton,
9370
+ {
9371
+ type: "button",
9372
+ "data-active": isActive,
9373
+ "data-testid": `chat-session-item-${session.sessionId}`,
9374
+ onClick: () => onClick(session.sessionId),
9375
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SessionTitle, { children: session.title })
9376
+ }
9377
+ ),
9378
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SessionActions, { "data-testid": `chat-session-item-actions-${session.sessionId}`, children: actions }) : null
9379
+ ] });
9380
+ }
9381
+ );
9100
9382
  ChatSessionItem.displayName = "ChatSessionItem";
9383
+ var SessionRow = import_styled15.default.div`
9384
+ display: flex;
9385
+ align-items: center;
9386
+ gap: 8px;
9387
+ min-width: 0;
9388
+ `;
9101
9389
  var SessionTitle = import_styled15.default.span`
9102
9390
  display: block;
9103
9391
  min-width: 0;
@@ -9106,6 +9394,8 @@ var SessionTitle = import_styled15.default.span`
9106
9394
  white-space: nowrap;
9107
9395
  `;
9108
9396
  var SessionButton = import_styled15.default.button`
9397
+ flex: 1;
9398
+ min-width: 0;
9109
9399
  border: 1px solid transparent;
9110
9400
  border-radius: 12px;
9111
9401
  padding: 12px;
@@ -9138,6 +9428,12 @@ var SessionButton = import_styled15.default.button`
9138
9428
  background: rgba(255, 255, 255, 0.08);
9139
9429
  }
9140
9430
  `;
9431
+ var SessionActions = import_styled15.default.div`
9432
+ display: flex;
9433
+ align-items: center;
9434
+ gap: 6px;
9435
+ flex: 0 0 auto;
9436
+ `;
9141
9437
 
9142
9438
  // src/components/chat-conversation-list/lib/history-session-selection.ts
9143
9439
  var shouldLoadHistorySessionMessages = ({
@@ -9167,26 +9463,52 @@ var shouldLoadMoreSessions = ({
9167
9463
  threshold = SCROLL_LOAD_MORE_THRESHOLD_PX
9168
9464
  }) => scrollHeight - scrollTop - clientHeight <= threshold;
9169
9465
  var isHistorySessionMessagesPage = (value) => typeof value === "object" && value !== null && Array.isArray(value.messages);
9466
+ var matchesHydratedHistorySessions = (renderedHistorySessionIds, historySessionIds) => {
9467
+ if (renderedHistorySessionIds.length === historySessionIds.length) {
9468
+ return renderedHistorySessionIds.every(
9469
+ (sessionId, index3) => sessionId === historySessionIds[index3]
9470
+ );
9471
+ }
9472
+ if (renderedHistorySessionIds.length !== historySessionIds.length + 1) {
9473
+ return false;
9474
+ }
9475
+ const matchesWithoutLeadingExtra = renderedHistorySessionIds.slice(1).every((sessionId, index3) => sessionId === historySessionIds[index3]);
9476
+ if (matchesWithoutLeadingExtra) {
9477
+ return true;
9478
+ }
9479
+ return renderedHistorySessionIds.slice(0, -1).every((sessionId, index3) => sessionId === historySessionIds[index3]);
9480
+ };
9170
9481
  var ChatConversationList = () => {
9171
- const { labels, historySessionList, onLoadMoreSessions, onSelectHistorySession, store } = useChatContext();
9482
+ const {
9483
+ labels,
9484
+ historySessionList,
9485
+ onLoadMoreSessions,
9486
+ onSelectHistorySession,
9487
+ renderSessionItemActions,
9488
+ stopSession = async (_sessionId) => {
9489
+ },
9490
+ store
9491
+ } = useChatContext();
9172
9492
  const localSessions = useChatStore((s) => s.sessions);
9173
9493
  const activeSessionId = useChatStore((s) => s.activeSessionId);
9174
9494
  const startNewChat = useChatStore((s) => s.startNewChat);
9175
9495
  const setActiveSession = useChatStore((s) => s.setActiveSession);
9496
+ const isStreamingBySession = useChatStore((s) => s.isStreamingBySession);
9176
9497
  const hydrateHistorySessions = useChatStore((s) => s.hydrateHistorySessions);
9177
9498
  const hydrateHistorySessionMessages = useChatStore((s) => s.hydrateHistorySessionMessages);
9178
9499
  const hydrateHistorySessionMessagesPage = useChatStore((s) => s.hydrateHistorySessionMessagesPage);
9179
9500
  const setHistorySessionMessageLoadStatus = useChatStore(
9180
9501
  (s) => s.setHistorySessionMessageLoadStatus
9181
9502
  );
9182
- const isLoadingMoreRef = (0, import_react20.useRef)(false);
9183
- const hasSeenLoadingMoreRef = (0, import_react20.useRef)(false);
9184
- (0, import_react20.useEffect)(() => {
9503
+ const isLoadingMoreRef = (0, import_react21.useRef)(false);
9504
+ const hasSeenLoadingMoreRef = (0, import_react21.useRef)(false);
9505
+ const listRef = (0, import_react21.useRef)(null);
9506
+ (0, import_react21.useEffect)(() => {
9185
9507
  if (!historySessionList)
9186
9508
  return;
9187
9509
  hydrateHistorySessions(historySessionList.sessions);
9188
9510
  }, [historySessionList, hydrateHistorySessions]);
9189
- (0, import_react20.useEffect)(() => {
9511
+ (0, import_react21.useEffect)(() => {
9190
9512
  if (historySessionList?.isLoading) {
9191
9513
  hasSeenLoadingMoreRef.current = true;
9192
9514
  return;
@@ -9196,28 +9518,55 @@ var ChatConversationList = () => {
9196
9518
  isLoadingMoreRef.current = false;
9197
9519
  }
9198
9520
  }, [historySessionList?.isLoading]);
9199
- (0, import_react20.useEffect)(() => {
9521
+ (0, import_react21.useEffect)(() => {
9200
9522
  isLoadingMoreRef.current = false;
9201
9523
  hasSeenLoadingMoreRef.current = false;
9202
9524
  }, [historySessionList?.sessions.length, historySessionList?.hasMore]);
9203
9525
  const sessions = localSessions;
9204
- const handleSessionListScroll = (event) => {
9205
- if (!historySessionList?.hasMore || historySessionList.isLoading || !onLoadMoreSessions || isLoadingMoreRef.current) {
9526
+ const hasMoreSessions = historySessionList?.hasMore ?? false;
9527
+ const isHistorySessionListLoading = historySessionList?.isLoading ?? false;
9528
+ const renderedHistorySessionIds = sessions.filter((session) => !isDraftChatSessionId(session.sessionId)).map((session) => session.sessionId);
9529
+ const isHistorySessionListHydrated = !historySessionList || matchesHydratedHistorySessions(
9530
+ renderedHistorySessionIds,
9531
+ historySessionList.sessions.map((session) => session.sessionId)
9532
+ );
9533
+ const requestLoadMoreSessions = (0, import_react21.useCallback)(() => {
9534
+ if (!hasMoreSessions || isHistorySessionListLoading || !onLoadMoreSessions || isLoadingMoreRef.current) {
9206
9535
  return;
9207
9536
  }
9208
- const target = event.currentTarget;
9209
- if (shouldLoadMoreSessions({
9210
- scrollTop: target.scrollTop,
9211
- clientHeight: target.clientHeight,
9212
- scrollHeight: target.scrollHeight
9213
- })) {
9214
- isLoadingMoreRef.current = true;
9215
- void Promise.resolve(onLoadMoreSessions()).catch(() => {
9216
- isLoadingMoreRef.current = false;
9217
- hasSeenLoadingMoreRef.current = false;
9218
- });
9537
+ isLoadingMoreRef.current = true;
9538
+ void Promise.resolve(onLoadMoreSessions()).catch(() => {
9539
+ isLoadingMoreRef.current = false;
9540
+ hasSeenLoadingMoreRef.current = false;
9541
+ });
9542
+ }, [hasMoreSessions, isHistorySessionListLoading, onLoadMoreSessions]);
9543
+ const maybeLoadMoreSessions = (0, import_react21.useCallback)(
9544
+ (target) => {
9545
+ if (target.clientHeight <= 0 || target.scrollHeight <= 0) {
9546
+ return;
9547
+ }
9548
+ if (shouldLoadMoreSessions({
9549
+ scrollTop: target.scrollTop,
9550
+ clientHeight: target.clientHeight,
9551
+ scrollHeight: target.scrollHeight
9552
+ })) {
9553
+ requestLoadMoreSessions();
9554
+ }
9555
+ },
9556
+ [requestLoadMoreSessions]
9557
+ );
9558
+ (0, import_react21.useEffect)(() => {
9559
+ if (!listRef.current || !isHistorySessionListHydrated) {
9560
+ return;
9219
9561
  }
9220
- };
9562
+ maybeLoadMoreSessions(listRef.current);
9563
+ }, [isHistorySessionListHydrated, hasMoreSessions, localSessions.length, maybeLoadMoreSessions]);
9564
+ const handleSessionListScroll = (0, import_react21.useCallback)(
9565
+ (event) => {
9566
+ maybeLoadMoreSessions(event.currentTarget);
9567
+ },
9568
+ [maybeLoadMoreSessions]
9569
+ );
9221
9570
  const handleSelectSession = async (sessionId) => {
9222
9571
  setActiveSession(sessionId);
9223
9572
  const session = sessions.find((item) => item.sessionId === sessionId);
@@ -9259,13 +9608,21 @@ var ChatConversationList = () => {
9259
9608
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Title3, { children: labels.sessionsTitle }),
9260
9609
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CreateButton, { type: "button", "data-testid": "chat-create-session", onClick: startNewChat, children: labels.newChat })
9261
9610
  ] }),
9262
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(List2, { "data-testid": "chat-session-list", onScroll: handleSessionListScroll, children: [
9611
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(List2, { ref: listRef, "data-testid": "chat-session-list", onScroll: handleSessionListScroll, children: [
9263
9612
  sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
9264
9613
  ChatSessionItem,
9265
9614
  {
9266
9615
  session,
9267
9616
  isActive: activeSessionId === session.sessionId,
9268
- onClick: (sessionId) => void handleSelectSession(sessionId)
9617
+ onClick: (sessionId) => void handleSelectSession(sessionId),
9618
+ actions: isDraftChatSessionId(session.sessionId) ? void 0 : renderSessionItemActions?.({
9619
+ session,
9620
+ isActive: activeSessionId === session.sessionId,
9621
+ isStreaming: isStreamingBySession[session.sessionId] ?? false,
9622
+ selectSession: () => handleSelectSession(session.sessionId),
9623
+ startNewChat,
9624
+ stopSession: () => stopSession(session.sessionId)
9625
+ })
9269
9626
  },
9270
9627
  session.sessionId
9271
9628
  )),
@@ -9278,6 +9635,7 @@ var ChatConversationList = () => {
9278
9635
  var Container3 = import_styled16.default.aside`
9279
9636
  width: 280px;
9280
9637
  min-width: 280px;
9638
+ min-height: 0;
9281
9639
  border-right: 1px solid var(--border-default, rgba(255, 255, 255, 0.08));
9282
9640
  display: flex;
9283
9641
  flex-direction: column;
@@ -9323,6 +9681,8 @@ var CreateButton = import_styled16.default.button`
9323
9681
  }
9324
9682
  `;
9325
9683
  var List2 = import_styled16.default.div`
9684
+ flex: 1 1 0;
9685
+ min-height: 0;
9326
9686
  padding: 0 12px 16px;
9327
9687
  display: flex;
9328
9688
  flex-direction: column;
@@ -9384,7 +9744,8 @@ var AiChatWorkspaceContent = ({
9384
9744
  showNewChatButton,
9385
9745
  renderNewChatTrigger,
9386
9746
  showComposerOnlyBeforeFirstMessage = false,
9387
- onConversationStartedChange
9747
+ onConversationStartedChange,
9748
+ renderComposerModeAccessory
9388
9749
  }) => {
9389
9750
  const isConversationStarted = useChatStore(
9390
9751
  (state) => hasStartedConversation({
@@ -9395,7 +9756,7 @@ var AiChatWorkspaceContent = ({
9395
9756
  })
9396
9757
  );
9397
9758
  const shouldShowComposerOnly = showComposerOnlyBeforeFirstMessage && !showConversationList && !isConversationStarted;
9398
- (0, import_react21.useEffect)(() => {
9759
+ (0, import_react22.useEffect)(() => {
9399
9760
  onConversationStartedChange?.(isConversationStarted);
9400
9761
  }, [isConversationStarted, onConversationStartedChange]);
9401
9762
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Root, { "data-testid": "ai-chat", children: [
@@ -9403,12 +9764,13 @@ var AiChatWorkspaceContent = ({
9403
9764
  /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Workspace, { children: [
9404
9765
  showNewChatButton && !showConversationList && !shouldShowComposerOnly ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(QuickActions, { renderNewChatTrigger }) : null,
9405
9766
  shouldShowComposerOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChatThread, {}),
9406
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChatComposer, {})
9767
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChatComposer, { renderModeAccessory: renderComposerModeAccessory })
9407
9768
  ] })
9408
9769
  ] });
9409
9770
  };
9410
9771
  var QuickActions = ({ renderNewChatTrigger }) => {
9411
- const { labels, stopRef, store } = useChatContext();
9772
+ const { labels, stopSession = async (_sessionId) => {
9773
+ }, store } = useChatContext();
9412
9774
  const startNewChat = useChatStore((state) => state.startNewChat);
9413
9775
  const activeSessionId = useChatStore((state) => state.activeSessionId);
9414
9776
  const isActiveSessionStreaming = useChatStore(
@@ -9427,14 +9789,14 @@ var QuickActions = ({ renderNewChatTrigger }) => {
9427
9789
  if (!currentSessionId || !isCurrentSessionStreaming) {
9428
9790
  return;
9429
9791
  }
9430
- await stopRef.current(currentSessionId);
9792
+ await stopSession(currentSessionId);
9431
9793
  };
9432
9794
  const handleStartNewChat = async () => {
9433
9795
  const currentState = store.getState();
9434
9796
  const currentSessionId = currentState.activeSessionId;
9435
9797
  const isCurrentSessionStreaming = currentSessionId ? currentState.isStreamingBySession[currentSessionId] ?? false : false;
9436
9798
  if (currentSessionId && isCurrentSessionStreaming) {
9437
- void stopRef.current(currentSessionId);
9799
+ void stopSession(currentSessionId);
9438
9800
  }
9439
9801
  createNewSession();
9440
9802
  };
@@ -9478,6 +9840,7 @@ var AiChat = ({
9478
9840
  renderNewChatTrigger,
9479
9841
  showComposerOnlyBeforeFirstMessage = false,
9480
9842
  onConversationStartedChange,
9843
+ renderComposerModeAccessory,
9481
9844
  ...providerProps
9482
9845
  }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
9483
9846
  import_compass_ui4.ConfigProvider,
@@ -9521,7 +9884,8 @@ var AiChat = ({
9521
9884
  showNewChatButton,
9522
9885
  renderNewChatTrigger,
9523
9886
  showComposerOnlyBeforeFirstMessage,
9524
- onConversationStartedChange
9887
+ onConversationStartedChange,
9888
+ renderComposerModeAccessory
9525
9889
  }
9526
9890
  ) })
9527
9891
  }