iobroker.assistant 1.0.2 → 1.0.3
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 +3 -0
- package/admin/custom/.vite/manifest.json +91 -87
- package/admin/custom/assets/Components-C6qcpaRC.js +1 -0
- package/admin/custom/assets/{_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomAssistant__mf_owner__1-DcAGnE2z.js → _virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomAssistant__mf_owner__1-A4gakomR.js} +1 -1
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__198531368674860__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-CzBMxGFr.js → _virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__201375093093590__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-BkH7fzDw.js} +1 -1
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__198531368674860__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-1XsLCK2M.js → _virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__201375093093590__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-CwqmfMvn.js} +1 -1
- 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 → _virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__201375093093590__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BMuLYe6f.js} +80 -97
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__198531368674860__loadShare__shared-3mzaJWDF.js → _virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__201375093093590__loadShare__shared-BxjZmnpc.js} +2 -2
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__201375093093590__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-TM4l0OYm.js +122 -0
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__198531368674860__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-B_v57Qfr.js → _virtual_mf___mfe_internal__ConfigCustomAssistant__mf_owner__201375093093590__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-M61rjtmp.js} +1 -1
- package/admin/custom/assets/{dist-DiU1y0R9.js → dist-B3E7IYuQ.js} +1 -1
- package/admin/custom/assets/helpers-DE61bb74.js +1 -0
- package/admin/custom/assets/{hostInit-MshDicd1.js → hostInit-4roC4hEj.js} +1 -1
- package/admin/custom/assets/{lib-DjwHKtRi.js → lib-CchzgTUs.js} +1 -1
- package/admin/custom/assets/{mf-entry-bootstrap-0-7c1ddf47.js → mf-entry-bootstrap-0-4806bbe4.js} +2 -2
- package/admin/custom/assets/{pendingShares-CaJDCKLB.js → pendingShares-DLlv8yFY.js} +2 -2
- package/admin/custom/assets/prod-ChPGnyiA.js +15 -0
- package/admin/custom/assets/rolldown-runtime-COiEfhsA.js +1 -0
- package/admin/custom/assets/utils-Bi7ATSfV.js +4 -0
- package/admin/custom/customComponents.js +2 -2
- package/admin/custom/i18n/de.json +25 -0
- package/admin/custom/i18n/en.json +25 -0
- package/admin/custom/i18n/es.json +25 -0
- package/admin/custom/i18n/fr.json +25 -0
- package/admin/custom/i18n/it.json +25 -0
- package/admin/custom/i18n/nl.json +25 -0
- package/admin/custom/i18n/pl.json +25 -0
- package/admin/custom/i18n/pt.json +25 -0
- package/admin/custom/i18n/ru.json +25 -0
- package/admin/custom/i18n/uk.json +25 -0
- package/admin/custom/i18n/zh-cn.json +25 -0
- package/admin/custom/index.html +2 -2
- package/admin/custom/mf-manifest.json +1 -1
- package/admin/custom/mf-stats.json +1 -1
- package/admin/i18n/de.json +3 -1
- package/admin/i18n/en.json +3 -1
- package/admin/i18n/es.json +3 -1
- package/admin/i18n/fr.json +3 -1
- package/admin/i18n/it.json +3 -1
- package/admin/i18n/nl.json +3 -1
- package/admin/i18n/pl.json +3 -1
- package/admin/i18n/pt.json +3 -1
- package/admin/i18n/ru.json +3 -1
- package/admin/i18n/uk.json +3 -1
- package/admin/i18n/zh-cn.json +3 -1
- package/admin/jsonConfig.json +13 -0
- package/build/lib/journal.js +273 -0
- package/build/lib/journal.js.map +1 -0
- package/build/lib/voice/esphome.js +9 -1
- package/build/lib/voice/esphome.js.map +1 -1
- package/build/lib/voice/voiceServer.js +3 -1
- package/build/lib/voice/voiceServer.js.map +1 -1
- package/build/lib/voice/wyoming.js +3 -1
- package/build/lib/voice/wyoming.js.map +1 -1
- package/build/main.js +146 -12
- package/build/main.js.map +1 -1
- package/io-package.json +36 -1
- package/package.json +7 -7
- package/admin/custom/assets/Components-7BDDNrGP.js +0 -1
- 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 +0 -122
- package/admin/custom/assets/helpers-Dot7vgQQ.js +0 -1
- package/admin/custom/assets/rolldown-runtime-Dd_uD5pT.js +0 -1
- package/admin/custom/assets/utils-towTPKqG.js +0 -4
package/build/main.js
CHANGED
|
@@ -46,6 +46,7 @@ const timers_1 = require("./lib/timers");
|
|
|
46
46
|
const alarms_1 = require("./lib/alarms");
|
|
47
47
|
const memory_1 = require("./lib/memory");
|
|
48
48
|
const weather_1 = require("./lib/weather");
|
|
49
|
+
const journal_1 = require("./lib/journal");
|
|
49
50
|
const localLlm_1 = require("./lib/localLlm");
|
|
50
51
|
const credentials_1 = require("./lib/credentials");
|
|
51
52
|
const context_1 = require("./lib/context");
|
|
@@ -187,6 +188,8 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
187
188
|
/** Set once `onReady` initialised the pipeline — with or without a cloud {@link agent}. */
|
|
188
189
|
ready = false;
|
|
189
190
|
mcp = null;
|
|
191
|
+
/** Who asked what and how it was answered (admin chat); null until `onReady` read the config. */
|
|
192
|
+
journal = null;
|
|
190
193
|
/** Short-TTL cache for the expensive device/room/function listings; invalidated on enum changes. */
|
|
191
194
|
listCache = null;
|
|
192
195
|
/** Cache of a `<base>.SET` level state id → its writable boolean sibling switch (`<base>.ON_SET`/`.ON`), or ''. */
|
|
@@ -270,6 +273,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
270
273
|
const provider = cfg.provider || 'openai';
|
|
271
274
|
const localOnly = provider === 'none';
|
|
272
275
|
const apiKey = localOnly ? '' : (0, llm_1.effectiveApiKey)(cfg.provider, await (0, credentials_1.resolveApiKey)(this, cfg));
|
|
276
|
+
await this.setupJournal();
|
|
273
277
|
if (!localOnly && !apiKey) {
|
|
274
278
|
this.log.warn(cfg.credentialType === 'manager'
|
|
275
279
|
? 'No credential selected (manager mode) — pick an API-key credential in the adapter settings.'
|
|
@@ -278,12 +282,12 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
278
282
|
return;
|
|
279
283
|
}
|
|
280
284
|
try {
|
|
281
|
-
this.mcp = await (0, mcp_server_1.createInProcessMcp)({
|
|
285
|
+
this.mcp = this.journalMcp(await (0, mcp_server_1.createInProcessMcp)({
|
|
282
286
|
adapter: this,
|
|
283
287
|
language: this.language,
|
|
284
288
|
allowSetState: cfg.allowWriteStates,
|
|
285
289
|
allowObjectChange: cfg.allowObjectChange,
|
|
286
|
-
});
|
|
290
|
+
}));
|
|
287
291
|
this.listCache = new tools_1.ListCache();
|
|
288
292
|
const { tools, denied } = await (0, tools_1.buildMcpTools)(this.mcp, cfg, this.listCache, (id, fb) => this.resolveDeviceName(id, fb));
|
|
289
293
|
// Let the cloud LLM handle timers/alarms too (for phrasings the rule-based NLU misses).
|
|
@@ -314,7 +318,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
314
318
|
baseUrl: prov.baseUrl,
|
|
315
319
|
systemPrompt: cfg.systemPrompt || '',
|
|
316
320
|
maxTokens: cfg.maxTokens || 1024,
|
|
317
|
-
tools,
|
|
321
|
+
tools: tools.map(t => this.journalTool(t)),
|
|
318
322
|
log: this.log,
|
|
319
323
|
});
|
|
320
324
|
}
|
|
@@ -403,7 +407,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
403
407
|
language,
|
|
404
408
|
stt,
|
|
405
409
|
tts,
|
|
406
|
-
answer: question => this.answer(question, 'wyoming'),
|
|
410
|
+
answer: (question, sttMs) => this.answer(question, 'wyoming', { transport: 'wyoming', sttMs }),
|
|
407
411
|
getHints: () => this.buildSttHints(),
|
|
408
412
|
log: this.log,
|
|
409
413
|
});
|
|
@@ -463,7 +467,12 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
463
467
|
language,
|
|
464
468
|
stt,
|
|
465
469
|
tts,
|
|
466
|
-
answer: (question, origin) => this.answerVoice(question, origin.device
|
|
470
|
+
answer: (question, origin) => this.answerVoice(question, origin.device, {
|
|
471
|
+
transport: 'esphome',
|
|
472
|
+
room: origin.room,
|
|
473
|
+
wakeWord: origin.wakeWord,
|
|
474
|
+
sttMs: origin.sttMs,
|
|
475
|
+
}),
|
|
467
476
|
getHints: () => this.buildSttHints(),
|
|
468
477
|
media: this.media,
|
|
469
478
|
mediaHost: (cfg.esphomeMediaHost || '').trim(),
|
|
@@ -536,7 +545,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
536
545
|
language,
|
|
537
546
|
stt,
|
|
538
547
|
tts,
|
|
539
|
-
answer: (question, ctx) => this.answerVoice(question, ctx.device),
|
|
548
|
+
answer: (question, ctx) => this.answerVoice(question, ctx.device, { transport: 'udp', room: ctx.room, sttMs: ctx.sttMs }),
|
|
540
549
|
getHints: () => this.buildSttHints(),
|
|
541
550
|
log: this.log,
|
|
542
551
|
onStatus: (device, room, state) => {
|
|
@@ -586,11 +595,11 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
586
595
|
* not re-trigger onStateChange). The state writes must not block the spoken reply, so they are
|
|
587
596
|
* fire-and-forget.
|
|
588
597
|
*/
|
|
589
|
-
async answerVoice(question, source) {
|
|
598
|
+
async answerVoice(question, source, origin = {}) {
|
|
590
599
|
this.setStateAsync('text.request', { val: question, ack: true }).catch(() => { });
|
|
591
600
|
this.setQuerySource(source);
|
|
592
601
|
this.log.info(`Voice Q (${source}): ${question}`);
|
|
593
|
-
const answer = await this.answer(question, source);
|
|
602
|
+
const answer = await this.answer(question, source, { satellite: source, ...origin });
|
|
594
603
|
this.log.info(`Voice A (${source}): ${answer}`);
|
|
595
604
|
this.setStateAsync('text.response', { val: answer, ack: true }).catch(() => { });
|
|
596
605
|
return answer;
|
|
@@ -659,11 +668,17 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
659
668
|
pcm = pcm.subarray(44);
|
|
660
669
|
}
|
|
661
670
|
const language = msg.language || engines.language;
|
|
671
|
+
const sttStart = Date.now();
|
|
662
672
|
const text = (await engines.stt.transcribe(pcm, rate, language, await this.buildSttHints())).trim();
|
|
663
673
|
if (!text) {
|
|
664
674
|
return { text: '', answer: '' };
|
|
665
675
|
}
|
|
666
|
-
const answer = await this.answerVoice(text, source
|
|
676
|
+
const answer = await this.answerVoice(text, source, {
|
|
677
|
+
transport: 'native',
|
|
678
|
+
room,
|
|
679
|
+
wakeWord: typeof msg.wakeWord === 'string' ? msg.wakeWord : undefined,
|
|
680
|
+
sttMs: Date.now() - sttStart,
|
|
681
|
+
});
|
|
667
682
|
if (!answer) {
|
|
668
683
|
return { text, answer: '' };
|
|
669
684
|
}
|
|
@@ -2146,6 +2161,24 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2146
2161
|
}
|
|
2147
2162
|
return;
|
|
2148
2163
|
}
|
|
2164
|
+
// Admin chat: the journal of the last hours (message = { since?: ms }), and wiping it.
|
|
2165
|
+
if (obj.command === 'getJournal') {
|
|
2166
|
+
const since = Number(obj.message?.since) || 0;
|
|
2167
|
+
const result = this.journal?.enabled
|
|
2168
|
+
? { enabled: true, entries: this.journal.list(since) }
|
|
2169
|
+
: { enabled: false, entries: [] };
|
|
2170
|
+
if (obj.callback) {
|
|
2171
|
+
this.sendTo(obj.from, obj.command, result, obj.callback);
|
|
2172
|
+
}
|
|
2173
|
+
return;
|
|
2174
|
+
}
|
|
2175
|
+
if (obj.command === 'clearJournal') {
|
|
2176
|
+
this.journal?.clear();
|
|
2177
|
+
if (obj.callback) {
|
|
2178
|
+
this.sendTo(obj.from, obj.command, { ok: true }, obj.callback);
|
|
2179
|
+
}
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2149
2182
|
if (obj.command !== 'ask') {
|
|
2150
2183
|
return;
|
|
2151
2184
|
}
|
|
@@ -2168,13 +2201,14 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2168
2201
|
this.log.info(`A: ${answer}`);
|
|
2169
2202
|
this.setStateAsync('text.response', { val: answer, ack: true }).catch(() => { });
|
|
2170
2203
|
if (obj.callback) {
|
|
2171
|
-
this
|
|
2204
|
+
// `journaled`: the admin chat gets this exchange from the journal and must not add it twice.
|
|
2205
|
+
this.sendTo(obj.from, obj.command, { answer, journaled: !!this.journal?.enabled }, obj.callback);
|
|
2172
2206
|
}
|
|
2173
2207
|
}
|
|
2174
2208
|
catch (e) {
|
|
2175
2209
|
this.log.error(`Assistant error: ${e.message}`);
|
|
2176
2210
|
if (obj.callback) {
|
|
2177
|
-
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
2211
|
+
this.sendTo(obj.from, obj.command, { error: e.message, journaled: !!this.journal?.enabled }, obj.callback);
|
|
2178
2212
|
}
|
|
2179
2213
|
}
|
|
2180
2214
|
}
|
|
@@ -2187,7 +2221,12 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2187
2221
|
* is applied to the cloud LLM tier; every completed exchange (whichever tier answered) is recorded so
|
|
2188
2222
|
* later turns have the full thread.
|
|
2189
2223
|
*/
|
|
2190
|
-
|
|
2224
|
+
answer(question, source = '', origin = {}) {
|
|
2225
|
+
return this.journal
|
|
2226
|
+
? this.journal.run(question, source, origin, () => this.answerTracked(question, source))
|
|
2227
|
+
: this.answerTracked(question, source);
|
|
2228
|
+
}
|
|
2229
|
+
async answerTracked(question, source) {
|
|
2191
2230
|
const useCtx = this.config.useConversationContext !== false;
|
|
2192
2231
|
const history = useCtx ? this.context.get(source) : [];
|
|
2193
2232
|
const raw = await this.produceAnswer(question, history, source);
|
|
@@ -2195,6 +2234,9 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2195
2234
|
// (see followUpHint). Strip it here so it's neither stored, shown nor spoken, and expose it as the
|
|
2196
2235
|
// follow-up flag. Single-user voice → a shared field is race-free enough (read right after await).
|
|
2197
2236
|
this.lastFollowUp = /\[\[LISTEN\]\]/i.test(raw);
|
|
2237
|
+
if (this.lastFollowUp) {
|
|
2238
|
+
this.journal?.note({ followUp: true });
|
|
2239
|
+
}
|
|
2198
2240
|
const result = raw.replace(/\s*\[\[LISTEN\]\]\s*/gi, ' ').trim();
|
|
2199
2241
|
if (useCtx && result) {
|
|
2200
2242
|
this.context.add(source, question, result);
|
|
@@ -2278,6 +2320,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2278
2320
|
if (this.rings.length && (0, nlu_1.isStopCommand)(question)) {
|
|
2279
2321
|
const n = this.stopRinging();
|
|
2280
2322
|
this.log.info(`Ring stopped by voice (${n} session(s)).`);
|
|
2323
|
+
this.journal?.note({ tier: 'stop' });
|
|
2281
2324
|
const lang = String(this.config.voiceLanguage || this.language || 'en');
|
|
2282
2325
|
return lang === 'ru' ? 'Хорошо.' : lang === 'de' ? 'Ok.' : 'Okay.';
|
|
2283
2326
|
}
|
|
@@ -2288,6 +2331,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2288
2331
|
const asked = this.pending.question(source);
|
|
2289
2332
|
if (this.pending.deliver(source, question)) {
|
|
2290
2333
|
this.log.info(`Answer to "${asked}" from source '${source || 'any'}': ${question}`);
|
|
2334
|
+
this.journal?.note({ tier: 'askReply', detail: asked || undefined });
|
|
2291
2335
|
return '';
|
|
2292
2336
|
}
|
|
2293
2337
|
}
|
|
@@ -2297,6 +2341,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2297
2341
|
const routine = (0, routines_1.matchRoutine)(question, this.routines);
|
|
2298
2342
|
if (routine) {
|
|
2299
2343
|
this.log.info(`Routine '${routine.name}' triggered (source='${source}').`);
|
|
2344
|
+
this.journal?.note({ tier: 'routine', detail: routine.name });
|
|
2300
2345
|
await this.runRoutine(routine, source);
|
|
2301
2346
|
return routine.reply;
|
|
2302
2347
|
}
|
|
@@ -2330,6 +2375,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2330
2375
|
const ans = await this.localLlm.ask(facts ? `${facts}\n\n${question}` : question);
|
|
2331
2376
|
if (ans && !(0, localLlm_1.isHandoff)(ans)) {
|
|
2332
2377
|
this.log.info(`Answered by local LLM (source='${source}').`);
|
|
2378
|
+
this.journal?.note({ tier: 'localLlm', detail: this.localLlmName() });
|
|
2333
2379
|
return ans;
|
|
2334
2380
|
}
|
|
2335
2381
|
this.log.debug('Local LLM handed off to the cloud LLM.');
|
|
@@ -2347,6 +2393,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2347
2393
|
// Provider "none": no tier further down. Say so instead of failing — over voice an error is
|
|
2348
2394
|
// read out as a technical message.
|
|
2349
2395
|
this.log.info(`No local tier could answer and no LLM provider is configured (source='${source}').`);
|
|
2396
|
+
this.journal?.note({ tier: 'none' });
|
|
2350
2397
|
return this.localOnlyFallback();
|
|
2351
2398
|
}
|
|
2352
2399
|
const ctx = await this.buildDeviceContext();
|
|
@@ -2359,6 +2406,10 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2359
2406
|
// Prepend the current date/time (and the weather line, if a source is configured) to the user turn —
|
|
2360
2407
|
// cache-safe, see buildTimeContext. The stored history keeps the untouched question.
|
|
2361
2408
|
const questionForLlm = [this.buildTimeContext(), weather, question].filter(Boolean).join('\n\n');
|
|
2409
|
+
this.journal?.note({
|
|
2410
|
+
tier: 'cloud',
|
|
2411
|
+
detail: `${this.config.provider || 'openai'} · ${this.agent.model || 'auto'}`,
|
|
2412
|
+
});
|
|
2362
2413
|
return this.agent.ask(questionForLlm, sys, history);
|
|
2363
2414
|
}
|
|
2364
2415
|
/** Reply when nothing local understood the request and there is no cloud LLM (provider "none"). */
|
|
@@ -2431,6 +2482,81 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2431
2482
|
}
|
|
2432
2483
|
api.registerUsedResource(type, data).catch(e => this.log.debug(`could not register ${type} ${port}: ${e.message}`));
|
|
2433
2484
|
}
|
|
2485
|
+
/**
|
|
2486
|
+
* Open the conversation journal (shown in the admin chat). Every new or finished entry is mirrored to
|
|
2487
|
+
* `journal.last` as JSON — the chat subscribes to it, which is what makes the view live.
|
|
2488
|
+
*/
|
|
2489
|
+
async setupJournal() {
|
|
2490
|
+
const hours = Math.max(0, Math.min(168, Number(this.config.journalHours ?? 24) || 0));
|
|
2491
|
+
const file = path.join(this.instanceDataDir(), 'journal.json');
|
|
2492
|
+
// Also in io-package `instanceObjects`; created here for instances that predate it.
|
|
2493
|
+
await this.setObjectNotExistsAsync('journal', {
|
|
2494
|
+
type: 'channel',
|
|
2495
|
+
common: { name: 'Conversation journal' },
|
|
2496
|
+
native: {},
|
|
2497
|
+
});
|
|
2498
|
+
await this.setObjectNotExistsAsync('journal.last', {
|
|
2499
|
+
type: 'state',
|
|
2500
|
+
common: {
|
|
2501
|
+
name: 'Latest journal entry (JSON; written when a request starts and when it is answered)',
|
|
2502
|
+
type: 'string',
|
|
2503
|
+
role: 'json',
|
|
2504
|
+
read: true,
|
|
2505
|
+
write: false,
|
|
2506
|
+
def: '',
|
|
2507
|
+
},
|
|
2508
|
+
native: {},
|
|
2509
|
+
});
|
|
2510
|
+
this.journal = new journal_1.Journal({
|
|
2511
|
+
hours,
|
|
2512
|
+
file,
|
|
2513
|
+
log: this.log,
|
|
2514
|
+
onChange: entry => {
|
|
2515
|
+
this.setStateAsync('journal.last', { val: JSON.stringify(entry), ack: true }).catch(() => { });
|
|
2516
|
+
},
|
|
2517
|
+
});
|
|
2518
|
+
if (hours) {
|
|
2519
|
+
await this.journal.load();
|
|
2520
|
+
}
|
|
2521
|
+
else {
|
|
2522
|
+
// Switched off: do not keep what was recorded while it was on.
|
|
2523
|
+
await fs.promises.rm(file, { force: true }).catch(() => { });
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
/** Wrap the MCP connection so every state the pipeline reads or writes lands in the journal entry. */
|
|
2527
|
+
journalMcp(mcp) {
|
|
2528
|
+
return {
|
|
2529
|
+
listTools: () => mcp.listTools(),
|
|
2530
|
+
callTool: (name, args) => {
|
|
2531
|
+
this.journal?.stateAccess(name, args);
|
|
2532
|
+
return mcp.callTool(name, args);
|
|
2533
|
+
},
|
|
2534
|
+
close: () => mcp.close(),
|
|
2535
|
+
};
|
|
2536
|
+
}
|
|
2537
|
+
/** Wrap an LLM tool so its calls (arguments, result, duration) land in the journal entry. */
|
|
2538
|
+
journalTool(tool) {
|
|
2539
|
+
return {
|
|
2540
|
+
...tool,
|
|
2541
|
+
run: async (args) => {
|
|
2542
|
+
const start = Date.now();
|
|
2543
|
+
try {
|
|
2544
|
+
const result = await tool.run(args);
|
|
2545
|
+
this.journal?.tool(tool.name, args, Date.now() - start, result);
|
|
2546
|
+
return result;
|
|
2547
|
+
}
|
|
2548
|
+
catch (e) {
|
|
2549
|
+
this.journal?.tool(tool.name, args, Date.now() - start, undefined, e.message);
|
|
2550
|
+
throw e;
|
|
2551
|
+
}
|
|
2552
|
+
},
|
|
2553
|
+
};
|
|
2554
|
+
}
|
|
2555
|
+
/** Short name of the local model for the journal ("qwen2.5-1.5b-instruct-q4_k_m"). */
|
|
2556
|
+
localLlmName() {
|
|
2557
|
+
const url = (this.config.localLlmModelUrl || '').trim() || localLlm_1.DEFAULT_LOCAL_MODEL_URL;
|
|
2558
|
+
return (url.split(/[/\\]/).pop() || url).replace(/\?.*$/, '').replace(/\.gguf$/i, '');
|
|
2559
|
+
}
|
|
2434
2560
|
/** Writable per-instance data dir via the adapter-core function (with a fallback for old runtimes). */
|
|
2435
2561
|
instanceDataDir() {
|
|
2436
2562
|
try {
|
|
@@ -2559,6 +2685,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
2559
2685
|
if (!intents.length || !intents.every(i => this.canExecuteNlu(i, devices.length))) {
|
|
2560
2686
|
return null; // nothing matched, or one part cannot run here → let the LLM answer the whole thing
|
|
2561
2687
|
}
|
|
2688
|
+
this.journal?.note({ tier: 'nlu', detail: intents.map(i => i.action).join(' + ') });
|
|
2562
2689
|
const answers = [];
|
|
2563
2690
|
let failed = false;
|
|
2564
2691
|
for (const intent of intents) {
|
|
@@ -4153,6 +4280,7 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
4153
4280
|
}
|
|
4154
4281
|
try {
|
|
4155
4282
|
await this.setForeignStateAsync(write.id, { val: write.value, ack: false });
|
|
4283
|
+
this.journal?.stateAccess('set_state', { id: write.id, value: write.value });
|
|
4156
4284
|
this.log.info(`trigger '${def.id}': ${write.id} = ${JSON.stringify(write.value)}`);
|
|
4157
4285
|
}
|
|
4158
4286
|
catch (e) {
|
|
@@ -4888,6 +5016,12 @@ class Assistant extends adapter_core_1.Adapter {
|
|
|
4888
5016
|
catch {
|
|
4889
5017
|
// ignore
|
|
4890
5018
|
}
|
|
5019
|
+
try {
|
|
5020
|
+
await this.journal?.flush();
|
|
5021
|
+
}
|
|
5022
|
+
catch {
|
|
5023
|
+
// ignore
|
|
5024
|
+
}
|
|
4891
5025
|
try {
|
|
4892
5026
|
await this.mcp?.close();
|
|
4893
5027
|
}
|