mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-27 04:07:05 +00:00
🗂️ feat: Add Deployment Skill Directory (#13523)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
* feat: Add deployment skill directory * chore: Address deployment skill review feedback * fix: Include deployment skill file metadata * test: Add deployment skills e2e smoke test
This commit is contained in:
parent
6357ea10c1
commit
2c8d54e18c
32 changed files with 1836 additions and 69 deletions
|
|
@ -32,7 +32,9 @@ const { loadAgentTools, loadToolsForExecution } = require('~/server/services/Too
|
|||
const { filterFilesByAgentAccess } = require('~/server/services/Files/permissions');
|
||||
const {
|
||||
getSkillToolDeps,
|
||||
getSkillDbMethods,
|
||||
canAuthorSkillFiles,
|
||||
withDeploymentSkillIds,
|
||||
buildAgentToolContext,
|
||||
enrichLoadedToolsWithAgentContext,
|
||||
} = require('./skillDeps');
|
||||
|
|
@ -143,14 +145,17 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
|
|||
const skillsCapabilityEnabled = enabledCapabilities.has(AgentCapabilities.skills);
|
||||
const codeEnvAvailable = enabledCapabilities.has(AgentCapabilities.execute_code);
|
||||
const ephemeralSkillsToggle = req.body?.ephemeralAgent?.skills === true;
|
||||
const skillDbMethods = getSkillDbMethods();
|
||||
|
||||
const accessibleSkillIds = skillsCapabilityEnabled
|
||||
? await findAccessibleResources({
|
||||
userId: req.user.id,
|
||||
role: req.user.role,
|
||||
resourceType: ResourceType.SKILL,
|
||||
requiredPermissions: PermissionBits.VIEW,
|
||||
})
|
||||
? withDeploymentSkillIds(
|
||||
await findAccessibleResources({
|
||||
userId: req.user.id,
|
||||
role: req.user.role,
|
||||
resourceType: ResourceType.SKILL,
|
||||
requiredPermissions: PermissionBits.VIEW,
|
||||
}),
|
||||
)
|
||||
: [];
|
||||
const editableSkillIds = skillsCapabilityEnabled
|
||||
? await findAccessibleResources({
|
||||
|
|
@ -368,9 +373,9 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
|
|||
getToolFilesByIds: db.getToolFilesByIds,
|
||||
getCodeGeneratedFiles: db.getCodeGeneratedFiles,
|
||||
filterFilesByAgentAccess,
|
||||
listSkillsByAccess: db.listSkillsByAccess,
|
||||
listAlwaysApplySkills: db.listAlwaysApplySkills,
|
||||
getSkillByName: db.getSkillByName,
|
||||
listSkillsByAccess: skillDbMethods.listSkillsByAccess,
|
||||
listAlwaysApplySkills: skillDbMethods.listAlwaysApplySkills,
|
||||
getSkillByName: skillDbMethods.getSkillByName,
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -439,9 +444,9 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
|
|||
getToolFilesByIds: db.getToolFilesByIds,
|
||||
getCodeGeneratedFiles: db.getCodeGeneratedFiles,
|
||||
filterFilesByAgentAccess,
|
||||
listSkillsByAccess: db.listSkillsByAccess,
|
||||
listAlwaysApplySkills: db.listAlwaysApplySkills,
|
||||
getSkillByName: db.getSkillByName,
|
||||
listSkillsByAccess: skillDbMethods.listSkillsByAccess,
|
||||
listAlwaysApplySkills: skillDbMethods.listAlwaysApplySkills,
|
||||
getSkillByName: skillDbMethods.getSkillByName,
|
||||
},
|
||||
// The callback fires during BFS, before the helper prunes agents
|
||||
// whose edges end up filtered. Don't populate `agentConfigs` here —
|
||||
|
|
@ -646,9 +651,9 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
|
|||
getToolFilesByIds: db.getToolFilesByIds,
|
||||
getCodeGeneratedFiles: db.getCodeGeneratedFiles,
|
||||
filterFilesByAgentAccess,
|
||||
listSkillsByAccess: db.listSkillsByAccess,
|
||||
listAlwaysApplySkills: db.listAlwaysApplySkills,
|
||||
getSkillByName: db.getSkillByName,
|
||||
listSkillsByAccess: skillDbMethods.listSkillsByAccess,
|
||||
listAlwaysApplySkills: skillDbMethods.listAlwaysApplySkills,
|
||||
getSkillByName: skillDbMethods.getSkillByName,
|
||||
},
|
||||
);
|
||||
agentConfigs.set(agentId, config);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ const {
|
|||
getStorageMetadata,
|
||||
resolveRequestTenantId,
|
||||
enrichWithSkillConfigurable,
|
||||
mergeDeploymentSkillIds,
|
||||
createDeploymentSkillMethods,
|
||||
isDeploymentSkillFileSource,
|
||||
getDeploymentSkillDownloadStream,
|
||||
} = require('@librechat/api');
|
||||
const {
|
||||
Permissions,
|
||||
|
|
@ -27,6 +31,34 @@ const { checkPermission, grantPermission } = require('~/server/services/Permissi
|
|||
const { getFileStrategy } = require('~/server/utils/getFileStrategy');
|
||||
const db = require('~/models');
|
||||
|
||||
const deploymentSkillMethods = createDeploymentSkillMethods({
|
||||
getSkillById: db.getSkillById,
|
||||
getSkillByName: db.getSkillByName,
|
||||
listSkillsByAccess: db.listSkillsByAccess,
|
||||
listAlwaysApplySkills: db.listAlwaysApplySkills,
|
||||
listSkillFiles: db.listSkillFiles,
|
||||
getSkillFileByPath: db.getSkillFileByPath,
|
||||
updateSkillFileContent: db.updateSkillFileContent,
|
||||
updateSkillFileCodeEnvIds: db.updateSkillFileCodeEnvIds,
|
||||
});
|
||||
|
||||
function getSkillDbMethods() {
|
||||
return deploymentSkillMethods;
|
||||
}
|
||||
|
||||
function withDeploymentSkillIds(ids = []) {
|
||||
return mergeDeploymentSkillIds(ids);
|
||||
}
|
||||
|
||||
function getSkillStrategyFunctions(source) {
|
||||
if (isDeploymentSkillFileSource(source)) {
|
||||
return {
|
||||
getDownloadStream: (_req, filepath) => getDeploymentSkillDownloadStream(filepath),
|
||||
};
|
||||
}
|
||||
return getStrategyFunctions(source);
|
||||
}
|
||||
|
||||
function resolveSkillStorage(req, { isImage = false } = {}) {
|
||||
const source = getFileStrategy(req.config, { context: FileContext.skill_file, isImage });
|
||||
const strategy = getStrategyFunctions(source);
|
||||
|
|
@ -290,7 +322,7 @@ function enrichLoadedToolsWithAgentContext({ result, req, ctx = {}, fallback = {
|
|||
|
||||
/** Skill-related properties for ToolExecuteOptions (stable references, allocated once). */
|
||||
const skillToolDeps = {
|
||||
getSkillByName: db.getSkillByName,
|
||||
getSkillByName: deploymentSkillMethods.getSkillByName,
|
||||
getAuthorSkillByName,
|
||||
createSkill: db.createSkill,
|
||||
updateSkill: db.updateSkill,
|
||||
|
|
@ -299,14 +331,14 @@ const skillToolDeps = {
|
|||
canEditSkill,
|
||||
grantSkillOwner,
|
||||
saveSkillFileContent,
|
||||
listSkillFiles: db.listSkillFiles,
|
||||
getStrategyFunctions,
|
||||
listSkillFiles: deploymentSkillMethods.listSkillFiles,
|
||||
getStrategyFunctions: getSkillStrategyFunctions,
|
||||
batchUploadCodeEnvFiles,
|
||||
getSessionInfo,
|
||||
checkIfActive,
|
||||
updateSkillFileCodeEnvIds: db.updateSkillFileCodeEnvIds,
|
||||
getSkillFileByPath: db.getSkillFileByPath,
|
||||
updateSkillFileContent: db.updateSkillFileContent,
|
||||
updateSkillFileCodeEnvIds: deploymentSkillMethods.updateSkillFileCodeEnvIds,
|
||||
getSkillFileByPath: deploymentSkillMethods.getSkillFileByPath,
|
||||
updateSkillFileContent: deploymentSkillMethods.updateSkillFileContent,
|
||||
/**
|
||||
* `read_file` falls back to a sandbox `cat` for `/mnt/data/...` paths
|
||||
* and for `{firstSegment}/...` paths whose first segment isn't a known
|
||||
|
|
@ -327,6 +359,9 @@ module.exports = {
|
|||
getSkillToolDeps,
|
||||
canAuthorSkillFiles,
|
||||
isAgentSkillsEnabledForRun,
|
||||
getSkillDbMethods,
|
||||
withDeploymentSkillIds,
|
||||
getSkillStrategyFunctions,
|
||||
enrichWithSkillConfigurable,
|
||||
buildSkillPrimedIdsByName,
|
||||
buildAgentToolContext,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ const mockGetStrategyFunctions = jest.fn();
|
|||
const mockGetFileStrategy = jest.fn();
|
||||
const mockGetStorageMetadata = jest.fn();
|
||||
const mockResolveRequestTenantId = jest.fn();
|
||||
const mockCreateDeploymentSkillMethods = jest.fn((methods) => methods);
|
||||
|
||||
jest.mock('~/server/services/Files/strategies', () => ({
|
||||
getStrategyFunctions: (...args) => mockGetStrategyFunctions(...args),
|
||||
|
|
@ -22,8 +23,12 @@ jest.mock('~/server/services/Files/Code/process', () => ({
|
|||
|
||||
jest.mock('@librechat/api', () => ({
|
||||
checkAccess: jest.fn(),
|
||||
createDeploymentSkillMethods: (...args) => mockCreateDeploymentSkillMethods(...args),
|
||||
enrichWithSkillConfigurable: jest.fn(),
|
||||
getDeploymentSkillDownloadStream: jest.fn(),
|
||||
getStorageMetadata: (...args) => mockGetStorageMetadata(...args),
|
||||
isDeploymentSkillFileSource: jest.fn(() => false),
|
||||
mergeDeploymentSkillIds: jest.fn((ids = []) => ids),
|
||||
resolveRequestTenantId: (...args) => mockResolveRequestTenantId(...args),
|
||||
}));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue