mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-04-07 08:25:23 +02:00
revert: remove native web search approval handling
Native Anthropic web_search executes server-side before we can intercept it, making pre-execution approval impossible. Removing all native web search approval code (dropParams in OpenAI/Anthropic initialize, handleNativeWebSearchApproval in callbacks, toolApprovalConfig in getDefaultHandlers). Tool approval remains fully functional for MCP tools and LangChain tools. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5ee53e258f
commit
f713f9f43a
3 changed files with 1 additions and 132 deletions
|
|
@ -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<void>}
|
||||
*/
|
||||
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 });
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue