UNPKG

n8n

Version:

n8n Workflow Automation Tool

179 lines • 8.61 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AgentSkillsService = void 0; const api_types_1 = require("@n8n/api-types"); const backend_common_1 = require("@n8n/backend-common"); const di_1 = require("@n8n/di"); const n8n_workflow_1 = require("n8n-workflow"); const not_found_error_1 = require("../../errors/response-errors/not-found.error"); const agent_draft_utils_1 = require("./utils/agent-draft.utils"); const agent_repository_1 = require("./repositories/agent.repository"); const agent_resource_id_1 = require("./utils/agent-resource-id"); let AgentSkillsService = class AgentSkillsService { constructor(logger, agentRepository) { this.logger = logger; this.agentRepository = agentRepository; } async listSkills(agentId, projectId) { const entity = await this.agentRepository.findByIdAndProjectId(agentId, projectId); if (!entity) throw new not_found_error_1.NotFoundError('Agent not found'); return entity.skills ?? {}; } async getSkill(agentId, projectId, skillId) { const skills = await this.listSkills(agentId, projectId); const skill = skills[skillId]; if (!skill) throw new not_found_error_1.NotFoundError('Skill not found'); return skill; } async createSkill(agentId, projectId, skill) { const [result] = await this.createSkillsBatch(agentId, projectId, [skill], false); return result; } async createSkills(agentId, projectId, skills) { return await this.createSkillsBatch(agentId, projectId, skills, false); } async createAndAttachSkill(agentId, projectId, skill) { const [result] = await this.createSkillsBatch(agentId, projectId, [skill], true); return result; } async createSkillsBatch(agentId, projectId, skills, attach) { if (skills.length === 0) { throw new n8n_workflow_1.UserError('At least one skill is required.'); } const entity = await this.agentRepository.findByIdAndProjectId(agentId, projectId); if (!entity) throw new not_found_error_1.NotFoundError('Agent not found'); if (attach && !entity.schema) throw new n8n_workflow_1.UserError('Agent has no JSON config yet.'); for (const skill of skills) { this.validateSkill(skill); } this.assertBatchSkillNamesAreUnique(entity.skills ?? {}, skills); const results = skills.map((skill) => ({ id: this.addSkill(entity, skill), skill })); if (attach) { for (const { id } of results) this.attachSkillRef(entity, id); } (0, agent_draft_utils_1.markAgentDraftDirty)(entity); const saved = await this.agentRepository.save(entity); await this.clearRuntimes(agentId); this.logger.debug(attach ? 'Created and attached agent skill' : 'Created agent skills', { agentId, projectId, skillIds: results.map((r) => r.id), }); return results.map((r) => ({ ...r, versionId: saved.versionId })); } async updateSkill(agentId, projectId, skillId, updates) { const entity = await this.agentRepository.findByIdAndProjectId(agentId, projectId); if (!entity) throw new not_found_error_1.NotFoundError('Agent not found'); const existing = entity.skills?.[skillId]; if (!existing) throw new not_found_error_1.NotFoundError('Skill not found'); const updated = { ...existing, ...updates }; this.validateSkill(updated); this.assertSkillNameIsUnique(entity.skills ?? {}, updated.name, skillId); entity.skills = { ...(entity.skills ?? {}), [skillId]: updated, }; (0, agent_draft_utils_1.markAgentDraftDirty)(entity); const saved = await this.agentRepository.save(entity); await this.clearRuntimes(agentId); this.logger.debug('Updated agent skill', { agentId, projectId, skillId }); return { id: skillId, skill: updated, versionId: saved.versionId }; } async deleteSkill(agentId, projectId, skillId) { const entity = await this.agentRepository.findByIdAndProjectId(agentId, projectId); if (!entity) throw new not_found_error_1.NotFoundError('Agent not found'); const skills = { ...(entity.skills ?? {}) }; if (!skills[skillId]) throw new not_found_error_1.NotFoundError('Skill not found'); delete skills[skillId]; entity.skills = skills; if (entity.schema?.skills) { entity.schema.skills = entity.schema.skills.filter((t) => t.id !== skillId); } (0, agent_draft_utils_1.markAgentDraftDirty)(entity); await this.agentRepository.save(entity); await this.clearRuntimes(agentId); this.logger.debug('Deleted agent skill', { agentId, projectId, skillId }); } removeUnreferencedSkills(entity, config) { const referencedSkillIds = new Set((config.skills ?? []).map((t) => t.id)); const orphanSkillIds = Object.keys(entity.skills ?? {}).filter((id) => !referencedSkillIds.has(id)); if (orphanSkillIds.length === 0) return; const skills = { ...(entity.skills ?? {}) }; for (const id of orphanSkillIds) { delete skills[id]; } entity.skills = skills; } validateSkill(skill) { const result = api_types_1.agentSkillSchema.safeParse(skill); if (!result.success) { throw new n8n_workflow_1.UserError(`Invalid agent skill: ${result.error.issues[0]?.message ?? 'Invalid skill'}`); } } addSkill(entity, skill) { const skillId = (0, agent_resource_id_1.generateAgentResourceId)('skill', Object.keys(entity.skills ?? {})); entity.skills = { ...(entity.skills ?? {}), [skillId]: skill, }; return skillId; } assertSkillNameIsUnique(existing, name, currentSkillId) { const normalizedName = this.normalizeSkillName(name); const duplicate = Object.entries(existing ?? {}).find(([id, skill]) => id !== currentSkillId && this.normalizeSkillName(skill.name) === normalizedName); if (duplicate) { throw new n8n_workflow_1.UserError(`Agent already has a skill named "${name.trim()}".`); } } normalizeSkillName(name) { return name.trim().toLowerCase(); } assertBatchSkillNamesAreUnique(existing, skills) { const seenNames = new Set(); for (const skill of skills) { this.assertSkillNameIsUnique(existing, skill.name); const normalizedName = this.normalizeSkillName(skill.name); if (seenNames.has(normalizedName)) { throw new n8n_workflow_1.UserError(`Duplicate skill name in batch: "${skill.name.trim()}".`); } seenNames.add(normalizedName); } } attachSkillRef(entity, skillId) { if (!entity.schema) throw new n8n_workflow_1.UserError('Agent has no JSON config yet.'); entity.schema.skills = [ ...(entity.schema.skills ?? []).filter((ref) => ref.id !== skillId), { type: 'skill', id: skillId }, ]; } async clearRuntimes(agentId) { const { AgentRuntimeCacheService } = await import('./agent-runtime-cache.service.js'); di_1.Container.get(AgentRuntimeCacheService).clearRuntimes(agentId); } }; exports.AgentSkillsService = AgentSkillsService; exports.AgentSkillsService = AgentSkillsService = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [backend_common_1.Logger, agent_repository_1.AgentRepository]) ], AgentSkillsService); //# sourceMappingURL=agent-skills.service.js.map