Plan du planificateur HC ; dialogue avec le conseiller dans HA ; arbitre encadre (question a choix fermes, liste blanche)
This commit is contained in:
51
tests/conseiller-dialogue/run.mjs
Normal file
51
tests/conseiller-dialogue/run.mjs
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env node
|
||||
// Tests du dialogue avec le conseiller (08/10/2026) : vrai code des noeuds en vm.
|
||||
import fs from 'fs';
|
||||
import vm from 'vm';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
||||
const src = (f) => fs.readFileSync(path.join(ROOT, 'src/conseiller-dialogue', f), 'utf8');
|
||||
function run(code, inputJson, nodes = {}) {
|
||||
const ctx = { $input: { first: () => ({ json: inputJson }) }, $: (n) => ({ first: () => ({ json: nodes[n] }) }),
|
||||
console, Date, Intl, Math, Number, Object, String, JSON, Array, Boolean, Set, Map };
|
||||
vm.createContext(ctx);
|
||||
return vm.runInContext(`(function(){\n${code}\n})()`, ctx);
|
||||
}
|
||||
let f = 0;
|
||||
const check = (l, c, d = '') => { if (c) console.log(`✅ ${l}`); else { f++; console.log(`❌ ${l} ${d}`); } };
|
||||
const snap = (o = {}) => ({ data: JSON.stringify({ advisor_enabled: 'on', question: 'Pourquoi la VW ne charge pas ?',
|
||||
question_at: 2000, derniere_question_at: 1000, maintenant: '08/10 05:09', soc_percent: '30', battery_current_a: '0.2',
|
||||
pv_power_w: '0', house_ac_power_w: '1751', grid_power_w: '1908', edf_contacteur: 'on', session_hc: 'on',
|
||||
vehicule_branche: 'on', vehicule: 'VW', borne_puissance_w: '0', controleur_etat: 'night_no_grid_hc_lock',
|
||||
controleur_raison: 'Nuit sans autorisation HC réseau', mode_nuit: 'sans_edf', cible_matin: '30.7', acm_courant_max: '2',
|
||||
bilan_requis: '30.7', revue_jour_date: '2026-10-08', revue_jour_texte: '- EDF ferme en heures pleines de 18:06 a 01:24',
|
||||
revue_pistes: [{ code: 'edf_heures_pleines', piste: 'recharge de midi' }], ...o }) });
|
||||
|
||||
const P = src('BUILD_PROMPT.js'), V = src('VALIDATE_PARSE.js'), B = src('BUILD_HA_CALLS.js');
|
||||
const p = run(P, snap())[0].json;
|
||||
check('PROMPT: nouvelle question -> actif', p.enabled === true);
|
||||
check('PROMPT: les mesures et la revue sont transmises', /SOC 30 %/.test(p.messages[1].content) && /night_no_grid_hc_lock/.test(p.messages[1].content) && /18:06 a 01:24/.test(p.messages[1].content) && /recharge de midi/.test(p.messages[1].content));
|
||||
check('PROMPT: question deja traitee -> inactif', run(P, snap({ derniere_question_at: 2000 }))[0].json.enabled === false);
|
||||
check('PROMPT: question vide -> inactif', run(P, snap({ question: '' }))[0].json.enabled === false);
|
||||
check('PROMPT: kill-switch -> inactif', run(P, snap({ advisor_enabled: 'off' }))[0].json.enabled === false);
|
||||
|
||||
const rep = (t, extra = {}) => ({ model: 'qwen3-coder', choices: [{ message: { content: t } }], ...extra });
|
||||
const v1 = run(V, rep('La VW est bloquee (night_no_grid_hc_lock) : mode sans_edf, SOC 30 %.'), { BUILD_PROMPT: p })[0].json;
|
||||
check('VALIDATE: chiffres des donnees -> aucun avertissement', v1.status === 'ok' && v1.avertissement === '', JSON.stringify(v1.inventes));
|
||||
const v2 = run(V, rep('Il faudrait 6,5 kWh pour la remplir.'), { BUILD_PROMPT: p })[0].json;
|
||||
check('VALIDATE: ANTI-INVENTION — chiffre absent signale', /6.5/.test(v2.avertissement), v2.avertissement);
|
||||
check('VALIDATE: OpenRouter detecte', run(V, rep('ok', { id: 'gen-1' }), { BUILD_PROMPT: p })[0].json.source === 'openrouter');
|
||||
const v3 = run(V, { error: 'x' }, { BUILD_PROMPT: p })[0].json;
|
||||
check('VALIDATE: hors ligne -> llm_offline', v3.status === 'llm_offline');
|
||||
|
||||
const v4 = run(V, rep('Courant de la batterie : 0,2 A.'), { BUILD_PROMPT: run(P, snap({ battery_current_a: '0.20000000298023224' }))[0].json })[0].json;
|
||||
check('VALIDATE: arrondi d une mesure accepte (0.2000000029 -> 0,2)', v4.avertissement === '', v4.avertissement);
|
||||
check('PROMPT: vocabulaire du contacteur transmis', /« on » = EDF FERME/.test(p.messages[0].content));
|
||||
const calls = run(B, v2, { BUILD_PROMPT: p }).map((i) => i.json);
|
||||
check('PERIMETRE: une seule ecriture, sensor.evcs_conseiller_reponse', calls.length === 1 && calls[0].state_entity === 'sensor.evcs_conseiller_reponse');
|
||||
check('PERIMETRE: question, horodatage, avertissement et source publies', calls[0].data.attributes.question_at === 2000 && /6.5/.test(calls[0].data.attributes.avertissement) && /Spark/.test(calls[0].data.attributes.source_texte));
|
||||
const hl = run(B, v3, { BUILD_PROMPT: p }).map((i) => i.json)[0];
|
||||
check('PERIMETRE: hors ligne -> reponse explicite, question marquee traitee', /pas repondu/.test(hl.data.attributes.reponse) && hl.data.attributes.question_at === 2000);
|
||||
console.log(f ? `\n${f} ECHEC(S)` : '\nDIALOGUE OK');
|
||||
process.exit(f ? 1 : 0);
|
||||
Reference in New Issue
Block a user