Each text and vision harness setting now carries the generation settings its model takes (temperature, sampling limits, penalties, seed, reasoning effort), edited in a modal under the model pick so the harness block stays short. Nothing is set by default, so models keep their provider's own values until a super admin or admin changes them. A setting is only offered and only sent when the catalog says the model takes it: OpenRouter's supported_parameters is now stored on harness_models and refreshed by the hourly sync. Other providers list no parameters, so their models get them all.
106 lines
3.9 KiB
TypeScript
106 lines
3.9 KiB
TypeScript
import userAuth from "@/src/functions/backend/auth/user-auth";
|
|
import grabUserBot from "@/src/functions/backend/db/bots/grab-user-bot";
|
|
import grabBotHarnessOverview from "@/src/functions/backend/db/harness/grab-bot-harness-overview";
|
|
import grabHarnessSetting from "@/src/functions/backend/db/harness/grab-harness-setting";
|
|
import saveBotHarnessSetting from "@/src/functions/backend/db/harness/save-bot-harness-setting";
|
|
import logEvent, { grabRequestIP } from "@/src/functions/backend/logger";
|
|
import { withHarnessParameters } from "@/src/dict/harness-parameter-dict";
|
|
import { SaveBotHarnessSettingsRequestSchema } from "@/src/schemas/harness-schema";
|
|
import type { BotHarnessOverviewPayload } from "@/src/types";
|
|
import AppError from "@/src/utils/app-error";
|
|
import parseWithSchema from "@/src/utils/parse-with-schema";
|
|
import isReadOnlyUser from "@/src/utils/rbac/is-read-only-user";
|
|
import canManageCrew from "@/src/utils/rbac/can-manage-crew";
|
|
import safeErrorMessage from "@/src/utils/safe-error-message";
|
|
import type {
|
|
APIResponseObject,
|
|
BunextAPIRouteHandler,
|
|
} from "@moduletrace/bunext/types";
|
|
|
|
/**
|
|
* Saves which model each harness uses for one of the session user's
|
|
* worker bots. The coordinator always uses the defaults.
|
|
*/
|
|
export const handler: BunextAPIRouteHandler<
|
|
APIResponseObject<BotHarnessOverviewPayload>
|
|
> = async ({ req, body }) => {
|
|
try {
|
|
if (req.method != "POST") {
|
|
throw new AppError(`Method not allowed`);
|
|
}
|
|
|
|
const { user, user_types } = await userAuth({ req });
|
|
|
|
if (!user?.logged_in_status || !user.id) {
|
|
return { success: false, msg: `Unauthorized`, logoutUser: true };
|
|
}
|
|
|
|
if (isReadOnlyUser({ user_types: user_types || [] })) {
|
|
throw new AppError(`This user can only read records.`);
|
|
}
|
|
|
|
if (!canManageCrew({ user_types })) {
|
|
throw new AppError(`Only an admin can do that.`);
|
|
}
|
|
|
|
const { bot_id, settings } = parseWithSchema({
|
|
schema: SaveBotHarnessSettingsRequestSchema,
|
|
data: body,
|
|
});
|
|
|
|
const bot = await grabUserBot({ bot_id, user_id: user.id });
|
|
|
|
if (!bot?.id) {
|
|
throw new AppError(`Bot not found.`);
|
|
}
|
|
|
|
if (bot.kind == "coordinator") {
|
|
throw new AppError(
|
|
`The coordinator uses the default models. A super admin can change them in Settings, under Models.`,
|
|
);
|
|
}
|
|
|
|
for (const setting of settings) {
|
|
const existing = await grabHarnessSetting({ harness: setting.harness, bot_id: bot.id });
|
|
const { voice, ...options } = existing.source == "bot" ? existing.options : {};
|
|
|
|
await saveBotHarnessSetting({
|
|
bot_id: bot.id,
|
|
harness: setting.harness,
|
|
inherit: setting.inherit,
|
|
model_id: setting.model_id,
|
|
provider_id: setting.provider_id,
|
|
fallback: setting.fallback,
|
|
enabled: setting.enabled,
|
|
options: withHarnessParameters({
|
|
options: {
|
|
...options,
|
|
...(setting.voice ? { voice: setting.voice } : {}),
|
|
},
|
|
params: setting.params || {},
|
|
}),
|
|
});
|
|
}
|
|
|
|
await logEvent({
|
|
title: "Bot model settings changed",
|
|
category: "system",
|
|
user_id: user.id,
|
|
plain_text: `User #${user.id} changed ${bot.name}'s model settings for ${settings.map((s) => s.harness).join(", ")}.`,
|
|
metadata: { bot_id: bot.id, settings },
|
|
ip_address: grabRequestIP(req),
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
msg: `Saved.`,
|
|
singleRes: await grabBotHarnessOverview({ bot_id: bot.id }),
|
|
};
|
|
} catch (error: unknown) {
|
|
return {
|
|
success: false,
|
|
msg: safeErrorMessage({ error }),
|
|
};
|
|
}
|
|
};
|