diff --git a/.changeset/orange-fans-glow.md b/.changeset/orange-fans-glow.md new file mode 100644 index 000000000..74de500e1 --- /dev/null +++ b/.changeset/orange-fans-glow.md @@ -0,0 +1,5 @@ +--- +"@assistant-ui/react": patch +--- + +feat: Composer API Docs diff --git a/apps/www/components/docs/ParametersTable.tsx b/apps/www/components/docs/ParametersTable.tsx index d40780906..c4e6168ce 100644 --- a/apps/www/components/docs/ParametersTable.tsx +++ b/apps/www/components/docs/ParametersTable.tsx @@ -98,7 +98,7 @@ const ParametersBox: FC = ({ type, parameters }) => { ); }; -type ParametersTableProps = { +export type ParametersTableProps = { type?: string; parameters: Array; }; diff --git a/apps/www/components/docs/parameters/context.tsx b/apps/www/components/docs/parameters/context.tsx index 56696078c..ebd38e91f 100644 --- a/apps/www/components/docs/parameters/context.tsx +++ b/apps/www/components/docs/parameters/context.tsx @@ -1,125 +1,366 @@ -import { ParametersTable } from "@/components/docs"; +import { ParametersTableProps } from "../ParametersTable"; -export const AssistantContextValue = () => { - return ( - ModelConfig", + description: "Gets the current model config.", + required: true, + children: [ { - name: "useModelConfig", - type: "ReadonlyStore", - required: true, - description: - "Configuration of the model (system prompt, tools, etc.)", - children: [ + type: "ModelConfig", + parameters: [ { - type: "ModelConfigState", - parameters: [ + name: "system", + type: "string", + description: "The system prompt.", + }, + { + name: "tools", + type: "Record>", + description: "The tools available to the model.", + children: [ { - name: "getModelConfig", - type: "() => ModelConfig", - description: "Gets the current model config.", - required: true, - children: [ + type: "Tool", + parameters: [ + { + name: "description", + type: "string", + description: "The tool description.", + }, + { + name: "parameters", + type: "z.ZodType", + description: "The tool parameters.", + }, { - type: "ModelConfig", - parameters: [ - { - name: "system", - type: "string", - description: "The system prompt.", - }, - { - name: "tools", - type: "Record>", - description: "The tools available to the model.", - children: [ - { - type: "Tool", - parameters: [ - { - name: "description", - type: "string", - description: "The tool description.", - }, - { - name: "parameters", - type: "z.ZodType", - description: "The tool parameters.", - }, - { - name: "execute", - type: "(args: TArgs) => Promise", - description: "The tool execution function.", - }, - ], - }, - ], - }, - ], + name: "execute", + type: "(args: TArgs) => Promise", + description: "The tool execution function.", }, ], }, - { - name: "registerModelConfigProvider", - type: "(provider: () => ModelConfig) => Unsubscribe", - description: - "Registers a model config provider to update the model config.", - required: true, - }, ], }, ], }, + ], + }, + { + name: "registerModelConfigProvider", + type: "(provider: () => ModelConfig) => Unsubscribe", + description: + "Registers a model config provider to update the model config.", + required: true, + }, + ], +}; + +export const AssistantToolUIsState: ParametersTableProps = { + type: "AssistantToolUIsState", + parameters: [ + { + name: "getToolUI", + type: "(toolName: string) => ToolCallContentPartProps", + description: "Gets the current tool UI for a given tool name.", + required: true, + children: [ { - name: "useToolUIs", - type: "ReadonlyStore", - required: true, - description: "Tool UIs to render on tool calls.", - children: [ + type: "ToolCallContentPartProps", + parameters: [ { - type: "ToolUIsState", - parameters: [ - { - name: "getToolUI", - type: "(toolName: string) => ToolCallContentPartProps", - description: - "Gets the current tool UI for a given tool name.", - required: true, - children: [ - { - type: "ToolCallContentPartProps", - parameters: [ - { - name: "part", - type: "ToolCallContentPart", - description: "The tool call content part.", - }, - { - name: "status", - type: "'in_progress' | 'done' | 'error'", - description: "The tool call status.", - }, - { - name: "addResult", - type: "(result: TResult) => void", - description: "Adds a result to the tool call.", - }, - ], - }, - ], - }, - { - name: "setToolUI", - type: "(toolName: string, render: ToolCallContentPartComponent) => Unsubscribe", - description: "Sets the tool UI.", - required: true, - }, - ], + name: "part", + type: "ToolCallContentPart", + description: "The tool call content part.", + }, + { + name: "status", + type: "'in_progress' | 'done' | 'error'", + description: "The tool call status.", + }, + { + name: "addResult", + type: "(result: TResult) => void", + description: "Adds a result to the tool call.", }, ], }, - ]} - /> - ); + ], + }, + { + name: "setToolUI", + type: "(toolName: string, render: ToolCallContentPartComponent) => Unsubscribe", + description: "Sets the tool UI.", + required: true, + }, + ], +}; + +export const AssistantContextValue: ParametersTableProps = { + type: "AssistantContextValue", + parameters: [ + { + name: "useModelConfig", + type: "ReadonlyStore", + required: true, + description: "Configuration of the model (system prompt, tools, etc.)", + }, + { + name: "useToolUIs", + type: "ReadonlyStore", + required: true, + description: "Tool UIs to render on tool calls.", + children: [], + }, + ], +}; + +export const ThreadState: ParametersTableProps = { + type: "ThreadState", + parameters: [ + { + name: "messages", + type: "readonly ThreadMessage[]", + required: true, + description: "The messages in the thread.", + }, + { + name: "isRunning", + type: "boolean", + required: true, + description: "Whether the thread is running.", + }, + ], +}; + +export const ThreadActionsState: ParametersTableProps = { + type: "ThreadActionsState", + parameters: [ + { + name: "getBranches", + type: "(messageId: string) => readonly string[]", + required: true, + description: "A function to get the branches for a message.", + }, + { + name: "switchToBranch", + type: "(branchId: string) => void", + required: true, + description: "A function to switch to a branch.", + }, + { + name: "append", + type: "(message: AppendMessage) => void", + required: true, + description: "A function to append a message to the thread.", + }, + { + name: "startRun", + type: "(parentId: string | null) => void", + required: true, + description: "A function to start a run.", + }, + { + name: "cancelRun", + type: "() => void", + required: true, + description: "A function to cancel a run.", + }, + { + name: "addToolResult", + type: "(toolCallId: string, result: any) => void", + required: true, + description: "A function to add a tool result.", + }, + ], +}; + +export const BaseComposerState: ParametersTableProps = { + type: "BaseComposerState", + parameters: [ + { + name: "value", + type: "string", + required: true, + description: "The current value of the composer.", + }, + { + name: "setValue", + type: "(value: string) => void", + required: true, + description: "A function to set the value of the composer.", + }, + ], +}; + +export const ComposerState: ParametersTableProps = { + type: "ComposerState", + parameters: [ + ...BaseComposerState.parameters, + { + name: "isEditing", + type: "true", + required: true, + description: "Whether the composer is in edit mode.", + }, + { + name: "send", + type: "() => void", + required: true, + description: "A function to send the message.", + }, + { + name: "cancel", + type: "() => boolean", + required: true, + description: "A function to cancel the run. Returns true if the run was canceled.", + }, + ], +}; + +export const EditComposerState: ParametersTableProps = { + type: "EditComposerState", + parameters: [ + ...BaseComposerState.parameters, + { + name: "isEditing", + type: "boolean", + required: true, + description: "Whether the composer is in edit mode.", + }, + { + name: "edit", + type: "() => void", + required: true, + description: "A function to enter edit mode.", + }, + { + name: "send", + type: "() => void", + required: true, + description: "A function to send the message.", + }, + { + name: "cancel", + type: "() => boolean", + required: true, + description: "A function to cancel the edit mode. Always returns true.", + }, + ], +}; + +export const ThreadViewportState: ParametersTableProps = { + type: "ThreadViewportState", + parameters: [ + { + name: "isAtBottom", + type: "boolean", + required: true, + description: "Whether the thread is at the bottom.", + }, + { + name: "scrollToBottom", + type: "() => void", + required: true, + description: "A function to scroll to the bottom.", + }, + { + name: "onScrollToBottom", + type: "(callback: () => void) => Unsubscribe", + required: true, + description: "A function to subscribe to scroll to bottom events.", + }, + ], +}; + +export const ContentPartState: ParametersTableProps = { + type: "ContentPartState", + parameters: [ + { + name: "part", + type: "Readonly", + required: true, + description: "The current content part.", + }, + { + name: "status", + type: "'done' | 'in_progress' | 'error'", + required: true, + description: "The current content part status.", + }, + ], +}; + +export const MessageState: ParametersTableProps = { + type: "MessageState", + parameters: [ + { + name: "message", + type: "Readonly", + required: true, + description: "The current message.", + }, + { + name: "parentId", + type: "string | null", + required: true, + description: "The parent message id.", + }, + { + name: "branches", + type: "readonly string[]", + required: true, + description: "The branches for the message.", + }, + { + name: "isLast", + type: "boolean", + required: true, + description: "Whether the message is the last in the thread.", + }, + ], +}; + +export const MessageUtilsState: ParametersTableProps = { + type: "MessageUtilsState", + parameters: [ + { + name: "inProgressIndicator", + type: "ReactNode | null", + required: true, + description: "The in progress indicator to render.", + }, + { + name: "setInProgressIndicator", + type: "(value: ReactNode | null) => void", + required: true, + description: "A function to set the in progress indicator.", + }, + { + name: "isCopied", + type: "boolean", + required: true, + description: "Whether the message is copied.", + }, + { + name: "setIsCopied", + type: "(value: boolean) => void", + required: true, + description: "A function to set the is copied.", + }, + { + name: "isHovering", + type: "boolean", + required: true, + description: "Whether the message is being hovered.", + }, + { + name: "setIsHovering", + type: "(value: boolean) => void", + required: true, + description: "A function to set the is hovering.", + }, + ], }; diff --git a/apps/www/pages/reference/context.mdx b/apps/www/pages/reference/context.mdx index 0d703b835..855adf622 100644 --- a/apps/www/pages/reference/context.mdx +++ b/apps/www/pages/reference/context.mdx @@ -12,7 +12,20 @@ The context is split into four hierarchies: - **Content Part Context**: Provides access to the content part state. -import { AssistantContextValue } from "@/components/docs/parameters/context"; +import { ParametersTable } from "@/components/docs"; +import { + AssistantContextValue, + AssistantModelConfigState, + AssistantToolUIsState, + ThreadState, + ThreadActionsState, + ComposerState, + EditComposerState, + ThreadViewportState, + ContentPartState, + MessageState, + MessageUtilsState, +} from "@/components/docs/parameters/context"; ## Assistant Context @@ -28,9 +41,30 @@ import { useAssistantContext } from "@assistant-ui/react"; const { useModelConfig, useToolUIs } = useAssistantContext(); ``` -#### Return Type + - +### `useModelConfig` + +```tsx +const { useModelConfig } = useAssistantContext(); + +const getModelConfig = useModelConfig(m => m.getModelConfig); +const getModelConfig = useModelConfig.getState().getModelConfig; +``` + + + + +### `useToolUIs` + +```tsx +const { useToolUIs } = useAssistantContext(); + +const getToolUI = useToolUIs(m => m.getToolUI); +const getToolUI = useToolUIs.getState().getToolUI; +``` + + ## Thread Context @@ -47,6 +81,79 @@ import { useThreadContext } from "@assistant-ui/react"; const { useThread, useThreadActions, useComposer, useViewport } = useThreadContext(); ``` +### `useThread` + +```tsx +const { useThread } = useThreadContext(); + +const messages = useThread(m => m.messages); +const messages = useThread.getState().messages; + +const isRunning = useThread(m => m.isRunning); +const isRunning = useThread.getState().isRunning; +``` + + + +### `useThreadActions` + +```tsx +const { useThreadActions } = useThreadContext(); + +const getBranches = useThreadActions(m => m.getBranches); +const getBranches = useThreadActions.getState().getBranches; + +const switchToBranch = useThreadActions(m => m.switchToBranch); +const switchToBranch = useThreadActions.getState().switchToBranch; + +const append = useThreadActions(m => m.append); +const append = useThreadActions.getState().append; + +const startRun = useThreadActions(m => m.startRun); +const startRun = useThreadActions.getState().startRun; + +const cancelRun = useThreadActions(m => m.cancelRun); +const cancelRun = useThreadActions.getState().cancelRun; + +const addToolResult = useThreadActions(m => m.addToolResult); +const addToolResult = useThreadActions.getState().addToolResult; +``` + + + +### `useComposer` + +```tsx +const { useComposer } = useThreadContext(); + +const value = useComposer(m => m.value); +const value = useComposer.getState().value; + +const setValue = useComposer(m => m.setValue); +const setValue = useComposer.getState().setValue; +``` + +{/** TODO rest of composer state */} + + + +### `useViewport` + +```tsx +const { useViewport } = useThreadContext(); + +const isAtBottom = useViewport(m => m.isAtBottom); +const isAtBottom = useViewport.getState().isAtBottom; + +const scrollToBottom = useViewport(m => m.scrollToBottom); +const scrollToBottom = useViewport.getState().scrollToBottom; + +const onScrollToBottom = useViewport(m => m.onScrollToBottom); +const onScrollToBottom = useViewport.getState().onScrollToBottom; +``` + + + ## Message Context The **Message Context** provides access to MessageState, EditComposerState and MessageUtilsState. @@ -61,6 +168,68 @@ import { useMessageContext } from "@assistant-ui/react"; const { useMessage, useMessageUtils, useComposer } = useMessageContext(); ``` +### `useMessage` + +```tsx +const { useMessage } = useMessageContext(); + +const message = useMessage(m => m.message); +const message = useMessage.getState().message; + +const parentId = useMessage(m => m.parentId); +const parentId = useMessage.getState().parentId; + +const branches = useMessage(m => m.branches); +const branches = useMessage.getState().branches; + +const isLast = useMessage(m => m.isLast); +const isLast = useMessage.getState().isLast; +``` + + + +### `useMessageUtils` + +```tsx +const { useMessageUtils } = useMessageContext(); + +const inProgressIndicator = useMessageUtils(m => m.inProgressIndicator); +const inProgressIndicator = useMessageUtils.getState().inProgressIndicator; + +const setInProgressIndicator = useMessageUtils(m => m.setInProgressIndicator); +const setInProgressIndicator = useMessageUtils.getState().setInProgressIndicator; + +const isCopied = useMessageUtils(m => m.isCopied); +const isCopied = useMessageUtils.getState().isCopied; + +const setIsCopied = useMessageUtils(m => m.setIsCopied); +const setIsCopied = useMessageUtils.getState().setIsCopied; + +const isHovering = useMessageUtils(m => m.isHovering); +const isHovering = useMessageUtils.getState().isHovering; + +const setIsHovering = useMessageUtils(m => m.setIsHovering); +const setIsHovering = useMessageUtils.getState().setIsHovering; +``` + + + +### `useComposer` (Edit Composer) + +```tsx +const { useComposer } = useMessageContext(); + +const value = useComposer(m => m.value); +const value = useComposer.getState().value; + +const setValue = useComposer(m => m.setValue); +const setValue = useComposer.getState().setValue; +``` + +{/** TODO rest of composer state */} + + + ## Content Part Context The **Content Part Context** provides access to ContentPartState. @@ -73,4 +242,18 @@ This hook provides access to the context stores. import { useContentPartContext } from "@assistant-ui/react"; const { useContentPart } = useContentPartContext(); -```../../components/docs/parameters/contextParameters \ No newline at end of file +``` + +### `useContentPart` + +```tsx +const { useContentPart } = useContentPartContext(); + +const part = useContentPart(m => m.part); +const part = useContentPart.getState().part; + +const status = useContentPart(m => m.status); +const status = useContentPart.getState().status; +``` + + \ No newline at end of file diff --git a/packages/react/src/context/providers/MessageProvider.tsx b/packages/react/src/context/providers/MessageProvider.tsx index 721c6f934..1551cbdb5 100644 --- a/packages/react/src/context/providers/MessageProvider.tsx +++ b/packages/react/src/context/providers/MessageProvider.tsx @@ -11,7 +11,7 @@ import { MessageContext } from "../react/MessageContext"; import type { MessageContextValue } from "../react/MessageContext"; import { useThreadContext } from "../react/ThreadContext"; import type { MessageState } from "../stores/Message"; -import { makeEditComposerStore } from "../stores/MessageComposer"; +import { makeEditComposerStore } from "../stores/EditComposer"; import type { ThreadState } from "../stores/Thread"; import { makeMessageUtilsStore } from "../stores/MessageUtils"; diff --git a/packages/react/src/context/react/ComposerContext.ts b/packages/react/src/context/react/ComposerContext.ts index 572273a0f..c73e0d7b3 100644 --- a/packages/react/src/context/react/ComposerContext.ts +++ b/packages/react/src/context/react/ComposerContext.ts @@ -2,7 +2,7 @@ import { useContext, useMemo } from "react"; import { MessageContext } from "./MessageContext"; import { useThreadContext } from "./ThreadContext"; import type { ComposerState } from "../stores/Composer"; -import type { EditComposerState } from "../stores/MessageComposer"; +import type { EditComposerState } from "../stores/EditComposer"; import { ReadonlyStore } from "../ReadonlyStore"; export type ComposerContextValue = { diff --git a/packages/react/src/context/react/MessageContext.ts b/packages/react/src/context/react/MessageContext.ts index 99ec8be5a..843295f57 100644 --- a/packages/react/src/context/react/MessageContext.ts +++ b/packages/react/src/context/react/MessageContext.ts @@ -1,6 +1,6 @@ import { createContext, useContext } from "react"; import type { MessageState } from "../stores/Message"; -import type { EditComposerState } from "../stores/MessageComposer"; +import type { EditComposerState } from "../stores/EditComposer"; import { ReadonlyStore } from "../ReadonlyStore"; import { MessageUtilsState } from "../stores/MessageUtils"; diff --git a/packages/react/src/context/stores/MessageComposer.ts b/packages/react/src/context/stores/EditComposer.ts similarity index 100% rename from packages/react/src/context/stores/MessageComposer.ts rename to packages/react/src/context/stores/EditComposer.ts diff --git a/packages/react/src/context/stores/index.ts b/packages/react/src/context/stores/index.ts index 65df5c0e0..bc5c44181 100644 --- a/packages/react/src/context/stores/index.ts +++ b/packages/react/src/context/stores/index.ts @@ -1,7 +1,7 @@ export type { AssistantModelConfigState } from "./AssistantModelConfig"; export type { ContentPartState } from "./ContentPart"; export type { MessageState } from "./Message"; -export type { EditComposerState } from "./MessageComposer"; +export type { EditComposerState } from "./EditComposer"; export type { ThreadState } from "./Thread"; export type { ComposerState } from "./Composer"; export type { ThreadViewportState } from "./ThreadViewport";