@kumologica/sdk 3.6.3 → 3.6.4-beta3
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/cli/commands/run.js +4 -3
- package/package.json +5 -6
- package/src/app/lib/ai/chatai.js +206 -0
- package/src/app/preload.js +6 -0
- package/src/app/ui/editor-client/public/red/red.js +125 -1
- package/src/app/ui/editor-client/public/red/red.min.js +1 -1
- package/src/app/ui/editor-client/src/js/ui/aitab.js +90 -0
- package/src/app/ui/editor-client/src/js/ui/editor.js +115 -1
- package/src/app/ui/editor-client/src/js/ui/tray.js +10 -0
- package/cli/utils/fs/create-zip-file.js +0 -39
package/cli/commands/run.js
CHANGED
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
const path = require("path");
|
|
26
26
|
const fs = require("fs");
|
|
27
27
|
const { codegen } = require("@kumologica/builder");
|
|
28
|
-
const {
|
|
28
|
+
const { NodeJsTaskFlowBuilder} = require("../../src/builder/NodeJsTaskFlowBuilder");
|
|
29
|
+
//const { DesignerServer } = require("../../src/server/DesignerServer");
|
|
29
30
|
const { logError, logNotice, logInfo, logFatal } = require("../utils/logger");
|
|
30
31
|
|
|
31
32
|
exports.command = "run [project_directory]";
|
|
@@ -86,12 +87,12 @@ exports.handler = async ({ project_directory, loglevel, port, taskName, args })
|
|
|
86
87
|
};
|
|
87
88
|
|
|
88
89
|
// Start a server
|
|
89
|
-
let server = new
|
|
90
|
+
let server = new NodeJsTaskFlowBuilder({
|
|
90
91
|
flowPath: projectFlowFullPath,
|
|
91
92
|
cliParams,
|
|
92
93
|
});
|
|
93
94
|
|
|
94
|
-
await server.
|
|
95
|
+
await server.listen();
|
|
95
96
|
|
|
96
97
|
const tName = taskName || process.env.taskName;
|
|
97
98
|
const req = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kumologica/sdk",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.4-beta3",
|
|
4
4
|
"productName": "Kumologica Designer",
|
|
5
5
|
"copyright": "Copyright 2020 Kumologica Pty Ltd, All Rights Reserved.",
|
|
6
6
|
"author": "Kumologica Pty Ltd <contact@kumologica.com>",
|
|
@@ -83,10 +83,9 @@
|
|
|
83
83
|
"@aws-sdk/credential-providers": "^3.556.0",
|
|
84
84
|
"@aws-sdk/lib-dynamodb": "^3.549.0",
|
|
85
85
|
"@electron/remote": "^2.0.8",
|
|
86
|
-
"@kumologica/builder": "3.6.
|
|
87
|
-
"@kumologica/devkit": "3.6.
|
|
88
|
-
"@kumologica/runtime": "3.6.
|
|
89
|
-
"adm-zip": "0.4.13",
|
|
86
|
+
"@kumologica/builder": "3.6.4-beta3",
|
|
87
|
+
"@kumologica/devkit": "3.6.4-beta3",
|
|
88
|
+
"@kumologica/runtime": "3.6.4-beta3",
|
|
90
89
|
"ajv": "8.10.0",
|
|
91
90
|
"archive-type": "^4.0.0",
|
|
92
91
|
"basic-auth": "2.0.1",
|
|
@@ -178,7 +177,7 @@
|
|
|
178
177
|
"license-compatibility-checker": "^0.3.4",
|
|
179
178
|
"license-report": "^3.0.0",
|
|
180
179
|
"mocha": "10.2.0",
|
|
181
|
-
"node-sass": "
|
|
180
|
+
"node-sass": "9.0.0",
|
|
182
181
|
"tslint": "^5.18.0",
|
|
183
182
|
"typescript": "^3.5.3"
|
|
184
183
|
},
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chatAi(options)
|
|
3
|
+
*
|
|
4
|
+
* options: {
|
|
5
|
+
* provider: 'openai'|'anthropic'|'gemini'|'xai'|'deepseek',
|
|
6
|
+
* apiKey: string,
|
|
7
|
+
* model: string,
|
|
8
|
+
* conversation: [{ role: 'user'|'assistant'|'system', content: '...' }, ...],
|
|
9
|
+
* question: string,
|
|
10
|
+
* temperature?: number (0..1)
|
|
11
|
+
* }
|
|
12
|
+
*
|
|
13
|
+
* Returns: Promise<string> -> HTML snippet (string) ready to be inserted into the page.
|
|
14
|
+
*
|
|
15
|
+
* Requires: npm install node-fetch
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
const {
|
|
20
|
+
provider = "anthropic",
|
|
21
|
+
model = "claude-sonnet-4-20250514",
|
|
22
|
+
conversation = [],
|
|
23
|
+
question,
|
|
24
|
+
temperature = 0.2,
|
|
25
|
+
} = options;
|
|
26
|
+
|
|
27
|
+
*/
|
|
28
|
+
//async function chatAi(options) {
|
|
29
|
+
/**
|
|
30
|
+
* chatWithAI(options)
|
|
31
|
+
*
|
|
32
|
+
* options: {
|
|
33
|
+
* provider: 'openai'|'anthropic'|'gemini'|'xai'|'deepseek',
|
|
34
|
+
* apiKey: string,
|
|
35
|
+
* model: string,
|
|
36
|
+
* conversation: [{ role: 'user'|'assistant'|'system', content: '...' }, ...],
|
|
37
|
+
* question: string,
|
|
38
|
+
* temperature?: number (0..1)
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* Requires: npm install node-fetch
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
const fetch = require('node-fetch'); // Node 18+ can use global fetch
|
|
45
|
+
|
|
46
|
+
async function chatAi(options) {
|
|
47
|
+
const {
|
|
48
|
+
provider = "anthropic",
|
|
49
|
+
model = "claude-sonnet-4-20250514",
|
|
50
|
+
conversation = [],
|
|
51
|
+
question,
|
|
52
|
+
temperature = 0.2,
|
|
53
|
+
} = options;
|
|
54
|
+
|
|
55
|
+
if (!provider || !apiKey || !model) throw new Error('provider, apiKey and model are required');
|
|
56
|
+
if (!question) throw new Error('question is required');
|
|
57
|
+
|
|
58
|
+
const convo = conversation.slice();
|
|
59
|
+
convo.push({ role: 'user', content: question });
|
|
60
|
+
|
|
61
|
+
const makeOpenAIPayload = () => ({
|
|
62
|
+
model,
|
|
63
|
+
messages: convo.map(m => ({ role: m.role, content: m.content })),
|
|
64
|
+
temperature,
|
|
65
|
+
max_tokens: 1200,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const makeAnthropicPayload = () => ({
|
|
69
|
+
model,
|
|
70
|
+
max_tokens: 1200,
|
|
71
|
+
temperature,
|
|
72
|
+
messages: convo.map(m => ({ role: m.role, content: m.content })),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const makeGenericOpenAICompatiblePayload = () => ({
|
|
76
|
+
model,
|
|
77
|
+
messages: convo.map(m => ({ role: m.role, content: m.content })),
|
|
78
|
+
temperature,
|
|
79
|
+
max_tokens: 1200,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
let endpoint;
|
|
83
|
+
let body;
|
|
84
|
+
let headers = {};
|
|
85
|
+
|
|
86
|
+
if (provider === 'openai') {
|
|
87
|
+
endpoint = 'https://api.openai.com/v1/chat/completions';
|
|
88
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
89
|
+
headers['Content-Type'] = 'application/json';
|
|
90
|
+
body = JSON.stringify(makeOpenAIPayload());
|
|
91
|
+
|
|
92
|
+
} else if (provider === 'anthropic') {
|
|
93
|
+
endpoint = `https://api.anthropic.com/v1/messages`;
|
|
94
|
+
headers['x-api-key'] = apiKey;
|
|
95
|
+
headers['anthropic-version'] = '2023-06-01';
|
|
96
|
+
headers['Content-Type'] = 'application/json';
|
|
97
|
+
body = JSON.stringify(makeAnthropicPayload());
|
|
98
|
+
|
|
99
|
+
} else if (provider === 'gemini') {
|
|
100
|
+
endpoint = `https://api.generativeai.googleapis.com/v1/models/${encodeURIComponent(model)}:generate`;
|
|
101
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
102
|
+
headers['Content-Type'] = 'application/json';
|
|
103
|
+
body = JSON.stringify({
|
|
104
|
+
prompt: {
|
|
105
|
+
messages: convo.map(m => ({
|
|
106
|
+
author: m.role === 'user' ? 'user' : 'assistant',
|
|
107
|
+
content: [{ text: m.content }]
|
|
108
|
+
}))
|
|
109
|
+
},
|
|
110
|
+
temperature,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
} else if (provider === 'xai' || provider === 'x.ai' || provider === 'grok') {
|
|
114
|
+
endpoint = `https://api.x.ai/v1/chat/completions`;
|
|
115
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
116
|
+
headers['Content-Type'] = 'application/json';
|
|
117
|
+
body = JSON.stringify(makeGenericOpenAICompatiblePayload());
|
|
118
|
+
|
|
119
|
+
} else if (provider === 'deepseek' || provider === 'deepseekapi') {
|
|
120
|
+
endpoint = `https://api.deepseek.com/v1/chat/completions`;
|
|
121
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
122
|
+
headers['Content-Type'] = 'application/json';
|
|
123
|
+
body = JSON.stringify(makeGenericOpenAICompatiblePayload());
|
|
124
|
+
|
|
125
|
+
} else {
|
|
126
|
+
throw new Error('Unsupported provider: ' + provider);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const resp = await fetch(endpoint, { method: 'POST', headers, body });
|
|
130
|
+
if (!resp.ok) {
|
|
131
|
+
const text = await resp.text().catch(() => '');
|
|
132
|
+
throw new Error(`API error ${resp.status}: ${text}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const data = await resp.json();
|
|
136
|
+
|
|
137
|
+
console.log('Inside AI response:', data);
|
|
138
|
+
|
|
139
|
+
let assistantText = '';
|
|
140
|
+
if (data.choices && Array.isArray(data.choices) && data.choices[0]?.message?.content) {
|
|
141
|
+
assistantText = data.choices[0].message.content;
|
|
142
|
+
} else if (data.output_text) {
|
|
143
|
+
assistantText = data.output_text;
|
|
144
|
+
} else if (data.output && Array.isArray(data.output) && data.output[0]?.content) {
|
|
145
|
+
const cont = data.output[0].content;
|
|
146
|
+
if (Array.isArray(cont)) {
|
|
147
|
+
assistantText = cont.map(c => c.text || '').join('\n');
|
|
148
|
+
} else {
|
|
149
|
+
assistantText = (cont.text || '');
|
|
150
|
+
}
|
|
151
|
+
} else if (data.completion) {
|
|
152
|
+
assistantText = data.completion;
|
|
153
|
+
} else if (data.message?.content) {
|
|
154
|
+
assistantText = typeof data.message.content === 'string'
|
|
155
|
+
? data.message.content
|
|
156
|
+
: (data.message.content[0]?.text || '');
|
|
157
|
+
} else {
|
|
158
|
+
assistantText = JSON.stringify(data);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function escapeHtml(s) {
|
|
162
|
+
return s
|
|
163
|
+
.replace(/&/g, '&')
|
|
164
|
+
.replace(/</g, '<')
|
|
165
|
+
.replace(/>/g, '>')
|
|
166
|
+
.replace(/"/g, '"');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function renderMessageBlock(role, text) {
|
|
170
|
+
const fenceRe = /```([a-zA-Z0-9_-]*)\n([\s\S]*?)```/g;
|
|
171
|
+
let html = '';
|
|
172
|
+
let cursor = 0;
|
|
173
|
+
let m;
|
|
174
|
+
while ((m = fenceRe.exec(text)) !== null) {
|
|
175
|
+
const before = text.slice(cursor, m.index);
|
|
176
|
+
if (before.trim()) html += `<div class="body-text">${escapeHtml(before)}</div>`;
|
|
177
|
+
const lang = m[1] || 'text';
|
|
178
|
+
const code = m[2];
|
|
179
|
+
html += `<pre class="code-block"><code class="language-${escapeHtml(lang)}">${escapeHtml(code)}</code></pre>`;
|
|
180
|
+
cursor = m.index + m[0].length;
|
|
181
|
+
}
|
|
182
|
+
const tail = text.slice(cursor);
|
|
183
|
+
if (tail.trim()) html += `<div class="body-text">${escapeHtml(tail)}</div>`;
|
|
184
|
+
if (!html) html = '<div class="body-text"></div>';
|
|
185
|
+
return `<div class="msg role-${escapeHtml(role)}">
|
|
186
|
+
<h4 class="role">${escapeHtml(role)}</h4>
|
|
187
|
+
<div class="body">${html}</div>
|
|
188
|
+
</div>`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const fullConvo = convo.slice();
|
|
192
|
+
fullConvo.push({ role: 'assistant', content: assistantText });
|
|
193
|
+
const messageBlocks = fullConvo.map(m => renderMessageBlock(m.role, m.content)).join('\n');
|
|
194
|
+
|
|
195
|
+
const htmlSnippet = `
|
|
196
|
+
<div class="ai-chat-container" data-provider="${escapeHtml(provider)}" data-model="${escapeHtml(model)}">
|
|
197
|
+
<div class="ai-chat-messages">
|
|
198
|
+
${messageBlocks}
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
`;
|
|
202
|
+
|
|
203
|
+
return htmlSnippet;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports = { chatAi };
|
package/src/app/preload.js
CHANGED
|
@@ -37,6 +37,7 @@ const ProjectInfoConfig = require("./lib/stores/project-info-config-store");
|
|
|
37
37
|
const { CloudConfigStore } = require("./lib/stores/settings-cloud-store");
|
|
38
38
|
const { NetworkConfigStore } = require("./lib/stores/settings-network-store");
|
|
39
39
|
const { OpenAIClient } = require("./lib/ai/openai");
|
|
40
|
+
const { chatAi } = require("./lib/ai/chatai");
|
|
40
41
|
|
|
41
42
|
const AWSProfile = require("./lib/aws/aws-profile");
|
|
42
43
|
const AWSDeployer = require("./lib/aws");
|
|
@@ -580,6 +581,9 @@ function includeNodePathIntoPath() {
|
|
|
580
581
|
}
|
|
581
582
|
}
|
|
582
583
|
|
|
584
|
+
async function chatWithAi(conversation, question) {
|
|
585
|
+
await chatAi(conversation, question);
|
|
586
|
+
}
|
|
583
587
|
async function npmInstall(dependency) {
|
|
584
588
|
return new Promise((resolve, reject) => {
|
|
585
589
|
window.__kumologica.editor.terminal.eventEmitter.emit(
|
|
@@ -738,6 +742,8 @@ window.__kumologica.libs.simpleGit = simpleGit;
|
|
|
738
742
|
|
|
739
743
|
// AI utilities
|
|
740
744
|
window.__kumologica.libs.openAIClient = openAIClient;
|
|
745
|
+
window.__kumologica.libs.chatAi = chatWithAi;
|
|
746
|
+
|
|
741
747
|
|
|
742
748
|
/**
|
|
743
749
|
* Return the name of the valid kumologica flow or undefined otherwise.
|
|
@@ -31157,6 +31157,120 @@ RED.editor = (function () {
|
|
|
31157
31157
|
nodeInfoEditor = buildDescriptionForm(descriptionTab.content, node);
|
|
31158
31158
|
}
|
|
31159
31159
|
|
|
31160
|
+
// ...inside showEditDialog, after Help tab and before Notes tab...
|
|
31161
|
+
|
|
31162
|
+
// AI tab
|
|
31163
|
+
let aiTab = {
|
|
31164
|
+
id: 'editor-tab-ai',
|
|
31165
|
+
label: 'AI',
|
|
31166
|
+
name: 'AI',
|
|
31167
|
+
content: $('<div>', {
|
|
31168
|
+
class: 'editor-tray-content',
|
|
31169
|
+
id: 'ai-tab',
|
|
31170
|
+
css: { position: 'relative', height: '100%' }
|
|
31171
|
+
})
|
|
31172
|
+
.appendTo(editorContent)
|
|
31173
|
+
.hide(),
|
|
31174
|
+
iconClass: 'fa fa-magic',
|
|
31175
|
+
};
|
|
31176
|
+
|
|
31177
|
+
// List of text items (history/messages)
|
|
31178
|
+
const aiList = $('<div>', {
|
|
31179
|
+
id: 'ai-list',
|
|
31180
|
+
css: {
|
|
31181
|
+
'max-height': 'calc(100% - 120px)',
|
|
31182
|
+
'overflow-y': 'auto',
|
|
31183
|
+
'margin-bottom': '10px'
|
|
31184
|
+
}
|
|
31185
|
+
}).appendTo(aiTab.content);
|
|
31186
|
+
|
|
31187
|
+
// Text editor area
|
|
31188
|
+
const aiInputContainer = $('<div>', {
|
|
31189
|
+
css: {
|
|
31190
|
+
position: 'absolute',
|
|
31191
|
+
left: 0,
|
|
31192
|
+
right: 0,
|
|
31193
|
+
bottom: 0,
|
|
31194
|
+
padding: '10px',
|
|
31195
|
+
'background': '#f9f9f9',
|
|
31196
|
+
'box-shadow': '0 -1px 4px rgba(0,0,0,0.04)'
|
|
31197
|
+
}
|
|
31198
|
+
}).appendTo(aiTab.content);
|
|
31199
|
+
|
|
31200
|
+
const aiInput = $('<textarea>', {
|
|
31201
|
+
id: 'ai-input',
|
|
31202
|
+
rows: 3,
|
|
31203
|
+
css: {
|
|
31204
|
+
width: 'calc(100% - 110px)',
|
|
31205
|
+
resize: 'none',
|
|
31206
|
+
display: 'inline-block',
|
|
31207
|
+
verticalAlign: 'bottom'
|
|
31208
|
+
},
|
|
31209
|
+
placeholder: 'Type your AI prompt...'
|
|
31210
|
+
}).appendTo(aiInputContainer);
|
|
31211
|
+
|
|
31212
|
+
// Send button
|
|
31213
|
+
const aiSendBtn = $('<button>', {
|
|
31214
|
+
text: 'Send',
|
|
31215
|
+
class: 'editor-button primary',
|
|
31216
|
+
css: {
|
|
31217
|
+
float: 'right',
|
|
31218
|
+
marginLeft: '10px',
|
|
31219
|
+
width: '90px',
|
|
31220
|
+
height: '48px',
|
|
31221
|
+
position: 'relative',
|
|
31222
|
+
bottom: '0'
|
|
31223
|
+
}
|
|
31224
|
+
}).appendTo(aiInputContainer);
|
|
31225
|
+
|
|
31226
|
+
aiSendBtn.on('click', async function () {
|
|
31227
|
+
const val = aiInput.val().trim();
|
|
31228
|
+
if (val) {
|
|
31229
|
+
// Log the sent text to the console
|
|
31230
|
+
console.log('AI Tab Sent:', val);
|
|
31231
|
+
|
|
31232
|
+
|
|
31233
|
+
let res;
|
|
31234
|
+
|
|
31235
|
+
try {
|
|
31236
|
+
res = await window.__kumologica.libs.chatAi({conversation: [], question: val});
|
|
31237
|
+
console.log('AI Tab Response:', res);
|
|
31238
|
+
} catch (error) {
|
|
31239
|
+
console.log('AI Tab err:', error);
|
|
31240
|
+
res = error;
|
|
31241
|
+
}
|
|
31242
|
+
|
|
31243
|
+
// Add the original text to the list, aligned right
|
|
31244
|
+
$('<div>', {
|
|
31245
|
+
text: val,
|
|
31246
|
+
css: {
|
|
31247
|
+
padding: '6px 8px',
|
|
31248
|
+
margin: '2px 0',
|
|
31249
|
+
background: '#eaeaea',
|
|
31250
|
+
borderRadius: '4px',
|
|
31251
|
+
textAlign: 'right',
|
|
31252
|
+
display: 'flex',
|
|
31253
|
+
justifyContent: 'flex-end'
|
|
31254
|
+
}
|
|
31255
|
+
}).appendTo(aiList);
|
|
31256
|
+
|
|
31257
|
+
// Add the response text to the list, aligned left
|
|
31258
|
+
$('<div>', {
|
|
31259
|
+
text: 'Response to your text: ' + res,
|
|
31260
|
+
css: {
|
|
31261
|
+
padding: '6px 8px',
|
|
31262
|
+
margin: '2px 0',
|
|
31263
|
+
background: '#d0f5d8',
|
|
31264
|
+
borderRadius: '4px',
|
|
31265
|
+
textAlign: 'left'
|
|
31266
|
+
}
|
|
31267
|
+
}).appendTo(aiList);
|
|
31268
|
+
|
|
31269
|
+
aiInput.val('');
|
|
31270
|
+
}
|
|
31271
|
+
});
|
|
31272
|
+
// editorTabs.addTab(aiTab);
|
|
31273
|
+
|
|
31160
31274
|
var appearanceTab = {
|
|
31161
31275
|
id: 'editor-tab-appearance',
|
|
31162
31276
|
label: 'Appearance',
|
|
@@ -31407,7 +31521,7 @@ RED.editor = (function () {
|
|
|
31407
31521
|
'<option value="' +
|
|
31408
31522
|
ws.id +
|
|
31409
31523
|
'"' +
|
|
31410
|
-
|
|
31524
|
+
(ws.id == editing_config_node.z ? ' selected' : '') +
|
|
31411
31525
|
'></option>'
|
|
31412
31526
|
)
|
|
31413
31527
|
.text(workspaceLabel)
|
|
@@ -33814,10 +33928,12 @@ RED.eventLog = (function() {
|
|
|
33814
33928
|
$('#optionSettings').removeClass('node-property-selected');
|
|
33815
33929
|
$('#optionHelp').removeClass('node-property-selected');
|
|
33816
33930
|
$('#optionDocumentation').removeClass('node-property-selected');
|
|
33931
|
+
$('#optionAi').removeClass('node-property-selected');
|
|
33817
33932
|
|
|
33818
33933
|
$('#properties-tab').hide();
|
|
33819
33934
|
$('#help-tab').hide();
|
|
33820
33935
|
$('#documentation-tab').hide();
|
|
33936
|
+
$('#ai-tab').hide();
|
|
33821
33937
|
|
|
33822
33938
|
domEl.addClass('node-property-selected');
|
|
33823
33939
|
|
|
@@ -33831,6 +33947,9 @@ RED.eventLog = (function() {
|
|
|
33831
33947
|
case 'notes':
|
|
33832
33948
|
$('#documentation-tab').show();
|
|
33833
33949
|
break;
|
|
33950
|
+
case 'ai':
|
|
33951
|
+
$('#ai-tab').show();
|
|
33952
|
+
break;
|
|
33834
33953
|
}
|
|
33835
33954
|
}
|
|
33836
33955
|
|
|
@@ -33853,6 +33972,7 @@ RED.eventLog = (function() {
|
|
|
33853
33972
|
<div id="optionSettings" class="node-property-option node-property-selected">Settings</div>
|
|
33854
33973
|
<div id="optionHelp" class="node-property-option">Help</div>
|
|
33855
33974
|
<div id="optionDocumentation" class="node-property-option">Notes</div>
|
|
33975
|
+
<!--<div id="optionAi" class="node-property-option">AI</div>-->
|
|
33856
33976
|
</div>
|
|
33857
33977
|
`).appendTo(el);
|
|
33858
33978
|
}
|
|
@@ -34069,6 +34189,10 @@ RED.eventLog = (function() {
|
|
|
34069
34189
|
let $this = $(e.currentTarget);
|
|
34070
34190
|
selectOption($this, 'help');
|
|
34071
34191
|
});
|
|
34192
|
+
$('#optionAi').click((e) => {
|
|
34193
|
+
let $this = $(e.currentTarget);
|
|
34194
|
+
selectOption($this, 'ai');
|
|
34195
|
+
});
|
|
34072
34196
|
$('#optionDocumentation').click((e) => {
|
|
34073
34197
|
let $this = $(e.currentTarget);
|
|
34074
34198
|
selectOption($this, 'notes');
|