iobroker.assistant 0.1.6 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +61 -4
  2. package/admin/custom/.vite/manifest.json +122 -77
  3. package/admin/custom/assets/Components-7BDDNrGP.js +1 -0
  4. package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomAssistant__mf_owner__1-DcAGnE2z.js +1 -0
  5. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__198531368674860__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-CzBMxGFr.js +1 -0
  6. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__198531368674860__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-1XsLCK2M.js +1 -0
  7. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__198531368674860__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-CMv8bcyA.js +1217 -0
  8. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__198531368674860__loadShare__shared-3mzaJWDF.js +2 -0
  9. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__198531368674860__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-DS8oaQQt.js +122 -0
  10. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__198531368674860__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-B_v57Qfr.js +1 -0
  11. package/admin/custom/assets/dist-DiU1y0R9.js +1 -0
  12. package/admin/custom/assets/helpers-Dot7vgQQ.js +1 -0
  13. package/admin/custom/assets/hostInit-MshDicd1.js +1 -0
  14. package/admin/custom/assets/iconLibraryData-B5fiyl1C.js +1 -0
  15. package/admin/custom/assets/index-P2Xu9kJm.js +1 -0
  16. package/admin/custom/assets/lib-DjwHKtRi.js +3 -0
  17. package/admin/custom/assets/{mf-entry-bootstrap-0-87f15505.js → mf-entry-bootstrap-0-7c1ddf47.js} +14 -2
  18. package/admin/custom/assets/pendingShares-CaJDCKLB.js +2 -0
  19. package/admin/custom/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
  20. package/admin/custom/assets/utils-towTPKqG.js +4 -0
  21. package/admin/custom/assets/vite-preload-helper-BbbETgeG.js +1 -0
  22. package/admin/custom/customComponents.js +2 -2
  23. package/admin/custom/i18n/de.json +64 -57
  24. package/admin/custom/i18n/en.json +8 -1
  25. package/admin/custom/i18n/es.json +64 -57
  26. package/admin/custom/i18n/fr.json +64 -57
  27. package/admin/custom/i18n/it.json +64 -57
  28. package/admin/custom/i18n/nl.json +64 -57
  29. package/admin/custom/i18n/pl.json +64 -57
  30. package/admin/custom/i18n/pt.json +64 -57
  31. package/admin/custom/i18n/ru.json +64 -57
  32. package/admin/custom/i18n/uk.json +64 -57
  33. package/admin/custom/i18n/zh-cn.json +64 -57
  34. package/admin/custom/index.html +2 -2
  35. package/admin/custom/mf-manifest.json +1 -1
  36. package/admin/custom/mf-stats.json +1 -1
  37. package/admin/i18n/de.json +59 -3
  38. package/admin/i18n/en.json +59 -3
  39. package/admin/i18n/es.json +59 -3
  40. package/admin/i18n/fr.json +59 -3
  41. package/admin/i18n/it.json +59 -3
  42. package/admin/i18n/nl.json +59 -3
  43. package/admin/i18n/pl.json +59 -3
  44. package/admin/i18n/pt.json +59 -3
  45. package/admin/i18n/ru.json +59 -3
  46. package/admin/i18n/uk.json +59 -3
  47. package/admin/i18n/zh-cn.json +59 -3
  48. package/admin/jsonConfig.json +589 -75
  49. package/build/lib/ask.js +130 -0
  50. package/build/lib/ask.js.map +1 -0
  51. package/build/lib/llm.js +135 -13
  52. package/build/lib/llm.js.map +1 -1
  53. package/build/lib/nlu.js +74 -1
  54. package/build/lib/nlu.js.map +1 -1
  55. package/build/lib/notifications.js +112 -0
  56. package/build/lib/notifications.js.map +1 -0
  57. package/build/lib/presence.js +188 -0
  58. package/build/lib/presence.js.map +1 -0
  59. package/build/lib/routines.js +115 -0
  60. package/build/lib/routines.js.map +1 -0
  61. package/build/lib/targets.js +96 -0
  62. package/build/lib/targets.js.map +1 -0
  63. package/build/lib/triggers.js +632 -0
  64. package/build/lib/triggers.js.map +1 -0
  65. package/build/lib/voice/aws.js +9 -1
  66. package/build/lib/voice/aws.js.map +1 -1
  67. package/build/lib/voice/azure.js +9 -2
  68. package/build/lib/voice/azure.js.map +1 -1
  69. package/build/lib/voice/engines.js +82 -0
  70. package/build/lib/voice/engines.js.map +1 -1
  71. package/build/lib/voice/esphome.js +732 -0
  72. package/build/lib/voice/esphome.js.map +1 -0
  73. package/build/lib/voice/esphomeEntities.js +303 -0
  74. package/build/lib/voice/esphomeEntities.js.map +1 -0
  75. package/build/lib/voice/esphomeProto.js +181 -0
  76. package/build/lib/voice/esphomeProto.js.map +1 -0
  77. package/build/lib/voice/fallback.js +85 -0
  78. package/build/lib/voice/fallback.js.map +1 -0
  79. package/build/lib/voice/mediaServer.js +151 -0
  80. package/build/lib/voice/mediaServer.js.map +1 -0
  81. package/build/lib/voice/protocol.js.map +1 -1
  82. package/build/lib/voice/tone.js +32 -0
  83. package/build/lib/voice/tone.js.map +1 -0
  84. package/build/lib/voice/tts.js.map +1 -1
  85. package/build/lib/voice/ttsCache.js +274 -0
  86. package/build/lib/voice/ttsCache.js.map +1 -0
  87. package/build/lib/voice/vad.js +173 -0
  88. package/build/lib/voice/vad.js.map +1 -0
  89. package/build/lib/voice/voiceServer.js +13 -0
  90. package/build/lib/voice/voiceServer.js.map +1 -1
  91. package/build/main.js +1721 -67
  92. package/build/main.js.map +1 -1
  93. package/io-package.json +241 -3
  94. package/package.json +13 -12
  95. package/admin/custom/assets/Components-xWdtqvTH.js +0 -1
  96. package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomAssistant__mf_owner__1-dybYZgsu.js +0 -1
  97. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__1__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-BnSUsPHa.js +0 -1
  98. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__1__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-DlSVT49A.js +0 -1
  99. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-Cfsgderv.js +0 -1243
  100. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__1__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-ByJf4zv_.js +0 -1494
  101. package/admin/custom/assets/hostInit-CZawMH9B.js +0 -1
  102. package/admin/custom/assets/index-JB7g1jgx.js +0 -1
  103. package/admin/custom/assets/lib-bB-LHRhZ.js +0 -3
  104. package/admin/custom/assets/rolldown-runtime-C0FnF6B9.js +0 -1
  105. package/admin/custom/assets/virtualExposes-brKKZvi0.js +0 -1
  106. package/admin/custom/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__ConfigCustomAssistant__customComponents_js-CRhwj12f.js +0 -1
  107. package/admin/custom/assets/virtual_mf-exposes___mfe_internal__ConfigCustomAssistant__customComponents_js-C5XHUc1J.js +0 -2
  108. package/admin/custom/assets/vite-preload-helper-B7qeedMF.js +0 -1
