Skip to content

Commit 6b964bc

Browse files
committed
feat: fixed package manager issues with retry circuit logic
1 parent 37fe2bf commit 6b964bc

3 files changed

Lines changed: 78 additions & 34 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ venv/
2222
myvenv/
2323
heaven_venv/
2424
.venv/
25+
node_modules/
2526

2627
# Interactive environment data
2728
interp/

libs/interpreter_lib.py

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import shlex
3333
import shutil
3434
from rich.console import Console
35-
from rich.text import Text
3635

3736
litellm.set_verbose = False
3837
litellm.suppress_debug_info = True
@@ -1242,7 +1241,7 @@ def interpreter_main(self, version):
12421241
elif any(command in task.lower() for command in ['/mode ']):
12431242
mode = task.split(' ')[1]
12441243
if mode:
1245-
if not mode.lower() in ['code','script','command','vision','chat']:
1244+
if mode.lower() not in ['code','script','command','vision','chat']:
12461245
mode = 'code'
12471246
display_markdown_message(f"The input mode is not supported. Mode changed to {mode},"
12481247
"\nUse '/list' command to get the list of supported modes.")
@@ -1290,22 +1289,46 @@ def interpreter_main(self, version):
12901289
continue
12911290

12921291
# INSTALL - Command section.
1293-
elif any(command in task.lower() for command in ['/install']):
1294-
# get the package name after the command
1295-
package_name = task.split(' ')[1]
1292+
elif task.lower().startswith('/install'):
1293+
parts = task.split(' ')
1294+
if len(parts) >= 3:
1295+
# Case: /install <language> <package>
1296+
language = parts[1].lower()
1297+
package_name = parts[2]
1298+
1299+
# Validate language
1300+
if language in ['python', 'py']:
1301+
language = 'python'
1302+
elif language in ['javascript', 'js', 'node']:
1303+
language = 'javascript'
1304+
else:
1305+
# If unknown language, treat as package name to be safe
1306+
package_name = parts[1]
1307+
language = self.INTERPRETER_LANGUAGE
1308+
elif len(parts) == 2:
1309+
package_name = parts[1]
1310+
language = self.INTERPRETER_LANGUAGE
1311+
else:
1312+
display_markdown_message("Usage: **/install [language] <package_name>**")
1313+
continue
12961314

12971315
# check if package name is not system module.
12981316
system_modules = self.package_manager.get_system_modules()
12991317

1300-
# Skip installing system modules.
13011318
if package_name in system_modules:
13021319
self.logger.info(f"Package {package_name} is a system module.")
13031320
display_markdown_message(f"Package {package_name} is a system module.")
1304-
raise Exception(f"Package {package_name} is a system module.")
1321+
continue
13051322

13061323
if package_name:
1307-
self.logger.info(f"Installing package {package_name} on interpreter {self.INTERPRETER_LANGUAGE}")
1308-
self.package_manager.install_package(package_name, self.INTERPRETER_LANGUAGE)
1324+
self.logger.info(f"Installing package {package_name} for {language}")
1325+
display_markdown_message(f"Installing package **{package_name}** for **{language}**...")
1326+
try:
1327+
self.package_manager.install_package(package_name, language)
1328+
display_markdown_message(f"Successfully installed **{package_name}**")
1329+
except Exception as ex:
1330+
self.logger.error(f"Manual installation failed: {ex}")
1331+
display_markdown_message(f"Failed to install **{package_name}**: {ex}")
13091332
continue
13101333

13111334
# Get the prompt based on the mode.
@@ -1492,21 +1515,32 @@ def interpreter_main(self, version):
14921515
raise Exception(f"Package {package_name} is a system module.")
14931516

14941517
if package_name:
1495-
self.logger.info(f"Installing package {package_name} on interpreter {self.INTERPRETER_LANGUAGE}")
1496-
self.package_manager.install_package(package_name, self.INTERPRETER_LANGUAGE)
1497-
1498-
# Wait and Execute the code again.
1499-
time.sleep(3)
1500-
code_output, code_error = self._execute_generated_output(code_snippet, os_name, force_execute=True)
1501-
if code_output:
1502-
self.logger.info(f"{self.INTERPRETER_LANGUAGE} code executed successfully.")
1503-
display_code(code_output)
1504-
self.logger.info(f"Output: {code_output[:100]}")
1505-
elif code_error:
1506-
self.logger.info(f"{self.INTERPRETER_LANGUAGE} code executed with error.")
1507-
display_markdown_message(f"Error: {code_error}")
1508-
else:
1509-
display_markdown_message("Execution completed successfully. No stdout was produced.")
1518+
for attempt in range(1, 4):
1519+
try:
1520+
self.logger.info(f"Installing package {package_name} on interpreter {self.INTERPRETER_LANGUAGE} (Attempt {attempt}/3)")
1521+
self.package_manager.install_package(package_name, self.INTERPRETER_LANGUAGE)
1522+
1523+
# Wait and Execute the code again.
1524+
time.sleep(3)
1525+
code_output, code_error = self._execute_generated_output(code_snippet, os_name, force_execute=True)
1526+
if code_output:
1527+
self.logger.info(f"{self.INTERPRETER_LANGUAGE} code executed successfully.")
1528+
display_code(code_output)
1529+
self.logger.info(f"Output: {code_output[:100]}")
1530+
elif code_error:
1531+
self.logger.info(f"{self.INTERPRETER_LANGUAGE} code executed with error.")
1532+
display_markdown_message(f"Error: {code_error}")
1533+
else:
1534+
display_markdown_message("Execution completed successfully. No stdout was produced.")
1535+
break # Exit retry loop on success
1536+
except Exception as ex:
1537+
if attempt < 3:
1538+
self.logger.warning(f"Attempt {attempt} to install package {package_name} failed: {ex}")
1539+
display_markdown_message(f"Attempt {attempt}/3 to install package **{package_name}** failed. Retrying in 2 seconds...")
1540+
time.sleep(2)
1541+
else:
1542+
self.logger.error(f"Failed to install package {package_name} after 3 attempts: {ex}")
1543+
display_markdown_message(f"Failed to install package **{package_name}** after 3 attempts. Error: {ex}. Proceeding with repair logic...")
15101544

