@agentshouse/mdruntime 0.1.0-c94cfdbdb6f68 → 0.1.0-c95f0f04f2113
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 +19 -16
- 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 +248 -0
- package/dist/adapter.d.ts +139 -85
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +7 -10
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +40 -41
- package/dist/binary.d.ts +0 -5
- package/dist/binary.d.ts.map +1 -1
- package/dist/binary.js +1 -1
- package/dist/bootstrap.d.ts +30 -11
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +319 -111
- 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 +12 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +64 -0
- package/dist/change-set.d.ts +9 -16
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +11 -89
- package/dist/change.d.ts +32 -1
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +10 -1
- package/dist/chat-types.d.ts +3 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +2 -0
- package/dist/client.d.ts +28 -11
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +83 -7
- package/dist/collection.d.ts +11 -21
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +39 -321
- package/dist/compile.d.ts +16 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +717 -0
- package/dist/connection.d.ts +7 -137
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +98 -3600
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/{chat/context.js → context.js} +1 -4
- package/dist/conversation-row.d.ts +33 -0
- package/dist/conversation-row.d.ts.map +1 -0
- package/dist/conversation-row.js +47 -0
- package/dist/conversation.d.ts +36 -18
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +570 -287
- package/dist/digest.d.ts +7 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +113 -0
- 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 +7 -4
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +5 -0
- package/dist/entry.d.ts +5 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +33 -29
- package/dist/figures.d.ts +48 -0
- package/dist/figures.d.ts.map +1 -0
- package/dist/figures.js +197 -0
- package/dist/file.d.ts +2 -19
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +7 -122
- package/dist/host.d.ts +4 -7
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +67 -39
- package/dist/identity.d.ts +0 -2
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -6
- package/dist/index.d.ts +30 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- 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 +23 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +165 -0
- 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/media.d.ts +8 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +218 -0
- package/dist/memory.d.ts +14 -6
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +237 -105
- package/dist/messages.d.ts +52 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +168 -0
- package/dist/model.d.ts +8 -10
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +6 -18
- package/dist/models.d.ts +14 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +193 -0
- package/dist/name.d.ts +4 -0
- package/dist/name.d.ts.map +1 -0
- package/dist/name.js +122 -0
- package/dist/observation.d.ts +15 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +91 -2
- package/dist/opened.d.ts +22 -0
- package/dist/opened.d.ts.map +1 -0
- package/dist/opened.js +107 -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 +41 -8
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +41 -2
- package/dist/overlay.d.ts +3 -5
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +98 -172
- package/dist/{chat/parts.d.ts → parts.d.ts} +11 -9
- package/dist/parts.d.ts.map +1 -0
- package/dist/{chat/parts.js → parts.js} +45 -46
- package/dist/paths.d.ts +1 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +4 -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 +21 -206
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -493
- package/dist/{chat/questions.d.ts → questions.d.ts} +3 -2
- package/dist/questions.d.ts.map +1 -0
- package/dist/{chat/questions.js → questions.js} +8 -1
- package/dist/reach.d.ts +20 -9
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +278 -103
- package/dist/react.d.ts +6 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/{chat/read.d.ts → read.d.ts} +2 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/{chat/read.js → read.js} +4 -0
- package/dist/readiness.d.ts +14 -17
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +2 -8
- package/dist/reads.d.ts +35 -10
- package/dist/reads.d.ts.map +1 -1
- package/dist/reads.js +122 -84
- package/dist/recovery.d.ts +3 -2
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +43 -8
- package/dist/refresh.d.ts +18 -15
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +143 -58
- 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 +54 -36
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +313 -188
- package/dist/room-draft.d.ts +25 -6
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +158 -71
- 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 +31 -31
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +59 -123
- 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 +52 -14
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +518 -185
- 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 +12 -95
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +10 -266
- 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 +7 -3
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +119 -66
- 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 +4 -5
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -7
- 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 +106 -164
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +136 -752
- package/dist/stored.d.ts +156 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +637 -0
- package/dist/surface.d.ts +86 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +217 -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 +407 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +724 -0
- package/dist/tallies.d.ts +18 -0
- package/dist/tallies.d.ts.map +1 -0
- package/dist/tallies.js +129 -0
- package/dist/transfer.d.ts +0 -5
- package/dist/transfer.d.ts.map +1 -1
- package/dist/turn.d.ts +4 -2
- package/dist/turn.d.ts.map +1 -1
- package/dist/turn.js +46 -22
- package/dist/validation.d.ts +29 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +104 -0
- package/dist/windows.d.ts +1 -16
- package/dist/windows.d.ts.map +1 -1
- package/dist/windows.js +2 -79
- package/dist/wire.d.ts +33 -6
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +11 -2
- package/package.json +18 -19
- package/AGENTS.md +0 -299
- package/dist/chat/acts.d.ts +0 -33
- package/dist/chat/acts.d.ts.map +0 -1
- package/dist/chat/acts.js +0 -36
- package/dist/chat/context.d.ts +0 -3
- package/dist/chat/context.d.ts.map +0 -1
- package/dist/chat/earlier.d.ts +0 -10
- package/dist/chat/earlier.d.ts.map +0 -1
- package/dist/chat/earlier.js +0 -54
- package/dist/chat/input.d.ts +0 -9
- package/dist/chat/input.d.ts.map +0 -1
- package/dist/chat/input.js +0 -99
- package/dist/chat/kit.d.ts +0 -61
- package/dist/chat/kit.d.ts.map +0 -1
- package/dist/chat/kit.js +0 -123
- package/dist/chat/lasting.d.ts +0 -6
- package/dist/chat/lasting.d.ts.map +0 -1
- package/dist/chat/lasting.js +0 -19
- package/dist/chat/list.d.ts +0 -27
- package/dist/chat/list.d.ts.map +0 -1
- package/dist/chat/list.js +0 -99
- package/dist/chat/markdown.d.ts +0 -20
- package/dist/chat/markdown.d.ts.map +0 -1
- package/dist/chat/markdown.js +0 -188
- package/dist/chat/message.d.ts +0 -6
- package/dist/chat/message.d.ts.map +0 -1
- package/dist/chat/message.js +0 -192
- package/dist/chat/messages.d.ts +0 -22
- package/dist/chat/messages.d.ts.map +0 -1
- package/dist/chat/messages.js +0 -155
- package/dist/chat/name.d.ts +0 -6
- package/dist/chat/name.d.ts.map +0 -1
- package/dist/chat/name.js +0 -37
- package/dist/chat/opened.d.ts +0 -11
- package/dist/chat/opened.d.ts.map +0 -1
- package/dist/chat/opened.js +0 -17
- package/dist/chat/overlay.d.ts +0 -31
- package/dist/chat/overlay.d.ts.map +0 -1
- package/dist/chat/overlay.js +0 -97
- package/dist/chat/parts.d.ts.map +0 -1
- package/dist/chat/process.d.ts +0 -20
- package/dist/chat/process.d.ts.map +0 -1
- package/dist/chat/process.js +0 -32
- package/dist/chat/provider.d.ts +0 -63
- package/dist/chat/provider.d.ts.map +0 -1
- package/dist/chat/provider.js +0 -628
- package/dist/chat/question.d.ts +0 -9
- package/dist/chat/question.d.ts.map +0 -1
- package/dist/chat/question.js +0 -69
- package/dist/chat/questions.d.ts.map +0 -1
- package/dist/chat/read.d.ts.map +0 -1
- package/dist/chat/ready.d.ts +0 -34
- package/dist/chat/ready.d.ts.map +0 -1
- package/dist/chat/ready.js +0 -91
- package/dist/chat/style.d.ts +0 -4
- package/dist/chat/style.d.ts.map +0 -1
- package/dist/chat/style.js +0 -302
- package/dist/chat.d.ts +0 -14
- package/dist/chat.d.ts.map +0 -1
- package/dist/chat.js +0 -8
- package/dist/fence.d.ts +0 -6
- package/dist/fence.d.ts.map +0 -1
- package/dist/fence.js +0 -10
- package/dist/read-side.d.ts +0 -27
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -824
package/dist/conversation.js
CHANGED
|
@@ -1,17 +1,35 @@
|
|
|
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
|
-
import {
|
|
5
|
+
import { refusedForSpace } from './durability.js';
|
|
4
6
|
import { changeBatchIdentity, chatDraftRevision } from './identity.js';
|
|
5
7
|
import { OFFLINE } from './outcome.js';
|
|
6
|
-
import {
|
|
8
|
+
import { jobsOf, runningLine } from './parts.js';
|
|
9
|
+
import { openQuestion } from './questions.js';
|
|
10
|
+
import { untilAnswered } from './recovery.js';
|
|
11
|
+
import { capped, FROM_START, messageOrder, precedes } from './windows.js';
|
|
7
12
|
const QUIET = {
|
|
8
13
|
turn: null,
|
|
9
14
|
questions: [],
|
|
10
15
|
process: null,
|
|
11
16
|
commands: [],
|
|
12
17
|
options: [],
|
|
18
|
+
starting: null,
|
|
19
|
+
subagents: [],
|
|
20
|
+
link: null,
|
|
21
|
+
deliveryUnknown: [],
|
|
13
22
|
};
|
|
14
|
-
const FACTS = [
|
|
23
|
+
const FACTS = [
|
|
24
|
+
'questions',
|
|
25
|
+
'process',
|
|
26
|
+
'commands',
|
|
27
|
+
'options',
|
|
28
|
+
'starting',
|
|
29
|
+
'subagents',
|
|
30
|
+
'link',
|
|
31
|
+
'deliveryUnknown',
|
|
32
|
+
];
|
|
15
33
|
export function unheldView(conversation) {
|
|
16
34
|
return {
|
|
17
35
|
conversation,
|
|
@@ -19,13 +37,22 @@ export function unheldView(conversation) {
|
|
|
19
37
|
turn: null,
|
|
20
38
|
questions: [],
|
|
21
39
|
process: null,
|
|
40
|
+
processEnded: null,
|
|
22
41
|
commands: [],
|
|
23
42
|
options: [],
|
|
43
|
+
starting: null,
|
|
44
|
+
subagents: [],
|
|
45
|
+
link: null,
|
|
46
|
+
deliveryUnknown: [],
|
|
24
47
|
chatDraft: null,
|
|
48
|
+
jobs: [],
|
|
25
49
|
};
|
|
26
50
|
}
|
|
27
51
|
export const SESSION_STARTED = 'Session started';
|
|
28
52
|
const NEW_CHAT = 'new:';
|
|
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;
|
|
29
56
|
export function newChat(agent) {
|
|
30
57
|
return `${NEW_CHAT}${agent}`;
|
|
31
58
|
}
|
|
@@ -192,9 +219,22 @@ function askedOf(options) {
|
|
|
192
219
|
}
|
|
193
220
|
return { limit: capped(limit), after, before: beforeOf(after), total: total === true };
|
|
194
221
|
}
|
|
195
|
-
|
|
222
|
+
function phraseOf(text) {
|
|
223
|
+
if (text === undefined)
|
|
224
|
+
return null;
|
|
225
|
+
if (typeof text !== 'string' || text === '') {
|
|
226
|
+
throw runtimeError('invalid-text', 'a conversation is found by a phrase');
|
|
227
|
+
}
|
|
228
|
+
return text;
|
|
229
|
+
}
|
|
230
|
+
const DURABLE_WRITE = {
|
|
231
|
+
kind: 'rejected',
|
|
232
|
+
code: 'durable-write',
|
|
233
|
+
fields: {},
|
|
234
|
+
retryable: true,
|
|
235
|
+
};
|
|
196
236
|
function unwritten(draft) {
|
|
197
|
-
return draft.text === ''
|
|
237
|
+
return draft.text === '';
|
|
198
238
|
}
|
|
199
239
|
function pending(draft) {
|
|
200
240
|
return {
|
|
@@ -210,10 +250,7 @@ function withSubmitted(draft, submitted) {
|
|
|
210
250
|
return submitted.length === 0 ? unsent : { ...unsent, submitted };
|
|
211
251
|
}
|
|
212
252
|
function prepended(draft, said) {
|
|
213
|
-
return {
|
|
214
|
-
text: [said.text, draft.text].filter((one) => one !== '').join('\n'),
|
|
215
|
-
files: [...said.files, ...draft.files],
|
|
216
|
-
};
|
|
253
|
+
return { text: [said.text, draft.text].filter((one) => one !== '').join('\n') };
|
|
217
254
|
}
|
|
218
255
|
function returned(draft, submission, others) {
|
|
219
256
|
return withSubmitted({
|
|
@@ -223,10 +260,6 @@ function returned(draft, submission, others) {
|
|
|
223
260
|
}, others);
|
|
224
261
|
}
|
|
225
262
|
export function createConversationStore(deps) {
|
|
226
|
-
const stored = new Set();
|
|
227
|
-
const reads = new Map();
|
|
228
|
-
const partials = new Set();
|
|
229
|
-
const drafts = new Map();
|
|
230
263
|
const sending = new Map();
|
|
231
264
|
const behind = new Set();
|
|
232
265
|
const catching = new Map();
|
|
@@ -234,21 +267,27 @@ export function createConversationStore(deps) {
|
|
|
234
267
|
const lives = new Map();
|
|
235
268
|
const unsent = new Map();
|
|
236
269
|
const views = new Map();
|
|
237
|
-
const
|
|
270
|
+
const heardNewest = new Map();
|
|
271
|
+
let relisting = null;
|
|
238
272
|
const creations = new Set();
|
|
239
273
|
const listWatchers = new Set();
|
|
274
|
+
const unlisted = new Set();
|
|
240
275
|
let listKnown = false;
|
|
276
|
+
let listOwed = false;
|
|
277
|
+
let listTelling = false;
|
|
278
|
+
let rowTimer = null;
|
|
279
|
+
const closing = new AbortController();
|
|
241
280
|
const agentWatchers = new Set();
|
|
242
|
-
|
|
243
|
-
let
|
|
244
|
-
let
|
|
281
|
+
const unnamed = new Set();
|
|
282
|
+
let agentsShown = null;
|
|
283
|
+
let listedAgents = null;
|
|
284
|
+
let agentsReading = false;
|
|
245
285
|
let replicated = new Set();
|
|
246
286
|
let handedReplicated;
|
|
247
287
|
function liveOf(conversation) {
|
|
248
288
|
return lives.get(conversation) ?? QUIET;
|
|
249
289
|
}
|
|
250
|
-
function viewOf(conversation, held, frame) {
|
|
251
|
-
const draft = drafts.get(conversation);
|
|
290
|
+
function viewOf(conversation, held, frame, draft, ended, marked) {
|
|
252
291
|
const facts = liveOf(conversation);
|
|
253
292
|
return {
|
|
254
293
|
conversation,
|
|
@@ -262,11 +301,17 @@ export function createConversationStore(deps) {
|
|
|
262
301
|
turn: structuredClone(facts.turn),
|
|
263
302
|
questions: structuredClone(facts.questions),
|
|
264
303
|
process: facts.process === null ? null : { ...facts.process },
|
|
304
|
+
processEnded: ended,
|
|
265
305
|
commands: structuredClone(facts.commands),
|
|
266
306
|
options: structuredClone(facts.options),
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
307
|
+
starting: facts.starting,
|
|
308
|
+
subagents: structuredClone(facts.subagents),
|
|
309
|
+
link: facts.link === null ? null : { ...facts.link },
|
|
310
|
+
deliveryUnknown: [...facts.deliveryUnknown],
|
|
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),
|
|
270
315
|
};
|
|
271
316
|
}
|
|
272
317
|
function emit(conversation) {
|
|
@@ -278,7 +323,7 @@ export function createConversationStore(deps) {
|
|
|
278
323
|
const ready = [...view.watchers].filter((watcher) => watcher.ready);
|
|
279
324
|
if (ready.length === 0)
|
|
280
325
|
continue;
|
|
281
|
-
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);
|
|
282
327
|
for (const watcher of ready)
|
|
283
328
|
watcher.notify(value);
|
|
284
329
|
}
|
|
@@ -288,11 +333,13 @@ export function createConversationStore(deps) {
|
|
|
288
333
|
}
|
|
289
334
|
async function slide(local, conversation, arriving) {
|
|
290
335
|
let count;
|
|
336
|
+
let marked;
|
|
291
337
|
for (const view of views.values()) {
|
|
292
338
|
if (view.conversation !== conversation || view.window === null)
|
|
293
339
|
continue;
|
|
294
340
|
if (arriving === null) {
|
|
295
341
|
view.window = [];
|
|
342
|
+
view.marked = [];
|
|
296
343
|
view.more = false;
|
|
297
344
|
if (view.total !== null)
|
|
298
345
|
view.total = 0;
|
|
@@ -302,109 +349,250 @@ export function createConversationStore(deps) {
|
|
|
302
349
|
const next = windowOf(view.window, joining, view.asked.limit);
|
|
303
350
|
view.window = next.messages;
|
|
304
351
|
view.more ||= next.dropped;
|
|
352
|
+
if (arriving.length > 0) {
|
|
353
|
+
marked ??= await local.jobMarkers(conversation);
|
|
354
|
+
view.marked = marked;
|
|
355
|
+
}
|
|
305
356
|
if (view.total !== null && arriving.length > 0) {
|
|
306
357
|
count ??= await local.messageCount(conversation);
|
|
307
358
|
view.total = count;
|
|
308
359
|
}
|
|
309
360
|
}
|
|
310
361
|
}
|
|
311
|
-
function changesOf(conversation, arriving) {
|
|
312
|
-
return arriving.map(({ identity, text }) => ({ conversation, identity, text }));
|
|
313
|
-
}
|
|
314
362
|
function stateOf(conversation) {
|
|
315
363
|
const facts = liveOf(conversation);
|
|
316
364
|
if (facts.questions.length > 0)
|
|
317
365
|
return 'asking';
|
|
318
366
|
return facts.turn === null ? 'idle' : 'working';
|
|
319
367
|
}
|
|
320
|
-
function
|
|
321
|
-
|
|
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
|
+
};
|
|
376
|
+
}
|
|
377
|
+
async function entries() {
|
|
378
|
+
const list = await heldList();
|
|
379
|
+
if (list === null)
|
|
380
|
+
return null;
|
|
381
|
+
const held = list.length === 0
|
|
382
|
+
? []
|
|
383
|
+
: await deps.durably((local) => local.conversationRows(list.map(({ conversation }) => conversation)));
|
|
384
|
+
const rows = new Map(held.map((one) => [one.conversation, one]));
|
|
385
|
+
return list.map((entry) => ({
|
|
322
386
|
conversation: entry.conversation,
|
|
323
|
-
agent: { identity: entry.agent, name:
|
|
387
|
+
agent: { identity: entry.agent, name: entry.agentName, retired: entry.agentRetired },
|
|
324
388
|
name: entry.name,
|
|
325
389
|
created: entry.created,
|
|
326
390
|
finished: entry.finished,
|
|
327
391
|
outcome: entry.outcome,
|
|
328
|
-
|
|
329
|
-
|
|
392
|
+
waiting: entry.waiting,
|
|
393
|
+
...rowOf(entry.conversation),
|
|
394
|
+
...heldFacts(rows.get(entry.conversation), entry),
|
|
330
395
|
}));
|
|
331
396
|
}
|
|
397
|
+
async function heldList() {
|
|
398
|
+
const stored = (await (await deps.local()).facts()).conversationList;
|
|
399
|
+
if (stored !== null)
|
|
400
|
+
return stored;
|
|
401
|
+
return !listKnown && deps.stream() !== undefined && deps.online() ? null : [];
|
|
402
|
+
}
|
|
403
|
+
async function endedIn(conversation) {
|
|
404
|
+
const list = await heldList();
|
|
405
|
+
return list?.find((entry) => entry.conversation === conversation)?.processEnded ?? null;
|
|
406
|
+
}
|
|
407
|
+
function listChanged(change) {
|
|
408
|
+
void deps
|
|
409
|
+
.durably(async (local) => {
|
|
410
|
+
const { conversationList, conversationCursor } = await local.facts();
|
|
411
|
+
const kept = change.replacing ? [] : (conversationList ?? []);
|
|
412
|
+
const held = new Map(kept.map((entry) => [entry.conversation, entry]));
|
|
413
|
+
for (const entry of change.set) {
|
|
414
|
+
held.set(entry.conversation, { ...entry });
|
|
415
|
+
creations.delete(entry.conversation);
|
|
416
|
+
}
|
|
417
|
+
if (change.gone !== null)
|
|
418
|
+
held.delete(change.gone);
|
|
419
|
+
const list = [...held.values()];
|
|
420
|
+
if (JSON.stringify(list) !== JSON.stringify(conversationList)) {
|
|
421
|
+
await local.fact('conversationList', list);
|
|
422
|
+
}
|
|
423
|
+
if (change.cursor !== undefined) {
|
|
424
|
+
if (change.cursor !== conversationCursor) {
|
|
425
|
+
await local.fact('conversationCursor', change.cursor);
|
|
426
|
+
}
|
|
427
|
+
deps.stream()?.hold(change.cursor);
|
|
428
|
+
}
|
|
429
|
+
return list;
|
|
430
|
+
})
|
|
431
|
+
.catch(async () => (await (await deps.local()).facts()).conversationList ?? [])
|
|
432
|
+
.then((list) => {
|
|
433
|
+
if (deps.closed() || change.paged === true)
|
|
434
|
+
return;
|
|
435
|
+
endedAnew(list);
|
|
436
|
+
if (change.cursor !== undefined) {
|
|
437
|
+
listKnown = true;
|
|
438
|
+
settleBehind(list);
|
|
439
|
+
openingEnded();
|
|
440
|
+
deps.settled();
|
|
441
|
+
}
|
|
442
|
+
emitList();
|
|
443
|
+
if (!listKnown)
|
|
444
|
+
return;
|
|
445
|
+
retiredDrafts(list);
|
|
446
|
+
if (change.cursor === undefined &&
|
|
447
|
+
(list.length !== replicated.size ||
|
|
448
|
+
list.some(({ conversation }) => !replicated.has(conversation)))) {
|
|
449
|
+
deps.again();
|
|
450
|
+
}
|
|
451
|
+
}, () => { });
|
|
452
|
+
}
|
|
453
|
+
function endedAnew(list) {
|
|
454
|
+
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
455
|
+
for (const view of views.values()) {
|
|
456
|
+
const ended = entries.get(view.conversation)?.processEnded ?? null;
|
|
457
|
+
if (view.window === null || ended === view.ended)
|
|
458
|
+
continue;
|
|
459
|
+
view.ended = ended;
|
|
460
|
+
emit(view.conversation);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
let listShown = Promise.resolve();
|
|
464
|
+
function shownList(work) {
|
|
465
|
+
const reading = heldList();
|
|
466
|
+
listShown = listShown.then(async () => {
|
|
467
|
+
const list = await reading.catch(() => null);
|
|
468
|
+
if (list === null || deps.closed())
|
|
469
|
+
return;
|
|
470
|
+
work(list);
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
async function told() {
|
|
474
|
+
try {
|
|
475
|
+
while (listOwed && !deps.closed()) {
|
|
476
|
+
listOwed = false;
|
|
477
|
+
const value = await untilAnswered(entries, closing.signal);
|
|
478
|
+
if (deps.closed())
|
|
479
|
+
return;
|
|
480
|
+
if (value === null)
|
|
481
|
+
continue;
|
|
482
|
+
for (const watcher of listWatchers)
|
|
483
|
+
watcher(value);
|
|
484
|
+
for (const watcher of [...unlisted]) {
|
|
485
|
+
unlisted.delete(watcher);
|
|
486
|
+
listWatchers.add(watcher);
|
|
487
|
+
watcher(value);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
finally {
|
|
492
|
+
listTelling = false;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function tellList() {
|
|
496
|
+
if (deps.closed() || (listWatchers.size === 0 && unlisted.size === 0))
|
|
497
|
+
return;
|
|
498
|
+
listOwed = true;
|
|
499
|
+
if (listTelling)
|
|
500
|
+
return;
|
|
501
|
+
listTelling = true;
|
|
502
|
+
void told().catch(() => { });
|
|
503
|
+
}
|
|
504
|
+
function tellSoon() {
|
|
505
|
+
if (rowTimer !== null)
|
|
506
|
+
return;
|
|
507
|
+
rowTimer = setTimeout(() => {
|
|
508
|
+
rowTimer = null;
|
|
509
|
+
tellList();
|
|
510
|
+
}, ROW_INTERVAL_MS);
|
|
511
|
+
}
|
|
332
512
|
function emitList() {
|
|
333
|
-
if (deps.closed()
|
|
513
|
+
if (deps.closed())
|
|
514
|
+
return;
|
|
515
|
+
tellList();
|
|
516
|
+
emitAgents();
|
|
517
|
+
learned();
|
|
518
|
+
}
|
|
519
|
+
function learned() {
|
|
520
|
+
if (deps.closed())
|
|
521
|
+
return;
|
|
522
|
+
if (unlisted.size > 0)
|
|
523
|
+
tellList();
|
|
524
|
+
if (unnamed.size === 0)
|
|
334
525
|
return;
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
watcher
|
|
526
|
+
shownList((list) => {
|
|
527
|
+
const value = agents(list);
|
|
528
|
+
for (const watcher of [...unnamed]) {
|
|
529
|
+
unnamed.delete(watcher);
|
|
530
|
+
agentWatchers.add(watcher);
|
|
531
|
+
watcher(value);
|
|
532
|
+
}
|
|
533
|
+
});
|
|
338
534
|
}
|
|
339
|
-
function agents() {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
.
|
|
535
|
+
function agents(list) {
|
|
536
|
+
const named = new Map();
|
|
537
|
+
for (const agent of listedAgents ?? [])
|
|
538
|
+
named.set(agent.agent, agent);
|
|
539
|
+
for (const entry of list) {
|
|
540
|
+
named.set(entry.agent, { name: entry.agentName, retired: entry.agentRetired });
|
|
541
|
+
}
|
|
542
|
+
return [...named]
|
|
543
|
+
.filter(([, agent]) => !agent.retired)
|
|
544
|
+
.map(([identity, agent]) => ({ identity, name: agent.name }))
|
|
343
545
|
.sort((left, right) => left.name === right.name
|
|
344
546
|
? left.identity.localeCompare(right.identity)
|
|
345
547
|
: left.name.localeCompare(right.name));
|
|
346
548
|
}
|
|
549
|
+
function readAgents() {
|
|
550
|
+
const stream = deps.stream();
|
|
551
|
+
if (stream?.agents === undefined || !deps.online() || agentsReading)
|
|
552
|
+
return;
|
|
553
|
+
agentsReading = true;
|
|
554
|
+
void stream
|
|
555
|
+
.agents()
|
|
556
|
+
.then((read) => {
|
|
557
|
+
if (read === null)
|
|
558
|
+
return;
|
|
559
|
+
listedAgents = read;
|
|
560
|
+
emitAgents();
|
|
561
|
+
}, () => { })
|
|
562
|
+
.finally(() => {
|
|
563
|
+
agentsReading = false;
|
|
564
|
+
});
|
|
565
|
+
}
|
|
347
566
|
function emitAgents() {
|
|
348
567
|
if (deps.closed() || agentWatchers.size === 0)
|
|
349
568
|
return;
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
569
|
+
shownList((list) => {
|
|
570
|
+
const value = agents(list);
|
|
571
|
+
const shown = JSON.stringify(value);
|
|
572
|
+
if (shown === agentsShown)
|
|
573
|
+
return;
|
|
574
|
+
agentsShown = shown;
|
|
575
|
+
for (const watcher of agentWatchers)
|
|
576
|
+
watcher(value);
|
|
577
|
+
});
|
|
353
578
|
}
|
|
354
579
|
function setLive(conversation, next) {
|
|
355
|
-
const before =
|
|
356
|
-
const began = lives.get(conversation)?.turn?.started;
|
|
580
|
+
const before = rowOf(conversation);
|
|
357
581
|
if (next === null)
|
|
358
582
|
lives.delete(conversation);
|
|
359
583
|
else
|
|
360
584
|
lives.set(conversation, next);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
if (stateOf(conversation) !== before || next?.turn?.started !== began)
|
|
585
|
+
const after = rowOf(conversation);
|
|
586
|
+
if (after.state !== before.state || after.started !== before.started)
|
|
364
587
|
emitList();
|
|
588
|
+
else if (after.line !== before.line || after.question !== before.question)
|
|
589
|
+
tellSoon();
|
|
365
590
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
if ('pending' in held)
|
|
372
|
-
return;
|
|
373
|
-
const { documents } = held;
|
|
374
|
-
const names = new Map();
|
|
375
|
-
const retired = new Set();
|
|
376
|
-
for (const document of documents) {
|
|
377
|
-
if (document.type !== declaration.type)
|
|
378
|
-
continue;
|
|
379
|
-
const identity = document.fields?.[declaration.identity];
|
|
380
|
-
const name = document.fields?.[declaration.name];
|
|
381
|
-
if (typeof identity !== 'string' || typeof name !== 'string')
|
|
382
|
-
continue;
|
|
383
|
-
names.set(identity, name);
|
|
384
|
-
const ended = declaration.retired === undefined ? null : document.fields?.[declaration.retired];
|
|
385
|
-
if (ended !== undefined && ended !== null)
|
|
386
|
-
retired.add(identity);
|
|
387
|
-
}
|
|
388
|
-
const named = JSON.stringify([...names]) !== JSON.stringify([...agentNames]);
|
|
389
|
-
if (!named && JSON.stringify([...retired]) === JSON.stringify([...retiredAgents]))
|
|
390
|
-
return;
|
|
391
|
-
agentNames = names;
|
|
392
|
-
retiredAgents = retired;
|
|
393
|
-
if (named)
|
|
394
|
-
emitList();
|
|
395
|
-
emitAgents();
|
|
396
|
-
const ended = [...drafts.keys()].filter(retiredChat);
|
|
397
|
-
if (ended.length > 0)
|
|
398
|
-
await remove(ended);
|
|
399
|
-
}
|
|
400
|
-
function retiredChat(conversation) {
|
|
401
|
-
return (conversation.startsWith(NEW_CHAT) && retiredAgents.has(conversation.slice(NEW_CHAT.length)));
|
|
402
|
-
}
|
|
403
|
-
function agentsReady() {
|
|
404
|
-
agentsRead ??= readAgents().catch(() => {
|
|
405
|
-
agentsRead = null;
|
|
406
|
-
});
|
|
407
|
-
return agentsRead;
|
|
591
|
+
function retiredChat(conversation, list) {
|
|
592
|
+
if (!conversation.startsWith(NEW_CHAT))
|
|
593
|
+
return false;
|
|
594
|
+
const agent = conversation.slice(NEW_CHAT.length);
|
|
595
|
+
return list.some((entry) => entry.agent === agent && entry.agentRetired);
|
|
408
596
|
}
|
|
409
597
|
function live(conversation, change) {
|
|
410
598
|
const owed = unsent.get(conversation);
|
|
@@ -426,6 +614,12 @@ export function createConversationStore(deps) {
|
|
|
426
614
|
process: facts.has('process') ? QUIET.process : held.process,
|
|
427
615
|
commands: facts.has('commands') ? QUIET.commands : held.commands,
|
|
428
616
|
options: facts.has('options') ? QUIET.options : held.options,
|
|
617
|
+
starting: facts.has('starting') ? QUIET.starting : held.starting,
|
|
618
|
+
subagents: facts.has('subagents') ? QUIET.subagents : held.subagents,
|
|
619
|
+
link: facts.has('link') ? QUIET.link : held.link,
|
|
620
|
+
deliveryUnknown: facts.has('deliveryUnknown')
|
|
621
|
+
? QUIET.deliveryUnknown
|
|
622
|
+
: held.deliveryUnknown,
|
|
429
623
|
});
|
|
430
624
|
emit(conversation);
|
|
431
625
|
}
|
|
@@ -456,31 +650,94 @@ export function createConversationStore(deps) {
|
|
|
456
650
|
}
|
|
457
651
|
async function remove(leaving) {
|
|
458
652
|
await deps.durably(async (local) => {
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
653
|
+
const kept = new Set([
|
|
654
|
+
...(await local.conversations(leaving)).map(({ conversation }) => conversation),
|
|
655
|
+
...(await local.chatDrafts())
|
|
656
|
+
.filter(({ conversation }) => leaving.includes(conversation))
|
|
657
|
+
.map(({ conversation }) => conversation),
|
|
658
|
+
]);
|
|
465
659
|
await local.dropConversations(leaving);
|
|
466
660
|
const changed = [];
|
|
467
661
|
for (const conversation of leaving) {
|
|
468
|
-
if (
|
|
662
|
+
if (kept.has(conversation) || lives.has(conversation))
|
|
469
663
|
changed.push(conversation);
|
|
664
|
+
for (const view of views.values()) {
|
|
665
|
+
if (view.conversation === conversation)
|
|
666
|
+
view.draft = null;
|
|
470
667
|
}
|
|
471
|
-
stored.delete(conversation);
|
|
472
|
-
reads.delete(conversation);
|
|
473
|
-
partials.delete(conversation);
|
|
474
|
-
drafts.delete(conversation);
|
|
475
668
|
behind.delete(conversation);
|
|
669
|
+
heardNewest.delete(conversation);
|
|
476
670
|
unsent.delete(conversation);
|
|
477
671
|
setLive(conversation, null);
|
|
478
672
|
await slide(local, conversation, null);
|
|
479
673
|
}
|
|
480
674
|
if (changed.length > 0)
|
|
481
|
-
deps.publish(conversationChangeSet(
|
|
675
|
+
deps.publish(conversationChangeSet(changed));
|
|
482
676
|
});
|
|
483
677
|
}
|
|
678
|
+
function newestOfListed(entry) {
|
|
679
|
+
if (entry === undefined)
|
|
680
|
+
return undefined;
|
|
681
|
+
const heard = heardNewest.get(entry.conversation);
|
|
682
|
+
if (heard === undefined)
|
|
683
|
+
return entry.newest;
|
|
684
|
+
return entry.newest === null || heard > entry.newest ? heard : entry.newest;
|
|
685
|
+
}
|
|
686
|
+
function missed(conversation, held, entry) {
|
|
687
|
+
const read = held?.read;
|
|
688
|
+
const newest = newestOfListed(entry);
|
|
689
|
+
return (read === undefined ||
|
|
690
|
+
newest === undefined ||
|
|
691
|
+
held?.partial === true ||
|
|
692
|
+
(newest !== null && (read === null || newest > read)));
|
|
693
|
+
}
|
|
694
|
+
async function readsOf(local, conversations) {
|
|
695
|
+
return new Map((await local.conversations(conversations)).map((held) => [held.conversation, held]));
|
|
696
|
+
}
|
|
697
|
+
function retiredDrafts(list) {
|
|
698
|
+
if (!list.some((entry) => entry.agentRetired))
|
|
699
|
+
return;
|
|
700
|
+
void deps
|
|
701
|
+
.local()
|
|
702
|
+
.then((local) => local.chatDrafts())
|
|
703
|
+
.then((held) => {
|
|
704
|
+
if (!deps.closed() && held.some(({ conversation }) => retiredChat(conversation, list))) {
|
|
705
|
+
deps.again();
|
|
706
|
+
}
|
|
707
|
+
}, () => { });
|
|
708
|
+
}
|
|
709
|
+
function settleBehind(list) {
|
|
710
|
+
void deps
|
|
711
|
+
.durably(async (local) => {
|
|
712
|
+
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
713
|
+
const named = [...replicated].filter((conversation) => entries.has(conversation));
|
|
714
|
+
const held = await readsOf(local, named);
|
|
715
|
+
let owed = false;
|
|
716
|
+
for (const conversation of named) {
|
|
717
|
+
if (!missed(conversation, held.get(conversation), entries.get(conversation))) {
|
|
718
|
+
behind.delete(conversation);
|
|
719
|
+
}
|
|
720
|
+
else if (!behind.has(conversation)) {
|
|
721
|
+
gap(conversation);
|
|
722
|
+
owed = true;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
return owed;
|
|
726
|
+
})
|
|
727
|
+
.then((owed) => {
|
|
728
|
+
if (deps.closed())
|
|
729
|
+
return;
|
|
730
|
+
deps.settled();
|
|
731
|
+
if (owed)
|
|
732
|
+
deps.again();
|
|
733
|
+
}, () => { });
|
|
734
|
+
}
|
|
735
|
+
function noted(conversation, message) {
|
|
736
|
+
const heard = heardNewest.get(conversation);
|
|
737
|
+
if (heard === undefined || message.position > heard) {
|
|
738
|
+
heardNewest.set(conversation, message.position);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
484
741
|
function gap(conversation) {
|
|
485
742
|
gaps.set(conversation, (gaps.get(conversation) ?? 0) + 1);
|
|
486
743
|
behind.add(conversation);
|
|
@@ -489,7 +746,7 @@ export function createConversationStore(deps) {
|
|
|
489
746
|
return deps.durably(async (local) => {
|
|
490
747
|
if (!replicated.has(conversation))
|
|
491
748
|
return;
|
|
492
|
-
const read =
|
|
749
|
+
const read = (await readsOf(local, [conversation])).get(conversation)?.read;
|
|
493
750
|
const advances = read !== undefined &&
|
|
494
751
|
!behind.has(conversation) &&
|
|
495
752
|
(read === null || message.position > read);
|
|
@@ -499,22 +756,22 @@ export function createConversationStore(deps) {
|
|
|
499
756
|
messages: [message],
|
|
500
757
|
...(advances ? { read: { at: message.position, partial: false } } : {}),
|
|
501
758
|
});
|
|
502
|
-
stored.add(conversation);
|
|
503
|
-
if (advances)
|
|
504
|
-
reads.set(conversation, message.position);
|
|
505
759
|
sealTurns(conversation, new Set([message.turn]));
|
|
506
760
|
await slide(local, conversation, [message]);
|
|
507
|
-
deps.publish(conversationChangeSet(
|
|
761
|
+
deps.publish(conversationChangeSet([conversation]));
|
|
762
|
+
tellList();
|
|
508
763
|
});
|
|
509
764
|
}
|
|
510
765
|
async function readHistories(conversations, ended) {
|
|
511
766
|
const generations = new Map(conversations.map((one) => [one, gaps.get(one) ?? 0]));
|
|
512
|
-
|
|
767
|
+
const held = await readsOf(await deps.local(), conversations);
|
|
768
|
+
let waiting = conversations.map((conversation) => ({
|
|
513
769
|
conversation,
|
|
514
|
-
after:
|
|
770
|
+
after: held.get(conversation)?.read ?? undefined,
|
|
515
771
|
}));
|
|
516
|
-
while (
|
|
517
|
-
const
|
|
772
|
+
while (waiting.length > 0) {
|
|
773
|
+
const asking = waiting.slice(0, HISTORY_CONVERSATIONS);
|
|
774
|
+
const result = await deps.history({
|
|
518
775
|
conversations: asking.map(({ conversation, after }) => ({
|
|
519
776
|
conversation,
|
|
520
777
|
...(after === undefined ? {} : { after }),
|
|
@@ -537,7 +794,7 @@ export function createConversationStore(deps) {
|
|
|
537
794
|
if (!following.some((next) => next.conversation === conversation))
|
|
538
795
|
ended(conversation);
|
|
539
796
|
}
|
|
540
|
-
|
|
797
|
+
waiting = [...waiting.slice(HISTORY_CONVERSATIONS), ...following];
|
|
541
798
|
}
|
|
542
799
|
return null;
|
|
543
800
|
}
|
|
@@ -566,22 +823,19 @@ export function createConversationStore(deps) {
|
|
|
566
823
|
return;
|
|
567
824
|
const whole = next === undefined;
|
|
568
825
|
const cursor = next ?? newestOf(arriving, from);
|
|
569
|
-
const
|
|
826
|
+
const held = (await readsOf(local, [conversation])).get(conversation);
|
|
827
|
+
const partial = !whole && (held?.partial === true || held?.read === undefined);
|
|
570
828
|
const sealing = await sealed(local, conversation, new Set(arriving.map((message) => message.turn)));
|
|
571
829
|
await local.keepMessages({ conversation, messages: arriving, read: { at: cursor, partial } });
|
|
572
|
-
stored.add(conversation);
|
|
573
|
-
reads.set(conversation, cursor);
|
|
574
|
-
if (partial)
|
|
575
|
-
partials.add(conversation);
|
|
576
|
-
else
|
|
577
|
-
partials.delete(conversation);
|
|
578
830
|
sealTurns(conversation, new Set(arriving.map((message) => message.turn)));
|
|
579
831
|
if (whole && (gaps.get(conversation) ?? 0) === generation)
|
|
580
832
|
behind.delete(conversation);
|
|
581
833
|
await slide(local, conversation, arriving);
|
|
582
834
|
if (arriving.length > 0 || sealing || whole) {
|
|
583
|
-
deps.publish(conversationChangeSet(
|
|
835
|
+
deps.publish(conversationChangeSet([conversation]));
|
|
584
836
|
}
|
|
837
|
+
if (arriving.length > 0)
|
|
838
|
+
tellSoon();
|
|
585
839
|
});
|
|
586
840
|
}
|
|
587
841
|
function heard(event) {
|
|
@@ -613,28 +867,59 @@ export function createConversationStore(deps) {
|
|
|
613
867
|
live(conversation, { options: structuredClone(event.options) });
|
|
614
868
|
return;
|
|
615
869
|
}
|
|
870
|
+
if (event.kind === 'starting') {
|
|
871
|
+
live(conversation, { starting: event.step });
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
if (event.kind === 'subagents') {
|
|
875
|
+
live(conversation, { subagents: structuredClone(event.subagents) });
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
if (event.kind === 'link') {
|
|
879
|
+
live(conversation, { link: { connected: event.connected } });
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
if (event.kind === 'deliveries') {
|
|
883
|
+
live(conversation, { deliveryUnknown: [...event.unknown] });
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
616
886
|
const arriving = acceptedMessage(event.message);
|
|
617
887
|
if (arriving === null)
|
|
618
888
|
return;
|
|
889
|
+
noted(conversation, arriving);
|
|
619
890
|
if (replicated.has(conversation)) {
|
|
620
|
-
|
|
891
|
+
if (deps.full()) {
|
|
892
|
+
gap(conversation);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
void keep(conversation, arriving).catch((error) => {
|
|
896
|
+
if (refusedForSpace(error))
|
|
897
|
+
gap(conversation);
|
|
898
|
+
});
|
|
621
899
|
return;
|
|
622
900
|
}
|
|
623
901
|
if (sealTurns(conversation, new Set([arriving.turn])))
|
|
624
902
|
emit(conversation);
|
|
625
903
|
}
|
|
626
904
|
async function kept(local, conversation, following) {
|
|
627
|
-
|
|
905
|
+
const shown = following === null || empty(following) ? null : following;
|
|
906
|
+
if (shown === null)
|
|
628
907
|
await local.dropChatDraft(conversation);
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
908
|
+
else
|
|
909
|
+
await local.keepChatDrafts([shown]);
|
|
910
|
+
shownDraft(conversation, shown);
|
|
911
|
+
}
|
|
912
|
+
function shownDraft(conversation, draft) {
|
|
913
|
+
for (const view of views.values()) {
|
|
914
|
+
if (view.conversation === conversation)
|
|
915
|
+
view.draft = draft;
|
|
634
916
|
}
|
|
635
917
|
}
|
|
918
|
+
async function draftAt(local, conversation) {
|
|
919
|
+
return (await local.chatDraft(conversation)) ?? undefined;
|
|
920
|
+
}
|
|
636
921
|
async function sealed(local, conversation, turns) {
|
|
637
|
-
const held =
|
|
922
|
+
const held = await draftAt(local, conversation);
|
|
638
923
|
const submitted = held?.submitted ?? [];
|
|
639
924
|
const left = submitted.filter((one) => one.turn === null || !turns.has(one.turn));
|
|
640
925
|
if (held === undefined || left.length === submitted.length)
|
|
@@ -645,85 +930,70 @@ export function createConversationStore(deps) {
|
|
|
645
930
|
function moved(agent, operation, to) {
|
|
646
931
|
const from = newChat(agent);
|
|
647
932
|
return deps.durably(async (local) => {
|
|
648
|
-
const held =
|
|
649
|
-
const earlier =
|
|
933
|
+
const held = await draftAt(local, from);
|
|
934
|
+
const earlier = held?.moves ?? [];
|
|
650
935
|
if (earlier.includes(operation))
|
|
651
936
|
return;
|
|
652
937
|
const blank = {
|
|
653
938
|
conversation: from,
|
|
654
939
|
text: '',
|
|
655
|
-
files: [],
|
|
656
940
|
revision: chatDraftRevision(),
|
|
657
941
|
};
|
|
658
942
|
const { moves: _answered, ...unsent } = held ?? blank;
|
|
659
|
-
const taken =
|
|
943
|
+
const taken = (await draftAt(local, to)) !== undefined || empty(unsent)
|
|
944
|
+
? []
|
|
945
|
+
: [{ ...unsent, conversation: to }];
|
|
660
946
|
const left = { ...(taken.length === 0 ? unsent : blank), moves: [...earlier, operation] };
|
|
661
947
|
await local.keepChatDrafts([left, ...taken]);
|
|
662
|
-
|
|
948
|
+
shownDraft(from, left);
|
|
663
949
|
for (const one of taken)
|
|
664
|
-
|
|
665
|
-
deps.publish(conversationChangeSet([
|
|
950
|
+
shownDraft(to, one);
|
|
951
|
+
deps.publish(conversationChangeSet([from, to]));
|
|
666
952
|
});
|
|
667
953
|
}
|
|
668
954
|
function withDraft(conversation, next) {
|
|
669
955
|
return deps.durably(async (local) => {
|
|
670
|
-
const following = await next(
|
|
956
|
+
const following = await next(await draftAt(local, conversation), local);
|
|
671
957
|
if (following === undefined)
|
|
672
958
|
return;
|
|
673
959
|
await kept(local, conversation, following);
|
|
674
|
-
deps.publish(conversationChangeSet([
|
|
960
|
+
deps.publish(conversationChangeSet([conversation]));
|
|
675
961
|
});
|
|
676
962
|
}
|
|
677
963
|
async function submitted(conversation, operation, draft) {
|
|
678
964
|
let submission;
|
|
679
|
-
let earlier = false;
|
|
680
965
|
await withDraft(conversation, (current) => {
|
|
681
966
|
submission = current?.submitted?.find((one) => one.operation === operation);
|
|
682
|
-
earlier = submission !== undefined;
|
|
683
967
|
if (submission !== undefined)
|
|
684
968
|
return undefined;
|
|
685
969
|
const said = draft ?? current;
|
|
686
|
-
submission = {
|
|
687
|
-
operation,
|
|
688
|
-
text: said?.text ?? '',
|
|
689
|
-
files: [...(said?.files ?? [])],
|
|
690
|
-
turn: null,
|
|
691
|
-
};
|
|
970
|
+
submission = { operation, text: said?.text ?? '', turn: null };
|
|
692
971
|
return {
|
|
693
972
|
conversation,
|
|
694
973
|
...(draft === undefined || current === undefined
|
|
695
|
-
? { text: '',
|
|
696
|
-
: { text: current.text,
|
|
974
|
+
? { text: '', revision: chatDraftRevision() }
|
|
975
|
+
: { text: current.text, revision: current.revision }),
|
|
697
976
|
submitted: [...(current?.submitted ?? []), submission],
|
|
698
977
|
};
|
|
699
978
|
});
|
|
700
|
-
return
|
|
701
|
-
}
|
|
702
|
-
function forgotten(conversation, submission) {
|
|
703
|
-
return withDraft(conversation, (current) => {
|
|
704
|
-
const held = current?.submitted ?? [];
|
|
705
|
-
if (current === undefined || !held.includes(submission))
|
|
706
|
-
return undefined;
|
|
707
|
-
return withSubmitted(current, held.filter((one) => one !== submission));
|
|
708
|
-
});
|
|
979
|
+
return submission;
|
|
709
980
|
}
|
|
710
981
|
async function dispatched(conversation, submission) {
|
|
711
|
-
const dispatch = {};
|
|
982
|
+
const dispatch = { answered: false };
|
|
712
983
|
sending.set(submission.operation, dispatch);
|
|
713
984
|
try {
|
|
714
|
-
const
|
|
715
|
-
const result = await invoke('conversation.send', conversation, {
|
|
716
|
-
text: submission.text,
|
|
717
|
-
files,
|
|
985
|
+
const result = await invoke('conversations/send', conversation, {
|
|
718
986
|
operation_id: submission.operation,
|
|
987
|
+
text: submission.text,
|
|
719
988
|
});
|
|
989
|
+
dispatch.answered = result.kind !== 'transport-uncertainty';
|
|
720
990
|
if (result.kind === 'revoked-authorization')
|
|
721
991
|
return result;
|
|
722
992
|
if (result.kind !== 'action' && result.retryable) {
|
|
723
993
|
deps.unanswered();
|
|
724
994
|
return result;
|
|
725
995
|
}
|
|
726
|
-
const turn = answered(result, '
|
|
996
|
+
const turn = answered(result, 'message_id');
|
|
727
997
|
await withDraft(conversation, async (current, local) => {
|
|
728
998
|
const held = current?.submitted?.find((one) => one.operation === submission.operation);
|
|
729
999
|
if (current === undefined || held === undefined || held.turn !== null)
|
|
@@ -743,72 +1013,80 @@ export function createConversationStore(deps) {
|
|
|
743
1013
|
sending.delete(submission.operation);
|
|
744
1014
|
}
|
|
745
1015
|
}
|
|
746
|
-
function invoke(name, conversation, extra = {}) {
|
|
747
|
-
return deps.call(name, { conversation, ...extra });
|
|
1016
|
+
function invoke(name, conversation, extra = { operation_id: changeBatchIdentity() }) {
|
|
1017
|
+
return deps.call(name, { conversation_id: conversation, ...extra });
|
|
748
1018
|
}
|
|
749
1019
|
const surface = {
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
1020
|
+
list() {
|
|
1021
|
+
return new Promise((settle) => {
|
|
1022
|
+
const answer = (listed) => {
|
|
1023
|
+
unlisted.delete(answer);
|
|
1024
|
+
listWatchers.delete(answer);
|
|
1025
|
+
settle(listed);
|
|
1026
|
+
};
|
|
1027
|
+
unlisted.add(answer);
|
|
1028
|
+
learned();
|
|
1029
|
+
});
|
|
753
1030
|
},
|
|
754
1031
|
async read(conversation, options = {}) {
|
|
755
|
-
const
|
|
1032
|
+
const { text, ...windowed } = options;
|
|
1033
|
+
const asked = askedOf(windowed);
|
|
1034
|
+
const phrase = phraseOf(text);
|
|
756
1035
|
return deps.durably(async (local) => {
|
|
757
|
-
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
758
|
-
const total = asked.total ? await local.messageCount(conversation) : null;
|
|
759
|
-
|
|
1036
|
+
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before, phrase);
|
|
1037
|
+
const total = asked.total ? await local.messageCount(conversation, phrase) : null;
|
|
1038
|
+
const marked = await local.jobMarkers(conversation);
|
|
1039
|
+
return structuredClone(viewOf(conversation, messages, frameOf(asked, messages, more, total), (await local.chatDraft(conversation)) ?? null, await endedIn(conversation), marked));
|
|
760
1040
|
});
|
|
761
1041
|
},
|
|
762
1042
|
async create(input) {
|
|
763
|
-
const result = await deps.call('
|
|
764
|
-
const conversation = answered(result, '
|
|
1043
|
+
const result = await deps.call('conversations/create', input);
|
|
1044
|
+
const conversation = answered(result, 'conversation_id');
|
|
765
1045
|
if (conversation === null)
|
|
766
1046
|
return result;
|
|
767
|
-
|
|
1047
|
+
const listed = (await heldList()) ?? [];
|
|
1048
|
+
if (!listed.some((entry) => entry.conversation === conversation)) {
|
|
768
1049
|
creations.add(conversation);
|
|
1050
|
+
}
|
|
769
1051
|
const creation = creationOf(input);
|
|
770
1052
|
if (creation !== null)
|
|
771
1053
|
await moved(creation.agent, creation.operation, conversation);
|
|
772
1054
|
return result;
|
|
773
1055
|
},
|
|
774
1056
|
async send(conversation, operation = changeBatchIdentity(), draft) {
|
|
1057
|
+
if (deps.full())
|
|
1058
|
+
return DURABLE_WRITE;
|
|
775
1059
|
if (deps.online()) {
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
1060
|
+
const held = await submitted(conversation, operation, draft).catch((error) => {
|
|
1061
|
+
if (refusedForSpace(error))
|
|
1062
|
+
return null;
|
|
1063
|
+
throw error;
|
|
1064
|
+
});
|
|
1065
|
+
if (held === null)
|
|
1066
|
+
return DURABLE_WRITE;
|
|
1067
|
+
return dispatched(conversation, held);
|
|
781
1068
|
}
|
|
782
1069
|
if (draft !== undefined) {
|
|
783
1070
|
await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
|
|
784
1071
|
? undefined
|
|
785
|
-
: returned(current ?? { conversation, text: '',
|
|
1072
|
+
: returned(current ?? { conversation, text: '', revision: '' }, { operation, ...draft, turn: null }, current?.submitted ?? []));
|
|
786
1073
|
}
|
|
787
1074
|
return OFFLINE;
|
|
788
1075
|
},
|
|
789
1076
|
answer(conversation, answer) {
|
|
790
|
-
return invoke('
|
|
1077
|
+
return invoke('conversations/interaction/answer', conversation, {
|
|
1078
|
+
operation_id: changeBatchIdentity(),
|
|
1079
|
+
...answer,
|
|
1080
|
+
});
|
|
791
1081
|
},
|
|
792
1082
|
interrupt(conversation) {
|
|
793
|
-
return invoke('
|
|
1083
|
+
return invoke('conversations/interrupt', conversation);
|
|
794
1084
|
},
|
|
795
1085
|
kill(conversation) {
|
|
796
|
-
return invoke('
|
|
797
|
-
},
|
|
798
|
-
async cancel(conversation, turn) {
|
|
799
|
-
const result = await invoke('conversation.cancel', conversation, { turn });
|
|
800
|
-
if (result.kind !== 'action')
|
|
801
|
-
return result;
|
|
802
|
-
await withDraft(conversation, (current) => {
|
|
803
|
-
const held = current?.submitted?.find((one) => one.turn === turn);
|
|
804
|
-
if (current === undefined || held === undefined)
|
|
805
|
-
return undefined;
|
|
806
|
-
return returned(current, held, current.submitted.filter((one) => one !== held));
|
|
807
|
-
});
|
|
808
|
-
return result;
|
|
1086
|
+
return invoke('conversations/kill', conversation);
|
|
809
1087
|
},
|
|
810
1088
|
delete(conversation) {
|
|
811
|
-
return invoke('
|
|
1089
|
+
return invoke('conversations/delete', conversation);
|
|
812
1090
|
},
|
|
813
1091
|
};
|
|
814
1092
|
const chatDraft = {
|
|
@@ -816,7 +1094,6 @@ export function createConversationStore(deps) {
|
|
|
816
1094
|
return withDraft(conversation, (current) => ({
|
|
817
1095
|
conversation,
|
|
818
1096
|
text: draft.text,
|
|
819
|
-
files: [...draft.files],
|
|
820
1097
|
revision,
|
|
821
1098
|
...(current === undefined ? {} : pending(current)),
|
|
822
1099
|
}));
|
|
@@ -824,9 +1101,7 @@ export function createConversationStore(deps) {
|
|
|
824
1101
|
prepend(conversation, draft) {
|
|
825
1102
|
return withDraft(conversation, (current) => ({
|
|
826
1103
|
conversation,
|
|
827
|
-
...(current === undefined
|
|
828
|
-
? { text: draft.text, files: [...draft.files] }
|
|
829
|
-
: prepended(current, draft)),
|
|
1104
|
+
...(current === undefined ? { text: draft.text } : prepended(current, draft)),
|
|
830
1105
|
revision: chatDraftRevision(),
|
|
831
1106
|
...(current === undefined ? {} : pending(current)),
|
|
832
1107
|
}));
|
|
@@ -834,45 +1109,46 @@ export function createConversationStore(deps) {
|
|
|
834
1109
|
discard(conversation) {
|
|
835
1110
|
return withDraft(conversation, (current) => current === undefined
|
|
836
1111
|
? undefined
|
|
837
|
-
: {
|
|
838
|
-
conversation,
|
|
839
|
-
text: '',
|
|
840
|
-
files: [],
|
|
841
|
-
revision: chatDraftRevision(),
|
|
842
|
-
...pending(current),
|
|
843
|
-
});
|
|
1112
|
+
: { conversation, text: '', revision: chatDraftRevision(), ...pending(current) });
|
|
844
1113
|
},
|
|
845
1114
|
};
|
|
846
1115
|
return {
|
|
847
1116
|
surface,
|
|
848
1117
|
chatDraft,
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
if (entry.read !== undefined)
|
|
856
|
-
reads.set(entry.conversation, entry.read);
|
|
857
|
-
if (entry.partial)
|
|
858
|
-
partials.add(entry.conversation);
|
|
859
|
-
}
|
|
860
|
-
drafts.clear();
|
|
861
|
-
for (const record of kept)
|
|
862
|
-
drafts.set(record.conversation, record);
|
|
1118
|
+
async opened(local) {
|
|
1119
|
+
const { conversationList, conversationCursor } = await local.facts();
|
|
1120
|
+
if (conversationList === null || listKnown)
|
|
1121
|
+
return;
|
|
1122
|
+
deps.stream()?.hold(conversationCursor);
|
|
1123
|
+
learned();
|
|
863
1124
|
},
|
|
864
1125
|
async reconcile() {
|
|
865
1126
|
if (!listKnown)
|
|
866
1127
|
return;
|
|
867
|
-
const
|
|
1128
|
+
const local = await deps.local();
|
|
1129
|
+
const [held, kept, { conversationList }] = await Promise.all([
|
|
1130
|
+
local.conversations(),
|
|
1131
|
+
local.chatDrafts(),
|
|
1132
|
+
local.facts(),
|
|
1133
|
+
]);
|
|
1134
|
+
const list = conversationList ?? [];
|
|
1135
|
+
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
1136
|
+
const named = new Set(entries.keys());
|
|
1137
|
+
const reads = new Map(held.map((one) => [one.conversation, one]));
|
|
868
1138
|
const leaving = [
|
|
869
|
-
...new Set([
|
|
1139
|
+
...new Set([
|
|
1140
|
+
...replicated,
|
|
1141
|
+
...reads.keys(),
|
|
1142
|
+
...kept.map(({ conversation }) => conversation),
|
|
1143
|
+
]),
|
|
870
1144
|
].filter((conversation) => !named.has(conversation) &&
|
|
871
1145
|
!creations.has(conversation) &&
|
|
872
|
-
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation)));
|
|
1146
|
+
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation, list)));
|
|
873
1147
|
for (const conversation of named) {
|
|
874
|
-
if (!replicated.has(conversation)
|
|
1148
|
+
if (!replicated.has(conversation) &&
|
|
1149
|
+
missed(conversation, reads.get(conversation), entries.get(conversation))) {
|
|
875
1150
|
behind.add(conversation);
|
|
1151
|
+
}
|
|
876
1152
|
}
|
|
877
1153
|
replicated = named;
|
|
878
1154
|
handReplicated();
|
|
@@ -880,6 +1156,11 @@ export function createConversationStore(deps) {
|
|
|
880
1156
|
await remove(leaving);
|
|
881
1157
|
},
|
|
882
1158
|
async catchUp(progress) {
|
|
1159
|
+
if (deps.full()) {
|
|
1160
|
+
if (behind.size > 0)
|
|
1161
|
+
progress.complete = false;
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
883
1164
|
const owed = (conversation) => behind.has(conversation) && replicated.has(conversation);
|
|
884
1165
|
const read = async (conversations) => {
|
|
885
1166
|
if (conversations.length === 0 || deps.closed())
|
|
@@ -898,16 +1179,16 @@ export function createConversationStore(deps) {
|
|
|
898
1179
|
progress.complete = false;
|
|
899
1180
|
},
|
|
900
1181
|
async resend(progress) {
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
1182
|
+
const local = await deps.local();
|
|
1183
|
+
const tried = new Set();
|
|
1184
|
+
for (const { conversation } of await local.chatDrafts()) {
|
|
1185
|
+
for (;;) {
|
|
1186
|
+
const submission = (await local.chatDraft(conversation))?.submitted?.find((one) => one.turn === null && !sending.has(one.operation) && !tried.has(one.operation));
|
|
1187
|
+
if (submission === undefined)
|
|
1188
|
+
break;
|
|
905
1189
|
if (deps.closed())
|
|
906
1190
|
return;
|
|
907
|
-
|
|
908
|
-
await forgotten(conversation, submission);
|
|
909
|
-
continue;
|
|
910
|
-
}
|
|
1191
|
+
tried.add(submission.operation);
|
|
911
1192
|
const result = await dispatched(conversation, submission);
|
|
912
1193
|
if (result.kind === 'revoked-authorization')
|
|
913
1194
|
return;
|
|
@@ -928,12 +1209,11 @@ export function createConversationStore(deps) {
|
|
|
928
1209
|
known() {
|
|
929
1210
|
return listKnown;
|
|
930
1211
|
},
|
|
931
|
-
reconnected() {
|
|
932
|
-
for (const conversation of replicated)
|
|
933
|
-
gap(conversation);
|
|
934
|
-
},
|
|
935
1212
|
reopened() {
|
|
936
|
-
|
|
1213
|
+
relisting = null;
|
|
1214
|
+
for (const [operation, dispatch] of sending)
|
|
1215
|
+
if (!dispatch.answered)
|
|
1216
|
+
sending.delete(operation);
|
|
937
1217
|
},
|
|
938
1218
|
lost() {
|
|
939
1219
|
catching.clear();
|
|
@@ -946,30 +1226,37 @@ export function createConversationStore(deps) {
|
|
|
946
1226
|
asked,
|
|
947
1227
|
watchers: new Set(),
|
|
948
1228
|
window: null,
|
|
1229
|
+
draft: null,
|
|
1230
|
+
ended: null,
|
|
1231
|
+
marked: [],
|
|
949
1232
|
more: false,
|
|
950
1233
|
total: null,
|
|
951
1234
|
};
|
|
952
1235
|
views.set(key, view);
|
|
953
1236
|
const watcher = { notify: deliver, ready: false };
|
|
954
1237
|
view.watchers.add(watcher);
|
|
955
|
-
|
|
956
|
-
|
|
1238
|
+
const reading = new AbortController();
|
|
1239
|
+
void untilAnswered(() => deps.durably(async (local) => {
|
|
957
1240
|
if (view.window !== null)
|
|
958
1241
|
return;
|
|
959
1242
|
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
1243
|
+
view.draft = (await local.chatDraft(conversation)) ?? null;
|
|
1244
|
+
view.ended = await endedIn(conversation);
|
|
960
1245
|
view.window = messages;
|
|
1246
|
+
view.marked = await local.jobMarkers(conversation);
|
|
961
1247
|
view.more = more;
|
|
962
1248
|
view.total = asked.total ? await local.messageCount(conversation) : null;
|
|
963
|
-
})
|
|
1249
|
+
}), reading.signal)
|
|
964
1250
|
.then(() => {
|
|
965
1251
|
if (deps.closed() || !view.watchers.has(watcher))
|
|
966
1252
|
return;
|
|
967
1253
|
watcher.ready = true;
|
|
968
1254
|
const window = view.window ?? [];
|
|
969
|
-
watcher.notify(viewOf(conversation, window, sharedFrame(view, window)));
|
|
1255
|
+
watcher.notify(viewOf(conversation, window, sharedFrame(view, window), view.draft, view.ended, view.marked));
|
|
970
1256
|
})
|
|
971
1257
|
.catch(() => { });
|
|
972
1258
|
return () => {
|
|
1259
|
+
reading.abort();
|
|
973
1260
|
if (!view.watchers.delete(watcher))
|
|
974
1261
|
return;
|
|
975
1262
|
if (view.watchers.size === 0)
|
|
@@ -977,77 +1264,73 @@ export function createConversationStore(deps) {
|
|
|
977
1264
|
};
|
|
978
1265
|
},
|
|
979
1266
|
watchList(deliver) {
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
if (!deps.closed() && listWatchers.has(deliver))
|
|
983
|
-
deliver(entries());
|
|
984
|
-
});
|
|
1267
|
+
unlisted.add(deliver);
|
|
1268
|
+
learned();
|
|
985
1269
|
return () => {
|
|
1270
|
+
unlisted.delete(deliver);
|
|
986
1271
|
listWatchers.delete(deliver);
|
|
987
1272
|
};
|
|
988
1273
|
},
|
|
989
1274
|
watchAgents(deliver) {
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
deliver(agents());
|
|
994
|
-
});
|
|
1275
|
+
unnamed.add(deliver);
|
|
1276
|
+
learned();
|
|
1277
|
+
readAgents();
|
|
995
1278
|
return () => {
|
|
1279
|
+
unnamed.delete(deliver);
|
|
996
1280
|
agentWatchers.delete(deliver);
|
|
997
1281
|
};
|
|
998
1282
|
},
|
|
1283
|
+
learned,
|
|
999
1284
|
changed(set) {
|
|
1000
1285
|
for (const conversation of set.conversations)
|
|
1001
1286
|
emit(conversation);
|
|
1002
|
-
const declaration = deps.agents();
|
|
1003
|
-
if (declaration !== undefined &&
|
|
1004
|
-
set.documents.some((change) => change.locator === declaration.locator)) {
|
|
1005
|
-
agentsRead = readAgents().catch(() => {
|
|
1006
|
-
agentsRead = null;
|
|
1007
|
-
});
|
|
1008
|
-
}
|
|
1009
1287
|
},
|
|
1010
1288
|
receive(event) {
|
|
1011
1289
|
if (deps.closed())
|
|
1012
|
-
return
|
|
1013
|
-
if (event.kind === 'list'
|
|
1014
|
-
if (event.
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
}
|
|
1020
|
-
listKnown = true;
|
|
1021
|
-
openingEnded();
|
|
1022
|
-
}
|
|
1023
|
-
else if (event.kind === 'listed') {
|
|
1024
|
-
listing.set(event.entry.conversation, { ...event.entry });
|
|
1025
|
-
creations.delete(event.entry.conversation);
|
|
1026
|
-
}
|
|
1027
|
-
else {
|
|
1028
|
-
listing.delete(event.conversation);
|
|
1290
|
+
return;
|
|
1291
|
+
if (event.kind === 'list') {
|
|
1292
|
+
if (event.whole)
|
|
1293
|
+
relisting ??= new Map();
|
|
1294
|
+
if (relisting !== null) {
|
|
1295
|
+
for (const entry of event.entries)
|
|
1296
|
+
relisting.set(entry.conversation, { ...entry });
|
|
1029
1297
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1298
|
+
if (event.more && relisting !== null)
|
|
1299
|
+
return;
|
|
1300
|
+
const whole = relisting;
|
|
1301
|
+
relisting = null;
|
|
1302
|
+
listChanged({
|
|
1303
|
+
replacing: whole !== null,
|
|
1304
|
+
set: whole === null ? event.entries : [...whole.values()],
|
|
1305
|
+
gone: null,
|
|
1306
|
+
...(event.more ? { paged: true } : { cursor: event.cursor }),
|
|
1307
|
+
});
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
if (event.kind === 'listed') {
|
|
1311
|
+
relisting?.set(event.entry.conversation, { ...event.entry });
|
|
1312
|
+
listChanged({ replacing: false, set: [event.entry], gone: null });
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
if (event.kind === 'unlisted') {
|
|
1316
|
+
relisting?.delete(event.conversation);
|
|
1317
|
+
listChanged({ replacing: false, set: [], gone: event.conversation });
|
|
1318
|
+
return;
|
|
1035
1319
|
}
|
|
1036
1320
|
heard(event);
|
|
1037
|
-
return false;
|
|
1038
|
-
},
|
|
1039
|
-
searchable() {
|
|
1040
|
-
return [...(listKnown ? listing.keys() : stored)].sort();
|
|
1041
|
-
},
|
|
1042
|
-
acquired(conversation) {
|
|
1043
|
-
return reads.has(conversation) && !partials.has(conversation);
|
|
1044
1321
|
},
|
|
1045
1322
|
close() {
|
|
1323
|
+
closing.abort();
|
|
1324
|
+
if (rowTimer !== null)
|
|
1325
|
+
clearTimeout(rowTimer);
|
|
1326
|
+
rowTimer = null;
|
|
1046
1327
|
views.clear();
|
|
1047
1328
|
lives.clear();
|
|
1048
1329
|
unsent.clear();
|
|
1049
1330
|
listWatchers.clear();
|
|
1331
|
+
unlisted.clear();
|
|
1050
1332
|
agentWatchers.clear();
|
|
1333
|
+
unnamed.clear();
|
|
1051
1334
|
},
|
|
1052
1335
|
};
|
|
1053
1336
|
}
|