diff --git a/client/src/components/Chat/Input/OptionsPopover.tsx b/client/src/components/Chat/Input/OptionsPopover.tsx index 02f5150bc5..a49d31f334 100644 --- a/client/src/components/Chat/Input/OptionsPopover.tsx +++ b/client/src/components/Chat/Input/OptionsPopover.tsx @@ -66,7 +66,7 @@ export default function OptionsPopover({ {presetsDisabled ? null : ( diff --git a/client/src/components/Prompts/Command.tsx b/client/src/components/Prompts/Command.tsx index 40c2177734..a80dc1d78c 100644 --- a/client/src/components/Prompts/Command.tsx +++ b/client/src/components/Prompts/Command.tsx @@ -38,7 +38,7 @@ const Command = ({ } }; - if (disabled && !command) { + if (disabled === true && !command) { return null; } @@ -53,10 +53,10 @@ const Command = ({ placeholder={localize('com_ui_command_placeholder')} value={command} onChange={handleInputChange} - className="w-full rounded-lg border-none bg-surface-tertiary p-1 text-text-primary placeholder:text-text-secondary-alt focus:bg-surface-tertiary focus:outline-none focus:ring-0 md:w-96" + className="w-full rounded-lg border-none bg-surface-tertiary p-1 text-text-primary placeholder:text-text-secondary focus:bg-surface-tertiary focus:outline-none focus:ring-1 focus:ring-inset focus:ring-ring-primary md:w-96" /> - {!disabled && ( - {`${charCount}/${Constants.COMMANDS_MAX_LENGTH}`} + {disabled !== true && ( + {`${charCount}/${Constants.COMMANDS_MAX_LENGTH}`} )} diff --git a/client/src/components/Prompts/Description.tsx b/client/src/components/Prompts/Description.tsx index 23c0e85237..452c624ce8 100644 --- a/client/src/components/Prompts/Description.tsx +++ b/client/src/components/Prompts/Description.tsx @@ -50,10 +50,10 @@ const Description = ({ placeholder={localize('com_ui_description_placeholder')} value={description} onChange={handleInputChange} - className="w-full rounded-lg border-none bg-surface-tertiary p-1 text-text-primary placeholder:text-text-secondary-alt focus:bg-surface-tertiary focus:outline-none focus:ring-0 md:w-96" + className="w-full rounded-lg border-none bg-surface-tertiary p-1 text-text-primary placeholder:text-text-secondary focus:bg-surface-tertiary focus:outline-none focus:ring-1 focus:ring-inset focus:ring-ring-primary md:w-96" /> {!disabled && ( - {`${charCount}/${MAX_LENGTH}`} + {`${charCount}/${MAX_LENGTH}`} )} diff --git a/client/src/components/Prompts/Groups/CreatePromptForm.tsx b/client/src/components/Prompts/Groups/CreatePromptForm.tsx index f8c301f656..c409567bcd 100644 --- a/client/src/components/Prompts/Groups/CreatePromptForm.tsx +++ b/client/src/components/Prompts/Groups/CreatePromptForm.tsx @@ -111,10 +111,9 @@ const CreatePromptForm = ({
)} /> - +
-

+

{localize('com_ui_prompt_text')}*

-
+
methods.setValue('oneliner', value)} - tabIndex={3} + tabIndex={0} /> - methods.setValue('command', value)} tabIndex={4} /> + methods.setValue('command', value)} tabIndex={0} />
-
diff --git a/client/src/components/Prompts/Groups/VariableDialog.tsx b/client/src/components/Prompts/Groups/VariableDialog.tsx index c866914974..26fb8c4b1a 100644 --- a/client/src/components/Prompts/Groups/VariableDialog.tsx +++ b/client/src/components/Prompts/Groups/VariableDialog.tsx @@ -31,7 +31,7 @@ const VariableDialog: React.FC = ({ open, onClose, group }) return ( - + {group.name} diff --git a/client/src/components/Prompts/Groups/VariableForm.tsx b/client/src/components/Prompts/Groups/VariableForm.tsx index d77d164f72..711a39bbcd 100644 --- a/client/src/components/Prompts/Groups/VariableForm.tsx +++ b/client/src/components/Prompts/Groups/VariableForm.tsx @@ -1,12 +1,64 @@ import { useMemo } from 'react'; +import remarkGfm from 'remark-gfm'; +import remarkMath from 'remark-math'; +import supersub from 'remark-supersub'; +import rehypeKatex from 'rehype-katex'; +import ReactMarkdown from 'react-markdown'; +import rehypeHighlight from 'rehype-highlight'; import { useForm, useFieldArray, Controller, useWatch } from 'react-hook-form'; import type { TPromptGroup } from 'librechat-data-provider'; -import { extractVariableInfo, wrapVariable, replaceSpecialVars } from '~/utils'; +import { + cn, + wrapVariable, + defaultTextProps, + replaceSpecialVars, + extractVariableInfo, +} from '~/utils'; import { useAuthContext, useLocalize, useSubmitMessage } from '~/hooks'; -import { Textarea } from '~/components/ui'; +import { TextareaAutosize, InputWithDropdown } from '~/components/ui'; +import { code } from '~/components/Chat/Messages/Content/Markdown'; + +type FieldType = 'text' | 'select'; + +type FieldConfig = { + variable: string; + type: FieldType; + options?: string[]; +}; type FormValues = { - fields: { variable: string; value: string }[]; + fields: { variable: string; value: string; config: FieldConfig }[]; +}; + +/** + * Variable Format Guide: + * + * Variables in prompts should be enclosed in double curly braces: {{variable}} + * + * Simple text input: + * {{variable_name}} + * + * Dropdown select with predefined options: + * {{variable_name:option1|option2|option3}} + * + * All dropdown selects allow custom input in addition to predefined options. + * + * Examples: + * {{name}} - Simple text input for a name + * {{tone:formal|casual|business casual}} - Dropdown for tone selection with custom input option + * + * Note: The order of variables in the prompt will be preserved in the input form. + */ + +const parseFieldConfig = (variable: string): FieldConfig => { + const content = variable; + if (content.includes(':')) { + const [name, options] = content.split(':'); + if (options && options.includes('|')) { + return { variable: name, type: 'select', options: options.split('|') }; + } + } + return { variable: content, type: 'text' }; }; export default function VariableForm({ @@ -32,7 +84,11 @@ export default function VariableForm({ const { submitPrompt } = useSubmitMessage(); const { control, handleSubmit } = useForm({ defaultValues: { - fields: uniqueVariables.map((variable) => ({ variable: wrapVariable(variable), value: '' })), + fields: uniqueVariables.map((variable) => ({ + variable: wrapVariable(variable), + value: '', + config: parseFieldConfig(variable), + })), }, }); @@ -50,31 +106,16 @@ export default function VariableForm({ return null; } - const generateHighlightedText = () => { + const generateHighlightedMarkdown = () => { let tempText = mainText; - const parts: JSX.Element[] = []; - - allVariables.forEach((variable, index) => { + allVariables.forEach((variable) => { const placeholder = `{{${variable}}}`; - const partsBeforePlaceholder = tempText.split(placeholder); const fieldIndex = variableIndexMap.get(variable) as string | number; const fieldValue = fieldValues[fieldIndex].value as string; - parts.push( - {partsBeforePlaceholder[0]}, - - {fieldValue !== '' ? fieldValue : placeholder} - , - ); - - tempText = partsBeforePlaceholder.slice(1).join(placeholder); + const highlightText = fieldValue !== '' ? fieldValue : placeholder; + tempText = tempText.replaceAll(placeholder, `**${highlightText}**`); }); - - parts.push({tempText}); - - return parts; + return tempText; }; const onSubmit = (data: FormValues) => { @@ -91,32 +132,53 @@ export default function VariableForm({ }; return ( -
-
-
-

{generateHighlightedText()}

+
+ +
+ + {generateHighlightedMarkdown()} +
-
+
{fields.map((field, index) => ( -
+
( -