From 8d2c28f59d2eade7528a09bf74466cdd866c2b04 Mon Sep 17 00:00:00 2001 From: Simon Farshid Date: Sun, 7 Jul 2024 23:48:34 -0700 Subject: [PATCH] docs: new migrate everything to new website (#424) --- .gitignore | 2 +- apps/docs/.gitignore | 28 -- apps/docs/.map.ts | 4 + apps/docs/app/(home)/examples/page.tsx | 89 ++++ apps/docs/app/(home)/layout.tsx | 11 + apps/docs/app/(home)/page.tsx | 5 + apps/docs/app/api/chat/route.ts | 24 ++ apps/docs/app/api/search/route.ts | 10 +- apps/docs/app/docs/[[...slug]]/page.tsx | 57 ++- apps/docs/app/docs/layout.config.tsx | 102 +++++ apps/docs/app/docs/layout.tsx | 6 +- apps/docs/app/global.css | 91 ++++ apps/docs/app/layout.client.tsx | 24 ++ apps/docs/app/layout.config.tsx | 22 - apps/docs/app/layout.tsx | 11 +- apps/docs/app/page.tsx | 16 - apps/docs/app/reference/[...slug]/page.tsx | 46 ++ apps/docs/app/reference/layout.config.tsx | 9 + apps/docs/app/reference/layout.tsx | 7 + apps/docs/app/reference/page.tsx | 5 + apps/docs/app/source.ts | 26 +- apps/docs/assets/docs/architecture.png | Bin 0 -> 74858 bytes apps/docs/assets/providers/anthropic.svg | 8 + apps/docs/assets/providers/fireworks.svg | 24 ++ apps/docs/assets/providers/google.svg | 7 + apps/docs/assets/providers/huggingface.svg | 15 + apps/docs/assets/providers/meta.svg | 17 + apps/docs/assets/providers/mistral.svg | 23 + apps/docs/assets/providers/openai.svg | 11 + apps/docs/components.json | 17 + apps/docs/components/Home.tsx | 99 +++++ apps/docs/components/chatgpt/ChatGPT.tsx | 207 +++++++++ apps/docs/components/claude/Claude.tsx | 102 +++++ .../components/docs/DataAttributesTable.tsx | 52 +++ apps/docs/components/docs/KeyboardTable.tsx | 43 ++ apps/docs/components/docs/ParametersTable.tsx | 115 +++++ apps/docs/components/docs/index.ts | 3 + .../components/docs/parameters/context.tsx | 402 ++++++++++++++++++ .../components/docs/parameters/runtime.tsx | 126 ++++++ apps/docs/components/genui/GenUI.tsx | 9 + apps/docs/components/modal/ModalChat.tsx | 13 + apps/docs/components/shadcn/ModelPicker.tsx | 114 +++++ apps/docs/components/shadcn/Shadcn.tsx | 177 ++++++++ apps/docs/components/ui/badge.tsx | 36 ++ apps/docs/components/ui/button.tsx | 57 +++ apps/docs/components/ui/select.tsx | 164 +++++++ apps/docs/components/ui/sheet.tsx | 140 ++++++ apps/docs/components/ui/tooltip.tsx | 30 ++ apps/docs/content/docs/docs/advanced/API.mdx | 41 ++ .../content/docs/docs/advanced/Branching.mdx | 55 +++ .../content/docs/docs/advanced/Editing.mdx | 56 +++ .../content/docs/docs/advanced/Markdown.mdx | 55 +++ .../content/docs/docs/advanced/ToolUI.mdx | 147 +++++++ apps/docs/content/docs/docs/architecture.mdx | 18 + apps/docs/content/docs/docs/index.mdx | 72 ++++ apps/docs/content/docs/docs/meta.json | 14 + .../content/docs/docs/migrations/v0-3.mdx | 50 +++ .../docs/docs/runtimes/custom-rest.mdx | 122 ++++++ .../content/docs/docs/runtimes/langserve.mdx | 125 ++++++ .../docs/content/docs/docs/runtimes/meta.json | 4 + .../docs/docs/runtimes/pick-a-runtime.mdx | 7 + .../docs/runtimes/vercel-ai-sdk/meta.json | 3 + .../docs/docs/runtimes/vercel-ai-sdk/rsc.mdx | 205 +++++++++ .../runtimes/vercel-ai-sdk/use-assistant.mdx | 176 ++++++++ .../docs/runtimes/vercel-ai-sdk/use-chat.mdx | 120 ++++++ .../content/docs/docs/ui/AssistantModal.mdx | 62 +++ .../content/docs/docs/ui/AssistantSidebar.mdx | 62 +++ apps/docs/content/docs/docs/ui/Thread.mdx | 74 ++++ apps/docs/content/docs/docs/ui/meta.json | 3 + apps/docs/content/docs/index.mdx | 13 - apps/docs/content/docs/reference/context.mdx | 314 ++++++++++++++ .../docs/reference/integrations/meta.json | 3 + .../integrations/react-hook-form.mdx | 103 +++++ .../reference/integrations/vercel-ai-sdk.mdx | 145 +++++++ apps/docs/content/docs/reference/meta.json | 12 + .../docs/reference/primitives/ActionBar.mdx | 232 ++++++++++ .../reference/primitives/AssistantModal.mdx | 129 ++++++ .../reference/primitives/BranchPicker.mdx | 141 ++++++ .../docs/reference/primitives/Composer.mdx | 185 ++++++++ .../docs/reference/primitives/ContentPart.mdx | 80 ++++ .../docs/reference/primitives/Message.mdx | 169 ++++++++ .../docs/reference/primitives/Thread.mdx | 269 ++++++++++++ .../docs/reference/primitives/composition.mdx | 21 + .../docs/reference/primitives/meta.json | 13 + apps/docs/content/docs/reference/runtime.mdx | 28 ++ apps/docs/content/docs/test.mdx | 17 - apps/docs/lib/utils.ts | 6 + apps/docs/next-env.d.ts | 5 + apps/docs/package.json | 29 +- apps/docs/public/favicon/favicon.png | Bin 0 -> 741 bytes apps/docs/public/favicon/favicon.svg | 9 + apps/docs/tailwind.config.js | 13 - apps/docs/tailwind.config.ts | 87 ++++ apps/docs/tsconfig.json | 29 +- apps/www/public/registry/index.json | 135 ++++++ .../styles/default/markdown-text.json | 17 + .../public/registry/styles/default/modal.json | 19 + .../registry/styles/default/sidebar.json | 18 + .../registry/styles/default/thread-full.json | 20 + .../registry/styles/default/thread.json | 19 + .../styles/default/unstable-codeblock.json | 18 + .../default/unstable-markdown-text.json | 16 + .../styles/default/unstable-thread-full.json | 20 + .../styles/new-york/markdown-text.json | 17 + .../registry/styles/new-york/modal.json | 19 + .../registry/styles/new-york/sidebar.json | 18 + .../registry/styles/new-york/thread-full.json | 20 + .../registry/styles/new-york/thread.json | 19 + .../styles/new-york/unstable-codeblock.json | 18 + .../new-york/unstable-markdown-text.json | 16 + .../styles/new-york/unstable-thread-full.json | 20 + .../src/components/assistant-modal.tsx | 2 +- packages/react-ui/src/styles.css | 16 +- packages/react/README.md | 4 +- .../shadcn-registry/scripts/build-registry.ts | 2 +- pnpm-lock.yaml | 69 +++ 116 files changed, 6477 insertions(+), 174 deletions(-) delete mode 100644 apps/docs/.gitignore create mode 100644 apps/docs/.map.ts create mode 100644 apps/docs/app/(home)/examples/page.tsx create mode 100644 apps/docs/app/(home)/layout.tsx create mode 100644 apps/docs/app/(home)/page.tsx create mode 100644 apps/docs/app/api/chat/route.ts create mode 100644 apps/docs/app/docs/layout.config.tsx create mode 100644 apps/docs/app/layout.client.tsx delete mode 100644 apps/docs/app/layout.config.tsx delete mode 100644 apps/docs/app/page.tsx create mode 100644 apps/docs/app/reference/[...slug]/page.tsx create mode 100644 apps/docs/app/reference/layout.config.tsx create mode 100644 apps/docs/app/reference/layout.tsx create mode 100644 apps/docs/app/reference/page.tsx create mode 100644 apps/docs/assets/docs/architecture.png create mode 100644 apps/docs/assets/providers/anthropic.svg create mode 100644 apps/docs/assets/providers/fireworks.svg create mode 100644 apps/docs/assets/providers/google.svg create mode 100644 apps/docs/assets/providers/huggingface.svg create mode 100644 apps/docs/assets/providers/meta.svg create mode 100644 apps/docs/assets/providers/mistral.svg create mode 100644 apps/docs/assets/providers/openai.svg create mode 100644 apps/docs/components.json create mode 100644 apps/docs/components/Home.tsx create mode 100644 apps/docs/components/chatgpt/ChatGPT.tsx create mode 100644 apps/docs/components/claude/Claude.tsx create mode 100644 apps/docs/components/docs/DataAttributesTable.tsx create mode 100644 apps/docs/components/docs/KeyboardTable.tsx create mode 100644 apps/docs/components/docs/ParametersTable.tsx create mode 100644 apps/docs/components/docs/index.ts create mode 100644 apps/docs/components/docs/parameters/context.tsx create mode 100644 apps/docs/components/docs/parameters/runtime.tsx create mode 100644 apps/docs/components/genui/GenUI.tsx create mode 100644 apps/docs/components/modal/ModalChat.tsx create mode 100644 apps/docs/components/shadcn/ModelPicker.tsx create mode 100644 apps/docs/components/shadcn/Shadcn.tsx create mode 100644 apps/docs/components/ui/badge.tsx create mode 100644 apps/docs/components/ui/button.tsx create mode 100644 apps/docs/components/ui/select.tsx create mode 100644 apps/docs/components/ui/sheet.tsx create mode 100644 apps/docs/components/ui/tooltip.tsx create mode 100644 apps/docs/content/docs/docs/advanced/API.mdx create mode 100644 apps/docs/content/docs/docs/advanced/Branching.mdx create mode 100644 apps/docs/content/docs/docs/advanced/Editing.mdx create mode 100644 apps/docs/content/docs/docs/advanced/Markdown.mdx create mode 100644 apps/docs/content/docs/docs/advanced/ToolUI.mdx create mode 100644 apps/docs/content/docs/docs/architecture.mdx create mode 100644 apps/docs/content/docs/docs/index.mdx create mode 100644 apps/docs/content/docs/docs/meta.json create mode 100644 apps/docs/content/docs/docs/migrations/v0-3.mdx create mode 100644 apps/docs/content/docs/docs/runtimes/custom-rest.mdx create mode 100644 apps/docs/content/docs/docs/runtimes/langserve.mdx create mode 100644 apps/docs/content/docs/docs/runtimes/meta.json create mode 100644 apps/docs/content/docs/docs/runtimes/pick-a-runtime.mdx create mode 100644 apps/docs/content/docs/docs/runtimes/vercel-ai-sdk/meta.json create mode 100644 apps/docs/content/docs/docs/runtimes/vercel-ai-sdk/rsc.mdx create mode 100644 apps/docs/content/docs/docs/runtimes/vercel-ai-sdk/use-assistant.mdx create mode 100644 apps/docs/content/docs/docs/runtimes/vercel-ai-sdk/use-chat.mdx create mode 100644 apps/docs/content/docs/docs/ui/AssistantModal.mdx create mode 100644 apps/docs/content/docs/docs/ui/AssistantSidebar.mdx create mode 100644 apps/docs/content/docs/docs/ui/Thread.mdx create mode 100644 apps/docs/content/docs/docs/ui/meta.json delete mode 100644 apps/docs/content/docs/index.mdx create mode 100644 apps/docs/content/docs/reference/context.mdx create mode 100644 apps/docs/content/docs/reference/integrations/meta.json create mode 100644 apps/docs/content/docs/reference/integrations/react-hook-form.mdx create mode 100644 apps/docs/content/docs/reference/integrations/vercel-ai-sdk.mdx create mode 100644 apps/docs/content/docs/reference/meta.json create mode 100644 apps/docs/content/docs/reference/primitives/ActionBar.mdx create mode 100644 apps/docs/content/docs/reference/primitives/AssistantModal.mdx create mode 100644 apps/docs/content/docs/reference/primitives/BranchPicker.mdx create mode 100644 apps/docs/content/docs/reference/primitives/Composer.mdx create mode 100644 apps/docs/content/docs/reference/primitives/ContentPart.mdx create mode 100644 apps/docs/content/docs/reference/primitives/Message.mdx create mode 100644 apps/docs/content/docs/reference/primitives/Thread.mdx create mode 100644 apps/docs/content/docs/reference/primitives/composition.mdx create mode 100644 apps/docs/content/docs/reference/primitives/meta.json create mode 100644 apps/docs/content/docs/reference/runtime.mdx delete mode 100644 apps/docs/content/docs/test.mdx create mode 100644 apps/docs/lib/utils.ts create mode 100644 apps/docs/next-env.d.ts create mode 100644 apps/docs/public/favicon/favicon.png create mode 100644 apps/docs/public/favicon/favicon.svg delete mode 100644 apps/docs/tailwind.config.js create mode 100644 apps/docs/tailwind.config.ts create mode 100644 apps/www/public/registry/index.json create mode 100644 apps/www/public/registry/styles/default/markdown-text.json create mode 100644 apps/www/public/registry/styles/default/modal.json create mode 100644 apps/www/public/registry/styles/default/sidebar.json create mode 100644 apps/www/public/registry/styles/default/thread-full.json create mode 100644 apps/www/public/registry/styles/default/thread.json create mode 100644 apps/www/public/registry/styles/default/unstable-codeblock.json create mode 100644 apps/www/public/registry/styles/default/unstable-markdown-text.json create mode 100644 apps/www/public/registry/styles/default/unstable-thread-full.json create mode 100644 apps/www/public/registry/styles/new-york/markdown-text.json create mode 100644 apps/www/public/registry/styles/new-york/modal.json create mode 100644 apps/www/public/registry/styles/new-york/sidebar.json create mode 100644 apps/www/public/registry/styles/new-york/thread-full.json create mode 100644 apps/www/public/registry/styles/new-york/thread.json create mode 100644 apps/www/public/registry/styles/new-york/unstable-codeblock.json create mode 100644 apps/www/public/registry/styles/new-york/unstable-markdown-text.json create mode 100644 apps/www/public/registry/styles/new-york/unstable-thread-full.json diff --git a/.gitignore b/.gitignore index df8a7f1d1..673bd6c04 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,7 @@ out/ # production build dist -apps/www/public/registry/ +apps/docs/public/registry/ # turbo .turbo diff --git a/apps/docs/.gitignore b/apps/docs/.gitignore deleted file mode 100644 index 51c0e6b51..000000000 --- a/apps/docs/.gitignore +++ /dev/null @@ -1,28 +0,0 @@ -# deps -/node_modules - -# generated content -.map.ts -.contentlayer -.content-collections - -# test & build -/coverage -/.next/ -/out/ -/build -*.tsbuildinfo - -# misc -.DS_Store -*.pem -/.pnp -.pnp.js -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# others -.env*.local -.vercel -next-env.d.ts \ No newline at end of file diff --git a/apps/docs/.map.ts b/apps/docs/.map.ts new file mode 100644 index 000000000..4da1afa55 --- /dev/null +++ b/apps/docs/.map.ts @@ -0,0 +1,4 @@ +/** Auto-generated **/ +declare const map: Record + +export { map } \ No newline at end of file diff --git a/apps/docs/app/(home)/examples/page.tsx b/apps/docs/app/(home)/examples/page.tsx new file mode 100644 index 000000000..4d6107a51 --- /dev/null +++ b/apps/docs/app/(home)/examples/page.tsx @@ -0,0 +1,89 @@ +const Examples = () => { + return ( +
+

Examples

+ +

RSC Example

+

This is an example of how to use the Vercel AI SDK RSC Runtime.

+ + +

eCommerce Example

+

+ This is an example of an eCommerce chatbot that can help users find + products. Built with Vercel AI SDK RSC Runtime. +

+ + +

Inline Suggestions Example

+

This is an example of how to use inline suggestions.

+ + +

React Hook Form Example

+

This is an example of how to use @assistant-ui/react-hook-form.

+ + +

Custom REST API Example

+

+ This is an example of how to use @assistant-ui/react with a custom REST + API. +

+ + +

Thread History Persistence example

+

+ This is an example of how to restore the thread history using + @assistant-ui/react-ai-sdk and Vercel AI SDK. +

+ +
+ ); +}; + +export default Examples; diff --git a/apps/docs/app/(home)/layout.tsx b/apps/docs/app/(home)/layout.tsx new file mode 100644 index 000000000..f7bfbf830 --- /dev/null +++ b/apps/docs/app/(home)/layout.tsx @@ -0,0 +1,11 @@ +import { ReactNode } from "react"; +import { Layout } from "fumadocs-ui/layout"; +import { baseOptions } from "../docs/layout.config"; + +export default function HomeLayout({ + children, +}: { + children: ReactNode; +}): React.ReactElement { + return {children}; +} diff --git a/apps/docs/app/(home)/page.tsx b/apps/docs/app/(home)/page.tsx new file mode 100644 index 000000000..3953e986d --- /dev/null +++ b/apps/docs/app/(home)/page.tsx @@ -0,0 +1,5 @@ +import Home from "@/components/Home"; + +export default function HomePage() { + return ; +} diff --git a/apps/docs/app/api/chat/route.ts b/apps/docs/app/api/chat/route.ts new file mode 100644 index 000000000..273b2b1c5 --- /dev/null +++ b/apps/docs/app/api/chat/route.ts @@ -0,0 +1,24 @@ +import { createOpenAI } from "@ai-sdk/openai"; +import { streamText } from "ai"; + +const openai = createOpenAI({ + baseURL: process.env["OPENAI_BASE_URL"] as string, +}); + +export const runtime = "edge"; + +export async function POST(req: Request) { + const { messages } = await req.json(); + const result = await streamText({ + model: openai("gpt-3.5-turbo"), + messages: [ + { + role: "system", + content: "You are a helpful assistant.", + }, + ...messages, + ], + }); + + return result.toAIStreamResponse(); +} diff --git a/apps/docs/app/api/search/route.ts b/apps/docs/app/api/search/route.ts index 74983f973..b68090053 100644 --- a/apps/docs/app/api/search/route.ts +++ b/apps/docs/app/api/search/route.ts @@ -1,10 +1,10 @@ -import { getPages } from '@/app/source'; -import { createSearchAPI } from 'fumadocs-core/search/server'; +import { getPages } from "@/app/source"; +import { createSearchAPI } from "fumadocs-core/search/server"; -export const { GET } = createSearchAPI('advanced', { +export const { GET } = createSearchAPI("advanced", { indexes: getPages().map((page) => ({ - title: page.data.title, - structuredData: page.data.exports.structuredData, + title: (page.data as any).title, + structuredData: (page.data as any).exports.structuredData, id: page.url, url: page.url, })), diff --git a/apps/docs/app/docs/[[...slug]]/page.tsx b/apps/docs/app/docs/[[...slug]]/page.tsx index 07ea900f8..ecf42855e 100644 --- a/apps/docs/app/docs/[[...slug]]/page.tsx +++ b/apps/docs/app/docs/[[...slug]]/page.tsx @@ -1,25 +1,52 @@ -import { getPage, getPages } from '@/app/source'; -import type { Metadata } from 'next'; -import { DocsPage, DocsBody } from 'fumadocs-ui/page'; -import { notFound } from 'next/navigation'; +import { getPages, getPage } from "@/app/source"; +import type { Metadata } from "next"; +import { DocsPage, DocsBody } from "fumadocs-ui/page"; +import { notFound } from "next/navigation"; +import { cn } from "@/lib/utils"; +import { buttonVariants } from "@/components/ui/button"; +import { EditIcon } from "lucide-react"; export default async function Page({ params, }: { params: { slug?: string[] }; }) { - const page = getPage(params.slug); + const page = getPage(["docs", ...(params.slug ?? [])]); if (page == null) { notFound(); } - const MDX = page.data.exports.default; + const path = `apps/docs/content/docs/${page.file.path}`; + + const footer = ( + + + Edit on Github + + ); + + const MDX = (page.data as any).exports.default; return ( - + -

{page.data.title}

+

{(page.data as any).title}

@@ -27,18 +54,20 @@ export default async function Page({ } export async function generateStaticParams() { - return getPages().map((page) => ({ - slug: page.slugs, - })); + return getPages() + .filter((page) => page.slugs[0] === "docs") + .map((page) => ({ + slug: page.slugs.slice(1), + })); } export function generateMetadata({ params }: { params: { slug?: string[] } }) { - const page = getPage(params.slug); + const page = getPage(["docs", ...(params.slug ?? [])]); if (page == null) notFound(); return { - title: page.data.title, - description: page.data.description, + title: (page.data as any).title, + description: (page.data as any).description, } satisfies Metadata; } diff --git a/apps/docs/app/docs/layout.config.tsx b/apps/docs/app/docs/layout.config.tsx new file mode 100644 index 000000000..1af1f111e --- /dev/null +++ b/apps/docs/app/docs/layout.config.tsx @@ -0,0 +1,102 @@ +import { type BaseLayoutProps, type DocsLayoutProps } from "fumadocs-ui/layout"; +import { pageTree } from "@/app/source"; +import { RootToggle } from "fumadocs-ui/components/layout/root-toggle"; +import { BookIcon, LayoutTemplateIcon, UserIcon } from "lucide-react"; +import { LibraryIcon, type LucideIcon } from "lucide-react"; +import icon from "@/public/favicon/favicon.svg"; +import Image from "next/image"; + +type Mode = { + url: string; + title: string; + description: string; + icon: LucideIcon; + param: string; +}; + +export const modes: Mode[] = [ + { + icon: LibraryIcon, + title: "Documentation", + description: "@assistant-ui/react", + url: "/docs", + param: "docs", + }, + { + icon: LibraryIcon, + title: "Reference", + description: "@assistant-ui/react", + url: "/reference", + param: "reference", + }, +]; + +// shared configuration +export const baseOptions: BaseLayoutProps = { + githubUrl: "https://github.com/Yonom/assistant-ui", + nav: { + title: ( + <> + logo + assistant-ui + + ), + transparentMode: "none", + }, + links: [ + { + text: "Documentation", + url: "/docs", + icon: , + active: "nested-url", + }, + { + text: "Reference", + url: "/reference", + icon: , + active: "nested-url", + }, + { + text: "Examples", + url: "/examples", + icon: , + }, + { + text: "Discord", + url: "https://discord.gg/S9dwgCNEFs", + icon: , + external: true, + }, + ], +}; + +export const sharedDocsOptions: Partial = { + ...baseOptions, + sidebar: { + defaultOpenLevel: 0, + banner: ( + ({ + url: mode.url, + icon: ( + + ), + title: mode.title, + description: mode.description, + }))} + /> + ), + }, +}; + +// docs layout configuration +export const docsOptions: DocsLayoutProps = { + ...sharedDocsOptions, + tree: pageTree, +}; diff --git a/apps/docs/app/docs/layout.tsx b/apps/docs/app/docs/layout.tsx index ae2cc9e99..5d0998beb 100644 --- a/apps/docs/app/docs/layout.tsx +++ b/apps/docs/app/docs/layout.tsx @@ -1,6 +1,6 @@ -import { DocsLayout } from 'fumadocs-ui/layout'; -import type { ReactNode } from 'react'; -import { docsOptions } from '../layout.config'; +import { DocsLayout } from "fumadocs-ui/layout"; +import type { ReactNode } from "react"; +import { docsOptions } from "./layout.config"; export default function Layout({ children }: { children: ReactNode }) { return {children}; diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css index b5c61c956..fdd04564e 100644 --- a/apps/docs/app/global.css +++ b/apps/docs/app/global.css @@ -1,3 +1,94 @@ @tailwind base; @tailwind components; @tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 10% 3.9%; + + --radius: 0.5rem; + } + + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} + +.mode-docs { + --primary: var(--docs-color); +} + +.mode-reference { + --primary: var(--reference-color); +} + +:root { + --docs-color: 220deg 91% 54%; + --reference-color: 250 80% 54%; +} + +.dark { + --docs-color: 217deg 92% 76%; + --reference-color: 250 100% 80%; +} diff --git a/apps/docs/app/layout.client.tsx b/apps/docs/app/layout.client.tsx new file mode 100644 index 000000000..a8a7ffe4a --- /dev/null +++ b/apps/docs/app/layout.client.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { usePathname } from "next/navigation"; +import { type ReactNode } from "react"; +import { cn } from "@/lib/utils"; + +function useMode(): string | undefined { + const name = usePathname(); + return name.split("/")[1]; +} + +export function Body({ + children, +}: { + children: ReactNode; +}): React.ReactElement { + const mode = useMode(); + + return ( + + {children} + + ); +} diff --git a/apps/docs/app/layout.config.tsx b/apps/docs/app/layout.config.tsx deleted file mode 100644 index 659e35aa9..000000000 --- a/apps/docs/app/layout.config.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { type BaseLayoutProps, type DocsLayoutProps } from 'fumadocs-ui/layout'; -import { pageTree } from '@/app/source'; - -// shared configuration -export const baseOptions: BaseLayoutProps = { - nav: { - title: 'My App', - }, - links: [ - { - text: 'Documentation', - url: '/docs', - active: 'nested-url', - }, - ], -}; - -// docs layout configuration -export const docsOptions: DocsLayoutProps = { - ...baseOptions, - tree: pageTree, -}; diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx index a9c12cac8..bc23ad2dc 100644 --- a/apps/docs/app/layout.tsx +++ b/apps/docs/app/layout.tsx @@ -3,13 +3,18 @@ import { RootProvider } from "fumadocs-ui/provider"; import type { ReactNode } from "react"; import { GeistSans } from "geist/font/sans"; import { GeistMono } from "geist/font/mono"; +import { Body } from "./layout.client"; export default function Layout({ children }: { children: ReactNode }) { return ( - - + + {children} - + ); } diff --git a/apps/docs/app/page.tsx b/apps/docs/app/page.tsx deleted file mode 100644 index fa093f695..000000000 --- a/apps/docs/app/page.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import Link from 'next/link'; - -export default function HomePage() { - return ( -
-

Hello World

-

- You can open{' '} - - /docs - {' '} - and see the documentation. -

-
- ); -} diff --git a/apps/docs/app/reference/[...slug]/page.tsx b/apps/docs/app/reference/[...slug]/page.tsx new file mode 100644 index 000000000..b45e1603a --- /dev/null +++ b/apps/docs/app/reference/[...slug]/page.tsx @@ -0,0 +1,46 @@ +import { getPages, getPage } from "@/app/source"; +import type { Metadata } from "next"; +import { DocsPage, DocsBody } from "fumadocs-ui/page"; +import { notFound } from "next/navigation"; + +export default async function Page({ + params, +}: { + params: { slug?: string[] }; +}) { + const page = getPage(["reference", ...(params.slug ?? [])]); + + if (page == null) { + notFound(); + } + + const MDX = (page.data as any).exports.default; + + return ( + + +

{(page.data as any).title}

+ +
+
+ ); +} + +export async function generateStaticParams() { + return getPages() + .filter((page) => page.slugs[0] === "reference") + .map((page) => ({ + slug: page.slugs.slice(1), + })); +} + +export function generateMetadata({ params }: { params: { slug?: string[] } }) { + const page = getPage(["reference", ...(params.slug ?? [])]); + + if (page == null) notFound(); + + return { + title: (page.data as any).title, + description: (page.data as any).description, + } satisfies Metadata; +} diff --git a/apps/docs/app/reference/layout.config.tsx b/apps/docs/app/reference/layout.config.tsx new file mode 100644 index 000000000..dadc493f2 --- /dev/null +++ b/apps/docs/app/reference/layout.config.tsx @@ -0,0 +1,9 @@ +import { type DocsLayoutProps } from "fumadocs-ui/layout"; +import { pageTree } from "@/app/source"; +import { sharedDocsOptions } from "../docs/layout.config"; + +// docs layout configuration +export const docsOptions: DocsLayoutProps = { + ...sharedDocsOptions, + tree: pageTree, +}; diff --git a/apps/docs/app/reference/layout.tsx b/apps/docs/app/reference/layout.tsx new file mode 100644 index 000000000..5d0998beb --- /dev/null +++ b/apps/docs/app/reference/layout.tsx @@ -0,0 +1,7 @@ +import { DocsLayout } from "fumadocs-ui/layout"; +import type { ReactNode } from "react"; +import { docsOptions } from "./layout.config"; + +export default function Layout({ children }: { children: ReactNode }) { + return {children}; +} diff --git a/apps/docs/app/reference/page.tsx b/apps/docs/app/reference/page.tsx new file mode 100644 index 000000000..b61832207 --- /dev/null +++ b/apps/docs/app/reference/page.tsx @@ -0,0 +1,5 @@ +import { redirect } from "next/navigation"; + +export default function Page() { + return redirect("/reference/runtime"); +} diff --git a/apps/docs/app/source.ts b/apps/docs/app/source.ts index 5cb887be3..734dfc6b0 100644 --- a/apps/docs/app/source.ts +++ b/apps/docs/app/source.ts @@ -1,9 +1,21 @@ -import { map } from '@/.map'; -import { createMDXSource } from 'fumadocs-mdx'; -import { loader } from 'fumadocs-core/source'; +import { map } from "@/.map"; +import { createMDXSource } from "fumadocs-mdx"; +import { loader } from "fumadocs-core/source"; +import { z } from "zod"; -export const { getPage, getPages, pageTree } = loader({ - baseUrl: '/docs', - rootDir: 'docs', - source: createMDXSource(map), +const frontmatterSchema = z.object({ + title: z.string(), + description: z.string().optional(), + icon: z.string().optional(), + full: z.boolean().optional(), +}); + +export const { getPages, getPage, pageTree } = loader({ + baseUrl: "/", + rootDir: "docs", + source: createMDXSource(map, { + schema: { + frontmatter: frontmatterSchema, + }, + }), }); diff --git a/apps/docs/assets/docs/architecture.png b/apps/docs/assets/docs/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..297745a9c70df2f951ef247d6e0aeb357ad2892c GIT binary patch literal 74858 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 IS;E!vhO(e?SFu&8BD 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≥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 s^#31 + + + + + diff --git a/apps/docs/assets/providers/fireworks.svg b/apps/docs/assets/providers/fireworks.svg new file mode 100644 index 000000000..f70c2849d --- /dev/null +++ b/apps/docs/assets/providers/fireworks.svg @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/apps/docs/assets/providers/google.svg b/apps/docs/assets/providers/google.svg new file mode 100644 index 000000000..0fe37f3d8 --- /dev/null +++ b/apps/docs/assets/providers/google.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/apps/docs/assets/providers/huggingface.svg b/apps/docs/assets/providers/huggingface.svg new file mode 100644 index 000000000..d5770e91a --- /dev/null +++ b/apps/docs/assets/providers/huggingface.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/apps/docs/assets/providers/meta.svg b/apps/docs/assets/providers/meta.svg new file mode 100644 index 000000000..6621c0979 --- /dev/null +++ b/apps/docs/assets/providers/meta.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/apps/docs/assets/providers/mistral.svg b/apps/docs/assets/providers/mistral.svg new file mode 100644 index 000000000..6f81a163a --- /dev/null +++ b/apps/docs/assets/providers/mistral.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/assets/providers/openai.svg b/apps/docs/assets/providers/openai.svg new file mode 100644 index 000000000..9ea7020f8 --- /dev/null +++ b/apps/docs/assets/providers/openai.svg @@ -0,0 +1,11 @@ + + + + + OpenAI icon + + + + diff --git a/apps/docs/components.json b/apps/docs/components.json new file mode 100644 index 000000000..ff3d721de --- /dev/null +++ b/apps/docs/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "app/global.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} \ No newline at end of file diff --git a/apps/docs/components/Home.tsx b/apps/docs/components/Home.tsx new file mode 100644 index 000000000..0417ac633 --- /dev/null +++ b/apps/docs/components/Home.tsx @@ -0,0 +1,99 @@ +"use client"; + +import { Claude } from "@/components/claude/Claude"; +import { Shadcn } from "@/components/shadcn/Shadcn"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { useChat } from "@ai-sdk/react"; +import { AssistantRuntimeProvider } from "@assistant-ui/react"; +import { useVercelUseChatRuntime } from "@assistant-ui/react-ai-sdk"; +import Link from "next/link"; +import { useState } from "react"; +import { ChatGPT } from "./chatgpt/ChatGPT"; +import { GenUI } from "./genui/GenUI"; +import { ModalChat } from "./modal/ModalChat"; + +const supportedModels = [ + { + name: "Standalone", + component: Shadcn, + }, + { + name: "Modal", + component: ModalChat, + }, + { + name: "Tool UI", + component: GenUI, + }, + { + name: "ChatGPT Theme", + component: ChatGPT, + }, + { + name: "Claude Theme", + component: Claude, + }, +]; + +export default function Home() { + const [selectedModel, setSelectedModel] = useState(supportedModels[0]!); + const ChatComponent = selectedModel.component; + + return ( +
+
+

+ React Components for AI Chat +

+

+ Add an AI chatbot to your app in minutes. +

+
+ +
+ +
+
+

Examples:

+
+
+ {supportedModels.map((model) => ( + setSelectedModel(model)} + className="shrink-0 cursor-pointer px-4 py-2" + variant={ + selectedModel.name === model.name ? "default" : "secondary" + } + > + {model.name} + + ))} +
+
+
+ + + +
+
+
+ ); +} + +export type AssistantProps = { + chat: ReturnType; +}; + +const MyRuntimeProvider = ({ children }: { children: React.ReactNode }) => { + const chat = useChat(); + const runtime = useVercelUseChatRuntime(chat); + return ( + + {children} + + ); +}; diff --git a/apps/docs/components/chatgpt/ChatGPT.tsx b/apps/docs/components/chatgpt/ChatGPT.tsx new file mode 100644 index 000000000..1559d5f9b --- /dev/null +++ b/apps/docs/components/chatgpt/ChatGPT.tsx @@ -0,0 +1,207 @@ +"use client"; + +import { cn } from "@/lib/utils"; +import { + ActionBarPrimitive, + BranchPickerPrimitive, + ComposerPrimitive, + MessagePrimitive, + ThreadPrimitive, +} from "@assistant-ui/react"; +import * as Avatar from "@radix-ui/react-avatar"; +import { + ArrowUpIcon, + CheckIcon, + ChevronLeftIcon, + ChevronRightIcon, + CopyIcon, + Pencil1Icon, + ReloadIcon, +} from "@radix-ui/react-icons"; +import type { FC } from "react"; +import { Button, type ButtonProps } from "../ui/button"; +import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"; + +export const ChatGPT: FC = () => { + return ( + + + +
+ + C + +

How can I help you today?

+
+
+ + +
+ + + + + + + + + + +
+ + + +

+ ChatGPT can make mistakes. Check important info. +

+ + ); +}; + +const UserMessage: FC = () => { + return ( + +
+ + + + + + + + +
+ +
+
+ + +
+ ); +}; + +const EditComposer: FC = () => { + return ( + + + +
+ + Cancel + + + Send + +
+
+ ); +}; + +const AssistantMessage: FC = () => { + return ( + + + + C + + + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + +
+
+
+ ); +}; + +const BranchPicker: FC<{ className?: string }> = ({ className }) => { + return ( + + + + + + + / + + + + + + + ); +}; + +type ActionButtonProps = ButtonProps & { tooltip: string }; + +const ActionButton: FC = ({ + tooltip, + className, + children, + ...rest +}) => { + return ( + + + + + {tooltip} + + ); +}; diff --git a/apps/docs/components/claude/Claude.tsx b/apps/docs/components/claude/Claude.tsx new file mode 100644 index 000000000..783f182a1 --- /dev/null +++ b/apps/docs/components/claude/Claude.tsx @@ -0,0 +1,102 @@ +"use client"; + +import { cn } from "@/lib/utils"; +import { + ActionBarPrimitive, + ComposerPrimitive, + MessagePrimitive, + ThreadPrimitive, +} from "@assistant-ui/react"; +import { useMessageContext } from "@assistant-ui/react"; +import * as Avatar from "@radix-ui/react-avatar"; +import { ArrowUpIcon, ClipboardIcon, ReloadIcon } from "@radix-ui/react-icons"; +import type { FC } from "react"; + +export const Claude: FC = () => { + return ( + + + + +

+ Claude can make mistakes. Please double-check responses. +

+
+
+ + +
+ + + + +
+

+ Claude 3 Sonnet +

+
+
+ ); +}; + +const ChatMessage: FC = () => { + const { useMessage } = useMessageContext(); + const { message } = useMessage(); + + return ( + +
+ {message.role === "assistant" && ( +
+ )} +
+ + + + U + + + + +

+ +

+
+
+ + + + + + Retry + + + + + Copy + + + + + ); +}; diff --git a/apps/docs/components/docs/DataAttributesTable.tsx b/apps/docs/components/docs/DataAttributesTable.tsx new file mode 100644 index 000000000..e3514a693 --- /dev/null +++ b/apps/docs/components/docs/DataAttributesTable.tsx @@ -0,0 +1,52 @@ +import { Box, Code, Table, Text } from "@radix-ui/themes"; +import React from "react"; + +type KeyboardDef = { + attribute: string; + values: string; +}; + +export function DataAttributesTable({ data }: { data: KeyboardDef[] }) { + return ( + + + + + + Data attribute + + Values + + + + + {data.map(({ attribute, values }, i) => { + const key = `${attribute}-${i}`; + return ( + + + {attribute} + + + + {Array.isArray(values) ? ( + + {values.map( + (value, index) => + `"${value}" ${values.length !== index + 1 ? " | " : ""}`, + )} + + ) : ( + + {values} + + )} + + + ); + })} + + + + ); +} diff --git a/apps/docs/components/docs/KeyboardTable.tsx b/apps/docs/components/docs/KeyboardTable.tsx new file mode 100644 index 000000000..81986dc6f --- /dev/null +++ b/apps/docs/components/docs/KeyboardTable.tsx @@ -0,0 +1,43 @@ +import { Box, Flex, Kbd, Table } from "@radix-ui/themes"; +import type React from "react"; + +type KeyboardDef = { + keys: string[]; + description: React.ReactNode; +}; + +export function KeyboardTable({ data }: { data: KeyboardDef[] }) { + return ( + + + + + + Key + + Description + + + + + {data.map(({ keys, description }, i) => { + const key = `${description}-${i}`; + return ( + + + + {keys.map((k) => ( + {k} + ))} + + + + {description} + + ); + })} + + + + ); +} diff --git a/apps/docs/components/docs/ParametersTable.tsx b/apps/docs/components/docs/ParametersTable.tsx new file mode 100644 index 000000000..ff94786f0 --- /dev/null +++ b/apps/docs/components/docs/ParametersTable.tsx @@ -0,0 +1,115 @@ +import { cn } from "@/lib/utils"; +import type { FC, ReactNode } from "react"; + +type ParameterDef = { + name: string; + type?: string; + description: string | ReactNode; + required?: boolean; + default?: string; + children?: Array; +}; + +type ParameterProps = { + parameter: ParameterDef; + isLast: boolean; +}; + +const COMMON_PARAMS: Record = { + asChild: { + name: "asChild", + type: "boolean", + default: "false", + description: ( + <> + Change the default rendered element for the one passed as a child, + merging their props and behavior. +
+
+ Read the{" "} + + Composition + {" "} + guide for more details. + + ), + }, +}; + +const Parameter: FC = ({ + parameter: partialParameter, + isLast, +}) => { + const parameter = { + ...COMMON_PARAMS[partialParameter.name], + ...partialParameter, + }; + + return ( +
+
+

+ {parameter.name} + {!parameter.required && !parameter.default && "?"} + {!!parameter.type && ":"} +

+
+ {parameter.type} + {parameter.default && ` = ${parameter.default}`} +
+
+
+
+

{parameter.description}

+
+ {parameter.children?.map((property) => ( + + ))} +
+ ); +}; + +const ParametersList = ({ + parameters, +}: { + parameters: Array; +}) => { + return parameters.map((parameter, idx) => ( + + )); +}; +const ParametersBox: FC = ({ type, parameters }) => { + return ( +
+ {!!type && ( +

+ {type} +

+ )} + +
+ ); +}; + +export type ParametersTableProps = { + type?: string | undefined; + parameters: Array; +}; + +export const ParametersTable: FC = ({ + type, + parameters, +}) => { + return ( +
+ +
+ ); +}; diff --git a/apps/docs/components/docs/index.ts b/apps/docs/components/docs/index.ts new file mode 100644 index 000000000..1a807541f --- /dev/null +++ b/apps/docs/components/docs/index.ts @@ -0,0 +1,3 @@ +export { KeyboardTable } from "./KeyboardTable"; +export { DataAttributesTable } from "./DataAttributesTable"; +export { ParametersTable } from "./ParametersTable"; diff --git a/apps/docs/components/docs/parameters/context.tsx b/apps/docs/components/docs/parameters/context.tsx new file mode 100644 index 000000000..7302092c3 --- /dev/null +++ b/apps/docs/components/docs/parameters/context.tsx @@ -0,0 +1,402 @@ +import { ParametersTableProps } from "../ParametersTable"; + +export const AssistantActionsState: ParametersTableProps = { + type: "AssistantActionsState", + parameters: [ + { + name: "switchToThread", + type: "(threadId: string | null) => void", + description: "Switch to a new thread.", + required: true, + }, + ], +}; + +export const AssistantModelConfigState: ParametersTableProps = { + type: "AssistantModelConfigState", + parameters: [ + { + name: "getModelConfig", + type: "() => ModelConfig", + description: "Gets the current model config.", + required: true, + children: [ + { + 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: "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: [ + { + 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, + }, + ], +}; + +export const AssistantContextValue: ParametersTableProps = { + type: "AssistantContextValue", + parameters: [ + { + name: "useAssistantActions", + type: "ReadonlyStore", + required: true, + description: "Provides functions to perform actions on the assistant.", + }, + { + 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: "isRunning", + type: "boolean", + required: true, + description: "Whether the thread is running.", + }, + ], +}; + +export const ThreadMessagesState: ParametersTableProps = { + type: "ThreadMessagesState", + parameters: [ + { + name: "messages", + type: "readonly ThreadMessage[]", + required: true, + description: "The messages in the thread.", + }, + ], +}; + +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: "canCancel", + type: "true", + required: true, + description: "Whether the composer can be canceled.", + }, + { + 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: "() => void", + required: true, + description: "A function to cancel the run.", + }, + { + name: "focus", + type: "() => void", + required: true, + description: "A function to focus the composer.", + }, + { + name: "onFocus", + type: "(listener: () => void) => Unsubscribe", + required: true, + description: "A function to subscribe to focus events.", + }, + ], +}; + +export const EditComposerState: ParametersTableProps = { + type: "EditComposerState", + parameters: [ + ...BaseComposerState.parameters, + { + name: "canCancel", + type: "boolean", + required: true, + description: "Whether the composer can be canceled.", + }, + { + 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: "() => void", + required: true, + description: "A function to exit the edit mode.", + }, + ], +}; + +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: "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/docs/components/docs/parameters/runtime.tsx b/apps/docs/components/docs/parameters/runtime.tsx new file mode 100644 index 000000000..8531380ce --- /dev/null +++ b/apps/docs/components/docs/parameters/runtime.tsx @@ -0,0 +1,126 @@ +import { ParametersTable } from "@/components/docs"; + +export const AssistantRuntimeProviderProps = () => { + return ( + 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.", + }, + { + name: "subscribe", + type: "(callback: () => void) => Unsubscribe", + required: true, + description: "A function to subscribe to updates.", + }, + { + name: "registerModelConfigProvider", + type: "(provider: ModelConfigProvider) => Unsubscribe", + required: true, + description: + "A function to register a model config provider.", + }, + ], + }, + ], + }, + ]} + /> + ); +}; diff --git a/apps/docs/components/genui/GenUI.tsx b/apps/docs/components/genui/GenUI.tsx new file mode 100644 index 000000000..87d796b21 --- /dev/null +++ b/apps/docs/components/genui/GenUI.tsx @@ -0,0 +1,9 @@ +export const GenUI = () => { + return ( +