mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 08:20:14 +01:00
🧰 fix: Unprocessed Tool Calls Edge Case (#10440)
* chore: temp. remove @librechat/agents
* 🔧 chore: update @langchain/core to version 0.3.79
* chore: update dependencies for @langchain/core and add back latest @librechat/agents
* chore: update @librechat/agents to version 3.0.11
* fix: enhance error handling for uncaught exceptions due to abort errors
* fix: standardize warning message for uncatchable abort errors
* fix: improve tool call handling in ModelEndHandler for unprocessed edge case
* fix: prevent content type mismatch in message updates and preserve args in final updates
* chore: add debug logging for client disposal in disposeClient function
This commit is contained in:
parent
09c309bc78
commit
06c060b983
7 changed files with 910 additions and 197 deletions
|
|
@ -43,11 +43,11 @@
|
||||||
"@google/generative-ai": "^0.24.0",
|
"@google/generative-ai": "^0.24.0",
|
||||||
"@googleapis/youtube": "^20.0.0",
|
"@googleapis/youtube": "^20.0.0",
|
||||||
"@keyv/redis": "^4.3.3",
|
"@keyv/redis": "^4.3.3",
|
||||||
"@langchain/core": "^0.3.72",
|
"@langchain/core": "^0.3.79",
|
||||||
"@langchain/google-genai": "^0.2.13",
|
"@langchain/google-genai": "^0.2.13",
|
||||||
"@langchain/google-vertexai": "^0.2.13",
|
"@langchain/google-vertexai": "^0.2.13",
|
||||||
"@langchain/textsplitters": "^0.1.0",
|
"@langchain/textsplitters": "^0.1.0",
|
||||||
"@librechat/agents": "^3.0.5",
|
"@librechat/agents": "^3.0.11",
|
||||||
"@librechat/api": "*",
|
"@librechat/api": "*",
|
||||||
"@librechat/data-schemas": "*",
|
"@librechat/data-schemas": "*",
|
||||||
"@microsoft/microsoft-graph-client": "^3.0.7",
|
"@microsoft/microsoft-graph-client": "^3.0.7",
|
||||||
|
|
|
||||||
|
|
@ -376,6 +376,8 @@ function disposeClient(client) {
|
||||||
client.options = null;
|
client.options = null;
|
||||||
} catch {
|
} catch {
|
||||||
// Ignore errors during disposal
|
// Ignore errors during disposal
|
||||||
|
} finally {
|
||||||
|
logger.debug('[disposeClient] Client disposed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,22 @@ class ModelEndHandler {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const agentContext = graph.getAgentContext(metadata);
|
const agentContext = graph.getAgentContext(metadata);
|
||||||
if (
|
const isGoogle = agentContext.provider === Providers.GOOGLE;
|
||||||
agentContext.provider === Providers.GOOGLE ||
|
const streamingDisabled = !!agentContext.clientOptions?.disableStreaming;
|
||||||
agentContext.clientOptions?.disableStreaming
|
|
||||||
) {
|
const toolCalls = data?.output?.tool_calls;
|
||||||
handleToolCalls(data?.output?.tool_calls, metadata, graph);
|
let hasUnprocessedToolCalls = false;
|
||||||
|
if (Array.isArray(toolCalls) && toolCalls.length > 0 && graph?.toolCallStepIds?.has) {
|
||||||
|
try {
|
||||||
|
hasUnprocessedToolCalls = toolCalls.some(
|
||||||
|
(tc) => tc?.id && !graph.toolCallStepIds.has(tc.id),
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
hasUnprocessedToolCalls = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isGoogle || streamingDisabled || hasUnprocessedToolCalls) {
|
||||||
|
handleToolCalls(toolCalls, metadata, graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
const usage = data?.output?.usage_metadata;
|
const usage = data?.output?.usage_metadata;
|
||||||
|
|
@ -59,7 +70,6 @@ class ModelEndHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.collectedUsage.push(usage);
|
this.collectedUsage.push(usage);
|
||||||
const streamingDisabled = !!agentContext.clientOptions?.disableStreaming;
|
|
||||||
if (!streamingDisabled) {
|
if (!streamingDisabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,8 +185,8 @@ process.on('uncaughtException', (err) => {
|
||||||
logger.error('There was an uncaught error:', err);
|
logger.error('There was an uncaught error:', err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err.message.includes('abort')) {
|
if (err.message && err.message?.toLowerCase()?.includes('abort')) {
|
||||||
logger.warn('There was an uncatchable AbortController error.');
|
logger.warn('There was an uncatchable abort error.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,12 @@ export default function useStepHandler({
|
||||||
if (!updatedContent[index]) {
|
if (!updatedContent[index]) {
|
||||||
updatedContent[index] = { type: contentPart.type as AllContentTypes };
|
updatedContent[index] = { type: contentPart.type as AllContentTypes };
|
||||||
}
|
}
|
||||||
|
/** Prevent overwriting an existing content part with a different type */
|
||||||
|
const existingType = (updatedContent[index]?.type as string | undefined) ?? '';
|
||||||
|
if (existingType && !contentType.startsWith(existingType)) {
|
||||||
|
console.warn('Content type mismatch');
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
contentType.startsWith(ContentTypes.TEXT) &&
|
contentType.startsWith(ContentTypes.TEXT) &&
|
||||||
|
|
@ -151,12 +157,16 @@ export default function useStepHandler({
|
||||||
const existingToolCall = existingContent?.tool_call;
|
const existingToolCall = existingContent?.tool_call;
|
||||||
const toolCallArgs = (contentPart.tool_call as Agents.ToolCall).args;
|
const toolCallArgs = (contentPart.tool_call as Agents.ToolCall).args;
|
||||||
/** When args are a valid object, they are likely already invoked */
|
/** When args are a valid object, they are likely already invoked */
|
||||||
const args =
|
let args =
|
||||||
finalUpdate ||
|
finalUpdate ||
|
||||||
typeof existingToolCall?.args === 'object' ||
|
typeof existingToolCall?.args === 'object' ||
|
||||||
typeof toolCallArgs === 'object'
|
typeof toolCallArgs === 'object'
|
||||||
? contentPart.tool_call.args
|
? contentPart.tool_call.args
|
||||||
: (existingToolCall?.args ?? '') + (toolCallArgs ?? '');
|
: (existingToolCall?.args ?? '') + (toolCallArgs ?? '');
|
||||||
|
/** Preserve previously streamed args when final update omits them */
|
||||||
|
if (finalUpdate && args == null && existingToolCall?.args != null) {
|
||||||
|
args = existingToolCall.args;
|
||||||
|
}
|
||||||
|
|
||||||
const id = getNonEmptyValue([contentPart.tool_call.id, existingToolCall?.id]) ?? '';
|
const id = getNonEmptyValue([contentPart.tool_call.id, existingToolCall?.id]) ?? '';
|
||||||
const name = getNonEmptyValue([contentPart.tool_call.name, existingToolCall?.name]) ?? '';
|
const name = getNonEmptyValue([contentPart.tool_call.name, existingToolCall?.name]) ?? '';
|
||||||
|
|
|
||||||
1059
package-lock.json
generated
1059
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -82,8 +82,8 @@
|
||||||
"@azure/search-documents": "^12.0.0",
|
"@azure/search-documents": "^12.0.0",
|
||||||
"@azure/storage-blob": "^12.27.0",
|
"@azure/storage-blob": "^12.27.0",
|
||||||
"@keyv/redis": "^4.3.3",
|
"@keyv/redis": "^4.3.3",
|
||||||
"@langchain/core": "^0.3.72",
|
"@langchain/core": "^0.3.79",
|
||||||
"@librechat/agents": "^3.0.5",
|
"@librechat/agents": "^3.0.11",
|
||||||
"@librechat/data-schemas": "*",
|
"@librechat/data-schemas": "*",
|
||||||
"@modelcontextprotocol/sdk": "^1.17.1",
|
"@modelcontextprotocol/sdk": "^1.17.1",
|
||||||
"axios": "^1.12.1",
|
"axios": "^1.12.1",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue