@xinghunm/ai-chat 0.2.2 → 0.3.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,303 @@ 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 useTimelineBlockAnchors = ({
1073
+ blocks,
1074
+ displayedTimelineTextLength,
1075
+ isAssistantStreaming,
1076
+ message,
1077
+ messageRenderOrder
1078
+ }) => {
1079
+ const [timelineBlockAnchors, setTimelineBlockAnchors] = (0, import_react6.useState)({});
1080
+ const [visibleTimelineBlockKeys, setVisibleTimelineBlockKeys] = (0, import_react6.useState)({});
1081
+ const currentTimelineBlockKeys = (0, import_react6.useMemo)(
1082
+ () => blocks.map((block, index) => getTimelineBlockKey(block, index)).filter((blockKey) => Boolean(blockKey)),
1083
+ [blocks]
1084
+ );
1085
+ const timelineTextStreamLength = (0, import_react6.useMemo)(
1086
+ () => getTimelineDisplayUnitCount(getTimelineTextStream(message.content, blocks)),
1087
+ [blocks, message.content]
1088
+ );
1089
+ const previousTimelineStateRef = (0, import_react6.useRef)({
1090
+ messageId: message.id,
1091
+ blockKeys: currentTimelineBlockKeys,
1092
+ textLength: timelineTextStreamLength
1093
+ });
1094
+ const effectiveTimelineBlockAnchors = (0, import_react6.useMemo)(() => {
1095
+ if (messageRenderOrder !== "timeline" || !isAssistantStreaming) {
1096
+ return timelineBlockAnchors;
1097
+ }
1098
+ const previousTimelineState = previousTimelineStateRef.current;
1099
+ const previousBlockKeys = new Set(previousTimelineState.blockKeys);
1100
+ return currentTimelineBlockKeys.reduce(
1101
+ (acc, blockKey) => {
1102
+ const existingAnchor = timelineBlockAnchors[blockKey];
1103
+ if (existingAnchor !== void 0) {
1104
+ acc[blockKey] = existingAnchor;
1105
+ return acc;
1106
+ }
1107
+ if (!previousBlockKeys.has(blockKey)) {
1108
+ acc[blockKey] = timelineTextStreamLength;
1109
+ }
1110
+ return acc;
1111
+ },
1112
+ { ...timelineBlockAnchors }
1113
+ );
1114
+ }, [
1115
+ currentTimelineBlockKeys,
1116
+ isAssistantStreaming,
1117
+ messageRenderOrder,
1118
+ timelineBlockAnchors,
1119
+ timelineTextStreamLength
1120
+ ]);
1121
+ (0, import_react6.useEffect)(() => {
1122
+ const previousTimelineState = previousTimelineStateRef.current;
1123
+ if (previousTimelineState.messageId !== message.id) {
1124
+ if (Object.keys(timelineBlockAnchors).length > 0) {
1125
+ setTimelineBlockAnchors({});
1126
+ }
1127
+ if (Object.keys(visibleTimelineBlockKeys).length > 0) {
1128
+ setVisibleTimelineBlockKeys({});
1129
+ }
1130
+ previousTimelineStateRef.current = {
1131
+ messageId: message.id,
1132
+ blockKeys: currentTimelineBlockKeys,
1133
+ textLength: timelineTextStreamLength
1134
+ };
1135
+ return;
1136
+ }
1137
+ if (messageRenderOrder === "timeline" && isAssistantStreaming) {
1138
+ const previousBlockKeys = new Set(previousTimelineState.blockKeys);
1139
+ const nextAnchors = currentTimelineBlockKeys.reduce(
1140
+ (acc, blockKey) => {
1141
+ const existingAnchor = timelineBlockAnchors[blockKey];
1142
+ if (existingAnchor !== void 0) {
1143
+ acc[blockKey] = existingAnchor;
1144
+ return acc;
1145
+ }
1146
+ if (!previousBlockKeys.has(blockKey)) {
1147
+ acc[blockKey] = timelineTextStreamLength;
1148
+ }
1149
+ return acc;
1150
+ },
1151
+ {}
1152
+ );
1153
+ const hasAnchorChanged = Object.keys(nextAnchors).length !== Object.keys(timelineBlockAnchors).length || Object.entries(nextAnchors).some(
1154
+ ([blockKey, anchor]) => timelineBlockAnchors[blockKey] !== anchor
1155
+ );
1156
+ if (hasAnchorChanged) {
1157
+ setTimelineBlockAnchors(nextAnchors);
1158
+ }
1159
+ } else if (messageRenderOrder !== "timeline" && Object.keys(timelineBlockAnchors).length > 0) {
1160
+ setTimelineBlockAnchors({});
1161
+ }
1162
+ previousTimelineStateRef.current = {
1163
+ messageId: message.id,
1164
+ blockKeys: currentTimelineBlockKeys,
1165
+ textLength: timelineTextStreamLength
1166
+ };
1167
+ }, [
1168
+ currentTimelineBlockKeys,
1169
+ isAssistantStreaming,
1170
+ message.id,
1171
+ message.content,
1172
+ messageRenderOrder,
1173
+ timelineBlockAnchors,
1174
+ timelineTextStreamLength,
1175
+ visibleTimelineBlockKeys
1176
+ ]);
1177
+ (0, import_react6.useEffect)(() => {
1178
+ if (messageRenderOrder !== "timeline") {
1179
+ if (Object.keys(visibleTimelineBlockKeys).length > 0) {
1180
+ setVisibleTimelineBlockKeys({});
1181
+ }
1182
+ return;
1183
+ }
1184
+ const nextVisibleBlockKeys = currentTimelineBlockKeys.reduce(
1185
+ (acc, blockKey) => {
1186
+ if (visibleTimelineBlockKeys[blockKey]) {
1187
+ acc[blockKey] = true;
1188
+ return acc;
1189
+ }
1190
+ const anchor = effectiveTimelineBlockAnchors[blockKey];
1191
+ if (anchor !== void 0 && anchor <= displayedTimelineTextLength) {
1192
+ acc[blockKey] = true;
1193
+ }
1194
+ return acc;
1195
+ },
1196
+ {}
1197
+ );
1198
+ const hasVisibleBlockChanged = Object.keys(nextVisibleBlockKeys).length !== Object.keys(visibleTimelineBlockKeys).length || Object.keys(nextVisibleBlockKeys).some((blockKey) => !visibleTimelineBlockKeys[blockKey]);
1199
+ if (hasVisibleBlockChanged) {
1200
+ setVisibleTimelineBlockKeys(nextVisibleBlockKeys);
1201
+ }
1202
+ }, [
1203
+ currentTimelineBlockKeys,
1204
+ displayedTimelineTextLength,
1205
+ effectiveTimelineBlockAnchors,
1206
+ messageRenderOrder,
1207
+ timelineBlockAnchors,
1208
+ visibleTimelineBlockKeys
1209
+ ]);
1210
+ return {
1211
+ timelineBlockAnchors: effectiveTimelineBlockAnchors,
1212
+ visibleTimelineBlockKeys
1213
+ };
1214
+ };
1215
+
907
1216
  // src/components/chat-thread/components/pde-ai-execution-confirmation-card.tsx
