Skip to content

Latest commit

 

History

History
301 lines (238 loc) · 11.8 KB

File metadata and controls

301 lines (238 loc) · 11.8 KB

Mini Project PRD: Code Debugger Assistant

1. Project Overview

Project Name: Code Debugger Assistant Goal: Build a terminal-based AI assistant that receives a code file, detects the programming language, analyzes errors, proposes fixes with reasoning, and applies changes only after user approval.

The application uses LangChain 1.0, LCEL (LangChain Expression Language), OpenAI-compatible APIs, and a Textual TUI.


2. Problem Statement

Developers often spend time identifying syntax errors, runtime errors, lint issues, and simple logical mistakes. Existing tools either only report errors or directly rewrite code without enough explanation.

This project solves that by creating an AI-powered debugging assistant with a human-in-the-loop approval flow before modifying the source file.


3. Target Users

  • Students learning programming
  • Junior developers
  • Developers preparing demo projects
  • Trainers teaching debugging workflows
  • Engineers who want quick AI-assisted code correction with manual control

4. Scope

In Scope

  1. Accept a single code file as input.
  2. Auto-detect the programming language.
  3. Read and analyze the code.
  4. Detect likely issues: syntax errors, missing imports, runtime errors, type mistakes, bad API usage, logical mistakes.
  5. Generate: error summary, root-cause explanation, proposed corrected code, diff-style change summary.
  6. Ask user approval before applying changes.
  7. Apply approved changes to the original file.
  8. Show the workflow in a Textual TUI.
  9. Use structured LLM output (Pydantic v2 + OpenAI Structured Outputs).

Out of Scope for MVP

  • Multi-file repo-wide debugging
  • Git branch automation
  • Full IDE plugin
  • Remote code execution sandbox
  • Security vulnerability scanning
  • Production-grade code review
  • Automatic deployment

5. Tech Stack

