@ai-matrx/chat 0.7.5 → 0.7.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 (158) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/agents/api/fetch-pending-calls.js +4 -3
  3. package/dist/agents/api/submit-tool-results.js +3 -6
  4. package/dist/agents/components/ambient-assistant/ScrollAssistantLauncherImpl.js +13 -6
  5. package/dist/agents/components/chat/begin-fresh-chat.js +2 -2
  6. package/dist/agents/components/identity-refs/AiIdentityRef.js +2 -2
  7. package/dist/agents/components/inputs/smart-input/composer/ComposerSplash.js +2 -3
  8. package/dist/agents/components/inputs/smart-input/composer/useComposerMode.js +4 -2
  9. package/dist/agents/components/live-run/LiveRunDisplay.d.ts +7 -1
  10. package/dist/agents/components/live-run/LiveRunDisplay.js +3 -1
  11. package/dist/agents/components/messages-display/AgentConversationDisplay.js +1 -1
  12. package/dist/agents/components/messages-display/assistant/AgentEmptyMessageDisplay.js +4 -4
  13. package/dist/agents/components/messages-display/assistant/AssistantNoAnswer.js +1 -1
  14. package/dist/agents/components/messages-display/assistant/BreathingOrb.js +1 -1
  15. package/dist/agents/components/messages-display/assistant/InPlaceAnswerEditor.js +1 -1
  16. package/dist/agents/components/messages-display/citations/MessageSourcesRow.js +1 -1
  17. package/dist/agents/components/messages-display/conversation-tools/ConversationFindBar.js +4 -4
  18. package/dist/agents/components/messages-display/message-options/EditHistoryDialog.js +7 -7
  19. package/dist/agents/components/messages-display/user/AgentUserMessage.js +4 -4
  20. package/dist/agents/components/messages-display/user/CollabNoteMessage.js +2 -2
  21. package/dist/agents/components/messages-display/user/FirstTurnVariables.js +3 -3
  22. package/dist/agents/components/messages-display/user/PendingSendMessage.js +4 -4
  23. package/dist/agents/components/messages-display/user/RemarksTranscriptView.js +7 -7
  24. package/dist/agents/components/messages-display/user/ResourceAttachmentTile.js +9 -9
  25. package/dist/agents/components/messages-display/user/ResourceEditableToggleSamples.js +4 -4
  26. package/dist/agents/components/messages-display/user/UserActionBar.js +3 -3
  27. package/dist/agents/components/messages-display/user/UserMessageAttachmentStyleComparison.js +12 -12
  28. package/dist/agents/components/messages-display/user/UserMessageChipsDemo.js +19 -19
  29. package/dist/agents/components/messages-display/user/UserMessageHybridTileSamples.js +22 -22
  30. package/dist/agents/components/run/AgentRunnerPage.js +4 -4
  31. package/dist/agents/components/run/AssistantError.js +1 -1
  32. package/dist/agents/components/run/AssistantWarning.js +1 -1
  33. package/dist/agents/components/run/GenerationJobCard.js +5 -5
  34. package/dist/agents/components/run/IncompleteNote.js +1 -1
  35. package/dist/agents/components/run/RunJobWorkingLine.js +1 -1
  36. package/dist/agents/components/shared/AgentConversationColumn.js +1 -1
  37. package/dist/agents/components/shared/AgentHeaderMobile.js +6 -6
  38. package/dist/agents/components/shared/AgentModeController.js +1 -1
  39. package/dist/agents/components/shared/AutoInjectionSwitch.js +6 -6
  40. package/dist/agents/components/shared/DesktopFilterPanel.js +8 -8
  41. package/dist/agents/components/smart/AgentRunner.js +1 -1
  42. package/dist/agents/components/smart/CreateWithAiTabs.js +1 -1
  43. package/dist/agents/redux/agent-definition/agent-cache-bust-request.js +7 -7
  44. package/dist/agents/redux/execution-system/context-rules/receipt-check.js +2 -2
  45. package/dist/agents/redux/execution-system/inbox/inbox.thunks.d.ts +2 -2
  46. package/dist/agents/redux/execution-system/inbox/inbox.thunks.js +7 -15
  47. package/dist/agents/redux/execution-system/observational-memory/fetch-memory-cost.thunk.d.ts +1 -1
  48. package/dist/agents/redux/execution-system/observational-memory/fetch-memory-cost.thunk.js +7 -4
  49. package/dist/agents/redux/execution-system/selectors/aggregate.selectors.d.ts +1 -114
  50. package/dist/agents/redux/execution-system/selectors/aggregate.selectors.js +28 -43
  51. package/dist/agents/redux/execution-system/thunks/call-conversation-api.d.ts +44 -0
  52. package/dist/agents/redux/execution-system/thunks/call-conversation-api.js +78 -0
  53. package/dist/agents/redux/execution-system/thunks/continue-agent-json.d.ts +41 -0
  54. package/dist/agents/redux/execution-system/thunks/continue-agent-json.js +66 -0
  55. package/dist/agents/redux/execution-system/thunks/execute-instance.thunk.d.ts +20 -0
  56. package/dist/agents/redux/execution-system/thunks/execute-instance.thunk.js +9 -2
  57. package/dist/agents/redux/execution-system/thunks/launch-agent-execution.thunk.js +4 -6
  58. package/dist/agents/redux/execution-system/thunks/notify-and-play-dispatcher.d.ts +1 -5
  59. package/dist/agents/redux/execution-system/thunks/notify-and-play-dispatcher.js +2 -1
  60. package/dist/agents/redux/execution-system/thunks/resolve-base-url.js +7 -17
  61. package/dist/agents/redux/execution-system/thunks/settle-after-stop.thunk.js +2 -2
  62. package/dist/agents/redux/execution-system/thunks/smart-execute.thunk.js +3 -3
  63. package/dist/agents/redux/execution-system/utils/continuation-body.d.ts +8 -2
  64. package/dist/agents/redux/execution-system/utils/continuation-body.js +3 -3
  65. package/dist/agents/redux/execution-system/utils/required-organization.d.ts +18 -0
  66. package/dist/agents/redux/execution-system/utils/required-organization.js +14 -10
  67. package/dist/agents/redux/execution-system/utils/stream-block-accumulator.d.ts +69 -333
  68. package/dist/agents/redux/execution-system/utils/stream-block-accumulator.js +268 -1896
  69. package/dist/agents/services/mcp-connections.service.js +5 -8
  70. package/dist/agents/ui-first-tools/dispatcher/dispatch-ui-first-tool.thunk.js +2 -1
  71. package/dist/host/defaults/files-host.js +11 -1
  72. package/dist/host/defaults/files-ui.js +2 -1
  73. package/dist/host/defaults/server-api.d.ts +1 -15
  74. package/dist/host/defaults/server-api.js +0 -21
  75. package/dist/host/defaults/server.d.ts +2 -1
  76. package/dist/host/defaults/server.js +8 -6
  77. package/dist/host/request-headers.d.ts +26 -0
  78. package/dist/host/request-headers.js +15 -0
  79. package/dist/host/server/call-api.d.ts +0 -13
  80. package/dist/host/server/call-api.js +0 -2
  81. package/dist/host/server/matrx-transport.d.ts +0 -1
  82. package/dist/host/server/matrx-transport.js +0 -2
  83. package/dist/store/root-state.d.ts +4 -21
  84. package/dist/surfaces/hooks/useSurfaceConfig.js +2 -1
  85. package/dist/surfaces/runtime/surface-feedback.js +2 -2
  86. package/dist/tool-call-visualization/components/ArtifactResultBar.js +4 -4
  87. package/dist/tool-call-visualization/components/ChatResultColumn.d.ts +1 -1
  88. package/dist/tool-call-visualization/components/ToolCallBatch.js +2 -2
  89. package/dist/tool-call-visualization/components/ToolCallVisualization.js +5 -5
  90. package/dist/tool-call-visualization/components/ToolTabBodies.js +12 -12
  91. package/dist/tool-call-visualization/components/ToolUpdatesOverlay.js +4 -4
  92. package/dist/tool-call-visualization/configured-rows/ConfiguredToolRow.js +8 -8
  93. package/dist/tool-call-visualization/configured-rows/CopyToolButton.js +1 -1
  94. package/dist/tool-call-visualization/configured-rows/ToolProgressView.js +7 -7
  95. package/dist/tool-call-visualization/configured-rows/field-components.js +28 -50
  96. package/dist/tool-call-visualization/registry/GenericRenderer.js +4 -4
  97. package/dist/tool-call-visualization/renderers/_shared-entity/EmptyResultCard.js +1 -1
  98. package/dist/tool-call-visualization/renderers/_shared-entity/EntityCard.js +5 -5
  99. package/dist/tool-call-visualization/renderers/_shared-entity/PartPeekPopover.js +2 -2
  100. package/dist/tool-call-visualization/renderers/_shared-entity/ToolGlyph.js +1 -1
  101. package/dist/tool-call-visualization/renderers/_shared-entity/ToolResultCard.js +6 -6
  102. package/dist/tool-call-visualization/renderers/agent-call/AgentCallInline.js +5 -5
  103. package/dist/tool-call-visualization/renderers/agent-call/CollabCallCard.js +4 -4
  104. package/dist/tool-call-visualization/renderers/agent-call/ImageGenerationResult.js +1 -1
  105. package/dist/tool-call-visualization/renderers/ask/AskInline.js +3 -3
  106. package/dist/tool-call-visualization/renderers/ask-person/AskPersonInline.js +2 -2
  107. package/dist/tool-call-visualization/renderers/cloud-browser/CloudBrowserRunCard.js +5 -5
  108. package/dist/tool-call-visualization/renderers/ctx/CtxBatchInline.js +3 -3
  109. package/dist/tool-call-visualization/renderers/ctx/CtxGetInline.js +2 -2
  110. package/dist/tool-call-visualization/renderers/ctx/CtxItemCard.js +3 -3
  111. package/dist/tool-call-visualization/renderers/ctx/CtxPatchInline.js +6 -6
  112. package/dist/tool-call-visualization/renderers/dictionary/DictEntryList.js +12 -12
  113. package/dist/tool-call-visualization/renderers/dictionary/DictionaryOverlay.js +5 -5
  114. package/dist/tool-call-visualization/renderers/fs/FsInline.js +7 -7
  115. package/dist/tool-call-visualization/renderers/news-api/NewsInline.js +17 -17
  116. package/dist/tool-call-visualization/renderers/news-api/NewsOverlay.js +12 -12
  117. package/dist/tool-call-visualization/renderers/random-wheel/RandomWheelInline.js +34 -34
  118. package/dist/tool-call-visualization/renderers/records/RecordsInline.js +1 -1
  119. package/dist/tool-call-visualization/renderers/research/ResearchInline.js +10 -10
  120. package/dist/tool-call-visualization/renderers/research/ResearchOverlay.js +19 -19
  121. package/dist/tool-call-visualization/renderers/research/SubagentReportBlock.js +11 -11
  122. package/dist/tool-call-visualization/renderers/scrape/ScrapeInline.js +18 -18
  123. package/dist/tool-call-visualization/renderers/scrape/ScrapeOverlay.js +17 -17
  124. package/dist/tool-call-visualization/renderers/search/SearchInline.js +30 -30
  125. package/dist/tool-call-visualization/renderers/search/SearchOverlay.js +40 -40
  126. package/dist/tool-call-visualization/renderers/shell/ShellInline.js +3 -3
  127. package/dist/tool-call-visualization/renderers/skill/SkillInline.js +5 -5
  128. package/dist/tool-call-visualization/renderers/sql/DbSchemaInline.js +7 -7
  129. package/dist/tool-call-visualization/renderers/sql/SqlInline.js +4 -4
  130. package/dist/tool-call-visualization/renderers/workbook/WorkbookGrid.js +4 -4
  131. package/dist/tool-call-visualization/renderers/workbook/WorkbookInline.js +2 -2
  132. package/dist/tool-call-visualization/renderers/workbook/WorkbookOverlay.js +7 -7
  133. package/dist/tool-call-visualization/renderers/working-document/PatchDiffInline.js +3 -3
  134. package/dist/tool-call-visualization/result-fields/EmptyResult.js +1 -1
  135. package/dist/tool-call-visualization/result-fields/KeyValueGrid.js +9 -9
  136. package/dist/tool-call-visualization/result-fields/ResultFile.js +4 -4
  137. package/dist/tool-call-visualization/result-fields/ResultJson.js +1 -1
  138. package/dist/tool-call-visualization/result-fields/ResultMedia.js +2 -2
  139. package/dist/tool-call-visualization/result-fields/ResultScalar.js +2 -2
  140. package/dist/tool-call-visualization/result-fields/ResultTable.js +10 -10
  141. package/dist/tool-call-visualization/result-fields/ResultValue.js +7 -7
  142. package/dist/tool-call-visualization/result-fields/ShortId.js +3 -3
  143. package/dist/tool-call-visualization/result-fields/ToolErrorCard.js +4 -4
  144. package/dist/tool-call-visualization/result-fields/UrlChips.js +3 -3
  145. package/dist/tool-call-visualization/surface-write/SurfaceWriteDiff.js +2 -2
  146. package/dist/tool-call-visualization/surface-write/SurfaceWriteStress.js +1 -1
  147. package/dist/tool-call-visualization/window-panel/ToolCallWindowPanel.js +9 -9
  148. package/dist/ui/mandates-storage/mandateStorage.d.ts +36 -0
  149. package/dist/ui/mandates-storage/shortcutStorage.d.ts +9 -0
  150. package/dist/ui/markdown-stream/EnhancedChatMarkdown.js +22 -0
  151. package/dist/ui/markdown-stream/MarkdownStreamImpl.js +3 -3
  152. package/dist/ui/markdown-stream/StreamTextFallback.d.ts +6 -0
  153. package/dist/ui/markdown-stream/StreamTextFallback.js +23 -0
  154. package/dist/ui/markdown-stream/merge-thinking-across-hidden.d.ts +19 -0
  155. package/dist/ui/markdown-stream/merge-thinking-across-hidden.js +21 -0
  156. package/package.json +14 -9
  157. package/dist/agents/redux/execution-system/utils/content-prefilter.d.ts +0 -50
  158. package/dist/agents/redux/execution-system/utils/content-prefilter.js +0 -243
