UNPKG

n8n

Version:

n8n Workflow Automation Tool

123 lines 5.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InstanceAiLivenessService = exports.INSTANCE_AI_RUN_TIMEOUT_REASON = void 0; const constants_1 = require("@n8n/constants"); const ORCHESTRATOR_AGENT_ID = 'agent-001'; exports.INSTANCE_AI_RUN_TIMEOUT_REASON = 'timeout'; const RUN_TIMEOUT_MESSAGE = 'The run stopped making progress, so I cancelled it. You can retry or adjust the request.'; function getErrorMessage(error) { return error instanceof Error ? error.message : String(error); } class InstanceAiLivenessService { constructor(options) { this.options = options; this.timedOutRunIds = new Set(); this.timedOutActiveRunThreads = new Set(); } get backgroundTaskIdleTimeoutMs() { return this.options.backgroundTaskIdleTimeoutMs; } start() { if (!this.options.policy.hasEnabledTimeouts()) return; this.timeoutInterval = setInterval(() => { void this.sweepTimedOutWork(); }, constants_1.Time.minutes.toMilliseconds); } shutdown() { if (this.timeoutInterval) { clearInterval(this.timeoutInterval); this.timeoutInterval = undefined; } this.timedOutRunIds.clear(); this.timedOutActiveRunThreads.clear(); } clearThreadState(threadId) { this.timedOutActiveRunThreads.delete(threadId); } markRunTimedOut(runId) { this.timedOutRunIds.add(runId); } consumeRunTimedOut(runId) { const timedOut = this.timedOutRunIds.has(runId); if (timedOut) this.timedOutRunIds.delete(runId); return timedOut; } hasTimedOutActiveRunThread(threadId) { return this.timedOutActiveRunThreads.has(threadId); } async sweepTimedOutWork(now = Date.now()) { const { activeThreadIds, suspendedThreadIds, confirmationRequestIds } = this.options.runState.sweepTimedOut(this.options.policy, now); for (const threadId of activeThreadIds) { this.options.logger.debug('Cancelling timed-out active run', { threadId }); this.cancelTimedOutActiveRun(threadId); } for (const threadId of suspendedThreadIds) { this.options.logger.debug('Auto-rejecting timed-out suspended run', { threadId }); this.cancelTimedOutSuspendedRun(threadId); } for (const reqId of confirmationRequestIds) { this.options.logger.debug('Auto-rejecting timed-out sub-agent confirmation', { requestId: reqId, }); const pending = this.options.runState.getPendingConfirmation(reqId); if (pending) { const runId = this.options.runState.getActiveRunId(pending.threadId); if (runId) this.publishRunTimeoutNotice(pending.threadId, runId); } this.options.runState.rejectPendingConfirmation(reqId); } try { const timedOutTasks = await this.options.backgroundTasks.timeoutTimedOutTasks(this.options.policy, now); for (const task of timedOutTasks) { this.options.logger.debug('Timed out background task', { threadId: task.threadId, taskId: task.taskId, role: task.role, timeoutReason: task.timeoutReason, }); } } catch (error) { this.options.logger.warn('Failed to sweep timed-out background tasks', { error: getErrorMessage(error), }); } } cancelTimedOutActiveRun(threadId) { const active = this.options.runState.cancelActiveRun(threadId); if (!active) return; this.markRunTimedOut(active.runId); this.timedOutActiveRunThreads.add(threadId); this.publishRunTimeoutNotice(threadId, active.runId); active.abortController.abort(); } cancelTimedOutSuspendedRun(threadId) { const suspended = this.options.runState.cancelSuspendedRun(threadId); if (!suspended) return; this.markRunTimedOut(suspended.runId); suspended.abortController.abort(); this.options.finalizeCancelledSuspendedRun(suspended, exports.INSTANCE_AI_RUN_TIMEOUT_REASON); } publishRunTimeoutNotice(threadId, runId) { const responseId = `run-timeout:${runId}`; const alreadyPublished = this.options.eventBus .getEventsForRun(threadId, runId) .some((event) => event.responseId === responseId); if (alreadyPublished) return; this.options.eventBus.publish(threadId, { type: 'text-delta', runId, agentId: ORCHESTRATOR_AGENT_ID, responseId, payload: { text: RUN_TIMEOUT_MESSAGE }, }); } } exports.InstanceAiLivenessService = InstanceAiLivenessService; //# sourceMappingURL=instance-ai-liveness.service.js.map