node-red-contrib-knx-ultimate 6.2.0 → 6.2.1
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 +5 -0
- package/examples/KNX AI - Telegrambot Direct Chat.json +18 -0
- package/nodes/knxUltimateAI.html +186 -76
- package/nodes/knxUltimateAI.js +477 -3
- package/nodes/locales/de/knxUltimateAI.html +43 -2
- package/nodes/locales/de/knxUltimateAI.json +27 -9
- package/nodes/locales/en/knxUltimateAI.html +47 -2
- package/nodes/locales/en/knxUltimateAI.json +27 -9
- package/nodes/locales/es/knxUltimateAI.html +43 -2
- package/nodes/locales/es/knxUltimateAI.json +27 -9
- package/nodes/locales/fr/knxUltimateAI.html +43 -2
- package/nodes/locales/fr/knxUltimateAI.json +27 -9
- package/nodes/locales/it/knxUltimateAI.html +47 -2
- package/nodes/locales/it/knxUltimateAI.json +27 -9
- package/nodes/locales/zh-CN/knxUltimateAI.html +43 -2
- package/nodes/locales/zh-CN/knxUltimateAI.json +27 -9
- package/nodes/utils/knxAiHomeMemory.js +507 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 6.2.1** - July 2026<br/>
|
|
10
|
+
|
|
11
|
+
- **KNX AI — bounded proactive home intelligence**: added an opt-in **Proactive home & memory** section that derives a multilingual semantic model from ETS hierarchy, names, roles and DPTs and can proactively report reliably recognized covers, windows or doors left open beyond a configurable threshold. Notifications use output 3 with `msg.knxAi.type = "proactive_notification"`, retain the Telegram recipient through `msg.inputMessage`, obey quiet hours, a per-object cooldown and a maximum of three messages per hour, and never emit autonomous KNX commands on output 4. The LLM treats the user-only **AI Education** text as authoritative when deciding whether a candidate notification is useful; if Education cannot be evaluated, the notification is suppressed. A Markdown home reference is loaded at Node-RED startup, updated atomically and periodically, cleans stale temporary files, and is limited to 64–1,024 KB (256 KB by default), 120 significant observations, 80 aggregate habits, 80 notification records and 300 semantic ETS objects; older low-priority entries are pruned before the hard file limit can be exceeded. The direct Telegram example demonstrates the bounded memory and proactive settings.<br/>
|
|
12
|
+
- **KNX AI — clearer accordion editor and practical guidance**: replaced the crowded vertical tabs with three main accordion sections: **AI assistant**, **Conversations & home**, and **KNX traffic analysis**. Opening one section shows all related options together, with no nested tabs or hidden advanced details and no changes to persisted field IDs or values. Help and wiki documentation in every supported language now include realistic values for recipient, threshold, quiet hours, cooldown and memory, a copyable **AI Education** example, expected proactive/suppressed outcomes, and the KNX safety boundaries.<br/>
|
|
13
|
+
|
|
9
14
|
**Version 6.2.0** - July 2026<br/>
|
|
10
15
|
|
|
11
16
|
- **KNX AI — DPT 1 command payload normalization**: fixed actuator writes being rejected when an otherwise valid AI response represented a DPT 1.xxx value as numeric `1`/`0` (including quoted values) instead of a JSON boolean. Exact safe equivalents `true`/`false`, `1`/`0`, `on`/`off` and ETS value labels are now normalized to real booleans before local validation, confirmation and Universal Mode output; other numeric values remain rejected.<br/>
|
|
@@ -26,6 +26,16 @@
|
|
|
26
26
|
"y": 80,
|
|
27
27
|
"wires": []
|
|
28
28
|
},
|
|
29
|
+
{
|
|
30
|
+
"id": "comment_knx_ai_home_intelligence",
|
|
31
|
+
"type": "comment",
|
|
32
|
+
"z": "tab_knx_ai_telegram",
|
|
33
|
+
"name": "3. Home intelligence: bounded memory + proactive cover notifications",
|
|
34
|
+
"info": "This example enables proactive notifications after 120 minutes, outside 23:00-07:00. The most recent Telegram chat becomes the recipient. AI Education remains user-managed, and the Markdown memory file has a hard 256 KB limit. Proactive observations use output 3 only and never write to KNX.",
|
|
35
|
+
"x": 520,
|
|
36
|
+
"y": 120,
|
|
37
|
+
"wires": []
|
|
38
|
+
},
|
|
29
39
|
{
|
|
30
40
|
"id": "telegram_receiver_knx_ai",
|
|
31
41
|
"type": "telegram receiver",
|
|
@@ -98,6 +108,14 @@
|
|
|
98
108
|
"chatAdapterPreset": "none",
|
|
99
109
|
"chatInputCode": "",
|
|
100
110
|
"chatOutputCode": "",
|
|
111
|
+
"proactiveEnabled": true,
|
|
112
|
+
"proactiveRecipient": "",
|
|
113
|
+
"proactiveOpenMinutes": "120",
|
|
114
|
+
"proactiveCooldownMinutes": "360",
|
|
115
|
+
"proactiveQuietStart": "23:00",
|
|
116
|
+
"proactiveQuietEnd": "07:00",
|
|
117
|
+
"homeMemoryMaxKb": "256",
|
|
118
|
+
"aiEducation": "Avvisami se una persiana, una finestra o una porta rimane aperta insolitamente a lungo. Non inviare notifiche durante le ore silenziose configurate.",
|
|
101
119
|
"x": 500,
|
|
102
120
|
"y": 210,
|
|
103
121
|
"wires": [
|
package/nodes/knxUltimateAI.html
CHANGED
|
@@ -40,6 +40,59 @@
|
|
|
40
40
|
line-height: 1.4;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
#knx-ai-accordion {
|
|
44
|
+
margin-top: 12px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#knx-ai-accordion>h3 {
|
|
48
|
+
margin-top: 6px;
|
|
49
|
+
font-size: 14px;
|
|
50
|
+
font-weight: 600;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#knx-ai-accordion>.ui-accordion-content {
|
|
54
|
+
padding: 14px 16px;
|
|
55
|
+
overflow: visible;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
#knx-ai-accordion .knx-ai-accordion-subsection {
|
|
59
|
+
padding: 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#knx-ai-accordion .knx-ai-accordion-subsection+.knx-ai-accordion-subsection {
|
|
63
|
+
margin-top: 18px;
|
|
64
|
+
padding-top: 16px;
|
|
65
|
+
border-top: 1px solid var(--red-ui-form-input-border-color, #ccc);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
#knx-ai-accordion .knx-ai-accordion-subsection>h4 {
|
|
69
|
+
margin: 0 0 14px;
|
|
70
|
+
color: var(--red-ui-primary-text-color, #555);
|
|
71
|
+
font-size: 14px;
|
|
72
|
+
font-weight: 600;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#knx-ai-accordion .knx-ai-accordion-subsection>h4 i {
|
|
76
|
+
width: 18px;
|
|
77
|
+
text-align: center;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
#knx-ai-accordion .knx-ai-inline-subsection {
|
|
81
|
+
margin-top: 18px;
|
|
82
|
+
padding-top: 14px;
|
|
83
|
+
border-top: 1px dashed var(--red-ui-form-input-border-color, #ccc);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
#knx-ai-accordion .knx-ai-inline-subsection>h5 {
|
|
87
|
+
margin: 0 0 12px;
|
|
88
|
+
font-size: 13px;
|
|
89
|
+
font-weight: 600;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#knx-ai-accordion .knx-ai-accordion-mount>div {
|
|
93
|
+
display: block;
|
|
94
|
+
}
|
|
95
|
+
|
|
43
96
|
#knx-ai-ollama-steps,
|
|
44
97
|
#knx-ai-ollama-empty-help {
|
|
45
98
|
margin-left: 290px;
|
|
@@ -109,7 +162,15 @@
|
|
|
109
162
|
llmRequireCommandConfirmation: { value: true },
|
|
110
163
|
chatAdapterPreset: { value: "none" },
|
|
111
164
|
chatInputCode: { value: "" },
|
|
112
|
-
chatOutputCode: { value: "" }
|
|
165
|
+
chatOutputCode: { value: "" },
|
|
166
|
+
proactiveEnabled: { value: false },
|
|
167
|
+
proactiveRecipient: { value: "" },
|
|
168
|
+
proactiveOpenMinutes: { value: 120, required: true, validate: RED.validators.number() },
|
|
169
|
+
proactiveCooldownMinutes: { value: 360, required: true, validate: RED.validators.number() },
|
|
170
|
+
proactiveQuietStart: { value: "23:00" },
|
|
171
|
+
proactiveQuietEnd: { value: "07:00" },
|
|
172
|
+
homeMemoryMaxKb: { value: 256, required: true, validate: RED.validators.number() },
|
|
173
|
+
aiEducation: { value: "" }
|
|
113
174
|
},
|
|
114
175
|
credentials: {
|
|
115
176
|
llmApiKey: { type: "password" }
|
|
@@ -139,71 +200,25 @@
|
|
|
139
200
|
const OLLAMA_DEFAULT_MODEL = "llama3.1";
|
|
140
201
|
const ANTHROPIC_DEFAULT_MODEL = "claude-opus-4-8";
|
|
141
202
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
$(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
width: 100%;
|
|
162
|
-
margin: 0 0 2px 0;
|
|
163
|
-
}
|
|
164
|
-
.hue-vertical-tabs > ul.ui-tabs-nav li a {
|
|
165
|
-
display: block;
|
|
166
|
-
width: 100%;
|
|
167
|
-
white-space: normal;
|
|
168
|
-
position: relative;
|
|
169
|
-
border-bottom: none !important;
|
|
170
|
-
}
|
|
171
|
-
.hue-vertical-tabs > ul.ui-tabs-nav li.ui-tabs-active {
|
|
172
|
-
border-bottom: none !important;
|
|
173
|
-
}
|
|
174
|
-
.hue-vertical-tabs > ul.ui-tabs-nav li.ui-tabs-active a::after {
|
|
175
|
-
content: "";
|
|
176
|
-
position: absolute;
|
|
177
|
-
left: 0;
|
|
178
|
-
bottom: 0;
|
|
179
|
-
width: 50%;
|
|
180
|
-
height: 3px;
|
|
181
|
-
background: currentColor;
|
|
182
|
-
}
|
|
183
|
-
.hue-vertical-tabs .ui-tabs-panel {
|
|
184
|
-
flex: 1;
|
|
185
|
-
padding: 0.8em 1em;
|
|
186
|
-
box-sizing: border-box;
|
|
187
|
-
border: none;
|
|
188
|
-
background: transparent;
|
|
189
|
-
}
|
|
190
|
-
.hue-vertical-tabs .form-row > dt {
|
|
191
|
-
flex: 1 1 auto;
|
|
192
|
-
margin: 0;
|
|
193
|
-
}
|
|
194
|
-
.hue-vertical-tabs hr {
|
|
195
|
-
width: 100%;
|
|
196
|
-
border: 0;
|
|
197
|
-
border-top: 1px solid #ccc;
|
|
198
|
-
margin: 8px 0;
|
|
199
|
-
}
|
|
200
|
-
</style>`);
|
|
201
|
-
}
|
|
202
|
-
const $tabs = $("#knx-ai-tabs");
|
|
203
|
-
$tabs.addClass("hue-vertical-tabs");
|
|
204
|
-
$tabs.tabs();
|
|
205
|
-
$tabs.find("ul").addClass("ui-tabs-nav");
|
|
206
|
-
$tabs.find("li").removeClass("ui-corner-top").addClass("ui-corner-left");
|
|
203
|
+
const mountAccordionSection = (mountSelector, sectionSelector) => {
|
|
204
|
+
const $mount = $(mountSelector);
|
|
205
|
+
const $section = $(sectionSelector);
|
|
206
|
+
if ($mount.length && $section.length) $mount.append($section);
|
|
207
|
+
};
|
|
208
|
+
mountAccordionSection("#knx-ai-mount-assistant-setup", "#knx-ai-tab-llm-connection");
|
|
209
|
+
mountAccordionSection("#knx-ai-mount-assistant-context", "#knx-ai-tab-llm-context");
|
|
210
|
+
mountAccordionSection("#knx-ai-mount-assistant-advanced", "#knx-ai-tab-advanced");
|
|
211
|
+
mountAccordionSection("#knx-ai-mount-chat-adapter", "#knx-ai-tab-chat-adapter");
|
|
212
|
+
mountAccordionSection("#knx-ai-mount-home-intelligence", "#knx-ai-tab-home-intelligence");
|
|
213
|
+
mountAccordionSection("#knx-ai-mount-knx-capture", "#knx-ai-tab-capture");
|
|
214
|
+
mountAccordionSection("#knx-ai-mount-knx-storage", "#knx-ai-tab-storage");
|
|
215
|
+
mountAccordionSection("#knx-ai-mount-knx-detection", "#knx-ai-tab-detection");
|
|
216
|
+
$("#knx-ai-accordion").accordion({
|
|
217
|
+
active: 0,
|
|
218
|
+
animate: false,
|
|
219
|
+
collapsible: true,
|
|
220
|
+
heightStyle: "content"
|
|
221
|
+
});
|
|
207
222
|
|
|
208
223
|
const toggleLLM = () => {
|
|
209
224
|
const enabled = $("#node-input-llmEnabled").is(":checked");
|
|
@@ -300,6 +315,13 @@
|
|
|
300
315
|
};
|
|
301
316
|
configureChatAdapterPicker.call(this);
|
|
302
317
|
|
|
318
|
+
const updateProactiveVisibility = () => {
|
|
319
|
+
const enabled = $("#node-input-proactiveEnabled").is(":checked");
|
|
320
|
+
$("#knx-ai-proactive-settings").toggle(enabled);
|
|
321
|
+
};
|
|
322
|
+
$("#node-input-proactiveEnabled").on("change", updateProactiveVisibility);
|
|
323
|
+
updateProactiveVisibility();
|
|
324
|
+
|
|
303
325
|
$("#knx-ai-open-web-page-vue").on("click", function (evt) {
|
|
304
326
|
evt.preventDefault();
|
|
305
327
|
const adminRoot = resolveAdminRoot();
|
|
@@ -544,16 +566,53 @@
|
|
|
544
566
|
</div>
|
|
545
567
|
</div>
|
|
546
568
|
|
|
547
|
-
<div id="knx-ai-
|
|
548
|
-
<
|
|
549
|
-
|
|
550
|
-
<
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
<
|
|
555
|
-
|
|
556
|
-
|
|
569
|
+
<div id="knx-ai-accordion">
|
|
570
|
+
<h3><i class="fa fa-magic"></i> <span data-i18n="knxUltimateAI.sections.groupAssistant"></span></h3>
|
|
571
|
+
<div>
|
|
572
|
+
<div class="knx-ai-accordion-subsection">
|
|
573
|
+
<h4><i class="fa fa-cog"></i> <span data-i18n="knxUltimateAI.sections.quickSetup"></span></h4>
|
|
574
|
+
<div class="knx-ai-accordion-mount" id="knx-ai-mount-assistant-setup"></div>
|
|
575
|
+
</div>
|
|
576
|
+
<div class="knx-ai-accordion-subsection">
|
|
577
|
+
<h4><i class="fa fa-book"></i> <span data-i18n="knxUltimateAI.sections.llmContext"></span></h4>
|
|
578
|
+
<div class="knx-ai-accordion-mount" id="knx-ai-mount-assistant-context"></div>
|
|
579
|
+
</div>
|
|
580
|
+
<div class="knx-ai-accordion-subsection">
|
|
581
|
+
<h4><i class="fa fa-sliders"></i> <span data-i18n="knxUltimateAI.sections.advanced"></span></h4>
|
|
582
|
+
<div class="knx-ai-accordion-mount" id="knx-ai-mount-assistant-advanced"></div>
|
|
583
|
+
</div>
|
|
584
|
+
</div>
|
|
585
|
+
|
|
586
|
+
<h3><i class="fa fa-comments"></i> <span data-i18n="knxUltimateAI.sections.groupChatHome"></span></h3>
|
|
587
|
+
<div>
|
|
588
|
+
<div class="knx-ai-accordion-subsection">
|
|
589
|
+
<h4><i class="fa fa-plug"></i> <span data-i18n="knxUltimateAI.sections.chatAdapter"></span></h4>
|
|
590
|
+
<div class="knx-ai-accordion-mount" id="knx-ai-mount-chat-adapter"></div>
|
|
591
|
+
</div>
|
|
592
|
+
<div class="knx-ai-accordion-subsection">
|
|
593
|
+
<h4><i class="fa fa-home"></i> <span data-i18n="knxUltimateAI.sections.homeIntelligence"></span></h4>
|
|
594
|
+
<div class="knx-ai-accordion-mount" id="knx-ai-mount-home-intelligence"></div>
|
|
595
|
+
</div>
|
|
596
|
+
</div>
|
|
597
|
+
|
|
598
|
+
<h3><i class="fa fa-exchange"></i> <span data-i18n="knxUltimateAI.sections.groupKnxAnalysis"></span></h3>
|
|
599
|
+
<div>
|
|
600
|
+
<div class="knx-ai-accordion-subsection">
|
|
601
|
+
<h4><i class="fa fa-sign-in"></i> <span data-i18n="knxUltimateAI.sections.capture"></span></h4>
|
|
602
|
+
<div class="knx-ai-accordion-mount" id="knx-ai-mount-knx-capture"></div>
|
|
603
|
+
</div>
|
|
604
|
+
<div class="knx-ai-accordion-subsection">
|
|
605
|
+
<h4><i class="fa fa-database"></i> <span data-i18n="knxUltimateAI.sections.storage"></span></h4>
|
|
606
|
+
<div class="knx-ai-accordion-mount" id="knx-ai-mount-knx-storage"></div>
|
|
607
|
+
</div>
|
|
608
|
+
<div class="knx-ai-accordion-subsection">
|
|
609
|
+
<h4><i class="fa fa-search"></i> <span data-i18n="knxUltimateAI.sections.detection"></span></h4>
|
|
610
|
+
<div class="knx-ai-accordion-mount" id="knx-ai-mount-knx-detection"></div>
|
|
611
|
+
</div>
|
|
612
|
+
</div>
|
|
613
|
+
</div>
|
|
614
|
+
|
|
615
|
+
<div id="knx-ai-accordion-source" style="display:none;">
|
|
557
616
|
|
|
558
617
|
<div id="knx-ai-tab-capture">
|
|
559
618
|
<div class="form-row">
|
|
@@ -699,6 +758,57 @@
|
|
|
699
758
|
</div>
|
|
700
759
|
</div>
|
|
701
760
|
|
|
761
|
+
<div id="knx-ai-tab-home-intelligence">
|
|
762
|
+
<div class="form-tips" style="margin-bottom:12px;">
|
|
763
|
+
<span data-i18n="knxUltimateAI.messages.homeIntelligenceIntro"></span>
|
|
764
|
+
</div>
|
|
765
|
+
<div class="form-row">
|
|
766
|
+
<input type="checkbox" id="node-input-proactiveEnabled" style="display:inline-block; width:auto; vertical-align:top;">
|
|
767
|
+
<label style="width:auto" for="node-input-proactiveEnabled"> <span data-i18n="knxUltimateAI.properties.proactiveEnabled"></span></label>
|
|
768
|
+
</div>
|
|
769
|
+
<div id="knx-ai-proactive-settings">
|
|
770
|
+
<div class="form-row">
|
|
771
|
+
<label style="width:290px" for="node-input-proactiveRecipient"><i class="fa fa-user"></i> <span data-i18n="knxUltimateAI.properties.proactiveRecipient"></span></label>
|
|
772
|
+
<input style="width:100%" type="text" id="node-input-proactiveRecipient" data-i18n="[placeholder]knxUltimateAI.placeholder.proactiveRecipient">
|
|
773
|
+
</div>
|
|
774
|
+
<div class="form-row">
|
|
775
|
+
<label style="width:290px" for="node-input-proactiveOpenMinutes"><i class="fa fa-clock-o"></i> <span data-i18n="knxUltimateAI.properties.proactiveOpenMinutes"></span></label>
|
|
776
|
+
<input style="width:100px" type="number" min="1" max="1440" id="node-input-proactiveOpenMinutes">
|
|
777
|
+
</div>
|
|
778
|
+
<div class="form-row">
|
|
779
|
+
<label style="width:290px" for="node-input-proactiveQuietStart"><i class="fa fa-moon-o"></i> <span data-i18n="knxUltimateAI.properties.proactiveQuietStart"></span></label>
|
|
780
|
+
<input style="width:120px" type="time" id="node-input-proactiveQuietStart">
|
|
781
|
+
</div>
|
|
782
|
+
<div class="form-row">
|
|
783
|
+
<label style="width:290px" for="node-input-proactiveQuietEnd"><i class="fa fa-sun-o"></i> <span data-i18n="knxUltimateAI.properties.proactiveQuietEnd"></span></label>
|
|
784
|
+
<input style="width:120px" type="time" id="node-input-proactiveQuietEnd">
|
|
785
|
+
</div>
|
|
786
|
+
</div>
|
|
787
|
+
<div class="form-row" style="margin-top:14px;">
|
|
788
|
+
<label style="width:100%" for="node-input-aiEducation"><i class="fa fa-graduation-cap"></i> <span data-i18n="knxUltimateAI.properties.aiEducation"></span></label>
|
|
789
|
+
<textarea id="node-input-aiEducation" maxlength="16000" style="width:100%; min-height:180px; box-sizing:border-box;" data-i18n="[placeholder]knxUltimateAI.placeholder.aiEducation"></textarea>
|
|
790
|
+
</div>
|
|
791
|
+
<div class="form-tips" style="margin-bottom:12px;">
|
|
792
|
+
<span data-i18n="knxUltimateAI.messages.aiEducationHelp"></span>
|
|
793
|
+
</div>
|
|
794
|
+
<div class="knx-ai-inline-subsection">
|
|
795
|
+
<h5><i class="fa fa-sliders"></i> <span data-i18n="knxUltimateAI.sections.homeIntelligenceAdvanced"></span></h5>
|
|
796
|
+
<div>
|
|
797
|
+
<div class="form-row">
|
|
798
|
+
<label style="width:290px" for="node-input-proactiveCooldownMinutes"><i class="fa fa-bell-slash-o"></i> <span data-i18n="knxUltimateAI.properties.proactiveCooldownMinutes"></span></label>
|
|
799
|
+
<input style="width:100px" type="number" min="5" max="10080" id="node-input-proactiveCooldownMinutes">
|
|
800
|
+
</div>
|
|
801
|
+
<div class="form-row">
|
|
802
|
+
<label style="width:290px" for="node-input-homeMemoryMaxKb"><i class="fa fa-hdd-o"></i> <span data-i18n="knxUltimateAI.properties.homeMemoryMaxKb"></span></label>
|
|
803
|
+
<input style="width:100px" type="number" min="64" max="1024" id="node-input-homeMemoryMaxKb">
|
|
804
|
+
</div>
|
|
805
|
+
<div class="form-tips">
|
|
806
|
+
<span data-i18n="knxUltimateAI.messages.homeMemoryLimitHelp"></span>
|
|
807
|
+
</div>
|
|
808
|
+
</div>
|
|
809
|
+
</div>
|
|
810
|
+
</div>
|
|
811
|
+
|
|
702
812
|
<div id="knx-ai-tab-llm-context">
|
|
703
813
|
<div id="knx-ai-llm-context-settings">
|
|
704
814
|
<div class="form-row">
|