@agentshouse/mdruntime 0.1.0-c2e8a6f99866d → 0.1.0-c2ef9303a058d
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/README.md +11 -9
- package/dist/adapter.d.ts +95 -67
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +5 -11
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +36 -47
- package/dist/binary.d.ts +0 -5
- package/dist/binary.d.ts.map +1 -1
- package/dist/binary.js +1 -1
- package/dist/bootstrap.d.ts +17 -9
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +143 -94
- package/dist/chain.d.ts +2 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/change-set.d.ts +1 -7
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +1 -4
- package/dist/client.d.ts +15 -12
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +56 -8
- package/dist/collection.d.ts +7 -4
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +24 -19
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +117 -243
- package/dist/connection.d.ts +14 -12
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1466 -1431
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/{chat/context.js → context.js} +1 -4
- package/dist/conversation.d.ts +18 -15
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +273 -185
- package/dist/durability.d.ts +6 -4
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +5 -0
- package/dist/entry.d.ts +3 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +17 -8
- package/dist/file.d.ts +2 -11
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +6 -4
- package/dist/host.d.ts +3 -7
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +55 -38
- package/dist/identity.d.ts +0 -2
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -6
- package/dist/index.d.ts +15 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/job.d.ts +14 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +28 -0
- package/dist/live.d.ts +2 -1
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +9 -5
- package/dist/media.d.ts +8 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +218 -0
- package/dist/memory.d.ts +12 -6
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +209 -101
- package/dist/messages.d.ts +28 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +89 -0
- package/dist/model.d.ts +8 -8
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +7 -13
- package/dist/observation.d.ts +3 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +8 -3
- package/dist/outcome.d.ts +13 -6
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +16 -5
- package/dist/overlay.js +1 -1
- package/dist/paths.d.ts +1 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +4 -0
- package/dist/query.d.ts +10 -206
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -494
- package/dist/reach.d.ts +14 -9
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +84 -72
- package/dist/react.d.ts +3 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/readiness.d.ts +14 -17
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +2 -8
- package/dist/recovery.d.ts +1 -0
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +26 -0
- package/dist/refresh.d.ts +10 -4
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +88 -30
- package/dist/replica.d.ts +11 -8
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +30 -15
- package/dist/room-draft.d.ts +22 -5
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +131 -51
- package/dist/rows.d.ts +18 -16
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +45 -153
- package/dist/save.d.ts +2 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +13 -7
- package/dist/search.d.ts +12 -95
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +10 -349
- package/dist/shared.d.ts +0 -1
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +0 -10
- package/dist/status.d.ts +4 -3
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -1
- package/dist/store.d.ts +25 -62
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +43 -282
- package/dist/stored.d.ts +12 -26
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +189 -226
- package/dist/tables.d.ts +55 -48
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +107 -57
- package/dist/transfer.d.ts +0 -5
- package/dist/transfer.d.ts.map +1 -1
- package/dist/validation.d.ts +3 -4
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +39 -97
- package/dist/windows.d.ts +1 -12
- package/dist/windows.d.ts.map +1 -1
- package/dist/windows.js +2 -75
- package/dist/wire.d.ts +14 -9
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +5 -3
- package/package.json +14 -18
- package/AGENTS.md +0 -312
- package/dist/chat/acts.d.ts +0 -33
- package/dist/chat/acts.d.ts.map +0 -1
- package/dist/chat/acts.js +0 -36
- package/dist/chat/context.d.ts +0 -3
- package/dist/chat/context.d.ts.map +0 -1
- package/dist/chat/earlier.d.ts +0 -10
- package/dist/chat/earlier.d.ts.map +0 -1
- package/dist/chat/earlier.js +0 -54
- package/dist/chat/house.d.ts +0 -25
- package/dist/chat/house.d.ts.map +0 -1
- package/dist/chat/house.js +0 -38
- package/dist/chat/input.d.ts +0 -11
- package/dist/chat/input.d.ts.map +0 -1
- package/dist/chat/input.js +0 -92
- package/dist/chat/kit.d.ts +0 -61
- package/dist/chat/kit.d.ts.map +0 -1
- package/dist/chat/kit.js +0 -123
- package/dist/chat/lasting.d.ts +0 -6
- package/dist/chat/lasting.d.ts.map +0 -1
- package/dist/chat/lasting.js +0 -19
- package/dist/chat/list.d.ts +0 -28
- package/dist/chat/list.d.ts.map +0 -1
- package/dist/chat/list.js +0 -103
- package/dist/chat/markdown.d.ts +0 -21
- package/dist/chat/markdown.d.ts.map +0 -1
- package/dist/chat/markdown.js +0 -246
- package/dist/chat/message.d.ts +0 -7
- package/dist/chat/message.d.ts.map +0 -1
- package/dist/chat/message.js +0 -244
- package/dist/chat/messages.d.ts +0 -30
- package/dist/chat/messages.d.ts.map +0 -1
- package/dist/chat/messages.js +0 -198
- package/dist/chat/name.d.ts +0 -7
- package/dist/chat/name.d.ts.map +0 -1
- package/dist/chat/name.js +0 -37
- package/dist/chat/opened.d.ts +0 -12
- package/dist/chat/opened.d.ts.map +0 -1
- package/dist/chat/opened.js +0 -19
- package/dist/chat/overlay.d.ts +0 -32
- package/dist/chat/overlay.d.ts.map +0 -1
- package/dist/chat/overlay.js +0 -103
- package/dist/chat/parts.d.ts +0 -58
- package/dist/chat/parts.d.ts.map +0 -1
- package/dist/chat/parts.js +0 -120
- package/dist/chat/pieces.d.ts +0 -62
- package/dist/chat/pieces.d.ts.map +0 -1
- package/dist/chat/pieces.js +0 -1110
- package/dist/chat/process.d.ts +0 -20
- package/dist/chat/process.d.ts.map +0 -1
- package/dist/chat/process.js +0 -32
- package/dist/chat/provider.d.ts +0 -70
- package/dist/chat/provider.d.ts.map +0 -1
- package/dist/chat/provider.js +0 -635
- package/dist/chat/question.d.ts +0 -9
- package/dist/chat/question.d.ts.map +0 -1
- package/dist/chat/question.js +0 -69
- package/dist/chat/questions.d.ts +0 -31
- package/dist/chat/questions.d.ts.map +0 -1
- package/dist/chat/questions.js +0 -111
- package/dist/chat/read.d.ts +0 -5
- package/dist/chat/read.d.ts.map +0 -1
- package/dist/chat/read.js +0 -13
- package/dist/chat/ready.d.ts +0 -37
- package/dist/chat/ready.d.ts.map +0 -1
- package/dist/chat/ready.js +0 -93
- package/dist/chat/room-file.d.ts +0 -8
- package/dist/chat/room-file.d.ts.map +0 -1
- package/dist/chat/room-file.js +0 -72
- package/dist/chat/steady.d.ts +0 -3
- package/dist/chat/steady.d.ts.map +0 -1
- package/dist/chat/steady.js +0 -26
- package/dist/chat/style.d.ts +0 -4
- package/dist/chat/style.d.ts.map +0 -1
- package/dist/chat/style.js +0 -306
- package/dist/chat.d.ts +0 -15
- package/dist/chat.d.ts.map +0 -1
- package/dist/chat.js +0 -8
- package/dist/reads.d.ts +0 -11
- package/dist/reads.d.ts.map +0 -1
- package/dist/reads.js +0 -98
package/dist/memory.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { documentFacts } from '@agentshouse/mdmodel';
|
|
2
|
+
import { NO_ROOM_TYPES, schemaTypes } from './attached-model.js';
|
|
1
3
|
import { sameChange } from './overlay.js';
|
|
4
|
+
const ATTACHMENTS = 'attachments';
|
|
5
|
+
function lastName(path) {
|
|
6
|
+
return path.slice(path.lastIndexOf('/') + 1);
|
|
7
|
+
}
|
|
2
8
|
const FIXTURE_RETENTION = {
|
|
3
9
|
history: { kind: 'duration', seconds: 1 },
|
|
4
|
-
outcome: 604_800,
|
|
5
10
|
refreshHorizon: 1,
|
|
6
11
|
};
|
|
7
12
|
function declaredRetention(value) {
|
|
@@ -15,12 +20,7 @@ function declaredRetention(value) {
|
|
|
15
20
|
}
|
|
16
21
|
const MODEL_ABSENT = { kind: 'model-unavailable', reason: 'not-readable' };
|
|
17
22
|
function modelsOf(room) {
|
|
18
|
-
return {
|
|
19
|
-
collection: room.model ?? MODEL_ABSENT,
|
|
20
|
-
...(room.typedSelection === undefined
|
|
21
|
-
? {}
|
|
22
|
-
: { selection: room.selectionModel ?? MODEL_ABSENT }),
|
|
23
|
-
};
|
|
23
|
+
return { collection: room.model ?? MODEL_ABSENT };
|
|
24
24
|
}
|
|
25
25
|
function changedModels(room, from) {
|
|
26
26
|
const now = modelsOf(room);
|
|
@@ -53,13 +53,16 @@ export function createMemoryAdapter(options = {}) {
|
|
|
53
53
|
const listeners = new Set();
|
|
54
54
|
const modeObservers = new Set();
|
|
55
55
|
const scripted = new Map();
|
|
56
|
-
const unsealed = new Map();
|
|
57
|
-
const sealed = new Set();
|
|
58
56
|
const sentTurns = new Map();
|
|
59
57
|
const historyPageSize = options.historyPageSize;
|
|
60
|
-
|
|
58
|
+
const attached = new Map();
|
|
59
|
+
const linked = new WeakMap();
|
|
60
|
+
const carried = new Map();
|
|
61
61
|
let expiring = [];
|
|
62
|
+
let openings = 0;
|
|
63
|
+
const declaredRooms = new Set();
|
|
62
64
|
let replicated = [];
|
|
65
|
+
let heldCursor = null;
|
|
63
66
|
let issued = 0;
|
|
64
67
|
function scriptConversations(entries) {
|
|
65
68
|
scripted.clear();
|
|
@@ -87,8 +90,48 @@ export function createMemoryAdapter(options = {}) {
|
|
|
87
90
|
const wanted = ordinals.get(`${locator}\u0000${target}`);
|
|
88
91
|
return held !== undefined && wanted !== undefined && held >= wanted;
|
|
89
92
|
}
|
|
93
|
+
function heldBlob(room, path) {
|
|
94
|
+
return attached.get(`${room.locator}\u0000${path}`) ?? room.blobs?.[path];
|
|
95
|
+
}
|
|
96
|
+
function freePath(room, name) {
|
|
97
|
+
const dot = name.lastIndexOf('.');
|
|
98
|
+
const stem = dot > 0 ? name.slice(0, dot) : name;
|
|
99
|
+
const extension = dot > 0 ? name.slice(dot) : '';
|
|
100
|
+
for (let count = 1;; count += 1) {
|
|
101
|
+
const path = `${ATTACHMENTS}/${count === 1 ? stem : `${stem}-${count}`}${extension}`;
|
|
102
|
+
if (heldBlob(room, path) === undefined && room.documents?.[path] === undefined)
|
|
103
|
+
return path;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const saved = new WeakMap();
|
|
107
|
+
function factsAt(room, path, content) {
|
|
108
|
+
const types = schemaTypes(room.model?.kind === 'model' ? room.model.snapshot.schema : null, NO_ROOM_TYPES);
|
|
109
|
+
let held = saved.get(types);
|
|
110
|
+
if (held === undefined) {
|
|
111
|
+
held = new Map();
|
|
112
|
+
saved.set(types, held);
|
|
113
|
+
}
|
|
114
|
+
const key = `${path}\u0000${content}`;
|
|
115
|
+
if (!held.has(key)) {
|
|
116
|
+
const facts = documentFacts(path, content, { types });
|
|
117
|
+
held.set(key, facts === null ? null : JSON.parse(JSON.stringify(facts)));
|
|
118
|
+
}
|
|
119
|
+
return held.get(key);
|
|
120
|
+
}
|
|
121
|
+
function factsIn(room, paths) {
|
|
122
|
+
const facts = {};
|
|
123
|
+
for (const path of paths) {
|
|
124
|
+
const content = room.documents?.[path];
|
|
125
|
+
const held = room.facts?.[path] ?? (content === undefined ? null : factsAt(room, path, content));
|
|
126
|
+
if (held !== null)
|
|
127
|
+
facts[path] = held;
|
|
128
|
+
}
|
|
129
|
+
return facts;
|
|
130
|
+
}
|
|
90
131
|
function retain(entries) {
|
|
91
132
|
for (const room of entries) {
|
|
133
|
+
for (const [path, content] of Object.entries(room.documents ?? {}))
|
|
134
|
+
factsAt(room, path, content);
|
|
92
135
|
note(room.locator, room);
|
|
93
136
|
const versions = served.get(room.locator) ?? new Map();
|
|
94
137
|
versions.set(room.roomVersion, room);
|
|
@@ -121,6 +164,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
121
164
|
roomVersion: room.roomVersion,
|
|
122
165
|
...(opening ? { models: modelsOf(room) } : {}),
|
|
123
166
|
documents: named(room.documents ?? {}, taken),
|
|
167
|
+
facts: factsIn(room, taken),
|
|
124
168
|
revisions: named(room.revisions ?? {}, [...taken, ...targets]),
|
|
125
169
|
...(room.fileIds === undefined
|
|
126
170
|
? {}
|
|
@@ -141,7 +185,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
141
185
|
...(folderRemovals.length === 0 ? {} : { folderRemovals }),
|
|
142
186
|
};
|
|
143
187
|
}
|
|
144
|
-
function advancement(room, from, at) {
|
|
188
|
+
function advancement(room, from, at, whole = false) {
|
|
145
189
|
const current = room.documents ?? {};
|
|
146
190
|
const previous = from.documents ?? {};
|
|
147
191
|
const currentTargets = new Set(Object.keys(room.binaryFiles ?? {}));
|
|
@@ -152,7 +196,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
152
196
|
const changed = Object.keys(current)
|
|
153
197
|
.filter((path) => current[path] !== previous[path] || headMoved(path))
|
|
154
198
|
.sort();
|
|
155
|
-
const size = pageSize ?? changed.length;
|
|
199
|
+
const size = whole ? changed.length : (pageSize ?? changed.length);
|
|
156
200
|
const taken = changed.slice(at, at + size);
|
|
157
201
|
const next = at + taken.length;
|
|
158
202
|
const opening = at === 0;
|
|
@@ -168,6 +212,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
168
212
|
roomVersion: room.roomVersion,
|
|
169
213
|
...(models === undefined ? {} : { models }),
|
|
170
214
|
documents: named(current, taken),
|
|
215
|
+
facts: factsIn(room, taken),
|
|
171
216
|
revisions: named(room.revisions ?? {}, [...taken, ...targets]),
|
|
172
217
|
...(room.fileIds === undefined
|
|
173
218
|
? {}
|
|
@@ -184,6 +229,26 @@ export function createMemoryAdapter(options = {}) {
|
|
|
184
229
|
...(pageToken === undefined ? {} : { pageToken }),
|
|
185
230
|
};
|
|
186
231
|
}
|
|
232
|
+
function carry(locator) {
|
|
233
|
+
const at = carried.get(locator);
|
|
234
|
+
const current = rooms.find((entry) => entry.locator === locator);
|
|
235
|
+
if (at === undefined || current === undefined || current.roomVersion === at)
|
|
236
|
+
return;
|
|
237
|
+
const from = served.get(locator)?.get(at);
|
|
238
|
+
carried.set(locator, current.roomVersion);
|
|
239
|
+
if (from === undefined)
|
|
240
|
+
return;
|
|
241
|
+
const page = advancement(current, from, 0, true);
|
|
242
|
+
for (const observer of observers) {
|
|
243
|
+
observer({
|
|
244
|
+
kind: 'room-change',
|
|
245
|
+
locator,
|
|
246
|
+
from: at,
|
|
247
|
+
roomVersion: current.roomVersion,
|
|
248
|
+
read: async () => page,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
187
252
|
function pageOf(conversation, after) {
|
|
188
253
|
const messages = conversation.messages ?? [];
|
|
189
254
|
const first = typeof after === 'string' ? messages.findIndex((message) => message.position > after) : 0;
|
|
@@ -198,16 +263,13 @@ export function createMemoryAdapter(options = {}) {
|
|
|
198
263
|
: {}),
|
|
199
264
|
};
|
|
200
265
|
}
|
|
201
|
-
function historiesOf(
|
|
202
|
-
const asked = input?.conversations;
|
|
203
|
-
if (!Array.isArray(asked))
|
|
204
|
-
return { kind: 'rejected', code: 'invalid_request', fields: {}, retryable: false };
|
|
266
|
+
function historiesOf(request) {
|
|
205
267
|
const histories = [];
|
|
206
|
-
for (const entry of
|
|
207
|
-
const conversation =
|
|
268
|
+
for (const entry of request.conversations) {
|
|
269
|
+
const conversation = scripted.get(entry.conversation);
|
|
208
270
|
if (conversation === undefined)
|
|
209
271
|
continue;
|
|
210
|
-
const outcome = conversation.outcomes?.
|
|
272
|
+
const outcome = conversation.outcomes?.history;
|
|
211
273
|
if (outcome !== undefined)
|
|
212
274
|
return outcome;
|
|
213
275
|
histories.push(pageOf(conversation, entry.after));
|
|
@@ -218,15 +280,13 @@ export function createMemoryAdapter(options = {}) {
|
|
|
218
280
|
function conversationAction(request) {
|
|
219
281
|
const name = request.name;
|
|
220
282
|
const input = (request.input ?? {});
|
|
221
|
-
if (name === '
|
|
222
|
-
return historiesOf(request.input);
|
|
223
|
-
if (name === 'conversation.create') {
|
|
283
|
+
if (name === 'conversations/create') {
|
|
224
284
|
issued += 1;
|
|
225
285
|
const conversation = `conversation-${issued}`;
|
|
226
286
|
scripted.set(conversation, { conversation });
|
|
227
|
-
return { kind: 'action', result: { conversation } };
|
|
287
|
+
return { kind: 'action', result: { conversation_id: conversation } };
|
|
228
288
|
}
|
|
229
|
-
const named = typeof input.
|
|
289
|
+
const named = typeof input.conversation_id === 'string' ? input.conversation_id : '';
|
|
230
290
|
const conversation = scripted.get(named);
|
|
231
291
|
if (conversation === undefined) {
|
|
232
292
|
return {
|
|
@@ -239,34 +299,28 @@ export function createMemoryAdapter(options = {}) {
|
|
|
239
299
|
const outcome = conversation.outcomes?.[name];
|
|
240
300
|
if (outcome !== undefined)
|
|
241
301
|
return outcome;
|
|
242
|
-
if (name === '
|
|
302
|
+
if (name === 'conversations/send') {
|
|
243
303
|
const operation = typeof input.operation_id === 'string' ? input.operation_id : null;
|
|
244
304
|
const answered = operation === null ? undefined : sentTurns.get(operation);
|
|
245
305
|
if (answered !== undefined)
|
|
246
|
-
return { kind: 'action', result: {
|
|
306
|
+
return { kind: 'action', result: { message_id: answered } };
|
|
247
307
|
issued += 1;
|
|
248
308
|
const turn = `turn-${issued}`;
|
|
249
|
-
unsealed.set(turn, named);
|
|
250
309
|
if (operation !== null)
|
|
251
310
|
sentTurns.set(operation, turn);
|
|
252
|
-
return { kind: 'action', result: { turn } };
|
|
311
|
+
return { kind: 'action', result: { message_id: turn } };
|
|
253
312
|
}
|
|
254
|
-
if (name === '
|
|
255
|
-
const turn = typeof input.turn === 'string' ? input.turn : '';
|
|
256
|
-
if (sealed.has(turn) || !unsealed.has(turn)) {
|
|
257
|
-
return { kind: 'rejected', code: 'turn-sealed', fields: { turn }, retryable: false };
|
|
258
|
-
}
|
|
259
|
-
unsealed.delete(turn);
|
|
260
|
-
return { kind: 'action', result: { turn, cancelled: true } };
|
|
261
|
-
}
|
|
262
|
-
if (name === 'conversation.delete')
|
|
313
|
+
if (name === 'conversations/delete')
|
|
263
314
|
scripted.delete(named);
|
|
264
|
-
return { kind: 'action', result: {
|
|
315
|
+
return { kind: 'action', result: { conversation_id: named } };
|
|
265
316
|
}
|
|
266
317
|
function announceList() {
|
|
267
|
-
const entries = [...scripted.values()].flatMap(({ conversation, listed }) => listed === undefined
|
|
268
|
-
|
|
269
|
-
|
|
318
|
+
const entries = [...scripted.values()].flatMap(({ conversation, listed, messages = [] }) => listed === undefined
|
|
319
|
+
? []
|
|
320
|
+
: [{ conversation, ...listed, newest: messages.at(-1)?.position ?? null }]);
|
|
321
|
+
for (const listener of listeners) {
|
|
322
|
+
listener({ kind: 'list', entries, whole: true, more: false, cursor: null });
|
|
323
|
+
}
|
|
270
324
|
}
|
|
271
325
|
function discovery() {
|
|
272
326
|
return {
|
|
@@ -278,8 +332,42 @@ export function createMemoryAdapter(options = {}) {
|
|
|
278
332
|
...(options.member === undefined ? {} : { member: options.member }),
|
|
279
333
|
};
|
|
280
334
|
}
|
|
335
|
+
function discovered() {
|
|
336
|
+
return resolveScript(scripts.discover, discovery, undefined).then((answer) => {
|
|
337
|
+
if (answer.kind === 'discovery')
|
|
338
|
+
for (const room of answer.rooms)
|
|
339
|
+
note(room.locator, room);
|
|
340
|
+
return answer;
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
function opened(notify) {
|
|
344
|
+
const opening = ++openings;
|
|
345
|
+
notify({ kind: 'opened' });
|
|
346
|
+
void discovered()
|
|
347
|
+
.catch(() => ({ kind: 'transport-uncertainty' }))
|
|
348
|
+
.then((answer) => {
|
|
349
|
+
if (opening !== openings)
|
|
350
|
+
return;
|
|
351
|
+
if (answer.kind !== 'discovery') {
|
|
352
|
+
openings += 1;
|
|
353
|
+
carried.clear();
|
|
354
|
+
const revoked = answer.kind === 'revoked-authorization';
|
|
355
|
+
notify({ kind: 'closed', revoked, lost: !revoked, authorityChanged: false });
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
declaredRooms.clear();
|
|
359
|
+
for (const room of answer.rooms)
|
|
360
|
+
declaredRooms.add(room.locator);
|
|
361
|
+
notify({ kind: 'discovered', discovery: answer });
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
function emitAll(event) {
|
|
365
|
+
for (const observer of observers)
|
|
366
|
+
observer(event);
|
|
367
|
+
}
|
|
281
368
|
return {
|
|
282
|
-
...(options.
|
|
369
|
+
...(options.roomTypes === undefined ? {} : { roomTypes: options.roomTypes }),
|
|
370
|
+
...(options.typedPaths === undefined ? {} : { typedPaths: options.typedPaths }),
|
|
283
371
|
setRooms(next) {
|
|
284
372
|
rooms = [...next];
|
|
285
373
|
retain(rooms);
|
|
@@ -288,33 +376,37 @@ export function createMemoryAdapter(options = {}) {
|
|
|
288
376
|
scriptConversations(next);
|
|
289
377
|
},
|
|
290
378
|
open() {
|
|
379
|
+
carried.clear();
|
|
291
380
|
announceList();
|
|
292
|
-
|
|
293
|
-
observer({ kind: 'opened' });
|
|
381
|
+
opened(emitAll);
|
|
294
382
|
},
|
|
295
|
-
close({ revoked = false, lost = !revoked } = {}) {
|
|
296
|
-
|
|
297
|
-
|
|
383
|
+
close({ revoked = false, lost = !revoked, authorityChanged = false } = {}) {
|
|
384
|
+
openings += 1;
|
|
385
|
+
carried.clear();
|
|
386
|
+
emitAll({ kind: 'closed', revoked, lost, authorityChanged });
|
|
298
387
|
},
|
|
299
388
|
expire(locators) {
|
|
300
389
|
expiring = [...locators];
|
|
301
390
|
},
|
|
302
|
-
notifyRoomVersion({ locator
|
|
303
|
-
|
|
304
|
-
observer({ kind: 'room-version', locator, roomVersion });
|
|
391
|
+
notifyRoomVersion({ locator }) {
|
|
392
|
+
carry(locator);
|
|
305
393
|
},
|
|
306
|
-
notifyAuthorityChanged(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
394
|
+
notifyAuthorityChanged(locators) {
|
|
395
|
+
const named = new Set(locators ?? [...declaredRooms, ...rooms.map((room) => room.locator)]);
|
|
396
|
+
const listed = rooms.filter((room) => named.has(room.locator));
|
|
397
|
+
const left = [...named].filter((locator) => !listed.some((room) => room.locator === locator));
|
|
398
|
+
for (const room of listed)
|
|
399
|
+
declaredRooms.add(room.locator);
|
|
400
|
+
for (const locator of left)
|
|
401
|
+
declaredRooms.delete(locator);
|
|
402
|
+
emitAll({
|
|
403
|
+
kind: 'authority-changed',
|
|
404
|
+
rooms: listed.map(declared),
|
|
405
|
+
left,
|
|
406
|
+
...(options.member === undefined ? {} : { member: options.member }),
|
|
407
|
+
});
|
|
312
408
|
},
|
|
313
409
|
notifyConversation(event) {
|
|
314
|
-
if (event.kind === 'accepted-message') {
|
|
315
|
-
sealed.add(event.message.turn);
|
|
316
|
-
unsealed.delete(event.message.turn);
|
|
317
|
-
}
|
|
318
410
|
for (const listener of listeners)
|
|
319
411
|
listener(event);
|
|
320
412
|
},
|
|
@@ -323,21 +415,31 @@ export function createMemoryAdapter(options = {}) {
|
|
|
323
415
|
observer(mode);
|
|
324
416
|
},
|
|
325
417
|
heldRooms() {
|
|
326
|
-
return
|
|
418
|
+
return [...carried.keys()].sort();
|
|
327
419
|
},
|
|
328
420
|
replicatedConversations() {
|
|
329
421
|
return replicated;
|
|
330
422
|
},
|
|
423
|
+
heldConversationCursor() {
|
|
424
|
+
return heldCursor;
|
|
425
|
+
},
|
|
331
426
|
conversations: {
|
|
332
427
|
replicate(next) {
|
|
333
428
|
replicated = [...next];
|
|
334
429
|
},
|
|
430
|
+
hold(cursor) {
|
|
431
|
+
heldCursor = cursor;
|
|
432
|
+
},
|
|
335
433
|
observe(notify) {
|
|
336
434
|
listeners.add(notify);
|
|
337
435
|
return () => {
|
|
338
436
|
listeners.delete(notify);
|
|
339
437
|
};
|
|
340
438
|
},
|
|
439
|
+
history: (request) => Promise.resolve(historiesOf(request)),
|
|
440
|
+
...(options.agents === undefined
|
|
441
|
+
? {}
|
|
442
|
+
: { agents: () => Promise.resolve(structuredClone(options.agents)) }),
|
|
341
443
|
},
|
|
342
444
|
serviceMode: {
|
|
343
445
|
observe(notify) {
|
|
@@ -349,44 +451,45 @@ export function createMemoryAdapter(options = {}) {
|
|
|
349
451
|
},
|
|
350
452
|
roomStream: {
|
|
351
453
|
hold(asked) {
|
|
352
|
-
|
|
353
|
-
const
|
|
354
|
-
expiring = [];
|
|
355
|
-
const moved = asked.flatMap((room) => {
|
|
454
|
+
const named = asked.map((room) => room.locator);
|
|
455
|
+
const unknown = asked.flatMap((room) => {
|
|
356
456
|
const current = rooms.find((entry) => entry.locator === room.locator);
|
|
357
457
|
return current === undefined ||
|
|
358
|
-
|
|
359
|
-
|
|
458
|
+
current.roomVersion === room.roomVersion ||
|
|
459
|
+
served.get(room.locator)?.has(room.roomVersion) === true
|
|
360
460
|
? []
|
|
361
|
-
: [
|
|
461
|
+
: [room.locator];
|
|
362
462
|
});
|
|
463
|
+
const expired = [
|
|
464
|
+
...new Set([...expiring.filter((locator) => named.includes(locator)), ...unknown]),
|
|
465
|
+
];
|
|
466
|
+
expiring = expiring.filter((locator) => !named.includes(locator));
|
|
363
467
|
queueMicrotask(() => {
|
|
364
|
-
for (const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
468
|
+
for (const room of asked) {
|
|
469
|
+
if (expired.includes(room.locator))
|
|
470
|
+
carried.delete(room.locator);
|
|
471
|
+
else {
|
|
472
|
+
carried.set(room.locator, room.roomVersion);
|
|
473
|
+
carry(room.locator);
|
|
474
|
+
}
|
|
368
475
|
}
|
|
476
|
+
emitAll({ kind: 'caught-up', expired });
|
|
369
477
|
});
|
|
370
478
|
},
|
|
371
|
-
reopen() {
|
|
372
|
-
queueMicrotask(() => {
|
|
373
|
-
for (const observer of observers) {
|
|
374
|
-
observer({ kind: 'closed', revoked: false, lost: false });
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
},
|
|
378
|
-
published() { },
|
|
379
479
|
observe(notify) {
|
|
380
480
|
observers.add(notify);
|
|
381
481
|
queueMicrotask(() => {
|
|
382
482
|
if (!observers.has(notify))
|
|
383
483
|
return;
|
|
384
484
|
if (options.unopened === true) {
|
|
385
|
-
notify({ kind: 'closed', revoked: false, lost: true });
|
|
485
|
+
notify({ kind: 'closed', revoked: false, lost: true, authorityChanged: false });
|
|
386
486
|
return;
|
|
387
487
|
}
|
|
388
488
|
announceList();
|
|
389
|
-
|
|
489
|
+
opened((event) => {
|
|
490
|
+
if (observers.has(notify))
|
|
491
|
+
notify(event);
|
|
492
|
+
});
|
|
390
493
|
});
|
|
391
494
|
return () => {
|
|
392
495
|
observers.delete(notify);
|
|
@@ -403,12 +506,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
403
506
|
return resolveScript(scripts.authorize, () => ({}), undefined);
|
|
404
507
|
},
|
|
405
508
|
async discover(_authorization) {
|
|
406
|
-
return
|
|
407
|
-
if (answer.kind === 'discovery')
|
|
408
|
-
for (const room of answer.rooms)
|
|
409
|
-
note(room.locator, room);
|
|
410
|
-
return answer;
|
|
411
|
-
});
|
|
509
|
+
return discovered();
|
|
412
510
|
},
|
|
413
511
|
reached,
|
|
414
512
|
follows(locator, roomVersion, next) {
|
|
@@ -487,32 +585,42 @@ export function createMemoryAdapter(options = {}) {
|
|
|
487
585
|
},
|
|
488
586
|
async binary(_authorization, request) {
|
|
489
587
|
return resolveScript(scripts.binary, () => {
|
|
490
|
-
if (request.kind === 'reference') {
|
|
491
|
-
return { kind: 'rejected', code: 'unscripted-binary', fields: {}, retryable: false };
|
|
492
|
-
}
|
|
493
588
|
const room = rooms.find((entry) => entry.locator === request.locator);
|
|
494
589
|
if (room === undefined)
|
|
495
590
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
496
|
-
const blob = room
|
|
591
|
+
const blob = heldBlob(room, request.path);
|
|
497
592
|
return blob === undefined
|
|
498
593
|
? { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false }
|
|
499
594
|
: { kind: 'binary', body: blob.stream(), mediaType: blob.type };
|
|
500
595
|
}, request);
|
|
501
596
|
},
|
|
502
597
|
async link(_authorization, request) {
|
|
503
|
-
return resolveScript(scripts.link, () =>
|
|
598
|
+
return resolveScript(scripts.link, () => {
|
|
599
|
+
const room = rooms.find((entry) => entry.locator === request.locator);
|
|
600
|
+
if (room === undefined)
|
|
601
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
602
|
+
const blob = heldBlob(room, request.path);
|
|
603
|
+
if (blob === undefined) {
|
|
604
|
+
return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
|
|
605
|
+
}
|
|
606
|
+
const url = linked.get(blob) ?? URL.createObjectURL(blob);
|
|
607
|
+
linked.set(blob, url);
|
|
608
|
+
return { kind: 'link', url, name: lastName(request.path), mediaType: blob.type };
|
|
609
|
+
}, request);
|
|
504
610
|
},
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
611
|
+
async attach(_authorization, request) {
|
|
612
|
+
return resolveScript(scripts.attach, () => {
|
|
613
|
+
const room = rooms.find((entry) => entry.locator === request.locator);
|
|
614
|
+
if (room === undefined)
|
|
615
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
616
|
+
const path = freePath(room, request.name);
|
|
617
|
+
attached.set(`${room.locator}\u0000${path}`, request.blob);
|
|
618
|
+
return { kind: 'attached', path, revision: `attached-${attached.size}` };
|
|
619
|
+
}, request);
|
|
512
620
|
},
|
|
513
621
|
async action(_authorization, request) {
|
|
514
622
|
return resolveScript(scripts.action, () => {
|
|
515
|
-
if (request.name.startsWith('
|
|
623
|
+
if (request.name.startsWith('conversations/'))
|
|
516
624
|
return conversationAction(request);
|
|
517
625
|
return { kind: 'rejected', code: 'unscripted-action', fields: {}, retryable: false };
|
|
518
626
|
}, request).then((answer) => {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AcceptedMessage } from './adapter.js';
|
|
2
|
+
import type { Connection } from './tables.js';
|
|
3
|
+
export declare const MESSAGE_TABLES: readonly string[];
|
|
4
|
+
export type HeldConversation = {
|
|
5
|
+
readonly conversation: string;
|
|
6
|
+
readonly read: string | null | undefined;
|
|
7
|
+
readonly partial: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type MessageWindow = {
|
|
10
|
+
readonly messages: AcceptedMessage[];
|
|
11
|
+
readonly more: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type ConversationWrite = {
|
|
14
|
+
readonly conversation: string;
|
|
15
|
+
readonly messages: readonly AcceptedMessage[];
|
|
16
|
+
readonly read?: {
|
|
17
|
+
readonly at: string | null;
|
|
18
|
+
readonly partial: boolean;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare function heldConversations(connection: Connection): HeldConversation[];
|
|
22
|
+
export declare function keptMessages(connection: Connection, { conversation, messages, read }: ConversationWrite): null;
|
|
23
|
+
export declare function messageWindow(connection: Connection, conversation: string, limit: number, before: readonly [string, string] | null, phrase: string | null): MessageWindow;
|
|
24
|
+
export declare function messageCount(connection: Connection, conversation: string, phrase: string | null): number;
|
|
25
|
+
export declare function turnArrived(connection: Connection, conversation: string, turn: string): boolean;
|
|
26
|
+
export declare function droppedMessages(connection: Connection, conversations: readonly string[]): void;
|
|
27
|
+
export declare function forgottenMessages(connection: Connection): void;
|
|
28
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAE1D,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAM3C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3E,CAAC;AAMF,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB,EAAE,CAmB5E;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,iBAAiB,GAClD,IAAI,CA+BN;AAkBD,wBAAgB,aAAa,CAC3B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,EACxC,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,aAAa,CAWf;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,MAAM,CAOR;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAO/F;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAK9F;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAG9D"}
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { sql } from '@agentshouse/mdmodel';
|
|
2
|
+
export const MESSAGE_TABLES = [
|
|
3
|
+
'CREATE TABLE conversation_reads (conversation TEXT PRIMARY KEY, read TEXT, partial INTEGER NOT NULL) WITHOUT ROWID',
|
|
4
|
+
'CREATE TABLE conversation_messages (id INTEGER PRIMARY KEY, conversation TEXT NOT NULL, identity TEXT NOT NULL, turn TEXT NOT NULL, position TEXT NOT NULL, message TEXT NOT NULL, text TEXT NOT NULL)',
|
|
5
|
+
'CREATE UNIQUE INDEX conversation_messages_identity ON conversation_messages (conversation, identity)',
|
|
6
|
+
'CREATE INDEX conversation_messages_position ON conversation_messages (conversation, position, identity)',
|
|
7
|
+
'CREATE INDEX conversation_messages_turn ON conversation_messages (conversation, turn)',
|
|
8
|
+
];
|
|
9
|
+
function text(value) {
|
|
10
|
+
return typeof value === 'string' ? value : String(value);
|
|
11
|
+
}
|
|
12
|
+
export function heldConversations(connection) {
|
|
13
|
+
const held = new Map();
|
|
14
|
+
for (const row of connection.rows('SELECT conversation, read, partial FROM conversation_reads')) {
|
|
15
|
+
held.set(text(row.conversation), {
|
|
16
|
+
conversation: text(row.conversation),
|
|
17
|
+
read: row.read === null ? null : text(row.read),
|
|
18
|
+
partial: Number(row.partial) === 1,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
for (const row of connection.rows('SELECT DISTINCT conversation FROM conversation_messages WHERE conversation NOT IN (SELECT conversation FROM conversation_reads)')) {
|
|
22
|
+
held.set(text(row.conversation), {
|
|
23
|
+
conversation: text(row.conversation),
|
|
24
|
+
read: undefined,
|
|
25
|
+
partial: true,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return [...held.values()];
|
|
29
|
+
}
|
|
30
|
+
export function keptMessages(connection, { conversation, messages, read }) {
|
|
31
|
+
for (const message of messages) {
|
|
32
|
+
const [held] = connection.rows('SELECT id FROM conversation_messages WHERE conversation = ? AND identity = ?', [conversation, message.identity]);
|
|
33
|
+
const record = [
|
|
34
|
+
message.turn,
|
|
35
|
+
message.position,
|
|
36
|
+
JSON.stringify(message.message ?? null),
|
|
37
|
+
message.text,
|
|
38
|
+
];
|
|
39
|
+
if (held === undefined) {
|
|
40
|
+
connection.run('INSERT INTO conversation_messages (conversation, identity, turn, position, message, text) VALUES (?, ?, ?, ?, ?, ?)', [conversation, message.identity, ...record]);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
connection.run('UPDATE conversation_messages SET turn = ?, position = ?, message = ?, text = ? WHERE id = ?', [...record, held.id]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (read !== undefined) {
|
|
47
|
+
connection.run('INSERT OR REPLACE INTO conversation_reads (conversation, read, partial) VALUES (?, ?, ?)', [conversation, read.at, read.partial ? 1 : 0]);
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
function accepted(row) {
|
|
52
|
+
return {
|
|
53
|
+
identity: text(row.identity),
|
|
54
|
+
turn: text(row.turn),
|
|
55
|
+
position: text(row.position),
|
|
56
|
+
text: text(row.text),
|
|
57
|
+
message: JSON.parse(text(row.message)),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function holding(phrase) {
|
|
61
|
+
return phrase === null
|
|
62
|
+
? { sql: '', bind: [] }
|
|
63
|
+
: { sql: ` AND ${sql.HOLDS_PHRASE}(text, ?)`, bind: [phrase.toLowerCase()] };
|
|
64
|
+
}
|
|
65
|
+
export function messageWindow(connection, conversation, limit, before, phrase) {
|
|
66
|
+
const held = holding(phrase);
|
|
67
|
+
const rows = connection.rows(`SELECT identity, turn, position, message, text FROM conversation_messages WHERE conversation = ?${held.sql}${before === null ? '' : ' AND (position < ? OR (position = ? AND identity < ?))'} ORDER BY position DESC, identity DESC LIMIT ?`, before === null
|
|
68
|
+
? [conversation, ...held.bind, limit + 1]
|
|
69
|
+
: [conversation, ...held.bind, before[0], before[0], before[1], limit + 1]);
|
|
70
|
+
return { messages: rows.slice(0, limit).map(accepted).reverse(), more: rows.length > limit };
|
|
71
|
+
}
|
|
72
|
+
export function messageCount(connection, conversation, phrase) {
|
|
73
|
+
const held = holding(phrase);
|
|
74
|
+
const [counted] = connection.rows(`SELECT count(*) AS held FROM conversation_messages WHERE conversation = ?${held.sql}`, [conversation, ...held.bind]);
|
|
75
|
+
return Number(counted?.held ?? 0);
|
|
76
|
+
}
|
|
77
|
+
export function turnArrived(connection, conversation, turn) {
|
|
78
|
+
return (connection.rows('SELECT 1 FROM conversation_messages WHERE conversation = ? AND turn = ? LIMIT 1', [conversation, turn]).length > 0);
|
|
79
|
+
}
|
|
80
|
+
export function droppedMessages(connection, conversations) {
|
|
81
|
+
for (const conversation of conversations) {
|
|
82
|
+
connection.run('DELETE FROM conversation_messages WHERE conversation = ?', [conversation]);
|
|
83
|
+
connection.run('DELETE FROM conversation_reads WHERE conversation = ?', [conversation]);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function forgottenMessages(connection) {
|
|
87
|
+
connection.run('DELETE FROM conversation_messages');
|
|
88
|
+
connection.run('DELETE FROM conversation_reads');
|
|
89
|
+
}
|