@agentshouse/mdruntime 0.1.0-ccbb89b0ca151 → 0.1.0-ccc0e3407f107
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/adapter.d.ts +74 -57
- 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 +29 -47
- package/dist/bootstrap.d.ts +11 -18
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +85 -108
- package/dist/chain.d.ts +2 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/client.d.ts +9 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/collection.d.ts +7 -4
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +23 -17
- package/dist/compile.d.ts +1 -6
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +91 -270
- package/dist/connection.d.ts +10 -9
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1009 -1063
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +7 -0
- package/dist/conversation.d.ts +16 -13
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +229 -155
- package/dist/durability.d.ts +6 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +3 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +17 -8
- package/dist/host.d.ts +3 -7
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +22 -27
- 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 +11 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/job.d.ts +14 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +28 -0
- package/dist/live.d.ts +2 -1
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +10 -7
- package/dist/media.d.ts +1 -1
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +27 -4
- package/dist/memory.d.ts +11 -5
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +167 -84
- package/dist/messages.d.ts +2 -2
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +15 -16
- package/dist/model.d.ts +8 -8
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +6 -12
- package/dist/observation.d.ts +3 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +8 -3
- package/dist/outcome.d.ts +0 -3
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +3 -1
- package/dist/paths.d.ts +1 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +4 -0
- package/dist/query.d.ts +4 -209
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -505
- package/dist/reach.d.ts +9 -8
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +37 -48
- package/dist/react.d.ts +3 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/readiness.d.ts +3 -17
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +4 -10
- package/dist/recovery.d.ts +1 -0
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +26 -0
- package/dist/refresh.d.ts +7 -5
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +29 -5
- package/dist/replica.d.ts +10 -8
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +29 -14
- package/dist/room-draft.d.ts +21 -5
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +98 -51
- package/dist/rows.d.ts +14 -21
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +48 -184
- package/dist/save.d.ts +2 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +20 -12
- package/dist/search.d.ts +12 -63
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +9 -52
- package/dist/shared.d.ts +0 -1
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +0 -10
- package/dist/status.d.ts +4 -3
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -1
- package/dist/store.d.ts +21 -34
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +34 -77
- package/dist/stored.d.ts +11 -34
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +158 -241
- package/dist/tables.d.ts +23 -48
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +29 -66
- package/dist/transfer.d.ts +0 -5
- package/dist/transfer.d.ts.map +1 -1
- package/dist/validation.d.ts +3 -4
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +42 -100
- 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 +9 -4
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +3 -1
- package/package.json +2 -2
- package/dist/fulltext.d.ts +0 -27
- package/dist/fulltext.d.ts.map +0 -1
- package/dist/fulltext.js +0 -368
- package/dist/reads.d.ts +0 -11
- package/dist/reads.d.ts.map +0 -1
- package/dist/reads.js +0 -100
- package/dist/words.d.ts +0 -19
- package/dist/words.d.ts.map +0 -1
- package/dist/words.js +0 -150
package/dist/conversation.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { cursorOf, decodedCursor } from '@agentshouse/mdmodel';
|
|
1
2
|
import { conversationChangeSet } from './change-set.js';
|
|
2
3
|
import { runtimeError } from './failure.js';
|
|
3
4
|
import { refusedForSpace } from './durability.js';
|
|
4
5
|
import { changeBatchIdentity, chatDraftRevision } from './identity.js';
|
|
5
6
|
import { OFFLINE } from './outcome.js';
|
|
6
|
-
import {
|
|
7
|
+
import { untilAnswered } from './recovery.js';
|
|
8
|
+
import { capped, FROM_START, messageOrder, precedes } from './windows.js';
|
|
7
9
|
const QUIET = {
|
|
8
10
|
turn: null,
|
|
9
11
|
questions: [],
|
|
@@ -11,6 +13,7 @@ const QUIET = {
|
|
|
11
13
|
commands: [],
|
|
12
14
|
options: [],
|
|
13
15
|
starting: null,
|
|
16
|
+
subagents: [],
|
|
14
17
|
link: null,
|
|
15
18
|
deliveryUnknown: [],
|
|
16
19
|
};
|
|
@@ -20,6 +23,7 @@ const FACTS = [
|
|
|
20
23
|
'commands',
|
|
21
24
|
'options',
|
|
22
25
|
'starting',
|
|
26
|
+
'subagents',
|
|
23
27
|
'link',
|
|
24
28
|
'deliveryUnknown',
|
|
25
29
|
];
|
|
@@ -30,9 +34,11 @@ export function unheldView(conversation) {
|
|
|
30
34
|
turn: null,
|
|
31
35
|
questions: [],
|
|
32
36
|
process: null,
|
|
37
|
+
processEnded: null,
|
|
33
38
|
commands: [],
|
|
34
39
|
options: [],
|
|
35
40
|
starting: null,
|
|
41
|
+
subagents: [],
|
|
36
42
|
link: null,
|
|
37
43
|
deliveryUnknown: [],
|
|
38
44
|
chatDraft: null,
|
|
@@ -47,10 +53,8 @@ export function newChat(agent) {
|
|
|
47
53
|
function creationOf(input) {
|
|
48
54
|
if (typeof input !== 'object' || input === null)
|
|
49
55
|
return null;
|
|
50
|
-
const { agent_id: agent, operation_id: operation
|
|
51
|
-
return typeof agent === 'string' && typeof operation === 'string'
|
|
52
|
-
? { agent, operation }
|
|
53
|
-
: null;
|
|
56
|
+
const { agent_id: agent, operation_id: operation } = input;
|
|
57
|
+
return typeof agent === 'string' && typeof operation === 'string' ? { agent, operation } : null;
|
|
54
58
|
}
|
|
55
59
|
function startedTurn(turn, operation) {
|
|
56
60
|
if (operation.op === 'begin')
|
|
@@ -209,7 +213,14 @@ function askedOf(options) {
|
|
|
209
213
|
}
|
|
210
214
|
return { limit: capped(limit), after, before: beforeOf(after), total: total === true };
|
|
211
215
|
}
|
|
212
|
-
|
|
216
|
+
function phraseOf(text) {
|
|
217
|
+
if (text === undefined)
|
|
218
|
+
return null;
|
|
219
|
+
if (typeof text !== 'string' || text === '') {
|
|
220
|
+
throw runtimeError('invalid-text', 'a conversation is found by a phrase');
|
|
221
|
+
}
|
|
222
|
+
return text;
|
|
223
|
+
}
|
|
213
224
|
const DURABLE_WRITE = {
|
|
214
225
|
kind: 'rejected',
|
|
215
226
|
code: 'durable-write',
|
|
@@ -255,13 +266,19 @@ export function createConversationStore(deps) {
|
|
|
255
266
|
const unsent = new Map();
|
|
256
267
|
const views = new Map();
|
|
257
268
|
const listing = new Map();
|
|
269
|
+
let relisting = null;
|
|
270
|
+
let listCursor = null;
|
|
258
271
|
const creations = new Set();
|
|
259
272
|
const listWatchers = new Set();
|
|
273
|
+
const unlisted = new Set();
|
|
260
274
|
let listKnown = false;
|
|
275
|
+
let listHeld = false;
|
|
276
|
+
let listKept = false;
|
|
261
277
|
const agentWatchers = new Set();
|
|
262
|
-
|
|
263
|
-
let
|
|
264
|
-
let
|
|
278
|
+
const unnamed = new Set();
|
|
279
|
+
let agentsShown = null;
|
|
280
|
+
let listedAgents = null;
|
|
281
|
+
let agentsReading = false;
|
|
265
282
|
let replicated = new Set();
|
|
266
283
|
let handedReplicated;
|
|
267
284
|
function liveOf(conversation) {
|
|
@@ -282,9 +299,11 @@ export function createConversationStore(deps) {
|
|
|
282
299
|
turn: structuredClone(facts.turn),
|
|
283
300
|
questions: structuredClone(facts.questions),
|
|
284
301
|
process: facts.process === null ? null : { ...facts.process },
|
|
302
|
+
processEnded: listing.get(conversation)?.processEnded ?? null,
|
|
285
303
|
commands: structuredClone(facts.commands),
|
|
286
304
|
options: structuredClone(facts.options),
|
|
287
305
|
starting: facts.starting,
|
|
306
|
+
subagents: structuredClone(facts.subagents),
|
|
288
307
|
link: facts.link === null ? null : { ...facts.link },
|
|
289
308
|
deliveryUnknown: [...facts.deliveryUnknown],
|
|
290
309
|
chatDraft: draft === undefined || unwritten(draft)
|
|
@@ -340,7 +359,7 @@ export function createConversationStore(deps) {
|
|
|
340
359
|
function entries() {
|
|
341
360
|
return [...listing.values()].map((entry) => ({
|
|
342
361
|
conversation: entry.conversation,
|
|
343
|
-
agent: { identity: entry.agent, name:
|
|
362
|
+
agent: { identity: entry.agent, name: entry.agentName },
|
|
344
363
|
name: entry.name,
|
|
345
364
|
created: entry.created,
|
|
346
365
|
finished: entry.finished,
|
|
@@ -350,25 +369,103 @@ export function createConversationStore(deps) {
|
|
|
350
369
|
started: lives.get(entry.conversation)?.turn?.started ?? null,
|
|
351
370
|
}));
|
|
352
371
|
}
|
|
372
|
+
function keepList() {
|
|
373
|
+
if (!listKnown || listKept)
|
|
374
|
+
return;
|
|
375
|
+
listKept = true;
|
|
376
|
+
queueMicrotask(() => {
|
|
377
|
+
listKept = false;
|
|
378
|
+
if (deps.closed())
|
|
379
|
+
return;
|
|
380
|
+
const entries = [...listing.values()];
|
|
381
|
+
const cursor = listCursor;
|
|
382
|
+
void deps
|
|
383
|
+
.durably(async (local) => {
|
|
384
|
+
await local.fact('conversationList', entries);
|
|
385
|
+
await local.fact('conversationCursor', cursor);
|
|
386
|
+
})
|
|
387
|
+
.catch(() => { });
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
function listed(entry) {
|
|
391
|
+
const ended = listing.get(entry.conversation)?.processEnded ?? null;
|
|
392
|
+
listing.set(entry.conversation, { ...entry });
|
|
393
|
+
creations.delete(entry.conversation);
|
|
394
|
+
if (entry.processEnded !== ended)
|
|
395
|
+
emit(entry.conversation);
|
|
396
|
+
}
|
|
353
397
|
function emitList() {
|
|
354
|
-
if (deps.closed()
|
|
398
|
+
if (deps.closed())
|
|
355
399
|
return;
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
watcher
|
|
400
|
+
if (listWatchers.size > 0) {
|
|
401
|
+
const value = entries();
|
|
402
|
+
for (const watcher of listWatchers)
|
|
403
|
+
watcher(value);
|
|
404
|
+
}
|
|
405
|
+
emitAgents();
|
|
406
|
+
learned();
|
|
407
|
+
}
|
|
408
|
+
function learned() {
|
|
409
|
+
if (deps.closed())
|
|
410
|
+
return;
|
|
411
|
+
if (!listKnown && !listHeld && deps.stream() !== undefined && deps.online())
|
|
412
|
+
return;
|
|
413
|
+
if (unlisted.size > 0) {
|
|
414
|
+
const value = entries();
|
|
415
|
+
for (const watcher of [...unlisted]) {
|
|
416
|
+
unlisted.delete(watcher);
|
|
417
|
+
listWatchers.add(watcher);
|
|
418
|
+
watcher(value);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
if (unnamed.size > 0) {
|
|
422
|
+
const value = agents();
|
|
423
|
+
for (const watcher of [...unnamed]) {
|
|
424
|
+
unnamed.delete(watcher);
|
|
425
|
+
agentWatchers.add(watcher);
|
|
426
|
+
watcher(value);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
359
429
|
}
|
|
360
430
|
function agents() {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
.
|
|
431
|
+
const named = new Map();
|
|
432
|
+
for (const agent of listedAgents ?? [])
|
|
433
|
+
named.set(agent.agent, agent);
|
|
434
|
+
for (const entry of listing.values()) {
|
|
435
|
+
named.set(entry.agent, { name: entry.agentName, retired: entry.agentRetired });
|
|
436
|
+
}
|
|
437
|
+
return [...named]
|
|
438
|
+
.filter(([, agent]) => !agent.retired)
|
|
439
|
+
.map(([identity, agent]) => ({ identity, name: agent.name }))
|
|
364
440
|
.sort((left, right) => left.name === right.name
|
|
365
441
|
? left.identity.localeCompare(right.identity)
|
|
366
442
|
: left.name.localeCompare(right.name));
|
|
367
443
|
}
|
|
444
|
+
function readAgents() {
|
|
445
|
+
const stream = deps.stream();
|
|
446
|
+
if (stream?.agents === undefined || !deps.online() || agentsReading)
|
|
447
|
+
return;
|
|
448
|
+
agentsReading = true;
|
|
449
|
+
void stream
|
|
450
|
+
.agents()
|
|
451
|
+
.then((read) => {
|
|
452
|
+
if (read === null)
|
|
453
|
+
return;
|
|
454
|
+
listedAgents = read;
|
|
455
|
+
emitAgents();
|
|
456
|
+
}, () => { })
|
|
457
|
+
.finally(() => {
|
|
458
|
+
agentsReading = false;
|
|
459
|
+
});
|
|
460
|
+
}
|
|
368
461
|
function emitAgents() {
|
|
369
462
|
if (deps.closed() || agentWatchers.size === 0)
|
|
370
463
|
return;
|
|
371
464
|
const value = agents();
|
|
465
|
+
const shown = JSON.stringify(value);
|
|
466
|
+
if (shown === agentsShown)
|
|
467
|
+
return;
|
|
468
|
+
agentsShown = shown;
|
|
372
469
|
for (const watcher of agentWatchers)
|
|
373
470
|
watcher(value);
|
|
374
471
|
}
|
|
@@ -384,55 +481,11 @@ export function createConversationStore(deps) {
|
|
|
384
481
|
if (stateOf(conversation) !== before || next?.turn?.started !== began)
|
|
385
482
|
emitList();
|
|
386
483
|
}
|
|
387
|
-
async function readAgents() {
|
|
388
|
-
const declaration = deps.agents();
|
|
389
|
-
if (declaration === undefined)
|
|
390
|
-
return;
|
|
391
|
-
const names = new Map();
|
|
392
|
-
const retired = new Set();
|
|
393
|
-
let covered = null;
|
|
394
|
-
for (let after;;) {
|
|
395
|
-
const read = await deps.documents(declaration, after);
|
|
396
|
-
if ('pending' in read)
|
|
397
|
-
return;
|
|
398
|
-
const coverage = JSON.stringify(read.coverage);
|
|
399
|
-
if (covered !== null && coverage !== covered)
|
|
400
|
-
return readAgents();
|
|
401
|
-
covered = coverage;
|
|
402
|
-
for (const document of read.documents) {
|
|
403
|
-
const identity = document.fields?.[declaration.identity];
|
|
404
|
-
const name = document.fields?.[declaration.name];
|
|
405
|
-
if (typeof identity !== 'string' || typeof name !== 'string')
|
|
406
|
-
continue;
|
|
407
|
-
names.set(identity, name);
|
|
408
|
-
const ended = declaration.retired === undefined ? null : document.fields?.[declaration.retired];
|
|
409
|
-
if (ended !== undefined && ended !== null)
|
|
410
|
-
retired.add(identity);
|
|
411
|
-
}
|
|
412
|
-
if (read.next === undefined)
|
|
413
|
-
break;
|
|
414
|
-
after = read.next;
|
|
415
|
-
}
|
|
416
|
-
const named = JSON.stringify([...names]) !== JSON.stringify([...agentNames]);
|
|
417
|
-
if (!named && JSON.stringify([...retired]) === JSON.stringify([...retiredAgents]))
|
|
418
|
-
return;
|
|
419
|
-
agentNames = names;
|
|
420
|
-
retiredAgents = retired;
|
|
421
|
-
if (named)
|
|
422
|
-
emitList();
|
|
423
|
-
emitAgents();
|
|
424
|
-
const ended = [...drafts.keys()].filter(retiredChat);
|
|
425
|
-
if (ended.length > 0)
|
|
426
|
-
await remove(ended);
|
|
427
|
-
}
|
|
428
484
|
function retiredChat(conversation) {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
agentsRead = null;
|
|
434
|
-
});
|
|
435
|
-
return agentsRead;
|
|
485
|
+
if (!conversation.startsWith(NEW_CHAT))
|
|
486
|
+
return false;
|
|
487
|
+
const agent = conversation.slice(NEW_CHAT.length);
|
|
488
|
+
return [...listing.values()].some((entry) => entry.agent === agent && entry.agentRetired);
|
|
436
489
|
}
|
|
437
490
|
function live(conversation, change) {
|
|
438
491
|
const owed = unsent.get(conversation);
|
|
@@ -455,6 +508,7 @@ export function createConversationStore(deps) {
|
|
|
455
508
|
commands: facts.has('commands') ? QUIET.commands : held.commands,
|
|
456
509
|
options: facts.has('options') ? QUIET.options : held.options,
|
|
457
510
|
starting: facts.has('starting') ? QUIET.starting : held.starting,
|
|
511
|
+
subagents: facts.has('subagents') ? QUIET.subagents : held.subagents,
|
|
458
512
|
link: facts.has('link') ? QUIET.link : held.link,
|
|
459
513
|
deliveryUnknown: facts.has('deliveryUnknown')
|
|
460
514
|
? QUIET.deliveryUnknown
|
|
@@ -508,6 +562,20 @@ export function createConversationStore(deps) {
|
|
|
508
562
|
deps.publish(conversationChangeSet(changed));
|
|
509
563
|
});
|
|
510
564
|
}
|
|
565
|
+
function missed(conversation) {
|
|
566
|
+
const read = reads.get(conversation);
|
|
567
|
+
const newest = listing.get(conversation)?.newest;
|
|
568
|
+
return (read === undefined ||
|
|
569
|
+
newest === undefined ||
|
|
570
|
+
partials.has(conversation) ||
|
|
571
|
+
(newest !== null && (read === null || newest > read)));
|
|
572
|
+
}
|
|
573
|
+
function noted(conversation, message) {
|
|
574
|
+
const entry = listing.get(conversation);
|
|
575
|
+
if (entry === undefined || (entry.newest !== null && entry.newest >= message.position))
|
|
576
|
+
return;
|
|
577
|
+
listing.set(conversation, { ...entry, newest: message.position });
|
|
578
|
+
}
|
|
511
579
|
function gap(conversation) {
|
|
512
580
|
gaps.set(conversation, (gaps.get(conversation) ?? 0) + 1);
|
|
513
581
|
behind.add(conversation);
|
|
@@ -542,7 +610,7 @@ export function createConversationStore(deps) {
|
|
|
542
610
|
}));
|
|
543
611
|
while (waiting.length > 0) {
|
|
544
612
|
const asking = waiting.slice(0, HISTORY_CONVERSATIONS);
|
|
545
|
-
const result = await deps.
|
|
613
|
+
const result = await deps.history({
|
|
546
614
|
conversations: asking.map(({ conversation, after }) => ({
|
|
547
615
|
conversation,
|
|
548
616
|
...(after === undefined ? {} : { after }),
|
|
@@ -645,6 +713,10 @@ export function createConversationStore(deps) {
|
|
|
645
713
|
live(conversation, { starting: event.step });
|
|
646
714
|
return;
|
|
647
715
|
}
|
|
716
|
+
if (event.kind === 'subagents') {
|
|
717
|
+
live(conversation, { subagents: structuredClone(event.subagents) });
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
648
720
|
if (event.kind === 'link') {
|
|
649
721
|
live(conversation, { link: { connected: event.connected } });
|
|
650
722
|
return;
|
|
@@ -656,6 +728,7 @@ export function createConversationStore(deps) {
|
|
|
656
728
|
const arriving = acceptedMessage(event.message);
|
|
657
729
|
if (arriving === null)
|
|
658
730
|
return;
|
|
731
|
+
noted(conversation, arriving);
|
|
659
732
|
if (replicated.has(conversation)) {
|
|
660
733
|
if (deps.full()) {
|
|
661
734
|
gap(conversation);
|
|
@@ -693,7 +766,7 @@ export function createConversationStore(deps) {
|
|
|
693
766
|
const from = newChat(agent);
|
|
694
767
|
return deps.durably(async (local) => {
|
|
695
768
|
const held = drafts.get(from);
|
|
696
|
-
const earlier =
|
|
769
|
+
const earlier = held?.moves ?? [];
|
|
697
770
|
if (earlier.includes(operation))
|
|
698
771
|
return;
|
|
699
772
|
const blank = {
|
|
@@ -722,10 +795,8 @@ export function createConversationStore(deps) {
|
|
|
722
795
|
}
|
|
723
796
|
async function submitted(conversation, operation, draft) {
|
|
724
797
|
let submission;
|
|
725
|
-
let earlier = false;
|
|
726
798
|
await withDraft(conversation, (current) => {
|
|
727
799
|
submission = current?.submitted?.find((one) => one.operation === operation);
|
|
728
|
-
earlier = submission !== undefined;
|
|
729
800
|
if (submission !== undefined)
|
|
730
801
|
return undefined;
|
|
731
802
|
const said = draft ?? current;
|
|
@@ -738,23 +809,15 @@ export function createConversationStore(deps) {
|
|
|
738
809
|
submitted: [...(current?.submitted ?? []), submission],
|
|
739
810
|
};
|
|
740
811
|
});
|
|
741
|
-
return
|
|
742
|
-
}
|
|
743
|
-
function forgotten(conversation, submission) {
|
|
744
|
-
return withDraft(conversation, (current) => {
|
|
745
|
-
const held = current?.submitted ?? [];
|
|
746
|
-
if (current === undefined || !held.includes(submission))
|
|
747
|
-
return undefined;
|
|
748
|
-
return withSubmitted(current, held.filter((one) => one !== submission));
|
|
749
|
-
});
|
|
812
|
+
return submission;
|
|
750
813
|
}
|
|
751
814
|
async function dispatched(conversation, submission) {
|
|
752
815
|
const dispatch = { answered: false };
|
|
753
816
|
sending.set(submission.operation, dispatch);
|
|
754
817
|
try {
|
|
755
|
-
const result = await invoke('
|
|
756
|
-
text: submission.text,
|
|
818
|
+
const result = await invoke('conversations/send', conversation, {
|
|
757
819
|
operation_id: submission.operation,
|
|
820
|
+
text: submission.text,
|
|
758
821
|
});
|
|
759
822
|
dispatch.answered = result.kind !== 'transport-uncertainty';
|
|
760
823
|
if (result.kind === 'revoked-authorization')
|
|
@@ -763,7 +826,7 @@ export function createConversationStore(deps) {
|
|
|
763
826
|
deps.unanswered();
|
|
764
827
|
return result;
|
|
765
828
|
}
|
|
766
|
-
const turn = answered(result, '
|
|
829
|
+
const turn = answered(result, 'message_id');
|
|
767
830
|
await withDraft(conversation, async (current, local) => {
|
|
768
831
|
const held = current?.submitted?.find((one) => one.operation === submission.operation);
|
|
769
832
|
if (current === undefined || held === undefined || held.turn !== null)
|
|
@@ -783,25 +846,34 @@ export function createConversationStore(deps) {
|
|
|
783
846
|
sending.delete(submission.operation);
|
|
784
847
|
}
|
|
785
848
|
}
|
|
786
|
-
function invoke(name, conversation, extra = {}) {
|
|
787
|
-
return deps.call(name, { conversation, ...extra });
|
|
849
|
+
function invoke(name, conversation, extra = { operation_id: changeBatchIdentity() }) {
|
|
850
|
+
return deps.call(name, { conversation_id: conversation, ...extra });
|
|
788
851
|
}
|
|
789
852
|
const surface = {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
853
|
+
list() {
|
|
854
|
+
return new Promise((settle) => {
|
|
855
|
+
const answer = (listed) => {
|
|
856
|
+
unlisted.delete(answer);
|
|
857
|
+
listWatchers.delete(answer);
|
|
858
|
+
settle(listed);
|
|
859
|
+
};
|
|
860
|
+
unlisted.add(answer);
|
|
861
|
+
learned();
|
|
862
|
+
});
|
|
793
863
|
},
|
|
794
864
|
async read(conversation, options = {}) {
|
|
795
|
-
const
|
|
865
|
+
const { text, ...windowed } = options;
|
|
866
|
+
const asked = askedOf(windowed);
|
|
867
|
+
const phrase = phraseOf(text);
|
|
796
868
|
return deps.durably(async (local) => {
|
|
797
|
-
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
798
|
-
const total = asked.total ? await local.messageCount(conversation) : null;
|
|
869
|
+
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before, phrase);
|
|
870
|
+
const total = asked.total ? await local.messageCount(conversation, phrase) : null;
|
|
799
871
|
return structuredClone(viewOf(conversation, messages, frameOf(asked, messages, more, total)));
|
|
800
872
|
});
|
|
801
873
|
},
|
|
802
874
|
async create(input) {
|
|
803
|
-
const result = await deps.call('
|
|
804
|
-
const conversation = answered(result, '
|
|
875
|
+
const result = await deps.call('conversations/create', input);
|
|
876
|
+
const conversation = answered(result, 'conversation_id');
|
|
805
877
|
if (conversation === null)
|
|
806
878
|
return result;
|
|
807
879
|
if (!listing.has(conversation))
|
|
@@ -822,11 +894,7 @@ export function createConversationStore(deps) {
|
|
|
822
894
|
});
|
|
823
895
|
if (held === null)
|
|
824
896
|
return DURABLE_WRITE;
|
|
825
|
-
|
|
826
|
-
if (!earlier || !deps.expired(operation))
|
|
827
|
-
return dispatched(conversation, submission);
|
|
828
|
-
await forgotten(conversation, submission);
|
|
829
|
-
return EXPIRED;
|
|
897
|
+
return dispatched(conversation, held);
|
|
830
898
|
}
|
|
831
899
|
if (draft !== undefined) {
|
|
832
900
|
await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
|
|
@@ -836,28 +904,19 @@ export function createConversationStore(deps) {
|
|
|
836
904
|
return OFFLINE;
|
|
837
905
|
},
|
|
838
906
|
answer(conversation, answer) {
|
|
839
|
-
return invoke('
|
|
907
|
+
return invoke('conversations/interaction/answer', conversation, {
|
|
908
|
+
operation_id: changeBatchIdentity(),
|
|
909
|
+
...answer,
|
|
910
|
+
});
|
|
840
911
|
},
|
|
841
912
|
interrupt(conversation) {
|
|
842
|
-
return invoke('
|
|
913
|
+
return invoke('conversations/interrupt', conversation);
|
|
843
914
|
},
|
|
844
915
|
kill(conversation) {
|
|
845
|
-
return invoke('
|
|
846
|
-
},
|
|
847
|
-
async cancel(conversation, turn) {
|
|
848
|
-
const result = await invoke('conversation.cancel', conversation, { turn });
|
|
849
|
-
if (result.kind !== 'action')
|
|
850
|
-
return result;
|
|
851
|
-
await withDraft(conversation, (current) => {
|
|
852
|
-
const held = current?.submitted?.find((one) => one.turn === turn);
|
|
853
|
-
if (current === undefined || held === undefined)
|
|
854
|
-
return undefined;
|
|
855
|
-
return returned(current, held, current.submitted.filter((one) => one !== held));
|
|
856
|
-
});
|
|
857
|
-
return result;
|
|
916
|
+
return invoke('conversations/kill', conversation);
|
|
858
917
|
},
|
|
859
918
|
delete(conversation) {
|
|
860
|
-
return invoke('
|
|
919
|
+
return invoke('conversations/delete', conversation);
|
|
861
920
|
},
|
|
862
921
|
};
|
|
863
922
|
const chatDraft = {
|
|
@@ -886,7 +945,15 @@ export function createConversationStore(deps) {
|
|
|
886
945
|
return {
|
|
887
946
|
surface,
|
|
888
947
|
chatDraft,
|
|
889
|
-
hydrate(held, kept) {
|
|
948
|
+
hydrate(held, kept, list, cursor) {
|
|
949
|
+
if (list !== null && !listKnown) {
|
|
950
|
+
listing.clear();
|
|
951
|
+
for (const entry of list)
|
|
952
|
+
listing.set(entry.conversation, { ...entry });
|
|
953
|
+
listHeld = true;
|
|
954
|
+
listCursor = cursor;
|
|
955
|
+
deps.stream()?.hold(cursor);
|
|
956
|
+
}
|
|
890
957
|
stored.clear();
|
|
891
958
|
reads.clear();
|
|
892
959
|
partials.clear();
|
|
@@ -900,6 +967,8 @@ export function createConversationStore(deps) {
|
|
|
900
967
|
drafts.clear();
|
|
901
968
|
for (const record of kept)
|
|
902
969
|
drafts.set(record.conversation, record);
|
|
970
|
+
if (listHeld)
|
|
971
|
+
learned();
|
|
903
972
|
},
|
|
904
973
|
async reconcile() {
|
|
905
974
|
if (!listKnown)
|
|
@@ -911,7 +980,7 @@ export function createConversationStore(deps) {
|
|
|
911
980
|
!creations.has(conversation) &&
|
|
912
981
|
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation)));
|
|
913
982
|
for (const conversation of named) {
|
|
914
|
-
if (!replicated.has(conversation))
|
|
983
|
+
if (!replicated.has(conversation) && missed(conversation))
|
|
915
984
|
behind.add(conversation);
|
|
916
985
|
}
|
|
917
986
|
replicated = named;
|
|
@@ -949,10 +1018,6 @@ export function createConversationStore(deps) {
|
|
|
949
1018
|
continue;
|
|
950
1019
|
if (deps.closed())
|
|
951
1020
|
return;
|
|
952
|
-
if (deps.expired(submission.operation)) {
|
|
953
|
-
await forgotten(conversation, submission);
|
|
954
|
-
continue;
|
|
955
|
-
}
|
|
956
1021
|
const result = await dispatched(conversation, submission);
|
|
957
1022
|
if (result.kind === 'revoked-authorization')
|
|
958
1023
|
return;
|
|
@@ -973,11 +1038,8 @@ export function createConversationStore(deps) {
|
|
|
973
1038
|
known() {
|
|
974
1039
|
return listKnown;
|
|
975
1040
|
},
|
|
976
|
-
reconnected() {
|
|
977
|
-
for (const conversation of replicated)
|
|
978
|
-
gap(conversation);
|
|
979
|
-
},
|
|
980
1041
|
reopened() {
|
|
1042
|
+
relisting = null;
|
|
981
1043
|
for (const [operation, dispatch] of sending)
|
|
982
1044
|
if (!dispatch.answered)
|
|
983
1045
|
sending.delete(operation);
|
|
@@ -999,15 +1061,15 @@ export function createConversationStore(deps) {
|
|
|
999
1061
|
views.set(key, view);
|
|
1000
1062
|
const watcher = { notify: deliver, ready: false };
|
|
1001
1063
|
view.watchers.add(watcher);
|
|
1002
|
-
|
|
1003
|
-
|
|
1064
|
+
const reading = new AbortController();
|
|
1065
|
+
void untilAnswered(() => deps.durably(async (local) => {
|
|
1004
1066
|
if (view.window !== null)
|
|
1005
1067
|
return;
|
|
1006
1068
|
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
1007
1069
|
view.window = messages;
|
|
1008
1070
|
view.more = more;
|
|
1009
1071
|
view.total = asked.total ? await local.messageCount(conversation) : null;
|
|
1010
|
-
})
|
|
1072
|
+
}), reading.signal)
|
|
1011
1073
|
.then(() => {
|
|
1012
1074
|
if (deps.closed() || !view.watchers.has(watcher))
|
|
1013
1075
|
return;
|
|
@@ -1017,6 +1079,7 @@ export function createConversationStore(deps) {
|
|
|
1017
1079
|
})
|
|
1018
1080
|
.catch(() => { });
|
|
1019
1081
|
return () => {
|
|
1082
|
+
reading.abort();
|
|
1020
1083
|
if (!view.watchers.delete(watcher))
|
|
1021
1084
|
return;
|
|
1022
1085
|
if (view.watchers.size === 0)
|
|
@@ -1024,77 +1087,88 @@ export function createConversationStore(deps) {
|
|
|
1024
1087
|
};
|
|
1025
1088
|
},
|
|
1026
1089
|
watchList(deliver) {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
if (!deps.closed() && listWatchers.has(deliver))
|
|
1030
|
-
deliver(entries());
|
|
1031
|
-
});
|
|
1090
|
+
unlisted.add(deliver);
|
|
1091
|
+
learned();
|
|
1032
1092
|
return () => {
|
|
1093
|
+
unlisted.delete(deliver);
|
|
1033
1094
|
listWatchers.delete(deliver);
|
|
1034
1095
|
};
|
|
1035
1096
|
},
|
|
1036
1097
|
watchAgents(deliver) {
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
deliver(agents());
|
|
1041
|
-
});
|
|
1098
|
+
unnamed.add(deliver);
|
|
1099
|
+
learned();
|
|
1100
|
+
readAgents();
|
|
1042
1101
|
return () => {
|
|
1102
|
+
unnamed.delete(deliver);
|
|
1043
1103
|
agentWatchers.delete(deliver);
|
|
1044
1104
|
};
|
|
1045
1105
|
},
|
|
1106
|
+
learned,
|
|
1046
1107
|
changed(set) {
|
|
1047
1108
|
for (const conversation of set.conversations)
|
|
1048
1109
|
emit(conversation);
|
|
1049
|
-
const declaration = deps.agents();
|
|
1050
|
-
if (declaration !== undefined &&
|
|
1051
|
-
set.documents.some((change) => change.locator === declaration.locator)) {
|
|
1052
|
-
agentsRead = readAgents().catch(() => {
|
|
1053
|
-
agentsRead = null;
|
|
1054
|
-
});
|
|
1055
|
-
}
|
|
1056
1110
|
},
|
|
1057
1111
|
receive(event) {
|
|
1058
1112
|
if (deps.closed())
|
|
1059
1113
|
return false;
|
|
1060
1114
|
if (event.kind === 'list' || event.kind === 'listed' || event.kind === 'unlisted') {
|
|
1061
1115
|
if (event.kind === 'list') {
|
|
1062
|
-
|
|
1116
|
+
if (event.whole)
|
|
1117
|
+
relisting ??= new Map();
|
|
1063
1118
|
for (const entry of event.entries) {
|
|
1064
|
-
|
|
1065
|
-
|
|
1119
|
+
if (relisting === null)
|
|
1120
|
+
listed(entry);
|
|
1121
|
+
else
|
|
1122
|
+
relisting.set(entry.conversation, { ...entry });
|
|
1123
|
+
}
|
|
1124
|
+
if (event.more)
|
|
1125
|
+
return false;
|
|
1126
|
+
if (relisting !== null) {
|
|
1127
|
+
listing.clear();
|
|
1128
|
+
for (const entry of relisting.values())
|
|
1129
|
+
listed(entry);
|
|
1130
|
+
relisting = null;
|
|
1066
1131
|
}
|
|
1132
|
+
listCursor = event.cursor;
|
|
1133
|
+
deps.stream()?.hold(event.cursor);
|
|
1067
1134
|
listKnown = true;
|
|
1135
|
+
for (const conversation of replicated) {
|
|
1136
|
+
if (!listing.has(conversation))
|
|
1137
|
+
continue;
|
|
1138
|
+
if (!missed(conversation))
|
|
1139
|
+
behind.delete(conversation);
|
|
1140
|
+
else if (!behind.has(conversation))
|
|
1141
|
+
gap(conversation);
|
|
1142
|
+
}
|
|
1068
1143
|
openingEnded();
|
|
1069
1144
|
}
|
|
1070
1145
|
else if (event.kind === 'listed') {
|
|
1071
|
-
|
|
1072
|
-
|
|
1146
|
+
listed(event.entry);
|
|
1147
|
+
relisting?.set(event.entry.conversation, { ...event.entry });
|
|
1073
1148
|
}
|
|
1074
1149
|
else {
|
|
1075
1150
|
listing.delete(event.conversation);
|
|
1151
|
+
relisting?.delete(event.conversation);
|
|
1076
1152
|
}
|
|
1153
|
+
keepList();
|
|
1077
1154
|
emitList();
|
|
1078
|
-
return (event.kind !== 'list' &&
|
|
1155
|
+
return ((event.kind !== 'list' &&
|
|
1079
1156
|
listKnown &&
|
|
1080
1157
|
(listing.size !== replicated.size ||
|
|
1081
|
-
[...listing.keys()].some((conversation) => !replicated.has(conversation))))
|
|
1158
|
+
[...listing.keys()].some((conversation) => !replicated.has(conversation)))) ||
|
|
1159
|
+
(listKnown && [...drafts.keys()].some(retiredChat)));
|
|
1082
1160
|
}
|
|
1083
1161
|
heard(event);
|
|
1084
1162
|
return false;
|
|
1085
1163
|
},
|
|
1086
|
-
searchable() {
|
|
1087
|
-
return [...(listKnown ? listing.keys() : stored)].sort();
|
|
1088
|
-
},
|
|
1089
|
-
acquired(conversation) {
|
|
1090
|
-
return reads.has(conversation) && !partials.has(conversation);
|
|
1091
|
-
},
|
|
1092
1164
|
close() {
|
|
1093
1165
|
views.clear();
|
|
1094
1166
|
lives.clear();
|
|
1095
1167
|
unsent.clear();
|
|
1096
1168
|
listWatchers.clear();
|
|
1169
|
+
unlisted.clear();
|
|
1097
1170
|
agentWatchers.clear();
|
|
1171
|
+
unnamed.clear();
|
|
1098
1172
|
},
|
|
1099
1173
|
};
|
|
1100
1174
|
}
|