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:
@@ -0,0 +1,19 @@
|
||||
import fetchApi from "@moduletrace/twui/utils/fetch/fetchApi";
|
||||
import type { APIResponseObject } from "@moduletrace/bunext/types";
|
||||
import type { SaveBotHarnessSettingsRequest } from "@/src/schemas/harness-schema";
|
||||
import type { BotHarnessOverviewPayload } from "@/src/types";
|
||||
|
||||
/**
|
||||
* Saves a worker bot's own model settings and returns the fresh page data.
|
||||
*/
|
||||
export default async function saveBotHarnessSettings(
|
||||
body: SaveBotHarnessSettingsRequest,
|
||||
) {
|
||||
return await fetchApi<
|
||||
SaveBotHarnessSettingsRequest,
|
||||
APIResponseObject<BotHarnessOverviewPayload>
|
||||
>(`/api/admin/bots/save-harness-settings`, {
|
||||
method: "POST",
|
||||
body,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { useContext } from "react";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import SettingsShell from "@/src/pages/admin/settings/(partials)/settings-shell";
|
||||
import BotHarnessForm from "../../(partials)/bot-harness-form";
|
||||
|
||||
/**
|
||||
* A worker bot's models: per harness, the default or its own pick. The
|
||||
* same form as the chat header's models modal.
|
||||
*/
|
||||
export default function BotModelsSection() {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
const bot = pageProps?.bot;
|
||||
const overview = pageProps?.bot_harness_overview;
|
||||
|
||||
if (!bot?.id || !overview) return null;
|
||||
|
||||
return (
|
||||
<SettingsShell
|
||||
title={`${bot.name}'s models`}
|
||||
description="Uses the default models unless you pick its own."
|
||||
>
|
||||
<BotHarnessForm bot={bot} harnesses={overview.harnesses} />
|
||||
</SettingsShell>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import userAuth from "@/src/functions/backend/auth/user-auth";
|
||||
import grabBots from "@/src/functions/backend/db/bots/grab-bots";
|
||||
import grabBotHarnessOverview from "@/src/functions/backend/db/harness/grab-bot-harness-overview";
|
||||
import type { PagePropsType, PageQueryObject } from "@/src/types";
|
||||
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
||||
|
||||
/**
|
||||
* A worker bot's model settings. The coordinator always uses the defaults,
|
||||
* so its page goes back to its conversation.
|
||||
*/
|
||||
export const server: BunextPageServerFn<PagePropsType> = async (params) => {
|
||||
const query: PageQueryObject = params.query;
|
||||
const { user } = await userAuth({ req: params.req });
|
||||
|
||||
if (!user?.id) {
|
||||
return { redirect: { destination: "/auth/login" } };
|
||||
}
|
||||
|
||||
const bots = await grabBots({ user_id: user.id });
|
||||
const bot = bots.find((b) => String(b.id) === String(query.bot_id));
|
||||
|
||||
if (!bot?.id) {
|
||||
return { redirect: { destination: "/admin/bots" } };
|
||||
}
|
||||
|
||||
if (bot.kind == "coordinator") {
|
||||
return { redirect: { destination: `/admin/bots/${bot.id}` } };
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
bots,
|
||||
bot,
|
||||
bot_harness_overview: await grabBotHarnessOverview({ bot_id: bot.id }),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { PagePropsType } from "@/src/types";
|
||||
import type { BunextPageModuleMetaFn } from "@moduletrace/bunext/types";
|
||||
import { SiteData } from "@/src/data/site-data";
|
||||
import BotModelsSection from "./(sections)/bot-models-section";
|
||||
|
||||
export default function BotModelsPage() {
|
||||
return <BotModelsSection />;
|
||||
}
|
||||
|
||||
export const meta: BunextPageModuleMetaFn = async (params) => {
|
||||
const bot = (params.serverRes?.props as PagePropsType | undefined)?.bot;
|
||||
|
||||
return {
|
||||
title: `${bot?.name || "Bot"} models | ${SiteData["SiteName"]}`,
|
||||
description: `Which models ${bot?.name || "this bot"} uses.`,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user