Add the harness, envs, per-bot models and chat attachments
- Harness: providers, model catalog synced hourly, automatic free picks, cooldowns, tool loop with context trimming, MCP computer tools - Bots queue runs replies and tasks through the harness; jobs wait (attempt refunded) while every model is resting - Envs: Settings > Environment, scoped general/workspace/computer, written to computers and redacted from tool output - Models: Settings > Models, per-harness provider select defaulting to OpenRouter, and a models modal on each bot's chat (the coordinator's edits the defaults) - Chat: thinking row while a reply runs, file attachments (upload, paste, drop) that replies read as images, audio and document text - Fix media uploads failing after a user's first file, and private files being served from the public media path Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
+46
-23
@@ -1,18 +1,23 @@
|
||||
import bunext from "@moduletrace/bunext";
|
||||
import { AppData } from "@/src/data/app-data";
|
||||
import type { BotJobKind } from "@/src/dict/bot-queue-dict";
|
||||
import claimBotJobs from "@/src/functions/backend/db/bots-queue/claim-bot-jobs";
|
||||
import releaseWorkerBotJobs from "@/src/functions/backend/db/bots-queue/release-worker-bot-jobs";
|
||||
import { logError } from "@/src/functions/backend/logger";
|
||||
import processBotJob from "./process-bot-job";
|
||||
import reportLostBotJobs from "./report-lost-bot-jobs";
|
||||
import { setBotsQueueWaker } from "./wake-bots-queue";
|
||||
|
||||
const worker = AppData.BotQueueWorker;
|
||||
let running = 0;
|
||||
const running = { task: 0, reply: 0 };
|
||||
let polling = false;
|
||||
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
/**
|
||||
* Starts the `bots_queue` handler: releases jobs a restart cut off, then
|
||||
* polls every `AppData.BotQueuePollMs`, reporting lost jobs and claiming
|
||||
* up to `AppData.BotQueueConcurrency` at once. Gated in production to the
|
||||
* up to `AppData.BotQueueConcurrency` tasks and, on their own slots,
|
||||
* `AppData.BotQueueReplyConcurrency` chat replies. Gated in production to the
|
||||
* `MAIN_SERVER` container, like cron.
|
||||
*/
|
||||
export default async function botsQueue() {
|
||||
@@ -28,38 +33,56 @@ export default async function botsQueue() {
|
||||
bunext.bunextLog.info(`Bots queue: released ${released} cut-off job(s)`);
|
||||
}
|
||||
|
||||
setBotsQueueWaker({ waker: wake });
|
||||
poll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls now, unless a poll is already running (`wakeBotsQueue`).
|
||||
*/
|
||||
function wake() {
|
||||
if (polling) return;
|
||||
|
||||
clearTimeout(timer);
|
||||
poll();
|
||||
}
|
||||
|
||||
async function claimAndRun({ kind, slots }: { kind: BotJobKind; slots: number }) {
|
||||
const free = slots - running[kind];
|
||||
|
||||
if (free < 1) return;
|
||||
|
||||
for (const job of await claimBotJobs({ worker, limit: free, kind })) {
|
||||
running[kind]++;
|
||||
|
||||
processBotJob({ job, worker })
|
||||
.catch((error) =>
|
||||
logError({
|
||||
title: `Bot job #${job.id} crashed`,
|
||||
error,
|
||||
}).catch(() => {}),
|
||||
)
|
||||
.finally(() => {
|
||||
running[kind]--;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function poll() {
|
||||
polling = true;
|
||||
|
||||
try {
|
||||
await reportLostBotJobs();
|
||||
|
||||
const free = AppData.BotQueueConcurrency - running;
|
||||
|
||||
if (free > 0) {
|
||||
const jobs = await claimBotJobs({ worker, limit: free });
|
||||
|
||||
for (const job of jobs) {
|
||||
running++;
|
||||
|
||||
processBotJob({ job, worker })
|
||||
.catch((error) =>
|
||||
logError({
|
||||
title: `Bot job #${job.id} crashed`,
|
||||
error,
|
||||
}).catch(() => {}),
|
||||
)
|
||||
.finally(() => {
|
||||
running--;
|
||||
});
|
||||
}
|
||||
}
|
||||
await claimAndRun({ kind: "reply", slots: AppData.BotQueueReplyConcurrency });
|
||||
await claimAndRun({ kind: "task", slots: AppData.BotQueueConcurrency });
|
||||
} catch (error) {
|
||||
await logError({ title: "Bots queue poll failed", error }).catch(
|
||||
() => {},
|
||||
);
|
||||
} finally {
|
||||
setTimeout(poll, AppData.BotQueuePollMs);
|
||||
polling = false;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(poll, AppData.BotQueuePollMs);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user