Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7016105521 | |||
| 2e4a79e925 | |||
| 14325cc16e | |||
| d9acd94155 | |||
| 85d5330fc8 | |||
| 9f27228565 | |||
| c27cdf870b | |||
| f9b1b0964e | |||
| fb5aa0070f | |||
| 35616d3e3e | |||
| 64e375e960 | |||
| 3087006561 | |||
| 3fa9f925ff | |||
| 0e27e83b57 | |||
| 33f34e9615 | |||
| 3257f4dc01 | |||
| e633f96338 | |||
| 2149e14573 | |||
| b8400242e4 | |||
| a234b48cda | |||
| 2e671bd27f | |||
| 2cd7286320 | |||
| fa1a5847cf | |||
| 10163277ca | |||
| 1a005b6584 | |||
| a4ae97ef81 | |||
| 378a657595 | |||
| 7f0aba9241 | |||
| e69c82dea9 | |||
| 70597dc453 | |||
| af90aeddf9 | |||
| 175979fb15 | |||
| 367fad475b | |||
| c086336a0f | |||
| 2d252e3221 | |||
| fdb81ee671 | |||
| 22b7e87aaf |
@@ -7,5 +7,6 @@
|
|||||||
"max_tokens": 50000,
|
"max_tokens": 50000,
|
||||||
"max_output_chars": 100000,
|
"max_output_chars": 100000,
|
||||||
"verbose": true,
|
"verbose": true,
|
||||||
"track_usage": true
|
"track_usage": true,
|
||||||
|
"track_trace": false
|
||||||
}
|
}
|
||||||
46
nanocode.py
46
nanocode.py
@@ -1,15 +1,12 @@
|
|||||||
import os
|
import os
|
||||||
from modaic import PrecompiledProgram, PrecompiledConfig
|
from modaic import PrecompiledProgram, PrecompiledConfig
|
||||||
import dspy
|
import dspy
|
||||||
|
import weave
|
||||||
import subprocess
|
import subprocess
|
||||||
from dspy.utils.callback import BaseCallback
|
from dspy.utils.callback import BaseCallback
|
||||||
|
|
||||||
# --- Modaic ---
|
|
||||||
|
|
||||||
MODAIC_REPO_PATH = "farouk1/nanocode"
|
MODAIC_REPO_PATH = "farouk1/nanocode"
|
||||||
|
|
||||||
# --- ANSI colors ---
|
|
||||||
|
|
||||||
RESET = "\033[0m"
|
RESET = "\033[0m"
|
||||||
BOLD = "\033[1m"
|
BOLD = "\033[1m"
|
||||||
DIM = "\033[2m"
|
DIM = "\033[2m"
|
||||||
@@ -38,7 +35,9 @@ def read_file(path: str, offset: int = 0, limit: int = None) -> str:
|
|||||||
if limit is None:
|
if limit is None:
|
||||||
limit = len(lines)
|
limit = len(lines)
|
||||||
selected = lines[offset : offset + limit]
|
selected = lines[offset : offset + limit]
|
||||||
content = "".join(f"{offset + idx + 1:4}| {line}" for idx, line in enumerate(selected))
|
content = "".join(
|
||||||
|
f"{offset + idx + 1:4}| {line}" for idx, line in enumerate(selected)
|
||||||
|
)
|
||||||
tokens = len(content) // 4 # ~4 chars per token estimate
|
tokens = len(content) // 4 # ~4 chars per token estimate
|
||||||
print(f"{MAGENTA}⏺ Reading file({path}) (~{tokens:,} tokens){RESET}")
|
print(f"{MAGENTA}⏺ Reading file({path}) (~{tokens:,} tokens){RESET}")
|
||||||
return content
|
return content
|
||||||
@@ -67,7 +66,9 @@ def write_file(path: str, content: str) -> str:
|
|||||||
|
|
||||||
lines = content.count("\n") + (1 if content and not content.endswith("\n") else 0)
|
lines = content.count("\n") + (1 if content and not content.endswith("\n") else 0)
|
||||||
tokens = len(content) // 4
|
tokens = len(content) // 4
|
||||||
print(f"{MAGENTA}⏺ {action} file({path}) ({lines} lines, ~{tokens:,} tokens){RESET}")
|
print(
|
||||||
|
f"{MAGENTA}⏺ {action} file({path}) ({lines} lines, ~{tokens:,} tokens){RESET}"
|
||||||
|
)
|
||||||
return f"ok: wrote {lines} lines ({tokens:,} tokens) to {path}"
|
return f"ok: wrote {lines} lines ({tokens:,} tokens) to {path}"
|
||||||
|
|
||||||
|
|
||||||
@@ -98,7 +99,7 @@ def edit_file(path: str, old: str, new: str, replace_all: bool = False) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def glob_files(pattern: str, path: str = ".") -> str:
|
def glob_files(pattern: str, path: str = ".") -> str:
|
||||||
"""[EXTERNAL FILESYSTEM] Find files on disk matching a glob pattern.
|
"""[EXTERNAL FILESYSTEM] Do not use for simple file listing, run bash instead. Find files on disk matching a glob pattern.
|
||||||
|
|
||||||
Respects .gitignore files automatically via ripgrep. Sorted by modification time.
|
Respects .gitignore files automatically via ripgrep. Sorted by modification time.
|
||||||
|
|
||||||
@@ -111,7 +112,7 @@ def glob_files(pattern: str, path: str = ".") -> str:
|
|||||||
"""
|
"""
|
||||||
print(f"{MAGENTA}⏺ Glob({pattern}): {path}{RESET}")
|
print(f"{MAGENTA}⏺ Glob({pattern}): {path}{RESET}")
|
||||||
|
|
||||||
cmd = ["rg", "--files", "-g", pattern, path]
|
cmd = ["rg", "--files", "--no-require-git", "-g", pattern, path]
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||||
files = result.stdout.strip().split("\n") if result.stdout.strip() else []
|
files = result.stdout.strip().split("\n") if result.stdout.strip() else []
|
||||||
@@ -127,7 +128,9 @@ def glob_files(pattern: str, path: str = ".") -> str:
|
|||||||
return "error: search timed out after 30s"
|
return "error: search timed out after 30s"
|
||||||
|
|
||||||
|
|
||||||
def grep_files(pattern: str, path: str = ".", glob: str = None, max_results: int = 50) -> str:
|
def grep_files(
|
||||||
|
pattern: str, path: str = ".", glob: str = None, max_results: int = 50
|
||||||
|
) -> str:
|
||||||
"""[EXTERNAL FILESYSTEM] Search files on disk for a regex pattern using ripgrep.
|
"""[EXTERNAL FILESYSTEM] Search files on disk for a regex pattern using ripgrep.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -235,6 +238,7 @@ class RLMCodingConfig(PrecompiledConfig):
|
|||||||
max_output_chars: int = 100000
|
max_output_chars: int = 100000
|
||||||
verbose: bool = True
|
verbose: bool = True
|
||||||
track_usage: bool = True
|
track_usage: bool = True
|
||||||
|
track_trace: bool = False
|
||||||
|
|
||||||
|
|
||||||
class RLMCodingProgram(PrecompiledProgram):
|
class RLMCodingProgram(PrecompiledProgram):
|
||||||
@@ -256,6 +260,19 @@ class RLMCodingProgram(PrecompiledProgram):
|
|||||||
def __init__(self, config: RLMCodingConfig, **kwargs):
|
def __init__(self, config: RLMCodingConfig, **kwargs):
|
||||||
super().__init__(config, **kwargs)
|
super().__init__(config, **kwargs)
|
||||||
|
|
||||||
|
if config.track_trace:
|
||||||
|
project = kwargs.get("project", os.getenv("WANDB_PROJECT"))
|
||||||
|
if project is None:
|
||||||
|
raise ValueError("project is required when track_trace is True")
|
||||||
|
|
||||||
|
wandb_key = kwargs.get("wandb_key", os.getenv("WANDB_API_KEY"))
|
||||||
|
if wandb_key is None:
|
||||||
|
raise ValueError("wandb_key is required when track_trace is True")
|
||||||
|
|
||||||
|
os.environ["WANDB_PROJECT"] = project
|
||||||
|
os.environ["WANDB_API_KEY"] = wandb_key
|
||||||
|
weave.init(project_name=project)
|
||||||
|
|
||||||
self.config = config
|
self.config = config
|
||||||
self.tools = {
|
self.tools = {
|
||||||
"read_file": read_file,
|
"read_file": read_file,
|
||||||
@@ -362,7 +379,7 @@ class RLMCodingProgram(PrecompiledProgram):
|
|||||||
|
|
||||||
def reload_repl(
|
def reload_repl(
|
||||||
self,
|
self,
|
||||||
): # we need to create a new instance for tool mutations to be passed back into the REPL
|
): # We need to create a new instance for tool mutations to be passed back into the REPL
|
||||||
"""Reload the REPL with the current tools."""
|
"""Reload the REPL with the current tools."""
|
||||||
|
|
||||||
new_instance = dspy.RLM(
|
new_instance = dspy.RLM(
|
||||||
@@ -406,17 +423,18 @@ class RLMCodingProgram(PrecompiledProgram):
|
|||||||
fix this in a later patch for future devs.
|
fix this in a later patch for future devs.
|
||||||
"""
|
"""
|
||||||
super().load_state(state)
|
super().load_state(state)
|
||||||
self.reload_lms() # recreate LMs from config (not from saved state)
|
self.reload_lms() # Recreate LMs from config (not from saved state)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
agent = RLMCodingProgram(RLMCodingConfig())
|
agent = RLMCodingProgram(RLMCodingConfig())
|
||||||
#agent(task="explicity call llm_query(who is the ceo of apple?) to get the answer to 'who is the ceo of apple?'")
|
|
||||||
branches = ["dev", "main", "prod"]
|
# agent(task="what's 1 + 1?")
|
||||||
|
|
||||||
|
branches = ["dev"]
|
||||||
for branch in branches:
|
for branch in branches:
|
||||||
agent.push_to_hub(
|
agent.push_to_hub(
|
||||||
MODAIC_REPO_PATH,
|
MODAIC_REPO_PATH,
|
||||||
commit_message="Remove list_files tool",
|
commit_message="Remove list_files tool",
|
||||||
branch=branch,
|
branch=branch,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"train": [],
|
"train": [],
|
||||||
"demos": [],
|
"demos": [],
|
||||||
"signature": {
|
"signature": {
|
||||||
"instructions": "You are a concise coding assistant.\n\nCRITICAL - Two execution environments exist:\n\n1. INTERNAL REPL (sandbox): Standard Python code you write executes in an isolated sandbox. Variables persist between iterations. Use for data processing, string manipulation, logic, loops, etc.\n\n2. EXTERNAL TOOLS (real system): Functions like read_file(), write_file(), run_bash(), glob_files(), grep_files() execute OUTSIDE the sandbox on the real filesystem and host machine. These have real, persistent side effects.\n\nWhen you need to:\n- Process data, do math, manipulate strings, iterate \u2192 write Python code directly in the REPL\n- Read/write actual files on disk \u2192 call read_file(), write_file(), edit_file()\n- Run shell commands on the host \u2192 call run_bash()\n- Search the codebase \u2192 call glob_files(), grep_files()\n\nDo NOT confuse REPL variables with external files. Reading a file into a variable does not mean the variable updates if the file changes - you must call read_file() again.\n\nYou are tasked with producing the following outputs given the inputs `task`:\n- {answer}\n\nYou have access to a Python REPL environment. Write Python code and it will be executed. You will see the output, then write more code based on what you learned. This is an iterative process.\n\nAvailable:\n- Variables: `task` (your input data)\n- `llm_query(prompt)` - query a sub-LLM (~500K char capacity) for semantic analysis\n- `llm_query_batched(prompts)` - query multiple prompts concurrently (much faster for multiple queries)\n- `print()` - ALWAYS print to see results\n- `SUBMIT(answer)` - submit final output when done\n- Standard libraries: re, json, collections, math, etc.\n\nIMPORTANT: This is ITERATIVE. Each code block you write will execute, you'll see the output, then you decide what to do next. Do NOT try to solve everything in one step.\n\n1. EXPLORE FIRST - Look at your data before processing it. Print samples, check types/lengths, understand the structure.\n2. ITERATE - Write small code snippets, observe outputs, then decide next steps. State persists between iterations.\n3. VERIFY BEFORE SUBMITTING - If results seem wrong (zeros, empty, unexpected), reconsider your approach.\n4. USE llm_query FOR SEMANTICS - String matching finds WHERE things are; llm_query understands WHAT things mean.\n5. MINIMIZE RETYPING (INPUTS & OUTPUTS) - When values are long, precise, or error-prone (IDs, numbers, code, quotes), re-access them via variables and parse/compute in code instead of retyping. Use small, targeted prints to sanity-check, but avoid manual copying when variables can carry the exact value.\n6. SUBMIT ONLY AFTER SEEING OUTPUTS - SUBMIT ends the current run immediately. If you need to inspect printed output, run it in one step, review the result, then call SUBMIT in a later step.\n\nYou have max 50 sub-LLM calls. When done, call SUBMIT() with your output.\nAdditional tools available (use these instead of standard library equivalents):\n- `read_file(path: str, offset: int, limit: int) -> str` - [EXTERNAL FILESYSTEM] Read file contents from disk with line numbers.\n- `write_file(path: str, content: str) -> str` - [EXTERNAL FILESYSTEM] Write content to a file on disk (creates or overwrites).\n- `edit_file(path: str, old: str, new: str, replace_all: bool) -> str` - [EXTERNAL FILESYSTEM] Replace text in a file on disk.\n- `glob_files(pattern: str, path: str) -> str` - [EXTERNAL FILESYSTEM] Find files on disk matching a glob pattern.\n- `grep_files(pattern: str, path: str, glob: str, max_results: int) -> str` - [EXTERNAL FILESYSTEM] Search files on disk for a regex pattern using ripgrep.\n- `run_bash(cmd: str) -> str` - [EXTERNAL SYSTEM] Run a shell command on the host machine.",
|
"instructions": "You are a concise coding assistant.\n\nCRITICAL - Two execution environments exist:\n\n1. INTERNAL REPL (sandbox): Standard Python code you write executes in an isolated sandbox. Variables persist between iterations. Use for data processing, string manipulation, logic, loops, etc.\n\n2. EXTERNAL TOOLS (real system): Functions like read_file(), write_file(), run_bash(), glob_files(), grep_files() execute OUTSIDE the sandbox on the real filesystem and host machine. These have real, persistent side effects.\n\nWhen you need to:\n- Process data, do math, manipulate strings, iterate \u2192 write Python code directly in the REPL\n- Read/write actual files on disk \u2192 call read_file(), write_file(), edit_file()\n- Run shell commands on the host \u2192 call run_bash()\n- Search the codebase \u2192 call glob_files(), grep_files()\n\nDo NOT confuse REPL variables with external files. Reading a file into a variable does not mean the variable updates if the file changes - you must call read_file() again.\n\nYou are tasked with producing the following outputs given the inputs `task`:\n- {answer}\n\nYou have access to a Python REPL environment. Write Python code and it will be executed. You will see the output, then write more code based on what you learned. This is an iterative process.\n\nAvailable:\n- Variables: `task` (your input data)\n- `llm_query(prompt)` - query a sub-LLM (~500K char capacity) for semantic analysis\n- `llm_query_batched(prompts)` - query multiple prompts concurrently (much faster for multiple queries)\n- `print()` - ALWAYS print to see results\n- `SUBMIT(answer)` - submit final output when done\n- Standard libraries: re, json, collections, math, etc.\n\nIMPORTANT: This is ITERATIVE. Each code block you write will execute, you'll see the output, then you decide what to do next. Do NOT try to solve everything in one step.\n\n1. EXPLORE FIRST - Look at your data before processing it. Print samples, check types/lengths, understand the structure.\n2. ITERATE - Write small code snippets, observe outputs, then decide next steps. State persists between iterations.\n3. VERIFY BEFORE SUBMITTING - If results seem wrong (zeros, empty, unexpected), reconsider your approach.\n4. USE llm_query FOR SEMANTICS - String matching finds WHERE things are; llm_query understands WHAT things mean.\n5. MINIMIZE RETYPING (INPUTS & OUTPUTS) - When values are long, precise, or error-prone (IDs, numbers, code, quotes), re-access them via variables and parse/compute in code instead of retyping. Use small, targeted prints to sanity-check, but avoid manual copying when variables can carry the exact value.\n6. SUBMIT ONLY AFTER SEEING OUTPUTS - SUBMIT ends the current run immediately. If you need to inspect printed output, run it in one step, review the result, then call SUBMIT in a later step.\n\nYou have max 50 sub-LLM calls. When done, call SUBMIT() with your output.\nAdditional tools available (use these instead of standard library equivalents):\n- `read_file(path: str, offset: int, limit: int) -> str` - [EXTERNAL FILESYSTEM] Read file contents from disk with line numbers.\n- `write_file(path: str, content: str) -> str` - [EXTERNAL FILESYSTEM] Write content to a file on disk (creates or overwrites).\n- `edit_file(path: str, old: str, new: str, replace_all: bool) -> str` - [EXTERNAL FILESYSTEM] Replace text in a file on disk.\n- `glob_files(pattern: str, path: str) -> str` - [EXTERNAL FILESYSTEM] Do not use for simple file listing, run bash instead. Find files on disk matching a glob pattern.\n- `grep_files(pattern: str, path: str, glob: str, max_results: int) -> str` - [EXTERNAL FILESYSTEM] Search files on disk for a regex pattern using ripgrep.\n- `run_bash(cmd: str) -> str` - [EXTERNAL SYSTEM] Run a shell command on the host machine.",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"prefix": "Variables Info:",
|
"prefix": "Variables Info:",
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ version = "0.1.0"
|
|||||||
description = "Add your description here"
|
description = "Add your description here"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = ["dspy>=3.1.2", "fastmcp>=2.14.3", "mcp2py>=0.6.0", "modaic>=0.10.4", "weave>=0.52.25"]
|
dependencies = ["dspy>=3.1.2", "fastmcp>=2.14.3", "mcp2py>=0.6.0", "modaic>=0.10.4", "wandb>=0.24.1", "weave>=0.52.25"]
|
||||||
|
|||||||
Reference in New Issue
Block a user