@@ -9,7 +9,12 @@
9
9
  "_header": {
10
10
  "type": "header",
11
11
  "size": 2,
12
- "text": "LLM assistant"
12
+ "text": "LLM assistant",
13
+ "xs": 12,
14
+ "sm": 12,
15
+ "md": 12,
16
+ "lg": 12,
17
+ "xl": 12
13
18
  },
14
19
  "provider": {
15
20
  "newLine": true,
@@ -20,38 +25,52 @@
20
25
  { "label": "Anthropic (Claude)", "value": "anthropic" },
21
26
  { "label": "Google Gemini", "value": "gemini" },
22
27
  { "label": "DeepSeek", "value": "deepseek" },
23
- { "label": "OpenAI-compatible (custom)", "value": "custom" }
28
+ { "label": "OpenAI-compatible (custom)", "value": "custom" },
29
+ { "label": "None (local only)", "value": "none" }
24
30
  ],
25
31
  "default": "openai",
32
+ "xs": 12,
26
33
  "sm": 12,
27
- "md": 4
34
+ "md": 4,
35
+ "lg": 4,
36
+ "xl": 4
28
37
  },
29
38
  "credentialType": {
30
39
  "newLine": true,
31
40
  "type": "select",
32
41
  "label": "Credential mode",
42
+ "hidden": "data.provider === 'none'",
33
43
  "options": [
34
44
  { "label": "Store key in adapter", "value": "manual" },
35
45
  { "label": "Central credential store", "value": "manager" }
36
46
  ],
37
47
  "default": "manual",
48
+ "xs": 12,
38
49
  "sm": 12,
39
- "md": 4
50
+ "md": 4,
51
+ "lg": 4,
52
+ "xl": 4
40
53
  },
41
54
  "apiKey": {
42
55
  "type": "password",
43
56
  "label": "API key",
44
- "hidden": "data.credentialType === 'manager'",
57
+ "hidden": "data.provider === 'none' || data.credentialType === 'manager'",
58
+ "xs": 12,
45
59
  "sm": 12,
46
- "md": 4
60
+ "md": 4,
61
+ "lg": 4,
62
+ "xl": 4
47
63
  },
48
64
  "credentialIdApiKey": {
49
65
  "type": "credential",
50
66
  "credentialType": "ai",
51
67
  "label": "API-key credential",
52
- "hidden": "data.credentialType !== 'manager'",
68
+ "hidden": "data.provider === 'none' || data.credentialType !== 'manager'",
69
+ "xs": 12,
53
70
  "sm": 12,
54
- "md": 4
71
+ "md": 4,
72
+ "lg": 4,
73
+ "xl": 4
55
74
  },
56
75
  "model": {
57
76
  "newLine": true,
@@ -62,17 +81,24 @@
62
81
  "freeSolo": true,
63
82
  "label": "Model",
64
83
  "help": "Loaded from the provider (instance must run); you can also type a model id.",
84
+ "hidden": "data.provider === 'none'",
65
85
  "default": "gpt-4o-mini",
86
+ "xs": 12,
66
87
  "sm": 12,
67
- "md": 4
88
+ "md": 4,
89
+ "lg": 4,
90
+ "xl": 4
68
91
  },
69
92
  "baseUrl": {
70
93
  "type": "text",
71
94
  "label": "Base URL (optional)",
72
95
  "help": "Override the endpoint, e.g. https://api.groq.com/openai/v1 for Groq. Leave empty for the provider default.",
73
96
  "hidden": "data.provider !== 'custom'",
97
+ "xs": 12,
74
98
  "sm": 12,
75
- "md": 8
99
+ "md": 8,
100
+ "lg": 8,
101
+ "xl": 8
76
102
  },
77
103
  "_testConnection": {
78
104
  "newLine": true,
@@ -81,56 +107,116 @@
81
107
  "command": "testApiConnection",
82
108
  "jsonData": "{\"provider\":\"${data.provider}\",\"apiKey\":\"${data.apiKey}\",\"credentialType\":\"${data.credentialType}\",\"model\":\"${data.model}\",\"baseUrl\":\"${data.baseUrl}\",\"credentialId\":\"${data.credentialIdApiKey}\"}",
83
109
  "variant": "outlined",
84
- "disabled": "data.credentialType === 'manager' ? !data.credentialIdApiKey : !data.apiKey",
110
+ "hidden": "data.provider === 'none'",
111
+ "disabled": "data.provider !== 'custom' && (data.credentialType === 'manager' ? !data.credentialIdApiKey : !data.apiKey)",
112
+ "xs": 12,
85
113
  "sm": 12,
86
- "md": 4
114
+ "md": 4,
115
+ "lg": 4,
116
+ "xl": 4
117
+ },
118
+ "_noneInfo": {
119
+ "newLine": true,
120
+ "type": "staticText",
121
+ "text": "Without an LLM provider only the local tiers answer: the rule-based commands, routines, timers and alarms, and the local model if enabled. Anything else gets a short \"I can't do that\" reply.",
122
+ "hidden": "data.provider !== 'none'",
123
+ "xs": 12,
124
+ "sm": 12,
125
+ "md": 12,
126
+ "lg": 12,
127
+ "xl": 12
87
128
  },
88
129
  "maxTokens": {
89
130
  "newLine": true,
90
131
  "type": "number",
91
132
  "label": "Max tokens",
133
+ "hidden": "data.provider === 'none'",
92
134
  "default": 1024,
93
135
  "min": 64,
94
136
  "max": 8192,
137
+ "xs": 12,
95
138
  "sm": 6,
96
- "md": 2
139
+ "md": 2,
140
+ "lg": 2,
141
+ "xl": 2
97
142
  },
98
143
  "useLocalNlu": {
99
144
  "type": "checkbox",
100
145
  "label": "Answer simple commands locally (fast, offline)",
101
146
  "help": "Try the built-in rule-based intent matching for turn on/off, dimming and status before calling the LLM.",
102
147
  "default": true,
148
+ "xs": 12,
149
+ "sm": 6,
150
+ "md": 4,
151
+ "lg": 4,
152
+ "xl": 4
153
+ },
154
+ "confirmWithTone": {
155
+ "type": "checkbox",
156
+ "label": "Confirm switch commands with a beep",
157
+ "help": "A successful switch command is confirmed by a short tone on the satellite instead of a spoken sentence - instant, where speaking costs a text-to-speech call. Questions, errors and the text channels are unaffected.",
158
+ "default": false,
159
+ "hidden": "!data.useLocalNlu",
160
+ "xs": 12,
103
161
  "sm": 6,
104
- "md": 4
162
+ "md": 4,
163
+ "lg": 4,
164
+ "xl": 4
105
165
  },
106
166
  "nluAliases": {
107
167
  "type": "table",
108
168
  "label": "Synonym dictionary",
109
169
  "help": "Rewrite spoken or typed variants to your device/room names before local matching, e.g. \"TV\" to \"Fernseher\". Leave the language empty to apply to all languages. Also used for the text channels.",
110
170
  "hidden": "!data.useLocalNlu",
171
+ "xs": 12,
111
172
  "sm": 12,
112
173
  "md": 12,
174
+ "lg": 12,
175
+ "xl": 12,
113
176
  "items": [
114
177
  { "type": "text", "attr": "from", "title": "Said or typed", "width": "40%" },
115
178
  { "type": "text", "attr": "to", "title": "Canonical term", "width": "40%" },
116
179
  { "type": "text", "attr": "language", "title": "Language (empty = all)", "width": "20%" }
117
180
  ]
118
181
  },
