diff --git a/swe_af/execution/coding_loop.py b/swe_af/execution/coding_loop.py index 009b9c8..7bd9704 100644 --- a/swe_af/execution/coding_loop.py +++ b/swe_af/execution/coding_loop.py @@ -699,6 +699,12 @@ async def run_coding_loop( # --- 4. BRANCH ON ACTION --- if action == "approve": + if iteration == 1: + if note_fn: + note_fn( + f"FAST-PATH EXIT: {issue_name} approved on first iteration", + tags=["coding_loop", "fast_path", "complete", issue_name], + ) if note_fn: note_fn( f"Coding loop APPROVED: {issue_name} after {iteration} iteration(s)", diff --git a/swe_af/execution/schemas.py b/swe_af/execution/schemas.py index f8653b4..2903a1d 100644 --- a/swe_af/execution/schemas.py +++ b/swe_af/execution/schemas.py @@ -374,6 +374,9 @@ class QASynthesisResult(BaseModel): "claude_code": { **{field: "sonnet" for field in ALL_MODEL_FIELDS}, "qa_synthesizer_model": "haiku", + "retry_advisor_model": "haiku", + "git_model": "haiku", + "merger_model": "haiku", }, "open_code": { **{field: "minimax/minimax-m2.5" for field in ALL_MODEL_FIELDS}, diff --git a/swe_af/reasoners/execution_agents.py b/swe_af/reasoners/execution_agents.py index d0f57ab..4086998 100644 --- a/swe_af/reasoners/execution_agents.py +++ b/swe_af/reasoners/execution_agents.py @@ -133,7 +133,7 @@ async def run_retry_advisor( model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=20, allowed_tools=[Tool.READ, Tool.GLOB, Tool.GREP, Tool.BASH], permission_mode=permission_mode or None, )) @@ -215,7 +215,7 @@ async def run_issue_advisor( model=model, provider=ai_provider, cwd=cwd, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=30, allowed_tools=[Tool.READ, Tool.GLOB, Tool.GREP, Tool.BASH], permission_mode=permission_mode or None, )) @@ -293,7 +293,7 @@ async def run_replanner( model=replan_model, provider=ai_provider, cwd=state.repo_path or ".", - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=30, allowed_tools=[Tool.READ, Tool.GLOB, Tool.GREP, Tool.BASH], permission_mode=permission_mode or None, )) @@ -407,7 +407,7 @@ class IssueWriterOutput(BaseModel): model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=20, allowed_tools=[Tool.READ, Tool.WRITE, Tool.GLOB, Tool.GREP], permission_mode=permission_mode or None, )) @@ -472,7 +472,7 @@ async def run_verifier( model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=30, allowed_tools=[Tool.READ, Tool.GLOB, Tool.GREP, Tool.BASH], permission_mode=permission_mode or None, )) @@ -558,7 +558,7 @@ async def run_git_init( model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=10, allowed_tools=[Tool.BASH], permission_mode=permission_mode or None, )) @@ -636,7 +636,7 @@ class WorkspaceSetupResult(BaseModel): model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=10, allowed_tools=[Tool.BASH], permission_mode=permission_mode or None, )) @@ -703,7 +703,7 @@ async def run_merger( model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=10, allowed_tools=[Tool.BASH, Tool.READ, Tool.GLOB, Tool.GREP], permission_mode=permission_mode or None, )) @@ -777,7 +777,7 @@ async def run_integration_tester( model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=30, allowed_tools=[Tool.BASH, Tool.READ, Tool.WRITE, Tool.GLOB, Tool.GREP], permission_mode=permission_mode or None, )) @@ -848,7 +848,7 @@ class WorkspaceCleanupResult(BaseModel): model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=10, allowed_tools=[Tool.BASH], permission_mode=permission_mode or None, )) @@ -922,7 +922,7 @@ async def run_coder( model=model, provider=ai_provider, cwd=worktree_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=50, allowed_tools=[ Tool.READ, Tool.WRITE, Tool.EDIT, Tool.BASH, Tool.GLOB, Tool.GREP, @@ -999,7 +999,7 @@ async def run_qa( model=model, provider=ai_provider, cwd=worktree_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=20, allowed_tools=[ Tool.READ, Tool.WRITE, Tool.EDIT, Tool.BASH, Tool.GLOB, Tool.GREP, @@ -1079,7 +1079,7 @@ async def run_code_reviewer( model=model, provider=ai_provider, cwd=worktree_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=20, allowed_tools=[Tool.READ, Tool.GLOB, Tool.GREP, Tool.BASH], permission_mode=permission_mode or None, )) @@ -1155,7 +1155,7 @@ async def run_qa_synthesizer( model=model, provider=ai_provider, cwd=worktree_path or ".", - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=10, allowed_tools=[], permission_mode=permission_mode or None, )) @@ -1251,7 +1251,7 @@ class FixGeneratorOutput(BaseModel): model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=30, allowed_tools=[Tool.READ, Tool.GLOB, Tool.GREP, Tool.BASH], permission_mode=permission_mode or None, )) @@ -1320,7 +1320,7 @@ async def run_repo_finalize( model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=10, allowed_tools=[Tool.BASH, Tool.READ, Tool.GLOB, Tool.GREP], permission_mode=permission_mode or None, )) @@ -1396,7 +1396,7 @@ async def run_github_pr( model=model, provider=ai_provider, cwd=repo_path, - max_turns=DEFAULT_AGENT_MAX_TURNS, + max_turns=10, allowed_tools=[Tool.BASH], permission_mode=permission_mode or None, )) diff --git a/swe_af/reasoners/pipeline.py b/swe_af/reasoners/pipeline.py index 001cf14..18b8170 100644 --- a/swe_af/reasoners/pipeline.py +++ b/swe_af/reasoners/pipeline.py @@ -166,7 +166,7 @@ async def run_product_manager( artifacts_dir: str = ".artifacts", additional_context: str = "", model: str = "sonnet", - max_turns: int = DEFAULT_AGENT_MAX_TURNS, + max_turns: int = 30, permission_mode: str = "", ai_provider: str = "claude", ) -> dict: @@ -212,7 +212,7 @@ async def run_architect( artifacts_dir: str = ".artifacts", feedback: str = "", model: str = "sonnet", - max_turns: int = DEFAULT_AGENT_MAX_TURNS, + max_turns: int = 30, permission_mode: str = "", ai_provider: str = "claude", ) -> dict: @@ -260,7 +260,7 @@ async def run_tech_lead( artifacts_dir: str = ".artifacts", revision_number: int = 0, model: str = "sonnet", - max_turns: int = DEFAULT_AGENT_MAX_TURNS, + max_turns: int = 30, permission_mode: str = "", ai_provider: str = "claude", ) -> dict: @@ -310,7 +310,7 @@ async def run_sprint_planner( repo_path: str, artifacts_dir: str = ".artifacts", model: str = "sonnet", - max_turns: int = DEFAULT_AGENT_MAX_TURNS, + max_turns: int = 30, permission_mode: str = "", ai_provider: str = "claude", ) -> dict: diff --git a/tests/test_model_config.py b/tests/test_model_config.py index 9f01798..5222f06 100644 --- a/tests/test_model_config.py +++ b/tests/test_model_config.py @@ -16,11 +16,12 @@ class TestResolveRuntimeModels(unittest.TestCase): def test_claude_code_defaults(self) -> None: resolved = resolve_runtime_models(runtime="claude_code", models=None) + haiku_fields = {"qa_synthesizer_model", "retry_advisor_model", "git_model", "merger_model"} for field in ALL_MODEL_FIELDS: - if field == "qa_synthesizer_model": - continue - self.assertEqual(resolved[field], "sonnet") - self.assertEqual(resolved["qa_synthesizer_model"], "haiku") + if field in haiku_fields: + self.assertEqual(resolved[field], "haiku") + else: + self.assertEqual(resolved[field], "sonnet") def test_open_code_defaults(self) -> None: resolved = resolve_runtime_models(runtime="open_code", models=None)