import { Chat, UIMessage, useChat, UseChatHelpers } from '@ai-sdk/react'; import { ChatInit, DynamicToolUIPart, HttpChatTransportInitOptions, ToolUIPart } from 'ai'; import { Component, Editor } from 'grapesjs'; import { StudioLayoutComponentsConfig } from '../types'; import { LicenseCheckResult } from '../utils'; import { ToolStatusProgressMap } from './clientToolsProcessors'; import { AiChatLayoutComponentsRegistryEntries } from './components/index'; import { AiChatOptions as AiChatOptionsSchema, CommonComponentPropsSchema } from './typesSchema'; /** * ChatMessage is a direct alias of AI SDK's UIMessage */ export type ChatMessage = UIMessage; /** * Built-in tool names that can be customized */ export declare enum AiChatToolName { ADD_NEW_COMPONENT = "addNewComponent", EDIT_COMPONENT = "editComponent", REMOVE_COMPONENT = "removeComponent", MOVE_COMPONENT = "moveComponent", ADD_NEW_PAGE = "addNewPage", ADD_NEW_PROJECT_PAGE = "addNewProjectPage", GET_PAGE_CONTENT = "getPageContent", LIST_PAGES = "listPages", FETCH_WEBSITE = "fetchWebsite", GENERATE_IMAGE = "generateImage", RUN_COMMAND = "runCommand" } export declare enum ChatToolAgentCode { ADD_COMPONENT_CODE = "addComponentCode", EDIT_COMPONENT_CODE = "editComponentCode", ADD_PAGE_CODE = "addPageCode", ADD_PROJECT_PAGE_CODE = "addProjectPageCode" } export declare enum ToolBuiltInCommands { SHOW_CODE = "showCode", IMPORT_CODE = "importCode", PAGE_SETTINGS = "pageSettings", PREVIEW = "preview", PUBLISH = "publish" } export declare enum AiChatCommands { getChatManager = "aiChat:getChatManager", getChatState = "aiChat:getChatState", getChatApi = "aiChat:getChatApi" } export interface ToolGenerateImageInput extends Record { prompt: string; images?: string[]; n?: number; size?: string; aspectRatio?: string; } export interface AiChatToolsArguments { [AiChatToolName.ADD_NEW_COMPONENT]: { name: string; plan: string; componentId: string; position: 'before' | 'beforeInside' | 'afterInside' | 'after'; imageUrls: string[]; }; [AiChatToolName.EDIT_COMPONENT]: { plan: string; imageUrls: string[]; }; [AiChatToolName.REMOVE_COMPONENT]: { componentId: string; }; [AiChatToolName.MOVE_COMPONENT]: { sourceId: string; targetId: string; targetIndex: number; }; [AiChatToolName.GET_PAGE_CONTENT]: { pageId: string; }; [AiChatToolName.ADD_NEW_PAGE]: { name: string; plan: string; imageUrls: string[]; }; [AiChatToolName.ADD_NEW_PROJECT_PAGE]: { name: string; plan: string; imageUrls: string[]; }; [AiChatToolName.RUN_COMMAND]: { commandId: ToolBuiltInCommands; }; [AiChatToolName.LIST_PAGES]: Record; [AiChatToolName.FETCH_WEBSITE]: { url: string; name: string; }; [AiChatToolName.GENERATE_IMAGE]: ToolGenerateImageInput; } export interface ProjectContext { /** * Selected page information */ selectedPage?: { id: string; name: string; content?: string; }; /** * Last selected component information */ selectedComponent?: { id: string; content: string; }; /** * Selected components */ selectedComponents: { id: string; content: string; }[]; /** * Project type (web, email, etc.) */ projectType: string; /** * Global styles from the editor */ globalStyles: string; /** * Device configurations */ devices: { name: string; width?: string | number; widthMedia?: string | number; }[]; /** * Available pages in the project */ availablePages: { id: string; name: string; }[]; /** * Installed plugins information */ installedPlugins: { id: string; name?: string; instructions?: string; description?: string; }[]; /** * Is the project an email. */ isEmail: boolean; /** * Indicates if the project is empty. */ isNewProject: boolean; /** * Image URLs associated with the project */ imageUrls: string[]; } export interface ChatRequestBody { id: string; trigger: string; messages: UIMessage[]; projectContext: ProjectContext; userPrompt: string; [key: string]: unknown; } export interface ChatContext extends Pick, 'id' | 'setMessages' | 'messages' | 'sendMessage' | 'status' | 'stop' | 'addToolApprovalResponse' | 'addToolOutput' | 'clearError' | 'error'>, Pick { setError: (error: Error | string | undefined) => void; } export interface AiChatMessageLayoutProps { editor: Editor; chatContext: ChatContext; message: UIMessage; } export interface AiChatMessagePartLayoutProps extends AiChatMessageLayoutProps { part: ChatMessage['parts'][0]; partIndex: number; } export interface AiChatMessageToolDetailLayoutProps extends AiChatMessagePartLayoutProps { part: ToolUIPart | DynamicToolUIPart; toolName: string; isProcessing: boolean; isCompleted?: boolean; input?: unknown; output?: unknown; } export interface AiChatToolData = Record> { type: 'data-tool-status'; id: string; data: { name: string; input: TInput; status: 'in-progress' | 'streaming' | 'done' | 'complete' | 'error'; content?: string; error?: string; metadata?: Record; }; } export interface AiChatClientToolOnDataProps = Record> { editor: Editor; chatApi: ChatApi; toolStatus: AiChatToolData; toolStatusProgress: ToolStatusProgressMap; } export interface CommandLabelProps { isExecuted: boolean; } type CommandToolResult = string | Record | void; export interface CommandToolClientDefinition { label?: (props: CommandLabelProps) => StudioLayoutComponentsConfig | undefined | void; execute?: (props: { editor: Editor; input: AiChatToolsArguments[AiChatToolName.RUN_COMMAND]; context: AiChatToolContext; }) => Promise | CommandToolResult; } export type CommandToolClientDefinitions = Partial>; export interface CreateCommandToolOptions { skipDefault?: boolean; commands?: CommandToolClientDefinitions; } /** * Client-side tool definition */ export interface AiChatClientTool = any> { /** * Execute the tool on the client side */ execute?: (input: TInput, context: AiChatToolContext) => Promise>; /** * Custom label for tool in the message. */ layoutToolLabel?: (props: AiChatMessageToolDetailLayoutProps) => StudioLayoutComponentsConfig | undefined | void; /** * Callback on incoming status data for this tool. */ onData?: (props: AiChatClientToolOnDataProps) => void; /** * Custom layout for tool in the message. */ layoutToolResult?: (props: AiChatMessageToolDetailLayoutProps) => StudioLayoutComponentsConfig | undefined | void; } /** * Context passed to client-side tools */ export interface AiChatToolContext { editor: Editor; messages: UIMessage[]; toolCallId: string; lastUserMessage?: UIMessage; abortController: AbortController; } /** * Default tools type */ export type AiChatDefaultToolName = AiChatToolName.REMOVE_COMPONENT | AiChatToolName.MOVE_COMPONENT | AiChatToolName.GET_PAGE_CONTENT | AiChatToolName.LIST_PAGES | AiChatToolName.GENERATE_IMAGE | AiChatToolName.RUN_COMMAND; export type AiChatDefaultTools = Record; /** * Custom tools type */ export type AiChatTools = Record; /** * Tools function to customize or extend default tools */ export type AiChatToolsFn = (props: { defaultTools: AiChatDefaultTools; editor: Editor; createCommandTool: (options?: CreateCommandToolOptions) => AiChatClientTool; }) => AiChatTools; /** * Props for custom message component */ export interface AiChatMessageProps { editor: Editor; message: UIMessage; isStreaming?: boolean; } export interface AiChatSuggestion { /** * Unique identifier for the suggestion. Used as i18n key suffix. */ id: string; /** * Label to display if i18n key is not found. */ label?: string; /** * Prompt to send when clicked. If not provided, uses the resolved label. */ prompt?: string; } /** * Props for custom empty state component */ export interface AiChatEmptyStateProps { editor: Editor; onSuggestionClick?: (suggestion: string) => void; } /** * Context passed to layout component customizers */ export interface LayoutComponentContext { editor: Editor; props: Omit; } type CustomLayoutComponentPropsFn = (props: LayoutComponentContext) => Partial>; /** * Customizable layout components * @example * layoutComponents: { * aiChatInput: ({ editor, props }) => ({ * ...props, * maxImages: 3, * }) * } */ export interface AiChatLayoutComponents { /** * Custom aiChatInput component props */ aiChatInput?: CustomLayoutComponentPropsFn; /** * Custom aiChatMessage component props */ aiChatMessage?: CustomLayoutComponentPropsFn; /** * Custom aiChatLoadingState component props */ aiChatLoadingState?: CustomLayoutComponentPropsFn; /** * Custom aiChatHeader component props */ aiChatHeader?: CustomLayoutComponentPropsFn; /** * Custom aiChatError component props */ aiChatError?: CustomLayoutComponentPropsFn; /** * Custom aiChatEmptyState component props */ aiChatEmptyState?: CustomLayoutComponentPropsFn; } export type ChatOptions = Partial[0], 'api' | 'transport'>>; /** * Uploaded asset information */ export interface UploadedAsset { id: string; src: string; name: string; mimeType: string; size: number; type?: string; } export interface CommonComponentProps extends CommonComponentPropsSchema { editor: Editor; chatContext: ChatContext; } /** * AI Chat plugin options */ export interface AiChatOptions extends Omit { /** * Custom endpoint for the chat API */ chatApi?: string | (() => string); /** * Customize or extend the default client-side tools * @example * tools: ({ defaultTools, editor }) => ({ * ...defaultTools, * getUserLocation: { * async execute() { * const location = await getLocationViaBrowserAPI(); * return `User location: ${location.city}`; * } * } * }) */ tools?: AiChatToolsFn; /** * Callback when a client tool call is made */ onTool?: ChatInit['onToolCall']; /** * Customize UI layout component props * layoutComponents: { * aiChatInput: () => ({ * maxImages: 3, * }), * } */ layoutComponents?: AiChatLayoutComponents; /** * Initial messages or async function to load messages * @example * // Dynamic loading * messages: async () => { * return await loadFromDatabase(); * } */ messages?: UIMessage[] | ((props: { editor: Editor; }) => Promise); /** * Callback when messages are updated (for persistence) * @example * onMessagesUpdate: async ({ messages }) => { * await saveToDatabase(messages); * } */ onMessagesUpdate?: (props: { messages: UIMessage[]; editor: Editor; }) => void | Promise; /** * Request body for API calls (merged with default body) */ body?: Record | ((props: { editor: Editor; body: ChatRequestBody; messages: UIMessage[]; }) => Record); /** * Additional chat options. * Refer to https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat * @example * chatOptions: { * onData: data => console.log('onData:', data), * onError: error => console.log('onError:', error), * onFinish: result => console.log('onFinish:', result) * } */ chatOptions?: Partial>; /** * Default transport options for chat API calls */ defaultTransportOptions?: Partial, 'prepareSendMessagesRequest'>>; /** * Function to get the access token * @example * getAccessToken: async () => { * const response = await fetch('/api/access-tokens'); * const result = await response.json(); * return result; * } */ getAccessToken?: () => Promise; } export interface AccessTokenData { accessToken: string; expiresAt?: string; } export interface AccessTokenStore { accessToken: string; timeout?: NodeJS.Timeout; license?: LicenseCheckResult; getAccessToken?: () => Promise; } export interface ToolDataAddComponentCommon { name: typeof ChatToolAgentCode.ADD_COMPONENT_CODE; input: AiChatToolsArguments[AiChatToolName.ADD_NEW_COMPONENT]; content: string; } export interface ToolDataAddComponentStreaming extends ToolDataAddComponentCommon { status: 'in-progress' | 'streaming'; } export interface ToolDataAddComponentDone extends ToolDataAddComponentCommon { status: 'done'; } export interface ToolDataAddComponentError extends ToolDataAddComponentCommon { status: 'error'; error: string; } export interface ToolDataAddComponent { type: 'data-tool-status'; id: string; data: ToolDataAddComponentStreaming | ToolDataAddComponentDone | ToolDataAddComponentError; } export interface ToolDataEditComponentCommon { name: typeof ChatToolAgentCode.EDIT_COMPONENT_CODE; input: AiChatToolsArguments[AiChatToolName.EDIT_COMPONENT]; content: string; } export interface ToolDataEditComponentStreaming extends ToolDataEditComponentCommon { status: 'in-progress' | 'streaming'; } export interface ToolDataEditComponentDone extends ToolDataEditComponentCommon { status: 'done'; } export interface ToolDataEditComponentError extends ToolDataEditComponentCommon { status: 'error'; error: string; } export interface ToolDataEditComponent { type: 'data-tool-status'; id: string; data: ToolDataEditComponentStreaming | ToolDataEditComponentDone | ToolDataEditComponentError; } export interface ToolDataAddPageCommon { name: typeof ChatToolAgentCode.ADD_PAGE_CODE; input: AiChatToolsArguments[AiChatToolName.ADD_NEW_PAGE]; content: string; } export interface ToolDataAddPageStreaming extends ToolDataAddPageCommon { status: 'in-progress' | 'streaming'; } export interface ToolDataAddPageDone extends ToolDataAddPageCommon { status: 'done'; } export interface ToolDataAddPageError extends ToolDataAddPageCommon { status: 'error'; error: string; } export interface ToolDataAddPage { type: 'data-tool-status'; id: string; data: ToolDataAddPageStreaming | ToolDataAddPageDone | ToolDataAddPageError; } export interface ToolDataAddProjectPageCommon { name: typeof ChatToolAgentCode.ADD_PROJECT_PAGE_CODE; input: AiChatToolsArguments[AiChatToolName.ADD_NEW_PROJECT_PAGE]; content: string; } export interface ToolDataAddProjectPageStreaming extends ToolDataAddProjectPageCommon { status: 'in-progress' | 'streaming'; } export interface ToolDataAddProjectPageDone extends ToolDataAddProjectPageCommon { status: 'done'; } export interface ToolDataAddProjectPageError extends ToolDataAddProjectPageCommon { status: 'error'; error: string; } export interface ToolDataAddProjectPage { type: 'data-tool-status'; id: string; data: ToolDataAddProjectPageStreaming | ToolDataAddProjectPageDone | ToolDataAddProjectPageError; } export type ToolDataTypes = ToolDataAddComponent | ToolDataEditComponent | ToolDataAddPage | ToolDataAddProjectPage; export interface ChatApi { readonly messages: UIMessage[]; readonly lastMessage: UIMessage | undefined; readonly status: Chat['status']; readonly error: Error | undefined; sendMessage: Chat['sendMessage']; setMessages: (messages: UIMessage[]) => void; clearError: () => void; stop: () => Promise; setError: (error: Error | string) => void; } export interface ChatState { chat: Chat; chatApi: ChatApi; isMessagesLoaded: boolean; toolStatusProgress: ToolStatusProgressMap; toolAbortControllers: Set; contextComponents: Set; onUpdate: (listener: () => void) => () => void; emitUpdate: () => void; } export {};