(no commit message)

This commit is contained in:
2026-01-21 16:50:23 -08:00
parent 519fb491d4
commit 24f352e8c5
4 changed files with 47 additions and 22 deletions

View File

@@ -4,7 +4,7 @@ Minimal Claude Code alternative. Single Python file, zero dependencies, ~250 lin
Built using Claude Code, then used to build itself.
![screenshot](https://d1pz4mbco29rws.cloudfront.net/public/nanocode.png)
![screenshot](screenshot.png)
## Features

View File

@@ -3,5 +3,5 @@
"max_iters": 15,
"lm": "openai/gpt-5.2-codex",
"api_base": "https://openrouter.ai/api/v1",
"max_tokens": 8192
"max_tokens": 16000
}

View File

@@ -25,6 +25,7 @@ MAGENTA = "\033[35m"
# --- Display utilities ---
def separator():
"""Return a horizontal separator line that fits the terminal width."""
return f"{DIM}{'' * min(os.get_terminal_size().columns, 80)}{RESET}"
@@ -37,6 +38,7 @@ def render_markdown(text):
# --- File operations ---
def read_file(path: str, offset: int = 0, limit: int = None) -> str:
"""Read file contents with line numbers.
@@ -138,6 +140,7 @@ def grep_files(pattern: str, path: str = ".") -> str:
# --- Shell operations ---
def run_bash(cmd: str) -> str:
"""Run a shell command and return output.
@@ -148,9 +151,7 @@ def run_bash(cmd: str) -> str:
Command output (stdout and stderr combined)
"""
proc = subprocess.Popen(
cmd, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
text=True
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
)
output_lines = []
try:
@@ -196,14 +197,20 @@ def select_model():
while True:
try:
choice = input(f"\n{BOLD}{BLUE}{RESET} Enter choice (1-8 or c): ").strip().lower()
choice = (
input(f"\n{BOLD}{BLUE}{RESET} Enter choice (1-8 or c): ")
.strip()
.lower()
)
if choice in AVAILABLE_MODELS:
name, model_id = AVAILABLE_MODELS[choice]
print(f"{GREEN}⏺ Selected: {name}{RESET}")
return model_id
elif choice == "c":
custom_model = input(f"{BOLD}{BLUE}{RESET} Enter model ID (e.g., openai/gpt-4): ").strip()
custom_model = input(
f"{BOLD}{BLUE}{RESET} Enter model ID (e.g., openai/gpt-4): "
).strip()
if custom_model:
print(f"{GREEN}⏺ Selected custom model: {custom_model}{RESET}")
return custom_model
@@ -218,12 +225,18 @@ def select_model():
# --- DSPy Signature ---
class CodingAssistant(dspy.Signature):
"""You are a concise coding assistant. Help the user with their coding task by using the available tools to read, write, edit files, search the codebase, and run commands."""
task: str = dspy.InputField(desc="The user's coding task or question")
answer: str = dspy.OutputField(desc="Your response to the user after completing the task")
affected_files: list[str] = dspy.OutputField(desc="List of files that were written or modified during the task")
answer: str = dspy.OutputField(
desc="Your response to the user after completing the task"
)
affected_files: list[str] = dspy.OutputField(
desc="List of files that were written or modified during the task"
)
# ReAct agent with tools
@@ -235,7 +248,7 @@ class ToolLoggingCallback(BaseCallback):
def on_tool_start(self, call_id, instance, inputs):
"""Log when a tool starts executing."""
tool_name = instance.name if hasattr(instance, 'name') else str(instance)
tool_name = instance.name if hasattr(instance, "name") else str(instance)
# Format args nicely
args_str = ", ".join(f"{k}={repr(v)[:50]}" for k, v in inputs.items())
print(f" {MAGENTA}{tool_name}({args_str}){RESET}", flush=True)
@@ -248,10 +261,12 @@ class ToolLoggingCallback(BaseCallback):
def on_module_end(self, call_id, outputs, exception):
"""Log when the finish tool is called (ReAct completion)."""
# Check if this is a ReAct prediction with tool_calls
if outputs and 'tool_calls' in outputs:
for call in outputs['tool_calls']:
args_str = ", ".join(f"{k}={repr(v)[:50]}" for k, v in call.args.items())
if call.name == 'finish':
if outputs and "tool_calls" in outputs:
for call in outputs["tool_calls"]:
args_str = ", ".join(
f"{k}={repr(v)[:50]}" for k, v in call.args.items()
)
if call.name == "finish":
print(f" {GREEN}⏺ finish{RESET}", flush=True)
else:
print(f" {MAGENTA}{call.name}({args_str}){RESET}", flush=True)
@@ -261,7 +276,8 @@ class AgentConfig(PrecompiledConfig):
max_iters: int = 15
lm: str = "openrouter/anthropic/claude-3.5-sonnet" # Default fallback
api_base: str = "https://openrouter.ai/api/v1"
max_tokens: int = 8192
max_tokens: int = 16000
class AgentProgram(PrecompiledProgram):
config: AgentConfig
@@ -273,8 +289,14 @@ class AgentProgram(PrecompiledProgram):
# Configure logging callback globally
dspy.settings.configure(callbacks=[ToolLoggingCallback()])
agent = dspy.ReAct(CodingAssistant, tools=tools, max_iters=self.config.max_iters)
lm = dspy.LM(self.config.lm, api_base=self.config.api_base, max_tokens=self.config.max_tokens)
agent = dspy.ReAct(
CodingAssistant, tools=tools, max_iters=self.config.max_iters
)
lm = dspy.LM(
self.config.lm,
api_base=self.config.api_base,
max_tokens=self.config.max_tokens,
)
agent.set_lm(lm)
self.agent = agent
@@ -282,6 +304,7 @@ class AgentProgram(PrecompiledProgram):
assert task, "Task cannot be empty"
return self.agent(task=task)
# --- Main ---
@@ -299,7 +322,9 @@ def main():
config.lm = model
agent = AgentProgram(config)
print(f"{BOLD}nanocode-dspy{RESET} | {DIM}{agent.config.lm} | {os.getcwd()}{RESET}\n")
print(
f"{BOLD}nanocode-dspy{RESET} | {DIM}{agent.config.lm} | {os.getcwd()}{RESET}\n"
)
# Conversation history for context
history = []
@@ -345,6 +370,7 @@ def main():
break
except Exception as err:
import traceback
traceback.print_exc()
print(f"{RED}⏺ Error: {err}{RESET}")
@@ -352,5 +378,4 @@ def main():
if __name__ == "__main__":
agent = AgentProgram(AgentConfig(lm="openai/gpt-5.2-codex"))
agent.push_to_hub("farouk1/nanocode")
#main()
# main()

View File

@@ -37,7 +37,7 @@
"launch_kwargs": {},
"train_kwargs": {},
"temperature": null,
"max_tokens": 8192,
"max_tokens": 16000,
"api_base": "https://openrouter.ai/api/v1"
}
},
@@ -79,7 +79,7 @@
"launch_kwargs": {},
"train_kwargs": {},
"temperature": null,
"max_tokens": 8192,
"max_tokens": 16000,
"api_base": "https://openrouter.ai/api/v1"
}
},