@agent-native/toolkit 0.209.0 → 0.209.1-nightly-20261015005848
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/app/chat/AgentSidebar.d.ts.map +1 -1
- package/dist/app/chat/AgentSidebar.js +22 -11
- package/dist/app/chat/AgentSidebar.js.map +1 -1
- package/dist/app/review/InlineMarkdown.d.ts +2 -0
- package/dist/app/review/InlineMarkdown.d.ts.map +1 -1
- package/dist/app/review/InlineMarkdown.js +25 -7
- package/dist/app/review/InlineMarkdown.js.map +1 -1
- package/dist/composer/MentionChip.d.ts +14 -0
- package/dist/composer/MentionChip.d.ts.map +1 -0
- package/dist/composer/MentionChip.js +11 -0
- package/dist/composer/MentionChip.js.map +1 -0
- package/dist/composer/MentionPopover.d.ts +5 -0
- package/dist/composer/MentionPopover.d.ts.map +1 -1
- package/dist/composer/MentionPopover.js +55 -44
- package/dist/composer/MentionPopover.js.map +1 -1
- package/dist/composer/PromptComposer.d.ts +6 -1
- package/dist/composer/PromptComposer.d.ts.map +1 -1
- package/dist/composer/PromptComposer.js +3 -3
- package/dist/composer/PromptComposer.js.map +1 -1
- package/dist/composer/TiptapComposer.d.ts +18 -2
- package/dist/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/composer/TiptapComposer.js +60 -12
- package/dist/composer/TiptapComposer.js.map +1 -1
- package/dist/composer/extensions/MentionReference.d.ts.map +1 -1
- package/dist/composer/extensions/MentionReference.js +16 -5
- package/dist/composer/extensions/MentionReference.js.map +1 -1
- package/dist/composer/index.d.ts +2 -1
- package/dist/composer/index.d.ts.map +1 -1
- package/dist/composer/index.js +1 -0
- package/dist/composer/index.js.map +1 -1
- package/package.json +4 -4
- package/src/app/chat/AgentSidebar.spec.tsx +339 -2
- package/src/app/chat/AgentSidebar.tsx +25 -10
- package/src/app/review/InlineMarkdown.spec.tsx +25 -0
- package/src/app/review/InlineMarkdown.tsx +29 -13
- package/src/composer/MentionChip.tsx +46 -0
- package/src/composer/MentionPopover.tsx +49 -7
- package/src/composer/PromptComposer.text-references.spec.tsx +198 -0
- package/src/composer/PromptComposer.tsx +12 -0
- package/src/composer/TiptapComposer.tsx +100 -10
- package/src/composer/extensions/MentionReference.tsx +22 -14
- package/src/composer/index.ts +2 -0
|
@@ -183,7 +183,12 @@ export interface TiptapComposerHandle {
|
|
|
183
183
|
* triggers such as `@` open their menus as if the person typed them.
|
|
184
184
|
*/
|
|
185
185
|
insertTextAtCursor?(text: string): void;
|
|
186
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Replace the draft. Each reference becomes a chip in place of
|
|
188
|
+
* `text.slice(start, end)`; one that overlaps another or crosses a line
|
|
189
|
+
* break stays text.
|
|
190
|
+
*/
|
|
191
|
+
setText(text: string, references?: readonly ComposerTextReference[]): void;
|
|
187
192
|
/** Submit replacement text with the current attachments and context, without editing the draft on failure. */
|
|
188
193
|
submitWithText(text: string): Promise<boolean>;
|
|
189
194
|
/** Submit the current draft as if the person pressed send. */
|
|
@@ -207,6 +212,13 @@ export interface ComposerTextSelection {
|
|
|
207
212
|
direction: "forward" | "backward" | "none";
|
|
208
213
|
}
|
|
209
214
|
|
|
215
|
+
/** A chip standing for `text.slice(start, end)` of a draft's plain text. */
|
|
216
|
+
export interface ComposerTextReference {
|
|
217
|
+
start: number;
|
|
218
|
+
end: number;
|
|
219
|
+
reference: AgentComposerReference;
|
|
220
|
+
}
|
|
221
|
+
|
|
210
222
|
export type ComposerSubmitIntent = "immediate" | "queued";
|
|
211
223
|
|
|
212
224
|
export const DEFAULT_VOICE_DICTATION_ENABLED = false;
|
|
@@ -1066,6 +1078,8 @@ export interface TiptapComposerProps {
|
|
|
1066
1078
|
initialText?: string;
|
|
1067
1079
|
/** Stable key used to re-apply the seeded text. */
|
|
1068
1080
|
initialTextKey?: string | number;
|
|
1081
|
+
/** Chips placed into `initialText`, as `setText` takes them. */
|
|
1082
|
+
initialReferences?: readonly ComposerTextReference[];
|
|
1069
1083
|
/**
|
|
1070
1084
|
* When provided, called instead of composerRuntime.send(). Used for queue
|
|
1071
1085
|
* mode and standalone prompt popovers. Receives the live composer
|
|
@@ -1095,6 +1109,9 @@ export interface TiptapComposerProps {
|
|
|
1095
1109
|
/** Called whenever the plain editor text changes. */
|
|
1096
1110
|
onTextChange?: (text: string) => void;
|
|
1097
1111
|
mentionItems?: MentionItem[];
|
|
1112
|
+
/** Why some of `mentionItems` could not load, shown in the @ popover. */
|
|
1113
|
+
mentionItemsError?: string;
|
|
1114
|
+
onRetryMentionItems?: () => void;
|
|
1098
1115
|
mentionPopoverDensity?: "default" | "stacked";
|
|
1099
1116
|
includeDefaultMentionSearch?: boolean;
|
|
1100
1117
|
onReferencesChange?: (references: Reference[]) => void;
|
|
@@ -1239,14 +1256,53 @@ export interface TiptapComposerProps {
|
|
|
1239
1256
|
onAttachmentError?: (message: string) => void;
|
|
1240
1257
|
}
|
|
1241
1258
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1259
|
+
interface TextChip {
|
|
1260
|
+
start: number;
|
|
1261
|
+
end: number;
|
|
1262
|
+
attrs: ReturnType<typeof mentionReferenceAttrs>;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
function plainTextToDoc(text: string, chips: readonly TextChip[] = []) {
|
|
1266
|
+
const ordered = [...chips].sort((a, b) => a.start - b.start);
|
|
1267
|
+
const lines: { start: number; end: number }[] = [];
|
|
1268
|
+
let lineStart = 0;
|
|
1269
|
+
for (const separator of text.matchAll(/\r?\n/g)) {
|
|
1270
|
+
lines.push({ start: lineStart, end: separator.index });
|
|
1271
|
+
lineStart = separator.index + separator[0].length;
|
|
1272
|
+
}
|
|
1273
|
+
lines.push({ start: lineStart, end: text.length });
|
|
1244
1274
|
return {
|
|
1245
1275
|
type: "doc",
|
|
1246
|
-
content: lines.map((line) =>
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1276
|
+
content: lines.map((line) => {
|
|
1277
|
+
const content: Record<string, unknown>[] = [];
|
|
1278
|
+
let cursor = line.start;
|
|
1279
|
+
const addText = (end: number) => {
|
|
1280
|
+
if (end > cursor) {
|
|
1281
|
+
content.push({ type: "text", text: text.slice(cursor, end) });
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
for (const chip of ordered) {
|
|
1285
|
+
if (
|
|
1286
|
+
chip.start < cursor ||
|
|
1287
|
+
line.end < chip.end ||
|
|
1288
|
+
chip.end <= chip.start
|
|
1289
|
+
)
|
|
1290
|
+
continue;
|
|
1291
|
+
addText(chip.start);
|
|
1292
|
+
content.push({ type: "mentionReference", attrs: chip.attrs });
|
|
1293
|
+
cursor = chip.end;
|
|
1294
|
+
}
|
|
1295
|
+
addText(line.end);
|
|
1296
|
+
// Drafts are reported trimmed, so a chip that ends one lost the space
|
|
1297
|
+
// picking it added; without it the next word typed joins the chip's text.
|
|
1298
|
+
if (
|
|
1299
|
+
cursor === text.length &&
|
|
1300
|
+
content.at(-1)?.type === "mentionReference"
|
|
1301
|
+
) {
|
|
1302
|
+
content.push({ type: "text", text: " " });
|
|
1303
|
+
}
|
|
1304
|
+
return { type: "paragraph", content };
|
|
1305
|
+
}),
|
|
1250
1306
|
};
|
|
1251
1307
|
}
|
|
1252
1308
|
|
|
@@ -2779,6 +2835,7 @@ export function TiptapComposer({
|
|
|
2779
2835
|
focusRef,
|
|
2780
2836
|
initialText,
|
|
2781
2837
|
initialTextKey,
|
|
2838
|
+
initialReferences,
|
|
2782
2839
|
onSubmit,
|
|
2783
2840
|
onEmptySubmit,
|
|
2784
2841
|
onBeforeSubmit,
|
|
@@ -2835,6 +2892,8 @@ export function TiptapComposer({
|
|
|
2835
2892
|
interceptBuildRequestsForBuilder = false,
|
|
2836
2893
|
onAttachmentError,
|
|
2837
2894
|
mentionItems: hostMentionItems = [],
|
|
2895
|
+
mentionItemsError,
|
|
2896
|
+
onRetryMentionItems,
|
|
2838
2897
|
mentionPopoverDensity = "default",
|
|
2839
2898
|
includeDefaultMentionSearch = true,
|
|
2840
2899
|
onReferencesChange,
|
|
@@ -2849,6 +2908,20 @@ export function TiptapComposer({
|
|
|
2849
2908
|
!(attachmentsEnabled && attachButton);
|
|
2850
2909
|
const adapters = useComposerRuntimeAdapters();
|
|
2851
2910
|
const t = adapters.translate!;
|
|
2911
|
+
const initialReferencesRef = useRef(initialReferences);
|
|
2912
|
+
initialReferencesRef.current = initialReferences;
|
|
2913
|
+
const textChips = useCallback(
|
|
2914
|
+
(references: readonly ComposerTextReference[] = []): TextChip[] =>
|
|
2915
|
+
references.flatMap(({ start, end, reference }) => {
|
|
2916
|
+
const normalized = adapters.agentChat!.normalizeReference!(
|
|
2917
|
+
reference,
|
|
2918
|
+
) as AgentComposerReference | null;
|
|
2919
|
+
return normalized
|
|
2920
|
+
? [{ start, end, attrs: mentionReferenceAttrs(normalized) }]
|
|
2921
|
+
: [];
|
|
2922
|
+
}),
|
|
2923
|
+
[adapters],
|
|
2924
|
+
);
|
|
2852
2925
|
const sendButtonTooltip = t(getComposerSendTooltipKey(willQueue), {
|
|
2853
2926
|
defaultValue: willQueue ? "Queue message" : "Send message",
|
|
2854
2927
|
});
|
|
@@ -3632,6 +3705,14 @@ export function TiptapComposer({
|
|
|
3632
3705
|
popoverRef.current?.moveDown();
|
|
3633
3706
|
return true;
|
|
3634
3707
|
}
|
|
3708
|
+
if (
|
|
3709
|
+
(event.key === "Enter" ||
|
|
3710
|
+
(event.key === "Tab" && !event.shiftKey)) &&
|
|
3711
|
+
popoverRef.current?.activateRetry()
|
|
3712
|
+
) {
|
|
3713
|
+
event.preventDefault();
|
|
3714
|
+
return true;
|
|
3715
|
+
}
|
|
3635
3716
|
// A mention comes only from an explicit pick of a highlighted row. With
|
|
3636
3717
|
// nothing highlighted, even while a search is pending, the "@" is
|
|
3637
3718
|
// plain text: Enter submits it and a late result changes nothing.
|
|
@@ -4032,7 +4113,11 @@ export function TiptapComposer({
|
|
|
4032
4113
|
);
|
|
4033
4114
|
if (from > 1 && before !== "" && !/\s/.test(before)) inserted = ` @`;
|
|
4034
4115
|
}
|
|
4116
|
+
// The popover anchors on the selection right after this insert, but an
|
|
4117
|
+
// execCommand edit reaches the editor state only once ProseMirror reads
|
|
4118
|
+
// the DOM back, so an @ goes through the editor directly.
|
|
4035
4119
|
if (
|
|
4120
|
+
mention ||
|
|
4036
4121
|
typeof document.execCommand !== "function" ||
|
|
4037
4122
|
!document.execCommand("insertText", false, inserted)
|
|
4038
4123
|
) {
|
|
@@ -4052,9 +4137,9 @@ export function TiptapComposer({
|
|
|
4052
4137
|
popoverStateRef.current = state;
|
|
4053
4138
|
setPopover(state);
|
|
4054
4139
|
},
|
|
4055
|
-
setText(text: string) {
|
|
4140
|
+
setText(text: string, references?: readonly ComposerTextReference[]) {
|
|
4056
4141
|
if (!isComposerEditorUsable(editor)) return;
|
|
4057
|
-
editor.commands.setContent(plainTextToDoc(text));
|
|
4142
|
+
editor.commands.setContent(plainTextToDoc(text, textChips(references)));
|
|
4058
4143
|
editor.commands.focus("end");
|
|
4059
4144
|
const trimmed = editor.getText({ blockSeparator: "\n" }).trim();
|
|
4060
4145
|
setEditorHasText(trimmed.length > 0);
|
|
@@ -5799,7 +5884,9 @@ export function TiptapComposer({
|
|
|
5799
5884
|
return;
|
|
5800
5885
|
} else if (initialTextKeyRef.current !== key) {
|
|
5801
5886
|
initialTextKeyRef.current = key;
|
|
5802
|
-
editor.commands.setContent(
|
|
5887
|
+
editor.commands.setContent(
|
|
5888
|
+
plainTextToDoc(initialText, textChips(initialReferencesRef.current)),
|
|
5889
|
+
);
|
|
5803
5890
|
} else {
|
|
5804
5891
|
return;
|
|
5805
5892
|
}
|
|
@@ -5821,6 +5908,7 @@ export function TiptapComposer({
|
|
|
5821
5908
|
initialText,
|
|
5822
5909
|
initialTextKey,
|
|
5823
5910
|
scheduleComposerDraftPersist,
|
|
5911
|
+
textChips,
|
|
5824
5912
|
updateSlotReferences,
|
|
5825
5913
|
]);
|
|
5826
5914
|
|
|
@@ -6228,6 +6316,8 @@ export function TiptapComposer({
|
|
|
6228
6316
|
commands={filteredCommands}
|
|
6229
6317
|
hint={hint}
|
|
6230
6318
|
isLoading={popover?.type === "@" ? mentionsLoading : skillsLoading}
|
|
6319
|
+
error={mentionItemsError}
|
|
6320
|
+
onRetry={onRetryMentionItems}
|
|
6231
6321
|
query={popover?.query ?? ""}
|
|
6232
6322
|
onSelectMention={handleSelectMention}
|
|
6233
6323
|
onSelectSkill={handleSelectSkill}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { mergeAttributes, Node } from "@tiptap/core";
|
|
2
2
|
import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { MentionChip } from "../MentionChip.js";
|
|
5
5
|
import type { MentionItemMedia as MentionItemMediaValue } from "../types.js";
|
|
6
6
|
|
|
7
|
+
const NAME_START = /^[\p{L}\p{M}\p{N}_]/u;
|
|
8
|
+
const NAME_END = /[\p{L}\p{M}\p{N}_]$/u;
|
|
9
|
+
|
|
7
10
|
function parseMentionItemMedia(
|
|
8
11
|
value: string | null,
|
|
9
12
|
): MentionItemMediaValue | null {
|
|
@@ -46,21 +49,16 @@ function parseMentionItemMedia(
|
|
|
46
49
|
const MentionReferenceComponent = ({ node }: { node: any }) => {
|
|
47
50
|
return (
|
|
48
51
|
<NodeViewWrapper as="span" className="inline">
|
|
49
|
-
<
|
|
50
|
-
className="
|
|
52
|
+
<MentionChip
|
|
53
|
+
className="select-none"
|
|
51
54
|
title={node.attrs.refPath || node.attrs.refId || node.attrs.label}
|
|
52
55
|
data-mention-reference=""
|
|
53
56
|
data-mention-ref-type={node.attrs.refType || undefined}
|
|
54
57
|
data-mention-ref-id={node.attrs.refId || undefined}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
size="sm"
|
|
60
|
-
fallbackIcon="stack"
|
|
61
|
-
/>
|
|
62
|
-
<span className="truncate">{node.attrs.label}</span>
|
|
63
|
-
</span>
|
|
58
|
+
icon={node.attrs.icon}
|
|
59
|
+
media={node.attrs.media}
|
|
60
|
+
label={node.attrs.label}
|
|
61
|
+
/>
|
|
64
62
|
</NodeViewWrapper>
|
|
65
63
|
);
|
|
66
64
|
};
|
|
@@ -106,8 +104,18 @@ export const MentionReference = Node.create({
|
|
|
106
104
|
];
|
|
107
105
|
},
|
|
108
106
|
|
|
109
|
-
renderText({ node }) {
|
|
110
|
-
|
|
107
|
+
renderText({ node, parent, index }) {
|
|
108
|
+
const text = `@${node.attrs.label}`;
|
|
109
|
+
// Text matches a mention only as a whole @name token, so a chip right
|
|
110
|
+
// against a word would read as no mention, or as a later one.
|
|
111
|
+
const before = parent.maybeChild(index - 1);
|
|
112
|
+
const after = parent.maybeChild(index + 1);
|
|
113
|
+
const leading = before?.isText && NAME_END.test(before.text ?? "");
|
|
114
|
+
const trailing =
|
|
115
|
+
NAME_END.test(text) &&
|
|
116
|
+
((after?.isText && NAME_START.test(after.text ?? "")) ||
|
|
117
|
+
after?.type === node.type);
|
|
118
|
+
return `${leading ? " " : ""}${text}${trailing ? " " : ""}`;
|
|
111
119
|
},
|
|
112
120
|
|
|
113
121
|
addNodeView() {
|
package/src/composer/index.ts
CHANGED
|
@@ -59,6 +59,7 @@ export {
|
|
|
59
59
|
type ComposerDraftSnapshot,
|
|
60
60
|
type ComposerSubmitIntent,
|
|
61
61
|
type TiptapComposerHandle,
|
|
62
|
+
type ComposerTextReference,
|
|
62
63
|
type ComposerTextSelection,
|
|
63
64
|
type TiptapComposerProps,
|
|
64
65
|
type TiptapComposerSubmitOptions,
|
|
@@ -128,6 +129,7 @@ export {
|
|
|
128
129
|
type AgentPromptAttachment,
|
|
129
130
|
type ReadAgentPromptAttachmentOptions,
|
|
130
131
|
} from "./prompt-attachments.js";
|
|
132
|
+
export { MentionChip, type MentionChipProps } from "./MentionChip.js";
|
|
131
133
|
export { MentionPopover } from "./MentionPopover.js";
|
|
132
134
|
export { useMentionSearch } from "./use-mention-search.js";
|
|
133
135
|
export {
|