@agentshouse/mdruntime 0.1.0-ce531b51ff088 → 0.1.0-ce5c5bb29be5a

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.
Files changed (185) hide show
  1. package/README.md +24 -11
  2. package/dist/adapter.d.ts +172 -48
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js +1 -9
  5. package/dist/attached-model.d.ts +15 -0
  6. package/dist/attached-model.d.ts.map +1 -0
  7. package/dist/attached-model.js +81 -0
  8. package/dist/attempt.d.ts +16 -0
  9. package/dist/attempt.d.ts.map +1 -0
  10. package/dist/attempt.js +70 -0
  11. package/dist/binary.d.ts +18 -0
  12. package/dist/binary.d.ts.map +1 -0
  13. package/dist/binary.js +8 -0
  14. package/dist/bootstrap.d.ts +36 -6
  15. package/dist/bootstrap.d.ts.map +1 -1
  16. package/dist/bootstrap.js +199 -48
  17. package/dist/chain.d.ts +11 -0
  18. package/dist/chain.d.ts.map +1 -0
  19. package/dist/chain.js +64 -0
  20. package/dist/change-set.d.ts +9 -14
  21. package/dist/change-set.d.ts.map +1 -1
  22. package/dist/change-set.js +11 -56
  23. package/dist/change.d.ts +45 -0
  24. package/dist/change.d.ts.map +1 -1
  25. package/dist/change.js +34 -0
  26. package/dist/client.d.ts +37 -15
  27. package/dist/client.d.ts.map +1 -1
  28. package/dist/client.js +159 -29
  29. package/dist/collection.d.ts +12 -14
  30. package/dist/collection.d.ts.map +1 -1
  31. package/dist/collection.js +52 -56
  32. package/dist/compile.d.ts +16 -0
  33. package/dist/compile.d.ts.map +1 -0
  34. package/dist/compile.js +773 -0
  35. package/dist/connection.d.ts +67 -28
  36. package/dist/connection.d.ts.map +1 -1
  37. package/dist/connection.js +3911 -1044
  38. package/dist/conversation.d.ts +59 -18
  39. package/dist/conversation.d.ts.map +1 -1
  40. package/dist/conversation.js +849 -248
  41. package/dist/digest.d.ts +7 -0
  42. package/dist/digest.d.ts.map +1 -0
  43. package/dist/digest.js +113 -0
  44. package/dist/durability.d.ts +4 -1
  45. package/dist/durability.d.ts.map +1 -1
  46. package/dist/durability.js +5 -0
  47. package/dist/entry.d.ts +20 -0
  48. package/dist/entry.d.ts.map +1 -0
  49. package/dist/entry.js +151 -0
  50. package/dist/expectation.d.ts +21 -0
  51. package/dist/expectation.d.ts.map +1 -0
  52. package/dist/expectation.js +70 -0
  53. package/dist/failure.d.ts +13 -0
  54. package/dist/failure.d.ts.map +1 -0
  55. package/dist/failure.js +19 -0
  56. package/dist/fence.d.ts +6 -0
  57. package/dist/fence.d.ts.map +1 -0
  58. package/dist/fence.js +10 -0
  59. package/dist/file.d.ts +2 -19
  60. package/dist/file.d.ts.map +1 -1
  61. package/dist/file.js +7 -122
  62. package/dist/fulltext.d.ts +27 -0
  63. package/dist/fulltext.d.ts.map +1 -0
  64. package/dist/fulltext.js +370 -0
  65. package/dist/host.d.ts +20 -2
  66. package/dist/host.d.ts.map +1 -1
  67. package/dist/host.js +166 -48
  68. package/dist/identity.d.ts +4 -0
  69. package/dist/identity.d.ts.map +1 -1
  70. package/dist/identity.js +16 -1
  71. package/dist/index.d.ts +20 -9
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +9 -0
  74. package/dist/live.d.ts +22 -0
  75. package/dist/live.d.ts.map +1 -0
  76. package/dist/live.js +124 -0
  77. package/dist/media.d.ts +8 -0
  78. package/dist/media.d.ts.map +1 -0
  79. package/dist/media.js +218 -0
  80. package/dist/memory.d.ts +22 -8
  81. package/dist/memory.d.ts.map +1 -1
  82. package/dist/memory.js +208 -47
  83. package/dist/messages.d.ts +28 -0
  84. package/dist/messages.d.ts.map +1 -0
  85. package/dist/messages.js +90 -0
  86. package/dist/model.d.ts +22 -14
  87. package/dist/model.d.ts.map +1 -1
  88. package/dist/model.js +13 -4
  89. package/dist/name.d.ts +4 -0
  90. package/dist/name.d.ts.map +1 -0
  91. package/dist/name.js +122 -0
  92. package/dist/observation.d.ts +21 -1
  93. package/dist/observation.d.ts.map +1 -1
  94. package/dist/observation.js +128 -17
  95. package/dist/open.d.ts +2 -0
  96. package/dist/open.d.ts.map +1 -0
  97. package/dist/open.js +1 -0
  98. package/dist/opened.d.ts +22 -0
  99. package/dist/opened.d.ts.map +1 -0
  100. package/dist/opened.js +107 -0
  101. package/dist/outcome.d.ts +72 -5
  102. package/dist/outcome.d.ts.map +1 -1
  103. package/dist/outcome.js +81 -1
  104. package/dist/overlay.d.ts +15 -5
  105. package/dist/overlay.d.ts.map +1 -1
  106. package/dist/overlay.js +136 -180
  107. package/dist/paths.d.ts +1 -1
  108. package/dist/paths.d.ts.map +1 -1
  109. package/dist/paths.js +4 -16
  110. package/dist/query.d.ts +78 -7
  111. package/dist/query.d.ts.map +1 -1
  112. package/dist/query.js +126 -43
  113. package/dist/reach.d.ts +54 -0
  114. package/dist/reach.d.ts.map +1 -0
  115. package/dist/reach.js +448 -0
  116. package/dist/react.d.ts +43 -0
  117. package/dist/react.d.ts.map +1 -0
  118. package/dist/react.js +54 -0
  119. package/dist/readiness.d.ts +52 -0
  120. package/dist/readiness.d.ts.map +1 -0
  121. package/dist/readiness.js +27 -0
  122. package/dist/recovery.d.ts +26 -0
  123. package/dist/recovery.d.ts.map +1 -0
  124. package/dist/recovery.js +224 -0
  125. package/dist/refresh.d.ts +19 -7
  126. package/dist/refresh.d.ts.map +1 -1
  127. package/dist/refresh.js +125 -53
  128. package/dist/replica.d.ts +58 -33
  129. package/dist/replica.d.ts.map +1 -1
  130. package/dist/replica.js +320 -158
  131. package/dist/room-draft.d.ts +60 -10
  132. package/dist/room-draft.d.ts.map +1 -1
  133. package/dist/room-draft.js +227 -42
  134. package/dist/rows.d.ts +39 -34
  135. package/dist/rows.d.ts.map +1 -1
  136. package/dist/rows.js +195 -81
  137. package/dist/save.d.ts +74 -6
  138. package/dist/save.d.ts.map +1 -1
  139. package/dist/save.js +898 -181
  140. package/dist/search.d.ts +41 -29
  141. package/dist/search.d.ts.map +1 -1
  142. package/dist/search.js +37 -105
  143. package/dist/seed.d.ts +16 -0
  144. package/dist/seed.d.ts.map +1 -0
  145. package/dist/seed.js +75 -0
  146. package/dist/shared.d.ts +15 -0
  147. package/dist/shared.d.ts.map +1 -0
  148. package/dist/shared.js +421 -0
  149. package/dist/status.d.ts +7 -2
  150. package/dist/status.d.ts.map +1 -1
  151. package/dist/status.js +3 -9
  152. package/dist/store.d.ts +109 -59
  153. package/dist/store.d.ts.map +1 -1
  154. package/dist/store.js +323 -344
  155. package/dist/stored.d.ts +130 -0
  156. package/dist/stored.d.ts.map +1 -0
  157. package/dist/stored.js +560 -0
  158. package/dist/tables.d.ts +325 -0
  159. package/dist/tables.d.ts.map +1 -0
  160. package/dist/tables.js +578 -0
  161. package/dist/transfer.d.ts +0 -5
  162. package/dist/transfer.d.ts.map +1 -1
  163. package/dist/turn.d.ts +9 -0
  164. package/dist/turn.d.ts.map +1 -0
  165. package/dist/turn.js +75 -0
  166. package/dist/validation.d.ts +29 -0
  167. package/dist/validation.d.ts.map +1 -0
  168. package/dist/validation.js +101 -0
  169. package/dist/windows.d.ts +22 -0
  170. package/dist/windows.d.ts.map +1 -0
  171. package/dist/windows.js +89 -0
  172. package/dist/wire.d.ts +194 -19
  173. package/dist/wire.d.ts.map +1 -1
  174. package/dist/wire.js +90 -61
  175. package/dist/words.d.ts +19 -0
  176. package/dist/words.d.ts.map +1 -0
  177. package/dist/words.js +156 -0
  178. package/package.json +33 -10
  179. package/AGENTS.md +0 -207
  180. package/dist/attachment.d.ts +0 -3
  181. package/dist/attachment.d.ts.map +0 -1
  182. package/dist/attachment.js +0 -8
  183. package/dist/read-side.d.ts +0 -14
  184. package/dist/read-side.d.ts.map +0 -1
  185. package/dist/read-side.js +0 -371
