Add tasks: the crew's shared to-do list
Bots and workspaces each keep a list of work tracked until it's done, and the bots move it along themselves as they work. - tasks (one collection per bot or per workspace), task_notes (the progress log) and task_media (a deliverable or a reference file, its bytes a private media row served at /media/private/<id>) - statuses todo/doing/blocked/done/cancelled, with blocked_reason while only the user can unblock it - visibility as SQL in src/utils/task-access: a user's own bots and workspaces, a run's own list plus its workspaces, everything for the coordinator; every tool and endpoint resolves through it - list_tasks, create_task and update_task on every run, so a chat reply, a task and a routine all read the list, log progress and file what they produced - TasksNote on every run and TaskReminderNote in chat, so a greeting or a proposed next step brings pending work up in one measured line - tasks group on the workspace dashboard and a tasks modal in the conversation header, sharing one form, row and detail panel - a bot's or workspace's own chat uploads are read before the delete so none are stranded; bot files keep their folder Also corrects the README's RAM guidance and table alignment.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||
import type { BUN_SQLITE_COBBLE_TASKS, BunSQLiteTables } from "@/db/types/db";
|
||||
import { AppData } from "@/src/data/app-data";
|
||||
import type { TaskStatus } from "@/src/dict/task-dict";
|
||||
import type { TaskDetail } from "@/src/types";
|
||||
import AppError from "@/src/utils/app-error";
|
||||
import grabCrewRole from "../access/grab-crew-role";
|
||||
import grabTask from "./grab-task";
|
||||
import taskScopeValues from "./task-scope-values";
|
||||
|
||||
type Params = {
|
||||
/**
|
||||
* The user whose run or request creates it.
|
||||
*/
|
||||
user_id: number | string;
|
||||
bot_id?: number | string | null;
|
||||
workspace_id?: number | string | null;
|
||||
title: string;
|
||||
description?: string;
|
||||
status?: TaskStatus;
|
||||
/**
|
||||
* The bot creating it with its tool; none for a user's manual add.
|
||||
*/
|
||||
created_by_bot_id?: number | string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a task to a bot's own list or a workspace's shared one. A user adds
|
||||
* one to a bot they chat with or a workspace they're in; a bot's run adds
|
||||
* one to its own list or to a workspace it works in (its tool checks
|
||||
* that). Caps a collection at `TaskMaxPerScope` open and finished tasks.
|
||||
*/
|
||||
export default async function createTask({
|
||||
user_id,
|
||||
bot_id,
|
||||
workspace_id,
|
||||
title,
|
||||
description,
|
||||
status,
|
||||
created_by_bot_id,
|
||||
}: Params): Promise<TaskDetail> {
|
||||
const scope = taskScopeValues({ bot_id, workspace_id });
|
||||
const role = await grabCrewRole({ user_id });
|
||||
|
||||
if (!created_by_bot_id && role == "member") {
|
||||
throw new AppError(`Only an admin can add a task.`);
|
||||
}
|
||||
|
||||
const count = Number(
|
||||
(
|
||||
await BunSQLite.sql<{ n: number }>({
|
||||
sql: `SELECT COUNT(*) AS n FROM tasks WHERE ${
|
||||
scope.bot_id ? `bot_id = ?` : `workspace_id = ?`
|
||||
}`,
|
||||
values: [Number(scope.bot_id || scope.workspace_id)],
|
||||
})
|
||||
).payload?.[0]?.n || 0,
|
||||
);
|
||||
|
||||
if (count >= AppData.TaskMaxPerScope) {
|
||||
throw new AppError(`That list is full (${AppData.TaskMaxPerScope} tasks). Finish or delete one first.`);
|
||||
}
|
||||
|
||||
const res = await BunSQLite.insert<BUN_SQLITE_COBBLE_TASKS, (typeof BunSQLiteTables)[number]>({
|
||||
table: "tasks",
|
||||
data: [
|
||||
{
|
||||
bot_id: scope.bot_id || undefined,
|
||||
workspace_id: scope.workspace_id || undefined,
|
||||
title: title.trim().slice(0, AppData.TaskTitleMaxLength),
|
||||
description: description || undefined,
|
||||
status: status || "todo",
|
||||
origin: created_by_bot_id ? "bot" : "user",
|
||||
created_by_bot_id: created_by_bot_id ? Number(created_by_bot_id) : undefined,
|
||||
created_by_user_id: Number(user_id),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const task_id = res.singleRes?.id || res.postInsertReturn?.insertId;
|
||||
|
||||
if (!res.success || !task_id) {
|
||||
throw new Error(`Couldn't save the task: ${res.msg}`);
|
||||
}
|
||||
|
||||
return await grabTask({ user_id, task_id });
|
||||
}
|
||||
Reference in New Issue
Block a user