@adecore/agents-react 0.21.0 → 0.21.2
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/status-look.js +2 -3
- package/dist/chat/chat-client.d.ts +1 -1
- package/dist/chat/chat-client.js +2 -2
- package/dist/chat/drafts.js +6 -12
- 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/resume-compaction.js +2 -11
- package/dist/chat/logic/scrubber.js +9 -18
- package/dist/chat/logic/timeline.js +15 -10
- package/dist/chat/logic/tool-catalog.js +3 -4
- package/dist/chat/mentions.js +5 -6
- package/dist/chat/runtime-modes.js +2 -4
- package/dist/chat/stash.js +1 -3
- package/dist/chat/thumbnails.js +3 -4
- package/dist/chat/timeline-scroll.js +39 -45
- package/dist/chat/ui/BookmarkSubmenu.js +1 -5
- package/dist/chat/ui/CodeBlock.js +2 -3
- package/dist/chat/ui/Composer.js +57 -69
- package/dist/chat/ui/Markdown.js +11 -11
- package/dist/chat/ui/Pickers.js +5 -9
- package/dist/chat/ui/QuoteButton.js +2 -3
- package/dist/chat/ui/RunSettings.js +8 -2
- package/dist/chat/ui/Scrubber.js +2 -3
- package/dist/chat/ui/SubagentControls.js +1 -3
- package/dist/chat/ui/Timeline.js +15 -18
- 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/intelligent-ui/UiBlockFrame.d.ts +14 -1
- package/dist/chat/ui/intelligent-ui/UiBlockFrame.js +47 -5
- package/dist/chat/ui/intelligent-ui/UiReply.d.ts +3 -1
- package/dist/chat/ui/intelligent-ui/UiReply.js +34 -30
- package/dist/chat/ui/intelligent-ui/block-local.d.ts +9 -0
- package/dist/chat/ui/intelligent-ui/block-local.js +30 -1
- package/dist/chat/ui/intelligent-ui/node-text.d.ts +6 -0
- package/dist/chat/ui/intelligent-ui/node-text.js +54 -0
- package/dist/chat/ui/intelligent-ui/registry.js +2 -1
- package/dist/chat/ui/intelligent-ui/render-context.d.ts +4 -1
- package/dist/chat/ui/intelligent-ui/renderers/chart.js +5 -7
- package/dist/chat/ui/intelligent-ui/renderers/choices.js +6 -2
- package/dist/chat/ui/intelligent-ui/renderers/content.js +6 -13
- package/dist/chat/ui/intelligent-ui/renderers/data.js +8 -15
- package/dist/chat/ui/intelligent-ui/renderers/inputs.d.ts +1 -0
- package/dist/chat/ui/intelligent-ui/renderers/inputs.js +16 -4
- package/dist/chat/ui/intelligent-ui/renderers/links.js +2 -1
- package/dist/chat/ui/intelligent-ui/use-ui-links.d.ts +4 -4
- package/dist/chat/ui/intelligent-ui/use-ui-links.js +29 -10
- package/dist/chat/ui/intelligent-ui/use-ui-queries.d.ts +2 -1
- package/dist/chat/ui/intelligent-ui/use-ui-queries.js +34 -21
- package/dist/chat/ui/rows/MessageRows.js +3 -4
- package/dist/chat/ui/rows/WorkRows.d.ts +4 -3
- package/dist/chat/ui/rows/WorkRows.js +19 -14
- package/dist/chat/visual-viewport.d.ts +1 -1
- package/dist/chat/visual-viewport.js +9 -8
- package/dist/locales/en/agent-chat.json +23 -4
- package/dist/locales/nl/agent-chat.json +23 -4
- package/dist/port-transport.js +4 -8
- package/dist/state/chats.js +15 -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 -29
- package/src/agents/status-look.ts +2 -3
- package/src/chat/chat-client.ts +2 -3
- package/src/chat/drafts.ts +6 -14
- 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/resume-compaction.ts +2 -11
- package/src/chat/logic/scrubber.ts +13 -17
- package/src/chat/logic/timeline.ts +22 -11
- package/src/chat/logic/tool-catalog.ts +7 -6
- package/src/chat/mentions.ts +5 -6
- package/src/chat/runtime-modes.ts +2 -4
- package/src/chat/stash.ts +1 -3
- package/src/chat/thumbnails.ts +3 -4
- package/src/chat/timeline-scroll.ts +43 -52
- package/src/chat/ui/BookmarkSubmenu.tsx +1 -5
- package/src/chat/ui/CodeBlock.tsx +2 -3
- package/src/chat/ui/Composer.tsx +66 -86
- package/src/chat/ui/Markdown.tsx +13 -17
- package/src/chat/ui/Pickers.tsx +5 -9
- package/src/chat/ui/QuoteButton.tsx +2 -3
- package/src/chat/ui/RunSettings.tsx +9 -2
- package/src/chat/ui/Scrubber.tsx +2 -3
- package/src/chat/ui/SubagentControls.tsx +1 -3
- package/src/chat/ui/SubagentTimeline.tsx +1 -2
- package/src/chat/ui/Timeline.tsx +18 -20
- 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/intelligent-ui/UiBlockFrame.tsx +135 -5
- package/src/chat/ui/intelligent-ui/UiReply.tsx +48 -38
- package/src/chat/ui/intelligent-ui/block-local.ts +36 -1
- package/src/chat/ui/intelligent-ui/node-text.ts +60 -0
- package/src/chat/ui/intelligent-ui/registry.ts +2 -1
- package/src/chat/ui/intelligent-ui/render-context.ts +8 -2
- package/src/chat/ui/intelligent-ui/renderers/chart.tsx +5 -7
- package/src/chat/ui/intelligent-ui/renderers/choices.tsx +6 -2
- package/src/chat/ui/intelligent-ui/renderers/content.tsx +9 -14
- package/src/chat/ui/intelligent-ui/renderers/data.tsx +13 -19
- package/src/chat/ui/intelligent-ui/renderers/inputs.tsx +28 -5
- package/src/chat/ui/intelligent-ui/renderers/links.tsx +2 -1
- package/src/chat/ui/intelligent-ui/use-ui-links.ts +31 -11
- package/src/chat/ui/intelligent-ui/use-ui-queries.ts +48 -22
- 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 +4 -5
- package/src/chat/ui/rows/WorkRows.tsx +86 -69
- package/src/chat/visual-viewport.ts +10 -8
- package/src/host.ts +1 -3
- package/src/locales/en/agent-chat.json +23 -4
- package/src/locales/nl/agent-chat.json +23 -4
- package/src/port-transport.ts +4 -8
- package/src/state/chats.ts +16 -15
- 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
- package/dist/chat/ui/intelligent-ui/UiBlockFooter.d.ts +0 -15
- package/dist/chat/ui/intelligent-ui/UiBlockFooter.js +0 -50
- package/src/chat/ui/intelligent-ui/UiBlockFooter.tsx +0 -139
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
@@ -40,14 +40,14 @@ export function ToggleLine({
|
|
|
40
40
|
trailing,
|
|
41
41
|
className
|
|
42
42
|
}: {
|
|
43
|
-
icon:
|
|
43
|
+
icon: ReactNode;
|
|
44
44
|
label: string;
|
|
45
45
|
detail?: string;
|
|
46
46
|
open: boolean;
|
|
47
47
|
onToggle(): void;
|
|
48
48
|
failed?: boolean;
|
|
49
49
|
live?: boolean;
|
|
50
|
-
trailing?:
|
|
50
|
+
trailing?: ReactNode;
|
|
51
51
|
className?: string;
|
|
52
52
|
}) {
|
|
53
53
|
return (
|
|
@@ -75,24 +75,60 @@ export function ToggleLine({
|
|
|
75
75
|
);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
/* The diff renderers load lazily, so a diff waits on them under a line that says so. */
|
|
79
|
+
function DiffSuspense({ children }: { children: ReactNode }) {
|
|
79
80
|
const { t } = useTranslation('agent-chat');
|
|
81
|
+
return <Suspense fallback={<div className="px-3 py-2 text-xs text-text-faint">{t('work.loadingDiff')}</div>}>{children}</Suspense>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* A file in a changed files card, which opens its diff under it. */
|
|
85
|
+
function ChangedFileLine({
|
|
86
|
+
path,
|
|
87
|
+
open,
|
|
88
|
+
onToggle,
|
|
89
|
+
trailing,
|
|
90
|
+
children
|
|
91
|
+
}: {
|
|
92
|
+
path: string;
|
|
93
|
+
open: boolean;
|
|
94
|
+
onToggle(): void;
|
|
95
|
+
trailing: ReactNode;
|
|
96
|
+
children: ReactNode;
|
|
97
|
+
}) {
|
|
98
|
+
return (
|
|
99
|
+
<div className="border-t border-border">
|
|
100
|
+
<button
|
|
101
|
+
className="flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-text-muted hover:bg-surface-hover"
|
|
102
|
+
data-file-path={path}
|
|
103
|
+
onClick={onToggle}
|
|
104
|
+
>
|
|
105
|
+
<Icon icon={ChevronRight} size={12} className={clsx('shrink-0 text-text-faint transition-transform', open && 'rotate-90')} />
|
|
106
|
+
<span className="min-w-0 truncate font-mono text-text">{path}</span>
|
|
107
|
+
<span className="grow" />
|
|
108
|
+
{trailing}
|
|
109
|
+
</button>
|
|
110
|
+
{open && <div className="border-t border-border">{children}</div>}
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function ToolBody({ tool }: { tool: ChatToolItem }) {
|
|
80
116
|
const patches = unifiedChanges(tool);
|
|
81
117
|
const changes = patches.length > 0 ? [] : fileChanges(tool.name, tool.input);
|
|
82
118
|
return (
|
|
83
119
|
<div className="mt-1.5 mb-2 ml-6 overflow-hidden rounded-md border border-border bg-surface-raised">
|
|
84
120
|
{patches.length > 0 ? (
|
|
85
|
-
<
|
|
121
|
+
<DiffSuspense>
|
|
86
122
|
{patches.map((change, index) => (
|
|
87
123
|
<UnifiedDiff key={index} change={change} />
|
|
88
124
|
))}
|
|
89
|
-
</
|
|
125
|
+
</DiffSuspense>
|
|
90
126
|
) : changes.length > 0 ? (
|
|
91
|
-
<
|
|
127
|
+
<DiffSuspense>
|
|
92
128
|
{changes.map((change, index) => (
|
|
93
129
|
<EditDiff key={index} change={change} />
|
|
94
130
|
))}
|
|
95
|
-
</
|
|
131
|
+
</DiffSuspense>
|
|
96
132
|
) : (
|
|
97
133
|
<pre className="max-h-64 overflow-auto px-3 py-2 font-mono text-code text-text-muted select-text">
|
|
98
134
|
{clip(JSON.stringify(tool.input, null, 2) ?? '')}
|
|
@@ -113,9 +149,10 @@ function ToolBody({ tool }: { tool: ChatToolItem }) {
|
|
|
113
149
|
);
|
|
114
150
|
}
|
|
115
151
|
|
|
116
|
-
/*
|
|
117
|
-
|
|
118
|
-
|
|
152
|
+
/*
|
|
153
|
+
* One settled tool call: a line, and its input and output behind it. An image the call looked at is
|
|
154
|
+
* drawn under the line. `icon`, `label` and `failed` let a row that knows the call better name it.
|
|
155
|
+
*/
|
|
119
156
|
export function WorkRow({
|
|
120
157
|
tool,
|
|
121
158
|
nested,
|
|
@@ -127,7 +164,7 @@ export function WorkRow({
|
|
|
127
164
|
tool: ChatToolItem;
|
|
128
165
|
nested?: boolean;
|
|
129
166
|
detail?: string;
|
|
130
|
-
icon?:
|
|
167
|
+
icon?: ReactNode;
|
|
131
168
|
label?: string;
|
|
132
169
|
failed?: boolean;
|
|
133
170
|
}) {
|
|
@@ -235,14 +272,13 @@ function omittedLabel(reason: 'binary' | 'too-large'): string {
|
|
|
235
272
|
|
|
236
273
|
/* One file of a turn's checkpoint diff: its patch, or the reason there is none. */
|
|
237
274
|
function CheckpointFileBody({ file }: { file: ChatCheckpointFile }) {
|
|
238
|
-
const { t } = useTranslation('agent-chat');
|
|
239
275
|
if (file.omitted) {
|
|
240
276
|
return <div className="px-3 py-2 text-xs text-text-faint">{omittedLabel(file.omitted)}</div>;
|
|
241
277
|
}
|
|
242
278
|
return (
|
|
243
|
-
<
|
|
279
|
+
<DiffSuspense>
|
|
244
280
|
<UnifiedDiff change={file} />
|
|
245
|
-
</
|
|
281
|
+
</DiffSuspense>
|
|
246
282
|
);
|
|
247
283
|
}
|
|
248
284
|
|
|
@@ -261,11 +297,11 @@ function ChangedFilesCard({
|
|
|
261
297
|
deleted?: number;
|
|
262
298
|
/* A jump from outside the chat that asked for this card; each new one opens it. */
|
|
263
299
|
revealNonce?: number;
|
|
264
|
-
children:
|
|
300
|
+
children: ReactNode;
|
|
265
301
|
}) {
|
|
266
302
|
const { t } = useTranslation('agent-chat');
|
|
267
303
|
const [expanded, setExpanded] = useState(false);
|
|
268
|
-
// A jump
|
|
304
|
+
// A jump opens the card, also one that mounted it by scrolling it on screen; the flash is gone by the next visit.
|
|
269
305
|
const [seenReveal, setSeenReveal] = useState(0);
|
|
270
306
|
if (revealNonce > 0 && revealNonce !== seenReveal) {
|
|
271
307
|
setSeenReveal(revealNonce);
|
|
@@ -345,28 +381,20 @@ export function ChangedFilesRow({
|
|
|
345
381
|
deleted={files.reduce((sum, file) => sum + file.deleted, 0)}
|
|
346
382
|
>
|
|
347
383
|
{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>
|
|
384
|
+
<ChangedFileLine
|
|
385
|
+
key={file.path}
|
|
386
|
+
path={file.path}
|
|
387
|
+
open={open[file.path] === true}
|
|
388
|
+
onToggle={() => setOpen((o) => ({ ...o, [file.path]: !o[file.path] }))}
|
|
389
|
+
trailing={
|
|
390
|
+
<>
|
|
391
|
+
<span className="text-chat-added tabular-nums">+{file.added}</span>
|
|
392
|
+
<span className="text-chat-removed tabular-nums">-{file.deleted}</span>
|
|
393
|
+
</>
|
|
394
|
+
}
|
|
395
|
+
>
|
|
396
|
+
<CheckpointFileBody file={file} />
|
|
397
|
+
</ChangedFileLine>
|
|
370
398
|
))}
|
|
371
399
|
</ChangedFilesCard>
|
|
372
400
|
);
|
|
@@ -384,7 +412,7 @@ function ProviderChangedFiles({
|
|
|
384
412
|
tools: ChatToolItem[];
|
|
385
413
|
open: Record<string, boolean>;
|
|
386
414
|
revealNonce: number;
|
|
387
|
-
setOpen:
|
|
415
|
+
setOpen: Dispatch<SetStateAction<Record<string, boolean>>>;
|
|
388
416
|
}) {
|
|
389
417
|
const { t } = useTranslation('agent-chat');
|
|
390
418
|
const byPath = new Map<string, { edits: FileChange[]; patches: ChatFileChange[] }>();
|
|
@@ -411,35 +439,24 @@ function ProviderChangedFiles({
|
|
|
411
439
|
}
|
|
412
440
|
return (
|
|
413
441
|
<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
|
-
})}
|
|
442
|
+
{[...byPath].map(([path, entry]) => (
|
|
443
|
+
<ChangedFileLine
|
|
444
|
+
key={path}
|
|
445
|
+
path={path}
|
|
446
|
+
open={open[path] === true}
|
|
447
|
+
onToggle={() => setOpen((o) => ({ ...o, [path]: !o[path] }))}
|
|
448
|
+
trailing={<span className="text-text-faint">{t('work.edits', { count: entry.edits.length + entry.patches.length })}</span>}
|
|
449
|
+
>
|
|
450
|
+
<DiffSuspense>
|
|
451
|
+
{entry.patches.map((change, index) => (
|
|
452
|
+
<UnifiedDiff key={`patch-${index}`} change={change} />
|
|
453
|
+
))}
|
|
454
|
+
{entry.edits.map((change, index) => (
|
|
455
|
+
<EditDiff key={`edit-${index}`} change={change} />
|
|
456
|
+
))}
|
|
457
|
+
</DiffSuspense>
|
|
458
|
+
</ChangedFileLine>
|
|
459
|
+
))}
|
|
443
460
|
</ChangedFilesCard>
|
|
444
461
|
);
|
|
445
462
|
}
|
|
@@ -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 };
|
|
@@ -300,7 +299,6 @@ export interface ChatHost {
|
|
|
300
299
|
};
|
|
301
300
|
/* Offers a fork of the chat after one of its turns; null offers none. */
|
|
302
301
|
fork: ((chatId: string, turnId: string) => void) | null;
|
|
303
|
-
/* Opens the app's settings on a section: `providers`, or `agents`. */
|
|
304
302
|
openSettings(section: 'providers' | 'agents'): void;
|
|
305
303
|
/* Whether the host lets a chat go on by itself once a limit it stopped on lifts. */
|
|
306
304
|
useResumeAtReset(scopeId: string): boolean;
|
|
@@ -498,6 +498,7 @@
|
|
|
498
498
|
"from": "from {{previous}}"
|
|
499
499
|
},
|
|
500
500
|
"table": {
|
|
501
|
+
"label": "Table of {{columns}}",
|
|
501
502
|
"showAll": "Show all {{total}} rows"
|
|
502
503
|
},
|
|
503
504
|
"chart": {
|
|
@@ -514,8 +515,10 @@
|
|
|
514
515
|
"outsideProject": "Outside the project, shown as text",
|
|
515
516
|
"options": "Options",
|
|
516
517
|
"choices": "Choices",
|
|
518
|
+
"checklist": "Checklist",
|
|
517
519
|
"choice": {
|
|
518
520
|
"waiting": "Available when the reply is done",
|
|
521
|
+
"reading": "Available once the live data is read",
|
|
519
522
|
"unavailable": "Not available",
|
|
520
523
|
"sent": "Sent",
|
|
521
524
|
"queued": "Queued",
|
|
@@ -525,14 +528,11 @@
|
|
|
525
528
|
"answered": "Answered with “{{label}}”",
|
|
526
529
|
"chose": "Chose “{{label}}”",
|
|
527
530
|
"choseOlder": "Chose “{{label}}” on the reply of {{time}}",
|
|
528
|
-
"sendContext": "Send",
|
|
529
|
-
"copyText": "Copy text",
|
|
530
531
|
"fixes_one": "{{count}} fix",
|
|
531
532
|
"fixes_other": "{{count}} fixes",
|
|
532
533
|
"shownAsText": "Shown as text",
|
|
533
534
|
"unknownComponent": "This version cannot draw {{component}}",
|
|
534
535
|
"renderFailed": "Could not draw this part",
|
|
535
|
-
"tooLarge": "The block is too large to draw",
|
|
536
536
|
"unreadable": "The block could not be read",
|
|
537
537
|
"live": {
|
|
538
538
|
"label": "Live",
|
|
@@ -540,7 +540,26 @@
|
|
|
540
540
|
"sources": "Reads {{sources}}",
|
|
541
541
|
"failed": "Could not read {{source}}",
|
|
542
542
|
"refused": "Not allowed to read {{source}}",
|
|
543
|
-
"notRead": "Not read"
|
|
543
|
+
"notRead": "Not read",
|
|
544
|
+
"reasons": {
|
|
545
|
+
"access-unavailable": "The access of the chat that wrote this is no longer available.",
|
|
546
|
+
"block-stale": "This block changed since it was drawn.",
|
|
547
|
+
"busy": "Too many live blocks are reading right now.",
|
|
548
|
+
"link-unchecked": "This link has to be checked again.",
|
|
549
|
+
"link-unsupported": "This is not a link the machine can open.",
|
|
550
|
+
"links-unsupported": "The machine does not open links from blocks.",
|
|
551
|
+
"no-unique-match": "The source found no single match for that name.",
|
|
552
|
+
"outside-project": "This is outside the project the agent wrote this in.",
|
|
553
|
+
"query-undeclared": "This block does not read that source.",
|
|
554
|
+
"refresh-limit": "This source reads at most once every ten seconds.",
|
|
555
|
+
"result-too-large": "What the source returned is too large.",
|
|
556
|
+
"snapshot-too-large": "The first readings were too large to keep.",
|
|
557
|
+
"source-unregistered": "The machine does not know this source.",
|
|
558
|
+
"stale-read": "Read the source again before you choose.",
|
|
559
|
+
"target-unavailable": "What this points to is no longer available.",
|
|
560
|
+
"timed-out": "The source took too long to answer.",
|
|
561
|
+
"unreadable": "The source could not be read."
|
|
562
|
+
}
|
|
544
563
|
}
|
|
545
564
|
}
|
|
546
565
|
}
|
|
@@ -498,6 +498,7 @@
|
|
|
498
498
|
"from": "vanaf {{previous}}"
|
|
499
499
|
},
|
|
500
500
|
"table": {
|
|
501
|
+
"label": "Tabel van {{columns}}",
|
|
501
502
|
"showAll": "Alle {{total}} rijen tonen"
|
|
502
503
|
},
|
|
503
504
|
"chart": {
|
|
@@ -514,8 +515,10 @@
|
|
|
514
515
|
"outsideProject": "Buiten het project, als tekst getoond",
|
|
515
516
|
"options": "Opties",
|
|
516
517
|
"choices": "Keuzes",
|
|
518
|
+
"checklist": "Checklijst",
|
|
517
519
|
"choice": {
|
|
518
520
|
"waiting": "Beschikbaar zodra het antwoord klaar is",
|
|
521
|
+
"reading": "Beschikbaar zodra de live gegevens gelezen zijn",
|
|
519
522
|
"unavailable": "Niet beschikbaar",
|
|
520
523
|
"sent": "Verstuurd",
|
|
521
524
|
"queued": "In de wachtrij",
|
|
@@ -525,14 +528,11 @@
|
|
|
525
528
|
"answered": "Beantwoord met “{{label}}”",
|
|
526
529
|
"chose": "Gekozen: “{{label}}”",
|
|
527
530
|
"choseOlder": "Gekozen: “{{label}}”, bij het antwoord van {{time}}",
|
|
528
|
-
"sendContext": "Versturen",
|
|
529
|
-
"copyText": "Tekst kopiëren",
|
|
530
531
|
"fixes_one": "{{count}} correctie",
|
|
531
532
|
"fixes_other": "{{count}} correcties",
|
|
532
533
|
"shownAsText": "Als tekst getoond",
|
|
533
534
|
"unknownComponent": "Deze versie kan {{component}} niet tekenen",
|
|
534
535
|
"renderFailed": "Dit deel kon niet getekend worden",
|
|
535
|
-
"tooLarge": "Het blok is te groot om te tekenen",
|
|
536
536
|
"unreadable": "Het blok kon niet gelezen worden",
|
|
537
537
|
"live": {
|
|
538
538
|
"label": "Live",
|
|
@@ -540,7 +540,26 @@
|
|
|
540
540
|
"sources": "Leest {{sources}}",
|
|
541
541
|
"failed": "{{source}} lezen lukte niet",
|
|
542
542
|
"refused": "Geen toegang tot {{source}}",
|
|
543
|
-
"notRead": "Niet gelezen"
|
|
543
|
+
"notRead": "Niet gelezen",
|
|
544
|
+
"reasons": {
|
|
545
|
+
"access-unavailable": "De toegang van de chat die dit schreef is niet meer beschikbaar.",
|
|
546
|
+
"block-stale": "Dit blok is veranderd sinds het getekend werd.",
|
|
547
|
+
"busy": "Er lezen nu te veel live blokken tegelijk.",
|
|
548
|
+
"link-unchecked": "Deze link moet opnieuw gecontroleerd worden.",
|
|
549
|
+
"link-unsupported": "Dit is geen link die de machine kan openen.",
|
|
550
|
+
"links-unsupported": "De machine opent geen links uit blokken.",
|
|
551
|
+
"no-unique-match": "De bron vond voor die naam niet precies één overeenkomst.",
|
|
552
|
+
"outside-project": "Dit valt buiten het project waarin de agent dit schreef.",
|
|
553
|
+
"query-undeclared": "Dit blok leest die bron niet.",
|
|
554
|
+
"refresh-limit": "Deze bron leest hooguit eens per tien seconden.",
|
|
555
|
+
"result-too-large": "Wat de bron teruggaf is te groot.",
|
|
556
|
+
"snapshot-too-large": "De eerste metingen waren te groot om te bewaren.",
|
|
557
|
+
"source-unregistered": "De machine kent deze bron niet.",
|
|
558
|
+
"stale-read": "Lees de bron opnieuw voordat je kiest.",
|
|
559
|
+
"target-unavailable": "Waar dit naar verwijst is niet meer beschikbaar.",
|
|
560
|
+
"timed-out": "De bron deed er te lang over om te antwoorden.",
|
|
561
|
+
"unreadable": "De bron kon niet gelezen worden."
|
|
562
|
+
}
|
|
544
563
|
}
|
|
545
564
|
}
|
|
546
565
|
}
|
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 {
|
package/src/state/chats.ts
CHANGED
|
@@ -160,7 +160,11 @@ export function applyEvent(state: ChatState, event: ChatEvent): ChatState {
|
|
|
160
160
|
case 'delta': {
|
|
161
161
|
const item = state.items[event.itemId];
|
|
162
162
|
if (event.uiQueries && item?.kind === 'assistant') {
|
|
163
|
-
|
|
163
|
+
// The text first, as the daemon's thread applies it, then the metadata on what it grew into.
|
|
164
|
+
const { uiQueries, ...text } = event;
|
|
165
|
+
const grown = event.text === '' ? state : applyEvent(state, text);
|
|
166
|
+
const reply = grown.items[event.itemId] ?? item;
|
|
167
|
+
return { ...grown, items: { ...grown.items, [event.itemId]: { ...reply, uiQueries } as ChatItem } };
|
|
164
168
|
}
|
|
165
169
|
if (event.ui !== undefined && event.text === '') {
|
|
166
170
|
if (item?.kind === 'assistant' && item.streaming && event.textLength === item.text.length) {
|
|
@@ -190,6 +194,15 @@ export function applyEvent(state: ChatState, event: ChatEvent): ChatState {
|
|
|
190
194
|
}
|
|
191
195
|
}
|
|
192
196
|
|
|
197
|
+
/* Fields of a held chat that are not part of its thread; a chat this client does not hold stays as it is. */
|
|
198
|
+
function withFields(store: ChatsStore, key: string, fields: Pick<ChatState, 'bookmarks' | 'visuals'>): Partial<ChatsStore> {
|
|
199
|
+
const current = store.byKey[key];
|
|
200
|
+
if (!current) {
|
|
201
|
+
return {};
|
|
202
|
+
}
|
|
203
|
+
return { byKey: { ...store.byKey, [key]: { ...current, ...fields } } };
|
|
204
|
+
}
|
|
205
|
+
|
|
193
206
|
export const useChats = create<ChatsStore>((set) => ({
|
|
194
207
|
byKey: {},
|
|
195
208
|
statusByKey: {},
|
|
@@ -243,22 +256,10 @@ export const useChats = create<ChatsStore>((set) => ({
|
|
|
243
256
|
});
|
|
244
257
|
},
|
|
245
258
|
bookmarks(key, bookmarks) {
|
|
246
|
-
set((s) => {
|
|
247
|
-
const current = s.byKey[key];
|
|
248
|
-
if (!current) {
|
|
249
|
-
return {};
|
|
250
|
-
}
|
|
251
|
-
return { byKey: { ...s.byKey, [key]: { ...current, bookmarks } } };
|
|
252
|
-
});
|
|
259
|
+
set((s) => withFields(s, key, { bookmarks }));
|
|
253
260
|
},
|
|
254
261
|
visuals(key, visuals) {
|
|
255
|
-
set((s) => {
|
|
256
|
-
const current = s.byKey[key];
|
|
257
|
-
if (!current) {
|
|
258
|
-
return {};
|
|
259
|
-
}
|
|
260
|
-
return { byKey: { ...s.byKey, [key]: { ...current, visuals } } };
|
|
261
|
-
});
|
|
262
|
+
set((s) => withFields(s, key, { visuals }));
|
|
262
263
|
},
|
|
263
264
|
forget(key) {
|
|
264
265
|
set((s) => {
|