@agentshouse/mdruntime 0.1.0-cee9c8aa4cd86 → 0.1.0-cf1e7fdb9c600

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