From 1ea6bf6e3369491a1f11b686ae7dee42e49d22f5 Mon Sep 17 00:00:00 2001 From: Rockachopa Date: Thu, 30 Apr 2026 06:32:30 +0000 Subject: [PATCH] STEP35-476: Integrate dispatch_router into orchestrator triage loop - Added dispatch_router.py call for agent assignment routing - Added dispatch decision logging to $LOG_DIR/dispatch_decisions.log - Fall back to 'claude' if router fails - Logs agent, score, category, reason per dispatch --- bin/timmy-orchestrator.sh | 50 ++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/bin/timmy-orchestrator.sh b/bin/timmy-orchestrator.sh index 990e83da..5607b737 100755 --- a/bin/timmy-orchestrator.sh +++ b/bin/timmy-orchestrator.sh @@ -129,20 +129,42 @@ Preserved by timmy-orchestrator to prevent loss." 2>/dev/null && git p # Auto-assignment is opt-in because silent queue mutation resurrects old state. if [ "$unassigned_count" -gt 0 ]; then if [ "$AUTO_ASSIGN_UNASSIGNED" = "1" ]; then - log "Assigning $unassigned_count issues to claude..." - while IFS= read -r line; do - local repo=$(echo "$line" | sed 's/.*REPO=\([^ ]*\).*/\1/') - local num=$(echo "$line" | sed 's/.*NUM=\([^ ]*\).*/\1/') - curl -sf -X PATCH "$GITEA_URL/api/v1/repos/$repo/issues/$num" \ - -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"assignees":["claude"]}' >/dev/null 2>&1 && \ - log " Assigned #$num ($repo) to claude" - done < "$state_dir/unassigned.txt" - else - log "Auto-assign disabled: leaving $unassigned_count unassigned issues untouched" - fi - fi + log "Assigning $unassigned_count issues via dispatch router..." + DISPATCH_LOG="$LOG_DIR/dispatch_decisions.log" + while IFS= read -r line; do + local repo=$(echo "$line" | sed 's/.*REPO=\([^ ]*\).*//') + local num=$(echo "$line" | sed 's/.*NUM=\([^ ]*\).*//') + local title=$(echo "$line" | sed 's/.*TITLE=//') + + # Call dispatch_router to pick best agent + local route_json + route_json=$(python3 "$SCRIPT_DIR/tools/dispatch_router.py" "$title" "$repo" 2>/dev/null) || route_json="" + + local recommended_agent="claude" # fallback + local route_category="unknown" + local route_score="0" + local route_reason="fallback" + + if [ -n "$route_json" ]; then + recommended_agent=$(echo "$route_json" | python3 -c "import sys,json; print(json.load(sys.stdin).get('recommended_agent','claude'))" 2>/dev/null || echo "claude") + route_score=$(echo "$route_json" | python3 -c "import sys,json; print(json.load(sys.stdin).get('score',0))" 2>/dev/null || echo "0") + route_category=$(echo "$route_json" | python3 -c "import sys,json; print(json.load(sys.stdin).get('category','unknown'))" 2>/dev/null || echo "unknown") + route_reason=$(echo "$route_json" | python3 -c "import sys,json; print(json.load(sys.stdin).get('reason',''))" 2>/dev/null || echo "") + fi + + # Assign via API + curl -sf -X PATCH "$GITEA_URL/api/v1/repos/$repo/issues/$num" \\ + -H "Authorization: token $GITEA_TOKEN" \\ + -H "Content-Type: application/json" \\ + -d "{\"assignees\":[\"$recommended_agent\"]}" >/dev/null 2>&1 && \\ + log " Assigned #$num ($repo) to $recommended_agent [score=$route_score cat=$route_category]" + + # Log dispatch decision for audit (RFC3339 timestamp) + printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \ + "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$num" "$repo" "$title" "$recommended_agent" "$route_score" "$route_category|$route_reason" \ + >> "$DISPATCH_LOG" + done < "$state_dir/unassigned.txt" + else fi # Phase 2: PR review via Timmy (LLM) if [ "$pr_count" -gt 0 ]; then