mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-03 20:32:39 +02:00
Add debug mode toggle for playground
This commit is contained in:
parent
bb6a546b02
commit
e1225e2ff8
3 changed files with 60 additions and 20 deletions
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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,15 +52,20 @@ 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">
|
||||||
<button className="flex items-center gap-1 text-xs text-gray-600 dark:text-gray-300 hover:underline self-start" onClick={() => setExpanded(true)}>
|
<div className="text-gray-700 dark:text-gray-200">
|
||||||
<ChevronDownIcon size={16} />
|
{preview}
|
||||||
Show internal message
|
</div>
|
||||||
</button>
|
<div className="flex justify-between items-center gap-6">
|
||||||
<div className="text-right text-xs">
|
<button className="flex items-center gap-1 text-xs text-gray-600 dark:text-gray-300 hover:underline self-start" onClick={() => setExpanded(true)}>
|
||||||
{deltaDisplay}
|
<ChevronDownIcon size={16} />
|
||||||
|
Show internal message
|
||||||
|
</button>
|
||||||
|
<div className="text-right text-xs">
|
||||||
|
{deltaDisplay}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -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) => {
|
||||||
<div key={index}>
|
const renderedMessage = renderMessage(message, index);
|
||||||
{renderMessage(message, index)}
|
if (renderedMessage) {
|
||||||
</div>
|
return (
|
||||||
))}
|
<div key={index}>
|
||||||
|
{renderedMessage}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})}
|
||||||
{loadingAssistantResponse && <AssistantMessageLoading />}
|
{loadingAssistantResponse && <AssistantMessageLoading />}
|
||||||
</div>
|
</div>
|
||||||
<div ref={messagesEndRef} />
|
<div ref={messagesEndRef} />
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue