node-red-contrib-ai-agent 0.0.1 → 0.0.3

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.
@@ -0,0 +1,338 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType('ai-model', {
3
+ category: 'AI Agent',
4
+ inputs: 1,
5
+ outputs: 1,
6
+ icon: 'model/ai-model-icon.svg',
7
+ paletteLabel: 'AI Model',
8
+ label: function() {
9
+ return this.name || 'AI Model';
10
+ },
11
+ color: '#a6bbcf',
12
+ defaults: {
13
+ name: { value: '' },
14
+ model: {
15
+ value: '',
16
+ required: true,
17
+ validate: function(val) {
18
+ return val && val.length > 0;
19
+ }
20
+ },
21
+ temperature: {
22
+ value: 0.7,
23
+ validate: RED.validators.number(),
24
+ required: true
25
+ },
26
+ maxTokens: {
27
+ value: 1000,
28
+ validate: RED.validators.number(),
29
+ required: true
30
+ }
31
+ },
32
+ credentials: {
33
+ apiKey: { type: "text" }
34
+ },
35
+ oneditprepare: function() {
36
+ var node = this;
37
+
38
+ // Store the original values to detect changes
39
+ var originalValues = {
40
+ name: node.name || '',
41
+ model: node.model || '',
42
+ temperature: node.temperature || 0.7,
43
+ maxTokens: node.maxTokens || 1000,
44
+ apiKey: (this.credentials && this.credentials.apiKey) || ''
45
+ };
46
+
47
+ // Initialize temperature slider
48
+ $('#node-config-input-temperature').on('input', function() {
49
+ $('#temperature-value').text($(this).val());
50
+ });
51
+
52
+ // Set initial values
53
+ $('#node-config-input-name').val(originalValues.name);
54
+ $('#node-config-input-model').val(originalValues.model);
55
+ $('#node-config-input-temperature').val(originalValues.temperature);
56
+ $('#node-config-input-maxTokens').val(originalValues.maxTokens);
57
+ $('#temperature-value').text(originalValues.temperature);
58
+
59
+ // Initialize credentials if they don't exist
60
+ this.credentials = this.credentials || {};
61
+
62
+ // Always set the API key field value from credentials
63
+ // This ensures the existing key is preserved when opening the editor
64
+ const currentApiKey = (this.credentials && this.credentials.apiKey) || '';
65
+ $('#node-config-input-credentials-apiKey').val(currentApiKey);
66
+
67
+ // Update the originalValues to include the current API key
68
+ originalValues.apiKey = currentApiKey;
69
+
70
+ // Override the default close behavior to prevent marking as changed when no changes were made
71
+ var originalClose = RED.view.state.RED_view_state_close;
72
+ RED.view.state.RED_view_state_close = function() {
73
+ var currentValues = {
74
+ name: $('#node-config-input-name').val(),
75
+ model: $('#node-config-input-model').val(),
76
+ temperature: parseFloat($('#node-config-input-temperature').val()),
77
+ maxTokens: parseInt($('#node-config-input-maxTokens').val()),
78
+ apiKey: $('#node-config-input-credentials-apiKey').val()
79
+ };
80
+
81
+ var hasChanges = Object.keys(originalValues).some(function(key) {
82
+ return originalValues[key] !== currentValues[key];
83
+ });
84
+
85
+ if (!hasChanges) {
86
+ // If no changes, prevent the dirty flag from being set
87
+ RED.view.state.dirty = RED.view.state._dirty;
88
+ }
89
+
90
+ // Call the original close function
91
+ originalClose.apply(this, arguments);
92
+
93
+ // Restore the original close function
94
+ RED.view.state.RED_view_state_close = originalClose;
95
+ };
96
+
97
+ // Add validation for required fields
98
+ $('#node-config-dialog-form').on('submit', function(e) {
99
+ if (!$('#node-config-input-name').val()) {
100
+ RED.notify('Please enter a name for the configuration', 'error');
101
+ return false;
102
+ }
103
+ if (!$('#node-config-input-credentials-apiKey').val()) {
104
+ RED.notify('Please enter an OpenRouter API key', 'error');
105
+ return false;
106
+ }
107
+ if (!$('#node-config-input-model').val()) {
108
+ RED.notify('Please select an AI model', 'error');
109
+ return false;
110
+ }
111
+ return true;
112
+ });
113
+ },
114
+
115
+ oneditsave: function() {
116
+ // Save all configuration values
117
+ this.name = $('#node-config-input-name').val();
118
+ this.model = $('#node-config-input-model').val();
119
+ this.temperature = parseFloat($('#node-config-input-temperature').val());
120
+ this.maxTokens = parseInt($('#node-config-input-maxTokens').val());
121
+
122
+ // Always ensure credentials object exists
123
+ this.credentials = this.credentials || {};
124
+
125
+ // Only update the API key if the field is not empty
126
+ // This preserves the existing key if the field is left blank
127
+ var apiKey = $('#node-config-input-credentials-apiKey').val();
128
+ if (apiKey !== '') {
129
+ this.credentials.apiKey = apiKey;
130
+ }
131
+ },
132
+
133
+ oneditcancel: function() {
134
+ // Clean up if needed
135
+ this.credentials = this.credentials || {};
136
+ }
137
+ });
138
+ </script>
139
+
140
+ <script type="text/x-red" data-template-name="ai-model">
141
+ <div class="form-row">
142
+ <label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
143
+ <input type="text" id="node-config-input-name" placeholder="AI Model">
144
+ </div>
145
+
146
+ <div class="form-row">
147
+ <label for="node-config-input-credentials-apiKey"><i class="fa fa-key"></i> OpenRouter API Key</label>
148
+ <input type="password" id="node-config-input-credentials-apiKey" placeholder="sk-or-...">
149
+ </div>
150
+
151
+ <div class="form-row">
152
+ <label for="node-config-input-model"><i class="fa fa-microchip"></i> AI Model</label>
153
+ <select id="node-config-input-model" style="width: 70%;">
154
+ <optgroup label="OpenAI">
155
+ <option value="openai/codex-mini" selected>Codex Mini ($1.50/1M input, $6/1M output, 200K context)</option>
156
+ <option value="openai/gpt-4.1">GPT-4.1 ($2/1M input, $8/1M output, 1M context)</option>
157
+ <option value="openai/gpt-4.1-mini">GPT-4.1 Mini ($0.40/1M input, $1.60/1M output, 1M context)</option>
158
+ <option value="openai/gpt-4.1-nano">GPT-4.1 Nano ($0.10/1M input, $0.40/1M output, 1M context)</option>
159
+ <option value="openai/o1-pro">o1 Pro ($150/1M input, $600/1M output, 200K context)</option>
160
+ <option value="openai/gpt-4o-mini-search-preview">GPT-4o Mini Search Preview ($0.15/1M input, $0.60/1M output, 128K context)</option>
161
+ <option value="openai/gpt-4o-search-preview">GPT-4o Search Preview ($2.50/1M input, $10/1M output, 128K context)</option>
162
+ <option value="openai/gpt-4.5-preview">GPT-4.5 Preview ($75/1M input, $150/1M output, 128K context)</option>
163
+ <option value="openai/o1">o1 ($15/1M input, $60/1M output, 200K context)</option>
164
+ <option value="openai/gpt-4o-2024-11-20">GPT-4o (2024-11-20) ($2.50/1M input, $10/1M output, 128K context)</option>
165
+ <option value="openai/o1-preview">o1 Preview ($15/1M input, $60/1M output, 128K context)</option>
166
+ <option value="openai/o1-preview-2024-09-12">o1 Preview (2024-09-12) ($15/1M input, $60/1M output, 128K context)</option>
167
+ <option value="openai/o1-mini">o1 Mini ($1.10/1M input, $4.40/1M output, 128K context)</option>
168
+ <option value="openai/o1-mini-2024-09-12">o1 Mini (2024-09-12) ($1.10/1M input, $4.40/1M output, 128K context)</option>
169
+ <option value="openai/chatgpt-4o-latest">ChatGPT-4o ($5/1M input, $15/1M output, 128K context)</option>
170
+ <option value="openai/gpt-4o-2024-08-06">GPT-4o (2024-08-06) ($2.50/1M input, $10/1M output, 128K context)</option>
171
+ <option value="openai/gpt-4o-mini">GPT-4o Mini ($0.15/1M input, $0.60/1M output, 128K context)</option>
172
+ <option value="openai/gpt-4o-mini-2024-07-18">GPT-4o Mini (2024-07-18) ($0.15/1M input, $0.60/1M output, 128K context)</option>
173
+ <option value="openai/gpt-4o">GPT-4o ($2.50/1M input, $10/1M output, 128K context)</option>
174
+ <option value="openai/gpt-4o:extended">GPT-4o Extended ($6/1M input, $18/1M output, 128K context)</option>
175
+ <option value="openai/gpt-4o-2024-05-13">GPT-4o (2024-05-13) ($5/1M input, $15/1M output, 128K context)</option>
176
+ <option value="openai/gpt-4-turbo">GPT-4 Turbo ($10/1M input, $30/1M output, 128K context)</option>
177
+ <option value="openai/gpt-3.5-turbo-0613">GPT-3.5 Turbo v0613 ($1/1M input, $2/1M output, 4K context)</option>
178
+ <option value="openai/gpt-4-turbo-preview">GPT-4 Turbo Preview ($10/1M input, $30/1M output, 128K context)</option>
179
+ <option value="openai/gpt-4-1106-preview">GPT-4 Turbo v1106 ($10/1M input, $30/1M output, 128K context)</option>
180
+ <option value="openai/gpt-3.5-turbo-instruct">GPT-3.5 Turbo Instruct ($1.50/1M input, $2/1M output, 4K context)</option>
181
+ <option value="openai/gpt-3.5-turbo-16k">GPT-3.5 Turbo 16k ($3/1M input, $4/1M output, 16K context)</option>
182
+ <option value="openai/gpt-4">GPT-4 ($30/1M input, $60/1M output, 8K context)</option>
183
+ <option value="openai/gpt-4-0314">GPT-4 v0314 ($30/1M input, $60/1M output, 8K context)</option>
184
+ </optgroup>
185
+ <optgroup label="Anthropic">
186
+ <option value="anthropic/claude-opus-4" selected>Claude Opus 4 ($15/1M input, $75/1M output, 200K context)</option>
187
+ <option value="anthropic/claude-sonnet-4">Claude Sonnet 4 ($3/1M input, $15/1M output, 200K context)</option>
188
+ <option value="anthropic/claude-3.7-sonnet">Claude 3.7 Sonnet ($3/1M input, $15/1M output, 200K context)</option>
189
+ <option value="anthropic/claude-3.7-sonnet:thinking">Claude 3.7 Sonnet (thinking) ($3/1M input, $15/1M output, 200K context)</option>
190
+ <option value="anthropic/claude-3.7-sonnet:beta">Claude 3.7 Sonnet (self-moderated) ($3/1M input, $15/1M output, 200K context)</option>
191
+ <option value="anthropic/claude-3.5-haiku:beta">Claude 3.5 Haiku (self-moderated) ($0.80/1M input, $4/1M output, 200K context)</option>
192
+ <option value="anthropic/claude-3.5-haiku">Claude 3.5 Haiku ($0.80/1M input, $4/1M output, 200K context)</option>
193
+ <option value="anthropic/claude-3.5-haiku-20241022:beta">Claude 3.5 Haiku (2024-10-22, self-moderated) ($0.80/1M input, $4/1M output, 200K context)</option>
194
+ <option value="anthropic/claude-3.5-haiku-20241022">Claude 3.5 Haiku (2024-10-22) ($0.80/1M input, $4/1M output, 200K context)</option>
195
+ <option value="anthropic/claude-3.5-sonnet:beta">Claude 3.5 Sonnet (self-moderated) ($3/1M input, $15/1M output, 200K context)</option>
196
+ <option value="anthropic/claude-3.5-sonnet">Claude 3.5 Sonnet ($3/1M input, $15/1M output, 200K context)</option>
197
+ <option value="anthropic/claude-3.5-sonnet-20240620:beta">Claude 3.5 Sonnet (2024-06-20, self-moderated) ($3/1M input, $15/1M output, 200K context)</option>
198
+ <option value="anthropic/claude-3.5-sonnet-20240620">Claude 3.5 Sonnet (2024-06-20) ($3/1M input, $15/1M output, 200K context)</option>
199
+ <option value="anthropic/claude-3-haiku:beta">Claude 3 Haiku (self-moderated) ($0.25/1M input, $1.25/1M output, 200K context)</option>
200
+ <option value="anthropic/claude-3-haiku">Claude 3 Haiku ($0.25/1M input, $1.25/1M output, 200K context)</option>
201
+ <option value="anthropic/claude-3-opus:beta">Claude 3 Opus (self-moderated) ($15/1M input, $75/1M output, 200K context)</option>
202
+ <option value="anthropic/claude-3-opus">Claude 3 Opus ($15/1M input, $75/1M output, 200K context)</option>
203
+ <option value="anthropic/claude-3-sonnet:beta">Claude 3 Sonnet (self-moderated) ($3/1M input, $15/1M output, 200K context)</option>
204
+ <option value="anthropic/claude-3-sonnet">Claude 3 Sonnet ($3/1M input, $15/1M output, 200K context)</option>
205
+ <option value="anthropic/claude-2.1:beta">Claude v2.1 (self-moderated) ($8/1M input, $24/1M output, 200K context)</option>
206
+ <option value="anthropic/claude-2.1">Claude v2.1 ($8/1M input, $24/1M output, 200K context)</option>
207
+ <option value="anthropic/claude-2:beta">Claude v2 (self-moderated) ($8/1M input, $24/1M output, 200K context)</option>
208
+ <option value="anthropic/claude-2">Claude v2 ($8/1M input, $24/1M output, 200K context)</option>
209
+ <option value="anthropic/claude-2.0:beta">Claude v2.0 (self-moderated) ($8/1M input, $24/1M output, 100K context)</option>
210
+ <option value="anthropic/claude-2.0">Claude v2.0 ($8/1M input, $24/1M output, 100K context)</option>
211
+ </optgroup>
212
+ <optgroup label="Google">
213
+ <option value="google/gemini-2.5-flash-lite-preview-06-17">Gemini 2.5 Flash Lite ($0.10/1M input, $0.40/1M output)</option>
214
+ <option value="google/gemini-2.5-flash">Gemini 2.5 Flash ($0.30/1M input, $2.50/1M output)</option>
215
+ <option value="google/gemini-2.5-flash-preview-05-20">Gemini 2.5 Flash 05-20 ($0.15/1M input, $0.60/1M output)</option>
216
+ <option value="google/gemini-2.5-flash-preview-05-20:thinking">Gemini 2.5 Flash 05-20 Thinking ($0.15/1M input, $3.50/1M output)</option>
217
+ <option value="google/gemini-2.0-pro">Gemini 2.0 Pro ($0.50/1M input, $1.50/1M output)</option>
218
+ <option value="google/gemini-2.0-pro:thinking">Gemini 2.0 Pro Thinking ($0.50/1M input, $1.50/1M output)</option>
219
+ <option value="google/gemini-1.5-pro">Gemini 1.5 Pro ($3.50/1M input, $10.50/1M output)</option>
220
+ <option value="google/gemini-1.5-pro:thinking">Gemini 1.5 Pro Thinking ($3.50/1M input, $10.50/1M output)</option>
221
+ <option value="google/gemini-1.5-flash">Gemini 1.5 Flash ($0.35/1M input, $1.05/1M output)</option>
222
+ <option value="google/gemini-1.5-flash:thinking">Gemini 1.5 Flash Thinking ($0.35/1M input, $1.05/1M output)</option>
223
+ <option value="google/gemma-3-4b-it">Gemma 3 4B ($0.02/1M input, $0.04/1M output)</option>
224
+ <option value="google/gemma-3-4b-it:free">Gemma 3 4B (Free tier) ($0/1M input, $0/1M output)</option>
225
+ <option value="google/gemma-3-12b-it">Gemma 3 12B ($0.05/1M input, $0.10/1M output)</option>
226
+ <option value="google/gemma-3-12b-it:free">Gemma 3 12B (Free tier) ($0/1M input, $0/1M output)</option>
227
+ <option value="google/gemma-3-27b-it">Gemma 3 27B ($0.09/1M input, $0.17/1M output)</option>
228
+ <option value="google/gemma-3-27b-it:free">Gemma 3 27B (Free tier) ($0/1M input, $0/1M output)</option>
229
+ <option value="google/gemma-2-9b-it">Gemma 2 9B ($0.20/1M input/output)</option>
230
+ <option value="google/gemma-2-9b-it:free">Gemma 2 9B (Free tier) ($0/1M input/output)</option>
231
+ <option value="google/gemma-2-27b-it">Gemma 2 27B ($0.80/1M input/output)</option>
232
+ <option value="google/gemini-flash-1.5-8b">Gemini 1.5 Flash 8B ($0.038/1M input, $0.15/1M output)</option>
233
+ <option value="google/gemini-pro-1.5">Gemini 1.5 Pro ($1.25/1M input, $5/1M output)</option>
234
+ </optgroup>
235
+ <optgroup label="Mistral">
236
+ <option value="mistralai/mistral-small-3.2-24b-instruct:free">Mistral Small 3.2 24B (Free) ($0/1M input, $0/1M output, 96K context)</option>
237
+ <option value="mistralai/mistral-small-3.2-24b-instruct">Mistral Small 3.2 24B ($0.05/1M input, $0.10/1M output, 128K context)</option>
238
+ <option value="mistralai/magistral-small-2506">Magistral Small 2506 ($0.50/1M input, $1.50/1M output, 40K context)</option>
239
+ <option value="mistralai/magistral-medium-2506">Magistral Medium 2506 ($2/1M input, $5/1M output, 41K context)</option>
240
+ <option value="mistralai/magistral-medium-2506:thinking">Magistral Medium 2506 (thinking) ($2/1M input, $5/1M output, 41K context)</option>
241
+ <option value="mistralai/mistral-medium-3">Mistral Medium 3 ($0.40/1M input, $2/1M output, 131K context)</option>
242
+ <option value="mistralai/mistral-small-3.1-24b-instruct:free">Mistral Small 3.1 24B (Free) ($0/1M input, $0/1M output, 96K context)</option>
243
+ <option value="mistralai/mistral-small-3.1-24b-instruct">Mistral Small 3.1 24B ($0.05/1M input, $0.10/1M output, 128K context)</option>
244
+ <option value="mistralai/mistral-saba">Saba ($0.20/1M input, $0.60/1M output, 33K context)</option>
245
+ <option value="mistralai/mistral-small-24b-instruct-2501:free">Mistral Small 3 (Free) ($0/1M input, $0/1M output, 33K context)</option>
246
+ <option value="mistralai/mistral-small-24b-instruct-2501">Mistral Small 3 ($0.05/1M input, $0.08/1M output, 33K context)</option>
247
+ <option value="mistralai/codestral-2501">Codestral 2501 ($0.30/1M input, $0.90/1M output, 262K context)</option>
248
+ <option value="mistralai/mistral-large-2411">Mistral Large 2411 ($2/1M input, $6/1M output, 131K context)</option>
249
+ <option value="mistralai/mistral-large-2407">Mistral Large 2407 ($2/1M input, $6/1M output, 131K context)</option>
250
+ <option value="mistralai/pixtral-large-2411">Pixtral Large 2411 ($2/1M input, $6/1M output, 131K context)</option>
251
+ <option value="infermatic/mn-inferor-12b">Infermatic: Mistral Nemo Inferor 12B ($0.80/1M input, $1.20/1M output, 16K context)</option>
252
+ <option value="raifle/sorcererlm-8x22b">SorcererLM 8x22B ($4.50/1M input, $4.50/1M output, 16K context)</option>
253
+ <option value="thedrummer/unslopnemo-12b">TheDrummer: UnslopNemo 12B ($0.40/1M input, $0.40/1M output, 33K context)</option>
254
+ <option value="mistralai/ministral-8b">Ministral 8B ($0.10/1M input, $0.10/1M output, 128K context)</option>
255
+ <option value="mistralai/ministral-3b">Ministral 3B ($0.04/1M input, $0.04/1M output, 131K context)</option>
256
+ <option value="mistralai/pixtral-12b">Pixtral 12B ($0.10/1M input, $0.10/1M output, 33K context)</option>
257
+ <option value="aetherwiing/mn-starcannon-12b">Aetherwiing: Starcannon 12B ($0.80/1M input, $1.20/1M output, 16K context)</option>
258
+ <option value="nothingiisreal/mn-celeste-12b">Mistral Nemo 12B Celeste ($0.80/1M input, $1.20/1M output, 16K context)</option>
259
+ <option value="mistralai/mistral-nemo:free">Mistral Nemo (Free) ($0/1M input, $0/1M output, 131K context)</option>
260
+ <option value="mistralai/mistral-nemo">Mistral Nemo ($0.008/1M input, $0.001/1M output, 131K context)</option>
261
+ <option value="cognitivecomputations/dolphin-mixtral-8x22b">Dolphin 2.9.2 Mixtral 8x22B ($0.90/1M input, $0.90/1M output, 16K context)</option>
262
+ <option value="mistralai/mistral-7b-instruct:free">Mistral 7B Instruct (Free) ($0/1M input, $0/1M output, 33K context)</option>
263
+ <option value="mistralai/mistral-7b-instruct">Mistral 7B Instruct ($0.028/1M input, $0.054/1M output, 33K context)</option>
264
+ <option value="mistralai/mistral-7b-instruct-v0.3">Mistral 7B Instruct v0.3 ($0.028/1M input, $0.054/1M output, 33K context)</option>
265
+ <option value="mistralai/mixtral-8x22b-instruct">Mistral: Mixtral 8x22B Instruct ($0.90/1M input, $0.90/1M output, 66K context)</option>
266
+ <option value="microsoft/wizardlm-2-8x22b">WizardLM-2 8x22B ($0.48/1M input, $0.48/1M output, 66K context)</option>
267
+ <option value="mistralai/mistral-large">Mistral Large ($2/1M input, $6/1M output, 128K context)</option>
268
+ <option value="nousresearch/nous-hermes-2-mixtral-8x7b-dpo">Nous: Hermes 2 Mixtral 8x7B DPO ($0.60/1M input, $0.60/1M output, 33K context)</option>
269
+ <option value="mistralai/mistral-small">Mistral Small ($0.20/1M input, $0.60/1M output, 33K context)</option>
270
+ <option value="mistralai/mistral-tiny">Mistral Tiny ($0.25/1M input, $0.25/1M output, 33K context)</option>
271
+ <option value="mistralai/mistral-7b-instruct-v0.2">Mistral 7B Instruct v0.2 ($0.20/1M input, $0.20/1M output, 33K context)</option>
272
+ <option value="mistralai/mixtral-8x7b-instruct">Mistral: Mixtral 8x7B Instruct ($0.08/1M input, $0.24/1M output, 33K context)</option>
273
+ <option value="undi95/toppy-m-7b">Toppy M 7B ($0.80/1M input, $1.20/1M output, 4K context)</option>
274
+ <option value="mistralai/mistral-7b-instruct-v0.1">Mistral 7B Instruct v0.1 ($0.11/1M input, $0.19/1M output, 3K context)</option>
275
+ </optgroup>
276
+ <optgroup label="DeepSeek">
277
+ <option value="deepseek/deepseek-r1-0528:free" selected>DeepSeek R1 0528 (Free) ($0/1M input, $0/1M output, 163K context)</option>
278
+ <option value="deepseek/deepseek-r1-0528">DeepSeek R1 0528 ($0.50/1M input, $2.15/1M output, 128K context)</option>
279
+ <option value="deepseek/deepseek-prover-v2">DeepSeek Prover V2 ($0.50/1M input, $2.18/1M output, 131K context)</option>
280
+ <option value="tngtech/deepseek-r1t-chimera:free">TNG: DeepSeek R1T Chimera (Free) ($0/1M input, $0/1M output, 163K context)</option>
281
+ <option value="microsoft/mai-ds-r1:free">Microsoft: MAI DS R1 (Free) ($0/1M input, $0/1M output, 163K context)</option>
282
+ <option value="deepseek/deepseek-v3-base:free">DeepSeek V3 Base (Free) ($0/1M input, $0/1M output, 163K context)</option>
283
+ <option value="deepseek/deepseek-chat-v3-0324:free">DeepSeek V3 0324 (Free) ($0/1M input, $0/1M output, 16K context)</option>
284
+ <option value="deepseek/deepseek-chat-v3-0324">DeepSeek V3 0324 ($0.28/1M input, $0.88/1M output, 163K context)</option>
285
+ <option value="perplexity/r1-1776">Perplexity: R1 1776 ($2/1M input, $8/1M output, 128K context)</option>
286
+ <option value="deepseek/deepseek-r1:free">DeepSeek R1 (Free) ($0/1M input, $0/1M output, 163K context)</option>
287
+ <option value="deepseek/deepseek-r1">DeepSeek R1 ($0.45/1M input, $2.15/1M output, 128K context)</option>
288
+ <option value="deepseek/deepseek-chat:free">DeepSeek V3 (Free) ($0/1M input, $0/1M output, 163K context)</option>
289
+ <option value="deepseek/deepseek-chat">DeepSeek V3 ($0.38/1M input, $0.89/1M output, 163K context)</option>
290
+ </optgroup>
291
+ <optgroup label="xAI Grok">
292
+ <option value="x-ai/grok-3-mini">Grok 3 Mini ($0.30/1M input, $0.50/1M output, 131K context)</option>
293
+ <option value="x-ai/grok-3">Grok 3 ($3/1M input, $15/1M output, 131K context)</option>
294
+ <option value="x-ai/grok-3-mini-beta">Grok 3 Mini Beta ($0.30/1M input, $0.50/1M output, 131K context)</option>
295
+ <option value="x-ai/grok-3-beta">Grok 3 Beta ($3/1M input, $15/1M output, 131K context)</option>
296
+ <option value="x-ai/grok-2-vision-1212">Grok 2 Vision 1212 ($2/1M input, $10/1M output, 33K context)</option>
297
+ <option value="x-ai/grok-2-1212">Grok 2 1212 ($2/1M input, $10/1M output, 131K context)</option>
298
+ <option value="x-ai/grok-vision-beta">Grok Vision Beta ($5/1M input, $15/1M output, 8K context)</option>
299
+ </optgroup>
300
+
301
+ <optgroup label="Meta">
302
+ <option value="meta-llama/llama-4-maverick:free">Llama 4 Maverick (Free) ($0/1M input, $0/1M output, 128K context)</option>
303
+ <option value="meta-llama/llama-4-maverick">Llama 4 Maverick ($0.15/1M input, $0.60/1M output, 1M context)</option>
304
+ <option value="meta-llama/llama-4-scout:free">Llama 4 Scout (Free) ($0/1M input, $0/1M output, 64K context)</option>
305
+ <option value="meta-llama/llama-4-scout">Llama 4 Scout ($0.08/1M input, $0.30/1M output, 1M context)</option>
306
+ </optgroup>
307
+ </select>
308
+ </div>
309
+
310
+ <div class="form-row">
311
+ <label for="node-config-input-temperature"><i class="fa fa-thermometer-half"></i> Temperature</label>
312
+ <input type="range" id="node-config-input-temperature" min="0" max="2" step="0.1" style="width: 50%;">
313
+ <span id="temperature-value" style="margin-left: 10px;">0.7</span>
314
+ </div>
315
+
316
+ <div class="form-row">
317
+ <label for="node-config-input-maxTokens"><i class="fa fa-font"></i> Max Tokens</label>
318
+ <input type="number" id="node-config-input-maxTokens" min="1" max="4000" value="1000" style="width: 30%;">
319
+ </div>
320
+
321
+ <div class="form-tips">
322
+ <p><b>Note:</b> You'll need an OpenRouter API key to use AI models.</p>
323
+ </div>
324
+ </script>
325
+
326
+ <script type="text/x-red" data-help-name="ai-model">
327
+ <h3>AI Model Configuration</h3>
328
+ <p>Configure your AI model settings for use with AI Agent nodes.</p>
329
+
330
+ <h4>Configuration</h4>
331
+ <ul>
332
+ <li><b>Name:</b> A name for this configuration</li>
333
+ <li><b>OpenRouter API Key:</b> Your OpenRouter API key (required)</li>
334
+ <li><b>AI Model:</b> The AI model to use for generating responses</li>
335
+ <li><b>Temperature:</b> Controls randomness (0 = deterministic, 2 = very random)</li>
336
+ <li><b>Max Tokens:</b> Maximum number of tokens to generate in the response</li>
337
+ </ul>
338
+ </script>
@@ -0,0 +1,73 @@
1
+ module.exports = function(RED) {
2
+ function AiModelNode(config) {
3
+ RED.nodes.createNode(this, config);
4
+
5
+ // Store configuration
6
+ this.name = config.name;
7
+ this.model = config.model;
8
+ this.temperature = parseFloat(config.temperature) || 0.7;
9
+ this.maxTokens = parseInt(config.maxTokens) || 1000;
10
+
11
+ // Get credentials
12
+ this.credentials = this.credentials || {};
13
+
14
+ // Process incoming messages
15
+ this.on('input', function(msg, send, done) {
16
+ try {
17
+ // Validate configuration
18
+ if (!this.model) {
19
+ this.status({fill:"red", shape:"ring", text:"Error: No model selected"});
20
+ this.error("AI Model node error: No model selected. Please select a model in the node's configuration.", msg);
21
+ if (done) done();
22
+ return;
23
+ }
24
+
25
+ if (!this.credentials || !this.credentials.apiKey) {
26
+ this.status({fill:"red", shape:"ring", text:"Error: No API key"});
27
+ this.error("AI Model node error: No API key configured. Please add your OpenRouter API key in the node's configuration.", msg);
28
+ if (done) done();
29
+ return;
30
+ }
31
+
32
+ // Clone the message to avoid modifying the original
33
+ const newMsg = RED.util.cloneMessage(msg);
34
+
35
+ // Add AI configuration to the message
36
+ newMsg.aiagent = {
37
+ model: this.model,
38
+ apiKey: this.credentials.apiKey,
39
+ temperature: this.temperature,
40
+ maxTokens: this.maxTokens
41
+ };
42
+
43
+ // Update node status
44
+ this.status({fill:"green", shape:"dot", text:"Ready"});
45
+
46
+ // Send the modified message
47
+ send([newMsg, null]);
48
+
49
+ // Complete the async operation
50
+ if (done) {
51
+ done();
52
+ }
53
+ } catch (error) {
54
+ this.status({fill:"red", shape:"ring", text:"Error processing message"});
55
+ this.error("Error in AI Model node: " + error.message, msg);
56
+ if (done) done();
57
+ }
58
+ }.bind(this));
59
+
60
+ // Handle node cleanup
61
+ this.on('close', function(done) {
62
+ this.status({});
63
+ if (done) done();
64
+ });
65
+ }
66
+
67
+ // Register the node type
68
+ RED.nodes.registerType("ai-model", AiModelNode, {
69
+ credentials: {
70
+ apiKey: { type: "password" }
71
+ }
72
+ });
73
+ };
package/package.json CHANGED
@@ -1,36 +1,52 @@
1
- {
2
- "name": "node-red-contrib-ai-agent",
3
- "version": "0.0.1",
4
- "description": "AI Agent for Node-RED",
5
- "repository": {
6
- "type": "git",
7
- "url": "git@github.com:lesichkovm/node-red-contrib-ai-agent.git"
8
- },
9
- "keywords": [
10
- "ai",
11
- "agent",
12
- "node-red",
13
- "node-red-contrib",
14
- "node-red-contrib-ai-agent"
15
- ],
16
- "main": "ai-agent.js",
17
- "scripts": {
18
- "test": "echo \"Error: no test specified\" && exit 1"
19
- },
20
- "author": "Milan Lesichkov",
21
- "maintainers": [
22
- {
23
- "name": "Milan Lesichkov",
24
- "email": "lesichkovm@gmail.com"
25
- }
26
- ],
27
- "license": "MIT",
28
- "node-red": {
29
- "nodes": {
30
- "ai-agent": "ai-agent.js"
31
- }
32
- },
33
- "dependencies": {
34
- "knex": "^3.1.0"
35
- }
36
- }
1
+ {
2
+ "name": "node-red-contrib-ai-agent",
3
+ "version": "0.0.3",
4
+ "description": "AI Agent for Node-RED",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git@github.com:lesichkovm/node-red-contrib-ai-agent.git"
8
+ },
9
+ "keywords": [
10
+ "ai",
11
+ "agent",
12
+ "node-red",
13
+ "node-red-contrib",
14
+ "node-red-contrib-ai-agent"
15
+ ],
16
+ "main": "ai-agent.js",
17
+ "scripts": {
18
+ "test": "echo \"Error: no test specified\" && exit 1"
19
+ },
20
+ "author": "Milan Lesichkov",
21
+ "maintainers": [
22
+ {
23
+ "name": "Milan Lesichkov",
24
+ "email": "lesichkovm@gmail.com"
25
+ }
26
+ ],
27
+ "license": "AGPL-3.0",
28
+ "files": [
29
+ "agent/*",
30
+ "model/*",
31
+ "tool/*"
32
+ ],
33
+ "dependencies": {
34
+ "node-red": ">=1.0.0",
35
+ "axios": "^1.6.0"
36
+ },
37
+ "devDependencies": {
38
+ "eslint": "^8.0.0",
39
+ "prettier": "^3.0.0"
40
+ },
41
+ "engines": {
42
+ "node": ">=14.0.0"
43
+ },
44
+ "node-red": {
45
+ "version": ">=1.0.0",
46
+ "nodes": {
47
+ "ai-agent": "./agent/ai-agent.js",
48
+ "ai-model": "./model/ai-model.js",
49
+ "ai-tool": "./tool/ai-tool.js"
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
3
+ <rect x="10" y="10" width="80" height="80" rx="10" fill="#a6bbcf" stroke="#7a9cbc" stroke-width="2"/>
4
+ <path d="M30,30 L70,30 L70,50 L30,50 Z" fill="white" stroke="#5a7a99" stroke-width="2"/>
5
+ <path d="M40,60 L60,60 L60,70 L40,70 Z" fill="white" stroke="#5a7a99" stroke-width="2"/>
6
+ <path d="M30,35 L40,35" stroke="#5a7a99" stroke-width="2"/>
7
+ <path d="M30,45 L50,45" stroke="#5a7a99" stroke-width="2"/>
8
+ </svg>