Area Tool
Language Python 3.10+
UI Textual
Chain Composition LangChain 1.0 LCEL (`PromptTemplate
LLM Any OpenAI-compatible API (LM Studio, OpenAI, Anthropic, Groq, OpenRouter)
Model Init init_chat_model() for provider-agnostic setup
Structured Response Pydantic v2 / OpenAI Structured Outputs
Diff Generation Python difflib
File Handling Plain Python pathlib / open()
Language Detection File extension mapping + optional Pygments fallback
Testing Pytest (36 tests)

6. Provider Strategy

The app is provider-agnostic — switch between providers via .env only, no code changes required.

Provider Key env vars
LM Studio (local) MODEL_PROVIDER=openai, BASE_URL=http://localhost:1234/v1, OPENAI_API_KEY=lm-studio
OpenAI MODEL_PROVIDER=openai, MODEL_NAME=gpt-4.1, OPENAI_API_KEY=sk-...
Anthropic MODEL_PROVIDER=anthropic, MODEL_NAME=claude-sonnet-4-5, ANTHROPIC_API_KEY=...
Google Gemini MODEL_PROVIDER=google_genai, MODEL_NAME=gemini-2.0-flash, GOOGLE_API_KEY=...
Groq MODEL_PROVIDER=groq, MODEL_NAME=llama-3.3-70b-versatile, GROQ_API_KEY=...
OpenRouter OPENROUTER_API_KEY=sk-or-v1-..., MODEL_NAME=openai/gpt-4.1

OpenRouter note: Setting OPENROUTER_API_KEY auto-activates OpenRouter regardless of MODEL_PROVIDER. Supports 300+ models from a single key. Model names use the provider/model-name format (e.g. anthropic/claude-sonnet-4-5).


7. User Journey

  1. User launches: python -m app.main
  2. Enter code file path → validated and loaded.
  3. App detects programming language.
  4. App runs the AI debugging LCEL chain (background thread, spinner shown).
  5. App displays: detected language, issues found (with severity badges), AI reasoning, confidence score, diff preview.
  6. User chooses: Approve & Overwrite / Save Corrected Copy / Reject / Back.
  7. If approved, app writes corrected code to disk (with .bak backup).
  8. Success/failure status shown.
  9. User can Debug Another File or Quit.

8. Functional Requirements

FR1: File Input

  • Invalid path shows a clear error in the UI.
  • Empty file is rejected.
  • Supported extensions: .py, .js, .ts, .java, .go, .cpp, .c, .html, .css, .json, .yaml, .rb, .rs, .php, .swift, .kt, .sql, .sh.

FR2: Language Detection

  • Extension map (primary, fast, deterministic).
  • Pygments content-based lexer guess (fallback for unknown extensions).
  • Returns "Unknown" gracefully — file is still passed to LLM.

FR3: Code Analysis (LCEL Chain)

DEBUG_PROMPT | llm.with_structured_output(DebugAnalysisResult)
  • Runs in @work(thread=True) background worker — UI stays responsive.
  • app.call_from_thread() (not screen.call_from_thread()) marshals results to UI.

FR4: Correction Proposal

  • Original code shown with syntax highlighting.
  • Corrected code shown with syntax highlighting.
  • Unified diff rendered (green = added, red = removed).
  • Each issue rendered with severity badge ([HIGH]/[MEDIUM]/[LOW]), description, and suggested fix.
  • Issues rendered as Rich markup via Static.update() (not dynamic mount()).

FR5: Human-in-the-Loop Approval

Button Action
Approve & Overwrite Writes corrected code; creates .bak backup first
Save Corrected Copy Writes <stem>_corrected<ext> alongside original
Reject Leaves all files unchanged
Back Returns to Analysis screen

FR6: Apply Changes

  • .bak backup auto-created before any overwrite.
  • Corrected copy: <stem>_corrected<suffix> naming.
  • Success/failure message shown in Status screen.
  • "Debug Another File" resets state and returns to File Selection screen.

9. Architecture

code-debugger-assistant/
├── app/
│   ├── main.py                # Entry point
│   ├── config.py              # Env vars, extension map, constants
│   ├── agent/
│   │   ├── schemas.py         # Pydantic v2: CodeIssue, DebugAnalysisResult
│   │   ├── prompts.py         # ChatPromptTemplate (system + human)
│   │   └── debugger_chain.py  # LCEL chain + multi-provider setup
│   ├── core/
│   │   ├── file_loader.py     # File validation + read (plain pathlib)
│   │   ├── language_detector.py
│   │   ├── diff_builder.py    # difflib wrapper
│   │   └── patch_writer.py    # overwrite + corrected copy
│   └── ui/
│       ├── debugger_app.py    # Root Textual App + shared state
│       ├── screens.py         # 5 Textual screens
│       └── widgets.py         # DiffViewer, CodeViewer, SectionHeader
├── tests/                     # 36 unit tests (all pass)
├── examples/
│   ├── buggy_python.py
│   ├── buggy_js.js
│   └── buggy_java.java
├── .env.example
├── pyproject.toml
└── README.md

10. LCEL Chain Design

Input: { language: str, source_code: str }
          ↓
  ChatPromptTemplate (system prompt + human message)
          ↓
  ChatModel.with_structured_output(DebugAnalysisResult)
          ↓
  DebugAnalysisResult (validated Pydantic v2)
          ↓
  diff_builder.build_diff_lines()
          ↓
  Textual ApprovalScreen → user decision
          ↓
  patch_writer.overwrite_file() | save_corrected_copy() | (no-op)

Why pure LCEL (not create_agent())?

  • Debugging is a single-shot structured call, not a multi-turn agent loop.
  • PromptTemplate | llm.with_structured_output() is simpler, faster, and easier to test.
  • Human-in-the-loop is handled by the Textual UI layer (Buttons), not LangChain middleware.

11. Structured Output Schema

from pydantic import BaseModel, Field
from typing import List, Literal

class CodeIssue(BaseModel):
    title: str
    description: str
    line_number: int | None = None
    severity: Literal["low", "medium", "high"]
    suggested_fix: str

class DebugAnalysisResult(BaseModel):
    language: str
    error_summary: str
    issues: List[CodeIssue]
    reasoning: str
    corrected_code: str
    change_summary: List[str]
    confidence_score: float  # 0.0-1.0

12. Textual UI Screens

# Screen Purpose
1 FileSelectionScreen Enter & validate file path
2 CodePreviewScreen Show source + language badge
3 AnalysisScreen Run LCEL chain (spinner) → show results
4 ApprovalScreen Diff + corrected code + 4 action buttons
5 StatusScreen Final outcome + restart/quit

Key implementation decisions:

  • @work(thread=True) for the LLM call keeps UI responsive.
  • app.call_from_thread() (not self.call_from_thread()) — call_from_thread is on App, not Screen.
  • height: auto on all content Static widgets — prevents collapsed zero-height boxes.
  • Rich markup via Static.update() for issues — more reliable than dynamic mount() from sync callbacks.
  • Screen stack: while len(stack) > 2 for restart — preserves FileSelectionScreen at index 1.
  • font-size is not valid in Textual CSS — use widget sizing instead.

13. System Prompt

You are a senior software debugging assistant.
Identify only ACTUAL errors: syntax, runtime, import, type, logical.
Preserve the developer's original intent and coding style.
Propose the MINIMAL set of changes needed to fix the code.
Return the COMPLETE corrected source code.
Do not add new features, libraries, or logic that wasn't there before.
Do not remove valid logic.
If the code appears correct, say so and return the original unchanged.
Return your answer using the required structured schema only.

14. MVP Success Criteria

  • User can load a code file.
  • System detects the language.
  • System analyzes code using LLM (structured output).
  • System shows issues, reasoning, corrected code, and diff.
  • User can approve or reject the fix.
  • File changes happen only after approval.
  • At least 3 languages demoed: Python, JavaScript, Java.
  • README clearly explains setup and usage.
  • 36 unit tests pass.

15. Bugs Fixed During Implementation

# Bug Root Cause Fix
1 App crash after LLM analysis self.call_from_thread() — not available on Screen Changed to app.call_from_thread()
2 CSS error on Status screen font-size is not a valid Textual CSS property Removed font-size: 2
3 "Debug Another File" → blank screen while stack > 1 removed FileSelectionScreen too Changed to while stack > 2
4 Issues section empty Dynamic mount() of IssueCard from sync callback unreliable Replaced with pre-declared Static + update() using Rich markup
5 NameError: Vertical Incorrectly removed Vertical from imports Restored import

16. Future Enhancements

  • Multi-file project analysis
  • Git diff integration
  • Unit test generation after fix
  • LangSmith tracing
  • Linter integration (ruff, eslint)
  • VS Code extension
  • Web UI version
  • Dockerized sandbox for safe code execution
  • Rollback previous fix
  • LangSmith observability