AMB only uses: training goes to its own plugin. This takes back the record of what works (api/ai_evidence.py), the training network and rounds (api/ai_training.py, ui_ai_network*.js, the round form), the Gates' record switch, the ways' order by record and the external_skill field of log_outside that only fed the record. Kept, as part of using AMB: - the user's word under a finished run, now only told to the AI (ai_run_control.set_verdict, ui_ai_verdict.js); - the Gates' "Custom nodes: only the ways'" rule; - a picks block left to the AI takes its recommended picture. Reverts73518dc,67bf5b2,6647b05and49d05cf, then puts those three back with tests in test_ai_run_watch, test_ai_gates and test_ai_panels. Full suite and structure check pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 lines
2.2 KiB
JavaScript
47 lines
2.2 KiB
JavaScript
/**
|
|
* The user's word on a finished run (api/ai_run_control.py set_verdict), under its pictures: turned
|
|
* out well, or not; a click again takes it back. It goes to the AI as their message.
|
|
* POST /anomalous/ai_tasks/{task}/runs/{step}/verdict {verdict: good | bad | null}; the task's update
|
|
* draws it chosen.
|
|
*/
|
|
|
|
import { translate as t } from './locales.js';
|
|
import { anomalousAlert } from './ui_dialog.js';
|
|
import { icon } from './ui_ai_icons.js';
|
|
|
|
function el(tag, className, text) {
|
|
const node = document.createElement(tag);
|
|
if (className) node.className = className;
|
|
if (text !== undefined) node.textContent = text;
|
|
return node;
|
|
}
|
|
|
|
/** The two buttons of run `step` in task `taskId`, the one the user chose marked. */
|
|
export function verdictRow(step, taskId) {
|
|
const row = el('div', 'anomalous-ai-verdict');
|
|
row.append(el('span', 'anomalous-ai-verdict-ask', t(step.verdict ? 'aiVerdictKept' : 'aiVerdictAsk')));
|
|
for (const verdict of ['good', 'bad']) {
|
|
const chosen = step.verdict === verdict;
|
|
const node = el('button', `anomalous-ai-verdict-pick is-${verdict}${chosen ? ' is-chosen' : ''}`);
|
|
node.type = 'button';
|
|
node.setAttribute('aria-pressed', String(chosen));
|
|
node.title = t(chosen ? 'aiVerdictTakeBack' : `aiVerdictHint_${verdict}`);
|
|
node.append(icon(verdict === 'good' ? 'check' : 'close', 13), el('span', '', t(`aiVerdict_${verdict}`)));
|
|
node.onclick = async () => {
|
|
row.querySelectorAll('button').forEach(item => { item.disabled = true; });
|
|
try {
|
|
const response = await fetch(`/anomalous/ai_tasks/${encodeURIComponent(taskId)}/runs/${encodeURIComponent(step.id)}/verdict`, {
|
|
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ verdict: chosen ? null : verdict }),
|
|
});
|
|
const answer = await response.json().catch(() => ({}));
|
|
if (!response.ok) throw new Error(answer.error || response.statusText);
|
|
} catch (error) {
|
|
row.querySelectorAll('button').forEach(item => { item.disabled = false; });
|
|
await anomalousAlert(error.message);
|
|
}
|
|
};
|
|
row.append(node);
|
|
}
|
|
return row;
|
|
}
|