iobroker.javascript 10.2.5 → 10.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -23
- package/admin/assets/AiChatPanel-BjRIKaXG.js +27 -0
- package/admin/assets/{AiChatService-BOL3J2Jd.js → AiChatService-DP1EmVk2.js} +3 -3
- package/admin/assets/AiDiffView-DeynDw7L.js +1 -0
- package/admin/assets/{AiInlineProvider-BIlcrTkS.js → AiInlineProvider-jkEIJJJ-.js} +1 -1
- package/admin/assets/BlocklyEditor-DhwThchX.js +301 -0
- package/admin/assets/Compile-B0uHjrBE.css +1 -0
- package/admin/assets/Compile-e8N5zI-J.js +165 -0
- package/admin/assets/Debugger-BDQUKM1K.js +15 -0
- package/admin/assets/Diff--plofAtP.js +1 -0
- package/admin/assets/{Documentation-Bc0RmoEF.js → Documentation-D3E0U4AK.js} +4 -4
- package/admin/assets/ExpandMore-Dio4GeHC.js +1 -0
- package/admin/assets/FbEditor-B8S-mCvc.css +1 -0
- package/admin/assets/FbEditor-BjLPNzpK.js +15 -0
- package/admin/assets/History-Ewi5YEEn.js +1 -0
- package/admin/assets/Import-6Mm2vrM2.js +1 -0
- package/admin/assets/MonacoDiff-BYvG7IqB.js +1 -0
- package/admin/assets/NotificationsActive-CuNfWVJM.js +1 -0
- package/admin/assets/RulesEditor--YX6ETsU.js +1 -0
- package/admin/assets/{ScriptEditor-CEHpEFp7.js → ScriptEditor-BadPC8Mf.js} +2 -2
- package/admin/assets/ScriptEditorVanillaMonaco-BnAmy59d.js +3 -0
- package/admin/assets/Send-Pz1eveU5.js +1 -0
- package/admin/assets/_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-Ceh8EDcF.js +1 -0
- 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 +1217 -0
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__234968779812303__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-DLWT3PGo.js +9 -0
- package/admin/assets/aiPromptBuilder-Co6AqZwx.js +1 -0
- package/admin/assets/{blockly-fcfyKYzp.js → blockly-B0t_IRJQ.js} +1 -1
- package/admin/assets/blocklyTheme-iZoge1S9.js +1 -0
- package/admin/assets/blocks_action-Ctn5A1AU.js +1 -0
- package/admin/assets/{blocks_convert-BP2RjhQH.js → blocks_convert-BI0lf0sf.js} +1 -1
- package/admin/assets/blocks_logic-o49klUX_.js +1 -0
- package/admin/assets/blocks_number-DZtyWFyR.js +1 -0
- package/admin/assets/blocks_object-BuzGCxVr.js +1 -0
- package/admin/assets/blocks_procedures-jn9sIYmR.js +3 -0
- package/admin/assets/blocks_sendto-Coui8w1H.js +5 -0
- package/admin/assets/blocks_switch-CeRZizTM.js +2 -0
- package/admin/assets/blocks_system-CaBPIC40.js +1 -0
- package/admin/assets/blocks_text-DeDtPYWf.js +1 -0
- package/admin/assets/blocks_time-CTXQH3Lm.js +1 -0
- package/admin/assets/blocks_timeout-D8IOKOb-.js +1 -0
- package/admin/assets/{blocks_trigger-CnmXLCUE.js → blocks_trigger-zuuXJbhb.js} +2 -2
- package/admin/assets/{cronHoverProvider-CcIFAhVy.js → cronHoverProvider-Curcjz4m.js} +1 -1
- package/admin/assets/dist-CzitsFi7.js +1 -0
- package/admin/assets/field_cron-RgLY53_S.js +1 -0
- package/admin/assets/field_oid-rBhotXJe.js +1 -0
- package/admin/assets/field_script-CU7g3-oB.js +1 -0
- package/admin/assets/helpers-BZgjFQNf.js +1 -0
- package/admin/assets/helpers-BwllSRzJ.js +1 -0
- package/admin/assets/hostInit-CrHjJGJJ.js +1 -0
- package/admin/assets/index-BHhhebRG.css +1 -0
- package/admin/assets/index-Bmmscq2G.js +157 -0
- package/admin/assets/{inlineChatWidget-N8xIkvxX.js → inlineChatWidget-ChchJD9a.js} +2 -2
- package/admin/assets/{inlineDiffController-BuqYsKKq.js → inlineDiffController-ly6qX4jk.js} +2 -2
- package/admin/assets/loadBlocks-BcFtthDb.js +117 -0
- package/admin/assets/loadMonaco-BVOEahNw.js +1 -0
- package/admin/assets/{mf-entry-bootstrap-0-a5a39621.js → mf-entry-bootstrap-0-6db6c4fc.js} +3 -3
- package/admin/assets/pendingShares-mBGPbRwZ.js +2 -0
- package/admin/assets/reactour.esm-Dk3aGxKn.js +137 -0
- package/admin/assets/{stateHoverProvider-BYAbe1Ay.js → stateHoverProvider-wAsP-THx.js} +1 -1
- package/admin/assets/tileFbd-CWAy7R7m.svg +85 -0
- package/admin/assets/utils-DUKzLJUz.js +4 -0
- package/admin/assets/vite-preload-helper-DjNwdemH.js +1 -0
- package/admin/custom/assets/Components-fDcxCyN4.js +1 -0
- package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-BraOrMSu.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-DbKT6Hsb.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-CVvbIPAy.js +1 -0
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DVb0ZZ1Q.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BhZYie9-.js} +89 -89
- 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 +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare__date_mf_2_fns__loadShare__.js-Djg9OMcQ.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare__leaflet__loadShare__.js-D9EyCd42.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__loadShare__shared-Hb6V6BnJ.js +2 -0
- 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 +122 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__prebuild__leaflet__prebuild__-CHjWtrkp.js +1 -0
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__prebuild__react_mf_2_dom_mf_1_client__prebuild__-DOkC-g0X.js +9 -0
- package/admin/custom/assets/dist-CzitsFi7.js +1 -0
- package/admin/custom/assets/helpers-BZgjFQNf.js +1 -0
- package/admin/custom/assets/hostInit-akwaQLq8.js +1 -0
- package/admin/custom/assets/index-BkItz-nL.js +1 -0
- package/admin/custom/assets/{lib-BmDlTzq2.js → lib-CADOx2YN.js} +1 -1
- package/admin/custom/assets/{mf-entry-bootstrap-0-ad1cd7d0.js → mf-entry-bootstrap-0-3c4565e0.js} +3 -3
- package/admin/custom/assets/pendingShares-TCMDgBLn.js +2 -0
- package/admin/custom/assets/utils-DUKzLJUz.js +4 -0
- package/admin/custom/assets/vite-preload-helper-DjNwdemH.js +1 -0
- package/admin/custom/customComponents.js +2 -2
- package/admin/custom/i18n/de.json +19 -1
- package/admin/custom/i18n/en.json +19 -1
- package/admin/custom/i18n/es.json +19 -1
- package/admin/custom/i18n/fr.json +19 -1
- package/admin/custom/i18n/it.json +19 -1
- package/admin/custom/i18n/nl.json +19 -1
- package/admin/custom/i18n/pl.json +19 -1
- package/admin/custom/i18n/pt.json +19 -1
- package/admin/custom/i18n/ru.json +19 -1
- package/admin/custom/i18n/uk.json +19 -1
- package/admin/custom/i18n/zh-cn.json +19 -1
- package/admin/i18n/de.json +13 -1
- package/admin/i18n/en.json +13 -1
- package/admin/i18n/es.json +13 -1
- package/admin/i18n/fr.json +13 -1
- package/admin/i18n/it.json +13 -1
- package/admin/i18n/nl.json +13 -1
- package/admin/i18n/pl.json +13 -1
- package/admin/i18n/pt.json +13 -1
- package/admin/i18n/ru.json +13 -1
- package/admin/i18n/uk.json +13 -1
- package/admin/i18n/zh-cn.json +13 -1
- package/admin/jsonConfig.json +274 -86
- package/admin/mf-manifest.json +1 -1
- package/admin/mf-stats.json +1 -1
- package/admin/remoteEntry.js +2 -2
- package/admin/tab.html +3 -7
- package/build/lib/aiProviderResolver.js +145 -25
- package/build/lib/aiProviderResolver.js.map +1 -1
- package/build/lib/anthropicAdapter.js +37 -0
- package/build/lib/anthropicAdapter.js.map +1 -1
- package/build/lib/fb/analyze.js +288 -0
- package/build/lib/fb/analyze.js.map +1 -0
- package/build/lib/fb/blocks.js +605 -0
- package/build/lib/fb/blocks.js.map +1 -0
- package/build/lib/fb/generate.js +326 -0
- package/build/lib/fb/generate.js.map +1 -0
- package/build/lib/fb/graph.js +240 -0
- package/build/lib/fb/graph.js.map +1 -0
- package/build/lib/fb/index.js +57 -0
- package/build/lib/fb/index.js.map +1 -0
- package/build/lib/fb/js.js +33 -0
- package/build/lib/fb/js.js.map +1 -0
- package/build/lib/fb/layout.js +205 -0
- package/build/lib/fb/layout.js.map +1 -0
- package/build/lib/fb/library.js +657 -0
- package/build/lib/fb/library.js.map +1 -0
- package/build/lib/fb/runtime.js +793 -0
- package/build/lib/fb/runtime.js.map +1 -0
- package/build/lib/fb/time.js +76 -0
- package/build/lib/fb/time.js.map +1 -0
- package/build/lib/fb/types.js +19 -0
- package/build/lib/fb/types.js.map +1 -0
- package/build/lib/fb/user.js +78 -0
- package/build/lib/fb/user.js.map +1 -0
- package/build/lib/inspect.js +66 -10
- package/build/lib/inspect.js.map +1 -1
- package/build/lib/javascript.d.ts +1 -1
- package/build/lib/mirror.js +28 -23
- package/build/lib/mirror.js.map +1 -1
- package/build/lib/sandbox.js +44 -0
- package/build/lib/sandbox.js.map +1 -1
- package/build/lib/scriptHistory.js +245 -0
- package/build/lib/scriptHistory.js.map +1 -0
- package/build/main.js +641 -32
- package/build/main.js.map +1 -1
- package/build/types.d.ts +20 -1
- package/docs/de/fbd.md +274 -0
- package/docs/en/fbd.md +260 -0
- package/io-package.json +55 -29
- package/package.json +7 -7
- package/admin/assets/AiChatPanel-oBeXbUFv.js +0 -27
- package/admin/assets/AiDiffView-C-KKjnJD.js +0 -1
- package/admin/assets/Debugger-DwHHsh9O.js +0 -15
- package/admin/assets/Error-DZ4vCykD.js +0 -1
- package/admin/assets/Import-Cu02ceLW.js +0 -1
- package/admin/assets/RulesEditor-QCbi1lV_.js +0 -1
- package/admin/assets/ScriptEditorVanillaMonaco-ChQmnk0p.js +0 -3
- package/admin/assets/_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-CM95r358.js +0 -1
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BEpNZh4U.js +0 -1217
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-FeM77flT.js +0 -9
- package/admin/assets/aiPromptBuilder-DKler0UK.js +0 -1
- package/admin/assets/blocks_action-DywZVfRY.js +0 -1
- package/admin/assets/blocks_logic-CdTl5YZw.js +0 -1
- package/admin/assets/blocks_number-DXFd9Rva.js +0 -1
- package/admin/assets/blocks_object-by1uBDHi.js +0 -1
- package/admin/assets/blocks_procedures-BcJ7N70D.js +0 -3
- package/admin/assets/blocks_sendto-qIKzOAcV.js +0 -5
- package/admin/assets/blocks_switch-dLF6hSJl.js +0 -2
- package/admin/assets/blocks_system-DmX-SBy8.js +0 -1
- package/admin/assets/blocks_text-BI4zNU3o.js +0 -1
- package/admin/assets/blocks_time-BgYA4Y_4.js +0 -1
- package/admin/assets/blocks_timeout-DUzgMyAu.js +0 -1
- package/admin/assets/dist-D4uJqRBO.js +0 -4
- package/admin/assets/field_cron-Ba46q8Qc.js +0 -1
- package/admin/assets/field_oid-lWCjOzuq.js +0 -1
- package/admin/assets/field_script-BCWZHhnW.js +0 -1
- package/admin/assets/helpers-CnEjYAup.js +0 -1
- package/admin/assets/hostInit-CVybS7BB.js +0 -1
- package/admin/assets/index-B3s0zmWC.js +0 -871
- package/admin/assets/index-CXaeqPRy.css +0 -1
- package/admin/assets/pendingShares-DOAkyFMS.js +0 -1
- package/admin/assets/vite-preload-helper-CaC3yEL3.js +0 -1
- package/admin/custom/assets/Components-FkGDIlId.js +0 -1
- package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-Cs88NUCd.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-P-8ffWXw.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-ZVuRAEo5.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-Dna3WF04.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare___mf_0_mui_mf_1_x_mf_2_date_mf_2_pickers__loadShare__.js-DcjdCGAx.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare__date_mf_2_fns__loadShare__.js-CnhNjamd.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare__leaflet__loadShare__.js-Dz7BFJqH.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-B0olko2J.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-CzN4reh_.js +0 -122
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild__leaflet__prebuild__-xPcBaiTQ.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild__react_mf_2_dom_mf_1_client__prebuild__-DuFBE5fh.js +0 -9
- package/admin/custom/assets/dist-D4uJqRBO.js +0 -4
- package/admin/custom/assets/hostInit-6oh4UY2k.js +0 -1
- package/admin/custom/assets/index-BrlyEy6J.js +0 -1
- package/admin/custom/assets/pendingShares-kV2kwejX.js +0 -1
- package/admin/custom/assets/vite-preload-helper-CaC3yEL3.js +0 -1
- /package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__37453319418803__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-CXpyx8Vy.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__198282747311932__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-CXpyx8Vy.js} +0 -0
package/README.md
CHANGED
|
@@ -18,6 +18,8 @@ Executes JavaScript, TypeScript Scripts.
|
|
|
18
18
|
- 🇺🇸 [Upgrade guide](docs/en/upgrade-guide.md)
|
|
19
19
|
- 🇩🇪 [Funktionsdokumentation](docs/de/javascript.md)
|
|
20
20
|
- 🇩🇪 [Benutzung](docs/de/usage.md)
|
|
21
|
+
- 🇺🇸 [Function block diagrams](docs/en/fbd.md)
|
|
22
|
+
- 🇩🇪 [Funktionspläne](docs/de/fbd.md)
|
|
21
23
|
- Blockly
|
|
22
24
|
- 🇺🇸 Here you can find the description of [blockly](docs/en/blockly.md).
|
|
23
25
|
- 🇩🇪 Hier kann man die Beschreibung von [Blockly](docs/de/blockly.md) finden.
|
|
@@ -28,6 +30,30 @@ Executes JavaScript, TypeScript Scripts.
|
|
|
28
30
|
-->
|
|
29
31
|
|
|
30
32
|
## Changelog
|
|
33
|
+
### 10.4.0 (2026-10-08)
|
|
34
|
+
* (@GermanBluefox) 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
|
|
35
|
+
* (@GermanBluefox) Only 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
|
|
36
|
+
* (@GermanBluefox) The `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
|
|
37
|
+
* (@GermanBluefox) The 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)
|
|
38
|
+
* (@GermanBluefox) Stopping 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)
|
|
39
|
+
* (@GermanBluefox) The 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
|
|
40
|
+
* (@GermanBluefox) An AI answer without content now says why (stop reason, token counts) instead of leaving an empty chat bubble, and every failed request is logged
|
|
41
|
+
* (@GermanBluefox) An answer cut off at the output limit is marked as incomplete
|
|
42
|
+
* (@GermanBluefox) Sorted the scripts in the `@` list of the AI chat by their path
|
|
43
|
+
* (@GermanBluefox) The AI chat can be maximized to the whole editor area (#2389)
|
|
44
|
+
* (@GermanBluefox) The AI chat shows a spinner for the whole request, not only until the first tool call
|
|
45
|
+
* (@GermanBluefox) Fixed an accepted AI suggestion not reaching the visible editor
|
|
46
|
+
* (@GermanBluefox) Fixed the splitters jumping back to their previous width while being dragged
|
|
47
|
+
* (@GermanBluefox) Blockly: fixed a parameter of a "JavaScript function" with its default name making the script unsavable
|
|
48
|
+
* (@GermanBluefox) Added 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)
|
|
49
|
+
* (@GermanBluefox) Added a "Script history" tab with the used storage per script and buttons to delete single, orphaned or all histories
|
|
50
|
+
* (@GermanBluefox) Moved the credentials table to its own tab
|
|
51
|
+
* (@GermanBluefox) Mirror: a changed file no longer resets `enabled` and `engine` of the script (#2396)
|
|
52
|
+
|
|
53
|
+
### 10.3.0 (2026-09-20)
|
|
54
|
+
* (@GermanBluefox) 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
|
|
55
|
+
* (@GermanBluefox) Added 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)
|
|
56
|
+
|
|
31
57
|
### 10.2.5 (2026-09-17)
|
|
32
58
|
* (@GermanBluefox) Added the functions help dialog in editor
|
|
33
59
|
|
|
@@ -48,29 +74,6 @@ Executes JavaScript, TypeScript Scripts.
|
|
|
48
74
|
* (@GermanBluefox) The inline completion took the model chosen in the AI chat but picked the provider itself, so a model of one provider could be requested with the credentials and at the endpoint of another. Model and provider are now remembered and used together
|
|
49
75
|
* (@GermanBluefox) When two providers offer a model of the same name - a proxy and the vendor behind it, for instance - which of them served it was decided by whichever answered first, and could change from one reload to the next. The provider configured first wins now, so the direct route is preferred over a proxy
|
|
50
76
|
|
|
51
|
-
### 10.1.4 (2026-09-03)
|
|
52
|
-
* (@GermanBluefox) Rules: the text of an action can round the trigger value with `%.1s` - any number of digits after the decimal point, also `%.2old` for the old value - formatted with the decimal separator of the system, so `Kühlschrank zu warm (%.1s°C)` gives `29,4°C` where `%s` gave `29.400000000000002°C`
|
|
53
|
-
* (@GermanBluefox) Corrected the function block in blockly
|
|
54
|
-
* (@GermanBluefox) A custom OpenAI-compatible AI endpoint answered "Invalid API key" in the inline completion and while loading the model list, although the test button in the settings said "ok": both asked the adapter for the provider `openai`, and the adapter picks the key by that name, so they used the "OpenAI API key" instead of the "Custom API key". The custom endpoint is now addressed as what it is, everywhere (#2369)
|
|
55
|
-
* (@GermanBluefox) A configured "Custom API Base URL" also redirected every request meant for OpenAI itself to that address - with the OpenAI key attached and no way to switch it off. The base URL now belongs to the custom endpoint alone, so both can be used side by side. If the key of your custom endpoint is in the "OpenAI API key" field, move it to the "Custom API key" field; the adapter writes a warning in the log if it finds such a setup (#2369)
|
|
56
|
-
* (@GermanBluefox) A folded "or"/"else" section of a rule still occupied the 64px every section reserves as a drop target, and showed the top 64px of the very cards it was supposed to hide - clipped, and out of reach of the scrollbar. Being the last thing in the rule, that looked like a rule that could not be scrolled to its end
|
|
57
|
-
* (@GermanBluefox) The 1px line between the script tabs and the toolbar stopped 10px short of the left edge and 40px short of the right one: the tab row carried a margin and a `calc(100% - 50px)` width to leave room for the "close all but current" button. Both are padding on the tab strip now, so the line reaches the edges of the pane
|
|
58
|
-
* (@GermanBluefox) Blockly was grey in every dark theme - workspace, toolbox and flyout were hard-coded colours, which left a grey block sitting in the middle of, for instance, the navy "modernDark" admin. They follow the colours of the active ioBroker theme now, in light themes as well. The blocks themselves keep the colour of their category
|
|
59
|
-
|
|
60
|
-
### 10.1.3 (2026-08-30)
|
|
61
|
-
* (@GermanBluefox) The plain text export named its files after the script ID instead of the script name, so every dot of a name came out as an underscore - `HK-Balkontuer_v0.1` was exported as `HK-Balkontuer_v0_1.js`, and importing it back renamed the script to that. The files are now named after the script (#2364)
|
|
62
|
-
* (@GermanBluefox) Importing a plain text export treated a dot inside a file name as a folder level, so `PW-TV-Control_v0.6.js` created a folder `PW-TV-Control_v0` containing a script named `6`. Only the directories of the ZIP are folders now (#2364)
|
|
63
|
-
* (@GermanBluefox) The folder icons in the script tree were drawn at less than half the size of the script icons next to them: they spaced themselves with a padding, and since `CssBaseline` sets `box-sizing: border-box` that padding was subtracted from their 20px instead of being added to them. They use a margin now, like the script icons always did (#2360)
|
|
64
|
-
* (@GermanBluefox) The log below the editor could not be resized while a script was open: the editor area guessed its height from the height the tabs and the toolbar were expected to have, hung over the bottom edge of its pane and covered the 8px splitter with the horizontal scrollbar of the editor, which swallowed the mouse click. The three parts now share the height as a flex column (#2351)
|
|
65
|
-
* (@GermanBluefox) The script list cut off long names, although there was still free space next to them: the space for the buttons at the end of a row was a fixed 185px, which is more than the three buttons occupy, and it did not account for the icon column
|
|
66
|
-
* (@GermanBluefox) Fixed the Blockly comment block: the text was written in white on the yellow block and could not be read, the editor opened somewhere else on the page instead of over the block, and on a smartphone or tablet it did not open at all and left the whole workspace unusable until the page was reloaded (#2348)
|
|
67
|
-
* (@GermanBluefox) Fixed the script mirror for folder names containing regular expression characters: a folder called e.g. `Lampen (Flur` aborted the synchronization with a `SyntaxError`, a folder called e.g. `[ab]` silently synchronized the scripts of another folder (#2239)
|
|
68
|
-
* (@GermanBluefox) The Blockly block "http (POST)" got a "content type" selector, so an API that insists on `Content-Type: application/json` no longer needs an `exec` block. "automatic" is the default and behaves exactly as before, "own" allows any other type (#1983)
|
|
69
|
-
* (@GermanBluefox) `getSchedules()` returned the schedules of the time wizard of **all** scripts, even without the argument `true`. Now only the schedules of the own script are returned (#2164)
|
|
70
|
-
* (@GermanBluefox) `clearSchedule()` did not accept the objects that `getSchedules()` returns for schedules of the time wizard, so such a schedule stayed in the script and in the schedule counter (#2164)
|
|
71
|
-
* (@GermanBluefox) `clearSchedule()` can now clear the CRON jobs of other scripts too, as documented for `getSchedules(true)` (#2164)
|
|
72
|
-
* (@GermanBluefox) `getSchedules()` no longer lists the already canceled schedules of the own script in an `onStop` callback (#2164)
|
|
73
|
-
|
|
74
77
|
## License
|
|
75
78
|
The MIT License (MIT)
|
|
76
79
|
|
|
@@ -0,0 +1,27 @@
|
|
|
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,4 +1,4 @@
|
|
|
1
|
-
import{o as e}from"./rolldown-runtime-C0FnF6B9.js";import{
|
|
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
2
|
Copy EXACTLY this syntax. Do NOT change the callback signature.
|
|
3
3
|
IMPORTANT: Write all code at top level. NEVER use console.log (use log instead). NEVER define functions with the function keyword.
|
|
4
4
|
|
|
@@ -70,7 +70,7 @@ wait(ms) | toInt(val) | toFloat(val) | toBoolean(val)
|
|
|
70
70
|
messageTo(target, data) | onMessage(name, cb) | onLog(severity, cb)
|
|
71
71
|
runScript(name) | startScript(name) | stopScript(name) | isScriptActive(name)
|
|
72
72
|
|
|
73
|
-
Write comments in ${e}. Put code in a \`\`\`javascript code block.`}function
|
|
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
74
|
Use EXACT state IDs from the plan. Write text/comments in ${e}.
|
|
75
75
|
|
|
76
76
|
IMPORTANT RULES:
|
|
@@ -213,4 +213,4 @@ IMPORTANT RULES:
|
|
|
213
213
|
</statement>
|
|
214
214
|
</block>
|
|
215
215
|
|
|
216
|
-
Write comments in ${e}. Put blocks in a \`\`\`xml code block.`}function
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
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};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{m as e}from"./AiChatService-DP1EmVk2.js";var t=800,n=`You are a code completion engine for ioBroker JavaScript adapter scripts.
|
|
2
2
|
Complete the code at the cursor position marked with <CURSOR>.
|
|
3
3
|
Return ONLY the completion text, no explanation, no markdown fences, no comments about what you did.
|
|
4
4
|
If you cannot complete, return an empty string.
|