@agentshouse/mdruntime 0.1.0-alpha.7 → 0.1.0-alpha.9

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 (86) hide show
  1. package/dist/adapter.d.ts +107 -16
  2. package/dist/adapter.d.ts.map +1 -1
  3. package/dist/adapter.js.map +1 -1
  4. package/dist/bootstrap.d.ts +6 -1
  5. package/dist/bootstrap.d.ts.map +1 -1
  6. package/dist/bootstrap.js +14 -6
  7. package/dist/bootstrap.js.map +1 -1
  8. package/dist/change.d.ts +1 -0
  9. package/dist/change.d.ts.map +1 -1
  10. package/dist/change.js.map +1 -1
  11. package/dist/client.d.ts +63 -0
  12. package/dist/client.d.ts.map +1 -0
  13. package/dist/client.js +227 -0
  14. package/dist/client.js.map +1 -0
  15. package/dist/collection.d.ts +19 -4
  16. package/dist/collection.d.ts.map +1 -1
  17. package/dist/collection.js +88 -25
  18. package/dist/collection.js.map +1 -1
  19. package/dist/connection.d.ts +37 -9
  20. package/dist/connection.d.ts.map +1 -1
  21. package/dist/connection.js +818 -274
  22. package/dist/connection.js.map +1 -1
  23. package/dist/conversation.d.ts +57 -0
  24. package/dist/conversation.d.ts.map +1 -0
  25. package/dist/conversation.js +401 -0
  26. package/dist/conversation.js.map +1 -0
  27. package/dist/durability.d.ts +8 -3
  28. package/dist/durability.d.ts.map +1 -1
  29. package/dist/durability.js +5 -59
  30. package/dist/durability.js.map +1 -1
  31. package/dist/file.d.ts +20 -0
  32. package/dist/file.d.ts.map +1 -0
  33. package/dist/file.js +149 -0
  34. package/dist/file.js.map +1 -0
  35. package/dist/host.d.ts +9 -0
  36. package/dist/host.d.ts.map +1 -0
  37. package/dist/host.js +200 -0
  38. package/dist/host.js.map +1 -0
  39. package/dist/identity.d.ts +2 -0
  40. package/dist/identity.d.ts.map +1 -0
  41. package/dist/identity.js +16 -0
  42. package/dist/identity.js.map +1 -0
  43. package/dist/index.d.ts +10 -4
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js.map +1 -1
  46. package/dist/memory.d.ts +16 -2
  47. package/dist/memory.d.ts.map +1 -1
  48. package/dist/memory.js +196 -15
  49. package/dist/memory.js.map +1 -1
  50. package/dist/model.d.ts +70 -0
  51. package/dist/model.d.ts.map +1 -0
  52. package/dist/model.js +28 -0
  53. package/dist/model.js.map +1 -0
  54. package/dist/outcome.d.ts +16 -9
  55. package/dist/outcome.d.ts.map +1 -1
  56. package/dist/outcome.js +10 -0
  57. package/dist/outcome.js.map +1 -1
  58. package/dist/query.d.ts +13 -0
  59. package/dist/query.d.ts.map +1 -0
  60. package/dist/query.js +18 -0
  61. package/dist/query.js.map +1 -0
  62. package/dist/refresh.d.ts +2 -1
  63. package/dist/refresh.d.ts.map +1 -1
  64. package/dist/refresh.js +6 -4
  65. package/dist/refresh.js.map +1 -1
  66. package/dist/replica.d.ts +5 -2
  67. package/dist/replica.d.ts.map +1 -1
  68. package/dist/replica.js +23 -6
  69. package/dist/replica.js.map +1 -1
  70. package/dist/save.d.ts +6 -1
  71. package/dist/save.d.ts.map +1 -1
  72. package/dist/save.js +52 -11
  73. package/dist/save.js.map +1 -1
  74. package/dist/status.d.ts +11 -2
  75. package/dist/status.d.ts.map +1 -1
  76. package/dist/status.js +5 -4
  77. package/dist/status.js.map +1 -1
  78. package/dist/store.d.ts +38 -4
  79. package/dist/store.d.ts.map +1 -1
  80. package/dist/store.js +64 -7
  81. package/dist/store.js.map +1 -1
  82. package/dist/wire.d.ts +63 -0
  83. package/dist/wire.d.ts.map +1 -0
  84. package/dist/wire.js +139 -0
  85. package/dist/wire.js.map +1 -0
  86. package/package.json +10 -2
