Compare commits

...

2 Commits

24 changed files with 267 additions and 207 deletions

View File

@@ -23,6 +23,7 @@ export type AgentForm = {
instructions: string | null;
model: string | null;
model_parameters: AgentModelParameters;
conversation_starters: string[];
tools?: string[];
provider?: AgentProvider | OptionWithIcon;
agent_ids?: string[];

View File

@@ -4,7 +4,7 @@ import { useGetEndpointsQuery, useGetStartupConfig } from 'librechat-data-provid
import type * as t from 'librechat-data-provider';
import type { ReactNode } from 'react';
import { useChatContext, useAgentsMapContext, useAssistantsMapContext } from '~/Providers';
import { useGetAssistantDocsQuery } from '~/data-provider';
import { useGetAssistantDocsQuery, useGetAgentByIdQuery } from '~/data-provider';
import ConvoIcon from '~/components/Endpoints/ConvoIcon';
import { getIconEndpoint, getEntity, cn } from '~/utils';
import { useLocalize, useSubmitMessage } from '~/hooks';
@@ -12,8 +12,22 @@ import { TooltipAnchor } from '~/components/ui';
import { BirthdayIcon } from '~/components/svg';
import ConvoStarter from './ConvoStarter';
const getSequentialFromRandom = (arr: string[], count: number) => {
if (arr.length <= count) {
return arr;
}
const maxStartIndex = arr.length - count;
const startIndex = Math.floor(Math.random() * (maxStartIndex + 1));
return arr.slice(startIndex, startIndex + count);
};
export default function Landing({ Header }: { Header?: ReactNode }) {
const { conversation } = useChatContext();
const { data: agentData } = useGetAgentByIdQuery(conversation?.agent_id ?? '', {
enabled: typeof conversation?.agent_id === 'string' && conversation.agent_id.length > 0,
});
const agentsMap = useAgentsMapContext();
const assistantMap = useAssistantsMapContext();
const { data: startupConfig } = useGetStartupConfig();
@@ -51,6 +65,10 @@ export default function Landing({ Header }: { Header?: ReactNode }) {
? (entity as t.Agent | undefined)?.avatar?.filepath ?? ''
: ((entity as t.Assistant | undefined)?.metadata?.avatar as string | undefined) ?? '';
const conversation_starters = useMemo(() => {
if (isAgent && agentData?.conversation_starters) {
return agentData.conversation_starters;
}
/* The user made updates, use client-side cache, or they exist in an Agent */
if (entity && (entity.conversation_starters?.length ?? 0) > 0) {
return entity.conversation_starters;
@@ -87,6 +105,11 @@ export default function Landing({ Header }: { Header?: ReactNode }) {
return localize('com_nav_welcome_message');
};
const randomizedStarters = useMemo(
() => getSequentialFromRandom(conversation_starters, 4),
[conversation_starters],
);
return (
<div className="relative h-full">
<div className="absolute left-0 right-0">{Header != null ? Header : null}</div>
@@ -127,16 +150,10 @@ export default function Landing({ Header }: { Header?: ReactNode }) {
</h2>
)}
<div className="mt-8 flex flex-wrap justify-center gap-3 px-4">
{conversation_starters.length > 0 &&
conversation_starters
.slice(0, Constants.MAX_CONVO_STARTERS)
.map((text: string, index: number) => (
<ConvoStarter
key={index}
text={text}
onClick={() => sendConversationStarter(text)}
/>
))}
{randomizedStarters.length > 0 &&
randomizedStarters.map((text: string, index: number) => (
<ConvoStarter key={index} text={text} onClick={() => sendConversationStarter(text)} />
))}
</div>
</div>
</div>

View File

@@ -16,6 +16,7 @@ import { useCreateAgentMutation, useUpdateAgentMutation } from '~/data-provider'
import { useLocalize, useAuthContext, useHasAccess } from '~/hooks';
import { useToastContext, useFileMapContext } from '~/Providers';
import { icons } from '~/components/Chat/Menus/Endpoints/Icons';
import { AgentConversationStarters } from '~/components/ui';
import Action from '~/components/SidePanel/Builder/Action';
import { ToolSelectDialog } from '~/components/Tools';
import DuplicateAgent from './DuplicateAgent';
@@ -33,7 +34,7 @@ import { Panel } from '~/common';
const labelClass = 'mb-2 text-token-text-primary block font-medium';
const inputClass = cn(
defaultTextProps,
'flex w-full px-3 py-2 border-border-light bg-surface-secondary focus-visible:ring-2 focus-visible:ring-ring-primary',
'flex w-full px-3 py-2 dark:border-surface-secondary dark:bg-surface-secondary rounded-xl mb-2 transition-all duration-200',
removeFocusOutlines,
);
@@ -310,6 +311,22 @@ export default function AgentConfig({
)}
/>
</div>
{/* Conversation Starters */}
<div className="relative mb-6">
{/* the label of conversation starters is in the component */}
<Controller
name="conversation_starters"
control={control}
defaultValue={[]}
render={({ field }) => (
<AgentConversationStarters
field={field}
inputClass={inputClass}
labelClass={labelClass}
/>
)}
/>
</div>
{/* Model and Provider */}
<div className="mb-4">
<label className={labelClass} htmlFor="provider">

View File

@@ -126,6 +126,7 @@ export default function AgentPanel({
model: _model,
model_parameters,
provider: _provider,
conversation_starters: starters,
agent_ids,
end_after_tools,
hide_sequential_outputs,
@@ -146,6 +147,7 @@ export default function AgentPanel({
tools,
provider,
model_parameters,
conversation_starters: starters.filter((starter) => starter.trim() !== ''),
agent_ids,
end_after_tools,
hide_sequential_outputs,
@@ -169,6 +171,7 @@ export default function AgentPanel({
tools,
provider,
model_parameters,
conversation_starters: starters.filter((starter) => starter.trim() !== ''),
agent_ids,
end_after_tools,
hide_sequential_outputs,

View File

@@ -89,6 +89,15 @@ export default function AgentSelect({
return;
}
if (
name === 'conversation_starters' &&
Array.isArray(value) &&
value.every((item) => typeof item === 'string')
) {
formValues[name] = value;
return;
}
if (typeof value !== 'number' && typeof value !== 'object') {
formValues[name] = value;
}

View File

@@ -1,155 +0,0 @@
import React, { useRef, useState } from 'react';
import { Plus, X } from 'lucide-react';
import { Transition } from 'react-transition-group';
import { Constants } from 'librechat-data-provider';
import { TooltipAnchor } from '~/components/ui';
import { useLocalize } from '~/hooks';
interface AssistantConversationStartersProps {
field: {
value: string[];
onChange: (value: string[]) => void;
};
inputClass: string;
labelClass: string;
}
const AssistantConversationStarters: React.FC<AssistantConversationStartersProps> = ({
field,
inputClass,
labelClass,
}) => {
const localize = useLocalize();
const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
const nodeRef = useRef(null);
const [newStarter, setNewStarter] = useState('');
const handleAddStarter = () => {
if (newStarter.trim() && field.value.length < Constants.MAX_CONVO_STARTERS) {
const newValues = [newStarter, ...field.value];
field.onChange(newValues);
setNewStarter('');
}
};
const handleDeleteStarter = (index: number) => {
const newValues = field.value.filter((_, i) => i !== index);
field.onChange(newValues);
};
const defaultStyle = {
transition: 'opacity 200ms ease-in-out',
opacity: 0,
};
const triggerShake = (element: HTMLElement) => {
element.classList.remove('shake');
void element.offsetWidth;
element.classList.add('shake');
setTimeout(() => {
element.classList.remove('shake');
}, 200);
};
const transitionStyles = {
entering: { opacity: 1 },
entered: { opacity: 1 },
exiting: { opacity: 0 },
exited: { opacity: 0 },
};
const hasReachedMax = field.value.length >= Constants.MAX_CONVO_STARTERS;
return (
<div className="relative">
<label className={labelClass} htmlFor="conversation_starters">
{localize('com_assistants_conversation_starters')}
</label>
<div className="mt-4 space-y-2">
{/* Persistent starter, used for creating only */}
<div className="relative">
<input
ref={(el) => (inputRefs.current[0] = el)}
value={newStarter}
maxLength={64}
className={`${inputClass} pr-10`}
type="text"
placeholder={
hasReachedMax
? localize('com_assistants_max_starters_reached')
: localize('com_assistants_conversation_starters_placeholder')
}
onChange={(e) => setNewStarter(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
if (hasReachedMax) {
triggerShake(e.currentTarget);
} else {
handleAddStarter();
}
}
}}
/>
<Transition
nodeRef={nodeRef}
in={field.value.length < Constants.MAX_CONVO_STARTERS}
timeout={200}
unmountOnExit
>
{(state: string) => (
<div
ref={nodeRef}
style={{
...defaultStyle,
...transitionStyles[state as keyof typeof transitionStyles],
transition: state === 'entering' ? 'none' : defaultStyle.transition,
}}
className="absolute right-1 top-1"
>
<TooltipAnchor
side="top"
description={
hasReachedMax
? localize('com_assistants_max_starters_reached')
: localize('com_ui_add')
}
className="flex size-7 items-center justify-center rounded-lg transition-colors duration-200 hover:bg-surface-hover"
onClick={handleAddStarter}
disabled={hasReachedMax}
>
<Plus className="size-4" />
</TooltipAnchor>
</div>
)}
</Transition>
</div>
{field.value.map((starter, index) => (
<div key={index} className="relative">
<input
ref={(el) => (inputRefs.current[index + 1] = el)}
value={starter}
onChange={(e) => {
const newValue = [...field.value];
newValue[index] = e.target.value;
field.onChange(newValue);
}}
className={`${inputClass} pr-10`}
type="text"
maxLength={64}
/>
<TooltipAnchor
side="top"
description={localize('com_ui_delete')}
className="absolute right-1 top-1 flex size-7 items-center justify-center rounded-lg transition-colors duration-200 hover:bg-surface-hover"
onClick={() => handleDeleteStarter(index)}
>
<X className="size-4" />
</TooltipAnchor>
</div>
))}
</div>
</div>
);
};
export default AssistantConversationStarters;

View File

@@ -14,13 +14,12 @@ import type { FunctionTool, TConfig, TPlugin } from 'librechat-data-provider';
import type { AssistantForm, AssistantPanelProps } from '~/common';
import { useCreateAssistantMutation, useUpdateAssistantMutation } from '~/data-provider';
import { cn, cardStyle, defaultTextProps, removeFocusOutlines } from '~/utils';
import AssistantConversationStarters from './AssistantConversationStarters';
import { SelectDropDown, AgentConversationStarters } from '~/components/ui';
import { useAssistantsMapContext, useToastContext } from '~/Providers';
import { useSelectAssistant, useLocalize } from '~/hooks';
import { ToolSelectDialog } from '~/components/Tools';
import CapabilitiesForm from './CapabilitiesForm';
import AppendDateCheckbox from './AppendDateCheckbox';
import { SelectDropDown } from '~/components/ui';
import AssistantAvatar from './AssistantAvatar';
import AssistantSelect from './AssistantSelect';
import ContextButton from './ContextButton';
@@ -339,7 +338,7 @@ export default function AssistantPanel({
control={control}
defaultValue={[]}
render={({ field }) => (
<AssistantConversationStarters
<AgentConversationStarters
field={field}
inputClass={inputClass}
labelClass={labelClass}

View File

@@ -0,0 +1,165 @@
import React, { useRef, useState, useEffect, DragEvent } from 'react';
import { X, GripVertical } from 'lucide-react';
import { Constants } from 'librechat-data-provider';
import { TooltipAnchor } from './Tooltip';
import { useLocalize } from '~/hooks';
import { motion, AnimatePresence } from 'framer-motion';
interface AgentConversationStartersProps {
field: {
value: string[];
onChange: (value: string[]) => void;
};
inputClass: string;
labelClass: string;
}
export default function AgentConversationStarters({
field,
inputClass,
labelClass,
}: AgentConversationStartersProps) {
const localize = useLocalize();
const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
const [dragIndex, setDragIndex] = useState<number | null>(null);
const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);
const [isCollapsed, setIsCollapsed] = useState<boolean>(true);
useEffect(() => {
if (field.value.length === 0) {
field.onChange(['']);
}
}, [field.value, field]);
const handleDeleteStarter = (index: number) => {
if (!field.value[index]) {
return;
}
const newValues = field.value.filter((_, i) => i !== index);
if (newValues.length === 0) {
newValues.push('');
}
field.onChange(newValues);
};
const handleStarterChange = (value: string, index: number) => {
const newValue = [...field.value];
newValue[index] = value;
if (
index === field.value.length - 1 &&
value.trim() &&
field.value.length < Constants.MAX_CONVO_STARTERS
) {
newValue.push('');
}
field.onChange(newValue);
};
const handleBlur = (index: number) => {
if (!field.value[index] && index !== field.value.length - 1) {
const newValues = field.value.filter((val, i) => i !== index || val.trim() !== '');
if (newValues.length === 0) {
newValues.push('');
}
field.onChange(newValues);
}
};
const handleDragStart = (index: number) => (e: DragEvent<HTMLDivElement>) => {
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', String(index));
setDragIndex(index);
};
const handleDragEnd = () => {
setDragIndex(null);
setDragOverIndex(null);
};
const handleDragOver = (index: number) => (e: DragEvent<HTMLDivElement>) => {
e.preventDefault();
setDragOverIndex(index);
};
const handleDrop = (index: number) => (e: DragEvent<HTMLDivElement>) => {
e.preventDefault();
if (dragIndex === null || dragIndex === index) {
return;
}
const updated = [...field.value];
const [removed] = updated.splice(dragIndex, 1);
updated.splice(index, 0, removed);
field.onChange(updated);
setDragIndex(null);
setDragOverIndex(null);
};
const getDisplayValue = (starter: string, index: number) => {
if (dragIndex === null || dragOverIndex === null) {
return starter;
}
if (index === dragOverIndex && dragIndex !== dragOverIndex) {
return field.value[dragIndex];
}
if (index === dragIndex && dragIndex !== dragOverIndex) {
return '';
}
return starter;
};
return (
<div className="relative">
<label className={labelClass} htmlFor="conversation_starters">
{localize('com_agents_conversation_starters')}
</label>
<div className="mt-4 space-y-2">
<AnimatePresence>
{field.value.map((starter, index) => (
<motion.div
key={index}
className={`hover:bg-accent-primary/5 group relative flex h-10 transform-gpu
items-center rounded-lg transition-transform duration-300
ease-in-out
${dragIndex === index ? 'scale-[0.98] opacity-50' : ''}
${dragOverIndex === index ? 'bg-accent-primary/10 shadow-sm' : ''}
${dragIndex !== null ? 'cursor-grabbing' : ''}`}
draggable
data-index={index}
onDragStart={handleDragStart(index)}
onDragEnd={handleDragEnd}
onDragOver={handleDragOver(index)}
onDrop={handleDrop(index)}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ type: 'spring', stiffness: 300, damping: 20 }}
layout
>
<div className="flex h-full cursor-grab items-center justify-center px-2 opacity-60 transition-opacity group-hover:opacity-100">
<GripVertical className="size-4 text-text-secondary" />
</div>
<input
ref={(el) => (inputRefs.current[index] = el)}
value={getDisplayValue(starter, index)}
onChange={(e) => handleStarterChange(e.target.value, index)}
onBlur={() => handleBlur(index)}
className={`${inputClass} relative h-full flex-1 pr-10 transition-colors`}
type="text"
maxLength={64}
/>
<TooltipAnchor
side="top"
description={localize('com_ui_delete')}
className="absolute bottom-[0.55rem] right-1 flex size-7 items-center justify-center rounded-lg transition-colors duration-200 hover:bg-surface-hover"
onClick={() => handleDeleteStarter(index)}
disabled={!starter.trim()}
>
<X className="size-4" />
</TooltipAnchor>
</motion.div>
))}
</AnimatePresence>
</div>
</div>
);
}

View File

@@ -36,3 +36,4 @@ export { default as ModelParameters } from './ModelParameters';
export { default as InputWithDropdown } from './InputWithDropDown';
export { default as SelectDropDownPop } from './SelectDropDownPop';
export { default as MultiSelectDropDown } from './MultiSelectDropDown';
export { default as AgentConversationStarters } from './AgentConversationStarters';

View File

@@ -628,8 +628,8 @@ export default {
com_download_expires: 'انقر هنا للتنزيل - تنتهي الصلاحية في {0}',
com_download_expired: 'انتهت صلاحية التنزيل',
com_click_to_download: '(انقر هنا للتنزيل)',
com_assistants_conversation_starters_placeholder: 'أدخل بداية المحادثة',
com_assistants_conversation_starters: 'بدء المحادثات',
com_agents_conversation_starters_placeholder: 'أدخل بداية المحادثة',
com_agents_conversation_starters: 'بدء المحادثات',
com_assistants_code_interpreter_info:
'يُمكّن مُفسِّر الشفرة المساعد من كتابة وتشغيل الشفرة البرمجية. يمكن لهذه الأداة معالجة الملفات ذات البيانات والتنسيقات المتنوعة، وإنشاء ملفات مثل الرسوم البيانية',
com_sidepanel_agent_builder: 'بانٍ المساعد',
@@ -698,7 +698,7 @@ export default {
com_ui_add_model_preset: 'إضافة نموذج أو إعداد مسبق للرد الإضافي',
com_ui_loading: 'جارِ التحميل...',
com_ui_all_proper: 'الكل',
com_assistants_max_starters_reached: 'تم الوصول إلى الحد الأقصى لبادئات المحادثة',
com_agents_max_starters_reached: 'تم الوصول إلى الحد الأقصى لبادئات المحادثة',
com_ui_revoke_keys: 'إلغاء المفاتيح',
com_ui_revoke_key_endpoint: 'إلغاء المفتاح لـ {0}',
com_ui_revoke_key_confirm: 'هل أنت متأكد من إلغاء هذا المفتاح؟',

View File

@@ -85,8 +85,8 @@ export default {
com_assistants_update_error: 'Houve um erro ao atualizar seu assistente.',
com_assistants_create_success: 'Criado com sucesso',
com_assistants_create_error: 'Houve um erro ao criar seu assistente.',
com_assistants_conversation_starters: 'Iniciadores de Conversa',
com_assistants_conversation_starters_placeholder: 'Digite um iniciador de conversa',
com_agents_conversation_starters: 'Iniciadores de Conversa',
com_agents_conversation_starters_placeholder: 'Digite um iniciador de conversa',
com_sidepanel_agent_builder: 'Construtor de Agente',
com_agents_name_placeholder: 'Opcional: O nome do agente',
com_agents_description_placeholder: 'Opcional: Descreva seu Agente aqui',
@@ -247,7 +247,7 @@ export default {
com_ui_mention:
'Mencione um endpoint, assistente ou predefinição para alternar rapidamente para ele',
com_ui_add_model_preset: 'Adicionar um modelo ou predefinição para uma resposta adicional',
com_assistants_max_starters_reached: 'Número máximo de iniciadores de conversa atingido',
com_agents_max_starters_reached: 'Número máximo de iniciadores de conversa atingido',
com_ui_regenerate: 'Regenerar',
com_ui_continue: 'Continuar',
com_ui_edit: 'Editar',

View File

@@ -780,9 +780,9 @@ export default {
com_click_to_download: '(hier klicken zum Herunterladen)',
com_download_expires: '(hier klicken zum Herunterladen - läuft ab am {0})',
com_sidepanel_agent_builder: 'Agenten Ersteller',
com_assistants_conversation_starters_placeholder: 'Gib einen Gesprächseinstieg ein',
com_agents_conversation_starters_placeholder: 'Gib einen Gesprächseinstieg ein',
com_agents_name_placeholder: 'Optional: Der Name des Agenten',
com_assistants_conversation_starters: 'Gesprächseinstiege',
com_agents_conversation_starters: 'Gesprächseinstiege',
com_agents_description_placeholder: 'Optional: Beschreibe hier deinen Agenten',
com_agents_search_name: 'Agenten nach Namen suchen',
com_agents_instructions_placeholder: 'Die Systemanweisungen, die der Agent verwendet',
@@ -812,7 +812,7 @@ export default {
com_ui_select_provider_first: 'Wähle zuerst einen Anbieter',
com_ui_select_provider: 'Wähle einen Anbieter',
com_ui_revoke_keys: 'Schlüssel widerrufen',
com_assistants_max_starters_reached: 'Maximale Anzahl an Gesprächseinstiegen erreicht',
com_agents_max_starters_reached: 'Maximale Anzahl an Gesprächseinstiegen erreicht',
com_ui_revoke_keys_confirm: 'Bist du sicher, dass du alle Schlüssel widerrufen möchtest?',
com_ui_revoke_key_confirm: 'Bist du sicher, dass du diesen Schlüssel widerrufen möchtest?',
com_ui_revoke_key_endpoint: 'API-Schlüssel für {0} widerrufen',

View File

@@ -105,8 +105,8 @@ export default {
com_assistants_update_error: 'There was an error updating your assistant.',
com_assistants_create_success: 'Successfully created',
com_assistants_create_error: 'There was an error creating your assistant.',
com_assistants_conversation_starters: 'Conversation Starters',
com_assistants_conversation_starters_placeholder: 'Enter a conversation starter',
com_agents_conversation_starters: 'Conversation Starters',
com_agents_conversation_starters_placeholder: 'Enter a conversation starter',
com_sidepanel_agent_builder: 'Agent Builder',
com_agents_name_placeholder: 'Optional: The name of the agent',
com_agents_description_placeholder: 'Optional: Describe your Agent here',
@@ -300,7 +300,7 @@ export default {
com_ui_fork_from_message: 'Select a fork option',
com_ui_mention: 'Mention an endpoint, assistant, or preset to quickly switch to it',
com_ui_add_model_preset: 'Add a model or preset for an additional response',
com_assistants_max_starters_reached: 'Max number of conversation starters reached',
com_agents_max_starters_reached: 'Max number of conversation starters reached',
com_ui_duplication_success: 'Successfully duplicated conversation',
com_ui_duplication_processing: 'Duplicating conversation...',
com_ui_duplication_error: 'There was an error duplicating the conversation',

View File

@@ -681,12 +681,12 @@ export default {
com_click_to_download: '(haga clic aquí para descargar)',
com_assistants_conversation_starters: 'Iniciadores de Conversación',
com_agents_conversation_starters: 'Iniciadores de Conversación',
com_assistants_code_interpreter_info:
'El Intérprete de Código permite al asistente escribir y ejecutar código. Esta herramienta puede procesar archivos con diversos formatos y datos, y generar archivos como gráficos.',
com_assistants_conversation_starters_placeholder: 'Ingrese un iniciador de conversación',
com_agents_conversation_starters_placeholder: 'Ingrese un iniciador de conversación',
com_sidepanel_agent_builder: 'Constructor de Agentes',
@@ -820,7 +820,7 @@ export default {
com_ui_add_model_preset:
'Agregar un modelo o configuración preestablecida para una respuesta adicional',
com_assistants_max_starters_reached: 'Se alcanzó el número máximo de iniciadores de conversación',
com_agents_max_starters_reached: 'Se alcanzó el número máximo de iniciadores de conversación',
com_ui_loading: 'Cargando...',

View File

@@ -778,10 +778,10 @@ export default {
com_download_expired: 'Téléchargement expiré',
com_download_expires: '(cliquez ici pour télécharger - expire le {0})',
com_click_to_download: '(cliquez ici pour télécharger)',
com_assistants_conversation_starters: 'Suggestions de conversation',
com_agents_conversation_starters: 'Suggestions de conversation',
com_assistants_code_interpreter_info:
'L\'interpréteur de code permet à l\'assistant d\'écrire et d\'exécuter du code. Cet outil peut traiter des fichiers avec différents formats de données et générer des fichiers tels que des graphiques.',
com_assistants_conversation_starters_placeholder: 'Saisissez une amorce de conversation',
com_agents_conversation_starters_placeholder: 'Saisissez une amorce de conversation',
com_sidepanel_agent_builder: 'Constructeur d\'agent',
com_agents_name_placeholder: 'Facultatif : Le nom de l\'agent',
com_agents_instructions_placeholder: 'Les instructions système que l\'agent utilise',
@@ -815,7 +815,7 @@ export default {
'Utilisez `{{current_date}}` pour la date actuelle et `{{current_user}}` pour votre nom de compte.',
com_ui_select_search_region: 'Rechercher une région par nom',
com_ui_dropdown_variables: 'Variables déroulantes :',
com_assistants_max_starters_reached: 'Nombre maximum de démarreurs de conversation atteint',
com_agents_max_starters_reached: 'Nombre maximum de démarreurs de conversation atteint',
com_ui_dropdown_variables_info:
'Créez des menus déroulants personnalisés pour vos prompts : `{{nom_variable:option1|option2|option3}}`',
com_ui_revoke_keys: 'Révoquer les clés',

View File

@@ -660,10 +660,10 @@ export default {
com_download_expired: 'download scaduto',
com_download_expires: '(clicca qui per scaricare - scade il {0})',
com_click_to_download: 'clicca qui per scaricare',
com_assistants_conversation_starters: 'Spunti di Conversazione',
com_agents_conversation_starters: 'Spunti di Conversazione',
com_assistants_code_interpreter_info:
'L\'Interprete Codice permette all\'assistente di scrivere ed eseguire codice. Questo strumento può elaborare file con diversi formati e tipi di dati, e generare file come grafici.',
com_assistants_conversation_starters_placeholder: 'Inserisci un argomento di conversazione',
com_agents_conversation_starters_placeholder: 'Inserisci un argomento di conversazione',
com_sidepanel_agent_builder: 'Costruttore Agente',
com_agents_name_placeholder: 'Opzionale: Il nome dell\'agente',
com_agents_description_placeholder: 'Opzionale: Descrivi qui il tuo Agente',
@@ -737,7 +737,7 @@ export default {
com_ui_add_model_preset: 'Aggiungi un modello o una preimpostazione per una risposta aggiuntiva',
com_ui_loading: 'Caricamento...',
com_ui_all_proper: 'Tutto',
com_assistants_max_starters_reached: 'Raggiunto il numero massimo di conversazioni iniziali',
com_agents_max_starters_reached: 'Raggiunto il numero massimo di conversazioni iniziali',
com_ui_revoke_keys: 'Revoca Chiavi',
com_ui_revoke_keys_confirm: 'Sei sicuro di voler revocare tutte le chiavi?',
com_ui_revoke_key_endpoint: 'Revoca Chiave per {0}',

View File

@@ -81,8 +81,8 @@ export default {
com_assistants_update_error: 'アシスタントの更新中にエラーが発生しました。',
com_assistants_create_success: 'アシスタントが正常に作成されました。',
com_assistants_create_error: 'アシスタントの作成中にエラーが発生しました。',
com_assistants_conversation_starters: '会話のきっかけ',
com_assistants_conversation_starters_placeholder: '会話のきっかけを入力してください',
com_agents_conversation_starters: '会話のきっかけ',
com_agents_conversation_starters_placeholder: '会話のきっかけを入力してください',
com_sidepanel_agent_builder: 'エージェントビルダー',
com_agents_name_placeholder: 'オプション: エージェントの名前',
com_agents_description_placeholder: 'オプション: エージェントの説明を入力してください',
@@ -245,7 +245,7 @@ export default {
com_ui_mention:
'エンドポイント、アシスタント、またはプリセットを素早く切り替えるには、それらを言及してください。',
com_ui_add_model_preset: '追加の応答のためのモデルまたはプリセットを追加する',
com_assistants_max_starters_reached: '会話の開始が最大数に達しました',
com_agents_max_starters_reached: '会話の開始が最大数に達しました',
com_ui_regenerate: '再度 生成する',
com_ui_continue: '続きを生成する',
com_ui_edit: '編集',

View File

@@ -987,7 +987,7 @@ export default {
com_click_to_download: '(다운로드하려면 클릭하세요)',
com_assistants_conversation_starters_placeholder: '대화를 시작할 문구를 입력하세요',
com_agents_conversation_starters_placeholder: '대화를 시작할 문구를 입력하세요',
com_download_expires: '(다운로드하려면 클릭하세요 - {0} 후 만료)',
@@ -995,7 +995,7 @@ export default {
com_sidepanel_agent_builder: '에이전트 제작기',
com_assistants_conversation_starters: '대화 시작하기',
com_agents_conversation_starters: '대화 시작하기',
com_agents_instructions_placeholder: '에이전트가 사용하는 시스템 지침',
@@ -1051,7 +1051,7 @@ export default {
com_ui_add_model_preset: '추가 응답을 위한 모델 또는 프리셋 추가',
com_assistants_max_starters_reached: '대화 시작 문구 최대 개수에 도달했습니다',
com_agents_max_starters_reached: '대화 시작 문구 최대 개수에 도달했습니다',
com_ui_revoke_keys: '키 취소',

View File

@@ -669,9 +669,9 @@ export default {
com_assistants_code_interpreter_info:
'Интерпретатор кода позволяет ассистенту создавать и выполнять код. Этот инструмент может обрабатывать файлы с различными данными и форматами, а также создавать файлы, например графики.',
com_assistants_conversation_starters_placeholder: 'Введите начальную фразу для разговора',
com_agents_conversation_starters_placeholder: 'Введите начальную фразу для разговора',
com_assistants_conversation_starters: 'Примеры запросов',
com_agents_conversation_starters: 'Примеры запросов',
com_sidepanel_agent_builder: 'Конструктор агента',
@@ -801,7 +801,7 @@ export default {
com_ui_add_model_preset: 'Добавить модель или пресет для дополнительного ответа',
com_assistants_max_starters_reached: 'Достигнуто максимальное количество начальных подсказок',
com_agents_max_starters_reached: 'Достигнуто максимальное количество начальных подсказок',
com_ui_all_proper: 'Все',

View File

@@ -76,8 +76,8 @@ export default {
com_assistants_update_error: '更新助手时出现错误。',
com_assistants_create_success: '已成功创建',
com_assistants_create_error: '创建助手时出现错误。',
com_assistants_conversation_starters: '对话启动器',
com_assistants_conversation_starters_placeholder: '输入对话启动器',
com_agents_conversation_starters: '对话启动器',
com_agents_conversation_starters_placeholder: '输入对话启动器',
com_sidepanel_agent_builder: '代理构建器',
com_agents_name_placeholder: '可选:代理名称',
com_agents_description_placeholder: '可选:在此描述您的代理',
@@ -232,7 +232,7 @@ export default {
com_ui_fork_from_message: '选择分叉选项',
com_ui_mention: '提及一个端点、助手或预设以快速切换到它',
com_ui_add_model_preset: '添加一个模型或预设以获得额外的回复',
com_assistants_max_starters_reached: '已达到对话启动器的最大数量',
com_agents_max_starters_reached: '已达到对话启动器的最大数量',
com_ui_regenerate: '重新生成',
com_ui_continue: '继续',
com_ui_edit: '编辑',

View File

@@ -597,11 +597,11 @@ export default {
com_error_files_upload_canceled:
'檔案上傳請求已取消。注意:檔案上傳可能仍在處理中,需要手動刪除。',
com_click_to_download: '(點選此處下載)',
com_assistants_conversation_starters_placeholder: '輸入對話開場白',
com_agents_conversation_starters_placeholder: '輸入對話開場白',
com_download_expires: '(點擊此處下載 - {0} 後過期)',
com_sidepanel_agent_builder: '代理建構器',
com_agents_name_placeholder: '選填:代理人的名稱',
com_assistants_conversation_starters: '對話起點',
com_agents_conversation_starters: '對話起點',
com_agents_description_placeholder: '選填:在此描述您的代理程式',
com_assistants_code_interpreter_info:
'程式碼解譯器可讓助理撰寫和執行程式碼。此工具能處理各種資料格式的檔案,並產生圖表等檔案。',
@@ -664,7 +664,7 @@ export default {
com_ui_renaming_var: '重新命名「{0}」',
com_ui_latest_footer: '讓每個人都能使用 AI',
com_ui_upload_invalid: '上傳的檔案無效。必須是不超過限制的圖片檔',
com_assistants_max_starters_reached: '已達對話起始項目的最大數量',
com_agents_max_starters_reached: '已達對話起始項目的最大數量',
com_ui_add_model_preset: '新增模型或預設設定以取得額外回應',
com_ui_upload_invalid_var: '上傳的檔案無效。必須是不超過 {0} MB 的圖片檔案',
com_ui_loading: '載入中...',

View File

@@ -1151,7 +1151,7 @@ export enum Constants {
/** Saved Tag */
SAVED_TAG = 'Saved',
/** Max number of Conversation starters for Agents/Assistants */
MAX_CONVO_STARTERS = 4,
MAX_CONVO_STARTERS = 64,
/** Global/instance Project Name */
GLOBAL_PROJECT_NAME = 'instance',
/** Delimiter for MCP tools */

View File

@@ -146,6 +146,7 @@ export const defaultAgentFormValues = {
instructions: '',
model: '',
model_parameters: {},
conversation_starters: [],
tools: [],
provider: {},
projectIds: [],

View File

@@ -229,6 +229,7 @@ export type AgentCreateParams = {
provider: AgentProvider;
model: string | null;
model_parameters: AgentModelParameters;
conversation_starters?: string[];
} & Pick<Agent, 'agent_ids' | 'end_after_tools' | 'hide_sequential_outputs'>;
export type AgentUpdateParams = {
@@ -242,6 +243,7 @@ export type AgentUpdateParams = {
provider?: AgentProvider;
model?: string | null;
model_parameters?: AgentModelParameters;
conversation_starters?: string[] | null;
projectIds?: string[];
removeProjectIds?: string[];
isCollaborative?: boolean;