@agentshouse/mdruntime 0.1.0-ce131cb435f8b → 0.1.0-ce41fec66d91b

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 (229) hide show
  1. package/README.md +18 -15
  2. package/dist/adapter.d.ts +110 -72
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/attached-model.d.ts +5 -1
  5. package/dist/attached-model.d.ts.map +1 -1
  6. package/dist/attached-model.js +38 -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 +25 -10
  11. package/dist/bootstrap.d.ts.map +1 -1
  12. package/dist/bootstrap.js +180 -103
  13. package/dist/chain.d.ts +11 -0
  14. package/dist/chain.d.ts.map +1 -0
  15. package/dist/chain.js +64 -0
  16. package/dist/change-set.d.ts +9 -16
  17. package/dist/change-set.d.ts.map +1 -1
  18. package/dist/change-set.js +11 -89
  19. package/dist/change.d.ts +31 -1
  20. package/dist/change.d.ts.map +1 -1
  21. package/dist/change.js +10 -1
  22. package/dist/client.d.ts +11 -8
  23. package/dist/client.d.ts.map +1 -1
  24. package/dist/client.js +80 -7
  25. package/dist/collection.d.ts +10 -22
  26. package/dist/collection.d.ts.map +1 -1
  27. package/dist/collection.js +39 -356
  28. package/dist/compile.d.ts +16 -0
  29. package/dist/compile.d.ts.map +1 -0
  30. package/dist/compile.js +786 -0
  31. package/dist/connection.d.ts +17 -11
  32. package/dist/connection.d.ts.map +1 -1
  33. package/dist/connection.js +2779 -1329
  34. package/dist/conversation.d.ts +19 -11
  35. package/dist/conversation.d.ts.map +1 -1
  36. package/dist/conversation.js +298 -166
  37. package/dist/digest.d.ts +7 -0
  38. package/dist/digest.d.ts.map +1 -0
  39. package/dist/digest.js +113 -0
  40. package/dist/durability.d.ts +2 -5
  41. package/dist/durability.d.ts.map +1 -1
  42. package/dist/durability.js +5 -0
  43. package/dist/entry.d.ts +4 -1
  44. package/dist/entry.d.ts.map +1 -1
  45. package/dist/entry.js +18 -24
  46. package/dist/file.d.ts +2 -19
  47. package/dist/file.d.ts.map +1 -1
  48. package/dist/file.js +7 -122
  49. package/dist/fulltext.d.ts +27 -0
  50. package/dist/fulltext.d.ts.map +1 -0
  51. package/dist/fulltext.js +370 -0
  52. package/dist/host.d.ts +3 -5
  53. package/dist/host.d.ts.map +1 -1
  54. package/dist/host.js +48 -21
  55. package/dist/identity.d.ts +0 -1
  56. package/dist/identity.d.ts.map +1 -1
  57. package/dist/identity.js +0 -3
  58. package/dist/index.d.ts +14 -11
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +6 -2
  61. package/dist/live.d.ts +22 -0
  62. package/dist/live.d.ts.map +1 -0
  63. package/dist/live.js +123 -0
  64. package/dist/media.d.ts +8 -0
  65. package/dist/media.d.ts.map +1 -0
  66. package/dist/media.js +218 -0
  67. package/dist/memory.d.ts +10 -6
  68. package/dist/memory.d.ts.map +1 -1
  69. package/dist/memory.js +195 -102
  70. package/dist/messages.d.ts +28 -0
  71. package/dist/messages.d.ts.map +1 -0
  72. package/dist/messages.js +90 -0
  73. package/dist/model.d.ts +6 -1
  74. package/dist/model.d.ts.map +1 -1
  75. package/dist/model.js +7 -10
  76. package/dist/name.d.ts +4 -0
  77. package/dist/name.d.ts.map +1 -0
  78. package/dist/name.js +122 -0
  79. package/dist/observation.d.ts +13 -0
  80. package/dist/observation.d.ts.map +1 -1
  81. package/dist/observation.js +84 -0
  82. package/dist/opened.d.ts +22 -0
  83. package/dist/opened.d.ts.map +1 -0
  84. package/dist/opened.js +107 -0
  85. package/dist/outcome.d.ts +40 -8
  86. package/dist/outcome.d.ts.map +1 -1
  87. package/dist/outcome.js +38 -2
  88. package/dist/overlay.d.ts +2 -6
  89. package/dist/overlay.d.ts.map +1 -1
  90. package/dist/overlay.js +87 -176
  91. package/dist/paths.d.ts +1 -0
  92. package/dist/paths.d.ts.map +1 -1
  93. package/dist/paths.js +4 -0
  94. package/dist/query.d.ts +11 -1
  95. package/dist/query.d.ts.map +1 -1
  96. package/dist/query.js +13 -1
  97. package/dist/reach.d.ts +13 -4
  98. package/dist/reach.d.ts.map +1 -1
  99. package/dist/reach.js +200 -78
  100. package/dist/readiness.d.ts +14 -15
  101. package/dist/readiness.d.ts.map +1 -1
  102. package/dist/readiness.js +2 -8
  103. package/dist/recovery.d.ts +3 -2
  104. package/dist/recovery.d.ts.map +1 -1
  105. package/dist/recovery.js +34 -7
  106. package/dist/refresh.d.ts +18 -15
  107. package/dist/refresh.d.ts.map +1 -1
  108. package/dist/refresh.js +136 -58
  109. package/dist/replica.d.ts +55 -38
  110. package/dist/replica.d.ts.map +1 -1
  111. package/dist/replica.js +278 -198
  112. package/dist/room-draft.d.ts +21 -3
  113. package/dist/room-draft.d.ts.map +1 -1
  114. package/dist/room-draft.js +102 -28
  115. package/dist/rows.d.ts +38 -31
  116. package/dist/rows.d.ts.map +1 -1
  117. package/dist/rows.js +173 -101
  118. package/dist/save.d.ts +52 -15
  119. package/dist/save.d.ts.map +1 -1
  120. package/dist/save.js +504 -182
  121. package/dist/search.d.ts +11 -43
  122. package/dist/search.d.ts.map +1 -1
  123. package/dist/search.js +0 -213
  124. package/dist/shared.d.ts +4 -3
  125. package/dist/shared.d.ts.map +1 -1
  126. package/dist/shared.js +62 -35
  127. package/dist/status.d.ts +4 -3
  128. package/dist/status.d.ts.map +1 -1
  129. package/dist/status.js +3 -1
  130. package/dist/store.d.ts +81 -101
  131. package/dist/store.d.ts.map +1 -1
  132. package/dist/store.js +300 -693
  133. package/dist/stored.d.ts +130 -0
  134. package/dist/stored.d.ts.map +1 -0
  135. package/dist/stored.js +560 -0
  136. package/dist/tables.d.ts +325 -0
  137. package/dist/tables.d.ts.map +1 -0
  138. package/dist/tables.js +578 -0
  139. package/dist/transfer.d.ts +0 -5
  140. package/dist/transfer.d.ts.map +1 -1
  141. package/dist/turn.d.ts +2 -2
  142. package/dist/turn.d.ts.map +1 -1
  143. package/dist/turn.js +34 -23
  144. package/dist/validation.d.ts +29 -0
  145. package/dist/validation.d.ts.map +1 -0
  146. package/dist/validation.js +101 -0
  147. package/dist/windows.d.ts +2 -6
  148. package/dist/windows.d.ts.map +1 -1
  149. package/dist/windows.js +30 -34
  150. package/dist/wire.d.ts +17 -5
  151. package/dist/wire.d.ts.map +1 -1
  152. package/dist/wire.js +5 -2
  153. package/dist/words.d.ts +19 -0
  154. package/dist/words.d.ts.map +1 -0
  155. package/dist/words.js +156 -0
  156. package/package.json +18 -19
  157. package/AGENTS.md +0 -299
  158. package/dist/chat/acts.d.ts +0 -33
  159. package/dist/chat/acts.d.ts.map +0 -1
  160. package/dist/chat/acts.js +0 -36
  161. package/dist/chat/context.d.ts +0 -3
  162. package/dist/chat/context.d.ts.map +0 -1
  163. package/dist/chat/context.js +0 -10
  164. package/dist/chat/earlier.d.ts +0 -10
  165. package/dist/chat/earlier.d.ts.map +0 -1
  166. package/dist/chat/earlier.js +0 -54
  167. package/dist/chat/input.d.ts +0 -9
  168. package/dist/chat/input.d.ts.map +0 -1
  169. package/dist/chat/input.js +0 -99
  170. package/dist/chat/kit.d.ts +0 -61
  171. package/dist/chat/kit.d.ts.map +0 -1
  172. package/dist/chat/kit.js +0 -123
  173. package/dist/chat/lasting.d.ts +0 -6
  174. package/dist/chat/lasting.d.ts.map +0 -1
  175. package/dist/chat/lasting.js +0 -19
  176. package/dist/chat/list.d.ts +0 -27
  177. package/dist/chat/list.d.ts.map +0 -1
  178. package/dist/chat/list.js +0 -99
  179. package/dist/chat/markdown.d.ts +0 -20
  180. package/dist/chat/markdown.d.ts.map +0 -1
  181. package/dist/chat/markdown.js +0 -188
  182. package/dist/chat/message.d.ts +0 -6
  183. package/dist/chat/message.d.ts.map +0 -1
  184. package/dist/chat/message.js +0 -192
  185. package/dist/chat/messages.d.ts +0 -22
  186. package/dist/chat/messages.d.ts.map +0 -1
  187. package/dist/chat/messages.js +0 -155
  188. package/dist/chat/name.d.ts +0 -6
  189. package/dist/chat/name.d.ts.map +0 -1
  190. package/dist/chat/name.js +0 -37
  191. package/dist/chat/opened.d.ts +0 -11
  192. package/dist/chat/opened.d.ts.map +0 -1
  193. package/dist/chat/opened.js +0 -17
  194. package/dist/chat/overlay.d.ts +0 -31
  195. package/dist/chat/overlay.d.ts.map +0 -1
  196. package/dist/chat/overlay.js +0 -97
  197. package/dist/chat/parts.d.ts +0 -57
  198. package/dist/chat/parts.d.ts.map +0 -1
  199. package/dist/chat/parts.js +0 -119
  200. package/dist/chat/process.d.ts +0 -20
  201. package/dist/chat/process.d.ts.map +0 -1
  202. package/dist/chat/process.js +0 -32
  203. package/dist/chat/provider.d.ts +0 -63
  204. package/dist/chat/provider.d.ts.map +0 -1
  205. package/dist/chat/provider.js +0 -628
  206. package/dist/chat/question.d.ts +0 -9
  207. package/dist/chat/question.d.ts.map +0 -1
  208. package/dist/chat/question.js +0 -69
  209. package/dist/chat/questions.d.ts +0 -31
  210. package/dist/chat/questions.d.ts.map +0 -1
  211. package/dist/chat/questions.js +0 -111
  212. package/dist/chat/read.d.ts +0 -5
  213. package/dist/chat/read.d.ts.map +0 -1
  214. package/dist/chat/read.js +0 -13
  215. package/dist/chat/ready.d.ts +0 -34
  216. package/dist/chat/ready.d.ts.map +0 -1
  217. package/dist/chat/ready.js +0 -91
  218. package/dist/chat/style.d.ts +0 -4
  219. package/dist/chat/style.d.ts.map +0 -1
  220. package/dist/chat/style.js +0 -302
  221. package/dist/chat.d.ts +0 -14
  222. package/dist/chat.d.ts.map +0 -1
  223. package/dist/chat.js +0 -8
  224. package/dist/read-side.d.ts +0 -27
  225. package/dist/read-side.d.ts.map +0 -1
  226. package/dist/read-side.js +0 -824
  227. package/dist/reads.d.ts +0 -11
  228. package/dist/reads.d.ts.map +0 -1
  229. 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,
