Let the coordinator create bots and put them in workspaces
The coordinator had no tool to add a worker, so a request to create one fell back to update_workspace and wrote a bot that did not exist into the workspace context. create_bot now adds a worker with its name, role and instructions and joins it to a workspace, and add_bot_to_workspace puts an existing worker in one. Both are coordinator-only and chat-replies-only, and createBot still enforces the crew-manager check. The coordinator's prompts now say how a bot gets created, and that one which does not exist is never written into workspace context. pick-free-hue moves to utils so the tool can pick a hue without importing from layouts.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||
import { z } from "zod";
|
||||
import type { BUN_SQLITE_COBBLE_BOTS, BUN_SQLITE_COBBLE_WORKSPACES } from "@/db/types/db";
|
||||
import { AppData } from "@/src/data/app-data";
|
||||
import createBot from "@/src/functions/backend/db/bots/create-bot";
|
||||
import addBotToWorkspace from "@/src/functions/backend/db/workspaces/add-bot-to-workspace";
|
||||
import pickFreeHue from "@/src/utils/pick-free-hue";
|
||||
import type { HarnessTool } from "../../types";
|
||||
|
||||
type Params = {
|
||||
user_id: number | string;
|
||||
/**
|
||||
* The user's workspaces the new bot can join.
|
||||
*/
|
||||
workspaces: BUN_SQLITE_COBBLE_WORKSPACES[];
|
||||
/**
|
||||
* The workspace the conversation is in: the one a new bot joins when
|
||||
* none is named.
|
||||
*/
|
||||
workspace_id?: number | string | null;
|
||||
};
|
||||
|
||||
type Args = {
|
||||
name: string;
|
||||
role: string;
|
||||
instructions: string;
|
||||
workspace_id?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Lets the coordinator add a worker bot to the crew, and put it in one of
|
||||
* the user's workspaces, so it has a place to work and be talked to.
|
||||
* Creating a bot is one of the few structural changes the coordinator
|
||||
* makes, so it only runs once the user has agreed.
|
||||
*/
|
||||
export default function createBotTool({
|
||||
user_id,
|
||||
workspaces,
|
||||
workspace_id,
|
||||
}: Params): HarnessTool<Args> {
|
||||
const list = workspaces.map((w) => `${w.id}: ${w.name}`).join("; ");
|
||||
const here = workspaces.find((w) => w.id == workspace_id);
|
||||
|
||||
return {
|
||||
name: "create_bot",
|
||||
description: `Add a worker bot to the crew: give it a short name, its job in one line, and the instructions it keeps (markdown: what it does, how it works, what it handles). A bot works in the workspace it joins, where the user can also talk to it; without one it has no computer or workspace until you give it either. Only do this when the user has asked for it or agreed to it.${here ? ` Leave out workspace_id for ${here.name}, the workspace you're in.` : ""} Workspaces: ${list || "none"}.`,
|
||||
schema: z.object({
|
||||
name: z.string().trim().min(1).max(40),
|
||||
role: z.string().trim().max(120),
|
||||
instructions: z.string().trim().min(1).max(AppData.PromptMaxLength),
|
||||
workspace_id: z.number().int().optional(),
|
||||
}),
|
||||
run: async ({ args }) => {
|
||||
const target = args.workspace_id
|
||||
? workspaces.find((w) => w.id == args.workspace_id)
|
||||
: here;
|
||||
|
||||
if (args.workspace_id && !target?.id) {
|
||||
throw new Error(
|
||||
`No workspace has id ${args.workspace_id}. Workspaces: ${list || "none"}.`,
|
||||
);
|
||||
}
|
||||
|
||||
const hues =
|
||||
(
|
||||
await BunSQLite.sql<BUN_SQLITE_COBBLE_BOTS>({
|
||||
sql: `SELECT hue FROM bots`,
|
||||
values: [],
|
||||
})
|
||||
).payload || [];
|
||||
|
||||
const bot_id = await createBot({
|
||||
user_id,
|
||||
name: args.name,
|
||||
role: args.role,
|
||||
hue: pickFreeHue({ taken: hues.map((bot) => bot.hue) }),
|
||||
system_prompt: args.instructions,
|
||||
});
|
||||
|
||||
if (target?.id) {
|
||||
await addBotToWorkspace({ user_id, workspace_id: target.id, bot_id });
|
||||
}
|
||||
|
||||
const where = target?.name ? ` and joins ${target.name}` : "";
|
||||
|
||||
return `${args.name} is on the crew (bot #${bot_id})${where}.${target ? "" : " It has no workspace yet: put it in one with add_bot_to_workspace, or give it a computer with assign_computer."}`;
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user