15111545
if code_error and not code_error.startswith("Safety blocked:"):
15121546
code_snippet, repaired_output, repaired_error = self._attempt_repair_after_failure(

libs/package_manager.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import subprocess
22
import re
3-
import logging
43
import requests
54
import stdlib_list
5+
import os
66
from libs.logger import Logger
77

88

@@ -15,6 +15,15 @@ def __init__(self):
1515
self.npm_command = "npm"
1616
self.logger = Logger.initialize("logs/interpreter.log")
1717

18+
def _run_command(self, args):
19+
"""Run a shell command with OS-appropriate settings."""
20+
try:
21+
# On Windows, shell=True is needed to resolve script-based commands like npm or pip
22+
use_shell = os.name == 'nt'
23+
return subprocess.check_call(args, shell=use_shell)
24+
except subprocess.CalledProcessError as e:
25+
raise e
26+
1827
def install_package(self, package_name, language):
1928
if language == "python":
2029
if not self._check_package_exists_pip(package_name):
@@ -77,23 +86,23 @@ def get_system_modules(self):
7786

7887
def _install_package_with_pip(self, package_name):
7988
try:
80-
subprocess.check_call([self.pip_command, "install", package_name])
89+
self._run_command([self.pip_command, "install", package_name])
8190
self.logger.info(f"Successfully installed package with pip: {package_name}")
8291
except subprocess.CalledProcessError as exception:
8392
self.logger.error(f"Failed to install package with pip: {package_name}")
8493
raise exception
8594

8695
def _install_package_with_pip3(self, package_name):
8796
try:
88-
subprocess.check_call([self.pip3_command, "install", package_name])
97+
self._run_command([self.pip3_command, "install", package_name])
8998
self.logger.info(f"Successfully installed package with pip3: {package_name}")
9099
except subprocess.CalledProcessError as exception:
91100
self.logger.error(f"Failed to install package with pip3: {package_name}")
92101
raise exception
93102

94103
def _install_package_with_npm(self, package_name):
95104
try:
96-
subprocess.check_call([self.npm_command, "install", package_name])
105+
self._run_command([self.npm_command, "install", package_name])
97106
self.logger.info(f"Successfully installed package with npm: {package_name}")
98107
except subprocess.CalledProcessError as exception:
99108
self.logger.error(f"Failed to install package with npm: {package_name}")
@@ -102,20 +111,20 @@ def _install_package_with_npm(self, package_name):
102111
def _is_package_installed(self, package_name, package_manager):
103112
if package_manager == "pip":
104113
try:
105-
subprocess.check_call([self.pip_command, "show", package_name])
114+
self._run_command([self.pip_command, "show", package_name])
106115
self.logger.info(f"Package {package_name} is installed")
107116
return True
108117
except subprocess.CalledProcessError:
109118
try:
110-
subprocess.check_call([self.pip3_command, "show", package_name])
119+
self._run_command([self.pip3_command, "show", package_name])
111120
self.logger.info(f"Package {package_name} is installed")
112121
return True
113122
except subprocess.CalledProcessError:
114123
self.logger.info(f"Package {package_name} is not installed")
115124
return False
116125
elif package_manager == "npm":
117126
try:
118-
subprocess.check_call([self.npm_command, "list", "-g", package_name])
127+
self._run_command([self.npm_command, "list", "-g", package_name])
119128
self.logger.info(f"Package {package_name} is installed")
120129
return True
121130
except subprocess.CalledProcessError:
@@ -169,12 +178,12 @@ def _check_package_exists_pip(self, package_name):
169178

170179
def _check_package_exists_npm(self, package_name):
171180
try:
172-
response = requests.get(f"https://www.npmjs.com/package/{package_name}")
181+
response = requests.get(f"https://registry.npmjs.org/{package_name}")
173182
if response.status_code == 200:
174-
self.logger.info(f"Package {package_name} exists on npm website")
183+
self.logger.info(f"Package {package_name} exists on npm registry")
175184
return True
176185
else:
177-
self.logger.info(f"Package {package_name} does not exist on npm website")
186+
self.logger.info(f"Package {package_name} does not exist on npm registry")
178187
return False
179188
except requests.exceptions.RequestException as exception:
180189
self.logger.error(f"Failed to check package existence on npm website: {exception}")

0 commit comments

Comments
 (0)