@xinghunm/ai-chat 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ __export(src_exports, {
33
33
  AiChat: () => AiChat,
34
34
  AiChatProvider: () => AiChatProvider,
35
35
  CHAT_AGENT_MODES: () => CHAT_AGENT_MODES,
36
+ CHAT_MESSAGE_RENDER_ORDERS: () => CHAT_MESSAGE_RENDER_ORDERS,
36
37
  ChatComposer: () => ChatComposer,
37
38
  ChatConversationList: () => ChatConversationList,
38
39
  ChatThread: () => ChatThread,
@@ -62,6 +63,7 @@ var import_vanilla = require("zustand/vanilla");
62
63
  // src/types/index.ts
63
64
  var CHAT_AGENT_MODES = ["ask", "plan", "agent"];
64
65
  var DEFAULT_CHAT_AGENT_MODE = "agent";
66
+ var CHAT_MESSAGE_RENDER_ORDERS = ["blocks-first", "timeline"];
65
67
  var DEFAULT_AI_CHAT_LABELS = {
66
68
  sendButton: "Send",
67
69
  stopButton: "Stop",
@@ -563,7 +565,14 @@ var createDefaultChatTransport = ({
563
565
  // src/components/ai-chat-provider/index.tsx
564
566
  var import_jsx_runtime = require("@emotion/react/jsx-runtime");
565
567
  var AiChatProvider = (props) => {
566
- const { defaultMode, labels, renderMessageBlock, enableImageAttachments = true, children } = props;
568
+ const {
569
+ defaultMode,
570
+ labels,
571
+ renderMessageBlock,
572
+ messageRenderOrder,
573
+ enableImageAttachments = true,
574
+ children
575
+ } = props;
567
576
  const [store] = (0, import_react2.useState)(
568
577
  () => createChatStore(defaultMode ? { preferredMode: defaultMode } : void 0)
569
578
  );
@@ -615,6 +624,7 @@ var AiChatProvider = (props) => {
615
624
  sendRef,
616
625
  retryRef,
617
626
  renderMessageBlock,
627
+ messageRenderOrder,
618
628
  transformStreamPacket: defaultTransformStreamPacket,
619
629
  enableImageAttachments
620
630
  }),
@@ -625,6 +635,7 @@ var AiChatProvider = (props) => {
625
635
  defaultTransformStreamPacket,
626
636
  enableImageAttachments,
627
637
  labels,
638
+ messageRenderOrder,
628
639
  renderMessageBlock,
629
640
  sendRef,
630
641
  retryRef,
@@ -636,7 +647,7 @@ var AiChatProvider = (props) => {
636
647
  };
637
648
 
638
649
  // src/components/chat-thread/index.tsx
639
- var import_react10 = require("react");
650
+ var import_react11 = require("react");
640
651
  var import_styled9 = __toESM(require("@emotion/styled"));
641
652
 
642
653
  // src/context/use-chat-context.ts
@@ -657,9 +668,9 @@ var useChatStore = (selector) => {
657
668
  var CHAT_THREAD_SCROLL_TOP_GAP = 16;
658
669
 
659
670
  // src/components/chat-thread/components/chat-message-item.tsx
660
- var import_react8 = require("react");
671
+ var import_react9 = require("react");
661
672
  var import_styled7 = __toESM(require("@emotion/styled"));
662
- var import_react9 = require("@emotion/react");
673
+ var import_react10 = require("@emotion/react");
663
674
  var import_react_markdown = __toESM(require("react-markdown"));
664
675
  var import_remark_gfm = __toESM(require("remark-gfm"));
665
676
  var import_remark_math = __toESM(require("remark-math"));
@@ -897,6 +908,7 @@ var useChatMessageReveal = (message) => {
897
908
  ];
898
909
  return {
899
910
  isAssistantStreaming,
911
+ isFreshBlockActive,
900
912
  displayedContent,
901
913
  settledContent,
902
914
  freshContent,
@@ -904,6 +916,325 @@ var useChatMessageReveal = (message) => {
904
916
  };
905
917
  };
906
918
 
919
+ // src/components/chat-thread/hooks/use-timeline-block-anchors.ts
920
+ var import_react6 = require("react");
921
+
922
+ // src/components/chat-thread/lib/chat-message-timeline.ts
923
+ var stringifyTimelineKeyPart = (value) => {
924
+ if (value === null || value === void 0) {
925
+ return String(value);
926
+ }
927
+ if (Array.isArray(value)) {
928
+ return `[${value.map((item) => stringifyTimelineKeyPart(item)).join(",")}]`;
929
+ }
930
+ if (typeof value === "object") {
931
+ return `{${Object.entries(value).sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey)).map(([key, nestedValue]) => `${key}:${stringifyTimelineKeyPart(nestedValue)}`).join(",")}}`;
932
+ }
933
+ return String(value);
934
+ };
935
+ var getTimelineBlockKey = (block, index) => {
936
+ switch (block.type) {
937
+ case "markdown":
938
+ return null;
939
+ case "notice":
940
+ return `${index}:notice:${block.tone}:${block.text}`;
941
+ case "parameter_summary":
942
+ return `${index}:parameter_summary:${block.items.map((item) => `${item.label}:${item.value}:${item.fieldPath ?? ""}`).join("|")}`;
943
+ case "confirmation_card":
944
+ return `${index}:confirmation_card:${block.proposal.proposalId}`;
945
+ case "result_summary":
946
+ return `${index}:result_summary:${block.summary.taskId}:${block.summary.status}`;
947
+ case "questionnaire":
948
+ return `${index}:questionnaire:${block.questionnaire.questionnaireId}`;
949
+ case "custom":
950
+ return `${index}:custom:${block.kind}:${stringifyTimelineKeyPart(block.data)}`;
951
+ default:
952
+ return null;
953
+ }
954
+ };
955
+ var getTimelineConsumedText = (blocks) => blocks.filter(
956
+ (block) => block.type === "markdown"
957
+ ).map((block) => block.text).join("\n\n");
958
+ var getTimelineTextStream = (content, blocks) => {
959
+ const consumedText = getTimelineConsumedText(blocks);
960
+ if (consumedText.length > 0 && content.startsWith(consumedText)) {
961
+ return content.slice(consumedText.length);
962
+ }
963
+ return content;
964
+ };
965
+ var buildTimelineTextDisplay = (content, isAssistantStreaming, isFreshBlockActive = isAssistantStreaming) => {
966
+ const contentBlocks = splitMarkdownBlocks(content);
967
+ const settledContent = isAssistantStreaming && isFreshBlockActive && contentBlocks.length > 1 ? contentBlocks.slice(0, -1).join("\n\n") : content;
968
+ const freshContent = isAssistantStreaming && isFreshBlockActive && contentBlocks.length > 1 ? contentBlocks[contentBlocks.length - 1] ?? "" : "";
969
+ const displayedBlocks = contentBlocks.length > 1 ? contentBlocks.map((blockContent, index) => ({
970
+ content: blockContent,
971
+ tone: isAssistantStreaming && isFreshBlockActive && freshContent && index === contentBlocks.length - 1 ? "fresh" : "settled"
972
+ })) : [{ content, tone: "settled" }];
973
+ return {
974
+ settledContent,
975
+ freshContent,
976
+ displayedBlocks
977
+ };
978
+ };
979
+ var getTimelineDisplayUnitCount = (content) => splitMarkdownBlocks(content).reduce((count, block) => count + Array.from(block).length, 0);
980
+ var buildAnchoredTimelineSegments = ({
981
+ blocks,
982
+ timelineBlockAnchors,
983
+ timelineDisplayedBlocks,
984
+ visibleTimelineBlockKeys
985
+ }) => {
986
+ const orderedTimelineSegments = [];
987
+ const totalTimelineUnits = timelineDisplayedBlocks.reduce(
988
+ (count, block) => count + Array.from(block.content).length,
989
+ 0
990
+ );
991
+ let textCursor = 0;
992
+ const buildTextSegment = (start, end, options) => {
993
+ if (end <= start) {
994
+ return null;
995
+ }
996
+ const displayedBlocks = [];
997
+ let blockCursor = 0;
998
+ for (const block of timelineDisplayedBlocks) {
999
+ const blockUnits = Array.from(block.content);
1000
+ const blockStart = blockCursor;
1001
+ const blockEnd = blockCursor + blockUnits.length;
1002
+ if (blockEnd <= start) {
1003
+ blockCursor = blockEnd;
1004
+ continue;
1005
+ }
1006
+ if (blockStart >= end) {
1007
+ break;
1008
+ }
1009
+ const sliceStart = Math.max(0, start - blockStart);
1010
+ const sliceEnd = Math.min(blockUnits.length, end - blockStart);
1011
+ const slicedContent = blockUnits.slice(sliceStart, sliceEnd).join("");
1012
+ if (slicedContent) {
1013
+ displayedBlocks.push({
1014
+ content: slicedContent,
1015
+ tone: options?.forceSettled ? "settled" : block.tone
1016
+ });
1017
+ }
1018
+ blockCursor = blockEnd;
1019
+ }
1020
+ const content = displayedBlocks.map((block) => block.content).join("\n\n");
1021
+ if (!content) {
1022
+ return null;
1023
+ }
1024
+ return {
1025
+ type: "text",
1026
+ content,
1027
+ displayedBlocks,
1028
+ useTimelineSegmentation: true
1029
+ };
1030
+ };
1031
+ let trailingCutoff = totalTimelineUnits;
1032
+ for (const [index, block] of blocks.entries()) {
1033
+ if (block.type === "markdown") {
1034
+ orderedTimelineSegments.push({
1035
+ type: "markdown",
1036
+ content: block.text
1037
+ });
1038
+ continue;
1039
+ }
1040
+ const blockKey = getTimelineBlockKey(block, index);
1041
+ const anchor = blockKey !== null ? timelineBlockAnchors[blockKey] ?? totalTimelineUnits : totalTimelineUnits;
1042
+ const isBlockVisible = blockKey !== null && visibleTimelineBlockKeys?.[blockKey] ? true : anchor <= totalTimelineUnits;
1043
+ if (anchor > textCursor) {
1044
+ const textSegment = buildTextSegment(textCursor, Math.min(anchor, totalTimelineUnits), {
1045
+ forceSettled: isBlockVisible
1046
+ });
1047
+ if (textSegment) {
1048
+ orderedTimelineSegments.push(textSegment);
1049
+ }
1050
+ }
1051
+ if (!isBlockVisible) {
1052
+ textCursor = Math.min(anchor, totalTimelineUnits);
1053
+ trailingCutoff = Math.min(trailingCutoff, textCursor);
1054
+ continue;
1055
+ }
1056
+ trailingCutoff = totalTimelineUnits;
1057
+ orderedTimelineSegments.push({
1058
+ type: "block",
1059
+ block,
1060
+ index
1061
+ });
1062
+ textCursor = Math.max(textCursor, anchor);
1063
+ }
1064
+ const trailingTextSegment = buildTextSegment(textCursor, trailingCutoff);
1065
+ if (trailingTextSegment) {
1066
+ orderedTimelineSegments.push(trailingTextSegment);
1067
+ }
1068
+ return orderedTimelineSegments;
1069
+ };
1070
+
1071
+ // src/components/chat-thread/hooks/use-timeline-block-anchors.ts
1072
+ var createTimelineAnchorState = ({
1073
+ messageId,
1074
+ currentBlockKeys
1075
+ }) => ({
1076
+ messageId,
1077
+ previousBlockKeys: currentBlockKeys,
1078
+ timelineBlockAnchors: {},
1079
+ visibleTimelineBlockKeys: {}
1080
+ });
1081
+ var timelineAnchorReducer = (state, action) => {
1082
+ switch (action.type) {
1083
+ case "reset-message":
1084
+ if (state.messageId === action.messageId) {
1085
+ return state;
1086
+ }
1087
+ return createTimelineAnchorState(action);
1088
+ case "sync-anchors": {
1089
+ const previousBlockKeys = new Set(state.previousBlockKeys);
1090
+ const nextAnchors = action.currentBlockKeys.reduce(
1091
+ (acc, blockKey) => {
1092
+ const existingAnchor = state.timelineBlockAnchors[blockKey];
1093
+ if (existingAnchor !== void 0) {
1094
+ acc[blockKey] = existingAnchor;
1095
+ return acc;
1096
+ }
1097
+ if (!previousBlockKeys.has(blockKey)) {
1098
+ acc[blockKey] = action.timelineTextStreamLength;
1099
+ }
1100
+ return acc;
1101
+ },
1102
+ {}
1103
+ );
1104
+ const hasAnchorChanged = Object.keys(nextAnchors).length !== Object.keys(state.timelineBlockAnchors).length || Object.entries(nextAnchors).some(
1105
+ ([blockKey, anchor]) => state.timelineBlockAnchors[blockKey] !== anchor
1106
+ );
1107
+ const hasPreviousKeysChanged = action.currentBlockKeys.length !== state.previousBlockKeys.length || action.currentBlockKeys.some(
1108
+ (blockKey, index) => state.previousBlockKeys[index] !== blockKey
1109
+ );
1110
+ if (!hasAnchorChanged && !hasPreviousKeysChanged) {
1111
+ return state;
1112
+ }
1113
+ return {
1114
+ ...state,
1115
+ previousBlockKeys: action.currentBlockKeys,
1116
+ timelineBlockAnchors: hasAnchorChanged ? nextAnchors : state.timelineBlockAnchors
1117
+ };
1118
+ }
1119
+ case "sync-visible": {
1120
+ const nextVisibleBlockKeys = action.currentBlockKeys.reduce(
1121
+ (acc, blockKey) => {
1122
+ if (state.visibleTimelineBlockKeys[blockKey]) {
1123
+ acc[blockKey] = true;
1124
+ return acc;
1125
+ }
1126
+ const anchor = action.effectiveTimelineBlockAnchors[blockKey];
1127
+ if (anchor !== void 0 && anchor <= action.displayedTimelineTextLength) {
1128
+ acc[blockKey] = true;
1129
+ }
1130
+ return acc;
1131
+ },
1132
+ {}
1133
+ );
1134
+ const hasVisibleBlockChanged = Object.keys(nextVisibleBlockKeys).length !== Object.keys(state.visibleTimelineBlockKeys).length || Object.keys(nextVisibleBlockKeys).some(
1135
+ (blockKey) => !state.visibleTimelineBlockKeys[blockKey]
1136
+ );
1137
+ if (!hasVisibleBlockChanged) {
1138
+ return state;
1139
+ }
1140
+ return {
1141
+ ...state,
1142
+ visibleTimelineBlockKeys: nextVisibleBlockKeys
1143
+ };
1144
+ }
1145
+ default:
1146
+ return state;
1147
+ }
1148
+ };
1149
+ var useTimelineBlockAnchors = ({
1150
+ blocks,
1151
+ displayedTimelineTextLength,
1152
+ isAssistantStreaming,
1153
+ message,
1154
+ messageRenderOrder
1155
+ }) => {
1156
+ const currentTimelineBlockKeys = (0, import_react6.useMemo)(
1157
+ () => blocks.map((block, index) => getTimelineBlockKey(block, index)).filter((blockKey) => Boolean(blockKey)),
1158
+ [blocks]
1159
+ );
1160
+ const timelineTextStreamLength = (0, import_react6.useMemo)(
1161
+ () => getTimelineDisplayUnitCount(getTimelineTextStream(message.content, blocks)),
1162
+ [blocks, message.content]
1163
+ );
1164
+ const [state, dispatch] = (0, import_react6.useReducer)(
1165
+ timelineAnchorReducer,
1166
+ {
1167
+ messageId: message.id,
1168
+ currentBlockKeys: currentTimelineBlockKeys
1169
+ },
1170
+ createTimelineAnchorState
1171
+ );
1172
+ const effectiveTimelineBlockAnchors = (0, import_react6.useMemo)(() => {
1173
+ if (messageRenderOrder !== "timeline" || !isAssistantStreaming) {
1174
+ return state.timelineBlockAnchors;
1175
+ }
1176
+ const previousBlockKeys = new Set(state.previousBlockKeys);
1177
+ return currentTimelineBlockKeys.reduce(
1178
+ (acc, blockKey) => {
1179
+ const existingAnchor = state.timelineBlockAnchors[blockKey];
1180
+ if (existingAnchor !== void 0) {
1181
+ acc[blockKey] = existingAnchor;
1182
+ return acc;
1183
+ }
1184
+ if (!previousBlockKeys.has(blockKey)) {
1185
+ acc[blockKey] = timelineTextStreamLength;
1186
+ }
1187
+ return acc;
1188
+ },
1189
+ { ...state.timelineBlockAnchors }
1190
+ );
1191
+ }, [
1192
+ currentTimelineBlockKeys,
1193
+ isAssistantStreaming,
1194
+ messageRenderOrder,
1195
+ state.previousBlockKeys,
1196
+ state.timelineBlockAnchors,
1197
+ timelineTextStreamLength
1198
+ ]);
1199
+ (0, import_react6.useEffect)(() => {
1200
+ dispatch({
1201
+ type: "reset-message",
1202
+ messageId: message.id,
1203
+ currentBlockKeys: currentTimelineBlockKeys
1204
+ });
1205
+ }, [currentTimelineBlockKeys, message.id]);
1206
+ (0, import_react6.useEffect)(() => {
1207
+ if (messageRenderOrder !== "timeline" || !isAssistantStreaming) {
1208
+ return;
1209
+ }
1210
+ dispatch({
1211
+ type: "sync-anchors",
1212
+ currentBlockKeys: currentTimelineBlockKeys,
1213
+ timelineTextStreamLength
1214
+ });
1215
+ }, [currentTimelineBlockKeys, isAssistantStreaming, messageRenderOrder, timelineTextStreamLength]);
1216
+ (0, import_react6.useEffect)(() => {
1217
+ if (messageRenderOrder !== "timeline") {
1218
+ return;
1219
+ }
1220
+ dispatch({
1221
+ type: "sync-visible",
1222
+ currentBlockKeys: currentTimelineBlockKeys,
1223
+ effectiveTimelineBlockAnchors,
1224
+ displayedTimelineTextLength
1225
+ });
1226
+ }, [
1227
+ currentTimelineBlockKeys,
1228
+ displayedTimelineTextLength,
1229
+ effectiveTimelineBlockAnchors,
1230
+ messageRenderOrder
1231
+ ]);
1232
+ return {
1233
+ timelineBlockAnchors: messageRenderOrder === "timeline" ? effectiveTimelineBlockAnchors : {},
1234
+ visibleTimelineBlockKeys: messageRenderOrder === "timeline" ? state.visibleTimelineBlockKeys : {}
1235
+ };
1236
+ };
1237
+
907
1238
  // src/components/chat-thread/components/pde-ai-execution-confirmation-card.tsx
908
1239
  var import_styled = __toESM(require("@emotion/styled"));
909
1240
  var import_jsx_runtime2 = require("@emotion/react/jsx-runtime");
@@ -1114,7 +1445,7 @@ var Value = import_styled3.default.span`
1114
1445
  `;
1115
1446
 
1116
1447
  // src/components/chat-thread/components/pde-ai-questionnaire-card.tsx
1117
- var import_react6 = require("react");
1448
+ var import_react7 = require("react");
1118
1449
  var import_styled4 = __toESM(require("@emotion/styled"));
1119
1450
  var import_jsx_runtime5 = require("@emotion/react/jsx-runtime");
1120
1451
  var OTHER_OPTION_VALUE = "__other__";
@@ -1216,10 +1547,10 @@ var PDEAIQuestionnaireCardInner = ({
1216
1547
  interactive = false,
1217
1548
  onSubmit
1218
1549
  }) => {
1219
- const [answers, setAnswers] = (0, import_react6.useState)(
1550
+ const [answers, setAnswers] = (0, import_react7.useState)(
1220
1551
  () => createInitialAnswers(questionnaire)
1221
1552
  );
1222
- const [errorMessage, setErrorMessage] = (0, import_react6.useState)(null);
1553
+ const [errorMessage, setErrorMessage] = (0, import_react7.useState)(null);
1223
1554
  const handleSubmit = () => {
1224
1555
  const missingQuestions = questionnaire.questions.filter(
1225
1556
  (question) => question.required && isMissingRequiredAnswer(question, answers)
@@ -1655,7 +1986,7 @@ var Detail = import_styled5.default.li`
1655
1986
 
1656
1987
  // src/components/chat-thread/components/image-viewer.tsx
1657
1988
  var import_styled6 = __toESM(require("@emotion/styled"));
1658
- var import_react7 = require("react");
1989
+ var import_react8 = require("react");
1659
1990
  var import_jsx_runtime7 = require("@emotion/react/jsx-runtime");
1660
1991
  var Overlay = import_styled6.default.div`
1661
1992
  position: fixed;
@@ -1674,8 +2005,8 @@ var Img = import_styled6.default.img`
1674
2005
  border-radius: 4px;
1675
2006
  `;
1676
2007
  var ImageViewer = ({ src, alt, onClose }) => {
1677
- const overlayRef = (0, import_react7.useRef)(null);
1678
- (0, import_react7.useEffect)(() => {
2008
+ const overlayRef = (0, import_react8.useRef)(null);
2009
+ (0, import_react8.useEffect)(() => {
1679
2010
  const handleKey = (e) => {
1680
2011
  if (e.key === "Escape")
1681
2012
  onClose();
@@ -1683,7 +2014,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
1683
2014
  document.addEventListener("keydown", handleKey);
1684
2015
  return () => document.removeEventListener("keydown", handleKey);
1685
2016
  }, [onClose]);
1686
- (0, import_react7.useEffect)(() => {
2017
+ (0, import_react8.useEffect)(() => {
1687
2018
  overlayRef.current?.focus();
1688
2019
  }, []);
1689
2020
  const stopPropagation = (e) => e.stopPropagation();
@@ -1846,9 +2177,16 @@ var ChatMessageItemView = ({
1846
2177
  onQuestionnaireSubmit,
1847
2178
  renderMessageBlock
1848
2179
  }) => {
1849
- const { labels } = useChatContext();
1850
- const [activeImage, setActiveImage] = (0, import_react8.useState)(void 0);
1851
- const { displayedBlocks, displayedContent, freshContent, isAssistantStreaming, settledContent } = useChatMessageReveal(message);
2180
+ const { labels, messageRenderOrder = "blocks-first" } = useChatContext();
2181
+ const [activeImage, setActiveImage] = (0, import_react9.useState)(void 0);
2182
+ const {
2183
+ displayedBlocks,
2184
+ displayedContent,
2185
+ freshContent,
2186
+ isAssistantStreaming,
2187
+ isFreshBlockActive,
2188
+ settledContent
2189
+ } = useChatMessageReveal(message);
1852
2190
  const isStoppedAssistant = message.role === "assistant" && message.status === "stopped";
1853
2191
  const attachments = message.attachments ?? [];
1854
2192
  const blocks = message.blocks ?? [];
@@ -1860,6 +2198,22 @@ var ChatMessageItemView = ({
1860
2198
  const canSubmitConfirmation = isPlanMode && typeof onConfirmationSubmit === "function";
1861
2199
  const canSubmitQuestionnaire = isPlanMode && typeof onQuestionnaireSubmit === "function";
1862
2200
  const shouldShowStreamingCaret = isAssistantStreaming && (!shouldRenderStructuredBlocks || hasTextContent);
2201
+ const timelineConsumedText = messageRenderOrder === "timeline" ? getTimelineConsumedText(blocks) : "";
2202
+ const hasConsumedTimelineText = timelineConsumedText.length > 0 && displayedContent.startsWith(timelineConsumedText);
2203
+ const timelineDisplayedContent = hasConsumedTimelineText ? displayedContent.slice(timelineConsumedText.length) : displayedContent;
2204
+ const timelineTextDisplay = buildTimelineTextDisplay(
2205
+ timelineDisplayedContent,
2206
+ isAssistantStreaming,
2207
+ isFreshBlockActive
2208
+ );
2209
+ const displayedTimelineTextLength = getTimelineDisplayUnitCount(timelineDisplayedContent);
2210
+ const { timelineBlockAnchors, visibleTimelineBlockKeys } = useTimelineBlockAnchors({
2211
+ blocks,
2212
+ displayedTimelineTextLength,
2213
+ isAssistantStreaming,
2214
+ message,
2215
+ messageRenderOrder
2216
+ });
1863
2217
  const renderChatMessageBlock = (block, index) => {
1864
2218
  switch (block.type) {
1865
2219
  case "markdown":
@@ -1873,11 +2227,11 @@ var ChatMessageItemView = ({
1873
2227
  `markdown-${index}`
1874
2228
  );
1875
2229
  case "notice":
1876
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PDEAINoticeCard, { text: block.text, tone: block.tone }) }, `notice-${index}`);
2230
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PDEAINoticeCard, { text: block.text, tone: block.tone }) }, `notice-${index}`);
1877
2231
  case "parameter_summary":
1878
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PDEAIParameterSummaryCard, { items: block.items }) }, `parameter-summary-${index}`);
2232
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PDEAIParameterSummaryCard, { items: block.items }) }, `parameter-summary-${index}`);
1879
2233
  case "confirmation_card":
1880
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2234
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1881
2235
  PDEAIExecutionConfirmationCard,
1882
2236
  {
1883
2237
  proposal: block.proposal,
@@ -1890,9 +2244,9 @@ var ChatMessageItemView = ({
1890
2244
  }
1891
2245
  ) }, `confirmation-card-${index}`);
1892
2246
  case "result_summary":
1893
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PDEAIResultSummaryCard, { summary: block.summary }) }, `result-summary-${index}`);
2247
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PDEAIResultSummaryCard, { summary: block.summary }) }, `result-summary-${index}`);
1894
2248
  case "questionnaire":
1895
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2249
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1896
2250
  PDEAIQuestionnaireCard,
1897
2251
  {
1898
2252
  questionnaire: block.questionnaire,
@@ -1904,7 +2258,7 @@ var ChatMessageItemView = ({
1904
2258
  }
1905
2259
  ) }, `questionnaire-${index}`);
1906
2260
  case "custom":
1907
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.Fragment, { children: renderMessageBlock?.({
2261
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: renderMessageBlock?.({
1908
2262
  block,
1909
2263
  index,
1910
2264
  message,
@@ -1916,19 +2270,69 @@ var ChatMessageItemView = ({
1916
2270
  return null;
1917
2271
  }
1918
2272
  };
1919
- const renderTextContent = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1920
- displayedBlocks.filter((block) => block.content).map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1921
- ContentBlock,
1922
- {
1923
- "data-testid": block.tone === "fresh" ? "chat-message-fresh-block" : "chat-message-settled-block",
1924
- "data-block-tone": block.tone,
1925
- "data-block-index": index,
1926
- children: renderMarkdownContent(block.content)
1927
- },
1928
- `${block.tone}-${index}`
1929
- )),
1930
- !displayedBlocks.some((block) => block.content) && !settledContent && !freshContent && hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentBlock, { "data-testid": "chat-message-settled-block", "data-block-tone": "settled", children: renderMarkdownContent(displayedContent) }) : null
1931
- ] });
2273
+ const renderTextContent = (options) => {
2274
+ const textContent = options?.content ?? displayedContent;
2275
+ const localTimelineTextDisplay = options?.displayedBlocks ? void 0 : options?.useTimelineSegmentation && options.content !== void 0 ? buildTimelineTextDisplay(options.content, isAssistantStreaming, isFreshBlockActive) : void 0;
2276
+ const textBlocks = options?.displayedBlocks ?? localTimelineTextDisplay?.displayedBlocks ?? displayedBlocks;
2277
+ const settledText = localTimelineTextDisplay?.settledContent ?? settledContent;
2278
+ const freshText = localTimelineTextDisplay?.freshContent ?? freshContent;
2279
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
2280
+ textBlocks.filter((block) => block.content).map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2281
+ ContentBlock,
2282
+ {
2283
+ "data-testid": block.tone === "fresh" ? "chat-message-fresh-block" : "chat-message-settled-block",
2284
+ "data-block-tone": block.tone,
2285
+ "data-block-index": index,
2286
+ children: renderMarkdownContent(block.content)
2287
+ },
2288
+ `${block.tone}-${index}`
2289
+ )),
2290
+ !textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentBlock, { "data-testid": "chat-message-settled-block", "data-block-tone": "settled", children: renderMarkdownContent(textContent) }) : null
2291
+ ] });
2292
+ };
2293
+ const renderStaticTextSegment = (content) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentBlock, { "data-testid": "chat-message-settled-block", "data-block-tone": "settled", children: renderMarkdownContent(content) });
2294
+ const bodySegments = (() => {
2295
+ if (!shouldRenderStructuredBlocks && hasTextContent) {
2296
+ return [{ type: "text" }];
2297
+ }
2298
+ if (!shouldRenderStructuredBlocks) {
2299
+ return [];
2300
+ }
2301
+ if (messageRenderOrder === "timeline" && hasTextContent) {
2302
+ const hasAnchoredStructuredBlocks = blocks.some((block, index) => {
2303
+ const blockKey = getTimelineBlockKey(block, index);
2304
+ return blockKey ? timelineBlockAnchors[blockKey] !== void 0 : false;
2305
+ });
2306
+ if (hasAnchoredStructuredBlocks) {
2307
+ return buildAnchoredTimelineSegments({
2308
+ blocks,
2309
+ timelineBlockAnchors,
2310
+ timelineDisplayedBlocks: timelineTextDisplay.displayedBlocks,
2311
+ visibleTimelineBlockKeys
2312
+ });
2313
+ }
2314
+ const orderedTimelineSegments = blocks.map(
2315
+ (block, index) => block.type === "markdown" ? {
2316
+ type: "markdown",
2317
+ content: block.text
2318
+ } : {
2319
+ type: "block",
2320
+ block,
2321
+ index
2322
+ }
2323
+ );
2324
+ if (!timelineConsumedText) {
2325
+ return displayedContent ? [{ type: "text", content: displayedContent }, ...orderedTimelineSegments] : orderedTimelineSegments;
2326
+ }
2327
+ return timelineDisplayedContent ? [...orderedTimelineSegments, { type: "text", content: timelineDisplayedContent }] : orderedTimelineSegments;
2328
+ }
2329
+ const orderedBlocks = blocks.map((block, index) => ({
2330
+ type: "block",
2331
+ block,
2332
+ index
2333
+ }));
2334
+ return hasTextContent ? [...orderedBlocks, { type: "text" }] : orderedBlocks;
2335
+ })();
1932
2336
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1933
2337
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Bubble, { "data-role": message.role, "data-status": message.status ?? "done", children: [
1934
2338
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Header2, { children: [
@@ -1947,17 +2351,18 @@ var ChatMessageItemView = ({
1947
2351
  isStoppedAssistant ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StatusTag, { "data-testid": "chat-message-stopped-tag", children: labels.stoppedResponse }) : null
1948
2352
  ] }),
1949
2353
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Content, { "data-testid": "chat-message-content", children: [
1950
- shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(ContentStack, { "data-testid": "chat-message-body-stack", children: [
1951
- shouldRenderStructuredBlocks ? blocks.map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1952
- ContentSegment,
1953
- {
1954
- "data-testid": "chat-message-content-segment",
1955
- children: renderChatMessageBlock(block, index)
1956
- },
1957
- `${block.type}-${index}`
1958
- )) : null,
1959
- hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentSegment, { "data-testid": "chat-message-content-segment", children: renderTextContent() }) : null
1960
- ] }) : null,
2354
+ shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentStack, { "data-testid": "chat-message-body-stack", children: bodySegments.map((segment, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2355
+ ContentSegment,
2356
+ {
2357
+ "data-testid": "chat-message-content-segment",
2358
+ children: segment.type === "block" ? renderChatMessageBlock(segment.block, segment.index) : segment.type === "text" ? segment.content !== void 0 ? segment.useTimelineSegmentation ? renderTextContent({
2359
+ content: segment.content,
2360
+ displayedBlocks: segment.displayedBlocks,
2361
+ useTimelineSegmentation: true
2362
+ }) : renderStaticTextSegment(segment.content) : renderTextContent() : renderStaticTextSegment(segment.content)
2363
+ },
2364
+ segment.type === "text" ? `text-${index}` : segment.type === "markdown" ? `markdown-${index}` : `${segment.block.type}-${segment.index}`
2365
+ )) }) : null,
1961
2366
  attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AttachmentGrid, { "data-testid": "chat-message-attachment-grid", children: attachments.map((attachment) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1962
2367
  AttachmentButton,
1963
2368
  {
@@ -1984,7 +2389,7 @@ var ChatMessageItemView = ({
1984
2389
  ) : null
1985
2390
  ] });
1986
2391
  };
