# Part 2: Generative UI URL: /docs/runtimes/langgraph/tutorial/part-2 Display stock ticker information with generative UI components. In the previous step, we set up the frontend to connect to a LangGraph Cloud endpoint. In this step, we will set up a component to display stock ticker information. import Image from "next/image"; import price from "./images/acme-price.png"; Price snapshot For reference, this the corresponding code in the backend: [https://github.com/assistant-ui/assistant-ui-stockbroker/blob/main/backend/src/tools.ts#L193C1-L216C3](https://github.com/assistant-ui/assistant-ui-stockbroker/blob/main/backend/src/tools.ts#L193C1-L216C3) ```ts title="assistant-ui-stockbroker/backend/tools/PriceSnapshotTool.ts" export const priceSnapshotTool = tool( async (input) => { const data = await callFinancialDatasetAPI({ endpoint: "/prices/snapshot", params: { ticker: input.ticker, }, }); return JSON.stringify(data, null); }, { name: "price_snapshot", description: "Retrieves the current stock price and related market data for a given company.", schema: z.object({ ticker: z.string().describe("The ticker of the company. Example: 'AAPL'"), }), }, ); ``` PriceSnapshotTool \[#pricesnapshottool] We create a new file under `/components/tools/price-snapshot/PriceSnapshotTool.tsx` to define the tool. First, we define the tool arguments and result types: ```ts title="@/components/tools/price-snapshot/PriceSnapshotTool.tsx" type PriceSnapshotToolArgs = { ticker: string; }; type PriceSnapshotToolResult = { snapshot: { price: number; day_change: number; day_change_percent: number; time: string; }; }; ``` Then, we use `makeAssistantToolUI` to define the tool UI: ```tsx title="@/components/tools/price-snapshot/PriceSnapshotTool.tsx" "use client"; import { makeAssistantToolUI } from "@assistant-ui/react"; export const PriceSnapshotTool = makeAssistantToolUI< PriceSnapshotToolArgs, string >({ toolName: "price_snapshot", render: function PriceSnapshotUI({ args, result }) { return (
          price_snapshot({JSON.stringify(args)})
        
); }, }); ``` This simply displays the tool name and arguments passed to it, but not the result. Bind tool UI \[#bind-tool-ui] ```tsx title="@/app/page.tsx" {1,8} import { PriceSnapshotTool } from "@/components/tools/price-snapshot/PriceSnapshotTool"; export default function Home() { return (
); } ``` Try it out! \[#try-it-out] Ask the assistant for the current stock price of Tesla. You should see the following text appear: ``` price_snapshot({ticker: "TSLA"}) ``` Next, we will visualize the function's result. Visualizing tool results \[#visualizing-tool-results] Install dependencies \[#install-dependencies] The tool result component relies on shadcn/ui's `Card` component. We will install it as a dependency. ```sh npx shadcn@latest add card ``` You will be prompted to setup a `components.json` file, after this step, a `card` UI component will be installed in your project. Add PriceSnapshot \[#add-pricesnapshot] We create a new file under `/components/tools/price-snapshot/price-snapshot.tsx` to define the new tool result UI. ```tsx title="@/components/tools/price-snapshot/price-snapshot.tsx" "use client"; import { ArrowDownIcon, ArrowUpIcon } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; type PriceSnapshotToolArgs = { ticker: string; }; type PriceSnapshotToolResult = { price: number; day_change: number; day_change_percent: number; time: string; }; export function PriceSnapshot({ ticker, price, day_change, day_change_percent, time, }: PriceSnapshotToolArgs & PriceSnapshotToolResult) { const isPositiveChange = day_change >= 0; const changeColor = isPositiveChange ? "text-green-600" : "text-red-600"; const ArrowIcon = isPositiveChange ? ArrowUpIcon : ArrowDownIcon; return ( {ticker}

${price?.toFixed(2)}

Day Change

$ {Math.abs(day_change)?.toFixed(2)} ( {Math.abs(day_change_percent)?.toFixed(2)}%)

Last Updated

{new Date(time).toLocaleTimeString()}

); } ``` Update PriceSnapshotTool \[#update-pricesnapshottool] We will import the new `` component and use it in the `render` function whenever a tool result is available. ```tsx title="@/components/tools/price-snapshot/PriceSnapshotTool.tsx" {3,25-30,37-42} "use client"; import { PriceSnapshot } from "./price-snapshot"; import { makeAssistantToolUI } from "@assistant-ui/react"; type PriceSnapshotToolArgs = { ticker: string; }; type PriceSnapshotToolResult = { snapshot: { price: number; day_change: number; day_change_percent: number; time: string; }; }; export const PriceSnapshotTool = makeAssistantToolUI< PriceSnapshotToolArgs, string >({ toolName: "price_snapshot", render: function PriceSnapshotUI({ args, result }) { let resultObj: PriceSnapshotToolResult | { error: string }; try { resultObj = result ? JSON.parse(result) : {}; } catch (e) { resultObj = { error: result! }; } return (
          price_snapshot({JSON.stringify(args)})
        
{"snapshot" in resultObj && ( )} {"error" in resultObj && (

{resultObj.error}

)}
); }, }); ``` Try it out! \[#try-it-out-1] Ask the assistant for the current stock price of Tesla. You should see the tool result appear: import price2 from "./images/tsla-price.png"; Price snapshot result Fallback tool UI \[#fallback-tool-ui] Instead of defining a custom tool UI for every tool, we can also define a fallback UI for all tools that are not explicitly defined. This requires shadcn/ui's `Button` component. We will install it as a dependency. ```sh npx shadcn@latest add button ``` Then create a new file under `/components/tools/ToolFallback.tsx` to define the fallback UI. ```tsx title="@/components/tools/ToolFallback.tsx" import { ToolCallMessagePartComponent } from "@assistant-ui/react"; import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"; import { useState } from "react"; import { Button } from "@/components/ui/button"; export const ToolFallback: ToolCallMessagePartComponent = ({ toolName, argsText, result, }) => { const [isCollapsed, setIsCollapsed] = useState(true); return (

Used tool: {toolName}

{!isCollapsed && (
{argsText}
{result !== undefined && (

Result:

                {typeof result === "string"
                  ? result
                  : JSON.stringify(result, null, 2)}
              
)}
)}
); }; ``` Bind fallback UI \[#bind-fallback-ui] ```tsx title="@/app/page.tsx" {1,8} import { ToolFallback } from "@/components/tools/ToolFallback"; export default function Home() { return (
); } ```