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)
|
||||
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
|
||||
|
|
@ -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-model`: Specify the model name for the expert tool (defaults to o1-preview for OpenAI)
|
||||
- `--chat`: Enable chat mode for interactive assistance
|
||||
- `--verbose`: Enable detailed logging output for debugging and monitoring
|
||||
|
||||
### Example Tasks
|
||||
|
||||
|
|
|
|||
|
|
@ -21,11 +21,13 @@ from ra_aid.prompts import (
|
|||
WEB_RESEARCH_PROMPT_SECTION_CHAT
|
||||
)
|
||||
from ra_aid.llm import initialize_llm
|
||||
|
||||
from ra_aid.logging_config import setup_logging, get_logger
|
||||
from ra_aid.tool_configs import (
|
||||
get_chat_tools
|
||||
)
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='RA.Aid - AI Agent for executing programming and research tasks',
|
||||
|
|
@ -85,6 +87,11 @@ Examples:
|
|||
action='store_true',
|
||||
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()
|
||||
|
||||
|
|
@ -126,9 +133,13 @@ def is_stage_requested(stage: str) -> bool:
|
|||
|
||||
def main():
|
||||
"""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:
|
||||
args = parse_arguments()
|
||||
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:
|
||||
console.print(Panel(
|
||||
|
|
|
|||
|
|
@ -10,17 +10,11 @@ import threading
|
|||
import time
|
||||
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 ra_aid.console.formatting import print_stage_header, print_error
|
||||
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 (
|
||||
get_implementation_tools,
|
||||
get_research_tools,
|
||||
|
|
@ -69,6 +63,8 @@ from ra_aid.prompts import (
|
|||
|
||||
console = Console()
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
def run_research_agent(
|
||||
base_task_or_query: str,
|
||||
model,
|
||||
|
|
@ -107,6 +103,11 @@ def run_research_agent(
|
|||
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
|
||||
if memory is None:
|
||||
memory = MemorySaver()
|
||||
|
|
@ -156,12 +157,17 @@ def run_research_agent(
|
|||
if config:
|
||||
run_config.update(config)
|
||||
|
||||
# Display console message if provided
|
||||
if console_message:
|
||||
console.print(Panel(Markdown(console_message), title="🔬 Looking into it..."))
|
||||
try:
|
||||
# Display console message if provided
|
||||
if console_message:
|
||||
console.print(Panel(Markdown(console_message), title="🔬 Looking into it..."))
|
||||
|
||||
# Run agent with retry logic
|
||||
return run_agent_with_retry(agent, prompt, run_config)
|
||||
# Run agent with retry logic
|
||||
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(
|
||||
query: str,
|
||||
|
|
@ -198,6 +204,11 @@ def run_web_research_agent(
|
|||
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
|
||||
if memory is None:
|
||||
memory = MemorySaver()
|
||||
|
|
@ -239,12 +250,17 @@ def run_web_research_agent(
|
|||
if config:
|
||||
run_config.update(config)
|
||||
|
||||
# Display console message if provided
|
||||
if console_message:
|
||||
console.print(Panel(Markdown(console_message), title="🔍 Starting Web Research..."))
|
||||
try:
|
||||
# Display console message if provided
|
||||
if console_message:
|
||||
console.print(Panel(Markdown(console_message), title="🔍 Starting Web Research..."))
|
||||
|
||||
# Run agent with retry logic
|
||||
return run_agent_with_retry(agent, prompt, run_config)
|
||||
# Run agent with retry logic
|
||||
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(
|
||||
base_task: str,
|
||||
|
|
@ -270,6 +286,10 @@ def run_planning_agent(
|
|||
Returns:
|
||||
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
|
||||
if memory is None:
|
||||
memory = MemorySaver()
|
||||
|
|
@ -310,9 +330,13 @@ def run_planning_agent(
|
|||
if config:
|
||||
run_config.update(config)
|
||||
|
||||
# Run agent with retry logic
|
||||
print_stage_header("Planning Stage")
|
||||
return run_agent_with_retry(agent, planning_prompt, run_config)
|
||||
try:
|
||||
print_stage_header("Planning Stage")
|
||||
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(
|
||||
base_task: str,
|
||||
|
|
@ -345,6 +369,12 @@ def run_task_implementation_agent(
|
|||
Returns:
|
||||
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
|
||||
if memory is None:
|
||||
memory = MemorySaver()
|
||||
|
|
@ -382,8 +412,12 @@ def run_task_implementation_agent(
|
|||
if config:
|
||||
run_config.update(config)
|
||||
|
||||
# Run agent with retry logic
|
||||
return run_agent_with_retry(agent, prompt, run_config)
|
||||
try:
|
||||
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 = []
|
||||
_INTERRUPT_CONTEXT = None
|
||||
|
|
@ -413,6 +447,8 @@ def check_interrupt():
|
|||
raise AgentInterrupt("Interrupt requested")
|
||||
|
||||
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
|
||||
if threading.current_thread() is threading.main_thread():
|
||||
original_handler = signal.getsignal(signal.SIGINT)
|
||||
|
|
@ -423,6 +459,7 @@ def run_agent_with_retry(agent, prompt: str, config: dict) -> Optional[str]:
|
|||
|
||||
with InterruptibleSection():
|
||||
try:
|
||||
logger.debug("Attempt %d/%d", attempt + 1, max_retries)
|
||||
# Track agent execution depth
|
||||
current_depth = _global_memory.get('agent_depth', 0)
|
||||
_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()
|
||||
try:
|
||||
for chunk in agent.stream({"messages": [HumanMessage(content=prompt)]}, config):
|
||||
logger.debug("Agent output: %s", chunk)
|
||||
check_interrupt()
|
||||
print_agent_output(chunk)
|
||||
logger.debug("Agent run completed successfully")
|
||||
return "Agent run completed successfully"
|
||||
except (KeyboardInterrupt, AgentInterrupt):
|
||||
raise
|
||||
except (InternalServerError, APITimeoutError, RateLimitError, APIError) as e:
|
||||
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}")
|
||||
logger.warning("API error (attempt %d/%d): %s", attempt + 1, max_retries, str(e))
|
||||
delay = base_delay * (2 ** attempt)
|
||||
print_error(f"Encountered {e.__class__.__name__}: {e}. Retrying in {delay}s... (Attempt {attempt+1}/{max_retries})")
|
||||
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_extensions import TypeAlias
|
||||
from ..agent_utils import AgentInterrupt
|
||||
|
||||
from ra_aid.exceptions import AgentInterrupt
|
||||
ResearchResult = Dict[str, Union[str, bool, Dict[int, Any], List[Any], None]]
|
||||
from rich.console import Console
|
||||
from ra_aid.tools.memory import _global_memory
|
||||
|
|
|
|||
Loading…
Reference in New Issue