import type { LanguageModelUsage, UIMessage } from "ai"; import { z } from "zod"; import { AllowedMCPServerZodSchema } from "./mcp"; import { UserPreferences } from "./user"; import { tag } from "lib/tag"; export type ChatMetadata = { usage?: LanguageModelUsage; chatModel?: ChatModel; toolChoice?: "auto" | "none" | "manual"; toolCount?: number; agentId?: string; }; export type ChatModel = { provider: string; model: string; }; export const ChatAttachmentSchema = z.object({ type: z.enum(["file", "source-url"]), url: z.string(), mediaType: z.string().optional(), filename: z.string().optional(), }); export type ChatAttachment = z.infer; export type ChatThread = { id: string; title: string; userId: string; createdAt: Date; }; export type ChatMessage = { id: string; threadId: string; role: UIMessage["role"]; parts: UIMessage["parts"]; metadata?: ChatMetadata; createdAt: Date; }; export const ChatMentionSchema = z.discriminatedUnion("type", [ z.object({ type: z.literal("mcpTool"), name: z.string(), description: z.string().optional(), serverName: z.string().optional(), serverId: z.string(), }), z.object({ type: z.literal("defaultTool"), name: z.string(), label: z.string(), description: z.string().optional(), }), z.object({ type: z.literal("mcpServer"), name: z.string(), description: z.string().optional(), toolCount: z.number().optional(), serverId: z.string(), }), z.object({ type: z.literal("workflow"), name: z.string(), description: z.string().nullish(), workflowId: z.string(), icon: z .object({ type: z.literal("emoji"), value: z.string(), style: z.record(z.string(), z.string()).optional(), }) .nullish(), }), z.object({ type: z.literal("agent"), name: z.string(), description: z.string().nullish(), agentId: z.string(), icon: z .object({ type: z.literal("emoji"), value: z.string(), style: z.record(z.string(), z.string()).optional(), }) .nullish(), }), ]); export type ChatMention = z.infer; export const chatApiSchemaRequestBodySchema = z.object({ id: z.string(), message: z.any() as z.ZodType, chatModel: z .object({ provider: z.string(), model: z.string(), }) .optional(), toolChoice: z.enum(["auto", "none", "manual"]), mentions: z.array(ChatMentionSchema).optional(), imageTool: z.object({ model: z.string().optional() }).optional(), allowedMcpServers: z.record(z.string(), AllowedMCPServerZodSchema).optional(), allowedAppDefaultToolkit: z.array(z.string()).optional(), attachments: z.array(ChatAttachmentSchema).optional(), }); export type ChatApiSchemaRequestBody = z.infer< typeof chatApiSchemaRequestBodySchema >; export type ChatRepository = { insertThread(thread: Omit): Promise; selectThread(id: string): Promise; deleteChatMessage(id: string): Promise; selectThreadDetails(id: string): Promise< | (ChatThread & { messages: ChatMessage[]; userPreferences?: UserPreferences; }) | null >; selectMessagesByThreadId(threadId: string): Promise; selectThreadsByUserId(userId: string): Promise< (ChatThread & { lastMessageAt: number; })[] >; updateThread( id: string, thread: Partial>, ): Promise; deleteThread(id: string): Promise; upsertThread( thread: PartialBy, "userId">, ): Promise; insertMessage(message: Omit): Promise; upsertMessage(message: Omit): Promise; deleteMessagesByChatIdAfterTimestamp(messageId: string): Promise; deleteAllThreads(userId: string): Promise; deleteUnarchivedThreads(userId: string): Promise; checkAccess(id: string, userId: string): Promise; insertMessages( messages: PartialBy[], ): Promise; }; export const ManualToolConfirmTag = tag<{ confirm: boolean; }>("manual-tool-confirm");