🎉 feat: Code Interpreter API and Agents Release (#4860)

* feat: Code Interpreter API & File Search Agent Uploads

chore: add back code files

wip: first pass, abstract key dialog

refactor: influence checkbox on key changes

refactor: update localization keys for 'execute code' to 'run code'

wip: run code button

refactor: add throwError parameter to loadAuthValues and getUserPluginAuthValue functions

feat: first pass, API tool calling

fix: handle missing toolId in callTool function and return 404 for non-existent tools

feat: show code outputs

fix: improve error handling in callTool function and log errors

fix: handle potential null value for filepath in attachment destructuring

fix: normalize language before rendering and prevent null return

fix: add loading indicator in RunCode component while executing code

feat: add support for conditional code execution in Markdown components

feat: attachments

refactor: remove bash

fix: pass abort signal to graph/run

refactor: debounce and rate limit tool call

refactor: increase debounce delay for execute function

feat: set code output attachments

feat: image attachments

refactor: apply message context

refactor: pass `partIndex`

feat: toolCall schema/model/methods

feat: block indexing

feat: get tool calls

chore: imports

chore: typing

chore: condense type imports

feat: get tool calls

fix: block indexing

chore: typing

refactor: update tool calls mapping to support multiple results

fix: add unique key to nav link for rendering

wip: first pass, tool call results

refactor: update query cache from successful tool call mutation

style: improve result switcher styling

chore: note on using \`.toObject()\`

feat: add agent_id field to conversation schema

chore: typing

refactor: rename agentMap to agentsMap for consistency

feat: Agent Name as chat input placeholder

chore: bump agents

📦 chore: update @langchain dependencies to latest versions to match agents package

📦 chore: update @librechat/agents dependency to version 1.8.0

fix: Aborting agent stream removes sender; fix(bedrock): completion removes preset name label

refactor: remove direct file parameter to use req.file, add `processAgentFileUpload` for image uploads

feat: upload menu

feat: prime message_file resources

feat: implement conversation access validation in chat route

refactor: remove file parameter from processFileUpload and use req.file instead

feat: add savedMessageIds set to track saved message IDs in BaseClient, to prevent unnecessary double-write to db

feat: prevent duplicate message saves by checking savedMessageIds in AgentController

refactor: skip legacy RAG API handling for agents

feat: add files field to convoSchema

refactor: update request type annotations from Express.Request to ServerRequest in file processing functions

feat: track conversation files

fix: resendFiles, addPreviousAttachments handling

feat: add ID validation for session_id and file_id in download route

feat: entity_id for code file uploads/downloads

fix: code file edge cases

feat: delete related tool calls

feat: add stream rate handling for LLM configuration

feat: enhance system content with attached file information

fix: improve error logging in resource priming function

* WIP: PoC, sequential agents

WIP: PoC Sequential Agents, first pass content data + bump agents package

fix: package-lock

WIP: PoC, o1 support, refactor bufferString

feat: convertJsonSchemaToZod

fix: form issues and schema defining erroneous model

fix: max length issue on agent form instructions, limit conversation messages to sequential agents

feat: add abort signal support to createRun function and AgentClient

feat: PoC, hide prior sequential agent steps

fix: update parameter naming from config to metadata in event handlers for clarity, add model to usage data

refactor: use only last contentData, track model for usage data

chore: bump agents package

fix: content parts issue

refactor: filter contentParts to include tool calls and relevant indices

feat: show function calls

refactor: filter context messages to exclude tool calls when no tools are available to the agent

fix: ensure tool call content is not undefined in formatMessages

feat: add agent_id field to conversationPreset schema

feat: hide sequential agents

feat: increase upload toast duration to 10 seconds

* refactor: tool context handling & update Code API Key Dialog

feat: toolContextMap

chore: skipSpecs -> useSpecs

ci: fix handleTools tests

feat: API Key Dialog

* feat: Agent Permissions Admin Controls

feat: replace label with button for prompt permission toggle

feat: update agent permissions

feat: enable experimental agents and streamline capability configuration

feat: implement access control for agents and enhance endpoint menu items

feat: add welcome message for agent selection in localization

feat: add agents permission to access control and update version to 0.7.57

* fix: update types in useAssistantListMap and useMentions hooks for better null handling

* feat: mention agents

* fix: agent tool resource race conditions when deleting agent tool resource files

* feat: add error handling for code execution with user feedback

* refactor: rename AdminControls to AdminSettings for clarity

* style: add gap to button in AdminSettings for improved layout

* refactor: separate agent query hooks and check access to enable fetching

* fix: remove unused provider from agent initialization options, creates issue with custom endpoints

* refactor: remove redundant/deprecated modelOptions from AgentClient processes

* chore: update @librechat/agents to version 1.8.5 in package.json and package-lock.json

* fix: minor styling issues + agent panel uniformity

* fix: agent edge cases when set endpoint is no longer defined

* refactor: remove unused cleanup function call from AppService

* fix: update link in ApiKeyDialog to point to pricing page

* fix: improve type handling and layout calculations in SidePanel component

* fix: add missing localization string for agent selection in SidePanel

* chore: form styling and localizations for upload filesearch/code interpreter

* fix: model selection placeholder logic in AgentConfig component

* style: agent capabilities

* fix: add localization for provider selection and improve dropdown styling in ModelPanel

* refactor: use gpt-4o-mini > gpt-3.5-turbo

* fix: agents configuration for loadDefaultInterface and update related tests

* feat: DALLE Agents support
This commit is contained in:
Danny Avila 2024-12-04 15:48:13 -05:00 committed by GitHub
parent affcebd48c
commit 1a815f5e19
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
189 changed files with 5056 additions and 1815 deletions

View file

@ -1,38 +1,39 @@
import { useState } from 'react';
import { KeyRoundIcon } from 'lucide-react';
import { AuthType, AgentCapabilities } from 'librechat-data-provider';
import { useFormContext, Controller, useForm, useWatch } from 'react-hook-form';
import { useFormContext, Controller, useWatch } from 'react-hook-form';
import type { AgentForm } from '~/common';
import {
Input,
OGDialog,
Checkbox,
HoverCard,
HoverCardContent,
HoverCardPortal,
HoverCardTrigger,
Button,
} from '~/components/ui';
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
import { useLocalize, useAuthCodeTool } from '~/hooks';
import { useLocalize, useCodeApiKeyForm } from '~/hooks';
import { CircleHelpIcon } from '~/components/svg';
import ApiKeyDialog from './ApiKeyDialog';
import { ESide } from '~/common';
type ApiKeyFormData = {
apiKey: string;
authType?: string | AuthType;
};
export default function Action({ authType = '', isToolAuthenticated = false }) {
const localize = useLocalize();
const methods = useFormContext<AgentForm>();
const { control, setValue, getValues } = methods;
const [isDialogOpen, setIsDialogOpen] = useState(false);
const {
onSubmit,
isDialogOpen,
setIsDialogOpen,
handleRevokeApiKey,
methods: keyFormMethods,
} = useCodeApiKeyForm({
onSubmit: () => {
setValue(AgentCapabilities.execute_code, true, { shouldDirty: true });
},
onRevoke: () => {
setValue(AgentCapabilities.execute_code, false, { shouldDirty: true });
},
});
const runCodeIsEnabled = useWatch({ control, name: AgentCapabilities.execute_code });
const { installTool, removeTool } = useAuthCodeTool({ isEntityTool: true });
const { reset, register, handleSubmit } = useForm<ApiKeyFormData>();
const isUserProvided = authType === AuthType.USER_PROVIDED;
const handleCheckboxChange = (checked: boolean) => {
@ -45,18 +46,6 @@ export default function Action({ authType = '', isToolAuthenticated = false }) {
}
};
const onSubmit = (data: { apiKey: string }) => {
reset();
installTool(data.apiKey);
setIsDialogOpen(false);
};
const handleRevokeApiKey = () => {
reset();
removeTool();
setIsDialogOpen(false);
};
return (
<>
<HoverCard openDelay={50}>
@ -87,7 +76,7 @@ export default function Action({ authType = '', isToolAuthenticated = false }) {
className="form-check-label text-token-text-primary w-full cursor-pointer"
htmlFor={AgentCapabilities.execute_code}
>
{localize('com_agents_execute_code')}
{localize('com_ui_run_code')}
</label>
</button>
<div className="ml-2 flex gap-2">
@ -104,48 +93,23 @@ export default function Action({ authType = '', isToolAuthenticated = false }) {
<HoverCardContent side={ESide.Top} className="w-80">
<div className="space-y-2">
<p className="text-sm text-text-secondary">
{/* // TODO: add a Code Interpreter description */}
{localize('com_agents_code_interpreter')}
</p>
</div>
</HoverCardContent>
</HoverCardPortal>
</div>
</HoverCard>
<OGDialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<OGDialogTemplate
className="w-11/12 sm:w-1/4"
title={localize('com_agents_tool_not_authenticated')}
main={
<form onSubmit={handleSubmit(onSubmit)}>
<Input
type="password"
placeholder="Enter API Key"
autoComplete="one-time-code"
readOnly={true}
onFocus={(e) => (e.target.readOnly = false)}
{...register('apiKey', { required: true })}
/>
</form>
}
selection={{
selectHandler: handleSubmit(onSubmit),
selectClasses: 'bg-green-500 hover:bg-green-600 text-white',
selectText: localize('com_ui_save'),
}}
buttons={
isUserProvided &&
isToolAuthenticated && (
<Button
onClick={handleRevokeApiKey}
className="bg-destructive text-white transition-all duration-200 hover:bg-destructive/80"
>
{localize('com_ui_revoke')}
</Button>
)
}
showCancelButton={true}
/>
</OGDialog>
<ApiKeyDialog
isOpen={isDialogOpen}
onSubmit={onSubmit}
onRevoke={handleRevokeApiKey}
onOpenChange={setIsDialogOpen}
register={keyFormMethods.register}
isToolAuthenticated={isToolAuthenticated}
handleSubmit={keyFormMethods.handleSubmit}
isUserProvided={authType === AuthType.USER_PROVIDED}
/>
</>
);
}

View file

@ -0,0 +1,106 @@
import type { UseFormRegister, UseFormHandleSubmit } from 'react-hook-form';
import type { ApiKeyFormData } from '~/common';
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
import { Input, Button, OGDialog } from '~/components/ui';
import { useLocalize } from '~/hooks';
export default function ApiKeyDialog({
isOpen,
onSubmit,
onRevoke,
onOpenChange,
isUserProvided,
isToolAuthenticated,
register,
handleSubmit,
}: {
isOpen: boolean;
onOpenChange: (open: boolean) => void;
onSubmit: (data: { apiKey: string }) => void;
onRevoke: () => void;
isUserProvided: boolean;
isToolAuthenticated: boolean;
register: UseFormRegister<ApiKeyFormData>;
handleSubmit: UseFormHandleSubmit<ApiKeyFormData>;
}) {
const localize = useLocalize();
const languageIcons = [
'python.svg',
'nodedotjs.svg',
'tsnode.svg',
'rust.svg',
'go.svg',
'c.svg',
'cplusplus.svg',
'php.svg',
'fortran.svg',
];
return (
<OGDialog open={isOpen} onOpenChange={onOpenChange}>
<OGDialogTemplate
className="w-11/12 sm:w-[450px]"
title=""
main={
<>
<div className="mb-4 text-center font-medium">
{localize('com_ui_librechat_code_api_title')}
</div>
<div className="mb-4 text-center text-sm">
{localize('com_ui_librechat_code_api_subtitle')}
</div>
{/* Language Icons Stack */}
<div className="mb-6">
<div className="mx-auto mb-4 flex max-w-[400px] flex-wrap justify-center gap-3">
{languageIcons.map((icon) => (
<div key={icon} className="h-6 w-6">
<img
src={`/assets/${icon}`}
alt=""
className="h-full w-full object-contain opacity-[0.85] dark:invert"
/>
</div>
))}
</div>
<a
href="https://code.librechat.ai/pricing"
target="_blank"
rel="noopener noreferrer"
className="block text-center text-[15px] font-medium text-blue-500 underline decoration-1 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300"
>
{localize('com_ui_librechat_code_api_key')}
</a>
</div>
<form onSubmit={handleSubmit(onSubmit)}>
<Input
type="password"
placeholder={localize('com_ui_enter_api_key')}
autoComplete="one-time-code"
readOnly={true}
onFocus={(e) => (e.target.readOnly = false)}
{...register('apiKey', { required: true })}
/>
</form>
</>
}
selection={{
selectHandler: handleSubmit(onSubmit),
selectClasses: 'bg-green-500 hover:bg-green-600 text-white',
selectText: localize('com_ui_save'),
}}
buttons={
isUserProvided &&
isToolAuthenticated && (
<Button
onClick={onRevoke}
className="bg-destructive text-white transition-all duration-200 hover:bg-destructive/80"
>
{localize('com_ui_revoke')}
</Button>
)
}
showCancelButton={true}
/>
</OGDialog>
);
}

View file

@ -12,6 +12,7 @@ import type { ExtendedFile, AgentForm } from '~/common';
import { useFileHandling, useLocalize, useLazyEffect } from '~/hooks';
import FileRow from '~/components/Chat/Input/Files/FileRow';
import { useGetFileConfig } from '~/data-provider';
import { AttachmentIcon } from '~/components/svg';
import { useChatContext } from '~/Providers';
const tool_resource = EToolResources.execute_code;
@ -68,8 +69,8 @@ export default function Files({
return (
<div className="mb-2 w-full">
<div className="flex flex-col gap-4">
<div className="text-token-text-tertiary rounded-lg text-xs">
<div className="flex flex-col gap-3">
<div className="rounded-lg text-xs text-text-secondary">
{localize('com_assistants_code_interpreter_files')}
</div>
<FileRow
@ -85,10 +86,10 @@ export default function Files({
<button
type="button"
disabled={!agent_id || codeChecked === false}
className="btn btn-neutral border-token-border-light relative h-8 w-full rounded-lg font-medium"
className="btn btn-neutral border-token-border-light relative h-9 w-full rounded-lg font-medium"
onClick={handleButtonClick}
>
<div className="flex w-full items-center justify-center gap-2">
<div className="flex w-full items-center justify-center gap-1">
<input
multiple={true}
type="file"
@ -98,7 +99,8 @@ export default function Files({
disabled={!agent_id || codeChecked === false}
onChange={handleFileChange}
/>
{localize('com_ui_upload_files')}
<AttachmentIcon className="text-token-text-primary h-4 w-4" />
{localize('com_ui_upload_code_files')}
</div>
</button>
</div>

View file

@ -16,13 +16,18 @@ export default function CodeForm({
const { data } = useVerifyAgentToolAuth({ toolId: Tools.execute_code });
return (
<div className="mb-4">
<div className="mb-1.5 flex items-center">
<span>
<label className="text-token-text-primary block font-medium">
{localize('com_assistants_capabilities')}
</label>
</span>
<div className="w-full">
<div className="mb-1.5 flex items-center gap-2">
<div className="flex flex-row items-center gap-1">
<div className="flex items-center gap-1">
<span className="text-token-text-primary block font-medium">
{localize('com_agents_code_interpreter_title')}
</span>
<span className="text-xs text-text-secondary">
{localize('com_agents_by_librechat')}
</span>
</div>
</div>
</div>
<div className="flex flex-col items-start gap-2">
<Action authType={data?.message} isToolAuthenticated={data?.authenticated} />