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,8 +1,16 @@
|
||||
import { z } from "zod";
|
||||
import { AppData } from "@/src/data/app-data";
|
||||
import { BotHues, type BotHue } from "@/src/dict/bot-dict";
|
||||
|
||||
/**
|
||||
* The workspace a conversation is in; left out (or null) for a bot's own
|
||||
* chat.
|
||||
*/
|
||||
const WorkspaceIdField = z.coerce.number().int().positive().nullish();
|
||||
|
||||
export const SendBotMessageRequestSchema = z.object({
|
||||
bot_id: z.coerce.number().int().positive("Pick a bot to message"),
|
||||
workspace_id: WorkspaceIdField,
|
||||
text: z.string().trim().max(4000, "Keep messages under 4000 characters").default(""),
|
||||
media_ids: z
|
||||
.array(z.coerce.number().int().positive())
|
||||
@@ -21,10 +29,61 @@ export type BotIdRequest = z.infer<typeof BotIdRequestSchema>;
|
||||
export const SetBotComputerRequestSchema = z.object({
|
||||
bot_id: z.coerce.number().int().positive("Pick a bot"),
|
||||
computer_id: z.coerce.number().int().positive("Pick a computer"),
|
||||
/**
|
||||
* In a workspace this switches the workspace's default computer.
|
||||
*/
|
||||
workspace_id: WorkspaceIdField,
|
||||
});
|
||||
|
||||
export type SetBotComputerRequest = z.infer<typeof SetBotComputerRequestSchema>;
|
||||
|
||||
export const BotSessionIdRequestSchema = z.object({
|
||||
session_id: z.coerce.number().int().positive("Pick a session"),
|
||||
});
|
||||
|
||||
export type BotSessionIdRequest = z.infer<typeof BotSessionIdRequestSchema>;
|
||||
|
||||
export const BotConversationRequestSchema = z.object({
|
||||
bot_id: z.coerce.number().int().positive("Pick a bot"),
|
||||
workspace_id: WorkspaceIdField,
|
||||
});
|
||||
|
||||
export type BotConversationRequest = z.infer<typeof BotConversationRequestSchema>;
|
||||
|
||||
export const ListBotSessionsRequestSchema = BotConversationRequestSchema.extend({
|
||||
query: z.string().trim().max(200).optional(),
|
||||
page: z.coerce.number().int().positive().optional(),
|
||||
});
|
||||
|
||||
export type ListBotSessionsRequest = z.infer<typeof ListBotSessionsRequestSchema>;
|
||||
|
||||
export const CreateBotRequestSchema = z.object({
|
||||
name: z.string().trim().min(1, "Give the bot a name").max(40, "Keep the name under 40 characters"),
|
||||
role: z.string().trim().max(120, "Keep the role to one line").default(""),
|
||||
hue: z.enum(BotHues.map((h) => h.value) as [BotHue, ...BotHue[]]),
|
||||
system_prompt: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "Tell the bot what it does")
|
||||
.max(AppData.PromptMaxLength),
|
||||
/**
|
||||
* Also put it in this workspace.
|
||||
*/
|
||||
workspace_id: WorkspaceIdField,
|
||||
});
|
||||
|
||||
export type CreateBotRequest = z.infer<typeof CreateBotRequestSchema>;
|
||||
|
||||
/**
|
||||
* The coordinator keeps its name and has no hue: only its instructions
|
||||
* change.
|
||||
*/
|
||||
export const UpdateBotRequestSchema = CreateBotRequestSchema.omit({ workspace_id: true }).extend({
|
||||
bot_id: z.coerce.number().int().positive("Pick a bot"),
|
||||
});
|
||||
|
||||
export type UpdateBotRequest = z.infer<typeof UpdateBotRequestSchema>;
|
||||
|
||||
export const UploadBotAttachmentRequestSchema = z.object({
|
||||
/**
|
||||
* The file as a base64 data URL.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const CreateComputerRequestSchema = z.object({
|
||||
name: z.string().trim().min(1, "Give the computer a name").max(60, "Keep the name under 60 characters"),
|
||||
description: z.string().trim().max(240, "Keep the description short").default(""),
|
||||
/**
|
||||
* Also link it to this workspace.
|
||||
*/
|
||||
workspace_id: z.coerce.number().int().positive().nullish(),
|
||||
});
|
||||
|
||||
export type CreateComputerRequest = z.infer<typeof CreateComputerRequestSchema>;
|
||||
|
||||
export const ComputerIdRequestSchema = z.object({
|
||||
computer_id: z.coerce.number().int().positive("Pick a computer"),
|
||||
});
|
||||
|
||||
export type ComputerIdRequest = z.infer<typeof ComputerIdRequestSchema>;
|
||||
@@ -67,6 +67,20 @@ export const SaveBotHarnessSettingsRequestSchema = z.object({
|
||||
.max(Harnesses.length),
|
||||
});
|
||||
|
||||
/**
|
||||
* A workspace's own model settings. `inherit` drops the workspace's
|
||||
* setting for that harness so each bot uses its own or the default again.
|
||||
*/
|
||||
export const SaveWorkspaceHarnessSettingsRequestSchema = SaveBotHarnessSettingsRequestSchema.omit({
|
||||
bot_id: true,
|
||||
}).extend({
|
||||
workspace_id: z.coerce.number().int().positive(),
|
||||
});
|
||||
|
||||
export type SaveWorkspaceHarnessSettingsRequest = z.infer<
|
||||
typeof SaveWorkspaceHarnessSettingsRequestSchema
|
||||
>;
|
||||
|
||||
export type SaveHarnessProviderRequest = z.infer<
|
||||
typeof SaveHarnessProviderRequestSchema
|
||||
>;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const ProfileImageTargets = ["bot", "workspace"] as const;
|
||||
|
||||
export type ProfileImageTarget = (typeof ProfileImageTargets)[number];
|
||||
|
||||
export const SetProfileImageRequestSchema = z.object({
|
||||
target: z.enum(ProfileImageTargets),
|
||||
id: z.coerce.number().int().positive(),
|
||||
/**
|
||||
* The picture as a base64 data URL; null removes it.
|
||||
*/
|
||||
data_url: z.string().startsWith("data:image/", "Pick an image").nullable(),
|
||||
});
|
||||
|
||||
export type SetProfileImageRequest = z.infer<typeof SetProfileImageRequestSchema>;
|
||||
@@ -0,0 +1,47 @@
|
||||
import { z } from "zod";
|
||||
import { AppData } from "@/src/data/app-data";
|
||||
|
||||
const WorkspaceId = z.coerce.number().int().positive("Pick a workspace");
|
||||
const Prompt = z.string().trim().max(AppData.PromptMaxLength, `Keep it under ${AppData.PromptMaxLength} characters`);
|
||||
|
||||
export const CreateWorkspaceRequestSchema = z.object({
|
||||
name: z.string().trim().min(1, "Give the workspace a name").max(60, "Keep the name under 60 characters"),
|
||||
description: z.string().trim().max(240, "Keep the description short").default(""),
|
||||
system_prompt: Prompt.default(""),
|
||||
});
|
||||
|
||||
export type CreateWorkspaceRequest = z.infer<typeof CreateWorkspaceRequestSchema>;
|
||||
|
||||
export const UpdateWorkspaceRequestSchema = CreateWorkspaceRequestSchema.extend({
|
||||
workspace_id: WorkspaceId,
|
||||
archived: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type UpdateWorkspaceRequest = z.infer<typeof UpdateWorkspaceRequestSchema>;
|
||||
|
||||
export const WorkspaceIdRequestSchema = z.object({
|
||||
workspace_id: WorkspaceId,
|
||||
});
|
||||
|
||||
export type WorkspaceIdRequest = z.infer<typeof WorkspaceIdRequestSchema>;
|
||||
|
||||
export const WorkspaceBotRequestSchema = z.object({
|
||||
workspace_id: WorkspaceId,
|
||||
bot_id: z.coerce.number().int().positive("Pick a bot"),
|
||||
});
|
||||
|
||||
export type WorkspaceBotRequest = z.infer<typeof WorkspaceBotRequestSchema>;
|
||||
|
||||
export const UpdateWorkspaceBotRequestSchema = WorkspaceBotRequestSchema.extend({
|
||||
system_prompt: Prompt.default(""),
|
||||
memory: Prompt.default(""),
|
||||
});
|
||||
|
||||
export type UpdateWorkspaceBotRequest = z.infer<typeof UpdateWorkspaceBotRequestSchema>;
|
||||
|
||||
export const WorkspaceComputerRequestSchema = z.object({
|
||||
workspace_id: WorkspaceId,
|
||||
computer_id: z.coerce.number().int().positive("Pick a computer"),
|
||||
});
|
||||
|
||||
export type WorkspaceComputerRequest = z.infer<typeof WorkspaceComputerRequestSchema>;
|
||||
Reference in New Issue
Block a user