@ai-matrx/chat 0.4.2 → 0.4.8

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 (144) hide show
  1. package/CHANGELOG.md +60 -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 +25 -12
  60. package/dist/agents/redux/execution-system/thunks/run-headless-agent-json.d.ts +2 -0
  61. package/dist/agents/redux/execution-system/thunks/run-headless-agent-json.js +25 -4
  62. package/dist/agents/redux/execution-system/utils/assemble-cx-content-blocks.js +2 -1
  63. package/dist/agents/redux/execution-system/utils/inbound-render-block.d.ts +8 -0
  64. package/dist/agents/redux/execution-system/utils/inbound-render-block.js +17 -2
  65. package/dist/agents/redux/execution-system/utils/normalize-content-blocks.js +1 -1
  66. package/dist/agents/redux/execution-system/utils/progress-data-block.d.ts +11 -0
  67. package/dist/agents/redux/execution-system/utils/progress-data-block.js +37 -0
  68. package/dist/agents/redux/execution-system/utils/stream-block-accumulator.js +10 -8
  69. package/dist/agents/redux/mcp/mcp.slice.js +15 -7
  70. package/dist/agents/redux/tools/tools.thunks.js +3 -0
  71. package/dist/agents/runtime-reconnect/ServerOperationBanner.d.ts +6 -1
  72. package/dist/agents/runtime-reconnect/ServerOperationBanner.js +6 -1
  73. package/dist/agents/runtime-reconnect/reconnect-server-operation.thunk.js +10 -6
  74. package/dist/agents/ui-first-tools/ui/ApprovalCard.js +1 -1
  75. package/dist/agents/ui-first-tools/ui/AskCard.js +1 -1
  76. package/dist/agents/ui-first-tools/ui/lists/TaskPanel.js +1 -1
  77. package/dist/conversation/hooks/useDomCapturePrint.js +1 -1
  78. package/dist/conversation/utils/markdown-print.js +1 -1
  79. package/dist/cx-chat/components/messages/AssistantMessage.js +3 -5
  80. package/dist/cx-conversation/AssistantMessage.js +3 -5
  81. package/dist/host/app-data-slots.d.ts +85 -0
  82. package/dist/host/app-data-slots.js +42 -0
  83. package/dist/host/bare-host-chrome.js +1 -0
  84. package/dist/host/defaults/prefs.d.ts +19 -0
  85. package/dist/host/defaults/prefs.js +52 -0
  86. package/dist/host/defaults/workspace-gate.js +2 -1
  87. package/dist/host/index.d.ts +1 -1
  88. package/dist/host/index.js +2 -1
  89. package/dist/host/react.js +16 -1
  90. package/dist/host/source.d.ts +21 -0
  91. package/dist/host/ui-slots.d.ts +1 -23
  92. package/dist/host/ui-slots.js +0 -34
  93. package/dist/public-chat/components/PublicMessageOptionsMenu.js +2 -1
  94. package/dist/surfaces/redux/surfaceConfigSlice.js +2 -0
  95. package/dist/surfaces/redux/userStateSlice.js +3 -1
  96. package/dist/surfaces/runtime/agent-offer.js +1 -1
  97. package/dist/surfaces/runtime/surface-writeback.js +1 -1
  98. package/dist/tool-call-visualization/db-renderer/fetchToolRendererRow.js +2 -0
  99. package/dist/tool-call-visualization/renderers/agent-call/AgentCallInline.js +1 -1
  100. package/dist/tool-call-visualization/renderers/agent-call/CollabCallCard.js +1 -1
  101. package/dist/tool-call-visualization/renderers/fs/FsInline.js +1 -1
  102. package/dist/tool-call-visualization/renderers/random-wheel/RandomWheelInline.js +1 -1
  103. package/dist/tool-call-visualization/renderers/research/ResearchOverlay.js +4 -4
  104. package/dist/tool-call-visualization/renderers/research/SubagentReportBlock.js +2 -2
  105. package/dist/tool-call-visualization/renderers/scrape/ScrapeOverlay.js +1 -1
  106. package/dist/tool-call-visualization/renderers/search/SearchInline.js +1 -1
  107. package/dist/tool-call-visualization/renderers/search/SearchOverlay.js +1 -1
  108. package/dist/tool-call-visualization/renderers/sql/SqlInline.js +1 -1
  109. package/dist/tool-call-visualization/result-fields/KeyValueGrid.js +1 -1
  110. package/dist/tool-call-visualization/result-fields/ResultMarkdown.js +1 -1
  111. package/dist/tool-call-visualization/result-fields/ResultValue.js +1 -1
  112. package/dist/tool-call-visualization/surface-write/SurfaceWriteDiff.js +1 -1
  113. package/dist/ui/AudioOutputBlockSkeleton.d.ts +17 -0
  114. package/dist/ui/AudioOutputBlockSkeleton.js +78 -0
  115. package/dist/ui/chat-protocol-from-stream.d.ts +60 -0
  116. package/dist/ui/chat-protocol-from-stream.js +135 -0
  117. package/dist/ui/markdown-stream/EnhancedChatMarkdown.d.ts +59 -0
  118. package/dist/ui/markdown-stream/EnhancedChatMarkdown.js +1108 -0
  119. package/dist/ui/markdown-stream/MarkdownStream.d.ts +88 -0
  120. package/dist/ui/markdown-stream/MarkdownStream.js +14 -0
  121. package/dist/ui/markdown-stream/MarkdownStreamImpl.d.ts +4 -0
  122. package/dist/ui/markdown-stream/MarkdownStreamImpl.js +86 -0
  123. package/dist/ui/markdown-stream/StreamAwareChatMarkdown.d.ts +58 -0
  124. package/dist/ui/markdown-stream/StreamAwareChatMarkdown.js +294 -0
  125. package/dist/ui/markdown-stream/internal-handlers/AgentCallChildTrace.d.ts +22 -0
  126. package/dist/ui/markdown-stream/internal-handlers/AgentCallChildTrace.js +128 -0
  127. package/dist/ui/markdown-stream/internal-handlers/InlineAssistantError.d.ts +3 -0
  128. package/dist/ui/markdown-stream/internal-handlers/InlineAssistantError.js +26 -0
  129. package/dist/ui/markdown-stream/internal-handlers/InlineThinkingSlot.d.ts +14 -0
  130. package/dist/ui/markdown-stream/internal-handlers/InlineThinkingSlot.js +23 -0
  131. package/dist/ui/markdown-stream/internal-handlers/ToolHandlers.d.ts +42 -0
  132. package/dist/ui/markdown-stream/internal-handlers/ToolHandlers.js +109 -0
  133. package/dist/ui/markdown-stream/useBoundAgentOutputSchema.d.ts +2 -0
  134. package/dist/ui/markdown-stream/useBoundAgentOutputSchema.js +33 -0
  135. package/dist/window-panels/windows/agents/AgentAssistantMarkdownDebugWindow.js +1 -1
  136. package/package.json +10 -8
  137. package/dist/host/content-ir-slots.d.ts +0 -235
  138. package/dist/host/content-ir-slots.js +0 -135
  139. package/dist/host/markdown-slots.d.ts +0 -53
  140. package/dist/host/markdown-slots.js +0 -32
  141. package/dist/host/rich-document-slots.d.ts +0 -123
  142. package/dist/host/rich-document-slots.js +0 -36
  143. package/dist/utils/content-ir/report-kind-at-raw-renderer.d.ts +0 -19
  144. package/dist/utils/content-ir/report-kind-at-raw-renderer.js +0 -32
