mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-10-20 17:13:44 +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
|
|
@ -5,6 +5,8 @@ const {
|
|||
toSkillStatesRecord,
|
||||
validateSkillStatesPayload,
|
||||
pruneOrphanSkillStates,
|
||||
getDeploymentSkillIds,
|
||||
mergeDeploymentSkillIds,
|
||||
} = require('@librechat/api');
|
||||
const { ResourceType, PermissionBits } = require('librechat-data-provider');
|
||||
const { findAccessibleResources } = require('~/server/services/PermissionService');
|
||||
|
|
@ -21,15 +23,20 @@ function buildPruneDeps(user) {
|
|||
const existing = await Skill.find({ _id: { $in: validIds } })
|
||||
.select('_id')
|
||||
.lean();
|
||||
return existing.map((doc) => doc._id.toString());
|
||||
const deploymentIds = getDeploymentSkillIds()
|
||||
.map((id) => id.toString())
|
||||
.filter((id) => validIds.includes(id));
|
||||
return [...existing.map((doc) => doc._id.toString()), ...deploymentIds];
|
||||
},
|
||||
findAccessibleSkillIds: () =>
|
||||
findAccessibleResources({
|
||||
userId: user.id,
|
||||
role: user.role,
|
||||
resourceType: ResourceType.SKILL,
|
||||
requiredPermissions: PermissionBits.VIEW,
|
||||
}),
|
||||
findAccessibleSkillIds: async () =>
|
||||
mergeDeploymentSkillIds(
|
||||
await findAccessibleResources({
|
||||
userId: user.id,
|
||||
role: user.role,
|
||||
resourceType: ResourceType.SKILL,
|
||||
requiredPermissions: PermissionBits.VIEW,
|
||||
}),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,9 @@ jest.mock('~/server/services/Files/permissions', () => ({
|
|||
|
||||
jest.mock('~/server/services/Endpoints/agents/skillDeps', () => ({
|
||||
getSkillToolDeps: mockGetSkillToolDeps,
|
||||
getSkillDbMethods: jest.fn(() => ({})),
|
||||
canAuthorSkillFiles: mockCanAuthorSkillFiles,
|
||||
withDeploymentSkillIds: jest.fn((ids = []) => ids),
|
||||
enrichWithSkillConfigurable: mockEnrichWithSkillConfigurable,
|
||||
buildSkillPrimedIdsByName: mockBuildSkillPrimedIdsByName,
|
||||
buildAgentToolContext: mockBuildAgentToolContext,
|
||||
|
|
|
|||
|
|
@ -200,7 +200,9 @@ jest.mock('~/server/services/Files/permissions', () => ({
|
|||
|
||||
jest.mock('~/server/services/Endpoints/agents/skillDeps', () => ({
|
||||
getSkillToolDeps: mockGetSkillToolDeps,
|
||||
getSkillDbMethods: jest.fn(() => ({})),
|
||||
canAuthorSkillFiles: mockCanAuthorSkillFiles,
|
||||
withDeploymentSkillIds: jest.fn((ids = []) => ids),
|
||||
enrichWithSkillConfigurable: mockEnrichWithSkillConfigurable,
|
||||
buildSkillPrimedIdsByName: mockBuildSkillPrimedIdsByName,
|
||||
buildAgentToolContext: mockBuildAgentToolContext,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,9 @@ const {
|
|||
} = require('~/server/services/PermissionService');
|
||||
const {
|
||||
getSkillToolDeps,
|
||||
getSkillDbMethods,
|
||||
canAuthorSkillFiles,
|
||||
withDeploymentSkillIds,
|
||||
buildAgentToolContext,
|
||||
enrichLoadedToolsWithAgentContext,
|
||||
} = require('~/server/services/Endpoints/agents/skillDeps');
|
||||
|
|
@ -229,6 +231,7 @@ const OpenAIChatCompletionController = async (req, res) => {
|
|||
endpoint: agent.provider,
|
||||
model_parameters: agent.model_parameters ?? {},
|
||||
};
|
||||
const skillDbMethods = getSkillDbMethods();
|
||||
|
||||
// `filterFilesByAgentAccess` is intentionally omitted: it calls
|
||||
// `checkPermission` with `resourceType: AGENT`, but this route
|
||||
|
|
@ -246,21 +249,23 @@ const OpenAIChatCompletionController = async (req, res) => {
|
|||
getUserCodeFiles: db.getUserCodeFiles,
|
||||
getToolFilesByIds: db.getToolFilesByIds,
|
||||
getCodeGeneratedFiles: db.getCodeGeneratedFiles,
|
||||
listSkillsByAccess: db.listSkillsByAccess,
|
||||
listAlwaysApplySkills: db.listAlwaysApplySkills,
|
||||
getSkillByName: db.getSkillByName,
|
||||
listSkillsByAccess: skillDbMethods.listSkillsByAccess,
|
||||
listAlwaysApplySkills: skillDbMethods.listAlwaysApplySkills,
|
||||
getSkillByName: skillDbMethods.getSkillByName,
|
||||
};
|
||||
|
||||
const enabledCapabilities = new Set(agentsEConfig?.capabilities);
|
||||
const skillsCapabilityEnabled = enabledCapabilities.has(AgentCapabilities.skills);
|
||||
const ephemeralSkillsToggle = req.body?.ephemeralAgent?.skills === true;
|
||||
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({
|
||||
|
|
|
|||
|
|
@ -56,7 +56,9 @@ const {
|
|||
} = require('~/server/services/PermissionService');
|
||||
const {
|
||||
getSkillToolDeps,
|
||||
getSkillDbMethods,
|
||||
canAuthorSkillFiles,
|
||||
withDeploymentSkillIds,
|
||||
buildAgentToolContext,
|
||||
enrichLoadedToolsWithAgentContext,
|
||||
} = require('~/server/services/Endpoints/agents/skillDeps');
|
||||
|
|
@ -351,6 +353,7 @@ const createResponse = async (req, res) => {
|
|||
|
||||
// Create tool loader
|
||||
const loadTools = createToolLoader(abortController.signal);
|
||||
const skillDbMethods = getSkillDbMethods();
|
||||
|
||||
// Initialize the agent first to check for disableStreaming
|
||||
const endpointOption = {
|
||||
|
|
@ -374,9 +377,9 @@ const createResponse = async (req, res) => {
|
|||
getUserCodeFiles: db.getUserCodeFiles,
|
||||
getToolFilesByIds: db.getToolFilesByIds,
|
||||
getCodeGeneratedFiles: db.getCodeGeneratedFiles,
|
||||
listSkillsByAccess: db.listSkillsByAccess,
|
||||
listAlwaysApplySkills: db.listAlwaysApplySkills,
|
||||
getSkillByName: db.getSkillByName,
|
||||
listSkillsByAccess: skillDbMethods.listSkillsByAccess,
|
||||
listAlwaysApplySkills: skillDbMethods.listAlwaysApplySkills,
|
||||
getSkillByName: skillDbMethods.getSkillByName,
|
||||
};
|
||||
|
||||
const enabledCapabilities = new Set(
|
||||
|
|
@ -385,12 +388,14 @@ const createResponse = async (req, res) => {
|
|||
const skillsCapabilityEnabled = enabledCapabilities.has(AgentCapabilities.skills);
|
||||
const ephemeralSkillsToggle = req.body?.ephemeralAgent?.skills === true;
|
||||
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({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue