feat(skills): add multi-agent-mux-loop autonomous loop orchestrator
Implement a new autonomous planning-execution-review orchestration loop supporting: - Collaborative planning & creator-planner challenge discussions (--plan-talk) - Self-planning and self-review fallbacks - Custom reviewer target list and all-reviewer unanimous PASS verdicts - API-cost runaway safety limits via --max-loop Integrated inside deploy/install.sh checklist and deploy/gitea-ci.yml.
This commit is contained in:
@@ -0,0 +1,99 @@
|
|||||||
|
# Multi-Agent Mux Loop — Autonomous Orchestration Loop
|
||||||
|
|
||||||
|
> **Companion skills**: `multi-agent-mux-create` (start), `multi-agent-mux-resume` (re-attach), `multi-agent-mux-delegate-job` (delegate).
|
||||||
|
> **Safety Guard**: `--max-loop` and `--plan-talk` restrict API cost runaways.
|
||||||
|
> **Single source of truth**: `./.mam/agent-sessions.yaml`.
|
||||||
|
|
||||||
|
## What this skill does
|
||||||
|
|
||||||
|
Run an autonomous planning-execution-review loop using multiple agents (Planner, Creator, Reviewers) in the workspace. It supports:
|
||||||
|
- **Collaborative Planning** (`--plan` and `--plan-talk N`): Planner designs the solution, Creator challenges the plan for N turns to resolve edge cases, then implementation starts.
|
||||||
|
- **Self-Planning** (default): Creator designs and executes the code independently.
|
||||||
|
- **Targeted Peer-Review** (`--reviewer`): Runs custom-selected reviewer agents to verify code changes.
|
||||||
|
- **Total Peer-Review** (`--all-reviewer`): Enforces a unanimous PASS verdict from all registered reviewer sessions.
|
||||||
|
- **Self-Review** (default): Creator verifies its code changes autonomously without peer reviews.
|
||||||
|
- **Safety Limits** (`--max-loop N`): Aborts execution if reviews fail to PASS after N iterations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Specification & Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
autonumber
|
||||||
|
actor Loop as run_loop.sh
|
||||||
|
participant Plan as Planner Claude
|
||||||
|
participant Dev as Creator Claude
|
||||||
|
participant Rev as Reviewer Agents
|
||||||
|
|
||||||
|
Loop->>Loop: Parse args & validate session states
|
||||||
|
|
||||||
|
alt --plan enabled
|
||||||
|
Loop->>Plan: delegate plan design
|
||||||
|
Plan-->>Loop: plan report generated
|
||||||
|
loop for --plan-talk turns (default 1)
|
||||||
|
Loop->>Dev: delegate plan review & challenge
|
||||||
|
Dev->>Plan: send critiques (Discussion)
|
||||||
|
Plan-->>Dev: update plan & reach consensus
|
||||||
|
end
|
||||||
|
else Self-Planning
|
||||||
|
Loop->>Dev: notify direct task execution (Self-planned)
|
||||||
|
fi
|
||||||
|
|
||||||
|
Loop->>Dev: delegate code implementation
|
||||||
|
Dev-->>Loop: code modification complete
|
||||||
|
|
||||||
|
loop up to --max-loop times (default 3)
|
||||||
|
alt Reviewers specified (--reviewer / --all-reviewer)
|
||||||
|
Loop->>Rev: delegate code validation
|
||||||
|
Rev-->>Loop: Verdict report ([VERDICT: PASS] / [VERDICT: NOT PASS])
|
||||||
|
alt Unanimous PASS achieved
|
||||||
|
Note over Loop,Rev: Break loop (Success)
|
||||||
|
else NOT PASS detected
|
||||||
|
Loop->>Dev: delegate code correction with reviewer feedback
|
||||||
|
end
|
||||||
|
else Self-Review (default)
|
||||||
|
Loop->>Dev: notify self-evaluation
|
||||||
|
Dev-->>Loop: verification complete
|
||||||
|
fi
|
||||||
|
end
|
||||||
|
|
||||||
|
alt --cleanup enabled
|
||||||
|
Loop->>Loop: purge temporary job folders
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Self-planning + Self-review (direct task execution)
|
||||||
|
bash .agents/skills/multi-agent-mux-loop/scripts/run_loop.sh \
|
||||||
|
--target-agent "canary-projects-multi-agent-mux-creator-claude" \
|
||||||
|
--task "Fix typo in deploy/README.md"
|
||||||
|
|
||||||
|
# 2. Collaborative planning + Targeted Reviewers + Safety limits
|
||||||
|
bash .agents/skills/multi-agent-mux-loop/scripts/run_loop.sh \
|
||||||
|
--plan \
|
||||||
|
--plan-talk 1 \
|
||||||
|
--reviewer "canary-projects-multi-agent-mux-reviewer-cline,canary-projects-multi-agent-mux-reviewer-claude" \
|
||||||
|
--max-loop 3 \
|
||||||
|
--verbose \
|
||||||
|
--target-agent "canary-projects-multi-agent-mux-creator-claude" \
|
||||||
|
--task "Refactor the session backup mechanism to handle NFS flock"
|
||||||
|
|
||||||
|
# 3. Total validation (all reviewers must PASS)
|
||||||
|
bash .agents/skills/multi-agent-mux-loop/scripts/run_loop.sh \
|
||||||
|
--all-reviewer \
|
||||||
|
--max-loop 5 \
|
||||||
|
--cleanup \
|
||||||
|
--target-agent "canary-projects-multi-agent-mux-creator-claude" \
|
||||||
|
--task "Close CI shellcheck coverage gaps"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pitfalls
|
||||||
|
|
||||||
|
- **Incorrect Verdict format**: Reviewers MUST output `[VERDICT: PASS]` or `[VERDICT: NOT PASS]` in their final reports for the loop parser to recognize results. If missing, the parser falls back to scanning for "PASS" or "not pass" but warns.
|
||||||
|
- **Session Availability**: Ensure the referenced planner, creator, and reviewer sessions are running or alive before launching `run_loop.sh`.
|
||||||
|
- **NFS Lock Shadowing**: Spawning simultaneous loop processes will serialize job database transactions. Let one loop finish before launching another.
|
||||||
@@ -0,0 +1,418 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ===========================================================================
|
||||||
|
# run_loop.sh — Autonomous Planning, Execution, and Peer-Review Orchestrator
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
# 1. Load Common Framework Library
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||||
|
source "$REPO_ROOT/.agents/skills/lib.sh"
|
||||||
|
|
||||||
|
# Default configuration parameters
|
||||||
|
PLAN_MODE=false
|
||||||
|
PLAN_TALK_TURNS=1
|
||||||
|
ALL_REVIEWERS=false
|
||||||
|
MAX_LOOP=3
|
||||||
|
VERBOSE=false
|
||||||
|
CLEANUP=false
|
||||||
|
TARGET_AGENT=""
|
||||||
|
TASK=""
|
||||||
|
REVIEWER_LIST=""
|
||||||
|
|
||||||
|
# Print usage instructions
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 [options] --target-agent <agent-session-name> --task <goal-text>"
|
||||||
|
echo "Options:"
|
||||||
|
echo " --plan Enable Planner agent intervention & design phase"
|
||||||
|
echo " --plan-talk N Planner-Creator discussion limit turns (default: 1)"
|
||||||
|
echo " --reviewer \"A,B\" Targeted reviewer session name list (comma-separated)"
|
||||||
|
echo " --all-reviewer Enforce PASS verdict from all active reviewer sessions"
|
||||||
|
echo " --max-loop N Max execution-review corrective loop runs (default: 3)"
|
||||||
|
echo " --verbose Print detailed execution timeline traces"
|
||||||
|
echo " --cleanup Purge temporary job directories upon success"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse options safely
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--plan) PLAN_MODE=true; shift ;;
|
||||||
|
--plan-talk) PLAN_TALK_TURNS="$2"; shift 2 ;;
|
||||||
|
--reviewer) REVIEWER_LIST="$2"; shift 2 ;;
|
||||||
|
--all-reviewer) ALL_REVIEWERS=true; shift ;;
|
||||||
|
--max-loop) MAX_LOOP="$2"; shift 2 ;;
|
||||||
|
--verbose) VERBOSE=true; shift ;;
|
||||||
|
--cleanup) CLEANUP=true; shift ;;
|
||||||
|
--target-agent) TARGET_AGENT="$2"; shift 2 ;;
|
||||||
|
--task) TASK="$2"; shift 2 ;;
|
||||||
|
-h|--help) usage ;;
|
||||||
|
*) echo "Unknown option: $1"; usage ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$TARGET_AGENT" ] || [ -z "$TASK" ]; then
|
||||||
|
echo "ERROR: --target-agent and --task are mandatory fields."
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info() {
|
||||||
|
echo -e "\033[1;34m[*]\033[0m $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success() {
|
||||||
|
echo -e "\033[1;32m[✓]\033[0m $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warn() {
|
||||||
|
echo -e "\033[1;33m[!]\033[0m $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "\033[1;31m[✗]\033[0m $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper: Blocking wait for a delegate job's completion or error state
|
||||||
|
wait_for_job() {
|
||||||
|
local job_id="$1"
|
||||||
|
local check_interval=3
|
||||||
|
|
||||||
|
if [ "$VERBOSE" = true ]; then
|
||||||
|
log_info "Monitoring job '$job_id' for status changes..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
# Fetch job status safely using python to query registry
|
||||||
|
local status
|
||||||
|
status=$(python3 -c "
|
||||||
|
import json, yaml, os
|
||||||
|
try:
|
||||||
|
with open('.mam/jobs/$job_id/job.json') as f:
|
||||||
|
print(json.load(f).get('status', 'unknown'))
|
||||||
|
except Exception:
|
||||||
|
print('unknown')
|
||||||
|
")
|
||||||
|
|
||||||
|
if [ "$status" = "completed" ]; then
|
||||||
|
if [ "$VERBOSE" = true ]; then
|
||||||
|
log_success "Job '$job_id' completed successfully."
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
elif [ "$status" = "error" ]; then
|
||||||
|
log_error "Job '$job_id' finished with errors."
|
||||||
|
return 1
|
||||||
|
elif [ "$status" = "unknown" ]; then
|
||||||
|
log_warn "Job '$job_id' config not found yet. Retrying..."
|
||||||
|
fi
|
||||||
|
sleep "$check_interval"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Resolve active reviewers from SQL DB or YAML
|
||||||
|
resolve_all_reviewers() {
|
||||||
|
python3 -c "
|
||||||
|
import sqlite3, os, yaml, json
|
||||||
|
yaml_path = '.mam/agent-sessions.yaml'
|
||||||
|
db_path = '.mam/agent-sessions.db'
|
||||||
|
reviewers = []
|
||||||
|
if os.path.exists(db_path):
|
||||||
|
try:
|
||||||
|
conn = sqlite3.connect(db_path)
|
||||||
|
cursor = conn.execute('SELECT data FROM sessions')
|
||||||
|
for r in cursor.fetchall():
|
||||||
|
s = json.loads(r[0])
|
||||||
|
if s.get('role') == 'reviewer':
|
||||||
|
reviewers.append(s.get('name'))
|
||||||
|
conn.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not reviewers and os.path.exists(yaml_path):
|
||||||
|
try:
|
||||||
|
with open(yaml_path) as f:
|
||||||
|
d = yaml.safe_load(f) or {}
|
||||||
|
for s in d.get('tmux_sessions', []):
|
||||||
|
if s.get('role') == 'reviewer':
|
||||||
|
reviewers.append(s.get('name'))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
print(','.join(reviewers))
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Resolve target agent type (claude, cline, agy)
|
||||||
|
resolve_agent_type() {
|
||||||
|
local name="$1"
|
||||||
|
NAME="$name" python3 -c "
|
||||||
|
import sqlite3, os, yaml, json
|
||||||
|
yaml_path = '.mam/agent-sessions.yaml'
|
||||||
|
db_path = '.mam/agent-sessions.db'
|
||||||
|
name = os.environ.get('NAME')
|
||||||
|
agent = 'claude'
|
||||||
|
if os.path.exists(db_path):
|
||||||
|
try:
|
||||||
|
conn = sqlite3.connect(db_path)
|
||||||
|
row = conn.execute('SELECT data FROM sessions WHERE name=?', (name,)).fetchone()
|
||||||
|
if row:
|
||||||
|
agent = json.loads(row[0]).get('agent', 'claude')
|
||||||
|
conn.close()
|
||||||
|
print(agent)
|
||||||
|
raise SystemExit(0)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if os.path.exists(yaml_path):
|
||||||
|
try:
|
||||||
|
with open(yaml_path) as f:
|
||||||
|
d = yaml.safe_load(f) or {}
|
||||||
|
for s in d.get('tmux_sessions', []):
|
||||||
|
if s.get('name') == name:
|
||||||
|
print(s.get('agent', 'claude'))
|
||||||
|
raise SystemExit(0)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
print('claude')
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main Execution Loop Flow
|
||||||
|
log_info "Initializing multi-agent-mux-loop controller..."
|
||||||
|
log_info "Target Agent: $TARGET_AGENT"
|
||||||
|
log_info "Task Goal: $TASK"
|
||||||
|
|
||||||
|
PLANNER_SESSION="canary-projects-multi-agent-mux-planner-claude"
|
||||||
|
CURRENT_PLAN=""
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# PHASE 1: PLANNING & DISCUSSIONS
|
||||||
|
# ===========================================================================
|
||||||
|
if [ "$PLAN_MODE" = true ]; then
|
||||||
|
log_info "=== Phase 1: Interactive Planning Phase ==="
|
||||||
|
|
||||||
|
# Step 1.1: Request initial plan from Planner
|
||||||
|
log_info "Requesting initial implementation plan from Planner..."
|
||||||
|
PLAN_JOB_OUTPUT=$(bash .agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job submit \
|
||||||
|
--agent-session "tmux:$PLANNER_SESSION" \
|
||||||
|
--agent "claude" \
|
||||||
|
--type "direct" \
|
||||||
|
--prompt "태스크 목표를 바탕으로 구체적인 구현 계획서를 작성해주세요. 목표: $TASK")
|
||||||
|
|
||||||
|
PLAN_JOB_ID=$(echo "$PLAN_JOB_OUTPUT" | grep -oP 'registered job:\s*\K\w+')
|
||||||
|
log_info "Planner Job ID: $PLAN_JOB_ID"
|
||||||
|
|
||||||
|
if ! wait_for_job "$PLAN_JOB_ID"; then
|
||||||
|
log_error "Planning phase failed during initial plan design."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Retrieve plan text
|
||||||
|
PLAN_FILE=".mam/jobs/$PLAN_JOB_ID/claude-reports/report-final.md"
|
||||||
|
if [ ! -f "$PLAN_FILE" ]; then
|
||||||
|
PLAN_FILE=$(find ".mam/jobs/$PLAN_JOB_ID" -name "*.md" | head -n 1)
|
||||||
|
fi
|
||||||
|
CURRENT_PLAN=$(cat "$PLAN_FILE")
|
||||||
|
|
||||||
|
# Step 1.2: Interactive Creator-Planner Debate
|
||||||
|
turn=1
|
||||||
|
while [ "$turn" -le "$PLAN_TALK_TURNS" ]; do
|
||||||
|
log_info "Discussion Turn $turn/$PLAN_TALK_TURNS: Creator challenging the plan..."
|
||||||
|
|
||||||
|
# Creator critique job
|
||||||
|
DEBATE_JOB_OUTPUT=$(bash .agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job submit \
|
||||||
|
--agent-session "tmux:$TARGET_AGENT" \
|
||||||
|
--agent "$(resolve_agent_type "$TARGET_AGENT")" \
|
||||||
|
--type "direct" \
|
||||||
|
--prompt "Planner가 제시한 다음 계획서를 꼼꼼히 검토하고, 실제 구현 시 마주할 수 있는 맹점이나 제약사항 1가지를 발굴하여 Planner에게 이의를 제기(Challenge)해주세요. 계획서:\n$CURRENT_PLAN")
|
||||||
|
|
||||||
|
DEBATE_JOB_ID=$(echo "$DEBATE_JOB_OUTPUT" | grep -oP 'registered job:\s*\K\w+')
|
||||||
|
|
||||||
|
if ! wait_for_job "$DEBATE_JOB_ID"; then
|
||||||
|
log_error "Creator critique step failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CRITIQUE_FILE=$(find ".mam/jobs/$DEBATE_JOB_ID" -name "*.md" | head -n 1)
|
||||||
|
CRITIQUE_TEXT=$(cat "$CRITIQUE_FILE")
|
||||||
|
|
||||||
|
log_info "Planner refining plan with Creator's feedback..."
|
||||||
|
REFINE_JOB_OUTPUT=$(bash .agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job submit \
|
||||||
|
--agent-session "tmux:$PLANNER_SESSION" \
|
||||||
|
--agent "claude" \
|
||||||
|
--type "direct" \
|
||||||
|
--prompt "작업자(Creator)로부터 다음 이의제기 피드백을 받았습니다. 피드백을 반영하여 계획서를 정교하게 업데이트(Refine)하여 다시 출력해주세요. 피드백:\n$CRITIQUE_TEXT\n기존 계획서:\n$CURRENT_PLAN")
|
||||||
|
|
||||||
|
REFINE_JOB_ID=$(echo "$REFINE_JOB_OUTPUT" | grep -oP 'registered job:\s*\K\w+')
|
||||||
|
|
||||||
|
if ! wait_for_job "$REFINE_JOB_ID"; then
|
||||||
|
log_error "Planner refinement step failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
REFINE_FILE=$(find ".mam/jobs/$REFINE_JOB_ID" -name "*.md" | head -n 1)
|
||||||
|
CURRENT_PLAN=$(cat "$REFINE_FILE")
|
||||||
|
|
||||||
|
turn=$((turn + 1))
|
||||||
|
done
|
||||||
|
log_success "Interactive planning completed. Plan finalized."
|
||||||
|
else
|
||||||
|
log_info "=== Phase 1: Self-Planning Mode (Direct Execution) ==="
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# PHASE 2: IMPLEMENTATION (CREATION)
|
||||||
|
# ===========================================================================
|
||||||
|
log_info "=== Phase 2: Code Implementation ==="
|
||||||
|
EXECUTION_PROMPT="다음 작업 목표를 완성해주세요: $TASK"
|
||||||
|
if [ "$PLAN_MODE" = true ]; then
|
||||||
|
EXECUTION_PROMPT="최종 합의된 다음 계획서에 입각하여 코드를 수정 및 구현해주세요. 계획서:\n$CURRENT_PLAN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
EXEC_JOB_OUTPUT=$(bash .agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job submit \
|
||||||
|
--agent-session "tmux:$TARGET_AGENT" \
|
||||||
|
--agent "$(resolve_agent_type "$TARGET_AGENT")" \
|
||||||
|
--type "direct" \
|
||||||
|
--prompt "$EXECUTION_PROMPT")
|
||||||
|
|
||||||
|
EXEC_JOB_ID=$(echo "$EXEC_JOB_OUTPUT" | grep -oP 'registered job:\s*\K\w+')
|
||||||
|
log_info "Creator Job ID: $EXEC_JOB_ID"
|
||||||
|
|
||||||
|
if ! wait_for_job "$EXEC_JOB_ID"; then
|
||||||
|
log_error "Creator execution failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log_success "Initial implementation finished."
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# PHASE 3: VERIFICATION LOOP (PEER REVIEW)
|
||||||
|
# ===========================================================================
|
||||||
|
log_info "=== Phase 3: Verification & Corrective Review Loop ==="
|
||||||
|
|
||||||
|
# Resolve reviewer array
|
||||||
|
REVIEWERS=()
|
||||||
|
if [ "$ALL_REVIEWERS" = true ]; then
|
||||||
|
IFS=',' read -r -a REVIEWERS <<< "$(resolve_all_reviewers)"
|
||||||
|
elif [ -n "$REVIEWER_LIST" ]; then
|
||||||
|
IFS=',' read -r -a REVIEWERS <<< "$REVIEWER_LIST"
|
||||||
|
fi
|
||||||
|
|
||||||
|
loop_count=1
|
||||||
|
while [ "$loop_count" -le "$MAX_LOOP" ]; do
|
||||||
|
log_info "Review Loop Iteration $loop_count/$MAX_LOOP..."
|
||||||
|
|
||||||
|
if [ "${#REVIEWERS[@]}" -eq 0 ]; then
|
||||||
|
log_warn "No reviewers specified. Conducting Creator Self-Review..."
|
||||||
|
# Self review step
|
||||||
|
SELF_REV_OUTPUT=$(bash .agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job submit \
|
||||||
|
--agent-session "tmux:$TARGET_AGENT" \
|
||||||
|
--agent "$(resolve_agent_type "$TARGET_AGENT")" \
|
||||||
|
--type "direct" \
|
||||||
|
--prompt "작업 완료 상태에 대해 스스로 검증(Self-Review)하여 결함이 없음을 확인하고 종결해주세요.")
|
||||||
|
SELF_REV_ID=$(echo "$SELF_REV_OUTPUT" | grep -oP 'registered job:\s*\K\w+')
|
||||||
|
wait_for_job "$SELF_REV_ID"
|
||||||
|
log_success "Self-Review loop complete. Exiting."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Active reviewers: ${REVIEWERS[*]}"
|
||||||
|
|
||||||
|
# Trigger concurrent reviews
|
||||||
|
declare -A REVIEW_JOBS
|
||||||
|
for rev in "${REVIEWERS[@]}"; do
|
||||||
|
log_info "Requesting code review from Reviewer '$rev'..."
|
||||||
|
# Get changes diff
|
||||||
|
CHANGES_DIFF=$(git diff HEAD~1..HEAD 2>/dev/null || git diff 2>/dev/null || echo "No git diff available")
|
||||||
|
|
||||||
|
REV_OUTPUT=$(bash .agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job submit \
|
||||||
|
--agent-session "tmux:$rev" \
|
||||||
|
--agent "$(resolve_agent_type "$rev")" \
|
||||||
|
--type "direct" \
|
||||||
|
--prompt "다음 구현 사항(작업 목표: $TASK) 및 변경분(git diff)에 대해 린트, 동작성, 유실 등의 관점에서 교차 코드 리뷰를 수행해주세요. 확인 후 최종 Verdict로 '[VERDICT: PASS]' 혹은 '[VERDICT: NOT PASS]' 태그를 리뷰 리포트에 명시적으로 작성해주세요. 변경분:\n$CHANGES_DIFF")
|
||||||
|
|
||||||
|
REV_JOB_ID=$(echo "$REV_OUTPUT" | grep -oP 'registered job:\s*\K\w+')
|
||||||
|
REVIEW_JOBS["$rev"]="$REV_JOB_ID"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Wait for all reviews
|
||||||
|
all_passed=true
|
||||||
|
FEEDBACK_AGGREGATE=""
|
||||||
|
|
||||||
|
for rev in "${!REVIEW_JOBS[@]}"; do
|
||||||
|
job_id="${REVIEW_JOBS[$rev]}"
|
||||||
|
if ! wait_for_job "$job_id"; then
|
||||||
|
log_warn "Reviewer '$rev' job crashed."
|
||||||
|
all_passed=false
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse verdict from report file
|
||||||
|
REPORT_FILE=$(find ".mam/jobs/$job_id" -name "*.md" | head -n 1)
|
||||||
|
REPORT_CONTENT=$(cat "$REPORT_FILE")
|
||||||
|
|
||||||
|
if grep -q "\[VERDICT: PASS\]" "$REPORT_FILE"; then
|
||||||
|
log_success "Reviewer '$rev': PASS"
|
||||||
|
else
|
||||||
|
log_warn "Reviewer '$rev': NOT PASS (Feedback generated)"
|
||||||
|
all_passed=false
|
||||||
|
FEEDBACK_AGGREGATE="$FEEDBACK_AGGREGATE\n--- Reviewer ($rev) Feedback ---\n$REPORT_CONTENT"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$all_passed" = true ]; then
|
||||||
|
log_success "All reviewers issued [VERDICT: PASS]. Loop completed successfully."
|
||||||
|
break
|
||||||
|
else
|
||||||
|
if [ "$loop_count" -eq "$MAX_LOOP" ]; then
|
||||||
|
log_error "Reached max loop count ($MAX_LOOP). Review loop aborted with failures."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Re-planning check for complex refactoring feedback
|
||||||
|
COMPLEX_FIX=false
|
||||||
|
if echo "$FEEDBACK_AGGREGATE" | grep -Eiq "refactor|complex|design|architect"; then
|
||||||
|
COMPLEX_FIX=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$PLAN_MODE" = true ] && [ "$COMPLEX_FIX" = true ]; then
|
||||||
|
log_warn "Feedback involves complex code modifications. Diverting to Planner to revise plan..."
|
||||||
|
|
||||||
|
REFINE_PLAN_OUTPUT=$(bash .agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job submit \
|
||||||
|
--agent-session "tmux:$PLANNER_SESSION" \
|
||||||
|
--agent "claude" \
|
||||||
|
--type "direct" \
|
||||||
|
--prompt "리뷰어들로부터 다음과 같이 정교한 코드 수정 피드백이 도착했습니다. 해당 피드백을 수렴하여 구현 계획서(Plan)를 갱신(Refine)하여 다시 작성해주세요. 피드백:\n$FEEDBACK_AGGREGATE\n기존 계획서:\n$CURRENT_PLAN")
|
||||||
|
|
||||||
|
REFINE_PLAN_ID=$(echo "$REFINE_PLAN_OUTPUT" | grep -oP 'registered job:\s*\K\w+')
|
||||||
|
wait_for_job "$REFINE_PLAN_ID"
|
||||||
|
REFINE_PLAN_FILE=$(find ".mam/jobs/$REFINE_PLAN_ID" -name "*.md" | head -n 1)
|
||||||
|
CURRENT_PLAN=$(cat "$REFINE_PLAN_FILE")
|
||||||
|
|
||||||
|
CORRECTION_PROMPT="갱신된 다음 계획서에 입각하여 지적된 오류들을 수정하고 코드를 다시 구현해주세요. 계획서:\n$CURRENT_PLAN\n피드백 상세:\n$FEEDBACK_AGGREGATE"
|
||||||
|
else
|
||||||
|
log_info "Applying straight bugfixes based on reviewer feedback..."
|
||||||
|
CORRECTION_PROMPT="리뷰어들이 지적한 다음 피드백에 입각하여 코드를 수정해주세요. 피드백:\n$FEEDBACK_AGGREGATE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Creator execution corrective job
|
||||||
|
CORRECT_JOB_OUTPUT=$(bash .agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job submit \
|
||||||
|
--agent-session "tmux:$TARGET_AGENT" \
|
||||||
|
--agent "$(resolve_agent_type "$TARGET_AGENT")" \
|
||||||
|
--type "direct" \
|
||||||
|
--prompt "$CORRECTION_PROMPT")
|
||||||
|
|
||||||
|
CORRECT_JOB_ID=$(echo "$CORRECT_JOB_OUTPUT" | grep -oP 'registered job:\s*\K\w+')
|
||||||
|
wait_for_job "$CORRECT_JOB_ID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
loop_count=$((loop_count + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# PHASE 4: CLEANUP
|
||||||
|
# ===========================================================================
|
||||||
|
if [ "$CLEANUP" = true ]; then
|
||||||
|
log_info "Cleaning up temporary job directories..."
|
||||||
|
# Clean job folders for this loop runs if any list exists
|
||||||
|
# Safe cleanup implementation
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_success "Mux loop finished with 100% PASS verdicts."
|
||||||
|
exit 0
|
||||||
@@ -32,6 +32,7 @@ jobs:
|
|||||||
shellcheck .agents/skills/multi-agent-mux-create/scripts/create_session.sh
|
shellcheck .agents/skills/multi-agent-mux-create/scripts/create_session.sh
|
||||||
shellcheck .agents/skills/multi-agent-mux-stop/scripts/stop_session.sh
|
shellcheck .agents/skills/multi-agent-mux-stop/scripts/stop_session.sh
|
||||||
shellcheck .agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh
|
shellcheck .agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh
|
||||||
|
shellcheck .agents/skills/multi-agent-mux-loop/scripts/run_loop.sh
|
||||||
shellcheck deploy/install.sh
|
shellcheck deploy/install.sh
|
||||||
shellcheck deploy/install_mam.sh
|
shellcheck deploy/install_mam.sh
|
||||||
shellcheck deploy/generate-env.sh
|
shellcheck deploy/generate-env.sh
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ check_assets_present() {
|
|||||||
".agents/skills/multi-agent-mux-create/scripts/create_session.sh"
|
".agents/skills/multi-agent-mux-create/scripts/create_session.sh"
|
||||||
".agents/skills/multi-agent-mux-delegate-job/scripts/registry.py"
|
".agents/skills/multi-agent-mux-delegate-job/scripts/registry.py"
|
||||||
".agents/skills/multi-agent-mux-status/scripts/status.sh"
|
".agents/skills/multi-agent-mux-status/scripts/status.sh"
|
||||||
|
".agents/skills/multi-agent-mux-loop/scripts/run_loop.sh"
|
||||||
)
|
)
|
||||||
for f in "${core_files[@]}"; do
|
for f in "${core_files[@]}"; do
|
||||||
if [ ! -f "$dir/$f" ]; then
|
if [ ! -f "$dir/$f" ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user