UNPKG

n8n

Version:

n8n Workflow Automation Tool

328 lines • 14.6 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.AgentExecutionOrchestratorService = 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 external_hooks_1 = require("../../external-hooks"); const telemetry_1 = require("../../telemetry"); const agent_execution_service_1 = require("./agent-execution.service"); const agent_run_tracing_service_1 = require("./agent-run-tracing.service"); const agent_runtime_cache_service_1 = require("./agent-runtime-cache.service"); const execution_recorder_1 = require("./execution-recorder"); const integration_message_context_service_1 = require("./integrations/integration-message-context.service"); const n8n_checkpoint_storage_1 = require("./integrations/n8n-checkpoint-storage"); const agent_execution_counter_1 = require("./utils/agent-execution-counter"); const agent_stream_1 = require("./utils/agent-stream"); const execution_to_message_mapper_1 = require("./utils/execution-to-message-mapper"); function getMaxIterationsChunks() { const id = crypto.randomUUID(); return [ { type: 'text-start', id }, { type: 'text-delta', id, delta: 'The agent has reached the maximum number of iterations and has stopped.', }, { type: 'text-end', id }, ]; } let AgentExecutionOrchestratorService = class AgentExecutionOrchestratorService { constructor(logger, n8nCheckpointStorage, agentExecutionService, telemetry, runtimeCacheService, integrationMessageContextService, agentRunTracingService, externalHooks) { this.logger = logger; this.n8nCheckpointStorage = n8nCheckpointStorage; this.agentExecutionService = agentExecutionService; this.telemetry = telemetry; this.runtimeCacheService = runtimeCacheService; this.integrationMessageContextService = integrationMessageContextService; this.agentRunTracingService = agentRunTracingService; this.externalHooks = externalHooks; } async getConversationHistory(params) { const { threadId, projectId, agentId } = params; const detail = await this.agentExecutionService.getThreadDetail(threadId, projectId, agentId); if (!detail) return null; return (0, execution_to_message_mapper_1.executionsToMessagesDto)(detail.executions); } async *resumeForChat(config) { const { agentId, projectId, runId, toolCallId, resumeData, integrationType, user, usePublishedVersion = true, onExecutionRecorded, } = config; const checkpointStatus = await this.n8nCheckpointStorage.getStatus(runId); if (checkpointStatus.status === 'expired') { throw new n8n_workflow_1.UserError(`Checkpoint ${runId} is expired and cannot be resumed`); } if (checkpointStatus.status === 'not-found') { throw new n8n_workflow_1.UserError(`Checkpoint ${runId} not found and cannot be resumed`); } const memoryScope = checkpointStatus.checkpoint?.persistence; if (!memoryScope) { throw new n8n_workflow_1.UserError(`Checkpoint ${runId} has no memory data and cannot be resumed`); } const threadId = memoryScope.threadId; const runtime = await this.runtimeCacheService.getRuntime({ agentId, projectId, usePublishedVersion, integrationType, user: usePublishedVersion ? undefined : user, }); const { agent: agentInstance, toolRegistry } = runtime; const recorder = new execution_recorder_1.ExecutionRecorder(toolRegistry); const runType = usePublishedVersion ? 'production' : 'test'; try { const suspendedExecution = this.agentRunTracingService.enabled ? await this.agentExecutionService.findLatestSuspendedRun(threadId) : undefined; const tracing = await this.agentRunTracingService.build({ agentId, projectId, threadId, userId: user?.id, source: suspendedExecution?.source ?? 'unknown', modelId: (0, agent_run_tracing_service_1.modelIdFromSnapshot)(agentInstance.snapshot.model), }); const resultStream = await agentInstance.resume('stream', resumeData, { runId, toolCallId, executionCounter: (0, agent_execution_counter_1.createAgentExecutionCounter)(this.telemetry, { agentId, userId: user?.id, }), ...(tracing ? { telemetry: tracing } : {}), }); for await (const value of (0, agent_stream_1.streamAgentChunks)(resultStream.stream)) { recorder.record(value); yield value; } } catch (error) { recorder.record({ type: 'error', error }); recorder.record({ type: 'finish', finishReason: 'error' }); throw error; } finally { const messageRecord = recorder.getMessageRecord(); await this.persistRecordedExecution({ onExecutionRecorded, failureMessage: 'Failed to record resumed agent execution', params: { threadId, agentId, agentName: agentInstance.name, projectId, userMessage: null, record: messageRecord, hitlStatus: recorder.suspended ? 'suspended' : 'resumed', telemetry: { runType, configuration: runtime.telemetryConfiguration, }, }, }); } } async *executeForChat(config) { const { agentId, projectId, message, user, memory, onExecutionRecorded } = config; const runtime = await this.runtimeCacheService.getRuntime({ agentId, projectId, integrationType: api_types_1.N8N_CHAT_INTEGRATION_TYPE, user, }); await this.integrationMessageContextService.setLatest(memory.threadId, memory.resourceId, { integrationConnectionId: api_types_1.N8N_CHAT_INTEGRATION_TYPE, platform: api_types_1.N8N_CHAT_INTEGRATION_TYPE, target: { type: 'dm', userId: user.id, threadId: memory.threadId }, interactingUserId: user.id, updatedAt: new Date().toISOString(), }); yield* this.streamChatResponse({ agentInstance: runtime.agent, toolRegistry: runtime.toolRegistry, agentId, userId: user.id, message, memory, projectId: runtime.projectId, telemetry: { runType: 'test', configuration: runtime.telemetryConfiguration, }, onExecutionRecorded, }); } async *executeForChatPublished(config) { const { agentId, projectId, message, memory, integrationType } = config; await this.externalHooks.run('agent.preExecute', [agentId]); const runtime = await this.runtimeCacheService.getRuntime({ agentId, projectId, integrationType, usePublishedVersion: true, }); yield* this.streamChatResponse({ agentInstance: runtime.agent, toolRegistry: runtime.toolRegistry, agentId, message, memory, projectId: runtime.projectId, source: integrationType, telemetry: { runType: 'production', configuration: runtime.telemetryConfiguration, }, }); } async *executeForTaskPublished(config) { const { agentId, projectId, message, memory, taskId, taskVersionId } = config; await this.externalHooks.run('agent.preExecute', [agentId]); const runtime = await this.runtimeCacheService.getRuntime({ agentId, projectId, integrationType: 'task', usePublishedVersion: true, }); yield* this.streamChatResponse({ agentInstance: runtime.agent, toolRegistry: runtime.toolRegistry, agentId, message, memory, projectId: runtime.projectId, source: 'task', taskId, taskVersionId, telemetry: { runType: 'production', configuration: runtime.telemetryConfiguration, }, }); } async *executeForTaskNow(config) { const { agentId, projectId, user, message, memory, taskId } = config; const runtime = await this.runtimeCacheService.getRuntime({ agentId, projectId, user, }); yield* this.streamChatResponse({ agentInstance: runtime.agent, toolRegistry: runtime.toolRegistry, agentId, userId: user.id, message, memory, projectId: runtime.projectId, source: 'task', taskId, telemetry: { runType: 'test', configuration: runtime.telemetryConfiguration, }, }); } async *streamChatResponse(config) { const { agentInstance, toolRegistry, agentId, userId, message, memory, projectId, source, taskId, taskVersionId, telemetry, onExecutionRecorded, } = config; const { threadId, resourceId } = memory; const recorder = new execution_recorder_1.ExecutionRecorder(toolRegistry); try { const tracing = await this.agentRunTracingService.build({ agentId, projectId, threadId, userId, source: source ?? 'test', modelId: (0, agent_run_tracing_service_1.modelIdFromSnapshot)(agentInstance.snapshot.model), }); const resultStream = await agentInstance.stream(message, { persistence: { threadId, resourceId }, executionCounter: (0, agent_execution_counter_1.createAgentExecutionCounter)(this.telemetry, { agentId, userId }), ...(tracing ? { telemetry: tracing } : {}), }); for await (const value of (0, agent_stream_1.streamAgentChunks)(resultStream.stream)) { recorder.record(value); if (value.type === 'tool-call-suspended') { this.logger.info('Chat: tool-call-suspended chunk received', { agentId, toolCallId: value.toolCallId, toolName: value.toolName, }); } if (value.type === 'finish' && value.finishReason === 'max-iterations') { for (const chunk of getMaxIterationsChunks()) { recorder.record(chunk); yield chunk; } } yield value; } } catch (error) { recorder.record({ type: 'error', error }); recorder.record({ type: 'finish', finishReason: 'error' }); throw error; } finally { const messageRecord = recorder.getMessageRecord(); await this.persistRecordedExecution({ onExecutionRecorded, failureMessage: 'Failed to record agent execution', params: { threadId, agentId, agentName: agentInstance.name, projectId, userMessage: message, record: messageRecord, hitlStatus: recorder.suspended ? 'suspended' : undefined, source, taskId, taskVersionId, telemetry, }, }); } } async persistRecordedExecution(args) { const { onExecutionRecorded, params, failureMessage } = args; const persist = async () => { const executionId = await this.agentExecutionService.recordMessage(params); onExecutionRecorded?.(executionId); }; const logFailure = (error) => { this.logger.warn(failureMessage, { agentId: params.agentId, threadId: params.threadId, error: error instanceof Error ? error.message : String(error), }); }; if (onExecutionRecorded) { try { await persist(); } catch (error) { logFailure(error); } } else { void persist().catch(logFailure); } } }; exports.AgentExecutionOrchestratorService = AgentExecutionOrchestratorService; exports.AgentExecutionOrchestratorService = AgentExecutionOrchestratorService = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [backend_common_1.Logger, n8n_checkpoint_storage_1.N8NCheckpointStorage, agent_execution_service_1.AgentExecutionService, telemetry_1.Telemetry, agent_runtime_cache_service_1.AgentRuntimeCacheService, integration_message_context_service_1.IntegrationMessageContextService, agent_run_tracing_service_1.AgentRunTracingService, external_hooks_1.ExternalHooks]) ], AgentExecutionOrchestratorService); //# sourceMappingURL=agent-execution-orchestrator.service.js.map