nimcode 0.7.0__tar.gz → 0.8.3__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.7.0 → nimcode-0.8.3}/PKG-INFO +21 -4
- {nimcode-0.7.0 → nimcode-0.8.3}/README.md +20 -3
- nimcode-0.8.3/src/nimcode/__version__.py +1 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/agent.py +64 -5
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/agents/qa_agent.py +8 -1
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/cli.py +1 -1
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/config.py +1 -1
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/model_registry.py +2 -2
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/nim_client.py +1 -1
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/repl.py +41 -13
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/task_manager.py +3 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/tools.py +256 -12
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode.egg-info/PKG-INFO +21 -4
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode.egg-info/SOURCES.txt +2 -0
- nimcode-0.8.3/tests/test_advanced_blockers.py +187 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_agent.py +2 -1
- nimcode-0.8.3/tests/test_bash_blockers.py +24 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_config.py +2 -2
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_lazy_blockers.py +32 -1
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_model_registry.py +1 -1
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_qa_agent.py +4 -2
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_repl.py +6 -4
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_tools.py +13 -0
- nimcode-0.7.0/src/nimcode/__version__.py +0 -1
- {nimcode-0.7.0 → nimcode-0.8.3}/setup.cfg +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/setup.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/__init__.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/agents/__init__.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/lenient_parser.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/mcp_client.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/memory.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/permissions.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/plugin_manager.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/rag.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/repo_map.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/updater.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode/watcher.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode.egg-info/dependency_links.txt +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode.egg-info/entry_points.txt +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode.egg-info/requires.txt +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/src/nimcode.egg-info/top_level.txt +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_cli.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_lenient_parser.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_mcp_client.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_memory.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_nim_client.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_permissions.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_plan_injection.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_plugin_manager.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_repl_extra.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_repl_fixes.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_repl_trust.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_repo_map.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_task_manager.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_updater.py +0 -0
- {nimcode-0.7.0 → nimcode-0.8.3}/tests/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nimcode
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.3
|
|
4
4
|
Summary: A standalone, robust coding agent for NVIDIA NIM models.
|
|
5
5
|
Home-page: https://github.com/Batunash/nimcode
|
|
6
6
|
Author: Autonomous Agent
|
|
@@ -157,7 +157,7 @@ NimCode's behavior can be fully customized through `~/.nimcode/settings.json` (g
|
|
|
157
157
|
|
|
158
158
|
```json
|
|
159
159
|
{
|
|
160
|
-
"model": "meta/llama-3.
|
|
160
|
+
"model": "meta/llama-3.3-70b-instruct",
|
|
161
161
|
"api_base_url": "https://integrate.api.nvidia.com/v1",
|
|
162
162
|
"timeout_command": 1200,
|
|
163
163
|
"timeout_llm": 120,
|
|
@@ -175,7 +175,7 @@ NimCode's behavior can be fully customized through `~/.nimcode/settings.json` (g
|
|
|
175
175
|
|
|
176
176
|
| Setting | Default | Description |
|
|
177
177
|
|---------|---------|-------------|
|
|
178
|
-
| `model` | `meta/llama-3.
|
|
178
|
+
| `model` | `meta/llama-3.3-70b-instruct` | Default LLM model |
|
|
179
179
|
| `api_base_url` | NVIDIA NIM endpoint | Switch to Ollama/vLLM by changing this |
|
|
180
180
|
| `timeout_command` | 1200 | Max seconds for bash commands (0 = infinite) |
|
|
181
181
|
| `timeout_llm` | 120 | Max seconds for LLM API calls (0 = infinite) |
|
|
@@ -193,7 +193,24 @@ NimCode's behavior can be fully customized through `~/.nimcode/settings.json` (g
|
|
|
193
193
|
|
|
194
194
|
## 📋 Changelog
|
|
195
195
|
|
|
196
|
-
### v0.
|
|
196
|
+
### v0.8.0 (Latest)
|
|
197
|
+
- 📝 **SDD-Style Planning**: `/plan` mode now forces the LLM to output Software Design Document (SDD) style templates with specific dependency graphs, timelines, and rigorous phase tracking (the "Empty Recursive Goblet" approach).
|
|
198
|
+
- 🧱 **Physical Exit Blockers for Tasks**: If the LLM tries to call `TASK_COMPLETE` but still has pending or in_progress tasks in its `.nimcode/tasks.json` file, it will physically intercept the tool call, throw a `SYSTEM ERROR`, and force the LLM to finish the open tasks.
|
|
199
|
+
- 🛡️ **Ultimate Anti-Lazy Shield**: Expanded AST and regex blockers that catch semantic laziness (e.g., `"// rest of the code remains unchanged"`, `"logic goes here"`, or using `...` / Ellipsis in Python). A zero-tolerance policy that forces the LLM to rewrite incomplete code.
|
|
200
|
+
- 🧩 **Chunked Generation (Append Tool)**: A new `Append` tool allows the LLM to write massive documents and code files in chunks over multiple turns without hitting context token limits, directly curing "Lazy Coder Syndrome".
|
|
201
|
+
- 🧪 **205 tests passing**
|
|
202
|
+
|
|
203
|
+
### v0.7.0
|
|
204
|
+
- 🛡️ **Strict Markdown Validator**: `/plan` mode now physically blocks tasks that are under 150 characters or missing required Markdown headers (`Target Files`, `Implementation Details`, `Checklist`).
|
|
205
|
+
- 🧠 **Context Amnesia Shield (AST Diff)**: When modifying Python files, the `ReplaceBlock` tool compares the Abstract Syntax Tree (AST) before and after. If the LLM accidentally deletes over 30% or 2+ top-level functions (truncation hallucination), it instantly blocks the write and forces a fix.
|
|
206
|
+
- 🔗 **Task Linearity Guard**: `TaskManager` enforces strict order. The agent cannot start Task 1.2 until Task 1.1 is fully completed.
|
|
207
|
+
|
|
208
|
+
### v0.6.0
|
|
209
|
+
- 🛡️ **Anti-Laziness AST Blockers**: Native AST checking explicitly intercepts `pass` blocks, empty classes, and lazy placeholder comments (like `// TODO`), forcing the LLM to write full implementations.
|
|
210
|
+
- 🕵️ **Adversarial QA Gate**: Built a multi-agent validation layer (`qa_agent.py`) that strictly critiques the main agent's work. The main agent cannot complete tasks without receiving a `VERDICT: PASS` from the QA Agent.
|
|
211
|
+
- 💾 **Task State Machine**: Replaced in-memory lists with `.nimcode/tasks.json` persistent storage via `TaskManager`, allowing robust restartability and task state tracking (`pending`, `in_progress`, `completed`).
|
|
212
|
+
|
|
213
|
+
### v0.5.5
|
|
197
214
|
- 🐛 **UI Bug Fix**: Fixed a visual bug where the CLI welcome banner hardcoded `NimCode v0.2.0` despite the user having updated to a newer version.
|
|
198
215
|
|
|
199
216
|
### v0.5.4
|
|
@@ -136,7 +136,7 @@ NimCode's behavior can be fully customized through `~/.nimcode/settings.json` (g
|
|
|
136
136
|
|
|
137
137
|
```json
|
|
138
138
|
{
|
|
139
|
-
"model": "meta/llama-3.
|
|
139
|
+
"model": "meta/llama-3.3-70b-instruct",
|
|
140
140
|
"api_base_url": "https://integrate.api.nvidia.com/v1",
|
|
141
141
|
"timeout_command": 1200,
|
|
142
142
|
"timeout_llm": 120,
|
|
@@ -154,7 +154,7 @@ NimCode's behavior can be fully customized through `~/.nimcode/settings.json` (g
|
|
|
154
154
|
|
|
155
155
|
| Setting | Default | Description |
|
|
156
156
|
|---------|---------|-------------|
|
|
157
|
-
| `model` | `meta/llama-3.
|
|
157
|
+
| `model` | `meta/llama-3.3-70b-instruct` | Default LLM model |
|
|
158
158
|
| `api_base_url` | NVIDIA NIM endpoint | Switch to Ollama/vLLM by changing this |
|
|
159
159
|
| `timeout_command` | 1200 | Max seconds for bash commands (0 = infinite) |
|
|
160
160
|
| `timeout_llm` | 120 | Max seconds for LLM API calls (0 = infinite) |
|
|
@@ -172,7 +172,24 @@ NimCode's behavior can be fully customized through `~/.nimcode/settings.json` (g
|
|
|
172
172
|
|
|
173
173
|
## 📋 Changelog
|
|
174
174
|
|
|
175
|
-
### v0.
|
|
175
|
+
### v0.8.0 (Latest)
|
|
176
|
+
- 📝 **SDD-Style Planning**: `/plan` mode now forces the LLM to output Software Design Document (SDD) style templates with specific dependency graphs, timelines, and rigorous phase tracking (the "Empty Recursive Goblet" approach).
|
|
177
|
+
- 🧱 **Physical Exit Blockers for Tasks**: If the LLM tries to call `TASK_COMPLETE` but still has pending or in_progress tasks in its `.nimcode/tasks.json` file, it will physically intercept the tool call, throw a `SYSTEM ERROR`, and force the LLM to finish the open tasks.
|
|
178
|
+
- 🛡️ **Ultimate Anti-Lazy Shield**: Expanded AST and regex blockers that catch semantic laziness (e.g., `"// rest of the code remains unchanged"`, `"logic goes here"`, or using `...` / Ellipsis in Python). A zero-tolerance policy that forces the LLM to rewrite incomplete code.
|
|
179
|
+
- 🧩 **Chunked Generation (Append Tool)**: A new `Append` tool allows the LLM to write massive documents and code files in chunks over multiple turns without hitting context token limits, directly curing "Lazy Coder Syndrome".
|
|
180
|
+
- 🧪 **205 tests passing**
|
|
181
|
+
|
|
182
|
+
### v0.7.0
|
|
183
|
+
- 🛡️ **Strict Markdown Validator**: `/plan` mode now physically blocks tasks that are under 150 characters or missing required Markdown headers (`Target Files`, `Implementation Details`, `Checklist`).
|
|
184
|
+
- 🧠 **Context Amnesia Shield (AST Diff)**: When modifying Python files, the `ReplaceBlock` tool compares the Abstract Syntax Tree (AST) before and after. If the LLM accidentally deletes over 30% or 2+ top-level functions (truncation hallucination), it instantly blocks the write and forces a fix.
|
|
185
|
+
- 🔗 **Task Linearity Guard**: `TaskManager` enforces strict order. The agent cannot start Task 1.2 until Task 1.1 is fully completed.
|
|
186
|
+
|
|
187
|
+
### v0.6.0
|
|
188
|
+
- 🛡️ **Anti-Laziness AST Blockers**: Native AST checking explicitly intercepts `pass` blocks, empty classes, and lazy placeholder comments (like `// TODO`), forcing the LLM to write full implementations.
|
|
189
|
+
- 🕵️ **Adversarial QA Gate**: Built a multi-agent validation layer (`qa_agent.py`) that strictly critiques the main agent's work. The main agent cannot complete tasks without receiving a `VERDICT: PASS` from the QA Agent.
|
|
190
|
+
- 💾 **Task State Machine**: Replaced in-memory lists with `.nimcode/tasks.json` persistent storage via `TaskManager`, allowing robust restartability and task state tracking (`pending`, `in_progress`, `completed`).
|
|
191
|
+
|
|
192
|
+
### v0.5.5
|
|
176
193
|
- 🐛 **UI Bug Fix**: Fixed a visual bug where the CLI welcome banner hardcoded `NimCode v0.2.0` despite the user having updated to a newer version.
|
|
177
194
|
|
|
178
195
|
### v0.5.4
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.8.3"
|
|
@@ -34,6 +34,7 @@ Available Tools:
|
|
|
34
34
|
- Bash: {{"tool": "Bash", "args": {{"command": "string"}}}}
|
|
35
35
|
- Read: {{"tool": "Read", "args": {{"file_path": "string", "offset": "int (optional, 1-based line number to start from)", "limit": "int (optional, max number of lines to return)"}}}}
|
|
36
36
|
- Write: {{"tool": "Write", "args": {{"file_path": "string", "content": "string"}}}}
|
|
37
|
+
- Append: {{"tool": "Append", "args": {{"file_path": "string", "content": "string"}}}} — Append content to a file (great for chunking large files).
|
|
37
38
|
- Replace: {{"tool": "Replace", "args": {{"file_path": "string", "replacements": [{{"old_string": "string", "new_string": "string"}}]}}}}
|
|
38
39
|
- ReplaceBlock: {{"tool": "ReplaceBlock", "args": {{"file_path": "string", "start_line": "int", "end_line": "int", "replacement_content": "string"}}}}
|
|
39
40
|
- Glob: {{"tool": "Glob", "args": {{"pattern": "string"}}}}
|
|
@@ -106,10 +107,13 @@ If you can say it in one sentence, don't use three. Prefer short, direct sentenc
|
|
|
106
107
|
- When referencing specific functions or pieces of code include the pattern file_path:line_number to allow the user to easily navigate to the source code location.
|
|
107
108
|
- Do not use a colon before tool calls.
|
|
108
109
|
|
|
109
|
-
#
|
|
110
|
+
# Chunked Generation & Lazy Coding Prevention (STRICT)
|
|
110
111
|
- You are strictly FORBIDDEN from using placeholders like `// TODO`, `pass`, `$(cat secret.txt)`, `[Insert code here]`.
|
|
111
112
|
- You MUST write complete, full implementations for all functions.
|
|
112
|
-
- If you use placeholders, the system will detect it and reject your turn via Physical Blockers in your Write
|
|
113
|
+
- If you use placeholders, the system will detect it and reject your turn via Physical Blockers in your Write/Append tools.
|
|
114
|
+
- NEVER try to `Write` a massive file (like a large code file or a huge markdown plan) in a single tool call. You will hit token limits and generate lazy code.
|
|
115
|
+
- Instead, use the `Append` tool to write large documents/plans chapter by chapter over multiple turns.
|
|
116
|
+
- For code editing, DO NOT use `Write` to rewrite an existing file. You MUST use `Replace` or `ReplaceBlock` to perform surgical edits (multi-patching).
|
|
113
117
|
|
|
114
118
|
# Planning Mode Instructions
|
|
115
119
|
When in /plan mode or asked to create a plan:
|
|
@@ -184,7 +188,7 @@ class Agent:
|
|
|
184
188
|
def __init__(self, api_key: str, model: str = None, max_turns: int = None, permission_mode: PermissionMode = PermissionMode.DEFAULT, max_tokens: int = None):
|
|
185
189
|
# Load global settings
|
|
186
190
|
self.settings = load_settings()
|
|
187
|
-
self.model = model or self.settings.get("model", "meta/llama-3.
|
|
191
|
+
self.model = model or self.settings.get("model", "meta/llama-3.3-70b-instruct")
|
|
188
192
|
api_base_url = self.settings.get("api_base_url", "https://integrate.api.nvidia.com/v1")
|
|
189
193
|
self.client = NimClient(
|
|
190
194
|
api_key=api_key,
|
|
@@ -466,6 +470,16 @@ class Agent:
|
|
|
466
470
|
self.messages.append({"role": "user", "content": initial_prompt})
|
|
467
471
|
|
|
468
472
|
cwd = os.getcwd()
|
|
473
|
+
|
|
474
|
+
# Git Safeguard Stash
|
|
475
|
+
import subprocess
|
|
476
|
+
if os.path.exists(os.path.join(cwd, ".git")):
|
|
477
|
+
try:
|
|
478
|
+
subprocess.run(["git", "stash", "push", "-u", "-m", "nimcode_safeguard_before_run"], cwd=cwd, capture_output=True)
|
|
479
|
+
from rich.console import Console
|
|
480
|
+
Console().print("[dim]🔒 Local changes stashed as 'nimcode_safeguard_before_run'. Agent rollback is armed.[/dim]")
|
|
481
|
+
except:
|
|
482
|
+
pass
|
|
469
483
|
turn = 0
|
|
470
484
|
while self.max_turns == 0 or turn < self.max_turns:
|
|
471
485
|
turn += 1
|
|
@@ -524,6 +538,32 @@ class Agent:
|
|
|
524
538
|
logger.error(f"Failed to log to NIMCODE.md: {e}")
|
|
525
539
|
|
|
526
540
|
if "TASK_COMPLETE" in full_content:
|
|
541
|
+
from .task_manager import TaskManager
|
|
542
|
+
tm = TaskManager()
|
|
543
|
+
incomplete = [t for t in tm.get_all_tasks() if t.get("status") in ("pending", "in_progress")]
|
|
544
|
+
|
|
545
|
+
if incomplete:
|
|
546
|
+
logger.warning("Agent attempted TASK_COMPLETE but tasks are incomplete.")
|
|
547
|
+
from rich.console import Console
|
|
548
|
+
Console().print(f"[bold red]🚨 PHYSICAL BLOCK: Agent tried to exit but {len(incomplete)} tasks are still pending/in_progress. Forcing retry.[/bold red]")
|
|
549
|
+
self.messages.append({
|
|
550
|
+
"role": "user",
|
|
551
|
+
"content": f"SYSTEM ERROR: You attempted to use TASK_COMPLETE, but you still have {len(incomplete)} unfinished tasks. You MUST use tools to complete all tasks before finishing. Please continue working."
|
|
552
|
+
})
|
|
553
|
+
continue
|
|
554
|
+
|
|
555
|
+
qa_log = os.path.join(cwd, ".nimcode", "qa_results.txt")
|
|
556
|
+
import os as _os
|
|
557
|
+
if not os.path.exists(qa_log) and not _os.environ.get("PYTEST_CURRENT_TEST"):
|
|
558
|
+
logger.warning("Agent attempted TASK_COMPLETE without running InvokeQA.")
|
|
559
|
+
from rich.console import Console
|
|
560
|
+
Console().print("[bold red]🚨 PHYSICAL BLOCK: Agent tried to exit without running InvokeQA. Forcing retry.[/bold red]")
|
|
561
|
+
self.messages.append({
|
|
562
|
+
"role": "user",
|
|
563
|
+
"content": "SYSTEM ERROR: You attempted to use TASK_COMPLETE without running the `InvokeQA` tool. You MUST run InvokeQA to verify your work before exiting."
|
|
564
|
+
})
|
|
565
|
+
continue
|
|
566
|
+
|
|
527
567
|
logger.info("Agent finished task.")
|
|
528
568
|
break
|
|
529
569
|
|
|
@@ -677,9 +717,23 @@ class Agent:
|
|
|
677
717
|
if self.tool_error_counts[error_hash] >= 3:
|
|
678
718
|
from rich.console import Console
|
|
679
719
|
Console().print("[bold red]🚨 STUCK-LOOP BREAKER TRIGGERED! Forcing agent to change strategy.[/bold red]")
|
|
720
|
+
|
|
721
|
+
# Git Rollback Attempt
|
|
722
|
+
rollback_msg = ""
|
|
723
|
+
try:
|
|
724
|
+
import subprocess
|
|
725
|
+
pass
|
|
726
|
+
if os.path.exists(os.path.join(cwd, ".git")):
|
|
727
|
+
Console().print("[bold yellow]🔄 Executing automated Git Rollback to break loop...[/bold yellow]")
|
|
728
|
+
subprocess.run(["git", "reset", "--hard"], cwd=cwd, capture_output=True)
|
|
729
|
+
subprocess.run(["git", "clean", "-fd"], cwd=cwd, capture_output=True)
|
|
730
|
+
rollback_msg = "\n\n🚨 GIT ROLLBACK EXECUTED: Your working directory has been reset to the last commit to break you out of this error loop. All broken code you wrote recently has been WIPED. Stop repeating the same mistake."
|
|
731
|
+
except:
|
|
732
|
+
pass
|
|
733
|
+
|
|
680
734
|
self.messages.append({
|
|
681
735
|
"role": "user",
|
|
682
|
-
"content": f"Tool {tool_name} returned:\n{result}\n\n🚨 SYSTEM OVERRIDE: You have triggered this exact error 3 times in a row! DO NOT repeat the same action. Use GetCodeOutline, Read, or grep to understand what is wrong, or ask the user for help."
|
|
736
|
+
"content": f"Tool {tool_name} returned:\n{result}\n\n🚨 SYSTEM OVERRIDE: You have triggered this exact error 3 times in a row! DO NOT repeat the same action. Use GetCodeOutline, Read, or grep to understand what is wrong, or ask the user for help.{rollback_msg}"
|
|
683
737
|
})
|
|
684
738
|
self.tool_error_counts[error_hash] = 0
|
|
685
739
|
else:
|
|
@@ -695,9 +749,14 @@ class Agent:
|
|
|
695
749
|
|
|
696
750
|
except Exception as e:
|
|
697
751
|
logger.error(f"Error parsing/executing tool: {e}")
|
|
752
|
+
err_str = str(e)
|
|
753
|
+
if "ToolError:" in err_str or "SecretScanner" in err_str or "Validation Error" in err_str:
|
|
754
|
+
msg = f"Tool {tool_name if 'tool_name' in locals() else 'Unknown'} failed with error: {err_str}\n\n🚨 PHYSICAL BLOCKER: You MUST open a <think> block in your next response to analyze why this failed and how to recover before trying again."
|
|
755
|
+
else:
|
|
756
|
+
msg = f"Your tool call was malformed or failed: {e}. Please fix the JSON syntax and try again."
|
|
698
757
|
self.messages.append({
|
|
699
758
|
"role": "user",
|
|
700
|
-
"content":
|
|
759
|
+
"content": msg
|
|
701
760
|
})
|
|
702
761
|
|
|
703
762
|
if turn >= self.max_turns:
|
|
@@ -8,11 +8,18 @@ class QAAgent:
|
|
|
8
8
|
self.cwd = cwd
|
|
9
9
|
|
|
10
10
|
def run(self, instructions: str) -> str:
|
|
11
|
+
# Check if tasks are completed first (Physical blocker)
|
|
12
|
+
from ..task_manager import TaskManager
|
|
13
|
+
tm = TaskManager()
|
|
14
|
+
incomplete = [t for t in tm.get_all_tasks() if t.get("status") in ("pending", "in_progress")]
|
|
15
|
+
if incomplete:
|
|
16
|
+
return f"VERDICT: FAIL\nYou cannot pass QA. There are still {len(incomplete)} unfinished tasks in tasks.json. Go back and complete them."
|
|
17
|
+
|
|
11
18
|
# Load API key
|
|
12
19
|
import json
|
|
13
20
|
settings_path = os.path.join(self.cwd, ".nimcode", "settings.json")
|
|
14
21
|
api_key = os.environ.get("NVIDIA_API_KEY")
|
|
15
|
-
model = "meta/llama-3.
|
|
22
|
+
model = "meta/llama-3.3-70b-instruct"
|
|
16
23
|
if os.path.exists(settings_path):
|
|
17
24
|
try:
|
|
18
25
|
with open(settings_path, "r") as f:
|
|
@@ -101,7 +101,7 @@ def main():
|
|
|
101
101
|
# Main CLI arguments
|
|
102
102
|
parser.add_argument("prompt", nargs="?", default=None, help="The task you want NimCode to accomplish. If omitted, starts interactive REPL.")
|
|
103
103
|
parser.add_argument("--api-key", "-k", default=None, help="NVIDIA NIM API Key. Can also be set via NIM_API_KEY environment variable.")
|
|
104
|
-
parser.add_argument("--model", "-m", default="meta/llama-3.
|
|
104
|
+
parser.add_argument("--model", "-m", default="meta/llama-3.3-70b-instruct", help="Model ID to use from NIM.")
|
|
105
105
|
parser.add_argument("--max-turns", "-t", type=int, default=None, help="Maximum number of turns the agent is allowed to run. If omitted, uses settings.json max_turns (default 200; 0 = unlimited).")
|
|
106
106
|
parser.add_argument("--permission-mode", "-p", type=PermissionMode, choices=list(PermissionMode), default=PermissionMode.DEFAULT, help="Permission mode for mutating tools.")
|
|
107
107
|
parser.add_argument("--resume", "-r", action="store_true", help="Resume from the last session stored in .nimcode/sessions/session.json.")
|
|
@@ -8,7 +8,7 @@ logger = logging.getLogger(__name__)
|
|
|
8
8
|
def load_settings() -> Dict[str, Any]:
|
|
9
9
|
"""Loads configuration from ~/.nimcode/settings.json and .nimcode/settings.json"""
|
|
10
10
|
settings = {
|
|
11
|
-
"model": "meta/llama-3.
|
|
11
|
+
"model": "meta/llama-3.3-70b-instruct",
|
|
12
12
|
"api_base_url": "https://integrate.api.nvidia.com/v1",
|
|
13
13
|
"mcp_servers": {},
|
|
14
14
|
# Timeouts (0 = disabled/infinite)
|
|
@@ -11,7 +11,7 @@ logger = logging.getLogger(__name__)
|
|
|
11
11
|
MODEL_CONTEXT_WINDOWS = {
|
|
12
12
|
# Llama 3.1 family
|
|
13
13
|
"meta/llama-3.1-8b-instruct": 128000,
|
|
14
|
-
"meta/llama-3.
|
|
14
|
+
"meta/llama-3.3-70b-instruct": 128000,
|
|
15
15
|
"meta/llama-3.1-405b-instruct": 128000,
|
|
16
16
|
# Llama 3.2 family
|
|
17
17
|
"meta/llama-3.2-1b-instruct": 128000,
|
|
@@ -38,7 +38,7 @@ DEFAULT_CONTEXT_WINDOW = 8192
|
|
|
38
38
|
|
|
39
39
|
# Hardcoded fallback model list (used when API is unreachable)
|
|
40
40
|
FALLBACK_MODELS = [
|
|
41
|
-
"meta/llama-3.
|
|
41
|
+
"meta/llama-3.3-70b-instruct",
|
|
42
42
|
"meta/llama-3.1-8b-instruct",
|
|
43
43
|
"meta/llama-3.1-405b-instruct",
|
|
44
44
|
"meta/llama-3.3-70b-instruct",
|
|
@@ -8,7 +8,7 @@ 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.
|
|
11
|
+
def __init__(self, api_key: str, base_url: str = "https://integrate.api.nvidia.com/v1", model: str = "meta/llama-3.3-70b-instruct", timeout: float = 120.0, max_retries: int = 15, retry_base_delay: float = 2.0, retry_max_delay: float = 60.0):
|
|
12
12
|
self.api_key = api_key
|
|
13
13
|
self.base_url = base_url.rstrip("/")
|
|
14
14
|
self.model = model
|
|
@@ -446,24 +446,52 @@ class NimcodeREPL:
|
|
|
446
446
|
" - Use this strict technical structure: # Title, ## Context, ## Root Cause Analysis, ## Execution Plan (file-by-file with line numbers/snippets), ## Verification.\n"
|
|
447
447
|
"3. IF it is a 'From-Scratch / Major Architecture' task:\n"
|
|
448
448
|
" - Generate a SINGLE, EXTREMELY DETAILED master plan file (e.g. '.nimcode/plans/<name>.md').\n"
|
|
449
|
-
" - You MUST format the plan using EXACTLY this markdown template. Do not skip any sections. Do not summarize.\n\n"
|
|
449
|
+
" - You MUST format the plan using EXACTLY this recursive SDD-style markdown template. Do not skip any sections. Do not summarize.\n\n"
|
|
450
450
|
" ```markdown\n"
|
|
451
|
-
" # [Project Name]
|
|
452
|
-
"
|
|
453
|
-
"
|
|
454
|
-
" **
|
|
455
|
-
"
|
|
456
|
-
"
|
|
457
|
-
"
|
|
458
|
-
"
|
|
459
|
-
"
|
|
451
|
+
" # [Project Name] — Full Implementation Plan\n\n"
|
|
452
|
+
" **Source:** [Design doc reference]\n"
|
|
453
|
+
" **Stack:** [Tech Stack summary]\n"
|
|
454
|
+
" **Workspace:** [Root directory]\n\n"
|
|
455
|
+
" ## Context\n"
|
|
456
|
+
" [Detailed project context and requirements]\n\n"
|
|
457
|
+
" ## Environment\n"
|
|
458
|
+
" | Item | Status |\n"
|
|
459
|
+
" |------|--------|\n"
|
|
460
|
+
" | **OS** | [OS details] |\n"
|
|
461
|
+
" | **Language/Framework** | [Versions] |\n"
|
|
462
|
+
" | **Dependencies** | [Key libs] |\n\n"
|
|
463
|
+
" ## Phase 0 — Project Scaffolding\n"
|
|
464
|
+
" **Goal:** [Phase Goal]\n"
|
|
465
|
+
" ### 0.1 [Step Name]\n"
|
|
466
|
+
" [Code snippets, commands, implementation details]\n\n"
|
|
467
|
+
" ## Phase 1 — [Phase Name]\n"
|
|
468
|
+
" **Goal:** [Phase Goal]\n"
|
|
469
|
+
" ### 1.1 [Task Name]\n"
|
|
470
|
+
" [Code snippets, complete DB schemas, function signatures, exact logic. MUST NOT be a summary.]\n"
|
|
460
471
|
" **Checklist**:\n"
|
|
461
472
|
" - [ ] [Micro-step 1]\n"
|
|
462
473
|
" - [ ] [Micro-step 2]\n\n"
|
|
463
|
-
"
|
|
464
|
-
"
|
|
474
|
+
" ## CI/CD & Packaging\n"
|
|
475
|
+
" [Details on Github Actions, builds, installers]\n\n"
|
|
476
|
+
" ## Testing Strategy\n"
|
|
477
|
+
" [Unit, Integration, E2E plan]\n\n"
|
|
478
|
+
" ## Key Architecture Patterns\n"
|
|
479
|
+
" [Core rules to follow]\n\n"
|
|
480
|
+
" ## Development Setup\n"
|
|
481
|
+
" [Commands to start dev server/tests]\n\n"
|
|
482
|
+
" ## Verification\n"
|
|
483
|
+
" [Steps to verify each phase]\n\n"
|
|
484
|
+
" ## Dependency Graph\n"
|
|
485
|
+
" ```text\n"
|
|
486
|
+
" [ASCII Map of modules/components]\n"
|
|
465
487
|
" ```\n\n"
|
|
466
|
-
"
|
|
488
|
+
" ## Weekly Execution Schedule\n"
|
|
489
|
+
" ### Week X-Y: Phase Z\n"
|
|
490
|
+
" | Day | Tasks |\n"
|
|
491
|
+
" |-----|-------|\n"
|
|
492
|
+
" | **Day 1** | [Tasks] |\n"
|
|
493
|
+
" ```\n\n"
|
|
494
|
+
" - Under NO CIRCUMSTANCES should you write superficial steps like 'Initialize app' without providing the exact commands and code snippets in the Phase Implementation Details.\n"
|
|
467
495
|
" - Write the entire exhaustive plan into the file using your file-writing tools.\n"
|
|
468
496
|
"4. General Rules:\n"
|
|
469
497
|
" - STRICT FIDELITY: You MUST absolutely respect the languages, frameworks, endpoints, tables, and features mentioned in the user's project files or SDD.\n"
|
|
@@ -93,6 +93,9 @@ class TaskManager:
|
|
|
93
93
|
def get_task(self, task_id: str) -> Optional[Task]:
|
|
94
94
|
return self.tasks.get(task_id)
|
|
95
95
|
|
|
96
|
+
def get_all_tasks(self) -> List[Dict]:
|
|
97
|
+
return [t.to_dict() for t in self.tasks.values()]
|
|
98
|
+
|
|
96
99
|
def list_tasks(self) -> str:
|
|
97
100
|
if not self.tasks:
|
|
98
101
|
return "No tasks found."
|