@ai-matrx/chat 0.4.2 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/agent-copy/RichCopySplit.d.ts +17 -0
  3. package/dist/agent-copy/RichCopySplit.js +34 -0
  4. package/dist/agents/components/agent-widgets/chat-assistant/AssistantMessageCard.js +1 -1
  5. package/dist/agents/components/chat/ConversationRecordsChip.js +1 -1
  6. package/dist/agents/components/context-items/bodies/WorkingDocumentBody.d.ts +5 -2
  7. package/dist/agents/components/context-items/bodies/WorkingDocumentBody.js +6 -1
  8. package/dist/agents/components/context-policies-display/ContextValueBody.js +1 -1
  9. package/dist/agents/components/context-preview/ContextCompareView.js +1 -1
  10. package/dist/agents/components/custom-agent/CustomAgentWindow.js +1 -1
  11. package/dist/agents/components/inputs/smart-input/AgentTextarea.d.ts +6 -1
  12. package/dist/agents/components/inputs/smart-input/AgentTextarea.js +2 -2
  13. package/dist/agents/components/inputs/smart-input/ComposerToolsNotice.d.ts +1 -0
  14. package/dist/agents/components/inputs/smart-input/ComposerToolsNotice.js +5 -0
  15. package/dist/agents/components/inputs/smart-input/ConversationContextRail.d.ts +5 -1
  16. package/dist/agents/components/inputs/smart-input/ConversationContextRail.js +6 -1
  17. package/dist/agents/components/inputs/smart-input/InboxQueueStrip.d.ts +6 -1
  18. package/dist/agents/components/inputs/smart-input/InboxQueueStrip.js +6 -1
  19. package/dist/agents/components/inputs/smart-input/InputActionButtons.js +8 -6
  20. package/dist/agents/components/inputs/smart-input/SmartInputFileDropTarget.d.ts +5 -1
  21. package/dist/agents/components/inputs/smart-input/SmartInputFileDropTarget.js +8 -1
  22. package/dist/agents/components/inputs/smart-input/composer/ComposerAgentPill.js +2 -2
  23. package/dist/agents/components/inputs/smart-input/composer/ComposerChipsRow.d.ts +5 -2
  24. package/dist/agents/components/inputs/smart-input/composer/ComposerChipsRow.js +6 -1
  25. package/dist/agents/components/inputs/smart-input/composer/ComposerMetaRow.d.ts +6 -8
  26. package/dist/agents/components/inputs/smart-input/composer/ComposerMetaRow.js +13 -1
  27. package/dist/agents/components/inputs/smart-input/composer/useOutputShapeCatalog.d.ts +1 -1
  28. package/dist/agents/components/inputs/smart-input/composer/useOutputShapeCatalog.js +1 -1
  29. package/dist/agents/components/live-run/LiveRunDisplay.js +1 -1
  30. package/dist/agents/components/live-run/RunSetDisplay.js +1 -1
  31. package/dist/agents/components/memory/components/AgentMemoryAllView.js +1 -1
  32. package/dist/agents/components/messages-display/assistant/AgentAssistantMessage.d.ts +1 -0
  33. package/dist/agents/components/messages-display/assistant/AgentAssistantMessage.js +4 -3
  34. package/dist/agents/components/messages-display/assistant/AgentEmptyMessageDisplay.js +1 -1
  35. package/dist/agents/components/messages-display/assistant/AssistantMessageFooter.d.ts +2 -2
  36. package/dist/agents/components/messages-display/assistant/AssistantMessageFooter.js +4 -7
  37. package/dist/agents/components/messages-display/assistant/InPlaceAnswerEditor.js +2 -2
  38. package/dist/agents/components/messages-display/citations/MessageSourcesRow.js +1 -1
  39. package/dist/agents/components/messages-display/rich-document/chat-message-source.d.ts +2 -0
  40. package/dist/agents/components/messages-display/rich-document/chat-message-source.js +41 -0
  41. package/dist/agents/components/messages-display/rich-document/chatMessageActions.d.ts +31 -0
  42. package/dist/agents/components/messages-display/rich-document/chatMessageActions.js +39 -0
  43. package/dist/agents/components/messages-display/user/AgentUserMessage.d.ts +1 -0
  44. package/dist/agents/components/messages-display/user/AgentUserMessage.js +7 -4
  45. package/dist/agents/components/messages-display/user/CollabNoteMessage.js +1 -1
  46. package/dist/agents/components/messages-display/user/UserActionBar.js +49 -39
  47. package/dist/agents/components/working-document/WorkingDocumentEditor.d.ts +1 -1
  48. package/dist/agents/components/working-document/WorkingDocumentPanel.js +2 -1
  49. package/dist/agents/identity/run-tier-store.js +3 -0
  50. package/dist/agents/redux/agent-definition/cache-bust-middleware.js +2 -0
  51. package/dist/agents/redux/agent-settings/agentSettingsSlice.d.ts +0 -4
  52. package/dist/agents/redux/agent-settings/agentSettingsSlice.js +12 -5
  53. package/dist/agents/redux/execution-system/host-conversations/host-conversation.thunks.d.ts +4 -1
  54. package/dist/agents/redux/execution-system/host-conversations/host-conversation.thunks.js +45 -0
  55. package/dist/agents/redux/execution-system/inbox/inbox-turn-end.middleware.js +2 -1
  56. package/dist/agents/redux/execution-system/instance-ui-state/run-configuration-persist.js +2 -0
  57. package/dist/agents/redux/execution-system/messages/messages.selectors.js +1 -1
  58. package/dist/agents/redux/execution-system/thunks/execute-instance.thunk.js +6 -0
  59. package/dist/agents/redux/execution-system/thunks/process-stream.js +1 -1
  60. package/dist/agents/redux/execution-system/utils/assemble-cx-content-blocks.js +2 -1
  61. package/dist/agents/redux/execution-system/utils/inbound-render-block.d.ts +8 -0
  62. package/dist/agents/redux/execution-system/utils/inbound-render-block.js +17 -2
  63. package/dist/agents/redux/execution-system/utils/normalize-content-blocks.js +1 -1
  64. package/dist/agents/redux/execution-system/utils/progress-data-block.d.ts +11 -0
  65. package/dist/agents/redux/execution-system/utils/progress-data-block.js +37 -0
  66. package/dist/agents/redux/execution-system/utils/stream-block-accumulator.js +10 -8
  67. package/dist/agents/redux/mcp/mcp.slice.js +15 -7
  68. package/dist/agents/redux/tools/tools.thunks.js +3 -0
  69. package/dist/agents/runtime-reconnect/ServerOperationBanner.d.ts +6 -1
  70. package/dist/agents/runtime-reconnect/ServerOperationBanner.js +6 -1
  71. package/dist/agents/ui-first-tools/ui/ApprovalCard.js +1 -1
  72. package/dist/agents/ui-first-tools/ui/AskCard.js +1 -1
  73. package/dist/agents/ui-first-tools/ui/lists/TaskPanel.js +1 -1
  74. package/dist/conversation/hooks/useDomCapturePrint.js +1 -1
  75. package/dist/conversation/utils/markdown-print.js +1 -1
  76. package/dist/cx-chat/components/messages/AssistantMessage.js +3 -5
  77. package/dist/cx-conversation/AssistantMessage.js +3 -5
  78. package/dist/host/app-data-slots.d.ts +85 -0
  79. package/dist/host/app-data-slots.js +42 -0
  80. package/dist/host/bare-host-chrome.js +1 -0
  81. package/dist/host/defaults/prefs.d.ts +11 -0
  82. package/dist/host/defaults/prefs.js +43 -0
  83. package/dist/host/defaults/workspace-gate.js +2 -1
  84. package/dist/host/index.d.ts +1 -1
  85. package/dist/host/index.js +2 -1
  86. package/dist/host/react.js +16 -1
  87. package/dist/host/source.d.ts +21 -0
  88. package/dist/host/ui-slots.d.ts +1 -23
  89. package/dist/host/ui-slots.js +0 -34
  90. package/dist/public-chat/components/PublicMessageOptionsMenu.js +2 -1
  91. package/dist/surfaces/redux/surfaceConfigSlice.js +2 -0
  92. package/dist/surfaces/redux/userStateSlice.js +3 -1
  93. package/dist/surfaces/runtime/agent-offer.js +1 -1
  94. package/dist/surfaces/runtime/surface-writeback.js +1 -1
  95. package/dist/tool-call-visualization/db-renderer/fetchToolRendererRow.js +2 -0
  96. package/dist/tool-call-visualization/renderers/agent-call/AgentCallInline.js +1 -1
  97. package/dist/tool-call-visualization/renderers/agent-call/CollabCallCard.js +1 -1
  98. package/dist/tool-call-visualization/renderers/fs/FsInline.js +1 -1
  99. package/dist/tool-call-visualization/renderers/random-wheel/RandomWheelInline.js +1 -1
  100. package/dist/tool-call-visualization/renderers/research/ResearchOverlay.js +4 -4
  101. package/dist/tool-call-visualization/renderers/research/SubagentReportBlock.js +2 -2
  102. package/dist/tool-call-visualization/renderers/scrape/ScrapeOverlay.js +1 -1
  103. package/dist/tool-call-visualization/renderers/search/SearchInline.js +1 -1
  104. package/dist/tool-call-visualization/renderers/search/SearchOverlay.js +1 -1
  105. package/dist/tool-call-visualization/renderers/sql/SqlInline.js +1 -1
  106. package/dist/tool-call-visualization/result-fields/KeyValueGrid.js +1 -1
  107. package/dist/tool-call-visualization/result-fields/ResultMarkdown.js +1 -1
  108. package/dist/tool-call-visualization/result-fields/ResultValue.js +1 -1
  109. package/dist/tool-call-visualization/surface-write/SurfaceWriteDiff.js +1 -1
  110. package/dist/ui/AudioOutputBlockSkeleton.d.ts +17 -0
  111. package/dist/ui/AudioOutputBlockSkeleton.js +78 -0
  112. package/dist/ui/chat-protocol-from-stream.d.ts +60 -0
  113. package/dist/ui/chat-protocol-from-stream.js +135 -0
  114. package/dist/ui/markdown-stream/EnhancedChatMarkdown.d.ts +59 -0
  115. package/dist/ui/markdown-stream/EnhancedChatMarkdown.js +1108 -0
  116. package/dist/ui/markdown-stream/MarkdownStream.d.ts +88 -0
  117. package/dist/ui/markdown-stream/MarkdownStream.js +14 -0
  118. package/dist/ui/markdown-stream/MarkdownStreamImpl.d.ts +4 -0
  119. package/dist/ui/markdown-stream/MarkdownStreamImpl.js +86 -0
  120. package/dist/ui/markdown-stream/StreamAwareChatMarkdown.d.ts +58 -0
  121. package/dist/ui/markdown-stream/StreamAwareChatMarkdown.js +294 -0
  122. package/dist/ui/markdown-stream/internal-handlers/AgentCallChildTrace.d.ts +22 -0
  123. package/dist/ui/markdown-stream/internal-handlers/AgentCallChildTrace.js +128 -0
  124. package/dist/ui/markdown-stream/internal-handlers/InlineAssistantError.d.ts +3 -0
  125. package/dist/ui/markdown-stream/internal-handlers/InlineAssistantError.js +26 -0
  126. package/dist/ui/markdown-stream/internal-handlers/InlineThinkingSlot.d.ts +14 -0
  127. package/dist/ui/markdown-stream/internal-handlers/InlineThinkingSlot.js +23 -0
  128. package/dist/ui/markdown-stream/internal-handlers/ToolHandlers.d.ts +42 -0
  129. package/dist/ui/markdown-stream/internal-handlers/ToolHandlers.js +109 -0
  130. package/dist/ui/markdown-stream/useBoundAgentOutputSchema.d.ts +2 -0
  131. package/dist/ui/markdown-stream/useBoundAgentOutputSchema.js +33 -0
  132. package/dist/window-panels/windows/agents/AgentAssistantMarkdownDebugWindow.js +1 -1
  133. package/package.json +7 -5
  134. package/dist/host/content-ir-slots.d.ts +0 -235
  135. package/dist/host/content-ir-slots.js +0 -135
  136. package/dist/host/markdown-slots.d.ts +0 -53
  137. package/dist/host/markdown-slots.js +0 -32
  138. package/dist/host/rich-document-slots.d.ts +0 -123
  139. package/dist/host/rich-document-slots.js +0 -36
  140. package/dist/utils/content-ir/report-kind-at-raw-renderer.d.ts +0 -19
  141. package/dist/utils/content-ir/report-kind-at-raw-renderer.js +0 -32
