Give workspace computers to attached bots in their own chat
A computer linked to a workspace now shows in the composer (and is usable by tasks and replies) when chatting with any bot attached to that workspace, not only in the workspace conversation. Members see those computers through their assigned workers too, and assign_computer still describes direct grants only.
This commit is contained in:
@@ -8,20 +8,28 @@ type Params = {
|
||||
* workspace's, the default first, and nothing else.
|
||||
*/
|
||||
workspace_id?: number | string | null;
|
||||
/**
|
||||
* In its own chat, whether the computers of the workspaces it's
|
||||
* attached to count too (they do by default). The `assign_computer`
|
||||
* tool's view of direct access turns them off.
|
||||
*/
|
||||
include_workspace_computers?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Every computer a bot can use where it's working. In a workspace, the
|
||||
* workspace's computers (none linked: none at all), its default first. In
|
||||
* its own chat, the ones it was given directly (`bot_computers`); the
|
||||
* coordinator can use all of them. There the one it works on now
|
||||
* (`bots.computer_id`) comes first, else the main one, so `computers[0]`
|
||||
* is where its tasks run by default. The same for every user it works
|
||||
* for: callers check the user reaches the bot.
|
||||
* its own chat, the ones it was given directly (`bot_computers`) and those
|
||||
* of the workspaces it's attached to, since a workspace's computer is
|
||||
* every bit its own; the coordinator can use all of them. There the one it
|
||||
* works on now (`bots.computer_id`) comes first, else the main one, so
|
||||
* `computers[0]` is where its tasks run by default. The same for every
|
||||
* user it works for: callers check the user reaches the bot.
|
||||
*/
|
||||
export default async function grabBotComputers({
|
||||
bot_id,
|
||||
workspace_id,
|
||||
include_workspace_computers = true,
|
||||
}: Params): Promise<BUN_SQLITE_COBBLE_COMPUTERS[]> {
|
||||
if (workspace_id) {
|
||||
const res = await BunSQLite.sql<BUN_SQLITE_COBBLE_COMPUTERS>({
|
||||
@@ -39,15 +47,26 @@ export default async function grabBotComputers({
|
||||
return res.payload || [];
|
||||
}
|
||||
|
||||
const workspace_computers_sql = include_workspace_computers
|
||||
? `OR c.id IN (
|
||||
SELECT wc.computer_id FROM workspace_computers wc
|
||||
JOIN workspaces w ON w.id = wc.workspace_id AND w.archived = 0
|
||||
JOIN workspace_bots wb ON wb.workspace_id = w.id AND wb.bot_id = ?
|
||||
)`
|
||||
: "";
|
||||
|
||||
const res = await BunSQLite.sql<BUN_SQLITE_COBBLE_COMPUTERS>({
|
||||
sql: `SELECT c.* FROM computers c
|
||||
WHERE (
|
||||
(SELECT kind FROM bots WHERE id = ?) = 'coordinator'
|
||||
OR c.id IN (SELECT computer_id FROM bot_computers WHERE bot_id = ?)
|
||||
${workspace_computers_sql}
|
||||
)
|
||||
ORDER BY c.id = (SELECT computer_id FROM bots WHERE id = ?) DESC,
|
||||
c.kind = 'main' DESC, c.id ASC`,
|
||||
values: [bot_id, bot_id, bot_id],
|
||||
values: include_workspace_computers
|
||||
? [bot_id, bot_id, bot_id, bot_id]
|
||||
: [bot_id, bot_id, bot_id],
|
||||
});
|
||||
|
||||
return res.payload || [];
|
||||
|
||||
@@ -28,9 +28,10 @@ type Args = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Lets the coordinator give a crew member access to one of the user's
|
||||
* computers in its own chat (`bot_computers`), or take it away. In a
|
||||
* workspace, bots use the workspace's computers instead.
|
||||
* Lets the coordinator give a crew member direct access to one of the
|
||||
* user's computers (`bot_computers`), or take it away. The computers of
|
||||
* the workspaces a bot is attached to are its own too, in its own chat as
|
||||
* well as in the workspace.
|
||||
*/
|
||||
export default function assignComputerTool({
|
||||
user_id,
|
||||
@@ -76,7 +77,7 @@ export default function assignComputerTool({
|
||||
|
||||
await removeBotFromComputer({ user_id, bot_id: worker.id, computer_id: computer.id });
|
||||
|
||||
return `${worker.name} can't use ${ref} in its own chat any more. In a workspace it still uses the workspace's computers.`;
|
||||
return `${worker.name} can't use ${ref} directly any more. A workspace it's attached to may still give it.`;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -127,7 +127,10 @@ export default async function grabBotChatTools({
|
||||
await Promise.all(
|
||||
workers.map(async (worker) => [
|
||||
worker.id || 0,
|
||||
await grabBotComputers({ bot_id: worker.id || 0 }),
|
||||
await grabBotComputers({
|
||||
bot_id: worker.id || 0,
|
||||
include_workspace_computers: false,
|
||||
}),
|
||||
]),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -3,7 +3,8 @@ import type { CrewAccessParams, SqlCondition } from "./types";
|
||||
/**
|
||||
* The computers a user opens and sees: super admins and admins every one,
|
||||
* anyone else only those of the bots they chat with (the computers of
|
||||
* their workspaces, and those their assigned workers were given).
|
||||
* their workspaces, those their assigned workers were given, and those of
|
||||
* the workspaces their assigned workers are attached to).
|
||||
*/
|
||||
export default function computersSql({ role, user_id, alias = "c" }: CrewAccessParams): SqlCondition {
|
||||
if (role != "member") return { sql: `1`, values: [] };
|
||||
@@ -16,7 +17,13 @@ export default function computersSql({ role, user_id, alias = "c" }: CrewAccessP
|
||||
SELECT bc.computer_id FROM bot_computers bc
|
||||
JOIN bot_users bu ON bu.bot_id = bc.bot_id AND bu.user_id = ?
|
||||
JOIN bots b ON b.id = bc.bot_id AND b.kind != 'coordinator'
|
||||
UNION
|
||||
SELECT wc.computer_id FROM workspace_computers wc
|
||||
JOIN workspaces w ON w.id = wc.workspace_id AND w.archived = 0
|
||||
JOIN workspace_bots wb ON wb.workspace_id = w.id
|
||||
JOIN bot_users bu ON bu.bot_id = wb.bot_id AND bu.user_id = ?
|
||||
JOIN bots b ON b.id = wb.bot_id AND b.kind != 'coordinator'
|
||||
)`,
|
||||
values: [Number(user_id), Number(user_id)],
|
||||
values: [Number(user_id), Number(user_id), Number(user_id)],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ const db = new Database(":memory:");
|
||||
|
||||
beforeAll(() => {
|
||||
db.run(`CREATE TABLE bots (id INTEGER PRIMARY KEY, kind TEXT)`);
|
||||
db.run(`CREATE TABLE workspaces (id INTEGER PRIMARY KEY)`);
|
||||
db.run(`CREATE TABLE workspaces (id INTEGER PRIMARY KEY, archived INTEGER DEFAULT 0)`);
|
||||
db.run(`CREATE TABLE bot_users (bot_id INTEGER, user_id INTEGER)`);
|
||||
db.run(`CREATE TABLE workspace_users (workspace_id INTEGER, user_id INTEGER)`);
|
||||
db.run(`CREATE TABLE workspace_bots (workspace_id INTEGER, bot_id INTEGER)`);
|
||||
db.run(`INSERT INTO bots VALUES (1, 'coordinator'), (2, 'worker'), (3, 'worker')`);
|
||||
db.run(`INSERT INTO workspaces VALUES (10), (11)`);
|
||||
db.run(`INSERT INTO bot_users VALUES (2, 7), (1, 7)`);
|
||||
db.run(`INSERT INTO workspaces VALUES (10, 0), (11, 0)`);
|
||||
db.run(`INSERT INTO bot_users VALUES (2, 7), (1, 7), (3, 9)`);
|
||||
db.run(`INSERT INTO workspace_users VALUES (11, 7)`);
|
||||
db.run(`INSERT INTO workspace_bots VALUES (11, 3)`);
|
||||
db.run(`CREATE TABLE computers (id INTEGER PRIMARY KEY)`);
|
||||
@@ -46,6 +46,7 @@ describe("chatBotsSql", () => {
|
||||
test("a member only with workers assigned to them, even if the coordinator was", () => {
|
||||
expect(ids({ table: "bots", alias: "b", condition: chatBotsSql({ role: "member", user_id: 7 }) })).toEqual([2]);
|
||||
expect(ids({ table: "bots", alias: "b", condition: chatBotsSql({ role: "member", user_id: 8 }) })).toEqual([]);
|
||||
expect(ids({ table: "bots", alias: "b", condition: chatBotsSql({ role: "member", user_id: 9 }) })).toEqual([3]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,4 +73,8 @@ describe("computersSql", () => {
|
||||
expect(ids({ table: "computers", alias: "c", condition: computersSql({ role: "member", user_id: 7 }) })).toEqual([21, 22]);
|
||||
expect(ids({ table: "computers", alias: "c", condition: computersSql({ role: "member", user_id: 8 }) })).toEqual([]);
|
||||
});
|
||||
|
||||
test("a member sees the computers of the workspaces their assigned workers are in", () => {
|
||||
expect(ids({ table: "computers", alias: "c", condition: computersSql({ role: "member", user_id: 9 }) })).toEqual([21]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user