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,66 @@
|
||||
import type { HarnessTool } from "../../types";
|
||||
|
||||
type Params = {
|
||||
tool: HarnessTool;
|
||||
/**
|
||||
* Absolute paths of the env files on the computer.
|
||||
*/
|
||||
shell_path: string;
|
||||
json_path: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a computer tool run with the computer's envs. The sandbox's shells
|
||||
* don't read a profile, so bash commands source the env file first and
|
||||
* Python or JavaScript code loads the JSON one. The model never sees the
|
||||
* addition; other tools pass through.
|
||||
*/
|
||||
export default function withComputerEnv({
|
||||
tool,
|
||||
shell_path,
|
||||
json_path,
|
||||
}: Params): HarnessTool {
|
||||
const shell_prefix = `[ -f ${shell_path} ] && . ${shell_path}; `;
|
||||
|
||||
if (tool.name == "sandbox_execute_bash") {
|
||||
return {
|
||||
...tool,
|
||||
run: ({ args, signal }) =>
|
||||
tool.run({
|
||||
args: typeof args?.cmd == "string" ? { ...args, cmd: `${shell_prefix}${args.cmd}` } : args,
|
||||
signal,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
if (tool.name == "sandbox_execute_code") {
|
||||
return {
|
||||
...tool,
|
||||
run: ({ args, signal }) =>
|
||||
tool.run({
|
||||
args:
|
||||
typeof args?.code == "string"
|
||||
? { ...args, code: `${codePrefix({ language: args.language, json_path })}${args.code}` }
|
||||
: args,
|
||||
signal,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
return tool;
|
||||
}
|
||||
|
||||
function codePrefix({ language, json_path }: { language?: unknown; json_path: string }) {
|
||||
const path = JSON.stringify(json_path);
|
||||
const lang = typeof language == "string" ? language.toLowerCase() : "python";
|
||||
|
||||
if (lang.startsWith("py")) {
|
||||
return `import json as _cobble_json, os as _cobble_os; _cobble_os.environ.update(_cobble_json.load(open(${path})) if _cobble_os.path.exists(${path}) else {})\n`;
|
||||
}
|
||||
|
||||
if (lang.startsWith("js") || lang.startsWith("javascript") || lang.startsWith("node")) {
|
||||
return `try { Object.assign(process.env, JSON.parse(require("fs").readFileSync(${path}, "utf8"))); } catch {}\n`;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
Reference in New Issue
Block a user