182
+ "routines": {
183
+ "newLine": true,
184
+ "type": "table",
185
+ "label": "Routines",
186
+ "help": "A phrase that runs a list of actions: \"Gute Nacht\" switches off five things and answers once. Phrases: several separated by commas (matched anywhere in the sentence, upper/lower case and umlauts do not matter). Actions as JSON, same shape as a trigger: [{\"setState\":{\"id\":\"hm-rpc.0.ABC.1.STATE\",\"value\":false}},{\"say\":\"Schlaf gut\",\"room\":\"Schlafzimmer\"}]. Reply: what the assistant answers (leave empty to stay silent). Matched before the offline rule engine and before the LLM, so a routine is never reinterpreted.",
187
+ "xs": 12,
188
+ "sm": 12,
189
+ "md": 12,
190
+ "lg": 12,
191
+ "xl": 12,
192
+ "items": [
193
+ { "type": "text", "attr": "name", "title": "Name", "width": "15%" },
194
+ { "type": "text", "attr": "phrases", "title": "Phrases (comma separated)", "width": "30%" },
195
+ { "type": "text", "attr": "actions", "title": "Actions (JSON)", "width": "35%" },
196
+ { "type": "text", "attr": "reply", "title": "Reply", "width": "20%" }
197
+ ]
198
+ },
119
199
  "useConversationContext": {
120
200
  "type": "checkbox",
121
201
  "label": "Remember the conversation (follow-up questions)",
122
202
  "help": "Keep the last few turns per source (chat, telegram, satellite) for a few minutes so follow-ups like 'and the kitchen too' work. In-memory only.",
123
203
  "default": true,
204
+ "xs": 12,
124
205
  "sm": 6,
125
- "md": 4
206
+ "md": 4,
207
+ "lg": 4,
208
+ "xl": 4
126
209
  },
127
210
  "useLongTermMemory": {
128
211
  "type": "checkbox",
129
212
  "label": "Long-term memory (remember facts across sessions)",
130
213
  "help": "Lets the assistant durably remember facts you tell it (names, preferences, where things are) and use them in later conversations. Stored in the memory.* states; the LLM gets remember/forget tools.",
131
214
  "default": true,
215
+ "xs": 12,
132
216
  "sm": 6,
133
- "md": 4
217
+ "md": 4,
218
+ "lg": 4,
219
+ "xl": 4
134
220
  },
135
221
  "weatherInstance": {
136
222
  "newLine": true,
@@ -138,8 +224,28 @@
138
224
  "command": "getWeatherInstances",
139
225
  "label": "Weather source",
140
226
  "help": "Pick an installed weather adapter to answer weather questions from (Open-Meteo, Weather Underground, OpenWeatherMap are fully understood; others are read best-effort). Start that adapter once so its data/locations appear here.",
227
+ "xs": 12,
141
228
  "sm": 12,
142
- "md": 6
229
+ "md": 6,
230
+ "lg": 6,
231
+ "xl": 6
232
+ },
233
+ "presence": {
234
+ "newLine": true,
235
+ "type": "table",
236
+ "label": "Presence",
237
+ "help": "Which states tell the assistant who is at home - one row per person. Any state works: the residents adapter, a phone ping like ping.0.phone-denis.alive, a router client state or your own flag. Kind: empty or person, guest, pet (a pet never makes the house occupied). Home value: leave empty for the usual forms (true, 1, \"home\", \"anwesend\"), or enter the exact value that means at home. Used to tell the LLM who is around, to hold back announcements to an empty house (notify with onlyWhenHome) and as a trigger source via presence.anyoneHome.",
238
+ "xs": 12,
239
+ "sm": 12,
240
+ "md": 12,
241
+ "lg": 12,
242
+ "xl": 12,
243
+ "items": [
244
+ { "type": "text", "attr": "id", "title": "State id", "width": "45%" },
245
+ { "type": "text", "attr": "name", "title": "Name", "width": "25%" },
246
+ { "type": "text", "attr": "kind", "title": "Kind (person/guest/pet)", "width": "15%" },
247
+ { "type": "text", "attr": "homeValue", "title": "Home value (empty = auto)", "width": "15%" }
248
+ ]
143
249
  },
144
250
  "timerAnnounce": {
145
251
  "newLine": true,
@@ -147,23 +253,44 @@
147
253
  "label": "Announce when a timer expires",
148
254
  "help": "Speak an announcement on the satellite a countdown timer was set from (or on all satellites) when it runs out. Timers are always mirrored into the timers.* states for scripts and visualization.",
149
255
  "default": true,
256
+ "xs": 12,
150
257
  "sm": 6,
151
- "md": 4
258
+ "md": 4,
259
+ "lg": 4,
260
+ "xl": 4
152
261
  },
153
262
  "alarmAnnounce": {
154
263
  "type": "checkbox",
155
264
  "label": "Announce when an alarm goes off",
156
265
  "help": "Speak an announcement when an alarm at a fixed clock time fires. Alarms are always mirrored into the alarms.* states for scripts and visualization.",
157
266
  "default": true,
267
+ "xs": 12,
158
268
  "sm": 6,
159
- "md": 4
269
+ "md": 4,
270
+ "lg": 4,
271
+ "xl": 4
272
+ },
273
+ "notifyRephrase": {
274
+ "newLine": true,
275
+ "type": "checkbox",
276
+ "label": "Reword system notifications",
277
+ "help": "Spoken system notifications (notify.text / the ioBroker notification manager) are reworded by the LLM into one natural sentence first - their raw texts are written for a log viewer. Costs one small LLM call per notification; the original text is spoken if it fails. Urgent ones (notify.alert) are announced even when Do-Not-Disturb is on.",
278
+ "default": true,
279
+ "xs": 12,
280
+ "sm": 6,
281
+ "md": 4,
282
+ "lg": 4,
283
+ "xl": 4
160
284
  },
161
285
  "_soundsHint": {
162
286
  "newLine": true,
163
287
  "type": "staticText",
164
288
  "text": "Two default sounds (timer.wav, alarm.wav) are preinstalled — pick one below or upload your own mp3/wav. The selected sound plays before the spoken announcement. Needs ffmpeg on the host and at least one satellite.",
289
+ "xs": 12,
165
290
  "sm": 12,
166
- "md": 12
291
+ "md": 12,
292
+ "lg": 12,
293
+ "xl": 12
167
294
  },
168
295
  "ringSeconds": {
169
296
  "newLine": true,
@@ -173,8 +300,11 @@
173
300
  "default": 60,
174
301
  "min": 0,
175
302
  "max": 600,
303
+ "xs": 12,
176
304
  "sm": 6,
177
- "md": 3
305
+ "md": 3,
306
+ "lg": 3,
307
+ "xl": 3
178
308
  },
179
309
  "timerSound": {
180
310
  "newLine": true,
@@ -187,8 +317,11 @@
187
317
  "refresh": true,
188
318
  "maxSize": 5242880,
189
319
  "label": "Timer sound (mp3/wav, optional)",
320
+ "xs": 12,
190
321
  "sm": 12,
191
- "md": 5
322
+ "md": 5,
323
+ "lg": 5,
324
+ "xl": 5
192
325
  },
