iobroker.javascript 10.1.3 → 10.1.4

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.
Files changed (81) hide show
  1. package/README.md +6 -5
  2. package/admin/assets/AiChatPanel-D93BBufl.js +242 -0
  3. package/admin/assets/AiDiffView-D5QZDwuC.js +1 -0
  4. package/admin/assets/{AiInlineProvider-CaHd2G2Q.js → AiInlineProvider-CRU2J938.js} +1 -1
  5. package/admin/assets/Debugger-BLzsRkue.js +15 -0
  6. package/admin/assets/Error-BWXtkB6H.js +1 -0
  7. package/admin/assets/Import-D_RBSmNU.js +1 -0
  8. package/admin/assets/RulesEditor-DpKr8byp.js +1 -0
  9. package/admin/assets/RulesEditor-QNWIRnqB.css +1 -0
  10. package/admin/assets/{ScriptEditor-C6ekGK_v.js → ScriptEditor-DK6nNmcp.js} +2 -2
  11. package/admin/assets/{ScriptEditorVanillaMonaco-BzazJaUa.js → ScriptEditorVanillaMonaco-BVIwadsl.js} +3 -3
  12. package/admin/assets/{_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-CL_S1FIh.js → _virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-v3-PYsgp.js} +1 -1
  13. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-GB0oxSwG.js +1217 -0
  14. package/admin/assets/{_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-DdX5BXjB.js → _virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-SF46owzN.js} +1 -1
  15. package/admin/assets/aiPromptBuilder-CtijdvYL.js +1 -0
  16. package/admin/assets/{blocks_action-CaHoI2vK.js → blocks_action-Dflw8PyN.js} +1 -1
  17. package/admin/assets/{blocks_convert-Dno4Uyat.js → blocks_convert-XTqMxB04.js} +1 -1
  18. package/admin/assets/{blocks_logic-C4MPyL6T.js → blocks_logic-JaZOQj6_.js} +1 -1
  19. package/admin/assets/{blocks_number-BMu9V-ca.js → blocks_number-TU4dV-Ia.js} +1 -1
  20. package/admin/assets/{blocks_object-vU59tx8A.js → blocks_object-V6ojF22C.js} +1 -1
  21. package/admin/assets/{blocks_procedures-CfhGGNAK.js → blocks_procedures-Cu8VeJhw.js} +1 -1
  22. package/admin/assets/{blocks_sendto-oZjHfEt6.js → blocks_sendto-BnDWzP0n.js} +1 -1
  23. package/admin/assets/{blocks_switch-DtRe2uV0.js → blocks_switch-DKUc060E.js} +1 -1
  24. package/admin/assets/{blocks_system-CWkKMHLd.js → blocks_system-BW_UpMW-.js} +1 -1
  25. package/admin/assets/{blocks_text-CunCNUrR.js → blocks_text-BIU2kf_V.js} +1 -1
  26. package/admin/assets/{blocks_time-B_Duc9-g.js → blocks_time-2vgvS4_j.js} +1 -1
  27. package/admin/assets/{blocks_timeout-B5PA_0Xv.js → blocks_timeout-BPzmWif8.js} +1 -1
  28. package/admin/assets/{blocks_trigger-BePNP-VV.js → blocks_trigger-BSFZEWEO.js} +1 -1
  29. package/admin/assets/{cronHoverProvider-COaB74MF.js → cronHoverProvider-BMVsvVuG.js} +1 -1
  30. package/admin/assets/{field_cron-BkiRQvy7.js → field_cron-Br4hxeLb.js} +1 -1
  31. package/admin/assets/{field_oid-pEOMkwS7.js → field_oid-ojNnLVGL.js} +1 -1
  32. package/admin/assets/{field_script-D8TaeXTc.js → field_script-Bs925umq.js} +1 -1
  33. package/admin/assets/{helpers-Cbd0K4kn.js → helpers-BFQD9R82.js} +1 -1
  34. package/admin/assets/{hostInit-PWanFl0v.js → hostInit-B_aW3Wuw.js} +1 -1
  35. package/admin/assets/index-BnLv569U.js +871 -0
  36. package/admin/assets/{inlineChatWidget-CmSJN0Rv.js → inlineChatWidget-BcLIwfEH.js} +1 -1
  37. package/admin/assets/{inlineDiffController-CauFSimb.js → inlineDiffController-DGl5rDYU.js} +1 -1
  38. package/admin/assets/{mf-entry-bootstrap-0-66751765.js → mf-entry-bootstrap-0-ec2e487a.js} +2 -2
  39. package/admin/assets/{stateHoverProvider-g3dqXZ8K.js → stateHoverProvider-XKm8a_93.js} +1 -1
  40. package/admin/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__iobroker_javascript__remoteEntry_js-Dc9L2TVn.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__iobroker_javascript__remoteEntry_js-IRf47UYM.js} +1 -1
  41. package/admin/custom/assets/Components-BpxzAzc7.js +1 -0
  42. package/admin/custom/assets/{_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-Bd9Y-jyc.js → _virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-wwYTJNxa.js} +1 -1
  43. package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-BGJv4zZP.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-DzaRKfE_.js} +1 -1
  44. package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-B4E6MFJ4.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-B9fjpXOq.js} +1 -1
  45. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-QxUxIFgP.js +1217 -0
  46. package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-D81YCXgE.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-BUk3WHjQ.js} +9 -9
  47. package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-CxkJmLDG.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-DqjU6PXX.js} +1 -1
  48. package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__prebuild__date_mf_2_fns__prebuild__-BNLW3sTg.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__prebuild__date_mf_2_fns__prebuild__-CXAEcWml.js} +1 -1
  49. package/admin/custom/assets/{hostInit-CxnK2NMF.js → hostInit-CkdLQZaZ.js} +1 -1
  50. package/admin/custom/assets/{index-CHg-uG3r.js → index-D2qJNee0.js} +1 -1
  51. package/admin/custom/assets/{lib-D4Fc4r7w.js → lib-D9tipKpE.js} +2 -2
  52. package/admin/custom/assets/{mf-entry-bootstrap-0-16561517.js → mf-entry-bootstrap-0-ff278fef.js} +2 -2
  53. package/admin/custom/assets/{setYear-Dhce8K9j.js → setYear-DXk_Jooa.js} +1 -1
  54. package/admin/custom/assets/virtualExposes-vH26J8jF.js +1 -0
  55. package/admin/custom/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-jnBHXUID.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-qdaLIbFV.js} +1 -1
  56. package/admin/custom/assets/{virtual_mf-exposes___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-PH1CCUgS.js → virtual_mf-exposes___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-C1DpedFv.js} +2 -2
  57. package/admin/custom/customComponents.js +2 -2
  58. package/admin/jsonConfig.json +1 -1
  59. package/admin/mf-manifest.json +1 -1
  60. package/admin/mf-stats.json +1 -1
  61. package/admin/remoteEntry.js +2 -2
  62. package/admin/tab.html +4 -4
  63. package/build/lib/aiProviderResolver.js +18 -6
  64. package/build/lib/aiProviderResolver.js.map +1 -1
  65. package/build/main.js +26 -0
  66. package/build/main.js.map +1 -1
  67. package/io-package.json +14 -14
  68. package/package.json +2 -2
  69. package/admin/assets/AiChatPanel-rQsCR89v.js +0 -242
  70. package/admin/assets/AiDiffView-BoglEOaq.js +0 -1
  71. package/admin/assets/Debugger-Bj4PsKNm.js +0 -15
  72. package/admin/assets/Error-RANTMuGx.js +0 -1
  73. package/admin/assets/Import-CJgQwwNY.js +0 -1
  74. package/admin/assets/RulesEditor-BcGsf9n4.css +0 -1
  75. package/admin/assets/RulesEditor-PYpUIg7N.js +0 -1
  76. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BAOcdAz5.js +0 -1243
  77. package/admin/assets/aiPromptBuilder-a2bvj40X.js +0 -1
  78. package/admin/assets/index-4M2aGX3M.js +0 -871
  79. package/admin/custom/assets/Components-uxORfFYU.js +0 -1
  80. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DMefPDeL.js +0 -1243
  81. package/admin/custom/assets/virtualExposes-DUFP2Erj.js +0 -1
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "javascript",
4
- "version": "10.1.3",
4
+ "version": "10.1.4",
5
5
  "blockedVersions": [
6
6
  "8.0.0",
7
7
  "8.0.1"
@@ -40,6 +40,19 @@
40
40
  "Matthias Kleine <info@haus-automatisierung.com>"
41
41
  ],
