@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/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, chatConfigPresets, chatUtils, cn, configUtils, createObjectUrlFromDataUrl, defaultChatConfig, featureFlags, formatDate, getAgentColor, getAgentInitials, mergeConfig, themeUtils, useChatUserContext, validateConfig };
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, chatConfigPresets, chatUtils, cn, configUtils, createObjectUrlFromDataUrl, defaultChatConfig, featureFlags, formatDate, getAgentColor, getAgentInitials, mergeConfig, themeUtils, useChatUserContext, validateConfig };
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__ */ jsx23("div", { className: "flex-1", children: /* @__PURE__ */ jsx23(
4655
- Textarea,
4656
- {
4657
- ref: textareaRef,
4658
- value,
4659
- onChange: (e) => onChange(e.target.value),
4660
- onKeyDown: handleKeyDown,
4661
- placeholder,
4662
- disabled,
4663
- className: "max-h-[120px] resize-none border-0 bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0",
4664
- rows: 1
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
- themeUtils,
6081
- useChatUserContext,
6082
- validateConfig
6109
+ useChatUserContext
6083
6110
  };
6084
6111
  //# sourceMappingURL=index.js.map