@agentshouse/mdruntime 0.1.0-c5d3fa6fb67bc → 0.1.0-c63ad08fad0c3
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 +240 -220
- package/README.md +9 -8
- package/dist/adapter.d.ts +72 -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 +26 -7
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +167 -82
- 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 +9 -16
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +11 -89
- 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 +16 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +721 -0
- package/dist/connection.d.ts +22 -8
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +2509 -830
- package/dist/conversation.d.ts +15 -3
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +238 -94
- 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 +3 -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/fulltext.d.ts +27 -0
- package/dist/fulltext.d.ts.map +1 -0
- package/dist/fulltext.js +368 -0
- package/dist/host.d.ts +5 -4
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +57 -7
- package/dist/identity.d.ts +0 -1
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -3
- package/dist/index.d.ts +12 -8
- 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/messages.d.ts +28 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +90 -0
- 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 +29 -2
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +46 -7
- 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 +18 -3
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +1 -1
- package/dist/reads.d.ts +11 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +100 -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 +13 -15
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +78 -51
- package/dist/replica.d.ts +57 -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 +25 -42
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +30 -169
- 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 +97 -88
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +335 -659
- package/dist/stored.d.ts +145 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +567 -0
- package/dist/tables.d.ts +342 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +576 -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/dist/words.d.ts +19 -0
- package/dist/words.d.ts.map +1 -0
- package/dist/words.js +150 -0
- package/package.json +10 -4
- 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,21 +294,36 @@ 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
|
-
function changesOf(conversation, arriving) {
|
|
268
|
-
return arriving.map(({ identity, text }) => ({ conversation, identity, text }));
|
|
269
|
-
}
|
|
270
327
|
function stateOf(conversation) {
|
|
271
328
|
const facts = liveOf(conversation);
|
|
272
329
|
if (facts.questions.length > 0)
|
|
@@ -281,6 +338,7 @@ export function createConversationStore(deps) {
|
|
|
281
338
|
created: entry.created,
|
|
282
339
|
finished: entry.finished,
|
|
283
340
|
outcome: entry.outcome,
|
|
341
|
+
waiting: entry.waiting,
|
|
284
342
|
state: stateOf(entry.conversation),
|
|
285
343
|
started: lives.get(entry.conversation)?.turn?.started ?? null,
|
|
286
344
|
}));
|
|
@@ -323,23 +381,30 @@ export function createConversationStore(deps) {
|
|
|
323
381
|
const declaration = deps.agents();
|
|
324
382
|
if (declaration === undefined)
|
|
325
383
|
return;
|
|
326
|
-
const held = await deps.documents(declaration);
|
|
327
|
-
if ('pending' in held)
|
|
328
|
-
return;
|
|
329
|
-
const { documents } = held;
|
|
330
384
|
const names = new Map();
|
|
331
385
|
const retired = new Set();
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
386
|
+
let covered = null;
|
|
387
|
+
for (let after;;) {
|
|
388
|
+
const read = await deps.documents(declaration, after);
|
|
389
|
+
if ('pending' in read)
|
|
390
|
+
return;
|
|
391
|
+
const coverage = JSON.stringify(read.coverage);
|
|
392
|
+
if (covered !== null && coverage !== covered)
|
|
393
|
+
return readAgents();
|
|
394
|
+
covered = coverage;
|
|
395
|
+
for (const document of read.documents) {
|
|
396
|
+
const identity = document.fields?.[declaration.identity];
|
|
397
|
+
const name = document.fields?.[declaration.name];
|
|
398
|
+
if (typeof identity !== 'string' || typeof name !== 'string')
|
|
399
|
+
continue;
|
|
400
|
+
names.set(identity, name);
|
|
401
|
+
const ended = declaration.retired === undefined ? null : document.fields?.[declaration.retired];
|
|
402
|
+
if (ended !== undefined && ended !== null)
|
|
403
|
+
retired.add(identity);
|
|
404
|
+
}
|
|
405
|
+
if (read.next === undefined)
|
|
406
|
+
break;
|
|
407
|
+
after = read.next;
|
|
343
408
|
}
|
|
344
409
|
const named = JSON.stringify([...names]) !== JSON.stringify([...agentNames]);
|
|
345
410
|
if (!named && JSON.stringify([...retired]) === JSON.stringify([...retiredAgents]))
|
|
@@ -363,9 +428,34 @@ export function createConversationStore(deps) {
|
|
|
363
428
|
return agentsRead;
|
|
364
429
|
}
|
|
365
430
|
function live(conversation, change) {
|
|
431
|
+
const owed = unsent.get(conversation);
|
|
432
|
+
for (const fact of FACTS.filter((one) => one in change))
|
|
433
|
+
owed?.delete(fact);
|
|
366
434
|
setLive(conversation, { ...liveOf(conversation), ...change });
|
|
367
435
|
emit(conversation);
|
|
368
436
|
}
|
|
437
|
+
function openingEnded() {
|
|
438
|
+
const owed = [...unsent];
|
|
439
|
+
unsent.clear();
|
|
440
|
+
for (const [conversation, facts] of owed) {
|
|
441
|
+
const held = lives.get(conversation);
|
|
442
|
+
if (held === undefined || facts.size === 0)
|
|
443
|
+
continue;
|
|
444
|
+
setLive(conversation, {
|
|
445
|
+
turn: held.turn,
|
|
446
|
+
questions: facts.has('questions') ? QUIET.questions : held.questions,
|
|
447
|
+
process: facts.has('process') ? QUIET.process : held.process,
|
|
448
|
+
commands: facts.has('commands') ? QUIET.commands : held.commands,
|
|
449
|
+
options: facts.has('options') ? QUIET.options : held.options,
|
|
450
|
+
starting: facts.has('starting') ? QUIET.starting : held.starting,
|
|
451
|
+
link: facts.has('link') ? QUIET.link : held.link,
|
|
452
|
+
deliveryUnknown: facts.has('deliveryUnknown')
|
|
453
|
+
? QUIET.deliveryUnknown
|
|
454
|
+
: held.deliveryUnknown,
|
|
455
|
+
});
|
|
456
|
+
emit(conversation);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
369
459
|
function relayed(conversation, turn, operation) {
|
|
370
460
|
const held = liveOf(conversation).turn;
|
|
371
461
|
const next = held?.turn === turn ? appliedTurn(held, operation) : startedTurn(turn, operation);
|
|
@@ -392,12 +482,6 @@ export function createConversationStore(deps) {
|
|
|
392
482
|
}
|
|
393
483
|
async function remove(leaving) {
|
|
394
484
|
await deps.durably(async (local) => {
|
|
395
|
-
const removed = [];
|
|
396
|
-
for (const conversation of leaving) {
|
|
397
|
-
for (const identity of await local.messageIdentities(conversation)) {
|
|
398
|
-
removed.push({ conversation, identity, text: null });
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
485
|
await local.dropConversations(leaving);
|
|
402
486
|
const changed = [];
|
|
403
487
|
for (const conversation of leaving) {
|
|
@@ -409,11 +493,12 @@ export function createConversationStore(deps) {
|
|
|
409
493
|
partials.delete(conversation);
|
|
410
494
|
drafts.delete(conversation);
|
|
411
495
|
behind.delete(conversation);
|
|
496
|
+
unsent.delete(conversation);
|
|
412
497
|
setLive(conversation, null);
|
|
413
|
-
slide(conversation, null);
|
|
498
|
+
await slide(local, conversation, null);
|
|
414
499
|
}
|
|
415
500
|
if (changed.length > 0)
|
|
416
|
-
deps.publish(conversationChangeSet(
|
|
501
|
+
deps.publish(conversationChangeSet(changed));
|
|
417
502
|
});
|
|
418
503
|
}
|
|
419
504
|
function gap(conversation) {
|
|
@@ -438,11 +523,11 @@ export function createConversationStore(deps) {
|
|
|
438
523
|
if (advances)
|
|
439
524
|
reads.set(conversation, message.position);
|
|
440
525
|
sealTurns(conversation, new Set([message.turn]));
|
|
441
|
-
slide(conversation, [message]);
|
|
442
|
-
deps.publish(conversationChangeSet(
|
|
526
|
+
await slide(local, conversation, [message]);
|
|
527
|
+
deps.publish(conversationChangeSet([conversation]));
|
|
443
528
|
});
|
|
444
529
|
}
|
|
445
|
-
async function readHistories(conversations) {
|
|
530
|
+
async function readHistories(conversations, ended) {
|
|
446
531
|
const generations = new Map(conversations.map((one) => [one, gaps.get(one) ?? 0]));
|
|
447
532
|
let asking = conversations.map((conversation) => ({
|
|
448
533
|
conversation,
|
|
@@ -468,10 +553,33 @@ export function createConversationStore(deps) {
|
|
|
468
553
|
following.push({ conversation: page.conversation, after: page.next });
|
|
469
554
|
}
|
|
470
555
|
}
|
|
556
|
+
for (const { conversation } of asking) {
|
|
557
|
+
if (!following.some((next) => next.conversation === conversation))
|
|
558
|
+
ended(conversation);
|
|
559
|
+
}
|
|
471
560
|
asking = following;
|
|
472
561
|
}
|
|
473
562
|
return null;
|
|
474
563
|
}
|
|
564
|
+
function caughtUp(conversations) {
|
|
565
|
+
const ends = new Map();
|
|
566
|
+
for (const conversation of conversations) {
|
|
567
|
+
const held = new Promise((end) => ends.set(conversation, end));
|
|
568
|
+
catching.set(conversation, held);
|
|
569
|
+
void held.then(() => {
|
|
570
|
+
if (catching.get(conversation) === held)
|
|
571
|
+
catching.delete(conversation);
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
const ended = (conversation) => ends.get(conversation)?.();
|
|
575
|
+
const read = readHistories(conversations, ended);
|
|
576
|
+
const endAll = () => {
|
|
577
|
+
for (const conversation of conversations)
|
|
578
|
+
ended(conversation);
|
|
579
|
+
};
|
|
580
|
+
read.then(endAll, endAll);
|
|
581
|
+
return read;
|
|
582
|
+
}
|
|
475
583
|
function keepPage(conversation, arriving, from, next, generation) {
|
|
476
584
|
return deps.durably(async (local) => {
|
|
477
585
|
if (!replicated.has(conversation))
|
|
@@ -490,9 +598,9 @@ export function createConversationStore(deps) {
|
|
|
490
598
|
sealTurns(conversation, new Set(arriving.map((message) => message.turn)));
|
|
491
599
|
if (whole && (gaps.get(conversation) ?? 0) === generation)
|
|
492
600
|
behind.delete(conversation);
|
|
493
|
-
slide(conversation, arriving);
|
|
601
|
+
await slide(local, conversation, arriving);
|
|
494
602
|
if (arriving.length > 0 || sealing || whole) {
|
|
495
|
-
deps.publish(conversationChangeSet(
|
|
603
|
+
deps.publish(conversationChangeSet([conversation]));
|
|
496
604
|
}
|
|
497
605
|
});
|
|
498
606
|
}
|
|
@@ -501,11 +609,8 @@ export function createConversationStore(deps) {
|
|
|
501
609
|
if (event.kind === 'gap') {
|
|
502
610
|
if (replicated.has(conversation))
|
|
503
611
|
gap(conversation);
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
return;
|
|
507
|
-
setLive(conversation, { ...QUIET, turn: held.turn });
|
|
508
|
-
emit(conversation);
|
|
612
|
+
if (lives.has(conversation))
|
|
613
|
+
unsent.set(conversation, new Set(FACTS));
|
|
509
614
|
return;
|
|
510
615
|
}
|
|
511
616
|
if (event.kind === 'turn') {
|
|
@@ -528,6 +633,18 @@ export function createConversationStore(deps) {
|
|
|
528
633
|
live(conversation, { options: structuredClone(event.options) });
|
|
529
634
|
return;
|
|
530
635
|
}
|
|
636
|
+
if (event.kind === 'starting') {
|
|
637
|
+
live(conversation, { starting: event.step });
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
if (event.kind === 'link') {
|
|
641
|
+
live(conversation, { link: { connected: event.connected } });
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
if (event.kind === 'deliveries') {
|
|
645
|
+
live(conversation, { deliveryUnknown: [...event.unknown] });
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
531
648
|
const arriving = acceptedMessage(event.message);
|
|
532
649
|
if (arriving === null)
|
|
533
650
|
return;
|
|
@@ -567,7 +684,6 @@ export function createConversationStore(deps) {
|
|
|
567
684
|
const blank = {
|
|
568
685
|
conversation: from,
|
|
569
686
|
text: '',
|
|
570
|
-
files: [],
|
|
571
687
|
revision: chatDraftRevision(),
|
|
572
688
|
};
|
|
573
689
|
const { moves: _answered, ...unsent } = held ?? blank;
|
|
@@ -577,7 +693,7 @@ export function createConversationStore(deps) {
|
|
|
577
693
|
drafts.set(from, left);
|
|
578
694
|
for (const one of taken)
|
|
579
695
|
drafts.set(to, one);
|
|
580
|
-
deps.publish(conversationChangeSet([
|
|
696
|
+
deps.publish(conversationChangeSet([from, to]));
|
|
581
697
|
});
|
|
582
698
|
}
|
|
583
699
|
function withDraft(conversation, next) {
|
|
@@ -586,7 +702,7 @@ export function createConversationStore(deps) {
|
|
|
586
702
|
if (following === undefined)
|
|
587
703
|
return;
|
|
588
704
|
await kept(local, conversation, following);
|
|
589
|
-
deps.publish(conversationChangeSet([
|
|
705
|
+
deps.publish(conversationChangeSet([conversation]));
|
|
590
706
|
});
|
|
591
707
|
}
|
|
592
708
|
async function submitted(conversation, operation, draft) {
|
|
@@ -598,17 +714,12 @@ export function createConversationStore(deps) {
|
|
|
598
714
|
if (submission !== undefined)
|
|
599
715
|
return undefined;
|
|
600
716
|
const said = draft ?? current;
|
|
601
|
-
submission = {
|
|
602
|
-
operation,
|
|
603
|
-
text: said?.text ?? '',
|
|
604
|
-
files: [...(said?.files ?? [])],
|
|
605
|
-
turn: null,
|
|
606
|
-
};
|
|
717
|
+
submission = { operation, text: said?.text ?? '', turn: null };
|
|
607
718
|
return {
|
|
608
719
|
conversation,
|
|
609
720
|
...(draft === undefined || current === undefined
|
|
610
|
-
? { text: '',
|
|
611
|
-
: { text: current.text,
|
|
721
|
+
? { text: '', revision: chatDraftRevision() }
|
|
722
|
+
: { text: current.text, revision: current.revision }),
|
|
612
723
|
submitted: [...(current?.submitted ?? []), submission],
|
|
613
724
|
};
|
|
614
725
|
});
|
|
@@ -626,10 +737,8 @@ export function createConversationStore(deps) {
|
|
|
626
737
|
const dispatch = {};
|
|
627
738
|
sending.set(submission.operation, dispatch);
|
|
628
739
|
try {
|
|
629
|
-
const files = await Promise.all(submission.files.map(async (file) => ({ ...(await declaredFile(file)), blob: file.blob })));
|
|
630
740
|
const result = await invoke('conversation.send', conversation, {
|
|
631
741
|
text: submission.text,
|
|
632
|
-
files,
|
|
633
742
|
operation_id: submission.operation,
|
|
634
743
|
});
|
|
635
744
|
if (result.kind === 'revoked-authorization')
|
|
@@ -667,8 +776,12 @@ export function createConversationStore(deps) {
|
|
|
667
776
|
return entries();
|
|
668
777
|
},
|
|
669
778
|
async read(conversation, options = {}) {
|
|
670
|
-
const
|
|
671
|
-
return deps.durably(async (local) =>
|
|
779
|
+
const asked = askedOf(options);
|
|
780
|
+
return deps.durably(async (local) => {
|
|
781
|
+
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
782
|
+
const total = asked.total ? await local.messageCount(conversation) : null;
|
|
783
|
+
return structuredClone(viewOf(conversation, messages, frameOf(asked, messages, more, total)));
|
|
784
|
+
});
|
|
672
785
|
},
|
|
673
786
|
async create(input) {
|
|
674
787
|
const result = await deps.call('conversation.create', input);
|
|
@@ -693,10 +806,19 @@ export function createConversationStore(deps) {
|
|
|
693
806
|
if (draft !== undefined) {
|
|
694
807
|
await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
|
|
695
808
|
? undefined
|
|
696
|
-
: returned(current ?? { conversation, text: '',
|
|
809
|
+
: returned(current ?? { conversation, text: '', revision: '' }, { operation, ...draft, turn: null }, current?.submitted ?? []));
|
|
697
810
|
}
|
|
698
811
|
return OFFLINE;
|
|
699
812
|
},
|
|
813
|
+
async attach(room, file) {
|
|
814
|
+
if (!deps.online())
|
|
815
|
+
return OFFLINE;
|
|
816
|
+
return deps.call('conversation.attach', {
|
|
817
|
+
room,
|
|
818
|
+
...(await declaredFile(file)),
|
|
819
|
+
blob: file.blob,
|
|
820
|
+
});
|
|
821
|
+
},
|
|
700
822
|
answer(conversation, answer) {
|
|
701
823
|
return invoke('conversation.answer', conversation, { answer });
|
|
702
824
|
},
|
|
@@ -727,21 +849,22 @@ export function createConversationStore(deps) {
|
|
|
727
849
|
return withDraft(conversation, (current) => ({
|
|
728
850
|
conversation,
|
|
729
851
|
text: draft.text,
|
|
730
|
-
files: [...draft.files],
|
|
731
852
|
revision,
|
|
732
853
|
...(current === undefined ? {} : pending(current)),
|
|
733
854
|
}));
|
|
734
855
|
},
|
|
856
|
+
prepend(conversation, draft) {
|
|
857
|
+
return withDraft(conversation, (current) => ({
|
|
858
|
+
conversation,
|
|
859
|
+
...(current === undefined ? { text: draft.text } : prepended(current, draft)),
|
|
860
|
+
revision: chatDraftRevision(),
|
|
861
|
+
...(current === undefined ? {} : pending(current)),
|
|
862
|
+
}));
|
|
863
|
+
},
|
|
735
864
|
discard(conversation) {
|
|
736
865
|
return withDraft(conversation, (current) => current === undefined
|
|
737
866
|
? undefined
|
|
738
|
-
: {
|
|
739
|
-
conversation,
|
|
740
|
-
text: '',
|
|
741
|
-
files: [],
|
|
742
|
-
revision: chatDraftRevision(),
|
|
743
|
-
...pending(current),
|
|
744
|
-
});
|
|
867
|
+
: { conversation, text: '', revision: chatDraftRevision(), ...pending(current) });
|
|
745
868
|
},
|
|
746
869
|
};
|
|
747
870
|
return {
|
|
@@ -781,12 +904,20 @@ export function createConversationStore(deps) {
|
|
|
781
904
|
await remove(leaving);
|
|
782
905
|
},
|
|
783
906
|
async catchUp(progress) {
|
|
784
|
-
const
|
|
785
|
-
|
|
786
|
-
|
|
907
|
+
const owed = (conversation) => behind.has(conversation) && replicated.has(conversation);
|
|
908
|
+
const read = async (conversations) => {
|
|
909
|
+
if (conversations.length === 0 || deps.closed())
|
|
910
|
+
return;
|
|
911
|
+
const failed = await caughtUp(conversations);
|
|
787
912
|
if (failed?.kind === 'transport-uncertainty')
|
|
788
913
|
progress.reachable = false;
|
|
789
|
-
}
|
|
914
|
+
};
|
|
915
|
+
const asking = [...behind].filter(owed).sort();
|
|
916
|
+
const awaited = asking.filter((conversation) => catching.has(conversation));
|
|
917
|
+
await Promise.all([
|
|
918
|
+
read(asking.filter((conversation) => !catching.has(conversation))),
|
|
919
|
+
Promise.all(awaited.map((conversation) => catching.get(conversation))).then(() => read(awaited.filter((conversation) => owed(conversation) && !catching.has(conversation)))),
|
|
920
|
+
]);
|
|
790
921
|
if (behind.size > 0)
|
|
791
922
|
progress.complete = false;
|
|
792
923
|
},
|
|
@@ -828,27 +959,38 @@ export function createConversationStore(deps) {
|
|
|
828
959
|
reopened() {
|
|
829
960
|
sending.clear();
|
|
830
961
|
},
|
|
962
|
+
lost() {
|
|
963
|
+
catching.clear();
|
|
964
|
+
},
|
|
831
965
|
watch(conversation, options, deliver) {
|
|
832
|
-
const
|
|
833
|
-
const key = JSON.stringify([conversation, limit ?? null]);
|
|
966
|
+
const asked = askedOf(options);
|
|
967
|
+
const key = JSON.stringify([conversation, asked.limit, asked.after ?? null, asked.total]);
|
|
834
968
|
const view = views.get(key) ?? {
|
|
835
969
|
conversation,
|
|
836
|
-
|
|
970
|
+
asked,
|
|
837
971
|
watchers: new Set(),
|
|
838
972
|
window: null,
|
|
973
|
+
more: false,
|
|
974
|
+
total: null,
|
|
839
975
|
};
|
|
840
976
|
views.set(key, view);
|
|
841
977
|
const watcher = { notify: deliver, ready: false };
|
|
842
978
|
view.watchers.add(watcher);
|
|
843
979
|
void deps
|
|
844
980
|
.durably(async (local) => {
|
|
845
|
-
view.window
|
|
981
|
+
if (view.window !== null)
|
|
982
|
+
return;
|
|
983
|
+
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
984
|
+
view.window = messages;
|
|
985
|
+
view.more = more;
|
|
986
|
+
view.total = asked.total ? await local.messageCount(conversation) : null;
|
|
846
987
|
})
|
|
847
988
|
.then(() => {
|
|
848
989
|
if (deps.closed() || !view.watchers.has(watcher))
|
|
849
990
|
return;
|
|
850
991
|
watcher.ready = true;
|
|
851
|
-
|
|
992
|
+
const window = view.window ?? [];
|
|
993
|
+
watcher.notify(viewOf(conversation, window, sharedFrame(view, window)));
|
|
852
994
|
})
|
|
853
995
|
.catch(() => { });
|
|
854
996
|
return () => {
|
|
@@ -900,6 +1042,7 @@ export function createConversationStore(deps) {
|
|
|
900
1042
|
creations.delete(entry.conversation);
|
|
901
1043
|
}
|
|
902
1044
|
listKnown = true;
|
|
1045
|
+
openingEnded();
|
|
903
1046
|
}
|
|
904
1047
|
else if (event.kind === 'listed') {
|
|
905
1048
|
listing.set(event.entry.conversation, { ...event.entry });
|
|
@@ -926,6 +1069,7 @@ export function createConversationStore(deps) {
|
|
|
926
1069
|
close() {
|
|
927
1070
|
views.clear();
|
|
928
1071
|
lives.clear();
|
|
1072
|
+
unsent.clear();
|
|
929
1073
|
listWatchers.clear();
|
|
930
1074
|
agentWatchers.clear();
|
|
931
1075
|
},
|
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"}
|