@agent-native/toolkit 0.14.3 → 0.15.1
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/agent-native.eject.json +19 -1
- package/dist/chat-history.css +3 -1
- 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/dist/design-system/default-adapter.d.ts.map +1 -1
- package/dist/design-system/default-adapter.js +4 -1
- package/dist/design-system/default-adapter.js.map +1 -1
- package/dist/design-system/default-adapter.spec.js +12 -0
- package/dist/design-system/default-adapter.spec.js.map +1 -1
- package/dist/design-system/types.d.ts +2 -0
- package/dist/design-system/types.d.ts.map +1 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +5 -2
- package/dist/provider.js.map +1 -1
- package/dist/sharing/SharePrimitives.d.ts +31 -0
- package/dist/sharing/SharePrimitives.d.ts.map +1 -0
- package/dist/sharing/SharePrimitives.js +45 -0
- package/dist/sharing/SharePrimitives.js.map +1 -0
- package/dist/sharing/index.d.ts +1 -0
- package/dist/sharing/index.d.ts.map +1 -1
- package/dist/sharing/index.js +1 -0
- package/dist/sharing/index.js.map +1 -1
- package/package.json +2 -2
- package/src/chat-history.css +3 -1
- 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
- package/src/design-system/default-adapter.spec.tsx +15 -0
- package/src/design-system/default-adapter.tsx +5 -1
- package/src/design-system/types.ts +2 -0
- package/src/provider.tsx +9 -1
- package/src/sharing/SharePrimitives.tsx +185 -0
- package/src/sharing/index.ts +8 -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,22 +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();
|
|
503
608
|
return `GPT-5.6 ${variant}`;
|
|
504
609
|
}
|
|
505
|
-
return friendlyModelName(model);
|
|
610
|
+
return friendlyModelName(model, t);
|
|
506
611
|
}
|
|
507
|
-
export function compactComposerReasoningEffortLabel(effort) {
|
|
508
|
-
if (effort === "medium" || effort === "auto")
|
|
509
|
-
return "
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
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
|
+
}
|
|
515
651
|
}
|
|
516
652
|
/**
|
|
517
653
|
* Deduplicate models to only the latest version per family.
|
|
@@ -562,16 +698,21 @@ const MODEL_COST_TIERS = [
|
|
|
562
698
|
["flash", 1],
|
|
563
699
|
["pro", 3],
|
|
564
700
|
];
|
|
565
|
-
const COST_TIER_LABELS = { 1: "Lower", 2: "Medium", 3: "Higher" };
|
|
566
701
|
export function composerModelCostTier(model) {
|
|
567
702
|
const normalized = model.toLowerCase();
|
|
568
703
|
return MODEL_COST_TIERS.find(([token]) => normalized.includes(token))?.[1];
|
|
569
704
|
}
|
|
570
705
|
function ModelCostTier({ model }) {
|
|
706
|
+
const t = useComposerRuntimeAdapters().translate;
|
|
571
707
|
const tier = composerModelCostTier(model);
|
|
572
708
|
if (!tier)
|
|
573
709
|
return null;
|
|
574
|
-
|
|
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 })] }));
|
|
575
716
|
}
|
|
576
717
|
export function getComposerReasoningEffortOptions(model) {
|
|
577
718
|
return model === "auto"
|
|
@@ -597,7 +738,7 @@ function ModelSelector({ model, effort, engines, showAutoModelOption = true, mod
|
|
|
597
738
|
getComposerReasoningEffortOptions(model);
|
|
598
739
|
const selectedEffort = reasoning?.resolve?.(model, effort) ??
|
|
599
740
|
resolveReasoningEffortSelection(model, effort ?? defaultEffort);
|
|
600
|
-
const effortLabel = reasoning?.label ?? reasoningEffortLabel;
|
|
741
|
+
const effortLabel = useCallback((value) => localizedReasoningEffortLabel(t, value, (reasoning?.label ?? reasoningEffortLabel)(value)), [reasoning?.label, t]);
|
|
601
742
|
// Collapse non-selected families by default. The family containing the
|
|
602
743
|
// currently-selected model stays expanded so the user sees their pick at
|
|
603
744
|
// a glance; clicking another family's header expands it inline.
|
|
@@ -669,9 +810,13 @@ function ModelSelector({ model, effort, engines, showAutoModelOption = true, mod
|
|
|
669
810
|
onConnectLocalRuntime?.(engine);
|
|
670
811
|
setOpen(false);
|
|
671
812
|
}, [onConnectLocalRuntime]);
|
|
672
|
-
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":
|
|
673
|
-
|
|
674
|
-
|
|
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: () => {
|
|
675
820
|
if (onConnectProvider) {
|
|
676
821
|
onConnectProvider();
|
|
677
822
|
}
|
|
@@ -690,14 +835,17 @@ function ModelSelector({ model, effort, engines, showAutoModelOption = true, mod
|
|
|
690
835
|
defaultValue: "Add your own keys",
|
|
691
836
|
}) }), _jsx("span", { className: "block text-[11px] text-muted-foreground", children: t("agentPanel.configureProviderKeys", {
|
|
692
837
|
defaultValue: "Choose a cloud, gateway, or local provider",
|
|
693
|
-
}) })] })] }), !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 &&
|
|
694
842
|
imageModel.options.map((option) => (_jsxs("button", { type: "button", onClick: () => {
|
|
695
843
|
imageModel.onChange(option.value);
|
|
696
844
|
setImageExpanded(false);
|
|
697
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: () => {
|
|
698
846
|
onChange("auto", autoModelGroup.engine);
|
|
699
847
|
setOpen(false);
|
|
700
|
-
}, 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 &&
|
|
701
849
|
providerGroups.length > 0 &&
|
|
702
850
|
!onlyConnectPathAvailable && (_jsx("div", { className: "my-1 border-t border-border" })), !onlyConnectPathAvailable &&
|
|
703
851
|
providerGroups.map((group) => {
|
|
@@ -710,10 +858,12 @@ function ModelSelector({ model, effort, engines, showAutoModelOption = true, mod
|
|
|
710
858
|
const statusLabel = group.statusLabel ??
|
|
711
859
|
(!group.configured
|
|
712
860
|
? canConnectLocalRuntime
|
|
713
|
-
? "
|
|
714
|
-
: "
|
|
861
|
+
? t("agentChat.auth.logIn", { defaultValue: "Sign in" })
|
|
862
|
+
: t("agentChat.composer.needsApiKey", {
|
|
863
|
+
defaultValue: "needs API key",
|
|
864
|
+
})
|
|
715
865
|
: undefined);
|
|
716
|
-
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
|
|
717
867
|
? connectLocalRuntime(group.engine)
|
|
718
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 &&
|
|
719
869
|
models.map((m) => (_jsxs("button", { type: "button", onClick: () => {
|
|
@@ -735,16 +885,23 @@ function ModelSelector({ model, effort, engines, showAutoModelOption = true, mod
|
|
|
735
885
|
setOpen(false);
|
|
736
886
|
}, className: `flex w-full items-center gap-3 ps-7 pe-3 py-1.5 text-start ${group.configured
|
|
737
887
|
? "hover:bg-accent/50"
|
|
738
|
-
: "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));
|
|
739
889
|
}), !showModelListSkeleton &&
|
|
740
890
|
!onlyConnectPathAvailable &&
|
|
741
|
-
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 &&
|
|
742
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)))] }))] })] }));
|
|
743
895
|
}
|
|
744
896
|
function ModelSelectorSkeleton() {
|
|
745
|
-
|
|
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)))] }));
|
|
746
903
|
}
|
|
747
|
-
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, }) {
|
|
748
905
|
const adapters = useComposerRuntimeAdapters();
|
|
749
906
|
const t = adapters.translate;
|
|
750
907
|
const sendButtonTooltip = t(getComposerSendTooltipKey(willQueue), {
|
|
@@ -788,9 +945,9 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
788
945
|
const filteredMentionItems = useMemo(() => filterMentionItemsForSlots(mentionItems, slotReferences), [mentionItems, slotReferences]);
|
|
789
946
|
const { skills, hint, isLoading: skillsLoading, } = useSkills(includeDefaultSlashSkills && popover?.type === "/");
|
|
790
947
|
const allSlashCommands = useMemo(() => mergeSlashCommands([
|
|
791
|
-
...(includeDefaultSlashCommands ?
|
|
948
|
+
...(includeDefaultSlashCommands ? builtInCommands(t) : []),
|
|
792
949
|
...slashCommands,
|
|
793
|
-
]), [includeDefaultSlashCommands, slashCommands]);
|
|
950
|
+
]), [includeDefaultSlashCommands, slashCommands, t]);
|
|
794
951
|
const allSlashSkills = useMemo(() => mergeSlashSkills([
|
|
795
952
|
...(includeDefaultSlashSkills ? skills : []),
|
|
796
953
|
...slashSkills,
|
|
@@ -856,12 +1013,14 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
856
1013
|
}, [composerRuntime]);
|
|
857
1014
|
// Tiptap reads extension config once at init; ref keeps runtime prop
|
|
858
1015
|
// changes visible to Placeholder's function form.
|
|
859
|
-
const
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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;
|
|
865
1024
|
const editor = useEditor({
|
|
866
1025
|
extensions: createTiptapComposerExtensions(() => placeholderRef.current),
|
|
867
1026
|
editable: !disabled,
|
|
@@ -944,7 +1103,9 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
944
1103
|
void Promise.all(attachments.map((file) => composerRuntime.addAttachment(file))).catch((error) => {
|
|
945
1104
|
const msg = error instanceof Error
|
|
946
1105
|
? error.message
|
|
947
|
-
: "
|
|
1106
|
+
: t("agentChat.composer.pastedImageError", {
|
|
1107
|
+
defaultValue: "Could not attach the pasted image. Try a different format.",
|
|
1108
|
+
});
|
|
948
1109
|
onAttachmentErrorRef.current?.(msg);
|
|
949
1110
|
});
|
|
950
1111
|
return true;
|
|
@@ -963,7 +1124,9 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
963
1124
|
.catch((error) => {
|
|
964
1125
|
const msg = error instanceof Error
|
|
965
1126
|
? error.message
|
|
966
|
-
: "
|
|
1127
|
+
: t("agentChat.composer.pastedTextError", {
|
|
1128
|
+
defaultValue: "Could not attach the pasted text.",
|
|
1129
|
+
});
|
|
967
1130
|
onAttachmentErrorRef.current?.(msg);
|
|
968
1131
|
});
|
|
969
1132
|
return true;
|
|
@@ -980,7 +1143,9 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
980
1143
|
onError: (error) => {
|
|
981
1144
|
const msg = error instanceof Error
|
|
982
1145
|
? error.message
|
|
983
|
-
: "
|
|
1146
|
+
: t("agentChat.composer.droppedFileError", {
|
|
1147
|
+
defaultValue: "Could not attach the dropped file. Try a different format.",
|
|
1148
|
+
});
|
|
984
1149
|
onAttachmentErrorRef.current?.(msg);
|
|
985
1150
|
},
|
|
986
1151
|
});
|
|
@@ -1145,6 +1310,13 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1145
1310
|
},
|
|
1146
1311
|
},
|
|
1147
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]);
|
|
1148
1320
|
// A tab can stay mounted while becoming the active composer later. Publish
|
|
1149
1321
|
// its existing draft when the host starts observing it so contextual UI is
|
|
1150
1322
|
// correct immediately after a tab switch, not only after the next keystroke.
|
|
@@ -1340,29 +1512,52 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1340
1512
|
const activeContext = trimVoiceContextValue(adapters.agentChat.formatContextItems(contextItems) ||
|
|
1341
1513
|
formatPromptContextItems(contextItems), 3200);
|
|
1342
1514
|
if (activeContext) {
|
|
1343
|
-
snippets.push({
|
|
1515
|
+
snippets.push({
|
|
1516
|
+
label: t("agentChat.composer.activeAppContext", {
|
|
1517
|
+
defaultValue: "Active app context",
|
|
1518
|
+
}),
|
|
1519
|
+
value: activeContext,
|
|
1520
|
+
});
|
|
1344
1521
|
}
|
|
1345
1522
|
const selectedReferences = trimVoiceContextValue(slotReferences.map((ref) => slotReferenceTitle(ref)).join(", "), 1200);
|
|
1346
1523
|
if (selectedReferences) {
|
|
1347
1524
|
snippets.push({
|
|
1348
|
-
label: "
|
|
1525
|
+
label: t("agentChat.composer.selectedReferences", {
|
|
1526
|
+
defaultValue: "Selected references",
|
|
1527
|
+
}),
|
|
1349
1528
|
value: selectedReferences,
|
|
1350
1529
|
});
|
|
1351
1530
|
}
|
|
1352
1531
|
const draft = isComposerEditorUsable(editor)
|
|
1353
1532
|
? trimVoiceContextValue(editor.state.doc.textContent, 1200)
|
|
1354
1533
|
: null;
|
|
1355
|
-
if (draft)
|
|
1356
|
-
snippets.push({
|
|
1534
|
+
if (draft) {
|
|
1535
|
+
snippets.push({
|
|
1536
|
+
label: t("agentChat.composer.currentDraft", {
|
|
1537
|
+
defaultValue: "Current draft",
|
|
1538
|
+
}),
|
|
1539
|
+
value: draft,
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1357
1542
|
if (typeof document !== "undefined") {
|
|
1358
1543
|
const title = trimVoiceContextValue(document.title, 160);
|
|
1359
|
-
if (title)
|
|
1360
|
-
snippets.push({
|
|
1544
|
+
if (title) {
|
|
1545
|
+
snippets.push({
|
|
1546
|
+
label: t("agentChat.composer.pageTitle", {
|
|
1547
|
+
defaultValue: "Page title",
|
|
1548
|
+
}),
|
|
1549
|
+
value: title,
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1361
1552
|
}
|
|
1362
1553
|
if (typeof window !== "undefined") {
|
|
1363
1554
|
const route = trimVoiceContextValue(window.location.pathname, 240);
|
|
1364
|
-
if (route)
|
|
1365
|
-
snippets.push({
|
|
1555
|
+
if (route) {
|
|
1556
|
+
snippets.push({
|
|
1557
|
+
label: t("agentChat.composer.route", { defaultValue: "Route" }),
|
|
1558
|
+
value: route,
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1366
1561
|
}
|
|
1367
1562
|
if (snippets.length === 0)
|
|
1368
1563
|
return undefined;
|
|
@@ -1371,7 +1566,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1371
1566
|
mode: "dictation",
|
|
1372
1567
|
snippets,
|
|
1373
1568
|
};
|
|
1374
|
-
}, [adapters, contextItems, editor, slotReferences]);
|
|
1569
|
+
}, [adapters, contextItems, editor, slotReferences, t]);
|
|
1375
1570
|
const voice = useVoiceDictation({
|
|
1376
1571
|
onTranscript: insertTranscript,
|
|
1377
1572
|
onLiveUpdate: handleLiveUpdate,
|
|
@@ -1576,6 +1771,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1576
1771
|
const oversizedDocumentError = getOversizedDocumentAttachmentError(attachments, {
|
|
1577
1772
|
maxBytes: maxDocumentAttachmentBytes,
|
|
1578
1773
|
label: documentAttachmentLimitLabel,
|
|
1774
|
+
translate: t,
|
|
1579
1775
|
});
|
|
1580
1776
|
if (oversizedDocumentError) {
|
|
1581
1777
|
onAttachmentErrorRef.current?.(oversizedDocumentError);
|
|
@@ -1627,15 +1823,22 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1627
1823
|
return;
|
|
1628
1824
|
// Composer mode: send with context via agent chat bridge
|
|
1629
1825
|
if (composerMode) {
|
|
1630
|
-
const config =
|
|
1826
|
+
const config = localizedComposerModeConfig(composerMode, t);
|
|
1631
1827
|
config.beforeSend?.();
|
|
1632
1828
|
const message = displayableComposerModeMessage({
|
|
1633
1829
|
messagePrefix: config.messagePrefix,
|
|
1634
1830
|
trimmedText: trimmed,
|
|
1635
1831
|
attachmentCount: attachments.length,
|
|
1832
|
+
attachedContextFallback: t("agentChat.composer.useAttachedContext", {
|
|
1833
|
+
defaultValue: "Use the attached context.",
|
|
1834
|
+
}),
|
|
1636
1835
|
});
|
|
1637
1836
|
const modePrompt = trimmed ||
|
|
1638
|
-
(attachments.length > 0
|
|
1837
|
+
(attachments.length > 0
|
|
1838
|
+
? t("agentChat.composer.useAttachedContext", {
|
|
1839
|
+
defaultValue: "Use the attached context.",
|
|
1840
|
+
})
|
|
1841
|
+
: "");
|
|
1639
1842
|
if (attachments.length > 0) {
|
|
1640
1843
|
composerRuntime.setText(`${message}\n\n<context>\n${config.getContext(modePrompt)}\n</context>`);
|
|
1641
1844
|
composerRuntime.send();
|
|
@@ -1712,6 +1915,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1712
1915
|
syncComposerState,
|
|
1713
1916
|
voice,
|
|
1714
1917
|
allSlashCommands,
|
|
1918
|
+
t,
|
|
1715
1919
|
]);
|
|
1716
1920
|
// Helper functions that operate on the editor view directly
|
|
1717
1921
|
// These are called from handleKeyDown which can't use React state
|
|
@@ -1899,13 +2103,19 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1899
2103
|
if (isComposerEditorUsable(editor)) {
|
|
1900
2104
|
editor.commands.focus("end");
|
|
1901
2105
|
}
|
|
1902
|
-
}, "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
|
|
1903
2110
|
? "border-ring bg-accent ring-2 ring-ring/40"
|
|
1904
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: () => {
|
|
1905
2112
|
selectedContextItemKeyRef.current = null;
|
|
1906
2113
|
setSelectedContextItemKey(null);
|
|
1907
2114
|
onRemoveContextItem?.(item.key);
|
|
1908
|
-
}, "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 ??
|
|
1909
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 })] }));
|
|
1910
2120
|
}
|
|
1911
2121
|
//# sourceMappingURL=TiptapComposer.js.map
|