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 +22 -0
- package/README.md +24 -5
- package/dist/nodes/BergetAiChat/bergetai.svg +2 -7
- package/dist/nodes/BergetAiChatModel/BergetAiChatModel.node.d.ts +10 -0
- package/dist/nodes/BergetAiChatModel/BergetAiChatModel.node.js +198 -0
- package/dist/nodes/BergetAiChatModel/bergetai.svg +3 -0
- package/dist/nodes/BergetAiEmbeddings/bergetai.svg +2 -7
- package/dist/nodes/BergetAiOcr/bergetai.svg +2 -7
- package/dist/nodes/BergetAiRerank/bergetai.svg +2 -7
- package/dist/nodes/BergetAiSpeech/bergetai.svg +2 -7
- package/package.json +10 -6
- package/dist/nodes/BergetAiAgent/BergetAiAgent.node.d.ts +0 -10
- package/dist/nodes/BergetAiAgent/BergetAiAgent.node.js +0 -365
- package/dist/nodes/BergetAiAgent/bergetai.svg +0 -8
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)
|
|
3
|
+
n8n community nodes for [Berget AI](https://berget.ai), packaged as a single installable module. Maintained by Micke Kring.
|
|
4
4
|
|
|
5
|
-
Includes
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
|
2
|
-
<
|
|
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;
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
<svg
|
|
2
|
-
<
|
|
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
|
|
2
|
-
<
|
|
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
|
|
2
|
-
<
|
|
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
|
|
2
|
-
<
|
|
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.
|
|
4
|
-
"description": "n8n community nodes for Berget AI — chat,
|
|
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
|
-
"
|
|
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": "^
|
|
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>
|