Switch to RLM instead of ReAct
This commit is contained in:
83
nanocode.py
83
nanocode.py
@@ -1,6 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
"""nanocode-dspy - minimal claude code alternative using DSPy ReAct"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import glob as globlib
|
||||
@@ -9,6 +6,9 @@ from modaic import PrecompiledProgram, PrecompiledConfig
|
||||
import dspy
|
||||
from dspy.utils.callback import BaseCallback
|
||||
|
||||
# --- Modaic ---
|
||||
|
||||
MODAIC_REPO_PATH = "farouk1/nanocode"
|
||||
|
||||
# --- ANSI colors ---
|
||||
|
||||
@@ -22,7 +22,6 @@ YELLOW = "\033[33m"
|
||||
RED = "\033[31m"
|
||||
MAGENTA = "\033[35m"
|
||||
|
||||
|
||||
# --- Display utilities ---
|
||||
|
||||
|
||||
@@ -172,14 +171,14 @@ def run_bash(cmd: str) -> str:
|
||||
# --- Model selection ---
|
||||
|
||||
AVAILABLE_MODELS = {
|
||||
"1": ("Claude 3.5 Sonnet", "anthropic/claude-3.5-sonnet"),
|
||||
"2": ("Claude 3.5 Haiku", "anthropic/claude-3.5-haiku"),
|
||||
"3": ("GPT-4o", "openai/gpt-4o"),
|
||||
"4": ("GPT-4o mini", "openai/gpt-4o-mini"),
|
||||
"5": ("Gemini Pro 1.5", "google/gemini-pro-1.5"),
|
||||
"6": ("Llama 3.1 405B", "meta-llama/llama-3.1-405b-instruct"),
|
||||
"7": ("DeepSeek V3", "deepseek/deepseek-chat"),
|
||||
"8": ("Qwen 2.5 72B", "qwen/qwen-2.5-72b-instruct"),
|
||||
"1": ("GPT-5.2 Codex", "openai/gpt-5.2-codex"),
|
||||
"2": ("GPT-5.2", "openai/gpt-5.2"),
|
||||
"3": ("Claude Opus 4.5", "anthropic/claude-opus-4.5"),
|
||||
"4": ("Claude Opus 4", "anthropic/claude-opus-4"),
|
||||
"5": ("Qwen 3 Coder", "qwen/qwen3-coder"),
|
||||
"6": ("Gemini 3 Flash Preview", "google/gemini-3-flash-preview"),
|
||||
"7": ("Kimi K2 0905", "moonshotai/kimi-k2-0905"),
|
||||
"8": ("Minimax M2.1", "minimax/minimax-m2.1"),
|
||||
}
|
||||
|
||||
|
||||
@@ -223,9 +222,6 @@ def select_model():
|
||||
exit(1)
|
||||
|
||||
|
||||
# --- 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."""
|
||||
|
||||
@@ -238,9 +234,14 @@ class CodingAssistant(dspy.Signature):
|
||||
)
|
||||
|
||||
|
||||
# ReAct agent with tools
|
||||
|
||||
tools = [read_file, write_file, edit_file, glob_files, grep_files, run_bash]
|
||||
tools = {
|
||||
"readfile": read_file,
|
||||
"writefile": write_file,
|
||||
"editfile": edit_file,
|
||||
"globfiles": glob_files,
|
||||
"grepfiles": grep_files,
|
||||
"runbash": run_bash,
|
||||
}
|
||||
|
||||
|
||||
class ToolLoggingCallback(BaseCallback):
|
||||
@@ -272,31 +273,44 @@ class ToolLoggingCallback(BaseCallback):
|
||||
print(f" {MAGENTA}⏺ {call.name}({args_str}){RESET}", flush=True)
|
||||
|
||||
|
||||
class AgentConfig(PrecompiledConfig):
|
||||
max_iters: int = 15
|
||||
class RLMCodingConfig(PrecompiledConfig):
|
||||
max_iters: int = 20
|
||||
lm: str = "openrouter/anthropic/claude-3.5-sonnet" # Default fallback
|
||||
sub_lm: str = "openrouter/openai/gpt-4.1" # Default fallback
|
||||
api_base: str = "https://openrouter.ai/api/v1"
|
||||
max_tokens: int = 16000
|
||||
max_output_chars: int = 100000
|
||||
verbose: bool = False
|
||||
|
||||
|
||||
class AgentProgram(PrecompiledProgram):
|
||||
config: AgentConfig
|
||||
class RLMCodingProgram(PrecompiledProgram):
|
||||
config: RLMCodingConfig
|
||||
|
||||
def __init__(self, config: AgentConfig, **kwargs):
|
||||
def __init__(self, config: RLMCodingConfig, **kwargs):
|
||||
self.config = config
|
||||
super().__init__(config, **kwargs)
|
||||
|
||||
# Configure logging callback globally
|
||||
# tool logging for introspections on multi-turn conversations
|
||||
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,
|
||||
)
|
||||
sub_lm = dspy.LM(
|
||||
self.config.sub_lm,
|
||||
api_base=self.config.api_base,
|
||||
max_tokens=self.config.max_tokens,
|
||||
)
|
||||
agent = dspy.RLM(
|
||||
CodingAssistant,
|
||||
sub_lm=sub_lm,
|
||||
tools=tools,
|
||||
max_output_chars=self.config.max_output_chars,
|
||||
max_iterations=self.config.max_iters,
|
||||
verbose=self.config.verbose,
|
||||
)
|
||||
|
||||
agent.set_lm(lm)
|
||||
self.agent = agent
|
||||
|
||||
@@ -304,12 +318,7 @@ class AgentProgram(PrecompiledProgram):
|
||||
assert task, "Task cannot be empty"
|
||||
return self.agent(task=task)
|
||||
|
||||
|
||||
# --- Main ---
|
||||
|
||||
|
||||
def main():
|
||||
"""Create AgentConfig with selected model."""
|
||||
model = os.getenv("MODEL")
|
||||
if model is None:
|
||||
model = select_model()
|
||||
@@ -318,10 +327,10 @@ def main():
|
||||
if not model.startswith("openrouter/"):
|
||||
model = f"openrouter/{model}"
|
||||
|
||||
config = AgentConfig()
|
||||
config = RLMCodingConfig()
|
||||
config.lm = model
|
||||
|
||||
agent = AgentProgram(config)
|
||||
agent = RLMCodingProgram(config)
|
||||
print(
|
||||
f"{BOLD}nanocode-dspy{RESET} | {DIM}{agent.config.lm} | {os.getcwd()}{RESET}\n"
|
||||
)
|
||||
@@ -376,6 +385,6 @@ def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
agent = AgentProgram(AgentConfig(lm="openai/gpt-5.2-codex"))
|
||||
agent.push_to_hub("farouk1/nanocode")
|
||||
agent = RLMCodingProgram(RLMCodingConfig(lm="openai/gpt-5.2-codex"))
|
||||
agent.push_to_hub(MODAIC_REPO_PATH, commit_message="Switch to RLM instead of ReAct", tag="v0.0.1")
|
||||
#main()
|
||||
|
||||
Reference in New Issue
Block a user