Files
cobble/src/functions/backend/db/bots-queue/stopped-job-report.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

46 lines
1.4 KiB
TypeScript

import { BotStoppedMessage } from "@/src/dict/bot-queue-dict";
type Job = {
session_id?: number | string | null;
kind?: string | null;
title?: string | null;
};
/**
* What the bot says in a conversation the user stopped it in. A task names
* the work that was cut off, so a long job that quietly went nowhere reads
* as stopped rather than as finished; a reply has no title worth quoting.
*/
export default function stoppedJobReport({ job }: { job: Job }): string {
const title = (job.title || "").trim();
return job.kind == "task" && title
? `${BotStoppedMessage} I was on **${title}**.`
: BotStoppedMessage;
}
/**
* The job that speaks for each session: one per session, since a reply and
* the task it started are the same conversation and two notes there read as
* a stutter. A task wins, because it's the one that can name the work.
*/
export function pickReportedJobs<T extends Job>({ jobs }: { jobs: T[] }): Map<number, T> {
const picked = new Map<number, T>();
for (const job of jobs) {
/**
* A job with no session is stopped all the same; it just has
* nowhere to report it.
*/
if (job.session_id === null || job.session_id === undefined) continue;
const known = picked.get(Number(job.session_id));
if (!known || (known.kind != "task" && job.kind == "task")) {
picked.set(Number(job.session_id), job);
}
}
return picked;
}