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:
2026-10-19 03:38:38 +01:00
co-authored by Claude Opus 5.5
parent d49f524fe8
commit 6a2665dae9
223 changed files with 12342 additions and 162 deletions
+66 -1
View File
@@ -56,11 +56,76 @@ export const AppData = {
BotQueueWorker: "main",
BotQueuePollMs: 3000,
/**
* Jobs run at once. Jobs on the same computer always run one at a time.
* Tasks run at once. Tasks on the same computer always run one at a time.
*/
BotQueueConcurrency: 3,
/**
* Chat replies run at once, on their own slots so they never wait
* behind long tasks. One per bot at a time.
*/
BotQueueReplyConcurrency: 3,
/**
* Finished jobs are deleted after this many days.
*/
BotQueueRetentionDays: 30,
/**
* Automatic model picks (`rankAutoModels`). A free model from outside
* `AutoModelVendorPreference` must have at least this much context, and
* this intelligence index or, unscored, this many billion parameters.
*/
HarnessAutoMinContext: 32000,
HarnessAutoMinScore: 12,
HarnessAutoMinSizeB: 20,
/**
* Models tried per harness call before giving up (pinned plus
* automatic fallbacks).
*/
HarnessMaxCandidates: 5,
HarnessRequestTimeoutMs: 3 * 60 * 1000,
/**
* A model that rate limits or fails is skipped for this long, unless
* the provider says when to come back (capped at the max).
*/
HarnessCooldownMs: 60 * 1000,
HarnessMaxCooldownMs: 24 * 60 * 60 * 1000,
/**
* Model turns in one text run before it must stop and report.
*/
HarnessMaxToolSteps: 30,
/**
* Longest tool result handed back to the model.
*/
HarnessToolResultMaxChars: 20000,
/**
* Upload cap for audio sent to transcription.
*/
HarnessMaxAudioBytes: 25 * 1024 * 1024,
/**
* Connecting to an MCP server (a computer) gives up after this long.
*/
McpConnectTimeoutMs: 15 * 1000,
/**
* One MCP tool call gives up after this long without progress.
*/
McpToolTimeoutMs: 5 * 60 * 1000,
/**
* How much of the conversation a bot sees when it replies.
*/
BotReplyHistoryMessages: 40,
/**
* Tool turns a chat reply may take. Long work goes to a task instead.
*/
BotReplyMaxToolSteps: 8,
/**
* Chat attachments: per file, per message, and how much of a
* document's text a reply reads.
*/
BotAttachmentMaxBytes: 20 * 1024 * 1024,
BotAttachmentMaxFiles: 6,
BotAttachmentMaxTextChars: 20000,
/**
* Only this many of the latest messages with files hand the files
* themselves to a reply; older ones are named.
*/
BotReplyAttachmentMessages: 4,
} as const;
+42
View File
@@ -0,0 +1,42 @@
/**
* Prompts the helper harnesses send. The text model gets their output in
* place of the media, so they must leave nothing out that it may need.
*/
export const ReadImagePrompt = `Describe this image for someone who can't see it and has to act on it.
- Copy all visible text exactly, keeping its layout where it matters (tables, forms, code, menus).
- Describe what is shown, its structure, and anything notable or unusual.
- For a screenshot, name the app or page, its state, and every control a user could click.
- Don't guess at what you can't see. Plain text only, no preamble.`;
export const TranscribeAudioPrompt = `Transcribe this audio exactly as spoken, in the language spoken. Output only the transcript: no preamble, no notes, no timestamps.`;
/**
* Added to the text model's prompt when a message part was read by another
* harness, so it knows it is working from a description.
*/
export const MediaReadNote = `Some attachments in this conversation were read for you by another model; you see its reading in [brackets] instead of the file.`;
/**
* Added to a bot's prompt when it answers the user in chat.
*/
export const ChatReplyNote = `# Replying in chat
You are chatting with the user. Answer their latest messages directly and briefly, in markdown.
- Quick questions and small changes: answer now.
- Work that takes more than a moment, or anything on a computer (running commands, editing files, browsing): call start_task with a clear brief, then tell the user in a sentence that you're on it. The result is posted here when it's done.
- When a message mixes both, answer the quick parts in this reply and start a task for the rest.
- When the user tells you something worth keeping, save it with update_memory. When they correct how you work, update your instructions with update_instructions.
- Never claim you did something you didn't do.`;
/**
* Added to the coordinator's chat prompt: it hands work to the crew.
*/
export const CoordinatorReplyNote = `As the coordinator, hand work that fits a crew member's role to them with delegate_task. They post the result in their own conversation, so tell the user who is on it.`;
/**
* Added to a bot's prompt when it works through a queued task.
*/
export const TaskRunNote = `# Working on a task
You are working through a task on your own; the user isn't watching. Use your tools until the task is done, then answer with the report for the user: what you did, what you found, and anything left for them. Keep the report short and in markdown. If you're blocked on something only the user can give you, stop and ask for it in the report.`;