@agentshouse/mdruntime 0.1.0-cf04ede9fb796 → 0.1.0-cf0c43fc48aad

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 (220) hide show
  1. package/README.md +12 -12
  2. package/dist/acceptance.d.ts +0 -3
  3. package/dist/acceptance.d.ts.map +1 -1
  4. package/dist/acceptance.js +74 -164
  5. package/dist/act-lanes.d.ts +30 -0
  6. package/dist/act-lanes.d.ts.map +1 -0
  7. package/dist/act-lanes.js +225 -0
  8. package/dist/actions.d.ts +8 -2
  9. package/dist/actions.d.ts.map +1 -1
  10. package/dist/actions.js +118 -67
  11. package/dist/adapter.d.ts +27 -48
  12. package/dist/adapter.d.ts.map +1 -1
  13. package/dist/bootstrap.d.ts +1 -1
  14. package/dist/bootstrap.d.ts.map +1 -1
  15. package/dist/bootstrap.js +6 -19
  16. package/dist/change-set.d.ts +4 -0
  17. package/dist/change-set.d.ts.map +1 -1
  18. package/dist/change-set.js +6 -0
  19. package/dist/change.d.ts.map +1 -1
  20. package/dist/change.js +4 -2
  21. package/dist/client.d.ts +9 -18
  22. package/dist/client.d.ts.map +1 -1
  23. package/dist/client.js +32 -15
  24. package/dist/collection.d.ts +22 -4
  25. package/dist/collection.d.ts.map +1 -1
  26. package/dist/collection.js +12 -2
  27. package/dist/compile.d.ts +2 -0
  28. package/dist/compile.d.ts.map +1 -1
  29. package/dist/compile.js +31 -24
  30. package/dist/connection.d.ts.map +1 -1
  31. package/dist/connection.js +26 -21
  32. package/dist/conversation-live.d.ts +10 -6
  33. package/dist/conversation-live.d.ts.map +1 -1
  34. package/dist/conversation-live.js +8 -6
  35. package/dist/conversation.d.ts +28 -10
  36. package/dist/conversation.d.ts.map +1 -1
  37. package/dist/conversation.js +194 -141
  38. package/dist/declaration.d.ts +10 -0
  39. package/dist/declaration.d.ts.map +1 -0
  40. package/dist/declaration.js +24 -0
  41. package/dist/discovery.d.ts.map +1 -1
  42. package/dist/discovery.js +19 -44
  43. package/dist/durability.d.ts +3 -0
  44. package/dist/durability.d.ts.map +1 -1
  45. package/dist/entry.js +1 -1
  46. package/dist/expectation.d.ts +26 -13
  47. package/dist/expectation.d.ts.map +1 -1
  48. package/dist/expectation.js +72 -19
  49. package/dist/failure.d.ts +3 -0
  50. package/dist/failure.d.ts.map +1 -1
  51. package/dist/failure.js +6 -0
  52. package/dist/host.d.ts +17 -2
  53. package/dist/host.d.ts.map +1 -1
  54. package/dist/host.js +45 -11
  55. package/dist/index.d.ts +12 -8
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +10 -6
  58. package/dist/install.d.ts +2 -4
  59. package/dist/install.d.ts.map +1 -1
  60. package/dist/install.js +52 -78
  61. package/dist/lifecycle.d.ts +1 -1
  62. package/dist/lifecycle.d.ts.map +1 -1
  63. package/dist/lifecycle.js +40 -31
  64. package/dist/listing.d.ts +6 -11
  65. package/dist/listing.d.ts.map +1 -1
  66. package/dist/listing.js +25 -62
  67. package/dist/live.d.ts.map +1 -1
  68. package/dist/live.js +3 -3
  69. package/dist/locks.d.ts +2 -4
  70. package/dist/locks.d.ts.map +1 -1
  71. package/dist/locks.js +10 -39
  72. package/dist/lost.d.ts.map +1 -1
  73. package/dist/lost.js +10 -22
  74. package/dist/media.d.ts +1 -1
  75. package/dist/media.d.ts.map +1 -1
  76. package/dist/media.js +4 -4
  77. package/dist/memory.d.ts +4 -2
  78. package/dist/memory.d.ts.map +1 -1
  79. package/dist/memory.js +44 -23
  80. package/dist/messages.d.ts +9 -5
  81. package/dist/messages.d.ts.map +1 -1
  82. package/dist/messages.js +25 -35
  83. package/dist/model.d.ts +0 -1
  84. package/dist/model.d.ts.map +1 -1
  85. package/dist/model.js +0 -5
  86. package/dist/models.d.ts +4 -8
  87. package/dist/models.d.ts.map +1 -1
  88. package/dist/models.js +95 -137
  89. package/dist/observation.d.ts.map +1 -1
  90. package/dist/observation.js +12 -17
  91. package/dist/opened.d.ts +1 -1
  92. package/dist/opened.d.ts.map +1 -1
  93. package/dist/opened.js +5 -5
  94. package/dist/opening.d.ts.map +1 -1
  95. package/dist/opening.js +5 -9
  96. package/dist/outcome.d.ts +3 -0
  97. package/dist/outcome.d.ts.map +1 -1
  98. package/dist/outcome.js +15 -0
  99. package/dist/overlay.d.ts +5 -1
  100. package/dist/overlay.d.ts.map +1 -1
  101. package/dist/overlay.js +36 -21
  102. package/dist/page-metadata.d.ts +8 -0
  103. package/dist/page-metadata.d.ts.map +1 -0
  104. package/dist/page-metadata.js +19 -0
  105. package/dist/parts.d.ts +3 -59
  106. package/dist/parts.d.ts.map +1 -1
  107. package/dist/parts.js +10 -123
  108. package/dist/preparation.d.ts.map +1 -1
  109. package/dist/preparation.js +25 -24
  110. package/dist/presence.d.ts +52 -0
  111. package/dist/presence.d.ts.map +1 -0
  112. package/dist/presence.js +220 -0
  113. package/dist/queries.d.ts +1 -1
  114. package/dist/queries.d.ts.map +1 -1
  115. package/dist/queries.js +24 -14
  116. package/dist/query.d.ts +0 -1
  117. package/dist/query.d.ts.map +1 -1
  118. package/dist/questions.d.ts +0 -5
  119. package/dist/questions.d.ts.map +1 -1
  120. package/dist/questions.js +0 -7
  121. package/dist/queue.d.ts +40 -0
  122. package/dist/queue.d.ts.map +1 -0
  123. package/dist/queue.js +450 -0
  124. package/dist/reach.d.ts.map +1 -1
  125. package/dist/reach.js +67 -22
  126. package/dist/react.d.ts +5 -0
  127. package/dist/react.d.ts.map +1 -1
  128. package/dist/react.js +33 -1
  129. package/dist/reads.d.ts +3 -1
  130. package/dist/reads.d.ts.map +1 -1
  131. package/dist/reads.js +9 -2
  132. package/dist/recovery.d.ts +3 -1
  133. package/dist/recovery.d.ts.map +1 -1
  134. package/dist/recovery.js +29 -7
  135. package/dist/refresh.js +2 -2
  136. package/dist/refusal.d.ts.map +1 -1
  137. package/dist/refusal.js +5 -6
  138. package/dist/replica.d.ts +5 -11
  139. package/dist/replica.d.ts.map +1 -1
  140. package/dist/replica.js +13 -15
  141. package/dist/retried.d.ts +30 -0
  142. package/dist/retried.d.ts.map +1 -0
  143. package/dist/retried.js +72 -0
  144. package/dist/room-draft.d.ts +4 -6
  145. package/dist/room-draft.d.ts.map +1 -1
  146. package/dist/room-draft.js +46 -57
  147. package/dist/room-drafts.d.ts.map +1 -1
  148. package/dist/room-drafts.js +17 -16
  149. package/dist/rows.d.ts.map +1 -1
  150. package/dist/rows.js +3 -4
  151. package/dist/runtime.d.ts +9 -18
  152. package/dist/runtime.d.ts.map +1 -1
  153. package/dist/save.d.ts +42 -90
  154. package/dist/save.d.ts.map +1 -1
  155. package/dist/save.js +334 -167
  156. package/dist/saves.d.ts +2 -40
  157. package/dist/saves.d.ts.map +1 -1
  158. package/dist/saves.js +107 -705
  159. package/dist/seed.d.ts.map +1 -1
  160. package/dist/seed.js +2 -3
  161. package/dist/shared.d.ts +0 -5
  162. package/dist/shared.d.ts.map +1 -1
  163. package/dist/shared.js +4 -90
  164. package/dist/shown.d.ts +4 -3
  165. package/dist/shown.d.ts.map +1 -1
  166. package/dist/shown.js +26 -31
  167. package/dist/socket/lanes.d.ts +12 -4
  168. package/dist/socket/lanes.d.ts.map +1 -1
  169. package/dist/socket/lanes.js +34 -8
  170. package/dist/socket/session.d.ts +0 -1
  171. package/dist/socket/session.d.ts.map +1 -1
  172. package/dist/socket.d.ts +3 -6
  173. package/dist/socket.d.ts.map +1 -1
  174. package/dist/socket.js +5 -16
  175. package/dist/source.d.ts +0 -7
  176. package/dist/source.d.ts.map +1 -1
  177. package/dist/source.js +5 -4
  178. package/dist/store/records.d.ts +8 -6
  179. package/dist/store/records.d.ts.map +1 -1
  180. package/dist/store/records.js +13 -6
  181. package/dist/store/space.d.ts +1 -1
  182. package/dist/store/space.d.ts.map +1 -1
  183. package/dist/store/space.js +0 -2
  184. package/dist/store/watchers.js +1 -2
  185. package/dist/store.d.ts +11 -6
  186. package/dist/store.d.ts.map +1 -1
  187. package/dist/store.js +38 -13
  188. package/dist/stored.d.ts +2 -1
  189. package/dist/stored.d.ts.map +1 -1
  190. package/dist/stored.js +11 -11
  191. package/dist/surface.d.ts +1 -1
  192. package/dist/surface.d.ts.map +1 -1
  193. package/dist/surface.js +13 -16
  194. package/dist/sync.d.ts.map +1 -1
  195. package/dist/sync.js +88 -85
  196. package/dist/tables.d.ts +6 -8
  197. package/dist/tables.d.ts.map +1 -1
  198. package/dist/tables.js +41 -20
  199. package/dist/tallies.js +5 -5
  200. package/dist/validation.d.ts.map +1 -1
  201. package/dist/validation.js +2 -2
  202. package/dist/wire.d.ts +51 -7
  203. package/dist/wire.d.ts.map +1 -1
  204. package/dist/wire.js +15 -4
  205. package/package.json +3 -2
  206. package/dist/attempt.d.ts +0 -16
  207. package/dist/attempt.d.ts.map +0 -1
  208. package/dist/attempt.js +0 -70
  209. package/dist/job.d.ts +0 -33
  210. package/dist/job.d.ts.map +0 -1
  211. package/dist/job.js +0 -54
  212. package/dist/log.d.ts +0 -6
  213. package/dist/log.d.ts.map +0 -1
  214. package/dist/log.js +0 -14
  215. package/dist/socket/rooms.d.ts +0 -44
  216. package/dist/socket/rooms.d.ts.map +0 -1
  217. package/dist/socket/rooms.js +0 -90
  218. package/dist/store/fences.d.ts +0 -16
  219. package/dist/store/fences.d.ts.map +0 -1
  220. package/dist/store/fences.js +0 -26
