mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
✨ feat: Add Google Parameters, Ollama/Openrouter Reasoning, & UI Optimizations (#5456)
* feat: Google Model Parameters * fix: dynamic input number value, previously coerced by zod schema * refactor: support openrouter reasoning tokens and XML for thinking directive to conform to ollama * fix: virtualize combobox to prevent performance drop on re-renders of long model/agent/assistant lists * refactor: simplify Fork component by removing unnecessary chat context index * fix: prevent rendering of Thinking component when children are null * refactor: update Markdown component to replace <think> tags and simplify remarkPlugins configuration * refactor: reorder remarkPlugins to improve plugin configuration in Markdown component
This commit is contained in:
parent
7818ae5c60
commit
af430e46f4
12 changed files with 200 additions and 50 deletions
|
|
@ -1253,6 +1253,12 @@ ${convo}
|
||||||
delete modelOptions.stop;
|
delete modelOptions.stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let reasoningKey = 'reasoning_content';
|
||||||
|
if (this.useOpenRouter) {
|
||||||
|
modelOptions.include_reasoning = true;
|
||||||
|
reasoningKey = 'reasoning';
|
||||||
|
}
|
||||||
|
|
||||||
if (modelOptions.stream) {
|
if (modelOptions.stream) {
|
||||||
streamPromise = new Promise((resolve) => {
|
streamPromise = new Promise((resolve) => {
|
||||||
streamResolve = resolve;
|
streamResolve = resolve;
|
||||||
|
|
@ -1291,14 +1297,14 @@ ${convo}
|
||||||
|
|
||||||
let reasoningCompleted = false;
|
let reasoningCompleted = false;
|
||||||
for await (const chunk of stream) {
|
for await (const chunk of stream) {
|
||||||
if (chunk?.choices?.[0]?.delta?.reasoning_content) {
|
if (chunk?.choices?.[0]?.delta?.[reasoningKey]) {
|
||||||
if (reasoningTokens.length === 0) {
|
if (reasoningTokens.length === 0) {
|
||||||
const thinkingDirective = ':::thinking\n';
|
const thinkingDirective = '<think>\n';
|
||||||
intermediateReply.push(thinkingDirective);
|
intermediateReply.push(thinkingDirective);
|
||||||
reasoningTokens.push(thinkingDirective);
|
reasoningTokens.push(thinkingDirective);
|
||||||
onProgress(thinkingDirective);
|
onProgress(thinkingDirective);
|
||||||
}
|
}
|
||||||
const reasoning_content = chunk?.choices?.[0]?.delta?.reasoning_content || '';
|
const reasoning_content = chunk?.choices?.[0]?.delta?.[reasoningKey] || '';
|
||||||
intermediateReply.push(reasoning_content);
|
intermediateReply.push(reasoning_content);
|
||||||
reasoningTokens.push(reasoning_content);
|
reasoningTokens.push(reasoning_content);
|
||||||
onProgress(reasoning_content);
|
onProgress(reasoning_content);
|
||||||
|
|
@ -1307,7 +1313,7 @@ ${convo}
|
||||||
const token = chunk?.choices?.[0]?.delta?.content || '';
|
const token = chunk?.choices?.[0]?.delta?.content || '';
|
||||||
if (!reasoningCompleted && reasoningTokens.length > 0 && token) {
|
if (!reasoningCompleted && reasoningTokens.length > 0 && token) {
|
||||||
reasoningCompleted = true;
|
reasoningCompleted = true;
|
||||||
const separatorTokens = '\n:::\n';
|
const separatorTokens = '\n</think>\n';
|
||||||
reasoningTokens.push(separatorTokens);
|
reasoningTokens.push(separatorTokens);
|
||||||
onProgress(separatorTokens);
|
onProgress(separatorTokens);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@
|
||||||
"react-speech-recognition": "^3.10.0",
|
"react-speech-recognition": "^3.10.0",
|
||||||
"react-textarea-autosize": "^8.4.0",
|
"react-textarea-autosize": "^8.4.0",
|
||||||
"react-transition-group": "^4.4.5",
|
"react-transition-group": "^4.4.5",
|
||||||
|
"react-virtualized": "^9.22.6",
|
||||||
"recoil": "^0.7.7",
|
"recoil": "^0.7.7",
|
||||||
"regenerator-runtime": "^0.14.1",
|
"regenerator-runtime": "^0.14.1",
|
||||||
"rehype-highlight": "^6.0.0",
|
"rehype-highlight": "^6.0.0",
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,10 @@ const Thinking = ({ children }: ThinkingProps) => {
|
||||||
setIsExpanded(!isExpanded);
|
setIsExpanded(!isExpanded);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (children == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -157,13 +157,13 @@ type TContentProps = {
|
||||||
|
|
||||||
const Markdown = memo(({ content = '', showCursor, isLatestMessage }: TContentProps) => {
|
const Markdown = memo(({ content = '', showCursor, isLatestMessage }: TContentProps) => {
|
||||||
const LaTeXParsing = useRecoilValue<boolean>(store.LaTeXParsing);
|
const LaTeXParsing = useRecoilValue<boolean>(store.LaTeXParsing);
|
||||||
const codeArtifacts = useRecoilValue<boolean>(store.codeArtifacts);
|
|
||||||
|
|
||||||
const isInitializing = content === '';
|
const isInitializing = content === '';
|
||||||
|
|
||||||
let currentContent = content;
|
let currentContent = content;
|
||||||
if (!isInitializing) {
|
if (!isInitializing) {
|
||||||
currentContent = currentContent.replace('z-index: 1;', '') || '';
|
currentContent = currentContent.replace('<think>', ':::thinking') || '';
|
||||||
|
currentContent = currentContent.replace('</think>', ':::') || '';
|
||||||
currentContent = LaTeXParsing ? preprocessLaTeX(currentContent) : currentContent;
|
currentContent = LaTeXParsing ? preprocessLaTeX(currentContent) : currentContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,15 +189,13 @@ const Markdown = memo(({ content = '', showCursor, isLatestMessage }: TContentPr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const remarkPlugins: Pluggable[] = codeArtifacts
|
const remarkPlugins: Pluggable[] = [
|
||||||
? [
|
supersub,
|
||||||
supersub,
|
remarkGfm,
|
||||||
remarkGfm,
|
remarkDirective,
|
||||||
[remarkMath, { singleDollarTextMath: true }],
|
artifactPlugin,
|
||||||
remarkDirective,
|
[remarkMath, { singleDollarTextMath: true }],
|
||||||
artifactPlugin,
|
];
|
||||||
]
|
|
||||||
: [supersub, remarkGfm, [remarkMath, { singleDollarTextMath: true }]];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ArtifactProvider>
|
<ArtifactProvider>
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ import {
|
||||||
HoverCardContent,
|
HoverCardContent,
|
||||||
} from '~/components/ui';
|
} from '~/components/ui';
|
||||||
import OptionHover from '~/components/SidePanel/Parameters/OptionHover';
|
import OptionHover from '~/components/SidePanel/Parameters/OptionHover';
|
||||||
import { useToastContext, useChatContext } from '~/Providers';
|
|
||||||
import { useLocalize, useNavigateToConvo } from '~/hooks';
|
import { useLocalize, useNavigateToConvo } from '~/hooks';
|
||||||
import { useForkConvoMutation } from '~/data-provider';
|
import { useForkConvoMutation } from '~/data-provider';
|
||||||
|
import { useToastContext } from '~/Providers';
|
||||||
import { ESide } from '~/common';
|
import { ESide } from '~/common';
|
||||||
import { cn } from '~/utils';
|
import { cn } from '~/utils';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
@ -112,10 +112,9 @@ export default function Fork({
|
||||||
latestMessageId?: string;
|
latestMessageId?: string;
|
||||||
}) {
|
}) {
|
||||||
const localize = useLocalize();
|
const localize = useLocalize();
|
||||||
const { index } = useChatContext();
|
|
||||||
const { showToast } = useToastContext();
|
const { showToast } = useToastContext();
|
||||||
const [remember, setRemember] = useState(false);
|
const [remember, setRemember] = useState(false);
|
||||||
const { navigateToConvo } = useNavigateToConvo(index);
|
const { navigateToConvo } = useNavigateToConvo();
|
||||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
const [forkSetting, setForkSetting] = useRecoilState(store.forkSetting);
|
const [forkSetting, setForkSetting] = useRecoilState(store.forkSetting);
|
||||||
const [activeSetting, setActiveSetting] = useState(optionLabels.default);
|
const [activeSetting, setActiveSetting] = useState(optionLabels.default);
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ import { OptionTypes } from 'librechat-data-provider';
|
||||||
import type { DynamicSettingProps } from 'librechat-data-provider';
|
import type { DynamicSettingProps } from 'librechat-data-provider';
|
||||||
import { useLocalize, useDebouncedInput, useParameterEffects } from '~/hooks';
|
import { useLocalize, useDebouncedInput, useParameterEffects } from '~/hooks';
|
||||||
import { Label, Input, HoverCard, HoverCardTrigger } from '~/components/ui';
|
import { Label, Input, HoverCard, HoverCardTrigger } from '~/components/ui';
|
||||||
import { cn, defaultTextProps } from '~/utils';
|
|
||||||
import { useChatContext } from '~/Providers';
|
import { useChatContext } from '~/Providers';
|
||||||
import OptionHover from './OptionHover';
|
import OptionHover from './OptionHover';
|
||||||
import { ESide } from '~/common';
|
import { ESide } from '~/common';
|
||||||
|
import { cn } from '~/utils';
|
||||||
|
|
||||||
function DynamicInput({
|
function DynamicInput({
|
||||||
label = '',
|
label = '',
|
||||||
|
|
@ -50,7 +50,7 @@ function DynamicInput({
|
||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
if (type === 'number') {
|
if (type === 'number') {
|
||||||
if (!isNaN(Number(value))) {
|
if (!isNaN(Number(value))) {
|
||||||
setInputValue(e);
|
setInputValue(e, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setInputValue(e);
|
setInputValue(e);
|
||||||
|
|
@ -70,7 +70,7 @@ function DynamicInput({
|
||||||
htmlFor={`${settingKey}-dynamic-input`}
|
htmlFor={`${settingKey}-dynamic-input`}
|
||||||
className="text-left text-sm font-medium"
|
className="text-left text-sm font-medium"
|
||||||
>
|
>
|
||||||
{labelCode ? localize(label) ?? label : label || settingKey}{' '}
|
{labelCode ? localize(label) || label : label || settingKey}{' '}
|
||||||
{showDefault && (
|
{showDefault && (
|
||||||
<small className="opacity-40">
|
<small className="opacity-40">
|
||||||
(
|
(
|
||||||
|
|
@ -87,7 +87,7 @@ function DynamicInput({
|
||||||
disabled={readonly}
|
disabled={readonly}
|
||||||
value={inputValue ?? ''}
|
value={inputValue ?? ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
placeholder={placeholderCode ? localize(placeholder) ?? placeholder : placeholder}
|
placeholder={placeholderCode ? localize(placeholder) || placeholder : placeholder}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-10 max-h-10 w-full resize-none border-none bg-surface-secondary px-3 py-2',
|
'flex h-10 max-h-10 w-full resize-none border-none bg-surface-secondary px-3 py-2',
|
||||||
)}
|
)}
|
||||||
|
|
@ -95,7 +95,7 @@ function DynamicInput({
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
{description && (
|
{description && (
|
||||||
<OptionHover
|
<OptionHover
|
||||||
description={descriptionCode ? localize(description) ?? description : description}
|
description={descriptionCode ? localize(description) || description : description}
|
||||||
side={ESide.Left}
|
side={ESide.Left}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import {
|
||||||
ImageDetail,
|
ImageDetail,
|
||||||
EModelEndpoint,
|
EModelEndpoint,
|
||||||
openAISettings,
|
openAISettings,
|
||||||
|
googleSettings,
|
||||||
BedrockProviders,
|
BedrockProviders,
|
||||||
anthropicSettings,
|
anthropicSettings,
|
||||||
} from 'librechat-data-provider';
|
} from 'librechat-data-provider';
|
||||||
|
|
@ -352,6 +353,87 @@ const meta: Record<string, SettingDefinition> = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const google: Record<string, SettingDefinition> = {
|
||||||
|
temperature: createDefinition(baseDefinitions.temperature, {
|
||||||
|
default: googleSettings.temperature.default,
|
||||||
|
range: {
|
||||||
|
min: googleSettings.temperature.min,
|
||||||
|
max: googleSettings.temperature.max,
|
||||||
|
step: googleSettings.temperature.step,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
topP: createDefinition(baseDefinitions.topP, {
|
||||||
|
default: googleSettings.topP.default,
|
||||||
|
range: {
|
||||||
|
min: googleSettings.topP.min,
|
||||||
|
max: googleSettings.topP.max,
|
||||||
|
step: googleSettings.topP.step,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
topK: {
|
||||||
|
key: 'topK',
|
||||||
|
label: 'com_endpoint_top_k',
|
||||||
|
labelCode: true,
|
||||||
|
description: 'com_endpoint_google_topk',
|
||||||
|
descriptionCode: true,
|
||||||
|
type: 'number',
|
||||||
|
default: googleSettings.topK.default,
|
||||||
|
range: {
|
||||||
|
min: googleSettings.topK.min,
|
||||||
|
max: googleSettings.topK.max,
|
||||||
|
step: googleSettings.topK.step,
|
||||||
|
},
|
||||||
|
component: 'slider',
|
||||||
|
optionType: 'model',
|
||||||
|
columnSpan: 4,
|
||||||
|
},
|
||||||
|
maxOutputTokens: {
|
||||||
|
key: 'maxOutputTokens',
|
||||||
|
label: 'com_endpoint_max_output_tokens',
|
||||||
|
labelCode: true,
|
||||||
|
type: 'number',
|
||||||
|
component: 'input',
|
||||||
|
description: 'com_endpoint_google_maxoutputtokens',
|
||||||
|
descriptionCode: true,
|
||||||
|
placeholder: 'com_nav_theme_system',
|
||||||
|
placeholderCode: true,
|
||||||
|
default: googleSettings.maxOutputTokens.default,
|
||||||
|
range: {
|
||||||
|
min: googleSettings.maxOutputTokens.min,
|
||||||
|
max: googleSettings.maxOutputTokens.max,
|
||||||
|
step: googleSettings.maxOutputTokens.step,
|
||||||
|
},
|
||||||
|
optionType: 'model',
|
||||||
|
columnSpan: 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const googleConfig: SettingsConfiguration = [
|
||||||
|
librechat.modelLabel,
|
||||||
|
librechat.promptPrefix,
|
||||||
|
librechat.maxContextTokens,
|
||||||
|
google.maxOutputTokens,
|
||||||
|
google.temperature,
|
||||||
|
google.topP,
|
||||||
|
google.topK,
|
||||||
|
librechat.resendFiles,
|
||||||
|
];
|
||||||
|
|
||||||
|
const googleCol1: SettingsConfiguration = [
|
||||||
|
baseDefinitions.model as SettingDefinition,
|
||||||
|
librechat.modelLabel,
|
||||||
|
librechat.promptPrefix,
|
||||||
|
];
|
||||||
|
|
||||||
|
const googleCol2: SettingsConfiguration = [
|
||||||
|
librechat.maxContextTokens,
|
||||||
|
google.maxOutputTokens,
|
||||||
|
google.temperature,
|
||||||
|
google.topP,
|
||||||
|
google.topK,
|
||||||
|
librechat.resendFiles,
|
||||||
|
];
|
||||||
|
|
||||||
const openAI: SettingsConfiguration = [
|
const openAI: SettingsConfiguration = [
|
||||||
openAIParams.chatGptLabel,
|
openAIParams.chatGptLabel,
|
||||||
librechat.promptPrefix,
|
librechat.promptPrefix,
|
||||||
|
|
@ -529,6 +611,7 @@ export const settings: Record<string, SettingsConfiguration | undefined> = {
|
||||||
[`${EModelEndpoint.bedrock}-${BedrockProviders.Meta}`]: bedrockGeneral,
|
[`${EModelEndpoint.bedrock}-${BedrockProviders.Meta}`]: bedrockGeneral,
|
||||||
[`${EModelEndpoint.bedrock}-${BedrockProviders.AI21}`]: bedrockGeneral,
|
[`${EModelEndpoint.bedrock}-${BedrockProviders.AI21}`]: bedrockGeneral,
|
||||||
[`${EModelEndpoint.bedrock}-${BedrockProviders.Amazon}`]: bedrockGeneral,
|
[`${EModelEndpoint.bedrock}-${BedrockProviders.Amazon}`]: bedrockGeneral,
|
||||||
|
[EModelEndpoint.google]: googleConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
const openAIColumns = {
|
const openAIColumns = {
|
||||||
|
|
@ -571,6 +654,10 @@ export const presetSettings: Record<
|
||||||
[`${EModelEndpoint.bedrock}-${BedrockProviders.Meta}`]: bedrockGeneralColumns,
|
[`${EModelEndpoint.bedrock}-${BedrockProviders.Meta}`]: bedrockGeneralColumns,
|
||||||
[`${EModelEndpoint.bedrock}-${BedrockProviders.AI21}`]: bedrockGeneralColumns,
|
[`${EModelEndpoint.bedrock}-${BedrockProviders.AI21}`]: bedrockGeneralColumns,
|
||||||
[`${EModelEndpoint.bedrock}-${BedrockProviders.Amazon}`]: bedrockGeneralColumns,
|
[`${EModelEndpoint.bedrock}-${BedrockProviders.Amazon}`]: bedrockGeneralColumns,
|
||||||
|
[EModelEndpoint.google]: {
|
||||||
|
col1: googleCol1,
|
||||||
|
col2: googleCol2,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const agentSettings: Record<string, SettingsConfiguration | undefined> = Object.entries(
|
export const agentSettings: Record<string, SettingsConfiguration | undefined> = Object.entries(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import * as Ariakit from '@ariakit/react';
|
import * as Ariakit from '@ariakit/react';
|
||||||
import { matchSorter } from 'match-sorter';
|
import { matchSorter } from 'match-sorter';
|
||||||
|
import { AutoSizer, List } from 'react-virtualized';
|
||||||
import { startTransition, useMemo, useState, useEffect, useRef, memo } from 'react';
|
import { startTransition, useMemo, useState, useEffect, useRef, memo } from 'react';
|
||||||
import { cn } from '~/utils';
|
import { cn } from '~/utils';
|
||||||
import type { OptionWithIcon } from '~/common';
|
import type { OptionWithIcon } from '~/common';
|
||||||
|
|
@ -17,6 +18,8 @@ interface ControlComboboxProps {
|
||||||
SelectIcon?: React.ReactNode;
|
SelectIcon?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ROW_HEIGHT = 36;
|
||||||
|
|
||||||
function ControlCombobox({
|
function ControlCombobox({
|
||||||
selectedValue,
|
selectedValue,
|
||||||
displayValue,
|
displayValue,
|
||||||
|
|
@ -45,6 +48,39 @@ function ControlCombobox({
|
||||||
}
|
}
|
||||||
}, [isCollapsed]);
|
}, [isCollapsed]);
|
||||||
|
|
||||||
|
const rowRenderer = ({
|
||||||
|
index,
|
||||||
|
key,
|
||||||
|
style,
|
||||||
|
}: {
|
||||||
|
index: number;
|
||||||
|
key: string;
|
||||||
|
style: React.CSSProperties;
|
||||||
|
}) => {
|
||||||
|
const item = matches[index];
|
||||||
|
return (
|
||||||
|
<Ariakit.SelectItem
|
||||||
|
key={key}
|
||||||
|
value={`${item.value ?? ''}`}
|
||||||
|
aria-label={`${item.label ?? item.value ?? ''}`}
|
||||||
|
className={cn(
|
||||||
|
'flex cursor-pointer items-center px-3 text-sm',
|
||||||
|
'text-text-primary hover:bg-surface-tertiary',
|
||||||
|
'data-[active-item]:bg-surface-tertiary',
|
||||||
|
)}
|
||||||
|
render={<Ariakit.ComboboxItem />}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
{item.icon != null && (
|
||||||
|
<div className="assistant-item mr-2 flex h-5 w-5 items-center justify-center overflow-hidden rounded-full">
|
||||||
|
{item.icon}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<span className="flex-grow truncate text-left">{item.label}</span>
|
||||||
|
</Ariakit.SelectItem>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full items-center justify-center px-1">
|
<div className="flex w-full items-center justify-center px-1">
|
||||||
<Ariakit.ComboboxProvider
|
<Ariakit.ComboboxProvider
|
||||||
|
|
@ -93,28 +129,20 @@ function ControlCombobox({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Ariakit.ComboboxList className="max-h-[50vh] overflow-auto">
|
<div className="max-h-[50vh]">
|
||||||
{matches.map((item) => (
|
<AutoSizer disableHeight>
|
||||||
<Ariakit.SelectItem
|
{({ width }) => (
|
||||||
key={item.value}
|
<List
|
||||||
value={`${item.value ?? ''}`}
|
width={width}
|
||||||
aria-label={`${item.label ?? item.value ?? ''}`}
|
height={Math.min(matches.length * ROW_HEIGHT, 300)}
|
||||||
className={cn(
|
rowCount={matches.length}
|
||||||
'flex cursor-pointer items-center px-3 py-2 text-sm',
|
rowHeight={ROW_HEIGHT}
|
||||||
'text-text-primary hover:bg-surface-tertiary',
|
rowRenderer={rowRenderer}
|
||||||
'data-[active-item]:bg-surface-tertiary',
|
overscanRowCount={5}
|
||||||
)}
|
/>
|
||||||
render={<Ariakit.ComboboxItem />}
|
)}
|
||||||
>
|
</AutoSizer>
|
||||||
{item.icon != null && (
|
</div>
|
||||||
<div className="assistant-item mr-2 flex h-5 w-5 items-center justify-center overflow-hidden rounded-full">
|
|
||||||
{item.icon}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<span className="flex-grow truncate text-left">{item.label}</span>
|
|
||||||
</Ariakit.SelectItem>
|
|
||||||
))}
|
|
||||||
</Ariakit.ComboboxList>
|
|
||||||
</Ariakit.SelectPopover>
|
</Ariakit.SelectPopover>
|
||||||
</Ariakit.SelectProvider>
|
</Ariakit.SelectProvider>
|
||||||
</Ariakit.ComboboxProvider>
|
</Ariakit.ComboboxProvider>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ function useDebouncedInput<T = unknown>({
|
||||||
initialValue: T;
|
initialValue: T;
|
||||||
delay?: number;
|
delay?: number;
|
||||||
}): [
|
}): [
|
||||||
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> | T) => void,
|
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> | T, numeric?: boolean) => void,
|
||||||
T,
|
T,
|
||||||
SetterOrUpdater<T>,
|
SetterOrUpdater<T>,
|
||||||
// (newValue: string) => void,
|
// (newValue: string) => void,
|
||||||
|
|
@ -37,12 +37,15 @@ function useDebouncedInput<T = unknown>({
|
||||||
|
|
||||||
/** An onChange handler that updates the local state and the debounced option */
|
/** An onChange handler that updates the local state and the debounced option */
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> | T) => {
|
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> | T, numeric?: boolean) => {
|
||||||
const newValue: T =
|
let newValue: T =
|
||||||
typeof e !== 'object'
|
typeof e !== 'object'
|
||||||
? e
|
? e
|
||||||
: ((e as React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>).target
|
: ((e as React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>).target
|
||||||
.value as unknown as T);
|
.value as unknown as T);
|
||||||
|
if (numeric === true) {
|
||||||
|
newValue = Number(newValue) as unknown as T;
|
||||||
|
}
|
||||||
setValue(newValue);
|
setValue(newValue);
|
||||||
setDebouncedOption(newValue);
|
setDebouncedOption(newValue);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
25
package-lock.json
generated
25
package-lock.json
generated
|
|
@ -952,6 +952,7 @@
|
||||||
"react-speech-recognition": "^3.10.0",
|
"react-speech-recognition": "^3.10.0",
|
||||||
"react-textarea-autosize": "^8.4.0",
|
"react-textarea-autosize": "^8.4.0",
|
||||||
"react-transition-group": "^4.4.5",
|
"react-transition-group": "^4.4.5",
|
||||||
|
"react-virtualized": "^9.22.6",
|
||||||
"recoil": "^0.7.7",
|
"recoil": "^0.7.7",
|
||||||
"regenerator-runtime": "^0.14.1",
|
"regenerator-runtime": "^0.14.1",
|
||||||
"rehype-highlight": "^6.0.0",
|
"rehype-highlight": "^6.0.0",
|
||||||
|
|
@ -29460,6 +29461,11 @@
|
||||||
"react-dom": "^15.x.x || ^16.x.x || ^17.x.x || ^18.x.x"
|
"react-dom": "^15.x.x || ^16.x.x || ^17.x.x || ^18.x.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-lifecycles-compat": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||||
|
},
|
||||||
"node_modules/react-markdown": {
|
"node_modules/react-markdown": {
|
||||||
"version": "9.0.1",
|
"version": "9.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz",
|
||||||
|
|
@ -29760,6 +29766,23 @@
|
||||||
"react-dom": ">=16.6.0"
|
"react-dom": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-virtualized": {
|
||||||
|
"version": "9.22.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.6.tgz",
|
||||||
|
"integrity": "sha512-U5j7KuUQt3AaMatlMJ0UJddqSiX+Km0YJxSqbAzIiGw5EmNz0khMyqP2hzgu4+QUtm+QPIrxzUX4raJxmVJnHg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.7.2",
|
||||||
|
"clsx": "^1.0.4",
|
||||||
|
"dom-helpers": "^5.1.3",
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"react-lifecycles-compat": "^3.0.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
|
|
@ -35067,7 +35090,7 @@
|
||||||
},
|
},
|
||||||
"packages/data-provider": {
|
"packages/data-provider": {
|
||||||
"name": "librechat-data-provider",
|
"name": "librechat-data-provider",
|
||||||
"version": "0.7.693",
|
"version": "0.7.694",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "librechat-data-provider",
|
"name": "librechat-data-provider",
|
||||||
"version": "0.7.693",
|
"version": "0.7.694",
|
||||||
"description": "data services for librechat apps",
|
"description": "data services for librechat apps",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist/index.es.js",
|
"module": "dist/index.es.js",
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ export const paramEndpoints = new Set<EModelEndpoint | string>([
|
||||||
EModelEndpoint.azureOpenAI,
|
EModelEndpoint.azureOpenAI,
|
||||||
EModelEndpoint.anthropic,
|
EModelEndpoint.anthropic,
|
||||||
EModelEndpoint.custom,
|
EModelEndpoint.custom,
|
||||||
|
EModelEndpoint.google,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export enum BedrockProviders {
|
export enum BedrockProviders {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue