@agentshouse/mdruntime 0.1.0-cd507e16e5fc0 → 0.1.0-cd574a610e9c8
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 +21 -19
- package/dist/acceptance.d.ts +0 -3
- package/dist/acceptance.d.ts.map +1 -1
- package/dist/acceptance.js +75 -165
- package/dist/act-lanes.d.ts +30 -0
- package/dist/act-lanes.d.ts.map +1 -0
- package/dist/act-lanes.js +225 -0
- package/dist/actions.d.ts +8 -2
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +118 -67
- package/dist/adapter.d.ts +90 -58
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +0 -1
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +0 -5
- package/dist/authored.d.ts +88 -0
- package/dist/authored.d.ts.map +1 -0
- package/dist/authored.js +345 -0
- package/dist/bootstrap.d.ts +1 -1
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +6 -19
- package/dist/change-set.d.ts +4 -0
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +6 -0
- package/dist/change.d.ts +4 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +7 -2
- package/dist/chat-types.d.ts +0 -2
- package/dist/chat-types.d.ts.map +1 -1
- package/dist/chat-types.js +0 -2
- package/dist/client.d.ts +13 -20
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +36 -20
- package/dist/collection.d.ts +25 -4
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +19 -2
- package/dist/column.d.ts +5 -0
- package/dist/column.d.ts.map +1 -0
- package/dist/column.js +9 -0
- package/dist/compile.d.ts +2 -0
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +31 -25
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +31 -24
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +1 -1
- package/dist/conversation-live.d.ts +26 -12
- package/dist/conversation-live.d.ts.map +1 -1
- package/dist/conversation-live.js +23 -12
- package/dist/conversation-row.d.ts +8 -1
- package/dist/conversation-row.d.ts.map +1 -1
- package/dist/conversation-row.js +20 -7
- package/dist/conversation.d.ts +37 -12
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +320 -234
- package/dist/declaration.d.ts +10 -0
- package/dist/declaration.d.ts.map +1 -0
- package/dist/declaration.js +24 -0
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +19 -44
- package/dist/durability.d.ts +4 -0
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +4 -0
- package/dist/entry.js +1 -1
- package/dist/expectation.d.ts +26 -13
- package/dist/expectation.d.ts.map +1 -1
- package/dist/expectation.js +72 -19
- package/dist/failure.d.ts +3 -0
- package/dist/failure.d.ts.map +1 -1
- package/dist/failure.js +6 -0
- package/dist/figures.d.ts.map +1 -1
- package/dist/figures.js +4 -2
- package/dist/file.d.ts +1 -1
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +3 -2
- package/dist/host.d.ts +18 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +59 -15
- package/dist/index.d.ts +16 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -7
- package/dist/install.d.ts +10 -6
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +92 -111
- package/dist/lifecycle.d.ts +1 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +54 -40
- package/dist/listing.d.ts +11 -12
- package/dist/listing.d.ts.map +1 -1
- package/dist/listing.js +48 -72
- package/dist/live.d.ts +5 -3
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +74 -33
- package/dist/loaded.d.ts +5 -0
- package/dist/loaded.d.ts.map +1 -0
- package/dist/loaded.js +40 -0
- package/dist/locks.d.ts +2 -4
- package/dist/locks.d.ts.map +1 -1
- package/dist/locks.js +10 -39
- package/dist/lost.d.ts.map +1 -1
- package/dist/lost.js +11 -23
- package/dist/media.d.ts +6 -1
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +68 -17
- package/dist/memory.d.ts +8 -3
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +92 -33
- package/dist/messages.d.ts +12 -6
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +30 -38
- package/dist/model.d.ts +0 -1
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +0 -5
- package/dist/models.d.ts +4 -8
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +97 -139
- package/dist/observation.d.ts +27 -12
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +184 -85
- package/dist/opened.d.ts +1 -1
- package/dist/opened.d.ts.map +1 -1
- package/dist/opened.js +5 -5
- package/dist/opening.d.ts.map +1 -1
- package/dist/opening.js +5 -9
- package/dist/outcome.d.ts +13 -1
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +32 -2
- package/dist/overlay.d.ts +6 -2
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +37 -24
- package/dist/page-metadata.d.ts +8 -0
- package/dist/page-metadata.d.ts.map +1 -0
- package/dist/page-metadata.js +19 -0
- package/dist/parts.d.ts +3 -58
- package/dist/parts.d.ts.map +1 -1
- package/dist/parts.js +10 -115
- package/dist/preparation.d.ts +27 -6
- package/dist/preparation.d.ts.map +1 -1
- package/dist/preparation.js +156 -68
- package/dist/presence.d.ts +58 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +231 -0
- package/dist/queries.d.ts +2 -2
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +67 -31
- package/dist/query.d.ts +0 -1
- package/dist/query.d.ts.map +1 -1
- package/dist/questions.d.ts +1 -5
- package/dist/questions.d.ts.map +1 -1
- package/dist/questions.js +1 -7
- package/dist/queue.d.ts +40 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +480 -0
- package/dist/reach.d.ts +2 -3
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +88 -26
- package/dist/react.d.ts +8 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +33 -1
- package/dist/readiness.d.ts +9 -3
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +3 -5
- package/dist/reads.d.ts +4 -2
- package/dist/reads.d.ts.map +1 -1
- package/dist/reads.js +11 -4
- package/dist/recovery.d.ts +3 -1
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +29 -7
- package/dist/refresh.js +2 -2
- package/dist/refusal.d.ts.map +1 -1
- package/dist/refusal.js +5 -6
- package/dist/replica.d.ts +5 -11
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +15 -17
- package/dist/retried.d.ts +30 -0
- package/dist/retried.d.ts.map +1 -0
- package/dist/retried.js +72 -0
- package/dist/room-draft.d.ts +31 -8
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +273 -66
- package/dist/room-drafts.d.ts.map +1 -1
- package/dist/room-drafts.js +22 -18
- package/dist/room-list.d.ts +10 -0
- package/dist/room-list.d.ts.map +1 -0
- package/dist/room-list.js +45 -0
- package/dist/rows.d.ts +2 -1
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +9 -10
- package/dist/runtime.d.ts +9 -18
- package/dist/runtime.d.ts.map +1 -1
- package/dist/save.d.ts +42 -90
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +327 -229
- package/dist/saves.d.ts +4 -40
- package/dist/saves.d.ts.map +1 -1
- package/dist/saves.js +143 -714
- package/dist/seed.d.ts.map +1 -1
- package/dist/seed.js +4 -5
- package/dist/shared.d.ts +0 -5
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +4 -90
- package/dist/shown.d.ts +7 -5
- package/dist/shown.d.ts.map +1 -1
- package/dist/shown.js +77 -63
- package/dist/socket/lanes.d.ts +12 -4
- package/dist/socket/lanes.d.ts.map +1 -1
- package/dist/socket/lanes.js +34 -8
- package/dist/socket/session.d.ts +0 -1
- package/dist/socket/session.d.ts.map +1 -1
- package/dist/socket.d.ts +3 -6
- package/dist/socket.d.ts.map +1 -1
- package/dist/socket.js +5 -16
- package/dist/source.d.ts +5 -7
- package/dist/source.d.ts.map +1 -1
- package/dist/source.js +18 -6
- package/dist/store/installs.d.ts +2 -2
- package/dist/store/installs.d.ts.map +1 -1
- package/dist/store/installs.js +10 -4
- package/dist/store/readiness.d.ts +5 -4
- package/dist/store/readiness.d.ts.map +1 -1
- package/dist/store/readiness.js +28 -12
- package/dist/store/records.d.ts +18 -7
- package/dist/store/records.d.ts.map +1 -1
- package/dist/store/records.js +58 -24
- package/dist/store/rooms-shown.d.ts +8 -0
- package/dist/store/rooms-shown.d.ts.map +1 -0
- package/dist/store/rooms-shown.js +13 -0
- package/dist/store/space.d.ts +1 -1
- package/dist/store/space.d.ts.map +1 -1
- package/dist/store/space.js +0 -2
- package/dist/store/watchers.js +1 -2
- package/dist/store.d.ts +23 -14
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +46 -17
- package/dist/stored.d.ts +25 -14
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +83 -32
- package/dist/surface.d.ts +5 -3
- package/dist/surface.d.ts.map +1 -1
- package/dist/surface.js +25 -23
- package/dist/sync.d.ts +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +96 -92
- package/dist/tables.d.ts +16 -57
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +91 -332
- package/dist/tallies.d.ts.map +1 -1
- package/dist/tallies.js +6 -7
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +4 -10
- package/dist/wire.d.ts +53 -7
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +17 -4
- package/package.json +3 -2
- package/dist/attempt.d.ts +0 -16
- package/dist/attempt.d.ts.map +0 -1
- package/dist/attempt.js +0 -70
- package/dist/job.d.ts +0 -33
- package/dist/job.d.ts.map +0 -1
- package/dist/job.js +0 -54
- package/dist/log.d.ts +0 -6
- package/dist/log.d.ts.map +0 -1
- package/dist/log.js +0 -14
- package/dist/socket/rooms.d.ts +0 -44
- package/dist/socket/rooms.d.ts.map +0 -1
- package/dist/socket/rooms.js +0 -90
- package/dist/store/fences.d.ts +0 -16
- package/dist/store/fences.d.ts.map +0 -1
- package/dist/store/fences.js +0 -26
package/dist/conversation.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { cursorOf, decodedCursor } from '@agentshouse/mdmodel';
|
|
2
|
+
import { applied, isTurn, standingState, } from '@agentshouse/session-content';
|
|
2
3
|
import { conversationChangeSet } from './change-set.js';
|
|
3
4
|
import { FACTS, QUIET, } from './conversation-live.js';
|
|
4
5
|
import { heldFacts } from './conversation-row.js';
|
|
5
|
-
import { runtimeError } from './failure.js';
|
|
6
|
+
import { runtimeError, uncaught } from './failure.js';
|
|
6
7
|
import { refusedForSpace } from './durability.js';
|
|
7
8
|
import { changeBatchIdentity, chatDraftRevision } from './identity.js';
|
|
8
|
-
import { OFFLINE } from './outcome.js';
|
|
9
|
-
import {
|
|
9
|
+
import { OFFLINE, } from './outcome.js';
|
|
10
|
+
import { runningLine } from './parts.js';
|
|
11
|
+
import { record, text } from './read.js';
|
|
10
12
|
import { openQuestion, questionAsked } from './questions.js';
|
|
11
13
|
import { untilAnswered } from './recovery.js';
|
|
14
|
+
import { retrying } from './retried.js';
|
|
12
15
|
import { capped, FROM_START, messageOrder, precedes } from './windows.js';
|
|
13
16
|
export function unheldView(conversation) {
|
|
14
17
|
return {
|
|
@@ -21,15 +24,19 @@ export function unheldView(conversation) {
|
|
|
21
24
|
commands: [],
|
|
22
25
|
options: [],
|
|
23
26
|
starting: null,
|
|
24
|
-
|
|
27
|
+
state: null,
|
|
25
28
|
link: null,
|
|
29
|
+
deliveryWaiting: [],
|
|
26
30
|
deliveryUnknown: [],
|
|
27
31
|
chatDraft: null,
|
|
28
|
-
|
|
32
|
+
dismissedSuggestion: null,
|
|
33
|
+
pins: [],
|
|
29
34
|
};
|
|
30
35
|
}
|
|
31
36
|
export const SESSION_STARTED = 'Session started';
|
|
32
37
|
const NEW_CHAT = 'new:';
|
|
38
|
+
const LISTING = 'listing';
|
|
39
|
+
export const CATCHING_UP = 'catching-up';
|
|
33
40
|
export const HISTORY_CONVERSATIONS = 64;
|
|
34
41
|
export function newChat(agent) {
|
|
35
42
|
return `${NEW_CHAT}${agent}`;
|
|
@@ -42,52 +49,15 @@ function creationOf(input) {
|
|
|
42
49
|
}
|
|
43
50
|
function startedTurn(turn, operation) {
|
|
44
51
|
if (operation.op === 'begin')
|
|
45
|
-
return { turn, started: operation.at, parts: []
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
turn,
|
|
49
|
-
started: null,
|
|
50
|
-
parts: [],
|
|
51
|
-
context: { used: operation.used, window: operation.window },
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
return operation.op === 'start' && operation.index === 0
|
|
55
|
-
? { turn, started: null, parts: [structuredClone(operation.part)], context: null }
|
|
56
|
-
: null;
|
|
57
|
-
}
|
|
58
|
-
function changedFields(part, operation) {
|
|
59
|
-
if (operation.op === 'append') {
|
|
60
|
-
return { text: `${String(part.text ?? '')}${operation.text}` };
|
|
61
|
-
}
|
|
62
|
-
if (operation.op === 'status') {
|
|
63
|
-
return { status: operation.status, result: structuredClone(operation.result) };
|
|
64
|
-
}
|
|
65
|
-
if (operation.op === 'count')
|
|
66
|
-
return { count: operation.count };
|
|
67
|
-
return { entries: structuredClone(operation.entries) };
|
|
52
|
+
return { turn, started: operation.at, parts: [] };
|
|
53
|
+
const parts = applied([], operation);
|
|
54
|
+
return parts === null ? null : { turn, started: null, parts };
|
|
68
55
|
}
|
|
69
56
|
function appliedTurn(held, operation) {
|
|
70
57
|
if (operation.op === 'begin')
|
|
71
58
|
return { ...held, started: operation.at };
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
if (operation.op === 'start') {
|
|
76
|
-
if (operation.index !== 0 && operation.index !== held.parts.length)
|
|
77
|
-
return null;
|
|
78
|
-
return {
|
|
79
|
-
...held,
|
|
80
|
-
parts: [...held.parts.slice(0, operation.index), structuredClone(operation.part)],
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
const part = held.parts[operation.index];
|
|
84
|
-
if (typeof part !== 'object' || part === null)
|
|
85
|
-
return null;
|
|
86
|
-
const changed = { ...part, ...changedFields(part, operation) };
|
|
87
|
-
return {
|
|
88
|
-
...held,
|
|
89
|
-
parts: held.parts.map((kept, at) => (at === operation.index ? changed : kept)),
|
|
90
|
-
};
|
|
59
|
+
const parts = applied(held.parts, operation);
|
|
60
|
+
return parts === null ? null : { ...held, parts };
|
|
91
61
|
}
|
|
92
62
|
function windowOf(held, arriving, limit) {
|
|
93
63
|
const byIdentity = new Map(held.map((message) => [message.identity, message]));
|
|
@@ -110,7 +80,7 @@ function frameOf(asked, messages, more, total) {
|
|
|
110
80
|
};
|
|
111
81
|
}
|
|
112
82
|
function newestOf(arriving, from) {
|
|
113
|
-
return arriving.reduce((top, message) => (top === null || message.
|
|
83
|
+
return arriving.reduce((top, message) => (top === null || message.change > top ? message.change : top), from);
|
|
114
84
|
}
|
|
115
85
|
function acceptedMessage(value) {
|
|
116
86
|
if (typeof value !== 'object' || value === null)
|
|
@@ -119,6 +89,7 @@ function acceptedMessage(value) {
|
|
|
119
89
|
if (typeof record.identity !== 'string' ||
|
|
120
90
|
typeof record.turn !== 'string' ||
|
|
121
91
|
typeof record.position !== 'string' ||
|
|
92
|
+
typeof record.change !== 'string' ||
|
|
122
93
|
typeof record.text !== 'string') {
|
|
123
94
|
return null;
|
|
124
95
|
}
|
|
@@ -126,6 +97,7 @@ function acceptedMessage(value) {
|
|
|
126
97
|
identity: record.identity,
|
|
127
98
|
turn: record.turn,
|
|
128
99
|
position: record.position,
|
|
100
|
+
change: record.change,
|
|
129
101
|
text: record.text,
|
|
130
102
|
message: structuredClone(record.message),
|
|
131
103
|
};
|
|
@@ -227,17 +199,17 @@ function withSubmitted(draft, submitted) {
|
|
|
227
199
|
const { submitted: _held, ...unsent } = draft;
|
|
228
200
|
return submitted.length === 0 ? unsent : { ...unsent, submitted };
|
|
229
201
|
}
|
|
230
|
-
function
|
|
231
|
-
return
|
|
202
|
+
export function joinedDraft(first, second) {
|
|
203
|
+
return [first, second].filter((one) => one !== '').join('\n');
|
|
232
204
|
}
|
|
233
205
|
function returned(draft, submission, others) {
|
|
234
206
|
return withSubmitted({
|
|
235
207
|
conversation: draft.conversation,
|
|
236
|
-
|
|
208
|
+
text: joinedDraft(submission.text, draft.text),
|
|
237
209
|
revision: chatDraftRevision(),
|
|
238
210
|
}, others);
|
|
239
211
|
}
|
|
240
|
-
function viewOf(alive, conversation, held, frame, draft, ended,
|
|
212
|
+
function viewOf(alive, conversation, held, frame, { draft, ended, dismissed, pins }) {
|
|
241
213
|
const facts = alive.liveOf(conversation);
|
|
242
214
|
return {
|
|
243
215
|
conversation,
|
|
@@ -255,26 +227,41 @@ function viewOf(alive, conversation, held, frame, draft, ended, marked) {
|
|
|
255
227
|
commands: structuredClone(facts.commands),
|
|
256
228
|
options: structuredClone(facts.options),
|
|
257
229
|
starting: facts.starting,
|
|
258
|
-
|
|
230
|
+
state: sessionOf(facts, held, ended),
|
|
259
231
|
link: facts.link === null ? null : { ...facts.link },
|
|
232
|
+
deliveryWaiting: [...facts.deliveryWaiting],
|
|
260
233
|
deliveryUnknown: [...facts.deliveryUnknown],
|
|
261
234
|
chatDraft: draft === null || unwritten(draft) ? null : { text: draft.text, revision: draft.revision },
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
: jobsOf(marked.filter(({ at }) => ended === null || at > ended), facts.turn),
|
|
235
|
+
dismissedSuggestion: dismissed,
|
|
236
|
+
pins: [...pins],
|
|
265
237
|
};
|
|
266
238
|
}
|
|
239
|
+
function sessionOf(facts, held, ended) {
|
|
240
|
+
if (facts.state !== null)
|
|
241
|
+
return structuredClone(facts.state);
|
|
242
|
+
const saved = [...held]
|
|
243
|
+
.reverse()
|
|
244
|
+
.map(({ message }) => record(message))
|
|
245
|
+
.find(({ content }) => isTurn(content));
|
|
246
|
+
const at = saved === undefined ? null : text(saved, 'accepted_at');
|
|
247
|
+
if (saved === undefined || !isTurn(saved.content) || at === null)
|
|
248
|
+
return null;
|
|
249
|
+
const down = facts.process?.running === false;
|
|
250
|
+
return structuredClone(standingState(saved.content.state, at, down ? at : ended));
|
|
251
|
+
}
|
|
267
252
|
function emit(alive, conversation) {
|
|
268
253
|
if (alive.deps.closed())
|
|
269
254
|
return;
|
|
270
255
|
for (const view of alive.views()) {
|
|
271
|
-
const
|
|
256
|
+
const held = view.held.now();
|
|
257
|
+
const { window } = held;
|
|
272
258
|
if (view.conversation !== conversation || window === null)
|
|
273
259
|
continue;
|
|
274
260
|
const ready = view.ready();
|
|
275
261
|
if (ready.length === 0)
|
|
276
262
|
continue;
|
|
277
|
-
const
|
|
263
|
+
const frame = sharedFrame(view, window);
|
|
264
|
+
const value = viewOf(alive, conversation, window, frame, held);
|
|
278
265
|
for (const watcher of ready)
|
|
279
266
|
watcher.notify(value);
|
|
280
267
|
}
|
|
@@ -285,23 +272,18 @@ function sharedFrame(view, window) {
|
|
|
285
272
|
}
|
|
286
273
|
async function slide(alive, local, conversation, arriving) {
|
|
287
274
|
let count;
|
|
288
|
-
let marked;
|
|
289
275
|
for (const view of alive.views()) {
|
|
290
276
|
const { held } = view;
|
|
291
277
|
const { window, total } = held.now();
|
|
292
278
|
if (view.conversation !== conversation || window === null)
|
|
293
279
|
continue;
|
|
294
280
|
if (arriving === null) {
|
|
295
|
-
held.set({ window: [],
|
|
281
|
+
held.set({ window: [], more: false, total: total === null ? null : 0 });
|
|
296
282
|
continue;
|
|
297
283
|
}
|
|
298
284
|
const joining = arriving.filter((message) => precedes(message, view.asked.before));
|
|
299
285
|
const next = windowOf(window, joining, view.asked.limit);
|
|
300
286
|
held.set({ window: next.messages, more: held.now().more || next.dropped });
|
|
301
|
-
if (arriving.length > 0) {
|
|
302
|
-
marked ??= await local.jobMarkers(conversation);
|
|
303
|
-
held.set({ marked });
|
|
304
|
-
}
|
|
305
287
|
if (held.now().total !== null && arriving.length > 0) {
|
|
306
288
|
count ??= await local.messageCount(conversation);
|
|
307
289
|
held.set({ total: count });
|
|
@@ -325,66 +307,90 @@ function rowOf(alive, conversation) {
|
|
|
325
307
|
};
|
|
326
308
|
}
|
|
327
309
|
async function entries(alive) {
|
|
328
|
-
const
|
|
329
|
-
if (
|
|
310
|
+
const listing = await heldListing(alive);
|
|
311
|
+
if (listing === null)
|
|
312
|
+
return null;
|
|
313
|
+
const list = listing.conversations;
|
|
314
|
+
const agents = new Map(listing.agents.map((agent) => [agent.id, agent]));
|
|
315
|
+
if (list.some((entry) => !agents.has(entry.agent)))
|
|
330
316
|
return null;
|
|
331
317
|
const held = list.length === 0
|
|
332
318
|
? []
|
|
333
319
|
: await alive.deps.durably((local) => local.conversationRows(list.map(({ conversation }) => conversation)));
|
|
334
320
|
const rows = new Map(held.map((one) => [one.conversation, one]));
|
|
335
|
-
return list.map((entry) =>
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
321
|
+
return list.map((entry) => {
|
|
322
|
+
const agent = agents.get(entry.agent);
|
|
323
|
+
return {
|
|
324
|
+
conversation: entry.conversation,
|
|
325
|
+
agent: { identity: agent.id, name: agent.name, retired: agent.retired_at !== null },
|
|
326
|
+
name: entry.name,
|
|
327
|
+
created: entry.created,
|
|
328
|
+
finished: entry.finished,
|
|
329
|
+
outcome: entry.outcome,
|
|
330
|
+
waiting: entry.waiting,
|
|
331
|
+
subject: entry.subject,
|
|
332
|
+
...rowOf(alive, entry.conversation),
|
|
333
|
+
...heldFacts(rows.get(entry.conversation), entry),
|
|
334
|
+
};
|
|
335
|
+
});
|
|
346
336
|
}
|
|
347
|
-
async function
|
|
348
|
-
const
|
|
349
|
-
if (
|
|
350
|
-
return
|
|
351
|
-
return !alive.known() && alive.deps.stream() !== undefined && alive.deps.online()
|
|
337
|
+
async function heldListing(alive) {
|
|
338
|
+
const { conversationList, agentList } = await (await alive.deps.local()).facts();
|
|
339
|
+
if (conversationList !== null && agentList !== null)
|
|
340
|
+
return { conversations: conversationList, agents: agentList };
|
|
341
|
+
return !alive.known() && alive.deps.stream() !== undefined && alive.deps.online()
|
|
342
|
+
? null
|
|
343
|
+
: { conversations: [], agents: [] };
|
|
352
344
|
}
|
|
353
345
|
async function endedIn(alive, conversation) {
|
|
354
|
-
const
|
|
355
|
-
return
|
|
346
|
+
const listing = await heldListing(alive);
|
|
347
|
+
return (listing?.conversations.find((entry) => entry.conversation === conversation)?.processEnded ??
|
|
348
|
+
null);
|
|
349
|
+
}
|
|
350
|
+
function upserted(kept, set, key) {
|
|
351
|
+
const held = new Map(kept.map((one) => [key(one), one]));
|
|
352
|
+
for (const one of set)
|
|
353
|
+
held.set(key(one), { ...one });
|
|
354
|
+
return held;
|
|
356
355
|
}
|
|
357
356
|
function listChanged(alive, change) {
|
|
358
357
|
void alive.deps
|
|
359
358
|
.durably(async (local) => {
|
|
360
|
-
const { conversationList, conversationCursor } = await local.facts();
|
|
361
|
-
const
|
|
362
|
-
const
|
|
363
|
-
for (const entry of change.set) {
|
|
364
|
-
held.set(entry.conversation, { ...entry });
|
|
359
|
+
const { conversationList, agentList, conversationCursor } = await local.facts();
|
|
360
|
+
const held = upserted(change.replacing ? [] : (conversationList ?? []), change.set, (entry) => entry.conversation);
|
|
361
|
+
for (const entry of change.set)
|
|
365
362
|
alive.created(entry.conversation);
|
|
366
|
-
}
|
|
367
363
|
if (change.gone !== null)
|
|
368
364
|
held.delete(change.gone);
|
|
369
365
|
const list = [...held.values()];
|
|
366
|
+
const agents = [
|
|
367
|
+
...upserted(change.replacing ? [] : (agentList ?? []), change.agents, (agent) => agent.id).values(),
|
|
368
|
+
];
|
|
370
369
|
if (JSON.stringify(list) !== JSON.stringify(conversationList)) {
|
|
371
370
|
await local.fact('conversationList', list);
|
|
372
371
|
}
|
|
372
|
+
if (JSON.stringify(agents) !== JSON.stringify(agentList)) {
|
|
373
|
+
await local.fact('agentList', agents);
|
|
374
|
+
}
|
|
373
375
|
if (change.cursor !== undefined) {
|
|
374
376
|
if (change.cursor !== conversationCursor) {
|
|
375
377
|
await local.fact('conversationCursor', change.cursor);
|
|
376
378
|
}
|
|
377
379
|
alive.deps.stream()?.hold(change.cursor);
|
|
378
380
|
}
|
|
379
|
-
return list;
|
|
381
|
+
return { conversations: list, agents };
|
|
380
382
|
})
|
|
381
|
-
.catch(async () =>
|
|
382
|
-
.
|
|
383
|
+
.catch(async () => {
|
|
384
|
+
const { conversationList, agentList } = await (await alive.deps.local()).facts();
|
|
385
|
+
return { conversations: conversationList ?? [], agents: agentList ?? [] };
|
|
386
|
+
})
|
|
387
|
+
.then((listing) => {
|
|
383
388
|
if (alive.deps.closed() || change.paged === true)
|
|
384
389
|
return;
|
|
390
|
+
const list = listing.conversations;
|
|
385
391
|
endedAnew(alive, list);
|
|
386
392
|
if (change.cursor !== undefined) {
|
|
387
|
-
alive.held.set({ listKnown: true });
|
|
393
|
+
alive.held.set({ listKnown: true, openingListed: true });
|
|
388
394
|
settleBehind(alive, list);
|
|
389
395
|
openingEnded(alive);
|
|
390
396
|
alive.deps.settled();
|
|
@@ -392,14 +398,15 @@ function listChanged(alive, change) {
|
|
|
392
398
|
emitList(alive);
|
|
393
399
|
if (!alive.known())
|
|
394
400
|
return;
|
|
395
|
-
retiredDrafts(alive,
|
|
396
|
-
const { replicated } = alive.held.now();
|
|
397
|
-
if (change.cursor === undefined
|
|
398
|
-
|
|
399
|
-
list.some(({ conversation }) => !replicated.has(conversation))
|
|
401
|
+
retiredDrafts(alive, listing);
|
|
402
|
+
const { replicated, openingRead } = alive.held.now();
|
|
403
|
+
if (change.cursor === undefined
|
|
404
|
+
? list.length !== replicated.size ||
|
|
405
|
+
list.some(({ conversation }) => !replicated.has(conversation))
|
|
406
|
+
: openingRead) {
|
|
400
407
|
alive.deps.again();
|
|
401
408
|
}
|
|
402
|
-
},
|
|
409
|
+
}, uncaught);
|
|
403
410
|
}
|
|
404
411
|
function endedAnew(alive, list) {
|
|
405
412
|
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
@@ -412,20 +419,23 @@ function endedAnew(alive, list) {
|
|
|
412
419
|
emit(alive, view.conversation);
|
|
413
420
|
}
|
|
414
421
|
}
|
|
415
|
-
function
|
|
416
|
-
const reading =
|
|
422
|
+
function shownListing(alive, work) {
|
|
423
|
+
const reading = heldListing(alive);
|
|
417
424
|
alive.inOrder(async () => {
|
|
418
|
-
const
|
|
419
|
-
|
|
425
|
+
const listing = await reading.catch((error) => {
|
|
426
|
+
uncaught(error);
|
|
427
|
+
return null;
|
|
428
|
+
});
|
|
429
|
+
if (listing === null || alive.deps.closed())
|
|
420
430
|
return;
|
|
421
|
-
work(
|
|
431
|
+
work(listing);
|
|
422
432
|
});
|
|
423
433
|
}
|
|
424
434
|
async function told(alive) {
|
|
425
435
|
try {
|
|
426
436
|
while (alive.held.now().listOwed && !alive.deps.closed()) {
|
|
427
437
|
alive.held.set({ listOwed: false });
|
|
428
|
-
const value = await untilAnswered(() => entries(alive), alive.closing);
|
|
438
|
+
const value = await untilAnswered(retrying(alive.deps.retries, 'conversations', LISTING, () => entries(alive)), alive.closing, () => true, alive.deps.recovery);
|
|
429
439
|
if (alive.deps.closed())
|
|
430
440
|
return;
|
|
431
441
|
if (value === null)
|
|
@@ -463,57 +473,48 @@ export function conversationsLearned(alive) {
|
|
|
463
473
|
return;
|
|
464
474
|
if (alive.listeners.waiting())
|
|
465
475
|
tellList(alive);
|
|
466
|
-
if (!alive.agentListeners.waiting())
|
|
476
|
+
if (!alive.agentListeners.waiting() && !alive.listedListeners.waiting())
|
|
467
477
|
return;
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
478
|
+
shownListing(alive, (listing) => {
|
|
479
|
+
alive.agentListeners.welcome(agentsOf(listing));
|
|
480
|
+
alive.listedListeners.welcome(structuredClone(listing.agents));
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
function agentsOf(listing) {
|
|
484
|
+
return listing.agents
|
|
485
|
+
.filter((agent) => agent.retired_at === null)
|
|
486
|
+
.map((agent) => ({
|
|
487
|
+
identity: agent.id,
|
|
488
|
+
name: agent.name,
|
|
489
|
+
cli: agent.cli,
|
|
490
|
+
model: agent.model,
|
|
491
|
+
effort: agent.effort,
|
|
492
|
+
environment: {
|
|
493
|
+
identity: agent.environment,
|
|
494
|
+
name: agent.environment_name,
|
|
495
|
+
state: agent.environment_connected ? 'online' : 'offline',
|
|
496
|
+
},
|
|
497
|
+
}))
|
|
480
498
|
.sort((left, right) => left.name === right.name
|
|
481
499
|
? left.identity.localeCompare(right.identity)
|
|
482
500
|
: left.name.localeCompare(right.name));
|
|
483
501
|
}
|
|
484
|
-
function readAgents(alive) {
|
|
485
|
-
const stream = alive.deps.stream();
|
|
486
|
-
if (stream?.agents === undefined || !alive.deps.online() || alive.held.now().agentsReading)
|
|
487
|
-
return;
|
|
488
|
-
const { agents: read } = stream;
|
|
489
|
-
const { agentListeners } = alive;
|
|
490
|
-
alive.held.set({ agentsReading: true });
|
|
491
|
-
void alive.deps.recovery
|
|
492
|
-
.attempt('agents', async () => {
|
|
493
|
-
if (!alive.deps.online() || (!agentListeners.waiting() && !agentListeners.told())) {
|
|
494
|
-
return 'done';
|
|
495
|
-
}
|
|
496
|
-
const listed = await read();
|
|
497
|
-
if (listed === null)
|
|
498
|
-
return 'done';
|
|
499
|
-
alive.held.set({ listedAgents: listed });
|
|
500
|
-
emitAgents(alive);
|
|
501
|
-
return 'done';
|
|
502
|
-
})
|
|
503
|
-
.finally(() => {
|
|
504
|
-
alive.held.set({ agentsReading: false });
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
502
|
function emitAgents(alive) {
|
|
508
|
-
|
|
503
|
+
const { agentListeners, listedListeners } = alive;
|
|
504
|
+
if (alive.deps.closed() || (!agentListeners.told() && !listedListeners.told()))
|
|
509
505
|
return;
|
|
510
|
-
|
|
511
|
-
const value =
|
|
506
|
+
shownListing(alive, (listing) => {
|
|
507
|
+
const value = agentsOf(listing);
|
|
512
508
|
const shown = JSON.stringify(value);
|
|
513
|
-
if (shown
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
509
|
+
if (shown !== alive.held.now().agentsShown) {
|
|
510
|
+
alive.held.set({ agentsShown: shown });
|
|
511
|
+
agentListeners.tell(value);
|
|
512
|
+
}
|
|
513
|
+
const listed = JSON.stringify(listing.agents);
|
|
514
|
+
if (listed !== alive.held.now().listedShown) {
|
|
515
|
+
alive.held.set({ listedShown: listed });
|
|
516
|
+
listedListeners.tell(structuredClone(listing.agents));
|
|
517
|
+
}
|
|
517
518
|
});
|
|
518
519
|
}
|
|
519
520
|
function setLive(alive, conversation, next) {
|
|
@@ -527,11 +528,11 @@ function setLive(alive, conversation, next) {
|
|
|
527
528
|
after.asked !== before.asked)
|
|
528
529
|
tellSoon(alive);
|
|
529
530
|
}
|
|
530
|
-
function retiredChat(conversation,
|
|
531
|
+
function retiredChat(conversation, listing) {
|
|
531
532
|
if (!conversation.startsWith(NEW_CHAT))
|
|
532
533
|
return false;
|
|
533
534
|
const agent = conversation.slice(NEW_CHAT.length);
|
|
534
|
-
return
|
|
535
|
+
return listing.agents.some((one) => one.id === agent && one.retired_at !== null);
|
|
535
536
|
}
|
|
536
537
|
function live(alive, conversation, change) {
|
|
537
538
|
alive.factsHeard(conversation, FACTS.filter((one) => one in change));
|
|
@@ -550,8 +551,9 @@ function openingEnded(alive) {
|
|
|
550
551
|
commands: facts.has('commands') ? QUIET.commands : held.commands,
|
|
551
552
|
options: facts.has('options') ? QUIET.options : held.options,
|
|
552
553
|
starting: facts.has('starting') ? QUIET.starting : held.starting,
|
|
553
|
-
|
|
554
|
+
state: facts.has('state') ? QUIET.state : held.state,
|
|
554
555
|
link: facts.has('link') ? QUIET.link : held.link,
|
|
556
|
+
deliveryWaiting: facts.has('deliveryWaiting') ? QUIET.deliveryWaiting : held.deliveryWaiting,
|
|
555
557
|
deliveryUnknown: facts.has('deliveryUnknown') ? QUIET.deliveryUnknown : held.deliveryUnknown,
|
|
556
558
|
});
|
|
557
559
|
emit(alive, conversation);
|
|
@@ -583,19 +585,13 @@ function handReplicated(alive) {
|
|
|
583
585
|
}
|
|
584
586
|
async function remove(alive, leaving) {
|
|
585
587
|
await alive.deps.durably(async (local) => {
|
|
586
|
-
const kept = new Set(
|
|
587
|
-
...(await local.conversations(leaving)).map(({ conversation }) => conversation),
|
|
588
|
-
...(await local.chatDrafts())
|
|
589
|
-
.filter(({ conversation }) => leaving.includes(conversation))
|
|
590
|
-
.map(({ conversation }) => conversation),
|
|
591
|
-
]);
|
|
592
|
-
await local.dropConversations(leaving);
|
|
588
|
+
const kept = new Set(await local.dropConversations(leaving));
|
|
593
589
|
const changed = [];
|
|
594
590
|
for (const conversation of leaving) {
|
|
595
591
|
if (kept.has(conversation) || alive.liveHeld(conversation) !== undefined) {
|
|
596
592
|
changed.push(conversation);
|
|
597
593
|
}
|
|
598
|
-
|
|
594
|
+
heldInViews(alive, conversation, { draft: null, dismissed: null });
|
|
599
595
|
alive.forget(conversation);
|
|
600
596
|
setLive(alive, conversation, null);
|
|
601
597
|
await slide(alive, local, conversation, null);
|
|
@@ -624,7 +620,7 @@ async function readsOf(local, conversations) {
|
|
|
624
620
|
return new Map((await local.conversations(conversations)).map((held) => [held.conversation, held]));
|
|
625
621
|
}
|
|
626
622
|
function retiredDrafts(alive, list) {
|
|
627
|
-
if (!list.some((
|
|
623
|
+
if (!list.agents.some((agent) => agent.retired_at !== null))
|
|
628
624
|
return;
|
|
629
625
|
void alive.deps
|
|
630
626
|
.local()
|
|
@@ -634,7 +630,7 @@ function retiredDrafts(alive, list) {
|
|
|
634
630
|
held.some(({ conversation }) => retiredChat(conversation, list))) {
|
|
635
631
|
alive.deps.again();
|
|
636
632
|
}
|
|
637
|
-
},
|
|
633
|
+
}, uncaught);
|
|
638
634
|
}
|
|
639
635
|
function settleBehind(alive, list) {
|
|
640
636
|
void alive.deps
|
|
@@ -660,21 +656,19 @@ function settleBehind(alive, list) {
|
|
|
660
656
|
alive.deps.settled();
|
|
661
657
|
if (owed)
|
|
662
658
|
alive.deps.again();
|
|
663
|
-
},
|
|
659
|
+
}, uncaught);
|
|
664
660
|
}
|
|
665
661
|
function keep(alive, conversation, message) {
|
|
666
662
|
return alive.deps.durably(async (local) => {
|
|
667
663
|
if (!alive.held.now().replicated.has(conversation))
|
|
668
664
|
return;
|
|
669
665
|
const read = (await readsOf(local, [conversation])).get(conversation)?.read;
|
|
670
|
-
const advances = read !== undefined &&
|
|
671
|
-
!alive.behind(conversation) &&
|
|
672
|
-
(read === null || message.position > read);
|
|
666
|
+
const advances = read !== undefined && !alive.behind(conversation) && (read === null || message.change > read);
|
|
673
667
|
await sealed(alive, local, conversation, new Set([message.turn]));
|
|
674
668
|
await local.keepMessages({
|
|
675
669
|
conversation,
|
|
676
670
|
messages: [message],
|
|
677
|
-
...(advances ? { read: { at: message.
|
|
671
|
+
...(advances ? { read: { at: message.change, partial: false } } : {}),
|
|
678
672
|
});
|
|
679
673
|
sealTurns(alive, conversation, new Set([message.turn]));
|
|
680
674
|
await slide(alive, local, conversation, [message]);
|
|
@@ -786,8 +780,8 @@ function heard(alive, event) {
|
|
|
786
780
|
live(alive, conversation, { starting: event.step });
|
|
787
781
|
return;
|
|
788
782
|
}
|
|
789
|
-
if (event.kind === '
|
|
790
|
-
live(alive, conversation, {
|
|
783
|
+
if (event.kind === 'state') {
|
|
784
|
+
live(alive, conversation, { state: structuredClone(event.state) });
|
|
791
785
|
return;
|
|
792
786
|
}
|
|
793
787
|
if (event.kind === 'link') {
|
|
@@ -795,13 +789,16 @@ function heard(alive, event) {
|
|
|
795
789
|
return;
|
|
796
790
|
}
|
|
797
791
|
if (event.kind === 'deliveries') {
|
|
798
|
-
live(alive, conversation, {
|
|
792
|
+
live(alive, conversation, {
|
|
793
|
+
deliveryWaiting: [...event.waiting],
|
|
794
|
+
deliveryUnknown: [...event.unknown],
|
|
795
|
+
});
|
|
799
796
|
return;
|
|
800
797
|
}
|
|
801
798
|
const arriving = acceptedMessage(event.message);
|
|
802
799
|
if (arriving === null)
|
|
803
800
|
return;
|
|
804
|
-
alive.heardAt(conversation, arriving.
|
|
801
|
+
alive.heardAt(conversation, arriving.change);
|
|
805
802
|
if (alive.held.now().replicated.has(conversation)) {
|
|
806
803
|
if (alive.deps.full()) {
|
|
807
804
|
alive.gapOpened(conversation);
|
|
@@ -810,6 +807,8 @@ function heard(alive, event) {
|
|
|
810
807
|
void keep(alive, conversation, arriving).catch((error) => {
|
|
811
808
|
if (refusedForSpace(error))
|
|
812
809
|
alive.gapOpened(conversation);
|
|
810
|
+
else
|
|
811
|
+
uncaught(error);
|
|
813
812
|
});
|
|
814
813
|
return;
|
|
815
814
|
}
|
|
@@ -817,19 +816,27 @@ function heard(alive, event) {
|
|
|
817
816
|
emit(alive, conversation);
|
|
818
817
|
}
|
|
819
818
|
async function kept(alive, local, conversation, following) {
|
|
820
|
-
const
|
|
821
|
-
if (
|
|
819
|
+
const draft = following === null || empty(following) ? null : following;
|
|
820
|
+
if (draft === null)
|
|
822
821
|
await local.dropChatDraft(conversation);
|
|
823
822
|
else
|
|
824
|
-
await local.keepChatDrafts([
|
|
825
|
-
|
|
823
|
+
await local.keepChatDrafts([draft]);
|
|
824
|
+
heldInViews(alive, conversation, { draft });
|
|
826
825
|
}
|
|
827
|
-
function
|
|
826
|
+
function heldInViews(alive, conversation, held) {
|
|
828
827
|
for (const view of alive.views()) {
|
|
829
828
|
if (view.conversation === conversation)
|
|
830
|
-
view.held.set(
|
|
829
|
+
view.held.set(held);
|
|
831
830
|
}
|
|
832
831
|
}
|
|
832
|
+
async function factOf(local, name) {
|
|
833
|
+
return Object.fromEntries((await local.conversationFacts())
|
|
834
|
+
.filter((fact) => fact.name === name)
|
|
835
|
+
.map(({ conversation, value }) => [conversation, value]));
|
|
836
|
+
}
|
|
837
|
+
async function dismissedIn(local, conversation) {
|
|
838
|
+
return (await factOf(local, 'dismissedSuggestion'))[conversation] ?? null;
|
|
839
|
+
}
|
|
833
840
|
async function draftAt(local, conversation) {
|
|
834
841
|
return (await local.chatDraft(conversation)) ?? undefined;
|
|
835
842
|
}
|
|
@@ -860,9 +867,9 @@ function moved(alive, agent, operation, to) {
|
|
|
860
867
|
: [{ ...unsent, conversation: to }];
|
|
861
868
|
const left = { ...(taken.length === 0 ? unsent : blank), moves: [...earlier, operation] };
|
|
862
869
|
await local.keepChatDrafts([left, ...taken]);
|
|
863
|
-
|
|
870
|
+
heldInViews(alive, from, { draft: left });
|
|
864
871
|
for (const one of taken)
|
|
865
|
-
|
|
872
|
+
heldInViews(alive, to, { draft: one });
|
|
866
873
|
alive.deps.publish(conversationChangeSet([from, to]));
|
|
867
874
|
});
|
|
868
875
|
}
|
|
@@ -893,13 +900,10 @@ async function submitted(alive, conversation, operation, draft) {
|
|
|
893
900
|
});
|
|
894
901
|
return submission;
|
|
895
902
|
}
|
|
896
|
-
async function dispatched(alive, conversation, submission) {
|
|
903
|
+
async function dispatched(alive, conversation, submission, resent = false) {
|
|
897
904
|
const dispatch = alive.sendingBegan(submission.operation);
|
|
898
905
|
try {
|
|
899
|
-
const result = await invoke(alive, 'conversations/send', conversation, {
|
|
900
|
-
operation_id: submission.operation,
|
|
901
|
-
text: submission.text,
|
|
902
|
-
});
|
|
906
|
+
const result = await invoke(alive, 'conversations/send', conversation, submission.operation, { text: submission.text }, { step: 'sending', instance: `message ${submission.operation}` });
|
|
903
907
|
dispatch.set({ answered: result.kind !== 'transport-uncertainty' });
|
|
904
908
|
if (result.kind === 'revoked-authorization')
|
|
905
909
|
return result;
|
|
@@ -907,6 +911,7 @@ async function dispatched(alive, conversation, submission) {
|
|
|
907
911
|
alive.deps.unanswered();
|
|
908
912
|
return result;
|
|
909
913
|
}
|
|
914
|
+
alive.deps.heard(submission.operation, resent);
|
|
910
915
|
const turn = answered(result, 'message_id');
|
|
911
916
|
await withDraft(alive, conversation, async (current, local) => {
|
|
912
917
|
const held = current?.submitted?.find((one) => one.operation === submission.operation);
|
|
@@ -926,11 +931,12 @@ async function dispatched(alive, conversation, submission) {
|
|
|
926
931
|
alive.sendingEnded(submission.operation, dispatch);
|
|
927
932
|
}
|
|
928
933
|
}
|
|
929
|
-
function invoke(alive, name, conversation, extra = {
|
|
930
|
-
return alive.deps.call(name, { conversation_id: conversation, ...extra });
|
|
934
|
+
function invoke(alive, name, conversation, operation, extra = {}, attempt) {
|
|
935
|
+
return alive.deps.call(name, { conversation_id: conversation, operation_id: operation, ...extra }, attempt);
|
|
931
936
|
}
|
|
932
|
-
export function conversationSurface(alive) {
|
|
937
|
+
export function conversationSurface(alive, files) {
|
|
933
938
|
return {
|
|
939
|
+
...files,
|
|
934
940
|
list() {
|
|
935
941
|
return new Promise((settle) => {
|
|
936
942
|
const answer = (listed) => {
|
|
@@ -948,8 +954,12 @@ export function conversationSurface(alive) {
|
|
|
948
954
|
return alive.deps.durably(async (local) => {
|
|
949
955
|
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before, phrase);
|
|
950
956
|
const total = asked.total ? await local.messageCount(conversation, phrase) : null;
|
|
951
|
-
|
|
952
|
-
|
|
957
|
+
return structuredClone(viewOf(alive, conversation, messages, frameOf(asked, messages, more, total), {
|
|
958
|
+
draft: (await local.chatDraft(conversation)) ?? null,
|
|
959
|
+
ended: await endedIn(alive, conversation),
|
|
960
|
+
dismissed: await dismissedIn(local, conversation),
|
|
961
|
+
pins: (await local.facts()).chatPins,
|
|
962
|
+
}));
|
|
953
963
|
});
|
|
954
964
|
},
|
|
955
965
|
async create(input) {
|
|
@@ -957,7 +967,7 @@ export function conversationSurface(alive) {
|
|
|
957
967
|
const conversation = answered(result, 'conversation_id');
|
|
958
968
|
if (conversation === null)
|
|
959
969
|
return result;
|
|
960
|
-
const listed = (await
|
|
970
|
+
const listed = (await heldListing(alive))?.conversations ?? [];
|
|
961
971
|
if (!listed.some((entry) => entry.conversation === conversation)) {
|
|
962
972
|
alive.creating(conversation);
|
|
963
973
|
}
|
|
@@ -986,40 +996,90 @@ export function conversationSurface(alive) {
|
|
|
986
996
|
}
|
|
987
997
|
return OFFLINE;
|
|
988
998
|
},
|
|
989
|
-
answer(conversation, answer) {
|
|
990
|
-
return invoke(alive, 'conversations/interaction/answer', conversation,
|
|
991
|
-
|
|
992
|
-
|
|
999
|
+
answer(conversation, answer, operation) {
|
|
1000
|
+
return invoke(alive, 'conversations/interaction/answer', conversation, operation, answer);
|
|
1001
|
+
},
|
|
1002
|
+
interrupt(conversation, operation) {
|
|
1003
|
+
return invoke(alive, 'conversations/interrupt', conversation, operation);
|
|
1004
|
+
},
|
|
1005
|
+
kill(conversation, operation) {
|
|
1006
|
+
return invoke(alive, 'conversations/kill', conversation, operation);
|
|
1007
|
+
},
|
|
1008
|
+
delete(conversation, operation) {
|
|
1009
|
+
return invoke(alive, 'conversations/delete', conversation, operation);
|
|
1010
|
+
},
|
|
1011
|
+
takeOut(conversation, message, operation) {
|
|
1012
|
+
return invoke(alive, 'conversations/take-out', conversation, operation, {
|
|
1013
|
+
message_id: message,
|
|
1014
|
+
});
|
|
1015
|
+
},
|
|
1016
|
+
decide({ request, room, message }, decision, operation) {
|
|
1017
|
+
return alive.deps.call('agent-functions/decide', {
|
|
1018
|
+
room_ref: room,
|
|
1019
|
+
request,
|
|
1020
|
+
...(message === undefined ? {} : { message }),
|
|
1021
|
+
decision,
|
|
1022
|
+
operation_id: operation,
|
|
1023
|
+
});
|
|
1024
|
+
},
|
|
1025
|
+
rename(conversation, name, operation) {
|
|
1026
|
+
return invoke(alive, 'conversations/rename', conversation, operation, { name });
|
|
1027
|
+
},
|
|
1028
|
+
option(conversation, option, value, operation) {
|
|
1029
|
+
return invoke(alive, 'conversations/option/set', conversation, operation, { option, value });
|
|
1030
|
+
},
|
|
1031
|
+
retry(conversation, message, operation) {
|
|
1032
|
+
return invoke(alive, 'conversations/retry', conversation, operation, {
|
|
1033
|
+
message_id: message,
|
|
993
1034
|
});
|
|
994
1035
|
},
|
|
995
|
-
|
|
996
|
-
|
|
1036
|
+
async pin(figures) {
|
|
1037
|
+
const pins = [...figures];
|
|
1038
|
+
await alive.deps.durably((local) => local.fact('chatPins', pins));
|
|
1039
|
+
const views = [...alive.views()];
|
|
1040
|
+
for (const view of views)
|
|
1041
|
+
view.held.set({ pins });
|
|
1042
|
+
for (const conversation of new Set(views.map((view) => view.conversation))) {
|
|
1043
|
+
emit(alive, conversation);
|
|
1044
|
+
}
|
|
997
1045
|
},
|
|
998
|
-
|
|
999
|
-
|
|
1046
|
+
async openTurn(conversation, turn) {
|
|
1047
|
+
await alive.deps.durably((local) => local.keepConversationFact({ conversation, name: 'openedTurn', value: turn }));
|
|
1048
|
+
tellList(alive);
|
|
1000
1049
|
},
|
|
1001
|
-
|
|
1002
|
-
return
|
|
1050
|
+
dismissSuggestion(conversation, suggestion) {
|
|
1051
|
+
return alive.deps.durably(async (local) => {
|
|
1052
|
+
if ((await dismissedIn(local, conversation)) === suggestion)
|
|
1053
|
+
return;
|
|
1054
|
+
await local.keepConversationFact({
|
|
1055
|
+
conversation,
|
|
1056
|
+
name: 'dismissedSuggestion',
|
|
1057
|
+
value: suggestion,
|
|
1058
|
+
});
|
|
1059
|
+
heldInViews(alive, conversation, { dismissed: suggestion });
|
|
1060
|
+
alive.deps.publish(conversationChangeSet([conversation]));
|
|
1061
|
+
});
|
|
1003
1062
|
},
|
|
1004
1063
|
};
|
|
1005
1064
|
}
|
|
1065
|
+
function rewritten(alive, conversation, text, revision = chatDraftRevision()) {
|
|
1066
|
+
return withDraft(alive, conversation, (current) => ({
|
|
1067
|
+
conversation,
|
|
1068
|
+
text: text(current?.text ?? ''),
|
|
1069
|
+
revision,
|
|
1070
|
+
...(current === undefined ? {} : pending(current)),
|
|
1071
|
+
}));
|
|
1072
|
+
}
|
|
1006
1073
|
export function chatDraftSurface(alive) {
|
|
1007
1074
|
return {
|
|
1008
|
-
write(conversation, draft, revision
|
|
1009
|
-
return
|
|
1010
|
-
conversation,
|
|
1011
|
-
text: draft.text,
|
|
1012
|
-
revision,
|
|
1013
|
-
...(current === undefined ? {} : pending(current)),
|
|
1014
|
-
}));
|
|
1075
|
+
write(conversation, draft, revision) {
|
|
1076
|
+
return rewritten(alive, conversation, () => draft.text, revision);
|
|
1015
1077
|
},
|
|
1016
1078
|
prepend(conversation, draft) {
|
|
1017
|
-
return
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
...(current === undefined ? {} : pending(current)),
|
|
1022
|
-
}));
|
|
1079
|
+
return rewritten(alive, conversation, (held) => joinedDraft(draft.text, held));
|
|
1080
|
+
},
|
|
1081
|
+
append(conversation, draft) {
|
|
1082
|
+
return rewritten(alive, conversation, (held) => joinedDraft(held, draft.text));
|
|
1023
1083
|
},
|
|
1024
1084
|
discard(conversation) {
|
|
1025
1085
|
return withDraft(alive, conversation, (current) => current === undefined
|
|
@@ -1029,31 +1089,34 @@ export function chatDraftSurface(alive) {
|
|
|
1029
1089
|
};
|
|
1030
1090
|
}
|
|
1031
1091
|
export async function conversationsOpened(alive, local) {
|
|
1032
|
-
const { conversationList, conversationCursor } = await local.facts();
|
|
1033
|
-
if (conversationList === null || alive.known())
|
|
1092
|
+
const { conversationList, agentList, conversationCursor } = await local.facts();
|
|
1093
|
+
if (conversationList === null || agentList === null || alive.known())
|
|
1034
1094
|
return;
|
|
1035
1095
|
alive.deps.stream()?.hold(conversationCursor);
|
|
1036
1096
|
conversationsLearned(alive);
|
|
1037
1097
|
}
|
|
1098
|
+
export function reconcileOpening(alive) {
|
|
1099
|
+
alive.held.set({ openingRead: true });
|
|
1100
|
+
return reconcileConversations(alive);
|
|
1101
|
+
}
|
|
1038
1102
|
export async function reconcileConversations(alive) {
|
|
1039
1103
|
if (!alive.known())
|
|
1040
1104
|
return;
|
|
1041
1105
|
const local = await alive.deps.local();
|
|
1042
|
-
const [held,
|
|
1106
|
+
const [held, stored, { conversationList, agentList }] = await Promise.all([
|
|
1043
1107
|
local.conversations(),
|
|
1044
|
-
local.
|
|
1108
|
+
local.storedConversations(),
|
|
1045
1109
|
local.facts(),
|
|
1046
1110
|
]);
|
|
1047
1111
|
const list = conversationList ?? [];
|
|
1112
|
+
const listing = { conversations: list, agents: agentList ?? [] };
|
|
1048
1113
|
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
1049
1114
|
const named = new Set(entries.keys());
|
|
1050
1115
|
const reads = new Map(held.map((one) => [one.conversation, one]));
|
|
1051
1116
|
const { replicated } = alive.held.now();
|
|
1052
|
-
const leaving = [
|
|
1053
|
-
...new Set([...replicated, ...reads.keys(), ...kept.map(({ conversation }) => conversation)]),
|
|
1054
|
-
].filter((conversation) => !named.has(conversation) &&
|
|
1117
|
+
const leaving = [...new Set([...replicated, ...stored])].filter((conversation) => !named.has(conversation) &&
|
|
1055
1118
|
!alive.isCreating(conversation) &&
|
|
1056
|
-
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation,
|
|
1119
|
+
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation, listing)));
|
|
1057
1120
|
for (const conversation of named) {
|
|
1058
1121
|
if (!replicated.has(conversation) &&
|
|
1059
1122
|
missed(alive, conversation, reads.get(conversation), entries.get(conversation))) {
|
|
@@ -1088,6 +1151,17 @@ export async function catchUpConversations(alive, progress) {
|
|
|
1088
1151
|
if (!alive.current())
|
|
1089
1152
|
progress.complete = false;
|
|
1090
1153
|
}
|
|
1154
|
+
export async function holdsSubmission(alive, operation) {
|
|
1155
|
+
if (alive.sending(operation))
|
|
1156
|
+
return true;
|
|
1157
|
+
const local = await alive.deps.local();
|
|
1158
|
+
for (const { conversation } of await local.chatDrafts()) {
|
|
1159
|
+
const held = (await local.chatDraft(conversation))?.submitted;
|
|
1160
|
+
if (held?.some((one) => one.operation === operation && one.turn === null) === true)
|
|
1161
|
+
return true;
|
|
1162
|
+
}
|
|
1163
|
+
return false;
|
|
1164
|
+
}
|
|
1091
1165
|
export async function resendConversations(alive, progress) {
|
|
1092
1166
|
const local = await alive.deps.local();
|
|
1093
1167
|
const tried = new Set();
|
|
@@ -1099,7 +1173,7 @@ export async function resendConversations(alive, progress) {
|
|
|
1099
1173
|
if (alive.deps.closed())
|
|
1100
1174
|
return;
|
|
1101
1175
|
tried.add(submission.operation);
|
|
1102
|
-
const result = await dispatched(alive, conversation, submission);
|
|
1176
|
+
const result = await dispatched(alive, conversation, submission, true);
|
|
1103
1177
|
if (result.kind === 'revoked-authorization')
|
|
1104
1178
|
return;
|
|
1105
1179
|
if (result.kind === 'transport-uncertainty') {
|
|
@@ -1119,23 +1193,25 @@ export function watchConversation(alive, conversation, options, deliver) {
|
|
|
1119
1193
|
const { view, watcher } = alive.viewJoined(key, conversation, asked, deliver);
|
|
1120
1194
|
const { held } = view;
|
|
1121
1195
|
const reading = new AbortController();
|
|
1122
|
-
void untilAnswered(() => alive.deps.durably(async (local) => {
|
|
1196
|
+
void untilAnswered(retrying(alive.deps.retries, 'reading', `window ${key}`, () => alive.deps.durably(async (local) => {
|
|
1123
1197
|
if (held.now().window !== null)
|
|
1124
1198
|
return;
|
|
1125
1199
|
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
1126
1200
|
held.set({ draft: (await local.chatDraft(conversation)) ?? null });
|
|
1127
1201
|
held.set({ ended: await endedIn(alive, conversation) });
|
|
1202
|
+
held.set({ dismissed: await dismissedIn(local, conversation) });
|
|
1203
|
+
held.set({ pins: (await local.facts()).chatPins });
|
|
1128
1204
|
held.set({ window: messages });
|
|
1129
|
-
held.set({ marked: await local.jobMarkers(conversation) });
|
|
1130
1205
|
held.set({ more });
|
|
1131
1206
|
held.set({ total: asked.total ? await local.messageCount(conversation) : null });
|
|
1132
|
-
}), reading.signal)
|
|
1207
|
+
})), reading.signal)
|
|
1133
1208
|
.then(() => {
|
|
1134
1209
|
if (alive.deps.closed() || !view.admit(watcher))
|
|
1135
1210
|
return;
|
|
1136
|
-
const
|
|
1137
|
-
const shown = window ?? [];
|
|
1138
|
-
|
|
1211
|
+
const now = held.now();
|
|
1212
|
+
const shown = now.window ?? [];
|
|
1213
|
+
const frame = sharedFrame(view, shown);
|
|
1214
|
+
watcher.notify(viewOf(alive, conversation, shown, frame, now));
|
|
1139
1215
|
})
|
|
1140
1216
|
.catch(() => { });
|
|
1141
1217
|
return () => {
|
|
@@ -1151,9 +1227,13 @@ export function watchConversationList(alive, deliver) {
|
|
|
1151
1227
|
export function watchConversationAgents(alive, deliver) {
|
|
1152
1228
|
alive.agentListeners.join(deliver);
|
|
1153
1229
|
conversationsLearned(alive);
|
|
1154
|
-
readAgents(alive);
|
|
1155
1230
|
return () => alive.agentListeners.leave(deliver);
|
|
1156
1231
|
}
|
|
1232
|
+
export function watchListedAgents(alive, deliver) {
|
|
1233
|
+
alive.listedListeners.join(deliver);
|
|
1234
|
+
conversationsLearned(alive);
|
|
1235
|
+
return () => alive.listedListeners.leave(deliver);
|
|
1236
|
+
}
|
|
1157
1237
|
export function conversationsChanged(alive, set) {
|
|
1158
1238
|
for (const conversation of set.conversations)
|
|
1159
1239
|
emit(alive, conversation);
|
|
@@ -1165,26 +1245,32 @@ export function receiveConversationEvent(alive, event) {
|
|
|
1165
1245
|
if (event.whole)
|
|
1166
1246
|
alive.relistBegun();
|
|
1167
1247
|
if (alive.relisting())
|
|
1168
|
-
alive.relistHeard(event.entries);
|
|
1248
|
+
alive.relistHeard(event.entries, event.agents);
|
|
1169
1249
|
if (event.more && alive.relisting())
|
|
1170
1250
|
return;
|
|
1171
1251
|
const whole = alive.relistTaken();
|
|
1172
1252
|
listChanged(alive, {
|
|
1173
1253
|
replacing: whole !== null,
|
|
1174
|
-
set: whole === null ? event.entries : [...whole.values()],
|
|
1254
|
+
set: whole === null ? event.entries : [...whole.conversations.values()],
|
|
1255
|
+
agents: whole === null ? event.agents : [...whole.agents.values()],
|
|
1175
1256
|
gone: null,
|
|
1176
1257
|
...(event.more ? { paged: true } : { cursor: event.cursor }),
|
|
1177
1258
|
});
|
|
1178
1259
|
return;
|
|
1179
1260
|
}
|
|
1180
1261
|
if (event.kind === 'listed') {
|
|
1181
|
-
alive.relistHeard([event.entry]);
|
|
1182
|
-
listChanged(alive, { replacing: false, set: [event.entry], gone: null });
|
|
1262
|
+
alive.relistHeard([event.entry], []);
|
|
1263
|
+
listChanged(alive, { replacing: false, set: [event.entry], agents: [], gone: null });
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
if (event.kind === 'agent') {
|
|
1267
|
+
alive.relistHeard([], [event.agent]);
|
|
1268
|
+
listChanged(alive, { replacing: false, set: [], agents: [event.agent], gone: null });
|
|
1183
1269
|
return;
|
|
1184
1270
|
}
|
|
1185
1271
|
if (event.kind === 'unlisted') {
|
|
1186
1272
|
alive.relistDropped(event.conversation);
|
|
1187
|
-
listChanged(alive, { replacing: false, set: [], gone: event.conversation });
|
|
1273
|
+
listChanged(alive, { replacing: false, set: [], agents: [], gone: event.conversation });
|
|
1188
1274
|
return;
|
|
1189
1275
|
}
|
|
1190
1276
|
heard(alive, event);
|