forked from elizaOS/eliza
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add agent selection, router and sidebar layout in React client
- Loading branch information
Showing
23 changed files
with
2,541 additions
and
553 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export default function Agent() { | ||
return ( | ||
<div className="min-h-screen flex flex-col items-center justify-center p-4"> | ||
<p className="text-lg text-gray-600"> | ||
Select an option from the sidebar to configure, view, or chat | ||
with your ELIZA agent | ||
</p> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { useQuery } from "@tanstack/react-query"; | ||
import { Button } from "@/components/ui/button"; | ||
import { useNavigate } from "react-router-dom"; | ||
import "./App.css"; | ||
|
||
type Agent = { | ||
id: string; | ||
name: string; | ||
}; | ||
|
||
function Agents() { | ||
const navigate = useNavigate(); | ||
const { data: agents, isLoading } = useQuery({ | ||
queryKey: ["agents"], | ||
queryFn: async () => { | ||
const res = await fetch("/api/agents"); | ||
const data = await res.json(); | ||
return data.agents as Agent[]; | ||
}, | ||
}); | ||
|
||
return ( | ||
<div className="min-h-screen flex flex-col items-center justify-center p-4"> | ||
<h1 className="text-2xl font-bold mb-8">Select your agent:</h1> | ||
|
||
{isLoading ? ( | ||
<div>Loading agents...</div> | ||
) : ( | ||
<div className="grid gap-4 w-full max-w-md"> | ||
{agents?.map((agent) => ( | ||
<Button | ||
key={agent.id} | ||
className="w-full text-lg py-6" | ||
onClick={() => { | ||
navigate(`/${agent.id}`); | ||
}} | ||
> | ||
{agent.name} | ||
</Button> | ||
))} | ||
</div> | ||
)} | ||
</div> | ||
); | ||
} | ||
|
||
export default Agents; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
#root { | ||
max-width: 1280px; | ||
margin: 0 auto; | ||
padding: 2rem; | ||
text-align: center; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export default function Character() { | ||
return ( | ||
<div className="min-h-screen w-full flex flex-col items-center justify-center p-4"> | ||
<p className="text-lg text-gray-600">WIP</p> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { useState } from "react"; | ||
import { useParams } from "react-router-dom"; | ||
import { useMutation } from "@tanstack/react-query"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Button } from "@/components/ui/button"; | ||
import "./App.css"; | ||
|
||
type TextResponse = { | ||
text: string; | ||
user: string; | ||
}; | ||
|
||
export default function Chat() { | ||
const { agentId } = useParams(); | ||
const [input, setInput] = useState(""); | ||
const [messages, setMessages] = useState<TextResponse[]>([]); | ||
|
||
const mutation = useMutation({ | ||
mutationFn: async (text: string) => { | ||
const res = await fetch(`/api/${agentId}/message`, { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, | ||
body: JSON.stringify({ | ||
text, | ||
userId: "user", | ||
roomId: `default-room-${agentId}`, | ||
}), | ||
}); | ||
return res.json() as Promise<TextResponse[]>; | ||
}, | ||
onSuccess: (data) => { | ||
setMessages((prev) => [...prev, ...data]); | ||
}, | ||
}); | ||
|
||
const handleSubmit = async (e: React.FormEvent) => { | ||
e.preventDefault(); | ||
if (!input.trim()) return; | ||
|
||
// Add user message immediately to state | ||
const userMessage: TextResponse = { | ||
text: input, | ||
user: "user", | ||
}; | ||
setMessages((prev) => [...prev, userMessage]); | ||
|
||
mutation.mutate(input); | ||
setInput(""); | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-col h-screen max-h-screen w-full"> | ||
<div className="flex-1 min-h-0 overflow-y-auto p-4"> | ||
<div className="max-w-3xl mx-auto space-y-4"> | ||
{messages.length > 0 ? ( | ||
messages.map((message, index) => ( | ||
<div | ||
key={index} | ||
className={`flex ${ | ||
message.user === "user" | ||
? "justify-end" | ||
: "justify-start" | ||
}`} | ||
> | ||
<div | ||
className={`max-w-[80%] rounded-lg px-4 py-2 ${ | ||
message.user === "user" | ||
? "bg-primary text-primary-foreground" | ||
: "bg-muted" | ||
}`} | ||
> | ||
{message.text} | ||
</div> | ||
</div> | ||
)) | ||
) : ( | ||
<div className="text-center text-muted-foreground"> | ||
No messages yet. Start a conversation! | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
|
||
<div className="border-t p-4 bg-background"> | ||
<div className="max-w-3xl mx-auto"> | ||
<form onSubmit={handleSubmit} className="flex gap-2"> | ||
<Input | ||
value={input} | ||
onChange={(e) => setInput(e.target.value)} | ||
placeholder="Type a message..." | ||
className="flex-1" | ||
disabled={mutation.isPending} | ||
/> | ||
<Button type="submit" disabled={mutation.isPending}> | ||
{mutation.isPending ? "..." : "Send"} | ||
</Button> | ||
</form> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { SidebarProvider } from "@/components/ui/sidebar"; | ||
import { AppSidebar } from "@/components/app-sidebar"; | ||
import { Outlet } from "react-router-dom"; | ||
|
||
export default function Layout() { | ||
return ( | ||
<SidebarProvider> | ||
<AppSidebar /> | ||
<Outlet /> | ||
</SidebarProvider> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { Calendar, Home, Inbox, Search, Settings } from "lucide-react"; | ||
import { useParams } from "react-router-dom"; | ||
|
||
import { | ||
Sidebar, | ||
SidebarContent, | ||
SidebarGroup, | ||
SidebarGroupContent, | ||
SidebarGroupLabel, | ||
SidebarMenu, | ||
SidebarMenuButton, | ||
SidebarMenuItem, | ||
SidebarTrigger, | ||
} from "@/components/ui/sidebar"; | ||
|
||
// Menu items. | ||
const items = [ | ||
{ | ||
title: "Chat", | ||
url: "chat", | ||
icon: Inbox, | ||
}, | ||
{ | ||
title: "Character Overview", | ||
url: "character", | ||
icon: Calendar, | ||
}, | ||
]; | ||
|
||
export function AppSidebar() { | ||
const { agentId } = useParams(); | ||
|
||
return ( | ||
<Sidebar> | ||
<SidebarContent> | ||
<SidebarGroup> | ||
<SidebarGroupLabel>Application</SidebarGroupLabel> | ||
<SidebarGroupContent> | ||
<SidebarMenu> | ||
{items.map((item) => ( | ||
<SidebarMenuItem key={item.title}> | ||
<SidebarMenuButton asChild> | ||
<a href={`/${agentId}/${item.url}`}> | ||
<item.icon /> | ||
<span>{item.title}</span> | ||
</a> | ||
</SidebarMenuButton> | ||
</SidebarMenuItem> | ||
))} | ||
</SidebarMenu> | ||
</SidebarGroupContent> | ||
</SidebarGroup> | ||
</SidebarContent> | ||
</Sidebar> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
"use client"; | ||
|
||
import * as React from "react"; | ||
import * as SeparatorPrimitive from "@radix-ui/react-separator"; | ||
|
||
import { cn } from "@/lib/utils"; | ||
|
||
const Separator = React.forwardRef< | ||
React.ElementRef<typeof SeparatorPrimitive.Root>, | ||
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root> | ||
>( | ||
( | ||
{ className, orientation = "horizontal", decorative = true, ...props }, | ||
ref | ||
) => ( | ||
<SeparatorPrimitive.Root | ||
ref={ref} | ||
decorative={decorative} | ||
orientation={orientation} | ||
className={cn( | ||
"shrink-0 bg-border", | ||
orientation === "horizontal" | ||
? "h-[1px] w-full" | ||
: "h-full w-[1px]", | ||
className | ||
)} | ||
{...props} | ||
/> | ||
) | ||
); | ||
Separator.displayName = SeparatorPrimitive.Root.displayName; | ||
|
||
export { Separator }; |
Oops, something went wrong.