Files
cobble/src/bots-queue/job-abort-registry.ts
T
tben fcad4b49d6 Let a user stop a bot, and say the app is still alpha
The thinking row and the header menu both carry Stop while a bot has work
open for the user anywhere: every pending or processing job of that bot in
their conversations is failed as stopped, its task closed, a Stopped step
recorded and one closing message posted per session, so the thread stops
waiting and the bot goes idle. The handler running the job is aborted from
this process through a registry, so a job stuck waiting on a model stops at
once instead of on its next heartbeat, and a late face change after the
abort is dropped.

The release stage is now said in the app too: Settings > General reports
"Cobble v0.1.5 (alpha)" next to development, and the README and RELEASING.md
say what alpha means for installs.
2026-10-23 10:19:41 +01:00

41 lines
1.4 KiB
TypeScript

/**
* The abort controllers of the jobs this process is running right now,
* keyed by job id. Stopping a bot from the chat aborts the request its job
* is waiting on (a model that never answers, a tool that hangs) instead of
* leaving it to find out on its next heartbeat, which can take minutes.
*
* Only the process running a job can abort it, so this is a bonus: the job
* is already failed in `bots_queue`, and a handler in another process
* learns that on its next `updateBotJob`. Kept free of imports so the API
* routes can use it without pulling the queue handler into a page bundle.
*/
const running = new Map<number, () => void>();
/**
* Called by a handler once it holds a job, with the way to abort it.
*/
export function registerJobAbort({ job_id, abort }: { job_id: number | string; abort: () => void }) {
running.set(Number(job_id), abort);
}
/**
* Called by a handler in its `finally`, whatever the outcome.
*/
export function unregisterJobAbort({ job_id }: { job_id: number | string }) {
running.delete(Number(job_id));
}
/**
* Aborts a job running here. False means another process (or nobody) has
* it, so the row's new status is how it finds out.
*/
export function abortRunningJob({ job_id }: { job_id: number | string }) {
const abort = running.get(Number(job_id));
if (!abort) return false;
abort();
return true;
}