iobroker.javascript 10.4.0 → 10.4.2

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 (134) hide show
  1. package/README.md +7 -17
  2. package/admin/assets/AiChatPanel-Bh1UgzLN.js +27 -0
  3. package/admin/assets/AiChatService-h1EHSXaR.js +216 -0
  4. package/admin/assets/AiDiffView-pmbNE43A.js +1 -0
  5. package/admin/assets/AiInlineProvider-CslJGmO0.js +5 -0
  6. package/admin/assets/{BlocklyEditor-DhwThchX.js → BlocklyEditor-DD7PWWnm.js} +7 -7
  7. package/admin/assets/Compile-CHnsUZ3H.js +165 -0
  8. package/admin/assets/Debugger-DcFTsY_u.js +15 -0
  9. package/admin/assets/Diff-BMtToKAY.js +1 -0
  10. package/admin/assets/{Documentation-D3E0U4AK.js → Documentation-DmTfviYr.js} +4 -4
  11. package/admin/assets/ExpandMore-BjBfK8y_.js +1 -0
  12. package/admin/assets/{FbEditor-BjLPNzpK.js → FbEditor-BCD6eDj-.js} +6 -6
  13. package/admin/assets/History-DM03Cwv-.js +1 -0
  14. package/admin/assets/Import-Bh_K9cpx.js +1 -0
  15. package/admin/assets/MonacoDiff-yYWwyqpx.js +1 -0
  16. package/admin/assets/NotificationsActive-B7pgt1LW.js +1 -0
  17. package/admin/assets/RulesEditor-CV-5poRY.js +1 -0
  18. package/admin/assets/ScriptEditor-sb_g6vXT.js +2 -0
  19. package/admin/assets/ScriptEditorVanillaMonaco-DbOlv3vi.js +3 -0
  20. package/admin/assets/Send-Bo4QPFhQ.js +1 -0
  21. package/admin/assets/_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-B7myBQHF.js +1 -0
  22. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__57338878793567__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-8WiAnp-r.js +1217 -0
  23. package/admin/assets/{_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__234968779812303__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-DLWT3PGo.js → _virtual_mf___mfe_internal__iobroker_javascript__mf_owner__57338878793567__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-BCLgOrQh.js} +1 -1
  24. package/admin/assets/aiPromptBuilder-jeMwCFvL.js +1 -0
  25. package/admin/assets/blocklyTheme-B0abPSuE.js +1 -0
  26. package/admin/assets/{blocks_action-Ctn5A1AU.js → blocks_action-CM4AAMF1.js} +1 -1
  27. package/admin/assets/{blocks_convert-BI0lf0sf.js → blocks_convert-DIBthcQF.js} +1 -1
  28. package/admin/assets/{blocks_logic-o49klUX_.js → blocks_logic-CJBNXoP3.js} +1 -1
  29. package/admin/assets/{blocks_number-DZtyWFyR.js → blocks_number-GuNZ4kQO.js} +1 -1
  30. package/admin/assets/{blocks_object-BuzGCxVr.js → blocks_object-BFR1ocL_.js} +1 -1
  31. package/admin/assets/{blocks_procedures-jn9sIYmR.js → blocks_procedures-CQxCN9F8.js} +1 -1
  32. package/admin/assets/{blocks_sendto-Coui8w1H.js → blocks_sendto-DSfpmOb2.js} +1 -1
  33. package/admin/assets/{blocks_switch-CeRZizTM.js → blocks_switch-CzWnVKX-.js} +1 -1
  34. package/admin/assets/{blocks_system-CaBPIC40.js → blocks_system-DVfA31Hy.js} +1 -1
  35. package/admin/assets/{blocks_text-DeDtPYWf.js → blocks_text-CgO-seeL.js} +1 -1
  36. package/admin/assets/{blocks_time-CTXQH3Lm.js → blocks_time-DNQPTg92.js} +1 -1
  37. package/admin/assets/{blocks_timeout-D8IOKOb-.js → blocks_timeout-BXypxY7F.js} +1 -1
  38. package/admin/assets/{blocks_trigger-zuuXJbhb.js → blocks_trigger-elp6XrND.js} +1 -1
  39. package/admin/assets/cronHoverProvider-CZrYrB2m.js +2 -0
  40. package/admin/assets/{dist-CzitsFi7.js → dist-CSJEdwl2.js} +1 -1
  41. package/admin/assets/field_cron-m1xxzKf2.js +1 -0
  42. package/admin/assets/field_oid-BLNfi7lh.js +1 -0
  43. package/admin/assets/field_script-CGDpmlGL.js +1 -0
  44. package/admin/assets/{helpers-BwllSRzJ.js → helpers-Ch3tewpw.js} +1 -1
  45. package/admin/assets/helpers-DT5-3o-l.js +1 -0
  46. package/admin/assets/{hostInit-CrHjJGJJ.js → hostInit-CflF0J5w.js} +1 -1
  47. package/admin/assets/index-_7Mh4AxK.js +157 -0
  48. package/admin/assets/inlineChatWidget-BfjarD99.js +2 -0
  49. package/admin/assets/{inlineDiffController-ly6qX4jk.js → inlineDiffController-VazWO1wi.js} +1 -1
  50. package/admin/assets/{loadBlocks-BcFtthDb.js → loadBlocks-CGEGNJcd.js} +23 -23
  51. package/admin/assets/{mf-entry-bootstrap-0-6db6c4fc.js → mf-entry-bootstrap-0-536f3328.js} +3 -3
  52. package/admin/assets/{pendingShares-mBGPbRwZ.js → pendingShares-WHCuAHKo.js} +2 -2
  53. package/admin/assets/reactour.esm-CETRUaME.js +137 -0
  54. package/admin/assets/{stateHoverProvider-wAsP-THx.js → stateHoverProvider-BfhQov29.js} +1 -1
  55. package/admin/assets/{utils-DUKzLJUz.js → utils-BFhwh2EC.js} +1 -1
  56. package/admin/assets/vite-preload-helper-BbbETgeG.js +1 -0
  57. package/admin/custom/assets/Components-C6UfjQAS.js +1 -0
  58. package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-B1DaT32e.js +1 -0
  59. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-BRo2TJu1.js +1 -0
  60. package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BhZYie9-.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-nQIzP_1l.js} +95 -95
  61. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__loadShare___mf_0_mui_mf_1_x_mf_2_date_mf_2_pickers__loadShare__.js-DQfhTnYi.js +1 -0
  62. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__loadShare__date_mf_2_fns__loadShare__.js-BrsJpRn9.js +1 -0
  63. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__loadShare__shared-Bm5cq4Wz.js +2 -0
  64. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-Bv9I6S4D.js +122 -0
  65. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__prebuild__leaflet__prebuild__-R1ziirob.js +1 -0
  66. package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__prebuild__react_mf_2_dom_mf_1_client__prebuild__-DOkC-g0X.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__prebuild__react_mf_2_dom_mf_1_client__prebuild__--phH3reL.js} +1 -1
  67. package/admin/custom/assets/{dist-CzitsFi7.js → dist-CSJEdwl2.js} +1 -1
  68. package/admin/custom/assets/helpers-DT5-3o-l.js +1 -0
  69. package/admin/custom/assets/{hostInit-akwaQLq8.js → hostInit-CuGqkIzY.js} +1 -1
  70. package/admin/custom/assets/index-CgBEPuXx.js +1 -0
  71. package/admin/custom/assets/{lib-CADOx2YN.js → lib-WawTWipl.js} +1 -1
  72. package/admin/custom/assets/{mf-entry-bootstrap-0-3c4565e0.js → mf-entry-bootstrap-0-81b08d9c.js} +3 -3
  73. package/admin/custom/assets/pendingShares-5RvH3v48.js +2 -0
  74. package/admin/custom/assets/{utils-DUKzLJUz.js → utils-BFhwh2EC.js} +1 -1
  75. package/admin/custom/assets/vite-preload-helper-BbbETgeG.js +1 -0
  76. package/admin/custom/customComponents.js +2 -2
  77. package/admin/mf-manifest.json +1 -1
  78. package/admin/mf-stats.json +1 -1
  79. package/admin/remoteEntry.js +2 -2
  80. package/admin/tab.html +2 -2
  81. package/build/lib/ai.js +53 -0
  82. package/build/lib/ai.js.map +1 -0
  83. package/build/main.js +19 -618
  84. package/build/main.js.map +1 -1
  85. package/io-package.json +26 -26
  86. package/package.json +6 -5
  87. package/admin/assets/AiChatPanel-BjRIKaXG.js +0 -27
  88. package/admin/assets/AiChatService-DP1EmVk2.js +0 -216
  89. package/admin/assets/AiDiffView-DeynDw7L.js +0 -1
  90. package/admin/assets/AiInlineProvider-jkEIJJJ-.js +0 -5
  91. package/admin/assets/Compile-e8N5zI-J.js +0 -165
  92. package/admin/assets/Debugger-BDQUKM1K.js +0 -15
  93. package/admin/assets/Diff--plofAtP.js +0 -1
  94. package/admin/assets/ExpandMore-Dio4GeHC.js +0 -1
  95. package/admin/assets/History-Ewi5YEEn.js +0 -1
  96. package/admin/assets/Import-6Mm2vrM2.js +0 -1
  97. package/admin/assets/MonacoDiff-BYvG7IqB.js +0 -1
  98. package/admin/assets/NotificationsActive-CuNfWVJM.js +0 -1
  99. package/admin/assets/RulesEditor--YX6ETsU.js +0 -1
  100. package/admin/assets/ScriptEditor-BadPC8Mf.js +0 -2
  101. package/admin/assets/ScriptEditorVanillaMonaco-BnAmy59d.js +0 -3
  102. package/admin/assets/Send-Pz1eveU5.js +0 -1
  103. package/admin/assets/_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-Ceh8EDcF.js +0 -1
  104. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__234968779812303__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BRdHvuuG.js +0 -1217
  105. package/admin/assets/aiPromptBuilder-Co6AqZwx.js +0 -1
  106. package/admin/assets/blocklyTheme-iZoge1S9.js +0 -1
  107. package/admin/assets/cronHoverProvider-Curcjz4m.js +0 -2
  108. package/admin/assets/field_cron-RgLY53_S.js +0 -1
  109. package/admin/assets/field_oid-rBhotXJe.js +0 -1
  110. package/admin/assets/field_script-CU7g3-oB.js +0 -1
  111. package/admin/assets/helpers-BZgjFQNf.js +0 -1
  112. package/admin/assets/index-Bmmscq2G.js +0 -157
  113. package/admin/assets/inlineChatWidget-ChchJD9a.js +0 -2
  114. package/admin/assets/reactour.esm-Dk3aGxKn.js +0 -137
  115. package/admin/assets/vite-preload-helper-DjNwdemH.js +0 -1
  116. package/admin/custom/assets/Components-fDcxCyN4.js +0 -1
  117. package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-BraOrMSu.js +0 -1
  118. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-CVvbIPAy.js +0 -1
  119. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare___mf_0_mui_mf_1_x_mf_2_date_mf_2_pickers__loadShare__.js-CV50dgj4.js +0 -1
  120. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare__date_mf_2_fns__loadShare__.js-Djg9OMcQ.js +0 -1
  121. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare__shared-Hb6V6BnJ.js +0 -2
  122. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-BrY-nF2a.js +0 -122
  123. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__prebuild__leaflet__prebuild__-CHjWtrkp.js +0 -1
  124. package/admin/custom/assets/helpers-BZgjFQNf.js +0 -1
  125. package/admin/custom/assets/index-BkItz-nL.js +0 -1
  126. package/admin/custom/assets/pendingShares-TCMDgBLn.js +0 -2
  127. package/admin/custom/assets/vite-preload-helper-DjNwdemH.js +0 -1
  128. package/build/lib/aiProviderResolver.js +0 -260
  129. package/build/lib/aiProviderResolver.js.map +0 -1
  130. package/build/lib/anthropicAdapter.js +0 -212
  131. package/build/lib/anthropicAdapter.js.map +0 -1
  132. /package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-DbKT6Hsb.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-DbKT6Hsb.js} +0 -0
  133. /package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare__leaflet__loadShare__.js-D9EyCd42.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__loadShare__leaflet__loadShare__.js-D9EyCd42.js} +0 -0
  134. /package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-CXpyx8Vy.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__18840520564161__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-CXpyx8Vy.js} +0 -0
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "javascript",
4
- "version": "10.4.0",
4
+ "version": "10.4.2",
5
5
  "blockedVersions": [
6
6
  "8.0.0",
7
7
  "8.0.1"
@@ -40,18 +40,31 @@
40
40
  "Matthias Kleine <info@haus-automatisierung.com>"
41
41
  ],
