@drx974/n8n-nodes-deepseek-fixed 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/README.md +68 -0
- package/dist/credentials/DeepSeekFixedApi.credentials.d.ts +7 -0
- package/dist/credentials/DeepSeekFixedApi.credentials.js +28 -0
- package/dist/nodes/LmChatDeepSeekFixed/ChatDeepSeekFixed.d.ts +56 -0
- package/dist/nodes/LmChatDeepSeekFixed/ChatDeepSeekFixed.js +162 -0
- package/dist/nodes/LmChatDeepSeekFixed/LmChatDeepSeekFixed.node.d.ts +5 -0
- package/dist/nodes/LmChatDeepSeekFixed/LmChatDeepSeekFixed.node.js +98 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# n8n-nodes-deepseek-fixed-romy
|
|
2
|
+
|
|
3
|
+
Nœud DeepSeek Chat Model "maison" pour l'AI Agent n8n. Corrige les deux bugs
|
|
4
|
+
documentés qui cassent le Tool Calling avec DeepSeek dans n8n :
|
|
5
|
+
|
|
6
|
+
1. **Rejet du schéma `strict`** : DeepSeek renvoie une erreur 400
|
|
7
|
+
("Required properties must match...") quand n8n envoie `strict: true`
|
|
8
|
+
dans la définition JSON Schema des tools. Ce nœud ne transmet jamais ce
|
|
9
|
+
flag, quel que soit ce que l'AI Agent essaie de passer.
|
|
10
|
+
|
|
11
|
+
2. **`reasoning_content` non renvoyé** : en Thinking Mode, DeepSeek exige que
|
|
12
|
+
le `reasoning_content` du tour précédent soit renvoyé tel quel dès que ce
|
|
13
|
+
tour contenait des tool_calls, sinon 400 ("The reasoning_content in the
|
|
14
|
+
thinking mode must be passed back to the API"). Ce nœud stocke ce champ
|
|
15
|
+
sur chaque message assistant et le réinjecte automatiquement au tour
|
|
16
|
+
suivant — Thinking Mode reste utilisable même avec des tools.
|
|
17
|
+
|
|
18
|
+
Par défaut, Thinking Mode est **désactivé** (le plus sûr avec Tool Calling) ;
|
|
19
|
+
vous pouvez l'activer (`high` / `max`) si vous voulez le raisonnement
|
|
20
|
+
chain-of-thought sur cet agent.
|
|
21
|
+
|
|
22
|
+
## Build
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install
|
|
26
|
+
npm run build
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Déploiement recommandé (le plus sûr, évite l'incident déjà rencontré)
|
|
30
|
+
|
|
31
|
+
Ne PAS faire `npm install` à la main dans le container n8n (ça duplique les
|
|
32
|
+
dépendances et peut casser le chargement des nodes, comme déjà vécu).
|
|
33
|
+
|
|
34
|
+
**Méthode recommandée : publier sur npm puis installer via l'UI n8n**
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm login # une fois, avec un compte npm (peut être le vôtre)
|
|
38
|
+
npm publish --access public
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Puis, dans n8n : **Settings → Community Nodes → Install**, coller le nom du
|
|
42
|
+
package `n8n-nodes-deepseek-fixed-romy`, cocher la case de risque, Install,
|
|
43
|
+
puis **redémarrer le container n8n** (obligatoire pour que le node se charge,
|
|
44
|
+
surtout en mode queue).
|
|
45
|
+
|
|
46
|
+
Si vous préférez ne pas publier publiquement, publiez sous un nom scope privé
|
|
47
|
+
(`@votre-compte/n8n-nodes-deepseek-fixed`) avec un compte npm payant "private
|
|
48
|
+
package", ou utilisez un registre npm privé si vous en avez un (Verdaccio,
|
|
49
|
+
GitHub Packages, etc.) — le flux d'installation via l'UI reste identique.
|
|
50
|
+
|
|
51
|
+
## Utilisation dans l'AI Agent
|
|
52
|
+
|
|
53
|
+
1. Ajouter le nœud **DeepSeek Chat Model (Fixed)**
|
|
54
|
+
2. Credential : coller votre clé API DeepSeek (`DeepSeek Fixed API`)
|
|
55
|
+
3. Le connecter à l'entrée "Chat Model" de l'AI Agent
|
|
56
|
+
4. Laisser **Thinking Mode = Disabled** pour du Tool Calling simple, ou
|
|
57
|
+
passer à `high`/`max` si vous voulez le raisonnement — les deux
|
|
58
|
+
fonctionnent avec les tools.
|
|
59
|
+
5. Connecter vos tools comme d'habitude.
|
|
60
|
+
|
|
61
|
+
## Limites connues
|
|
62
|
+
|
|
63
|
+
- Pas de support du streaming token-par-token (`_generate` uniquement,
|
|
64
|
+
pas de `_streamResponseChunks`) — suffisant pour l'usage AI Agent classique,
|
|
65
|
+
mais à garder en tête si vous branchez ça sur un chat en streaming.
|
|
66
|
+
- Testé par compilation TypeScript stricte contre `@langchain/core@1.2.2` et
|
|
67
|
+
`n8n-workflow@2.16.0` (versions au 10/07/2026) — à revalider si n8n monte
|
|
68
|
+
une version majeure différente de LangChain en interne.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeepSeekFixedApi = void 0;
|
|
4
|
+
class DeepSeekFixedApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'deepSeekFixedApi';
|
|
7
|
+
this.displayName = 'DeepSeek Fixed API';
|
|
8
|
+
this.documentationUrl = 'https://api-docs.deepseek.com/';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'API Key',
|
|
12
|
+
name: 'apiKey',
|
|
13
|
+
type: 'string',
|
|
14
|
+
typeOptions: { password: true },
|
|
15
|
+
default: '',
|
|
16
|
+
required: true,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
displayName: 'Base URL',
|
|
20
|
+
name: 'baseUrl',
|
|
21
|
+
type: 'string',
|
|
22
|
+
default: 'https://api.deepseek.com',
|
|
23
|
+
description: 'Override if you proxy DeepSeek through your own endpoint',
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.DeepSeekFixedApi = DeepSeekFixedApi;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
2
|
+
import type { BaseChatModelParams, BindToolsInput } from '@langchain/core/language_models/chat_models';
|
|
3
|
+
import type { BaseMessage } from '@langchain/core/messages';
|
|
4
|
+
import type { ChatResult } from '@langchain/core/outputs';
|
|
5
|
+
import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
|
|
6
|
+
export type ThinkingMode = 'disabled' | 'high' | 'max';
|
|
7
|
+
export interface ChatDeepSeekFixedParams extends BaseChatModelParams {
|
|
8
|
+
apiKey: string;
|
|
9
|
+
baseURL?: string;
|
|
10
|
+
model: string;
|
|
11
|
+
temperature?: number;
|
|
12
|
+
maxTokens?: number;
|
|
13
|
+
thinkingMode?: ThinkingMode;
|
|
14
|
+
timeout?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Minimal, self-contained LangChain ChatModel for DeepSeek that fixes the two
|
|
18
|
+
* documented n8n / DeepSeek incompatibilities when used behind the AI Agent node:
|
|
19
|
+
*
|
|
20
|
+
* 1. DeepSeek rejects tool definitions carrying `"strict": true` in the JSON
|
|
21
|
+
* schema (400 "Required properties must match..."). We never emit `strict`.
|
|
22
|
+
*
|
|
23
|
+
* 2. In Thinking Mode, DeepSeek requires the `reasoning_content` of a prior
|
|
24
|
+
* assistant turn to be echoed back once that turn included tool_calls,
|
|
25
|
+
* otherwise it 400s with "The reasoning_content in the thinking mode must
|
|
26
|
+
* be passed back to the API." We stash it on additional_kwargs and replay
|
|
27
|
+
* it automatically on the next turn.
|
|
28
|
+
*
|
|
29
|
+
* Thinking Mode defaults to "disabled", which sidesteps rule 2 entirely and is
|
|
30
|
+
* the recommended setting whenever the model is wired into an AI Agent with
|
|
31
|
+
* tools. Set it to "high"/"max" if you need chain-of-thought and are fine with
|
|
32
|
+
* the extra latency/token cost — rule 2's handling keeps tool calls working
|
|
33
|
+
* either way.
|
|
34
|
+
*/
|
|
35
|
+
export declare class ChatDeepSeekFixed extends BaseChatModel {
|
|
36
|
+
apiKey: string;
|
|
37
|
+
baseURL: string;
|
|
38
|
+
modelName: string;
|
|
39
|
+
temperature?: number;
|
|
40
|
+
maxTokens?: number;
|
|
41
|
+
thinkingMode: ThinkingMode;
|
|
42
|
+
timeout: number;
|
|
43
|
+
private client;
|
|
44
|
+
private boundTools;
|
|
45
|
+
constructor(fields: ChatDeepSeekFixedParams);
|
|
46
|
+
_llmType(): string;
|
|
47
|
+
/**
|
|
48
|
+
* Fix #1: convert tools without ever passing a `strict` flag through, no
|
|
49
|
+
* matter what the caller (n8n's AI Agent) asks for. `convertToOpenAITool`
|
|
50
|
+
* only sets `strict` when explicitly told to, so simply not forwarding it
|
|
51
|
+
* here is enough to keep it out of the wire payload.
|
|
52
|
+
*/
|
|
53
|
+
bindTools(tools: BindToolsInput[], _kwargs?: Record<string, unknown>): ReturnType<NonNullable<BaseChatModel['bindTools']>>;
|
|
54
|
+
private toOpenAIMessages;
|
|
55
|
+
_generate(messages: BaseMessage[], _options: this['ParsedCallOptions'], _runManager?: CallbackManagerForLLMRun): Promise<ChatResult>;
|
|
56
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ChatDeepSeekFixed = void 0;
|
|
7
|
+
const chat_models_1 = require("@langchain/core/language_models/chat_models");
|
|
8
|
+
const messages_1 = require("@langchain/core/messages");
|
|
9
|
+
const function_calling_1 = require("@langchain/core/utils/function_calling");
|
|
10
|
+
const openai_1 = __importDefault(require("openai"));
|
|
11
|
+
/**
|
|
12
|
+
* Minimal, self-contained LangChain ChatModel for DeepSeek that fixes the two
|
|
13
|
+
* documented n8n / DeepSeek incompatibilities when used behind the AI Agent node:
|
|
14
|
+
*
|
|
15
|
+
* 1. DeepSeek rejects tool definitions carrying `"strict": true` in the JSON
|
|
16
|
+
* schema (400 "Required properties must match..."). We never emit `strict`.
|
|
17
|
+
*
|
|
18
|
+
* 2. In Thinking Mode, DeepSeek requires the `reasoning_content` of a prior
|
|
19
|
+
* assistant turn to be echoed back once that turn included tool_calls,
|
|
20
|
+
* otherwise it 400s with "The reasoning_content in the thinking mode must
|
|
21
|
+
* be passed back to the API." We stash it on additional_kwargs and replay
|
|
22
|
+
* it automatically on the next turn.
|
|
23
|
+
*
|
|
24
|
+
* Thinking Mode defaults to "disabled", which sidesteps rule 2 entirely and is
|
|
25
|
+
* the recommended setting whenever the model is wired into an AI Agent with
|
|
26
|
+
* tools. Set it to "high"/"max" if you need chain-of-thought and are fine with
|
|
27
|
+
* the extra latency/token cost — rule 2's handling keeps tool calls working
|
|
28
|
+
* either way.
|
|
29
|
+
*/
|
|
30
|
+
class ChatDeepSeekFixed extends chat_models_1.BaseChatModel {
|
|
31
|
+
constructor(fields) {
|
|
32
|
+
super(fields);
|
|
33
|
+
this.boundTools = [];
|
|
34
|
+
this.apiKey = fields.apiKey;
|
|
35
|
+
this.baseURL = fields.baseURL ?? 'https://api.deepseek.com';
|
|
36
|
+
this.modelName = fields.model;
|
|
37
|
+
this.temperature = fields.temperature;
|
|
38
|
+
this.maxTokens = fields.maxTokens;
|
|
39
|
+
this.thinkingMode = fields.thinkingMode ?? 'disabled';
|
|
40
|
+
this.timeout = fields.timeout ?? 60000;
|
|
41
|
+
this.client = new openai_1.default({
|
|
42
|
+
apiKey: this.apiKey,
|
|
43
|
+
baseURL: this.baseURL,
|
|
44
|
+
timeout: this.timeout,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
_llmType() {
|
|
48
|
+
return 'deepseek-fixed';
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Fix #1: convert tools without ever passing a `strict` flag through, no
|
|
52
|
+
* matter what the caller (n8n's AI Agent) asks for. `convertToOpenAITool`
|
|
53
|
+
* only sets `strict` when explicitly told to, so simply not forwarding it
|
|
54
|
+
* here is enough to keep it out of the wire payload.
|
|
55
|
+
*/
|
|
56
|
+
bindTools(tools, _kwargs) {
|
|
57
|
+
this.boundTools = tools.map((tool) => (0, function_calling_1.convertToOpenAITool)(tool));
|
|
58
|
+
// n8n's AI Agent supplies a fresh model instance per execution via
|
|
59
|
+
// supplyData(), so mutating in place and returning `this` is safe here
|
|
60
|
+
// and avoids depending on Runnable.bind(), which this LangChain version
|
|
61
|
+
// no longer exposes on BaseChatModel.
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
toOpenAIMessages(messages) {
|
|
65
|
+
return messages.map((message) => {
|
|
66
|
+
const type = message._getType();
|
|
67
|
+
if (type === 'human') {
|
|
68
|
+
return { role: 'user', content: message.content };
|
|
69
|
+
}
|
|
70
|
+
if (type === 'system') {
|
|
71
|
+
return { role: 'system', content: message.content };
|
|
72
|
+
}
|
|
73
|
+
if (type === 'tool') {
|
|
74
|
+
const toolMessage = message;
|
|
75
|
+
return {
|
|
76
|
+
role: 'tool',
|
|
77
|
+
tool_call_id: toolMessage.tool_call_id,
|
|
78
|
+
content: toolMessage.content,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// assistant / ai turn
|
|
82
|
+
const aiMessage = message;
|
|
83
|
+
const toolCalls = aiMessage.tool_calls && aiMessage.tool_calls.length > 0
|
|
84
|
+
? aiMessage.tool_calls.map((toolCall) => ({
|
|
85
|
+
id: toolCall.id ?? '',
|
|
86
|
+
type: 'function',
|
|
87
|
+
function: {
|
|
88
|
+
name: toolCall.name,
|
|
89
|
+
arguments: JSON.stringify(toolCall.args ?? {}),
|
|
90
|
+
},
|
|
91
|
+
}))
|
|
92
|
+
: undefined;
|
|
93
|
+
// Fix #2: replay reasoning_content we stashed from DeepSeek's previous
|
|
94
|
+
// response, only relevant when Thinking Mode is active.
|
|
95
|
+
const storedReasoning = aiMessage.additional_kwargs?.reasoning_content;
|
|
96
|
+
const extra = this.thinkingMode !== 'disabled' && storedReasoning
|
|
97
|
+
? { reasoning_content: storedReasoning }
|
|
98
|
+
: {};
|
|
99
|
+
return {
|
|
100
|
+
role: 'assistant',
|
|
101
|
+
content: aiMessage.content ?? '',
|
|
102
|
+
...(toolCalls ? { tool_calls: toolCalls } : {}),
|
|
103
|
+
...extra,
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async _generate(messages, _options, _runManager) {
|
|
108
|
+
const openAIMessages = this.toOpenAIMessages(messages);
|
|
109
|
+
const body = {
|
|
110
|
+
model: this.modelName,
|
|
111
|
+
messages: openAIMessages,
|
|
112
|
+
max_tokens: this.maxTokens,
|
|
113
|
+
};
|
|
114
|
+
// DeepSeek ignores temperature/top_p/penalties in Thinking Mode (silently,
|
|
115
|
+
// no error) — omit it in that case to avoid misleading configuration.
|
|
116
|
+
if (this.thinkingMode === 'disabled') {
|
|
117
|
+
body.temperature = this.temperature;
|
|
118
|
+
}
|
|
119
|
+
if (this.boundTools.length > 0) {
|
|
120
|
+
body.tools = this.boundTools;
|
|
121
|
+
}
|
|
122
|
+
if (this.thinkingMode !== 'disabled') {
|
|
123
|
+
body.extra_body = {
|
|
124
|
+
thinking: { type: 'enabled' },
|
|
125
|
+
...(this.thinkingMode === 'max' ? { reasoning_effort: 'max' } : {}),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const completion = await this.client.chat.completions.create(body);
|
|
129
|
+
const choice = completion.choices[0];
|
|
130
|
+
const rawMessage = choice.message;
|
|
131
|
+
const toolCalls = (rawMessage.tool_calls ?? [])
|
|
132
|
+
.filter((toolCall) => 'function' in toolCall)
|
|
133
|
+
.map((toolCall) => {
|
|
134
|
+
let args = {};
|
|
135
|
+
try {
|
|
136
|
+
args = JSON.parse(toolCall.function.arguments || '{}');
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
args = {};
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
id: toolCall.id,
|
|
143
|
+
name: toolCall.function.name,
|
|
144
|
+
args,
|
|
145
|
+
type: 'tool_call',
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
const aiMessage = new messages_1.AIMessage({
|
|
149
|
+
content: rawMessage.content ?? '',
|
|
150
|
+
tool_calls: toolCalls,
|
|
151
|
+
additional_kwargs: rawMessage.reasoning_content
|
|
152
|
+
? { reasoning_content: rawMessage.reasoning_content }
|
|
153
|
+
: {},
|
|
154
|
+
});
|
|
155
|
+
const generation = {
|
|
156
|
+
text: rawMessage.content ?? '',
|
|
157
|
+
message: aiMessage,
|
|
158
|
+
};
|
|
159
|
+
return { generations: [generation] };
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.ChatDeepSeekFixed = ChatDeepSeekFixed;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { INodeType, INodeTypeDescription, ISupplyDataFunctions, SupplyData } from 'n8n-workflow';
|
|
2
|
+
export declare class LmChatDeepSeekFixed implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LmChatDeepSeekFixed = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const ChatDeepSeekFixed_1 = require("./ChatDeepSeekFixed");
|
|
6
|
+
class LmChatDeepSeekFixed {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.description = {
|
|
9
|
+
displayName: 'DeepSeek Chat Model (Fixed)',
|
|
10
|
+
name: 'lmChatDeepSeekFixed',
|
|
11
|
+
icon: 'fa:comment',
|
|
12
|
+
iconColor: 'black',
|
|
13
|
+
group: ['transform'],
|
|
14
|
+
version: 1,
|
|
15
|
+
description: 'DeepSeek chat model for the AI Agent — fixes the strict tool-schema rejection and the reasoning_content passback error',
|
|
16
|
+
defaults: {
|
|
17
|
+
name: 'DeepSeek Chat Model (Fixed)',
|
|
18
|
+
},
|
|
19
|
+
codex: {
|
|
20
|
+
categories: ['AI'],
|
|
21
|
+
subcategories: {
|
|
22
|
+
AI: ['Language Models'],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
|
26
|
+
inputs: [],
|
|
27
|
+
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
|
28
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.AiLanguageModel],
|
|
29
|
+
outputNames: ['Model'],
|
|
30
|
+
credentials: [
|
|
31
|
+
{
|
|
32
|
+
name: 'deepSeekFixedApi',
|
|
33
|
+
required: true,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
properties: [
|
|
37
|
+
{
|
|
38
|
+
displayName: 'Model',
|
|
39
|
+
name: 'model',
|
|
40
|
+
type: 'string',
|
|
41
|
+
default: 'deepseek-v4-flash',
|
|
42
|
+
description: 'e.g. deepseek-v4-flash, deepseek-v4-pro',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
displayName: 'Thinking Mode',
|
|
46
|
+
name: 'thinkingMode',
|
|
47
|
+
type: 'options',
|
|
48
|
+
options: [
|
|
49
|
+
{ name: 'Disabled (Recommended With Tool Calling)', value: 'disabled' },
|
|
50
|
+
{ name: 'Enabled — High Effort', value: 'high' },
|
|
51
|
+
{ name: 'Enabled — Max Effort', value: 'max' },
|
|
52
|
+
],
|
|
53
|
+
default: 'disabled',
|
|
54
|
+
description: 'When enabled, reasoning_content is tracked and replayed automatically so tool calling keeps working',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
displayName: 'Temperature',
|
|
58
|
+
name: 'temperature',
|
|
59
|
+
type: 'number',
|
|
60
|
+
default: 0.7,
|
|
61
|
+
typeOptions: { minValue: 0, maxValue: 2, numberPrecision: 2 },
|
|
62
|
+
description: 'Ignored by DeepSeek whenever Thinking Mode is enabled',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
displayName: 'Max Tokens',
|
|
66
|
+
name: 'maxTokens',
|
|
67
|
+
type: 'number',
|
|
68
|
+
default: 2048,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
displayName: 'Timeout (ms)',
|
|
72
|
+
name: 'timeout',
|
|
73
|
+
type: 'number',
|
|
74
|
+
default: 60000,
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
async supplyData(itemIndex) {
|
|
80
|
+
const credentials = await this.getCredentials('deepSeekFixedApi');
|
|
81
|
+
const model = this.getNodeParameter('model', itemIndex);
|
|
82
|
+
const thinkingMode = this.getNodeParameter('thinkingMode', itemIndex);
|
|
83
|
+
const temperature = this.getNodeParameter('temperature', itemIndex);
|
|
84
|
+
const maxTokens = this.getNodeParameter('maxTokens', itemIndex);
|
|
85
|
+
const timeout = this.getNodeParameter('timeout', itemIndex);
|
|
86
|
+
const chatModel = new ChatDeepSeekFixed_1.ChatDeepSeekFixed({
|
|
87
|
+
apiKey: credentials.apiKey,
|
|
88
|
+
baseURL: credentials.baseUrl || 'https://api.deepseek.com',
|
|
89
|
+
model,
|
|
90
|
+
thinkingMode,
|
|
91
|
+
temperature,
|
|
92
|
+
maxTokens,
|
|
93
|
+
timeout,
|
|
94
|
+
});
|
|
95
|
+
return { response: chatModel };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.LmChatDeepSeekFixed = LmChatDeepSeekFixed;
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@drx974/n8n-nodes-deepseek-fixed",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "DeepSeek Chat Model for n8n AI Agent — fixes strict tool-schema rejection and reasoning_content passback",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package"
|
|
7
|
+
],
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public"
|
|
11
|
+
},
|
|
12
|
+
"main": "dist/nodes/LmChatDeepSeekFixed/LmChatDeepSeekFixed.node.js",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"n8n": {
|
|
17
|
+
"n8nNodesApiVersion": 1,
|
|
18
|
+
"credentials": [
|
|
19
|
+
"dist/credentials/DeepSeekFixedApi.credentials.js"
|
|
20
|
+
],
|
|
21
|
+
"nodes": [
|
|
22
|
+
"dist/nodes/LmChatDeepSeekFixed/LmChatDeepSeekFixed.node.js"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@langchain/core": "*"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"openai": "^6.46.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@langchain/core": "^1.2.2",
|
|
36
|
+
"@types/node": "^24.0.0",
|
|
37
|
+
"n8n-workflow": "^2.16.0",
|
|
38
|
+
"typescript": "^5.9.3"
|
|
39
|
+
}
|
|
40
|
+
}
|