@ai-matrx/chat 0.3.11 → 0.3.19
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 +83 -0
- package/dist/agent-copy/export.d.ts +10 -2
- package/dist/agent-copy/export.js +3 -2
- package/dist/agents/components/agent-widgets/chat-assistant/CompactAssistantInput.js +1 -1
- package/dist/agents/components/debug/SandboxFileViewer.js +1 -3
- package/dist/agents/components/inputs/AgentVariablesInline.js +1 -1
- package/dist/agents/components/inputs/smart-input/AgentTextarea.js +1 -1
- package/dist/agents/components/inputs/smart-input/InputActionButtons.js +1 -1
- package/dist/agents/components/inputs/smart-input/composer/ComposerAgentPeek.js +6 -6
- package/dist/agents/components/messages-display/TranscriptIntegrityCopyButton.js +4 -4
- package/dist/agents/components/messages-display/user/UserActionBar.js +3 -18
- package/dist/agents/components/run/AgentRunHeader.js +1 -2
- package/dist/agents/components/shared/AgentConversationColumn.js +1 -1
- package/dist/agents/components/shared/AgentHeader.js +1 -2
- package/dist/agents/components/shared/AgentHeaderMobile.js +1 -2
- package/dist/agents/components/working-document/DocumentLinkPicker.d.ts +1 -1
- package/dist/agents/components/working-document/WorkingDocumentPanel.js +1 -1
- package/dist/agents/components/working-document/documents-workspace/DocumentsListRail.js +2 -2
- package/dist/agents/components/working-document/documents-workspace/DocumentsWorkspace.js +2 -2
- package/dist/agents/hooks/useInstanceInputUndoRedo.d.ts +1 -1
- package/dist/agents/hooks/useInstanceInputUndoRedo.js +1 -1
- package/dist/agents/hooks/useWorkingDocument.js +7 -6
- package/dist/agents/model-registry/model-classes.d.ts +1 -43
- package/dist/agents/model-registry/model-classes.js +1 -40
- package/dist/agents/model-registry/parse.d.ts +1 -88
- package/dist/agents/model-registry/parse.js +1 -246
- package/dist/agents/prompt-preview/PromptPreviewContent.js +1 -3
- package/dist/agents/redux/agent-definition/selectors.d.ts +8 -8
- package/dist/agents/redux/execution-system/active-requests/active-requests.selectors.d.ts +14 -0
- package/dist/agents/redux/execution-system/active-requests/active-requests.selectors.js +30 -0
- package/dist/agents/redux/execution-system/client-capabilities/desktop-native.provider.js +10 -1
- package/dist/agents/redux/execution-system/instance-working-document/cx-working-document.service.d.ts +18 -16
- package/dist/agents/redux/execution-system/instance-working-document/cx-working-document.service.js +101 -52
- package/dist/agents/redux/execution-system/instance-working-document/instance-working-document.slice.d.ts +2 -2
- package/dist/agents/redux/execution-system/instance-working-document/instance-working-document.thunks.d.ts +1 -1
- package/dist/agents/redux/execution-system/instance-working-document/scratchpad.thunks.d.ts +1 -1
- package/dist/agents/redux/execution-system/message-crud/refetch-single-message.thunk.js +5 -0
- package/dist/agents/redux/execution-system/thunks/process-stream.js +2 -2
- package/dist/agents/redux/execution-system/utils/stream-block-accumulator.d.ts +14 -0
- package/dist/agents/redux/execution-system/utils/stream-block-accumulator.js +28 -0
- package/dist/agents/utils/platform-keys.d.ts +15 -0
- package/dist/agents/utils/platform-keys.js +69 -0
- package/dist/context/sources/scopes.d.ts +1 -1
- package/dist/cx-chat/components/user-input/ConversationInput.js +1 -1
- package/dist/cx-conversation/ConversationInput.js +1 -1
- package/dist/host/db-types.d.ts +23242 -23071
- package/dist/host/ui-slots.d.ts +50 -64
- package/dist/host/ui-slots.js +12 -52
- package/dist/public-chat/components/GuidedVariableInputs.js +1 -1
- package/dist/public-chat/components/PublicVariableInputs.js +1 -1
- package/dist/react.cjs +11 -23
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +11 -23
- package/dist/react.js.map +1 -1
- package/dist/surfaces/manifests/_conversation-document.manifest.js +1 -1
- package/dist/tool-call-visualization/registry/registry.js +13 -0
- package/dist/ui/composer/useTouchOnlyDevice.js +1 -1
- package/dist/ui/skills-types.d.ts +1 -275
- package/dist/ui/skills-types.js +1 -0
- package/dist/voice-agent/components/VoiceDebugPanel.js +1 -3
- package/package.json +60 -34
- package/dist/agents/components/run/run-sidebar/AgentRunsSidebar.d.ts +0 -15
- package/dist/agents/components/run/run-sidebar/AgentRunsSidebar.js +0 -201
- package/dist/agents/components/run-controls/AgentExecutionTestModal.d.ts +0 -36
- package/dist/agents/components/run-controls/AgentExecutionTestModal.js +0 -440
- package/dist/agents/components/run-controls/AgentLauncherSidebarTester.d.ts +0 -6
- package/dist/agents/components/run-controls/AgentLauncherSidebarTester.js +0 -127
- package/dist/agents/components/run-controls/AgentWidgetInvokerTester.d.ts +0 -6
- package/dist/agents/components/run-controls/AgentWidgetInvokerTester.js +0 -84
- package/dist/agents/components/run-controls/CreatorRunPanel.d.ts +0 -22
- package/dist/agents/components/run-controls/CreatorRunPanel.js +0 -108
- package/dist/agents/components/run-controls/CreatorRunTabContent.d.ts +0 -30
- package/dist/agents/components/run-controls/CreatorRunTabContent.js +0 -319
- package/dist/agents/components/run-controls/PayloadTab.d.ts +0 -5
- package/dist/agents/components/run-controls/PayloadTab.js +0 -388
- package/dist/agents/components/run-controls/TesterSettingsPanel.d.ts +0 -71
- package/dist/agents/components/run-controls/TesterSettingsPanel.js +0 -470
- package/dist/agents/components/shared/AgentOptionsMenu.d.ts +0 -8
- package/dist/agents/components/shared/AgentOptionsMenu.js +0 -776
- package/dist/agents/components/shared/AgentPeekDuplicateButton.d.ts +0 -8
- package/dist/agents/components/shared/AgentPeekDuplicateButton.js +0 -66
- package/dist/agents/components/shared/AgentSaveStatus.d.ts +0 -7
- package/dist/agents/components/shared/AgentSaveStatus.js +0 -128
- package/dist/agents/components/shared/AgentSaveTapButton.d.ts +0 -18
- package/dist/agents/components/shared/AgentSaveTapButton.js +0 -105
- package/dist/agents/components/shared/useAgentSaveAction.d.ts +0 -33
- package/dist/agents/components/shared/useAgentSaveAction.js +0 -179
- package/dist/agents/components/shell/AgentsListHeader.d.ts +0 -1
- package/dist/agents/components/shell/AgentsListHeader.js +0 -69
- package/dist/agents/components/undo-history/AgentEditHistory.d.ts +0 -9
- package/dist/agents/components/undo-history/AgentEditHistory.js +0 -244
- package/dist/agents/components/unused/AgentSharedHeader.d.ts +0 -3
- package/dist/agents/components/unused/AgentSharedHeader.js +0 -134
- package/dist/agents/components/widgets/AgentWidgetsPage.d.ts +0 -11
- package/dist/agents/components/widgets/AgentWidgetsPage.js +0 -571
- package/dist/agents/components/widgets/WidgetVariableInputs.d.ts +0 -8
- package/dist/agents/components/widgets/WidgetVariableInputs.js +0 -80
- package/dist/agents/components/widgets/build-widget-launch.d.ts +0 -70
- package/dist/agents/components/widgets/build-widget-launch.js +0 -90
- package/dist/agents/hooks/useAgentAutoSave.d.ts +0 -1
- package/dist/agents/hooks/useAgentAutoSave.js +0 -127
- package/dist/agents/hooks/useAgentBuilderWriteHandlers.d.ts +0 -9
- package/dist/agents/hooks/useAgentBuilderWriteHandlers.js +0 -102
- package/dist/agents/hooks/useAgentDuplicateFlow.d.ts +0 -25
- package/dist/agents/hooks/useAgentDuplicateFlow.js +0 -133
- package/dist/agents/hooks/useAgentUndoRedo.d.ts +0 -31
- package/dist/agents/hooks/useAgentUndoRedo.js +0 -134
- package/dist/agents/hooks/useAgentUsages.d.ts +0 -17
- package/dist/agents/hooks/useAgentUsages.js +0 -36
- package/dist/agents/hooks/useDriftAlerts.d.ts +0 -11
- package/dist/agents/hooks/useDriftAlerts.js +0 -36
- package/dist/agents/hooks/useDriftReport.d.ts +0 -20
- package/dist/agents/hooks/useDriftReport.js +0 -34
- package/dist/agents/lifecycle/useAgentLifecycleActions.d.ts +0 -17
- package/dist/agents/lifecycle/useAgentLifecycleActions.js +0 -63
- package/dist/agents/message-flags/useMessageFlags.d.ts +0 -8
- package/dist/agents/message-flags/useMessageFlags.js +0 -68
- package/dist/agents/services/agent-definition-snapshot.service.d.ts +0 -15
- package/dist/agents/services/agent-definition-snapshot.service.js +0 -20
- package/dist/agents/surface-catalog-profile.d.ts +0 -96
- package/dist/agents/surface-catalog-profile.js +0 -79
- package/dist/cx-chat/hooks/useAgentBootstrap.d.ts +0 -1
- package/dist/cx-chat/hooks/useAgentBootstrap.js +0 -110
- package/dist/host/builder-door.d.ts +0 -61
- package/dist/host/builder-door.js +0 -25
- package/dist/next/lazy/CreatorRunPanel.d.ts +0 -1
- package/dist/next/lazy/CreatorRunPanel.js +0 -11
- package/dist/ui/composer/composerSubmit.d.ts +0 -50
- package/dist/ui/composer/composerSubmit.js +0 -32
package/dist/agents/redux/execution-system/instance-working-document/cx-working-document.service.js
CHANGED
|
@@ -10,27 +10,67 @@ function rowToCxWorkingDocument(row) {
|
|
|
10
10
|
return {
|
|
11
11
|
id: row.id,
|
|
12
12
|
conversationId: row.metadata?.origin_conversation_id ?? null,
|
|
13
|
-
kind: row.
|
|
13
|
+
kind: kindForTypeId(row.document_type_id),
|
|
14
14
|
title: row.title,
|
|
15
|
-
content: row.
|
|
15
|
+
content: row.body,
|
|
16
16
|
version: row.version,
|
|
17
17
|
createdAt: row.created_at,
|
|
18
18
|
updatedAt: row.updated_at
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
const
|
|
21
|
+
const WORKING_DOCUMENT_ENTITY = "document";
|
|
22
|
+
const TYPE_SLUG = {
|
|
23
|
+
working: "working_document",
|
|
24
|
+
scratch: "scratch"
|
|
25
|
+
};
|
|
26
|
+
const WD_COLUMNS = "id, document_type_id, title, body, version, metadata, created_at, updated_at";
|
|
27
|
+
let typeIdsPromise = null;
|
|
28
|
+
let typeIdsResolved = null;
|
|
29
|
+
function workingDocumentTypeIds() {
|
|
30
|
+
if (!typeIdsPromise) {
|
|
31
|
+
typeIdsPromise = (async () => {
|
|
32
|
+
const { data, error } = await supabase.schema("platform").from("categories").select("id, slug").eq("dimension", "document_type").in("slug", [TYPE_SLUG.working, TYPE_SLUG.scratch]).is("deleted_at", null);
|
|
33
|
+
if (error) {
|
|
34
|
+
typeIdsPromise = null;
|
|
35
|
+
throw new Error(
|
|
36
|
+
`[working-document] document types read failed: ${error.message}`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
const bySlug = new Map(
|
|
40
|
+
(data ?? []).map((r) => [r.slug, r.id])
|
|
41
|
+
);
|
|
42
|
+
const working = bySlug.get(TYPE_SLUG.working);
|
|
43
|
+
const scratch = bySlug.get(TYPE_SLUG.scratch);
|
|
44
|
+
if (!working || !scratch) {
|
|
45
|
+
typeIdsPromise = null;
|
|
46
|
+
throw new Error(
|
|
47
|
+
"[working-document] the content store has no Working document / Scratch type."
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
typeIdsResolved = { working, scratch };
|
|
51
|
+
return typeIdsResolved;
|
|
52
|
+
})();
|
|
53
|
+
}
|
|
54
|
+
return typeIdsPromise;
|
|
55
|
+
}
|
|
56
|
+
function kindForTypeId(typeId) {
|
|
57
|
+
return typeIdsResolved?.scratch === typeId ? "scratch" : "working";
|
|
58
|
+
}
|
|
59
|
+
const WD = () => supabase.schema("content").from("document");
|
|
22
60
|
function getWorkingDocumentAccess(documentId) {
|
|
23
|
-
return resolveResourceAccess(supabase,
|
|
61
|
+
return resolveResourceAccess(supabase, WORKING_DOCUMENT_ENTITY, documentId);
|
|
24
62
|
}
|
|
25
63
|
async function getCxWorkingDocumentById(documentId) {
|
|
26
|
-
|
|
64
|
+
await workingDocumentTypeIds();
|
|
65
|
+
const { data, error } = await WD().select(WD_COLUMNS).eq("id", documentId).is("deleted_at", null).maybeSingle();
|
|
27
66
|
if (error) {
|
|
28
67
|
throw new Error(`[working-document] get by id failed: ${error.message}`);
|
|
29
68
|
}
|
|
30
69
|
return data ? rowToCxWorkingDocument(data) : null;
|
|
31
70
|
}
|
|
32
71
|
async function updateCxWorkingDocumentTitle(id, title) {
|
|
33
|
-
|
|
72
|
+
await workingDocumentTypeIds();
|
|
73
|
+
const { data, error } = await WD().update({ title }).eq("id", id).select(WD_COLUMNS).single();
|
|
34
74
|
if (error || !data) {
|
|
35
75
|
throw new Error(
|
|
36
76
|
`[working-document] title update failed: ${error?.message ?? "no row"}`
|
|
@@ -39,7 +79,8 @@ async function updateCxWorkingDocumentTitle(id, title) {
|
|
|
39
79
|
return rowToCxWorkingDocument(data);
|
|
40
80
|
}
|
|
41
81
|
async function updateCxWorkingDocumentContent(id, content) {
|
|
42
|
-
|
|
82
|
+
await workingDocumentTypeIds();
|
|
83
|
+
const { data, error } = await WD().update({ body: content }).eq("id", id).select(WD_COLUMNS).single();
|
|
43
84
|
if (error || !data) {
|
|
44
85
|
throw new Error(
|
|
45
86
|
`[working-document] content update failed: ${error?.message ?? "no row"}`
|
|
@@ -48,17 +89,18 @@ async function updateCxWorkingDocumentContent(id, content) {
|
|
|
48
89
|
return rowToCxWorkingDocument(data);
|
|
49
90
|
}
|
|
50
91
|
async function commitWorkingDocumentContent(id, content, baseVersion) {
|
|
92
|
+
await workingDocumentTypeIds();
|
|
51
93
|
const result = await guardedUpdate({
|
|
52
94
|
expectedVersion: baseVersion,
|
|
53
95
|
applyUpdate: async ({ expectedVersion, nextVersion }) => {
|
|
54
|
-
const { data, error } = await WD().update({ content, version: nextVersion }).eq("id", id).eq("version", expectedVersion).select(
|
|
96
|
+
const { data, error } = await WD().update({ body: content, version: nextVersion }).eq("id", id).eq("version", expectedVersion).select(WD_COLUMNS).maybeSingle();
|
|
55
97
|
if (error) {
|
|
56
98
|
throw new Error(`[working-document] commit failed: ${error.message}`);
|
|
57
99
|
}
|
|
58
100
|
return { data, error: null };
|
|
59
101
|
},
|
|
60
102
|
fetchCurrent: async () => {
|
|
61
|
-
const { data, error } = await WD().select(
|
|
103
|
+
const { data, error } = await WD().select(WD_COLUMNS).eq("id", id).is("deleted_at", null).maybeSingle();
|
|
62
104
|
if (error) {
|
|
63
105
|
throw new Error(
|
|
64
106
|
`[working-document] get by id failed: ${error.message}`
|
|
@@ -87,11 +129,7 @@ async function currentUserId() {
|
|
|
87
129
|
} = await getClaimsUser(supabase);
|
|
88
130
|
return user?.id ?? null;
|
|
89
131
|
}
|
|
90
|
-
const WD_GRANT_SPELLINGS = [
|
|
91
|
-
"working_document",
|
|
92
|
-
"working_documents",
|
|
93
|
-
"workbench.working_documents"
|
|
94
|
-
];
|
|
132
|
+
const WD_GRANT_SPELLINGS = [WORKING_DOCUMENT_ENTITY, "content.document"];
|
|
95
133
|
async function listGrantedDocumentIds(uid) {
|
|
96
134
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
97
135
|
const { data, error } = await supabase.schema("iam").from("permissions").select("resource_id, status, expires_at").in("resource_type", WD_GRANT_SPELLINGS).eq("granted_to_user_id", uid).or("status.is.null,status.neq.rejected").or(`expires_at.is.null,expires_at.gt.${nowIso}`);
|
|
@@ -105,7 +143,8 @@ async function listGrantedDocumentIds(uid) {
|
|
|
105
143
|
async function listUserDocuments(kind, limit = 50, scope = "mine") {
|
|
106
144
|
const uid = await currentUserId();
|
|
107
145
|
if (!uid) return [];
|
|
108
|
-
|
|
146
|
+
const typeIds = await workingDocumentTypeIds();
|
|
147
|
+
let query = WD().select(WD_COLUMNS).eq("document_type_id", typeIds[kind]).is("deleted_at", null).order("updated_at", { ascending: false }).limit(limit);
|
|
109
148
|
if (scope === "mine") {
|
|
110
149
|
query = query.eq("created_by", uid);
|
|
111
150
|
} else {
|
|
@@ -122,7 +161,8 @@ async function listUserDocuments(kind, limit = 50, scope = "mine") {
|
|
|
122
161
|
async function listRecentUserDocuments(limit = 100) {
|
|
123
162
|
const uid = await currentUserId();
|
|
124
163
|
if (!uid) return [];
|
|
125
|
-
const
|
|
164
|
+
const typeIds = await workingDocumentTypeIds();
|
|
165
|
+
const { data, error } = await WD().select("id, metadata, document_type_id, title, preview, updated_at").in("document_type_id", [typeIds.working, typeIds.scratch]).eq("created_by", uid).is("deleted_at", null).order("updated_at", { ascending: false }).limit(limit);
|
|
126
166
|
if (error) {
|
|
127
167
|
throw new Error(`[working-document] list recent failed: ${error.message}`);
|
|
128
168
|
}
|
|
@@ -131,9 +171,9 @@ async function listRecentUserDocuments(limit = 100) {
|
|
|
131
171
|
// Origin lives in metadata.origin_conversation_id (the legacy
|
|
132
172
|
// conversation_id column was dropped in STEP 3).
|
|
133
173
|
conversationId: row.metadata?.origin_conversation_id ?? null,
|
|
134
|
-
kind: row.
|
|
174
|
+
kind: kindForTypeId(row.document_type_id),
|
|
135
175
|
title: row.title,
|
|
136
|
-
preview: (row.
|
|
176
|
+
preview: (row.preview ?? "").trim().slice(0, 200),
|
|
137
177
|
updatedAt: row.updated_at
|
|
138
178
|
}));
|
|
139
179
|
}
|
|
@@ -148,19 +188,26 @@ function materializeWorkingDocument(args) {
|
|
|
148
188
|
return promise;
|
|
149
189
|
}
|
|
150
190
|
async function materializeWorkingDocumentImpl(args) {
|
|
191
|
+
const typeIds = await workingDocumentTypeIds();
|
|
151
192
|
const { data, error } = await WD().upsert(
|
|
152
193
|
{
|
|
153
194
|
id: args.id,
|
|
154
195
|
organization_id: args.organizationId,
|
|
155
|
-
|
|
196
|
+
document_type_id: typeIds[args.kind],
|
|
197
|
+
format: "markdown",
|
|
198
|
+
visibility: "personal",
|
|
156
199
|
title: args.title,
|
|
157
|
-
|
|
200
|
+
body: args.content,
|
|
158
201
|
metadata: {
|
|
159
202
|
origin_conversation_id: args.conversationId
|
|
160
203
|
}
|
|
204
|
+
// content_hash and data_class are derived by the database (the derive
|
|
205
|
+
// trigger and the per-type class floor); the generated Insert type
|
|
206
|
+
// lists them as required, so the row is passed as the canonical
|
|
207
|
+
// content-store writers pass it (features/rich-document createDocument).
|
|
161
208
|
},
|
|
162
209
|
{ onConflict: "id" }
|
|
163
|
-
).select(
|
|
210
|
+
).select(WD_COLUMNS).single();
|
|
164
211
|
if (error || !data) {
|
|
165
212
|
throw new Error(
|
|
166
213
|
`[working-document] materialize failed: ${error?.message ?? "no row"}`
|
|
@@ -179,7 +226,7 @@ function edgeMetadata(kind, enabled) {
|
|
|
179
226
|
}
|
|
180
227
|
async function linkDocumentToConversation(args) {
|
|
181
228
|
const res = await associationsService.add({
|
|
182
|
-
sourceType:
|
|
229
|
+
sourceType: WORKING_DOCUMENT_ENTITY,
|
|
183
230
|
sourceId: args.documentId,
|
|
184
231
|
targetType: "conversation",
|
|
185
232
|
targetId: args.conversationId,
|
|
@@ -194,7 +241,7 @@ async function linkDocumentToConversation(args) {
|
|
|
194
241
|
}
|
|
195
242
|
async function unlinkDocumentFromConversation(documentId, conversationId) {
|
|
196
243
|
const res = await associationsService.remove({
|
|
197
|
-
sourceType:
|
|
244
|
+
sourceType: WORKING_DOCUMENT_ENTITY,
|
|
198
245
|
sourceId: documentId,
|
|
199
246
|
targetType: "conversation",
|
|
200
247
|
targetId: conversationId
|
|
@@ -223,7 +270,7 @@ async function listConversationDocuments(conversationId) {
|
|
|
223
270
|
`[working-document] list links failed: ${res.error.message ?? res.error.code}`
|
|
224
271
|
);
|
|
225
272
|
}
|
|
226
|
-
return res.data.edges.filter((e) => e.sourceType ===
|
|
273
|
+
return res.data.edges.filter((e) => e.sourceType === WORKING_DOCUMENT_ENTITY).map((e) => {
|
|
227
274
|
const meta = e.metadata ?? {};
|
|
228
275
|
return {
|
|
229
276
|
documentId: e.sourceId,
|
|
@@ -234,7 +281,7 @@ async function listConversationDocuments(conversationId) {
|
|
|
234
281
|
}
|
|
235
282
|
async function listDocumentConversations(documentId) {
|
|
236
283
|
const res = await associationsService.listForSources(
|
|
237
|
-
|
|
284
|
+
WORKING_DOCUMENT_ENTITY,
|
|
238
285
|
[documentId],
|
|
239
286
|
"conversation"
|
|
240
287
|
);
|
|
@@ -245,53 +292,54 @@ async function listDocumentConversations(documentId) {
|
|
|
245
292
|
}
|
|
246
293
|
return res.data.edges.map((e) => e.targetId);
|
|
247
294
|
}
|
|
248
|
-
const WORKING_DOCUMENT_TOKEN = "working_document";
|
|
249
295
|
async function listWorkingDocumentVersions(documentId, limit = 50) {
|
|
250
|
-
const { data, error } = await supabase.rpc("version_list", {
|
|
251
|
-
p_token: WORKING_DOCUMENT_TOKEN,
|
|
252
|
-
p_id: documentId,
|
|
253
|
-
p_limit: limit
|
|
254
|
-
});
|
|
296
|
+
const { data, error } = await supabase.schema("content").rpc("version_list", { p_document_id: documentId, p_limit: limit });
|
|
255
297
|
if (error) {
|
|
256
298
|
throw new Error(`[working-document] version_list failed: ${error.message}`);
|
|
257
299
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
300
|
+
const rows = data ?? [];
|
|
301
|
+
const newest = rows.reduce((m, r) => Math.max(m, r.content_version), 0);
|
|
302
|
+
return rows.map((r) => ({
|
|
303
|
+
version: r.content_version,
|
|
304
|
+
operation: r.change_kind,
|
|
261
305
|
actorId: r.actor_id ?? null,
|
|
262
|
-
occurredAt: r.
|
|
263
|
-
isCurrent: r.
|
|
306
|
+
occurredAt: r.created_at,
|
|
307
|
+
isCurrent: r.content_version === newest
|
|
264
308
|
}));
|
|
265
309
|
}
|
|
266
310
|
async function getWorkingDocumentVersionContent(documentId, version) {
|
|
267
|
-
const { data, error } = await supabase.rpc("
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
p_version: version
|
|
311
|
+
const { data, error } = await supabase.schema("content").rpc("version_get", {
|
|
312
|
+
p_document_id: documentId,
|
|
313
|
+
p_content_version: version
|
|
271
314
|
});
|
|
272
315
|
if (error) {
|
|
273
|
-
throw new Error(
|
|
274
|
-
`[working-document] version_snapshot failed: ${error.message}`
|
|
275
|
-
);
|
|
316
|
+
throw new Error(`[working-document] version_get failed: ${error.message}`);
|
|
276
317
|
}
|
|
277
|
-
const
|
|
278
|
-
return typeof
|
|
318
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
319
|
+
return typeof row?.body === "string" ? row.body : null;
|
|
279
320
|
}
|
|
280
321
|
async function restoreWorkingDocumentVersion(documentId, version) {
|
|
281
|
-
const { data, error } = await
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
322
|
+
const { data: current, error: readError } = await WD().select("version").eq("id", documentId).maybeSingle();
|
|
323
|
+
if (readError || !current) {
|
|
324
|
+
throw new Error(
|
|
325
|
+
`[working-document] restore read failed: ${readError?.message ?? "no row"}`
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
const { data, error } = await supabase.schema("content").rpc("version_restore", {
|
|
329
|
+
p_document_id: documentId,
|
|
330
|
+
p_content_version: version,
|
|
331
|
+
p_expected_version: current.version
|
|
285
332
|
});
|
|
286
333
|
if (error) {
|
|
287
334
|
throw new Error(
|
|
288
335
|
`[working-document] version_restore failed: ${error.message}`
|
|
289
336
|
);
|
|
290
337
|
}
|
|
291
|
-
|
|
338
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
339
|
+
return row?.content_version ?? version;
|
|
292
340
|
}
|
|
293
341
|
export {
|
|
294
|
-
|
|
342
|
+
WORKING_DOCUMENT_ENTITY,
|
|
295
343
|
commitWorkingDocumentContent,
|
|
296
344
|
getCxWorkingDocumentById,
|
|
297
345
|
getWorkingDocumentAccess,
|
|
@@ -309,5 +357,6 @@ export {
|
|
|
309
357
|
softDeleteWorkingDocument,
|
|
310
358
|
unlinkDocumentFromConversation,
|
|
311
359
|
updateCxWorkingDocumentContent,
|
|
312
|
-
updateCxWorkingDocumentTitle
|
|
360
|
+
updateCxWorkingDocumentTitle,
|
|
361
|
+
workingDocumentTypeIds
|
|
313
362
|
};
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* - `content` — canonical document text shared by every mount.
|
|
20
20
|
* - `binding` — durable source. `{ kind: "none" }` = ephemeral;
|
|
21
21
|
* `{ kind: "cx_working_document", id }` = a row in
|
|
22
|
-
* `
|
|
22
|
+
* `content.document` (the chat default); `{ kind: "note" }`
|
|
23
23
|
* = a `workbench.notes` row (working kind only); `studio_document`
|
|
24
24
|
* = Scribe's source (shared context-value builder).
|
|
25
25
|
* - `saving` — true while a bound-source persist is in flight.
|
|
@@ -56,7 +56,7 @@ export declare function workingDocKey(conversationId: string, kind?: WorkingDocu
|
|
|
56
56
|
* Durable source the document is bound to.
|
|
57
57
|
* - "none" — ephemeral (Redux only).
|
|
58
58
|
* - "note" — a `workbench.notes` row (working kind only).
|
|
59
|
-
* - "cx_working_document"— a `
|
|
59
|
+
* - "cx_working_document"— a `content.document` row: the durable,
|
|
60
60
|
* conversation-scoped default backing. The agent's
|
|
61
61
|
* ctx_patch edits persist here (working kind) and
|
|
62
62
|
* round-trip back via Supabase realtime.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* scratch). MATERIALIZE-ON-WRITE model:
|
|
6
6
|
*
|
|
7
7
|
* - Enabling a document only RESERVES a client id (binding) — no DB row. The
|
|
8
|
-
* durable `
|
|
8
|
+
* durable `content.document` row is created on the FIRST byte of
|
|
9
9
|
* content, by whichever party writes first
|
|
10
10
|
* (`materializeWorkingDocumentThunk` for the user; the server's writeback
|
|
11
11
|
* for the agent, reflected via the stream). The separate association edge
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Scratchpad thunks — the USER-GLOBAL scratchpad pool.
|
|
3
3
|
*
|
|
4
|
-
* Scratchpads are the user's personal notepads: `
|
|
4
|
+
* Scratchpads are the user's personal notepads: `content.document`
|
|
5
5
|
* rows (kind "scratch") owned by the user, DECOUPLED from conversations. One is
|
|
6
6
|
* ACTIVE at all times (`userPreferences.scratchpad.activeId`, synced
|
|
7
7
|
* cross-device); the active one is published read-only into a conversation's
|
|
@@ -3,6 +3,7 @@ import { supabase } from "../../../../host/db.js";
|
|
|
3
3
|
import { updateMessageRecord } from "../messages/messages.slice.js";
|
|
4
4
|
import { messageRowToRecord } from "../thunks/conversation-bundle.js";
|
|
5
5
|
import { durableRecordId } from "@ai-matrx/kit/ids";
|
|
6
|
+
import { isSignedOutVisitor } from "../../../../host/identity.js";
|
|
6
7
|
function hasDisplayableMessageContent(value) {
|
|
7
8
|
if (!Array.isArray(value)) return false;
|
|
8
9
|
return value.some((part) => {
|
|
@@ -27,6 +28,9 @@ const refetchSingleMessage = createAsyncThunk(
|
|
|
27
28
|
message: "This answer has no saved copy yet \u2014 nothing to reload."
|
|
28
29
|
});
|
|
29
30
|
}
|
|
31
|
+
if (await isSignedOutVisitor()) {
|
|
32
|
+
return { conversationId, messageId, found: false, refreshed: false };
|
|
33
|
+
}
|
|
30
34
|
const read = () => {
|
|
31
35
|
const byId = supabase.schema("chat").from("message").select("*").eq("id", messageId);
|
|
32
36
|
const scoped = persistedConversationId ? byId.eq("conversation_id", persistedConversationId) : byId;
|
|
@@ -35,6 +39,7 @@ const refetchSingleMessage = createAsyncThunk(
|
|
|
35
39
|
let result = await read();
|
|
36
40
|
let delay = 250;
|
|
37
41
|
for (let attempt = 0; waitForReadable && attempt < 7; attempt++) {
|
|
42
|
+
if (result.error) break;
|
|
38
43
|
const hasBody = hasDisplayableMessageContent(
|
|
39
44
|
result.data?.user_content ?? result.data?.content
|
|
40
45
|
);
|
|
@@ -111,7 +111,7 @@ import { docKindForContextKey } from "../../../utils/workingDocumentContext.js";
|
|
|
111
111
|
import { isCanvasItemContextKey } from "../../../utils/canvasItemContext.js";
|
|
112
112
|
import { StreamingJsonTracker } from "@ai-matrx/kit/json-extract";
|
|
113
113
|
import { StreamBlockAccumulator } from "../utils/stream-block-accumulator.js";
|
|
114
|
-
import {
|
|
114
|
+
import { deriveAnswerDataText } from "../active-requests/active-requests.selectors.js";
|
|
115
115
|
import { captureError } from "../../../../host/diagnostics.js";
|
|
116
116
|
import { readReceiptThread, withReceiptHandle } from "../instance-resources/remark-handles.js";
|
|
117
117
|
import { stampPersistedRemarkHandles } from "../message-crud/stamp-remark-handles.thunk.js";
|
|
@@ -351,7 +351,7 @@ async function processStream({
|
|
|
351
351
|
const runJsonExtraction = (isFinal) => {
|
|
352
352
|
if (!jsonTracker) return;
|
|
353
353
|
const req = getState().activeRequests.byRequestId[requestId];
|
|
354
|
-
const answerText = req ?
|
|
354
|
+
const answerText = req ? deriveAnswerDataText(req, blockAccumulator.getWrapperSplitSources()) : "";
|
|
355
355
|
if (!reasoningLeakReported && hasReasoningLeak(answerText)) {
|
|
356
356
|
reasoningLeakReported = true;
|
|
357
357
|
captureError({
|
|
@@ -38,6 +38,15 @@ export declare class StreamBlockAccumulator {
|
|
|
38
38
|
* to be a different typed block (see the bare-JSON duplication note there).
|
|
39
39
|
*/
|
|
40
40
|
private currentBlockEmitted;
|
|
41
|
+
/**
|
|
42
|
+
* THE DATA KEEPS ITS KINDS. A JSON wrapper that holds kinds is drawn as its
|
|
43
|
+
* kinds plus a residual (A7) — the residual is the wrapper's data WITH ITS
|
|
44
|
+
* KINDS REMOVED, so it is a display projection, never the answer. Every
|
|
45
|
+
* such split remembers the bytes it was cut from, keyed by its first block
|
|
46
|
+
* index, so data capture (`deriveAnswerDataText`) reads what the model wrote.
|
|
47
|
+
* Live only; a rewind forgets every split at or past its boundary.
|
|
48
|
+
*/
|
|
49
|
+
private wrapperSplits;
|
|
41
50
|
private subState;
|
|
42
51
|
/**
|
|
43
52
|
* URL + label for the current `audio` block. The accumulator's single-line
|
|
@@ -148,6 +157,11 @@ export declare class StreamBlockAccumulator {
|
|
|
148
157
|
* the local streaming state so the replacement provider attempt cannot
|
|
149
158
|
* concatenate onto or resurrect the failed attempt.
|
|
150
159
|
*/
|
|
160
|
+
/** The source bytes behind every live A7 wrapper split (see `wrapperSplits`). */
|
|
161
|
+
getWrapperSplitSources(): Array<{
|
|
162
|
+
blockIds: string[];
|
|
163
|
+
source: string;
|
|
164
|
+
}>;
|
|
151
165
|
rewindToBlockCount(blockCount: number): void;
|
|
152
166
|
/**
|
|
153
167
|
* Close the current text block at an interleaved-content boundary — a tool
|
|
@@ -321,6 +321,15 @@ class StreamBlockAccumulator {
|
|
|
321
321
|
* to be a different typed block (see the bare-JSON duplication note there).
|
|
322
322
|
*/
|
|
323
323
|
currentBlockEmitted = false;
|
|
324
|
+
/**
|
|
325
|
+
* THE DATA KEEPS ITS KINDS. A JSON wrapper that holds kinds is drawn as its
|
|
326
|
+
* kinds plus a residual (A7) — the residual is the wrapper's data WITH ITS
|
|
327
|
+
* KINDS REMOVED, so it is a display projection, never the answer. Every
|
|
328
|
+
* such split remembers the bytes it was cut from, keyed by its first block
|
|
329
|
+
* index, so data capture (`deriveAnswerDataText`) reads what the model wrote.
|
|
330
|
+
* Live only; a rewind forgets every split at or past its boundary.
|
|
331
|
+
*/
|
|
332
|
+
wrapperSplits = /* @__PURE__ */ new Map();
|
|
324
333
|
subState = { kind: "none" };
|
|
325
334
|
/**
|
|
326
335
|
* URL + label for the current `audio` block. The accumulator's single-line
|
|
@@ -524,7 +533,19 @@ ${this.pendingLineFragment}` : this.pendingLineFragment
|
|
|
524
533
|
* the local streaming state so the replacement provider attempt cannot
|
|
525
534
|
* concatenate onto or resurrect the failed attempt.
|
|
526
535
|
*/
|
|
536
|
+
/** The source bytes behind every live A7 wrapper split (see `wrapperSplits`). */
|
|
537
|
+
getWrapperSplitSources() {
|
|
538
|
+
return [...this.wrapperSplits.values()].map((split) => ({
|
|
539
|
+
blockIds: split.indices.map((i) => `client_block_${i}`),
|
|
540
|
+
source: split.source
|
|
541
|
+
}));
|
|
542
|
+
}
|
|
527
543
|
rewindToBlockCount(blockCount) {
|
|
544
|
+
for (const [start, split] of this.wrapperSplits) {
|
|
545
|
+
if (start >= blockCount || split.indices.some((i) => i >= blockCount)) {
|
|
546
|
+
this.wrapperSplits.delete(start);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
528
549
|
this.irDisposeAll();
|
|
529
550
|
this.currentBlockIndex = Math.max(0, blockCount);
|
|
530
551
|
this.currentBlockType = "text";
|
|
@@ -1769,6 +1790,9 @@ ${this.currentBlockContent}
|
|
|
1769
1790
|
const containerMetadata = genericXml || recoveredXmlContainer ? { genericXmlContainer: true } : void 0;
|
|
1770
1791
|
let emitted = 0;
|
|
1771
1792
|
let followsKind = false;
|
|
1793
|
+
const splitStart = this.currentBlockIndex;
|
|
1794
|
+
const splitIndices = [];
|
|
1795
|
+
const isWrapperSplit = pieces.some((piece) => piece.type === "residual");
|
|
1772
1796
|
for (const piece of pieces) {
|
|
1773
1797
|
if (piece.type === "chrome") continue;
|
|
1774
1798
|
const isKind = piece.type === "kind";
|
|
@@ -1788,9 +1812,13 @@ ${this.currentBlockContent}
|
|
|
1788
1812
|
metadata: asJson ? withIrEnvelope(content, void 0) : containerMetadata
|
|
1789
1813
|
};
|
|
1790
1814
|
dispatch(this.upsertAction({ requestId: this.requestId, block }));
|
|
1815
|
+
splitIndices.push(this.currentBlockIndex);
|
|
1791
1816
|
emitted++;
|
|
1792
1817
|
this.emitCount++;
|
|
1793
1818
|
}
|
|
1819
|
+
if (isWrapperSplit && emitted > 0) {
|
|
1820
|
+
this.wrapperSplits.set(splitStart, { indices: splitIndices, source: recoverySource });
|
|
1821
|
+
}
|
|
1794
1822
|
this.currentBlockEmitted = emitted > 0;
|
|
1795
1823
|
return emitted > 0;
|
|
1796
1824
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* platform-keys — which platform the person is on, and the undo/redo shortcut hints for it.
|
|
3
|
+
* Shared by the run-side input undo (useInstanceInputUndoRedo) and the agent builder's
|
|
4
|
+
* own undo hook (matrx-frontend features/agents/hooks/useAgentUndoRedo).
|
|
5
|
+
*/
|
|
6
|
+
export type Platform = "mac" | "windows" | "ios" | "android" | "linux" | "unknown";
|
|
7
|
+
export declare function getPlatform(): Platform;
|
|
8
|
+
export declare function isMacLike(): boolean;
|
|
9
|
+
export declare function isTouchDevice(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Returns a human-readable shortcut hint string for the current platform.
|
|
12
|
+
* Examples: "⌘Z" on Mac, "Ctrl+Z" on Windows, "Shake" on iOS.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getUndoShortcutHint(): string;
|
|
15
|
+
export declare function getRedoShortcutHint(): string;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
let _cachedPlatform = null;
|
|
2
|
+
function getPlatform() {
|
|
3
|
+
if (_cachedPlatform) return _cachedPlatform;
|
|
4
|
+
if (typeof navigator === "undefined") return "unknown";
|
|
5
|
+
const ua = navigator.userAgent.toLowerCase();
|
|
6
|
+
if (/iphone|ipad|ipod/.test(ua)) {
|
|
7
|
+
_cachedPlatform = "ios";
|
|
8
|
+
} else if (/android/.test(ua)) {
|
|
9
|
+
_cachedPlatform = "android";
|
|
10
|
+
} else if (/mac/.test(ua)) {
|
|
11
|
+
_cachedPlatform = "mac";
|
|
12
|
+
} else if (/win/.test(ua)) {
|
|
13
|
+
_cachedPlatform = "windows";
|
|
14
|
+
} else if (/linux/.test(ua)) {
|
|
15
|
+
_cachedPlatform = "linux";
|
|
16
|
+
} else {
|
|
17
|
+
_cachedPlatform = "unknown";
|
|
18
|
+
}
|
|
19
|
+
return _cachedPlatform;
|
|
20
|
+
}
|
|
21
|
+
function isMacLike() {
|
|
22
|
+
const p = getPlatform();
|
|
23
|
+
return p === "mac" || p === "ios";
|
|
24
|
+
}
|
|
25
|
+
function isTouchDevice() {
|
|
26
|
+
const p = getPlatform();
|
|
27
|
+
return p === "ios" || p === "android";
|
|
28
|
+
}
|
|
29
|
+
function getUndoShortcutHint() {
|
|
30
|
+
const p = getPlatform();
|
|
31
|
+
switch (p) {
|
|
32
|
+
case "mac":
|
|
33
|
+
return "\u2318Z";
|
|
34
|
+
case "ios":
|
|
35
|
+
return "Shake to Undo";
|
|
36
|
+
case "android":
|
|
37
|
+
return "Ctrl+Z";
|
|
38
|
+
case "windows":
|
|
39
|
+
return "Ctrl+Z";
|
|
40
|
+
case "linux":
|
|
41
|
+
return "Ctrl+Z";
|
|
42
|
+
default:
|
|
43
|
+
return "Ctrl+Z";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function getRedoShortcutHint() {
|
|
47
|
+
const p = getPlatform();
|
|
48
|
+
switch (p) {
|
|
49
|
+
case "mac":
|
|
50
|
+
return "\u21E7\u2318Z";
|
|
51
|
+
case "ios":
|
|
52
|
+
return "Shake to Redo";
|
|
53
|
+
case "android":
|
|
54
|
+
return "Ctrl+Shift+Z";
|
|
55
|
+
case "windows":
|
|
56
|
+
return "Ctrl+Y";
|
|
57
|
+
case "linux":
|
|
58
|
+
return "Ctrl+Shift+Z";
|
|
59
|
+
default:
|
|
60
|
+
return "Ctrl+Shift+Z";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
getPlatform,
|
|
65
|
+
getRedoShortcutHint,
|
|
66
|
+
getUndoShortcutHint,
|
|
67
|
+
isMacLike,
|
|
68
|
+
isTouchDevice
|
|
69
|
+
};
|
|
@@ -20,7 +20,7 @@ import type { ComponentType } from "react";
|
|
|
20
20
|
import type { AssociationSourceEdge, AssociationTargetEdge } from "@ai-matrx/associations";
|
|
21
21
|
import type { ChatDatabase, Json } from "../../host/db-types.js";
|
|
22
22
|
import { type AnyComponent, type AnyFn } from "../../host/registered-source.js";
|
|
23
|
-
export type ContextItemRow = ChatDatabase["
|
|
23
|
+
export type ContextItemRow = ChatDatabase["deprecated"]["Tables"]["context_items"]["Row"];
|
|
24
24
|
export type ContextItemValueType = ChatDatabase["public"]["Enums"]["context_value_type"];
|
|
25
25
|
export type ContextValueType = ContextItemValueType;
|
|
26
26
|
export interface ScopeNode {
|
|
@@ -53,7 +53,7 @@ import { useTouchOnlyDevice } from "../../../ui/composer/useTouchOnlyDevice.js";
|
|
|
53
53
|
import {
|
|
54
54
|
composerKeyIntent,
|
|
55
55
|
intentTakesTheKey
|
|
56
|
-
} from "
|
|
56
|
+
} from "@ai-matrx/kit/composer-keys";
|
|
57
57
|
import { Button } from "@ai-matrx/design-system/controls";
|
|
58
58
|
function uploadMimeToBlockType(mime) {
|
|
59
59
|
return mime.startsWith("image/") ? "image" : "document";
|
|
@@ -64,7 +64,7 @@ import { useTouchOnlyDevice } from "../ui/composer/useTouchOnlyDevice.js";
|
|
|
64
64
|
import {
|
|
65
65
|
composerKeyIntent,
|
|
66
66
|
intentTakesTheKey
|
|
67
|
-
} from "
|
|
67
|
+
} from "@ai-matrx/kit/composer-keys";
|
|
68
68
|
import { Button } from "@ai-matrx/design-system/controls";
|
|
69
69
|
function ConversationInput({
|
|
70
70
|
sessionId,
|