@@ -0,0 +1,66 @@
1
+ import { removeContextEntry, setContextEntries } from "../instance-context/instance-context.slice.js";
2
+ import { setUserInputText } from "../instance-user-input/instance-user-input.slice.js";
3
+ import { executeInstance } from "./execute-instance.thunk.js";
4
+ import { loadConversation } from "./load-conversation.thunk.js";
5
+ import {
6
+ adoptHeadlessAgentJson
7
+ } from "./run-headless-agent-json.js";
8
+ function continuationTurnProblem(opts) {
9
+ const typed = typeof opts.userInput === "string" && opts.userInput.trim().length > 0;
10
+ if (typed && opts.hostTurn) return "A turn is the person's words or a host turn, never both.";
11
+ if (!typed && !opts.hostTurn) return "Nothing to send: the turn has neither the person's words nor a host turn.";
12
+ if (opts.hostTurn && (!opts.hostTurn.text.trim() || !opts.hostTurn.reason.trim())) return "A host turn needs its text and its reason.";
13
+ return null;
14
+ }
15
+ async function continueAgentJson(dispatch, getState, opts) {
16
+ const { conversationId } = opts;
17
+ const problem = continuationTurnProblem(opts);
18
+ if (problem) return { success: false, data: null, fullResponse: "", error: problem, conversationId };
19
+ try {
20
+ if (!getState().conversations.byConversationId[conversationId]) {
21
+ await dispatch(loadConversation({ conversationId })).unwrap();
22
+ }
23
+ const context = Object.entries(opts.context ?? {});
24
+ const writes = context.filter(([, value]) => value !== null && value !== void 0);
25
+ for (const [key] of context.filter(([, value]) => value === null)) dispatch(removeContextEntry({ conversationId, key }));
26
+ if (writes.length) dispatch(setContextEntries({ conversationId, entries: writes.map(([key, value]) => ({ key, value })) }));
27
+ if (opts.userInput) dispatch(setUserInputText({ conversationId, text: opts.userInput }));
28
+ let requestId = null;
29
+ const sent = await dispatch(
30
+ executeInstance({
31
+ conversationId,
32
+ initiation: opts.initiation ?? (opts.hostTurn ? "auto" : "user"),
33
+ ...opts.hostTurn ? { hostTurn: opts.hostTurn } : {},
34
+ onRequestId: (id) => {
35
+ requestId = id;
36
+ opts.onRequestId?.(id);
37
+ }
38
+ })
39
+ );
40
+ if (executeInstance.rejected.match(sent)) {
41
+ const reason = typeof sent.payload === "string" ? sent.payload : sent.error.message ?? "The turn could not be sent.";
42
+ return { success: false, data: null, fullResponse: "", error: reason, conversationId, ...requestId ? { requestId } : {} };
43
+ }
44
+ return await adoptHeadlessAgentJson(dispatch, getState, {
45
+ requestId: sent.payload.requestId,
46
+ conversationId,
47
+ surfaceKey: opts.surfaceKey,
48
+ keepInstance: opts.keepInstance ?? true,
49
+ ...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
50
+ ...opts.pollIntervalMs !== void 0 ? { pollIntervalMs: opts.pollIntervalMs } : {},
51
+ ...opts.settleMs !== void 0 ? { settleMs: opts.settleMs } : {},
52
+ ...opts.expect ? { expect: opts.expect } : {},
53
+ ...opts.onResult ? { onResult: opts.onResult } : {},
54
+ ...opts.signal ? { signal: opts.signal } : {},
55
+ ...opts.failureMessages ? { failureMessages: opts.failureMessages } : {}
56
+ });
57
+ } catch (err) {
58
+ const message = err instanceof Error ? err.message : String(err);
59
+ console.error("[continueAgentJson] the turn failed before it ran", { conversationId, err });
60
+ return { success: false, data: null, fullResponse: "", error: message, conversationId };
61
+ }
62
+ }
63
+ export {
64
+ continuationTurnProblem,
65
+ continueAgentJson
66
+ };
@@ -36,6 +36,8 @@ export declare function isEmptyUserInput(userInput: unknown): boolean;
36
36
  */
37
37
  export declare function refusesEmptyTurn(args: {
38
38
  retry: boolean;
39
+ /** A host-written turn is a message even with no `user_input`. */
40
+ hostTurn?: boolean;
39
41
  hasPriorTurns: boolean;
40
42
  cacheOnly: boolean;
41
43
  isEphemeral: boolean;
@@ -123,6 +125,24 @@ interface ExecuteInstanceArgs {
123
125
  * composer: the person may already be typing the next message in it.
124
126
  */
125
127
  submission?: FrozenSubmission;
128
+ /**
129
+ * A turn the HOST writes on a persisted conversation — never something the
130
+ * person typed (THE USER-INPUT LAW). Sent as `host_turn` instead of
131
+ * `user_input`: a short activation line the model reads, plus which host
132
+ * feature wrote it; the turn's content rides `context`. Only a continuation
133
+ * (the conversation already has turns). The Applet builder's automatic fix
134
+ * round is one (lane F6b).
135
+ */
136
+ hostTurn?: HostTurnInput;
137
+ }
138
+ /** `ConversationContinueRequest.host_turn` — what a host-written turn carries. */
139
+ export interface HostTurnInput {
140
+ /** The activation line the model reads. */
141
+ text: string;
142
+ /** Which host feature wrote it (≤80 chars). */
143
+ reason: string;
144
+ /** Extra stamps for the stored message. */
145
+ metadata?: Record<string, unknown>;
126
146
  }
127
147
  interface ExecuteInstanceResult {
128
148
  requestId: string;
@@ -155,7 +155,7 @@ function isEmptyUserInput(userInput) {
155
155
  });
156
156
  }
157
157
  function refusesEmptyTurn(args) {
158
- if (args.retry || !args.hasPriorTurns) return false;
158
+ if (args.retry || args.hostTurn || !args.hasPriorTurns) return false;
159
159
  if (!shouldContinuePersistedConversation(
160
160
  args.cacheOnly,
161
161
  args.hasPriorTurns,
@@ -254,7 +254,8 @@ const executeInstance = createAsyncThunk(
254
254
  initiation,
255
255
  onRequestId,
256
256
  surfaceRefreshed = false,
257
- submission
257
+ submission,
258
+ hostTurn
258
259
  }, { getState, dispatch, rejectWithValue: reject }) => {
259
260
  const requestId = generateRequestId();
260
261
  const rejectWithValue = (value, originalErrorName) => reject(
@@ -340,6 +341,7 @@ const executeInstance = createAsyncThunk(
340
341
  }
341
342
  if (refusesEmptyTurn({
342
343
  retry,
344
+ hostTurn: Boolean(hostTurn),
343
345
  hasPriorTurns: selectMessageCount(conversationId)(state) > 0,
344
346
  cacheOnly: instance.cacheOnly,
345
347
  isEphemeral: instance.isEphemeral === true,
@@ -535,11 +537,16 @@ const executeInstance = createAsyncThunk(
535
537
  ).replace("{conversation_id}", encodeURIComponent(conversationId));
536
538
  url = `${baseUrl}${convPath}`;
537
539
  routedPayload = buildContinuationBody(payload, {
540
+ hostTurn,
538
541
  retry: Boolean(retry),
539
542
  debug: Boolean(debug),
540
543
  cacheBypass: pendingBypass
541
544
  });
542
545
  } else {
546
+ if (hostTurn) {
547
+ console.error(`[execute-instance] a host turn ("${hostTurn.reason}") was sent on conversation "${conversationId}", which has no persisted turns \u2014 nothing was sent.`);
548
+ return rejectWithValue("A host turn continues a conversation; this one has no turns yet");
549
+ }
543
550
  const start = resolveStartPath({
544
551
  agentId: instance.agentId,
545
552
  pinnedVersionId: instance.initialAgentVersionId ?? null,
@@ -26,10 +26,7 @@ import { alwaysOnSurfaceKeys } from "../../../../surfaces/utils/always-on-contex
26
26
  import {
27
27
  fetchAgentRunTier
28
28
  } from "../../agent-definition/thunks.js";
29
- import {
30
- isSignedOutVisitor,
31
- NotAuthenticatedError
32
- } from "../../../../host/identity.js";
29
+ import { isSignedOutVisitor, NotAuthenticatedError, selectAccessToken } from "../../../../host/identity.js";
33
30
  import { applyLaunchModelOverrides } from "../instance-model-overrides/launch-model-overrides.js";
34
31
  import { selectAgentRunTier, selectAgentById } from "../../agent-definition/selectors.js";
35
32
  import { getShortcutRecordFromState } from "../../agent-shortcuts/selectors.js";
@@ -84,8 +81,9 @@ import {
84
81
  resolvePerLaunchMappings
85
82
  } from "./surface-scope-mapping.js";
86
83
  import { ensureAgentCatalog } from "../../../identity/agent-identity.js";
84
+ import { selectOrganizationId } from "../../../../host/org.js";
87
85
  function hasSignedInSession(state) {
88
- return Boolean(state.userAuth?.accessToken);
86
+ return Boolean(selectAccessToken(state));
89
87
  }
90
88
  const INTERACTIVE_MODES = /* @__PURE__ */ new Set([
91
89
  "modal-full",
@@ -144,7 +142,7 @@ const launchAgentExecution = createAsyncThunk("instances/launch", async (options
144
142
  );
145
143
  }
146
144
  if (!agentId) {
147
- const selectedOrganizationId = adminLaneOrganizationId() ?? getState().appContext?.organization_id ?? null;
145
+ const selectedOrganizationId = adminLaneOrganizationId() ?? selectOrganizationId(getState());
148
146
  const questionOrganizationId = organizationId ?? selectedOrganizationId ?? await (await import("../../../../host/org.js")).ensureOrgId(null);
149
147
  const displayKey = mandateKey;
150
148
  const resolved = await resolveMandate(displayKey, { organizationId: questionOrganizationId });
@@ -34,11 +34,7 @@ export interface NotifyAndPlayEntry<S> {
34
34
  run: (args: never, ctx: NotifyAndPlayContext<S>) => Promise<unknown>;
35
35
  };
36
36
  }
37
- export declare function createNotifyAndPlayDispatcher<S extends {
38
- userAuth?: {
39
- id?: string | null;
40
- } | null;
41
- }>(options: {
37
+ export declare function createNotifyAndPlayDispatcher<S>(options: {
42
38
  /** Redux action type prefix, e.g. "scribeTools/dispatch". */
43
39
  typePrefix: string;
44
40
  /** Human label used in the unknown-tool message, e.g. "scribe". */
@@ -1,12 +1,13 @@
1
1
  import { createAsyncThunk } from "@reduxjs/toolkit";
2
2
  import { extractErrorMessage } from "@ai-matrx/data/net";
3
3
  import { postDelegatedToolOutcome } from "./post-delegated-tool-outcome.js";
4
+ import { selectUserId } from "../../../../host/identity.js";
4
5
  function createNotifyAndPlayDispatcher(options) {
5
6
  const { typePrefix, family, isToolName, getEntry } = options;
6
7
  return createAsyncThunk(
7
8
  typePrefix,
8
9
  async ({ conversationId, requestId, callId, toolName, args }, { dispatch, getState }) => {
9
- const userId = getState().userAuth?.id ?? null;
10
+ const userId = selectUserId(getState());
10
11
  const base = { conversationId, requestId, callId, toolName };
11
12
  const fail = (errorType, message, durationMs) => postDelegatedToolOutcome(dispatch, {
12
13
  ...base,
@@ -1,5 +1,5 @@
1
- import { adminLaneHeadersFor, adminLaneOrganizationId } from "../../../../host/server/admin-lane.js";
2
- import { adminSeatReplyOrganizationId } from "../utils/required-organization.js";
1
+ import { chatRequestHeaders } from "../../../../host/request-headers.js";
2
+ import { conversationRequestOrganizationId } from "../utils/required-organization.js";
3
3
  import {
4
4
  selectResolvedBaseUrl,
5
5
  selectActiveServer
@@ -14,7 +14,6 @@ import {
14
14
  getCachedLocalEngine,
15
15
  supportsLocalAgentExecution
16
16
  } from "../../../../host/server/local-engine.js";
17
- import { selectOrganizationId } from "../../../../host/org.js";
18
17
  import { getChatHost, isChatHostConfigured } from "../../../../host/configure.js";
19
18
  import {
20
19
  ConfidentialRoutingRefusedError,
@@ -86,21 +85,12 @@ function resolveBackendUnchecked(state, conversationId) {
86
85
  const entry = state.instanceUIState?.byConversationId?.[conversationId] ?? null;
87
86
  const overrideUrl = entry?.serverOverrideUrl ?? null;
88
87
  const headers = {
89
- "Content-Type": "application/json"
88
+ "Content-Type": "application/json",
89
+ ...chatRequestHeaders(
90
+ { accessToken: selectAccessToken(state), fingerprintId: selectFingerprintId(state) },
91
+ conversationRequestOrganizationId(state, conversationId)
92
+ )
90
93
  };
91
- const accessToken = selectAccessToken(state);
92
- const fingerprintId = selectFingerprintId(state);
93
- if (accessToken) {
94
- headers["Authorization"] = `Bearer ${accessToken}`;
95
- } else if (fingerprintId) {
96
- headers["X-Fingerprint-ID"] = fingerprintId;
97
- }
98
- const conversationOrganizationId = state.conversations?.byConversationId?.[conversationId]?.organizationId ?? null;
99
- const organizationId = adminSeatReplyOrganizationId(state, conversationId) ?? conversationOrganizationId ?? adminLaneOrganizationId() ?? selectOrganizationId(state);
100
- if (organizationId) {
101
- headers["X-Organization-Id"] = organizationId;
102
- Object.assign(headers, adminLaneHeadersFor(organizationId));
103
- }
104
94
  if (overrideUrl) {
105
95
  const ref = resolveAgentSandboxRef(state, conversationId);
106
96
  if (ref && ref.kind !== "local-pc") {
@@ -1,5 +1,5 @@
1
1
  import { createAsyncThunk } from "@reduxjs/toolkit";
2
- import { cancelAgentRunRequest } from "../../../../host/server/matrx-transport.js";
2
+ import { cancelConversationRun } from "./call-conversation-api.js";
3
3
  import { fetchOperationsByLink } from "../../../runtime-reconnect/api.js";
4
4
  import { resolveBackendForConversation } from "./resolve-base-url.js";
5
5
  import { loadConversation } from "./load-conversation.thunk.js";
@@ -82,7 +82,7 @@ const settleAfterStop = createAsyncThunk(
82
82
  }
83
83
  if (op && !op.is_terminal && !cancelSentFor && op.request_id) {
84
84
  cancelSentFor = op.request_id;
85
- const result = await dispatch(cancelAgentRunRequest(op.request_id));
85
+ const result = await dispatch(cancelConversationRun(conversationId, op.request_id));
86
86
  if (result.error) {
87
87
  console.warn("[settle-after-stop] late server cancel failed", {
88
88
  conversationId,
@@ -37,7 +37,7 @@ import {
37
37
  selectInFlightRequestIds,
38
38
  settleAfterStop
39
39
  } from "./settle-after-stop.thunk.js";
40
- import { cancelAgentRunRequest } from "../../../../host/server/matrx-transport.js";
40
+ import { cancelConversationRun } from "./call-conversation-api.js";
41
41
  import { toast } from "../../../../host/notify.js";
42
42
  import { selectHostConversation } from "../host-conversations/host-conversations.selectors.js";
43
43
  import { sendToHost, stopHostTurn } from "../host-conversations/host-conversation.thunks.js";
@@ -508,7 +508,7 @@ const cancelExecution = createAsyncThunk(
508
508
  serverRequestId
509
509
  );
510
510
  void dispatch(
511
- cancelAgentRunRequest(serverRequestId, "cancel", seenSeq)
511
+ cancelConversationRun(conversationId, serverRequestId, "cancel", seenSeq)
512
512
  ).then((result) => {
513
513
  if (result.error) {
514
514
  console.warn(
@@ -564,7 +564,7 @@ const interruptAndSend = createAsyncThunk(
564
564
  serverRequestId
565
565
  );
566
566
  void dispatch(
567
- cancelAgentRunRequest(serverRequestId, "interrupt", seenSeq)
567
+ cancelConversationRun(conversationId, serverRequestId, "interrupt", seenSeq)
568
568
  ).then(
569
569
  (result) => {
570
570
  if (result.error) {
@@ -56,11 +56,17 @@ export declare const CONTINUATION_FIELD_ROUTING: {
56
56
  readonly max_iterations: "not assembled by this thunk";
57
57
  readonly max_retries_per_iteration: "not assembled by this thunk";
58
58
  readonly responder_agent_id: "coding-mirror replies only; not assembled by this thunk";
59
- readonly host_turn: "host-owned turns only; not assembled by this thunk";
59
+ readonly host_turn: "set by the builder from the hostTurn option (never copied from the payload)";
60
60
  };
61
61
  export interface ContinuationBodyOptions {
62
62
  retry: boolean;
63
+ /** A host-written turn: sent as `host_turn`, and `user_input` is omitted (the person said nothing). */
64
+ hostTurn?: {
65
+ text: string;
66
+ reason: string;
67
+ metadata?: Record<string, unknown>;
68
+ };
63
69
  debug: boolean;
64
70
  cacheBypass: unknown;
65
71
  }
66
- export declare function buildContinuationBody(payload: AssembledAgentStartRequest, { retry, debug, cacheBypass }: ContinuationBodyOptions): Record<string, unknown>;
72
+ export declare function buildContinuationBody(payload: AssembledAgentStartRequest, { retry, debug, cacheBypass, hostTurn }: ContinuationBodyOptions): Record<string, unknown>;
@@ -50,12 +50,12 @@ const CONTINUATION_FIELD_ROUTING = {
50
50
  max_iterations: "not assembled by this thunk",
51
51
  max_retries_per_iteration: "not assembled by this thunk",
52
52
  responder_agent_id: "coding-mirror replies only; not assembled by this thunk",
53
- host_turn: "host-owned turns only; not assembled by this thunk"
53
+ host_turn: "set by the builder from the hostTurn option (never copied from the payload)"
54
54
  };
55
55
  const EMPTY_IS_MEANINGFUL = /* @__PURE__ */ new Set(["tools", "output_kinds"]);
56
56
  const FALSE_IS_MEANINGFUL = /* @__PURE__ */ new Set(["memory", "tools_replace", "context_withheld"]);
57
- function buildContinuationBody(payload, { retry, debug, cacheBypass }) {
58
- const body = retry ? { retry: true } : { user_input: payload.user_input };
57
+ function buildContinuationBody(payload, { retry, debug, cacheBypass, hostTurn }) {
58
+ const body = retry ? { retry: true } : hostTurn ? { host_turn: hostTurn } : { user_input: payload.user_input };
59
59
  body.stream = true;
60
60
  const source = payload;
61
61
  for (const [key, route] of Object.entries(CONTINUATION_FIELD_ROUTING)) {
@@ -80,4 +80,22 @@ export declare function launchAsksForOrganizationBeforeOpen(launch: {
80
80
  opensWindow: boolean;
81
81
  }): boolean;
82
82
  export declare function ensureExecutionOrganization(state: ChatRootState, conversationId: string): Promise<string | null>;
83
+ /**
84
+ * THE ORG RULE (Audit B family 26): which organization a request on this conversation names.
85
+ * ONE function, read by the turn (`requireExecutionOrganizationId`) and by the conversation door
86
+ * every conversation-bound call rides (`resolveBackendForConversation`), so a turn and an inbox /
87
+ * tool-result / pending-calls / memory-cost / cancel call on the same conversation can never name
88
+ * different organizations. Guard: `__tests__/one-org-rule-per-conversation.test.ts`.
89
+ *
90
+ * - Not yet persisted (`cacheOnly !== false`, or not in the store): the organization a launcher
91
+ * declared, then the admin seat's platform tenant (only in a host with a database), then the
92
+ * app-selected organization.
93
+ * - Persisted: the row owns its organization forever. The one exception is a platform admin
94
+ * replying from the admin seat to a conversation they reach only as an admin: the request names
95
+ * the platform tenant (the admin lane admits nothing else); the row's own organization is
96
+ * restored server-side and never changes.
97
+ *
98
+ * Returns null when nothing names one (the caller decides whether that refuses).
99
+ */
100
+ export declare function conversationRequestOrganizationId(state: ChatRootState, conversationId: string): string | null;
83
101
  export declare function requireExecutionOrganizationId(state: ChatRootState, conversationId: string): string;
@@ -33,29 +33,33 @@ async function ensureExecutionOrganization(state, conversationId) {
33
33
  return null;
34
34
  }
35
35
  }
36
+ function conversationRequestOrganizationId(state, conversationId) {
37
+ const instance = state.conversations?.byConversationId?.[conversationId];
38
+ if (instance && instance.cacheOnly === false) {
39
+ return adminSeatReplyOrganizationId(state, conversationId) ?? instance.organizationId ?? null;
40
+ }
41
+ return instance?.organizationId ?? // A host with no database has no admin seat to bill (G-DOOR: this door branches on the host).
42
+ (chatHostHasDatabase() ? adminLaneOrganizationId() : null) ?? selectOrganizationId(state) ?? null;
43
+ }
36
44
  function requireExecutionOrganizationId(state, conversationId) {
37
45
  const instance = state.conversations.byConversationId[conversationId];
38
46
  if (!instance) {
39
47
  throw new Error(`Conversation ${conversationId} not found.`);
40
48
  }
49
+ const organizationId = conversationRequestOrganizationId(state, conversationId);
50
+ if (organizationId) return organizationId;
41
51
  if (instance.cacheOnly !== false) {
42
- const startOrganizationId = instance.organizationId ?? // A host with no database has no admin seat to bill (G-DOOR: this door branches on the host).
43
- (chatHostHasDatabase() ? adminLaneOrganizationId() : void 0) ?? selectOrganizationId(state);
44
- if (startOrganizationId) return startOrganizationId;
45
52
  throw new Error(
46
53
  "Select an organization before sending this message. The request was not sent."
47
54
  );
48
55
  }
49
- const organizationId = adminSeatReplyOrganizationId(state, conversationId) ?? instance.organizationId;
50
- if (!organizationId) {
51
- throw new Error(
52
- "This conversation has no organization. Reload it before sending another message."
53
- );
54
- }
55
- return organizationId;
56
+ throw new Error(
57
+ "This conversation has no organization. Reload it before sending another message."
58
+ );
56
59
  }
57
60
  export {
58
61
  adminSeatReplyOrganizationId,
62
+ conversationRequestOrganizationId,
59
63
  ensureExecutionOrganization,
60
64
  executionOrganizationForRequest,
61
65
  isFingerprintGuestExecution,