@adecore/agents 0.20.0 → 0.21.0
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/dist/chat/attachment-store.d.ts +2 -0
- package/dist/chat/attachment-store.js +38 -2
- package/dist/chat/backend.d.ts +13 -1
- package/dist/chat/chat-core.d.ts +53 -1
- package/dist/chat/chat-core.js +53 -10
- package/dist/chat/chat-session.d.ts +29 -2
- package/dist/chat/chat-session.js +258 -15
- package/dist/chat/claude-backend.d.ts +4 -0
- package/dist/chat/claude-backend.js +39 -0
- package/dist/chat/claude-protocol.d.ts +2 -0
- package/dist/chat/claude-protocol.js +12 -1
- package/dist/chat/codex-backend.d.ts +4 -0
- package/dist/chat/codex-backend.js +77 -5
- package/dist/chat/codex-protocol.d.ts +1 -0
- package/dist/chat/codex-protocol.js +74 -5
- package/dist/chat/delta-coalescer.js +1 -1
- package/dist/chat/errors.d.ts +1 -1
- package/dist/chat/fake-codex.js +33 -0
- package/dist/chat/generated-image.d.ts +6 -0
- package/dist/chat/generated-image.js +74 -0
- package/dist/chat/projector.js +9 -2
- package/dist/chat/thread.js +6 -0
- package/dist/chat/ui-queries.d.ts +38 -0
- package/dist/chat/ui-queries.js +311 -0
- package/dist/host/handlers.js +4 -1
- package/package.json +5 -4
- package/src/chat/attachment-store.ts +38 -2
- package/src/chat/backend.ts +16 -2
- package/src/chat/chat-core.ts +60 -9
- package/src/chat/chat-session.ts +294 -16
- package/src/chat/claude-backend.ts +40 -0
- package/src/chat/claude-protocol.ts +16 -1
- package/src/chat/codex-backend.ts +77 -5
- package/src/chat/codex-protocol.ts +78 -6
- package/src/chat/delta-coalescer.ts +1 -1
- package/src/chat/errors.ts +2 -0
- package/src/chat/fake-codex.ts +34 -0
- package/src/chat/generated-image.ts +88 -0
- package/src/chat/projector.ts +9 -2
- package/src/chat/thread.ts +6 -0
- package/src/chat/ui-queries.ts +360 -0
- package/src/host/handlers.ts +9 -1
|
@@ -4,6 +4,8 @@ export declare class AttachmentStore {
|
|
|
4
4
|
readonly dir: string;
|
|
5
5
|
constructor(home: string);
|
|
6
6
|
save(chatId: string, upload: ChatAttachmentUpload): Promise<ChatAttachment>;
|
|
7
|
+
saveGenerated(chatId: string, ref: string, upload: ChatAttachmentUpload): Promise<ChatAttachment>;
|
|
8
|
+
copy(chatId: string, attachment: ChatAttachment): Promise<ChatAttachment>;
|
|
7
9
|
removeAll(chatId: string): Promise<void>;
|
|
8
10
|
folderOf(chatId: string): string;
|
|
9
11
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { randomBytes } from 'node:crypto';
|
|
2
|
-
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { link, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { extname, join } from 'node:path';
|
|
4
4
|
import { attachmentImageMime } from '@adecore/agent-contracts';
|
|
5
5
|
// The extension the file gets on disk when its name does not carry a usable one.
|
|
@@ -50,6 +50,42 @@ export class AttachmentStore {
|
|
|
50
50
|
await writeFile(path, bytes, { mode: 0o600 });
|
|
51
51
|
return { id, name: upload.name, mime, size: bytes.byteLength, path };
|
|
52
52
|
}
|
|
53
|
+
async saveGenerated(chatId, ref, upload) {
|
|
54
|
+
const id = createHash('sha256').update(`codex-image:${ref}`).digest('hex');
|
|
55
|
+
const bytes = Buffer.from(upload.data, 'base64');
|
|
56
|
+
const folder = this.folderOf(chatId);
|
|
57
|
+
await mkdir(folder, { recursive: true, mode: 0o700 });
|
|
58
|
+
const path = join(folder, `${id}.${extensionFor('', upload.mime)}`);
|
|
59
|
+
const temporary = join(folder, `.${id}-${randomBytes(8).toString('hex')}.tmp`);
|
|
60
|
+
try {
|
|
61
|
+
await writeFile(temporary, bytes, { mode: 0o600, flag: 'wx' });
|
|
62
|
+
try {
|
|
63
|
+
// Publish complete bytes without replacing an image another replay has already saved.
|
|
64
|
+
await link(temporary, path);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error.code !== 'EEXIST') {
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
const previous = await readFile(path);
|
|
71
|
+
if (!previous.equals(bytes)) {
|
|
72
|
+
throw new Error('The generated image id already belongs to another image');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
await rm(temporary, { force: true });
|
|
78
|
+
}
|
|
79
|
+
return { id, name: upload.name, mime: upload.mime, size: bytes.byteLength, path };
|
|
80
|
+
}
|
|
81
|
+
async copy(chatId, attachment) {
|
|
82
|
+
const bytes = await readFile(attachment.path);
|
|
83
|
+
const folder = this.folderOf(chatId);
|
|
84
|
+
await mkdir(folder, { recursive: true, mode: 0o700 });
|
|
85
|
+
const path = join(folder, `${createHash('sha256').update(attachment.id).digest('hex')}.${extensionFor(attachment.name, attachment.mime)}`);
|
|
86
|
+
await writeFile(path, bytes, { mode: 0o600 });
|
|
87
|
+
return { ...attachment, path };
|
|
88
|
+
}
|
|
53
89
|
/* Everything a chat attached; used when the chat itself is deleted. */
|
|
54
90
|
async removeAll(chatId) {
|
|
55
91
|
await rm(this.folderOf(chatId), { recursive: true, force: true });
|
package/dist/chat/backend.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChatAttachment, ChatFileChange, ChatQuestion, ChatSkill, ChatSubagentUsage, ChatTurnLimit, ChatWorkflow, ModelSelection, RuntimeMode } from '@adecore/agent-contracts';
|
|
1
|
+
import type { ChatAttachment, ChatAttachmentUpload, ChatFileChange, ChatQuestion, ChatSkill, ChatSubagentUsage, ChatTurnLimit, ChatWorkflow, ModelSelection, RuntimeMode } from '@adecore/agent-contracts';
|
|
2
2
|
import type { LimitsUpdate } from '../usage/limits/normalize.ts';
|
|
3
3
|
import type { SpawnChatProcess } from './chat-process.ts';
|
|
4
4
|
export interface BackendLaunch {
|
|
@@ -14,6 +14,7 @@ export interface BackendLaunch {
|
|
|
14
14
|
resumeNote: string | null;
|
|
15
15
|
folders?: readonly string[];
|
|
16
16
|
spawn?: SpawnChatProcess;
|
|
17
|
+
saveGeneratedImage?(ref: string, upload: ChatAttachmentUpload): Promise<ChatAttachment>;
|
|
17
18
|
}
|
|
18
19
|
export interface TurnInput {
|
|
19
20
|
promptId?: string;
|
|
@@ -47,11 +48,21 @@ export type BackendEvent = {
|
|
|
47
48
|
type: 'text.delta';
|
|
48
49
|
ref: string;
|
|
49
50
|
text: string;
|
|
51
|
+
phase?: string;
|
|
50
52
|
} | {
|
|
51
53
|
type: 'text.done';
|
|
52
54
|
ref: string;
|
|
53
55
|
text: string;
|
|
54
56
|
parentRef?: string | null;
|
|
57
|
+
phase?: string;
|
|
58
|
+
} | {
|
|
59
|
+
type: 'image.generated';
|
|
60
|
+
ref: string;
|
|
61
|
+
upload: ChatAttachmentUpload;
|
|
62
|
+
width?: number;
|
|
63
|
+
height?: number;
|
|
64
|
+
revisedPrompt?: string;
|
|
65
|
+
transparentBackground?: boolean;
|
|
55
66
|
} | {
|
|
56
67
|
type: 'thinking.delta';
|
|
57
68
|
ref: string;
|
|
@@ -194,6 +205,7 @@ export interface ChatBackend {
|
|
|
194
205
|
readonly pid: number | null;
|
|
195
206
|
start(): Promise<void>;
|
|
196
207
|
sendTurn(input: TurnInput): void;
|
|
208
|
+
steerTurn?(input: TurnInput): Promise<boolean>;
|
|
197
209
|
compact(): void;
|
|
198
210
|
interrupt(): void;
|
|
199
211
|
respondApproval(requestId: string, decision: ApprovalDecision, message?: string): boolean;
|
package/dist/chat/chat-core.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type AgentKind, type ChatAttachment, type ChatAttachResult, type ChatAttachmentUpload, type ChatBookmark, type ChatCheckpointDiff, type ChatConfigurePayload, type ChatCreatePayload, type ChatEvent, type ChatHistoryResult, type ChatInfo, type ChatItem, type ChatQueuedMessage, type ChatSkill, type ChatSubagentPayload, type ChatSubagentResult, type ChatTurnItem, type ChatVisual, type ModelSelection, type RuntimeMode } from '@adecore/agent-contracts';
|
|
1
|
+
import { type AgentKind, type ChatAttachment, type ChatAttachResult, type ChatAttachmentUpload, type ChatBookmark, type ChatCheckpointDiff, type ChatConfigurePayload, type ChatCreatePayload, type ChatEvent, type ChatHistoryResult, type ChatInfo, type ChatItem, type ChatQueuedMessage, type ChatUiChoicePayload, type ChatUiQueryPayload, type ChatUiLinkPayload, type ChatSkill, type ChatSubagentPayload, type ChatSubagentResult, type ChatTurnItem, type ChatVisual, type ModelSelection, type RuntimeMode } from '@adecore/agent-contracts';
|
|
2
|
+
import { type ChatUiHost } from './ui-queries.ts';
|
|
2
3
|
import { ClientSinks } from '../client-sinks.ts';
|
|
3
4
|
import type { AgentEvent, AgentSink } from '../events.ts';
|
|
4
5
|
import type { OutboxOutcome } from '../outbox/outbox-worker.ts';
|
|
@@ -25,6 +26,7 @@ export interface InterruptedRun {
|
|
|
25
26
|
attempt: number;
|
|
26
27
|
}
|
|
27
28
|
export interface ChatCoreOptions {
|
|
29
|
+
intelligentUi?: ChatUiHost;
|
|
28
30
|
providers: ProviderRegistry;
|
|
29
31
|
store?: ChatStore;
|
|
30
32
|
checkpoints?: TurnCheckpoints;
|
|
@@ -95,8 +97,21 @@ export declare class ChatCore {
|
|
|
95
97
|
mime: string;
|
|
96
98
|
size: number;
|
|
97
99
|
path: string;
|
|
100
|
+
width?: number | undefined;
|
|
101
|
+
height?: number | undefined;
|
|
98
102
|
}[] | undefined;
|
|
99
103
|
createdAt: number;
|
|
104
|
+
uiChoice?: {
|
|
105
|
+
itemId: string;
|
|
106
|
+
blockId: string;
|
|
107
|
+
revision: string;
|
|
108
|
+
choiceId: string;
|
|
109
|
+
label: string;
|
|
110
|
+
sourceAt: number;
|
|
111
|
+
older: boolean;
|
|
112
|
+
values?: Record<string, unknown> | undefined;
|
|
113
|
+
at: number;
|
|
114
|
+
} | undefined;
|
|
100
115
|
}[] | undefined;
|
|
101
116
|
queuePaused?: boolean | undefined;
|
|
102
117
|
background?: {
|
|
@@ -174,6 +189,7 @@ export declare class ChatCore {
|
|
|
174
189
|
protected readonly subagents: SubagentReader;
|
|
175
190
|
readonly claudeProjectsDir: string;
|
|
176
191
|
readonly composerPreferences: ComposerPreferences;
|
|
192
|
+
private readonly uiQueries;
|
|
177
193
|
private readonly checkpoints;
|
|
178
194
|
private readonly instructions;
|
|
179
195
|
private readonly skillIndex;
|
|
@@ -251,6 +267,42 @@ export declare class ChatCore {
|
|
|
251
267
|
queued: boolean;
|
|
252
268
|
turnId: string;
|
|
253
269
|
}>;
|
|
270
|
+
linkUi(payload: ChatUiLinkPayload, clientId: string): Promise<{
|
|
271
|
+
state: "chip" | "plain";
|
|
272
|
+
target?: {
|
|
273
|
+
type: "File";
|
|
274
|
+
path: string;
|
|
275
|
+
line?: number | undefined;
|
|
276
|
+
} | {
|
|
277
|
+
type: "Diff";
|
|
278
|
+
path: string;
|
|
279
|
+
} | {
|
|
280
|
+
type: "Commit";
|
|
281
|
+
sha: string;
|
|
282
|
+
} | {
|
|
283
|
+
type: "Node";
|
|
284
|
+
id: string;
|
|
285
|
+
} | undefined;
|
|
286
|
+
cwd?: string | undefined;
|
|
287
|
+
viewId?: string | undefined;
|
|
288
|
+
projectId?: string | undefined;
|
|
289
|
+
staged?: boolean | undefined;
|
|
290
|
+
conflicted?: boolean | undefined;
|
|
291
|
+
relativePath?: string | undefined;
|
|
292
|
+
label?: string | undefined;
|
|
293
|
+
reason?: string | undefined;
|
|
294
|
+
}>;
|
|
295
|
+
queryUi(payload: ChatUiQueryPayload, clientId: string): Promise<{
|
|
296
|
+
state: "failed" | "fresh" | "refused";
|
|
297
|
+
value?: unknown;
|
|
298
|
+
readId?: string | undefined;
|
|
299
|
+
readAt: number;
|
|
300
|
+
reason?: string | undefined;
|
|
301
|
+
}>;
|
|
302
|
+
choose(payload: ChatUiChoicePayload): Promise<{
|
|
303
|
+
queued: boolean;
|
|
304
|
+
turnId: string;
|
|
305
|
+
}>;
|
|
254
306
|
attachment(chatId: string, id: string): ChatAttachment | null;
|
|
255
307
|
unqueue(chatId: string, messageId: string): ChatQueuedMessage;
|
|
256
308
|
sendNow(chatId: string, messageId: string): void;
|
package/dist/chat/chat-core.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { homedir } from 'node:os';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import { ChatAttachmentUploadsSchema } from '@adecore/agent-contracts';
|
|
3
|
+
import { ChatAttachmentUploadsSchema, generatedImageAttachment } from '@adecore/agent-contracts';
|
|
4
|
+
import { ChatUiQueries } from './ui-queries.js';
|
|
4
5
|
import { ClientSinks } from '../client-sinks.js';
|
|
5
6
|
import { errorText } from '../error-text.js';
|
|
6
7
|
import { AccountError, definedEnv, isDefaultAccountOf, launchEnv, storedAccount } from '../providers/accounts/launch.js';
|
|
@@ -59,6 +60,7 @@ export class ChatCore {
|
|
|
59
60
|
/* Where Claude Code keeps the projects of its default account on this machine; empty when it has none. */
|
|
60
61
|
claudeProjectsDir;
|
|
61
62
|
composerPreferences = new ComposerPreferences();
|
|
63
|
+
uiQueries;
|
|
62
64
|
checkpoints;
|
|
63
65
|
instructions;
|
|
64
66
|
skillIndex;
|
|
@@ -84,6 +86,7 @@ export class ChatCore {
|
|
|
84
86
|
onInterruptedRun;
|
|
85
87
|
limitResume;
|
|
86
88
|
constructor(options) {
|
|
89
|
+
this.uiQueries = options.intelligentUi ? new ChatUiQueries(options.intelligentUi) : null;
|
|
87
90
|
this.providers = options.providers;
|
|
88
91
|
this.store = options.store ?? null;
|
|
89
92
|
this.bookmarks = options.bookmarks ?? null;
|
|
@@ -269,6 +272,7 @@ export class ChatCore {
|
|
|
269
272
|
const references = this.referencesFor(payload.chatId);
|
|
270
273
|
const session = new ChatSession({
|
|
271
274
|
info,
|
|
275
|
+
...(this.uiQueries ? { ui: { schemas: this.uiQueries.schemas, observe: (item, final) => this.uiQueries.observe(session, item, final) } } : {}),
|
|
272
276
|
items: stored?.items ?? [],
|
|
273
277
|
preambles: stored?.preambles ?? [],
|
|
274
278
|
provider,
|
|
@@ -279,6 +283,7 @@ export class ChatCore {
|
|
|
279
283
|
this.accounts?.launched?.(kind, chatAccount);
|
|
280
284
|
return env;
|
|
281
285
|
},
|
|
286
|
+
saveGeneratedImage: (ref, upload) => this.attachments.saveGenerated(payload.chatId, ref, upload),
|
|
282
287
|
instructions: () => this.instructionsFor(payload.chatId),
|
|
283
288
|
resumeNote: () => this.resumeNoteFor(payload.chatId),
|
|
284
289
|
folders: () => this.foldersFor(payload.chatId),
|
|
@@ -362,11 +367,16 @@ export class ChatCore {
|
|
|
362
367
|
const log = this.logs.get(chatId);
|
|
363
368
|
const events = since === undefined ? null : log.after(since);
|
|
364
369
|
if (events !== null) {
|
|
365
|
-
return { info: session.info, items: [], events, seq: log.seq };
|
|
370
|
+
return { info: session.info, items: [], events: [...events, ...session.uiPreviews], seq: log.seq };
|
|
366
371
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
372
|
+
const page = historyLimit === undefined ? session.thread.snapshot() : session.thread.history(historyLimit);
|
|
373
|
+
return {
|
|
374
|
+
...page,
|
|
375
|
+
info: session.info,
|
|
376
|
+
items: session.previewItems(page.items),
|
|
377
|
+
...(historyLimit === undefined ? {} : { pending: session.previewItems(session.thread.pending()) }),
|
|
378
|
+
seq: log.seq
|
|
379
|
+
};
|
|
370
380
|
}
|
|
371
381
|
/*
|
|
372
382
|
* `attach` with the chat's bookmarks and visuals. They are read before the client joins, so a
|
|
@@ -546,7 +556,29 @@ export class ChatCore {
|
|
|
546
556
|
throw new ChatError('invalid-attachments', checked.error.issues[0].message);
|
|
547
557
|
}
|
|
548
558
|
const attachments = await Promise.all(uploads.map((upload) => this.attachments.save(chatId, upload)));
|
|
549
|
-
return session.
|
|
559
|
+
return session.sendInput(text, { ...extras, ...(attachments.length > 0 ? { attachments } : {}) });
|
|
560
|
+
}
|
|
561
|
+
async linkUi(payload, clientId) {
|
|
562
|
+
if (!this.attached.get(payload.chatId)?.has(clientId) || !this.uiQueries) {
|
|
563
|
+
throw new ChatError('refused-query', 'Attach to the chat before resolving its UI links.');
|
|
564
|
+
}
|
|
565
|
+
return this.uiQueries.link(this.require(payload.chatId), payload);
|
|
566
|
+
}
|
|
567
|
+
async queryUi(payload, clientId) {
|
|
568
|
+
if (!this.attached.get(payload.chatId)?.has(clientId)) {
|
|
569
|
+
throw new ChatError('refused-query', 'Attach to the chat before reading its UI queries.');
|
|
570
|
+
}
|
|
571
|
+
if (!this.uiQueries) {
|
|
572
|
+
throw new ChatError('refused-query', 'This host does not provide UI query sources.');
|
|
573
|
+
}
|
|
574
|
+
return this.uiQueries.query(this.require(payload.chatId), payload);
|
|
575
|
+
}
|
|
576
|
+
async choose(payload) {
|
|
577
|
+
const session = this.require(payload.chatId);
|
|
578
|
+
const queries = await this.uiQueries?.choiceValues(session, payload);
|
|
579
|
+
const result = session.choose(payload, queries);
|
|
580
|
+
await this.persisted(payload.chatId);
|
|
581
|
+
return result;
|
|
550
582
|
}
|
|
551
583
|
/* The file behind an attachment id: what this chat's thread or queue says it is, or a visual's page. */
|
|
552
584
|
attachment(chatId, id) {
|
|
@@ -555,7 +587,8 @@ export class ChatCore {
|
|
|
555
587
|
return null;
|
|
556
588
|
}
|
|
557
589
|
for (const item of session.thread.list()) {
|
|
558
|
-
const
|
|
590
|
+
const generated = generatedImageAttachment(item);
|
|
591
|
+
const found = item.kind === 'user' ? item.attachments?.find((attachment) => attachment.id === id) : generated?.id === id ? generated : null;
|
|
559
592
|
if (found) {
|
|
560
593
|
return found;
|
|
561
594
|
}
|
|
@@ -599,7 +632,7 @@ export class ChatCore {
|
|
|
599
632
|
throw new ChatError('chat-busy', `Chat ${chatId} is still working on the previous message`);
|
|
600
633
|
}
|
|
601
634
|
await this.clearing(chatId);
|
|
602
|
-
session.clear(force);
|
|
635
|
+
const ended = session.clear(force);
|
|
603
636
|
// Before the record is written, so what it takes along from the record is gone from the write as well.
|
|
604
637
|
const cleared = this.cleared(chatId);
|
|
605
638
|
// A debounced write still waiting holds the old thread and must not land after the empty one.
|
|
@@ -607,7 +640,7 @@ export class ChatCore {
|
|
|
607
640
|
// Folded right away: every line before the reset describes a thread that is gone.
|
|
608
641
|
await Promise.all([
|
|
609
642
|
this.persistNow(chatId, true),
|
|
610
|
-
this.attachments.removeAll(chatId),
|
|
643
|
+
ended.then(() => this.attachments.removeAll(chatId)),
|
|
611
644
|
this.bookmarks?.removeChat(chatId),
|
|
612
645
|
this.visuals?.removeChat(chatId),
|
|
613
646
|
cleared
|
|
@@ -646,8 +679,9 @@ export class ChatCore {
|
|
|
646
679
|
const session = this.require(chatId);
|
|
647
680
|
// A write already out would put the record back after the delete.
|
|
648
681
|
const writing = this.writes.get(chatId);
|
|
649
|
-
|
|
682
|
+
const ended = session.dispose();
|
|
650
683
|
this.subagents.releaseChat(chatId);
|
|
684
|
+
this.uiQueries?.forget(chatId);
|
|
651
685
|
this.coalescers.get(chatId)?.dispose();
|
|
652
686
|
this.coalescers.delete(chatId);
|
|
653
687
|
this.logs.get(chatId)?.close();
|
|
@@ -663,6 +697,7 @@ export class ChatCore {
|
|
|
663
697
|
const snapshot = session.thread.snapshot();
|
|
664
698
|
this.forgotten(chatId);
|
|
665
699
|
await writing;
|
|
700
|
+
await ended;
|
|
666
701
|
await Promise.all([
|
|
667
702
|
this.store?.delete(chatId),
|
|
668
703
|
this.attachments.removeAll(chatId),
|
|
@@ -955,6 +990,14 @@ export class ChatCore {
|
|
|
955
990
|
return next;
|
|
956
991
|
}
|
|
957
992
|
emit(chatId, event) {
|
|
993
|
+
if (event.type === 'delta' && event.ui !== undefined) {
|
|
994
|
+
// Previews follow all pending text but have no log position or observer side effects.
|
|
995
|
+
this.coalescers.get(chatId)?.flush();
|
|
996
|
+
for (const clientId of this.attached.get(chatId) ?? []) {
|
|
997
|
+
this.sinks.to(clientId, { event: 'chat.event', payload: { chatId, event } });
|
|
998
|
+
}
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
958
1001
|
this.activity.set(chatId, Date.now());
|
|
959
1002
|
let coalescer = this.coalescers.get(chatId);
|
|
960
1003
|
if (!coalescer) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { ChatAttachment, ChatCheckpointDiff, ChatEvent, ChatInfo, ChatItem, ChatQueuedMessage, ChatSkill, ModelSelection, RuntimeMode } from '@adecore/agent-contracts';
|
|
1
|
+
import type { ChatAttachment, ChatAssistantItem, ChatCheckpointDiff, ChatEvent, ChatInfo, ChatItem, ChatQueuedMessage, ChatSkill, ChatUiChoiceOrigin, ChatUiChoicePayload, ChatUiQueryState, ModelSelection, RuntimeMode } from '@adecore/agent-contracts';
|
|
2
|
+
import type { UiCompileOptions } from '@adecore/intelligent-ui/compiler';
|
|
2
3
|
import type { ChatProvider } from '../providers/provider.ts';
|
|
3
4
|
import type { LimitsUpdate } from '../usage/limits/normalize.ts';
|
|
5
|
+
import type { BackendLaunch } from './backend.ts';
|
|
4
6
|
import type { SpawnChatProcess } from './chat-process.ts';
|
|
5
7
|
import type { ChatTitleInput } from './chat-title.ts';
|
|
6
8
|
import type { SubagentSettlement } from './subagent-settlement.ts';
|
|
@@ -34,12 +36,17 @@ export interface ChatSessionOptions {
|
|
|
34
36
|
command: string[];
|
|
35
37
|
env(account: string | undefined): Record<string, string>;
|
|
36
38
|
spawn?: SpawnChatProcess;
|
|
39
|
+
saveGeneratedImage?: BackendLaunch['saveGeneratedImage'];
|
|
37
40
|
instructions?(): string | null;
|
|
38
41
|
resumeNote?(): string | null;
|
|
39
42
|
folders?(): readonly string[];
|
|
40
43
|
promptNotes?: PromptNotes;
|
|
41
44
|
references?: ChatReferences;
|
|
42
45
|
checkpoints?: TurnCheckpoints;
|
|
46
|
+
ui?: {
|
|
47
|
+
schemas: UiCompileOptions['querySchemas'];
|
|
48
|
+
observe(item: ChatAssistantItem, final: boolean): void;
|
|
49
|
+
};
|
|
43
50
|
emit(event: ChatEvent): void;
|
|
44
51
|
onLimits?(update: LimitsUpdate): void;
|
|
45
52
|
persist(): void;
|
|
@@ -58,6 +65,8 @@ export interface LimitResumeHooks {
|
|
|
58
65
|
owed(): boolean;
|
|
59
66
|
}
|
|
60
67
|
export interface ChatSendExtras {
|
|
68
|
+
uiChoice?: ChatUiChoiceOrigin;
|
|
69
|
+
delivery?: 'steer' | 'queue';
|
|
61
70
|
mentions?: string[];
|
|
62
71
|
skills?: string[];
|
|
63
72
|
chats?: string[];
|
|
@@ -93,7 +102,12 @@ export declare class ChatSession {
|
|
|
93
102
|
private readonly orphans;
|
|
94
103
|
private pendingPreambles;
|
|
95
104
|
private submission;
|
|
105
|
+
private readonly steering;
|
|
106
|
+
private readonly uiStreams;
|
|
107
|
+
private readonly uiCompiled;
|
|
96
108
|
constructor(options: ChatSessionOptions);
|
|
109
|
+
get uiPreviews(): ChatEvent[];
|
|
110
|
+
previewItems(items: ChatItem[]): ChatItem[];
|
|
97
111
|
get id(): string;
|
|
98
112
|
get info(): ChatInfo;
|
|
99
113
|
get running(): boolean;
|
|
@@ -110,6 +124,17 @@ export declare class ChatSession {
|
|
|
110
124
|
queued: boolean;
|
|
111
125
|
turnId: string;
|
|
112
126
|
};
|
|
127
|
+
updateUiQueries(itemId: string, uiQueries: ChatUiQueryState): void;
|
|
128
|
+
choose(payload: ChatUiChoicePayload, queries?: Readonly<Record<string, unknown>>): {
|
|
129
|
+
queued: boolean;
|
|
130
|
+
turnId: string;
|
|
131
|
+
};
|
|
132
|
+
private recordUiAnswer;
|
|
133
|
+
sendInput(text: string, extras?: ChatSendExtras): Promise<{
|
|
134
|
+
queued: boolean;
|
|
135
|
+
turnId: string;
|
|
136
|
+
}>;
|
|
137
|
+
private submitInput;
|
|
113
138
|
unqueue(messageId: string): ChatQueuedMessage | null;
|
|
114
139
|
sendNow(messageId: string): boolean;
|
|
115
140
|
private get queue();
|
|
@@ -122,7 +147,7 @@ export declare class ChatSession {
|
|
|
122
147
|
approve(requestId: string, decision: 'allow' | 'allow-always' | 'deny', message?: string): boolean;
|
|
123
148
|
answer(requestId: string, answers: Record<string, string>): boolean;
|
|
124
149
|
dismiss(itemId: string): boolean;
|
|
125
|
-
clear(force: boolean): void
|
|
150
|
+
clear(force: boolean): Promise<void>;
|
|
126
151
|
settleStored(selection: ModelSelection, resume: ResumeDecision): void;
|
|
127
152
|
resume(turnId: string, attempt: number, words: ResumeWords): Promise<void>;
|
|
128
153
|
abandon(turnId: string, reason: string | null): void;
|
|
@@ -201,6 +226,8 @@ export declare class ChatSession {
|
|
|
201
226
|
private settleFromTranscripts;
|
|
202
227
|
private settleRows;
|
|
203
228
|
private emit;
|
|
229
|
+
private latestUiAttachment;
|
|
230
|
+
private clearUi;
|
|
204
231
|
private delegatingChange;
|
|
205
232
|
}
|
|
206
233
|
export interface ResumeDecision {
|