@flowfuse/nr-assistant 0.3.1-92d1581-202507160925.0 → 0.4.1-429f18d-202508261332.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/CHANGELOG.md +58 -0
- package/index.html +109 -1
- package/lib/assistant.js +5 -12
- package/lib/settings.js +22 -0
- package/package.json +5 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
### 0.4.0
|
|
2
|
+
- update package for 0.4.0 release
|
|
3
|
+
- Bump flowfuse/github-actions-workflows from 0.39.0 to 0.40.0 (#60)
|
|
4
|
+
- Update imports (#64) @Steve-Mcl
|
|
5
|
+
- Implement node suggestions (#62) @Steve-Mcl
|
|
6
|
+
- Add copy to clipboard and generate comment node to explain dialog (#61) @Steve-Mcl
|
|
7
|
+
|
|
8
|
+
### 0.3.0
|
|
9
|
+
- Change assistant button to menu for exposing new Flows Explainer by @Steve-Mcl in #53
|
|
10
|
+
- Add menu shortcuts for menu items by @Steve-Mcl in #54
|
|
11
|
+
- Show flow explanation in dialog by @Steve-Mcl in #52
|
|
12
|
+
- Add codelens for CSS and DB2 ui-template by @Steve-Mcl in #56
|
|
13
|
+
|
|
14
|
+
### 0.2.1
|
|
15
|
+
- Improve README with visuals of what it does by @Steve-Mcl in #49
|
|
16
|
+
- V0.2.1 by @Steve-Mcl in #50
|
|
17
|
+
|
|
18
|
+
### 0.2.0
|
|
19
|
+
|
|
20
|
+
- Bump flowfuse/github-actions-workflows from 0.19.0 to 0.28.0 by @dependabot in #32
|
|
21
|
+
- Bump flowfuse/github-actions-workflows from 0.28.0 to 0.29.0 by @dependabot in #33
|
|
22
|
+
- Bump flowfuse/github-actions-workflows from 0.29.0 to 0.30.0 by @dependabot in #34
|
|
23
|
+
- Bump flowfuse/github-actions-workflows from 0.30.0 to 0.34.0 by @dependabot in #35
|
|
24
|
+
- Bump flowfuse/github-actions-workflows from 0.34.0 to 0.36.0 by @dependabot in #36
|
|
25
|
+
- Bump flowfuse/github-actions-workflows from 0.36.0 to 0.38.0 by @dependabot in #38
|
|
26
|
+
- Clarify usage restriction of the plugin by @knolleary in #39
|
|
27
|
+
- chore: Pin external actions to commit hash by @ppawlowski in #40
|
|
28
|
+
- chore: fix lint script by @ppawlowski in #41
|
|
29
|
+
- Bump actions/setup-node from 4.3.0 to 4.4.0 by @dependabot in #42
|
|
30
|
+
- Add initial MCP support by @Steve-Mcl in #44
|
|
31
|
+
- V0.2.0 by @Steve-Mcl in #47
|
|
32
|
+
|
|
33
|
+
### 0.1.3
|
|
34
|
+
|
|
35
|
+
- Fix icon on device agent by @Steve-Mcl in #29
|
|
36
|
+
- bump for 0.1.3 by @Steve-Mcl in #30
|
|
37
|
+
|
|
38
|
+
### 0.1.2
|
|
39
|
+
|
|
40
|
+
- Fix height of new icon on NR3.x by @Steve-Mcl in #26
|
|
41
|
+
- bump for 0.1.2 by @Steve-Mcl in #27
|
|
42
|
+
|
|
43
|
+
### 0.1.1
|
|
44
|
+
|
|
45
|
+
- ci: Add build and publish nightly package workflow by @ppawlowski in #7
|
|
46
|
+
- Bump tibdex/github-app-token from 1 to 2 by @dependabot in #11
|
|
47
|
+
- Add JSON editor code lens by @Steve-Mcl in #14
|
|
48
|
+
- Correct handling of locked flows by @Steve-Mcl in #17
|
|
49
|
+
- Update package.json for version bump release by @Steve-Mcl in #20
|
|
50
|
+
- add custom icon to toolbar button by @Steve-Mcl in #21
|
|
51
|
+
- Add comma to settings.js by @kazuhitoyokoi in #22
|
|
52
|
+
- Improved messaging for error responses by @Steve-Mcl in #24
|
|
53
|
+
|
|
54
|
+
### 0.1.0
|
|
55
|
+
|
|
56
|
+
- add automations by @Steve-Mcl in #1
|
|
57
|
+
- Bump JS-DevTools/npm-publish from 2 to 3 by @dependabot in #5
|
|
58
|
+
- Wording and layout improvements prior to first release by @Steve-Mcl in #8
|
package/index.html
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
const modulesAllowed = RED.settings.functionExternalModules !== false
|
|
25
25
|
const assistantOptions = {
|
|
26
26
|
enabled: false,
|
|
27
|
+
tablesEnabled: false,
|
|
27
28
|
requestTimeout: AI_TIMEOUT
|
|
28
29
|
}
|
|
29
30
|
let assistantInitialised = false
|
|
@@ -42,6 +43,7 @@
|
|
|
42
43
|
if (topic === 'nr-assistant/initialise') {
|
|
43
44
|
assistantOptions.enabled = !!msg?.enabled
|
|
44
45
|
assistantOptions.requestTimeout = msg?.requestTimeout || AI_TIMEOUT
|
|
46
|
+
assistantOptions.tablesEnabled = msg?.tablesEnabled === true
|
|
45
47
|
initAssistant(msg)
|
|
46
48
|
RED.actions.add('flowfuse-nr-assistant:function-builder', showFunctionBuilderPrompt, { label: '@flowfuse/nr-assistant/flowfuse-nr-assistant:function-builder.action.label' })
|
|
47
49
|
setMenuShortcutKey('ff-assistant-function-builder', 'red-ui-workspace', 'ctrl-alt-f', 'flowfuse-nr-assistant:function-builder')
|
|
@@ -69,7 +71,7 @@
|
|
|
69
71
|
}
|
|
70
72
|
RED.plugins.registerPlugin('flowfuse-nr-assistant', plugin)
|
|
71
73
|
|
|
72
|
-
function initAssistant () {
|
|
74
|
+
function initAssistant (options) {
|
|
73
75
|
if (assistantInitialised) {
|
|
74
76
|
return
|
|
75
77
|
}
|
|
@@ -88,6 +90,7 @@
|
|
|
88
90
|
const jsonCommandId = 'nr-assistant-json-inline'
|
|
89
91
|
const cssCommandId = 'nr-assistant-css-inline'
|
|
90
92
|
const db2uiTemplateCommandId = 'nr-assistant-html-dashboard2-template-inline'
|
|
93
|
+
const ffTablesNodeCommandId = 'nr-assistant-ff-tables-node-inline'
|
|
91
94
|
|
|
92
95
|
debug('registering code lens providers...')
|
|
93
96
|
|
|
@@ -264,6 +267,48 @@
|
|
|
264
267
|
}
|
|
265
268
|
})
|
|
266
269
|
|
|
270
|
+
assistantOptions.tablesEnabled && monaco.languages.registerCodeLensProvider('sql', {
|
|
271
|
+
provideCodeLenses: function (model, token) {
|
|
272
|
+
debug('SQL CodeLens provider called', model, token)
|
|
273
|
+
const thisEditor = getMonacoEditorForModel(model)
|
|
274
|
+
if (!thisEditor) {
|
|
275
|
+
return
|
|
276
|
+
}
|
|
277
|
+
const node = RED.view.selection()?.nodes?.[0]
|
|
278
|
+
// only support tables query nodes for now
|
|
279
|
+
if (!node || node.type !== 'tables-query' || node._def?.set?.id !== '@flowfuse/nr-tables-nodes/tables-query') {
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
lenses: [
|
|
284
|
+
{
|
|
285
|
+
range: {
|
|
286
|
+
startLineNumber: 1,
|
|
287
|
+
startColumn: 1,
|
|
288
|
+
endLineNumber: 2,
|
|
289
|
+
endColumn: 1
|
|
290
|
+
},
|
|
291
|
+
id: ffTablesNodeCommandId
|
|
292
|
+
}
|
|
293
|
+
],
|
|
294
|
+
dispose: () => { }
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
resolveCodeLens: function (model, codeLens, token) {
|
|
298
|
+
debug('SQL CodeLens resolve called', model, codeLens, token)
|
|
299
|
+
if (codeLens.id !== ffTablesNodeCommandId) {
|
|
300
|
+
return codeLens
|
|
301
|
+
}
|
|
302
|
+
codeLens.command = {
|
|
303
|
+
id: codeLens.id,
|
|
304
|
+
title: 'Ask the FlowFuse Assistant 🪄',
|
|
305
|
+
tooltip: 'Click to ask FlowFuse Assistant for help with PostgreSQL',
|
|
306
|
+
arguments: [model, codeLens, token]
|
|
307
|
+
}
|
|
308
|
+
return codeLens
|
|
309
|
+
}
|
|
310
|
+
})
|
|
311
|
+
|
|
267
312
|
debug('registering commands...')
|
|
268
313
|
|
|
269
314
|
monaco.editor.registerCommand(funcCommandId, function (accessor, model, codeLens, token) {
|
|
@@ -581,6 +626,69 @@
|
|
|
581
626
|
}
|
|
582
627
|
})
|
|
583
628
|
|
|
629
|
+
assistantOptions.tablesEnabled && monaco.editor.registerCommand(ffTablesNodeCommandId, function (accessor, model, codeLens, token) {
|
|
630
|
+
debug('running command', ffTablesNodeCommandId)
|
|
631
|
+
const node = RED.view.selection()?.nodes?.[0]
|
|
632
|
+
if (!node) {
|
|
633
|
+
console.warn('No node selected') // should not happen
|
|
634
|
+
return
|
|
635
|
+
}
|
|
636
|
+
if (!assistantOptions.enabled) {
|
|
637
|
+
RED.notify(plugin._('errors.assistant-not-enabled'), 'warning')
|
|
638
|
+
return
|
|
639
|
+
}
|
|
640
|
+
const thisEditor = getMonacoEditorForModel(model)
|
|
641
|
+
if (thisEditor) {
|
|
642
|
+
if (!document.body.contains(thisEditor.getDomNode())) {
|
|
643
|
+
console.warn('Editor is no longer in the DOM, cannot proceed.')
|
|
644
|
+
return
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// FUTURE: for including selected text in the context for features like "fix my code", "refactor this", "what is this?" etc
|
|
648
|
+
// const userSelection = triggeredEditor.getSelection()
|
|
649
|
+
// const selectedText = model.getValueInRange(userSelection)
|
|
650
|
+
/** @type {PromptOptions} */
|
|
651
|
+
const promptOptions = {
|
|
652
|
+
method: 'flowfuse-tables-query',
|
|
653
|
+
lang: 'sql',
|
|
654
|
+
dialect: 'g',
|
|
655
|
+
type: node.type
|
|
656
|
+
// selectedText: model.getValueInRange(userSelection)
|
|
657
|
+
}
|
|
658
|
+
/** @type {PromptUIOptions} */
|
|
659
|
+
const uiOptions = {
|
|
660
|
+
title: 'FlowFuse Assistant : FlowFuse Query',
|
|
661
|
+
explanation: 'The FlowFuse Assistant can help you write SQL queries.',
|
|
662
|
+
description: 'Enter a short description of what you want it to do.'
|
|
663
|
+
}
|
|
664
|
+
doPrompt(node, thisEditor, promptOptions, uiOptions, (error, response) => {
|
|
665
|
+
if (error) {
|
|
666
|
+
console.warn('Error processing request', error)
|
|
667
|
+
return
|
|
668
|
+
}
|
|
669
|
+
debug('sql response', response)
|
|
670
|
+
const responseData = response?.data
|
|
671
|
+
if (responseData && responseData.sql) {
|
|
672
|
+
// ensure the editor is still present in the DOM
|
|
673
|
+
if (!document.body.contains(thisEditor.getDomNode())) {
|
|
674
|
+
console.warn('Editor is no longer in the DOM')
|
|
675
|
+
return
|
|
676
|
+
}
|
|
677
|
+
thisEditor.focus()
|
|
678
|
+
const currentSelection = thisEditor.getSelection()
|
|
679
|
+
thisEditor.executeEdits('', [
|
|
680
|
+
{
|
|
681
|
+
range: new monaco.Range(currentSelection.startLineNumber, currentSelection.startColumn, currentSelection.endLineNumber, currentSelection.endColumn),
|
|
682
|
+
text: responseData.sql
|
|
683
|
+
}
|
|
684
|
+
])
|
|
685
|
+
}
|
|
686
|
+
})
|
|
687
|
+
} else {
|
|
688
|
+
console.warn('Could not find editor for model', model.uri.toString())
|
|
689
|
+
}
|
|
690
|
+
})
|
|
691
|
+
|
|
584
692
|
const toolbarMenuButton = $('<li><a id="red-ui-header-button-ff-ai" class="button" href="#"></a></li>')
|
|
585
693
|
const toolbarMenuButtonAnchor = toolbarMenuButton.find('a')
|
|
586
694
|
const deployButtonLi = $('#red-ui-header-button-deploy').closest('li')
|
package/lib/assistant.js
CHANGED
|
@@ -6,20 +6,12 @@ const { getLongestUpstreamPath } = require('./flowGraph')
|
|
|
6
6
|
const { hasProperty } = require('./utils')
|
|
7
7
|
const semver = require('semver')
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// import typedef AssistantSettings
|
|
11
10
|
/**
|
|
12
|
-
* @typedef {
|
|
13
|
-
* @property {boolean} enabled - Whether the Assistant is enabled
|
|
14
|
-
* @property {number} requestTimeout - The timeout for requests to the Assistant backend in milliseconds
|
|
15
|
-
* @property {string} url - The URL of the Assistant server
|
|
16
|
-
* @property {string} token - The authentication token for the Assistant server
|
|
17
|
-
* @property {Object} [got] - The got instance to use for HTTP requests
|
|
18
|
-
* @property {Object} completions - Settings for completions
|
|
19
|
-
* @property {string} completions.modelUrl - The URL to the ML model
|
|
20
|
-
* @property {string} completions.vocabularyUrl - The URL to the completions vocabulary lookup data
|
|
11
|
+
* @typedef {import('./settings.js').AssistantSettings} AssistantSettings
|
|
21
12
|
*/
|
|
22
13
|
|
|
14
|
+
const FF_ASSISTANT_USER_AGENT = 'FlowFuse Assistant Plugin/' + require('../package.json').version
|
|
23
15
|
class Assistant {
|
|
24
16
|
constructor () {
|
|
25
17
|
// Main properties
|
|
@@ -70,7 +62,7 @@ class Assistant {
|
|
|
70
62
|
await this.dispose() // Dispose of any existing instance before initializing a new one
|
|
71
63
|
this.RED = RED
|
|
72
64
|
this.options = options || {}
|
|
73
|
-
this.got = this.options.got || require('got') // got can
|
|
65
|
+
this.got = this.options.got || require('got') // got can be passed in for testing purposes
|
|
74
66
|
|
|
75
67
|
if (!this.options.enabled) {
|
|
76
68
|
RED.log.info('FlowFuse Assistant Plugin is not enabled')
|
|
@@ -88,6 +80,7 @@ class Assistant {
|
|
|
88
80
|
|
|
89
81
|
const clientSettings = {
|
|
90
82
|
enabled: this.options.enabled !== false && !!this.options.url,
|
|
83
|
+
tablesEnabled: this.options.tables?.enabled === true,
|
|
91
84
|
requestTimeout: this.options.requestTimeout || 60000
|
|
92
85
|
}
|
|
93
86
|
RED.comms.publish('nr-assistant/initialise', clientSettings, true /* retain */)
|
package/lib/settings.js
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} AssistantSettings
|
|
3
|
+
* @property {boolean} enabled - Whether the Assistant is enabled
|
|
4
|
+
* @property {number} requestTimeout - The timeout for requests to the Assistant backend in milliseconds
|
|
5
|
+
* @property {string} url - The URL of the Assistant server
|
|
6
|
+
* @property {string} token - The authentication token for the Assistant server
|
|
7
|
+
* @property {Object} [got] - The got instance to use for HTTP requests
|
|
8
|
+
* @property {Object} completions - Settings for completions
|
|
9
|
+
* @property {string} completions.modelUrl - The URL to the ML model
|
|
10
|
+
* @property {string} completions.vocabularyUrl - The URL to the completions vocabulary lookup data
|
|
11
|
+
* @property {Object} tables - Settings for tables
|
|
12
|
+
* @property {Boolean} tables.enabled - Whether the tables feature is enabled
|
|
13
|
+
*/
|
|
14
|
+
|
|
1
15
|
module.exports = {
|
|
16
|
+
/**
|
|
17
|
+
* Get the Assistant settings from the RED instance.
|
|
18
|
+
* @param {Object} RED - The RED instance
|
|
19
|
+
* @returns {AssistantSettings} - The Assistant settings
|
|
20
|
+
*/
|
|
2
21
|
getSettings: (RED) => {
|
|
3
22
|
const assistantSettings = (RED.settings.flowforge && RED.settings.flowforge.assistant) || {}
|
|
4
23
|
if (assistantSettings.enabled !== true) {
|
|
@@ -13,6 +32,9 @@ module.exports = {
|
|
|
13
32
|
modelUrl: null,
|
|
14
33
|
vocabularyUrl: null
|
|
15
34
|
}
|
|
35
|
+
assistantSettings.tables = {
|
|
36
|
+
enabled: !!(RED.settings.flowforge?.tables?.token) // for MVP, use the presence of a token is an indicator that tables are enabled
|
|
37
|
+
}
|
|
16
38
|
return assistantSettings
|
|
17
39
|
}
|
|
18
40
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowfuse/nr-assistant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1-429f18d-202508261332.0",
|
|
4
4
|
"description": "FlowFuse Node-RED assistant plugin",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -37,9 +37,11 @@
|
|
|
37
37
|
"node": ">=16.x"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.17.0",
|
|
41
41
|
"got": "^11.8.6",
|
|
42
|
-
"onnxruntime-web": "^1.22.0"
|
|
42
|
+
"onnxruntime-web": "^1.22.0",
|
|
43
|
+
"semver": "^7.7.2",
|
|
44
|
+
"zod": "^3.25.76"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
45
47
|
"eslint": "^8.48.0",
|