@adecore/agents-react 0.21.1 → 0.22.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/agents/model-requirement.d.ts +6 -0
- package/dist/agents/model-requirement.js +26 -0
- package/dist/agents/status-look.js +2 -3
- package/dist/chat/chat-client.d.ts +3 -2
- package/dist/chat/chat-client.js +4 -2
- package/dist/chat/drafts.d.ts +2 -1
- package/dist/chat/drafts.js +21 -17
- package/dist/chat/logic/ansi.js +5 -1
- package/dist/chat/logic/fork.js +8 -9
- package/dist/chat/logic/limit.js +17 -14
- package/dist/chat/logic/picker-entries.d.ts +10 -0
- package/dist/chat/logic/picker-entries.js +19 -0
- package/dist/chat/logic/resume-compaction.js +2 -11
- package/dist/chat/logic/scrubber.js +9 -18
- package/dist/chat/logic/timeline.d.ts +5 -0
- package/dist/chat/logic/timeline.js +25 -11
- package/dist/chat/logic/tool-catalog.js +3 -4
- package/dist/chat/mentions.js +5 -6
- package/dist/chat/prompt-hold.d.ts +8 -0
- package/dist/chat/prompt-hold.js +16 -0
- package/dist/chat/quote.d.ts +4 -0
- package/dist/chat/quote.js +19 -0
- package/dist/chat/runtime-modes.js +2 -4
- package/dist/chat/stash.d.ts +8 -2
- package/dist/chat/stash.js +22 -8
- package/dist/chat/subagent-list.d.ts +7 -1
- package/dist/chat/subagent-list.js +13 -1
- package/dist/chat/thumbnails.js +3 -4
- package/dist/chat/timeline-scroll.d.ts +6 -2
- package/dist/chat/timeline-scroll.js +45 -46
- package/dist/chat/ui/BookmarkSubmenu.js +1 -5
- package/dist/chat/ui/ChatActivity.js +22 -8
- package/dist/chat/ui/CodeBlock.js +2 -3
- package/dist/chat/ui/Composer.js +160 -88
- package/dist/chat/ui/ComposerInput.d.ts +3 -1
- package/dist/chat/ui/ComposerInput.js +13 -4
- package/dist/chat/ui/Markdown.js +11 -11
- package/dist/chat/ui/Pickers.js +31 -27
- package/dist/chat/ui/PromptComposer.d.ts +8 -1
- package/dist/chat/ui/PromptComposer.js +18 -6
- package/dist/chat/ui/QuoteButton.js +4 -5
- package/dist/chat/ui/RunSettings.js +8 -2
- package/dist/chat/ui/Scrubber.js +2 -3
- package/dist/chat/ui/SubagentControls.d.ts +4 -2
- package/dist/chat/ui/SubagentControls.js +13 -11
- package/dist/chat/ui/SubagentInfo.d.ts +1 -1
- package/dist/chat/ui/SubagentInfo.js +9 -15
- package/dist/chat/ui/SubagentStopButton.js +2 -1
- package/dist/chat/ui/Timeline.js +39 -21
- package/dist/chat/ui/TimelineMenu.js +3 -9
- package/dist/chat/ui/UnifiedDiff.js +3 -5
- package/dist/chat/ui/VisualFrame.js +3 -4
- package/dist/chat/ui/composer/keys.js +19 -11
- package/dist/chat/ui/composer/menu-aria.d.ts +10 -0
- package/dist/chat/ui/composer/menu-aria.js +18 -0
- package/dist/chat/ui/intelligent-ui/render-context.d.ts +1 -1
- package/dist/chat/ui/quote-selection.d.ts +5 -2
- package/dist/chat/ui/quote-selection.js +3 -2
- package/dist/chat/ui/rows/MessageRows.js +26 -8
- package/dist/chat/ui/rows/Rows.js +1 -1
- package/dist/chat/ui/rows/WorkRows.d.ts +7 -4
- package/dist/chat/ui/rows/WorkRows.js +22 -17
- package/dist/chat/visual-viewport.d.ts +1 -1
- package/dist/chat/visual-viewport.js +9 -8
- package/dist/host.d.ts +1 -0
- package/dist/host.js +1 -0
- package/dist/locales/en/agent-chat.json +30 -7
- package/dist/locales/nl/agent-chat.json +30 -7
- package/dist/port-transport.js +4 -8
- package/dist/state/chats.d.ts +2 -1
- package/dist/state/chats.js +29 -15
- package/dist/state/usage.js +44 -49
- package/dist/storage.js +7 -7
- package/dist/theme.css +6 -14
- package/dist/usage/LimitsList.js +1 -2
- package/dist/usage/UsageBreakdown.js +1 -3
- package/dist/usage/UsageDialog.js +2 -4
- package/dist/usage/format.js +6 -6
- package/dist/usage/money.js +1 -5
- package/dist/usage/summary.js +2 -4
- package/package.json +24 -4
- package/src/agents/model-requirement.ts +36 -0
- package/src/agents/status-look.ts +2 -3
- package/src/chat/chat-client.ts +7 -3
- package/src/chat/drafts.ts +33 -21
- package/src/chat/logic/ansi.ts +5 -1
- package/src/chat/logic/fork.ts +8 -9
- package/src/chat/logic/limit.ts +17 -16
- package/src/chat/logic/picker-entries.ts +25 -0
- package/src/chat/logic/resume-compaction.ts +2 -11
- package/src/chat/logic/scrubber.ts +13 -17
- package/src/chat/logic/timeline.ts +39 -13
- package/src/chat/logic/tool-catalog.ts +7 -6
- package/src/chat/mentions.ts +5 -6
- package/src/chat/prompt-hold.ts +27 -0
- package/src/chat/quote.ts +20 -0
- package/src/chat/runtime-modes.ts +2 -4
- package/src/chat/stash.ts +32 -8
- package/src/chat/subagent-list.ts +19 -5
- package/src/chat/thumbnails.ts +3 -4
- package/src/chat/timeline-scroll.ts +58 -53
- package/src/chat/ui/BookmarkSubmenu.tsx +1 -5
- package/src/chat/ui/ChatActivity.tsx +35 -9
- package/src/chat/ui/CodeBlock.tsx +2 -3
- package/src/chat/ui/Composer.tsx +263 -138
- package/src/chat/ui/ComposerInput.tsx +18 -3
- package/src/chat/ui/Markdown.tsx +13 -17
- package/src/chat/ui/Pickers.tsx +56 -39
- package/src/chat/ui/PromptComposer.tsx +37 -8
- package/src/chat/ui/QuoteButton.tsx +5 -5
- package/src/chat/ui/RunSettings.tsx +9 -2
- package/src/chat/ui/Scrubber.tsx +2 -3
- package/src/chat/ui/SubagentControls.tsx +23 -22
- package/src/chat/ui/SubagentInfo.tsx +24 -42
- package/src/chat/ui/SubagentStopButton.tsx +2 -1
- package/src/chat/ui/SubagentTimeline.tsx +1 -2
- package/src/chat/ui/Timeline.tsx +44 -24
- package/src/chat/ui/TimelineMenu.tsx +3 -9
- package/src/chat/ui/UnifiedDiff.tsx +3 -5
- package/src/chat/ui/VisualFrame.tsx +3 -4
- package/src/chat/ui/composer/keys.ts +21 -11
- package/src/chat/ui/composer/menu-aria.ts +29 -0
- package/src/chat/ui/intelligent-ui/render-context.ts +2 -2
- package/src/chat/ui/quote-selection.ts +6 -4
- package/src/chat/ui/rehype-chips.ts +1 -1
- package/src/chat/ui/rehype-fade.ts +1 -1
- package/src/chat/ui/remark-html-as-text.ts +1 -1
- package/src/chat/ui/rows/MessageRows.tsx +47 -9
- package/src/chat/ui/rows/Rows.tsx +3 -1
- package/src/chat/ui/rows/WorkRows.tsx +101 -70
- package/src/chat/visual-viewport.ts +10 -8
- package/src/host.ts +4 -3
- package/src/locales/en/agent-chat.json +30 -7
- package/src/locales/nl/agent-chat.json +30 -7
- package/src/port-transport.ts +4 -8
- package/src/state/chats.ts +42 -16
- package/src/state/usage.ts +49 -60
- package/src/storage.ts +7 -7
- package/src/theme.css +6 -14
- package/src/usage/LimitsList.tsx +2 -4
- package/src/usage/UsageBreakdown.tsx +2 -5
- package/src/usage/UsageDialog.tsx +2 -4
- package/src/usage/format.ts +6 -6
- package/src/usage/money.ts +1 -5
- package/src/usage/summary.ts +2 -4
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Suspense, useEffect, useState } from 'react';
|
|
1
|
+
import { Suspense, useEffect, useState, type Dispatch, type ReactNode, type SetStateAction } from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import i18next from 'i18next';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { ChevronRight, FileDiff, X } from 'lucide-react';
|
|
6
6
|
import type { ChatCheckpointDiff, ChatCheckpointFile, ChatFileChange, ChatToolItem, ChatTurnItem } from '@adecore/agent-contracts';
|
|
7
|
+
import type { BaseMoved } from '../../logic/timeline';
|
|
7
8
|
import { fileChanges, liveOutput, readImagePath, toolStartedAt, toolSummary, unifiedChanges, type FileChange } from '../../logic/tools';
|
|
8
9
|
import { useOpenForFind } from '../find-reveal';
|
|
9
10
|
import { chatHost } from '../../../host';
|
|
@@ -40,14 +41,14 @@ export function ToggleLine({
|
|
|
40
41
|
trailing,
|
|
41
42
|
className
|
|
42
43
|
}: {
|
|
43
|
-
icon:
|
|
44
|
+
icon: ReactNode;
|
|
44
45
|
label: string;
|
|
45
46
|
detail?: string;
|
|
46
47
|
open: boolean;
|
|
47
48
|
onToggle(): void;
|
|
48
49
|
failed?: boolean;
|
|
49
50
|
live?: boolean;
|
|
50
|
-
trailing?:
|
|
51
|
+
trailing?: ReactNode;
|
|
51
52
|
className?: string;
|
|
52
53
|
}) {
|
|
53
54
|
return (
|
|
@@ -75,24 +76,60 @@ export function ToggleLine({
|
|
|
75
76
|
);
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
/* The diff renderers load lazily, so a diff waits on them under a line that says so. */
|
|
80
|
+
function DiffSuspense({ children }: { children: ReactNode }) {
|
|
79
81
|
const { t } = useTranslation('agent-chat');
|
|
82
|
+
return <Suspense fallback={<div className="px-3 py-2 text-xs text-text-faint">{t('work.loadingDiff')}</div>}>{children}</Suspense>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* A file in a changed files card, which opens its diff under it. */
|
|
86
|
+
function ChangedFileLine({
|
|
87
|
+
path,
|
|
88
|
+
open,
|
|
89
|
+
onToggle,
|
|
90
|
+
trailing,
|
|
91
|
+
children
|
|
92
|
+
}: {
|
|
93
|
+
path: string;
|
|
94
|
+
open: boolean;
|
|
95
|
+
onToggle(): void;
|
|
96
|
+
trailing: ReactNode;
|
|
97
|
+
children: ReactNode;
|
|
98
|
+
}) {
|
|
99
|
+
return (
|
|
100
|
+
<div className="border-t border-border">
|
|
101
|
+
<button
|
|
102
|
+
className="flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-text-muted hover:bg-surface-hover"
|
|
103
|
+
data-file-path={path}
|
|
104
|
+
onClick={onToggle}
|
|
105
|
+
>
|
|
106
|
+
<Icon icon={ChevronRight} size={12} className={clsx('shrink-0 text-text-faint transition-transform', open && 'rotate-90')} />
|
|
107
|
+
<span className="min-w-0 truncate font-mono text-text">{path}</span>
|
|
108
|
+
<span className="grow" />
|
|
109
|
+
{trailing}
|
|
110
|
+
</button>
|
|
111
|
+
{open && <div className="border-t border-border">{children}</div>}
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function ToolBody({ tool }: { tool: ChatToolItem }) {
|
|
80
117
|
const patches = unifiedChanges(tool);
|
|
81
118
|
const changes = patches.length > 0 ? [] : fileChanges(tool.name, tool.input);
|
|
82
119
|
return (
|
|
83
120
|
<div className="mt-1.5 mb-2 ml-6 overflow-hidden rounded-md border border-border bg-surface-raised">
|
|
84
121
|
{patches.length > 0 ? (
|
|
85
|
-
<
|
|
122
|
+
<DiffSuspense>
|
|
86
123
|
{patches.map((change, index) => (
|
|
87
124
|
<UnifiedDiff key={index} change={change} />
|
|
88
125
|
))}
|
|
89
|
-
</
|
|
126
|
+
</DiffSuspense>
|
|
90
127
|
) : changes.length > 0 ? (
|
|
91
|
-
<
|
|
128
|
+
<DiffSuspense>
|
|
92
129
|
{changes.map((change, index) => (
|
|
93
130
|
<EditDiff key={index} change={change} />
|
|
94
131
|
))}
|
|
95
|
-
</
|
|
132
|
+
</DiffSuspense>
|
|
96
133
|
) : (
|
|
97
134
|
<pre className="max-h-64 overflow-auto px-3 py-2 font-mono text-code text-text-muted select-text">
|
|
98
135
|
{clip(JSON.stringify(tool.input, null, 2) ?? '')}
|
|
@@ -113,9 +150,10 @@ function ToolBody({ tool }: { tool: ChatToolItem }) {
|
|
|
113
150
|
);
|
|
114
151
|
}
|
|
115
152
|
|
|
116
|
-
/*
|
|
117
|
-
|
|
118
|
-
|
|
153
|
+
/*
|
|
154
|
+
* One settled tool call: a line, and its input and output behind it. An image the call looked at is
|
|
155
|
+
* drawn under the line. `icon`, `label` and `failed` let a row that knows the call better name it.
|
|
156
|
+
*/
|
|
119
157
|
export function WorkRow({
|
|
120
158
|
tool,
|
|
121
159
|
nested,
|
|
@@ -127,7 +165,7 @@ export function WorkRow({
|
|
|
127
165
|
tool: ChatToolItem;
|
|
128
166
|
nested?: boolean;
|
|
129
167
|
detail?: string;
|
|
130
|
-
icon?:
|
|
168
|
+
icon?: ReactNode;
|
|
131
169
|
label?: string;
|
|
132
170
|
failed?: boolean;
|
|
133
171
|
}) {
|
|
@@ -235,14 +273,13 @@ function omittedLabel(reason: 'binary' | 'too-large'): string {
|
|
|
235
273
|
|
|
236
274
|
/* One file of a turn's checkpoint diff: its patch, or the reason there is none. */
|
|
237
275
|
function CheckpointFileBody({ file }: { file: ChatCheckpointFile }) {
|
|
238
|
-
const { t } = useTranslation('agent-chat');
|
|
239
276
|
if (file.omitted) {
|
|
240
277
|
return <div className="px-3 py-2 text-xs text-text-faint">{omittedLabel(file.omitted)}</div>;
|
|
241
278
|
}
|
|
242
279
|
return (
|
|
243
|
-
<
|
|
280
|
+
<DiffSuspense>
|
|
244
281
|
<UnifiedDiff change={file} />
|
|
245
|
-
</
|
|
282
|
+
</DiffSuspense>
|
|
246
283
|
);
|
|
247
284
|
}
|
|
248
285
|
|
|
@@ -253,19 +290,22 @@ function ChangedFilesCard({
|
|
|
253
290
|
added,
|
|
254
291
|
deleted,
|
|
255
292
|
revealNonce = 0,
|
|
293
|
+
baseMoved,
|
|
256
294
|
children
|
|
257
295
|
}: {
|
|
258
296
|
count: number;
|
|
259
297
|
truncated?: boolean;
|
|
298
|
+
/* Set when the branch moved during the turn: the count is then what changed in the folder, not only the agent's work. */
|
|
299
|
+
baseMoved?: BaseMoved | undefined;
|
|
260
300
|
added?: number;
|
|
261
301
|
deleted?: number;
|
|
262
302
|
/* A jump from outside the chat that asked for this card; each new one opens it. */
|
|
263
303
|
revealNonce?: number;
|
|
264
|
-
children:
|
|
304
|
+
children: ReactNode;
|
|
265
305
|
}) {
|
|
266
306
|
const { t } = useTranslation('agent-chat');
|
|
267
307
|
const [expanded, setExpanded] = useState(false);
|
|
268
|
-
// A jump
|
|
308
|
+
// A jump opens the card, also one that mounted it by scrolling it on screen; the flash is gone by the next visit.
|
|
269
309
|
const [seenReveal, setSeenReveal] = useState(0);
|
|
270
310
|
if (revealNonce > 0 && revealNonce !== seenReveal) {
|
|
271
311
|
setSeenReveal(revealNonce);
|
|
@@ -279,13 +319,20 @@ function ChangedFilesCard({
|
|
|
279
319
|
onClick={() => setExpanded((value) => !value)}
|
|
280
320
|
>
|
|
281
321
|
<Icon icon={FileDiff} size={12} className="shrink-0" />
|
|
282
|
-
<span className="shrink-0 font-medium text-text">
|
|
322
|
+
<span className="shrink-0 font-medium text-text">
|
|
323
|
+
{baseMoved === undefined ? t('work.changedFiles', { count }) : t('work.folderChanges', { count })}
|
|
324
|
+
</span>
|
|
283
325
|
{truncated && <span className="min-w-0 truncate text-text-faint">{t('work.andMore')}</span>}
|
|
284
326
|
<span className="grow" />
|
|
285
327
|
{added !== undefined && <span className="text-chat-added tabular-nums">+{added}</span>}
|
|
286
328
|
{deleted !== undefined && <span className="text-chat-removed tabular-nums">-{deleted}</span>}
|
|
287
329
|
<Icon icon={ChevronRight} size={12} className={clsx('shrink-0 text-text-faint transition-transform', expanded && 'rotate-90')} />
|
|
288
330
|
</button>
|
|
331
|
+
{baseMoved !== undefined && (
|
|
332
|
+
<div className="pr-3 pb-2 pl-8 text-xs text-text-faint">
|
|
333
|
+
{t('work.baseMoved', { from: baseMoved.from.slice(0, 7), to: baseMoved.to.slice(0, 7) })}
|
|
334
|
+
</div>
|
|
335
|
+
)}
|
|
289
336
|
{expanded && children}
|
|
290
337
|
</div>
|
|
291
338
|
);
|
|
@@ -301,12 +348,14 @@ export function ChangedFilesRow({
|
|
|
301
348
|
tools,
|
|
302
349
|
diff,
|
|
303
350
|
checkpoint,
|
|
351
|
+
baseMoved,
|
|
304
352
|
chatId,
|
|
305
353
|
turnId
|
|
306
354
|
}: {
|
|
307
355
|
tools: ChatToolItem[];
|
|
308
356
|
diff: ChatCheckpointDiff | null;
|
|
309
357
|
checkpoint: boolean;
|
|
358
|
+
baseMoved?: BaseMoved | undefined;
|
|
310
359
|
chatId: string;
|
|
311
360
|
turnId: string;
|
|
312
361
|
}) {
|
|
@@ -339,34 +388,27 @@ export function ChangedFilesRow({
|
|
|
339
388
|
return (
|
|
340
389
|
<ChangedFilesCard
|
|
341
390
|
revealNonce={revealNonce}
|
|
391
|
+
baseMoved={baseMoved}
|
|
342
392
|
count={files.length}
|
|
343
393
|
truncated={checkpointDiff.truncated}
|
|
344
394
|
added={files.reduce((sum, file) => sum + file.added, 0)}
|
|
345
395
|
deleted={files.reduce((sum, file) => sum + file.deleted, 0)}
|
|
346
396
|
>
|
|
347
397
|
{files.map((file) => (
|
|
348
|
-
<
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
<span className="text-chat-removed tabular-nums">-{file.deleted}</span>
|
|
363
|
-
</button>
|
|
364
|
-
{open[file.path] && (
|
|
365
|
-
<div className="border-t border-border">
|
|
366
|
-
<CheckpointFileBody file={file} />
|
|
367
|
-
</div>
|
|
368
|
-
)}
|
|
369
|
-
</div>
|
|
398
|
+
<ChangedFileLine
|
|
399
|
+
key={file.path}
|
|
400
|
+
path={file.path}
|
|
401
|
+
open={open[file.path] === true}
|
|
402
|
+
onToggle={() => setOpen((o) => ({ ...o, [file.path]: !o[file.path] }))}
|
|
403
|
+
trailing={
|
|
404
|
+
<>
|
|
405
|
+
<span className="text-chat-added tabular-nums">+{file.added}</span>
|
|
406
|
+
<span className="text-chat-removed tabular-nums">-{file.deleted}</span>
|
|
407
|
+
</>
|
|
408
|
+
}
|
|
409
|
+
>
|
|
410
|
+
<CheckpointFileBody file={file} />
|
|
411
|
+
</ChangedFileLine>
|
|
370
412
|
))}
|
|
371
413
|
</ChangedFilesCard>
|
|
372
414
|
);
|
|
@@ -384,7 +426,7 @@ function ProviderChangedFiles({
|
|
|
384
426
|
tools: ChatToolItem[];
|
|
385
427
|
open: Record<string, boolean>;
|
|
386
428
|
revealNonce: number;
|
|
387
|
-
setOpen:
|
|
429
|
+
setOpen: Dispatch<SetStateAction<Record<string, boolean>>>;
|
|
388
430
|
}) {
|
|
389
431
|
const { t } = useTranslation('agent-chat');
|
|
390
432
|
const byPath = new Map<string, { edits: FileChange[]; patches: ChatFileChange[] }>();
|
|
@@ -411,35 +453,24 @@ function ProviderChangedFiles({
|
|
|
411
453
|
}
|
|
412
454
|
return (
|
|
413
455
|
<ChangedFilesCard count={byPath.size} revealNonce={revealNonce}>
|
|
414
|
-
{[...byPath].map(([path, entry]) =>
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
<
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
<UnifiedDiff key={`patch-${index}`} change={change} />
|
|
433
|
-
))}
|
|
434
|
-
{entry.edits.map((change, index) => (
|
|
435
|
-
<EditDiff key={`edit-${index}`} change={change} />
|
|
436
|
-
))}
|
|
437
|
-
</Suspense>
|
|
438
|
-
</div>
|
|
439
|
-
)}
|
|
440
|
-
</div>
|
|
441
|
-
);
|
|
442
|
-
})}
|
|
456
|
+
{[...byPath].map(([path, entry]) => (
|
|
457
|
+
<ChangedFileLine
|
|
458
|
+
key={path}
|
|
459
|
+
path={path}
|
|
460
|
+
open={open[path] === true}
|
|
461
|
+
onToggle={() => setOpen((o) => ({ ...o, [path]: !o[path] }))}
|
|
462
|
+
trailing={<span className="text-text-faint">{t('work.edits', { count: entry.edits.length + entry.patches.length })}</span>}
|
|
463
|
+
>
|
|
464
|
+
<DiffSuspense>
|
|
465
|
+
{entry.patches.map((change, index) => (
|
|
466
|
+
<UnifiedDiff key={`patch-${index}`} change={change} />
|
|
467
|
+
))}
|
|
468
|
+
{entry.edits.map((change, index) => (
|
|
469
|
+
<EditDiff key={`edit-${index}`} change={change} />
|
|
470
|
+
))}
|
|
471
|
+
</DiffSuspense>
|
|
472
|
+
</ChangedFileLine>
|
|
473
|
+
))}
|
|
443
474
|
</ChangedFilesCard>
|
|
444
475
|
);
|
|
445
476
|
}
|
|
@@ -2,7 +2,7 @@ import type { VisualScrollRequest } from '@adecore/agent-contracts/visual';
|
|
|
2
2
|
import { visualViewportGeometry } from './logic/visual-viewport';
|
|
3
3
|
import type { VisualBridge } from './visual-bridge';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/* Keeps one small frame in a full-height timeline row, without rendering React on scroll. */
|
|
6
6
|
export class VisualViewportController {
|
|
7
7
|
private readonly box: HTMLElement;
|
|
8
8
|
private readonly viewport: HTMLElement;
|
|
@@ -40,11 +40,7 @@ export class VisualViewportController {
|
|
|
40
40
|
if (this.disposed) {
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
|
-
const
|
|
44
|
-
const box = this.box.getBoundingClientRect();
|
|
45
|
-
// A chat on a canvas can be scaled; messages inside its frame use unscaled CSS pixels.
|
|
46
|
-
const scale = outer.height / this.scroller.offsetHeight || 1;
|
|
47
|
-
const top = (box.top - outer.top) / scale - this.scroller.clientTop;
|
|
43
|
+
const top = this.offsetInScroller(this.scroller.getBoundingClientRect(), this.box.getBoundingClientRect());
|
|
48
44
|
const available = this.scroller.clientHeight;
|
|
49
45
|
const geometry = visualViewportGeometry(this.box.offsetHeight, available, top);
|
|
50
46
|
this.viewport.style.height = `${geometry.height}px`;
|
|
@@ -67,8 +63,7 @@ export class VisualViewportController {
|
|
|
67
63
|
return;
|
|
68
64
|
}
|
|
69
65
|
this.pendingDelta = 0;
|
|
70
|
-
const
|
|
71
|
-
const start = this.scroller.scrollTop + (box.top - outer.top) / scale - this.scroller.clientTop;
|
|
66
|
+
const start = this.scroller.scrollTop + this.offsetInScroller(outer, box);
|
|
72
67
|
const top = 'to' in request ? start + request.to : request.edge === 'start' ? 0 : this.scroller.scrollHeight;
|
|
73
68
|
this.scroller.scrollTo({ top, behavior: 'instant' });
|
|
74
69
|
this.refresh();
|
|
@@ -83,6 +78,13 @@ export class VisualViewportController {
|
|
|
83
78
|
this.bridge.setViewport(null);
|
|
84
79
|
}
|
|
85
80
|
|
|
81
|
+
/* The box's top below the scroller's visible top, in the scroller's own pixels. */
|
|
82
|
+
private offsetInScroller(outer: DOMRect, box: DOMRect): number {
|
|
83
|
+
// A chat on a canvas can be scaled; messages inside its frame use unscaled CSS pixels.
|
|
84
|
+
const scale = outer.height / this.scroller.offsetHeight || 1;
|
|
85
|
+
return (box.top - outer.top) / scale - this.scroller.clientTop;
|
|
86
|
+
}
|
|
87
|
+
|
|
86
88
|
private schedule(): void {
|
|
87
89
|
if (this.frame || this.disposed) {
|
|
88
90
|
return;
|
package/src/host.ts
CHANGED
|
@@ -134,7 +134,7 @@ export interface TimelineFind {
|
|
|
134
134
|
/* The dictation control beside the composer's editor; it takes its text from the editor itself. */
|
|
135
135
|
export interface ComposerDictationProps {
|
|
136
136
|
targetRef: RefObject<HTMLElement | null>;
|
|
137
|
-
/*
|
|
137
|
+
/* In the composer's row of round controls. */
|
|
138
138
|
buttonContainer: HTMLElement | null | undefined;
|
|
139
139
|
disabled: boolean;
|
|
140
140
|
editor(): EditorView | null;
|
|
@@ -239,7 +239,6 @@ export interface ChatHost {
|
|
|
239
239
|
/* The image a tool read, drawn under its row; null draws none. */
|
|
240
240
|
ReadImage: ComponentType<{ path: string }> | null;
|
|
241
241
|
code: {
|
|
242
|
-
/* Whether the app is light or dark right now. */
|
|
243
242
|
useMode(): 'light' | 'dark';
|
|
244
243
|
/* The Shiki theme ids code is drawn in, one per mode. */
|
|
245
244
|
useThemes(): { light: string; dark: string };
|
|
@@ -280,6 +279,8 @@ export interface ChatHost {
|
|
|
280
279
|
useLoginBlocked(scopeId: string): string | null;
|
|
281
280
|
/* The name and the mark of a project of the host, for the usage per project; null draws the folder's own. */
|
|
282
281
|
useProjectLook(scopeId: string, projectId: string | null): { name: string; mark: ReactNode } | null;
|
|
282
|
+
/* What a person calls the machine the scope's chats run on, or null when it has no name worth saying. */
|
|
283
|
+
useMachineLabel(scopeId: string): string | null;
|
|
283
284
|
/* Where another chat of the app stands, for a fork's way back and a note from a fork. */
|
|
284
285
|
useChatPlace(chatId: string): ChatPlace;
|
|
285
286
|
/* What a chat may read besides its folder, named under an empty thread. */
|
|
@@ -300,7 +301,6 @@ export interface ChatHost {
|
|
|
300
301
|
};
|
|
301
302
|
/* Offers a fork of the chat after one of its turns; null offers none. */
|
|
302
303
|
fork: ((chatId: string, turnId: string) => void) | null;
|
|
303
|
-
/* Opens the app's settings on a section: `providers`, or `agents`. */
|
|
304
304
|
openSettings(section: 'providers' | 'agents'): void;
|
|
305
305
|
/* Whether the host lets a chat go on by itself once a limit it stopped on lifts. */
|
|
306
306
|
useResumeAtReset(scopeId: string): boolean;
|
|
@@ -347,6 +347,7 @@ const DEFAULT_HOST: ChatHost = {
|
|
|
347
347
|
openLogin: null,
|
|
348
348
|
useLoginBlocked: () => null,
|
|
349
349
|
useProjectLook: () => null,
|
|
350
|
+
useMachineLabel: () => null,
|
|
350
351
|
useChatPlace: () => NOWHERE,
|
|
351
352
|
useContextSources: () => NO_SOURCES,
|
|
352
353
|
useHidesFolder: () => false,
|
|
@@ -91,7 +91,8 @@
|
|
|
91
91
|
"user": {
|
|
92
92
|
"heading": "You",
|
|
93
93
|
"showAll": "Show all",
|
|
94
|
-
"showLess": "Show less"
|
|
94
|
+
"showLess": "Show less",
|
|
95
|
+
"quoteGone": "The reply this quote came from is no longer in this chat."
|
|
95
96
|
},
|
|
96
97
|
"report": {
|
|
97
98
|
"heading": "Report"
|
|
@@ -107,7 +108,8 @@
|
|
|
107
108
|
"note": {
|
|
108
109
|
"hide": "Hide",
|
|
109
110
|
"show": "Show",
|
|
110
|
-
"openFork": "Open fork"
|
|
111
|
+
"openFork": "Open fork",
|
|
112
|
+
"openWaiting": "Open to answer"
|
|
111
113
|
},
|
|
112
114
|
"compaction": {
|
|
113
115
|
"plain": "Context compacted",
|
|
@@ -165,6 +167,9 @@
|
|
|
165
167
|
},
|
|
166
168
|
"changedFiles_one": "{{count}} changed file",
|
|
167
169
|
"changedFiles_other": "{{count}} changed files",
|
|
170
|
+
"folderChanges_one": "{{count}} change in the folder this turn",
|
|
171
|
+
"folderChanges_other": "{{count}} changes in the folder this turn",
|
|
172
|
+
"baseMoved": "The branch moved during this turn ({{from}} to {{to}}), so this includes what came in with it.",
|
|
168
173
|
"andMore": "and more, truncated",
|
|
169
174
|
"edits_one": "{{count}} edit",
|
|
170
175
|
"edits_other": "{{count}} edits",
|
|
@@ -249,6 +254,17 @@
|
|
|
249
254
|
},
|
|
250
255
|
"composer": {
|
|
251
256
|
"slotFailed": "This control failed to render",
|
|
257
|
+
"inputLabel": "Message",
|
|
258
|
+
"menu": {
|
|
259
|
+
"commands": "Commands",
|
|
260
|
+
"skills": "Skills",
|
|
261
|
+
"mentions": "Mentions"
|
|
262
|
+
},
|
|
263
|
+
"held": {
|
|
264
|
+
"question": "A question is waiting. It opens when you pause typing.",
|
|
265
|
+
"approval": "An approval is waiting. It opens when you pause typing.",
|
|
266
|
+
"show": "Show now"
|
|
267
|
+
},
|
|
252
268
|
"commands": {
|
|
253
269
|
"model": "Switch the model",
|
|
254
270
|
"compact": "Compact the context",
|
|
@@ -294,7 +310,8 @@
|
|
|
294
310
|
},
|
|
295
311
|
"quote": {
|
|
296
312
|
"add": "Quote",
|
|
297
|
-
"remove": "Remove quote"
|
|
313
|
+
"remove": "Remove quote",
|
|
314
|
+
"goToSource": "Go to the reply"
|
|
298
315
|
},
|
|
299
316
|
"removeAttachment": "Remove {{name}}",
|
|
300
317
|
"attach": "Attach files",
|
|
@@ -319,6 +336,9 @@
|
|
|
319
336
|
"monitors_one": "{{count}} monitor",
|
|
320
337
|
"monitors_other": "{{count}} monitors",
|
|
321
338
|
"pausedUntil": "paused until {{time}}",
|
|
339
|
+
"progress": "{{done}} of {{total}} sub-agents done",
|
|
340
|
+
"needsYou_one": "{{count}} needs you",
|
|
341
|
+
"needsYou_other": "{{count}} need you",
|
|
322
342
|
"took": {
|
|
323
343
|
"done": "done in {{duration}}",
|
|
324
344
|
"failed": "failed after {{duration}}",
|
|
@@ -332,8 +352,10 @@
|
|
|
332
352
|
"subagents": {
|
|
333
353
|
"stop": {
|
|
334
354
|
"task": "Stop this task",
|
|
355
|
+
"native": "Stop this sub-agent",
|
|
335
356
|
"mark": "Mark as stopped. The CLI cannot stop one sub-agent, so it may keep working until the chat's process ends."
|
|
336
357
|
},
|
|
358
|
+
"stale": "This sub-agent belongs to a process that has ended.",
|
|
337
359
|
"title": "Sub-agents",
|
|
338
360
|
"backToMain": "Back to the main agent",
|
|
339
361
|
"loading": "Loading the conversation…",
|
|
@@ -344,9 +366,7 @@
|
|
|
344
366
|
"stopFailed": "The sub-agent could not be stopped",
|
|
345
367
|
"info": {
|
|
346
368
|
"label": "About this sub-agent",
|
|
347
|
-
"tokens": "{{tokens}} tokens"
|
|
348
|
-
"showTask": "Show its task",
|
|
349
|
-
"hideTask": "Hide its task"
|
|
369
|
+
"tokens": "{{tokens}} tokens"
|
|
350
370
|
}
|
|
351
371
|
},
|
|
352
372
|
"modes": {
|
|
@@ -382,7 +402,10 @@
|
|
|
382
402
|
"noMatch": "No models match",
|
|
383
403
|
"legacyGroup_one": "Legacy models ({{count}})",
|
|
384
404
|
"legacyGroup_other": "Legacy models ({{count}})",
|
|
385
|
-
"legacy": "Legacy"
|
|
405
|
+
"legacy": "Legacy",
|
|
406
|
+
"requires": "Requires {{cli}} {{version}} or later on {{machine}}",
|
|
407
|
+
"requiresHere": "Requires {{cli}} {{version}} or later",
|
|
408
|
+
"providerSettings": "Provider settings"
|
|
386
409
|
},
|
|
387
410
|
"stash": {
|
|
388
411
|
"title": "Stashed prompts",
|
|
@@ -91,7 +91,8 @@
|
|
|
91
91
|
"user": {
|
|
92
92
|
"heading": "Jij",
|
|
93
93
|
"showAll": "Alles tonen",
|
|
94
|
-
"showLess": "Minder tonen"
|
|
94
|
+
"showLess": "Minder tonen",
|
|
95
|
+
"quoteGone": "Het antwoord waar dit citaat vandaan kwam, staat niet meer in deze chat."
|
|
95
96
|
},
|
|
96
97
|
"report": {
|
|
97
98
|
"heading": "Rapport"
|
|
@@ -107,7 +108,8 @@
|
|
|
107
108
|
"note": {
|
|
108
109
|
"hide": "Verbergen",
|
|
109
110
|
"show": "Tonen",
|
|
110
|
-
"openFork": "Fork openen"
|
|
111
|
+
"openFork": "Fork openen",
|
|
112
|
+
"openWaiting": "Openen om te antwoorden"
|
|
111
113
|
},
|
|
112
114
|
"compaction": {
|
|
113
115
|
"plain": "Context gecomprimeerd",
|
|
@@ -165,6 +167,9 @@
|
|
|
165
167
|
},
|
|
166
168
|
"changedFiles_one": "{{count}} gewijzigd bestand",
|
|
167
169
|
"changedFiles_other": "{{count}} gewijzigde bestanden",
|
|
170
|
+
"folderChanges_one": "{{count}} wijziging in de map tijdens deze beurt",
|
|
171
|
+
"folderChanges_other": "{{count}} wijzigingen in de map tijdens deze beurt",
|
|
172
|
+
"baseMoved": "De branch is tijdens deze beurt verplaatst ({{from}} naar {{to}}), dus dit omvat ook wat daarmee binnenkwam.",
|
|
168
173
|
"andMore": "en meer, afgekapt",
|
|
169
174
|
"edits_one": "{{count}} bewerking",
|
|
170
175
|
"edits_other": "{{count}} bewerkingen",
|
|
@@ -249,6 +254,17 @@
|
|
|
249
254
|
},
|
|
250
255
|
"composer": {
|
|
251
256
|
"slotFailed": "Dit onderdeel kon niet worden getekend",
|
|
257
|
+
"inputLabel": "Bericht",
|
|
258
|
+
"menu": {
|
|
259
|
+
"commands": "Commando's",
|
|
260
|
+
"skills": "Skills",
|
|
261
|
+
"mentions": "Vermeldingen"
|
|
262
|
+
},
|
|
263
|
+
"held": {
|
|
264
|
+
"question": "Er wacht een vraag. Die opent zodra je even stopt met typen.",
|
|
265
|
+
"approval": "Er wacht een goedkeuring. Die opent zodra je even stopt met typen.",
|
|
266
|
+
"show": "Nu tonen"
|
|
267
|
+
},
|
|
252
268
|
"commands": {
|
|
253
269
|
"model": "Wissel van model",
|
|
254
270
|
"compact": "Comprimeer de context",
|
|
@@ -294,7 +310,8 @@
|
|
|
294
310
|
},
|
|
295
311
|
"quote": {
|
|
296
312
|
"add": "Citeren",
|
|
297
|
-
"remove": "Citaat verwijderen"
|
|
313
|
+
"remove": "Citaat verwijderen",
|
|
314
|
+
"goToSource": "Naar het antwoord"
|
|
298
315
|
},
|
|
299
316
|
"removeAttachment": "{{name}} verwijderen",
|
|
300
317
|
"attach": "Bestanden toevoegen",
|
|
@@ -319,6 +336,9 @@
|
|
|
319
336
|
"monitors_one": "{{count}} monitor",
|
|
320
337
|
"monitors_other": "{{count}} monitors",
|
|
321
338
|
"pausedUntil": "gepauzeerd tot {{time}}",
|
|
339
|
+
"progress": "{{done}} van {{total}} sub-agents klaar",
|
|
340
|
+
"needsYou_one": "{{count}} vraagt aandacht",
|
|
341
|
+
"needsYou_other": "{{count}} vragen aandacht",
|
|
322
342
|
"took": {
|
|
323
343
|
"done": "klaar in {{duration}}",
|
|
324
344
|
"failed": "mislukt na {{duration}}",
|
|
@@ -332,8 +352,10 @@
|
|
|
332
352
|
"subagents": {
|
|
333
353
|
"stop": {
|
|
334
354
|
"task": "Deze taak stoppen",
|
|
355
|
+
"native": "Deze sub-agent stoppen",
|
|
335
356
|
"mark": "Markeren als gestopt. De CLI kan een losse sub-agent niet stoppen, dus die werkt mogelijk door tot het proces van de chat eindigt."
|
|
336
357
|
},
|
|
358
|
+
"stale": "Deze sub-agent hoort bij een proces dat al gestopt is.",
|
|
337
359
|
"title": "Sub-agents",
|
|
338
360
|
"backToMain": "Terug naar de main agent",
|
|
339
361
|
"loading": "Gesprek laden…",
|
|
@@ -344,9 +366,7 @@
|
|
|
344
366
|
"stopFailed": "De sub-agent kon niet worden gestopt",
|
|
345
367
|
"info": {
|
|
346
368
|
"label": "Over deze sub-agent",
|
|
347
|
-
"tokens": "{{tokens}} tokens"
|
|
348
|
-
"showTask": "Opdracht tonen",
|
|
349
|
-
"hideTask": "Opdracht verbergen"
|
|
369
|
+
"tokens": "{{tokens}} tokens"
|
|
350
370
|
}
|
|
351
371
|
},
|
|
352
372
|
"modes": {
|
|
@@ -382,7 +402,10 @@
|
|
|
382
402
|
"noMatch": "Geen modellen gevonden",
|
|
383
403
|
"legacyGroup_one": "Legacy-modellen ({{count}})",
|
|
384
404
|
"legacyGroup_other": "Legacy-modellen ({{count}})",
|
|
385
|
-
"legacy": "Legacy"
|
|
405
|
+
"legacy": "Legacy",
|
|
406
|
+
"requires": "Vereist {{cli}} {{version}} of nieuwer op {{machine}}",
|
|
407
|
+
"requiresHere": "Vereist {{cli}} {{version}} of nieuwer",
|
|
408
|
+
"providerSettings": "Providerinstellingen"
|
|
386
409
|
},
|
|
387
410
|
"stash": {
|
|
388
411
|
"title": "Stashed prompts",
|
package/src/port-transport.ts
CHANGED
|
@@ -110,15 +110,11 @@ export function portTransport(port: FramePort): PortTransport {
|
|
|
110
110
|
return promise;
|
|
111
111
|
},
|
|
112
112
|
on<E extends AgentEventType>(event: E, handler: (payload: ChatEventMap[E]) => void): () => void {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
eventHandlers.set(event, handlers);
|
|
117
|
-
}
|
|
118
|
-
const set = handlers;
|
|
119
|
-
set.add(handler);
|
|
113
|
+
const handlers = eventHandlers.get(event) ?? new Set();
|
|
114
|
+
eventHandlers.set(event, handlers);
|
|
115
|
+
handlers.add(handler);
|
|
120
116
|
return () => {
|
|
121
|
-
|
|
117
|
+
handlers.delete(handler);
|
|
122
118
|
};
|
|
123
119
|
},
|
|
124
120
|
subscribeStatus(handler: (status: ChatTransportStatus) => void): () => void {
|