Files
DemonGatanjieu-Anomalous_Mo…/web/modules/ui_ai_verdict.js
T
DemonGatanjieuandClaude Opus 5.5 98c90dd8e4 Move training out of AMB: drop the run record and the training network
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.

Reverts 73518dc, 67bf5b2, 6647b05 and 49d05cf, 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>
2026-11-01 21:11:05 +08:00

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;
}