Let a delegated task choose the workspace it runs in
delegate_task had no workspace argument: a task handed over from the coordinator's own chat always ran in the worker's own chat, on that worker's memory, files and directly assigned computers alone, even when the work belonged to a workspace. The coordinator could not say where the work goes, and the prompt never said the two differ. - delegate_task takes an optional workspace_id: the worker runs the task in that workspace's context, with its own instructions and memory there, the project's files and the workspace's computers, and the result lands in its conversation in that workspace. - A worker missing from that workspace is added first (pushBotCreated) and the reply says so. - Handed over from inside a workspace the task always runs there; a different workspace_id is refused instead of ignored. - The coordinator prompt, CoordinatorReplyNote and the tool description now spell the distinction out.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import type { BUN_SQLITE_COBBLE_BOTS, BUN_SQLITE_COBBLE_WORKSPACES } from "@/db/types/db";
|
||||
import delegateTaskTool from "./delegate-task-tool";
|
||||
|
||||
const worker = { id: 5, name: "Researcher", role: "research", kind: "worker" } as BUN_SQLITE_COBBLE_BOTS;
|
||||
const workspace = { id: 3, name: "Launch", archived: 0 } as BUN_SQLITE_COBBLE_WORKSPACES;
|
||||
const signal = new AbortController().signal;
|
||||
|
||||
function coordinatorTool({
|
||||
workspace_id,
|
||||
workers = [worker],
|
||||
workspaces = [workspace],
|
||||
}: { workspace_id?: number; workers?: BUN_SQLITE_COBBLE_BOTS[]; workspaces?: BUN_SQLITE_COBBLE_WORKSPACES[] } = {}) {
|
||||
return delegateTaskTool({
|
||||
user_id: 1,
|
||||
coordinator_id: 1,
|
||||
session_id: 10,
|
||||
workspace_id: workspace_id ?? null,
|
||||
coordinator_name: "Coordinator",
|
||||
workers,
|
||||
workspaces,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The tool's own confines, kept to what needs no database: the argument it
|
||||
* accepts and the refusal that keeps a workspace hand-over in its
|
||||
* workspace. Every run that gets past those reaches the DB.
|
||||
*/
|
||||
describe("delegateTaskTool", () => {
|
||||
test("takes an optional workspace the task runs in", () => {
|
||||
const tool = coordinatorTool();
|
||||
|
||||
expect(tool.name).toBe("delegate_task");
|
||||
expect(tool.schema?.safeParse({ bot_id: 5, title: "Dig", instructions: "Read the docs." }).success).toBe(true);
|
||||
expect(
|
||||
tool.schema?.safeParse({ bot_id: 5, title: "Dig", instructions: "Read the docs.", workspace_id: 3 }).success,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test("names the workspaces it can hand work into", () => {
|
||||
expect(coordinatorTool().description).toContain("3: Launch");
|
||||
});
|
||||
|
||||
test("in a workspace, says the task runs there and offers no other", () => {
|
||||
const tool = coordinatorTool({ workspace_id: 3 });
|
||||
|
||||
expect(tool.description).toContain("runs there");
|
||||
expect(tool.schema?.safeParse({ bot_id: 5, title: "Dig", instructions: "x", workspace_id: 9 }).success).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("refuses to move a hand-over out of the workspace it came from", async () => {
|
||||
await expect(
|
||||
coordinatorTool({ workspace_id: 3 }).run({
|
||||
args: { bot_id: 5, title: "Dig", instructions: "x", workspace_id: 9 },
|
||||
signal,
|
||||
}),
|
||||
).rejects.toThrow(/runs in that workspace/);
|
||||
});
|
||||
|
||||
test("accepts the workspace it came from", async () => {
|
||||
/** Reaches the DB and fails there for a test id, never on the guard. */
|
||||
await expect(
|
||||
coordinatorTool({ workspace_id: 3 }).run({
|
||||
args: { bot_id: 5, title: "Dig", instructions: "x", workspace_id: 3 },
|
||||
signal,
|
||||
}),
|
||||
).rejects.not.toThrow(/runs in that workspace/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user