nimcode 0.3.3__tar.gz → 0.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nimcode-0.3.3 → nimcode-0.3.4}/PKG-INFO +1 -1
- {nimcode-0.3.3 → nimcode-0.3.4}/README.md +14 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/setup.py +1 -1
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/agent.py +13 -4
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/config.py +6 -1
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/nim_client.py +5 -4
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/tools.py +10 -3
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/updater.py +6 -1
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode.egg-info/PKG-INFO +1 -1
- {nimcode-0.3.3 → nimcode-0.3.4}/setup.cfg +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/__init__.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/cli.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/lenient_parser.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/mcp_client.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/memory.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/permissions.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/plugin_manager.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/rag.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/repl.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode/watcher.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode.egg-info/SOURCES.txt +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode.egg-info/dependency_links.txt +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode.egg-info/entry_points.txt +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode.egg-info/requires.txt +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/src/nimcode.egg-info/top_level.txt +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_agent.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_cli.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_config.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_lenient_parser.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_mcp_client.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_memory.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_nim_client.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_permissions.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_plugin_manager.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_repl.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_repl_extra.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_repl_trust.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_tools.py +0 -0
- {nimcode-0.3.3 → nimcode-0.3.4}/tests/test_updater.py +0 -0
|
@@ -121,6 +121,20 @@ NimCode creates a `.nimcode` directory inside your projects. This directory acts
|
|
|
121
121
|
- `.nimcode/skills/`: Any custom guidelines, framework rules, or memories you teach the agent.
|
|
122
122
|
- `.nimcode/history/`: File backups for `/undo` capabilities.
|
|
123
123
|
|
|
124
|
+
### Advanced Configuration (Timeouts)
|
|
125
|
+
|
|
126
|
+
NimCode's limits and timeouts can be customized through the `.nimcode/settings.json` file. Setting any timeout to `0` will completely disable it (infinite timeout).
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"timeout_command": 1200, // Max time for bash commands (in seconds)
|
|
131
|
+
"timeout_llm": 120, // Max time for LLM API responses (in seconds)
|
|
132
|
+
"timeout_format": 10, // Max time for auto-formatters like black/prettier
|
|
133
|
+
"timeout_browser": 15000, // Max time for browser operations (in milliseconds)
|
|
134
|
+
"timeout_updater": 3 // Max time for update checks
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
124
138
|
## 🛡️ Requirements
|
|
125
139
|
|
|
126
140
|
- Python 3.8+
|
|
@@ -53,7 +53,12 @@ class Agent:
|
|
|
53
53
|
self.settings = load_settings()
|
|
54
54
|
self.model = model or self.settings.get("model", "meta/llama-3.1-70b-instruct")
|
|
55
55
|
api_base_url = self.settings.get("api_base_url", "https://integrate.api.nvidia.com/v1")
|
|
56
|
-
self.client = NimClient(
|
|
56
|
+
self.client = NimClient(
|
|
57
|
+
api_key=api_key,
|
|
58
|
+
base_url=api_base_url,
|
|
59
|
+
model=self.model,
|
|
60
|
+
timeout=self.settings.get("timeout_llm", 120.0)
|
|
61
|
+
)
|
|
57
62
|
|
|
58
63
|
# Initialize MCP Manager
|
|
59
64
|
self.mcp = MCPManager(self.settings)
|
|
@@ -338,8 +343,10 @@ class Agent:
|
|
|
338
343
|
if file_path.endswith(".py"):
|
|
339
344
|
import subprocess
|
|
340
345
|
try:
|
|
341
|
-
|
|
342
|
-
|
|
346
|
+
t_fmt = self.settings.get("timeout_format", 10)
|
|
347
|
+
t_fmt = None if t_fmt == 0 else t_fmt
|
|
348
|
+
subprocess.run(["black", "-q", file_path], capture_output=True, timeout=t_fmt)
|
|
349
|
+
lint = subprocess.run(["flake8", "--select=E9,F821,F822,F823", file_path], capture_output=True, text=True, timeout=t_fmt)
|
|
343
350
|
if lint.returncode != 0:
|
|
344
351
|
import sys
|
|
345
352
|
if sys.stdin.isatty():
|
|
@@ -357,7 +364,9 @@ class Agent:
|
|
|
357
364
|
elif file_path.endswith((".js", ".ts", ".jsx", ".tsx")):
|
|
358
365
|
import subprocess
|
|
359
366
|
try:
|
|
360
|
-
|
|
367
|
+
t_fmt = self.settings.get("timeout_format", 10)
|
|
368
|
+
t_fmt = None if t_fmt == 0 else t_fmt
|
|
369
|
+
subprocess.run(["npx", "--yes", "prettier", "--write", file_path], capture_output=True, timeout=t_fmt)
|
|
361
370
|
except Exception:
|
|
362
371
|
pass
|
|
363
372
|
except KeyboardInterrupt:
|
|
@@ -10,7 +10,12 @@ def load_settings() -> Dict[str, Any]:
|
|
|
10
10
|
settings = {
|
|
11
11
|
"model": "meta/llama-3.1-70b-instruct",
|
|
12
12
|
"api_base_url": "https://integrate.api.nvidia.com/v1",
|
|
13
|
-
"mcp_servers": {}
|
|
13
|
+
"mcp_servers": {},
|
|
14
|
+
"timeout_command": 1200, # Timeout for bash commands (seconds)
|
|
15
|
+
"timeout_llm": 120, # Timeout for LLM API calls (seconds)
|
|
16
|
+
"timeout_format": 10, # Timeout for formatting/linting tools (seconds)
|
|
17
|
+
"timeout_browser": 15000, # Timeout for browser actions (milliseconds)
|
|
18
|
+
"timeout_updater": 3 # Timeout for update checks (seconds)
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
# Global settings
|
|
@@ -8,10 +8,11 @@ from typing import List, Dict, Any, Optional, AsyncGenerator
|
|
|
8
8
|
logger = logging.getLogger(__name__)
|
|
9
9
|
|
|
10
10
|
class NimClient:
|
|
11
|
-
def __init__(self, api_key: str, base_url: str = "https://integrate.api.nvidia.com/v1", model: str = "meta/llama-3.1-70b-instruct"):
|
|
11
|
+
def __init__(self, api_key: str, base_url: str = "https://integrate.api.nvidia.com/v1", model: str = "meta/llama-3.1-70b-instruct", timeout: float = 120.0):
|
|
12
12
|
self.api_key = api_key
|
|
13
13
|
self.base_url = base_url.rstrip("/")
|
|
14
14
|
self.model = model
|
|
15
|
+
self.timeout = None if timeout == 0 else timeout
|
|
15
16
|
self.headers = {
|
|
16
17
|
"Authorization": f"Bearer {self.api_key}",
|
|
17
18
|
"Content-Type": "application/json",
|
|
@@ -39,7 +40,7 @@ class NimClient:
|
|
|
39
40
|
f"{self.base_url}/chat/completions",
|
|
40
41
|
headers=self.headers,
|
|
41
42
|
json=payload,
|
|
42
|
-
timeout=
|
|
43
|
+
timeout=self.timeout
|
|
43
44
|
)
|
|
44
45
|
response.raise_for_status()
|
|
45
46
|
data = response.json()
|
|
@@ -70,7 +71,7 @@ class NimClient:
|
|
|
70
71
|
f"{self.base_url}/chat/completions",
|
|
71
72
|
headers=self.headers,
|
|
72
73
|
json=payload,
|
|
73
|
-
timeout=
|
|
74
|
+
timeout=self.timeout
|
|
74
75
|
)
|
|
75
76
|
response.raise_for_status()
|
|
76
77
|
data = response.json()
|
|
@@ -98,7 +99,7 @@ class NimClient:
|
|
|
98
99
|
chunk_yielded = False
|
|
99
100
|
try:
|
|
100
101
|
async with httpx.AsyncClient() as client:
|
|
101
|
-
async with client.stream("POST", f"{self.base_url}/chat/completions", headers=self.headers, json=payload, timeout=
|
|
102
|
+
async with client.stream("POST", f"{self.base_url}/chat/completions", headers=self.headers, json=payload, timeout=self.timeout) as response:
|
|
102
103
|
if response.status_code in [408, 429, 500, 502, 503, 504, 529]:
|
|
103
104
|
raise httpx.HTTPStatusError(f"Temporary server error {response.status_code}", request=response.request, response=response)
|
|
104
105
|
|
|
@@ -239,6 +239,8 @@ class ToolRegistry:
|
|
|
239
239
|
return f"Started task '{task_id}' in the background. Check logs at {log_file}. Use /tasks to manage."
|
|
240
240
|
|
|
241
241
|
try:
|
|
242
|
+
t_cmd = settings.get("timeout_command", 1200)
|
|
243
|
+
t_cmd = None if t_cmd == 0 else t_cmd
|
|
242
244
|
result = subprocess.run(
|
|
243
245
|
command,
|
|
244
246
|
shell=True,
|
|
@@ -246,7 +248,7 @@ class ToolRegistry:
|
|
|
246
248
|
stdout=subprocess.PIPE,
|
|
247
249
|
stderr=subprocess.PIPE,
|
|
248
250
|
text=True,
|
|
249
|
-
timeout=
|
|
251
|
+
timeout=t_cmd
|
|
250
252
|
)
|
|
251
253
|
out = result.stdout + "\n" + result.stderr
|
|
252
254
|
out = out.strip()
|
|
@@ -257,7 +259,7 @@ class ToolRegistry:
|
|
|
257
259
|
|
|
258
260
|
return out if out else "Command executed successfully with no output."
|
|
259
261
|
except subprocess.TimeoutExpired:
|
|
260
|
-
return "Error: Command timed out after
|
|
262
|
+
return f"Error: Command timed out after {t_cmd} seconds."
|
|
261
263
|
except Exception as e:
|
|
262
264
|
return f"Error running bash: {e}"
|
|
263
265
|
|
|
@@ -565,11 +567,16 @@ class ToolRegistry:
|
|
|
565
567
|
try:
|
|
566
568
|
from playwright.sync_api import sync_playwright
|
|
567
569
|
import base64
|
|
570
|
+
from .config import load_settings
|
|
571
|
+
|
|
572
|
+
settings = load_settings()
|
|
573
|
+
t_browser = settings.get("timeout_browser", 15000)
|
|
574
|
+
t_browser = 0 if t_browser == 0 else t_browser
|
|
568
575
|
|
|
569
576
|
with sync_playwright() as p:
|
|
570
577
|
browser = p.chromium.launch(headless=True)
|
|
571
578
|
page = browser.new_page()
|
|
572
|
-
page.goto(url, wait_until="networkidle", timeout=
|
|
579
|
+
page.goto(url, wait_until="networkidle", timeout=t_browser)
|
|
573
580
|
|
|
574
581
|
screenshot_bytes = page.screenshot(type="jpeg", quality=50)
|
|
575
582
|
b64_img = base64.b64encode(screenshot_bytes).decode('utf-8')
|
|
@@ -13,7 +13,12 @@ class AutoUpdater:
|
|
|
13
13
|
Returns the latest version string if > CURRENT_VERSION, else None.
|
|
14
14
|
"""
|
|
15
15
|
try:
|
|
16
|
-
|
|
16
|
+
from .config import load_settings
|
|
17
|
+
settings = load_settings()
|
|
18
|
+
t_upd = settings.get("timeout_updater", 3.0)
|
|
19
|
+
t_upd = None if t_upd == 0 else t_upd
|
|
20
|
+
|
|
21
|
+
async with httpx.AsyncClient(timeout=t_upd) as client:
|
|
17
22
|
response = await client.get("https://pypi.org/pypi/nimcode/json")
|
|
18
23
|
if response.status_code == 200:
|
|
19
24
|
data = response.json()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|