refactor: tool classification and calling logic

This commit is contained in:
Danny Avila 2025-12-08 14:57:14 -05:00
parent 3588929c70
commit 984607d339
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
6 changed files with 25 additions and 14 deletions

View file

@ -1,5 +1,6 @@
const { nanoid } = require('nanoid'); const { nanoid } = require('nanoid');
const { sendEvent } = require('@librechat/api'); const { sendEvent } = require('@librechat/api');
const { Constants } = require('@librechat/agents');
const { logger } = require('@librechat/data-schemas'); const { logger } = require('@librechat/data-schemas');
const { Tools, StepTypes, FileContext, ErrorTypes } = require('librechat-data-provider'); const { Tools, StepTypes, FileContext, ErrorTypes } = require('librechat-data-provider');
const { const {
@ -406,9 +407,11 @@ function createToolEndCallback({ req, res, artifactPromises }) {
} }
return; return;
} }
// Constants.PROGRAMMATIC_TOOL_CALLING
{ {
if (output.name !== Tools.execute_code) { const isCodeTool =
output.name === Tools.execute_code || output.name === Constants.PROGRAMMATIC_TOOL_CALLING;
if (!isCodeTool) {
return; return;
} }
} }

View file

@ -91,7 +91,11 @@ const Part = memo(
const isToolCall = const isToolCall =
'args' in toolCall && (!toolCall.type || toolCall.type === ToolCallTypes.TOOL_CALL); 'args' in toolCall && (!toolCall.type || toolCall.type === ToolCallTypes.TOOL_CALL);
if (isToolCall && toolCall.name === Tools.execute_code) { if (
isToolCall &&
(toolCall.name === Tools.execute_code ||
toolCall.name === Constants.PROGRAMMATIC_TOOL_CALLING)
) {
return ( return (
<ExecuteCode <ExecuteCode
attachments={attachments} attachments={attachments}

View file

@ -67,7 +67,7 @@ export default function ExecuteCode({
const [contentHeight, setContentHeight] = useState<number | undefined>(0); const [contentHeight, setContentHeight] = useState<number | undefined>(0);
const prevShowCodeRef = useRef<boolean>(showCode); const prevShowCodeRef = useRef<boolean>(showCode);
const { lang, code } = useParseArgs(args) ?? ({} as ParsedArgs); const { lang = 'py', code } = useParseArgs(args) ?? ({} as ParsedArgs);
const progress = useProgress(initialProgress); const progress = useProgress(initialProgress);
useEffect(() => { useEffect(() => {

View file

@ -701,7 +701,7 @@
"com_ui_mcp_servers_allow_use": "Allow users to use MCP servers", "com_ui_mcp_servers_allow_use": "Allow users to use MCP servers",
"com_ui_all": "all", "com_ui_all": "all",
"com_ui_all_proper": "All", "com_ui_all_proper": "All",
"com_ui_analyzing": "Analyzing", "com_ui_analyzing": "Running tools with code",
"com_ui_analyzing_finished": "Finished analyzing", "com_ui_analyzing_finished": "Finished analyzing",
"com_ui_api_key": "API Key", "com_ui_api_key": "API Key",
"com_ui_api_key_source": "API Key Source", "com_ui_api_key_source": "API Key Source",

View file

@ -282,8 +282,10 @@ export interface BuildToolClassificationResult {
/** /**
* Checks if an agent is allowed to have classification features based on TOOL_CLASSIFICATION_AGENT_IDS. * Checks if an agent is allowed to have classification features based on TOOL_CLASSIFICATION_AGENT_IDS.
* If TOOL_CLASSIFICATION_AGENT_IDS is not set, all agents are allowed (including when no agentId).
* If set, requires agentId to be in the list.
* @param agentId - The agent ID to check * @param agentId - The agent ID to check
* @returns Whether the agent is allowed (true if no restriction set, or agent is in the list) * @returns Whether the agent is allowed
*/ */
export function isAgentAllowedForClassification(agentId?: string): boolean { export function isAgentAllowedForClassification(agentId?: string): boolean {
const allowedAgentIds = parseToolList(process.env.TOOL_CLASSIFICATION_AGENT_IDS); const allowedAgentIds = parseToolList(process.env.TOOL_CLASSIFICATION_AGENT_IDS);
@ -344,6 +346,14 @@ export async function buildToolClassification(
const { loadedTools, userId, agentId, loadAuthValues } = params; const { loadedTools, userId, agentId, loadAuthValues } = params;
const additionalTools: GenericTool[] = []; const additionalTools: GenericTool[] = [];
/** Check if this agent is allowed to have classification features (requires agentId) */
if (!isAgentAllowedForClassification(agentId)) {
logger.debug(
`[buildToolClassification] Agent ${agentId ?? 'undefined'} not allowed for classification, skipping`,
);
return { toolRegistry: undefined, additionalTools };
}
const mcpTools = loadedTools.filter(isMCPTool); const mcpTools = loadedTools.filter(isMCPTool);
if (mcpTools.length === 0) { if (mcpTools.length === 0) {
return { toolRegistry: undefined, additionalTools }; return { toolRegistry: undefined, additionalTools };
@ -355,14 +365,6 @@ export async function buildToolClassification(
/** Clean up temporary mcpJsonSchema property from tools now that registry is populated */ /** Clean up temporary mcpJsonSchema property from tools now that registry is populated */
cleanupMCPToolSchemas(mcpTools); cleanupMCPToolSchemas(mcpTools);
/** Check if this agent is allowed to have classification features */
if (!isAgentAllowedForClassification(agentId)) {
logger.debug(
`[buildToolClassification] Agent ${agentId} not in TOOL_CLASSIFICATION_AGENT_IDS, skipping PTC/ToolSearch`,
);
return { toolRegistry, additionalTools };
}
/** /**
* Check if this agent actually has tools that match the patterns. * Check if this agent actually has tools that match the patterns.
* Only enable PTC if the agent has programmatic tools. * Only enable PTC if the agent has programmatic tools.

View file

@ -1643,6 +1643,8 @@ export enum Constants {
LC_TRANSFER_TO_ = 'lc_transfer_to_', LC_TRANSFER_TO_ = 'lc_transfer_to_',
/** Placeholder Agent ID for Ephemeral Agents */ /** Placeholder Agent ID for Ephemeral Agents */
EPHEMERAL_AGENT_ID = 'ephemeral', EPHEMERAL_AGENT_ID = 'ephemeral',
/** Programmatic Tool Calling tool name */
PROGRAMMATIC_TOOL_CALLING = 'run_tools_with_code',
} }
export enum LocalStorageKeys { export enum LocalStorageKeys {