diff --git a/README.md b/README.md index b3fa114..5119d51 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,22 @@ RA.Aid (ReAct Aid) is a powerful AI-driven command-line tool that integrates `aider` (https://aider.chat/) within a LangChain ReAct agent loop. This unique combination allows developers to leverage aider's code editing capabilities while benefiting from LangChain's agent-based task execution framework. The tool provides an intelligent assistant that can help with research, planning, and implementation of development tasks. +⚠️ **IMPORTANT: USE AT YOUR OWN RISK** ⚠️ +- This tool **can and will** automatically execute shell commands on your system +- No warranty is provided, either express or implied +- Always review the actions the agent proposes before allowing them to proceed + +## Key Features + +- **Multi-Step Task Planning**: The agent breaks down complex tasks into discrete, manageable steps and executes them sequentially. This systematic approach ensures thorough implementation and reduces errors. + +- **Automated Command Execution**: The agent can run shell commands automatically to accomplish tasks. While this makes it powerful, it also means you should carefully review its actions. + +- **Three-Stage Architecture**: + 1. **Research**: Analyzes codebases and gathers context + 2. **Planning**: Breaks down tasks into specific, actionable steps + 3. **Implementation**: Executes each planned step sequentially + What sets RA.Aid apart is its ability to handle complex programming tasks that extend beyond single-shot code edits. By combining research, strategic planning, and implementation into a cohesive workflow, RA.Aid can: - Break down and execute multi-step programming tasks @@ -62,70 +78,76 @@ What sets RA.Aid apart is its ability to handle complex programming tasks that e ## Installation -### Prerequisites +RA.Aid can be installed directly using pip: -- Python 3.8 or higher -- pip package manager - -### Steps - -1. Install from PyPI: ```bash pip install ra-aid ``` -Or install from source: +### Prerequisites + +Before using RA.Aid, you'll need to set up your API keys for the required AI services: + ```bash -git clone https://github.com/ai-christianson/ra-aid.git -cd ra-aid -pip install . +# Required: Set up your Anthropic API key +export ANTHROPIC_API_KEY=your_api_key_here + +# Optional: Set up OpenAI API key if using OpenAI features +export OPENAI_API_KEY=your_api_key_here ``` -2. Install additional dependencies: -```bash -pip install -r requirements.txt -``` - -3. (Optional) Install development dependencies: -```bash -pip install -r requirements-dev.txt -``` +You can get your API keys from: +- Anthropic API key: https://console.anthropic.com/ +- OpenAI API key: https://platform.openai.com/api-keys ## Usage -RA.Aid is used via the `ra-aid` command. The basic usage pattern is: +RA.Aid is designed to be simple yet powerful. Here's how to use it: ```bash -ra-aid [task] +# Basic usage +ra-aid -m "Your task or query here" + +# Research-only mode (no implementation) +ra-aid -m "Explain the authentication flow" --research-only ``` -### Examples +### Command Line Options -Research a topic: -```bash -ra-aid "Research best practices for Python package structure" -``` +- `-m, --message`: The task or query to be executed (required) +- `--research-only`: Only perform research without implementation -Plan a development task: -```bash -ra-aid "Plan the implementation of a new REST API endpoint" -``` +### Example Tasks -Generate code or documentation: -```bash -ra-aid "Create a README.md template for my project" -``` +1. Code Implementation: + ```bash + ra-aid -m "Add input validation to the user registration endpoint" + ``` -### Interactive Mode +2. Code Research: + ```bash + ra-aid -m "Explain how the authentication middleware works" --research-only + ``` -For an interactive session where you can enter multiple tasks: +3. Refactoring: + ```bash + ra-aid -m "Refactor the database connection code to use connection pooling" + ``` + +### Environment Variables + +RA.Aid uses the following environment variables: + +- `ANTHROPIC_API_KEY` (Required): Your Anthropic API key for accessing Claude +- `OPENAI_API_KEY` (Optional): Your OpenAI API key if using OpenAI features + +You can set these permanently in your shell's configuration file (e.g., `~/.bashrc` or `~/.zshrc`): ```bash -ra-aid +export ANTHROPIC_API_KEY=your_api_key_here +export OPENAI_API_KEY=your_api_key_here ``` -This will start an interactive prompt where you can input tasks sequentially. - ## Architecture RA.Aid implements a three-stage architecture for handling development and research tasks: diff --git a/ra_aid/__main__.py b/ra_aid/__main__.py index 6780872..19842e1 100644 --- a/ra_aid/__main__.py +++ b/ra_aid/__main__.py @@ -1,5 +1,8 @@ import sqlite3 import argparse +import os +import sys +import shutil from langchain_anthropic import ChatAnthropic from langchain_core.messages import HumanMessage from langgraph.checkpoint.memory import MemorySaver @@ -24,13 +27,24 @@ from ra_aid.prompts import ( def parse_arguments(): parser = argparse.ArgumentParser( - description='AI Agent for executing programming and research tasks', - formatter_class=argparse.RawDescriptionHelpFormatter + description='RA.Aid - AI Agent for executing programming and research tasks', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=''' +Examples: + ra-aid -m "Add error handling to the database module" + ra-aid -m "Explain the authentication flow" --research-only + ''' ) parser.add_argument( - 'task', + '-m', '--message', type=str, - help='The task to be executed by the agent' + required=True, + help='The task or query to be executed by the agent' + ) + parser.add_argument( + '--research-only', + action='store_true', + help='Only perform research without implementation' ) return parser.parse_args() @@ -59,7 +73,8 @@ def is_informational_query() -> bool: Returns: bool: True if query is informational (no implementation requested), False otherwise """ - return not is_stage_requested('implementation') + # Check both the research_only flag and implementation_requested state + return _global_memory.get('config', {}).get('research_only', False) or not is_stage_requested('implementation') def is_stage_requested(stage: str) -> bool: """Check if a stage has been requested to proceed. @@ -147,7 +162,7 @@ def summarize_research_findings(base_task: str, config: dict) -> None: while True: try: for chunk in summary_agent.stream( - {"messages": [HumanMessage(content=summary_prompt)]}, + {"messages": [HumanMessage(content=summary_prompt)]}, config ): print_agent_output(chunk) @@ -195,17 +210,53 @@ def run_research_subtasks(base_task: str, config: dict): print(f"Encountered Anthropic Internal Server Error: {e}. Retrying...") continue +def validate_environment(): + """Validate required environment variables and dependencies.""" + missing = [] + + # Check API keys + if not os.environ.get('ANTHROPIC_API_KEY'): + missing.append('ANTHROPIC_API_KEY environment variable is not set') + if not os.environ.get('OPENAI_API_KEY'): + missing.append('OPENAI_API_KEY environment variable is not set') + + # Check for aider binary + if not shutil.which('aider'): + missing.append('aider binary not found in PATH. Please install aider: pip install aider') + + if missing: + print("Error: Missing required dependencies:", file=sys.stderr) + for error in missing: + print(f"- {error}", file=sys.stderr) + sys.exit(1) + if __name__ == "__main__": + validate_environment() args = parse_arguments() - base_task = args.task - config = {"configurable": {"thread_id": "abc123"}, "recursion_limit": 100} + base_task = args.message + config = { + "configurable": { + "thread_id": "abc123" + }, + "recursion_limit": 100, + "research_only": args.research_only + } + + # Store config in global memory for access by is_informational_query + _global_memory['config'] = config # Run research stage print_stage_header("RESEARCH STAGE") + research_prompt = f"""User query: {base_task} + +{RESEARCH_PROMPT} + +Be very thorough in your research and emit lots of snippets, key facts. If you take more than a few steps, be eager to emit research subtasks.{'' if args.research_only else ' Only request implementation if the user explicitly asked for changes to be made.'}""" + while True: try: for chunk in research_agent.stream( - {"messages": [HumanMessage(content=f"User query: {base_task}\n\n{RESEARCH_PROMPT}\n\nBe very thorough in your research and emit lots of snippets, key facts. If you take more than a few steps, be eager to emit research subtasks. Only request implementation if the user explicitly asked for changes to be made.")]}, + {"messages": [HumanMessage(content=research_prompt)]}, config ): print_agent_output(chunk) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 5dcea46..0000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -langchain-anthropic -langgraph -rich>=13.0.0 -GitPython==3.1.41 -fuzzywuzzy==0.18.0 -python-Levenshtein==0.23.0 -pathspec>=0.11.0