Skip to content

kunwardhruv/Self-Correcting-Code-Assistant

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Self-Correcting code assistant β€” Self-Correcting Code Agent

Give it any task in plain English. It writes the code, generates its own test cases, executes and validates everything, and self-corrects until all tests pass β€” no manual testing required.

Python Streamlit LangGraph Groq


What It Does

Traditional AI code generation: LLM writes code β†’ you test it β†’ you debug it β†’ repeat manually.

CodeFix AI: LLM writes code β†’ agent tests it β†’ agent debugs it β†’ agent rewrites β†’ repeats automatically.

You type:   "Write a function that finds all duplicates in a list"
Agent does: generates tests β†’ writes code β†’ runs tests β†’ fixes errors β†’ passes βœ“
You get:    working, tested Python code

Pipeline Architecture

graph TD
    A([User: Task Description]) --> B

    B["πŸ§ͺ generate_tests\nAuto-write pytest cases from task"]
    B --> C

    C["✍️ generate_code\nLLM writes Python solution"]
    C --> D

    D["⚑ execute_code\nRun code directly β€” catch crashes"]
    D -->|Execution crashed| E
    D -->|Ran successfully| F

    F["πŸ”¬ run_tests\nRun pytest with generated test cases"]
    F -->|All tests PASS| G
    F -->|Tests FAIL + retries left| E
    F -->|Tests FAIL + max attempts| G

    E["πŸ” analyze_error\nStructured diagnosis: root cause + fix plan"]
    E --> C

    G(["βœ… END: Return final code + metrics"])

    style A fill:#1e1e3a,color:#e2e8f0,stroke:#6d28d9
    style B fill:#1e1e3a,color:#818cf8,stroke:#818cf8
    style C fill:#1e1e3a,color:#a78bfa,stroke:#a78bfa
    style D fill:#1e1e3a,color:#fbbf24,stroke:#fbbf24
    style E fill:#1e1e3a,color:#f87171,stroke:#f87171
    style F fill:#1e1e3a,color:#2dd4bf,stroke:#2dd4bf
    style G fill:#1e1e3a,color:#34d399,stroke:#34d399
Loading

Self-Correction Loop

sequenceDiagram
    participant U as User
    participant ST as Streamlit UI
    participant LG as LangGraph
    participant LLM as Groq LLM
    participant PY as Python Subprocess

    U->>ST: Task description
    ST->>LG: stream(initial_state)

    LG->>LLM: Generate test cases for task
    LLM-->>LG: pytest test functions
    LG-->>ST: Test cases ready

    loop Until tests pass or max_attempts reached
        LG->>LLM: Generate or fix code
        LLM-->>LG: Python code
        LG-->>ST: Code generated

        LG->>PY: python solution.py
        PY-->>LG: stdout/stderr
        LG-->>ST: Execution result

        alt Execution crashed
            LG->>LLM: Analyze crash
            LLM-->>LG: Root cause + fix plan
            LG-->>ST: Error analysis shown
        else Executed OK
            LG->>PY: pytest test_solution.py
            PY-->>LG: test results
            LG-->>ST: Test results shown

            alt All tests pass
                LG-->>ST: Complete
            else Tests fail
                LG->>LLM: Analyze failures
                LLM-->>LG: Root cause + fix plan
                LG-->>ST: Error analysis shown
            end
        end
    end

    ST-->>U: Final code + metrics
Loading

System Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    USER (Browser)                     β”‚
β”‚         Task input Β· Live output Β· Final code         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚ HTTP
                            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              STREAMLIT (app.py)                       β”‚
β”‚  session_state persistence Β· live render_all()        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚ Python call
                            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           LANGGRAPH STATEGRAPH (graph/pipeline.py)    β”‚
β”‚                                                       β”‚
β”‚  generate_tests β†’ generate_code β†’ execute_code        β”‚
β”‚                        β–²              β”‚               β”‚
β”‚                        β”‚         crashβ”‚ok             β”‚
β”‚                  analyze_error   β†β”€β”€β”€β”€β”˜               β”‚
β”‚                        β–²         run_tests            β”‚
β”‚                        └──────── failβ”‚pass            β”‚
β”‚                                      β–Ό                β”‚
β”‚                                     END               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚ API calls (3 nodes)
               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              GROQ API β€” Llama-3.3-70B                 β”‚
β”‚    test_generator Β· code_generator Β· error_analyzer   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚ subprocess
               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         LOCAL PYTHON SUBPROCESS (isolated)            β”‚
β”‚      execute_code Β· run_tests Β· tempfile sandbox      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Folder Structure

