@agentshouse/mdruntime 0.1.0-c52f87bb83a70 → 0.1.0-c55c6f69061ee

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 (219) hide show
  1. package/README.md +11 -9
  2. package/dist/adapter.d.ts +94 -63
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/attached-model.d.ts +2 -1
  5. package/dist/attached-model.d.ts.map +1 -1
  6. package/dist/attached-model.js +28 -4
  7. package/dist/binary.d.ts +0 -5
  8. package/dist/binary.d.ts.map +1 -1
  9. package/dist/binary.js +1 -1
  10. package/dist/bootstrap.d.ts +16 -8
  11. package/dist/bootstrap.d.ts.map +1 -1
  12. package/dist/bootstrap.js +142 -94
  13. package/dist/change-set.d.ts +1 -7
  14. package/dist/change-set.d.ts.map +1 -1
  15. package/dist/change-set.js +1 -4
  16. package/dist/client.d.ts +10 -11
  17. package/dist/client.d.ts.map +1 -1
  18. package/dist/client.js +54 -8
  19. package/dist/collection.d.ts +5 -3
  20. package/dist/collection.d.ts.map +1 -1
  21. package/dist/collection.js +24 -19
  22. package/dist/compile.d.ts +7 -2
  23. package/dist/compile.d.ts.map +1 -1
  24. package/dist/compile.js +125 -48
  25. package/dist/connection.d.ts +10 -10
  26. package/dist/connection.d.ts.map +1 -1
  27. package/dist/connection.js +1611 -1313
  28. package/dist/context.d.ts +2 -0
  29. package/dist/context.d.ts.map +1 -0
  30. package/dist/{chat/context.js → context.js} +1 -4
  31. package/dist/conversation.d.ts +17 -14
  32. package/dist/conversation.d.ts.map +1 -1
  33. package/dist/conversation.js +262 -159
  34. package/dist/durability.d.ts +1 -5
  35. package/dist/durability.d.ts.map +1 -1
  36. package/dist/durability.js +5 -0
  37. package/dist/entry.d.ts +1 -0
  38. package/dist/entry.d.ts.map +1 -1
  39. package/dist/entry.js +2 -1
  40. package/dist/file.d.ts +2 -11
  41. package/dist/file.d.ts.map +1 -1
  42. package/dist/file.js +6 -4
  43. package/dist/host.d.ts +4 -7
  44. package/dist/host.d.ts.map +1 -1
  45. package/dist/host.js +52 -32
  46. package/dist/identity.d.ts +0 -1
  47. package/dist/identity.d.ts.map +1 -1
  48. package/dist/identity.js +0 -3
  49. package/dist/index.d.ts +13 -11
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +6 -3
  52. package/dist/job.d.ts +14 -0
  53. package/dist/job.d.ts.map +1 -0
  54. package/dist/job.js +28 -0
  55. package/dist/live.d.ts +2 -1
  56. package/dist/live.d.ts.map +1 -1
  57. package/dist/live.js +9 -5
  58. package/dist/media.d.ts +8 -0
  59. package/dist/media.d.ts.map +1 -0
  60. package/dist/media.js +218 -0
  61. package/dist/memory.d.ts +10 -6
  62. package/dist/memory.d.ts.map +1 -1
  63. package/dist/memory.js +177 -100
  64. package/dist/messages.d.ts +28 -0
  65. package/dist/messages.d.ts.map +1 -0
  66. package/dist/messages.js +89 -0
  67. package/dist/model.d.ts +6 -1
  68. package/dist/model.d.ts.map +1 -1
  69. package/dist/model.js +7 -10
  70. package/dist/observation.d.ts +3 -2
  71. package/dist/observation.d.ts.map +1 -1
  72. package/dist/observation.js +8 -3
  73. package/dist/outcome.d.ts +13 -6
  74. package/dist/outcome.d.ts.map +1 -1
  75. package/dist/outcome.js +16 -5
  76. package/dist/overlay.js +1 -1
  77. package/dist/paths.d.ts +1 -0
  78. package/dist/paths.d.ts.map +1 -1
  79. package/dist/paths.js +4 -0
  80. package/dist/phrase.d.ts +3 -0
  81. package/dist/phrase.d.ts.map +1 -0
  82. package/dist/phrase.js +8 -0
  83. package/dist/query.d.ts +14 -1
  84. package/dist/query.d.ts.map +1 -1
  85. package/dist/query.js +32 -2
  86. package/dist/reach.d.ts +13 -7
  87. package/dist/reach.d.ts.map +1 -1
  88. package/dist/reach.js +80 -64
  89. package/dist/react.d.ts +1 -0
  90. package/dist/react.d.ts.map +1 -1
  91. package/dist/readiness.d.ts +14 -17
  92. package/dist/readiness.d.ts.map +1 -1
  93. package/dist/readiness.js +2 -8
  94. package/dist/recovery.d.ts +1 -0
  95. package/dist/recovery.d.ts.map +1 -1
  96. package/dist/recovery.js +26 -0
  97. package/dist/refresh.d.ts +10 -4
  98. package/dist/refresh.d.ts.map +1 -1
  99. package/dist/refresh.js +104 -30
  100. package/dist/replica.d.ts +5 -5
  101. package/dist/replica.d.ts.map +1 -1
  102. package/dist/replica.js +7 -7
  103. package/dist/room-draft.d.ts +20 -3
  104. package/dist/room-draft.d.ts.map +1 -1
  105. package/dist/room-draft.js +131 -51
  106. package/dist/rows.d.ts +17 -7
  107. package/dist/rows.d.ts.map +1 -1
  108. package/dist/rows.js +120 -87
  109. package/dist/save.d.ts +2 -0
  110. package/dist/save.d.ts.map +1 -1
  111. package/dist/save.js +13 -7
  112. package/dist/search.d.ts +12 -95
  113. package/dist/search.d.ts.map +1 -1
  114. package/dist/search.js +10 -349
  115. package/dist/shared.d.ts +0 -1
  116. package/dist/shared.d.ts.map +1 -1
  117. package/dist/shared.js +0 -10
  118. package/dist/status.d.ts +4 -3
  119. package/dist/status.d.ts.map +1 -1
  120. package/dist/status.js +3 -1
  121. package/dist/store.d.ts +34 -60
  122. package/dist/store.d.ts.map +1 -1
  123. package/dist/store.js +71 -275
  124. package/dist/stored.d.ts +42 -23
  125. package/dist/stored.d.ts.map +1 -1
  126. package/dist/stored.js +198 -210
  127. package/dist/tables.d.ts +79 -46
  128. package/dist/tables.d.ts.map +1 -1
  129. package/dist/tables.js +101 -53
  130. package/dist/transfer.d.ts +0 -5
  131. package/dist/transfer.d.ts.map +1 -1
  132. package/dist/validation.d.ts +3 -4
  133. package/dist/validation.d.ts.map +1 -1
  134. package/dist/validation.js +35 -96
  135. package/dist/wire.d.ts +6 -9
  136. package/dist/wire.d.ts.map +1 -1
  137. package/dist/wire.js +3 -3
  138. package/package.json +14 -18
  139. package/AGENTS.md +0 -310
  140. package/dist/chat/acts.d.ts +0 -33
  141. package/dist/chat/acts.d.ts.map +0 -1
  142. package/dist/chat/acts.js +0 -36
  143. package/dist/chat/context.d.ts +0 -3
  144. package/dist/chat/context.d.ts.map +0 -1
  145. package/dist/chat/earlier.d.ts +0 -10
  146. package/dist/chat/earlier.d.ts.map +0 -1
  147. package/dist/chat/earlier.js +0 -54
  148. package/dist/chat/house.d.ts +0 -25
  149. package/dist/chat/house.d.ts.map +0 -1
  150. package/dist/chat/house.js +0 -38
  151. package/dist/chat/input.d.ts +0 -11
  152. package/dist/chat/input.d.ts.map +0 -1
  153. package/dist/chat/input.js +0 -92
  154. package/dist/chat/kit.d.ts +0 -61
  155. package/dist/chat/kit.d.ts.map +0 -1
  156. package/dist/chat/kit.js +0 -123
  157. package/dist/chat/lasting.d.ts +0 -6
  158. package/dist/chat/lasting.d.ts.map +0 -1
  159. package/dist/chat/lasting.js +0 -19
  160. package/dist/chat/list.d.ts +0 -28
  161. package/dist/chat/list.d.ts.map +0 -1
  162. package/dist/chat/list.js +0 -103
  163. package/dist/chat/markdown.d.ts +0 -21
  164. package/dist/chat/markdown.d.ts.map +0 -1
  165. package/dist/chat/markdown.js +0 -246
  166. package/dist/chat/message.d.ts +0 -7
  167. package/dist/chat/message.d.ts.map +0 -1
  168. package/dist/chat/message.js +0 -237
  169. package/dist/chat/messages.d.ts +0 -29
  170. package/dist/chat/messages.d.ts.map +0 -1
  171. package/dist/chat/messages.js +0 -190
  172. package/dist/chat/name.d.ts +0 -7
  173. package/dist/chat/name.d.ts.map +0 -1
  174. package/dist/chat/name.js +0 -37
  175. package/dist/chat/opened.d.ts +0 -12
  176. package/dist/chat/opened.d.ts.map +0 -1
  177. package/dist/chat/opened.js +0 -19
  178. package/dist/chat/overlay.d.ts +0 -32
  179. package/dist/chat/overlay.d.ts.map +0 -1
  180. package/dist/chat/overlay.js +0 -103
  181. package/dist/chat/parts.d.ts +0 -58
  182. package/dist/chat/parts.d.ts.map +0 -1
  183. package/dist/chat/parts.js +0 -120
  184. package/dist/chat/pieces.d.ts +0 -62
  185. package/dist/chat/pieces.d.ts.map +0 -1
  186. package/dist/chat/pieces.js +0 -1110
  187. package/dist/chat/process.d.ts +0 -20
  188. package/dist/chat/process.d.ts.map +0 -1
  189. package/dist/chat/process.js +0 -32
  190. package/dist/chat/provider.d.ts +0 -68
  191. package/dist/chat/provider.d.ts.map +0 -1
  192. package/dist/chat/provider.js +0 -619
  193. package/dist/chat/question.d.ts +0 -9
  194. package/dist/chat/question.d.ts.map +0 -1
  195. package/dist/chat/question.js +0 -69
  196. package/dist/chat/questions.d.ts +0 -31
  197. package/dist/chat/questions.d.ts.map +0 -1
  198. package/dist/chat/questions.js +0 -111
  199. package/dist/chat/read.d.ts +0 -5
  200. package/dist/chat/read.d.ts.map +0 -1
  201. package/dist/chat/read.js +0 -13
  202. package/dist/chat/ready.d.ts +0 -37
  203. package/dist/chat/ready.d.ts.map +0 -1
  204. package/dist/chat/ready.js +0 -93
  205. package/dist/chat/room-file.d.ts +0 -8
  206. package/dist/chat/room-file.d.ts.map +0 -1
  207. package/dist/chat/room-file.js +0 -72
  208. package/dist/chat/steady.d.ts +0 -3
  209. package/dist/chat/steady.d.ts.map +0 -1
  210. package/dist/chat/steady.js +0 -26
  211. package/dist/chat/style.d.ts +0 -4
  212. package/dist/chat/style.d.ts.map +0 -1
  213. package/dist/chat/style.js +0 -306
  214. package/dist/chat.d.ts +0 -15
  215. package/dist/chat.d.ts.map +0 -1
  216. package/dist/chat.js +0 -8
  217. package/dist/reads.d.ts +0 -11
  218. package/dist/reads.d.ts.map +0 -1
  219. package/dist/reads.js +0 -98
