@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.
- package/dist/adapter.d.ts +107 -16
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/bootstrap.d.ts +6 -1
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +14 -6
- package/dist/bootstrap.js.map +1 -1
- package/dist/change.d.ts +1 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js.map +1 -1
- package/dist/client.d.ts +63 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +227 -0
- package/dist/client.js.map +1 -0
- package/dist/collection.d.ts +19 -4
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +88 -25
- package/dist/collection.js.map +1 -1
- package/dist/connection.d.ts +37 -9
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +818 -274
- package/dist/connection.js.map +1 -1
- package/dist/conversation.d.ts +57 -0
- package/dist/conversation.d.ts.map +1 -0
- package/dist/conversation.js +401 -0
- package/dist/conversation.js.map +1 -0
- package/dist/durability.d.ts +8 -3
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +5 -59
- package/dist/durability.js.map +1 -1
- package/dist/file.d.ts +20 -0
- package/dist/file.d.ts.map +1 -0
- package/dist/file.js +149 -0
- package/dist/file.js.map +1 -0
- package/dist/host.d.ts +9 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +200 -0
- package/dist/host.js.map +1 -0
- package/dist/identity.d.ts +2 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +16 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +16 -2
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +196 -15
- package/dist/memory.js.map +1 -1
- package/dist/model.d.ts +70 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +28 -0
- package/dist/model.js.map +1 -0
- package/dist/outcome.d.ts +16 -9
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +10 -0
- package/dist/outcome.js.map +1 -1
- package/dist/query.d.ts +13 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +18 -0
- package/dist/query.js.map +1 -0
- package/dist/refresh.d.ts +2 -1
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +6 -4
- package/dist/refresh.js.map +1 -1
- package/dist/replica.d.ts +5 -2
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +23 -6
- package/dist/replica.js.map +1 -1
- package/dist/save.d.ts +6 -1
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +52 -11
- package/dist/save.js.map +1 -1
- package/dist/status.d.ts +11 -2
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +5 -4
- package/dist/status.js.map +1 -1
- package/dist/store.d.ts +38 -4
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +64 -7
- package/dist/store.js.map +1 -1
- package/dist/wire.d.ts +63 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +139 -0
- package/dist/wire.js.map +1 -0
- 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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"}
|
package/dist/durability.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
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
|
package/dist/durability.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"durability.d.ts","sourceRoot":"","sources":["../src/durability.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/durability.js
CHANGED
|
@@ -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
|
|
5
|
-
|
|
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
|
-
|
|
56
|
-
|
|
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
|
package/dist/durability.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/workspace/packages/mdruntime/src/durability.ts"],"sourcesContent":["const
|
|
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"}
|