package/dist/memory.js CHANGED
@@ -1,9 +1,11 @@
1
- import { ROOM_CONTRACT_VERSION, } from './adapter.js';
2
- import { MD_MODEL } from './collection.js';
3
1
  import { sameChange } from './overlay.js';
2
+ const ATTACHMENTS = 'attachments';
3
+ function lastName(path) {
4
+ return path.slice(path.lastIndexOf('/') + 1);
5
+ }
4
6
  const FIXTURE_RETENTION = {
5
7
  history: { kind: 'duration', seconds: 1 },
6
- outcome: 1,
8
+ outcome: 604_800,
7
9
  refreshHorizon: 1,
8
10
  };
9
11
  function declaredRetention(value) {
@@ -15,6 +17,14 @@ function declaredRetention(value) {
15
17
  }
16
18
  throw new Error('history retention duration must be a finite positive number of seconds');
17
19
  }
20
+ const MODEL_ABSENT = { kind: 'model-unavailable', reason: 'not-readable' };
21
+ function modelsOf(room) {
22
+ return { collection: room.model ?? MODEL_ABSENT };
23
+ }
24
+ function changedModels(room, from) {
25
+ const now = modelsOf(room);
26
+ return JSON.stringify(now) === JSON.stringify(modelsOf(from)) ? undefined : now;
27
+ }
18
28
  function named(source, paths) {
19
29
  const taken = {};
20
30
  for (const path of paths) {
@@ -31,8 +41,6 @@ async function resolveScript(answer, fallback, request) {
31
41
  }
32
42
  export function createMemoryAdapter(options = {}) {
33
43
  let rooms = options.rooms === undefined ? [] : [...options.rooms];
34
- const mdModel = options.mdModel ?? MD_MODEL;
35
- const supportedVersions = options.supportedVersions ?? [ROOM_CONTRACT_VERSION];
36
44
  const capabilities = options.capabilities ?? [];
37
45
  const providerLimits = options.providerLimits ?? [];
38
46
  const retention = declaredRetention(options.retention);
@@ -46,8 +54,12 @@ export function createMemoryAdapter(options = {}) {
46
54
  const scripted = new Map();
47
55
  const unsealed = new Map();
48
56
  const sealed = new Set();
57
+ const sentTurns = new Map();
49
58
  const historyPageSize = options.historyPageSize;
50
- let selected = [];
59
+ const attached = new Map();
60
+ const linked = new WeakMap();
61
+ let held = [];
62
+ let expiring = [];
51
63
  let replicated = [];
52
64
  let issued = 0;
53
65
  function scriptConversations(entries) {
@@ -76,6 +88,19 @@ export function createMemoryAdapter(options = {}) {
76
88
  const wanted = ordinals.get(`${locator}\u0000${target}`);
77
89
  return held !== undefined && wanted !== undefined && held >= wanted;
78
90
  }
91
+ function heldBlob(room, path) {
92
+ return attached.get(`${room.locator}\u0000${path}`) ?? room.blobs?.[path];
93
+ }
94
+ function freePath(room, name) {
95
+ const dot = name.lastIndexOf('.');
96
+ const stem = dot > 0 ? name.slice(0, dot) : name;
97
+ const extension = dot > 0 ? name.slice(dot) : '';
98
+ for (let count = 1;; count += 1) {
99
+ const path = `${ATTACHMENTS}/${count === 1 ? stem : `${stem}-${count}`}${extension}`;
100
+ if (heldBlob(room, path) === undefined && room.documents?.[path] === undefined)
101
+ return path;
102
+ }
103
+ }
79
104
  function retain(entries) {
80
105
  for (const room of entries) {
81
106
  note(room.locator, room);
@@ -89,37 +114,54 @@ export function createMemoryAdapter(options = {}) {
89
114
  return {
90
115
  name: room.name,
91
116
  locator: room.locator,
117
+ handle: room.handle,
92
118
  roomVersion: room.roomVersion,
93
119
  operations: room.operations,
94
120
  replica: room.replica,
95
- attachedModel: room.attachedModel,
96
121
  ...(room.typedSelection === undefined ? {} : { typedSelection: room.typedSelection }),
97
122
  providerOwnedPaths: room.providerOwnedPaths,
98
123
  };
99
124
  }
100
- function page(room, from) {
125
+ function page(room, after) {
101
126
  const paths = Object.keys(room.documents ?? {}).sort();
127
+ const opening = after === undefined;
128
+ const from = opening ? 0 : paths.filter((path) => path <= after).length;
102
129
  const size = pageSize ?? paths.length;
103
130
  const taken = paths.slice(from, from + size);
104
131
  const next = from + taken.length;
105
- const targets = from === 0 ? (room.binaryTargets ?? []) : [];
132
+ const targets = opening ? Object.keys(room.binaryFiles ?? {}) : [];
106
133
  return {
107
134
  kind: 'bootstrap',
108
135
  roomVersion: room.roomVersion,
136
+ ...(opening ? { models: modelsOf(room) } : {}),
109
137
  documents: named(room.documents ?? {}, taken),
110
- revisions: named(room.revisions ?? {}, taken),
138
+ revisions: named(room.revisions ?? {}, [...taken, ...targets]),
139
+ ...(room.fileIds === undefined
140
+ ? {}
141
+ : { fileIds: named(room.fileIds, [...taken, ...targets]) }),
111
142
  changes: named(room.changes ?? {}, [...taken, ...targets]),
112
- binaryTargets: targets,
113
- ...(from === 0 && room.attachments !== undefined ? { attachments: room.attachments } : {}),
114
- ...(next < paths.length ? { pageToken: String(next) } : {}),
143
+ binaryFiles: named(room.binaryFiles ?? {}, targets),
144
+ ...(opening && room.folders !== undefined ? { folders: room.folders } : {}),
145
+ ...(next < paths.length ? { pageToken: taken.at(-1) } : {}),
146
+ };
147
+ }
148
+ function foldersMoved(room, from) {
149
+ const now = new Set(room.folders ?? []);
150
+ const before = new Set(from.folders ?? []);
151
+ const folders = [...now].filter((folder) => !before.has(folder)).sort();
152
+ const folderRemovals = [...before].filter((folder) => !now.has(folder)).sort();
153
+ return {
154
+ ...(folders.length === 0 ? {} : { folders }),
155
+ ...(folderRemovals.length === 0 ? {} : { folderRemovals }),
115
156
  };
116
157
  }
117
158
  function advancement(room, from, at) {
118
159
  const current = room.documents ?? {};
119
160
  const previous = from.documents ?? {};
120
- const currentTargets = new Set(room.binaryTargets ?? []);
121
- const previousTargets = new Set(from.binaryTargets ?? []);
161
+ const currentTargets = new Set(Object.keys(room.binaryFiles ?? {}));
162
+ const previousTargets = new Set(Object.keys(from.binaryFiles ?? {}));
122
163
  const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
164
+ room.fileIds?.[path] !== from.fileIds?.[path] ||
123
165
  !sameChange(room.changes?.[path], from.changes?.[path]);
124
166
  const changed = Object.keys(current)
125
167
  .filter((path) => current[path] !== previous[path] || headMoved(path))
@@ -134,22 +176,25 @@ export function createMemoryAdapter(options = {}) {
134
176
  const targets = opening
135
177
  ? [...currentTargets].filter((target) => !previousTargets.has(target) || headMoved(target))
136
178
  : [];
137
- const attachments = room.attachments ?? [];
138
- const declared = opening && JSON.stringify(attachments) !== JSON.stringify(from.attachments ?? []);
179
+ const models = opening ? changedModels(room, from) : undefined;
139
180
  return {
140
181
  kind: 'net-advancement',
141
182
  roomVersion: room.roomVersion,
183
+ ...(models === undefined ? {} : { models }),
142
184
  documents: named(current, taken),
143
- revisions: named(room.revisions ?? {}, taken),
185
+ revisions: named(room.revisions ?? {}, [...taken, ...targets]),
186
+ ...(room.fileIds === undefined
187
+ ? {}
188
+ : { fileIds: named(room.fileIds, [...taken, ...targets]) }),
144
189
  changes: named(room.changes ?? {}, [...taken, ...targets]),
145
- binaryTargets: targets,
190
+ binaryFiles: named(room.binaryFiles ?? {}, targets),
191
+ ...(opening ? foldersMoved(room, from) : {}),
146
192
  removals: opening
147
193
  ? [
148
194
  ...Object.keys(previous).filter((path) => !(path in current) && !currentTargets.has(path)),
149
195
  ...[...previousTargets].filter((target) => !currentTargets.has(target) && !(target in current)),
150
196
  ].sort()
151
197
  : [],
152
- ...(declared ? { attachments } : {}),
153
198
  ...(pageToken === undefined ? {} : { pageToken }),
154
199
  };
155
200
  }
@@ -170,7 +215,7 @@ export function createMemoryAdapter(options = {}) {
170
215
  function historiesOf(input) {
171
216
  const asked = input?.conversations;
172
217
  if (!Array.isArray(asked))
173
- return { kind: 'rejected', code: 'invalid_request', fields: {} };
218
+ return { kind: 'rejected', code: 'invalid_request', fields: {}, retryable: false };
174
219
  const histories = [];
175
220
  for (const entry of asked) {
176
221
  const conversation = typeof entry.conversation === 'string' ? scripted.get(entry.conversation) : undefined;
@@ -198,21 +243,32 @@ export function createMemoryAdapter(options = {}) {
198
243
  const named = typeof input.conversation === 'string' ? input.conversation : '';
199
244
  const conversation = scripted.get(named);
200
245
  if (conversation === undefined) {
201
- return { kind: 'rejected', code: 'unknown-conversation', fields: { conversation: named } };
246
+ return {
247
+ kind: 'rejected',
248
+ code: 'unknown-conversation',
249
+ fields: { conversation: named },
250
+ retryable: false,
251
+ };
202
252
  }
203
253
  const outcome = conversation.outcomes?.[name];
204
254
  if (outcome !== undefined)
205
255
  return outcome;
206
256
  if (name === 'conversation.send') {
257
+ const operation = typeof input.operation_id === 'string' ? input.operation_id : null;
258
+ const answered = operation === null ? undefined : sentTurns.get(operation);
259
+ if (answered !== undefined)
260
+ return { kind: 'action', result: { turn: answered } };
207
261
  issued += 1;
208
262
  const turn = `turn-${issued}`;
209
263
  unsealed.set(turn, named);
264
+ if (operation !== null)
265
+ sentTurns.set(operation, turn);
210
266
  return { kind: 'action', result: { turn } };
211
267
  }
212
268
  if (name === 'conversation.cancel') {
213
269
  const turn = typeof input.turn === 'string' ? input.turn : '';
214
270
  if (sealed.has(turn) || !unsealed.has(turn)) {
215
- return { kind: 'rejected', code: 'turn-sealed', fields: { turn } };
271
+ return { kind: 'rejected', code: 'turn-sealed', fields: { turn }, retryable: false };
216
272
  }
217
273
  unsealed.delete(turn);
218
274
  return { kind: 'action', result: { turn, cancelled: true } };
@@ -221,18 +277,26 @@ export function createMemoryAdapter(options = {}) {
221
277
  scripted.delete(named);
222
278
  return { kind: 'action', result: { conversation: named } };
223
279
  }
280
+ function announceList() {
281
+ const entries = [...scripted.values()].flatMap(({ conversation, listed, messages = [] }) => listed === undefined
282
+ ? []
283
+ : [{ conversation, ...listed, newest: messages.at(-1)?.position ?? null }]);
284
+ for (const listener of listeners)
285
+ listener({ kind: 'list', entries });
286
+ }
224
287
  function discovery() {
225
288
  return {
226
289
  kind: 'discovery',
227
- supportedVersions,
228
- mdModel,
229
290
  rooms: rooms.map(declared),
230
291
  capabilities,
231
292
  providerLimits,
232
293
  retention,
294
+ ...(options.member === undefined ? {} : { member: options.member }),
233
295
  };
234
296
  }
235
297
  return {
298
+ ...(options.exhaustiveDiscovery === undefined ? {} : { exhaustiveDiscovery: true }),
299
+ ...(options.roomTypes === undefined ? {} : { roomTypes: options.roomTypes }),
236
300
  setRooms(next) {
237
301
  rooms = [...next];
238
302
  retain(rooms);
@@ -240,9 +304,28 @@ export function createMemoryAdapter(options = {}) {
240
304
  setConversations(next) {
241
305
  scriptConversations(next);
242
306
  },
243
- notifyRoomVersion(notification) {
307
+ open() {
308
+ announceList();
309
+ for (const observer of observers)
310
+ observer({ kind: 'opened' });
311
+ },
312
+ close({ revoked = false, lost = !revoked } = {}) {
244
313
  for (const observer of observers)
245
- observer(notification);
314
+ observer({ kind: 'closed', revoked, lost });
315
+ },
316
+ expire(locators) {
317
+ expiring = [...locators];
318
+ },
319
+ notifyRoomVersion({ locator, roomVersion }) {
320
+ for (const observer of observers)
321
+ observer({ kind: 'room-version', locator, roomVersion });
322
+ },
323
+ notifyAuthorityChanged(scope) {
324
+ for (const observer of observers) {
325
+ observer(scope === undefined
326
+ ? { kind: 'authority-changed' }
327
+ : { kind: 'authority-changed', scope });
328
+ }
246
329
  },
247
330
  notifyConversation(event) {
248
331
  if (event.kind === 'accepted-message') {
@@ -256,8 +339,8 @@ export function createMemoryAdapter(options = {}) {
256
339
  for (const observer of modeObservers)
257
340
  observer(mode);
258
341
  },
259
- selectedRooms() {
260
- return selected;
342
+ heldRooms() {
343
+ return held;
261
344
  },
262
345
  replicatedConversations() {
263
346
  return replicated;
@@ -281,12 +364,46 @@ export function createMemoryAdapter(options = {}) {
281
364
  };
282
365
  },
283
366
  },
284
- roomVersions: {
285
- select(locators) {
286
- selected = [...locators];
367
+ roomStream: {
368
+ hold(asked) {
369
+ held = asked.map((room) => room.locator);
370
+ const expired = expiring.filter((locator) => held.includes(locator));
371
+ expiring = [];
372
+ const moved = asked.flatMap((room) => {
373
+ const current = rooms.find((entry) => entry.locator === room.locator);
374
+ return current === undefined ||
375
+ expired.includes(room.locator) ||
376
+ current.roomVersion === room.roomVersion
377
+ ? []
378
+ : [{ locator: room.locator, roomVersion: current.roomVersion }];
379
+ });
380
+ queueMicrotask(() => {
381
+ for (const observer of observers) {
382
+ for (const room of moved)
383
+ observer({ kind: 'room-version', ...room });
384
+ observer({ kind: 'opening', expired });
385
+ }
386
+ });
387
+ },
388
+ reopen() {
389
+ queueMicrotask(() => {
390
+ for (const observer of observers) {
391
+ observer({ kind: 'closed', revoked: false, lost: false });
392
+ }
393
+ });
287
394
  },
288
395
  observe(notify) {
289
396
  observers.add(notify);
397
+ queueMicrotask(() => {
398
+ if (!observers.has(notify))
399
+ return;
400
+ if (options.unopened === true) {
401
+ notify({ kind: 'closed', revoked: false, lost: true });
402
+ return;
403
+ }
404
+ announceList();
405
+ notify({ kind: 'opened' });
406
+ });
290
407
  return () => {
291
408
  observers.delete(notify);
292
409
  };
@@ -298,13 +415,6 @@ export function createMemoryAdapter(options = {}) {
298
415
  else
299
416
  scripts[operation] = answer;
300
417
  },
301
- async model(_authorization, request) {
302
- return resolveScript(scripts.model, () => {
303
- const room = rooms.find((entry) => entry.locator === request.locator);
304
- const answer = request.attached === 'collection' ? room?.model : room?.selectionModel;
305
- return answer ?? { kind: 'model-unavailable', reason: 'not-readable' };
306
- }, request);
307
- },
308
418
  async authorize() {
309
419
  return resolveScript(scripts.authorize, () => ({}), undefined);
310
420
  },
@@ -317,13 +427,21 @@ export function createMemoryAdapter(options = {}) {
317
427
  });
318
428
  },
319
429
  reached,
430
+ follows(locator, roomVersion, next) {
431
+ const scripted = scripts.follows;
432
+ if (typeof scripted === 'boolean')
433
+ return scripted;
434
+ if (scripted !== undefined)
435
+ return scripted(locator, roomVersion, next);
436
+ return true;
437
+ },
320
438
  async bootstrap(_authorization, request) {
321
439
  return resolveScript(scripts.bootstrap, () => {
322
440
  const room = rooms.find((entry) => entry.locator === request.locator);
323
441
  if (room === undefined) {
324
442
  return { kind: 'room-not-readable', locator: request.locator };
325
443
  }
326
- return page(room, request.pageToken === undefined ? 0 : Number(request.pageToken));
444
+ return page(room, request.pageToken);
327
445
  }, request).then((answer) => note(request.locator, answer));
328
446
  },
329
447
  async refresh(_authorization, request) {
@@ -341,10 +459,6 @@ export function createMemoryAdapter(options = {}) {
341
459
  }
342
460
  return advancement(continuation.room, continuation.from, continuation.at);
343
461
  }
344
- if (request.minPosition !== undefined &&
345
- !reached(room.locator, room.roomVersion, request.minPosition)) {
346
- return { kind: 'retryable-refusal', code: 'replica_behind', fields: {} };
347
- }
348
462
  if (request.fromRoomVersion === room.roomVersion) {
349
463
  return { kind: 'still-current' };
350
464
  }
@@ -360,8 +474,20 @@ export function createMemoryAdapter(options = {}) {
360
474
  if (room === undefined) {
361
475
  return { kind: 'room-not-readable', locator: request.locator };
362
476
  }
363
- return { kind: 'rejected', code: 'unscripted-mutation', fields: {}, affected: {} };
364
- }, request).then((answer) => note(request.locator, answer));
477
+ return {
478
+ kind: 'rejected',
479
+ code: 'unscripted-mutation',
480
+ fields: {},
481
+ retryable: false,
482
+ affected: {},
483
+ };
484
+ }, request).then((answer) => {
485
+ const destination = request.changeBatch.between?.destination.room;
486
+ if (answer.kind === 'accepted' && answer.destination !== undefined && destination) {
487
+ note(destination, answer.destination);
488
+ }
489
+ return note(request.locator, answer);
490
+ });
365
491
  },
366
492
  async history(_authorization, request) {
367
493
  return resolveScript(scripts.history, () => {
@@ -375,11 +501,46 @@ export function createMemoryAdapter(options = {}) {
375
501
  };
376
502
  }, request);
377
503
  },
504
+ async binary(_authorization, request) {
505
+ return resolveScript(scripts.binary, () => {
506
+ const room = rooms.find((entry) => entry.locator === request.locator);
507
+ if (room === undefined)
508
+ return { kind: 'room-not-readable', locator: request.locator };
509
+ const blob = heldBlob(room, request.path);
510
+ return blob === undefined
511
+ ? { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false }
512
+ : { kind: 'binary', body: blob.stream(), mediaType: blob.type };
513
+ }, request);
514
+ },
515
+ async link(_authorization, request) {
516
+ return resolveScript(scripts.link, () => {
517
+ const room = rooms.find((entry) => entry.locator === request.locator);
518
+ if (room === undefined)
519
+ return { kind: 'room-not-readable', locator: request.locator };
520
+ const blob = heldBlob(room, request.path);
521
+ if (blob === undefined) {
522
+ return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
523
+ }
524
+ const url = linked.get(blob) ?? URL.createObjectURL(blob);
525
+ linked.set(blob, url);
526
+ return { kind: 'link', url, name: lastName(request.path), mediaType: blob.type };
527
+ }, request);
528
+ },
529
+ async attach(_authorization, request) {
530
+ return resolveScript(scripts.attach, () => {
531
+ const room = rooms.find((entry) => entry.locator === request.locator);
532
+ if (room === undefined)
533
+ return { kind: 'room-not-readable', locator: request.locator };
534
+ const path = freePath(room, request.name);
535
+ attached.set(`${room.locator}\u0000${path}`, request.blob);
536
+ return { kind: 'attached', path, revision: `attached-${attached.size}` };
537
+ }, request);
538
+ },
378
539
  async action(_authorization, request) {
379
540
  return resolveScript(scripts.action, () => {
380
541
  if (request.name.startsWith('conversation.'))
381
542
  return conversationAction(request);
382
- return { kind: 'rejected', code: 'unscripted-action', fields: {} };
543
+ return { kind: 'rejected', code: 'unscripted-action', fields: {}, retryable: false };
383
544
  }, request).then((answer) => {
384
545
  if (answer.kind === 'action' && answer.at !== undefined)
385
546
  note(answer.at.locator, answer.at);
@@ -0,0 +1,28 @@
1
+ import type { AcceptedMessage } from './adapter.js';
2
+ import type { Connection } from './tables.js';
3
+ export declare const MESSAGE_TABLES: readonly string[];
4
+ export type HeldConversation = {
5
+ readonly conversation: string;
6
+ readonly read: string | null | undefined;
7
+ readonly partial: boolean;
8
+ };
9
+ export type MessageWindow = {
10
+ readonly messages: AcceptedMessage[];
11
+ readonly more: boolean;
12
+ };
13
+ export type ConversationWrite = {
14
+ readonly conversation: string;
15
+ readonly messages: readonly AcceptedMessage[];
16
+ readonly read?: {
17
+ readonly at: string | null;
18
+ readonly partial: boolean;
19
+ };
20
+ };
21
+ export declare function heldConversations(connection: Connection): HeldConversation[];
22
+ export declare function keptMessages(connection: Connection, { conversation, messages, read }: ConversationWrite): null;
23
+ export declare function messageWindow(connection: Connection, conversation: string, limit: number, before: readonly [string, string] | null): MessageWindow;
24
+ export declare function messageCount(connection: Connection, conversation: string): number;
25
+ export declare function turnArrived(connection: Connection, conversation: string, turn: string): boolean;
26
+ export declare function droppedMessages(connection: Connection, conversations: readonly string[]): void;
27
+ export declare function forgottenMessages(connection: Connection): void;
28
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAE1D,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAM3C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3E,CAAC;AAMF,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB,EAAE,CAmB5E;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,iBAAiB,GAClD,IAAI,CAoCN;AAYD,wBAAgB,aAAa,CAC3B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GACvC,aAAa,CAUf;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAMjF;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAO/F;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAW9F;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAG9D"}
@@ -0,0 +1,90 @@
1
+ import { indexMessage, unindexMessages } from './fulltext.js';
2
+ export const MESSAGE_TABLES = [
3
+ 'CREATE TABLE conversation_reads (conversation TEXT PRIMARY KEY, read TEXT, partial INTEGER NOT NULL) WITHOUT ROWID',
4
+ 'CREATE TABLE conversation_messages (id INTEGER PRIMARY KEY, conversation TEXT NOT NULL, identity TEXT NOT NULL, turn TEXT NOT NULL, position TEXT NOT NULL, message TEXT NOT NULL, text TEXT NOT NULL)',
5
+ 'CREATE UNIQUE INDEX conversation_messages_identity ON conversation_messages (conversation, identity)',
6
+ 'CREATE INDEX conversation_messages_position ON conversation_messages (conversation, position, identity)',
7
+ 'CREATE INDEX conversation_messages_turn ON conversation_messages (conversation, turn)',
8
+ ];
9
+ function text(value) {
10
+ return typeof value === 'string' ? value : String(value);
11
+ }
12
+ export function heldConversations(connection) {
13
+ const held = new Map();
14
+ for (const row of connection.rows('SELECT conversation, read, partial FROM conversation_reads')) {
15
+ held.set(text(row.conversation), {
16
+ conversation: text(row.conversation),
17
+ read: row.read === null ? null : text(row.read),
18
+ partial: Number(row.partial) === 1,
19
+ });
20
+ }
21
+ for (const row of connection.rows('SELECT DISTINCT conversation FROM conversation_messages WHERE conversation NOT IN (SELECT conversation FROM conversation_reads)')) {
22
+ held.set(text(row.conversation), {
23
+ conversation: text(row.conversation),
24
+ read: undefined,
25
+ partial: true,
26
+ });
27
+ }
28
+ return [...held.values()];
29
+ }
30
+ export function keptMessages(connection, { conversation, messages, read }) {
31
+ for (const message of messages) {
32
+ const [held] = connection.rows('SELECT id FROM conversation_messages WHERE conversation = ? AND identity = ?', [conversation, message.identity]);
33
+ const record = [
34
+ message.turn,
35
+ message.position,
36
+ JSON.stringify(message.message ?? null),
37
+ message.text,
38
+ ];
39
+ let id;
40
+ if (held === undefined) {
41
+ connection.run('INSERT INTO conversation_messages (conversation, identity, turn, position, message, text) VALUES (?, ?, ?, ?, ?, ?)', [conversation, message.identity, ...record]);
42
+ id = Number(connection.rows('SELECT last_insert_rowid() AS id')[0].id);
43
+ }
44
+ else {
45
+ id = Number(held.id);
46
+ unindexMessages(connection, [id]);
47
+ connection.run('UPDATE conversation_messages SET turn = ?, position = ?, message = ?, text = ? WHERE id = ?', [...record, id]);
48
+ }
49
+ indexMessage(connection, id, message.text);
50
+ }
51
+ if (read !== undefined) {
52
+ connection.run('INSERT OR REPLACE INTO conversation_reads (conversation, read, partial) VALUES (?, ?, ?)', [conversation, read.at, read.partial ? 1 : 0]);
53
+ }
54
+ return null;
55
+ }
56
+ function accepted(row) {
57
+ return {
58
+ identity: text(row.identity),
59
+ turn: text(row.turn),
60
+ position: text(row.position),
61
+ text: text(row.text),
62
+ message: JSON.parse(text(row.message)),
63
+ };
64
+ }
65
+ export function messageWindow(connection, conversation, limit, before) {
66
+ const rows = connection.rows(`SELECT identity, turn, position, message, text FROM conversation_messages WHERE conversation = ?${before === null ? '' : ' AND (position < ? OR (position = ? AND identity < ?))'} ORDER BY position DESC, identity DESC LIMIT ?`, before === null
67
+ ? [conversation, limit + 1]
68
+ : [conversation, before[0], before[0], before[1], limit + 1]);
69
+ return { messages: rows.slice(0, limit).map(accepted).reverse(), more: rows.length > limit };
70
+ }
71
+ export function messageCount(connection, conversation) {
72
+ const [counted] = connection.rows('SELECT count(*) AS held FROM conversation_messages WHERE conversation = ?', [conversation]);
73
+ return Number(counted?.held ?? 0);
74
+ }
75
+ export function turnArrived(connection, conversation, turn) {
76
+ return (connection.rows('SELECT 1 FROM conversation_messages WHERE conversation = ? AND turn = ? LIMIT 1', [conversation, turn]).length > 0);
77
+ }
78
+ export function droppedMessages(connection, conversations) {
79
+ for (const conversation of conversations) {
80
+ unindexMessages(connection, connection
81
+ .rows('SELECT id FROM conversation_messages WHERE conversation = ?', [conversation])
82
+ .map((row) => Number(row.id)));
83
+ connection.run('DELETE FROM conversation_messages WHERE conversation = ?', [conversation]);
84
+ connection.run('DELETE FROM conversation_reads WHERE conversation = ?', [conversation]);
85
+ }
86
+ }
87
+ export function forgottenMessages(connection) {
88
+ connection.run('DELETE FROM conversation_messages');
89
+ connection.run('DELETE FROM conversation_reads');
90
+ }
package/dist/model.d.ts CHANGED
@@ -1,55 +1,63 @@
1
- import type { Definition, FieldSpec, SectionSpec, VerifiedModel } from '@agentshouse/mdmodel';
1
+ import type { Definition, ValueFacts, VerifiedModel } from '@agentshouse/mdmodel';
2
+ import type { Open } from './open.js';
2
3
  export type ModelIdentity = {
3
4
  identity: string;
4
5
  version: string;
5
6
  };
6
7
  export type ModelSnapshot = ModelIdentity & {
7
8
  schema: string | null;
9
+ revision: string | null;
8
10
  };
9
- export type ModelUnavailableReason = 'not-readable' | 'revoked' | 'not-acquired' | 'version-changed' | 'invalid';
11
+ export type ModelUnavailableReason = Open<'not-readable' | 'revoked' | 'not-acquired' | 'invalid'>;
10
12
  export type ModelResult = {
11
13
  kind: 'model';
12
14
  snapshot: ModelSnapshot;
13
15
  } | {
14
16
  kind: 'model-unavailable';
15
17
  reason: ModelUnavailableReason;
16
- } | {
17
- kind: 'transport-uncertainty';
18
- } | {
19
- kind: 'revoked-authorization';
20
- };
21
- export type MdType = {
22
- name: string;
23
- fields: Readonly<Record<string, FieldSpec>>;
24
- sections: Readonly<Record<string, SectionSpec>>;
25
18
  };
19
+ export type MdType = Definition;
26
20
  export type ModelState = {
27
21
  status: 'unavailable';
28
22
  reason: ModelUnavailableReason;
23
+ schema?: string | null;
24
+ revision?: string | null;
29
25
  } | {
30
26
  status: 'current' | 'cached';
31
27
  snapshot: ModelSnapshot;
32
28
  verifiedWith: ModelIdentity;
33
29
  types: VerifiedModel['types'];
34
30
  };
35
- export type TypesResult = {
31
+ export type StoredModel = Extract<ModelState, {
36
32
  status: 'unavailable';
33
+ }> | Omit<Extract<ModelState, {
34
+ status: 'current' | 'cached';
35
+ }>, 'types'>;
36
+ export type TypesResult = {
37
+ status: Open<'unavailable'>;
37
38
  reason: ModelUnavailableReason;
39
+ types: null;
40
+ schema?: string | null;
41
+ revision?: string | null;
38
42
  } | {
39
- status: 'current' | 'cached';
43
+ status: Open<'current' | 'cached'>;
40
44
  identity: string;
41
45
  version: string;
42
46
  verifiedWith: ModelIdentity;
43
47
  types: readonly MdType[];
48
+ schema: string | null;
49
+ revision: string | null;
44
50
  };
45
51
  export type ValidationReceipt = {
46
52
  identity: string;
47
53
  version: string;
48
- source: 'current' | 'cached';
54
+ source: Open<'current' | 'cached'>;
49
55
  };
50
56
  export declare const NO_MODEL: ModelState;
51
57
  export declare function definitionOf(state: ModelState, type: string | undefined): Definition | undefined;
52
58
  export declare function modelTypes(state: ModelState): TypesResult;
59
+ export declare function storedModel(state: ModelState): StoredModel;
53
60
  export declare function cached(state: ModelState): ModelState;
54
61
  export declare function sameModel(left: ModelIdentity, right: ModelIdentity): boolean;
62
+ export declare function referenceField(facts: ValueFacts | undefined): boolean;
55
63
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE9F,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AACtE,MAAM,MAAM,sBAAsB,GAC9B,cAAc,GACd,SAAS,GACT,cAAc,GACd,iBAAiB,GACjB,SAAS,CAAC;AACd,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,CAAC;AACtC,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAC5C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CACjD,CAAC;AACF,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACzD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B,CAAC;AACN,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACzD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,CAAC;AACN,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC;AACpG,eAAO,MAAM,QAAQ,EAAE,UAA8D,CAAC;AACtF,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAGhG;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAczD;AACD,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAEpD;AACD,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAE5E"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}