1987
- var ChatMessageItem = (0, import_react8.memo)(
2392
+ var ChatMessageItem = (0, import_react9.memo)(
1988
2393
  ChatMessageItemView,
1989
2394
  (previousProps, nextProps) => isSameMessage(
1990
2395
  previousProps.message,
@@ -2129,7 +2534,7 @@ var AttachmentImage = import_styled7.default.img`
2129
2534
  var TableWrapper = import_styled7.default.div`
2130
2535
  overflow-x: auto;
2131
2536
  `;
2132
- var caretBlink = import_react9.keyframes`
2537
+ var caretBlink = import_react10.keyframes`
2133
2538
  0%, 49% {
2134
2539
  opacity: 1;
2135
2540
  }
@@ -2138,7 +2543,7 @@ var caretBlink = import_react9.keyframes`
2138
2543
  opacity: 0.2;
2139
2544
  }
2140
2545
  `;
2141
- var shimmer = import_react9.keyframes`
2546
+ var shimmer = import_react10.keyframes`
2142
2547
  0%, 100% {
2143
2548
  transform: scale(0.9) rotate(0deg);
2144
2549
  opacity: 0.55;
@@ -2349,18 +2754,18 @@ var ChatThreadView = ({
2349
2754
  onQuestionnaireSubmit,
2350
2755
  renderMessageBlock
2351
2756
  }) => {
2352
- const containerRef = (0, import_react10.useRef)(null);
2353
- const conversationTurns = (0, import_react10.useMemo)(
2757
+ const containerRef = (0, import_react11.useRef)(null);
2758
+ const conversationTurns = (0, import_react11.useMemo)(
2354
2759
  () => groupConversationTurns(historyMessages, streamingMessage),
2355
2760
  [historyMessages, streamingMessage]
2356
2761
  );
2357
2762
  const latestTurn = conversationTurns[conversationTurns.length - 1];
2358
2763
  const previousTurns = conversationTurns.slice(0, -1);
2359
2764
  const latestUserMessageId = latestTurn?.userMessage?.id;
2360
- const latestUserMessageRef = (0, import_react10.useRef)(null);
2361
- const reservedSpaceFrameRef = (0, import_react10.useRef)(null);
2362
- const [latestTurnMinHeight, setLatestTurnMinHeight] = (0, import_react10.useState)(0);
2363
- const measureLatestTurnMinHeight = (0, import_react10.useCallback)(() => {
2765
+ const latestUserMessageRef = (0, import_react11.useRef)(null);
2766
+ const reservedSpaceFrameRef = (0, import_react11.useRef)(null);
2767
+ const [latestTurnMinHeight, setLatestTurnMinHeight] = (0, import_react11.useState)(0);
2768
+ const measureLatestTurnMinHeight = (0, import_react11.useCallback)(() => {
2364
2769
  const container = containerRef.current;
2365
2770
  if (!container)
2366
2771
  return;
@@ -2370,7 +2775,7 @@ var ChatThreadView = ({
2370
2775
  const nextMinHeight = Math.max(0, container.clientHeight - paddingTop - paddingBottom);
2371
2776
  setLatestTurnMinHeight((current) => current === nextMinHeight ? current : nextMinHeight);
2372
2777
  }, []);
2373
- const scrollLatestUserMessageToTop = (0, import_react10.useCallback)(() => {
2778
+ const scrollLatestUserMessageToTop = (0, import_react11.useCallback)(() => {
2374
2779
  const container = containerRef.current;
2375
2780
  const target = latestUserMessageRef.current;
2376
2781
  if (!container || !target)
@@ -2390,7 +2795,7 @@ var ChatThreadView = ({
2390
2795
  }
2391
2796
  container.scrollTop = nextScrollTop;
2392
2797
  }, []);
2393
- (0, import_react10.useLayoutEffect)(() => {
2798
+ (0, import_react11.useLayoutEffect)(() => {
2394
2799
  if (reservedSpaceFrameRef.current !== null) {
2395
2800
  window.cancelAnimationFrame(reservedSpaceFrameRef.current);
2396
2801
  reservedSpaceFrameRef.current = null;
@@ -2419,7 +2824,7 @@ var ChatThreadView = ({
2419
2824
  }
2420
2825
  };
2421
2826
  }, [latestUserMessageId, measureLatestTurnMinHeight, scrollLatestUserMessageToTop]);
2422
- (0, import_react10.useLayoutEffect)(() => {
2827
+ (0, import_react11.useLayoutEffect)(() => {
2423
2828
  if (!latestUserMessageId)
2424
2829
  return;
2425
2830
  const handleResize = () => {
@@ -2507,13 +2912,13 @@ var ChatThread = () => {
2507
2912
  const updateQA = useChatStore((s) => s.updateQuestionnaireAnswers);
2508
2913
  const clearSessionError = useChatStore((s) => s.clearSessionError);
2509
2914
  const { sendRef, retryRef, renderMessageBlock, labels } = useChatContext();
2510
- const handleRetry = (0, import_react10.useCallback)(() => {
2915
+ const handleRetry = (0, import_react11.useCallback)(() => {
2511
2916
  if (!activeSessionId)
2512
2917
  return;
2513
2918
  clearSessionError(activeSessionId);
2514
2919
  void retryRef.current();
2515
2920
  }, [activeSessionId, clearSessionError, retryRef]);
2516
- const handleQuestionnaireSubmit = (0, import_react10.useCallback)(
2921
+ const handleQuestionnaireSubmit = (0, import_react11.useCallback)(
2517
2922
  (submission) => {
2518
2923
  if (activeSessionId && submission.sourceMessageId) {
2519
2924
  updateQA(
@@ -2527,7 +2932,7 @@ var ChatThread = () => {
2527
2932
  },
2528
2933
  [activeSessionId, updateQA, sendRef]
2529
2934
  );
2530
- const handleConfirmationSubmit = (0, import_react10.useCallback)(
2935
+ const handleConfirmationSubmit = (0, import_react11.useCallback)(
2531
2936
  (submission) => {
2532
2937
  void sendRef.current(submission.content);
2533
2938
  },
@@ -2612,7 +3017,7 @@ var RetryButton = import_styled9.default.button`
2612
3017
  `;
2613
3018
 
2614
3019
  // src/components/chat-composer/index.tsx
2615
- var import_react14 = require("react");
3020
+ var import_react15 = require("react");
2616
3021
  var import_styled14 = __toESM(require("@emotion/styled"));
2617
3022
 
2618
3023
  // src/components/chat-composer/lib/chat-composer.ts
@@ -2724,10 +3129,10 @@ var resolveSendSession = ({
2724
3129
  };
2725
3130
 
2726
3131
  // src/components/chat-composer/hooks/use-chat-composer.ts
2727
- var import_react12 = require("react");
3132
+ var import_react13 = require("react");
2728
3133
 
2729
3134
  // src/components/chat-composer/hooks/use-composer-attachments.ts
2730
- var import_react11 = require("react");
3135
+ var import_react12 = require("react");
2731
3136
  var SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
2732
3137
  var MAX_COMPOSER_ATTACHMENTS = 10;
2733
3138
  var createObjectUrl = (file) => typeof URL !== "undefined" && typeof URL.createObjectURL === "function" ? URL.createObjectURL(file) : "";
@@ -2741,12 +3146,12 @@ var releaseComposerAttachments = (attachments) => {
2741
3146
  attachments.forEach((attachment) => revokeObjectUrl(attachment.previewUrl));
2742
3147
  };
2743
3148
  var useComposerAttachments = () => {
2744
- const [attachments, setAttachments] = (0, import_react11.useState)([]);
2745
- const attachmentsRef = (0, import_react11.useRef)([]);
2746
- (0, import_react11.useEffect)(() => {
3149
+ const [attachments, setAttachments] = (0, import_react12.useState)([]);
3150
+ const attachmentsRef = (0, import_react12.useRef)([]);
3151
+ (0, import_react12.useEffect)(() => {
2747
3152
  attachmentsRef.current = attachments;
2748
3153
  }, [attachments]);
2749
- (0, import_react11.useEffect)(
3154
+ (0, import_react12.useEffect)(
2750
3155
  () => () => {
2751
3156
  releaseComposerAttachments(attachmentsRef.current);
2752
3157
  },
@@ -2859,10 +3264,10 @@ var useChatComposer = () => {
2859
3264
  const clearSessionError = useChatStore((s) => s.clearSessionError);
2860
3265
  const setPreferredMode = useChatStore((s) => s.setPreferredMode);
2861
3266
  const setSessionMode = useChatStore((s) => s.setSessionMode);
2862
- const [availableModels, setAvailableModels] = (0, import_react12.useState)([]);
2863
- const [isModelsLoading, setIsModelsLoading] = (0, import_react12.useState)(true);
2864
- const [isModelsError, setIsModelsError] = (0, import_react12.useState)(false);
2865
- const fetchModels = (0, import_react12.useCallback)(async () => {
3267
+ const [availableModels, setAvailableModels] = (0, import_react13.useState)([]);
3268
+ const [isModelsLoading, setIsModelsLoading] = (0, import_react13.useState)(true);
3269
+ const [isModelsError, setIsModelsError] = (0, import_react13.useState)(false);
3270
+ const fetchModels = (0, import_react13.useCallback)(async () => {
2866
3271
  setIsModelsLoading(true);
2867
3272
  setIsModelsError(false);
2868
3273
  try {
@@ -2874,31 +3279,31 @@ var useChatComposer = () => {
2874
3279
  setIsModelsLoading(false);
2875
3280
  }
2876
3281
  }, [transport]);
2877
- (0, import_react12.useEffect)(() => {
3282
+ (0, import_react13.useEffect)(() => {
2878
3283
  void fetchModels();
2879
3284
  }, [fetchModels]);
2880
3285
  const hasModels = availableModels.length > 0;
2881
- const [value, setValue] = (0, import_react12.useState)("");
2882
- const [selectedModel, setSelectedModel] = (0, import_react12.useState)("");
2883
- const [selectedMode, setSelectedModeLocal] = (0, import_react12.useState)(DEFAULT_CHAT_AGENT_MODE);
2884
- const [attachmentNotice, setAttachmentNotice] = (0, import_react12.useState)(null);
3286
+ const [value, setValue] = (0, import_react13.useState)("");
3287
+ const [selectedModel, setSelectedModel] = (0, import_react13.useState)("");
3288
+ const [selectedMode, setSelectedModeLocal] = (0, import_react13.useState)(DEFAULT_CHAT_AGENT_MODE);
3289
+ const [attachmentNotice, setAttachmentNotice] = (0, import_react13.useState)(null);
2885
3290
  const { attachments, appendFiles, removeAttachment, takeMessageAttachments } = useComposerAttachments();
2886
- const abortControllerRef = (0, import_react12.useRef)(null);
2887
- const stopRequestRef = (0, import_react12.useRef)(null);
2888
- const lastRequestRef = (0, import_react12.useRef)(null);
2889
- (0, import_react12.useEffect)(() => {
3291
+ const abortControllerRef = (0, import_react13.useRef)(null);
3292
+ const stopRequestRef = (0, import_react13.useRef)(null);
3293
+ const lastRequestRef = (0, import_react13.useRef)(null);
3294
+ (0, import_react13.useEffect)(() => {
2890
3295
  setSelectedModel(
2891
3296
  (current) => resolveSelectedChatModel({ currentModel: current, availableModels, isModelsLoading })
2892
3297
  );
2893
3298
  }, [availableModels, isModelsLoading]);
2894
- (0, import_react12.useEffect)(() => {
3299
+ (0, import_react13.useEffect)(() => {
2895
3300
  if (activeSession) {
2896
3301
  setSelectedModeLocal(activeSession.mode ?? DEFAULT_CHAT_AGENT_MODE);
2897
3302
  return;
2898
3303
  }
2899
3304
  setSelectedModeLocal(preferredMode ?? DEFAULT_CHAT_AGENT_MODE);
2900
3305
  }, [activeSession, preferredMode]);
2901
- (0, import_react12.useEffect)(() => {
3306
+ (0, import_react13.useEffect)(() => {
2902
3307
  if (!attachmentNotice)
2903
3308
  return;
2904
3309
  const timeoutId = window.setTimeout(
@@ -2917,7 +3322,7 @@ var useChatComposer = () => {
2917
3322
  stopRequestRef.current.timeoutId = null;
2918
3323
  }
2919
3324
  };
2920
- const clearStopRequest = (0, import_react12.useCallback)((sessionId) => {
3325
+ const clearStopRequest = (0, import_react13.useCallback)((sessionId) => {
2921
3326
  if (!stopRequestRef.current)
2922
3327
  return;
2923
3328
  if (sessionId && stopRequestRef.current.sessionId !== sessionId)
@@ -2925,7 +3330,7 @@ var useChatComposer = () => {
2925
3330
  clearStopTimeout(sessionId);
2926
3331
  stopRequestRef.current = null;
2927
3332
  }, []);
2928
- const finalizeStop = (0, import_react12.useCallback)(
3333
+ const finalizeStop = (0, import_react13.useCallback)(
2929
3334
  (sessionId) => {
2930
3335
  if (stopRequestRef.current?.sessionId === sessionId) {
2931
3336
  if (stopRequestRef.current.finalized)
@@ -2940,7 +3345,7 @@ var useChatComposer = () => {
2940
3345
  },
2941
3346
  [clearStopRequest, finalizeStoppedStreamingMessage]
2942
3347
  );
2943
- const runStream = (0, import_react12.useCallback)(
3348
+ const runStream = (0, import_react13.useCallback)(
2944
3349
  async ({
2945
3350
  localSessionId,
2946
3351
  sessionId,
@@ -3029,7 +3434,7 @@ var useChatComposer = () => {
3029
3434
  setSessionError
3030
3435
  ]
3031
3436
  );
3032
- const send = (0, import_react12.useCallback)(
3437
+ const send = (0, import_react13.useCallback)(
3033
3438
  async (contentOverride) => {
3034
3439
  const content = (contentOverride ?? value).trim();
3035
3440
  const hasText = Boolean(content);
@@ -3177,14 +3582,14 @@ var useChatComposer = () => {
3177
3582
  };
3178
3583
 
3179
3584
  // src/components/chat-composer/components/chat-composer-attachment-list.tsx
3180
- var import_react13 = require("react");
3585
+ var import_react14 = require("react");
3181
3586
  var import_styled10 = __toESM(require("@emotion/styled"));
3182
3587
  var import_jsx_runtime11 = require("@emotion/react/jsx-runtime");
3183
3588
  var ChatComposerAttachmentList = ({
3184
3589
  attachments,
3185
3590
  onRemoveAttachment
3186
3591
  }) => {
3187
- const [activeImage, setActiveImage] = (0, import_react13.useState)(null);
3592
+ const [activeImage, setActiveImage] = (0, import_react14.useState)(null);
3188
3593
  if (!attachments.length) {
3189
3594
  return null;
3190
3595
  }
@@ -3676,7 +4081,7 @@ var ChatComposerView = ({
3676
4081
  onStop,
3677
4082
  onSend
3678
4083
  }) => {
3679
- const imageInputRef = (0, import_react14.useRef)(null);
4084
+ const imageInputRef = (0, import_react15.useRef)(null);
3680
4085
  const canSend = canSendChatMessage({
3681
4086
  value,
3682
4087
  attachmentCount: attachments.length,
@@ -3788,7 +4193,7 @@ var ChatComposer = () => {
3788
4193
  const { labels, sendRef, retryRef, enableImageAttachments } = useChatContext();
3789
4194
  const { state, actions } = useChatComposer();
3790
4195
  const { send, retry } = actions;
3791
- (0, import_react14.useEffect)(() => {
4196
+ (0, import_react15.useEffect)(() => {
3792
4197
  sendRef.current = send;
3793
4198
  retryRef.current = async () => {
3794
4199
  retry();
@@ -3909,10 +4314,10 @@ var AttachButton = import_styled14.default.button`
3909
4314
  var import_styled16 = __toESM(require("@emotion/styled"));
3910
4315
 
3911
4316
  // src/components/chat-conversation-list/components/chat-session-item.tsx
3912
- var import_react15 = require("react");
4317
+ var import_react16 = require("react");
3913
4318
  var import_styled15 = __toESM(require("@emotion/styled"));
3914
4319
  var import_jsx_runtime16 = require("@emotion/react/jsx-runtime");
3915
- var ChatSessionItem = (0, import_react15.memo)(
4320
+ var ChatSessionItem = (0, import_react16.memo)(
3916
4321
  ({ session, isActive, modeLabel, onClick }) => {
3917
4322
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3918
4323
  SessionButton,
@@ -4108,6 +4513,7 @@ var Workspace = import_styled17.default.section`
4108
4513
  AiChat,
4109
4514
  AiChatProvider,
4110
4515
  CHAT_AGENT_MODES,
4516
+ CHAT_MESSAGE_RENDER_ORDERS,
4111
4517
  ChatComposer,
4112
4518
  ChatConversationList,
4113
4519
  ChatThread,