@@ -1,6 +1,7 @@
1
1
  import { setInstanceStatus } from "../conversations/conversations.slice.js";
2
2
  import { confirmInboxItem } from "./inbox.slice.js";
3
3
  import { isStrandablePersonLine } from "./inbox.selectors.js";
4
+ import { isHostConversation } from "../host-conversations/host-conversations.selectors.js";
4
5
  function hasPersonLineWaiting(state, conversationId) {
5
6
  return (state.conversationInbox?.byConversationId[conversationId] ?? []).some(
6
7
  isStrandablePersonLine
@@ -15,7 +16,7 @@ const inboxTurnEndMiddleware = (store) => (next) => (action) => {
15
16
  const status = store.getState().conversations?.byConversationId[action.payload.conversationId]?.status;
16
17
  if (status === "complete") conversationId = action.payload.conversationId;
17
18
  }
18
- if (conversationId && hasPersonLineWaiting(store.getState(), conversationId)) {
19
+ if (conversationId && !isHostConversation(store.getState(), conversationId) && hasPersonLineWaiting(store.getState(), conversationId)) {
19
20
  const id = conversationId;
20
21
  void import("./deliver-stranded-queue.thunk.js").then(
21
22
  ({ deliverStrandedQueue }) => store.dispatch(
@@ -1,6 +1,7 @@
1
1
  import { mergeJsonColumn } from "@ai-matrx/data/db";
2
2
  import { supabase } from "../../../../host/db.js";
3
3
  import { setInstanceStatus } from "../conversations/conversations.slice.js";
4
+ import { isHostConversation } from "../host-conversations/host-conversations.selectors.js";
4
5
  const RUN_CONFIGURATION_KEY = "run_configuration";
5
6
  const EDIT_DEBOUNCE_MS = 1500;
6
7
  const TURN_SETTLE_MS = 4e3;
@@ -104,6 +105,7 @@ async function persistRunConfiguration(conversationId, config) {
104
105
  function isPersistable(state, conversationId) {
105
106
  const record = state.conversations?.byConversationId[conversationId];
106
107
  if (!record || record.cacheOnly || record.isEphemeral) return false;
108
+ if (isHostConversation(state, conversationId)) return false;
107
109
  return !(record.status === "running" || record.status === "streaming" || record.status === "paused");
108
110
  }
109
111
  const storedSignature = /* @__PURE__ */ new Map();
@@ -12,7 +12,7 @@ import {
12
12
  fromCxAudioPart,
13
13
  fromCxVideoPart
14
14
  } from "@ai-matrx/media/files";
15
- import { seedPersistedEnvelopeCache } from "../../../../host/content-ir-slots.js";
15
+ import { seedPersistedEnvelopeCache } from "@ai-matrx/rich-content/kinds/registry/region-envelope-memo";
16
16
  import {
17
17
  readEnvelope,
18
18
  reconstructRegionValue
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  executionRejectionMeta
3
3
  } from "./execution-rejection-meta.js";
4
+ import { isHostConversation } from "../host-conversations/host-conversations.selectors.js";
4
5
  import { attributionForSend } from "../../../../host/app-identity.js";
5
6
  import { mintClientTempId } from "@ai-matrx/kit/ids";
6
7
  import { createAsyncThunk } from "@reduxjs/toolkit";
@@ -262,6 +263,11 @@ const executeInstance = createAsyncThunk(
262
263
  if (!instance) {
263
264
  throw new Error(`Conversation ${conversationId} not found`);
264
265
  }
266
+ if (isHostConversation(state, conversationId)) {
267
+ throw new Error(
268
+ `Conversation ${conversationId} is carried by its host; it sends through the host's source.`
269
+ );
270
+ }
265
271
  const claimHeldElsewhere = isExecutionClaimed(conversationId);
266
272
  if (claimHeldElsewhere || hasAbortController(conversationId) || instance.status === "running" || instance.status === "streaming") {
267
273
  if (submission) {
@@ -5,7 +5,11 @@ import {
5
5
  classifyUsageRefusal
6
6
  } from "../../../../host/usage-gate.js";
7
7
  import { parseNdjsonStream } from "../../../../host/server/stream-parser.js";
8
- import { isStreamTransportLost, StreamTransportError } from "@ai-matrx/agents/matrx";
8
+ import {
9
+ isStreamTransportLost,
10
+ readStreamCursor,
11
+ StreamTransportError
12
+ } from "@ai-matrx/agents/matrx";
9
13
  import { monitorStream } from "@ai-matrx/data/net";
10
14
  import { mintClientTempId } from "@ai-matrx/kit/ids";
11
15
  import { withPerformedScript } from "../../../speech-script/types.js";
@@ -139,15 +143,7 @@ import { getCapabilitiesForConversation } from "../../../runtime/get-model-capab
139
143
  import { toast } from "../../../../host/notify.js";
140
144
  import { isDirectiveApplyEvent } from "@ai-matrx/agents/envelope";
141
145
  import { proposeDirective } from "../../proposed-directives/proposedDirectivesSlice.js";
142
- function readTransportCursor(event) {
143
- if (typeof event !== "object" || event === null || !("stream_seq" in event) || typeof event.stream_seq !== "number" || !Number.isSafeInteger(event.stream_seq) || event.stream_seq <= 0) {
144
- return null;
145
- }
146
- return {
147
- streamId: "stream_id" in event && typeof event.stream_id === "string" && event.stream_id.length > 0 ? event.stream_id : null,
148
- streamSeq: event.stream_seq
149
- };
150
- }
146
+ const readTransportCursor = readStreamCursor;
151
147
  function renderBlockToContentType(type) {
152
148
  if (type === "image" || type === "image_output") return "image";
153
149
  if (type === "audio_output") return "audio";
@@ -190,7 +186,7 @@ import {
190
186
  import { StreamProfiler } from "../../../../ui/stream-profiler.js";
191
187
  import { makePartialKindStalenessGate } from "@ai-matrx/content-ir/wire";
192
188
  import { prepareInboundRenderBlock } from "../utils/inbound-render-block.js";
193
- import { progressDataRenderBlock } from "../../../../host/content-ir-slots.js";
189
+ import { progressDataRenderBlock } from "../utils/progress-data-block.js";
194
190
  import { DECISION_ANSWERS_BLOCK_TYPE } from "../../../../utils/content-ir/decision-answers-ids.js";
195
191
  import { recordContextReceipt } from "../context-rules/receipt-check.js";
196
192
  import { assembleMessageParts } from "../utils/assemble-cx-content-blocks.js";
@@ -349,6 +345,7 @@ async function processStream({
349
345
  let pendingTransportCursor = null;
350
346
  const batchedDispatch = (action) => dispatch(autoBatched(action));
351
347
  let reasoningLeakReported = false;
348
+ let serverStructuredData = null;
352
349
  const runJsonExtraction = (isFinal) => {
353
350
  if (!jsonTracker) return;
354
351
  const req = getState().activeRequests.byRequestId[requestId];
@@ -367,10 +364,22 @@ async function processStream({
367
364
  const jsonState = isFinal ? jsonTracker.finalize() : jsonTracker.getState();
368
365
  if (isFinal || jsonState.revision !== lastJsonRevision) {
369
366
  lastJsonRevision = jsonState.revision;
367
+ const clientResults = jsonState.results.map(toSnapshot);
368
+ const results = serverStructuredData ? [
369
+ toSnapshot({
370
+ value: serverStructuredData,
371
+ type: Array.isArray(serverStructuredData) ? "array" : "object",
372
+ source: "whole-string",
373
+ isComplete: true,
374
+ repairApplied: false,
375
+ warnings: ["Server structured_output payload"]
376
+ }),
377
+ ...clientResults
378
+ ] : clientResults;
370
379
  batchedDispatch(
371
380
  updateExtractedJson({
372
381
  requestId,
373
- results: jsonState.results.map(toSnapshot),
382
+ results,
374
383
  revision: jsonState.revision,
375
384
  isComplete: isFinal
376
385
  })
@@ -1920,6 +1929,10 @@ async function processStream({
1920
1929
  );
1921
1930
  } else if (isStructuredOutputEvent(event)) {
1922
1931
  otherEvents++;
1932
+ if (event.data.success && event.data.data != null && typeof event.data.data === "object") {
1933
+ serverStructuredData = event.data.data;
1934
+ runJsonExtraction(false);
1935
+ }
1923
1936
  dispatch(
1924
1937
  appendTimeline({
1925
1938
  requestId,
@@ -276,6 +276,8 @@ export interface HeadlessAgentJsonResult {
276
276
  * result passes through untouched.
277
277
  */
278
278
  export declare function failWarnedOutputMissingKeys(getState: () => ChatRootState, opts: Pick<HeadlessAgentJsonOptions, "mandateKey" | "surfaceKey" | "expect">, result: HeadlessAgentJsonResult): Promise<HeadlessAgentJsonResult>;
279
+ /** The first JSON object in `text` that holds EVERY required key, or null. */
280
+ export declare function recoverByRequiredKeys(text: string | undefined, required: readonly string[]): Record<string, unknown> | null;
279
281
  /**
280
282
  * The plain sentence of a warned-holder failure (`failWarnedOutputMissingKeys`),
281
283
  * or `null` for any other result. A lane that swallows failures to `null`
@@ -1,4 +1,4 @@
1
- import { extractFirstJson } from "@ai-matrx/kit/json-extract";
1
+ import { extractAllJson, extractFirstJson } from "@ai-matrx/kit/json-extract";
2
2
  import { extractErrorMessage } from "@ai-matrx/data/net";
3
3
  import { destroyInstanceIfAllowed } from "../conversations/conversations.thunks.js";
4
4
  import { captureError } from "../../../../host/diagnostics.js";
@@ -129,13 +129,18 @@ async function failWarnedOutputMissingKeys(getState, opts, result) {
129
129
  if (required.length === 0) return result;
130
130
  let missing;
131
131
  if (result.success && isRecord) {
132
- const record = data;
133
- const answers = typeof record.answers === "object" && record.answers !== null && !Array.isArray(record.answers) ? record.answers : null;
134
- missing = required.filter((key) => !(key in record) && !(answers && key in answers));
132
+ missing = missingRequiredKeys(data, required);
135
133
  } else {
136
134
  missing = [...required];
137
135
  }
138
136
  if (missing.length === 0) return result;
137
+ const recovered = recoverByRequiredKeys(result.fullResponse, required);
138
+ if (recovered) {
139
+ console.warn(
140
+ `[runHeadlessAgentJson] ${opts.surfaceKey}: the first JSON read lacked ${missing.join(", ")}; a candidate in the answer holding every required key was used instead.`
141
+ );
142
+ return { ...result, success: true, data: recovered, noResult: false, error: void 0, errorDetail: void 0 };
143
+ }
139
144
  const warning = resolved.outputWarnings[0];
140
145
  const holderId = warning.holderId ?? resolved.agentId;
141
146
  let holderName;
@@ -174,6 +179,21 @@ async function failWarnedOutputMissingKeys(getState, opts, result) {
174
179
  errorDetail: `mandate_output_unusable: missing ${keys}`
175
180
  };
176
181
  }
182
+ function missingRequiredKeys(record, required) {
183
+ const answers = typeof record.answers === "object" && record.answers !== null && !Array.isArray(record.answers) ? record.answers : null;
184
+ return required.filter((key) => !(key in record) && !(answers && key in answers));
185
+ }
186
+ function recoverByRequiredKeys(text, required) {
187
+ if (!text || required.length === 0) return null;
188
+ for (const candidate of extractAllJson(text, { allowFuzzy: true })) {
189
+ const value = candidate.value;
190
+ if (typeof value !== "object" || value === null || Array.isArray(value)) continue;
191
+ if (missingRequiredKeys(value, required).length === 0) {
192
+ return value;
193
+ }
194
+ }
195
+ return null;
196
+ }
177
197
  function mandateOutputUnusableSentence(result) {
178
198
  if (result.success) return null;
179
199
  if (!result.errorDetail?.startsWith("mandate_output_unusable")) return null;
@@ -565,5 +585,6 @@ export {
565
585
  failWarnedOutputMissingKeys,
566
586
  livePosture,
567
587
  mandateOutputUnusableSentence,
588
+ recoverByRequiredKeys,
568
589
  runHeadlessAgentJson
569
590
  };
@@ -1,7 +1,8 @@
1
1
  import { computeChildOwnedRanges } from "./child-owned-ranges.js";
2
2
  import { toCxMediaPart } from "@ai-matrx/media/files";
3
3
  import { isUnifiedImageBlock } from "@ai-matrx/media/files";
4
- import { isSpecialCodeLanguage } from "../../../../host/content-ir-slots.js";
4
+ import { SPECIAL_CODE_LANGUAGES } from "@ai-matrx/rich-content/display/markdown-classification/processors/utils/content-splitter-core";
5
+ const isSpecialCodeLanguage = (language) => SPECIAL_CODE_LANGUAGES.includes(language);
5
6
  import { IR_ENVELOPE_KEY } from "@ai-matrx/content-ir";
6
7
  import { envelopeCacheFromEnvelopes } from "@ai-matrx/content-ir";
7
8
  import { readEnvelope } from "@ai-matrx/content-ir";
@@ -40,3 +40,11 @@ export declare function prepareInboundRenderBlock(data: RenderBlockPayload, gate
40
40
  block: RenderBlockPayload;
41
41
  sanitized: RenderBlockPayload;
42
42
  };
43
+ /**
44
+ * Ingest guard for SERVER-BUILT envelopes riding `metadata.__ir` on a `render_block` event:
45
+ * valid -> same reference back + seeded into rich-content's region-envelope memo; malformed ->
46
+ * stripped copy + a loud diagnostic. Semantics live on the pure function in `@ai-matrx/content-ir`.
47
+ */
48
+ export declare function sanitizeInboundEnvelopeMetadata(metadata: Record<string, unknown> | null | undefined, context: {
49
+ blockId: string;
50
+ }): Record<string, unknown> | undefined;
@@ -1,5 +1,6 @@
1
1
  import { captureError } from "../../../../host/diagnostics.js";
2
- import { sanitizeInboundEnvelopeMetadata } from "../../../../host/content-ir-slots.js";
2
+ import { sanitizeInboundEnvelopeMetadata as sanitizeInboundEnvelopeMetadataPure } from "@ai-matrx/content-ir";
3
+ import { seedEnvelope } from "@ai-matrx/rich-content/kinds/registry/region-envelope-memo";
3
4
  import { sanitizeInboundPartialKindMetadata } from "@ai-matrx/content-ir/wire";
4
5
  import { fromRenderBlock } from "@ai-matrx/media/files";
5
6
  function prepareInboundRenderBlock(data, gatePartialKindStaleness) {
@@ -30,6 +31,20 @@ function prepareInboundRenderBlock(data, gatePartialKindStaleness) {
30
31
  sanitized
31
32
  };
32
33
  }
34
+ function sanitizeInboundEnvelopeMetadata(metadata, context) {
35
+ return sanitizeInboundEnvelopeMetadataPure(metadata, context, {
36
+ seedEnvelope: (envelope) => seedEnvelope(envelope),
37
+ reportMalformed: ({ blockId, engine, raw }) => {
38
+ captureError({
39
+ source: "content-ir",
40
+ message: `render_block "${blockId}" carried a malformed metadata.__ir envelope (engine "${engine}") \u2014 dropped before Redux so it can't poison the pipeline`,
41
+ relation: engine,
42
+ raw
43
+ });
44
+ }
45
+ });
46
+ }
33
47
  export {
34
- prepareInboundRenderBlock
48
+ prepareInboundRenderBlock,
49
+ sanitizeInboundEnvelopeMetadata
35
50
  };
@@ -6,7 +6,7 @@ import {
6
6
  } from "@ai-matrx/media/files";
7
7
  import { DECISION_ANSWERS_BLOCK_TYPE } from "../../../../utils/content-ir/decision-answers-ids.js";
8
8
  import { withPerformedScript } from "../../../speech-script/types.js";
9
- import { seedPersistedEnvelopeCache } from "../../../../host/content-ir-slots.js";
9
+ import { seedPersistedEnvelopeCache } from "@ai-matrx/rich-content/kinds/registry/region-envelope-memo";
10
10
  function normalizeContentBlocks(rawBlocks) {
11
11
  return rawBlocks.map((block, i) => normalizeSingle(block, i));
12
12
  }
@@ -0,0 +1,11 @@
1
+ import type { RenderBlockPayload } from "@ai-matrx/agents/generated/stream-events";
2
+ /**
3
+ * Promote a server progress event's canonical `content_ir` value into the
4
+ * render block consumed by MarkdownStream/LiveRunDisplay.
5
+ *
6
+ * Pipeline endpoints still need their ordinary typed `data` event for domain
7
+ * state. When that event also carries `content_ir`, this adapter gives the
8
+ * exact same event a canonical visual representation without asking each
9
+ * feature to parse or route it itself.
10
+ */
11
+ export declare function progressDataRenderBlock(data: unknown, eventIndex: number, blockIndex: number): RenderBlockPayload | null;
@@ -0,0 +1,37 @@
1
+ import { IR_ENVELOPE_KEY } from "@ai-matrx/content-ir";
2
+ import { envelopeFromCompleteValue } from "@ai-matrx/rich-content/kinds/registry/kind-correctors";
3
+ import { applyIrKindRoute } from "@ai-matrx/rich-content/kinds/react/kind-route";
4
+ function progressDataRenderBlock(data, eventIndex, blockIndex) {
5
+ if (!isJsonObject(data) || !isJsonObject(data.content_ir)) return null;
6
+ const value = data.content_ir;
7
+ const kind = value.__kind;
8
+ if (typeof kind !== "string" || kind.trim().length === 0) return null;
9
+ const source = JSON.stringify(value);
10
+ const metadata = {
11
+ [IR_ENVELOPE_KEY]: envelopeFromCompleteValue(value, kind)
12
+ };
13
+ const routed = applyIrKindRoute({
14
+ type: "code",
15
+ serverData: { language: "json" },
16
+ metadata
17
+ });
18
+ const projectedContent = routed.serverData?.content;
19
+ return {
20
+ blockId: `progress_content_ir_${eventIndex}`,
21
+ blockIndex,
22
+ type: routed.type,
23
+ status: "complete",
24
+ // The unified artifact stage consumes RenderBlockPayload.content directly
25
+ // for structured_info. Preserve the JSON in the envelope fingerprint; put
26
+ // the registered component's canonical projection on the visible channel.
27
+ content: typeof projectedContent === "string" ? projectedContent : source,
28
+ data: routed.serverData ?? null,
29
+ metadata: routed.metadata
30
+ };
31
+ }
32
+ function isJsonObject(value) {
33
+ return typeof value === "object" && value !== null && !Array.isArray(value);
34
+ }
35
+ export {
36
+ progressDataRenderBlock
37
+ };
@@ -54,14 +54,13 @@ import {
54
54
  isUnclosedGenericXmlOpening,
55
55
  startUnrecognizedXmlContainer,
56
56
  normalizeCodeLanguage,
57
- isSpecialCodeLanguage,
58
- kindRegistry,
59
- componentRegistry,
60
- envelopeForCompletedFenceRegion,
61
- envelopeForCompletedXmlRegion,
62
- withIrEnvelope,
63
- sessionEnvelope
64
- } from "../../../../host/content-ir-slots.js";
57
+ SPECIAL_CODE_LANGUAGES
58
+ } from "@ai-matrx/rich-content/display/markdown-classification/processors/utils/content-splitter-v2";
59
+ import { kindRegistry } from "@ai-matrx/rich-content/host/kind-registry";
60
+ import { componentRegistry } from "@ai-matrx/rich-content/host/component-registry";
61
+ import { hostSplitterEnvelopes } from "@ai-matrx/rich-content/host/splitter-envelopes";
62
+ import { withIrEnvelope } from "@ai-matrx/rich-content/kinds/registry/region-envelope-memo";
63
+ import { sessionEnvelope } from "@ai-matrx/rich-content/kinds/registry/kind-correctors";
65
64
  import { disposeParseSession, openParseSession } from "@ai-matrx/content-ir";
66
65
  import {
67
66
  IR_ENVELOPE_KEY
@@ -71,6 +70,9 @@ import {
71
70
  splitAroundEmbeddedKindJson
72
71
  } from "../../../../utils/content-ir/surfaces/embedded-kind-json.js";
73
72
  import { captureError } from "../../../../host/diagnostics.js";
73
+ const isSpecialCodeLanguage = (language) => SPECIAL_CODE_LANGUAGES.includes(language);
74
+ const envelopeForCompletedXmlRegion = (tag, regionText) => hostSplitterEnvelopes()?.xmlRegion(tag, regionText) ?? null;
75
+ const envelopeForCompletedFenceRegion = (language, regionText) => hostSplitterEnvelopes()?.fenceRegion(language, regionText) ?? null;
74
76
  function countStructuralObjectBraces(source) {
75
77
  let opens = 0;
76
78
  let closes = 0;
@@ -1,4 +1,5 @@
1
1
  import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
2
+ import { chatHostHasDatabase } from "../../../host/configure.js";
2
3
  import {
3
4
  fetchMcpCatalog,
4
5
  connectMcpServer as connectMcpServerService
@@ -22,12 +23,14 @@ const initialState = {
22
23
  availabilityError: null
23
24
  };
24
25
  const EMPTY_MCP_AVAILABILITY = {};
26
+ const NEEDS_DATABASE = { condition: () => chatHostHasDatabase() };
25
27
  const fetchCatalog = createAsyncThunk("mcp/fetchCatalog", async () => {
26
28
  return fetchMcpCatalog();
27
- });
29
+ }, NEEDS_DATABASE);
28
30
  const fetchAvailability = createAsyncThunk(
29
31
  "mcp/fetchAvailability",
30
- async ({ organizationId, slugs }) => fetchMcpAvailability(organizationId, slugs)
32
+ async ({ organizationId, slugs }) => fetchMcpAvailability(organizationId, slugs),
33
+ NEEDS_DATABASE
31
34
  );
32
35
  const connectServer = createAsyncThunk(
33
36
  "mcp/connectServer",
@@ -35,7 +38,8 @@ const connectServer = createAsyncThunk(
35
38
  const connectionId = await connectMcpServerService(params);
36
39
  dispatch(fetchCatalog());
37
40
  return { serverId: params.serverId, connectionId };
38
- }
41
+ },
42
+ NEEDS_DATABASE
39
43
  );
40
44
  const connectServerWithCredentials = createAsyncThunk(
41
45
  "mcp/connectServerWithCredentials",
@@ -49,7 +53,8 @@ const connectServerWithCredentials = createAsyncThunk(
49
53
  });
50
54
  dispatch(fetchCatalog());
51
55
  return { serverId: params.serverId, connectionId: summary.connection_id };
52
- }
56
+ },
57
+ NEEDS_DATABASE
53
58
  );
54
59
  const disconnectServer = createAsyncThunk(
55
60
  "mcp/disconnectServer",
@@ -57,7 +62,8 @@ const disconnectServer = createAsyncThunk(
57
62
  await disconnectMcpConnection(serverId);
58
63
  dispatch(fetchCatalog());
59
64
  return serverId;
60
- }
65
+ },
66
+ NEEDS_DATABASE
61
67
  );
62
68
  const discoverServerTools = createAsyncThunk(
63
69
  "mcp/discoverServerTools",
@@ -70,14 +76,16 @@ const discoverServerTools = createAsyncThunk(
70
76
  resources: [],
71
77
  prompts: []
72
78
  };
73
- }
79
+ },
80
+ NEEDS_DATABASE
74
81
  );
75
82
  const refreshServerToken = createAsyncThunk(
76
83
  "mcp/refreshServerToken",
77
84
  async (serverId) => {
78
85
  await refreshMcpConnection(serverId);
79
86
  return serverId;
80
- }
87
+ },
88
+ NEEDS_DATABASE
81
89
  );
82
90
  const mcpSlice = createSlice({
83
91
  name: "mcp",
@@ -2,7 +2,9 @@ import { createAsyncThunk } from "@reduxjs/toolkit";
2
2
  import { supabase } from "../../../host/db.js";
3
3
  import { pgErrorToError } from "@ai-matrx/data";
4
4
  import { recordUnavailable } from "../../../host/diagnostics.js";
5
+ import { chatHostHasDatabase } from "../../../host/configure.js";
5
6
  const fetchAvailableTools = createAsyncThunk("tools/fetchAvailable", async (_, { getState }) => {
7
+ if (!chatHostHasDatabase()) return [];
6
8
  if (getState().tools.status === "succeeded") {
7
9
  return getState().tools.tools;
8
10
  }
@@ -28,6 +30,7 @@ const fetchToolById = createAsyncThunk(
28
30
  },
29
31
  {
30
32
  condition: (toolId, { getState }) => {
33
+ if (!chatHostHasDatabase()) return false;
31
34
  const state = getState().tools;
32
35
  if (state.tools.some((tool) => tool.id === toolId)) return false;
33
36
  if (state.identityById[toolId]) return false;
@@ -1,3 +1,8 @@
1
- export declare function ServerOperationBanner({ conversationId, }: {
1
+ /**
2
+ * A run that outlived its stream on the platform server (resume, reconnect, parked on a
3
+ * person). A host-owned conversation has no server operation, so the banner is absent there
4
+ * (G-DOOR gate).
5
+ */
6
+ export declare function ServerOperationBanner({ conversationId }: {
2
7
  conversationId: string;
3
8
  }): import("react").JSX.Element | null;
@@ -13,7 +13,12 @@ import { useAppDispatch, useAppSelector } from "../../store/hooks.js";
13
13
  import { selectActivePendingAsksForConversation } from "../ui-first-tools/redux/pending-asks.slice.js";
14
14
  import { resumeInstance } from "../redux/execution-system/thunks/resume-instance.thunk.js";
15
15
  import { reconnectServerOperation } from "./reconnect-server-operation.thunk.js";
16
- function ServerOperationBanner({
16
+ import { useConversationAbilities } from "../redux/execution-system/host-conversations/conversation-abilities.js";
17
+ function ServerOperationBanner({ conversationId }) {
18
+ const { hosted } = useConversationAbilities();
19
+ return hosted ? null : /* @__PURE__ */ jsx(ServerOperationBannerBody, { conversationId });
20
+ }
21
+ function ServerOperationBannerBody({
17
22
  conversationId
18
23
  }) {
19
24
  const dispatch = useAppDispatch();
@@ -1,7 +1,11 @@
1
1
  import { retryReconnect } from "./retry-reconnect.js";
2
2
  import { discardRetainedTransportConsumer } from "../redux/execution-system/thunks/process-stream.js";
3
3
  import { createAsyncThunk } from "@reduxjs/toolkit";
4
- import { runtimeOperationRejoinPath, settleRunPickup } from "@ai-matrx/agents/matrx";
4
+ import {
5
+ pickServerJobOperation,
6
+ runtimeOperationRejoinPath,
7
+ settleRunPickup
8
+ } from "@ai-matrx/agents/matrx";
5
9
  import { toast } from "../../host/notify.js";
6
10
  import { captureError } from "../../host/diagnostics.js";
7
11
  import { setRequestStatus } from "../redux/execution-system/active-requests/active-requests.slice.js";
@@ -77,8 +81,9 @@ const reconnectServerOperation = createAsyncThunk(
77
81
  clearFollower();
78
82
  return noFollow;
79
83
  }
80
- op = byLink?.operations.find((o) => !o.is_terminal) ?? null;
81
- settledWhileDisconnected = !op && Boolean(byLink?.operations.length);
84
+ const picked = pickServerJobOperation(byLink?.operations);
85
+ op = picked && !picked.is_terminal ? picked : null;
86
+ settledWhileDisconnected = Boolean(picked?.is_terminal);
82
87
  } catch (err) {
83
88
  const superseded = ctrl.signal.aborted || !stillOwner();
84
89
  clearFollower();
@@ -263,9 +268,8 @@ const reconnectServerOperation = createAsyncThunk(
263
268
  clearFollower();
264
269
  return noFollow;
265
270
  }
266
- const stillLive = refreshed?.operations.find(
267
- (operation) => !operation.is_terminal
268
- );
271
+ const latest = pickServerJobOperation(refreshed?.operations);
272
+ const stillLive = latest && !latest.is_terminal ? latest : null;
269
273
  if (stillLive) {
270
274
  if (followers.get(conversationId) === ctrl) {
271
275
  followers.delete(conversationId);
@@ -17,7 +17,7 @@ import { Button } from "@ai-matrx/design-system";
17
17
  import { Checkbox } from "../../../ui/checkbox.js";
18
18
  import { Textarea } from "@ai-matrx/design-system";
19
19
  import { ChangeDiff } from "../../../host/ui-slots.js";
20
- import { KindInstanceRender } from "../../../host/content-ir-slots.js";
20
+ import { KindInstanceRender } from "@ai-matrx/rich-content/host/app-bindings";
21
21
  import { StructuredValueView } from "../../../host/ui-slots.js";
22
22
  import { cn } from "@ai-matrx/design-system";
23
23
  import { useAppDispatch } from "../../../store/hooks.js";
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useMemo, useState } from "react";
4
- import { RichContent } from "../../../host/ui-slots.js";
5
4
  import {
6
5
  Info,
7
6
  AlertTriangle,
@@ -35,6 +34,7 @@ import { getAskDraft, setAskDraft } from "../redux/ask-draft-registry.js";
35
34
  import { AskCardCountdown } from "./AskCardCountdown.js";
36
35
  import { AgentCardShell } from "./AgentCardShell.js";
37
36
  import { Button } from "@ai-matrx/design-system/controls";
37
+ import { RichContent } from "@ai-matrx/rich-content/levels/RichContent";
38
38
  const SINGLE_LABELS = { send: "Send", skip: "Skip" };
39
39
  const OTHER_SENTINEL = "__matrx_other__";
40
40
  const LEVEL_ICONS = {
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { readOf } from "../../../../host/ui-slots.js";
4
- import { RichContent } from "../../../../host/ui-slots.js";
5
4
  import { UntrustedCount } from "../../../../host/ui-slots.js";
6
5
  import { useCallback, useEffect, useState } from "react";
7
6
  import {
@@ -48,6 +47,7 @@ import { confirm as confirmDialog } from "../../../../host/ui-slots.js";
48
47
  import { selectUserId } from "../../../../host/identity.js";
49
48
  import { useChatCanvasTab } from "../../../../host/canvas.js";
50
49
  import { CONVERSATION_LISTS_KIND } from "../../../../host/canvas-tabs.js";
50
+ import { RichContent } from "@ai-matrx/rich-content/levels/RichContent";
51
51
  function useConversationListsTab(conversationId) {
52
52
  const tab = useChatCanvasTab({ kind: CONVERSATION_LISTS_KIND, key: conversationId });
53
53
  return {
@@ -16,7 +16,7 @@ function useDomCapturePrint() {
16
16
  setError(null);
17
17
  let releaseRenderAll = null;
18
18
  try {
19
- const { renderAllDiagrams } = await import("../../host/markdown-slots.js");
19
+ const { renderAllDiagrams } = await import("@ai-matrx/rich-content/mermaid/lazy-draw");
20
20
  releaseRenderAll = (await renderAllDiagrams()).release;
21
21
  const [{ captureDocumentPdf }, { downloadFile }] = await Promise.all([
22
22
  import("@ai-matrx/alchemy/operate/capture"),
@@ -13,7 +13,7 @@ function printMarkdownContent(markdown, title = "AI Response") {
13
13
  prepare: async () => {
14
14
  let drawn;
15
15
  try {
16
- const { drawMermaidForPrint } = await import("../../host/markdown-slots.js");
16
+ const { drawMermaidForPrint } = await import("@ai-matrx/rich-content/mermaid/print-render");
17
17
  drawn = await drawMermaidForPrint(markdown);
18
18
  } catch (error) {
19
19
  console.error("[print] diagrams could not be drawn", error);
@@ -13,10 +13,8 @@ import {
13
13
  Save
14
14
  } from "lucide-react";
15
15
  import { Button } from "@ai-matrx/design-system/controls";
16
- import {
17
- MarkdownStream,
18
- AudioOutputBlockSkeleton
19
- } from "../../../host/markdown-slots.js";
16
+ import { MarkdownStream } from "../../../ui/markdown-stream/MarkdownStream.js";
17
+ import AudioOutputBlockSkeleton from "../../../ui/AudioOutputBlockSkeleton.js";
20
18
  import { useDomCapturePrint } from "../../../conversation/hooks/useDomCapturePrint.js";
21
19
  import { useAppSelector, useAppDispatch } from "../../../store/hooks.js";
22
20
  import { selectMessageHasUnsavedChanges } from "../../_legacy-stubs.js";
@@ -24,7 +22,7 @@ import { editMessage } from "../../_legacy-stubs.js";
24
22
  import { buildContentBlocksForSave } from "../../utils/buildContentBlocksForSave.js";
25
23
  import { useMediaLoadRecovery } from "@ai-matrx/media/core";
26
24
  import { chatConversationsActions } from "../../_legacy-stubs.js";
27
- import { RichDocumentActions } from "../../../host/rich-document-slots.js";
25
+ import { RichDocumentActions } from "@ai-matrx/rich-content/rich-document/RichDocumentActions";
28
26
  import { MessageTimestamp } from "../../../agents/components/messages-display/MessageTimestamp.js";
29
27
  import { ErrorAlchemyMenu } from "../../../host/ui-slots.js";
30
28
  import { downloadFile } from "@ai-matrx/kit/download";
@@ -13,10 +13,8 @@ import {
13
13
  Save
14
14
  } from "lucide-react";
15
15
  import { Button } from "@ai-matrx/design-system/controls";
16
- import {
17
- MarkdownStream,
18
- AudioOutputBlockSkeleton
19
- } from "../host/markdown-slots.js";
16
+ import { MarkdownStream } from "../ui/markdown-stream/MarkdownStream.js";
17
+ import AudioOutputBlockSkeleton from "../ui/AudioOutputBlockSkeleton.js";
20
18
  import { useDomCapturePrint } from "../conversation/hooks/useDomCapturePrint.js";
21
19
  import { useAppSelector, useAppDispatch } from "../store/hooks.js";
22
20
  import { selectMessageHasUnsavedChanges } from "./_legacy-stubs.js";
@@ -24,7 +22,7 @@ import { editMessage } from "./_legacy-stubs.js";
24
22
  import { buildContentBlocksForSave } from "./utils/buildContentBlocksForSave.js";
25
23
  import { useMediaLoadRecovery } from "@ai-matrx/media/core";
26
24
  import { chatConversationsActions } from "./_legacy-stubs.js";
27
- import { RichDocumentActions } from "../host/rich-document-slots.js";
25
+ import { RichDocumentActions } from "@ai-matrx/rich-content/rich-document/RichDocumentActions";
28
26
  import { MessageTimestamp } from "../agents/components/messages-display/MessageTimestamp.js";
29
27
  import { ErrorAlchemyMenu } from "../host/ui-slots.js";
30
28
  import { downloadFile } from "@ai-matrx/kit/download";