@adecore/agents-react 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/chat-client.d.ts +1 -0
- package/dist/chat/logic/generated-image.d.ts +27 -0
- package/dist/chat/logic/generated-image.js +32 -0
- package/dist/chat/logic/timeline-target.d.ts +19 -1
- package/dist/chat/logic/timeline-target.js +49 -3
- package/dist/chat/logic/timeline.js +25 -17
- package/dist/chat/subagent-conversation.d.ts +2 -1
- package/dist/chat/subagent-conversation.js +7 -1
- package/dist/chat/timeline-flash.d.ts +3 -1
- package/dist/chat/timeline-flash.js +2 -2
- package/dist/chat/ui/CodeBlock.d.ts +3 -1
- package/dist/chat/ui/CodeBlock.js +38 -7
- package/dist/chat/ui/Composer.js +13 -3
- package/dist/chat/ui/ImageView.d.ts +8 -2
- package/dist/chat/ui/ImageView.js +12 -6
- package/dist/chat/ui/Markdown.d.ts +7 -1
- package/dist/chat/ui/Markdown.js +80 -23
- package/dist/chat/ui/MessageActions.js +6 -7
- package/dist/chat/ui/SubagentTimeline.js +7 -3
- package/dist/chat/ui/Timeline.js +68 -8
- package/dist/chat/ui/TimelineMenu.js +7 -3
- package/dist/chat/ui/file-links.d.ts +2 -1
- package/dist/chat/ui/file-links.js +8 -3
- package/dist/chat/ui/intelligent-ui/UiBlockFooter.d.ts +15 -0
- package/dist/chat/ui/intelligent-ui/UiBlockFooter.js +50 -0
- package/dist/chat/ui/intelligent-ui/UiBlockFrame.d.ts +10 -0
- package/dist/chat/ui/intelligent-ui/UiBlockFrame.js +61 -0
- package/dist/chat/ui/intelligent-ui/UiFallbackPart.d.ts +10 -0
- package/dist/chat/ui/intelligent-ui/UiFallbackPart.js +11 -0
- package/dist/chat/ui/intelligent-ui/UiReply.d.ts +13 -0
- package/dist/chat/ui/intelligent-ui/UiReply.js +325 -0
- package/dist/chat/ui/intelligent-ui/block-local.d.ts +2 -0
- package/dist/chat/ui/intelligent-ui/block-local.js +13 -0
- package/dist/chat/ui/intelligent-ui/chart-data.d.ts +16 -0
- package/dist/chat/ui/intelligent-ui/chart-data.js +46 -0
- package/dist/chat/ui/intelligent-ui/node-text.d.ts +9 -0
- package/dist/chat/ui/intelligent-ui/node-text.js +52 -0
- package/dist/chat/ui/intelligent-ui/registry.d.ts +2 -0
- package/dist/chat/ui/intelligent-ui/registry.js +50 -0
- package/dist/chat/ui/intelligent-ui/render-context.d.ts +50 -0
- package/dist/chat/ui/intelligent-ui/render-context.js +3 -0
- package/dist/chat/ui/intelligent-ui/renderers/chart.d.ts +3 -0
- package/dist/chat/ui/intelligent-ui/renderers/chart.js +125 -0
- package/dist/chat/ui/intelligent-ui/renderers/choices.d.ts +4 -0
- package/dist/chat/ui/intelligent-ui/renderers/choices.js +41 -0
- package/dist/chat/ui/intelligent-ui/renderers/content.d.ts +14 -0
- package/dist/chat/ui/intelligent-ui/renderers/content.js +66 -0
- package/dist/chat/ui/intelligent-ui/renderers/data.d.ts +7 -0
- package/dist/chat/ui/intelligent-ui/renderers/data.js +87 -0
- package/dist/chat/ui/intelligent-ui/renderers/inputs.d.ts +7 -0
- package/dist/chat/ui/intelligent-ui/renderers/inputs.js +60 -0
- package/dist/chat/ui/intelligent-ui/renderers/links.d.ts +10 -0
- package/dist/chat/ui/intelligent-ui/renderers/links.js +86 -0
- package/dist/chat/ui/intelligent-ui/renderers/structure.d.ts +6 -0
- package/dist/chat/ui/intelligent-ui/renderers/structure.js +32 -0
- package/dist/chat/ui/intelligent-ui/renderers/text.d.ts +8 -0
- package/dist/chat/ui/intelligent-ui/renderers/text.js +61 -0
- package/dist/chat/ui/intelligent-ui/reply-parts.d.ts +9 -0
- package/dist/chat/ui/intelligent-ui/reply-parts.js +18 -0
- package/dist/chat/ui/intelligent-ui/table-data.d.ts +31 -0
- package/dist/chat/ui/intelligent-ui/table-data.js +79 -0
- package/dist/chat/ui/intelligent-ui/tones.d.ts +7 -0
- package/dist/chat/ui/intelligent-ui/tones.js +31 -0
- package/dist/chat/ui/intelligent-ui/use-later.d.ts +1 -0
- package/dist/chat/ui/intelligent-ui/use-later.js +16 -0
- package/dist/chat/ui/intelligent-ui/use-ui-links.d.ts +9 -0
- package/dist/chat/ui/intelligent-ui/use-ui-links.js +107 -0
- package/dist/chat/ui/intelligent-ui/use-ui-queries.d.ts +20 -0
- package/dist/chat/ui/intelligent-ui/use-ui-queries.js +259 -0
- package/dist/chat/ui/reply-context.d.ts +8 -0
- package/dist/chat/ui/reply-context.js +1 -0
- package/dist/chat/ui/rows/GeneratedImageRow.d.ts +5 -0
- package/dist/chat/ui/rows/GeneratedImageRow.js +121 -0
- package/dist/chat/ui/rows/MessageRows.js +27 -7
- package/dist/chat/ui/rows/Rows.js +4 -2
- package/dist/chat/ui/rows/SubagentRow.js +5 -0
- package/dist/chat/ui/rows/WorkRows.d.ts +4 -1
- package/dist/chat/ui/rows/WorkRows.js +4 -3
- package/dist/host.d.ts +25 -3
- package/dist/host.js +1 -0
- package/dist/locales/en/agent-chat.json +89 -1
- package/dist/locales/nl/agent-chat.json +89 -1
- package/dist/state/chats.js +9 -0
- package/dist/theme.css +38 -2
- package/package.json +133 -7
- package/src/chat/chat-client.ts +1 -0
- package/src/chat/logic/generated-image.ts +48 -0
- package/src/chat/logic/timeline-target.ts +69 -4
- package/src/chat/logic/timeline.ts +28 -17
- package/src/chat/subagent-conversation.ts +13 -2
- package/src/chat/timeline-flash.ts +5 -3
- package/src/chat/ui/CodeBlock.tsx +70 -21
- package/src/chat/ui/Composer.tsx +22 -5
- package/src/chat/ui/ImageView.tsx +51 -8
- package/src/chat/ui/Markdown.tsx +123 -26
- package/src/chat/ui/MessageActions.tsx +15 -8
- package/src/chat/ui/SubagentTimeline.tsx +26 -1
- package/src/chat/ui/Timeline.tsx +98 -22
- package/src/chat/ui/TimelineMenu.tsx +6 -3
- package/src/chat/ui/file-links.ts +9 -3
- package/src/chat/ui/intelligent-ui/UiBlockFooter.tsx +139 -0
- package/src/chat/ui/intelligent-ui/UiBlockFrame.tsx +89 -0
- package/src/chat/ui/intelligent-ui/UiFallbackPart.tsx +21 -0
- package/src/chat/ui/intelligent-ui/UiReply.tsx +531 -0
- package/src/chat/ui/intelligent-ui/block-local.ts +16 -0
- package/src/chat/ui/intelligent-ui/chart-data.ts +67 -0
- package/src/chat/ui/intelligent-ui/node-text.ts +59 -0
- package/src/chat/ui/intelligent-ui/registry.ts +52 -0
- package/src/chat/ui/intelligent-ui/render-context.ts +78 -0
- package/src/chat/ui/intelligent-ui/renderers/chart.tsx +321 -0
- package/src/chat/ui/intelligent-ui/renderers/choices.tsx +98 -0
- package/src/chat/ui/intelligent-ui/renderers/content.tsx +145 -0
- package/src/chat/ui/intelligent-ui/renderers/data.tsx +187 -0
- package/src/chat/ui/intelligent-ui/renderers/inputs.tsx +121 -0
- package/src/chat/ui/intelligent-ui/renderers/links.tsx +157 -0
- package/src/chat/ui/intelligent-ui/renderers/structure.tsx +84 -0
- package/src/chat/ui/intelligent-ui/renderers/text.tsx +124 -0
- package/src/chat/ui/intelligent-ui/reply-parts.ts +22 -0
- package/src/chat/ui/intelligent-ui/table-data.ts +104 -0
- package/src/chat/ui/intelligent-ui/tones.ts +37 -0
- package/src/chat/ui/intelligent-ui/use-later.ts +17 -0
- package/src/chat/ui/intelligent-ui/use-ui-links.ts +123 -0
- package/src/chat/ui/intelligent-ui/use-ui-queries.ts +282 -0
- package/src/chat/ui/reply-context.ts +7 -0
- package/src/chat/ui/rows/GeneratedImageRow.tsx +244 -0
- package/src/chat/ui/rows/MessageRows.tsx +69 -7
- package/src/chat/ui/rows/Rows.tsx +4 -2
- package/src/chat/ui/rows/SubagentRow.tsx +5 -0
- package/src/chat/ui/rows/WorkRows.tsx +20 -5
- package/src/host.ts +46 -3
- package/src/locales/en/agent-chat.json +89 -1
- package/src/locales/nl/agent-chat.json +89 -1
- package/src/state/chats.ts +9 -0
- package/src/theme.css +38 -2
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import type { UiReplyTarget } from '../logic/timeline-target.js';
|
|
1
2
|
import type { ChatInfo } from '@adecore/agent-contracts';
|
|
2
3
|
export declare const ReplyContext: import("react").Context<{
|
|
3
4
|
provider: ChatInfo['provider'];
|
|
4
5
|
chatId?: string;
|
|
5
6
|
} | null>;
|
|
7
|
+
export declare const UiReplyNavigationContext: import("react").Context<{
|
|
8
|
+
chatId: string;
|
|
9
|
+
reveal(target: UiReplyTarget): void;
|
|
10
|
+
flash: (UiReplyTarget & {
|
|
11
|
+
nonce: number;
|
|
12
|
+
}) | null;
|
|
13
|
+
} | null>;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { Trans, useTranslation } from 'react-i18next';
|
|
5
|
+
import { Check, Copy, Ellipsis, ExternalLink, FolderDown, ImageIcon, Maximize2 } from 'lucide-react';
|
|
6
|
+
import { Button, ButtonGroup, copyText, ErrorBoundary, FileIcon, Icon, IconButton, Menu, Surface } from '@adecore/ui';
|
|
7
|
+
import { chatHost } from '../../../host.js';
|
|
8
|
+
import { useChatScope } from '../../../scope.js';
|
|
9
|
+
import { useCurrentItem } from '../../../state/chats.js';
|
|
10
|
+
import { formatBytes } from '../../attachments.js';
|
|
11
|
+
import { attachmentAspect, generatedImageView } from '../../logic/generated-image.js';
|
|
12
|
+
import { toolStartedAt } from '../../logic/tools.js';
|
|
13
|
+
import { CHIP_IN_MESSAGE, MENTION_TONE } from '../chips.js';
|
|
14
|
+
import { openFileLink, useFileLinkCwd } from '../file-links.js';
|
|
15
|
+
import { ImageThumb } from '../ImageView.js';
|
|
16
|
+
import { ROW_GUTTER } from '../icons.js';
|
|
17
|
+
import { RunningFor, WorkRow } from './WorkRows.js';
|
|
18
|
+
const SAVED_FLASH_MS = 2000;
|
|
19
|
+
// Where each image went, so a row the thread unmounts while scrolling still says so when it comes back.
|
|
20
|
+
const savedPaths = new Map();
|
|
21
|
+
/* True for `ms` after `start()`, for a check mark that says an action landed. */
|
|
22
|
+
function useFlash(ms) {
|
|
23
|
+
const [on, setOn] = useState(false);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!on) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const timer = setTimeout(() => setOn(false), ms);
|
|
29
|
+
return () => clearTimeout(timer);
|
|
30
|
+
}, [on, ms]);
|
|
31
|
+
return [on, () => setOn(true)];
|
|
32
|
+
}
|
|
33
|
+
function failureText(failure, t) {
|
|
34
|
+
switch (failure.kind) {
|
|
35
|
+
case 'provider':
|
|
36
|
+
return failure.message ?? undefined;
|
|
37
|
+
case 'empty':
|
|
38
|
+
return t('generatedImage.empty');
|
|
39
|
+
case 'not-image':
|
|
40
|
+
return t('generatedImage.notImage');
|
|
41
|
+
case 'too-large':
|
|
42
|
+
return t('generatedImage.tooLarge', { size: formatBytes(failure.limit) });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/* The line over the image, in the measures of a tool line but nothing to fold. */
|
|
46
|
+
function HeadLine({ label, detail, live, startedAt }) {
|
|
47
|
+
return (_jsxs("div", { className: "-mx-1 mb-0.5 flex h-7 items-center gap-2 px-1 text-xs text-text-muted", children: [_jsx("span", { className: clsx(ROW_GUTTER, live && 'text-accent'), children: _jsx(Icon, { icon: ImageIcon, size: 12 }) }), _jsx("span", { className: clsx('shrink-0', live && 'chat-live-text'), children: label }), detail && _jsx("span", { className: "min-w-0 truncate text-text-faint", children: detail }), _jsx("span", { className: "grow" }), startedAt !== undefined && _jsx(RunningFor, { startedAt: startedAt })] }));
|
|
48
|
+
}
|
|
49
|
+
/* The file a saved image became, which opens where the app opens a file link. */
|
|
50
|
+
function SavedFile({ path }) {
|
|
51
|
+
const cwd = useFileLinkCwd();
|
|
52
|
+
const { id } = useChatScope();
|
|
53
|
+
const chip = (_jsxs(_Fragment, { children: [_jsx(FileIcon, { path: path, size: 14 }), _jsx("span", { className: "truncate", children: path })] }));
|
|
54
|
+
if (chatHost().fileLinks === null) {
|
|
55
|
+
return _jsx("span", { className: clsx(CHIP_IN_MESSAGE, MENTION_TONE), children: chip });
|
|
56
|
+
}
|
|
57
|
+
return (_jsx("button", { type: "button", className: clsx(CHIP_IN_MESSAGE, MENTION_TONE, 'hover:brightness-95'), "data-file-path": path, onClick: () => openFileLink(cwd, { path, directory: false }, id), children: chip }));
|
|
58
|
+
}
|
|
59
|
+
function ReadyImage({ chatId, attachment, prompt, transparent }) {
|
|
60
|
+
const { t } = useTranslation('agent-chat');
|
|
61
|
+
const { id: scopeId } = useChatScope();
|
|
62
|
+
const { attachments } = chatHost();
|
|
63
|
+
const source = attachments.useUrl(scopeId, chatId, attachment.id);
|
|
64
|
+
const savedKey = `${scopeId}\n${chatId}\n${attachment.id}`;
|
|
65
|
+
const [lightbox, setLightbox] = useState(false);
|
|
66
|
+
const [saving, setSaving] = useState(false);
|
|
67
|
+
const [savedPath, setSavedPath] = useState(() => savedPaths.get(savedKey) ?? null);
|
|
68
|
+
const [savedFlash, flashSaved] = useFlash(SAVED_FLASH_MS);
|
|
69
|
+
const missing = source.failure !== null;
|
|
70
|
+
const aspect = attachmentAspect(attachment);
|
|
71
|
+
const { open, saveToProject } = attachments;
|
|
72
|
+
const detail = [
|
|
73
|
+
attachment.width !== undefined && attachment.height !== undefined
|
|
74
|
+
? t('generatedImage.dimensions', { width: attachment.width, height: attachment.height })
|
|
75
|
+
: null,
|
|
76
|
+
formatBytes(attachment.size),
|
|
77
|
+
transparent ? t('generatedImage.transparent') : null
|
|
78
|
+
]
|
|
79
|
+
.filter((part) => part !== null)
|
|
80
|
+
.join(' · ');
|
|
81
|
+
const openFile = open === undefined ? undefined : () => open(scopeId, chatId, attachment.id, attachment.name);
|
|
82
|
+
const save = saveToProject === undefined
|
|
83
|
+
? undefined
|
|
84
|
+
: async () => {
|
|
85
|
+
setSaving(true);
|
|
86
|
+
try {
|
|
87
|
+
const path = await saveToProject(scopeId, chatId, attachment.id, attachment.name);
|
|
88
|
+
if (path !== null) {
|
|
89
|
+
savedPaths.set(savedKey, path);
|
|
90
|
+
setSavedPath(path);
|
|
91
|
+
flashSaved();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// The host's dialog shows why; the row stays as it was.
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
setSaving(false);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const lightboxActions = (_jsxs(_Fragment, { children: [openFile !== undefined && _jsx(IconButton, { icon: ExternalLink, size: "sm", label: t('generatedImage.open'), onClick: openFile }), save !== undefined && _jsx(IconButton, { icon: FolderDown, size: "sm", label: t('generatedImage.save'), disabled: saving, onClick: () => void save() })] }));
|
|
102
|
+
return (_jsxs("div", { children: [_jsx(HeadLine, { label: t('generatedImage.label'), detail: detail }), _jsxs("div", { className: "flex max-w-90 flex-col gap-1.5", children: [_jsxs("div", { className: clsx('group/image relative', aspect === undefined && 'w-fit', transparent && source.url !== null && 'chat-checkerboard rounded-lg'), children: [_jsx(ImageThumb, { source: source, alt: attachment.name, aspect: aspect, className: aspect === undefined ? 'max-h-90 max-w-full object-contain' : undefined, actions: lightboxActions, open: lightbox, onOpenChange: setLightbox }), source.url !== null && (_jsx(Surface, { role: "toolbar", "aria-label": t('generatedImage.actions'), className: "absolute top-2 right-2 rounded-lg p-0.5 opacity-0 transition-opacity group-focus-within/image:opacity-100 group-hover/image:opacity-100 has-[[data-popup-open]]:opacity-100 pointer-coarse:opacity-100", children: _jsxs(ButtonGroup, { children: [_jsx(IconButton, { icon: Maximize2, size: "sm", label: t('generatedImage.openLarge'), onClick: () => setLightbox(true) }), prompt !== null && (_jsxs(Menu.Root, { children: [_jsx(IconButton, { icon: Ellipsis, size: "sm", label: t('generatedImage.more'), render: _jsx(Menu.Trigger, {}) }), _jsx(Menu.Popup, { align: "end", children: _jsxs(Menu.Item, { onClick: () => copyText(prompt), children: [_jsx(Icon, { icon: Copy, size: 14 }), " ", t('generatedImage.copyPrompt')] }) })] }))] }) }))] }), (openFile !== undefined || save !== undefined) && (_jsxs("div", { className: "flex items-center gap-1.5", children: [openFile !== undefined && (_jsx(Button, { size: "xs", variant: "secondary", disabled: missing, onClick: openFile, children: t('generatedImage.open') })), save !== undefined && (_jsx(Button, { size: "xs", variant: "secondary", disabled: missing || saving || savedFlash, onClick: () => void save(), children: savedFlash ? (_jsxs(_Fragment, { children: [_jsx(Icon, { icon: Check, size: 12 }), " ", t('generatedImage.saved')] })) : (t('generatedImage.save')) }))] })), savedPath !== null && !savedFlash && (_jsx("div", { className: "flex min-w-0 items-center gap-1.5 text-xs text-text-muted", children: _jsx(Trans, { t: t, i18nKey: "generatedImage.savedTo", values: { path: savedPath }, components: { file: _jsx(SavedFile, { path: savedPath }) } }) }))] })] }));
|
|
103
|
+
}
|
|
104
|
+
/*
|
|
105
|
+
* The row of an image generation. Not a fold like other tool calls: the image is the result a person
|
|
106
|
+
* came for, so it stays open, opens large in the lightbox and offers what the host lets a person do
|
|
107
|
+
* with it. A failure is an ordinary failed tool line, with the reason as its detail.
|
|
108
|
+
*/
|
|
109
|
+
export function GeneratedImageRow({ chatId, tool: derived }) {
|
|
110
|
+
const { t } = useTranslation('agent-chat');
|
|
111
|
+
const tool = useCurrentItem(chatId, derived);
|
|
112
|
+
const view = generatedImageView(tool);
|
|
113
|
+
switch (view.state) {
|
|
114
|
+
case 'generating':
|
|
115
|
+
return _jsx(HeadLine, { label: t('generatedImage.generating'), live: true, startedAt: toolStartedAt(tool) });
|
|
116
|
+
case 'failed':
|
|
117
|
+
return (_jsx(WorkRow, { tool: tool, icon: _jsx(Icon, { icon: ImageIcon, size: 12 }), label: t('generatedImage.failed'), detail: failureText(view.failure, t) ?? '', failed: true }));
|
|
118
|
+
case 'ready':
|
|
119
|
+
return (_jsx(ErrorBoundary, { label: t('generatedImage.renderFailed'), resetKeys: [view.attachment], compact: true, className: "relative rounded-lg", children: _jsx(ReadyImage, { chatId: chatId, attachment: view.attachment, prompt: view.prompt, transparent: view.transparent }) }));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useContext, useState } from 'react';
|
|
2
|
+
import { useContext, useMemo, useState } from 'react';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
-
import { Bot, Brain, Check, ChevronDown, CircleAlert, File, Info, MessageCircleQuestionMark, TriangleAlert, X } from 'lucide-react';
|
|
5
|
+
import { Bot, Brain, Check, ChevronDown, CircleAlert, File, Info, MessageCircleQuestionMark, Reply, TriangleAlert, X } from 'lucide-react';
|
|
6
6
|
import { fileBadge, formatBytes, isImageAttachment } from '../../attachments.js';
|
|
7
7
|
import { useChatRow, useCurrentItem } from '../../../state/chats.js';
|
|
8
8
|
import { chatHost } from '../../../host.js';
|
|
@@ -15,12 +15,13 @@ import { FadingWords } from '../FadingWords.js';
|
|
|
15
15
|
import { settledBlocksText } from '../markdown-blocks.js';
|
|
16
16
|
import { WHOLE_FADE_CLASS } from '../rehype-fade.js';
|
|
17
17
|
import { useRevealedText } from '../reveal.js';
|
|
18
|
-
import { formatAgo, formatElapsedShort, formatTokens } from '@adecore/ui/format';
|
|
18
|
+
import { formatAgo, formatElapsedShort, formatMoment, formatTokens } from '@adecore/ui/format';
|
|
19
19
|
import { Icon, Tooltip, useTickingText } from '@adecore/ui';
|
|
20
20
|
import { toolSummary } from '../../logic/tools.js';
|
|
21
21
|
import { ROW_GUTTER } from '../icons.js';
|
|
22
22
|
import { useOpenForFind } from '../find-reveal.js';
|
|
23
|
-
import { ReplyContext } from '../reply-context.js';
|
|
23
|
+
import { ReplyContext, UiReplyNavigationContext } from '../reply-context.js';
|
|
24
|
+
import { UiReply } from '../intelligent-ui/UiReply.js';
|
|
24
25
|
// A long prompt folds so the answer stays in view; the reader can open it.
|
|
25
26
|
const USER_FOLD_LINES = 8;
|
|
26
27
|
const USER_FOLD_CHARS = 600;
|
|
@@ -55,7 +56,20 @@ export function UserRow({ chatId, item }) {
|
|
|
55
56
|
const attachments = item.attachments ?? [];
|
|
56
57
|
const chats = item.chats ?? [];
|
|
57
58
|
useOpenForFind(item.id, 'text', setOpen);
|
|
58
|
-
return (_jsxs("div", { "data-find-item": item.id, className: "flex flex-col items-end", children: [_jsx(MessageHeading, { children: t('rows.user.heading') }), attachments.length > 0 && (_jsx("div", { className: "mb-1.5 flex max-w-[80%] flex-wrap justify-end gap-1.5", children: attachments.map((attachment) => isImageAttachment(attachment.mime) ? (_jsx(AttachmentThumb, { chatId: chatId, attachment: attachment }, attachment.id)) : (_jsx(AttachmentLink, { chatId: chatId, attachment: attachment }, attachment.id))) })), chats.length > 0 && (_jsx("div", { className: "mb-1.5 flex max-w-[80%] flex-wrap justify-end gap-1.5", children: chats.map((id) => (_jsx(ChatReferenceChip, { chatId: id }, id))) })), item.text !== '' && (_jsxs("div", { className: "relative max-w-[80%] rounded-2xl bg-surface-active px-3.5 py-2.5 text-sm wrap-anywhere text-text select-text", children: [_jsx("div", { "data-find-field": "text", className: clsx(long && !open && FOLD), children: _jsx(MessageMarkdown, { text: item.text, mentions: item.mentions, skills: item.skills }) }), long && (_jsxs("button", { className: "mt-1 flex items-center gap-1 text-xs text-text-muted hover:text-text", onClick: () => setOpen((o) => !o), children: [_jsx(Icon, { icon: ChevronDown, size: 12, className: clsx('transition-transform', open && 'rotate-180') }), ' ', open ? t('rows.user.showLess') : t('rows.user.showAll')] }))] }))] }));
|
|
59
|
+
return (_jsxs("div", { "data-find-item": item.id, className: "flex flex-col items-end", children: [_jsx(MessageHeading, { children: t('rows.user.heading') }), attachments.length > 0 && (_jsx("div", { className: "mb-1.5 flex max-w-[80%] flex-wrap justify-end gap-1.5", children: attachments.map((attachment) => isImageAttachment(attachment.mime) ? (_jsx(AttachmentThumb, { chatId: chatId, attachment: attachment }, attachment.id)) : (_jsx(AttachmentLink, { chatId: chatId, attachment: attachment }, attachment.id))) })), chats.length > 0 && (_jsx("div", { className: "mb-1.5 flex max-w-[80%] flex-wrap justify-end gap-1.5", children: chats.map((id) => (_jsx(ChatReferenceChip, { chatId: id }, id))) })), item.uiChoice !== undefined && _jsx(ChoiceLine, { chatId: chatId, choice: item.uiChoice }), item.text !== '' && (_jsxs("div", { className: "relative max-w-[80%] rounded-2xl bg-surface-active px-3.5 py-2.5 text-sm wrap-anywhere text-text select-text", children: [_jsx("div", { "data-find-field": "text", className: clsx(long && !open && FOLD), children: _jsx(MessageMarkdown, { text: item.text, mentions: item.mentions, skills: item.skills }) }), long && (_jsxs("button", { className: "mt-1 flex items-center gap-1 text-xs text-text-muted hover:text-text", onClick: () => setOpen((o) => !o), children: [_jsx(Icon, { icon: ChevronDown, size: 12, className: clsx('transition-transform', open && 'rotate-180') }), ' ', open ? t('rows.user.showLess') : t('rows.user.showAll')] }))] }))] }));
|
|
60
|
+
}
|
|
61
|
+
/*
|
|
62
|
+
* The choice a message answers. The label stays out of the message, which holds exactly what the agent
|
|
63
|
+
* read, and out of a copied selection; a screen reader hears it between the heading and the message.
|
|
64
|
+
*/
|
|
65
|
+
function ChoiceLine({ chatId, choice }) {
|
|
66
|
+
const { t } = useTranslation('agent-chat');
|
|
67
|
+
const inherited = useContext(UiReplyNavigationContext);
|
|
68
|
+
const navigation = inherited?.chatId === chatId ? inherited : null;
|
|
69
|
+
const Tag = navigation ? 'button' : 'div';
|
|
70
|
+
return (_jsxs(Tag, { type: navigation ? 'button' : undefined, onClick: navigation ? () => navigation.reveal(choice) : undefined, className: clsx('mb-1 flex max-w-[80%] items-start gap-1.5 px-1 text-left text-xs text-text-muted select-none', navigation && 'rounded-md hover:text-text focus-visible:outline-2 focus-visible:outline-accent'), children: [_jsx(Icon, { icon: Reply, size: 12, className: "mt-1 shrink-0" }), _jsx("span", { className: "min-w-0 wrap-anywhere", children: choice.older
|
|
71
|
+
? t('blocks.choseOlder', { label: choice.label, time: formatMoment(choice.sourceAt) })
|
|
72
|
+
: t('blocks.chose', { label: choice.label }) })] }));
|
|
59
73
|
}
|
|
60
74
|
/*
|
|
61
75
|
* Who wrote a message, for a screen reader only: one heading per message is what lets VoiceOver's
|
|
@@ -107,18 +121,24 @@ function Writing() {
|
|
|
107
121
|
*/
|
|
108
122
|
export function AssistantRow({ chatId, item: derived }) {
|
|
109
123
|
const item = useCurrentItem(chatId, derived);
|
|
124
|
+
const scope = useChatScope();
|
|
125
|
+
const context = useContext(ReplyContext);
|
|
126
|
+
const reply = useMemo(() => (context === null && !item.parentToolUseId ? { scopeId: scope.id, chatId, itemId: item.id, streaming: item.streaming } : undefined), [context, item.parentToolUseId, scope.id, chatId, item.id, item.streaming]);
|
|
110
127
|
const mode = chatHost().useStreaming();
|
|
111
128
|
const [sawWriting] = useState(item.streaming);
|
|
112
129
|
const live = mode === 'words' && item.streaming;
|
|
113
130
|
const reveal = useRevealedText(item.text, live);
|
|
131
|
+
if (item.ui?.length && !item.parentToolUseId && !(mode === 'whole' && item.streaming)) {
|
|
132
|
+
return (_jsxs("div", { "data-find-item": item.id, className: "-mx-1 px-1 pb-2", children: [_jsx(ReplyHeading, { chatId: chatId }), _jsx("div", { "data-find-field": "text", "data-quote-answer": true, className: "contents", children: _jsx(UiReply, { text: item.text, blocks: item.ui, answers: item.uiAnswers, queries: item.uiQueries, reply: reply, context: { scopeId: scope.id, chatId, itemId: item.id, phase: item.streaming ? 'streaming' : 'final', answer: null } }) })] }));
|
|
133
|
+
}
|
|
114
134
|
if (mode === 'blocks') {
|
|
115
135
|
const settled = item.streaming ? settledBlocksText(item.text) : item.text;
|
|
116
|
-
return (_jsxs("div", { "data-find-item": item.id, className: "-mx-1 px-1 pb-2", children: [_jsx(ReplyHeading, { chatId: chatId }), settled !== '' && (_jsx("div", { "data-find-field": "text", "data-quote-answer": true, className: "contents", children: _jsx(ReplyMarkdown, { text: settled, streaming: false, arriving: sawWriting }) })), item.streaming && _jsx(Writing, {})] }));
|
|
136
|
+
return (_jsxs("div", { "data-find-item": item.id, className: "-mx-1 px-1 pb-2", children: [_jsx(ReplyHeading, { chatId: chatId }), settled !== '' && (_jsx("div", { "data-find-field": "text", "data-quote-answer": true, className: "contents", children: _jsx(ReplyMarkdown, { text: settled, streaming: false, arriving: sawWriting, reply: reply }) })), item.streaming && _jsx(Writing, {})] }));
|
|
117
137
|
}
|
|
118
138
|
if (mode === 'whole' && item.streaming) {
|
|
119
139
|
return (_jsxs("div", { className: "-mx-1 px-1 pb-2", children: [_jsx(ReplyHeading, { chatId: chatId }), _jsx(Writing, {})] }));
|
|
120
140
|
}
|
|
121
|
-
return (_jsxs("div", { "data-find-item": item.id, className: clsx('-mx-1 px-1 pb-2', mode === 'whole' && sawWriting && WHOLE_FADE_CLASS), children: [_jsx(ReplyHeading, { chatId: chatId }), _jsx("div", { "data-find-field": "text", "data-quote-answer": true, className: "contents", children: _jsx(ReplyMarkdown, { text: reveal.text, streaming: reveal.active }) }), live && item.text === '' && _jsx("span", { className: "inline-block h-3.5 w-1.5 animate-pulse rounded-sm bg-text-faint align-middle" })] }));
|
|
141
|
+
return (_jsxs("div", { "data-find-item": item.id, className: clsx('-mx-1 px-1 pb-2', mode === 'whole' && sawWriting && WHOLE_FADE_CLASS), children: [_jsx(ReplyHeading, { chatId: chatId }), _jsx("div", { "data-find-field": "text", "data-quote-answer": true, className: "contents", children: _jsx(ReplyMarkdown, { text: reveal.text, streaming: reveal.active, reply: reply }) }), live && item.text === '' && _jsx("span", { className: "inline-block h-3.5 w-1.5 animate-pulse rounded-sm bg-text-faint align-middle" })] }));
|
|
122
142
|
}
|
|
123
143
|
/*
|
|
124
144
|
* What the model thought before it answered. It shimmers while it streams and folds itself away
|
|
@@ -2,7 +2,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { ErrorBoundary } from '@adecore/ui';
|
|
4
4
|
import { AgentTurnRow, ApprovalHistoryRow, AssistantRow, CompactionRow, NoteRow, QuestionHistoryRow, ReportRow, ThinkingRow, UserRow } from './MessageRows.js';
|
|
5
|
+
import { isImageGeneration } from '../../logic/generated-image.js';
|
|
5
6
|
import { ForksRow } from './ForksRow.js';
|
|
7
|
+
import { GeneratedImageRow } from './GeneratedImageRow.js';
|
|
6
8
|
import { SubagentBranchRow } from './SubagentRow.js';
|
|
7
9
|
import { VisualRow } from './VisualRow.js';
|
|
8
10
|
import { WorkflowRow } from './WorkflowRow.js';
|
|
@@ -31,9 +33,9 @@ export function Row({ row, chatId, toggleGroup, toggleTurn, toggleSubagent, open
|
|
|
31
33
|
case 'thinking':
|
|
32
34
|
return _jsx(ThinkingRow, { chatId: chatId, item: row.item });
|
|
33
35
|
case 'work':
|
|
34
|
-
return _jsx(WorkRow, { tool: row.tool });
|
|
36
|
+
return isImageGeneration(row.tool) ? _jsx(GeneratedImageRow, { chatId: chatId, tool: row.tool }) : _jsx(WorkRow, { tool: row.tool });
|
|
35
37
|
case 'work-live':
|
|
36
|
-
return _jsx(WorkLiveRow, { chatId: chatId, tool: row.tool });
|
|
38
|
+
return isImageGeneration(row.tool) ? _jsx(GeneratedImageRow, { chatId: chatId, tool: row.tool }) : _jsx(WorkLiveRow, { chatId: chatId, tool: row.tool });
|
|
37
39
|
case 'workflow':
|
|
38
40
|
return _jsx(WorkflowRow, { chatId: chatId, tool: row.tool, workflow: row.workflow, onOpenAgent: openConversation });
|
|
39
41
|
case 'work-group':
|
|
@@ -8,6 +8,8 @@ import { Icon, useNow } from '@adecore/ui';
|
|
|
8
8
|
import { useOpenForFind } from '../find-reveal.js';
|
|
9
9
|
import { Markdown } from '../Markdown.js';
|
|
10
10
|
import { TaskRow } from './TaskRow.js';
|
|
11
|
+
import { isImageGeneration } from '../../logic/generated-image.js';
|
|
12
|
+
import { GeneratedImageRow } from './GeneratedImageRow.js';
|
|
11
13
|
import { RunningFor, ToggleLine, WorkLiveRow, WorkRow } from './WorkRows.js';
|
|
12
14
|
import { entryTimeOf, statusWordOf, taskIdOf } from '../../subagent-list.js';
|
|
13
15
|
import { useSubagentSupport } from '../../subagent-support.js';
|
|
@@ -24,6 +26,9 @@ const CHILDREN_MAX_PX = 320;
|
|
|
24
26
|
*/
|
|
25
27
|
function ChildRow({ chatId, item }) {
|
|
26
28
|
if (item.kind === 'tool') {
|
|
29
|
+
if (isImageGeneration(item)) {
|
|
30
|
+
return _jsx(GeneratedImageRow, { chatId: chatId, tool: item });
|
|
31
|
+
}
|
|
27
32
|
return item.state === 'running' ? _jsx(WorkLiveRow, { chatId: chatId, tool: item }) : _jsx(WorkRow, { tool: item });
|
|
28
33
|
}
|
|
29
34
|
if (item.kind === 'assistant') {
|
|
@@ -10,10 +10,13 @@ export declare function ToggleLine({ icon, label, detail, open, onToggle, failed
|
|
|
10
10
|
trailing?: React.ReactNode;
|
|
11
11
|
className?: string;
|
|
12
12
|
}): import("react").JSX.Element;
|
|
13
|
-
export declare function WorkRow({ tool, nested, detail }: {
|
|
13
|
+
export declare function WorkRow({ tool, nested, detail, icon, label, failed }: {
|
|
14
14
|
tool: ChatToolItem;
|
|
15
15
|
nested?: boolean;
|
|
16
16
|
detail?: string;
|
|
17
|
+
icon?: React.ReactNode;
|
|
18
|
+
label?: string;
|
|
19
|
+
failed?: boolean;
|
|
17
20
|
}): import("react").JSX.Element;
|
|
18
21
|
export declare function RunningFor({ startedAt }: {
|
|
19
22
|
startedAt: number;
|
|
@@ -37,13 +37,14 @@ function ToolBody({ tool }) {
|
|
|
37
37
|
return (_jsxs("div", { className: "mt-1.5 mb-2 ml-6 overflow-hidden rounded-md border border-border bg-surface-raised", children: [patches.length > 0 ? (_jsx(Suspense, { fallback: _jsx("div", { className: "px-3 py-2 text-xs text-text-faint", children: t('work.loadingDiff') }), children: patches.map((change, index) => (_jsx(UnifiedDiff, { change: change }, index))) })) : changes.length > 0 ? (_jsx(Suspense, { fallback: _jsx("div", { className: "px-3 py-2 text-xs text-text-faint", children: t('work.loadingDiff') }), children: changes.map((change, index) => (_jsx(EditDiff, { change: change }, index))) })) : (_jsx("pre", { className: "max-h-64 overflow-auto px-3 py-2 font-mono text-code text-text-muted select-text", children: clip(JSON.stringify(tool.input, null, 2) ?? '') })), tool.output !== null && tool.output !== '' && patches.length === 0 && (_jsx("pre", { "data-find-field": "output", className: clsx('max-h-64 overflow-auto whitespace-pre-wrap border-t border-border px-3 py-2 font-mono text-code select-text', tool.state === 'error' ? 'text-chat-removed' : 'text-chat-output'), children: _jsx(AnsiOutput, { text: tool.output, limit: OUTPUT_LIMIT }) }))] }));
|
|
38
38
|
}
|
|
39
39
|
/* One settled tool call: a line, and its input and output behind it. An image the call looked at
|
|
40
|
-
is drawn under the line, because a picture says more about that read than its path does.
|
|
41
|
-
|
|
40
|
+
is drawn under the line, because a picture says more about that read than its path does.
|
|
41
|
+
`icon`, `label` and `failed` let a row that knows the call better name it in its own words. */
|
|
42
|
+
export function WorkRow({ tool, nested, detail, icon, label, failed }) {
|
|
42
43
|
const [open, setOpen] = useState(false);
|
|
43
44
|
const image = tool.state === 'done' ? readImagePath(tool.name, tool.input) : null;
|
|
44
45
|
const { ReadImage } = chatHost();
|
|
45
46
|
useOpenForFind(tool.id, 'output', setOpen);
|
|
46
|
-
return (_jsxs("div", { "data-find-item": tool.id, className: nested ? 'ml-6' : undefined, children: [_jsx(ToggleLine, { icon: toolIcon(tool.name), label: tool.name, detail: detail ?? toolSummary(tool.name, tool.input), open: open, onToggle: () => setOpen((o) => !o), failed: tool.state === 'error' }), image !== null && ReadImage !== null && _jsx(ReadImage, { path: image }), open && _jsx(ToolBody, { tool: tool })] }));
|
|
47
|
+
return (_jsxs("div", { "data-find-item": tool.id, className: nested ? 'ml-6' : undefined, children: [_jsx(ToggleLine, { icon: icon ?? toolIcon(tool.name), label: label ?? tool.name, detail: detail ?? toolSummary(tool.name, tool.input), open: open, onToggle: () => setOpen((o) => !o), failed: failed ?? tool.state === 'error' }), image !== null && ReadImage !== null && _jsx(ReadImage, { path: image }), open && _jsx(ToolBody, { tool: tool })] }));
|
|
47
48
|
}
|
|
48
49
|
/* "running for 12s" next to a live call. */
|
|
49
50
|
export function RunningFor({ startedAt }) {
|
package/dist/host.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ComponentProps, ComponentType, ReactNode, RefObject } from 'react'
|
|
|
2
2
|
import type { Extension } from '@codemirror/state';
|
|
3
3
|
import type { EditorView } from '@codemirror/view';
|
|
4
4
|
import type { ThemeRegistration } from 'shiki';
|
|
5
|
-
import type { AgentKind, ChatCheckpointDiff, ChatConfigurePayload, ChatItem, ChatSubagentItem } from '@adecore/agent-contracts';
|
|
5
|
+
import type { AgentKind, ChatCheckpointDiff, ChatConfigurePayload, ChatItem, ChatSubagentItem, ChatUiChoicePayload, ChatUiQueryPayload, ChatUiQueryReading, ChatUiLinkPayload, ChatUiLinkReading } from '@adecore/agent-contracts';
|
|
6
6
|
import type { TimelineRow } from './chat/logic/timeline.js';
|
|
7
7
|
import type { FindReveal } from './chat/ui/find-reveal.js';
|
|
8
8
|
import type { PromptAction } from './prompts/logic/prompts.js';
|
|
@@ -40,8 +40,18 @@ export interface ChatActions {
|
|
|
40
40
|
export interface FileRef {
|
|
41
41
|
path: string;
|
|
42
42
|
line?: number;
|
|
43
|
+
column?: number;
|
|
44
|
+
endLine?: number;
|
|
43
45
|
directory: boolean;
|
|
44
46
|
}
|
|
47
|
+
export interface ShellCodeBlockContext {
|
|
48
|
+
scopeId: string;
|
|
49
|
+
chatId: string;
|
|
50
|
+
itemId: string;
|
|
51
|
+
language: 'sh' | 'bash' | 'zsh';
|
|
52
|
+
code: string;
|
|
53
|
+
complete: boolean;
|
|
54
|
+
}
|
|
45
55
|
export interface ChatPlace {
|
|
46
56
|
title: string | null;
|
|
47
57
|
go(): void;
|
|
@@ -116,6 +126,14 @@ export interface ReplyAuthor {
|
|
|
116
126
|
}
|
|
117
127
|
export interface ChatHost {
|
|
118
128
|
storage?: ChatStorageOptions;
|
|
129
|
+
intelligentUi?: {
|
|
130
|
+
subscribe?(scopeId: string, chatId: string, changed: () => void): () => void;
|
|
131
|
+
link?(scopeId: string, payload: ChatUiLinkPayload): Promise<ChatUiLinkReading>;
|
|
132
|
+
openLink?(scopeId: string, reading: ChatUiLinkReading): void;
|
|
133
|
+
openUrl?(scopeId: string, url: string): void;
|
|
134
|
+
query?(scopeId: string, payload: ChatUiQueryPayload): Promise<ChatUiQueryReading>;
|
|
135
|
+
sendChoice(scopeId: string, payload: ChatUiChoicePayload): Promise<'sent' | 'queued'>;
|
|
136
|
+
};
|
|
119
137
|
accents: {
|
|
120
138
|
all: readonly AccentChoice[];
|
|
121
139
|
featured: readonly string[];
|
|
@@ -130,6 +148,8 @@ export interface ChatHost {
|
|
|
130
148
|
attachments: {
|
|
131
149
|
useUrl(scopeId: string, chatId: string, attachmentId: string): ResourceUrl;
|
|
132
150
|
read(scopeId: string, chatId: string, attachmentId: string): Promise<Blob>;
|
|
151
|
+
open?(scopeId: string, chatId: string, attachmentId: string, suggestedName: string): void;
|
|
152
|
+
saveToProject?(scopeId: string, chatId: string, attachmentId: string, suggestedName: string): Promise<string | null>;
|
|
133
153
|
};
|
|
134
154
|
ReadImage: ComponentType<{
|
|
135
155
|
path: string;
|
|
@@ -145,10 +165,12 @@ export interface ChatHost {
|
|
|
145
165
|
}>;
|
|
146
166
|
};
|
|
147
167
|
useStreaming(): 'words' | 'blocks' | 'whole';
|
|
168
|
+
useSendDelivery(): 'queue' | 'steer';
|
|
148
169
|
fileLinks: {
|
|
149
|
-
target(text: string, cwd: string | null): FileRef | null;
|
|
150
|
-
open(cwd: string | null, ref: FileRef): void;
|
|
170
|
+
target(text: string, cwd: string | null, scopeId?: string | null): FileRef | null;
|
|
171
|
+
open(cwd: string | null, ref: FileRef, scopeId?: string | null): void;
|
|
151
172
|
} | null;
|
|
173
|
+
renderShellCodeBlock?: (context: ShellCodeBlockContext) => ReactNode;
|
|
152
174
|
useTimelineFind(options: TimelineFindOptions): TimelineFind;
|
|
153
175
|
dictation: {
|
|
154
176
|
Textarea: ComponentType<TextareaProps>;
|
package/dist/host.js
CHANGED
|
@@ -20,6 +20,7 @@ const DEFAULT_HOST = {
|
|
|
20
20
|
ReadImage: null,
|
|
21
21
|
code: { useMode: () => 'light', useThemes: () => ({ light: 'github-light', dark: 'github-dark' }), custom: [] },
|
|
22
22
|
useStreaming: () => 'words',
|
|
23
|
+
useSendDelivery: () => 'queue',
|
|
23
24
|
fileLinks: null,
|
|
24
25
|
useTimelineFind: () => NO_FIND,
|
|
25
26
|
dictation: { Textarea: PlainTextarea, composer: null },
|
|
@@ -307,7 +307,9 @@
|
|
|
307
307
|
"description": "A turn is running. Stop it and clear the thread?",
|
|
308
308
|
"confirm": "Stop and clear"
|
|
309
309
|
},
|
|
310
|
-
"waitingBelow": "Waiting for your answer below"
|
|
310
|
+
"waitingBelow": "Waiting for your answer below",
|
|
311
|
+
"steerButton": "Send to the running agent. Hold Option or Alt to queue after this turn.",
|
|
312
|
+
"queueWithSteerButton": "Queue after this turn. Hold Option or Alt to send to the running agent."
|
|
311
313
|
},
|
|
312
314
|
"activity": {
|
|
313
315
|
"subagents_one": "{{count}} sub-agent",
|
|
@@ -433,6 +435,25 @@
|
|
|
433
435
|
"zoomOut": "Zoom out",
|
|
434
436
|
"reset": "Reset"
|
|
435
437
|
},
|
|
438
|
+
"generatedImage": {
|
|
439
|
+
"label": "Generated image",
|
|
440
|
+
"generating": "Generating image",
|
|
441
|
+
"failed": "Image generation failed",
|
|
442
|
+
"empty": "The image came back empty",
|
|
443
|
+
"notImage": "The result is not an image",
|
|
444
|
+
"tooLarge": "The image is larger than {{size}}",
|
|
445
|
+
"dimensions": "{{width}} × {{height}}",
|
|
446
|
+
"transparent": "transparent",
|
|
447
|
+
"actions": "Image actions",
|
|
448
|
+
"more": "More actions",
|
|
449
|
+
"copyPrompt": "Copy prompt",
|
|
450
|
+
"open": "Open",
|
|
451
|
+
"openLarge": "Open large",
|
|
452
|
+
"save": "Save to project…",
|
|
453
|
+
"saved": "Saved",
|
|
454
|
+
"savedTo": "Saved to <file>{{path}}</file>",
|
|
455
|
+
"renderFailed": "This image failed to render"
|
|
456
|
+
},
|
|
436
457
|
"account": {
|
|
437
458
|
"pill": "{{provider}} account {{account}}"
|
|
438
459
|
},
|
|
@@ -454,5 +475,72 @@
|
|
|
454
475
|
"failed": "failed",
|
|
455
476
|
"cancelled": "cancelled"
|
|
456
477
|
}
|
|
478
|
+
},
|
|
479
|
+
"code": {
|
|
480
|
+
"actions": "Code actions",
|
|
481
|
+
"copyFailed": "Could not copy the code. Try again."
|
|
482
|
+
},
|
|
483
|
+
"blocks": {
|
|
484
|
+
"label": "Interactive block",
|
|
485
|
+
"progress": {
|
|
486
|
+
"label": "Progress",
|
|
487
|
+
"of": "{{value}} of {{max}}"
|
|
488
|
+
},
|
|
489
|
+
"step": {
|
|
490
|
+
"done": "Done",
|
|
491
|
+
"running": "Running",
|
|
492
|
+
"pending": "Waiting",
|
|
493
|
+
"failed": "Failed",
|
|
494
|
+
"skipped": "Skipped"
|
|
495
|
+
},
|
|
496
|
+
"stat": {
|
|
497
|
+
"change": "{{change}} from {{previous}}",
|
|
498
|
+
"from": "from {{previous}}"
|
|
499
|
+
},
|
|
500
|
+
"table": {
|
|
501
|
+
"showAll": "Show all {{total}} rows"
|
|
502
|
+
},
|
|
503
|
+
"chart": {
|
|
504
|
+
"values": "Values",
|
|
505
|
+
"summary": "{{count}} values, highest {{label}} at {{value}}",
|
|
506
|
+
"summarySeries": "{{count}} categories, highest {{series}} for {{label}} at {{value}}"
|
|
507
|
+
},
|
|
508
|
+
"image": {
|
|
509
|
+
"label": "Image",
|
|
510
|
+
"unavailable": "The image is not available"
|
|
511
|
+
},
|
|
512
|
+
"sources": "Sources",
|
|
513
|
+
"citation": "Source {{number}}: {{title}}",
|
|
514
|
+
"outsideProject": "Outside the project, shown as text",
|
|
515
|
+
"options": "Options",
|
|
516
|
+
"choices": "Choices",
|
|
517
|
+
"choice": {
|
|
518
|
+
"waiting": "Available when the reply is done",
|
|
519
|
+
"unavailable": "Not available",
|
|
520
|
+
"sent": "Sent",
|
|
521
|
+
"queued": "Queued",
|
|
522
|
+
"failed": "Could not send. Try again.",
|
|
523
|
+
"ready": "Choices are ready"
|
|
524
|
+
},
|
|
525
|
+
"answered": "Answered with “{{label}}”",
|
|
526
|
+
"chose": "Chose “{{label}}”",
|
|
527
|
+
"choseOlder": "Chose “{{label}}” on the reply of {{time}}",
|
|
528
|
+
"sendContext": "Send",
|
|
529
|
+
"copyText": "Copy text",
|
|
530
|
+
"fixes_one": "{{count}} fix",
|
|
531
|
+
"fixes_other": "{{count}} fixes",
|
|
532
|
+
"shownAsText": "Shown as text",
|
|
533
|
+
"unknownComponent": "This version cannot draw {{component}}",
|
|
534
|
+
"renderFailed": "Could not draw this part",
|
|
535
|
+
"tooLarge": "The block is too large to draw",
|
|
536
|
+
"unreadable": "The block could not be read",
|
|
537
|
+
"live": {
|
|
538
|
+
"label": "Live",
|
|
539
|
+
"read": "read {{time}}",
|
|
540
|
+
"sources": "Reads {{sources}}",
|
|
541
|
+
"failed": "Could not read {{source}}",
|
|
542
|
+
"refused": "Not allowed to read {{source}}",
|
|
543
|
+
"notRead": "Not read"
|
|
544
|
+
}
|
|
457
545
|
}
|
|
458
546
|
}
|
|
@@ -307,7 +307,9 @@
|
|
|
307
307
|
"description": "Er loopt een turn. Die stoppen en de thread wissen?",
|
|
308
308
|
"confirm": "Stoppen en wissen"
|
|
309
309
|
},
|
|
310
|
-
"waitingBelow": "Wacht hieronder op je antwoord"
|
|
310
|
+
"waitingBelow": "Wacht hieronder op je antwoord",
|
|
311
|
+
"steerButton": "Stuur naar de werkende agent. Houd Option of Alt ingedrukt om te wachten tot deze beurt klaar is.",
|
|
312
|
+
"queueWithSteerButton": "Wacht tot deze beurt klaar is. Houd Option of Alt ingedrukt om naar de werkende agent te sturen."
|
|
311
313
|
},
|
|
312
314
|
"activity": {
|
|
313
315
|
"subagents_one": "{{count}} sub-agent",
|
|
@@ -433,6 +435,25 @@
|
|
|
433
435
|
"zoomOut": "Uitzoomen",
|
|
434
436
|
"reset": "Herstellen"
|
|
435
437
|
},
|
|
438
|
+
"generatedImage": {
|
|
439
|
+
"label": "Gegenereerde afbeelding",
|
|
440
|
+
"generating": "Afbeelding wordt gemaakt",
|
|
441
|
+
"failed": "Afbeelding maken mislukt",
|
|
442
|
+
"empty": "De afbeelding kwam leeg terug",
|
|
443
|
+
"notImage": "Het resultaat is geen afbeelding",
|
|
444
|
+
"tooLarge": "De afbeelding is groter dan {{size}}",
|
|
445
|
+
"dimensions": "{{width}} × {{height}}",
|
|
446
|
+
"transparent": "transparant",
|
|
447
|
+
"actions": "Acties voor de afbeelding",
|
|
448
|
+
"more": "Meer acties",
|
|
449
|
+
"copyPrompt": "Prompt kopiëren",
|
|
450
|
+
"open": "Openen",
|
|
451
|
+
"openLarge": "Groot openen",
|
|
452
|
+
"save": "Opslaan in project…",
|
|
453
|
+
"saved": "Opgeslagen",
|
|
454
|
+
"savedTo": "Opgeslagen in <file>{{path}}</file>",
|
|
455
|
+
"renderFailed": "Deze afbeelding kon niet worden getoond"
|
|
456
|
+
},
|
|
436
457
|
"account": {
|
|
437
458
|
"pill": "{{provider}}-account {{account}}"
|
|
438
459
|
},
|
|
@@ -454,5 +475,72 @@
|
|
|
454
475
|
"failed": "mislukt",
|
|
455
476
|
"cancelled": "geannuleerd"
|
|
456
477
|
}
|
|
478
|
+
},
|
|
479
|
+
"code": {
|
|
480
|
+
"actions": "Codeacties",
|
|
481
|
+
"copyFailed": "De code kon niet worden gekopieerd. Probeer het opnieuw."
|
|
482
|
+
},
|
|
483
|
+
"blocks": {
|
|
484
|
+
"label": "Interactief blok",
|
|
485
|
+
"progress": {
|
|
486
|
+
"label": "Voortgang",
|
|
487
|
+
"of": "{{value}} van {{max}}"
|
|
488
|
+
},
|
|
489
|
+
"step": {
|
|
490
|
+
"done": "Klaar",
|
|
491
|
+
"running": "Bezig",
|
|
492
|
+
"pending": "Wacht",
|
|
493
|
+
"failed": "Mislukt",
|
|
494
|
+
"skipped": "Overgeslagen"
|
|
495
|
+
},
|
|
496
|
+
"stat": {
|
|
497
|
+
"change": "{{change}} vanaf {{previous}}",
|
|
498
|
+
"from": "vanaf {{previous}}"
|
|
499
|
+
},
|
|
500
|
+
"table": {
|
|
501
|
+
"showAll": "Alle {{total}} rijen tonen"
|
|
502
|
+
},
|
|
503
|
+
"chart": {
|
|
504
|
+
"values": "Waarden",
|
|
505
|
+
"summary": "{{count}} waarden, hoogste {{label}} met {{value}}",
|
|
506
|
+
"summarySeries": "{{count}} categorieën, hoogste {{series}} bij {{label}} met {{value}}"
|
|
507
|
+
},
|
|
508
|
+
"image": {
|
|
509
|
+
"label": "Afbeelding",
|
|
510
|
+
"unavailable": "De afbeelding is niet beschikbaar"
|
|
511
|
+
},
|
|
512
|
+
"sources": "Bronnen",
|
|
513
|
+
"citation": "Bron {{number}}: {{title}}",
|
|
514
|
+
"outsideProject": "Buiten het project, als tekst getoond",
|
|
515
|
+
"options": "Opties",
|
|
516
|
+
"choices": "Keuzes",
|
|
517
|
+
"choice": {
|
|
518
|
+
"waiting": "Beschikbaar zodra het antwoord klaar is",
|
|
519
|
+
"unavailable": "Niet beschikbaar",
|
|
520
|
+
"sent": "Verstuurd",
|
|
521
|
+
"queued": "In de wachtrij",
|
|
522
|
+
"failed": "Versturen lukte niet. Probeer het opnieuw.",
|
|
523
|
+
"ready": "De keuzes staan klaar"
|
|
524
|
+
},
|
|
525
|
+
"answered": "Beantwoord met “{{label}}”",
|
|
526
|
+
"chose": "Gekozen: “{{label}}”",
|
|
527
|
+
"choseOlder": "Gekozen: “{{label}}”, bij het antwoord van {{time}}",
|
|
528
|
+
"sendContext": "Versturen",
|
|
529
|
+
"copyText": "Tekst kopiëren",
|
|
530
|
+
"fixes_one": "{{count}} correctie",
|
|
531
|
+
"fixes_other": "{{count}} correcties",
|
|
532
|
+
"shownAsText": "Als tekst getoond",
|
|
533
|
+
"unknownComponent": "Deze versie kan {{component}} niet tekenen",
|
|
534
|
+
"renderFailed": "Dit deel kon niet getekend worden",
|
|
535
|
+
"tooLarge": "Het blok is te groot om te tekenen",
|
|
536
|
+
"unreadable": "Het blok kon niet gelezen worden",
|
|
537
|
+
"live": {
|
|
538
|
+
"label": "Live",
|
|
539
|
+
"read": "gelezen {{time}}",
|
|
540
|
+
"sources": "Leest {{sources}}",
|
|
541
|
+
"failed": "{{source}} lezen lukte niet",
|
|
542
|
+
"refused": "Geen toegang tot {{source}}",
|
|
543
|
+
"notRead": "Niet gelezen"
|
|
544
|
+
}
|
|
457
545
|
}
|
|
458
546
|
}
|
package/dist/state/chats.js
CHANGED
|
@@ -79,6 +79,15 @@ export function applyEvent(state, event) {
|
|
|
79
79
|
}
|
|
80
80
|
case 'delta': {
|
|
81
81
|
const item = state.items[event.itemId];
|
|
82
|
+
if (event.uiQueries && item?.kind === 'assistant') {
|
|
83
|
+
return { ...state, items: { ...state.items, [event.itemId]: { ...item, uiQueries: event.uiQueries } } };
|
|
84
|
+
}
|
|
85
|
+
if (event.ui !== undefined && event.text === '') {
|
|
86
|
+
if (item?.kind === 'assistant' && item.streaming && event.textLength === item.text.length) {
|
|
87
|
+
return { ...state, items: { ...state.items, [event.itemId]: { ...item, ui: event.ui } } };
|
|
88
|
+
}
|
|
89
|
+
return state;
|
|
90
|
+
}
|
|
82
91
|
if (item?.kind === 'assistant' || item?.kind === 'thinking') {
|
|
83
92
|
const grown = { ...item, text: item.text + event.text };
|
|
84
93
|
// The first text is structure after all, since an empty reply that is not streaming has no row.
|