diff --git a/apps/www/components/shadcn/Shadcn.tsx b/apps/www/components/shadcn/Shadcn.tsx
index e00866030..5333614fb 100644
--- a/apps/www/components/shadcn/Shadcn.tsx
+++ b/apps/www/components/shadcn/Shadcn.tsx
@@ -132,20 +132,7 @@ export const Shadcn = () => {
-
+
);
diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json
index 81884deea..dc00ebaba 100644
--- a/packages/react-ui/package.json
+++ b/packages/react-ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@assistant-ui/react-ui",
- "version": "0.0.8",
+ "version": "0.0.9",
"license": "MIT",
"exports": {
".": {
diff --git a/packages/react-ui/src/components/assistant-message.tsx b/packages/react-ui/src/components/assistant-message.tsx
index d7770a58c..b6f9c4251 100644
--- a/packages/react-ui/src/components/assistant-message.tsx
+++ b/packages/react-ui/src/components/assistant-message.tsx
@@ -10,6 +10,7 @@ import { Avatar } from "./base/avatar";
import { styled } from "../styled";
import { useThreadConfig } from "./thread-config";
import { AssistantActionBar } from "./assistant-action-bar";
+import { Text } from "./text";
export const AssistantMessage: FC = () => {
return (
@@ -24,7 +25,7 @@ export const AssistantMessage: FC = () => {
AssistantMessage.displayName = "AssistantMessage";
-const AssistantAvatar: FC = () => {
+export const AssistantAvatar: FC = () => {
const { assistantAvatar: avatar = { fallback: "A" } } = useThreadConfig();
return ;
};
@@ -46,10 +47,12 @@ export const AssistantMessageContent = forwardRef<
HTMLDivElement,
AssistantMessageContentProps
>(({ components: componentsProp, ...rest }, ref) => {
- const { assistantMessage: { components } = {} } = useThreadConfig();
+ const { assistantMessage: { components = {} } = {} } = useThreadConfig();
return (
-
+
);
});
diff --git a/packages/react-ui/src/components/index.ts b/packages/react-ui/src/components/index.ts
index 376685559..fa72a5e26 100644
--- a/packages/react-ui/src/components/index.ts
+++ b/packages/react-ui/src/components/index.ts
@@ -6,6 +6,7 @@ export {
type UserMessageConfig,
type AssistantMessageConfig,
type StringsConfig,
+ type SuggestionConfig,
type ThreadConfigProviderProps,
} from "./thread-config";
@@ -35,6 +36,7 @@ export {
export {
AssistantMessage,
AssistantMessageRoot,
+ AssistantAvatar,
AssistantMessageContent,
type AssistantMessageContentProps,
} from "./assistant-message";
@@ -74,7 +76,17 @@ export {
export { AssistantModal, AssistantModalTrigger } from "./assistant-modal";
-export { ThreadWelcome, ThreadWelcomeRoot } from "./thread-welcome";
+export {
+ ThreadWelcome,
+ ThreadWelcomeRoot,
+ ThreadWelcomeAvatar,
+ ThreadWelcomeMessage,
+ type ThreadWelcomeMessageProps,
+ ThreadWelcomeSuggestions,
+ ThreadWelcomeSuggestion,
+} from "./thread-welcome";
+
+export { Text } from "./text";
export { MarkdownText } from "./markdown-text";
diff --git a/packages/react-ui/src/components/text.tsx b/packages/react-ui/src/components/text.tsx
new file mode 100644
index 000000000..f68ddd89b
--- /dev/null
+++ b/packages/react-ui/src/components/text.tsx
@@ -0,0 +1,17 @@
+import { FC } from "react";
+import {
+ ContentPartPrimitive,
+ TextContentPartProps,
+} from "@assistant-ui/react";
+
+export const Text: FC = ({ status }) => {
+ return (
+
+
+
+ );
+};
diff --git a/packages/react-ui/src/components/thread-config.tsx b/packages/react-ui/src/components/thread-config.tsx
index 7acaf000b..b158be525 100644
--- a/packages/react-ui/src/components/thread-config.tsx
+++ b/packages/react-ui/src/components/thread-config.tsx
@@ -1,9 +1,20 @@
-import { TextContentPartComponent } from "@assistant-ui/react";
+import {
+ AssistantRuntimeProvider,
+ TextContentPartComponent,
+} from "@assistant-ui/react";
import { FC, PropsWithChildren, createContext, useContext } from "react";
import { AvatarProps } from "./base/avatar";
+import { AssistantRuntime } from "@assistant-ui/react";
+
+export type SuggestionConfig = {
+ icon?: string;
+ text: string;
+ prompt?: string;
+};
export type ThreadWelcomeConfig = {
message?: string | null | undefined;
+ suggestions?: SuggestionConfig[] | undefined;
};
export type UserMessageConfig = {
diff --git a/packages/react-ui/src/components/thread-welcome.tsx b/packages/react-ui/src/components/thread-welcome.tsx
index 1f945b98a..9dbc7a8a3 100644
--- a/packages/react-ui/src/components/thread-welcome.tsx
+++ b/packages/react-ui/src/components/thread-welcome.tsx
@@ -3,13 +3,14 @@ import { ThreadPrimitive } from "@assistant-ui/react";
import { ComponentPropsWithoutRef, forwardRef, type FC } from "react";
import { styled } from "../styled";
import { Avatar } from "./base/avatar";
-import { useThreadConfig } from "./thread-config";
+import { SuggestionConfig, useThreadConfig } from "./thread-config";
export const ThreadWelcome: FC = () => {
return (
+
);
};
@@ -35,7 +36,7 @@ export const ThreadWelcomeRoot = forwardRef<
ThreadWelcomeRoot.displayName = "ThreadWelcomeRoot";
-const ThreadWelcomeAvatar: FC = () => {
+export const ThreadWelcomeAvatar: FC = () => {
const { assistantAvatar: avatar = { fallback: "A" } } = useThreadConfig();
return ;
};
@@ -44,16 +45,16 @@ const ThreadWelcomeMessageStyled = styled("p", {
className: "aui-thread-welcome-message",
});
-type ThreadWelcomeMessageProps = Omit<
+export type ThreadWelcomeMessageProps = Omit<
ComponentPropsWithoutRef,
"children"
> & { message?: string | undefined };
-const ThreadWelcomeMessage = forwardRef<
+export const ThreadWelcomeMessage = forwardRef<
HTMLParagraphElement,
ThreadWelcomeMessageProps
>(({ message: messageProp, ...rest }, ref) => {
- const { welcome: { message } = { message: "How can I help you today?" } } =
+ const { welcome: { message = "How can I help you today?" } = {} } =
useThreadConfig();
return (
@@ -63,3 +64,45 @@ const ThreadWelcomeMessage = forwardRef<
});
ThreadWelcomeMessage.displayName = "ThreadWelcomeMessage";
+
+const ThreadWelcomeSuggestionContainer = styled("div", {
+ className: "aui-thread-welcome-suggestion-container",
+});
+
+const ThreadWelcomeSuggestionStyled = styled(ThreadPrimitive.Suggestion, {
+ className: "aui-thread-welcome-suggestion",
+});
+
+export type ThreadWelcomeSuggestionProps = {
+ suggestion: SuggestionConfig;
+};
+
+export const ThreadWelcomeSuggestion: FC = ({
+ suggestion: { text, prompt },
+}) => {
+ return (
+
+ {text}
+
+ );
+};
+
+export const ThreadWelcomeSuggestions: FC = () => {
+ const { welcome: { suggestions } = {} } = useThreadConfig();
+ return (
+
+ {suggestions?.map((suggestion) => (
+
+ ))}
+
+ );
+};
+
+ThreadWelcomeSuggestions.displayName = "ThreadWelcomeSuggestions";
diff --git a/packages/react-ui/src/components/user-message.tsx b/packages/react-ui/src/components/user-message.tsx
index acb671ec3..97b709f68 100644
--- a/packages/react-ui/src/components/user-message.tsx
+++ b/packages/react-ui/src/components/user-message.tsx
@@ -6,6 +6,7 @@ import { BranchPicker } from "./branch-picker";
import { styled } from "../styled";
import { MessagePrimitiveContentProps } from "@assistant-ui/react";
import { UserActionBar } from "./user-action-bar";
+import { Text } from "./text";
export const UserMessage: FC = () => {
return (
@@ -38,7 +39,7 @@ export const UserMessageContent = forwardRef<
>(({ components, ...props }, ref) => {
return (
-
+
);
});
diff --git a/packages/react-ui/src/styles.css b/packages/react-ui/src/styles.css
index f300abed1..4d932231a 100644
--- a/packages/react-ui/src/styles.css
+++ b/packages/react-ui/src/styles.css
@@ -221,11 +221,12 @@
@apply font-medium;
}
- /* TODO text content part */
+ .aui-text {
+ @apply whitespace-pre-line;
+ }
- .aui-content-part-in-progress {
- @apply bg-foreground inline-block size-3 rounded-full;
- @apply animate-aui-pulse;
+ .aui-text-in-progress::after {
+ @apply animate-aui-pulse font-sans content-['\25CF'] ltr:ml-1 rtl:mr-1;
}
.animate-aui-pulse {
diff --git a/packages/react/src/primitive-hooks/thread/useThreadSuggestion.tsx b/packages/react/src/primitive-hooks/thread/useThreadSuggestion.tsx
index dfeade443..1b503e5be 100644
--- a/packages/react/src/primitive-hooks/thread/useThreadSuggestion.tsx
+++ b/packages/react/src/primitive-hooks/thread/useThreadSuggestion.tsx
@@ -1,5 +1,6 @@
import { useCallback } from "react";
import { useThreadContext } from "../../context";
+import { useAppendMessage } from "../../hooks";
export type UseApplyThreadSuggestionProps = {
prompt: string;
@@ -13,16 +14,18 @@ export const useThreadSuggestion = ({
}: UseApplyThreadSuggestionProps) => {
const { useThread, useComposer } = useThreadContext();
+ const append = useAppendMessage();
const disabled = useThread((t) => t.isRunning);
const callback = useCallback(() => {
const thread = useThread.getState();
const composer = useComposer.getState();
- composer.setValue(prompt);
-
if (autoSend && !thread.isRunning) {
- composer.send();
+ append(prompt);
+ composer.setValue("");
+ } else {
+ composer.setValue(prompt);
}
- }, [useThread, useComposer, prompt, autoSend]);
+ }, [useThread, useComposer, autoSend, append, prompt]);
if (disabled) return null;
return callback;