Skip to content
Open

Demo #10

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
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Google Gemini API Key
# Get your API key from: https://makersuite.google.com/app/apikey
GEMINI_API_KEY=your_gemini_api_key_here

# Enable demo image conditioning (loads images from ./demo as context)
DEMO_ENABLED=false
1 change: 1 addition & 0 deletions demo/description.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Find funding of a YC 2025 winter startup at https://www.ycombinator.com/companies?batch=Winter%202025.
3 changes: 3 additions & 0 deletions demo/prompt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Find funding of a YC 2025 winter startup at https://www.ycombinator.com/companies?batch=Winter%202025.

Pick 3 startups from the YC 2025 batch, check how much they raised by doing a google search in a separate tab, and add their names and most recent raise to the google docs at https://docs.google.com/document/d/1IzFp0tiDhllwW_mdyCQKkvNY7uKFYNulge1A4gAvCYs/edit?tab=t.0 on a new line.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix capitalization of proper nouns.

"google search" should be "Google search" and "google docs" should be "Google Docs" as these are proper product names.

📝 Suggested fix
-Pick 3 startups from the YC 2025 batch, check how much they raised by doing a google search in a separate tab, and add their names and most recent raise to the google docs at https://docs.google.com/document/d/1IzFp0tiDhllwW_mdyCQKkvNY7uKFYNulge1A4gAvCYs/edit?tab=t.0 on a new line.
+Pick 3 startups from the YC 2025 batch, check how much they raised by doing a Google search in a separate tab, and add their names and most recent raise to the Google Docs at https://docs.google.com/document/d/1IzFp0tiDhllwW_mdyCQKkvNY7uKFYNulge1A4gAvCYs/edit?tab=t.0 on a new line.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Pick 3 startups from the YC 2025 batch, check how much they raised by doing a google search in a separate tab, and add their names and most recent raise to the google docs at https://docs.google.com/document/d/1IzFp0tiDhllwW_mdyCQKkvNY7uKFYNulge1A4gAvCYs/edit?tab=t.0 on a new line.
Pick 3 startups from the YC 2025 batch, check how much they raised by doing a Google search in a separate tab, and add their names and most recent raise to the Google Docs at https://docs.google.com/document/d/1IzFp0tiDhllwW_mdyCQKkvNY7uKFYNulge1A4gAvCYs/edit?tab=t.0 on a new line.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~3-~3: “Google” is a proper noun and needs to be capitalized.
Context: ..., check how much they raised by doing a google search in a separate tab, and add their...

(A_GOOGLE)


[uncategorized] ~3-~3: Did you mean “Google Docs”?
Context: ...heir names and most recent raise to the google docs at https://docs.google.com/document/d/1...

(GOOGLE_PRODUCTS)

🤖 Prompt for AI Agents
In `@demo/prompt.txt` at line 3, In demo/prompt.txt update the sentence "Pick 3
startups from the YC 2025 batch, check how much they raised by doing a google
search in a separate tab, and add their names and most recent raise to the
google docs..." to correctly capitalize product names: change "google search" to
"Google search" (or "Google Search") and "google docs" to "Google Docs",
preserving the rest of the sentence and punctuation.

Binary file added demo/step1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/step2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/step3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/step4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/step5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/step6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ services:
volumes:
- ./screenshots:/tmp/screenshots
- ./logs:/app/logs
- ./demo:/app/demo:ro
environment:
- GEMINI_API_KEY=${GEMINI_API_KEY}
- MCP_SERVER_URL=http://playwright-browser:3001
- DEMO_ENABLED=${DEMO_ENABLED:-false}
depends_on:
playwright-browser:
condition: service_healthy
Expand Down
1 change: 1 addition & 0 deletions services/nextjs-webapp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vercel
87 changes: 73 additions & 14 deletions services/nextjs-webapp/src/components/ChatWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import RecordingMetadataModal from './RecordingMetadataModal'

interface Message {
id: string
role: 'user' | 'assistant' | 'system'
role: 'user' | 'assistant' | 'system' | 'memory'
content: string
timestamp: Date
thumbnail?: string
imageCount?: number
}

interface ChatWindowProps {
Expand Down Expand Up @@ -67,9 +69,36 @@ export default function ChatWindow({ isRecording = false }: ChatWindowProps) {
},
])
setIsLoading(false)
} else if (data.type === 'memory_injected') {
// Memory was injected - show it immediately
if (data.metadata) {
setMessages((prev) => [
...prev,
{
id: Date.now().toString() + '-memory',
role: 'memory',
content: `Memory retrieved: ${data.metadata.description}`,
timestamp: new Date(),
thumbnail: data.metadata.thumbnail,
imageCount: data.metadata.image_count,
},
])
}
} else if (data.type === 'status') {
// Handle status updates (e.g., "thinking", "executing action")
// Handle status updates (e.g., "thinking", "executing action", "interrupt_received")
console.log('Status:', data.content)
if (data.content === 'interrupt_received') {
// Show a system message that the interrupt was received
setMessages((prev) => [
...prev,
{
id: Date.now().toString() + '-interrupt',
role: 'system',
content: 'Interrupt received - will be applied at next iteration',
timestamp: new Date(),
},
])
}
} else if (data.type === 'recording_status') {
// Handle recording status updates
if (data.session_id) {
Expand Down Expand Up @@ -158,7 +187,7 @@ export default function ChatWindow({ isRecording = false }: ChatWindowProps) {
}, [isRecording, isConnected])

const sendMessage = () => {
if (!input.trim() || !isConnected || isLoading) return
if (!input.trim() || !isConnected) return

const userMessage: Message = {
id: Date.now().toString(),
Expand All @@ -168,14 +197,24 @@ export default function ChatWindow({ isRecording = false }: ChatWindowProps) {
}

setMessages((prev) => [...prev, userMessage])
setIsLoading(true)

wsRef.current?.send(
JSON.stringify({
type: 'message',
content: input.trim(),
})
)
// If already loading, send as interrupt; otherwise send as new message
if (isLoading) {
wsRef.current?.send(
JSON.stringify({
type: 'interrupt',
content: input.trim(),
})
)
} else {
setIsLoading(true)
wsRef.current?.send(
JSON.stringify({
type: 'message',
content: input.trim(),
})
)
}

setInput('')
}
Expand Down Expand Up @@ -279,10 +318,26 @@ export default function ChatWindow({ isRecording = false }: ChatWindowProps) {
? 'bg-blue-600 text-white'
: message.role === 'system'
? 'bg-gray-800 text-gray-300 text-sm italic'
: message.role === 'memory'
? 'bg-purple-900 text-purple-100 border border-purple-700'
: 'bg-gray-700 text-white'
}`}
>
<p className="whitespace-pre-wrap">{message.content}</p>
{message.role === 'memory' && message.thumbnail && (
<div className="mb-2">
<img
src={message.thumbnail}
alt="Memory thumbnail"
className="w-32 h-auto rounded border border-purple-600"
/>
{message.imageCount && (
<span className="text-xs text-purple-300 mt-1 block">
+{message.imageCount - 1} more images
</span>
)}
</div>
)}
<p className="whitespace-pre-wrap break-words">{message.content}</p>
<span className="text-xs opacity-50 mt-1 block">
{message.timestamp.toLocaleTimeString()}
</span>
Expand Down Expand Up @@ -314,16 +369,20 @@ export default function ChatWindow({ isRecording = false }: ChatWindowProps) {
<div className="flex gap-2">
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
onChange={(e) => {
setInput(e.target.value)
e.target.style.height = 'auto'
e.target.style.height = Math.min(e.target.scrollHeight, 120) + 'px'
}}
Comment on lines +372 to +376

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Textarea auto-resize doesn’t reset after send.

When setInput('') runs, the height stays expanded because no onChange fires. This leaves a tall empty box after sending multiline input.

🧩 Suggested fix
@@
-  const messagesEndRef = useRef<HTMLDivElement>(null)
+  const messagesEndRef = useRef<HTMLDivElement>(null)
+  const inputRef = useRef<HTMLTextAreaElement>(null)
@@
-    setInput('')
+    setInput('')
+    if (inputRef.current) inputRef.current.style.height = 'auto'
@@
-          <textarea
+          <textarea
+            ref={inputRef}
             value={input}
             onChange={(e) => {
               setInput(e.target.value)
               e.target.style.height = 'auto'
               e.target.style.height = Math.min(e.target.scrollHeight, 120) + 'px'
             }}
🤖 Prompt for AI Agents
In `@services/nextjs-webapp/src/components/ChatWindow.tsx` around lines 372 - 376,
The textarea stays expanded after setInput('') because clearing the value
doesn't trigger onChange to shrink the element; add a ref to the textarea (e.g.,
inputRef) and, after clearing input in your send handler (where you call
setInput('')), explicitly reset the element height
(inputRef.current.style.height = 'auto' or a desired min height) or add a
useEffect that watches the input state and collapses the textarea when input ===
''. Also keep the existing onChange resizing logic (which should use
inputRef.current or e.target) so manual typing still auto-resizes.

onKeyDown={handleKeyDown}
placeholder="Ask the agent to do something..."
className="flex-1 bg-gray-800 text-white rounded-lg px-4 py-2 resize-none focus:outline-none focus:ring-2 focus:ring-blue-500"
className="flex-1 bg-gray-800 text-white rounded-lg px-4 py-2 resize-none focus:outline-none focus:ring-2 focus:ring-blue-500 overflow-x-hidden break-words"
rows={1}
disabled={!isConnected}
/>
<button
onClick={sendMessage}
disabled={!isConnected || !input.trim() || isLoading}
disabled={!isConnected || !input.trim()}
className="bg-blue-600 hover:bg-blue-700 disabled:bg-gray-700 disabled:cursor-not-allowed text-white px-4 py-2 rounded-lg transition-colors"
>
Send
Expand Down
Loading