Make sure file modification tools are not available when research only flag is used.
This commit is contained in:
parent
3be54fac2f
commit
f4c7c8f150
|
|
@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Adjust research prompt to make sure related files are related to the base task, not just the research subtask.
|
- Adjust research prompt to make sure related files are related to the base task, not just the research subtask.
|
||||||
- Track tasks by ID and allow them to be deleted.
|
- Track tasks by ID and allow them to be deleted.
|
||||||
- Make one_shot_completed tool available to research agent.
|
- Make one_shot_completed tool available to research agent.
|
||||||
|
- Make sure file modification tools are not available when research only flag is used.
|
||||||
|
|
||||||
## [0.6.0] - 2024-12-17
|
## [0.6.0] - 2024-12-17
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,17 +30,29 @@ import time
|
||||||
from anthropic import APIError, APITimeoutError, RateLimitError, InternalServerError
|
from anthropic import APIError, APITimeoutError, RateLimitError, InternalServerError
|
||||||
from ra_aid.llm import initialize_llm
|
from ra_aid.llm import initialize_llm
|
||||||
|
|
||||||
# Common tools used across multiple agents
|
# Read-only tools that don't modify system state
|
||||||
COMMON_TOOLS = [
|
READ_ONLY_TOOLS = [
|
||||||
emit_related_files,
|
emit_related_files,
|
||||||
emit_key_facts,
|
emit_key_facts,
|
||||||
delete_key_facts,
|
delete_key_facts,
|
||||||
emit_key_snippets,
|
emit_key_snippets,
|
||||||
delete_key_snippets,
|
delete_key_snippets,
|
||||||
read_file_tool,
|
read_file_tool,
|
||||||
write_file_tool,
|
|
||||||
fuzzy_find_project_files,
|
fuzzy_find_project_files,
|
||||||
ripgrep_search,
|
ripgrep_search
|
||||||
|
]
|
||||||
|
|
||||||
|
# Tools that can modify files or system state
|
||||||
|
MODIFICATION_TOOLS = [
|
||||||
|
write_file_tool,
|
||||||
|
file_str_replace,
|
||||||
|
run_shell_command,
|
||||||
|
run_programming_task
|
||||||
|
]
|
||||||
|
|
||||||
|
# Common tools used across multiple agents
|
||||||
|
COMMON_TOOLS = READ_ONLY_TOOLS + [
|
||||||
|
write_file_tool,
|
||||||
file_str_replace
|
file_str_replace
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -134,56 +146,55 @@ implementation_memory = MemorySaver()
|
||||||
|
|
||||||
def get_research_tools(research_only: bool = False, expert_enabled: bool = True) -> list:
|
def get_research_tools(research_only: bool = False, expert_enabled: bool = True) -> list:
|
||||||
"""Get the list of research tools based on mode and whether expert is enabled."""
|
"""Get the list of research tools based on mode and whether expert is enabled."""
|
||||||
tools = RESEARCH_TOOLS.copy() # Start with research-specific tools including list_directory_tree
|
# Start with read-only tools
|
||||||
|
tools = READ_ONLY_TOOLS.copy()
|
||||||
|
|
||||||
# Add common tools
|
# Add research tools except run_shell_command
|
||||||
tools.extend(COMMON_TOOLS.copy())
|
research_tools = [t for t in RESEARCH_TOOLS if t != run_shell_command]
|
||||||
|
tools.extend(research_tools)
|
||||||
|
|
||||||
|
# Add modification tools if not research_only
|
||||||
|
if not research_only:
|
||||||
|
tools.extend(MODIFICATION_TOOLS)
|
||||||
|
tools.append(request_complex_implementation)
|
||||||
|
|
||||||
|
# Add expert tools if enabled
|
||||||
if expert_enabled:
|
if expert_enabled:
|
||||||
tools.extend(EXPERT_TOOLS)
|
tools.extend(EXPERT_TOOLS)
|
||||||
|
|
||||||
if not research_only:
|
|
||||||
tools.append(request_complex_implementation)
|
|
||||||
|
|
||||||
return tools
|
return tools
|
||||||
|
|
||||||
def get_planning_tools(expert_enabled: bool = True) -> list:
|
def get_planning_tools(expert_enabled: bool = True) -> list:
|
||||||
tools = [
|
"""Get the list of planning tools based on whether expert is enabled."""
|
||||||
list_directory_tree,
|
# Start with common tools
|
||||||
|
tools = COMMON_TOOLS.copy()
|
||||||
|
|
||||||
|
# Add planning-specific tools
|
||||||
|
planning_tools = [
|
||||||
emit_plan,
|
emit_plan,
|
||||||
emit_task,
|
emit_task,
|
||||||
swap_task_order,
|
swap_task_order
|
||||||
emit_related_files,
|
|
||||||
emit_key_facts,
|
|
||||||
delete_key_facts,
|
|
||||||
emit_key_snippets,
|
|
||||||
delete_key_snippets,
|
|
||||||
read_file_tool,
|
|
||||||
fuzzy_find_project_files,
|
|
||||||
ripgrep_search
|
|
||||||
]
|
]
|
||||||
|
tools.extend(planning_tools)
|
||||||
|
|
||||||
|
# Add expert tools if enabled
|
||||||
if expert_enabled:
|
if expert_enabled:
|
||||||
tools.append(ask_expert)
|
tools.extend(EXPERT_TOOLS)
|
||||||
tools.append(emit_expert_context)
|
|
||||||
return tools
|
return tools
|
||||||
|
|
||||||
def get_implementation_tools(expert_enabled: bool = True) -> list:
|
def get_implementation_tools(expert_enabled: bool = True) -> list:
|
||||||
tools = [
|
"""Get the list of implementation tools based on whether expert is enabled."""
|
||||||
list_directory_tree,
|
# Start with common tools
|
||||||
run_shell_command,
|
tools = COMMON_TOOLS.copy()
|
||||||
run_programming_task,
|
|
||||||
emit_related_files,
|
# Add modification tools since it's not research-only
|
||||||
emit_key_facts,
|
tools.extend(MODIFICATION_TOOLS)
|
||||||
delete_key_facts,
|
|
||||||
emit_key_snippets,
|
# Add expert tools if enabled
|
||||||
delete_key_snippets,
|
|
||||||
read_file_tool,
|
|
||||||
fuzzy_find_project_files,
|
|
||||||
ripgrep_search
|
|
||||||
]
|
|
||||||
if expert_enabled:
|
if expert_enabled:
|
||||||
tools.append(ask_expert)
|
tools.extend(EXPERT_TOOLS)
|
||||||
tools.append(emit_expert_context)
|
|
||||||
return tools
|
return tools
|
||||||
|
|
||||||
def is_informational_query() -> bool:
|
def is_informational_query() -> bool:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
"""Configuration and environment validation utilities."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Tuple, List
|
||||||
|
|
||||||
|
from ra_aid import print_error
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ProviderConfig:
|
||||||
|
"""Configuration for a provider."""
|
||||||
|
key_name: str
|
||||||
|
base_required: bool = False
|
||||||
|
|
||||||
|
PROVIDER_CONFIGS = {
|
||||||
|
"anthropic": ProviderConfig("ANTHROPIC_API_KEY", base_required=True),
|
||||||
|
"openai": ProviderConfig("OPENAI_API_KEY", base_required=True),
|
||||||
|
"openrouter": ProviderConfig("OPENROUTER_API_KEY", base_required=True),
|
||||||
|
"openai-compatible": ProviderConfig("OPENAI_API_KEY", base_required=True),
|
||||||
|
}
|
||||||
|
|
||||||
|
def validate_environment(args) -> Tuple[bool, List[str]]:
|
||||||
|
"""Validate required environment variables and dependencies.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
args: The parsed command line arguments containing:
|
||||||
|
- provider: The main LLM provider
|
||||||
|
- expert_provider: The expert LLM provider
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple containing:
|
||||||
|
- bool: Whether expert mode is enabled
|
||||||
|
- List[str]: List of missing expert configuration items
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
SystemExit: If required base environment variables are missing
|
||||||
|
"""
|
||||||
|
missing = []
|
||||||
|
provider = args.provider
|
||||||
|
expert_provider = args.expert_provider
|
||||||
|
|
||||||
|
# Check API keys based on provider configs
|
||||||
|
if provider in PROVIDER_CONFIGS:
|
||||||
|
config = PROVIDER_CONFIGS[provider]
|
||||||
|
if config.base_required and not os.environ.get(config.key_name):
|
||||||
|
missing.append(f'{config.key_name} environment variable is not set')
|
||||||
|
|
||||||
|
# Special case for openai-compatible needing base URL
|
||||||
|
if provider == "openai-compatible" and not os.environ.get('OPENAI_API_BASE'):
|
||||||
|
missing.append('OPENAI_API_BASE environment variable is not set')
|
||||||
|
|
||||||
|
expert_missing = []
|
||||||
|
if expert_provider in PROVIDER_CONFIGS:
|
||||||
|
config = PROVIDER_CONFIGS[expert_provider]
|
||||||
|
expert_key = f'EXPERT_{config.key_name}'
|
||||||
|
expert_key_missing = not os.environ.get(expert_key)
|
||||||
|
|
||||||
|
# Try fallback to base key if providers match
|
||||||
|
fallback_available = expert_provider == provider and os.environ.get(config.key_name)
|
||||||
|
if expert_key_missing and fallback_available:
|
||||||
|
os.environ[expert_key] = os.environ[config.key_name]
|
||||||
|
expert_key_missing = False
|
||||||
|
|
||||||
|
if expert_key_missing:
|
||||||
|
expert_missing.append(f'{expert_key} environment variable is not set')
|
||||||
|
|
||||||
|
# Special case for openai-compatible expert needing base URL
|
||||||
|
if expert_provider == "openai-compatible":
|
||||||
|
expert_base = 'EXPERT_OPENAI_API_BASE'
|
||||||
|
base_missing = not os.environ.get(expert_base)
|
||||||
|
base_fallback = expert_provider == provider and os.environ.get('OPENAI_API_BASE')
|
||||||
|
|
||||||
|
if base_missing and base_fallback:
|
||||||
|
os.environ[expert_base] = os.environ['OPENAI_API_BASE']
|
||||||
|
base_missing = False
|
||||||
|
|
||||||
|
if base_missing:
|
||||||
|
expert_missing.append(f'{expert_base} environment variable is not set')
|
||||||
|
|
||||||
|
# If main keys missing, we must exit immediately
|
||||||
|
if missing:
|
||||||
|
print_error("Missing required dependencies:")
|
||||||
|
for item in missing:
|
||||||
|
print_error(f"- {item}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# If expert keys missing, we disable expert tools instead of exiting
|
||||||
|
expert_enabled = True
|
||||||
|
if expert_missing:
|
||||||
|
expert_enabled = False
|
||||||
|
|
||||||
|
return expert_enabled, expert_missing
|
||||||
Loading…
Reference in New Issue