n8n-nodes-berget-mk 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 ADDED
@@ -0,0 +1,23 @@
1
+ # n8n-nodes-berget-mk
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.
4
+
5
+ Includes six nodes: **Chat**, **Agent** (with tool calling), **Embeddings**, **OCR**, **Speech-to-Text**, and **Rerank**.
6
+
7
+ ## Install
8
+
9
+ In n8n: **Settings → Community Nodes → Install** and enter:
10
+
11
+ ```text
12
+ n8n-nodes-berget-mk
13
+ ```
14
+
15
+ Then add a **Berget AI API** credential with your API key from [berget.ai](https://berget.ai).
16
+
17
+ ## Compatibility
18
+
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.
20
+
21
+ ## License
22
+
23
+ MIT
@@ -0,0 +1,9 @@
1
+ import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class BergetAiApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ authenticate: IAuthenticateGeneric;
8
+ test: ICredentialTestRequest;
9
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BergetAiApi = void 0;
4
+ class BergetAiApi {
5
+ constructor() {
6
+ this.name = 'bergetAiApi';
7
+ this.displayName = 'Berget AI API';
8
+ this.documentationUrl = 'https://api.berget.ai/docs';
9
+ this.properties = [
10
+ {
11
+ displayName: 'API Key',
12
+ name: 'apiKey',
13
+ type: 'string',
14
+ typeOptions: { password: true },
15
+ default: '',
16
+ required: true,
17
+ description: 'Your Berget AI API key. Get it from https://berget.ai',
18
+ },
19
+ ];
20
+ this.authenticate = {
21
+ type: 'generic',
22
+ properties: {
23
+ headers: {
24
+ Authorization: '=Bearer {{$credentials.apiKey}}',
25
+ },
26
+ },
27
+ };
28
+ this.test = {
29
+ request: {
30
+ baseURL: 'https://api.berget.ai/v1',
31
+ url: '/models',
32
+ method: 'GET',
33
+ },
34
+ };
35
+ }
36
+ }
37
+ exports.BergetAiApi = BergetAiApi;
@@ -0,0 +1,10 @@
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
+ }
@@ -0,0 +1,365 @@
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;
@@ -0,0 +1,8 @@
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>
@@ -0,0 +1,10 @@
1
+ import { IExecuteFunctions, ILoadOptionsFunctions, INodeExecutionData, INodePropertyOptions, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class BergetAiChat implements INodeType {
3
+ description: INodeTypeDescription;
4
+ methods: {
5
+ loadOptions: {
6
+ getModels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
7
+ };
8
+ };
9
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
10
+ }