Files
2025-11-29 18:16:25 +08:00

235 lines
9.2 KiB
Python

#!/usr/bin/env python3
"""
Cost & Performance Estimator
Provides transparent estimates for automation operations
"""
import json
from typing import Dict, List
from dataclasses import dataclass, asdict
@dataclass
class AgentEstimate:
"""Estimate for a single agent"""
agent_name: str
description: str
estimated_tokens: int
estimated_minutes: int
priority: str # high, medium, low
purpose: str
@dataclass
class AutomationEstimate:
"""Complete automation estimate"""
mode: str # quick, focused, comprehensive
total_agents: int
agents: List[AgentEstimate]
total_tokens_min: int
total_tokens_max: int
total_minutes_min: int
total_minutes_max: int
total_cost_min: float
total_cost_max: float
recommendations: List[str]
class CostEstimator:
"""Estimates cost and time for automation"""
# Token costs (as of Jan 2025, Claude Sonnet)
TOKEN_COST_INPUT = 0.000003 # $3 per 1M input tokens
TOKEN_COST_OUTPUT = 0.000015 # $15 per 1M output tokens
# Approximate tokens per agent type
AGENT_TOKEN_ESTIMATES = {
'project-analyzer': {'input': 2000, 'output': 1500, 'minutes': 3},
'structure-analyzer': {'input': 1000, 'output': 800, 'minutes': 2},
'security-analyzer': {'input': 1500, 'output': 1000, 'minutes': 3},
'performance-analyzer': {'input': 1500, 'output': 1000, 'minutes': 4},
'test-coverage-analyzer': {'input': 1200, 'output': 800, 'minutes': 3},
'latex-structure-analyzer': {'input': 1000, 'output': 800, 'minutes': 3},
'citation-analyzer': {'input': 800, 'output': 600, 'minutes': 2},
'link-validator': {'input': 1000, 'output': 700, 'minutes': 2},
}
# Default estimate for unknown agents
DEFAULT_ESTIMATE = {'input': 1000, 'output': 800, 'minutes': 3}
def estimate_agent(self, agent_name: str, priority: str = 'medium', purpose: str = '') -> AgentEstimate:
"""
Estimate cost/time for a single agent
Args:
agent_name: Name of the agent
priority: high, medium, or low
purpose: What this agent does
Returns:
AgentEstimate object
"""
estimate = self.AGENT_TOKEN_ESTIMATES.get(agent_name, self.DEFAULT_ESTIMATE)
total_tokens = estimate['input'] + estimate['output']
minutes = estimate['minutes']
return AgentEstimate(
agent_name=agent_name,
description=purpose or f"Analyzes {agent_name.replace('-', ' ')}",
estimated_tokens=total_tokens,
estimated_minutes=minutes,
priority=priority,
purpose=purpose
)
def estimate_quick_mode(self) -> AutomationEstimate:
"""Estimate for quick analysis mode"""
agents = [
self.estimate_agent('project-analyzer', 'high', 'Intelligent project analysis'),
]
return self._calculate_total_estimate('quick', agents, [
'Fastest way to understand your project',
'Low cost, high value',
'Can expand to full automation after'
])
def estimate_focused_mode(self, focus_areas: List[str]) -> AutomationEstimate:
"""Estimate for focused automation mode"""
# Map focus areas to agents
area_to_agents = {
'security': ['security-analyzer'],
'testing': ['test-coverage-analyzer'],
'performance': ['performance-analyzer'],
'structure': ['structure-analyzer'],
'latex': ['latex-structure-analyzer', 'citation-analyzer'],
'links': ['link-validator'],
}
agents = [self.estimate_agent('project-analyzer', 'high', 'Initial analysis')]
for area in focus_areas:
for agent_name in area_to_agents.get(area, []):
agents.append(self.estimate_agent(agent_name, 'high', f'Analyze {area}'))
return self._calculate_total_estimate('focused', agents, [
'Targeted automation for your specific needs',
'Medium cost, high relevance',
'Focuses on what matters most to you'
])
def estimate_comprehensive_mode(self, project_type: str) -> AutomationEstimate:
"""Estimate for comprehensive automation mode"""
agents = [
self.estimate_agent('project-analyzer', 'high', 'Project analysis'),
self.estimate_agent('structure-analyzer', 'high', 'Structure analysis'),
]
# Add type-specific agents
if project_type in ['programming', 'web_app', 'cli']:
agents.extend([
self.estimate_agent('security-analyzer', 'high', 'Security audit'),
self.estimate_agent('performance-analyzer', 'medium', 'Performance check'),
self.estimate_agent('test-coverage-analyzer', 'high', 'Test coverage'),
])
elif project_type in ['academic_writing', 'research']:
agents.extend([
self.estimate_agent('latex-structure-analyzer', 'high', 'LaTeX structure'),
self.estimate_agent('citation-analyzer', 'high', 'Citations & bibliography'),
self.estimate_agent('link-validator', 'medium', 'Link validation'),
])
return self._calculate_total_estimate('comprehensive', agents, [
'Complete automation system',
'Highest cost, most comprehensive',
'Full agent suite, skills, commands, hooks'
])
def _calculate_total_estimate(self, mode: str, agents: List[AgentEstimate], recommendations: List[str]) -> AutomationEstimate:
"""Calculate total estimates from agent list"""
total_tokens = sum(a.estimated_tokens for a in agents)
total_minutes = max(5, sum(a.estimated_minutes for a in agents) // 2) # Parallel execution
# Add buffer (20-50% uncertainty)
tokens_min = total_tokens
tokens_max = int(total_tokens * 1.5)
minutes_min = total_minutes
minutes_max = int(total_minutes * 1.3)
# Calculate costs (rough approximation: 60% input, 40% output)
cost_min = (tokens_min * 0.6 * self.TOKEN_COST_INPUT) + (tokens_min * 0.4 * self.TOKEN_COST_OUTPUT)
cost_max = (tokens_max * 0.6 * self.TOKEN_COST_INPUT) + (tokens_max * 0.4 * self.TOKEN_COST_OUTPUT)
return AutomationEstimate(
mode=mode,
total_agents=len(agents),
agents=agents,
total_tokens_min=tokens_min,
total_tokens_max=tokens_max,
total_minutes_min=minutes_min,
total_minutes_max=minutes_max,
total_cost_min=round(cost_min, 3),
total_cost_max=round(cost_max, 3),
recommendations=recommendations
)
def format_estimate(self, estimate: AutomationEstimate) -> str:
"""Format estimate for display"""
lines = []
lines.append(f"╔══════════════════════════════════════════════════╗")
lines.append(f"║ Automation Estimate - {estimate.mode.upper()} Mode")
lines.append(f"╚══════════════════════════════════════════════════╝")
lines.append("")
# Agent list
for agent in estimate.agents:
priority_icon = "" if agent.priority == "high" else ""
lines.append(f"{priority_icon} {agent.agent_name}")
lines.append(f" {agent.description}")
lines.append(f" ⏱️ ~{agent.estimated_minutes} min | 💰 ~{agent.estimated_tokens} tokens")
lines.append("")
lines.append("────────────────────────────────────────────────────")
# Totals
lines.append(f"Total Agents: {estimate.total_agents}")
lines.append(f"Estimated Time: {estimate.total_minutes_min}-{estimate.total_minutes_max} minutes")
lines.append(f"Estimated Tokens: {estimate.total_tokens_min:,}-{estimate.total_tokens_max:,}")
lines.append(f"Estimated Cost: ${estimate.total_cost_min:.3f}-${estimate.total_cost_max:.3f}")
lines.append("")
lines.append("💡 Notes:")
for rec in estimate.recommendations:
lines.append(f"{rec}")
return "\n".join(lines)
def export_estimate(self, estimate: AutomationEstimate, output_path: str = None) -> Dict:
"""Export estimate as JSON"""
data = asdict(estimate)
if output_path:
with open(output_path, 'w') as f:
json.dump(data, f, indent=2)
return data
# Example usage
if __name__ == '__main__':
estimator = CostEstimator()
print("1. QUICK MODE ESTIMATE")
print("="*60)
quick = estimator.estimate_quick_mode()
print(estimator.format_estimate(quick))
print("\n\n2. FOCUSED MODE ESTIMATE (Security + Testing)")
print("="*60)
focused = estimator.estimate_focused_mode(['security', 'testing'])
print(estimator.format_estimate(focused))
print("\n\n3. COMPREHENSIVE MODE ESTIMATE (Programming Project)")
print("="*60)
comprehensive = estimator.estimate_comprehensive_mode('programming')
print(estimator.format_estimate(comprehensive))