| | const { logger } = require('@librechat/data-schemas'); |
| | const { createContentAggregator } = require('@librechat/agents'); |
| | const { |
| | validateAgentModel, |
| | getCustomEndpointConfig, |
| | createSequentialChainEdges, |
| | } = require('@librechat/api'); |
| | const { |
| | Constants, |
| | EModelEndpoint, |
| | isAgentsEndpoint, |
| | getResponseSender, |
| | } = require('librechat-data-provider'); |
| | const { |
| | createToolEndCallback, |
| | getDefaultHandlers, |
| | } = require('~/server/controllers/agents/callbacks'); |
| | const { initializeAgent } = require('~/server/services/Endpoints/agents/agent'); |
| | const { getModelsConfig } = require('~/server/controllers/ModelController'); |
| | const { loadAgentTools } = require('~/server/services/ToolService'); |
| | const AgentClient = require('~/server/controllers/agents/client'); |
| | const { getAgent } = require('~/models/Agent'); |
| | const { logViolation } = require('~/cache'); |
| |
|
| | |
| | |
| | |
| | function createToolLoader(signal) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | return async function loadTools({ req, res, agentId, tools, provider, model, tool_resources }) { |
| | const agent = { id: agentId, tools, provider, model }; |
| | try { |
| | return await loadAgentTools({ |
| | req, |
| | res, |
| | agent, |
| | signal, |
| | tool_resources, |
| | }); |
| | } catch (error) { |
| | logger.error('Error loading tools for agent ' + agentId, error); |
| | } |
| | }; |
| | } |
| |
|
| | const initializeClient = async ({ req, res, signal, endpointOption }) => { |
| | if (!endpointOption) { |
| | throw new Error('Endpoint option not provided'); |
| | } |
| | const appConfig = req.config; |
| |
|
| | |
| | |
| | const collectedUsage = []; |
| | |
| | const artifactPromises = []; |
| | const { contentParts, aggregateContent } = createContentAggregator(); |
| | const toolEndCallback = createToolEndCallback({ req, res, artifactPromises }); |
| | const eventHandlers = getDefaultHandlers({ |
| | res, |
| | aggregateContent, |
| | toolEndCallback, |
| | collectedUsage, |
| | }); |
| |
|
| | if (!endpointOption.agent) { |
| | throw new Error('No agent promise provided'); |
| | } |
| |
|
| | const primaryAgent = await endpointOption.agent; |
| | delete endpointOption.agent; |
| | if (!primaryAgent) { |
| | throw new Error('Agent not found'); |
| | } |
| |
|
| | const modelsConfig = await getModelsConfig(req); |
| | const validationResult = await validateAgentModel({ |
| | req, |
| | res, |
| | modelsConfig, |
| | logViolation, |
| | agent: primaryAgent, |
| | }); |
| |
|
| | if (!validationResult.isValid) { |
| | throw new Error(validationResult.error?.message); |
| | } |
| |
|
| | const agentConfigs = new Map(); |
| | const allowedProviders = new Set(appConfig?.endpoints?.[EModelEndpoint.agents]?.allowedProviders); |
| |
|
| | const loadTools = createToolLoader(signal); |
| | |
| | const requestFiles = req.body.files ?? []; |
| | |
| | const conversationId = req.body.conversationId; |
| |
|
| | const primaryConfig = await initializeAgent({ |
| | req, |
| | res, |
| | loadTools, |
| | requestFiles, |
| | conversationId, |
| | agent: primaryAgent, |
| | endpointOption, |
| | allowedProviders, |
| | isInitialAgent: true, |
| | }); |
| |
|
| | const agent_ids = primaryConfig.agent_ids; |
| | let userMCPAuthMap = primaryConfig.userMCPAuthMap; |
| |
|
| | async function processAgent(agentId) { |
| | const agent = await getAgent({ id: agentId }); |
| | if (!agent) { |
| | throw new Error(`Agent ${agentId} not found`); |
| | } |
| |
|
| | const validationResult = await validateAgentModel({ |
| | req, |
| | res, |
| | agent, |
| | modelsConfig, |
| | logViolation, |
| | }); |
| |
|
| | if (!validationResult.isValid) { |
| | throw new Error(validationResult.error?.message); |
| | } |
| |
|
| | const config = await initializeAgent({ |
| | req, |
| | res, |
| | agent, |
| | loadTools, |
| | requestFiles, |
| | conversationId, |
| | endpointOption, |
| | allowedProviders, |
| | }); |
| | if (userMCPAuthMap != null) { |
| | Object.assign(userMCPAuthMap, config.userMCPAuthMap ?? {}); |
| | } else { |
| | userMCPAuthMap = config.userMCPAuthMap; |
| | } |
| | agentConfigs.set(agentId, config); |
| | } |
| |
|
| | let edges = primaryConfig.edges; |
| | const checkAgentInit = (agentId) => agentId === primaryConfig.id || agentConfigs.has(agentId); |
| | if ((edges?.length ?? 0) > 0) { |
| | for (const edge of edges) { |
| | if (Array.isArray(edge.to)) { |
| | for (const to of edge.to) { |
| | if (checkAgentInit(to)) { |
| | continue; |
| | } |
| | await processAgent(to); |
| | } |
| | } else if (typeof edge.to === 'string' && checkAgentInit(edge.to)) { |
| | continue; |
| | } else if (typeof edge.to === 'string') { |
| | await processAgent(edge.to); |
| | } |
| |
|
| | if (Array.isArray(edge.from)) { |
| | for (const from of edge.from) { |
| | if (checkAgentInit(from)) { |
| | continue; |
| | } |
| | await processAgent(from); |
| | } |
| | } else if (typeof edge.from === 'string' && checkAgentInit(edge.from)) { |
| | continue; |
| | } else if (typeof edge.from === 'string') { |
| | await processAgent(edge.from); |
| | } |
| | } |
| | } |
| |
|
| | |
| | if (agent_ids?.length) { |
| | for (const agentId of agent_ids) { |
| | if (checkAgentInit(agentId)) { |
| | continue; |
| | } |
| | await processAgent(agentId); |
| | } |
| |
|
| | const chain = await createSequentialChainEdges([primaryConfig.id].concat(agent_ids), '{convo}'); |
| | edges = edges ? edges.concat(chain) : chain; |
| | } |
| |
|
| | primaryConfig.edges = edges; |
| |
|
| | let endpointConfig = appConfig.endpoints?.[primaryConfig.endpoint]; |
| | if (!isAgentsEndpoint(primaryConfig.endpoint) && !endpointConfig) { |
| | try { |
| | endpointConfig = getCustomEndpointConfig({ |
| | endpoint: primaryConfig.endpoint, |
| | appConfig, |
| | }); |
| | } catch (err) { |
| | logger.error( |
| | '[api/server/controllers/agents/client.js #titleConvo] Error getting custom endpoint config', |
| | err, |
| | ); |
| | } |
| | } |
| |
|
| | const sender = |
| | primaryAgent.name ?? |
| | getResponseSender({ |
| | ...endpointOption, |
| | model: endpointOption.model_parameters.model, |
| | modelDisplayLabel: endpointConfig?.modelDisplayLabel, |
| | modelLabel: endpointOption.model_parameters.modelLabel, |
| | }); |
| |
|
| | const client = new AgentClient({ |
| | req, |
| | res, |
| | sender, |
| | contentParts, |
| | agentConfigs, |
| | eventHandlers, |
| | collectedUsage, |
| | aggregateContent, |
| | artifactPromises, |
| | agent: primaryConfig, |
| | spec: endpointOption.spec, |
| | iconURL: endpointOption.iconURL, |
| | attachments: primaryConfig.attachments, |
| | endpointType: endpointOption.endpointType, |
| | resendFiles: primaryConfig.resendFiles ?? true, |
| | maxContextTokens: primaryConfig.maxContextTokens, |
| | endpoint: |
| | primaryConfig.id === Constants.EPHEMERAL_AGENT_ID |
| | ? primaryConfig.endpoint |
| | : EModelEndpoint.agents, |
| | }); |
| |
|
| | return { client, userMCPAuthMap }; |
| | }; |
| |
|
| | module.exports = { initializeClient }; |
| |
|