FEAT add verbose logging
This commit is contained in:
parent
64fc0f6b99
commit
204f44cda0
|
|
@ -151,6 +151,9 @@ ra-aid -m "Your task or query here"
|
||||||
|
|
||||||
# Research-only mode (no implementation)
|
# Research-only mode (no implementation)
|
||||||
ra-aid -m "Explain the authentication flow" --research-only
|
ra-aid -m "Explain the authentication flow" --research-only
|
||||||
|
|
||||||
|
# Enable verbose logging for detailed execution information
|
||||||
|
ra-aid -m "Add new feature" --verbose
|
||||||
```
|
```
|
||||||
|
|
||||||
### Command Line Options
|
### Command Line Options
|
||||||
|
|
@ -164,6 +167,7 @@ ra-aid -m "Explain the authentication flow" --research-only
|
||||||
- `--expert-provider`: Specify the provider for the expert tool (defaults to OpenAI)
|
- `--expert-provider`: Specify the provider for the expert tool (defaults to OpenAI)
|
||||||
- `--expert-model`: Specify the model name for the expert tool (defaults to o1-preview for OpenAI)
|
- `--expert-model`: Specify the model name for the expert tool (defaults to o1-preview for OpenAI)
|
||||||
- `--chat`: Enable chat mode for interactive assistance
|
- `--chat`: Enable chat mode for interactive assistance
|
||||||
|
- `--verbose`: Enable detailed logging output for debugging and monitoring
|
||||||
|
|
||||||
### Example Tasks
|
### Example Tasks
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,13 @@ from ra_aid.prompts import (
|
||||||
WEB_RESEARCH_PROMPT_SECTION_CHAT
|
WEB_RESEARCH_PROMPT_SECTION_CHAT
|
||||||
)
|
)
|
||||||
from ra_aid.llm import initialize_llm
|
from ra_aid.llm import initialize_llm
|
||||||
|
from ra_aid.logging_config import setup_logging, get_logger
|
||||||
from ra_aid.tool_configs import (
|
from ra_aid.tool_configs import (
|
||||||
get_chat_tools
|
get_chat_tools
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
def parse_arguments():
|
def parse_arguments():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description='RA.Aid - AI Agent for executing programming and research tasks',
|
description='RA.Aid - AI Agent for executing programming and research tasks',
|
||||||
|
|
@ -85,6 +87,11 @@ Examples:
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='Enable chat mode with direct human interaction (implies --hil)'
|
help='Enable chat mode with direct human interaction (implies --hil)'
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--verbose',
|
||||||
|
action='store_true',
|
||||||
|
help='Enable verbose logging output'
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
@ -126,9 +133,13 @@ def is_stage_requested(stage: str) -> bool:
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Main entry point for the ra-aid command line tool."""
|
"""Main entry point for the ra-aid command line tool."""
|
||||||
|
args = parse_arguments()
|
||||||
|
setup_logging(args.verbose)
|
||||||
|
logger.debug("Starting RA.Aid with arguments: %s", args)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
args = parse_arguments()
|
|
||||||
expert_enabled, expert_missing, web_research_enabled, web_research_missing = validate_environment(args) # Will exit if main env vars missing
|
expert_enabled, expert_missing, web_research_enabled, web_research_missing = validate_environment(args) # Will exit if main env vars missing
|
||||||
|
logger.debug("Environment validation successful")
|
||||||
|
|
||||||
if expert_missing:
|
if expert_missing:
|
||||||
console.print(Panel(
|
console.print(Panel(
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,11 @@ import threading
|
||||||
import time
|
import time
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
class AgentInterrupt(Exception):
|
|
||||||
"""Exception raised when an agent's execution is interrupted.
|
|
||||||
|
|
||||||
This exception is used for internal agent interruption handling,
|
|
||||||
separate from KeyboardInterrupt which is reserved for top-level handling.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
from langgraph.prebuilt import create_react_agent
|
from langgraph.prebuilt import create_react_agent
|
||||||
from ra_aid.console.formatting import print_stage_header, print_error
|
from ra_aid.console.formatting import print_stage_header, print_error
|
||||||
from ra_aid.console.output import print_agent_output
|
from ra_aid.console.output import print_agent_output
|
||||||
|
from ra_aid.logging_config import get_logger
|
||||||
|
from ra_aid.exceptions import AgentInterrupt
|
||||||
from ra_aid.tool_configs import (
|
from ra_aid.tool_configs import (
|
||||||
get_implementation_tools,
|
get_implementation_tools,
|
||||||
get_research_tools,
|
get_research_tools,
|
||||||
|
|
@ -69,6 +63,8 @@ from ra_aid.prompts import (
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
def run_research_agent(
|
def run_research_agent(
|
||||||
base_task_or_query: str,
|
base_task_or_query: str,
|
||||||
model,
|
model,
|
||||||
|
|
@ -107,6 +103,11 @@ def run_research_agent(
|
||||||
research_only=True
|
research_only=True
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
thread_id = thread_id or str(uuid.uuid4())
|
||||||
|
logger.debug("Starting research agent with thread_id=%s", thread_id)
|
||||||
|
logger.debug("Research configuration: expert=%s, research_only=%s, hil=%s, web=%s",
|
||||||
|
expert_enabled, research_only, hil, web_research_enabled)
|
||||||
|
|
||||||
# Initialize memory if not provided
|
# Initialize memory if not provided
|
||||||
if memory is None:
|
if memory is None:
|
||||||
memory = MemorySaver()
|
memory = MemorySaver()
|
||||||
|
|
@ -156,12 +157,17 @@ def run_research_agent(
|
||||||
if config:
|
if config:
|
||||||
run_config.update(config)
|
run_config.update(config)
|
||||||
|
|
||||||
# Display console message if provided
|
try:
|
||||||
if console_message:
|
# Display console message if provided
|
||||||
console.print(Panel(Markdown(console_message), title="🔬 Looking into it..."))
|
if console_message:
|
||||||
|
console.print(Panel(Markdown(console_message), title="🔬 Looking into it..."))
|
||||||
|
|
||||||
# Run agent with retry logic
|
# Run agent with retry logic
|
||||||
return run_agent_with_retry(agent, prompt, run_config)
|
logger.debug("Research agent completed successfully")
|
||||||
|
return run_agent_with_retry(agent, prompt, run_config)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Research agent failed: %s", str(e), exc_info=True)
|
||||||
|
raise
|
||||||
|
|
||||||
def run_web_research_agent(
|
def run_web_research_agent(
|
||||||
query: str,
|
query: str,
|
||||||
|
|
@ -198,6 +204,11 @@ def run_web_research_agent(
|
||||||
expert_enabled=True
|
expert_enabled=True
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
thread_id = thread_id or str(uuid.uuid4())
|
||||||
|
logger.debug("Starting web research agent with thread_id=%s", thread_id)
|
||||||
|
logger.debug("Web research configuration: expert=%s, hil=%s, web=%s",
|
||||||
|
expert_enabled, hil, web_research_enabled)
|
||||||
|
|
||||||
# Initialize memory if not provided
|
# Initialize memory if not provided
|
||||||
if memory is None:
|
if memory is None:
|
||||||
memory = MemorySaver()
|
memory = MemorySaver()
|
||||||
|
|
@ -239,12 +250,17 @@ def run_web_research_agent(
|
||||||
if config:
|
if config:
|
||||||
run_config.update(config)
|
run_config.update(config)
|
||||||
|
|
||||||
# Display console message if provided
|
try:
|
||||||
if console_message:
|
# Display console message if provided
|
||||||
console.print(Panel(Markdown(console_message), title="🔍 Starting Web Research..."))
|
if console_message:
|
||||||
|
console.print(Panel(Markdown(console_message), title="🔍 Starting Web Research..."))
|
||||||
|
|
||||||
# Run agent with retry logic
|
# Run agent with retry logic
|
||||||
return run_agent_with_retry(agent, prompt, run_config)
|
logger.debug("Web research agent completed successfully")
|
||||||
|
return run_agent_with_retry(agent, prompt, run_config)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Web research agent failed: %s", str(e), exc_info=True)
|
||||||
|
raise
|
||||||
|
|
||||||
def run_planning_agent(
|
def run_planning_agent(
|
||||||
base_task: str,
|
base_task: str,
|
||||||
|
|
@ -270,6 +286,10 @@ def run_planning_agent(
|
||||||
Returns:
|
Returns:
|
||||||
Optional[str]: The completion message if planning completed successfully
|
Optional[str]: The completion message if planning completed successfully
|
||||||
"""
|
"""
|
||||||
|
thread_id = thread_id or str(uuid.uuid4())
|
||||||
|
logger.debug("Starting planning agent with thread_id=%s", thread_id)
|
||||||
|
logger.debug("Planning configuration: expert=%s, hil=%s", expert_enabled, hil)
|
||||||
|
|
||||||
# Initialize memory if not provided
|
# Initialize memory if not provided
|
||||||
if memory is None:
|
if memory is None:
|
||||||
memory = MemorySaver()
|
memory = MemorySaver()
|
||||||
|
|
@ -310,9 +330,13 @@ def run_planning_agent(
|
||||||
if config:
|
if config:
|
||||||
run_config.update(config)
|
run_config.update(config)
|
||||||
|
|
||||||
# Run agent with retry logic
|
try:
|
||||||
print_stage_header("Planning Stage")
|
print_stage_header("Planning Stage")
|
||||||
return run_agent_with_retry(agent, planning_prompt, run_config)
|
logger.debug("Planning agent completed successfully")
|
||||||
|
return run_agent_with_retry(agent, planning_prompt, run_config)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Planning agent failed: %s", str(e), exc_info=True)
|
||||||
|
raise
|
||||||
|
|
||||||
def run_task_implementation_agent(
|
def run_task_implementation_agent(
|
||||||
base_task: str,
|
base_task: str,
|
||||||
|
|
@ -345,6 +369,12 @@ def run_task_implementation_agent(
|
||||||
Returns:
|
Returns:
|
||||||
Optional[str]: The completion message if task completed successfully
|
Optional[str]: The completion message if task completed successfully
|
||||||
"""
|
"""
|
||||||
|
thread_id = thread_id or str(uuid.uuid4())
|
||||||
|
logger.debug("Starting implementation agent with thread_id=%s", thread_id)
|
||||||
|
logger.debug("Implementation configuration: expert=%s, web=%s", expert_enabled, web_research_enabled)
|
||||||
|
logger.debug("Task details: base_task=%s, current_task=%s", base_task, task)
|
||||||
|
logger.debug("Related files: %s", related_files)
|
||||||
|
|
||||||
# Initialize memory if not provided
|
# Initialize memory if not provided
|
||||||
if memory is None:
|
if memory is None:
|
||||||
memory = MemorySaver()
|
memory = MemorySaver()
|
||||||
|
|
@ -382,8 +412,12 @@ def run_task_implementation_agent(
|
||||||
if config:
|
if config:
|
||||||
run_config.update(config)
|
run_config.update(config)
|
||||||
|
|
||||||
# Run agent with retry logic
|
try:
|
||||||
return run_agent_with_retry(agent, prompt, run_config)
|
logger.debug("Implementation agent completed successfully")
|
||||||
|
return run_agent_with_retry(agent, prompt, run_config)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Implementation agent failed: %s", str(e), exc_info=True)
|
||||||
|
raise
|
||||||
|
|
||||||
_CONTEXT_STACK = []
|
_CONTEXT_STACK = []
|
||||||
_INTERRUPT_CONTEXT = None
|
_INTERRUPT_CONTEXT = None
|
||||||
|
|
@ -413,6 +447,8 @@ def check_interrupt():
|
||||||
raise AgentInterrupt("Interrupt requested")
|
raise AgentInterrupt("Interrupt requested")
|
||||||
|
|
||||||
def run_agent_with_retry(agent, prompt: str, config: dict) -> Optional[str]:
|
def run_agent_with_retry(agent, prompt: str, config: dict) -> Optional[str]:
|
||||||
|
"""Run an agent with retry logic for API errors."""
|
||||||
|
logger.debug("Running agent with prompt length: %d", len(prompt))
|
||||||
original_handler = None
|
original_handler = None
|
||||||
if threading.current_thread() is threading.main_thread():
|
if threading.current_thread() is threading.main_thread():
|
||||||
original_handler = signal.getsignal(signal.SIGINT)
|
original_handler = signal.getsignal(signal.SIGINT)
|
||||||
|
|
@ -423,6 +459,7 @@ def run_agent_with_retry(agent, prompt: str, config: dict) -> Optional[str]:
|
||||||
|
|
||||||
with InterruptibleSection():
|
with InterruptibleSection():
|
||||||
try:
|
try:
|
||||||
|
logger.debug("Attempt %d/%d", attempt + 1, max_retries)
|
||||||
# Track agent execution depth
|
# Track agent execution depth
|
||||||
current_depth = _global_memory.get('agent_depth', 0)
|
current_depth = _global_memory.get('agent_depth', 0)
|
||||||
_global_memory['agent_depth'] = current_depth + 1
|
_global_memory['agent_depth'] = current_depth + 1
|
||||||
|
|
@ -431,14 +468,18 @@ def run_agent_with_retry(agent, prompt: str, config: dict) -> Optional[str]:
|
||||||
check_interrupt()
|
check_interrupt()
|
||||||
try:
|
try:
|
||||||
for chunk in agent.stream({"messages": [HumanMessage(content=prompt)]}, config):
|
for chunk in agent.stream({"messages": [HumanMessage(content=prompt)]}, config):
|
||||||
|
logger.debug("Agent output: %s", chunk)
|
||||||
check_interrupt()
|
check_interrupt()
|
||||||
print_agent_output(chunk)
|
print_agent_output(chunk)
|
||||||
|
logger.debug("Agent run completed successfully")
|
||||||
return "Agent run completed successfully"
|
return "Agent run completed successfully"
|
||||||
except (KeyboardInterrupt, AgentInterrupt):
|
except (KeyboardInterrupt, AgentInterrupt):
|
||||||
raise
|
raise
|
||||||
except (InternalServerError, APITimeoutError, RateLimitError, APIError) as e:
|
except (InternalServerError, APITimeoutError, RateLimitError, APIError) as e:
|
||||||
if attempt == max_retries - 1:
|
if attempt == max_retries - 1:
|
||||||
|
logger.error("Max retries reached, failing: %s", str(e))
|
||||||
raise RuntimeError(f"Max retries ({max_retries}) exceeded. Last error: {e}")
|
raise RuntimeError(f"Max retries ({max_retries}) exceeded. Last error: {e}")
|
||||||
|
logger.warning("API error (attempt %d/%d): %s", attempt + 1, max_retries, str(e))
|
||||||
delay = base_delay * (2 ** attempt)
|
delay = base_delay * (2 ** attempt)
|
||||||
print_error(f"Encountered {e.__class__.__name__}: {e}. Retrying in {delay}s... (Attempt {attempt+1}/{max_retries})")
|
print_error(f"Encountered {e.__class__.__name__}: {e}. Retrying in {delay}s... (Attempt {attempt+1}/{max_retries})")
|
||||||
start = time.monotonic()
|
start = time.monotonic()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
"""Custom exceptions for RA.Aid."""
|
||||||
|
|
||||||
|
class AgentInterrupt(Exception):
|
||||||
|
"""Exception raised when an agent's execution is interrupted.
|
||||||
|
|
||||||
|
This exception is used for internal agent interruption handling,
|
||||||
|
separate from KeyboardInterrupt which is reserved for top-level handling.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
def setup_logging(verbose: bool = False) -> None:
|
||||||
|
logger = logging.getLogger("ra_aid")
|
||||||
|
logger.setLevel(logging.DEBUG if verbose else logging.INFO)
|
||||||
|
|
||||||
|
if not logger.handlers:
|
||||||
|
handler = logging.StreamHandler(sys.stdout)
|
||||||
|
formatter = logging.Formatter(
|
||||||
|
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||||
|
)
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
def get_logger(name: Optional[str] = None) -> logging.Logger:
|
||||||
|
return logging.getLogger(f"ra_aid.{name}" if name else "ra_aid")
|
||||||
|
|
@ -4,7 +4,7 @@ from langchain_core.tools import tool
|
||||||
from typing import Dict, Any, Union, List
|
from typing import Dict, Any, Union, List
|
||||||
from typing_extensions import TypeAlias
|
from typing_extensions import TypeAlias
|
||||||
from ..agent_utils import AgentInterrupt
|
from ..agent_utils import AgentInterrupt
|
||||||
|
from ra_aid.exceptions import AgentInterrupt
|
||||||
ResearchResult = Dict[str, Union[str, bool, Dict[int, Any], List[Any], None]]
|
ResearchResult = Dict[str, Union[str, bool, Dict[int, Any], List[Any], None]]
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from ra_aid.tools.memory import _global_memory
|
from ra_aid.tools.memory import _global_memory
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue