rowboat/apps/rowboat/app/projects/[projectId]/playground/app.tsx

162 lines
6 KiB
TypeScript
Raw Normal View History

2025-01-13 15:31:31 +05:30
'use client';
2025-03-10 16:56:16 +05:30
import { useState } from "react";
2025-01-13 15:31:31 +05:30
import { z } from "zod";
2025-03-27 18:52:17 +05:30
import { MCPServer, PlaygroundChat } from "@/app/lib/types/types";
import { Workflow } from "@/app/lib/types/workflow_types";
import { Chat } from "./components/chat";
import { Panel } from "@/components/common/panel-common";
import { Button } from "@/components/ui/button";
2025-01-13 15:31:31 +05:30
import { apiV1 } from "rowboat-shared";
2025-03-10 16:56:16 +05:30
import { TestProfile } from "@/app/lib/types/testing_types";
2025-02-27 23:42:04 +05:30
import { WithStringId } from "@/app/lib/types/types";
2025-03-27 18:52:17 +05:30
import { ProfileSelector } from "@/app/projects/[projectId]/test/[[...slug]]/components/selectors/profile-selector";
import { CheckIcon, CopyIcon, PlusIcon, UserIcon } from "lucide-react";
import { USE_TESTING_FEATURE } from "@/app/lib/feature_flags";
2025-01-13 15:31:31 +05:30
const defaultSystemMessage = '';
export function App({
hidden = false,
projectId,
workflow,
messageSubscriber,
2025-03-20 17:05:13 +05:30
mcpServerUrls,
toolWebhookUrl,
2025-01-13 15:31:31 +05:30
}: {
hidden?: boolean;
projectId: string;
workflow: z.infer<typeof Workflow>;
messageSubscriber?: (messages: z.infer<typeof apiV1.ChatMessage>[]) => void;
2025-03-20 17:05:13 +05:30
mcpServerUrls: Array<z.infer<typeof MCPServer>>;
toolWebhookUrl: string;
2025-01-13 15:31:31 +05:30
}) {
const [counter, setCounter] = useState<number>(0);
2025-03-27 18:52:17 +05:30
const [testProfile, setTestProfile] = useState<WithStringId<z.infer<typeof TestProfile>> | null>(null);
const [systemMessage, setSystemMessage] = useState<string>(defaultSystemMessage);
2025-01-13 15:31:31 +05:30
const [chat, setChat] = useState<z.infer<typeof PlaygroundChat>>({
projectId,
createdAt: new Date().toISOString(),
messages: [],
simulated: false,
systemMessage: defaultSystemMessage,
});
2025-03-27 18:52:17 +05:30
const [isProfileSelectorOpen, setIsProfileSelectorOpen] = useState(false);
const [showCopySuccess, setShowCopySuccess] = useState(false);
2025-01-13 15:31:31 +05:30
function handleSystemMessageChange(message: string) {
setSystemMessage(message);
setCounter(counter + 1);
}
2025-03-03 19:39:51 +05:30
function handleTestProfileChange(profile: WithStringId<z.infer<typeof TestProfile>> | null) {
2025-02-27 23:42:04 +05:30
setTestProfile(profile);
2025-01-13 15:31:31 +05:30
setCounter(counter + 1);
2025-02-27 23:42:04 +05:30
}
function handleNewChatButtonClick() {
2025-01-13 15:31:31 +05:30
setCounter(counter + 1);
setChat({
projectId,
createdAt: new Date().toISOString(),
messages: [],
simulated: false,
systemMessage: defaultSystemMessage,
2025-01-13 15:31:31 +05:30
});
}
2025-03-27 18:52:17 +05:30
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);
};
if (hidden) {
return <></>;
}
return (
2025-03-27 18:52:17 +05:30
<>
<Panel
title={
<div className="flex items-center gap-3">
<div className="text-sm font-medium text-gray-900 dark:text-gray-100">
PLAYGROUND
</div>
<Button
variant="primary"
size="sm"
onClick={handleNewChatButtonClick}
className="bg-blue-50 text-blue-700 hover:bg-blue-100"
showHoverContent={true}
hoverContent="New chat"
>
<PlusIcon className="w-4 h-4" />
</Button>
</div>
}
rightActions={
<div className="flex items-center gap-3">
{USE_TESTING_FEATURE && (
<Button
variant="secondary"
size="sm"
onClick={() => setIsProfileSelectorOpen(true)}
showHoverContent={true}
hoverContent={testProfile?.name || 'Select test profile'}
>
<UserIcon className="w-4 h-4" />
</Button>
)}
2025-03-27 18:52:17 +05:30
<Button
variant="secondary"
size="sm"
onClick={handleCopyJson}
showHoverContent={true}
hoverContent={showCopySuccess ? "Copied" : "Copy JSON"}
>
{showCopySuccess ? (
<CheckIcon className="w-4 h-4" />
) : (
<CopyIcon className="w-4 h-4" />
)}
</Button>
</div>
}
>
{USE_TESTING_FEATURE && (
<ProfileSelector
projectId={projectId}
isOpen={isProfileSelectorOpen}
onOpenChange={setIsProfileSelectorOpen}
onSelect={handleTestProfileChange}
selectedProfileId={testProfile?._id}
/>
)}
2025-03-27 18:52:17 +05:30
<div className="h-full overflow-auto px-4 py-4">
<Chat
key={`chat-${counter}`}
chat={chat}
projectId={projectId}
workflow={workflow}
testProfile={testProfile}
messageSubscriber={messageSubscriber}
onTestProfileChange={handleTestProfileChange}
systemMessage={systemMessage}
onSystemMessageChange={handleSystemMessageChange}
mcpServerUrls={mcpServerUrls}
toolWebhookUrl={toolWebhookUrl}
/>
</div>
</Panel>
</>
);
2025-01-13 15:31:31 +05:30
}