193
326
  "_playTimerSound": {
194
327
  "type": "sendTo",
@@ -197,8 +330,11 @@
197
330
  "variant": "outlined",
198
331
  "jsonData": "{\"name\":\"${data.timerSound}\"}",
199
332
  "disabled": "!data.timerSound",
333
+ "xs": 12,
200
334
  "sm": 6,
201
- "md": 2
335
+ "md": 2,
336
+ "lg": 2,
337
+ "xl": 2
202
338
  },
203
339
  "alarmSound": {
204
340
  "newLine": true,
@@ -211,8 +347,11 @@
211
347
  "refresh": true,
212
348
  "maxSize": 5242880,
213
349
  "label": "Alarm sound (mp3/wav, optional)",
350
+ "xs": 12,
214
351
  "sm": 12,
215
- "md": 5
352
+ "md": 5,
353
+ "lg": 5,
354
+ "xl": 5
216
355
  },
217
356
  "_playAlarmSound": {
218
357
  "type": "sendTo",
@@ -221,8 +360,11 @@
221
360
  "variant": "outlined",
222
361
  "jsonData": "{\"name\":\"${data.alarmSound}\"}",
223
362
  "disabled": "!data.alarmSound",
363
+ "xs": 12,
224
364
  "sm": 6,
225
- "md": 2
365
+ "md": 2,
366
+ "lg": 2,
367
+ "xl": 2
226
368
  },
227
369
  "useLocalLlm": {
228
370
  "newLine": true,
@@ -230,16 +372,22 @@
230
372
  "label": "Use a local LLM before the cloud (installed on demand)",
231
373
  "help": "Runs a small local model (node-llama-cpp) for general questions; escalates to the cloud LLM when it needs live device data. Install it with the button below.",
232
374
  "default": false,
375
+ "xs": 12,
233
376
  "sm": 12,
234
- "md": 6
377
+ "md": 6,
378
+ "lg": 6,
379
+ "xl": 6
235
380
  },
236
381
  "localLlmModelUrl": {
237
382
  "type": "text",
238
383
  "label": "Local model URL (GGUF, optional)",
239
384
  "help": "Direct URL of a GGUF model. Leave empty for the default (Qwen2.5-1.5B-Instruct). Small models recommended on Raspberry Pi / arm64.",
240
385
  "hidden": "!data.useLocalLlm",
386
+ "xs": 12,
241
387
  "sm": 12,
242
- "md": 6
388
+ "md": 6,
389
+ "lg": 6,
390
+ "xl": 6
243
391
  },
244
392
  "_installLocalLlm": {
245
393
  "newLine": true,
@@ -251,8 +399,11 @@
251
399
  "showProcess": true,
252
400
  "timeout": 600000,
253
401
  "help": "Downloads the engine and model (several hundred MB). Progress is shown below.",
402
+ "xs": 12,
254
403
  "sm": 12,
255
- "md": 4
404
+ "md": 4,
405
+ "lg": 4,
406
+ "xl": 4
256
407
  },
257
408
  "_localLlmProgress": {
258
409
  "newLine": true,
@@ -263,14 +414,22 @@
263
414
  "bundlerType": "module",
264
415
  "guiApi": 2,
265
416
  "hidden": "!data.useLocalLlm",
417
+ "xs": 12,
266
418
  "sm": 12,
267
- "md": 8
419
+ "md": 8,
420
+ "lg": 8,
421
+ "xl": 8
268
422
  },
269
423
  "_accessHeader": {
270
424
  "newLine": true,
271
425
  "type": "header",
272
426
  "size": 2,
273
- "text": "Access / permissions"
427
+ "text": "Access / permissions",
428
+ "xs": 12,
429
+ "sm": 12,
430
+ "md": 12,
431
+ "lg": 12,
432
+ "xl": 12
274
433
  },
275
434
  "readObjects": {
276
435
  "newLine": true,
@@ -281,69 +440,108 @@
281
440
  { "label": "Any object (get_object/search_objects)", "value": "all" }
282
441
  ],
283
442
  "default": "devices",
443
+ "xs": 12,
284
444
  "sm": 12,
285
- "md": 4
445
+ "md": 4,
446
+ "lg": 4,
447
+ "xl": 4
286
448
  },
287
449
  "allowWriteStates": {
288
450
  "newLine": true,
289
451
  "type": "checkbox",
290
452
  "label": "Allow writing states (control devices)",
291
453
  "default": true,
454
+ "xs": 12,
292
455
  "sm": 6,
293
- "md": 3
456
+ "md": 3,
457
+ "lg": 3,
458
+ "xl": 3
459
+ },
460
+ "verifyWrites": {
461
+ "type": "checkbox",
462
+ "label": "Verify device feedback",
463
+ "help": "After a switch command, wait up to 2 seconds for the device to acknowledge the new value (ack:true) and report \"did not respond\" if it never does. Leave this off for devices that never acknowledge (MQTT, scripts, 0_userdata) - every command would look failed.",
464
+ "default": false,
465
+ "hidden": "!data.allowWriteStates",
466
+ "xs": 12,
467
+ "sm": 6,
468
+ "md": 4,
469
+ "lg": 4,
470
+ "xl": 4
294
471
  },
295
472
  "allowHistory": {
296
473
  "type": "checkbox",
297
474
  "label": "Allow reading history",
298
475
  "default": true,
476
+ "xs": 12,
299
477
  "sm": 6,
300
- "md": 3
478
+ "md": 3,
479
+ "lg": 3,
480
+ "xl": 3
301
481
  },
302
482
  "allowReadLogs": {
303
483
  "newLine": true,
304
484
  "type": "checkbox",
305
485
  "label": "Allow reading logs",
306
486
  "default": false,
487
+ "xs": 12,
307
488
  "sm": 6,
308
- "md": 3
489
+ "md": 3,
490
+ "lg": 3,
491
+ "xl": 3
309
492
  },
310
493
  "allowWriteLogs": {
311
494
  "type": "checkbox",
312
495
  "label": "Allow writing to the log",
313
496
  "default": false,
497
+ "xs": 12,
314
498
  "sm": 6,
315
- "md": 3
499
+ "md": 3,
500
+ "lg": 3,
501
+ "xl": 3
316
502
  },
317
503
  "allowFiles": {
318
504
  "newLine": true,
319
505
  "type": "checkbox",
320
506
  "label": "Allow reading files",
321
507
  "default": false,
508
+ "xs": 12,
322
509
  "sm": 6,
323
- "md": 3
510
+ "md": 3,
511
+ "lg": 3,
512
+ "xl": 3
324
513
  },
325
514
  "allowSystemInfo": {
326
515
  "type": "checkbox",
327
516
  "label": "Allow system info (hosts, instances, adapters)",
328
517
  "default": true,
518
+ "xs": 12,
329
519
  "sm": 6,
330
- "md": 3
520
+ "md": 3,
521
+ "lg": 3,
522
+ "xl": 3
331
523
  },
332
524
  "allowObjectChange": {
333
525
  "newLine": true,
334
526
  "type": "checkbox",
335
527
  "label": "Allow changing objects and files (dangerous)",
336
528
  "default": false,
529
+ "xs": 12,
337
530
  "sm": 12,
338
- "md": 6
531
+ "md": 6,
532
+ "lg": 6,
533
+ "xl": 6
339
534
  },