42
42
  "news": {
43
+ "10.1.4": {
44
+ "en": "Rules: the text of an action can round the trigger value with `%.1s` - any number of digits after the decimal point, also `%.2old` for the old value - formatted with the decimal separator of the system, so `Kühlschrank zu warm (%.1s°C)` gives `29,4°C` where `%s` gave `29.400000000000002°C`\nCorrected the function block in blockly\nA custom OpenAI-compatible AI endpoint answered \"Invalid API key\" in the inline completion and while loading the model list, although the test button in the settings said \"ok\": both asked the adapter for the provider `openai`, and the adapter picks the key by that name, so they used the \"OpenAI API key\" instead of the \"Custom API key\". The custom endpoint is now addressed as what it is, everywhere (#2369)\nA configured \"Custom API Base URL\" also redirected every request meant for OpenAI itself to that address - with the OpenAI key attached and no way to switch it off. The base URL now belongs to the custom endpoint alone, so both can be used side by side. If the key of your custom endpoint is in the \"OpenAI API key\" field, move it to the \"Custom API key\" field; the adapter writes a warning in the log if it finds such a setup (#2369)",
45
+ "de": "Regeln: Der Text einer Aktion kann den Triggerwert mit `%.1s` runden — beliebig viele Nachkommastellen, auch `%.2old` für den alten Wert — formatiert mit dem Dezimaltrennzeichen des Systems, also `Kühlschrank zu warm (%.1s°C) `ergibt `29,4°C`, während `%s` `29.400000000000002°C` ergibt\nFunktionsblock in Blockly korrigiert\nEin benutzerdefinierter OpenAI-kompatibler KI-Endpunkt antwortete beim Laden der Modellliste mit „Ungültiger API-Schlüssel“, obwohl der Testbutton in den Einstellungen „ok“ sagte: Beide fragten den Adapter nach dem Anbieter `openai`, und der Adapter wählt den Schlüssel mit diesem Namen aus, also nutzten sie den „OpenAI API Key“ statt des „Custom API Key“. Der benutzerdefinierte Endpunkt wird jetzt überall behandelt (#2369)\nEine konfigurierte „Custom API Base URL“ leitete auch jede Anfrage für OpenAI an diese Adresse um — mit OpenAI-Key und ohne Abschaltmöglichkeit. Die Basis-URL gehört nun nur zum Endpunkt, also beide nebeneinander. Wenn der Schlüssel Ihres Endpunkts im Feld „OpenAI API Key“ steht, schreibt der Adapter eine Warnung in das Log (#2369)",
46
+ "ru": "Правила: в тексте действия можно округлить значение триггера до «%.1s» — любое количество цифр после десятичной точки, а также «%.2old» для старого значения — отформатированное с использованием десятичного разделителя системы, поэтому `Kühlschrank zu warm (%.1s°C) `дает значение `29,4°C`, где `%s` даёт `29,400000000000002°C`\nИсправлен функциональный блок в blockly\nСпециальная конечная точка искусственного интеллекта, совместимая с OpenAI, ответила «Неверный ключ API» при встраиваемом заполнении и загрузке списка моделей, хотя на кнопке тестирования в настройках было написано «ОК»: обе команды запросили у адаптера поставщика `openai`, и адаптер выбирает ключ под этим именем, поэтому вместо «Custom API key» они использовали «ключ OpenAI API». Настраиваемая конечная точка теперь везде рассматривается как есть (#2369)\nНастроенный «Custom API Base URL» также перенаправлял каждый запрос, предназначенный для самого OpenAI, на этот адрес — при этом ключ OpenAI был прикреплен, и его нельзя было отключить. Теперь базовый URL-адрес принадлежит только настраиваемой конечной точке, поэтому их можно использовать одновременно. Если ключ вашей пользовательской конечной точки находится в поле «Ключ OpenAI API», переместите его в поле «Custom API key»; если адаптер обнаружит такую настройку, в журнал запишет предупреждение (#2369)",
47
+ "pt": "Regras: o texto de uma ação pode arredondar o valor do gatilho com `%.1s` - qualquer número de dígitos após o ponto decimal, também `%.2old` para o valor antigo - formatado com o separador decimal do sistema. 2°C”\nCorrigiu o bloco de função em bloco\nUm endpoint de IA compatível com OpenAI respondeu “chave de API inválida” no preenchimento em linha e ao carregar a lista de modelos, embora o botão de teste nas configurações dissesse “ok”: ambos pediram ao adaptador o provedor `openai` e o adaptador escolheu a chave com esse nome, então eles usaram a “chave de API OpenAI” em vez da “chave de API personalizada”. O endpoint personalizado agora é o que é, em todo lugar (#2369)\nUm “URL base de API personalizado” também redirecionava cada solicitação do OpenAI para esse endereço — com a chave OpenAI anexada e sem como desligá-la. O URL base agora pertence ao endpoint personalizado e pode ser usado lado a lado. Se a chave do seu endpoint estiver no campo “Chave de API OpenAI”, mova-a para “Chave de API personalizada”; o adaptador grava um aviso no log (#2369)",
48
+ "nl": "Regels: de tekst van een actie kan de triggerwaarde afronden met `%.1s` - een willekeurig aantal cijfers achter de komma, ook `%.2oud` voor de oude waarde - opgemaakt met het decimale scheidingsteken van het systeem, zodat `Kühlschrank zu warm (%.1s°C) `geeft `29,4°C` waarbij `%s` `29.4000002°C` gaf\nHet functieblok in blockly gecorrigeerd\nEen aangepast AI-eindpunt dat compatibel is met OpenAI antwoordde „Ongeldige API-sleutel” in de inline-aanvulling en tijdens het laden van de modellenlijst, hoewel op de testknop in de instellingen „OK” stond: beiden vroegen de adapter naar de provider `openai`, en de adapter kiest de sleutel met die naam, dus gebruikten ze de „OpenAI API-sleutel” in plaats van de „Aangepaste API-sleutel”. Het aangepaste eindpunt wordt nu overal weergegeven zoals het is (#2369)\nEen geconfigureerde „Custom API Base URL” heeft ook elk verzoek dat voor OpenAI zelf was bedoeld, omgeleid naar dat adres - met de OpenAI-sleutel eraan gekoppeld en zonder mogelijkheid om het uit te schakelen. De basis-URL behoort nu alleen tot het aangepaste eindpunt, dus beide kunnen naast elkaar worden gebruikt. Als de sleutel van uw aangepaste eindpunt zich in het veld „OpenAI API-sleutel” bevindt, verplaats deze dan naar het veld „Aangepaste API-sleutel”; de adapter schrijft een waarschuwing in het logboek als er een dergelijke instelling wordt gevonden (#2369)",
49
+ "fr": "Règles : le texte d'une action peut arrondir la valeur de déclenchement par « %.1s », un nombre quelconque de chiffres après la virgule, et « %.2old » pour l'ancienne valeur, formaté avec le séparateur décimal du système, donc « Kühlschrank zu warm (%.1s°C) » donne « 29,4°C » où « %s` a donné 29,400000000000002°C »\nCorrection du bloc de fonctions dans Blockly\nUn terminal IA personnalisé compatible avec OpenAI a répondu « Clé API non valide » en ligne et en chargeant la liste des modèles, mais le bouton de test des paramètres indiquait « OK » : les deux ont demandé à l'adaptateur le fournisseur « openai », et l'adaptateur a choisi la clé portant ce nom. Ils ont donc utilisé la « clé API OpenAI » au lieu de la « clé API personnalisée ». Le point de terminaison personnalisé est désormais traité tel quel, partout (#2369)\nUne « URL de base API personnalisée » configurée redirigeait toutes les requêtes destinées à OpenAI vers cette adresse, avec la clé OpenAI attachée, sans moyen de la désactiver. L'URL de base n'appartient qu'au point de terminaison personnalisé, donc côte à côte. Si la clé de votre terminal personnalisé se trouve dans le champ « Clé API OpenAI », l'adaptateur écrit un avertissement dans le journal s'il détecte une telle configuration (#2369)",
50
+ "it": "Regole: il testo di un'azione può arrotondare il valore del trigger con «%.1s» - qualsiasi numero di cifre dopo la virgola, anche «%.2old» per il vecchio valore - con il separatore decimale del sistema, quindi «Kühlschrank zu warm (%.1s°C)» dà «29,4°C» dove «%s» dà «29.40000000000000000\" 02 °C»\nCorretto il blocco funzione in blocco\nUn endpoint AI personalizzato compatibile con OpenAI ha risposto «Chiave API non valida» nel completamento in linea e durante il caricamento dell'elenco dei modelli, anche se il pulsante di test diceva «ok»: entrambi hanno chiesto al provider «openai» e l'adattatore ha scelto la chiave con quel nome. L'endpoint personalizzato ora è così, ovunque (#2369)\nUn «Custom API Base URL» reindirizzava anche tutte le richieste di OpenAI a quell'indirizzo, con la chiave OpenAI allegata e senza modo di spegnerla. L'URL di base ora appartiene solo all'endpoint personalizzato. Se la chiave del suo endpoint è nel campo «OpenAI API key», la sposti nel campo «Custom API key»; l'adattatore scrive un avviso nel log se trova tale setup (#2369)",
51
+ "es": "Reglas: el texto de una acción puede redondear el valor de activación con `%.1s` (cualquier número de dígitos después de la coma decimal, también `%.2old» para el valor anterior, formateado con el separador decimal del sistema, por lo que `Kühlschrank zu warm (%.1s°C) `da 29,4°C`, donde `%s` daba 29,40000000002°C\nSe corrigió el bloque de funciones en blockly\nUn punto final de IA personalizado compatible con OpenAI respondió «Clave de API no válida» al terminar en línea y al cargar la lista de modelos, aunque el botón de prueba de la configuración decía «vale»: ambos pidieron al adaptador el proveedor `openai` y el adaptador escogió la clave con ese nombre, por lo que usaron la «clave de API de OpenAI» en lugar de la «clave de API personalizada». El punto final personalizado ahora se dirige como es, en todas partes (#2369)\nUna «URL base de API personalizada» configurada también redirigía todas las solicitudes de OpenAI a esa dirección, con la clave de OpenAI adjunta y sin forma de desactivarla. La URL base ahora pertenece solo al punto final personalizado, por lo que pueden usarse. Si la clave de su punto final personalizado está en el campo «Clave API OpenAI», muévala al campo «Clave API personalizada»; el adaptador escribe un aviso en el registro si encuentra esa configuración (#2369)",
52
+ "pl": "Reguły: tekst akcji może zaokrąglić wartość wyzwalającą o `%.1s` - dowolną liczbę cyfr po przecinku, także `%.2old` dla starej wartości - sformatowaną za pomocą separatora dziesiętnego systemu, więc `Kühlschrank zu warm (%.1s°C) `daje `29,4°C` gdzie `%s` dało `29.400000000000002°C`\nPoprawiono blok funkcji w bloku\nNiestandardowy punkt końcowy AI zgodny z OpenAI odpowiedział na „Nieprawidłowy klucz API” podczas uzupełniania linii i podczas ładowania listy modeli, chociaż przycisk testowy w ustawieniach powiedział „ok”: obaj poprosili adapter o dostawcę `openai`, a adapter wybiera klucz pod tą nazwą, więc użyli „klucza API OpenAI” zamiast „Custom API key”. Niestandardowy punkt końcowy jest teraz adresowany tak, jak jest, wszędzie (#2369)\nSkonfigurowany „Custom API Base URL” przekierował również każde żądanie przeznaczone dla samego OpenAI na ten adres - z dołączonym kluczem OpenAI i bez możliwości jego wyłączenia. Podstawowy adres URL należy teraz do samego niestandardowego punktu końcowego, więc oba mogą być używane obok siebie. Jeśli klucz niestandardowego punktu końcowego znajduje się w polu „Klucz API OpenAI”, przenieś go do pola „Custom API key”; adapter zapisuje ostrzeżenie w dzienniku, jeśli znajdzie taką konfigurację (#2369)",
53
+ "uk": "Правила: текст дії може округлити значення тригера з `%.1s `- будь-якою кількістю цифр після десяткової коми, також `%.2old` для старого значення - відформатоване десятковим роздільником системи, тому `Kühlschrank zu warm (%.1s°C)` дає `29,4°C`, де `%s` дав `29.400000000000002°C`\nВиправлено функціональний блок в blockly\nСпеціальна кінцева точка AI, сумісна з OpenAI, відповіла «Недійсний ключ API» у вбудованому доповненні та під час завантаження списку моделей, хоча на кнопці тестування в налаштуваннях було написано «ok»: обидва запитали у адаптера постачальника `openai`, а адаптер вибирає ключ під цим ім'ям, тому вони використовували «ключ API OpenAI» замість «Custom API key». Користувацьку кінцеву точку тепер адресовано як те, що вона є, скрізь (#2369)\nНалаштована «Custom API Base URL» також перенаправляла кожен запит, призначений для самої OpenAI, на цю адресу - з прикріпленим ключем OpenAI і без можливості його вимкнути. Базова URL-адреса тепер належить лише користувацькій кінцевій точці, тому обидві можуть бути використані поруч. Якщо ключ вашої користувацької кінцевої точки знаходиться в полі «OpenAI API key», перемістіть його в поле «Custom API key»; адаптер записує попередження в журнал, якщо знайде таку настройку (#2369)",
54
+ "zh-cn": "规则:动作文本可以用 `%.1s` 对触发值进行四舍五入——小数点后的任意位数,旧值也是 `%.2old` ——使用系统的十进制分隔符进行格式化,因此 `Kühlschrank zu warm (%.1s°C) `给出 `29,4°C`,其中 `%s` 给出 `29.4000000000002°C`\n方块更正了功能块\n一个兼容 OpenAI 的自定义 AI 端点在行内完成和加载模型列表时回答 “无效 API 密钥”,尽管设置中的测试按钮显示 “确定”:两者都要求适配器提供提供商 “openai”,而适配器按该名称选择密钥,因此他们使用 “OpenAI API 密钥” 而不是 “自定义 API 密钥”。现在,自定义终端节点随处可见 (#2369)\n配置的 “自定义API基础网址” 还将所有发送给OpenAI本身的请求重定向到该地址——附加了OpenAI密钥,无法将其关闭。基本 URL 现在仅属于自定义端点,因此两者可以并排使用。如果您的自定义终端节点的密钥位于 “OpenAI API 密钥” 字段中,请将其移至 “自定义 API 密钥” 字段;如果适配器发现此类设置,则会在日志中写入警告 (#2369)"
55
+ },
43
56
  "10.1.3": {
44
57
  "en": "The plain text export named its files after the script ID instead of the script name, so every dot of a name came out as an underscore - `HK-Balkontuer_v0.1` was exported as `HK-Balkontuer_v0_1.js`, and importing it back renamed the script to that. The files are now named after the script (#2364)\nImporting a plain text export treated a dot inside a file name as a folder level, so `PW-TV-Control_v0.6.js` created a folder `PW-TV-Control_v0` containing a script named `6`. Only the directories of the ZIP are folders now (#2364)\nThe folder icons in the script tree were drawn at less than half the size of the script icons next to them: they spaced themselves with a padding, and since `CssBaseline` sets `box-sizing: border-box` that padding was subtracted from their 20px instead of being added to them. They use a margin now, like the script icons always did (#2360)\nThe log below the editor could not be resized while a script was open: the editor area guessed its height from the height the tabs and the toolbar were expected to have, hung over the bottom edge of its pane and covered the 8px splitter with the horizontal scrollbar of the editor, which swallowed the mouse click. The three parts now share the height as a flex column (#2351)\nThe script list cut off long names, although there was still free space next to them: the space for the buttons at the end of a row was a fixed 185px, which is more than the three buttons occupy, and it did not account for the icon column\nFixed the Blockly comment block: the text was written in white on the yellow block and could not be read, the editor opened somewhere else on the page instead of over the block, and on a smartphone or tablet it did not open at all and left the whole workspace unusable until the page was reloaded (#2348)\nFixed the script mirror for folder names containing regular expression characters: a folder called e.g. `Lampen (Flur` aborted the synchronization with a `SyntaxError`, a folder called e.g. `[ab]` silently synchronized the scripts of another folder (#2239)\nThe Blockly block \"http (POST)\" got a \"content type\" selector, so an API that insists on `Content-Type: application/json` no longer needs an `exec` block. \"automatic\" is the default and behaves exactly as before, \"own\" allows any other type (#1983)\n`getSchedules()` returned the schedules of the time wizard of **all** scripts, even without the argument `true`. Now only the schedules of the own script are returned (#2164)\n`clearSchedule()` did not accept the objects that `getSchedules()` returns for schedules of the time wizard, so such a schedule stayed in the script and in the schedule counter (#2164)\n`clearSchedule()` can now clear the CRON jobs of other scripts too, as documented for `getSchedules(true)` (#2164)\n`getSchedules()` no longer lists the already canceled schedules of the own script in an `onStop` callback (#2164)",
45
58
  "de": "Beim Export im Klartext wurden die Dateien nach der Skript-ID anstatt nach dem Skriptnamen benannt. Dadurch wurde jeder Punkt im Namen als Unterstrich dargestellt – beispielsweise wurde `HK-Balkontuer_v0.1` als `HK-Balkontuer_v0_1.js` exportiert, und beim erneuten Import wurde das Skript entsprechend umbenannt. Die Dateien sind nun nach dem Skript benannt (#2364).\nBeim Importieren eines Klartextexports wurde ein Punkt im Dateinamen als Ordnerebene interpretiert, sodass `PW-TV-Control_v0.6.js` einen Ordner `PW-TV-Control_v0` mit einem Skript namens `6` erstellte. Nur die Verzeichnisse der ZIP-Datei sind jetzt Ordner (#2364).\nDie Ordnersymbole im Skriptbaum wurden mit weniger als der halben Größe der daneben liegenden Skriptsymbole dargestellt: Sie hatten einen Innenabstand (Padding), und da `CssBaseline` `box-sizing: border-box` festlegt, wurde dieser Innenabstand von ihren 20 Pixeln abgezogen, anstatt addiert zu werden. Sie verwenden nun einen Außenabstand (Margin), wie es bei den Skriptsymbolen immer der Fall war (#2360).\nDer Bereich unterhalb des Editors konnte nicht in der Größe angepasst werden, solange ein Skript geöffnet war: Der Editorbereich berechnete seine Höhe anhand der erwarteten Höhe der Tabs und der Symbolleiste, ragte über den unteren Rand des Fensters hinaus und verdeckte den 8-Pixel-Trennstreifen mit der horizontalen Scrollleiste des Editors, wodurch der Mausklick blockiert wurde. Die drei Bereiche teilen sich nun die Höhe als Flexbox-Spalte (#2351).\nDie Skriptliste schnitt lange Namen ab, obwohl daneben noch Platz war: Der Platz für die Schaltflächen am Ende einer Zeile betrug feste 185 Pixel, was mehr ist, als die drei Schaltflächen einnehmen, und die Spalte für die Symbole nicht berücksichtigte.\nDer Blockly-Kommentarblock wurde korrigiert: Der Text wurde in Weiß auf dem gelben Block geschrieben und war unlesbar, der Editor öffnete sich an einer anderen Stelle auf der Seite anstatt über dem Block, und auf einem Smartphone oder Tablet öffnete er sich überhaupt nicht und der gesamte Arbeitsbereich war unbrauchbar, bis die Seite neu geladen wurde (#2348).\nDas Problem mit der Skriptspiegelung für Ordnernamen, die reguläre Ausdrücke enthalten, wurde behoben: Ein Ordner namens z. B. `Lampen (Flur` brach die Synchronisierung mit einem `SyntaxError` ab, ein Ordner namens z. B. `[ab]` synchronisierte stillschweigend die Skripte eines anderen Ordners (#2239).\nDer Blockly-Block „http (POST)“ hat einen „Content-Type“-Selektor erhalten, sodass eine API, die auf `Content-Type: application/json` besteht, keinen `exec`-Block mehr benötigt. „automatic“ ist die Standardeinstellung und verhält sich wie zuvor, „own“ erlaubt jeden anderen Typ (#1983).\n`getSchedules()` gab die Zeitpläne des Zeitassistenten **aller** Skripte zurück, selbst ohne das Argument `true`. Jetzt werden nur noch die Zeitpläne des eigenen Skripts zurückgegeben (#2164).\n`clearSchedule()` akzeptierte die Objekte nicht, die `getSchedules()` für Zeitpläne des Zeitassistenten zurückgibt, sodass ein solcher Zeitplan im Skript und im Zeitplanzähler verblieb (#2164).\n`clearSchedule()` kann nun auch die CRON-Jobs anderer Skripte löschen, wie für `getSchedules(true)` dokumentiert (#2164).\n`getSchedules()` listet die bereits abgebrochenen Zeitpläne des eigenen Skripts nicht mehr in einem `onStop`-Callback auf (#2164).",
@@ -117,19 +130,6 @@
117
130
  "pl": "Dodano możliwość wykonywania skryptów jednokierunkowych bez zapisywania ich",
118
131
  "uk": "Додана можливість виконання односторонніх скриптів без їх збереження.",
119
132
  "zh-cn": "新增了执行单向脚本而不保存的功能。"
120
- },
121
- "9.3.0": {
122
- "en": "Implemented the support for credentials manager in the configuration\nAdded the possiblilty to execute scripts from AI agent",
123
- "de": "Die Unterstützung für den Anmeldeinformationsmanager wurde in der Konfiguration implementiert.\nEs wurde die Möglichkeit hinzugefügt, Skripte vom KI-Agenten auszuführen.",
124
- "ru": "В конфигурацию добавлена поддержка менеджера учетных данных.\nДобавлена возможность выполнения скриптов из ИИ-агента.",
125
- "pt": "Implementei o suporte para o gerenciador de credenciais na configuração.\nAdicionada a possibilidade de executar scripts a partir de um agente de IA.",
126
- "nl": "De ondersteuning voor de referentiebeheerder is geïmplementeerd in de configuratie.\nDe mogelijkheid om scripts uit te voeren via een AI-agent is toegevoegd.",
127
- "fr": "La prise en charge du gestionnaire d'identifiants a été implémentée dans la configuration.\nAjout de la possibilité d'exécuter des scripts depuis un agent d'IA",
128
- "it": "Implementato il supporto per il gestore delle credenziali nella configurazione\nAggiunta la possibilità di eseguire script dall'agente IA",
129
- "es": "Se implementó la compatibilidad con el administrador de credenciales en la configuración.\nSe agregó la posibilidad de ejecutar scripts desde el agente de IA.",
130
- "pl": "Wprowadzono obsługę menedżera poświadczeń w konfiguracji\nDodano możliwość wykonywania skryptów z poziomu agenta AI",
131
- "uk": "Реалізовано підтримку менеджера облікових даних у конфігурації\nДодано можливість виконання скриптів з агента штучного інтелекту",
132
- "zh-cn": "在配置中实现了对凭据管理器的支持\n增加了从 AI 代理执行脚本的功能。"
133
133
  }
134
134
  },
135
135
  "platform": "Javascript/Node.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.javascript",
3
- "version": "10.1.3",
3
+ "version": "10.1.4",
4
4
  "description": "Rules Engine for ioBroker",
5
5
  "author": "bluefox <dogafox@gmail.com>",
6
6
  "contributors": [
@@ -49,7 +49,7 @@
49
49
  "jszip": "^3.10.1",
50
50
  "node-inspect": "^2.0.0",
51
51
  "node-schedule": "2.1.1",
52
- "nodemailer": "^9.0.6",
52
+ "nodemailer": "^9.1.1",
53
53
  "prettier": "^3.9.6",
54
54
  "promisify-child-process": "^5.0.1",
55
55
  "semver": "^7.8.5",
@@ -1,242 +0,0 @@
1
- import{o as e}from"./rolldown-runtime-C0FnF6B9.js";import{t}from"./vite-preload-helper-B7qeedMF.js";import{An as n,Bt as r,Cn as i,Dn as a,En as o,Ht as s,Jn as c,Lt as l,Rn as u,Ut as d,Vt as f,Xt as p,Yn as m,Zt as h,_r as g,br as _,bt as v,f as y,fr as b,kn as x,mn as S,mr as C,pn as w,st as T,ut as E,vt as D,wr as O,xn as k,yn as A,yr as j,yt as M,zt as N}from"./_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BAOcdAz5.js";import{b as P,f as ee,m as F,p as I,s as L}from"./index-4M2aGX3M.js";var R=u(c(`path`,{d:`M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m5 11h-4v4h-2v-4H7v-2h4V7h2v4h4z`}),`AddCircleOutlined`),z=u(c(`path`,{d:`M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4zM17 11h-4v4h-2v-4H7V9h4V5h2v4h4z`}),`AddComment`),B=u(c(`path`,{d:`M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10h5v-2h-5c-4.34 0-8-3.66-8-8s3.66-8 8-8 8 3.66 8 8v1.43c0 .79-.71 1.57-1.5 1.57s-1.5-.78-1.5-1.57V12c0-2.76-2.24-5-5-5s-5 2.24-5 5 2.24 5 5 5c1.38 0 2.64-.56 3.54-1.47.65.89 1.77 1.47 2.96 1.47 1.97 0 3.5-1.6 3.5-3.57V12c0-5.52-4.48-10-10-10m0 13c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3`}),`AlternateEmail`),V=u(c(`path`,{d:`M9.01 14H2v2h7.01v3L13 15l-3.99-4zm5.98-1v-3H22V8h-7.01V5L11 9z`}),`CompareArrows`),te=u(c(`path`,{d:`M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4m0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4`}),`Person`),H=u(c(`path`,{d:`M3 10h11v2H3zm0-4h11v2H3zm0 8h7v2H3zm17.59-2.07-4.25 4.24-2.12-2.12-1.41 1.41L16.34 19 22 13.34z`}),`PlaylistAddCheck`),U=u(c(`path`,{d:`M20 9V7c0-1.1-.9-2-2-2h-3c0-1.66-1.34-3-3-3S9 3.34 9 5H6c-1.1 0-2 .9-2 2v2c-1.66 0-3 1.34-3 3s1.34 3 3 3v4c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-4c1.66 0 3-1.34 3-3s-1.34-3-3-3M7.5 11.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5S9.83 13 9 13s-1.5-.67-1.5-1.5M16 17H8v-2h8zm-1-4c-.83 0-1.5-.67-1.5-1.5S14.17 10 15 10s1.5.67 1.5 1.5S15.83 13 15 13`}),`SmartToy`);O();var W=e(T(),1),G=t(()=>import(`./docs-compact-D7rpMc7r.js`),[],import.meta.url),K={openai:`img/openai.svg`,anthropic:`img/anthropic.svg`,gemini:`img/gemini.svg`,deepseek:`img/deepseek.svg`,custom:`img/custom.svg`},q={width:16,height:16,flexShrink:0,opacity:.7},ne={ru:`Russian`,en:`English`,de:`German`,es:`Spanish`,fr:`French`,it:`Italian`,pl:`Polish`,nl:`Dutch`,pt:`Portuguese`,uk:`Ukrainian`,"zh-cn":`Chinese`},J=null,Y=null,X=null,Z=null;function re(){J=null,Y=null,X=null,Z=null}async function ie(e,t){if(J)return J;let n=Object.keys(t)[0];if(!n)return null;let r=await e.sendTo(n,`getAvailableAiProviders`,{}),i=((r==null?void 0:r.providers)||[]).map(e=>e.provider),a=((r==null?void 0:r.providers)||[]).find(e=>e.provider===`custom`);return i.length?(J={providers:i,gptBaseUrl:a==null?void 0:a.baseUrl},J):null}var ae=`embedding.text-embedding.textembedding.embeddinggemma.embed-.-embed.bge-.mxbai-embed.nomic-embed.arctic-embed.snowflake-arctic-embed.all-minilm.multilingual-e5.jina-embed.voyage-.gecko.paraphrase-multilingual.dall-e.gpt-image.image-edit.-image-preview.-image-latest.flash-image.nano-banana.stable-diffusion.sdxl.midjourney.flux-.imagen.sora.veo-.cogvideo.runway-.lumiere.lyria.whisper.tts-.-tts.speech-.audio-preview.mini-tts.mini-transcribe.-transcribe.native-audio.flash-live.gpt-audio.realtime.bark-.xtts.voicebox.moderation.omni-moderation.llama-guard.shieldgemma.prompt-guard.-guardian.safeguard.rerank.reranker.babbage-.davinci-.curie-.text-ada-.text-davinci.text-curie.text-babbage.instructgpt.code-davinci.code-cushman.-turbo-instruct.-search-preview.-search-api.code-search.text-search.similarity-.computer-use-preview.deep-research.robotics.aqa.reader-lm.-nsql.minicheck`.split(`.`);function oe(e){let t=e.toLowerCase();return!(ae.some(e=>t.includes(e))||t.startsWith(`claude-1`)||t.startsWith(`claude-instant`))}async function se(e,t){let n=await ie(e,t);if(!n)return{models:[],providerMap:{},errors:[`No API keys configured`]};let r=Object.keys(t)[0];if(!r)return{models:[],providerMap:{},errors:[y.t(`No running javascript instance found`)]};let i=[],a={},o=[],s=(e,t)=>{for(let n of e)oe(n)&&(a[n]||(i.push(n),a[n]=t))},c=[],l=(t,n)=>{c.push(e.sendTo(r,`testApiConnection`,{provider:t===`custom`?`openai`:t}).then(e=>{e.models?s(e.models,t):e.error&&o.push(`${n||t}: ${e.error}`)}).catch(e=>{o.push(`${n||t}: ${String(e)}`)}))},u={openai:`OpenAI`,anthropic:`Anthropic`,gemini:`Gemini`,deepseek:`DeepSeek`,custom:`Custom`};for(let e of n.providers)l(e,u[e]);return await Promise.all(c),i.sort(),{models:i,providerMap:a,errors:o}}async function ce(e,t,n){var r;return await e.sendTo(t,`chatCompletion`,{timeout:n.timeout||6e5,model:n.model,provider:n.provider,messages:n.messages,...n.baseUrl?{baseUrl:n.baseUrl}:{},...(r=n.tools)!=null&&r.length?{tools:n.tools}:{}})}async function le(e){if(Z)return Z;let t=await e.getObjectViewSystem(`state`,``,`香`),n=await e.getObjectViewSystem(`channel`,``,`香`),r=await e.getObjectViewSystem(`device`,``,`香`),i=await e.getObjectViewSystem(`folder`,``,`香`),a=await e.getObjectViewSystem(`enum`,``,`香`);return Z=Object.assign(t,n,r,i,a),Z}async function ue(e){return le(e)}function de(e,t){return e&&typeof e==`object`?e[t]||e.en:e||``}async function fe(e){if(Y)return Y;let t=y.getLanguage(),n=await le(e),r=Object.keys(n).sort(),i=new W.default,a=[],o=[`UNREACH_STICKY`],s=[W.Types.info],c=[],l=[],u=[],d=[];r.forEach(e=>{var t,r;((t=n[e])==null?void 0:t.type)===`enum`?c.push(e):(r=n[e])!=null&&(r=r.common)!=null&&r.smartName&&d.push(e)}),c.forEach(e=>{e.startsWith(`enum.rooms.`)?l.push(e):e.startsWith(`enum.functions.`)&&u.push(e);let t=n[e].common.members;t!=null&&t.length&&t.forEach(e=>{n[e]&&!d.includes(e)&&d.push(e)})});let f={id:``,objects:n,_keysOptional:r,_usedIdsOptional:a,ignoreIndicators:o,excludedTypes:s},p=[];d.forEach(e=>{f.id=e;let r=i.detect(f);r&&r.forEach(e=>{var r;let i=(r=e.states.find(e=>e.id))==null?void 0:r.id;if(!i||p.find(e=>e.id===i))return;let a=n[i],o={id:i,name:de(a.common.name,t),type:a.type,deviceType:e.type,states:e.states.filter(e=>e.id).map(e=>({id:e.id,name:e.name,role:e.defaultRole,type:n[e.id].common.type,unit:n[e.id].common.unit,read:n[e.id].common.read??!0,write:n[e.id].common.write??!0}))},s=i.split(`.`),c,d;(a.type===`channel`||a.type===`state`)&&(s.pop(),c=s.join(`.`),n[c]&&(n[c].type===`channel`||n[c].type===`folder`)?(s.pop(),d=s.join(`.`),(!n[d]||n[d].type!==`device`&&n[c].type!==`folder`)&&(d=void 0)):c=void 0);let f=l.find(e=>{var t,r,a;return(t=n[e].common.members)!=null&&t.includes(i)||c&&(r=n[e].common.members)!=null&&r.includes(c)?!0:d&&((a=n[e].common.members)==null?void 0:a.includes(d))});f&&(o.room=de(n[f].common.name,t));let m=u.find(e=>{var t,r,a;return(t=n[e].common.members)!=null&&t.includes(i)||c&&(r=n[e].common.members)!=null&&r.includes(c)?!0:d&&((a=n[e].common.members)==null?void 0:a.includes(d))});m&&(o.function=de(n[m].common.name,t)),p.push(o)})});for(let e=0;e<p.length;e++){let r=p[e];if(r.type===`state`||r.type===`channel`){let e=r.id.split(`.`);e.pop();let i=n[e.join(`.`)];if(i&&(i.type===`channel`||i.type===`device`||i.type===`folder`)){var m,h;r.name=de(((m=i.common)==null?void 0:m.name)||r.name,t),e.pop();let a=n[e.join(`.`)];if((a==null?void 0:a.type)===`device`&&(h=a.common)!=null&&h.icon){var g;r.name=de(((g=a.common)==null?void 0:g.name)||r.name,t)}}else{var _;r.name=de((i==null||(_=i.common)==null?void 0:_.name)||r.name,t)}}}return Y=p,p}async function pe(){return X||(X=(await G).default,X)}function me(){return ne[y.getLanguage()]||`English`}function he(e){return`You write ioBroker JavaScript adapter scripts.
2
- Copy EXACTLY this syntax. Do NOT change the callback signature.
3
- IMPORTANT: Write all code at top level. NEVER use console.log (use log instead). NEVER define functions with the function keyword.
4
-
5
- // CORRECT: on() always has ONE callback argument called obj
6
- on('zigbee.0.sensor.state', (obj) => {
7
- // obj.state.val = the new value (boolean or number)
8
- // obj.id = the state ID that changed
9
- setState('zigbee.0.lamp.state', obj.state.val);
10
- log('Changed to ' + obj.state.val);
11
- });
12
-
13
- // CORRECT: on() with filter
14
- on({id: /zigbee\\.0\\..*\\.state$/, change: 'ne'}, (obj) => {
15
- if (obj.state.val === true) {
16
- setState('zigbee.0.other.state', true);
17
- }
18
- });
19
-
20
- // Other correct examples:
21
- setState('id', true);
22
- setState('id', 50);
23
- const val = getState('id').val;
24
- schedule('0 7 * * *', () => { log('runs daily at 07:00'); });
25
- schedule('0 22 * * *', () => { setState('id', false); });
26
-
27
- // CORRECT Telegram: always use sendTo, NEVER setState on telegram
28
- sendTo('telegram.0', 'send', {text: 'Alert: ' + someValue});
29
-
30
- // CORRECT httpGet: res.data is a STRING, parse JSON with JSON.parse
31
- httpGet('https://api.example.com/data', (err, res) => {
32
- const data = JSON.parse(res.data);
33
- log('Temperature: ' + data.main.temp);
34
- });
35
-
36
- $('state[state.id=*.state](rooms=Room)').each((id) => { setState(id, false); });
37
- createState('name', 0, {type: 'number', name: 'Name'});
38
- // CORRECT: one-time delayed action (turn off after 5 minutes = 300000ms)
39
- setStateDelayed('zigbee.0.lamp.state', false, false, 5 * 60 * 1000);
40
- log(formatDate(new Date(), 'DD.MM.YYYY hh:mm'));
41
-
42
- WRONG: on('id', (id, state) => {}) CORRECT: on('id', (obj) => {})
43
- WRONG: set('id', true) CORRECT: setState('id', true)
44
- WRONG: adapter.setState('id', true) CORRECT: setState('id', true)
45
- WRONG: obj.val or newState.val CORRECT: obj.state.val
46
- WRONG: on('change', {id: 'x'}, cb) CORRECT: on({id: 'x', change: 'ne'}, cb)
47
- WRONG: setState('telegram.0', text) CORRECT: sendTo('telegram.0', 'send', {text: text})
48
- WRONG: res.body.main.temp CORRECT: JSON.parse(res.data).main.temp
49
- WRONG: function myFunc() {} CORRECT: write code directly, no function definitions
50
- WRONG: setTimeout(fn, ms) CORRECT: setStateDelayed(id, val, false, ms) for one-time delay
51
- WRONG: schedule('*/5 * * * *', fn) for one-time delay. schedule() is ONLY for recurring tasks
52
- Values are boolean (true/false) or numbers, NEVER strings like 'ON'/'OFF'.
53
- NEVER use: function keyword, require, import, setInterval, setTimeout, console.log, debug().
54
-
55
- All available functions (use syntax from examples above):
56
- on(pattern, (obj)=>{}) | once(pattern, (obj)=>{}) | unsubscribe(handler)
57
- setState(id, val) | getState(id).val | setStateChanged(id, val) | setStateDelayed(id, val, ack, ms) | clearStateDelayed(id)
58
- existsState(id) | existsObject(id) | getObject(id) | setObject(id, obj) | extendObject(id, obj) | deleteObject(id)
59
- createState(name, initVal, {type,name,role}) | deleteState(name) | createAlias(name, alias)
60
- schedule(cron, ()=>{}) | clearSchedule(obj) | scheduleById(id, (obj)=>{}) | getSchedules()
61
- sendTo(adapter, cmd, msg) | sendToHost(host, cmd, msg)
62
- $('selector').each((id)=>{}) | $('selector').setState(val) | $('selector').getState()
63
- log(text) | formatDate(date, 'DD.MM.YYYY hh:mm') | formatTimeDiff(ms) | formatValue(val, decimals)
64
- getDateObject(str) | getAstroDate(pattern) | isAstroDay() | compareTime(start, end, op)
65
- exec(cmd, (err,stdout,stderr)=>{}) | httpGet(url, (err,res)=>{}) | httpPost(url, data, (err,res)=>{})
66
- readFile(adapter, name, (err,data)=>{}) | writeFile(adapter, name, data, cb) | delFile(adapter, name, cb)
67
- onFile(id, name, withFile, cb) | offFile(id, name) | onStop(cb, timeout)
68
- getHistory(inst, {id,start,end,aggregate,count}, cb) | getEnums(name) | getIdByName(name)
69
- wait(ms) | toInt(val) | toFloat(val) | toBoolean(val)
70
- messageTo(target, data) | onMessage(name, cb) | onLog(severity, cb)
71
- runScript(name) | startScript(name) | stopScript(name) | isScriptActive(name)
72
-
73
- Write comments in ${e}. Put code in a \`\`\`javascript code block.`}function ge(e){return`You generate ioBroker Blockly XML blocks. Return Blockly XML in a \`\`\`xml code block.
74
- Use EXACT state IDs from the plan. Write text/comments in ${e}.
75
-
76
- IMPORTANT RULES:
77
- - Return ONLY the inner blocks (no <xml> wrapper needed)
78
- - Use the exact block types shown below
79
- - State IDs must be full paths like "zigbee2mqtt.0.0x1234.state"
80
- - Values are boolean (true/false) or numbers, NEVER strings like "ON"/"OFF"
81
- - For Telegram use sendto_custom block, NEVER setState on telegram
82
-
83
- ## Block Templates
84
-
85
- ### Trigger: on_ext (react to state changes)
86
- <block type="on_ext" x="0" y="0">
87
- <mutation xmlns="http://www.w3.org/1999/xhtml" items="1"></mutation>
88
- <field name="CONDITION">ne</field>
89
- <field name="ACK_CONDITION"></field>
90
- <value name="OID0">
91
- <shadow type="field_oid"><field name="oid">STATE_ID_HERE</field></shadow>
92
- </value>
93
- <statement name="STATEMENT">
94
- <!-- actions here -->
95
- </statement>
96
- </block>
97
-
98
- ### Schedule: schedule (cron-based)
99
- <block type="schedule" x="0" y="0">
100
- <field name="SCHEDULE">0 7 * * *</field>
101
- <statement name="STATEMENT">
102
- <!-- actions here -->
103
- </statement>
104
- </block>
105
-
106
- ### Set State: control
107
- <block type="control">
108
- <mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
109
- <field name="OID">STATE_ID_HERE</field>
110
- <field name="WITH_DELAY">FALSE</field>
111
- <value name="VALUE">
112
- <block type="logic_boolean"><field name="BOOL">TRUE</field></block>
113
- </value>
114
- </block>
115
-
116
- ### Get State Value: get_value
117
- <block type="get_value">
118
- <field name="ATTR">val</field>
119
- <field name="OID">STATE_ID_HERE</field>
120
- </block>
121
-
122
- ### Log: debug
123
- <block type="debug">
124
- <field name="Severity">log</field>
125
- <value name="TEXT">
126
- <shadow type="text"><field name="TEXT">Message here</field></shadow>
127
- </value>
128
- </block>
129
-
130
- ### SendTo (Telegram): sendto_custom
131
- <block type="sendto_custom">
132
- <mutation xmlns="http://www.w3.org/1999/xhtml" items="1"></mutation>
133
- <field name="INSTANCE">telegram.0</field>
134
- <field name="COMMAND">send</field>
135
- <field name="LOG"></field>
136
- <value name="ARG0">
137
- <block type="text"><field name="TEXT">Message text</field></block>
138
- </value>
139
- <value name="ATTR0">
140
- <block type="text"><field name="TEXT">text</field></block>
141
- </value>
142
- </block>
143
-
144
- ### Timeout: timeouts_settimeout
145
- <block type="timeouts_settimeout">
146
- <field name="NAME">timeout1</field>
147
- <field name="DELAY">5000</field>
148
- <field name="UNIT">ms</field>
149
- <statement name="STATEMENT">
150
- <!-- delayed actions -->
151
- </statement>
152
- </block>
153
-
154
- ### If/Else: controls_if
155
- <block type="controls_if">
156
- <mutation else="1"></mutation>
157
- <value name="IF0">
158
- <block type="logic_compare">
159
- <field name="OP">EQ</field>
160
- <value name="A"><block type="get_value"><field name="ATTR">val</field><field name="OID">STATE_ID</field></block></value>
161
- <value name="B"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value>
162
- </block>
163
- </value>
164
- <statement name="DO0"><!-- then --></statement>
165
- <statement name="ELSE"><!-- else --></statement>
166
- </block>
167
-
168
- ### Number value
169
- <block type="math_number"><field name="NUM">0</field></block>
170
-
171
- ### Text value
172
- <block type="text"><field name="TEXT">hello</field></block>
173
-
174
- ### Boolean value
175
- <block type="logic_boolean"><field name="BOOL">TRUE</field></block>
176
-
177
- ### Comparison: logic_compare
178
- <block type="logic_compare">
179
- <field name="OP">EQ</field>
180
- <!-- OP can be: EQ, NEQ, LT, LTE, GT, GTE -->
181
- <value name="A"><!-- left side --></value>
182
- <value name="B"><!-- right side --></value>
183
- </block>
184
-
185
- ## Common Patterns
186
-
187
- ### Turn on light when sensor triggers:
188
- <block type="on_ext" x="0" y="0">
189
- <mutation xmlns="http://www.w3.org/1999/xhtml" items="1"></mutation>
190
- <field name="CONDITION">ne</field>
191
- <field name="ACK_CONDITION"></field>
192
- <value name="OID0">
193
- <shadow type="field_oid"><field name="oid">zigbee2mqtt.0.0xSENSOR.occupancy</field></shadow>
194
- </value>
195
- <statement name="STATEMENT">
196
- <block type="controls_if">
197
- <value name="IF0">
198
- <block type="logic_compare">
199
- <field name="OP">EQ</field>
200
- <value name="A"><block type="get_value"><field name="ATTR">val</field><field name="OID">zigbee2mqtt.0.0xSENSOR.occupancy</field></block></value>
201
- <value name="B"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value>
202
- </block>
203
- </value>
204
- <statement name="DO0">
205
- <block type="control">
206
- <mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
207
- <field name="OID">zigbee2mqtt.0.0xLAMP.state</field>
208
- <field name="WITH_DELAY">FALSE</field>
209
- <value name="VALUE"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value>
210
- </block>
211
- </statement>
212
- </block>
213
- </statement>
214
- </block>
215
-
216
- Write comments in ${e}. Put blocks in a \`\`\`xml code block.`}function _e(e){let t=e;return t=t.replace(/<think>[\s\S]*?<\/think>/gi,``),t=t.replace(/<\|endoftext\|>/g,``),t=t.replace(/<\|im_start\|>[\s\S]*?<\|im_end\|>/g,``),t=t.replace(/<\|im_start\|>[\s\S]*/g,``),t.trim()}var ve=[{type:`function`,function:{name:`search_datapoints`,description:`Search ALL ioBroker objects by ID, name, or role — includes states, channels, devices, folders, enums (rooms/functions), adapters, instances, scripts, meta, etc. Returns matching IDs with object type, name, role, unit, and a hasChildren hint for containers. IMPORTANT: Aliases and physical device groupings are usually CHANNELS containing multiple state children (e.g. a motion sensor is often a channel alias.0.Floor.Room.MotionSensor with states ACTUAL, BATTERY, STATE under it). If a channel/device/folder matches your query, call get_object_info on its ID to list its state children. Role-based queries work too: "sensor.motion", "switch.light", "value.temperature".`,parameters:{type:`object`,properties:{query:{type:`string`,description:`Search pattern (case-insensitive substring) - matches against object ID, name, and role. Examples: "bewegungsmelder", "temperature", "sensor.motion", "alias.0", "küche", "zigbee2mqtt.0.lamp".`},max_results:{type:`number`,description:`Maximum number of results to return (default: 20).`},object_type:{type:`string`,description:`Optional filter by object type: "state", "channel", "device", "folder", "enum", "adapter", "instance", "script", "meta", etc. Omit to search every type.`}},required:[`query`]}}},{type:`function`,function:{name:`get_state_value`,description:`Get the current value of an ioBroker state/datapoint. Returns value, timestamp, and acknowledgment flag.`,parameters:{type:`object`,properties:{id:{type:`string`,description:`The full state ID, e.g. "zigbee2mqtt.0.sensor.temperature"`}},required:[`id`]}}},{type:`function`,function:{name:`get_object_info`,description:`Get detailed info about ANY ioBroker object + its full parent hierarchy + direct children. Works for every object type: state, channel, device, folder, adapter, instance, enum, meta, script. Returns: the object itself, parent chain (all non-state ancestors up to the adapter), and — if the object is a container (channel/device/folder/enum/instance/adapter/meta) — the list of direct children with their types, names, roles and units. Use this to navigate the object tree: start from a channel found by search_datapoints, read its children to see the actual state IDs underneath.`,parameters:{type:`object`,properties:{id:{type:`string`,description:`The full object ID, e.g. "zigbee2mqtt.0.0x1234.state", "alias.0.Room.MotionSensor", or "enum.rooms.kitchen".`}},required:[`id`]}}},{type:`function`,function:{name:`search_scripts`,description:`Search through all ioBroker JavaScript/Blockly/Rules scripts. Can search by script name/path OR by content (e.g. find all scripts that use a specific datapoint ID). Returns matching script names, paths, and matching lines.`,parameters:{type:`object`,properties:{query:{type:`string`,description:`Search term - matches against script name, path, AND source code content. Examples: "carport", "zigbee2mqtt.0.lamp.state", "telegram"`},max_results:{type:`number`,description:`Maximum number of scripts to return (default: 10)`}},required:[`query`]}}},{type:`function`,function:{name:`read_script`,description:`Read the full source code of a specific ioBroker script by its ID or path. Use search_scripts first to find the script ID, then read_script to see its complete code.`,parameters:{type:`object`,properties:{id:{type:`string`,description:`The script ID (e.g. "script.js.common.Licht.Carport") or path (e.g. "common/Licht/Carport")`}},required:[`id`]}}},{type:`function`,function:{name:`list_scripts`,description:`List ALL available ioBroker scripts with their names, paths, types (JavaScript/Blockly/TypeScript), and enabled status. Use this to get an overview of all scripts before searching or reading specific ones.`,parameters:{type:`object`,properties:{}}}},{type:`function`,function:{name:`run_script`,description:"Execute a JavaScript or TypeScript snippet in the live ioBroker javascript engine and get back everything it logged. The code runs with the full script API (log, console.*, setState, getState, on, schedule, $, exec, httpGet, …) in VERBOSE mode, so internal operations (setState/getState/subscribe/…) are logged too — ideal for diagnosing behaviour or inspecting values. The snippet runs for a short window and is then automatically STOPPED and fully cleaned up (timers, subscriptions, schedules removed); it does NOT create a persistent script. Use `log(...)` or `console.log(...)` in the code to surface the values you want to inspect. WARNING: side effects are real (e.g. setState changes actual devices) — prefer read-only diagnostics unless the user explicitly asked to change something.",parameters:{type:`object`,properties:{source:{type:`string`,description:`The JavaScript (or TypeScript) source to execute. Log the values you want to inspect via log(...) / console.log(...). Top-level await is supported.`},engineType:{type:`string`,description:`Optional. "TypeScript/ts" to run the code as TypeScript. Defaults to JavaScript.`},timeout:{type:`number`,description:`Optional. Milliseconds to keep the script alive to collect asynchronous logs before it is stopped (default 5000, max 60000). Increase when waiting for timers, subscriptions or HTTP responses.`},logLevel:{type:`string`,description:`Optional minimum severity to return: silly, debug, info, warn, error. Default silly (everything).`}},required:[`source`]}}},{type:`function`,function:{name:`get_editor_selection`,description:`Read what the user has currently selected in the script editor. Returns the selected text and its line/column range, or a message if nothing is selected. Use this when the user refers to "this", "das hier", "the selection", or asks about a specific piece of code they highlighted.`,parameters:{type:`object`,properties:{}}}},{type:`function`,function:{name:`get_editor_content`,description:`Read the full current content of the script editor (may differ from the initial script version if the user has made edits). Use this when you need the live editor state rather than the saved script.`,parameters:{type:`object`,properties:{}}}},{type:`function`,function:{name:`get_cursor_position`,description:`Read the current cursor position (line and column, 1-based) in the script editor.`,parameters:{type:`object`,properties:{}}}},{type:`function`,function:{name:`highlight_text_in_editor`,description:`Search for a literal text in the script editor and select + scroll to it. Returns how many occurrences were found. Use this to draw the user's attention to a specific snippet you are discussing.`,parameters:{type:`object`,properties:{text:{type:`string`,description:`Exact substring to search for (case-sensitive).`}},required:[`text`]}}},{type:`function`,function:{name:`highlight_line_range`,description:`Select and scroll to a range of lines in the editor. Both line numbers are 1-based and inclusive. Use this to show the user which block of code you are referring to.`,parameters:{type:`object`,properties:{start_line:{type:`number`,description:`First line (1-based, inclusive).`},end_line:{type:`number`,description:`Last line (1-based, inclusive).`}},required:[`start_line`,`end_line`]}}},{type:`function`,function:{name:`go_to_line`,description:`Move the cursor to a specific line (and optional column) and scroll that line into view. Use this to navigate the user to a relevant spot.`,parameters:{type:`object`,properties:{line:{type:`number`,description:`1-based line number.`},column:{type:`number`,description:`1-based column (optional, default 1).`}},required:[`line`]}}},{type:`function`,function:{name:`insert_text_at_cursor`,description:`Insert text at the current cursor position in the editor (or replace the current selection if one exists). Use sparingly — prefer returning code in a fenced markdown block so the user can review and smart-apply it. Only use direct insertion when the user explicitly asked you to write something into the editor.`,parameters:{type:`object`,properties:{text:{type:`string`,description:`Text to insert.`}},required:[`text`]}}},{type:`function`,function:{name:`replace_selection`,description:`Replace the currently selected text in the editor with new text. Fails if nothing is selected. Use this to refactor or rewrite a specific highlighted snippet.`,parameters:{type:`object`,properties:{text:{type:`string`,description:`Replacement text.`}},required:[`text`]}}},{type:`function`,function:{name:`get_diagnostics`,description:`Read all active Monaco diagnostics (errors, warnings, info, hints) from the current editor model — this is what shows up as red/yellow squiggles. Use this to find syntax errors, unused variables, missing types, or other editor-reported issues the user might be asking about.`,parameters:{type:`object`,properties:{}}}},{type:`function`,function:{name:`get_document_symbols`,description:`Get the document outline of the current script: all top-level functions, classes, constants, and variables with their line numbers. Use this to understand the structure of a long script or to find where a specific function is defined.`,parameters:{type:`object`,properties:{}}}}];function ye(e){return e&&typeof e==`object`?e.en||e.de||``:e||``}function be(e,t,n){let r=(n||``).toLowerCase();if(!r)return!1;if(e.toLowerCase().includes(r))return!0;let i=t==null?void 0:t.common;if(!i)return!1;let a=ye(i.name).toLowerCase();if(a&&a.includes(r))return!0;let o=(i.role||``).toLowerCase();return!!(o&&o.includes(r))}async function xe(e,t,n=20,r){let i=await ue(e),a=r==null?void 0:r.toLowerCase(),o=[],s=Object.keys(i),c=new Set;for(let e of s){let t=e.lastIndexOf(`.`);t>0&&c.add(e.substring(0,t))}for(let e of s){let r=i[e],s=r==null?void 0:r.type;if(!s||a&&s!==a||!be(e,r,t))continue;let l=r.common,u={id:e,type:s,name:ye(l==null?void 0:l.name)};if(l!=null&&l.role&&(u.role=l.role),s===`state`?(u.stateType=(l==null?void 0:l.type)||``,l!=null&&l.unit&&(u.unit=l.unit)):c.has(e)&&(u.hasChildren=!0),o.push(u),o.length>=n)break}return o.length===0?JSON.stringify({message:`No objects found matching "${t}". Hint: try a role like "sensor.motion" or a partial path.`}):JSON.stringify(o)}async function Se(e,t){try{let n=await e.getState(t);return JSON.stringify(n?{val:n.val,ts:n.ts?new Date(n.ts).toISOString():null,ack:n.ack,from:n.from}:{error:`State '${t}' not found`})}catch{return JSON.stringify({error:`Failed to read state '${t}'`})}}var Ce=new Set([`channel`,`device`,`folder`,`adapter`,`instance`,`enum`,`meta`]),we=50;async function Te(e,t){try{let r=await e.getObject(t);if(!r)return JSON.stringify({error:`Object '${t}' not found`});let i={id:r._id,type:r.type,common:r.common},a=t.split(`.`),o=[];for(let t=a.length-1;t>=2;t--){let r=a.slice(0,t).join(`.`);try{let t=await e.getObject(r);if(t&&t.type!==`state`){var n;o.push({id:t._id,type:t.type,name:ye((n=t.common)==null?void 0:n.name),common:t.common})}}catch{}}if(o.length>0&&(i.parents=o),Ce.has(r.type)){let n=await ue(e),r=[],a=`${t}.`,o=!1;for(let e of Object.keys(n))if(e.startsWith(a)&&!e.substring(a.length).includes(`.`)){let t=n[e],i=t==null?void 0:t.common,a={id:e,name:ye(i==null?void 0:i.name),type:(t==null?void 0:t.type)||``};if(i!=null&&i.role&&(a.role=i.role),(t==null?void 0:t.type)===`state`&&i!=null&&i.unit&&(a.unit=i.unit),r.push(a),r.length>=we){o=!0;break}}r.length>0&&(i.children=r,o&&(i.childrenTruncated=!0,i.childrenHint=`Only the first ${we} children are shown. Use search_datapoints with a more specific query or the object_type filter to narrow down.`))}return JSON.stringify(i)}catch{return JSON.stringify({error:`Failed to read object '${t}'`})}}function Ee(e){return I(e)||e}function De(e,t,n=10){let r=t.toLowerCase(),i=[];for(let t of e){let e=t.id.toLowerCase(),a=t.name.toLowerCase(),o=t.id.replace(/^script\.js\./,``).replace(/\./g,`/`),s=t.engineType===`Blockly`||t.engineType===`Rules`,c=e.includes(r)||a.includes(r),l=s?Ee(t.source):t.source,u=l.toLowerCase().includes(r);if(c||u){let e={id:t.id,path:o,name:t.name,type:s?`Blockly`:t.engineType.includes(`TypeScript`)?`TypeScript`:`JavaScript`,enabled:t.enabled};if(u){let t=l.split(`
217
- `),n=[];for(let e=0;e<t.length&&!(t[e].toLowerCase().includes(r)&&(n.push({line:e+1,text:t[e].trim()}),n.length>=5));e++);n.length>0&&(e.matchingLines=n)}if(i.push(e),i.length>=n)break}}return i.length===0?JSON.stringify({message:`No scripts found matching "${t}"`}):JSON.stringify(i)}function Oe(e,t){let n=t.replace(/\//g,`.`).toLowerCase(),r=e.find(e=>{let t=e.id.toLowerCase();return t===n||t===`script.js.${n}`||t.endsWith(`.${n}`)});if(!r)return JSON.stringify({error:`Script '${t}' not found. Use search_scripts to find available scripts.`});let i=r.engineType===`Blockly`||r.engineType===`Rules`,a=i?Ee(r.source):r.source,o=r.id.replace(/^script\.js\./,``).replace(/\./g,`/`);return JSON.stringify({id:r.id,path:o,name:r.name,type:i?`Blockly`:r.engineType.includes(`TypeScript`)?`TypeScript`:`JavaScript`,enabled:r.enabled,source:a})}function ke(e){let t=e.map(e=>({id:e.id,path:e.id.replace(/^script\.js\./,``).replace(/\./g,`/`),name:e.name,type:e.engineType===`Blockly`||e.engineType===`Rules`?`Blockly`:e.engineType.includes(`TypeScript`)?`TypeScript`:`JavaScript`,enabled:e.enabled}));return JSON.stringify(t)}function Q(){return JSON.stringify({error:`Editor is not available. This tool requires the script editor to be open.`})}async function Ae(e,t,n){if(!t)return JSON.stringify({error:`No running javascript instance found to execute the script.`});let r=n.source;if(!r||typeof r!=`string`)return JSON.stringify({error:`No source code provided.`});try{var i;let a=await e.sendTo(t,`execute`,{source:r,engineType:n.engineType,timeout:n.timeout,logLevel:n.logLevel});return!a||a.ok===!1?JSON.stringify({error:(a==null?void 0:a.error)||`Execution failed`,logs:(a==null?void 0:a.logs)||[]}):JSON.stringify({engineType:a.engineType,runtime:a.runtime,truncated:a.truncated||!1,logCount:((i=a.logs)==null?void 0:i.length)||0,logs:a.logs||[],output:a.output||``})}catch(e){return JSON.stringify({error:`Failed to execute script: ${e instanceof Error?e.message:String(e)}`})}}async function je(e,t,n,r,i){let a;try{a=JSON.parse(t.function.arguments)}catch{return JSON.stringify({error:`Invalid arguments: ${t.function.arguments}`})}switch(t.function.name){case`search_datapoints`:return xe(e,a.query,a.max_results||20,a.object_type);case`get_state_value`:return Se(e,a.id);case`get_object_info`:return Te(e,a.id);case`search_scripts`:return De(n||[],a.query,a.max_results||10);case`read_script`:return Oe(n||[],a.id);case`list_scripts`:return ke(n||[]);case`run_script`:return Ae(e,i,a);case`get_editor_selection`:{if(!(r!=null&&r.getSelection))return Q();let e=r.getSelection();return JSON.stringify(e||{message:`No text is currently selected in the editor.`})}case`get_editor_content`:return r!=null&&r.getContent?JSON.stringify({content:r.getContent()}):Q();case`get_cursor_position`:{if(!(r!=null&&r.getCursorPosition))return Q();let e=r.getCursorPosition();return JSON.stringify(e||{message:`Editor has no cursor position (not focused).`})}case`highlight_text_in_editor`:{if(!(r!=null&&r.highlightText))return Q();let e=r.highlightText(a.text);return JSON.stringify({matches:e,message:e===0?`Text "${a.text}" was not found in the editor.`:`Highlighted ${e} occurrence(s) of "${a.text}".`})}case`highlight_line_range`:{if(!(r!=null&&r.highlightLineRange))return Q();let e=r.highlightLineRange(a.start_line,a.end_line);return JSON.stringify({success:e,message:e?`Selected lines ${a.start_line}-${a.end_line}.`:`Could not select the requested line range.`})}case`go_to_line`:{if(!(r!=null&&r.goToLine))return Q();let e=r.goToLine(a.line,a.column);return JSON.stringify({success:e,message:e?`Cursor moved to line ${a.line}.`:`Could not move the cursor.`})}case`insert_text_at_cursor`:{if(!(r!=null&&r.insertTextAtCursor))return Q();let e=r.insertTextAtCursor(a.text);return JSON.stringify({success:e,message:e?`Text inserted at cursor.`:`Editor rejected the insertion.`})}case`replace_selection`:{if(!(r!=null&&r.replaceSelection))return Q();let e=r.replaceSelection(a.text);return JSON.stringify({success:e,message:e?`Selection replaced.`:`No text was selected to replace.`})}case`get_diagnostics`:{if(!(r!=null&&r.getDiagnostics))return Q();let e=r.getDiagnostics();return JSON.stringify({count:e.length,diagnostics:e})}case`get_document_symbols`:{if(!(r!=null&&r.getSymbols))return Q();let e=await r.getSymbols();return JSON.stringify({count:e.length,symbols:e})}default:return JSON.stringify({error:`Unknown tool: ${t.function.name}`})}}var Me=0;function Ne(){return`msg_${Date.now()}_${++Me}`}function Pe(e){let{socket:n,runningInstances:r,currentCode:i,currentLanguage:a,allScripts:o,editorApi:s,currentScriptId:c}=e,l=b((e,t,n)=>e===`none`||!n?null:{range:t,scriptId:c||``,scriptVersion:(i||``).length,kind:e,originalText:n},[c,i]),[u,d]=_(()=>{try{let e=window.localStorage.getItem(`Editor.aiChatMessages`);return e?JSON.parse(e):[]}catch{return[]}}),f=b(e=>{d(t=>{let n=typeof e==`function`?e(t):e,r=n.length>100?n.slice(-100):n;try{window.localStorage.setItem(`Editor.aiChatMessages`,JSON.stringify(r))}catch{try{let e=r.slice(-20);window.localStorage.setItem(`Editor.aiChatMessages`,JSON.stringify(e))}catch{}}return r})},[]),[p,m]=_(!1),[h,g]=_(null),[v,x]=_(window.localStorage.getItem(`Editor.aiChatMode`)||`agent`),S=b(e=>{x(e),window.localStorage.setItem(`Editor.aiChatMode`,e)},[]),[w,T]=_(null),[E,D]=_(window.localStorage.getItem(`openai-model`)||``),[O,k]=_([]),[A,M]=_({}),[N,P]=_(!0),[I,L]=_(null),R=j(null),z=j(null),B=j(null),V=j(null),te=b(e=>{D(e),window.localStorage.setItem(`openai-model`,e)},[]),H=b(async()=>{P(!0),L(null);try{let e=await se(n,r);if(k(e.models),M(e.providerMap),e.models.length>0){let t=window.localStorage.getItem(`openai-model`);t&&e.models.includes(t)?D(t):D(e.models[0])}e.errors.length>0&&L(e.errors.join(`; `))}catch(e){L(String(e))}P(!1)},[n,r]);C(()=>{H()},[H]);let U=b(e=>{let t=!1,n=!1,r=[],i=!1,a=/@([\w/äöüÄÖÜß-]+)/g,s;for(;(s=a.exec(e))!==null;){let e=s[1].toLowerCase();if(e===`alle`||e===`all`)t=!0;else if(e===`geräte`||e===`devices`||e===`geraete`)n=!0;else if(i=!0,o&&o.length>0){let e=s[1].replace(/\//g,`.`).toLowerCase(),t=e.split(`.`),n=o.find(n=>{let r=n.id.toLowerCase(),i=r.replace(/^script\.js\./,``);if(i===e||i.endsWith(`.${e}`)||r===`script.js.${e}`)return!0;let a=0;for(let e of t){let t=i.indexOf(e,a);if(t===-1)return!1;a=t+e.length}return!0});if(n)r.push(n.id);else for(let e of t){if(e.length<3)continue;let t=o.filter(t=>t.id.toLowerCase().includes(`.${e}`)||t.name.toLowerCase().includes(e));for(let e of t)r.includes(e.id)||r.push(e.id)}}}return i&&r.length===0&&(t=!0),{cleanMessage:e.replace(/@[\w/äöüÄÖÜß]+\s*/g,``).trim(),mentionedScriptIds:r,includeAll:t,includeDevices:n}},[o]),W=b(async(e,t,s)=>{V.current||=await pe(),R.current||=await ie(n,r);let c=me(),l=a===`blockly`,u=e||s.length>0,d=`You are an AI assistant for ioBroker JavaScript adapter scripting. Help the user write, debug, and understand ioBroker scripts. Write comments in ${c}. Use the ioBroker JavaScript API correctly.
218
-
219
- ioBroker object hierarchy: adapter.instance.device.channel.state
220
- - A "state" is a single datapoint (e.g. zigbee2mqtt.0.0x1234.temperature)
221
- - A "channel" groups related states (e.g. zigbee2mqtt.0.0x1234 contains temperature, humidity, battery)
222
- - A "device" groups channels (e.g. zigbee2mqtt.0.0x1234)
223
- - The channel/device often has the human-readable name (e.g. "Living Room Sensor")
224
- When looking up info about a datapoint, ALWAYS also check its parent channel/device for the device name and context. Use get_object_info which returns the full parent hierarchy automatically.
225
-
226
- To verify code or diagnose runtime behaviour, you can use the run_script tool: it executes a JavaScript/TypeScript snippet in the live engine (verbose mode) and returns everything it logged, then auto-stops it. Log the values you want to inspect via log(...) / console.log(...). It runs against the live system, so prefer read-only diagnostics (getState, $, getObject) and only call setState when the user explicitly asked to change something.
227
-
228
- Available API and syntax rules:
229
- ${V.current}`;if(l&&(d+="\n\nThe user is working in the Blockly visual editor. When asked to create or modify code, respond with Blockly XML in a ```xml code block instead of JavaScript."),(t||e)&&(B.current||=await fe(n),d+=`\n\nAvailable smart home devices:\n${JSON.stringify(B.current,null,0)}`),!u&&i){if(l){let e=i.indexOf(`%%BLOCKLY_XML%%`),t=e===-1?i:i.substring(0,e).trim(),n=e===-1?``:i.substring(e+15).trim();d+=`\n\nThe user is working on this Blockly script (currently open in the editor).\n\nGenerated JavaScript (shows the logic):\n\`\`\`javascript\n${t}\n\`\`\``,n&&(d+=`\n\nBlockly XML (use for modifications):\n\`\`\`xml\n${n}\n\`\`\``)}else d+=`\n\nThe user's question is about this script (currently open in the editor, ${a||`javascript`}):\n\`\`\`${a||`javascript`}\n${i}\n\`\`\``}if(e&&o&&o.length>0)d+=`\n\nThe user requested ALL scripts. Search through all of them to answer the question. Always identify WHICH script you describe by its full ID. Scripts may reference datapoint IDs via variables.\n\n${ee(o,!0)}`;else if(s.length>0&&o){let e=o.filter(e=>s.includes(e.id));e.length>0&&(d+=`\n\nIMPORTANT: The user is asking about the following script(s). Answer ONLY about these scripts, NOT about the currently open editor tab. Analyze the source code below carefully:\n\n${ee(e,!0)}`)}return l&&(d+=`\n\n${ge(c)}`),[{role:`system`,content:d}]},[n,r,i,a,o]),G=b(async e=>{if(!e.trim()||p)return;let t=A[E];if(!t){T(y.t(`Please select a valid model`));return}let i=R.current||await ie(n,r);if(R.current=i,!i){T(y.t(`No API keys configured`));return}let o=Object.keys(r)[0];if(!o){T(y.t(`No running javascript instance found`));return}let s=t===`custom`&&i.gptBaseUrl||``,c={id:Ne(),role:`user`,content:e,timestamp:Date.now()},l={id:Ne(),role:`assistant`,content:`⏳ ${y.t(`Generating plan...`)}`,timestamp:Date.now()};f(e=>[...e,c,l]),m(!0),T(null);try{let r=me();B.current||=await fe(n);let i=B.current||[],c=`Devices in my smart home:\n${JSON.stringify(i)}\n\nI need a plan for this task: ${e}\n\nAnswer with max 6 lines. Use FULL device IDs from the list above (e.g. zigbee2mqtt.0.0xa4c1383f5ef5fb07.state). No explanation. No reasoning.\n1. IDs: <full IDs from the device list. If a device is not in the list, use TODO_DEVICE_ID as placeholder>\n2. Trigger: <on(id) for state changes OR schedule('min hour * * *') for time-based tasks>\n3. Condition: <when to act>\n4. Actions: <what to set, with full IDs and values. For Telegram use sendTo('telegram.0', 'send', {text: msg})>\n5. Else: <alternative actions or nothing>\n6. Extra: <logging, formatting, etc.>\nValues are boolean (true/false) or numbers, not strings. Use .state not .state_toggle.`,l=await ce(n,o,{messages:[{role:`user`,content:c}],model:E,provider:t,baseUrl:s});if(l.error){T(l.error),f(e=>e.slice(0,-2)),m(!1);return}let u=_e(l.content||``);f(e=>{let t=[...e],n=t[t.length-1];return(n==null?void 0:n.role)===`assistant`&&(t[t.length-1]={...n,content:`📋 **${y.t(`Plan`)}:**\n${u}`}),t});let d={id:Ne(),role:`assistant`,content:`⏳ ${y.t(`Generating code...`)}`,timestamp:Date.now()};f(e=>[...e,d]);let p=a===`blockly`,h=p?`TASK: ${e}\n\nPLAN:\n${u}\n\nGenerate Blockly XML blocks for this ioBroker automation. Use the exact state IDs from the plan. If the plan contains TODO_DEVICE_ID, keep it as a placeholder. Write comments in ${r}. Put the blocks in a \`\`\`xml code block. You may add a short explanation before or after the XML.`:`TASK: ${e}\n\nPLAN:\n${u}\n\nWrite the ioBroker script. Use the exact state IDs from the plan. If the plan contains TODO_DEVICE_ID, keep it as a placeholder with a comment so the user can fill in the correct ID. Write comments in ${r}. Put the code in a \`\`\`javascript code block. You may add a short explanation before or after the code.`,_=p?ge(r):he(r),v=await ce(n,o,{messages:[{role:`system`,content:_},{role:`user`,content:h}],model:E,provider:t,baseUrl:s});if(v.error){T(v.error),f(e=>e.slice(0,-1)),m(!1);return}let b=_e(v.content||``);f(e=>{let t=[...e],n=t[t.length-1];return(n==null?void 0:n.role)===`assistant`&&(t[t.length-1]={...n,content:b}),t}),g(`${y.t(`devices`)}: ${i.length}`)}catch(e){T(String(e)),f(e=>e.slice(0,-1))}m(!1)},[E,A,p,n,r,a,f]),K=b(async e=>{if(v===`code`)return G(e);if(!e.trim()||p)return;let t=A[E];if(!t){T(y.t(`Please select a valid model`));return}let i=R.current||await ie(n,r);if(R.current=i,!i){T(y.t(`No API keys configured`));return}let a=Object.keys(r)[0];if(!a){T(y.t(`No running javascript instance found`));return}let c=z.current;if(z.current=null,!c)try{var d;let e=s==null||(d=s.getSelection)==null?void 0:d.call(s);e&&e.text&&(c=l(`selection`,e.range,e.text))}catch{}let h={id:Ne(),role:`user`,content:e,timestamp:Date.now(),sourceRange:c},_={id:Ne(),role:`assistant`,content:``,timestamp:Date.now(),sourceRange:c};f(e=>[...e,h,_]),m(!0),T(null);let{cleanMessage:b,mentionedScriptIds:x,includeAll:S,includeDevices:C}=U(e),w=[];if(S)w.push(`${y.t(`all scripts`)} (${(o==null?void 0:o.length)||0})`);else if(x.length>0){let e=x.map(e=>e.replace(/^script\.js\./,``));w.push(e.join(`, `))}else w.push(y.t(`current script`));C&&w.push(y.t(`devices`)),g(`${y.t(`Context`)}: ${w.join(` + `)}`);let D=await W(S,C,x),O=t===`custom`&&i.gptBaseUrl||``,k=b||e;if(o&&o.length>0){let e=k.match(/\b[\w-]+\.\d+\.[\w.-]+/g);if(e){let t=[];for(let n of new Set(e)){let e=F(o,n);e.length>0&&t.push(`Datapoint "${n}" is used in:\n${e.map(e=>` - ${e.scriptName} (${e.scriptId}) line ${e.lineNumber}: ${e.usageType} → ${e.line}`).join(`
230
- `)}`)}t.length>0&&(k+=`\n\n[Automatic analysis results]\n${t.join(`
231
-
232
- `)}`)}}let j=[...D,...u.filter(e=>e.role!==`system`).map(e=>({role:e.role,content:e.content})),{role:`user`,content:k}],M=v===`agent`;try{let e=[...j];for(let r=0;r<5;r++){let i=await ce(n,a,{messages:e,model:E,provider:t,baseUrl:O,...M?{tools:ve}:{}});if(i.error){if(M&&r===0&&i.error.toLowerCase().includes(`tool`)){let r=await ce(n,a,{messages:e,model:E,provider:t,baseUrl:O});if(r.error)T(r.error),f(e=>e.slice(0,-1));else{let e=_e(r.content||``);f(t=>{let n=[...t],r=n[n.length-1];return(r==null?void 0:r.role)===`assistant`&&(n[n.length-1]={...r,content:e}),n})}break}T(i.error),f(e=>e.slice(0,-1));break}let c=i.tool_calls;if((!c||c.length===0)&&M&&i.content){let e=i.content.trim();try{let t=JSON.parse(e);t.name&&t.arguments&&(c=[{id:`text_tool_${Date.now()}`,type:`function`,function:{name:t.name,arguments:JSON.stringify(t.arguments)}}])}catch{}}if(!c||c.length===0){let e=_e(i.content||``);f(t=>{let n=[...t],r=n[n.length-1];return(r==null?void 0:r.role)===`assistant`&&(n[n.length-1]={...r,content:e}),n});break}i.tool_calls=c;let l=i.tool_calls.map(e=>{let t={};try{t=JSON.parse(e.function.arguments)}catch{}switch(e.function.name){case`search_datapoints`:return`🔍 ${y.t(`Searching datapoints`)}: "${String(t.query||``)}"`;case`get_state_value`:return`📊 ${y.t(`Reading value`)}: ${String(t.id||``)}`;case`get_object_info`:return`📋 ${y.t(`Loading object info`)}: ${String(t.id||``)}`;case`search_scripts`:return`🔍 ${y.t(`Searching scripts`)}: "${String(t.query||``)}"`;case`read_script`:return`📖 ${y.t(`Reading script`)}: ${String(t.id||``)}`;case`list_scripts`:return`📂 ${y.t(`Loading script list`)}`;default:return`⚙️ ${e.function.name}`}});f(e=>{let t=[...e],n=t[t.length-1];return(n==null?void 0:n.role)===`assistant`&&(t[t.length-1]={...n,content:l.join(`
233
- `)}),t}),e.push({role:`assistant`,content:i.content||``,tool_calls:i.tool_calls});for(let t of i.tool_calls){let r=await je(n,t,o,s,a);e.push({role:`tool`,tool_call_id:t.id,content:r})}}}catch(e){T(String(e)),f(e=>e.slice(0,-1))}m(!1)},[E,A,u,p,n,r,W,U,o,v,G,f,l,s]),q=b(()=>{f([]),T(null),m(!1),g(null),re(),window.localStorage.removeItem(`Editor.aiChatHistory`)},[f]),ne=b(async(e,t)=>{let i=A[E];if(!i)return`Error: ${y.t(`Please select a valid model`)}`;let o=R.current||await ie(n,r);if(R.current=o,!o)return`Error: ${y.t(`No API keys configured`)}`;let s=Object.keys(r)[0];if(!s)return`Error: ${y.t(`No running javascript instance found`)}`;let c=i===`custom`&&o.gptBaseUrl||``,l=a||`javascript`,u=`You are an assistant for writing ioBroker ${l} scripts. The user will ask a question about a snippet of their code. Match your answer to the question: \n- If they ask for an explanation, description, or "what does this do?", reply with clear prose (a few sentences). Do NOT repeat the code unchanged. \n- If they explicitly ask for a change, refactor, fix, or rewrite, reply with a single fenced \`\`\`${l===`blockly`?`xml`:l}\`\`\` code block containing the full replacement for the selection. You may add one short sentence before or after the block. \n- If they ask something ambiguous or meta (e.g. "is this correct?"), reply in prose first and only include code if proposing a change. \nioBroker globals available in scripts: on, setState, getState, schedule, sendTo, log, createState, setStateDelayed, existsState, httpGet, httpPost.`,d=t?`Code from my editor:\n\n\`\`\`${l===`blockly`?`xml`:l}\n${t}\n\`\`\`\n\n${e}`:e;try{let e=await ce(n,s,{messages:[{role:`system`,content:u},{role:`user`,content:d}],model:E,provider:i,baseUrl:c});return e.error?`Error: ${e.error}`:e.content||``}catch(e){return`Error: ${e.message||String(e)}`}},[E,A,r,n,a]);return{messages:u,isLoading:p,error:w,model:E,availableModels:O,modelProviderMap:A,modelsLoading:N,modelsError:I,lastContextInfo:h,mode:v,setMode:S,setModel:te,sendMessage:K,triggerAiAction:b(e=>{e.range&&e.code?z.current=l(e.kind||`codelens`,e.range,e.code):z.current=null,t(async()=>{let{buildActionPrompt:e}=await import(`./aiPromptBuilder-a2bvj40X.js`);return{buildActionPrompt:e}},[],import.meta.url).then(({buildActionPrompt:t})=>{let n=t({action:e.action,code:e.code,language:a||`javascript`,diagnostic:e.diagnostic,question:e.question,rangeLabel:e.rangeLabel});n?K(n):z.current=null}).catch(()=>{z.current=null,T(y.t(`Failed to build AI action prompt`))})},[K,a,l]),askInline:ne,clearChat:q,retryLoadModels:H}}O();var Fe=({code:e,language:t,themeType:n,onInsertCode:r,onShowDiff:i,sourceRange:a})=>{let o=j(null);C(()=>{var r;let i=window.monaco;if(!o.current||!(i!=null&&(r=i.editor)!=null&&r.colorize))return;let a=t===`ts`||t===`typescript`?`typescript`:t||`javascript`;i.editor.colorize(e,a,{theme:n===`dark`?`vs-dark`:`vs`}).then(e=>{o.current&&(o.current.innerHTML=e)})},[e,t,n]);let s=b(()=>{navigator.clipboard.writeText(e)},[e]);return m(f,{sx:{position:`relative`,my:1,borderRadius:1,overflow:`hidden`,border:`1px solid`,borderColor:`divider`},children:[m(f,{sx:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,px:1,py:.5,bgcolor:`action.hover`,borderBottom:`1px solid`,borderColor:`divider`},children:[c(f,{sx:{fontSize:`0.75rem`,color:`text.secondary`,textTransform:`uppercase`},children:t||`javascript`}),m(f,{children:[c(N,{title:y.t(`Copy`),children:c(S,{size:`small`,onClick:s,children:c(D,{sx:{fontSize:16}})})}),r&&c(N,{title:y.t(`Insert into editor`),children:c(S,{size:`small`,onClick:()=>r(e),children:c(R,{sx:{fontSize:16}})})}),i&&c(N,{title:y.t(`Show as diff`),children:c(S,{size:`small`,onClick:()=>i(e,a),children:c(V,{sx:{fontSize:16}})})})]})]}),c(`pre`,{ref:o,style:{margin:0,padding:`8px 12px`,overflow:`auto`,maxHeight:400,fontSize:`13px`,fontFamily:`'Cascadia Code', 'Fira Code', 'Consolas', monospace`,backgroundColor:n===`dark`?`#1e1e1e`:`#f8f8f8`,color:n===`dark`?`#d4d4d4`:`#333`},children:e})]})};O();var Ie=({xml:e,themeType:t})=>{let n=j(null),r=j(null),[i,a]=_(60),o=j(!1);return C(()=>{o.current&&(o.current=!1,requestAnimationFrame(()=>{let e=window.Blockly,t=r.current;e&&t&&(e.svgResize(t),t.scrollCenter())}))},[i]),C(()=>{let i=window.Blockly;if(!(!i||!n.current)){r.current&&=(r.current.dispose(),null);try{let s=i.inject(n.current,{readOnly:!0,toolbox:null,trashcan:!1,zoom:{controls:!1,wheel:!1,startScale:1},move:{scrollbars:!1,drag:!1,wheel:!1},sounds:!1,renderer:`thrasos`,theme:t===`dark`?L():`classic`,media:`google-blockly/media/`});r.current=s;let c=e.trim();c.startsWith(`<xml`)||(c=`<xml xmlns="https://developers.google.com/blockly/xml">${c}</xml>`);let l=i.utils.xml.textToDom(c),u=10,d=Array.from(l.querySelectorAll(`:scope > block`));for(let e of d)e.setAttribute(`x`,`10`),e.setAttribute(`y`,String(u)),u+=200;i.Xml.domToWorkspace(l,s);let f=s.getTopBlocks(!1);if(f.length>1){let e=10;for(let t of f){let n=t.getRelativeToSurfaceXY();t.moveBy(10-n.x,e-n.y),e+=t.getHeightWidth().height+20}}let p=s.getBlocksBoundingBox();if(p){let e=p.bottom-p.top+20,t=Math.max(60,Math.ceil(e));o.current=!0,a(t)}}catch{}return()=>{r.current&&=(r.current.dispose(),null)}}},[e,t]),c(f,{ref:n,sx:{width:`100%`,height:i,minHeight:60,borderRadius:1,overflow:`hidden`,border:`1px solid`,borderColor:`divider`}})};O();function Le(e){let t=[],n=/```(\w*)\n?([\s\S]*?)```/g,r=0,i;for(;(i=n.exec(e))!==null;){if(i.index>r){let n=e.substring(r,i.index).trim();n&&t.push({type:`text`,content:n})}t.push({type:`code`,content:i[2].trim(),language:i[1]||`javascript`}),r=i.index+i[0].length}if(r<e.length){let n=e.substring(r).trim();n&&t.push({type:`text`,content:n})}return t.length===0&&t.push({type:`text`,content:e}),t}function $(e){let t=[],n=/(\*\*(.+?)\*\*|\*(.+?)\*|`(.+?)`)/g,r=0,i,a=0;for(;(i=n.exec(e))!==null;)i.index>r&&t.push(e.substring(r,i.index)),i[2]?t.push(c(`strong`,{children:i[2]},a++)):i[3]?t.push(c(`em`,{children:i[3]},a++)):i[4]&&t.push(c(`code`,{className:`ai-chat-inline-code`,style:{padding:`2px 6px`,borderRadius:4,fontSize:`0.85em`,fontFamily:`'Cascadia Code', 'Fira Code', 'Consolas', monospace`},children:i[4]},a++)),r=i.index+i[0].length;return r<e.length&&t.push(e.substring(r)),t}function Re(e){return e.trim().startsWith(`|`)&&e.trim().endsWith(`|`)}function ze(e){return/^\|[\s:]*-+[\s:|-]*\|$/.test(e.trim())}function Be(e,t,n){let r=t.palette.mode===`dark`,i=e=>e.trim().replace(/^\||\|$/g,``).split(`|`).map(e=>e.trim()),a=i(e[0]),o=e.slice(2).map(i);return c(f,{sx:{overflowX:`auto`,my:1},children:m(`table`,{style:{borderCollapse:`collapse`,width:`100%`,fontSize:`0.8rem`,color:t.palette.text.primary},children:[c(`thead`,{children:c(`tr`,{children:a.map((e,n)=>c(`th`,{style:{border:`1px solid ${t.palette.divider}`,padding:`6px 10px`,backgroundColor:r?t.palette.grey[800]:t.palette.grey[100],color:t.palette.text.primary,fontWeight:600,textAlign:`left`},children:$(e)},n))})}),c(`tbody`,{children:o.map((e,n)=>c(`tr`,{style:{backgroundColor:n%2==1?r?t.palette.grey[900]:t.palette.grey[50]:void 0},children:e.map((e,n)=>c(`td`,{style:{border:`1px solid ${t.palette.divider}`,padding:`6px 10px`,color:t.palette.text.primary},children:$(e)},n))},n))})]})},n)}function Ve(e,t){let n=e.split(`
234
- `),r=[],i=0,a=0;for(;a<n.length;){let e=n[a].trim();if(e===``){a++;continue}if(/^(-{3,}|\*{3,}|_{3,})$/.test(e)){r.push(c(`hr`,{style:{border:`none`,borderTop:`1px solid ${t.palette.divider}`,margin:`8px 0`}},i++)),a++;continue}let o=e.match(/^(#{1,4})\s+(.+)$/);if(o){let e=o[1].length;r.push(c(`div`,{style:{fontWeight:600,fontSize:[`1.2em`,`1.1em`,`1em`,`0.95em`][e-1],margin:`8px 0 4px`},children:$(o[2])},i++)),a++;continue}if(Re(e)&&a+1<n.length&&ze(n[a+1].trim())&&a+2<n.length){let e=[n[a],n[a+1]],o=a+2;for(;o<n.length&&Re(n[o]);)e.push(n[o]),o++;r.push(Be(e,t,i++)),a=o;continue}if(/^[-*+]\s/.test(e)){let e=[];for(;a<n.length&&/^\s*[-*+]\s/.test(n[a]);)e.push(n[a].replace(/^\s*[-*+]\s/,``).trim()),a++;r.push(c(`ul`,{style:{margin:`4px 0`,paddingLeft:20},children:e.map((e,t)=>c(`li`,{children:$(e)},t))},i++));continue}if(/^\d+[.)]\s/.test(e)){let e=[];for(;a<n.length&&/^\s*\d+[.)]\s/.test(n[a]);)e.push(n[a].replace(/^\s*\d+[.)]\s/,``).trim()),a++;r.push(c(`ol`,{style:{margin:`4px 0`,paddingLeft:20},children:e.map((e,t)=>c(`li`,{children:$(e)},t))},i++));continue}r.push(c(`div`,{children:$(e)},i++)),a++}return r}var He=({message:e,themeType:t,currentLanguage:r,onInsertCode:i,onShowDiff:a,onApplyCode:o})=>{let l=e.role===`user`,u=s(),p=l?t===`dark`?u.palette.primary.dark:u.palette.primary.main:t===`dark`?u.palette.secondary.dark:u.palette.secondary.main,h=u.palette.getContrastText(p),_=g(()=>Le(e.content),[e.content]),v=(e,t)=>!!(e===`xml`||e===`blockly`||r===`blockly`&&t&&/<block\s+type=/.test(t));return m(f,{sx:{display:`flex`,gap:1,px:1.5,py:1,mx:.75,my:.5,bgcolor:l?t===`dark`?`rgba(144, 202, 249, 0.10)`:`rgba(25, 118, 210, 0.07)`:t===`dark`?`rgba(206, 147, 216, 0.10)`:`rgba(156, 39, 176, 0.06)`,borderRadius:1.5,borderLeft:`3px solid`,borderLeftColor:p,transition:`background-color 120ms`,"&:hover":{bgcolor:l?t===`dark`?`rgba(144, 202, 249, 0.16)`:`rgba(25, 118, 210, 0.12)`:t===`dark`?`rgba(206, 147, 216, 0.16)`:`rgba(156, 39, 176, 0.10)`}},children:[c(n,{sx:{width:28,height:28,bgcolor:p,color:h,flexShrink:0,mt:.5},children:c(l?te:U,{sx:{fontSize:18}})}),c(f,{sx:{flex:1,minWidth:0,fontSize:`0.875rem`,lineHeight:1.6},children:_.map((n,r)=>n.type===`code`?v(n.language,n.content)?m(f,{sx:{my:1},children:[c(Ie,{xml:n.content,themeType:t}),m(f,{sx:{display:`flex`,gap:.5,mt:.5},children:[o&&c(d,{size:`small`,variant:`contained`,color:`primary`,startIcon:c(H,{sx:{fontSize:14}}),onClick:()=>o(n.content),sx:{textTransform:`none`,fontSize:`0.75rem`},children:y.t(`Apply blocks`)}),i&&c(d,{size:`small`,variant:`outlined`,startIcon:c(R,{sx:{fontSize:14}}),onClick:()=>i(n.content),sx:{textTransform:`none`,fontSize:`0.75rem`},children:y.t(`Insert blocks`)})]})]},r):c(Fe,{code:n.content,language:n.language||`javascript`,themeType:t,onInsertCode:i,onShowDiff:a,sourceRange:e.sourceRange||null},r):c(f,{sx:{wordBreak:`break-word`,color:u.palette.text.primary},children:Ve(n.content,u)},r))})]})};function Ue(e){let t=(e||``).toLowerCase();return t.includes(`blockly`)||t.includes(`rules`)?`blockly`:t.includes(`typescript`)?`typescript`:`javascript`}function We(e,t){return`\`\`\`${t===`blockly`?`xml`:t}\n${e}\n\`\`\``}function Ge(e){let t=(e.code||``).trim(),n=Ue(e.language),r=e.rangeLabel?` (${e.rangeLabel})`:``;switch(e.action){case`explain`:return t?[`Please explain what this ioBroker ${n} code does${r}.`,`Focus on: which datapoints it reads/writes, which triggers fire it, and any side-effects.`,``,We(t,n)].join(`
235
- `):null;case`refactor`:return t?[`Refactor this ioBroker ${n} code${r} to be cleaner and more idiomatic.`,`Preserve behavior exactly. Keep ioBroker APIs (on, setState, getState, schedule, sendTo, log).`,`Return the full refactored block inside a \`\`\`${n===`blockly`?`xml`:n}\`\`\` code block so it can be smart-applied.`,``,We(t,n)].join(`
236
- `):null;case`comment`:return t?[`Add clear, concise inline comments to this ioBroker ${n} code${r}.`,`Only add comments where they add real value (non-obvious logic, tricky edge cases, business rules).`,`Do not over-comment trivial lines. Return the commented version in a code block.`,``,We(t,n)].join(`
237
- `):null;case`fix`:{if(!t)return null;let i=(e.diagnostic||``).trim();return[`This ioBroker ${n} code has an issue${r}. Please fix it and return the corrected code.${i?`\nReported problem: ${i}`:``}`,`Keep the fix minimal — do not rewrite unrelated parts.`,``,We(t,n)].join(`
238
- `)}case`tests`:return t?[`Suggest how to test this ioBroker ${n} script manually inside the ioBroker admin UI${r}.`,``,"ioBroker scripts run inside the adapter sandbox and CANNOT be unit-tested with Jest, Mocha, or any external test framework. Do NOT propose Jest/Mocha tests, do NOT propose extracting the code into a separate Node.js project, do NOT write `describe` / `test` blocks.",``,`Instead, propose a short list of manual test cases. For each case describe:`,` • Setup — which ioBroker datapoints to prepare and to which values (via the objects tree "Values" tab)`,` • Action — what to trigger: set a state with setState, wait for a schedule, change a sensor value, etc.`,` • Expected — what should happen afterwards: which states should change, what should appear in the adapter log (javascript.0), which side effects are visible`,``,`Keep it concise: 3-6 cases covering the happy path, typical edge cases, and any guard conditions the script has.`,``,We(t,n)].join(`
239
- `):null;case`ask`:{let i=(e.question||``).trim();return i?t?[`Regarding this ioBroker ${n} code${r}:`,``,We(t,n),``,i].join(`
240
- `):i:null}default:return null}}function Ke(e){let t=(e||``).trimStart();if(!t.startsWith(`/`))return null;let n=t.match(/^\/(\w+)(?:\s+([\s\S]*))?$/);if(!n)return null;let r=n[1].toLowerCase(),i=(n[2]||``).trim(),a={explain:`explain`,erklaere:`explain`,erklaeren:`explain`,refactor:`refactor`,refaktor:`refactor`,refaktoriere:`refactor`,comment:`comment`,comments:`comment`,kommentar:`comment`,kommentiere:`comment`,fix:`fix`,fixme:`fix`,tests:`tests`,test:`tests`,ask:`ask`,frag:`ask`,frage:`ask`}[r];return a?{action:a,rest:i}:null}O();function qe(){return[{id:`@all`,label:y.t(`mention @all`),descriptionKey:`All scripts`},{id:`@devices`,label:y.t(`mention @devices`),descriptionKey:`Smart home devices`}]}function Je({provider:e,isDark:t}){return K[e]?c(`img`,{src:`./img/${e}.svg`,alt:e,style:{...q,...t?{filter:`invert(0.85)`}:{}},onError:e=>{e.target.style.display=`none`}}):null}function Ye(){try{let e=window.localStorage.getItem(`Editor.aiChatHistory`);return e?JSON.parse(e):[]}catch{return[]}}var Xe=({onSend:e,disabled:t,themeType:n,hasSelection:s,selectionText:u,allScripts:d,model:h,availableModels:v,modelProviderMap:w,modelsLoading:T,onModelChange:E,mode:D,onModeChange:O,currentLanguage:ee})=>{let[F,I]=_(``),[L,R]=_(!1),[z,V]=_(``),[te,H]=_(0),U=j(null),W=j(-1),G=j(Ye()),K=j(-1),q=j(``),ne=g(()=>{let e=qe().map(e=>({...e,description:y.t(e.descriptionKey)}));if(d)for(let t of d){let n=t.id.replace(/^script\.js\./,``).replace(/\./g,`/`);e.push({id:`@${n}`,label:`@${n}`,description:`${t.name} [${t.enabled?`active`:`inactive`}]`})}return e},[d]),J=g(()=>{if(!z)return ne;let e=z.toLowerCase();return ne.filter(t=>t.id.toLowerCase().includes(e)||t.description.toLowerCase().includes(e))},[ne,z]);C(()=>{H(0)},[z]);let Y=b(()=>{let n=F.trim();if(!n||t)return;let r=n,i=Ke(n);if(i){let e=s&&u?u:``,t=Ge({action:i.action,code:e,language:ee||`javascript`,question:i.action===`ask`?i.rest:void 0,diagnostic:i.action===`fix`&&i.rest||void 0});t&&(r=t)}else s&&u&&(r=`[Selected code in editor]\n\`\`\`\n${u}\n\`\`\`\n\n${n}`);G.current.push(n),K.current=-1,q.current=``;try{let e=G.current.slice(-50);window.localStorage.setItem(`Editor.aiChatHistory`,JSON.stringify(e))}catch{}e(r),I(``),R(!1),requestAnimationFrame(()=>{var e;return(e=U.current)==null?void 0:e.focus()})},[F,t,e,s,u,ee]),X=b(e=>{let t=W.current,n=U.current;if(t<0){let t=F?`${F}${e} `:`${e} `;I(t),R(!1),V(``),setTimeout(()=>{n&&(n.focus(),n.setSelectionRange(t.length,t.length))},0);return}let r=F.substring(0,t),i=(n==null?void 0:n.selectionStart)??F.length,a=`${r}${e} ${F.substring(i)}`;I(a),R(!1),V(``),W.current=-1,setTimeout(()=>{if(n){let t=r.length+e.length+1;n.focus(),n.setSelectionRange(t,t)}},0)},[F]),Z=b(()=>{W.current=-1,V(``),R(e=>!e)},[]),re=b(e=>{let t=e.target.value;I(t);let n=e.target.selectionStart??t.length,r=t.substring(0,n).match(/@([\w/äöüÄÖÜß]*)$/);r?(W.current=n-r[0].length,V(r[1]),R(!0)):(R(!1),V(``))},[]),ie=b(e=>{if(L&&J.length>0){if(e.key===`ArrowDown`){e.preventDefault(),H(e=>(e+1)%J.length);return}if(e.key===`ArrowUp`){e.preventDefault(),H(e=>(e-1+J.length)%J.length);return}if(e.key===`Enter`||e.key===`Tab`){e.preventDefault(),X(J[te].id);return}if(e.key===`Escape`){e.preventDefault(),R(!1);return}}if(e.key===`ArrowUp`&&!L&&G.current.length>0){let t=U.current,n=!t||t.selectionStart===0,r=!F.includes(`
241
- `);if(n&&r){e.preventDefault(),K.current===-1?(q.current=F,K.current=G.current.length-1):K.current>0&&K.current--,I(G.current[K.current]);return}}if(e.key===`ArrowDown`&&!L&&K.current>=0){let t=U.current,n=!t||t.selectionStart===F.length,r=!F.includes(`
242
- `);if(n&&r){e.preventDefault(),K.current<G.current.length-1?(K.current++,I(G.current[K.current])):(K.current=-1,I(q.current));return}}e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),Y())},[Y,L,J,te,X,F]);return m(f,{sx:{borderTop:`1px solid`,borderColor:`divider`,position:`relative`},children:[L&&J.length>0&&c(a,{elevation:4,sx:{position:`absolute`,bottom:`100%`,left:8,right:8,maxHeight:200,overflow:`auto`,zIndex:10,mb:.5},children:c(A,{dense:!0,disablePadding:!0,children:J.slice(0,15).map((e,t)=>c(k,{selected:t===te,onClick:()=>X(e.id),sx:{py:.25,minHeight:32},children:c(i,{primary:e.label,secondary:e.description,slotProps:{primary:{sx:{fontSize:`0.8rem`,fontWeight:500}},secondary:{sx:{fontSize:`0.7rem`}}}})},e.id))})}),D===`code`&&c(p,{label:`${y.t(`mention @devices`)} — ${y.t(`Smart home devices`)}`,size:`small`,variant:`outlined`,sx:{mx:1,mt:.5,maxWidth:`calc(100% - 16px)`}}),s&&u&&c(p,{icon:c(M,{sx:{fontSize:14}}),label:y.t(`Selected code as context`),size:`small`,variant:`outlined`,sx:{mx:1,mt:.5,maxWidth:`calc(100% - 16px)`}}),m(f,{sx:{mx:1,mt:.5,mb:.5,border:`1px solid`,borderColor:`divider`,borderRadius:1.5,overflow:`hidden`,"&:focus-within":{borderColor:`primary.main`}},children:[c(l,{inputRef:U,fullWidth:!0,multiline:!0,maxRows:6,placeholder:y.t(`Ask about your script...`),value:F,onChange:re,onKeyDown:ie,disabled:t,onBlur:()=>{setTimeout(()=>R(!1),200)},variant:`standard`,slotProps:{input:{disableUnderline:!0}},sx:{px:1.5,pt:1,pb:.5,"& .MuiInputBase-root":{fontSize:`0.875rem`}}}),m(f,{sx:{display:`flex`,alignItems:`center`,gap:.75,px:1,pb:.5},children:[c(N,{title:m(f,{sx:{fontSize:`0.8rem`,lineHeight:1.5,maxWidth:360},children:[c(f,{sx:{fontWeight:600,mb:.75},children:y.t(`AI chat mode`)}),m(f,{sx:{mb:.75},children:[m(`strong`,{children:[`💬 `,y.t(`Chat`)]}),` —`,` `,y.t(`Plain conversation. Use for questions, explanations, syntax help. Does not read or modify your scripts.`)]}),m(f,{sx:{mb:.75},children:[m(`strong`,{children:[`🤖 `,y.t(`Agent`)]}),` —`,` `,y.t(`For larger models with tool support. The AI can read, create, and edit scripts, look up datapoints, and browse the object tree — useful for "create a script that...", "which scripts use this state?" or "analyze my light script".`)]}),m(f,{children:[m(`strong`,{children:[`💻 `,y.t(`Code`)]}),` —`,` `,y.t(`For smaller models without tool support. Two-step script generator (plan then code) — useful for "create a script that..." or "write a Blockly rule for...". Output goes into the editor for smart-apply.`)]})]}),enterDelay:400,placement:`left`,children:m(x,{value:D,onChange:e=>O(e.target.value),size:`small`,variant:`standard`,disableUnderline:!0,sx:{fontSize:`0.7rem`,color:`text.secondary`,border:`1px solid`,borderColor:`text.secondary`,borderRadius:3,bgcolor:`action.hover`,px:.75,"&:hover":{borderColor:`text.disabled`,bgcolor:`action.hover`},"& .MuiSelect-select":{py:`2px`,pr:`18px !important`,display:`flex`,alignItems:`center`,gap:.5}},children:[c(o,{value:`chat`,sx:{fontSize:`0.75rem`},title:y.t(`Plain conversation. Best for: general questions, syntax help, concept explanations.`),children:`💬 Chat`}),c(o,{value:`agent`,sx:{fontSize:`0.75rem`},title:y.t(`For larger models with tool support. Best for: creating, editing, or analyzing scripts; finding datapoint usages; inspecting the object tree.`),children:`🤖 Agent`}),c(o,{value:`code`,sx:{fontSize:`0.75rem`},title:y.t(`For smaller models without tool support. Best for: creating new JavaScript/TypeScript or Blockly scripts from a description.`),children:`💻 Code`})]})}),c(x,{value:h,onChange:e=>E(e.target.value),size:`small`,disabled:T||v.length===0,variant:`standard`,disableUnderline:!0,sx:{fontSize:`0.7rem`,color:`text.secondary`,border:`1px solid`,borderColor:`text.secondary`,borderRadius:3,bgcolor:`action.hover`,px:.75,"&:hover":{borderColor:`text.disabled`,bgcolor:`action.hover`},"& .MuiSelect-select":{py:`2px`,pr:`18px !important`,display:`flex`,alignItems:`center`,gap:.5}},children:v.map(e=>m(o,{value:e,sx:{fontSize:`0.75rem`,display:`flex`,gap:.5},children:[c(Je,{provider:w[e],isDark:n===`dark`}),e]},e))}),c(N,{title:y.t(`Mention scripts as context for the AI. Use @all for all scripts or @scriptName for a specific one.`),enterDelay:500,children:c(S,{size:`small`,onClick:Z,sx:{p:`3px`,color:L?`primary.main`:`text.secondary`,border:`1px solid`,borderColor:L?`primary.main`:`text.secondary`,bgcolor:L?void 0:`action.hover`,borderRadius:3,"&:hover":{borderColor:`text.disabled`,bgcolor:`action.hover`}},children:c(B,{sx:{fontSize:16}})})}),c(f,{sx:{flex:1}}),m(r,{variant:`caption`,sx:{color:`text.disabled`,fontSize:`0.65rem`,mr:.5,whiteSpace:`nowrap`},children:[`Enter `,y.t(`to send`)]}),c(N,{title:`${y.t(`Send`)} (Enter)`,children:c(`span`,{children:c(S,{color:`primary`,onClick:Y,disabled:t||!F.trim(),size:`small`,sx:{p:.25},children:c(P,{sx:{fontSize:18}})})})})]})]})]})};O();var Ze=({socket:e,runningInstances:t,themeType:n,currentCode:i,currentLanguage:a,selectedCode:o,allScripts:s,editorApi:l,aiActionRequest:u,onAiActionConsumed:d,onRegisterInlineAsk:p,onInsertCode:_,onShowDiff:x,onApplyCode:T,currentScriptId:D,onClose:O})=>{var k;let A=j(null),{messages:M,isLoading:P,error:ee,model:F,availableModels:I,modelProviderMap:L,modelsLoading:R,modelsError:B,lastContextInfo:V,mode:te,setMode:H,setModel:U,sendMessage:W,triggerAiAction:G,askInline:K,clearChat:q,retryLoadModels:ne}=Pe(g(()=>({socket:e,runningInstances:t,currentCode:i,currentLanguage:a,allScripts:s,editorApi:l,currentScriptId:D}),[e,t,i,a,s,l,D]));C(()=>(p==null||p(K),()=>p==null?void 0:p(null)),[K,p]);let J=j(null);C(()=>{!u||J.current===u||(J.current=u,G(u),d==null||d())},[u,G,d]),C(()=>{var e;(e=A.current)==null||e.scrollIntoView({behavior:`smooth`})},[M]);let Y=b(e=>{_==null||_(e)},[_]),X=b((e,t)=>{x==null||x(e,t)},[x]),Z=b(e=>{T==null||T(e)},[T]);return m(f,{sx:{display:`flex`,flexDirection:`column`,height:`100%`,bgcolor:`background.default`,"& .ai-chat-inline-code":{backgroundColor:`action.selected`,color:`text.primary`,border:`1px solid`,borderColor:`divider`}},children:[m(f,{sx:{display:`flex`,alignItems:`center`,gap:1,px:1,py:.5,borderBottom:`1px solid`,borderColor:`divider`,bgcolor:n===`dark`?`grey.900`:`grey.100`,flexShrink:0},children:[c(r,{variant:`subtitle2`,sx:{fontWeight:600,flex:1,color:`text.primary`},children:y.t(`AI Chat`)}),R&&c(h,{size:16}),c(N,{title:y.t(`New chat`),children:c(S,{size:`small`,onClick:q,children:c(z,{sx:{fontSize:18}})})}),c(N,{title:y.t(`Close`),children:c(S,{size:`small`,onClick:O,children:c(v,{sx:{fontSize:18}})})})]}),(ee||B)&&c(w,{severity:`error`,sx:{m:1,py:0},action:B?c(S,{size:`small`,onClick:ne,children:c(E,{sx:{fontSize:16}})}):void 0,children:ee||B}),V&&c(r,{variant:`caption`,sx:{px:1.5,py:.25,color:`text.secondary`,fontSize:`0.7rem`,bgcolor:`action.hover`,borderBottom:`1px solid`,borderColor:`divider`,flexShrink:0},children:V}),m(f,{sx:{flex:1,overflow:`auto`,py:1},children:[M.length===0&&!P&&m(f,{sx:{display:`flex`,flexDirection:`column`,alignItems:`center`,justifyContent:`center`,height:`100%`,color:`text.secondary`,px:3,textAlign:`center`},children:[c(r,{variant:`body2`,sx:{mb:1},children:y.t(`Ask questions about your script, request changes, or generate new code.`)}),m(r,{variant:`caption`,color:`text.disabled`,children:[`Enter `,y.t(`to send`),`, Shift+Enter `,y.t(`for new line`)]})]}),M.filter(e=>e.role!==`system`).map(e=>c(He,{message:e,themeType:n,currentLanguage:a,onInsertCode:Y,onShowDiff:X,onApplyCode:Z},e.id)),P&&((k=M[M.length-1])==null?void 0:k.content)===``&&m(f,{sx:{display:`flex`,alignItems:`center`,gap:1,px:2,py:1},children:[c(h,{size:16}),c(r,{variant:`caption`,color:`text.secondary`,children:y.t(`Thinking...`)})]}),c(`div`,{ref:A})]}),c(Xe,{onSend:W,disabled:P||I.length===0,themeType:n,hasSelection:!!o,selectionText:o,allScripts:s,model:F,availableModels:I,modelProviderMap:L,modelsLoading:R,onModelChange:U,mode:te,onModeChange:H,currentLanguage:a})]})};export{Ze as default,Ke as n,Ge as t};
@@ -1 +0,0 @@
1
- import{Bt as e,Jn as t,Rt as n,St as r,Ut as i,Vt as a,Yn as o,bt as s,f as c,fr as l,mr as u,wr as d,yr as f}from"./_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BAOcdAz5.js";d();var p=({originalCode:d,modifiedCode:p,language:m,themeType:h,onAccept:g,onReject:_})=>{let v=f(null),y=f(null),b=f(null);u(()=>{let e=window.monaco;if(!e||!v.current)return;let t=e.editor.createDiffEditor(v.current,{readOnly:!1,originalEditable:!1,renderSideBySide:!0,automaticLayout:!0,theme:h===`dark`?`vs-dark`:`vs`,scrollBeyondLastLine:!1,minimap:{enabled:!1}}),n=e.editor.createModel(d,m),r=e.editor.createModel(p,m);return b.current=r,t.setModel({original:n,modified:r}),y.current=t,()=>{t.dispose(),n.dispose(),r.dispose(),y.current=null,b.current=null}},[d,p,m,h]);let x=l(()=>{var e;g(((e=b.current)==null?void 0:e.getValue())||p)},[p,g]);return o(a,{sx:{display:`flex`,flexDirection:`column`,height:`100%`,width:`100%`},children:[o(n,{variant:`dense`,sx:{minHeight:36,bgcolor:`background.paper`,borderBottom:`1px solid`,borderColor:`divider`,gap:1,flexShrink:0},children:[t(e,{variant:`subtitle2`,sx:{flex:1},children:c.t(`AI suggested changes`)}),t(i,{variant:`contained`,color:`success`,size:`small`,startIcon:t(r,{}),onClick:x,children:c.t(`Accept`)}),t(i,{variant:`outlined`,color:`error`,size:`small`,startIcon:t(s,{}),onClick:_,children:c.t(`Reject`)})]}),t(a,{ref:v,sx:{flex:1,overflow:`hidden`}})]})};export{p as default};