Add workspaces, conversation sessions, app-managed computers and pictures
- Rail: Add icon with stacked form modals (bot, workspace, computer), coordinator, recent bots with "See all bots", Workspaces section, and a workspace mode listing only its crew - Workspaces: page for context, bots (per-workspace instructions and memory), computers (default, link, unlink), models and delete; conversations scoped per bot per workspace - Sessions: conversations split into searchable, reopenable sessions with carry-over summaries; sessions and new-session header icons - Computers: created and provisioned over the docker socket, home dir kept at DATA_DIR/computers/<id> after delete; super admins only - Models: workspace settings win over a bot's own, then the defaults - Pictures for bots and workspaces; bots editable from the header - Coordinator tools: update_workspace, set_bot_workspace_instructions Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
import type { BUN_SQLITE_COBBLE_BOTS } from "@/db/types/db";
|
||||
import { AppData } from "@/src/data/app-data";
|
||||
import { ChatReplyNote, CoordinatorReplyNote, CoordinatorSoloNote } from "@/src/data/harness-prompts";
|
||||
import {
|
||||
ChatReplyNote,
|
||||
CoordinatorReplyNote,
|
||||
CoordinatorSoloNote,
|
||||
WorkspaceLearningNote,
|
||||
} from "@/src/data/harness-prompts";
|
||||
import grabBotMessages from "@/src/functions/backend/db/bots/grab-bot-messages";
|
||||
import grabBotPrompt from "@/src/functions/backend/db/bots/grab-bot-prompt";
|
||||
import grabBotComputers from "@/src/functions/backend/db/computers/grab-bot-computers";
|
||||
@@ -8,6 +13,8 @@ import runTextLoop from "@/src/harness/text/run-text-loop";
|
||||
import grabBotChatTools from "@/src/harness/tools/bot/grab-bot-chat-tools";
|
||||
import botMessagesToHarness from "./bot-messages-to-harness";
|
||||
import composeComputersNote from "./compose-computers-note";
|
||||
import grabSessionCarryOver from "./grab-session-carry-over";
|
||||
import jobSessionId from "@/src/functions/backend/db/bots-queue/job-session-id";
|
||||
import loadAttachmentParts from "./load-attachment-parts";
|
||||
import withTakeOverRefs from "./with-take-over-refs";
|
||||
import type { BotJobContext, BotJobOutcome } from "./types";
|
||||
@@ -17,11 +24,14 @@ type Params = BotJobContext & {
|
||||
};
|
||||
|
||||
/**
|
||||
* Answers the user in chat: the bot reads the recent conversation (and
|
||||
* the files of the latest messages, `loadAttachmentParts`) and
|
||||
* replies, knowing its computers (`composeComputersNote`), with its chat tools (memory, instructions, start_task, and for
|
||||
* the coordinator delegate_task). Finishes silently when the last message
|
||||
* is already the bot's, i.e. an earlier reply answered everything.
|
||||
* Answers the user in chat: the bot reads the session's recent messages
|
||||
* (and the files of the latest ones, `loadAttachmentParts`) and replies,
|
||||
* knowing where it is (its workspace, if the session is in one), what
|
||||
* happened in the session before (`grabSessionCarryOver`) and its
|
||||
* computers (`composeComputersNote`), with its chat tools (memory,
|
||||
* instructions, start_task, and for the coordinator delegate_task).
|
||||
* Finishes silently when the last message is already the bot's, i.e. an
|
||||
* earlier reply answered everything.
|
||||
*/
|
||||
export default async function runBotReply({
|
||||
bot,
|
||||
@@ -29,8 +39,11 @@ export default async function runBotReply({
|
||||
signal,
|
||||
report,
|
||||
}: Params): Promise<BotJobOutcome> {
|
||||
const session_id = await jobSessionId({ job });
|
||||
const workspace_id = job.workspace_id || null;
|
||||
|
||||
const history = await grabBotMessages({
|
||||
bot_id: bot.id,
|
||||
session_id,
|
||||
limit: AppData.BotReplyHistoryMessages,
|
||||
});
|
||||
|
||||
@@ -38,8 +51,19 @@ export default async function runBotReply({
|
||||
return { result: "", silent: true };
|
||||
}
|
||||
|
||||
const prompt = await grabBotPrompt({ bot_id: bot.id, user_id: bot.user_id });
|
||||
const computers = await grabBotComputers({ bot_id: bot.id, user_id: bot.user_id });
|
||||
const prompt = await grabBotPrompt({ bot_id: bot.id, user_id: bot.user_id, workspace_id });
|
||||
const computers = await grabBotComputers({ bot_id: bot.id, user_id: bot.user_id, workspace_id });
|
||||
|
||||
/**
|
||||
* A summary that can't be written now (no model free) is left out
|
||||
* rather than holding up the reply.
|
||||
*/
|
||||
const carry_over = await grabSessionCarryOver({
|
||||
session_id,
|
||||
bot_id: bot.id,
|
||||
workspace_id,
|
||||
signal,
|
||||
}).catch(() => "");
|
||||
|
||||
const take_overs: string[] = [];
|
||||
|
||||
@@ -47,6 +71,8 @@ export default async function runBotReply({
|
||||
bot,
|
||||
user_id: bot.user_id,
|
||||
computers,
|
||||
session_id,
|
||||
workspace_id,
|
||||
message_id: job.message_id || undefined,
|
||||
onTakeOver: ({ ref }) => take_overs.push(ref),
|
||||
});
|
||||
@@ -64,8 +90,14 @@ export default async function runBotReply({
|
||||
const result = await runTextLoop({
|
||||
system: [
|
||||
prompt,
|
||||
carry_over,
|
||||
ChatReplyNote,
|
||||
composeComputersNote({ computers, is_coordinator: bot.kind == "coordinator" }),
|
||||
workspace_id ? WorkspaceLearningNote : "",
|
||||
composeComputersNote({
|
||||
computers,
|
||||
is_coordinator: bot.kind == "coordinator",
|
||||
in_workspace: Boolean(workspace_id),
|
||||
}),
|
||||
crew_note,
|
||||
`Now: ${new Date().toUTCString()}.`,
|
||||
]
|
||||
@@ -78,6 +110,7 @@ export default async function runBotReply({
|
||||
tools,
|
||||
max_steps: AppData.BotReplyMaxToolSteps,
|
||||
bot_id: bot.id,
|
||||
workspace_id,
|
||||
signal,
|
||||
onStep: report,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user