340
535
  "systemPrompt": {
341
536
  "newLine": true,
342
537
  "type": "text",
343
538
  "label": "System prompt",
344
539
  "minRows": 4,
540
+ "xs": 12,
345
541
  "sm": 12,
346
- "md": 12
542
+ "md": 12,
543
+ "lg": 12,
544
+ "xl": 12
347
545
  }
348
546
  }
349
547
  },
@@ -358,7 +556,69 @@
358
556
  "name": "ConfigCustomAssistant/Components/DeviceAclComponent",
359
557
  "guiApi": 2,
360
558
  "bundlerType": "module",
361
- "sm": 12
559
+ "xs": 12,
560
+ "sm": 12,
561
+ "md": 12,
562
+ "lg": 12,
563
+ "xl": 12
564
+ }
565
+ }
566
+ },
567
+ "_triggers": {
568
+ "type": "panel",
569
+ "label": "Triggers",
570
+ "items": {
571
+ "_triggersHeader": {
572
+ "type": "header",
573
+ "text": "Proactive triggers",
574
+ "size": 2,
575
+ "xs": 12,
576
+ "sm": 12,
577
+ "md": 12,
578
+ "lg": 12,
579
+ "xl": 12
580
+ },
581
+ "_triggersHint": {
582
+ "type": "staticText",
583
+ "text": "A trigger watches states or the clock and then speaks, writes a state, or asks you a question and acts on your answer. Switch single triggers off at runtime with triggers.items.<id>.enabled, test one with its fire button, and all of them with triggers.enabled.",
584
+ "xs": 12,
585
+ "sm": 12,
586
+ "md": 12,
587
+ "lg": 12,
588
+ "xl": 12
589
+ },
590
+ "triggers": {
591
+ "type": "table",
592
+ "label": "Triggers",
593
+ "help": "Condition as JSON: {\"state\":\"javascript.0.window\",\"value\":true} or {\"time\":\"23:00\",\"days\":[1,2,3,4,5]}; add \"also\"/\"unless\" for extra or blocking conditions, or use a list for alternatives. Say = announcement, Ask = question (needs response rules, JSON: [{\"match\":\"agreement\",\"say\":\"Okay\",\"setState\":{\"id\":\"...\",\"value\":false}}]). Extra actions as JSON: [{\"setState\":{\"id\":\"...\",\"value\":false}}]. Delay waits before acting (90s/30m/5h), cooldown is the minimum gap between two firings in seconds (default 3600).",
594
+ "xs": 12,
595
+ "sm": 12,
596
+ "md": 12,
597
+ "lg": 12,
598
+ "xl": 12,
599
+ "items": [
600
+ { "type": "text", "attr": "id", "title": "Id", "width": "8%" },
601
+ { "type": "text", "attr": "name", "title": "Name", "width": "12%" },
602
+ { "type": "text", "attr": "when", "title": "When (JSON)", "width": "20%" },
603
+ { "type": "text", "attr": "room", "title": "Room", "width": "8%" },
604
+ { "type": "text", "attr": "say", "title": "Say", "width": "14%" },
605
+ { "type": "text", "attr": "ask", "title": "Ask", "width": "14%" },
606
+ { "type": "text", "attr": "onResponse", "title": "Response rules (JSON)", "width": "10%" },
607
+ { "type": "text", "attr": "actions", "title": "Extra actions (JSON)", "width": "8%" },
608
+ { "type": "text", "attr": "delay", "title": "Delay", "width": "3%" },
609
+ { "type": "number", "attr": "cooldownSec", "title": "Cooldown (s)", "width": "3%", "min": 0 }
610
+ ]
611
+ },
612
+ "triggerRephrase": {
613
+ "type": "checkbox",
614
+ "label": "Let the LLM reword trigger texts",
615
+ "help": "Before a trigger speaks, the model rewords its text so repeated announcements do not sound canned. Costs one small LLM call per announcement; the original text is used if it fails.",
616
+ "default": false,
617
+ "xs": 12,
618
+ "sm": 12,
619
+ "md": 6,
620
+ "lg": 6,
621
+ "xl": 6
362
622
  }
363
623
  }
364
624
  },
@@ -369,7 +629,12 @@
369
629
  "_voiceHeader": {
370
630
  "type": "header",
371
631
  "size": 2,
372
- "text": "Voice satellites"
632
+ "text": "Voice satellites",
633
+ "xs": 12,
634
+ "sm": 12,
635
+ "md": 12,
636
+ "lg": 12,
637
+ "xl": 12
373
638
  },
374
639
  "voiceEnabled": {
375
640
  "newLine": true,
@@ -377,8 +642,11 @@
377
642
  "label": "Enable voice (STT/TTS for satellites)",
378
643
  "help": "Enables speech recognition/synthesis. ioBroker-native satellites reach it over the message bus — no port needed. Turn on the UDP server below only for ESP / Hannah satellites.",
379
644
  "default": false,
645
+ "xs": 12,
380
646
  "sm": 12,
381
- "md": 6
647
+ "md": 6,
648
+ "lg": 6,
649
+ "xl": 6
382
650
  },
383
651
  "udpServerEnabled": {
384
652
  "newLine": true,
@@ -387,20 +655,25 @@
387
655
  "help": "Opens a UDP port for streaming microphone satellites (Hannah-compatible / ESP). Not needed for ioBroker-native satellites.",
388
656
  "default": false,
389
657
  "hidden": "!data.voiceEnabled",
658
+ "xs": 12,
390
659
  "sm": 12,
391
- "md": 6
660
+ "md": 6,
661
+ "lg": 6,
662
+ "xl": 6
392
663
  },
393
664
  "bind": {
394
665
  "newLine": true,
395
666
  "type": "ip",
396
- "freeSolo": true,
397
667
  "label": "Bind address",
398
668
  "help": "Interface the UDP voice server listens on. 0.0.0.0 = all interfaces; pick a specific host IP so satellites on the LAN can reach it.",
399
669
  "default": "0.0.0.0",
400
670
  "listenOnAllPorts": true,
401
671
  "hidden": "!data.voiceEnabled || !data.udpServerEnabled",
672
+ "xs": 12,
402
673
  "sm": 6,
403
- "md": 3
674
+ "md": 3,
675
+ "lg": 3,
676
+ "xl": 3
404
677
  },
405
678
  "port": {
406
679
  "type": "number",
@@ -409,8 +682,11 @@
409
682
  "min": 1,
410
683
  "max": 65535,
411
684
  "hidden": "!data.voiceEnabled || !data.udpServerEnabled",
685
+ "xs": 12,
412
686
  "sm": 6,
413
- "md": 3
687
+ "md": 3,
688
+ "lg": 3,
689
+ "xl": 3
414
690
  },
415
691
  "wyomingEnabled": {
416
692
  "newLine": true,
@@ -419,8 +695,11 @@
419
695
  "help": "Home Assistant Voice PE / wyoming-satellite / ESPHome voice devices can stream to this adapter over the Wyoming protocol.",
420
696
  "default": false,
421
697
  "hidden": "!data.voiceEnabled",
698
+ "xs": 12,
422
699
  "sm": 8,
423
- "md": 5
700
+ "md": 5,
701
+ "lg": 5,
702
+ "xl": 5
424
703
  },
