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
@@ -0,0 +1,40 @@
import Img from "@moduletrace/twui/layout/Img";
import Link from "@moduletrace/twui/layout/Link";
import Span from "@moduletrace/twui/layout/Span";
import type { BotMessageAttachment } from "@/src/types";
import AttachmentIcon from "./attachment-icon";
/**
* One file on a message: an image as a thumbnail, anything else as a
* named chip. Both open the file in a new tab.
*/
export default function MessageAttachment({
name,
media_type,
url,
thumbnail_url,
}: BotMessageAttachment) {
if (media_type == "image") {
return (
<Link href={url} target="_blank" title={name} className="block">
<Img
src={thumbnail_url || url}
alt={name}
className="max-h-48 max-w-64 rounded-default-lg border border-solid border-hairline object-cover"
/>
</Link>
);
}
return (
<Link
href={url}
target="_blank"
title={name}
className="flex max-w-64 items-center gap-2 rounded-default-lg border border-solid border-hairline bg-surface px-3 py-2 text-[13px] leading-[18px] text-ink no-underline hover:border-hairline-strong"
>
<AttachmentIcon media_type={media_type} />
<Span className="truncate">{name}</Span>
</Link>
);
}