From c319904f00654753f82a025a674f3a2f6348d76b Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 27 Nov 2025 18:20:12 +0100 Subject: [PATCH] feat: Add debug mode to inspect LLM prompts and responses - Add DebugContext to track all LLM interactions - Create DebugPanel component with floating UI - Track prompts/responses in Tutor component (move analysis, hints, questions) - Track prompts/responses in Analysis page (move commentary) - Add NEXT_PUBLIC_DEBUG environment variable to enable/disable - Include metadata (FEN, personality, language, etc.) in debug entries - Add copy-to-clipboard and clear functionality - Add DEBUG_MODE.md documentation --- DEBUG_MODE.md | 51 +++++++++ src/app/analysis/page.tsx | 24 ++++- src/app/layout.tsx | 9 +- src/components/DebugPanel.tsx | 192 ++++++++++++++++++++++++++++++++++ src/components/Tutor.tsx | 20 ++++ src/contexts/DebugContext.tsx | 59 +++++++++++ 6 files changed, 352 insertions(+), 3 deletions(-) create mode 100644 DEBUG_MODE.md create mode 100644 src/components/DebugPanel.tsx create mode 100644 src/contexts/DebugContext.tsx diff --git a/DEBUG_MODE.md b/DEBUG_MODE.md new file mode 100644 index 0000000..4288449 --- /dev/null +++ b/DEBUG_MODE.md @@ -0,0 +1,51 @@ +# Debug Mode + +Debug mode allows you to inspect the exact prompts sent to the LLM and the responses received. This is useful for troubleshooting AI behavior and understanding how the tutor works. + +## Enabling Debug Mode + +1. Create a `.env.local` file in the root directory (if it doesn't exist) +2. Add the following line: + ``` + NEXT_PUBLIC_DEBUG=true + ``` +3. Restart the development server (`npm run dev`) + +## Using Debug Mode + +When debug mode is enabled, you'll see: + +### Floating Debug Panel +- A purple "Debug Mode" button appears in the bottom-right corner +- Click to expand and see all LLM interactions +- Shows a list of all prompts sent during your session +- Click any entry to see the full prompt and response + +### Features +- **Copy to Clipboard**: Copy prompts or responses for analysis +- **Clear Entries**: Clear all debug entries +- **Metadata**: View additional context like FEN, personality, language, etc. +- **Timestamps**: See when each interaction occurred + +### What's Tracked + +**Tutor Component:** +- Move Analysis (automatic after each move) +- Best Move Requests (when user asks for the best move) +- Hint Requests (when user asks for a hint) +- General Questions (any other user question) + +**Analysis Page:** +- Move Analysis for each move in the game +- Includes move number, color, FEN before/after, evaluation changes + +## Disabling Debug Mode + +1. Remove or comment out the `NEXT_PUBLIC_DEBUG=true` line in `.env.local` +2. Or set it to `false`: `NEXT_PUBLIC_DEBUG=false` +3. Restart the development server + +## Privacy Note + +Debug mode only runs locally in your browser. No debug data is sent to any server. + diff --git a/src/app/analysis/page.tsx b/src/app/analysis/page.tsx index b16f947..fa038bb 100644 --- a/src/app/analysis/page.tsx +++ b/src/app/analysis/page.tsx @@ -17,6 +17,7 @@ import { lookupPossibleOpenings, buildMoveSequenceFromSteps, OpeningMetadata } f import { getGenAIModel } from "@/lib/gemini"; import { ChatSession } from "@google/generative-ai"; import ReactMarkdown from "react-markdown"; +import { useDebug } from "@/contexts/DebugContext"; interface MoveStep { san: string; @@ -42,6 +43,7 @@ export default function AnalysisPage() { const [language, setLanguage] = useState("en"); const [apiKey, setApiKey] = useState(null); const t = useTranslation(language); + const { addEntry } = useDebug(); const [input, setInput] = useState(""); const [detectedFormat, setDetectedFormat] = useState(null); @@ -286,8 +288,28 @@ INSTRUCTIONS: - Keep it educational and stay true to your personality tone.`; const result = await chatSession.sendMessage(prompt); + const responseText = result.response.text(); + if (!cancelled) { - setComments(prev => ({ ...prev, [currentIndex]: result.response.text() })); + setComments(prev => ({ ...prev, [currentIndex]: responseText })); + + // Track debug entry + addEntry({ + type: 'analysis', + action: `Move ${step.moveNumber} Analysis (${step.color})`, + prompt, + response: responseText, + metadata: { + moveNumber: step.moveNumber, + san: step.san, + color: step.color, + fenBefore: step.fenBefore, + fenAfter: step.fenAfter, + cpLoss: delta, + personality: selectedPersonality.name, + language, + } + }); } } catch (err) { console.error("Commentary failed", err); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 2be7141..6f90783 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,8 @@ import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import Footer from "@/components/Footer"; +import { DebugProvider } from "@/contexts/DebugContext"; +import DebugPanel from "@/components/DebugPanel"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -29,8 +31,11 @@ export default function RootLayout({ - {children} -