42
42
  "news": {
43
- "10.4.0": {
44
- "en": "The endpoint of an AI request comes out of the configuration and no longer out of the request. An address in the message used to win over the stored one, which was the comfortable way to put a proxy in front of OpenAI - and at the same time the way to have this instance carry the stored key, as the `Authorization` of that request, to an address of somebody else's choosing. Whoever may send a message to this instance could do that. A proxy belongs in the configuration now, where it is entered once by whoever may configure the adapter. The editor never sent an address, so nothing changes for it; the Test buttons of the settings dialog keep trying what stands in the form, with one limit: an address out of the form counts only together with a key out of the form - one's own key to one's own endpoint gives nothing away. In the credential-store mode the saved address is used, so an endpoint of one's own has to be saved before it can be tested there\nOnly an entry that was stored as an AI credential is read from the central credential store. The store holds the secrets of the whole system - a database password, the login of a camera - and a request for \"the key of this provider\" could name any one of them\nThe `execute` message - which runs a script here, with the whole ioBroker API behind it - checks who asked for it. A message never said on whose behalf it came, so there was nothing to check, and everyone who may send one to this instance could have code executed. Where the js-controller names the user (7.2.5 and newer, which put the user of a socket connection into the message), that user needs the right that a command on the host needs. Where it does not name one - an older controller, a script, an adapter - nothing changes\nThe question before a debug session (\"The script will be stopped and must be activated manually after debugging\") started the debugging even when it was answered with \"Cancel\" (#2382)\nStopping a debug session could end the debugged process with \"uncaught exception: write EPIPE\": the inspector process exited at once, although the process it debugs writes its whole log through its pipes and was still shutting down. The inspector now stops that process first and waits till it is really gone, a broken pipe cannot end a debugged script anymore, and the reset of the connection to the debugged process is not reported as an internal error of the inspector (#2382)\nThe AI chat stayed empty when a request took longer than 30 seconds: the answer is pushed as an instance message now instead of waiting for the socket callback\nAn AI answer without content now says why (stop reason, token counts) instead of leaving an empty chat bubble, and every failed request is logged\nAn answer cut off at the output limit is marked as incomplete\nSorted the scripts in the `@` list of the AI chat by their path\nThe AI chat can be maximized to the whole editor area (#2389)\nThe AI chat shows a spinner for the whole request, not only until the first tool call\nFixed an accepted AI suggestion not reaching the visible editor\nFixed the splitters jumping back to their previous width while being dragged\nBlockly: fixed a parameter of a \"JavaScript function\" with its default name making the script unsavable\nAdded a script history: saved versions can be listed, compared and restored in the editor. \"Saved versions per script\" (30 by default, 0 switches it off)\nAdded a \"Script history\" tab with the used storage per script and buttons to delete single, orphaned or all histories\nMoved the credentials table to its own tab\nMirror: a changed file no longer resets `enabled` and `engine` of the script (#2396)",
45
- "de": "Der Endpunkt einer KI-Anfrage kommt aus der Konfiguration und nicht mehr aus der Anfrage. Eine Adresse in der Nachricht überwog die gespeicherte, was die bequeme Art war, einen Proxy vor OpenAI zu platzieren und gleichzeitig den gespeicherten Schlüssel als `Autorisierung` der Anfrage an eine andere Adresse weiterzuleiten. Wer dieser Instanz eine Nachricht sendet, kann das tun. Ein Proxy gehört jetzt in die Konfiguration. Jeder, der den Adapter konfiguriert, gibt ihn ein. Der Editor hat nie eine Adresse gesendet, also ändert sich daran nichts. Die Testschaltflächen im Einstellungsdialog versuchen immer, was im Formular steht, mit einem Limit: Eine Adresse aus dem Formular zählt nur zusammen — der eigene Schlüssel zum eigenen Endpunkt verrät nichts. Im Credential-Store-Modus wird die Adresse verwendet, also muss ein eigener Endpunkt gespeichert werden\nNur ein KI-Eintrag wird aus dem zentralen Anmeldespeicher gelesen. Der Laden hat das ganze System — Datenbank-Passwort, Kamera-Login — und eine Anfrage nach dem Providerschlüssel könnte jeden nennen\nDie `execute`-Meldung, die hier ein Skript mit der ganzen ioBroker-API ausführt, prüft, wer danach gefragt hat. Eine Nachricht sagte nie, in wessen Namen sie kam, also gab es nichts zu prüfen, und jeder, der eine an diese Instanz sendet, konnte Code ausführen. Wenn der JS-Controller den Benutzer benennt (7.2.5 und neuer, was den Socket-Benutzer in die Nachricht einfügt), benötigt er das Recht, das ein Befehl auf dem Host benötigt. Wo es keinen nennt — ein älterer Controller, ein Script, ein Adapter — ändert sich nichts\nDie Frage vor einer Debug-Sitzung („Das Script wird gestoppt und muss danach manuell aktiviert werden“) begann das Debuggen, auch wenn es mit „Abbrechen“ beantwortet wurde (#2382)\nDas Beenden einer Debug-Sitzung könnte den Debugvorgang mit „uncaught exception: write EPIPE“ beenden: Der Inspector-Prozess wurde sofort beendet, obwohl er sein ganzes Log durchläuft und trotzdem heruntergefahren wird. Der Inspector stoppt den Prozess jetzt zuerst und wartet, bis er wirklich weg ist. Eine kaputte Leitung kann ein Debug-Skript nicht mehr beenden und das Zurücksetzen der Verbindung wird nicht als interner Fehler gemeldet (#2382)\nDer KI-Chat blieb leer, wenn eine Anfrage länger als 30 Sekunden dauerte: Die Antwort wird als Instanznachricht gesendet, statt auf den Socket-Rückruf zu warten\nEine KI-Antwort ohne Inhalt sagt nun warum (Grund, Token zählen), statt eine leere Chatblase, und jede Anfrage wird geloggt\nEine Antwort am Ausgabelimit gilt als unvollständig\nSortierte die Skripte in der `@`-Liste des KI-Chats\nDer KI-Chat ist auf den ganzen Editor maximierbar (#2389)\nDer KI-Chat zeigt die gesamte Anfrage an, nicht nur bis zum ersten Tool-Aufruf\nEin AI-Vorschlag kam nicht im sichtbaren Editor an\nFehler behoben, bei dem die Splitter beim Ziehen wieder breit wurden\nBlockly: Der Standardname einer JavaScript-Funktion machte das Skript unspeicherbar\nSkriptverlauf hinzugefügt: Gespeicherte Versionen im Editor anzeigen „Gespeicherte Versionen pro Skript“ (30, 0 schaltet ab)\nReiter „Skriptverlauf“ mit Speicherplatz pro Script und Buttons zum Löschen einzelner oder aller Historien hinzugefügt\nDie Anmeldeinformationen in ein eigenes Tab verschoben\nMirror: Eine geänderte Datei setzt „Enabled“ und „Engine“ nicht mehr zurück (#2396)",
46
- "ru": "Конечная точка запроса AI выходит из конфигурации и больше не входит в запрос. Раньше адрес, указанный в сообщении, выигрывал над сохраненным, что было удобнее поставить прокси-сервер перед OpenAI, и в то же время этот экземпляр передавал сохраненный ключ в виде «Авторизации» этого запроса на чужой адрес. Это мог сделать тот, кто может отправить сообщение в этот инстанс. Теперь в конфигурацию входит прокси-сервер, в который каждый, кто может настроить адаптер, вводится один раз. Редактор так и не прислал адрес, поэтому ничего не изменилось. Кнопки «Тестирование» в диалоговом окне настроек продолжают пересматривать то, что написано в форме, но только одно: адрес, не указанный в форме, засчитывается только вместе с ключом, вышедшим из формы, — собственный ключ к конечной точке ничего не даст. В режиме хранилища учетных данных используется сохраненный адрес, поэтому перед тестированием необходимо сохранить собственную конечную точку\nИз центрального хранилища учетных данных считывается только запись, которая была сохранена в качестве учетных данных AI. В хранилище хранятся секреты всей системы — пароль к базе данных, логин камеры — и любой из них может быть назван запрос на получение «ключа этого провайдера»\nСообщение `execute`, которое запускает здесь скрипт, за которым стоит весь API IOBroker, проверяет, кто его запросил. В сообщении так и не было указано, от чьего имени оно пришло, поэтому проверять было нечего, и каждый, кто отправит сообщение в этот экземпляр, мог выполнить код. Если js-controller вводит имя пользователя (версия 7.2.5 и более поздняя версия, в которой в сообщении указано имя пользователя, подключенного к сокету), этому пользователю нужны права, необходимые команде на хосте. Там, где имя не указано — старый контроллер, скрипт, адаптер — ничего не меняется\nВопрос перед сеансом отладки («Скрипт будет остановлен и должен быть активирован вручную после отладки») запустил отладку, даже если на него был дан ответ «Отмена» (#2382)\nОстановка сеанса отладки может привести к завершению отлаженного процесса с появлением «необнаруженного исключения: запись EPIPE»: процесс инспектора сразу же завершился, хотя отлаживаемый процесс записывает весь журнал по каналам и все равно завершается. Теперь инспектор сначала останавливает этот процесс и дожидается его полного завершения, сломанный канал больше не может завершить отлаженный скрипт, а сброс соединения с отлаженным процессом не считается внутренней ошибкой инспектора (#2382)\nЧат с искусственным интеллектом оставался пустым, если запрос длился более 30 секунд: теперь ответ отправляется в виде сообщения экземпляра, а не в ожидании обратного вызова сокета\nТеперь ответ на запрос с помощью искусственного интеллекта, не содержащий информации (причина остановки, количество токенов), вместо того чтобы оставлять пустое окно чата, и каждый неудачный запрос регистрируется в журнале\nОтвет, вырезанный по выходному пределу, помечается как неполный\nСкрипты в списке «@» чата с искусственным интеллектом отсортированы по пути\nЧат с искусственным интеллектом можно максимально использовать для всей области редактора (#2389)\nЧат с искусственным интеллектом показывает, как обрабатывается весь запрос, а не только до первого вызова инструмента\nИсправлено, что принятое предложение об искусственном интеллекте не попадало в видимый редактор\nИсправлена ошибка, из-за которой разделители возвращались к прежней ширине при перетаскивании\nBlockly: исправлен параметр «функции JavaScript» с именем по умолчанию, делающий скрипт недоступным для сохранения\nДобавлена история сценариев: сохраненные версии можно перечислять, сравнивать и восстанавливать в редакторе. «Сохраненные версии для каждого скрипта» (по умолчанию 30, 0 отключает)\nДобавлена вкладка «История сценариев» с объемом используемого хранилища для каждого скрипта и кнопками для удаления отдельных, потерянных или всех историй\nПереместил таблицу учетных данных на отдельную вкладку\nЗеркало: измененный файл больше не перезагружает `enabled` и `engine` скрипта (#2396)",
47
- "pt": "O endpoint de uma solicitação de IA sai da configuração e não mais da solicitação. Um endereço na mensagem era usado para vencer o armazenado, que era a forma cômoda de colocar um proxy na frente do OpenAI — e de fazer com que essa instância levasse a chave armazenada, como a “Autorização” do pedido, para um endereço escolhido por outra pessoa. Quem mandar uma mensagem a essa instância pode. Um proxy pertence à configuração agora, onde é inserido uma vez por quem configura o adaptador. O editor nunca enviou um endereço, então nada muda; os botões de teste da caixa de diálogo de configurações testam o que está no formulário, com um limite: um endereço fora do formulário só conta junto com uma chave fora do formulário. No modo de armazenamento de credenciais, o endereço salvo é usado, então um endpoint próprio deve ser salvo antes de testá-lo.\nSomente uma entrada armazenada como credencial de IA é lida no repositório central. A loja guarda os segredos de todo o sistema - senha do banco de dados, login da câmera - e um pedido de “chave desse provedor” pode citar qualquer um deles\nA mensagem `execute` - que executa um script aqui, com toda a API IOBroker - verifica quem a pediu. A mensagem nunca dizia de quem veio, então não havia nada a verificar e todo mundo que enviasse uma para essa instância poderia executar o código. Quando o js-controller nomeia o usuário (7.2.5 e versões mais recentes, que incluem uma conexão de soquete na mensagem), ele precisa dos direitos de um comando no host. Onde não se cita um - um controle antigo, um script, um adaptador - nada muda\nA pergunta antes da sessão de depuração (“O script será interrompido e deve ser ativado manualmente após a depuração”) iniciava a depuração mesmo com “Cancelar” (#2382)\nInterromper uma sessão de depuração pode encerrar o processo depurado com “exceção não detectada: escreva EPIPE”: o processo do inspetor saiu de uma vez, embora ele grave todo o log e continue sendo encerrado. O inspetor agora interrompe o processo primeiro e espera até que ele acabe. Um cano quebrado não pode mais encerrar um script depurado e a reinicialização da conexão não é relatada como um erro interno do inspetor (#2382)\nO chat de IA ficava vazio quando uma solicitação demorava mais de 30 segundos: a resposta agora é enviada em vez de esperar pelo soquete\nUma resposta de IA sem conteúdo agora diz o porquê (motivo, token conta) em vez de deixar um balão vazio, e cada falha é registrada\nUma resposta cortada no limite de saída é incompleta\nOrdenou os scripts na lista `@` do chat de IA por caminho\nO chat de IA pode ser usado em todo o editor (#2389)\nO chat de IA mostra toda a solicitação, não só até a primeira chamada\nCorrigimos uma sugestão de IA aceita que não chegava ao editor\nCorrigido o retorno dos divisores à largura anterior ao ser arrastado\nBlockly: corrigiu o parâmetro de uma “função JavaScript” com o nome padrão e o script não salvo\nHistórico do script: versões salvas podem ser listadas, comparadas e restauradas no editor. “Versões salvas por script” (30 por padrão, 0 desliga)\nFoi adicionada a aba “Histórico de scripts” com botões para excluir histórias únicas, órfãs ou todas\nMudou a tabela de credenciais para sua aba\nMirror: um arquivo alterado não reinicia mais o script (#2396)",
48
- "nl": "Het eindpunt van een AI-verzoek komt voort uit de configuratie en niet meer uit de aanvraag. Een adres in het bericht dat werd gebruikt om het opgeslagen adres te winnen, wat de comfortabele manier was om een proxy voor OpenAI te zetten - en tegelijkertijd de manier om deze instantie de opgeslagen sleutel, als 'autorisatie' van dat verzoek, naar een adres van iemand anders te laten dragen. Wie een bericht naar deze instantie kan sturen, zou dat kunnen doen. Een proxy hoort nu thuis in de configuratie, waar hij één keer wordt ingevoerd door degene die de adapter mag configureren. De redacteur heeft nooit een adres gestuurd, dus er verandert niets; de testknoppen van het instellingenvenster blijven proberen wat er in het formulier staat, met één limiet: een adres buiten het formulier telt alleen mee met een sleutel uit het formulier - de eigen sleutel tot het eigen eindpunt verraadt niets. In de modus voor het opslaan van inloggegevens wordt het opgeslagen adres gebruikt, dus er moet een eigen eindpunt worden opgeslagen voordat het daar kan worden getest.\nAlleen een item dat is opgeslagen als AI-inloggegevens, wordt gelezen uit de centrale opslag voor inloggegevens. De winkel bevat de geheimen van het hele systeem - een wachtwoord voor de database, de login van een camera - en een verzoek om „de sleutel van deze provider” zou elk van hen kunnen noemen\nHet `execute` bericht - dat hier een script uitvoert, met de hele IOBroker API erachter - checkt wie erom heeft gevraagd. In een bericht werd nooit gezegd namens wie het kwam, dus er was niets om te controleren, en iedereen die een bericht naar dit exemplaar zou sturen, kon code laten uitvoeren. Als de js-controller de gebruiker een naam geeft (7.2.5 en nieuwer, waardoor de gebruiker van een socketverbinding in het bericht wordt geplaatst), heeft die gebruiker het recht nodig heeft dat een commando op de host nodig heeft. Waar er geen naam wordt genoemd - een oudere controller, een script, een adapter - verandert er niets\nDe vraag vóór een foutopsporingssessie („Het script wordt gestopt en moet na de foutopsporing handmatig worden geactiveerd”) startte de foutopsporing, zelfs toen deze werd beantwoord met „Annuleren” (#2382)\nAls u een foutopsporingssessie stopt, kan het foutopsporingsproces worden beëindigd met „uncaught exception: write EPIPE”: het inspectieproces werd meteen afgesloten, hoewel het proces dat wordt gedebugd het hele logboek door de leidingen schrijft en nog steeds werd afgesloten. De inspecteur stopt nu eerst dat proces en wacht tot het echt weg is. Een kapotte pipe kan een script met foutopsporing niet meer beëindigen, en het opnieuw instellen van de verbinding met het foutopsporingsproces wordt niet gerapporteerd als een interne fout van de inspecteur (#2382)\nDe AI-chat bleef leeg wanneer een verzoek langer dan 30 seconden duurde: het antwoord wordt nu als een instantiebericht verzonden in plaats van te wachten tot het contact wordt teruggebeld\nEen AI-antwoord zonder inhoud zegt nu waarom (stop reden, token telt) in plaats van een lege chatballon achter te laten, en elk mislukt verzoek wordt geregistreerd\nEen antwoord dat bij de uitvoerlimiet wordt onderbroken, wordt als onvolledig gemarkeerd.\nDe scripts in de `@` lijst van de AI-chat gesorteerd op hun pad\nDe AI-chat kan worden gemaximaliseerd naar het hele redactiegebied (#2389)\nDe AI-chat toont een spinner voor het hele verzoek, niet alleen tot de eerste oproep tot de tool\nEen geaccepteerde AI-suggestie heeft de zichtbare editor niet bereikt\nProbleem opgelost dat de splitters terugsprongen naar hun vorige breedte terwijl ze werden gesleept\nBlockly: een parameter van een „JavaScript-functie” opgelost met de standaardnaam, waardoor het script niet kon worden opgeslagen\nScriptgeschiedenis toegevoegd: opgeslagen versies kunnen worden weergegeven, vergeleken en hersteld in de editor. „Opgeslagen versies per script” (standaard 30, 0 schakelt dit uit)\nEen tabblad „Scriptgeschiedenis” toegevoegd met de gebruikte opslag per script en knoppen om enkele, verweesde of alle geschiedenissen te verwijderen\nDe tabel met inloggegevens is verplaatst naar een eigen tabblad\nSpiegel: in een gewijzigd bestand worden niet langer de `enabled` en `engine` van het script gereset (#2396)",
49
- "fr": "Le point final d'une demande d'IA provient de la configuration et non plus de la demande. Une adresse dans le message l'emportait sur celle enregistrée, ce qui était le moyen le plus simple de placer un proxy devant OpenAI, et en même temps de faire en sorte que cette instance transmette la clé stockée, en tant qu' « autorisation » de cette demande, à une adresse choisie par quelqu'un d'autre. Celui qui enverra un message à cette instance peut le faire. Un proxy a sa place maintenant, où il est saisi une seule fois par le configurateur de l'adaptateur. L'éditeur n'a jamais envoyé d'adresse, donc rien ne change ; les boutons Test de la boîte de dialogue des paramètres permettent d'essayer le contenu du formulaire, avec une limite : une adresse ne compte qu'avec une clé de formulaire. La clé de connexion de chacun à son propre point de terminaison ne donne rien. En mode Credential-Store, l'adresse enregistrée est utilisée, donc votre propre terminal doit être enregistré avant d'y être testé\nSeule une entrée enregistrée sous forme d'IA est lue dans la banque d'informations centrale. La boutique détient les secrets du système (mot de passe de base de données, identifiant d'une caméra) et une demande de « clé de ce fournisseur » pourrait nommer n'importe lequel\nLe message « Execute », qui lance un script ici, avec l'API complète d'IObroker, vérifie qui l'a demandé. Aucun message ne disait de qui il provenait, il n'y avait donc rien à vérifier, et tous ceux qui en envoyaient un à cette instance pouvaient exécuter du code. Lorsque le contrôleur JS donne un nom à l'utilisateur (version 7.2.5 et versions ultérieures, qui met l'utilisateur d'une connexion socket dans le message), il doit saisir une commande sur l'hôte. Là où il n'y en a pas, une ancienne manette, un script, un adaptateur, rien ne change\nLa question posée avant une session de débogage (« Le script sera arrêté et doit être activé manuellement après le débogage ») lançait le débogage même avec la réponse « Annuler » (#2382)\nL'arrêt d'une session de débogage pouvait mettre fin au processus avec « exception non détectée : écrivez EPIPE » : le processus d'inspection s'arrête immédiatement, alors que le processus écrit tout son journal et était toujours en train de s'arrêter. L'inspecteur arrête d'abord ce processus et attend qu'il soit vraiment terminé. Un tuyau cassé ne peut plus arrêter un script, et la réinitialisation de la connexion au processus n'est pas signalée comme une erreur interne de l'inspecteur (#2382)\nLe chat IA restait vide lorsqu'une demande durait plus de 30 secondes : la réponse est envoyée sous forme de message d'instance au lieu d'attendre le rappel\nUne réponse IA sans contenu explique pourquoi (raison de l'arrêt, compte) au lieu de laisser une bulle de discussion vide, et chaque échec est enregistré\nUne réponse coupée à la limite de sortie est marquée comme incomplète\nA trié les scripts de la liste « @ » du chat IA par chemin\nLe chat IA peut être étendu à l'ensemble de l'éditeur (#2389)\nLe chat IA affiche une liste complète de la requête, pas seulement avant le premier outil\nCorrection d'une suggestion d'IA acceptée qui n'atteignait pas l'éditeur\nCorrection des séparateurs qui revenaient à leur largeur d'origine\nBlockly : le nom par défaut d'une « fonction JavaScript » a été corrigé, rendant le script impossible à enregistrer\nAjout d'un historique des scripts : l'éditeur peut lister, comparer et restaurer les versions. « Versions enregistrées par script » (30 par défaut, 0 désactive)\nAjout d'un onglet « Historique des scripts » avec des boutons pour supprimer un historique, orphelin ou complet\nA déplacé le tableau des codes vers son propre onglet\nMiroir : un fichier modifié ne réinitialise plus « activé » et « moteur » du script (#2396)",
50
- "it": "L'endpoint di una richiesta AI deriva dalla configurazione e non più dalla richiesta. Un indirizzo nel messaggio prevaleva su quello memorizzato, che era il modo più comodo per mettere un proxy davanti a OpenAI e per far sì che questa istanza portasse la chiave memorizzata, come «Autorizzazione» della richiesta, a un indirizzo scelto da qualcun altro. Chiunque invii un messaggio a questo caso può farlo. Il proxy fa parte della configurazione ora, e chi configura l'adattatore lo inserisce una volta. L'editor non ha mai inviato un indirizzo, quindi non cambia nulla; i pulsanti Test delle impostazioni continuano a provare ciò che è nel modulo, con un limite: un indirizzo fuori dal modulo conta solo insieme a una chiave. In modalità credenziali si usa l'indirizzo salvato, quindi è necessario salvare un endpoint prima di testarlo\nSolo una voce archiviata come credenziale AI viene letta dall'archivio centrale. Il negozio contiene i segreti del sistema: password del database, login di una telecamera, e richiedendo «la chiave di questo provider»\nIl messaggio `execute`, che esegue uno script con l'intera API IOBroker, verifica chi lo ha richiesto. Un messaggio non diceva da chi provenisse, quindi non c'era nulla da controllare e chiunque ne inviasse uno poteva far eseguire il codice. Se il js-controller nomina l'utente (7.2.5 e successivi, inserendo nel messaggio l'utente di una connessione socket), a quell'utente serve il diritto di comando sull'host. Se non ne nomina uno, un vecchio controller, uno script, non cambia nulla\nLa domanda prima di una sessione di debug («Lo script verrà interrotto e deve essere attivato manualmente dopo il debug») anche se ha risposto con «Annulla» (#2382)\nL'interruzione di una sessione di debug potrebbe terminare con «uncatch exception: write EPIPE»: il processo di ispezione è terminato subito, anche se il processo di debug scrive l'intero log nelle pipe e si sta ancora chiudendo. L'ispettore ora interrompe prima il processo e aspetta che finisca davvero, una pipe rotta non può più terminare uno script di debug e il ripristino della connessione non viene segnalato come errore interno (#2382)\nLa chat AI è rimasta vuota quando una richiesta richiedeva più di 30 secondi: ora la risposta viene inviata come istanza invece di\nUna risposta AI senza contenuto ora spiega perché (stop reason, token counts) invece di lasciare una chat vuota e ogni richiesta fallita\nUna risposta al limite di uscita è incompleta\nHa ordinato gli script della chat AI `@` in base al percorso\nLa chat AI può essere estesa a tutto l'editor (#2389)\nLa chat AI mostra l'intera richiesta, non solo fino al primo tool\nRisolto un problema AI accettato che non arrivava all'editor\nRisolto il problema con gli splitter che tornavano alla larghezza precedente\nBlockly: corretto un parametro di «funzione JavaScript» che rendeva lo script non salvabile\nCronologia script aggiunta: le versioni salvate sono confrontate e ripristinate «Versioni salvate per script» (30 di default, 0 lo spegne)\nAggiunta una scheda «Cronologia script» con spazio per script e pulsanti per eliminare singole o orfane\nHa spostato la tabella credenziali\nMirror: un file modificato non resetta più «enabled» e «engine» (#2396)",
51
- "es": "El punto final de una solicitud de IA sale de la configuración y ya no de la solicitud. Una dirección en el mensaje solía ganarse a la almacenada, que era la forma más cómoda de poner un proxy delante de OpenAI y, al mismo tiempo, hacer que esta instancia llevara la clave almacenada, como «Autorización» de esa solicitud, a la dirección que eligiera otra persona. Quienquiera que envíe un mensaje a esta instancia puede hacerlo. El proxy pertenece a la configuración ahora, donde lo introduce una vez quien configure el adaptador. El editor nunca envió una dirección, así que no cambia nada; los botones de prueba del cuadro de diálogo de ajustes siguen intentando lo que hay en el formulario, con un límite: una dirección fuera del formulario solo cuenta junto con una clave fuera del formulario; la propia clave del punto final no revela nada. En el modo almacén de credenciales se usa la dirección guardada, por lo que hay que guardar un punto final propio antes de poder probarlo allí\nEn la tienda central de credenciales solo se lee una entrada guardada como credencial de IA. La tienda guarda los secretos de todo el sistema (la contraseña de una base de datos, el inicio de sesión de una cámara) y solicitar «la clave de este proveedor» podría nombrar a cualquiera de ellos\nEl mensaje «ejecutar», que ejecuta un guion aquí, con toda la API de IOBroker detrás, comprueba quién lo pidió. Un mensaje nunca decía en nombre de quién venía, así que no había nada que comprobar y cualquiera que enviara uno a esta instancia podría ejecutar código. Cuando el controlador js nombra al usuario (7.2.5 y posterior, que pone al usuario de una conexión de socket en el mensaje), ese usuario necesita el derecho que necesita un comando del host. Cuando no nombra uno (un mando, un guion, un adaptador antiguo), nada cambia\nLa pregunta antes de una sesión de depuración («El guion se detendrá y se activará manualmente tras la depuración») inició la depuración incluso cuando se respondió con «Cancelar» (#2382)\nDetener una sesión de depuración podría terminar el proceso con una «excepción no detectada: escriba EPIPE»: el proceso del inspector salió de una vez, aunque el proceso que depura escribe todo su registro y seguía cerrándose. El inspector ahora detiene primero el proceso y espera a que termine, una tubería rota ya no puede terminar un guion depurado y el restablecimiento de la conexión al proceso depurado no se informa como error interno del inspector (#2382)\nEl chat de IA permaneció vacío cuando una solicitud tardó más de 30 segundos: la respuesta se envía como mensaje de instancia en lugar de esperar a la llamada del socket\nUna respuesta de IA sin contenido ahora dice por qué (detener motivo, cuenta fichas) en lugar de dejar una burbuja de chat vacía, y cada solicitud fallida se registra\nUna respuesta cortada en el límite de salida está incompleta\nOrdenó los guiones de la lista `@ del chat de IA por ruta\nEl chat de IA se puede maximizar en toda el área de edición (#2389)\nEl chat de IA muestra una ruleta para toda la solicitud, no solo hasta la primera llamada\nSe corrigió una sugerencia de IA aceptada que no llegaba al editor visible\nSe ha corregido que los divisores volvieran a su ancho anterior al arrastrarlos\nBlockly: se ha corregido un parámetro de una «función de JavaScript» con su nombre por defecto que no se podía guardar\nAñadió un historial de guiones: las versiones guardadas se muestran, comparan y restauran en el editor. «Versiones guardadas por guion» (30 por defecto, 0 lo desactiva)\nSe ha añadido una pestaña de «Historial de guiones» con el almacenamiento de cada guion y botones para borrar un solo historial, huérfano o todo\nMovió la tabla de credenciales a su pestaña\nEspejo: un archivo cambiado ya no restablece «activado» y «motor» del guion (#2396)",
52
- "pl": "Punkt końcowy żądania AI wychodzi z konfiguracji i nie jest już poza żądaniem. Adres w wiadomości używany do zdobycia zapisanego adresu, co było wygodnym sposobem umieszczenia proxy przed OpenAI - a jednocześnie sposobem, aby ta instancja przenosiła przechowywany klucz, jako „Autoryzacja” tego żądania, na adres wybrany przez kogoś innego. Ktokolwiek może wysłać wiadomość do tej instancji, może to zrobić. Serwer proxy należy teraz do konfiguracji, gdzie jest wprowadzany raz przez każdego, kto może skonfigurować adapter. Edytor nigdy nie wysłał adresu, więc nic się nie zmienia; przyciski Test w oknie dialogowym ustawień wciąż próbują tego, co znajduje się w formularzu, z jednym limitem: adres poza formularzem liczy się tylko razem z kluczem z formularza - własny klucz do własnego punktu końcowego nic nie daje. W trybie przechowywania poświadczeń używany jest zapisany adres, więc własny punkt końcowy musi zostać zapisany, zanim będzie można go tam przetestować\nTylko wpis, który został zapisany jako dane uwierzytelniające AI, jest odczytywany z centralnego magazynu poświadczeń. Sklep przechowuje tajemnice całego systemu - hasło do bazy danych, login kamery - a prośba o „klucz tego dostawcy” może wymienić dowolny z nich\nKomunikat `execute` - który uruchamia tutaj skrypt, za którym znajduje się cały interfejs API ioBroker - sprawdza, kto o to poprosił. Wiadomość nigdy nie powiedziała, w czyim imieniu przyszła, więc nie było nic do sprawdzenia, a każdy, kto może wysłać ją do tej instancji, mógł wykonać kod. Tam, gdzie kontroler js nazywa użytkownika (7.2.5 i nowszy, który umieszcza użytkownika połączenia gniazda w wiadomości), ten użytkownik potrzebuje prawa, którego potrzebuje polecenie na hoście. Gdzie nie nazywa jednego - starszy kontroler, skrypt, adapter - nic się nie zmienia\nPytanie przed sesją debugowania („Skrypt zostanie zatrzymany i musi zostać aktywowany ręcznie po debugowaniu”) rozpoczęło debugowanie nawet wtedy, gdy odpowiedziano na nie „Anuluj” (#2382)\nZatrzymanie sesji debugowania może zakończyć proces debugowania „niewychwytywany wyjątek: napisz EPIPE”: proces inspektora zakończył się natychmiast, chociaż proces, który debuguje, zapisuje cały dziennik przez swoje rury i nadal się zamykał. Inspektor najpierw zatrzymuje ten proces i czeka, aż naprawdę zniknie, zepsuta rura nie może już zakończyć debugowanego skryptu, a zresetowanie połączenia z debugowanym procesem nie jest zgłaszane jako wewnętrzny błąd inspektora (#2382)\nCzat AI pozostał pusty, gdy żądanie trwało dłużej niż 30 sekund: odpowiedź jest teraz przesyłana jako wiadomość instancji zamiast czekać na wywołanie zwrotne gniazda\nOdpowiedź AI bez treści mówi teraz, dlaczego (powód zatrzymania, liczenie tokenów) zamiast pozostawiać pustą bańkę czatu, a każde nieudane żądanie jest rejestrowane\nOdpowiedź odcięta na granicy wyjściowej jest oznaczona jako niekompletna\nPosortowane skrypty na liście `@` czatu AI według ich ścieżki\nCzat AI można zmaksymalizować do całego obszaru edytora (#2389)\nCzat AI pokazuje spinner dla całego żądania, nie tylko do pierwszego wywołania narzędzia\nNaprawiono zaakceptowaną sugestię AI, która nie dotarła do widocznego edytora\nNaprawiono rozgałęźniki przeskakujące z powrotem do poprzedniej szerokości podczas przeciągania\nBlockly: naprawiono parametr „funkcji JavaScript” z jej domyślną nazwą, co uniemożliwia zapisanie skryptu\nDodano historię skryptów: zapisane wersje można wyświetlać, porównywać i przywrócić w edytorze. „Zapisane wersje na skrypt” (domyślnie 30, 0 wyłącza go)\nDodano zakładkę „Historia skryptów” z używaną pamięcią na skrypt i przyciskami do usuwania pojedynczych, osieroconych lub wszystkich historii\nPrzeniesiono tabelę poświadczeń na własną kartę\nMirror: zmieniony plik nie resetuje już „włączonego” i „silnika” skryptu (#2396)",
53
- "uk": "Кінцева точка запиту AI виходить із конфігурації, а більше не із запиту. Адреса в повідомленні використовувалася для перемоги над збереженим, що було зручним способом поставити проксі перед OpenAI - і в той же час спосіб, щоб цей екземпляр переносив збережений ключ, як «Авторизація» цього запиту, на адресу, яку хтось вибрав. Той, хто може надіслати повідомлення цій інстанції, може це зробити. Проксі-сервер зараз належить до конфігурації, де його вводить один раз той, хто може налаштувати адаптер. Редактор ніколи не надсилав адресу, тому для неї нічого не змінюється; кнопки «Тест» діалогового вікна налаштувань продовжують пробувати те, що стоїть у формі, з одним обмеженням: адреса поза формою враховується лише разом із ключем поза формою - власний ключ до власної кінцевої точки нічого не дає. У режимі сховища облікових даних використовується збережена адреса, тому перед тим, як її можна буде перевірити там, потрібно зберегти власну кінцеву точку\nЛише запис, який був збережений як обліковий запис AI, читається з центрального сховища облікових даних. У магазині зберігаються секрети всієї системи - пароль бази даних, логін камери - і запит на «ключ цього провайдера» міг назвати будь-який з них\nПовідомлення `execute` - яке запускає тут скрипт, з усім API IObroker за ним - перевіряє, хто його запитав. У повідомленні ніколи не було сказано, від чиго імені воно прийшло, тому перевіряти нічого, і кожен, хто може надіслати його на цей екземпляр, міг виконати код. Якщо js-контролер називає користувача (7.2.5 і новіших версій, які поміщають користувача підключення до сокета в повідомлення), цьому користувачеві потрібно право, яке потрібно команді на хості. Де не називає одного - старий контролер, скрипт, адаптер - нічого не змінюється\nПитання перед сеансом налагодження («Скрипт буде зупинений і повинен бути активований вручну після налагодження») запустило налагодження навіть тоді, коли на нього відповіли «Скасувати» (#2382)\nЗупинення сеансу налагодження може завершити налагоджений процес із «незловленим винятком: запишіть EPIPE»: процес інспектора вийшов одразу, хоча процес, який він налагоджує, записує весь свій журнал через свої труби і все ще вимикався. Тепер інспектор спочатку зупиняє цей процес і чекає, поки він дійсно зникне, зламана труба більше не може закінчити налагоджений скрипт, а скидання з'єднання з налагодженим процесом не повідомляється як внутрішня помилка інспектора (#2382)\nЧат AI залишався порожнім, коли запит тривав більше 30 секунд: відповідь тепер передається як повідомлення про екземпляр замість того, щоб чекати зворотного виклику сокета\nВідповідь AI без вмісту тепер говорить чому (причина зупинки, кількість токенів) замість того, щоб залишати порожню бульбашку чату, і кожен невдалий запит реєструється\nВідповідь, відрізана на вихідній межі, позначається як неповна\nСортування скриптів у списку `@` чату AI за їх шляхом\nЧат AI може бути максимально розширений для всієї області редактора (#2389)\nЧат AI показує спіннер для всього запиту, не тільки до першого виклику інструменту\nВиправлено прийняту пропозицію AI, яка не потрапляє до видимого редактора\nВиправлено, коли спліттери повертаються до попередньої ширини під час перетягування\nBlockly: виправлено параметр «функції JavaScript» з її назвою за замовчуванням, що робить сценарій непридатним для збереження\nДодана історія скриптів: збережені версії можна перерахувати, порівнювати та відновлювати в редакторі. «Збережені версії для скрипту» (30 за замовчуванням, 0 вимикає його)\nДодана вкладка «Історія сценаріїв» з використовуваним сховищем для скрипта та кнопками для видалення одиничних, осиротілих або всіх історій\nПереміщено таблицю облікових даних на власну вкладку\nДзеркало: змінений файл більше не скидає `enabled` і `engine` скрипта (#2396)",
54
- "zh-cn": "AI 请求的端点来自配置,不再来自请求。消息中的一个地址过去用来赢得存储的地址,这是在 OpenAI 面前放置代理的便捷方式,同时也是让该实例将存储的密钥(作为该请求的 “授权”)携带到他人选择的地址的方法。任何可以向该实例发送消息的人都可以这样做。代理现在属于配置中,任何可以配置适配器的人都只能输入一次代理。编辑器从未发送过地址,因此没有任何变化;设置对话框的测试按钮一直在尝试表单中的内容,但有一个限制:表单中的地址只能与表单中的密钥一起计算——一个人自己访问自己端点的密钥不会泄露任何东西。在凭证存储模式下,使用保存的地址,因此必须先保存自己的端点,然后才能在那里进行测试\n只有作为 AI 凭据存储的条目才能从中央凭证存储中读取。商店保存着整个系统的秘密——数据库密码、摄像机的登录名——而请求 “这个提供商的密钥” 可以说出其中任何一个的名字\n“执行” 消息——它在这里运行一个脚本,背后是整个 IOBroker API ——检查是谁要求的。一条消息从来没有说过是代表谁来的,所以没有什么可检查的,每个可能向这个实例发送一条消息的人都可以执行代码。其中 js-controller 命名用户(7.2.5 及更高版本,它将套接字连接的用户放入消息中),则该用户需要主机上命令所需的权限。它没有命名的地方 —— 较旧的控制器、脚本、适配器 —— 没有任何变化\n调试会话之前的问题(“脚本将停止,调试后必须手动激活”)启动了调试,即使回答 “取消” (#2382)\n停止调试会话可能会以 “未捕获的异常:写入 EPIPE” 结束调试进程:检查器进程立即退出,尽管它调试的进程通过管道写入了全部日志,并且仍在关闭。检查器现在会先停止该进程,然后等到它真正消失,管道损坏无法再结束已调试的脚本,并且重置与调试进程的连接不会被报告为检查器的内部错误 (#2382)\n当请求花费超过 30 秒时,AI 聊天将保持空白:答案现在作为实例消息推送,而不是等待套接字回调\n没有内容的 AI 答案现在会显示原因(停止原因、令牌数),而不是留下空的聊天气泡,并且每个失败的请求都会被记录下来\n输出限制处截止的答案被标记为不完整\n按路径对 AI 聊天的 `@` 列表中的脚本进行排序\nAI 聊天可以最大化到整个编辑器区域 (#2389)\nAI 聊天会显示整个请求的微调器,不仅仅是第一次工具调用\n修复了接受的 AI 建议无法到达可见编辑器的问题\n修复了分离器在被拖动时会跳回之前的宽度的问题\nBlockly:修复了使用默认名称的 “JavaScript 函数” 的参数使脚本无法保存的问题\n添加了脚本历史记录:可以在编辑器中列出、比较和恢复保存的版本。“每个脚本保存的版本”(默认为 30,0 将其关闭)\n添加了 “脚本历史记录” 选项卡,其中包含每个脚本使用的存储空间以及用于删除单个、孤立或所有历史记录的按钮\n已将凭据表移至其自己的选项卡\n镜像:更改后的文件不再重置脚本的 “已启用” 和 “引擎” (#2396)"
43
+ "10.4.2": {
44
+ "en": "Fixed: the AI chat stopped with \"m.default is not a constructor\", and the variable view of the debugger did not show objects",
45
+ "de": "Behoben: Der KI-Chat endete mit „m.default is not a constructor“ und die Variablenansicht des Debuggers zeigte keine Objekte",
46
+ "ru": "Исправлено: чат с искусственным интеллектом останавливался с надписью «m.default не является конструктором», а в виде переменных в отладчике не отображались объекты",
47
+ "pt": "Corrigido: o chat de IA parou com “m.default não é um construtor” e a visão variável do depurador não mostra objetos",
48
+ "nl": "Opgelost: de AI-chat stopte met „m.default is geen constructor”, en de variabele weergave van de debugger toonde geen objecten",
49
+ "fr": "Corrigé : le chat IA s'arrêtait avec « m.default n'est pas un constructeur » et la vue variable du débogueur ne montrait aucun objet",
50
+ "it": "Risolto: la chat AI si fermava con «m.default non è un costruttore» e la vista variabile del debugger non mostrava oggetti",
51
+ "es": "Corregido: el chat de la IA paró con «m.default no es un constructor» y la vista variable del depurador no mostraba objetos",
52
+ "pl": "Naprawiono: czat AI zatrzymał się z „m.default nie jest konstruktorem”, a zmienny widok debuggera nie pokazywał obiektów",
53
+ "uk": "Виправлено: чат AI зупинився з «m.default не є конструктором», а змінний вигляд налагоджувача не показував об'єктів",
54
+ "zh-cn": "修复:AI 聊天因 “m.default 不是构造函数” 而停止,调试器的变量视图未显示对象"
55
+ },
56
+ "10.4.1": {
57
+ "en": "Changed: the AI assistant uses the shared libraries `@iobroker/ai-core` and `@iobroker/ai-gui`",
58
+ "de": "Geändert: Der KI-Assistent nutzt die Bibliotheken @iobroker /ai-core und @iobroker /ai-gui",
59
+ "ru": "Изменено: помощник по искусственному интеллекту использует разделяемые библиотеки `@iobroker /ai-core` и `@iobroker /ai-gui`",
60
+ "pt": "Alterado: o assistente de IA usa as bibliotecas `@iobroker /ai-core` e `@iobroker /ai-gui`",
61
+ "nl": "Gewijzigd: de AI-assistent gebruikt de gedeelde bibliotheken `@iobroker /ai-core` en `@iobroker /ai-gui`",
62
+ "fr": "Modifié : l'assistant IA utilise les bibliothèques partagées @iobroker /ai-core et @iobroker /ai-gui",
63
+ "it": "Modificato: l'AI usa le librerie condivise @iobroker /ai-core e @iobroker /ai-gui",
64
+ "es": "Cambiado: el asistente de IA usa las bibliotecas compartidas `@iobroker /ai-core` y `@iobroker /ai-gui`",
65
+ "pl": "Zmieniono: asystent AI korzysta z bibliotek współdzielonych `@iobroker /ai-core` i `@iobroker /ai-gui`",
66
+ "uk": "Змінено: помічник AI використовує спільні бібліотеки `@iobroker /ai-core` та `@iobroker /ai-gui`",
67
+ "zh-cn": "已更改:AI 助手使用共享库 @iobroker /ai-core 和 @iobroker /ai-gui"
55
68
  },
56
69
  "10.3.0": {
57
70
  "en": "The code editor (Monaco), Blockly and the Rules blocks are loaded only when a script of that kind is opened, so the editor starts faster\nAdded function block diagrams (FBD, in the style of CFC): timers, counters, flip-flops, edges, comparison, arithmetic, conversions, control, calendar (cron, sun events), log and messages, and a block with own JavaScript - wired to ioBroker states. See [the description](docs/en/fbd.md)",
@@ -117,19 +130,6 @@
117
130
  "pl": "Zasady: wybór stanu stałego",
118
131
  "uk": "Правила: вибір штату фіксований",
119
132
  "zh-cn": "规则:选州固定"
120
- },
121
- "10.2.1": {
122
- "en": "Rules: selection of state fixed",
123
- "de": "Regeln: Bundeslandwahl fest",
124
- "ru": "Правила: выбор фиксированного государства",
125
- "pt": "Regras: seleção de estado fixo",
126
- "nl": "Regels: de keuze van de staat is vastgesteld",
127
- "fr": "Règles : choix de l'État fixe",
128
- "it": "Regole: scelta dello stato fissa",
129
- "es": "Reglas: selección de estado fija",
130
- "pl": "Zasady: wybór stanu stałego",
131
- "uk": "Правила: вибір штату фіксований",
132
- "zh-cn": "规则:选州固定"
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.4.0",
3
+ "version": "10.4.2",
4
4
  "description": "Rules Engine for ioBroker",
5
5
  "author": "bluefox <dogafox@gmail.com>",
6
6
  "contributors": [
@@ -42,15 +42,16 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@iobroker/adapter-core": "^3.4.3",
45
- "@iobroker/types": "^7.2.4",
45
+ "@iobroker/ai-core": "^0.0.4",
46
+ "@iobroker/types": "^7.2.5",
46
47
  "@types/node": "^22.20.5",
47
48
  "axios": "^1.20.0",
48
49
  "jsonata": "^2.2.2",
49
50
  "jszip": "^3.10.2",
50
51
  "node-inspect": "^2.0.0",
51
52
  "node-schedule": "2.1.1",
52
- "nodemailer": "^10.0.14",
53
- "prettier": "^3.9.9",
53
+ "nodemailer": "^10.1.0",
54
+ "prettier": "^3.9.10",
54
55
  "semver": "^7.8.5",
55
56
  "suncalc2": "^1.8.1",
56
57
  "typescript": "~6.0.3",
@@ -72,7 +73,7 @@
72
73
  "@types/request": "^2.48.13",
73
74
  "@types/suncalc": "^1.9.2",
74
75
  "alcalzone-shared": "^5.0.0",
75
- "jsdom": "^30.1.1",
76
+ "jsdom": "^30.1.2",
76
77
  "timekeeper": "^2.3.1"
77
78
  },
78
79
  "bugs": {
@@ -1,27 +0,0 @@
1
- import{An as e,Ar as t,Bn as n,Dt as r,Et as i,Fn as a,Fr as o,Jt as s,Kt as c,Ln as l,Mn as u,On as d,Or as f,Qn as p,Sr as m,Tr as h,Tt as g,Wt as _,Xt as v,Yn as y,Yt as b,bn as ee,cr as x,gt as S,in as C,jr as w,lr as T,m as E,qt as D,rn as O,xn as k,zn as A}from"./_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__234968779812303__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BRdHvuuG.js";import{t as j}from"./Send-Pz1eveU5.js";import{t as te}from"./vite-preload-helper-DjNwdemH.js";import{c as ne,o as M,s as N}from"./index-Bmmscq2G.js";import{_ as P,a as F,c as I,d as L,f as R,g as z,h as B,i as V,l as H,m as U,n as W,o as G,p as K,r as q,s as J,t as Y,u as re}from"./AiChatService-DP1EmVk2.js";import{t as X}from"./blocklyTheme-iZoge1S9.js";var Z=y(x(`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`),ie=y(x(`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`),ae=y(x(`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`),oe=y(x(`path`,{d:`M9.01 14H2v2h7.01v3L13 15l-3.99-4zm5.98-1v-3H22V8h-7.01V5L11 9z`}),`CompareArrows`),se=y(x(`path`,{d:`M7 14H5v5h5v-2H7zm-2-4h2V7h3V5H5zm12 7h-3v2h5v-5h-2zM14 5v2h3v3h2V5z`}),`Fullscreen`),ce=y(x(`path`,{d:`M5 16h3v3h2v-5H5zm3-8H5v2h5V5H8zm6 11h2v-3h3v-2h-5zm2-11V5h-2v5h5V8z`}),`FullscreenExit`),le=y(x(`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`),ue=y(x(`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`),de=y(x(`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 fe=[{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 pe(e){return e&&typeof e==`object`?e.en||e.de||``:e||``}function me(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=pe(i.name).toLowerCase();if(a&&a.includes(r))return!0;let o=(i.role||``).toLowerCase();return!!(o&&o.includes(r))}async function he(e,t,n=20,r){let i=await G(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||!me(e,r,t))continue;let l=r.common,u={id:e,type:s,name:pe(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 ge(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 _e=new Set([`channel`,`device`,`folder`,`adapter`,`instance`,`enum`,`meta`]),ve=50;async function ye(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:pe((n=t.common)==null?void 0:n.name),common:t.common})}}catch{}}if(o.length>0&&(i.parents=o),_e.has(r.type)){let n=await G(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:pe(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>=ve){o=!0;break}}r.length>0&&(i.children=r,o&&(i.childrenTruncated=!0,i.childrenHint=`Only the first ${ve} 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 be(e){return N(e)||e}function xe(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?be(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(`
2
- `),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 Se(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?be(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 Ce(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 we(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 Te(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 he(e,a.query,a.max_results||20,a.object_type);case`get_state_value`:return ge(e,a.id);case`get_object_info`:return ye(e,a.id);case`search_scripts`:return xe(n||[],a.query,a.max_results||10);case`read_script`:return Se(n||[],a.id);case`list_scripts`:return Ce(n||[]);case`run_script`:return we(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 Ee=0;function De(){return`msg_${Date.now()}_${++Ee}`}function Oe(e){let{socket:n,runningInstances:r,currentCode:i,currentLanguage:a,allScripts:o,editorApi:s,currentScriptId:c}=e,l=m((e,t,n)=>e===`none`||!n?null:{range:t,scriptId:c||``,scriptVersion:(i||``).length,kind:e,originalText:n},[c,i]),[u,d]=w(()=>{try{let e=window.localStorage.getItem(`Editor.aiChatMessages`);return e?JSON.parse(e):[]}catch{return[]}}),f=m(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,g]=w(!1),[_,v]=w(null),[y,b]=w(window.localStorage.getItem(`Editor.aiChatMode`)||`agent`),ee=m(e=>{b(e),window.localStorage.setItem(`Editor.aiChatMode`,e)},[]),[x,S]=w(null),[C,T]=w(window.localStorage.getItem(`openai-model`)||``),[D,O]=w([]),[k,A]=w({}),[j,N]=w(!0),[W,G]=w(null),Y=t(null),X=t(null),Z=t(null),ie=t(null),ae=m(e=>{T(e),B(e,k[e])},[k]),oe=m(async()=>{N(!0),G(null);try{let e=await K(n,r);if(O(e.models),A(e.providerMap),e.models.length>0){let t=U().model,n=t&&e.models.includes(t)?t:e.models[0];T(n),B(n,e.providerMap[n])}e.errors.length>0&&G(e.errors.join(`; `))}catch(e){G(String(e))}N(!1)},[n,r]);h(()=>{oe()},[oe]);let se=m(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]),ce=m(async(e,t,s)=>{ie.current||=await re(),Y.current||=await J(n,r);let c=L(),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.
3
-
4
- ioBroker object hierarchy: adapter.instance.device.channel.state
5
- - A "state" is a single datapoint (e.g. zigbee2mqtt.0.0x1234.temperature)
6
- - A "channel" groups related states (e.g. zigbee2mqtt.0.0x1234 contains temperature, humidity, battery)
7
- - A "device" groups channels (e.g. zigbee2mqtt.0.0x1234)
8
- - The channel/device often has the human-readable name (e.g. "Living Room Sensor")
9
- 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.
10
-
11
- 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.
12
-
13
- Available API and syntax rules:
14
- ${ie.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)&&(Z.current||=await F(n),d+=`\n\nAvailable smart home devices:\n${JSON.stringify(Z.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${M(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${M(e,!0)}`)}return l&&(d+=`\n\n${I(c)}`),[{role:`system`,content:d}]},[n,r,i,a,o]),le=m(async e=>{if(!e.trim()||p)return;let t=k[C];if(!t){S(E.t(`Please select a valid model`));return}let i=Y.current||await J(n,r);if(Y.current=i,!i){S(E.t(`No API keys configured`));return}let o=Object.keys(r)[0];if(!o){S(E.t(`No running javascript instance found`));return}let s=t===`custom`&&i.gptBaseUrl||``,c={id:De(),role:`user`,content:e,timestamp:Date.now()},l={id:De(),role:`assistant`,content:`⏳ ${E.t(`Generating plan...`)}`,timestamp:Date.now()};f(e=>[...e,c,l]),g(!0),S(null);try{let r=L();Z.current||=await F(n);let i=Z.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 z(n,o,{messages:[{role:`user`,content:c}],model:C,provider:t,baseUrl:s});if(l.error){S(l.error),f(e=>e.slice(0,-2)),g(!1);return}let u=P(l.content||``)||V(l);f(e=>{let t=[...e],n=t[t.length-1];return(n==null?void 0:n.role)===`assistant`&&(t[t.length-1]={...n,content:`📋 **${E.t(`Plan`)}:**\n${u}`}),t});let d={id:De(),role:`assistant`,content:`⏳ ${E.t(`Generating code...`)}`,timestamp:Date.now()};f(e=>[...e,d]);let p=a===`blockly`,m=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.`,h=p?I(r):H(r),_=await z(n,o,{messages:[{role:`system`,content:h},{role:`user`,content:m}],model:C,provider:t,baseUrl:s});if(_.error){S(_.error),f(e=>e.slice(0,-1)),g(!1);return}let y=P(_.content||``)||V(_);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}),v(`${E.t(`devices`)}: ${i.length}`)}catch(e){S(String(e)),f(e=>e.slice(0,-1))}g(!1)},[C,k,p,n,r,a,f]),ue=m(async e=>{if(y===`code`)return le(e);if(!e.trim()||p)return;let t=k[C];if(!t){S(E.t(`Please select a valid model`));return}let i=Y.current||await J(n,r);if(Y.current=i,!i){S(E.t(`No API keys configured`));return}let a=Object.keys(r)[0];if(!a){S(E.t(`No running javascript instance found`));return}let c=X.current;if(X.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 m={id:De(),role:`user`,content:e,timestamp:Date.now(),sourceRange:c},h={id:De(),role:`assistant`,content:``,timestamp:Date.now(),sourceRange:c};f(e=>[...e,m,h]),g(!0),S(null);let{cleanMessage:_,mentionedScriptIds:b,includeAll:ee,includeDevices:x}=se(e),w=[];if(ee)w.push(`${E.t(`all scripts`)} (${(o==null?void 0:o.length)||0})`);else if(b.length>0){let e=b.map(e=>e.replace(/^script\.js\./,``));w.push(e.join(`, `))}else w.push(E.t(`current script`));x&&w.push(E.t(`devices`)),v(`${E.t(`Context`)}: ${w.join(` + `)}`);let T=await ce(ee,x,b),D=t===`custom`&&i.gptBaseUrl||``,O=_||e;if(o&&o.length>0){let e=O.match(/\b[\w-]+\.\d+\.[\w.-]+/g);if(e){let t=[];for(let n of new Set(e)){let e=ne(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(`
15
- `)}`)}t.length>0&&(O+=`\n\n[Automatic analysis results]\n${t.join(`
16
-
17
- `)}`)}}let A=[...T,...u.filter(e=>e.role!==`system`).map(e=>({role:e.role,content:e.content})),{role:`user`,content:O}],j=y===`agent`;try{let e=[...A],r=!1;for(let i=0;i<5;i++){let c=await z(n,a,{messages:e,model:C,provider:t,baseUrl:D,...j?{tools:fe}:{}});if(c.error){if(j&&i===0&&c.error.toLowerCase().includes(`tool`)){let i=await z(n,a,{messages:e,model:C,provider:t,baseUrl:D});if(i.error)S(i.error),f(e=>e.slice(0,-1));else{let e=P(i.content||``)||V(i);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})}r=!0;break}S(c.error),f(e=>e.slice(0,-1)),r=!0;break}let l=c.tool_calls;if((!l||l.length===0)&&j&&c.content){let e=c.content.trim();try{let t=JSON.parse(e);t.name&&t.arguments&&(l=[{id:`text_tool_${Date.now()}`,type:`function`,function:{name:t.name,arguments:JSON.stringify(t.arguments)}}])}catch{}}if(!l||l.length===0){let e=P(c.content||``);e&&R(c)&&(e+=`\n\n⚠️ ${E.t(`The answer is incomplete: the model hit its output limit. Raise "Maximum answer length" in the adapter settings, or ask for a smaller part.`)}`),e||(e=V(c),console.warn(`[AiChat] no usable content in the answer`,{instanceId:a,model:C,provider:t,round:i,rawLength:(c.content||``).length,result:c})),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}),r=!0;break}c.tool_calls=l;let u=c.tool_calls.map(e=>{let t={};try{t=JSON.parse(e.function.arguments)}catch{}switch(e.function.name){case`search_datapoints`:return`🔍 ${E.t(`Searching datapoints`)}: "${String(t.query||``)}"`;case`get_state_value`:return`📊 ${E.t(`Reading value`)}: ${String(t.id||``)}`;case`get_object_info`:return`📋 ${E.t(`Loading object info`)}: ${String(t.id||``)}`;case`search_scripts`:return`🔍 ${E.t(`Searching scripts`)}: "${String(t.query||``)}"`;case`read_script`:return`📖 ${E.t(`Reading script`)}: ${String(t.id||``)}`;case`list_scripts`:return`📂 ${E.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:u.join(`
18
- `)}),t}),e.push({role:`assistant`,content:c.content||``,tool_calls:c.tool_calls});for(let t of c.tool_calls){let r=await Te(n,t,o,s,a);e.push({role:`tool`,tool_call_id:t.id,content:r})}}if(!r){let e=E.t(`No final answer after %s tool rounds`,`5`);S(e),f(t=>{let n=[...t],r=n[n.length-1];return(r==null?void 0:r.role)===`assistant`&&(n[n.length-1]={...r,content:`${r.content?`${r.content}\n\n`:``}⚠️ ${e}`}),n})}}catch(e){S(String(e)),f(e=>e.slice(0,-1))}g(!1)},[C,k,u,p,n,r,ce,se,o,y,le,f,l,s]),de=m(()=>{f([]),S(null),g(!1),v(null),q(),window.localStorage.removeItem(`Editor.aiChatHistory`)},[f]),pe=m(async(e,t)=>{let i=k[C];if(!i)return`Error: ${E.t(`Please select a valid model`)}`;let o=Y.current||await J(n,r);if(Y.current=o,!o)return`Error: ${E.t(`No API keys configured`)}`;let s=Object.keys(r)[0];if(!s)return`Error: ${E.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 z(n,s,{messages:[{role:`system`,content:u},{role:`user`,content:d}],model:C,provider:i,baseUrl:c});return e.error?`Error: ${e.error}`:e.content||``}catch(e){return`Error: ${e.message||String(e)}`}},[C,k,r,n,a]);return{messages:u,isLoading:p,error:x,model:C,availableModels:D,modelProviderMap:k,modelsLoading:j,modelsError:W,lastContextInfo:_,mode:y,setMode:ee,setModel:ae,sendMessage:ue,triggerAiAction:m(e=>{e.range&&e.code?X.current=l(e.kind||`codelens`,e.range,e.code):X.current=null,te(async()=>{let{buildActionPrompt:e}=await import(`./aiPromptBuilder-Co6AqZwx.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?ue(n):X.current=null}).catch(()=>{X.current=null,S(E.t(`Failed to build AI action prompt`))})},[ue,a,l]),askInline:pe,clearChat:de,retryLoadModels:oe}}o();var ke=({code:e,language:n,themeType:r,onInsertCode:i,onShowDiff:a,sourceRange:o})=>{let l=t(null);h(()=>{var t;let i=window.monaco;if(!l.current||!(i!=null&&(t=i.editor)!=null&&t.colorize))return;let a=n===`ts`||n===`typescript`?`typescript`:n||`javascript`;i.editor.colorize(e,a,{theme:r===`dark`?`vs-dark`:`vs`}).then(e=>{l.current&&(l.current.innerHTML=e)})},[e,n,r]);let u=m(()=>{navigator.clipboard.writeText(e)},[e]);return T(s,{sx:{position:`relative`,my:1,borderRadius:1,overflow:`hidden`,border:`1px solid`,borderColor:`divider`},children:[T(s,{sx:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,px:1,py:.5,bgcolor:`action.hover`,borderBottom:`1px solid`,borderColor:`divider`},children:[x(s,{sx:{fontSize:`0.75rem`,color:`text.secondary`,textTransform:`uppercase`},children:n||`javascript`}),T(s,{children:[x(c,{title:E.t(`Copy`),children:x(k,{size:`small`,onClick:u,children:x(g,{sx:{fontSize:16}})})}),i&&x(c,{title:E.t(`Insert into editor`),children:x(k,{size:`small`,onClick:()=>i(e),children:x(Z,{sx:{fontSize:16}})})}),a&&x(c,{title:E.t(`Show as diff`),children:x(k,{size:`small`,onClick:()=>a(e,o),children:x(oe,{sx:{fontSize:16}})})})]})]}),x(`pre`,{ref:l,style:{margin:0,padding:`8px 12px`,overflow:`auto`,maxHeight:400,fontSize:`13px`,fontFamily:`'Cascadia Code', 'Fira Code', 'Consolas', monospace`,backgroundColor:r===`dark`?`#1e1e1e`:`#f8f8f8`,color:r===`dark`?`#d4d4d4`:`#333`},children:e})]})};o();var Ae=({xml:e})=>{let n=p(),r=t(null),i=t(null),[a,o]=w(60),c=t(!1);return h(()=>{c.current&&(c.current=!1,requestAnimationFrame(()=>{let e=window.Blockly,t=i.current;e&&t&&(e.svgResize(t),t.scrollCenter())}))},[a]),h(()=>{let t=window.Blockly;if(t&&r.current){i.current&&=(i.current.dispose(),null);try{let a=t.inject(r.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:X(n),media:`google-blockly/media/`});i.current=a;let s=e.trim();s.startsWith(`<xml`)||(s=`<xml xmlns="https://developers.google.com/blockly/xml">${s}</xml>`);let l=t.utils.xml.textToDom(s),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;t.Xml.domToWorkspace(l,a);let f=a.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=a.getBlocksBoundingBox();if(p){let e=p.bottom-p.top+20,t=Math.max(60,Math.ceil(e));c.current=!0,o(t)}}catch{}return()=>{i.current&&=(i.current.dispose(),null)}}},[e,n]),x(s,{ref:r,sx:{width:`100%`,height:a,minHeight:60,borderRadius:1,overflow:`hidden`,border:`1px solid`,borderColor:`divider`}})};o();function je(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(x(`strong`,{children:i[2]},a++)):i[3]?t.push(x(`em`,{children:i[3]},a++)):i[4]&&t.push(x(`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 Me(e){return e.trim().startsWith(`|`)&&e.trim().endsWith(`|`)}function Ne(e){return/^\|[\s:]*-+[\s:|-]*\|$/.test(e.trim())}function Pe(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 x(s,{sx:{overflowX:`auto`,my:1},children:T(`table`,{style:{borderCollapse:`collapse`,width:`100%`,fontSize:`0.8rem`,color:t.palette.text.primary},children:[x(`thead`,{children:x(`tr`,{children:a.map((e,n)=>x(`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))})}),x(`tbody`,{children:o.map((e,n)=>x(`tr`,{style:{backgroundColor:n%2==1?r?t.palette.grey[900]:t.palette.grey[50]:void 0},children:e.map((e,n)=>x(`td`,{style:{border:`1px solid ${t.palette.divider}`,padding:`6px 10px`,color:t.palette.text.primary},children:$(e)},n))},n))})]})},n)}function Fe(e,t){let n=e.split(`
19
- `),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(x(`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(x(`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(Me(e)&&a+1<n.length&&Ne(n[a+1].trim())&&a+2<n.length){let e=[n[a],n[a+1]],o=a+2;for(;o<n.length&&Me(n[o]);)e.push(n[o]),o++;r.push(Pe(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(x(`ul`,{style:{margin:`4px 0`,paddingLeft:20},children:e.map((e,t)=>x(`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(x(`ol`,{style:{margin:`4px 0`,paddingLeft:20},children:e.map((e,t)=>x(`li`,{children:$(e)},t))},i++));continue}r.push(x(`div`,{children:$(e)},i++)),a++}return r}var Ie=({message:e,themeType:t,currentLanguage:r,onInsertCode:i,onShowDiff:a,onApplyCode:o})=>{let c=e.role===`user`,l=b(),u=c?t===`dark`?l.palette.primary.dark:l.palette.primary.main:t===`dark`?l.palette.secondary.dark:l.palette.secondary.main,d=l.palette.getContrastText(u),p=f(()=>je(e.content),[e.content]),m=(e,t)=>!!(e===`xml`||e===`blockly`||r===`blockly`&&t&&/<block\s+type=/.test(t));return T(s,{sx:{display:`flex`,gap:1,px:1.5,py:1,mx:.75,my:.5,bgcolor:c?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:u,transition:`background-color 120ms`,"&:hover":{bgcolor:c?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:[x(n,{sx:{width:28,height:28,bgcolor:u,color:d,flexShrink:0,mt:.5},children:x(c?le:de,{sx:{fontSize:18}})}),x(s,{sx:{flex:1,minWidth:0,fontSize:`0.875rem`,lineHeight:1.6},children:p.map((n,r)=>n.type===`code`?m(n.language,n.content)?T(s,{sx:{my:1},children:[x(Ae,{xml:n.content}),T(s,{sx:{display:`flex`,gap:.5,mt:.5},children:[o&&x(v,{size:`small`,variant:`contained`,color:`primary`,startIcon:x(ue,{sx:{fontSize:14}}),onClick:()=>o(n.content),sx:{textTransform:`none`,fontSize:`0.75rem`},children:E.t(`Apply blocks`)}),i&&x(v,{size:`small`,variant:`outlined`,startIcon:x(Z,{sx:{fontSize:14}}),onClick:()=>i(n.content),sx:{textTransform:`none`,fontSize:`0.75rem`},children:E.t(`Insert blocks`)})]})]},r):x(ke,{code:n.content,language:n.language||`javascript`,themeType:t,onInsertCode:i,onShowDiff:a,sourceRange:e.sourceRange||null},r):x(s,{sx:{wordBreak:`break-word`,color:l.palette.text.primary},children:Fe(n.content,l)},r))})]})};function Le(e){let t=(e||``).toLowerCase();return t.includes(`blockly`)||t.includes(`rules`)?`blockly`:t.includes(`typescript`)?`typescript`:`javascript`}function Re(e,t){return`\`\`\`${t===`blockly`?`xml`:t}\n${e}\n\`\`\``}function ze(e){let t=(e.code||``).trim(),n=Le(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.`,``,Re(t,n)].join(`
20
- `):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.`,``,Re(t,n)].join(`
21
- `):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.`,``,Re(t,n)].join(`
22
- `):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.`,``,Re(t,n)].join(`
23
- `)}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.`,``,Re(t,n)].join(`
24
- `):null;case`ask`:{let i=(e.question||``).trim();return i?t?[`Regarding this ioBroker ${n} code${r}:`,``,Re(t,n),``,i].join(`
25
- `):i:null}default:return null}}function Be(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 Ve(){return[{id:`@all`,label:E.t(`mention @all`),descriptionKey:`All scripts`},{id:`@devices`,label:E.t(`mention @devices`),descriptionKey:`Smart home devices`}]}function He({provider:e,isDark:t}){return W[e]?x(`img`,{src:`./img/${e}.svg`,alt:e,style:{...Y,...t?{filter:`invert(0.85)`}:{}},onError:e=>{e.target.style.display=`none`}}):null}function Ue(){try{let e=window.localStorage.getItem(`Editor.aiChatHistory`);return e?JSON.parse(e):[]}catch{return[]}}var We=({onSend:n,disabled:r,themeType:o,hasSelection:p,selectionText:g,allScripts:v,model:y,availableModels:b,modelProviderMap:ee,modelsLoading:S,onModelChange:C,mode:te,onModeChange:ne,currentLanguage:M})=>{let[N,P]=w(``),[F,I]=w(!1),[L,R]=w(``),[z,B]=w(0),V=t(null),H=t(-1),U=t(Ue()),W=t(-1),G=t(``),K=f(()=>{let e=Ve().map(e=>({...e,description:E.t(e.descriptionKey)}));if(v){let t=v.map(e=>{let t=e.id.replace(/^script\.js\./,``).replace(/\./g,`/`);return{id:`@${t}`,label:`@${t}`,description:`${e.name} [${e.enabled?`active`:`inactive`}]`}});t.sort((e,t)=>e.label.localeCompare(t.label,void 0,{numeric:!0})),e.push(...t)}return e},[v]),q=f(()=>{if(!L)return K;let e=L.toLowerCase();return K.filter(t=>t.id.toLowerCase().includes(e)||t.description.toLowerCase().includes(e))},[K,L]);h(()=>{B(0)},[L]);let J=m(()=>{let e=N.trim();if(!e||r)return;let t=e,i=Be(e);if(i){let e=p&&g?g:``,n=ze({action:i.action,code:e,language:M||`javascript`,question:i.action===`ask`?i.rest:void 0,diagnostic:i.action===`fix`&&i.rest||void 0});n&&(t=n)}else p&&g&&(t=`[Selected code in editor]\n\`\`\`\n${g}\n\`\`\`\n\n${e}`);U.current.push(e),W.current=-1,G.current=``;try{let e=U.current.slice(-50);window.localStorage.setItem(`Editor.aiChatHistory`,JSON.stringify(e))}catch{}n(t),P(``),I(!1),requestAnimationFrame(()=>{var e;return(e=V.current)==null?void 0:e.focus()})},[N,r,n,p,g,M]),Y=m(e=>{let t=H.current,n=V.current;if(t<0){let t=N?`${N}${e} `:`${e} `;P(t),I(!1),R(``),setTimeout(()=>{n&&(n.focus(),n.setSelectionRange(t.length,t.length))},0);return}let r=N.substring(0,t),i=(n==null?void 0:n.selectionStart)??N.length,a=`${r}${e} ${N.substring(i)}`;P(a),I(!1),R(``),H.current=-1,setTimeout(()=>{if(n){let t=r.length+e.length+1;n.focus(),n.setSelectionRange(t,t)}},0)},[N]),re=m(()=>{H.current=-1,R(``),I(e=>!e)},[]),X=m(e=>{let t=e.target.value;P(t);let n=e.target.selectionStart??t.length,r=t.substring(0,n).match(/@([\w/äöüÄÖÜß]*)$/);r?(H.current=n-r[0].length,R(r[1]),I(!0)):(I(!1),R(``))},[]),Z=m(e=>{if(F&&q.length>0){if(e.key===`ArrowDown`){e.preventDefault(),B(e=>(e+1)%q.length);return}if(e.key===`ArrowUp`){e.preventDefault(),B(e=>(e-1+q.length)%q.length);return}if(e.key===`Enter`||e.key===`Tab`){e.preventDefault(),Y(q[z].id);return}if(e.key===`Escape`){e.preventDefault(),I(!1);return}}if(e.key===`ArrowUp`&&!F&&U.current.length>0){let t=V.current,n=!t||t.selectionStart===0,r=!N.includes(`
26
- `);if(n&&r){e.preventDefault(),W.current===-1?(G.current=N,W.current=U.current.length-1):W.current>0&&W.current--,P(U.current[W.current]);return}}if(e.key===`ArrowDown`&&!F&&W.current>=0){let t=V.current,n=!t||t.selectionStart===N.length,r=!N.includes(`
27
- `);if(n&&r){e.preventDefault(),W.current<U.current.length-1?(W.current++,P(U.current[W.current])):(W.current=-1,P(G.current));return}}e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),J())},[J,F,q,z,Y,N]);return T(s,{sx:{borderTop:`1px solid`,borderColor:`divider`,position:`relative`},children:[F&&q.length>0&&x(l,{elevation:4,sx:{position:`absolute`,bottom:`100%`,left:8,right:8,maxHeight:200,overflow:`auto`,zIndex:10,mb:.5},children:x(d,{dense:!0,disablePadding:!0,children:q.slice(0,15).map((t,n)=>x(e,{selected:n===z,onClick:()=>Y(t.id),sx:{py:.25,minHeight:32},children:x(u,{primary:t.label,secondary:t.description,slotProps:{primary:{sx:{fontSize:`0.8rem`,fontWeight:500}},secondary:{sx:{fontSize:`0.7rem`}}}})},t.id))})}),te===`code`&&x(O,{label:`${E.t(`mention @devices`)} — ${E.t(`Smart home devices`)}`,size:`small`,variant:`outlined`,sx:{mx:1,mt:.5,maxWidth:`calc(100% - 16px)`}}),p&&g&&x(O,{icon:x(i,{sx:{fontSize:14}}),label:E.t(`Selected code as context`),size:`small`,variant:`outlined`,sx:{mx:1,mt:.5,maxWidth:`calc(100% - 16px)`}}),T(s,{sx:{mx:1,mt:.5,mb:.5,border:`1px solid`,borderColor:`divider`,borderRadius:1.5,overflow:`hidden`,"&:focus-within":{borderColor:`primary.main`}},children:[x(_,{inputRef:V,fullWidth:!0,multiline:!0,maxRows:6,placeholder:E.t(`Ask about your script...`),value:N,onChange:X,onKeyDown:Z,disabled:r,onBlur:()=>{setTimeout(()=>I(!1),200)},variant:`standard`,slotProps:{input:{disableUnderline:!0}},sx:{px:1.5,pt:1,pb:.5,"& .MuiInputBase-root":{fontSize:`0.875rem`}}}),T(s,{sx:{display:`flex`,alignItems:`center`,gap:.75,px:1,pb:.5},children:[x(c,{title:T(s,{sx:{fontSize:`0.8rem`,lineHeight:1.5,maxWidth:360},children:[x(s,{sx:{fontWeight:600,mb:.75},children:E.t(`AI chat mode`)}),T(s,{sx:{mb:.75},children:[T(`strong`,{children:[`💬 `,E.t(`Chat`)]}),` —`,` `,E.t(`Plain conversation. Use for questions, explanations, syntax help. Does not read or modify your scripts.`)]}),T(s,{sx:{mb:.75},children:[T(`strong`,{children:[`🤖 `,E.t(`Agent`)]}),` —`,` `,E.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".`)]}),T(s,{children:[T(`strong`,{children:[`💻 `,E.t(`Code`)]}),` —`,` `,E.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:T(A,{value:te,onChange:e=>ne(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:[x(a,{value:`chat`,sx:{fontSize:`0.75rem`},title:E.t(`Plain conversation. Best for: general questions, syntax help, concept explanations.`),children:`💬 Chat`}),x(a,{value:`agent`,sx:{fontSize:`0.75rem`},title:E.t(`For larger models with tool support. Best for: creating, editing, or analyzing scripts; finding datapoint usages; inspecting the object tree.`),children:`🤖 Agent`}),x(a,{value:`code`,sx:{fontSize:`0.75rem`},title:E.t(`For smaller models without tool support. Best for: creating new JavaScript/TypeScript or Blockly scripts from a description.`),children:`💻 Code`})]})}),x(A,{value:y,onChange:e=>C(e.target.value),size:`small`,disabled:S||b.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:b.map(e=>T(a,{value:e,sx:{fontSize:`0.75rem`,display:`flex`,gap:.5},children:[x(He,{provider:ee[e],isDark:o===`dark`}),e]},e))}),x(c,{title:E.t(`Mention scripts as context for the AI. Use @all for all scripts or @scriptName for a specific one.`),enterDelay:500,children:x(k,{size:`small`,onClick:re,sx:{p:`3px`,color:F?`primary.main`:`text.secondary`,border:`1px solid`,borderColor:F?`primary.main`:`text.secondary`,bgcolor:F?void 0:`action.hover`,borderRadius:3,"&:hover":{borderColor:`text.disabled`,bgcolor:`action.hover`}},children:x(ae,{sx:{fontSize:16}})})}),x(s,{sx:{flex:1}}),T(D,{variant:`caption`,sx:{color:`text.disabled`,fontSize:`0.65rem`,mr:.5,whiteSpace:`nowrap`},children:[`Enter `,E.t(`to send`)]}),x(c,{title:`${E.t(`Send`)} (Enter)`,children:x(`span`,{children:x(k,{color:`primary`,onClick:J,disabled:r||!N.trim(),size:`small`,sx:{p:.25},children:x(j,{sx:{fontSize:18}})})})})]})]})]})};o();var Ge=({socket:e,runningInstances:n,themeType:i,currentCode:a,currentLanguage:o,selectedCode:l,allScripts:u,editorApi:d,aiActionRequest:p,onAiActionConsumed:g,onRegisterInlineAsk:_,onInsertCode:v,onShowDiff:y,onApplyCode:b,currentScriptId:w,maximized:O,onToggleMaximized:A,onClose:j})=>{var te;let ne=t(null),{messages:M,isLoading:N,error:P,model:F,availableModels:I,modelProviderMap:L,modelsLoading:R,modelsError:z,lastContextInfo:B,mode:V,setMode:H,setModel:U,sendMessage:W,triggerAiAction:G,askInline:K,clearChat:q,retryLoadModels:J}=Oe(f(()=>({socket:e,runningInstances:n,currentCode:a,currentLanguage:o,allScripts:u,editorApi:d,currentScriptId:w}),[e,n,a,o,u,d,w]));h(()=>(_==null||_(K),()=>_==null?void 0:_(null)),[K,_]);let Y=t(null);h(()=>{p&&Y.current!==p&&(Y.current=p,G(p),g==null||g())},[p,G,g]),h(()=>{var e;(e=ne.current)==null||e.scrollIntoView({behavior:`smooth`})},[M]);let re=m(e=>{v==null||v(e)},[v]),X=m((e,t)=>{y==null||y(e,t)},[y]),Z=m(e=>{b==null||b(e)},[b]);return T(s,{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:[T(s,{sx:{display:`flex`,alignItems:`center`,gap:1,px:1,py:.5,borderBottom:`1px solid`,borderColor:`divider`,bgcolor:i===`dark`?`grey.900`:`grey.100`,flexShrink:0},children:[x(D,{variant:`subtitle2`,sx:{fontWeight:600,flex:1,color:`text.primary`},children:E.t(`AI Chat`)}),(R||N)&&x(C,{size:16}),x(c,{title:E.t(`New chat`),children:x(k,{size:`small`,onClick:q,children:x(ie,{sx:{fontSize:18}})})}),A?x(c,{title:O?E.t(`Restore the split view`):E.t(`Use the whole width`),children:x(k,{size:`small`,onClick:A,children:x(O?ce:se,{sx:{fontSize:18}})})}):null,x(c,{title:E.t(`Close`),children:x(k,{size:`small`,onClick:j,children:x(r,{sx:{fontSize:18}})})})]}),(P||z)&&x(ee,{severity:`error`,sx:{m:1,py:0},action:z?x(k,{size:`small`,onClick:J,children:x(S,{sx:{fontSize:16}})}):void 0,children:P||z}),B&&x(D,{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:B}),T(s,{sx:{flex:1,overflow:`auto`,py:1},children:[M.length===0&&!N&&T(s,{sx:{display:`flex`,flexDirection:`column`,alignItems:`center`,justifyContent:`center`,height:`100%`,color:`text.secondary`,px:3,textAlign:`center`},children:[x(D,{variant:`body2`,sx:{mb:1},children:E.t(`Ask questions about your script, request changes, or generate new code.`)}),T(D,{variant:`caption`,color:`text.disabled`,children:[`Enter `,E.t(`to send`),`, Shift+Enter `,E.t(`for new line`)]})]}),M.filter(e=>e.role!==`system`).map(e=>x(Ie,{message:e,themeType:i,currentLanguage:o,onInsertCode:re,onShowDiff:X,onApplyCode:Z},e.id)),N&&T(s,{sx:{display:`flex`,alignItems:`center`,gap:1,px:2,py:1},children:[x(C,{size:16}),x(D,{variant:`caption`,color:`text.secondary`,children:(te=M[M.length-1])!=null&&te.content?E.t(`Request is running...`):E.t(`Thinking...`)})]}),x(`div`,{ref:ne})]}),x(We,{onSend:W,disabled:N||I.length===0,themeType:i,hasSelection:!!l,selectionText:l,allScripts:u,model:F,availableModels:I,modelProviderMap:L,modelsLoading:R,onModelChange:U,mode:V,onModeChange:H,currentLanguage:o})]})};export{Ge as default,Be as n,ze as t};
@@ -1,216 +0,0 @@
1
- import{o as e}from"./rolldown-runtime-C0FnF6B9.js";import{m as t,ut as n}from"./_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__234968779812303__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BRdHvuuG.js";import{t as r}from"./vite-preload-helper-DjNwdemH.js";var i=e(n(),1),a=r(()=>import(`./docs-compact-D7rpMc7r.js`),[],import.meta.url),o={openai:`img/openai.svg`,anthropic:`img/anthropic.svg`,gemini:`img/gemini.svg`,deepseek:`img/deepseek.svg`,custom:`img/custom.svg`},s={width:16,height:16,flexShrink:0,opacity:.7},c={ru:`Russian`,en:`English`,de:`German`,es:`Spanish`,fr:`French`,it:`Italian`,pl:`Polish`,nl:`Dutch`,pt:`Portuguese`,uk:`Ukrainian`,"zh-cn":`Chinese`},l=null,u=null,d=null,f=null;function p(){l=null,u=null,d=null,f=null}async function m(e,t){if(l)return l;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?(l={providers:i,gptBaseUrl:a==null?void 0:a.baseUrl},l):null}var h=`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 g(e){let t=e.toLowerCase();return!(h.some(e=>t.includes(e))||t.startsWith(`claude-1`)||t.startsWith(`claude-instant`))}var _=`openai-model`,v=`openai-model-provider`;function y(e,t){window.localStorage.setItem(_,e),t?window.localStorage.setItem(v,t):window.localStorage.removeItem(v)}function b(){return{model:window.localStorage.getItem(_)||``,provider:window.localStorage.getItem(v)||``}}async function x(e,n){let r=await m(e,n);if(!r)return{models:[],providerMap:{},errors:[`No API keys configured`]};let i=Object.keys(n)[0];if(!i)return{models:[],providerMap:{},errors:[t.t(`No running javascript instance found`)]};let a=[],o={},s=[],c={},l=[],u=(t,n)=>{l.push(e.sendTo(i,`testApiConnection`,{provider:t}).then(e=>{e.models?c[t]=e.models:e.error&&s.push(`${n||t}: ${e.error}`)}).catch(e=>{s.push(`${n||t}: ${String(e)}`)}))},d={openai:`OpenAI`,anthropic:`Anthropic`,gemini:`Gemini`,deepseek:`DeepSeek`,custom:`Custom`};for(let e of r.providers)u(e,d[e]);await Promise.all(l);for(let e of r.providers)for(let t of c[e]||[])g(t)&&!o[t]&&(a.push(t),o[t]=e);return a.sort(),{models:a,providerMap:o,errors:s}}var S=`aiChatAnswer`,C=6e5,w=null,T=null,E=0;function D(){w=null,T=null}async function O(e,t){return w||(T||=(async()=>{let n={sessionToken:`ai-${Date.now().toString(36)}-${Math.random().toString(36).substring(2,10)}`,pending:new Map};try{let r=await e.subscribeOnInstance(t,S,{sessionToken:n.sessionToken},e=>{let t=e;if(!(t!=null&&t.requestId))return;let r=n.pending.get(t.requestId);r&&(n.pending.delete(t.requestId),r(t))});return r!=null&&r.accepted?(e.registerConnectionHandler(function t(n){n||(e.unregisterConnectionHandler(t),D())}),w=n,n):null}catch(e){return console.warn(`[AiChat] cannot subscribe for pushed answers, falling back to the callback`,e),null}finally{T=null}})(),T)}async function k(e,n,r){var i;let a=r.timeout||C,o=await O(e,n),s=o?`req-${++E}-${Date.now().toString(36)}`:``,c=await e.sendTo(n,`chatCompletion`,{timeout:a,model:r.model,provider:r.provider,messages:r.messages,...r.baseUrl?{baseUrl:r.baseUrl}:{},...(i=r.tools)!=null&&i.length?{tools:r.tools}:{},...o?{uiSession:o.sessionToken,requestId:s}:{}});return!o||!(c!=null&&c.accepted)?c:new Promise(e=>{let n=setTimeout(()=>{o.pending.delete(s),D(),e({error:`${t.t(`No answer within`)} ${Math.round(a/1e3)}s`})},a);o.pending.set(s,t=>{clearTimeout(n),e(t)})})}async function A(e){if(f)return f;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 f=Object.assign(t,n,r,i,a),f}async function j(e){return A(e)}function M(e,t){return e&&typeof e==`object`?e[t]||e.en:e||``}async function N(e){if(u)return u;let n=t.getLanguage(),r=await A(e),a=Object.keys(r).sort(),o=new i.default,s=[],c=[`UNREACH_STICKY`],l=[i.Types.info],d=[],f=[],p=[],m=[];a.forEach(e=>{var t,n;((t=r[e])==null?void 0:t.type)===`enum`?d.push(e):(n=r[e])!=null&&(n=n.common)!=null&&n.smartName&&m.push(e)}),d.forEach(e=>{e.startsWith(`enum.rooms.`)?f.push(e):e.startsWith(`enum.functions.`)&&p.push(e);let t=r[e].common.members;t!=null&&t.length&&t.forEach(e=>{r[e]&&!m.includes(e)&&m.push(e)})});let h={id:``,objects:r,_keysOptional:a,_usedIdsOptional:s,ignoreIndicators:c,excludedTypes:l},g=[];m.forEach(e=>{h.id=e;let t=o.detect(h);t&&t.forEach(e=>{var t;let i=(t=e.states.find(e=>e.id))==null?void 0:t.id;if(!i||g.find(e=>e.id===i))return;let a=r[i],o={id:i,name:M(a.common.name,n),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:r[e.id].common.type,unit:r[e.id].common.unit,read:r[e.id].common.read??!0,write:r[e.id].common.write??!0}))},s=i.split(`.`),c,l;(a.type===`channel`||a.type===`state`)&&(s.pop(),c=s.join(`.`),r[c]&&(r[c].type===`channel`||r[c].type===`folder`)?(s.pop(),l=s.join(`.`),(!r[l]||r[l].type!==`device`&&r[c].type!==`folder`)&&(l=void 0)):c=void 0);let u=f.find(e=>{var t,n,a;return(t=r[e].common.members)!=null&&t.includes(i)||c&&(n=r[e].common.members)!=null&&n.includes(c)?!0:l&&((a=r[e].common.members)==null?void 0:a.includes(l))});u&&(o.room=M(r[u].common.name,n));let d=p.find(e=>{var t,n,a;return(t=r[e].common.members)!=null&&t.includes(i)||c&&(n=r[e].common.members)!=null&&n.includes(c)?!0:l&&((a=r[e].common.members)==null?void 0:a.includes(l))});d&&(o.function=M(r[d].common.name,n)),g.push(o)})});for(let e=0;e<g.length;e++){let t=g[e];if(t.type===`state`||t.type===`channel`){let e=t.id.split(`.`);e.pop();let i=r[e.join(`.`)];if(i&&(i.type===`channel`||i.type===`device`||i.type===`folder`)){var _,v;t.name=M(((_=i.common)==null?void 0:_.name)||t.name,n),e.pop();let a=r[e.join(`.`)];if((a==null?void 0:a.type)===`device`&&(v=a.common)!=null&&v.icon){var y;t.name=M(((y=a.common)==null?void 0:y.name)||t.name,n)}}else{var b;t.name=M((i==null||(b=i.common)==null?void 0:b.name)||t.name,n)}}}return u=g,g}async function P(){return d||(d=(await a).default,d)}function F(){return c[t.getLanguage()]||`English`}function I(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 L(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 R(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()}function z(e){return e.finishReason===`max_tokens`||e.finishReason===`length`}function B(e){var n,r;let i=(e.content||``).trim(),a=[];if(e.finishReason&&a.push(`${t.t(`Stop reason`)}: ${e.finishReason}`),((n=e.usage)==null?void 0:n.input)!==void 0||((r=e.usage)==null?void 0:r.output)!==void 0){var o,s;a.push(`${t.t(`Tokens in/out`)}: ${((o=e.usage)==null?void 0:o.input)??`?`}/${((s=e.usage)==null?void 0:s.output)??`?`}`)}let c=a.length?` (${a.join(`, `)})`:``;if(i)return`⚠️ ${t.t(`The model answered with reasoning only, no result`)}${c}\n\n${i}`;if(e.finishReason===`max_tokens`||e.finishReason===`length`)return`⚠️ ${t.t(`The model used up its output budget before writing an answer. Try a shorter question or less context.`)}${c}`;if(e.success!==!0){let n;try{n=typeof e==`string`?e:JSON.stringify(e)}catch{n=Object.prototype.toString.call(e)}return`⚠️ ${t.t(`The javascript adapter did not answer this request. Check the adapter log.`)}\n\n\`${t.t(`Reply`)}: ${n.substring(0,300)}\``}return`⚠️ ${t.t(`The model returned an empty answer`)}${c}`}export{R as _,N as a,L as c,F as d,z as f,k as g,y as h,B as i,I as l,b as m,o as n,j as o,x as p,p as r,m as s,s as t,P as u};
@@ -1 +0,0 @@
1
- import{Ar as e,Dt as t,Fr as n,Gt as r,Jt as i,Sr as a,Xt as o,cr as s,kt as c,lr as l,m as u,qt as d}from"./_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__234968779812303__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BRdHvuuG.js";import{t as f}from"./MonacoDiff-BYvG7IqB.js";n();var p=({originalCode:n,modifiedCode:p,language:m,themeType:h,onAccept:g,onReject:_})=>{let v=e(null),y=a(()=>{var e;g(((e=v.current)==null?void 0:e.getModifiedValue())??p)},[p,g]);return l(i,{sx:{display:`flex`,flexDirection:`column`,height:`100%`,width:`100%`},children:[l(r,{variant:`dense`,sx:{minHeight:36,bgcolor:`background.paper`,borderBottom:`1px solid`,borderColor:`divider`,gap:1,flexShrink:0},children:[s(d,{variant:`subtitle2`,sx:{flex:1},children:u.t(`AI suggested changes`)}),s(o,{variant:`contained`,color:`success`,size:`small`,startIcon:s(c,{}),onClick:y,children:u.t(`Accept`)}),s(o,{variant:`outlined`,color:`error`,size:`small`,startIcon:s(t,{}),onClick:_,children:u.t(`Reject`)})]}),s(i,{sx:{flex:1,overflow:`hidden`},children:s(f,{ref:v,originalCode:n,modifiedCode:p,language:m,themeType:h})})]})};export{p as default};