🔃 fix: Draft Clearing, Claude Titles, Remove Default Vision Max Tokens (#6501)

* refactor: remove legacy max_tokens setting for vision models in OpenAIClient (intended for gpt-4-preview)

* refactor: streamline capability checks in loadAgentTools function, still allow actions if tools are disabled

* fix: enhance error handling for token limits in AnthropicClient and update error message in translations

* feat: append timestamp to cloned agent names for better identification

* chore: update @librechat/agents dependency to version 2.3.94

* refactor: remove clearDraft helper from useSubmitMessage and centralize draft clearing logic to SSE handling, helps prevent user message loss if logout occurs

* refactor: increase debounce time for clearDraft function to improve auto-save performance
This commit is contained in:
Danny Avila 2025-03-23 18:47:40 -04:00 committed by GitHub
parent 20f353630e
commit 4b85fe9206
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 634 additions and 590 deletions

View file

@ -2,6 +2,7 @@ const Anthropic = require('@anthropic-ai/sdk');
const { HttpsProxyAgent } = require('https-proxy-agent');
const {
Constants,
ErrorTypes,
EModelEndpoint,
anthropicSettings,
getResponseSender,
@ -147,12 +148,17 @@ class AnthropicClient extends BaseClient {
this.maxPromptTokens =
this.options.maxPromptTokens || this.maxContextTokens - this.maxResponseTokens;
if (this.maxPromptTokens + this.maxResponseTokens > this.maxContextTokens) {
throw new Error(
`maxPromptTokens + maxOutputTokens (${this.maxPromptTokens} + ${this.maxResponseTokens} = ${
this.maxPromptTokens + this.maxResponseTokens
}) must be less than or equal to maxContextTokens (${this.maxContextTokens})`,
);
const reservedTokens = this.maxPromptTokens + this.maxResponseTokens;
if (reservedTokens > this.maxContextTokens) {
const info = `Total Possible Tokens + Max Output Tokens must be less than or equal to Max Context Tokens: ${this.maxPromptTokens} (total possible output) + ${this.maxResponseTokens} (max output) = ${reservedTokens}/${this.maxContextTokens} (max context)`;
const errorMessage = `{ "type": "${ErrorTypes.INPUT_LENGTH}", "info": "${info}" }`;
logger.warn(info);
throw new Error(errorMessage);
} else if (this.maxResponseTokens === this.maxContextTokens) {
const info = `Max Output Tokens must be less than Max Context Tokens: ${this.maxResponseTokens} (max output) = ${this.maxContextTokens} (max context)`;
const errorMessage = `{ "type": "${ErrorTypes.INPUT_LENGTH}", "info": "${info}" }`;
logger.warn(info);
throw new Error(errorMessage);
}
this.sender =

View file

@ -1185,10 +1185,6 @@ ${convo}
opts.httpAgent = new HttpsProxyAgent(this.options.proxy);
}
if (this.isVisionModel) {
modelOptions.max_tokens = 4000;
}
/** @type {TAzureConfig | undefined} */
const azureConfig = this.options?.req?.app?.locals?.[EModelEndpoint.azureOpenAI];

View file

@ -49,7 +49,7 @@
"@langchain/google-genai": "^0.1.11",
"@langchain/google-vertexai": "^0.2.2",
"@langchain/textsplitters": "^0.1.0",
"@librechat/agents": "^2.3.93",
"@librechat/agents": "^2.3.94",
"@librechat/data-schemas": "*",
"@waylaidwanderer/fetch-event-source": "^3.0.1",
"axios": "^1.8.2",

View file

@ -212,6 +212,11 @@ const duplicateAgentHandler = async (req, res) => {
tool_resources: _tool_resources = {},
...cloneData
} = agent;
cloneData.name = `${agent.name} (${new Date().toLocaleString('en-US', {
dateStyle: 'short',
timeStyle: 'short',
hour12: false,
})})`;
if (_tool_resources?.[EToolResources.ocr]) {
cloneData.tool_resources = {

View file

@ -425,21 +425,16 @@ async function loadAgentTools({ req, res, agent, tool_resources, openAIApiKey })
}
const endpointsConfig = await getEndpointsConfig(req);
const capabilities = endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? [];
const areToolsEnabled = capabilities.includes(AgentCapabilities.tools);
if (!areToolsEnabled) {
logger.debug('Tools are not enabled for this agent.');
return {};
}
const isFileSearchEnabled = capabilities.includes(AgentCapabilities.file_search);
const isCodeEnabled = capabilities.includes(AgentCapabilities.execute_code);
const areActionsEnabled = capabilities.includes(AgentCapabilities.actions);
const enabledCapabilities = new Set(endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? []);
const checkCapability = (capability) => enabledCapabilities.has(capability);
const areToolsEnabled = checkCapability(AgentCapabilities.tools);
const _agentTools = agent.tools?.filter((tool) => {
if (tool === Tools.file_search && !isFileSearchEnabled) {
if (tool === Tools.file_search && !checkCapability(AgentCapabilities.file_search)) {
return false;
} else if (tool === Tools.execute_code && !isCodeEnabled) {
} else if (tool === Tools.execute_code && !checkCapability(AgentCapabilities.execute_code)) {
return false;
} else if (!areToolsEnabled && !tool.includes(actionDelimiter)) {
return false;
}
return true;
@ -473,6 +468,10 @@ async function loadAgentTools({ req, res, agent, tool_resources, openAIApiKey })
continue;
}
if (!areToolsEnabled) {
continue;
}
if (tool.mcp === true) {
agentTools.push(tool);
continue;
@ -505,7 +504,7 @@ async function loadAgentTools({ req, res, agent, tool_resources, openAIApiKey })
return map;
}, {});
if (!areActionsEnabled) {
if (!checkCapability(AgentCapabilities.actions)) {
return {
tools: agentTools,
toolContextMap,