425
704
  "wyomingPort": {
426
705
  "type": "number",
@@ -429,8 +708,91 @@
429
708
  "min": 1,
430
709
  "max": 65535,
431
710
  "hidden": "!data.voiceEnabled || !data.wyomingEnabled",
711
+ "xs": 12,
432
712
  "sm": 4,
433
- "md": 3
713
+ "md": 3,
714
+ "lg": 3,
715
+ "xl": 3
716
+ },
717
+ "esphomeEnabled": {
718
+ "newLine": true,
719
+ "type": "checkbox",
720
+ "label": "Also drive ESPHome voice satellites",
721
+ "help": "ThirdReality Voice & Music Assistant, Home Assistant Voice PE, linux-voice-assistant. These devices listen on TCP 6053 and the adapter dials them, so no port is opened for the audio itself — only the media server below, which they fetch the spoken reply from.",
722
+ "default": false,
723
+ "hidden": "!data.voiceEnabled",
724
+ "xs": 12,
725
+ "sm": 12,
726
+ "md": 6,
727
+ "lg": 6,
728
+ "xl": 6
729
+ },
730
+ "esphomeDevices": {
731
+ "newLine": true,
732
+ "type": "table",
733
+ "label": "ESPHome satellites",
734
+ "help": "One row per device. Port empty = 6053. The room is what the assistant treats the satellite as being in. Leave the password empty unless the device really has an API password set — table values are stored unencrypted.",
735
+ "hidden": "!data.voiceEnabled || !data.esphomeEnabled",
736
+ "xs": 12,
737
+ "sm": 12,
738
+ "md": 12,
739
+ "lg": 12,
740
+ "xl": 12,
741
+ "items": [
742
+ { "type": "text", "attr": "ip", "title": "Address (IP or host name)", "width": "30%" },
743
+ {
744
+ "type": "number",
745
+ "attr": "port",
746
+ "title": "Port",
747
+ "width": "15%",
748
+ "min": 1,
749
+ "max": 65535,
750
+ "default": 6053
751
+ },
752
+ { "type": "text", "attr": "room", "title": "Room", "width": "30%" },
753
+ { "type": "text", "attr": "password", "title": "API password (usually empty)", "width": "25%" }
754
+ ]
755
+ },
756
+ "esphomeMediaPort": {
757
+ "newLine": true,
758
+ "type": "number",
759
+ "label": "Media server port",
760
+ "help": "ESPHome satellites do not get the reply over their API socket — they fetch it as a URL. This is the port that small HTTP server listens on.",
761
+ "default": 8099,
762
+ "min": 1,
763
+ "max": 65535,
764
+ "hidden": "!data.voiceEnabled || !data.esphomeEnabled",
765
+ "xs": 12,
766
+ "sm": 6,
767
+ "md": 3,
768
+ "lg": 3,
769
+ "xl": 3
770
+ },
771
+ "esphomeMediaHost": {
772
+ "type": "text",
773
+ "label": "Media server address for the devices",
774
+ "help": "Host the satellites should fetch the audio from. Empty = use the address of each device connection automatically; set it only if the devices reach this machine under a different address (NAT, Docker, VLAN).",
775
+ "default": "",
776
+ "hidden": "!data.voiceEnabled || !data.esphomeEnabled",
777
+ "xs": 12,
778
+ "sm": 6,
779
+ "md": 4,
780
+ "lg": 4,
781
+ "xl": 4
782
+ },
783
+ "esphomeSilenceMs": {
784
+ "type": "number",
785
+ "label": "End of speech after (ms of silence)",
786
+ "help": "These devices stream until the server stops them, so the adapter decides when you stopped talking. Raise it if replies cut you off, lower it if the assistant waits too long.",
787
+ "default": 900,
788
+ "min": 200,
789
+ "max": 5000,
790
+ "hidden": "!data.voiceEnabled || !data.esphomeEnabled",
791
+ "xs": 12,
792
+ "sm": 6,
793
+ "md": 3,
794
+ "lg": 3,
795
+ "xl": 3
434
796
  },
435
797
  "voiceLanguage": {
436
798
  "newLine": true,
@@ -453,8 +815,33 @@
453
815
  ],
454
816
  "default": "",
455
817
  "hidden": "!data.voiceEnabled",
818
+ "xs": 12,
456
819
  "sm": 6,
457
- "md": 3
820
+ "md": 3,
821
+ "lg": 3,
822
+ "xl": 3
823
+ },
824
+ "announceTargets": {
825
+ "newLine": true,
826
+ "type": "table",
827
+ "label": "Announcement targets (groups and people)",
828
+ "help": "Give a set of satellites a name, so an announcement, a question or a trigger can address it: a group of rooms (\"Upstairs\") or the speakers that belong to one person (\"Denis\", so \"tell Denis dinner is ready\" reaches them). Members: satellite ids, room names or device names, separated by commas. Kind: empty or group, or person. A real satellite or room of the same name always wins, so a group can never make a speaker unreachable.",
829
+ "hidden": "!data.voiceEnabled",
830
+ "xs": 12,
831
+ "sm": 12,
832
+ "md": 12,
833
+ "lg": 12,
834
+ "xl": 12,
835
+ "items": [
836
+ { "type": "text", "attr": "name", "title": "Name", "width": "25%" },
837
+ {
838
+ "type": "text",
839
+ "attr": "members",
840
+ "title": "Satellites, rooms or devices (comma separated)",
841
+ "width": "60%"
842
+ },
843
+ { "type": "text", "attr": "kind", "title": "Kind (group/person)", "width": "15%" }
844
+ ]
458
845
  },
459
846
  "sttProvider": {
460
847
  "newLine": true,
@@ -468,8 +855,11 @@
468
855
  ],
469
856
  "default": "openai",
470
857
  "hidden": "!data.voiceEnabled",
858
+ "xs": 12,
471
859
  "sm": 6,
472
- "md": 3
860
+ "md": 3,
861
+ "lg": 3,
862
+ "xl": 3
473
863
  },
474
864
  "ttsProvider": {
475
865
  "type": "select",
@@ -482,8 +872,50 @@
482
872
  ],
483
873
  "default": "openai",
484
874
  "hidden": "!data.voiceEnabled",
875
+ "xs": 12,
485
876
  "sm": 6,
486
- "md": 3
877
+ "md": 3,
878
+ "lg": 3,
879
+ "xl": 3
880
+ },
881
+ "sttFallback": {
882
+ "newLine": true,
883
+ "type": "select",
884
+ "label": "Speech-to-text fallback",
885
+ "help": "Used when the provider above fails (outage, expired key, empty quota). A local engine keeps voice working without the internet.",
886
+ "options": [
887
+ { "label": "None", "value": "" },
888
+ { "label": "OpenAI (Whisper)", "value": "openai" },
889
+ { "label": "Azure Speech", "value": "azure" },
890
+ { "label": "AWS Transcribe", "value": "aws" },
891
+ { "label": "Vosk (local)", "value": "vosk" }
892
+ ],
893
+ "default": "",
894
+ "hidden": "!data.voiceEnabled",
895
+ "xs": 12,
896
+ "sm": 6,
897
+ "md": 3,
898
+ "lg": 3,
899
+ "xl": 3
900
+ },
901
+ "ttsFallback": {
902
+ "type": "select",
903
+ "label": "Text-to-speech fallback",
904
+ "help": "Used when the provider above fails. Piper keeps the assistant speaking without the internet.",
905
+ "options": [
906
+ { "label": "None", "value": "" },
907
+ { "label": "OpenAI", "value": "openai" },
908
+ { "label": "Azure Speech", "value": "azure" },
909
+ { "label": "AWS Polly", "value": "aws" },
910
+ { "label": "Piper (local)", "value": "piper" }
911
+ ],
912
+ "default": "",
913
+ "hidden": "!data.voiceEnabled",
914
+ "xs": 12,
915
+ "sm": 6,
916
+ "md": 3,
917
+ "lg": 3,
918
+ "xl": 3
487
919
  },
488
920
  "voiceCredentialType": {
489
921
  "newLine": true,
@@ -495,15 +927,23 @@
495
927
  ],
496
928
  "default": "manual",
497
929
  "hidden": "!data.voiceEnabled || (data.sttProvider === 'vosk' && data.ttsProvider === 'piper')",
930
+ "xs": 12,
498
931
  "sm": 12,
499
- "md": 4
932
+ "md": 4,
933
+ "lg": 4,
934
+ "xl": 4
500
935
  },
501
936
  "_openaiSpeechHeader": {
502
937
  "newLine": true,
503
938
  "type": "header",
504
939
  "size": 3,
505
940
  "text": "OpenAI speech",
506
- "hidden": "!data.voiceEnabled || (data.sttProvider !== 'openai' && data.ttsProvider !== 'openai')"
941
+ "hidden": "!data.voiceEnabled || (data.sttProvider !== 'openai' && data.ttsProvider !== 'openai')",
942
+ "xs": 12,
943
+ "sm": 12,
944
+ "md": 12,
945
+ "lg": 12,
946
+ "xl": 12
507
947
  },
508
948
  "voiceApiKey": {
509
949
  "newLine": true,
@@ -511,8 +951,11 @@
511
951
  "label": "OpenAI key for speech (optional)",
512
952
  "help": "Leave empty to reuse the main API key when the LLM provider is OpenAI; required otherwise.",
513
953
  "hidden": "!data.voiceEnabled || (data.sttProvider !== 'openai' && data.ttsProvider !== 'openai') || data.voiceCredentialType === 'manager'",
954
+ "xs": 12,
514
955
  "sm": 12,
515
- "md": 8
956
+ "md": 8,
957
+ "lg": 8,
958
+ "xl": 8
516
959
  },
517
960
  "voiceCredentialId": {
518
961
  "newLine": true,
@@ -520,8 +963,11 @@
520
963
  "credentialType": "ai",
521
964
  "label": "OpenAI credential",
522
965
  "hidden": "!data.voiceEnabled || (data.sttProvider !== 'openai' && data.ttsProvider !== 'openai') || data.voiceCredentialType !== 'manager'",
966
+ "xs": 12,
523
967
  "sm": 12,
524
- "md": 6
968
+ "md": 6,
969
+ "lg": 6,
970
+ "xl": 6
525
971
  },
526
972
  "ttsVoice": {
527
973
  "newLine": true,
@@ -534,8 +980,11 @@
534
980
  "help": "Loaded from the provider (instance must run); you can also type a voice id.",
535
981
  "default": "alloy",
536
982
  "hidden": "!data.voiceEnabled || data.ttsProvider !== 'openai'",
983
+ "xs": 12,
537
984
  "sm": 6,
538
- "md": 4
985
+ "md": 4,
986
+ "lg": 4,
987
+ "xl": 4
539
988
  },
540
989
  "sttModel": {
541
990
  "newLine": true,
@@ -543,39 +992,56 @@
543
992
  "label": "OpenAI STT model (optional)",
544
993
  "help": "Empty = whisper-1. Also: gpt-4o-transcribe, gpt-4o-mini-transcribe.",
545
994
  "hidden": "!data.voiceEnabled || data.sttProvider !== 'openai'",
995
+ "xs": 12,
546
996
  "sm": 6,
547
- "md": 4
997
+ "md": 4,
998
+ "lg": 4,
999
+ "xl": 4
548
1000
  },
549
1001
  "ttsModel": {
550
1002
  "type": "text",
551
1003
  "label": "OpenAI TTS model (optional)",
552
1004
  "help": "Empty = tts-1. Also: tts-1-hd, gpt-4o-mini-tts.",
553
1005
  "hidden": "!data.voiceEnabled || data.ttsProvider !== 'openai'",
1006
+ "xs": 12,
554
1007
  "sm": 6,
555
- "md": 4
1008
+ "md": 4,
1009
+ "lg": 4,
1010
+ "xl": 4
556
1011
  },
557
1012
  "_azureSpeechHeader": {
558
1013
  "newLine": true,
559
1014
  "type": "header",
560
1015
  "size": 3,
561
1016
  "text": "Azure Speech",
562
- "hidden": "!data.voiceEnabled || (data.sttProvider !== 'azure' && data.ttsProvider !== 'azure')"
1017
+ "hidden": "!data.voiceEnabled || (data.sttProvider !== 'azure' && data.ttsProvider !== 'azure')",
1018
+ "xs": 12,
1019
+ "sm": 12,
1020
+ "md": 12,
1021
+ "lg": 12,
1022
+ "xl": 12
563
1023
  },
564
1024
  "azureSpeechKey": {
565
1025
  "newLine": true,
566
1026
  "type": "password",
567
1027
  "label": "Azure subscription key",
568
1028
  "hidden": "!data.voiceEnabled || (data.sttProvider !== 'azure' && data.ttsProvider !== 'azure') || data.voiceCredentialType === 'manager'",
1029
+ "xs": 12,
569
1030
  "sm": 12,
570
- "md": 5
1031
+ "md": 5,
1032
+ "lg": 5,
1033
+ "xl": 5
571
1034
  },
572
1035
  "azureSpeechRegion": {
573
1036
  "type": "text",
574
1037
  "label": "Azure region",
575
1038
  "help": "e.g. westeurope",
576
1039
  "hidden": "!data.voiceEnabled || (data.sttProvider !== 'azure' && data.ttsProvider !== 'azure') || data.voiceCredentialType === 'manager'",
1040
+ "xs": 12,
577
1041
  "sm": 6,
578
- "md": 3
1042
+ "md": 3,
1043
+ "lg": 3,
1044
+ "xl": 3
579
1045
  },
580
1046
  "azureCredentialId": {
581
1047
  "newLine": true,
@@ -583,8 +1049,11 @@
583
1049
  "credentialType": "azure",
584
1050
  "label": "Azure credential",
585
1051
  "hidden": "!data.voiceEnabled || (data.sttProvider !== 'azure' && data.ttsProvider !== 'azure') || data.voiceCredentialType !== 'manager'",
1052
+ "xs": 12,
586
1053
  "sm": 12,
587
- "md": 6
1054
+ "md": 6,
1055
+ "lg": 6,
1056
+ "xl": 6
588
1057
  },
