""" CodeMentor Pro - Multi-type Error Detection Now routes Python, JavaScript, C++, and Java through REAL execution: - Python -> local subprocess sandbox (default; set config.PYTHON_EXECUTION_ENGINE=judge0 to route it through Judge0 too) - JavaScript/C++/Java -> Judge0 (real compile/interpret + execute) Whenever a real engine can't be used for a given submission (Judge0 down, rate-limited, or no engine mapped for the language) we transparently fall back to the same LLM static-estimate prompt used before, so the app never just fails a submission outright - it degrades honestly instead. """ from sandbox import execute_code from store import record_submission, get_weakness_note from llm import call_groq_json from prompts import LOGICAL_ERROR_PROMPT, STATIC_ANALYSIS_PROMPT def _run_static_estimate(code: str, language: str) -> dict: """LLM-based fallback when no real execution happened for this submission.""" out = { "syntax": {"found": False, "message": ""}, "runtime": {"found": False, "message": ""}, "tle": {"found": False, "message": "", "runtime_seconds": None}, "syntax_err": False, "tle_err": False, } try: static_result = call_groq_json(STATIC_ANALYSIS_PROMPT, f"Language: {language}\n\nCode:\n{code}") except Exception as e: out["syntax"]["message"] = f"{language} static analysis unavailable: {e}" return out if static_result.get("syntax_error_found"): out["syntax"] = { "found": True, "message": static_result.get( "syntax_error_message", "Potential syntax issue detected (unverified — static estimate)." ), } out["syntax_err"] = True else: out["syntax"]["message"] = ( f"No obvious syntax issues found for {language} " "(unverified — static LLM estimate, not real execution)." ) if static_result.get("runtime_error_found"): out["runtime"] = {"found": True, "message": static_result.get("runtime_error_message", "")} if static_result.get("tle_risk_found"): out["tle"] = { "found": True, "message": static_result.get( "tle_risk_message", "Potential performance risk (unverified — static estimate)." ), "runtime_seconds": None, } out["tle_err"] = True return out def detect_errors(code: str, language: str) -> dict: result = { "syntax": {"found": False, "message": ""}, "runtime": {"found": False, "message": ""}, "tle": {"found": False, "message": "", "runtime_seconds": None}, "logical": {"found": False, "issues": []}, "weakness_note": "", "verified_by_execution": False, } syntax_err = False tle_err = False exec_result = execute_code(code, language) if not exec_result.engine_failure: # Real execution happened - Python (local) or C++/Java (Judge0). result["verified_by_execution"] = True result["tle"]["runtime_seconds"] = exec_result.runtime_seconds if exec_result.error_type == "syntax": result["syntax"] = {"found": True, "message": exec_result.error_message} syntax_err = True elif exec_result.error_type == "runtime": result["runtime"] = {"found": True, "message": exec_result.error_message} elif exec_result.error_type == "tle": result["tle"] = { "found": True, "message": exec_result.error_message, "runtime_seconds": exec_result.runtime_seconds, } tle_err = True else: # No engine available for this submission (unmapped language, or a # live Judge0 failure) - fall back to the LLM static estimate. static = _run_static_estimate(code, language) result["syntax"] = static["syntax"] result["runtime"] = static["runtime"] result["tle"] = static["tle"] syntax_err = static["syntax_err"] tle_err = static["tle_err"] if language in ("python", "javascript", "cpp", "java"): # This language normally HAS a real engine, so engine_failure here # means Judge0 failed just for this run - worth surfacing clearly # rather than silently looking identical to "no engine exists". result["syntax"]["message"] = ( f"⚠️ Real execution unavailable this run ({exec_result.error_message}) — " f"showing an unverified static estimate instead. {result['syntax']['message']}" ) logical_err = False if not syntax_err: try: llm_result = call_groq_json(LOGICAL_ERROR_PROMPT, f"Language: {language}\n\nCode:\n{code}") if llm_result.get("logical_errors_found"): logical_err = True result["logical"] = {"found": True, "issues": llm_result.get("issues", [])} except Exception as e: result["logical"] = {"found": False, "issues": [], "error": str(e)} record_submission(language, code, syntax_error=syntax_err, logical_error=logical_err, tle=tle_err) result["weakness_note"] = get_weakness_note(language) return result