mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-25 00:16:29 +02:00
fix copilot bugs
This commit is contained in:
parent
18812a4887
commit
64cfe43135
3 changed files with 39 additions and 114 deletions
|
|
@ -15,7 +15,7 @@ import clsx from "clsx";
|
||||||
import { Action as WorkflowDispatch } from "./workflow_editor";
|
import { Action as WorkflowDispatch } from "./workflow_editor";
|
||||||
import MarkdownContent from "../../../lib/components/markdown-content";
|
import MarkdownContent from "../../../lib/components/markdown-content";
|
||||||
import { CopyAsJsonButton } from "../playground/copy-as-json-button";
|
import { CopyAsJsonButton } from "../playground/copy-as-json-button";
|
||||||
import { CornerDownLeftIcon, SendIcon } from "lucide-react";
|
import { CornerDownLeftIcon, PlusIcon, SendIcon } from "lucide-react";
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -23,7 +23,7 @@ const CopilotContext = createContext<{
|
||||||
workflow: z.infer<typeof Workflow> | null;
|
workflow: z.infer<typeof Workflow> | null;
|
||||||
handleApplyChange: (messageIndex: number, actionIndex: number, field?: string) => void;
|
handleApplyChange: (messageIndex: number, actionIndex: number, field?: string) => void;
|
||||||
appliedChanges: Record<string, boolean>;
|
appliedChanges: Record<string, boolean>;
|
||||||
}>({ workflow: null, handleApplyChange: () => {}, appliedChanges: {} });
|
}>({ workflow: null, handleApplyChange: () => { }, appliedChanges: {} });
|
||||||
|
|
||||||
export function getAppliedChangeKey(messageIndex: number, actionIndex: number, field: string) {
|
export function getAppliedChangeKey(messageIndex: number, actionIndex: number, field: string) {
|
||||||
return `${messageIndex}-${actionIndex}-${field}`;
|
return `${messageIndex}-${actionIndex}-${field}`;
|
||||||
|
|
@ -174,35 +174,35 @@ function App({
|
||||||
projectId,
|
projectId,
|
||||||
workflow,
|
workflow,
|
||||||
dispatch,
|
dispatch,
|
||||||
chatContext=undefined,
|
chatContext = undefined,
|
||||||
messages,
|
|
||||||
setMessages,
|
|
||||||
loadingResponse,
|
|
||||||
setLoadingResponse,
|
|
||||||
loadingMessage,
|
|
||||||
setLoadingMessage,
|
|
||||||
responseError,
|
|
||||||
setResponseError,
|
|
||||||
}: {
|
}: {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
workflow: z.infer<typeof Workflow>;
|
workflow: z.infer<typeof Workflow>;
|
||||||
dispatch: (action: WorkflowDispatch) => void;
|
dispatch: (action: WorkflowDispatch) => void;
|
||||||
chatContext?: z.infer<typeof CopilotChatContext>;
|
chatContext?: z.infer<typeof CopilotChatContext>;
|
||||||
messages: z.infer<typeof CopilotMessage>[];
|
|
||||||
setMessages: (messages: z.infer<typeof CopilotMessage>[]) => void;
|
|
||||||
loadingResponse: boolean;
|
|
||||||
setLoadingResponse: (loading: boolean) => void;
|
|
||||||
loadingMessage: string;
|
|
||||||
setLoadingMessage: (message: string) => void;
|
|
||||||
responseError: string | null;
|
|
||||||
setResponseError: (error: string | null) => void;
|
|
||||||
}) {
|
}) {
|
||||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [messages, setMessages] = useState<z.infer<typeof CopilotMessage>[]>([]);
|
||||||
|
const [loadingResponse, setLoadingResponse] = useState(false);
|
||||||
|
const [loadingMessage, setLoadingMessage] = useState("Thinking");
|
||||||
|
const [responseError, setResponseError] = useState<string | null>(null);
|
||||||
const [appliedChanges, setAppliedChanges] = useState<Record<string, boolean>>({});
|
const [appliedChanges, setAppliedChanges] = useState<Record<string, boolean>>({});
|
||||||
const [discardContext, setDiscardContext] = useState(false);
|
const [discardContext, setDiscardContext] = useState(false);
|
||||||
const [lastRequest, setLastRequest] = useState<unknown | null>(null);
|
const [lastRequest, setLastRequest] = useState<unknown | null>(null);
|
||||||
const [lastResponse, setLastResponse] = useState<unknown | null>(null);
|
const [lastResponse, setLastResponse] = useState<unknown | null>(null);
|
||||||
|
|
||||||
|
// Check for initial prompt in local storage and send it
|
||||||
|
useEffect(() => {
|
||||||
|
const prompt = localStorage.getItem(`project_prompt_${projectId}`);
|
||||||
|
if (prompt && messages.length === 0) {
|
||||||
|
localStorage.removeItem(`project_prompt_${projectId}`);
|
||||||
|
setMessages([{
|
||||||
|
role: 'user',
|
||||||
|
content: prompt
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
}, [projectId, messages.length, setMessages]);
|
||||||
|
|
||||||
// First useEffect for loading messages
|
// First useEffect for loading messages
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLoadingMessage("Thinking");
|
setLoadingMessage("Thinking");
|
||||||
|
|
@ -481,8 +481,8 @@ function App({
|
||||||
{effectiveContext.type === 'tool' && `Tool: ${effectiveContext.name}`}
|
{effectiveContext.type === 'tool' && `Tool: ${effectiveContext.name}`}
|
||||||
{effectiveContext.type === 'prompt' && `Prompt: ${effectiveContext.name}`}
|
{effectiveContext.type === 'prompt' && `Prompt: ${effectiveContext.name}`}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className="text-gray-500 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-300"
|
className="text-gray-500 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-300"
|
||||||
onClick={() => setDiscardContext(true)}
|
onClick={() => setDiscardContext(true)}
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
<svg className="w-4 h-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
|
@ -503,83 +503,42 @@ function App({
|
||||||
export function Copilot({
|
export function Copilot({
|
||||||
projectId,
|
projectId,
|
||||||
workflow,
|
workflow,
|
||||||
chatContext=undefined,
|
chatContext = undefined,
|
||||||
dispatch,
|
dispatch,
|
||||||
onNewChat,
|
|
||||||
messages,
|
|
||||||
setMessages,
|
|
||||||
loadingResponse,
|
|
||||||
setLoadingResponse,
|
|
||||||
loadingMessage,
|
|
||||||
setLoadingMessage,
|
|
||||||
responseError,
|
|
||||||
setResponseError,
|
|
||||||
}: {
|
}: {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
workflow: z.infer<typeof Workflow>;
|
workflow: z.infer<typeof Workflow>;
|
||||||
chatContext?: z.infer<typeof CopilotChatContext>;
|
chatContext?: z.infer<typeof CopilotChatContext>;
|
||||||
dispatch: (action: WorkflowDispatch) => void;
|
dispatch: (action: WorkflowDispatch) => void;
|
||||||
onNewChat: () => void;
|
|
||||||
messages: z.infer<typeof CopilotMessage>[];
|
|
||||||
setMessages: (messages: z.infer<typeof CopilotMessage>[]) => void;
|
|
||||||
loadingResponse: boolean;
|
|
||||||
setLoadingResponse: (loading: boolean) => void;
|
|
||||||
loadingMessage: string;
|
|
||||||
setLoadingMessage: (message: string) => void;
|
|
||||||
responseError: string | null;
|
|
||||||
setResponseError: (error: string | null) => void;
|
|
||||||
}) {
|
}) {
|
||||||
const searchParams = useSearchParams();
|
const [copilotKey, setCopilotKey] = useState(0);
|
||||||
|
|
||||||
// Check for initial prompt in URL and send it
|
function handleNewChat() {
|
||||||
useEffect(() => {
|
setCopilotKey(prev => prev + 1);
|
||||||
const prompt = searchParams.get('prompt');
|
}
|
||||||
if (prompt && messages.length === 0) {
|
|
||||||
setMessages([{
|
|
||||||
role: 'user',
|
|
||||||
content: prompt
|
|
||||||
}]);
|
|
||||||
|
|
||||||
// Clean up the URL
|
|
||||||
const url = new URL(window.location.href);
|
|
||||||
url.searchParams.delete('prompt');
|
|
||||||
window.history.replaceState({}, '', url);
|
|
||||||
}
|
|
||||||
}, [searchParams, messages.length, setMessages]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StructuredPanel
|
<StructuredPanel
|
||||||
fancy
|
fancy
|
||||||
title="COPILOT"
|
title="COPILOT"
|
||||||
tooltip="Get AI assistance for creating and improving your multi-agent system"
|
tooltip="Get AI assistance for creating and improving your multi-agent system"
|
||||||
actions={[
|
actions={[
|
||||||
<ActionButton
|
<ActionButton
|
||||||
key="ask"
|
key="ask"
|
||||||
primary
|
primary
|
||||||
icon={
|
icon={<PlusIcon className="w-4 h-4" />}
|
||||||
<svg className="w-4 h-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
onClick={handleNewChat}
|
||||||
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 12h14m-7 7V5" />
|
|
||||||
</svg>
|
|
||||||
}
|
|
||||||
onClick={onNewChat}
|
|
||||||
>
|
>
|
||||||
New
|
New
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<App
|
<App
|
||||||
|
key={copilotKey}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
workflow={workflow}
|
workflow={workflow}
|
||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
chatContext={chatContext}
|
chatContext={chatContext}
|
||||||
messages={messages}
|
|
||||||
setMessages={setMessages}
|
|
||||||
loadingResponse={loadingResponse}
|
|
||||||
setLoadingResponse={setLoadingResponse}
|
|
||||||
loadingMessage={loadingMessage}
|
|
||||||
setLoadingMessage={setLoadingMessage}
|
|
||||||
responseError={responseError}
|
|
||||||
setResponseError={setResponseError}
|
|
||||||
/>
|
/>
|
||||||
</StructuredPanel>
|
</StructuredPanel>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,7 @@ import { PublishedBadge } from "./published_badge";
|
||||||
import { BackIcon, HamburgerIcon, WorkflowIcon } from "../../../lib/components/icons";
|
import { BackIcon, HamburgerIcon, WorkflowIcon } from "../../../lib/components/icons";
|
||||||
import { CopyIcon, ImportIcon, Layers2Icon, RadioIcon, RedoIcon, ServerIcon, Sparkles, UndoIcon } from "lucide-react";
|
import { CopyIcon, ImportIcon, Layers2Icon, RadioIcon, RedoIcon, ServerIcon, Sparkles, UndoIcon } from "lucide-react";
|
||||||
import { EntityList } from "./entity_list";
|
import { EntityList } from "./entity_list";
|
||||||
import { CopilotMessage } from "../../../lib/types/copilot_types";
|
|
||||||
import { McpImportTools } from "./mcp_imports";
|
import { McpImportTools } from "./mcp_imports";
|
||||||
import { useSearchParams } from 'next/navigation';
|
|
||||||
|
|
||||||
enablePatches();
|
enablePatches();
|
||||||
|
|
||||||
|
|
@ -598,29 +596,18 @@ export function WorkflowEditor({
|
||||||
const [showCopySuccess, setShowCopySuccess] = useState(false);
|
const [showCopySuccess, setShowCopySuccess] = useState(false);
|
||||||
const [showCopilot, setShowCopilot] = useState(false);
|
const [showCopilot, setShowCopilot] = useState(false);
|
||||||
const [copilotWidth, setCopilotWidth] = useState(25);
|
const [copilotWidth, setCopilotWidth] = useState(25);
|
||||||
const [copilotKey, setCopilotKey] = useState(0);
|
|
||||||
const [copilotMessages, setCopilotMessages] = useState<z.infer<typeof CopilotMessage>[]>([]);
|
|
||||||
const [loadingResponse, setLoadingResponse] = useState(false);
|
|
||||||
const [loadingMessage, setLoadingMessage] = useState("Thinking...");
|
|
||||||
const [responseError, setResponseError] = useState<string | null>(null);
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const [isMcpImportModalOpen, setIsMcpImportModalOpen] = useState(false);
|
const [isMcpImportModalOpen, setIsMcpImportModalOpen] = useState(false);
|
||||||
|
|
||||||
console.log(`workflow editor chat key: ${state.present.chatKey}`);
|
console.log(`workflow editor chat key: ${state.present.chatKey}`);
|
||||||
|
|
||||||
// Auto-show copilot and increment key when prompt is present
|
// Auto-show copilot and increment key when prompt is present
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const prompt = searchParams.get('prompt');
|
const prompt = localStorage.getItem(`project_prompt_${state.present.workflow.projectId}`);
|
||||||
|
console.log('init project prompt', prompt);
|
||||||
if (prompt) {
|
if (prompt) {
|
||||||
setShowCopilot(true);
|
setShowCopilot(true);
|
||||||
setCopilotKey(prev => prev + 1); // Force copilot to reset
|
|
||||||
|
|
||||||
// Clean up the URL
|
|
||||||
const url = new URL(window.location.href);
|
|
||||||
url.searchParams.delete('prompt');
|
|
||||||
window.history.replaceState({}, '', url);
|
|
||||||
}
|
}
|
||||||
}, [searchParams]);
|
}, [state.present.workflow.projectId]);
|
||||||
|
|
||||||
function handleSelectAgent(name: string) {
|
function handleSelectAgent(name: string) {
|
||||||
dispatch({ type: "select_agent", name });
|
dispatch({ type: "select_agent", name });
|
||||||
|
|
@ -958,7 +945,6 @@ export function WorkflowEditor({
|
||||||
onResize={(size) => setCopilotWidth(size)}
|
onResize={(size) => setCopilotWidth(size)}
|
||||||
>
|
>
|
||||||
<Copilot
|
<Copilot
|
||||||
key={copilotKey}
|
|
||||||
projectId={state.present.workflow.projectId}
|
projectId={state.present.workflow.projectId}
|
||||||
workflow={state.present.workflow}
|
workflow={state.present.workflow}
|
||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
|
|
@ -971,21 +957,6 @@ export function WorkflowEditor({
|
||||||
messages: chatMessages
|
messages: chatMessages
|
||||||
} : undefined
|
} : undefined
|
||||||
}
|
}
|
||||||
onNewChat={() => {
|
|
||||||
setCopilotKey(prev => prev + 1);
|
|
||||||
setCopilotMessages([]);
|
|
||||||
setLoadingResponse(false);
|
|
||||||
setLoadingMessage("Thinking...");
|
|
||||||
setResponseError(null);
|
|
||||||
}}
|
|
||||||
messages={copilotMessages}
|
|
||||||
setMessages={setCopilotMessages}
|
|
||||||
loadingResponse={loadingResponse}
|
|
||||||
setLoadingResponse={setLoadingResponse}
|
|
||||||
loadingMessage={loadingMessage}
|
|
||||||
setLoadingMessage={setLoadingMessage}
|
|
||||||
responseError={responseError}
|
|
||||||
setResponseError={setResponseError}
|
|
||||||
/>
|
/>
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
</>}
|
</>}
|
||||||
|
|
|
||||||
|
|
@ -206,14 +206,9 @@ export default function App() {
|
||||||
throw new Error('Project creation failed - no project ID returned');
|
throw new Error('Project creation failed - no project ID returned');
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = new URLSearchParams({
|
// write prompt to local storage
|
||||||
prompt: promptText,
|
localStorage.setItem(`project_prompt_${response.id}`, promptText);
|
||||||
autostart: 'true'
|
router.push(`/projects/${response.id}/workflow`);
|
||||||
});
|
|
||||||
const url = `/projects/${response.id}/workflow?${params.toString()}`;
|
|
||||||
|
|
||||||
console.log('Navigating to:', url);
|
|
||||||
window.location.href = url;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating project:', error);
|
console.error('Error creating project:', error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue