This commit is contained in:
marko-kraemer 2025-03-30 23:59:53 -07:00
parent 61bb4c11ae
commit b52fbcafb0
12 changed files with 24 additions and 576 deletions

View File

@ -8,7 +8,6 @@ from typing import AsyncGenerator, Optional, Dict, Any
import sys
from agent.prompt import INSTRUCTIONS
async def run_agent(thread_id: str, stream: bool = True, thread_manager: Optional[ThreadManager] = None):
"""Run the development agent with specified configuration."""

View File

@ -1,57 +0,0 @@
// Add audio effects to the page
document.addEventListener('DOMContentLoaded', () => {
// Create audio context
const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();
// Button click sound
const button = document.querySelector('.glow-button');
button.addEventListener('click', () => {
playClickSound();
});
// Letter hover sound
const letters = document.querySelectorAll('.letter');
letters.forEach(letter => {
letter.addEventListener('mouseenter', () => {
playHoverSound(Math.random() * 200 + 600); // Random frequency for variety
});
});
// Function to play click sound
function playClickSound() {
const oscillator = audioCtx.createOscillator();
const gainNode = audioCtx.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(400, audioCtx.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(20, audioCtx.currentTime + 0.3);
gainNode.gain.setValueAtTime(0.3, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3);
oscillator.start();
oscillator.stop(audioCtx.currentTime + 0.3);
}
// Function to play hover sound
function playHoverSound(frequency) {
const oscillator = audioCtx.createOscillator();
const gainNode = audioCtx.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(frequency, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0.1, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.1);
oscillator.start();
oscillator.stop(audioCtx.currentTime + 0.1);
}
});

View File

@ -1,38 +0,0 @@
// Custom cursor effect
document.addEventListener('DOMContentLoaded', () => {
const cursor = document.querySelector('.custom-cursor');
document.addEventListener('mousemove', (e) => {
cursor.style.left = e.clientX + 'px';
cursor.style.top = e.clientY + 'px';
});
// Expand cursor when hovering over interactive elements
const interactiveElements = document.querySelectorAll('.glow-button, .letter');
interactiveElements.forEach(el => {
el.addEventListener('mouseenter', () => {
cursor.style.width = '40px';
cursor.style.height = '40px';
cursor.style.backgroundColor = 'rgba(233, 69, 96, 0.2)';
cursor.style.mixBlendMode = 'normal';
});
el.addEventListener('mouseleave', () => {
cursor.style.width = '20px';
cursor.style.height = '20px';
cursor.style.backgroundColor = 'transparent';
cursor.style.mixBlendMode = 'difference';
});
});
// Hide cursor when leaving the window
document.addEventListener('mouseout', (e) => {
if (e.relatedTarget === null) {
cursor.style.opacity = '0';
}
});
document.addEventListener('mouseover', () => {
cursor.style.opacity = '1';
});
});

View File

@ -1,52 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fancy Hello World</title>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="hello-world">
<h1 class="title">
<span class="letter">H</span>
<span class="letter">e</span>
<span class="letter">l</span>
<span class="letter">l</span>
<span class="letter">o</span>
<span class="letter space"></span>
<span class="letter">W</span>
<span class="letter">o</span>
<span class="letter">r</span>
<span class="letter">l</span>
<span class="letter">d</span>
<span class="letter">!</span>
</h1>
<div class="subtitle">Welcome to my fancy webpage</div>
</div>
<div class="floating-icons">
<i class="fas fa-star"></i>
<i class="fas fa-heart"></i>
<i class="fas fa-code"></i>
<i class="fas fa-rocket"></i>
<i class="fas fa-magic"></i>
<i class="fas fa-star"></i>
<i class="fas fa-heart"></i>
<i class="fas fa-code"></i>
</div>
<button class="glow-button">Click Me!</button>
</div>
<script src="script.js"></script>
<script src="audio.js"></script>
<script src="cursor.js"></script>
<!-- Add a custom cursor -->
<div class="custom-cursor"></div>
</body>
</html>

View File

@ -1,192 +0,0 @@
// Set animation delay for each letter
document.querySelectorAll('.letter').forEach((letter, index) => {
letter.style.setProperty('--i', index);
});
// Create floating icons randomly
const floatingIcons = document.querySelector('.floating-icons');
const icons = floatingIcons.querySelectorAll('i');
icons.forEach(icon => {
// Random position
const startPositionX = Math.random() * 100;
const startDelay = Math.random() * 10;
const duration = 10 + Math.random() * 20;
const scale = 0.5 + Math.random() * 1.5;
icon.style.left = `${startPositionX}%`;
icon.style.animationDuration = `${duration}s`;
icon.style.animationDelay = `${startDelay}s`;
icon.style.fontSize = `${scale}rem`;
});
// Add click event to the button
const button = document.querySelector('.glow-button');
button.addEventListener('click', () => {
// Create explosion effect
for (let i = 0; i < 30; i++) {
createParticle();
}
});
function createParticle() {
const particle = document.createElement('div');
particle.classList.add('particle');
// Random styles
const size = Math.random() * 15 + 5;
const color = `hsl(${Math.random() * 360}, 70%, 60%)`;
const angle = Math.random() * Math.PI * 2;
const velocity = 1 + Math.random() * 3;
const posX = Math.cos(angle) * velocity;
const posY = Math.sin(angle) * velocity;
// Apply styles
particle.style.width = `${size}px`;
particle.style.height = `${size}px`;
particle.style.background = color;
particle.style.borderRadius = '50%';
particle.style.position = 'absolute';
particle.style.top = '50%';
particle.style.left = '50%';
particle.style.transform = 'translate(-50%, -50%)';
particle.style.pointerEvents = 'none';
document.querySelector('.container').appendChild(particle);
// Animate the particle
let positionX = 0;
let positionY = 0;
let opacity = 1;
let scale = 1;
const animate = () => {
if (opacity <= 0) {
particle.remove();
return;
}
positionX += posX;
positionY += posY;
opacity -= 0.02;
scale += 0.02;
particle.style.transform = `translate(calc(-50% + ${positionX}px), calc(-50% + ${positionY}px)) scale(${scale})`;
particle.style.opacity = opacity;
requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
}
// Add some interactivity to the page
document.addEventListener('mousemove', (e) => {
const mouseX = e.clientX / window.innerWidth;
const mouseY = e.clientY / window.innerHeight;
document.body.style.background = `linear-gradient(
135deg,
hsl(240, 20%, 15%),
hsl(${220 + mouseX * 40}, 30%, 20%),
hsl(${200 + mouseY * 60}, 40%, 25%)
)`;
// Make the title follow the cursor slightly
const title = document.querySelector('.title');
title.style.transform = `translateX(${(mouseX - 0.5) * 20}px) translateY(${(mouseY - 0.5) * 10}px)`;
});
// Add a typing effect to the subtitle
const subtitle = document.querySelector('.subtitle');
const subtitleText = subtitle.textContent;
subtitle.textContent = '';
subtitle.style.opacity = '1';
let charIndex = 0;
function typeSubtitle() {
if (charIndex < subtitleText.length) {
subtitle.textContent += subtitleText.charAt(charIndex);
charIndex++;
setTimeout(typeSubtitle, 100);
}
}
// Start typing after a delay
setTimeout(typeSubtitle, 1500);
// Add a confetti explosion when the page loads
window.addEventListener('load', () => {
setTimeout(() => {
for (let i = 0; i < 50; i++) {
createParticle(true);
}
}, 1000);
});
// Modify the createParticle function to allow for initial explosion
function createParticle(isInitial = false) {
const particle = document.createElement('div');
particle.classList.add('particle');
// Random styles
const size = Math.random() * 15 + 5;
const color = `hsl(${Math.random() * 360}, 70%, 60%)`;
const angle = Math.random() * Math.PI * 2;
const velocity = 1 + Math.random() * 3;
const posX = Math.cos(angle) * velocity;
const posY = Math.sin(angle) * velocity;
// Apply styles
particle.style.width = `${size}px`;
particle.style.height = `${size}px`;
particle.style.background = color;
particle.style.borderRadius = isInitial ? `${Math.random() * 50}%` : '50%';
document.querySelector('.container').appendChild(particle);
// Set initial position
let startX = 50;
let startY = 50;
if (isInitial) {
// For initial explosion, start from the center of the screen
startX = window.innerWidth / 2;
startY = window.innerHeight / 2;
particle.style.top = `${startY}px`;
particle.style.left = `${startX}px`;
} else {
// For button click, start from the button
const button = document.querySelector('.glow-button');
const buttonRect = button.getBoundingClientRect();
startX = buttonRect.left + buttonRect.width / 2;
startY = buttonRect.top + buttonRect.height / 2;
particle.style.top = `${startY}px`;
particle.style.left = `${startX}px`;
}
// Animate the particle
let positionX = 0;
let positionY = 0;
let opacity = 1;
let scale = 1;
const animate = () => {
if (opacity <= 0) {
particle.remove();
return;
}
positionX += posX;
positionY += posY;
opacity -= 0.02;
scale += 0.02;
particle.style.transform = `translate(${positionX}px, ${positionY}px) scale(${scale})`;
particle.style.opacity = opacity;
requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
}

View File

@ -1,197 +0,0 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Poppins', sans-serif;
background: linear-gradient(135deg, #1a1a2e, #16213e, #0f3460);
color: #fff;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
position: relative;
}
.container {
text-align: center;
padding: 2rem;
position: relative;
z-index: 1;
}
.hello-world {
margin-bottom: 3rem;
}
.title {
font-size: 5rem;
font-weight: 700;
margin-bottom: 1rem;
display: flex;
justify-content: center;
}
.letter {
display: inline-block;
animation: bounce 1s ease infinite;
animation-delay: calc(0.1s * var(--i));
transform-origin: bottom;
}
.space {
width: 1rem;
}
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
}
.subtitle {
font-size: 1.5rem;
font-weight: 300;
opacity: 0;
animation: fadeIn 2s ease forwards 1s;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.floating-icons {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.floating-icons i {
position: absolute;
color: rgba(255, 255, 255, 0.3);
animation: float 15s linear infinite;
}
@keyframes float {
0% {
transform: translateY(100vh) scale(0);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(-100px) scale(1.5);
opacity: 0;
}
}
.glow-button {
background: none;
border: 2px solid #e94560;
color: #e94560;
padding: 0.8rem 2rem;
font-size: 1.2rem;
border-radius: 50px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: all 0.3s ease;
font-family: 'Poppins', sans-serif;
z-index: 1;
margin-top: 2rem;
}
.glow-button:hover {
color: white;
box-shadow: 0 0 20px #e94560;
}
.glow-button::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 0%;
height: 100%;
background-color: #e94560;
transition: all 0.3s ease;
z-index: -1;
}
.glow-button:hover::before {
width: 100%;
}
/* Particle effect for button */
.particle {
position: absolute;
pointer-events: none;
z-index: 99;
}
/* Add a cool text shadow effect to title */
.title {
text-shadow: 0 0 10px rgba(233, 69, 96, 0.5);
}
/* Add a subtle pulse effect to the button */
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(233, 69, 96, 0.7);
}
70% {
box-shadow: 0 0 0 10px rgba(233, 69, 96, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(233, 69, 96, 0);
}
}
.glow-button {
animation: pulse 2s infinite;
}
/* Custom cursor */
.custom-cursor {
position: fixed;
width: 20px;
height: 20px;
border: 2px solid #e94560;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
z-index: 9999;
transition: width 0.2s, height 0.2s, background-color 0.2s;
mix-blend-mode: difference;
}
/* Add responsive design */
@media (max-width: 768px) {
.title {
font-size: 3rem;
}
.subtitle {
font-size: 1.2rem;
}
}

View File

@ -55,7 +55,6 @@ function DashboardContent() {
onSubmit={handleSubmit}
loading={isSubmitting}
placeholder="Ask anything..."
minHeight="min-h-[100px]"
value={inputValue}
onChange={setInputValue}
/>

View File

@ -5,24 +5,15 @@ import { useRouter } from 'next/navigation';
import { useAuth } from '@/context/auth-context';
import { Button } from '@/components/ui/button';
import { ArrowDown } from 'lucide-react';
import { getProject, getThread, addMessage, getMessages, startAgent, stopAgent, getAgentStatus, streamAgent, getAgentRuns } from '@/lib/api';
import { addMessage, getMessages, startAgent, stopAgent, getAgentStatus, streamAgent, getAgentRuns } from '@/lib/api';
import { toast } from 'sonner';
import { Project } from '@/lib/types';
import { Skeleton } from "@/components/ui/skeleton";
import { ChatInput } from '@/components/chat-input';
// Define a type for the params to make React.use() work properly
type ThreadParams = { id: string; threadId: string };
// Define types for the API responses
interface ApiThread {
thread_id: string;
messages: Array<{
role: string;
content: string;
}>;
created_at: string;
}
interface ApiMessage {
role: string;
@ -46,8 +37,6 @@ export default function ThreadPage({ params }: { params: Promise<ThreadParams> }
const { user, isLoading: isAuthLoading } = useAuth();
const router = useRouter();
const [project, setProject] = useState<Project | null>(null);
const [thread, setThread] = useState<ApiThread | null>(null);
const [messages, setMessages] = useState<ApiMessage[]>([]);
const [newMessage, setNewMessage] = useState('');
const [isLoading, setIsLoading] = useState(true);
@ -175,7 +164,7 @@ export default function ThreadPage({ params }: { params: Promise<ThreadParams> }
// Store cleanup function
streamCleanupRef.current = cleanup;
}, [threadId]);
}, [threadId, streamContent]);
useEffect(() => {
if (!isAuthLoading && !user) {
@ -198,12 +187,12 @@ export default function ThreadPage({ params }: { params: Promise<ThreadParams> }
}
// Load project data
const projectData = await getProject(projectId) as unknown as Project;
setProject(projectData);
// const projectData = await getProject(projectId) as unknown as Project;
// setProject(projectData);
// Load thread data
const threadData = await getThread(threadId) as unknown as ApiThread;
setThread(threadData);
// const threadData = await getThread(threadId) as unknown as ApiThread;
// setThread(threadData);
// Load messages
const messagesData = await getMessages(threadId) as unknown as ApiMessage[];
@ -372,13 +361,11 @@ export default function ThreadPage({ params }: { params: Promise<ThreadParams> }
// Adjust textarea height based on content
useEffect(() => {
const textarea = textareaRef.current;
if (!textarea) return;
const adjustHeight = () => {
textarea.style.height = 'auto';
const newHeight = Math.min(textarea.scrollHeight, 200); // Max height of 200px
textarea.style.height = `${newHeight}px`;
if (textareaRef.current) {
textareaRef.current.style.height = 'auto';
textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;
}
};
adjustHeight();
@ -388,17 +375,17 @@ export default function ThreadPage({ params }: { params: Promise<ThreadParams> }
return () => window.removeEventListener('resize', adjustHeight);
}, [newMessage]);
// Handle keyboard shortcuts
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
// Send on Enter (without Shift)
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
// // Handle keyboard shortcuts
// const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
// // Send on Enter (without Shift)
// if (e.key === 'Enter' && !e.shiftKey) {
// e.preventDefault();
if (newMessage.trim() && !isSending && agentStatus !== 'running') {
handleSubmitMessage(newMessage);
}
}
};
// if (newMessage.trim() && !isSending && agentStatus !== 'running') {
// handleSubmitMessage(newMessage);
// }
// }
// };
// Check if user has scrolled up from bottom
const handleScroll = () => {

View File

@ -177,7 +177,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="mr-2.5 h-6 w-6 text-black transition-transform duration-200 group-hover/logo:scale-110"
className="mr-2.5 h-5 w-5 text-black transition-transform duration-200 group-hover/logo:scale-110"
>
<path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
</svg>

View File

@ -6,7 +6,6 @@ import { MainNav } from '@/components/main-nav';
import { AppSidebar } from "@/components/app-sidebar"
import { SiteHeader } from "@/components/site-header"
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"
import { Skeleton } from "@/components/ui/skeleton"
export function LayoutContent({ children }: { children: React.ReactNode }) {
const pathname = usePathname();

View File

@ -33,7 +33,7 @@ export function MainNav() {
toast.success('Successfully logged out');
router.push('/auth/login');
router.refresh();
} catch (error) {
} catch {
toast.error('Failed to log out. Please try again.');
}
};

View File

@ -50,7 +50,7 @@ export function NavUser({
toast.success('Successfully logged out')
router.push('/auth/login')
router.refresh()
} catch (error) {
} catch {
toast.error('Failed to log out. Please try again.')
}
}