// debug-panel.jsx — floating developer panel shared across all variants. // Surfaces: recent exchanges, fact-match status, backend, latency, and the // full keyword-lookup table from the Python reference. function DebugPanel({ debug, onClose, palette, font }) { const [tab, setTab] = React.useState("turns"); return (
fetch pup / debug
{[ { id: "turns", label: "turns" }, { id: "intents", label: "intents" }, { id: "keywords", label: "keywords" }, { id: "about", label: "about" }, ].map(t => ( ))}
{tab === "turns" && } {tab === "intents" && } {tab === "keywords" && } {tab === "about" && }
); } function DebugLog({ debug, palette }) { if (debug.length === 0) { return (
No turns yet. Ask Fetch something.
); } return (
{debug.map((d, i) => (
{new Date(d.t).toLocaleTimeString()} {d.backend} · {d.ms}ms
user> {d.user}
fetch> {d.reply}
{"source: "} {d.source === "fact" ? `fact · ${d.fact?.keyword}` : d.source === "intent" ? `intent · ${d.label}` : d.source || "unknown"}
))}
); } function DebugKB({ palette }) { return (
{FETCH_KNOWLEDGE_BASE.length} keywords · first match wins
{FETCH_KNOWLEDGE_BASE.map(([k, v]) => (
{k}
{v}
))}
); } function DebugIntents({ palette }) { return (
{FETCH_INTENTS.length} intents · first match wins
{FETCH_INTENTS.map(intent => (
{intent.label}
{intent.response}
))}
); } function DebugAbout({ palette }) { return (
Fetch Pup is a static browser demo — there is no model running.
Responses come from two layers: an intent matcher that handles greetings and small talk, and a keyword lookup table that returns dog facts verbatim. If neither matches, you get one of three fallback replies.
The generative version, powered by Meta's BlenderBot-400M-distill, runs separately as a Docker Space.
Designed with Claude Design · Built with Claude Code
); } Object.assign(window, { DebugPanel });