@ai-matrx/chat 0.3.15 → 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 +47 -0
- package/dist/agents/components/agent-widgets/chat-assistant/CompactAssistantInput.js +1 -1
- 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/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/redux/agent-definition/selectors.d.ts +8 -8
- 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/utils/platform-keys.d.ts +15 -0
- package/dist/agents/utils/platform-keys.js +69 -0
- 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 +1017 -1692
- package/dist/host/ui-slots.d.ts +47 -64
- package/dist/host/ui-slots.js +10 -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/package.json +56 -30
- 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
|
|
@@ -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
|
+
};
|
|
@@ -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,
|