@agentshouse/mdruntime 0.1.0-cd9e28a590f84 → 0.1.0-cdded6c080913
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 +366 -216
- 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 +22 -15
- 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 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- 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 +33 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +54 -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 +5 -4
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +62 -20
- 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/observation.d.ts +2 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +7 -2
- 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 +12 -10
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +165 -109
- 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 +50 -18
- 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 +11 -8
- 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/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 +110 -48
- 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,21 +45,22 @@ 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
|
}
|
|
51
59
|
function creationOf(input) {
|
|
52
60
|
if (typeof input !== 'object' || input === null)
|
|
53
61
|
return null;
|
|
54
|
-
const { agent_id: agent, operation_id: operation
|
|
55
|
-
return typeof agent === 'string' && typeof operation === 'string'
|
|
56
|
-
? { agent, operation }
|
|
57
|
-
: null;
|
|
62
|
+
const { agent_id: agent, operation_id: operation } = input;
|
|
63
|
+
return typeof agent === 'string' && typeof operation === 'string' ? { agent, operation } : null;
|
|
58
64
|
}
|
|
59
65
|
function startedTurn(turn, operation) {
|
|
60
66
|
if (operation.op === 'begin')
|
|
@@ -221,7 +227,6 @@ function phraseOf(text) {
|
|
|
221
227
|
}
|
|
222
228
|
return text;
|
|
223
229
|
}
|
|
224
|
-
const EXPIRED = { kind: 'rejected', code: 'expired', fields: {}, retryable: false };
|
|
225
230
|
const DURABLE_WRITE = {
|
|
226
231
|
kind: 'rejected',
|
|
227
232
|
code: 'durable-write',
|
|
@@ -255,10 +260,6 @@ function returned(draft, submission, others) {
|
|
|
255
260
|
}, others);
|
|
256
261
|
}
|
|
257
262
|
export function createConversationStore(deps) {
|
|
258
|
-
const stored = new Set();
|
|
259
|
-
const reads = new Map();
|
|
260
|
-
const partials = new Set();
|
|
261
|
-
const drafts = new Map();
|
|
262
263
|
const sending = new Map();
|
|
263
264
|
const behind = new Set();
|
|
264
265
|
const catching = new Map();
|
|
@@ -266,15 +267,16 @@ export function createConversationStore(deps) {
|
|
|
266
267
|
const lives = new Map();
|
|
267
268
|
const unsent = new Map();
|
|
268
269
|
const views = new Map();
|
|
269
|
-
const
|
|
270
|
+
const heardNewest = new Map();
|
|
270
271
|
let relisting = null;
|
|
271
|
-
let listCursor = null;
|
|
272
272
|
const creations = new Set();
|
|
273
273
|
const listWatchers = new Set();
|
|
274
274
|
const unlisted = new Set();
|
|
275
275
|
let listKnown = false;
|
|
276
|
-
let
|
|
277
|
-
let
|
|
276
|
+
let listOwed = false;
|
|
277
|
+
let listTelling = false;
|
|
278
|
+
let rowTimer = null;
|
|
279
|
+
const closing = new AbortController();
|
|
278
280
|
const agentWatchers = new Set();
|
|
279
281
|
const unnamed = new Set();
|
|
280
282
|
let agentsShown = null;
|
|
@@ -285,8 +287,7 @@ export function createConversationStore(deps) {
|
|
|
285
287
|
function liveOf(conversation) {
|
|
286
288
|
return lives.get(conversation) ?? QUIET;
|
|
287
289
|
}
|
|
288
|
-
function viewOf(conversation, held, frame) {
|
|
289
|
-
const draft = drafts.get(conversation);
|
|
290
|
+
function viewOf(conversation, held, frame, draft, ended, marked) {
|
|
290
291
|
const facts = liveOf(conversation);
|
|
291
292
|
return {
|
|
292
293
|
conversation,
|
|
@@ -300,15 +301,17 @@ export function createConversationStore(deps) {
|
|
|
300
301
|
turn: structuredClone(facts.turn),
|
|
301
302
|
questions: structuredClone(facts.questions),
|
|
302
303
|
process: facts.process === null ? null : { ...facts.process },
|
|
304
|
+
processEnded: ended,
|
|
303
305
|
commands: structuredClone(facts.commands),
|
|
304
306
|
options: structuredClone(facts.options),
|
|
305
307
|
starting: facts.starting,
|
|
306
308
|
subagents: structuredClone(facts.subagents),
|
|
307
309
|
link: facts.link === null ? null : { ...facts.link },
|
|
308
310
|
deliveryUnknown: [...facts.deliveryUnknown],
|
|
309
|
-
chatDraft: draft ===
|
|
310
|
-
|
|
311
|
-
|
|
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),
|
|
312
315
|
};
|
|
313
316
|
}
|
|
314
317
|
function emit(conversation) {
|
|
@@ -320,7 +323,7 @@ export function createConversationStore(deps) {
|
|
|
320
323
|
const ready = [...view.watchers].filter((watcher) => watcher.ready);
|
|
321
324
|
if (ready.length === 0)
|
|
322
325
|
continue;
|
|
323
|
-
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);
|
|
324
327
|
for (const watcher of ready)
|
|
325
328
|
watcher.notify(value);
|
|
326
329
|
}
|
|
@@ -330,11 +333,13 @@ export function createConversationStore(deps) {
|
|
|
330
333
|
}
|
|
331
334
|
async function slide(local, conversation, arriving) {
|
|
332
335
|
let count;
|
|
336
|
+
let marked;
|
|
333
337
|
for (const view of views.values()) {
|
|
334
338
|
if (view.conversation !== conversation || view.window === null)
|
|
335
339
|
continue;
|
|
336
340
|
if (arriving === null) {
|
|
337
341
|
view.window = [];
|
|
342
|
+
view.marked = [];
|
|
338
343
|
view.more = false;
|
|
339
344
|
if (view.total !== null)
|
|
340
345
|
view.total = 0;
|
|
@@ -344,6 +349,10 @@ export function createConversationStore(deps) {
|
|
|
344
349
|
const next = windowOf(view.window, joining, view.asked.limit);
|
|
345
350
|
view.window = next.messages;
|
|
346
351
|
view.more ||= next.dropped;
|
|
352
|
+
if (arriving.length > 0) {
|
|
353
|
+
marked ??= await local.jobMarkers(conversation);
|
|
354
|
+
view.marked = marked;
|
|
355
|
+
}
|
|
347
356
|
if (view.total !== null && arriving.length > 0) {
|
|
348
357
|
count ??= await local.messageCount(conversation);
|
|
349
358
|
view.total = count;
|
|
@@ -356,79 +365,179 @@ export function createConversationStore(deps) {
|
|
|
356
365
|
return 'asking';
|
|
357
366
|
return facts.turn === null ? 'idle' : 'working';
|
|
358
367
|
}
|
|
359
|
-
function
|
|
360
|
-
|
|
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) => ({
|
|
361
387
|
conversation: entry.conversation,
|
|
362
|
-
agent: { identity: entry.agent, name: entry.agentName },
|
|
388
|
+
agent: { identity: entry.agent, name: entry.agentName, retired: entry.agentRetired },
|
|
363
389
|
name: entry.name,
|
|
364
390
|
created: entry.created,
|
|
365
391
|
finished: entry.finished,
|
|
366
392
|
outcome: entry.outcome,
|
|
367
393
|
waiting: entry.waiting,
|
|
368
|
-
|
|
369
|
-
|
|
394
|
+
...rowOf(entry.conversation),
|
|
395
|
+
...heldFacts(rows.get(entry.conversation), entry),
|
|
370
396
|
}));
|
|
371
397
|
}
|
|
372
|
-
function
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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)
|
|
379
435
|
return;
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
|
|
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);
|
|
388
472
|
});
|
|
389
473
|
}
|
|
390
|
-
function
|
|
391
|
-
|
|
392
|
-
|
|
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);
|
|
393
512
|
}
|
|
394
513
|
function emitList() {
|
|
395
514
|
if (deps.closed())
|
|
396
515
|
return;
|
|
397
|
-
|
|
398
|
-
const value = entries();
|
|
399
|
-
for (const watcher of listWatchers)
|
|
400
|
-
watcher(value);
|
|
401
|
-
}
|
|
516
|
+
tellList();
|
|
402
517
|
emitAgents();
|
|
403
518
|
learned();
|
|
404
519
|
}
|
|
405
520
|
function learned() {
|
|
406
521
|
if (deps.closed())
|
|
407
522
|
return;
|
|
408
|
-
if (
|
|
523
|
+
if (unlisted.size > 0)
|
|
524
|
+
tellList();
|
|
525
|
+
if (unnamed.size === 0)
|
|
409
526
|
return;
|
|
410
|
-
|
|
411
|
-
const value =
|
|
412
|
-
for (const watcher of [...unlisted]) {
|
|
413
|
-
unlisted.delete(watcher);
|
|
414
|
-
listWatchers.add(watcher);
|
|
415
|
-
watcher(value);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
if (unnamed.size > 0) {
|
|
419
|
-
const value = agents();
|
|
527
|
+
shownList((list) => {
|
|
528
|
+
const value = agents(list);
|
|
420
529
|
for (const watcher of [...unnamed]) {
|
|
421
530
|
unnamed.delete(watcher);
|
|
422
531
|
agentWatchers.add(watcher);
|
|
423
532
|
watcher(value);
|
|
424
533
|
}
|
|
425
|
-
}
|
|
534
|
+
});
|
|
426
535
|
}
|
|
427
|
-
function agents() {
|
|
536
|
+
function agents(list) {
|
|
428
537
|
const named = new Map();
|
|
429
538
|
for (const agent of listedAgents ?? [])
|
|
430
539
|
named.set(agent.agent, agent);
|
|
431
|
-
for (const entry of
|
|
540
|
+
for (const entry of list) {
|
|
432
541
|
named.set(entry.agent, { name: entry.agentName, retired: entry.agentRetired });
|
|
433
542
|
}
|
|
434
543
|
return [...named]
|
|
@@ -458,31 +567,35 @@ export function createConversationStore(deps) {
|
|
|
458
567
|
function emitAgents() {
|
|
459
568
|
if (deps.closed() || agentWatchers.size === 0)
|
|
460
569
|
return;
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
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
|
+
});
|
|
468
579
|
}
|
|
469
580
|
function setLive(conversation, next) {
|
|
470
|
-
const before =
|
|
471
|
-
const began = lives.get(conversation)?.turn?.started;
|
|
581
|
+
const before = rowOf(conversation);
|
|
472
582
|
if (next === null)
|
|
473
583
|
lives.delete(conversation);
|
|
474
584
|
else
|
|
475
585
|
lives.set(conversation, next);
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (stateOf(conversation) !== before || next?.turn?.started !== began)
|
|
586
|
+
const after = rowOf(conversation);
|
|
587
|
+
if (after.state !== before.state || after.started !== before.started)
|
|
479
588
|
emitList();
|
|
589
|
+
else if (after.line !== before.line ||
|
|
590
|
+
after.question !== before.question ||
|
|
591
|
+
after.asked !== before.asked)
|
|
592
|
+
tellSoon();
|
|
480
593
|
}
|
|
481
|
-
function retiredChat(conversation) {
|
|
594
|
+
function retiredChat(conversation, list) {
|
|
482
595
|
if (!conversation.startsWith(NEW_CHAT))
|
|
483
596
|
return false;
|
|
484
597
|
const agent = conversation.slice(NEW_CHAT.length);
|
|
485
|
-
return
|
|
598
|
+
return list.some((entry) => entry.agent === agent && entry.agentRetired);
|
|
486
599
|
}
|
|
487
600
|
function live(conversation, change) {
|
|
488
601
|
const owed = unsent.get(conversation);
|
|
@@ -540,17 +653,23 @@ export function createConversationStore(deps) {
|
|
|
540
653
|
}
|
|
541
654
|
async function remove(leaving) {
|
|
542
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
|
+
]);
|
|
543
662
|
await local.dropConversations(leaving);
|
|
544
663
|
const changed = [];
|
|
545
664
|
for (const conversation of leaving) {
|
|
546
|
-
if (
|
|
665
|
+
if (kept.has(conversation) || lives.has(conversation))
|
|
547
666
|
changed.push(conversation);
|
|
667
|
+
for (const view of views.values()) {
|
|
668
|
+
if (view.conversation === conversation)
|
|
669
|
+
view.draft = null;
|
|
548
670
|
}
|
|
549
|
-
stored.delete(conversation);
|
|
550
|
-
reads.delete(conversation);
|
|
551
|
-
partials.delete(conversation);
|
|
552
|
-
drafts.delete(conversation);
|
|
553
671
|
behind.delete(conversation);
|
|
672
|
+
heardNewest.delete(conversation);
|
|
554
673
|
unsent.delete(conversation);
|
|
555
674
|
setLive(conversation, null);
|
|
556
675
|
await slide(local, conversation, null);
|
|
@@ -559,19 +678,68 @@ export function createConversationStore(deps) {
|
|
|
559
678
|
deps.publish(conversationChangeSet(changed));
|
|
560
679
|
});
|
|
561
680
|
}
|
|
562
|
-
function
|
|
563
|
-
|
|
564
|
-
|
|
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);
|
|
565
692
|
return (read === undefined ||
|
|
566
693
|
newest === undefined ||
|
|
567
|
-
|
|
694
|
+
held?.partial === true ||
|
|
568
695
|
(newest !== null && (read === null || newest > read)));
|
|
569
696
|
}
|
|
570
|
-
function
|
|
571
|
-
|
|
572
|
-
|
|
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))
|
|
573
702
|
return;
|
|
574
|
-
|
|
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
|
+
}
|
|
575
743
|
}
|
|
576
744
|
function gap(conversation) {
|
|
577
745
|
gaps.set(conversation, (gaps.get(conversation) ?? 0) + 1);
|
|
@@ -581,7 +749,7 @@ export function createConversationStore(deps) {
|
|
|
581
749
|
return deps.durably(async (local) => {
|
|
582
750
|
if (!replicated.has(conversation))
|
|
583
751
|
return;
|
|
584
|
-
const read =
|
|
752
|
+
const read = (await readsOf(local, [conversation])).get(conversation)?.read;
|
|
585
753
|
const advances = read !== undefined &&
|
|
586
754
|
!behind.has(conversation) &&
|
|
587
755
|
(read === null || message.position > read);
|
|
@@ -591,19 +759,18 @@ export function createConversationStore(deps) {
|
|
|
591
759
|
messages: [message],
|
|
592
760
|
...(advances ? { read: { at: message.position, partial: false } } : {}),
|
|
593
761
|
});
|
|
594
|
-
stored.add(conversation);
|
|
595
|
-
if (advances)
|
|
596
|
-
reads.set(conversation, message.position);
|
|
597
762
|
sealTurns(conversation, new Set([message.turn]));
|
|
598
763
|
await slide(local, conversation, [message]);
|
|
599
764
|
deps.publish(conversationChangeSet([conversation]));
|
|
765
|
+
tellList();
|
|
600
766
|
});
|
|
601
767
|
}
|
|
602
768
|
async function readHistories(conversations, ended) {
|
|
603
769
|
const generations = new Map(conversations.map((one) => [one, gaps.get(one) ?? 0]));
|
|
770
|
+
const held = await readsOf(await deps.local(), conversations);
|
|
604
771
|
let waiting = conversations.map((conversation) => ({
|
|
605
772
|
conversation,
|
|
606
|
-
after:
|
|
773
|
+
after: held.get(conversation)?.read ?? undefined,
|
|
607
774
|
}));
|
|
608
775
|
while (waiting.length > 0) {
|
|
609
776
|
const asking = waiting.slice(0, HISTORY_CONVERSATIONS);
|
|
@@ -659,15 +826,10 @@ export function createConversationStore(deps) {
|
|
|
659
826
|
return;
|
|
660
827
|
const whole = next === undefined;
|
|
661
828
|
const cursor = next ?? newestOf(arriving, from);
|
|
662
|
-
const
|
|
829
|
+
const held = (await readsOf(local, [conversation])).get(conversation);
|
|
830
|
+
const partial = !whole && (held?.partial === true || held?.read === undefined);
|
|
663
831
|
const sealing = await sealed(local, conversation, new Set(arriving.map((message) => message.turn)));
|
|
664
832
|
await local.keepMessages({ conversation, messages: arriving, read: { at: cursor, partial } });
|
|
665
|
-
stored.add(conversation);
|
|
666
|
-
reads.set(conversation, cursor);
|
|
667
|
-
if (partial)
|
|
668
|
-
partials.add(conversation);
|
|
669
|
-
else
|
|
670
|
-
partials.delete(conversation);
|
|
671
833
|
sealTurns(conversation, new Set(arriving.map((message) => message.turn)));
|
|
672
834
|
if (whole && (gaps.get(conversation) ?? 0) === generation)
|
|
673
835
|
behind.delete(conversation);
|
|
@@ -675,6 +837,8 @@ export function createConversationStore(deps) {
|
|
|
675
837
|
if (arriving.length > 0 || sealing || whole) {
|
|
676
838
|
deps.publish(conversationChangeSet([conversation]));
|
|
677
839
|
}
|
|
840
|
+
if (arriving.length > 0)
|
|
841
|
+
tellSoon();
|
|
678
842
|
});
|
|
679
843
|
}
|
|
680
844
|
function heard(event) {
|
|
@@ -741,17 +905,24 @@ export function createConversationStore(deps) {
|
|
|
741
905
|
emit(conversation);
|
|
742
906
|
}
|
|
743
907
|
async function kept(local, conversation, following) {
|
|
744
|
-
|
|
908
|
+
const shown = following === null || empty(following) ? null : following;
|
|
909
|
+
if (shown === null)
|
|
745
910
|
await local.dropChatDraft(conversation);
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
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;
|
|
751
919
|
}
|
|
752
920
|
}
|
|
921
|
+
async function draftAt(local, conversation) {
|
|
922
|
+
return (await local.chatDraft(conversation)) ?? undefined;
|
|
923
|
+
}
|
|
753
924
|
async function sealed(local, conversation, turns) {
|
|
754
|
-
const held =
|
|
925
|
+
const held = await draftAt(local, conversation);
|
|
755
926
|
const submitted = held?.submitted ?? [];
|
|
756
927
|
const left = submitted.filter((one) => one.turn === null || !turns.has(one.turn));
|
|
757
928
|
if (held === undefined || left.length === submitted.length)
|
|
@@ -762,8 +933,8 @@ export function createConversationStore(deps) {
|
|
|
762
933
|
function moved(agent, operation, to) {
|
|
763
934
|
const from = newChat(agent);
|
|
764
935
|
return deps.durably(async (local) => {
|
|
765
|
-
const held =
|
|
766
|
-
const earlier =
|
|
936
|
+
const held = await draftAt(local, from);
|
|
937
|
+
const earlier = held?.moves ?? [];
|
|
767
938
|
if (earlier.includes(operation))
|
|
768
939
|
return;
|
|
769
940
|
const blank = {
|
|
@@ -772,18 +943,20 @@ export function createConversationStore(deps) {
|
|
|
772
943
|
revision: chatDraftRevision(),
|
|
773
944
|
};
|
|
774
945
|
const { moves: _answered, ...unsent } = held ?? blank;
|
|
775
|
-
const taken =
|
|
946
|
+
const taken = (await draftAt(local, to)) !== undefined || empty(unsent)
|
|
947
|
+
? []
|
|
948
|
+
: [{ ...unsent, conversation: to }];
|
|
776
949
|
const left = { ...(taken.length === 0 ? unsent : blank), moves: [...earlier, operation] };
|
|
777
950
|
await local.keepChatDrafts([left, ...taken]);
|
|
778
|
-
|
|
951
|
+
shownDraft(from, left);
|
|
779
952
|
for (const one of taken)
|
|
780
|
-
|
|
953
|
+
shownDraft(to, one);
|
|
781
954
|
deps.publish(conversationChangeSet([from, to]));
|
|
782
955
|
});
|
|
783
956
|
}
|
|
784
957
|
function withDraft(conversation, next) {
|
|
785
958
|
return deps.durably(async (local) => {
|
|
786
|
-
const following = await next(
|
|
959
|
+
const following = await next(await draftAt(local, conversation), local);
|
|
787
960
|
if (following === undefined)
|
|
788
961
|
return;
|
|
789
962
|
await kept(local, conversation, following);
|
|
@@ -792,10 +965,8 @@ export function createConversationStore(deps) {
|
|
|
792
965
|
}
|
|
793
966
|
async function submitted(conversation, operation, draft) {
|
|
794
967
|
let submission;
|
|
795
|
-
let earlier = false;
|
|
796
968
|
await withDraft(conversation, (current) => {
|
|
797
969
|
submission = current?.submitted?.find((one) => one.operation === operation);
|
|
798
|
-
earlier = submission !== undefined;
|
|
799
970
|
if (submission !== undefined)
|
|
800
971
|
return undefined;
|
|
801
972
|
const said = draft ?? current;
|
|
@@ -808,15 +979,7 @@ export function createConversationStore(deps) {
|
|
|
808
979
|
submitted: [...(current?.submitted ?? []), submission],
|
|
809
980
|
};
|
|
810
981
|
});
|
|
811
|
-
return
|
|
812
|
-
}
|
|
813
|
-
function forgotten(conversation, submission) {
|
|
814
|
-
return withDraft(conversation, (current) => {
|
|
815
|
-
const held = current?.submitted ?? [];
|
|
816
|
-
if (current === undefined || !held.includes(submission))
|
|
817
|
-
return undefined;
|
|
818
|
-
return withSubmitted(current, held.filter((one) => one !== submission));
|
|
819
|
-
});
|
|
982
|
+
return submission;
|
|
820
983
|
}
|
|
821
984
|
async function dispatched(conversation, submission) {
|
|
822
985
|
const dispatch = { answered: false };
|
|
@@ -875,7 +1038,8 @@ export function createConversationStore(deps) {
|
|
|
875
1038
|
return deps.durably(async (local) => {
|
|
876
1039
|
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before, phrase);
|
|
877
1040
|
const total = asked.total ? await local.messageCount(conversation, phrase) : null;
|
|
878
|
-
|
|
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));
|
|
879
1043
|
});
|
|
880
1044
|
},
|
|
881
1045
|
async create(input) {
|
|
@@ -883,8 +1047,10 @@ export function createConversationStore(deps) {
|
|
|
883
1047
|
const conversation = answered(result, 'conversation_id');
|
|
884
1048
|
if (conversation === null)
|
|
885
1049
|
return result;
|
|
886
|
-
|
|
1050
|
+
const listed = (await heldList()) ?? [];
|
|
1051
|
+
if (!listed.some((entry) => entry.conversation === conversation)) {
|
|
887
1052
|
creations.add(conversation);
|
|
1053
|
+
}
|
|
888
1054
|
const creation = creationOf(input);
|
|
889
1055
|
if (creation !== null)
|
|
890
1056
|
await moved(creation.agent, creation.operation, conversation);
|
|
@@ -901,11 +1067,7 @@ export function createConversationStore(deps) {
|
|
|
901
1067
|
});
|
|
902
1068
|
if (held === null)
|
|
903
1069
|
return DURABLE_WRITE;
|
|
904
|
-
|
|
905
|
-
if (!earlier || !deps.expired(operation))
|
|
906
|
-
return dispatched(conversation, submission);
|
|
907
|
-
await forgotten(conversation, submission);
|
|
908
|
-
return EXPIRED;
|
|
1070
|
+
return dispatched(conversation, held);
|
|
909
1071
|
}
|
|
910
1072
|
if (draft !== undefined) {
|
|
911
1073
|
await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
|
|
@@ -956,43 +1118,40 @@ export function createConversationStore(deps) {
|
|
|
956
1118
|
return {
|
|
957
1119
|
surface,
|
|
958
1120
|
chatDraft,
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
listCursor = cursor;
|
|
966
|
-
deps.stream()?.hold(cursor);
|
|
967
|
-
}
|
|
968
|
-
stored.clear();
|
|
969
|
-
reads.clear();
|
|
970
|
-
partials.clear();
|
|
971
|
-
for (const entry of held) {
|
|
972
|
-
stored.add(entry.conversation);
|
|
973
|
-
if (entry.read !== undefined)
|
|
974
|
-
reads.set(entry.conversation, entry.read);
|
|
975
|
-
if (entry.partial)
|
|
976
|
-
partials.add(entry.conversation);
|
|
977
|
-
}
|
|
978
|
-
drafts.clear();
|
|
979
|
-
for (const record of kept)
|
|
980
|
-
drafts.set(record.conversation, record);
|
|
981
|
-
if (listHeld)
|
|
982
|
-
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();
|
|
983
1127
|
},
|
|
984
1128
|
async reconcile() {
|
|
985
1129
|
if (!listKnown)
|
|
986
1130
|
return;
|
|
987
|
-
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]));
|
|
988
1141
|
const leaving = [
|
|
989
|
-
...new Set([
|
|
1142
|
+
...new Set([
|
|
1143
|
+
...replicated,
|
|
1144
|
+
...reads.keys(),
|
|
1145
|
+
...kept.map(({ conversation }) => conversation),
|
|
1146
|
+
]),
|
|
990
1147
|
].filter((conversation) => !named.has(conversation) &&
|
|
991
1148
|
!creations.has(conversation) &&
|
|
992
|
-
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation)));
|
|
1149
|
+
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation, list)));
|
|
993
1150
|
for (const conversation of named) {
|
|
994
|
-
if (!replicated.has(conversation) &&
|
|
1151
|
+
if (!replicated.has(conversation) &&
|
|
1152
|
+
missed(conversation, reads.get(conversation), entries.get(conversation))) {
|
|
995
1153
|
behind.add(conversation);
|
|
1154
|
+
}
|
|
996
1155
|
}
|
|
997
1156
|
replicated = named;
|
|
998
1157
|
handReplicated();
|
|
@@ -1023,16 +1182,16 @@ export function createConversationStore(deps) {
|
|
|
1023
1182
|
progress.complete = false;
|
|
1024
1183
|
},
|
|
1025
1184
|
async resend(progress) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
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;
|
|
1030
1192
|
if (deps.closed())
|
|
1031
1193
|
return;
|
|
1032
|
-
|
|
1033
|
-
await forgotten(conversation, submission);
|
|
1034
|
-
continue;
|
|
1035
|
-
}
|
|
1194
|
+
tried.add(submission.operation);
|
|
1036
1195
|
const result = await dispatched(conversation, submission);
|
|
1037
1196
|
if (result.kind === 'revoked-authorization')
|
|
1038
1197
|
return;
|
|
@@ -1070,6 +1229,9 @@ export function createConversationStore(deps) {
|
|
|
1070
1229
|
asked,
|
|
1071
1230
|
watchers: new Set(),
|
|
1072
1231
|
window: null,
|
|
1232
|
+
draft: null,
|
|
1233
|
+
ended: null,
|
|
1234
|
+
marked: [],
|
|
1073
1235
|
more: false,
|
|
1074
1236
|
total: null,
|
|
1075
1237
|
};
|
|
@@ -1081,7 +1243,10 @@ export function createConversationStore(deps) {
|
|
|
1081
1243
|
if (view.window !== null)
|
|
1082
1244
|
return;
|
|
1083
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);
|
|
1084
1248
|
view.window = messages;
|
|
1249
|
+
view.marked = await local.jobMarkers(conversation);
|
|
1085
1250
|
view.more = more;
|
|
1086
1251
|
view.total = asked.total ? await local.messageCount(conversation) : null;
|
|
1087
1252
|
}), reading.signal)
|
|
@@ -1090,7 +1255,7 @@ export function createConversationStore(deps) {
|
|
|
1090
1255
|
return;
|
|
1091
1256
|
watcher.ready = true;
|
|
1092
1257
|
const window = view.window ?? [];
|
|
1093
|
-
watcher.notify(viewOf(conversation, window, sharedFrame(view, window)));
|
|
1258
|
+
watcher.notify(viewOf(conversation, window, sharedFrame(view, window), view.draft, view.ended, view.marked));
|
|
1094
1259
|
})
|
|
1095
1260
|
.catch(() => { });
|
|
1096
1261
|
return () => {
|
|
@@ -1125,58 +1290,43 @@ export function createConversationStore(deps) {
|
|
|
1125
1290
|
},
|
|
1126
1291
|
receive(event) {
|
|
1127
1292
|
if (deps.closed())
|
|
1128
|
-
return
|
|
1129
|
-
if (event.kind === 'list'
|
|
1130
|
-
if (event.
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
for (const entry of event.entries)
|
|
1134
|
-
|
|
1135
|
-
listed(entry);
|
|
1136
|
-
else
|
|
1137
|
-
relisting.set(entry.conversation, { ...entry });
|
|
1138
|
-
}
|
|
1139
|
-
if (event.more)
|
|
1140
|
-
return false;
|
|
1141
|
-
if (relisting !== null) {
|
|
1142
|
-
listing.clear();
|
|
1143
|
-
for (const entry of relisting.values())
|
|
1144
|
-
listed(entry);
|
|
1145
|
-
relisting = null;
|
|
1146
|
-
}
|
|
1147
|
-
listCursor = event.cursor;
|
|
1148
|
-
deps.stream()?.hold(event.cursor);
|
|
1149
|
-
listKnown = true;
|
|
1150
|
-
for (const conversation of replicated) {
|
|
1151
|
-
if (!listing.has(conversation))
|
|
1152
|
-
continue;
|
|
1153
|
-
if (!missed(conversation))
|
|
1154
|
-
behind.delete(conversation);
|
|
1155
|
-
else if (!behind.has(conversation))
|
|
1156
|
-
gap(conversation);
|
|
1157
|
-
}
|
|
1158
|
-
openingEnded();
|
|
1159
|
-
}
|
|
1160
|
-
else if (event.kind === 'listed') {
|
|
1161
|
-
listed(event.entry);
|
|
1162
|
-
relisting?.set(event.entry.conversation, { ...event.entry });
|
|
1163
|
-
}
|
|
1164
|
-
else {
|
|
1165
|
-
listing.delete(event.conversation);
|
|
1166
|
-
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 });
|
|
1167
1300
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
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;
|
|
1175
1322
|
}
|
|
1176
1323
|
heard(event);
|
|
1177
|
-
return false;
|
|
1178
1324
|
},
|
|
1179
1325
|
close() {
|
|
1326
|
+
closing.abort();
|
|
1327
|
+
if (rowTimer !== null)
|
|
1328
|
+
clearTimeout(rowTimer);
|
|
1329
|
+
rowTimer = null;
|
|
1180
1330
|
views.clear();
|
|
1181
1331
|
lives.clear();
|
|
1182
1332
|
unsent.clear();
|