node-red-contrib-knx-ultimate 6.3.21 → 6.3.22
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 +10 -0
- package/nodes/knxUltimateAI.html +78 -10
- package/nodes/knxUltimateAI.js +209 -94
- package/nodes/locales/de/knxUltimateAI.html +5 -3
- package/nodes/locales/de/knxUltimateAI.json +13 -3
- package/nodes/locales/en/knxUltimateAI.html +5 -3
- package/nodes/locales/en/knxUltimateAI.json +13 -3
- package/nodes/locales/es/knxUltimateAI.html +5 -3
- package/nodes/locales/es/knxUltimateAI.json +13 -3
- package/nodes/locales/fr/knxUltimateAI.html +5 -3
- package/nodes/locales/fr/knxUltimateAI.json +13 -3
- package/nodes/locales/it/knxUltimateAI.html +5 -3
- package/nodes/locales/it/knxUltimateAI.json +13 -3
- package/nodes/locales/zh-CN/knxUltimateAI.html +5 -3
- package/nodes/locales/zh-CN/knxUltimateAI.json +13 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 6.3.22** - August 2026<br/>
|
|
10
|
+
|
|
11
|
+
- **KNX AI — visible context size and real prompt weight**: the “Chat context overview” card now shows the current operational context limit and the actual UTF-8 size of the last operational chat prompt. Ollama, Bionic, OpenAI-compatible and Claude token-usage fields are captured when returned by the provider; otherwise the UI clearly labels the token count as an estimate. Local limits reflect the active context without exceeding KNX AI's 16K cap.<br/>
|
|
12
|
+
- **KNX AI — documentation-free operational chat**: Telegram, RedBot and custom CHAT adapters no longer inject packaged help, README, changelog, wiki or example snippets into model prompts. They retain live and archived KNX data, ETS semantics, Node-RED inventory, conversation and home memory, AI Education, cameras and TTS; the web Assistant keeps documentation access for package-support questions.<br/>
|
|
13
|
+
- **KNX AI — tolerant safe-read normalization**: state queries from small local models no longer become rejected writes when the model returns exact ETS destinations but omits the operation discriminator and payload. Payload-free operations are safely inferred as `GroupValue_Read`; payload-bearing operations remain writes and retain every ETS-role, DPT, payload and confirmation safeguard.<br/>
|
|
14
|
+
- **KNX AI — fixed 16K Ollama runtime and prompt budget**: Ollama's advertised model maximum is now informational instead of being sent back as the requested `num_ctx`. KNX AI caps `num_ctx` and its relevance-selected semantic prompt at 16K, preventing 131K KV-cache allocation and full-context prefill. An audit confirmed that OpenAI and Claude receive only output limits, not a client-selected maximum context window.<br/>
|
|
15
|
+
- **KNX AI — fixed 16K Bionic prompt budget**: Bionic's reported active or maximum context can no longer promote conversations to the full 131K data view. KNX AI always builds a relevance-selected 16K semantic prompt for Bionic while preserving the provider's loaded instance, open-ended reasoning, routines, KNX control, cameras and TTS capabilities.<br/>
|
|
16
|
+
- **KNX AI — preserve Bionic LM Studio context**: model discovery now keeps the context length of an already loaded Bionic instance instead of confusing the model's maximum capability with the desired runtime setting. KNX AI no longer loads inactive models through the management API: the first chat request leaves JIT loading and saved per-model defaults to Bionic, while KNX AI uses a conservative 16K prompt budget until the active configuration can be inspected.<br/>
|
|
17
|
+
- **KNX AI — neutral structured-response example**: the conversational contract now demonstrates empty action arrays instead of a fabricated group address, DPT, camera and payload. This prevents small local models from copying placeholder operations into unrelated replies such as greetings while preserving open-ended reasoning and every existing KNX, camera, TTS and routine capability.<br/>
|
|
18
|
+
|
|
9
19
|
**Version 6.3.21** - August 2026<br/>
|
|
10
20
|
|
|
11
21
|
- **KNX AI — persistent adapter-event history**: every event published by an automatically detected adapter is now normalized into vendor-neutral metadata and appended to a node-specific daily JSONL archive. The archive follows the 10-day KNX retention, guaranteeing at least 24 hours of camera and future adapter events across Node-RED restarts without storing snapshot image data. The editor context card exposes the actual adapter-history directories.<br/>
|
package/nodes/knxUltimateAI.html
CHANGED
|
@@ -182,12 +182,18 @@
|
|
|
182
182
|
#knx-ai-detected-adapters-status,
|
|
183
183
|
#knx-ai-chat-context-status,
|
|
184
184
|
.knx-ai-chat-context-intro,
|
|
185
|
+
.knx-ai-chat-context-metric,
|
|
185
186
|
.knx-ai-chat-context-description,
|
|
186
187
|
.knx-ai-chat-context-pattern {
|
|
187
188
|
color: var(--red-ui-secondary-text-color, #777);
|
|
188
189
|
font-size: 12px;
|
|
189
190
|
}
|
|
190
191
|
|
|
192
|
+
.knx-ai-chat-context-metric {
|
|
193
|
+
margin-top: 6px;
|
|
194
|
+
font-weight: 600;
|
|
195
|
+
}
|
|
196
|
+
|
|
191
197
|
.knx-ai-chat-context-group-title {
|
|
192
198
|
margin: 12px 0 2px;
|
|
193
199
|
font-size: 12px;
|
|
@@ -610,6 +616,8 @@
|
|
|
610
616
|
const $sources = $("#knx-ai-chat-context-sources-list").empty();
|
|
611
617
|
const $files = $("#knx-ai-chat-context-files-list").empty();
|
|
612
618
|
const $directories = $("#knx-ai-chat-context-directories-list").empty();
|
|
619
|
+
const $contextLimit = $("#knx-ai-chat-context-limit");
|
|
620
|
+
const $lastPromptUsage = $("#knx-ai-chat-context-last-prompt");
|
|
613
621
|
if (!overview || typeof overview !== "object") {
|
|
614
622
|
$content.hide();
|
|
615
623
|
$status
|
|
@@ -633,12 +641,59 @@
|
|
|
633
641
|
$row.appendTo($list);
|
|
634
642
|
};
|
|
635
643
|
|
|
644
|
+
const formatCompactTokens = function (value) {
|
|
645
|
+
const tokens = Math.max(0, Number(value) || 0);
|
|
646
|
+
if (!tokens) return "?";
|
|
647
|
+
if (tokens >= 1024 && tokens % 1024 === 0) return (tokens / 1024) + "K";
|
|
648
|
+
return tokens.toLocaleString();
|
|
649
|
+
};
|
|
650
|
+
const formatBytes = function (value) {
|
|
651
|
+
const bytes = Math.max(0, Number(value) || 0);
|
|
652
|
+
if (bytes >= (1024 * 1024)) return (bytes / (1024 * 1024)).toLocaleString(undefined, { maximumFractionDigits: 1 }) + " MB";
|
|
653
|
+
if (bytes >= 1024) return (bytes / 1024).toLocaleString(undefined, { maximumFractionDigits: 1 }) + " KB";
|
|
654
|
+
return bytes.toLocaleString() + " B";
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
const contextLimit = overview.contextLimit && typeof overview.contextLimit === "object" ? overview.contextLimit : {};
|
|
658
|
+
const currentProvider = String(contextLimit.provider || $("#node-input-llmProvider").val() || "").toLowerCase();
|
|
659
|
+
let contextLimitTokens = Math.max(0, Number(contextLimit.tokens) || 0);
|
|
660
|
+
if (!contextLimitTokens && (currentProvider === "lmstudio" || currentProvider === "ollama")) {
|
|
661
|
+
contextLimitTokens = Math.min(Math.max(0, Number($("#node-input-llmContextLength").val()) || 16384), 16384);
|
|
662
|
+
}
|
|
663
|
+
const contextLimitValue = contextLimitTokens
|
|
664
|
+
? formatCompactTokens(contextLimitTokens) + " " + t("knxUltimateAI.messages.chatContextTokens", "tokens")
|
|
665
|
+
: t("knxUltimateAI.messages.chatContextProviderManaged", "managed by the selected provider/model");
|
|
666
|
+
$contextLimit
|
|
667
|
+
.text(t("knxUltimateAI.messages.chatContextLimitLabel", "Maximum operational context") + ": " + contextLimitValue)
|
|
668
|
+
.attr("title", contextLimitTokens ? contextLimitTokens.toLocaleString() + " tokens" : contextLimitValue);
|
|
669
|
+
|
|
670
|
+
const promptUsage = overview.lastPromptUsage && typeof overview.lastPromptUsage === "object" ? overview.lastPromptUsage : null;
|
|
671
|
+
if (promptUsage && Number(promptUsage.bytes) > 0) {
|
|
672
|
+
const exactInputTokens = Math.max(0, Number(promptUsage.exactInputTokens) || 0);
|
|
673
|
+
const estimatedInputTokens = Math.max(0, Number(promptUsage.estimatedInputTokens) || 0);
|
|
674
|
+
const tokenText = exactInputTokens
|
|
675
|
+
? formatCompactTokens(exactInputTokens) + " " + t("knxUltimateAI.messages.chatContextExactInputTokens", "input tokens measured by the provider")
|
|
676
|
+
: "~" + formatCompactTokens(estimatedInputTokens) + " " + t("knxUltimateAI.messages.chatContextEstimatedInputTokens", "estimated input tokens");
|
|
677
|
+
const imageText = Number(promptUsage.imageCount) > 0
|
|
678
|
+
? " · " + Number(promptUsage.imageCount).toLocaleString() + " " + t("knxUltimateAI.messages.chatContextImages", "images")
|
|
679
|
+
: "";
|
|
680
|
+
$lastPromptUsage.text(
|
|
681
|
+
t("knxUltimateAI.messages.chatContextLastPromptLabel", "Last chat prompt actual size") + ": " +
|
|
682
|
+
formatBytes(promptUsage.bytes) + " · " + tokenText + imageText
|
|
683
|
+
);
|
|
684
|
+
} else {
|
|
685
|
+
$lastPromptUsage.text(
|
|
686
|
+
t("knxUltimateAI.messages.chatContextLastPromptLabel", "Last chat prompt actual size") + ": " +
|
|
687
|
+
t("knxUltimateAI.messages.chatContextLastPromptUnavailable", "not available until the first chat request")
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
|
|
636
691
|
const sourceLabels = {
|
|
637
692
|
knxTraffic: t("knxUltimateAI.messages.chatContextSourceKnxTraffic", "Live KNX summary, anomalies, topology and selected telegrams."),
|
|
638
693
|
adapterHistory: t("knxUltimateAI.messages.chatContextSourceAdapterHistory", "Persistent history of automatically detected adapter events."),
|
|
639
694
|
etsProject: t("knxUltimateAI.messages.chatContextSourceEtsProject", "ETS semantics and the full Node-RED project inventory."),
|
|
640
695
|
memoryEducation: t("knxUltimateAI.messages.chatContextSourceMemoryEducation", "Session context, AI Education and bounded home memory."),
|
|
641
|
-
|
|
696
|
+
cameras: t("knxUltimateAI.messages.chatContextSourceCameras", "Detected cameras and their available capabilities."),
|
|
642
697
|
ttsUltimate: t("knxUltimateAI.messages.chatContextSourceTtsUltimate", "Selected TTS Ultimate announcement target.")
|
|
643
698
|
};
|
|
644
699
|
(Array.isArray(overview.sources) ? overview.sources : []).forEach(function (sourceId) {
|
|
@@ -752,11 +807,14 @@
|
|
|
752
807
|
let text = t("knxUltimateAI.messages.lmStudioContextAvailable", "Maximum model context") + ": " + maxTokens + " token";
|
|
753
808
|
let color = "#555";
|
|
754
809
|
if (state === "loading") {
|
|
755
|
-
text = t("knxUltimateAI.messages.lmStudioContextLoading", "
|
|
810
|
+
text = t("knxUltimateAI.messages.lmStudioContextLoading", "Checking the active model context") + "…";
|
|
756
811
|
color = "#1565c0";
|
|
812
|
+
} else if (state === "inactive") {
|
|
813
|
+
text = t("knxUltimateAI.messages.lmStudioContextInactive", "Model inactive; Bionic defaults will be used on the first request");
|
|
814
|
+
color = "#555";
|
|
757
815
|
} else if (state === "configured") {
|
|
758
816
|
const configuredTokens = formatContextTokens(detail.configuredContextLength || detail.loadedContextLength || detail.maxContextLength);
|
|
759
|
-
text = t("knxUltimateAI.messages.lmStudioContextConfigured", "
|
|
817
|
+
text = t("knxUltimateAI.messages.lmStudioContextConfigured", "Active model context") + ": " + configuredTokens + " token";
|
|
760
818
|
color = "#2e7d32";
|
|
761
819
|
} else if (state === "error") {
|
|
762
820
|
text = String(errorText || t("knxUltimateAI.messages.lmStudioContextFailed", "Unable to configure the model context"));
|
|
@@ -764,6 +822,9 @@
|
|
|
764
822
|
} else if (detail.loadedContextLength > 0) {
|
|
765
823
|
text += " · " + t("knxUltimateAI.messages.lmStudioContextCurrentlyLoaded", "currently loaded") + ": " + loadedTokens + " token";
|
|
766
824
|
}
|
|
825
|
+
if (provider === "lmstudio" || provider === "ollama") {
|
|
826
|
+
text += " · " + t("knxUltimateAI.messages.localContextBudget", "KNX AI context budget") + ": 16K";
|
|
827
|
+
}
|
|
767
828
|
$status.text(text).css("color", color).show();
|
|
768
829
|
};
|
|
769
830
|
|
|
@@ -824,9 +885,13 @@
|
|
|
824
885
|
}
|
|
825
886
|
|
|
826
887
|
const requestVersion = ++localContextRequestVersion;
|
|
827
|
-
|
|
888
|
+
const activeContextLength = Number(detail.loadedContextLength) > 0
|
|
889
|
+
? Number(detail.loadedContextLength)
|
|
890
|
+
: Number(detail.maxContextLength);
|
|
891
|
+
$("#node-input-llmContextLength").val(activeContextLength);
|
|
828
892
|
if (provider === "ollama") {
|
|
829
|
-
detail.configuredContextLength = Number(detail.maxContextLength);
|
|
893
|
+
detail.configuredContextLength = Math.min(Number(detail.maxContextLength), 16384);
|
|
894
|
+
$("#node-input-llmContextLength").val(detail.configuredContextLength);
|
|
830
895
|
setLocalModelContextStatus(detail, "configured");
|
|
831
896
|
return;
|
|
832
897
|
}
|
|
@@ -848,13 +913,14 @@
|
|
|
848
913
|
type: "POST",
|
|
849
914
|
contentType: "application/json",
|
|
850
915
|
data: JSON.stringify(payload)
|
|
851
|
-
|
|
916
|
+
})
|
|
852
917
|
.done(function (data) {
|
|
853
918
|
if (requestVersion !== localContextRequestVersion) return;
|
|
854
|
-
|
|
855
|
-
detail.
|
|
856
|
-
|
|
857
|
-
|
|
919
|
+
const resolvedContextLength = Math.max(0, Number(data && data.contextLength) || 0);
|
|
920
|
+
detail.loadedContextLength = data && data.active === true ? resolvedContextLength : 0;
|
|
921
|
+
detail.configuredContextLength = resolvedContextLength;
|
|
922
|
+
$("#node-input-llmContextLength").val(resolvedContextLength);
|
|
923
|
+
setLocalModelContextStatus(detail, data && data.active === true ? "configured" : "inactive");
|
|
858
924
|
})
|
|
859
925
|
.fail(function (xhr) {
|
|
860
926
|
if (requestVersion !== localContextRequestVersion) return;
|
|
@@ -1120,6 +1186,8 @@
|
|
|
1120
1186
|
<div id="knx-ai-chat-context-status" data-i18n="knxUltimateAI.messages.chatContextLoading"></div>
|
|
1121
1187
|
<div id="knx-ai-chat-context-content" style="display:none;">
|
|
1122
1188
|
<div class="knx-ai-chat-context-intro" data-i18n="knxUltimateAI.messages.chatContextIntro"></div>
|
|
1189
|
+
<div id="knx-ai-chat-context-limit" class="knx-ai-chat-context-metric"></div>
|
|
1190
|
+
<div id="knx-ai-chat-context-last-prompt" class="knx-ai-chat-context-metric"></div>
|
|
1123
1191
|
<div class="knx-ai-chat-context-group-title" data-i18n="knxUltimateAI.messages.chatContextSourcesTitle"></div>
|
|
1124
1192
|
<div id="knx-ai-chat-context-sources-list"></div>
|
|
1125
1193
|
<div class="knx-ai-chat-context-group-title" data-i18n="knxUltimateAI.messages.chatContextFilesTitle"></div>
|