From 0d775003bf1b9456351eaf11fe1a39d206aaea3c Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Thu, 10 Apr 2025 11:44:22 +0530 Subject: [PATCH 01/14] Hide projects list behind CTA --- apps/rowboat/app/projects/select/app.tsx | 21 ++++++++++++--- .../select/components/search-projects.tsx | 27 ++++++++++++++----- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/apps/rowboat/app/projects/select/app.tsx b/apps/rowboat/app/projects/select/app.tsx index 226431e3..6bf91aae 100644 --- a/apps/rowboat/app/projects/select/app.tsx +++ b/apps/rowboat/app/projects/select/app.tsx @@ -15,6 +15,8 @@ import { CustomPromptCard } from "./components/custom-prompt-card"; import { Submit } from "./components/submit-button"; import { PageHeading } from "@/components/ui/page-heading"; import { USE_MULTIPLE_PROJECTS } from "@/app/lib/feature_flags"; +import { FolderOpenIcon, XMarkIcon } from "@heroicons/react/24/outline"; +import { Button } from "@/components/ui/button"; const sectionHeaderStyles = clsx( "text-sm font-medium", @@ -39,6 +41,7 @@ const textareaStyles = clsx( export default function App() { const [projects, setProjects] = useState[]>([]); const [isLoading, setIsLoading] = useState(true); + const [isProjectPaneOpen, setIsProjectPaneOpen] = useState(false); const [selectedCard, setSelectedCard] = useState<'custom' | any>('custom'); const [customPrompt, setCustomPrompt] = useState(""); @@ -198,7 +201,7 @@ export default function App() { : "mt-8 -mx-12" )}> {/* Left side: Project Selection */} - {USE_MULTIPLE_PROJECTS && ( + {USE_MULTIPLE_PROJECTS && isProjectPaneOpen && (
setIsProjectPaneOpen(false)} />
)} @@ -213,7 +217,8 @@ export default function App() { {/* Right side: Project Creation */}
{USE_MULTIPLE_PROJECTS && ( -
+
Create a new project + {!isProjectPaneOpen && ( + + )}
)} diff --git a/apps/rowboat/app/projects/select/components/search-projects.tsx b/apps/rowboat/app/projects/select/components/search-projects.tsx index 1b6cbe0b..d00ede72 100644 --- a/apps/rowboat/app/projects/select/components/search-projects.tsx +++ b/apps/rowboat/app/projects/select/components/search-projects.tsx @@ -1,9 +1,10 @@ -import { Project } from "@/types/project_types"; +import { Project } from "@/app/lib/types/project_types"; import { z } from "zod"; import { ProjectList } from "./project-list"; import { SectionHeading } from "@/components/ui/section-heading"; import { HorizontalDivider } from "@/components/ui/horizontal-divider"; import clsx from 'clsx'; +import { XMarkIcon } from "@heroicons/react/24/outline"; interface SearchProjectsProps { projects: z.infer[]; @@ -11,6 +12,7 @@ interface SearchProjectsProps { heading: string; subheading: string; className?: string; + onClose?: () => void; } export function SearchProjects({ @@ -18,16 +20,27 @@ export function SearchProjects({ isLoading, heading, subheading, - className + className, + onClose }: SearchProjectsProps) { return (
- - {heading} - +
+ + {heading} + + {onClose && ( + + )} +
From 767584dbbc3c0bbbb1ed8adb5632bb726dffb4d3 Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Thu, 10 Apr 2025 13:22:16 +0530 Subject: [PATCH 02/14] Fix the copy button not working Fix copy button not working --- .../projects/[projectId]/playground/app.tsx | 37 +++++++------- .../playground/components/chat.tsx | 51 +++++++++++++------ 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/apps/rowboat/app/projects/[projectId]/playground/app.tsx b/apps/rowboat/app/projects/[projectId]/playground/app.tsx index 864036fc..858994f6 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/app.tsx @@ -1,5 +1,5 @@ 'use client'; -import { useState } from "react"; +import { useState, useCallback, useRef } from "react"; import { z } from "zod"; import { MCPServer, PlaygroundChat } from "@/app/lib/types/types"; import { Workflow } from "@/app/lib/types/workflow_types"; @@ -30,7 +30,6 @@ export function App({ mcpServerUrls: Array>; toolWebhookUrl: string; }) { - const [counter, setCounter] = useState(0); const [testProfile, setTestProfile] = useState> | null>(null); const [systemMessage, setSystemMessage] = useState(defaultSystemMessage); const [chat, setChat] = useState>({ @@ -42,19 +41,17 @@ export function App({ }); const [isProfileSelectorOpen, setIsProfileSelectorOpen] = useState(false); const [showCopySuccess, setShowCopySuccess] = useState(false); + const getCopyContentRef = useRef<(() => string) | null>(null); function handleSystemMessageChange(message: string) { setSystemMessage(message); - setCounter(counter + 1); } function handleTestProfileChange(profile: WithStringId> | null) { setTestProfile(profile); - setCounter(counter + 1); } function handleNewChatButtonClick() { - setCounter(counter + 1); setChat({ projectId, createdAt: new Date().toISOString(), @@ -62,21 +59,23 @@ export function App({ simulated: false, systemMessage: defaultSystemMessage, }); + setSystemMessage(defaultSystemMessage); } - const handleCopyJson = () => { - const jsonString = JSON.stringify({ - messages: [{ - role: 'system', - content: systemMessage, - }, ...chat.messages], - }, null, 2); - navigator.clipboard.writeText(jsonString); - setShowCopySuccess(true); - setTimeout(() => { - setShowCopySuccess(false); - }, 2000); - }; + const handleCopyJson = useCallback(() => { + if (getCopyContentRef.current) { + try { + const data = getCopyContentRef.current(); + navigator.clipboard.writeText(data); + setShowCopySuccess(true); + setTimeout(() => { + setShowCopySuccess(false); + }, 2000); + } catch (error) { + console.error('Error copying:', error); + } + } + }, []); if (hidden) { return <>; @@ -140,7 +139,6 @@ export function App({ />
{ getCopyContentRef.current = fn; }} />
diff --git a/apps/rowboat/app/projects/[projectId]/playground/components/chat.tsx b/apps/rowboat/app/projects/[projectId]/playground/components/chat.tsx index af50c465..f22ed662 100644 --- a/apps/rowboat/app/projects/[projectId]/playground/components/chat.tsx +++ b/apps/rowboat/app/projects/[projectId]/playground/components/chat.tsx @@ -1,5 +1,5 @@ 'use client'; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState, useCallback } from "react"; import { getAssistantResponseStreamId } from "@/app/actions/actions"; import { Messages } from "./messages"; import z from "zod"; @@ -27,6 +27,7 @@ export function Chat({ onSystemMessageChange, mcpServerUrls, toolWebhookUrl, + onCopyClick, }: { chat: z.infer; projectId: string; @@ -38,6 +39,7 @@ export function Chat({ onSystemMessageChange: (message: string) => void; mcpServerUrls: Array>; toolWebhookUrl: string; + onCopyClick: (fn: () => string) => void; }) { const [messages, setMessages] = useState[]>(chat.messages); const [loadingAssistantResponse, setLoadingAssistantResponse] = useState(false); @@ -47,9 +49,23 @@ export function Chat({ const [fetchResponseError, setFetchResponseError] = useState(null); const [lastAgenticRequest, setLastAgenticRequest] = useState(null); const [lastAgenticResponse, setLastAgenticResponse] = useState(null); - const [isProfileSelectorOpen, setIsProfileSelectorOpen] = useState(false); const [optimisticMessages, setOptimisticMessages] = useState[]>(chat.messages); - const messagesEndRef = useRef(null); + + const getCopyContent = useCallback(() => { + return JSON.stringify({ + messages: [{ + role: 'system', + content: systemMessage, + }, ...messages], + lastRequest: lastAgenticRequest, + lastResponse: lastAgenticResponse, + }, null, 2); + }, [messages, systemMessage, lastAgenticRequest, lastAgenticResponse]); + + // Expose copy function to parent + useEffect(() => { + onCopyClick(getCopyContent); + }, [getCopyContent, onCopyClick]); // reset optimistic messages when messages change useEffect(() => { @@ -63,7 +79,6 @@ export function Chat({ .forEach((message) => { toolCallResults[message.tool_call_id] = message; }); - console.log('toolCallResults', toolCallResults); function handleUserMessage(prompt: string) { const updatedMessages: z.infer[] = [...messages, { @@ -94,7 +109,6 @@ export function Chat({ // get assistant response useEffect(() => { - console.log('stream useEffect called'); let ignore = false; let eventSource: EventSource | null = null; let msgs: z.infer[] = []; @@ -102,6 +116,11 @@ export function Chat({ async function process() { setLoadingAssistantResponse(true); setFetchResponseError(null); + + // Reset request/response state before making new request + setLastAgenticRequest(null); + setLastAgenticResponse(null); + const { agents, tools, prompts, startAgent } = convertWorkflowToAgenticAPI(workflow); const request: z.infer = { projectId, @@ -121,8 +140,9 @@ export function Chat({ toolWebhookUrl: toolWebhookUrl, testProfile: testProfile ?? undefined, }; - setLastAgenticRequest(null); - setLastAgenticResponse(null); + + // Store the full request object + setLastAgenticRequest(request); let streamId: string | null = null; try { @@ -139,14 +159,9 @@ export function Chat({ } if (ignore || !streamId) { - console.log('almost there', ignore, streamId); return; } - // log the stream id - console.log('🔄 got assistant response', streamId); - - // read from SSE stream eventSource = new EventSource(`/api/v1/stream-response/${streamId}`); eventSource.addEventListener("message", (event) => { @@ -158,7 +173,6 @@ export function Chat({ const data = JSON.parse(event.data); const msg = AgenticAPIChatMessage.parse(data); const parsedMsg = convertFromAgenticAPIChatMessages([msg])[0]; - console.log('🔄 got assistant response chunk', parsedMsg); msgs.push(parsedMsg); setOptimisticMessages(prev => [...prev, parsedMsg]); } catch (err) { @@ -173,9 +187,15 @@ export function Chat({ eventSource.close(); } - console.log('🔄 got assistant response done', event.data); - const parsed: {state: unknown} = JSON.parse(event.data); + const parsed = JSON.parse(event.data); setAgenticState(parsed.state); + + // Combine state and collected messages in the response + setLastAgenticResponse({ + ...parsed, + messages: msgs + }); + setMessages([...messages, ...msgs]); setLoadingAssistantResponse(false); }); @@ -207,7 +227,6 @@ export function Chat({ return () => { ignore = true; - console.log('stream useEffect cleanup called'); if (eventSource) { eventSource.close(); } From 882a33aa6fe52b73a8723c0e141882537d08da71 Mon Sep 17 00:00:00 2001 From: akhisud3195 Date: Thu, 10 Apr 2025 14:10:13 +0530 Subject: [PATCH 03/14] Fix tool param name bug --- .../[projectId]/entities/tool_config.tsx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/rowboat/app/projects/[projectId]/entities/tool_config.tsx b/apps/rowboat/app/projects/[projectId]/entities/tool_config.tsx index 472c6489..4a827b7f 100644 --- a/apps/rowboat/app/projects/[projectId]/entities/tool_config.tsx +++ b/apps/rowboat/app/projects/[projectId]/entities/tool_config.tsx @@ -3,7 +3,7 @@ import { WorkflowTool } from "../../../lib/types/workflow_types"; import { Checkbox, Select, SelectItem, RadioGroup, Radio } from "@heroui/react"; import { z } from "zod"; import { ImportIcon, XIcon, PlusIcon } from "lucide-react"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { Textarea } from "@/components/ui/textarea"; import { Panel } from "@/components/common/panel-common"; import { Button } from "@/components/ui/button"; @@ -40,6 +40,12 @@ export function ParameterConfig({ handleRename: (oldName: string, newName: string) => void, readOnly?: boolean }) { + const [localName, setLocalName] = useState(param.name); + + useEffect(() => { + setLocalName(param.name); + }, [param.name]); + return (
@@ -65,11 +71,11 @@ export function ParameterConfig({ Name