diff --git a/apps/docs/content/docs/runtimes/langgraph/index.mdx b/apps/docs/content/docs/runtimes/langgraph/index.mdx index d1024196f..24cb06d8a 100644 --- a/apps/docs/content/docs/runtimes/langgraph/index.mdx +++ b/apps/docs/content/docs/runtimes/langgraph/index.mdx @@ -27,7 +27,9 @@ npx assistant-ui@latest create -t langgraph my-app Create a `.env.local` file in your project with the following variables: ```sh -NEXT_PUBLIC_LANGGRAPH_API_URL=your_api_url +# LANGCHAIN_API_KEY=your_api_key # for production +# LANGGRAPH_API_URL=your_api_url # for production +NEXT_PUBLIC_LANGGRAPH_API_URL=your_api_url # for development (no api key required) NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID=your_graph_id ``` @@ -43,53 +45,6 @@ NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID=your_graph_id ```sh npm2yarn npm install @assistant-ui/react @assistant-ui/react-langgraph @langchain/langgraph-sdk -``` - - - - -### Setup helper functions - - - This example connects to the LangGraph server directly from the browser. For - production use-cases, you should use a proxy server (see below). - - -```tsx twoslash include chatApi title="@/lib/chatApi.ts" -// @filename: /lib/chatApi.ts - -// ---cut--- -import { Client } from "@langchain/langgraph-sdk"; -import { LangChainMessage } from "@assistant-ui/react-langgraph"; - -const createClient = () => { - const apiUrl = process.env["NEXT_PUBLIC_LANGGRAPH_API_URL"] || "/api"; - return new Client({ - apiUrl, - }); -}; - -export const createThread = async () => { - const client = createClient(); - return client.threads.create(); -}; - -export const sendMessage = async (params: { - threadId: string; - messages: LangChainMessage; -}) => { - const client = createClient(); - return client.runs.stream( - params.threadId, - process.env["NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID"]!, - { - input: { - messages: params.messages, - }, - streamMode: "messages", - }, - ); -}; ``` @@ -176,25 +131,74 @@ export const OPTIONS = () => { -### Define a `MyRuntimeProvider` component +### Setup helper functions -```tsx twoslash include MyRuntimeProvider title="@/app/MyRuntimeProvider.tsx" -// @filename: /app/MyRuntimeProvider.tsx +```tsx twoslash include chatApi title="@/lib/chatApi.ts" +// @filename: /lib/chatApi.ts + +// ---cut--- +import { Client } from "@langchain/langgraph-sdk"; +import { LangChainMessage } from "@assistant-ui/react-langgraph"; + +const createClient = () => { + const apiUrl = process.env["NEXT_PUBLIC_LANGGRAPH_API_URL"] || "/api"; + return new Client({ + apiUrl, + }); +}; + +export const createThread = async () => { + const client = createClient(); + return client.threads.create(); +}; + +export const getThreadState = async ( + threadId: string, +): Promise> => { + const client = createClient(); + return client.threads.getState(threadId); +}; + +export const sendMessage = async (params: { + threadId: string; + messages: LangChainMessage; +}) => { + const client = createClient(); + return client.runs.stream( + params.threadId, + process.env["NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID"]!, + { + input: { + messages: params.messages, + }, + streamMode: "messages", + }, + ); +}; +``` + + + + +### Define a `MyAssistant` component + +```tsx twoslash include MyAssistant title="@/components/MyAssistant.tsx" +// @filename: /components/MyAssistant.tsx // @include: chatApi // ---cut--- "use client"; import { useRef } from "react"; -import { AssistantRuntimeProvider } from "@assistant-ui/react"; +import { Thread } from "@assistant-ui/react"; import { useLangGraphRuntime } from "@assistant-ui/react-langgraph"; -import { createThread, sendMessage } from "@/lib/chatApi"; +import { makeMarkdownText } from "@assistant-ui/react-markdown"; + +import { createThread, getThreadState, sendMessage } from "@/lib/chatApi"; -export function MyRuntimeProvider({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { +const MarkdownText = makeMarkdownText(); + +export function MyAssistant() { const threadIdRef = useRef(); const runtime = useLangGraphRuntime({ threadId: threadIdRef.current, @@ -209,12 +213,22 @@ export function MyRuntimeProvider({ messages, }); }, + onSwitchToNewThread: async () => { + const { thread_id } = await createThread(); + threadIdRef.current = thread_id; + }, + onSwitchToThread: async (threadId) => { + const state = await getThreadState(threadId); + threadIdRef.current = threadId; + return { messages: state.values.messages }; + }, }); return ( - - {children} - + ); } ``` @@ -222,24 +236,19 @@ export function MyRuntimeProvider({ -### Wrap your app in `MyRuntimeProvider` +### Use the `MyAssistant` component -```tsx twoslash title="@/app/layout.tsx" {2,8,12} -// @include: MyRuntimeProvider -// @filename: /app/layout.tsx +```tsx twoslash title="@/app/page.tsx" {2,8} +// @include: MyAssistant +// @filename: /app/page.tsx // ---cut--- -import { ReactNode } from "react"; -import { MyRuntimeProvider } from "@/app/MyRuntimeProvider"; +import { MyAssistant } from "@/components/MyAssistant"; -export default function RootLayout({ - children, -}: Readonly<{ children: ReactNode }>) { +export default function Home() { return ( - - - {children} - - +
+ +
); } ```