@copilotz/chat-ui 0.3.0 → 0.3.2
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/README.md +3 -34
- package/dist/index.cjs +172 -150
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -43
- package/dist/index.d.ts +3 -43
- package/dist/index.js +171 -144
- package/dist/index.js.map +1 -1
- package/dist/styles.css +16 -0
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -488,6 +488,8 @@ interface ChatInputProps {
|
|
|
488
488
|
acceptedFileTypes?: string[];
|
|
489
489
|
className?: string;
|
|
490
490
|
config?: ChatConfig;
|
|
491
|
+
mentionAgents?: AgentOption[];
|
|
492
|
+
onTargetAgentChange?: (agentId: string | null) => void;
|
|
491
493
|
}
|
|
492
494
|
declare const ChatInput: React__default.FC<ChatInputProps>;
|
|
493
495
|
|
|
@@ -693,48 +695,6 @@ declare const UserProfile: React__default.FC<UserProfileProps>;
|
|
|
693
695
|
|
|
694
696
|
declare const defaultChatConfig: Required<ChatConfig>;
|
|
695
697
|
declare function mergeConfig(_baseConfig: ChatConfig, userConfig?: Partial<ChatConfig>): Required<ChatConfig>;
|
|
696
|
-
declare const chatConfigPresets: {
|
|
697
|
-
readonly minimal: Partial<ChatConfig>;
|
|
698
|
-
readonly full: Partial<ChatConfig>;
|
|
699
|
-
readonly developer: Partial<ChatConfig>;
|
|
700
|
-
readonly customer_support: Partial<ChatConfig>;
|
|
701
|
-
};
|
|
702
|
-
declare function validateConfig(config: ChatConfig): string[];
|
|
703
|
-
declare const themeUtils: {
|
|
704
|
-
getSystemTheme: () => "light" | "dark";
|
|
705
|
-
resolveTheme: (theme: "light" | "dark" | "auto") => "light" | "dark";
|
|
706
|
-
applyTheme: (theme: "light" | "dark" | "auto") => void;
|
|
707
|
-
};
|
|
708
|
-
declare const featureFlags: {
|
|
709
|
-
isEnabled: (config: Required<ChatConfig>, feature: keyof Required<ChatConfig>["features"]) => boolean;
|
|
710
|
-
getEnabledFeatures: (config: Required<ChatConfig>) => string[];
|
|
711
|
-
hasAnyFeature: (config: Required<ChatConfig>, features: (keyof Required<ChatConfig>["features"])[]) => boolean;
|
|
712
|
-
};
|
|
713
|
-
declare const configUtils: {
|
|
714
|
-
createConfigHook: (config: Required<ChatConfig>) => {
|
|
715
|
-
config: Required<ChatConfig>;
|
|
716
|
-
isFeatureEnabled: (feature: keyof Required<ChatConfig>["features"]) => boolean;
|
|
717
|
-
getLabel: (key: keyof Required<ChatConfig>["labels"]) => string | undefined;
|
|
718
|
-
getBranding: () => {
|
|
719
|
-
logo?: React.ReactNode;
|
|
720
|
-
title?: string;
|
|
721
|
-
subtitle?: string;
|
|
722
|
-
avatar?: React.ReactNode;
|
|
723
|
-
};
|
|
724
|
-
getUI: () => {
|
|
725
|
-
theme?: "light" | "dark" | "auto";
|
|
726
|
-
showTimestamps?: boolean;
|
|
727
|
-
showAvatars?: boolean;
|
|
728
|
-
compactMode?: boolean;
|
|
729
|
-
showWordCount?: boolean;
|
|
730
|
-
collapseLongMessages?: boolean;
|
|
731
|
-
collapseLongMessagesForUserOnly?: boolean;
|
|
732
|
-
longMessagePreviewChars?: number;
|
|
733
|
-
longMessageChunkChars?: number;
|
|
734
|
-
renderUserMarkdown?: boolean;
|
|
735
|
-
};
|
|
736
|
-
};
|
|
737
|
-
};
|
|
738
698
|
|
|
739
699
|
declare function cn(...inputs: ClassValue[]): string;
|
|
740
700
|
declare const formatDate: (timestamp: number, labels?: ChatConfig["labels"]) => string;
|
|
@@ -757,4 +717,4 @@ declare function assignAgentColors(agents: AgentOption[]): (AgentOption & {
|
|
|
757
717
|
color: string;
|
|
758
718
|
})[];
|
|
759
719
|
|
|
760
|
-
export { AgentBadge, type AgentOption, type AudioAttachment, type ChatCallbacks, type ChatConfig, ChatHeader, type ChatHeaderConfig, type ChatHeaderProps, ChatInput, type ChatMarkdownConfig, type ChatMessage, type ChatState, type ChatThread, ChatUI, type ChatUserContext, ChatUserContextProvider, type ChatV2Props, type CreateVoiceProvider, type CustomField, type FileUploadProgress, type MediaAttachment, type MemoryItem, Message, type MessageAction, type MessageActionEvent, ParticipantsSelector, Sidebar, type SidebarConfig, type SidebarProps, type StateCallback, type StreamingUpdate, TargetAgentSelector, ThreadManager, type ToolCall, type UserCustomField, UserMenu, type UserMenuCallbacks, type UserMenuConfig, type UserMenuProps, type UserMenuUser, UserProfile, type UserProfileConfig, type UserProfileProps, type UserProfileUser, type VoiceComposerState, type VoiceProvider, type VoiceProviderHandlers, type VoiceProviderOptions, type VoiceReviewMode, type VoiceSegment, type VoiceTranscript, type VoiceTranscriptMode, assignAgentColors,
|
|
720
|
+
export { AgentBadge, type AgentOption, type AudioAttachment, type ChatCallbacks, type ChatConfig, ChatHeader, type ChatHeaderConfig, type ChatHeaderProps, ChatInput, type ChatMarkdownConfig, type ChatMessage, type ChatState, type ChatThread, ChatUI, type ChatUserContext, ChatUserContextProvider, type ChatV2Props, type CreateVoiceProvider, type CustomField, type FileUploadProgress, type MediaAttachment, type MemoryItem, Message, type MessageAction, type MessageActionEvent, ParticipantsSelector, Sidebar, type SidebarConfig, type SidebarProps, type StateCallback, type StreamingUpdate, TargetAgentSelector, ThreadManager, type ToolCall, type UserCustomField, UserMenu, type UserMenuCallbacks, type UserMenuConfig, type UserMenuProps, type UserMenuUser, UserProfile, type UserProfileConfig, type UserProfileProps, type UserProfileUser, type VoiceComposerState, type VoiceProvider, type VoiceProviderHandlers, type VoiceProviderOptions, type VoiceReviewMode, type VoiceSegment, type VoiceTranscript, type VoiceTranscriptMode, assignAgentColors, chatUtils, cn, createObjectUrlFromDataUrl, defaultChatConfig, formatDate, getAgentColor, getAgentInitials, mergeConfig, useChatUserContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -488,6 +488,8 @@ interface ChatInputProps {
|
|
|
488
488
|
acceptedFileTypes?: string[];
|
|
489
489
|
className?: string;
|
|
490
490
|
config?: ChatConfig;
|
|
491
|
+
mentionAgents?: AgentOption[];
|
|
492
|
+
onTargetAgentChange?: (agentId: string | null) => void;
|
|
491
493
|
}
|
|
492
494
|
declare const ChatInput: React__default.FC<ChatInputProps>;
|
|
493
495
|
|
|
@@ -693,48 +695,6 @@ declare const UserProfile: React__default.FC<UserProfileProps>;
|
|
|
693
695
|
|
|
694
696
|
declare const defaultChatConfig: Required<ChatConfig>;
|
|
695
697
|
declare function mergeConfig(_baseConfig: ChatConfig, userConfig?: Partial<ChatConfig>): Required<ChatConfig>;
|
|
696
|
-
declare const chatConfigPresets: {
|
|
697
|
-
readonly minimal: Partial<ChatConfig>;
|
|
698
|
-
readonly full: Partial<ChatConfig>;
|
|
699
|
-
readonly developer: Partial<ChatConfig>;
|
|
700
|
-
readonly customer_support: Partial<ChatConfig>;
|
|
701
|
-
};
|
|
702
|
-
declare function validateConfig(config: ChatConfig): string[];
|
|
703
|
-
declare const themeUtils: {
|
|
704
|
-
getSystemTheme: () => "light" | "dark";
|
|
705
|
-
resolveTheme: (theme: "light" | "dark" | "auto") => "light" | "dark";
|
|
706
|
-
applyTheme: (theme: "light" | "dark" | "auto") => void;
|
|
707
|
-
};
|
|
708
|
-
declare const featureFlags: {
|
|
709
|
-
isEnabled: (config: Required<ChatConfig>, feature: keyof Required<ChatConfig>["features"]) => boolean;
|
|
710
|
-
getEnabledFeatures: (config: Required<ChatConfig>) => string[];
|
|
711
|
-
hasAnyFeature: (config: Required<ChatConfig>, features: (keyof Required<ChatConfig>["features"])[]) => boolean;
|
|
712
|
-
};
|
|
713
|
-
declare const configUtils: {
|
|
714
|
-
createConfigHook: (config: Required<ChatConfig>) => {
|
|
715
|
-
config: Required<ChatConfig>;
|
|
716
|
-
isFeatureEnabled: (feature: keyof Required<ChatConfig>["features"]) => boolean;
|
|
717
|
-
getLabel: (key: keyof Required<ChatConfig>["labels"]) => string | undefined;
|
|
718
|
-
getBranding: () => {
|
|
719
|
-
logo?: React.ReactNode;
|
|
720
|
-
title?: string;
|
|
721
|
-
subtitle?: string;
|
|
722
|
-
avatar?: React.ReactNode;
|
|
723
|
-
};
|
|
724
|
-
getUI: () => {
|
|
725
|
-
theme?: "light" | "dark" | "auto";
|
|
726
|
-
showTimestamps?: boolean;
|
|
727
|
-
showAvatars?: boolean;
|
|
728
|
-
compactMode?: boolean;
|
|
729
|
-
showWordCount?: boolean;
|
|
730
|
-
collapseLongMessages?: boolean;
|
|
731
|
-
collapseLongMessagesForUserOnly?: boolean;
|
|
732
|
-
longMessagePreviewChars?: number;
|
|
733
|
-
longMessageChunkChars?: number;
|
|
734
|
-
renderUserMarkdown?: boolean;
|
|
735
|
-
};
|
|
736
|
-
};
|
|
737
|
-
};
|
|
738
698
|
|
|
739
699
|
declare function cn(...inputs: ClassValue[]): string;
|
|
740
700
|
declare const formatDate: (timestamp: number, labels?: ChatConfig["labels"]) => string;
|
|
@@ -757,4 +717,4 @@ declare function assignAgentColors(agents: AgentOption[]): (AgentOption & {
|
|
|
757
717
|
color: string;
|
|
758
718
|
})[];
|
|
759
719
|
|
|
760
|
-
export { AgentBadge, type AgentOption, type AudioAttachment, type ChatCallbacks, type ChatConfig, ChatHeader, type ChatHeaderConfig, type ChatHeaderProps, ChatInput, type ChatMarkdownConfig, type ChatMessage, type ChatState, type ChatThread, ChatUI, type ChatUserContext, ChatUserContextProvider, type ChatV2Props, type CreateVoiceProvider, type CustomField, type FileUploadProgress, type MediaAttachment, type MemoryItem, Message, type MessageAction, type MessageActionEvent, ParticipantsSelector, Sidebar, type SidebarConfig, type SidebarProps, type StateCallback, type StreamingUpdate, TargetAgentSelector, ThreadManager, type ToolCall, type UserCustomField, UserMenu, type UserMenuCallbacks, type UserMenuConfig, type UserMenuProps, type UserMenuUser, UserProfile, type UserProfileConfig, type UserProfileProps, type UserProfileUser, type VoiceComposerState, type VoiceProvider, type VoiceProviderHandlers, type VoiceProviderOptions, type VoiceReviewMode, type VoiceSegment, type VoiceTranscript, type VoiceTranscriptMode, assignAgentColors,
|
|
720
|
+
export { AgentBadge, type AgentOption, type AudioAttachment, type ChatCallbacks, type ChatConfig, ChatHeader, type ChatHeaderConfig, type ChatHeaderProps, ChatInput, type ChatMarkdownConfig, type ChatMessage, type ChatState, type ChatThread, ChatUI, type ChatUserContext, ChatUserContextProvider, type ChatV2Props, type CreateVoiceProvider, type CustomField, type FileUploadProgress, type MediaAttachment, type MemoryItem, Message, type MessageAction, type MessageActionEvent, ParticipantsSelector, Sidebar, type SidebarConfig, type SidebarProps, type StateCallback, type StreamingUpdate, TargetAgentSelector, ThreadManager, type ToolCall, type UserCustomField, UserMenu, type UserMenuCallbacks, type UserMenuConfig, type UserMenuProps, type UserMenuUser, UserProfile, type UserProfileConfig, type UserProfileProps, type UserProfileUser, type VoiceComposerState, type VoiceProvider, type VoiceProviderHandlers, type VoiceProviderOptions, type VoiceReviewMode, type VoiceSegment, type VoiceTranscript, type VoiceTranscriptMode, assignAgentColors, chatUtils, cn, createObjectUrlFromDataUrl, defaultChatConfig, formatDate, getAgentColor, getAgentInitials, mergeConfig, useChatUserContext };
|
package/dist/index.js
CHANGED
|
@@ -168,127 +168,6 @@ function mergeConfig(_baseConfig, userConfig) {
|
|
|
168
168
|
headerActions: userConfig.headerActions || defaultChatConfig.headerActions
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
|
-
var chatConfigPresets = {
|
|
172
|
-
minimal: {
|
|
173
|
-
features: {
|
|
174
|
-
enableThreads: false,
|
|
175
|
-
enableFileUpload: false,
|
|
176
|
-
enableAudioRecording: false,
|
|
177
|
-
enableMessageEditing: false,
|
|
178
|
-
enableMessageCopy: true,
|
|
179
|
-
enableRegeneration: true,
|
|
180
|
-
enableToolCallsDisplay: false
|
|
181
|
-
},
|
|
182
|
-
ui: {
|
|
183
|
-
compactMode: true,
|
|
184
|
-
showTimestamps: false,
|
|
185
|
-
showAvatars: false
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
full: {
|
|
189
|
-
features: {
|
|
190
|
-
enableThreads: true,
|
|
191
|
-
enableFileUpload: true,
|
|
192
|
-
enableAudioRecording: true,
|
|
193
|
-
enableMessageEditing: true,
|
|
194
|
-
enableMessageCopy: true,
|
|
195
|
-
enableRegeneration: true,
|
|
196
|
-
enableToolCallsDisplay: true
|
|
197
|
-
},
|
|
198
|
-
ui: {
|
|
199
|
-
showTimestamps: true,
|
|
200
|
-
showAvatars: true,
|
|
201
|
-
compactMode: false,
|
|
202
|
-
showWordCount: true
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
developer: {
|
|
206
|
-
features: {
|
|
207
|
-
enableThreads: true,
|
|
208
|
-
enableFileUpload: true,
|
|
209
|
-
enableAudioRecording: false,
|
|
210
|
-
enableMessageEditing: true,
|
|
211
|
-
enableMessageCopy: true,
|
|
212
|
-
enableRegeneration: true,
|
|
213
|
-
enableToolCallsDisplay: true
|
|
214
|
-
},
|
|
215
|
-
ui: {
|
|
216
|
-
showTimestamps: true,
|
|
217
|
-
showAvatars: true,
|
|
218
|
-
compactMode: false,
|
|
219
|
-
showWordCount: true
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
customer_support: {
|
|
223
|
-
branding: {
|
|
224
|
-
title: "Customer Support",
|
|
225
|
-
subtitle: "How can I help you today?"
|
|
226
|
-
},
|
|
227
|
-
features: {
|
|
228
|
-
enableThreads: true,
|
|
229
|
-
enableFileUpload: true,
|
|
230
|
-
enableAudioRecording: false,
|
|
231
|
-
enableMessageEditing: false,
|
|
232
|
-
enableMessageCopy: true,
|
|
233
|
-
enableRegeneration: false,
|
|
234
|
-
enableToolCallsDisplay: false
|
|
235
|
-
},
|
|
236
|
-
ui: {
|
|
237
|
-
showTimestamps: true,
|
|
238
|
-
showAvatars: true,
|
|
239
|
-
compactMode: false
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
};
|
|
243
|
-
function validateConfig(config) {
|
|
244
|
-
const errors = [];
|
|
245
|
-
if (config.features?.maxAttachments && config.features.maxAttachments < 1) {
|
|
246
|
-
errors.push("maxAttachments must be at least 1");
|
|
247
|
-
}
|
|
248
|
-
if (config.features?.maxFileSize && config.features.maxFileSize < 1024) {
|
|
249
|
-
errors.push("maxFileSize must be at least 1024 bytes (1KB)");
|
|
250
|
-
}
|
|
251
|
-
if (config.branding?.title && typeof config.branding.title !== "string") {
|
|
252
|
-
errors.push("branding.title must be a string");
|
|
253
|
-
}
|
|
254
|
-
return errors;
|
|
255
|
-
}
|
|
256
|
-
var themeUtils = {
|
|
257
|
-
getSystemTheme: () => {
|
|
258
|
-
if (typeof globalThis.matchMedia === "undefined") return "light";
|
|
259
|
-
return globalThis.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
260
|
-
},
|
|
261
|
-
resolveTheme: (theme) => {
|
|
262
|
-
return theme === "auto" ? themeUtils.getSystemTheme() : theme;
|
|
263
|
-
},
|
|
264
|
-
applyTheme: (theme) => {
|
|
265
|
-
if (typeof document === "undefined") return;
|
|
266
|
-
const resolvedTheme = themeUtils.resolveTheme(theme);
|
|
267
|
-
document.documentElement.classList.toggle("dark", resolvedTheme === "dark");
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
var featureFlags = {
|
|
271
|
-
isEnabled: (config, feature) => {
|
|
272
|
-
return config.features[feature] === true;
|
|
273
|
-
},
|
|
274
|
-
getEnabledFeatures: (config) => {
|
|
275
|
-
return Object.entries(config.features).filter(([_, enabled]) => enabled === true).map(([feature]) => feature);
|
|
276
|
-
},
|
|
277
|
-
hasAnyFeature: (config, features) => {
|
|
278
|
-
return features.some((feature) => featureFlags.isEnabled(config, feature));
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
var configUtils = {
|
|
282
|
-
createConfigHook: (config) => {
|
|
283
|
-
return {
|
|
284
|
-
config,
|
|
285
|
-
isFeatureEnabled: (feature) => featureFlags.isEnabled(config, feature),
|
|
286
|
-
getLabel: (key) => config.labels[key],
|
|
287
|
-
getBranding: () => config.branding,
|
|
288
|
-
getUI: () => config.ui
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
171
|
|
|
293
172
|
// src/components/chat/Message.tsx
|
|
294
173
|
import React, { useState, useMemo, useEffect, memo } from "react";
|
|
@@ -3159,7 +3038,7 @@ var ChatHeader = ({
|
|
|
3159
3038
|
};
|
|
3160
3039
|
|
|
3161
3040
|
// src/components/chat/ChatInput.tsx
|
|
3162
|
-
import { useState as useState6, useRef as useRef5, useCallback as useCallback3, useEffect as useEffect9, memo as memo3 } from "react";
|
|
3041
|
+
import React11, { useState as useState6, useRef as useRef5, useCallback as useCallback3, useEffect as useEffect9, memo as memo3 } from "react";
|
|
3163
3042
|
|
|
3164
3043
|
// src/components/chat/UserContext.tsx
|
|
3165
3044
|
import { createContext as createContext2, useCallback as useCallback2, useContext as useContext2, useEffect as useEffect8, useMemo as useMemo4, useState as useState5 } from "react";
|
|
@@ -3766,6 +3645,29 @@ import {
|
|
|
3766
3645
|
Loader2 as Loader22
|
|
3767
3646
|
} from "lucide-react";
|
|
3768
3647
|
import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3648
|
+
function getActiveMentionMatch(value, caret) {
|
|
3649
|
+
const prefix = value.slice(0, caret);
|
|
3650
|
+
const match = /(^|\s)@([\w.-]*)$/.exec(prefix);
|
|
3651
|
+
if (!match) return null;
|
|
3652
|
+
const query = match[2] ?? "";
|
|
3653
|
+
return {
|
|
3654
|
+
start: prefix.length - query.length - 1,
|
|
3655
|
+
end: caret,
|
|
3656
|
+
query
|
|
3657
|
+
};
|
|
3658
|
+
}
|
|
3659
|
+
function resolveTargetFromMentions(value, agents) {
|
|
3660
|
+
const matches = value.matchAll(/(^|\s)@([\w.-]+)/g);
|
|
3661
|
+
for (const match of matches) {
|
|
3662
|
+
const mention = match[2]?.toLowerCase();
|
|
3663
|
+
if (!mention) continue;
|
|
3664
|
+
const agent = agents.find(
|
|
3665
|
+
(candidate) => candidate.id.toLowerCase() === mention || candidate.name.toLowerCase() === mention
|
|
3666
|
+
);
|
|
3667
|
+
if (agent) return agent;
|
|
3668
|
+
}
|
|
3669
|
+
return null;
|
|
3670
|
+
}
|
|
3769
3671
|
var FileUploadItem = memo3(function FileUploadItem2({ file, progress, onCancel }) {
|
|
3770
3672
|
const guessTypeFromName = (name) => {
|
|
3771
3673
|
const ext = (name || "").split(".").pop()?.toLowerCase();
|
|
@@ -4026,7 +3928,9 @@ var ChatInput = memo3(function ChatInput2({
|
|
|
4026
3928
|
// 10MB
|
|
4027
3929
|
acceptedFileTypes = ["image/*", "video/*", "audio/*"],
|
|
4028
3930
|
className = "",
|
|
4029
|
-
config
|
|
3931
|
+
config,
|
|
3932
|
+
mentionAgents = [],
|
|
3933
|
+
onTargetAgentChange
|
|
4030
3934
|
}) {
|
|
4031
3935
|
const voiceComposeEnabled = config?.voiceCompose?.enabled === true;
|
|
4032
3936
|
const voiceDefaultMode = config?.voiceCompose?.defaultMode ?? "text";
|
|
@@ -4051,6 +3955,8 @@ var ChatInput = memo3(function ChatInput2({
|
|
|
4051
3955
|
const [voiceCountdownMs, setVoiceCountdownMs] = useState6(0);
|
|
4052
3956
|
const [isVoiceAutoSendActive, setIsVoiceAutoSendActive] = useState6(false);
|
|
4053
3957
|
const [voiceError, setVoiceError] = useState6(null);
|
|
3958
|
+
const [activeMention, setActiveMention] = useState6(null);
|
|
3959
|
+
const [activeMentionIndex, setActiveMentionIndex] = useState6(0);
|
|
4054
3960
|
const textareaRef = useRef5(null);
|
|
4055
3961
|
const fileInputRef = useRef5(null);
|
|
4056
3962
|
const mediaRecorderRef = useRef5(null);
|
|
@@ -4061,6 +3967,35 @@ var ChatInput = memo3(function ChatInput2({
|
|
|
4061
3967
|
const voiceDraftRef = useRef5(null);
|
|
4062
3968
|
const voiceAppendBaseRef = useRef5(null);
|
|
4063
3969
|
const voiceAppendBaseDurationRef = useRef5(0);
|
|
3970
|
+
const filteredMentionAgents = React11.useMemo(() => {
|
|
3971
|
+
if (!activeMention || mentionAgents.length === 0) return [];
|
|
3972
|
+
const query = activeMention.query.trim().toLowerCase();
|
|
3973
|
+
const rank = (agent) => {
|
|
3974
|
+
const id = agent.id.toLowerCase();
|
|
3975
|
+
const name = agent.name.toLowerCase();
|
|
3976
|
+
if (!query) return 0;
|
|
3977
|
+
if (name.startsWith(query) || id.startsWith(query)) return 0;
|
|
3978
|
+
if (name.includes(query) || id.includes(query)) return 1;
|
|
3979
|
+
return 2;
|
|
3980
|
+
};
|
|
3981
|
+
return mentionAgents.filter((agent) => rank(agent) < 2).sort((left, right) => {
|
|
3982
|
+
const rankDiff = rank(left) - rank(right);
|
|
3983
|
+
if (rankDiff !== 0) return rankDiff;
|
|
3984
|
+
return left.name.localeCompare(right.name);
|
|
3985
|
+
}).slice(0, 6);
|
|
3986
|
+
}, [activeMention, mentionAgents]);
|
|
3987
|
+
const isMentionMenuOpen = filteredMentionAgents.length > 0;
|
|
3988
|
+
const syncMentionState = useCallback3((nextValue, nextCaret) => {
|
|
3989
|
+
const caret = typeof nextCaret === "number" ? nextCaret : textareaRef.current?.selectionStart ?? nextValue.length;
|
|
3990
|
+
const nextMatch = getActiveMentionMatch(nextValue, caret);
|
|
3991
|
+
setActiveMention((prev) => {
|
|
3992
|
+
if (prev?.start === nextMatch?.start && prev?.end === nextMatch?.end && prev?.query === nextMatch?.query) {
|
|
3993
|
+
return prev;
|
|
3994
|
+
}
|
|
3995
|
+
return nextMatch;
|
|
3996
|
+
});
|
|
3997
|
+
setActiveMentionIndex(0);
|
|
3998
|
+
}, []);
|
|
4064
3999
|
useEffect9(() => {
|
|
4065
4000
|
return () => {
|
|
4066
4001
|
if (mediaStreamRef.current) {
|
|
@@ -4078,14 +4013,70 @@ var ChatInput = memo3(function ChatInput2({
|
|
|
4078
4013
|
useEffect9(() => {
|
|
4079
4014
|
voiceDraftRef.current = voiceDraft;
|
|
4080
4015
|
}, [voiceDraft]);
|
|
4016
|
+
useEffect9(() => {
|
|
4017
|
+
if (!isMentionMenuOpen) {
|
|
4018
|
+
setActiveMentionIndex(0);
|
|
4019
|
+
return;
|
|
4020
|
+
}
|
|
4021
|
+
setActiveMentionIndex(
|
|
4022
|
+
(prev) => prev >= filteredMentionAgents.length ? 0 : prev
|
|
4023
|
+
);
|
|
4024
|
+
}, [filteredMentionAgents.length, isMentionMenuOpen]);
|
|
4025
|
+
const selectMentionAgent = useCallback3((agent) => {
|
|
4026
|
+
if (!activeMention) return;
|
|
4027
|
+
const replacement = `@${agent.name} `;
|
|
4028
|
+
const nextValue = value.slice(0, activeMention.start) + replacement + value.slice(activeMention.end);
|
|
4029
|
+
const nextCaret = activeMention.start + replacement.length;
|
|
4030
|
+
onChange(nextValue);
|
|
4031
|
+
onTargetAgentChange?.(agent.id);
|
|
4032
|
+
setActiveMention(null);
|
|
4033
|
+
setActiveMentionIndex(0);
|
|
4034
|
+
requestAnimationFrame(() => {
|
|
4035
|
+
textareaRef.current?.focus();
|
|
4036
|
+
textareaRef.current?.setSelectionRange(nextCaret, nextCaret);
|
|
4037
|
+
});
|
|
4038
|
+
}, [activeMention, onChange, onTargetAgentChange, value]);
|
|
4081
4039
|
const handleSubmit = (e) => {
|
|
4082
4040
|
e.preventDefault();
|
|
4083
4041
|
if (!value.trim() && attachments.length === 0 || disabled || isGenerating) return;
|
|
4042
|
+
const mentionedAgent = resolveTargetFromMentions(value, mentionAgents);
|
|
4043
|
+
if (mentionedAgent) {
|
|
4044
|
+
onTargetAgentChange?.(mentionedAgent.id);
|
|
4045
|
+
}
|
|
4084
4046
|
onSubmit(value.trim(), attachments);
|
|
4085
4047
|
onChange("");
|
|
4086
4048
|
onAttachmentsChange([]);
|
|
4049
|
+
setActiveMention(null);
|
|
4050
|
+
setActiveMentionIndex(0);
|
|
4087
4051
|
};
|
|
4088
4052
|
const handleKeyDown = (e) => {
|
|
4053
|
+
if (isMentionMenuOpen) {
|
|
4054
|
+
if (e.key === "ArrowDown") {
|
|
4055
|
+
e.preventDefault();
|
|
4056
|
+
setActiveMentionIndex(
|
|
4057
|
+
(prev) => prev >= filteredMentionAgents.length - 1 ? 0 : prev + 1
|
|
4058
|
+
);
|
|
4059
|
+
return;
|
|
4060
|
+
}
|
|
4061
|
+
if (e.key === "ArrowUp") {
|
|
4062
|
+
e.preventDefault();
|
|
4063
|
+
setActiveMentionIndex(
|
|
4064
|
+
(prev) => prev <= 0 ? filteredMentionAgents.length - 1 : prev - 1
|
|
4065
|
+
);
|
|
4066
|
+
return;
|
|
4067
|
+
}
|
|
4068
|
+
if ((e.key === "Enter" || e.key === "Tab") && filteredMentionAgents[activeMentionIndex]) {
|
|
4069
|
+
e.preventDefault();
|
|
4070
|
+
selectMentionAgent(filteredMentionAgents[activeMentionIndex]);
|
|
4071
|
+
return;
|
|
4072
|
+
}
|
|
4073
|
+
if (e.key === "Escape") {
|
|
4074
|
+
e.preventDefault();
|
|
4075
|
+
setActiveMention(null);
|
|
4076
|
+
setActiveMentionIndex(0);
|
|
4077
|
+
return;
|
|
4078
|
+
}
|
|
4079
|
+
}
|
|
4089
4080
|
if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey && window.innerWidth > 768) {
|
|
4090
4081
|
e.preventDefault();
|
|
4091
4082
|
handleSubmit(e);
|
|
@@ -4651,19 +4642,48 @@ var ChatInput = memo3(function ChatInput2({
|
|
|
4651
4642
|
/* @__PURE__ */ jsx23(TooltipContent, { children: config?.labels?.attachFileTooltip })
|
|
4652
4643
|
] })
|
|
4653
4644
|
] }),
|
|
4654
|
-
/* @__PURE__ */
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4645
|
+
/* @__PURE__ */ jsxs13("div", { className: "relative flex-1", children: [
|
|
4646
|
+
/* @__PURE__ */ jsx23(
|
|
4647
|
+
Textarea,
|
|
4648
|
+
{
|
|
4649
|
+
ref: textareaRef,
|
|
4650
|
+
value,
|
|
4651
|
+
onChange: (e) => {
|
|
4652
|
+
onChange(e.target.value);
|
|
4653
|
+
syncMentionState(e.target.value, e.target.selectionStart ?? e.target.value.length);
|
|
4654
|
+
},
|
|
4655
|
+
onSelect: (e) => {
|
|
4656
|
+
const target = e.target;
|
|
4657
|
+
syncMentionState(target.value, target.selectionStart ?? target.value.length);
|
|
4658
|
+
},
|
|
4659
|
+
onClick: (e) => {
|
|
4660
|
+
const target = e.target;
|
|
4661
|
+
syncMentionState(target.value, target.selectionStart ?? target.value.length);
|
|
4662
|
+
},
|
|
4663
|
+
onKeyDown: handleKeyDown,
|
|
4664
|
+
placeholder,
|
|
4665
|
+
disabled,
|
|
4666
|
+
className: "max-h-[120px] resize-none border-0 bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0",
|
|
4667
|
+
rows: 1
|
|
4668
|
+
}
|
|
4669
|
+
),
|
|
4670
|
+
isMentionMenuOpen && /* @__PURE__ */ jsx23("div", { className: "absolute bottom-full left-0 right-0 mb-2 overflow-hidden rounded-md border bg-popover shadow-md", children: /* @__PURE__ */ jsx23("div", { className: "p-1", children: filteredMentionAgents.map((agent, index) => /* @__PURE__ */ jsxs13(
|
|
4671
|
+
"button",
|
|
4672
|
+
{
|
|
4673
|
+
type: "button",
|
|
4674
|
+
className: `flex w-full items-center gap-2 rounded-sm px-3 py-2 text-left text-sm ${index === activeMentionIndex ? "bg-accent text-accent-foreground" : "hover:bg-accent/60"}`,
|
|
4675
|
+
onMouseDown: (mouseEvent) => {
|
|
4676
|
+
mouseEvent.preventDefault();
|
|
4677
|
+
selectMentionAgent(agent);
|
|
4678
|
+
},
|
|
4679
|
+
children: [
|
|
4680
|
+
/* @__PURE__ */ jsx23("span", { className: "font-medium", children: agent.name }),
|
|
4681
|
+
agent.description && /* @__PURE__ */ jsx23("span", { className: "truncate text-xs text-muted-foreground", children: agent.description })
|
|
4682
|
+
]
|
|
4683
|
+
},
|
|
4684
|
+
agent.id
|
|
4685
|
+
)) }) })
|
|
4686
|
+
] }),
|
|
4667
4687
|
enableAudioRecording && !isRecording && canAddMoreAttachments && !value.trim() && (voiceComposeEnabled ? /* @__PURE__ */ jsxs13(Tooltip, { children: [
|
|
4668
4688
|
/* @__PURE__ */ jsx23(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx23(
|
|
4669
4689
|
Button,
|
|
@@ -5205,6 +5225,16 @@ var UserProfile = ({
|
|
|
5205
5225
|
// src/components/chat/ChatUI.tsx
|
|
5206
5226
|
import { Sparkles, ArrowRight, MessageSquare, Lightbulb as Lightbulb2, Zap, HelpCircle } from "lucide-react";
|
|
5207
5227
|
import { jsx as jsx26, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
5228
|
+
function getMessageSpeakerKey(message) {
|
|
5229
|
+
if (!message) return null;
|
|
5230
|
+
if (message.role === "assistant") {
|
|
5231
|
+
return message.senderAgentId ?? message.senderName ?? "assistant";
|
|
5232
|
+
}
|
|
5233
|
+
if (message.role === "user") {
|
|
5234
|
+
return "user";
|
|
5235
|
+
}
|
|
5236
|
+
return message.role;
|
|
5237
|
+
}
|
|
5208
5238
|
var ChatUI = ({
|
|
5209
5239
|
messages = [],
|
|
5210
5240
|
threads = [],
|
|
@@ -5650,7 +5680,7 @@ var ChatUI = ({
|
|
|
5650
5680
|
children: virtualizer.getVirtualItems().map((virtualRow) => {
|
|
5651
5681
|
const message = messages[virtualRow.index];
|
|
5652
5682
|
const prevMessage = virtualRow.index > 0 ? messages[virtualRow.index - 1] : null;
|
|
5653
|
-
const isGrouped = prevMessage !== null && prevMessage.role === message.role;
|
|
5683
|
+
const isGrouped = prevMessage !== null && prevMessage.role === message.role && getMessageSpeakerKey(prevMessage) === getMessageSpeakerKey(message);
|
|
5654
5684
|
return /* @__PURE__ */ jsx26(
|
|
5655
5685
|
"div",
|
|
5656
5686
|
{
|
|
@@ -5716,7 +5746,9 @@ var ChatUI = ({
|
|
|
5716
5746
|
enableAudioRecording: config.features.enableAudioRecording,
|
|
5717
5747
|
maxAttachments: config.features.maxAttachments,
|
|
5718
5748
|
maxFileSize: config.features.maxFileSize,
|
|
5719
|
-
config
|
|
5749
|
+
config,
|
|
5750
|
+
mentionAgents: participantIds && participantIds.length > 0 ? agentOptions.filter((a) => participantIds.includes(a.id)) : agentOptions,
|
|
5751
|
+
onTargetAgentChange
|
|
5720
5752
|
}
|
|
5721
5753
|
)
|
|
5722
5754
|
] })
|
|
@@ -6066,19 +6098,14 @@ export {
|
|
|
6066
6098
|
UserMenu,
|
|
6067
6099
|
UserProfile,
|
|
6068
6100
|
assignAgentColors,
|
|
6069
|
-
chatConfigPresets,
|
|
6070
6101
|
chatUtils,
|
|
6071
6102
|
cn,
|
|
6072
|
-
configUtils,
|
|
6073
6103
|
createObjectUrlFromDataUrl,
|
|
6074
6104
|
defaultChatConfig,
|
|
6075
|
-
featureFlags,
|
|
6076
6105
|
formatDate,
|
|
6077
6106
|
getAgentColor,
|
|
6078
6107
|
getAgentInitials,
|
|
6079
6108
|
mergeConfig,
|
|
6080
|
-
|
|
6081
|
-
useChatUserContext,
|
|
6082
|
-
validateConfig
|
|
6109
|
+
useChatUserContext
|
|
6083
6110
|
};
|
|
6084
6111
|
//# sourceMappingURL=index.js.map
|