@@ -1,8 +1,9 @@
1
1
  import { conversationChangeSet } from './change-set.js';
2
2
  import { runtimeError } from './failure.js';
3
- import { declaredFile } from './file.js';
3
+ import { refusedForSpace } from './durability.js';
4
4
  import { changeBatchIdentity, chatDraftRevision } from './identity.js';
5
5
  import { OFFLINE } from './outcome.js';
6
+ import { untilAnswered } from './recovery.js';
6
7
  import { capped, cursorOf, decodedCursor, FROM_START, messageOrder, precedes } from './windows.js';
7
8
  const QUIET = {
8
9
  turn: null,
@@ -11,6 +12,7 @@ const QUIET = {
11
12
  commands: [],
12
13
  options: [],
13
14
  starting: null,
15
+ subagents: [],
14
16
  link: null,
15
17
  deliveryUnknown: [],
16
18
  };
@@ -20,6 +22,7 @@ const FACTS = [
20
22
  'commands',
21
23
  'options',
22
24
  'starting',
25
+ 'subagents',
23
26
  'link',
24
27
  'deliveryUnknown',
25
28
  ];
@@ -33,6 +36,7 @@ export function unheldView(conversation) {
33
36
  commands: [],
34
37
  options: [],
35
38
  starting: null,
39
+ subagents: [],
36
40
  link: null,
37
41
  deliveryUnknown: [],
38
42
  chatDraft: null,
@@ -40,6 +44,7 @@ export function unheldView(conversation) {
40
44
  }
41
45
  export const SESSION_STARTED = 'Session started';
42
46
  const NEW_CHAT = 'new:';
47
+ export const HISTORY_CONVERSATIONS = 64;
43
48
  export function newChat(agent) {
44
49
  return `${NEW_CHAT}${agent}`;
45
50
  }
@@ -206,7 +211,21 @@ function askedOf(options) {
206
211
  }
207
212
  return { limit: capped(limit), after, before: beforeOf(after), total: total === true };
208
213
  }
214
+ function phraseOf(text) {
215
+ if (text === undefined)
216
+ return null;
217
+ if (typeof text !== 'string' || text === '') {
218
+ throw runtimeError('invalid-text', 'a conversation is found by a phrase');
219
+ }
220
+ return text;
221
+ }
209
222
  const EXPIRED = { kind: 'rejected', code: 'expired', fields: {}, retryable: false };
223
+ const DURABLE_WRITE = {
224
+ kind: 'rejected',
225
+ code: 'durable-write',
226
+ fields: {},
227
+ retryable: true,
228
+ };
210
229
  function unwritten(draft) {
211
230
  return draft.text === '';
212
231
  }
@@ -246,13 +265,19 @@ export function createConversationStore(deps) {
246
265
  const unsent = new Map();
247
266
  const views = new Map();
248
267
  const listing = new Map();
268
+ let relisting = null;
269
+ let listCursor = null;
249
270
  const creations = new Set();
250
271
  const listWatchers = new Set();
272
+ const unlisted = new Set();
251
273
  let listKnown = false;
274
+ let listHeld = false;
275
+ let listKept = false;
252
276
  const agentWatchers = new Set();
253
- let agentNames = new Map();
254
- let retiredAgents = new Set();
255
- let agentsRead = null;
277
+ const unnamed = new Set();
278
+ let agentsShown = null;
279
+ let listedAgents = null;
280
+ let agentsReading = false;
256
281
  let replicated = new Set();
257
282
  let handedReplicated;
258
283
  function liveOf(conversation) {
@@ -276,6 +301,7 @@ export function createConversationStore(deps) {
276
301
  commands: structuredClone(facts.commands),
277
302
  options: structuredClone(facts.options),
278
303
  starting: facts.starting,
304
+ subagents: structuredClone(facts.subagents),
279
305
  link: facts.link === null ? null : { ...facts.link },
280
306
  deliveryUnknown: [...facts.deliveryUnknown],
281
307
  chatDraft: draft === undefined || unwritten(draft)
@@ -322,9 +348,6 @@ export function createConversationStore(deps) {
322
348
  }
323
349
  }
324
350
  }
325
- function changesOf(conversation, arriving) {
326
- return arriving.map(({ identity, text }) => ({ conversation, identity, text }));
327
- }
328
351
  function stateOf(conversation) {
329
352
  const facts = liveOf(conversation);
330
353
  if (facts.questions.length > 0)
@@ -334,7 +357,7 @@ export function createConversationStore(deps) {
334
357
  function entries() {
335
358
  return [...listing.values()].map((entry) => ({
336
359
  conversation: entry.conversation,
337
- agent: { identity: entry.agent, name: agentNames.get(entry.agent) ?? null },
360
+ agent: { identity: entry.agent, name: entry.agentName },
338
361
  name: entry.name,
339
362
  created: entry.created,
340
363
  finished: entry.finished,
@@ -344,25 +367,100 @@ export function createConversationStore(deps) {
344
367
  started: lives.get(entry.conversation)?.turn?.started ?? null,
345
368
  }));
346
369
  }
370
+ function keepList() {
371
+ if (!listKnown || listKept)
372
+ return;
373
+ listKept = true;
374
+ queueMicrotask(() => {
375
+ listKept = false;
376
+ if (deps.closed())
377
+ return;
378
+ const entries = [...listing.values()];
379
+ const cursor = listCursor;
380
+ void deps
381
+ .durably(async (local) => {
382
+ await local.fact('conversationList', entries);
383
+ await local.fact('conversationCursor', cursor);
384
+ })
385
+ .catch(() => { });
386
+ });
387
+ }
388
+ function listed(entry) {
389
+ listing.set(entry.conversation, { ...entry });
390
+ creations.delete(entry.conversation);
391
+ }
347
392
  function emitList() {
348
- if (deps.closed() || listWatchers.size === 0)
393
+ if (deps.closed())
349
394
  return;
350
- const value = entries();
351
- for (const watcher of listWatchers)
352
- watcher(value);
395
+ if (listWatchers.size > 0) {
396
+ const value = entries();
397
+ for (const watcher of listWatchers)
398
+ watcher(value);
399
+ }
400
+ emitAgents();
401
+ learned();
402
+ }
403
+ function learned() {
404
+ if (deps.closed())
405
+ return;
406
+ if (!listKnown && !listHeld && deps.stream() !== undefined && deps.online())
407
+ return;
408
+ if (unlisted.size > 0) {
409
+ const value = entries();
410
+ for (const watcher of [...unlisted]) {
411
+ unlisted.delete(watcher);
412
+ listWatchers.add(watcher);
413
+ watcher(value);
414
+ }
415
+ }
416
+ if (unnamed.size > 0) {
417
+ const value = agents();
418
+ for (const watcher of [...unnamed]) {
419
+ unnamed.delete(watcher);
420
+ agentWatchers.add(watcher);
421
+ watcher(value);
422
+ }
423
+ }
353
424
  }
354
425
  function agents() {
355
- return [...agentNames]
356
- .filter(([identity]) => !retiredAgents.has(identity))
357
- .map(([identity, name]) => ({ identity, name }))
426
+ const named = new Map();
427
+ for (const agent of listedAgents ?? [])
428
+ named.set(agent.agent, agent);
429
+ for (const entry of listing.values()) {
430
+ named.set(entry.agent, { name: entry.agentName, retired: entry.agentRetired });
431
+ }
432
+ return [...named]
433
+ .filter(([, agent]) => !agent.retired)
434
+ .map(([identity, agent]) => ({ identity, name: agent.name }))
358
435
  .sort((left, right) => left.name === right.name
359
436
  ? left.identity.localeCompare(right.identity)
360
437
  : left.name.localeCompare(right.name));
361
438
  }
439
+ function readAgents() {
440
+ const stream = deps.stream();
441
+ if (stream?.agents === undefined || !deps.online() || agentsReading)
442
+ return;
443
+ agentsReading = true;
444
+ void stream
445
+ .agents()
446
+ .then((read) => {
447
+ if (read === null)
448
+ return;
449
+ listedAgents = read;
450
+ emitAgents();
451
+ }, () => { })
452
+ .finally(() => {
453
+ agentsReading = false;
454
+ });
455
+ }
362
456
  function emitAgents() {
363
457
  if (deps.closed() || agentWatchers.size === 0)
364
458
  return;
365
459
  const value = agents();
460
+ const shown = JSON.stringify(value);
461
+ if (shown === agentsShown)
462
+ return;
463
+ agentsShown = shown;
366
464
  for (const watcher of agentWatchers)
367
465
  watcher(value);
368
466
  }
@@ -378,55 +476,11 @@ export function createConversationStore(deps) {
378
476
  if (stateOf(conversation) !== before || next?.turn?.started !== began)
379
477
  emitList();
380
478
  }
381
- async function readAgents() {
382
- const declaration = deps.agents();
383
- if (declaration === undefined)
384
- return;
385
- const names = new Map();
386
- const retired = new Set();
387
- let covered = null;
388
- for (let after;;) {
389
- const read = await deps.documents(declaration, after);
390
- if ('pending' in read)
391
- return;
392
- const coverage = JSON.stringify(read.coverage);
393
- if (covered !== null && coverage !== covered)
394
- return readAgents();
395
- covered = coverage;
396
- for (const document of read.documents) {
397
- const identity = document.fields?.[declaration.identity];
398
- const name = document.fields?.[declaration.name];
399
- if (typeof identity !== 'string' || typeof name !== 'string')
400
- continue;
401
- names.set(identity, name);
402
- const ended = declaration.retired === undefined ? null : document.fields?.[declaration.retired];
403
- if (ended !== undefined && ended !== null)
404
- retired.add(identity);
405
- }
406
- if (read.next === undefined)
407
- break;
408
- after = read.next;
409
- }
410
- const named = JSON.stringify([...names]) !== JSON.stringify([...agentNames]);
411
- if (!named && JSON.stringify([...retired]) === JSON.stringify([...retiredAgents]))
412
- return;
413
- agentNames = names;
414
- retiredAgents = retired;
415
- if (named)
416
- emitList();
417
- emitAgents();
418
- const ended = [...drafts.keys()].filter(retiredChat);
419
- if (ended.length > 0)
420
- await remove(ended);
421
- }
422
479
  function retiredChat(conversation) {
423
- return (conversation.startsWith(NEW_CHAT) && retiredAgents.has(conversation.slice(NEW_CHAT.length)));
424
- }
425
- function agentsReady() {
426
- agentsRead ??= readAgents().catch(() => {
427
- agentsRead = null;
428
- });
429
- return agentsRead;
480
+ if (!conversation.startsWith(NEW_CHAT))
481
+ return false;
482
+ const agent = conversation.slice(NEW_CHAT.length);
483
+ return [...listing.values()].some((entry) => entry.agent === agent && entry.agentRetired);
430
484
  }
431
485
  function live(conversation, change) {
432
486
  const owed = unsent.get(conversation);
@@ -449,6 +503,7 @@ export function createConversationStore(deps) {
449
503
  commands: facts.has('commands') ? QUIET.commands : held.commands,
450
504
  options: facts.has('options') ? QUIET.options : held.options,
451
505
  starting: facts.has('starting') ? QUIET.starting : held.starting,
506
+ subagents: facts.has('subagents') ? QUIET.subagents : held.subagents,
452
507
  link: facts.has('link') ? QUIET.link : held.link,
453
508
  deliveryUnknown: facts.has('deliveryUnknown')
454
509
  ? QUIET.deliveryUnknown
@@ -483,12 +538,6 @@ export function createConversationStore(deps) {
483
538
  }
484
539
  async function remove(leaving) {
485
540
  await deps.durably(async (local) => {
486
- const removed = [];
487
- for (const conversation of leaving) {
488
- for (const identity of await local.messageIdentities(conversation)) {
489
- removed.push({ conversation, identity, text: null });
490
- }
491
- }
492
541
  await local.dropConversations(leaving);
493
542
  const changed = [];
494
543
  for (const conversation of leaving) {
@@ -505,9 +554,23 @@ export function createConversationStore(deps) {
505
554
  await slide(local, conversation, null);
506
555
  }
507
556
  if (changed.length > 0)
508
- deps.publish(conversationChangeSet(removed, changed));
557
+ deps.publish(conversationChangeSet(changed));
509
558
  });
510
559
  }
560
+ function missed(conversation) {
561
+ const read = reads.get(conversation);
562
+ const newest = listing.get(conversation)?.newest;
563
+ return (read === undefined ||
564
+ newest === undefined ||
565
+ partials.has(conversation) ||
566
+ (newest !== null && (read === null || newest > read)));
567
+ }
568
+ function noted(conversation, message) {
569
+ const entry = listing.get(conversation);
570
+ if (entry === undefined || (entry.newest !== null && entry.newest >= message.position))
571
+ return;
572
+ listing.set(conversation, { ...entry, newest: message.position });
573
+ }
511
574
  function gap(conversation) {
512
575
  gaps.set(conversation, (gaps.get(conversation) ?? 0) + 1);
513
576
  behind.add(conversation);
@@ -531,17 +594,18 @@ export function createConversationStore(deps) {
531
594
  reads.set(conversation, message.position);
532
595
  sealTurns(conversation, new Set([message.turn]));
533
596
  await slide(local, conversation, [message]);
534
- deps.publish(conversationChangeSet(changesOf(conversation, [message]), [conversation]));
597
+ deps.publish(conversationChangeSet([conversation]));
535
598
  });
536
599
  }
537
600
  async function readHistories(conversations, ended) {
538
601
  const generations = new Map(conversations.map((one) => [one, gaps.get(one) ?? 0]));
539
- let asking = conversations.map((conversation) => ({
602
+ let waiting = conversations.map((conversation) => ({
540
603
  conversation,
541
604
  after: reads.get(conversation) ?? undefined,
542
605
  }));
543
- while (asking.length > 0) {
544
- const result = await deps.call('conversation.history', {
606
+ while (waiting.length > 0) {
607
+ const asking = waiting.slice(0, HISTORY_CONVERSATIONS);
608
+ const result = await deps.history({
545
609
  conversations: asking.map(({ conversation, after }) => ({
546
610
  conversation,
547
611
  ...(after === undefined ? {} : { after }),
@@ -564,7 +628,7 @@ export function createConversationStore(deps) {
564
628
  if (!following.some((next) => next.conversation === conversation))
565
629
  ended(conversation);
566
630
  }
567
- asking = following;
631
+ waiting = [...waiting.slice(HISTORY_CONVERSATIONS), ...following];
568
632
  }
569
633
  return null;
570
634
  }
@@ -607,7 +671,7 @@ export function createConversationStore(deps) {
607
671
  behind.delete(conversation);
608
672
  await slide(local, conversation, arriving);
609
673
  if (arriving.length > 0 || sealing || whole) {
610
- deps.publish(conversationChangeSet(changesOf(conversation, arriving), [conversation]));
674
+ deps.publish(conversationChangeSet([conversation]));
611
675
  }
612
676
  });
613
677
  }
@@ -644,6 +708,10 @@ export function createConversationStore(deps) {
644
708
  live(conversation, { starting: event.step });
645
709
  return;
646
710
  }
711
+ if (event.kind === 'subagents') {
712
+ live(conversation, { subagents: structuredClone(event.subagents) });
713
+ return;
714
+ }
647
715
  if (event.kind === 'link') {
648
716
  live(conversation, { link: { connected: event.connected } });
649
717
  return;
@@ -655,8 +723,16 @@ export function createConversationStore(deps) {
655
723
  const arriving = acceptedMessage(event.message);
656
724
  if (arriving === null)
657
725
  return;
726
+ noted(conversation, arriving);
658
727
  if (replicated.has(conversation)) {
659
- void keep(conversation, arriving).catch(() => { });
728
+ if (deps.full()) {
729
+ gap(conversation);
730
+ return;
731
+ }
732
+ void keep(conversation, arriving).catch((error) => {
733
+ if (refusedForSpace(error))
734
+ gap(conversation);
735
+ });
660
736
  return;
661
737
  }
662
738
  if (sealTurns(conversation, new Set([arriving.turn])))
@@ -700,7 +776,7 @@ export function createConversationStore(deps) {
700
776
  drafts.set(from, left);
701
777
  for (const one of taken)
702
778
  drafts.set(to, one);
703
- deps.publish(conversationChangeSet([], [from, to]));
779
+ deps.publish(conversationChangeSet([from, to]));
704
780
  });
705
781
  }
706
782
  function withDraft(conversation, next) {
@@ -709,7 +785,7 @@ export function createConversationStore(deps) {
709
785
  if (following === undefined)
710
786
  return;
711
787
  await kept(local, conversation, following);
712
- deps.publish(conversationChangeSet([], [conversation]));
788
+ deps.publish(conversationChangeSet([conversation]));
713
789
  });
714
790
  }
715
791
  async function submitted(conversation, operation, draft) {
@@ -741,20 +817,21 @@ export function createConversationStore(deps) {
741
817
  });
742
818
  }
743
819
  async function dispatched(conversation, submission) {
744
- const dispatch = {};
820
+ const dispatch = { answered: false };
745
821
  sending.set(submission.operation, dispatch);
746
822
  try {
747
- const result = await invoke('conversation.send', conversation, {
748
- text: submission.text,
823
+ const result = await invoke('conversations/send', conversation, {
749
824
  operation_id: submission.operation,
825
+ text: submission.text,
750
826
  });
827
+ dispatch.answered = result.kind !== 'transport-uncertainty';
751
828
  if (result.kind === 'revoked-authorization')
752
829
  return result;
753
830
  if (result.kind !== 'action' && result.retryable) {
754
831
  deps.unanswered();
755
832
  return result;
756
833
  }
757
- const turn = answered(result, 'turn');
834
+ const turn = answered(result, 'message_id');
758
835
  await withDraft(conversation, async (current, local) => {
759
836
  const held = current?.submitted?.find((one) => one.operation === submission.operation);
760
837
  if (current === undefined || held === undefined || held.turn !== null)
@@ -774,25 +851,34 @@ export function createConversationStore(deps) {
774
851
  sending.delete(submission.operation);
775
852
  }
776
853
  }
777
- function invoke(name, conversation, extra = {}) {
778
- return deps.call(name, { conversation, ...extra });
854
+ function invoke(name, conversation, extra = { operation_id: changeBatchIdentity() }) {
855
+ return deps.call(name, { conversation_id: conversation, ...extra });
779
856
  }
780
857
  const surface = {
781
- async list() {
782
- await agentsReady();
783
- return entries();
858
+ list() {
859
+ return new Promise((settle) => {
860
+ const answer = (listed) => {
861
+ unlisted.delete(answer);
862
+ listWatchers.delete(answer);
863
+ settle(listed);
864
+ };
865
+ unlisted.add(answer);
866
+ learned();
867
+ });
784
868
  },
785
869
  async read(conversation, options = {}) {
786
- const asked = askedOf(options);
870
+ const { text, ...windowed } = options;
871
+ const asked = askedOf(windowed);
872
+ const phrase = phraseOf(text);
787
873
  return deps.durably(async (local) => {
788
- const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
789
- const total = asked.total ? await local.messageCount(conversation) : null;
874
+ const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before, phrase);
875
+ const total = asked.total ? await local.messageCount(conversation, phrase) : null;
790
876
  return structuredClone(viewOf(conversation, messages, frameOf(asked, messages, more, total)));
791
877
  });
792
878
  },
793
879
  async create(input) {
794
- const result = await deps.call('conversation.create', input);
795
- const conversation = answered(result, 'conversation');
880
+ const result = await deps.call('conversations/create', input);
881
+ const conversation = answered(result, 'conversation_id');
796
882
  if (conversation === null)
797
883
  return result;
798
884
  if (!listing.has(conversation))
@@ -803,8 +889,17 @@ export function createConversationStore(deps) {
803
889
  return result;
804
890
  },
805
891
  async send(conversation, operation = changeBatchIdentity(), draft) {
892
+ if (deps.full())
893
+ return DURABLE_WRITE;
806
894
  if (deps.online()) {
807
- const { submission, earlier } = await submitted(conversation, operation, draft);
895
+ const held = await submitted(conversation, operation, draft).catch((error) => {
896
+ if (refusedForSpace(error))
897
+ return null;
898
+ throw error;
899
+ });
900
+ if (held === null)
901
+ return DURABLE_WRITE;
902
+ const { submission, earlier } = held;
808
903
  if (!earlier || !deps.expired(operation))
809
904
  return dispatched(conversation, submission);
810
905
  await forgotten(conversation, submission);
@@ -817,38 +912,20 @@ export function createConversationStore(deps) {
817
912
  }
818
913
  return OFFLINE;
819
914
  },
820
- async attach(room, file) {
821
- if (!deps.online())
822
- return OFFLINE;
823
- return deps.call('conversation.attach', {
824
- room,
825
- ...(await declaredFile(file)),
826
- blob: file.blob,
827
- });
828
- },
829
915
  answer(conversation, answer) {
830
- return invoke('conversation.answer', conversation, { answer });
916
+ return invoke('conversations/interaction/answer', conversation, {
917
+ operation_id: changeBatchIdentity(),
918
+ ...answer,
919
+ });
831
920
  },
832
921
  interrupt(conversation) {
833
- return invoke('conversation.interrupt', conversation);
922
+ return invoke('conversations/interrupt', conversation);
834
923
  },
835
924
  kill(conversation) {
836
- return invoke('conversation.kill', conversation);
837
- },
838
- async cancel(conversation, turn) {
839
- const result = await invoke('conversation.cancel', conversation, { turn });
840
- if (result.kind !== 'action')
841
- return result;
842
- await withDraft(conversation, (current) => {
843
- const held = current?.submitted?.find((one) => one.turn === turn);
844
- if (current === undefined || held === undefined)
845
- return undefined;
846
- return returned(current, held, current.submitted.filter((one) => one !== held));
847
- });
848
- return result;
925
+ return invoke('conversations/kill', conversation);
849
926
  },
850
927
  delete(conversation) {
851
- return invoke('conversation.delete', conversation);
928
+ return invoke('conversations/delete', conversation);
852
929
  },
853
930
  };
854
931
  const chatDraft = {
@@ -877,7 +954,15 @@ export function createConversationStore(deps) {
877
954
  return {
878
955
  surface,
879
956
  chatDraft,
880
- hydrate(held, kept) {
957
+ hydrate(held, kept, list, cursor) {
958
+ if (list !== null && !listKnown) {
959
+ listing.clear();
960
+ for (const entry of list)
961
+ listing.set(entry.conversation, { ...entry });
962
+ listHeld = true;
963
+ listCursor = cursor;
964
+ deps.stream()?.hold(cursor);
965
+ }
881
966
  stored.clear();
882
967
  reads.clear();
883
968
  partials.clear();
@@ -891,6 +976,8 @@ export function createConversationStore(deps) {
891
976
  drafts.clear();
892
977
  for (const record of kept)
893
978
  drafts.set(record.conversation, record);
979
+ if (listHeld)
980
+ learned();
894
981
  },
895
982
  async reconcile() {
896
983
  if (!listKnown)
@@ -902,7 +989,7 @@ export function createConversationStore(deps) {
902
989
  !creations.has(conversation) &&
903
990
  (!conversation.startsWith(NEW_CHAT) || retiredChat(conversation)));
904
991
  for (const conversation of named) {
905
- if (!replicated.has(conversation))
992
+ if (!replicated.has(conversation) && missed(conversation))
906
993
  behind.add(conversation);
907
994
  }
908
995
  replicated = named;
@@ -911,6 +998,11 @@ export function createConversationStore(deps) {
911
998
  await remove(leaving);
912
999
  },
913
1000
  async catchUp(progress) {
1001
+ if (deps.full()) {
1002
+ if (behind.size > 0)
1003
+ progress.complete = false;
1004
+ return;
1005
+ }
914
1006
  const owed = (conversation) => behind.has(conversation) && replicated.has(conversation);
915
1007
  const read = async (conversations) => {
916
1008
  if (conversations.length === 0 || deps.closed())
@@ -959,12 +1051,11 @@ export function createConversationStore(deps) {
959
1051
  known() {
960
1052
  return listKnown;
961
1053
  },
962
- reconnected() {
963
- for (const conversation of replicated)
964
- gap(conversation);
965
- },
966
1054
  reopened() {
967
- sending.clear();
1055
+ relisting = null;
1056
+ for (const [operation, dispatch] of sending)
1057
+ if (!dispatch.answered)
1058
+ sending.delete(operation);
968
1059
  },
969
1060
  lost() {
970
1061
  catching.clear();
@@ -983,15 +1074,15 @@ export function createConversationStore(deps) {
983
1074
  views.set(key, view);
984
1075
  const watcher = { notify: deliver, ready: false };
985
1076
  view.watchers.add(watcher);
986
- void deps
987
- .durably(async (local) => {
1077
+ const reading = new AbortController();
1078
+ void untilAnswered(() => deps.durably(async (local) => {
988
1079
  if (view.window !== null)
989
1080
  return;
990
1081
  const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
991
1082
  view.window = messages;
992
1083
  view.more = more;
993
1084
  view.total = asked.total ? await local.messageCount(conversation) : null;
994
- })
1085
+ }), reading.signal)
995
1086
  .then(() => {
996
1087
  if (deps.closed() || !view.watchers.has(watcher))
997
1088
  return;
@@ -1001,6 +1092,7 @@ export function createConversationStore(deps) {
1001
1092
  })
1002
1093
  .catch(() => { });
1003
1094
  return () => {
1095
+ reading.abort();
1004
1096
  if (!view.watchers.delete(watcher))
1005
1097
  return;
1006
1098
  if (view.watchers.size === 0)
@@ -1008,77 +1100,88 @@ export function createConversationStore(deps) {
1008
1100
  };
1009
1101
  },
1010
1102
  watchList(deliver) {
1011
- listWatchers.add(deliver);
1012
- void agentsReady().then(() => {
1013
- if (!deps.closed() && listWatchers.has(deliver))
1014
- deliver(entries());
1015
- });
1103
+ unlisted.add(deliver);
1104
+ learned();
1016
1105
  return () => {
1106
+ unlisted.delete(deliver);
1017
1107
  listWatchers.delete(deliver);
1018
1108
  };
1019
1109
  },
1020
1110
  watchAgents(deliver) {
1021
- agentWatchers.add(deliver);
1022
- void agentsReady().then(() => {
1023
- if (!deps.closed() && agentWatchers.has(deliver))
1024
- deliver(agents());
1025
- });
1111
+ unnamed.add(deliver);
1112
+ learned();
1113
+ readAgents();
1026
1114
  return () => {
1115
+ unnamed.delete(deliver);
1027
1116
  agentWatchers.delete(deliver);
1028
1117
  };
1029
1118
  },
1119
+ learned,
1030
1120
  changed(set) {
1031
1121
  for (const conversation of set.conversations)
1032
1122
  emit(conversation);
1033
- const declaration = deps.agents();
1034
- if (declaration !== undefined &&
1035
- set.documents.some((change) => change.locator === declaration.locator)) {
1036
- agentsRead = readAgents().catch(() => {
1037
- agentsRead = null;
1038
- });
1039
- }
1040
1123
  },
1041
1124
  receive(event) {
1042
1125
  if (deps.closed())
1043
1126
  return false;
1044
1127
  if (event.kind === 'list' || event.kind === 'listed' || event.kind === 'unlisted') {
1045
1128
  if (event.kind === 'list') {
1046
- listing.clear();
1129
+ if (event.whole)
1130
+ relisting ??= new Map();
1047
1131
  for (const entry of event.entries) {
1048
- listing.set(entry.conversation, { ...entry });
1049
- creations.delete(entry.conversation);
1132
+ if (relisting === null)
1133
+ listed(entry);
1134
+ else
1135
+ relisting.set(entry.conversation, { ...entry });
1136
+ }
1137
+ if (event.more)
1138
+ return false;
1139
+ if (relisting !== null) {
1140
+ listing.clear();
1141
+ for (const entry of relisting.values())
1142
+ listed(entry);
1143
+ relisting = null;
1050
1144
  }
1145
+ listCursor = event.cursor;
1146
+ deps.stream()?.hold(event.cursor);
1051
1147
  listKnown = true;
1148
+ for (const conversation of replicated) {
1149
+ if (!listing.has(conversation))
1150
+ continue;
1151
+ if (!missed(conversation))
1152
+ behind.delete(conversation);
1153
+ else if (!behind.has(conversation))
1154
+ gap(conversation);
1155
+ }
1052
1156
  openingEnded();
1053
1157
  }
1054
1158
  else if (event.kind === 'listed') {
1055
- listing.set(event.entry.conversation, { ...event.entry });
1056
- creations.delete(event.entry.conversation);
1159
+ listed(event.entry);
1160
+ relisting?.set(event.entry.conversation, { ...event.entry });
1057
1161
  }
1058
1162
  else {
1059
1163
  listing.delete(event.conversation);
1164
+ relisting?.delete(event.conversation);
1060
1165
  }
1166
+ keepList();
1061
1167
  emitList();
1062
- return (event.kind !== 'list' &&
1168
+ return ((event.kind !== 'list' &&
1063
1169
  listKnown &&
1064
1170
  (listing.size !== replicated.size ||
1065
- [...listing.keys()].some((conversation) => !replicated.has(conversation))));
1171
+ [...listing.keys()].some((conversation) => !replicated.has(conversation)))) ||
1172
+ (listKnown && [...drafts.keys()].some(retiredChat)));
1066
1173
  }
1067
1174
  heard(event);
1068
1175
  return false;
1069
1176
  },
1070
- searchable() {
1071
- return [...(listKnown ? listing.keys() : stored)].sort();
1072
- },
1073
- acquired(conversation) {
1074
- return reads.has(conversation) && !partials.has(conversation);
1075
- },
1076
1177
  close() {
1077
1178
  views.clear();
1078
1179
  lives.clear();
1079
1180
  unsent.clear();
1080
1181
  listWatchers.clear();
1182
+ unlisted.clear();
1081
1183
  agentWatchers.clear();
1184
+ unnamed.clear();
1082
1185
  },
1083
1186
  };
1084
1187
  }