Add bot types with a permission matrix, and workspace admin bots
A bot's powers came from bots.kind alone, so only the coordinator could hand work to other bots. bot_types now works like user_types: a row with no workspace holds everywhere (the coordinator), one with a workspace only there (a workspace admin), and no row is a worker. bots.kind stays the legacy marker of the one coordinator for who sees it. The matrices in src/dict/bot-types-dict.ts say what each type may do, whom it may direct and who grants it, read by one generic interpreter (rbac/type-assignment.ts) that userTypeAssignment now wraps too. Every run reads its powers once (grabBotRunPowers) and the chat tools, task runs and task tools gate on them instead of kind; a run's powers are its type's and its user's together. In the workspace it leads, an admin hands tasks to the workers there (results relayed back to it), sets their instructions, adds tasks to their lists and keeps the workspace's context when its user may. Super admins and admins grant it from the workspace's settings or the chat header's menu, and the coordinator with set_bot_type. Admins are marked with a filled green shield beside their name across the workspace, kept live by pushBotUpdated's admin_workspace_ids. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import grabBotRunPowers from "@/src/functions/backend/db/bot-types/grab-bot-run-powers";
|
||||
import grabWorkspaceAdminTools from "@/src/harness/tools/bot/grab-workspace-admin-tools";
|
||||
import workspaceAdminsNote from "./workspace-admins-note";
|
||||
import type { BUN_SQLITE_COBBLE_BOTS } from "@/db/types/db";
|
||||
import {
|
||||
ActionCheckNote,
|
||||
@@ -87,13 +90,15 @@ export default async function runBotTask({
|
||||
const computers = await grabBotComputers({ bot_id: bot.id, workspace_id });
|
||||
|
||||
/**
|
||||
* A coordinator's task can also change workspaces: the findings
|
||||
* it was asked to record go there, not only in the report.
|
||||
* What the bot's types let it do here. A coordinator's task can
|
||||
* also change workspaces, and a workspace admin's its workspace:
|
||||
* the findings it was asked to record go there, not only in the
|
||||
* report.
|
||||
*/
|
||||
const coordinator_workspaces =
|
||||
bot.kind == "coordinator"
|
||||
? (await grabUserWorkspaces({ user_id })).filter((w) => !w.archived)
|
||||
: [];
|
||||
const powers = await grabBotRunPowers({ bot_id: bot.id, workspace_id });
|
||||
const coordinator_workspaces = powers.is_coordinator
|
||||
? (await grabUserWorkspaces({ user_id })).filter((w) => !w.archived)
|
||||
: [];
|
||||
const carry_over = await grabSessionCarryOver({
|
||||
session_id,
|
||||
bot_id: bot.id,
|
||||
@@ -121,6 +126,16 @@ export default async function runBotTask({
|
||||
*/
|
||||
const scopes = await grabRunScopes({ bot, user_id, workspace_id });
|
||||
|
||||
/**
|
||||
* A workspace admin's task keeps the workspace's context and its
|
||||
* members' instructions; it hands nothing over (no session to report
|
||||
* back to mid-task).
|
||||
*/
|
||||
const admin_tools =
|
||||
!powers.is_coordinator && workspace_id && powers.is_workspace_admin
|
||||
? (await grabWorkspaceAdminTools({ bot, user_id, workspace_id, powers, scopes })).tools
|
||||
: [];
|
||||
|
||||
const tools = [
|
||||
...(await grabBotTools({
|
||||
user_id,
|
||||
@@ -128,10 +143,12 @@ export default async function runBotTask({
|
||||
workspace_id,
|
||||
computers,
|
||||
session_id,
|
||||
is_coordinator: bot.kind == "coordinator",
|
||||
is_coordinator: powers.is_coordinator,
|
||||
admin_workspace_ids: powers.admin_workspace_ids,
|
||||
scopes,
|
||||
})),
|
||||
...(bot.kind == "coordinator"
|
||||
...admin_tools,
|
||||
...(powers.is_coordinator
|
||||
? [
|
||||
createWorkspaceTool({ user_id, workspaces: coordinator_workspaces }),
|
||||
...(coordinator_workspaces.length
|
||||
@@ -204,9 +221,14 @@ export default async function runBotTask({
|
||||
TasksNote,
|
||||
ActionCheckNote,
|
||||
workspace_id ? WorkspaceLearningNote : "",
|
||||
bot.kind == "coordinator"
|
||||
powers.is_coordinator
|
||||
? `If this brief asked you to record something in a workspace (its context, or a new one), do it yourself with update_workspace or create_workspace before you report: the report alone changes nothing.`
|
||||
: "",
|
||||
: admin_tools.some((tool) => tool.name == "update_workspace")
|
||||
? `If this brief asked you to record something in this workspace's context, do it yourself with update_workspace before you report: the report alone changes nothing.`
|
||||
: "",
|
||||
powers.is_coordinator || powers.is_workspace_admin
|
||||
? ""
|
||||
: await workspaceAdminsNote({ bot_id: bot.id, workspace_id }),
|
||||
computer
|
||||
? `You're working on the computer "${computer.name}" (a Linux sandbox with a shell, files, code runners and a browser). Use its tools; don't ask the user to run anything. When only the user can go on (a login, a captcha, a code sent to them), ask them to take over with ask_user_to_take_over.`
|
||||
: workspace_id
|
||||
|
||||
Reference in New Issue
Block a user