33# Response Analyzer for Ralph Wiggum
44# Intelligent exit detection through semantic analysis of Claude's responses
55
6- set -euo pipefail
6+ set -eo pipefail
77
88ANALYSIS_STATE_FILE=" ${RALPH_STATE_DIR:- .claude} /ralph-analysis.json"
99COMPLETION_CONFIDENCE_THRESHOLD=${RALPH_COMPLETION_THRESHOLD:- 40}
1010MAX_TEST_ONLY_LOOPS=${RALPH_MAX_TEST_ONLY:- 5}
1111MAX_STUCK_LOOPS=${RALPH_MAX_STUCK:- 3}
1212
13- declare -A COMPLETION_KEYWORDS=(
14- [" done" ]=10 [" complete" ]=15 [" completed" ]=15 [" finished" ]=12
15- [" success" ]=10 [" successful" ]=10 [" all tests pass" ]=20
16- [" tests passing" ]=18 [" implementation complete" ]=20
17- [" task complete" ]=20 [" project complete" ]=25
18- [" ready for review" ]=15 [" ready to deploy" ]=15
19- )
13+ # Completion keywords and their confidence scores (keyword:score format)
14+ COMPLETION_KEYWORDS=" done:10 complete:15 completed:15 finished:12 success:10 successful:10"
15+ COMPLETION_KEYWORDS=" $COMPLETION_KEYWORDS all_tests_pass:20 tests_passing:18 implementation_complete:20"
16+ COMPLETION_KEYWORDS=" $COMPLETION_KEYWORDS task_complete:20 project_complete:25 ready_for_review:15 ready_to_deploy:15"
2017
21- declare -A STUCK_KEYWORDS=(
22- [" stuck" ]=1 [" blocked" ]=1 [" cannot proceed" ]=1 [" unable to" ]=1
23- [" failed repeatedly" ]=1 [" same error" ]=1 [" infinite loop" ]=1 [" going in circles" ]=1
24- )
18+ # Stuck keywords (presence indicates stuck state)
19+ STUCK_KEYWORDS=" stuck blocked cannot_proceed unable_to failed_repeatedly same_error infinite_loop going_in_circles"
2520
2621init_response_analyzer () {
2722 [[ -f " $ANALYSIS_STATE_FILE " ]] && return
@@ -47,20 +42,25 @@ detect_completion_signals() {
4742 local output=" $1 "
4843 local output_lower=$( echo " $output " | tr ' [:upper:]' ' [:lower:]' )
4944 local confidence=0
50- local signals_found=()
51-
52- for keyword in " ${! COMPLETION_KEYWORDS[@]} " ; do
53- if echo " $output_lower " | grep -qi " $keyword " ; then
54- (( confidence += ${COMPLETION_KEYWORDS[$keyword]} )) || true
55- signals_found+=(" $keyword " )
45+ local signals_found=" "
46+
47+ # Parse keyword:score pairs
48+ for pair in $COMPLETION_KEYWORDS ; do
49+ local keyword=" ${pair%:* } "
50+ local score=" ${pair#*: } "
51+ # Convert underscores to spaces for matching
52+ local search_term=" ${keyword// _/ } "
53+ if echo " $output_lower " | grep -qi " $search_term " ; then
54+ (( confidence += score)) || true
55+ signals_found=" ${signals_found: +$signals_found ,} $keyword "
5656 fi
5757 done
5858
59- echo " $output " | grep -q " ---RALPH_STATUS---" && { (( confidence += 15 )) || true ; signals_found+=( " structured_status" ) ; }
60- echo " $output " | grep -qE ' \[DONE\]|\[COMPLETE\]|\[FINISHED\]' && { (( confidence += 20 )) || true ; signals_found+=( " explicit_marker" ) ; }
59+ echo " $output " | grep -q " ---RALPH_STATUS---" && { (( confidence += 15 )) || true ; signals_found= " ${signals_found : + $signals_found ,} structured_status" ; }
60+ echo " $output " | grep -qE ' \[DONE\]|\[COMPLETE\]|\[FINISHED\]' && { (( confidence += 20 )) || true ; signals_found= " ${signals_found : + $signals_found ,} explicit_marker" ; }
6161
62- jq -n --argjson confidence " $confidence " --arg signals " $( IFS=, ; echo " ${ signals_found[*]} " ) " \
63- ' {confidence: $confidence, signals: ($signals | split(","))}'
62+ jq -n --argjson confidence " $confidence " --arg signals " $signals_found " \
63+ ' {confidence: $confidence, signals: (if $signals == "" then [] else ($signals | split(",")) end )}'
6464}
6565
6666detect_test_only_loop () {
@@ -85,8 +85,10 @@ detect_stuck_state() {
8585 local output_lower=$( echo " $output " | tr ' [:upper:]' ' [:lower:]' )
8686 local stuck_count=0
8787
88- for keyword in " ${! STUCK_KEYWORDS[@]} " ; do
89- echo " $output_lower " | grep -qi " $keyword " && (( stuck_count++ )) || true
88+ for keyword in $STUCK_KEYWORDS ; do
89+ # Convert underscores to spaces for matching
90+ local search_term=" ${keyword// _/ } "
91+ echo " $output_lower " | grep -qi " $search_term " && (( stuck_count++ )) || true
9092 done
9193
9294 local error_mentions=$( echo " $output_lower " | grep -c " error\|failed\|exception" || echo " 0" )
0 commit comments