Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agent UI v1.5 #277

Merged
merged 8 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 204 additions & 0 deletions agenthub/app/agentchat/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
'use client'

import React, { useState, useRef, useEffect } from 'react';
import { ChatEditor } from '@/components/chat/editor/Editor';
import { useMounted } from '@/lib/mounted';

import { Message, Chat } from '@/interfaces/agentchat';
import { Sidebar } from '@/components/agentchat/Sidebar';
import { Header } from '@/components/agentchat/Header';
import { MessageList } from '@/components/agentchat/MessageList';
import axios from 'axios';
import { AgentCommand } from '@/components/chat/body/message-box';
import { baseUrl, serverUrl } from '@/lib/env';



const updateChatName = (chatId: number, newName: string) => {
// setChats(prevChats =>
// prevChats.map(chat =>
// chat.id === chatId ? { ...chat, name: newName } : chat
// )
// );
};








const ChatInterface: React.FC = () => {
const [messages, setMessages] = useState<Message[]>([]);
const [darkMode, setDarkMode] = useState<boolean>(false);
const [chats, setChats] = useState<Chat[]>([{ id: 1, name: 'General' }]);
const [activeChat, setActiveChat] = useState<number>(1);
const messagesEndRef = useRef<HTMLDivElement>(null);

function parseText(input: string): string {
// Step 1: Replace mention spans with the custom format
let parsed = input.replace(/<span class="mention" data-type="mention" data-id="([^"]+)">@[^<]+<\/span>/g, '?>>$1/?>>');

// Step 2: Convert <br> tags to newlines
parsed = parsed.replace(/<br[^>]*>/g, '\n');

// Step 3: Remove all remaining HTML tags
parsed = parsed.replace(/<[^>]+>/g, '');

// Decode HTML entities (e.g., &quot;, &amp;)
parsed = parsed.replace(/&quot;/g, '"')
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&#39;/g, "'");

return parsed.trim();
}

interface MessageBundle {
name: string;
content: string;
}


function parseNamedContent(inputString: string) {
// Regular expression to match the pattern ?>>Name/?>>\s*Content
const regex = /\?>>(.*?)\/?>>([^?]*)/g;
const results = [];

// Find all matches
let match;
while ((match = regex.exec(inputString)) !== null) {
// Extract name and content, trim whitespace
const name = match[1].trim().slice(0, -2);
// Preserve newlines in content but trim surrounding whitespace
const content = match[2].replace(/^\s+|\s+$/g, '');

results.push({
name,
content
});
}

return results;
}

// Ex


useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);

const handleSend = async (content: string, attachments: File[]) => {
if (content.trim() || attachments.length > 0) {
const newMessage: Message = {
id: Date.now(),
text: content,
sender: 'user',
timestamp: new Date(),
attachments: attachments.map(file => file.name),
thinking: false
};
setMessages([...messages, newMessage]);

let messageId = Date.now();

// Handle file uploads here (e.g., to a server)
const botMessage: Message = {
id: messageId,
text: ``,
sender: 'bot',
timestamp: new Date(),
thinking: true
};

setMessages(prevMessages => [...prevMessages, botMessage]);

const res = await _(parseNamedContent(parseText(content))[0] as AgentCommand)

setMessages(prevMessages => [...prevMessages].map(message => {
if (message.id == messageId) {
return { ...message, thinking: false };
}
return res.content;
}));
}
};

const addChat = () => {
const newChat: Chat = { id: Date.now(), name: `Chat ${chats.length + 1}` };
setChats([...chats, newChat]);
setActiveChat(newChat.id);
};