codefix-ai/
β”‚
β”œβ”€β”€ agents/
β”‚   β”œβ”€β”€ state.py              ← AgentState TypedDict β€” shared schema
β”‚   β”œβ”€β”€ test_generator.py     ← Node β‘ : auto-generates pytest cases from task
β”‚   β”œβ”€β”€ code_generator.py     ← Node β‘‘: writes/rewrites code (3 prompt strategies)
β”‚   β”œβ”€β”€ code_executor.py      ← Node β‘’: direct python run β€” catches crashes early
β”‚   β”œβ”€β”€ test_runner.py        ← Node β‘£: pytest in isolated subprocess
β”‚   β”œβ”€β”€ error_analyzer.py     ← Node β‘€: structured root cause diagnosis
β”‚   └── __init__.py
β”‚
β”œβ”€β”€ graph/
β”‚   β”œβ”€β”€ pipeline.py           ← LangGraph StateGraph + conditional retry edges
β”‚   └── __init__.py
β”‚
β”œβ”€β”€ .streamlit/
β”‚   └── config.toml           ← Dark violet theme
β”‚
β”œβ”€β”€ app.py                    ← Streamlit UI (entry point)
β”œβ”€β”€ .env.example
β”œβ”€β”€ requirements.txt
└── README.md

Agent Details

Agent Input Output Uses LLM?
test_generator task generated_tests βœ…
code_generator task + error_analysis code βœ…
code_executor code execution_status, execution_output ❌
test_runner code + generated_tests test_output, status ❌
error_analyzer code + error_log error_analysis βœ…

3 LLM calls per retry cycle. Code execution and testing run locally β€” no API cost.


Setup

git clone https://github.com/kunwardhruv/codefix-ai
cd codefix-ai

pip install -r requirements.txt

# Get free API key at console.groq.com
copy .env.example .env
# Add: GROQ_API_KEY=gsk_...

streamlit run app.py

Test Cases

Easy β€” first attempt pass

Palindrome Check

Write a function is_palindrome(s) that returns True if the string is a palindrome.
Ignore spaces, punctuation, and case.
"A man a plan a canal Panama" β†’ True

FizzBuzz

Write a function fizzbuzz(n) that returns a list of strings 1 to n.
Multiples of 3 β†’ "Fizz", 5 β†’ "Buzz", both β†’ "FizzBuzz", else number as string.

Medium β€” 1-2 retries

Anagram Groups

Write a function group_anagrams(words) that groups anagrams together.
["eat","tea","tan","ate","nat","bat"] β†’ [["eat","tea","ate"],["tan","nat"],["bat"]]

Longest Substring Without Repeating

Write a function longest_unique_substring(s) that returns the length of the longest
substring without repeating characters. "abcabcbb" β†’ 3

Flatten Nested List

Write a function flatten(lst) that flattens any depth of nested lists.
[1, [2, [3, [4]], 5]] β†’ [1, 2, 3, 4, 5]

LRU Cache

Write a class LRUCache(capacity) with get(key) and put(key, value) methods.
Evict least recently used when over capacity. Standard library only.

Hard β€” multiple retries

Valid Sudoku

Write a function is_valid_sudoku(board) that takes a 9x9 grid (list of lists, "." for empty)
and returns True if no row, column, or 3x3 box has duplicate digits.

Word Ladder

Write a function word_ladder(begin_word, end_word, word_list) that returns the minimum
number of single-letter transformations to reach end_word. Return 0 if impossible.

Edge case stress tests

Roman Numeral Round Trip

Write int_to_roman(num) and roman_to_int(s).
Must be perfect inverses: roman_to_int(int_to_roman(n)) == n for all n in 1-3999.

Expression Evaluator (no eval)

Write evaluate(expression) for math strings with +, -, *, / and parentheses.
No eval() allowed. "(1+2)*(3+4)" β†’ 21. Handle operator precedence.

Key Design Decisions

Why generate tests before code? Test-first forces the LLM to reason about what the code must do before how β€” higher first-attempt pass rate.

Why subprocess instead of exec()? exec() runs untrusted LLM code in-process. A bad generation can crash the entire agent. Subprocess gives full isolation + 15s timeout.

Why a dedicated error_analyzer node? Raw traceback β†’ code_generator = blind retry. Structured diagnosis (root cause + specific lines + fix plan) β†’ targeted rewrite = fewer retries.

Why temperature=0? Code needs determinism. Randomness hurts correctness here.

Why session_state for results? Streamlit re-runs the whole script on every click. Without session_state, clicking any expander clears all output.


Author

Dhruv Singh β€” AI/ML Engineer

About

AI agent that writes Python code, auto-generates test cases, executes, captures errors, and self-corrects in a loop until all tests pass. Built with LangGraph + Groq Llama-3.3-70B + Streamlit.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages