Agents API Reference¶
Overview¶
The Agents API provides interfaces for interacting with different AI agents (Claude, Gemini, Q) and managing agent execution.
Agent Interface¶
Base Agent Class¶
class Agent:
"""
Abstract base class for AI agents.
All agent implementations must inherit from this class
and implement the required methods.
"""
def __init__(self, name: str, command: str):
"""
Initialize agent.
Args:
name (str): Agent identifier
command (str): Command to execute agent
"""
self.name = name
self.command = command
self.available = self.check_availability()
def check_availability(self) -> bool:
"""
Check if agent is available on system.
Returns:
bool: True if agent is available
Example:
agent = ClaudeAgent()
if agent.available:
agent.execute(prompt)
"""
return shutil.which(self.command) is not None
def execute(self, prompt_file: str) -> Tuple[bool, str]:
"""
Execute agent with prompt file.
Args:
prompt_file (str): Path to prompt file
Returns:
tuple: (success, output)
Raises:
AgentExecutionError: If execution fails
"""
raise NotImplementedError
def validate_prompt(self, prompt_file: str) -> bool:
"""
Validate prompt file before execution.
Args:
prompt_file (str): Path to prompt file
Returns:
bool: True if prompt is valid
"""
if not os.path.exists(prompt_file):
return False
with open(prompt_file) as f:
content = f.read()
return len(content) > 0 and len(content) < self.max_context
Agent Implementations¶
Claude Agent¶
class ClaudeAgent(Agent):
"""
Claude AI agent implementation.
Attributes:
max_context (int): Maximum context window (200K tokens)
timeout (int): Execution timeout in seconds
"""
def __init__(self):
super().__init__('claude', 'claude')
self.max_context = 800000 # ~200K tokens
self.timeout = 300
def execute(self, prompt_file: str) -> Tuple[bool, str]:
"""
Execute Claude with prompt.
Args:
prompt_file (str): Path to prompt file
Returns:
tuple: (success, output)
Example:
claude = ClaudeAgent()
success, output = claude.execute('PROMPT.md')
"""
if not self.available:
return False, "Claude not available"
try:
result = subprocess.run(
[self.command, prompt_file],
capture_output=True,
text=True,
timeout=self.timeout,
env=self.get_environment()
)
return result.returncode == 0, result.stdout
except subprocess.TimeoutExpired:
return False, "Claude execution timed out"
except Exception as e:
return False, f"Claude execution error: {str(e)}"
def get_environment(self) -> dict:
"""Get environment variables for Claude."""
env = os.environ.copy()
# Add Claude-specific environment variables
return env
Gemini Agent¶
class GeminiAgent(Agent):
"""
Gemini AI agent implementation.
Attributes:
max_context (int): Maximum context window (32K tokens)
timeout (int): Execution timeout in seconds
"""
def __init__(self):
super().__init__('gemini', 'gemini')
self.max_context = 130000 # ~32K tokens
self.timeout = 300
def execute(self, prompt_file: str) -> Tuple[bool, str]:
"""
Execute Gemini with prompt.
Args:
prompt_file (str): Path to prompt file
Returns:
tuple: (success, output)
Example:
gemini = GeminiAgent()
success, output = gemini.execute('PROMPT.md')
"""
if not self.available:
return False, "Gemini not available"
try:
# Gemini may need additional arguments
cmd = [self.command, '--no-web', prompt_file]
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=self.timeout
)
return result.returncode == 0, result.stdout
except subprocess.TimeoutExpired:
return False, "Gemini execution timed out"
except Exception as e:
return False, f"Gemini execution error: {str(e)}"
Q Agent¶
class QAgent(Agent):
"""
Q Chat AI agent implementation.
Attributes:
max_context (int): Maximum context window (8K tokens)
timeout (int): Execution timeout in seconds
"""
def __init__(self):
super().__init__('q', 'q')
self.max_context = 32000 # ~8K tokens
self.timeout = 300
def execute(self, prompt_file: str) -> Tuple[bool, str]:
"""
Execute Q with prompt.
Args:
prompt_file (str): Path to prompt file
Returns:
tuple: (success, output)
Example:
q = QAgent()
success, output = q.execute('PROMPT.md')
"""
if not self.available:
return False, "Q not available"
try:
result = subprocess.run(
[self.command, prompt_file],
capture_output=True,
text=True,
timeout=self.timeout
)
return result.returncode == 0, result.stdout
except subprocess.TimeoutExpired:
return False, "Q execution timed out"
except Exception as e:
return False, f"Q execution error: {str(e)}"
Agent Manager¶
class AgentManager:
"""
Manages multiple AI agents and handles agent selection.
Example:
manager = AgentManager()
agent = manager.get_agent('auto')
success, output = agent.execute('PROMPT.md')
"""
def __init__(self):
"""Initialize agent manager with all available agents."""
self.agents = {
'claude': ClaudeAgent(),
'gemini': GeminiAgent(),
'q': QAgent()
}
self.available_agents = self.detect_available_agents()
def detect_available_agents(self) -> List[str]:
"""
Detect which agents are available on the system.
Returns:
list: Names of available agents
Example:
manager = AgentManager()
available = manager.detect_available_agents()
print(f"Available agents: {available}")
"""
available = []
for name, agent in self.agents.items():
if agent.available:
available.append(name)
return available
def get_agent(self, name: str = 'auto') -> Agent:
"""
Get specific agent or auto-select best available.
Args:
name (str): Agent name or 'auto' for auto-selection
Returns:
Agent: Selected agent instance
Raises:
ValueError: If requested agent not available
Example:
manager = AgentManager()
# Get specific agent
claude = manager.get_agent('claude')
# Auto-select best available
agent = manager.get_agent('auto')
"""
if name == 'auto':
return self.auto_select_agent()
if name not in self.agents:
raise ValueError(f"Unknown agent: {name}")
agent = self.agents[name]
if not agent.available:
raise ValueError(f"Agent not available: {name}")
return agent
def auto_select_agent(self) -> Agent:
"""
Automatically select the best available agent.
Priority: claude > gemini > q
Returns:
Agent: Best available agent
Raises:
RuntimeError: If no agents available
"""
priority = ['claude', 'gemini', 'q']
for agent_name in priority:
if agent_name in self.available_agents:
return self.agents[agent_name]
raise RuntimeError("No AI agents available")
def execute_with_fallback(self, prompt_file: str,
preferred_agent: str = 'auto') -> Tuple[bool, str, str]:
"""
Execute with fallback to other agents if preferred fails.
Args:
prompt_file (str): Path to prompt file
preferred_agent (str): Preferred agent name
Returns:
tuple: (success, output, agent_used)
Example:
manager = AgentManager()
success, output, agent = manager.execute_with_fallback('PROMPT.md')
print(f"Executed with {agent}")
"""
# Try preferred agent first
try:
agent = self.get_agent(preferred_agent)
success, output = agent.execute(prompt_file)
if success:
return True, output, agent.name
except (ValueError, RuntimeError):
pass
# Try other available agents
for agent_name in self.available_agents:
if agent_name != preferred_agent:
agent = self.agents[agent_name]
success, output = agent.execute(prompt_file)
if success:
return True, output, agent.name
return False, "All agents failed", None
Agent Execution Utilities¶
Retry Logic¶
def execute_with_retry(agent: Agent, prompt_file: str,
max_retries: int = 3,
delay: int = 2) -> Tuple[bool, str]:
"""
Execute agent with retry logic.
Args:
agent (Agent): Agent to execute
prompt_file (str): Path to prompt file
max_retries (int): Maximum retry attempts
delay (int): Delay between retries in seconds
Returns:
tuple: (success, output)
Example:
agent = ClaudeAgent()
success, output = execute_with_retry(agent, 'PROMPT.md')
"""
for attempt in range(max_retries):
success, output = agent.execute(prompt_file)
if success:
return True, output
if attempt < max_retries - 1:
time.sleep(delay * (2 ** attempt)) # Exponential backoff
return False, f"Failed after {max_retries} attempts"
Output Processing¶
def process_agent_output(output: str) -> dict:
"""
Process and parse agent output.
Args:
output (str): Raw agent output
Returns:
dict: Processed output with metadata
Example:
success, raw_output = agent.execute('PROMPT.md')
processed = process_agent_output(raw_output)
"""
processed = {
'raw': output,
'lines': output.splitlines(),
'size': len(output),
'has_error': 'error' in output.lower(),
'has_completion': False, # Legacy completion marker - no longer used
'files_modified': extract_modified_files(output),
'commands_run': extract_commands(output)
}
return processed
def extract_modified_files(output: str) -> List[str]:
"""Extract list of modified files from output."""
files = []
patterns = [
r"Created file: (.+)",
r"Modified file: (.+)",
r"Writing to (.+)"
]
for pattern in patterns:
matches = re.findall(pattern, output)
files.extend(matches)
return list(set(files))
def extract_commands(output: str) -> List[str]:
"""Extract executed commands from output."""
commands = []
patterns = [
r"Running: (.+)",
r"Executing: (.+)",
r"\$ (.+)"
]
for pattern in patterns:
matches = re.findall(pattern, output)
commands.extend(matches)
return commands
Agent Metrics¶
class AgentMetrics:
"""
Track agent performance metrics.
Example:
metrics = AgentMetrics()
metrics.record_execution('claude', 45.3, True)
stats = metrics.get_stats('claude')
"""
def __init__(self):
self.executions = []
def record_execution(self, agent_name: str,
duration: float,
success: bool,
output_size: int = 0):
"""
Record agent execution metrics.
Args:
agent_name (str): Name of agent
duration (float): Execution duration in seconds
success (bool): Whether execution succeeded
output_size (int): Size of output in bytes
"""
self.executions.append({
'agent': agent_name,
'duration': duration,
'success': success,
'output_size': output_size,
'timestamp': time.time()
})
def get_stats(self, agent_name: str = None) -> dict:
"""
Get statistics for agent(s).
Args:
agent_name (str): Specific agent or None for all
Returns:
dict: Agent statistics
"""
if agent_name:
data = [e for e in self.executions if e['agent'] == agent_name]
else:
data = self.executions
if not data:
return {}
durations = [e['duration'] for e in data]
success_rate = sum(1 for e in data if e['success']) / len(data)
return {
'total_executions': len(data),
'success_rate': success_rate,
'avg_duration': sum(durations) / len(durations),
'min_duration': min(durations),
'max_duration': max(durations),
'total_duration': sum(durations)
}
Custom Agent Implementation¶
class CustomAgent(Agent):
"""
Template for implementing custom AI agents.
Example:
class MyAgent(CustomAgent):
def __init__(self):
super().__init__('myagent', 'myagent-cli')
def execute(self, prompt_file):
# Custom execution logic
pass
"""
def __init__(self, name: str, command: str):
super().__init__(name, command)
self.configure()
def configure(self):
"""Override to configure custom agent."""
pass
def pre_execute(self, prompt_file: str):
"""Hook called before execution."""
pass
def post_execute(self, output: str):
"""Hook called after execution."""
pass
def execute(self, prompt_file: str) -> Tuple[bool, str]:
"""Execute custom agent with hooks."""
self.pre_execute(prompt_file)
# Implement custom execution logic
success, output = self._execute_command(prompt_file)
self.post_execute(output)
return success, output
def _execute_command(self, prompt_file: str) -> Tuple[bool, str]:
"""Override with custom command execution."""
raise NotImplementedError