const _ = async (command: AgentCommand) => {
const addAgentResponse = await axios.post(`${baseUrl}/api/proxy`, {
type: 'POST',
url: `${serverUrl}/add_agent`,
payload: {
agent_name: command.name,
task_input: command.content,
}
});

console.log(addAgentResponse.data);

// Wait for 1050ms
await new Promise(resolve => setTimeout(resolve, 1050));

let recent_response: any;

try {
// Second request: Execute agent
const executeAgentResponse = await axios.post(`${baseUrl}/api/proxy`, {
type: 'GET',
url: `${serverUrl}/execute_agent?pid=${addAgentResponse.data.pid}`,
});

console.log(executeAgentResponse.data);
recent_response = executeAgentResponse.data.response.result.content;

if (typeof recent_response !== 'string') {
recent_response = "Agent Had Difficulty Thinking"
}
} catch (e) {
recent_response = "Agent Had Difficulty Thinking"
}


//return recent_response
return {
name: command.name,
content: recent_response
};
}

const mounted = useMounted();

return (
<div className={`flex h-screen ${darkMode ? 'bg-gray-900' : 'bg-gray-50'}`}>
<Sidebar
chats={chats}
activeChat={activeChat}
setActiveChat={setActiveChat}
addChat={addChat}
updateChatName={updateChatName}
darkMode={darkMode}
/>
<div className="flex flex-col flex-grow pb-4">
<Header darkMode={darkMode} setDarkMode={setDarkMode} />
<MessageList messages={messages} darkMode={darkMode} />
<div className='w-full flex h-fit justify-center'>
{mounted && <ChatEditor onSend={handleSend} darkMode={darkMode} />}
</div>

<div ref={messagesEndRef} />
</div>
</div>
);
};


export default ChatInterface;
28 changes: 18 additions & 10 deletions agenthub/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ import '@/styles/google-font-Source-Sans-Pro.css'
import '@/styles/google-font-IBM-Plex-Mono.css'
import "./globals.css";
import "./ts.css"
import '@mantine/core/styles.css';

import { ColorSchemeScript, MantineProvider } from '@mantine/core';

export const metadata: Metadata = {
title: 'AIOS – The future of AI Agents',
Expand Down Expand Up @@ -72,18 +75,23 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<link rel="alternate" type="application/rss+xml" href="/blog/feed.xml" title="Hugging Face Blog" />
<script defer data-domain="huggingface.co" src="/js/script.js"></script>
</Head> */}
<head>
<ColorSchemeScript />
</head>
<body>
<Providers>
<main
className="HomePage flex min-h-screen flex-col text-black bg-white dark:bg-gray-950"
style={{ fontSize: 16 }}
>
<div className="flex min-h-screen flex-col">
<NavHeader />
{/* <div className='w-full bg-inherit opacity-0 h-[24px]'></div> */}
{children}
</div>
</main>
<MantineProvider>
<main
className="HomePage flex min-h-screen flex-col text-black bg-white dark:bg-gray-950"
style={{ fontSize: 16 }}
>
<div className="flex min-h-screen flex-col">
{/* <NavHeader /> */}
{/* <div className='w-full bg-inherit opacity-0 h-[24px]'></div> */}
{children}
</div>
</main>
</MantineProvider>
</Providers>
</body>
</html>
Expand Down
31 changes: 31 additions & 0 deletions agenthub/components/agentchat/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';

import { Switch, useMantineTheme } from '@mantine/core';
import { Sun, Moon, Hash } from 'lucide-react';

export interface HeaderProps {
darkMode: boolean;
setDarkMode: React.Dispatch<React.SetStateAction<boolean>>;
}

export const Header: React.FC<HeaderProps> = ({ darkMode, setDarkMode }) => {
const theme = useMantineTheme();
return (
<div className={`flex justify-between items-center p-3 border-b ${darkMode ? 'bg-gray-900 text-white border-gray-800' : 'bg-white text-black border-gray-200'}`}>
<div className="flex items-center space-x-2">
<Hash size={20} className="text-gray-500" />
<h1 className="text-lg font-medium">General</h1>
</div>
<div className="flex items-center space-x-2">
<Sun size={16} className={darkMode ? 'text-gray-400' : 'text-yellow-500'} />
<Switch
checked={darkMode}
onChange={(event) => setDarkMode(event.currentTarget.checked)}
size="sm"
color={theme.primaryColor}
/>
<Moon size={16} className={darkMode ? 'text-blue-400' : 'text-gray-400'} />
</div>
</div>
);
};
Loading
Loading