@@ -0,0 +1,1108 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState, useEffect, useLayoutEffect, useMemo, useCallback, useRef } from "react";
4
+ import { cn } from "@ai-matrx/design-system";
5
+ import { splitContentIntoBlocksV2 } from "@ai-matrx/rich-content/display/markdown-classification/processors/utils/content-splitter-v2";
6
+ import { renderSettledFromRecord, settledOneShotBlocks } from "@ai-matrx/rich-content/display/chat-markdown/settle-stream-blocks";
7
+ import { expandTextBlocksInList } from "@ai-matrx/rich-content/display/markdown-classification/processors/utils/expand-text-blocks";
8
+ import { reuseUnchangedBlocks } from "@ai-matrx/rich-content/display/chat-markdown/stable-blocks";
9
+ import { useProgressiveMount } from "@ai-matrx/rich-content/display/chat-markdown/progressive-mount";
10
+ import { renderBlockToContentBlock } from "@ai-matrx/rich-content/display/chat-markdown/render-block-to-content-block";
11
+ import { DocumentFootnotes, DocumentNumberingProvider } from "@ai-matrx/rich-content/markdown-core/syntax/elements/DocumentNumbering";
12
+ import { OptionalMarkdownSourceEditProvider } from "@ai-matrx/rich-content/markdown-core/syntax/elements/MarkdownSourceEdit";
13
+ function MaybeSourceEdit({ source, save, children }) {
14
+ return /* @__PURE__ */ jsx(OptionalMarkdownSourceEditProvider, { source, save, children });
15
+ }
16
+ import { RichCopySplit } from "../../agent-copy/RichCopySplit.js";
17
+ import { ShimmerText } from "../ShimmerText.js";
18
+ import {
19
+ RunJobWorkingLine,
20
+ useIsRunJob
21
+ } from "../../agents/components/run/RunJobWorkingLine.js";
22
+ import { GenerationJobCard } from "../../agents/components/run/GenerationJobCard.js";
23
+ import { selectRequestGenerationJob } from "../../agents/redux/execution-system/active-requests/active-requests.selectors.js";
24
+ import { FullScreenMarkdownEditor } from "../../host/app-data-slots.js";
25
+ import { InlineStatusIndicator } from "@ai-matrx/rich-content/display/chat-markdown/internal-handlers/InlineStatusIndicator";
26
+ import { InlineThinkingSlot } from "./internal-handlers/InlineThinkingSlot.js";
27
+ import {
28
+ selectAccumulatedTextWithCitationMarkers,
29
+ selectIsReasoningStreaming,
30
+ selectUnifiedSlotRange,
31
+ selectAgentCallChildSlots,
32
+ selectAllRenderBlocks,
33
+ selectToolLifecycleMap,
34
+ selectLiveCitationMarkersByBlockId,
35
+ blockCarriesDataNotText,
36
+ blockHasSomethingToRender,
37
+ verbalizedDecisionJsonTextBlockIds
38
+ } from "../../agents/redux/execution-system/active-requests/active-requests.selectors.js";
39
+ import {
40
+ insertCitationMarkers
41
+ } from "../../agents/redux/execution-system/messages/message-citations.js";
42
+ import {
43
+ foldAgentWork,
44
+ SHORT_TEXT_FOLD_MAX
45
+ } from "../../tool-call-visualization/grouping/foldAgentWork.js";
46
+ import { AgentWorkGroup } from "../../tool-call-visualization/components/AgentWorkGroup.js";
47
+ import { holdsADecision, recordHoldsADecision } from "../../tool-call-visualization/components/holdsADecision.js";
48
+ import {
49
+ EXPERT_WORKING_LABEL,
50
+ useMachineFramesVisible
51
+ } from "../../agents/components/shared/transcript-audience.js";
52
+ import { getToolDisplayMode } from "../../tool-call-visualization/registry/registry.js";
53
+ import { isCloudBrowserToolName } from "../../tool-call-visualization/renderers/cloud-browser/cloudBrowserRun.js";
54
+ import { collectCloudBrowserRun } from "../../tool-call-visualization/grouping/groupCloudBrowserRuns.js";
55
+ import {
56
+ selectMessageInterleavedContent,
57
+ selectMessagesInterleavedRuns
58
+ } from "../../agents/redux/execution-system/messages/messages.selectors.js";
59
+ import { useAppSelector } from "../../store/hooks.js";
60
+ import { ToolCard, ToolBatch } from "./internal-handlers/ToolHandlers.js";
61
+ import { InlineAssistantError } from "./internal-handlers/InlineAssistantError.js";
62
+ import { PlainTextFallback } from "@ai-matrx/rich-content/display/chat-markdown/internal-handlers/PlainTextFallback";
63
+ import { SafeBlockRenderer } from "@ai-matrx/rich-content/display/chat-markdown/internal-handlers/SafeBlockRenderer";
64
+ import { MarkdownStreamingProvider } from "@ai-matrx/rich-content/markdown-core/streaming-context";
65
+ import { useBoundAgentOutputSchema } from "./useBoundAgentOutputSchema.js";
66
+ import { MarkdownErrorBoundary } from "@ai-matrx/rich-content/display/chat-markdown/internal-handlers/MarkdownErrorBoundary";
67
+ import { ErrorAlchemyMenu } from "../../host/ui-slots.js";
68
+ const _EMPTY_SEGMENTS = [];
69
+ const _EMPTY_SLOTS = [];
70
+ const _selectEmptyString = () => "";
71
+ const _selectFalse = () => false;
72
+ const _selectEmptySegments = () => _EMPTY_SEGMENTS;
73
+ const _selectNoRuns = () => null;
74
+ const _selectEmptySlots = () => _EMPTY_SLOTS;
75
+ const _selectEmptyRenderBlocks = () => void 0;
76
+ const _EMPTY_CITATION_MARKERS = {};
77
+ const _selectEmptyCitationMarkers = () => _EMPTY_CITATION_MARKERS;
78
+ const TOOL_BATCH_MIN = 2;
79
+ function groupConsecutiveToolSlots(slots, getBatchKind, isCloudBrowserBridge) {
80
+ const out = [];
81
+ let browserRunOrder = 0;
82
+ for (let i = 0; i < slots.length; ) {
83
+ const s = slots[i];
84
+ const batchKind = s.kind === "tool" ? getBatchKind(s.callId) : null;
85
+ if (s.kind === "tool" && batchKind === "cloud-browser") {
86
+ const run = collectCloudBrowserRun(slots, i, (candidate) => {
87
+ if (candidate.kind === "tool" && getBatchKind(candidate.callId) === "cloud-browser") {
88
+ return "browser";
89
+ }
90
+ return isCloudBrowserBridge(candidate) ? "bridge" : "break";
91
+ });
92
+ out.push({
93
+ kind: "tool_batch",
94
+ callIds: run.browserItems.map(
95
+ (candidate) => candidate.callId
96
+ ),
97
+ seq: s.seq,
98
+ batchKind,
99
+ browserRunOrder,
100
+ browserBreakBefore: browserRunOrder > 0,
101
+ browserBreakAfter: run.breakAfter
102
+ });
103
+ out.push(...run.bridgeItems);
104
+ browserRunOrder++;
105
+ i = run.nextIndex;
106
+ continue;
107
+ }
108
+ if (s.kind === "tool" && batchKind) {
109
+ const callIds = [s.callId];
110
+ let j = i + 1;
111
+ while (j < slots.length) {
112
+ const candidate = slots[j];
113
+ if (!candidate || candidate.kind !== "tool" || getBatchKind(candidate.callId) !== batchKind) {
114
+ break;
115
+ }
116
+ callIds.push(candidate.callId);
117
+ j++;
118
+ }
119
+ out.push(
120
+ callIds.length >= TOOL_BATCH_MIN ? { kind: "tool_batch", callIds, seq: s.seq, batchKind } : s
121
+ );
122
+ i = j;
123
+ } else {
124
+ out.push(s);
125
+ i++;
126
+ }
127
+ }
128
+ return out;
129
+ }
130
+ function groupConsecutiveDbTools(segments, getBatchKind, isCloudBrowserBridge) {
131
+ const out = [];
132
+ let browserRunOrder = 0;
133
+ for (let i = 0; i < segments.length; ) {
134
+ const seg = segments[i];
135
+ const batchKind = seg.type === "db_tool" ? getBatchKind(seg) : null;
136
+ if (seg.type === "db_tool" && batchKind === "cloud-browser") {
137
+ const run = collectCloudBrowserRun(segments, i, (candidate) => {
138
+ if (candidate.type === "db_tool" && getBatchKind(candidate) === "cloud-browser") {
139
+ return "browser";
140
+ }
141
+ return isCloudBrowserBridge(candidate) ? "bridge" : "break";
142
+ });
143
+ out.push({
144
+ type: "db_tool_batch",
145
+ segments: run.browserItems,
146
+ key: `db-tool-batch-${seg.callId}`,
147
+ batchKind,
148
+ browserRunOrder,
149
+ browserBreakBefore: browserRunOrder > 0,
150
+ browserBreakAfter: run.breakAfter
151
+ });
152
+ out.push(...run.bridgeItems);
153
+ browserRunOrder++;
154
+ i = run.nextIndex;
155
+ continue;
156
+ }
157
+ if (seg.type === "db_tool" && batchKind) {
158
+ const run = [seg];
159
+ let j = i + 1;
160
+ while (j < segments.length) {
161
+ const candidate = segments[j];
162
+ if (!candidate || candidate.type !== "db_tool" || getBatchKind(candidate) !== batchKind) {
163
+ break;
164
+ }
165
+ run.push(candidate);
166
+ j++;
167
+ }
168
+ out.push(
169
+ run.length >= TOOL_BATCH_MIN ? {
170
+ type: "db_tool_batch",
171
+ segments: run,
172
+ key: `db-tool-batch-${run[0].callId}`,
173
+ batchKind
174
+ } : seg
175
+ );
176
+ i = j;
177
+ } else {
178
+ out.push(seg);
179
+ i++;
180
+ }
181
+ }
182
+ return out;
183
+ }
184
+ function flattenWorkSlots(items) {
185
+ return items.flatMap(
186
+ (item) => item.kind === "tool_batch" && item.batchKind === "default" ? item.callIds.map((callId) => ({
187
+ kind: "tool",
188
+ callId,
189
+ seq: item.seq
190
+ })) : [item]
191
+ );
192
+ }
193
+ function flattenWorkSegments(items) {
194
+ return items.flatMap(
195
+ (item) => item.type === "db_tool_batch" && item.batchKind === "default" ? item.segments : [item]
196
+ );
197
+ }
198
+ function toolSpan(startedAt, completedAt) {
199
+ if (!startedAt || !completedAt) return null;
200
+ const start = Date.parse(startedAt);
201
+ const end = Date.parse(completedAt);
202
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end < start) {
203
+ return null;
204
+ }
205
+ return { start, end };
206
+ }
207
+ function mergeSpans(spans) {
208
+ let start = Infinity;
209
+ let end = -Infinity;
210
+ for (const s of spans) {
211
+ if (!s) continue;
212
+ if (s.start < start) start = s.start;
213
+ if (s.end > end) end = s.end;
214
+ }
215
+ return end >= start ? { start, end } : null;
216
+ }
217
+ function classifyTextForFold(text) {
218
+ const trimmed = text?.trim() ?? "";
219
+ if (trimmed.length === 0) return "shortText";
220
+ return trimmed.length <= SHORT_TEXT_FOLD_MAX ? "shortText" : "visible";
221
+ }
222
+ const EnhancedChatMarkdownInternal = ({
223
+ requestId,
224
+ recordMessageIds,
225
+ streamSlotStart,
226
+ streamSlotEnd,
227
+ agentCallId,
228
+ turnId,
229
+ conversationId,
230
+ content,
231
+ taskId,
232
+ className,
233
+ isStreamActive,
234
+ onContentChange,
235
+ analysisData,
236
+ messageId,
237
+ allowFullScreenEditor = true,
238
+ hideCopyButton = true,
239
+ serverProcessedBlocks,
240
+ applyLocalEdits = true
241
+ }) => {
242
+ const [isEditorOpen, setIsEditorOpen] = useState(false);
243
+ const outputSchema = useBoundAgentOutputSchema(conversationId);
244
+ const [editedContent, setEditedContent] = useState(null);
245
+ const [hasError, setHasError] = useState(false);
246
+ const requestTextSelector = useMemo(
247
+ () => requestId ? selectAccumulatedTextWithCitationMarkers(requestId) : _selectEmptyString,
248
+ [requestId]
249
+ );
250
+ const requestText = useAppSelector(requestTextSelector);
251
+ const liveCitationMarkersSelector = useMemo(
252
+ () => requestId ? selectLiveCitationMarkersByBlockId(requestId) : _selectEmptyCitationMarkers,
253
+ [requestId]
254
+ );
255
+ const liveCitationMarkersByBlockId = useAppSelector(
256
+ liveCitationMarkersSelector
257
+ );
258
+ const isReasoningActive = useAppSelector(
259
+ requestId ? selectIsReasoningStreaming(requestId) : _selectFalse
260
+ );
261
+ const isRunJob = useIsRunJob(requestId);
262
+ const isVideoJob = useAppSelector(
263
+ requestId ? selectRequestGenerationJob(requestId) : () => null
264
+ )?.kind === "video";
265
+ const unifiedSlotsSelector = useMemo(
266
+ () => requestId ? agentCallId ? (
267
+ // One collaboration child's blocks (the card's half of D209).
268
+ selectAgentCallChildSlots(requestId, agentCallId)
269
+ ) : selectUnifiedSlotRange(requestId, streamSlotStart, streamSlotEnd) : _selectEmptySlots,
270
+ [requestId, agentCallId, streamSlotStart, streamSlotEnd]
271
+ );
272
+ const unifiedSlots = useAppSelector(unifiedSlotsSelector);
273
+ const singleRecordContent = useAppSelector(
274
+ messageId && conversationId ? selectMessageInterleavedContent(conversationId, messageId) : _selectEmptySegments
275
+ );
276
+ const recordRunsKey = recordMessageIds && recordMessageIds.length > 1 ? recordMessageIds.join("|") : "";
277
+ const recordRunsSelector = useMemo(
278
+ () => recordRunsKey && conversationId ? selectMessagesInterleavedRuns(conversationId, recordRunsKey.split("|")) : _selectNoRuns,
279
+ [recordRunsKey, conversationId]
280
+ );
281
+ const recordRuns = useAppSelector(recordRunsSelector);
282
+ const messageInterleavedRuns = useMemo(
283
+ () => recordRuns ?? [singleRecordContent],
284
+ [recordRuns, singleRecordContent]
285
+ );
286
+ const messageInterleavedContent = useMemo(
287
+ () => messageInterleavedRuns.length === 1 ? messageInterleavedRuns[0] : messageInterleavedRuns.flat(),
288
+ [messageInterleavedRuns]
289
+ );
290
+ const renderBlocksSelector = useMemo(
291
+ () => requestId ? selectAllRenderBlocks(requestId) : _selectEmptyRenderBlocks,
292
+ [requestId]
293
+ );
294
+ const reduxRenderBlocks = useAppSelector(renderBlocksSelector);
295
+ const renderBlocksMap = useMemo(() => {
296
+ if (!reduxRenderBlocks) return {};
297
+ const map = {};
298
+ for (const b of reduxRenderBlocks) {
299
+ map[b.blockId] = b;
300
+ }
301
+ return map;
302
+ }, [reduxRenderBlocks]);
303
+ const hiddenDecisionJsonTextBlockIds = useMemo(
304
+ () => verbalizedDecisionJsonTextBlockIds(reduxRenderBlocks),
305
+ [reduxRenderBlocks]
306
+ );
307
+ const hasReduxRenderBlocks = !!(reduxRenderBlocks && reduxRenderBlocks.length > 0);
308
+ const settledFromRecord = renderSettledFromRecord({
309
+ isStreamActive: !!isStreamActive,
310
+ messageId,
311
+ recordSegmentCount: messageInterleavedContent.length
312
+ });
313
+ const resolvedContent = settledFromRecord ? content : requestText || content;
314
+ const currentContent = editedContent ?? resolvedContent;
315
+ const hasRequestOrTaskId = requestId || taskId;
316
+ const hasReceivedNonTextContent = serverProcessedBlocks && serverProcessedBlocks.length > 0 || hasReduxRenderBlocks;
317
+ const isWaitingForContent = hasRequestOrTaskId && !resolvedContent.trim() && !hasReceivedNonTextContent;
318
+ const hasUnifiedSpecial = !settledFromRecord && (streamSlotStart !== void 0 || streamSlotEnd !== void 0 || agentCallId !== void 0 || unifiedSlots.some(
319
+ (s) => s.kind === "tool" || s.kind === "status" || s.kind === "error" || s.kind === "thinking" || s.kind === "render_block" && blockCarriesDataNotText(renderBlocksMap[s.blockId])
320
+ ));
321
+ const hasDbInterleavedSpecial = messageInterleavedContent.some(
322
+ (s) => s.type === "db_tool" || s.type === "thinking"
323
+ );
324
+ const toolLifecycleMapSelector = useMemo(
325
+ () => requestId ? selectToolLifecycleMap(requestId) : () => void 0,
326
+ [requestId]
327
+ );
328
+ const toolLifecycleMap = useAppSelector(toolLifecycleMapSelector);
329
+ const machineFramesVisible = useMachineFramesVisible();
330
+ const groupedSlots = useMemo(
331
+ () => groupConsecutiveToolSlots(
332
+ unifiedSlots,
333
+ (callId) => {
334
+ const toolName = toolLifecycleMap?.[callId]?.toolName ?? null;
335
+ if (getToolDisplayMode(toolName) !== "auto") return null;
336
+ return isCloudBrowserToolName(toolName) ? "cloud-browser" : "default";
337
+ },
338
+ (slot) => {
339
+ if (slot.kind === "thinking" || slot.kind === "status") return true;
340
+ if (slot.kind !== "render_block") return false;
341
+ const block = renderBlocksMap[slot.blockId];
342
+ if (!block) return true;
343
+ return block.type === "text" && classifyTextForFold(block.content) === "shortText";
344
+ }
345
+ ),
346
+ [unifiedSlots, toolLifecycleMap, renderBlocksMap]
347
+ );
348
+ const groupedSegmentRuns = useMemo(
349
+ () => messageInterleavedRuns.map(
350
+ (run) => groupConsecutiveDbTools(
351
+ run,
352
+ (seg) => {
353
+ const toolName = seg.record?.toolName ?? seg.stubName;
354
+ if (getToolDisplayMode(toolName) !== "auto") return null;
355
+ return isCloudBrowserToolName(toolName) ? "cloud-browser" : "default";
356
+ },
357
+ (segment) => {
358
+ if (segment.type === "thinking" || segment.type === "status")
359
+ return true;
360
+ return segment.type === "text" && classifyTextForFold(segment.content) === "shortText";
361
+ }
362
+ )
363
+ ),
364
+ [messageInterleavedRuns]
365
+ );
366
+ const groupedSegments = useMemo(
367
+ () => groupedSegmentRuns.length === 1 ? groupedSegmentRuns[0] : groupedSegmentRuns.flat(),
368
+ [groupedSegmentRuns]
369
+ );
370
+ const isSettled = !isStreamActive;
371
+ const workGroupedSlots = useMemo(() => {
372
+ if (!isSettled) return groupedSlots;
373
+ if (messageId && !settledFromRecord) return groupedSlots;
374
+ if (!machineFramesVisible) return groupedSlots;
375
+ return foldAgentWork(groupedSlots, {
376
+ classify: (slot) => {
377
+ if (slot.kind === "tool" && holdsADecision(toolLifecycleMap?.[slot.callId])) return "visible";
378
+ if (slot.kind === "tool_batch" && slot.callIds.some((id) => holdsADecision(toolLifecycleMap?.[id]))) {
379
+ return "visible";
380
+ }
381
+ if (slot.kind === "thinking" || slot.kind === "status" || slot.kind === "tool" || slot.kind === "tool_batch") {
382
+ return "work";
383
+ }
384
+ if (slot.kind === "render_block") {
385
+ const rb = renderBlocksMap[slot.blockId];
386
+ if (!rb) return "shortText";
387
+ if (rb.type === "text") return classifyTextForFold(rb.content);
388
+ }
389
+ return "visible";
390
+ },
391
+ stepsOf: (slot) => slot.kind === "tool_batch" ? slot.callIds.length : 1,
392
+ spanOf: (slot) => {
393
+ const entrySpan = (callId) => {
394
+ const e = toolLifecycleMap?.[callId];
395
+ return toolSpan(e?.startedAt, e?.completedAt);
396
+ };
397
+ if (slot.kind === "tool") return entrySpan(slot.callId);
398
+ if (slot.kind === "tool_batch") {
399
+ return mergeSpans(slot.callIds.map(entrySpan));
400
+ }
401
+ return null;
402
+ }
403
+ });
404
+ }, [
405
+ isSettled,
406
+ messageId,
407
+ settledFromRecord,
408
+ groupedSlots,
409
+ toolLifecycleMap,
410
+ renderBlocksMap,
411
+ machineFramesVisible
412
+ ]);
413
+ const workGroupedSegments = useMemo(() => {
414
+ if (!isSettled) return groupedSegments;
415
+ if (!machineFramesVisible) return groupedSegments;
416
+ const dbToolSpan = (seg) => toolSpan(seg.record?.startedAt, seg.record?.completedAt);
417
+ return groupedSegmentRuns.flatMap((runSegments) => foldAgentWork(runSegments, {
418
+ classify: (seg) => {
419
+ if (seg.type === "db_tool" && recordHoldsADecision(seg.record)) return "visible";
420
+ if (seg.type === "db_tool_batch" && seg.segments.some((one) => recordHoldsADecision(one.record))) {
421
+ return "visible";
422
+ }
423
+ if (seg.type === "thinking" || seg.type === "status" || seg.type === "db_tool" || seg.type === "db_tool_batch") {
424
+ return "work";
425
+ }
426
+ if (seg.type === "text") return classifyTextForFold(seg.content);
427
+ return "visible";
428
+ },
429
+ stepsOf: (seg) => seg.type === "db_tool_batch" ? seg.segments.length : 1,
430
+ spanOf: (seg) => {
431
+ if (seg.type === "db_tool") return dbToolSpan(seg);
432
+ if (seg.type === "db_tool_batch") {
433
+ return mergeSpans(seg.segments.map(dbToolSpan));
434
+ }
435
+ return null;
436
+ }
437
+ }));
438
+ }, [isSettled, groupedSegments, groupedSegmentRuns, machineFramesVisible]);
439
+ useEffect(() => {
440
+ if (isStreamActive) {
441
+ setEditedContent(null);
442
+ }
443
+ }, [isStreamActive]);
444
+ useEffect(() => {
445
+ if (applyLocalEdits === false) {
446
+ setEditedContent(null);
447
+ }
448
+ }, [applyLocalEdits, resolvedContent]);
449
+ const useServerBlocks = serverProcessedBlocks && serverProcessedBlocks.length > 0;
450
+ const { blocks, blockError } = useMemo(() => {
451
+ if (isWaitingForContent) return { blocks: [], blockError: false };
452
+ if (!settledFromRecord && hasReduxRenderBlocks && reduxRenderBlocks) {
453
+ const settled = settledOneShotBlocks({
454
+ isStreamActive: !!isStreamActive,
455
+ blockIds: reduxRenderBlocks.map((rb) => rb.blockId),
456
+ content: currentContent
457
+ });
458
+ if (settled) {
459
+ return { blocks: expandTextBlocksInList(settled), blockError: false };
460
+ }
461
+ }
462
+ if (!settledFromRecord && hasReduxRenderBlocks && reduxRenderBlocks) {
463
+ const clientBlocks = reduxRenderBlocks.filter(
464
+ (rb) => blockHasSomethingToRender(rb) && !hiddenDecisionJsonTextBlockIds.has(rb.blockId)
465
+ ).map(renderBlockToContentBlock);
466
+ return {
467
+ blocks: expandTextBlocksInList(clientBlocks),
468
+ blockError: false
469
+ };
470
+ }
471
+ if (useServerBlocks && serverProcessedBlocks) {
472
+ const supplementaryBlocks = serverProcessedBlocks.map(
473
+ (sb) => ({
474
+ type: sb.type,
475
+ content: sb.content ?? "",
476
+ serverData: sb.data ?? void 0,
477
+ metadata: sb.metadata,
478
+ language: sb.data?.language,
479
+ src: sb.data?.src,
480
+ alt: sb.data?.alt
481
+ })
482
+ );
483
+ const expandedSupplementaryBlocks = expandTextBlocksInList(supplementaryBlocks);
484
+ if (currentContent.trim()) {
485
+ try {
486
+ const textBlocks = splitContentIntoBlocksV2(currentContent);
487
+ const parsed = Array.isArray(textBlocks) ? textBlocks : [];
488
+ return {
489
+ blocks: [
490
+ ...expandTextBlocksInList(parsed),
491
+ ...expandedSupplementaryBlocks
492
+ ],
493
+ blockError: false
494
+ };
495
+ } catch {
496
+ return {
497
+ blocks: [
498
+ { type: "text", content: currentContent },
499
+ ...expandedSupplementaryBlocks
500
+ ],
501
+ blockError: false
502
+ };
503
+ }
504
+ }
505
+ return { blocks: expandedSupplementaryBlocks, blockError: false };
506
+ }
507
+ try {
508
+ const result = splitContentIntoBlocksV2(currentContent);
509
+ return {
510
+ blocks: expandTextBlocksInList(Array.isArray(result) ? result : []),
511
+ blockError: false
512
+ };
513
+ } catch (error) {
514
+ console.error(
515
+ "[MarkdownStream] Error splitting content into blocks:",
516
+ error
517
+ );
518
+ return {
519
+ blocks: [{ type: "text", content: currentContent }],
520
+ blockError: true
521
+ };
522
+ }
523
+ }, [
524
+ currentContent,
525
+ isStreamActive,
526
+ isWaitingForContent,
527
+ useServerBlocks,
528
+ serverProcessedBlocks,
529
+ hasReduxRenderBlocks,
530
+ reduxRenderBlocks,
531
+ hiddenDecisionJsonTextBlockIds,
532
+ settledFromRecord
533
+ ]);
534
+ useEffect(() => {
535
+ if (blockError) {
536
+ setHasError(true);
537
+ }
538
+ }, [blockError]);
539
+ const processedBlocks = useMemo(() => {
540
+ if (isStreamActive) return blocks;
541
+ const result = [];
542
+ let i = 0;
543
+ while (i < blocks.length) {
544
+ if (blocks[i].type === "reasoning") {
545
+ const reasoningGroup = [];
546
+ while (i < blocks.length && blocks[i].type === "reasoning") {
547
+ reasoningGroup.push(blocks[i].content);
548
+ i++;
549
+ }
550
+ if (reasoningGroup.length > 1) {
551
+ result.push({
552
+ type: "consolidated_reasoning",
553
+ content: reasoningGroup.join("\n---\n"),
554
+ // Join for fallback
555
+ metadata: { reasoningTexts: reasoningGroup }
556
+ });
557
+ } else {
558
+ result.push({
559
+ type: "reasoning",
560
+ content: reasoningGroup[0]
561
+ });
562
+ }
563
+ } else {
564
+ result.push(blocks[i]);
565
+ i++;
566
+ }
567
+ }
568
+ return result;
569
+ }, [blocks, isStreamActive]);
570
+ const prevBlocksRef = useRef([]);
571
+ const slotBlocksRef = useRef(/* @__PURE__ */ new Map());
572
+ const stableBlocks = useMemo(
573
+ () => reuseUnchangedBlocks(prevBlocksRef.current, processedBlocks),
574
+ [processedBlocks]
575
+ );
576
+ useLayoutEffect(() => {
577
+ prevBlocksRef.current = stableBlocks;
578
+ }, [stableBlocks]);
579
+ const { shown: mountedBlockCount, sentinel: progressiveSentinel } = useProgressiveMount(stableBlocks.length);
580
+ const interleavedTextSplits = useMemo(() => {
581
+ const splits = /* @__PURE__ */ new Map();
582
+ for (const segment of messageInterleavedContent) {
583
+ if (segment.type !== "text" || splits.has(segment.content)) continue;
584
+ try {
585
+ splits.set(segment.content, splitContentIntoBlocksV2(segment.content));
586
+ } catch {
587
+ splits.set(segment.content, [
588
+ { type: "text", content: segment.content, startLine: 0, endLine: 0 }
589
+ ]);
590
+ }
591
+ }
592
+ return splits;
593
+ }, [messageInterleavedContent]);
594
+ const interleavedTextBlockTotal = hasDbInterleavedSpecial ? messageInterleavedContent.reduce(
595
+ (sum, segment) => segment.type === "text" ? sum + (interleavedTextSplits.get(segment.content)?.length ?? 0) : sum,
596
+ 0
597
+ ) : 0;
598
+ const { shown: interleavedShown, sentinel: interleavedSentinel } = useProgressiveMount(interleavedTextBlockTotal);
599
+ const lastReasoningBlockIndex = useMemo(() => {
600
+ for (let i = processedBlocks.length - 1; i >= 0; i--) {
601
+ if (processedBlocks[i].type === "reasoning") {
602
+ return i;
603
+ }
604
+ }
605
+ return -1;
606
+ }, [processedBlocks]);
607
+ const latestRef = useRef({ currentContent, onContentChange, applyLocalEdits });
608
+ useLayoutEffect(() => {
609
+ latestRef.current = { currentContent, onContentChange, applyLocalEdits };
610
+ });
611
+ const blockContentChange = useCallback((next) => {
612
+ const { onContentChange: change, currentContent: prev } = latestRef.current;
613
+ change?.(next, prev);
614
+ }, []);
615
+ const replaceBlockContent = useCallback(
616
+ (original, replacement, remark) => {
617
+ const { currentContent: currentContent2, onContentChange: onContentChange2, applyLocalEdits: applyLocalEdits2 } = latestRef.current;
618
+ try {
619
+ const idx = currentContent2.indexOf(original);
620
+ if (idx === -1) {
621
+ console.warn(
622
+ // access-errors: ok — console-only diagnostic about an in-memory substring comparison performed here (indexOf === -1), no record read involved
623
+ "[MarkdownStream] replaceBlockContent: original substring not found in content.",
624
+ { originalLen: original.length, contentLen: currentContent2.length }
625
+ );
626
+ return;
627
+ }
628
+ const updatedContent = currentContent2.slice(0, idx) + replacement + currentContent2.slice(idx + original.length);
629
+ onContentChange2?.(updatedContent, currentContent2, remark);
630
+ if (applyLocalEdits2 !== false) {
631
+ setEditedContent(updatedContent);
632
+ }
633
+ } catch (error) {
634
+ console.error("[MarkdownStream] Error in replaceBlockContent:", error);
635
+ }
636
+ },
637
+ []
638
+ );
639
+ const handleOpenEditor = useCallback(() => {
640
+ try {
641
+ if (isStreamActive) return;
642
+ setIsEditorOpen(true);
643
+ } catch (error) {
644
+ console.error("[MarkdownStream] Error opening editor:", error);
645
+ }
646
+ }, [isStreamActive]);
647
+ const handleCancelEdit = useCallback(() => {
648
+ try {
649
+ setIsEditorOpen(false);
650
+ } catch (error) {
651
+ console.error("[MarkdownStream] Error canceling edit:", error);
652
+ }
653
+ }, []);
654
+ const handleSaveEdit = useCallback(
655
+ (newContent) => {
656
+ try {
657
+ onContentChange?.(newContent, currentContent);
658
+ if (applyLocalEdits !== false) {
659
+ setEditedContent(newContent);
660
+ }
661
+ setIsEditorOpen(false);
662
+ } catch (error) {
663
+ console.error("[MarkdownStream] Error saving edit:", error);
664
+ }
665
+ },
666
+ [onContentChange, applyLocalEdits, currentContent]
667
+ );
668
+ const blockKey = useCallback((block, index) => {
669
+ if (block.type === "code") {
670
+ return `code-${index}`;
671
+ }
672
+ return `${block.type}-${block.content.slice(0, 100)}-${index}`;
673
+ }, []);
674
+ const renderBlock = useCallback(
675
+ (block, index, isLastReasoning = false) => {
676
+ try {
677
+ if (!block || typeof block !== "object") {
678
+ console.warn("[MarkdownStream] Invalid block at index:", index);
679
+ return null;
680
+ }
681
+ return /* @__PURE__ */ jsx(
682
+ SafeBlockRenderer,
683
+ {
684
+ block,
685
+ index,
686
+ isStreamActive,
687
+ onContentChange: onContentChange ? blockContentChange : void 0,
688
+ conversationId,
689
+ messageId,
690
+ requestId,
691
+ taskId,
692
+ isLastReasoningBlock: isLastReasoning,
693
+ replaceBlockContent,
694
+ handleOpenEditor,
695
+ outputSchema
696
+ },
697
+ blockKey(block, index)
698
+ );
699
+ } catch (error) {
700
+ console.error(
701
+ "[MarkdownStream] Error in renderBlock at index:",
702
+ index,
703
+ error
704
+ );
705
+ return /* @__PURE__ */ jsxs(
706
+ "div",
707
+ {
708
+ className: "py-2 px-1 text-sm text-neutral-600 dark:text-neutral-400 whitespace-pre-wrap break-words border-l-2 border-red-500 bg-red-50 dark:bg-red-950/20",
709
+ children: [
710
+ block?.content || "[Render error]",
711
+ /* @__PURE__ */ jsx(ErrorAlchemyMenu, {})
712
+ ]
713
+ },
714
+ blockKey(block, index)
715
+ );
716
+ }
717
+ },
718
+ [
719
+ blockKey,
720
+ isStreamActive,
721
+ onContentChange,
722
+ blockContentChange,
723
+ conversationId,
724
+ messageId,
725
+ requestId,
726
+ taskId,
727
+ replaceBlockContent,
728
+ handleOpenEditor,
729
+ outputSchema
730
+ ]
731
+ );
732
+ const containerStyles = cn(
733
+ "pt-1 pb-0 px-0 space-y-4 font-sans text-md antialiased leading-relaxed tracking-wide overflow-x-clip min-w-0 break-words",
734
+ // The first block starts flush (no top margin) — app/globals.css.
735
+ "block w-full bg-inherit markdown-flush-start",
736
+ className
737
+ );
738
+ if (hasError) {
739
+ return /* @__PURE__ */ jsx(
740
+ PlainTextFallback,
741
+ {
742
+ requestId,
743
+ content: currentContent,
744
+ className
745
+ }
746
+ );
747
+ }
748
+ const hasPreTextSegments = isWaitingForContent && requestId && hasUnifiedSpecial;
749
+ if (isWaitingForContent && !hasPreTextSegments) {
750
+ try {
751
+ return /* @__PURE__ */ jsx("div", { className: "mb-1 w-full min-w-0 text-left overflow-x-clip", children: /* @__PURE__ */ jsx("div", { className: containerStyles, children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-start py-1", children: requestId && isVideoJob ? /* @__PURE__ */ jsx(GenerationJobCard, { requestId }) : requestId && isRunJob ? (
752
+ // A generation job names itself, its model and its clock —
753
+ // "Processing…" for a minute reads as a hang.
754
+ /* @__PURE__ */ jsx(RunJobWorkingLine, { requestId })
755
+ ) : /* @__PURE__ */ jsx(
756
+ ShimmerText,
757
+ {
758
+ text: isReasoningActive ? "Reasoning\u2026" : "Processing\u2026",
759
+ className: "text-sm"
760
+ }
761
+ ) }) }) });
762
+ } catch (error) {
763
+ console.error("[MarkdownStream] Error rendering loading state:", error);
764
+ return /* @__PURE__ */ jsx(PlainTextFallback, { content: "Loading...", className });
765
+ }
766
+ }
767
+ const stableSlotBlocks = (key, next) => {
768
+ const prev = slotBlocksRef.current.get(key) ?? [];
769
+ const stable = reuseUnchangedBlocks(prev, next);
770
+ slotBlocksRef.current.set(key, stable);
771
+ return stable;
772
+ };
773
+ const renderGroupedSlot = (slot, i) => {
774
+ if (!requestId) return null;
775
+ if (slot.kind === "tool_batch") {
776
+ if (!machineFramesVisible) return null;
777
+ return /* @__PURE__ */ jsx(
778
+ ToolBatch,
779
+ {
780
+ requestId,
781
+ callIds: slot.callIds,
782
+ conversationId: conversationId ?? "",
783
+ browserRunOrder: slot.browserRunOrder,
784
+ browserBreakBefore: slot.browserBreakBefore,
785
+ browserBreakAfter: slot.browserBreakAfter
786
+ },
787
+ `tool-batch-${slot.callIds[0]}`
788
+ );
789
+ }
790
+ if (slot.kind === "render_block") {
791
+ let rb = renderBlocksMap[slot.blockId];
792
+ if (!rb) return null;
793
+ if (!blockHasSomethingToRender(rb)) {
794
+ return null;
795
+ }
796
+ if (hiddenDecisionJsonTextBlockIds.has(slot.blockId)) {
797
+ return null;
798
+ }
799
+ if (rb.type === "text" && rb.content) {
800
+ const liveMarkers = liveCitationMarkersByBlockId[slot.blockId];
801
+ if (liveMarkers && liveMarkers.length > 0) {
802
+ rb = {
803
+ ...rb,
804
+ content: insertCitationMarkers(rb.content, liveMarkers)
805
+ };
806
+ }
807
+ }
808
+ if (rb.type === "text" && rb.content?.trim()) {
809
+ const sub = (() => {
810
+ try {
811
+ return splitContentIntoBlocksV2(rb.content);
812
+ } catch {
813
+ return null;
814
+ }
815
+ })();
816
+ if (sub && sub.length > 0) {
817
+ let lastReasoningIdx = -1;
818
+ for (let j = sub.length - 1; j >= 0; j--) {
819
+ if (sub[j].type === "reasoning" || sub[j].type === "thinking") {
820
+ lastReasoningIdx = j;
821
+ break;
822
+ }
823
+ }
824
+ const isStreamingRb = rb.status === "streaming";
825
+ return stableSlotBlocks(
826
+ `slot:${slot.seq}`,
827
+ sub.map(
828
+ (b, j) => ({
829
+ ...b,
830
+ isStreamingBlock: isStreamingRb && j === lastReasoningIdx
831
+ })
832
+ )
833
+ ).map((b, j) => renderBlock(b, i * 1e3 + j));
834
+ }
835
+ }
836
+ const [block] = stableSlotBlocks(`slotb:${slot.seq}`, [renderBlockToContentBlock(rb)]);
837
+ return renderBlock(block, i);
838
+ }
839
+ if (slot.kind === "tool") {
840
+ if (!machineFramesVisible) {
841
+ const entry = toolLifecycleMap?.[slot.callId];
842
+ const settled = entry?.status === "completed" || entry?.status === "error";
843
+ return settled ? null : /* @__PURE__ */ jsx(
844
+ InlineStatusIndicator,
845
+ {
846
+ label: EXPERT_WORKING_LABEL
847
+ },
848
+ `tool-${slot.callId}`
849
+ );
850
+ }
851
+ return /* @__PURE__ */ jsx(
852
+ ToolCard,
853
+ {
854
+ requestId,
855
+ callId: slot.callId,
856
+ conversationId: conversationId ?? ""
857
+ },
858
+ `tool-${slot.callId}`
859
+ );
860
+ }
861
+ if (slot.kind === "status") {
862
+ if (requestId && isVideoJob) {
863
+ return /* @__PURE__ */ jsx(
864
+ GenerationJobCard,
865
+ {
866
+ requestId,
867
+ className: "my-2"
868
+ },
869
+ `status-${slot.seq}`
870
+ );
871
+ }
872
+ if (requestId && isRunJob) {
873
+ return /* @__PURE__ */ jsx(
874
+ RunJobWorkingLine,
875
+ {
876
+ requestId,
877
+ className: "flex items-center py-2"
878
+ },
879
+ `status-${slot.seq}`
880
+ );
881
+ }
882
+ return /* @__PURE__ */ jsx(
883
+ InlineStatusIndicator,
884
+ {
885
+ label: machineFramesVisible ? slot.label : EXPERT_WORKING_LABEL
886
+ },
887
+ `status-${slot.seq}`
888
+ );
889
+ }
890
+ if (slot.kind === "thinking") {
891
+ return /* @__PURE__ */ jsx(
892
+ InlineThinkingSlot,
893
+ {
894
+ requestId,
895
+ chunkStartIndex: slot.chunkStartIndex,
896
+ chunkEndIndex: slot.chunkEndIndex,
897
+ renderReasoning: (content2, isStreaming) => renderBlock(
898
+ {
899
+ type: "reasoning",
900
+ content: content2,
901
+ isStreamingBlock: isStreaming
902
+ },
903
+ i
904
+ )
905
+ },
906
+ `thinking-${slot.seq}`
907
+ );
908
+ }
909
+ if (slot.kind === "error") {
910
+ return /* @__PURE__ */ jsx(InlineAssistantError, { requestId }, `error-${slot.seq}`);
911
+ }
912
+ return null;
913
+ };
914
+ let interleavedBudget = interleavedShown;
915
+ const renderGroupedSegment = (segment, segIdx) => {
916
+ if (interleavedBudget <= 0 && interleavedShown < interleavedTextBlockTotal) return null;
917
+ if (segment.type === "db_tool_batch") {
918
+ if (!machineFramesVisible) return null;
919
+ return /* @__PURE__ */ jsx(
920
+ ToolBatch,
921
+ {
922
+ segments: segment.segments,
923
+ conversationId: conversationId ?? "",
924
+ browserRunOrder: segment.browserRunOrder,
925
+ browserBreakBefore: segment.browserBreakBefore,
926
+ browserBreakAfter: segment.browserBreakAfter
927
+ },
928
+ `tool-batch-${segment.segments[0]?.callId ?? segment.key}`
929
+ );
930
+ }
931
+ if (segment.type === "db_tool") {
932
+ if (!machineFramesVisible) return null;
933
+ return /* @__PURE__ */ jsx(
934
+ ToolCard,
935
+ {
936
+ callId: segment.callId,
937
+ segment,
938
+ conversationId: conversationId ?? ""
939
+ },
940
+ `tool-${segment.callId}`
941
+ );
942
+ }
943
+ if (segment.type === "render_block") {
944
+ const block = {
945
+ type: segment.blockType,
946
+ content: segment.content ?? "",
947
+ serverData: segment.data ?? void 0,
948
+ metadata: segment.metadata
949
+ };
950
+ return stableSlotBlocks(`segrb:${segIdx}`, expandTextBlocksInList([block])).map(
951
+ (expandedBlock, blockIdx) => renderBlock(expandedBlock, segIdx * 1e3 + blockIdx)
952
+ );
953
+ }
954
+ if (segment.type === "thinking") {
955
+ const thinkBlocks = (() => {
956
+ try {
957
+ return splitContentIntoBlocksV2(segment.content);
958
+ } catch {
959
+ return [
960
+ {
961
+ type: "reasoning",
962
+ content: segment.content,
963
+ startLine: 0,
964
+ endLine: 0
965
+ }
966
+ ];
967
+ }
968
+ })();
969
+ return stableSlotBlocks(
970
+ `segthink:${segIdx}`,
971
+ thinkBlocks.map((block) => ({ ...block, type: "reasoning" }))
972
+ ).map((block, blockIdx) => renderBlock(block, segIdx * 1e3 + blockIdx));
973
+ }
974
+ if (segment.type === "text") {
975
+ const segBlocks = interleavedTextSplits.get(segment.content) ?? (() => {
976
+ try {
977
+ return splitContentIntoBlocksV2(segment.content);
978
+ } catch {
979
+ return [
980
+ {
981
+ type: "text",
982
+ content: segment.content,
983
+ startLine: 0,
984
+ endLine: 0
985
+ }
986
+ ];
987
+ }
988
+ })();
989
+ const visible = segBlocks.slice(0, Math.max(0, interleavedBudget));
990
+ interleavedBudget -= segBlocks.length;
991
+ return stableSlotBlocks(`segtext:${segIdx}`, visible).map(
992
+ (block, blockIdx) => renderBlock(block, segIdx * 1e3 + blockIdx)
993
+ );
994
+ }
995
+ return null;
996
+ };
997
+ try {
998
+ return (
999
+ // A live stream heals half-arrived markdown in every MarkdownCore leaf
1000
+ // below (links, images, emphasis) — finished messages are untouched.
1001
+ /* @__PURE__ */ jsx(MarkdownStreamingProvider, { value: !!isStreamActive, children: /* @__PURE__ */ jsx(DocumentNumberingProvider, { source: currentContent, children: /* @__PURE__ */ jsx(MaybeSourceEdit, { source: currentContent, save: isStreamActive ? void 0 : onContentChange ? handleSaveEdit : void 0, children: /* @__PURE__ */ jsxs(
1002
+ "div",
1003
+ {
1004
+ className: "mb-1 w-full min-w-0 text-left overflow-x-clip",
1005
+ "data-matrx-doc-root": "",
1006
+ "data-block-count": hasUnifiedSpecial ? void 0 : hasDbInterleavedSpecial ? interleavedTextBlockTotal : stableBlocks.length,
1007
+ "data-blocks-mounted": hasUnifiedSpecial ? void 0 : hasDbInterleavedSpecial ? Math.min(interleavedShown, interleavedTextBlockTotal) : mountedBlockCount,
1008
+ children: [
1009
+ /* @__PURE__ */ jsxs("div", { className: containerStyles, children: [
1010
+ hasUnifiedSpecial && requestId ? workGroupedSlots.map(
1011
+ (slot, i) => slot.kind === "agent_work" ? /* @__PURE__ */ jsx(
1012
+ AgentWorkGroup,
1013
+ {
1014
+ sessionKey: `agent-work:${requestId}:${slot.items[0]?.seq ?? i}`,
1015
+ order: i,
1016
+ durationMs: slot.durationMs,
1017
+ stepCount: slot.stepCount,
1018
+ conversationId,
1019
+ children: flattenWorkSlots(slot.items).map(
1020
+ (s, k) => renderGroupedSlot(s, i * 1e3 + k)
1021
+ )
1022
+ },
1023
+ `agent-work-${slot.items[0]?.seq ?? i}`
1024
+ ) : renderGroupedSlot(slot, i)
1025
+ ) : hasDbInterleavedSpecial ? workGroupedSegments.map(
1026
+ (segment, segIdx) => "kind" in segment && segment.kind === "agent_work" ? /* @__PURE__ */ jsx(
1027
+ AgentWorkGroup,
1028
+ {
1029
+ sessionKey: `agent-work:${messageId ?? conversationId ?? ""}:${segIdx}`,
1030
+ order: segIdx,
1031
+ durationMs: segment.durationMs,
1032
+ stepCount: segment.stepCount,
1033
+ conversationId,
1034
+ children: flattenWorkSegments(segment.items).map(
1035
+ (s, k) => renderGroupedSegment(s, segIdx * 1e3 + k)
1036
+ )
1037
+ },
1038
+ `agent-work-${messageId ?? ""}-${segIdx}`
1039
+ ) : renderGroupedSegment(segment, segIdx)
1040
+ ) : stableBlocks.slice(0, mountedBlockCount).map(
1041
+ (block, index) => renderBlock(
1042
+ block,
1043
+ index,
1044
+ index === lastReasoningBlockIndex
1045
+ )
1046
+ ),
1047
+ !hasUnifiedSpecial && !hasDbInterleavedSpecial && progressiveSentinel,
1048
+ !hasUnifiedSpecial && hasDbInterleavedSpecial && interleavedSentinel,
1049
+ /* @__PURE__ */ jsx(DocumentFootnotes, { render: (markdown) => renderBlock({ type: "text", content: markdown }, 1e6) })
1050
+ ] }),
1051
+ !hideCopyButton && /* @__PURE__ */ jsx(
1052
+ MarkdownErrorBoundary,
1053
+ {
1054
+ fallback: null,
1055
+ onError: (error) => console.error("[MarkdownStream] CopyButton error:", error),
1056
+ children: /* @__PURE__ */ jsx(
1057
+ RichCopySplit,
1058
+ {
1059
+ label: "Content",
1060
+ human: currentContent,
1061
+ contentFlavor: "markdown",
1062
+ stripThinking: true,
1063
+ size: "xs",
1064
+ className: "absolute top-1/2 right-1 z-10 -translate-y-1/2"
1065
+ }
1066
+ )
1067
+ }
1068
+ ),
1069
+ allowFullScreenEditor && /* @__PURE__ */ jsx(
1070
+ MarkdownErrorBoundary,
1071
+ {
1072
+ fallback: null,
1073
+ onError: (error) => console.error("[MarkdownStream] FullScreenEditor error:", error),
1074
+ children: /* @__PURE__ */ jsx(
1075
+ FullScreenMarkdownEditor,
1076
+ {
1077
+ imagePolicy: "inherit",
1078
+ isOpen: isEditorOpen,
1079
+ initialContent: currentContent,
1080
+ onSave: handleSaveEdit,
1081
+ onCancel: handleCancelEdit,
1082
+ analysisData,
1083
+ messageId,
1084
+ conversationId,
1085
+ tabs: [
1086
+ "write",
1087
+ "matrx_split",
1088
+ "markdown",
1089
+ "wysiwyg",
1090
+ "preview"
1091
+ ],
1092
+ initialTab: "matrx_split"
1093
+ }
1094
+ )
1095
+ }
1096
+ )
1097
+ ]
1098
+ }
1099
+ ) }) }) })
1100
+ );
1101
+ } catch (error) {
1102
+ console.error("[MarkdownStream] Critical error in render:", error);
1103
+ return /* @__PURE__ */ jsx(PlainTextFallback, { content: currentContent, className });
1104
+ }
1105
+ };
1106
+ export {
1107
+ EnhancedChatMarkdownInternal
1108
+ };