@agentshouse/mdruntime 0.1.0-c5b50992a4193 → 0.1.0-c698c0ebd65bd
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 +151 -96
- package/README.md +13 -3
- package/dist/adapter.d.ts +47 -14
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attempt.d.ts +16 -0
- package/dist/attempt.d.ts.map +1 -0
- package/dist/attempt.js +70 -0
- package/dist/binary.d.ts +23 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +8 -0
- package/dist/bootstrap.d.ts +17 -5
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +92 -38
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +19 -12
- package/dist/change.d.ts +15 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +26 -1
- package/dist/chat/acts.d.ts +33 -0
- package/dist/chat/acts.d.ts.map +1 -0
- package/dist/chat/acts.js +36 -0
- package/dist/chat/context.d.ts +3 -0
- package/dist/chat/context.d.ts.map +1 -0
- package/dist/chat/context.js +10 -0
- package/dist/chat/input.d.ts +9 -0
- package/dist/chat/input.d.ts.map +1 -0
- package/dist/chat/input.js +99 -0
- package/dist/chat/kit.d.ts +60 -0
- package/dist/chat/kit.d.ts.map +1 -0
- package/dist/chat/kit.js +123 -0
- package/dist/chat/lasting.d.ts +6 -0
- package/dist/chat/lasting.d.ts.map +1 -0
- package/dist/chat/lasting.js +19 -0
- package/dist/chat/list.d.ts +26 -0
- package/dist/chat/list.d.ts.map +1 -0
- package/dist/chat/list.js +62 -0
- package/dist/chat/markdown.d.ts +20 -0
- package/dist/chat/markdown.d.ts.map +1 -0
- package/dist/chat/markdown.js +188 -0
- package/dist/chat/message.d.ts +6 -0
- package/dist/chat/message.d.ts.map +1 -0
- package/dist/chat/message.js +192 -0
- package/dist/chat/messages.d.ts +21 -0
- package/dist/chat/messages.d.ts.map +1 -0
- package/dist/chat/messages.js +151 -0
- package/dist/chat/name.d.ts +6 -0
- package/dist/chat/name.d.ts.map +1 -0
- package/dist/chat/name.js +37 -0
- package/dist/chat/opened.d.ts +11 -0
- package/dist/chat/opened.d.ts.map +1 -0
- package/dist/chat/opened.js +17 -0
- package/dist/chat/overlay.d.ts +31 -0
- package/dist/chat/overlay.d.ts.map +1 -0
- package/dist/chat/overlay.js +97 -0
- package/dist/chat/parts.d.ts +57 -0
- package/dist/chat/parts.d.ts.map +1 -0
- package/dist/chat/parts.js +119 -0
- package/dist/chat/process.d.ts +20 -0
- package/dist/chat/process.d.ts.map +1 -0
- package/dist/chat/process.js +32 -0
- package/dist/chat/provider.d.ts +63 -0
- package/dist/chat/provider.d.ts.map +1 -0
- package/dist/chat/provider.js +620 -0
- package/dist/chat/question.d.ts +9 -0
- package/dist/chat/question.d.ts.map +1 -0
- package/dist/chat/question.js +80 -0
- package/dist/chat/questions.d.ts +31 -0
- package/dist/chat/questions.d.ts.map +1 -0
- package/dist/chat/questions.js +111 -0
- package/dist/chat/read.d.ts +5 -0
- package/dist/chat/read.d.ts.map +1 -0
- package/dist/chat/read.js +13 -0
- package/dist/chat/ready.d.ts +33 -0
- package/dist/chat/ready.d.ts.map +1 -0
- package/dist/chat/ready.js +91 -0
- package/dist/chat/style.d.ts +4 -0
- package/dist/chat/style.d.ts.map +1 -0
- package/dist/chat/style.js +302 -0
- package/dist/chat.d.ts +14 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +8 -0
- package/dist/client.d.ts +15 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +66 -16
- package/dist/collection.d.ts +6 -11
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +56 -19
- package/dist/connection.d.ts +22 -9
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +566 -175
- package/dist/conversation.d.ts +15 -5
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +189 -64
- package/dist/entry.d.ts +17 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +156 -0
- package/dist/expectation.d.ts +21 -0
- package/dist/expectation.d.ts.map +1 -0
- package/dist/expectation.js +70 -0
- package/dist/failure.d.ts +13 -0
- package/dist/failure.d.ts.map +1 -0
- package/dist/failure.js +19 -0
- package/dist/fence.d.ts +6 -0
- package/dist/fence.d.ts.map +1 -0
- package/dist/fence.js +10 -0
- package/dist/host.d.ts +3 -1
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +16 -12
- package/dist/identity.d.ts +3 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +13 -1
- package/dist/index.d.ts +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/memory.d.ts +5 -3
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +62 -20
- package/dist/model.d.ts +3 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/open.d.ts +2 -0
- package/dist/open.d.ts.map +1 -0
- package/dist/open.js +1 -0
- package/dist/outcome.d.ts +32 -3
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +42 -1
- package/dist/overlay.d.ts +14 -3
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +75 -37
- package/dist/query.d.ts +4 -0
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -0
- package/dist/reach.d.ts +2 -0
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +44 -20
- package/dist/react.d.ts +25 -16
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +8 -6
- package/dist/read-side.d.ts.map +1 -1
- package/dist/read-side.js +9 -2
- package/dist/refresh.d.ts +10 -0
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +42 -38
- package/dist/replica.d.ts +7 -4
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +74 -54
- package/dist/room-draft.d.ts +26 -9
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +132 -23
- package/dist/rows.d.ts +5 -1
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +10 -2
- package/dist/save.d.ts +26 -1
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +345 -37
- package/dist/search.d.ts +3 -2
- package/dist/search.d.ts.map +1 -1
- package/dist/status.d.ts +2 -2
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +0 -8
- package/dist/store.d.ts +48 -14
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +366 -170
- package/dist/wire.d.ts +7 -3
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +15 -2
- package/package.json +26 -14
- package/dist/attachment.d.ts +0 -3
- package/dist/attachment.d.ts.map +0 -1
- package/dist/attachment.js +0 -8
package/dist/conversation.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { ConversationAction, ConversationAgents, ConversationEvent, ConversationMessage, ConversationStream, ProcessCommand, SessionOption, TurnContext } from './adapter.js';
|
|
2
2
|
import { type ChangeSet } from './change-set.js';
|
|
3
3
|
import { type ChatDraftFile } from './file.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { Open } from './open.js';
|
|
5
|
+
import { type CallResult, type Offline } from './outcome.js';
|
|
5
6
|
import type { DocumentResult } from './query.js';
|
|
6
7
|
import type { SearchedMessage } from './search.js';
|
|
7
8
|
import type { CycleProgress } from './status.js';
|
|
8
9
|
import type { ChatDraftRecord, HeldConversation, RuntimeStore } from './store.js';
|
|
9
|
-
export type ConversationState = 'working' | 'asking' | 'idle'
|
|
10
|
+
export type ConversationState = Open<'working' | 'asking' | 'idle'>;
|
|
10
11
|
export type ConversationEntry = {
|
|
11
12
|
conversation: string;
|
|
12
13
|
agent: {
|
|
@@ -20,6 +21,10 @@ export type ConversationEntry = {
|
|
|
20
21
|
state: ConversationState;
|
|
21
22
|
started: string | null;
|
|
22
23
|
};
|
|
24
|
+
export type ConversationAgent = {
|
|
25
|
+
identity: string;
|
|
26
|
+
name: string;
|
|
27
|
+
};
|
|
23
28
|
export type RunningTurn = {
|
|
24
29
|
turn: string;
|
|
25
30
|
started: string | null;
|
|
@@ -43,13 +48,15 @@ export type ConversationView = {
|
|
|
43
48
|
} | null;
|
|
44
49
|
commands: readonly ProcessCommand[];
|
|
45
50
|
options: readonly SessionOption[];
|
|
46
|
-
chatDraft: ChatDraft
|
|
51
|
+
chatDraft: (ChatDraft & {
|
|
52
|
+
readonly revision: string;
|
|
53
|
+
}) | null;
|
|
47
54
|
};
|
|
48
55
|
export type ConversationSurface = {
|
|
49
56
|
list(): Promise<readonly ConversationEntry[]>;
|
|
50
57
|
read(conversation: string, options?: ConversationOptions): Promise<ConversationView>;
|
|
51
58
|
create(input: unknown): Promise<CallResult>;
|
|
52
|
-
send(conversation: string): Promise<CallResult>;
|
|
59
|
+
send(conversation: string, operation?: string, draft?: ChatDraft): Promise<CallResult | Offline>;
|
|
53
60
|
answer(conversation: string, answer: unknown): Promise<CallResult>;
|
|
54
61
|
interrupt(conversation: string): Promise<CallResult>;
|
|
55
62
|
kill(conversation: string): Promise<CallResult>;
|
|
@@ -57,7 +64,7 @@ export type ConversationSurface = {
|
|
|
57
64
|
delete(conversation: string): Promise<CallResult>;
|
|
58
65
|
};
|
|
59
66
|
export type ChatDraftSurface = {
|
|
60
|
-
write(conversation: string, draft: ChatDraft): Promise<void>;
|
|
67
|
+
write(conversation: string, draft: ChatDraft, revision?: string): Promise<void>;
|
|
61
68
|
discard(conversation: string): Promise<void>;
|
|
62
69
|
};
|
|
63
70
|
export type ConversationDependencies = {
|
|
@@ -67,6 +74,7 @@ export type ConversationDependencies = {
|
|
|
67
74
|
durably<T>(work: (local: RuntimeStore) => Promise<T>): Promise<T>;
|
|
68
75
|
stream(): ConversationStream | undefined;
|
|
69
76
|
publish(set: ChangeSet): void;
|
|
77
|
+
online(): boolean;
|
|
70
78
|
closed(): boolean;
|
|
71
79
|
};
|
|
72
80
|
export type ConversationStore = {
|
|
@@ -75,10 +83,12 @@ export type ConversationStore = {
|
|
|
75
83
|
hydrate(held: readonly HeldConversation[], drafts: readonly ChatDraftRecord[]): void;
|
|
76
84
|
reconcile(): Promise<void>;
|
|
77
85
|
catchUp(progress: CycleProgress): Promise<void>;
|
|
86
|
+
resend(progress: CycleProgress): Promise<void>;
|
|
78
87
|
current(): boolean;
|
|
79
88
|
reconnected(): void;
|
|
80
89
|
watch(conversation: string, options: ConversationOptions, deliver: (view: ConversationView) => void): () => void;
|
|
81
90
|
watchList(deliver: (entries: readonly ConversationEntry[]) => void): () => void;
|
|
91
|
+
watchAgents(deliver: (agents: readonly ConversationAgent[]) => void): () => void;
|
|
82
92
|
changed(set: ChangeSet): void;
|
|
83
93
|
receive(event: ConversationEvent): boolean;
|
|
84
94
|
messages(): readonly SearchedMessage[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../src/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EAEjB,mBAAmB,EACnB,kBAAkB,EAElB,cAAc,EACd,aAAa,EACb,WAAW,EAEZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAyB,KAAK,SAAS,EAAsB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../src/conversation.ts"],"names":[],"mappings":"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"}
|
package/dist/conversation.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { conversationChangeSet } from './change-set.js';
|
|
2
|
+
import { runtimeError } from './failure.js';
|
|
2
3
|
import { declaredFile } from './file.js';
|
|
4
|
+
import { changeBatchIdentity, chatDraftRevision } from './identity.js';
|
|
5
|
+
import { OFFLINE } from './outcome.js';
|
|
3
6
|
const QUIET = {
|
|
4
7
|
turn: null,
|
|
5
8
|
questions: [],
|
|
@@ -152,15 +155,33 @@ function limitOf(options) {
|
|
|
152
155
|
if (limit === undefined)
|
|
153
156
|
return undefined;
|
|
154
157
|
if (!Number.isInteger(limit) || limit < 0) {
|
|
155
|
-
throw
|
|
158
|
+
throw runtimeError('invalid-limit', `conversation limit must be a non-negative integer, got ${String(limit)}`);
|
|
156
159
|
}
|
|
157
160
|
return limit;
|
|
158
161
|
}
|
|
162
|
+
function unwritten(draft) {
|
|
163
|
+
return draft.text === '' && draft.files.length === 0;
|
|
164
|
+
}
|
|
165
|
+
function pending(draft) {
|
|
166
|
+
return draft.submitted === undefined ? {} : { submitted: draft.submitted };
|
|
167
|
+
}
|
|
168
|
+
function withSubmitted(draft, submitted) {
|
|
169
|
+
const { submitted: _held, ...unsent } = draft;
|
|
170
|
+
return submitted.length === 0 ? unsent : { ...unsent, submitted };
|
|
171
|
+
}
|
|
172
|
+
function returned(draft, submission, others) {
|
|
173
|
+
return withSubmitted({
|
|
174
|
+
conversation: draft.conversation,
|
|
175
|
+
text: [submission.text, draft.text].filter((one) => one !== '').join('\n'),
|
|
176
|
+
files: [...submission.files, ...draft.files],
|
|
177
|
+
revision: chatDraftRevision(),
|
|
178
|
+
}, others);
|
|
179
|
+
}
|
|
159
180
|
export function createConversationStore(deps) {
|
|
160
181
|
const messages = new Map();
|
|
161
182
|
const reads = new Map();
|
|
162
183
|
const drafts = new Map();
|
|
163
|
-
const sending = new
|
|
184
|
+
const sending = new Set();
|
|
164
185
|
const behind = new Set();
|
|
165
186
|
const gaps = new Map();
|
|
166
187
|
const lives = new Map();
|
|
@@ -168,7 +189,9 @@ export function createConversationStore(deps) {
|
|
|
168
189
|
const listing = new Map();
|
|
169
190
|
const listWatchers = new Set();
|
|
170
191
|
let listKnown = false;
|
|
192
|
+
const agentWatchers = new Set();
|
|
171
193
|
let agentNames = new Map();
|
|
194
|
+
let retiredAgents = new Set();
|
|
172
195
|
let agentsRead = null;
|
|
173
196
|
let replicated = new Set();
|
|
174
197
|
let handedReplicated;
|
|
@@ -196,9 +219,9 @@ export function createConversationStore(deps) {
|
|
|
196
219
|
process: facts.process === null ? null : { ...facts.process },
|
|
197
220
|
commands: structuredClone(facts.commands),
|
|
198
221
|
options: structuredClone(facts.options),
|
|
199
|
-
chatDraft: draft === undefined || draft
|
|
222
|
+
chatDraft: draft === undefined || unwritten(draft)
|
|
200
223
|
? null
|
|
201
|
-
: { text: draft.text, files: [...draft.files] },
|
|
224
|
+
: { text: draft.text, files: [...draft.files], revision: draft.revision },
|
|
202
225
|
};
|
|
203
226
|
}
|
|
204
227
|
function emit(conversation, messagesChanged = true) {
|
|
@@ -243,6 +266,21 @@ export function createConversationStore(deps) {
|
|
|
243
266
|
for (const watcher of listWatchers)
|
|
244
267
|
watcher(value);
|
|
245
268
|
}
|
|
269
|
+
function agents() {
|
|
270
|
+
return [...agentNames]
|
|
271
|
+
.filter(([identity]) => !retiredAgents.has(identity))
|
|
272
|
+
.map(([identity, name]) => ({ identity, name }))
|
|
273
|
+
.sort((left, right) => left.name === right.name
|
|
274
|
+
? left.identity.localeCompare(right.identity)
|
|
275
|
+
: left.name.localeCompare(right.name));
|
|
276
|
+
}
|
|
277
|
+
function emitAgents() {
|
|
278
|
+
if (deps.closed() || agentWatchers.size === 0)
|
|
279
|
+
return;
|
|
280
|
+
const value = agents();
|
|
281
|
+
for (const watcher of agentWatchers)
|
|
282
|
+
watcher(value);
|
|
283
|
+
}
|
|
246
284
|
function setLive(conversation, next) {
|
|
247
285
|
const before = stateOf(conversation);
|
|
248
286
|
const began = lives.get(conversation)?.turn?.started;
|
|
@@ -261,18 +299,27 @@ export function createConversationStore(deps) {
|
|
|
261
299
|
return;
|
|
262
300
|
const { documents } = await deps.documents(declaration.locator);
|
|
263
301
|
const names = new Map();
|
|
302
|
+
const retired = new Set();
|
|
264
303
|
for (const document of documents) {
|
|
265
304
|
if (document.type !== declaration.type)
|
|
266
305
|
continue;
|
|
267
306
|
const identity = document.fields?.[declaration.identity];
|
|
268
307
|
const name = document.fields?.[declaration.name];
|
|
269
|
-
if (typeof identity
|
|
270
|
-
|
|
308
|
+
if (typeof identity !== 'string' || typeof name !== 'string')
|
|
309
|
+
continue;
|
|
310
|
+
names.set(identity, name);
|
|
311
|
+
const ended = declaration.retired === undefined ? null : document.fields?.[declaration.retired];
|
|
312
|
+
if (ended !== undefined && ended !== null)
|
|
313
|
+
retired.add(identity);
|
|
271
314
|
}
|
|
272
|
-
|
|
315
|
+
const named = JSON.stringify([...names]) !== JSON.stringify([...agentNames]);
|
|
316
|
+
if (!named && JSON.stringify([...retired]) === JSON.stringify([...retiredAgents]))
|
|
273
317
|
return;
|
|
274
318
|
agentNames = names;
|
|
275
|
-
|
|
319
|
+
retiredAgents = retired;
|
|
320
|
+
if (named)
|
|
321
|
+
emitList();
|
|
322
|
+
emitAgents();
|
|
276
323
|
}
|
|
277
324
|
function agentsReady() {
|
|
278
325
|
agentsRead ??= readAgents().catch(() => {
|
|
@@ -342,18 +389,15 @@ export function createConversationStore(deps) {
|
|
|
342
389
|
const advances = read !== undefined &&
|
|
343
390
|
!behind.has(conversation) &&
|
|
344
391
|
(read === null || message.position > read);
|
|
345
|
-
|
|
392
|
+
await sealed(local, conversation, new Set([message.turn]));
|
|
346
393
|
await local.keepMessages({
|
|
347
394
|
conversation,
|
|
348
395
|
messages: [message],
|
|
349
396
|
...(advances ? { read: message.position } : {}),
|
|
350
|
-
sealed,
|
|
351
397
|
});
|
|
352
398
|
messages.set(conversation, merged(messages.get(conversation) ?? [], [message]));
|
|
353
399
|
if (advances)
|
|
354
400
|
reads.set(conversation, message.position);
|
|
355
|
-
if (sealed)
|
|
356
|
-
drafts.delete(conversation);
|
|
357
401
|
sealTurns(conversation, new Set([message.turn]));
|
|
358
402
|
deps.publish(conversationChangeSet([{ conversation, identity: message.identity }], [conversation]));
|
|
359
403
|
});
|
|
@@ -405,17 +449,14 @@ export function createConversationStore(deps) {
|
|
|
405
449
|
if (!replicated.has(conversation))
|
|
406
450
|
return;
|
|
407
451
|
const newest = arriving.reduce((top, message) => (top === null || message.position > top ? message.position : top), from ?? null);
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
await local.keepMessages({ conversation, messages: arriving, read: newest, sealed });
|
|
452
|
+
const sealing = await sealed(local, conversation, new Set(arriving.map((message) => message.turn)));
|
|
453
|
+
await local.keepMessages({ conversation, messages: arriving, read: newest });
|
|
411
454
|
messages.set(conversation, merged(messages.get(conversation) ?? [], arriving));
|
|
412
455
|
reads.set(conversation, newest);
|
|
413
|
-
if (sealed)
|
|
414
|
-
drafts.delete(conversation);
|
|
415
456
|
sealTurns(conversation, new Set(arriving.map((message) => message.turn)));
|
|
416
457
|
if ((gaps.get(conversation) ?? 0) === generation)
|
|
417
458
|
behind.delete(conversation);
|
|
418
|
-
if (arriving.length > 0 ||
|
|
459
|
+
if (arriving.length > 0 || sealing) {
|
|
419
460
|
deps.publish(conversationChangeSet(arriving.map((message) => ({ conversation, identity: message.identity })), [conversation]));
|
|
420
461
|
}
|
|
421
462
|
});
|
|
@@ -462,22 +503,89 @@ export function createConversationStore(deps) {
|
|
|
462
503
|
if (sealTurns(conversation, new Set([arriving.turn])))
|
|
463
504
|
emit(conversation);
|
|
464
505
|
}
|
|
506
|
+
async function kept(local, conversation, following) {
|
|
507
|
+
if (following === null || (unwritten(following) && following.submitted === undefined)) {
|
|
508
|
+
await local.dropChatDraft(conversation);
|
|
509
|
+
drafts.delete(conversation);
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
await local.keepChatDraft(following);
|
|
513
|
+
drafts.set(conversation, following);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
async function sealed(local, conversation, turns) {
|
|
517
|
+
const held = drafts.get(conversation);
|
|
518
|
+
const submitted = held?.submitted ?? [];
|
|
519
|
+
const left = submitted.filter((one) => one.turn === null || !turns.has(one.turn));
|
|
520
|
+
if (held === undefined || left.length === submitted.length)
|
|
521
|
+
return false;
|
|
522
|
+
await kept(local, conversation, withSubmitted(held, left));
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
465
525
|
function withDraft(conversation, next) {
|
|
466
526
|
return deps.durably(async (local) => {
|
|
467
527
|
const following = next(drafts.get(conversation));
|
|
468
528
|
if (following === undefined)
|
|
469
529
|
return;
|
|
470
|
-
|
|
471
|
-
await local.dropChatDraft(conversation);
|
|
472
|
-
drafts.delete(conversation);
|
|
473
|
-
}
|
|
474
|
-
else {
|
|
475
|
-
await local.keepChatDraft(following);
|
|
476
|
-
drafts.set(conversation, following);
|
|
477
|
-
}
|
|
530
|
+
await kept(local, conversation, following);
|
|
478
531
|
deps.publish(conversationChangeSet([], [conversation]));
|
|
479
532
|
});
|
|
480
533
|
}
|
|
534
|
+
async function submitted(conversation, operation, draft) {
|
|
535
|
+
let submission;
|
|
536
|
+
await withDraft(conversation, (current) => {
|
|
537
|
+
submission = current?.submitted?.find((one) => one.operation === operation);
|
|
538
|
+
if (submission !== undefined)
|
|
539
|
+
return undefined;
|
|
540
|
+
const said = draft ?? current;
|
|
541
|
+
submission = {
|
|
542
|
+
operation,
|
|
543
|
+
text: said?.text ?? '',
|
|
544
|
+
files: [...(said?.files ?? [])],
|
|
545
|
+
turn: null,
|
|
546
|
+
};
|
|
547
|
+
return {
|
|
548
|
+
conversation,
|
|
549
|
+
...(draft === undefined || current === undefined
|
|
550
|
+
? { text: '', files: [], revision: chatDraftRevision() }
|
|
551
|
+
: { text: current.text, files: current.files, revision: current.revision }),
|
|
552
|
+
submitted: [...(current?.submitted ?? []), submission],
|
|
553
|
+
};
|
|
554
|
+
});
|
|
555
|
+
return submission;
|
|
556
|
+
}
|
|
557
|
+
async function dispatched(conversation, submission) {
|
|
558
|
+
sending.add(submission.operation);
|
|
559
|
+
try {
|
|
560
|
+
const files = await Promise.all(submission.files.map(async (file) => ({ ...(await declaredFile(file)), blob: file.blob })));
|
|
561
|
+
const result = await invoke('conversation.send', conversation, {
|
|
562
|
+
text: submission.text,
|
|
563
|
+
files,
|
|
564
|
+
operation_id: submission.operation,
|
|
565
|
+
});
|
|
566
|
+
if (result.kind === 'revoked-authorization')
|
|
567
|
+
return result;
|
|
568
|
+
if (result.kind !== 'action' && result.retryable)
|
|
569
|
+
return result;
|
|
570
|
+
const turn = turnOf(result);
|
|
571
|
+
await withDraft(conversation, (current) => {
|
|
572
|
+
const held = current?.submitted?.find((one) => one.operation === submission.operation);
|
|
573
|
+
if (current === undefined || held === undefined || held.turn !== null)
|
|
574
|
+
return undefined;
|
|
575
|
+
const others = current.submitted.filter((one) => one !== held);
|
|
576
|
+
if (result.kind !== 'action')
|
|
577
|
+
return returned(current, held, others);
|
|
578
|
+
const arrived = (messages.get(conversation) ?? []).some((message) => message.turn === turn);
|
|
579
|
+
return withSubmitted(current, turn === null || arrived
|
|
580
|
+
? others
|
|
581
|
+
: current.submitted.map((one) => (one === held ? { ...held, turn } : one)));
|
|
582
|
+
});
|
|
583
|
+
return result;
|
|
584
|
+
}
|
|
585
|
+
finally {
|
|
586
|
+
sending.delete(submission.operation);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
481
589
|
function invoke(name, conversation, extra = {}) {
|
|
482
590
|
return deps.call(name, { conversation, ...extra });
|
|
483
591
|
}
|
|
@@ -493,41 +601,16 @@ export function createConversationStore(deps) {
|
|
|
493
601
|
create(input) {
|
|
494
602
|
return deps.call('conversation.create', input);
|
|
495
603
|
},
|
|
496
|
-
async send(conversation) {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
if (pending !== undefined) {
|
|
500
|
-
sending.set(conversation, pending);
|
|
501
|
-
deps.publish(conversationChangeSet([], [conversation]));
|
|
604
|
+
async send(conversation, operation = changeBatchIdentity(), draft) {
|
|
605
|
+
if (deps.online()) {
|
|
606
|
+
return dispatched(conversation, await submitted(conversation, operation, draft));
|
|
502
607
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
})));
|
|
508
|
-
const result = await invoke('conversation.send', conversation, {
|
|
509
|
-
text: draft?.text ?? '',
|
|
510
|
-
files,
|
|
511
|
-
});
|
|
512
|
-
const turn = turnOf(result);
|
|
513
|
-
if (turn === null || draft === undefined)
|
|
514
|
-
return result;
|
|
515
|
-
await withDraft(conversation, (current) => {
|
|
516
|
-
if (current !== draft)
|
|
517
|
-
return undefined;
|
|
518
|
-
const sealed = (messages.get(conversation) ?? []).some((message) => message.turn === turn);
|
|
519
|
-
return sealed ? null : { ...draft, turn };
|
|
520
|
-
});
|
|
521
|
-
return result;
|
|
522
|
-
}
|
|
523
|
-
finally {
|
|
524
|
-
if (pending !== undefined && sending.get(conversation) === pending) {
|
|
525
|
-
sending.delete(conversation);
|
|
526
|
-
if (drafts.get(conversation) === draft) {
|
|
527
|
-
deps.publish(conversationChangeSet([], [conversation]));
|
|
528
|
-
}
|
|
529
|
-
}
|
|
608
|
+
if (draft !== undefined) {
|
|
609
|
+
await withDraft(conversation, (current) => current?.submitted?.some((one) => one.operation === operation) === true
|
|
610
|
+
? undefined
|
|
611
|
+
: returned(current ?? { conversation, text: '', files: [], revision: '' }, { operation, ...draft, turn: null }, current?.submitted ?? []));
|
|
530
612
|
}
|
|
613
|
+
return OFFLINE;
|
|
531
614
|
},
|
|
532
615
|
answer(conversation, answer) {
|
|
533
616
|
return invoke('conversation.answer', conversation, { answer });
|
|
@@ -542,7 +625,12 @@ export function createConversationStore(deps) {
|
|
|
542
625
|
const result = await invoke('conversation.cancel', conversation, { turn });
|
|
543
626
|
if (result.kind !== 'action')
|
|
544
627
|
return result;
|
|
545
|
-
await withDraft(conversation, (current) =>
|
|
628
|
+
await withDraft(conversation, (current) => {
|
|
629
|
+
const held = current?.submitted?.find((one) => one.turn === turn);
|
|
630
|
+
if (current === undefined || held === undefined)
|
|
631
|
+
return undefined;
|
|
632
|
+
return returned(current, held, current.submitted.filter((one) => one !== held));
|
|
633
|
+
});
|
|
546
634
|
return result;
|
|
547
635
|
},
|
|
548
636
|
delete(conversation) {
|
|
@@ -550,16 +638,25 @@ export function createConversationStore(deps) {
|
|
|
550
638
|
},
|
|
551
639
|
};
|
|
552
640
|
const chatDraft = {
|
|
553
|
-
write(conversation, draft) {
|
|
554
|
-
return withDraft(conversation, () => ({
|
|
641
|
+
write(conversation, draft, revision = chatDraftRevision()) {
|
|
642
|
+
return withDraft(conversation, (current) => ({
|
|
555
643
|
conversation,
|
|
556
644
|
text: draft.text,
|
|
557
645
|
files: [...draft.files],
|
|
558
|
-
|
|
646
|
+
revision,
|
|
647
|
+
...(current?.submitted === undefined ? {} : { submitted: current.submitted }),
|
|
559
648
|
}));
|
|
560
649
|
},
|
|
561
650
|
discard(conversation) {
|
|
562
|
-
return withDraft(conversation, (current) =>
|
|
651
|
+
return withDraft(conversation, (current) => current === undefined
|
|
652
|
+
? undefined
|
|
653
|
+
: {
|
|
654
|
+
conversation,
|
|
655
|
+
text: '',
|
|
656
|
+
files: [],
|
|
657
|
+
revision: chatDraftRevision(),
|
|
658
|
+
...pending(current),
|
|
659
|
+
});
|
|
563
660
|
},
|
|
564
661
|
};
|
|
565
662
|
return {
|
|
@@ -605,6 +702,23 @@ export function createConversationStore(deps) {
|
|
|
605
702
|
if (behind.size > 0)
|
|
606
703
|
progress.complete = false;
|
|
607
704
|
},
|
|
705
|
+
async resend(progress) {
|
|
706
|
+
for (const [conversation, held] of [...drafts]) {
|
|
707
|
+
for (const submission of held.submitted ?? []) {
|
|
708
|
+
if (submission.turn !== null || sending.has(submission.operation))
|
|
709
|
+
continue;
|
|
710
|
+
if (deps.closed())
|
|
711
|
+
return;
|
|
712
|
+
const result = await dispatched(conversation, submission);
|
|
713
|
+
if (result.kind === 'revoked-authorization')
|
|
714
|
+
return;
|
|
715
|
+
if (result.kind === 'transport-uncertainty') {
|
|
716
|
+
progress.reachable = false;
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
},
|
|
608
722
|
current() {
|
|
609
723
|
return behind.size === 0;
|
|
610
724
|
},
|
|
@@ -650,6 +764,16 @@ export function createConversationStore(deps) {
|
|
|
650
764
|
listWatchers.delete(deliver);
|
|
651
765
|
};
|
|
652
766
|
},
|
|
767
|
+
watchAgents(deliver) {
|
|
768
|
+
agentWatchers.add(deliver);
|
|
769
|
+
void agentsReady().then(() => {
|
|
770
|
+
if (!deps.closed() && agentWatchers.has(deliver))
|
|
771
|
+
deliver(agents());
|
|
772
|
+
});
|
|
773
|
+
return () => {
|
|
774
|
+
agentWatchers.delete(deliver);
|
|
775
|
+
};
|
|
776
|
+
},
|
|
653
777
|
changed(set) {
|
|
654
778
|
for (const conversation of set.conversations)
|
|
655
779
|
emit(conversation);
|
|
@@ -697,6 +821,7 @@ export function createConversationStore(deps) {
|
|
|
697
821
|
views.clear();
|
|
698
822
|
lives.clear();
|
|
699
823
|
listWatchers.clear();
|
|
824
|
+
agentWatchers.clear();
|
|
700
825
|
},
|
|
701
826
|
};
|
|
702
827
|
}
|
package/dist/entry.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type QueryResult } from './query.js';
|
|
2
|
+
export { QueryError } from './query.js';
|
|
3
|
+
export type EntryRoom = {
|
|
4
|
+
locator: string;
|
|
5
|
+
schema: string | null;
|
|
6
|
+
documents: Readonly<Record<string, string>>;
|
|
7
|
+
};
|
|
8
|
+
export type EntryArguments = Readonly<Record<string, string>>;
|
|
9
|
+
export type EntryParameterKind = 'string' | 'integer' | 'number' | 'boolean';
|
|
10
|
+
export declare function boundQuery(template: unknown, args: EntryArguments): unknown;
|
|
11
|
+
export declare function entryParameters(template: unknown): readonly string[];
|
|
12
|
+
export declare function entryRefusal(template: unknown): string | null;
|
|
13
|
+
export type EntryScope = {
|
|
14
|
+
results(queries: Readonly<Record<string, unknown>>): Promise<Record<string, QueryResult>>;
|
|
15
|
+
};
|
|
16
|
+
export declare function entryScope(rooms: readonly EntryRoom[]): EntryScope;
|
|
17
|
+
//# sourceMappingURL=entry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AAGA,OAAO,EAML,KAAK,WAAW,EAEjB,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,WAAW,CAAC,CAAC,CAAC;CAC3F,CAAC;AAEF,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,UAAU,CAqDlE"}
|
package/dist/entry.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { attachedModel } from './attached-model.js';
|
|
2
|
+
import { collectionOf, passingDocument } from './collection.js';
|
|
3
|
+
import { NO_MODEL } from './model.js';
|
|
4
|
+
import { invalid, planOf, plain, QueryError, } from './query.js';
|
|
5
|
+
import { createReadSide } from './read-side.js';
|
|
6
|
+
import { rowsOf } from './rows.js';
|
|
7
|
+
export { QueryError } from './query.js';
|
|
8
|
+
const PARAMETER = '$param';
|
|
9
|
+
const KIND = 'as';
|
|
10
|
+
const INTEGER = /^-?(?:0|[1-9][0-9]*)$/u;
|
|
11
|
+
const NUMBER = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/u;
|
|
12
|
+
function parameterOf(value) {
|
|
13
|
+
if (!plain(value) || !Object.hasOwn(value, PARAMETER))
|
|
14
|
+
return null;
|
|
15
|
+
const { [PARAMETER]: name, [KIND]: kind = 'string', ...rest } = value;
|
|
16
|
+
if (typeof name !== 'string' || Object.keys(rest).length > 0)
|
|
17
|
+
return null;
|
|
18
|
+
if (kind !== 'string' && kind !== 'integer' && kind !== 'number' && kind !== 'boolean') {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return { name, kind };
|
|
22
|
+
}
|
|
23
|
+
function converted(text, kind, at) {
|
|
24
|
+
if (kind === 'string')
|
|
25
|
+
return text;
|
|
26
|
+
if (kind === 'boolean') {
|
|
27
|
+
if (text === 'true' || text === 'false')
|
|
28
|
+
return text === 'true';
|
|
29
|
+
return invalid(at, 'expects true or false');
|
|
30
|
+
}
|
|
31
|
+
if (!(kind === 'integer' ? INTEGER : NUMBER).test(text))
|
|
32
|
+
invalid(at, `expects ${kind === 'integer' ? 'an integer' : 'a number'}`);
|
|
33
|
+
const number = Number(text);
|
|
34
|
+
if (!Number.isFinite(number) || (kind === 'integer' && !Number.isSafeInteger(number))) {
|
|
35
|
+
invalid(at, 'is out of range');
|
|
36
|
+
}
|
|
37
|
+
return number;
|
|
38
|
+
}
|
|
39
|
+
function bound(template, args, at) {
|
|
40
|
+
const parameter = parameterOf(template);
|
|
41
|
+
if (parameter !== null) {
|
|
42
|
+
const text = args[parameter.name];
|
|
43
|
+
if (text === undefined || !Object.hasOwn(args, parameter.name)) {
|
|
44
|
+
invalid(at, `names the parameter ${parameter.name}, which the route lacks`);
|
|
45
|
+
}
|
|
46
|
+
return converted(text, parameter.kind, at);
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(template)) {
|
|
49
|
+
return template.map((item, index) => bound(item, args, `${at}[${index}]`));
|
|
50
|
+
}
|
|
51
|
+
if (plain(template)) {
|
|
52
|
+
return Object.fromEntries(Object.entries(template).map(([name, value]) => [
|
|
53
|
+
name,
|
|
54
|
+
bound(value, args, at === '' ? name : `${at}.${name}`),
|
|
55
|
+
]));
|
|
56
|
+
}
|
|
57
|
+
return template;
|
|
58
|
+
}
|
|
59
|
+
export function boundQuery(template, args) {
|
|
60
|
+
return bound(template, args, '');
|
|
61
|
+
}
|
|
62
|
+
export function entryParameters(template) {
|
|
63
|
+
const parameter = parameterOf(template);
|
|
64
|
+
if (parameter !== null)
|
|
65
|
+
return [parameter.name];
|
|
66
|
+
if (Array.isArray(template))
|
|
67
|
+
return [...new Set(template.flatMap(entryParameters))];
|
|
68
|
+
if (plain(template))
|
|
69
|
+
return [...new Set(Object.values(template).flatMap(entryParameters))];
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
const SAMPLED = {
|
|
73
|
+
direction: 'asc',
|
|
74
|
+
nulls: 'last',
|
|
75
|
+
stringSort: 'lexical',
|
|
76
|
+
locale: 'en',
|
|
77
|
+
limit: 0,
|
|
78
|
+
pathPrefix: 'entry',
|
|
79
|
+
field: '/entry',
|
|
80
|
+
fields: '/entry',
|
|
81
|
+
types: 'any',
|
|
82
|
+
$in: 'entry',
|
|
83
|
+
$nin: 'entry',
|
|
84
|
+
$all: 'entry',
|
|
85
|
+
$size: 0,
|
|
86
|
+
$exists: true,
|
|
87
|
+
$gt: 0,
|
|
88
|
+
$gte: 0,
|
|
89
|
+
$lt: 0,
|
|
90
|
+
$lte: 0,
|
|
91
|
+
};
|
|
92
|
+
function sampled(template, key) {
|
|
93
|
+
if (parameterOf(template) !== null)
|
|
94
|
+
return Object.hasOwn(SAMPLED, key) ? SAMPLED[key] : null;
|
|
95
|
+
if (Array.isArray(template))
|
|
96
|
+
return template.map((item) => sampled(item, key));
|
|
97
|
+
if (plain(template)) {
|
|
98
|
+
return Object.fromEntries(Object.entries(template).map(([name, value]) => [name, sampled(value, name)]));
|
|
99
|
+
}
|
|
100
|
+
return template;
|
|
101
|
+
}
|
|
102
|
+
export function entryRefusal(template) {
|
|
103
|
+
try {
|
|
104
|
+
planOf(sampled(template, ''), { listed: false, rooms: [] });
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (error instanceof QueryError)
|
|
109
|
+
return error.message;
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export function entryScope(rooms) {
|
|
114
|
+
const readSide = createReadSide();
|
|
115
|
+
const held = [];
|
|
116
|
+
const documents = rooms.flatMap((room) => {
|
|
117
|
+
const model = attachedModel({
|
|
118
|
+
kind: 'model',
|
|
119
|
+
snapshot: { identity: room.locator, version: '', schema: room.schema, revision: null },
|
|
120
|
+
}, NO_MODEL).state;
|
|
121
|
+
held.push({
|
|
122
|
+
locator: room.locator,
|
|
123
|
+
available: model.status !== 'unavailable',
|
|
124
|
+
types: model.status === 'unavailable' ? [] : Object.values(model.types),
|
|
125
|
+
});
|
|
126
|
+
const composition = { model, selection: null };
|
|
127
|
+
const collection = collectionOf(room.documents, composition);
|
|
128
|
+
return Object.keys(room.documents)
|
|
129
|
+
.sort()
|
|
130
|
+
.map((path) => ({
|
|
131
|
+
locator: room.locator,
|
|
132
|
+
path,
|
|
133
|
+
before: [],
|
|
134
|
+
after: rowsOf(room.locator, path, passingDocument(collection, path) ?? null, composition, null, null),
|
|
135
|
+
}));
|
|
136
|
+
});
|
|
137
|
+
readSide.apply({
|
|
138
|
+
documents,
|
|
139
|
+
drafts: [],
|
|
140
|
+
rooms: [],
|
|
141
|
+
queues: [],
|
|
142
|
+
presentations: [],
|
|
143
|
+
messages: [],
|
|
144
|
+
conversations: [],
|
|
145
|
+
});
|
|
146
|
+
const planned = { listed: true, rooms: held };
|
|
147
|
+
return {
|
|
148
|
+
async results(queries) {
|
|
149
|
+
const results = {};
|
|
150
|
+
for (const [name, query] of Object.entries(queries)) {
|
|
151
|
+
results[name] = await readSide.query(planOf(query, planned));
|
|
152
|
+
}
|
|
153
|
+
return results;
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|