Start a coding agent for a batch of features. Args: feature_ids: List of feature IDs to implement in batch resume: If True, resume features already in_progress Returns: Tuple of (success, message)
(self, feature_ids: list[int], resume: bool = False)
| 746 | return True, f"Started feature {feature_id}" |
| 747 | |
| 748 | def start_feature_batch(self, feature_ids: list[int], resume: bool = False) -> tuple[bool, str]: |
| 749 | """Start a coding agent for a batch of features. |
| 750 | |
| 751 | Args: |
| 752 | feature_ids: List of feature IDs to implement in batch |
| 753 | resume: If True, resume features already in_progress |
| 754 | |
| 755 | Returns: |
| 756 | Tuple of (success, message) |
| 757 | """ |
| 758 | if not feature_ids: |
| 759 | return False, "No features to start" |
| 760 | |
| 761 | # Single feature falls back to start_feature |
| 762 | if len(feature_ids) == 1: |
| 763 | return self.start_feature(feature_ids[0], resume=resume) |
| 764 | |
| 765 | with self._lock: |
| 766 | # Check if any feature in batch is already running |
| 767 | for fid in feature_ids: |
| 768 | if fid in self.running_coding_agents or fid in self._feature_to_primary: |
| 769 | return False, f"Feature {fid} already running" |
| 770 | if len(self.running_coding_agents) >= self.max_concurrency: |
| 771 | return False, "At max concurrency" |
| 772 | total_agents = len(self.running_coding_agents) + len(self.running_testing_agents) |
| 773 | if total_agents >= MAX_TOTAL_AGENTS: |
| 774 | return False, f"At max total agents ({total_agents}/{MAX_TOTAL_AGENTS})" |
| 775 | |
| 776 | # Mark all features as in_progress in a single transaction |
| 777 | session = self.get_session() |
| 778 | try: |
| 779 | features_to_mark = [] |
| 780 | for fid in feature_ids: |
| 781 | feature = session.query(Feature).filter(Feature.id == fid).first() |
| 782 | if not feature: |
| 783 | return False, f"Feature {fid} not found" |
| 784 | if feature.passes: |
| 785 | return False, f"Feature {fid} already complete" |
| 786 | if not resume: |
| 787 | if feature.in_progress: |
| 788 | return False, f"Feature {fid} already in progress" |
| 789 | features_to_mark.append(feature) |
| 790 | else: |
| 791 | if not feature.in_progress: |
| 792 | return False, f"Feature {fid} not in progress, cannot resume" |
| 793 | |
| 794 | for feature in features_to_mark: |
| 795 | feature.in_progress = True |
| 796 | session.commit() |
| 797 | finally: |
| 798 | session.close() |
| 799 | |
| 800 | # Spawn batch coding agent |
| 801 | success, message = self._spawn_coding_agent_batch(feature_ids) |
| 802 | if not success: |
| 803 | # Clear in_progress on failure |
| 804 | session = self.get_session() |
| 805 | try: |
no test coverage detected