n8n
Version:
n8n Workflow Automation Tool
164 lines (160 loc) • 8.94 kB
JavaScript
;
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.InstanceAiBuilderDelegateAdapterService = exports.INSTANCE_AI_BUILDER_ADDENDUM = void 0;
const di_1 = require("@n8n/di");
const instance_ai_1 = require("@n8n/instance-ai");
const typeorm_1 = require("@n8n/typeorm");
const n8n_workflow_1 = require("n8n-workflow");
const forbidden_error_1 = require("../../errors/response-errors/forbidden.error");
const check_access_1 = require("../../permissions.ee/check-access");
const agent_config_service_1 = require("./agent-config.service");
const agent_skills_service_1 = require("./agent-skills.service");
const agents_service_1 = require("./agents.service");
const agents_builder_service_1 = require("./builder/agents-builder.service");
const n8n_memory_1 = require("./integrations/n8n-memory");
const agent_thread_repository_1 = require("./repositories/agent-thread.repository");
const agent_config_hash_1 = require("./utils/agent-config-hash");
exports.INSTANCE_AI_BUILDER_ADDENDUM = `## Instance AI session rules
You are running as a sub-agent inside n8n's instance AI chat; the user sees your questions as chat cards.
Preview links work in this chat. Include a markdown Preview link after a successful build and when \`call_agent\` reports an unsupported interaction as \`approval_required\`, using the exact relative path from "When To Build vs When To Converse" (form: \`[Preview](<path>)\`). Do not invent absolute URLs. Do not omit the link and describe the path in plain text instead.
You can publish and unpublish the target agent with \`publish_agent\` and \`unpublish_agent\`. Never tell the user to open the agent editor and click Publish.
The Instance AI orchestrator can create workflows and data tables — never ask the user to create them manually. State missing prerequisites in your reply; the orchestrator will provision them and call you again.`;
function isTextDeltaChunk(chunk) {
return chunk.type === 'text-delta';
}
function toBuilderTurnStream(chunks) {
let resolveText;
const text = new Promise((resolve) => {
resolveText = resolve;
});
let acc = '';
async function* pump() {
try {
for await (const chunk of chunks) {
if (isTextDeltaChunk(chunk))
acc += chunk.delta;
yield chunk;
}
}
finally {
resolveText(acc);
}
}
return { fullStream: pump(), text };
}
let InstanceAiBuilderDelegateAdapterService = class InstanceAiBuilderDelegateAdapterService {
constructor(agentsService, agentsBuilderService, n8nMemory, agentThreadRepository, agentConfig, agentSkills) {
this.agentsService = agentsService;
this.agentsBuilderService = agentsBuilderService;
this.n8nMemory = n8nMemory;
this.agentThreadRepository = agentThreadRepository;
this.agentConfig = agentConfig;
this.agentSkills = agentSkills;
}
buildSubAgentSession(session) {
return {
threadId: session.threadId,
hostThreadId: session.hostThreadId,
runId: session.runId,
instructionsAddendum: exports.INSTANCE_AI_BUILDER_ADDENDUM,
modelConfig: session.modelConfig,
...(session.telemetry ? { telemetry: session.telemetry } : {}),
...(session.memoryTaskObserver ? { memoryTaskObserver: session.memoryTaskObserver } : {}),
abortSignal: session.abortSignal,
};
}
createDelegate(user, projectId, credentialProvider) {
const assertProjectScope = async (scope) => {
if (!(await (0, check_access_1.userHasScopes)(user, [scope], false, { projectId }))) {
throw new forbidden_error_1.ForbiddenError('You do not have permission to access agents in this project.');
}
};
return {
createAgent: async (name, id) => {
await assertProjectScope('agent:create');
const agent = await this.agentsService.create(projectId, name, {
id,
adoptUnconfiguredOnCollision: true,
});
return { agentId: agent.id, projectId };
},
streamBuild: async (agentId, message, session) => {
await assertProjectScope('agent:update');
return toBuilderTurnStream(this.agentsBuilderService.buildAgent(agentId, projectId, message, credentialProvider, user, this.buildSubAgentSession(session)));
},
resumeBuild: async (agentId, resume, session) => {
await assertProjectScope('agent:update');
return toBuilderTurnStream(this.agentsBuilderService.resumeBuild(agentId, projectId, resume.runId, resume.toolCallId, resume.resumeData, credentialProvider, user, this.buildSubAgentSession(session)));
},
findOpenSuspensions: async (agentId, session) => {
await assertProjectScope('agent:update');
const checkpoint = await this.agentsBuilderService.findOpenCheckpointForThread(agentId, session.threadId);
if (!checkpoint)
return [];
return Object.values(checkpoint.pendingToolCalls ?? {})
.filter((tc) => tc.suspended)
.map((tc) => ({ runId: tc.runId, toolCallId: tc.toolCallId }));
},
cancelOpenSuspension: async (agentId, runId) => {
await assertProjectScope('agent:update');
await this.agentsBuilderService.cancelCheckpoint(agentId, runId);
},
listAgents: async () => {
await assertProjectScope('agent:read');
const agents = await this.agentsService.findByProjectId(projectId);
return agents.map((agent) => ({
agentId: agent.id,
name: agent.name,
published: agent.activeVersionId !== null,
updatedAt: agent.updatedAt.toISOString(),
}));
},
resolveAgentName: async (agentId) => {
await assertProjectScope('agent:read');
return (await this.agentsService.findById(agentId, projectId))?.name;
},
readAgentArtifact: async (agentId) => {
await assertProjectScope('agent:read');
const config = await this.agentConfig.getConfig(agentId, projectId).catch((error) => {
if (error instanceof n8n_workflow_1.UserError)
return null;
throw error;
});
if (!config)
return null;
return {
config,
skills: await this.agentSkills.listSkills(agentId, projectId),
configHash: (0, agent_config_hash_1.getAgentConfigHash)(config),
};
},
};
}
async deleteBuilderSessions(instanceAiThreadId) {
const prefix = (0, instance_ai_1.instanceAiBuilderThreadPrefix)(instanceAiThreadId);
const threads = await this.agentThreadRepository.find({
select: { id: true },
where: { id: (0, typeorm_1.Like)(`${prefix}%`) },
});
for (const { id } of threads) {
const memory = this.n8nMemory.getImplementation(id.slice(prefix.length));
await memory.deleteMessagesByThread(id);
await memory.deleteThread(id);
}
}
};
exports.InstanceAiBuilderDelegateAdapterService = InstanceAiBuilderDelegateAdapterService;
exports.InstanceAiBuilderDelegateAdapterService = InstanceAiBuilderDelegateAdapterService = __decorate([
(0, di_1.Service)(),
__metadata("design:paramtypes", [agents_service_1.AgentsService, agents_builder_service_1.AgentsBuilderService, n8n_memory_1.N8nMemory, agent_thread_repository_1.AgentThreadRepository, agent_config_service_1.AgentConfigService, agent_skills_service_1.AgentSkillsService])
], InstanceAiBuilderDelegateAdapterService);
//# sourceMappingURL=instance-ai-builder-delegate.adapter.js.map