diff --git a/lib/aiRuns.js b/lib/aiRuns.js index 8e59ce4..8df7b33 100644 --- a/lib/aiRuns.js +++ b/lib/aiRuns.js @@ -243,7 +243,13 @@ async function getRun(id) { `SELECT i.model_id, m.name, i.status, i.tags, i.error, i.renamed_from, i.renamed_to, i.collections FROM ai_run_items i LEFT JOIN models m ON m.id = i.model_id WHERE i.run_id = $1 AND i.status <> 'pending' ORDER BY i.updated_at DESC LIMIT 12`, [id]); - return { ...shapeRun(run), recent }; + // Every failure, not only the ones still inside that window: a model that + // failed early would otherwise scroll out of sight with no way to find it. + const { rows: failures } = await db.query( + `SELECT i.model_id, m.name, i.error + FROM ai_run_items i LEFT JOIN models m ON m.id = i.model_id + WHERE i.run_id = $1 AND i.status = 'error' ORDER BY i.updated_at DESC LIMIT 200`, [id]); + return { ...shapeRun(run), recent, failures }; } async function stop(id) { @@ -257,7 +263,7 @@ async function stop(id) { async function resume(id) { const resumed = await db.transaction(async (client) => { const { rows: [run] } = await client.query( - `SELECT id FROM ai_runs WHERE id = $1 AND status IN ('paused', 'stopped', 'failed') FOR UPDATE`, [id]); + `SELECT id FROM ai_runs WHERE id = $1 AND status IN ('paused', 'stopped', 'failed', 'done') FOR UPDATE`, [id]); if (!run) return false; const retried = await client.query( `UPDATE ai_run_items SET status = 'pending', error = NULL WHERE run_id = $1 AND status = 'error'`, [id]); diff --git a/public/app.js b/public/app.js index fba20d0..27979f9 100644 --- a/public/app.js +++ b/public/app.js @@ -1420,7 +1420,8 @@ function runHtml(run, detail) { const options = run.options || {}; const cost = options.pricesKnown ? money(run.cost_usd) : 'cost unknown (add prices in Settings)'; const canStop = run.status === 'running' || run.status === 'paused'; - const canResume = ['paused', 'stopped', 'failed'].includes(run.status) && (processed < run.total || run.failed > 0); + // 'done' too: a run that finished with failures still has something to retry. + const canResume = ['paused', 'stopped', 'failed', 'done'].includes(run.status) && (processed < run.total || run.failed > 0); const feed = detail && detail.recent.length ? `