Skip to content

feat: initial n8n integration experiment - #50

Draft
BobdenOs wants to merge 3 commits into
mainfrom
feat/n8n
Draft

feat: initial n8n integration experiment#50
BobdenOs wants to merge 3 commits into
mainfrom
feat/n8n

Conversation

@BobdenOs

@BobdenOs BobdenOs commented Aug 9, 2026

Copy link
Copy Markdown

overview

Experimental workflow integration leveraging the out-of-the-box benefits from CAP best practices.

With the recent partnership between SAP and n8n it seemed fitting to experiment with a first class citizen experience between n8n and CAP.

Choice Paralysis

With the heavy focus of n8n on promoting their >2000 integration nodes it results in a counter productive user experience. Therefor this CAP integration is heavily focused on leveraging the existing CAP capabilities to provide the actually useful nodes.

image

Agent integration

With the @agent annotation it becomes possible to develop custom agents with easy leveraging the CAP capabilities. This comes with perfect integration with n8n as it removes the large amount of LLM provider nodes that actual n8n users have to dig through to get their LLM powered nodes to function. With the cap llm service being defined it is not even required to select a model in your workflow to make the LLM powered nodes work. There still is a specialized CAP LLM node that allows you to pick which CAP service should be exactly used to provide the LLM connection. This gives the flexibility to switch between big and small models to your specific tasks requirements.

image

Data integration

As CAP is very powerful in its ability to model and query data there is no need to use the n8n specific data storage approaches. Which also comes with massive anti patterns (e.g. excel sheets, csv files, application layer processing). It is as simple as picking your preferred level of complexity by either taking the CAP Entity node or the CAP CQL Query node. But do not worry even if you do not know much about CAP you will still be powered by all the best practices.

The default Data transformation nodes of n8n are actually being collapsed into CQL behind the scenes. Which means you get all the exact same n8n user experience. With the exact same CAP powered database push down. Which can greatly reduce the amount of data movement and processing as the database query execution optimizer will have a wholistic view of your data manipulation intends. It also comes with the big benefit that pretty much all the n8n nodes are expected to be run against a single item at a time. Which means that of course internally the result of the accumulated CQL query are streamed row by row from the database ensuring that even large datasets will flow through your workflow without any limitations.

image

Action integration

You might be scared that some of the feature that you need are not being exposed by n8n or are missing from the CAP integration. It can be complicated to define your own custom n8n nodes, but this is not a concern for CAP applications. As it is as simple as defining your own action in the CAP application and using the "CAP action" node to bridge any gaps you could possibly encounter.

image

Event driven

One of the biggest complexities of running large workflows or task chains. Is to ensure your system does not get overloaded as all time based workflows are triggered at 0 0 * * * / 12 am midnight. Therefor the workflows steps are flowing through the CAP queue. Allowing the CAP instances to share the load throughout the system and ensures that if an instance encounters problems that the workflow will perform reliably. Retrying in between nodes having easy to recover and continue the workflow without having to ever restart the whole workflow. This ability to retain the intermediate state is especially important if very expensive LLM based nodes have successfully produced their results. It would double or triple the LLM costs if these nodes would have to run every try.

image

Authentication

A large benefit of having the system be merged directly into CAP is that it leverage the exact same authentication and authorization principles. Removing the need to register separate credentials or crossing between systems with the potential that users might get elevated privileges once the workflow starts processing their requests.

Local development

One of the biggest powers of CAP as a framework is its ability to run locally offline with mocks and with very fast development cycles. This integration gains the exact same benefits simply use cds w and any changes you make to your model will be directly reflected in your CAP nodes. Allowing for an agile development cycle as most CAP users are already gotten used to. If you use the default SQLite in memory database you might have to recreate your workflow a few times.

@hyperspace-pr-bot

Copy link
Copy Markdown
Contributor

Summary

The following content is AI-generated and provides a summary of the pull request:


feat: Initial n8n Integration Experiment 🔗

This PR introduces an experimental, first-class CAP integration with n8n, replacing the typical n8n server process entirely with a native CAP-hosted implementation. CAP serves the n8n editor UI, owns all workflow execution, and leverages existing CAP capabilities (data, actions, agents, LLM, auth) directly.

🗂️ What's Changed

New: CAP-native n8n Engine

  • lib/n8n/N8nAdapter.cjs — Registers n8n as a CAP protocol adapter (cds.service.protocols['n8n']) so any CDS service annotated with @n8n is automatically mounted.
  • lib/n8n/api-adapter.js — Full Express router implementing the n8n REST API (/rest/*, /api/v1/*, /webhook-test/*, SSE push) backed entirely by CAP, with no n8n process running. Handles static asset serving, static cache generation from n8n-editor-ui, and SPA fallback.
  • srv/N8nService.cds + srv/N8nService.js — CAP ApplicationService that executes workflow graphs in-process, routing node outputs via cds.emit('workflow.step'). Supports partial execution, pin data, multi-input (Merge/CompareDatasets), batching (SplitInBatches), retryOnFail, continueOnFail, and stale execution cleanup.
  • db/n8n.cds — CDS entities for persisting WorkflowDefinitions, WorkflowExecutions, and WorkflowStepResults.

New: Node Executors (lib/n8n/nodes/executors/)

Native CAP implementations for all supported n8n node types:

Category Nodes
Flow control ManualTrigger, If, Switch, Filter, SplitInBatches/Loop, Wait, StopAndError, NoOp
Data Set, Code, Merge, SplitOut, Sort, Summarize, Limit, RemoveDuplicates, CompareDatasets, DateTime
Format Markdown, Html, Xml
Connectivity HttpRequest, RespondToWebhook, ExecuteWorkflow, ExecuteWorkflowTrigger, ErrorTrigger, StickyNote, ChatTrigger, Chat
CAP custom capEntity (CRUD), capAction, capCql, capLlmProvider, capAgent (A2A)
LangChain AI chainLlm, textClassifier, chainSummarization, sentimentAnalysis, informationExtractor, guardrails, agent

Shared utilities: resolve.js (n8n expression resolver with fast-paths), conditions.js (full filter/condition evaluator), llm.js (shared LLM caller via cds.requires.llm).

Modified

  • cds-plugin.js — Registers the n8n protocol adapter and mounts static files after serving.
  • package.json — Adds n8n as an optional peer dependency, registers the n8n CDS kind, includes db/ in published files, and adds optional dependencies (cheerio, showdown, xml2js, node-html-markdown).
  • tests/bookshop/ — Minor updates: repository URL fix, adds @cap-js/agents, bumps @sap/cds-common-content, adds cds watch script, and wires n8n/llm in CDS requires.

Have you...

  • Added relevant entry to the change log?

  • 🔄 Regenerate and Update Summary
  • ✏️ Insert as PR Description (deletes this comment)
  • 🗑️ Delete comment
PR Bot Information

Version: 1.29.18

  • LLM: anthropic--claude-4.6-sonnet
  • Correlation ID: a11fb5e0-943a-11f1-9622-6451c71a8a30
  • Summary Prompt: Default Prompt
  • File Content Strategy: Full file content
  • Output Template: Repository PR Template
  • Event Trigger: pull_request.opened

Comment thread lib/n8n/nodes/executors/Markdown.js Fixed
Comment thread lib/n8n/nodes/executors/Set.js Fixed
Comment thread lib/n8n/nodes/executors/conditions.js Fixed
Comment thread lib/n8n/nodes/executors/conditions.js Fixed
Comment thread lib/n8n/nodes/executors/Summarize.js Fixed
Comment thread lib/n8n/nodes/executors/Summarize.js Fixed
Comment thread lib/n8n/nodes/executors/Summarize.js Fixed
Comment thread lib/n8n/nodes/executors/CapAiClassify.js Fixed
Comment thread lib/n8n/nodes/executors/CapAiExtract.js Fixed
Comment thread lib/n8n/nodes/executors/HttpRequest.js Fixed
Comment thread lib/n8n/nodes/executors/SplitOut.js Fixed
Comment thread lib/n8n/nodes/executors/Summarize.js Fixed
- CQL query token fusion: capEntity(list/get) and capCql nodes emit a
  _cql_query token instead of executing immediately. Downstream foldable
  nodes (Filter→WHERE, Sort→ORDER BY, Limit→LIMIT, If→two-branch WHERE)
  fold into the token and pass it on with no data flowing. The first
  non-foldable consumer executes the accumulated query. Recorded outputs
  for token nodes are stripped so the UI shows no items and no arrows on
  fused chains.

- Preview mode (UI "run current/previous node"): token nodes execute
  directly at the target node only, capped to 1 row, so the editor can
  show type information without fetching full result sets.

- Privileged execution: capEntity create/update/delete and capAction run
  under cds.User.Privileged so @requires annotations don't block
  workflow-driven calls.

- $node[...].json expression support: makeAccessor gains a .json getter
  so $node["NodeName"].json.field resolves correctly.

- Seed workflows: wf-book-catalog, wf-book-detail, wf-book-lifecycle,
  wf-place-order, wf-stock-report, wf-author-bibliography, wf-key-variants,
  wf-catalog-enriched, wf-chapter-browser, wf-fusion-demo and sub-workflows.

- Test suite: 24 tests across cap-entity and cap-action covering all
  seed workflows end-to-end through the HTTP layer.
Comment thread srv/N8nService.js
// Persist all port arrays so the UI can show each port's items per run.
await this._recordStep(executionId, nodeId, 'success', recordedOutputs, null)
// runIndex was just incremented by _recordStep; the current run is at index - 1
const nodeRunIndex = (_nodeRunIndex[executionId]?.[nodeId] ?? 1) - 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants