n8n-nodes-berget-mk 0.1.0 → 0.2.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 ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Micke Kring
4
+ Copyright (c) Berget AI (original author)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md CHANGED
@@ -1,8 +1,19 @@
1
1
  # n8n-nodes-berget-mk
2
2
 
3
- n8n community nodes for [Berget AI](https://berget.ai). Fork of the upstream `@bergetai/n8n-nodes-all` maintained by Micke Kring, packaged as a single installable module.
3
+ n8n community nodes for [Berget AI](https://berget.ai), packaged as a single installable module. Maintained by Micke Kring.
4
4
 
5
- Includes six nodes: **Chat**, **Agent** (with tool calling), **Embeddings**, **OCR**, **Speech-to-Text**, and **Rerank**.
5
+ Includes:
6
+
7
+ - **Berget AI Chat** — one-shot chat completions (action node)
8
+ - **Berget AI Chat Model** — sub-node that plugs into n8n's built-in **AI Agent**, **Basic LLM Chain**, and other LangChain-based nodes. Exposes `reasoning_effort` and the full standard LLM parameter set.
9
+ - **Berget AI Embeddings** — create text embeddings
10
+ - **Berget AI OCR** — document text extraction (PDF, DOCX, images)
11
+ - **Berget AI Speech-to-Text** — audio transcription (KB-Whisper for Swedish)
12
+ - **Berget AI Rerank** — document reranking
13
+
14
+ > ⚠️ **Experimental — actively developed.** This package is pre-1.0 and the shape of individual nodes may change between minor releases. Pin a specific version in production workflows until `1.0.0`.
15
+ >
16
+ > **Breaking change in `0.2.0`:** the home-built `Berget AI Agent` node was removed and replaced with a `Berget AI Chat Model` sub-node that plugs into n8n's built-in **AI Agent**. See [CHANGELOG.md](CHANGELOG.md) for migration notes.
6
17
 
7
18
  ## Install
8
19
 
@@ -14,10 +25,18 @@ n8n-nodes-berget-mk
14
25
 
15
26
  Then add a **Berget AI API** credential with your API key from [berget.ai](https://berget.ai).
16
27
 
17
- ## Compatibility
28
+ ## Using Berget with n8n's AI Agent
29
+
30
+ 1. Add n8n's built-in **AI Agent** node to your workflow.
31
+ 2. Add a **Berget AI Chat Model** node and drag it onto the canvas below the Agent.
32
+ 3. Connect it to the Agent's **Chat Model** socket.
33
+ 4. Select a Berget AI chat model (the list loads live from the API).
34
+ 5. Optionally add Memory and Tool sub-nodes — they work as normal with Berget as the underlying LLM.
35
+
36
+ ## Changelog
18
37
 
19
- Uses the same internal node type names as the upstream package (`bergetAiChat`, `bergetAiAgent`, etc.), so workflows built against `@bergetai/n8n-nodes-all` continue to work after switching.
38
+ See [CHANGELOG.md](CHANGELOG.md) for what's changed between releases.
20
39
 
21
40
  ## License
22
41
 
23
- MIT
42
+ MIT. Originally based on the open-source Berget AI n8n nodes.
@@ -1,8 +1,3 @@
1
- <svg width="463" height="419" viewBox="0 0 463 419" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <defs>
3
- <filter id="invertFilter">
4
- <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
5
- </filter>
6
- </defs>
7
- <path d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z" fill="black" filter="url(#invertFilter)"/>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 463 419">
2
+ <path fill="#10b981" d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z"/>
8
3
  </svg>
@@ -0,0 +1,10 @@
1
+ import { type ILoadOptionsFunctions, type INodePropertyOptions, type INodeType, type INodeTypeDescription, type ISupplyDataFunctions, type SupplyData } from 'n8n-workflow';
2
+ export declare class BergetAiChatModel implements INodeType {
3
+ description: INodeTypeDescription;
4
+ methods: {
5
+ loadOptions: {
6
+ getModels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
7
+ };
8
+ };
9
+ supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData>;
10
+ }
@@ -0,0 +1,198 @@
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.BergetAiChatModel = void 0;
7
+ const openai_1 = require("@langchain/openai");
8
+ const axios_1 = __importDefault(require("axios"));
9
+ const n8n_workflow_1 = require("n8n-workflow");
10
+ const BERGET_API_BASE_URL = 'https://api.berget.ai/v1';
11
+ class BergetAiChatModel {
12
+ constructor() {
13
+ this.description = {
14
+ displayName: 'Berget AI Chat Model',
15
+ name: 'bergetAiChatModel',
16
+ icon: 'file:bergetai.svg',
17
+ group: ['transform'],
18
+ version: 1,
19
+ description: "Berget AI chat model. Plug into n8n's built-in AI Agent, Basic LLM Chain, or any LangChain-based node to use Berget AI as the underlying LLM.",
20
+ defaults: { name: 'Berget AI Chat Model' },
21
+ codex: {
22
+ categories: ['AI'],
23
+ subcategories: {
24
+ AI: ['Language Models', 'Root Nodes'],
25
+ 'Language Models': ['Chat Models (Recommended)'],
26
+ },
27
+ },
28
+ credentials: [{ name: 'bergetAiApi', required: true }],
29
+ inputs: [],
30
+ outputs: [n8n_workflow_1.NodeConnectionTypes.AiLanguageModel],
31
+ outputNames: ['Model'],
32
+ properties: [
33
+ {
34
+ displayName: 'This node must be connected to an AI Agent, Chain, or another LangChain-based parent node. It cannot be executed on its own.',
35
+ name: 'notice',
36
+ type: 'notice',
37
+ default: '',
38
+ },
39
+ {
40
+ displayName: 'Model',
41
+ name: 'model',
42
+ type: 'options',
43
+ typeOptions: { loadOptionsMethod: 'getModels' },
44
+ default: '',
45
+ required: true,
46
+ description: 'The Berget AI chat model to use. The list is fetched live from the Berget AI API.',
47
+ },
48
+ {
49
+ displayName: 'Options',
50
+ name: 'options',
51
+ type: 'collection',
52
+ placeholder: 'Add Option',
53
+ default: {},
54
+ options: [
55
+ {
56
+ displayName: 'Frequency Penalty',
57
+ name: 'frequencyPenalty',
58
+ type: 'number',
59
+ typeOptions: { minValue: -2, maxValue: 2, numberPrecision: 2 },
60
+ default: 0,
61
+ description: "Positive values penalize new tokens based on their frequency in the text so far, decreasing the model's likelihood to repeat itself",
62
+ },
63
+ {
64
+ displayName: 'Maximum Number of Tokens',
65
+ name: 'maxTokens',
66
+ type: 'number',
67
+ typeOptions: { minValue: 1 },
68
+ default: 1024,
69
+ description: 'The maximum number of tokens to generate in the completion. Leave blank to let the model decide.',
70
+ },
71
+ {
72
+ displayName: 'Presence Penalty',
73
+ name: 'presencePenalty',
74
+ type: 'number',
75
+ typeOptions: { minValue: -2, maxValue: 2, numberPrecision: 2 },
76
+ default: 0,
77
+ description: "Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics",
78
+ },
79
+ {
80
+ displayName: 'Reasoning Effort',
81
+ name: 'reasoningEffort',
82
+ type: 'options',
83
+ default: 'medium',
84
+ description: 'Controls how much thinking a reasoning-capable model performs. Only applies to models that support chain-of-thought reasoning (GPT-OSS, DeepSeek R1, etc.). Ignored by non-reasoning models.',
85
+ options: [
86
+ {
87
+ name: 'Low',
88
+ value: 'low',
89
+ description: 'Favor speed and use fewer reasoning tokens',
90
+ },
91
+ {
92
+ name: 'Medium',
93
+ value: 'medium',
94
+ description: 'Balance speed and accuracy',
95
+ },
96
+ {
97
+ name: 'High',
98
+ value: 'high',
99
+ description: 'Favor accuracy with more reasoning tokens',
100
+ },
101
+ ],
102
+ },
103
+ {
104
+ displayName: 'Response Format',
105
+ name: 'responseFormat',
106
+ type: 'options',
107
+ default: 'text',
108
+ options: [
109
+ { name: 'Text', value: 'text' },
110
+ { name: 'JSON Object', value: 'json_object' },
111
+ ],
112
+ description: 'Force the model to return a specific response format. Use JSON Object when you want parseable JSON output.',
113
+ },
114
+ {
115
+ displayName: 'Sampling Temperature',
116
+ name: 'temperature',
117
+ type: 'number',
118
+ typeOptions: { minValue: 0, maxValue: 2, numberPrecision: 2 },
119
+ default: 0.7,
120
+ description: 'Controls randomness. Lower values are more deterministic, higher values more creative.',
121
+ },
122
+ {
123
+ displayName: 'Timeout (Ms)',
124
+ name: 'timeout',
125
+ type: 'number',
126
+ typeOptions: { minValue: 1 },
127
+ default: 60000,
128
+ description: 'Maximum time in milliseconds to wait for an API response',
129
+ },
130
+ {
131
+ displayName: 'Top P',
132
+ name: 'topP',
133
+ type: 'number',
134
+ typeOptions: { minValue: 0, maxValue: 1, numberPrecision: 2 },
135
+ default: 1,
136
+ description: 'Nucleus sampling cutoff. Alternative to temperature.',
137
+ },
138
+ ],
139
+ },
140
+ ],
141
+ };
142
+ this.methods = {
143
+ loadOptions: {
144
+ async getModels() {
145
+ var _a, _b;
146
+ const credentials = await this.getCredentials('bergetAiApi');
147
+ const response = await axios_1.default.get(`${BERGET_API_BASE_URL}/models`, {
148
+ headers: {
149
+ Authorization: `Bearer ${credentials.apiKey}`,
150
+ 'Content-Type': 'application/json',
151
+ },
152
+ });
153
+ const models = (_b = (_a = response.data) === null || _a === void 0 ? void 0 : _a.data) !== null && _b !== void 0 ? _b : [];
154
+ return models
155
+ .filter((m) => m.model_type === 'text')
156
+ .map((m) => {
157
+ var _a, _b, _c;
158
+ return ({
159
+ name: (_a = m.name) !== null && _a !== void 0 ? _a : m.id,
160
+ value: m.id,
161
+ description: m.owned_by ? `${(_b = m.name) !== null && _b !== void 0 ? _b : m.id} (${m.owned_by})` : ((_c = m.name) !== null && _c !== void 0 ? _c : m.id),
162
+ });
163
+ })
164
+ .sort((a, b) => a.name.localeCompare(b.name));
165
+ },
166
+ },
167
+ };
168
+ }
169
+ async supplyData(itemIndex) {
170
+ var _a, _b, _c, _d, _e;
171
+ const credentials = await this.getCredentials('bergetAiApi');
172
+ const modelName = this.getNodeParameter('model', itemIndex);
173
+ const options = this.getNodeParameter('options', itemIndex, {});
174
+ const modelKwargs = {};
175
+ if (options.reasoningEffort) {
176
+ modelKwargs.reasoning_effort = options.reasoningEffort;
177
+ }
178
+ if (options.responseFormat && options.responseFormat !== 'text') {
179
+ modelKwargs.response_format = { type: options.responseFormat };
180
+ }
181
+ const model = new openai_1.ChatOpenAI({
182
+ apiKey: credentials.apiKey,
183
+ model: modelName,
184
+ configuration: {
185
+ baseURL: BERGET_API_BASE_URL,
186
+ },
187
+ temperature: (_a = options.temperature) !== null && _a !== void 0 ? _a : 0.7,
188
+ topP: (_b = options.topP) !== null && _b !== void 0 ? _b : 1,
189
+ maxTokens: options.maxTokens,
190
+ frequencyPenalty: (_c = options.frequencyPenalty) !== null && _c !== void 0 ? _c : 0,
191
+ presencePenalty: (_d = options.presencePenalty) !== null && _d !== void 0 ? _d : 0,
192
+ timeout: (_e = options.timeout) !== null && _e !== void 0 ? _e : 60000,
193
+ modelKwargs: Object.keys(modelKwargs).length > 0 ? modelKwargs : undefined,
194
+ });
195
+ return { response: model };
196
+ }
197
+ }
198
+ exports.BergetAiChatModel = BergetAiChatModel;
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 463 419">
2
+ <path fill="#10b981" d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z"/>
3
+ </svg>
@@ -1,8 +1,3 @@
1
- <svg width="463" height="419" viewBox="0 0 463 419" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <defs>
3
- <filter id="invertFilter">
4
- <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
5
- </filter>
6
- </defs>
7
- <path d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z" fill="black" filter="url(#invertFilter)"/>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 463 419">
2
+ <path fill="#10b981" d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z"/>
8
3
  </svg>
@@ -1,8 +1,3 @@
1
- <svg width="463" height="419" viewBox="0 0 463 419" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <defs>
3
- <filter id="invertFilter">
4
- <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
5
- </filter>
6
- </defs>
7
- <path d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z" fill="black" filter="url(#invertFilter)"/>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 463 419">
2
+ <path fill="#10b981" d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z"/>
8
3
  </svg>
@@ -1,8 +1,3 @@
1
- <svg width="463" height="419" viewBox="0 0 463 419" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <defs>
3
- <filter id="invertFilter">
4
- <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
5
- </filter>
6
- </defs>
7
- <path d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z" fill="black" filter="url(#invertFilter)"/>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 463 419">
2
+ <path fill="#10b981" d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z"/>
8
3
  </svg>
@@ -1,8 +1,3 @@
1
- <svg width="463" height="419" viewBox="0 0 463 419" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <defs>
3
- <filter id="invertFilter">
4
- <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
5
- </filter>
6
- </defs>
7
- <path d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z" fill="black" filter="url(#invertFilter)"/>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 463 419">
2
+ <path fill="#10b981" d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z"/>
8
3
  </svg>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "n8n-nodes-berget-mk",
3
- "version": "0.1.0",
4
- "description": "n8n community nodes for Berget AI — chat, agent, embeddings, OCR, speech, and rerank. Fork maintained by Micke Kring.",
3
+ "version": "0.2.0",
4
+ "description": "n8n community nodes for Berget AI — chat, embeddings, OCR, speech, rerank, and a Chat Model sub-node that plugs into n8n's built-in AI Agent.",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",
7
7
  "n8n",
@@ -9,13 +9,13 @@
9
9
  "berget",
10
10
  "ai",
11
11
  "llm",
12
- "agent",
13
12
  "chat",
14
13
  "embeddings",
15
14
  "ocr",
16
15
  "speech",
17
16
  "rerank",
18
- "tools"
17
+ "langchain",
18
+ "ai-agent"
19
19
  ],
20
20
  "license": "MIT",
21
21
  "homepage": "https://github.com/mickekring/n8n-nodes-berget-mk",
@@ -41,11 +41,15 @@
41
41
  "form-data": "^4.0.0"
42
42
  },
43
43
  "devDependencies": {
44
+ "@langchain/core": "^1.1.39",
45
+ "@langchain/openai": "^1.4.3",
44
46
  "@types/node": "^20.11.0",
45
- "n8n-workflow": "^1.17.0",
47
+ "n8n-workflow": "^2.16.0",
46
48
  "typescript": "^5.3.0"
47
49
  },
48
50
  "peerDependencies": {
51
+ "@langchain/core": "*",
52
+ "@langchain/openai": "*",
49
53
  "n8n-workflow": "*"
50
54
  },
51
55
  "engines": {
@@ -57,8 +61,8 @@
57
61
  "dist/credentials/BergetAiApi.credentials.js"
58
62
  ],
59
63
  "nodes": [
60
- "dist/nodes/BergetAiAgent/BergetAiAgent.node.js",
61
64
  "dist/nodes/BergetAiChat/BergetAiChat.node.js",
65
+ "dist/nodes/BergetAiChatModel/BergetAiChatModel.node.js",
62
66
  "dist/nodes/BergetAiEmbeddings/BergetAiEmbeddings.node.js",
63
67
  "dist/nodes/BergetAiOcr/BergetAiOcr.node.js",
64
68
  "dist/nodes/BergetAiRerank/BergetAiRerank.node.js",
@@ -1,10 +0,0 @@
1
- import { IExecuteFunctions, ILoadOptionsFunctions, INodeExecutionData, INodePropertyOptions, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
- export declare class BergetAiAgent implements INodeType {
3
- description: INodeTypeDescription;
4
- methods: {
5
- loadOptions: {
6
- getModels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
7
- };
8
- };
9
- execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
10
- }
@@ -1,365 +0,0 @@
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.BergetAiAgent = void 0;
7
- const n8n_workflow_1 = require("n8n-workflow");
8
- const axios_1 = __importDefault(require("axios"));
9
- class BergetAiAgent {
10
- constructor() {
11
- this.description = {
12
- displayName: 'Berget AI Agent',
13
- name: 'bergetAiAgent',
14
- icon: 'file:bergetai.svg',
15
- group: ['transform'],
16
- version: 1,
17
- subtitle: '={{$parameter["operation"] + ": " + $parameter["model"]}}',
18
- description: 'AI Agent with tool calling capabilities using Berget AI models',
19
- defaults: {
20
- name: 'Berget AI Agent',
21
- },
22
- inputs: ['main'],
23
- outputs: ['main'],
24
- credentials: [
25
- {
26
- name: 'bergetAiApi',
27
- required: true,
28
- },
29
- ],
30
- requestDefaults: {
31
- ignoreHttpStatusErrors: true,
32
- baseURL: 'https://api.berget.ai/v1',
33
- },
34
- properties: [
35
- {
36
- displayName: 'Operation',
37
- name: 'operation',
38
- type: 'options',
39
- noDataExpression: true,
40
- options: [
41
- {
42
- name: 'Agent',
43
- value: 'agent',
44
- description: 'Run agent with tool calling',
45
- action: 'Run agent with tool calling',
46
- },
47
- ],
48
- default: 'agent',
49
- },
50
- {
51
- displayName: 'Model',
52
- name: 'model',
53
- type: 'options',
54
- typeOptions: {
55
- loadOptionsMethod: 'getModels',
56
- },
57
- default: '',
58
- description: 'Model to use for the agent',
59
- required: true,
60
- },
61
- {
62
- displayName: 'System Prompt',
63
- name: 'systemPrompt',
64
- type: 'string',
65
- typeOptions: {
66
- rows: 4,
67
- },
68
- default: 'You are a helpful AI assistant with access to tools. Use the tools when necessary to help the user accomplish their tasks.',
69
- description: 'System prompt that defines the agent\'s behavior and capabilities',
70
- },
71
- {
72
- displayName: 'User Message',
73
- name: 'userMessage',
74
- type: 'string',
75
- typeOptions: {
76
- rows: 2,
77
- },
78
- default: '',
79
- description: 'The user\'s message or task for the agent',
80
- required: true,
81
- },
82
- {
83
- displayName: 'Tools',
84
- name: 'tools',
85
- type: 'fixedCollection',
86
- typeOptions: {
87
- multipleValues: true,
88
- },
89
- default: {
90
- values: [],
91
- },
92
- description: 'Tools available to the agent',
93
- options: [
94
- {
95
- displayName: 'Tool',
96
- name: 'values',
97
- values: [
98
- {
99
- displayName: 'Tool Name',
100
- name: 'name',
101
- type: 'string',
102
- default: '',
103
- description: 'Name of the tool',
104
- required: true,
105
- },
106
- {
107
- displayName: 'Tool Description',
108
- name: 'description',
109
- type: 'string',
110
- typeOptions: {
111
- rows: 2,
112
- },
113
- default: '',
114
- description: 'Description of what the tool does',
115
- required: true,
116
- },
117
- {
118
- displayName: 'Parameters',
119
- name: 'parameters',
120
- type: 'json',
121
- default: '{\n "type": "object",\n "properties": {},\n "required": []\n}',
122
- description: 'JSON Schema for tool parameters',
123
- },
124
- ],
125
- },
126
- ],
127
- },
128
- {
129
- displayName: 'Options',
130
- name: 'options',
131
- type: 'collection',
132
- placeholder: 'Add options',
133
- default: {},
134
- options: [
135
- {
136
- displayName: 'Temperature',
137
- name: 'temperature',
138
- type: 'number',
139
- typeOptions: {
140
- minValue: 0,
141
- maxValue: 2,
142
- numberStepSize: 0.1,
143
- },
144
- default: 0.7,
145
- description: 'Controls randomness in responses. Lower values = more deterministic.',
146
- },
147
- {
148
- displayName: 'Max Tokens',
149
- name: 'max_tokens',
150
- type: 'number',
151
- default: 2000,
152
- description: 'Maximum number of tokens to generate',
153
- },
154
- {
155
- displayName: 'Max Iterations',
156
- name: 'max_iterations',
157
- type: 'number',
158
- default: 5,
159
- description: 'Maximum number of agent iterations (tool calls)',
160
- },
161
- {
162
- displayName: 'Tool Choice',
163
- name: 'tool_choice',
164
- type: 'options',
165
- options: [
166
- {
167
- name: 'Auto',
168
- value: 'auto',
169
- description: 'Model decides when to use tools',
170
- },
171
- {
172
- name: 'Required',
173
- value: 'required',
174
- description: 'Model must use a tool',
175
- },
176
- {
177
- name: 'None',
178
- value: 'none',
179
- description: 'Model will not use tools',
180
- },
181
- ],
182
- default: 'auto',
183
- description: 'Control how the model uses tools',
184
- },
185
- ],
186
- },
187
- ],
188
- };
189
- this.methods = {
190
- loadOptions: {
191
- async getModels() {
192
- try {
193
- const credentials = await this.getCredentials('bergetAiApi');
194
- const response = await axios_1.default.get('https://api.berget.ai/v1/models', {
195
- headers: {
196
- 'Authorization': `Bearer ${credentials.apiKey}`,
197
- 'Content-Type': 'application/json',
198
- },
199
- });
200
- if (response.status !== 200) {
201
- throw new Error(`API error: ${response.statusText}`);
202
- }
203
- // Filter models that support chat completions and tool calling
204
- const models = response.data.data || [];
205
- const chatModels = models.filter((model) => {
206
- // Use API metadata: filter for text models with function calling capability
207
- return model.model_type === 'text' &&
208
- model.capabilities &&
209
- model.capabilities.function_calling === true;
210
- });
211
- return chatModels.map((model) => ({
212
- name: model.id,
213
- value: model.id,
214
- description: `${model.id}${model.owned_by ? ` (${model.owned_by})` : ''}`,
215
- })).sort((a, b) => a.name.localeCompare(b.name));
216
- }
217
- catch (error) {
218
- throw new Error(`Failed to load models from Berget AI API. Please check your API key and network connection. Error: ${error instanceof Error ? error.message : String(error)}`);
219
- }
220
- },
221
- },
222
- };
223
- }
224
- async execute() {
225
- var _a, _b, _c, _d, _e;
226
- const items = this.getInputData();
227
- const returnData = [];
228
- const credentials = await this.getCredentials('bergetAiApi');
229
- for (let i = 0; i < items.length; i++) {
230
- try {
231
- const operation = this.getNodeParameter('operation', i);
232
- const model = this.getNodeParameter('model', i);
233
- const systemPrompt = this.getNodeParameter('systemPrompt', i);
234
- const userMessage = this.getNodeParameter('userMessage', i);
235
- const toolsConfig = this.getNodeParameter('tools.values', i, []);
236
- const options = this.getNodeParameter('options', i, {});
237
- if (operation === 'agent') {
238
- // Parse and validate tools
239
- const tools = toolsConfig.map(tool => {
240
- if (!tool.name || !tool.description) {
241
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Tool name and description are required', { itemIndex: i });
242
- }
243
- try {
244
- const parameters = typeof tool.parameters === 'string'
245
- ? JSON.parse(tool.parameters)
246
- : tool.parameters;
247
- // Validate that parameters is a valid JSON Schema object
248
- if (typeof parameters !== 'object' || parameters === null) {
249
- throw new Error('Parameters must be a valid JSON Schema object');
250
- }
251
- return {
252
- type: 'function',
253
- function: {
254
- name: tool.name.trim(),
255
- description: tool.description.trim(),
256
- parameters,
257
- },
258
- };
259
- }
260
- catch (error) {
261
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid JSON Schema in parameters for tool "${tool.name}": ${error instanceof Error ? error.message : String(error)}`, { itemIndex: i });
262
- }
263
- });
264
- // Initialize conversation
265
- const messages = [
266
- { role: 'system', content: systemPrompt },
267
- { role: 'user', content: userMessage },
268
- ];
269
- const maxIterations = options.max_iterations || 5;
270
- let iteration = 0;
271
- let finalResponse = null;
272
- const toolCalls = [];
273
- // Agent loop
274
- while (iteration < maxIterations) {
275
- iteration++;
276
- const body = {
277
- model,
278
- messages,
279
- temperature: (_a = options.temperature) !== null && _a !== void 0 ? _a : 0.7,
280
- max_tokens: (_b = options.max_tokens) !== null && _b !== void 0 ? _b : 2000,
281
- };
282
- // Add tools if available
283
- if (tools.length > 0) {
284
- body.tools = tools;
285
- if (options.tool_choice) {
286
- body.tool_choice = options.tool_choice;
287
- }
288
- }
289
- const response = await axios_1.default.post('https://api.berget.ai/v1/chat/completions', body, {
290
- headers: {
291
- 'Authorization': `Bearer ${credentials.apiKey}`,
292
- 'Content-Type': 'application/json',
293
- },
294
- });
295
- if (response.status !== 200) {
296
- const errorMessage = ((_d = (_c = response.data) === null || _c === void 0 ? void 0 : _c.error) === null || _d === void 0 ? void 0 : _d.message) ||
297
- ((_e = response.data) === null || _e === void 0 ? void 0 : _e.message) ||
298
- response.statusText ||
299
- 'Unknown API error';
300
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Berget AI API error (${response.status}): ${errorMessage}. Check your API key and model availability`, {
301
- itemIndex: i
302
- });
303
- }
304
- const choice = response.data.choices[0];
305
- const message = choice.message;
306
- // Add assistant's response to messages
307
- messages.push(message);
308
- // Check if there are tool calls
309
- if (message.tool_calls && message.tool_calls.length > 0) {
310
- // Process each tool call
311
- for (const toolCall of message.tool_calls) {
312
- toolCalls.push({
313
- id: toolCall.id,
314
- name: toolCall.function.name,
315
- arguments: toolCall.function.arguments,
316
- iteration,
317
- });
318
- // Tool execution is not implemented in this node
319
- // This node only handles the AI conversation flow and tool call detection
320
- // Actual tool execution should be handled by subsequent nodes in the workflow
321
- // The tool calls are returned in the output for further processing
322
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Tool execution is not supported in this node. The AI model requested to call tool "${toolCall.function.name}" but this node only handles conversation flow. Use the tool calls in the output to implement actual tool execution in your workflow.`, {
323
- itemIndex: i,
324
- description: 'Connect this node to other nodes that can execute the requested tools, then feed the results back to continue the conversation.'
325
- });
326
- }
327
- }
328
- else {
329
- // No tool calls, agent is done
330
- finalResponse = message.content;
331
- break;
332
- }
333
- // Check finish reason
334
- if (choice.finish_reason === 'stop') {
335
- finalResponse = message.content;
336
- break;
337
- }
338
- }
339
- returnData.push({
340
- json: {
341
- response: finalResponse,
342
- tool_calls: toolCalls,
343
- iterations: iteration,
344
- messages: messages,
345
- model,
346
- },
347
- pairedItem: { item: i },
348
- });
349
- }
350
- }
351
- catch (error) {
352
- if (this.continueOnFail()) {
353
- returnData.push({
354
- json: { error: error instanceof Error ? error.message : String(error) },
355
- pairedItem: { item: i },
356
- });
357
- continue;
358
- }
359
- throw error;
360
- }
361
- }
362
- return [returnData];
363
- }
364
- }
365
- exports.BergetAiAgent = BergetAiAgent;
@@ -1,8 +0,0 @@
1
- <svg width="463" height="419" viewBox="0 0 463 419" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <defs>
3
- <filter id="invertFilter">
4
- <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
5
- </filter>
6
- </defs>
7
- <path d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z" fill="black" filter="url(#invertFilter)"/>
8
- </svg>