2026-03-02 04:30:10 +03:00
import subprocess
import sys
import json
import re
import time
from pathlib import Path
2026-04-19 15:22:49 +03:00
2026-03-02 04:30:10 +03:00
def get_base_dir ():
if getattr ( sys , "frozen" , False ):
return Path ( sys . executable ) . parent
return Path ( __file__ ) . resolve () . parent . parent
2026-04-19 15:22:49 +03:00
BASE_DIR = get_base_dir ()
API_CONFIG_PATH = BASE_DIR / "config" / "api_keys.json"
PROJECTS_DIR = Path . home () / "Desktop" / "JarvisProjects"
MAX_FIX_ATTEMPTS = 5
MODEL_PLANNER = "gemini-2.5-flash"
MODEL_WRITER = "gemini-2.5-flash"
2026-03-02 04:30:10 +03:00
def _get_api_key () -> str :
with open ( API_CONFIG_PATH , "r" , encoding = "utf-8" ) as f :
return json . load ( f )[ "gemini_api_key" ]
def _get_model ( model_name : str ):
import google.generativeai as genai
genai . configure ( api_key = _get_api_key ())
return genai . GenerativeModel ( model_name )
2026-04-19 15:22:49 +03:00
def _strip_fences ( text : str ) -> str :
2026-03-02 04:30:10 +03:00
text = text . strip ()
2026-04-19 15:22:49 +03:00
text = re . sub ( r "^```[a-zA-Z]*\r?\n?" , "" , text )
text = re . sub ( r "\r?\n?```\s*$" , "" , text )
2026-03-02 04:30:10 +03:00
return text . strip ()
2026-04-19 15:22:49 +03:00
def _is_rate_limit ( error : Exception ) -> bool :
msg = str ( error ) . lower ()
return "429" in msg or "quota" in msg or "resource_exhausted" in msg
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
def _parse_traceback ( output : str , project_files : list [ str ]) -> tuple [ str | None , int | None ]:
pattern = re . compile ( r 'File [" \' ]([^" \' ]+\.py)[" \' ],\s+line\s+(\d+)' , re . IGNORECASE )
matches = pattern . findall ( output )
for raw_path , line_str in reversed ( matches ):
raw_name = Path ( raw_path ) . name
for pf in project_files :
if Path ( pf ) . name == raw_name or pf == raw_path or raw_path . endswith ( pf ):
return pf , int ( line_str )
return None , None
def _classify_error ( output : str ) -> str :
low = output . lower ()
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
if any ( x in low for x in ( "no module named" , "modulenotfounderror" , "importerror" )):
return "dependency_error"
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
if "syntaxerror" in low or "invalid syntax" in low :
return "syntax_error"
if "cannot import" in low or "importerror" in low :
return "import_error"
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
if any ( x in low for x in (
"traceback" , "exception" , "error:" , "nameerror" , "typeerror" ,
"attributeerror" , "valueerror" , "keyerror" , "indexerror" ,
"zerodivisionerror" , "filenotfounderror" , "permissionerror" ,
)):
return "runtime_error"
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
return "none"
def _has_error ( output : str , run_command : str ) -> bool :
low = output . lower ()
if "timed out" in low :
2026-03-02 04:30:10 +03:00
return False
2026-04-19 15:22:49 +03:00
if not output . strip ():
return False
error_type = _classify_error ( output )
return error_type != "none"
class RateLimitError ( Exception ):
pass
2026-03-02 04:30:10 +03:00
def _plan_project ( description : str , language : str ) -> dict :
model = _get_model ( MODEL_PLANNER )
2026-04-19 15:22:49 +03:00
prompt = f """You are a senior software architect. Create a minimal, complete file plan for this project.
2026-03-02 04:30:10 +03:00
Language: { language }
Description: { description }
2026-04-19 15:22:49 +03:00
Return ONLY valid JSON — no markdown, no explanation:
2026-03-02 04:30:10 +03:00
{{
2026-04-19 15:22:49 +03:00
"project_name": "snake_case_name",
2026-03-02 04:30:10 +03:00
"entry_point": "main.py",
"files": [
2026-04-19 15:22:49 +03:00
{{
"path": "main.py",
"description": "Entry point — what it does and which modules it imports",
"imports": ["utils.helpers", "core.engine"]
}} ,
{{
"path": "utils/helpers.py",
"description": "Helper utilities — what functions it exposes",
"imports": []
}}
2026-03-02 04:30:10 +03:00
],
"run_command": "python main.py",
2026-04-19 15:22:49 +03:00
"dependencies": ["requests"]
2026-03-02 04:30:10 +03:00
}}
2026-04-19 15:22:49 +03:00
Critical rules:
1. List files in DEPENDENCY ORDER — files with no imports come first, entry point comes last.
2. The "imports" field must list every other project module this file imports (dot-notation, e.g. "utils.helpers").
3. Keep it minimal — only files truly needed.
4. Entry point must be in the files list.
5. Use relative paths only (e.g. "utils/helpers.py", not absolute paths).
6. Standard library modules (os, sys, json, etc.) do NOT go in "dependencies".
2026-03-02 04:30:10 +03:00
JSON:"""
try :
response = model . generate_content ( prompt )
2026-04-19 15:22:49 +03:00
raw = _strip_fences ( response . text )
2026-03-02 04:30:10 +03:00
return json . loads ( raw )
except json . JSONDecodeError as e :
raise ValueError ( f "Planner returned invalid JSON: { e } \n Raw: { response . text [: 300 ] } " )
2026-04-19 15:22:49 +03:00
except Exception as e :
if _is_rate_limit ( e ):
raise RateLimitError ( str ( e ))
raise
2026-03-02 04:30:10 +03:00
def _write_file (
2026-04-19 15:22:49 +03:00
file_info : dict ,
2026-03-02 04:30:10 +03:00
project_description : str ,
all_files : list [ dict ],
language : str ,
2026-04-19 15:22:49 +03:00
project_dir : Path ,
already_written : dict [ str , str ],
2026-03-02 04:30:10 +03:00
) -> str :
model = _get_model ( MODEL_WRITER )
2026-04-19 15:22:49 +03:00
file_path = file_info [ "path" ]
file_desc = file_info . get ( "description" , "" )
file_imports = file_info . get ( "imports" , [])
2026-03-02 04:30:10 +03:00
file_list = " \n " . join (
2026-04-19 15:22:49 +03:00
f " [ { i + 1 } ] { f [ 'path' ] } : { f . get ( 'description' , '' ) } "
for i , f in enumerate ( all_files )
2026-03-02 04:30:10 +03:00
)
2026-04-19 15:22:49 +03:00
dependency_context = ""
for dep_dotted in file_imports :
dep_path = dep_dotted . replace ( "." , "/" ) + ".py"
if dep_path in already_written :
code_snippet = already_written [ dep_path ][: 2000 ]
dependency_context += f " \n\n --- { dep_path } (you must import from this) --- \n { code_snippet } "
lang_rules = ""
if language . lower () == "python" :
lang_rules = """
Python-specific rules:
- Use type hints for all function signatures.
- Add docstrings for all public functions and classes.
- Use if __name__ == "__main__": guard in the entry point.
- For relative imports within the project, use: from utils.helpers import foo (match the project structure exactly).
- Do NOT use implicit relative imports (from . import ...) unless it's a proper package with __init__.py.
- If this is a package subdirectory, create __init__.py files where needed."""
elif language . lower () in ( "javascript" , "typescript" , "js" , "ts" ):
lang_rules = """
JS/TS-specific rules:
- Use ES modules (import/export), not CommonJS (require).
- Add JSDoc comments for all exported functions.
- Handle promise rejections with try/catch in async functions."""
prompt = f """You are a senior { language } developer writing production-quality code for a real project.
2026-03-02 04:30:10 +03:00
Project goal: { project_description }
2026-04-19 15:22:49 +03:00
Complete project file structure (in dependency order):
2026-03-02 04:30:10 +03:00
{ file_list }
2026-04-19 15:22:49 +03:00
{ f "Dependencies this file must import from other project files: { dependency_context } " if dependency_context else "" }
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
Your task: Write the complete, working code for: { file_path }
Purpose of this file: { file_desc }
{ f "This file imports from: { ', ' . join ( file_imports ) } " if file_imports else "This file has no project-internal imports." }
{ lang_rules }
General rules:
- Output ONLY raw code. Absolutely no explanation, no markdown, no triple backticks.
- Write COMPLETE, RUNNABLE code — no placeholders, no "# TODO", no "pass" stubs.
- Every import must either be from the standard library, listed dependencies, or the project files shown above.
- Match import paths EXACTLY to the file paths in the project structure (e.g. if file is "utils/helpers.py", import as "from utils.helpers import ...").
- Use proper error handling (try/except) where I/O or network calls are made.
- The code must work correctly when the project entry point is run from the project root directory.
2026-03-02 04:30:10 +03:00
Code for { file_path } :"""
try :
response = model . generate_content ( prompt )
2026-04-19 15:22:49 +03:00
code = _strip_fences ( response . text )
2026-03-02 04:30:10 +03:00
full_path = project_dir / file_path
full_path . parent . mkdir ( parents = True , exist_ok = True )
full_path . write_text ( code , encoding = "utf-8" )
2026-04-19 15:22:49 +03:00
print ( f "[DevAgent] ✅ Written: { file_path } ( { len ( code ) } chars)" )
2026-03-02 04:30:10 +03:00
return code
except Exception as e :
if _is_rate_limit ( e ):
raise RateLimitError ( str ( e ))
raise
def _install_dependencies ( dependencies : list [ str ], project_dir : Path ) -> str :
if not dependencies :
2026-04-19 15:22:49 +03:00
return "No external dependencies."
to_install = []
for dep in dependencies :
pkg_name = re . split ( r "[>=<!]" , dep )[ 0 ] . strip ()
result = subprocess . run (
[ sys . executable , "-m" , "pip" , "show" , pkg_name ],
capture_output = True , text = True
)
if result . returncode != 0 :
to_install . append ( dep )
else :
print ( f "[DevAgent] ✓ Already installed: { pkg_name } " )
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
if not to_install :
return f "All dependencies already installed: { ', ' . join ( dependencies ) } "
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
print ( f "[DevAgent] 📦 Installing: { to_install } " )
2026-03-02 04:30:10 +03:00
try :
result = subprocess . run (
2026-04-19 15:22:49 +03:00
[ sys . executable , "-m" , "pip" , "install" ] + to_install ,
2026-03-02 04:30:10 +03:00
capture_output = True , text = True ,
encoding = "utf-8" , errors = "replace" ,
timeout = 120 , cwd = str ( project_dir )
)
if result . returncode == 0 :
2026-04-19 15:22:49 +03:00
return f "Installed: { ', ' . join ( to_install ) } "
return f "Install warning (non-fatal): { result . stderr [: 200 ] } "
2026-03-02 04:30:10 +03:00
except subprocess . TimeoutExpired :
2026-04-19 15:22:49 +03:00
return "Dependency install timed out (non-fatal)."
2026-03-02 04:30:10 +03:00
except Exception as e :
2026-04-19 15:22:49 +03:00
return f "Install error (non-fatal): { e } "
2026-03-02 04:30:10 +03:00
def _open_vscode ( project_dir : Path ) -> bool :
2026-04-19 15:22:49 +03:00
vscode_candidates = [
2026-03-02 04:30:10 +03:00
"code" ,
2026-04-19 15:22:49 +03:00
rf "C:\Users\ { Path . home () . name } \AppData\Local\Programs\Microsoft VS Code\bin\code.cmd" ,
r "C:\Program Files\Microsoft VS Code\bin\code.cmd" ,
2026-03-02 04:30:10 +03:00
]
2026-04-19 15:22:49 +03:00
for cmd in vscode_candidates :
2026-03-02 04:30:10 +03:00
try :
subprocess . Popen (
[ cmd , str ( project_dir )],
2026-04-19 15:22:49 +03:00
shell = True ,
2026-03-02 04:30:10 +03:00
stdout = subprocess . DEVNULL ,
2026-04-19 15:22:49 +03:00
stderr = subprocess . DEVNULL
2026-03-02 04:30:10 +03:00
)
2026-04-19 15:22:49 +03:00
time . sleep ( 1.5 )
2026-03-02 04:30:10 +03:00
print ( f "[DevAgent] 💻 VSCode opened: { project_dir } " )
return True
except Exception :
continue
return False
def _run_project ( run_command : str , project_dir : Path , timeout : int = 30 ) -> str :
print ( f "[DevAgent] 🚀 Running: { run_command } " )
try :
parts = run_command . split ()
2026-04-19 15:22:49 +03:00
if parts [ 0 ] . lower () == "python" :
2026-03-02 04:30:10 +03:00
parts [ 0 ] = sys . executable
result = subprocess . run (
parts ,
capture_output = True , text = True ,
encoding = "utf-8" , errors = "replace" ,
2026-04-19 15:22:49 +03:00
timeout = timeout ,
cwd = str ( project_dir )
2026-03-02 04:30:10 +03:00
)
2026-04-19 15:22:49 +03:00
stdout = result . stdout . strip ()
stderr = result . stderr . strip ()
combined_parts = []
if stdout :
combined_parts . append ( f "STDOUT: \n { stdout } " )
if stderr :
combined_parts . append ( f "STDERR: \n { stderr } " )
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
return " \n\n " . join ( combined_parts ) if combined_parts else "Ran with no output."
2026-03-02 04:30:10 +03:00
except subprocess . TimeoutExpired :
2026-04-19 15:22:49 +03:00
return f "Timed out after { timeout } s — long-running app (server/GUI) is likely working."
2026-03-02 04:30:10 +03:00
except FileNotFoundError as e :
return f "Command not found: { e } "
except Exception as e :
return f "Run error: { e } "
2026-04-19 15:22:49 +03:00
def _try_auto_install ( error_output : str , project_dir : Path ) -> bool :
"""ModuleNotFoundError varsa eksik paketi otomatik kurmaya çalışır."""
pattern = re . compile (
r "No module named [' \" ]([a-zA-Z0-9_\-\.]+)[' \" ]" , re . IGNORECASE
)
match = pattern . search ( error_output )
if not match :
return False
pkg = match . group ( 1 ) . replace ( "_" , "-" ) . split ( "." )[ 0 ]
print ( f "[DevAgent] 🔧 Auto-installing missing package: { pkg } " )
try :
result = subprocess . run (
[ sys . executable , "-m" , "pip" , "install" , pkg ],
capture_output = True , text = True ,
encoding = "utf-8" , errors = "replace" ,
timeout = 60 , cwd = str ( project_dir )
)
return result . returncode == 0
except Exception :
return False
def _fix_files (
2026-03-02 04:30:10 +03:00
error_output : str ,
project_description : str ,
all_files : list [ dict ],
2026-04-19 15:22:49 +03:00
file_codes : dict [ str , str ],
2026-03-02 04:30:10 +03:00
language : str ,
2026-04-19 15:22:49 +03:00
project_dir : Path ,
entry_point : str ,
) -> dict [ str , str ]:
2026-03-02 04:30:10 +03:00
model = _get_model ( MODEL_PLANNER )
2026-04-19 15:22:49 +03:00
error_file , error_line = _parse_traceback ( error_output , list ( file_codes . keys ()))
error_type = _classify_error ( error_output )
files_to_fix : list [ str ] = []
if error_file :
files_to_fix . append ( error_file )
if error_type == "import_error" :
for fi in all_files :
if error_file . replace ( "/" , "." ) . replace ( ".py" , "" ) in fi . get ( "imports" , []):
p = fi [ "path" ]
if p not in files_to_fix :
files_to_fix . append ( p )
else :
files_to_fix . append ( entry_point )
updated_codes : dict [ str , str ] = {}
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
for fix_path in files_to_fix :
current_code = file_codes . get ( fix_path , "" )
other_ctx = ""
for fp , code in file_codes . items ():
if fp != fix_path and code :
snippet = code [: 1500 ] + ( "..." if len ( code ) > 1500 else "" )
other_ctx += f " \n --- { fp } --- \n { snippet } \n "
line_hint = f " \n Error appears to be near line { error_line } in this file." if (
error_line and fix_path == error_file
) else ""
prompt = f """You are an expert { language } debugger. Fix the broken file below.
2026-03-02 04:30:10 +03:00
Project goal: { project_description }
2026-04-19 15:22:49 +03:00
All project files:
{ chr ( 10 ) . join ( f " - { f [ 'path' ] } : { f . get ( 'description' , '' ) } " for f in all_files ) }
Other files for context (read-only — fix only the target file):
{ other_ctx [: 3500 ] }
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
File to fix: { fix_path }{ line_hint }
Error type: { error_type }
2026-03-02 04:30:10 +03:00
Error output:
2026-04-19 15:22:49 +03:00
{ error_output [: 2500 ] }
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
Current (broken) code:
2026-03-02 04:30:10 +03:00
{ current_code }
2026-04-19 15:22:49 +03:00
Rules:
- Output ONLY the complete fixed code. No explanation, no markdown, no backticks.
- Fix ALL errors visible in the error output.
- Keep all existing correct logic — do not remove working features.
- Ensure import paths match the actual project file structure exactly.
- Do NOT introduce new bugs or remove error handling.
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
Fixed code for { fix_path } :"""
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
try :
response = model . generate_content ( prompt )
fixed = _strip_fences ( response . text )
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
full_path = project_dir / fix_path
full_path . parent . mkdir ( parents = True , exist_ok = True )
full_path . write_text ( fixed , encoding = "utf-8" )
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
updated_codes [ fix_path ] = fixed
print ( f "[DevAgent] 🔧 Fixed: { fix_path } " )
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
except Exception as e :
if _is_rate_limit ( e ):
raise RateLimitError ( str ( e ))
print ( f "[DevAgent] ⚠️ Could not fix { fix_path } : { e } " )
return updated_codes
2026-03-02 04:30:10 +03:00
def _build_project (
description : str ,
language : str ,
project_name : str ,
timeout : int ,
speak = None ,
2026-04-19 15:22:49 +03:00
player = None ,
2026-03-02 04:30:10 +03:00
) -> str :
def log ( msg : str ):
print ( f "[DevAgent] { msg } " )
if player :
player . write_log ( f "[DevAgent] { msg } " )
log ( "Planning project structure..." )
try :
plan = _plan_project ( description , language )
except RateLimitError :
2026-04-19 15:22:49 +03:00
msg = "Rate limit reached, sir. Please try again in a moment."
2026-03-02 04:30:10 +03:00
if speak : speak ( msg )
return msg
except ValueError as e :
msg = f "Planning failed: { e } "
if speak : speak ( msg )
return msg
2026-04-19 15:22:49 +03:00
proj_name = project_name or plan . get ( "project_name" , "jarvis_project" )
proj_name = re . sub ( r "[^\w\-]" , "_" , proj_name )
project_dir = PROJECTS_DIR / proj_name
2026-03-02 04:30:10 +03:00
project_dir . mkdir ( parents = True , exist_ok = True )
2026-04-19 15:22:49 +03:00
files = plan . get ( "files" , [])
entry_point = plan . get ( "entry_point" , "main.py" )
run_command = plan . get ( "run_command" , f "python { entry_point } " )
2026-03-02 04:30:10 +03:00
dependencies = plan . get ( "dependencies" , [])
log ( f "Project: { proj_name } | Files: { len ( files ) } | Entry: { entry_point } " )
2026-04-19 15:22:49 +03:00
def _dep_sort_key ( fi : dict ) -> int :
return len ( fi . get ( "imports" , []))
sorted_files = sorted ( files , key = _dep_sort_key )
2026-03-02 04:30:10 +03:00
file_codes : dict [ str , str ] = {}
2026-04-19 15:22:49 +03:00
for file_info in sorted_files :
2026-03-02 04:30:10 +03:00
file_path = file_info . get ( "path" , "" )
if not file_path :
continue
log ( f "Writing { file_path } ..." )
2026-04-19 15:22:49 +03:00
for attempt in range ( 2 ):
try :
code = _write_file (
file_info = file_info ,
project_description = description ,
all_files = files ,
language = language ,
project_dir = project_dir ,
already_written = file_codes ,
)
file_codes [ file_path ] = code
time . sleep ( 0.4 )
break
except RateLimitError :
if attempt == 0 :
log ( "Rate limit — waiting 20s..." )
time . sleep ( 20 )
else :
log ( f "Rate limit retry failed for { file_path } , skipping." )
except Exception as e :
log ( f "Failed to write { file_path } : { e } " )
break
2026-03-02 04:30:10 +03:00
if not file_codes :
2026-04-19 15:22:49 +03:00
msg = "I could not write any project files, sir."
2026-03-02 04:30:10 +03:00
if speak : speak ( msg )
return msg
if dependencies :
2026-04-19 15:22:49 +03:00
install_result = _install_dependencies ( dependencies , project_dir )
log ( install_result )
2026-03-02 04:30:10 +03:00
_open_vscode ( project_dir )
2026-04-19 15:22:49 +03:00
last_output = ""
auto_installs = 0
2026-03-02 04:30:10 +03:00
for attempt in range ( 1 , MAX_FIX_ATTEMPTS + 1 ):
log ( f "Running project (attempt { attempt } / { MAX_FIX_ATTEMPTS } )..." )
last_output = _run_project ( run_command , project_dir , timeout )
2026-04-19 15:22:49 +03:00
log ( f "Output preview: { last_output [: 150 ] } " )
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
if not _has_error ( last_output , run_command ):
2026-03-02 04:30:10 +03:00
msg = (
f "Project ' { proj_name } ' is working, sir. "
f "Built in { attempt } attempt { 's' if attempt > 1 else '' } . "
2026-04-19 15:22:49 +03:00
f "Saved to: { project_dir } "
2026-03-02 04:30:10 +03:00
)
if speak : speak ( msg )
return f " { msg } \n\n Output: \n { last_output } "
if attempt == MAX_FIX_ATTEMPTS :
break
2026-04-19 15:22:49 +03:00
error_type = _classify_error ( last_output )
if error_type == "dependency_error" and auto_installs < 3 :
installed = _try_auto_install ( last_output , project_dir )
if installed :
auto_installs += 1
log ( "Missing dependency installed, retrying..." )
time . sleep ( 1 )
continue
2026-03-02 04:30:10 +03:00
2026-04-19 15:22:49 +03:00
log ( f "Fixing errors (type: { error_type } )..." )
2026-03-02 04:30:10 +03:00
try :
2026-04-19 15:22:49 +03:00
updated = _fix_files (
error_output = last_output ,
project_description = description ,
all_files = files ,
file_codes = file_codes ,
language = language ,
project_dir = project_dir ,
entry_point = entry_point ,
2026-03-02 04:30:10 +03:00
)
2026-04-19 15:22:49 +03:00
file_codes . update ( updated )
time . sleep ( 1 )
2026-03-02 04:30:10 +03:00
except RateLimitError :
2026-04-19 15:22:49 +03:00
msg = "Rate limit reached during fix. Project saved, check it manually in VSCode."
2026-03-02 04:30:10 +03:00
if speak : speak ( msg )
return msg
except Exception as e :
2026-04-19 15:22:49 +03:00
log ( f "Fix step failed: { e } " )
2026-03-02 04:30:10 +03:00
msg = (
2026-04-19 15:22:49 +03:00
f "I couldn't fully fix ' { proj_name } ' after { MAX_FIX_ATTEMPTS } attempts, sir. "
f "Project is saved at { project_dir } — open it in VSCode and check manually."
2026-03-02 04:30:10 +03:00
)
if speak : speak ( msg )
2026-04-19 15:22:49 +03:00
return f " { msg } \n\n Last error: \n { last_output [: 600 ] } "
2026-03-02 04:30:10 +03:00
def dev_agent (
parameters : dict ,
response = None ,
player = None ,
session_memory = None ,
2026-04-19 15:22:49 +03:00
speak = None ,
2026-03-02 04:30:10 +03:00
) -> str :
p = parameters or {}
description = p . get ( "description" , "" ) . strip ()
language = p . get ( "language" , "python" ) . strip ()
project_name = p . get ( "project_name" , "" ) . strip ()
timeout = int ( p . get ( "timeout" , 30 ))
if not description :
return "Please describe the project you want me to build, sir."
return _build_project (
description = description ,
language = language ,
project_name = project_name ,
timeout = timeout ,
speak = speak ,
2026-04-19 15:22:49 +03:00
player = player ,
2026-03-02 04:30:10 +03:00
)