@agent-native/core 0.78.0 → 0.78.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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +9 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/types.ts +22 -0
- package/corpus/core/src/client/AgentPanel.tsx +8 -0
- package/corpus/core/src/client/AssistantChat.tsx +40 -0
- package/corpus/core/src/client/agent-chat.ts +173 -0
- package/corpus/core/src/client/composer/TiptapComposer.tsx +316 -60
- package/corpus/core/src/client/composer/extensions/MentionReference.tsx +3 -0
- package/corpus/core/src/client/composer/types.ts +22 -0
- package/corpus/core/src/client/index.ts +5 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +10 -0
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +10 -2
- package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +14 -7
- package/corpus/templates/assets/.agents/skills/library-management/SKILL.md +12 -0
- package/corpus/templates/assets/AGENTS.md +18 -3
- package/corpus/templates/assets/actions/_image-model-default.ts +24 -0
- package/corpus/templates/assets/actions/dismiss-variant-slots.ts +15 -22
- package/corpus/templates/assets/actions/generate-asset.ts +30 -23
- package/corpus/templates/assets/actions/generate-image-batch.ts +76 -29
- package/corpus/templates/assets/actions/generate-image.ts +46 -30
- package/corpus/templates/assets/actions/generate-video.ts +18 -3
- package/corpus/templates/assets/actions/list-assets.ts +39 -8
- package/corpus/templates/assets/actions/list-libraries.ts +24 -2
- package/corpus/templates/assets/actions/navigate.ts +1 -1
- package/corpus/templates/assets/actions/open-asset-picker.ts +38 -1
- package/corpus/templates/assets/actions/refresh-generation-run.ts +10 -0
- package/corpus/templates/assets/actions/save-generated-image.ts +21 -19
- package/corpus/templates/assets/actions/variant-slots.ts +131 -28
- package/corpus/templates/assets/actions/view-screen.ts +9 -0
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +425 -0
- package/corpus/templates/assets/app/components/layout/Header.tsx +3 -1
- package/corpus/templates/assets/app/components/layout/Layout.tsx +5 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +4 -6
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +47 -21
- package/corpus/templates/assets/app/i18n-data.ts +1815 -0
- package/corpus/templates/assets/app/lib/libraries.ts +6 -0
- package/corpus/templates/assets/app/lib/picker-chat-handoff.ts +71 -0
- package/corpus/templates/assets/app/routes/_index.tsx +4 -0
- package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -2
- package/corpus/templates/assets/app/routes/audit.tsx +1 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +1557 -2164
- package/corpus/templates/assets/app/routes/brand-kits._index.tsx +7 -191
- package/corpus/templates/assets/app/routes/brand-kits.tsx +1 -5
- package/corpus/templates/assets/app/routes/libraries.tsx +4 -4
- package/corpus/templates/assets/app/routes/library.$id.tsx +9 -7
- package/corpus/templates/assets/app/routes/library.tsx +1454 -175
- package/corpus/templates/assets/server/db/index.ts +1 -1
- package/corpus/templates/assets/server/lib/generation.ts +86 -15
- package/corpus/templates/assets/server/plugins/agent-chat.ts +196 -0
- package/corpus/templates/assets/server/plugins/db.ts +5 -0
- package/corpus/templates/assets/shared/api.ts +6 -3
- package/dist/agent/types.d.ts +21 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +2 -2
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +6 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +15 -3
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat.d.ts +32 -0
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +113 -0
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +2 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +228 -56
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/extensions/MentionReference.d.ts.map +1 -1
- package/dist/client/composer/extensions/MentionReference.js +3 -0
- package/dist/client/composer/extensions/MentionReference.js.map +1 -1
- package/dist/client/composer/types.d.ts +21 -0
- package/dist/client/composer/types.d.ts.map +1 -1
- package/dist/client/composer/types.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +5 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +2 -2
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
|
@@ -6,10 +6,12 @@ import { useEditor, EditorContent } from "@tiptap/react";
|
|
|
6
6
|
import StarterKit from "@tiptap/starter-kit";
|
|
7
7
|
import { useState, useRef, useEffect, useCallback, useImperativeHandle, useMemo, } from "react";
|
|
8
8
|
import { getReasoningEffortOptionsForModel, reasoningEffortLabel, } from "../../shared/reasoning-effort.js";
|
|
9
|
-
import { sendToAgentChat } from "../agent-chat.js";
|
|
9
|
+
import { normalizeAgentComposerReference, sendToAgentChat, AGENT_CHAT_INSERT_REFERENCE_EVENT, AGENT_CHAT_INSERT_REFERENCE_MESSAGE_TYPE, } from "../agent-chat.js";
|
|
10
10
|
import { tryDelegateBuildRequestToBuilder } from "../builder-frame.js";
|
|
11
|
+
import { isTrustedBuilderMessage } from "../builder-frame.js";
|
|
11
12
|
import { Popover, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
|
|
12
13
|
import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
|
|
14
|
+
import { isTrustedFrameMessage } from "../frame.js";
|
|
13
15
|
import { useBuilderConnectFlow } from "../settings/useBuilderStatus.js";
|
|
14
16
|
import { ComposerPlusMenu } from "./ComposerPlusMenu.js";
|
|
15
17
|
import { getComposerDraftKey } from "./draft-key.js";
|
|
@@ -28,6 +30,93 @@ export function canSubmitComposerContent(options) {
|
|
|
28
30
|
(options.hasEditorContent || options.attachmentCount > 0));
|
|
29
31
|
}
|
|
30
32
|
const MAX_DOCUMENT_ATTACHMENT_BYTES = 4 * 1024 * 1024;
|
|
33
|
+
function composerReferenceFromMentionItem(item) {
|
|
34
|
+
return {
|
|
35
|
+
label: item.label,
|
|
36
|
+
icon: item.icon || "file",
|
|
37
|
+
source: item.source,
|
|
38
|
+
refType: item.refType,
|
|
39
|
+
refId: item.refId || null,
|
|
40
|
+
refPath: item.refPath || null,
|
|
41
|
+
slotKey: item.slotKey,
|
|
42
|
+
slotLabel: item.slotLabel,
|
|
43
|
+
metadata: item.metadata,
|
|
44
|
+
clearsSlots: item.clearsSlots,
|
|
45
|
+
relatedReferences: item.relatedReferences,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function mentionReferenceAttrs(ref) {
|
|
49
|
+
return {
|
|
50
|
+
label: ref.label,
|
|
51
|
+
icon: ref.icon || "file",
|
|
52
|
+
source: ref.source,
|
|
53
|
+
refType: ref.refType,
|
|
54
|
+
refId: ref.refId || null,
|
|
55
|
+
refPath: ref.refPath || null,
|
|
56
|
+
slotKey: ref.slotKey || null,
|
|
57
|
+
slotLabel: ref.slotLabel || null,
|
|
58
|
+
metadata: ref.metadata || null,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function referenceFromComposerReference(ref) {
|
|
62
|
+
return {
|
|
63
|
+
type: ref.refType === "file"
|
|
64
|
+
? "file"
|
|
65
|
+
: ref.refType === "agent"
|
|
66
|
+
? "agent"
|
|
67
|
+
: ref.refType === "custom-agent"
|
|
68
|
+
? "custom-agent"
|
|
69
|
+
: "mention",
|
|
70
|
+
path: ref.refPath || "",
|
|
71
|
+
name: ref.label,
|
|
72
|
+
source: ref.source || "",
|
|
73
|
+
refType: ref.refType,
|
|
74
|
+
refId: ref.refId || undefined,
|
|
75
|
+
slotKey: ref.slotKey,
|
|
76
|
+
slotLabel: ref.slotLabel,
|
|
77
|
+
metadata: ref.metadata,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function applySlotReferenceChanges(current, references) {
|
|
81
|
+
let next = current;
|
|
82
|
+
const applyOne = (ref) => {
|
|
83
|
+
for (const related of ref.relatedReferences ?? []) {
|
|
84
|
+
applyOne(related);
|
|
85
|
+
}
|
|
86
|
+
if (!ref.slotKey)
|
|
87
|
+
return;
|
|
88
|
+
const cleared = new Set([ref.slotKey, ...(ref.clearsSlots ?? [])]);
|
|
89
|
+
next = next.filter((existing) => !cleared.has(existing.slotKey ?? ""));
|
|
90
|
+
next = [...next, ref];
|
|
91
|
+
};
|
|
92
|
+
for (const ref of references) {
|
|
93
|
+
applyOne(ref);
|
|
94
|
+
}
|
|
95
|
+
return next;
|
|
96
|
+
}
|
|
97
|
+
function removeSlotReference(current, ref) {
|
|
98
|
+
const removed = new Set([ref.slotKey, ...(ref.clearsSlots ?? [])]);
|
|
99
|
+
return current.filter((existing) => !removed.has(existing.slotKey ?? ""));
|
|
100
|
+
}
|
|
101
|
+
function slotReferenceTitle(ref) {
|
|
102
|
+
return ref.slotLabel ? `${ref.slotLabel}: ${ref.label}` : ref.label;
|
|
103
|
+
}
|
|
104
|
+
function metadataString(metadata, key) {
|
|
105
|
+
const value = metadata?.[key];
|
|
106
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
107
|
+
}
|
|
108
|
+
function filterMentionItemsForSlots(items, slotReferences) {
|
|
109
|
+
return items.filter((item) => {
|
|
110
|
+
const requiredSlotKey = metadataString(item.metadata, "requiredSlotKey");
|
|
111
|
+
const requiredRefId = metadataString(item.metadata, "requiredRefId");
|
|
112
|
+
if (!requiredSlotKey || !requiredRefId)
|
|
113
|
+
return true;
|
|
114
|
+
const selected = slotReferences.find((ref) => ref.slotKey === requiredSlotKey);
|
|
115
|
+
if (!selected?.refId)
|
|
116
|
+
return true;
|
|
117
|
+
return selected.refId === requiredRefId;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
31
120
|
function isDocumentAttachment(value) {
|
|
32
121
|
if (value.type === "document")
|
|
33
122
|
return true;
|
|
@@ -84,6 +173,21 @@ function uniquifyComposerImageFile(file) {
|
|
|
84
173
|
const uniqueName = `${Date.now()}-${Math.random().toString(36).slice(2)}-${file.name}`;
|
|
85
174
|
return new File([file], uniqueName, { type: file.type });
|
|
86
175
|
}
|
|
176
|
+
function composerDocumentHasContent(doc) {
|
|
177
|
+
if (doc.textContent.trim().length > 0)
|
|
178
|
+
return true;
|
|
179
|
+
let hasContent = false;
|
|
180
|
+
doc.descendants((node) => {
|
|
181
|
+
if (node.type.name === "mentionReference" ||
|
|
182
|
+
node.type.name === "fileReference" ||
|
|
183
|
+
node.type.name === "skillReference") {
|
|
184
|
+
hasContent = true;
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
return true;
|
|
188
|
+
});
|
|
189
|
+
return hasContent;
|
|
190
|
+
}
|
|
87
191
|
export function handleComposerFileDrop(options) {
|
|
88
192
|
const droppedFiles = Array.from(options.event.dataTransfer?.files ?? []);
|
|
89
193
|
if (droppedFiles.length === 0)
|
|
@@ -479,14 +583,15 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
479
583
|
const popoverRef = useRef(null);
|
|
480
584
|
const composerRuntime = useComposerRuntime();
|
|
481
585
|
const [editorHasText, setEditorHasText] = useState(false);
|
|
586
|
+
const [slotReferences, setSlotReferences] = useState([]);
|
|
482
587
|
const composerText = useComposer((state) => state.text);
|
|
483
588
|
const composerAttachments = useComposer((state) => state.attachments);
|
|
484
589
|
const canSend = canSubmitComposerContent({
|
|
485
|
-
hasEditorContent: editorHasText,
|
|
590
|
+
hasEditorContent: editorHasText || slotReferences.length > 0,
|
|
486
591
|
attachmentCount: composerAttachments.length,
|
|
487
592
|
disabled,
|
|
488
593
|
});
|
|
489
|
-
const
|
|
594
|
+
const hasContextRows = contextItems.length > 0 || slotReferences.length > 0;
|
|
490
595
|
const [composerMode, setComposerMode] = useState(null);
|
|
491
596
|
const composerModeRef = useRef(null);
|
|
492
597
|
const isMac = typeof navigator !== "undefined" &&
|
|
@@ -502,6 +607,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
502
607
|
const planModeDisabledRef = useRef(planModeDisabled);
|
|
503
608
|
planModeDisabledRef.current = planModeDisabled;
|
|
504
609
|
const { items: mentionItems, isLoading: mentionsLoading } = useMentionSearch(popover?.type === "@" ? popover.query : "", popover?.type === "@");
|
|
610
|
+
const filteredMentionItems = useMemo(() => filterMentionItemsForSlots(mentionItems, slotReferences), [mentionItems, slotReferences]);
|
|
505
611
|
const { skills, hint, isLoading: skillsLoading, } = useSkills(includeDefaultSlashSkills && popover?.type === "/");
|
|
506
612
|
const allSlashCommands = useMemo(() => mergeSlashCommands([
|
|
507
613
|
...(includeDefaultSlashCommands ? BUILT_IN_COMMANDS : []),
|
|
@@ -530,8 +636,8 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
530
636
|
s.description?.toLowerCase().includes(q));
|
|
531
637
|
}, [allSlashSkills, popover]);
|
|
532
638
|
// Keep refs in sync with state
|
|
533
|
-
const mentionItemsRef = useRef(
|
|
534
|
-
mentionItemsRef.current =
|
|
639
|
+
const mentionItemsRef = useRef(filteredMentionItems);
|
|
640
|
+
mentionItemsRef.current = filteredMentionItems;
|
|
535
641
|
const filteredCommandsRef = useRef(filteredCommands);
|
|
536
642
|
filteredCommandsRef.current = filteredCommands;
|
|
537
643
|
const filteredSkillsRef = useRef(filteredSkills);
|
|
@@ -541,6 +647,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
541
647
|
const onTextChangeRef = useRef(onTextChange);
|
|
542
648
|
onTextChangeRef.current = onTextChange;
|
|
543
649
|
const initialTextKeyRef = useRef(undefined);
|
|
650
|
+
const seenReferenceInsertIdsRef = useRef(new Set());
|
|
544
651
|
const closePopover = useCallback(() => {
|
|
545
652
|
setPopover(null);
|
|
546
653
|
popoverStateRef.current = null;
|
|
@@ -570,7 +677,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
570
677
|
if (initialText !== undefined) {
|
|
571
678
|
ed.commands.setContent(plainTextToDoc(initialText));
|
|
572
679
|
ed.commands.focus("end");
|
|
573
|
-
setEditorHasText(ed.state.doc
|
|
680
|
+
setEditorHasText(composerDocumentHasContent(ed.state.doc));
|
|
574
681
|
initialTextKeyRef.current = initialTextKey ?? initialText;
|
|
575
682
|
}
|
|
576
683
|
else {
|
|
@@ -578,7 +685,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
578
685
|
if (saved) {
|
|
579
686
|
ed.commands.setContent(saved);
|
|
580
687
|
ed.commands.focus("end");
|
|
581
|
-
setEditorHasText(ed.state.doc
|
|
688
|
+
setEditorHasText(composerDocumentHasContent(ed.state.doc));
|
|
582
689
|
}
|
|
583
690
|
}
|
|
584
691
|
onTextChangeRef.current?.(ed.state.doc.textContent.trim());
|
|
@@ -588,26 +695,14 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
588
695
|
onUpdate: ({ editor: ed }) => {
|
|
589
696
|
// Drive the send button's enabled state from the actual editor contents;
|
|
590
697
|
// the composer runtime is only synced on submit, so its isEmpty lags.
|
|
591
|
-
|
|
592
|
-
if (!hasContent) {
|
|
593
|
-
ed.state.doc.descendants((node) => {
|
|
594
|
-
if (node.type.name === "mentionReference" ||
|
|
595
|
-
node.type.name === "fileReference" ||
|
|
596
|
-
node.type.name === "skillReference") {
|
|
597
|
-
hasContent = true;
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
600
|
-
return true;
|
|
601
|
-
});
|
|
602
|
-
}
|
|
603
|
-
setEditorHasText(hasContent);
|
|
698
|
+
setEditorHasText(composerDocumentHasContent(ed.state.doc));
|
|
604
699
|
onTextChangeRef.current?.(ed.state.doc.textContent.trim());
|
|
605
700
|
// Debounce-save draft to localStorage
|
|
606
701
|
clearTimeout(draftTimerRef.current);
|
|
607
702
|
draftTimerRef.current = setTimeout(() => {
|
|
608
703
|
try {
|
|
609
704
|
const html = ed.getHTML();
|
|
610
|
-
const isEmpty = !ed.state.doc
|
|
705
|
+
const isEmpty = !composerDocumentHasContent(ed.state.doc);
|
|
611
706
|
if (isEmpty) {
|
|
612
707
|
localStorage.removeItem(draftKey);
|
|
613
708
|
}
|
|
@@ -819,6 +914,92 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
819
914
|
},
|
|
820
915
|
},
|
|
821
916
|
});
|
|
917
|
+
const insertReference = useCallback((ref) => {
|
|
918
|
+
const normalized = normalizeAgentComposerReference(ref);
|
|
919
|
+
const ed = editor;
|
|
920
|
+
if (!normalized || !ed)
|
|
921
|
+
return;
|
|
922
|
+
if (normalized.slotKey) {
|
|
923
|
+
setSlotReferences((current) => applySlotReferenceChanges(current, [normalized]));
|
|
924
|
+
ed.commands.focus("end");
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
if (normalized.relatedReferences?.some((item) => item.slotKey)) {
|
|
928
|
+
setSlotReferences((current) => applySlotReferenceChanges(current, normalized.relatedReferences ?? []));
|
|
929
|
+
}
|
|
930
|
+
ed.chain()
|
|
931
|
+
.focus()
|
|
932
|
+
.insertContent({
|
|
933
|
+
type: "mentionReference",
|
|
934
|
+
attrs: mentionReferenceAttrs(normalized),
|
|
935
|
+
})
|
|
936
|
+
.insertContent(" ")
|
|
937
|
+
.run();
|
|
938
|
+
setEditorHasText(true);
|
|
939
|
+
}, [editor]);
|
|
940
|
+
const insertReferenceIfEmpty = useCallback((payload) => {
|
|
941
|
+
const insertMessageId = typeof payload.insertMessageId === "string"
|
|
942
|
+
? payload.insertMessageId
|
|
943
|
+
: "";
|
|
944
|
+
if (insertMessageId) {
|
|
945
|
+
if (seenReferenceInsertIdsRef.current.has(insertMessageId))
|
|
946
|
+
return;
|
|
947
|
+
seenReferenceInsertIdsRef.current.add(insertMessageId);
|
|
948
|
+
}
|
|
949
|
+
const ed = editor;
|
|
950
|
+
if (!ed || disabled || composerModeRef.current)
|
|
951
|
+
return;
|
|
952
|
+
const normalized = normalizeAgentComposerReference(payload);
|
|
953
|
+
if (normalized?.slotKey) {
|
|
954
|
+
insertReference(normalized);
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
if (composerAttachments.length > 0)
|
|
958
|
+
return;
|
|
959
|
+
if (composerDocumentHasContent(ed.state.doc))
|
|
960
|
+
return;
|
|
961
|
+
insertReference(payload);
|
|
962
|
+
}, [composerAttachments.length, disabled, editor, insertReference]);
|
|
963
|
+
useEffect(() => {
|
|
964
|
+
if (typeof window === "undefined")
|
|
965
|
+
return;
|
|
966
|
+
const handleEvent = (event) => {
|
|
967
|
+
const payload = event.detail;
|
|
968
|
+
const normalized = normalizeAgentComposerReference(payload);
|
|
969
|
+
if (!normalized)
|
|
970
|
+
return;
|
|
971
|
+
insertReferenceIfEmpty({
|
|
972
|
+
...normalized,
|
|
973
|
+
insertMessageId: typeof payload?.insertMessageId === "string"
|
|
974
|
+
? payload.insertMessageId
|
|
975
|
+
: "",
|
|
976
|
+
});
|
|
977
|
+
};
|
|
978
|
+
const handleMessage = (event) => {
|
|
979
|
+
if (!isTrustedFrameMessage(event) && !isTrustedBuilderMessage(event)) {
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
if (event.data?.type !== AGENT_CHAT_INSERT_REFERENCE_MESSAGE_TYPE) {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
const payload = event.data.data;
|
|
986
|
+
const normalized = normalizeAgentComposerReference(payload);
|
|
987
|
+
if (!normalized)
|
|
988
|
+
return;
|
|
989
|
+
insertReferenceIfEmpty({
|
|
990
|
+
...normalized,
|
|
991
|
+
insertMessageId: typeof payload?.insertMessageId === "string"
|
|
992
|
+
? payload.insertMessageId
|
|
993
|
+
: "",
|
|
994
|
+
});
|
|
995
|
+
};
|
|
996
|
+
window.addEventListener(AGENT_CHAT_INSERT_REFERENCE_EVENT, handleEvent);
|
|
997
|
+
window.addEventListener("message", handleMessage);
|
|
998
|
+
return () => {
|
|
999
|
+
window.removeEventListener(AGENT_CHAT_INSERT_REFERENCE_EVENT, handleEvent);
|
|
1000
|
+
window.removeEventListener("message", handleMessage);
|
|
1001
|
+
};
|
|
1002
|
+
}, [insertReferenceIfEmpty]);
|
|
822
1003
|
useImperativeHandle(focusRef, () => ({
|
|
823
1004
|
focus() {
|
|
824
1005
|
editor?.commands.focus("end");
|
|
@@ -830,6 +1011,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
830
1011
|
editor.commands.focus("end");
|
|
831
1012
|
const trimmed = editor.state.doc.textContent.trim();
|
|
832
1013
|
setEditorHasText(trimmed.length > 0);
|
|
1014
|
+
setSlotReferences([]);
|
|
833
1015
|
composerRuntime.setText(trimmed);
|
|
834
1016
|
onTextChangeRef.current?.(trimmed);
|
|
835
1017
|
try {
|
|
@@ -842,6 +1024,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
842
1024
|
}
|
|
843
1025
|
catch { }
|
|
844
1026
|
},
|
|
1027
|
+
insertReference,
|
|
845
1028
|
}));
|
|
846
1029
|
const handleSelectMode = useCallback((mode) => {
|
|
847
1030
|
setComposerMode(mode);
|
|
@@ -961,9 +1144,12 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
961
1144
|
const extractComposerPayload = useCallback(() => {
|
|
962
1145
|
const ed = editor;
|
|
963
1146
|
if (!ed) {
|
|
964
|
-
return {
|
|
1147
|
+
return {
|
|
1148
|
+
text: slotReferences.map((ref) => slotReferenceTitle(ref)).join(", "),
|
|
1149
|
+
references: slotReferences.map(referenceFromComposerReference),
|
|
1150
|
+
};
|
|
965
1151
|
}
|
|
966
|
-
const references =
|
|
1152
|
+
const references = slotReferences.map(referenceFromComposerReference);
|
|
967
1153
|
// Build text that preserves @mentions (getText() strips them).
|
|
968
1154
|
// Walk the document and reconstruct with @name for mention/file/skill nodes.
|
|
969
1155
|
const textParts = [];
|
|
@@ -990,7 +1176,9 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
990
1176
|
textParts.push("\n");
|
|
991
1177
|
}
|
|
992
1178
|
});
|
|
993
|
-
const
|
|
1179
|
+
const rawText = textParts.join("").trim();
|
|
1180
|
+
const text = rawText ||
|
|
1181
|
+
slotReferences.map((ref) => slotReferenceTitle(ref)).join(", ");
|
|
994
1182
|
ed.state.doc.descendants((node) => {
|
|
995
1183
|
if (node.type.name === "fileReference") {
|
|
996
1184
|
// Legacy support
|
|
@@ -1016,6 +1204,9 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1016
1204
|
source: node.attrs.source,
|
|
1017
1205
|
refType: node.attrs.refType,
|
|
1018
1206
|
refId: node.attrs.refId,
|
|
1207
|
+
slotKey: node.attrs.slotKey,
|
|
1208
|
+
slotLabel: node.attrs.slotLabel,
|
|
1209
|
+
metadata: node.attrs.metadata,
|
|
1019
1210
|
});
|
|
1020
1211
|
}
|
|
1021
1212
|
else if (node.type.name === "skillReference") {
|
|
@@ -1028,7 +1219,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1028
1219
|
}
|
|
1029
1220
|
});
|
|
1030
1221
|
return { text, references };
|
|
1031
|
-
}, [editor]);
|
|
1222
|
+
}, [editor, slotReferences]);
|
|
1032
1223
|
const syncComposerState = useCallback(() => {
|
|
1033
1224
|
const { text, references } = extractComposerPayload();
|
|
1034
1225
|
const requestMode = execMode === "plan" ? "plan" : execMode === "build" ? "act" : undefined;
|
|
@@ -1109,6 +1300,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1109
1300
|
cancelActiveVoice();
|
|
1110
1301
|
ed.commands.clearContent();
|
|
1111
1302
|
setEditorHasText(false);
|
|
1303
|
+
setSlotReferences([]);
|
|
1112
1304
|
setComposerMode(null);
|
|
1113
1305
|
composerModeRef.current = null;
|
|
1114
1306
|
try {
|
|
@@ -1129,6 +1321,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1129
1321
|
cancelActiveVoice();
|
|
1130
1322
|
ed.commands.clearContent();
|
|
1131
1323
|
setEditorHasText(false);
|
|
1324
|
+
setSlotReferences([]);
|
|
1132
1325
|
try {
|
|
1133
1326
|
localStorage.removeItem(draftKey);
|
|
1134
1327
|
}
|
|
@@ -1151,6 +1344,7 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1151
1344
|
cancelActiveVoice();
|
|
1152
1345
|
ed.commands.clearContent();
|
|
1153
1346
|
setEditorHasText(false);
|
|
1347
|
+
setSlotReferences([]);
|
|
1154
1348
|
try {
|
|
1155
1349
|
localStorage.removeItem(draftKey);
|
|
1156
1350
|
}
|
|
@@ -1177,22 +1371,8 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1177
1371
|
const currentPos = ed.state.selection.from;
|
|
1178
1372
|
// startPos is after the trigger char, so -1 to include the @ or /
|
|
1179
1373
|
const deleteFrom = Math.max(0, pop.startPos - 1);
|
|
1180
|
-
ed.chain()
|
|
1181
|
-
|
|
1182
|
-
.deleteRange({ from: deleteFrom, to: currentPos })
|
|
1183
|
-
.insertContent({
|
|
1184
|
-
type: "mentionReference",
|
|
1185
|
-
attrs: {
|
|
1186
|
-
label: item.label,
|
|
1187
|
-
icon: item.icon || "file",
|
|
1188
|
-
source: item.source,
|
|
1189
|
-
refType: item.refType,
|
|
1190
|
-
refId: item.refId || null,
|
|
1191
|
-
refPath: item.refPath || null,
|
|
1192
|
-
},
|
|
1193
|
-
})
|
|
1194
|
-
.insertContent(" ")
|
|
1195
|
-
.run();
|
|
1374
|
+
ed.chain().focus().deleteRange({ from: deleteFrom, to: currentPos }).run();
|
|
1375
|
+
insertReference(composerReferenceFromMentionItem(item));
|
|
1196
1376
|
popoverStateRef.current = null;
|
|
1197
1377
|
setPopover(null);
|
|
1198
1378
|
}
|
|
@@ -1235,21 +1415,10 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1235
1415
|
.chain()
|
|
1236
1416
|
.focus()
|
|
1237
1417
|
.deleteRange({ from: deleteFrom, to: currentPos })
|
|
1238
|
-
.insertContent({
|
|
1239
|
-
type: "mentionReference",
|
|
1240
|
-
attrs: {
|
|
1241
|
-
label: item.label,
|
|
1242
|
-
icon: item.icon || "file",
|
|
1243
|
-
source: item.source,
|
|
1244
|
-
refType: item.refType,
|
|
1245
|
-
refId: item.refId || null,
|
|
1246
|
-
refPath: item.refPath || null,
|
|
1247
|
-
},
|
|
1248
|
-
})
|
|
1249
|
-
.insertContent(" ")
|
|
1250
1418
|
.run();
|
|
1419
|
+
insertReference(composerReferenceFromMentionItem(item));
|
|
1251
1420
|
closePopover();
|
|
1252
|
-
}, [editor, popover, closePopover]);
|
|
1421
|
+
}, [editor, popover, closePopover, insertReference]);
|
|
1253
1422
|
const handleSelectCommand = useCallback((command) => {
|
|
1254
1423
|
if (!editor || !popover)
|
|
1255
1424
|
return;
|
|
@@ -1369,7 +1538,10 @@ export function TiptapComposer({ placeholder = "Message agent...", disabled = fa
|
|
|
1369
1538
|
setComposerMode(null);
|
|
1370
1539
|
composerModeRef.current = null;
|
|
1371
1540
|
editor?.commands.focus("end");
|
|
1372
|
-
} }) })),
|
|
1373
|
-
|
|
1541
|
+
} }) })), hasContextRows && (_jsxs("div", { "data-agent-composer-variant": layoutVariant, "data-agent-composer-slot": "context-row", className: "agent-composer-context-row flex flex-wrap gap-1.5 px-2.5 pt-2 pb-0", children: [slotReferences.map((ref) => (_jsxs("span", { className: "inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-background px-2 py-1 text-[11px] font-medium text-foreground shadow-sm", children: [_jsx(IconClipboardList, { className: "h-3 w-3 shrink-0 text-muted-foreground" }), ref.slotLabel && (_jsx("span", { className: "shrink-0 text-muted-foreground", children: ref.slotLabel })), _jsx("span", { className: "min-w-0 truncate", children: ref.label }), _jsx("button", { type: "button", onClick: () => {
|
|
1542
|
+
setSlotReferences((current) => removeSlotReference(current, ref));
|
|
1543
|
+
editor?.commands.focus("end");
|
|
1544
|
+
}, "aria-label": `Remove ${slotReferenceTitle(ref)} reference`, 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", { className: "inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-muted/50 px-2 py-1 text-[11px] font-medium text-foreground", 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: () => onRemoveContextItem?.(item.key), "aria-label": `Remove ${item.title} context`, 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 ??
|
|
1545
|
+
(plusMenuMode === "hidden" ? null : (_jsx(ComposerPlusMenu, { onSelectMode: handleSelectMode, mode: plusMenuMode, 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, onChange: onModelChange, onEffortChange: onEffortChange, providerConnectStatusEnabled: providerConnectStatusEnabled, onConnectProvider: onConnectProvider, 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 })), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => 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 disabled:opacity-30 disabled:cursor-not-allowed", children: _jsx(IconArrowUp, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Send message" })] })] }))] }), _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 })] }));
|
|
1374
1546
|
}
|
|
1375
1547
|
//# sourceMappingURL=TiptapComposer.js.map
|