@agent-native/toolkit 0.14.3 → 0.15.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/composer/ComposerPlusMenu.d.ts.map +1 -1
- package/dist/composer/ComposerPlusMenu.js +131 -35
- package/dist/composer/ComposerPlusMenu.js.map +1 -1
- package/dist/composer/MentionPopover.d.ts.map +1 -1
- package/dist/composer/MentionPopover.js +40 -5
- package/dist/composer/MentionPopover.js.map +1 -1
- package/dist/composer/PastedTextChip.d.ts.map +1 -1
- package/dist/composer/PastedTextChip.js +26 -2
- package/dist/composer/PastedTextChip.js.map +1 -1
- package/dist/composer/PastedTextChip.spec.d.ts +2 -0
- package/dist/composer/PastedTextChip.spec.d.ts.map +1 -0
- package/dist/composer/PastedTextChip.spec.js +42 -0
- package/dist/composer/PastedTextChip.spec.js.map +1 -0
- package/dist/composer/PromptComposer.d.ts.map +1 -1
- package/dist/composer/PromptComposer.js +26 -5
- package/dist/composer/PromptComposer.js.map +1 -1
- package/dist/composer/TiptapComposer.d.ts +5 -3
- package/dist/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/composer/TiptapComposer.js +289 -79
- package/dist/composer/TiptapComposer.js.map +1 -1
- package/dist/composer/TiptapComposer.spec.js +57 -0
- package/dist/composer/TiptapComposer.spec.js.map +1 -1
- package/dist/composer/VoiceButton.d.ts.map +1 -1
- package/dist/composer/VoiceButton.js +24 -5
- package/dist/composer/VoiceButton.js.map +1 -1
- package/dist/composer/runtime-adapters.d.ts +1 -0
- package/dist/composer/runtime-adapters.d.ts.map +1 -1
- package/dist/composer/runtime-adapters.js +8 -1
- package/dist/composer/runtime-adapters.js.map +1 -1
- package/dist/composer/runtime-adapters.spec.js +15 -0
- package/dist/composer/runtime-adapters.spec.js.map +1 -1
- package/dist/composer/useRealtimeVoiceMode.d.ts.map +1 -1
- package/dist/composer/useRealtimeVoiceMode.js +204 -68
- package/dist/composer/useRealtimeVoiceMode.js.map +1 -1
- package/dist/composer/useRealtimeVoiceMode.spec.js +27 -1
- package/dist/composer/useRealtimeVoiceMode.spec.js.map +1 -1
- package/dist/context-ui/ContextMeter.d.ts +3 -2
- package/dist/context-ui/ContextMeter.d.ts.map +1 -1
- package/dist/context-ui/ContextMeter.js +23 -3
- package/dist/context-ui/ContextMeter.js.map +1 -1
- package/dist/context-ui/ContextMeter.spec.d.ts +2 -0
- package/dist/context-ui/ContextMeter.spec.d.ts.map +1 -0
- package/dist/context-ui/ContextMeter.spec.js +52 -0
- package/dist/context-ui/ContextMeter.spec.js.map +1 -0
- package/dist/context-ui/ContextSegmentRow.d.ts +5 -3
- package/dist/context-ui/ContextSegmentRow.d.ts.map +1 -1
- package/dist/context-ui/ContextSegmentRow.js +74 -7
- package/dist/context-ui/ContextSegmentRow.js.map +1 -1
- package/dist/context-ui/ContextTreemap.d.ts +3 -2
- package/dist/context-ui/ContextTreemap.d.ts.map +1 -1
- package/dist/context-ui/ContextTreemap.js +5 -2
- package/dist/context-ui/ContextTreemap.js.map +1 -1
- package/dist/context-ui/ContextXRayPanel.d.ts +3 -2
- package/dist/context-ui/ContextXRayPanel.d.ts.map +1 -1
- package/dist/context-ui/ContextXRayPanel.js +112 -23
- package/dist/context-ui/ContextXRayPanel.js.map +1 -1
- package/dist/context-ui/types.d.ts +2 -0
- package/dist/context-ui/types.d.ts.map +1 -1
- package/dist/context-ui/types.js +7 -1
- package/dist/context-ui/types.js.map +1 -1
- package/package.json +2 -2
- package/src/composer/ComposerPlusMenu.tsx +170 -52
- package/src/composer/MentionPopover.tsx +43 -7
- package/src/composer/PastedTextChip.spec.tsx +58 -0
- package/src/composer/PastedTextChip.tsx +35 -7
- package/src/composer/PromptComposer.tsx +28 -7
- package/src/composer/TiptapComposer.spec.ts +85 -0
- package/src/composer/TiptapComposer.tsx +338 -81
- package/src/composer/VoiceButton.tsx +36 -11
- package/src/composer/runtime-adapters.spec.tsx +19 -0
- package/src/composer/runtime-adapters.tsx +12 -2
- package/src/composer/useRealtimeVoiceMode.spec.ts +34 -0
- package/src/composer/useRealtimeVoiceMode.tsx +219 -69
- package/src/context-ui/ContextMeter.spec.tsx +73 -0
- package/src/context-ui/ContextMeter.tsx +34 -4
- package/src/context-ui/ContextSegmentRow.tsx +111 -22
- package/src/context-ui/ContextTreemap.tsx +7 -1
- package/src/context-ui/ContextXRayPanel.tsx +138 -24
- package/src/context-ui/types.ts +14 -0
|
@@ -5,6 +5,7 @@ import { useCallback, useEffect, useState } from "react";
|
|
|
5
5
|
|
|
6
6
|
import { cn } from "../utils.js";
|
|
7
7
|
import { countLines, unwrapAttachmentEnvelope } from "./pasted-text.js";
|
|
8
|
+
import { useComposerRuntimeAdapters } from "./runtime-adapters.js";
|
|
8
9
|
|
|
9
10
|
function readAttachmentText(attachment: Attachment): Promise<string> | string {
|
|
10
11
|
if ("file" in attachment && attachment.file instanceof File) {
|
|
@@ -58,6 +59,9 @@ export function PastedTextChip({
|
|
|
58
59
|
}: PastedTextChipProps) {
|
|
59
60
|
const [open, setOpen] = useState(false);
|
|
60
61
|
const { text, lines, chars } = usePastedAttachmentText(attachment);
|
|
62
|
+
const adapters = useComposerRuntimeAdapters();
|
|
63
|
+
const t = adapters.translate!;
|
|
64
|
+
const formatNumber = adapters.formatNumber!;
|
|
61
65
|
|
|
62
66
|
const handleRemove = useCallback(
|
|
63
67
|
(event: React.MouseEvent) => {
|
|
@@ -67,7 +71,17 @@ export function PastedTextChip({
|
|
|
67
71
|
[attachment.id, onRemove],
|
|
68
72
|
);
|
|
69
73
|
|
|
70
|
-
const
|
|
74
|
+
const lineSummary = t("agentChat.pastedText.lines", {
|
|
75
|
+
count: lines,
|
|
76
|
+
formattedCount: formatNumber(lines),
|
|
77
|
+
defaultValue: `${lines} lines`,
|
|
78
|
+
});
|
|
79
|
+
const charSummary = t("agentChat.pastedText.characters", {
|
|
80
|
+
count: chars,
|
|
81
|
+
formattedCount: formatNumber(chars),
|
|
82
|
+
defaultValue: `${chars} chars`,
|
|
83
|
+
});
|
|
84
|
+
const summary = lines > 0 ? lineSummary : charSummary;
|
|
71
85
|
|
|
72
86
|
return (
|
|
73
87
|
<PopoverPrimitive.Root open={open} onOpenChange={setOpen}>
|
|
@@ -81,7 +95,9 @@ export function PastedTextChip({
|
|
|
81
95
|
: "max-w-[260px] px-2.5 py-2 text-xs",
|
|
82
96
|
onRemove && !compact && "pe-7",
|
|
83
97
|
)}
|
|
84
|
-
aria-label="
|
|
98
|
+
aria-label={t("agentChat.pastedText.preview", {
|
|
99
|
+
defaultValue: "Preview pasted text",
|
|
100
|
+
})}
|
|
85
101
|
>
|
|
86
102
|
<span
|
|
87
103
|
className={cn(
|
|
@@ -94,7 +110,11 @@ export function PastedTextChip({
|
|
|
94
110
|
/>
|
|
95
111
|
</span>
|
|
96
112
|
<span className="min-w-0 flex-1">
|
|
97
|
-
<span className="block truncate font-medium">
|
|
113
|
+
<span className="block truncate font-medium">
|
|
114
|
+
{t("agentChat.pastedText.title", {
|
|
115
|
+
defaultValue: "Pasted text",
|
|
116
|
+
})}
|
|
117
|
+
</span>
|
|
98
118
|
<span className="block text-[11px] text-muted-foreground">
|
|
99
119
|
{summary}
|
|
100
120
|
</span>
|
|
@@ -104,7 +124,9 @@ export function PastedTextChip({
|
|
|
104
124
|
role="button"
|
|
105
125
|
tabIndex={-1}
|
|
106
126
|
onClick={handleRemove}
|
|
107
|
-
aria-label="
|
|
127
|
+
aria-label={t("agentChat.pastedText.remove", {
|
|
128
|
+
defaultValue: "Remove pasted text",
|
|
129
|
+
})}
|
|
108
130
|
className={cn(
|
|
109
131
|
"flex h-5 w-5 shrink-0 cursor-pointer items-center justify-center rounded text-muted-foreground hover:text-foreground",
|
|
110
132
|
compact ? "" : "absolute end-1.5 top-1.5",
|
|
@@ -126,15 +148,21 @@ export function PastedTextChip({
|
|
|
126
148
|
<div className="flex items-center justify-between gap-2 border-b border-border px-3 py-2">
|
|
127
149
|
<div className="flex items-center gap-2 min-w-0">
|
|
128
150
|
<IconClipboardText className="h-4 w-4 shrink-0 text-muted-foreground" />
|
|
129
|
-
<span className="text-sm font-medium truncate">
|
|
151
|
+
<span className="text-sm font-medium truncate">
|
|
152
|
+
{t("agentChat.pastedText.title", {
|
|
153
|
+
defaultValue: "Pasted text",
|
|
154
|
+
})}
|
|
155
|
+
</span>
|
|
130
156
|
<span className="text-[11px] text-muted-foreground shrink-0">
|
|
131
|
-
{
|
|
157
|
+
{lineSummary} · {charSummary}
|
|
132
158
|
</span>
|
|
133
159
|
</div>
|
|
134
160
|
<button
|
|
135
161
|
type="button"
|
|
136
162
|
onClick={() => setOpen(false)}
|
|
137
|
-
aria-label="
|
|
163
|
+
aria-label={t("agentChat.composer.closePreview", {
|
|
164
|
+
defaultValue: "Close preview",
|
|
165
|
+
})}
|
|
138
166
|
className="flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded text-muted-foreground hover:text-foreground"
|
|
139
167
|
>
|
|
140
168
|
<IconX className="h-3.5 w-3.5" />
|
|
@@ -315,6 +315,7 @@ function ImagePreviewLightbox({
|
|
|
315
315
|
alt: string;
|
|
316
316
|
onClose: () => void;
|
|
317
317
|
}) {
|
|
318
|
+
const t = useComposerRuntimeAdapters().translate!;
|
|
318
319
|
useEffect(() => {
|
|
319
320
|
const handler = (e: KeyboardEvent) => {
|
|
320
321
|
if (e.key === "Escape") onClose();
|
|
@@ -330,7 +331,9 @@ function ImagePreviewLightbox({
|
|
|
330
331
|
return (
|
|
331
332
|
<div
|
|
332
333
|
role="dialog"
|
|
333
|
-
aria-label="
|
|
334
|
+
aria-label={t("agentChat.composer.imagePreview", {
|
|
335
|
+
defaultValue: "Image preview",
|
|
336
|
+
})}
|
|
334
337
|
onClick={onClose}
|
|
335
338
|
className="fixed inset-0 z-[300] flex items-center justify-center bg-black/80 p-6 cursor-zoom-out"
|
|
336
339
|
>
|
|
@@ -343,7 +346,9 @@ function ImagePreviewLightbox({
|
|
|
343
346
|
<button
|
|
344
347
|
type="button"
|
|
345
348
|
onClick={onClose}
|
|
346
|
-
aria-label="
|
|
349
|
+
aria-label={t("agentChat.composer.closePreview", {
|
|
350
|
+
defaultValue: "Close preview",
|
|
351
|
+
})}
|
|
347
352
|
className="absolute end-4 top-4 flex h-8 w-8 cursor-pointer items-center justify-center rounded-full border border-white/30 bg-black/40 text-white hover:bg-black/60"
|
|
348
353
|
>
|
|
349
354
|
<IconX className="h-4 w-4" />
|
|
@@ -361,6 +366,7 @@ function AttachmentChip({
|
|
|
361
366
|
}) {
|
|
362
367
|
const src = useMemo(() => getImageSrc(attachment), [attachment]);
|
|
363
368
|
const [previewOpen, setPreviewOpen] = useState(false);
|
|
369
|
+
const t = useComposerRuntimeAdapters().translate!;
|
|
364
370
|
useEffect(
|
|
365
371
|
() => () => {
|
|
366
372
|
if (src?.startsWith("blob:")) URL.revokeObjectURL(src);
|
|
@@ -378,7 +384,10 @@ function AttachmentChip({
|
|
|
378
384
|
<button
|
|
379
385
|
type="button"
|
|
380
386
|
onClick={() => setPreviewOpen(true)}
|
|
381
|
-
aria-label={
|
|
387
|
+
aria-label={t("agentChat.composer.previewAttachment", {
|
|
388
|
+
name: attachment.name,
|
|
389
|
+
defaultValue: `Preview ${attachment.name}`,
|
|
390
|
+
})}
|
|
382
391
|
className="agent-composer-attachment-image group relative flex h-16 min-w-16 max-w-28 cursor-zoom-in items-center justify-center overflow-hidden rounded-lg border border-border/70 bg-muted/50"
|
|
383
392
|
>
|
|
384
393
|
<img
|
|
@@ -400,7 +409,10 @@ function AttachmentChip({
|
|
|
400
409
|
onRemove(attachment.id);
|
|
401
410
|
}
|
|
402
411
|
}}
|
|
403
|
-
aria-label={
|
|
412
|
+
aria-label={t("agentChat.composer.removeAttachment", {
|
|
413
|
+
name: attachment.name,
|
|
414
|
+
defaultValue: `Remove ${attachment.name}`,
|
|
415
|
+
})}
|
|
404
416
|
className="absolute end-1 top-1 flex h-5 w-5 cursor-pointer items-center justify-center rounded-full border border-border/60 bg-background/90 text-muted-foreground hover:text-foreground"
|
|
405
417
|
>
|
|
406
418
|
<IconX className="h-3 w-3" />
|
|
@@ -420,13 +432,17 @@ function AttachmentChip({
|
|
|
420
432
|
return (
|
|
421
433
|
<div className="agent-composer-attachment-chip group relative inline-flex max-w-[200px] items-center gap-2 rounded-md border border-border/70 bg-muted/50 px-2 py-1.5 text-xs">
|
|
422
434
|
<div className="flex h-6 w-6 shrink-0 items-center justify-center rounded bg-background text-[9px] font-semibold uppercase text-muted-foreground">
|
|
423
|
-
{attachment.name.split(".").pop() ||
|
|
435
|
+
{attachment.name.split(".").pop() ||
|
|
436
|
+
t("agentChat.composer.file", { defaultValue: "file" })}
|
|
424
437
|
</div>
|
|
425
438
|
<span className="min-w-0 truncate font-medium">{attachment.name}</span>
|
|
426
439
|
<button
|
|
427
440
|
type="button"
|
|
428
441
|
onClick={() => onRemove(attachment.id)}
|
|
429
|
-
aria-label={
|
|
442
|
+
aria-label={t("agentChat.composer.removeAttachment", {
|
|
443
|
+
name: attachment.name,
|
|
444
|
+
defaultValue: `Remove ${attachment.name}`,
|
|
445
|
+
})}
|
|
430
446
|
className="flex h-5 w-5 shrink-0 cursor-pointer items-center justify-center rounded text-muted-foreground hover:text-foreground"
|
|
431
447
|
>
|
|
432
448
|
<IconX className="h-3 w-3" />
|
|
@@ -506,6 +522,7 @@ function PromptComposerInner({
|
|
|
506
522
|
composerRef,
|
|
507
523
|
}: PromptComposerProps) {
|
|
508
524
|
const adapters = useComposerRuntimeAdapters();
|
|
525
|
+
const t = adapters.translate!;
|
|
509
526
|
const modelsAdapter = adapters.models!;
|
|
510
527
|
const BuilderSetupCard = modelsAdapter.BuilderSetupCard;
|
|
511
528
|
const BuilderSetupContent = modelsAdapter.BuilderSetupContent;
|
|
@@ -641,7 +658,11 @@ function PromptComposerInner({
|
|
|
641
658
|
maxDocumentAttachmentBytes={maxDocumentAttachmentBytes}
|
|
642
659
|
documentAttachmentLimitLabel={documentAttachmentLimitLabel}
|
|
643
660
|
placeholder={
|
|
644
|
-
gateComposer
|
|
661
|
+
gateComposer
|
|
662
|
+
? t("agentChat.composer.connectAbove", {
|
|
663
|
+
defaultValue: "Connect AI above to continue...",
|
|
664
|
+
})
|
|
665
|
+
: placeholder
|
|
645
666
|
}
|
|
646
667
|
initialText={initialText}
|
|
647
668
|
initialTextKey={initialTextKey}
|
|
@@ -28,6 +28,31 @@ import {
|
|
|
28
28
|
} from "./TiptapComposer.js";
|
|
29
29
|
|
|
30
30
|
describe("createTiptapComposerExtensions", () => {
|
|
31
|
+
it("refreshes the rendered placeholder after a locale change", () => {
|
|
32
|
+
let placeholder = "Ask the agent...";
|
|
33
|
+
const element = document.createElement("div");
|
|
34
|
+
const editor = new Editor({
|
|
35
|
+
element,
|
|
36
|
+
extensions: createTiptapComposerExtensions(() => placeholder),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(
|
|
40
|
+
element
|
|
41
|
+
.querySelector(".is-editor-empty")
|
|
42
|
+
?.getAttribute("data-placeholder"),
|
|
43
|
+
).toBe("Ask the agent...");
|
|
44
|
+
|
|
45
|
+
placeholder = "Frag den Agenten...";
|
|
46
|
+
editor.view.dispatch(editor.state.tr.setSelection(editor.state.selection));
|
|
47
|
+
|
|
48
|
+
expect(
|
|
49
|
+
element
|
|
50
|
+
.querySelector(".is-editor-empty")
|
|
51
|
+
?.getAttribute("data-placeholder"),
|
|
52
|
+
).toBe("Frag den Agenten...");
|
|
53
|
+
editor.destroy();
|
|
54
|
+
});
|
|
55
|
+
|
|
31
56
|
it("rejects a truthy editor after BFCache/remount destruction", () => {
|
|
32
57
|
const editor = new Editor({
|
|
33
58
|
element: document.createElement("div"),
|
|
@@ -68,6 +93,17 @@ describe("createTiptapComposerExtensions", () => {
|
|
|
68
93
|
expect(compactComposerReasoningEffortLabel("medium")).toBe("Med");
|
|
69
94
|
expect(compactComposerReasoningEffortLabel("minimal")).toBe("Min");
|
|
70
95
|
expect(compactComposerReasoningEffortLabel("xhigh")).toBe("XHigh");
|
|
96
|
+
|
|
97
|
+
const translate = (key: string, options?: Record<string, unknown>) =>
|
|
98
|
+
key === "agentChat.composer.defaultModel"
|
|
99
|
+
? "Standardmodell"
|
|
100
|
+
: key === "agentChat.composer.reasoningMediumShort"
|
|
101
|
+
? "Mittel"
|
|
102
|
+
: String(options?.defaultValue ?? key);
|
|
103
|
+
expect(compactComposerModelName("auto", translate)).toBe("Standardmodell");
|
|
104
|
+
expect(compactComposerReasoningEffortLabel("medium", translate)).toBe(
|
|
105
|
+
"Mittel",
|
|
106
|
+
);
|
|
71
107
|
});
|
|
72
108
|
|
|
73
109
|
it("keeps the prompt composer schema minimal and restores legacy draft HTML", () => {
|
|
@@ -202,6 +238,14 @@ describe("createTiptapComposerExtensions", () => {
|
|
|
202
238
|
attachmentCount: 1,
|
|
203
239
|
}),
|
|
204
240
|
).toBe("Create an extension: Use the attached context.");
|
|
241
|
+
expect(
|
|
242
|
+
displayableComposerModeMessage({
|
|
243
|
+
messagePrefix: "Erstelle eine Erweiterung: ",
|
|
244
|
+
trimmedText: "",
|
|
245
|
+
attachmentCount: 1,
|
|
246
|
+
attachedContextFallback: "Verwende den angehängten Kontext.",
|
|
247
|
+
}),
|
|
248
|
+
).toBe("Erstelle eine Erweiterung: Verwende den angehängten Kontext.");
|
|
205
249
|
});
|
|
206
250
|
|
|
207
251
|
it("detects oversized PDF attachments before submit", () => {
|
|
@@ -256,6 +300,47 @@ describe("createTiptapComposerExtensions", () => {
|
|
|
256
300
|
).toBeNull();
|
|
257
301
|
});
|
|
258
302
|
|
|
303
|
+
it("localizes a custom multipart document cap", () => {
|
|
304
|
+
const file = new File(
|
|
305
|
+
[new Uint8Array(4 * 1024 * 1024 + 1)],
|
|
306
|
+
"reference.pdf",
|
|
307
|
+
{ type: "application/pdf" },
|
|
308
|
+
);
|
|
309
|
+
let translatedOptions: Record<string, unknown> | undefined;
|
|
310
|
+
|
|
311
|
+
const error = getOversizedDocumentAttachmentError(
|
|
312
|
+
[
|
|
313
|
+
{
|
|
314
|
+
type: "document",
|
|
315
|
+
name: "reference.pdf",
|
|
316
|
+
contentType: "application/pdf",
|
|
317
|
+
file,
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
{
|
|
321
|
+
maxBytes: 4 * 1024 * 1024,
|
|
322
|
+
label: "Präsentationsdateien",
|
|
323
|
+
translate: (key, options) => {
|
|
324
|
+
expect(key).toBe("agentChat.composer.documentTooLarge");
|
|
325
|
+
translatedOptions = options;
|
|
326
|
+
return `„${String(options?.name)}“ ist ${String(options?.size)} MB groß. ${String(options?.label)} sind auf ${String(options?.maxSize)} MB begrenzt.`;
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
expect(error).toBe(
|
|
332
|
+
"„reference.pdf“ ist 4.0 MB groß. Präsentationsdateien sind auf 4 MB begrenzt.",
|
|
333
|
+
);
|
|
334
|
+
expect(translatedOptions).toEqual(
|
|
335
|
+
expect.objectContaining({
|
|
336
|
+
name: "reference.pdf",
|
|
337
|
+
size: "4.0",
|
|
338
|
+
label: "Präsentationsdateien",
|
|
339
|
+
maxSize: "4",
|
|
340
|
+
}),
|
|
341
|
+
);
|
|
342
|
+
});
|
|
343
|
+
|
|
259
344
|
it("maps Enter keybindings to immediate and queued submit intents", () => {
|
|
260
345
|
const enter = {
|
|
261
346
|
key: "Enter",
|