@agentshouse/mdruntime 0.1.0-c94cfdbdb6f68 → 0.1.0-c95dc33df5c05
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 +250 -0
- package/dist/adapter.d.ts +140 -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 +5 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +13 -0
- package/dist/client.d.ts +30 -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 +53 -0
- package/dist/conversation.d.ts +37 -18
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +573 -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 +16 -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/holdings.d.ts +29 -0
- package/dist/holdings.d.ts.map +1 -0
- package/dist/holdings.js +95 -0
- 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 +31 -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 +44 -9
- 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} +5 -2
- package/dist/questions.d.ts.map +1 -0
- package/dist/{chat/questions.js → questions.js} +12 -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 +10 -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 +136 -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 +88 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +222 -0
- package/dist/sync.d.ts +20 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +531 -0
- package/dist/tables.d.ts +415 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +740 -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 +34 -6
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +12 -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, questionAsked } 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,253 @@ 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
|
+
asked: questionAsked(liveOf(conversation).questions),
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
async function entries() {
|
|
379
|
+
const list = await heldList();
|
|
380
|
+
if (list === null)
|
|
381
|
+
return null;
|
|
382
|
+
const held = list.length === 0
|
|
383
|
+
? []
|
|
384
|
+
: await deps.durably((local) => local.conversationRows(list.map(({ conversation }) => conversation)));
|
|
385
|
+
const rows = new Map(held.map((one) => [one.conversation, one]));
|
|
386
|
+
return list.map((entry) => ({
|
|
322
387
|
conversation: entry.conversation,
|
|
323
|
-
agent: { identity: entry.agent, name:
|
|
388
|
+
agent: { identity: entry.agent, name: entry.agentName, retired: entry.agentRetired },
|
|
324
389
|
name: entry.name,
|
|
325
390
|
created: entry.created,
|
|
326
391
|
finished: entry.finished,
|
|
327
392
|
outcome: entry.outcome,
|
|
328
|
-
|
|
329
|
-
|
|
393
|
+
waiting: entry.waiting,
|
|
394
|
+
...rowOf(entry.conversation),
|
|
395
|
+
...heldFacts(rows.get(entry.conversation), entry),
|
|
330
396
|
}));
|
|
331
397
|
}
|
|
398
|
+
async function heldList() {
|
|
399
|
+
const stored = (await (await deps.local()).facts()).conversationList;
|
|
400
|
+
if (stored !== null)
|
|
401
|
+
return stored;
|
|
402
|
+
return !listKnown && deps.stream() !== undefined && deps.online() ? null : [];
|
|
403
|
+
}
|
|
404
|
+
async function endedIn(conversation) {
|
|
405
|
+
const list = await heldList();
|
|
406
|
+
return list?.find((entry) => entry.conversation === conversation)?.processEnded ?? null;
|
|
407
|
+
}
|
|
408
|
+
function listChanged(change) {
|
|
409
|
+
void deps
|
|
410
|
+
.durably(async (local) => {
|
|
411
|
+
const { conversationList, conversationCursor } = await local.facts();
|
|
412
|
+
const kept = change.replacing ? [] : (conversationList ?? []);
|
|
413
|
+
const held = new Map(kept.map((entry) => [entry.conversation, entry]));
|
|
414
|
+
for (const entry of change.set) {
|
|
415
|
+
held.set(entry.conversation, { ...entry });
|
|
416
|
+
creations.delete(entry.conversation);
|
|
417
|
+
}
|
|
418
|
+
if (change.gone !== null)
|
|
419
|
+
held.delete(change.gone);
|
|
420
|
+
const list = [...held.values()];
|
|
421
|
+
if (JSON.stringify(list) !== JSON.stringify(conversationList)) {
|
|
422
|
+
await local.fact('conversationList', list);
|
|
423
|
+
}
|
|
424
|
+
if (change.cursor !== undefined) {
|
|
425
|
+
if (change.cursor !== conversationCursor) {
|
|
426
|
+
await local.fact('conversationCursor', change.cursor);
|
|
427
|
+
}
|
|
428
|
+
deps.stream()?.hold(change.cursor);
|
|
429
|
+
}
|
|
430
|
+
return list;
|
|
431
|
+
})
|
|
432
|
+
.catch(async () => (await (await deps.local()).facts()).conversationList ?? [])
|
|
433
|
+
.then((list) => {
|
|
434
|
+
if (deps.closed() || change.paged === true)
|
|
435
|
+
return;
|
|
436
|
+
endedAnew(list);
|
|
437
|
+
if (change.cursor !== undefined) {
|
|
438
|
+
listKnown = true;
|
|
439
|
+
settleBehind(list);
|
|
440
|
+
openingEnded();
|
|
441
|
+
deps.settled();
|
|
442
|
+
}
|
|
443
|
+
emitList();
|
|
444
|
+
if (!listKnown)
|
|
445
|
+
return;
|
|
446
|
+
retiredDrafts(list);
|
|
447
|
+
if (change.cursor === undefined &&
|
|
448
|
+
(list.length !== replicated.size ||
|
|
449
|
+
list.some(({ conversation }) => !replicated.has(conversation)))) {
|
|
450
|
+
deps.again();
|
|
451
|
+
}
|
|
452
|
+
}, () => { });
|
|
453
|
+
}
|
|
454
|
+
function endedAnew(list) {
|
|
455
|
+
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
456
|
+
for (const view of views.values()) {
|
|
457
|
+
const ended = entries.get(view.conversation)?.processEnded ?? null;
|
|
458
|
+
if (view.window === null || ended === view.ended)
|
|
459
|
+
continue;
|
|
460
|
+
view.ended = ended;
|
|
461
|
+
emit(view.conversation);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
let listShown = Promise.resolve();
|
|
465
|
+
function shownList(work) {
|
|
466
|
+
const reading = heldList();
|
|
467
|
+
listShown = listShown.then(async () => {
|
|
468
|
+
const list = await reading.catch(() => null);
|
|
469
|
+
if (list === null || deps.closed())
|
|
470
|
+
return;
|
|
471
|
+
work(list);
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
async function told() {
|
|
475
|
+
try {
|
|
476
|
+
while (listOwed && !deps.closed()) {
|
|
477
|
+
listOwed = false;
|
|
478
|
+
const value = await untilAnswered(entries, closing.signal);
|
|
479
|
+
if (deps.closed())
|
|
480
|
+
return;
|
|
481
|
+
if (value === null)
|
|
482
|
+
continue;
|
|
483
|
+
for (const watcher of listWatchers)
|
|
484
|
+
watcher(value);
|
|
485
|
+
for (const watcher of [...unlisted]) {
|
|
486
|
+
unlisted.delete(watcher);
|
|
487
|
+
listWatchers.add(watcher);
|
|
488
|
+
watcher(value);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
finally {
|
|
493
|
+
listTelling = false;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function tellList() {
|
|
497
|
+
if (deps.closed() || (listWatchers.size === 0 && unlisted.size === 0))
|
|
498
|
+
return;
|
|
499
|
+
listOwed = true;
|
|
500
|
+
if (listTelling)
|
|
501
|
+
return;
|
|
502
|
+
listTelling = true;
|
|
503
|
+
void told().catch(() => { });
|
|
504
|
+
}
|
|
505
|
+
function tellSoon() {
|
|
506
|
+
if (rowTimer !== null)
|
|
507
|
+
return;
|
|
508
|
+
rowTimer = setTimeout(() => {
|
|
509
|
+
rowTimer = null;
|
|
510
|
+
tellList();
|
|
511
|
+
}, ROW_INTERVAL_MS);
|
|
512
|
+
}
|
|
332
513
|
function emitList() {
|
|
333
|
-
if (deps.closed()
|
|
514
|
+
if (deps.closed())
|
|
515
|
+
return;
|
|
516
|
+
tellList();
|
|
517
|
+
emitAgents();
|
|
518
|
+
learned();
|
|
519
|
+
}
|
|
520
|
+
function learned() {
|
|
521
|
+
if (deps.closed())
|
|
522
|
+
return;
|
|
523
|
+
if (unlisted.size > 0)
|
|
524
|
+
tellList();
|
|
525
|
+
if (unnamed.size === 0)
|
|
334
526
|
return;
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
watcher
|
|
527
|
+
shownList((list) => {
|
|
528
|
+
const value = agents(list);
|
|
529
|
+
for (const watcher of [...unnamed]) {
|
|
530
|
+
unnamed.delete(watcher);
|
|
531
|
+
agentWatchers.add(watcher);
|
|
532
|
+
watcher(value);
|
|
533
|
+
}
|
|
534
|
+
});
|
|
338
535
|
}
|
|
339
|
-
function agents() {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
.
|
|
536
|
+
function agents(list) {
|
|
537
|
+
const named = new Map();
|
|
538
|
+
for (const agent of listedAgents ?? [])
|
|
539
|
+
named.set(agent.agent, agent);
|
|
540
|
+
for (const entry of list) {
|
|
541
|
+
named.set(entry.agent, { name: entry.agentName, retired: entry.agentRetired });
|
|
542
|
+
}
|
|
543
|
+
return [...named]
|
|
544
|
+
.filter(([, agent]) => !agent.retired)
|
|
545
|
+
.map(([identity, agent]) => ({ identity, name: agent.name }))
|
|
343
546
|
.sort((left, right) => left.name === right.name
|
|
344
547
|
? left.identity.localeCompare(right.identity)
|
|
345
548
|
: left.name.localeCompare(right.name));
|
|
346
549
|
}
|
|
550
|
+
function readAgents() {
|
|
551
|
+
const stream = deps.stream();
|
|
552
|
+
if (stream?.agents === undefined || !deps.online() || agentsReading)
|
|
553
|
+
return;
|
|
554
|
+
agentsReading = true;
|
|
555
|
+
void stream
|
|
556
|
+
.agents()
|
|
557
|
+
.then((read) => {
|
|
558
|
+
if (read === null)
|
|
559
|
+
return;
|
|
560
|
+
listedAgents = read;
|
|
561
|
+
emitAgents();
|
|
562
|
+
}, () => { })
|
|
563
|
+
.finally(() => {
|
|
564
|
+
agentsReading = false;
|
|
565
|
+
});
|
|
566
|
+
}
|
|
347
567
|
function emitAgents() {
|
|
348
568
|
if (deps.closed() || agentWatchers.size === 0)
|
|
349
569
|
return;
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
570
|
+
shownList((list) => {
|
|
571
|
+
const value = agents(list);
|
|
572
|
+
const shown = JSON.stringify(value);
|
|
573
|
+
if (shown === agentsShown)
|
|
574
|
+
return;
|
|
575
|
+
agentsShown = shown;
|
|
576
|
+
for (const watcher of agentWatchers)
|
|
577
|
+
watcher(value);
|
|
578
|
+
});
|
|
353
579
|
}
|
|
354
580
|
function setLive(conversation, next) {
|
|
355
|
-
const before =
|
|
356
|
-
const began = lives.get(conversation)?.turn?.started;
|
|
581
|
+
const before = rowOf(conversation);
|
|
357
582
|
if (next === null)
|
|
358
583
|
lives.delete(conversation);
|
|
359
584
|
else
|
|
360
585
|
lives.set(conversation, next);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
if (stateOf(conversation) !== before || next?.turn?.started !== began)
|
|
586
|
+
const after = rowOf(conversation);
|
|
587
|
+
if (after.state !== before.state || after.started !== before.started)
|
|
364
588
|
emitList();
|
|
589
|
+
else if (after.line !== before.line ||
|
|
590
|
+
after.question !== before.question ||
|
|
591
|
+
after.asked !== before.asked)
|
|
592
|
+
tellSoon();
|
|
365
593
|
}
|
|
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;
|
|
594
|
+
function retiredChat(conversation, list) {
|
|
595
|
+
if (!conversation.startsWith(NEW_CHAT))
|
|
596
|
+
return false;
|
|
597
|
+
const agent = conversation.slice(NEW_CHAT.length);
|
|
598
|
+
return list.some((entry) => entry.agent === agent && entry.agentRetired);
|
|
408
599
|
}
|
|
409
600
|
function live(conversation, change) {
|
|
410
601
|
const owed = unsent.get(conversation);
|
|
@@ -426,6 +617,12 @@ export function createConversationStore(deps) {
|
|
|
426
617
|
process: facts.has('process') ? QUIET.process : held.process,
|
|
427
618
|
commands: facts.has('commands') ? QUIET.commands : held.commands,
|
|
428
619
|
options: facts.has('options') ? QUIET.options : held.options,
|
|
620
|
+
starting: facts.has('starting') ? QUIET.starting : held.starting,
|
|
621
|
+
subagents: facts.has('subagents') ? QUIET.subagents : held.subagents,
|
|
622
|
+
link: facts.has('link') ? QUIET.link : held.link,
|
|
623
|
+
deliveryUnknown: facts.has('deliveryUnknown')
|
|
624
|
+
? QUIET.deliveryUnknown
|
|
625
|
+
: held.deliveryUnknown,
|
|
429
626
|
});
|
|
430
627
|
emit(conversation);
|
|
431
628
|
}
|
|
@@ -456,31 +653,94 @@ export function createConversationStore(deps) {
|
|
|
456
653
|
}
|
|
457
654
|
async function remove(leaving) {
|
|
458
655
|
await deps.durably(async (local) => {
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
656
|
+
const kept = new Set([
|
|
657
|
+
...(await local.conversations(leaving)).map(({ conversation }) => conversation),
|
|
658
|
+
...(await local.chatDrafts())
|
|
659
|
+
.filter(({ conversation }) => leaving.includes(conversation))
|
|
660
|
+
.map(({ conversation }) => conversation),
|
|
661
|
+
]);
|
|
465
662
|
await local.dropConversations(leaving);
|
|
466
663
|
const changed = [];
|
|
467
664
|
for (const conversation of leaving) {
|
|
468
|
-
if (
|
|
665
|
+
if (kept.has(conversation) || lives.has(conversation))
|
|
469
666
|
changed.push(conversation);
|
|
667
|
+
for (const view of views.values()) {
|
|
668
|
+
if (view.conversation === conversation)
|
|
669
|
+
view.draft = null;
|
|
470
670
|
}
|
|
471
|
-
stored.delete(conversation);
|
|
472
|
-
reads.delete(conversation);
|
|
473
|
-
partials.delete(conversation);
|
|
474
|
-
drafts.delete(conversation);
|
|
475
671
|
behind.delete(conversation);
|
|
672
|
+
heardNewest.delete(conversation);
|
|
476
673
|
unsent.delete(conversation);
|
|
477
674
|
setLive(conversation, null);
|
|
478
675
|
await slide(local, conversation, null);
|
|
479
676
|
}
|
|
480
677
|
if (changed.length > 0)
|
|
481
|
-
deps.publish(conversationChangeSet(
|
|
678
|
+
deps.publish(conversationChangeSet(changed));
|
|
482
679
|
});
|
|
483
680
|
}
|
|
681
|
+
function newestOfListed(entry) {
|
|
682
|
+
if (entry === undefined)
|
|
683
|
+
return undefined;
|
|
684
|
+
const heard = heardNewest.get(entry.conversation);
|
|
685
|
+
if (heard === undefined)
|
|
686
|
+
return entry.newest;
|
|
687
|
+
return entry.newest === null || heard > entry.newest ? heard : entry.newest;
|
|
688
|
+
}
|
|
689
|
+
function missed(conversation, held, entry) {
|
|
690
|
+
const read = held?.read;
|
|
691
|
+
const newest = newestOfListed(entry);
|
|
692
|
+
return (read === undefined ||
|
|
693
|
+
newest === undefined ||
|
|
694
|
+
held?.partial === true ||
|
|
695
|
+
(newest !== null && (read === null || newest > read)));
|
|
696
|
+
}
|
|
697
|
+
async function readsOf(local, conversations) {
|
|
698
|
+
return new Map((await local.conversations(conversations)).map((held) => [held.conversation, held]));
|
|
699
|
+
}
|
|
700
|
+
function retiredDrafts(list) {
|
|
701
|
+
if (!list.some((entry) => entry.agentRetired))
|
|
702
|
+
return;
|
|
703
|
+
void deps
|
|
704
|
+
.local()
|
|
705
|
+
.then((local) => local.chatDrafts())
|
|
706
|
+
.then((held) => {
|
|
707
|
+
if (!deps.closed() && held.some(({ conversation }) => retiredChat(conversation, list))) {
|
|
708
|
+
deps.again();
|
|
709
|
+
}
|
|
710
|
+
}, () => { });
|
|
711
|
+
}
|
|
712
|
+
function settleBehind(list) {
|
|
713
|
+
void deps
|
|
714
|
+
.durably(async (local) => {
|
|
715
|
+
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
716
|
+
const named = [...replicated].filter((conversation) => entries.has(conversation));
|
|
717
|
+
const held = await readsOf(local, named);
|
|
718
|
+
let owed = false;
|
|
719
|
+
for (const conversation of named) {
|
|
720
|
+
if (!missed(conversation, held.get(conversation), entries.get(conversation))) {
|
|
721
|
+
behind.delete(conversation);
|
|
722
|
+
}
|
|
723
|
+
else if (!behind.has(conversation)) {
|
|
724
|
+
gap(conversation);
|
|
725
|
+
owed = true;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return owed;
|
|
729
|
+
})
|
|
730
|
+
.then((owed) => {
|
|
731
|
+
if (deps.closed())
|
|
732
|
+
return;
|
|
733
|
+
deps.settled();
|
|
734
|
+
if (owed)
|
|
735
|
+
deps.again();
|
|
736
|
+
}, () => { });
|
|
737
|
+
}
|
|
738
|
+
function noted(conversation, message) {
|
|
739
|
+
const heard = heardNewest.get(conversation);
|
|
740
|
+
if (heard === undefined || message.position > heard) {
|
|
741
|
+
heardNewest.set(conversation, message.position);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
484
744
|
function gap(conversation) {
|
|
485
745
|
gaps.set(conversation, (gaps.get(conversation) ?? 0) + 1);
|
|
486
746
|
behind.add(conversation);
|
|
@@ -489,7 +749,7 @@ export function createConversationStore(deps) {
|
|
|
489
749
|
return deps.durably(async (local) => {
|
|
490
750
|
if (!replicated.has(conversation))
|
|
491
751
|
return;
|
|
492
|
-
const read =
|
|
752
|
+
const read = (await readsOf(local, [conversation])).get(conversation)?.read;
|
|
493
753
|
const advances = read !== undefined &&
|
|
494
754
|
!behind.has(conversation) &&
|
|
495
755
|
(read === null || message.position > read);
|
|
@@ -499,22 +759,22 @@ export function createConversationStore(deps) {
|
|
|
499
759
|
messages: [message],
|
|
500
760
|
...(advances ? { read: { at: message.position, partial: false } } : {}),
|
|
501
761
|
});
|
|
502
|
-
stored.add(conversation);
|
|
503
|
-
if (advances)
|
|
504
|
-
reads.set(conversation, message.position);
|
|
505
762
|
sealTurns(conversation, new Set([message.turn]));
|
|
506
763
|
await slide(local, conversation, [message]);
|
|
507
|
-
deps.publish(conversationChangeSet(
|
|
764
|
+
deps.publish(conversationChangeSet([conversation]));
|
|
765
|
+
tellList();
|
|
508
766
|
});
|
|
509
767
|
}
|
|
510
768
|
async function readHistories(conversations, ended) {
|
|
511
769
|
const generations = new Map(conversations.map((one) => [one, gaps.get(one) ?? 0]));
|
|
512
|
-
|
|
770
|
+
const held = await readsOf(await deps.local(), conversations);
|
|
771
|
+
let waiting = conversations.map((conversation) => ({
|
|
513
772
|
conversation,
|
|
514
|
-
after:
|
|
773
|
+
after: held.get(conversation)?.read ?? undefined,
|
|
515
774
|
}));
|
|
516
|
-
while (
|
|
517
|
-
const
|
|
775
|
+
while (waiting.length > 0) {
|
|
776
|
+
const asking = waiting.slice(0, HISTORY_CONVERSATIONS);
|
|
777
|
+
const result = await deps.history({
|
|
518
778
|
conversations: asking.map(({ conversation, after }) => ({
|
|
519
779
|
conversation,
|
|
520
780
|
...(after === undefined ? {} : { after }),
|
|
@@ -537,7 +797,7 @@ export function createConversationStore(deps) {
|
|
|
537
797
|
if (!following.some((next) => next.conversation === conversation))
|
|
538
798
|
ended(conversation);
|
|
539
799
|
}
|
|
540
|
-
|
|
800
|
+
waiting = [...waiting.slice(HISTORY_CONVERSATIONS), ...following];
|
|
541
801
|
}
|
|
542
802
|
return null;
|
|
543
803
|
}
|
|
@@ -566,22 +826,19 @@ export function createConversationStore(deps) {
|
|
|
566
826
|
return;
|
|
567
827
|
const whole = next === undefined;
|
|
568
828
|
const cursor = next ?? newestOf(arriving, from);
|
|
569
|
-
const
|
|
829
|
+
const held = (await readsOf(local, [conversation])).get(conversation);
|
|
830
|
+
const partial = !whole && (held?.partial === true || held?.read === undefined);
|
|
570
831
|
const sealing = await sealed(local, conversation, new Set(arriving.map((message) => message.turn)));
|
|
571
832
|
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
833
|
sealTurns(conversation, new Set(arriving.map((message) => message.turn)));
|
|
579
834
|
if (whole && (gaps.get(conversation) ?? 0) === generation)
|
|
580
835
|
behind.delete(conversation);
|
|
581
836
|
await slide(local, conversation, arriving);
|
|
582
837
|
if (arriving.length > 0 || sealing || whole) {
|
|
583
|
-
deps.publish(conversationChangeSet(
|
|
838
|
+
deps.publish(conversationChangeSet([conversation]));
|
|
584
839
|
}
|
|
840
|
+
if (arriving.length > 0)
|
|
841
|
+
tellSoon();
|
|
585
842
|
});
|
|
586
843
|
}
|
|
587
844
|
function heard(event) {
|
|
@@ -613,28 +870,59 @@ export function createConversationStore(deps) {
|
|
|
613
870
|
live(conversation, { options: structuredClone(event.options) });
|
|
614
871
|
return;
|
|
615
872
|
}
|
|
873
|
+
if (event.kind === 'starting') {
|
|
874
|
+
live(conversation, { starting: event.step });
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (event.kind === 'subagents') {
|
|
878
|
+
live(conversation, { subagents: structuredClone(event.subagents) });
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (event.kind === 'link') {
|
|
882
|
+
live(conversation, { link: { connected: event.connected } });
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
if (event.kind === 'deliveries') {
|
|
886
|
+
live(conversation, { deliveryUnknown: [...event.unknown] });
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
616
889
|
const arriving = acceptedMessage(event.message);
|
|
617
890
|
if (arriving === null)
|
|
618
891
|
return;
|
|
892
|
+
noted(conversation, arriving);
|
|
619
893
|
if (replicated.has(conversation)) {
|
|
620
|
-
|
|
894
|
+
if (deps.full()) {
|
|
895
|
+
gap(conversation);
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
void keep(conversation, arriving).catch((error) => {
|
|
899
|
+
if (refusedForSpace(error))
|
|
900
|
+
gap(conversation);
|
|
901
|
+
});
|
|
621
902
|
return;
|
|
622
903
|
}
|
|
623
904
|
if (sealTurns(conversation, new Set([arriving.turn])))
|
|
624
905
|
emit(conversation);
|
|
625
906
|
}
|
|
626
907
|
async function kept(local, conversation, following) {
|
|
627
|
-
|
|
908
|
+
const shown = following === null || empty(following) ? null : following;
|
|
909
|
+
if (shown === null)
|
|
628
910
|
await local.dropChatDraft(conversation);
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
911
|
+
else
|
|
912
|
+
await local.keepChatDrafts([shown]);
|
|
913
|
+
shownDraft(conversation, shown);
|
|
914
|
+
}
|
|
915
|
+
function shownDraft(conversation, draft) {
|
|
916
|
+
for (const view of views.values()) {
|
|
917
|
+
if (view.conversation === conversation)
|
|
918
|
+
view.draft = draft;
|
|
634
919
|
}
|
|
635
920
|
}
|
|
921
|
+
async function draftAt(local, conversation) {
|
|
922
|
+
return (await local.chatDraft(conversation)) ?? undefined;
|
|
923
|
+
}
|
|
636
924
|
async function sealed(local, conversation, turns) {
|
|
637
|
-
const held =
|
|
925
|
+
const held = await draftAt(local, conversation);
|
|
638
926
|
const submitted = held?.submitted ?? [];
|
|
639
927
|
const left = submitted.filter((one) => one.turn === null || !turns.has(one.turn));
|
|
640
928
|
if (held === undefined || left.length === submitted.length)
|
|
@@ -645,85 +933,70 @@ export function createConversationStore(deps) {
|
|
|
645
933
|
function moved(agent, operation, to) {
|
|
646
934
|
const from = newChat(agent);
|
|
647
935
|
return deps.durably(async (local) => {
|
|
648
|
-
const held =
|
|
649
|
-
const earlier =
|
|
936
|
+
const held = await draftAt(local, from);
|
|
937
|
+
const earlier = held?.moves ?? [];
|
|
650
938
|
if (earlier.includes(operation))
|
|
651
939
|
return;
|
|
652
940
|
const blank = {
|
|
653
941
|
conversation: from,
|
|
654
942
|
text: '',
|
|
655
|
-
files: [],
|
|
656
943
|
revision: chatDraftRevision(),
|
|
657
944
|
};
|
|
658
945
|
const { moves: _answered, ...unsent } = held ?? blank;
|
|
659
|
-
const taken =
|
|
946
|
+
const taken = (await draftAt(local, to)) !== undefined || empty(unsent)
|
|
947
|
+
? []
|
|
948
|
+
: [{ ...unsent, conversation: to }];
|
|
660
949
|
const left = { ...(taken.length === 0 ? unsent : blank), moves: [...earlier, operation] };
|
|
661
950
|
await local.keepChatDrafts([left, ...taken]);
|
|
662
|
-
|
|
951
|
+
shownDraft(from, left);
|
|
663
952
|
for (const one of taken)
|
|
664
|
-
|
|
665
|
-
deps.publish(conversationChangeSet([
|
|
953
|
+
shownDraft(to, one);
|
|
954
|
+
deps.publish(conversationChangeSet([from, to]));
|
|
666
955
|
});
|
|
667
956
|
}
|
|
668
957
|
function withDraft(conversation, next) {
|
|
669
958
|
return deps.durably(async (local) => {
|
|
670
|
-
const following = await next(
|
|
959
|
+
const following = await next(await draftAt(local, conversation), local);
|
|
671
960
|
if (following === undefined)
|
|
672
961
|
return;
|
|
673
962
|
await kept(local, conversation, following);
|
|
674
|
-
deps.publish(conversationChangeSet([
|
|
963
|
+
deps.publish(conversationChangeSet([conversation]));
|
|
675
964
|
});
|
|
676
965
|
}
|
|
677
966
|
async function submitted(conversation, operation, draft) {
|
|
678
967
|
let submission;
|
|
679
|
-
let earlier = false;
|
|
680
968
|
await withDraft(conversation, (current) => {
|
|
681
969
|
submission = current?.submitted?.find((one) => one.operation === operation);
|
|
682
|
-
earlier = submission !== undefined;
|
|
683
970
|
if (submission !== undefined)
|
|
684
971
|
return undefined;
|
|
685
972
|
const said = draft ?? current;
|
|
686
|
-
submission = {
|
|
687
|
-
operation,
|
|
688
|
-
text: said?.text ?? '',
|
|
689
|
-
files: [...(said?.files ?? [])],
|
|
690
|
-
turn: null,
|
|
691
|
-
};
|
|
973
|
+
submission = { operation, text: said?.text ?? '', turn: null };
|
|
692
974
|
return {
|
|
693
975
|
conversation,
|
|
694
976
|
...(draft === undefined || current === undefined
|
|
695
|
-
? { text: '',
|
|
696
|
-
: { text: current.text,
|
|
977
|
+
? { text: '', revision: chatDraftRevision() }
|
|
978
|
+
: { text: current.text, revision: current.revision }),
|
|
697
979
|
submitted: [...(current?.submitted ?? []), submission],
|
|
698
980
|
};
|
|
699
981
|
});
|
|
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
|
-
});
|
|
982
|
+
return submission;
|
|
709
983
|
}
|
|
710
984
|
async function dispatched(conversation, submission) {
|
|
711
|
-
const dispatch = {};
|
|
985
|
+
const dispatch = { answered: false };
|
|
712
986
|
sending.set(submission.operation, dispatch);
|
|
713
987
|
try {
|
|
714
|
-
const
|
|
715
|
-
const result = await invoke('conversation.send', conversation, {
|
|
716
|
-
text: submission.text,
|
|
717
|
-
files,
|
|
988
|
+
const result = await invoke('conversations/send', conversation, {
|
|
718
989
|
operation_id: submission.operation,
|
|
990
|
+
text: submission.text,
|
|
719
991
|
});
|
|
992
|
+
dispatch.answered = result.kind !== 'transport-uncertainty';
|
|
720
993
|
if (result.kind === 'revoked-authorization')
|
|
721
994
|
return result;
|
|
722
995
|
if (result.kind !== 'action' && result.retryable) {
|
|
723
996
|
deps.unanswered();
|
|
724
997
|
return result;
|
|
725
998
|
}
|
|
726
|
-
const turn = answered(result, '
|
|
999
|
+
const turn = answered(result, 'message_id');
|
|
727
1000
|
await withDraft(conversation, async (current, local) => {
|
|
728
1001
|
const held = current?.submitted?.find((one) => one.operation === submission.operation);
|
|
729
1002
|
if (current === undefined || held === undefined || held.turn !== null)
|
|
@@ -743,72 +1016,80 @@ export function createConversationStore(deps) {
|
|
|
743
1016
|
sending.delete(submission.operation);
|
|
744
1017
|
}
|
|
745
1018
|
}
|
|
746
|
-
function invoke(name, conversation, extra = {}) {
|
|
747
|
-
return deps.call(name, { conversation, ...extra });
|
|
1019
|
+
function invoke(name, conversation, extra = { operation_id: changeBatchIdentity() }) {
|
|
1020
|
+
return deps.call(name, { conversation_id: conversation, ...extra });
|
|
748
1021
|
}
|
|
749
1022
|
const surface = {
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
1023
|
+
list() {
|
|
1024
|
+
return new Promise((settle) => {
|
|
1025
|
+
const answer = (listed) => {
|
|
1026
|
+
unlisted.delete(answer);
|
|
1027
|
+
listWatchers.delete(answer);
|
|
1028
|
+
settle(listed);
|
|
1029
|
+
};
|
|
1030
|
+
unlisted.add(answer);
|
|
1031
|
+
learned();
|
|
1032
|
+
});
|
|
753
1033
|
},
|
|
754
1034
|
async read(conversation, options = {}) {
|
|
755
|
-
const
|
|
1035
|
+
const { text, ...windowed } = options;
|
|
1036
|
+
const asked = askedOf(windowed);
|
|
1037
|
+
const phrase = phraseOf(text);
|
|
756
1038
|
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
|
-
|
|
1039
|
+
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before, phrase);
|
|
1040
|
+
const total = asked.total ? await local.messageCount(conversation, phrase) : null;
|
|
1041
|
+
const marked = await local.jobMarkers(conversation);
|
|
1042
|
+
return structuredClone(viewOf(conversation, messages, frameOf(asked, messages, more, total), (await local.chatDraft(conversation)) ?? null, await endedIn(conversation), marked));
|
|
760
1043
|
});
|
|
761
1044
|
},
|
|
762
1045
|
async create(input) {
|
|
763
|
-
const result = await deps.call('
|
|
764
|
-
const conversation = answered(result, '
|
|
1046
|
+
const result = await deps.call('conversations/create', input);
|
|
1047
|
+
const conversation = answered(result, 'conversation_id');
|
|
765
1048
|
if (conversation === null)
|
|
766
1049
|
return result;
|
|
767
|
-
|
|
1050
|
+
const listed = (await heldList()) ?? [];
|
|
1051
|
+
if (!listed.some((entry) => entry.conversation === conversation)) {
|
|
768
1052
|
creations.add(conversation);
|
|
1053
|
+
}
|
|
769
1054
|
const creation = creationOf(input);
|
|
770
1055
|
if (creation !== null)
|
|
771
1056
|
await moved(creation.agent, creation.operation, conversation);
|
|
772
1057
|
return result;
|
|
773
1058
|
},
|
|
774
1059
|
async send(conversation, operation = changeBatchIdentity(), draft) {
|
|
1060
|
+
if (deps.full())
|
|
1061
|
+
return DURABLE_WRITE;
|
|
775
1062
|
if (deps.online()) {
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
1063
|
+
const held = await submitted(conversation, operation, draft).catch((error) => {
|
|
1064
|
+
if (refusedForSpace(error))
|
|
1065
|
+
return null;
|
|
1066
|
+
throw error;
|
|
1067
|
+
});
|
|
1068
|
+
if (held === null)
|
|
1069
|
+
return DURABLE_WRITE;
|
|
1070
|
+
return dispatched(conversation, held);
|
|
781
1071
|
}
|
|
782
1072
|
if (draft !== undefined) {
|
|
783
1073
|
await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
|
|
784
1074
|
? undefined
|
|
785
|
-
: returned(current ?? { conversation, text: '',
|
|
1075
|
+
: returned(current ?? { conversation, text: '', revision: '' }, { operation, ...draft, turn: null }, current?.submitted ?? []));
|
|
786
1076
|
}
|
|
787
1077
|
return OFFLINE;
|
|
788
1078
|
},
|
|
789
1079
|
answer(conversation, answer) {
|
|
790
|
-
return invoke('
|
|
1080
|
+
return invoke('conversations/interaction/answer', conversation, {
|
|
1081
|
+
operation_id: changeBatchIdentity(),
|
|
1082
|
+
...answer,
|
|
1083
|
+
});
|
|
791
1084
|
},
|
|
792
1085
|
interrupt(conversation) {
|
|
793
|
-
return invoke('
|
|
1086
|
+
return invoke('conversations/interrupt', conversation);
|
|
794
1087
|
},
|
|
795
1088
|
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;
|
|
1089
|
+
return invoke('conversations/kill', conversation);
|
|
809
1090
|
},
|
|
810
1091
|
delete(conversation) {
|
|
811
|
-
return invoke('
|
|
1092
|
+
return invoke('conversations/delete', conversation);
|
|
812
1093
|
},
|
|
813
1094
|
};
|
|
814
1095
|
const chatDraft = {
|
|
@@ -816,7 +1097,6 @@ export function createConversationStore(deps) {
|
|
|
816
1097
|
return withDraft(conversation, (current) => ({
|
|
817
1098
|
conversation,
|
|
818
1099
|
text: draft.text,
|
|
819
|
-
files: [...draft.files],
|
|
820
1100
|
revision,
|
|
821
1101
|
...(current === undefined ? {} : pending(current)),
|
|
822
1102
|
}));
|
|
@@ -824,9 +1104,7 @@ export function createConversationStore(deps) {
|
|
|
824
1104
|
prepend(conversation, draft) {
|
|
825
1105
|
return withDraft(conversation, (current) => ({
|
|
826
1106
|
conversation,
|
|
827
|
-
...(current === undefined
|
|
828
|
-
? { text: draft.text, files: [...draft.files] }
|
|
829
|
-
: prepended(current, draft)),
|
|
1107
|
+
...(current === undefined ? { text: draft.text } : prepended(current, draft)),
|
|
830
1108
|
revision: chatDraftRevision(),
|
|
831
1109
|
...(current === undefined ? {} : pending(current)),
|
|
832
1110
|
}));
|
|
@@ -834,45 +1112,46 @@ export function createConversationStore(deps) {
|
|
|
834
1112
|
discard(conversation) {
|
|
835
1113
|
return withDraft(conversation, (current) => current === undefined
|
|
836
1114
|
? undefined
|
|
837
|
-
: {
|
|
838
|
-
conversation,
|
|
839
|
-
text: '',
|
|
840
|
-
files: [],
|
|
841
|
-
revision: chatDraftRevision(),
|
|
842
|
-
...pending(current),
|
|
843
|
-
});
|
|
1115
|
+
: { conversation, text: '', revision: chatDraftRevision(), ...pending(current) });
|
|
844
1116
|
},
|
|
845
1117
|
};
|
|
846
1118
|
return {
|
|
847
1119
|
surface,
|
|
848
1120
|
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);
|
|
1121
|
+
async opened(local) {
|
|
1122
|
+
const { conversationList, conversationCursor } = await local.facts();
|
|
1123
|
+
if (conversationList === null || listKnown)
|
|
1124
|
+
return;
|
|
1125
|
+
deps.stream()?.hold(conversationCursor);
|
|
1126
|
+
learned();
|
|
863
1127
|
},
|
|
864
1128
|
async reconcile() {
|
|
865
1129
|
if (!listKnown)
|
|
866
1130
|
return;
|
|
867
|
-
const
|
|
1131
|
+
const local = await deps.local();
|
|
1132
|
+
const [held, kept, { conversationList }] = await Promise.all([
|
|
1133
|
+
local.conversations(),
|
|
1134
|
+
local.chatDrafts(),
|
|
1135
|
+
local.facts(),
|
|
1136
|
+
]);
|
|
1137
|
+
const list = conversationList ?? [];
|
|
1138
|
+
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
1139
|
+
const named = new Set(entries.keys());
|
|
1140
|
+
const reads = new Map(held.map((one) => [one.conversation, one]));
|
|
868
1141
|
const leaving = [
|
|
869
|
-
...new Set([
|
|
1142
|
+
...new Set([
|
|
1143
|
+
...replicated,
|
|
1144
|
+
...reads.keys(),
|
|
1145
|
+
...kept.map(({ conversation }) => conversation),
|
|
1146
|
+
]),
|
|
870
1147
|
].filter((conversation) => !named.has(conversation) &&
|
|
871
1148
|
!creations.has(conversation) &&
|
|
872
|
-
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation)));
|
|
1149
|
+
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation, list)));
|
|
873
1150
|
for (const conversation of named) {
|
|
874
|
-
if (!replicated.has(conversation)
|
|
1151
|
+
if (!replicated.has(conversation) &&
|
|
1152
|
+
missed(conversation, reads.get(conversation), entries.get(conversation))) {
|
|
875
1153
|
behind.add(conversation);
|
|
1154
|
+
}
|
|
876
1155
|
}
|
|
877
1156
|
replicated = named;
|
|
878
1157
|
handReplicated();
|
|
@@ -880,6 +1159,11 @@ export function createConversationStore(deps) {
|
|
|
880
1159
|
await remove(leaving);
|
|
881
1160
|
},
|
|
882
1161
|
async catchUp(progress) {
|
|
1162
|
+
if (deps.full()) {
|
|
1163
|
+
if (behind.size > 0)
|
|
1164
|
+
progress.complete = false;
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
883
1167
|
const owed = (conversation) => behind.has(conversation) && replicated.has(conversation);
|
|
884
1168
|
const read = async (conversations) => {
|
|
885
1169
|
if (conversations.length === 0 || deps.closed())
|
|
@@ -898,16 +1182,16 @@ export function createConversationStore(deps) {
|
|
|
898
1182
|
progress.complete = false;
|
|
899
1183
|
},
|
|
900
1184
|
async resend(progress) {
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
1185
|
+
const local = await deps.local();
|
|
1186
|
+
const tried = new Set();
|
|
1187
|
+
for (const { conversation } of await local.chatDrafts()) {
|
|
1188
|
+
for (;;) {
|
|
1189
|
+
const submission = (await local.chatDraft(conversation))?.submitted?.find((one) => one.turn === null && !sending.has(one.operation) && !tried.has(one.operation));
|
|
1190
|
+
if (submission === undefined)
|
|
1191
|
+
break;
|
|
905
1192
|
if (deps.closed())
|
|
906
1193
|
return;
|
|
907
|
-
|
|
908
|
-
await forgotten(conversation, submission);
|
|
909
|
-
continue;
|
|
910
|
-
}
|
|
1194
|
+
tried.add(submission.operation);
|
|
911
1195
|
const result = await dispatched(conversation, submission);
|
|
912
1196
|
if (result.kind === 'revoked-authorization')
|
|
913
1197
|
return;
|
|
@@ -928,12 +1212,11 @@ export function createConversationStore(deps) {
|
|
|
928
1212
|
known() {
|
|
929
1213
|
return listKnown;
|
|
930
1214
|
},
|
|
931
|
-
reconnected() {
|
|
932
|
-
for (const conversation of replicated)
|
|
933
|
-
gap(conversation);
|
|
934
|
-
},
|
|
935
1215
|
reopened() {
|
|
936
|
-
|
|
1216
|
+
relisting = null;
|
|
1217
|
+
for (const [operation, dispatch] of sending)
|
|
1218
|
+
if (!dispatch.answered)
|
|
1219
|
+
sending.delete(operation);
|
|
937
1220
|
},
|
|
938
1221
|
lost() {
|
|
939
1222
|
catching.clear();
|
|
@@ -946,30 +1229,37 @@ export function createConversationStore(deps) {
|
|
|
946
1229
|
asked,
|
|
947
1230
|
watchers: new Set(),
|
|
948
1231
|
window: null,
|
|
1232
|
+
draft: null,
|
|
1233
|
+
ended: null,
|
|
1234
|
+
marked: [],
|
|
949
1235
|
more: false,
|
|
950
1236
|
total: null,
|
|
951
1237
|
};
|
|
952
1238
|
views.set(key, view);
|
|
953
1239
|
const watcher = { notify: deliver, ready: false };
|
|
954
1240
|
view.watchers.add(watcher);
|
|
955
|
-
|
|
956
|
-
|
|
1241
|
+
const reading = new AbortController();
|
|
1242
|
+
void untilAnswered(() => deps.durably(async (local) => {
|
|
957
1243
|
if (view.window !== null)
|
|
958
1244
|
return;
|
|
959
1245
|
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
1246
|
+
view.draft = (await local.chatDraft(conversation)) ?? null;
|
|
1247
|
+
view.ended = await endedIn(conversation);
|
|
960
1248
|
view.window = messages;
|
|
1249
|
+
view.marked = await local.jobMarkers(conversation);
|
|
961
1250
|
view.more = more;
|
|
962
1251
|
view.total = asked.total ? await local.messageCount(conversation) : null;
|
|
963
|
-
})
|
|
1252
|
+
}), reading.signal)
|
|
964
1253
|
.then(() => {
|
|
965
1254
|
if (deps.closed() || !view.watchers.has(watcher))
|
|
966
1255
|
return;
|
|
967
1256
|
watcher.ready = true;
|
|
968
1257
|
const window = view.window ?? [];
|
|
969
|
-
watcher.notify(viewOf(conversation, window, sharedFrame(view, window)));
|
|
1258
|
+
watcher.notify(viewOf(conversation, window, sharedFrame(view, window), view.draft, view.ended, view.marked));
|
|
970
1259
|
})
|
|
971
1260
|
.catch(() => { });
|
|
972
1261
|
return () => {
|
|
1262
|
+
reading.abort();
|
|
973
1263
|
if (!view.watchers.delete(watcher))
|
|
974
1264
|
return;
|
|
975
1265
|
if (view.watchers.size === 0)
|
|
@@ -977,77 +1267,73 @@ export function createConversationStore(deps) {
|
|
|
977
1267
|
};
|
|
978
1268
|
},
|
|
979
1269
|
watchList(deliver) {
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
if (!deps.closed() && listWatchers.has(deliver))
|
|
983
|
-
deliver(entries());
|
|
984
|
-
});
|
|
1270
|
+
unlisted.add(deliver);
|
|
1271
|
+
learned();
|
|
985
1272
|
return () => {
|
|
1273
|
+
unlisted.delete(deliver);
|
|
986
1274
|
listWatchers.delete(deliver);
|
|
987
1275
|
};
|
|
988
1276
|
},
|
|
989
1277
|
watchAgents(deliver) {
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
deliver(agents());
|
|
994
|
-
});
|
|
1278
|
+
unnamed.add(deliver);
|
|
1279
|
+
learned();
|
|
1280
|
+
readAgents();
|
|
995
1281
|
return () => {
|
|
1282
|
+
unnamed.delete(deliver);
|
|
996
1283
|
agentWatchers.delete(deliver);
|
|
997
1284
|
};
|
|
998
1285
|
},
|
|
1286
|
+
learned,
|
|
999
1287
|
changed(set) {
|
|
1000
1288
|
for (const conversation of set.conversations)
|
|
1001
1289
|
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
1290
|
},
|
|
1010
1291
|
receive(event) {
|
|
1011
1292
|
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);
|
|
1293
|
+
return;
|
|
1294
|
+
if (event.kind === 'list') {
|
|
1295
|
+
if (event.whole)
|
|
1296
|
+
relisting ??= new Map();
|
|
1297
|
+
if (relisting !== null) {
|
|
1298
|
+
for (const entry of event.entries)
|
|
1299
|
+
relisting.set(entry.conversation, { ...entry });
|
|
1029
1300
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1301
|
+
if (event.more && relisting !== null)
|
|
1302
|
+
return;
|
|
1303
|
+
const whole = relisting;
|
|
1304
|
+
relisting = null;
|
|
1305
|
+
listChanged({
|
|
1306
|
+
replacing: whole !== null,
|
|
1307
|
+
set: whole === null ? event.entries : [...whole.values()],
|
|
1308
|
+
gone: null,
|
|
1309
|
+
...(event.more ? { paged: true } : { cursor: event.cursor }),
|
|
1310
|
+
});
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
if (event.kind === 'listed') {
|
|
1314
|
+
relisting?.set(event.entry.conversation, { ...event.entry });
|
|
1315
|
+
listChanged({ replacing: false, set: [event.entry], gone: null });
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
if (event.kind === 'unlisted') {
|
|
1319
|
+
relisting?.delete(event.conversation);
|
|
1320
|
+
listChanged({ replacing: false, set: [], gone: event.conversation });
|
|
1321
|
+
return;
|
|
1035
1322
|
}
|
|
1036
1323
|
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
1324
|
},
|
|
1045
1325
|
close() {
|
|
1326
|
+
closing.abort();
|
|
1327
|
+
if (rowTimer !== null)
|
|
1328
|
+
clearTimeout(rowTimer);
|
|
1329
|
+
rowTimer = null;
|
|
1046
1330
|
views.clear();
|
|
1047
1331
|
lives.clear();
|
|
1048
1332
|
unsent.clear();
|
|
1049
1333
|
listWatchers.clear();
|
|
1334
|
+
unlisted.clear();
|
|
1050
1335
|
agentWatchers.clear();
|
|
1336
|
+
unnamed.clear();
|
|
1051
1337
|
},
|
|
1052
1338
|
};
|
|
1053
1339
|
}
|