UNPKG

n8n

Version:

n8n Workflow Automation Tool

194 lines 6.77 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.initSseStream = initSseStream; exports.pumpChunks = pumpChunks; const agents_1 = require("@n8n/agents"); function initSseStream(res) { res.setHeader('Content-Type', 'text/event-stream; charset=UTF-8'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.setHeader('X-Accel-Buffering', 'no'); res.flushHeaders(); res.socket?.setNoDelay?.(true); const send = (event) => { res.write(`data: ${JSON.stringify(event)}\n\n`); res.flush?.(); }; return { send }; } function toAgentSseMessage(message) { if (!('content' in message) || !Array.isArray(message.content)) return undefined; const content = []; for (const part of message.content) { if (part.type === 'text' && 'text' in part) { content.push({ type: 'text', text: part.text }); } else if (part.type === 'reasoning' && 'text' in part) { content.push({ type: 'reasoning', text: part.text }); } } if (content.length === 0) return undefined; return { role: message.role, content }; } function emitTextLikeChunk(chunk, send) { switch (chunk.type) { case 'text-start': send({ type: 'text-start', id: chunk.id }); break; case 'text-delta': if (chunk.delta) send({ type: 'text-delta', id: chunk.id, delta: chunk.delta }); break; case 'text-end': send({ type: 'text-end', id: chunk.id }); break; case 'reasoning-start': send({ type: 'reasoning-start', id: chunk.id }); break; case 'reasoning-delta': if (chunk.delta) send({ type: 'reasoning-delta', id: chunk.id, delta: chunk.delta }); break; case 'reasoning-end': send({ type: 'reasoning-end', id: chunk.id }); break; } } function handleWorkingMemoryChunk(chunk, ctx) { const { send, workingMemoryToolCallIds } = ctx; const isWmName = 'toolName' in chunk && chunk.toolName === agents_1.UPDATE_WORKING_MEMORY_TOOL_NAME; if (chunk.type === 'tool-input-delta') { return workingMemoryToolCallIds.has(chunk.toolCallId); } if (!isWmName) return false; if (chunk.type === 'tool-input-start' || chunk.type === 'tool-call') { workingMemoryToolCallIds.add(chunk.toolCallId); return true; } if (chunk.type === 'tool-execution-start') return true; if (chunk.type === 'tool-result') { if (chunk.isError) { const errMsg = chunk.output instanceof Error ? chunk.output.message : String(chunk.output); send({ type: 'error', message: `Working memory update failed: ${errMsg}` }); } else { send({ type: 'working-memory-update', toolName: chunk.toolName }); } return true; } return false; } function emitToolChunk(chunk, ctx) { const { send, onToolEvent } = ctx; if (chunk.type !== 'tool-call-suspended' && handleWorkingMemoryChunk(chunk, ctx)) { return { suspended: false }; } switch (chunk.type) { case 'tool-input-start': send({ type: 'tool-input-start', toolCallId: chunk.toolCallId, toolName: chunk.toolName, }); onToolEvent?.toolInputStart?.(chunk.toolName); break; case 'tool-input-delta': if (chunk.delta) { send({ type: 'tool-input-delta', toolCallId: chunk.toolCallId, delta: chunk.delta }); onToolEvent?.toolInputDelta?.(chunk.toolCallId, chunk.delta); } break; case 'tool-call': send({ type: 'tool-call', toolCallId: chunk.toolCallId, toolName: chunk.toolName, input: chunk.input, }); break; case 'tool-execution-start': send({ type: 'tool-execution-start', toolCallId: chunk.toolCallId, toolName: chunk.toolName, }); break; case 'tool-result': send({ type: 'tool-result', toolCallId: chunk.toolCallId, toolName: chunk.toolName, output: chunk.output, ...(chunk.isError !== undefined && { isError: chunk.isError }), }); onToolEvent?.toolResult?.(chunk.toolName); break; case 'tool-call-suspended': { const payload = { toolCallId: chunk.toolCallId, runId: chunk.runId, toolName: chunk.toolName, input: chunk.suspendPayload, }; send({ type: 'tool-call-suspended', payload }); return { suspended: true }; } } return { suspended: false }; } function emitChunkEvents(chunk, ctx) { switch (chunk.type) { case 'start-step': ctx.send({ type: 'start-step' }); return { suspended: false }; case 'finish-step': ctx.send({ type: 'finish-step' }); return { suspended: false }; case 'text-start': case 'text-delta': case 'text-end': case 'reasoning-start': case 'reasoning-delta': case 'reasoning-end': emitTextLikeChunk(chunk, ctx.send); return { suspended: false }; case 'tool-input-start': case 'tool-input-delta': case 'tool-call': case 'tool-execution-start': case 'tool-result': case 'tool-call-suspended': return emitToolChunk(chunk, ctx); case 'message': { const sseMessage = toAgentSseMessage(chunk.message); if (sseMessage) ctx.send({ type: 'message', message: sseMessage }); return { suspended: false }; } case 'error': { const errMsg = chunk.error instanceof Error ? chunk.error.message : String(chunk.error); ctx.send({ type: 'error', message: errMsg }); return { suspended: false }; } default: return { suspended: false }; } } async function pumpChunks(chunks, send, onToolEvent) { const ctx = { send, onToolEvent, workingMemoryToolCallIds: new Set(), }; for await (const chunk of chunks) { const { suspended } = emitChunkEvents(chunk, ctx); if (suspended) return true; } return false; } //# sourceMappingURL=agent-sse-stream.js.map