@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
|
@@ -168,6 +168,7 @@ function isDocumentAttachment(value) {
|
|
|
168
168
|
export function getOversizedDocumentAttachmentError(attachments, options = {}) {
|
|
169
169
|
const maxBytes = options.maxBytes ?? MAX_DOCUMENT_ATTACHMENT_BYTES;
|
|
170
170
|
const label = options.label ?? "PDFs";
|
|
171
|
+
const t = options.translate;
|
|
171
172
|
for (const attachment of attachments) {
|
|
172
173
|
if (!attachment || typeof attachment !== "object")
|
|
173
174
|
continue;
|
|
@@ -184,7 +185,14 @@ export function getOversizedDocumentAttachmentError(attachments, options = {}) {
|
|
|
184
185
|
: file.name;
|
|
185
186
|
const mb = (file.size / 1024 / 1024).toFixed(1);
|
|
186
187
|
const maxMb = (maxBytes / 1024 / 1024).toFixed(0);
|
|
187
|
-
return
|
|
188
|
+
return (t?.("agentChat.composer.documentTooLarge", {
|
|
189
|
+
defaultValue: '"{{name}}" is {{size}} MB. {{label}} are capped at {{maxSize}} MB to stay within message limits. Please reduce the file size or split it into smaller parts.',
|
|
190
|
+
name,
|
|
191
|
+
size: mb,
|
|
192
|
+
label,
|
|
193
|
+
maxSize: maxMb,
|
|
194
|
+
}) ??
|
|
195
|
+
`"${name}" is ${mb} MB. ${label} are capped at ${maxMb} MB to stay within message limits. Please reduce the file size or split it into smaller parts.`);
|
|
188
196
|
}
|
|
189
197
|
return null;
|
|
190
198
|
}
|
|
@@ -219,7 +227,9 @@ export function getComposerPopoverPosition(view, pos) {
|
|
|
219
227
|
}
|
|
220
228
|
export function displayableComposerModeMessage(options) {
|
|
221
229
|
const modePrompt = options.trimmedText ||
|
|
222
|
-
(options.attachmentCount > 0
|
|
230
|
+
(options.attachmentCount > 0
|
|
231
|
+
? (options.attachedContextFallback ?? "Use the attached context.")
|
|
232
|
+
: "");
|
|
223
233
|
return `${options.messagePrefix}${modePrompt}`;
|
|
224
234
|
}
|
|
225
235
|
function uniquifyComposerImageFile(file) {
|
|
@@ -255,14 +265,52 @@ export function handleComposerFileDrop(options) {
|
|
|
255
265
|
});
|
|
256
266
|
return true;
|
|
257
267
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
268
|
+
function builtInCommands(t) {
|
|
269
|
+
return [
|
|
270
|
+
{
|
|
271
|
+
name: "clear",
|
|
272
|
+
description: t("agentChat.commands.clearShort", {
|
|
273
|
+
defaultValue: "Start a new chat",
|
|
274
|
+
}),
|
|
275
|
+
icon: "clear",
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: "new",
|
|
279
|
+
description: t("agentChat.commands.newShort", {
|
|
280
|
+
defaultValue: "Start a new chat",
|
|
281
|
+
}),
|
|
282
|
+
icon: "new",
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
name: "history",
|
|
286
|
+
description: t("agentChat.commands.history", {
|
|
287
|
+
defaultValue: "Browse all chats",
|
|
288
|
+
}),
|
|
289
|
+
icon: "history",
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
name: "plan",
|
|
293
|
+
description: t("agentChat.commands.plan", {
|
|
294
|
+
defaultValue: "Switch to read-only planning",
|
|
295
|
+
}),
|
|
296
|
+
icon: "plan",
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
name: "act",
|
|
300
|
+
description: t("agentChat.commands.act", {
|
|
301
|
+
defaultValue: "Switch back to acting",
|
|
302
|
+
}),
|
|
303
|
+
icon: "act",
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
name: "help",
|
|
307
|
+
description: t("agentChat.commands.help", {
|
|
308
|
+
defaultValue: "Show available commands",
|
|
309
|
+
}),
|
|
310
|
+
icon: "help",
|
|
311
|
+
},
|
|
312
|
+
];
|
|
313
|
+
}
|
|
266
314
|
function normalizeSlashCommandName(name) {
|
|
267
315
|
return name.replace(/^\/+/, "").trim().toLowerCase();
|
|
268
316
|
}
|
|
@@ -292,10 +340,7 @@ function mergeSlashSkills(skills) {
|
|
|
292
340
|
}
|
|
293
341
|
const COMPOSER_MODE_CONFIGS = {
|
|
294
342
|
skill: {
|
|
295
|
-
label: "Create Skill",
|
|
296
343
|
icon: IconBulb,
|
|
297
|
-
placeholder: "Describe the skill you want to create...",
|
|
298
|
-
messagePrefix: "Create a skill: ",
|
|
299
344
|
getContext: (prompt) => `The user wants to create an agent skill. Their description: "${prompt}"
|
|
300
345
|
|
|
301
346
|
Follow the create-skill pattern to build this. Before writing:
|
|
@@ -316,10 +361,7 @@ After creating, update the shared AGENTS.md resource to reference the new skill
|
|
|
316
361
|
Keep the skill concise (under 500 lines) and actionable.`,
|
|
317
362
|
},
|
|
318
363
|
job: {
|
|
319
|
-
label: "Schedule Task",
|
|
320
364
|
icon: IconClock,
|
|
321
|
-
placeholder: "Describe what should happen and when...",
|
|
322
|
-
messagePrefix: "Create a recurring job: ",
|
|
323
365
|
getContext: (prompt) => `The user wants to create a recurring job. Their description: "${prompt}"
|
|
324
366
|
|
|
325
367
|
Use the manage-jobs tool with action "create" to create this. You need to:
|
|
@@ -331,10 +373,7 @@ Use the manage-jobs tool with action "create" to create this. You need to:
|
|
|
331
373
|
The job will run automatically on the schedule. Make the instructions specific — include which actions to call and what to do with results.`,
|
|
332
374
|
},
|
|
333
375
|
automation: {
|
|
334
|
-
label: "Create Automation",
|
|
335
376
|
icon: IconBolt,
|
|
336
|
-
placeholder: "Describe what you want to automate...",
|
|
337
|
-
messagePrefix: "Create an automation: ",
|
|
338
377
|
beforeSend: () => {
|
|
339
378
|
window.dispatchEvent(new CustomEvent("agent-panel:set-mode", {
|
|
340
379
|
detail: { mode: "chat" },
|
|
@@ -345,10 +384,7 @@ The job will run automatically on the schedule. Make the instructions specific
|
|
|
345
384
|
Use manage-automations with action=define to create it. Ask clarifying questions if needed about what event to trigger on, conditions, and what actions to take.`,
|
|
346
385
|
},
|
|
347
386
|
extension: {
|
|
348
|
-
label: "Create Extension",
|
|
349
387
|
icon: IconTool,
|
|
350
|
-
placeholder: "Describe the interactive extension you want to build...",
|
|
351
|
-
messagePrefix: "Create an extension: ",
|
|
352
388
|
getContext: (prompt) => `The user wants to create an interactive extension (sandboxed mini-app). Their description: "${prompt}"
|
|
353
389
|
|
|
354
390
|
Use the create-extension action with Alpine.js HTML content. The extension runs as a sandboxed iframe with Tailwind CSS and modest default canvas padding. For edge-to-edge layouts, put data-extension-layout="full-bleed" on the outermost element.
|
|
@@ -360,8 +396,59 @@ Make the extension functional and visually polished. Extensions can use extensio
|
|
|
360
396
|
Prefer appAction()/appFetch() for app data. Some actions return JSON strings for CLI compatibility, so parse string results before counting rows or reading arrays. Do not guess raw SQL table names or columns for app data; use dbQuery() only when the table is known to exist in the current schema.`,
|
|
361
397
|
},
|
|
362
398
|
};
|
|
363
|
-
function
|
|
399
|
+
function localizedComposerModeConfig(mode, t) {
|
|
364
400
|
const config = COMPOSER_MODE_CONFIGS[mode];
|
|
401
|
+
const copies = {
|
|
402
|
+
skill: {
|
|
403
|
+
label: t("agentChat.composer.createSkill", {
|
|
404
|
+
defaultValue: "Create Skill",
|
|
405
|
+
}),
|
|
406
|
+
placeholder: t("agentChat.composer.describeSkill", {
|
|
407
|
+
defaultValue: "Describe the skill you want to create...",
|
|
408
|
+
}),
|
|
409
|
+
messagePrefix: t("agentChat.composer.createSkillPrefix", {
|
|
410
|
+
defaultValue: "Create a skill: ",
|
|
411
|
+
}),
|
|
412
|
+
},
|
|
413
|
+
job: {
|
|
414
|
+
label: t("agentChat.composer.scheduleTask", {
|
|
415
|
+
defaultValue: "Schedule Task",
|
|
416
|
+
}),
|
|
417
|
+
placeholder: t("agentChat.composer.describeSchedule", {
|
|
418
|
+
defaultValue: "Describe what should happen and when...",
|
|
419
|
+
}),
|
|
420
|
+
messagePrefix: t("agentChat.composer.scheduleTaskPrefix", {
|
|
421
|
+
defaultValue: "Create a recurring job: ",
|
|
422
|
+
}),
|
|
423
|
+
},
|
|
424
|
+
automation: {
|
|
425
|
+
label: t("agentChat.composer.createAutomation", {
|
|
426
|
+
defaultValue: "Create Automation",
|
|
427
|
+
}),
|
|
428
|
+
placeholder: t("agentChat.composer.describeAutomation", {
|
|
429
|
+
defaultValue: "Describe what you want to automate...",
|
|
430
|
+
}),
|
|
431
|
+
messagePrefix: t("agentChat.composer.createAutomationPrefix", {
|
|
432
|
+
defaultValue: "Create an automation: ",
|
|
433
|
+
}),
|
|
434
|
+
},
|
|
435
|
+
extension: {
|
|
436
|
+
label: t("agentChat.composer.createExtension", {
|
|
437
|
+
defaultValue: "Create Extension",
|
|
438
|
+
}),
|
|
439
|
+
placeholder: t("agentChat.composer.describeExtension", {
|
|
440
|
+
defaultValue: "Describe the interactive extension you want to build...",
|
|
441
|
+
}),
|
|
442
|
+
messagePrefix: t("agentChat.composer.createExtensionPrefix", {
|
|
443
|
+
defaultValue: "Create an extension: ",
|
|
444
|
+
}),
|
|
445
|
+
},
|
|
446
|
+
};
|
|
447
|
+
return { ...config, ...copies[mode] };
|
|
448
|
+
}
|
|
449
|
+
function ComposerModeChip({ mode, onRemove, }) {
|
|
450
|
+
const t = useComposerRuntimeAdapters().translate;
|
|
451
|
+
const config = localizedComposerModeConfig(mode, t);
|
|
365
452
|
const Icon = config.icon;
|
|
366
453
|
return (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-md border border-border bg-muted/50 px-1.5 py-0.5 text-xs font-medium text-foreground", children: [_jsx(Icon, { className: "h-3 w-3 text-muted-foreground" }), config.label, _jsx("button", { type: "button", onClick: onRemove, className: "ms-0.5 rounded-sm text-muted-foreground hover:text-foreground cursor-pointer", children: _jsx(IconX, { className: "h-3 w-3" }) })] }));
|
|
367
454
|
}
|
|
@@ -410,21 +497,34 @@ export function createTiptapComposerExtensions(getPlaceholder) {
|
|
|
410
497
|
MentionReference,
|
|
411
498
|
];
|
|
412
499
|
}
|
|
413
|
-
function ModeSelector({ mode, onChange, planModeDisabled = false, planModeDisabledReason
|
|
500
|
+
function ModeSelector({ mode, onChange, planModeDisabled = false, planModeDisabledReason, }) {
|
|
501
|
+
const t = useComposerRuntimeAdapters().translate;
|
|
414
502
|
const [open, setOpen] = useState(false);
|
|
415
|
-
|
|
503
|
+
const resolvedPlanModeDisabledReason = planModeDisabledReason ??
|
|
504
|
+
t("agentChat.composer.planDesktopRequired", {
|
|
505
|
+
defaultValue: "Open Agent Native Desktop to use Plan mode.",
|
|
506
|
+
});
|
|
507
|
+
return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": mode === "build"
|
|
508
|
+
? t("agentChat.composer.actMode", { defaultValue: "Act mode" })
|
|
509
|
+
: t("agentChat.plan.mode", { defaultValue: "Plan mode" }), "data-agent-composer-slot": "mode-button", className: "agent-composer-mode-button shrink-0 flex items-center gap-1 rounded-md px-2 py-1 text-[12px] font-medium text-muted-foreground hover:bg-accent/50 hover:text-foreground", children: [mode === "build"
|
|
510
|
+
? t("agentChat.plan.act", { defaultValue: "Act" })
|
|
511
|
+
: t("agentChat.composer.plan", { defaultValue: "Plan" }), _jsx(IconChevronDown, { className: "h-3 w-3 opacity-60" })] }) }), _jsxs(PopoverContent, { side: "top", align: "end", sideOffset: 6, collisionPadding: 8, "data-agent-native-composer-popover": "true", className: "z-[260] w-60 rounded-lg border-border p-0 py-1 shadow-lg", style: { fontSize: 13 }, children: [_jsxs("button", { type: "button", onClick: () => {
|
|
416
512
|
onChange("build");
|
|
417
513
|
setOpen(false);
|
|
418
|
-
}, className: "flex w-full items-center gap-3 px-3 py-2 hover:bg-accent/50 text-start", children: [_jsx(IconPencil, { className: "h-4 w-4 shrink-0 text-muted-foreground" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("span", { className: "font-medium text-foreground text-[13px]", children: "Act" }), _jsx("p", { className: "text-[11px] text-muted-foreground mt-0.5", children:
|
|
514
|
+
}, className: "flex w-full items-center gap-3 px-3 py-2 hover:bg-accent/50 text-start", children: [_jsx(IconPencil, { className: "h-4 w-4 shrink-0 text-muted-foreground" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("span", { className: "font-medium text-foreground text-[13px]", children: t("agentChat.plan.act", { defaultValue: "Act" }) }), _jsx("p", { className: "text-[11px] text-muted-foreground mt-0.5", children: t("agentChat.composer.actDescription", {
|
|
515
|
+
defaultValue: "Use tools and make approved changes",
|
|
516
|
+
}) })] }), mode === "build" && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] }), _jsxs("button", { type: "button", disabled: planModeDisabled, title: planModeDisabled ? resolvedPlanModeDisabledReason : undefined, onClick: () => {
|
|
419
517
|
if (planModeDisabled)
|
|
420
518
|
return;
|
|
421
519
|
onChange("plan");
|
|
422
520
|
setOpen(false);
|
|
423
521
|
}, className: `flex w-full items-center gap-3 px-3 py-2 text-start ${planModeDisabled
|
|
424
522
|
? "cursor-not-allowed opacity-60"
|
|
425
|
-
: "hover:bg-accent/50"}`, children: [_jsx(IconClipboardList, { className: "h-4 w-4 shrink-0 text-muted-foreground" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("span", { className: "font-medium text-foreground text-[13px]", children: "Plan" }), _jsx("p", { className: "text-[11px] text-muted-foreground mt-0.5", children: planModeDisabled
|
|
426
|
-
?
|
|
427
|
-
:
|
|
523
|
+
: "hover:bg-accent/50"}`, children: [_jsx(IconClipboardList, { className: "h-4 w-4 shrink-0 text-muted-foreground" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("span", { className: "font-medium text-foreground text-[13px]", children: t("agentChat.composer.plan", { defaultValue: "Plan" }) }), _jsx("p", { className: "text-[11px] text-muted-foreground mt-0.5", children: planModeDisabled
|
|
524
|
+
? resolvedPlanModeDisabledReason
|
|
525
|
+
: t("agentChat.composer.planDescription", {
|
|
526
|
+
defaultValue: "Read-only research and approval first",
|
|
527
|
+
}) })] }), mode === "plan" && !planModeDisabled && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] })] })] }));
|
|
428
528
|
}
|
|
429
529
|
const FRIENDLY_MODEL_NAMES = {
|
|
430
530
|
auto: "Default model",
|
|
@@ -449,7 +549,12 @@ export function shouldShowModelSelectorSkeleton(isLoading, engineCount) {
|
|
|
449
549
|
export function shouldShowOnlyConnectPath(showBuilderCta, groups) {
|
|
450
550
|
return showBuilderCta && groups.every((group) => !group.configured);
|
|
451
551
|
}
|
|
452
|
-
function friendlyModelName(model) {
|
|
552
|
+
function friendlyModelName(model, t) {
|
|
553
|
+
if (model === "auto") {
|
|
554
|
+
return (t?.("agentChat.composer.defaultModel", {
|
|
555
|
+
defaultValue: "Default model",
|
|
556
|
+
}) ?? "Default model");
|
|
557
|
+
}
|
|
453
558
|
if (FRIENDLY_MODEL_NAMES[model])
|
|
454
559
|
return FRIENDLY_MODEL_NAMES[model];
|
|
455
560
|
// Claude: claude-{tier}-{major}[-minor][-dateYYYYMMDD] → Tier Major[.Minor]
|
|
@@ -496,21 +601,53 @@ function friendlyModelName(model) {
|
|
|
496
601
|
}
|
|
497
602
|
return model;
|
|
498
603
|
}
|
|
499
|
-
export function compactComposerModelName(model) {
|
|
604
|
+
export function compactComposerModelName(model, t) {
|
|
500
605
|
const gpt56Variant = model.match(/^(?:openai\/)?gpt-5[.-]6[.-](sol|terra|luna)$/i)?.[1];
|
|
501
606
|
if (gpt56Variant) {
|
|
502
|
-
|
|
607
|
+
const variant = gpt56Variant[0].toUpperCase() + gpt56Variant.slice(1).toLowerCase();
|
|
608
|
+
return `GPT-5.6 ${variant}`;
|
|
503
609
|
}
|
|
504
|
-
return friendlyModelName(model);
|
|
610
|
+
return friendlyModelName(model, t);
|
|
505
611
|
}
|
|
506
|
-
export function compactComposerReasoningEffortLabel(effort) {
|
|
507
|
-
if (effort === "medium" || effort === "auto")
|
|
508
|
-
return "
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
612
|
+
export function compactComposerReasoningEffortLabel(effort, t) {
|
|
613
|
+
if (effort === "medium" || effort === "auto") {
|
|
614
|
+
return (t?.("agentChat.composer.reasoningMediumShort", {
|
|
615
|
+
defaultValue: "Med",
|
|
616
|
+
}) ?? "Med");
|
|
617
|
+
}
|
|
618
|
+
if (effort === "minimal") {
|
|
619
|
+
return (t?.("agentChat.composer.reasoningMinimalShort", {
|
|
620
|
+
defaultValue: "Min",
|
|
621
|
+
}) ?? "Min");
|
|
622
|
+
}
|
|
623
|
+
if (effort === "xhigh") {
|
|
624
|
+
return (t?.("agentChat.composer.reasoningExtraHighShort", {
|
|
625
|
+
defaultValue: "XHigh",
|
|
626
|
+
}) ?? "XHigh");
|
|
627
|
+
}
|
|
628
|
+
return t
|
|
629
|
+
? localizedReasoningEffortLabel(t, effort, reasoningEffortLabel(effort))
|
|
630
|
+
: reasoningEffortLabel(effort);
|
|
631
|
+
}
|
|
632
|
+
function localizedReasoningEffortLabel(t, effort, defaultValue) {
|
|
633
|
+
switch (effort) {
|
|
634
|
+
case "auto":
|
|
635
|
+
return t("agentChat.composer.reasoningEffort.auto", { defaultValue });
|
|
636
|
+
case "none":
|
|
637
|
+
return t("agentChat.composer.reasoningEffort.none", { defaultValue });
|
|
638
|
+
case "minimal":
|
|
639
|
+
return t("agentChat.composer.reasoningEffort.minimal", { defaultValue });
|
|
640
|
+
case "low":
|
|
641
|
+
return t("agentChat.composer.reasoningEffort.low", { defaultValue });
|
|
642
|
+
case "medium":
|
|
643
|
+
return t("agentChat.composer.reasoningEffort.medium", { defaultValue });
|
|
644
|
+
case "high":
|
|
645
|
+
return t("agentChat.composer.reasoningEffort.high", { defaultValue });
|
|
646
|
+
case "xhigh":
|
|
647
|
+
return t("agentChat.composer.reasoningEffort.xhigh", { defaultValue });
|
|
648
|
+
case "max":
|
|
649
|
+
return t("agentChat.composer.reasoningEffort.max", { defaultValue });
|
|
650
|
+
}
|
|
514
651
|
}
|
|
515
652
|
/**
|
|
516
653
|
* Deduplicate models to only the latest version per family.
|
|
@@ -561,16 +698,21 @@ const MODEL_COST_TIERS = [
|
|
|
561
698
|
["flash", 1],
|
|
562
699
|
["pro", 3],
|
|
563
700
|
];
|
|
564
|
-
const COST_TIER_LABELS = { 1: "Lower", 2: "Medium", 3: "Higher" };
|
|
565
701
|
export function composerModelCostTier(model) {
|
|
566
702
|
const normalized = model.toLowerCase();
|
|
567
703
|
return MODEL_COST_TIERS.find(([token]) => normalized.includes(token))?.[1];
|
|
568
704
|
}
|
|
569
705
|
function ModelCostTier({ model }) {
|
|
706
|
+
const t = useComposerRuntimeAdapters().translate;
|
|
570
707
|
const tier = composerModelCostTier(model);
|
|
571
708
|
if (!tier)
|
|
572
709
|
return null;
|
|
573
|
-
|
|
710
|
+
const costLabel = tier === 1
|
|
711
|
+
? t("agentChat.composer.costLower", { defaultValue: "Lower cost" })
|
|
712
|
+
: tier === 2
|
|
713
|
+
? t("agentChat.composer.costMedium", { defaultValue: "Medium cost" })
|
|
714
|
+
: t("agentChat.composer.costHigher", { defaultValue: "Higher cost" });
|
|
715
|
+
return (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", className: "shrink-0 text-[11px] tabular-nums text-muted-foreground/60", children: "$".repeat(tier) }), _jsx("span", { className: "sr-only", children: costLabel })] }));
|
|
574
716
|
}
|
|
575
717
|
export function getComposerReasoningEffortOptions(model) {
|
|
576
718
|
return model === "auto"
|
|
@@ -596,7 +738,7 @@ function ModelSelector({ model, effort, engines, showAutoModelOption = true, mod
|
|
|
596
738
|
getComposerReasoningEffortOptions(model);
|
|
597
739
|
const selectedEffort = reasoning?.resolve?.(model, effort) ??
|
|
598
740
|
resolveReasoningEffortSelection(model, effort ?? defaultEffort);
|
|
599
|
-
const effortLabel = reasoning?.label ?? reasoningEffortLabel;
|
|
741
|
+
const effortLabel = useCallback((value) => localizedReasoningEffortLabel(t, value, (reasoning?.label ?? reasoningEffortLabel)(value)), [reasoning?.label, t]);
|
|
600
742
|
// Collapse non-selected families by default. The family containing the
|
|
601
743
|
// currently-selected model stays expanded so the user sees their pick at
|
|
602
744
|
// a glance; clicking another family's header expands it inline.
|
|
@@ -668,9 +810,13 @@ function ModelSelector({ model, effort, engines, showAutoModelOption = true, mod
|
|
|
668
810
|
onConnectLocalRuntime?.(engine);
|
|
669
811
|
setOpen(false);
|
|
670
812
|
}, [onConnectLocalRuntime]);
|
|
671
|
-
return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", "data-agent-composer-slot": "model-button", "aria-label":
|
|
672
|
-
|
|
673
|
-
|
|
813
|
+
return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", "data-agent-composer-slot": "model-button", "aria-label": `${t("agentChat.composer.model", {
|
|
814
|
+
defaultValue: "Model",
|
|
815
|
+
})}: ${friendlyModelName(model, t)}${effortOptions.length > 0
|
|
816
|
+
? `. ${t("agentChat.composer.reasoning", {
|
|
817
|
+
defaultValue: "Reasoning",
|
|
818
|
+
})}: ${effortLabel(selectedEffort)}`
|
|
819
|
+
: ""}`, className: "agent-composer-model-button flex min-w-0 max-w-[10.5rem] shrink items-center gap-1 rounded-md px-2 py-1 text-[12px] font-medium text-muted-foreground hover:bg-accent/50 hover:text-foreground", children: [_jsx("span", { className: "min-w-0 truncate", children: compactComposerModelName(model, t) }), effortOptions.length > 0 && (_jsxs("span", { className: "agent-composer-model-effort min-w-0 shrink truncate text-muted-foreground/70", children: ["\u00B7 ", compactComposerReasoningEffortLabel(selectedEffort, t)] })), _jsx(IconChevronDown, { className: "h-3 w-3 shrink-0 opacity-60" })] }) }), _jsxs(PopoverContent, { side: "top", align: "end", sideOffset: 6, collisionPadding: 8, "data-agent-native-composer-popover": "true", className: "z-[260] box-border w-72 overflow-y-auto rounded-lg border-border p-0 py-1 shadow-lg", style: MODEL_SELECTOR_POPOVER_STYLE, children: [showBuilderCta && (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: () => {
|
|
674
820
|
if (onConnectProvider) {
|
|
675
821
|
onConnectProvider();
|
|
676
822
|
}
|
|
@@ -689,14 +835,17 @@ function ModelSelector({ model, effort, engines, showAutoModelOption = true, mod
|
|
|
689
835
|
defaultValue: "Add your own keys",
|
|
690
836
|
}) }), _jsx("span", { className: "block text-[11px] text-muted-foreground", children: t("agentPanel.configureProviderKeys", {
|
|
691
837
|
defaultValue: "Choose a cloud, gateway, or local provider",
|
|
692
|
-
}) })] })] }), !onlyConnectPathAvailable && (_jsx("div", { className: "my-1 border-t border-border" }))] })), imageModel && imageModel.options.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex items-center hover:bg-accent/30", children: _jsxs("button", { type: "button", "aria-expanded": imageExpanded, onClick: () => setImageExpanded((prev) => !prev), className: "flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-start", children: [imageExpanded ? (_jsx(IconChevronDown, { className: "h-3 w-3 shrink-0 text-muted-foreground" })) : (_jsx(IconChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground rtl:-scale-x-100" })), _jsx("span", { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0", children: imageModel.label ??
|
|
838
|
+
}) })] })] }), !onlyConnectPathAvailable && (_jsx("div", { className: "my-1 border-t border-border" }))] })), imageModel && imageModel.options.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex items-center hover:bg-accent/30", children: _jsxs("button", { type: "button", "aria-expanded": imageExpanded, onClick: () => setImageExpanded((prev) => !prev), className: "flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-start", children: [imageExpanded ? (_jsx(IconChevronDown, { className: "h-3 w-3 shrink-0 text-muted-foreground" })) : (_jsx(IconChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground rtl:-scale-x-100" })), _jsx("span", { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0", children: imageModel.label ??
|
|
839
|
+
t("agentChat.composer.imageModel", {
|
|
840
|
+
defaultValue: "Image model",
|
|
841
|
+
}) }), !imageExpanded && imageModelLabel && (_jsx("span", { className: "text-[11px] text-muted-foreground/80 truncate", children: imageModelLabel }))] }) }), imageExpanded &&
|
|
693
842
|
imageModel.options.map((option) => (_jsxs("button", { type: "button", onClick: () => {
|
|
694
843
|
imageModel.onChange(option.value);
|
|
695
844
|
setImageExpanded(false);
|
|
696
845
|
}, className: "flex w-full items-center gap-3 ps-7 pe-3 py-1.5 text-start hover:bg-accent/50", children: [_jsx("span", { className: "flex-1 min-w-0 text-[13px] text-foreground truncate", children: option.label }), option.value === imageModel.value && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] }, option.value))), _jsx("div", { className: "my-1 border-t border-border" })] })), showModelListSkeleton && _jsx(ModelSelectorSkeleton, {}), autoModelGroup && !onlyConnectPathAvailable && (_jsxs("button", { type: "button", onClick: () => {
|
|
697
846
|
onChange("auto", autoModelGroup.engine);
|
|
698
847
|
setOpen(false);
|
|
699
|
-
}, className: "flex w-full items-center gap-3 px-3 py-1.5 text-start hover:bg-accent/50", children: [_jsx("span", { className: "flex-1 min-w-0 text-[13px] text-foreground truncate", children: "Auto" }), model === "auto" && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] })), autoModelGroup &&
|
|
848
|
+
}, className: "flex w-full items-center gap-3 px-3 py-1.5 text-start hover:bg-accent/50", children: [_jsx("span", { className: "flex-1 min-w-0 text-[13px] text-foreground truncate", children: t("agentChat.composer.auto", { defaultValue: "Auto" }) }), model === "auto" && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] })), autoModelGroup &&
|
|
700
849
|
providerGroups.length > 0 &&
|
|
701
850
|
!onlyConnectPathAvailable && (_jsx("div", { className: "my-1 border-t border-border" })), !onlyConnectPathAvailable &&
|
|
702
851
|
providerGroups.map((group) => {
|
|
@@ -709,10 +858,12 @@ function ModelSelector({ model, effort, engines, showAutoModelOption = true, mod
|
|
|
709
858
|
const statusLabel = group.statusLabel ??
|
|
710
859
|
(!group.configured
|
|
711
860
|
? canConnectLocalRuntime
|
|
712
|
-
? "
|
|
713
|
-
: "
|
|
861
|
+
? t("agentChat.auth.logIn", { defaultValue: "Sign in" })
|
|
862
|
+
: t("agentChat.composer.needsApiKey", {
|
|
863
|
+
defaultValue: "needs API key",
|
|
864
|
+
})
|
|
714
865
|
: undefined);
|
|
715
|
-
return (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center hover:bg-accent/30", children: [_jsxs("button", { type: "button", "aria-expanded": isExpanded, onClick: () => toggleGroup(groupKey), className: "flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-start", children: [_jsx(ChevronIcon, { className: "h-3 w-3 shrink-0 text-muted-foreground rtl:-scale-x-100" }), _jsx("span", { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0", children: group.label }), !isExpanded && groupKey === selectedGroupKey && (_jsx("span", { className: "text-[11px] text-muted-foreground/80 truncate", children: friendlyModelName(model) }))] }), !group.configured && statusLabel && (_jsx("button", { type: "button", className: "ms-auto max-w-[9rem] shrink-0 text-end text-[10px] text-muted-foreground/60 hover:text-foreground cursor-pointer pe-3 py-1.5", onClick: () => canConnectLocalRuntime
|
|
866
|
+
return (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center hover:bg-accent/30", children: [_jsxs("button", { type: "button", "aria-expanded": isExpanded, onClick: () => toggleGroup(groupKey), className: "flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-start", children: [_jsx(ChevronIcon, { className: "h-3 w-3 shrink-0 text-muted-foreground rtl:-scale-x-100" }), _jsx("span", { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0", children: group.label }), !isExpanded && groupKey === selectedGroupKey && (_jsx("span", { className: "text-[11px] text-muted-foreground/80 truncate", children: friendlyModelName(model, t) }))] }), !group.configured && statusLabel && (_jsx("button", { type: "button", className: "ms-auto max-w-[9rem] shrink-0 text-end text-[10px] text-muted-foreground/60 hover:text-foreground cursor-pointer pe-3 py-1.5", onClick: () => canConnectLocalRuntime
|
|
716
867
|
? connectLocalRuntime(group.engine)
|
|
717
868
|
: openLlmSettings(), children: statusLabel })), group.configured && statusLabel && (_jsx("span", { className: "ms-auto max-w-[9rem] shrink-0 pe-3 text-end text-[10px] text-muted-foreground/70", children: statusLabel }))] }), isExpanded &&
|
|
718
869
|
models.map((m) => (_jsxs("button", { type: "button", onClick: () => {
|
|
@@ -734,16 +885,23 @@ function ModelSelector({ model, effort, engines, showAutoModelOption = true, mod
|
|
|
734
885
|
setOpen(false);
|
|
735
886
|
}, className: `flex w-full items-center gap-3 ps-7 pe-3 py-1.5 text-start ${group.configured
|
|
736
887
|
? "hover:bg-accent/50"
|
|
737
|
-
: "opacity-40 cursor-default"}`, children: [_jsx("span", { className: "flex-1 min-w-0 text-[13px] text-foreground truncate", children: friendlyModelName(m) }), _jsx(ModelCostTier, { model: m }), m === model && group.configured && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] }, m)))] }, groupKey));
|
|
888
|
+
: "opacity-40 cursor-default"}`, children: [_jsx("span", { className: "flex-1 min-w-0 text-[13px] text-foreground truncate", children: friendlyModelName(m, t) }), _jsx(ModelCostTier, { model: m }), m === model && group.configured && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] }, m)))] }, groupKey));
|
|
738
889
|
}), !showModelListSkeleton &&
|
|
739
890
|
!onlyConnectPathAvailable &&
|
|
740
|
-
effortOptions.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "my-1 border-t border-border" }), _jsx("div", { className: "flex items-center hover:bg-accent/30", children: _jsxs("button", { type: "button", "aria-expanded": effortExpanded, onClick: () => setEffortExpanded((prev) => !prev), className: "flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-start", children: [effortExpanded ? (_jsx(IconChevronDown, { className: "h-3 w-3 shrink-0 text-muted-foreground" })) : (_jsx(IconChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground rtl:-scale-x-100" })), _jsx("span", { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0", children:
|
|
891
|
+
effortOptions.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "my-1 border-t border-border" }), _jsx("div", { className: "flex items-center hover:bg-accent/30", children: _jsxs("button", { type: "button", "aria-expanded": effortExpanded, onClick: () => setEffortExpanded((prev) => !prev), className: "flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-start", children: [effortExpanded ? (_jsx(IconChevronDown, { className: "h-3 w-3 shrink-0 text-muted-foreground" })) : (_jsx(IconChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground rtl:-scale-x-100" })), _jsx("span", { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0", children: t("agentChat.composer.reasoning", {
|
|
892
|
+
defaultValue: "Reasoning",
|
|
893
|
+
}) }), !effortExpanded && (_jsx("span", { className: "text-[11px] text-muted-foreground/80 truncate", children: effortLabel(selectedEffort) }))] }) }), effortExpanded &&
|
|
741
894
|
effortOptions.map((option) => (_jsxs("button", { type: "button", onClick: () => onEffortChange?.(option), className: "flex w-full items-center gap-3 ps-7 pe-3 py-1.5 text-start hover:bg-accent/50", children: [_jsx("span", { className: "flex-1 min-w-0 text-[13px] text-foreground truncate", children: effortLabel(option) }), option === selectedEffort && (_jsx(IconCheck, { className: "h-3.5 w-3.5 shrink-0 text-blue-500" }))] }, option)))] }))] })] }));
|
|
742
895
|
}
|
|
743
896
|
function ModelSelectorSkeleton() {
|
|
744
|
-
|
|
897
|
+
const t = useComposerRuntimeAdapters().translate;
|
|
898
|
+
return (_jsxs("div", { className: "space-y-1 px-2 py-2", role: "status", "aria-label": t("agentChat.composer.loadingModels", {
|
|
899
|
+
defaultValue: "Loading models",
|
|
900
|
+
}), children: [_jsx("span", { className: "sr-only", children: t("agentChat.composer.loadingModelsProgress", {
|
|
901
|
+
defaultValue: "Loading models…",
|
|
902
|
+
}) }), ["w-24", "w-32", "w-20", "w-28"].map((width, index) => (_jsxs("div", { className: "flex items-center gap-1.5 px-1 py-1.5", children: [_jsx(Skeleton, { className: "size-3 rounded-sm" }), _jsx(Skeleton, { className: `h-3 ${width}` })] }, index)))] }));
|
|
745
903
|
}
|
|
746
|
-
export function TiptapComposer({ placeholder
|
|
904
|
+
export function TiptapComposer({ placeholder, disabled = false, maxDocumentAttachmentBytes = MAX_DOCUMENT_ATTACHMENT_BYTES, documentAttachmentLimitLabel = "PDFs", focusRef, initialText, initialTextKey, onSubmit, onBeforeSubmit, clearOnSubmit = true, onTextChange, actionButton, willQueue = false, extraActionButton, stopButton, attachButton, modeControl, toolbarSlot, layoutVariant = "default", slashCommands = [], slashSkills = [], includeDefaultSlashCommands = true, includeDefaultSlashSkills = true, onSlashCommand, execMode, onExecModeChange, planModeDisabled = false, planModeDisabledReason, voiceEnabled = DEFAULT_VOICE_DICTATION_ENABLED, selectedModel, selectedEffort, showAutoModelOption = true, availableModels, modelListLoading, onModelChange, onEffortChange, providerConnectStatusEnabled, onConnectProvider, onConnectLocalRuntime, imageModelMenu, draftScope, contextItems = [], onRemoveContextItem, plusMenuMode = "full", extensionTools = false, interceptBuildRequestsForBuilder = false, onAttachmentError, }) {
|
|
747
905
|
const adapters = useComposerRuntimeAdapters();
|
|
748
906
|
const t = adapters.translate;
|
|
749
907
|
const sendButtonTooltip = t(getComposerSendTooltipKey(willQueue), {
|
|
@@ -787,9 +945,9 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
787
945
|
const filteredMentionItems = useMemo(() => filterMentionItemsForSlots(mentionItems, slotReferences), [mentionItems, slotReferences]);
|
|
788
946
|
const { skills, hint, isLoading: skillsLoading, } = useSkills(includeDefaultSlashSkills && popover?.type === "/");
|
|
789
947
|
const allSlashCommands = useMemo(() => mergeSlashCommands([
|
|
790
|
-
...(includeDefaultSlashCommands ?
|
|
948
|
+
...(includeDefaultSlashCommands ? builtInCommands(t) : []),
|
|
791
949
|
...slashCommands,
|
|
792
|
-
]), [includeDefaultSlashCommands, slashCommands]);
|
|
950
|
+
]), [includeDefaultSlashCommands, slashCommands, t]);
|
|
793
951
|
const allSlashSkills = useMemo(() => mergeSlashSkills([
|
|
794
952
|
...(includeDefaultSlashSkills ? skills : []),
|
|
795
953
|
...slashSkills,
|
|
@@ -855,12 +1013,14 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
855
1013
|
}, [composerRuntime]);
|
|
856
1014
|
// Tiptap reads extension config once at init; ref keeps runtime prop
|
|
857
1015
|
// changes visible to Placeholder's function form.
|
|
858
|
-
const
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1016
|
+
const resolvedPlaceholder = composerMode
|
|
1017
|
+
? localizedComposerModeConfig(composerMode, t).placeholder
|
|
1018
|
+
: (placeholder ??
|
|
1019
|
+
t("agentChat.composer.messageAgent", {
|
|
1020
|
+
defaultValue: "Message agent...",
|
|
1021
|
+
}));
|
|
1022
|
+
const placeholderRef = useRef(resolvedPlaceholder);
|
|
1023
|
+
placeholderRef.current = resolvedPlaceholder;
|
|
864
1024
|
const editor = useEditor({
|
|
865
1025
|
extensions: createTiptapComposerExtensions(() => placeholderRef.current),
|
|
866
1026
|
editable: !disabled,
|
|
@@ -943,7 +1103,9 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
943
1103
|
void Promise.all(attachments.map((file) => composerRuntime.addAttachment(file))).catch((error) => {
|
|
944
1104
|
const msg = error instanceof Error
|
|
945
1105
|
? error.message
|
|
946
|
-
: "
|
|
1106
|
+
: t("agentChat.composer.pastedImageError", {
|
|
1107
|
+
defaultValue: "Could not attach the pasted image. Try a different format.",
|
|
1108
|
+
});
|
|
947
1109
|
onAttachmentErrorRef.current?.(msg);
|
|
948
1110
|
});
|
|
949
1111
|
return true;
|
|
@@ -962,7 +1124,9 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
962
1124
|
.catch((error) => {
|
|
963
1125
|
const msg = error instanceof Error
|
|
964
1126
|
? error.message
|
|
965
|
-
: "
|
|
1127
|
+
: t("agentChat.composer.pastedTextError", {
|
|
1128
|
+
defaultValue: "Could not attach the pasted text.",
|
|
1129
|
+
});
|
|
966
1130
|
onAttachmentErrorRef.current?.(msg);
|
|
967
1131
|
});
|
|
968
1132
|
return true;
|
|
@@ -979,7 +1143,9 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
979
1143
|
onError: (error) => {
|
|
980
1144
|
const msg = error instanceof Error
|
|
981
1145
|
? error.message
|
|
982
|
-
: "
|
|
1146
|
+
: t("agentChat.composer.droppedFileError", {
|
|
1147
|
+
defaultValue: "Could not attach the dropped file. Try a different format.",
|
|
1148
|
+
});
|
|
983
1149
|
onAttachmentErrorRef.current?.(msg);
|
|
984
1150
|
},
|
|
985
1151
|
});
|
|
@@ -1144,6 +1310,13 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1144
1310
|
},
|
|
1145
1311
|
},
|
|
1146
1312
|
});
|
|
1313
|
+
// Placeholder decorations are computed by ProseMirror. Dispatching an empty
|
|
1314
|
+
// transaction makes a locale or composer-mode change visible immediately.
|
|
1315
|
+
useEffect(() => {
|
|
1316
|
+
if (!isComposerEditorUsable(editor))
|
|
1317
|
+
return;
|
|
1318
|
+
editor.view.dispatch(editor.state.tr.setSelection(editor.state.selection));
|
|
1319
|
+
}, [editor, resolvedPlaceholder]);
|
|
1147
1320
|
// A tab can stay mounted while becoming the active composer later. Publish
|
|
1148
1321
|
// its existing draft when the host starts observing it so contextual UI is
|
|
1149
1322
|
// correct immediately after a tab switch, not only after the next keystroke.
|
|
@@ -1339,29 +1512,52 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1339
1512
|
const activeContext = trimVoiceContextValue(adapters.agentChat.formatContextItems(contextItems) ||
|
|
1340
1513
|
formatPromptContextItems(contextItems), 3200);
|
|
1341
1514
|
if (activeContext) {
|
|
1342
|
-
snippets.push({
|
|
1515
|
+
snippets.push({
|
|
1516
|
+
label: t("agentChat.composer.activeAppContext", {
|
|
1517
|
+
defaultValue: "Active app context",
|
|
1518
|
+
}),
|
|
1519
|
+
value: activeContext,
|
|
1520
|
+
});
|
|
1343
1521
|
}
|
|
1344
1522
|
const selectedReferences = trimVoiceContextValue(slotReferences.map((ref) => slotReferenceTitle(ref)).join(", "), 1200);
|
|
1345
1523
|
if (selectedReferences) {
|
|
1346
1524
|
snippets.push({
|
|
1347
|
-
label: "
|
|
1525
|
+
label: t("agentChat.composer.selectedReferences", {
|
|
1526
|
+
defaultValue: "Selected references",
|
|
1527
|
+
}),
|
|
1348
1528
|
value: selectedReferences,
|
|
1349
1529
|
});
|
|
1350
1530
|
}
|
|
1351
1531
|
const draft = isComposerEditorUsable(editor)
|
|
1352
1532
|
? trimVoiceContextValue(editor.state.doc.textContent, 1200)
|
|
1353
1533
|
: null;
|
|
1354
|
-
if (draft)
|
|
1355
|
-
snippets.push({
|
|
1534
|
+
if (draft) {
|
|
1535
|
+
snippets.push({
|
|
1536
|
+
label: t("agentChat.composer.currentDraft", {
|
|
1537
|
+
defaultValue: "Current draft",
|
|
1538
|
+
}),
|
|
1539
|
+
value: draft,
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1356
1542
|
if (typeof document !== "undefined") {
|
|
1357
1543
|
const title = trimVoiceContextValue(document.title, 160);
|
|
1358
|
-
if (title)
|
|
1359
|
-
snippets.push({
|
|
1544
|
+
if (title) {
|
|
1545
|
+
snippets.push({
|
|
1546
|
+
label: t("agentChat.composer.pageTitle", {
|
|
1547
|
+
defaultValue: "Page title",
|
|
1548
|
+
}),
|
|
1549
|
+
value: title,
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1360
1552
|
}
|
|
1361
1553
|
if (typeof window !== "undefined") {
|
|
1362
1554
|
const route = trimVoiceContextValue(window.location.pathname, 240);
|
|
1363
|
-
if (route)
|
|
1364
|
-
snippets.push({
|
|
1555
|
+
if (route) {
|
|
1556
|
+
snippets.push({
|
|
1557
|
+
label: t("agentChat.composer.route", { defaultValue: "Route" }),
|
|
1558
|
+
value: route,
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1365
1561
|
}
|
|
1366
1562
|
if (snippets.length === 0)
|
|
1367
1563
|
return undefined;
|
|
@@ -1370,7 +1566,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1370
1566
|
mode: "dictation",
|
|
1371
1567
|
snippets,
|
|
1372
1568
|
};
|
|
1373
|
-
}, [adapters, contextItems, editor, slotReferences]);
|
|
1569
|
+
}, [adapters, contextItems, editor, slotReferences, t]);
|
|
1374
1570
|
const voice = useVoiceDictation({
|
|
1375
1571
|
onTranscript: insertTranscript,
|
|
1376
1572
|
onLiveUpdate: handleLiveUpdate,
|
|
@@ -1575,6 +1771,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1575
1771
|
const oversizedDocumentError = getOversizedDocumentAttachmentError(attachments, {
|
|
1576
1772
|
maxBytes: maxDocumentAttachmentBytes,
|
|
1577
1773
|
label: documentAttachmentLimitLabel,
|
|
1774
|
+
translate: t,
|
|
1578
1775
|
});
|
|
1579
1776
|
if (oversizedDocumentError) {
|
|
1580
1777
|
onAttachmentErrorRef.current?.(oversizedDocumentError);
|
|
@@ -1626,15 +1823,22 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1626
1823
|
return;
|
|
1627
1824
|
// Composer mode: send with context via agent chat bridge
|
|
1628
1825
|
if (composerMode) {
|
|
1629
|
-
const config =
|
|
1826
|
+
const config = localizedComposerModeConfig(composerMode, t);
|
|
1630
1827
|
config.beforeSend?.();
|
|
1631
1828
|
const message = displayableComposerModeMessage({
|
|
1632
1829
|
messagePrefix: config.messagePrefix,
|
|
1633
1830
|
trimmedText: trimmed,
|
|
1634
1831
|
attachmentCount: attachments.length,
|
|
1832
|
+
attachedContextFallback: t("agentChat.composer.useAttachedContext", {
|
|
1833
|
+
defaultValue: "Use the attached context.",
|
|
1834
|
+
}),
|
|
1635
1835
|
});
|
|
1636
1836
|
const modePrompt = trimmed ||
|
|
1637
|
-
(attachments.length > 0
|
|
1837
|
+
(attachments.length > 0
|
|
1838
|
+
? t("agentChat.composer.useAttachedContext", {
|
|
1839
|
+
defaultValue: "Use the attached context.",
|
|
1840
|
+
})
|
|
1841
|
+
: "");
|
|
1638
1842
|
if (attachments.length > 0) {
|
|
1639
1843
|
composerRuntime.setText(`${message}\n\n<context>\n${config.getContext(modePrompt)}\n</context>`);
|
|
1640
1844
|
composerRuntime.send();
|
|
@@ -1711,6 +1915,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1711
1915
|
syncComposerState,
|
|
1712
1916
|
voice,
|
|
1713
1917
|
allSlashCommands,
|
|
1918
|
+
t,
|
|
1714
1919
|
]);
|
|
1715
1920
|
// Helper functions that operate on the editor view directly
|
|
1716
1921
|
// These are called from handleKeyDown which can't use React state
|
|
@@ -1898,13 +2103,19 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1898
2103
|
if (isComposerEditorUsable(editor)) {
|
|
1899
2104
|
editor.commands.focus("end");
|
|
1900
2105
|
}
|
|
1901
|
-
}, "aria-label":
|
|
2106
|
+
}, "aria-label": t("agentChat.composer.removeReference", {
|
|
2107
|
+
defaultValue: "Remove {{name}} reference",
|
|
2108
|
+
name: slotReferenceTitle(ref),
|
|
2109
|
+
}), className: "ms-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconX, { className: "h-3 w-3" }) })] }, ref.slotKey))), contextItems.map((item) => (_jsxs("span", { "data-state": selectedContextItemKey === item.key ? "selected" : undefined, className: `inline-flex max-w-full items-center gap-1.5 rounded-md border px-2 py-1 text-[11px] font-medium text-foreground ${selectedContextItemKey === item.key
|
|
1902
2110
|
? "border-ring bg-accent ring-2 ring-ring/40"
|
|
1903
2111
|
: "border-border bg-muted/50"}`, children: [_jsx(IconClipboardList, { className: "h-3 w-3 shrink-0 text-muted-foreground" }), _jsx("span", { className: "min-w-0 truncate", children: item.title }), _jsx("button", { type: "button", onClick: () => {
|
|
1904
2112
|
selectedContextItemKeyRef.current = null;
|
|
1905
2113
|
setSelectedContextItemKey(null);
|
|
1906
2114
|
onRemoveContextItem?.(item.key);
|
|
1907
|
-
}, "aria-label":
|
|
2115
|
+
}, "aria-label": t("agentChat.composer.removeContext", {
|
|
2116
|
+
defaultValue: "Remove {{name}} context",
|
|
2117
|
+
name: item.title,
|
|
2118
|
+
}), className: "ms-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconX, { className: "h-3 w-3" }) })] }, item.key)))] })), _jsx("div", { "data-agent-composer-variant": layoutVariant, "data-agent-composer-slot": "editor-wrap", className: `agent-composer-editor-wrap ${composerMode || hasContextRows ? "px-2 pt-1 pb-1" : "px-2 pt-2 pb-1"}`, children: _jsx(EditorContent, { editor: editor, "data-agent-composer-variant": layoutVariant, "data-agent-composer-slot": "editor", className: "agent-composer-editor aui-composer flex-1 min-w-0 [&_.ProseMirror]:outline-none [&_.ProseMirror_p]:m-0 px-0.5" }) }), voiceEnabled && _jsx(VoiceRecordingOverlay, { voice: voice }), _jsxs("div", { "data-agent-composer-variant": layoutVariant, "data-agent-composer-slot": "toolbar", className: "agent-composer-toolbar flex items-center gap-1 px-2 py-1.5", children: [attachButton ??
|
|
1908
2119
|
(plusMenuMode === "hidden" ? null : (_jsx(ComposerPlusMenu, { onSelectMode: handleSelectMode, mode: plusMenuMode, extensionTools: extensionTools, onAttachmentError: onAttachmentError }))), toolbarSlot ?? modeControl, _jsx("div", { "data-agent-composer-slot": "toolbar-spacer", className: "flex-1" }), selectedModel && availableModels && onModelChange && (_jsx(ModelSelector, { model: selectedModel, effort: selectedEffort, engines: availableModels, showAutoModelOption: showAutoModelOption, modelListLoading: modelListLoading, onChange: onModelChange, onEffortChange: onEffortChange, providerConnectStatusEnabled: providerConnectStatusEnabled, onConnectProvider: onConnectProvider, onConnectLocalRuntime: onConnectLocalRuntime, imageModel: imageModelMenu })), execMode && onExecModeChange && (_jsx(ModeSelector, { mode: execMode, onChange: onExecModeChange, planModeDisabled: planModeDisabled, planModeDisabledReason: planModeDisabledReason })), actionButton ?? (_jsxs(_Fragment, { children: [extraActionButton, voiceEnabled && (_jsx(VoiceButton, { voice: voice, isMac: isMac, disabled: disabled })), primaryAction === "stop" ? (stopButton) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => void submitComposer("immediate"), disabled: !canSend, "data-agent-composer-slot": "send-button", className: "agent-composer-send-button shrink-0 flex h-7 w-7 items-center justify-center rounded-md bg-primary text-primary-foreground hover:opacity-90 transition-[opacity,transform] duration-150 active:scale-[0.97] disabled:opacity-30 disabled:cursor-not-allowed", children: _jsx(IconArrowUp, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: sendButtonTooltip })] }))] }))] }), _jsx(MentionPopover, { ref: popoverRef, type: popover?.type ?? "@", position: popover?.position ?? null, mentionItems: filteredMentionItems, skills: filteredSkills, commands: filteredCommands, hint: hint, isLoading: popover?.type === "@" ? mentionsLoading : skillsLoading, query: popover?.query ?? "", onSelectMention: handleSelectMention, onSelectSkill: handleSelectSkill, onSelectCommand: handleSelectCommand, onClose: closePopover })] }));
|
|
1909
2120
|
}
|
|
1910
2121
|
//# sourceMappingURL=TiptapComposer.js.map
|