@agentshouse/mdruntime 0.1.0-ca6edc1abd618 → 0.1.0-ca8707258fdde
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 +2 -2
- package/dist/acceptance.d.ts +26 -0
- package/dist/acceptance.d.ts.map +1 -0
- package/dist/acceptance.js +384 -0
- package/dist/adapter.d.ts +102 -70
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +3 -10
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +29 -47
- package/dist/bootstrap.d.ts +16 -14
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +272 -129
- package/dist/chain.d.ts +2 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/change.d.ts +1 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/chat-types.d.ts +3 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +2 -0
- package/dist/client.d.ts +20 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +55 -6
- package/dist/collection.d.ts +7 -4
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +23 -17
- package/dist/compile.d.ts +6 -6
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +278 -282
- package/dist/connection.d.ts +22 -44
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1600 -3577
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +7 -0
- package/dist/conversation-row.d.ts +33 -0
- package/dist/conversation-row.d.ts.map +1 -0
- package/dist/conversation-row.js +47 -0
- package/dist/conversation.d.ts +27 -18
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +484 -258
- package/dist/durability.d.ts +6 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +3 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +18 -8
- package/dist/figures.d.ts +48 -0
- package/dist/figures.d.ts.map +1 -0
- package/dist/figures.js +197 -0
- 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 +29 -32
- package/dist/identity.d.ts +0 -1
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -3
- package/dist/index.d.ts +20 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/install.d.ts +86 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +537 -0
- package/dist/job.d.ts +33 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +54 -0
- package/dist/live.d.ts +5 -4
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +62 -20
- package/dist/log.d.ts +1 -0
- package/dist/log.d.ts.map +1 -1
- 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 -5
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +216 -85
- package/dist/messages.d.ts +27 -3
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +97 -19
- package/dist/model.d.ts +8 -10
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +5 -17
- 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 +14 -5
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +19 -2
- package/dist/overlay.d.ts +1 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +11 -0
- package/dist/parts.d.ts +59 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +118 -0
- 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 +18 -207
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -505
- package/dist/questions.d.ts +32 -0
- package/dist/questions.d.ts.map +1 -0
- package/dist/questions.js +118 -0
- package/dist/reach.d.ts +18 -11
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +206 -126
- package/dist/react.d.ts +5 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/read.d.ts +7 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +17 -0
- package/dist/readiness.d.ts +3 -17
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +4 -10
- package/dist/reads.d.ts +34 -10
- package/dist/reads.d.ts.map +1 -1
- package/dist/reads.js +114 -86
- package/dist/recovery.d.ts +1 -0
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +35 -1
- package/dist/refresh.d.ts +7 -5
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +33 -5
- package/dist/replica.d.ts +10 -11
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +52 -20
- package/dist/room-draft.d.ts +21 -5
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +98 -51
- package/dist/room-drafts.d.ts +29 -0
- package/dist/room-drafts.d.ts.map +1 -0
- package/dist/room-drafts.js +216 -0
- 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 +22 -13
- package/dist/saves.d.ts +96 -0
- package/dist/saves.d.ts.map +1 -0
- package/dist/saves.js +999 -0
- package/dist/search.d.ts +12 -63
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +9 -52
- package/dist/seed.d.ts +16 -2
- package/dist/seed.d.ts.map +1 -1
- package/dist/seed.js +66 -0
- package/dist/shared.d.ts +0 -1
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +0 -10
- package/dist/socket/admission.d.ts +7 -0
- package/dist/socket/admission.d.ts.map +1 -0
- package/dist/socket/admission.js +39 -0
- package/dist/socket/answers.d.ts +6 -0
- package/dist/socket/answers.d.ts.map +1 -0
- package/dist/socket/answers.js +20 -0
- package/dist/socket/reads.d.ts +10 -0
- package/dist/socket/reads.d.ts.map +1 -0
- package/dist/socket/reads.js +31 -0
- package/dist/socket.d.ts +43 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +96 -0
- package/dist/source.d.ts +61 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +81 -0
- package/dist/status.d.ts +4 -5
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -7
- package/dist/store/fences.d.ts +16 -0
- package/dist/store/fences.d.ts.map +1 -0
- package/dist/store/fences.js +26 -0
- package/dist/store/installs.d.ts +30 -0
- package/dist/store/installs.d.ts.map +1 -0
- package/dist/store/installs.js +34 -0
- package/dist/store/records.d.ts +212 -0
- package/dist/store/records.d.ts.map +1 -0
- package/dist/store/records.js +408 -0
- package/dist/store/room-held.d.ts +8 -0
- package/dist/store/room-held.d.ts.map +1 -0
- package/dist/store/room-held.js +17 -0
- package/dist/store/watchers.d.ts +15 -0
- package/dist/store/watchers.d.ts.map +1 -0
- package/dist/store/watchers.js +36 -0
- package/dist/store/writes.d.ts +24 -0
- package/dist/store/writes.d.ts.map +1 -0
- package/dist/store/writes.js +125 -0
- package/dist/store.d.ts +76 -158
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +117 -403
- package/dist/stored.d.ts +66 -55
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +343 -273
- package/dist/tables.d.ts +118 -65
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +199 -99
- package/dist/tallies.d.ts +18 -0
- package/dist/tallies.d.ts.map +1 -0
- package/dist/tallies.js +129 -0
- 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 +42 -100
- 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 +23 -8
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +8 -2
- package/package.json +2 -2
- package/dist/fence.d.ts +0 -6
- package/dist/fence.d.ts.map +0 -1
- package/dist/fence.js +0 -10
- package/dist/fulltext.d.ts +0 -27
- package/dist/fulltext.d.ts.map +0 -1
- package/dist/fulltext.js +0 -368
- package/dist/words.d.ts +0 -19
- package/dist/words.d.ts.map +0 -1
- package/dist/words.js +0 -150
package/dist/memory.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { documentFacts, parse } 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) {
|
|
@@ -48,13 +53,16 @@ export function createMemoryAdapter(options = {}) {
|
|
|
48
53
|
const listeners = new Set();
|
|
49
54
|
const modeObservers = new Set();
|
|
50
55
|
const scripted = new Map();
|
|
51
|
-
const unsealed = new Map();
|
|
52
|
-
const sealed = new Set();
|
|
53
56
|
const sentTurns = new Map();
|
|
54
57
|
const historyPageSize = options.historyPageSize;
|
|
55
|
-
|
|
58
|
+
const attached = new Map();
|
|
59
|
+
const linked = new WeakMap();
|
|
60
|
+
const carried = new Map();
|
|
56
61
|
let expiring = [];
|
|
62
|
+
let openings = 0;
|
|
63
|
+
const declaredRooms = new Set();
|
|
57
64
|
let replicated = [];
|
|
65
|
+
let heldCursor = null;
|
|
58
66
|
let issued = 0;
|
|
59
67
|
function scriptConversations(entries) {
|
|
60
68
|
scripted.clear();
|
|
@@ -82,8 +90,48 @@ export function createMemoryAdapter(options = {}) {
|
|
|
82
90
|
const wanted = ordinals.get(`${locator}\u0000${target}`);
|
|
83
91
|
return held !== undefined && wanted !== undefined && held >= wanted;
|
|
84
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, parse(content, path), { 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
|
+
}
|
|
85
131
|
function retain(entries) {
|
|
86
132
|
for (const room of entries) {
|
|
133
|
+
for (const [path, content] of Object.entries(room.documents ?? {}))
|
|
134
|
+
factsAt(room, path, content);
|
|
87
135
|
note(room.locator, room);
|
|
88
136
|
const versions = served.get(room.locator) ?? new Map();
|
|
89
137
|
versions.set(room.roomVersion, room);
|
|
@@ -116,10 +164,14 @@ export function createMemoryAdapter(options = {}) {
|
|
|
116
164
|
roomVersion: room.roomVersion,
|
|
117
165
|
...(opening ? { models: modelsOf(room) } : {}),
|
|
118
166
|
documents: named(room.documents ?? {}, taken),
|
|
167
|
+
facts: factsIn(room, taken),
|
|
119
168
|
revisions: named(room.revisions ?? {}, [...taken, ...targets]),
|
|
120
169
|
...(room.fileIds === undefined
|
|
121
170
|
? {}
|
|
122
171
|
: { fileIds: named(room.fileIds, [...taken, ...targets]) }),
|
|
172
|
+
...(room.created === undefined
|
|
173
|
+
? {}
|
|
174
|
+
: { created: named(room.created, [...taken, ...targets]) }),
|
|
123
175
|
changes: named(room.changes ?? {}, [...taken, ...targets]),
|
|
124
176
|
binaryFiles: named(room.binaryFiles ?? {}, targets),
|
|
125
177
|
...(opening && room.folders !== undefined ? { folders: room.folders } : {}),
|
|
@@ -136,18 +188,19 @@ export function createMemoryAdapter(options = {}) {
|
|
|
136
188
|
...(folderRemovals.length === 0 ? {} : { folderRemovals }),
|
|
137
189
|
};
|
|
138
190
|
}
|
|
139
|
-
function advancement(room, from, at) {
|
|
191
|
+
function advancement(room, from, at, whole = false) {
|
|
140
192
|
const current = room.documents ?? {};
|
|
141
193
|
const previous = from.documents ?? {};
|
|
142
194
|
const currentTargets = new Set(Object.keys(room.binaryFiles ?? {}));
|
|
143
195
|
const previousTargets = new Set(Object.keys(from.binaryFiles ?? {}));
|
|
144
196
|
const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
|
|
145
197
|
room.fileIds?.[path] !== from.fileIds?.[path] ||
|
|
198
|
+
room.created?.[path] !== from.created?.[path] ||
|
|
146
199
|
!sameChange(room.changes?.[path], from.changes?.[path]);
|
|
147
200
|
const changed = Object.keys(current)
|
|
148
201
|
.filter((path) => current[path] !== previous[path] || headMoved(path))
|
|
149
202
|
.sort();
|
|
150
|
-
const size = pageSize ?? changed.length;
|
|
203
|
+
const size = whole ? changed.length : (pageSize ?? changed.length);
|
|
151
204
|
const taken = changed.slice(at, at + size);
|
|
152
205
|
const next = at + taken.length;
|
|
153
206
|
const opening = at === 0;
|
|
@@ -163,10 +216,14 @@ export function createMemoryAdapter(options = {}) {
|
|
|
163
216
|
roomVersion: room.roomVersion,
|
|
164
217
|
...(models === undefined ? {} : { models }),
|
|
165
218
|
documents: named(current, taken),
|
|
219
|
+
facts: factsIn(room, taken),
|
|
166
220
|
revisions: named(room.revisions ?? {}, [...taken, ...targets]),
|
|
167
221
|
...(room.fileIds === undefined
|
|
168
222
|
? {}
|
|
169
223
|
: { fileIds: named(room.fileIds, [...taken, ...targets]) }),
|
|
224
|
+
...(room.created === undefined
|
|
225
|
+
? {}
|
|
226
|
+
: { created: named(room.created, [...taken, ...targets]) }),
|
|
170
227
|
changes: named(room.changes ?? {}, [...taken, ...targets]),
|
|
171
228
|
binaryFiles: named(room.binaryFiles ?? {}, targets),
|
|
172
229
|
...(opening ? foldersMoved(room, from) : {}),
|
|
@@ -179,6 +236,26 @@ export function createMemoryAdapter(options = {}) {
|
|
|
179
236
|
...(pageToken === undefined ? {} : { pageToken }),
|
|
180
237
|
};
|
|
181
238
|
}
|
|
239
|
+
function carry(locator) {
|
|
240
|
+
const at = carried.get(locator);
|
|
241
|
+
const current = rooms.find((entry) => entry.locator === locator);
|
|
242
|
+
if (at === undefined || current === undefined || current.roomVersion === at)
|
|
243
|
+
return;
|
|
244
|
+
const from = served.get(locator)?.get(at);
|
|
245
|
+
carried.set(locator, current.roomVersion);
|
|
246
|
+
if (from === undefined)
|
|
247
|
+
return;
|
|
248
|
+
const page = advancement(current, from, 0, true);
|
|
249
|
+
for (const observer of observers) {
|
|
250
|
+
observer({
|
|
251
|
+
kind: 'room-change',
|
|
252
|
+
locator,
|
|
253
|
+
from: at,
|
|
254
|
+
roomVersion: current.roomVersion,
|
|
255
|
+
read: async () => page,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
182
259
|
function pageOf(conversation, after) {
|
|
183
260
|
const messages = conversation.messages ?? [];
|
|
184
261
|
const first = typeof after === 'string' ? messages.findIndex((message) => message.position > after) : 0;
|
|
@@ -193,16 +270,13 @@ export function createMemoryAdapter(options = {}) {
|
|
|
193
270
|
: {}),
|
|
194
271
|
};
|
|
195
272
|
}
|
|
196
|
-
function historiesOf(
|
|
197
|
-
const asked = input?.conversations;
|
|
198
|
-
if (!Array.isArray(asked))
|
|
199
|
-
return { kind: 'rejected', code: 'invalid_request', fields: {}, retryable: false };
|
|
273
|
+
function historiesOf(request) {
|
|
200
274
|
const histories = [];
|
|
201
|
-
for (const entry of
|
|
202
|
-
const conversation =
|
|
275
|
+
for (const entry of request.conversations) {
|
|
276
|
+
const conversation = scripted.get(entry.conversation);
|
|
203
277
|
if (conversation === undefined)
|
|
204
278
|
continue;
|
|
205
|
-
const outcome = conversation.outcomes?.
|
|
279
|
+
const outcome = conversation.outcomes?.history;
|
|
206
280
|
if (outcome !== undefined)
|
|
207
281
|
return outcome;
|
|
208
282
|
histories.push(pageOf(conversation, entry.after));
|
|
@@ -213,15 +287,13 @@ export function createMemoryAdapter(options = {}) {
|
|
|
213
287
|
function conversationAction(request) {
|
|
214
288
|
const name = request.name;
|
|
215
289
|
const input = (request.input ?? {});
|
|
216
|
-
if (name === '
|
|
217
|
-
return historiesOf(request.input);
|
|
218
|
-
if (name === 'conversation.create') {
|
|
290
|
+
if (name === 'conversations/create') {
|
|
219
291
|
issued += 1;
|
|
220
292
|
const conversation = `conversation-${issued}`;
|
|
221
293
|
scripted.set(conversation, { conversation });
|
|
222
|
-
return { kind: 'action', result: { conversation } };
|
|
294
|
+
return { kind: 'action', result: { conversation_id: conversation } };
|
|
223
295
|
}
|
|
224
|
-
const named = typeof input.
|
|
296
|
+
const named = typeof input.conversation_id === 'string' ? input.conversation_id : '';
|
|
225
297
|
const conversation = scripted.get(named);
|
|
226
298
|
if (conversation === undefined) {
|
|
227
299
|
return {
|
|
@@ -234,34 +306,28 @@ export function createMemoryAdapter(options = {}) {
|
|
|
234
306
|
const outcome = conversation.outcomes?.[name];
|
|
235
307
|
if (outcome !== undefined)
|
|
236
308
|
return outcome;
|
|
237
|
-
if (name === '
|
|
309
|
+
if (name === 'conversations/send') {
|
|
238
310
|
const operation = typeof input.operation_id === 'string' ? input.operation_id : null;
|
|
239
311
|
const answered = operation === null ? undefined : sentTurns.get(operation);
|
|
240
312
|
if (answered !== undefined)
|
|
241
|
-
return { kind: 'action', result: {
|
|
313
|
+
return { kind: 'action', result: { message_id: answered } };
|
|
242
314
|
issued += 1;
|
|
243
315
|
const turn = `turn-${issued}`;
|
|
244
|
-
unsealed.set(turn, named);
|
|
245
316
|
if (operation !== null)
|
|
246
317
|
sentTurns.set(operation, turn);
|
|
247
|
-
return { kind: 'action', result: { turn } };
|
|
318
|
+
return { kind: 'action', result: { message_id: turn } };
|
|
248
319
|
}
|
|
249
|
-
if (name === '
|
|
250
|
-
const turn = typeof input.turn === 'string' ? input.turn : '';
|
|
251
|
-
if (sealed.has(turn) || !unsealed.has(turn)) {
|
|
252
|
-
return { kind: 'rejected', code: 'turn-sealed', fields: { turn }, retryable: false };
|
|
253
|
-
}
|
|
254
|
-
unsealed.delete(turn);
|
|
255
|
-
return { kind: 'action', result: { turn, cancelled: true } };
|
|
256
|
-
}
|
|
257
|
-
if (name === 'conversation.delete')
|
|
320
|
+
if (name === 'conversations/delete')
|
|
258
321
|
scripted.delete(named);
|
|
259
|
-
return { kind: 'action', result: {
|
|
322
|
+
return { kind: 'action', result: { conversation_id: named } };
|
|
260
323
|
}
|
|
261
324
|
function announceList() {
|
|
262
|
-
const entries = [...scripted.values()].flatMap(({ conversation, listed }) => listed === undefined
|
|
263
|
-
|
|
264
|
-
|
|
325
|
+
const entries = [...scripted.values()].flatMap(({ conversation, listed, messages = [] }) => listed === undefined
|
|
326
|
+
? []
|
|
327
|
+
: [{ conversation, ...listed, newest: messages.at(-1)?.position ?? null }]);
|
|
328
|
+
for (const listener of listeners) {
|
|
329
|
+
listener({ kind: 'list', entries, whole: true, more: false, cursor: null });
|
|
330
|
+
}
|
|
265
331
|
}
|
|
266
332
|
function discovery() {
|
|
267
333
|
return {
|
|
@@ -273,9 +339,42 @@ export function createMemoryAdapter(options = {}) {
|
|
|
273
339
|
...(options.member === undefined ? {} : { member: options.member }),
|
|
274
340
|
};
|
|
275
341
|
}
|
|
342
|
+
function discovered() {
|
|
343
|
+
return resolveScript(scripts.discover, discovery, undefined).then((answer) => {
|
|
344
|
+
if (answer.kind === 'discovery')
|
|
345
|
+
for (const room of answer.rooms)
|
|
346
|
+
note(room.locator, room);
|
|
347
|
+
return answer;
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
function opened(notify) {
|
|
351
|
+
const opening = ++openings;
|
|
352
|
+
notify({ kind: 'opened' });
|
|
353
|
+
void discovered()
|
|
354
|
+
.catch(() => ({ kind: 'transport-uncertainty' }))
|
|
355
|
+
.then((answer) => {
|
|
356
|
+
if (opening !== openings)
|
|
357
|
+
return;
|
|
358
|
+
if (answer.kind !== 'discovery') {
|
|
359
|
+
openings += 1;
|
|
360
|
+
carried.clear();
|
|
361
|
+
const revoked = answer.kind === 'revoked-authorization';
|
|
362
|
+
notify({ kind: 'closed', revoked, lost: !revoked, authorityChanged: false });
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
declaredRooms.clear();
|
|
366
|
+
for (const room of answer.rooms)
|
|
367
|
+
declaredRooms.add(room.locator);
|
|
368
|
+
notify({ kind: 'discovered', discovery: answer });
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
function emitAll(event) {
|
|
372
|
+
for (const observer of observers)
|
|
373
|
+
observer(event);
|
|
374
|
+
}
|
|
276
375
|
return {
|
|
277
|
-
...(options.exhaustiveDiscovery === undefined ? {} : { exhaustiveDiscovery: true }),
|
|
278
376
|
...(options.roomTypes === undefined ? {} : { roomTypes: options.roomTypes }),
|
|
377
|
+
...(options.typedPaths === undefined ? {} : { typedPaths: options.typedPaths }),
|
|
279
378
|
setRooms(next) {
|
|
280
379
|
rooms = [...next];
|
|
281
380
|
retain(rooms);
|
|
@@ -284,33 +383,37 @@ export function createMemoryAdapter(options = {}) {
|
|
|
284
383
|
scriptConversations(next);
|
|
285
384
|
},
|
|
286
385
|
open() {
|
|
386
|
+
carried.clear();
|
|
287
387
|
announceList();
|
|
288
|
-
|
|
289
|
-
observer({ kind: 'opened' });
|
|
388
|
+
opened(emitAll);
|
|
290
389
|
},
|
|
291
|
-
close({ revoked = false, lost = !revoked } = {}) {
|
|
292
|
-
|
|
293
|
-
|
|
390
|
+
close({ revoked = false, lost = !revoked, authorityChanged = false } = {}) {
|
|
391
|
+
openings += 1;
|
|
392
|
+
carried.clear();
|
|
393
|
+
emitAll({ kind: 'closed', revoked, lost, authorityChanged });
|
|
294
394
|
},
|
|
295
395
|
expire(locators) {
|
|
296
396
|
expiring = [...locators];
|
|
297
397
|
},
|
|
298
|
-
notifyRoomVersion({ locator
|
|
299
|
-
|
|
300
|
-
observer({ kind: 'room-version', locator, roomVersion });
|
|
398
|
+
notifyRoomVersion({ locator }) {
|
|
399
|
+
carry(locator);
|
|
301
400
|
},
|
|
302
|
-
notifyAuthorityChanged(
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
401
|
+
notifyAuthorityChanged(locators) {
|
|
402
|
+
const named = new Set(locators ?? [...declaredRooms, ...rooms.map((room) => room.locator)]);
|
|
403
|
+
const listed = rooms.filter((room) => named.has(room.locator));
|
|
404
|
+
const left = [...named].filter((locator) => !listed.some((room) => room.locator === locator));
|
|
405
|
+
for (const room of listed)
|
|
406
|
+
declaredRooms.add(room.locator);
|
|
407
|
+
for (const locator of left)
|
|
408
|
+
declaredRooms.delete(locator);
|
|
409
|
+
emitAll({
|
|
410
|
+
kind: 'authority-changed',
|
|
411
|
+
rooms: listed.map(declared),
|
|
412
|
+
left,
|
|
413
|
+
...(options.member === undefined ? {} : { member: options.member }),
|
|
414
|
+
});
|
|
308
415
|
},
|
|
309
416
|
notifyConversation(event) {
|
|
310
|
-
if (event.kind === 'accepted-message') {
|
|
311
|
-
sealed.add(event.message.turn);
|
|
312
|
-
unsealed.delete(event.message.turn);
|
|
313
|
-
}
|
|
314
417
|
for (const listener of listeners)
|
|
315
418
|
listener(event);
|
|
316
419
|
},
|
|
@@ -319,21 +422,31 @@ export function createMemoryAdapter(options = {}) {
|
|
|
319
422
|
observer(mode);
|
|
320
423
|
},
|
|
321
424
|
heldRooms() {
|
|
322
|
-
return
|
|
425
|
+
return [...carried.keys()].sort();
|
|
323
426
|
},
|
|
324
427
|
replicatedConversations() {
|
|
325
428
|
return replicated;
|
|
326
429
|
},
|
|
430
|
+
heldConversationCursor() {
|
|
431
|
+
return heldCursor;
|
|
432
|
+
},
|
|
327
433
|
conversations: {
|
|
328
434
|
replicate(next) {
|
|
329
435
|
replicated = [...next];
|
|
330
436
|
},
|
|
437
|
+
hold(cursor) {
|
|
438
|
+
heldCursor = cursor;
|
|
439
|
+
},
|
|
331
440
|
observe(notify) {
|
|
332
441
|
listeners.add(notify);
|
|
333
442
|
return () => {
|
|
334
443
|
listeners.delete(notify);
|
|
335
444
|
};
|
|
336
445
|
},
|
|
446
|
+
history: (request) => Promise.resolve(historiesOf(request)),
|
|
447
|
+
...(options.agents === undefined
|
|
448
|
+
? {}
|
|
449
|
+
: { agents: () => Promise.resolve(structuredClone(options.agents)) }),
|
|
337
450
|
},
|
|
338
451
|
serviceMode: {
|
|
339
452
|
observe(notify) {
|
|
@@ -345,44 +458,46 @@ export function createMemoryAdapter(options = {}) {
|
|
|
345
458
|
},
|
|
346
459
|
roomStream: {
|
|
347
460
|
hold(asked) {
|
|
348
|
-
|
|
349
|
-
const
|
|
350
|
-
expiring = [];
|
|
351
|
-
const moved = asked.flatMap((room) => {
|
|
461
|
+
const named = asked.map((room) => room.locator);
|
|
462
|
+
const unknown = asked.flatMap((room) => {
|
|
352
463
|
const current = rooms.find((entry) => entry.locator === room.locator);
|
|
464
|
+
const version = room.roomVersion;
|
|
353
465
|
return current === undefined ||
|
|
354
|
-
|
|
355
|
-
|
|
466
|
+
(version !== null &&
|
|
467
|
+
(current.roomVersion === version || served.get(room.locator)?.has(version) === true))
|
|
356
468
|
? []
|
|
357
|
-
: [
|
|
469
|
+
: [room.locator];
|
|
358
470
|
});
|
|
471
|
+
const expired = [
|
|
472
|
+
...new Set([...expiring.filter((locator) => named.includes(locator)), ...unknown]),
|
|
473
|
+
];
|
|
474
|
+
expiring = expiring.filter((locator) => !named.includes(locator));
|
|
359
475
|
queueMicrotask(() => {
|
|
360
|
-
for (const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
476
|
+
for (const room of asked) {
|
|
477
|
+
if (expired.includes(room.locator) || room.roomVersion === null)
|
|
478
|
+
carried.delete(room.locator);
|
|
479
|
+
else {
|
|
480
|
+
carried.set(room.locator, room.roomVersion);
|
|
481
|
+
carry(room.locator);
|
|
482
|
+
}
|
|
364
483
|
}
|
|
484
|
+
emitAll({ kind: 'caught-up', expired });
|
|
365
485
|
});
|
|
366
486
|
},
|
|
367
|
-
reopen() {
|
|
368
|
-
queueMicrotask(() => {
|
|
369
|
-
for (const observer of observers) {
|
|
370
|
-
observer({ kind: 'closed', revoked: false, lost: false });
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
},
|
|
374
|
-
published() { },
|
|
375
487
|
observe(notify) {
|
|
376
488
|
observers.add(notify);
|
|
377
489
|
queueMicrotask(() => {
|
|
378
490
|
if (!observers.has(notify))
|
|
379
491
|
return;
|
|
380
492
|
if (options.unopened === true) {
|
|
381
|
-
notify({ kind: 'closed', revoked: false, lost: true });
|
|
493
|
+
notify({ kind: 'closed', revoked: false, lost: true, authorityChanged: false });
|
|
382
494
|
return;
|
|
383
495
|
}
|
|
384
496
|
announceList();
|
|
385
|
-
|
|
497
|
+
opened((event) => {
|
|
498
|
+
if (observers.has(notify))
|
|
499
|
+
notify(event);
|
|
500
|
+
});
|
|
386
501
|
});
|
|
387
502
|
return () => {
|
|
388
503
|
observers.delete(notify);
|
|
@@ -399,12 +514,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
399
514
|
return resolveScript(scripts.authorize, () => ({}), undefined);
|
|
400
515
|
},
|
|
401
516
|
async discover(_authorization) {
|
|
402
|
-
return
|
|
403
|
-
if (answer.kind === 'discovery')
|
|
404
|
-
for (const room of answer.rooms)
|
|
405
|
-
note(room.locator, room);
|
|
406
|
-
return answer;
|
|
407
|
-
});
|
|
517
|
+
return discovered();
|
|
408
518
|
},
|
|
409
519
|
reached,
|
|
410
520
|
follows(locator, roomVersion, next) {
|
|
@@ -486,18 +596,39 @@ export function createMemoryAdapter(options = {}) {
|
|
|
486
596
|
const room = rooms.find((entry) => entry.locator === request.locator);
|
|
487
597
|
if (room === undefined)
|
|
488
598
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
489
|
-
const blob = room
|
|
599
|
+
const blob = heldBlob(room, request.path);
|
|
490
600
|
return blob === undefined
|
|
491
601
|
? { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false }
|
|
492
602
|
: { kind: 'binary', body: blob.stream(), mediaType: blob.type };
|
|
493
603
|
}, request);
|
|
494
604
|
},
|
|
495
605
|
async link(_authorization, request) {
|
|
496
|
-
return resolveScript(scripts.link, () =>
|
|
606
|
+
return resolveScript(scripts.link, () => {
|
|
607
|
+
const room = rooms.find((entry) => entry.locator === request.locator);
|
|
608
|
+
if (room === undefined)
|
|
609
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
610
|
+
const blob = heldBlob(room, request.path);
|
|
611
|
+
if (blob === undefined) {
|
|
612
|
+
return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
|
|
613
|
+
}
|
|
614
|
+
const url = linked.get(blob) ?? URL.createObjectURL(blob);
|
|
615
|
+
linked.set(blob, url);
|
|
616
|
+
return { kind: 'link', url, name: lastName(request.path), mediaType: blob.type };
|
|
617
|
+
}, request);
|
|
618
|
+
},
|
|
619
|
+
async attach(_authorization, request) {
|
|
620
|
+
return resolveScript(scripts.attach, () => {
|
|
621
|
+
const room = rooms.find((entry) => entry.locator === request.locator);
|
|
622
|
+
if (room === undefined)
|
|
623
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
624
|
+
const path = freePath(room, request.name);
|
|
625
|
+
attached.set(`${room.locator}\u0000${path}`, request.blob);
|
|
626
|
+
return { kind: 'attached', path, revision: `attached-${attached.size}` };
|
|
627
|
+
}, request);
|
|
497
628
|
},
|
|
498
629
|
async action(_authorization, request) {
|
|
499
630
|
return resolveScript(scripts.action, () => {
|
|
500
|
-
if (request.name.startsWith('
|
|
631
|
+
if (request.name.startsWith('conversations/'))
|
|
501
632
|
return conversationAction(request);
|
|
502
633
|
return { kind: 'rejected', code: 'unscripted-action', fields: {}, retryable: false };
|
|
503
634
|
}, request).then((answer) => {
|
package/dist/messages.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { AcceptedMessage } from './adapter.js';
|
|
2
|
+
import type { JobMarker } from './job.js';
|
|
2
3
|
import type { Connection } from './tables.js';
|
|
3
4
|
export declare const MESSAGE_TABLES: readonly string[];
|
|
5
|
+
export declare const ROWS = "WITH chosen AS (\n SELECT listed.value AS conversation,\n (SELECT id FROM conversation_messages WHERE conversation = listed.value AND json_extract(message, '$.role') = 'assistant' ORDER BY position DESC, identity DESC LIMIT 1) AS answer,\n (SELECT id FROM conversation_messages WHERE conversation = listed.value AND text <> '' ORDER BY position DESC, identity DESC LIMIT 1) AS said,\n (SELECT id FROM conversation_messages WHERE conversation = listed.value AND json_extract(message, '$.role') = 'house' ORDER BY position, identity LIMIT 1) AS opened,\n (SELECT id FROM conversation_messages WHERE conversation = listed.value AND json_extract(message, '$.role') = 'house' AND json_extract(message, '$.waiting') = 1 ORDER BY position, identity LIMIT 1) AS asking\n FROM json_each(?) AS listed\n )\n SELECT chosen.conversation AS conversation,\n substr(said.text, 1, 512) AS said_text,\n json_extract(said.message, '$.role') AS said_role,\n json_extract(said.message, '$.accepted_at') AS said_at,\n substr(json_extract(answer.message, '$.failure'), 1, 512) AS failure,\n json_extract(opened.message, '$.source') AS opened_source,\n json_extract(opened.message, '$.sender') AS opened_sender,\n asking.identity AS asking_identity,\n substr(asking.text, 1, 512) AS asking_text,\n json_extract(asking.message, '$.accepted_at') AS asking_at,\n json_extract(asking.message, '$.source') AS asking_source,\n json_extract(asking.message, '$.sender') AS asking_sender\n FROM chosen\n LEFT JOIN conversation_messages said ON said.id = chosen.said\n LEFT JOIN conversation_messages answer ON answer.id = chosen.answer\n LEFT JOIN conversation_messages opened ON opened.id = chosen.opened\n LEFT JOIN conversation_messages asking ON asking.id = chosen.asking";
|
|
6
|
+
export declare const JOB_MARKERS = "SELECT json_extract(part.value, '$.text') AS said,\n json_extract(message, '$.accepted_at') AS at\n FROM conversation_messages, json_each(message, '$.parts') AS part\n WHERE conversation = ? AND instr(message, '\"marker\":\"job\"') > 0\n AND json_extract(part.value, '$.type') = 'marker'\n AND json_extract(part.value, '$.marker') = 'job'\n ORDER BY position, identity, part.key";
|
|
4
7
|
export type HeldConversation = {
|
|
5
8
|
readonly conversation: string;
|
|
6
9
|
readonly read: string | null | undefined;
|
|
@@ -10,6 +13,25 @@ export type MessageWindow = {
|
|
|
10
13
|
readonly messages: AcceptedMessage[];
|
|
11
14
|
readonly more: boolean;
|
|
12
15
|
};
|
|
16
|
+
export type HeldSource = {
|
|
17
|
+
readonly source: unknown;
|
|
18
|
+
readonly sender: string | null;
|
|
19
|
+
};
|
|
20
|
+
export type HeldRow = {
|
|
21
|
+
readonly conversation: string;
|
|
22
|
+
readonly said: {
|
|
23
|
+
readonly text: string;
|
|
24
|
+
readonly role: string | null;
|
|
25
|
+
readonly at: string | null;
|
|
26
|
+
} | null;
|
|
27
|
+
readonly failure: string | null;
|
|
28
|
+
readonly opened: HeldSource | null;
|
|
29
|
+
readonly asking: (HeldSource & {
|
|
30
|
+
readonly identity: string;
|
|
31
|
+
readonly text: string;
|
|
32
|
+
readonly at: string | null;
|
|
33
|
+
}) | null;
|
|
34
|
+
};
|
|
13
35
|
export type ConversationWrite = {
|
|
14
36
|
readonly conversation: string;
|
|
15
37
|
readonly messages: readonly AcceptedMessage[];
|
|
@@ -18,10 +40,12 @@ export type ConversationWrite = {
|
|
|
18
40
|
readonly partial: boolean;
|
|
19
41
|
};
|
|
20
42
|
};
|
|
21
|
-
export declare function heldConversations(connection: Connection): HeldConversation[];
|
|
43
|
+
export declare function heldConversations(connection: Connection, conversations: readonly string[] | null): HeldConversation[];
|
|
22
44
|
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): MessageWindow;
|
|
24
|
-
export declare function messageCount(connection: Connection, conversation: string): number;
|
|
45
|
+
export declare function messageWindow(connection: Connection, conversation: string, limit: number, before: readonly [string, string] | null, phrase: string | null): MessageWindow;
|
|
46
|
+
export declare function messageCount(connection: Connection, conversation: string, phrase: string | null): number;
|
|
47
|
+
export declare function conversationRows(connection: Connection, conversations: readonly string[]): HeldRow[];
|
|
48
|
+
export declare function jobMarkers(connection: Connection, conversation: string): JobMarker[];
|
|
25
49
|
export declare function turnArrived(connection: Connection, conversation: string, turn: string): boolean;
|
|
26
50
|
export declare function droppedMessages(connection: Connection, conversations: readonly string[]): void;
|
|
27
51
|
export declare function forgottenMessages(connection: Connection): void;
|
package/dist/messages.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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"}
|