Add debug mode toggle for playground

This commit is contained in:
akhisud3195 2025-05-07 15:56:30 +05:30
parent bb6a546b02
commit e1225e2ff8
3 changed files with 60 additions and 20 deletions

View file

@ -11,7 +11,7 @@ import { apiV1 } from "rowboat-shared";
import { TestProfile } from "@/app/lib/types/testing_types"; import { TestProfile } from "@/app/lib/types/testing_types";
import { WithStringId } from "@/app/lib/types/types"; import { WithStringId } from "@/app/lib/types/types";
import { ProfileSelector } from "@/app/projects/[projectId]/test/[[...slug]]/components/selectors/profile-selector"; import { ProfileSelector } from "@/app/projects/[projectId]/test/[[...slug]]/components/selectors/profile-selector";
import { CheckIcon, CopyIcon, PlusIcon, UserIcon, InfoIcon } from "lucide-react"; import { CheckIcon, CopyIcon, PlusIcon, UserIcon, InfoIcon, BugIcon, BugOffIcon } from "lucide-react";
import { USE_TESTING_FEATURE } from "@/app/lib/feature_flags"; import { USE_TESTING_FEATURE } from "@/app/lib/feature_flags";
import { clsx } from "clsx"; import { clsx } from "clsx";
@ -39,6 +39,7 @@ export function App({
const [counter, setCounter] = useState<number>(0); 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 [showDebugMessages, setShowDebugMessages] = useState<boolean>(true);
const [chat, setChat] = useState<z.infer<typeof PlaygroundChat>>({ const [chat, setChat] = useState<z.infer<typeof PlaygroundChat>>({
projectId, projectId,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
@ -116,6 +117,20 @@ export function App({
> >
<PlusIcon className="w-4 h-4" /> <PlusIcon className="w-4 h-4" />
</Button> </Button>
<Button
variant="primary"
size="sm"
onClick={() => setShowDebugMessages(!showDebugMessages)}
className={showDebugMessages ? "bg-blue-50 text-blue-700 hover:bg-blue-100" : "bg-gray-50 text-gray-500 hover:bg-gray-100"}
showHoverContent={true}
hoverContent={showDebugMessages ? "Hide debug messages" : "Show debug messages"}
>
{showDebugMessages ? (
<BugIcon className="w-4 h-4" />
) : (
<BugOffIcon className="w-4 h-4" />
)}
</Button>
</div> </div>
} }
rightActions={ rightActions={
@ -169,6 +184,7 @@ export function App({
mcpServerUrls={mcpServerUrls} mcpServerUrls={mcpServerUrls}
toolWebhookUrl={toolWebhookUrl} toolWebhookUrl={toolWebhookUrl}
onCopyClick={(fn) => { getCopyContentRef.current = fn; }} onCopyClick={(fn) => { getCopyContentRef.current = fn; }}
showDebugMessages={showDebugMessages}
/> />
</div> </div>
</Panel> </Panel>

View file

@ -28,6 +28,7 @@ export function Chat({
mcpServerUrls, mcpServerUrls,
toolWebhookUrl, toolWebhookUrl,
onCopyClick, onCopyClick,
showDebugMessages = true,
}: { }: {
chat: z.infer<typeof PlaygroundChat>; chat: z.infer<typeof PlaygroundChat>;
projectId: string; projectId: string;
@ -40,6 +41,7 @@ export function Chat({
mcpServerUrls: Array<z.infer<typeof MCPServer>>; mcpServerUrls: Array<z.infer<typeof MCPServer>>;
toolWebhookUrl: string; toolWebhookUrl: string;
onCopyClick: (fn: () => string) => void; onCopyClick: (fn: () => string) => void;
showDebugMessages?: boolean;
}) { }) {
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);
@ -285,6 +287,7 @@ export function Chat({
systemMessage={systemMessage} systemMessage={systemMessage}
onSystemMessageChange={onSystemMessageChange} onSystemMessageChange={onSystemMessageChange}
showSystemMessage={false} showSystemMessage={false}
showDebugMessages={showDebugMessages}
/> />
</div> </div>
</div> </div>

View file

@ -35,12 +35,15 @@ function InternalAssistantMessage({ content, sender, latency, delta }: { content
// Show plus icon and duration // Show plus icon and duration
const deltaDisplay = ( const deltaDisplay = (
<span className="inline-flex items-center gap-1 text-gray-400 dark:text-gray-500"> <span className="inline-flex items-center text-gray-400 dark:text-gray-500">
<PlusIcon size={12} /> +{Math.round(delta / 1000)}s
{Math.round(delta / 1000)}s
</span> </span>
); );
// Get first line preview
const firstLine = content.split('\n')[0].trim();
const preview = firstLine.length > 50 ? firstLine.substring(0, 50) + '...' : firstLine;
return ( return (
<div className="self-start flex flex-col gap-1 my-5"> <div className="self-start flex flex-col gap-1 my-5">
<div className="text-gray-500 dark:text-gray-400 text-xs pl-1"> <div className="text-gray-500 dark:text-gray-400 text-xs pl-1">
@ -49,9 +52,13 @@ function InternalAssistantMessage({ content, sender, latency, delta }: { content
<div className={expanded ? 'max-w-[85%] inline-block' : 'inline-block'}> <div className={expanded ? 'max-w-[85%] inline-block' : 'inline-block'}>
<div className={expanded <div className={expanded
? 'bg-gray-50 dark:bg-zinc-800 px-4 py-2.5 rounded-2xl rounded-bl-lg text-sm leading-relaxed text-gray-700 dark:text-gray-200 border-none shadow-sm animate-slideUpAndFade flex flex-col items-stretch' ? 'bg-gray-50 dark:bg-zinc-800 px-4 py-2.5 rounded-2xl rounded-bl-lg text-sm leading-relaxed text-gray-700 dark:text-gray-200 border-none shadow-sm animate-slideUpAndFade flex flex-col items-stretch'
: 'bg-gray-50 dark:bg-zinc-800 px-4 py-0.5 rounded-2xl rounded-bl-lg text-sm leading-relaxed text-gray-700 dark:text-gray-200 border-none shadow-sm animate-slideUpAndFade w-fit'}> : 'bg-gray-50 dark:bg-zinc-800 px-4 py-2.5 rounded-2xl rounded-bl-lg text-sm leading-relaxed text-gray-700 dark:text-gray-200 border-none shadow-sm animate-slideUpAndFade w-fit'}>
{!expanded ? ( {!expanded ? (
<div className="flex justify-between items-center gap-6 mt-2"> <div className="flex flex-col gap-2">
<div className="text-gray-700 dark:text-gray-200">
{preview}
</div>
<div className="flex justify-between items-center gap-6">
<button className="flex items-center gap-1 text-xs text-gray-600 dark:text-gray-300 hover:underline self-start" onClick={() => setExpanded(true)}> <button className="flex items-center gap-1 text-xs text-gray-600 dark:text-gray-300 hover:underline self-start" onClick={() => setExpanded(true)}>
<ChevronDownIcon size={16} /> <ChevronDownIcon size={16} />
Show internal message Show internal message
@ -60,6 +67,7 @@ function InternalAssistantMessage({ content, sender, latency, delta }: { content
{deltaDisplay} {deltaDisplay}
</div> </div>
</div> </div>
</div>
) : ( ) : (
<> <>
<div className="text-left mb-2"> <div className="text-left mb-2">
@ -207,9 +215,8 @@ function TransferToAgentToolCall({
return <></>; return <></>;
} }
const deltaDisplay = ( const deltaDisplay = (
<span className="inline-flex items-center gap-1 text-gray-400 dark:text-gray-500"> <span className="inline-flex items-center text-gray-400 dark:text-gray-500">
<PlusIcon size={12} /> +{Math.round(delta / 1000)}s
{Math.round(delta / 1000)}s
</span> </span>
); );
return ( return (
@ -333,6 +340,7 @@ export function Messages({
systemMessage, systemMessage,
onSystemMessageChange, onSystemMessageChange,
showSystemMessage, showSystemMessage,
showDebugMessages = true,
}: { }: {
projectId: string; projectId: string;
messages: z.infer<typeof apiV1.ChatMessage>[]; messages: z.infer<typeof apiV1.ChatMessage>[];
@ -343,6 +351,7 @@ export function Messages({
systemMessage: string | undefined; systemMessage: string | undefined;
onSystemMessageChange: (message: string) => void; onSystemMessageChange: (message: string) => void;
showSystemMessage: boolean; showSystemMessage: boolean;
showDebugMessages?: boolean;
}) { }) {
const messagesEndRef = useRef<HTMLDivElement>(null); const messagesEndRef = useRef<HTMLDivElement>(null);
let lastUserMessageTimestamp = 0; let lastUserMessageTimestamp = 0;
@ -363,6 +372,12 @@ export function Messages({
// Helper: is this message a transfer pill or internal message? // Helper: is this message a transfer pill or internal message?
const isTransferPill = 'tool_calls' in message && message.tool_calls.some(tc => tc.function.name.startsWith('transfer_to_')); const isTransferPill = 'tool_calls' in message && message.tool_calls.some(tc => tc.function.name.startsWith('transfer_to_'));
const isInternal = message.agenticResponseType === 'internal'; const isInternal = message.agenticResponseType === 'internal';
// Skip internal messages and transfer pills if debug mode is off
if (!showDebugMessages && (isTransferPill || isInternal)) {
return null;
}
if (isTransferPill || isInternal) { if (isTransferPill || isInternal) {
// Find previous message that is either a transfer pill or internal message // Find previous message that is either a transfer pill or internal message
let delta = latency; let delta = latency;
@ -442,11 +457,17 @@ export function Messages({
return ( return (
<div className="max-w-[768px] mx-auto"> <div className="max-w-[768px] mx-auto">
<div className="flex flex-col"> <div className="flex flex-col">
{messages.map((message, index) => ( {messages.map((message, index) => {
const renderedMessage = renderMessage(message, index);
if (renderedMessage) {
return (
<div key={index}> <div key={index}>
{renderMessage(message, index)} {renderedMessage}
</div> </div>
))} );
}
return null;
})}
{loadingAssistantResponse && <AssistantMessageLoading />} {loadingAssistantResponse && <AssistantMessageLoading />}
</div> </div>
<div ref={messagesEndRef} /> <div ref={messagesEndRef} />