@@ -1,14 +1,17 @@
1
1
  import { cursorOf, decodedCursor } from '@agentshouse/mdmodel';
2
+ import { applied, isTurn, standingState, } from '@agentshouse/session-content';
2
3
  import { conversationChangeSet } from './change-set.js';
3
4
  import { FACTS, QUIET, } from './conversation-live.js';
4
5
  import { heldFacts } from './conversation-row.js';
5
- import { runtimeError } from './failure.js';
6
+ import { runtimeError, uncaught } from './failure.js';
6
7
  import { refusedForSpace } from './durability.js';
7
8
  import { changeBatchIdentity, chatDraftRevision } from './identity.js';
8
9
  import { OFFLINE } from './outcome.js';
9
- import { jobsOf, runningLine } from './parts.js';
10
+ import { runningLine } from './parts.js';
11
+ import { record, text } from './read.js';
10
12
  import { openQuestion, questionAsked } from './questions.js';
11
13
  import { untilAnswered } from './recovery.js';
14
+ import { retrying } from './retried.js';
12
15
  import { capped, FROM_START, messageOrder, precedes } from './windows.js';
13
16
  export function unheldView(conversation) {
14
17
  return {
@@ -21,15 +24,19 @@ export function unheldView(conversation) {
21
24
  commands: [],
22
25
  options: [],
23
26
  starting: null,
24
- subagents: [],
27
+ state: null,
25
28
  link: null,
29
+ deliveryWaiting: [],
26
30
  deliveryUnknown: [],
27
31
  chatDraft: null,
28
- jobs: [],
32
+ dismissedSuggestion: null,
29
33
  };
30
34
  }
31
35
  export const SESSION_STARTED = 'Session started';
32
36
  const NEW_CHAT = 'new:';
37
+ const LISTING = 'listing';
38
+ const AGENTS = 'agents';
39
+ export const CATCHING_UP = 'catching-up';
33
40
  export const HISTORY_CONVERSATIONS = 64;
34
41
  export function newChat(agent) {
35
42
  return `${NEW_CHAT}${agent}`;
@@ -42,52 +49,15 @@ function creationOf(input) {
42
49
  }
43
50
  function startedTurn(turn, operation) {
44
51
  if (operation.op === 'begin')
45
- return { turn, started: operation.at, parts: [], context: null };
46
- if (operation.op === 'context') {
47
- return {
48
- turn,
49
- started: null,
50
- parts: [],
51
- context: { used: operation.used, window: operation.window },
52
- };
53
- }
54
- return operation.op === 'start' && operation.index === 0
55
- ? { turn, started: null, parts: [structuredClone(operation.part)], context: null }
56
- : null;
57
- }
58
- function changedFields(part, operation) {
59
- if (operation.op === 'append') {
60
- return { text: `${String(part.text ?? '')}${operation.text}` };
61
- }
62
- if (operation.op === 'status') {
63
- return { status: operation.status, result: structuredClone(operation.result) };
64
- }
65
- if (operation.op === 'count')
66
- return { count: operation.count };
67
- return { entries: structuredClone(operation.entries) };
52
+ return { turn, started: operation.at, parts: [] };
53
+ const parts = applied([], operation);
54
+ return parts === null ? null : { turn, started: null, parts };
68
55
  }
69
56
  function appliedTurn(held, operation) {
70
57
  if (operation.op === 'begin')
71
58
  return { ...held, started: operation.at };
72
- if (operation.op === 'context') {
73
- return { ...held, context: { used: operation.used, window: operation.window } };
74
- }
75
- if (operation.op === 'start') {
76
- if (operation.index !== 0 && operation.index !== held.parts.length)
77
- return null;
78
- return {
79
- ...held,
80
- parts: [...held.parts.slice(0, operation.index), structuredClone(operation.part)],
81
- };
82
- }
83
- const part = held.parts[operation.index];
84
- if (typeof part !== 'object' || part === null)
85
- return null;
86
- const changed = { ...part, ...changedFields(part, operation) };
87
- return {
88
- ...held,
89
- parts: held.parts.map((kept, at) => (at === operation.index ? changed : kept)),
90
- };
59
+ const parts = applied(held.parts, operation);
60
+ return parts === null ? null : { ...held, parts };
91
61
  }
92
62
  function windowOf(held, arriving, limit) {
93
63
  const byIdentity = new Map(held.map((message) => [message.identity, message]));
@@ -110,7 +80,7 @@ function frameOf(asked, messages, more, total) {
110
80
  };
111
81
  }
112
82
  function newestOf(arriving, from) {
113
- return arriving.reduce((top, message) => (top === null || message.position > top ? message.position : top), from);
83
+ return arriving.reduce((top, message) => (top === null || message.change > top ? message.change : top), from);
114
84
  }
115
85
  function acceptedMessage(value) {
116
86
  if (typeof value !== 'object' || value === null)
@@ -119,6 +89,7 @@ function acceptedMessage(value) {
119
89
  if (typeof record.identity !== 'string' ||
120
90
  typeof record.turn !== 'string' ||
121
91
  typeof record.position !== 'string' ||
92
+ typeof record.change !== 'string' ||
122
93
  typeof record.text !== 'string') {
123
94
  return null;
124
95
  }
@@ -126,6 +97,7 @@ function acceptedMessage(value) {
126
97
  identity: record.identity,
127
98
  turn: record.turn,
128
99
  position: record.position,
100
+ change: record.change,
129
101
  text: record.text,
130
102
  message: structuredClone(record.message),
131
103
  };
@@ -227,17 +199,17 @@ function withSubmitted(draft, submitted) {
227
199
  const { submitted: _held, ...unsent } = draft;
228
200
  return submitted.length === 0 ? unsent : { ...unsent, submitted };
229
201
  }
230
- function prepended(draft, said) {
231
- return { text: [said.text, draft.text].filter((one) => one !== '').join('\n') };
202
+ export function joinedDraft(first, second) {
203
+ return [first, second].filter((one) => one !== '').join('\n');
232
204
  }
233
205
  function returned(draft, submission, others) {
234
206
  return withSubmitted({
235
207
  conversation: draft.conversation,
236
- ...prepended(draft, submission),
208
+ text: joinedDraft(submission.text, draft.text),
237
209
  revision: chatDraftRevision(),
238
210
  }, others);
239
211
  }
240
- function viewOf(alive, conversation, held, frame, draft, ended, marked) {
212
+ function viewOf(alive, conversation, held, frame, draft, ended, dismissed) {
241
213
  const facts = alive.liveOf(conversation);
242
214
  return {
243
215
  conversation,
@@ -255,26 +227,39 @@ function viewOf(alive, conversation, held, frame, draft, ended, marked) {
255
227
  commands: structuredClone(facts.commands),
256
228
  options: structuredClone(facts.options),
257
229
  starting: facts.starting,
258
- subagents: structuredClone(facts.subagents),
230
+ state: sessionOf(facts, held, ended),
259
231
  link: facts.link === null ? null : { ...facts.link },
232
+ deliveryWaiting: [...facts.deliveryWaiting],
260
233
  deliveryUnknown: [...facts.deliveryUnknown],
261
234
  chatDraft: draft === null || unwritten(draft) ? null : { text: draft.text, revision: draft.revision },
262
- jobs: facts.process?.running === false
263
- ? []
264
- : jobsOf(marked.filter(({ at }) => ended === null || at > ended), facts.turn),
235
+ dismissedSuggestion: dismissed,
265
236
  };
266
237
  }
238
+ function sessionOf(facts, held, ended) {
239
+ if (facts.state !== null)
240
+ return structuredClone(facts.state);
241
+ const saved = [...held]
242
+ .reverse()
243
+ .map(({ message }) => record(message))
244
+ .find(({ content }) => isTurn(content));
245
+ const at = saved === undefined ? null : text(saved, 'accepted_at');
246
+ if (saved === undefined || !isTurn(saved.content) || at === null)
247
+ return null;
248
+ const down = facts.process?.running === false;
249
+ return structuredClone(standingState(saved.content.state, at, down ? at : ended));
250
+ }
267
251
  function emit(alive, conversation) {
268
252
  if (alive.deps.closed())
269
253
  return;
270
254
  for (const view of alive.views()) {
271
- const { window, draft, ended, marked } = view.held.now();
255
+ const { window, draft, ended, dismissed } = view.held.now();
272
256
  if (view.conversation !== conversation || window === null)
273
257
  continue;
274
258
  const ready = view.ready();
275
259
  if (ready.length === 0)
276
260
  continue;
277
- const value = viewOf(alive, conversation, window, sharedFrame(view, window), draft, ended, marked);
261
+ const frame = sharedFrame(view, window);
262
+ const value = viewOf(alive, conversation, window, frame, draft, ended, dismissed);
278
263
  for (const watcher of ready)
279
264
  watcher.notify(value);
280
265
  }
@@ -285,23 +270,18 @@ function sharedFrame(view, window) {
285
270
  }
286
271
  async function slide(alive, local, conversation, arriving) {
287
272
  let count;
288
- let marked;
289
273
  for (const view of alive.views()) {
290
274
  const { held } = view;
291
275
  const { window, total } = held.now();
292
276
  if (view.conversation !== conversation || window === null)
293
277
  continue;
294
278
  if (arriving === null) {
295
- held.set({ window: [], marked: [], more: false, total: total === null ? null : 0 });
279
+ held.set({ window: [], more: false, total: total === null ? null : 0 });
296
280
  continue;
297
281
  }
298
282
  const joining = arriving.filter((message) => precedes(message, view.asked.before));
299
283
  const next = windowOf(window, joining, view.asked.limit);
300
284
  held.set({ window: next.messages, more: held.now().more || next.dropped });
301
- if (arriving.length > 0) {
302
- marked ??= await local.jobMarkers(conversation);
303
- held.set({ marked });
304
- }
305
285
  if (held.now().total !== null && arriving.length > 0) {
306
286
  count ??= await local.messageCount(conversation);
307
287
  held.set({ total: count });
@@ -399,7 +379,7 @@ function listChanged(alive, change) {
399
379
  list.some(({ conversation }) => !replicated.has(conversation)))) {
400
380
  alive.deps.again();
401
381
  }
402
- }, () => { });
382
+ }, uncaught);
403
383
  }
404
384
  function endedAnew(alive, list) {
405
385
  const entries = new Map(list.map((entry) => [entry.conversation, entry]));
@@ -415,7 +395,10 @@ function endedAnew(alive, list) {
415
395
  function shownList(alive, work) {
416
396
  const reading = heldList(alive);
417
397
  alive.inOrder(async () => {
418
- const list = await reading.catch(() => null);
398
+ const list = await reading.catch((error) => {
399
+ uncaught(error);
400
+ return null;
401
+ });
419
402
  if (list === null || alive.deps.closed())
420
403
  return;
421
404
  work(list);
@@ -425,7 +408,7 @@ async function told(alive) {
425
408
  try {
426
409
  while (alive.held.now().listOwed && !alive.deps.closed()) {
427
410
  alive.held.set({ listOwed: false });
428
- const value = await untilAnswered(() => entries(alive), alive.closing);
411
+ const value = await untilAnswered(retrying(alive.deps.retries, 'conversations', LISTING, () => entries(alive)), alive.closing, () => true, alive.deps.recovery);
429
412
  if (alive.deps.closed())
430
413
  return;
431
414
  if (value === null)
@@ -468,15 +451,24 @@ export function conversationsLearned(alive) {
468
451
  shownList(alive, (list) => alive.agentListeners.welcome(agents(alive, list)));
469
452
  }
470
453
  function agents(alive, list) {
471
- const named = new Map();
472
- for (const agent of alive.held.now().listedAgents ?? [])
473
- named.set(agent.agent, agent);
454
+ const read = new Map((alive.held.now().listedAgents ?? []).map((one) => [one.agent, one]));
455
+ const named = new Map(read);
474
456
  for (const entry of list) {
475
457
  named.set(entry.agent, { name: entry.agentName, retired: entry.agentRetired });
476
458
  }
477
459
  return [...named]
478
460
  .filter(([, agent]) => !agent.retired)
479
- .map(([identity, agent]) => ({ identity, name: agent.name }))
461
+ .map(([identity, agent]) => {
462
+ const held = read.get(identity);
463
+ return held === undefined
464
+ ? { identity, name: agent.name }
465
+ : {
466
+ identity,
467
+ name: agent.name,
468
+ cli: held.cli,
469
+ environment: structuredClone(held.environment),
470
+ };
471
+ })
480
472
  .sort((left, right) => left.name === right.name
481
473
  ? left.identity.localeCompare(right.identity)
482
474
  : left.name.localeCompare(right.name));
@@ -493,7 +485,7 @@ function readAgents(alive) {
493
485
  if (!alive.deps.online() || (!agentListeners.waiting() && !agentListeners.told())) {
494
486
  return 'done';
495
487
  }
496
- const listed = await read();
488
+ const listed = await retrying(alive.deps.retries, 'conversations', AGENTS, read)();
497
489
  if (listed === null)
498
490
  return 'done';
499
491
  alive.held.set({ listedAgents: listed });
@@ -550,8 +542,9 @@ function openingEnded(alive) {
550
542
  commands: facts.has('commands') ? QUIET.commands : held.commands,
551
543
  options: facts.has('options') ? QUIET.options : held.options,
552
544
  starting: facts.has('starting') ? QUIET.starting : held.starting,
553
- subagents: facts.has('subagents') ? QUIET.subagents : held.subagents,
545
+ state: facts.has('state') ? QUIET.state : held.state,
554
546
  link: facts.has('link') ? QUIET.link : held.link,
547
+ deliveryWaiting: facts.has('deliveryWaiting') ? QUIET.deliveryWaiting : held.deliveryWaiting,
555
548
  deliveryUnknown: facts.has('deliveryUnknown') ? QUIET.deliveryUnknown : held.deliveryUnknown,
556
549
  });
557
550
  emit(alive, conversation);
@@ -583,19 +576,13 @@ function handReplicated(alive) {
583
576
  }
584
577
  async function remove(alive, leaving) {
585
578
  await alive.deps.durably(async (local) => {
586
- const kept = new Set([
587
- ...(await local.conversations(leaving)).map(({ conversation }) => conversation),
588
- ...(await local.chatDrafts())
589
- .filter(({ conversation }) => leaving.includes(conversation))
590
- .map(({ conversation }) => conversation),
591
- ]);
592
- await local.dropConversations(leaving);
579
+ const kept = new Set(await local.dropConversations(leaving));
593
580
  const changed = [];
594
581
  for (const conversation of leaving) {
595
582
  if (kept.has(conversation) || alive.liveHeld(conversation) !== undefined) {
596
583
  changed.push(conversation);
597
584
  }
598
- shownDraft(alive, conversation, null);
585
+ heldInViews(alive, conversation, { draft: null, dismissed: null });
599
586
  alive.forget(conversation);
600
587
  setLive(alive, conversation, null);
601
588
  await slide(alive, local, conversation, null);
@@ -634,7 +621,7 @@ function retiredDrafts(alive, list) {
634
621
  held.some(({ conversation }) => retiredChat(conversation, list))) {
635
622
  alive.deps.again();
636
623
  }
637
- }, () => { });
624
+ }, uncaught);
638
625
  }
639
626
  function settleBehind(alive, list) {
640
627
  void alive.deps
@@ -660,21 +647,19 @@ function settleBehind(alive, list) {
660
647
  alive.deps.settled();
661
648
  if (owed)
662
649
  alive.deps.again();
663
- }, () => { });
650
+ }, uncaught);
664
651
  }
665
652
  function keep(alive, conversation, message) {
666
653
  return alive.deps.durably(async (local) => {
667
654
  if (!alive.held.now().replicated.has(conversation))
668
655
  return;
669
656
  const read = (await readsOf(local, [conversation])).get(conversation)?.read;
670
- const advances = read !== undefined &&
671
- !alive.behind(conversation) &&
672
- (read === null || message.position > read);
657
+ const advances = read !== undefined && !alive.behind(conversation) && (read === null || message.change > read);
673
658
  await sealed(alive, local, conversation, new Set([message.turn]));
674
659
  await local.keepMessages({
675
660
  conversation,
676
661
  messages: [message],
677
- ...(advances ? { read: { at: message.position, partial: false } } : {}),
662
+ ...(advances ? { read: { at: message.change, partial: false } } : {}),
678
663
  });
679
664
  sealTurns(alive, conversation, new Set([message.turn]));
680
665
  await slide(alive, local, conversation, [message]);
@@ -786,8 +771,8 @@ function heard(alive, event) {
786
771
  live(alive, conversation, { starting: event.step });
787
772
  return;
788
773
  }
789
- if (event.kind === 'subagents') {
790
- live(alive, conversation, { subagents: structuredClone(event.subagents) });
774
+ if (event.kind === 'state') {
775
+ live(alive, conversation, { state: structuredClone(event.state) });
791
776
  return;
792
777
  }
793
778
  if (event.kind === 'link') {
@@ -795,13 +780,16 @@ function heard(alive, event) {
795
780
  return;
796
781
  }
797
782
  if (event.kind === 'deliveries') {
798
- live(alive, conversation, { deliveryUnknown: [...event.unknown] });
783
+ live(alive, conversation, {
784
+ deliveryWaiting: [...event.waiting],
785
+ deliveryUnknown: [...event.unknown],
786
+ });
799
787
  return;
800
788
  }
801
789
  const arriving = acceptedMessage(event.message);
802
790
  if (arriving === null)
803
791
  return;
804
- alive.heardAt(conversation, arriving.position);
792
+ alive.heardAt(conversation, arriving.change);
805
793
  if (alive.held.now().replicated.has(conversation)) {
806
794
  if (alive.deps.full()) {
807
795
  alive.gapOpened(conversation);
@@ -810,6 +798,8 @@ function heard(alive, event) {
810
798
  void keep(alive, conversation, arriving).catch((error) => {
811
799
  if (refusedForSpace(error))
812
800
  alive.gapOpened(conversation);
801
+ else
802
+ uncaught(error);
813
803
  });
814
804
  return;
815
805
  }
@@ -817,19 +807,27 @@ function heard(alive, event) {
817
807
  emit(alive, conversation);
818
808
  }
819
809
  async function kept(alive, local, conversation, following) {
820
- const shown = following === null || empty(following) ? null : following;
821
- if (shown === null)
810
+ const draft = following === null || empty(following) ? null : following;
811
+ if (draft === null)
822
812
  await local.dropChatDraft(conversation);
823
813
  else
824
- await local.keepChatDrafts([shown]);
825
- shownDraft(alive, conversation, shown);
814
+ await local.keepChatDrafts([draft]);
815
+ heldInViews(alive, conversation, { draft });
826
816
  }
827
- function shownDraft(alive, conversation, draft) {
817
+ function heldInViews(alive, conversation, held) {
828
818
  for (const view of alive.views()) {
829
819
  if (view.conversation === conversation)
830
- view.held.set({ draft });
820
+ view.held.set(held);
831
821
  }
832
822
  }
823
+ async function factOf(local, name) {
824
+ return Object.fromEntries((await local.conversationFacts())
825
+ .filter((fact) => fact.name === name)
826
+ .map(({ conversation, value }) => [conversation, value]));
827
+ }
828
+ async function dismissedIn(local, conversation) {
829
+ return (await factOf(local, 'dismissedSuggestion'))[conversation] ?? null;
830
+ }
833
831
  async function draftAt(local, conversation) {
834
832
  return (await local.chatDraft(conversation)) ?? undefined;
835
833
  }
@@ -860,9 +858,9 @@ function moved(alive, agent, operation, to) {
860
858
  : [{ ...unsent, conversation: to }];
861
859
  const left = { ...(taken.length === 0 ? unsent : blank), moves: [...earlier, operation] };
862
860
  await local.keepChatDrafts([left, ...taken]);
863
- shownDraft(alive, from, left);
861
+ heldInViews(alive, from, { draft: left });
864
862
  for (const one of taken)
865
- shownDraft(alive, to, one);
863
+ heldInViews(alive, to, { draft: one });
866
864
  alive.deps.publish(conversationChangeSet([from, to]));
867
865
  });
868
866
  }
@@ -893,13 +891,10 @@ async function submitted(alive, conversation, operation, draft) {
893
891
  });
894
892
  return submission;
895
893
  }
896
- async function dispatched(alive, conversation, submission) {
894
+ async function dispatched(alive, conversation, submission, resent = false) {
897
895
  const dispatch = alive.sendingBegan(submission.operation);
898
896
  try {
899
- const result = await invoke(alive, 'conversations/send', conversation, {
900
- operation_id: submission.operation,
901
- text: submission.text,
902
- });
897
+ const result = await invoke(alive, 'conversations/send', conversation, submission.operation, { text: submission.text }, { step: 'sending', instance: `message ${submission.operation}` });
903
898
  dispatch.set({ answered: result.kind !== 'transport-uncertainty' });
904
899
  if (result.kind === 'revoked-authorization')
905
900
  return result;
@@ -907,6 +902,7 @@ async function dispatched(alive, conversation, submission) {
907
902
  alive.deps.unanswered();
908
903
  return result;
909
904
  }
905
+ alive.deps.heard(submission.operation, resent);
910
906
  const turn = answered(result, 'message_id');
911
907
  await withDraft(alive, conversation, async (current, local) => {
912
908
  const held = current?.submitted?.find((one) => one.operation === submission.operation);
@@ -926,8 +922,8 @@ async function dispatched(alive, conversation, submission) {
926
922
  alive.sendingEnded(submission.operation, dispatch);
927
923
  }
928
924
  }
929
- function invoke(alive, name, conversation, extra = { operation_id: changeBatchIdentity() }) {
930
- return alive.deps.call(name, { conversation_id: conversation, ...extra });
925
+ function invoke(alive, name, conversation, operation, extra = {}, attempt) {
926
+ return alive.deps.call(name, { conversation_id: conversation, operation_id: operation, ...extra }, attempt);
931
927
  }
932
928
  export function conversationSurface(alive) {
933
929
  return {
@@ -948,8 +944,7 @@ export function conversationSurface(alive) {
948
944
  return alive.deps.durably(async (local) => {
949
945
  const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before, phrase);
950
946
  const total = asked.total ? await local.messageCount(conversation, phrase) : null;
951
- const marked = await local.jobMarkers(conversation);
952
- return structuredClone(viewOf(alive, conversation, messages, frameOf(asked, messages, more, total), (await local.chatDraft(conversation)) ?? null, await endedIn(alive, conversation), marked));
947
+ return structuredClone(viewOf(alive, conversation, messages, frameOf(asked, messages, more, total), (await local.chatDraft(conversation)) ?? null, await endedIn(alive, conversation), await dismissedIn(local, conversation)));
953
948
  });
954
949
  },
955
950
  async create(input) {
@@ -986,40 +981,88 @@ export function conversationSurface(alive) {
986
981
  }
987
982
  return OFFLINE;
988
983
  },
989
- answer(conversation, answer) {
990
- return invoke(alive, 'conversations/interaction/answer', conversation, {
991
- operation_id: changeBatchIdentity(),
992
- ...answer,
984
+ answer(conversation, answer, operation) {
985
+ return invoke(alive, 'conversations/interaction/answer', conversation, operation, answer);
986
+ },
987
+ interrupt(conversation, operation) {
988
+ return invoke(alive, 'conversations/interrupt', conversation, operation);
989
+ },
990
+ kill(conversation, operation) {
991
+ return invoke(alive, 'conversations/kill', conversation, operation);
992
+ },
993
+ delete(conversation, operation) {
994
+ return invoke(alive, 'conversations/delete', conversation, operation);
995
+ },
996
+ takeOut(conversation, message, operation) {
997
+ return invoke(alive, 'conversations/take-out', conversation, operation, {
998
+ message_id: message,
993
999
  });
994
1000
  },
995
- interrupt(conversation) {
996
- return invoke(alive, 'conversations/interrupt', conversation);
1001
+ decide({ request, room, message }, decision, operation) {
1002
+ return alive.deps.call('agent-functions/decide', {
1003
+ room_ref: room,
1004
+ request,
1005
+ ...(message === undefined ? {} : { message }),
1006
+ decision,
1007
+ operation_id: operation,
1008
+ });
1009
+ },
1010
+ rename(conversation, name, operation) {
1011
+ return invoke(alive, 'conversations/rename', conversation, operation, { name });
997
1012
  },
998
- kill(conversation) {
999
- return invoke(alive, 'conversations/kill', conversation);
1013
+ option(conversation, option, value, operation) {
1014
+ return invoke(alive, 'conversations/option/set', conversation, operation, { option, value });
1000
1015
  },
1001
- delete(conversation) {
1002
- return invoke(alive, 'conversations/delete', conversation);
1016
+ retry(conversation, message, operation) {
1017
+ return invoke(alive, 'conversations/retry', conversation, operation, {
1018
+ message_id: message,
1019
+ });
1020
+ },
1021
+ async pins() {
1022
+ return (await (await alive.deps.local()).facts()).chatPins;
1023
+ },
1024
+ pin(figures) {
1025
+ return alive.deps.durably((local) => local.fact('chatPins', [...figures]));
1026
+ },
1027
+ async openedTurns() {
1028
+ return factOf(await alive.deps.local(), 'openedTurn');
1029
+ },
1030
+ openTurn(conversation, turn) {
1031
+ return alive.deps.durably((local) => local.keepConversationFact({ conversation, name: 'openedTurn', value: turn }));
1032
+ },
1033
+ dismissSuggestion(conversation, suggestion) {
1034
+ return alive.deps.durably(async (local) => {
1035
+ if ((await dismissedIn(local, conversation)) === suggestion)
1036
+ return;
1037
+ await local.keepConversationFact({
1038
+ conversation,
1039
+ name: 'dismissedSuggestion',
1040
+ value: suggestion,
1041
+ });
1042
+ heldInViews(alive, conversation, { dismissed: suggestion });
1043
+ alive.deps.publish(conversationChangeSet([conversation]));
1044
+ });
1003
1045
  },
1004
1046
  };
1005
1047
  }
1048
+ function rewritten(alive, conversation, text, revision = chatDraftRevision()) {
1049
+ return withDraft(alive, conversation, (current) => ({
1050
+ conversation,
1051
+ text: text(current?.text ?? ''),
1052
+ revision,
1053
+ ...(current === undefined ? {} : pending(current)),
1054
+ }));
1055
+ }
1006
1056
  export function chatDraftSurface(alive) {
1007
1057
  return {
1008
- write(conversation, draft, revision = chatDraftRevision()) {
1009
- return withDraft(alive, conversation, (current) => ({
1010
- conversation,
1011
- text: draft.text,
1012
- revision,
1013
- ...(current === undefined ? {} : pending(current)),
1014
- }));
1058
+ write(conversation, draft, revision) {
1059
+ return rewritten(alive, conversation, () => draft.text, revision);
1015
1060
  },
1016
1061
  prepend(conversation, draft) {
1017
- return withDraft(alive, conversation, (current) => ({
1018
- conversation,
1019
- ...(current === undefined ? { text: draft.text } : prepended(current, draft)),
1020
- revision: chatDraftRevision(),
1021
- ...(current === undefined ? {} : pending(current)),
1022
- }));
1062
+ return rewritten(alive, conversation, (held) => joinedDraft(draft.text, held));
1063
+ },
1064
+ append(conversation, draft) {
1065
+ return rewritten(alive, conversation, (held) => joinedDraft(held, draft.text));
1023
1066
  },
1024
1067
  discard(conversation) {
1025
1068
  return withDraft(alive, conversation, (current) => current === undefined
@@ -1039,9 +1082,9 @@ export async function reconcileConversations(alive) {
1039
1082
  if (!alive.known())
1040
1083
  return;
1041
1084
  const local = await alive.deps.local();
1042
- const [held, kept, { conversationList }] = await Promise.all([
1085
+ const [held, stored, { conversationList }] = await Promise.all([
1043
1086
  local.conversations(),
1044
- local.chatDrafts(),
1087
+ local.storedConversations(),
1045
1088
  local.facts(),
1046
1089
  ]);
1047
1090
  const list = conversationList ?? [];
@@ -1049,9 +1092,7 @@ export async function reconcileConversations(alive) {
1049
1092
  const named = new Set(entries.keys());
1050
1093
  const reads = new Map(held.map((one) => [one.conversation, one]));
1051
1094
  const { replicated } = alive.held.now();
1052
- const leaving = [
1053
- ...new Set([...replicated, ...reads.keys(), ...kept.map(({ conversation }) => conversation)]),
1054
- ].filter((conversation) => !named.has(conversation) &&
1095
+ const leaving = [...new Set([...replicated, ...stored])].filter((conversation) => !named.has(conversation) &&
1055
1096
  !alive.isCreating(conversation) &&
1056
1097
  (!conversation.startsWith(NEW_CHAT) || retiredChat(conversation, list)));
1057
1098
  for (const conversation of named) {
@@ -1088,6 +1129,17 @@ export async function catchUpConversations(alive, progress) {
1088
1129
  if (!alive.current())
1089
1130
  progress.complete = false;
1090
1131
  }
1132
+ export async function holdsSubmission(alive, operation) {
1133
+ if (alive.sending(operation))
1134
+ return true;
1135
+ const local = await alive.deps.local();
1136
+ for (const { conversation } of await local.chatDrafts()) {
1137
+ const held = (await local.chatDraft(conversation))?.submitted;
1138
+ if (held?.some((one) => one.operation === operation && one.turn === null) === true)
1139
+ return true;
1140
+ }
1141
+ return false;
1142
+ }
1091
1143
  export async function resendConversations(alive, progress) {
1092
1144
  const local = await alive.deps.local();
1093
1145
  const tried = new Set();
@@ -1099,7 +1151,7 @@ export async function resendConversations(alive, progress) {
1099
1151
  if (alive.deps.closed())
1100
1152
  return;
1101
1153
  tried.add(submission.operation);
1102
- const result = await dispatched(alive, conversation, submission);
1154
+ const result = await dispatched(alive, conversation, submission, true);
1103
1155
  if (result.kind === 'revoked-authorization')
1104
1156
  return;
1105
1157
  if (result.kind === 'transport-uncertainty') {
@@ -1119,23 +1171,24 @@ export function watchConversation(alive, conversation, options, deliver) {
1119
1171
  const { view, watcher } = alive.viewJoined(key, conversation, asked, deliver);
1120
1172
  const { held } = view;
1121
1173
  const reading = new AbortController();
1122
- void untilAnswered(() => alive.deps.durably(async (local) => {
1174
+ void untilAnswered(retrying(alive.deps.retries, 'reading', `window ${key}`, () => alive.deps.durably(async (local) => {
1123
1175
  if (held.now().window !== null)
1124
1176
  return;
1125
1177
  const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
1126
1178
  held.set({ draft: (await local.chatDraft(conversation)) ?? null });
1127
1179
  held.set({ ended: await endedIn(alive, conversation) });
1180
+ held.set({ dismissed: await dismissedIn(local, conversation) });
1128
1181
  held.set({ window: messages });
1129
- held.set({ marked: await local.jobMarkers(conversation) });
1130
1182
  held.set({ more });
1131
1183
  held.set({ total: asked.total ? await local.messageCount(conversation) : null });
1132
- }), reading.signal)
1184
+ })), reading.signal)
1133
1185
  .then(() => {
1134
1186
  if (alive.deps.closed() || !view.admit(watcher))
1135
1187
  return;
1136
- const { window, draft, ended, marked } = held.now();
1188
+ const { window, draft, ended, dismissed } = held.now();
1137
1189
  const shown = window ?? [];
1138
- watcher.notify(viewOf(alive, conversation, shown, sharedFrame(view, shown), draft, ended, marked));
1190
+ const frame = sharedFrame(view, shown);
1191
+ watcher.notify(viewOf(alive, conversation, shown, frame, draft, ended, dismissed));
1139
1192
  })
1140
1193
  .catch(() => { });
1141
1194
  return () => {
@@ -0,0 +1,10 @@
1
+ import type { DiscoveredRoom, OperationScopes, PathRule, RoomDeclaration } from './adapter.js';
2
+ export type WriteRefusal = {
3
+ readonly code: 'room-root' | 'provider-owned-path' | 'invalid-path' | `${keyof OperationScopes}-grant`;
4
+ readonly path: string;
5
+ };
6
+ export type WriteRule = (path: string, needs: readonly (keyof OperationScopes)[]) => WriteRefusal | null;
7
+ export declare function declared({ locator: _locator, roomVersion: _roomVersion, ...declaration }: DiscoveredRoom): RoomDeclaration;
8
+ export declare function sameDeclaration(left: RoomDeclaration, right: RoomDeclaration): boolean;
9
+ export declare function writeRule({ operations, providerOwnedPaths, authoredPaths, }: Pick<RoomDeclaration, 'operations' | 'providerOwnedPaths' | 'authoredPaths'>, pathRule: PathRule, local: boolean): WriteRule;
10
+ //# sourceMappingURL=declaration.d.ts.map