🚧 chore: merge latest dev build (#4288)

* fix: agent initialization, add `collectedUsage` handling

* style: improve side panel styling

* refactor(loadAgent): Optimize order agent project ID retrieval

* feat: code execution

* fix: typing issues

* feat: ExecuteCode content part

* refactor: use local state for default collapsed state of analysis content parts

* fix: code parsing in ExecuteCode component

* chore: bump agents package, export loadAuthValues

* refactor: Update handleTools.js to use EnvVar for code execution tool authentication

* WIP

* feat: download code outputs

* fix(useEventHandlers): type issues

* feat: backend handling for code outputs

* Refactor: Remove console.log statement in Part.tsx

* refactor: add attachments to TMessage/messageSchema

* WIP: prelim handling for code outputs

* feat: attachments rendering

* refactor: improve attachments rendering

* fix: attachments, nullish edge case, handle attachments from event stream, bump agents package

* fix filename download

* fix: tool assignment for 'run code' on agent creation

* fix: image handling by adding attachments

* refactor: prevent agent creation without provider/model

* refactor: remove unnecessary space in agent creation success message

* refactor: select first model if selecting provider from empty on form

* fix: Agent avatar bug

* fix: `defaultAgentFormValues` causing boolean typing issue and typeerror

* fix: capabilities counting as tools, causing duplication of them

* fix: formatted messages edge case where consecutive content text type parts with the latter having tool_call_ids would cause consecutive AI messages to be created. furthermore, content could not be an array for tool_use messages (anthropic limitation)

* chore: bump @librechat/agents dependency to version 1.6.9

* feat: bedrock agents

* feat: new Agents icon

* feat: agent titling

* feat: agent landing

* refactor: allow sharing agent globally only if user is admin or author

* feat: initial AgentPanelSkeleton

* feat: AgentPanelSkeleton

* feat: collaborative agents

* chore: add potential authorName as part of schema

* chore: Remove unnecessary console.log statement

* WIP: agent model parameters

* chore: ToolsDialog typing and tool related localization chnages

* refactor: update tool instance type (latest langchain class), and rename google tool to 'google' proper

* chore: add back tools

* feat: Agent knowledge files upload

* refactor: better verbiage for disabled knowledge

* chore: debug logs for file deletions

* chore: debug logs for file deletions

* feat: upload/delete agent knowledge/file-search files

* feat: file search UI for agents

* feat: first pass, file search tool

* chore: update default agent capabilities and info
This commit is contained in:
Danny Avila 2024-09-30 17:17:57 -04:00 committed by GitHub
parent f33e75e2ee
commit ad74350036
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
123 changed files with 3611 additions and 1541 deletions

View file

@ -1,13 +1,18 @@
import { useEffect, useMemo } from 'react';
import React, { useMemo, useEffect } from 'react';
import { ChevronLeft } from 'lucide-react';
import { Controller, useFormContext } from 'react-hook-form';
import type { AgentForm, AgentModelPanelProps } from '~/common';
import { SelectDropDown, ModelParameters } from '~/components/ui';
import { cn, cardStyle } from '~/utils';
import { getSettingsKeys } from 'librechat-data-provider';
import { useFormContext, Controller } from 'react-hook-form';
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
import type * as t from 'librechat-data-provider';
import type { AgentForm, AgentModelPanelProps, StringOption } from '~/common';
import { componentMapping } from '~/components/SidePanel/Parameters/components';
import { agentSettings } from '~/components/SidePanel/Parameters/settings';
import { getEndpointField, cn, cardStyle } from '~/utils';
import { SelectDropDown } from '~/components/ui';
import { useLocalize } from '~/hooks';
import { Panel } from '~/common';
export default function ModelPanel({
export default function Parameters({
setActivePanel,
providers,
models: modelsData,
@ -15,30 +20,56 @@ export default function ModelPanel({
const localize = useLocalize();
const { control, setValue, watch } = useFormContext<AgentForm>();
const model = watch('model');
const modelParameters = watch('model_parameters');
const providerOption = watch('provider');
const model = watch('model');
const provider = useMemo(() => {
if (!providerOption) {
return '';
}
return typeof providerOption === 'string' ? providerOption : providerOption.value;
const value =
typeof providerOption === 'string'
? providerOption
: (providerOption as StringOption | undefined)?.value;
return value ?? '';
}, [providerOption]);
const models = useMemo(() => (provider ? modelsData[provider] : []), [modelsData, provider]);
useEffect(() => {
if (provider && model) {
const modelExists = models.includes(model);
const _model = model ?? '';
if (provider && _model) {
const modelExists = models.includes(_model);
if (!modelExists) {
const newModels = modelsData[provider];
setValue('model', newModels[0] ?? '');
}
}
if (provider && !_model) {
setValue('model', models[0] ?? '');
}
}, [provider, models, modelsData, setValue, model]);
const { data: endpointsConfig } = useGetEndpointsQuery();
const bedrockRegions = useMemo(() => {
return endpointsConfig?.[provider]?.availableRegions ?? [];
}, [endpointsConfig, provider]);
const endpointType = useMemo(
() => getEndpointField(endpointsConfig, provider, 'type'),
[provider, endpointsConfig],
);
const parameters = useMemo(() => {
const [combinedKey, endpointKey] = getSettingsKeys(endpointType ?? provider, model ?? '');
return agentSettings[combinedKey] ?? agentSettings[endpointKey];
}, [endpointType, model, provider]);
const setOption = (optionKey: keyof t.AgentModelParameters) => (value: t.AgentParameterValue) => {
setValue(`model_parameters.${optionKey}`, value);
};
return (
<div className="h-full overflow-auto px-2 pb-12 text-sm">
<div className="scrollbar-gutter-stable h-full min-h-[50vh] overflow-auto pb-12 text-sm">
<div className="model-panel relative flex flex-col items-center px-16 py-6 text-center">
<div className="absolute left-0 top-6">
<button
@ -56,228 +87,125 @@ export default function ModelPanel({
<div className="mb-2 mt-2 text-xl font-medium">{localize('com_ui_model_parameters')}</div>
</div>
{/* Endpoint aka Provider for Agents */}
<div className="mb-4">
<label
className="text-token-text-primary model-panel-label mb-2 block font-medium"
htmlFor="provider"
>
{localize('com_ui_provider')} <span className="text-red-500">*</span>
</label>
<Controller
name="provider"
control={control}
rules={{ required: true, minLength: 1 }}
render={({ field, fieldState: { error } }) => (
<>
<SelectDropDown
emptyTitle={true}
value={field.value ?? ''}
placeholder={localize('com_ui_select_provider')}
setValue={field.onChange}
availableValues={providers}
showAbove={false}
showLabel={false}
className={cn(
cardStyle,
'flex h-[40px] w-full flex-none items-center justify-center border-none px-4 hover:cursor-pointer',
!field.value && 'border-2 border-yellow-400',
<div className="p-2">
{/* Endpoint aka Provider for Agents */}
<div className="mb-4">
<label
className="text-token-text-primary model-panel-label mb-2 block font-medium"
htmlFor="provider"
>
{localize('com_ui_provider')} <span className="text-red-500">*</span>
</label>
<Controller
name="provider"
control={control}
rules={{ required: true, minLength: 1 }}
render={({ field, fieldState: { error } }) => (
<>
<SelectDropDown
emptyTitle={true}
value={field.value ?? ''}
placeholder={localize('com_ui_select_provider')}
setValue={field.onChange}
availableValues={providers}
showAbove={false}
showLabel={false}
className={cn(
cardStyle,
'flex h-[40px] w-full flex-none items-center justify-center border-none px-4 hover:cursor-pointer',
(field.value === undefined || field.value === '') &&
'border-2 border-yellow-400',
)}
containerClassName={cn('rounded-md', error ? 'border-red-500 border-2' : '')}
/>
{error && (
<span className="model-panel-error text-sm text-red-500 transition duration-300 ease-in-out">
{localize('com_ui_field_required')}
</span>
)}
containerClassName={cn('rounded-md', error ? 'border-red-500 border-2' : '')}
/>
{error && (
<span className="model-panel-error text-sm text-red-500 transition duration-300 ease-in-out">
{localize('com_ui_field_required')}
</span>
)}
</>
)}
/>
</div>
{/* Model */}
<div className="model-panel-section mb-6">
<label
className={cn(
'text-token-text-primary model-panel-label mb-2 block font-medium',
!provider && 'text-gray-500 dark:text-gray-400',
)}
htmlFor="model"
>
{localize('com_ui_model')} <span className="text-red-500">*</span>
</label>
<Controller
name="model"
control={control}
rules={{ required: true, minLength: 1 }}
render={({ field, fieldState: { error } }) => (
<>
<SelectDropDown
emptyTitle={true}
placeholder={
provider
? localize('com_ui_select_model')
: localize('com_ui_select_provider_first')
}
value={field.value}
setValue={field.onChange}
availableValues={models}
showAbove={false}
showLabel={false}
disabled={!provider}
className={cn(
cardStyle,
'flex h-[40px] w-full flex-none items-center justify-center border-none px-4',
!provider ? 'cursor-not-allowed bg-gray-200' : 'hover:cursor-pointer',
</>
)}
/>
</div>
{/* Model */}
<div className="model-panel-section mb-4">
<label
className={cn(
'text-token-text-primary model-panel-label mb-2 block font-medium',
!provider && 'text-gray-500 dark:text-gray-400',
)}
htmlFor="model"
>
{localize('com_ui_model')} <span className="text-red-500">*</span>
</label>
<Controller
name="model"
control={control}
rules={{ required: true, minLength: 1 }}
render={({ field, fieldState: { error } }) => (
<>
<SelectDropDown
emptyTitle={true}
placeholder={
provider
? localize('com_ui_select_model')
: localize('com_ui_select_provider_first')
}
value={field.value}
setValue={field.onChange}
availableValues={models}
showAbove={false}
showLabel={false}
disabled={!provider}
className={cn(
cardStyle,
'flex h-[40px] w-full flex-none items-center justify-center border-none px-4',
!provider ? 'cursor-not-allowed bg-gray-200' : 'hover:cursor-pointer',
)}
containerClassName={cn('rounded-md', error ? 'border-red-500 border-2' : '')}
/>
{provider && error && (
<span className="text-sm text-red-500 transition duration-300 ease-in-out">
{localize('com_ui_field_required')}
</span>
)}
containerClassName={cn('rounded-md', error ? 'border-red-500 border-2' : '')}
/>
{provider && error && (
<span className="text-sm text-red-500 transition duration-300 ease-in-out">
{localize('com_ui_field_required')}
</span>
)}
</>
)}
/>
</div>
<div className="mb-4">
<Controller
name="model_parameters.temperature"
control={control}
rules={{ required: false }}
render={({ field }) => (
<>
<ModelParameters
label="com_endpoint_temperature"
ariaLabel="Temperature"
min={-2}
max={2}
step={0.01}
stepClick={0.01}
initialValue={field.value ?? 1}
onChange={field.onChange}
showButtons={true}
disabled={!provider}
/>
</>
)}
/>
</div>
<div className="mb-4">
<Controller
name="model_parameters.max_context_tokens"
control={control}
rules={{ required: false }}
render={({ field }) => (
<>
<ModelParameters
label="com_endpoint_max_output_tokens"
ariaLabel="Max Context Tokens"
min={0}
max={4096}
step={1}
stepClick={1}
initialValue={field.value ?? 0}
onChange={field.onChange}
showButtons={true}
disabled={!provider}
/>
</>
)}
/>
</div>
<div className="mb-4">
<Controller
name="model_parameters.max_output_tokens"
control={control}
rules={{ required: false }}
render={({ field }) => (
<>
<ModelParameters
label="com_endpoint_context_tokens"
ariaLabel="Max Context Tokens"
min={0}
max={4096}
step={1}
stepClick={1}
initialValue={field.value ?? 0}
onChange={field.onChange}
showButtons={true}
disabled={!provider}
/>
</>
)}
/>
</div>
<div className="mb-4">
<Controller
name="model_parameters.top_p"
control={control}
rules={{ required: false }}
render={({ field }) => (
<>
<ModelParameters
label="com_endpoint_top_p"
ariaLabel="Top P"
min={-2}
max={2}
step={0.01}
stepClick={0.01}
initialValue={field.value ?? 1}
onChange={field.onChange}
showButtons={true}
disabled={!provider}
/>
</>
)}
/>
</div>
<div className="mb-4">
<Controller
name="model_parameters.frequency_penalty"
control={control}
rules={{ required: false }}
render={({ field }) => (
<>
<ModelParameters
label="com_endpoint_frequency_penalty"
ariaLabel="Frequency Penalty"
min={-2}
max={2}
step={0.01}
stepClick={0.01}
initialValue={field.value ?? 0}
onChange={field.onChange}
showButtons={true}
disabled={!provider}
/>
</>
)}
/>
</div>
<div className="mb-4">
<Controller
name="model_parameters.presence_penalty"
control={control}
rules={{ required: false }}
render={({ field }) => (
<>
<ModelParameters
label="com_endpoint_presence_penalty"
ariaLabel="Presence Penalty"
min={-2}
max={2}
step={0.01}
stepClick={0.01}
initialValue={field.value ?? 0}
onChange={field.onChange}
showButtons={true}
disabled={!provider}
/>
</>
)}
/>
</>
)}
/>
</div>
</div>
{/* Model Parameters */}
{parameters && (
<div className="h-auto max-w-full overflow-x-hidden p-2">
<div className="grid grid-cols-4 gap-6">
{' '}
{/* This is the parent element containing all settings */}
{/* Below is an example of an applied dynamic setting, each be contained by a div with the column span specified */}
{parameters.map((setting) => {
const Component = componentMapping[setting.component];
if (!Component) {
return null;
}
const { key, default: defaultValue, ...rest } = setting;
if (key === 'region' && bedrockRegions.length) {
rest.options = bedrockRegions;
}
return (
<Component
key={key}
settingKey={key}
defaultValue={defaultValue}
{...rest}
setOption={setOption as t.TSetOption}
conversation={modelParameters as Partial<t.TConversation>}
/>
);
})}
</div>
</div>
)}
</div>
);
}