🔁 refactor: Capabilities for Tools/File handling for Direct Endpoints (#8253)

* feat: add useAgentCapabilities hook to manage agent capabilities

* refactor: move  agents and endpoints configuration to AgentPanel context provider

* refactor: implement useGetAgentsConfig hook for consolidated agents and endpoints management

* refactor: enhance ToolsDropdown to utilize agent capabilities and streamline dropdown item rendering

* chore: reorder return values in useAgentCapabilities for improved clarity

* refactor: enhance agent capabilities handling in AttachFileMenu and update file handling logic to allow capabilities to be used for non-agents endpoints
This commit is contained in:
Danny Avila 2025-07-04 14:51:26 -04:00 committed by GitHub
parent a288ad1d9c
commit f5511e4a4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 308 additions and 250 deletions

View file

@ -2,20 +2,20 @@ import { useMemo } from 'react';
import { ChevronLeft } from 'lucide-react';
import { AgentCapabilities } from 'librechat-data-provider';
import { useFormContext, Controller } from 'react-hook-form';
import type { AgentForm, AgentPanelProps } from '~/common';
import type { AgentForm } from '~/common';
import { useAgentPanelContext } from '~/Providers';
import MaxAgentSteps from './MaxAgentSteps';
import AgentChain from './AgentChain';
import { useLocalize } from '~/hooks';
import AgentChain from './AgentChain';
import { Panel } from '~/common';
export default function AdvancedPanel({
agentsConfig,
setActivePanel,
}: Pick<AgentPanelProps, 'setActivePanel' | 'agentsConfig'>) {
export default function AdvancedPanel() {
const localize = useLocalize();
const methods = useFormContext<AgentForm>();
const { control, watch } = methods;
const currentAgentId = watch('id');
const { agentsConfig, setActivePanel } = useAgentPanelContext();
const chainEnabled = useMemo(
() => agentsConfig?.capabilities.includes(AgentCapabilities.chain) ?? false,
[agentsConfig],

View file

@ -1,9 +1,10 @@
import React, { useState, useMemo, useCallback } from 'react';
import { EModelEndpoint } from 'librechat-data-provider';
import { Controller, useWatch, useFormContext } from 'react-hook-form';
import { EModelEndpoint, AgentCapabilities } from 'librechat-data-provider';
import type { AgentForm, AgentPanelProps, IconComponentTypes } from '~/common';
import { cn, defaultTextProps, removeFocusOutlines, getEndpointField, getIconKey } from '~/utils';
import { useToastContext, useFileMapContext, useAgentPanelContext } from '~/Providers';
import useAgentCapabilities from '~/hooks/Agents/useAgentCapabilities';
import Action from '~/components/SidePanel/Builder/Action';
import { ToolSelectDialog } from '~/components/Tools';
import { icons } from '~/hooks/Endpoint/Icons';
@ -26,17 +27,20 @@ const inputClass = cn(
removeFocusOutlines,
);
export default function AgentConfig({
agentsConfig,
createMutation,
endpointsConfig,
}: Pick<AgentPanelProps, 'agentsConfig' | 'createMutation' | 'endpointsConfig'>) {
export default function AgentConfig({ createMutation }: Pick<AgentPanelProps, 'createMutation'>) {
const localize = useLocalize();
const fileMap = useFileMapContext();
const { showToast } = useToastContext();
const methods = useFormContext<AgentForm>();
const [showToolDialog, setShowToolDialog] = useState(false);
const { actions, setAction, groupedTools: allTools, setActivePanel } = useAgentPanelContext();
const {
actions,
setAction,
agentsConfig,
setActivePanel,
endpointsConfig,
groupedTools: allTools,
} = useAgentPanelContext();
const { control } = methods;
const provider = useWatch({ control, name: 'provider' });
@ -45,34 +49,15 @@ export default function AgentConfig({
const tools = useWatch({ control, name: 'tools' });
const agent_id = useWatch({ control, name: 'id' });
const toolsEnabled = useMemo(
() => agentsConfig?.capabilities?.includes(AgentCapabilities.tools) ?? false,
[agentsConfig],
);
const actionsEnabled = useMemo(
() => agentsConfig?.capabilities?.includes(AgentCapabilities.actions) ?? false,
[agentsConfig],
);
const artifactsEnabled = useMemo(
() => agentsConfig?.capabilities?.includes(AgentCapabilities.artifacts) ?? false,
[agentsConfig],
);
const ocrEnabled = useMemo(
() => agentsConfig?.capabilities?.includes(AgentCapabilities.ocr) ?? false,
[agentsConfig],
);
const fileSearchEnabled = useMemo(
() => agentsConfig?.capabilities?.includes(AgentCapabilities.file_search) ?? false,
[agentsConfig],
);
const webSearchEnabled = useMemo(
() => agentsConfig?.capabilities?.includes(AgentCapabilities.web_search) ?? false,
[agentsConfig],
);
const codeEnabled = useMemo(
() => agentsConfig?.capabilities?.includes(AgentCapabilities.execute_code) ?? false,
[agentsConfig],
);
const {
ocrEnabled,
codeEnabled,
toolsEnabled,
actionsEnabled,
artifactsEnabled,
webSearchEnabled,
fileSearchEnabled,
} = useAgentCapabilities(agentsConfig?.capabilities);
const context_files = useMemo(() => {
if (typeof agent === 'string') {

View file

@ -7,8 +7,6 @@ import {
Constants,
SystemRoles,
EModelEndpoint,
TAgentsEndpoint,
TEndpointsConfig,
isAssistantsEndpoint,
} from 'librechat-data-provider';
import type { AgentForm, StringOption } from '~/common';
@ -30,19 +28,15 @@ import { Button } from '~/components';
import ModelPanel from './ModelPanel';
import { Panel } from '~/common';
export default function AgentPanel({
agentsConfig,
endpointsConfig,
}: {
agentsConfig: TAgentsEndpoint | null;
endpointsConfig: TEndpointsConfig;
}) {
export default function AgentPanel() {
const localize = useLocalize();
const { user } = useAuthContext();
const { showToast } = useToastContext();
const {
activePanel,
agentsConfig,
setActivePanel,
endpointsConfig,
setCurrentAgentId,
agent_id: current_agent_id,
} = useAgentPanelContext();
@ -323,14 +317,10 @@ export default function AgentPanel({
<ModelPanel models={models} providers={providers} setActivePanel={setActivePanel} />
)}
{canEditAgent && !agentQuery.isInitialLoading && activePanel === Panel.builder && (
<AgentConfig
createMutation={create}
agentsConfig={agentsConfig}
endpointsConfig={endpointsConfig}
/>
<AgentConfig createMutation={create} />
)}
{canEditAgent && !agentQuery.isInitialLoading && activePanel === Panel.advanced && (
<AdvancedPanel setActivePanel={setActivePanel} agentsConfig={agentsConfig} />
<AdvancedPanel />
)}
{canEditAgent && !agentQuery.isInitialLoading && (
<AgentFooter

View file

@ -1,8 +1,5 @@
import { useEffect, useMemo } from 'react';
import { EModelEndpoint, AgentCapabilities } from 'librechat-data-provider';
import type { TConfig, TEndpointsConfig, TAgentsEndpoint } from 'librechat-data-provider';
import { useEffect } from 'react';
import { AgentPanelProvider, useAgentPanelContext } from '~/Providers/AgentPanelContext';
import { useGetEndpointsQuery } from '~/data-provider';
import VersionPanel from './Version/VersionPanel';
import { useChatContext } from '~/Providers';
import ActionsPanel from './ActionsPanel';
@ -22,21 +19,6 @@ function AgentPanelSwitchWithContext() {
const { conversation } = useChatContext();
const { activePanel, setCurrentAgentId } = useAgentPanelContext();
// TODO: Implement MCP endpoint
const { data: endpointsConfig = {} as TEndpointsConfig } = useGetEndpointsQuery();
const agentsConfig = useMemo<TAgentsEndpoint | null>(() => {
const config = endpointsConfig?.[EModelEndpoint.agents] ?? null;
if (!config) return null;
return {
...(config as TConfig),
capabilities: Array.isArray(config.capabilities)
? config.capabilities.map((cap) => cap as unknown as AgentCapabilities)
: ([] as AgentCapabilities[]),
} as TAgentsEndpoint;
}, [endpointsConfig]);
useEffect(() => {
const agent_id = conversation?.agent_id ?? '';
if (agent_id) {
@ -57,5 +39,5 @@ function AgentPanelSwitchWithContext() {
if (activePanel === Panel.mcp) {
return <MCPPanel />;
}
return <AgentPanel agentsConfig={agentsConfig} endpointsConfig={endpointsConfig} />;
return <AgentPanel />;
}