@@ -0,0 +1,401 @@
1
+ import { declaredFile } from './file.js';
2
+ const NO_TURNS = new Set();
3
+ function carriedMessage(value) {
4
+ if (typeof value !== 'object' || value === null) return null;
5
+ const record = value;
6
+ if (typeof record.turn !== 'string') return null;
7
+ return structuredClone(value);
8
+ }
9
+ function historyPage(result) {
10
+ if (result.kind !== 'action') return null;
11
+ const answer = result.result;
12
+ if (typeof answer !== 'object' || answer === null) return null;
13
+ const record = answer;
14
+ if (!Array.isArray(record.messages)) return null;
15
+ const messages = [];
16
+ for (const entry of record.messages){
17
+ const carried = carriedMessage(entry);
18
+ if (carried !== null) messages.push(carried);
19
+ }
20
+ return {
21
+ messages,
22
+ cursor: typeof record.cursor === 'string' ? record.cursor : null
23
+ };
24
+ }
25
+ function turnOf(result) {
26
+ if (result.kind !== 'action') return null;
27
+ const answer = result.result;
28
+ if (typeof answer !== 'object' || answer === null) return null;
29
+ const record = answer;
30
+ return typeof record.turn === 'string' ? record.turn : null;
31
+ }
32
+ function newest(held, page, arrived) {
33
+ const arriving = new Set(page.messages.map((entry)=>entry.turn));
34
+ const overlap = held.messages.findIndex((entry)=>arriving.has(entry.turn));
35
+ const carried = overlap === -1 ? [] : held.messages.slice(0, overlap);
36
+ const placed = new Set([
37
+ ...carried,
38
+ ...page.messages
39
+ ].map((entry)=>entry.turn));
40
+ const live = held.messages.filter((entry)=>arrived.has(entry.turn) && !placed.has(entry.turn));
41
+ return {
42
+ ...held,
43
+ messages: [
44
+ ...carried,
45
+ ...page.messages,
46
+ ...live
47
+ ],
48
+ cursor: overlap === -1 ? page.cursor : held.cursor
49
+ };
50
+ }
51
+ function older(held, page) {
52
+ const present = new Set(held.messages.map((entry)=>entry.turn));
53
+ return {
54
+ ...held,
55
+ messages: [
56
+ ...page.messages.filter((entry)=>!present.has(entry.turn)),
57
+ ...held.messages
58
+ ],
59
+ cursor: page.cursor
60
+ };
61
+ }
62
+ function sealed(held, arriving) {
63
+ const at = held.messages.findIndex((entry)=>entry.turn === arriving.turn);
64
+ if (at === -1) return {
65
+ ...held,
66
+ messages: [
67
+ ...held.messages,
68
+ arriving
69
+ ]
70
+ };
71
+ const messages = [
72
+ ...held.messages
73
+ ];
74
+ messages[at] = arriving;
75
+ return {
76
+ ...held,
77
+ messages
78
+ };
79
+ }
80
+ export function createConversationStore(deps) {
81
+ const held = new Map();
82
+ const composed = new Map();
83
+ const growing = new Map();
84
+ const viewers = new Set();
85
+ const issued = new Map();
86
+ const live = new Map();
87
+ let handed;
88
+ function heldOf(conversation) {
89
+ return held.get(conversation) ?? {
90
+ messages: [],
91
+ cursor: null,
92
+ summary: null
93
+ };
94
+ }
95
+ function instructionOf(conversation) {
96
+ return composed.get(conversation) ?? {
97
+ text: '',
98
+ files: [],
99
+ turn: null
100
+ };
101
+ }
102
+ function viewOf(conversation) {
103
+ const carried = heldOf(conversation);
104
+ const unsent = composed.get(conversation);
105
+ return {
106
+ conversation,
107
+ messages: structuredClone(carried.messages),
108
+ olderPages: carried.cursor !== null,
109
+ growingText: growing.get(conversation) ?? null,
110
+ summary: structuredClone(carried.summary),
111
+ instruction: unsent === undefined || unsent.turn !== null ? null : {
112
+ text: unsent.text,
113
+ files: [
114
+ ...unsent.files
115
+ ]
116
+ }
117
+ };
118
+ }
119
+ function emit(conversation) {
120
+ if (deps.closed()) return;
121
+ for (const viewer of viewers){
122
+ if (viewer.conversation === conversation && viewer.ready) viewer.notify(viewOf(conversation));
123
+ }
124
+ }
125
+ function viewed() {
126
+ return [
127
+ ...new Set([
128
+ ...viewers
129
+ ].map((viewer)=>viewer.conversation))
130
+ ].sort();
131
+ }
132
+ function hand() {
133
+ const path = deps.path();
134
+ if (path === undefined) return;
135
+ const open = viewed();
136
+ const named = JSON.stringify(open);
137
+ if (named === handed) return;
138
+ handed = named;
139
+ path.view(open);
140
+ }
141
+ function keptRecord(conversation) {
142
+ const carried = heldOf(conversation);
143
+ return {
144
+ conversation,
145
+ messages: carried.messages,
146
+ cursor: carried.cursor,
147
+ summary: carried.summary
148
+ };
149
+ }
150
+ async function settle(local, conversation) {
151
+ const sent = instructionOf(conversation).turn;
152
+ if (sent === null) return;
153
+ if (!heldOf(conversation).messages.some((entry)=>entry.turn === sent)) return;
154
+ composed.delete(conversation);
155
+ await local.dropInstruction(conversation);
156
+ }
157
+ async function keep(conversation, next) {
158
+ const kept = await deps.durably(async (local)=>{
159
+ const following = next(heldOf(conversation));
160
+ if (following === null) return false;
161
+ held.set(conversation, following);
162
+ await local.keepConversation(keptRecord(conversation));
163
+ await settle(local, conversation);
164
+ return true;
165
+ });
166
+ if (kept) emit(conversation);
167
+ return kept;
168
+ }
169
+ async function keepInstruction(conversation, next) {
170
+ await deps.durably(async (local)=>{
171
+ const stored = next(instructionOf(conversation));
172
+ composed.set(conversation, stored);
173
+ await local.keepInstruction({
174
+ conversation,
175
+ ...stored
176
+ });
177
+ await settle(local, conversation);
178
+ });
179
+ emit(conversation);
180
+ }
181
+ async function dropInstruction(conversation) {
182
+ await deps.durably(async (local)=>{
183
+ composed.delete(conversation);
184
+ await local.dropInstruction(conversation);
185
+ });
186
+ emit(conversation);
187
+ }
188
+ function supersede(conversation) {
189
+ issued.set(conversation, (issued.get(conversation) ?? 0) + 1);
190
+ }
191
+ async function fill(conversation, cursor) {
192
+ const generation = issued.get(conversation);
193
+ const result = await deps.call('conversation.history', {
194
+ conversation,
195
+ ...cursor === null ? {} : {
196
+ cursor
197
+ }
198
+ });
199
+ const page = historyPage(result);
200
+ if (page === null) return result;
201
+ const landed = await keep(conversation, (carried)=>{
202
+ if (issued.get(conversation) !== generation) return null;
203
+ if (cursor !== null) return carried.cursor === cursor ? older(carried, page) : null;
204
+ return newest(carried, page, live.get(conversation) ?? NO_TURNS);
205
+ });
206
+ if (landed && cursor === null) live.delete(conversation);
207
+ return result;
208
+ }
209
+ function invoke(name, conversation, extra = {}) {
210
+ return deps.call(name, {
211
+ conversation,
212
+ ...extra
213
+ });
214
+ }
215
+ const surface = {
216
+ list () {
217
+ const declaration = deps.cards();
218
+ if (declaration === undefined) return Promise.resolve([]);
219
+ const documents = deps.documents().documents.filter((document)=>document.room === declaration.locator);
220
+ const entries = [];
221
+ for (const card of documents){
222
+ if (card.type !== declaration.type) continue;
223
+ const identity = card.fields[declaration.identity];
224
+ if (typeof identity !== 'string') continue;
225
+ const agent = documents.find((document)=>document.backlinks.some((backlink)=>backlink.path === card.path && backlink.field === declaration.agent));
226
+ entries.push({
227
+ conversation: identity,
228
+ card,
229
+ agent: agent ?? null
230
+ });
231
+ }
232
+ entries.sort((left, right)=>left.conversation < right.conversation ? -1 : 1);
233
+ return Promise.resolve(entries);
234
+ },
235
+ read (conversation) {
236
+ return deps.durably(()=>Promise.resolve(viewOf(conversation)));
237
+ },
238
+ older (conversation) {
239
+ const cursor = heldOf(conversation).cursor;
240
+ if (cursor === null) return Promise.resolve(null);
241
+ return fill(conversation, cursor);
242
+ },
243
+ compose (conversation, supplied) {
244
+ return keepInstruction(conversation, ()=>({
245
+ text: supplied.text,
246
+ files: [
247
+ ...supplied.files
248
+ ],
249
+ turn: null
250
+ }));
251
+ },
252
+ discard (conversation) {
253
+ return dropInstruction(conversation);
254
+ },
255
+ create (input) {
256
+ return deps.call('conversation.create', input);
257
+ },
258
+ async send (conversation) {
259
+ const unsent = instructionOf(conversation);
260
+ const files = await Promise.all(unsent.files.map(declaredFile));
261
+ const result = await invoke('conversation.send', conversation, {
262
+ text: unsent.text,
263
+ files
264
+ });
265
+ const turn = turnOf(result);
266
+ if (turn === null) return result;
267
+ await keepInstruction(conversation, (stored)=>({
268
+ ...stored,
269
+ turn
270
+ }));
271
+ return result;
272
+ },
273
+ answer (conversation, answer) {
274
+ return invoke('conversation.answer', conversation, {
275
+ answer
276
+ });
277
+ },
278
+ interrupt (conversation) {
279
+ return invoke('conversation.interrupt', conversation);
280
+ },
281
+ kill (conversation) {
282
+ return invoke('conversation.kill', conversation);
283
+ },
284
+ async cancel (conversation, turn) {
285
+ const result = await invoke('conversation.cancel', conversation, {
286
+ turn
287
+ });
288
+ if (result.kind !== 'action') return result;
289
+ if (instructionOf(conversation).turn === turn) {
290
+ await keepInstruction(conversation, (stored)=>({
291
+ ...stored,
292
+ turn: null
293
+ }));
294
+ }
295
+ return result;
296
+ },
297
+ async delete (conversation) {
298
+ const result = await invoke('conversation.delete', conversation);
299
+ if (result.kind !== 'action') return result;
300
+ growing.delete(conversation);
301
+ live.delete(conversation);
302
+ supersede(conversation);
303
+ await deps.durably(async (local)=>{
304
+ held.delete(conversation);
305
+ composed.delete(conversation);
306
+ await local.dropConversation(conversation);
307
+ await local.dropInstruction(conversation);
308
+ });
309
+ emit(conversation);
310
+ return result;
311
+ }
312
+ };
313
+ return {
314
+ surface,
315
+ hydrate (conversations, instructions) {
316
+ held.clear();
317
+ for (const stored of conversations){
318
+ held.set(stored.conversation, {
319
+ messages: stored.messages,
320
+ cursor: stored.cursor,
321
+ summary: stored.summary
322
+ });
323
+ }
324
+ composed.clear();
325
+ for (const stored of instructions){
326
+ composed.set(stored.conversation, {
327
+ text: stored.text,
328
+ files: stored.files,
329
+ turn: stored.turn
330
+ });
331
+ }
332
+ },
333
+ observe (conversation, notify) {
334
+ const first = !viewed().includes(conversation);
335
+ const viewer = {
336
+ conversation,
337
+ notify,
338
+ ready: false
339
+ };
340
+ viewers.add(viewer);
341
+ if (first) {
342
+ live.set(conversation, new Set());
343
+ supersede(conversation);
344
+ }
345
+ hand();
346
+ void deps.durably(()=>Promise.resolve()).then(async ()=>{
347
+ if (deps.closed() || !viewers.has(viewer)) return;
348
+ viewer.ready = true;
349
+ viewer.notify(viewOf(conversation));
350
+ if (first) await fill(conversation, null);
351
+ }).catch(()=>{});
352
+ return ()=>{
353
+ if (!viewers.delete(viewer)) return;
354
+ if (!viewed().includes(conversation)) {
355
+ growing.delete(conversation);
356
+ live.delete(conversation);
357
+ }
358
+ hand();
359
+ };
360
+ },
361
+ receive (event) {
362
+ if (deps.closed() || !viewed().includes(event.conversation)) return;
363
+ if (event.kind === 'growing-text') {
364
+ growing.set(event.conversation, {
365
+ turn: event.turn,
366
+ text: event.text
367
+ });
368
+ emit(event.conversation);
369
+ return;
370
+ }
371
+ if (event.kind === 'session-summary') {
372
+ const summary = structuredClone(event.summary);
373
+ void keep(event.conversation, (carried)=>({
374
+ ...carried,
375
+ summary
376
+ })).catch(()=>{});
377
+ return;
378
+ }
379
+ const arriving = carriedMessage(event.message);
380
+ if (arriving === null) return;
381
+ live.get(event.conversation)?.add(arriving.turn);
382
+ if (growing.get(event.conversation)?.turn === arriving.turn) {
383
+ growing.delete(event.conversation);
384
+ }
385
+ void deps.durably(async (local)=>{
386
+ held.set(event.conversation, sealed(heldOf(event.conversation), arriving));
387
+ await local.keepConversation(keptRecord(event.conversation));
388
+ await settle(local, event.conversation);
389
+ }).then(()=>{
390
+ emit(event.conversation);
391
+ }).catch(()=>{});
392
+ },
393
+ close () {
394
+ viewers.clear();
395
+ growing.clear();
396
+ live.clear();
397
+ }
398
+ };
399
+ }
400
+
401
+ //# sourceMappingURL=conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/conversation.ts"],"sourcesContent":["import type { QueryDocument, QueryResult } from '@agentshouse/query';\nimport type {\n ConversationAction,\n ConversationCards,\n ConversationEvent,\n ConversationMessage,\n ViewedConversations,\n} from './adapter.js';\nimport { declaredFile, type InstructionFile } from './file.js';\nimport type { CallResult } from './outcome.js';\nimport type { ConversationRecord, InstructionRecord, RuntimeStore } from './store.js';\n\nexport type ConversationEntry = {\n conversation: string;\n card: QueryDocument;\n agent: QueryDocument | null;\n};\n\nexport type GrowingText = { turn: string; text: string };\n\nexport type UnsentInstruction = {\n text: string;\n files: readonly InstructionFile[];\n};\n\nexport type ConversationView = {\n conversation: string;\n messages: readonly ConversationMessage[];\n olderPages: boolean;\n growingText: GrowingText | null;\n summary: unknown;\n instruction: UnsentInstruction | null;\n};\n\nexport type ConversationSurface = {\n list(): Promise<readonly ConversationEntry[]>;\n read(conversation: string): Promise<ConversationView>;\n older(conversation: string): Promise<CallResult | null>;\n compose(conversation: string, instruction: UnsentInstruction): Promise<void>;\n discard(conversation: string): Promise<void>;\n create(input: unknown): Promise<CallResult>;\n send(conversation: string): Promise<CallResult>;\n answer(conversation: string, answer: unknown): Promise<CallResult>;\n interrupt(conversation: string): Promise<CallResult>;\n kill(conversation: string): Promise<CallResult>;\n cancel(conversation: string, turn: string): Promise<CallResult>;\n delete(conversation: string): Promise<CallResult>;\n};\n\nexport type ConversationDependencies = {\n cards(): ConversationCards | undefined;\n documents(): QueryResult;\n call(name: ConversationAction, input: unknown): Promise<CallResult>;\n durably<T>(work: (local: RuntimeStore) => Promise<T>): Promise<T>;\n path(): ViewedConversations | undefined;\n closed(): boolean;\n};\n\nexport type ConversationStore = {\n surface: ConversationSurface;\n hydrate(\n conversations: readonly ConversationRecord[],\n instructions: readonly InstructionRecord[],\n ): void;\n observe(conversation: string, notify: (view: ConversationView) => void): () => void;\n receive(event: ConversationEvent): void;\n close(): void;\n};\n\ntype Held = {\n messages: readonly ConversationMessage[];\n cursor: string | null;\n summary: unknown;\n};\n\ntype Composed = {\n text: string;\n files: readonly InstructionFile[];\n turn: string | null;\n};\n\ntype Viewing = {\n conversation: string;\n notify: (view: ConversationView) => void;\n ready: boolean;\n};\n\ntype HistoryPage = {\n messages: readonly ConversationMessage[];\n cursor: string | null;\n};\n\nconst NO_TURNS: ReadonlySet<string> = new Set();\n\nfunction carriedMessage(value: unknown): ConversationMessage | null {\n if (typeof value !== 'object' || value === null) return null;\n const record = value as { turn?: unknown };\n if (typeof record.turn !== 'string') return null;\n return structuredClone(value) as ConversationMessage;\n}\n\nfunction historyPage(result: CallResult): HistoryPage | null {\n if (result.kind !== 'action') return null;\n const answer = result.result;\n if (typeof answer !== 'object' || answer === null) return null;\n const record = answer as { messages?: unknown; cursor?: unknown };\n if (!Array.isArray(record.messages)) return null;\n const messages: ConversationMessage[] = [];\n for (const entry of record.messages) {\n const carried = carriedMessage(entry);\n if (carried !== null) messages.push(carried);\n }\n return { messages, cursor: typeof record.cursor === 'string' ? record.cursor : null };\n}\n\nfunction turnOf(result: CallResult): string | null {\n if (result.kind !== 'action') return null;\n const answer = result.result;\n if (typeof answer !== 'object' || answer === null) return null;\n const record = answer as { turn?: unknown };\n return typeof record.turn === 'string' ? record.turn : null;\n}\n\nfunction newest(held: Held, page: HistoryPage, arrived: ReadonlySet<string>): Held {\n const arriving = new Set(page.messages.map((entry) => entry.turn));\n const overlap = held.messages.findIndex((entry) => arriving.has(entry.turn));\n const carried = overlap === -1 ? [] : held.messages.slice(0, overlap);\n const placed = new Set([...carried, ...page.messages].map((entry) => entry.turn));\n const live = held.messages.filter((entry) => arrived.has(entry.turn) && !placed.has(entry.turn));\n return {\n ...held,\n messages: [...carried, ...page.messages, ...live],\n cursor: overlap === -1 ? page.cursor : held.cursor,\n };\n}\n\nfunction older(held: Held, page: HistoryPage): Held {\n const present = new Set(held.messages.map((entry) => entry.turn));\n return {\n ...held,\n messages: [...page.messages.filter((entry) => !present.has(entry.turn)), ...held.messages],\n cursor: page.cursor,\n };\n}\n\nfunction sealed(held: Held, arriving: ConversationMessage): Held {\n const at = held.messages.findIndex((entry) => entry.turn === arriving.turn);\n if (at === -1) return { ...held, messages: [...held.messages, arriving] };\n const messages = [...held.messages];\n messages[at] = arriving;\n return { ...held, messages };\n}\n\nexport function createConversationStore(deps: ConversationDependencies): ConversationStore {\n const held = new Map<string, Held>();\n const composed = new Map<string, Composed>();\n const growing = new Map<string, GrowingText>();\n const viewers = new Set<Viewing>();\n const issued = new Map<string, number>();\n const live = new Map<string, Set<string>>();\n let handed: string | undefined;\n\n function heldOf(conversation: string): Held {\n return held.get(conversation) ?? { messages: [], cursor: null, summary: null };\n }\n\n function instructionOf(conversation: string): Composed {\n return composed.get(conversation) ?? { text: '', files: [], turn: null };\n }\n\n function viewOf(conversation: string): ConversationView {\n const carried = heldOf(conversation);\n const unsent = composed.get(conversation);\n return {\n conversation,\n messages: structuredClone(carried.messages),\n olderPages: carried.cursor !== null,\n growingText: growing.get(conversation) ?? null,\n summary: structuredClone(carried.summary),\n instruction:\n unsent === undefined || unsent.turn !== null\n ? null\n : { text: unsent.text, files: [...unsent.files] },\n };\n }\n\n function emit(conversation: string) {\n if (deps.closed()) return;\n for (const viewer of viewers) {\n if (viewer.conversation === conversation && viewer.ready) viewer.notify(viewOf(conversation));\n }\n }\n\n function viewed(): readonly string[] {\n return [...new Set([...viewers].map((viewer) => viewer.conversation))].sort();\n }\n\n function hand() {\n const path = deps.path();\n if (path === undefined) return;\n const open = viewed();\n const named = JSON.stringify(open);\n if (named === handed) return;\n handed = named;\n path.view(open);\n }\n\n function keptRecord(conversation: string): ConversationRecord {\n const carried = heldOf(conversation);\n return {\n conversation,\n messages: carried.messages,\n cursor: carried.cursor,\n summary: carried.summary,\n };\n }\n\n async function settle(local: RuntimeStore, conversation: string) {\n const sent = instructionOf(conversation).turn;\n if (sent === null) return;\n if (!heldOf(conversation).messages.some((entry) => entry.turn === sent)) return;\n composed.delete(conversation);\n await local.dropInstruction(conversation);\n }\n\n async function keep(\n conversation: string,\n next: (carried: Held) => Held | null,\n ): Promise<boolean> {\n const kept = await deps.durably(async (local) => {\n const following = next(heldOf(conversation));\n if (following === null) return false;\n held.set(conversation, following);\n await local.keepConversation(keptRecord(conversation));\n await settle(local, conversation);\n return true;\n });\n if (kept) emit(conversation);\n return kept;\n }\n\n async function keepInstruction(conversation: string, next: (unsent: Composed) => Composed) {\n await deps.durably(async (local) => {\n const stored = next(instructionOf(conversation));\n composed.set(conversation, stored);\n await local.keepInstruction({ conversation, ...stored });\n await settle(local, conversation);\n });\n emit(conversation);\n }\n\n async function dropInstruction(conversation: string) {\n await deps.durably(async (local) => {\n composed.delete(conversation);\n await local.dropInstruction(conversation);\n });\n emit(conversation);\n }\n\n function supersede(conversation: string) {\n issued.set(conversation, (issued.get(conversation) ?? 0) + 1);\n }\n\n async function fill(conversation: string, cursor: string | null): Promise<CallResult> {\n const generation = issued.get(conversation);\n const result = await deps.call('conversation.history', {\n conversation,\n ...(cursor === null ? {} : { cursor }),\n });\n const page = historyPage(result);\n if (page === null) return result;\n const landed = await keep(conversation, (carried) => {\n if (issued.get(conversation) !== generation) return null;\n if (cursor !== null) return carried.cursor === cursor ? older(carried, page) : null;\n return newest(carried, page, live.get(conversation) ?? NO_TURNS);\n });\n if (landed && cursor === null) live.delete(conversation);\n return result;\n }\n\n function invoke(\n name: ConversationAction,\n conversation: string,\n extra: Readonly<Record<string, unknown>> = {},\n ): Promise<CallResult> {\n return deps.call(name, { conversation, ...extra });\n }\n\n const surface: ConversationSurface = {\n list() {\n const declaration = deps.cards();\n if (declaration === undefined) return Promise.resolve([]);\n const documents = deps\n .documents()\n .documents.filter((document) => document.room === declaration.locator);\n const entries: ConversationEntry[] = [];\n for (const card of documents) {\n if (card.type !== declaration.type) continue;\n const identity = card.fields[declaration.identity];\n if (typeof identity !== 'string') continue;\n const agent = documents.find((document) =>\n document.backlinks.some(\n (backlink) => backlink.path === card.path && backlink.field === declaration.agent,\n ),\n );\n entries.push({ conversation: identity, card, agent: agent ?? null });\n }\n entries.sort((left, right) => (left.conversation < right.conversation ? -1 : 1));\n return Promise.resolve(entries);\n },\n read(conversation: string) {\n return deps.durably(() => Promise.resolve(viewOf(conversation)));\n },\n older(conversation: string) {\n const cursor = heldOf(conversation).cursor;\n if (cursor === null) return Promise.resolve(null);\n return fill(conversation, cursor);\n },\n compose(conversation: string, supplied: UnsentInstruction) {\n return keepInstruction(conversation, () => ({\n text: supplied.text,\n files: [...supplied.files],\n turn: null,\n }));\n },\n discard(conversation: string) {\n return dropInstruction(conversation);\n },\n create(input: unknown) {\n return deps.call('conversation.create', input);\n },\n async send(conversation: string) {\n const unsent = instructionOf(conversation);\n const files = await Promise.all(unsent.files.map(declaredFile));\n const result = await invoke('conversation.send', conversation, { text: unsent.text, files });\n const turn = turnOf(result);\n if (turn === null) return result;\n await keepInstruction(conversation, (stored) => ({ ...stored, turn }));\n return result;\n },\n answer(conversation: string, answer: unknown) {\n return invoke('conversation.answer', conversation, { answer });\n },\n interrupt(conversation: string) {\n return invoke('conversation.interrupt', conversation);\n },\n kill(conversation: string) {\n return invoke('conversation.kill', conversation);\n },\n async cancel(conversation: string, turn: string) {\n const result = await invoke('conversation.cancel', conversation, { turn });\n if (result.kind !== 'action') return result;\n if (instructionOf(conversation).turn === turn) {\n await keepInstruction(conversation, (stored) => ({ ...stored, turn: null }));\n }\n return result;\n },\n async delete(conversation: string) {\n const result = await invoke('conversation.delete', conversation);\n if (result.kind !== 'action') return result;\n growing.delete(conversation);\n live.delete(conversation);\n supersede(conversation);\n await deps.durably(async (local) => {\n held.delete(conversation);\n composed.delete(conversation);\n await local.dropConversation(conversation);\n await local.dropInstruction(conversation);\n });\n emit(conversation);\n return result;\n },\n };\n\n return {\n surface,\n hydrate(conversations, instructions) {\n held.clear();\n for (const stored of conversations) {\n held.set(stored.conversation, {\n messages: stored.messages,\n cursor: stored.cursor,\n summary: stored.summary,\n });\n }\n composed.clear();\n for (const stored of instructions) {\n composed.set(stored.conversation, {\n text: stored.text,\n files: stored.files,\n turn: stored.turn,\n });\n }\n },\n observe(conversation: string, notify: (view: ConversationView) => void) {\n const first = !viewed().includes(conversation);\n const viewer: Viewing = { conversation, notify, ready: false };\n viewers.add(viewer);\n if (first) {\n live.set(conversation, new Set());\n supersede(conversation);\n }\n hand();\n void deps\n .durably(() => Promise.resolve())\n .then(async () => {\n if (deps.closed() || !viewers.has(viewer)) return;\n viewer.ready = true;\n viewer.notify(viewOf(conversation));\n if (first) await fill(conversation, null);\n })\n .catch(() => {});\n return () => {\n if (!viewers.delete(viewer)) return;\n if (!viewed().includes(conversation)) {\n growing.delete(conversation);\n live.delete(conversation);\n }\n hand();\n };\n },\n receive(event: ConversationEvent) {\n if (deps.closed() || !viewed().includes(event.conversation)) return;\n if (event.kind === 'growing-text') {\n growing.set(event.conversation, { turn: event.turn, text: event.text });\n emit(event.conversation);\n return;\n }\n if (event.kind === 'session-summary') {\n const summary = structuredClone(event.summary);\n void keep(event.conversation, (carried) => ({ ...carried, summary })).catch(() => {});\n return;\n }\n const arriving = carriedMessage(event.message);\n if (arriving === null) return;\n live.get(event.conversation)?.add(arriving.turn);\n if (growing.get(event.conversation)?.turn === arriving.turn) {\n growing.delete(event.conversation);\n }\n void deps\n .durably(async (local) => {\n held.set(event.conversation, sealed(heldOf(event.conversation), arriving));\n await local.keepConversation(keptRecord(event.conversation));\n await settle(local, event.conversation);\n })\n .then(() => {\n emit(event.conversation);\n })\n .catch(() => {});\n },\n close() {\n viewers.clear();\n growing.clear();\n live.clear();\n },\n };\n}\n"],"names":["declaredFile","NO_TURNS","Set","carriedMessage","value","record","turn","structuredClone","historyPage","result","kind","answer","Array","isArray","messages","entry","carried","push","cursor","turnOf","newest","held","page","arrived","arriving","map","overlap","findIndex","has","slice","placed","live","filter","older","present","sealed","at","createConversationStore","deps","Map","composed","growing","viewers","issued","handed","heldOf","conversation","get","summary","instructionOf","text","files","viewOf","unsent","olderPages","growingText","instruction","undefined","emit","closed","viewer","ready","notify","viewed","sort","hand","path","open","named","JSON","stringify","view","keptRecord","settle","local","sent","some","delete","dropInstruction","keep","next","kept","durably","following","set","keepConversation","keepInstruction","stored","supersede","fill","generation","call","landed","invoke","name","extra","surface","list","declaration","cards","Promise","resolve","documents","document","room","locator","entries","card","type","identity","fields","agent","find","backlinks","backlink","field","left","right","read","compose","supplied","discard","create","input","send","all","interrupt","kill","cancel","dropConversation","hydrate","conversations","instructions","clear","observe","first","includes","add","then","catch","receive","event","message","close"],"mappings":"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"}
@@ -1,4 +1,9 @@
1
- export declare function requestPersistentStorage(): Promise<void>;
2
- export declare function detectStorageLoss(stored: string | null): string | null;
3
- export declare function nextGeneration(stored: string | null): string;
1
+ export type RuntimeShell = {
2
+ persistentStorage: boolean;
3
+ generation: string | null;
4
+ keepGeneration(value: string): void | Promise<void>;
5
+ dropGeneration(): void | Promise<void>;
6
+ };
7
+ export declare function detectStorageLoss(stored: string | null, reported: string | null): string | null;
8
+ export declare function nextGeneration(stored: string | null, reported: string | null): string;
4
9
  //# sourceMappingURL=durability.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"durability.d.ts","sourceRoot":"","sources":["../src/durability.ts"],"names":[],"mappings":"AAiCA,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG9D;AAoBD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAItE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAS5D"}