908
1217
  var import_styled = __toESM(require("@emotion/styled"));
909
1218
  var import_jsx_runtime2 = require("@emotion/react/jsx-runtime");
@@ -1114,7 +1423,7 @@ var Value = import_styled3.default.span`
1114
1423
  `;
1115
1424
 
1116
1425
  // src/components/chat-thread/components/pde-ai-questionnaire-card.tsx
1117
- var import_react6 = require("react");
1426
+ var import_react7 = require("react");
1118
1427
  var import_styled4 = __toESM(require("@emotion/styled"));
1119
1428
  var import_jsx_runtime5 = require("@emotion/react/jsx-runtime");
1120
1429
  var OTHER_OPTION_VALUE = "__other__";
@@ -1216,10 +1525,10 @@ var PDEAIQuestionnaireCardInner = ({
1216
1525
  interactive = false,
1217
1526
  onSubmit
1218
1527
  }) => {
1219
- const [answers, setAnswers] = (0, import_react6.useState)(
1528
+ const [answers, setAnswers] = (0, import_react7.useState)(
1220
1529
  () => createInitialAnswers(questionnaire)
1221
1530
  );
1222
- const [errorMessage, setErrorMessage] = (0, import_react6.useState)(null);
1531
+ const [errorMessage, setErrorMessage] = (0, import_react7.useState)(null);
1223
1532
  const handleSubmit = () => {
1224
1533
  const missingQuestions = questionnaire.questions.filter(
1225
1534
  (question) => question.required && isMissingRequiredAnswer(question, answers)
@@ -1655,7 +1964,7 @@ var Detail = import_styled5.default.li`
1655
1964
 
1656
1965
  // src/components/chat-thread/components/image-viewer.tsx
1657
1966
  var import_styled6 = __toESM(require("@emotion/styled"));
1658
- var import_react7 = require("react");
1967
+ var import_react8 = require("react");
1659
1968
  var import_jsx_runtime7 = require("@emotion/react/jsx-runtime");
1660
1969
  var Overlay = import_styled6.default.div`
1661
1970
  position: fixed;
@@ -1674,8 +1983,8 @@ var Img = import_styled6.default.img`
1674
1983
  border-radius: 4px;
1675
1984
  `;
1676
1985
  var ImageViewer = ({ src, alt, onClose }) => {
1677
- const overlayRef = (0, import_react7.useRef)(null);
1678
- (0, import_react7.useEffect)(() => {
1986
+ const overlayRef = (0, import_react8.useRef)(null);
1987
+ (0, import_react8.useEffect)(() => {
1679
1988
  const handleKey = (e) => {
1680
1989
  if (e.key === "Escape")
1681
1990
  onClose();
@@ -1683,7 +1992,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
1683
1992
  document.addEventListener("keydown", handleKey);
1684
1993
  return () => document.removeEventListener("keydown", handleKey);
1685
1994
  }, [onClose]);
1686
- (0, import_react7.useEffect)(() => {
1995
+ (0, import_react8.useEffect)(() => {
1687
1996
  overlayRef.current?.focus();
1688
1997
  }, []);
1689
1998
  const stopPropagation = (e) => e.stopPropagation();
@@ -1846,9 +2155,16 @@ var ChatMessageItemView = ({
1846
2155
  onQuestionnaireSubmit,
1847
2156
  renderMessageBlock
1848
2157
  }) => {
1849
- const { labels } = useChatContext();
1850
- const [activeImage, setActiveImage] = (0, import_react8.useState)(void 0);
1851
- const { displayedBlocks, displayedContent, freshContent, isAssistantStreaming, settledContent } = useChatMessageReveal(message);
2158
+ const { labels, messageRenderOrder = "blocks-first" } = useChatContext();
2159
+ const [activeImage, setActiveImage] = (0, import_react9.useState)(void 0);
2160
+ const {
2161
+ displayedBlocks,
2162
+ displayedContent,
2163
+ freshContent,
2164
+ isAssistantStreaming,
2165
+ isFreshBlockActive,
2166
+ settledContent
2167
+ } = useChatMessageReveal(message);
1852
2168
  const isStoppedAssistant = message.role === "assistant" && message.status === "stopped";
1853
2169
  const attachments = message.attachments ?? [];
1854
2170
  const blocks = message.blocks ?? [];
@@ -1860,6 +2176,22 @@ var ChatMessageItemView = ({
1860
2176
  const canSubmitConfirmation = isPlanMode && typeof onConfirmationSubmit === "function";
1861
2177
  const canSubmitQuestionnaire = isPlanMode && typeof onQuestionnaireSubmit === "function";
1862
2178
  const shouldShowStreamingCaret = isAssistantStreaming && (!shouldRenderStructuredBlocks || hasTextContent);
2179
+ const timelineConsumedText = messageRenderOrder === "timeline" ? getTimelineConsumedText(blocks) : "";
2180
+ const hasConsumedTimelineText = timelineConsumedText.length > 0 && displayedContent.startsWith(timelineConsumedText);
2181
+ const timelineDisplayedContent = hasConsumedTimelineText ? displayedContent.slice(timelineConsumedText.length) : displayedContent;
2182
+ const timelineTextDisplay = buildTimelineTextDisplay(
2183
+ timelineDisplayedContent,
2184
+ isAssistantStreaming,
2185
+ isFreshBlockActive
2186
+ );
2187
+ const displayedTimelineTextLength = getTimelineDisplayUnitCount(timelineDisplayedContent);
2188
+ const { timelineBlockAnchors, visibleTimelineBlockKeys } = useTimelineBlockAnchors({
2189
+ blocks,
2190
+ displayedTimelineTextLength,
2191
+ isAssistantStreaming,
2192
+ message,
2193
+ messageRenderOrder
2194
+ });
1863
2195
  const renderChatMessageBlock = (block, index) => {
1864
2196
  switch (block.type) {
1865
2197
  case "markdown":
@@ -1873,11 +2205,11 @@ var ChatMessageItemView = ({
1873
2205
  `markdown-${index}`
1874
2206
  );
1875
2207
  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}`);
2208
+ 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
2209
  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}`);
2210
+ 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
2211
  case "confirmation_card":
1880
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2212
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1881
2213
  PDEAIExecutionConfirmationCard,
1882
2214
  {
1883
2215
  proposal: block.proposal,
@@ -1890,9 +2222,9 @@ var ChatMessageItemView = ({
1890
2222
  }
1891
2223
  ) }, `confirmation-card-${index}`);
1892
2224
  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}`);
2225
+ 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
2226
  case "questionnaire":
1895
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2227
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1896
2228
  PDEAIQuestionnaireCard,
1897
2229
  {
1898
2230
  questionnaire: block.questionnaire,
@@ -1904,7 +2236,7 @@ var ChatMessageItemView = ({
1904
2236
  }
1905
2237
  ) }, `questionnaire-${index}`);
1906
2238
  case "custom":
1907
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.Fragment, { children: renderMessageBlock?.({
2239
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: renderMessageBlock?.({
1908
2240
  block,
1909
2241
  index,
1910
2242
  message,
@@ -1916,19 +2248,69 @@ var ChatMessageItemView = ({
1916
2248
  return null;
1917
2249
  }
1918
2250
  };
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
- ] });
2251
+ const renderTextContent = (options) => {
2252
+ const textContent = options?.content ?? displayedContent;
2253
+ const localTimelineTextDisplay = options?.displayedBlocks ? void 0 : options?.useTimelineSegmentation && options.content !== void 0 ? buildTimelineTextDisplay(options.content, isAssistantStreaming, isFreshBlockActive) : void 0;
2254
+ const textBlocks = options?.displayedBlocks ?? localTimelineTextDisplay?.displayedBlocks ?? displayedBlocks;
2255
+ const settledText = localTimelineTextDisplay?.settledContent ?? settledContent;
2256
+ const freshText = localTimelineTextDisplay?.freshContent ?? freshContent;
2257
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
2258
+ textBlocks.filter((block) => block.content).map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2259
+ ContentBlock,
2260
+ {
2261
+ "data-testid": block.tone === "fresh" ? "chat-message-fresh-block" : "chat-message-settled-block",
2262
+ "data-block-tone": block.tone,
2263
+ "data-block-index": index,
2264
+ children: renderMarkdownContent(block.content)
2265
+ },
2266
+ `${block.tone}-${index}`
2267
+ )),
2268
+ !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
2269
+ ] });
2270
+ };
2271
+ const renderStaticTextSegment = (content) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentBlock, { "data-testid": "chat-message-settled-block", "data-block-tone": "settled", children: renderMarkdownContent(content) });
2272
+ const bodySegments = (() => {
2273
+ if (!shouldRenderStructuredBlocks && hasTextContent) {
2274
+ return [{ type: "text" }];
2275
+ }
2276
+ if (!shouldRenderStructuredBlocks) {
2277
+ return [];
2278
+ }
2279
+ if (messageRenderOrder === "timeline" && hasTextContent) {
2280
+ const hasAnchoredStructuredBlocks = blocks.some((block, index) => {
2281
+ const blockKey = getTimelineBlockKey(block, index);
2282
+ return blockKey ? timelineBlockAnchors[blockKey] !== void 0 : false;
2283
+ });
2284
+ if (hasAnchoredStructuredBlocks) {
2285
+ return buildAnchoredTimelineSegments({
2286
+ blocks,
2287
+ timelineBlockAnchors,
2288
+ timelineDisplayedBlocks: timelineTextDisplay.displayedBlocks,
2289
+ visibleTimelineBlockKeys
2290
+ });
2291
+ }
2292
+ const orderedTimelineSegments = blocks.map(
2293
+ (block, index) => block.type === "markdown" ? {
2294
+ type: "markdown",
2295
+ content: block.text
2296
+ } : {
2297
+ type: "block",
2298
+ block,
2299
+ index
2300
+ }
2301
+ );
2302
+ if (!timelineConsumedText) {
2303
+ return displayedContent ? [{ type: "text", content: displayedContent }, ...orderedTimelineSegments] : orderedTimelineSegments;
2304
+ }
2305
+ return timelineDisplayedContent ? [...orderedTimelineSegments, { type: "text", content: timelineDisplayedContent }] : orderedTimelineSegments;
2306
+ }
2307
+ const orderedBlocks = blocks.map((block, index) => ({
2308
+ type: "block",
2309
+ block,
2310
+ index
2311
+ }));
2312
+ return hasTextContent ? [...orderedBlocks, { type: "text" }] : orderedBlocks;
2313
+ })();
1932
2314
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1933
2315
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Bubble, { "data-role": message.role, "data-status": message.status ?? "done", children: [
1934
2316
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Header2, { children: [
@@ -1947,17 +2329,18 @@ var ChatMessageItemView = ({
1947
2329
  isStoppedAssistant ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StatusTag, { "data-testid": "chat-message-stopped-tag", children: labels.stoppedResponse }) : null
1948
2330
  ] }),
1949
2331
  /* @__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,
2332
+ 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)(
2333
+ ContentSegment,
2334
+ {
2335
+ "data-testid": "chat-message-content-segment",
2336
+ children: segment.type === "block" ? renderChatMessageBlock(segment.block, segment.index) : segment.type === "text" ? segment.content !== void 0 ? segment.useTimelineSegmentation ? renderTextContent({
2337
+ content: segment.content,
2338
+ displayedBlocks: segment.displayedBlocks,
2339
+ useTimelineSegmentation: true
2340
+ }) : renderStaticTextSegment(segment.content) : renderTextContent() : renderStaticTextSegment(segment.content)
2341
+ },
2342
+ segment.type === "text" ? `text-${index}` : segment.type === "markdown" ? `markdown-${index}` : `${segment.block.type}-${segment.index}`
2343
+ )) }) : null,
1961
2344
  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
2345
  AttachmentButton,
1963
2346
  {
@@ -1984,7 +2367,7 @@ var ChatMessageItemView = ({
1984
2367
  ) : null
1985
2368
  ] });
1986
2369
  };
1987
- var ChatMessageItem = (0, import_react8.memo)(
2370
+ var ChatMessageItem = (0, import_react9.memo)(
1988
2371
  ChatMessageItemView,
1989
2372
  (previousProps, nextProps) => isSameMessage(
1990
2373
  previousProps.message,
@@ -2129,7 +2512,7 @@ var AttachmentImage = import_styled7.default.img`
2129
2512
  var TableWrapper = import_styled7.default.div`
2130
2513
  overflow-x: auto;
2131
2514
  `;
2132
- var caretBlink = import_react9.keyframes`
2515
+ var caretBlink = import_react10.keyframes`
2133
2516
  0%, 49% {
2134
2517
  opacity: 1;
2135
2518
  }
@@ -2138,7 +2521,7 @@ var caretBlink = import_react9.keyframes`
2138
2521
  opacity: 0.2;
2139
2522
  }
2140
2523
  `;
2141
- var shimmer = import_react9.keyframes`
2524
+ var shimmer = import_react10.keyframes`
2142
2525
  0%, 100% {
2143
2526
  transform: scale(0.9) rotate(0deg);
2144
2527
  opacity: 0.55;
@@ -2349,18 +2732,18 @@ var ChatThreadView = ({
2349
2732
  onQuestionnaireSubmit,
2350
2733
  renderMessageBlock
2351
2734
  }) => {
2352
- const containerRef = (0, import_react10.useRef)(null);
2353
- const conversationTurns = (0, import_react10.useMemo)(
2735
+ const containerRef = (0, import_react11.useRef)(null);
2736
+ const conversationTurns = (0, import_react11.useMemo)(
2354
2737
  () => groupConversationTurns(historyMessages, streamingMessage),
2355
2738
  [historyMessages, streamingMessage]
2356
2739
  );
2357
2740
  const latestTurn = conversationTurns[conversationTurns.length - 1];
2358
2741
  const previousTurns = conversationTurns.slice(0, -1);
2359
2742
  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)(() => {
2743
+ const latestUserMessageRef = (0, import_react11.useRef)(null);
2744
+ const reservedSpaceFrameRef = (0, import_react11.useRef)(null);
2745
+ const [latestTurnMinHeight, setLatestTurnMinHeight] = (0, import_react11.useState)(0);
2746
+ const measureLatestTurnMinHeight = (0, import_react11.useCallback)(() => {
2364
2747
  const container = containerRef.current;
2365
2748
  if (!container)
2366
2749
  return;
@@ -2370,7 +2753,7 @@ var ChatThreadView = ({
2370
2753
  const nextMinHeight = Math.max(0, container.clientHeight - paddingTop - paddingBottom);
2371
2754
  setLatestTurnMinHeight((current) => current === nextMinHeight ? current : nextMinHeight);
2372
2755
  }, []);
2373
- const scrollLatestUserMessageToTop = (0, import_react10.useCallback)(() => {
2756
+ const scrollLatestUserMessageToTop = (0, import_react11.useCallback)(() => {
2374
2757
  const container = containerRef.current;
2375
2758
  const target = latestUserMessageRef.current;
2376
2759
  if (!container || !target)
@@ -2390,7 +2773,7 @@ var ChatThreadView = ({
2390
2773
  }
2391
2774
  container.scrollTop = nextScrollTop;
2392
2775
  }, []);
2393
- (0, import_react10.useLayoutEffect)(() => {
2776
+ (0, import_react11.useLayoutEffect)(() => {
2394
2777
  if (reservedSpaceFrameRef.current !== null) {
2395
2778
  window.cancelAnimationFrame(reservedSpaceFrameRef.current);
2396
2779
  reservedSpaceFrameRef.current = null;
@@ -2419,7 +2802,7 @@ var ChatThreadView = ({
2419
2802
  }
2420
2803
  };
2421
2804
  }, [latestUserMessageId, measureLatestTurnMinHeight, scrollLatestUserMessageToTop]);
2422
- (0, import_react10.useLayoutEffect)(() => {
2805
+ (0, import_react11.useLayoutEffect)(() => {
2423
2806
  if (!latestUserMessageId)
2424
2807
  return;
2425
2808
  const handleResize = () => {
@@ -2507,13 +2890,13 @@ var ChatThread = () => {
2507
2890
  const updateQA = useChatStore((s) => s.updateQuestionnaireAnswers);
2508
2891
  const clearSessionError = useChatStore((s) => s.clearSessionError);
2509
2892
  const { sendRef, retryRef, renderMessageBlock, labels } = useChatContext();
2510
- const handleRetry = (0, import_react10.useCallback)(() => {
2893
+ const handleRetry = (0, import_react11.useCallback)(() => {
2511
2894
  if (!activeSessionId)
2512
2895
  return;
2513
2896
  clearSessionError(activeSessionId);
2514
2897
  void retryRef.current();
2515
2898
  }, [activeSessionId, clearSessionError, retryRef]);
2516
- const handleQuestionnaireSubmit = (0, import_react10.useCallback)(
2899
+ const handleQuestionnaireSubmit = (0, import_react11.useCallback)(
2517
2900
  (submission) => {
2518
2901
  if (activeSessionId && submission.sourceMessageId) {
2519
2902
  updateQA(
@@ -2527,7 +2910,7 @@ var ChatThread = () => {
2527
2910
  },
2528
2911
  [activeSessionId, updateQA, sendRef]
2529
2912
  );
2530
- const handleConfirmationSubmit = (0, import_react10.useCallback)(
2913
+ const handleConfirmationSubmit = (0, import_react11.useCallback)(
2531
2914
  (submission) => {
2532
2915
  void sendRef.current(submission.content);
2533
2916
  },
@@ -2612,7 +2995,7 @@ var RetryButton = import_styled9.default.button`
2612
2995
  `;
2613
2996
 
2614
2997
  // src/components/chat-composer/index.tsx
2615
- var import_react14 = require("react");
2998
+ var import_react15 = require("react");
2616
2999
  var import_styled14 = __toESM(require("@emotion/styled"));
2617
3000
 
2618
3001
  // src/components/chat-composer/lib/chat-composer.ts
@@ -2724,10 +3107,10 @@ var resolveSendSession = ({
2724
3107
  };
2725
3108
 
2726
3109
  // src/components/chat-composer/hooks/use-chat-composer.ts
2727
- var import_react12 = require("react");
3110
+ var import_react13 = require("react");
2728
3111
 
2729
3112
  // src/components/chat-composer/hooks/use-composer-attachments.ts
2730
- var import_react11 = require("react");
3113
+ var import_react12 = require("react");
2731
3114
  var SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
2732
3115
  var MAX_COMPOSER_ATTACHMENTS = 10;
2733
3116
  var createObjectUrl = (file) => typeof URL !== "undefined" && typeof URL.createObjectURL === "function" ? URL.createObjectURL(file) : "";
@@ -2741,12 +3124,12 @@ var releaseComposerAttachments = (attachments) => {
2741
3124
  attachments.forEach((attachment) => revokeObjectUrl(attachment.previewUrl));
2742
3125
  };
2743
3126
  var useComposerAttachments = () => {
2744
- const [attachments, setAttachments] = (0, import_react11.useState)([]);
2745
- const attachmentsRef = (0, import_react11.useRef)([]);
2746
- (0, import_react11.useEffect)(() => {
3127
+ const [attachments, setAttachments] = (0, import_react12.useState)([]);
3128
+ const attachmentsRef = (0, import_react12.useRef)([]);
3129
+ (0, import_react12.useEffect)(() => {
2747
3130
  attachmentsRef.current = attachments;
2748
3131
  }, [attachments]);
2749
- (0, import_react11.useEffect)(
3132
+ (0, import_react12.useEffect)(
2750
3133
  () => () => {
2751
3134
  releaseComposerAttachments(attachmentsRef.current);
2752
3135
  },
@@ -2859,10 +3242,10 @@ var useChatComposer = () => {
2859
3242
  const clearSessionError = useChatStore((s) => s.clearSessionError);
2860
3243
  const setPreferredMode = useChatStore((s) => s.setPreferredMode);
2861
3244
  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 () => {
3245
+ const [availableModels, setAvailableModels] = (0, import_react13.useState)([]);
3246
+ const [isModelsLoading, setIsModelsLoading] = (0, import_react13.useState)(true);
3247
+ const [isModelsError, setIsModelsError] = (0, import_react13.useState)(false);
3248
+ const fetchModels = (0, import_react13.useCallback)(async () => {
2866
3249
  setIsModelsLoading(true);
2867
3250
  setIsModelsError(false);
2868
3251
  try {
@@ -2874,31 +3257,31 @@ var useChatComposer = () => {
2874
3257
  setIsModelsLoading(false);
2875
3258
  }
2876
3259
  }, [transport]);
2877
- (0, import_react12.useEffect)(() => {
3260
+ (0, import_react13.useEffect)(() => {
2878
3261
  void fetchModels();
2879
3262
  }, [fetchModels]);
2880
3263
  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);
3264
+ const [value, setValue] = (0, import_react13.useState)("");
3265
+ const [selectedModel, setSelectedModel] = (0, import_react13.useState)("");
3266
+ const [selectedMode, setSelectedModeLocal] = (0, import_react13.useState)(DEFAULT_CHAT_AGENT_MODE);
3267
+ const [attachmentNotice, setAttachmentNotice] = (0, import_react13.useState)(null);
2885
3268
  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)(() => {
3269
+ const abortControllerRef = (0, import_react13.useRef)(null);
3270
+ const stopRequestRef = (0, import_react13.useRef)(null);
3271
+ const lastRequestRef = (0, import_react13.useRef)(null);
3272
+ (0, import_react13.useEffect)(() => {
2890
3273
  setSelectedModel(
2891
3274
  (current) => resolveSelectedChatModel({ currentModel: current, availableModels, isModelsLoading })
2892
3275
  );
2893
3276
  }, [availableModels, isModelsLoading]);
2894
- (0, import_react12.useEffect)(() => {
3277
+ (0, import_react13.useEffect)(() => {
2895
3278
  if (activeSession) {
2896
3279
  setSelectedModeLocal(activeSession.mode ?? DEFAULT_CHAT_AGENT_MODE);
2897
3280
  return;
2898
3281
  }
2899
3282
  setSelectedModeLocal(preferredMode ?? DEFAULT_CHAT_AGENT_MODE);
2900
3283
  }, [activeSession, preferredMode]);
2901
- (0, import_react12.useEffect)(() => {
3284
+ (0, import_react13.useEffect)(() => {
2902
3285
  if (!attachmentNotice)
2903
3286
  return;
2904
3287
  const timeoutId = window.setTimeout(
@@ -2917,7 +3300,7 @@ var useChatComposer = () => {
2917
3300
  stopRequestRef.current.timeoutId = null;
2918
3301
  }
2919
3302
  };
2920
- const clearStopRequest = (0, import_react12.useCallback)((sessionId) => {
3303
+ const clearStopRequest = (0, import_react13.useCallback)((sessionId) => {
2921
3304
  if (!stopRequestRef.current)
2922
3305
  return;
2923
3306
  if (sessionId && stopRequestRef.current.sessionId !== sessionId)
@@ -2925,7 +3308,7 @@ var useChatComposer = () => {
2925
3308
  clearStopTimeout(sessionId);
2926
3309
  stopRequestRef.current = null;
2927
3310
  }, []);
2928
- const finalizeStop = (0, import_react12.useCallback)(
3311
+ const finalizeStop = (0, import_react13.useCallback)(
2929
3312
  (sessionId) => {
2930
3313
  if (stopRequestRef.current?.sessionId === sessionId) {
2931
3314
  if (stopRequestRef.current.finalized)
@@ -2940,7 +3323,7 @@ var useChatComposer = () => {
2940
3323
  },
2941
3324
  [clearStopRequest, finalizeStoppedStreamingMessage]
2942
3325
  );
2943
- const runStream = (0, import_react12.useCallback)(
3326
+ const runStream = (0, import_react13.useCallback)(
2944
3327
  async ({
2945
3328
  localSessionId,
2946
3329
  sessionId,
@@ -3029,7 +3412,7 @@ var useChatComposer = () => {
3029
3412
  setSessionError
3030
3413
  ]
3031
3414
  );
3032
- const send = (0, import_react12.useCallback)(
3415
+ const send = (0, import_react13.useCallback)(
3033
3416
  async (contentOverride) => {
3034
3417
  const content = (contentOverride ?? value).trim();
3035
3418
  const hasText = Boolean(content);
@@ -3177,14 +3560,14 @@ var useChatComposer = () => {
3177
3560
  };
3178
3561
 
3179
3562
  // src/components/chat-composer/components/chat-composer-attachment-list.tsx
3180
- var import_react13 = require("react");
3563
+ var import_react14 = require("react");
3181
3564
  var import_styled10 = __toESM(require("@emotion/styled"));
3182
3565
  var import_jsx_runtime11 = require("@emotion/react/jsx-runtime");
3183
3566
  var ChatComposerAttachmentList = ({
3184
3567
  attachments,
3185
3568
  onRemoveAttachment
3186
3569
  }) => {
3187
- const [activeImage, setActiveImage] = (0, import_react13.useState)(null);
3570
+ const [activeImage, setActiveImage] = (0, import_react14.useState)(null);
3188
3571
  if (!attachments.length) {
3189
3572
  return null;
3190
3573
  }
@@ -3676,7 +4059,7 @@ var ChatComposerView = ({
3676
4059
  onStop,
3677
4060
  onSend
3678
4061
  }) => {
3679
- const imageInputRef = (0, import_react14.useRef)(null);
4062
+ const imageInputRef = (0, import_react15.useRef)(null);
3680
4063
  const canSend = canSendChatMessage({
3681
4064
  value,
3682
4065
  attachmentCount: attachments.length,
@@ -3788,7 +4171,7 @@ var ChatComposer = () => {
3788
4171
  const { labels, sendRef, retryRef, enableImageAttachments } = useChatContext();
3789
4172
  const { state, actions } = useChatComposer();
3790
4173
  const { send, retry } = actions;
3791
- (0, import_react14.useEffect)(() => {
4174
+ (0, import_react15.useEffect)(() => {
3792
4175
  sendRef.current = send;
3793
4176
  retryRef.current = async () => {
3794
4177
  retry();
@@ -3909,10 +4292,10 @@ var AttachButton = import_styled14.default.button`
3909
4292
  var import_styled16 = __toESM(require("@emotion/styled"));
3910
4293
 
3911
4294
  // src/components/chat-conversation-list/components/chat-session-item.tsx
3912
- var import_react15 = require("react");
4295
+ var import_react16 = require("react");
3913
4296
  var import_styled15 = __toESM(require("@emotion/styled"));
3914
4297
  var import_jsx_runtime16 = require("@emotion/react/jsx-runtime");
3915
- var ChatSessionItem = (0, import_react15.memo)(
4298
+ var ChatSessionItem = (0, import_react16.memo)(
3916
4299
  ({ session, isActive, modeLabel, onClick }) => {
3917
4300
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3918
4301
  SessionButton,
@@ -4108,6 +4491,7 @@ var Workspace = import_styled17.default.section`
4108
4491
  AiChat,
4109
4492
  AiChatProvider,
4110
4493
  CHAT_AGENT_MODES,
4494
+ CHAT_MESSAGE_RENDER_ORDERS,
4111
4495
  ChatComposer,
4112
4496
  ChatConversationList,
4113
4497
  ChatThread,