Fix the copy button not working

Fix copy button not working
This commit is contained in:
akhisud3195 2025-04-10 13:22:16 +05:30
parent 0d775003bf
commit 767584dbbc
2 changed files with 53 additions and 35 deletions

View file

@ -1,5 +1,5 @@
'use client'; 'use client';
import { useState } from "react"; import { useState, useCallback, useRef } from "react";
import { z } from "zod"; import { z } from "zod";
import { MCPServer, PlaygroundChat } from "@/app/lib/types/types"; import { MCPServer, PlaygroundChat } from "@/app/lib/types/types";
import { Workflow } from "@/app/lib/types/workflow_types"; import { Workflow } from "@/app/lib/types/workflow_types";
@ -30,7 +30,6 @@ export function App({
mcpServerUrls: Array<z.infer<typeof MCPServer>>; mcpServerUrls: Array<z.infer<typeof MCPServer>>;
toolWebhookUrl: string; toolWebhookUrl: string;
}) { }) {
const [counter, setCounter] = useState<number>(0);
const [testProfile, setTestProfile] = useState<WithStringId<z.infer<typeof TestProfile>> | null>(null); const [testProfile, setTestProfile] = useState<WithStringId<z.infer<typeof TestProfile>> | null>(null);
const [systemMessage, setSystemMessage] = useState<string>(defaultSystemMessage); const [systemMessage, setSystemMessage] = useState<string>(defaultSystemMessage);
const [chat, setChat] = useState<z.infer<typeof PlaygroundChat>>({ const [chat, setChat] = useState<z.infer<typeof PlaygroundChat>>({
@ -42,19 +41,17 @@ export function App({
}); });
const [isProfileSelectorOpen, setIsProfileSelectorOpen] = useState(false); const [isProfileSelectorOpen, setIsProfileSelectorOpen] = useState(false);
const [showCopySuccess, setShowCopySuccess] = useState(false); const [showCopySuccess, setShowCopySuccess] = useState(false);
const getCopyContentRef = useRef<(() => string) | null>(null);
function handleSystemMessageChange(message: string) { function handleSystemMessageChange(message: string) {
setSystemMessage(message); setSystemMessage(message);
setCounter(counter + 1);
} }
function handleTestProfileChange(profile: WithStringId<z.infer<typeof TestProfile>> | null) { function handleTestProfileChange(profile: WithStringId<z.infer<typeof TestProfile>> | null) {
setTestProfile(profile); setTestProfile(profile);
setCounter(counter + 1);
} }
function handleNewChatButtonClick() { function handleNewChatButtonClick() {
setCounter(counter + 1);
setChat({ setChat({
projectId, projectId,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
@ -62,21 +59,23 @@ export function App({
simulated: false, simulated: false,
systemMessage: defaultSystemMessage, systemMessage: defaultSystemMessage,
}); });
setSystemMessage(defaultSystemMessage);
} }
const handleCopyJson = () => { const handleCopyJson = useCallback(() => {
const jsonString = JSON.stringify({ if (getCopyContentRef.current) {
messages: [{ try {
role: 'system', const data = getCopyContentRef.current();
content: systemMessage, navigator.clipboard.writeText(data);
}, ...chat.messages], setShowCopySuccess(true);
}, null, 2); setTimeout(() => {
navigator.clipboard.writeText(jsonString); setShowCopySuccess(false);
setShowCopySuccess(true); }, 2000);
setTimeout(() => { } catch (error) {
setShowCopySuccess(false); console.error('Error copying:', error);
}, 2000); }
}; }
}, []);
if (hidden) { if (hidden) {
return <></>; return <></>;
@ -140,7 +139,6 @@ export function App({
/> />
<div className="h-full overflow-auto px-4 py-4"> <div className="h-full overflow-auto px-4 py-4">
<Chat <Chat
key={`chat-${counter}`}
chat={chat} chat={chat}
projectId={projectId} projectId={projectId}
workflow={workflow} workflow={workflow}
@ -151,6 +149,7 @@ export function App({
onSystemMessageChange={handleSystemMessageChange} onSystemMessageChange={handleSystemMessageChange}
mcpServerUrls={mcpServerUrls} mcpServerUrls={mcpServerUrls}
toolWebhookUrl={toolWebhookUrl} toolWebhookUrl={toolWebhookUrl}
onCopyClick={(fn) => { getCopyContentRef.current = fn; }}
/> />
</div> </div>
</Panel> </Panel>

View file

@ -1,5 +1,5 @@
'use client'; 'use client';
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState, useCallback } from "react";
import { getAssistantResponseStreamId } from "@/app/actions/actions"; import { getAssistantResponseStreamId } from "@/app/actions/actions";
import { Messages } from "./messages"; import { Messages } from "./messages";
import z from "zod"; import z from "zod";
@ -27,6 +27,7 @@ export function Chat({
onSystemMessageChange, onSystemMessageChange,
mcpServerUrls, mcpServerUrls,
toolWebhookUrl, toolWebhookUrl,
onCopyClick,
}: { }: {
chat: z.infer<typeof PlaygroundChat>; chat: z.infer<typeof PlaygroundChat>;
projectId: string; projectId: string;
@ -38,6 +39,7 @@ export function Chat({
onSystemMessageChange: (message: string) => void; onSystemMessageChange: (message: string) => void;
mcpServerUrls: Array<z.infer<typeof MCPServer>>; mcpServerUrls: Array<z.infer<typeof MCPServer>>;
toolWebhookUrl: string; toolWebhookUrl: string;
onCopyClick: (fn: () => string) => void;
}) { }) {
const [messages, setMessages] = useState<z.infer<typeof apiV1.ChatMessage>[]>(chat.messages); const [messages, setMessages] = useState<z.infer<typeof apiV1.ChatMessage>[]>(chat.messages);
const [loadingAssistantResponse, setLoadingAssistantResponse] = useState<boolean>(false); const [loadingAssistantResponse, setLoadingAssistantResponse] = useState<boolean>(false);
@ -47,9 +49,23 @@ export function Chat({
const [fetchResponseError, setFetchResponseError] = useState<string | null>(null); const [fetchResponseError, setFetchResponseError] = useState<string | null>(null);
const [lastAgenticRequest, setLastAgenticRequest] = useState<unknown | null>(null); const [lastAgenticRequest, setLastAgenticRequest] = useState<unknown | null>(null);
const [lastAgenticResponse, setLastAgenticResponse] = useState<unknown | null>(null); const [lastAgenticResponse, setLastAgenticResponse] = useState<unknown | null>(null);
const [isProfileSelectorOpen, setIsProfileSelectorOpen] = useState(false);
const [optimisticMessages, setOptimisticMessages] = useState<z.infer<typeof apiV1.ChatMessage>[]>(chat.messages); const [optimisticMessages, setOptimisticMessages] = useState<z.infer<typeof apiV1.ChatMessage>[]>(chat.messages);
const messagesEndRef = useRef<HTMLDivElement>(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 // reset optimistic messages when messages change
useEffect(() => { useEffect(() => {
@ -63,7 +79,6 @@ export function Chat({
.forEach((message) => { .forEach((message) => {
toolCallResults[message.tool_call_id] = message; toolCallResults[message.tool_call_id] = message;
}); });
console.log('toolCallResults', toolCallResults);
function handleUserMessage(prompt: string) { function handleUserMessage(prompt: string) {
const updatedMessages: z.infer<typeof apiV1.ChatMessage>[] = [...messages, { const updatedMessages: z.infer<typeof apiV1.ChatMessage>[] = [...messages, {
@ -94,7 +109,6 @@ export function Chat({
// get assistant response // get assistant response
useEffect(() => { useEffect(() => {
console.log('stream useEffect called');
let ignore = false; let ignore = false;
let eventSource: EventSource | null = null; let eventSource: EventSource | null = null;
let msgs: z.infer<typeof apiV1.ChatMessage>[] = []; let msgs: z.infer<typeof apiV1.ChatMessage>[] = [];
@ -102,6 +116,11 @@ export function Chat({
async function process() { async function process() {
setLoadingAssistantResponse(true); setLoadingAssistantResponse(true);
setFetchResponseError(null); setFetchResponseError(null);
// Reset request/response state before making new request
setLastAgenticRequest(null);
setLastAgenticResponse(null);
const { agents, tools, prompts, startAgent } = convertWorkflowToAgenticAPI(workflow); const { agents, tools, prompts, startAgent } = convertWorkflowToAgenticAPI(workflow);
const request: z.infer<typeof AgenticAPIChatRequest> = { const request: z.infer<typeof AgenticAPIChatRequest> = {
projectId, projectId,
@ -121,8 +140,9 @@ export function Chat({
toolWebhookUrl: toolWebhookUrl, toolWebhookUrl: toolWebhookUrl,
testProfile: testProfile ?? undefined, testProfile: testProfile ?? undefined,
}; };
setLastAgenticRequest(null);
setLastAgenticResponse(null); // Store the full request object
setLastAgenticRequest(request);
let streamId: string | null = null; let streamId: string | null = null;
try { try {
@ -139,14 +159,9 @@ export function Chat({
} }
if (ignore || !streamId) { if (ignore || !streamId) {
console.log('almost there', ignore, streamId);
return; return;
} }
// log the stream id
console.log('🔄 got assistant response', streamId);
// read from SSE stream
eventSource = new EventSource(`/api/v1/stream-response/${streamId}`); eventSource = new EventSource(`/api/v1/stream-response/${streamId}`);
eventSource.addEventListener("message", (event) => { eventSource.addEventListener("message", (event) => {
@ -158,7 +173,6 @@ export function Chat({
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
const msg = AgenticAPIChatMessage.parse(data); const msg = AgenticAPIChatMessage.parse(data);
const parsedMsg = convertFromAgenticAPIChatMessages([msg])[0]; const parsedMsg = convertFromAgenticAPIChatMessages([msg])[0];
console.log('🔄 got assistant response chunk', parsedMsg);
msgs.push(parsedMsg); msgs.push(parsedMsg);
setOptimisticMessages(prev => [...prev, parsedMsg]); setOptimisticMessages(prev => [...prev, parsedMsg]);
} catch (err) { } catch (err) {
@ -173,9 +187,15 @@ export function Chat({
eventSource.close(); eventSource.close();
} }
console.log('🔄 got assistant response done', event.data); const parsed = JSON.parse(event.data);
const parsed: {state: unknown} = JSON.parse(event.data);
setAgenticState(parsed.state); setAgenticState(parsed.state);
// Combine state and collected messages in the response
setLastAgenticResponse({
...parsed,
messages: msgs
});
setMessages([...messages, ...msgs]); setMessages([...messages, ...msgs]);
setLoadingAssistantResponse(false); setLoadingAssistantResponse(false);
}); });
@ -207,7 +227,6 @@ export function Chat({
return () => { return () => {
ignore = true; ignore = true;
console.log('stream useEffect cleanup called');
if (eventSource) { if (eventSource) {
eventSource.close(); eventSource.close();
} }