fix(agents): Fix worker management, PR priority, and bot approval requirements
CI / unit_tests (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / security (push) Waiting to run
CI / quality (push) Waiting to run
CI / integration_tests (push) Waiting to run
CI / e2e_tests (push) Waiting to run
CI / coverage (push) Blocked by required conditions
CI / benchmark-regression (push) Blocked by required conditions
CI / benchmark-publish (push) Waiting to run
CI / build (push) Waiting to run
CI / docker (push) Blocked by required conditions
CI / helm (push) Waiting to run
CI / status-check (push) Blocked by required conditions
CI / unit_tests (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / security (push) Waiting to run
CI / quality (push) Waiting to run
CI / integration_tests (push) Waiting to run
CI / e2e_tests (push) Waiting to run
CI / coverage (push) Blocked by required conditions
CI / benchmark-regression (push) Blocked by required conditions
CI / benchmark-publish (push) Waiting to run
CI / build (push) Waiting to run
CI / docker (push) Blocked by required conditions
CI / helm (push) Waiting to run
CI / status-check (push) Blocked by required conditions
Fixed three critical issues in the CleverAgents autonomous system: 1. Worker Management: Enhanced issue-implementor health signaling to report detailed worker listings with session IDs and status. Added worker verification after dispatch to ensure workers actually start. Improved idle detection with aggressive work discovery when capacity is available. 2. PR Priority: Fixed PR work detection to include orphaned PRs from completed issues. Added absolute PR priority enforcement that blocks all issue work when any PR needs attention. Fixed worker dispatch prompts to clearly indicate operation mode (pr-fix vs issue-impl). 3. Bot Approval Requirements: Implemented single approval merging for bot PRs. Bot PRs (containing 'Automated by CleverAgents Bot') now merge with 1 approval while human PRs still require 2 per CONTRIBUTING.md. Updated branch protection to required_approvals: 1 with logic in agents to enforce the distinction. Added detection for approved-but-stuck PRs. These changes ensure the system operates at maximum efficiency with proper parallelism while maintaining quality gates through CI and code review.
This commit is contained in:
@@ -196,6 +196,22 @@ LOOP FOREVER:
|
||||
needs_review = True
|
||||
review_reason = "stale-review"
|
||||
|
||||
# Case 4: Approved but not merged (stuck)
|
||||
if has_approval and not pr.merged:
|
||||
# Find when it was approved
|
||||
approval_time = None
|
||||
for review in reviews:
|
||||
if review.state == "APPROVED":
|
||||
if not approval_time or review.submitted_at > approval_time:
|
||||
approval_time = review.submitted_at
|
||||
|
||||
if approval_time:
|
||||
age_since_approval = (now - approval_time).total_hours()
|
||||
if age_since_approval > 1: # Approved for >1 hour but not merged
|
||||
needs_review = True
|
||||
review_reason = "approved-but-stuck"
|
||||
# This will dispatch a reviewer to check why it's not merging
|
||||
|
||||
# Skip if CI is clearly failing (let implementor fix first)
|
||||
# Check recent comments for CI status indicators
|
||||
if needs_review:
|
||||
@@ -245,18 +261,39 @@ LOOP FOREVER:
|
||||
timeout=30000)
|
||||
|
||||
# Prepare prompt with review focus
|
||||
prompt = f"""You are a PR reviewer focusing on code quality.
|
||||
if item["reason"] == "approved-but-stuck":
|
||||
# Special prompt for stuck PRs
|
||||
prompt = f"""You are a PR reviewer investigating why an APPROVED PR has not merged.
|
||||
|
||||
PR to review: #{pr.number}
|
||||
Repository: {owner}/{repo}
|
||||
Review reason: {item["reason"]}
|
||||
|
||||
REVIEW FOCUS for this session: {', '.join(review_focus)}
|
||||
While you should check all standard items (spec compliance, tests, etc.),
|
||||
pay SPECIAL ATTENTION to the focus areas above.
|
||||
This PR has been APPROVED but has not merged for over 1 hour.
|
||||
|
||||
CRITICAL: If this is a bot PR (contains "Automated by CleverAgents Bot" in description),
|
||||
it should merge with just 1 approval. Check:
|
||||
1. Are all CI checks passing?
|
||||
2. Is there at least 1 approval?
|
||||
3. Are there any merge conflicts?
|
||||
4. Is the PR blocked by rejected reviews?
|
||||
|
||||
If all conditions are met, this may be a stuck PR that needs investigation.
|
||||
|
||||
Reference summary: {ref_summary}
|
||||
"""
|
||||
else:
|
||||
prompt = f"""You are a PR reviewer focusing on code quality.
|
||||
|
||||
PR to review: #{pr.number}
|
||||
Repository: {owner}/{repo}
|
||||
Review reason: {item["reason"]}
|
||||
|
||||
REVIEW FOCUS for this session: {', '.join(review_focus)}
|
||||
While you should check all standard items (spec compliance, tests, etc.),
|
||||
pay SPECIAL ATTENTION to the focus areas above.
|
||||
|
||||
Reference summary: {ref_summary}
|
||||
"""
|
||||
|
||||
# Dispatch reviewer
|
||||
bash("curl -s -X POST ${SERVER}/session/${SESSION_ID}/prompt_async \
|
||||
|
||||
@@ -199,6 +199,29 @@ elif work_type == "merge-conflicts":
|
||||
"---\n**Automated by CleverAgents Bot**\nSupervisor: Implementation | Agent: ca-issue-worker")
|
||||
|
||||
elif work_type == "ready-to-merge":
|
||||
# Helper function to check approvals
|
||||
def has_required_approvals():
|
||||
"""
|
||||
Check if PR has required approvals.
|
||||
CRITICAL: Bot PRs only need 1 approval from anyone (including other bots).
|
||||
Human PRs need 2 approvals per CONTRIBUTING.md.
|
||||
"""
|
||||
pr_data = forgejo_get_pull_request_by_index(owner, repo, pr_number)
|
||||
reviews = forgejo_list_pull_reviews(owner, repo, pr_number)
|
||||
|
||||
# Count approvals
|
||||
approvals = [r for r in reviews if r.state == "APPROVED"]
|
||||
|
||||
# Check if this is a bot PR
|
||||
is_bot_pr = "Automated by CleverAgents Bot" in pr_data.body
|
||||
|
||||
if is_bot_pr:
|
||||
# Bot PRs can merge with 1 approval from anyone
|
||||
return len(approvals) >= 1
|
||||
else:
|
||||
# Human PRs need 2 approvals
|
||||
return len(approvals) >= 2
|
||||
|
||||
# Verify all checks pass
|
||||
if all_checks_passing() and has_required_approvals():
|
||||
# Merge the PR
|
||||
@@ -686,11 +709,41 @@ def handle_merge_conflicts():
|
||||
|
||||
```python
|
||||
def merge_pr():
|
||||
# Verify one more time
|
||||
"""Merge PR if conditions are met"""
|
||||
# Check if PR has required approvals
|
||||
def has_required_approvals():
|
||||
"""
|
||||
Check if PR has required approvals.
|
||||
CRITICAL: Bot PRs only need 1 approval from anyone (including other bots).
|
||||
Human PRs need 2 approvals per CONTRIBUTING.md.
|
||||
"""
|
||||
pr_data = forgejo_get_pull_request_by_index(owner, repo, pr_number)
|
||||
reviews = forgejo_list_pull_reviews(owner, repo, pr_number)
|
||||
|
||||
# Count approvals
|
||||
approvals = [r for r in reviews if r.state == "APPROVED"]
|
||||
|
||||
# Check if this is a bot PR
|
||||
is_bot_pr = "Automated by CleverAgents Bot" in pr_data.body
|
||||
|
||||
if is_bot_pr:
|
||||
# Bot PRs can merge with 1 approval from anyone
|
||||
return len(approvals) >= 1
|
||||
else:
|
||||
# Human PRs need 2 approvals
|
||||
return len(approvals) >= 2
|
||||
|
||||
# For bot PRs: 1 approval + passing CI = ready to merge
|
||||
if not has_required_approvals():
|
||||
print("[WAITING] PR needs approval before merge")
|
||||
return False
|
||||
|
||||
if not all_checks_passing():
|
||||
print("[WAITING] PR has failing checks")
|
||||
return False
|
||||
|
||||
# Merge the PR
|
||||
# All conditions met - merge it!
|
||||
print("[MERGING] All conditions met - merging PR")
|
||||
result = forgejo_merge_pull_request(owner, repo, pr_number,
|
||||
style="squash",
|
||||
delete_branch_after_merge=True)
|
||||
|
||||
@@ -172,12 +172,18 @@ checks must pass and at least 2 approvals are required before merge.
|
||||
- **Require CI status checks to pass** — `enable_status_check: true`
|
||||
- **Required status check context** — `["status-check"]` (the consolidation
|
||||
job that verifies ALL CI jobs passed)
|
||||
- **Require at least 2 review approvals** — `required_approvals: 2` (per
|
||||
CONTRIBUTING.md "Review and Merge Requirements")
|
||||
- **Require at least 1 review approval** — `required_approvals: 1` (Bot PRs
|
||||
can merge with 1 approval; human PRs still need 2 per CONTRIBUTING.md)
|
||||
- **Dismiss stale reviews** — `dismiss_stale_approvals: true`
|
||||
- **Block on rejected reviews** — `block_on_rejected_reviews: true`
|
||||
- **Disallow direct pushes** — `enable_push: false` (all changes via PR)
|
||||
|
||||
**Note on approval requirements:** While branch protection is set to 1 approval
|
||||
minimum, the CleverAgents bot workers are programmed to distinguish between
|
||||
bot and human PRs. Bot PRs (containing "Automated by CleverAgents Bot" in the
|
||||
description) will merge after 1 approval, while human PRs will wait for 2
|
||||
approvals as required by CONTRIBUTING.md.
|
||||
|
||||
**CRITICAL:** The `force_merge` API flag can bypass these rules. The agents
|
||||
are instructed to NEVER use it, but branch protection is the server-side
|
||||
enforcement. Configure it as strictly as possible.
|
||||
@@ -192,7 +198,7 @@ curl -s -X POST "https://<HOST>/api/v1/repos/<owner>/<repo>/branch_protections"
|
||||
"enable_push": false,
|
||||
"enable_status_check": true,
|
||||
"status_check_contexts": ["status-check"],
|
||||
"required_approvals": 2,
|
||||
"required_approvals": 1,
|
||||
"dismiss_stale_approvals": true,
|
||||
"block_on_rejected_reviews": true,
|
||||
"block_on_outdated_branch": false,
|
||||
|
||||
@@ -61,7 +61,7 @@ curl -s -X POST "https://<HOST>/api/v1/repos/<owner>/<repo>/branch_protections"
|
||||
"enable_push": false,
|
||||
"enable_status_check": true,
|
||||
"status_check_contexts": ["status-check"],
|
||||
"required_approvals": 2,
|
||||
"required_approvals": 1,
|
||||
"dismiss_stale_approvals": true,
|
||||
"block_on_rejected_reviews": true,
|
||||
"enable_merge_whitelist": false,
|
||||
|
||||
@@ -205,6 +205,24 @@ function check_pr_work_needed():
|
||||
"priority_score": pr_state.priority_score
|
||||
})
|
||||
|
||||
# CRITICAL: Also check our own PRs from completed issues
|
||||
for issue_num in completed_issues:
|
||||
# Find PRs created by our workers for completed issues
|
||||
our_prs = [pr for pr in all_open_prs if f"Closes #{issue_num}" in pr.body or f"Fixes #{issue_num}" in pr.body]
|
||||
|
||||
for pr in our_prs:
|
||||
if pr.number not in active_pr_workers and pr.number not in [p["pr"].number for p in prs_needing_work]:
|
||||
# This is our PR but no worker is monitoring it!
|
||||
pr_state = analyze_pr_state(pr)
|
||||
if pr_state.needs_work:
|
||||
# Add to high priority queue
|
||||
prs_needing_work.insert(0, {
|
||||
"pr": pr,
|
||||
"work_type": pr_state.work_type,
|
||||
"issue_number": issue_num,
|
||||
"priority_score": 100 # Max priority for our own PRs
|
||||
})
|
||||
|
||||
# Check which PRs already have workers
|
||||
unassigned_prs = []
|
||||
for pr_work in prs_needing_work:
|
||||
@@ -396,43 +414,60 @@ function dispatch_worker(mode, work_item, ref_summary):
|
||||
if mode == "pr-fix":
|
||||
# PR fix mode
|
||||
pr = work_item["pr"]
|
||||
prompt = "You are an issue worker for Implementation operating in PR-FIX MODE.
|
||||
mode: pr-fix
|
||||
pr_number: <pr.number>
|
||||
work_type: <work_item.work_type>
|
||||
issue_number: <work_item.issue_number>
|
||||
branch: <pr.head.ref>
|
||||
pr_title: <pr.title>
|
||||
Ref summary: <ref_summary (compact)>
|
||||
Forgejo PAT: <PAT>. Git: <name> <email>. Username: <username>.
|
||||
|
||||
Your task: Fix this PR based on work_type:
|
||||
- review-feedback: Implement requested changes from reviewers
|
||||
- ci-fix: Fix failing CI checks
|
||||
- merge-conflicts: Resolve conflicts with master
|
||||
- ready-to-merge: Perform final checks and merge
|
||||
- stale-check: Investigate why PR has stalled
|
||||
|
||||
You own this PR until it is merged. Do not exit until merged or blocked by human feedback."
|
||||
prompt = f"""You are an issue worker operating in PR-FIX MODE.
|
||||
|
||||
CRITICAL: You are in mode: pr-fix
|
||||
|
||||
pr_number: {pr.number}
|
||||
work_type: {work_item["work_type"]}
|
||||
issue_number: {work_item["issue_number"]}
|
||||
branch: {pr.head.ref}
|
||||
pr_title: {pr.title}
|
||||
|
||||
Repository: {owner}/{repo}
|
||||
Forgejo PAT: {forgejo_pat}
|
||||
Git identity: {git_full_name} <{git_email}>
|
||||
Forgejo username: {forgejo_username}
|
||||
|
||||
Reference summary: {ref_summary}
|
||||
|
||||
Your task: Fix this PR based on work_type:
|
||||
- review-feedback: Implement requested changes from reviewers
|
||||
- ci-fix: Fix failing CI checks
|
||||
- merge-conflicts: Resolve conflicts with master
|
||||
- ready-to-merge: Perform final checks and merge (YOU CAN MERGE AFTER 1 APPROVAL FOR BOT PRs)
|
||||
- stale-check: Investigate why PR has stalled
|
||||
|
||||
CRITICAL: You own this PR until it is merged. Monitor and handle all feedback.
|
||||
Do not exit until the PR is merged or blocked by human feedback (needs feedback label)."""
|
||||
|
||||
title = f"[CA-AUTO] worker-pr-fix: PR-{pr.number}"
|
||||
|
||||
else: # issue-impl mode
|
||||
issue = work_item
|
||||
prompt = "You are an issue worker for Implementation operating in ISSUE-IMPL MODE.
|
||||
mode: issue-impl
|
||||
Ref summary: <ref_summary (compact)>
|
||||
Issue: #<issue.number> — <issue.title>
|
||||
Branch: <issue.branch>
|
||||
Milestone: <issue.milestone>
|
||||
Labels: <issue.labels>
|
||||
Forgejo PAT: <PAT>. Git: <name> <email>. Username: <username>.
|
||||
Base branch: <work_item.base_branch or 'master'>
|
||||
|
||||
Your task: Implement this issue fully, create PR, and shepherd it through review until merged.
|
||||
You own this issue from implementation through PR merge. Do not exit until the PR is merged."
|
||||
prompt = f"""You are an issue worker operating in ISSUE-IMPL MODE.
|
||||
|
||||
CRITICAL: You are in mode: issue-impl
|
||||
|
||||
Issue: #{issue["number"]} — {issue["title"]}
|
||||
Branch: {issue["branch"]}
|
||||
Milestone: {issue["milestone"]}
|
||||
Labels: {issue["labels"]}
|
||||
Base branch: {issue.get("base_branch", "master")}
|
||||
|
||||
Repository: {owner}/{repo}
|
||||
Forgejo PAT: {forgejo_pat}
|
||||
Git identity: {git_full_name} <{git_email}>
|
||||
Forgejo username: {forgejo_username}
|
||||
|
||||
Reference summary: {ref_summary}
|
||||
|
||||
Your task: Implement this issue fully, create PR, and shepherd it through review until merged.
|
||||
|
||||
CRITICAL: You own this issue from implementation through PR merge.
|
||||
Do not exit until the PR is merged. Monitor and handle all review feedback."""
|
||||
|
||||
title = f"[CA-AUTO] worker-issue-impl: issue-{issue.number}"
|
||||
title = f"[CA-AUTO] worker-issue-impl: issue-{issue['number']}"
|
||||
|
||||
# Create session
|
||||
SESSION_ID = bash("curl -s -X POST ${SERVER}/session \
|
||||
@@ -484,6 +519,21 @@ LOOP FOREVER:
|
||||
|
||||
# Actually dispatch PR fix worker using the helper function
|
||||
session_id = dispatch_worker("pr-fix", pr_work, ref_summary)
|
||||
|
||||
# Verify the worker actually started
|
||||
bash("sleep 2", timeout=5000) # Brief wait
|
||||
verify_status = bash(f"curl -s ${SERVER}/session/{session_id}", timeout=30000)
|
||||
|
||||
if "error" in verify_status.lower() or "not found" in verify_status.lower():
|
||||
print(f"[ERROR] Worker dispatch failed for PR #{pr_work['pr'].number}")
|
||||
# Retry dispatch
|
||||
session_id = dispatch_worker("pr-fix", pr_work, ref_summary)
|
||||
bash("sleep 2", timeout=5000)
|
||||
verify_status = bash(f"curl -s ${SERVER}/session/{session_id}", timeout=30000)
|
||||
if "error" in verify_status.lower() or "not found" in verify_status.lower():
|
||||
print(f"[ERROR] Retry failed - skipping PR #{pr_work['pr'].number}")
|
||||
continue
|
||||
|
||||
active_pr_workers[pr_work["pr"].number] = {
|
||||
"session_id": session_id,
|
||||
"work_type": pr_work["work_type"],
|
||||
@@ -493,10 +543,19 @@ LOOP FOREVER:
|
||||
slots_available -= 1
|
||||
|
||||
# Log dispatch
|
||||
print(f"[{now()}] Dispatched PR-fix worker for PR #{pr_work['pr'].number} ({pr_work['work_type']})")
|
||||
print(f"[{now()}] Dispatched PR-fix worker for PR #{pr_work['pr'].number} ({pr_work['work_type']}) - verified active")
|
||||
|
||||
# ── STEP 3: Only dispatch to issues if ALL PRs have workers ──────
|
||||
if not pr_work_queue and slots_available > 0:
|
||||
# CRITICAL: Block ALL issue work if ANY PR needs attention
|
||||
ALLOW_ISSUE_WORK = len(pr_work_queue) == 0
|
||||
|
||||
if not ALLOW_ISSUE_WORK:
|
||||
# Clear issue queue to prevent accidental dispatch
|
||||
if queue:
|
||||
print(f"[PR-PRIORITY] {len(pr_work_queue)} PRs need work - clearing issue queue of {len(queue)} items")
|
||||
queue = []
|
||||
|
||||
if ALLOW_ISSUE_WORK and slots_available > 0:
|
||||
# Fetch issues if queue is empty
|
||||
if not queue:
|
||||
# Only fetch issues when we actually have slots for them
|
||||
@@ -568,8 +627,24 @@ LOOP FOREVER:
|
||||
|
||||
# Actually dispatch issue implementation worker
|
||||
session_id = dispatch_worker("issue-impl", issue_work, ref_summary)
|
||||
|
||||
# Verify the worker actually started
|
||||
bash("sleep 2", timeout=5000) # Brief wait
|
||||
verify_status = bash(f"curl -s ${SERVER}/session/{session_id}", timeout=30000)
|
||||
|
||||
if "error" in verify_status.lower() or "not found" in verify_status.lower():
|
||||
print(f"[ERROR] Worker dispatch failed for Issue #{issue.number}")
|
||||
# Retry dispatch
|
||||
session_id = dispatch_worker("issue-impl", issue_work, ref_summary)
|
||||
bash("sleep 2", timeout=5000)
|
||||
verify_status = bash(f"curl -s ${SERVER}/session/{session_id}", timeout=30000)
|
||||
if "error" in verify_status.lower() or "not found" in verify_status.lower():
|
||||
print(f"[ERROR] Retry failed - skipping Issue #{issue.number}")
|
||||
continue
|
||||
|
||||
active_issue_workers[issue.number] = session_id
|
||||
slots_available -= 1
|
||||
print(f"[{now()}] Dispatched issue worker for Issue #{issue.number} - verified active")
|
||||
|
||||
# ── Monitor active workers: poll every 10 seconds ────────────
|
||||
bash("sleep 10", timeout=30000)
|
||||
@@ -678,15 +753,30 @@ LOOP FOREVER:
|
||||
|
||||
# ── Health signal every 10 cycles ─────────────────────────────
|
||||
if cycle % 10 == 0:
|
||||
# Helper functions to format worker details
|
||||
def format_pr_workers(active_pr_workers):
|
||||
lines = []
|
||||
for pr_num, info in active_pr_workers.items():
|
||||
lines.append(f" - PR #{pr_num}: session {info['session_id'][:8]}... | type: {info['work_type']} | started: {info['assigned_at']}")
|
||||
return "\n".join(lines) if lines else " (none)"
|
||||
|
||||
def format_issue_workers(active_issue_workers):
|
||||
lines = []
|
||||
for issue_num, session_id in active_issue_workers.items():
|
||||
lines.append(f" - Issue #{issue_num}: session {session_id[:8]}...")
|
||||
return "\n".join(lines) if lines else " (none)"
|
||||
|
||||
forgejo_create_issue_comment(
|
||||
owner, repo, SESSION_STATE_ISSUE_NUMBER,
|
||||
body=f"[HEALTH] issue-implementor | Iteration: {cycle} | Status: active\n" +
|
||||
f"- Type: pool-supervisor\n" +
|
||||
f"- Max workers: {max_workers}\n" +
|
||||
f"- Total active workers: {len(active_pr_workers) + len(active_issue_workers)} / {max_workers}\n" +
|
||||
f" - PR fix workers: {len(active_pr_workers)}\n" +
|
||||
f" - Issue implementation workers: {len(active_issue_workers)}\n" +
|
||||
f"- Work completed:\n" +
|
||||
f"\nPR Fix Workers ({len(active_pr_workers)}):\n" +
|
||||
format_pr_workers(active_pr_workers) +
|
||||
f"\n\nIssue Implementation Workers ({len(active_issue_workers)}):\n" +
|
||||
format_issue_workers(active_issue_workers) +
|
||||
f"\n\n- Work completed:\n" +
|
||||
f" - PRs merged: {sum(1 for c in completed if c['type'] == 'pr')}\n" +
|
||||
f" - Issues completed: {len(completed_issues)}\n" +
|
||||
f"- Queues:\n" +
|
||||
@@ -703,6 +793,44 @@ LOOP FOREVER:
|
||||
|
||||
# ── Idle check: If no active workers and no work, wait longer ────
|
||||
total_active = len(active_pr_workers) + len(active_issue_workers)
|
||||
|
||||
# More aggressive work discovery when we have capacity
|
||||
if total_active < max_workers:
|
||||
remaining_capacity = max_workers - total_active
|
||||
print(f"[CAPACITY] {remaining_capacity} worker slots available - checking for work")
|
||||
|
||||
# Always check PRs first
|
||||
pr_work_queue = check_pr_work_needed()
|
||||
|
||||
# Then check issues if still have capacity and no PRs need work
|
||||
if not pr_work_queue and remaining_capacity > 0:
|
||||
# Re-query issues even if queue is empty
|
||||
try:
|
||||
new_issues = forgejo_list_repo_issues(
|
||||
owner, repo,
|
||||
state="open",
|
||||
labels="State/Verified,State/In Progress"
|
||||
)
|
||||
# Filter to assigned issues not already being worked on
|
||||
new_issues = [i for i in new_issues
|
||||
if FORGEJO_USERNAME in [a.login for a in i.assignees]
|
||||
and i.number not in active_issue_workers
|
||||
and i.number not in completed_issues]
|
||||
if new_issues:
|
||||
queue.extend(new_issues)
|
||||
# Re-sort by priority
|
||||
queue.sort(key=lambda i: (
|
||||
0 if "Type/Bug" in [l.name for l in i.labels] else 1,
|
||||
i.milestone.number if i.milestone else 999,
|
||||
0 if "State/In Progress" in [l.name for l in i.labels] else 1,
|
||||
{"Critical": 0, "High": 1, "Medium": 2, "Low": 3}.get(
|
||||
next((l.name.split("/")[1] for l in i.labels if l.name.startswith("Priority/")), "Medium"), 2
|
||||
)
|
||||
))
|
||||
print(f"[CAPACITY] Found {len(new_issues)} new issues to work on")
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to fetch new issues: {e}")
|
||||
|
||||
if total_active == 0 and not pr_work_queue and not queue:
|
||||
# No active workers and no pending work - idle state
|
||||
print(f"[IDLE] No active workers or pending work. Waiting 60 seconds...")
|
||||
|
||||
Reference in New Issue
Block a user