-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathapi.py
More file actions
142 lines (120 loc) · 4.54 KB
/
Copy pathapi.py
File metadata and controls
142 lines (120 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""
Public API for fireteam library.
Provides adaptive task execution using Claude Code CLI.
Piggybacks on user's Claude Code session for unified billing.
Usage:
import fireteam
result = await fireteam.execute(
project_dir="/path/to/project",
goal="Fix the bug in auth.py",
context="Error logs: ...",
)
"""
import logging
from pathlib import Path
from . import config
from .claude_cli import CLISession
from .circuit_breaker import CircuitBreaker, create_circuit_breaker
from .complexity import ComplexityLevel, estimate_complexity
from .loops import single_turn, moderate_loop, full_loop
from .models import ExecutionMode, ExecutionResult, LoopConfig
from .rate_limiter import RateLimiter, get_rate_limiter
# Map complexity levels to execution modes
# SIMPLE is now treated as SINGLE_TURN (no separate mode)
COMPLEXITY_TO_MODE = {
ComplexityLevel.TRIVIAL: ExecutionMode.SINGLE_TURN,
ComplexityLevel.SIMPLE: ExecutionMode.SINGLE_TURN, # Merged with SINGLE_TURN
ComplexityLevel.MODERATE: ExecutionMode.MODERATE,
ComplexityLevel.COMPLEX: ExecutionMode.FULL,
}
async def execute(
project_dir: str | Path,
goal: str,
mode: ExecutionMode | None = None,
context: str = "",
max_iterations: int | None = None,
calls_per_hour: int | None = None,
session: CLISession | None = None,
circuit_breaker: CircuitBreaker | None = None,
logger: logging.Logger | None = None,
) -> ExecutionResult:
"""
Execute a task with appropriate complexity handling.
Uses Claude Code CLI, piggybacking on the user's existing
session and credits. No separate API key required.
Args:
project_dir: Path to the project directory
goal: Task description
mode: Execution mode (None = auto-detect from complexity)
context: Additional context (crash logs, etc.)
max_iterations: Maximum loop iterations for MODERATE/FULL modes (None = infinite)
calls_per_hour: Rate limit for API calls (default: 100)
session: Optional CLI session for continuity across calls
circuit_breaker: Optional circuit breaker for stuck loop detection
logger: Optional logger
Returns:
ExecutionResult with success status and output
Features:
- Claude Code session piggybacking (unified billing)
- Adaptive complexity routing
- Circuit breaker warnings for stuck loops
- Rate limiting for API budget
- Dual-gate exit detection
- Session continuity via Claude Code
"""
project_dir = Path(project_dir).resolve()
log = logger or logging.getLogger("fireteam")
# Initialize session for continuity
session = session or CLISession()
# Initialize rate limiter
rate_limiter = get_rate_limiter(calls_per_hour=calls_per_hour)
# Initialize circuit breaker
breaker = circuit_breaker or create_circuit_breaker()
# Auto-detect mode if not specified
if mode is None:
log.info("Estimating task complexity...")
complexity = await estimate_complexity(
goal, context, project_dir=project_dir, session=session
)
mode = COMPLEXITY_TO_MODE[complexity]
log.info(f"Complexity: {complexity.value} -> Mode: {mode.value}")
# Use config default if max_iterations not explicitly provided
effective_max_iterations = max_iterations if max_iterations is not None else config.MAX_ITERATIONS
# Dispatch based on mode
if mode == ExecutionMode.SINGLE_TURN:
return await single_turn(
project_dir, goal, context,
session=session,
rate_limiter=rate_limiter,
log=log,
)
elif mode == ExecutionMode.MODERATE:
cfg = LoopConfig(
max_iterations=effective_max_iterations,
parallel_reviewers=1,
majority_required=1,
)
return await moderate_loop(
project_dir, goal, context,
session=session,
rate_limiter=rate_limiter,
circuit_breaker=breaker,
cfg=cfg,
log=log,
)
elif mode == ExecutionMode.FULL:
cfg = LoopConfig(
max_iterations=effective_max_iterations,
parallel_reviewers=3,
majority_required=2,
)
return await full_loop(
project_dir, goal, context,
session=session,
rate_limiter=rate_limiter,
circuit_breaker=breaker,
cfg=cfg,
log=log,
)
else:
return ExecutionResult(success=False, mode=mode, error=f"Unknown mode: {mode}")