👐 refactor: Agents Accessibility and Gemini Error Handling (#5972)

* style: Enhance ControlCombobox with Carat Display, ClassName, and Disabled State

* refactor(ModelPanel): replace SelectDropdown with ControlCombobox for improved accessibility

* style: Adjust padding and positioning in ModelPanel for improved layout

* style(ControlCombobox): add containerClassName and iconSide props for enhanced customization

* style(ControlCombobox): add iconClassName prop for customizable icon styling

* refactor(AgentPanel): enhance layout with new button for creating agents and adjust structure for better alignment

* refactor(AgentSelect): replace SelectDropDown with ControlCombobox for improved accessibility and layout

* feat(translation): add new translation key for improved UI clarity

* style(AgentSwitcher, AssistantSwitcher): add iconClassName prop for customizable icon styling

* refactor(AgentPanelSkeleton): improve layout of skeleton components to match new visual structure

* style(AgentPanel, AgentPanelSkeleton): add margin to flex container for improved layout consistency

* a11y(AgentSelect, ControlCombobox): add selectId prop for preventing focus going to start to page after agent selection

* fix(AgentSelect): update SELECT_ID constant for improved clarity in component identification

* fix(GoogleClient): update type annotation, add abort handling for content generation requests, catch "uncaught" abort errors and GoogleGenerativeAI errors from `@google/generative-ai`
This commit is contained in:
Danny Avila 2025-02-21 15:02:07 -05:00 committed by GitHub
parent 1e625f7557
commit fc733d2b9e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 227 additions and 150 deletions

View file

@ -1,16 +1,17 @@
import { Plus, EarthIcon } from 'lucide-react';
import { EarthIcon } from 'lucide-react';
import { useCallback, useEffect, useRef } from 'react';
import { AgentCapabilities, defaultAgentFormValues } from 'librechat-data-provider';
import type { UseMutationResult, QueryObserverResult } from '@tanstack/react-query';
import type { Agent, AgentCreateParams } from 'librechat-data-provider';
import type { UseFormReset } from 'react-hook-form';
import type { TAgentCapabilities, AgentForm, TAgentOption } from '~/common';
import { cn, createDropdownSetter, createProviderOption, processAgentOption } from '~/utils';
import { useListAgentsQuery, useGetStartupConfig } from '~/data-provider';
import SelectDropDown from '~/components/ui/SelectDropDown';
import { cn, createProviderOption, processAgentOption } from '~/utils';
import ControlCombobox from '~/components/ui/ControlCombobox';
import { useLocalize } from '~/hooks';
const keys = new Set(Object.keys(defaultAgentFormValues));
const SELECT_ID = 'agent-builder-combobox';
export default function AgentSelect({
reset,
@ -120,6 +121,9 @@ export default function AgentSelect({
}
resetAgentForm(agent);
setTimeout(() => {
document.getElementById(SELECT_ID)?.focus();
}, 5);
},
[agents, createMutation, setCurrentAgentId, agentQuery.data, resetAgentForm, reset],
);
@ -152,51 +156,36 @@ export default function AgentSelect({
}, [selectedAgentId, agents, onSelect]);
const createAgent = localize('com_ui_create') + ' ' + localize('com_ui_agent');
const hasAgentValue = !!(typeof currentAgentValue === 'object'
? currentAgentValue.value != null && currentAgentValue.value !== ''
: typeof currentAgentValue !== 'undefined');
return (
<SelectDropDown
value={!hasAgentValue ? createAgent : (currentAgentValue as TAgentOption)}
setValue={createDropdownSetter(onSelect)}
availableValues={
agents ?? [
<ControlCombobox
selectId={SELECT_ID}
containerClassName="px-0"
selectedValue={(currentAgentValue?.value ?? '') + ''}
displayValue={currentAgentValue?.label ?? ''}
selectPlaceholder={createAgent}
iconSide="right"
searchPlaceholder={localize('com_agents_search_name')}
SelectIcon={currentAgentValue?.icon}
setValue={onSelect}
items={
agents?.map((agent) => ({
label: agent.name ?? '',
value: agent.id ?? '',
icon: agent.icon,
})) ?? [
{
label: 'Loading...',
value: '',
},
]
}
iconSide="left"
optionIconSide="right"
showAbove={false}
showLabel={false}
emptyTitle={true}
showOptionIcon={true}
containerClassName="flex-grow"
searchClassName="dark:from-gray-850"
searchPlaceholder={localize('com_agents_search_name')}
optionsClass="hover:bg-gray-20/50 dark:border-gray-700"
optionsListClass="rounded-lg shadow-lg dark:bg-gray-850 dark:border-gray-700 dark:last:border"
currentValueClass={cn(
'text-md font-semibold text-gray-900 dark:text-white',
hasAgentValue ? 'text-gray-500' : '',
)}
className={cn(
'rounded-md dark:border-gray-700 dark:bg-gray-850',
'z-50 flex h-[40px] w-full flex-none items-center justify-center truncate px-4 hover:cursor-pointer hover:border-green-500 focus:border-gray-400',
)}
renderOption={() => (
<span className="flex items-center gap-1.5 truncate">
<span className="absolute inset-y-0 left-0 flex items-center pl-2 text-gray-800 dark:text-gray-100">
<Plus className="w-[16px]" />
</span>
<span className={cn('ml-4 flex h-6 items-center gap-1 text-gray-800 dark:text-gray-100')}>
{createAgent}
</span>
</span>
'z-50 flex h-[40px] w-full flex-none items-center justify-center truncate rounded-md bg-transparent font-bold',
)}
ariaLabel={localize('com_ui_agent')}
isCollapsed={false}
showCarat={true}
/>
);
}