@ai-matrx/chat 0.4.9 → 0.4.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/dist/agents/components/context-items/bodies/ContextInputBody.js +1 -1
- package/dist/agents/components/context-items/bodies/GenericBody.js +1 -1
- package/dist/agents/components/conversation-actions/conversation-verbs.js +1 -1
- package/dist/agents/components/inputs/smart-input/RunSkillPicker.js +1 -1
- package/dist/agents/components/live-run/LiveRunDisplay.js +1 -1
- package/dist/agents/components/live-run/LiveRunProgress.js +1 -1
- package/dist/agents/components/live-run/RunSetDisplay.js +1 -1
- package/dist/agents/components/messages-display/assistant/AgentAssistantMessage.js +2 -2
- package/dist/agents/components/messages-display/assistant/InPlaceAnswerEditor.js +1 -1
- package/dist/agents/components/messages-display/conversation-tools/find-in-conversation.js +1 -1
- package/dist/agents/components/messages-display/message-options/buildTaskSeedFromMessage.js +1 -1
- package/dist/agents/components/messages-display/user/AgentUserMessage.js +1 -1
- package/dist/agents/components/messages-display/user/FirstTurnVariables.js +1 -1
- package/dist/agents/components/run/AgentStatusIndicator.js +1 -1
- package/dist/agents/components/run/RunJobWorkingLine.js +1 -1
- package/dist/agents/components/shared/AgentNewRunButton.js +1 -1
- package/dist/agents/components/shared/AgentPlanningIndicator.js +1 -1
- package/dist/agents/conversation-export/conversation-transfer.js +1 -1
- package/dist/agents/conversation-export/document-markdown.js +1 -1
- package/dist/agents/hooks/useConversationRoutePromotion.js +1 -1
- package/dist/agents/hooks/useModelControls.js +1 -1
- package/dist/agents/redux/agent-definition/converters.js +1 -1
- package/dist/agents/redux/agent-definition/slice.js +1 -1
- package/dist/agents/redux/conversation-list/conversation-list.thunks.js +1 -1
- package/dist/agents/redux/execution-system/active-requests/active-requests.selectors.js +1 -1
- package/dist/agents/redux/execution-system/instance-context/sync-canvas-item-context.thunk.js +1 -1
- package/dist/agents/redux/execution-system/thunks/process-stream.js +1 -1
- package/dist/agents/redux/execution-system/thunks/resolve-base-url.js +17 -0
- package/dist/agents/redux/execution-system/thunks/run-ai-stream.d.ts +7 -0
- package/dist/agents/redux/execution-system/thunks/run-ai-stream.js +13 -0
- package/dist/agents/redux/execution-system/thunks/run-headless-agent-json.js +14 -2
- package/dist/agents/redux/execution-system/utils/assemble-cx-content-blocks.js +1 -1
- package/dist/agents/redux/execution-system/utils/normalize-content-blocks.js +1 -1
- package/dist/agents/redux/execution-system/utils/output-contract-guard.js +1 -1
- package/dist/agents/redux/execution-system/utils/stream-block-accumulator.js +8 -8
- package/dist/agents/routing/confidential-routing.d.ts +52 -0
- package/dist/agents/routing/confidential-routing.js +38 -0
- package/dist/agents/utils/canvasItemContext.js +1 -1
- package/dist/canvas/workspace/ChatPanelTitleMenu.js +1 -1
- package/dist/canvas/workspace/useCanvasWorkspaceConversation.js +1 -1
- package/dist/cx-chat/components/SsrSidebarChats.js +1 -1
- package/dist/cx-chat/components/core/ChatConversationClient.js +1 -1
- package/dist/cx-chat/components/messages/AssistantMessage.js +1 -1
- package/dist/cx-chat/hooks/useInstanceBootstrap.js +1 -1
- package/dist/cx-conversation/AssistantMessage.js +1 -1
- package/dist/host/configure.js +4 -1
- package/dist/host/contract.d.ts +14 -1
- package/dist/host/index.d.ts +1 -0
- package/dist/host/index.js +1 -0
- package/dist/mandates/llm-params.d.ts +1 -1
- package/dist/mandates/output-contract.js +1 -1
- package/dist/mandates/service.d.ts +1 -1
- package/dist/mandates/service.js +1 -1
- package/dist/mandates/test-run-core.js +1 -1
- package/dist/public-chat/components/PublicMessageOptionsMenu.js +1 -1
- package/dist/surfaces/services/surface-config.service.js +1 -1
- package/dist/tool-call-visualization/components/ToolCallBatch.js +1 -1
- package/dist/tool-call-visualization/components/ToolCallVisualization.js +1 -1
- package/dist/tool-call-visualization/renderers/agent-call/AgentCallInline.js +1 -1
- package/dist/tool-call-visualization/renderers/agent-call/CollabCallCard.js +1 -1
- package/dist/tool-call-visualization/renderers/agent-call/collab-subtitle.js +3 -3
- package/dist/tool-call-visualization/renderers/skill/SkillInline.js +1 -1
- package/dist/tool-call-visualization/result-fields/KeyValueGrid.js +1 -1
- package/dist/tool-call-visualization/result-fields/ResultValue.js +1 -1
- package/dist/tool-call-visualization/result-fields/shape.js +1 -1
- package/dist/tool-call-visualization/utils/cxToolCallToLifecycleEntry.js +2 -2
- package/dist/tool-call-visualization/utils/human-copy.js +3 -3
- package/dist/ui/mandates-storage/provision-shapes.d.ts +1 -1
- package/dist/ui/mandates-storage/provision-shapes.js +1 -1
- package/dist/ui/markdown-stream/EnhancedChatMarkdown.js +1 -1
- package/dist/ui/treatment-shape.d.ts +1 -1
- package/dist/ui/treatment-shape.js +1 -1
- package/dist/voice-agent/relay/useVoiceRelaySession.js +1 -1
- package/package.json +26 -9
- package/dist/agents/hooks/useWarmAgent.d.ts +0 -8
- package/dist/agents/hooks/useWarmAgent.js +0 -25
- package/dist/agents/utils/artifactId.d.ts +0 -34
- package/dist/agents/utils/artifactId.js +0 -15
- package/dist/ui/ShimmerText.d.ts +0 -5
- package/dist/ui/ShimmerText.js +0 -21
- package/dist/ui/addressWithoutNavigating.d.ts +0 -68
- package/dist/ui/addressWithoutNavigating.js +0 -60
- package/dist/utils/content-ir/decision-answers-ids.d.ts +0 -3
- package/dist/utils/content-ir/decision-answers-ids.js +0 -6
- package/dist/utils/content-ir/envelope-parity.d.ts +0 -12
- package/dist/utils/content-ir/envelope-parity.js +0 -32
- package/dist/utils/content-ir/instance-title.d.ts +0 -26
- package/dist/utils/content-ir/instance-title.js +0 -39
- package/dist/utils/content-ir/kinds/kind-markdown-utils.d.ts +0 -84
- package/dist/utils/content-ir/kinds/kind-markdown-utils.js +0 -233
- package/dist/utils/content-ir/kinds/kind-value-markdown.d.ts +0 -5
- package/dist/utils/content-ir/kinds/kind-value-markdown.js +0 -17
- package/dist/utils/content-ir/legacy-quiz-envelope.d.ts +0 -3
- package/dist/utils/content-ir/legacy-quiz-envelope.js +0 -45
- package/dist/utils/content-ir/surfaces/embedded-kind-json.d.ts +0 -140
- package/dist/utils/content-ir/surfaces/embedded-kind-json.js +0 -527
- package/dist/utils/content-ir/surfaces/json-kind-signal.d.ts +0 -307
- package/dist/utils/content-ir/surfaces/json-kind-signal.js +0 -945
- package/dist/utils/content-ir/surfaces/kind-image-alt.d.ts +0 -27
- package/dist/utils/content-ir/surfaces/kind-image-alt.js +0 -117
- package/dist/utils/content-ir/surfaces/kind-one-line.d.ts +0 -67
- package/dist/utils/content-ir/surfaces/kind-one-line.js +0 -209
- package/dist/utils/content-ir/surfaces/kind-text-label.d.ts +0 -20
- package/dist/utils/content-ir/surfaces/kind-text-label.js +0 -50
- package/dist/utils/content-ir/surfaces/kind-text-to-markdown.d.ts +0 -47
- package/dist/utils/content-ir/surfaces/kind-text-to-markdown.js +0 -399
- package/dist/utils/content-ir/surfaces/markdown-escaped-kind.d.ts +0 -54
- package/dist/utils/content-ir/surfaces/markdown-escaped-kind.js +0 -128
- package/dist/utils/content-ir/surfaces/quoted-kind-lift.d.ts +0 -61
- package/dist/utils/content-ir/surfaces/quoted-kind-lift.js +0 -215
- package/dist/utils/inline-decision/decision-options.d.ts +0 -21
- package/dist/utils/inline-decision/decision-options.js +0 -32
- package/dist/utils/json.d.ts +0 -63
- package/dist/utils/json.js +0 -22
- package/dist/utils/markdown/plain-title.d.ts +0 -25
- package/dist/utils/markdown/plain-title.js +0 -51
- package/dist/utils/rendered-find.d.ts +0 -9
- package/dist/utils/rendered-find.js +0 -68
- package/dist/utils/rich-editor/core/caret-context.d.ts +0 -24
- package/dist/utils/rich-editor/core/caret-context.js +0 -73
- package/dist/utils/rich-editor/in-place/caret-handoff.d.ts +0 -3
- package/dist/utils/rich-editor/in-place/caret-handoff.js +0 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# @ai-matrx/chat
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
- Chat's own message surfaces import `ui/markdown-stream/MarkdownStream` by its default export, so a host test that mocks that module (default only) replaces it everywhere, as it did when it was a slot.
|
|
6
|
+
|
|
7
|
+
## 0.4.12 — chat keeps no copy of another package's code
|
|
8
|
+
|
|
9
|
+
- Deleted `src/utils/content-ir/**` (14 modules, 4.4k lines): every import now reads
|
|
10
|
+
`@ai-matrx/content-ir/surfaces`, whose versions are the stricter ones (the kind-value-markdown
|
|
11
|
+
registration lives on `globalThis`, so dual loaders share one registration).
|
|
12
|
+
- Deleted nine modules that were byte-identical to their owner and import the owner instead:
|
|
13
|
+
`agents/utils/artifactId`, `ui/ShimmerText`, `ui/addressWithoutNavigating`,
|
|
14
|
+
`utils/inline-decision/decision-options`, `utils/json`, `utils/markdown/plain-title`,
|
|
15
|
+
`utils/rendered-find` → `@ai-matrx/rich-content/utils/…`; `utils/rich-editor/core/caret-context`,
|
|
16
|
+
`utils/rich-editor/in-place/caret-handoff` → `@ai-matrx/rich-editor/…` (one caret hand-off
|
|
17
|
+
state instead of two).
|
|
18
|
+
|
|
19
|
+
Consumer action: replace these specifiers —
|
|
20
|
+
`@ai-matrx/chat/utils/content-ir/**` → `@ai-matrx/content-ir/surfaces` (re-register
|
|
21
|
+
`registerKindValueMarkdown` from there); `@ai-matrx/chat/agents/utils/artifactId` →
|
|
22
|
+
`@ai-matrx/rich-content/utils/lifted/artifactId`; `@ai-matrx/chat/ui/ShimmerText` →
|
|
23
|
+
`@ai-matrx/rich-content/utils/lifted/ShimmerText`; `@ai-matrx/chat/ui/addressWithoutNavigating` →
|
|
24
|
+
`@ai-matrx/rich-content/utils/addressWithoutNavigating`;
|
|
25
|
+
`@ai-matrx/chat/utils/inline-decision/decision-options` → `@ai-matrx/rich-content/utils/decision-options`;
|
|
26
|
+
`@ai-matrx/chat/utils/json` → `@ai-matrx/rich-content/utils/json`;
|
|
27
|
+
`@ai-matrx/chat/utils/markdown/plain-title` → `@ai-matrx/rich-content/utils/plain-title`;
|
|
28
|
+
`@ai-matrx/chat/utils/rendered-find` → `@ai-matrx/rich-content/utils/rendered-find`.
|
|
29
|
+
|
|
30
|
+
## 0.4.11 — every AI run request reports its client latency
|
|
31
|
+
|
|
32
|
+
- `runAiStream` sends `X-Matrx-Client-Sent-At` (epoch ms of the frozen submission moment) and
|
|
33
|
+
`X-Matrx-Client-Prep-Ms` (submission to fetch dispatch) on every turn and resume request
|
|
34
|
+
(`buildLatencyHeaders`); the server persists one `platform.ai_request_latency` row per request.
|
|
35
|
+
- Forcing test `agents/redux/execution-system/thunks/__tests__/every-ai-run-request-reports-its-client-latency.test.ts`.
|
|
36
|
+
|
|
37
|
+
Consumer action: none.
|
|
38
|
+
|
|
39
|
+
## 0.4.10 — a confidential conversation never reaches a cloud target
|
|
40
|
+
|
|
41
|
+
- THE CONFIDENTIAL-ROUTING RULE moves from the frozen kernel (`src/compat`) into the real chat:
|
|
42
|
+
`agents/routing/confidential-routing.ts` (pure: `decideRouting`, `localityOfChannel`,
|
|
43
|
+
`ConfidentialRoutingRefusedError`), also exported from `@ai-matrx/chat/host`.
|
|
44
|
+
- New host port `routing: { policy(conversationId) => "any" | "local-only" }` (default `"any"`).
|
|
45
|
+
- `resolveBackendForConversation` — the one place every send path resolves its target — refuses a
|
|
46
|
+
`local-only` conversation on every channel but `local-runtime` (the Matrx Local engine on this
|
|
47
|
+
computer), including the cloud fallback when a local-pc conversation finds no engine. It throws
|
|
48
|
+
`ConfidentialRoutingRefusedError` (message = the sentence the person reads, `remedy`, `code`
|
|
49
|
+
`confidential_thread_cloud_target_refused`) before any request is made.
|
|
50
|
+
- Forcing test `agents/routing/__tests__/confidential-conversation-never-reaches-the-cloud.test.ts`
|
|
51
|
+
(red on the unfixed resolver; three plant.py mutations red).
|
|
52
|
+
|
|
53
|
+
Consumer action: none for hosts without confidential conversations (the default policy is `"any"`).
|
|
54
|
+
A host with confidential conversations (matrx-local) passes `routing` to its chat host.
|
|
55
|
+
|
|
3
56
|
## 0.4.9 — the shell chat remembers each page's own chat, and its title menu lists your conversations
|
|
4
57
|
|
|
5
58
|
- `shellChatHome`: outside boards and Education, the conversation is remembered PER PAGE
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { humanizeIdentifier } from "@ai-matrx/kit/text-case";
|
|
4
4
|
import { AnswerValueView } from "../../../../host/ui-slots.js";
|
|
5
|
-
import { valueCarriesKind } from "
|
|
5
|
+
import { valueCarriesKind } from "@ai-matrx/content-ir/surfaces";
|
|
6
6
|
function displayValue(value) {
|
|
7
7
|
if (typeof value === "string") return value;
|
|
8
8
|
if (value === null) return "null";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { AnswerValueView } from "../../../../host/ui-slots.js";
|
|
4
|
-
import { hasKindKeyAnySpelling, valueCarriesKind } from "
|
|
4
|
+
import { hasKindKeyAnySpelling, valueCarriesKind } from "@ai-matrx/content-ir/surfaces";
|
|
5
5
|
function carriesKind(value) {
|
|
6
6
|
return valueCarriesKind(value);
|
|
7
7
|
}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
renameConversation
|
|
8
8
|
} from "../../redux/conversation-list/conversation-row-actions.thunks.js";
|
|
9
9
|
import { conversationRenameOpener } from "./rename/conversationRenameOpener.js";
|
|
10
|
-
import { conversationTitleText } from "
|
|
10
|
+
import { conversationTitleText } from "@ai-matrx/content-ir/surfaces";
|
|
11
11
|
function displayConversationTitle(title) {
|
|
12
12
|
if (!title) return "Untitled conversation";
|
|
13
13
|
return title.trim().length > 0 ? conversationTitleText(title) ?? title : "Untitled conversation";
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
PicksSkeletons
|
|
29
29
|
} from "./RunPicksSurface.js";
|
|
30
30
|
import { groupCatalog, toolCategoryLabel } from "./run-tool-catalog.js";
|
|
31
|
-
import { catalogProseText } from "
|
|
31
|
+
import { catalogProseText } from "@ai-matrx/content-ir/surfaces";
|
|
32
32
|
function tierForSkill(skillId, config) {
|
|
33
33
|
if (config.included.includes(skillId)) return "included";
|
|
34
34
|
if (config.listed.includes(skillId)) return "listed";
|
|
@@ -4,7 +4,7 @@ import { useEffect, useRef } from "react";
|
|
|
4
4
|
import { Loader2, TriangleAlert, X } from "lucide-react";
|
|
5
5
|
import { cn } from "@ai-matrx/design-system";
|
|
6
6
|
import { useAppSelector } from "../../../store/hooks.js";
|
|
7
|
-
import
|
|
7
|
+
import MarkdownStream from "../../../ui/markdown-stream/MarkdownStream.js";
|
|
8
8
|
import { AgentAssistantMessage } from "../messages-display/assistant/AgentAssistantMessage.js";
|
|
9
9
|
import { useRetainRequestForViewer } from "../../redux/execution-system/active-requests/useRetainRequestForViewer.js";
|
|
10
10
|
import {
|
|
@@ -5,7 +5,7 @@ import { cn } from "@ai-matrx/design-system";
|
|
|
5
5
|
import {
|
|
6
6
|
honestProgressSummary
|
|
7
7
|
} from "@ai-matrx/kit/progress";
|
|
8
|
-
import { isJsonObject } from "
|
|
8
|
+
import { isJsonObject } from "@ai-matrx/rich-content/utils/json";
|
|
9
9
|
const STATUSES = /* @__PURE__ */ new Set([
|
|
10
10
|
"waiting",
|
|
11
11
|
"running",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useAppDispatch, useAppSelector } from "../../../store/hooks.js";
|
|
4
|
-
import
|
|
4
|
+
import MarkdownStream from "../../../ui/markdown-stream/MarkdownStream.js";
|
|
5
5
|
import { cn } from "@ai-matrx/design-system";
|
|
6
6
|
import { LiveRunDisplay } from "./LiveRunDisplay.js";
|
|
7
7
|
import { selectRunSetEntries } from "../../redux/execution-system/run-sets/run-sets.slice.js";
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
useState,
|
|
8
8
|
useEffect
|
|
9
9
|
} from "react";
|
|
10
|
-
import
|
|
10
|
+
import MarkdownStream from "../../../../ui/markdown-stream/MarkdownStream.js";
|
|
11
11
|
import "../rich-document/chat-message-source.js";
|
|
12
12
|
import { RecordAnnotations, annotationRecordOf } from "@ai-matrx/rich-content/host/app-bindings";
|
|
13
13
|
import { useAppDispatch, useAppSelector } from "../../../../store/hooks.js";
|
|
@@ -75,7 +75,7 @@ import { retryConversationTurn } from "../../../redux/execution-system/message-c
|
|
|
75
75
|
import { commitInlineContentEdit } from "../../../redux/execution-system/message-crud/commit-inline-edit.thunk.js";
|
|
76
76
|
import { InPlaceAnswerEditor } from "./InPlaceAnswerEditor.js";
|
|
77
77
|
import { updateMessageRecord } from "../../../redux/execution-system/messages/messages.slice.js";
|
|
78
|
-
import { handInPlaceCaret } from "
|
|
78
|
+
import { handInPlaceCaret } from "@ai-matrx/rich-editor/in-place/caret-handoff";
|
|
79
79
|
import { toast } from "../../../../host/notify.js";
|
|
80
80
|
import { useDomCapturePrint } from "../../../../conversation/hooks/useDomCapturePrint.js";
|
|
81
81
|
import { MessageFilesStrip } from "../../../../host/ui-slots.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { Loader2 } from "lucide-react";
|
|
5
|
-
import { takeInPlaceCaret } from "
|
|
5
|
+
import { takeInPlaceCaret } from "@ai-matrx/rich-editor/in-place/caret-handoff";
|
|
6
6
|
import { useAppDispatch } from "../../../../store/hooks.js";
|
|
7
7
|
import { updateMessageRecord } from "../../../redux/execution-system/messages/messages.slice.js";
|
|
8
8
|
import {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { collectRenderedFindRanges, findRenderedTextMatches } from "
|
|
1
|
+
import { collectRenderedFindRanges, findRenderedTextMatches } from "@ai-matrx/rich-content/utils/rendered-find";
|
|
2
2
|
function findTextMatches(text, query) {
|
|
3
3
|
return findRenderedTextMatches(text, query.trim());
|
|
4
4
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { durableRecordId } from "@ai-matrx/kit/ids";
|
|
2
|
-
import { plainTitleFromMarkdown } from "
|
|
2
|
+
import { plainTitleFromMarkdown } from "@ai-matrx/rich-content/utils/plain-title";
|
|
3
3
|
import { cleanMarkdown } from "@ai-matrx/content-ir/source";
|
|
4
4
|
import { buildConversationMessageTitle } from "../../../utils/conversation-message-title.js";
|
|
5
5
|
function buildMessagePreviewLabel(content, maxLength = 160) {
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
} from "../../../redux/execution-system/instance-variable-values/instance-variable-values.selectors.js";
|
|
37
37
|
import { MessageAttachmentStrip } from "../MessageAttachmentStrip.js";
|
|
38
38
|
import { isAttachmentMessagePart } from "../../context-items/normalize.js";
|
|
39
|
-
import
|
|
39
|
+
import MarkdownStream from "../../../../ui/markdown-stream/MarkdownStream.js";
|
|
40
40
|
import "../rich-document/chat-message-source.js";
|
|
41
41
|
import { literalUserText } from "./literal-user-text.js";
|
|
42
42
|
import { buildVariableDisplayLines } from "../../../utils/variable-display-lines.js";
|
|
@@ -11,7 +11,7 @@ import { buildVariableDisplayLines } from "../../../utils/variable-display-lines
|
|
|
11
11
|
import { EntityRef } from "../../../../host/ui-slots.js";
|
|
12
12
|
import { useEntityTitles } from "../../../../host/ui-slots.js";
|
|
13
13
|
import { AnswerValueView } from "../../../../host/ui-slots.js";
|
|
14
|
-
import { isKindJsonText, valueCarriesKind } from "
|
|
14
|
+
import { isKindJsonText, valueCarriesKind } from "@ai-matrx/content-ir/surfaces";
|
|
15
15
|
function kindCarryingValue(value) {
|
|
16
16
|
if (!valueCarriesKind(value)) return null;
|
|
17
17
|
if (typeof value === "string" && isKindJsonText(value)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
|
-
import { ShimmerText } from "
|
|
4
|
+
import { ShimmerText } from "@ai-matrx/rich-content/utils/lifted/ShimmerText";
|
|
5
5
|
import { useAppSelector } from "../../../store/hooks.js";
|
|
6
6
|
import {
|
|
7
7
|
selectRequestGenerationJob,
|
|
@@ -6,7 +6,7 @@ import { useAppDispatch, useAppSelector } from "../../../store/hooks.js";
|
|
|
6
6
|
import { startNewConversation } from "../../redux/execution-system/thunks/create-instance.thunk.js";
|
|
7
7
|
import { PlusTapButton } from "@ai-matrx/tap-target/buttons";
|
|
8
8
|
import { selectFocusedConversation } from "../../redux/execution-system/conversation-focus/conversation-focus.selectors.js";
|
|
9
|
-
import { pushAddressWithoutNavigating } from "
|
|
9
|
+
import { pushAddressWithoutNavigating } from "@ai-matrx/rich-content/utils/addressWithoutNavigating";
|
|
10
10
|
function AgentNewRunButton({ surfaceKey }) {
|
|
11
11
|
const conversationId = useAppSelector(selectFocusedConversation(surfaceKey));
|
|
12
12
|
const dispatch = useAppDispatch();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import { ShimmerText } from "
|
|
3
|
+
import { ShimmerText } from "@ai-matrx/rich-content/utils/lifted/ShimmerText";
|
|
4
4
|
function AgentPlanningIndicator({
|
|
5
5
|
compact = false,
|
|
6
6
|
label = "Planning..."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { toast } from "../../host/notify.js";
|
|
2
2
|
import { unwrapKindEnvelopes } from "@ai-matrx/content-ir/source";
|
|
3
|
-
import { kindTextToMarkdown } from "
|
|
3
|
+
import { kindTextToMarkdown } from "@ai-matrx/content-ir/surfaces";
|
|
4
4
|
import { extractFlatText } from "../redux/execution-system/messages/messages.selectors.js";
|
|
5
5
|
import { selectConversationTitle } from "../redux/execution-system/conversations/conversations.selectors.js";
|
|
6
6
|
import { isMessagePinned } from "../message-pins/pinned-messages-store.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { unwrapKindEnvelopes } from "@ai-matrx/content-ir/source";
|
|
2
|
-
import { kindTextToMarkdown } from "
|
|
2
|
+
import { kindTextToMarkdown } from "@ai-matrx/content-ir/surfaces";
|
|
3
3
|
function documentMarkdown(markdown) {
|
|
4
4
|
return kindTextToMarkdown(unwrapKindEnvelopes(markdown));
|
|
5
5
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useEffect, useEffectEvent, useRef } from "react";
|
|
3
3
|
import { useRouter } from "../../host/navigation.js";
|
|
4
|
-
import { replaceAddressWithoutNavigating } from "
|
|
4
|
+
import { replaceAddressWithoutNavigating } from "@ai-matrx/rich-content/utils/addressWithoutNavigating";
|
|
5
5
|
import { useAppDispatch, useAppSelector, useAppStore } from "../../store/hooks.js";
|
|
6
6
|
import { waitForConversationPersisted } from "../redux/execution-system/conversations/conversation-persistence.js";
|
|
7
7
|
import { selectMessageCount } from "../redux/execution-system/messages/messages.selectors.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { LLM_PARAMS_KEYS } from "@ai-matrx/agents/generated/llm-enums";
|
|
3
3
|
import { UI_GATE_KEYS } from "../redux/agent-settings/ui-gates.js";
|
|
4
|
-
import { isJsonObject } from "
|
|
4
|
+
import { isJsonObject } from "@ai-matrx/rich-content/utils/json";
|
|
5
5
|
import { outputFormatControlKey } from "@ai-matrx/agents/models";
|
|
6
6
|
function supportsTools(normalizedControls) {
|
|
7
7
|
const normalizedTools = normalizedControls?.tools;
|
|
@@ -15,7 +15,7 @@ import { sanitizeAgentToolIds } from "./sanitize-tool-ids.js";
|
|
|
15
15
|
import { stripNullish } from "../../../ui/payload.js";
|
|
16
16
|
import { OrganizationContextError } from "@ai-matrx/agents/matrx";
|
|
17
17
|
import { parseUiGates } from "../agent-settings/ui-gates.js";
|
|
18
|
-
import { isJsonObject } from "
|
|
18
|
+
import { isJsonObject } from "@ai-matrx/rich-content/utils/json";
|
|
19
19
|
import {
|
|
20
20
|
recordAgentDataIssue,
|
|
21
21
|
recoverAgentDataField
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import { CONVERSATION_LIST_PAGE_SIZE } from "./conversation-list.types.js";
|
|
17
17
|
import { excludeHiddenLane } from "../conversation-history/history-filters.js";
|
|
18
18
|
import { getUserId, hasBrowserSession } from "../../../host/identity.js";
|
|
19
|
-
import { conversationTitleText } from "
|
|
19
|
+
import { conversationTitleText } from "@ai-matrx/content-ir/surfaces";
|
|
20
20
|
function resolveCanonicalAgentIdForConversationsFetch(input, state) {
|
|
21
21
|
const versionFilter = input.versionFilter === void 0 ? null : input.versionFilter;
|
|
22
22
|
let mapKey;
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import { createSelector } from "@reduxjs/toolkit";
|
|
6
6
|
import { isAnswerKeptWarning } from "./answer-kept-warning.js";
|
|
7
7
|
import { blockMediaFileId } from "../utils/block-media-identity.js";
|
|
8
|
-
import { DECISION_ANSWERS_BLOCK_TYPE } from "
|
|
8
|
+
import { DECISION_ANSWERS_BLOCK_TYPE } from "@ai-matrx/content-ir/surfaces";
|
|
9
9
|
import { decisionAnswersText } from "@ai-matrx/agents/presentation/decision-answers";
|
|
10
10
|
import {
|
|
11
11
|
readEnvelope,
|
package/dist/agents/redux/execution-system/instance-context/sync-canvas-item-context.thunk.js
CHANGED
|
@@ -8,7 +8,7 @@ import { applyContextDeltaToContent } from "../instance-working-document/context
|
|
|
8
8
|
import { CANVAS_ITEM_UPDATED_EVENT } from "../../../utils/canvas-item-event.js";
|
|
9
9
|
import { invalidateCanvasItemCache } from "../../../../host/ui-slots.js";
|
|
10
10
|
import { canvasGetVersionHistory, canvasGetById } from "../../../../host/ui-slots.js";
|
|
11
|
-
import { isMaterializedArtifactId } from "
|
|
11
|
+
import { isMaterializedArtifactId } from "@ai-matrx/rich-content/utils/lifted/artifactId";
|
|
12
12
|
import { recordUnavailable } from "../../../../host/diagnostics.js";
|
|
13
13
|
function extractBody(content) {
|
|
14
14
|
const stored = content;
|
|
@@ -187,7 +187,7 @@ import { StreamProfiler } from "../../../../ui/stream-profiler.js";
|
|
|
187
187
|
import { makePartialKindStalenessGate } from "@ai-matrx/content-ir/wire";
|
|
188
188
|
import { prepareInboundRenderBlock } from "../utils/inbound-render-block.js";
|
|
189
189
|
import { progressDataRenderBlock } from "../utils/progress-data-block.js";
|
|
190
|
-
import { DECISION_ANSWERS_BLOCK_TYPE } from "
|
|
190
|
+
import { DECISION_ANSWERS_BLOCK_TYPE } from "@ai-matrx/content-ir/surfaces";
|
|
191
191
|
import { recordContextReceipt } from "../context-rules/receipt-check.js";
|
|
192
192
|
import { assembleMessageParts } from "../utils/assemble-cx-content-blocks.js";
|
|
193
193
|
import { materializeMessageArtifacts } from "../../../../host/ui-slots.js";
|
|
@@ -14,6 +14,12 @@ import {
|
|
|
14
14
|
supportsLocalAgentExecution
|
|
15
15
|
} from "../../../../host/server/local-engine.js";
|
|
16
16
|
import { selectOrganizationId } from "../../../../host/org.js";
|
|
17
|
+
import { getChatHost, isChatHostConfigured } from "../../../../host/configure.js";
|
|
18
|
+
import {
|
|
19
|
+
ConfidentialRoutingRefusedError,
|
|
20
|
+
decideRouting,
|
|
21
|
+
localityOfChannel
|
|
22
|
+
} from "../../../routing/confidential-routing.js";
|
|
17
23
|
const EC2_SANDBOX_SERVER_URL = typeof process !== "undefined" && process.env.NEXT_PUBLIC_EC2_SANDBOX_SERVER_URL || "";
|
|
18
24
|
function dedicatedEc2ServerForConversation(state, conversationId) {
|
|
19
25
|
if (selectActiveServer(state) !== "production") return null;
|
|
@@ -65,6 +71,17 @@ function resolveBaseUrlForConversation(state, conversationId) {
|
|
|
65
71
|
return resolved.endsWith("/") ? resolved.slice(0, -1) : resolved;
|
|
66
72
|
}
|
|
67
73
|
function resolveBackendForConversation(state, conversationId) {
|
|
74
|
+
const resolved = resolveBackendUnchecked(state, conversationId);
|
|
75
|
+
if (resolved && isChatHostConfigured()) {
|
|
76
|
+
const decision = decideRouting(
|
|
77
|
+
getChatHost().routing.policy(conversationId),
|
|
78
|
+
localityOfChannel(resolved.channel)
|
|
79
|
+
);
|
|
80
|
+
if (!decision.allowed) throw new ConfidentialRoutingRefusedError(conversationId, decision);
|
|
81
|
+
}
|
|
82
|
+
return resolved;
|
|
83
|
+
}
|
|
84
|
+
function resolveBackendUnchecked(state, conversationId) {
|
|
68
85
|
const entry = state.instanceUIState?.byConversationId?.[conversationId] ?? null;
|
|
69
86
|
const overrideUrl = entry?.serverOverrideUrl ?? null;
|
|
70
87
|
const headers = {
|
|
@@ -201,6 +201,13 @@ export interface UnprocessableErrorClassification {
|
|
|
201
201
|
}
|
|
202
202
|
/** Classify HTTP 422s by server code; message text is legacy fallback only. */
|
|
203
203
|
export declare function classifyUnprocessableError(errorCode: string | null, serverMessage: string): UnprocessableErrorClassification;
|
|
204
|
+
/**
|
|
205
|
+
* `X-Matrx-Client-Sent-At` (epoch ms of the frozen submission moment) and
|
|
206
|
+
* `X-Matrx-Client-Prep-Ms` (submission → fetch dispatch). `submitAt` is a
|
|
207
|
+
* `performance.now()` stamp, so the epoch time is derived from the monotonic
|
|
208
|
+
* elapsed time — immune to wall-clock steps between submit and dispatch.
|
|
209
|
+
*/
|
|
210
|
+
export declare function buildLatencyHeaders(submitAt: number, nowPerf?: number, nowEpoch?: number): Record<string, string>;
|
|
204
211
|
/**
|
|
205
212
|
* Retry only after the server explicitly rejected the POST before execution
|
|
206
213
|
* with `X-Matrx-Drain`. Once that proof exists, brief connection failures are
|
|
@@ -180,6 +180,13 @@ function waitForDrainRetry(ms, signal) {
|
|
|
180
180
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
181
181
|
});
|
|
182
182
|
}
|
|
183
|
+
function buildLatencyHeaders(submitAt, nowPerf = performance.now(), nowEpoch = Date.now()) {
|
|
184
|
+
const prepMs = Math.max(0, nowPerf - submitAt);
|
|
185
|
+
return {
|
|
186
|
+
"X-Matrx-Client-Sent-At": String(Math.round(nowEpoch - prepMs)),
|
|
187
|
+
"X-Matrx-Client-Prep-Ms": String(Math.round(prepMs))
|
|
188
|
+
};
|
|
189
|
+
}
|
|
183
190
|
async function fetchThroughDeploymentDrain(url, init, signal) {
|
|
184
191
|
const deadline = Date.now() + DEPLOYMENT_DRAIN_MAX_WAIT_MS;
|
|
185
192
|
let drainObserved = false;
|
|
@@ -299,6 +306,11 @@ async function runAiStreamOnce(args) {
|
|
|
299
306
|
);
|
|
300
307
|
}
|
|
301
308
|
}
|
|
309
|
+
if (kind !== "rejoin") {
|
|
310
|
+
Object.assign(fetchInit, {
|
|
311
|
+
headers: { ...headers, ...buildLatencyHeaders(submitAt) }
|
|
312
|
+
});
|
|
313
|
+
}
|
|
302
314
|
response = kind === "rejoin" ? await fetchRejoin(
|
|
303
315
|
url,
|
|
304
316
|
fetchInit,
|
|
@@ -586,6 +598,7 @@ export {
|
|
|
586
598
|
StreamCancelledError,
|
|
587
599
|
StreamPhaseError,
|
|
588
600
|
StreamRejoinUnavailableError,
|
|
601
|
+
buildLatencyHeaders,
|
|
589
602
|
classifyUnprocessableError,
|
|
590
603
|
fetchThroughDeploymentDrain,
|
|
591
604
|
parseApiErrorBody,
|
|
@@ -151,7 +151,8 @@ async function failWarnedOutputMissingKeys(getState, opts, result) {
|
|
|
151
151
|
}
|
|
152
152
|
const who = holderName ?? (warning.holderType === "workflow" ? "The chosen workflow" : "The chosen agent");
|
|
153
153
|
const keys = missing.join(", ");
|
|
154
|
-
const
|
|
154
|
+
const brokenJson = !(result.success && isRecord) && looksLikeBrokenJson(result.fullResponse);
|
|
155
|
+
const sentence = brokenJson ? `${who} ran, but its answer came back as broken JSON, so it couldn't be read and nothing was saved. Run it again.` : `${who} ran, but its answer is missing ${keys} this job needs, so nothing was saved. It was chosen although it does not declare those keys \u2014 pick one that does.`;
|
|
155
156
|
captureError({
|
|
156
157
|
source: "agent-json-result",
|
|
157
158
|
code: "mandate_output_unusable",
|
|
@@ -162,7 +163,7 @@ async function failWarnedOutputMissingKeys(getState, opts, result) {
|
|
|
162
163
|
...result.requestId ? { requestId: result.requestId } : {},
|
|
163
164
|
...result.conversationId ? { conversationId: result.conversationId } : {},
|
|
164
165
|
raw: {
|
|
165
|
-
defect: "warned-holder-answer-missing-required-keys",
|
|
166
|
+
defect: brokenJson ? "answer-is-broken-json" : "warned-holder-answer-missing-required-keys",
|
|
166
167
|
mandateKey: opts.mandateKey,
|
|
167
168
|
surfaceKey: opts.surfaceKey,
|
|
168
169
|
holderId,
|
|
@@ -179,6 +180,17 @@ async function failWarnedOutputMissingKeys(getState, opts, result) {
|
|
|
179
180
|
errorDetail: `mandate_output_unusable: missing ${keys}`
|
|
180
181
|
};
|
|
181
182
|
}
|
|
183
|
+
function looksLikeBrokenJson(text) {
|
|
184
|
+
if (!text) return false;
|
|
185
|
+
const t = text.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "");
|
|
186
|
+
if (!t.startsWith("{") && !t.startsWith("[")) return false;
|
|
187
|
+
try {
|
|
188
|
+
JSON.parse(t);
|
|
189
|
+
return false;
|
|
190
|
+
} catch {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
182
194
|
function missingRequiredKeys(record, required) {
|
|
183
195
|
const answers = typeof record.answers === "object" && record.answers !== null && !Array.isArray(record.answers) ? record.answers : null;
|
|
184
196
|
return required.filter((key) => !(key in record) && !(answers && key in answers));
|
|
@@ -9,7 +9,7 @@ import { readEnvelope } from "@ai-matrx/content-ir";
|
|
|
9
9
|
import {
|
|
10
10
|
DECISION_ANSWERS_BLOCK_TYPE,
|
|
11
11
|
DECISION_ANSWERS_KIND
|
|
12
|
-
} from "
|
|
12
|
+
} from "@ai-matrx/content-ir/surfaces";
|
|
13
13
|
function isReasoningEnd(e) {
|
|
14
14
|
return e.kind === "reasoning_end";
|
|
15
15
|
}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
fromCxAudioPart,
|
|
5
5
|
fromCxVideoPart
|
|
6
6
|
} from "@ai-matrx/media/files";
|
|
7
|
-
import { DECISION_ANSWERS_BLOCK_TYPE } from "
|
|
7
|
+
import { DECISION_ANSWERS_BLOCK_TYPE } from "@ai-matrx/content-ir/surfaces";
|
|
8
8
|
import { withPerformedScript } from "../../../speech-script/types.js";
|
|
9
9
|
import { seedPersistedEnvelopeCache } from "@ai-matrx/rich-content/kinds/registry/region-envelope-memo";
|
|
10
10
|
function normalizeContentBlocks(rawBlocks) {
|
|
@@ -3,7 +3,7 @@ import { hasField } from "@ai-matrx/agents/field-flags";
|
|
|
3
3
|
import { peekMandateCatalogueEntry } from "../../../../host/ui-slots.js";
|
|
4
4
|
import { fetchAgentOutputSchemas } from "../../../../mandates/output-contract.js";
|
|
5
5
|
import { SURFACE_WRITE_TOOL_NAME } from "../../../../surfaces/runtime/surface-writeback.js";
|
|
6
|
-
import { isJsonObject } from "
|
|
6
|
+
import { isJsonObject } from "@ai-matrx/rich-content/utils/json";
|
|
7
7
|
import { readAgentName } from "../../../identity/agent-identity.js";
|
|
8
8
|
function schemaName(schema) {
|
|
9
9
|
if (!isJsonObject(schema)) return null;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { parseDecisionOptionsFromBody } from "
|
|
2
|
-
import { QuotedKindLift } from "
|
|
3
|
-
import { canonicalizeCompletedLegacyQuizEnvelope } from "
|
|
4
|
-
import { envelopeMatchesParsedSource } from "
|
|
5
|
-
import { MarkdownEscapedKindJson } from "
|
|
6
|
-
import { KindImageAltUnwrap } from "
|
|
1
|
+
import { parseDecisionOptionsFromBody } from "@ai-matrx/rich-content/utils/decision-options";
|
|
2
|
+
import { QuotedKindLift } from "@ai-matrx/content-ir/surfaces";
|
|
3
|
+
import { canonicalizeCompletedLegacyQuizEnvelope } from "@ai-matrx/content-ir/surfaces";
|
|
4
|
+
import { envelopeMatchesParsedSource } from "@ai-matrx/content-ir/surfaces";
|
|
5
|
+
import { MarkdownEscapedKindJson } from "@ai-matrx/content-ir/surfaces";
|
|
6
|
+
import { KindImageAltUnwrap } from "@ai-matrx/content-ir/surfaces";
|
|
7
7
|
import { FENCE_META_KEY, splitFenceInfo } from "@ai-matrx/content-ir/source";
|
|
8
8
|
import {
|
|
9
9
|
hasUnclosedBacktickRun,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
kindGrammar,
|
|
17
17
|
kindObjectProseBreak,
|
|
18
18
|
bareRegionBreaksIntoProse
|
|
19
|
-
} from "
|
|
19
|
+
} from "@ai-matrx/content-ir/surfaces";
|
|
20
20
|
import {
|
|
21
21
|
findBalancedXmlClose,
|
|
22
22
|
initialXmlBalance
|
|
@@ -68,7 +68,7 @@ import {
|
|
|
68
68
|
import {
|
|
69
69
|
normalizeRecoveredContainerPiece,
|
|
70
70
|
splitAroundEmbeddedKindJson
|
|
71
|
-
} from "
|
|
71
|
+
} from "@ai-matrx/content-ir/surfaces";
|
|
72
72
|
import { captureError } from "../../../../host/diagnostics.js";
|
|
73
73
|
const isSpecialCodeLanguage = (language) => SPECIAL_CODE_LANGUAGES.includes(language);
|
|
74
74
|
const envelopeForCompletedXmlRegion = (tag, regionText) => hostSplitterEnvelopes()?.xmlRegion(tag, regionText) ?? null;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE CONFIDENTIAL-ROUTING RULE (CHAT-UI-PACKAGE-DESIGN §12 risk 4 — the highest-severity item).
|
|
3
|
+
*
|
|
4
|
+
* A conversation pinned `local-only` (matrx-local's "Confidential") REFUSES every target that is
|
|
5
|
+
* not the person's own machine. It does not downgrade, it does not warn-and-send, and it never
|
|
6
|
+
* quietly picks a different target: the send fails with a named reason and a remedy, before a byte
|
|
7
|
+
* leaves the machine. Re-deriving this per host is how private text reaches a cloud provider.
|
|
8
|
+
*
|
|
9
|
+
* Ported from the frozen kernel (`src/compat/config.ts` `decideRouting`) into the real chat
|
|
10
|
+
* (lanes/agents-chat-proposal.md W0(a)). Enforced at the one place every send path resolves its
|
|
11
|
+
* target: `resolveBackendForConversation` (`agents/redux/execution-system/thunks/resolve-base-url.ts`).
|
|
12
|
+
* The policy comes from the host's `routing` port (`host/contract.ts`; default: `"any"`).
|
|
13
|
+
*
|
|
14
|
+
* PURE on purpose: no imports, no React, no Redux, no `window`. The decision is headless so it can
|
|
15
|
+
* move (e.g. into `@ai-matrx/agents`) without a rewrite.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Where a conversation's text is allowed to go.
|
|
19
|
+
* - `"any"` — the platform default: any target the host offers.
|
|
20
|
+
* - `"local-only"` — CONFIDENTIAL: only the person's own machine (the Matrx Local engine).
|
|
21
|
+
*/
|
|
22
|
+
export type ChatRoutingPolicy = "any" | "local-only";
|
|
23
|
+
/** Where a resolved target sends text. */
|
|
24
|
+
export type ChatTargetLocality = "local" | "cloud";
|
|
25
|
+
/** The refusal a confidential conversation produces instead of a silent fallback. */
|
|
26
|
+
export interface ChatRoutingRefusal {
|
|
27
|
+
readonly allowed: false;
|
|
28
|
+
readonly code: "confidential_thread_cloud_target_refused";
|
|
29
|
+
readonly userMessage: string;
|
|
30
|
+
readonly remedy: string;
|
|
31
|
+
}
|
|
32
|
+
export type ChatRoutingDecision = {
|
|
33
|
+
readonly allowed: true;
|
|
34
|
+
} | ChatRoutingRefusal;
|
|
35
|
+
export declare const CONFIDENTIAL_REFUSAL_MESSAGE = "This conversation is marked confidential, so it cannot be sent to a cloud AI provider.";
|
|
36
|
+
export declare const CONFIDENTIAL_REFUSAL_REMEDY = "Run it on Matrx Local on this computer, or start a new conversation that is not marked confidential.";
|
|
37
|
+
/** The one decision. Anything that is not `"local"` is treated as cloud by its callers. */
|
|
38
|
+
export declare function decideRouting(policy: ChatRoutingPolicy, target: ChatTargetLocality): ChatRoutingDecision;
|
|
39
|
+
/**
|
|
40
|
+
* The locality of a resolved backend channel. Only `"local-runtime"` — the Matrx Local engine on
|
|
41
|
+
* this computer — is local. Every other channel (the global server, a sandbox override, a dedicated
|
|
42
|
+
* EC2 server, and any channel added later) is cloud: an unknown channel can never pass the rule.
|
|
43
|
+
*/
|
|
44
|
+
export declare function localityOfChannel(channel: string): ChatTargetLocality;
|
|
45
|
+
/** Thrown by the target resolver when a confidential conversation would reach the cloud. */
|
|
46
|
+
export declare class ConfidentialRoutingRefusedError extends Error {
|
|
47
|
+
readonly code: "confidential_thread_cloud_target_refused";
|
|
48
|
+
readonly remedy: string;
|
|
49
|
+
readonly conversationId: string;
|
|
50
|
+
constructor(conversationId: string, refusal: ChatRoutingRefusal);
|
|
51
|
+
}
|
|
52
|
+
export declare function isConfidentialRoutingRefusedError(error: unknown): error is ConfidentialRoutingRefusedError;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const CONFIDENTIAL_REFUSAL_MESSAGE = "This conversation is marked confidential, so it cannot be sent to a cloud AI provider.";
|
|
2
|
+
const CONFIDENTIAL_REFUSAL_REMEDY = "Run it on Matrx Local on this computer, or start a new conversation that is not marked confidential.";
|
|
3
|
+
function decideRouting(policy, target) {
|
|
4
|
+
if (policy === "local-only" && target !== "local") {
|
|
5
|
+
return {
|
|
6
|
+
allowed: false,
|
|
7
|
+
code: "confidential_thread_cloud_target_refused",
|
|
8
|
+
userMessage: CONFIDENTIAL_REFUSAL_MESSAGE,
|
|
9
|
+
remedy: CONFIDENTIAL_REFUSAL_REMEDY
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
return { allowed: true };
|
|
13
|
+
}
|
|
14
|
+
function localityOfChannel(channel) {
|
|
15
|
+
return channel === "local-runtime" ? "local" : "cloud";
|
|
16
|
+
}
|
|
17
|
+
class ConfidentialRoutingRefusedError extends Error {
|
|
18
|
+
code = "confidential_thread_cloud_target_refused";
|
|
19
|
+
remedy;
|
|
20
|
+
conversationId;
|
|
21
|
+
constructor(conversationId, refusal) {
|
|
22
|
+
super(refusal.userMessage);
|
|
23
|
+
this.name = "ConfidentialRoutingRefusedError";
|
|
24
|
+
this.remedy = refusal.remedy;
|
|
25
|
+
this.conversationId = conversationId;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isConfidentialRoutingRefusedError(error) {
|
|
29
|
+
return error instanceof ConfidentialRoutingRefusedError;
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
CONFIDENTIAL_REFUSAL_MESSAGE,
|
|
33
|
+
CONFIDENTIAL_REFUSAL_REMEDY,
|
|
34
|
+
ConfidentialRoutingRefusedError,
|
|
35
|
+
decideRouting,
|
|
36
|
+
isConfidentialRoutingRefusedError,
|
|
37
|
+
localityOfChannel
|
|
38
|
+
};
|