@agentshouse/mdruntime-adapter 0.1.0-cd0511bd2d033 → 0.1.0-cd24cf2286fd6
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/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +58 -70
- package/dist/chunks.d.ts +38 -0
- package/dist/chunks.d.ts.map +1 -0
- package/dist/chunks.js +247 -0
- package/dist/discovery.d.ts +1 -2
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +2 -3
- package/dist/house-model.d.ts +35 -113
- package/dist/house-model.d.ts.map +1 -1
- package/dist/house-model.js +23 -55
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/model.d.ts +5 -7
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +30 -18
- package/dist/read.d.ts +4 -8
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +17 -140
- package/dist/room-types.d.ts.map +1 -1
- package/dist/room-types.js +0 -2
- package/dist/site.d.ts.map +1 -1
- package/dist/site.js +28 -38
- package/dist/space-schema.d.ts +7 -0
- package/dist/space-schema.d.ts.map +1 -0
- package/dist/space-schema.js +18 -0
- package/dist/stream.d.ts +6 -4
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +81 -14
- package/dist/transport.d.ts +3 -7
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +1 -1
- package/package.json +2 -2
- package/dist/part.d.ts +0 -14
- package/dist/part.d.ts.map +0 -1
- package/dist/part.js +0 -90
- package/dist/room-stream.d.ts +0 -19
- package/dist/room-stream.d.ts.map +0 -1
- package/dist/room-stream.js +0 -57
package/dist/read.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { readPosition, roomVersion } from './version.js';
|
|
1
|
+
import { patching, ROW_WEIGHT, } from '@agentshouse/mdruntime';
|
|
2
|
+
import { roomVersion } from './version.js';
|
|
4
3
|
const REVISION_FILE = /^fr_([0-9a-z]+)\.[0-9a-z]+\.[0-9a-z]$/u;
|
|
5
4
|
function fileOf(revision) {
|
|
6
5
|
return REVISION_FILE.exec(revision)?.[1];
|
|
@@ -144,7 +143,10 @@ function binaried(binary) {
|
|
|
144
143
|
export function carriedFacts(held) {
|
|
145
144
|
return held.facts === undefined ? {} : { facts: held.facts };
|
|
146
145
|
}
|
|
147
|
-
function
|
|
146
|
+
function carriedSpace(held) {
|
|
147
|
+
return typeof held.space === 'string' ? { space: held.space } : {};
|
|
148
|
+
}
|
|
149
|
+
export function parseFile(value, mode) {
|
|
148
150
|
if (typeof value !== 'object' || value === null)
|
|
149
151
|
return null;
|
|
150
152
|
const file = value;
|
|
@@ -176,150 +178,18 @@ function parseFile(value, mode) {
|
|
|
176
178
|
...headed(head),
|
|
177
179
|
...binaried(binary),
|
|
178
180
|
...carriedFacts(file),
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
function parseModels(value, mode) {
|
|
182
|
-
if (!Array.isArray(value))
|
|
183
|
-
return null;
|
|
184
|
-
const files = [];
|
|
185
|
-
const contents = [];
|
|
186
|
-
for (const entry of value) {
|
|
187
|
-
const file = parseFile(entry, mode);
|
|
188
|
-
const { content } = entry;
|
|
189
|
-
if (file === null || typeof content !== 'string')
|
|
190
|
-
return null;
|
|
191
|
-
files.push(file);
|
|
192
|
-
contents.push({ path: file.path, content });
|
|
193
|
-
}
|
|
194
|
-
return { files, contents };
|
|
195
|
-
}
|
|
196
|
-
function parseRoomHead(value, mode) {
|
|
197
|
-
if (typeof value !== 'object' || value === null)
|
|
198
|
-
return null;
|
|
199
|
-
const held = value;
|
|
200
|
-
if (typeof held.manifest !== 'object' || held.manifest === null)
|
|
201
|
-
return null;
|
|
202
|
-
const models = parseModels(held.models, mode);
|
|
203
|
-
if (models === null)
|
|
204
|
-
return null;
|
|
205
|
-
const manifest = held.manifest;
|
|
206
|
-
if (manifest.scope !== 'room')
|
|
207
|
-
return null;
|
|
208
|
-
const at = readPosition(manifest);
|
|
209
|
-
if (typeof manifest.anchor !== 'string' || manifest.anchor.length === 0 || at === null)
|
|
210
|
-
return null;
|
|
211
|
-
if (typeof manifest.room_handle !== 'string' || manifest.room_handle.length === 0)
|
|
212
|
-
return null;
|
|
213
|
-
return { anchor: manifest.anchor, ...at, models };
|
|
214
|
-
}
|
|
215
|
-
export async function roomHead(payload, mode) {
|
|
216
|
-
let text = '';
|
|
217
|
-
try {
|
|
218
|
-
for await (const chunk of gunzipped(payload))
|
|
219
|
-
text += chunk;
|
|
220
|
-
return text.endsWith('\n') && text.indexOf('\n') === text.length - 1
|
|
221
|
-
? parseRoomHead(JSON.parse(text), mode)
|
|
222
|
-
: null;
|
|
223
|
-
}
|
|
224
|
-
catch {
|
|
225
|
-
return null;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
export function manifested(room, pageToken, models) {
|
|
229
|
-
return {
|
|
230
|
-
kind: 'bootstrap',
|
|
231
|
-
roomVersion: roomVersion(room),
|
|
232
|
-
documents: {},
|
|
233
|
-
facts: {},
|
|
234
|
-
revisions: {},
|
|
235
|
-
changes: {},
|
|
236
|
-
binaryFiles: {},
|
|
237
|
-
pageToken,
|
|
238
|
-
...(models === undefined ? {} : { models }),
|
|
181
|
+
...carriedSpace(file),
|
|
239
182
|
};
|
|
240
183
|
}
|
|
241
184
|
export function modelScope(room) {
|
|
242
|
-
return { ...emptyScope(room), files: room.models.files, contents: room.models.contents };
|
|
243
|
-
}
|
|
244
|
-
export function emptyScope(room) {
|
|
245
185
|
return {
|
|
246
186
|
anchor: room.anchor,
|
|
247
187
|
position: room.position,
|
|
248
188
|
logEpoch: room.logEpoch,
|
|
249
|
-
files:
|
|
250
|
-
contents:
|
|
189
|
+
files: room.models.files,
|
|
190
|
+
contents: room.models.contents,
|
|
251
191
|
};
|
|
252
192
|
}
|
|
253
|
-
function partLine(line, mode, read) {
|
|
254
|
-
if (read.ended)
|
|
255
|
-
return false;
|
|
256
|
-
let entry;
|
|
257
|
-
try {
|
|
258
|
-
entry = JSON.parse(line);
|
|
259
|
-
}
|
|
260
|
-
catch {
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
if (endLine(entry)) {
|
|
264
|
-
read.ended = true;
|
|
265
|
-
return true;
|
|
266
|
-
}
|
|
267
|
-
if (folderLine(entry)) {
|
|
268
|
-
read.folders.push(entry.folder);
|
|
269
|
-
return true;
|
|
270
|
-
}
|
|
271
|
-
const file = parseFile(entry, mode);
|
|
272
|
-
if (file === null)
|
|
273
|
-
return false;
|
|
274
|
-
read.files.push(file);
|
|
275
|
-
const { content } = entry;
|
|
276
|
-
if (typeof content === 'string')
|
|
277
|
-
read.contents.push({ path: file.path, content });
|
|
278
|
-
else if (content !== undefined)
|
|
279
|
-
return false;
|
|
280
|
-
return true;
|
|
281
|
-
}
|
|
282
|
-
async function partRead(chunks, mode) {
|
|
283
|
-
const read = { files: [], contents: [], folders: [], ended: false };
|
|
284
|
-
const pace = paced();
|
|
285
|
-
const unfinished = [];
|
|
286
|
-
for (let chunk = await chunks.read(); chunk.done !== true; chunk = await chunks.read()) {
|
|
287
|
-
const text = chunk.value;
|
|
288
|
-
let start = 0;
|
|
289
|
-
for (let end = text.indexOf('\n'); end !== -1; end = text.indexOf('\n', start)) {
|
|
290
|
-
const piece = text.slice(start, end);
|
|
291
|
-
const line = unfinished.length === 0 ? piece : unfinished.splice(0).join('') + piece;
|
|
292
|
-
if (!partLine(line, mode, read)) {
|
|
293
|
-
await chunks.cancel();
|
|
294
|
-
return null;
|
|
295
|
-
}
|
|
296
|
-
start = end + 1;
|
|
297
|
-
const due = pace(line.length + ROW_WEIGHT);
|
|
298
|
-
if (due instanceof Promise)
|
|
299
|
-
await due;
|
|
300
|
-
}
|
|
301
|
-
if (start < text.length)
|
|
302
|
-
unfinished.push(text.slice(start));
|
|
303
|
-
}
|
|
304
|
-
return unfinished.length === 0 ? read : null;
|
|
305
|
-
}
|
|
306
|
-
function endLine(entry) {
|
|
307
|
-
if (typeof entry !== 'object' || entry === null || !('end' in entry))
|
|
308
|
-
return false;
|
|
309
|
-
return entry.end === true && Object.keys(entry).length === 1;
|
|
310
|
-
}
|
|
311
|
-
function folderLine(entry) {
|
|
312
|
-
if (typeof entry !== 'object' || entry === null || !('folder' in entry))
|
|
313
|
-
return false;
|
|
314
|
-
return typeof entry.folder === 'string' && Object.keys(entry).length === 1;
|
|
315
|
-
}
|
|
316
|
-
export async function housePart(room, payload, mode) {
|
|
317
|
-
const read = await partRead(gunzipped(payload).getReader(), mode).catch(() => null);
|
|
318
|
-
if (read === null)
|
|
319
|
-
return { kind: 'transport-uncertainty' };
|
|
320
|
-
const { ended, ...scope } = read;
|
|
321
|
-
return { scope: { ...emptyScope(room), ...scope }, ended };
|
|
322
|
-
}
|
|
323
193
|
export function* bootstrapping(scope) {
|
|
324
194
|
const contents = new Map();
|
|
325
195
|
for (const entry of scope.contents) {
|
|
@@ -329,6 +199,8 @@ export function* bootstrapping(scope) {
|
|
|
329
199
|
const answer = answering();
|
|
330
200
|
for (const file of scope.files) {
|
|
331
201
|
yield ROW_WEIGHT;
|
|
202
|
+
if (file.space !== undefined)
|
|
203
|
+
continue;
|
|
332
204
|
if (file.head !== undefined)
|
|
333
205
|
answer.changes.set(file.path, file.head);
|
|
334
206
|
const content = contents.get(file.path);
|
|
@@ -353,5 +225,10 @@ export function schemaOf(scope, schema) {
|
|
|
353
225
|
const content = scope.contents.find((entry) => entry.path === schema);
|
|
354
226
|
return content === undefined
|
|
355
227
|
? null
|
|
356
|
-
: {
|
|
228
|
+
: {
|
|
229
|
+
schema: content.content,
|
|
230
|
+
version: file.version,
|
|
231
|
+
revision: file.revision ?? null,
|
|
232
|
+
...(file.space === undefined ? {} : { space: file.space }),
|
|
233
|
+
};
|
|
357
234
|
}
|
package/dist/room-types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"room-types.d.ts","sourceRoot":"","sources":["../src/room-types.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,YAC9B,cAAc,EACd,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,WAAW,EACX,OAAO,EACP,QAAQ,CACA,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,eAAO,MAAM,SAAS,SAAS,CAAC;AAEhC,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD,eAAO,MAAM,yBAAyB,UAAiC,CAAC;AAyBxE,eAAO,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"room-types.d.ts","sourceRoot":"","sources":["../src/room-types.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,YAC9B,cAAc,EACd,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,WAAW,EACX,OAAO,EACP,QAAQ,CACA,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,eAAO,MAAM,SAAS,SAAS,CAAC;AAEhC,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD,eAAO,MAAM,yBAAyB,UAAiC,CAAC;AAyBxE,eAAO,MAAM,gBAAgB,QA2FjB,CAAC"}
|
package/dist/room-types.js
CHANGED
|
@@ -58,8 +58,6 @@ export const HOUSE_ROOM_TYPES = [
|
|
|
58
58
|
` username: ${IDENTITY}`,
|
|
59
59
|
' sent_at: { type: string, format: date-time }',
|
|
60
60
|
` channel_message: ${IDENTITY}`,
|
|
61
|
-
' state: { enum: [sending, sent, failed] }',
|
|
62
|
-
' reason: { type: string }',
|
|
63
61
|
' labelled: { const: true }',
|
|
64
62
|
' reactions:',
|
|
65
63
|
' type: array',
|
package/dist/site.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAQR,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAQR,MAAM,wBAAwB,CAAC;AAehC,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAuBxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAiK1F"}
|
package/dist/site.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { stepped } from '@agentshouse/mdruntime';
|
|
2
1
|
import { actionOutcome } from './actions.js';
|
|
2
|
+
import { chunkedHead, chunkPart, siteChunkList } from './chunks.js';
|
|
3
3
|
import { mapDiscovery, parseSiteDiscovery, siteCapabilities, siteTracked, } from './discovery.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { classifyDoor, discoveryFailure } from './refusal.js';
|
|
4
|
+
import { spaceSchemas } from './space-schema.js';
|
|
5
|
+
import { discoveryFailure } from './refusal.js';
|
|
7
6
|
import { HOUSE_TYPED_PATHS } from './house-model.js';
|
|
8
7
|
import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
|
|
9
8
|
import { houseNotifications } from './stream.js';
|
|
10
9
|
import { houseSiteRoute, SITE_DOOR_SUBMIT, SITE_FILES, SITE_SUBMISSION, } from './transport.js';
|
|
11
|
-
import { followsVersion,
|
|
10
|
+
import { followsVersion, reachedVersion, roomVersion } from './version.js';
|
|
12
11
|
const UNCERTAIN = { kind: 'transport-uncertainty' };
|
|
13
12
|
function unfound() {
|
|
14
13
|
return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
|
|
@@ -19,50 +18,47 @@ function siteRoom(tracked) {
|
|
|
19
18
|
locator: tracked.locator,
|
|
20
19
|
handle: tracked.handle,
|
|
21
20
|
roomVersion: roomVersion(tracked),
|
|
22
|
-
operations: { write: [],
|
|
21
|
+
operations: { write: [], erase: [] },
|
|
23
22
|
replica: { selection: tracked.locator, admission: 'admitted', offline: 'open' },
|
|
24
23
|
providerOwnedPaths: [],
|
|
25
24
|
};
|
|
26
25
|
}
|
|
27
26
|
export function createSiteAdapter(transport, snapshot = false) {
|
|
27
|
+
const spaces = spaceSchemas();
|
|
28
28
|
const notifications = houseNotifications(transport, 'site', {
|
|
29
29
|
opened: async () => {
|
|
30
30
|
const found = await discovered();
|
|
31
31
|
return found.kind === 'discovery' ? found : null;
|
|
32
32
|
},
|
|
33
33
|
changed: () => null,
|
|
34
|
-
});
|
|
34
|
+
}, spaces);
|
|
35
35
|
const tracked = new Map();
|
|
36
|
-
const
|
|
37
|
-
const rooms = roomStreams('site');
|
|
36
|
+
const chunked = new Map();
|
|
38
37
|
function fileRoute(request) {
|
|
39
38
|
const entry = tracked.get(request.locator);
|
|
40
39
|
if (entry === undefined)
|
|
41
40
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
42
41
|
return `${SITE_FILES}${entry.authority}/${encodeURIComponent(request.revision)}/${encodeURIComponent(request.path)}`;
|
|
43
42
|
}
|
|
44
|
-
async function
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
48
|
-
return
|
|
49
|
-
const head = await
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
read.set(entry.locator, at.position);
|
|
43
|
+
async function listedRoom(entry) {
|
|
44
|
+
const past = chunked.get(entry.locator)?.position;
|
|
45
|
+
const listed = siteChunkList(await transport.read(`${houseSiteRoute('chunks')}/${entry.authority}${past === undefined ? '' : `?expired=${past}`}`), entry.locator);
|
|
46
|
+
if ('kind' in listed)
|
|
47
|
+
return listed;
|
|
48
|
+
const head = await chunkedHead(listed, entry, spaces);
|
|
49
|
+
if (head.kind === 'bootstrap')
|
|
50
|
+
chunked.set(entry.locator, listed);
|
|
53
51
|
return head;
|
|
54
52
|
}
|
|
55
|
-
async function
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
bytes: part.bytes,
|
|
65
|
-
};
|
|
53
|
+
async function chunkPage(entry, id, arriving) {
|
|
54
|
+
const room = chunked.get(entry.locator);
|
|
55
|
+
const address = room?.chunks.get(id);
|
|
56
|
+
if (room === undefined || address === undefined)
|
|
57
|
+
return UNCERTAIN;
|
|
58
|
+
const read = await transport.download(address.url);
|
|
59
|
+
if (read.status !== 200)
|
|
60
|
+
return UNCERTAIN;
|
|
61
|
+
return chunkPart(read.body, room, id, arriving);
|
|
66
62
|
}
|
|
67
63
|
async function discovered() {
|
|
68
64
|
const answer = await transport.read(houseSiteRoute('discover'));
|
|
@@ -92,8 +88,8 @@ export function createSiteAdapter(transport, snapshot = false) {
|
|
|
92
88
|
if (entry === undefined)
|
|
93
89
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
94
90
|
return request.pageToken === undefined
|
|
95
|
-
?
|
|
96
|
-
:
|
|
91
|
+
? listedRoom(entry)
|
|
92
|
+
: chunkPage(entry, request.pageToken, request.arriving);
|
|
97
93
|
},
|
|
98
94
|
...(snapshot
|
|
99
95
|
? {
|
|
@@ -162,13 +158,7 @@ export function createSiteAdapter(transport, snapshot = false) {
|
|
|
162
158
|
roomStream: snapshot
|
|
163
159
|
? undefined
|
|
164
160
|
: {
|
|
165
|
-
hold
|
|
166
|
-
notifications.send(rooms.flatMap((room) => {
|
|
167
|
-
const entry = tracked.get(room.locator);
|
|
168
|
-
const at = logPosition(room.roomVersion);
|
|
169
|
-
return entry === undefined || at === null ? [] : [presented(entry.authority, at)];
|
|
170
|
-
}));
|
|
171
|
-
},
|
|
161
|
+
hold: notifications.send,
|
|
172
162
|
observe: notifications.observe,
|
|
173
163
|
},
|
|
174
164
|
serviceMode: notifications.serviceMode,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type SpaceSchemas = {
|
|
2
|
+
held(space: string, revision: string): string | undefined;
|
|
3
|
+
keep(space: string, revision: string, text: string): void;
|
|
4
|
+
};
|
|
5
|
+
export declare function spaceSchemas(): SpaceSchemas;
|
|
6
|
+
export declare function spaceIdentity(space: string): string;
|
|
7
|
+
//# sourceMappingURL=space-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"space-schema.d.ts","sourceRoot":"","sources":["../src/space-schema.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1D,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3D,CAAC;AAEF,wBAAgB,YAAY,IAAI,YAAY,CAY3C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const HELD_TEXTS = 16;
|
|
2
|
+
export function spaceSchemas() {
|
|
3
|
+
const texts = new Map();
|
|
4
|
+
const key = (space, revision) => `${space} ${revision}`;
|
|
5
|
+
return {
|
|
6
|
+
held: (space, revision) => texts.get(key(space, revision)),
|
|
7
|
+
keep(space, revision, text) {
|
|
8
|
+
const named = key(space, revision);
|
|
9
|
+
texts.delete(named);
|
|
10
|
+
texts.set(named, text);
|
|
11
|
+
if (texts.size > HELD_TEXTS)
|
|
12
|
+
texts.delete(texts.keys().next().value);
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function spaceIdentity(space) {
|
|
17
|
+
return `space:${space}`;
|
|
18
|
+
}
|
package/dist/stream.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { type AuthorityChange, type Discovery, type ConversationStream, type RoomStreamEvent, type ServiceModeSignal } from '@agentshouse/mdruntime';
|
|
1
|
+
import { type AuthorityChange, type Discovery, type ConversationStream, type HeldRoom, type RoomStreamEvent, type ServiceModeSignal } from '@agentshouse/mdruntime';
|
|
2
2
|
import type { TrackedAuthority } from './discovery.js';
|
|
3
|
-
import
|
|
3
|
+
import type { SpaceSchemas } from './space-schema.js';
|
|
4
|
+
import { type HouseDoor, type HouseMode, type HouseStreamFrame } from './transport.js';
|
|
4
5
|
export type HouseOpeningFrame = Extract<HouseStreamFrame, {
|
|
5
6
|
type: 'opening';
|
|
6
7
|
}>;
|
|
@@ -10,14 +11,15 @@ export type HouseAuthorityChangedFrame = Extract<HouseStreamFrame, {
|
|
|
10
11
|
export type HouseDiscovering = {
|
|
11
12
|
opened(frame: HouseOpeningFrame | null): Promise<Discovery | null>;
|
|
12
13
|
changed(frame: HouseAuthorityChangedFrame): AuthorityChange | null;
|
|
14
|
+
expired?(authorities: readonly string[]): void;
|
|
13
15
|
};
|
|
14
16
|
export type HouseNotifications = {
|
|
15
17
|
runtime: string;
|
|
16
18
|
observe(notify: (event: RoomStreamEvent) => void): () => void;
|
|
17
|
-
send(rooms: readonly
|
|
19
|
+
send(rooms: readonly HeldRoom[]): void;
|
|
18
20
|
track(authorities: readonly TrackedAuthority[]): void;
|
|
19
21
|
conversations: ConversationStream;
|
|
20
22
|
serviceMode: ServiceModeSignal;
|
|
21
23
|
};
|
|
22
|
-
export declare function houseNotifications(transport: HouseDoor, mode: HouseMode, discovering: HouseDiscovering): HouseNotifications;
|
|
24
|
+
export declare function houseNotifications(transport: HouseDoor, mode: HouseMode, discovering: HouseDiscovering, spaces: SpaceSchemas): HouseNotifications;
|
|
23
25
|
//# sourceMappingURL=stream.d.ts.map
|
package/dist/stream.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EAEpB,KAAK,SAAS,EACd,KAAK,kBAAkB,
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EAEpB,KAAK,SAAS,EACd,KAAK,kBAAkB,EAEvB,KAAK,QAAQ,EAGb,KAAK,eAAe,EAEpB,KAAK,iBAAiB,EAEvB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAUtD,OAAO,EAEL,KAAK,SAAS,EAEd,KAAK,SAAS,EAGd,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAaxB,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AAE/E,MAAM,MAAM,0BAA0B,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,CAAC,CAAC;AAElG,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IACnE,OAAO,CAAC,KAAK,EAAE,0BAA0B,GAAG,eAAe,GAAG,IAAI,CAAC;IACnE,OAAO,CAAC,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC9D,IAAI,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,IAAI,CAAC;IACvC,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,aAAa,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AA2FF,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,SAAS,EACf,WAAW,EAAE,gBAAgB,EAC7B,MAAM,EAAE,YAAY,GACnB,kBAAkB,CA8XpB"}
|
package/dist/stream.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ROW_WEIGHT, stepped, } from '@agentshouse/mdruntime';
|
|
2
2
|
import { acceptedMessage, cursorPosition, houseHistory } from './history.js';
|
|
3
|
-
import { streamedModels } from './model.js';
|
|
3
|
+
import { keptSpaceSchemas, streamedModels } from './model.js';
|
|
4
4
|
import { answered, answering, binaryFileOf, folded, forgotten, headChange, revised, } from './read.js';
|
|
5
5
|
import { houseDoorRoute, } from './transport.js';
|
|
6
|
-
import { DECIMAL, roomVersion } from './version.js';
|
|
6
|
+
import { DECIMAL, logPosition, presented, roomVersion } from './version.js';
|
|
7
7
|
function turnOperation(frame) {
|
|
8
8
|
const { type: _type, conversation_id: _conversation, turn_id: _turn, ...operation } = frame;
|
|
9
9
|
return structuredClone(operation);
|
|
@@ -51,6 +51,10 @@ function* changed(tracked, entries, version, schemas) {
|
|
|
51
51
|
if (entry.path === tracked.schema)
|
|
52
52
|
schemas.set(entry.path, entry);
|
|
53
53
|
forgotten(answer, entry.path);
|
|
54
|
+
if (entry.space !== undefined) {
|
|
55
|
+
answer.removals.add(entry.path);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
54
58
|
if (entry.kind === 'removed') {
|
|
55
59
|
answer.removals.add(entry.path);
|
|
56
60
|
continue;
|
|
@@ -71,29 +75,37 @@ function* changed(tracked, entries, version, schemas) {
|
|
|
71
75
|
}
|
|
72
76
|
return { kind: 'net-advancement', roomVersion: version, ...(yield* answered(answer)) };
|
|
73
77
|
}
|
|
74
|
-
async function changePage(tracked, entries, version, mode) {
|
|
78
|
+
async function changePage(tracked, entries, version, mode, spaces, whole) {
|
|
75
79
|
const schemas = new Map();
|
|
76
80
|
const page = await stepped(changed(tracked, entries, version, schemas));
|
|
77
|
-
const models = await streamedModels(schemas, tracked, mode);
|
|
81
|
+
const models = await streamedModels(schemas, tracked, mode, spaces, whole);
|
|
78
82
|
return models === undefined ? page : { ...page, models };
|
|
79
83
|
}
|
|
80
|
-
export function houseNotifications(transport, mode, discovering) {
|
|
84
|
+
export function houseNotifications(transport, mode, discovering, spaces) {
|
|
81
85
|
const stream = transport.stream;
|
|
82
86
|
const staged = new Map();
|
|
83
87
|
let socket = null;
|
|
84
88
|
const tracking = new Map();
|
|
85
89
|
const observers = new Set();
|
|
90
|
+
const replaying = new Map();
|
|
86
91
|
const conversationObservers = new Set();
|
|
87
92
|
const modeObservers = new Set();
|
|
88
93
|
let replicated = [];
|
|
89
94
|
let listedCursor = null;
|
|
95
|
+
const unanswered = [];
|
|
96
|
+
const heldAtZero = new Set();
|
|
90
97
|
const live = new Set();
|
|
91
98
|
let opening = null;
|
|
92
99
|
let announced = null;
|
|
93
100
|
const runtime = crypto.randomUUID();
|
|
94
101
|
function emit(event) {
|
|
95
|
-
for (const observer of observers)
|
|
96
|
-
observer
|
|
102
|
+
for (const observer of observers) {
|
|
103
|
+
const held = replaying.get(observer);
|
|
104
|
+
if (held === undefined)
|
|
105
|
+
observer(event);
|
|
106
|
+
else
|
|
107
|
+
held.push(event);
|
|
108
|
+
}
|
|
97
109
|
}
|
|
98
110
|
function emitConversation(event) {
|
|
99
111
|
if (event.kind === 'turn' ||
|
|
@@ -115,6 +127,8 @@ export function houseNotifications(transport, mode, discovering) {
|
|
|
115
127
|
announced = null;
|
|
116
128
|
socket = next;
|
|
117
129
|
staged.clear();
|
|
130
|
+
unanswered.length = 0;
|
|
131
|
+
heldAtZero.clear();
|
|
118
132
|
const gapped = new Set([...replicated, ...live]);
|
|
119
133
|
live.clear();
|
|
120
134
|
for (const conversation of gapped)
|
|
@@ -216,6 +230,7 @@ export function houseNotifications(transport, mode, discovering) {
|
|
|
216
230
|
}
|
|
217
231
|
}
|
|
218
232
|
const next = held ?? { authority: frame.authority, parts: 0, entries: [] };
|
|
233
|
+
keptSpaceSchemas(frame.entries, spaces);
|
|
219
234
|
next.entries.push(...frame.entries);
|
|
220
235
|
next.parts += 1;
|
|
221
236
|
staged.set(frame.carry, next);
|
|
@@ -243,9 +258,13 @@ export function houseNotifications(transport, mode, discovering) {
|
|
|
243
258
|
return;
|
|
244
259
|
}
|
|
245
260
|
if (frame.type === 'caught_up') {
|
|
261
|
+
discovering.expired?.(frame.expired);
|
|
246
262
|
emit({
|
|
247
263
|
kind: 'caught-up',
|
|
248
|
-
expired:
|
|
264
|
+
expired: [
|
|
265
|
+
...frame.expired.flatMap((authority) => (tracking.get(authority) ?? []).map((tracked) => tracked.locator)),
|
|
266
|
+
...(unanswered.shift() ?? []),
|
|
267
|
+
],
|
|
249
268
|
});
|
|
250
269
|
return;
|
|
251
270
|
}
|
|
@@ -296,7 +315,9 @@ export function houseNotifications(transport, mode, discovering) {
|
|
|
296
315
|
const after = position(frame.after);
|
|
297
316
|
if (at === null || after === null || after >= at)
|
|
298
317
|
return;
|
|
299
|
-
const from =
|
|
318
|
+
const from = after === 0n && !heldAtZero.has(frame.authority)
|
|
319
|
+
? null
|
|
320
|
+
: roomVersion({ position: frame.after, logEpoch: frame.log_epoch });
|
|
300
321
|
const version = roomVersion({ position: frame.position, logEpoch: frame.log_epoch });
|
|
301
322
|
for (const tracked of tracking.get(frame.authority) ?? []) {
|
|
302
323
|
emit({
|
|
@@ -304,7 +325,7 @@ export function houseNotifications(transport, mode, discovering) {
|
|
|
304
325
|
locator: tracked.locator,
|
|
305
326
|
from,
|
|
306
327
|
roomVersion: version,
|
|
307
|
-
read: () => changePage(tracked, entries, version, mode),
|
|
328
|
+
read: () => changePage(tracked, entries, version, mode, spaces, from === null),
|
|
308
329
|
});
|
|
309
330
|
}
|
|
310
331
|
}
|
|
@@ -315,6 +336,8 @@ export function houseNotifications(transport, mode, discovering) {
|
|
|
315
336
|
announced = null;
|
|
316
337
|
socket = null;
|
|
317
338
|
staged.clear();
|
|
339
|
+
unanswered.length = 0;
|
|
340
|
+
heldAtZero.clear();
|
|
318
341
|
emit({ kind: 'closed', revoked, lost, authorityChanged });
|
|
319
342
|
});
|
|
320
343
|
return {
|
|
@@ -349,11 +372,15 @@ export function houseNotifications(transport, mode, discovering) {
|
|
|
349
372
|
},
|
|
350
373
|
observe(notify) {
|
|
351
374
|
observers.add(notify);
|
|
352
|
-
|
|
353
|
-
|
|
375
|
+
if (opening !== null) {
|
|
376
|
+
const replayed = [{ kind: 'opened' }];
|
|
377
|
+
if (announced !== null)
|
|
378
|
+
replayed.push(announced);
|
|
379
|
+
replaying.set(notify, replayed);
|
|
354
380
|
queueMicrotask(() => {
|
|
381
|
+
replaying.delete(notify);
|
|
355
382
|
for (const event of replayed)
|
|
356
|
-
if (
|
|
383
|
+
if (observers.has(notify))
|
|
357
384
|
notify(event);
|
|
358
385
|
});
|
|
359
386
|
}
|
|
@@ -364,7 +391,47 @@ export function houseNotifications(transport, mode, discovering) {
|
|
|
364
391
|
send(rooms) {
|
|
365
392
|
opening = null;
|
|
366
393
|
announced = null;
|
|
367
|
-
socket
|
|
394
|
+
if (socket === null)
|
|
395
|
+
return;
|
|
396
|
+
const entries = new Map([...tracking.values()].flat().map((tracked) => [tracked.locator, tracked]));
|
|
397
|
+
const named = rooms.flatMap((room) => {
|
|
398
|
+
const entry = entries.get(room.locator);
|
|
399
|
+
const at = room.roomVersion === null ? null : logPosition(room.roomVersion);
|
|
400
|
+
return entry === undefined || at === null ? [] : [{ entry, at }];
|
|
401
|
+
});
|
|
402
|
+
const unheld = rooms.flatMap((room) => {
|
|
403
|
+
const entry = entries.get(room.locator);
|
|
404
|
+
return entry === undefined || room.roomVersion !== null ? [] : [entry];
|
|
405
|
+
});
|
|
406
|
+
for (const { entry, at } of named) {
|
|
407
|
+
if (at.position === '0')
|
|
408
|
+
heldAtZero.add(entry.authority);
|
|
409
|
+
else
|
|
410
|
+
heldAtZero.delete(entry.authority);
|
|
411
|
+
}
|
|
412
|
+
for (const entry of unheld)
|
|
413
|
+
heldAtZero.delete(entry.authority);
|
|
414
|
+
const site = mode === 'site';
|
|
415
|
+
unanswered.push(site ? unheld.map((entry) => entry.locator) : []);
|
|
416
|
+
socket.hold([
|
|
417
|
+
...named.map(({ entry, at }) => presented(entry.authority, at)),
|
|
418
|
+
...(site ? [] : unheld).map((entry) => presented(entry.authority, { position: '0', logEpoch: entry.logEpoch })),
|
|
419
|
+
], runtime, listedCursor);
|
|
420
|
+
if (site)
|
|
421
|
+
return;
|
|
422
|
+
const made = unheld.filter((entry) => entry.position === '0');
|
|
423
|
+
queueMicrotask(() => {
|
|
424
|
+
for (const entry of made) {
|
|
425
|
+
const version = roomVersion(entry);
|
|
426
|
+
emit({
|
|
427
|
+
kind: 'room-change',
|
|
428
|
+
locator: entry.locator,
|
|
429
|
+
from: null,
|
|
430
|
+
roomVersion: version,
|
|
431
|
+
read: () => changePage(entry, [], version, mode, spaces, true),
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
});
|
|
368
435
|
},
|
|
369
436
|
track(entries) {
|
|
370
437
|
tracking.clear();
|
package/dist/transport.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { ConversationEvent, SavedFacts, TurnOperation } from '@agentshouse/mdruntime';
|
|
2
2
|
export declare const HOUSE_RUNTIME_READS: {
|
|
3
|
-
readonly acts: readonly ['account/push', 'agents/read', 'apps/features/set', 'apps/source/download', 'apps/source/top', 'batch', 'batch-upload', '
|
|
3
|
+
readonly acts: readonly ['account/push', 'agents/read', 'apps/features/set', 'apps/source/download', 'apps/source/top', 'batch', 'batch-upload', 'conversations/history', 'discover', 'files/attach', 'files/finish', 'files/get', 'revisions', 'room-chunks/list', 'search', 'sites/screenshot/read'];
|
|
4
4
|
readonly frames: readonly ['app-message', 'authority_changed', 'carried', 'caught_up', 'commands', 'conversation', 'conversation_deleted', 'conversations', 'deliveries', 'deployment', 'held', 'interactions', 'link', 'message', 'opening', 'options', 'part', 'process', 'received', 'signal', 'site', 'starting', 'subagents', 'tab-icon', 'turn'];
|
|
5
5
|
};
|
|
6
6
|
export type HouseRuntimeAct = (typeof HOUSE_RUNTIME_READS.acts)[number];
|
|
7
7
|
export type HouseRuntimeFrame = (typeof HOUSE_RUNTIME_READS.frames)[number];
|
|
8
8
|
export declare function houseDoorRoute(act: HouseRuntimeAct): string;
|
|
9
|
-
export declare function houseSiteRoute(act:
|
|
9
|
+
export declare function houseSiteRoute(act: 'chunks' | 'discover'): string;
|
|
10
10
|
export declare const SITE_SUBMISSION = "site/submission";
|
|
11
11
|
export declare const SITE_DOOR_SUBMIT = "/_house/door/submit";
|
|
12
12
|
export type HouseMode = 'credential' | 'site';
|
|
@@ -44,6 +44,7 @@ export type HouseStreamEntry = {
|
|
|
44
44
|
};
|
|
45
45
|
created_at?: string;
|
|
46
46
|
facts?: SavedFacts;
|
|
47
|
+
space?: string;
|
|
47
48
|
};
|
|
48
49
|
type LiveFact<K extends ConversationEvent['kind']> = Extract<ConversationEvent, {
|
|
49
50
|
kind: K;
|
|
@@ -172,15 +173,11 @@ export type HouseStream = {
|
|
|
172
173
|
opened(notify: (opening: HouseOpening) => void): () => void;
|
|
173
174
|
closed(notify: (closing: HouseClosing) => void): () => void;
|
|
174
175
|
};
|
|
175
|
-
export type HouseStreamed = HouseDoorAnswer & {
|
|
176
|
-
room: ReadableStream<Uint8Array> | null;
|
|
177
|
-
};
|
|
178
176
|
export type HouseDoor = {
|
|
179
177
|
door(route: string, body: unknown): Promise<HouseDoorAnswer>;
|
|
180
178
|
stream: HouseStream;
|
|
181
179
|
};
|
|
182
180
|
export type HouseTransport = HouseDoor & {
|
|
183
|
-
streamed(route: string, body: unknown, signal: AbortSignal): Promise<HouseStreamed>;
|
|
184
181
|
transfer(request: HouseByteTransfer): Promise<HouseDoorAnswer>;
|
|
185
182
|
put(url: string, body: Blob, headers: Readonly<Record<string, string>>): Promise<number>;
|
|
186
183
|
download(url: string): Promise<HouseBytesAnswer>;
|
|
@@ -188,7 +185,6 @@ export type HouseTransport = HouseDoor & {
|
|
|
188
185
|
export type HouseSiteTransport = HouseDoor & {
|
|
189
186
|
online(): boolean;
|
|
190
187
|
read(route: string): Promise<HouseDoorAnswer>;
|
|
191
|
-
streamed(route: string, signal: AbortSignal): Promise<HouseStreamed>;
|
|
192
188
|
download(route: string): Promise<HouseBytesAnswer>;
|
|
193
189
|
};
|
|
194
190
|
export {};
|