@agent-native/toolkit 0.14.2 → 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 +291 -80
- package/dist/composer/TiptapComposer.js.map +1 -1
- package/dist/composer/TiptapComposer.spec.js +60 -3
- 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 +90 -3
- package/src/composer/TiptapComposer.tsx +341 -82
- 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
|
@@ -148,7 +148,11 @@ function assetImageSource(payload: unknown): string | null {
|
|
|
148
148
|
);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
function assetTitle(
|
|
151
|
+
function assetTitle(
|
|
152
|
+
payload: unknown,
|
|
153
|
+
url: string,
|
|
154
|
+
generatedImageLabel: string,
|
|
155
|
+
): string {
|
|
152
156
|
if (payload && typeof payload === "object") {
|
|
153
157
|
const title = assetString((payload as AssetPickerPayload).title);
|
|
154
158
|
if (title) return title;
|
|
@@ -157,9 +161,9 @@ function assetTitle(payload: unknown, url: string): string {
|
|
|
157
161
|
}
|
|
158
162
|
try {
|
|
159
163
|
const name = new URL(url).pathname.split("/").filter(Boolean).pop();
|
|
160
|
-
return name ? decodeURIComponent(name) :
|
|
164
|
+
return name ? decodeURIComponent(name) : generatedImageLabel;
|
|
161
165
|
} catch {
|
|
162
|
-
return
|
|
166
|
+
return generatedImageLabel;
|
|
163
167
|
}
|
|
164
168
|
}
|
|
165
169
|
|
|
@@ -196,6 +200,7 @@ function UploadOnlyAttachButton({
|
|
|
196
200
|
onAttachmentError,
|
|
197
201
|
}: Pick<ComposerPlusMenuProps, "onAttachmentError">) {
|
|
198
202
|
const composerRuntime = useComposerRuntime();
|
|
203
|
+
const t = useComposerRuntimeAdapters().translate!;
|
|
199
204
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
200
205
|
const handleFilesSelected = async (files: FileList | null) => {
|
|
201
206
|
if (!files || files.length === 0) return;
|
|
@@ -205,7 +210,12 @@ function UploadOnlyAttachButton({
|
|
|
205
210
|
);
|
|
206
211
|
} catch (error) {
|
|
207
212
|
onAttachmentError?.(
|
|
208
|
-
formatAttachmentError(
|
|
213
|
+
formatAttachmentError(
|
|
214
|
+
error,
|
|
215
|
+
t("agentChat.composer.uploadFailed", {
|
|
216
|
+
defaultValue: "Could not upload the selected file.",
|
|
217
|
+
}),
|
|
218
|
+
),
|
|
209
219
|
);
|
|
210
220
|
}
|
|
211
221
|
};
|
|
@@ -228,14 +238,18 @@ function UploadOnlyAttachButton({
|
|
|
228
238
|
<button
|
|
229
239
|
type="button"
|
|
230
240
|
className="shrink-0 flex h-7 w-7 cursor-pointer items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-accent/50"
|
|
231
|
-
aria-label="
|
|
241
|
+
aria-label={t("agentChat.composer.upload", {
|
|
242
|
+
defaultValue: "Upload",
|
|
243
|
+
})}
|
|
232
244
|
onClick={() => inputRef.current?.click()}
|
|
233
245
|
>
|
|
234
246
|
<IconPlus className="h-4 w-4" />
|
|
235
247
|
</button>
|
|
236
248
|
</span>
|
|
237
249
|
</TooltipTrigger>
|
|
238
|
-
<TooltipContent>
|
|
250
|
+
<TooltipContent>
|
|
251
|
+
{t("agentChat.composer.upload", { defaultValue: "Upload" })}
|
|
252
|
+
</TooltipContent>
|
|
239
253
|
</Tooltip>
|
|
240
254
|
</>
|
|
241
255
|
);
|
|
@@ -363,7 +377,12 @@ function ComposerPlusMenuFull({
|
|
|
363
377
|
);
|
|
364
378
|
} catch (error) {
|
|
365
379
|
onAttachmentError?.(
|
|
366
|
-
formatAttachmentError(
|
|
380
|
+
formatAttachmentError(
|
|
381
|
+
error,
|
|
382
|
+
t("agentChat.composer.uploadFailed", {
|
|
383
|
+
defaultValue: "Could not upload the selected file.",
|
|
384
|
+
}),
|
|
385
|
+
),
|
|
367
386
|
);
|
|
368
387
|
}
|
|
369
388
|
};
|
|
@@ -390,17 +409,30 @@ function ComposerPlusMenuFull({
|
|
|
390
409
|
);
|
|
391
410
|
if (!res.ok) {
|
|
392
411
|
const body = await res.text().catch(() => "");
|
|
393
|
-
throw new Error(
|
|
412
|
+
throw new Error(
|
|
413
|
+
body ||
|
|
414
|
+
t("agentChat.composer.skill.uploadFailedStatus", {
|
|
415
|
+
status: res.status,
|
|
416
|
+
defaultValue: `Upload failed (${res.status})`,
|
|
417
|
+
}),
|
|
418
|
+
);
|
|
394
419
|
}
|
|
395
420
|
setSkillUploadStatus({
|
|
396
421
|
kind: "ok",
|
|
397
|
-
message:
|
|
422
|
+
message: t("agentChat.composer.skill.added", {
|
|
423
|
+
name: skillUploadFileName || `${slug}/SKILL.md`,
|
|
424
|
+
defaultValue: `Skill "${skillUploadFileName || `${slug}/SKILL.md`}" added`,
|
|
425
|
+
}),
|
|
398
426
|
});
|
|
399
427
|
window.setTimeout(() => setOpen(false), 1200);
|
|
400
428
|
} catch (err: any) {
|
|
401
429
|
setSkillUploadStatus({
|
|
402
430
|
kind: "err",
|
|
403
|
-
message:
|
|
431
|
+
message:
|
|
432
|
+
err?.message ||
|
|
433
|
+
t("agentChat.composer.skill.saveFailed", {
|
|
434
|
+
defaultValue: "Failed to save skill file",
|
|
435
|
+
}),
|
|
404
436
|
});
|
|
405
437
|
} finally {
|
|
406
438
|
setSkillUploadBusy(false);
|
|
@@ -413,11 +445,16 @@ function ComposerPlusMenuFull({
|
|
|
413
445
|
desc: string;
|
|
414
446
|
action: () => void;
|
|
415
447
|
hoverAction?: () => void;
|
|
448
|
+
isSkill?: boolean;
|
|
416
449
|
}[] = [
|
|
417
450
|
{
|
|
418
451
|
icon: <IconUpload className="h-3.5 w-3.5" />,
|
|
419
|
-
label: "
|
|
420
|
-
|
|
452
|
+
label: t("agentChat.composer.menu.uploadFile", {
|
|
453
|
+
defaultValue: "Upload File",
|
|
454
|
+
}),
|
|
455
|
+
desc: t("agentChat.composer.menu.uploadFileDescription", {
|
|
456
|
+
defaultValue: "Images, PDFs, text/code, JSON, CSV",
|
|
457
|
+
}),
|
|
421
458
|
action: () => {
|
|
422
459
|
setOpen(false);
|
|
423
460
|
setTimeout(() => fileUploadRef.current?.click(), 0);
|
|
@@ -425,8 +462,12 @@ function ComposerPlusMenuFull({
|
|
|
425
462
|
},
|
|
426
463
|
{
|
|
427
464
|
icon: <IconPhotoPlus className="h-3.5 w-3.5" />,
|
|
428
|
-
label: "
|
|
429
|
-
|
|
465
|
+
label: t("agentChat.composer.menu.generateImage", {
|
|
466
|
+
defaultValue: "Generate Image",
|
|
467
|
+
}),
|
|
468
|
+
desc: t("agentChat.composer.menu.generateImageDescription", {
|
|
469
|
+
defaultValue: "Open the Assets image picker",
|
|
470
|
+
}),
|
|
430
471
|
action: () => {
|
|
431
472
|
setOpen(false);
|
|
432
473
|
setAssetsPickerOpen(true);
|
|
@@ -434,8 +475,12 @@ function ComposerPlusMenuFull({
|
|
|
434
475
|
},
|
|
435
476
|
{
|
|
436
477
|
icon: <IconClock className="h-3.5 w-3.5" />,
|
|
437
|
-
label: "
|
|
438
|
-
|
|
478
|
+
label: t("agentChat.composer.menu.scheduleTask", {
|
|
479
|
+
defaultValue: "Schedule Task",
|
|
480
|
+
}),
|
|
481
|
+
desc: t("agentChat.composer.menu.scheduleTaskDescription", {
|
|
482
|
+
defaultValue: "Run something on a schedule",
|
|
483
|
+
}),
|
|
439
484
|
action: () => {
|
|
440
485
|
onSelectMode?.("job");
|
|
441
486
|
setOpen(false);
|
|
@@ -443,8 +488,12 @@ function ComposerPlusMenuFull({
|
|
|
443
488
|
},
|
|
444
489
|
{
|
|
445
490
|
icon: <IconBolt className="h-3.5 w-3.5" />,
|
|
446
|
-
label: "
|
|
447
|
-
|
|
491
|
+
label: t("agentChat.composer.menu.createAutomation", {
|
|
492
|
+
defaultValue: "Create Automation",
|
|
493
|
+
}),
|
|
494
|
+
desc: t("agentChat.composer.menu.createAutomationDescription", {
|
|
495
|
+
defaultValue: "Set up a when-X-do-Y rule",
|
|
496
|
+
}),
|
|
448
497
|
action: () => {
|
|
449
498
|
onSelectMode?.("automation");
|
|
450
499
|
setOpen(false);
|
|
@@ -454,8 +503,12 @@ function ComposerPlusMenuFull({
|
|
|
454
503
|
? [
|
|
455
504
|
{
|
|
456
505
|
icon: <IconTool className="h-3.5 w-3.5" />,
|
|
457
|
-
label: "
|
|
458
|
-
|
|
506
|
+
label: t("agentChat.composer.menu.createExtension", {
|
|
507
|
+
defaultValue: "Create Extension",
|
|
508
|
+
}),
|
|
509
|
+
desc: t("agentChat.composer.menu.createExtensionDescription", {
|
|
510
|
+
defaultValue: "Build a mini app extension",
|
|
511
|
+
}),
|
|
459
512
|
action: () => {
|
|
460
513
|
onSelectMode?.("extension");
|
|
461
514
|
setOpen(false);
|
|
@@ -467,8 +520,12 @@ function ComposerPlusMenuFull({
|
|
|
467
520
|
? [
|
|
468
521
|
{
|
|
469
522
|
icon: <IconPlugConnected className="h-3.5 w-3.5" />,
|
|
470
|
-
label: t("
|
|
471
|
-
|
|
523
|
+
label: t("agentChat.composer.menu.integrations", {
|
|
524
|
+
defaultValue: "Integrations",
|
|
525
|
+
}),
|
|
526
|
+
desc: t("agentChat.composer.menu.integrationsDescription", {
|
|
527
|
+
defaultValue: "Connect tools and services to the agent",
|
|
528
|
+
}),
|
|
472
529
|
action: () => {
|
|
473
530
|
setOpen(false);
|
|
474
531
|
setMcpDialogOpen(true);
|
|
@@ -478,10 +535,15 @@ function ComposerPlusMenuFull({
|
|
|
478
535
|
: []),
|
|
479
536
|
{
|
|
480
537
|
icon: <IconBulb className="h-3.5 w-3.5" />,
|
|
481
|
-
label: "
|
|
482
|
-
|
|
538
|
+
label: t("agentChat.composer.menu.createSkill", {
|
|
539
|
+
defaultValue: "Create Skill",
|
|
540
|
+
}),
|
|
541
|
+
desc: t("agentChat.composer.menu.createSkillDescription", {
|
|
542
|
+
defaultValue: "Teach the agent a new ability",
|
|
543
|
+
}),
|
|
483
544
|
action: openSkillFlyout,
|
|
484
545
|
hoverAction: openSkillFlyout,
|
|
546
|
+
isSkill: true,
|
|
485
547
|
},
|
|
486
548
|
];
|
|
487
549
|
|
|
@@ -516,7 +578,9 @@ function ComposerPlusMenuFull({
|
|
|
516
578
|
<PopoverTrigger asChild>
|
|
517
579
|
<button
|
|
518
580
|
type="button"
|
|
519
|
-
aria-label="
|
|
581
|
+
aria-label={t("agentChat.composer.add", {
|
|
582
|
+
defaultValue: "Add...",
|
|
583
|
+
})}
|
|
520
584
|
className="shrink-0 flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-accent/50 disabled:opacity-30 disabled:cursor-not-allowed"
|
|
521
585
|
>
|
|
522
586
|
<IconPlus className="h-4 w-4" />
|
|
@@ -524,7 +588,9 @@ function ComposerPlusMenuFull({
|
|
|
524
588
|
</PopoverTrigger>
|
|
525
589
|
</span>
|
|
526
590
|
</TooltipTrigger>
|
|
527
|
-
<TooltipContent>
|
|
591
|
+
<TooltipContent>
|
|
592
|
+
{t("agentChat.composer.add", { defaultValue: "Add..." })}
|
|
593
|
+
</TooltipContent>
|
|
528
594
|
</Tooltip>
|
|
529
595
|
<PopoverContent
|
|
530
596
|
side="top"
|
|
@@ -542,7 +608,7 @@ function ComposerPlusMenuFull({
|
|
|
542
608
|
{view === "menu" && (
|
|
543
609
|
<div className="py-1">
|
|
544
610
|
{menuItems.map((item) => {
|
|
545
|
-
const isSkill = item.
|
|
611
|
+
const isSkill = item.isSkill === true;
|
|
546
612
|
return (
|
|
547
613
|
<div
|
|
548
614
|
key={item.label}
|
|
@@ -619,10 +685,15 @@ function ComposerPlusMenuFull({
|
|
|
619
685
|
</span>
|
|
620
686
|
<div className="min-w-0">
|
|
621
687
|
<div className="text-[12px] font-medium text-foreground">
|
|
622
|
-
|
|
688
|
+
{t("agentChat.composer.skill.createNew", {
|
|
689
|
+
defaultValue: "Create new skill",
|
|
690
|
+
})}
|
|
623
691
|
</div>
|
|
624
692
|
<div className="mt-0.5 text-[10px] text-muted-foreground/60">
|
|
625
|
-
|
|
693
|
+
{t("agentChat.composer.skill.createDescription", {
|
|
694
|
+
defaultValue:
|
|
695
|
+
"Describe a skill and let the agent draft it",
|
|
696
|
+
})}
|
|
626
697
|
</div>
|
|
627
698
|
</div>
|
|
628
699
|
</button>
|
|
@@ -639,10 +710,15 @@ function ComposerPlusMenuFull({
|
|
|
639
710
|
</span>
|
|
640
711
|
<div className="min-w-0">
|
|
641
712
|
<div className="text-[12px] font-medium text-foreground">
|
|
642
|
-
|
|
713
|
+
{t("agentChat.composer.skill.uploadFile", {
|
|
714
|
+
defaultValue: "Upload skill file",
|
|
715
|
+
})}
|
|
643
716
|
</div>
|
|
644
717
|
<div className="mt-0.5 text-[10px] text-muted-foreground/60">
|
|
645
|
-
|
|
718
|
+
{t("agentChat.composer.skill.uploadDescription", {
|
|
719
|
+
defaultValue:
|
|
720
|
+
"Import an existing SKILL.md file",
|
|
721
|
+
})}
|
|
646
722
|
</div>
|
|
647
723
|
</div>
|
|
648
724
|
</button>
|
|
@@ -662,20 +738,29 @@ function ComposerPlusMenuFull({
|
|
|
662
738
|
className="mb-1.5 flex items-center gap-1 text-[11px] text-muted-foreground hover:text-foreground"
|
|
663
739
|
>
|
|
664
740
|
<IconArrowLeft className="h-3 w-3 rtl:-scale-x-100" />
|
|
665
|
-
|
|
741
|
+
{t("agentChat.composer.skill.back", {
|
|
742
|
+
defaultValue: "Back",
|
|
743
|
+
})}
|
|
666
744
|
</button>
|
|
667
745
|
<label className="mb-1 block text-[11px] font-semibold text-foreground">
|
|
668
|
-
|
|
746
|
+
{t("agentChat.composer.skill.uploadFile", {
|
|
747
|
+
defaultValue: "Upload skill file",
|
|
748
|
+
})}
|
|
669
749
|
</label>
|
|
670
750
|
<p className="mb-2 text-[10px] leading-relaxed text-muted-foreground/60">
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
751
|
+
{t("agentChat.composer.skill.review", {
|
|
752
|
+
name:
|
|
753
|
+
skillUploadFileName ||
|
|
754
|
+
t("agentChat.composer.skill.selectedFile", {
|
|
755
|
+
defaultValue: "the selected file",
|
|
756
|
+
}),
|
|
757
|
+
defaultValue: `Review the content from ${skillUploadFileName || "the selected file"} before saving.`,
|
|
758
|
+
})}
|
|
676
759
|
</p>
|
|
677
760
|
<label className="mb-1 block text-[10px] font-medium text-muted-foreground">
|
|
678
|
-
|
|
761
|
+
{t("agentChat.composer.skill.name", {
|
|
762
|
+
defaultValue: "Skill name",
|
|
763
|
+
})}
|
|
679
764
|
</label>
|
|
680
765
|
<input
|
|
681
766
|
value={skillUploadSlug}
|
|
@@ -684,14 +769,18 @@ function ComposerPlusMenuFull({
|
|
|
684
769
|
placeholder="my-skill"
|
|
685
770
|
/>
|
|
686
771
|
<p className="mb-2 text-[10px] text-muted-foreground/60">
|
|
687
|
-
|
|
772
|
+
{t("agentChat.composer.skill.savedAt", {
|
|
773
|
+
defaultValue: "Saved at",
|
|
774
|
+
})}{" "}
|
|
688
775
|
<span className="font-mono">
|
|
689
776
|
skills/{slugifyName(skillUploadSlug || "uploaded-skill")}
|
|
690
777
|
/SKILL.md
|
|
691
778
|
</span>
|
|
692
779
|
</p>
|
|
693
780
|
<label className="mb-1 block text-[10px] font-medium text-muted-foreground">
|
|
694
|
-
|
|
781
|
+
{t("agentChat.composer.skill.content", {
|
|
782
|
+
defaultValue: "Content",
|
|
783
|
+
})}
|
|
695
784
|
</label>
|
|
696
785
|
<textarea
|
|
697
786
|
value={skillUploadContent}
|
|
@@ -717,7 +806,9 @@ function ComposerPlusMenuFull({
|
|
|
717
806
|
onClick={() => setView("menu")}
|
|
718
807
|
className="rounded-md px-3 py-1.5 text-[12px] font-medium text-muted-foreground hover:bg-accent/40"
|
|
719
808
|
>
|
|
720
|
-
|
|
809
|
+
{t("agentChat.common.cancel", {
|
|
810
|
+
defaultValue: "Cancel",
|
|
811
|
+
})}
|
|
721
812
|
</button>
|
|
722
813
|
<button
|
|
723
814
|
type="button"
|
|
@@ -732,7 +823,7 @@ function ComposerPlusMenuFull({
|
|
|
732
823
|
{skillUploadBusy ? (
|
|
733
824
|
<IconLoader2 className="h-3 w-3 animate-spin" />
|
|
734
825
|
) : (
|
|
735
|
-
"Save"
|
|
826
|
+
t("agentChat.common.save", { defaultValue: "Save" })
|
|
736
827
|
)}
|
|
737
828
|
</button>
|
|
738
829
|
</div>
|
|
@@ -766,6 +857,7 @@ function AssetsPickerModal({
|
|
|
766
857
|
onOpenChange: (open: boolean) => void;
|
|
767
858
|
}) {
|
|
768
859
|
const adapters = useComposerRuntimeAdapters();
|
|
860
|
+
const t = adapters.translate!;
|
|
769
861
|
const iframeRef = useRef<HTMLIFrameElement | null>(null);
|
|
770
862
|
const standaloneWindowRef = useRef<Window | null>(null);
|
|
771
863
|
const [pickerReady, setPickerReady] = useState(false);
|
|
@@ -862,14 +954,23 @@ function AssetsPickerModal({
|
|
|
862
954
|
|
|
863
955
|
const url = assetImageSource(event.data.payload);
|
|
864
956
|
if (!url) return;
|
|
865
|
-
const title = assetTitle(
|
|
957
|
+
const title = assetTitle(
|
|
958
|
+
event.data.payload,
|
|
959
|
+
url,
|
|
960
|
+
t("agentChat.composer.assets.generatedImage", {
|
|
961
|
+
defaultValue: "Generated image",
|
|
962
|
+
}),
|
|
963
|
+
);
|
|
866
964
|
const assetId =
|
|
867
965
|
event.data.payload && typeof event.data.payload === "object"
|
|
868
966
|
? assetString((event.data.payload as AssetPickerPayload).assetId)
|
|
869
967
|
: null;
|
|
870
968
|
adapters.agentChat!.setContextItem!({
|
|
871
969
|
key: `asset-image:${assetId ?? url}`,
|
|
872
|
-
title:
|
|
970
|
+
title: t("agentChat.composer.assets.contextTitle", {
|
|
971
|
+
title,
|
|
972
|
+
defaultValue: `Image: ${title}`,
|
|
973
|
+
}),
|
|
873
974
|
context: assetContext(event.data.payload, url),
|
|
874
975
|
});
|
|
875
976
|
standaloneWindowRef.current = null;
|
|
@@ -894,6 +995,7 @@ function AssetsPickerModal({
|
|
|
894
995
|
onOpenChange,
|
|
895
996
|
open,
|
|
896
997
|
standaloneHandoffId,
|
|
998
|
+
t,
|
|
897
999
|
targetOrigin,
|
|
898
1000
|
]);
|
|
899
1001
|
|
|
@@ -927,13 +1029,17 @@ function AssetsPickerModal({
|
|
|
927
1029
|
id="composer-assets-picker-title"
|
|
928
1030
|
className="text-sm font-medium text-foreground"
|
|
929
1031
|
>
|
|
930
|
-
|
|
1032
|
+
{t("agentChat.composer.assets.generateImage", {
|
|
1033
|
+
defaultValue: "Generate image",
|
|
1034
|
+
})}
|
|
931
1035
|
</div>
|
|
932
1036
|
<button
|
|
933
1037
|
type="button"
|
|
934
1038
|
onClick={() => onOpenChange(false)}
|
|
935
1039
|
className="flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
936
|
-
aria-label="
|
|
1040
|
+
aria-label={t("agentChat.composer.assets.closePicker", {
|
|
1041
|
+
defaultValue: "Close image picker",
|
|
1042
|
+
})}
|
|
937
1043
|
>
|
|
938
1044
|
<IconX className="h-4 w-4" />
|
|
939
1045
|
</button>
|
|
@@ -941,7 +1047,10 @@ function AssetsPickerModal({
|
|
|
941
1047
|
{externalPicker ? (
|
|
942
1048
|
<div className="flex min-h-0 flex-1 flex-col items-center justify-center gap-3 p-8 text-center">
|
|
943
1049
|
<div className="max-w-md text-sm text-muted-foreground">
|
|
944
|
-
|
|
1050
|
+
{t("agentChat.composer.assets.openSecurely", {
|
|
1051
|
+
defaultValue:
|
|
1052
|
+
"Open Assets in a new tab to sign in and choose an image securely.",
|
|
1053
|
+
})}
|
|
945
1054
|
</div>
|
|
946
1055
|
<a
|
|
947
1056
|
href={standaloneUrl}
|
|
@@ -949,7 +1058,9 @@ function AssetsPickerModal({
|
|
|
949
1058
|
onClick={openStandalonePicker}
|
|
950
1059
|
className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground hover:bg-primary/90"
|
|
951
1060
|
>
|
|
952
|
-
|
|
1061
|
+
{t("agentChat.composer.assets.openPicker", {
|
|
1062
|
+
defaultValue: "Open Assets image picker",
|
|
1063
|
+
})}
|
|
953
1064
|
</a>
|
|
954
1065
|
</div>
|
|
955
1066
|
) : targetOrigin ? (
|
|
@@ -958,7 +1069,9 @@ function AssetsPickerModal({
|
|
|
958
1069
|
<iframe
|
|
959
1070
|
ref={iframeRef}
|
|
960
1071
|
src={iframeUrl}
|
|
961
|
-
title="
|
|
1072
|
+
title={t("agentChat.composer.assets.pickerTitle", {
|
|
1073
|
+
defaultValue: "Assets image picker",
|
|
1074
|
+
})}
|
|
962
1075
|
className={cn(
|
|
963
1076
|
"absolute inset-0 h-full w-full border-0 bg-background transition-opacity duration-150",
|
|
964
1077
|
pickerReady ? "opacity-100" : "pointer-events-none opacity-0",
|
|
@@ -974,7 +1087,9 @@ function AssetsPickerModal({
|
|
|
974
1087
|
</div>
|
|
975
1088
|
) : (
|
|
976
1089
|
<div className="flex min-h-0 flex-1 items-center justify-center p-8 text-center text-sm text-muted-foreground">
|
|
977
|
-
|
|
1090
|
+
{t("agentChat.composer.assets.invalidUrl", {
|
|
1091
|
+
defaultValue: "The configured image picker URL is not valid.",
|
|
1092
|
+
})}
|
|
978
1093
|
</div>
|
|
979
1094
|
)}
|
|
980
1095
|
</div>
|
|
@@ -984,11 +1099,14 @@ function AssetsPickerModal({
|
|
|
984
1099
|
}
|
|
985
1100
|
|
|
986
1101
|
function AssetsPickerLoadingSkeleton() {
|
|
1102
|
+
const t = useComposerRuntimeAdapters().translate!;
|
|
987
1103
|
return (
|
|
988
1104
|
<div
|
|
989
1105
|
className="absolute inset-0 flex flex-col gap-5 p-5"
|
|
990
1106
|
role="status"
|
|
991
|
-
aria-label="
|
|
1107
|
+
aria-label={t("agentChat.composer.assets.loadingPicker", {
|
|
1108
|
+
defaultValue: "Loading Assets picker",
|
|
1109
|
+
})}
|
|
992
1110
|
>
|
|
993
1111
|
<div className="flex items-center gap-3">
|
|
994
1112
|
<div className="h-9 flex-1 animate-pulse rounded-md bg-muted" />
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
TooltipProvider,
|
|
32
32
|
TooltipTrigger,
|
|
33
33
|
} from "../ui/tooltip.js";
|
|
34
|
+
import { useComposerRuntimeAdapters } from "./runtime-adapters.js";
|
|
34
35
|
import type { MentionItem, SkillResult, SlashCommand } from "./types.js";
|
|
35
36
|
|
|
36
37
|
export interface MentionPopoverRef {
|
|
@@ -101,6 +102,7 @@ function CommandIcon({ icon }: { icon?: string }) {
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
function HintWithLink({ hint }: { hint: string }) {
|
|
105
|
+
const t = useComposerRuntimeAdapters().translate!;
|
|
104
106
|
// If hint contains a URL, split it and render the URL as a link
|
|
105
107
|
const urlMatch = hint.match(/(https?:\/\/\S+)/);
|
|
106
108
|
if (!urlMatch) return <>{hint}</>;
|
|
@@ -115,7 +117,7 @@ function HintWithLink({ hint }: { hint: string }) {
|
|
|
115
117
|
rel="noopener noreferrer"
|
|
116
118
|
className="underline hover:text-foreground"
|
|
117
119
|
>
|
|
118
|
-
Learn more
|
|
120
|
+
{t("agentChat.mentions.learnMore", { defaultValue: "Learn more" })}
|
|
119
121
|
</a>
|
|
120
122
|
</>
|
|
121
123
|
);
|
|
@@ -190,6 +192,30 @@ export const MentionPopover = forwardRef<
|
|
|
190
192
|
|
|
191
193
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
192
194
|
const listRef = useRef<HTMLDivElement>(null);
|
|
195
|
+
const t = useComposerRuntimeAdapters().translate!;
|
|
196
|
+
|
|
197
|
+
const sectionLabel = (section: string) => {
|
|
198
|
+
switch (section) {
|
|
199
|
+
case "Agents":
|
|
200
|
+
return t("agentChat.mentions.sections.agents", {
|
|
201
|
+
defaultValue: "Agents",
|
|
202
|
+
});
|
|
203
|
+
case "Connected Agents":
|
|
204
|
+
return t("agentChat.mentions.sections.connectedAgents", {
|
|
205
|
+
defaultValue: "Connected Agents",
|
|
206
|
+
});
|
|
207
|
+
case "Files":
|
|
208
|
+
return t("agentChat.mentions.sections.files", {
|
|
209
|
+
defaultValue: "Files",
|
|
210
|
+
});
|
|
211
|
+
case "Other":
|
|
212
|
+
return t("agentChat.mentions.sections.other", {
|
|
213
|
+
defaultValue: "Other",
|
|
214
|
+
});
|
|
215
|
+
default:
|
|
216
|
+
return section;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
193
219
|
|
|
194
220
|
const itemCount =
|
|
195
221
|
type === "@" ? mentionItems.length : commands.length + skills.length;
|
|
@@ -302,14 +328,20 @@ export const MentionPopover = forwardRef<
|
|
|
302
328
|
<div className="px-3 py-4 text-center text-xs text-muted-foreground">
|
|
303
329
|
{type === "@" ? (
|
|
304
330
|
query ? (
|
|
305
|
-
"
|
|
331
|
+
t("agentChat.mentions.noResults", {
|
|
332
|
+
defaultValue: "No results found",
|
|
333
|
+
})
|
|
306
334
|
) : (
|
|
307
|
-
"
|
|
335
|
+
t("agentChat.mentions.typeToSearch", {
|
|
336
|
+
defaultValue: "Type to search...",
|
|
337
|
+
})
|
|
308
338
|
)
|
|
309
339
|
) : hint ? (
|
|
310
340
|
<HintWithLink hint={hint} />
|
|
311
341
|
) : (
|
|
312
|
-
"
|
|
342
|
+
t("agentChat.mentions.noSkills", {
|
|
343
|
+
defaultValue: "No skills available",
|
|
344
|
+
})
|
|
313
345
|
)}
|
|
314
346
|
</div>
|
|
315
347
|
) : (
|
|
@@ -321,7 +353,7 @@ export const MentionPopover = forwardRef<
|
|
|
321
353
|
return groupedMentions.map((group) => (
|
|
322
354
|
<div key={group.section}>
|
|
323
355
|
<div className="px-2 pt-2 pb-1 text-[10px] font-medium text-muted-foreground/70 uppercase tracking-wider">
|
|
324
|
-
{group.section}
|
|
356
|
+
{sectionLabel(group.section)}
|
|
325
357
|
</div>
|
|
326
358
|
{group.items.map((item) => {
|
|
327
359
|
const idx = flatIndex++;
|
|
@@ -359,7 +391,9 @@ export const MentionPopover = forwardRef<
|
|
|
359
391
|
{commands.length > 0 && (
|
|
360
392
|
<div>
|
|
361
393
|
<div className="px-2 pt-2 pb-1 text-[10px] font-medium text-muted-foreground/70 uppercase tracking-wider">
|
|
362
|
-
|
|
394
|
+
{t("agentChat.mentions.commands", {
|
|
395
|
+
defaultValue: "Commands",
|
|
396
|
+
})}
|
|
363
397
|
</div>
|
|
364
398
|
{commands.map((cmd) => {
|
|
365
399
|
const i = idx++;
|
|
@@ -395,7 +429,9 @@ export const MentionPopover = forwardRef<
|
|
|
395
429
|
<div>
|
|
396
430
|
{commands.length > 0 && (
|
|
397
431
|
<div className="px-2 pt-2 pb-1 text-[10px] font-medium text-muted-foreground/70 uppercase tracking-wider">
|
|
398
|
-
|
|
432
|
+
{t("agentChat.mentions.skills", {
|
|
433
|
+
defaultValue: "Skills",
|
|
434
|
+
})}
|
|
399
435
|
</div>
|
|
400
436
|
)}
|
|
401
437
|
<TooltipProvider delayDuration={200}>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
|
|
3
|
+
import type { Attachment } from "@assistant-ui/react";
|
|
4
|
+
import { act } from "react";
|
|
5
|
+
import { createRoot, type Root } from "react-dom/client";
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
|
+
|
|
8
|
+
import { PastedTextChip } from "./PastedTextChip.js";
|
|
9
|
+
import { ComposerRuntimeAdaptersProvider } from "./runtime-adapters.js";
|
|
10
|
+
|
|
11
|
+
describe("PastedTextChip", () => {
|
|
12
|
+
let container: HTMLDivElement;
|
|
13
|
+
let root: Root;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
17
|
+
container = document.createElement("div");
|
|
18
|
+
document.body.appendChild(container);
|
|
19
|
+
root = createRoot(container);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
act(() => root.unmount());
|
|
24
|
+
container.remove();
|
|
25
|
+
vi.unstubAllGlobals();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("formats pasted-text counts with the runtime locale formatter", async () => {
|
|
29
|
+
const text = Array.from({ length: 12_345 }, () => "line").join("\n");
|
|
30
|
+
const attachment = {
|
|
31
|
+
id: "pasted-1",
|
|
32
|
+
type: "file",
|
|
33
|
+
name: "pasted-text-1.txt",
|
|
34
|
+
content: [{ type: "text", text }],
|
|
35
|
+
} as Attachment;
|
|
36
|
+
|
|
37
|
+
await act(async () => {
|
|
38
|
+
root.render(
|
|
39
|
+
<ComposerRuntimeAdaptersProvider
|
|
40
|
+
adapters={{
|
|
41
|
+
formatNumber: (value) =>
|
|
42
|
+
new Intl.NumberFormat("de-DE").format(value),
|
|
43
|
+
translate: (key, options) =>
|
|
44
|
+
key === "agentChat.pastedText.lines"
|
|
45
|
+
? `${String(options?.formattedCount)} lines`
|
|
46
|
+
: String(options?.defaultValue ?? key),
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
<PastedTextChip attachment={attachment} />
|
|
50
|
+
</ComposerRuntimeAdaptersProvider>,
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await vi.waitFor(() => {
|
|
55
|
+
expect(container.textContent).toContain("12.345 lines");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|