1
+ {"version":3,"file":"durability.d.ts","sourceRoot":"","sources":["../src/durability.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IACzB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,cAAc,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAG/F;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAGrF"}
@@ -1,65 +1,11 @@
1
- const ASKED = 'mdruntime:persistent-storage';
2
- const GENERATION = 'mdruntime:generation';
3
1
  const STORAGE_LOSS_STATEMENT = 'Unsynchronized Drafts and Pending Changes were lost.';
4
- function remembered() {
5
- try {
6
- return window.localStorage.getItem(ASKED);
7
- } catch {
8
- return null;
9
- }
10
- }
11
- function remember() {
12
- try {
13
- window.localStorage.setItem(ASKED, '1');
14
- } catch {
15
- return;
16
- }
17
- }
18
- async function ask() {
19
- if (remembered() !== null) return;
20
- const persist = window.navigator.storage?.persist;
21
- if (typeof persist !== 'function') return;
22
- remember();
23
- try {
24
- await persist.call(window.navigator.storage);
25
- } catch {
26
- return;
27
- }
28
- }
29
- export async function requestPersistentStorage() {
30
- if (typeof window === 'undefined') return;
31
- await window.navigator.locks.request('mdruntime-persist', ask);
32
- }
33
- function readGeneration() {
34
- if (typeof window === 'undefined') return null;
35
- try {
36
- return window.localStorage.getItem(GENERATION);
37
- } catch {
38
- return null;
39
- }
40
- }
41
- function writeGeneration(value) {
42
- if (typeof window === 'undefined') return;
43
- try {
44
- window.localStorage.setItem(GENERATION, value);
45
- } catch {
46
- return;
47
- }
48
- }
49
- export function detectStorageLoss(stored) {
50
- const remembered = readGeneration();
51
- if (remembered === null || remembered === stored) return null;
2
+ export function detectStorageLoss(stored, reported) {
3
+ if (reported === null || reported === stored) return null;
52
4
  return STORAGE_LOSS_STATEMENT;
53
5
  }
54
- export function nextGeneration(stored) {
55
- const remembered = readGeneration();
56
- if (stored !== null && (remembered === null || remembered === stored)) {
57
- writeGeneration(stored);
58
- return stored;
59
- }
60
- const next = crypto.randomUUID();
61
- writeGeneration(next);
62
- return next;
6
+ export function nextGeneration(stored, reported) {
7
+ if (stored !== null && (reported === null || reported === stored)) return stored;
8
+ return crypto.randomUUID();
63
9
  }
64
10
 
65
11
  //# sourceMappingURL=durability.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdruntime/src/durability.ts"],"sourcesContent":["const ASKED = 'mdruntime:persistent-storage';\nconst GENERATION = 'mdruntime:generation';\n\nconst STORAGE_LOSS_STATEMENT = 'Unsynchronized Drafts and Pending Changes were lost.';\n\nfunction remembered(): string | null {\n try {\n return window.localStorage.getItem(ASKED);\n } catch {\n return null;\n }\n}\n\nfunction remember(): void {\n try {\n window.localStorage.setItem(ASKED, '1');\n } catch {\n return;\n }\n}\n\nasync function ask(): Promise<void> {\n if (remembered() !== null) return;\n const persist = window.navigator.storage?.persist;\n if (typeof persist !== 'function') return;\n remember();\n try {\n await persist.call(window.navigator.storage);\n } catch {\n return;\n }\n}\n\nexport async function requestPersistentStorage(): Promise<void> {\n if (typeof window === 'undefined') return;\n await window.navigator.locks.request('mdruntime-persist', ask);\n}\n\nfunction readGeneration(): string | null {\n if (typeof window === 'undefined') return null;\n try {\n return window.localStorage.getItem(GENERATION);\n } catch {\n return null;\n }\n}\n\nfunction writeGeneration(value: string): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(GENERATION, value);\n } catch {\n return;\n }\n}\n\nexport function detectStorageLoss(stored: string | null): string | null {\n const remembered = readGeneration();\n if (remembered === null || remembered === stored) return null;\n return STORAGE_LOSS_STATEMENT;\n}\n\nexport function nextGeneration(stored: string | null): string {\n const remembered = readGeneration();\n if (stored !== null && (remembered === null || remembered === stored)) {\n writeGeneration(stored);\n return stored;\n }\n const next = crypto.randomUUID();\n writeGeneration(next);\n return next;\n}\n"],"names":["ASKED","GENERATION","STORAGE_LOSS_STATEMENT","remembered","window","localStorage","getItem","remember","setItem","ask","persist","navigator","storage","call","requestPersistentStorage","locks","request","readGeneration","writeGeneration","value","detectStorageLoss","stored","nextGeneration","next","crypto","randomUUID"],"mappings":"AAAA,MAAMA,QAAQ;AACd,MAAMC,aAAa;AAEnB,MAAMC,yBAAyB;AAE/B,SAASC;IACP,IAAI;QACF,OAAOC,OAAOC,YAAY,CAACC,OAAO,CAACN;IACrC,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAASO;IACP,IAAI;QACFH,OAAOC,YAAY,CAACG,OAAO,CAACR,OAAO;IACrC,EAAE,OAAM;QACN;IACF;AACF;AAEA,eAAeS;IACb,IAAIN,iBAAiB,MAAM;IAC3B,MAAMO,UAAUN,OAAOO,SAAS,CAACC,OAAO,EAAEF;IAC1C,IAAI,OAAOA,YAAY,YAAY;IACnCH;IACA,IAAI;QACF,MAAMG,QAAQG,IAAI,CAACT,OAAOO,SAAS,CAACC,OAAO;IAC7C,EAAE,OAAM;QACN;IACF;AACF;AAEA,OAAO,eAAeE;IACpB,IAAI,OAAOV,WAAW,aAAa;IACnC,MAAMA,OAAOO,SAAS,CAACI,KAAK,CAACC,OAAO,CAAC,qBAAqBP;AAC5D;AAEA,SAASQ;IACP,IAAI,OAAOb,WAAW,aAAa,OAAO;IAC1C,IAAI;QACF,OAAOA,OAAOC,YAAY,CAACC,OAAO,CAACL;IACrC,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAASiB,gBAAgBC,KAAa;IACpC,IAAI,OAAOf,WAAW,aAAa;IACnC,IAAI;QACFA,OAAOC,YAAY,CAACG,OAAO,CAACP,YAAYkB;IAC1C,EAAE,OAAM;QACN;IACF;AACF;AAEA,OAAO,SAASC,kBAAkBC,MAAqB;IACrD,MAAMlB,aAAac;IACnB,IAAId,eAAe,QAAQA,eAAekB,QAAQ,OAAO;IACzD,OAAOnB;AACT;AAEA,OAAO,SAASoB,eAAeD,MAAqB;IAClD,MAAMlB,aAAac;IACnB,IAAII,WAAW,QAASlB,CAAAA,eAAe,QAAQA,eAAekB,MAAK,GAAI;QACrEH,gBAAgBG;QAChB,OAAOA;IACT;IACA,MAAME,OAAOC,OAAOC,UAAU;IAC9BP,gBAAgBK;IAChB,OAAOA;AACT"}
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/durability.ts"],"sourcesContent":["const STORAGE_LOSS_STATEMENT = 'Unsynchronized Drafts and Pending Changes were lost.';\n\nexport type RuntimeShell = {\n persistentStorage: boolean;\n generation: string | null;\n keepGeneration(value: string): void | Promise<void>;\n dropGeneration(): void | Promise<void>;\n};\n\nexport function detectStorageLoss(stored: string | null, reported: string | null): string | null {\n if (reported === null || reported === stored) return null;\n return STORAGE_LOSS_STATEMENT;\n}\n\nexport function nextGeneration(stored: string | null, reported: string | null): string {\n if (stored !== null && (reported === null || reported === stored)) return stored;\n return crypto.randomUUID();\n}\n"],"names":["STORAGE_LOSS_STATEMENT","detectStorageLoss","stored","reported","nextGeneration","crypto","randomUUID"],"mappings":"AAAA,MAAMA,yBAAyB;AAS/B,OAAO,SAASC,kBAAkBC,MAAqB,EAAEC,QAAuB;IAC9E,IAAIA,aAAa,QAAQA,aAAaD,QAAQ,OAAO;IACrD,OAAOF;AACT;AAEA,OAAO,SAASI,eAAeF,MAAqB,EAAEC,QAAuB;IAC3E,IAAID,WAAW,QAASC,CAAAA,aAAa,QAAQA,aAAaD,MAAK,GAAI,OAAOA;IAC1E,OAAOG,OAAOC,UAAU;AAC1B"}
package/dist/file.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ export type InstructionFile = {
2
+ name: string;
3
+ blob: Blob;
4
+ };
5
+ export type FileDeclaration = {
6
+ name: string;
7
+ mediaType: string;
8
+ byteLength: number;
9
+ contentHash: string;
10
+ width?: number;
11
+ height?: number;
12
+ };
13
+ export type Extent = {
14
+ width: number;
15
+ height: number;
16
+ };
17
+ export declare function extentOf(bytes: Uint8Array): Extent | null;
18
+ export declare function hexDigest(digest: ArrayBuffer): string;
19
+ export declare function declaredFile(file: InstructionFile): Promise<FileDeclaration>;
20
+ //# sourceMappingURL=file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA2GvD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAQzD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAErD;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAUlF"}