mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-27 04:07:05 +00:00
🔧 feat: Lazy file provisioning — defer uploads to tool invocation time
Move file provisioning from eager (at chat-request start) to lazy (at tool invocation time via ON_TOOL_EXECUTE). Files are now only uploaded to code env / vector DB when the LLM actually calls the respective tool. - resources.ts: primeResources no longer provisions; computes provisionState (which files need code env / vector DB uploads) with staleness check and single credential load - handlers.ts: add provisionFiles callback to ToolExecuteOptions, called once per tool-call batch before execution - initialize.ts: pass provisionState through InitializedAgent - initialize.js: implement provisionFiles closure that provisions files in parallel, batches DB updates, clears state after use; store provisionState in agentToolContexts for all agent types
This commit is contained in:
parent
40ab1073f3
commit
edd7d4cea4
5 changed files with 147 additions and 121 deletions
|
|
@ -1,5 +1,5 @@
|
|||
const { logger } = require('@librechat/data-schemas');
|
||||
const { createContentAggregator } = require('@librechat/agents');
|
||||
const { Constants, createContentAggregator } = require('@librechat/agents');
|
||||
const {
|
||||
loadSkillStates,
|
||||
initializeAgent,
|
||||
|
|
@ -232,6 +232,70 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
|
|||
},
|
||||
toolEndCallback,
|
||||
...getSkillToolDeps(),
|
||||
provisionFiles: async (toolNames, agentId) => {
|
||||
const ctx = agentToolContexts.get(agentId);
|
||||
if (!ctx?.provisionState) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { provisionState } = ctx;
|
||||
const needsCode =
|
||||
toolNames.includes(Constants.EXECUTE_CODE) ||
|
||||
toolNames.includes(Constants.PROGRAMMATIC_TOOL_CALLING);
|
||||
const needsSearch = toolNames.includes('file_search');
|
||||
|
||||
if (!needsCode && !needsSearch) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @type {import('@librechat/api').TFileUpdate[]} */
|
||||
const pendingUpdates = [];
|
||||
|
||||
if (needsCode && provisionState.codeEnvFiles.length > 0 && provisionState.codeApiKey) {
|
||||
const results = await Promise.allSettled(
|
||||
provisionState.codeEnvFiles.map(async (file) => {
|
||||
const { fileIdentifier, fileUpdate } = await provisionToCodeEnv({
|
||||
req,
|
||||
file,
|
||||
entity_id: agentId,
|
||||
apiKey: provisionState.codeApiKey,
|
||||
});
|
||||
file.metadata = { ...file.metadata, fileIdentifier };
|
||||
pendingUpdates.push(fileUpdate);
|
||||
}),
|
||||
);
|
||||
for (const result of results) {
|
||||
if (result.status === 'rejected') {
|
||||
logger.error('[provisionFiles] Code env provisioning failed', result.reason);
|
||||
}
|
||||
}
|
||||
provisionState.codeEnvFiles = [];
|
||||
}
|
||||
|
||||
if (needsSearch && provisionState.vectorDBFiles.length > 0) {
|
||||
const results = await Promise.allSettled(
|
||||
provisionState.vectorDBFiles.map(async (file) => {
|
||||
const result = await provisionToVectorDB({ req, file, entity_id: agentId });
|
||||
if (result.embedded) {
|
||||
file.embedded = true;
|
||||
if (result.fileUpdate) {
|
||||
pendingUpdates.push(result.fileUpdate);
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
for (const result of results) {
|
||||
if (result.status === 'rejected') {
|
||||
logger.error('[provisionFiles] Vector DB provisioning failed', result.reason);
|
||||
}
|
||||
}
|
||||
provisionState.vectorDBFiles = [];
|
||||
}
|
||||
|
||||
if (pendingUpdates.length > 0) {
|
||||
await Promise.allSettled(pendingUpdates.map((update) => db.updateFile(update)));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const summarizationOptions =
|
||||
|
|
@ -700,6 +764,11 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
|
|||
listSkillsByAccess: skillDbMethods.listSkillsByAccess,
|
||||
listAlwaysApplySkills: skillDbMethods.listAlwaysApplySkills,
|
||||
getSkillByName: skillDbMethods.getSkillByName,
|
||||
provisionToCodeEnv,
|
||||
provisionToVectorDB,
|
||||
checkSessionsAlive,
|
||||
loadCodeApiKey,
|
||||
updateFile: db.updateFile,
|
||||
},
|
||||
);
|
||||
agentConfigs.set(agentId, config);
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@ function buildAgentToolContext({ agent, config }) {
|
|||
fileAuthoringToolNames: config.fileAuthoringToolNames,
|
||||
skillPrimedIdsByName:
|
||||
buildSkillPrimedIdsByName(config.manualSkillPrimes, config.alwaysApplySkillPrimes) ?? {},
|
||||
provisionState: config.provisionState,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue