n8n-nodes-mindrouter 0.1.0 → 0.2.2

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 CHANGED
@@ -22,15 +22,23 @@ npm install n8n-nodes-mindrouter
22
22
  2. In n8n, add a **MindRouter API** credential and paste the key.
23
23
  3. Leave the base URL as `https://api.mindrouter.io/v1` unless you run a self-hosted gateway.
24
24
 
25
- ## Operations
25
+ ## Nodes
26
26
 
27
- ### Chat
27
+ ### MindRouter Chat Model
28
+
29
+ A sub-node for the **AI Agent** and **LLM Chain** nodes: click the **Chat Model** socket and pick *MindRouter Chat Model*. Choose any model from your account (loaded live) and set temperature, max tokens, top-p, penalties, and timeout. Everything the agent does then runs through the MindRouter gateway — guardrails, spend limits, and usage tracking included.
30
+
31
+ ### MindRouter
32
+
33
+ A regular node for direct calls.
34
+
35
+ #### Chat
28
36
 
29
37
  Send a prompt (or a full OpenAI-format `messages` array) to any model your account can use. The model dropdown is loaded live from your account, so it always matches your plan and provider settings. Supports temperature, max output tokens, and a simplified output (`text`, `model`, `usage`) or the raw API response.
30
38
 
31
- The node is usable as a tool by n8n **AI Agent** nodes.
39
+ The node is also usable as a tool by n8n **AI Agent** nodes.
32
40
 
33
- ### List Models
41
+ #### List Models
34
42
 
35
43
  Returns the models available to your account, including pricing metadata.
36
44
 
@@ -2,10 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MindRouter = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
- function normalizeBaseUrl(raw) {
6
- const url = String(raw !== null && raw !== void 0 ? raw : 'https://api.mindrouter.io/v1').trim();
7
- return url.replace(/\/+$/, '');
8
- }
5
+ const api_1 = require("../shared/api");
9
6
  class MindRouter {
10
7
  constructor() {
11
8
  this.description = {
@@ -129,21 +126,7 @@ class MindRouter {
129
126
  this.methods = {
130
127
  loadOptions: {
131
128
  async getModels() {
132
- var _a;
133
- const credentials = await this.getCredentials('mindRouterApi');
134
- const baseUrl = normalizeBaseUrl(credentials.baseUrl);
135
- const response = (await this.helpers.httpRequestWithAuthentication.call(this, 'mindRouterApi', {
136
- method: 'GET',
137
- url: `${baseUrl}/models`,
138
- json: true,
139
- }));
140
- const models = (_a = response.data) !== null && _a !== void 0 ? _a : [];
141
- return models
142
- .map((m) => ({
143
- name: m.display_name || m.id,
144
- value: m.id,
145
- }))
146
- .sort((a, b) => a.name.localeCompare(b.name));
129
+ return (0, api_1.loadModelOptions)(this);
147
130
  },
148
131
  },
149
132
  };
@@ -154,7 +137,7 @@ class MindRouter {
154
137
  const returnData = [];
155
138
  const operation = this.getNodeParameter('operation', 0);
156
139
  const credentials = await this.getCredentials('mindRouterApi');
157
- const baseUrl = normalizeBaseUrl(credentials.baseUrl);
140
+ const baseUrl = (0, api_1.normalizeBaseUrl)(credentials.baseUrl);
158
141
  for (let i = 0; i < items.length; i++) {
159
142
  try {
160
143
  if (operation === 'listModels') {
@@ -1,4 +1,28 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60">
2
- <rect width="60" height="60" rx="12" fill="#4F46E5"/>
3
- <path d="M14 42V18h6l10 14 10-14h6v24h-7V30l-9 12-9-12v12z" fill="#fff"/>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" role="img" aria-label="MindRouter">
2
+ <rect width="60" height="60" rx="12" fill="#101826"/>
3
+ <g transform="translate(8 12)">
4
+ <defs>
5
+ <mask id="mh">
6
+ <rect width="44" height="36" fill="#fff"/>
7
+ <circle cx="22" cy="18.5" r="5.4" fill="#000"/>
8
+ </mask>
9
+ </defs>
10
+ <g mask="url(#mh)">
11
+ <path d="M4 32 L12 7 L22 19 Z" fill="#FFFFFF"/>
12
+ <path d="M22 19 L31 10 L38 32 Z" fill="#FFFFFF"/>
13
+ </g>
14
+ <circle cx="22" cy="18.5" r="5.4" fill="none" stroke="#FFFFFF" stroke-width="2"/>
15
+ <g transform="translate(18 14.5) scale(0.5)">
16
+ <g fill="none" stroke="#14B8B0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
17
+ <path d="M3.8 8 H8"/>
18
+ <path d="M8 8 V5 H12"/>
19
+ <path d="M8 8 V11 H12"/>
20
+ </g>
21
+ <g fill="#14B8B0">
22
+ <circle cx="3.8" cy="8" r="1.5"/>
23
+ <circle cx="12.2" cy="5" r="1.3"/>
24
+ <circle cx="12.2" cy="11" r="1.3"/>
25
+ </g>
26
+ </g>
27
+ </g>
4
28
  </svg>
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MindRouterChatModel = void 0;
4
+ const openai_1 = require("@langchain/openai");
5
+ const n8n_workflow_1 = require("n8n-workflow");
6
+ const api_1 = require("../shared/api");
7
+ class MindRouterChatModel {
8
+ constructor() {
9
+ this.description = {
10
+ displayName: 'MindRouter Chat Model',
11
+ name: 'lmChatMindRouter',
12
+ icon: 'file:mindrouter.svg',
13
+ group: ['transform'],
14
+ version: 1,
15
+ description: 'Use MindRouter models with AI Agents and Chains',
16
+ defaults: {
17
+ name: 'MindRouter Chat Model',
18
+ },
19
+ codex: {
20
+ categories: ['AI'],
21
+ subcategories: {
22
+ AI: ['Language Models', 'Root Nodes'],
23
+ 'Language Models': ['Chat Models (Recommended)'],
24
+ },
25
+ resources: {
26
+ primaryDocumentation: [
27
+ {
28
+ url: 'https://mindrouter.io/docs',
29
+ },
30
+ ],
31
+ },
32
+ },
33
+ inputs: [],
34
+ outputs: [n8n_workflow_1.NodeConnectionTypes.AiLanguageModel],
35
+ outputNames: ['Model'],
36
+ credentials: [
37
+ {
38
+ name: 'mindRouterApi',
39
+ required: true,
40
+ },
41
+ ],
42
+ properties: [
43
+ {
44
+ displayName: 'Model Name or ID',
45
+ name: 'model',
46
+ type: 'options',
47
+ description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
48
+ typeOptions: {
49
+ loadOptionsMethod: 'getModels',
50
+ },
51
+ required: true,
52
+ default: '',
53
+ },
54
+ {
55
+ displayName: 'Options',
56
+ name: 'options',
57
+ type: 'collection',
58
+ placeholder: 'Add option',
59
+ default: {},
60
+ options: [
61
+ {
62
+ displayName: 'Temperature',
63
+ name: 'temperature',
64
+ type: 'number',
65
+ typeOptions: { minValue: 0, maxValue: 2, numberPrecision: 2 },
66
+ default: 1,
67
+ },
68
+ {
69
+ displayName: 'Max Output Tokens',
70
+ name: 'maxTokens',
71
+ type: 'number',
72
+ typeOptions: { minValue: 1 },
73
+ default: 1024,
74
+ },
75
+ {
76
+ displayName: 'Top P',
77
+ name: 'topP',
78
+ type: 'number',
79
+ typeOptions: { minValue: 0, maxValue: 1, numberPrecision: 2 },
80
+ default: 1,
81
+ },
82
+ {
83
+ displayName: 'Frequency Penalty',
84
+ name: 'frequencyPenalty',
85
+ type: 'number',
86
+ typeOptions: { minValue: -2, maxValue: 2, numberPrecision: 2 },
87
+ default: 0,
88
+ },
89
+ {
90
+ displayName: 'Presence Penalty',
91
+ name: 'presencePenalty',
92
+ type: 'number',
93
+ typeOptions: { minValue: -2, maxValue: 2, numberPrecision: 2 },
94
+ default: 0,
95
+ },
96
+ {
97
+ displayName: 'Timeout (Ms)',
98
+ name: 'timeout',
99
+ type: 'number',
100
+ typeOptions: { minValue: 1 },
101
+ default: 60000,
102
+ },
103
+ ],
104
+ },
105
+ ],
106
+ };
107
+ this.methods = {
108
+ loadOptions: {
109
+ async getModels() {
110
+ return (0, api_1.loadModelOptions)(this);
111
+ },
112
+ },
113
+ };
114
+ }
115
+ async supplyData(itemIndex) {
116
+ const credentials = await this.getCredentials('mindRouterApi');
117
+ const modelName = this.getNodeParameter('model', itemIndex);
118
+ const options = this.getNodeParameter('options', itemIndex, {});
119
+ const model = new openai_1.ChatOpenAI({
120
+ apiKey: String(credentials.apiKey),
121
+ model: modelName,
122
+ temperature: options.temperature,
123
+ maxTokens: options.maxTokens,
124
+ topP: options.topP,
125
+ frequencyPenalty: options.frequencyPenalty,
126
+ presencePenalty: options.presencePenalty,
127
+ timeout: options.timeout,
128
+ configuration: {
129
+ baseURL: (0, api_1.normalizeBaseUrl)(credentials.baseUrl),
130
+ },
131
+ });
132
+ return {
133
+ response: model,
134
+ };
135
+ }
136
+ }
137
+ exports.MindRouterChatModel = MindRouterChatModel;
@@ -0,0 +1,28 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" role="img" aria-label="MindRouter">
2
+ <rect width="60" height="60" rx="12" fill="#101826"/>
3
+ <g transform="translate(8 12)">
4
+ <defs>
5
+ <mask id="mh">
6
+ <rect width="44" height="36" fill="#fff"/>
7
+ <circle cx="22" cy="18.5" r="5.4" fill="#000"/>
8
+ </mask>
9
+ </defs>
10
+ <g mask="url(#mh)">
11
+ <path d="M4 32 L12 7 L22 19 Z" fill="#FFFFFF"/>
12
+ <path d="M22 19 L31 10 L38 32 Z" fill="#FFFFFF"/>
13
+ </g>
14
+ <circle cx="22" cy="18.5" r="5.4" fill="none" stroke="#FFFFFF" stroke-width="2"/>
15
+ <g transform="translate(18 14.5) scale(0.5)">
16
+ <g fill="none" stroke="#14B8B0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
17
+ <path d="M3.8 8 H8"/>
18
+ <path d="M8 8 V5 H12"/>
19
+ <path d="M8 8 V11 H12"/>
20
+ </g>
21
+ <g fill="#14B8B0">
22
+ <circle cx="3.8" cy="8" r="1.5"/>
23
+ <circle cx="12.2" cy="5" r="1.3"/>
24
+ <circle cx="12.2" cy="11" r="1.3"/>
25
+ </g>
26
+ </g>
27
+ </g>
28
+ </svg>
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeBaseUrl = normalizeBaseUrl;
4
+ exports.loadModelOptions = loadModelOptions;
5
+ function normalizeBaseUrl(raw) {
6
+ const url = String(raw !== null && raw !== void 0 ? raw : 'https://api.mindrouter.io/v1').trim();
7
+ return url.replace(/\/+$/, '');
8
+ }
9
+ async function loadModelOptions(context) {
10
+ var _a;
11
+ const credentials = await context.getCredentials('mindRouterApi');
12
+ const baseUrl = normalizeBaseUrl(credentials.baseUrl);
13
+ const response = (await context.helpers.httpRequestWithAuthentication.call(context, 'mindRouterApi', {
14
+ method: 'GET',
15
+ url: `${baseUrl}/models`,
16
+ json: true,
17
+ }));
18
+ return ((_a = response.data) !== null && _a !== void 0 ? _a : [])
19
+ .map((m) => ({ name: m.display_name || m.id, value: m.id }))
20
+ .sort((a, b) => a.name.localeCompare(b.name));
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-mindrouter",
3
- "version": "0.1.0",
3
+ "version": "0.2.2",
4
4
  "description": "n8n community node for MindRouter — unified gateway to AI models with Indonesian PII guardrails",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",
@@ -38,7 +38,8 @@
38
38
  "dist/credentials/MindRouterApi.credentials.js"
39
39
  ],
40
40
  "nodes": [
41
- "dist/nodes/MindRouter/MindRouter.node.js"
41
+ "dist/nodes/MindRouter/MindRouter.node.js",
42
+ "dist/nodes/MindRouterChatModel/MindRouterChatModel.node.js"
42
43
  ]
43
44
  },
44
45
  "devDependencies": {
@@ -50,5 +51,8 @@
50
51
  },
51
52
  "peerDependencies": {
52
53
  "n8n-workflow": "*"
54
+ },
55
+ "dependencies": {
56
+ "@langchain/openai": "^1.5.11"
53
57
  }
54
58
  }