Show how each bot message was generated

Every bot message gets an info button that opens its details: the
provider and model behind it, tokens and cost, the job that ran it, each
model used and every call in order. Each model call now records how it
was made in token_usages.settings (generation settings sent, whose
settings they were, pinned or automatic model, fallbacks), shown per
model in the modal.

Live replies now carry their token usage, from the job's push and the
live relay alike, so it shows without a reload.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-25 04:33:47 +01:00
co-authored by Claude Opus 5.5
parent feec69adca
commit c13b9ea826
48 changed files with 1307 additions and 57 deletions
@@ -9,6 +9,7 @@ import relayJobToRequester from "./relay-job-to-requester";
import jobSessionId from "./job-session-id";
import grabJobUserId from "./grab-job-user-id";
import grabRunningBotJobFace from "./grab-running-bot-job-face";
import withMessageUsage from "../usage/with-message-usage";
type Params = {
job_id: number | string;
@@ -78,7 +79,7 @@ export default async function completeBotJob({
});
}
const message = silent
const inserted = silent
? null
: await insertBotMessage({
bot_id: job.bot_id,
@@ -89,7 +90,7 @@ export default async function completeBotJob({
media_ids: attachments,
});
if (job.id && message?.id) {
if (job.id && inserted?.id) {
/**
* The job's model calls were written down as they happened, before
* its message existed. Now that it does, they belong to it, so the
@@ -97,10 +98,18 @@ export default async function completeBotJob({
*/
await BunSQLite.sql({
sql: `UPDATE token_usages SET message_id = ? WHERE job_id = ? AND message_id IS NULL`,
values: [message.id, job.id],
values: [inserted.id, job.id],
}).catch(() => {});
}
/**
* Pushed live as it is returned, so it carries its usage now: the
* thread shows the tokens without a reload.
*/
const message = inserted
? ((await withMessageUsage({ messages: [inserted] }).catch(() => [inserted]))[0] ?? inserted)
: null;
const user_id = await grabJobUserId({ job });
const bot = !user_id