Let crew managers edit a bot's workspace instructions where they work with it
A bot's instructions and memory for one workspace were only reachable
from the workspace's settings. The editor is now shared and also opens
from the conversation menu in that workspace ("Instructions here",
loaded on open through api/admin/workspaces/workspace-bot) and from the
workspace rows on the bot's settings page.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -70,7 +70,7 @@ export default function BotProfileModal({ bot }: Props) {
|
||||
<Span className="text-[13px] leading-[18px] text-ink-secondary">
|
||||
{bot.kind == "coordinator"
|
||||
? "The coordinator keeps its name. Give it a picture, or change its core instructions."
|
||||
: `${name}'s core instructions apply everywhere. What it does in one workspace is set on that workspace's page.`}
|
||||
: `${name}'s core instructions apply everywhere. What it does in one workspace is under Instructions here in the menu of its conversation there.`}
|
||||
</Span>
|
||||
</Stack>
|
||||
{!open ? null : system_prompt != undefined ? (
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import Modal from "@moduletrace/twui/elements/Modal";
|
||||
import Loading from "@moduletrace/twui/elements/Loading";
|
||||
import H2 from "@moduletrace/twui/layout/H2";
|
||||
import Span from "@moduletrace/twui/layout/Span";
|
||||
import Stack from "@moduletrace/twui/layout/Stack";
|
||||
import { NotebookPen } from "lucide-react";
|
||||
import type { BUN_SQLITE_COBBLE_WORKSPACES } from "@/db/types/db";
|
||||
import type { BotWithLastMessage } from "@/src/types";
|
||||
import WorkspaceBotForm from "@/src/components/general/workspace-bot-form";
|
||||
import useWorkspaceBotInstructions from "../(hooks)/use-workspace-bot-instructions";
|
||||
import HeaderMenuItem from "./header-menu-item";
|
||||
|
||||
type Props = {
|
||||
bot: BotWithLastMessage;
|
||||
workspace: BUN_SQLITE_COBBLE_WORKSPACES;
|
||||
on_open?: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* The header menu's row, in a workspace conversation, that opens what the
|
||||
* bot has for this workspace alone: its instructions here and its memory
|
||||
* here (crew managers). Both load when it opens, so it shows the bot's
|
||||
* own latest edits.
|
||||
*/
|
||||
export default function BotWorkspaceInstructionsModal({ bot, workspace, on_open }: Props) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const name = bot.name || "This bot";
|
||||
const place = workspace.name || "this workspace";
|
||||
const { instructions, error } = useWorkspaceBotInstructions({
|
||||
workspace_id: Number(workspace.id),
|
||||
bot_id: Number(bot.id),
|
||||
enabled: open,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (open) on_open?.();
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
target={
|
||||
<HeaderMenuItem
|
||||
icon={NotebookPen}
|
||||
title="Instructions here"
|
||||
description={`${name}'s instructions and memory in ${place}`}
|
||||
/>
|
||||
}
|
||||
targetWrapperProps={{ className: "w-full" }}
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
className="max-w-lg bg-paper p-6"
|
||||
>
|
||||
<Stack className="w-full gap-1! items-stretch">
|
||||
<H2 className="text-lg! leading-6! tracking-normal! font-bold text-ink">{`${name} in ${place}`}</H2>
|
||||
<Span className="text-[13px] leading-[18px] text-ink-secondary">
|
||||
{`On top of ${name}'s core instructions, which apply everywhere. These apply only in ${place}, and ${name} updates them itself as it learns how this workspace works.`}
|
||||
</Span>
|
||||
</Stack>
|
||||
{!open ? null : instructions ? (
|
||||
<WorkspaceBotForm
|
||||
workspace_id={Number(workspace.id)}
|
||||
bot_id={Number(bot.id)}
|
||||
bot_name={bot.name}
|
||||
system_prompt={instructions.system_prompt}
|
||||
memory={instructions.memory}
|
||||
onCancel={() => setOpen(false)}
|
||||
onSaved={() => setOpen(false)}
|
||||
/>
|
||||
) : error ? (
|
||||
<Span className="py-6 text-[13px] leading-[18px] text-ink-secondary">{error}</Span>
|
||||
) : (
|
||||
<Stack className="w-full py-10 items-center">
|
||||
<Loading />
|
||||
</Stack>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import BotTasksModal from "./bot-tasks-modal";
|
||||
import BotRoutinesModal from "./bot-routines-modal";
|
||||
import BotModelsModal from "./bot-models-modal";
|
||||
import BotAdminMenuItem from "./bot-admin-menu-item";
|
||||
import BotWorkspaceInstructionsModal from "./bot-workspace-instructions-modal";
|
||||
import HeaderMenuItem from "./header-menu-item";
|
||||
import NewSessionButton from "./new-session-button";
|
||||
import CopyChatMenuItem from "./copy-chat-menu-item";
|
||||
@@ -56,7 +57,8 @@ type Props = {
|
||||
|
||||
/**
|
||||
* The conversation header's menu: the sessions, a new session, copying
|
||||
* the session, the bot's computer, its models, in a workspace making it the admin there, its
|
||||
* the session, the bot's computer, its models, in a workspace its
|
||||
* instructions there and making it the admin there, its
|
||||
* settings and, while it works, stopping it. A
|
||||
* row that opens a modal closes the menu first, so the modal never sits
|
||||
* behind an open menu.
|
||||
@@ -77,6 +79,13 @@ export default function ConversationHeaderMenu({
|
||||
bot.kind == "coordinator"
|
||||
? isPassThroughUser({ user_types: pageProps?.user_types })
|
||||
: canManageCrew({ user_types: pageProps?.user_types });
|
||||
/**
|
||||
* A bot's instructions for one workspace, only there, for crew
|
||||
* managers (the coordinator's too: only the super admin sees it).
|
||||
*/
|
||||
const can_edit_here = Boolean(
|
||||
workspace?.id && canManageCrew({ user_types: pageProps?.user_types }),
|
||||
);
|
||||
/**
|
||||
* Admin is per workspace, so only in one, for a worker, and only for
|
||||
* those who hand out roles.
|
||||
@@ -161,6 +170,13 @@ export default function ConversationHeaderMenu({
|
||||
on_open={on_open}
|
||||
onSaved={on_model_saved}
|
||||
/>
|
||||
{can_edit_here && workspace?.id ? (
|
||||
<BotWorkspaceInstructionsModal
|
||||
bot={bot}
|
||||
workspace={workspace}
|
||||
on_open={on_open}
|
||||
/>
|
||||
) : null}
|
||||
{can_set_admin && workspace?.id ? (
|
||||
<BotAdminMenuItem
|
||||
bot_id={Number(bot.id)}
|
||||
|
||||
Reference in New Issue
Block a user