@agentshouse/mdruntime 0.1.0-ccbe92df1c4f6 → 0.1.0-ccc0e3407f107

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 +91 -58
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/attached-model.d.ts +5 -11
  5. package/dist/attached-model.d.ts.map +1 -1
  6. package/dist/attached-model.js +36 -47
  7. package/dist/bootstrap.d.ts +11 -14
  8. package/dist/bootstrap.d.ts.map +1 -1
  9. package/dist/bootstrap.js +101 -89
  10. package/dist/chain.d.ts +2 -1
  11. package/dist/chain.d.ts.map +1 -1
  12. package/dist/client.d.ts +15 -10
  13. package/dist/client.d.ts.map +1 -1
  14. package/dist/client.js +56 -7
  15. package/dist/collection.d.ts +7 -4
  16. package/dist/collection.d.ts.map +1 -1
  17. package/dist/collection.js +24 -19
  18. package/dist/compile.d.ts +1 -6
  19. package/dist/compile.d.ts.map +1 -1
  20. package/dist/compile.js +108 -243
  21. package/dist/connection.d.ts +14 -11
  22. package/dist/connection.d.ts.map +1 -1
  23. package/dist/connection.js +1256 -1225
  24. package/dist/context.d.ts +2 -0
  25. package/dist/context.d.ts.map +1 -0
  26. package/dist/{chat/context.js → context.js} +1 -4
  27. package/dist/conversation.d.ts +16 -15
  28. package/dist/conversation.d.ts.map +1 -1
  29. package/dist/conversation.js +234 -167
  30. package/dist/durability.d.ts +6 -1
  31. package/dist/durability.d.ts.map +1 -1
  32. package/dist/entry.d.ts +3 -2
  33. package/dist/entry.d.ts.map +1 -1
  34. package/dist/entry.js +17 -8
  35. package/dist/file.d.ts +2 -11
  36. package/dist/file.d.ts.map +1 -1
  37. package/dist/file.js +6 -4
  38. package/dist/host.d.ts +3 -7
  39. package/dist/host.d.ts.map +1 -1
  40. package/dist/host.js +53 -36
  41. package/dist/identity.d.ts +0 -1
  42. package/dist/identity.d.ts.map +1 -1
  43. package/dist/identity.js +0 -3
  44. package/dist/index.d.ts +12 -9
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +4 -1
  47. package/dist/job.d.ts +14 -0
  48. package/dist/job.d.ts.map +1 -0
  49. package/dist/job.js +28 -0
  50. package/dist/live.d.ts +2 -1
  51. package/dist/live.d.ts.map +1 -1
  52. package/dist/live.js +9 -5
  53. package/dist/media.d.ts +8 -0
  54. package/dist/media.d.ts.map +1 -0
  55. package/dist/media.js +218 -0
  56. package/dist/memory.d.ts +12 -6
  57. package/dist/memory.d.ts.map +1 -1
  58. package/dist/memory.js +210 -91
  59. package/dist/messages.d.ts +2 -2
  60. package/dist/messages.d.ts.map +1 -1
  61. package/dist/messages.js +15 -16
  62. package/dist/model.d.ts +8 -8
  63. package/dist/model.d.ts.map +1 -1
  64. package/dist/model.js +7 -13
  65. package/dist/observation.d.ts +3 -2
  66. package/dist/observation.d.ts.map +1 -1
  67. package/dist/observation.js +8 -3
  68. package/dist/outcome.d.ts +13 -5
  69. package/dist/outcome.d.ts.map +1 -1
  70. package/dist/outcome.js +16 -2
  71. package/dist/paths.d.ts +1 -0
  72. package/dist/paths.d.ts.map +1 -1
  73. package/dist/paths.js +4 -0
  74. package/dist/query.d.ts +8 -207
  75. package/dist/query.d.ts.map +1 -1
  76. package/dist/query.js +3 -505
  77. package/dist/reach.d.ts +14 -7
  78. package/dist/reach.d.ts.map +1 -1
  79. package/dist/reach.js +83 -53
  80. package/dist/react.d.ts +3 -1
  81. package/dist/react.d.ts.map +1 -1
  82. package/dist/readiness.d.ts +3 -16
  83. package/dist/readiness.d.ts.map +1 -1
  84. package/dist/readiness.js +2 -8
  85. package/dist/recovery.d.ts +1 -0
  86. package/dist/recovery.d.ts.map +1 -1
  87. package/dist/recovery.js +26 -0
  88. package/dist/refresh.d.ts +7 -5
  89. package/dist/refresh.d.ts.map +1 -1
  90. package/dist/refresh.js +30 -10
  91. package/dist/replica.d.ts +10 -9
  92. package/dist/replica.d.ts.map +1 -1
  93. package/dist/replica.js +30 -15
  94. package/dist/room-draft.d.ts +22 -5
  95. package/dist/room-draft.d.ts.map +1 -1
  96. package/dist/room-draft.js +131 -51
  97. package/dist/rows.d.ts +18 -16
  98. package/dist/rows.d.ts.map +1 -1
  99. package/dist/rows.js +45 -153
  100. package/dist/save.d.ts +2 -0
  101. package/dist/save.d.ts.map +1 -1
  102. package/dist/save.js +20 -12
  103. package/dist/search.d.ts +12 -63
  104. package/dist/search.d.ts.map +1 -1
  105. package/dist/search.js +9 -52
  106. package/dist/shared.d.ts +0 -1
  107. package/dist/shared.d.ts.map +1 -1
  108. package/dist/shared.js +0 -10
  109. package/dist/status.d.ts +4 -3
  110. package/dist/status.d.ts.map +1 -1
  111. package/dist/status.js +3 -1
  112. package/dist/store.d.ts +21 -39
  113. package/dist/store.d.ts.map +1 -1
  114. package/dist/store.js +33 -73
  115. package/dist/stored.d.ts +11 -27
  116. package/dist/stored.d.ts.map +1 -1
  117. package/dist/stored.js +187 -230
  118. package/dist/tables.d.ts +34 -51
  119. package/dist/tables.d.ts.map +1 -1
  120. package/dist/tables.js +75 -68
  121. package/dist/transfer.d.ts +0 -5
  122. package/dist/transfer.d.ts.map +1 -1
  123. package/dist/validation.d.ts +3 -4
  124. package/dist/validation.d.ts.map +1 -1
  125. package/dist/validation.js +42 -100
  126. package/dist/windows.d.ts +1 -12
  127. package/dist/windows.d.ts.map +1 -1
  128. package/dist/windows.js +2 -75
  129. package/dist/wire.d.ts +17 -8
  130. package/dist/wire.d.ts.map +1 -1
  131. package/dist/wire.js +5 -2
  132. package/package.json +10 -17
  133. package/AGENTS.md +0 -317
  134. package/dist/chat/acts.d.ts +0 -33
  135. package/dist/chat/acts.d.ts.map +0 -1
  136. package/dist/chat/acts.js +0 -36
  137. package/dist/chat/context.d.ts +0 -3
  138. package/dist/chat/context.d.ts.map +0 -1
  139. package/dist/chat/earlier.d.ts +0 -10
  140. package/dist/chat/earlier.d.ts.map +0 -1
  141. package/dist/chat/earlier.js +0 -54
  142. package/dist/chat/house.d.ts +0 -25
  143. package/dist/chat/house.d.ts.map +0 -1
  144. package/dist/chat/house.js +0 -38
  145. package/dist/chat/input.d.ts +0 -11
  146. package/dist/chat/input.d.ts.map +0 -1
  147. package/dist/chat/input.js +0 -92
  148. package/dist/chat/kit.d.ts +0 -61
  149. package/dist/chat/kit.d.ts.map +0 -1
  150. package/dist/chat/kit.js +0 -123
  151. package/dist/chat/lasting.d.ts +0 -6
  152. package/dist/chat/lasting.d.ts.map +0 -1
  153. package/dist/chat/lasting.js +0 -19
  154. package/dist/chat/list.d.ts +0 -28
  155. package/dist/chat/list.d.ts.map +0 -1
  156. package/dist/chat/list.js +0 -103
  157. package/dist/chat/markdown.d.ts +0 -20
  158. package/dist/chat/markdown.d.ts.map +0 -1
  159. package/dist/chat/markdown.js +0 -229
  160. package/dist/chat/message.d.ts +0 -7
  161. package/dist/chat/message.d.ts.map +0 -1
  162. package/dist/chat/message.js +0 -254
  163. package/dist/chat/messages.d.ts +0 -35
  164. package/dist/chat/messages.d.ts.map +0 -1
  165. package/dist/chat/messages.js +0 -210
  166. package/dist/chat/name.d.ts +0 -7
  167. package/dist/chat/name.d.ts.map +0 -1
  168. package/dist/chat/name.js +0 -37
  169. package/dist/chat/opened.d.ts +0 -12
  170. package/dist/chat/opened.d.ts.map +0 -1
  171. package/dist/chat/opened.js +0 -19
  172. package/dist/chat/overlay.d.ts +0 -32
  173. package/dist/chat/overlay.d.ts.map +0 -1
  174. package/dist/chat/overlay.js +0 -103
  175. package/dist/chat/parts.d.ts +0 -58
  176. package/dist/chat/parts.d.ts.map +0 -1
  177. package/dist/chat/parts.js +0 -120
  178. package/dist/chat/pieces.d.ts +0 -62
  179. package/dist/chat/pieces.d.ts.map +0 -1
  180. package/dist/chat/pieces.js +0 -1110
  181. package/dist/chat/process.d.ts +0 -20
  182. package/dist/chat/process.d.ts.map +0 -1
  183. package/dist/chat/process.js +0 -32
  184. package/dist/chat/provider.d.ts +0 -70
  185. package/dist/chat/provider.d.ts.map +0 -1
  186. package/dist/chat/provider.js +0 -635
  187. package/dist/chat/question.d.ts +0 -9
  188. package/dist/chat/question.d.ts.map +0 -1
  189. package/dist/chat/question.js +0 -69
  190. package/dist/chat/questions.d.ts +0 -31
  191. package/dist/chat/questions.d.ts.map +0 -1
  192. package/dist/chat/questions.js +0 -111
  193. package/dist/chat/read.d.ts +0 -5
  194. package/dist/chat/read.d.ts.map +0 -1
  195. package/dist/chat/read.js +0 -13
  196. package/dist/chat/ready.d.ts +0 -37
  197. package/dist/chat/ready.d.ts.map +0 -1
  198. package/dist/chat/ready.js +0 -93
  199. package/dist/chat/room-file.d.ts +0 -8
  200. package/dist/chat/room-file.d.ts.map +0 -1
  201. package/dist/chat/room-file.js +0 -72
  202. package/dist/chat/steady.d.ts +0 -3
  203. package/dist/chat/steady.d.ts.map +0 -1
  204. package/dist/chat/steady.js +0 -26
  205. package/dist/chat/style.d.ts +0 -4
  206. package/dist/chat/style.d.ts.map +0 -1
  207. package/dist/chat/style.js +0 -307
  208. package/dist/chat.d.ts +0 -15
  209. package/dist/chat.d.ts.map +0 -1
  210. package/dist/chat.js +0 -8
  211. package/dist/fulltext.d.ts +0 -27
  212. package/dist/fulltext.d.ts.map +0 -1
  213. package/dist/fulltext.js +0 -368
  214. package/dist/reads.d.ts +0 -11
  215. package/dist/reads.d.ts.map +0 -1
  216. package/dist/reads.js +0 -100
  217. package/dist/words.d.ts +0 -19
  218. package/dist/words.d.ts.map +0 -1
  219. package/dist/words.js +0 -150
@@ -1,10 +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
4
  import { refusedForSpace } from './durability.js';
4
- import { declaredFile } from './file.js';
5
5
  import { changeBatchIdentity, chatDraftRevision } from './identity.js';
6
6
  import { OFFLINE } from './outcome.js';
7
- 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';
8
9
  const QUIET = {
9
10
  turn: null,
10
11
  questions: [],
@@ -12,6 +13,7 @@ const QUIET = {
12
13
  commands: [],
13
14
  options: [],
14
15
  starting: null,
16
+ subagents: [],
15
17
  link: null,
16
18
  deliveryUnknown: [],
17
19
  };
@@ -21,6 +23,7 @@ const FACTS = [
21
23
  'commands',
22
24
  'options',
23
25
  'starting',
26
+ 'subagents',
24
27
  'link',
25
28
  'deliveryUnknown',
26
29
  ];
@@ -31,9 +34,11 @@ export function unheldView(conversation) {
31
34
  turn: null,
32
35
  questions: [],
33
36
  process: null,
37
+ processEnded: null,
34
38
  commands: [],
35
39
  options: [],
36
40
  starting: null,
41
+ subagents: [],
37
42
  link: null,
38
43
  deliveryUnknown: [],
39
44
  chatDraft: null,
@@ -48,10 +53,8 @@ export function newChat(agent) {
48
53
  function creationOf(input) {
49
54
  if (typeof input !== 'object' || input === null)
50
55
  return null;
51
- const { agent_id: agent, operation_id: operation, replaces, } = input;
52
- return typeof agent === 'string' && typeof operation === 'string' && replaces === undefined
53
- ? { agent, operation }
54
- : null;
56
+ const { agent_id: agent, operation_id: operation } = input;
57
+ return typeof agent === 'string' && typeof operation === 'string' ? { agent, operation } : null;
55
58
  }
56
59
  function startedTurn(turn, operation) {
57
60
  if (operation.op === 'begin')
@@ -210,7 +213,14 @@ function askedOf(options) {
210
213
  }
211
214
  return { limit: capped(limit), after, before: beforeOf(after), total: total === true };
212
215
  }
213
- const EXPIRED = { kind: 'rejected', code: 'expired', fields: {}, retryable: false };
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
+ }
214
224
  const DURABLE_WRITE = {
215
225
  kind: 'rejected',
216
226
  code: 'durable-write',
@@ -256,13 +266,19 @@ export function createConversationStore(deps) {
256
266
  const unsent = new Map();
257
267
  const views = new Map();
258
268
  const listing = new Map();
269
+ let relisting = null;
270
+ let listCursor = null;
259
271
  const creations = new Set();
260
272
  const listWatchers = new Set();
273
+ const unlisted = new Set();
261
274
  let listKnown = false;
275
+ let listHeld = false;
276
+ let listKept = false;
262
277
  const agentWatchers = new Set();
263
- let agentNames = new Map();
264
- let retiredAgents = new Set();
265
- let agentsRead = null;
278
+ const unnamed = new Set();
279
+ let agentsShown = null;
280
+ let listedAgents = null;
281
+ let agentsReading = false;
266
282
  let replicated = new Set();
267
283
  let handedReplicated;
268
284
  function liveOf(conversation) {
@@ -283,9 +299,11 @@ export function createConversationStore(deps) {
283
299
  turn: structuredClone(facts.turn),
284
300
  questions: structuredClone(facts.questions),
285
301
  process: facts.process === null ? null : { ...facts.process },
302
+ processEnded: listing.get(conversation)?.processEnded ?? null,
286
303
  commands: structuredClone(facts.commands),
287
304
  options: structuredClone(facts.options),
288
305
  starting: facts.starting,
306
+ subagents: structuredClone(facts.subagents),
289
307
  link: facts.link === null ? null : { ...facts.link },
290
308
  deliveryUnknown: [...facts.deliveryUnknown],
291
309
  chatDraft: draft === undefined || unwritten(draft)
@@ -341,7 +359,7 @@ export function createConversationStore(deps) {
341
359
  function entries() {
342
360
  return [...listing.values()].map((entry) => ({
343
361
  conversation: entry.conversation,
344
- agent: { identity: entry.agent, name: agentNames.get(entry.agent) ?? null },
362
+ agent: { identity: entry.agent, name: entry.agentName },
345
363
  name: entry.name,
346
364
  created: entry.created,
347
365
  finished: entry.finished,
@@ -351,25 +369,103 @@ export function createConversationStore(deps) {
351
369
  started: lives.get(entry.conversation)?.turn?.started ?? null,
352
370
  }));
353
371
  }
372
+ function keepList() {
373
+ if (!listKnown || listKept)
374
+ return;
375
+ listKept = true;
376
+ queueMicrotask(() => {
377
+ listKept = false;
378
+ if (deps.closed())
379
+ return;
380
+ const entries = [...listing.values()];
381
+ const cursor = listCursor;
382
+ void deps
383
+ .durably(async (local) => {
384
+ await local.fact('conversationList', entries);
385
+ await local.fact('conversationCursor', cursor);
386
+ })
387
+ .catch(() => { });
388
+ });
389
+ }
390
+ function listed(entry) {
391
+ const ended = listing.get(entry.conversation)?.processEnded ?? null;
392
+ listing.set(entry.conversation, { ...entry });
393
+ creations.delete(entry.conversation);
394
+ if (entry.processEnded !== ended)
395
+ emit(entry.conversation);
396
+ }
354
397
  function emitList() {
355
- if (deps.closed() || listWatchers.size === 0)
398
+ if (deps.closed())
356
399
  return;
357
- const value = entries();
358
- for (const watcher of listWatchers)
359
- watcher(value);
400
+ if (listWatchers.size > 0) {
401
+ const value = entries();
402
+ for (const watcher of listWatchers)
403
+ watcher(value);
404
+ }
405
+ emitAgents();
406
+ learned();
407
+ }
408
+ function learned() {
409
+ if (deps.closed())
410
+ return;
411
+ if (!listKnown && !listHeld && deps.stream() !== undefined && deps.online())
412
+ return;
413
+ if (unlisted.size > 0) {
414
+ const value = entries();
415
+ for (const watcher of [...unlisted]) {
416
+ unlisted.delete(watcher);
417
+ listWatchers.add(watcher);
418
+ watcher(value);
419
+ }
420
+ }
421
+ if (unnamed.size > 0) {
422
+ const value = agents();
423
+ for (const watcher of [...unnamed]) {
424
+ unnamed.delete(watcher);
425
+ agentWatchers.add(watcher);
426
+ watcher(value);
427
+ }
428
+ }
360
429
  }
361
430
  function agents() {
362
- return [...agentNames]
363
- .filter(([identity]) => !retiredAgents.has(identity))
364
- .map(([identity, name]) => ({ identity, name }))
431
+ const named = new Map();
432
+ for (const agent of listedAgents ?? [])
433
+ named.set(agent.agent, agent);
434
+ for (const entry of listing.values()) {
435
+ named.set(entry.agent, { name: entry.agentName, retired: entry.agentRetired });
436
+ }
437
+ return [...named]
438
+ .filter(([, agent]) => !agent.retired)
439
+ .map(([identity, agent]) => ({ identity, name: agent.name }))
365
440
  .sort((left, right) => left.name === right.name
366
441
  ? left.identity.localeCompare(right.identity)
367
442
  : left.name.localeCompare(right.name));
368
443
  }
444
+ function readAgents() {
445
+ const stream = deps.stream();
446
+ if (stream?.agents === undefined || !deps.online() || agentsReading)
447
+ return;
448
+ agentsReading = true;
449
+ void stream
450
+ .agents()
451
+ .then((read) => {
452
+ if (read === null)
453
+ return;
454
+ listedAgents = read;
455
+ emitAgents();
456
+ }, () => { })
457
+ .finally(() => {
458
+ agentsReading = false;
459
+ });
460
+ }
369
461
  function emitAgents() {
370
462
  if (deps.closed() || agentWatchers.size === 0)
371
463
  return;
372
464
  const value = agents();
465
+ const shown = JSON.stringify(value);
466
+ if (shown === agentsShown)
467
+ return;
468
+ agentsShown = shown;
373
469
  for (const watcher of agentWatchers)
374
470
  watcher(value);
375
471
  }
@@ -385,55 +481,11 @@ export function createConversationStore(deps) {
385
481
  if (stateOf(conversation) !== before || next?.turn?.started !== began)
386
482
  emitList();
387
483
  }
388
- async function readAgents() {
389
- const declaration = deps.agents();
390
- if (declaration === undefined)
391
- return;
392
- const names = new Map();
393
- const retired = new Set();
394
- let covered = null;
395
- for (let after;;) {
396
- const read = await deps.documents(declaration, after);
397
- if ('pending' in read)
398
- return;
399
- const coverage = JSON.stringify(read.coverage);
400
- if (covered !== null && coverage !== covered)
401
- return readAgents();
402
- covered = coverage;
403
- for (const document of read.documents) {
404
- const identity = document.fields?.[declaration.identity];
405
- const name = document.fields?.[declaration.name];
406
- if (typeof identity !== 'string' || typeof name !== 'string')
407
- continue;
408
- names.set(identity, name);
409
- const ended = declaration.retired === undefined ? null : document.fields?.[declaration.retired];
410
- if (ended !== undefined && ended !== null)
411
- retired.add(identity);
412
- }
413
- if (read.next === undefined)
414
- break;
415
- after = read.next;
416
- }
417
- const named = JSON.stringify([...names]) !== JSON.stringify([...agentNames]);
418
- if (!named && JSON.stringify([...retired]) === JSON.stringify([...retiredAgents]))
419
- return;
420
- agentNames = names;
421
- retiredAgents = retired;
422
- if (named)
423
- emitList();
424
- emitAgents();
425
- const ended = [...drafts.keys()].filter(retiredChat);
426
- if (ended.length > 0)
427
- await remove(ended);
428
- }
429
484
  function retiredChat(conversation) {
430
- return (conversation.startsWith(NEW_CHAT) && retiredAgents.has(conversation.slice(NEW_CHAT.length)));
431
- }
432
- function agentsReady() {
433
- agentsRead ??= readAgents().catch(() => {
434
- agentsRead = null;
435
- });
436
- return agentsRead;
485
+ if (!conversation.startsWith(NEW_CHAT))
486
+ return false;
487
+ const agent = conversation.slice(NEW_CHAT.length);
488
+ return [...listing.values()].some((entry) => entry.agent === agent && entry.agentRetired);
437
489
  }
438
490
  function live(conversation, change) {
439
491
  const owed = unsent.get(conversation);
@@ -456,6 +508,7 @@ export function createConversationStore(deps) {
456
508
  commands: facts.has('commands') ? QUIET.commands : held.commands,
457
509
  options: facts.has('options') ? QUIET.options : held.options,
458
510
  starting: facts.has('starting') ? QUIET.starting : held.starting,
511
+ subagents: facts.has('subagents') ? QUIET.subagents : held.subagents,
459
512
  link: facts.has('link') ? QUIET.link : held.link,
460
513
  deliveryUnknown: facts.has('deliveryUnknown')
461
514
  ? QUIET.deliveryUnknown
@@ -509,6 +562,20 @@ export function createConversationStore(deps) {
509
562
  deps.publish(conversationChangeSet(changed));
510
563
  });
511
564
  }
565
+ function missed(conversation) {
566
+ const read = reads.get(conversation);
567
+ const newest = listing.get(conversation)?.newest;
568
+ return (read === undefined ||
569
+ newest === undefined ||
570
+ partials.has(conversation) ||
571
+ (newest !== null && (read === null || newest > read)));
572
+ }
573
+ function noted(conversation, message) {
574
+ const entry = listing.get(conversation);
575
+ if (entry === undefined || (entry.newest !== null && entry.newest >= message.position))
576
+ return;
577
+ listing.set(conversation, { ...entry, newest: message.position });
578
+ }
512
579
  function gap(conversation) {
513
580
  gaps.set(conversation, (gaps.get(conversation) ?? 0) + 1);
514
581
  behind.add(conversation);
@@ -543,7 +610,7 @@ export function createConversationStore(deps) {
543
610
  }));
544
611
  while (waiting.length > 0) {
545
612
  const asking = waiting.slice(0, HISTORY_CONVERSATIONS);
546
- const result = await deps.call('conversation.history', {
613
+ const result = await deps.history({
547
614
  conversations: asking.map(({ conversation, after }) => ({
548
615
  conversation,
549
616
  ...(after === undefined ? {} : { after }),
@@ -646,6 +713,10 @@ export function createConversationStore(deps) {
646
713
  live(conversation, { starting: event.step });
647
714
  return;
648
715
  }
716
+ if (event.kind === 'subagents') {
717
+ live(conversation, { subagents: structuredClone(event.subagents) });
718
+ return;
719
+ }
649
720
  if (event.kind === 'link') {
650
721
  live(conversation, { link: { connected: event.connected } });
651
722
  return;
@@ -657,6 +728,7 @@ export function createConversationStore(deps) {
657
728
  const arriving = acceptedMessage(event.message);
658
729
  if (arriving === null)
659
730
  return;
731
+ noted(conversation, arriving);
660
732
  if (replicated.has(conversation)) {
661
733
  if (deps.full()) {
662
734
  gap(conversation);
@@ -694,7 +766,7 @@ export function createConversationStore(deps) {
694
766
  const from = newChat(agent);
695
767
  return deps.durably(async (local) => {
696
768
  const held = drafts.get(from);
697
- const earlier = (held?.moves ?? []).filter((one) => !deps.expired(one));
769
+ const earlier = held?.moves ?? [];
698
770
  if (earlier.includes(operation))
699
771
  return;
700
772
  const blank = {
@@ -723,10 +795,8 @@ export function createConversationStore(deps) {
723
795
  }
724
796
  async function submitted(conversation, operation, draft) {
725
797
  let submission;
726
- let earlier = false;
727
798
  await withDraft(conversation, (current) => {
728
799
  submission = current?.submitted?.find((one) => one.operation === operation);
729
- earlier = submission !== undefined;
730
800
  if (submission !== undefined)
731
801
  return undefined;
732
802
  const said = draft ?? current;
@@ -739,31 +809,24 @@ export function createConversationStore(deps) {
739
809
  submitted: [...(current?.submitted ?? []), submission],
740
810
  };
741
811
  });
742
- return { submission: submission, earlier };
743
- }
744
- function forgotten(conversation, submission) {
745
- return withDraft(conversation, (current) => {
746
- const held = current?.submitted ?? [];
747
- if (current === undefined || !held.includes(submission))
748
- return undefined;
749
- return withSubmitted(current, held.filter((one) => one !== submission));
750
- });
812
+ return submission;
751
813
  }
752
814
  async function dispatched(conversation, submission) {
753
- const dispatch = {};
815
+ const dispatch = { answered: false };
754
816
  sending.set(submission.operation, dispatch);
755
817
  try {
756
- const result = await invoke('conversation.send', conversation, {
757
- text: submission.text,
818
+ const result = await invoke('conversations/send', conversation, {
758
819
  operation_id: submission.operation,
820
+ text: submission.text,
759
821
  });
822
+ dispatch.answered = result.kind !== 'transport-uncertainty';
760
823
  if (result.kind === 'revoked-authorization')
761
824
  return result;
762
825
  if (result.kind !== 'action' && result.retryable) {
763
826
  deps.unanswered();
764
827
  return result;
765
828
  }
766
- const turn = answered(result, 'turn');
829
+ const turn = answered(result, 'message_id');
767
830
  await withDraft(conversation, async (current, local) => {
768
831
  const held = current?.submitted?.find((one) => one.operation === submission.operation);
769
832
  if (current === undefined || held === undefined || held.turn !== null)
@@ -783,25 +846,34 @@ export function createConversationStore(deps) {
783
846
  sending.delete(submission.operation);
784
847
  }
785
848
  }
786
- function invoke(name, conversation, extra = {}) {
787
- return deps.call(name, { conversation, ...extra });
849
+ function invoke(name, conversation, extra = { operation_id: changeBatchIdentity() }) {
850
+ return deps.call(name, { conversation_id: conversation, ...extra });
788
851
  }
789
852
  const surface = {
790
- async list() {
791
- await agentsReady();
792
- return entries();
853
+ list() {
854
+ return new Promise((settle) => {
855
+ const answer = (listed) => {
856
+ unlisted.delete(answer);
857
+ listWatchers.delete(answer);
858
+ settle(listed);
859
+ };
860
+ unlisted.add(answer);
861
+ learned();
862
+ });
793
863
  },
794
864
  async read(conversation, options = {}) {
795
- const asked = askedOf(options);
865
+ const { text, ...windowed } = options;
866
+ const asked = askedOf(windowed);
867
+ const phrase = phraseOf(text);
796
868
  return deps.durably(async (local) => {
797
- const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
798
- const total = asked.total ? await local.messageCount(conversation) : null;
869
+ const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before, phrase);
870
+ const total = asked.total ? await local.messageCount(conversation, phrase) : null;
799
871
  return structuredClone(viewOf(conversation, messages, frameOf(asked, messages, more, total)));
800
872
  });
801
873
  },
802
874
  async create(input) {
803
- const result = await deps.call('conversation.create', input);
804
- const conversation = answered(result, 'conversation');
875
+ const result = await deps.call('conversations/create', input);
876
+ const conversation = answered(result, 'conversation_id');
805
877
  if (conversation === null)
806
878
  return result;
807
879
  if (!listing.has(conversation))
@@ -822,11 +894,7 @@ export function createConversationStore(deps) {
822
894
  });
823
895
  if (held === null)
824
896
  return DURABLE_WRITE;
825
- const { submission, earlier } = held;
826
- if (!earlier || !deps.expired(operation))
827
- return dispatched(conversation, submission);
828
- await forgotten(conversation, submission);
829
- return EXPIRED;
897
+ return dispatched(conversation, held);
830
898
  }
831
899
  if (draft !== undefined) {
832
900
  await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
@@ -835,38 +903,20 @@ export function createConversationStore(deps) {
835
903
  }
836
904
  return OFFLINE;
837
905
  },
838
- async attach(room, file) {
839
- if (!deps.online())
840
- return OFFLINE;
841
- return deps.call('conversation.attach', {
842
- room,
843
- ...(await declaredFile(file)),
844
- blob: file.blob,
845
- });
846
- },
847
906
  answer(conversation, answer) {
848
- return invoke('conversation.answer', conversation, { answer });
907
+ return invoke('conversations/interaction/answer', conversation, {
908
+ operation_id: changeBatchIdentity(),
909
+ ...answer,
910
+ });
849
911
  },
850
912
  interrupt(conversation) {
851
- return invoke('conversation.interrupt', conversation);
913
+ return invoke('conversations/interrupt', conversation);
852
914
  },
853
915
  kill(conversation) {
854
- return invoke('conversation.kill', conversation);
855
- },
856
- async cancel(conversation, turn) {
857
- const result = await invoke('conversation.cancel', conversation, { turn });
858
- if (result.kind !== 'action')
859
- return result;
860
- await withDraft(conversation, (current) => {
861
- const held = current?.submitted?.find((one) => one.turn === turn);
862
- if (current === undefined || held === undefined)
863
- return undefined;
864
- return returned(current, held, current.submitted.filter((one) => one !== held));
865
- });
866
- return result;
916
+ return invoke('conversations/kill', conversation);
867
917
  },
868
918
  delete(conversation) {
869
- return invoke('conversation.delete', conversation);
919
+ return invoke('conversations/delete', conversation);
870
920
  },
871
921
  };
872
922
  const chatDraft = {
@@ -895,7 +945,15 @@ export function createConversationStore(deps) {
895
945
  return {
896
946
  surface,
897
947
  chatDraft,
898
- hydrate(held, kept) {
948
+ hydrate(held, kept, list, cursor) {
949
+ if (list !== null && !listKnown) {
950
+ listing.clear();
951
+ for (const entry of list)
952
+ listing.set(entry.conversation, { ...entry });
953
+ listHeld = true;
954
+ listCursor = cursor;
955
+ deps.stream()?.hold(cursor);
956
+ }
899
957
  stored.clear();
900
958
  reads.clear();
901
959
  partials.clear();
@@ -909,6 +967,8 @@ export function createConversationStore(deps) {
909
967
  drafts.clear();
910
968
  for (const record of kept)
911
969
  drafts.set(record.conversation, record);
970
+ if (listHeld)
971
+ learned();
912
972
  },
913
973
  async reconcile() {
914
974
  if (!listKnown)
@@ -920,7 +980,7 @@ export function createConversationStore(deps) {
920
980
  !creations.has(conversation) &&
921
981
  (!conversation.startsWith(NEW_CHAT) || retiredChat(conversation)));
922
982
  for (const conversation of named) {
923
- if (!replicated.has(conversation))
983
+ if (!replicated.has(conversation) && missed(conversation))
924
984
  behind.add(conversation);
925
985
  }
926
986
  replicated = named;
@@ -958,10 +1018,6 @@ export function createConversationStore(deps) {
958
1018
  continue;
959
1019
  if (deps.closed())
960
1020
  return;
961
- if (deps.expired(submission.operation)) {
962
- await forgotten(conversation, submission);
963
- continue;
964
- }
965
1021
  const result = await dispatched(conversation, submission);
966
1022
  if (result.kind === 'revoked-authorization')
967
1023
  return;
@@ -982,12 +1038,11 @@ export function createConversationStore(deps) {
982
1038
  known() {
983
1039
  return listKnown;
984
1040
  },
985
- reconnected() {
986
- for (const conversation of replicated)
987
- gap(conversation);
988
- },
989
1041
  reopened() {
990
- sending.clear();
1042
+ relisting = null;
1043
+ for (const [operation, dispatch] of sending)
1044
+ if (!dispatch.answered)
1045
+ sending.delete(operation);
991
1046
  },
992
1047
  lost() {
993
1048
  catching.clear();
@@ -1006,15 +1061,15 @@ export function createConversationStore(deps) {
1006
1061
  views.set(key, view);
1007
1062
  const watcher = { notify: deliver, ready: false };
1008
1063
  view.watchers.add(watcher);
1009
- void deps
1010
- .durably(async (local) => {
1064
+ const reading = new AbortController();
1065
+ void untilAnswered(() => deps.durably(async (local) => {
1011
1066
  if (view.window !== null)
1012
1067
  return;
1013
1068
  const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
1014
1069
  view.window = messages;
1015
1070
  view.more = more;
1016
1071
  view.total = asked.total ? await local.messageCount(conversation) : null;
1017
- })
1072
+ }), reading.signal)
1018
1073
  .then(() => {
1019
1074
  if (deps.closed() || !view.watchers.has(watcher))
1020
1075
  return;
@@ -1024,6 +1079,7 @@ export function createConversationStore(deps) {
1024
1079
  })
1025
1080
  .catch(() => { });
1026
1081
  return () => {
1082
+ reading.abort();
1027
1083
  if (!view.watchers.delete(watcher))
1028
1084
  return;
1029
1085
  if (view.watchers.size === 0)
@@ -1031,77 +1087,88 @@ export function createConversationStore(deps) {
1031
1087
  };
1032
1088
  },
1033
1089
  watchList(deliver) {
1034
- listWatchers.add(deliver);
1035
- void agentsReady().then(() => {
1036
- if (!deps.closed() && listWatchers.has(deliver))
1037
- deliver(entries());
1038
- });
1090
+ unlisted.add(deliver);
1091
+ learned();
1039
1092
  return () => {
1093
+ unlisted.delete(deliver);
1040
1094
  listWatchers.delete(deliver);
1041
1095
  };
1042
1096
  },
1043
1097
  watchAgents(deliver) {
1044
- agentWatchers.add(deliver);
1045
- void agentsReady().then(() => {
1046
- if (!deps.closed() && agentWatchers.has(deliver))
1047
- deliver(agents());
1048
- });
1098
+ unnamed.add(deliver);
1099
+ learned();
1100
+ readAgents();
1049
1101
  return () => {
1102
+ unnamed.delete(deliver);
1050
1103
  agentWatchers.delete(deliver);
1051
1104
  };
1052
1105
  },
1106
+ learned,
1053
1107
  changed(set) {
1054
1108
  for (const conversation of set.conversations)
1055
1109
  emit(conversation);
1056
- const declaration = deps.agents();
1057
- if (declaration !== undefined &&
1058
- set.documents.some((change) => change.locator === declaration.locator)) {
1059
- agentsRead = readAgents().catch(() => {
1060
- agentsRead = null;
1061
- });
1062
- }
1063
1110
  },
1064
1111
  receive(event) {
1065
1112
  if (deps.closed())
1066
1113
  return false;
1067
1114
  if (event.kind === 'list' || event.kind === 'listed' || event.kind === 'unlisted') {
1068
1115
  if (event.kind === 'list') {
1069
- listing.clear();
1116
+ if (event.whole)
1117
+ relisting ??= new Map();
1070
1118
  for (const entry of event.entries) {
1071
- listing.set(entry.conversation, { ...entry });
1072
- creations.delete(entry.conversation);
1119
+ if (relisting === null)
1120
+ listed(entry);
1121
+ else
1122
+ relisting.set(entry.conversation, { ...entry });
1123
+ }
1124
+ if (event.more)
1125
+ return false;
1126
+ if (relisting !== null) {
1127
+ listing.clear();
1128
+ for (const entry of relisting.values())
1129
+ listed(entry);
1130
+ relisting = null;
1073
1131
  }
1132
+ listCursor = event.cursor;
1133
+ deps.stream()?.hold(event.cursor);
1074
1134
  listKnown = true;
1135
+ for (const conversation of replicated) {
1136
+ if (!listing.has(conversation))
1137
+ continue;
1138
+ if (!missed(conversation))
1139
+ behind.delete(conversation);
1140
+ else if (!behind.has(conversation))
1141
+ gap(conversation);
1142
+ }
1075
1143
  openingEnded();
1076
1144
  }
1077
1145
  else if (event.kind === 'listed') {
1078
- listing.set(event.entry.conversation, { ...event.entry });
1079
- creations.delete(event.entry.conversation);
1146
+ listed(event.entry);
1147
+ relisting?.set(event.entry.conversation, { ...event.entry });
1080
1148
  }
1081
1149
  else {
1082
1150
  listing.delete(event.conversation);
1151
+ relisting?.delete(event.conversation);
1083
1152
  }
1153
+ keepList();
1084
1154
  emitList();
1085
- return (event.kind !== 'list' &&
1155
+ return ((event.kind !== 'list' &&
1086
1156
  listKnown &&
1087
1157
  (listing.size !== replicated.size ||
1088
- [...listing.keys()].some((conversation) => !replicated.has(conversation))));
1158
+ [...listing.keys()].some((conversation) => !replicated.has(conversation)))) ||
1159
+ (listKnown && [...drafts.keys()].some(retiredChat)));
1089
1160
  }
1090
1161
  heard(event);
1091
1162
  return false;
1092
1163
  },
1093
- searchable() {
1094
- return [...(listKnown ? listing.keys() : stored)].sort();
1095
- },
1096
- acquired(conversation) {
1097
- return reads.has(conversation) && !partials.has(conversation);
1098
- },
1099
1164
  close() {
1100
1165
  views.clear();
1101
1166
  lives.clear();
1102
1167
  unsent.clear();
1103
1168
  listWatchers.clear();
1169
+ unlisted.clear();
1104
1170
  agentWatchers.clear();
1171
+ unnamed.clear();
1105
1172
  },
1106
1173
  };
1107
1174
  }