diff --git a/api/server/controllers/agents/callbacks.js b/api/server/controllers/agents/callbacks.js index def76ad3e4..5ea5a00975 100644 --- a/api/server/controllers/agents/callbacks.js +++ b/api/server/controllers/agents/callbacks.js @@ -1,27 +1,16 @@ const { nanoid } = require('nanoid'); const { logger } = require('@librechat/data-schemas'); -const { Tools, StepTypes, FileContext, ErrorTypes, EModelEndpoint } = require('librechat-data-provider'); -const { - EnvVar, - Constants, - GraphEvents, - GraphNodeKeys, - ToolEndHandler, -} = require('@librechat/agents'); +const { Tools, StepTypes, FileContext, ErrorTypes } = require('librechat-data-provider'); const { sendEvent, - requiresApproval, GenerationJobManager, writeAttachmentEvent, createToolExecuteHandler, - MCPToolCallValidationHandler, } = require('@librechat/api'); const { processFileCitations } = require('~/server/services/Files/Citations'); const { processCodeOutput } = require('~/server/services/Files/Code/process'); const { loadAuthValues } = require('~/server/services/Tools/credentials'); const { saveBase64Image } = require('~/server/services/Files/process'); -const { getFlowStateManager } = require('~/config'); -const { getLogStores } = require('~/cache'); class ModelEndHandler { /** @@ -120,78 +109,6 @@ async function emitEvent(res, streamId, eventData) { } } -/** - * Checks if a tool call is a native Anthropic web search (server_tool_use). - * @param {Object} toolCall - The tool call object - * @returns {boolean} - */ -function isNativeWebSearch(toolCall) { - return toolCall?.name === Tools.web_search && toolCall?.id?.startsWith('srvtoolu_'); -} - -/** - * Handles approval flow for native web search tool calls. - * @param {Object} params - * @param {Object} params.toolCall - The tool call requiring approval - * @param {Object} params.toolApprovalConfig - The tool approval configuration - * @param {ServerResponse} params.res - The response object for SSE - * @param {string | null} params.streamId - The stream ID for resumable mode - * @param {string} params.stepId - The step ID - * @param {string} params.userId - The user ID - * @param {AbortSignal} [params.signal] - Optional abort signal - * @returns {Promise} - */ -async function handleNativeWebSearchApproval({ - toolCall, - toolApprovalConfig, - res, - streamId, - stepId, - userId, - signal, -}) { - const needsApproval = requiresApproval(Tools.web_search, toolApprovalConfig); - if (!needsApproval) { - return; - } - - const flowsCache = getLogStores(CacheKeys.FLOWS); - const flowManager = getFlowStateManager(flowsCache); - const derivedSignal = signal ? AbortSignal.any([signal]) : undefined; - - const toolArgs = toolCall.args || {}; - const { validationId, flowMetadata } = - await MCPToolCallValidationHandler.initiateValidationFlow( - userId, - 'anthropic', - Tools.web_search, - typeof toolArgs === 'string' ? { input: toolArgs } : toolArgs, - ); - - const validationData = { - id: stepId, - delta: { - type: StepTypes.TOOL_CALLS, - tool_calls: [{ id: toolCall.id, name: toolCall.name, args: '' }], - validation: validationId, - expires_at: Date.now() + Time.TEN_MINUTES, - }, - }; - await emitEvent(res, streamId, { event: GraphEvents.ON_RUN_STEP_DELTA, data: validationData }); - - const validationFlowType = MCPToolCallValidationHandler.getFlowType(); - await flowManager.createFlow(validationId, validationFlowType, flowMetadata, derivedSignal); - - const successData = { - id: stepId, - delta: { - type: StepTypes.TOOL_CALLS, - tool_calls: [{ id: toolCall.id, name: toolCall.name }], - }, - }; - await emitEvent(res, streamId, { event: GraphEvents.ON_RUN_STEP_DELTA, data: successData }); -} - /** * @typedef {Object} ToolExecuteOptions * @property {(toolNames: string[]) => Promise<{loadedTools: StructuredTool[]}>} loadTools - Function to load tools by name @@ -218,14 +135,12 @@ function getDefaultHandlers({ streamId = null, toolExecuteOptions = null, summarizationOptions = null, - toolApprovalConfig, }) { if (!res || !aggregateContent) { throw new Error( `[getDefaultHandlers] Missing required options: res: ${!res}, aggregateContent: ${!aggregateContent}`, ); } - const pendingNativeWebSearchApprovals = new Set(); const handlers = { [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage), [GraphEvents.TOOL_END]: new ToolEndHandler(toolEndCallback, logger), @@ -237,24 +152,6 @@ function getDefaultHandlers({ * @param {GraphRunnableConfig['configurable']} [metadata] The runnable metadata. */ handle: async (event, data, metadata) => { - if (data?.stepDetails?.type === StepTypes.TOOL_CALLS && toolApprovalConfig) { - const toolCalls = data.stepDetails.tool_calls || []; - for (const toolCall of toolCalls) { - if (isNativeWebSearch(toolCall) && !pendingNativeWebSearchApprovals.has(toolCall.id)) { - pendingNativeWebSearchApprovals.add(toolCall.id); - await handleNativeWebSearchApproval({ - toolCall, - toolApprovalConfig, - res, - streamId, - stepId: data.id, - userId: metadata?.user_id || metadata?.user?.id, - signal: metadata?.signal, - }); - } - } - } - aggregateContent({ event, data }); if (data?.stepDetails.type === StepTypes.TOOL_CALLS) { await emitEvent(res, streamId, { event, data }); diff --git a/api/server/services/Endpoints/agents/initialize.js b/api/server/services/Endpoints/agents/initialize.js index 82260585db..69767e191c 100644 --- a/api/server/services/Endpoints/agents/initialize.js +++ b/api/server/services/Endpoints/agents/initialize.js @@ -147,7 +147,6 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => { const summarizationOptions = appConfig?.summarization?.enabled === false ? { enabled: false } : { enabled: true }; - const toolApprovalConfig = appConfig?.endpoints?.[EModelEndpoint.agents]?.toolApproval; const eventHandlers = getDefaultHandlers({ res, toolExecuteOptions, @@ -156,7 +155,6 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => { toolEndCallback, collectedUsage, streamId, - toolApprovalConfig, }); if (!endpointOption.agent) { diff --git a/packages/api/src/endpoints/openai/initialize.ts b/packages/api/src/endpoints/openai/initialize.ts index 38f91a4198..a6ad6df895 100644 --- a/packages/api/src/endpoints/openai/initialize.ts +++ b/packages/api/src/endpoints/openai/initialize.ts @@ -1,5 +1,4 @@ import { ErrorTypes, EModelEndpoint, mapModelToAzureConfig } from 'librechat-data-provider'; -import type { TToolApproval } from 'librechat-data-provider'; import type { BaseInitializeParams, InitializeResultBase, @@ -10,23 +9,6 @@ import { getAzureCredentials, resolveHeaders, isUserProvided, checkUserKeyExpiry import { validateEndpointURL } from '~/auth'; import { getOpenAIConfig } from './config'; -function shouldDisableNativeWebSearch(toolApproval: TToolApproval | undefined): boolean { - if (!toolApproval) { - return false; - } - const { required, excluded } = toolApproval; - if (excluded?.includes('web_search')) { - return false; - } - if (required === true) { - return true; - } - if (Array.isArray(required) && required.includes('web_search')) { - return true; - } - return false; -} - /** * Initializes OpenAI options for agent usage. This function always returns configuration * options and never creates a client instance (equivalent to optionsOnly=true behavior). @@ -151,14 +133,6 @@ export async function initializeOpenAI({ user: req.user?.id, }; - const toolApproval = appConfig?.endpoints?.[EModelEndpoint.agents]?.toolApproval; - if (shouldDisableNativeWebSearch(toolApproval)) { - clientOptions.dropParams = clientOptions.dropParams ?? []; - if (!clientOptions.dropParams.includes('web_search')) { - clientOptions.dropParams.push('web_search'); - } - } - const finalClientOptions: OpenAIConfigOptions = { ...clientOptions, modelOptions,