mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-24 04:10:15 +01:00
🧹 chore: pre-release cleanup 2 (#3600)
* refactor: scrollToEnd * fix(validateConvoAccess): search conversation by ID for proper validation * feat: Add unique index for conversationId and user in convoSchema * refactor: Update font sizes 1 rem -> font-size-base in style.css * fix: Assistants map type issues * refactor: Remove obsolete scripts * fix: Update DropdownNoState component to handle both string and OptionType values * refactor: Remove config/loader.js file * fix: remove crypto.randomBytes(); refactor: Create reusable function for generating token and hash
This commit is contained in:
parent
6fead1005b
commit
1ff4841603
20 changed files with 172 additions and 637 deletions
|
|
@ -31,10 +31,10 @@ export default function Landing({ Header }: { Header?: ReactNode }) {
|
|||
endpoint = getIconEndpoint({ endpointsConfig, iconURL, endpoint });
|
||||
|
||||
const isAssistant = isAssistantsEndpoint(endpoint);
|
||||
const assistant = isAssistant && assistantMap[endpoint][assistant_id ?? ''];
|
||||
const assistantName = (assistant && assistant.name) || '';
|
||||
const assistantDesc = (assistant && assistant.description) || '';
|
||||
const avatar = (assistant && (assistant.metadata?.avatar as string)) || '';
|
||||
const assistant = isAssistant ? assistantMap?.[endpoint][assistant_id ?? ''] : undefined;
|
||||
const assistantName = assistant && assistant.name;
|
||||
const assistantDesc = assistant && assistant.description;
|
||||
const avatar = assistant && (assistant.metadata?.avatar as string);
|
||||
|
||||
const containerClassName =
|
||||
'shadow-stroke relative flex h-full items-center justify-center rounded-full bg-white text-black';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import type { TMessageProps } from '~/common';
|
||||
import Icon from '~/components/Chat/Messages/MessageIcon';
|
||||
import { useMessageHelpers, useLocalize } from '~/hooks';
|
||||
import ContentParts from './Content/ContentParts';
|
||||
import SiblingSwitch from './SiblingSwitch';
|
||||
import { useMessageHelpers } from '~/hooks';
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import MultiMessage from './MultiMessage';
|
||||
import HoverButtons from './HoverButtons';
|
||||
|
|
@ -12,6 +12,7 @@ import { cn } from '~/utils';
|
|||
import store from '~/store';
|
||||
|
||||
export default function Message(props: TMessageProps) {
|
||||
const localize = useLocalize();
|
||||
const { message, siblingIdx, siblingCount, setSiblingIdx, currentEditId, setCurrentEditId } =
|
||||
props;
|
||||
|
||||
|
|
@ -31,7 +32,6 @@ export default function Message(props: TMessageProps) {
|
|||
regenerateMessage,
|
||||
} = useMessageHelpers(props);
|
||||
const fontSize = useRecoilValue(store.fontSize);
|
||||
|
||||
const { content, children, messageId = null, isCreatedByUser, error, unfinished } = message ?? {};
|
||||
|
||||
if (!message) {
|
||||
|
|
@ -59,12 +59,13 @@ export default function Message(props: TMessageProps) {
|
|||
<div
|
||||
className={cn(
|
||||
'relative flex w-full flex-col',
|
||||
isCreatedByUser != null ? '' : 'agent-turn',
|
||||
isCreatedByUser === true ? '' : 'agent-turn',
|
||||
)}
|
||||
>
|
||||
<div className={cn('select-none font-semibold', fontSize)}>
|
||||
{/* TODO: LOCALIZE */}
|
||||
{isCreatedByUser != null ? 'You' : (assistant && assistant.name) ?? 'Assistant'}
|
||||
{isCreatedByUser === true
|
||||
? localize('com_user_message')
|
||||
: (assistant && assistant.name) ?? localize('com_ui_assistant')}
|
||||
</div>
|
||||
<div className="flex-col gap-1 md:gap-3">
|
||||
<div className="flex max-w-full flex-grow flex-col gap-0">
|
||||
|
|
@ -76,7 +77,7 @@ export default function Message(props: TMessageProps) {
|
|||
message={message}
|
||||
messageId={messageId}
|
||||
enterEdit={enterEdit}
|
||||
error={!!error}
|
||||
error={!!(error ?? false)}
|
||||
isSubmitting={isSubmitting}
|
||||
unfinished={unfinished ?? false}
|
||||
isCreatedByUser={isCreatedByUser ?? true}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type {
|
||||
TAssistantsMap,
|
||||
|
|
@ -20,7 +21,7 @@ export default function ConvoIcon({
|
|||
}: {
|
||||
conversation: TConversation | TPreset | null;
|
||||
endpointsConfig: TEndpointsConfig;
|
||||
assistantMap: TAssistantsMap;
|
||||
assistantMap: TAssistantsMap | undefined;
|
||||
containerClassName?: string;
|
||||
context?: 'message' | 'nav' | 'landing' | 'menu-item';
|
||||
className?: string;
|
||||
|
|
@ -29,11 +30,19 @@ export default function ConvoIcon({
|
|||
const iconURL = conversation?.iconURL;
|
||||
let endpoint = conversation?.endpoint;
|
||||
endpoint = getIconEndpoint({ endpointsConfig, iconURL, endpoint });
|
||||
const assistant =
|
||||
isAssistantsEndpoint(endpoint) && assistantMap?.[endpoint]?.[conversation?.assistant_id ?? ''];
|
||||
const assistantName = (assistant && assistant?.name) || '';
|
||||
const assistant = useMemo(() => {
|
||||
if (!isAssistantsEndpoint(conversation?.endpoint)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const avatar = (assistant && (assistant?.metadata?.avatar as string)) || '';
|
||||
const endpointKey = conversation?.endpoint ?? '';
|
||||
const assistantId = conversation?.assistant_id ?? '';
|
||||
|
||||
return assistantMap?.[endpointKey] ? assistantMap[endpointKey][assistantId] : undefined;
|
||||
}, [conversation?.endpoint, conversation?.assistant_id, assistantMap]);
|
||||
const assistantName = assistant && (assistant.name ?? '');
|
||||
|
||||
const avatar = (assistant && (assistant.metadata?.avatar as string)) || '';
|
||||
const endpointIconURL = getEndpointField(endpointsConfig, endpoint, 'iconURL');
|
||||
const iconKey = getIconKey({ endpoint, endpointsConfig, endpointIconURL });
|
||||
const Icon = icons[iconKey];
|
||||
|
|
|
|||
|
|
@ -62,12 +62,12 @@ export default function ActionsInput({
|
|||
const [functions, setFunctions] = useState<FunctionTool[] | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!action?.metadata?.raw_spec) {
|
||||
if (!action?.metadata.raw_spec) {
|
||||
return;
|
||||
}
|
||||
setInputValue(action.metadata.raw_spec);
|
||||
debouncedValidation(action.metadata.raw_spec, handleResult);
|
||||
}, [action?.metadata?.raw_spec]);
|
||||
}, [action?.metadata.raw_spec]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!validationResult || !validationResult.status || !validationResult.spec) {
|
||||
|
|
@ -100,7 +100,7 @@ export default function ActionsInput({
|
|||
},
|
||||
onError(error) {
|
||||
showToast({
|
||||
message: (error as Error)?.message ?? localize('com_assistants_update_actions_error'),
|
||||
message: (error as Error).message ?? localize('com_assistants_update_actions_error'),
|
||||
status: 'error',
|
||||
});
|
||||
},
|
||||
|
|
@ -180,7 +180,7 @@ export default function ActionsInput({
|
|||
assistant_id,
|
||||
endpoint,
|
||||
version,
|
||||
model: assistantMap[endpoint][assistant_id].model,
|
||||
model: assistantMap?.[endpoint][assistant_id].model ?? '',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -195,16 +195,32 @@ export default function ActionsInput({
|
|||
debouncedValidation(newValue, handleResult);
|
||||
};
|
||||
|
||||
const submitContext = () => {
|
||||
if (updateAction.isLoading) {
|
||||
return <Spinner className="icon-md" />;
|
||||
} else if (action?.action_id.length ?? 0) {
|
||||
return localize('com_ui_update');
|
||||
} else {
|
||||
return localize('com_ui_create');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="">
|
||||
<div className="mb-1 flex flex-wrap items-center justify-between gap-4">
|
||||
<label className="text-token-text-primary whitespace-nowrap font-medium">Schema</label>
|
||||
<label
|
||||
htmlFor="example-schema"
|
||||
className="text-token-text-primary whitespace-nowrap font-medium"
|
||||
>
|
||||
Schema
|
||||
</label>
|
||||
<div className="flex items-center gap-2">
|
||||
{/* <button className="btn btn-neutral border-token-border-light relative h-8 min-w-[100px] rounded-lg font-medium">
|
||||
<div className="flex w-full items-center justify-center text-xs">Import from URL</div>
|
||||
</button> */}
|
||||
<select
|
||||
id="example-schema"
|
||||
onChange={(e) => console.log(e.target.value)}
|
||||
className="border-token-border-medium h-8 min-w-[100px] rounded-lg border bg-transparent px-2 py-0 text-sm"
|
||||
>
|
||||
|
|
@ -250,23 +266,15 @@ export default function ActionsInput({
|
|||
</div>
|
||||
)}
|
||||
<div className="mt-4">
|
||||
<div className="mb-1.5 flex items-center">
|
||||
<span className="" data-state="closed">
|
||||
<label className="text-token-text-primary block font-medium">
|
||||
{localize('com_ui_privacy_policy')}
|
||||
</label>
|
||||
</span>
|
||||
</div>
|
||||
<div className="rounded-md border border-gray-300 px-3 py-2 shadow-none focus-within:border-gray-800 focus-within:ring-1 focus-within:ring-gray-800 dark:border-gray-700 dark:bg-gray-700 dark:focus-within:border-gray-500 dark:focus-within:ring-gray-500">
|
||||
<label
|
||||
htmlFor="privacyPolicyUrl"
|
||||
className="block text-xs font-medium text-gray-900 dark:text-gray-100"
|
||||
/>
|
||||
<label htmlFor="privacyPolicyUrl" className="block text-xs text-text-secondary">
|
||||
Privacy Policy URL
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
name="privacyPolicyUrl"
|
||||
id="privacyPolicyUrl"
|
||||
className="block w-full border-0 p-0 text-gray-900 placeholder-gray-500 shadow-none outline-none focus-within:shadow-none focus-within:outline-none focus-within:ring-0 focus:border-none focus:ring-0 dark:bg-gray-700 dark:text-gray-100 sm:text-sm"
|
||||
className="block w-full border-0 bg-transparent p-0 placeholder-text-secondary shadow-none outline-none focus-within:shadow-none focus-within:outline-none focus-within:ring-0 focus:border-none focus:ring-0 sm:text-sm"
|
||||
placeholder="https://api.example-weather-app.com/privacy"
|
||||
// value=""
|
||||
/>
|
||||
|
|
@ -280,13 +288,7 @@ export default function ActionsInput({
|
|||
className="focus:shadow-outline mt-1 flex min-w-[100px] items-center justify-center rounded bg-green-500 px-4 py-2 font-semibold text-white hover:bg-green-400 focus:border-green-500 focus:outline-none focus:ring-0 disabled:bg-green-400"
|
||||
type="button"
|
||||
>
|
||||
{updateAction.isLoading ? (
|
||||
<Spinner className="icon-md" />
|
||||
) : action?.action_id ? (
|
||||
localize('com_ui_update')
|
||||
) : (
|
||||
localize('com_ui_create')
|
||||
)}
|
||||
{submitContext()}
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ function Avatar({
|
|||
const { showToast } = useToastContext();
|
||||
|
||||
const activeModel = useMemo(() => {
|
||||
return assistantsMap[endpoint][assistant_id ?? '']?.model ?? '';
|
||||
return assistantsMap?.[endpoint][assistant_id ?? '']?.model ?? '';
|
||||
}, [assistantsMap, endpoint, assistant_id]);
|
||||
|
||||
const { mutate: uploadAvatar } = useUploadAssistantAvatarMutation({
|
||||
|
|
@ -59,7 +59,7 @@ function Avatar({
|
|||
setProgress(0.4);
|
||||
},
|
||||
onSuccess: (data, vars) => {
|
||||
if (!vars.postCreation) {
|
||||
if (vars.postCreation !== true) {
|
||||
showToast({ message: localize('com_ui_upload_success') });
|
||||
} else if (lastSeenCreatedId.current !== createMutation.data?.id) {
|
||||
lastSeenCreatedId.current = createMutation.data?.id ?? '';
|
||||
|
|
@ -136,9 +136,9 @@ function Avatar({
|
|||
createMutation.isSuccess &&
|
||||
input &&
|
||||
previewUrl &&
|
||||
previewUrl?.includes('base64')
|
||||
previewUrl.includes('base64')
|
||||
);
|
||||
if (sharedUploadCondition && lastSeenCreatedId.current === createMutation.data?.id) {
|
||||
if (sharedUploadCondition && lastSeenCreatedId.current === createMutation.data.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -149,8 +149,8 @@ function Avatar({
|
|||
formData.append('file', input, input.name);
|
||||
formData.append('assistant_id', createMutation.data.id);
|
||||
|
||||
if (typeof createMutation.data?.metadata === 'object') {
|
||||
formData.append('metadata', JSON.stringify(createMutation.data?.metadata));
|
||||
if (typeof createMutation.data.metadata === 'object') {
|
||||
formData.append('metadata', JSON.stringify(createMutation.data.metadata));
|
||||
}
|
||||
|
||||
uploadAvatar({
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ export default function AssistantPanel({
|
|||
const error = err as Error;
|
||||
showToast({
|
||||
message: `${localize('com_assistants_update_error')}${
|
||||
error?.message ? ` ${localize('com_ui_error')}: ${error?.message}` : ''
|
||||
error.message ? ` ${localize('com_ui_error')}: ${error.message}` : ''
|
||||
}`,
|
||||
status: 'error',
|
||||
});
|
||||
|
|
@ -119,7 +119,7 @@ export default function AssistantPanel({
|
|||
const error = err as Error;
|
||||
showToast({
|
||||
message: `${localize('com_assistants_create_error')}${
|
||||
error?.message ? ` ${localize('com_ui_error')}: ${error?.message}` : ''
|
||||
error.message ? ` ${localize('com_ui_error')}: ${error.message}` : ''
|
||||
}`,
|
||||
status: 'error',
|
||||
});
|
||||
|
|
@ -139,7 +139,7 @@ export default function AssistantPanel({
|
|||
return functionName;
|
||||
} else {
|
||||
const assistant = assistantMap?.[endpoint]?.[assistant_id];
|
||||
const tool = assistant?.tools?.find((tool) => tool.function?.name === functionName);
|
||||
const tool = assistant?.tools.find((tool) => tool.function?.name === functionName);
|
||||
if (assistant && tool) {
|
||||
return tool;
|
||||
}
|
||||
|
|
@ -193,6 +193,16 @@ export default function AssistantPanel({
|
|||
});
|
||||
};
|
||||
|
||||
let submitContext: string | JSX.Element;
|
||||
|
||||
if (create.isLoading || update.isLoading) {
|
||||
submitContext = <Spinner className="icon-md" />;
|
||||
} else if (assistant_id) {
|
||||
submitContext = localize('com_ui_save');
|
||||
} else {
|
||||
submitContext = localize('com_ui_create');
|
||||
}
|
||||
|
||||
return (
|
||||
<FormProvider {...methods}>
|
||||
<form
|
||||
|
|
@ -235,7 +245,7 @@ export default function AssistantPanel({
|
|||
<AssistantAvatar
|
||||
createMutation={create}
|
||||
assistant_id={assistant_id ?? null}
|
||||
metadata={assistant?.['metadata'] ?? null}
|
||||
metadata={assistant['metadata'] ?? null}
|
||||
endpoint={endpoint}
|
||||
version={version}
|
||||
/>
|
||||
|
|
@ -425,13 +435,7 @@ export default function AssistantPanel({
|
|||
className="btn btn-primary focus:shadow-outline flex w-full items-center justify-center px-4 py-2 font-semibold text-white hover:bg-green-600 focus:border-green-500"
|
||||
type="submit"
|
||||
>
|
||||
{create.isLoading || update.isLoading ? (
|
||||
<Spinner className="icon-md" />
|
||||
) : assistant_id ? (
|
||||
localize('com_ui_save')
|
||||
) : (
|
||||
localize('com_ui_create')
|
||||
)}
|
||||
{submitContext}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export default function ContextButton({
|
|||
createMutation,
|
||||
endpoint,
|
||||
}: {
|
||||
activeModel: string;
|
||||
activeModel?: string;
|
||||
assistant_id: string;
|
||||
setCurrentAssistantId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
createMutation: UseMutationResult<Assistant, Error, AssistantCreateParams>;
|
||||
|
|
@ -38,7 +38,7 @@ export default function ContextButton({
|
|||
status: 'success',
|
||||
});
|
||||
|
||||
if (createMutation.data?.id) {
|
||||
if (createMutation.data?.id !== undefined) {
|
||||
console.log('[deleteAssistant] resetting createMutation');
|
||||
createMutation.reset();
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ export default function ContextButton({
|
|||
return setOption('assistant_id')(firstAssistant.id);
|
||||
}
|
||||
|
||||
const currentAssistant = updatedList?.find(
|
||||
const currentAssistant = updatedList.find(
|
||||
(assistant) => assistant.id === conversation?.assistant_id,
|
||||
);
|
||||
|
||||
|
|
@ -75,6 +75,10 @@ export default function ContextButton({
|
|||
return null;
|
||||
}
|
||||
|
||||
if (activeModel?.length === 0 || activeModel === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ type OptionType = {
|
|||
};
|
||||
|
||||
interface DropdownProps {
|
||||
value: string;
|
||||
value: string | OptionType;
|
||||
label?: string;
|
||||
onChange: (value: string) => void;
|
||||
onChange: (value: string) => void | ((value: OptionType) => void);
|
||||
options: (string | OptionType)[];
|
||||
className?: string;
|
||||
anchor?: AnchorPropsWithSelection;
|
||||
|
|
@ -35,14 +35,19 @@ const Dropdown: FC<DropdownProps> = ({
|
|||
sizeClasses,
|
||||
testId = 'dropdown-menu',
|
||||
}) => {
|
||||
const getValue = (option: string | OptionType): string =>
|
||||
typeof option === 'string' ? option : option.value;
|
||||
|
||||
const getDisplay = (option: string | OptionType): string =>
|
||||
typeof option === 'string' ? option : (option.display ?? '') || option.value;
|
||||
|
||||
const selectedOption = options.find((option) => getValue(option) === getValue(value));
|
||||
|
||||
const displayValue = selectedOption != null ? getDisplay(selectedOption) : getDisplay(value);
|
||||
|
||||
return (
|
||||
<div className={cn('relative', className)}>
|
||||
<Listbox
|
||||
value={value}
|
||||
onChange={(newValue) => {
|
||||
onChange(newValue);
|
||||
}}
|
||||
>
|
||||
<Listbox value={value} onChange={onChange}>
|
||||
<div className={cn('relative', className)}>
|
||||
<ListboxButton
|
||||
data-testid={testId}
|
||||
|
|
@ -55,9 +60,7 @@ const Dropdown: FC<DropdownProps> = ({
|
|||
>
|
||||
<span className="block truncate">
|
||||
{label}
|
||||
{options
|
||||
.map((o) => (typeof o === 'string' ? { value: o, display: o } : o))
|
||||
.find((o) => o.value === value)?.display || value}
|
||||
{displayValue}
|
||||
</span>
|
||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<svg
|
||||
|
|
@ -79,7 +82,7 @@ const Dropdown: FC<DropdownProps> = ({
|
|||
>
|
||||
<ListboxOptions
|
||||
className={cn(
|
||||
'absolute z-50 mt-1 flex flex-col items-start gap-1 overflow-auto rounded-lg border border-gray-300 bg-white bg-white p-1.5 text-gray-700 shadow-lg transition-opacity focus:outline-none dark:border-gray-600 dark:bg-gray-700 dark:text-white',
|
||||
'absolute z-50 mt-1 flex flex-col items-start gap-1 overflow-auto rounded-lg border border-gray-300 bg-white p-1.5 text-gray-700 shadow-lg transition-opacity focus:outline-none dark:border-gray-600 dark:bg-gray-700 dark:text-white',
|
||||
sizeClasses,
|
||||
className,
|
||||
)}
|
||||
|
|
@ -89,17 +92,15 @@ const Dropdown: FC<DropdownProps> = ({
|
|||
{options.map((item, index) => (
|
||||
<ListboxOption
|
||||
key={index}
|
||||
value={typeof item === 'string' ? item : item.value}
|
||||
value={item}
|
||||
className={cn(
|
||||
'relative cursor-pointer select-none rounded border-gray-300 bg-white py-2.5 pl-3 pr-3 text-sm text-gray-700 hover:bg-gray-100 dark:border-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600',
|
||||
)}
|
||||
style={{ width: '100%' }}
|
||||
data-theme={typeof item === 'string' ? item : (item as OptionType).value}
|
||||
data-theme={getValue(item)}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<span className="block truncate">
|
||||
{typeof item === 'string' ? item : (item as OptionType).display}
|
||||
</span>
|
||||
<span className="block truncate">{getDisplay(item)}</span>
|
||||
</div>
|
||||
</ListboxOption>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export default function useAssistantsMap({
|
|||
isAuthenticated,
|
||||
}: {
|
||||
isAuthenticated: boolean;
|
||||
}): TAssistantsMap {
|
||||
}): TAssistantsMap | undefined {
|
||||
const { data: assistants = {} } = useListAssistantsQuery(EModelEndpoint.assistants, undefined, {
|
||||
select: (res) => mapAssistants(res.data),
|
||||
enabled: isAuthenticated,
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export default function useMessageActions(props: TMessageActions) {
|
|||
} = useChatContext();
|
||||
const { conversation: addedConvo, isSubmitting: isSubmittingAdditional } = useAddedChatContext();
|
||||
const conversation = useMemo(
|
||||
() => (isMultiMessage ? addedConvo : rootConvo),
|
||||
() => (isMultiMessage === true ? addedConvo : rootConvo),
|
||||
[isMultiMessage, addedConvo, rootConvo],
|
||||
);
|
||||
const assistantMap = useAssistantsMapContext();
|
||||
|
|
@ -41,24 +41,28 @@ export default function useMessageActions(props: TMessageActions) {
|
|||
const edit = useMemo(() => messageId === currentEditId, [messageId, currentEditId]);
|
||||
|
||||
const enterEdit = useCallback(
|
||||
(cancel?: boolean) => setCurrentEditId && setCurrentEditId(cancel ? -1 : messageId),
|
||||
(cancel?: boolean) => setCurrentEditId && setCurrentEditId(cancel === true ? -1 : messageId),
|
||||
[messageId, setCurrentEditId],
|
||||
);
|
||||
|
||||
const assistant = useMemo(
|
||||
() =>
|
||||
isAssistantsEndpoint(conversation?.endpoint) &&
|
||||
assistantMap?.[conversation?.endpoint ?? '']?.[message?.model ?? ''],
|
||||
[assistantMap, conversation?.endpoint, message?.model],
|
||||
);
|
||||
const assistant = useMemo(() => {
|
||||
if (!isAssistantsEndpoint(conversation?.endpoint)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const endpointKey = conversation?.endpoint ?? '';
|
||||
const modelKey = message?.model ?? '';
|
||||
|
||||
return assistantMap?.[endpointKey] ? assistantMap[endpointKey][modelKey] : undefined;
|
||||
}, [conversation?.endpoint, message?.model, assistantMap]);
|
||||
|
||||
const isSubmitting = useMemo(
|
||||
() => (isMultiMessage ? isSubmittingAdditional : isSubmittingRoot),
|
||||
() => (isMultiMessage === true ? isSubmittingAdditional : isSubmittingRoot),
|
||||
[isMultiMessage, isSubmittingAdditional, isSubmittingRoot],
|
||||
);
|
||||
|
||||
const regenerateMessage = useCallback(() => {
|
||||
if ((isSubmitting && isCreatedByUser) || !message) {
|
||||
if ((isSubmitting && isCreatedByUser === true) || !message) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -68,8 +72,8 @@ export default function useMessageActions(props: TMessageActions) {
|
|||
const copyToClipboard = useCopyToClipboard({ text, content });
|
||||
|
||||
const messageLabel = useMemo(() => {
|
||||
if (message?.isCreatedByUser) {
|
||||
return UsernameDisplay ? user?.name || user?.username : localize('com_user_message');
|
||||
if (message?.isCreatedByUser === true) {
|
||||
return UsernameDisplay ? user?.name != null || user?.username : localize('com_user_message');
|
||||
} else if (assistant) {
|
||||
return assistant.name ?? 'Assistant';
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useRef, useCallback } from 'react';
|
||||
import { useEffect, useRef, useCallback, useMemo } from 'react';
|
||||
import { Constants, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type { TMessageProps } from '~/common';
|
||||
import { useChatContext, useAssistantsMapContext } from '~/Providers';
|
||||
|
|
@ -24,7 +24,7 @@ export default function useMessageHelpers(props: TMessageProps) {
|
|||
|
||||
const { text, content, children, messageId = null, isCreatedByUser } = message ?? {};
|
||||
const edit = messageId === currentEditId;
|
||||
const isLast = !children?.length;
|
||||
const isLast = children?.length === 0 || children?.length === undefined;
|
||||
|
||||
useEffect(() => {
|
||||
const convoId = conversation?.conversationId;
|
||||
|
|
@ -44,7 +44,7 @@ export default function useMessageHelpers(props: TMessageProps) {
|
|||
const logInfo = {
|
||||
textKey,
|
||||
'latestText.current': latestText.current,
|
||||
messageId: message?.messageId,
|
||||
messageId: message.messageId,
|
||||
convoId,
|
||||
};
|
||||
if (
|
||||
|
|
@ -60,7 +60,7 @@ export default function useMessageHelpers(props: TMessageProps) {
|
|||
}, [isLast, message, setLatestMessage, conversation?.conversationId]);
|
||||
|
||||
const enterEdit = useCallback(
|
||||
(cancel?: boolean) => setCurrentEditId && setCurrentEditId(cancel ? -1 : messageId),
|
||||
(cancel?: boolean) => setCurrentEditId && setCurrentEditId(cancel === true ? -1 : messageId),
|
||||
[messageId, setCurrentEditId],
|
||||
);
|
||||
|
||||
|
|
@ -72,12 +72,19 @@ export default function useMessageHelpers(props: TMessageProps) {
|
|||
}
|
||||
}, [isSubmitting, setAbortScroll]);
|
||||
|
||||
const assistant =
|
||||
isAssistantsEndpoint(conversation?.endpoint) &&
|
||||
assistantMap?.[conversation?.endpoint ?? '']?.[message?.model ?? ''];
|
||||
const assistant = useMemo(() => {
|
||||
if (!isAssistantsEndpoint(conversation?.endpoint)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const endpointKey = conversation?.endpoint ?? '';
|
||||
const modelKey = message?.model ?? '';
|
||||
|
||||
return assistantMap?.[endpointKey] ? assistantMap[endpointKey][modelKey] : undefined;
|
||||
}, [conversation?.endpoint, message?.model, assistantMap]);
|
||||
|
||||
const regenerateMessage = () => {
|
||||
if ((isSubmitting && isCreatedByUser) || !message) {
|
||||
if ((isSubmitting && isCreatedByUser === true) || !message) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2217,31 +2217,31 @@ ol ol):not(:where([class~=not-prose] *)) {
|
|||
}
|
||||
|
||||
.message-content {
|
||||
font-size: var(--markdown-font-size, 1rem);
|
||||
font-size: var(--markdown-font-size, var(--font-size-base));
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.message-content pre code {
|
||||
font-size: calc(0.85 * var(--markdown-font-size, 1rem));
|
||||
font-size: calc(0.85 * var(--markdown-font-size, var(--font-size-base)));
|
||||
}
|
||||
|
||||
.message-content pre {
|
||||
font-size: var(--markdown-font-size, 1rem);
|
||||
font-size: var(--markdown-font-size, var(--font-size-base));
|
||||
}
|
||||
|
||||
.code-analyze-block pre code,
|
||||
.code-analyze-block .overflow-y-auto code {
|
||||
font-size: calc(0.85 * var(--markdown-font-size, 1rem));
|
||||
font-size: calc(0.85 * var(--markdown-font-size, var(--font-size-base)));
|
||||
}
|
||||
|
||||
.code-analyze-block pre,
|
||||
.code-analyze-block .overflow-y-auto {
|
||||
font-size: var(--markdown-font-size, 1rem);
|
||||
font-size: var(--markdown-font-size, var(--font-size-base));
|
||||
}
|
||||
|
||||
.progress-text-wrapper {
|
||||
font-size: var(--markdown-font-size, 1rem);
|
||||
line-height: calc(1.25 * var(--markdown-font-size, 1rem));
|
||||
font-size: var(--markdown-font-size, var(--font-size-base));
|
||||
line-height: calc(1.25 * var(--markdown-font-size, var(--font-size-base)));
|
||||
}
|
||||
|
||||
.progress-text-content {
|
||||
|
|
|
|||
|
|
@ -45,10 +45,8 @@ export const getTextKey = (message?: TMessage | null, convoId?: string | null) =
|
|||
};
|
||||
|
||||
export const scrollToEnd = () => {
|
||||
setTimeout(() => {
|
||||
const messagesEndElement = document.getElementById('messages-end');
|
||||
if (messagesEndElement) {
|
||||
messagesEndElement.scrollIntoView({ behavior: 'instant' });
|
||||
}
|
||||
}, 750);
|
||||
const messagesEndElement = document.getElementById('messages-end');
|
||||
if (messagesEndElement) {
|
||||
messagesEndElement.scrollIntoView({ behavior: 'instant' });
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue