Merge branch 'main' of https://github.com/langchain-ai/agent-ui-demo into brace/open-code
This commit is contained in:
4
.dockerignore
Normal file
4
.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
.next
|
||||
.git
|
||||
.env
|
||||
@@ -1,4 +1,7 @@
|
||||
# agent-ui demo
|
||||
# Chat LangGraph
|
||||
|
||||
> [!WARNING]
|
||||
> This repo is still a work in progress and is not intended for use. Estimated launch date 03/11. Thank you for your patience.
|
||||
|
||||
## Setup
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ export default function PortfolioView() {
|
||||
const chartData = selectedHolding ? generateChartData(selectedHolding) : [];
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-4xl bg-white rounded-xl shadow-lg overflow-hidden border border-gray-200">
|
||||
<div className="w-full max-w-3xl bg-white rounded-xl shadow-lg overflow-hidden border border-gray-200">
|
||||
<div className="bg-gradient-to-r from-indigo-700 to-indigo-500 px-6 py-4">
|
||||
<div className="flex justify-between items-center">
|
||||
<h2 className="text-white font-bold text-xl tracking-tight flex items-center">
|
||||
|
||||
@@ -149,7 +149,7 @@ export default function StockPrice(props: {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-4xl rounded-xl shadow-md overflow-hidden border border-gray-200 flex flex-col gap-4 p-3">
|
||||
<div className="w-full max-w-3xl rounded-xl shadow-md overflow-hidden border border-gray-200 flex flex-col gap-4 p-3">
|
||||
<div className="flex items-center justify-start gap-4 mb-2 text-lg font-medium text-gray-700">
|
||||
<p>{ticker}</p>
|
||||
<p>${currentPrice}</p>
|
||||
|
||||
@@ -320,7 +320,7 @@ export default function AccommodationsList({
|
||||
align: "start",
|
||||
loop: true,
|
||||
}}
|
||||
className="w-full sm:max-w-sm md:max-w-2xl lg:max-w-3xl"
|
||||
className="w-full sm:max-w-sm md:max-w-3xl lg:max-w-3xl"
|
||||
>
|
||||
<CarouselContent>
|
||||
{accommodations.map((accommodation) => (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>LangGraph Chat</title>
|
||||
<title>Chat LangGraph</title>
|
||||
<link href="/src/styles.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
{
|
||||
"node_version": "20",
|
||||
"graphs": {
|
||||
"agent": "./agent/agent.tsx:graph"
|
||||
"agent": "./agent/agent.ts:graph"
|
||||
},
|
||||
"ui": {
|
||||
"agent": "./agent/uis/index.tsx"
|
||||
},
|
||||
"_INTERNAL_docker_tag": "20",
|
||||
"env": ".env",
|
||||
"dependencies": ["."]
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ export default function ThreadHistory() {
|
||||
variant="ghost"
|
||||
onClick={() => setChatHistoryOpen((p) => !p)}
|
||||
>
|
||||
<PanelRightOpen />
|
||||
<PanelRightOpen className="size-5" />
|
||||
</Button>
|
||||
<h1 className="text-xl font-semibold tracking-tight">
|
||||
Thread History
|
||||
|
||||
@@ -4,7 +4,6 @@ import { motion } from "framer-motion";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useStreamContext } from "@/providers/Stream";
|
||||
import { useState, FormEvent } from "react";
|
||||
import { Input } from "../ui/input";
|
||||
import { Button } from "../ui/button";
|
||||
import { Checkpoint, Message } from "@langchain/langgraph-sdk";
|
||||
import { AssistantMessage, AssistantMessageLoading } from "./messages/ai";
|
||||
@@ -218,7 +217,7 @@ export function Thread() {
|
||||
variant="ghost"
|
||||
onClick={() => setChatHistoryOpen((p) => !p)}
|
||||
>
|
||||
<PanelRightOpen />
|
||||
<PanelRightOpen className="size-5" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@@ -233,7 +232,7 @@ export function Thread() {
|
||||
variant="ghost"
|
||||
onClick={() => setChatHistoryOpen((p) => !p)}
|
||||
>
|
||||
<PanelRightOpen />
|
||||
<PanelRightOpen className="size-5" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@@ -251,7 +250,7 @@ export function Thread() {
|
||||
>
|
||||
<LangGraphLogoSVG width={32} height={32} />
|
||||
<span className="text-xl font-semibold tracking-tight">
|
||||
LangGraph Chat
|
||||
Chat LangGraph
|
||||
</span>
|
||||
</motion.button>
|
||||
</div>
|
||||
@@ -277,7 +276,7 @@ export function Thread() {
|
||||
!chatStarted && "flex flex-col items-stretch mt-[25vh]",
|
||||
chatStarted && "grid grid-rows-[1fr_auto]",
|
||||
)}
|
||||
contentClassName="pt-8 pb-16 px-4 max-w-4xl mx-auto flex flex-col gap-4 w-full"
|
||||
contentClassName="pt-8 pb-16 max-w-3xl mx-auto flex flex-col gap-4 w-full"
|
||||
content={
|
||||
<>
|
||||
{messages
|
||||
@@ -304,29 +303,36 @@ export function Thread() {
|
||||
</>
|
||||
}
|
||||
footer={
|
||||
<div className="sticky flex flex-col items-center gap-8 bottom-8 px-4">
|
||||
<div className="sticky flex flex-col items-center gap-8 bottom-0 px-4 bg-white">
|
||||
{!chatStarted && (
|
||||
<div className="flex gap-3 items-center">
|
||||
<LangGraphLogoSVG className="flex-shrink-0 h-8" />
|
||||
<h1 className="text-2xl font-semibold tracking-tight">
|
||||
LangGraph Chat
|
||||
Chat LangGraph
|
||||
</h1>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ScrollToBottom className="absolute bottom-full left-1/2 -translate-x-1/2 mb-4 animate-in fade-in-0 zoom-in-95" />
|
||||
|
||||
<div className="bg-background rounded-2xl border shadow-md mx-auto w-full max-w-4xl relative z-10">
|
||||
<div className="bg-muted rounded-2xl border shadow-xs mx-auto mb-8 w-full max-w-3xl relative z-10">
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className="grid grid-rows-[1fr_auto] gap-2 max-w-4xl mx-auto"
|
||||
className="grid grid-rows-[1fr_auto] gap-2 max-w-3xl mx-auto"
|
||||
>
|
||||
<Input
|
||||
type="text"
|
||||
<textarea
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey && !e.metaKey) {
|
||||
e.preventDefault();
|
||||
const el = e.target as HTMLElement | undefined;
|
||||
const form = el?.closest("form");
|
||||
form?.requestSubmit();
|
||||
}
|
||||
}}
|
||||
placeholder="Type your message..."
|
||||
className="px-4 py-6 border-none bg-transparent shadow-none ring-0 outline-none focus:outline-none focus:ring-0"
|
||||
className="p-3.5 pb-0 border-none bg-transparent field-sizing-content shadow-none ring-0 outline-none focus:outline-none focus:ring-0 resize-none"
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-end p-2 pt-0">
|
||||
@@ -338,6 +344,7 @@ export function Thread() {
|
||||
) : (
|
||||
<Button
|
||||
type="submit"
|
||||
className="transition-all shadow-md"
|
||||
disabled={isLoading || !input.trim()}
|
||||
>
|
||||
Send
|
||||
|
||||
@@ -2,11 +2,11 @@ import { useStreamContext } from "@/providers/Stream";
|
||||
import { Checkpoint, Message } from "@langchain/langgraph-sdk";
|
||||
import { getContentString } from "../utils";
|
||||
import { BranchSwitcher, CommandBar } from "./shared";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { MarkdownText } from "../markdown-text";
|
||||
import { LoadExternalComponent } from "@langchain/langgraph-sdk/react-ui";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ToolCalls, ToolResult } from "./tool-calls";
|
||||
import { StringParam, useQueryParam } from "use-query-params";
|
||||
|
||||
function CustomComponent({
|
||||
message,
|
||||
@@ -15,6 +15,7 @@ function CustomComponent({
|
||||
message: Message;
|
||||
thread: ReturnType<typeof useStreamContext>;
|
||||
}) {
|
||||
const [apiUrl] = useQueryParam("apiUrl", StringParam);
|
||||
const meta = thread.getMessagesMetadata(message);
|
||||
const seenState = meta?.firstSeenState;
|
||||
const customComponent = seenState?.values.ui
|
||||
@@ -33,6 +34,7 @@ function CustomComponent({
|
||||
<div key={message.id}>
|
||||
{customComponent && (
|
||||
<LoadExternalComponent
|
||||
apiUrl={apiUrl ?? undefined}
|
||||
assistantId="agent"
|
||||
stream={thread}
|
||||
message={customComponent}
|
||||
@@ -66,20 +68,17 @@ export function AssistantMessage({
|
||||
|
||||
return (
|
||||
<div className="flex items-start mr-auto gap-2 group">
|
||||
<Avatar>
|
||||
<AvatarFallback>A</AvatarFallback>
|
||||
</Avatar>
|
||||
{isToolResult ? (
|
||||
<ToolResult message={message} />
|
||||
) : (
|
||||
<div className="flex flex-col gap-2">
|
||||
{hasToolCalls && <ToolCalls toolCalls={message.tool_calls} />}
|
||||
<CustomComponent message={message} thread={thread} />
|
||||
{contentString.length > 0 && (
|
||||
<div className="rounded-2xl bg-muted px-4 py-2">
|
||||
<div className="py-1">
|
||||
<MarkdownText>{contentString}</MarkdownText>
|
||||
</div>
|
||||
)}
|
||||
{hasToolCalls && <ToolCalls toolCalls={message.tool_calls} />}
|
||||
<CustomComponent message={message} thread={thread} />
|
||||
<div
|
||||
className={cn(
|
||||
"flex gap-2 items-center mr-auto transition-opacity",
|
||||
@@ -108,9 +107,6 @@ export function AssistantMessage({
|
||||
export function AssistantMessageLoading() {
|
||||
return (
|
||||
<div className="flex items-start mr-auto gap-2">
|
||||
<Avatar>
|
||||
<AvatarFallback>A</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex items-center gap-1 rounded-2xl bg-muted px-4 py-2 h-8">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-foreground/50 animate-[pulse_1.5s_ease-in-out_infinite]"></div>
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-foreground/50 animate-[pulse_1.5s_ease-in-out_0.5s_infinite]"></div>
|
||||
|
||||
@@ -84,7 +84,7 @@ export function HumanMessage({
|
||||
onSubmit={handleSubmitEdit}
|
||||
/>
|
||||
) : (
|
||||
<p className="text-right py-1">{contentString}</p>
|
||||
<p className="text-right px-4 py-2 rounded-3xl bg-muted">{contentString}</p>
|
||||
)}
|
||||
|
||||
<div
|
||||
|
||||
@@ -89,16 +89,16 @@ export const StreamProvider: React.FC<{ children: ReactNode }> = ({
|
||||
if (!apiUrl || !assistantId) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen w-full p-4">
|
||||
<div className="animate-in fade-in-0 zoom-in-95 flex flex-col border bg-background shadow-lg rounded-lg max-w-2xl">
|
||||
<div className="animate-in fade-in-0 zoom-in-95 flex flex-col border bg-background shadow-lg rounded-lg max-w-3xl">
|
||||
<div className="flex flex-col gap-2 mt-14 p-6 border-b">
|
||||
<div className="flex items-start flex-col gap-2">
|
||||
<LangGraphLogoSVG className="h-7" />
|
||||
<h1 className="text-xl font-semibold tracking-tight">
|
||||
LangGraph Chat
|
||||
Chat LangGraph
|
||||
</h1>
|
||||
</div>
|
||||
<p className="text-muted-foreground">
|
||||
Welcome to LangGraph Chat! Before you get started, you need to
|
||||
Welcome to Chat LangGraph! Before you get started, you need to
|
||||
enter the URL of the deployment and the assistant / graph ID.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user