589
1058
  "azureVoice": {
590
1059
  "newLine": true,
@@ -603,38 +1072,55 @@
603
1072
  "label": "Azure voice (optional)",
604
1073
  "help": "Loaded from Azure (instance must run); empty = pick by language. e.g. de-DE-KatjaNeural.",
605
1074
  "hidden": "!data.voiceEnabled || data.ttsProvider !== 'azure'",
1075
+ "xs": 12,
606
1076
  "sm": 6,
607
- "md": 5
1077
+ "md": 5,
1078
+ "lg": 5,
1079
+ "xl": 5
608
1080
  },
609
1081
  "_awsSpeechHeader": {
610
1082
  "newLine": true,
611
1083
  "type": "header",
612
1084
  "size": 3,
613
1085
  "text": "AWS speech",
614
- "hidden": "!data.voiceEnabled || (data.sttProvider !== 'aws' && data.ttsProvider !== 'aws')"
1086
+ "hidden": "!data.voiceEnabled || (data.sttProvider !== 'aws' && data.ttsProvider !== 'aws')",
1087
+ "xs": 12,
1088
+ "sm": 12,
1089
+ "md": 12,
1090
+ "lg": 12,
1091
+ "xl": 12
615
1092
  },
616
1093
  "awsAccessKeyId": {
617
1094
  "newLine": true,
618
1095
  "type": "text",
619
1096
  "label": "AWS access key id",
620
1097
  "hidden": "!data.voiceEnabled || (data.sttProvider !== 'aws' && data.ttsProvider !== 'aws') || data.voiceCredentialType === 'manager'",
1098
+ "xs": 12,
621
1099
  "sm": 12,
622
- "md": 4
1100
+ "md": 4,
1101
+ "lg": 4,
1102
+ "xl": 4
623
1103
  },
624
1104
  "awsSecretAccessKey": {
625
1105
  "type": "password",
626
1106
  "label": "AWS secret access key",
627
1107
  "hidden": "!data.voiceEnabled || (data.sttProvider !== 'aws' && data.ttsProvider !== 'aws') || data.voiceCredentialType === 'manager'",
1108
+ "xs": 12,
628
1109
  "sm": 12,
629
- "md": 4
1110
+ "md": 4,
1111
+ "lg": 4,
1112
+ "xl": 4
630
1113
  },
631
1114
  "awsRegion": {
632
1115
  "type": "text",
633
1116
  "label": "AWS region",
634
1117
  "help": "e.g. eu-central-1",
635
1118
  "hidden": "!data.voiceEnabled || (data.sttProvider !== 'aws' && data.ttsProvider !== 'aws') || data.voiceCredentialType === 'manager'",
1119
+ "xs": 12,
636
1120
  "sm": 6,
637
- "md": 3
1121
+ "md": 3,
1122
+ "lg": 3,
1123
+ "xl": 3
638
1124
  },
639
1125
  "awsCredentialId": {
640
1126
  "newLine": true,
@@ -642,8 +1128,11 @@
642
1128
  "credentialType": "aws",
643
1129
  "label": "AWS credential",
644
1130
  "hidden": "!data.voiceEnabled || (data.sttProvider !== 'aws' && data.ttsProvider !== 'aws') || data.voiceCredentialType !== 'manager'",
1131
+ "xs": 12,
645
1132
  "sm": 12,
646
- "md": 6
1133
+ "md": 6,
1134
+ "lg": 6,
1135
+ "xl": 6
647
1136
  },
648
1137
  "awsVoice": {
649
1138
  "newLine": true,
@@ -663,23 +1152,34 @@
663
1152
  "label": "AWS Polly voice (optional)",
664
1153
  "help": "Loaded from Polly (instance must run); empty = default per language. e.g. Vicki, Tatyana.",
665
1154
  "hidden": "!data.voiceEnabled || data.ttsProvider !== 'aws'",
1155
+ "xs": 12,
666
1156
  "sm": 6,
667
- "md": 5
1157
+ "md": 5,
1158
+ "lg": 5,
1159
+ "xl": 5
668
1160
  },
669
1161
  "_localSpeechHeader": {
670
1162
  "newLine": true,
671
1163
  "type": "header",
672
1164
  "size": 3,
673
1165
  "text": "Local speech (no cloud)",
674
- "hidden": "!data.voiceEnabled || (data.sttProvider !== 'vosk' && data.ttsProvider !== 'piper')"
1166
+ "hidden": "!data.voiceEnabled || (data.sttProvider !== 'vosk' && data.ttsProvider !== 'piper')",
1167
+ "xs": 12,
1168
+ "sm": 12,
1169
+ "md": 12,
1170
+ "lg": 12,
1171
+ "xl": 12
675
1172
  },
676
1173
  "_localSpeechHint": {
677
1174
  "newLine": true,
678
1175
  "type": "staticText",
679
1176
  "text": "Vosk (STT) and Piper (TTS) run on this host. Models and the Piper binary are downloaded automatically on first use (needs internet, plus 'unzip'/'tar'). No API key required.",
680
1177
  "hidden": "!data.voiceEnabled || (data.sttProvider !== 'vosk' && data.ttsProvider !== 'piper')",
1178
+ "xs": 12,
681
1179
  "sm": 12,
682
- "md": 12
1180
+ "md": 12,
1181
+ "lg": 12,
1182
+ "xl": 12
683
1183
  },
684
1184
  "voskModel": {
685
1185
  "newLine": true,
@@ -691,8 +1191,11 @@
691
1191
  "label": "Vosk model (optional)",
692
1192
  "help": "Model name from alphacephei.com/vosk/models, e.g. vosk-model-small-de-0.15. Empty = small default per language.",
693
1193
  "hidden": "!data.voiceEnabled || data.sttProvider !== 'vosk'",
1194
+ "xs": 12,
694
1195
  "sm": 12,
695
- "md": 6
1196
+ "md": 6,
1197
+ "lg": 6,
1198
+ "xl": 6
696
1199
  },
697
1200
  "piperVoice": {
698
1201
  "newLine": true,
@@ -704,8 +1207,11 @@
704
1207
  "label": "Piper voice (optional)",
705
1208
  "help": "e.g. de_DE-thorsten-medium, ru_RU-irina-medium. Empty = default per language.",
706
1209
  "hidden": "!data.voiceEnabled || data.ttsProvider !== 'piper'",
1210
+ "xs": 12,
707
1211
  "sm": 6,
708
- "md": 5
1212
+ "md": 5,
1213
+ "lg": 5,
1214
+ "xl": 5
709
1215
  }
710
1216
  }
711
1217
  },
@@ -720,7 +1226,11 @@
720
1226
  "name": "ConfigCustomAssistant/Components/ChatComponent",
721
1227
  "guiApi": 2,
722
1228
  "bundlerType": "module",
723
- "sm": 12
1229
+ "xs": 12,
1230
+ "sm": 12,
1231
+ "md": 12,
1232
+ "lg": 12,
1233
+ "xl": 12
724
1234
  }
725
1235
  }
726
1236
  },
@@ -735,7 +1245,11 @@
735
1245
  "name": "ConfigCustomAssistant/Components/SatellitesComponent",
736
1246
  "guiApi": 2,
737
1247
  "bundlerType": "module",
738
- "sm": 12
1248
+ "xs": 12,
1249
+ "sm": 12,
1250
+ "md": 12,
1251
+ "lg": 12,
1252
+ "xl": 12
739
1253
  }
740
1254
  }
741
1255
  }