@agentshouse/mdruntime 0.1.0-alpha.5 → 0.1.0-alpha.50

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 (129) hide show
  1. package/AGENTS.md +210 -0
  2. package/README.md +44 -0
  3. package/dist/adapter.d.ts +253 -19
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js +2 -1
  6. package/dist/adapter.js.map +1 -1
  7. package/dist/attachment.d.ts +3 -0
  8. package/dist/attachment.d.ts.map +1 -0
  9. package/dist/attachment.js +11 -0
  10. package/dist/attachment.js.map +1 -0
  11. package/dist/bootstrap.d.ts +7 -6
  12. package/dist/bootstrap.d.ts.map +1 -1
  13. package/dist/bootstrap.js +30 -10
  14. package/dist/bootstrap.js.map +1 -1
  15. package/dist/change-set.d.ts +33 -0
  16. package/dist/change-set.d.ts.map +1 -0
  17. package/dist/change-set.js +95 -0
  18. package/dist/change-set.js.map +1 -0
  19. package/dist/change.d.ts +10 -0
  20. package/dist/change.d.ts.map +1 -1
  21. package/dist/change.js.map +1 -1
  22. package/dist/client.d.ts +75 -0
  23. package/dist/client.d.ts.map +1 -0
  24. package/dist/client.js +237 -0
  25. package/dist/client.js.map +1 -0
  26. package/dist/collection.d.ts +26 -12
  27. package/dist/collection.d.ts.map +1 -1
  28. package/dist/collection.js +78 -31
  29. package/dist/collection.js.map +1 -1
  30. package/dist/connection.d.ts +85 -28
  31. package/dist/connection.d.ts.map +1 -1
  32. package/dist/connection.js +1756 -510
  33. package/dist/connection.js.map +1 -1
  34. package/dist/conversation.d.ts +79 -0
  35. package/dist/conversation.d.ts.map +1 -0
  36. package/dist/conversation.js +635 -0
  37. package/dist/conversation.js.map +1 -0
  38. package/dist/durability.d.ts +8 -3
  39. package/dist/durability.d.ts.map +1 -1
  40. package/dist/durability.js +8 -62
  41. package/dist/durability.js.map +1 -1
  42. package/dist/file.d.ts +20 -0
  43. package/dist/file.d.ts.map +1 -0
  44. package/dist/file.js +149 -0
  45. package/dist/file.js.map +1 -0
  46. package/dist/host.d.ts +14 -0
  47. package/dist/host.d.ts.map +1 -0
  48. package/dist/host.js +213 -0
  49. package/dist/host.js.map +1 -0
  50. package/dist/identity.d.ts +3 -0
  51. package/dist/identity.d.ts.map +1 -0
  52. package/dist/identity.js +23 -0
  53. package/dist/identity.js.map +1 -0
  54. package/dist/index.d.ts +15 -7
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +1 -0
  57. package/dist/index.js.map +1 -1
  58. package/dist/memory.d.ts +19 -2
  59. package/dist/memory.d.ts.map +1 -1
  60. package/dist/memory.js +283 -24
  61. package/dist/memory.js.map +1 -1
  62. package/dist/model.d.ts +55 -0
  63. package/dist/model.d.ts.map +1 -0
  64. package/dist/model.js +36 -0
  65. package/dist/model.js.map +1 -0
  66. package/dist/observation.d.ts +25 -0
  67. package/dist/observation.d.ts.map +1 -0
  68. package/dist/observation.js +92 -0
  69. package/dist/observation.js.map +1 -0
  70. package/dist/outcome.d.ts +22 -18
  71. package/dist/outcome.d.ts.map +1 -1
  72. package/dist/outcome.js +1 -11
  73. package/dist/outcome.js.map +1 -1
  74. package/dist/overlay.d.ts +9 -2
  75. package/dist/overlay.d.ts.map +1 -1
  76. package/dist/overlay.js +145 -6
  77. package/dist/overlay.js.map +1 -1
  78. package/dist/paths.d.ts +0 -1
  79. package/dist/paths.d.ts.map +1 -1
  80. package/dist/paths.js +0 -4
  81. package/dist/paths.js.map +1 -1
  82. package/dist/query.d.ts +213 -0
  83. package/dist/query.d.ts.map +1 -0
  84. package/dist/query.js +470 -0
  85. package/dist/query.js.map +1 -0
  86. package/dist/read-side.d.ts +14 -0
  87. package/dist/read-side.d.ts.map +1 -0
  88. package/dist/read-side.js +457 -0
  89. package/dist/read-side.js.map +1 -0
  90. package/dist/refresh.d.ts +4 -4
  91. package/dist/refresh.d.ts.map +1 -1
  92. package/dist/refresh.js +40 -10
  93. package/dist/refresh.js.map +1 -1
  94. package/dist/replica.d.ts +27 -4
  95. package/dist/replica.d.ts.map +1 -1
  96. package/dist/replica.js +255 -13
  97. package/dist/replica.js.map +1 -1
  98. package/dist/room-draft.d.ts +124 -0
  99. package/dist/room-draft.d.ts.map +1 -0
  100. package/dist/room-draft.js +406 -0
  101. package/dist/room-draft.js.map +1 -0
  102. package/dist/rows.d.ts +41 -0
  103. package/dist/rows.d.ts.map +1 -0
  104. package/dist/rows.js +102 -0
  105. package/dist/rows.js.map +1 -0
  106. package/dist/save.d.ts +11 -2
  107. package/dist/save.d.ts.map +1 -1
  108. package/dist/save.js +116 -128
  109. package/dist/save.js.map +1 -1
  110. package/dist/search.d.ts +61 -0
  111. package/dist/search.d.ts.map +1 -0
  112. package/dist/search.js +155 -0
  113. package/dist/search.js.map +1 -0
  114. package/dist/status.d.ts +9 -2
  115. package/dist/status.d.ts.map +1 -1
  116. package/dist/status.js +5 -4
  117. package/dist/status.js.map +1 -1
  118. package/dist/store.d.ts +90 -18
  119. package/dist/store.d.ts.map +1 -1
  120. package/dist/store.js +492 -67
  121. package/dist/store.js.map +1 -1
  122. package/dist/transfer.d.ts +5 -0
  123. package/dist/transfer.d.ts.map +1 -1
  124. package/dist/transfer.js.map +1 -1
  125. package/dist/wire.d.ts +64 -0
  126. package/dist/wire.d.ts.map +1 -0
  127. package/dist/wire.js +145 -0
  128. package/dist/wire.js.map +1 -0
  129. package/package.json +15 -13
@@ -0,0 +1,635 @@
1
+ import { conversationChangeSet } from './change-set.js';
2
+ import { declaredFile } from './file.js';
3
+ const QUIET = {
4
+ growingText: null,
5
+ plan: null,
6
+ workingNote: null,
7
+ questions: [],
8
+ process: null,
9
+ commands: [],
10
+ options: []
11
+ };
12
+ function ordered(left, right) {
13
+ if (left.position !== right.position) return left.position < right.position ? -1 : 1;
14
+ if (left.identity !== right.identity) return left.identity < right.identity ? -1 : 1;
15
+ return 0;
16
+ }
17
+ function merged(held, arriving) {
18
+ const byIdentity = new Map(held.map((message)=>[
19
+ message.identity,
20
+ message
21
+ ]));
22
+ for (const message of arriving)byIdentity.set(message.identity, message);
23
+ return [
24
+ ...byIdentity.values()
25
+ ].sort(ordered);
26
+ }
27
+ function acceptedMessage(value) {
28
+ if (typeof value !== 'object' || value === null) return null;
29
+ const record = value;
30
+ if (typeof record.identity !== 'string' || typeof record.turn !== 'string' || typeof record.position !== 'string' || typeof record.text !== 'string') {
31
+ return null;
32
+ }
33
+ return {
34
+ identity: record.identity,
35
+ turn: record.turn,
36
+ position: record.position,
37
+ text: record.text,
38
+ message: structuredClone(record.message)
39
+ };
40
+ }
41
+ function historyPage(value) {
42
+ if (typeof value !== 'object' || value === null) return null;
43
+ const record = value;
44
+ if (typeof record.conversation !== 'string' || !Array.isArray(record.messages)) return null;
45
+ if (record.next !== undefined && typeof record.next !== 'string') return null;
46
+ const messages = [];
47
+ for (const entry of record.messages){
48
+ const message = acceptedMessage(entry);
49
+ if (message === null) return null;
50
+ messages.push(message);
51
+ }
52
+ return {
53
+ conversation: record.conversation,
54
+ messages,
55
+ ...record.next === undefined ? {} : {
56
+ next: record.next
57
+ }
58
+ };
59
+ }
60
+ function historyPages(result) {
61
+ if (result.kind !== 'action') return null;
62
+ const answer = result.result;
63
+ if (typeof answer !== 'object' || answer === null) return null;
64
+ const { histories } = answer;
65
+ if (!Array.isArray(histories)) return null;
66
+ const pages = [];
67
+ for (const entry of histories){
68
+ const page = historyPage(entry);
69
+ if (page === null) return null;
70
+ pages.push(page);
71
+ }
72
+ return pages;
73
+ }
74
+ function turnOf(result) {
75
+ if (result.kind !== 'action') return null;
76
+ const answer = result.result;
77
+ if (typeof answer !== 'object' || answer === null) return null;
78
+ const record = answer;
79
+ return typeof record.turn === 'string' ? record.turn : null;
80
+ }
81
+ function limitOf(options) {
82
+ const { limit } = options;
83
+ if (limit === undefined) return undefined;
84
+ if (!Number.isInteger(limit) || limit < 0) {
85
+ throw new Error(`conversation limit must be a non-negative integer, got ${String(limit)}`);
86
+ }
87
+ return limit;
88
+ }
89
+ export function createConversationStore(deps) {
90
+ const messages = new Map();
91
+ const reads = new Map();
92
+ const drafts = new Map();
93
+ const sending = new Map();
94
+ const behind = new Set();
95
+ const gaps = new Map();
96
+ const lives = new Map();
97
+ const views = new Map();
98
+ let replicated = new Set();
99
+ let handedReplicated;
100
+ function liveOf(conversation) {
101
+ return lives.get(conversation) ?? QUIET;
102
+ }
103
+ function viewOf(conversation, limit) {
104
+ const held = messages.get(conversation) ?? [];
105
+ const shown = limit === undefined ? held : held.slice(Math.max(0, held.length - limit));
106
+ const draft = drafts.get(conversation);
107
+ const facts = liveOf(conversation);
108
+ return {
109
+ conversation,
110
+ messages: shown.map(({ identity, turn, text, message })=>({
111
+ identity,
112
+ turn,
113
+ text,
114
+ message: structuredClone(message)
115
+ })),
116
+ growingText: facts.growingText === null ? null : {
117
+ ...facts.growingText
118
+ },
119
+ workingNote: facts.workingNote === null ? null : {
120
+ ...facts.workingNote
121
+ },
122
+ plan: structuredClone(facts.plan?.plan ?? null),
123
+ questions: structuredClone(facts.questions),
124
+ process: facts.process === null ? null : {
125
+ ...facts.process
126
+ },
127
+ commands: structuredClone(facts.commands),
128
+ options: structuredClone(facts.options),
129
+ chatDraft: draft === undefined || draft.turn !== null || sending.get(conversation)?.draft === draft ? null : {
130
+ text: draft.text,
131
+ files: [
132
+ ...draft.files
133
+ ]
134
+ }
135
+ };
136
+ }
137
+ function emit(conversation) {
138
+ if (deps.closed()) return;
139
+ for (const view of views.values()){
140
+ if (view.conversation !== conversation) continue;
141
+ const ready = [
142
+ ...view.watchers
143
+ ].filter((watcher)=>watcher.ready);
144
+ if (ready.length === 0) continue;
145
+ const value = viewOf(conversation, view.limit);
146
+ for (const watcher of ready)watcher.notify(value);
147
+ }
148
+ }
149
+ function live(conversation, change) {
150
+ lives.set(conversation, {
151
+ ...liveOf(conversation),
152
+ ...change
153
+ });
154
+ emit(conversation);
155
+ }
156
+ function sealTurns(conversation, turns) {
157
+ const held = lives.get(conversation);
158
+ if (held === undefined) return false;
159
+ const growingText = held.growingText !== null && turns.has(held.growingText.turn) ? null : held.growingText;
160
+ const plan = held.plan !== null && turns.has(held.plan.turn) ? null : held.plan;
161
+ if (growingText === held.growingText && plan === held.plan) return false;
162
+ lives.set(conversation, {
163
+ ...held,
164
+ growingText,
165
+ plan
166
+ });
167
+ return true;
168
+ }
169
+ function handReplicated() {
170
+ const stream = deps.stream();
171
+ if (stream === undefined) return;
172
+ const held = [
173
+ ...replicated
174
+ ].sort();
175
+ const named = JSON.stringify(held);
176
+ if (named === handedReplicated) return;
177
+ handedReplicated = named;
178
+ stream.replicate(held);
179
+ }
180
+ async function documented() {
181
+ const declaration = deps.cards();
182
+ if (declaration === undefined) return [];
183
+ const { documents } = await deps.documents(declaration.locator);
184
+ return documents.filter((document)=>typeof document.type === 'string');
185
+ }
186
+ function carded(documents) {
187
+ const declaration = deps.cards();
188
+ if (declaration === undefined) return [];
189
+ const cards = [];
190
+ for (const card of documents){
191
+ if (card.type !== declaration.type) continue;
192
+ const identity = card.fields[declaration.identity];
193
+ if (typeof identity === 'string') cards.push({
194
+ conversation: identity,
195
+ card
196
+ });
197
+ }
198
+ return cards;
199
+ }
200
+ async function remove(leaving) {
201
+ await deps.durably(async (local)=>{
202
+ await local.dropConversations(leaving);
203
+ const removed = [];
204
+ const changed = [];
205
+ for (const conversation of leaving){
206
+ for (const message of messages.get(conversation) ?? []){
207
+ removed.push({
208
+ conversation,
209
+ identity: message.identity
210
+ });
211
+ }
212
+ if (messages.has(conversation) || drafts.has(conversation) || lives.has(conversation)) {
213
+ changed.push(conversation);
214
+ }
215
+ messages.delete(conversation);
216
+ reads.delete(conversation);
217
+ drafts.delete(conversation);
218
+ behind.delete(conversation);
219
+ lives.delete(conversation);
220
+ }
221
+ if (changed.length > 0) deps.publish(conversationChangeSet(removed, changed));
222
+ });
223
+ }
224
+ function gap(conversation) {
225
+ gaps.set(conversation, (gaps.get(conversation) ?? 0) + 1);
226
+ behind.add(conversation);
227
+ }
228
+ function keep(conversation, message) {
229
+ return deps.durably(async (local)=>{
230
+ if (!replicated.has(conversation)) return;
231
+ const read = reads.get(conversation);
232
+ const advances = read !== undefined && !behind.has(conversation) && (read === null || message.position > read);
233
+ const sealed = drafts.get(conversation)?.turn === message.turn;
234
+ await local.keepMessages({
235
+ conversation,
236
+ messages: [
237
+ message
238
+ ],
239
+ ...advances ? {
240
+ read: message.position
241
+ } : {},
242
+ sealed
243
+ });
244
+ messages.set(conversation, merged(messages.get(conversation) ?? [], [
245
+ message
246
+ ]));
247
+ if (advances) reads.set(conversation, message.position);
248
+ if (sealed) drafts.delete(conversation);
249
+ sealTurns(conversation, new Set([
250
+ message.turn
251
+ ]));
252
+ deps.publish(conversationChangeSet([
253
+ {
254
+ conversation,
255
+ identity: message.identity
256
+ }
257
+ ], [
258
+ conversation
259
+ ]));
260
+ });
261
+ }
262
+ async function readHistories(conversations) {
263
+ const generations = new Map(conversations.map((one)=>[
264
+ one,
265
+ gaps.get(one) ?? 0
266
+ ]));
267
+ const starts = new Map(conversations.map((one)=>[
268
+ one,
269
+ reads.get(one)
270
+ ]));
271
+ const arriving = new Map();
272
+ const complete = new Set();
273
+ let asking = conversations.map((conversation)=>({
274
+ conversation,
275
+ after: starts.get(conversation) ?? undefined
276
+ }));
277
+ while(asking.length > 0){
278
+ const result = await deps.call('conversation.history', {
279
+ conversations: asking.map(({ conversation, after })=>({
280
+ conversation,
281
+ ...after === undefined ? {} : {
282
+ after
283
+ }
284
+ }))
285
+ });
286
+ const pages = historyPages(result);
287
+ if (pages === null) return result;
288
+ const asked = new Set(asking.map(({ conversation })=>conversation));
289
+ const following = [];
290
+ for (const page of pages){
291
+ if (!asked.has(page.conversation)) continue;
292
+ arriving.set(page.conversation, [
293
+ ...arriving.get(page.conversation) ?? [],
294
+ ...page.messages
295
+ ]);
296
+ if (page.next === undefined) complete.add(page.conversation);
297
+ else following.push({
298
+ conversation: page.conversation,
299
+ after: page.next
300
+ });
301
+ }
302
+ asking = following;
303
+ }
304
+ for (const [conversation, held] of arriving){
305
+ if (!complete.has(conversation)) continue;
306
+ await keepHistory(conversation, held, starts.get(conversation), generations.get(conversation) ?? 0);
307
+ }
308
+ return null;
309
+ }
310
+ function keepHistory(conversation, arriving, from, generation) {
311
+ return deps.durably(async (local)=>{
312
+ if (!replicated.has(conversation)) return;
313
+ const newest = arriving.reduce((top, message)=>top === null || message.position > top ? message.position : top, from ?? null);
314
+ const turn = drafts.get(conversation)?.turn;
315
+ const sealed = arriving.some((message)=>message.turn === turn);
316
+ await local.keepMessages({
317
+ conversation,
318
+ messages: arriving,
319
+ read: newest,
320
+ sealed
321
+ });
322
+ messages.set(conversation, merged(messages.get(conversation) ?? [], arriving));
323
+ reads.set(conversation, newest);
324
+ if (sealed) drafts.delete(conversation);
325
+ sealTurns(conversation, new Set(arriving.map((message)=>message.turn)));
326
+ if ((gaps.get(conversation) ?? 0) === generation) behind.delete(conversation);
327
+ if (arriving.length > 0 || sealed) {
328
+ deps.publish(conversationChangeSet(arriving.map((message)=>({
329
+ conversation,
330
+ identity: message.identity
331
+ })), [
332
+ conversation
333
+ ]));
334
+ }
335
+ });
336
+ }
337
+ function withDraft(conversation, next) {
338
+ return deps.durably(async (local)=>{
339
+ const following = next(drafts.get(conversation));
340
+ if (following === undefined) return;
341
+ if (following === null) {
342
+ await local.dropChatDraft(conversation);
343
+ drafts.delete(conversation);
344
+ } else {
345
+ await local.keepChatDraft(following);
346
+ drafts.set(conversation, following);
347
+ }
348
+ deps.publish(conversationChangeSet([], [
349
+ conversation
350
+ ]));
351
+ });
352
+ }
353
+ function invoke(name, conversation, extra = {}) {
354
+ return deps.call(name, {
355
+ conversation,
356
+ ...extra
357
+ });
358
+ }
359
+ const surface = {
360
+ async list () {
361
+ const declaration = deps.cards();
362
+ if (declaration === undefined) return [];
363
+ const documents = await documented();
364
+ const entries = carded(documents).map(({ conversation, card })=>({
365
+ conversation,
366
+ card,
367
+ agent: documents.find((document)=>document.backlinks.some((backlink)=>backlink.path === card.path && backlink.field === declaration.agent)) ?? null
368
+ }));
369
+ entries.sort((left, right)=>left.conversation < right.conversation ? -1 : 1);
370
+ return entries;
371
+ },
372
+ async read (conversation, options = {}) {
373
+ const limit = limitOf(options);
374
+ return deps.durably(()=>Promise.resolve(viewOf(conversation, limit)));
375
+ },
376
+ create (input) {
377
+ return deps.call('conversation.create', input);
378
+ },
379
+ async send (conversation) {
380
+ const draft = drafts.get(conversation);
381
+ const pending = draft === undefined ? undefined : {
382
+ draft
383
+ };
384
+ if (pending !== undefined) {
385
+ sending.set(conversation, pending);
386
+ deps.publish(conversationChangeSet([], [
387
+ conversation
388
+ ]));
389
+ }
390
+ try {
391
+ const files = await Promise.all((draft?.files ?? []).map(async (file)=>({
392
+ ...await declaredFile(file),
393
+ blob: file.blob
394
+ })));
395
+ const result = await invoke('conversation.send', conversation, {
396
+ text: draft?.text ?? '',
397
+ files
398
+ });
399
+ const turn = turnOf(result);
400
+ if (turn === null || draft === undefined) return result;
401
+ await withDraft(conversation, (current)=>{
402
+ if (current !== draft) return undefined;
403
+ const sealed = (messages.get(conversation) ?? []).some((message)=>message.turn === turn);
404
+ return sealed ? null : {
405
+ ...draft,
406
+ turn
407
+ };
408
+ });
409
+ return result;
410
+ } finally{
411
+ if (pending !== undefined && sending.get(conversation) === pending) {
412
+ sending.delete(conversation);
413
+ if (drafts.get(conversation) === draft) {
414
+ deps.publish(conversationChangeSet([], [
415
+ conversation
416
+ ]));
417
+ }
418
+ }
419
+ }
420
+ },
421
+ answer (conversation, answer) {
422
+ return invoke('conversation.answer', conversation, {
423
+ answer
424
+ });
425
+ },
426
+ interrupt (conversation) {
427
+ return invoke('conversation.interrupt', conversation);
428
+ },
429
+ kill (conversation) {
430
+ return invoke('conversation.kill', conversation);
431
+ },
432
+ async cancel (conversation, turn) {
433
+ const result = await invoke('conversation.cancel', conversation, {
434
+ turn
435
+ });
436
+ if (result.kind !== 'action') return result;
437
+ await withDraft(conversation, (current)=>current === undefined || current.turn !== turn ? undefined : {
438
+ ...current,
439
+ turn: null
440
+ });
441
+ return result;
442
+ },
443
+ delete (conversation) {
444
+ return invoke('conversation.delete', conversation);
445
+ }
446
+ };
447
+ const chatDraft = {
448
+ write (conversation, draft) {
449
+ return withDraft(conversation, ()=>({
450
+ conversation,
451
+ text: draft.text,
452
+ files: [
453
+ ...draft.files
454
+ ],
455
+ turn: null
456
+ }));
457
+ },
458
+ discard (conversation) {
459
+ return withDraft(conversation, (current)=>current === undefined ? undefined : null);
460
+ }
461
+ };
462
+ return {
463
+ surface,
464
+ chatDraft,
465
+ hydrate (held, stored) {
466
+ messages.clear();
467
+ reads.clear();
468
+ for (const entry of held){
469
+ messages.set(entry.conversation, [
470
+ ...entry.messages
471
+ ].sort(ordered));
472
+ if (entry.read !== undefined) reads.set(entry.conversation, entry.read);
473
+ }
474
+ drafts.clear();
475
+ for (const record of stored)drafts.set(record.conversation, record);
476
+ },
477
+ async reconcile () {
478
+ const named = new Set(carded(await documented()).map((entry)=>entry.conversation));
479
+ const leaving = [
480
+ ...new Set([
481
+ ...replicated,
482
+ ...messages.keys(),
483
+ ...reads.keys(),
484
+ ...drafts.keys()
485
+ ])
486
+ ].filter((conversation)=>!named.has(conversation));
487
+ for (const conversation of named){
488
+ if (!replicated.has(conversation)) behind.add(conversation);
489
+ }
490
+ replicated = named;
491
+ handReplicated();
492
+ if (leaving.length > 0) await remove(leaving);
493
+ },
494
+ async catchUp (progress) {
495
+ const reading = [
496
+ ...behind
497
+ ].filter((conversation)=>replicated.has(conversation)).sort();
498
+ if (reading.length > 0 && !deps.closed()) {
499
+ const failed = await readHistories(reading);
500
+ if (failed?.kind === 'transport-uncertainty') progress.reachable = false;
501
+ }
502
+ if (behind.size > 0) progress.complete = false;
503
+ },
504
+ current () {
505
+ return behind.size === 0;
506
+ },
507
+ reconnected () {
508
+ for (const conversation of replicated)gap(conversation);
509
+ },
510
+ watch (conversation, options, deliver) {
511
+ const limit = limitOf(options);
512
+ const key = JSON.stringify([
513
+ conversation,
514
+ limit ?? null
515
+ ]);
516
+ const view = views.get(key) ?? {
517
+ conversation,
518
+ limit,
519
+ watchers: new Set()
520
+ };
521
+ views.set(key, view);
522
+ const watcher = {
523
+ notify: deliver,
524
+ ready: false
525
+ };
526
+ view.watchers.add(watcher);
527
+ void deps.durably(()=>Promise.resolve()).then(()=>{
528
+ if (deps.closed() || !view.watchers.has(watcher)) return;
529
+ watcher.ready = true;
530
+ watcher.notify(viewOf(conversation, limit));
531
+ }).catch(()=>{});
532
+ return ()=>{
533
+ if (!view.watchers.delete(watcher)) return;
534
+ if (view.watchers.size === 0) views.delete(key);
535
+ };
536
+ },
537
+ changed (set) {
538
+ for (const conversation of set.conversations)emit(conversation);
539
+ },
540
+ receive (event) {
541
+ if (deps.closed()) return;
542
+ const { conversation } = event;
543
+ if (event.kind === 'gap') {
544
+ if (replicated.has(conversation)) gap(conversation);
545
+ if (lives.delete(conversation)) emit(conversation);
546
+ return;
547
+ }
548
+ if (event.kind === 'growing-text') {
549
+ live(conversation, {
550
+ growingText: {
551
+ turn: event.turn,
552
+ text: event.text
553
+ }
554
+ });
555
+ return;
556
+ }
557
+ if (event.kind === 'plan') {
558
+ live(conversation, {
559
+ plan: {
560
+ turn: event.turn,
561
+ plan: structuredClone(event.plan)
562
+ }
563
+ });
564
+ return;
565
+ }
566
+ if (event.kind === 'working-note') {
567
+ live(conversation, {
568
+ workingNote: event.note === null ? null : {
569
+ noteId: event.note.noteId,
570
+ text: event.note.text
571
+ }
572
+ });
573
+ return;
574
+ }
575
+ if (event.kind === 'questions') {
576
+ live(conversation, {
577
+ questions: structuredClone(event.questions)
578
+ });
579
+ return;
580
+ }
581
+ if (event.kind === 'process') {
582
+ live(conversation, {
583
+ process: {
584
+ running: event.running
585
+ }
586
+ });
587
+ return;
588
+ }
589
+ if (event.kind === 'commands') {
590
+ live(conversation, {
591
+ commands: structuredClone(event.commands)
592
+ });
593
+ return;
594
+ }
595
+ if (event.kind === 'options') {
596
+ live(conversation, {
597
+ options: structuredClone(event.options)
598
+ });
599
+ return;
600
+ }
601
+ const arriving = acceptedMessage(event.message);
602
+ if (arriving === null) return;
603
+ if (replicated.has(conversation)) {
604
+ void keep(conversation, arriving).catch(()=>{});
605
+ return;
606
+ }
607
+ if (sealTurns(conversation, new Set([
608
+ arriving.turn
609
+ ]))) emit(conversation);
610
+ },
611
+ messages () {
612
+ return [
613
+ ...messages
614
+ ].flatMap(([conversation, held])=>held.map(({ identity, text })=>({
615
+ conversation,
616
+ identity,
617
+ text
618
+ })));
619
+ },
620
+ message (conversation, identity) {
621
+ const held = messages.get(conversation)?.find((message)=>message.identity === identity);
622
+ return held === undefined ? null : {
623
+ conversation,
624
+ identity,
625
+ text: held.text
626
+ };
627
+ },
628
+ close () {
629
+ views.clear();
630
+ lives.clear();
631
+ }
632
+ };
633
+ }
634
+
635
+ //# sourceMappingURL=conversation.js.map