Recherche abbrechen + Chats löschen (mit Aufräumen) + Truncation-Fix

- Manueller Abbruch: POST /api/sessions/:id/abort (nur Owner), AbortController
  für laufende Jobs (auch mitten im API-Stream), cancelQueued für wartende,
  ⛔-Button in der Activity-Bar, 'abgebrochen'-Event + History-Eintrag
- Chats löschen: 🗑-Button in der Sidebar mit Bestätigung, Ownership-Check
  (vorher konnte jeder fremde Chats löschen), löscht jetzt auch Messages
  und Dashboard-Dateien (HTML/GPX/tour.json) mit
- Truncation-Fix: finish_reason 'length' wird erkannt (sichtbarer Fehler
  statt leerer Abschluss), max_tokens auf 131072 (GLM-Max), 10-Min-Timeout
  gegen hängende Streams
This commit is contained in:
nico committed 2026-08-28 07:17:06 +02:00
1 parent 0b51bb6142
commit 8a2bf46b09
8 files changed
+237 -39

No files matched your search

+56 -23
View File
@@ -8,7 +8,7 @@ const { config, getModel, getModels } = require('./lib/config');
const db = require('./lib/db');
const queue = require('./lib/queue');
const { runResearchJob } = require('./lib/research');
const { closeBrowser } = require('./lib/tools');
const { closeBrowser, deleteSessionFiles } = require('./lib/tools');
const app = express();
app.disable('x-powered-by');
@@ -206,9 +206,31 @@ app.get('/api/sessions/:id/share', requireAuth, (req, res) => {
app.delete('/api/sessions/:id', requireAuth, (req, res) => {
const session = db.getSession(req.params.id);
if (!session) return res.status(404).json({ error: 'Session nicht gefunden' });
if (!session || session.owner_name !== req.user.n) {
return res.status(404).json({ error: 'Session nicht gefunden' });
}
queue.cancelQueued(session.id);
queue.abortRunning(session.id);
db.deleteSession(session.id);
deleteSessionFiles(session.id);
res.json({ ok: true });
});
app.post('/api/sessions/:id/abort', requireAuth, (req, res) => {
const session = db.getSession(req.params.id);
if (!session || session.owner_name !== req.user.n) {
return res.status(404).json({ error: 'Session nicht gefunden' });
}
if (queue.queuedBefore(session.id) >= 0) {
// Job wartet noch in der Queue → direkt entfernen
queue.cancelQueued(session.id);
db.setSessionStatus(session.id, 'done');
emitToSession(session.id, 'aborted', {});
emitToSession(session.id, 'status', { sessionStatus: 'done', jobStatus: 'aborted' });
} else {
// Laufender Job → Controller auslösen, der Job räumt selbst auf
queue.abortRunning(session.id);
}
res.json({ ok: true });
});
@@ -259,32 +281,43 @@ app.post('/api/sessions/:id/messages', requireAuth, (req, res) => {
}
db.setSessionStatus(session.id, 'queued');
const controller = queue.registerController(session.id);
const job = {
sessionId: session.id,
async run() {
db.setSessionStatus(session.id, 'running');
emitToSession(session.id, 'status', { sessionStatus: 'running', jobStatus: 'running' });
try {
db.setSessionStatus(session.id, 'running');
emitToSession(session.id, 'status', { sessionStatus: 'running', jobStatus: 'running' });
const emit = {
token: (t) => emitToSession(session.id, 'token', { text: t }),
thinking: (t) => emitToSession(session.id, 'thinking', { text: t }),
progress: (icon, text) => emitToSession(session.id, 'progress', { icon, text }),
step: (text) => emitToSession(session.id, 'step', { text }),
done: (result) => {
emitToSession(session.id, 'done', result);
emitToSession(session.id, 'status', { sessionStatus: 'done', jobStatus: 'done' });
sendPush(session, result);
},
error: (msg) => emitToSession(session.id, 'error', { text: msg }),
};
const emit = {
token: (t) => emitToSession(session.id, 'token', { text: t }),
thinking: (t) => emitToSession(session.id, 'thinking', { text: t }),
progress: (icon, text) => emitToSession(session.id, 'progress', { icon, text }),
step: (text) => emitToSession(session.id, 'step', { text }),
done: (result) => {
emitToSession(session.id, 'done', result);
emitToSession(session.id, 'status', { sessionStatus: 'done', jobStatus: 'done' });
sendPush(session, result);
},
aborted: () => {
emitToSession(session.id, 'aborted', {});
emitToSession(session.id, 'status', { sessionStatus: 'done', jobStatus: 'aborted' });
},
error: (msg) => emitToSession(session.id, 'error', { text: msg }),
};
await runResearchJob(
config,
db.getSession(session.id),
text,
emit,
db
);
await runResearchJob(
config,
db.getSession(session.id),
text,
emit,
db,
controller.signal
);
} finally {
queue.clearController(session.id);
}
},
async onError(e) {
console.error('Job-Fehler:', e);