diff --git a/app/src/features/bots/BotDialog.tsx b/app/src/features/bots/BotDialog.tsx index 1b5153cc..b94e481a 100644 --- a/app/src/features/bots/BotDialog.tsx +++ b/app/src/features/bots/BotDialog.tsx @@ -3,6 +3,7 @@ import { type FormEvent, useState } from "react"; import { useT } from "../../i18n"; import { errorText } from "../../lib/api"; import { + type AgentKind, AVATAR_PALETTE, type Bot, type BotModel, @@ -17,6 +18,8 @@ import { BotAvatar } from "./BotAvatar"; import { ColorPicker } from "./ColorPicker"; const MODELS: BotModel[] = ["default", "fable", "opus", "sonnet", "haiku"]; +/** Stable, for a selector: a new array each time would render in a loop. */ +const CLAUDE_ONLY: AgentKind[] = ["claude"]; type Props = { onClose(): void } & ({ crewId: CrewId; bot?: undefined } | { bot: Bot }); @@ -34,6 +37,12 @@ export function BotDialog(props: Props) { const custom = color !== undefined && !(AVATAR_PALETTE as readonly string[]).includes(color); const [picking, setPicking] = useState(custom); const [model, setModel] = useState(editing?.model ?? "default"); + // One command prefix per line, for a bot whose agent cannot ask (spec 30). + const [commands, setCommands] = useState((editing?.allowedCommands ?? []).join("\n")); + // Which agent runs the bot is chosen once, when it is made (spec 30). + const agents = useApp((state) => state.system?.enabledAgents ?? CLAUDE_ONLY); + const [agent, setAgent] = useState("claude"); + const runsOn: AgentKind = editing?.agent ?? agent; const [error, setError] = useState(null); const [busy, setBusy] = useState(false); @@ -50,6 +59,10 @@ export function BotDialog(props: Props) { ...(role !== editing.role && { role }), ...(instructions !== editing.instructions && { instructions }), ...(color !== undefined && color !== editing.color && { color }), + ...(editing.agent !== "claude" && + commands !== editing.allowedCommands.join("\n") && { + allowedCommands: commands.split("\n"), + }), }); if (model !== editing.model) { // The bot restarts on it once nothing is in progress. @@ -62,7 +75,8 @@ export function BotDialog(props: Props) { role, instructions, ...(color !== undefined && { color }), - ...(model !== "default" && { model }), + ...(runsOn === "claude" && model !== "default" && { model }), + ...(runsOn !== "claude" && { agent: runsOn }), }); } putBot(bot); @@ -118,13 +132,40 @@ export function BotDialog(props: Props) { placeholder={t.bots.dialog.instructionsPlaceholder} hint={editing ? t.bots.dialog.instructionsHint : undefined} /> - setModel(event.target.value as BotModel)} - options={MODELS.map((value) => ({ value, label: t.chat.model.names[value] }))} - hint={t.chat.model.cost} - /> + {!editing && agents.length > 1 && ( +
+ setAgent(event.target.value as AgentKind)} + options={agents.map((value) => ({ value, label: t.bots.dialog.agent.names[value] }))} + /> + {agent !== "claude" && ( +

+ {t.bots.dialog.agent.experimental} +

+ )} +
+ )} + {editing && editing.agent !== "claude" && ( +