@agentshouse/mdruntime-adapter 0.1.0-alpha.1 → 0.1.0-alpha.11
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/AGENTS.md +82 -0
- package/dist/actions.d.ts +16 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +451 -0
- package/dist/actions.js.map +1 -0
- package/dist/adapter.d.ts +10 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +285 -0
- package/dist/adapter.js.map +1 -0
- package/dist/digest.d.ts +3 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +11 -0
- package/dist/digest.js.map +1 -0
- package/dist/discovery.d.ts +87 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +347 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/map.d.ts +3 -0
- package/dist/map.d.ts.map +1 -0
- package/dist/map.js +15 -0
- package/dist/map.js.map +1 -0
- package/dist/model.d.ts +19 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +64 -0
- package/dist/model.js.map +1 -0
- package/dist/read.d.ts +73 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +326 -0
- package/dist/read.js.map +1 -0
- package/dist/refusal.d.ts +11 -0
- package/dist/refusal.d.ts.map +1 -0
- package/dist/refusal.js +78 -0
- package/dist/refusal.js.map +1 -0
- package/dist/site.d.ts +4 -0
- package/dist/site.d.ts.map +1 -0
- package/dist/site.js +200 -0
- package/dist/site.js.map +1 -0
- package/dist/stream.d.ts +12 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +298 -0
- package/dist/stream.js.map +1 -0
- package/dist/transport.d.ts +88 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +12 -0
- package/dist/transport.js.map +1 -0
- package/dist/version.d.ts +14 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +29 -0
- package/dist/version.js.map +1 -0
- package/dist/write.d.ts +47 -0
- package/dist/write.d.ts.map +1 -0
- package/dist/write.js +389 -0
- package/dist/write.js.map +1 -0
- package/package.json +7 -2
package/dist/site.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { mapDiscovery, parseSiteDiscovery, siteCapabilities, siteSlots, siteTracked } from './discovery.js';
|
|
2
|
+
import { MODEL_ABSENT, failedModel, heldModel, modelKey, modelShelf } from './model.js';
|
|
3
|
+
import { advancedScope, authorityRoot, bootstrapOf, definitionsOf, parseEnumeration, parseSiteBootstrap, refreshFrom, selectionRoots } from './read.js';
|
|
4
|
+
import { classifyDoor, discoveryFailure } from './refusal.js';
|
|
5
|
+
import { houseNotifications } from './stream.js';
|
|
6
|
+
import { PRIVATE_AUTHORITY, SITE_DOOR_BOOTSTRAP, SITE_DOOR_DISCOVER, SITE_DOOR_ENUMERATE } from './transport.js';
|
|
7
|
+
import { logPosition, presented, roomVersion } from './version.js';
|
|
8
|
+
const UNCERTAIN = {
|
|
9
|
+
kind: 'transport-uncertainty'
|
|
10
|
+
};
|
|
11
|
+
function siteRoom(tracked, attachedModel) {
|
|
12
|
+
const read = selectionRoots(tracked);
|
|
13
|
+
return {
|
|
14
|
+
name: tracked.handle,
|
|
15
|
+
locator: tracked.locator,
|
|
16
|
+
collectionRoot: tracked.collectionRoot,
|
|
17
|
+
roomVersion: roomVersion(tracked),
|
|
18
|
+
operations: {
|
|
19
|
+
read: [
|
|
20
|
+
...read
|
|
21
|
+
],
|
|
22
|
+
sync: [
|
|
23
|
+
...read
|
|
24
|
+
],
|
|
25
|
+
write: [],
|
|
26
|
+
delete: []
|
|
27
|
+
},
|
|
28
|
+
replica: {
|
|
29
|
+
selection: tracked.locator,
|
|
30
|
+
admission: 'admitted'
|
|
31
|
+
},
|
|
32
|
+
attachedModel,
|
|
33
|
+
providerOwnedPaths: []
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function settled(refused) {
|
|
37
|
+
return refused.kind === 'beyond-horizon' ? UNCERTAIN : refused;
|
|
38
|
+
}
|
|
39
|
+
export function createSiteAdapter(transport) {
|
|
40
|
+
const notifications = houseNotifications(transport, 'site');
|
|
41
|
+
const tracked = new Map();
|
|
42
|
+
const models = modelShelf();
|
|
43
|
+
const acquired = new Map();
|
|
44
|
+
let caught = new Map();
|
|
45
|
+
async function enumeration(entry, from) {
|
|
46
|
+
const answer = await transport.door(SITE_DOOR_ENUMERATE, {
|
|
47
|
+
positions: [
|
|
48
|
+
presented(entry.authority, from)
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
const classified = classifyDoor(answer.status, answer.body, entry.locator);
|
|
52
|
+
if (classified !== null) return classified;
|
|
53
|
+
return parseEnumeration(answer.body, 'site') ?? UNCERTAIN;
|
|
54
|
+
}
|
|
55
|
+
async function caughtUp(entry) {
|
|
56
|
+
const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}`);
|
|
57
|
+
const classified = classifyDoor(answer.status, answer.body, entry.locator);
|
|
58
|
+
if (classified !== null) return {
|
|
59
|
+
failure: settled(classified)
|
|
60
|
+
};
|
|
61
|
+
const scope = parseSiteBootstrap(answer.body);
|
|
62
|
+
if (scope === null) return {
|
|
63
|
+
failure: UNCERTAIN
|
|
64
|
+
};
|
|
65
|
+
if (roomVersion(scope) === roomVersion(entry)) return {
|
|
66
|
+
scope
|
|
67
|
+
};
|
|
68
|
+
const found = await enumeration(entry, scope);
|
|
69
|
+
if ('kind' in found) return {
|
|
70
|
+
failure: settled(found)
|
|
71
|
+
};
|
|
72
|
+
const view = found.authorities.find((held)=>held.authority === entry.authority);
|
|
73
|
+
if (view === undefined) return {
|
|
74
|
+
failure: {
|
|
75
|
+
kind: 'room-not-readable',
|
|
76
|
+
locator: entry.locator
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
scope: advancedScope(scope, view)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
async function refreshed(entry, fromRoomVersion) {
|
|
84
|
+
const from = logPosition(fromRoomVersion);
|
|
85
|
+
if (from === null) return {
|
|
86
|
+
kind: 'beyond-horizon'
|
|
87
|
+
};
|
|
88
|
+
const streamed = notifications.advance(entry, from);
|
|
89
|
+
if (streamed !== null) return streamed;
|
|
90
|
+
const found = await enumeration(entry, from);
|
|
91
|
+
if ('kind' in found) return found;
|
|
92
|
+
return refreshFrom(found, entry, fromRoomVersion);
|
|
93
|
+
}
|
|
94
|
+
async function acquire(entry, held) {
|
|
95
|
+
if ('failure' in held) return {
|
|
96
|
+
snapshot: failedModel(held.failure),
|
|
97
|
+
identity: null
|
|
98
|
+
};
|
|
99
|
+
const model = await heldModel(definitionsOf(held.scope, entry.modelRoot), `${authorityRoot(entry.handle)}/${entry.modelRoot}`, MODEL_ABSENT);
|
|
100
|
+
acquired.set(entry.authority, {
|
|
101
|
+
roomVersion: roomVersion(held.scope),
|
|
102
|
+
model
|
|
103
|
+
});
|
|
104
|
+
return model;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
async authorize () {
|
|
108
|
+
return {};
|
|
109
|
+
},
|
|
110
|
+
async model (_authorization, request) {
|
|
111
|
+
return models.answer(request);
|
|
112
|
+
},
|
|
113
|
+
async discover () {
|
|
114
|
+
const answer = await transport.door(SITE_DOOR_DISCOVER, {});
|
|
115
|
+
const classified = classifyDoor(answer.status, answer.body, PRIVATE_AUTHORITY);
|
|
116
|
+
if (classified !== null) return discoveryFailure(classified);
|
|
117
|
+
const document = parseSiteDiscovery(answer.body);
|
|
118
|
+
if (document === null) return UNCERTAIN;
|
|
119
|
+
const entries = siteTracked(document);
|
|
120
|
+
tracked.clear();
|
|
121
|
+
for (const entry of entries)tracked.set(entry.locator, entry);
|
|
122
|
+
notifications.track(entries);
|
|
123
|
+
const published = new Set(entries.map((entry)=>entry.authority));
|
|
124
|
+
for (const authority of [
|
|
125
|
+
...acquired.keys()
|
|
126
|
+
]){
|
|
127
|
+
if (!published.has(authority)) acquired.delete(authority);
|
|
128
|
+
}
|
|
129
|
+
const fresh = new Map();
|
|
130
|
+
const current = new Map();
|
|
131
|
+
for (const entry of entries){
|
|
132
|
+
const kept = acquired.get(entry.authority);
|
|
133
|
+
if (kept !== undefined && kept.roomVersion === roomVersion(entry)) {
|
|
134
|
+
current.set(entry.authority, kept.model);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const held = await caughtUp(entry);
|
|
138
|
+
fresh.set(entry.authority, held);
|
|
139
|
+
current.set(entry.authority, await acquire(entry, held));
|
|
140
|
+
}
|
|
141
|
+
caught = fresh;
|
|
142
|
+
const rooms = entries.map((entry)=>{
|
|
143
|
+
const shelved = models.retain(modelKey(entry.locator, 'collection'), current.get(entry.authority));
|
|
144
|
+
return siteRoom(entry, shelved?.identity ?? null);
|
|
145
|
+
});
|
|
146
|
+
models.keep(entries.map((entry)=>entry.locator));
|
|
147
|
+
return {
|
|
148
|
+
...mapDiscovery(document, rooms, siteCapabilities()),
|
|
149
|
+
slots: siteSlots(document)
|
|
150
|
+
};
|
|
151
|
+
},
|
|
152
|
+
async bootstrap (_authorization, request) {
|
|
153
|
+
const entry = tracked.get(request.locator);
|
|
154
|
+
if (entry === undefined) return {
|
|
155
|
+
kind: 'room-not-readable',
|
|
156
|
+
locator: request.locator
|
|
157
|
+
};
|
|
158
|
+
if (request.pageToken !== undefined) return UNCERTAIN;
|
|
159
|
+
const held = caught.get(entry.authority) ?? await caughtUp(entry);
|
|
160
|
+
if ('failure' in held) return held.failure;
|
|
161
|
+
return bootstrapOf(held.scope, entry);
|
|
162
|
+
},
|
|
163
|
+
async refresh (_authorization, request) {
|
|
164
|
+
const entry = tracked.get(request.locator);
|
|
165
|
+
if (entry === undefined) return {
|
|
166
|
+
kind: 'room-not-readable',
|
|
167
|
+
locator: request.locator
|
|
168
|
+
};
|
|
169
|
+
if (request.pageToken !== undefined) return UNCERTAIN;
|
|
170
|
+
const result = await refreshed(entry, request.fromRoomVersion);
|
|
171
|
+
if (result.kind === 'beyond-horizon') caught.delete(entry.authority);
|
|
172
|
+
return result;
|
|
173
|
+
},
|
|
174
|
+
async mutate () {
|
|
175
|
+
return {
|
|
176
|
+
kind: 'rejected',
|
|
177
|
+
affected: {},
|
|
178
|
+
code: 'write-grant',
|
|
179
|
+
fields: {}
|
|
180
|
+
};
|
|
181
|
+
},
|
|
182
|
+
async history () {
|
|
183
|
+
return {
|
|
184
|
+
kind: 'no-history'
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
async action (_authorization, request) {
|
|
188
|
+
return {
|
|
189
|
+
kind: 'rejected',
|
|
190
|
+
code: 'action-unimplemented',
|
|
191
|
+
fields: {
|
|
192
|
+
name: request.name
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
roomVersions: notifications
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
//# sourceMappingURL=site.js.map
|
package/dist/site.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/workspace/packages/mdruntime-adapter/src/site.ts"],"sourcesContent":["import type {\n Adapter,\n AdapterFailure,\n BootstrapResult,\n DiscoverResult,\n DiscoveredRoom,\n ModelResult,\n RefreshResult,\n} from '@agentshouse/mdruntime';\nimport {\n mapDiscovery,\n parseSiteDiscovery,\n siteCapabilities,\n siteSlots,\n siteTracked,\n type SiteTracked,\n} from './discovery.js';\nimport {\n MODEL_ABSENT,\n failedModel,\n heldModel,\n modelKey,\n modelShelf,\n type HeldModel,\n} from './model.js';\nimport {\n advancedScope,\n authorityRoot,\n bootstrapOf,\n definitionsOf,\n parseEnumeration,\n parseSiteBootstrap,\n refreshFrom,\n selectionRoots,\n type HouseEnumeration,\n type HouseScope,\n} from './read.js';\nimport { classifyDoor, discoveryFailure } from './refusal.js';\nimport { houseNotifications } from './stream.js';\nimport {\n PRIVATE_AUTHORITY,\n SITE_DOOR_BOOTSTRAP,\n SITE_DOOR_DISCOVER,\n SITE_DOOR_ENUMERATE,\n type HouseSiteTransport,\n} from './transport.js';\nimport { logPosition, presented, roomVersion, type LogPosition } from './version.js';\n\ntype Refused = AdapterFailure | { kind: 'beyond-horizon' };\n\ntype CaughtUp = { scope: HouseScope } | { failure: AdapterFailure };\n\ntype Acquired = { roomVersion: string; model: HeldModel };\n\nconst UNCERTAIN = { kind: 'transport-uncertainty' } as const;\n\nfunction siteRoom(\n tracked: SiteTracked,\n attachedModel: DiscoveredRoom['attachedModel'],\n): DiscoveredRoom {\n const read = selectionRoots(tracked);\n return {\n name: tracked.handle,\n locator: tracked.locator,\n collectionRoot: tracked.collectionRoot,\n roomVersion: roomVersion(tracked),\n operations: { read: [...read], sync: [...read], write: [], delete: [] },\n replica: { selection: tracked.locator, admission: 'admitted' },\n attachedModel,\n providerOwnedPaths: [],\n };\n}\n\nfunction settled(refused: Refused): AdapterFailure {\n return refused.kind === 'beyond-horizon' ? UNCERTAIN : refused;\n}\n\nexport function createSiteAdapter(transport: HouseSiteTransport): Adapter {\n const notifications = houseNotifications(transport, 'site');\n const tracked = new Map<string, SiteTracked>();\n const models = modelShelf();\n const acquired = new Map<string, Acquired>();\n let caught = new Map<string, CaughtUp>();\n\n async function enumeration(\n entry: SiteTracked,\n from: LogPosition,\n ): Promise<HouseEnumeration | Refused> {\n const answer = await transport.door(SITE_DOOR_ENUMERATE, {\n positions: [presented(entry.authority, from)],\n });\n const classified = classifyDoor(answer.status, answer.body, entry.locator);\n if (classified !== null) return classified;\n return parseEnumeration(answer.body, 'site') ?? UNCERTAIN;\n }\n\n async function caughtUp(entry: SiteTracked): Promise<CaughtUp> {\n const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}`);\n const classified = classifyDoor(answer.status, answer.body, entry.locator);\n if (classified !== null) return { failure: settled(classified) };\n const scope = parseSiteBootstrap(answer.body);\n if (scope === null) return { failure: UNCERTAIN };\n if (roomVersion(scope) === roomVersion(entry)) return { scope };\n const found = await enumeration(entry, scope);\n if ('kind' in found) return { failure: settled(found) };\n const view = found.authorities.find((held) => held.authority === entry.authority);\n if (view === undefined)\n return { failure: { kind: 'room-not-readable', locator: entry.locator } };\n return { scope: advancedScope(scope, view) };\n }\n\n async function refreshed(entry: SiteTracked, fromRoomVersion: string): Promise<RefreshResult> {\n const from = logPosition(fromRoomVersion);\n if (from === null) return { kind: 'beyond-horizon' };\n const streamed = notifications.advance(entry, from);\n if (streamed !== null) return streamed;\n const found = await enumeration(entry, from);\n if ('kind' in found) return found;\n return refreshFrom(found, entry, fromRoomVersion);\n }\n\n async function acquire(entry: SiteTracked, held: CaughtUp): Promise<HeldModel> {\n if ('failure' in held) return { snapshot: failedModel(held.failure), identity: null };\n const model = await heldModel(\n definitionsOf(held.scope, entry.modelRoot),\n `${authorityRoot(entry.handle)}/${entry.modelRoot}`,\n MODEL_ABSENT,\n );\n acquired.set(entry.authority, { roomVersion: roomVersion(held.scope), model });\n return model;\n }\n\n return {\n async authorize() {\n return {};\n },\n\n async model(_authorization, request): Promise<ModelResult> {\n return models.answer(request);\n },\n\n async discover(): Promise<DiscoverResult> {\n const answer = await transport.door(SITE_DOOR_DISCOVER, {});\n const classified = classifyDoor(answer.status, answer.body, PRIVATE_AUTHORITY);\n if (classified !== null) return discoveryFailure(classified);\n const document = parseSiteDiscovery(answer.body);\n if (document === null) return UNCERTAIN;\n const entries = siteTracked(document);\n tracked.clear();\n for (const entry of entries) tracked.set(entry.locator, entry);\n notifications.track(entries);\n const published = new Set(entries.map((entry) => entry.authority));\n for (const authority of [...acquired.keys()]) {\n if (!published.has(authority)) acquired.delete(authority);\n }\n const fresh = new Map<string, CaughtUp>();\n const current = new Map<string, HeldModel>();\n for (const entry of entries) {\n const kept = acquired.get(entry.authority);\n if (kept !== undefined && kept.roomVersion === roomVersion(entry)) {\n current.set(entry.authority, kept.model);\n continue;\n }\n const held = await caughtUp(entry);\n fresh.set(entry.authority, held);\n current.set(entry.authority, await acquire(entry, held));\n }\n caught = fresh;\n const rooms = entries.map((entry) => {\n const shelved = models.retain(\n modelKey(entry.locator, 'collection'),\n current.get(entry.authority),\n );\n return siteRoom(entry, shelved?.identity ?? null);\n });\n models.keep(entries.map((entry) => entry.locator));\n return { ...mapDiscovery(document, rooms, siteCapabilities()), slots: siteSlots(document) };\n },\n\n async bootstrap(_authorization, request): Promise<BootstrapResult> {\n const entry = tracked.get(request.locator);\n if (entry === undefined) return { kind: 'room-not-readable', locator: request.locator };\n if (request.pageToken !== undefined) return UNCERTAIN;\n const held = caught.get(entry.authority) ?? (await caughtUp(entry));\n if ('failure' in held) return held.failure;\n return bootstrapOf(held.scope, entry);\n },\n\n async refresh(_authorization, request): Promise<RefreshResult> {\n const entry = tracked.get(request.locator);\n if (entry === undefined) return { kind: 'room-not-readable', locator: request.locator };\n if (request.pageToken !== undefined) return UNCERTAIN;\n const result = await refreshed(entry, request.fromRoomVersion);\n if (result.kind === 'beyond-horizon') caught.delete(entry.authority);\n return result;\n },\n\n async mutate() {\n return { kind: 'rejected', affected: {}, code: 'write-grant', fields: {} };\n },\n\n async history() {\n return { kind: 'no-history' };\n },\n\n async action(_authorization, request) {\n return { kind: 'rejected', code: 'action-unimplemented', fields: { name: request.name } };\n },\n\n roomVersions: notifications,\n };\n}\n"],"names":["mapDiscovery","parseSiteDiscovery","siteCapabilities","siteSlots","siteTracked","MODEL_ABSENT","failedModel","heldModel","modelKey","modelShelf","advancedScope","authorityRoot","bootstrapOf","definitionsOf","parseEnumeration","parseSiteBootstrap","refreshFrom","selectionRoots","classifyDoor","discoveryFailure","houseNotifications","PRIVATE_AUTHORITY","SITE_DOOR_BOOTSTRAP","SITE_DOOR_DISCOVER","SITE_DOOR_ENUMERATE","logPosition","presented","roomVersion","UNCERTAIN","kind","siteRoom","tracked","attachedModel","read","name","handle","locator","collectionRoot","operations","sync","write","delete","replica","selection","admission","providerOwnedPaths","settled","refused","createSiteAdapter","transport","notifications","Map","models","acquired","caught","enumeration","entry","from","answer","door","positions","authority","classified","status","body","caughtUp","failure","scope","found","view","authorities","find","held","undefined","refreshed","fromRoomVersion","streamed","advance","acquire","snapshot","identity","model","modelRoot","set","authorize","_authorization","request","discover","document","entries","clear","track","published","Set","map","keys","has","fresh","current","kept","get","rooms","shelved","retain","keep","slots","bootstrap","pageToken","refresh","result","mutate","affected","code","fields","history","action","roomVersions"],"mappings":"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"}
|
package/dist/stream.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RefreshPage, SelectedRooms, ViewedConversations } from '@agentshouse/mdruntime';
|
|
2
|
+
import type { TrackedAuthority } from './discovery.js';
|
|
3
|
+
import { type HouseDoor } from './transport.js';
|
|
4
|
+
import type { HouseMode } from './transport.js';
|
|
5
|
+
import { type LogPosition } from './version.js';
|
|
6
|
+
export type HouseNotifications = SelectedRooms & {
|
|
7
|
+
track(authorities: readonly TrackedAuthority[]): void;
|
|
8
|
+
advance(tracked: TrackedAuthority, from: LogPosition): RefreshPage | null;
|
|
9
|
+
conversations: ViewedConversations;
|
|
10
|
+
};
|
|
11
|
+
export declare function houseNotifications(transport: HouseDoor, mode: HouseMode): HouseNotifications;
|
|
12
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,WAAW,EAEX,aAAa,EACb,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAqB,KAAK,SAAS,EAA6B,MAAM,gBAAgB,CAAC;AAC9F,OAAO,KAAK,EAAE,SAAS,EAAsC,MAAM,gBAAgB,CAAC;AACpF,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAc7D,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG;IAC/C,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,OAAO,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAAC;IAC1E,aAAa,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAaF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CA+O5F"}
|
package/dist/stream.js
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { actionOutcome, HISTORY_PAGE, readConversationHistory } from './actions.js';
|
|
2
|
+
import { selects } from './read.js';
|
|
3
|
+
import { PRIVATE_AUTHORITY } from './transport.js';
|
|
4
|
+
import { roomVersion } from './version.js';
|
|
5
|
+
const HELD_POSITIONS_MAX = 256;
|
|
6
|
+
function position(value) {
|
|
7
|
+
if (!/^(?:0|[1-9][0-9]*)$/.test(value)) return null;
|
|
8
|
+
return BigInt(value);
|
|
9
|
+
}
|
|
10
|
+
function messageTurn(message) {
|
|
11
|
+
if (typeof message !== 'object' || message === null) return null;
|
|
12
|
+
const turn = message.message_id;
|
|
13
|
+
return typeof turn === 'string' ? turn : null;
|
|
14
|
+
}
|
|
15
|
+
export function houseNotifications(transport, mode) {
|
|
16
|
+
const stream = transport.stream;
|
|
17
|
+
const lines = new Map();
|
|
18
|
+
const locators = new Map();
|
|
19
|
+
const authorities = new Map();
|
|
20
|
+
const observers = new Set();
|
|
21
|
+
const conversationObservers = new Set();
|
|
22
|
+
const subscribedConversations = new Set();
|
|
23
|
+
let selected = [];
|
|
24
|
+
let viewed = [];
|
|
25
|
+
let listening = false;
|
|
26
|
+
function subscribe() {
|
|
27
|
+
const named = [];
|
|
28
|
+
const rooms = new Set();
|
|
29
|
+
for (const locator of selected){
|
|
30
|
+
const authority = authorities.get(locator);
|
|
31
|
+
if (authority === undefined || authority === PRIVATE_AUTHORITY) continue;
|
|
32
|
+
rooms.add(authority);
|
|
33
|
+
}
|
|
34
|
+
for (const room of rooms)named.push({
|
|
35
|
+
kind: 'room',
|
|
36
|
+
room
|
|
37
|
+
});
|
|
38
|
+
if (authorities.has(PRIVATE_AUTHORITY)) named.push({
|
|
39
|
+
kind: 'private'
|
|
40
|
+
});
|
|
41
|
+
for (const conversation of viewed){
|
|
42
|
+
named.push({
|
|
43
|
+
kind: 'conversation',
|
|
44
|
+
conversation
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
stream.subscribe(named);
|
|
48
|
+
}
|
|
49
|
+
function emitConversation(event) {
|
|
50
|
+
if (!viewed.includes(event.conversation)) return;
|
|
51
|
+
for (const observer of conversationObservers)observer(event);
|
|
52
|
+
}
|
|
53
|
+
async function catchUp(conversation, history) {
|
|
54
|
+
const viewedAnswer = await transport.door('/door/conversations/view', {
|
|
55
|
+
conversation_id: conversation
|
|
56
|
+
});
|
|
57
|
+
const summary = actionOutcome(viewedAnswer, 'conversations/view');
|
|
58
|
+
if (summary.kind === 'action' && typeof summary.result === 'object' && summary.result !== null) {
|
|
59
|
+
emitConversation({
|
|
60
|
+
kind: 'session-summary',
|
|
61
|
+
conversation,
|
|
62
|
+
summary: structuredClone('session' in summary.result ? summary.result.session : null)
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (!history) return;
|
|
66
|
+
const heldHistory = await readConversationHistory(transport, conversation);
|
|
67
|
+
if ('outcome' in heldHistory) return;
|
|
68
|
+
const newest = heldHistory.messages.slice(-HISTORY_PAGE);
|
|
69
|
+
for (const entry of newest){
|
|
70
|
+
const turn = messageTurn(entry);
|
|
71
|
+
if (turn === null) return;
|
|
72
|
+
emitConversation({
|
|
73
|
+
kind: 'accepted-message',
|
|
74
|
+
conversation,
|
|
75
|
+
message: {
|
|
76
|
+
turn,
|
|
77
|
+
message: structuredClone(entry)
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function announce(authority, at) {
|
|
83
|
+
const version = roomVersion(at);
|
|
84
|
+
for (const locator of locators.get(authority) ?? []){
|
|
85
|
+
for (const observer of observers)observer({
|
|
86
|
+
locator,
|
|
87
|
+
roomVersion: version
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function interrupt(authority) {
|
|
92
|
+
const line = lines.get(authority);
|
|
93
|
+
if (line !== undefined) lines.set(authority, {
|
|
94
|
+
logEpoch: line.logEpoch,
|
|
95
|
+
frames: []
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function resubscribed(authority, position, logEpoch) {
|
|
99
|
+
if (position === undefined || logEpoch === undefined) {
|
|
100
|
+
interrupt(authority);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const held = lines.get(authority)?.logEpoch;
|
|
104
|
+
lines.set(authority, {
|
|
105
|
+
logEpoch,
|
|
106
|
+
frames: []
|
|
107
|
+
});
|
|
108
|
+
if (held !== logEpoch) announce(authority, {
|
|
109
|
+
position,
|
|
110
|
+
logEpoch
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function receive(frame) {
|
|
114
|
+
if (frame.type === 'draft') {
|
|
115
|
+
emitConversation({
|
|
116
|
+
kind: 'growing-text',
|
|
117
|
+
conversation: frame.conversation_id,
|
|
118
|
+
turn: frame.turn_id,
|
|
119
|
+
text: frame.text
|
|
120
|
+
});
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (frame.type === 'message') {
|
|
124
|
+
const turn = messageTurn(frame.message);
|
|
125
|
+
if (turn === null) return;
|
|
126
|
+
emitConversation({
|
|
127
|
+
kind: 'accepted-message',
|
|
128
|
+
conversation: frame.conversation_id,
|
|
129
|
+
message: {
|
|
130
|
+
turn,
|
|
131
|
+
message: structuredClone(frame.message)
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (frame.type === 'session') {
|
|
137
|
+
emitConversation({
|
|
138
|
+
kind: 'session-summary',
|
|
139
|
+
conversation: frame.conversation_id,
|
|
140
|
+
summary: structuredClone(frame.summary)
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (frame.type === 'subscribed' && viewed.includes(frame.authority)) {
|
|
145
|
+
const reconnect = subscribedConversations.has(frame.authority);
|
|
146
|
+
subscribedConversations.add(frame.authority);
|
|
147
|
+
void catchUp(frame.authority, reconnect);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (frame.type === 'subscribed') {
|
|
151
|
+
resubscribed(frame.authority, frame.position, frame.log_epoch);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (frame.type !== 'entries') {
|
|
155
|
+
interrupt(frame.authority);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const at = position(frame.position);
|
|
159
|
+
if (at === null) {
|
|
160
|
+
interrupt(frame.authority);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const line = lines.get(frame.authority);
|
|
164
|
+
if (line?.logEpoch === frame.log_epoch) {
|
|
165
|
+
const last = line.frames.at(-1);
|
|
166
|
+
const continued = last !== undefined && last.position + 1n === at;
|
|
167
|
+
const next = continued ? [
|
|
168
|
+
...line.frames,
|
|
169
|
+
{
|
|
170
|
+
position: at,
|
|
171
|
+
entries: frame.entries
|
|
172
|
+
}
|
|
173
|
+
] : [
|
|
174
|
+
{
|
|
175
|
+
position: at,
|
|
176
|
+
entries: frame.entries
|
|
177
|
+
}
|
|
178
|
+
];
|
|
179
|
+
lines.set(frame.authority, {
|
|
180
|
+
logEpoch: line.logEpoch,
|
|
181
|
+
frames: next.length > HELD_POSITIONS_MAX ? [] : next
|
|
182
|
+
});
|
|
183
|
+
} else {
|
|
184
|
+
interrupt(frame.authority);
|
|
185
|
+
}
|
|
186
|
+
announce(frame.authority, {
|
|
187
|
+
position: frame.position,
|
|
188
|
+
logEpoch: frame.log_epoch
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
conversations: {
|
|
193
|
+
view (next) {
|
|
194
|
+
const open = new Set(next);
|
|
195
|
+
for (const conversation of subscribedConversations){
|
|
196
|
+
if (!open.has(conversation)) subscribedConversations.delete(conversation);
|
|
197
|
+
}
|
|
198
|
+
viewed = [
|
|
199
|
+
...next
|
|
200
|
+
];
|
|
201
|
+
subscribe();
|
|
202
|
+
},
|
|
203
|
+
observe (notify) {
|
|
204
|
+
conversationObservers.add(notify);
|
|
205
|
+
if (!listening) {
|
|
206
|
+
listening = true;
|
|
207
|
+
stream.observe(receive);
|
|
208
|
+
}
|
|
209
|
+
return ()=>{
|
|
210
|
+
conversationObservers.delete(notify);
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
track (entries) {
|
|
215
|
+
locators.clear();
|
|
216
|
+
authorities.clear();
|
|
217
|
+
for (const entry of entries){
|
|
218
|
+
locators.set(entry.authority, [
|
|
219
|
+
...locators.get(entry.authority) ?? [],
|
|
220
|
+
entry.locator
|
|
221
|
+
]);
|
|
222
|
+
authorities.set(entry.locator, entry.authority);
|
|
223
|
+
if (lines.get(entry.authority)?.logEpoch !== entry.logEpoch) {
|
|
224
|
+
lines.set(entry.authority, {
|
|
225
|
+
logEpoch: entry.logEpoch,
|
|
226
|
+
frames: []
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
for (const authority of lines.keys()){
|
|
231
|
+
if (!locators.has(authority)) lines.delete(authority);
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
select (named) {
|
|
235
|
+
selected = [
|
|
236
|
+
...named
|
|
237
|
+
];
|
|
238
|
+
subscribe();
|
|
239
|
+
},
|
|
240
|
+
observe (notify) {
|
|
241
|
+
observers.add(notify);
|
|
242
|
+
if (!listening) {
|
|
243
|
+
listening = true;
|
|
244
|
+
stream.observe(receive);
|
|
245
|
+
}
|
|
246
|
+
return ()=>{
|
|
247
|
+
observers.delete(notify);
|
|
248
|
+
};
|
|
249
|
+
},
|
|
250
|
+
advance (tracked, from) {
|
|
251
|
+
const line = lines.get(tracked.authority);
|
|
252
|
+
const start = position(from.position);
|
|
253
|
+
if (line === undefined || start === null || line.logEpoch !== from.logEpoch) return null;
|
|
254
|
+
const at = line.frames.findIndex((frame)=>frame.position === start + 1n);
|
|
255
|
+
if (at === -1) return null;
|
|
256
|
+
const pending = line.frames.slice(at);
|
|
257
|
+
const documents = {};
|
|
258
|
+
const revisions = {};
|
|
259
|
+
const removals = [];
|
|
260
|
+
for (const frame of pending){
|
|
261
|
+
for (const entry of frame.entries){
|
|
262
|
+
if (!selects(tracked, entry.path)) continue;
|
|
263
|
+
if (entry.kind === 'removed') {
|
|
264
|
+
delete documents[entry.path];
|
|
265
|
+
delete revisions[entry.path];
|
|
266
|
+
if (!removals.includes(entry.path)) removals.push(entry.path);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (entry.text === undefined) return null;
|
|
270
|
+
if (mode === 'credential' && entry.revision === undefined) return null;
|
|
271
|
+
documents[entry.path] = entry.text;
|
|
272
|
+
if (entry.revision !== undefined) revisions[entry.path] = entry.revision;
|
|
273
|
+
const removed = removals.indexOf(entry.path);
|
|
274
|
+
if (removed !== -1) removals.splice(removed, 1);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const last = pending.at(-1);
|
|
278
|
+
if (last === undefined) return null;
|
|
279
|
+
lines.set(tracked.authority, {
|
|
280
|
+
logEpoch: line.logEpoch,
|
|
281
|
+
frames: pending
|
|
282
|
+
});
|
|
283
|
+
return {
|
|
284
|
+
kind: 'net-advancement',
|
|
285
|
+
roomVersion: roomVersion({
|
|
286
|
+
position: last.position.toString(),
|
|
287
|
+
logEpoch: line.logEpoch
|
|
288
|
+
}),
|
|
289
|
+
documents,
|
|
290
|
+
revisions,
|
|
291
|
+
binaryTargets: [],
|
|
292
|
+
removals: removals.sort()
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/workspace/packages/mdruntime-adapter/src/stream.ts"],"sourcesContent":["import type {\n ConversationEvent,\n RefreshPage,\n RoomVersionNotification,\n SelectedRooms,\n ViewedConversations,\n} from '@agentshouse/mdruntime';\nimport { actionOutcome, HISTORY_PAGE, readConversationHistory } from './actions.js';\nimport type { TrackedAuthority } from './discovery.js';\nimport { selects } from './read.js';\nimport { PRIVATE_AUTHORITY, type HouseDoor, type HouseStreamAuthority } from './transport.js';\nimport type { HouseMode, HouseStreamEntry, HouseStreamFrame } from './transport.js';\nimport { roomVersion, type LogPosition } from './version.js';\n\nconst HELD_POSITIONS_MAX = 256;\n\ntype HeldFrame = {\n position: bigint;\n entries: readonly HouseStreamEntry[];\n};\n\ntype HeldLine = {\n logEpoch: string;\n frames: readonly HeldFrame[];\n};\n\nexport type HouseNotifications = SelectedRooms & {\n track(authorities: readonly TrackedAuthority[]): void;\n advance(tracked: TrackedAuthority, from: LogPosition): RefreshPage | null;\n conversations: ViewedConversations;\n};\n\nfunction position(value: string): bigint | null {\n if (!/^(?:0|[1-9][0-9]*)$/.test(value)) return null;\n return BigInt(value);\n}\n\nfunction messageTurn(message: unknown): string | null {\n if (typeof message !== 'object' || message === null) return null;\n const turn = (message as { message_id?: unknown }).message_id;\n return typeof turn === 'string' ? turn : null;\n}\n\nexport function houseNotifications(transport: HouseDoor, mode: HouseMode): HouseNotifications {\n const stream = transport.stream;\n const lines = new Map<string, HeldLine>();\n const locators = new Map<string, string[]>();\n const authorities = new Map<string, string>();\n const observers = new Set<(notification: RoomVersionNotification) => void>();\n const conversationObservers = new Set<(event: ConversationEvent) => void>();\n const subscribedConversations = new Set<string>();\n let selected: readonly string[] = [];\n let viewed: readonly string[] = [];\n let listening = false;\n\n function subscribe() {\n const named: HouseStreamAuthority[] = [];\n const rooms = new Set<string>();\n for (const locator of selected) {\n const authority = authorities.get(locator);\n if (authority === undefined || authority === PRIVATE_AUTHORITY) continue;\n rooms.add(authority);\n }\n for (const room of rooms) named.push({ kind: 'room', room });\n if (authorities.has(PRIVATE_AUTHORITY)) named.push({ kind: 'private' });\n for (const conversation of viewed) {\n named.push({ kind: 'conversation', conversation });\n }\n stream.subscribe(named);\n }\n\n function emitConversation(event: ConversationEvent) {\n if (!viewed.includes(event.conversation)) return;\n for (const observer of conversationObservers) observer(event);\n }\n\n async function catchUp(conversation: string, history: boolean) {\n const viewedAnswer = await transport.door('/door/conversations/view', {\n conversation_id: conversation,\n });\n const summary = actionOutcome(viewedAnswer, 'conversations/view');\n if (\n summary.kind === 'action' &&\n typeof summary.result === 'object' &&\n summary.result !== null\n ) {\n emitConversation({\n kind: 'session-summary',\n conversation,\n summary: structuredClone('session' in summary.result ? summary.result.session : null),\n });\n }\n if (!history) return;\n const heldHistory = await readConversationHistory(transport, conversation);\n if ('outcome' in heldHistory) return;\n const newest = heldHistory.messages.slice(-HISTORY_PAGE);\n for (const entry of newest) {\n const turn = messageTurn(entry);\n if (turn === null) return;\n emitConversation({\n kind: 'accepted-message',\n conversation,\n message: { turn, message: structuredClone(entry) },\n });\n }\n }\n\n function announce(authority: string, at: LogPosition) {\n const version = roomVersion(at);\n for (const locator of locators.get(authority) ?? []) {\n for (const observer of observers) observer({ locator, roomVersion: version });\n }\n }\n\n function interrupt(authority: string) {\n const line = lines.get(authority);\n if (line !== undefined) lines.set(authority, { logEpoch: line.logEpoch, frames: [] });\n }\n\n function resubscribed(authority: string, position?: string, logEpoch?: string) {\n if (position === undefined || logEpoch === undefined) {\n interrupt(authority);\n return;\n }\n const held = lines.get(authority)?.logEpoch;\n lines.set(authority, { logEpoch, frames: [] });\n if (held !== logEpoch) announce(authority, { position, logEpoch });\n }\n\n function receive(frame: HouseStreamFrame) {\n if (frame.type === 'draft') {\n emitConversation({\n kind: 'growing-text',\n conversation: frame.conversation_id,\n turn: frame.turn_id,\n text: frame.text,\n });\n return;\n }\n if (frame.type === 'message') {\n const turn = messageTurn(frame.message);\n if (turn === null) return;\n emitConversation({\n kind: 'accepted-message',\n conversation: frame.conversation_id,\n message: { turn, message: structuredClone(frame.message) },\n });\n return;\n }\n if (frame.type === 'session') {\n emitConversation({\n kind: 'session-summary',\n conversation: frame.conversation_id,\n summary: structuredClone(frame.summary),\n });\n return;\n }\n if (frame.type === 'subscribed' && viewed.includes(frame.authority)) {\n const reconnect = subscribedConversations.has(frame.authority);\n subscribedConversations.add(frame.authority);\n void catchUp(frame.authority, reconnect);\n return;\n }\n if (frame.type === 'subscribed') {\n resubscribed(frame.authority, frame.position, frame.log_epoch);\n return;\n }\n if (frame.type !== 'entries') {\n interrupt(frame.authority);\n return;\n }\n const at = position(frame.position);\n if (at === null) {\n interrupt(frame.authority);\n return;\n }\n const line = lines.get(frame.authority);\n if (line?.logEpoch === frame.log_epoch) {\n const last = line.frames.at(-1);\n const continued = last !== undefined && last.position + 1n === at;\n const next = continued\n ? [...line.frames, { position: at, entries: frame.entries }]\n : [{ position: at, entries: frame.entries }];\n lines.set(frame.authority, {\n logEpoch: line.logEpoch,\n frames: next.length > HELD_POSITIONS_MAX ? [] : next,\n });\n } else {\n interrupt(frame.authority);\n }\n announce(frame.authority, { position: frame.position, logEpoch: frame.log_epoch });\n }\n\n return {\n conversations: {\n view(next) {\n const open = new Set(next);\n for (const conversation of subscribedConversations) {\n if (!open.has(conversation)) subscribedConversations.delete(conversation);\n }\n viewed = [...next];\n subscribe();\n },\n observe(notify) {\n conversationObservers.add(notify);\n if (!listening) {\n listening = true;\n stream.observe(receive);\n }\n return () => {\n conversationObservers.delete(notify);\n };\n },\n },\n track(entries) {\n locators.clear();\n authorities.clear();\n for (const entry of entries) {\n locators.set(entry.authority, [...(locators.get(entry.authority) ?? []), entry.locator]);\n authorities.set(entry.locator, entry.authority);\n if (lines.get(entry.authority)?.logEpoch !== entry.logEpoch) {\n lines.set(entry.authority, { logEpoch: entry.logEpoch, frames: [] });\n }\n }\n for (const authority of lines.keys()) {\n if (!locators.has(authority)) lines.delete(authority);\n }\n },\n select(named) {\n selected = [...named];\n subscribe();\n },\n observe(notify) {\n observers.add(notify);\n if (!listening) {\n listening = true;\n stream.observe(receive);\n }\n return () => {\n observers.delete(notify);\n };\n },\n advance(tracked, from) {\n const line = lines.get(tracked.authority);\n const start = position(from.position);\n if (line === undefined || start === null || line.logEpoch !== from.logEpoch) return null;\n const at = line.frames.findIndex((frame) => frame.position === start + 1n);\n if (at === -1) return null;\n const pending = line.frames.slice(at);\n const documents: Record<string, string> = {};\n const revisions: Record<string, string> = {};\n const removals: string[] = [];\n for (const frame of pending) {\n for (const entry of frame.entries) {\n if (!selects(tracked, entry.path)) continue;\n if (entry.kind === 'removed') {\n delete documents[entry.path];\n delete revisions[entry.path];\n if (!removals.includes(entry.path)) removals.push(entry.path);\n continue;\n }\n if (entry.text === undefined) return null;\n if (mode === 'credential' && entry.revision === undefined) return null;\n documents[entry.path] = entry.text;\n if (entry.revision !== undefined) revisions[entry.path] = entry.revision;\n const removed = removals.indexOf(entry.path);\n if (removed !== -1) removals.splice(removed, 1);\n }\n }\n const last = pending.at(-1);\n if (last === undefined) return null;\n lines.set(tracked.authority, { logEpoch: line.logEpoch, frames: pending });\n return {\n kind: 'net-advancement',\n roomVersion: roomVersion({ position: last.position.toString(), logEpoch: line.logEpoch }),\n documents,\n revisions,\n binaryTargets: [],\n removals: removals.sort(),\n };\n },\n };\n}\n"],"names":["actionOutcome","HISTORY_PAGE","readConversationHistory","selects","PRIVATE_AUTHORITY","roomVersion","HELD_POSITIONS_MAX","position","value","test","BigInt","messageTurn","message","turn","message_id","houseNotifications","transport","mode","stream","lines","Map","locators","authorities","observers","Set","conversationObservers","subscribedConversations","selected","viewed","listening","subscribe","named","rooms","locator","authority","get","undefined","add","room","push","kind","has","conversation","emitConversation","event","includes","observer","catchUp","history","viewedAnswer","door","conversation_id","summary","result","structuredClone","session","heldHistory","newest","messages","slice","entry","announce","at","version","interrupt","line","set","logEpoch","frames","resubscribed","held","receive","frame","type","turn_id","text","reconnect","log_epoch","last","continued","next","entries","length","conversations","view","open","delete","observe","notify","track","clear","keys","select","advance","tracked","from","start","findIndex","pending","documents","revisions","removals","path","revision","removed","indexOf","splice","toString","binaryTargets","sort"],"mappings":"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"}
|