@agentshouse/mdruntime 0.1.0-c8eac46931574 → 0.1.0-c8f07dbee1c62
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/README.md +1 -1
- package/dist/acceptance.d.ts +6 -0
- package/dist/acceptance.d.ts.map +1 -0
- package/dist/acceptance.js +389 -0
- package/dist/actions.d.ts +20 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +250 -0
- package/dist/adapter.d.ts +23 -25
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +3 -10
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +21 -56
- package/dist/bootstrap.d.ts +8 -4
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +209 -78
- package/dist/cell.d.ts +6 -0
- package/dist/cell.d.ts.map +1 -0
- package/dist/cell.js +9 -0
- package/dist/chain.d.ts +2 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/change.d.ts +1 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/chat-types.d.ts +5 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +13 -0
- package/dist/client.d.ts +17 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -0
- package/dist/collection.d.ts +2 -1
- package/dist/collection.d.ts.map +1 -1
- package/dist/compile.d.ts +7 -7
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +229 -301
- package/dist/connection.d.ts +5 -141
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +98 -5279
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +7 -0
- package/dist/conversation-row.d.ts +33 -0
- package/dist/conversation-row.d.ts.map +1 -0
- package/dist/conversation-row.js +53 -0
- package/dist/conversation.d.ts +16 -6
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +364 -212
- package/dist/discovery.d.ts +10 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +175 -0
- package/dist/durability.d.ts +15 -0
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +2 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +17 -8
- package/dist/figures.d.ts +48 -0
- package/dist/figures.d.ts.map +1 -0
- package/dist/figures.js +197 -0
- package/dist/holdings.d.ts +29 -0
- package/dist/holdings.d.ts.map +1 -0
- package/dist/holdings.js +95 -0
- package/dist/host.d.ts +2 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +13 -13
- 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 +19 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/install.d.ts +56 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +560 -0
- package/dist/job.d.ts +26 -1
- package/dist/job.d.ts.map +1 -1
- package/dist/job.js +41 -0
- package/dist/lifecycle.d.ts +7 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +267 -0
- package/dist/listing.d.ts +53 -0
- package/dist/listing.d.ts.map +1 -0
- package/dist/listing.js +175 -0
- package/dist/live.d.ts +4 -4
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +53 -15
- package/dist/locks.d.ts +9 -0
- package/dist/locks.d.ts.map +1 -0
- package/dist/locks.js +61 -0
- package/dist/log.d.ts +1 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/lost.d.ts +5 -0
- package/dist/lost.d.ts.map +1 -0
- package/dist/lost.js +61 -0
- package/dist/memory.d.ts +4 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +43 -4
- package/dist/messages.d.ts +25 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +84 -5
- package/dist/model.d.ts +2 -9
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +0 -9
- package/dist/models.d.ts +14 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +193 -0
- package/dist/opening.d.ts +4 -0
- package/dist/opening.d.ts.map +1 -0
- package/dist/opening.js +56 -0
- package/dist/outcome.d.ts +4 -1
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +3 -0
- package/dist/overlay.d.ts +1 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +11 -0
- package/dist/parts.d.ts +59 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +118 -0
- package/dist/preparation.d.ts +20 -0
- package/dist/preparation.d.ts.map +1 -0
- package/dist/preparation.js +226 -0
- package/dist/queries.d.ts +16 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +272 -0
- package/dist/query.d.ts +13 -212
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -524
- package/dist/questions.d.ts +34 -0
- package/dist/questions.d.ts.map +1 -0
- package/dist/questions.js +122 -0
- package/dist/reach.d.ts +9 -8
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +160 -107
- package/dist/react.d.ts +9 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/read.d.ts +7 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +17 -0
- package/dist/reads.d.ts +36 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +150 -0
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +9 -1
- package/dist/refresh.d.ts +1 -1
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +8 -20
- package/dist/refusal.d.ts +5 -0
- package/dist/refusal.d.ts.map +1 -0
- package/dist/refusal.js +56 -0
- package/dist/replica.d.ts +8 -8
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +52 -19
- package/dist/room-draft.d.ts +2 -2
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-drafts.d.ts +24 -0
- package/dist/room-drafts.d.ts.map +1 -0
- package/dist/room-drafts.js +216 -0
- package/dist/rows.d.ts +14 -22
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +48 -189
- package/dist/runtime.d.ts +42 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +13 -10
- package/dist/saves.d.ts +70 -0
- package/dist/saves.d.ts.map +1 -0
- package/dist/saves.js +1004 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +1 -1
- package/dist/seed.d.ts +11 -2
- package/dist/seed.d.ts.map +1 -1
- package/dist/seed.js +71 -0
- package/dist/shared.d.ts +1 -1
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +9 -5
- package/dist/shown.d.ts +31 -0
- package/dist/shown.d.ts.map +1 -0
- package/dist/shown.js +294 -0
- package/dist/socket/admission.d.ts +7 -0
- package/dist/socket/admission.d.ts.map +1 -0
- package/dist/socket/admission.js +39 -0
- package/dist/socket/answers.d.ts +6 -0
- package/dist/socket/answers.d.ts.map +1 -0
- package/dist/socket/answers.js +20 -0
- package/dist/socket/lanes.d.ts +20 -0
- package/dist/socket/lanes.d.ts.map +1 -0
- package/dist/socket/lanes.js +77 -0
- package/dist/socket/reads.d.ts +10 -0
- package/dist/socket/reads.d.ts.map +1 -0
- package/dist/socket/reads.js +31 -0
- package/dist/socket/rooms.d.ts +43 -0
- package/dist/socket/rooms.d.ts.map +1 -0
- package/dist/socket/rooms.js +90 -0
- package/dist/socket/session.d.ts +39 -0
- package/dist/socket/session.d.ts.map +1 -0
- package/dist/socket/session.js +23 -0
- package/dist/socket.d.ts +70 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +175 -0
- package/dist/source.d.ts +61 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +81 -0
- package/dist/status.d.ts +0 -2
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +0 -6
- package/dist/store/fences.d.ts +16 -0
- package/dist/store/fences.d.ts.map +1 -0
- package/dist/store/fences.js +26 -0
- package/dist/store/installs.d.ts +30 -0
- package/dist/store/installs.d.ts.map +1 -0
- package/dist/store/installs.js +34 -0
- package/dist/store/readiness.d.ts +10 -0
- package/dist/store/readiness.d.ts.map +1 -0
- package/dist/store/readiness.js +52 -0
- package/dist/store/records.d.ts +212 -0
- package/dist/store/records.d.ts.map +1 -0
- package/dist/store/records.js +408 -0
- package/dist/store/room-held.d.ts +8 -0
- package/dist/store/room-held.d.ts.map +1 -0
- package/dist/store/room-held.js +17 -0
- package/dist/store/space.d.ts +11 -0
- package/dist/store/space.d.ts.map +1 -0
- package/dist/store/space.js +43 -0
- package/dist/store/watchers.d.ts +17 -0
- package/dist/store/watchers.d.ts.map +1 -0
- package/dist/store/watchers.js +57 -0
- package/dist/store/writes.d.ts +24 -0
- package/dist/store/writes.d.ts.map +1 -0
- package/dist/store/writes.js +125 -0
- package/dist/store.d.ts +107 -153
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +143 -396
- package/dist/stored.d.ts +58 -64
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +244 -156
- package/dist/surface.d.ts +88 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +222 -0
- package/dist/sync.d.ts +20 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +531 -0
- package/dist/tables.d.ts +111 -49
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +209 -54
- package/dist/tallies.d.ts +18 -0
- package/dist/tallies.d.ts.map +1 -0
- package/dist/tallies.js +129 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +7 -4
- package/dist/windows.d.ts +1 -12
- package/dist/windows.d.ts.map +1 -1
- package/dist/windows.js +2 -75
- package/dist/wire.d.ts +16 -1
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +6 -0
- package/package.json +2 -2
- package/dist/fence.d.ts +0 -6
- package/dist/fence.d.ts.map +0 -1
- package/dist/fence.js +0 -10
- package/dist/phrase.d.ts +0 -3
- package/dist/phrase.d.ts.map +0 -1
- package/dist/phrase.js +0 -8
package/dist/conversation.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { cursorOf, decodedCursor } from '@agentshouse/mdmodel';
|
|
1
2
|
import { conversationChangeSet } from './change-set.js';
|
|
3
|
+
import { heldFacts } from './conversation-row.js';
|
|
2
4
|
import { runtimeError } from './failure.js';
|
|
3
5
|
import { refusedForSpace } from './durability.js';
|
|
4
6
|
import { changeBatchIdentity, chatDraftRevision } from './identity.js';
|
|
5
7
|
import { OFFLINE } from './outcome.js';
|
|
8
|
+
import { jobsOf, runningLine } from './parts.js';
|
|
9
|
+
import { openQuestion, questionAsked } from './questions.js';
|
|
6
10
|
import { untilAnswered } from './recovery.js';
|
|
7
|
-
import { capped,
|
|
11
|
+
import { capped, FROM_START, messageOrder, precedes } from './windows.js';
|
|
8
12
|
const QUIET = {
|
|
9
13
|
turn: null,
|
|
10
14
|
questions: [],
|
|
@@ -33,6 +37,7 @@ export function unheldView(conversation) {
|
|
|
33
37
|
turn: null,
|
|
34
38
|
questions: [],
|
|
35
39
|
process: null,
|
|
40
|
+
processEnded: null,
|
|
36
41
|
commands: [],
|
|
37
42
|
options: [],
|
|
38
43
|
starting: null,
|
|
@@ -40,11 +45,14 @@ export function unheldView(conversation) {
|
|
|
40
45
|
link: null,
|
|
41
46
|
deliveryUnknown: [],
|
|
42
47
|
chatDraft: null,
|
|
48
|
+
jobs: [],
|
|
43
49
|
};
|
|
44
50
|
}
|
|
45
51
|
export const SESSION_STARTED = 'Session started';
|
|
46
52
|
const NEW_CHAT = 'new:';
|
|
47
53
|
export const HISTORY_CONVERSATIONS = 64;
|
|
54
|
+
// A row is read at a glance and each telling clones the list to every observing tab, while a running line changes at each Kit flush.
|
|
55
|
+
const ROW_INTERVAL_MS = 1_000;
|
|
48
56
|
export function newChat(agent) {
|
|
49
57
|
return `${NEW_CHAT}${agent}`;
|
|
50
58
|
}
|
|
@@ -219,7 +227,6 @@ function phraseOf(text) {
|
|
|
219
227
|
}
|
|
220
228
|
return text;
|
|
221
229
|
}
|
|
222
|
-
const EXPIRED = { kind: 'rejected', code: 'expired', fields: {}, retryable: false };
|
|
223
230
|
const DURABLE_WRITE = {
|
|
224
231
|
kind: 'rejected',
|
|
225
232
|
code: 'durable-write',
|
|
@@ -253,10 +260,6 @@ function returned(draft, submission, others) {
|
|
|
253
260
|
}, others);
|
|
254
261
|
}
|
|
255
262
|
export function createConversationStore(deps) {
|
|
256
|
-
const stored = new Set();
|
|
257
|
-
const reads = new Map();
|
|
258
|
-
const partials = new Set();
|
|
259
|
-
const drafts = new Map();
|
|
260
263
|
const sending = new Map();
|
|
261
264
|
const behind = new Set();
|
|
262
265
|
const catching = new Map();
|
|
@@ -264,15 +267,16 @@ export function createConversationStore(deps) {
|
|
|
264
267
|
const lives = new Map();
|
|
265
268
|
const unsent = new Map();
|
|
266
269
|
const views = new Map();
|
|
267
|
-
const
|
|
270
|
+
const heardNewest = new Map();
|
|
268
271
|
let relisting = null;
|
|
269
|
-
let listCursor = null;
|
|
270
272
|
const creations = new Set();
|
|
271
273
|
const listWatchers = new Set();
|
|
272
274
|
const unlisted = new Set();
|
|
273
275
|
let listKnown = false;
|
|
274
|
-
let
|
|
275
|
-
let
|
|
276
|
+
let listOwed = false;
|
|
277
|
+
let listTelling = false;
|
|
278
|
+
let rowTimer = null;
|
|
279
|
+
const closing = new AbortController();
|
|
276
280
|
const agentWatchers = new Set();
|
|
277
281
|
const unnamed = new Set();
|
|
278
282
|
let agentsShown = null;
|
|
@@ -283,8 +287,7 @@ export function createConversationStore(deps) {
|
|
|
283
287
|
function liveOf(conversation) {
|
|
284
288
|
return lives.get(conversation) ?? QUIET;
|
|
285
289
|
}
|
|
286
|
-
function viewOf(conversation, held, frame) {
|
|
287
|
-
const draft = drafts.get(conversation);
|
|
290
|
+
function viewOf(conversation, held, frame, draft, ended, marked) {
|
|
288
291
|
const facts = liveOf(conversation);
|
|
289
292
|
return {
|
|
290
293
|
conversation,
|
|
@@ -298,15 +301,17 @@ export function createConversationStore(deps) {
|
|
|
298
301
|
turn: structuredClone(facts.turn),
|
|
299
302
|
questions: structuredClone(facts.questions),
|
|
300
303
|
process: facts.process === null ? null : { ...facts.process },
|
|
304
|
+
processEnded: ended,
|
|
301
305
|
commands: structuredClone(facts.commands),
|
|
302
306
|
options: structuredClone(facts.options),
|
|
303
307
|
starting: facts.starting,
|
|
304
308
|
subagents: structuredClone(facts.subagents),
|
|
305
309
|
link: facts.link === null ? null : { ...facts.link },
|
|
306
310
|
deliveryUnknown: [...facts.deliveryUnknown],
|
|
307
|
-
chatDraft: draft ===
|
|
308
|
-
|
|
309
|
-
|
|
311
|
+
chatDraft: draft === null || unwritten(draft) ? null : { text: draft.text, revision: draft.revision },
|
|
312
|
+
jobs: facts.process?.running === false
|
|
313
|
+
? []
|
|
314
|
+
: jobsOf(marked.filter(({ at }) => ended === null || at > ended), facts.turn),
|
|
310
315
|
};
|
|
311
316
|
}
|
|
312
317
|
function emit(conversation) {
|
|
@@ -318,7 +323,7 @@ export function createConversationStore(deps) {
|
|
|
318
323
|
const ready = [...view.watchers].filter((watcher) => watcher.ready);
|
|
319
324
|
if (ready.length === 0)
|
|
320
325
|
continue;
|
|
321
|
-
const value = viewOf(conversation, view.window, sharedFrame(view, view.window));
|
|
326
|
+
const value = viewOf(conversation, view.window, sharedFrame(view, view.window), view.draft, view.ended, view.marked);
|
|
322
327
|
for (const watcher of ready)
|
|
323
328
|
watcher.notify(value);
|
|
324
329
|
}
|
|
@@ -328,11 +333,13 @@ export function createConversationStore(deps) {
|
|
|
328
333
|
}
|
|
329
334
|
async function slide(local, conversation, arriving) {
|
|
330
335
|
let count;
|
|
336
|
+
let marked;
|
|
331
337
|
for (const view of views.values()) {
|
|
332
338
|
if (view.conversation !== conversation || view.window === null)
|
|
333
339
|
continue;
|
|
334
340
|
if (arriving === null) {
|
|
335
341
|
view.window = [];
|
|
342
|
+
view.marked = [];
|
|
336
343
|
view.more = false;
|
|
337
344
|
if (view.total !== null)
|
|
338
345
|
view.total = 0;
|
|
@@ -342,6 +349,10 @@ export function createConversationStore(deps) {
|
|
|
342
349
|
const next = windowOf(view.window, joining, view.asked.limit);
|
|
343
350
|
view.window = next.messages;
|
|
344
351
|
view.more ||= next.dropped;
|
|
352
|
+
if (arriving.length > 0) {
|
|
353
|
+
marked ??= await local.jobMarkers(conversation);
|
|
354
|
+
view.marked = marked;
|
|
355
|
+
}
|
|
345
356
|
if (view.total !== null && arriving.length > 0) {
|
|
346
357
|
count ??= await local.messageCount(conversation);
|
|
347
358
|
view.total = count;
|
|
@@ -354,79 +365,179 @@ export function createConversationStore(deps) {
|
|
|
354
365
|
return 'asking';
|
|
355
366
|
return facts.turn === null ? 'idle' : 'working';
|
|
356
367
|
}
|
|
357
|
-
function
|
|
358
|
-
|
|
368
|
+
function rowOf(conversation) {
|
|
369
|
+
const turn = lives.get(conversation)?.turn ?? null;
|
|
370
|
+
return {
|
|
371
|
+
state: stateOf(conversation),
|
|
372
|
+
started: turn?.started ?? null,
|
|
373
|
+
line: turn === null ? null : runningLine(turn.parts),
|
|
374
|
+
question: openQuestion(liveOf(conversation).questions),
|
|
375
|
+
asked: questionAsked(liveOf(conversation).questions),
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
async function entries() {
|
|
379
|
+
const list = await heldList();
|
|
380
|
+
if (list === null)
|
|
381
|
+
return null;
|
|
382
|
+
const held = list.length === 0
|
|
383
|
+
? []
|
|
384
|
+
: await deps.durably((local) => local.conversationRows(list.map(({ conversation }) => conversation)));
|
|
385
|
+
const rows = new Map(held.map((one) => [one.conversation, one]));
|
|
386
|
+
return list.map((entry) => ({
|
|
359
387
|
conversation: entry.conversation,
|
|
360
|
-
agent: { identity: entry.agent, name: entry.agentName },
|
|
388
|
+
agent: { identity: entry.agent, name: entry.agentName, retired: entry.agentRetired },
|
|
361
389
|
name: entry.name,
|
|
362
390
|
created: entry.created,
|
|
363
391
|
finished: entry.finished,
|
|
364
392
|
outcome: entry.outcome,
|
|
365
393
|
waiting: entry.waiting,
|
|
366
|
-
|
|
367
|
-
|
|
394
|
+
...rowOf(entry.conversation),
|
|
395
|
+
...heldFacts(rows.get(entry.conversation), entry),
|
|
368
396
|
}));
|
|
369
397
|
}
|
|
370
|
-
function
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
398
|
+
async function heldList() {
|
|
399
|
+
const stored = (await (await deps.local()).facts()).conversationList;
|
|
400
|
+
if (stored !== null)
|
|
401
|
+
return stored;
|
|
402
|
+
return !listKnown && deps.stream() !== undefined && deps.online() ? null : [];
|
|
403
|
+
}
|
|
404
|
+
async function endedIn(conversation) {
|
|
405
|
+
const list = await heldList();
|
|
406
|
+
return list?.find((entry) => entry.conversation === conversation)?.processEnded ?? null;
|
|
407
|
+
}
|
|
408
|
+
function listChanged(change) {
|
|
409
|
+
void deps
|
|
410
|
+
.durably(async (local) => {
|
|
411
|
+
const { conversationList, conversationCursor } = await local.facts();
|
|
412
|
+
const kept = change.replacing ? [] : (conversationList ?? []);
|
|
413
|
+
const held = new Map(kept.map((entry) => [entry.conversation, entry]));
|
|
414
|
+
for (const entry of change.set) {
|
|
415
|
+
held.set(entry.conversation, { ...entry });
|
|
416
|
+
creations.delete(entry.conversation);
|
|
417
|
+
}
|
|
418
|
+
if (change.gone !== null)
|
|
419
|
+
held.delete(change.gone);
|
|
420
|
+
const list = [...held.values()];
|
|
421
|
+
if (JSON.stringify(list) !== JSON.stringify(conversationList)) {
|
|
422
|
+
await local.fact('conversationList', list);
|
|
423
|
+
}
|
|
424
|
+
if (change.cursor !== undefined) {
|
|
425
|
+
if (change.cursor !== conversationCursor) {
|
|
426
|
+
await local.fact('conversationCursor', change.cursor);
|
|
427
|
+
}
|
|
428
|
+
deps.stream()?.hold(change.cursor);
|
|
429
|
+
}
|
|
430
|
+
return list;
|
|
431
|
+
})
|
|
432
|
+
.catch(async () => (await (await deps.local()).facts()).conversationList ?? [])
|
|
433
|
+
.then((list) => {
|
|
434
|
+
if (deps.closed() || change.paged === true)
|
|
377
435
|
return;
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
|
|
436
|
+
endedAnew(list);
|
|
437
|
+
if (change.cursor !== undefined) {
|
|
438
|
+
listKnown = true;
|
|
439
|
+
settleBehind(list);
|
|
440
|
+
openingEnded();
|
|
441
|
+
deps.settled();
|
|
442
|
+
}
|
|
443
|
+
emitList();
|
|
444
|
+
if (!listKnown)
|
|
445
|
+
return;
|
|
446
|
+
retiredDrafts(list);
|
|
447
|
+
if (change.cursor === undefined &&
|
|
448
|
+
(list.length !== replicated.size ||
|
|
449
|
+
list.some(({ conversation }) => !replicated.has(conversation)))) {
|
|
450
|
+
deps.again();
|
|
451
|
+
}
|
|
452
|
+
}, () => { });
|
|
453
|
+
}
|
|
454
|
+
function endedAnew(list) {
|
|
455
|
+
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
456
|
+
for (const view of views.values()) {
|
|
457
|
+
const ended = entries.get(view.conversation)?.processEnded ?? null;
|
|
458
|
+
if (view.window === null || ended === view.ended)
|
|
459
|
+
continue;
|
|
460
|
+
view.ended = ended;
|
|
461
|
+
emit(view.conversation);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
let listShown = Promise.resolve();
|
|
465
|
+
function shownList(work) {
|
|
466
|
+
const reading = heldList();
|
|
467
|
+
listShown = listShown.then(async () => {
|
|
468
|
+
const list = await reading.catch(() => null);
|
|
469
|
+
if (list === null || deps.closed())
|
|
470
|
+
return;
|
|
471
|
+
work(list);
|
|
386
472
|
});
|
|
387
473
|
}
|
|
388
|
-
function
|
|
389
|
-
|
|
390
|
-
|
|
474
|
+
async function told() {
|
|
475
|
+
try {
|
|
476
|
+
while (listOwed && !deps.closed()) {
|
|
477
|
+
listOwed = false;
|
|
478
|
+
const value = await untilAnswered(entries, closing.signal);
|
|
479
|
+
if (deps.closed())
|
|
480
|
+
return;
|
|
481
|
+
if (value === null)
|
|
482
|
+
continue;
|
|
483
|
+
for (const watcher of listWatchers)
|
|
484
|
+
watcher(value);
|
|
485
|
+
for (const watcher of [...unlisted]) {
|
|
486
|
+
unlisted.delete(watcher);
|
|
487
|
+
listWatchers.add(watcher);
|
|
488
|
+
watcher(value);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
finally {
|
|
493
|
+
listTelling = false;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function tellList() {
|
|
497
|
+
if (deps.closed() || (listWatchers.size === 0 && unlisted.size === 0))
|
|
498
|
+
return;
|
|
499
|
+
listOwed = true;
|
|
500
|
+
if (listTelling)
|
|
501
|
+
return;
|
|
502
|
+
listTelling = true;
|
|
503
|
+
void told().catch(() => { });
|
|
504
|
+
}
|
|
505
|
+
function tellSoon() {
|
|
506
|
+
if (rowTimer !== null)
|
|
507
|
+
return;
|
|
508
|
+
rowTimer = setTimeout(() => {
|
|
509
|
+
rowTimer = null;
|
|
510
|
+
tellList();
|
|
511
|
+
}, ROW_INTERVAL_MS);
|
|
391
512
|
}
|
|
392
513
|
function emitList() {
|
|
393
514
|
if (deps.closed())
|
|
394
515
|
return;
|
|
395
|
-
|
|
396
|
-
const value = entries();
|
|
397
|
-
for (const watcher of listWatchers)
|
|
398
|
-
watcher(value);
|
|
399
|
-
}
|
|
516
|
+
tellList();
|
|
400
517
|
emitAgents();
|
|
401
518
|
learned();
|
|
402
519
|
}
|
|
403
520
|
function learned() {
|
|
404
521
|
if (deps.closed())
|
|
405
522
|
return;
|
|
406
|
-
if (
|
|
523
|
+
if (unlisted.size > 0)
|
|
524
|
+
tellList();
|
|
525
|
+
if (unnamed.size === 0)
|
|
407
526
|
return;
|
|
408
|
-
|
|
409
|
-
const value =
|
|
410
|
-
for (const watcher of [...unlisted]) {
|
|
411
|
-
unlisted.delete(watcher);
|
|
412
|
-
listWatchers.add(watcher);
|
|
413
|
-
watcher(value);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
if (unnamed.size > 0) {
|
|
417
|
-
const value = agents();
|
|
527
|
+
shownList((list) => {
|
|
528
|
+
const value = agents(list);
|
|
418
529
|
for (const watcher of [...unnamed]) {
|
|
419
530
|
unnamed.delete(watcher);
|
|
420
531
|
agentWatchers.add(watcher);
|
|
421
532
|
watcher(value);
|
|
422
533
|
}
|
|
423
|
-
}
|
|
534
|
+
});
|
|
424
535
|
}
|
|
425
|
-
function agents() {
|
|
536
|
+
function agents(list) {
|
|
426
537
|
const named = new Map();
|
|
427
538
|
for (const agent of listedAgents ?? [])
|
|
428
539
|
named.set(agent.agent, agent);
|
|
429
|
-
for (const entry of
|
|
540
|
+
for (const entry of list) {
|
|
430
541
|
named.set(entry.agent, { name: entry.agentName, retired: entry.agentRetired });
|
|
431
542
|
}
|
|
432
543
|
return [...named]
|
|
@@ -456,31 +567,35 @@ export function createConversationStore(deps) {
|
|
|
456
567
|
function emitAgents() {
|
|
457
568
|
if (deps.closed() || agentWatchers.size === 0)
|
|
458
569
|
return;
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
watcher
|
|
570
|
+
shownList((list) => {
|
|
571
|
+
const value = agents(list);
|
|
572
|
+
const shown = JSON.stringify(value);
|
|
573
|
+
if (shown === agentsShown)
|
|
574
|
+
return;
|
|
575
|
+
agentsShown = shown;
|
|
576
|
+
for (const watcher of agentWatchers)
|
|
577
|
+
watcher(value);
|
|
578
|
+
});
|
|
466
579
|
}
|
|
467
580
|
function setLive(conversation, next) {
|
|
468
|
-
const before =
|
|
469
|
-
const began = lives.get(conversation)?.turn?.started;
|
|
581
|
+
const before = rowOf(conversation);
|
|
470
582
|
if (next === null)
|
|
471
583
|
lives.delete(conversation);
|
|
472
584
|
else
|
|
473
585
|
lives.set(conversation, next);
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
if (stateOf(conversation) !== before || next?.turn?.started !== began)
|
|
586
|
+
const after = rowOf(conversation);
|
|
587
|
+
if (after.state !== before.state || after.started !== before.started)
|
|
477
588
|
emitList();
|
|
589
|
+
else if (after.line !== before.line ||
|
|
590
|
+
after.question !== before.question ||
|
|
591
|
+
after.asked !== before.asked)
|
|
592
|
+
tellSoon();
|
|
478
593
|
}
|
|
479
|
-
function retiredChat(conversation) {
|
|
594
|
+
function retiredChat(conversation, list) {
|
|
480
595
|
if (!conversation.startsWith(NEW_CHAT))
|
|
481
596
|
return false;
|
|
482
597
|
const agent = conversation.slice(NEW_CHAT.length);
|
|
483
|
-
return
|
|
598
|
+
return list.some((entry) => entry.agent === agent && entry.agentRetired);
|
|
484
599
|
}
|
|
485
600
|
function live(conversation, change) {
|
|
486
601
|
const owed = unsent.get(conversation);
|
|
@@ -538,17 +653,23 @@ export function createConversationStore(deps) {
|
|
|
538
653
|
}
|
|
539
654
|
async function remove(leaving) {
|
|
540
655
|
await deps.durably(async (local) => {
|
|
656
|
+
const kept = new Set([
|
|
657
|
+
...(await local.conversations(leaving)).map(({ conversation }) => conversation),
|
|
658
|
+
...(await local.chatDrafts())
|
|
659
|
+
.filter(({ conversation }) => leaving.includes(conversation))
|
|
660
|
+
.map(({ conversation }) => conversation),
|
|
661
|
+
]);
|
|
541
662
|
await local.dropConversations(leaving);
|
|
542
663
|
const changed = [];
|
|
543
664
|
for (const conversation of leaving) {
|
|
544
|
-
if (
|
|
665
|
+
if (kept.has(conversation) || lives.has(conversation))
|
|
545
666
|
changed.push(conversation);
|
|
667
|
+
for (const view of views.values()) {
|
|
668
|
+
if (view.conversation === conversation)
|
|
669
|
+
view.draft = null;
|
|
546
670
|
}
|
|
547
|
-
stored.delete(conversation);
|
|
548
|
-
reads.delete(conversation);
|
|
549
|
-
partials.delete(conversation);
|
|
550
|
-
drafts.delete(conversation);
|
|
551
671
|
behind.delete(conversation);
|
|
672
|
+
heardNewest.delete(conversation);
|
|
552
673
|
unsent.delete(conversation);
|
|
553
674
|
setLive(conversation, null);
|
|
554
675
|
await slide(local, conversation, null);
|
|
@@ -557,19 +678,68 @@ export function createConversationStore(deps) {
|
|
|
557
678
|
deps.publish(conversationChangeSet(changed));
|
|
558
679
|
});
|
|
559
680
|
}
|
|
560
|
-
function
|
|
561
|
-
|
|
562
|
-
|
|
681
|
+
function newestOfListed(entry) {
|
|
682
|
+
if (entry === undefined)
|
|
683
|
+
return undefined;
|
|
684
|
+
const heard = heardNewest.get(entry.conversation);
|
|
685
|
+
if (heard === undefined)
|
|
686
|
+
return entry.newest;
|
|
687
|
+
return entry.newest === null || heard > entry.newest ? heard : entry.newest;
|
|
688
|
+
}
|
|
689
|
+
function missed(conversation, held, entry) {
|
|
690
|
+
const read = held?.read;
|
|
691
|
+
const newest = newestOfListed(entry);
|
|
563
692
|
return (read === undefined ||
|
|
564
693
|
newest === undefined ||
|
|
565
|
-
|
|
694
|
+
held?.partial === true ||
|
|
566
695
|
(newest !== null && (read === null || newest > read)));
|
|
567
696
|
}
|
|
568
|
-
function
|
|
569
|
-
|
|
570
|
-
|
|
697
|
+
async function readsOf(local, conversations) {
|
|
698
|
+
return new Map((await local.conversations(conversations)).map((held) => [held.conversation, held]));
|
|
699
|
+
}
|
|
700
|
+
function retiredDrafts(list) {
|
|
701
|
+
if (!list.some((entry) => entry.agentRetired))
|
|
571
702
|
return;
|
|
572
|
-
|
|
703
|
+
void deps
|
|
704
|
+
.local()
|
|
705
|
+
.then((local) => local.chatDrafts())
|
|
706
|
+
.then((held) => {
|
|
707
|
+
if (!deps.closed() && held.some(({ conversation }) => retiredChat(conversation, list))) {
|
|
708
|
+
deps.again();
|
|
709
|
+
}
|
|
710
|
+
}, () => { });
|
|
711
|
+
}
|
|
712
|
+
function settleBehind(list) {
|
|
713
|
+
void deps
|
|
714
|
+
.durably(async (local) => {
|
|
715
|
+
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
716
|
+
const named = [...replicated].filter((conversation) => entries.has(conversation));
|
|
717
|
+
const held = await readsOf(local, named);
|
|
718
|
+
let owed = false;
|
|
719
|
+
for (const conversation of named) {
|
|
720
|
+
if (!missed(conversation, held.get(conversation), entries.get(conversation))) {
|
|
721
|
+
behind.delete(conversation);
|
|
722
|
+
}
|
|
723
|
+
else if (!behind.has(conversation)) {
|
|
724
|
+
gap(conversation);
|
|
725
|
+
owed = true;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return owed;
|
|
729
|
+
})
|
|
730
|
+
.then((owed) => {
|
|
731
|
+
if (deps.closed())
|
|
732
|
+
return;
|
|
733
|
+
deps.settled();
|
|
734
|
+
if (owed)
|
|
735
|
+
deps.again();
|
|
736
|
+
}, () => { });
|
|
737
|
+
}
|
|
738
|
+
function noted(conversation, message) {
|
|
739
|
+
const heard = heardNewest.get(conversation);
|
|
740
|
+
if (heard === undefined || message.position > heard) {
|
|
741
|
+
heardNewest.set(conversation, message.position);
|
|
742
|
+
}
|
|
573
743
|
}
|
|
574
744
|
function gap(conversation) {
|
|
575
745
|
gaps.set(conversation, (gaps.get(conversation) ?? 0) + 1);
|
|
@@ -579,7 +749,7 @@ export function createConversationStore(deps) {
|
|
|
579
749
|
return deps.durably(async (local) => {
|
|
580
750
|
if (!replicated.has(conversation))
|
|
581
751
|
return;
|
|
582
|
-
const read =
|
|
752
|
+
const read = (await readsOf(local, [conversation])).get(conversation)?.read;
|
|
583
753
|
const advances = read !== undefined &&
|
|
584
754
|
!behind.has(conversation) &&
|
|
585
755
|
(read === null || message.position > read);
|
|
@@ -589,19 +759,18 @@ export function createConversationStore(deps) {
|
|
|
589
759
|
messages: [message],
|
|
590
760
|
...(advances ? { read: { at: message.position, partial: false } } : {}),
|
|
591
761
|
});
|
|
592
|
-
stored.add(conversation);
|
|
593
|
-
if (advances)
|
|
594
|
-
reads.set(conversation, message.position);
|
|
595
762
|
sealTurns(conversation, new Set([message.turn]));
|
|
596
763
|
await slide(local, conversation, [message]);
|
|
597
764
|
deps.publish(conversationChangeSet([conversation]));
|
|
765
|
+
tellList();
|
|
598
766
|
});
|
|
599
767
|
}
|
|
600
768
|
async function readHistories(conversations, ended) {
|
|
601
769
|
const generations = new Map(conversations.map((one) => [one, gaps.get(one) ?? 0]));
|
|
770
|
+
const held = await readsOf(await deps.local(), conversations);
|
|
602
771
|
let waiting = conversations.map((conversation) => ({
|
|
603
772
|
conversation,
|
|
604
|
-
after:
|
|
773
|
+
after: held.get(conversation)?.read ?? undefined,
|
|
605
774
|
}));
|
|
606
775
|
while (waiting.length > 0) {
|
|
607
776
|
const asking = waiting.slice(0, HISTORY_CONVERSATIONS);
|
|
@@ -657,15 +826,10 @@ export function createConversationStore(deps) {
|
|
|
657
826
|
return;
|
|
658
827
|
const whole = next === undefined;
|
|
659
828
|
const cursor = next ?? newestOf(arriving, from);
|
|
660
|
-
const
|
|
829
|
+
const held = (await readsOf(local, [conversation])).get(conversation);
|
|
830
|
+
const partial = !whole && (held?.partial === true || held?.read === undefined);
|
|
661
831
|
const sealing = await sealed(local, conversation, new Set(arriving.map((message) => message.turn)));
|
|
662
832
|
await local.keepMessages({ conversation, messages: arriving, read: { at: cursor, partial } });
|
|
663
|
-
stored.add(conversation);
|
|
664
|
-
reads.set(conversation, cursor);
|
|
665
|
-
if (partial)
|
|
666
|
-
partials.add(conversation);
|
|
667
|
-
else
|
|
668
|
-
partials.delete(conversation);
|
|
669
833
|
sealTurns(conversation, new Set(arriving.map((message) => message.turn)));
|
|
670
834
|
if (whole && (gaps.get(conversation) ?? 0) === generation)
|
|
671
835
|
behind.delete(conversation);
|
|
@@ -673,6 +837,8 @@ export function createConversationStore(deps) {
|
|
|
673
837
|
if (arriving.length > 0 || sealing || whole) {
|
|
674
838
|
deps.publish(conversationChangeSet([conversation]));
|
|
675
839
|
}
|
|
840
|
+
if (arriving.length > 0)
|
|
841
|
+
tellSoon();
|
|
676
842
|
});
|
|
677
843
|
}
|
|
678
844
|
function heard(event) {
|
|
@@ -739,17 +905,24 @@ export function createConversationStore(deps) {
|
|
|
739
905
|
emit(conversation);
|
|
740
906
|
}
|
|
741
907
|
async function kept(local, conversation, following) {
|
|
742
|
-
|
|
908
|
+
const shown = following === null || empty(following) ? null : following;
|
|
909
|
+
if (shown === null)
|
|
743
910
|
await local.dropChatDraft(conversation);
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
911
|
+
else
|
|
912
|
+
await local.keepChatDrafts([shown]);
|
|
913
|
+
shownDraft(conversation, shown);
|
|
914
|
+
}
|
|
915
|
+
function shownDraft(conversation, draft) {
|
|
916
|
+
for (const view of views.values()) {
|
|
917
|
+
if (view.conversation === conversation)
|
|
918
|
+
view.draft = draft;
|
|
749
919
|
}
|
|
750
920
|
}
|
|
921
|
+
async function draftAt(local, conversation) {
|
|
922
|
+
return (await local.chatDraft(conversation)) ?? undefined;
|
|
923
|
+
}
|
|
751
924
|
async function sealed(local, conversation, turns) {
|
|
752
|
-
const held =
|
|
925
|
+
const held = await draftAt(local, conversation);
|
|
753
926
|
const submitted = held?.submitted ?? [];
|
|
754
927
|
const left = submitted.filter((one) => one.turn === null || !turns.has(one.turn));
|
|
755
928
|
if (held === undefined || left.length === submitted.length)
|
|
@@ -760,8 +933,8 @@ export function createConversationStore(deps) {
|
|
|
760
933
|
function moved(agent, operation, to) {
|
|
761
934
|
const from = newChat(agent);
|
|
762
935
|
return deps.durably(async (local) => {
|
|
763
|
-
const held =
|
|
764
|
-
const earlier =
|
|
936
|
+
const held = await draftAt(local, from);
|
|
937
|
+
const earlier = held?.moves ?? [];
|
|
765
938
|
if (earlier.includes(operation))
|
|
766
939
|
return;
|
|
767
940
|
const blank = {
|
|
@@ -770,18 +943,20 @@ export function createConversationStore(deps) {
|
|
|
770
943
|
revision: chatDraftRevision(),
|
|
771
944
|
};
|
|
772
945
|
const { moves: _answered, ...unsent } = held ?? blank;
|
|
773
|
-
const taken =
|
|
946
|
+
const taken = (await draftAt(local, to)) !== undefined || empty(unsent)
|
|
947
|
+
? []
|
|
948
|
+
: [{ ...unsent, conversation: to }];
|
|
774
949
|
const left = { ...(taken.length === 0 ? unsent : blank), moves: [...earlier, operation] };
|
|
775
950
|
await local.keepChatDrafts([left, ...taken]);
|
|
776
|
-
|
|
951
|
+
shownDraft(from, left);
|
|
777
952
|
for (const one of taken)
|
|
778
|
-
|
|
953
|
+
shownDraft(to, one);
|
|
779
954
|
deps.publish(conversationChangeSet([from, to]));
|
|
780
955
|
});
|
|
781
956
|
}
|
|
782
957
|
function withDraft(conversation, next) {
|
|
783
958
|
return deps.durably(async (local) => {
|
|
784
|
-
const following = await next(
|
|
959
|
+
const following = await next(await draftAt(local, conversation), local);
|
|
785
960
|
if (following === undefined)
|
|
786
961
|
return;
|
|
787
962
|
await kept(local, conversation, following);
|
|
@@ -790,10 +965,8 @@ export function createConversationStore(deps) {
|
|
|
790
965
|
}
|
|
791
966
|
async function submitted(conversation, operation, draft) {
|
|
792
967
|
let submission;
|
|
793
|
-
let earlier = false;
|
|
794
968
|
await withDraft(conversation, (current) => {
|
|
795
969
|
submission = current?.submitted?.find((one) => one.operation === operation);
|
|
796
|
-
earlier = submission !== undefined;
|
|
797
970
|
if (submission !== undefined)
|
|
798
971
|
return undefined;
|
|
799
972
|
const said = draft ?? current;
|
|
@@ -806,15 +979,7 @@ export function createConversationStore(deps) {
|
|
|
806
979
|
submitted: [...(current?.submitted ?? []), submission],
|
|
807
980
|
};
|
|
808
981
|
});
|
|
809
|
-
return
|
|
810
|
-
}
|
|
811
|
-
function forgotten(conversation, submission) {
|
|
812
|
-
return withDraft(conversation, (current) => {
|
|
813
|
-
const held = current?.submitted ?? [];
|
|
814
|
-
if (current === undefined || !held.includes(submission))
|
|
815
|
-
return undefined;
|
|
816
|
-
return withSubmitted(current, held.filter((one) => one !== submission));
|
|
817
|
-
});
|
|
982
|
+
return submission;
|
|
818
983
|
}
|
|
819
984
|
async function dispatched(conversation, submission) {
|
|
820
985
|
const dispatch = { answered: false };
|
|
@@ -873,7 +1038,8 @@ export function createConversationStore(deps) {
|
|
|
873
1038
|
return deps.durably(async (local) => {
|
|
874
1039
|
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before, phrase);
|
|
875
1040
|
const total = asked.total ? await local.messageCount(conversation, phrase) : null;
|
|
876
|
-
|
|
1041
|
+
const marked = await local.jobMarkers(conversation);
|
|
1042
|
+
return structuredClone(viewOf(conversation, messages, frameOf(asked, messages, more, total), (await local.chatDraft(conversation)) ?? null, await endedIn(conversation), marked));
|
|
877
1043
|
});
|
|
878
1044
|
},
|
|
879
1045
|
async create(input) {
|
|
@@ -881,8 +1047,10 @@ export function createConversationStore(deps) {
|
|
|
881
1047
|
const conversation = answered(result, 'conversation_id');
|
|
882
1048
|
if (conversation === null)
|
|
883
1049
|
return result;
|
|
884
|
-
|
|
1050
|
+
const listed = (await heldList()) ?? [];
|
|
1051
|
+
if (!listed.some((entry) => entry.conversation === conversation)) {
|
|
885
1052
|
creations.add(conversation);
|
|
1053
|
+
}
|
|
886
1054
|
const creation = creationOf(input);
|
|
887
1055
|
if (creation !== null)
|
|
888
1056
|
await moved(creation.agent, creation.operation, conversation);
|
|
@@ -899,11 +1067,7 @@ export function createConversationStore(deps) {
|
|
|
899
1067
|
});
|
|
900
1068
|
if (held === null)
|
|
901
1069
|
return DURABLE_WRITE;
|
|
902
|
-
|
|
903
|
-
if (!earlier || !deps.expired(operation))
|
|
904
|
-
return dispatched(conversation, submission);
|
|
905
|
-
await forgotten(conversation, submission);
|
|
906
|
-
return EXPIRED;
|
|
1070
|
+
return dispatched(conversation, held);
|
|
907
1071
|
}
|
|
908
1072
|
if (draft !== undefined) {
|
|
909
1073
|
await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
|
|
@@ -954,43 +1118,40 @@ export function createConversationStore(deps) {
|
|
|
954
1118
|
return {
|
|
955
1119
|
surface,
|
|
956
1120
|
chatDraft,
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
listCursor = cursor;
|
|
964
|
-
deps.stream()?.hold(cursor);
|
|
965
|
-
}
|
|
966
|
-
stored.clear();
|
|
967
|
-
reads.clear();
|
|
968
|
-
partials.clear();
|
|
969
|
-
for (const entry of held) {
|
|
970
|
-
stored.add(entry.conversation);
|
|
971
|
-
if (entry.read !== undefined)
|
|
972
|
-
reads.set(entry.conversation, entry.read);
|
|
973
|
-
if (entry.partial)
|
|
974
|
-
partials.add(entry.conversation);
|
|
975
|
-
}
|
|
976
|
-
drafts.clear();
|
|
977
|
-
for (const record of kept)
|
|
978
|
-
drafts.set(record.conversation, record);
|
|
979
|
-
if (listHeld)
|
|
980
|
-
learned();
|
|
1121
|
+
async opened(local) {
|
|
1122
|
+
const { conversationList, conversationCursor } = await local.facts();
|
|
1123
|
+
if (conversationList === null || listKnown)
|
|
1124
|
+
return;
|
|
1125
|
+
deps.stream()?.hold(conversationCursor);
|
|
1126
|
+
learned();
|
|
981
1127
|
},
|
|
982
1128
|
async reconcile() {
|
|
983
1129
|
if (!listKnown)
|
|
984
1130
|
return;
|
|
985
|
-
const
|
|
1131
|
+
const local = await deps.local();
|
|
1132
|
+
const [held, kept, { conversationList }] = await Promise.all([
|
|
1133
|
+
local.conversations(),
|
|
1134
|
+
local.chatDrafts(),
|
|
1135
|
+
local.facts(),
|
|
1136
|
+
]);
|
|
1137
|
+
const list = conversationList ?? [];
|
|
1138
|
+
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
1139
|
+
const named = new Set(entries.keys());
|
|
1140
|
+
const reads = new Map(held.map((one) => [one.conversation, one]));
|
|
986
1141
|
const leaving = [
|
|
987
|
-
...new Set([
|
|
1142
|
+
...new Set([
|
|
1143
|
+
...replicated,
|
|
1144
|
+
...reads.keys(),
|
|
1145
|
+
...kept.map(({ conversation }) => conversation),
|
|
1146
|
+
]),
|
|
988
1147
|
].filter((conversation) => !named.has(conversation) &&
|
|
989
1148
|
!creations.has(conversation) &&
|
|
990
|
-
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation)));
|
|
1149
|
+
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation, list)));
|
|
991
1150
|
for (const conversation of named) {
|
|
992
|
-
if (!replicated.has(conversation) &&
|
|
1151
|
+
if (!replicated.has(conversation) &&
|
|
1152
|
+
missed(conversation, reads.get(conversation), entries.get(conversation))) {
|
|
993
1153
|
behind.add(conversation);
|
|
1154
|
+
}
|
|
994
1155
|
}
|
|
995
1156
|
replicated = named;
|
|
996
1157
|
handReplicated();
|
|
@@ -1021,16 +1182,16 @@ export function createConversationStore(deps) {
|
|
|
1021
1182
|
progress.complete = false;
|
|
1022
1183
|
},
|
|
1023
1184
|
async resend(progress) {
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1185
|
+
const local = await deps.local();
|
|
1186
|
+
const tried = new Set();
|
|
1187
|
+
for (const { conversation } of await local.chatDrafts()) {
|
|
1188
|
+
for (;;) {
|
|
1189
|
+
const submission = (await local.chatDraft(conversation))?.submitted?.find((one) => one.turn === null && !sending.has(one.operation) && !tried.has(one.operation));
|
|
1190
|
+
if (submission === undefined)
|
|
1191
|
+
break;
|
|
1028
1192
|
if (deps.closed())
|
|
1029
1193
|
return;
|
|
1030
|
-
|
|
1031
|
-
await forgotten(conversation, submission);
|
|
1032
|
-
continue;
|
|
1033
|
-
}
|
|
1194
|
+
tried.add(submission.operation);
|
|
1034
1195
|
const result = await dispatched(conversation, submission);
|
|
1035
1196
|
if (result.kind === 'revoked-authorization')
|
|
1036
1197
|
return;
|
|
@@ -1068,6 +1229,9 @@ export function createConversationStore(deps) {
|
|
|
1068
1229
|
asked,
|
|
1069
1230
|
watchers: new Set(),
|
|
1070
1231
|
window: null,
|
|
1232
|
+
draft: null,
|
|
1233
|
+
ended: null,
|
|
1234
|
+
marked: [],
|
|
1071
1235
|
more: false,
|
|
1072
1236
|
total: null,
|
|
1073
1237
|
};
|
|
@@ -1079,7 +1243,10 @@ export function createConversationStore(deps) {
|
|
|
1079
1243
|
if (view.window !== null)
|
|
1080
1244
|
return;
|
|
1081
1245
|
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
1246
|
+
view.draft = (await local.chatDraft(conversation)) ?? null;
|
|
1247
|
+
view.ended = await endedIn(conversation);
|
|
1082
1248
|
view.window = messages;
|
|
1249
|
+
view.marked = await local.jobMarkers(conversation);
|
|
1083
1250
|
view.more = more;
|
|
1084
1251
|
view.total = asked.total ? await local.messageCount(conversation) : null;
|
|
1085
1252
|
}), reading.signal)
|
|
@@ -1088,7 +1255,7 @@ export function createConversationStore(deps) {
|
|
|
1088
1255
|
return;
|
|
1089
1256
|
watcher.ready = true;
|
|
1090
1257
|
const window = view.window ?? [];
|
|
1091
|
-
watcher.notify(viewOf(conversation, window, sharedFrame(view, window)));
|
|
1258
|
+
watcher.notify(viewOf(conversation, window, sharedFrame(view, window), view.draft, view.ended, view.marked));
|
|
1092
1259
|
})
|
|
1093
1260
|
.catch(() => { });
|
|
1094
1261
|
return () => {
|
|
@@ -1123,58 +1290,43 @@ export function createConversationStore(deps) {
|
|
|
1123
1290
|
},
|
|
1124
1291
|
receive(event) {
|
|
1125
1292
|
if (deps.closed())
|
|
1126
|
-
return
|
|
1127
|
-
if (event.kind === 'list'
|
|
1128
|
-
if (event.
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
for (const entry of event.entries)
|
|
1132
|
-
|
|
1133
|
-
listed(entry);
|
|
1134
|
-
else
|
|
1135
|
-
relisting.set(entry.conversation, { ...entry });
|
|
1136
|
-
}
|
|
1137
|
-
if (event.more)
|
|
1138
|
-
return false;
|
|
1139
|
-
if (relisting !== null) {
|
|
1140
|
-
listing.clear();
|
|
1141
|
-
for (const entry of relisting.values())
|
|
1142
|
-
listed(entry);
|
|
1143
|
-
relisting = null;
|
|
1144
|
-
}
|
|
1145
|
-
listCursor = event.cursor;
|
|
1146
|
-
deps.stream()?.hold(event.cursor);
|
|
1147
|
-
listKnown = true;
|
|
1148
|
-
for (const conversation of replicated) {
|
|
1149
|
-
if (!listing.has(conversation))
|
|
1150
|
-
continue;
|
|
1151
|
-
if (!missed(conversation))
|
|
1152
|
-
behind.delete(conversation);
|
|
1153
|
-
else if (!behind.has(conversation))
|
|
1154
|
-
gap(conversation);
|
|
1155
|
-
}
|
|
1156
|
-
openingEnded();
|
|
1157
|
-
}
|
|
1158
|
-
else if (event.kind === 'listed') {
|
|
1159
|
-
listed(event.entry);
|
|
1160
|
-
relisting?.set(event.entry.conversation, { ...event.entry });
|
|
1161
|
-
}
|
|
1162
|
-
else {
|
|
1163
|
-
listing.delete(event.conversation);
|
|
1164
|
-
relisting?.delete(event.conversation);
|
|
1293
|
+
return;
|
|
1294
|
+
if (event.kind === 'list') {
|
|
1295
|
+
if (event.whole)
|
|
1296
|
+
relisting ??= new Map();
|
|
1297
|
+
if (relisting !== null) {
|
|
1298
|
+
for (const entry of event.entries)
|
|
1299
|
+
relisting.set(entry.conversation, { ...entry });
|
|
1165
1300
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1301
|
+
if (event.more && relisting !== null)
|
|
1302
|
+
return;
|
|
1303
|
+
const whole = relisting;
|
|
1304
|
+
relisting = null;
|
|
1305
|
+
listChanged({
|
|
1306
|
+
replacing: whole !== null,
|
|
1307
|
+
set: whole === null ? event.entries : [...whole.values()],
|
|
1308
|
+
gone: null,
|
|
1309
|
+
...(event.more ? { paged: true } : { cursor: event.cursor }),
|
|
1310
|
+
});
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
if (event.kind === 'listed') {
|
|
1314
|
+
relisting?.set(event.entry.conversation, { ...event.entry });
|
|
1315
|
+
listChanged({ replacing: false, set: [event.entry], gone: null });
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
if (event.kind === 'unlisted') {
|
|
1319
|
+
relisting?.delete(event.conversation);
|
|
1320
|
+
listChanged({ replacing: false, set: [], gone: event.conversation });
|
|
1321
|
+
return;
|
|
1173
1322
|
}
|
|
1174
1323
|
heard(event);
|
|
1175
|
-
return false;
|
|
1176
1324
|
},
|
|
1177
1325
|
close() {
|
|
1326
|
+
closing.abort();
|
|
1327
|
+
if (rowTimer !== null)
|
|
1328
|
+
clearTimeout(rowTimer);
|
|
1329
|
+
rowTimer = null;
|
|
1178
1330
|
views.clear();
|
|
1179
1331
|
lives.clear();
|
|
1180
1332
|
unsent.clear();
|