@agentshouse/mdruntime 0.1.0-cbbae1fff01c6 → 0.1.0-cc00e9289ddf4
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 +17 -15
- package/dist/acceptance.d.ts.map +1 -1
- package/dist/acceptance.js +14 -23
- 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 +114 -63
- package/dist/adapter.d.ts +30 -12
- 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/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 +8 -18
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +27 -15
- package/dist/compile.d.ts +2 -0
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +17 -4
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +15 -13
- package/dist/conversation-live.d.ts +23 -8
- package/dist/conversation-live.d.ts.map +1 -1
- package/dist/conversation-live.js +21 -9
- package/dist/conversation-row.d.ts +2 -0
- package/dist/conversation-row.d.ts.map +1 -1
- package/dist/conversation-row.js +2 -0
- package/dist/conversation.d.ts +27 -5
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +279 -168
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +8 -6
- 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 +25 -14
- package/dist/expectation.d.ts.map +1 -1
- package/dist/expectation.js +51 -20
- package/dist/failure.d.ts +2 -0
- package/dist/failure.d.ts.map +1 -1
- package/dist/failure.js +3 -0
- package/dist/figures.d.ts.map +1 -1
- package/dist/figures.js +4 -2
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +2 -1
- package/dist/host.d.ts +1 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +39 -11
- package/dist/index.d.ts +11 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -6
- package/dist/install.d.ts +10 -4
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +45 -46
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +22 -16
- package/dist/listing.d.ts +7 -3
- package/dist/listing.d.ts.map +1 -1
- package/dist/listing.js +26 -13
- package/dist/live.d.ts +5 -3
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +71 -30
- package/dist/locks.d.ts.map +1 -1
- package/dist/locks.js +2 -3
- package/dist/lost.d.ts.map +1 -1
- package/dist/lost.js +2 -3
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +7 -10
- package/dist/memory.d.ts +3 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +50 -22
- package/dist/messages.d.ts +12 -3
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +24 -10
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +5 -8
- package/dist/observation.d.ts +27 -12
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +173 -69
- package/dist/opening.d.ts.map +1 -1
- package/dist/opening.js +3 -9
- package/dist/outcome.d.ts +7 -0
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +23 -2
- package/dist/overlay.d.ts +3 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +8 -4
- 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 +2 -9
- package/dist/parts.d.ts.map +1 -1
- package/dist/parts.js +6 -14
- package/dist/preparation.d.ts +27 -6
- package/dist/preparation.d.ts.map +1 -1
- package/dist/preparation.js +137 -56
- package/dist/presence.d.ts +7 -1
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js +22 -9
- package/dist/queries.d.ts +2 -2
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +62 -24
- package/dist/questions.d.ts +0 -5
- package/dist/questions.d.ts.map +1 -1
- package/dist/questions.js +0 -7
- package/dist/queue.d.ts +2 -2
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +25 -30
- package/dist/reach.d.ts +2 -3
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +75 -21
- package/dist/react.d.ts +7 -5
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +28 -5
- 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 +3 -1
- package/dist/reads.d.ts.map +1 -1
- package/dist/reads.js +5 -1
- package/dist/recovery.d.ts +3 -1
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +29 -7
- package/dist/refusal.d.ts.map +1 -1
- package/dist/refusal.js +1 -3
- 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 +2 -2
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +26 -21
- package/dist/rows.d.ts +2 -0
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +3 -0
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/save.d.ts +1 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +105 -55
- package/dist/saves.d.ts.map +1 -1
- package/dist/saves.js +3 -6
- package/dist/seed.d.ts.map +1 -1
- package/dist/seed.js +2 -2
- package/dist/shown.d.ts +3 -2
- package/dist/shown.d.ts.map +1 -1
- package/dist/shown.js +58 -39
- 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.d.ts +3 -3
- package/dist/socket.d.ts.map +1 -1
- package/dist/socket.js +3 -9
- package/dist/source.d.ts +0 -7
- package/dist/source.d.ts.map +1 -1
- 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 +11 -4
- package/dist/store/records.d.ts.map +1 -1
- package/dist/store/records.js +56 -20
- 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.d.ts +9 -6
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +11 -2
- package/dist/stored.d.ts +24 -13
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +73 -17
- package/dist/surface.d.ts +4 -3
- package/dist/surface.d.ts.map +1 -1
- package/dist/surface.js +12 -13
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +31 -17
- package/dist/tables.d.ts +14 -7
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +36 -15
- package/dist/tallies.d.ts.map +1 -1
- package/dist/tallies.js +1 -2
- package/dist/wire.d.ts +40 -3
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +11 -1
- package/package.json +3 -3
- 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 -5
- package/dist/job.d.ts.map +0 -1
- package/dist/job.js +0 -7
- package/dist/log.d.ts +0 -6
- package/dist/log.d.ts.map +0 -1
- package/dist/log.js +0 -14
package/dist/conversation.js
CHANGED
|
@@ -11,6 +11,7 @@ import { runningLine } from './parts.js';
|
|
|
11
11
|
import { record, text } from './read.js';
|
|
12
12
|
import { openQuestion, questionAsked } from './questions.js';
|
|
13
13
|
import { untilAnswered } from './recovery.js';
|
|
14
|
+
import { retrying } from './retried.js';
|
|
14
15
|
import { capped, FROM_START, messageOrder, precedes } from './windows.js';
|
|
15
16
|
export function unheldView(conversation) {
|
|
16
17
|
return {
|
|
@@ -25,12 +26,17 @@ export function unheldView(conversation) {
|
|
|
25
26
|
starting: null,
|
|
26
27
|
state: null,
|
|
27
28
|
link: null,
|
|
29
|
+
deliveryWaiting: [],
|
|
28
30
|
deliveryUnknown: [],
|
|
29
31
|
chatDraft: null,
|
|
32
|
+
dismissedSuggestion: null,
|
|
33
|
+
pins: [],
|
|
30
34
|
};
|
|
31
35
|
}
|
|
32
36
|
export const SESSION_STARTED = 'Session started';
|
|
33
37
|
const NEW_CHAT = 'new:';
|
|
38
|
+
const LISTING = 'listing';
|
|
39
|
+
export const CATCHING_UP = 'catching-up';
|
|
34
40
|
export const HISTORY_CONVERSATIONS = 64;
|
|
35
41
|
export function newChat(agent) {
|
|
36
42
|
return `${NEW_CHAT}${agent}`;
|
|
@@ -74,7 +80,7 @@ function frameOf(asked, messages, more, total) {
|
|
|
74
80
|
};
|
|
75
81
|
}
|
|
76
82
|
function newestOf(arriving, from) {
|
|
77
|
-
return arriving.reduce((top, message) => (top === null || message.
|
|
83
|
+
return arriving.reduce((top, message) => (top === null || message.change > top ? message.change : top), from);
|
|
78
84
|
}
|
|
79
85
|
function acceptedMessage(value) {
|
|
80
86
|
if (typeof value !== 'object' || value === null)
|
|
@@ -83,6 +89,7 @@ function acceptedMessage(value) {
|
|
|
83
89
|
if (typeof record.identity !== 'string' ||
|
|
84
90
|
typeof record.turn !== 'string' ||
|
|
85
91
|
typeof record.position !== 'string' ||
|
|
92
|
+
typeof record.change !== 'string' ||
|
|
86
93
|
typeof record.text !== 'string') {
|
|
87
94
|
return null;
|
|
88
95
|
}
|
|
@@ -90,6 +97,7 @@ function acceptedMessage(value) {
|
|
|
90
97
|
identity: record.identity,
|
|
91
98
|
turn: record.turn,
|
|
92
99
|
position: record.position,
|
|
100
|
+
change: record.change,
|
|
93
101
|
text: record.text,
|
|
94
102
|
message: structuredClone(record.message),
|
|
95
103
|
};
|
|
@@ -191,17 +199,17 @@ function withSubmitted(draft, submitted) {
|
|
|
191
199
|
const { submitted: _held, ...unsent } = draft;
|
|
192
200
|
return submitted.length === 0 ? unsent : { ...unsent, submitted };
|
|
193
201
|
}
|
|
194
|
-
function
|
|
195
|
-
return
|
|
202
|
+
export function joinedDraft(first, second) {
|
|
203
|
+
return [first, second].filter((one) => one !== '').join('\n');
|
|
196
204
|
}
|
|
197
205
|
function returned(draft, submission, others) {
|
|
198
206
|
return withSubmitted({
|
|
199
207
|
conversation: draft.conversation,
|
|
200
|
-
|
|
208
|
+
text: joinedDraft(submission.text, draft.text),
|
|
201
209
|
revision: chatDraftRevision(),
|
|
202
210
|
}, others);
|
|
203
211
|
}
|
|
204
|
-
function viewOf(alive, conversation, held, frame, draft, ended) {
|
|
212
|
+
function viewOf(alive, conversation, held, frame, { draft, ended, dismissed, pins }) {
|
|
205
213
|
const facts = alive.liveOf(conversation);
|
|
206
214
|
return {
|
|
207
215
|
conversation,
|
|
@@ -221,8 +229,11 @@ function viewOf(alive, conversation, held, frame, draft, ended) {
|
|
|
221
229
|
starting: facts.starting,
|
|
222
230
|
state: sessionOf(facts, held, ended),
|
|
223
231
|
link: facts.link === null ? null : { ...facts.link },
|
|
232
|
+
deliveryWaiting: [...facts.deliveryWaiting],
|
|
224
233
|
deliveryUnknown: [...facts.deliveryUnknown],
|
|
225
234
|
chatDraft: draft === null || unwritten(draft) ? null : { text: draft.text, revision: draft.revision },
|
|
235
|
+
dismissedSuggestion: dismissed,
|
|
236
|
+
pins: [...pins],
|
|
226
237
|
};
|
|
227
238
|
}
|
|
228
239
|
function sessionOf(facts, held, ended) {
|
|
@@ -242,13 +253,15 @@ function emit(alive, conversation) {
|
|
|
242
253
|
if (alive.deps.closed())
|
|
243
254
|
return;
|
|
244
255
|
for (const view of alive.views()) {
|
|
245
|
-
const
|
|
256
|
+
const held = view.held.now();
|
|
257
|
+
const { window } = held;
|
|
246
258
|
if (view.conversation !== conversation || window === null)
|
|
247
259
|
continue;
|
|
248
260
|
const ready = view.ready();
|
|
249
261
|
if (ready.length === 0)
|
|
250
262
|
continue;
|
|
251
|
-
const
|
|
263
|
+
const frame = sharedFrame(view, window);
|
|
264
|
+
const value = viewOf(alive, conversation, window, frame, held);
|
|
252
265
|
for (const watcher of ready)
|
|
253
266
|
watcher.notify(value);
|
|
254
267
|
}
|
|
@@ -294,66 +307,90 @@ function rowOf(alive, conversation) {
|
|
|
294
307
|
};
|
|
295
308
|
}
|
|
296
309
|
async function entries(alive) {
|
|
297
|
-
const
|
|
298
|
-
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)))
|
|
299
316
|
return null;
|
|
300
317
|
const held = list.length === 0
|
|
301
318
|
? []
|
|
302
319
|
: await alive.deps.durably((local) => local.conversationRows(list.map(({ conversation }) => conversation)));
|
|
303
320
|
const rows = new Map(held.map((one) => [one.conversation, one]));
|
|
304
|
-
return list.map((entry) =>
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
+
});
|
|
315
336
|
}
|
|
316
|
-
async function
|
|
317
|
-
const
|
|
318
|
-
if (
|
|
319
|
-
return
|
|
320
|
-
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: [] };
|
|
321
344
|
}
|
|
322
345
|
async function endedIn(alive, conversation) {
|
|
323
|
-
const
|
|
324
|
-
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;
|
|
325
355
|
}
|
|
326
356
|
function listChanged(alive, change) {
|
|
327
357
|
void alive.deps
|
|
328
358
|
.durably(async (local) => {
|
|
329
|
-
const { conversationList, conversationCursor } = await local.facts();
|
|
330
|
-
const
|
|
331
|
-
const
|
|
332
|
-
for (const entry of change.set) {
|
|
333
|
-
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)
|
|
334
362
|
alive.created(entry.conversation);
|
|
335
|
-
}
|
|
336
363
|
if (change.gone !== null)
|
|
337
364
|
held.delete(change.gone);
|
|
338
365
|
const list = [...held.values()];
|
|
366
|
+
const agents = [
|
|
367
|
+
...upserted(change.replacing ? [] : (agentList ?? []), change.agents, (agent) => agent.id).values(),
|
|
368
|
+
];
|
|
339
369
|
if (JSON.stringify(list) !== JSON.stringify(conversationList)) {
|
|
340
370
|
await local.fact('conversationList', list);
|
|
341
371
|
}
|
|
372
|
+
if (JSON.stringify(agents) !== JSON.stringify(agentList)) {
|
|
373
|
+
await local.fact('agentList', agents);
|
|
374
|
+
}
|
|
342
375
|
if (change.cursor !== undefined) {
|
|
343
376
|
if (change.cursor !== conversationCursor) {
|
|
344
377
|
await local.fact('conversationCursor', change.cursor);
|
|
345
378
|
}
|
|
346
379
|
alive.deps.stream()?.hold(change.cursor);
|
|
347
380
|
}
|
|
348
|
-
return list;
|
|
381
|
+
return { conversations: list, agents };
|
|
349
382
|
})
|
|
350
|
-
.catch(async () =>
|
|
351
|
-
.
|
|
383
|
+
.catch(async () => {
|
|
384
|
+
const { conversationList, agentList } = await (await alive.deps.local()).facts();
|
|
385
|
+
return { conversations: conversationList ?? [], agents: agentList ?? [] };
|
|
386
|
+
})
|
|
387
|
+
.then((listing) => {
|
|
352
388
|
if (alive.deps.closed() || change.paged === true)
|
|
353
389
|
return;
|
|
390
|
+
const list = listing.conversations;
|
|
354
391
|
endedAnew(alive, list);
|
|
355
392
|
if (change.cursor !== undefined) {
|
|
356
|
-
alive.held.set({ listKnown: true });
|
|
393
|
+
alive.held.set({ listKnown: true, openingListed: true });
|
|
357
394
|
settleBehind(alive, list);
|
|
358
395
|
openingEnded(alive);
|
|
359
396
|
alive.deps.settled();
|
|
@@ -361,11 +398,12 @@ function listChanged(alive, change) {
|
|
|
361
398
|
emitList(alive);
|
|
362
399
|
if (!alive.known())
|
|
363
400
|
return;
|
|
364
|
-
retiredDrafts(alive,
|
|
365
|
-
const { replicated } = alive.held.now();
|
|
366
|
-
if (change.cursor === undefined
|
|
367
|
-
|
|
368
|
-
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) {
|
|
369
407
|
alive.deps.again();
|
|
370
408
|
}
|
|
371
409
|
}, uncaught);
|
|
@@ -381,23 +419,23 @@ function endedAnew(alive, list) {
|
|
|
381
419
|
emit(alive, view.conversation);
|
|
382
420
|
}
|
|
383
421
|
}
|
|
384
|
-
function
|
|
385
|
-
const reading =
|
|
422
|
+
function shownListing(alive, work) {
|
|
423
|
+
const reading = heldListing(alive);
|
|
386
424
|
alive.inOrder(async () => {
|
|
387
|
-
const
|
|
425
|
+
const listing = await reading.catch((error) => {
|
|
388
426
|
uncaught(error);
|
|
389
427
|
return null;
|
|
390
428
|
});
|
|
391
|
-
if (
|
|
429
|
+
if (listing === null || alive.deps.closed())
|
|
392
430
|
return;
|
|
393
|
-
work(
|
|
431
|
+
work(listing);
|
|
394
432
|
});
|
|
395
433
|
}
|
|
396
434
|
async function told(alive) {
|
|
397
435
|
try {
|
|
398
436
|
while (alive.held.now().listOwed && !alive.deps.closed()) {
|
|
399
437
|
alive.held.set({ listOwed: false });
|
|
400
|
-
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);
|
|
401
439
|
if (alive.deps.closed())
|
|
402
440
|
return;
|
|
403
441
|
if (value === null)
|
|
@@ -435,57 +473,46 @@ export function conversationsLearned(alive) {
|
|
|
435
473
|
return;
|
|
436
474
|
if (alive.listeners.waiting())
|
|
437
475
|
tellList(alive);
|
|
438
|
-
if (!alive.agentListeners.waiting())
|
|
476
|
+
if (!alive.agentListeners.waiting() && !alive.listedListeners.waiting())
|
|
439
477
|
return;
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
+
environment: {
|
|
491
|
+
identity: agent.environment,
|
|
492
|
+
name: agent.environment_name,
|
|
493
|
+
state: agent.environment_connected ? 'online' : 'offline',
|
|
494
|
+
},
|
|
495
|
+
}))
|
|
452
496
|
.sort((left, right) => left.name === right.name
|
|
453
497
|
? left.identity.localeCompare(right.identity)
|
|
454
498
|
: left.name.localeCompare(right.name));
|
|
455
499
|
}
|
|
456
|
-
function readAgents(alive) {
|
|
457
|
-
const stream = alive.deps.stream();
|
|
458
|
-
if (stream?.agents === undefined || !alive.deps.online() || alive.held.now().agentsReading)
|
|
459
|
-
return;
|
|
460
|
-
const { agents: read } = stream;
|
|
461
|
-
const { agentListeners } = alive;
|
|
462
|
-
alive.held.set({ agentsReading: true });
|
|
463
|
-
void alive.deps.recovery
|
|
464
|
-
.attempt('agents', async () => {
|
|
465
|
-
if (!alive.deps.online() || (!agentListeners.waiting() && !agentListeners.told())) {
|
|
466
|
-
return 'done';
|
|
467
|
-
}
|
|
468
|
-
const listed = await read();
|
|
469
|
-
if (listed === null)
|
|
470
|
-
return 'done';
|
|
471
|
-
alive.held.set({ listedAgents: listed });
|
|
472
|
-
emitAgents(alive);
|
|
473
|
-
return 'done';
|
|
474
|
-
})
|
|
475
|
-
.finally(() => {
|
|
476
|
-
alive.held.set({ agentsReading: false });
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
500
|
function emitAgents(alive) {
|
|
480
|
-
|
|
501
|
+
const { agentListeners, listedListeners } = alive;
|
|
502
|
+
if (alive.deps.closed() || (!agentListeners.told() && !listedListeners.told()))
|
|
481
503
|
return;
|
|
482
|
-
|
|
483
|
-
const value =
|
|
504
|
+
shownListing(alive, (listing) => {
|
|
505
|
+
const value = agentsOf(listing);
|
|
484
506
|
const shown = JSON.stringify(value);
|
|
485
|
-
if (shown
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
507
|
+
if (shown !== alive.held.now().agentsShown) {
|
|
508
|
+
alive.held.set({ agentsShown: shown });
|
|
509
|
+
agentListeners.tell(value);
|
|
510
|
+
}
|
|
511
|
+
const listed = JSON.stringify(listing.agents);
|
|
512
|
+
if (listed !== alive.held.now().listedShown) {
|
|
513
|
+
alive.held.set({ listedShown: listed });
|
|
514
|
+
listedListeners.tell(structuredClone(listing.agents));
|
|
515
|
+
}
|
|
489
516
|
});
|
|
490
517
|
}
|
|
491
518
|
function setLive(alive, conversation, next) {
|
|
@@ -499,11 +526,11 @@ function setLive(alive, conversation, next) {
|
|
|
499
526
|
after.asked !== before.asked)
|
|
500
527
|
tellSoon(alive);
|
|
501
528
|
}
|
|
502
|
-
function retiredChat(conversation,
|
|
529
|
+
function retiredChat(conversation, listing) {
|
|
503
530
|
if (!conversation.startsWith(NEW_CHAT))
|
|
504
531
|
return false;
|
|
505
532
|
const agent = conversation.slice(NEW_CHAT.length);
|
|
506
|
-
return
|
|
533
|
+
return listing.agents.some((one) => one.id === agent && one.retired_at !== null);
|
|
507
534
|
}
|
|
508
535
|
function live(alive, conversation, change) {
|
|
509
536
|
alive.factsHeard(conversation, FACTS.filter((one) => one in change));
|
|
@@ -524,6 +551,7 @@ function openingEnded(alive) {
|
|
|
524
551
|
starting: facts.has('starting') ? QUIET.starting : held.starting,
|
|
525
552
|
state: facts.has('state') ? QUIET.state : held.state,
|
|
526
553
|
link: facts.has('link') ? QUIET.link : held.link,
|
|
554
|
+
deliveryWaiting: facts.has('deliveryWaiting') ? QUIET.deliveryWaiting : held.deliveryWaiting,
|
|
527
555
|
deliveryUnknown: facts.has('deliveryUnknown') ? QUIET.deliveryUnknown : held.deliveryUnknown,
|
|
528
556
|
});
|
|
529
557
|
emit(alive, conversation);
|
|
@@ -555,19 +583,13 @@ function handReplicated(alive) {
|
|
|
555
583
|
}
|
|
556
584
|
async function remove(alive, leaving) {
|
|
557
585
|
await alive.deps.durably(async (local) => {
|
|
558
|
-
const kept = new Set(
|
|
559
|
-
...(await local.conversations(leaving)).map(({ conversation }) => conversation),
|
|
560
|
-
...(await local.chatDrafts())
|
|
561
|
-
.filter(({ conversation }) => leaving.includes(conversation))
|
|
562
|
-
.map(({ conversation }) => conversation),
|
|
563
|
-
]);
|
|
564
|
-
await local.dropConversations(leaving);
|
|
586
|
+
const kept = new Set(await local.dropConversations(leaving));
|
|
565
587
|
const changed = [];
|
|
566
588
|
for (const conversation of leaving) {
|
|
567
589
|
if (kept.has(conversation) || alive.liveHeld(conversation) !== undefined) {
|
|
568
590
|
changed.push(conversation);
|
|
569
591
|
}
|
|
570
|
-
|
|
592
|
+
heldInViews(alive, conversation, { draft: null, dismissed: null });
|
|
571
593
|
alive.forget(conversation);
|
|
572
594
|
setLive(alive, conversation, null);
|
|
573
595
|
await slide(alive, local, conversation, null);
|
|
@@ -596,7 +618,7 @@ async function readsOf(local, conversations) {
|
|
|
596
618
|
return new Map((await local.conversations(conversations)).map((held) => [held.conversation, held]));
|
|
597
619
|
}
|
|
598
620
|
function retiredDrafts(alive, list) {
|
|
599
|
-
if (!list.some((
|
|
621
|
+
if (!list.agents.some((agent) => agent.retired_at !== null))
|
|
600
622
|
return;
|
|
601
623
|
void alive.deps
|
|
602
624
|
.local()
|
|
@@ -639,14 +661,12 @@ function keep(alive, conversation, message) {
|
|
|
639
661
|
if (!alive.held.now().replicated.has(conversation))
|
|
640
662
|
return;
|
|
641
663
|
const read = (await readsOf(local, [conversation])).get(conversation)?.read;
|
|
642
|
-
const advances = read !== undefined &&
|
|
643
|
-
!alive.behind(conversation) &&
|
|
644
|
-
(read === null || message.position > read);
|
|
664
|
+
const advances = read !== undefined && !alive.behind(conversation) && (read === null || message.change > read);
|
|
645
665
|
await sealed(alive, local, conversation, new Set([message.turn]));
|
|
646
666
|
await local.keepMessages({
|
|
647
667
|
conversation,
|
|
648
668
|
messages: [message],
|
|
649
|
-
...(advances ? { read: { at: message.
|
|
669
|
+
...(advances ? { read: { at: message.change, partial: false } } : {}),
|
|
650
670
|
});
|
|
651
671
|
sealTurns(alive, conversation, new Set([message.turn]));
|
|
652
672
|
await slide(alive, local, conversation, [message]);
|
|
@@ -767,13 +787,16 @@ function heard(alive, event) {
|
|
|
767
787
|
return;
|
|
768
788
|
}
|
|
769
789
|
if (event.kind === 'deliveries') {
|
|
770
|
-
live(alive, conversation, {
|
|
790
|
+
live(alive, conversation, {
|
|
791
|
+
deliveryWaiting: [...event.waiting],
|
|
792
|
+
deliveryUnknown: [...event.unknown],
|
|
793
|
+
});
|
|
771
794
|
return;
|
|
772
795
|
}
|
|
773
796
|
const arriving = acceptedMessage(event.message);
|
|
774
797
|
if (arriving === null)
|
|
775
798
|
return;
|
|
776
|
-
alive.heardAt(conversation, arriving.
|
|
799
|
+
alive.heardAt(conversation, arriving.change);
|
|
777
800
|
if (alive.held.now().replicated.has(conversation)) {
|
|
778
801
|
if (alive.deps.full()) {
|
|
779
802
|
alive.gapOpened(conversation);
|
|
@@ -791,19 +814,27 @@ function heard(alive, event) {
|
|
|
791
814
|
emit(alive, conversation);
|
|
792
815
|
}
|
|
793
816
|
async function kept(alive, local, conversation, following) {
|
|
794
|
-
const
|
|
795
|
-
if (
|
|
817
|
+
const draft = following === null || empty(following) ? null : following;
|
|
818
|
+
if (draft === null)
|
|
796
819
|
await local.dropChatDraft(conversation);
|
|
797
820
|
else
|
|
798
|
-
await local.keepChatDrafts([
|
|
799
|
-
|
|
821
|
+
await local.keepChatDrafts([draft]);
|
|
822
|
+
heldInViews(alive, conversation, { draft });
|
|
800
823
|
}
|
|
801
|
-
function
|
|
824
|
+
function heldInViews(alive, conversation, held) {
|
|
802
825
|
for (const view of alive.views()) {
|
|
803
826
|
if (view.conversation === conversation)
|
|
804
|
-
view.held.set(
|
|
827
|
+
view.held.set(held);
|
|
805
828
|
}
|
|
806
829
|
}
|
|
830
|
+
async function factOf(local, name) {
|
|
831
|
+
return Object.fromEntries((await local.conversationFacts())
|
|
832
|
+
.filter((fact) => fact.name === name)
|
|
833
|
+
.map(({ conversation, value }) => [conversation, value]));
|
|
834
|
+
}
|
|
835
|
+
async function dismissedIn(local, conversation) {
|
|
836
|
+
return (await factOf(local, 'dismissedSuggestion'))[conversation] ?? null;
|
|
837
|
+
}
|
|
807
838
|
async function draftAt(local, conversation) {
|
|
808
839
|
return (await local.chatDraft(conversation)) ?? undefined;
|
|
809
840
|
}
|
|
@@ -834,9 +865,9 @@ function moved(alive, agent, operation, to) {
|
|
|
834
865
|
: [{ ...unsent, conversation: to }];
|
|
835
866
|
const left = { ...(taken.length === 0 ? unsent : blank), moves: [...earlier, operation] };
|
|
836
867
|
await local.keepChatDrafts([left, ...taken]);
|
|
837
|
-
|
|
868
|
+
heldInViews(alive, from, { draft: left });
|
|
838
869
|
for (const one of taken)
|
|
839
|
-
|
|
870
|
+
heldInViews(alive, to, { draft: one });
|
|
840
871
|
alive.deps.publish(conversationChangeSet([from, to]));
|
|
841
872
|
});
|
|
842
873
|
}
|
|
@@ -867,13 +898,10 @@ async function submitted(alive, conversation, operation, draft) {
|
|
|
867
898
|
});
|
|
868
899
|
return submission;
|
|
869
900
|
}
|
|
870
|
-
async function dispatched(alive, conversation, submission) {
|
|
901
|
+
async function dispatched(alive, conversation, submission, resent = false) {
|
|
871
902
|
const dispatch = alive.sendingBegan(submission.operation);
|
|
872
903
|
try {
|
|
873
|
-
const result = await invoke(alive, 'conversations/send', conversation, {
|
|
874
|
-
operation_id: submission.operation,
|
|
875
|
-
text: submission.text,
|
|
876
|
-
});
|
|
904
|
+
const result = await invoke(alive, 'conversations/send', conversation, submission.operation, { text: submission.text }, { step: 'sending', instance: `message ${submission.operation}` });
|
|
877
905
|
dispatch.set({ answered: result.kind !== 'transport-uncertainty' });
|
|
878
906
|
if (result.kind === 'revoked-authorization')
|
|
879
907
|
return result;
|
|
@@ -881,6 +909,7 @@ async function dispatched(alive, conversation, submission) {
|
|
|
881
909
|
alive.deps.unanswered();
|
|
882
910
|
return result;
|
|
883
911
|
}
|
|
912
|
+
alive.deps.heard(submission.operation, resent);
|
|
884
913
|
const turn = answered(result, 'message_id');
|
|
885
914
|
await withDraft(alive, conversation, async (current, local) => {
|
|
886
915
|
const held = current?.submitted?.find((one) => one.operation === submission.operation);
|
|
@@ -900,8 +929,8 @@ async function dispatched(alive, conversation, submission) {
|
|
|
900
929
|
alive.sendingEnded(submission.operation, dispatch);
|
|
901
930
|
}
|
|
902
931
|
}
|
|
903
|
-
function invoke(alive, name, conversation, extra = {
|
|
904
|
-
return alive.deps.call(name, { conversation_id: conversation, ...extra });
|
|
932
|
+
function invoke(alive, name, conversation, operation, extra = {}, attempt) {
|
|
933
|
+
return alive.deps.call(name, { conversation_id: conversation, operation_id: operation, ...extra }, attempt);
|
|
905
934
|
}
|
|
906
935
|
export function conversationSurface(alive) {
|
|
907
936
|
return {
|
|
@@ -922,7 +951,12 @@ export function conversationSurface(alive) {
|
|
|
922
951
|
return alive.deps.durably(async (local) => {
|
|
923
952
|
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before, phrase);
|
|
924
953
|
const total = asked.total ? await local.messageCount(conversation, phrase) : null;
|
|
925
|
-
return structuredClone(viewOf(alive, conversation, messages, frameOf(asked, messages, more, total),
|
|
954
|
+
return structuredClone(viewOf(alive, conversation, messages, frameOf(asked, messages, more, total), {
|
|
955
|
+
draft: (await local.chatDraft(conversation)) ?? null,
|
|
956
|
+
ended: await endedIn(alive, conversation),
|
|
957
|
+
dismissed: await dismissedIn(local, conversation),
|
|
958
|
+
pins: (await local.facts()).chatPins,
|
|
959
|
+
}));
|
|
926
960
|
});
|
|
927
961
|
},
|
|
928
962
|
async create(input) {
|
|
@@ -930,7 +964,7 @@ export function conversationSurface(alive) {
|
|
|
930
964
|
const conversation = answered(result, 'conversation_id');
|
|
931
965
|
if (conversation === null)
|
|
932
966
|
return result;
|
|
933
|
-
const listed = (await
|
|
967
|
+
const listed = (await heldListing(alive))?.conversations ?? [];
|
|
934
968
|
if (!listed.some((entry) => entry.conversation === conversation)) {
|
|
935
969
|
alive.creating(conversation);
|
|
936
970
|
}
|
|
@@ -959,40 +993,90 @@ export function conversationSurface(alive) {
|
|
|
959
993
|
}
|
|
960
994
|
return OFFLINE;
|
|
961
995
|
},
|
|
962
|
-
answer(conversation, answer) {
|
|
963
|
-
return invoke(alive, 'conversations/interaction/answer', conversation,
|
|
964
|
-
|
|
965
|
-
|
|
996
|
+
answer(conversation, answer, operation) {
|
|
997
|
+
return invoke(alive, 'conversations/interaction/answer', conversation, operation, answer);
|
|
998
|
+
},
|
|
999
|
+
interrupt(conversation, operation) {
|
|
1000
|
+
return invoke(alive, 'conversations/interrupt', conversation, operation);
|
|
1001
|
+
},
|
|
1002
|
+
kill(conversation, operation) {
|
|
1003
|
+
return invoke(alive, 'conversations/kill', conversation, operation);
|
|
1004
|
+
},
|
|
1005
|
+
delete(conversation, operation) {
|
|
1006
|
+
return invoke(alive, 'conversations/delete', conversation, operation);
|
|
1007
|
+
},
|
|
1008
|
+
takeOut(conversation, message, operation) {
|
|
1009
|
+
return invoke(alive, 'conversations/take-out', conversation, operation, {
|
|
1010
|
+
message_id: message,
|
|
1011
|
+
});
|
|
1012
|
+
},
|
|
1013
|
+
decide({ request, room, message }, decision, operation) {
|
|
1014
|
+
return alive.deps.call('agent-functions/decide', {
|
|
1015
|
+
room_ref: room,
|
|
1016
|
+
request,
|
|
1017
|
+
...(message === undefined ? {} : { message }),
|
|
1018
|
+
decision,
|
|
1019
|
+
operation_id: operation,
|
|
1020
|
+
});
|
|
1021
|
+
},
|
|
1022
|
+
rename(conversation, name, operation) {
|
|
1023
|
+
return invoke(alive, 'conversations/rename', conversation, operation, { name });
|
|
1024
|
+
},
|
|
1025
|
+
option(conversation, option, value, operation) {
|
|
1026
|
+
return invoke(alive, 'conversations/option/set', conversation, operation, { option, value });
|
|
1027
|
+
},
|
|
1028
|
+
retry(conversation, message, operation) {
|
|
1029
|
+
return invoke(alive, 'conversations/retry', conversation, operation, {
|
|
1030
|
+
message_id: message,
|
|
966
1031
|
});
|
|
967
1032
|
},
|
|
968
|
-
|
|
969
|
-
|
|
1033
|
+
async pin(figures) {
|
|
1034
|
+
const pins = [...figures];
|
|
1035
|
+
await alive.deps.durably((local) => local.fact('chatPins', pins));
|
|
1036
|
+
const views = [...alive.views()];
|
|
1037
|
+
for (const view of views)
|
|
1038
|
+
view.held.set({ pins });
|
|
1039
|
+
for (const conversation of new Set(views.map((view) => view.conversation))) {
|
|
1040
|
+
emit(alive, conversation);
|
|
1041
|
+
}
|
|
970
1042
|
},
|
|
971
|
-
|
|
972
|
-
|
|
1043
|
+
async openTurn(conversation, turn) {
|
|
1044
|
+
await alive.deps.durably((local) => local.keepConversationFact({ conversation, name: 'openedTurn', value: turn }));
|
|
1045
|
+
tellList(alive);
|
|
973
1046
|
},
|
|
974
|
-
|
|
975
|
-
return
|
|
1047
|
+
dismissSuggestion(conversation, suggestion) {
|
|
1048
|
+
return alive.deps.durably(async (local) => {
|
|
1049
|
+
if ((await dismissedIn(local, conversation)) === suggestion)
|
|
1050
|
+
return;
|
|
1051
|
+
await local.keepConversationFact({
|
|
1052
|
+
conversation,
|
|
1053
|
+
name: 'dismissedSuggestion',
|
|
1054
|
+
value: suggestion,
|
|
1055
|
+
});
|
|
1056
|
+
heldInViews(alive, conversation, { dismissed: suggestion });
|
|
1057
|
+
alive.deps.publish(conversationChangeSet([conversation]));
|
|
1058
|
+
});
|
|
976
1059
|
},
|
|
977
1060
|
};
|
|
978
1061
|
}
|
|
1062
|
+
function rewritten(alive, conversation, text, revision = chatDraftRevision()) {
|
|
1063
|
+
return withDraft(alive, conversation, (current) => ({
|
|
1064
|
+
conversation,
|
|
1065
|
+
text: text(current?.text ?? ''),
|
|
1066
|
+
revision,
|
|
1067
|
+
...(current === undefined ? {} : pending(current)),
|
|
1068
|
+
}));
|
|
1069
|
+
}
|
|
979
1070
|
export function chatDraftSurface(alive) {
|
|
980
1071
|
return {
|
|
981
|
-
write(conversation, draft, revision
|
|
982
|
-
return
|
|
983
|
-
conversation,
|
|
984
|
-
text: draft.text,
|
|
985
|
-
revision,
|
|
986
|
-
...(current === undefined ? {} : pending(current)),
|
|
987
|
-
}));
|
|
1072
|
+
write(conversation, draft, revision) {
|
|
1073
|
+
return rewritten(alive, conversation, () => draft.text, revision);
|
|
988
1074
|
},
|
|
989
1075
|
prepend(conversation, draft) {
|
|
990
|
-
return
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
...(current === undefined ? {} : pending(current)),
|
|
995
|
-
}));
|
|
1076
|
+
return rewritten(alive, conversation, (held) => joinedDraft(draft.text, held));
|
|
1077
|
+
},
|
|
1078
|
+
append(conversation, draft) {
|
|
1079
|
+
return rewritten(alive, conversation, (held) => joinedDraft(held, draft.text));
|
|
996
1080
|
},
|
|
997
1081
|
discard(conversation) {
|
|
998
1082
|
return withDraft(alive, conversation, (current) => current === undefined
|
|
@@ -1002,31 +1086,34 @@ export function chatDraftSurface(alive) {
|
|
|
1002
1086
|
};
|
|
1003
1087
|
}
|
|
1004
1088
|
export async function conversationsOpened(alive, local) {
|
|
1005
|
-
const { conversationList, conversationCursor } = await local.facts();
|
|
1006
|
-
if (conversationList === null || alive.known())
|
|
1089
|
+
const { conversationList, agentList, conversationCursor } = await local.facts();
|
|
1090
|
+
if (conversationList === null || agentList === null || alive.known())
|
|
1007
1091
|
return;
|
|
1008
1092
|
alive.deps.stream()?.hold(conversationCursor);
|
|
1009
1093
|
conversationsLearned(alive);
|
|
1010
1094
|
}
|
|
1095
|
+
export function reconcileOpening(alive) {
|
|
1096
|
+
alive.held.set({ openingRead: true });
|
|
1097
|
+
return reconcileConversations(alive);
|
|
1098
|
+
}
|
|
1011
1099
|
export async function reconcileConversations(alive) {
|
|
1012
1100
|
if (!alive.known())
|
|
1013
1101
|
return;
|
|
1014
1102
|
const local = await alive.deps.local();
|
|
1015
|
-
const [held,
|
|
1103
|
+
const [held, stored, { conversationList, agentList }] = await Promise.all([
|
|
1016
1104
|
local.conversations(),
|
|
1017
|
-
local.
|
|
1105
|
+
local.storedConversations(),
|
|
1018
1106
|
local.facts(),
|
|
1019
1107
|
]);
|
|
1020
1108
|
const list = conversationList ?? [];
|
|
1109
|
+
const listing = { conversations: list, agents: agentList ?? [] };
|
|
1021
1110
|
const entries = new Map(list.map((entry) => [entry.conversation, entry]));
|
|
1022
1111
|
const named = new Set(entries.keys());
|
|
1023
1112
|
const reads = new Map(held.map((one) => [one.conversation, one]));
|
|
1024
1113
|
const { replicated } = alive.held.now();
|
|
1025
|
-
const leaving = [
|
|
1026
|
-
...new Set([...replicated, ...reads.keys(), ...kept.map(({ conversation }) => conversation)]),
|
|
1027
|
-
].filter((conversation) => !named.has(conversation) &&
|
|
1114
|
+
const leaving = [...new Set([...replicated, ...stored])].filter((conversation) => !named.has(conversation) &&
|
|
1028
1115
|
!alive.isCreating(conversation) &&
|
|
1029
|
-
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation,
|
|
1116
|
+
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation, listing)));
|
|
1030
1117
|
for (const conversation of named) {
|
|
1031
1118
|
if (!replicated.has(conversation) &&
|
|
1032
1119
|
missed(alive, conversation, reads.get(conversation), entries.get(conversation))) {
|
|
@@ -1061,6 +1148,17 @@ export async function catchUpConversations(alive, progress) {
|
|
|
1061
1148
|
if (!alive.current())
|
|
1062
1149
|
progress.complete = false;
|
|
1063
1150
|
}
|
|
1151
|
+
export async function holdsSubmission(alive, operation) {
|
|
1152
|
+
if (alive.sending(operation))
|
|
1153
|
+
return true;
|
|
1154
|
+
const local = await alive.deps.local();
|
|
1155
|
+
for (const { conversation } of await local.chatDrafts()) {
|
|
1156
|
+
const held = (await local.chatDraft(conversation))?.submitted;
|
|
1157
|
+
if (held?.some((one) => one.operation === operation && one.turn === null) === true)
|
|
1158
|
+
return true;
|
|
1159
|
+
}
|
|
1160
|
+
return false;
|
|
1161
|
+
}
|
|
1064
1162
|
export async function resendConversations(alive, progress) {
|
|
1065
1163
|
const local = await alive.deps.local();
|
|
1066
1164
|
const tried = new Set();
|
|
@@ -1072,7 +1170,7 @@ export async function resendConversations(alive, progress) {
|
|
|
1072
1170
|
if (alive.deps.closed())
|
|
1073
1171
|
return;
|
|
1074
1172
|
tried.add(submission.operation);
|
|
1075
|
-
const result = await dispatched(alive, conversation, submission);
|
|
1173
|
+
const result = await dispatched(alive, conversation, submission, true);
|
|
1076
1174
|
if (result.kind === 'revoked-authorization')
|
|
1077
1175
|
return;
|
|
1078
1176
|
if (result.kind === 'transport-uncertainty') {
|
|
@@ -1092,22 +1190,25 @@ export function watchConversation(alive, conversation, options, deliver) {
|
|
|
1092
1190
|
const { view, watcher } = alive.viewJoined(key, conversation, asked, deliver);
|
|
1093
1191
|
const { held } = view;
|
|
1094
1192
|
const reading = new AbortController();
|
|
1095
|
-
void untilAnswered(() => alive.deps.durably(async (local) => {
|
|
1193
|
+
void untilAnswered(retrying(alive.deps.retries, 'reading', `window ${key}`, () => alive.deps.durably(async (local) => {
|
|
1096
1194
|
if (held.now().window !== null)
|
|
1097
1195
|
return;
|
|
1098
1196
|
const { messages, more } = await local.messageWindow(conversation, asked.limit, asked.before);
|
|
1099
1197
|
held.set({ draft: (await local.chatDraft(conversation)) ?? null });
|
|
1100
1198
|
held.set({ ended: await endedIn(alive, conversation) });
|
|
1199
|
+
held.set({ dismissed: await dismissedIn(local, conversation) });
|
|
1200
|
+
held.set({ pins: (await local.facts()).chatPins });
|
|
1101
1201
|
held.set({ window: messages });
|
|
1102
1202
|
held.set({ more });
|
|
1103
1203
|
held.set({ total: asked.total ? await local.messageCount(conversation) : null });
|
|
1104
|
-
}), reading.signal)
|
|
1204
|
+
})), reading.signal)
|
|
1105
1205
|
.then(() => {
|
|
1106
1206
|
if (alive.deps.closed() || !view.admit(watcher))
|
|
1107
1207
|
return;
|
|
1108
|
-
const
|
|
1109
|
-
const shown = window ?? [];
|
|
1110
|
-
|
|
1208
|
+
const now = held.now();
|
|
1209
|
+
const shown = now.window ?? [];
|
|
1210
|
+
const frame = sharedFrame(view, shown);
|
|
1211
|
+
watcher.notify(viewOf(alive, conversation, shown, frame, now));
|
|
1111
1212
|
})
|
|
1112
1213
|
.catch(() => { });
|
|
1113
1214
|
return () => {
|
|
@@ -1123,9 +1224,13 @@ export function watchConversationList(alive, deliver) {
|
|
|
1123
1224
|
export function watchConversationAgents(alive, deliver) {
|
|
1124
1225
|
alive.agentListeners.join(deliver);
|
|
1125
1226
|
conversationsLearned(alive);
|
|
1126
|
-
readAgents(alive);
|
|
1127
1227
|
return () => alive.agentListeners.leave(deliver);
|
|
1128
1228
|
}
|
|
1229
|
+
export function watchListedAgents(alive, deliver) {
|
|
1230
|
+
alive.listedListeners.join(deliver);
|
|
1231
|
+
conversationsLearned(alive);
|
|
1232
|
+
return () => alive.listedListeners.leave(deliver);
|
|
1233
|
+
}
|
|
1129
1234
|
export function conversationsChanged(alive, set) {
|
|
1130
1235
|
for (const conversation of set.conversations)
|
|
1131
1236
|
emit(alive, conversation);
|
|
@@ -1137,26 +1242,32 @@ export function receiveConversationEvent(alive, event) {
|
|
|
1137
1242
|
if (event.whole)
|
|
1138
1243
|
alive.relistBegun();
|
|
1139
1244
|
if (alive.relisting())
|
|
1140
|
-
alive.relistHeard(event.entries);
|
|
1245
|
+
alive.relistHeard(event.entries, event.agents);
|
|
1141
1246
|
if (event.more && alive.relisting())
|
|
1142
1247
|
return;
|
|
1143
1248
|
const whole = alive.relistTaken();
|
|
1144
1249
|
listChanged(alive, {
|
|
1145
1250
|
replacing: whole !== null,
|
|
1146
|
-
set: whole === null ? event.entries : [...whole.values()],
|
|
1251
|
+
set: whole === null ? event.entries : [...whole.conversations.values()],
|
|
1252
|
+
agents: whole === null ? event.agents : [...whole.agents.values()],
|
|
1147
1253
|
gone: null,
|
|
1148
1254
|
...(event.more ? { paged: true } : { cursor: event.cursor }),
|
|
1149
1255
|
});
|
|
1150
1256
|
return;
|
|
1151
1257
|
}
|
|
1152
1258
|
if (event.kind === 'listed') {
|
|
1153
|
-
alive.relistHeard([event.entry]);
|
|
1154
|
-
listChanged(alive, { replacing: false, set: [event.entry], gone: null });
|
|
1259
|
+
alive.relistHeard([event.entry], []);
|
|
1260
|
+
listChanged(alive, { replacing: false, set: [event.entry], agents: [], gone: null });
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
if (event.kind === 'agent') {
|
|
1264
|
+
alive.relistHeard([], [event.agent]);
|
|
1265
|
+
listChanged(alive, { replacing: false, set: [], agents: [event.agent], gone: null });
|
|
1155
1266
|
return;
|
|
1156
1267
|
}
|
|
1157
1268
|
if (event.kind === 'unlisted') {
|
|
1158
1269
|
alive.relistDropped(event.conversation);
|
|
1159
|
-
listChanged(alive, { replacing: false, set: [], gone: event.conversation });
|
|
1270
|
+
listChanged(alive, { replacing: false, set: [], agents: [], gone: event.conversation });
|
|
1160
1271
|
return;
|
|
1161
1272
|
}
|
|
1162
1273
|
heard(alive, event);
|