@@ -10,8 +11,21 @@ const QUIET = {
10
11
  process: null,
11
12
  commands: [],
12
13
  options: [],
14
+ starting: null,
15
+ subagents: [],
16
+ link: null,
17
+ deliveryUnknown: [],
13
18
  };
14
- const FACTS = ['questions', 'process', 'commands', 'options'];
19
+ const FACTS = [
20
+ 'questions',
21
+ 'process',
22
+ 'commands',
23
+ 'options',
24
+ 'starting',
25
+ 'subagents',
26
+ 'link',
27
+ 'deliveryUnknown',
28
+ ];
15
29
  export function unheldView(conversation) {
16
30
  return {
17
31
  conversation,
@@ -21,19 +35,26 @@ export function unheldView(conversation) {
21
35
  process: null,
22
36
  commands: [],
23
37
  options: [],
38
+ starting: null,
39
+ subagents: [],
40
+ link: null,
41
+ deliveryUnknown: [],
24
42
  chatDraft: null,
25
43
  };
26
44
  }
27
45
  export const SESSION_STARTED = 'Session started';
28
46
  const NEW_CHAT = 'new:';
47
+ export const HISTORY_CONVERSATIONS = 64;
29
48
  export function newChat(agent) {
30
49
  return `${NEW_CHAT}${agent}`;
31
50
  }
32
51
  function creationOf(input) {
33
52
  if (typeof input !== 'object' || input === null)
34
53
  return null;
35
- const { agent_id: agent, operation_id: operation } = input;
36
- return typeof agent === 'string' && typeof operation === 'string' ? { agent, operation } : null;
54
+ const { agent_id: agent, operation_id: operation, replaces, } = input;
55
+ return typeof agent === 'string' && typeof operation === 'string' && replaces === undefined
56
+ ? { agent, operation }
57
+ : null;
37
58
  }
38
59
  function startedTurn(turn, operation) {
39
60
  if (operation.op === 'begin')
@@ -193,8 +214,14 @@ function askedOf(options) {
193
214
  return { limit: capped(limit), after, before: beforeOf(after), total: total === true };
194
215
  }
195
216
  const EXPIRED = { kind: 'rejected', code: 'expired', fields: {}, retryable: false };
217
+ const DURABLE_WRITE = {
218
+ kind: 'rejected',
219
+ code: 'durable-write',
220
+ fields: {},
221
+ retryable: true,
222
+ };
196
223
  function unwritten(draft) {
197
- return draft.text === '' && draft.files.length === 0;
224
+ return draft.text === '';
198
225
  }
199
226
  function pending(draft) {
200
227
  return {
@@ -210,10 +237,7 @@ function withSubmitted(draft, submitted) {
210
237
  return submitted.length === 0 ? unsent : { ...unsent, submitted };
211
238
  }
212
239
  function prepended(draft, said) {
213
- return {
214
- text: [said.text, draft.text].filter((one) => one !== '').join('\n'),
215
- files: [...said.files, ...draft.files],
216
- };
240
+ return { text: [said.text, draft.text].filter((one) => one !== '').join('\n') };
217
241
  }
218
242
  function returned(draft, submission, others) {
219
243
  return withSubmitted({
@@ -235,13 +259,19 @@ export function createConversationStore(deps) {
235
259
  const unsent = new Map();
236
260
  const views = new Map();
237
261
  const listing = new Map();
262
+ let relisting = null;
263
+ let listCursor = null;
238
264
  const creations = new Set();
239
265
  const listWatchers = new Set();
266
+ const unlisted = new Set();
240
267
  let listKnown = false;
268
+ let listHeld = false;
269
+ let listKept = false;
241
270
  const agentWatchers = new Set();
242
- let agentNames = new Map();
243
- let retiredAgents = new Set();
244
- let agentsRead = null;
271
+ const unnamed = new Set();
272
+ let agentsShown = null;
273
+ let listedAgents = null;
274
+ let agentsReading = false;
245
275
  let replicated = new Set();
246
276
  let handedReplicated;
247
277
  function liveOf(conversation) {
@@ -264,9 +294,13 @@ export function createConversationStore(deps) {
264
294
  process: facts.process === null ? null : { ...facts.process },
265
295
  commands: structuredClone(facts.commands),
266
296
  options: structuredClone(facts.options),
297
+ starting: facts.starting,
298
+ subagents: structuredClone(facts.subagents),
299
+ link: facts.link === null ? null : { ...facts.link },
300
+ deliveryUnknown: [...facts.deliveryUnknown],
267
301
  chatDraft: draft === undefined || unwritten(draft)
268
302
  ? null
269
- : { text: draft.text, files: [...draft.files], revision: draft.revision },
303
+ : { text: draft.text, revision: draft.revision },
270
304
  };
271
305
  }
272
306
  function emit(conversation) {
@@ -308,9 +342,6 @@ export function createConversationStore(deps) {
308
342
  }
309
343
  }
310
344
  }
311
- function changesOf(conversation, arriving) {
312
- return arriving.map(({ identity, text }) => ({ conversation, identity, text }));
313
- }
314
345
  function stateOf(conversation) {
315
346
  const facts = liveOf(conversation);
316
347
  if (facts.questions.length > 0)
@@ -320,34 +351,110 @@ export function createConversationStore(deps) {
320
351
  function entries() {
321
352
  return [...listing.values()].map((entry) => ({
322
353
  conversation: entry.conversation,
323
- agent: { identity: entry.agent, name: agentNames.get(entry.agent) ?? null },
354
+ agent: { identity: entry.agent, name: entry.agentName },
324
355
  name: entry.name,
325
356
  created: entry.created,
326
357
  finished: entry.finished,
327
358
  outcome: entry.outcome,
359
+ waiting: entry.waiting,
328
360
  state: stateOf(entry.conversation),
329
361
  started: lives.get(entry.conversation)?.turn?.started ?? null,
330
362
  }));
331
363
  }
364
+ function keepList() {
365
+ if (!listKnown || listKept)
366
+ return;
367
+ listKept = true;
368
+ queueMicrotask(() => {
369
+ listKept = false;
370
+ if (deps.closed())
371
+ return;
372
+ const entries = [...listing.values()];
373
+ const cursor = listCursor;
374
+ void deps
375
+ .durably(async (local) => {
376
+ await local.fact('conversationList', entries);
377
+ await local.fact('conversationCursor', cursor);
378
+ })
379
+ .catch(() => { });
380
+ });
381
+ }
382
+ function listed(entry) {
383
+ listing.set(entry.conversation, { ...entry });
384
+ creations.delete(entry.conversation);
385
+ }
332
386
  function emitList() {
333
- if (deps.closed() || listWatchers.size === 0)
387
+ if (deps.closed())
334
388
  return;
335
- const value = entries();
336
- for (const watcher of listWatchers)
337
- watcher(value);
389
+ if (listWatchers.size > 0) {
390
+ const value = entries();
391
+ for (const watcher of listWatchers)
392
+ watcher(value);
393
+ }
394
+ emitAgents();
395
+ learned();
396
+ }
397
+ function learned() {
398
+ if (deps.closed())
399
+ return;
400
+ if (!listKnown && !listHeld && deps.stream() !== undefined && deps.online())
401
+ return;
402
+ if (unlisted.size > 0) {
403
+ const value = entries();
404
+ for (const watcher of [...unlisted]) {
405
+ unlisted.delete(watcher);
406
+ listWatchers.add(watcher);
407
+ watcher(value);
408
+ }
409
+ }
410
+ if (unnamed.size > 0) {
411
+ const value = agents();
412
+ for (const watcher of [...unnamed]) {
413
+ unnamed.delete(watcher);
414
+ agentWatchers.add(watcher);
415
+ watcher(value);
416
+ }
417
+ }
338
418
  }
339
419
  function agents() {
340
- return [...agentNames]
341
- .filter(([identity]) => !retiredAgents.has(identity))
342
- .map(([identity, name]) => ({ identity, name }))
420
+ const named = new Map();
421
+ for (const agent of listedAgents ?? [])
422
+ named.set(agent.agent, agent);
423
+ for (const entry of listing.values()) {
424
+ named.set(entry.agent, { name: entry.agentName, retired: entry.agentRetired });
425
+ }
426
+ return [...named]
427
+ .filter(([, agent]) => !agent.retired)
428
+ .map(([identity, agent]) => ({ identity, name: agent.name }))
343
429
  .sort((left, right) => left.name === right.name
344
430
  ? left.identity.localeCompare(right.identity)
345
431
  : left.name.localeCompare(right.name));
346
432
  }
433
+ function readAgents() {
434
+ const stream = deps.stream();
435
+ if (stream?.agents === undefined || !deps.online() || agentsReading)
436
+ return;
437
+ agentsReading = true;
438
+ void stream
439
+ .agents()
440
+ .then((read) => {
441
+ if (read === null)
442
+ return;
443
+ listedAgents = read;
444
+ emitAgents();
445
+ }, () => { })
446
+ .finally(() => {
447
+ agentsReading = false;
448
+ });
449
+ }
347
450
  function emitAgents() {
348
451
  if (deps.closed() || agentWatchers.size === 0)
349
452
  return;
350
453
  const value = agents();
454
+ const shown = JSON.stringify(value);
455
+ if (shown === agentsShown)
456
+ return;
457
+ agentsShown = shown;
351
458
  for (const watcher of agentWatchers)
352
459
  watcher(value);
353
460
  }
@@ -363,48 +470,11 @@ export function createConversationStore(deps) {
363
470
  if (stateOf(conversation) !== before || next?.turn?.started !== began)
364
471
  emitList();
365
472
  }
366
- async function readAgents() {
367
- const declaration = deps.agents();
368
- if (declaration === undefined)
369
- return;
370
- const held = await deps.documents(declaration);
371
- if ('pending' in held)
372
- return;
373
- const { documents } = held;
374
- const names = new Map();
375
- const retired = new Set();
376
- for (const document of documents) {
377
- if (document.type !== declaration.type)
378
- continue;
379
- const identity = document.fields?.[declaration.identity];
380
- const name = document.fields?.[declaration.name];
381
- if (typeof identity !== 'string' || typeof name !== 'string')
382
- continue;
383
- names.set(identity, name);
384
- const ended = declaration.retired === undefined ? null : document.fields?.[declaration.retired];
385
- if (ended !== undefined && ended !== null)
386
- retired.add(identity);
387
- }
388
- const named = JSON.stringify([...names]) !== JSON.stringify([...agentNames]);
389
- if (!named && JSON.stringify([...retired]) === JSON.stringify([...retiredAgents]))
390
- return;
391
- agentNames = names;
392
- retiredAgents = retired;
393
- if (named)
394
- emitList();
395
- emitAgents();
396
- const ended = [...drafts.keys()].filter(retiredChat);
397
- if (ended.length > 0)
398
- await remove(ended);
399
- }
400
473
  function retiredChat(conversation) {
401
- return (conversation.startsWith(NEW_CHAT) && retiredAgents.has(conversation.slice(NEW_CHAT.length)));
402
- }
403
- function agentsReady() {
404
- agentsRead ??= readAgents().catch(() => {
405
- agentsRead = null;
406
- });
407
- return agentsRead;
474
+ if (!conversation.startsWith(NEW_CHAT))
475
+ return false;
476
+ const agent = conversation.slice(NEW_CHAT.length);
477
+ return [...listing.values()].some((entry) => entry.agent === agent && entry.agentRetired);
408
478
  }
409
479
  function live(conversation, change) {
410
480
  const owed = unsent.get(conversation);
@@ -426,6 +496,12 @@ export function createConversationStore(deps) {
426
496
  process: facts.has('process') ? QUIET.process : held.process,
427
497
  commands: facts.has('commands') ? QUIET.commands : held.commands,
428
498
  options: facts.has('options') ? QUIET.options : held.options,
499
+ starting: facts.has('starting') ? QUIET.starting : held.starting,
500
+ subagents: facts.has('subagents') ? QUIET.subagents : held.subagents,
501
+ link: facts.has('link') ? QUIET.link : held.link,
502
+ deliveryUnknown: facts.has('deliveryUnknown')
503
+ ? QUIET.deliveryUnknown
504
+ : held.deliveryUnknown,
429
505
  });
430
506
  emit(conversation);
431
507
  }
@@ -456,12 +532,6 @@ export function createConversationStore(deps) {
456
532
  }
457
533
  async function remove(leaving) {
458
534
  await deps.durably(async (local) => {
459
- const removed = [];
460
- for (const conversation of leaving) {
461
- for (const identity of await local.messageIdentities(conversation)) {
462
- removed.push({ conversation, identity, text: null });
463
- }
464
- }
465
535
  await local.dropConversations(leaving);
466
536
  const changed = [];
467
537
  for (const conversation of leaving) {
@@ -478,9 +548,23 @@ export function createConversationStore(deps) {
478
548
  await slide(local, conversation, null);
479
549
  }
480
550
  if (changed.length > 0)
481
- deps.publish(conversationChangeSet(removed, changed));
551
+ deps.publish(conversationChangeSet(changed));
482
552
  });
483
553
  }
554
+ function missed(conversation) {
555
+ const read = reads.get(conversation);
556
+ const newest = listing.get(conversation)?.newest;
557
+ return (read === undefined ||
558
+ newest === undefined ||
559
+ partials.has(conversation) ||
560
+ (newest !== null && (read === null || newest > read)));
561
+ }
562
+ function noted(conversation, message) {
563
+ const entry = listing.get(conversation);
564
+ if (entry === undefined || (entry.newest !== null && entry.newest >= message.position))
565
+ return;
566
+ listing.set(conversation, { ...entry, newest: message.position });
567
+ }
484
568
  function gap(conversation) {
485
569
  gaps.set(conversation, (gaps.get(conversation) ?? 0) + 1);
486
570
  behind.add(conversation);
@@ -504,17 +588,18 @@ export function createConversationStore(deps) {
504
588
  reads.set(conversation, message.position);
505
589
  sealTurns(conversation, new Set([message.turn]));
506
590
  await slide(local, conversation, [message]);
507
- deps.publish(conversationChangeSet(changesOf(conversation, [message]), [conversation]));
591
+ deps.publish(conversationChangeSet([conversation]));
508
592
  });
509
593
  }
510
594
  async function readHistories(conversations, ended) {
511
595
  const generations = new Map(conversations.map((one) => [one, gaps.get(one) ?? 0]));
512
- let asking = conversations.map((conversation) => ({
596
+ let waiting = conversations.map((conversation) => ({
513
597
  conversation,
514
598
  after: reads.get(conversation) ?? undefined,
515
599
  }));
516
- while (asking.length > 0) {
517
- const result = await deps.call('conversation.history', {
600
+ while (waiting.length > 0) {
601
+ const asking = waiting.slice(0, HISTORY_CONVERSATIONS);
602
+ const result = await deps.history({
518
603
  conversations: asking.map(({ conversation, after }) => ({
519
604
  conversation,
520
605
  ...(after === undefined ? {} : { after }),
@@ -537,7 +622,7 @@ export function createConversationStore(deps) {
537
622
  if (!following.some((next) => next.conversation === conversation))
538
623
  ended(conversation);
539
624
  }
540
- asking = following;
625
+ waiting = [...waiting.slice(HISTORY_CONVERSATIONS), ...following];
541
626
  }
542
627
  return null;
543
628
  }
@@ -580,7 +665,7 @@ export function createConversationStore(deps) {
580
665
  behind.delete(conversation);
581
666
  await slide(local, conversation, arriving);
582
667
  if (arriving.length > 0 || sealing || whole) {
583
- deps.publish(conversationChangeSet(changesOf(conversation, arriving), [conversation]));
668
+ deps.publish(conversationChangeSet([conversation]));
584
669
  }
585
670
  });
586
671
  }
@@ -613,11 +698,35 @@ export function createConversationStore(deps) {
613
698
  live(conversation, { options: structuredClone(event.options) });
614
699
  return;
615
700
  }
701
+ if (event.kind === 'starting') {
702
+ live(conversation, { starting: event.step });
703
+ return;
704
+ }
705
+ if (event.kind === 'subagents') {
706
+ live(conversation, { subagents: structuredClone(event.subagents) });
707
+ return;
708
+ }
709
+ if (event.kind === 'link') {
710
+ live(conversation, { link: { connected: event.connected } });
711
+ return;
712
+ }
713
+ if (event.kind === 'deliveries') {
714
+ live(conversation, { deliveryUnknown: [...event.unknown] });
715
+ return;
716
+ }
616
717
  const arriving = acceptedMessage(event.message);
617
718
  if (arriving === null)
618
719
  return;
720
+ noted(conversation, arriving);
619
721
  if (replicated.has(conversation)) {
620
- void keep(conversation, arriving).catch(() => { });
722
+ if (deps.full()) {
723
+ gap(conversation);
724
+ return;
725
+ }
726
+ void keep(conversation, arriving).catch((error) => {
727
+ if (refusedForSpace(error))
728
+ gap(conversation);
729
+ });
621
730
  return;
622
731
  }
623
732
  if (sealTurns(conversation, new Set([arriving.turn])))
@@ -652,7 +761,6 @@ export function createConversationStore(deps) {
652
761
  const blank = {
653
762
  conversation: from,
654
763
  text: '',
655
- files: [],
656
764
  revision: chatDraftRevision(),
657
765
  };
658
766
  const { moves: _answered, ...unsent } = held ?? blank;
@@ -662,7 +770,7 @@ export function createConversationStore(deps) {
662
770
  drafts.set(from, left);
663
771
  for (const one of taken)
664
772
  drafts.set(to, one);
665
- deps.publish(conversationChangeSet([], [from, to]));
773
+ deps.publish(conversationChangeSet([from, to]));
666
774
  });
667
775
  }
668
776
  function withDraft(conversation, next) {
@@ -671,7 +779,7 @@ export function createConversationStore(deps) {
671
779
  if (following === undefined)
672
780
  return;
673
781
  await kept(local, conversation, following);
674
- deps.publish(conversationChangeSet([], [conversation]));
782
+ deps.publish(conversationChangeSet([conversation]));
675
783
  });
676
784
  }
677
785
  async function submitted(conversation, operation, draft) {
@@ -683,17 +791,12 @@ export function createConversationStore(deps) {
683
791
  if (submission !== undefined)
684
792
  return undefined;
685
793
  const said = draft ?? current;
686
- submission = {
687
- operation,
688
- text: said?.text ?? '',
689
- files: [...(said?.files ?? [])],
690
- turn: null,
691
- };
794
+ submission = { operation, text: said?.text ?? '', turn: null };
692
795
  return {
693
796
  conversation,
694
797
  ...(draft === undefined || current === undefined
695
- ? { text: '', files: [], revision: chatDraftRevision() }
696
- : { text: current.text, files: current.files, revision: current.revision }),
798
+ ? { text: '', revision: chatDraftRevision() }
799
+ : { text: current.text, revision: current.revision }),
697
800
  submitted: [...(current?.submitted ?? []), submission],
698
801
  };
699
802
  });
@@ -708,22 +811,21 @@ export function createConversationStore(deps) {
708
811
  });
709
812
  }
710
813
  async function dispatched(conversation, submission) {
711
- const dispatch = {};
814
+ const dispatch = { answered: false };
712
815
  sending.set(submission.operation, dispatch);
713
816
  try {
714
- const files = await Promise.all(submission.files.map(async (file) => ({ ...(await declaredFile(file)), blob: file.blob })));
715
- const result = await invoke('conversation.send', conversation, {
716
- text: submission.text,
717
- files,
817
+ const result = await invoke('conversations/send', conversation, {
718
818
  operation_id: submission.operation,
819
+ text: submission.text,
719
820
  });
821
+ dispatch.answered = result.kind !== 'transport-uncertainty';
720
822
  if (result.kind === 'revoked-authorization')
721
823
  return result;
722
824
  if (result.kind !== 'action' && result.retryable) {
723
825
  deps.unanswered();
724
826
  return result;
725
827
  }
726
- const turn = answered(result, 'turn');
828
+ const turn = answered(result, 'message_id');
727
829
  await withDraft(conversation, async (current, local) => {
728
830
  const held = current?.submitted?.find((one) => one.operation === submission.operation);
729
831
  if (current === undefined || held === undefined || held.turn !== null)
@@ -743,13 +845,20 @@ export function createConversationStore(deps) {
743
845
  sending.delete(submission.operation);
744
846
  }
745
847
  }
746
- function invoke(name, conversation, extra = {}) {
747
- return deps.call(name, { conversation, ...extra });
848
+ function invoke(name, conversation, extra = { operation_id: changeBatchIdentity() }) {
849
+ return deps.call(name, { conversation_id: conversation, ...extra });
748
850
  }
749
851
  const surface = {
750
- async list() {
751
- await agentsReady();
752
- return entries();
852
+ list() {
853
+ return new Promise((settle) => {
854
+ const answer = (listed) => {
855
+ unlisted.delete(answer);
856
+ listWatchers.delete(answer);
857
+ settle(listed);
858
+ };
859
+ unlisted.add(answer);
860
+ learned();
861
+ });
753
862
  },
754
863
  async read(conversation, options = {}) {
755
864
  const asked = askedOf(options);
@@ -760,8 +869,8 @@ export function createConversationStore(deps) {
760
869
  });
761
870
  },
762
871
  async create(input) {
763
- const result = await deps.call('conversation.create', input);
764
- const conversation = answered(result, 'conversation');
872
+ const result = await deps.call('conversations/create', input);
873
+ const conversation = answered(result, 'conversation_id');
765
874
  if (conversation === null)
766
875
  return result;
767
876
  if (!listing.has(conversation))
@@ -772,8 +881,17 @@ export function createConversationStore(deps) {
772
881
  return result;
773
882
  },
774
883
  async send(conversation, operation = changeBatchIdentity(), draft) {
884
+ if (deps.full())
885
+ return DURABLE_WRITE;
775
886
  if (deps.online()) {
776
- const { submission, earlier } = await submitted(conversation, operation, draft);
887
+ const held = await submitted(conversation, operation, draft).catch((error) => {
888
+ if (refusedForSpace(error))
889
+ return null;
890
+ throw error;
891
+ });
892
+ if (held === null)
893
+ return DURABLE_WRITE;
894
+ const { submission, earlier } = held;
777
895
  if (!earlier || !deps.expired(operation))
778
896
  return dispatched(conversation, submission);
779
897
  await forgotten(conversation, submission);
@@ -782,33 +900,24 @@ export function createConversationStore(deps) {
782
900
  if (draft !== undefined) {
783
901
  await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
784
902
  ? undefined
785
- : returned(current ?? { conversation, text: '', files: [], revision: '' }, { operation, ...draft, turn: null }, current?.submitted ?? []));
903
+ : returned(current ?? { conversation, text: '', revision: '' }, { operation, ...draft, turn: null }, current?.submitted ?? []));
786
904
  }
787
905
  return OFFLINE;
788
906
  },
789
907
  answer(conversation, answer) {
790
- return invoke('conversation.answer', conversation, { answer });
908
+ return invoke('conversations/interaction/answer', conversation, {
909
+ operation_id: changeBatchIdentity(),
910
+ ...answer,
911
+ });
791
912
  },
792
913
  interrupt(conversation) {
793
- return invoke('conversation.interrupt', conversation);
914
+ return invoke('conversations/interrupt', conversation);
794
915
  },
795
916
  kill(conversation) {
796
- return invoke('conversation.kill', conversation);
797
- },
798
- async cancel(conversation, turn) {
799
- const result = await invoke('conversation.cancel', conversation, { turn });
800
- if (result.kind !== 'action')
801
- return result;
802
- await withDraft(conversation, (current) => {
803
- const held = current?.submitted?.find((one) => one.turn === turn);
804
- if (current === undefined || held === undefined)
805
- return undefined;
806
- return returned(current, held, current.submitted.filter((one) => one !== held));
807
- });
808
- return result;
917
+ return invoke('conversations/kill', conversation);
809
918
  },
810
919
  delete(conversation) {
811
- return invoke('conversation.delete', conversation);
920
+ return invoke('conversations/delete', conversation);
812
921
  },
813
922
  };
814
923
  const chatDraft = {
@@ -816,7 +925,6 @@ export function createConversationStore(deps) {
816
925
  return withDraft(conversation, (current) => ({
817
926
  conversation,
818
927
  text: draft.text,
819
- files: [...draft.files],
820
928
  revision,
821
929
  ...(current === undefined ? {} : pending(current)),
822
930
  }));
@@ -824,9 +932,7 @@ export function createConversationStore(deps) {
824
932
  prepend(conversation, draft) {
825
933
  return withDraft(conversation, (current) => ({
826
934
  conversation,
827
- ...(current === undefined
828
- ? { text: draft.text, files: [...draft.files] }
829
- : prepended(current, draft)),
935
+ ...(current === undefined ? { text: draft.text } : prepended(current, draft)),
830
936
  revision: chatDraftRevision(),
831
937
  ...(current === undefined ? {} : pending(current)),
832
938
  }));
@@ -834,19 +940,21 @@ export function createConversationStore(deps) {
834
940
  discard(conversation) {
835
941
  return withDraft(conversation, (current) => current === undefined
836
942
  ? undefined
837
- : {
838
- conversation,
839
- text: '',
840
- files: [],
841
- revision: chatDraftRevision(),
842
- ...pending(current),
843
- });
943
+ : { conversation, text: '', revision: chatDraftRevision(), ...pending(current) });
844
944
  },
845
945
  };
846
946
  return {
847
947
  surface,
848
948
  chatDraft,
849
- hydrate(held, kept) {
949
+ hydrate(held, kept, list, cursor) {
950
+ if (list !== null && !listKnown) {
951
+ listing.clear();
952
+ for (const entry of list)
953
+ listing.set(entry.conversation, { ...entry });
954
+ listHeld = true;
955
+ listCursor = cursor;
956
+ deps.stream()?.hold(cursor);
957
+ }
850
958
  stored.clear();
851
959
  reads.clear();
852
960
  partials.clear();
@@ -860,6 +968,8 @@ export function createConversationStore(deps) {
860
968
  drafts.clear();
861
969
  for (const record of kept)
862
970
  drafts.set(record.conversation, record);
971
+ if (listHeld)
972
+ learned();
863
973
  },
864
974
  async reconcile() {
865
975
  if (!listKnown)
@@ -871,7 +981,7 @@ export function createConversationStore(deps) {
871
981
  !creations.has(conversation) &&
872
982
  (!conversation.startsWith(NEW_CHAT) || retiredChat(conversation)));
873
983
  for (const conversation of named) {
874
- if (!replicated.has(conversation))
984
+ if (!replicated.has(conversation) && missed(conversation))
875
985
  behind.add(conversation);
876
986
  }
877
987
  replicated = named;
@@ -880,6 +990,11 @@ export function createConversationStore(deps) {
880
990
  await remove(leaving);
881
991
  },
882
992
  async catchUp(progress) {
993
+ if (deps.full()) {
994
+ if (behind.size > 0)
995
+ progress.complete = false;
996
+ return;
997
+ }
883
998
  const owed = (conversation) => behind.has(conversation) && replicated.has(conversation);
884
999
  const read = async (conversations) => {
885
1000
  if (conversations.length === 0 || deps.closed())
@@ -928,12 +1043,11 @@ export function createConversationStore(deps) {
928
1043
  known() {
929
1044
  return listKnown;
930
1045
  },
931
- reconnected() {
932
- for (const conversation of replicated)
933
- gap(conversation);
934
- },
935
1046
  reopened() {
936
- sending.clear();
1047
+ relisting = null;
1048
+ for (const [operation, dispatch] of sending)
1049
+ if (!dispatch.answered)
1050
+ sending.delete(operation);
937
1051
  },
938
1052
  lost() {
939
1053
  catching.clear();
@@ -952,15 +1066,15 @@ export function createConversationStore(deps) {
952
1066
  views.set(key, view);
953
1067
  const watcher = { notify: deliver, ready: false };
954
1068
  view.watchers.add(watcher);
955
- void deps
956
- .durably(async (local) => {
1069
+ const reading = new AbortController();
1070
+ void untilAnswered(() => deps.durably(async (local) => {
957
1071
  if (view.window !== null)
958
1072
  return;
959
1073
  const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
960
1074
  view.window = messages;
961
1075
  view.more = more;
962
1076
  view.total = asked.total ? await local.messageCount(conversation) : null;
963
- })
1077
+ }), reading.signal)
964
1078
  .then(() => {
965
1079
  if (deps.closed() || !view.watchers.has(watcher))
966
1080
  return;
@@ -970,6 +1084,7 @@ export function createConversationStore(deps) {
970
1084
  })
971
1085
  .catch(() => { });
972
1086
  return () => {
1087
+ reading.abort();
973
1088
  if (!view.watchers.delete(watcher))
974
1089
  return;
975
1090
  if (view.watchers.size === 0)
@@ -977,61 +1092,76 @@ export function createConversationStore(deps) {
977
1092
  };
978
1093
  },
979
1094
  watchList(deliver) {
980
- listWatchers.add(deliver);
981
- void agentsReady().then(() => {
982
- if (!deps.closed() && listWatchers.has(deliver))
983
- deliver(entries());
984
- });
1095
+ unlisted.add(deliver);
1096
+ learned();
985
1097
  return () => {
1098
+ unlisted.delete(deliver);
986
1099
  listWatchers.delete(deliver);
987
1100
  };
988
1101
  },
989
1102
  watchAgents(deliver) {
990
- agentWatchers.add(deliver);
991
- void agentsReady().then(() => {
992
- if (!deps.closed() && agentWatchers.has(deliver))
993
- deliver(agents());
994
- });
1103
+ unnamed.add(deliver);
1104
+ learned();
1105
+ readAgents();
995
1106
  return () => {
1107
+ unnamed.delete(deliver);
996
1108
  agentWatchers.delete(deliver);
997
1109
  };
998
1110
  },
1111
+ learned,
999
1112
  changed(set) {
1000
1113
  for (const conversation of set.conversations)
1001
1114
  emit(conversation);
1002
- const declaration = deps.agents();
1003
- if (declaration !== undefined &&
1004
- set.documents.some((change) => change.locator === declaration.locator)) {
1005
- agentsRead = readAgents().catch(() => {
1006
- agentsRead = null;
1007
- });
1008
- }
1009
1115
  },
1010
1116
  receive(event) {
1011
1117
  if (deps.closed())
1012
1118
  return false;
1013
1119
  if (event.kind === 'list' || event.kind === 'listed' || event.kind === 'unlisted') {
1014
1120
  if (event.kind === 'list') {
1015
- listing.clear();
1121
+ if (event.whole)
1122
+ relisting ??= new Map();
1016
1123
  for (const entry of event.entries) {
1017
- listing.set(entry.conversation, { ...entry });
1018
- creations.delete(entry.conversation);
1124
+ if (relisting === null)
1125
+ listed(entry);
1126
+ else
1127
+ relisting.set(entry.conversation, { ...entry });
1019
1128
  }
1129
+ if (event.more)
1130
+ return false;
1131
+ if (relisting !== null) {
1132
+ listing.clear();
1133
+ for (const entry of relisting.values())
1134
+ listed(entry);
1135
+ relisting = null;
1136
+ }
1137
+ listCursor = event.cursor;
1138
+ deps.stream()?.hold(event.cursor);
1020
1139
  listKnown = true;
1140
+ for (const conversation of replicated) {
1141
+ if (!listing.has(conversation))
1142
+ continue;
1143
+ if (!missed(conversation))
1144
+ behind.delete(conversation);
1145
+ else if (!behind.has(conversation))
1146
+ gap(conversation);
1147
+ }
1021
1148
  openingEnded();
1022
1149
  }
1023
1150
  else if (event.kind === 'listed') {
1024
- listing.set(event.entry.conversation, { ...event.entry });
1025
- creations.delete(event.entry.conversation);
1151
+ listed(event.entry);
1152
+ relisting?.set(event.entry.conversation, { ...event.entry });
1026
1153
  }
1027
1154
  else {
1028
1155
  listing.delete(event.conversation);
1156
+ relisting?.delete(event.conversation);
1029
1157
  }
1158
+ keepList();
1030
1159
  emitList();
1031
- return (event.kind !== 'list' &&
1160
+ return ((event.kind !== 'list' &&
1032
1161
  listKnown &&
1033
1162
  (listing.size !== replicated.size ||
1034
- [...listing.keys()].some((conversation) => !replicated.has(conversation))));
1163
+ [...listing.keys()].some((conversation) => !replicated.has(conversation)))) ||
1164
+ (listKnown && [...drafts.keys()].some(retiredChat)));
1035
1165
  }
1036
1166
  heard(event);
1037
1167
  return false;
@@ -1047,7 +1177,9 @@ export function createConversationStore(deps) {
1047
1177
  lives.clear();
1048
1178
  unsent.clear();
1049
1179
  listWatchers.clear();
1180
+ unlisted.clear();
1050
1181
  agentWatchers.clear();
1182
+ unnamed.clear();
1051
1183
  },
1052
1184
  };
1053
1185
  }