@agentshouse/mdruntime 0.1.0-c5d3fa6fb67bc → 0.1.0-c5f333dfa0583
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/AGENTS.md +225 -212
- package/README.md +9 -8
- package/dist/adapter.d.ts +64 -24
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +4 -1
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +13 -3
- package/dist/bootstrap.d.ts +15 -7
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +90 -61
- package/dist/chain.d.ts +11 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +64 -0
- package/dist/change-set.d.ts +8 -9
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +10 -85
- package/dist/change.d.ts +31 -1
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +10 -1
- package/dist/chat/earlier.d.ts +10 -0
- package/dist/chat/earlier.d.ts.map +1 -0
- package/dist/chat/earlier.js +54 -0
- package/dist/chat/house.d.ts +25 -0
- package/dist/chat/house.d.ts.map +1 -0
- package/dist/chat/house.js +38 -0
- package/dist/chat/input.d.ts +3 -1
- package/dist/chat/input.d.ts.map +1 -1
- package/dist/chat/input.js +11 -18
- package/dist/chat/kit.js +1 -1
- package/dist/chat/list.d.ts +2 -1
- package/dist/chat/list.d.ts.map +1 -1
- package/dist/chat/list.js +45 -5
- package/dist/chat/markdown.d.ts +1 -0
- package/dist/chat/markdown.d.ts.map +1 -1
- package/dist/chat/markdown.js +78 -20
- package/dist/chat/message.d.ts +1 -0
- package/dist/chat/message.d.ts.map +1 -1
- package/dist/chat/message.js +73 -11
- package/dist/chat/messages.d.ts +14 -1
- package/dist/chat/messages.d.ts.map +1 -1
- package/dist/chat/messages.js +79 -24
- package/dist/chat/name.d.ts +1 -0
- package/dist/chat/name.d.ts.map +1 -1
- package/dist/chat/name.js +1 -1
- package/dist/chat/opened.d.ts +1 -0
- package/dist/chat/opened.d.ts.map +1 -1
- package/dist/chat/opened.js +2 -0
- package/dist/chat/overlay.d.ts +1 -0
- package/dist/chat/overlay.d.ts.map +1 -1
- package/dist/chat/overlay.js +11 -5
- package/dist/chat/parts.d.ts +1 -0
- package/dist/chat/parts.d.ts.map +1 -1
- package/dist/chat/parts.js +3 -2
- package/dist/chat/pieces.d.ts +62 -0
- package/dist/chat/pieces.d.ts.map +1 -0
- package/dist/chat/pieces.js +1110 -0
- package/dist/chat/provider.d.ts +8 -1
- package/dist/chat/provider.d.ts.map +1 -1
- package/dist/chat/provider.js +98 -92
- package/dist/chat/question.d.ts +1 -1
- package/dist/chat/question.d.ts.map +1 -1
- package/dist/chat/question.js +7 -18
- package/dist/chat/ready.d.ts +5 -2
- package/dist/chat/ready.d.ts.map +1 -1
- package/dist/chat/ready.js +7 -5
- package/dist/chat/room-file.d.ts +8 -0
- package/dist/chat/room-file.d.ts.map +1 -0
- package/dist/chat/room-file.js +72 -0
- package/dist/chat/steady.d.ts +3 -0
- package/dist/chat/steady.d.ts.map +1 -0
- package/dist/chat/steady.js +26 -0
- package/dist/chat/style.d.ts.map +1 -1
- package/dist/chat/style.js +6 -1
- package/dist/chat.d.ts +3 -2
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +2 -2
- package/dist/client.d.ts +11 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +45 -7
- package/dist/collection.d.ts +6 -19
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +30 -287
- package/dist/compile.d.ts +11 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +712 -0
- package/dist/connection.d.ts +21 -8
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +2319 -688
- package/dist/conversation.d.ts +15 -3
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +233 -80
- package/dist/digest.d.ts +7 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +113 -0
- package/dist/durability.d.ts +2 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +3 -1
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +18 -23
- package/dist/file.d.ts +2 -10
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +3 -120
- package/dist/host.d.ts +5 -4
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +55 -7
- package/dist/index.d.ts +10 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/live.d.ts +22 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +123 -0
- package/dist/memory.d.ts +7 -3
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +39 -17
- package/dist/name.d.ts +4 -0
- package/dist/name.d.ts.map +1 -0
- package/dist/name.js +122 -0
- package/dist/observation.d.ts +14 -0
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +93 -3
- package/dist/opened.d.ts +22 -0
- package/dist/opened.d.ts.map +1 -0
- package/dist/opened.js +107 -0
- package/dist/outcome.d.ts +35 -4
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +28 -0
- package/dist/overlay.d.ts +2 -5
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +86 -171
- package/dist/query.d.ts +26 -2
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +34 -6
- package/dist/reach.d.ts +5 -1
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +167 -48
- package/dist/react.d.ts +3 -3
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +7 -17
- package/dist/readiness.d.ts +1 -1
- package/dist/readiness.d.ts.map +1 -1
- package/dist/reads.d.ts +11 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +98 -0
- package/dist/recovery.d.ts +2 -2
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +8 -7
- package/dist/refresh.d.ts +12 -15
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +74 -51
- package/dist/replica.d.ts +55 -33
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +295 -186
- package/dist/room-draft.d.ts +15 -1
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +32 -25
- package/dist/rows.d.ts +29 -30
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +113 -64
- package/dist/save.d.ts +51 -14
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +518 -180
- package/dist/search.d.ts +19 -4
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +192 -35
- package/dist/seed.d.ts +16 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +75 -0
- package/dist/shared.d.ts +8 -3
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +129 -66
- package/dist/store.d.ts +99 -71
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +461 -586
- package/dist/stored.d.ts +143 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +561 -0
- package/dist/tables.d.ts +320 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +537 -0
- package/dist/turn.d.ts +5 -3
- package/dist/turn.d.ts.map +1 -1
- package/dist/turn.js +51 -21
- package/dist/validation.d.ts +30 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +162 -0
- package/dist/windows.d.ts +22 -0
- package/dist/windows.d.ts.map +1 -0
- package/dist/windows.js +89 -0
- package/dist/wire.d.ts +32 -0
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +8 -0
- package/package.json +10 -3
- package/dist/acquisition.d.ts +0 -14
- package/dist/acquisition.d.ts.map +0 -1
- package/dist/acquisition.js +0 -24
- package/dist/read-side.d.ts +0 -25
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -642
package/dist/conversation.js
CHANGED
|
@@ -3,13 +3,26 @@ import { runtimeError } from './failure.js';
|
|
|
3
3
|
import { declaredFile } from './file.js';
|
|
4
4
|
import { changeBatchIdentity, chatDraftRevision } from './identity.js';
|
|
5
5
|
import { OFFLINE } from './outcome.js';
|
|
6
|
+
import { capped, cursorOf, decodedCursor, FROM_START, messageOrder, precedes } from './windows.js';
|
|
6
7
|
const QUIET = {
|
|
7
8
|
turn: null,
|
|
8
9
|
questions: [],
|
|
9
10
|
process: null,
|
|
10
11
|
commands: [],
|
|
11
12
|
options: [],
|
|
13
|
+
starting: null,
|
|
14
|
+
link: null,
|
|
15
|
+
deliveryUnknown: [],
|
|
12
16
|
};
|
|
17
|
+
const FACTS = [
|
|
18
|
+
'questions',
|
|
19
|
+
'process',
|
|
20
|
+
'commands',
|
|
21
|
+
'options',
|
|
22
|
+
'starting',
|
|
23
|
+
'link',
|
|
24
|
+
'deliveryUnknown',
|
|
25
|
+
];
|
|
13
26
|
export function unheldView(conversation) {
|
|
14
27
|
return {
|
|
15
28
|
conversation,
|
|
@@ -19,6 +32,9 @@ export function unheldView(conversation) {
|
|
|
19
32
|
process: null,
|
|
20
33
|
commands: [],
|
|
21
34
|
options: [],
|
|
35
|
+
starting: null,
|
|
36
|
+
link: null,
|
|
37
|
+
deliveryUnknown: [],
|
|
22
38
|
chatDraft: null,
|
|
23
39
|
};
|
|
24
40
|
}
|
|
@@ -30,8 +46,10 @@ export function newChat(agent) {
|
|
|
30
46
|
function creationOf(input) {
|
|
31
47
|
if (typeof input !== 'object' || input === null)
|
|
32
48
|
return null;
|
|
33
|
-
const { agent_id: agent, operation_id: operation } = input;
|
|
34
|
-
return typeof agent === 'string' && typeof operation === 'string'
|
|
49
|
+
const { agent_id: agent, operation_id: operation, replaces, } = input;
|
|
50
|
+
return typeof agent === 'string' && typeof operation === 'string' && replaces === undefined
|
|
51
|
+
? { agent, operation }
|
|
52
|
+
: null;
|
|
35
53
|
}
|
|
36
54
|
function startedTurn(turn, operation) {
|
|
37
55
|
if (operation.op === 'begin')
|
|
@@ -82,19 +100,25 @@ function appliedTurn(held, operation) {
|
|
|
82
100
|
parts: held.parts.map((kept, at) => (at === operation.index ? changed : kept)),
|
|
83
101
|
};
|
|
84
102
|
}
|
|
85
|
-
function ordered(left, right) {
|
|
86
|
-
if (left.position !== right.position)
|
|
87
|
-
return left.position < right.position ? -1 : 1;
|
|
88
|
-
if (left.identity !== right.identity)
|
|
89
|
-
return left.identity < right.identity ? -1 : 1;
|
|
90
|
-
return 0;
|
|
91
|
-
}
|
|
92
103
|
function windowOf(held, arriving, limit) {
|
|
93
104
|
const byIdentity = new Map(held.map((message) => [message.identity, message]));
|
|
94
105
|
for (const message of arriving)
|
|
95
106
|
byIdentity.set(message.identity, message);
|
|
96
|
-
const next = [...byIdentity.values()].sort(
|
|
97
|
-
|
|
107
|
+
const next = [...byIdentity.values()].sort(messageOrder);
|
|
108
|
+
const start = Math.max(0, next.length - limit);
|
|
109
|
+
return { messages: next.slice(start), dropped: start > 0 };
|
|
110
|
+
}
|
|
111
|
+
function frameOf(asked, messages, more, total) {
|
|
112
|
+
const oldest = messages[0];
|
|
113
|
+
const next = !more
|
|
114
|
+
? undefined
|
|
115
|
+
: oldest === undefined
|
|
116
|
+
? (asked.after ?? FROM_START)
|
|
117
|
+
: cursorOf([oldest.position, oldest.identity]);
|
|
118
|
+
return {
|
|
119
|
+
...(next === undefined ? {} : { next }),
|
|
120
|
+
...(total === null ? {} : { total }),
|
|
121
|
+
};
|
|
98
122
|
}
|
|
99
123
|
function newestOf(arriving, from) {
|
|
100
124
|
return arriving.reduce((top, message) => (top === null || message.position > top ? message.position : top), from);
|
|
@@ -165,18 +189,28 @@ function answered(result, field) {
|
|
|
165
189
|
const value = answer[field];
|
|
166
190
|
return typeof value === 'string' ? value : null;
|
|
167
191
|
}
|
|
168
|
-
function
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (
|
|
192
|
+
function beforeOf(after) {
|
|
193
|
+
if (after === undefined)
|
|
194
|
+
return null;
|
|
195
|
+
const decoded = typeof after === 'string' ? decodedCursor(after) : null;
|
|
196
|
+
if (decoded?.length === 0)
|
|
197
|
+
return null;
|
|
198
|
+
const [position, identity] = decoded ?? [];
|
|
199
|
+
if (decoded?.length !== 2 || typeof position !== 'string' || typeof identity !== 'string') {
|
|
200
|
+
throw runtimeError('invalid-after', `conversation after must be the next an earlier view returned, got ${String(after)}`);
|
|
201
|
+
}
|
|
202
|
+
return [position, identity];
|
|
203
|
+
}
|
|
204
|
+
function askedOf(options) {
|
|
205
|
+
const { limit, after, total } = options;
|
|
206
|
+
if (limit !== undefined && (!Number.isInteger(limit) || limit < 0)) {
|
|
173
207
|
throw runtimeError('invalid-limit', `conversation limit must be a non-negative integer, got ${String(limit)}`);
|
|
174
208
|
}
|
|
175
|
-
return limit;
|
|
209
|
+
return { limit: capped(limit), after, before: beforeOf(after), total: total === true };
|
|
176
210
|
}
|
|
177
211
|
const EXPIRED = { kind: 'rejected', code: 'expired', fields: {}, retryable: false };
|
|
178
212
|
function unwritten(draft) {
|
|
179
|
-
return draft.text === ''
|
|
213
|
+
return draft.text === '';
|
|
180
214
|
}
|
|
181
215
|
function pending(draft) {
|
|
182
216
|
return {
|
|
@@ -191,11 +225,13 @@ function withSubmitted(draft, submitted) {
|
|
|
191
225
|
const { submitted: _held, ...unsent } = draft;
|
|
192
226
|
return submitted.length === 0 ? unsent : { ...unsent, submitted };
|
|
193
227
|
}
|
|
228
|
+
function prepended(draft, said) {
|
|
229
|
+
return { text: [said.text, draft.text].filter((one) => one !== '').join('\n') };
|
|
230
|
+
}
|
|
194
231
|
function returned(draft, submission, others) {
|
|
195
232
|
return withSubmitted({
|
|
196
233
|
conversation: draft.conversation,
|
|
197
|
-
|
|
198
|
-
files: [...submission.files, ...draft.files],
|
|
234
|
+
...prepended(draft, submission),
|
|
199
235
|
revision: chatDraftRevision(),
|
|
200
236
|
}, others);
|
|
201
237
|
}
|
|
@@ -206,8 +242,10 @@ export function createConversationStore(deps) {
|
|
|
206
242
|
const drafts = new Map();
|
|
207
243
|
const sending = new Map();
|
|
208
244
|
const behind = new Set();
|
|
245
|
+
const catching = new Map();
|
|
209
246
|
const gaps = new Map();
|
|
210
247
|
const lives = new Map();
|
|
248
|
+
const unsent = new Map();
|
|
211
249
|
const views = new Map();
|
|
212
250
|
const listing = new Map();
|
|
213
251
|
const creations = new Set();
|
|
@@ -222,7 +260,7 @@ export function createConversationStore(deps) {
|
|
|
222
260
|
function liveOf(conversation) {
|
|
223
261
|
return lives.get(conversation) ?? QUIET;
|
|
224
262
|
}
|
|
225
|
-
function viewOf(conversation, held) {
|
|
263
|
+
function viewOf(conversation, held, frame) {
|
|
226
264
|
const draft = drafts.get(conversation);
|
|
227
265
|
const facts = liveOf(conversation);
|
|
228
266
|
return {
|
|
@@ -233,14 +271,18 @@ export function createConversationStore(deps) {
|
|
|
233
271
|
text,
|
|
234
272
|
message,
|
|
235
273
|
})),
|
|
274
|
+
...frame,
|
|
236
275
|
turn: structuredClone(facts.turn),
|
|
237
276
|
questions: structuredClone(facts.questions),
|
|
238
277
|
process: facts.process === null ? null : { ...facts.process },
|
|
239
278
|
commands: structuredClone(facts.commands),
|
|
240
279
|
options: structuredClone(facts.options),
|
|
280
|
+
starting: facts.starting,
|
|
281
|
+
link: facts.link === null ? null : { ...facts.link },
|
|
282
|
+
deliveryUnknown: [...facts.deliveryUnknown],
|
|
241
283
|
chatDraft: draft === undefined || unwritten(draft)
|
|
242
284
|
? null
|
|
243
|
-
: { text: draft.text,
|
|
285
|
+
: { text: draft.text, revision: draft.revision },
|
|
244
286
|
};
|
|
245
287
|
}
|
|
246
288
|
function emit(conversation) {
|
|
@@ -252,16 +294,34 @@ export function createConversationStore(deps) {
|
|
|
252
294
|
const ready = [...view.watchers].filter((watcher) => watcher.ready);
|
|
253
295
|
if (ready.length === 0)
|
|
254
296
|
continue;
|
|
255
|
-
const value = viewOf(conversation, view.window);
|
|
297
|
+
const value = viewOf(conversation, view.window, sharedFrame(view, view.window));
|
|
256
298
|
for (const watcher of ready)
|
|
257
299
|
watcher.notify(value);
|
|
258
300
|
}
|
|
259
301
|
}
|
|
260
|
-
function
|
|
302
|
+
function sharedFrame(view, window) {
|
|
303
|
+
return frameOf(view.asked, window, view.more, view.total);
|
|
304
|
+
}
|
|
305
|
+
async function slide(local, conversation, arriving) {
|
|
306
|
+
let count;
|
|
261
307
|
for (const view of views.values()) {
|
|
262
308
|
if (view.conversation !== conversation || view.window === null)
|
|
263
309
|
continue;
|
|
264
|
-
|
|
310
|
+
if (arriving === null) {
|
|
311
|
+
view.window = [];
|
|
312
|
+
view.more = false;
|
|
313
|
+
if (view.total !== null)
|
|
314
|
+
view.total = 0;
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
const joining = arriving.filter((message) => precedes(message, view.asked.before));
|
|
318
|
+
const next = windowOf(view.window, joining, view.asked.limit);
|
|
319
|
+
view.window = next.messages;
|
|
320
|
+
view.more ||= next.dropped;
|
|
321
|
+
if (view.total !== null && arriving.length > 0) {
|
|
322
|
+
count ??= await local.messageCount(conversation);
|
|
323
|
+
view.total = count;
|
|
324
|
+
}
|
|
265
325
|
}
|
|
266
326
|
}
|
|
267
327
|
function changesOf(conversation, arriving) {
|
|
@@ -281,6 +341,7 @@ export function createConversationStore(deps) {
|
|
|
281
341
|
created: entry.created,
|
|
282
342
|
finished: entry.finished,
|
|
283
343
|
outcome: entry.outcome,
|
|
344
|
+
waiting: entry.waiting,
|
|
284
345
|
state: stateOf(entry.conversation),
|
|
285
346
|
started: lives.get(entry.conversation)?.turn?.started ?? null,
|
|
286
347
|
}));
|
|
@@ -323,23 +384,30 @@ export function createConversationStore(deps) {
|
|
|
323
384
|
const declaration = deps.agents();
|
|
324
385
|
if (declaration === undefined)
|
|
325
386
|
return;
|
|
326
|
-
const held = await deps.documents(declaration);
|
|
327
|
-
if ('pending' in held)
|
|
328
|
-
return;
|
|
329
|
-
const { documents } = held;
|
|
330
387
|
const names = new Map();
|
|
331
388
|
const retired = new Set();
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
389
|
+
let covered = null;
|
|
390
|
+
for (let after;;) {
|
|
391
|
+
const read = await deps.documents(declaration, after);
|
|
392
|
+
if ('pending' in read)
|
|
393
|
+
return;
|
|
394
|
+
const coverage = JSON.stringify(read.coverage);
|
|
395
|
+
if (covered !== null && coverage !== covered)
|
|
396
|
+
return readAgents();
|
|
397
|
+
covered = coverage;
|
|
398
|
+
for (const document of read.documents) {
|
|
399
|
+
const identity = document.fields?.[declaration.identity];
|
|
400
|
+
const name = document.fields?.[declaration.name];
|
|
401
|
+
if (typeof identity !== 'string' || typeof name !== 'string')
|
|
402
|
+
continue;
|
|
403
|
+
names.set(identity, name);
|
|
404
|
+
const ended = declaration.retired === undefined ? null : document.fields?.[declaration.retired];
|
|
405
|
+
if (ended !== undefined && ended !== null)
|
|
406
|
+
retired.add(identity);
|
|
407
|
+
}
|
|
408
|
+
if (read.next === undefined)
|
|
409
|
+
break;
|
|
410
|
+
after = read.next;
|
|
343
411
|
}
|
|
344
412
|
const named = JSON.stringify([...names]) !== JSON.stringify([...agentNames]);
|
|
345
413
|
if (!named && JSON.stringify([...retired]) === JSON.stringify([...retiredAgents]))
|
|
@@ -363,9 +431,34 @@ export function createConversationStore(deps) {
|
|
|
363
431
|
return agentsRead;
|
|
364
432
|
}
|
|
365
433
|
function live(conversation, change) {
|
|
434
|
+
const owed = unsent.get(conversation);
|
|
435
|
+
for (const fact of FACTS.filter((one) => one in change))
|
|
436
|
+
owed?.delete(fact);
|
|
366
437
|
setLive(conversation, { ...liveOf(conversation), ...change });
|
|
367
438
|
emit(conversation);
|
|
368
439
|
}
|
|
440
|
+
function openingEnded() {
|
|
441
|
+
const owed = [...unsent];
|
|
442
|
+
unsent.clear();
|
|
443
|
+
for (const [conversation, facts] of owed) {
|
|
444
|
+
const held = lives.get(conversation);
|
|
445
|
+
if (held === undefined || facts.size === 0)
|
|
446
|
+
continue;
|
|
447
|
+
setLive(conversation, {
|
|
448
|
+
turn: held.turn,
|
|
449
|
+
questions: facts.has('questions') ? QUIET.questions : held.questions,
|
|
450
|
+
process: facts.has('process') ? QUIET.process : held.process,
|
|
451
|
+
commands: facts.has('commands') ? QUIET.commands : held.commands,
|
|
452
|
+
options: facts.has('options') ? QUIET.options : held.options,
|
|
453
|
+
starting: facts.has('starting') ? QUIET.starting : held.starting,
|
|
454
|
+
link: facts.has('link') ? QUIET.link : held.link,
|
|
455
|
+
deliveryUnknown: facts.has('deliveryUnknown')
|
|
456
|
+
? QUIET.deliveryUnknown
|
|
457
|
+
: held.deliveryUnknown,
|
|
458
|
+
});
|
|
459
|
+
emit(conversation);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
369
462
|
function relayed(conversation, turn, operation) {
|
|
370
463
|
const held = liveOf(conversation).turn;
|
|
371
464
|
const next = held?.turn === turn ? appliedTurn(held, operation) : startedTurn(turn, operation);
|
|
@@ -409,8 +502,9 @@ export function createConversationStore(deps) {
|
|
|
409
502
|
partials.delete(conversation);
|
|
410
503
|
drafts.delete(conversation);
|
|
411
504
|
behind.delete(conversation);
|
|
505
|
+
unsent.delete(conversation);
|
|
412
506
|
setLive(conversation, null);
|
|
413
|
-
slide(conversation, null);
|
|
507
|
+
await slide(local, conversation, null);
|
|
414
508
|
}
|
|
415
509
|
if (changed.length > 0)
|
|
416
510
|
deps.publish(conversationChangeSet(removed, changed));
|
|
@@ -438,11 +532,11 @@ export function createConversationStore(deps) {
|
|
|
438
532
|
if (advances)
|
|
439
533
|
reads.set(conversation, message.position);
|
|
440
534
|
sealTurns(conversation, new Set([message.turn]));
|
|
441
|
-
slide(conversation, [message]);
|
|
535
|
+
await slide(local, conversation, [message]);
|
|
442
536
|
deps.publish(conversationChangeSet(changesOf(conversation, [message]), [conversation]));
|
|
443
537
|
});
|
|
444
538
|
}
|
|
445
|
-
async function readHistories(conversations) {
|
|
539
|
+
async function readHistories(conversations, ended) {
|
|
446
540
|
const generations = new Map(conversations.map((one) => [one, gaps.get(one) ?? 0]));
|
|
447
541
|
let asking = conversations.map((conversation) => ({
|
|
448
542
|
conversation,
|
|
@@ -468,10 +562,33 @@ export function createConversationStore(deps) {
|
|
|
468
562
|
following.push({ conversation: page.conversation, after: page.next });
|
|
469
563
|
}
|
|
470
564
|
}
|
|
565
|
+
for (const { conversation } of asking) {
|
|
566
|
+
if (!following.some((next) => next.conversation === conversation))
|
|
567
|
+
ended(conversation);
|
|
568
|
+
}
|
|
471
569
|
asking = following;
|
|
472
570
|
}
|
|
473
571
|
return null;
|
|
474
572
|
}
|
|
573
|
+
function caughtUp(conversations) {
|
|
574
|
+
const ends = new Map();
|
|
575
|
+
for (const conversation of conversations) {
|
|
576
|
+
const held = new Promise((end) => ends.set(conversation, end));
|
|
577
|
+
catching.set(conversation, held);
|
|
578
|
+
void held.then(() => {
|
|
579
|
+
if (catching.get(conversation) === held)
|
|
580
|
+
catching.delete(conversation);
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
const ended = (conversation) => ends.get(conversation)?.();
|
|
584
|
+
const read = readHistories(conversations, ended);
|
|
585
|
+
const endAll = () => {
|
|
586
|
+
for (const conversation of conversations)
|
|
587
|
+
ended(conversation);
|
|
588
|
+
};
|
|
589
|
+
read.then(endAll, endAll);
|
|
590
|
+
return read;
|
|
591
|
+
}
|
|
475
592
|
function keepPage(conversation, arriving, from, next, generation) {
|
|
476
593
|
return deps.durably(async (local) => {
|
|
477
594
|
if (!replicated.has(conversation))
|
|
@@ -490,7 +607,7 @@ export function createConversationStore(deps) {
|
|
|
490
607
|
sealTurns(conversation, new Set(arriving.map((message) => message.turn)));
|
|
491
608
|
if (whole && (gaps.get(conversation) ?? 0) === generation)
|
|
492
609
|
behind.delete(conversation);
|
|
493
|
-
slide(conversation, arriving);
|
|
610
|
+
await slide(local, conversation, arriving);
|
|
494
611
|
if (arriving.length > 0 || sealing || whole) {
|
|
495
612
|
deps.publish(conversationChangeSet(changesOf(conversation, arriving), [conversation]));
|
|
496
613
|
}
|
|
@@ -501,11 +618,8 @@ export function createConversationStore(deps) {
|
|
|
501
618
|
if (event.kind === 'gap') {
|
|
502
619
|
if (replicated.has(conversation))
|
|
503
620
|
gap(conversation);
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
return;
|
|
507
|
-
setLive(conversation, { ...QUIET, turn: held.turn });
|
|
508
|
-
emit(conversation);
|
|
621
|
+
if (lives.has(conversation))
|
|
622
|
+
unsent.set(conversation, new Set(FACTS));
|
|
509
623
|
return;
|
|
510
624
|
}
|
|
511
625
|
if (event.kind === 'turn') {
|
|
@@ -528,6 +642,18 @@ export function createConversationStore(deps) {
|
|
|
528
642
|
live(conversation, { options: structuredClone(event.options) });
|
|
529
643
|
return;
|
|
530
644
|
}
|
|
645
|
+
if (event.kind === 'starting') {
|
|
646
|
+
live(conversation, { starting: event.step });
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
if (event.kind === 'link') {
|
|
650
|
+
live(conversation, { link: { connected: event.connected } });
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
if (event.kind === 'deliveries') {
|
|
654
|
+
live(conversation, { deliveryUnknown: [...event.unknown] });
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
531
657
|
const arriving = acceptedMessage(event.message);
|
|
532
658
|
if (arriving === null)
|
|
533
659
|
return;
|
|
@@ -567,7 +693,6 @@ export function createConversationStore(deps) {
|
|
|
567
693
|
const blank = {
|
|
568
694
|
conversation: from,
|
|
569
695
|
text: '',
|
|
570
|
-
files: [],
|
|
571
696
|
revision: chatDraftRevision(),
|
|
572
697
|
};
|
|
573
698
|
const { moves: _answered, ...unsent } = held ?? blank;
|
|
@@ -598,17 +723,12 @@ export function createConversationStore(deps) {
|
|
|
598
723
|
if (submission !== undefined)
|
|
599
724
|
return undefined;
|
|
600
725
|
const said = draft ?? current;
|
|
601
|
-
submission = {
|
|
602
|
-
operation,
|
|
603
|
-
text: said?.text ?? '',
|
|
604
|
-
files: [...(said?.files ?? [])],
|
|
605
|
-
turn: null,
|
|
606
|
-
};
|
|
726
|
+
submission = { operation, text: said?.text ?? '', turn: null };
|
|
607
727
|
return {
|
|
608
728
|
conversation,
|
|
609
729
|
...(draft === undefined || current === undefined
|
|
610
|
-
? { text: '',
|
|
611
|
-
: { text: current.text,
|
|
730
|
+
? { text: '', revision: chatDraftRevision() }
|
|
731
|
+
: { text: current.text, revision: current.revision }),
|
|
612
732
|
submitted: [...(current?.submitted ?? []), submission],
|
|
613
733
|
};
|
|
614
734
|
});
|
|
@@ -626,10 +746,8 @@ export function createConversationStore(deps) {
|
|
|
626
746
|
const dispatch = {};
|
|
627
747
|
sending.set(submission.operation, dispatch);
|
|
628
748
|
try {
|
|
629
|
-
const files = await Promise.all(submission.files.map(async (file) => ({ ...(await declaredFile(file)), blob: file.blob })));
|
|
630
749
|
const result = await invoke('conversation.send', conversation, {
|
|
631
750
|
text: submission.text,
|
|
632
|
-
files,
|
|
633
751
|
operation_id: submission.operation,
|
|
634
752
|
});
|
|
635
753
|
if (result.kind === 'revoked-authorization')
|
|
@@ -667,8 +785,12 @@ export function createConversationStore(deps) {
|
|
|
667
785
|
return entries();
|
|
668
786
|
},
|
|
669
787
|
async read(conversation, options = {}) {
|
|
670
|
-
const
|
|
671
|
-
return deps.durably(async (local) =>
|
|
788
|
+
const asked = askedOf(options);
|
|
789
|
+
return deps.durably(async (local) => {
|
|
790
|
+
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
791
|
+
const total = asked.total ? await local.messageCount(conversation) : null;
|
|
792
|
+
return structuredClone(viewOf(conversation, messages, frameOf(asked, messages, more, total)));
|
|
793
|
+
});
|
|
672
794
|
},
|
|
673
795
|
async create(input) {
|
|
674
796
|
const result = await deps.call('conversation.create', input);
|
|
@@ -693,10 +815,19 @@ export function createConversationStore(deps) {
|
|
|
693
815
|
if (draft !== undefined) {
|
|
694
816
|
await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
|
|
695
817
|
? undefined
|
|
696
|
-
: returned(current ?? { conversation, text: '',
|
|
818
|
+
: returned(current ?? { conversation, text: '', revision: '' }, { operation, ...draft, turn: null }, current?.submitted ?? []));
|
|
697
819
|
}
|
|
698
820
|
return OFFLINE;
|
|
699
821
|
},
|
|
822
|
+
async attach(room, file) {
|
|
823
|
+
if (!deps.online())
|
|
824
|
+
return OFFLINE;
|
|
825
|
+
return deps.call('conversation.attach', {
|
|
826
|
+
room,
|
|
827
|
+
...(await declaredFile(file)),
|
|
828
|
+
blob: file.blob,
|
|
829
|
+
});
|
|
830
|
+
},
|
|
700
831
|
answer(conversation, answer) {
|
|
701
832
|
return invoke('conversation.answer', conversation, { answer });
|
|
702
833
|
},
|
|
@@ -727,21 +858,22 @@ export function createConversationStore(deps) {
|
|
|
727
858
|
return withDraft(conversation, (current) => ({
|
|
728
859
|
conversation,
|
|
729
860
|
text: draft.text,
|
|
730
|
-
files: [...draft.files],
|
|
731
861
|
revision,
|
|
732
862
|
...(current === undefined ? {} : pending(current)),
|
|
733
863
|
}));
|
|
734
864
|
},
|
|
865
|
+
prepend(conversation, draft) {
|
|
866
|
+
return withDraft(conversation, (current) => ({
|
|
867
|
+
conversation,
|
|
868
|
+
...(current === undefined ? { text: draft.text } : prepended(current, draft)),
|
|
869
|
+
revision: chatDraftRevision(),
|
|
870
|
+
...(current === undefined ? {} : pending(current)),
|
|
871
|
+
}));
|
|
872
|
+
},
|
|
735
873
|
discard(conversation) {
|
|
736
874
|
return withDraft(conversation, (current) => current === undefined
|
|
737
875
|
? undefined
|
|
738
|
-
: {
|
|
739
|
-
conversation,
|
|
740
|
-
text: '',
|
|
741
|
-
files: [],
|
|
742
|
-
revision: chatDraftRevision(),
|
|
743
|
-
...pending(current),
|
|
744
|
-
});
|
|
876
|
+
: { conversation, text: '', revision: chatDraftRevision(), ...pending(current) });
|
|
745
877
|
},
|
|
746
878
|
};
|
|
747
879
|
return {
|
|
@@ -781,12 +913,20 @@ export function createConversationStore(deps) {
|
|
|
781
913
|
await remove(leaving);
|
|
782
914
|
},
|
|
783
915
|
async catchUp(progress) {
|
|
784
|
-
const
|
|
785
|
-
|
|
786
|
-
|
|
916
|
+
const owed = (conversation) => behind.has(conversation) && replicated.has(conversation);
|
|
917
|
+
const read = async (conversations) => {
|
|
918
|
+
if (conversations.length === 0 || deps.closed())
|
|
919
|
+
return;
|
|
920
|
+
const failed = await caughtUp(conversations);
|
|
787
921
|
if (failed?.kind === 'transport-uncertainty')
|
|
788
922
|
progress.reachable = false;
|
|
789
|
-
}
|
|
923
|
+
};
|
|
924
|
+
const asking = [...behind].filter(owed).sort();
|
|
925
|
+
const awaited = asking.filter((conversation) => catching.has(conversation));
|
|
926
|
+
await Promise.all([
|
|
927
|
+
read(asking.filter((conversation) => !catching.has(conversation))),
|
|
928
|
+
Promise.all(awaited.map((conversation) => catching.get(conversation))).then(() => read(awaited.filter((conversation) => owed(conversation) && !catching.has(conversation)))),
|
|
929
|
+
]);
|
|
790
930
|
if (behind.size > 0)
|
|
791
931
|
progress.complete = false;
|
|
792
932
|
},
|
|
@@ -828,27 +968,38 @@ export function createConversationStore(deps) {
|
|
|
828
968
|
reopened() {
|
|
829
969
|
sending.clear();
|
|
830
970
|
},
|
|
971
|
+
lost() {
|
|
972
|
+
catching.clear();
|
|
973
|
+
},
|
|
831
974
|
watch(conversation, options, deliver) {
|
|
832
|
-
const
|
|
833
|
-
const key = JSON.stringify([conversation, limit ?? null]);
|
|
975
|
+
const asked = askedOf(options);
|
|
976
|
+
const key = JSON.stringify([conversation, asked.limit, asked.after ?? null, asked.total]);
|
|
834
977
|
const view = views.get(key) ?? {
|
|
835
978
|
conversation,
|
|
836
|
-
|
|
979
|
+
asked,
|
|
837
980
|
watchers: new Set(),
|
|
838
981
|
window: null,
|
|
982
|
+
more: false,
|
|
983
|
+
total: null,
|
|
839
984
|
};
|
|
840
985
|
views.set(key, view);
|
|
841
986
|
const watcher = { notify: deliver, ready: false };
|
|
842
987
|
view.watchers.add(watcher);
|
|
843
988
|
void deps
|
|
844
989
|
.durably(async (local) => {
|
|
845
|
-
view.window
|
|
990
|
+
if (view.window !== null)
|
|
991
|
+
return;
|
|
992
|
+
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
993
|
+
view.window = messages;
|
|
994
|
+
view.more = more;
|
|
995
|
+
view.total = asked.total ? await local.messageCount(conversation) : null;
|
|
846
996
|
})
|
|
847
997
|
.then(() => {
|
|
848
998
|
if (deps.closed() || !view.watchers.has(watcher))
|
|
849
999
|
return;
|
|
850
1000
|
watcher.ready = true;
|
|
851
|
-
|
|
1001
|
+
const window = view.window ?? [];
|
|
1002
|
+
watcher.notify(viewOf(conversation, window, sharedFrame(view, window)));
|
|
852
1003
|
})
|
|
853
1004
|
.catch(() => { });
|
|
854
1005
|
return () => {
|
|
@@ -900,6 +1051,7 @@ export function createConversationStore(deps) {
|
|
|
900
1051
|
creations.delete(entry.conversation);
|
|
901
1052
|
}
|
|
902
1053
|
listKnown = true;
|
|
1054
|
+
openingEnded();
|
|
903
1055
|
}
|
|
904
1056
|
else if (event.kind === 'listed') {
|
|
905
1057
|
listing.set(event.entry.conversation, { ...event.entry });
|
|
@@ -926,6 +1078,7 @@ export function createConversationStore(deps) {
|
|
|
926
1078
|
close() {
|
|
927
1079
|
views.clear();
|
|
928
1080
|
lives.clear();
|
|
1081
|
+
unsent.clear();
|
|
929
1082
|
listWatchers.clear();
|
|
930
1083
|
agentWatchers.clear();
|
|
931
1084
|
},
|
package/dist/digest.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"AA0EA,MAAM,MAAM,MAAM,GAAG;IACnB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,GAAG,IAAI,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,MAAM,IAAI,MAAM,CAoC/B;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAMxD"}
|