From d83098f382acd106f21ce316d89b6f4a374ddea0 Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 18 Mar 2026 16:24:58 +0000 Subject: [PATCH] fix: pass SESSION_NAME to all agent-session.sh function calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Library functions need explicit session name argument — they no longer have closure over $SESSION_NAME from the parent script. - agent_kill_session: add $SESSION_NAME to all 11 call sites - agent_inject_into_session: add $SESSION_NAME to all call sites in phase-handler.sh and gardener-agent.sh - agent_kill_session: guard against missing arg (defensive) --- dev/dev-agent.sh | 2 +- dev/phase-handler.sh | 36 ++++++++++++++++++------------------ gardener/gardener-agent.sh | 10 +++++----- lib/agent-session.sh | 3 ++- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/dev/dev-agent.sh b/dev/dev-agent.sh index 68d93ea..5468b7c 100755 --- a/dev/dev-agent.sh +++ b/dev/dev-agent.sh @@ -100,7 +100,7 @@ CLAIMED=false cleanup() { rm -f "$LOCKFILE" "$STATUSFILE" # Kill any live session so Claude doesn't run without an orchestrator attached - agent_kill_session + agent_kill_session "$SESSION_NAME" # If we claimed the issue but never created a PR, unclaim it if [ "$CLAIMED" = true ] && [ -z "${PR_NUMBER:-}" ]; then log "cleanup: unclaiming issue (no PR created)" diff --git a/dev/phase-handler.sh b/dev/phase-handler.sh index 649a7a8..919fec3 100644 --- a/dev/phase-handler.sh +++ b/dev/phase-handler.sh @@ -121,7 +121,7 @@ do_merge() { notify_ctx \ "✅ PR #${pr} merged! Issue #${ISSUE} done." \ "✅ PR #${pr} merged! Issue #${ISSUE} done." - agent_kill_session + agent_kill_session "$SESSION_NAME" cleanup_worktree rm -f "$PHASE_FILE" "$IMPL_SUMMARY_FILE" "$THREAD_FILE" exit 0 @@ -166,7 +166,7 @@ do_merge() { -H "Content-Type: application/json" \ "${API}/issues/${ISSUE}" -d '{"state":"closed"}' >/dev/null 2>&1 || true cleanup_labels - agent_kill_session + agent_kill_session "$SESSION_NAME" cleanup_worktree rm -f "$PHASE_FILE" "$IMPL_SUMMARY_FILE" "$THREAD_FILE" exit 0 @@ -240,13 +240,13 @@ _on_phase_change() { log "PR already exists: #${PR_NUMBER}" else log "ERROR: PR creation got 409 but no existing PR found" - agent_inject_into_session "ERROR: Could not create PR (HTTP 409, no existing PR found). Check the Codeberg API. Retry by writing PHASE:awaiting_ci again after verifying the branch was pushed." + agent_inject_into_session "$SESSION_NAME" "ERROR: Could not create PR (HTTP 409, no existing PR found). Check the Codeberg API. Retry by writing PHASE:awaiting_ci again after verifying the branch was pushed." return 0 fi else log "ERROR: PR creation failed (HTTP ${PR_HTTP_CODE})" notify "failed to create PR (HTTP ${PR_HTTP_CODE})" - agent_inject_into_session "ERROR: Could not create PR (HTTP ${PR_HTTP_CODE}). Check branch was pushed: git push origin ${BRANCH}. Then write PHASE:awaiting_ci again." + agent_inject_into_session "$SESSION_NAME" "ERROR: Could not create PR (HTTP ${PR_HTTP_CODE}). Check branch was pushed: git push origin ${BRANCH}. Then write PHASE:awaiting_ci again." return 0 fi fi @@ -254,7 +254,7 @@ _on_phase_change() { # No CI configured? Treat as success immediately if [ "${WOODPECKER_REPO_ID:-2}" = "0" ]; then log "no CI configured — treating as passed" - agent_inject_into_session "CI passed on PR #${PR_NUMBER} (no CI configured for this project). + agent_inject_into_session "$SESSION_NAME" "CI passed on PR #${PR_NUMBER} (no CI configured for this project). Write PHASE:awaiting_review to the phase file, then stop and wait for review feedback." return 0 fi @@ -290,14 +290,14 @@ Write PHASE:awaiting_review to the phase file, then stop and wait for review fee if ! $CI_DONE; then log "TIMEOUT: CI didn't complete in ${CI_POLL_TIMEOUT}s" notify "CI timeout on PR #${PR_NUMBER}" - agent_inject_into_session "CI TIMEOUT: CI did not complete within 30 minutes for PR #${PR_NUMBER} (SHA: ${CI_CURRENT_SHA:0:7}). This may be an infrastructure issue. Write PHASE:needs_human if you cannot proceed." + agent_inject_into_session "$SESSION_NAME" "CI TIMEOUT: CI did not complete within 30 minutes for PR #${PR_NUMBER} (SHA: ${CI_CURRENT_SHA:0:7}). This may be an infrastructure issue. Write PHASE:needs_human if you cannot proceed." return 0 fi log "CI: ${CI_STATE}" if [ "$CI_STATE" = "success" ]; then - agent_inject_into_session "CI passed on PR #${PR_NUMBER}. + agent_inject_into_session "$SESSION_NAME" "CI passed on PR #${PR_NUMBER}. Write PHASE:awaiting_review to the phase file, then stop and wait for review feedback: echo \"PHASE:awaiting_review\" > \"${PHASE_FILE}\"" else @@ -366,7 +366,7 @@ Write PHASE:awaiting_review to the phase file, then stop and wait for review fee "CI failed on PR #${PR_NUMBER}: step=${FAILED_STEP:-unknown} (attempt ${CI_FIX_COUNT}/${MAX_CI_FIXES})" \ "CI failed on PR #${PR_NUMBER} | Pipeline #${PIPELINE_NUM:-?}
Step: ${FAILED_STEP:-unknown} (exit ${FAILED_EXIT:-?})
Attempt ${CI_FIX_COUNT}/${MAX_CI_FIXES}
${_ci_snippet:-no logs}
" - agent_inject_into_session "CI failed on PR #${PR_NUMBER} (attempt ${CI_FIX_COUNT}/${MAX_CI_FIXES}). + agent_inject_into_session "$SESSION_NAME" "CI failed on PR #${PR_NUMBER} (attempt ${CI_FIX_COUNT}/${MAX_CI_FIXES}). Failed step: ${FAILED_STEP:-unknown} (exit code ${FAILED_EXIT:-?}, pipeline #${PIPELINE_NUM:-?}) @@ -401,7 +401,7 @@ Instructions: PR_NUMBER="$FOUND_PR" log "found PR #${PR_NUMBER}" else - agent_inject_into_session "ERROR: Cannot find open PR for branch ${BRANCH}. Did you push? Verify with git status and git push origin ${BRANCH}, then write PHASE:awaiting_ci." + agent_inject_into_session "$SESSION_NAME" "ERROR: Cannot find open PR for branch ${BRANCH}. Did you push? Verify with git status and git push origin ${BRANCH}, then write PHASE:awaiting_ci." return 0 fi fi @@ -473,7 +473,7 @@ Instructions: if [ "$VERDICT" = "APPROVE" ]; then REVIEW_FOUND=true - agent_inject_into_session "Approved! PR #${PR_NUMBER} has been approved by the reviewer. + agent_inject_into_session "$SESSION_NAME" "Approved! PR #${PR_NUMBER} has been approved by the reviewer. Write PHASE:done to the phase file — the orchestrator will handle the merge: echo \"PHASE:done\" > \"${PHASE_FILE}\"" break @@ -485,7 +485,7 @@ Write PHASE:done to the phase file — the orchestrator will handle the merge: notify "PR #${PR_NUMBER}: hit ${MAX_REVIEW_ROUNDS} review rounds, needs human attention" fi REVIEW_FOUND=true - agent_inject_into_session "Review feedback (round ${REVIEW_ROUND}) on PR #${PR_NUMBER}: + agent_inject_into_session "$SESSION_NAME" "Review feedback (round ${REVIEW_ROUND}) on PR #${PR_NUMBER}: ${REVIEW_TEXT} @@ -520,7 +520,7 @@ Instructions: -H "Content-Type: application/json" \ "${API}/issues/${ISSUE}" -d '{"state":"closed"}' >/dev/null 2>&1 || true cleanup_labels - agent_kill_session + agent_kill_session "$SESSION_NAME" cleanup_worktree rm -f "$PHASE_FILE" "$IMPL_SUMMARY_FILE" "$THREAD_FILE" exit 0 @@ -528,7 +528,7 @@ Instructions: log "PR #${PR_NUMBER} was closed WITHOUT merge — NOT closing issue" notify "⚠️ PR #${PR_NUMBER} closed without merge. Issue #${ISSUE} remains open." cleanup_labels - agent_kill_session + agent_kill_session "$SESSION_NAME" cleanup_worktree exit 0 fi @@ -540,7 +540,7 @@ Instructions: if ! $REVIEW_FOUND && [ "$REVIEW_POLL_ELAPSED" -ge "$REVIEW_POLL_TIMEOUT" ]; then log "TIMEOUT: no review after 3h" notify "no review received for PR #${PR_NUMBER} after 3h" - agent_inject_into_session "TIMEOUT: No review received after 3 hours for PR #${PR_NUMBER}. Write PHASE:needs_human to escalate to a human reviewer." + agent_inject_into_session "$SESSION_NAME" "TIMEOUT: No review received after 3 hours for PR #${PR_NUMBER}. Write PHASE:needs_human to escalate to a human reviewer." fi # ── PHASE: needs_human ────────────────────────────────────────────────────── @@ -563,7 +563,7 @@ Instructions: if [ -z "${PR_NUMBER:-}" ]; then log "ERROR: PHASE:done but no PR_NUMBER — cannot merge" notify "PHASE:done but no PR known — needs human attention" - agent_kill_session + agent_kill_session "$SESSION_NAME" cleanup_labels return 1 fi @@ -576,7 +576,7 @@ Instructions: # If we reach here, merge failed (do_merge returned 1) log "merge failed — injecting error into session" - agent_inject_into_session "Merge failed for PR #${PR_NUMBER}. The orchestrator could not merge automatically. This may be due to merge conflicts or CI. Investigate the PR state and write PHASE:needs_human if human intervention is required." + agent_inject_into_session "$SESSION_NAME" "Merge failed for PR #${PR_NUMBER}. The orchestrator could not merge automatically. This may be due to merge conflicts or CI. Investigate the PR state and write PHASE:needs_human if human intervention is required." # ── PHASE: failed ─────────────────────────────────────────────────────────── elif [ "$phase" = "PHASE:failed" ]; then @@ -663,7 +663,7 @@ $(printf '%s' "$REFUSAL_JSON" | head -c 2000) esac CLAIMED=false # Don't unclaim again in cleanup() - agent_kill_session + agent_kill_session "$SESSION_NAME" cleanup_worktree rm -f "$PHASE_FILE" "$IMPL_SUMMARY_FILE" "$THREAD_FILE" return 1 @@ -686,7 +686,7 @@ $(printf '%s' "$REFUSAL_JSON" | head -c 2000) -d '{"labels":["backlog"]}' >/dev/null 2>&1 || true CLAIMED=false # Don't unclaim again in cleanup() - agent_kill_session + agent_kill_session "$SESSION_NAME" if [ -n "${PR_NUMBER:-}" ]; then log "keeping worktree (PR #${PR_NUMBER} still open)" else diff --git a/gardener/gardener-agent.sh b/gardener/gardener-agent.sh index 44cfbd7..bb41ed2 100644 --- a/gardener/gardener-agent.sh +++ b/gardener/gardener-agent.sh @@ -277,7 +277,7 @@ On unrecoverable error: printf 'PHASE:failed\nReason: %s\n' 'describe error' > '${PHASE_FILE}'" # ── Reset phase + result files ──────────────────────────────────────────── -agent_kill_session +agent_kill_session "$SESSION_NAME" rm -f "$PHASE_FILE" "$RESULT_FILE" touch "$RESULT_FILE" @@ -288,7 +288,7 @@ if ! create_agent_session "$SESSION_NAME" "$PROJECT_REPO_ROOT"; then exit 1 fi -agent_inject_into_session "$PROMPT" +agent_inject_into_session "$SESSION_NAME" "$PROMPT" log "Prompt sent to tmux session" matrix_send "gardener" "🌱 Gardener session started for ${CODEBERG_REPO}" 2>/dev/null || true @@ -332,7 +332,7 @@ Re-run your analysis from scratch: rm -f "$RESULT_FILE" touch "$RESULT_FILE" if create_agent_session "$SESSION_NAME" "$PROJECT_REPO_ROOT" 2>/dev/null; then - agent_inject_into_session "$RECOVERY_MSG" + agent_inject_into_session "$SESSION_NAME" "$RECOVERY_MSG" log "Recovery session started" IDLE_ELAPSED=0 else @@ -353,7 +353,7 @@ Re-run your analysis from scratch: if [ "$IDLE_ELAPSED" -ge "$MAX_RUNTIME" ]; then log "TIMEOUT: gardener session idle for ${MAX_RUNTIME}s — killing" matrix_send "gardener" "⚠️ Gardener session timed out after ${MAX_RUNTIME}s" 2>/dev/null || true - agent_kill_session + agent_kill_session "$SESSION_NAME" break fi continue @@ -365,7 +365,7 @@ Re-run your analysis from scratch: log "phase: ${CURRENT_PHASE}" if [ "$CURRENT_PHASE" = "PHASE:done" ] || [ "$CURRENT_PHASE" = "PHASE:failed" ]; then - agent_kill_session + agent_kill_session "$SESSION_NAME" break fi done diff --git a/lib/agent-session.sh b/lib/agent-session.sh index bbb4eac..31edede 100644 --- a/lib/agent-session.sh +++ b/lib/agent-session.sh @@ -60,5 +60,6 @@ inject_formula() { # Kill a tmux session gracefully (no-op if not found). agent_kill_session() { - tmux kill-session -t "$1" 2>/dev/null || true + local session="${1:-}" + [ -n "$session" ] && tmux kill-session -t "$session" 2>/dev/null || true }