n8n-nodes-openrouter-noreasoning 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Codialab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # n8n-nodes-openrouter-noreasoning
2
+
3
+ ![Version](https://img.shields.io/npm/v/n8n-nodes-openrouter-noreasoning.svg)
4
+ ![License](https://img.shields.io/npm/l/n8n-nodes-openrouter-noreasoning.svg)
5
+
6
+ A drop-in replacement for the official n8n **OpenRouter Chat Model** node that forces `reasoning: { enabled: false }` on every request. This fixes a current bug where DeepSeek V4 and V3.2 served through OpenRouter break tool calling when reasoning ("thinking") mode is active inside the n8n AI Agent.
7
+
8
+ ## Why this exists
9
+
10
+ OpenRouter's DeepSeek V4 / V3.2 endpoints currently emit `reasoning_content` tokens by default. When n8n's AI Agent receives those alongside `tool_calls`, the LangChain tool-calling loop fails to parse the assistant turn and the agent either repeats the same tool call forever or returns an empty response.
11
+
12
+ The cleanest fix is to send `"reasoning": {"enabled": false}` in the body of every chat completion request. The official OpenRouter node does not expose this flag, so this community node injects it via LangChain's `modelKwargs`.
13
+
14
+ For background see the OpenRouter docs on the [reasoning parameter](https://openrouter.ai/docs/use-cases/reasoning-tokens) and the upstream discussion in [DeepSeek + tool calling on OpenRouter](https://github.com/OpenRouterTeam/openrouter-runner/issues).
15
+
16
+ ## Installation
17
+
18
+ Inside your n8n instance:
19
+
20
+ 1. Open **Settings → Community Nodes**
21
+ 2. Click **Install**
22
+ 3. Enter the package name: `n8n-nodes-openrouter-noreasoning`
23
+ 4. Accept the risks of installing a community node and confirm
24
+ 5. Reload the editor
25
+
26
+ The node will appear in the node picker as **OpenRouter Chat Model (No Reasoning)** under the **Chat Models (Recommended)** category.
27
+
28
+ ## Usage
29
+
30
+ ![Screenshot placeholder](docs/screenshot.png)
31
+
32
+ 1. Drop an **AI Agent** node onto the canvas
33
+ 2. On the agent's **Chat Model** input, attach an **OpenRouter Chat Model (No Reasoning)** node
34
+ 3. Select or create an `OpenRouter API` credential (the native n8n one — no custom credential is required)
35
+ 4. Set the model (default: `deepseek/deepseek-v4-flash`) and tune options if needed
36
+ 5. Run the workflow — `reasoning: { enabled: false }` is injected automatically
37
+
38
+ ## Compatible models
39
+
40
+ - `deepseek/deepseek-v4-flash`
41
+ - `deepseek/deepseek-v4-pro`
42
+ - `deepseek/deepseek-v3.2`
43
+
44
+ Other models (Anthropic Claude, Google Gemini, OpenAI GPT, etc.) accept the `reasoning` parameter as well, but **silently ignore it** when reasoning is not applicable. There is no risk of errors when pointing this node at non-DeepSeek models — it just behaves like a normal OpenRouter Chat Model.
45
+
46
+ ## Local development
47
+
48
+ ```bash
49
+ npm install
50
+ npm run build # one-shot build
51
+ npm run dev # watch mode
52
+ npm run lint
53
+ ```
54
+
55
+ To test against a local n8n instance, link the built package:
56
+
57
+ ```bash
58
+ npm link
59
+ cd ~/.n8n/custom # or wherever your n8n custom dir is
60
+ npm link n8n-nodes-openrouter-noreasoning
61
+ ```
62
+
63
+ ## Publishing
64
+
65
+ ```bash
66
+ npm login
67
+ npm publish --access public
68
+ ```
69
+
70
+ The `prepublishOnly` script runs the build and the strict lint config before publishing.
71
+
72
+ ## License
73
+
74
+ [MIT](LICENSE.md)
@@ -0,0 +1,5 @@
1
+ import { type INodeType, type INodeTypeDescription, type ISupplyDataFunctions, type SupplyData } from 'n8n-workflow';
2
+ export declare class LmChatOpenRouterNoReasoning implements INodeType {
3
+ description: INodeTypeDescription;
4
+ supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData>;
5
+ }
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LmChatOpenRouterNoReasoning = void 0;
4
+ const openai_1 = require("@langchain/openai");
5
+ const n8n_workflow_1 = require("n8n-workflow");
6
+ class LmChatOpenRouterNoReasoning {
7
+ constructor() {
8
+ this.description = {
9
+ displayName: 'OpenRouter Chat Model (No Reasoning)',
10
+ name: 'lmChatOpenRouterNoReasoning',
11
+ icon: 'file:openrouter.svg',
12
+ group: ['transform'],
13
+ version: 1,
14
+ description: 'OpenRouter Chat Model with reasoning forcefully disabled (fixes DeepSeek tool calling)',
15
+ defaults: {
16
+ name: 'OpenRouter Chat Model (No Reasoning)',
17
+ },
18
+ codex: {
19
+ categories: ['AI'],
20
+ subcategories: {
21
+ AI: ['Language Models', 'Root Nodes'],
22
+ 'Language Models': ['Chat Models (Recommended)'],
23
+ },
24
+ resources: {
25
+ primaryDocumentation: [
26
+ {
27
+ url: 'https://github.com/codialab/n8n-nodes-openrouter-noreasoning',
28
+ },
29
+ ],
30
+ },
31
+ },
32
+ inputs: [],
33
+ outputs: [
34
+ {
35
+ type: n8n_workflow_1.NodeConnectionTypes.AiLanguageModel,
36
+ displayName: 'Model',
37
+ },
38
+ ],
39
+ credentials: [
40
+ {
41
+ name: 'openRouterApi',
42
+ required: true,
43
+ },
44
+ ],
45
+ requestDefaults: {
46
+ ignoreHttpStatusErrors: true,
47
+ baseURL: 'https://openrouter.ai/api/v1',
48
+ },
49
+ properties: [
50
+ {
51
+ displayName: 'Model',
52
+ name: 'model',
53
+ type: 'string',
54
+ default: 'deepseek/deepseek-v4-flash',
55
+ description: 'The model to use. Reasoning is automatically disabled in every request to avoid tool-calling issues.',
56
+ },
57
+ {
58
+ displayName: 'Options',
59
+ name: 'options',
60
+ placeholder: 'Add Option',
61
+ description: 'Additional options to add',
62
+ type: 'collection',
63
+ default: {},
64
+ options: [
65
+ {
66
+ displayName: 'Maximum Number of Tokens',
67
+ name: 'maxTokens',
68
+ default: -1,
69
+ description: 'The maximum number of tokens to generate in the completion. Use -1 for unlimited.',
70
+ type: 'number',
71
+ typeOptions: {
72
+ maxValue: 32768,
73
+ minValue: -1,
74
+ numberPrecision: 0,
75
+ },
76
+ },
77
+ {
78
+ displayName: 'Sampling Temperature',
79
+ name: 'temperature',
80
+ default: 0.7,
81
+ typeOptions: { maxValue: 2, minValue: 0, numberPrecision: 1 },
82
+ description: 'Controls randomness: lower values are more deterministic, higher are more creative',
83
+ type: 'number',
84
+ },
85
+ {
86
+ displayName: 'Top P',
87
+ name: 'topP',
88
+ default: 1,
89
+ typeOptions: { maxValue: 1, minValue: 0, numberPrecision: 1 },
90
+ description: 'Nucleus sampling: consider tokens with at least this cumulative probability',
91
+ type: 'number',
92
+ },
93
+ {
94
+ displayName: 'Frequency Penalty',
95
+ name: 'frequencyPenalty',
96
+ default: 0,
97
+ typeOptions: { maxValue: 2, minValue: -2, numberPrecision: 1 },
98
+ description: 'Positive values penalize repeated tokens based on their frequency so far',
99
+ type: 'number',
100
+ },
101
+ {
102
+ displayName: 'Presence Penalty',
103
+ name: 'presencePenalty',
104
+ default: 0,
105
+ typeOptions: { maxValue: 2, minValue: -2, numberPrecision: 1 },
106
+ description: 'Positive values penalize tokens that have already appeared at all',
107
+ type: 'number',
108
+ },
109
+ {
110
+ displayName: 'Timeout',
111
+ name: 'timeout',
112
+ default: 60000,
113
+ description: 'Maximum amount of time a request is allowed to take in ms',
114
+ type: 'number',
115
+ },
116
+ {
117
+ displayName: 'Max Retries',
118
+ name: 'maxRetries',
119
+ default: 2,
120
+ description: 'Maximum number of retries to attempt when a request fails',
121
+ type: 'number',
122
+ },
123
+ ],
124
+ },
125
+ ],
126
+ };
127
+ }
128
+ async supplyData(itemIndex) {
129
+ const credentials = await this.getCredentials('openRouterApi');
130
+ const modelName = this.getNodeParameter('model', itemIndex);
131
+ const options = this.getNodeParameter('options', itemIndex, {});
132
+ const configuration = {
133
+ baseURL: 'https://openrouter.ai/api/v1',
134
+ defaultHeaders: {
135
+ 'HTTP-Referer': 'https://n8n.io',
136
+ 'X-Title': 'n8n',
137
+ },
138
+ };
139
+ const model = new openai_1.ChatOpenAI({
140
+ apiKey: credentials.apiKey,
141
+ modelName,
142
+ temperature: options.temperature,
143
+ maxTokens: options.maxTokens === -1 ? undefined : options.maxTokens,
144
+ topP: options.topP,
145
+ frequencyPenalty: options.frequencyPenalty,
146
+ presencePenalty: options.presencePenalty,
147
+ timeout: options.timeout,
148
+ maxRetries: options.maxRetries,
149
+ configuration,
150
+ modelKwargs: {
151
+ reasoning: { enabled: false },
152
+ },
153
+ });
154
+ return {
155
+ response: model,
156
+ };
157
+ }
158
+ }
159
+ exports.LmChatOpenRouterNoReasoning = LmChatOpenRouterNoReasoning;
160
+ //# sourceMappingURL=LmChatOpenRouterNoReasoning.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LmChatOpenRouterNoReasoning.node.js","sourceRoot":"","sources":["../../../nodes/LmChatOpenRouterNoReasoning/LmChatOpenRouterNoReasoning.node.ts"],"names":[],"mappings":";;;AAAA,8CAAmE;AACnE,+CAMsB;AAEtB,MAAa,2BAA2B;IAAxC;QACC,gBAAW,GAAyB;YACnC,WAAW,EAAE,sCAAsC;YACnD,IAAI,EAAE,6BAA6B;YACnC,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,CAAC,WAAW,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,WAAW,EAAE,wFAAwF;YACrG,QAAQ,EAAE;gBACT,IAAI,EAAE,sCAAsC;aAC5C;YACD,KAAK,EAAE;gBACN,UAAU,EAAE,CAAC,IAAI,CAAC;gBAClB,aAAa,EAAE;oBACd,EAAE,EAAE,CAAC,iBAAiB,EAAE,YAAY,CAAC;oBACrC,iBAAiB,EAAE,CAAC,2BAA2B,CAAC;iBAChD;gBACD,SAAS,EAAE;oBACV,oBAAoB,EAAE;wBACrB;4BACC,GAAG,EAAE,8DAA8D;yBACnE;qBACD;iBACD;aACD;YACD,MAAM,EAAE,EAAE;YACV,OAAO,EAAE;gBACR;oBACC,IAAI,EAAE,kCAAmB,CAAC,eAAe;oBACzC,WAAW,EAAE,OAAO;iBACpB;aACD;YACD,WAAW,EAAE;gBACZ;oBACC,IAAI,EAAE,eAAe;oBACrB,QAAQ,EAAE,IAAI;iBACd;aACD;YACD,eAAe,EAAE;gBAChB,sBAAsB,EAAE,IAAI;gBAC5B,OAAO,EAAE,8BAA8B;aACvC;YACD,UAAU,EAAE;gBACX;oBACC,WAAW,EAAE,OAAO;oBACpB,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,4BAA4B;oBACrC,WAAW,EACV,sGAAsG;iBACvG;gBACD;oBACC,WAAW,EAAE,SAAS;oBACtB,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,YAAY;oBACzB,WAAW,EAAE,2BAA2B;oBACxC,IAAI,EAAE,YAAY;oBAClB,OAAO,EAAE,EAAE;oBACX,OAAO,EAAE;wBACR;4BACC,WAAW,EAAE,0BAA0B;4BACvC,IAAI,EAAE,WAAW;4BACjB,OAAO,EAAE,CAAC,CAAC;4BACX,WAAW,EAAE,mFAAmF;4BAChG,IAAI,EAAE,QAAQ;4BACd,WAAW,EAAE;gCACZ,QAAQ,EAAE,KAAK;gCACf,QAAQ,EAAE,CAAC,CAAC;gCACZ,eAAe,EAAE,CAAC;6BAClB;yBACD;wBACD;4BACC,WAAW,EAAE,sBAAsB;4BACnC,IAAI,EAAE,aAAa;4BACnB,OAAO,EAAE,GAAG;4BACZ,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE;4BAC7D,WAAW,EAAE,oFAAoF;4BACjG,IAAI,EAAE,QAAQ;yBACd;wBACD;4BACC,WAAW,EAAE,OAAO;4BACpB,IAAI,EAAE,MAAM;4BACZ,OAAO,EAAE,CAAC;4BACV,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE;4BAC7D,WAAW,EAAE,6EAA6E;4BAC1F,IAAI,EAAE,QAAQ;yBACd;wBACD;4BACC,WAAW,EAAE,mBAAmB;4BAChC,IAAI,EAAE,kBAAkB;4BACxB,OAAO,EAAE,CAAC;4BACV,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE;4BAC9D,WAAW,EAAE,0EAA0E;4BACvF,IAAI,EAAE,QAAQ;yBACd;wBACD;4BACC,WAAW,EAAE,kBAAkB;4BAC/B,IAAI,EAAE,iBAAiB;4BACvB,OAAO,EAAE,CAAC;4BACV,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE;4BAC9D,WAAW,EAAE,mEAAmE;4BAChF,IAAI,EAAE,QAAQ;yBACd;wBACD;4BACC,WAAW,EAAE,SAAS;4BACtB,IAAI,EAAE,SAAS;4BACf,OAAO,EAAE,KAAK;4BACd,WAAW,EAAE,2DAA2D;4BACxE,IAAI,EAAE,QAAQ;yBACd;wBACD;4BACC,WAAW,EAAE,aAAa;4BAC1B,IAAI,EAAE,YAAY;4BAClB,OAAO,EAAE,CAAC;4BACV,WAAW,EAAE,2DAA2D;4BACxE,IAAI,EAAE,QAAQ;yBACd;qBACD;iBACD;aACD;SACD,CAAC;IA2CH,CAAC;IAzCA,KAAK,CAAC,UAAU,CAA6B,SAAiB;QAC7D,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAW,CAAC;QACtE,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,CAQ7D,CAAC;QAEF,MAAM,aAAa,GAAkB;YACpC,OAAO,EAAE,8BAA8B;YACvC,cAAc,EAAE;gBACf,cAAc,EAAE,gBAAgB;gBAChC,SAAS,EAAE,KAAK;aAChB;SACD,CAAC;QAEF,MAAM,KAAK,GAAG,IAAI,mBAAU,CAAC;YAC5B,MAAM,EAAE,WAAW,CAAC,MAAgB;YACpC,SAAS;YACT,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,SAAS,EAAE,OAAO,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS;YACnE,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;YAC1C,eAAe,EAAE,OAAO,CAAC,eAAe;YACxC,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,aAAa;YACb,WAAW,EAAE;gBACZ,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;aAC7B;SACD,CAAC,CAAC;QAEH,OAAO;YACN,QAAQ,EAAE,KAAK;SACf,CAAC;IACH,CAAC;CACD;AAnKD,kEAmKC"}
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
2
+ <circle cx="12" cy="12" r="11" fill="#2D2D2D"/>
3
+ <text x="12" y="12" fill="#FFFFFF" font-family="Helvetica, Arial, sans-serif" font-size="9" font-weight="700" text-anchor="middle" dominant-baseline="central">OR</text>
4
+ </svg>
package/index.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = {};
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "n8n-nodes-openrouter-noreasoning",
3
+ "version": "0.1.0",
4
+ "description": "OpenRouter Chat Model node for n8n with reasoning forcefully disabled. Fixes tool calling issues with DeepSeek V4/V3.2 in AI Agent workflows.",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "openrouter",
8
+ "deepseek",
9
+ "ai-agent",
10
+ "langchain"
11
+ ],
12
+ "license": "MIT",
13
+ "homepage": "https://github.com/codialab/n8n-nodes-openrouter-noreasoning",
14
+ "author": {
15
+ "name": "Codialab",
16
+ "email": "contacto@codialab.com"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/codialab/n8n-nodes-openrouter-noreasoning.git"
21
+ },
22
+ "engines": {
23
+ "node": ">=20.15"
24
+ },
25
+ "main": "index.js",
26
+ "scripts": {
27
+ "build": "npx rimraf dist && tsc && gulp build:icons",
28
+ "dev": "tsc --watch",
29
+ "format": "prettier nodes --write",
30
+ "lint": "eslint nodes package.json",
31
+ "lintfix": "eslint nodes package.json --fix",
32
+ "prepublishOnly": "npm run build && npm run lint -c .eslintrc.prepublish.js nodes package.json"
33
+ },
34
+ "files": [
35
+ "dist"
36
+ ],
37
+ "n8n": {
38
+ "n8nNodesApiVersion": 1,
39
+ "credentials": [],
40
+ "nodes": [
41
+ "dist/nodes/LmChatOpenRouterNoReasoning/LmChatOpenRouterNoReasoning.node.js"
42
+ ]
43
+ },
44
+ "devDependencies": {
45
+ "@langchain/core": "^0.3.30",
46
+ "@langchain/openai": "^0.3.16",
47
+ "@typescript-eslint/parser": "~7.15.0",
48
+ "eslint": "^8.57.0",
49
+ "eslint-plugin-n8n-nodes-base": "^1.16.3",
50
+ "gulp": "^5.0.0",
51
+ "n8n-workflow": "*",
52
+ "prettier": "^3.3.2",
53
+ "rimraf": "^5.0.5",
54
+ "typescript": "^5.5.3"
55
+ },
56
+ "peerDependencies": {
57
+ "n8n-workflow": "*"
58
+ }
59
+ }