@agentshouse/mdruntime 0.1.0-c8f3163f32f93 → 0.1.0-c93103f5357ff
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/AGENTS.md +262 -262
- package/dist/acquisition.d.ts +14 -0
- package/dist/acquisition.d.ts.map +1 -0
- package/dist/acquisition.js +24 -0
- package/dist/adapter.d.ts +13 -7
- package/dist/adapter.d.ts.map +1 -1
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +4 -0
- package/dist/change-set.d.ts +2 -0
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +36 -10
- package/dist/chat/kit.d.ts +2 -1
- package/dist/chat/kit.d.ts.map +1 -1
- package/dist/chat/kit.js +3 -3
- package/dist/chat/list.d.ts +2 -1
- package/dist/chat/list.d.ts.map +1 -1
- package/dist/chat/list.js +4 -3
- package/dist/chat/message.d.ts.map +1 -1
- package/dist/chat/message.js +2 -2
- package/dist/chat/messages.d.ts +1 -0
- package/dist/chat/messages.d.ts.map +1 -1
- package/dist/chat/messages.js +4 -0
- package/dist/chat/provider.d.ts +1 -1
- package/dist/chat/provider.d.ts.map +1 -1
- package/dist/chat/provider.js +26 -17
- package/dist/chat/ready.d.ts +1 -0
- package/dist/chat/ready.d.ts.map +1 -1
- package/dist/chat/ready.js +2 -2
- package/dist/client.d.ts +10 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +11 -2
- package/dist/collection.d.ts +17 -3
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +230 -19
- package/dist/connection.d.ts +23 -7
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1031 -183
- package/dist/conversation.d.ts +10 -5
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +201 -95
- package/dist/durability.d.ts +7 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +2 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +3 -3
- package/dist/host.d.ts +16 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +82 -8
- package/dist/identity.d.ts +2 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +6 -0
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/memory.d.ts +3 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +14 -2
- package/dist/model.d.ts +4 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +10 -1
- package/dist/observation.d.ts +5 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +22 -11
- package/dist/overlay.d.ts +2 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +50 -55
- package/dist/query.d.ts +35 -3
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +8 -2
- package/dist/reach.d.ts +6 -3
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +16 -4
- package/dist/react.d.ts +7 -4
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +6 -4
- package/dist/read-side.d.ts +13 -6
- package/dist/read-side.d.ts.map +1 -1
- package/dist/read-side.js +285 -83
- package/dist/readiness.d.ts +53 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +33 -0
- package/dist/recovery.d.ts +25 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +197 -0
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +17 -10
- package/dist/replica.d.ts +1 -1
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +57 -20
- package/dist/room-draft.d.ts +13 -1
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +2 -2
- package/dist/rows.d.ts +5 -13
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +5 -13
- package/dist/save.d.ts +5 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +36 -13
- package/dist/search.d.ts +36 -6
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +132 -46
- package/dist/seed.d.ts +16 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +61 -0
- package/dist/shared.d.ts +11 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +368 -0
- package/dist/status.d.ts +4 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/store.d.ts +21 -5
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +157 -53
- package/dist/turn.d.ts +7 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +45 -0
- package/dist/wire.d.ts +136 -32
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +48 -31
- package/package.json +2 -2
package/dist/conversation.js
CHANGED
|
@@ -22,6 +22,17 @@ export function unheldView(conversation) {
|
|
|
22
22
|
chatDraft: null,
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
+
export const SESSION_STARTED = 'Session started';
|
|
26
|
+
const NEW_CHAT = 'new:';
|
|
27
|
+
export function newChat(agent) {
|
|
28
|
+
return `${NEW_CHAT}${agent}`;
|
|
29
|
+
}
|
|
30
|
+
function creationOf(input) {
|
|
31
|
+
if (typeof input !== 'object' || input === null)
|
|
32
|
+
return null;
|
|
33
|
+
const { agent_id: agent, operation_id: operation } = input;
|
|
34
|
+
return typeof agent === 'string' && typeof operation === 'string' ? { agent, operation } : null;
|
|
35
|
+
}
|
|
25
36
|
function startedTurn(turn, operation) {
|
|
26
37
|
if (operation.op === 'begin')
|
|
27
38
|
return { turn, started: operation.at, parts: [], context: null };
|
|
@@ -78,11 +89,15 @@ function ordered(left, right) {
|
|
|
78
89
|
return left.identity < right.identity ? -1 : 1;
|
|
79
90
|
return 0;
|
|
80
91
|
}
|
|
81
|
-
function
|
|
92
|
+
function windowOf(held, arriving, limit) {
|
|
82
93
|
const byIdentity = new Map(held.map((message) => [message.identity, message]));
|
|
83
94
|
for (const message of arriving)
|
|
84
95
|
byIdentity.set(message.identity, message);
|
|
85
|
-
|
|
96
|
+
const next = [...byIdentity.values()].sort(ordered);
|
|
97
|
+
return limit === undefined ? next : next.slice(Math.max(0, next.length - limit));
|
|
98
|
+
}
|
|
99
|
+
function newestOf(arriving, from) {
|
|
100
|
+
return arriving.reduce((top, message) => (top === null || message.position > top ? message.position : top), from);
|
|
86
101
|
}
|
|
87
102
|
function acceptedMessage(value) {
|
|
88
103
|
if (typeof value !== 'object' || value === null)
|
|
@@ -141,14 +156,14 @@ function historyPages(result) {
|
|
|
141
156
|
}
|
|
142
157
|
return pages;
|
|
143
158
|
}
|
|
144
|
-
function
|
|
159
|
+
function answered(result, field) {
|
|
145
160
|
if (result.kind !== 'action')
|
|
146
161
|
return null;
|
|
147
162
|
const answer = result.result;
|
|
148
163
|
if (typeof answer !== 'object' || answer === null)
|
|
149
164
|
return null;
|
|
150
|
-
const
|
|
151
|
-
return typeof
|
|
165
|
+
const value = answer[field];
|
|
166
|
+
return typeof value === 'string' ? value : null;
|
|
152
167
|
}
|
|
153
168
|
function limitOf(options) {
|
|
154
169
|
const { limit } = options;
|
|
@@ -159,11 +174,18 @@ function limitOf(options) {
|
|
|
159
174
|
}
|
|
160
175
|
return limit;
|
|
161
176
|
}
|
|
177
|
+
const EXPIRED = { kind: 'rejected', code: 'expired', fields: {}, retryable: false };
|
|
162
178
|
function unwritten(draft) {
|
|
163
179
|
return draft.text === '' && draft.files.length === 0;
|
|
164
180
|
}
|
|
165
181
|
function pending(draft) {
|
|
166
|
-
return
|
|
182
|
+
return {
|
|
183
|
+
...(draft.submitted === undefined ? {} : { submitted: draft.submitted }),
|
|
184
|
+
...(draft.moves === undefined ? {} : { moves: draft.moves }),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function empty(draft) {
|
|
188
|
+
return unwritten(draft) && draft.submitted === undefined && draft.moves === undefined;
|
|
167
189
|
}
|
|
168
190
|
function withSubmitted(draft, submitted) {
|
|
169
191
|
const { submitted: _held, ...unsent } = draft;
|
|
@@ -178,15 +200,17 @@ function returned(draft, submission, others) {
|
|
|
178
200
|
}, others);
|
|
179
201
|
}
|
|
180
202
|
export function createConversationStore(deps) {
|
|
181
|
-
const
|
|
203
|
+
const stored = new Set();
|
|
182
204
|
const reads = new Map();
|
|
205
|
+
const partials = new Set();
|
|
183
206
|
const drafts = new Map();
|
|
184
|
-
const sending = new
|
|
207
|
+
const sending = new Map();
|
|
185
208
|
const behind = new Set();
|
|
186
209
|
const gaps = new Map();
|
|
187
210
|
const lives = new Map();
|
|
188
211
|
const views = new Map();
|
|
189
212
|
const listing = new Map();
|
|
213
|
+
const creations = new Set();
|
|
190
214
|
const listWatchers = new Set();
|
|
191
215
|
let listKnown = false;
|
|
192
216
|
const agentWatchers = new Set();
|
|
@@ -198,22 +222,17 @@ export function createConversationStore(deps) {
|
|
|
198
222
|
function liveOf(conversation) {
|
|
199
223
|
return lives.get(conversation) ?? QUIET;
|
|
200
224
|
}
|
|
201
|
-
function
|
|
202
|
-
const held = messages.get(conversation) ?? [];
|
|
203
|
-
const shown = limit === undefined ? held : held.slice(Math.max(0, held.length - limit));
|
|
204
|
-
return shown.map(({ identity, turn, text, message }) => ({
|
|
205
|
-
identity,
|
|
206
|
-
turn,
|
|
207
|
-
text,
|
|
208
|
-
message: structuredClone(message),
|
|
209
|
-
}));
|
|
210
|
-
}
|
|
211
|
-
function viewOf(conversation, limit, shown = shownMessages(conversation, limit)) {
|
|
225
|
+
function viewOf(conversation, held) {
|
|
212
226
|
const draft = drafts.get(conversation);
|
|
213
227
|
const facts = liveOf(conversation);
|
|
214
228
|
return {
|
|
215
229
|
conversation,
|
|
216
|
-
messages:
|
|
230
|
+
messages: held.map(({ identity, turn, text, message }) => ({
|
|
231
|
+
identity,
|
|
232
|
+
turn,
|
|
233
|
+
text,
|
|
234
|
+
message,
|
|
235
|
+
})),
|
|
217
236
|
turn: structuredClone(facts.turn),
|
|
218
237
|
questions: structuredClone(facts.questions),
|
|
219
238
|
process: facts.process === null ? null : { ...facts.process },
|
|
@@ -224,23 +243,30 @@ export function createConversationStore(deps) {
|
|
|
224
243
|
: { text: draft.text, files: [...draft.files], revision: draft.revision },
|
|
225
244
|
};
|
|
226
245
|
}
|
|
227
|
-
function emit(conversation
|
|
246
|
+
function emit(conversation) {
|
|
228
247
|
if (deps.closed())
|
|
229
248
|
return;
|
|
230
249
|
for (const view of views.values()) {
|
|
231
|
-
if (view.conversation !== conversation)
|
|
250
|
+
if (view.conversation !== conversation || view.window === null)
|
|
232
251
|
continue;
|
|
233
|
-
if (messagesChanged)
|
|
234
|
-
view.messages = null;
|
|
235
252
|
const ready = [...view.watchers].filter((watcher) => watcher.ready);
|
|
236
253
|
if (ready.length === 0)
|
|
237
254
|
continue;
|
|
238
|
-
|
|
239
|
-
const value = viewOf(conversation, view.limit, view.messages);
|
|
255
|
+
const value = viewOf(conversation, view.window);
|
|
240
256
|
for (const watcher of ready)
|
|
241
257
|
watcher.notify(value);
|
|
242
258
|
}
|
|
243
259
|
}
|
|
260
|
+
function slide(conversation, arriving) {
|
|
261
|
+
for (const view of views.values()) {
|
|
262
|
+
if (view.conversation !== conversation || view.window === null)
|
|
263
|
+
continue;
|
|
264
|
+
view.window = arriving === null ? [] : windowOf(view.window, arriving, view.limit);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function changesOf(conversation, arriving) {
|
|
268
|
+
return arriving.map(({ identity, text }) => ({ conversation, identity, text }));
|
|
269
|
+
}
|
|
244
270
|
function stateOf(conversation) {
|
|
245
271
|
const facts = liveOf(conversation);
|
|
246
272
|
if (facts.questions.length > 0)
|
|
@@ -297,7 +323,10 @@ export function createConversationStore(deps) {
|
|
|
297
323
|
const declaration = deps.agents();
|
|
298
324
|
if (declaration === undefined)
|
|
299
325
|
return;
|
|
300
|
-
const
|
|
326
|
+
const held = await deps.documents(declaration);
|
|
327
|
+
if ('pending' in held)
|
|
328
|
+
return;
|
|
329
|
+
const { documents } = held;
|
|
301
330
|
const names = new Map();
|
|
302
331
|
const retired = new Set();
|
|
303
332
|
for (const document of documents) {
|
|
@@ -320,6 +349,12 @@ export function createConversationStore(deps) {
|
|
|
320
349
|
if (named)
|
|
321
350
|
emitList();
|
|
322
351
|
emitAgents();
|
|
352
|
+
const ended = [...drafts.keys()].filter(retiredChat);
|
|
353
|
+
if (ended.length > 0)
|
|
354
|
+
await remove(ended);
|
|
355
|
+
}
|
|
356
|
+
function retiredChat(conversation) {
|
|
357
|
+
return (conversation.startsWith(NEW_CHAT) && retiredAgents.has(conversation.slice(NEW_CHAT.length)));
|
|
323
358
|
}
|
|
324
359
|
function agentsReady() {
|
|
325
360
|
agentsRead ??= readAgents().catch(() => {
|
|
@@ -329,7 +364,7 @@ export function createConversationStore(deps) {
|
|
|
329
364
|
}
|
|
330
365
|
function live(conversation, change) {
|
|
331
366
|
setLive(conversation, { ...liveOf(conversation), ...change });
|
|
332
|
-
emit(conversation
|
|
367
|
+
emit(conversation);
|
|
333
368
|
}
|
|
334
369
|
function relayed(conversation, turn, operation) {
|
|
335
370
|
const held = liveOf(conversation).turn;
|
|
@@ -357,21 +392,25 @@ export function createConversationStore(deps) {
|
|
|
357
392
|
}
|
|
358
393
|
async function remove(leaving) {
|
|
359
394
|
await deps.durably(async (local) => {
|
|
360
|
-
await local.dropConversations(leaving);
|
|
361
395
|
const removed = [];
|
|
362
|
-
const changed = [];
|
|
363
396
|
for (const conversation of leaving) {
|
|
364
|
-
for (const
|
|
365
|
-
removed.push({ conversation, identity:
|
|
397
|
+
for (const identity of await local.messageIdentities(conversation)) {
|
|
398
|
+
removed.push({ conversation, identity, text: null });
|
|
366
399
|
}
|
|
367
|
-
|
|
400
|
+
}
|
|
401
|
+
await local.dropConversations(leaving);
|
|
402
|
+
const changed = [];
|
|
403
|
+
for (const conversation of leaving) {
|
|
404
|
+
if (stored.has(conversation) || drafts.has(conversation) || lives.has(conversation)) {
|
|
368
405
|
changed.push(conversation);
|
|
369
406
|
}
|
|
370
|
-
|
|
407
|
+
stored.delete(conversation);
|
|
371
408
|
reads.delete(conversation);
|
|
409
|
+
partials.delete(conversation);
|
|
372
410
|
drafts.delete(conversation);
|
|
373
411
|
behind.delete(conversation);
|
|
374
412
|
setLive(conversation, null);
|
|
413
|
+
slide(conversation, null);
|
|
375
414
|
}
|
|
376
415
|
if (changed.length > 0)
|
|
377
416
|
deps.publish(conversationChangeSet(removed, changed));
|
|
@@ -393,23 +432,21 @@ export function createConversationStore(deps) {
|
|
|
393
432
|
await local.keepMessages({
|
|
394
433
|
conversation,
|
|
395
434
|
messages: [message],
|
|
396
|
-
...(advances ? { read: message.position } : {}),
|
|
435
|
+
...(advances ? { read: { at: message.position, partial: false } } : {}),
|
|
397
436
|
});
|
|
398
|
-
|
|
437
|
+
stored.add(conversation);
|
|
399
438
|
if (advances)
|
|
400
439
|
reads.set(conversation, message.position);
|
|
401
440
|
sealTurns(conversation, new Set([message.turn]));
|
|
402
|
-
|
|
441
|
+
slide(conversation, [message]);
|
|
442
|
+
deps.publish(conversationChangeSet(changesOf(conversation, [message]), [conversation]));
|
|
403
443
|
});
|
|
404
444
|
}
|
|
405
445
|
async function readHistories(conversations) {
|
|
406
446
|
const generations = new Map(conversations.map((one) => [one, gaps.get(one) ?? 0]));
|
|
407
|
-
const starts = new Map(conversations.map((one) => [one, reads.get(one)]));
|
|
408
|
-
const arriving = new Map();
|
|
409
|
-
const complete = new Set();
|
|
410
447
|
let asking = conversations.map((conversation) => ({
|
|
411
448
|
conversation,
|
|
412
|
-
after:
|
|
449
|
+
after: reads.get(conversation) ?? undefined,
|
|
413
450
|
}));
|
|
414
451
|
while (asking.length > 0) {
|
|
415
452
|
const result = await deps.call('conversation.history', {
|
|
@@ -421,43 +458,41 @@ export function createConversationStore(deps) {
|
|
|
421
458
|
const pages = historyPages(result);
|
|
422
459
|
if (pages === null)
|
|
423
460
|
return result;
|
|
424
|
-
const asked = new
|
|
461
|
+
const asked = new Map(asking.map(({ conversation, after }) => [conversation, after]));
|
|
425
462
|
const following = [];
|
|
426
463
|
for (const page of pages) {
|
|
427
464
|
if (!asked.has(page.conversation))
|
|
428
465
|
continue;
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
...page.messages,
|
|
432
|
-
]);
|
|
433
|
-
if (page.next === undefined)
|
|
434
|
-
complete.add(page.conversation);
|
|
435
|
-
else
|
|
466
|
+
await keepPage(page.conversation, page.messages, asked.get(page.conversation) ?? null, page.next, generations.get(page.conversation) ?? 0);
|
|
467
|
+
if (page.next !== undefined) {
|
|
436
468
|
following.push({ conversation: page.conversation, after: page.next });
|
|
469
|
+
}
|
|
437
470
|
}
|
|
438
471
|
asking = following;
|
|
439
472
|
}
|
|
440
|
-
for (const [conversation, held] of arriving) {
|
|
441
|
-
if (!complete.has(conversation))
|
|
442
|
-
continue;
|
|
443
|
-
await keepHistory(conversation, held, starts.get(conversation), generations.get(conversation) ?? 0);
|
|
444
|
-
}
|
|
445
473
|
return null;
|
|
446
474
|
}
|
|
447
|
-
function
|
|
475
|
+
function keepPage(conversation, arriving, from, next, generation) {
|
|
448
476
|
return deps.durably(async (local) => {
|
|
449
477
|
if (!replicated.has(conversation))
|
|
450
478
|
return;
|
|
451
|
-
const
|
|
479
|
+
const whole = next === undefined;
|
|
480
|
+
const cursor = next ?? newestOf(arriving, from);
|
|
481
|
+
const partial = !whole && (partials.has(conversation) || !reads.has(conversation));
|
|
452
482
|
const sealing = await sealed(local, conversation, new Set(arriving.map((message) => message.turn)));
|
|
453
|
-
await local.keepMessages({ conversation, messages: arriving, read:
|
|
454
|
-
|
|
455
|
-
reads.set(conversation,
|
|
483
|
+
await local.keepMessages({ conversation, messages: arriving, read: { at: cursor, partial } });
|
|
484
|
+
stored.add(conversation);
|
|
485
|
+
reads.set(conversation, cursor);
|
|
486
|
+
if (partial)
|
|
487
|
+
partials.add(conversation);
|
|
488
|
+
else
|
|
489
|
+
partials.delete(conversation);
|
|
456
490
|
sealTurns(conversation, new Set(arriving.map((message) => message.turn)));
|
|
457
|
-
if ((gaps.get(conversation) ?? 0) === generation)
|
|
491
|
+
if (whole && (gaps.get(conversation) ?? 0) === generation)
|
|
458
492
|
behind.delete(conversation);
|
|
459
|
-
|
|
460
|
-
|
|
493
|
+
slide(conversation, arriving);
|
|
494
|
+
if (arriving.length > 0 || sealing || whole) {
|
|
495
|
+
deps.publish(conversationChangeSet(changesOf(conversation, arriving), [conversation]));
|
|
461
496
|
}
|
|
462
497
|
});
|
|
463
498
|
}
|
|
@@ -470,7 +505,7 @@ export function createConversationStore(deps) {
|
|
|
470
505
|
if (held === undefined)
|
|
471
506
|
return;
|
|
472
507
|
setLive(conversation, { ...QUIET, turn: held.turn });
|
|
473
|
-
emit(conversation
|
|
508
|
+
emit(conversation);
|
|
474
509
|
return;
|
|
475
510
|
}
|
|
476
511
|
if (event.kind === 'turn') {
|
|
@@ -504,12 +539,12 @@ export function createConversationStore(deps) {
|
|
|
504
539
|
emit(conversation);
|
|
505
540
|
}
|
|
506
541
|
async function kept(local, conversation, following) {
|
|
507
|
-
if (following === null || (
|
|
542
|
+
if (following === null || empty(following)) {
|
|
508
543
|
await local.dropChatDraft(conversation);
|
|
509
544
|
drafts.delete(conversation);
|
|
510
545
|
}
|
|
511
546
|
else {
|
|
512
|
-
await local.
|
|
547
|
+
await local.keepChatDrafts([following]);
|
|
513
548
|
drafts.set(conversation, following);
|
|
514
549
|
}
|
|
515
550
|
}
|
|
@@ -522,9 +557,32 @@ export function createConversationStore(deps) {
|
|
|
522
557
|
await kept(local, conversation, withSubmitted(held, left));
|
|
523
558
|
return true;
|
|
524
559
|
}
|
|
560
|
+
function moved(agent, operation, to) {
|
|
561
|
+
const from = newChat(agent);
|
|
562
|
+
return deps.durably(async (local) => {
|
|
563
|
+
const held = drafts.get(from);
|
|
564
|
+
const earlier = (held?.moves ?? []).filter((one) => !deps.expired(one));
|
|
565
|
+
if (earlier.includes(operation))
|
|
566
|
+
return;
|
|
567
|
+
const blank = {
|
|
568
|
+
conversation: from,
|
|
569
|
+
text: '',
|
|
570
|
+
files: [],
|
|
571
|
+
revision: chatDraftRevision(),
|
|
572
|
+
};
|
|
573
|
+
const { moves: _answered, ...unsent } = held ?? blank;
|
|
574
|
+
const taken = drafts.has(to) || empty(unsent) ? [] : [{ ...unsent, conversation: to }];
|
|
575
|
+
const left = { ...(taken.length === 0 ? unsent : blank), moves: [...earlier, operation] };
|
|
576
|
+
await local.keepChatDrafts([left, ...taken]);
|
|
577
|
+
drafts.set(from, left);
|
|
578
|
+
for (const one of taken)
|
|
579
|
+
drafts.set(to, one);
|
|
580
|
+
deps.publish(conversationChangeSet([], [from, to]));
|
|
581
|
+
});
|
|
582
|
+
}
|
|
525
583
|
function withDraft(conversation, next) {
|
|
526
584
|
return deps.durably(async (local) => {
|
|
527
|
-
const following = next(drafts.get(conversation));
|
|
585
|
+
const following = await next(drafts.get(conversation), local);
|
|
528
586
|
if (following === undefined)
|
|
529
587
|
return;
|
|
530
588
|
await kept(local, conversation, following);
|
|
@@ -533,8 +591,10 @@ export function createConversationStore(deps) {
|
|
|
533
591
|
}
|
|
534
592
|
async function submitted(conversation, operation, draft) {
|
|
535
593
|
let submission;
|
|
594
|
+
let earlier = false;
|
|
536
595
|
await withDraft(conversation, (current) => {
|
|
537
596
|
submission = current?.submitted?.find((one) => one.operation === operation);
|
|
597
|
+
earlier = submission !== undefined;
|
|
538
598
|
if (submission !== undefined)
|
|
539
599
|
return undefined;
|
|
540
600
|
const said = draft ?? current;
|
|
@@ -552,10 +612,19 @@ export function createConversationStore(deps) {
|
|
|
552
612
|
submitted: [...(current?.submitted ?? []), submission],
|
|
553
613
|
};
|
|
554
614
|
});
|
|
555
|
-
return submission;
|
|
615
|
+
return { submission: submission, earlier };
|
|
616
|
+
}
|
|
617
|
+
function forgotten(conversation, submission) {
|
|
618
|
+
return withDraft(conversation, (current) => {
|
|
619
|
+
const held = current?.submitted ?? [];
|
|
620
|
+
if (current === undefined || !held.includes(submission))
|
|
621
|
+
return undefined;
|
|
622
|
+
return withSubmitted(current, held.filter((one) => one !== submission));
|
|
623
|
+
});
|
|
556
624
|
}
|
|
557
625
|
async function dispatched(conversation, submission) {
|
|
558
|
-
|
|
626
|
+
const dispatch = {};
|
|
627
|
+
sending.set(submission.operation, dispatch);
|
|
559
628
|
try {
|
|
560
629
|
const files = await Promise.all(submission.files.map(async (file) => ({ ...(await declaredFile(file)), blob: file.blob })));
|
|
561
630
|
const result = await invoke('conversation.send', conversation, {
|
|
@@ -565,17 +634,19 @@ export function createConversationStore(deps) {
|
|
|
565
634
|
});
|
|
566
635
|
if (result.kind === 'revoked-authorization')
|
|
567
636
|
return result;
|
|
568
|
-
if (result.kind !== 'action' && result.retryable)
|
|
637
|
+
if (result.kind !== 'action' && result.retryable) {
|
|
638
|
+
deps.unanswered();
|
|
569
639
|
return result;
|
|
570
|
-
|
|
571
|
-
|
|
640
|
+
}
|
|
641
|
+
const turn = answered(result, 'turn');
|
|
642
|
+
await withDraft(conversation, async (current, local) => {
|
|
572
643
|
const held = current?.submitted?.find((one) => one.operation === submission.operation);
|
|
573
644
|
if (current === undefined || held === undefined || held.turn !== null)
|
|
574
645
|
return undefined;
|
|
575
646
|
const others = current.submitted.filter((one) => one !== held);
|
|
576
647
|
if (result.kind !== 'action')
|
|
577
648
|
return returned(current, held, others);
|
|
578
|
-
const arrived =
|
|
649
|
+
const arrived = turn !== null && (await local.turnArrived(conversation, turn));
|
|
579
650
|
return withSubmitted(current, turn === null || arrived
|
|
580
651
|
? others
|
|
581
652
|
: current.submitted.map((one) => (one === held ? { ...held, turn } : one)));
|
|
@@ -583,7 +654,8 @@ export function createConversationStore(deps) {
|
|
|
583
654
|
return result;
|
|
584
655
|
}
|
|
585
656
|
finally {
|
|
586
|
-
sending.
|
|
657
|
+
if (sending.get(submission.operation) === dispatch)
|
|
658
|
+
sending.delete(submission.operation);
|
|
587
659
|
}
|
|
588
660
|
}
|
|
589
661
|
function invoke(name, conversation, extra = {}) {
|
|
@@ -596,14 +668,27 @@ export function createConversationStore(deps) {
|
|
|
596
668
|
},
|
|
597
669
|
async read(conversation, options = {}) {
|
|
598
670
|
const limit = limitOf(options);
|
|
599
|
-
return deps.durably(() =>
|
|
671
|
+
return deps.durably(async (local) => structuredClone(viewOf(conversation, await local.messageWindow(conversation, limit))));
|
|
600
672
|
},
|
|
601
|
-
create(input) {
|
|
602
|
-
|
|
673
|
+
async create(input) {
|
|
674
|
+
const result = await deps.call('conversation.create', input);
|
|
675
|
+
const conversation = answered(result, 'conversation');
|
|
676
|
+
if (conversation === null)
|
|
677
|
+
return result;
|
|
678
|
+
if (!listing.has(conversation))
|
|
679
|
+
creations.add(conversation);
|
|
680
|
+
const creation = creationOf(input);
|
|
681
|
+
if (creation !== null)
|
|
682
|
+
await moved(creation.agent, creation.operation, conversation);
|
|
683
|
+
return result;
|
|
603
684
|
},
|
|
604
685
|
async send(conversation, operation = changeBatchIdentity(), draft) {
|
|
605
686
|
if (deps.online()) {
|
|
606
|
-
|
|
687
|
+
const { submission, earlier } = await submitted(conversation, operation, draft);
|
|
688
|
+
if (!earlier || !deps.expired(operation))
|
|
689
|
+
return dispatched(conversation, submission);
|
|
690
|
+
await forgotten(conversation, submission);
|
|
691
|
+
return EXPIRED;
|
|
607
692
|
}
|
|
608
693
|
if (draft !== undefined) {
|
|
609
694
|
await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
|
|
@@ -644,7 +729,7 @@ export function createConversationStore(deps) {
|
|
|
644
729
|
text: draft.text,
|
|
645
730
|
files: [...draft.files],
|
|
646
731
|
revision,
|
|
647
|
-
...(current
|
|
732
|
+
...(current === undefined ? {} : pending(current)),
|
|
648
733
|
}));
|
|
649
734
|
},
|
|
650
735
|
discard(conversation) {
|
|
@@ -662,18 +747,19 @@ export function createConversationStore(deps) {
|
|
|
662
747
|
return {
|
|
663
748
|
surface,
|
|
664
749
|
chatDraft,
|
|
665
|
-
hydrate(held,
|
|
666
|
-
|
|
750
|
+
hydrate(held, kept) {
|
|
751
|
+
stored.clear();
|
|
667
752
|
reads.clear();
|
|
668
|
-
|
|
669
|
-
view.messages = null;
|
|
753
|
+
partials.clear();
|
|
670
754
|
for (const entry of held) {
|
|
671
|
-
|
|
755
|
+
stored.add(entry.conversation);
|
|
672
756
|
if (entry.read !== undefined)
|
|
673
757
|
reads.set(entry.conversation, entry.read);
|
|
758
|
+
if (entry.partial)
|
|
759
|
+
partials.add(entry.conversation);
|
|
674
760
|
}
|
|
675
761
|
drafts.clear();
|
|
676
|
-
for (const record of
|
|
762
|
+
for (const record of kept)
|
|
677
763
|
drafts.set(record.conversation, record);
|
|
678
764
|
},
|
|
679
765
|
async reconcile() {
|
|
@@ -681,8 +767,10 @@ export function createConversationStore(deps) {
|
|
|
681
767
|
return;
|
|
682
768
|
const named = new Set(listing.keys());
|
|
683
769
|
const leaving = [
|
|
684
|
-
...new Set([...replicated, ...
|
|
685
|
-
].filter((conversation) => !named.has(conversation)
|
|
770
|
+
...new Set([...replicated, ...stored, ...reads.keys(), ...drafts.keys()]),
|
|
771
|
+
].filter((conversation) => !named.has(conversation) &&
|
|
772
|
+
!creations.has(conversation) &&
|
|
773
|
+
(!conversation.startsWith(NEW_CHAT) || retiredChat(conversation)));
|
|
686
774
|
for (const conversation of named) {
|
|
687
775
|
if (!replicated.has(conversation))
|
|
688
776
|
behind.add(conversation);
|
|
@@ -709,6 +797,10 @@ export function createConversationStore(deps) {
|
|
|
709
797
|
continue;
|
|
710
798
|
if (deps.closed())
|
|
711
799
|
return;
|
|
800
|
+
if (deps.expired(submission.operation)) {
|
|
801
|
+
await forgotten(conversation, submission);
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
712
804
|
const result = await dispatched(conversation, submission);
|
|
713
805
|
if (result.kind === 'revoked-authorization')
|
|
714
806
|
return;
|
|
@@ -716,16 +808,26 @@ export function createConversationStore(deps) {
|
|
|
716
808
|
progress.reachable = false;
|
|
717
809
|
return;
|
|
718
810
|
}
|
|
811
|
+
if (result.kind !== 'action' && result.retryable) {
|
|
812
|
+
progress.complete = false;
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
719
815
|
}
|
|
720
816
|
}
|
|
721
817
|
},
|
|
722
818
|
current() {
|
|
723
819
|
return behind.size === 0;
|
|
724
820
|
},
|
|
821
|
+
known() {
|
|
822
|
+
return listKnown;
|
|
823
|
+
},
|
|
725
824
|
reconnected() {
|
|
726
825
|
for (const conversation of replicated)
|
|
727
826
|
gap(conversation);
|
|
728
827
|
},
|
|
828
|
+
reopened() {
|
|
829
|
+
sending.clear();
|
|
830
|
+
},
|
|
729
831
|
watch(conversation, options, deliver) {
|
|
730
832
|
const limit = limitOf(options);
|
|
731
833
|
const key = JSON.stringify([conversation, limit ?? null]);
|
|
@@ -733,18 +835,20 @@ export function createConversationStore(deps) {
|
|
|
733
835
|
conversation,
|
|
734
836
|
limit,
|
|
735
837
|
watchers: new Set(),
|
|
736
|
-
|
|
838
|
+
window: null,
|
|
737
839
|
};
|
|
738
840
|
views.set(key, view);
|
|
739
841
|
const watcher = { notify: deliver, ready: false };
|
|
740
842
|
view.watchers.add(watcher);
|
|
741
843
|
void deps
|
|
742
|
-
.durably(() =>
|
|
844
|
+
.durably(async (local) => {
|
|
845
|
+
view.window ??= await local.messageWindow(conversation, limit);
|
|
846
|
+
})
|
|
743
847
|
.then(() => {
|
|
744
848
|
if (deps.closed() || !view.watchers.has(watcher))
|
|
745
849
|
return;
|
|
746
850
|
watcher.ready = true;
|
|
747
|
-
watcher.notify(viewOf(conversation,
|
|
851
|
+
watcher.notify(viewOf(conversation, view.window ?? []));
|
|
748
852
|
})
|
|
749
853
|
.catch(() => { });
|
|
750
854
|
return () => {
|
|
@@ -791,12 +895,15 @@ export function createConversationStore(deps) {
|
|
|
791
895
|
if (event.kind === 'list' || event.kind === 'listed' || event.kind === 'unlisted') {
|
|
792
896
|
if (event.kind === 'list') {
|
|
793
897
|
listing.clear();
|
|
794
|
-
for (const entry of event.entries)
|
|
898
|
+
for (const entry of event.entries) {
|
|
795
899
|
listing.set(entry.conversation, { ...entry });
|
|
900
|
+
creations.delete(entry.conversation);
|
|
901
|
+
}
|
|
796
902
|
listKnown = true;
|
|
797
903
|
}
|
|
798
904
|
else if (event.kind === 'listed') {
|
|
799
905
|
listing.set(event.entry.conversation, { ...event.entry });
|
|
906
|
+
creations.delete(event.entry.conversation);
|
|
800
907
|
}
|
|
801
908
|
else {
|
|
802
909
|
listing.delete(event.conversation);
|
|
@@ -810,12 +917,11 @@ export function createConversationStore(deps) {
|
|
|
810
917
|
heard(event);
|
|
811
918
|
return false;
|
|
812
919
|
},
|
|
813
|
-
|
|
814
|
-
return [...
|
|
920
|
+
searchable() {
|
|
921
|
+
return [...(listKnown ? listing.keys() : stored)].sort();
|
|
815
922
|
},
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
return held === undefined ? null : { conversation, identity, text: held.text };
|
|
923
|
+
acquired(conversation) {
|
|
924
|
+
return reads.has(conversation) && !partials.has(conversation);
|
|
819
925
|
},
|
|
820
926
|
close() {
|
|
821
927
|
views.clear();
|
package/dist/durability.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import type { Persistence } from './readiness.js';
|
|
2
|
+
export type StorageEstimate = {
|
|
3
|
+
readonly usage: number;
|
|
4
|
+
readonly quota: number;
|
|
5
|
+
};
|
|
1
6
|
export type RuntimeShell = {
|
|
2
|
-
|
|
7
|
+
persistence: Persistence;
|
|
3
8
|
generation: string | null;
|
|
4
9
|
keepGeneration(value: string): void | Promise<void>;
|
|
5
10
|
dropGeneration(): void | Promise<void>;
|
|
11
|
+
estimate?(): Promise<StorageEstimate | null>;
|
|
6
12
|
};
|
|
7
13
|
export declare function detectStorageLoss(stored: string | null, reported: string | null): string | null;
|
|
8
14
|
export declare function nextGeneration(stored: string | null, reported: string | null): string;
|
package/dist/durability.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"durability.d.ts","sourceRoot":"","sources":["../src/durability.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"durability.d.ts","sourceRoot":"","sources":["../src/durability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAIlD,MAAM,MAAM,eAAe,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjF,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,cAAc,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;CAC9C,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAG/F;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAGrF"}
|
package/dist/entry.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type QueryRows } from './query.js';
|
|
2
2
|
export { QueryError } from './query.js';
|
|
3
3
|
export type EntryRoom = {
|
|
4
4
|
locator: string;
|
|
@@ -11,7 +11,7 @@ export declare function boundQuery(template: unknown, args: EntryArguments): unk
|
|
|
11
11
|
export declare function entryParameters(template: unknown): readonly string[];
|
|
12
12
|
export declare function entryRefusal(template: unknown): string | null;
|
|
13
13
|
export type EntryScope = {
|
|
14
|
-
results(queries: Readonly<Record<string, unknown>>): Promise<Record<string,
|
|
14
|
+
results(queries: Readonly<Record<string, unknown>>): Promise<Record<string, QueryRows>>;
|
|
15
15
|
};
|
|
16
16
|
export declare function entryScope(rooms: readonly EntryRoom[]): EntryScope;
|
|
17
17
|
//# sourceMappingURL=entry.d.ts.map
|
package/dist/entry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AAGA,OAAO,EAML,KAAK,
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AAGA,OAAO,EAML,KAAK,SAAS,EAEf,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE9D,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AA0D7E,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAE3E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAMpE;AAkCD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAQ7D;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CACzF,CAAC;AAEF,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,UAAU,CAsDlE"}
|