The rail was built from page props and only knew bots it already had, so a bot the coordinator created did not appear until a reload. create_bot and add_bot_to_workspace now push server:bot-created (BotCreatedData) to everyone who sees the bot: its rail row, the workspaces it is in, and whether it belongs in that user's own chat list. useLiveBots inserts it, after the pinned coordinator outside a workspace and only when the open workspace is one it joined. liveRelay pushes created bots too, so a bot added by another process still shows.
84 lines
3.0 KiB
TypeScript
84 lines
3.0 KiB
TypeScript
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 pushBotCreated from "@/src/bots-queue/push-bot-created";
|
|
import addBotToWorkspace from "@/src/functions/backend/db/workspaces/add-bot-to-workspace";
|
|
import type { HarnessTool } from "../../types";
|
|
|
|
type Params = {
|
|
user_id: number | string;
|
|
/**
|
|
* The user's worker bots.
|
|
*/
|
|
workers: BUN_SQLITE_COBBLE_BOTS[];
|
|
/**
|
|
* The user's live workspaces.
|
|
*/
|
|
workspaces: BUN_SQLITE_COBBLE_WORKSPACES[];
|
|
};
|
|
|
|
type Args = {
|
|
bot_id: number;
|
|
workspace_id: number;
|
|
};
|
|
|
|
/**
|
|
* Lets the coordinator put a crew member in one of the user's workspaces,
|
|
* so the user can talk to it there and it gets that workspace's context,
|
|
* computers and models. Offered in the coordinator's own chat only, where
|
|
* the whole crew and every live workspace are known.
|
|
*/
|
|
export default function addBotToWorkspaceTool({
|
|
user_id,
|
|
workers,
|
|
workspaces,
|
|
}: Params): HarnessTool<Args> {
|
|
const crew = workers.map((bot) => `${bot.id}: ${bot.name}`).join("; ");
|
|
const list = workspaces.map((w) => `${w.id}: ${w.name}`).join("; ");
|
|
|
|
return {
|
|
name: "add_bot_to_workspace",
|
|
description: `Put a crew member in one of the user's workspaces. There they work with the workspace's context, its computers and its models, and the user chats with them in it. Use it when the user asks for a bot to work in a workspace, or after create_bot made one without a place. Crew: ${crew || "none"}. Workspaces: ${list || "none"}.`,
|
|
schema: z.object({
|
|
bot_id: z.number().int(),
|
|
workspace_id: z.number().int(),
|
|
}),
|
|
run: async ({ args }) => {
|
|
const worker = workers.find((bot) => bot.id == args.bot_id);
|
|
const workspace = workspaces.find((w) => w.id == args.workspace_id);
|
|
|
|
if (!worker?.id) {
|
|
throw new Error(`No crew member has id ${args.bot_id}. Crew: ${crew || "none"}.`);
|
|
}
|
|
|
|
if (!workspace?.id) {
|
|
throw new Error(
|
|
`No workspace has id ${args.workspace_id}. Workspaces: ${list || "none"}.`,
|
|
);
|
|
}
|
|
|
|
const already =
|
|
(
|
|
await BunSQLite.sql<{ present: number }>({
|
|
sql: `SELECT 1 AS present FROM workspace_bots WHERE workspace_id = ? AND bot_id = ? LIMIT 1`,
|
|
values: [workspace.id, worker.id],
|
|
})
|
|
).payload?.[0] || null;
|
|
|
|
if (already) {
|
|
return `${worker.name} is already in ${workspace.name}.`;
|
|
}
|
|
|
|
await addBotToWorkspace({
|
|
user_id,
|
|
workspace_id: workspace.id,
|
|
bot_id: worker.id,
|
|
});
|
|
|
|
await pushBotCreated({ bot: worker });
|
|
|
|
return `${worker.name} joined ${workspace.name}.`;
|
|
},
|
|
};
|
|
}
|