mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 08:50:15 +01:00
🔧 refactor: Centralize Default Agent Capabilities and Better Logging (#7598)
* refactor: Simplify grid column calculation in SourcesGroup component * refactor: Centralize default agent capabilities and simplify capability assignment * Edge case: use defined/fallback capabilities for ephemeral agents when the "agents" endpoint is not enabled * refactor: consolidate gemini 2 vision check * feat: enhance capability check logging for agents * chore: update librechat-data-provider version to 0.7.86 * refactor: import default agent capabilities for enhanced capability management * chore: standardize quotes in error message check for consistency * fix: improve error logging both client and api-side for mistral ocr upload errors * ci: update error handling in MistralOCR tests to use specific error message
This commit is contained in:
parent
077b7e7e79
commit
2f462c9b3c
11 changed files with 57 additions and 44 deletions
|
|
@ -283,6 +283,10 @@ router.post('/', async (req, res) => {
|
||||||
message += ': ' + error.message;
|
message += ': ' + error.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error.message?.includes('Invalid file format')) {
|
||||||
|
message = error.message;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: delete remote file if it exists
|
// TODO: delete remote file if it exists
|
||||||
try {
|
try {
|
||||||
await fs.unlink(req.file.path);
|
await fs.unlink(req.file.path);
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ async function uploadDocumentToMistral({
|
||||||
})
|
})
|
||||||
.then((res) => res.data)
|
.then((res) => res.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
logger.error('Error uploading document to Mistral:', error.message);
|
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -217,8 +216,16 @@ const uploadMistralOCR = async ({ req, file, file_id, entity_id }) => {
|
||||||
images,
|
images,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = 'Error uploading document to Mistral OCR API';
|
let message = 'Error uploading document to Mistral OCR API';
|
||||||
throw new Error(logAxiosError({ error, message }));
|
const detail = error?.response?.data?.detail;
|
||||||
|
if (detail && detail !== '') {
|
||||||
|
message = detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseMessage = error?.response?.data?.message;
|
||||||
|
throw new Error(
|
||||||
|
`${logAxiosError({ error, message })}${responseMessage && responseMessage !== '' ? ` - ${responseMessage}` : ''}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,13 +124,7 @@ describe('MistralOCR Service', () => {
|
||||||
fileName: 'test.pdf',
|
fileName: 'test.pdf',
|
||||||
apiKey: 'test-api-key',
|
apiKey: 'test-api-key',
|
||||||
}),
|
}),
|
||||||
).rejects.toThrow();
|
).rejects.toThrow(errorMessage);
|
||||||
|
|
||||||
const { logger } = require('~/config');
|
|
||||||
expect(logger.error).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('Error uploading document to Mistral:'),
|
|
||||||
expect.any(String),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ const { Calculator } = require('@langchain/community/tools/calculator');
|
||||||
const { tool: toolFn, Tool, DynamicStructuredTool } = require('@langchain/core/tools');
|
const { tool: toolFn, Tool, DynamicStructuredTool } = require('@langchain/core/tools');
|
||||||
const {
|
const {
|
||||||
Tools,
|
Tools,
|
||||||
|
Constants,
|
||||||
ErrorTypes,
|
ErrorTypes,
|
||||||
ContentTypes,
|
ContentTypes,
|
||||||
imageGenTools,
|
imageGenTools,
|
||||||
|
|
@ -14,6 +15,7 @@ const {
|
||||||
ImageVisionTool,
|
ImageVisionTool,
|
||||||
openapiToFunction,
|
openapiToFunction,
|
||||||
AgentCapabilities,
|
AgentCapabilities,
|
||||||
|
defaultAgentCapabilities,
|
||||||
validateAndParseOpenAPISpec,
|
validateAndParseOpenAPISpec,
|
||||||
} = require('librechat-data-provider');
|
} = require('librechat-data-provider');
|
||||||
const {
|
const {
|
||||||
|
|
@ -501,8 +503,22 @@ async function loadAgentTools({ req, res, agent, tool_resources, openAIApiKey })
|
||||||
}
|
}
|
||||||
|
|
||||||
const endpointsConfig = await getEndpointsConfig(req);
|
const endpointsConfig = await getEndpointsConfig(req);
|
||||||
const enabledCapabilities = new Set(endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? []);
|
let enabledCapabilities = new Set(endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? []);
|
||||||
const checkCapability = (capability) => enabledCapabilities.has(capability);
|
/** Edge case: use defined/fallback capabilities when the "agents" endpoint is not enabled */
|
||||||
|
if (enabledCapabilities.size === 0 && agent.id === Constants.EPHEMERAL_AGENT_ID) {
|
||||||
|
enabledCapabilities = new Set(
|
||||||
|
req.app?.locals?.[EModelEndpoint.agents]?.capabilities ?? defaultAgentCapabilities,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const checkCapability = (capability) => {
|
||||||
|
const enabled = enabledCapabilities.has(capability);
|
||||||
|
if (!enabled) {
|
||||||
|
logger.warn(
|
||||||
|
`Capability "${capability}" disabled${capability === AgentCapabilities.tools ? '.' : ' despite configured tool.'} User: ${req.user.id} | Agent: ${agent.id}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return enabled;
|
||||||
|
};
|
||||||
const areToolsEnabled = checkCapability(AgentCapabilities.tools);
|
const areToolsEnabled = checkCapability(AgentCapabilities.tools);
|
||||||
|
|
||||||
let includesWebSearch = false;
|
let includesWebSearch = false;
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ const {
|
||||||
Capabilities,
|
Capabilities,
|
||||||
EModelEndpoint,
|
EModelEndpoint,
|
||||||
isAgentsEndpoint,
|
isAgentsEndpoint,
|
||||||
AgentCapabilities,
|
|
||||||
isAssistantsEndpoint,
|
isAssistantsEndpoint,
|
||||||
defaultRetrievalModels,
|
defaultRetrievalModels,
|
||||||
defaultAssistantsVersion,
|
defaultAssistantsVersion,
|
||||||
|
defaultAgentCapabilities,
|
||||||
} = require('librechat-data-provider');
|
} = require('librechat-data-provider');
|
||||||
const { Providers } = require('@librechat/agents');
|
const { Providers } = require('@librechat/agents');
|
||||||
const partialRight = require('lodash/partialRight');
|
const partialRight = require('lodash/partialRight');
|
||||||
|
|
@ -197,16 +197,7 @@ function generateConfig(key, baseURL, endpoint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (agents) {
|
if (agents) {
|
||||||
config.capabilities = [
|
config.capabilities = defaultAgentCapabilities;
|
||||||
AgentCapabilities.execute_code,
|
|
||||||
AgentCapabilities.file_search,
|
|
||||||
AgentCapabilities.web_search,
|
|
||||||
AgentCapabilities.artifacts,
|
|
||||||
AgentCapabilities.actions,
|
|
||||||
AgentCapabilities.tools,
|
|
||||||
AgentCapabilities.chain,
|
|
||||||
AgentCapabilities.ocr,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assistants && endpoint === EModelEndpoint.azureAssistants) {
|
if (assistants && endpoint === EModelEndpoint.azureAssistants) {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ const logAxiosError = ({ message, error }) => {
|
||||||
requestInfo: { method, url },
|
requestInfo: { method, url },
|
||||||
stack,
|
stack,
|
||||||
});
|
});
|
||||||
} else if (error?.message?.includes('Cannot read properties of undefined (reading \'status\')')) {
|
} else if (error?.message?.includes("Cannot read properties of undefined (reading 'status')")) {
|
||||||
logMessage = `${message} It appears the request timed out or was unsuccessful: ${error.message}`;
|
logMessage = `${message} It appears the request timed out or was unsuccessful: ${error.message}`;
|
||||||
logger.error(logMessage, { stack });
|
logger.error(logMessage, { stack });
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import * as Ariakit from '@ariakit/react';
|
import * as Ariakit from '@ariakit/react';
|
||||||
import React, { useRef, useState, useMemo } from 'react';
|
import React, { useRef, useState, useMemo } from 'react';
|
||||||
import { EToolResources, EModelEndpoint } from 'librechat-data-provider';
|
|
||||||
import { FileSearch, ImageUpIcon, TerminalSquareIcon, FileType2Icon } from 'lucide-react';
|
import { FileSearch, ImageUpIcon, TerminalSquareIcon, FileType2Icon } from 'lucide-react';
|
||||||
|
import { EToolResources, EModelEndpoint, defaultAgentCapabilities } from 'librechat-data-provider';
|
||||||
import { FileUpload, TooltipAnchor, DropdownPopup, AttachmentIcon } from '~/components';
|
import { FileUpload, TooltipAnchor, DropdownPopup, AttachmentIcon } from '~/components';
|
||||||
import { useGetEndpointsQuery } from '~/data-provider';
|
import { useGetEndpointsQuery } from '~/data-provider';
|
||||||
import { useLocalize, useFileHandling } from '~/hooks';
|
import { useLocalize, useFileHandling } from '~/hooks';
|
||||||
|
|
@ -22,6 +22,10 @@ const AttachFile = ({ disabled }: AttachFileProps) => {
|
||||||
overrideEndpoint: EModelEndpoint.agents,
|
overrideEndpoint: EModelEndpoint.agents,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** TODO: Ephemeral Agent Capabilities
|
||||||
|
* Allow defining agent capabilities on a per-endpoint basis
|
||||||
|
* Use definition for agents endpoint for ephemeral agents
|
||||||
|
* */
|
||||||
const capabilities = useMemo(
|
const capabilities = useMemo(
|
||||||
() => endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? [],
|
() => endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? [],
|
||||||
[endpointsConfig],
|
[endpointsConfig],
|
||||||
|
|
|
||||||
|
|
@ -190,12 +190,8 @@ function SourcesGroup({ sources, limit = 3 }: { sources: ValidSource[]; limit?:
|
||||||
const remainingSources = sources.slice(limit);
|
const remainingSources = sources.slice(limit);
|
||||||
const hasMoreSources = remainingSources.length > 0;
|
const hasMoreSources = remainingSources.length > 0;
|
||||||
|
|
||||||
/** Calculate grid columns based on number of items (including the +X sources button if present) */
|
|
||||||
const totalItems = hasMoreSources ? visibleSources.length + 1 : visibleSources.length;
|
|
||||||
const gridCols = `grid-cols-${Math.min(totalItems, 4)}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`grid ${gridCols} scrollbar-none w-full gap-2 overflow-x-auto`}>
|
<div className="scrollbar-none grid w-full grid-cols-4 gap-2 overflow-x-auto">
|
||||||
<OGDialog>
|
<OGDialog>
|
||||||
{visibleSources.map((source, i) => (
|
{visibleSources.map((source, i) => (
|
||||||
<div key={`source-${i}`} className="w-full min-w-[120px]">
|
<div key={`source-${i}`} className="w-full min-w-[120px]">
|
||||||
|
|
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -45274,7 +45274,7 @@
|
||||||
},
|
},
|
||||||
"packages/data-provider": {
|
"packages/data-provider": {
|
||||||
"name": "librechat-data-provider",
|
"name": "librechat-data-provider",
|
||||||
"version": "0.7.85",
|
"version": "0.7.86",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.8.2",
|
"axios": "^1.8.2",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "librechat-data-provider",
|
"name": "librechat-data-provider",
|
||||||
"version": "0.7.85",
|
"version": "0.7.86",
|
||||||
"description": "data services for librechat apps",
|
"description": "data services for librechat apps",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist/index.es.js",
|
"module": "dist/index.es.js",
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,17 @@ export const assistantEndpointSchema = baseEndpointSchema.merge(
|
||||||
|
|
||||||
export type TAssistantEndpoint = z.infer<typeof assistantEndpointSchema>;
|
export type TAssistantEndpoint = z.infer<typeof assistantEndpointSchema>;
|
||||||
|
|
||||||
|
export const defaultAgentCapabilities = [
|
||||||
|
AgentCapabilities.execute_code,
|
||||||
|
AgentCapabilities.file_search,
|
||||||
|
AgentCapabilities.web_search,
|
||||||
|
AgentCapabilities.artifacts,
|
||||||
|
AgentCapabilities.actions,
|
||||||
|
AgentCapabilities.tools,
|
||||||
|
AgentCapabilities.chain,
|
||||||
|
AgentCapabilities.ocr,
|
||||||
|
];
|
||||||
|
|
||||||
export const agentsEndpointSChema = baseEndpointSchema.merge(
|
export const agentsEndpointSChema = baseEndpointSchema.merge(
|
||||||
z.object({
|
z.object({
|
||||||
/* agents specific */
|
/* agents specific */
|
||||||
|
|
@ -243,16 +254,7 @@ export const agentsEndpointSChema = baseEndpointSchema.merge(
|
||||||
capabilities: z
|
capabilities: z
|
||||||
.array(z.nativeEnum(AgentCapabilities))
|
.array(z.nativeEnum(AgentCapabilities))
|
||||||
.optional()
|
.optional()
|
||||||
.default([
|
.default(defaultAgentCapabilities),
|
||||||
AgentCapabilities.execute_code,
|
|
||||||
AgentCapabilities.file_search,
|
|
||||||
AgentCapabilities.web_search,
|
|
||||||
AgentCapabilities.artifacts,
|
|
||||||
AgentCapabilities.actions,
|
|
||||||
AgentCapabilities.tools,
|
|
||||||
AgentCapabilities.chain,
|
|
||||||
AgentCapabilities.ocr,
|
|
||||||
]),
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -950,8 +952,7 @@ export const visionModels = [
|
||||||
'gemma',
|
'gemma',
|
||||||
'gemini-exp',
|
'gemini-exp',
|
||||||
'gemini-1.5',
|
'gemini-1.5',
|
||||||
'gemini-2.0',
|
'gemini-2',
|
||||||
'gemini-2.5',
|
|
||||||
'gemini-3',
|
'gemini-3',
|
||||||
'moondream',
|
'moondream',
|
||||||
'llama3.2-vision',
|
'llama3.2-vision',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue