Skip to content

feat: use JSON for agent configuration#28339

Open
yehorkardash wants to merge 56 commits inton8n-agentsfrom
n8n-agents-json-config
Open

feat: use JSON for agent configuration#28339
yehorkardash wants to merge 56 commits inton8n-agentsfrom
n8n-agents-json-config

Conversation

@yehorkardash
Copy link
Copy Markdown
Contributor

@yehorkardash yehorkardash commented Apr 10, 2026

Summary

Introduces a JSON-based builder mode for the agent builder. The builder LLM now writes and patches the agent configuration as raw JSON strings rather than through writing typescript code. Custom tools are still written using typescript.

The builder prompt includes examples of using different features and simplified json schema of the agent config.
There's a custom json schema serializer that reduces token size of schema by around ~40%

Serialized agent schema
  name: string [1..128 chars] (required)
  description?: string [max 512 chars]
  model: string [min 1 chars, pattern: ^[a-z0-9-]+\\/[a-z0-9._-]+$] (required)
  credential: string [min 1 chars] (required)
  instructions: string (required)
  memory?: object
    enabled: boolean (required)
    storage: \"n8n\" | \"sqlite\" | \"postgres\" (required)
    connection?: Record<string, unknown>
    lastMessages?: integer [1..200]
    semanticRecall?: object
      topK: integer [1..100] (required)
      scope?: \"thread\" | \"resource\"
      messageRange?: object
        before: integer [min 0] (required)
        after: integer [min 0] (required)
      embedder?: string
  tools?: array with items any of:
    | (type = \"custom\")
      id: string [min 1 chars, pattern: ^[a-z0-9_-]+$] (required)
      requireApproval?: boolean
    | (type = \"workflow\")
      workflow: string [min 1 chars] (required)
      name?: string
      description?: string
      requireApproval?: boolean
      allOutputs?: boolean
    | (type = \"node\")
      name: string [min 1 chars] (required)
      description?: string
      node: object (required)
        nodeType: string [min 1 chars] (required)
        nodeTypeVersion: number (required)
        nodeParameters?: Record<string, unknown>
        credentials?: Record<string, { id: string, name: string }>
      inputSchema: object (required)
        type?: \"object\"
        properties?: Record<string, unknown>
        required?: array of <string>
      requireApproval?: boolean
  providerTools?: Record<string, Record<string, unknown>>
  config?: object
    thinking?: object
      provider: \"anthropic\" | \"openai\" (required)
      budgetTokens?: integer
      reasoningEffort?: string
    toolCallConcurrency?: integer [1..20]
    requireToolApproval?: boolean

The builder has access to two groups of tools:

Config tools (JSON mode)

Tool What it does
write_config Full replace — accepts a complete agent config as a JSON string, validates it, and persists it
patch_config Incremental update — accepts RFC 6902 JSON Patch operations, applies them to the current config via fast-json-patch, validates the result, and persists it

Both tools return { ok: true } on success or { ok: false, errors } with structured path/message/expected/received fields on failure. patch_config additionally returns a stage ("parse", "patch", or "schema") indicating where the failure occurred.

Shared tools (always present)

Tool What it does
build_custom_tool Writes or updates a custom TypeScript tool using the Tool builder API; validates the code in a sandbox before saving
list_credentials Lists credentials available in the project — call this before generating config
list_workflows Lists project workflows with compatible trigger types (manual, chat, schedule, etc.)
search_nodes Searches for n8n integration nodes by name or service
get_node_types Returns the full parameter schema for specific node IDs found via search_nodes

Validation pipeline

write_config and patch_config pass every config through the same pipeline:

  1. tryParseConfigJson — catches JSON.parse failures with position info
  2. AgentJsonConfigSchema.safeParse (Zod) — validates schema shape and field constraints
  3. agentsService.updateConfig — persists to the database

Zod errors are normalized by formatZodErrors into { path, message, expected, received } objects so the LLM can self-correct.

Related Linear tickets, Github issues, and Community forum posts

Review / Merge checklist

  • I have seen this code, I have run this code, and I take responsibility for this code.
  • PR title and summary are descriptive. (conventions)
  • Docs updated or follow-up ticket created.
  • Tests included.
  • PR Labeled with Backport to Beta, Backport to Stable, or Backport to v1 (if the PR is an urgent fix that needs to be backported)

@yehorkardash yehorkardash requested a review from a team as a code owner April 10, 2026 14:28
@yehorkardash yehorkardash removed the request for review from a team April 10, 2026 14:28
@n8n-assistant n8n-assistant bot added core Enhancement outside /nodes-base and /editor-ui n8n team Authored by the n8n team labels Apr 10, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 10, 2026

Bundle Report

Changes will decrease total bundle size by 87.43kB (-0.19%) ⬇️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
editor-ui-esm 45.6MB -87.43kB (-0.19%) ⬇️

Affected Assets, Files, and Routes:

view changes for bundle: editor-ui-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/worker-*.js 3.14MB 3.16MB 17560.39% ⚠️
assets/worker-*.js -3.14MB 17.9kB -99.43%
assets/src-*.js -676 bytes 2.42MB -0.03%
assets/index-*.js 592 bytes 1.31MB 0.05%
assets/ParameterInputList-*.js -39 bytes 1.27MB -0.0%
assets/dist-*.js 20.96kB 878.18kB 2.45%
assets/dist-*.js (New) 11.67kB 11.67kB 100.0% 🚀
assets/index-*.css -1.43kB 812.8kB -0.18%
assets/NDVEmptyState-*.js 719.23kB 721.41kB 33083.39% ⚠️
assets/useCanvasMapping-*.js -212 bytes 462.48kB -0.05%
assets/RunData-*.js 72.35kB 334.28kB 27.62% ⚠️
assets/InstanceAiView-*.js -29.38kB 288.94kB -9.23%
assets/NodeView-*.js -49 bytes 137.14kB -0.04%
assets/NodeCreator-*.js -419 bytes 103.45kB -0.4%
assets/VirtualSchema-*.js -39 bytes 94.47kB -0.04%
assets/CanvasRunWorkflowButton-*.js 6.68kB 84.32kB 8.61% ⚠️
assets/AgentBuilderView-*.js -4.45kB 78.6kB -5.35%
assets/CreditWarningBanner-*.js 429 bytes 53.56kB 0.81%
assets/SettingsInstanceAiView-*.js 545 bytes 43.17kB 1.28%
assets/NodeDetailsViewV2-*.js -184 bytes 37.85kB -0.48%
assets/SettingsInstanceAiView-*.css 62 bytes 23.63kB 0.26%
assets/AgentBuilderView-*.css -1.8kB 17.77kB -9.19%
assets/instanceAiSettings.store-*.js 355 bytes 13.69kB 2.66%
assets/DataTableDetailsView-*.css -23 bytes 6.41kB -0.36%
assets/nodeIcon-*.js -447 bytes 4.28kB -9.46%
assets/useAgentApi-*.js -27 bytes 2.56kB -1.04%
assets/estree-*.js (Deleted) -719.24kB 0 bytes -100.0% 🗑️
assets/theme-*.js (Deleted) -84.16kB 0 bytes -100.0% 🗑️
assets/node-*.js (Deleted) -70.47kB 0 bytes -100.0% 🗑️
assets/setupPanel.utils-*.js (Deleted) -7.27kB 0 bytes -100.0% 🗑️

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Apr 10, 2026

Merging this PR will not alter performance

✅ 32 untouched benchmarks
⏩ 20 skipped benchmarks1


Comparing n8n-agents-json-config (41b37e0) with master (9072365)2

Open in CodSpeed

Footnotes

  1. 20 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on n8n-agents (c0ff016) during the generation of this report, so master (9072365) was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7 issues found across 61 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/modules/agents/schema-text-serializer.ts">

<violation number="1" location="packages/cli/src/modules/agents/schema-text-serializer.ts:55">
P2: Array item unions are reduced to `unknown`, so discriminated-union item schemas lose their shape in output.</violation>

<violation number="2" location="packages/cli/src/modules/agents/schema-text-serializer.ts:85">
P1: Union fields are serialized as `array of ...`, which misrepresents `oneOf`/`anyOf` schemas.</violation>
</file>

<file name="packages/cli/src/modules/agents/__tests__/agent-secure-runtime.test.ts">

<violation number="1" location="packages/cli/src/modules/agents/__tests__/agent-secure-runtime.test.ts:318">
P2: Pass the tool input object as the second argument. The current call sends `'double'` into the handler, so the test won't produce `{ result: 42 }`.</violation>
</file>

<file name="packages/frontend/editor-ui/src/features/agents/components/AgentCodeEditor.vue">

<violation number="1" location="packages/frontend/editor-ui/src/features/agents/components/AgentCodeEditor.vue:102">
P2: Avoid duplicating the tool editor initialization logic; reuse `createToolEditor()` in the expanded-tools watcher to prevent divergence between two code paths.</violation>

<violation number="2" location="packages/frontend/editor-ui/src/features/agents/components/AgentCodeEditor.vue:180">
P2: Destroy and remove `toolViews` entries when a tool ID is removed from `agentTools` to avoid stale editor instances accumulating during runtime updates.</violation>
</file>

<file name="packages/@n8n/agents/src/sdk/agent.ts">

<violation number="1" location="packages/@n8n/agents/src/sdk/agent.ts:550">
P2: `snapshot` leaks a mutable reference to internal `thinkingConfig`, so external code can mutate agent state through what is documented as a read-only view.</violation>
</file>

<file name="packages/cli/src/modules/agents/agents.service.ts">

<violation number="1" location="packages/cli/src/modules/agents/agents.service.ts:25">
P2: Custom agent: **Quality & Performance Review**

Top-level import of `@n8n/workflow-sdk` eagerly loads a heavy dependency even though it is only needed in node-tool config validation flow.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant UI as Browser (Frontend)
    participant API as Agents Controller
    participant Tools as Agents Builder Tools
    participant Sandbox as Secure Runtime (IVM)
    participant DB as Database (Agents Table)

    Note over UI,DB: NEW: JSON-Based Agent Builder Flow

    UI->>API: POST /chat (Builder Mode)
    API->>Tools: Invoke Builder LLM

    alt NEW: Update Configuration (write_config / patch_config)
        Tools->>Tools: NEW: tryParseConfigJson()
        Tools->>Tools: NEW: fast-json-patch (if patching)
        Tools->>Tools: NEW: AgentJsonConfigSchema.safeParse (Zod)
        alt Validation Success
            Tools->>DB: NEW: updateConfig (Persist JSON)
            DB-->>Tools: ok: true
        else Validation Failure
            Tools-->>Tools: formatZodErrors()
            Tools-->>API: { ok: false, errors }
        end
    end

    alt NEW: Define Custom Tool (build_custom_tool)
        Tools->>Sandbox: NEW: describeToolSecurely(tsCode)
        Sandbox->>Sandbox: Compile TS to JS
        Sandbox-->>Tools: ToolDescriptor (JSON Schema)
        Tools->>DB: NEW: Save TS + Descriptor to 'tools' column
        DB-->>Tools: Saved
    end

    alt Shared Discovery Tools
        Tools->>DB: list_workflows / list_credentials
        DB-->>Tools: Result sets
        Tools->>Tools: search_nodes / get_node_types
    end

    Tools-->>API: Stream chunks / Tool results
    API-->>UI: SSE Stream (configUpdated / toolUpdated)

    Note over UI,DB: NEW: Runtime Agent Bootstrapping

    UI->>API: POST /chat (Agent Execution)
    API->>DB: Fetch JSON config & custom tools
    DB-->>API: Agent record (JSON schema + tools)
    API->>API: NEW: buildFromJson()
    Note right of API: Binds custom tools to Isolated-VM handlers
    API->>API: Agent.execute()
    API-->>UI: Response
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 10, 2026

Performance Comparison

Comparing currentlatest master14-day baseline

Memory consumption baseline with starter plan resources

Metric Current Latest Master Baseline (avg) vs Master vs Baseline Status
memory-heap-used-baseline 114.93 MB 114.53 MB 113.09 MB (σ 1.15) +0.3% +1.6% ⚠️
memory-rss-baseline 277.90 MB 287.07 MB 281.78 MB (σ 34.50) -3.2% -1.4%

docker-stats

Metric Current Latest Master Baseline (avg) vs Master vs Baseline Status
docker-image-size-runners 386.00 MB 386.00 MB 387.50 MB (σ 3.00) +0.0% -0.4%
docker-image-size-n8n 1280.00 MB 1269.76 MB 1269.76 MB (σ 0.00) +0.8% +0.8%

Idle baseline with Instance AI module loaded

Metric Current Latest Master Baseline (avg) vs Master vs Baseline Status
instance-ai-rss-baseline 347.86 MB 394.55 MB 369.15 MB (< 3 samples) -11.8% -5.8%
instance-ai-heap-used-baseline 186.84 MB 186.51 MB 186.46 MB (< 3 samples) +0.2% +0.2%
How to read this table
  • Current: This PR's value (or latest master if PR perf tests haven't run)
  • Latest Master: Most recent nightly master measurement
  • Baseline: Rolling 14-day average from master
  • vs Master: PR impact (current vs latest master)
  • vs Baseline: Drift from baseline (current vs rolling avg)
  • Status: ✅ within 1σ | ⚠️ 1-2σ | 🔴 >2σ regression

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/modules/agents/json-config/schema-text-serializer.ts">

<violation number="1" location="packages/cli/src/modules/agents/json-config/schema-text-serializer.ts:346">
P2: `serializeArrayUnion()` drops `(required)` / `(default: ...)` metadata for array-union fields, so required fields can be rendered as if optional.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Enhancement outside /nodes-base and /editor-ui n8n team Authored by the n8n team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant