The two limits were compiled in: a task run stopped at AppData.HarnessMaxToolSteps (200) and a chat reply at AppData.BotReplyMaxToolSteps (8), so an install that needed a longer task had to rebuild. Both are now `app_settings` rows (`harness_max_tool_steps` and `bot_reply_max_tool_steps`), read at the two loop call sites through grabHarnessMaxToolSteps and grabReplyMaxToolSteps, and edited by the super admin on Settings > General beside the prompt appendix. Zero clears a limit back to the code default, like the bot file quota. readStepLimit keeps the saved number only when it is a whole number of at least 1 and no more than AppData.BotStepLimitMax (1000), so a blank, a zero or a typo falls back instead of stopping every run before its first turn, and a huge number still ends in the wrap-up report. runTextLoop keeps AppData.HarnessMaxToolSteps as its default, so it stays free of database reads and its tests run as they did.
91 lines
2.7 KiB
TypeScript
91 lines
2.7 KiB
TypeScript
/**
|
|
* The harnesses: what a model is used for. Each harness has one model
|
|
* setting (`harness_settings`). Text is the brain and can't be turned off;
|
|
* the others are helpers it calls on. `automatic` ones pick a free model
|
|
* themselves when none is picked; the rest (transcription, speech,
|
|
* embeddings) are not available until one is, since free picks there
|
|
* rarely work.
|
|
*/
|
|
export const Harnesses = [
|
|
{
|
|
title: "Text",
|
|
value: "text",
|
|
automatic: true,
|
|
description: `Chats, plans and works on computers. Every bot thinks with it.`,
|
|
required: true,
|
|
},
|
|
{
|
|
title: "Media reading",
|
|
value: "vision",
|
|
automatic: true,
|
|
description: `Reads images, scans and screenshots for the text model when it can't see them itself.`,
|
|
required: false,
|
|
},
|
|
{
|
|
title: "Transcription",
|
|
value: "transcription",
|
|
automatic: false,
|
|
description: `Turns voice messages and recordings into text.`,
|
|
required: false,
|
|
},
|
|
{
|
|
title: "Speech",
|
|
value: "speech",
|
|
automatic: false,
|
|
description: `Reads bot replies aloud.`,
|
|
required: false,
|
|
},
|
|
{
|
|
title: "Image generation",
|
|
value: "image",
|
|
automatic: true,
|
|
description: `Makes images when a bot is asked for one.`,
|
|
required: false,
|
|
},
|
|
{
|
|
title: "Embeddings",
|
|
value: "embedding",
|
|
automatic: false,
|
|
description: `Turns the files bots save into vectors, so they can search them. Without one, searching falls back to plain text matching.`,
|
|
required: false,
|
|
},
|
|
] as const;
|
|
|
|
export type HarnessKind = (typeof Harnesses)[number]["value"];
|
|
|
|
/**
|
|
* The `app_settings` key holding the install's own limit on model turns in
|
|
* one run (a task). Unset means `AppData.HarnessMaxToolSteps`.
|
|
*/
|
|
export const HarnessMaxToolStepsSettingKey = "harness_max_tool_steps";
|
|
|
|
/**
|
|
* Vendors preferred for automatic picks, best first. Free models from any
|
|
* other vendor come after these, and only if they look competent.
|
|
*/
|
|
export const AutoModelVendorPreference = [
|
|
"deepseek",
|
|
"qwen",
|
|
"nvidia",
|
|
"liquid",
|
|
] as const;
|
|
|
|
/**
|
|
* Routers that pick a model themselves (e.g. `openrouter/free`). Used as
|
|
* the last automatic pick, after every named model.
|
|
*/
|
|
export const AutoModelRouterSlugs = ["openrouter/free"];
|
|
|
|
/**
|
|
* Models with one narrow job (moderation, embeddings, ranking). Never
|
|
* picked automatically.
|
|
*/
|
|
export const SpecialistModelPattern =
|
|
/guard|safety|moderation|embed|rerank|classif/i;
|
|
|
|
/**
|
|
* Names of small variants, ranked after their bigger siblings.
|
|
*/
|
|
export const SmallModelPattern =
|
|
/(?:^|[-_.:/])(nano|mini|small|lite|lightning|tiny|micro|xs)(?=$|[-_.:])/i;
|