fix(grok): self-healing embed fallback for review modes

If a grok read_file-based review (review/review-files/review-diff) returns
empty (the 0.2.20-style headless tool-gating regression), retry once with
the file(s)/diff embedded inline via the no-tools text path, when content
is under 256KB; otherwise emit a clear skip note. Keeps grok-reads-files as
the default happy path (works on 0.2.22) and degrades gracefully instead of
returning silence. text/verify/raw unchanged; Windows path handling intact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-05 08:32:28 -07:00
parent 90e2cb2dd7
commit 2d409a4e7a

View File

@@ -114,6 +114,40 @@ find_artifact() {
ls -t "$HOME/.grok/sessions/"*"/$1/$2/"* 2>/dev/null | head -1 ls -t "$HOME/.grok/sessions/"*"/$1/$2/"* 2>/dev/null | head -1
} }
# --- self-healing embed fallback for review modes -----------------------------
# The review/review-files/review-diff modes default to letting grok read the
# target files/diff ITSELF (read_file tool) — this works on grok >=0.2.22 and
# avoids stuffing large files into the prompt. But on grok 0.2.20 headless
# read_file wasn't wired, so those runs came back EMPTY (silent failure). The
# text/verify modes never had this problem because they EMBED all content inline
# (no tools). To survive a future regression of that kind, each review mode below
# retries ONCE with the file/diff contents embedded inline (the no-tools text
# path) when the grok-reads-files run returns empty — but only when the payload
# is small enough to safely inline (EMBED_FALLBACK_MAX_BYTES). Over that size we
# keep the existing behavior (report "no result") rather than blow up the prompt.
EMBED_FALLBACK_MAX_BYTES=262144 # ~256KB ceiling for inlining content into the prompt
# byte size of one or more files, summed; prints an integer (0 if none readable).
bytes_of_files() {
local total=0 n
for f in "$@"; do
n="$(wc -c < "$f" 2>/dev/null || echo 0)"
n="${n//[^0-9]/}"; [ -z "$n" ] && n=0
total=$(( total + n ))
done
printf '%s' "$total"
}
# Run grok in the no-tools text path against the already-built $PF, capturing the
# result into the caller's variable. Mirrors the text-mode invocation (web search
# off, short turn budget) since everything it needs is already in the prompt.
# Resets RUN_CWD to a neutral working dir so no tool-reachable cwd is implied.
embed_fallback_run() {
RUN_CWD="$WORK"
run_grok 240 --disable-web-search --max-turns 3
jfield text
}
case "$MODE" in case "$MODE" in
text|verify) text|verify)
# content from --prompt-file <path> (good for long docs) or the positional arg # content from --prompt-file <path> (good for long docs) or the positional arg
@@ -183,6 +217,18 @@ case "$MODE" in
printf 'Use your read_file tool to read the file at this absolute path, then do the task and stop. You may also read closely-related files it references if that helps. Do not modify anything.\nPath: %s\n\nTask: %s' "$tgt_win" "$instr" > "$PF" printf 'Use your read_file tool to read the file at this absolute path, then do the task and stop. You may also read closely-related files it references if that helps. Do not modify anything.\nPath: %s\n\nTask: %s' "$tgt_win" "$instr" > "$PF"
run_grok 240 --max-turns 12 run_grok 240 --max-turns 12
txt="$(jfield text)" txt="$(jfield text)"
if [ -z "$txt" ]; then
# grok-reads-files came back empty (possible read_file regression) -> retry
# ONCE with the file contents embedded inline, if small enough to inline.
sz="$(bytes_of_files "$resolved")"
if [ "$sz" -le "$EMBED_FALLBACK_MAX_BYTES" ]; then
echo "[$SELF] empty result; retrying with file embedded inline (${sz}B)" >&2
{ printf 'Review the following file. Answer in text only; do not use tools. Do not modify anything.\nPath: %s\n\nTask: %s\n\n=== BEGIN FILE ===\n' "$resolved" "$instr"; cat "$resolved"; printf '\n=== END FILE ===\n'; } > "$PF"
txt="$(embed_fallback_run)"
else
echo "[$SELF] embed-fallback skipped: file is ${sz}B (> ${EMBED_FALLBACK_MAX_BYTES}B threshold)" >&2
fi
fi
if [ -n "$txt" ]; then printf '%s\n' "$txt"; else if [ -n "$txt" ]; then printf '%s\n' "$txt"; else
echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; exit 1; fi echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; exit 1; fi
;; ;;
@@ -200,10 +246,12 @@ case "$MODE" in
done done
[ ${#files[@]} -eq 0 ] && { echo "usage: $SELF review-files [-i \"instructions\"] <file> [file ...]" >&2; exit 2; } [ ${#files[@]} -eq 0 ] && { echo "usage: $SELF review-files [-i \"instructions\"] <file> [file ...]" >&2; exit 2; }
list="" list=""
resolved_files=() # POSIX paths, kept for the embed fallback (sizing + cat)
for f in "${files[@]}"; do for f in "${files[@]}"; do
if [ -f "$f" ]; then r="$f" if [ -f "$f" ]; then r="$f"
elif [ -f "$REPO_ROOT/$f" ]; then r="$REPO_ROOT/$f" elif [ -f "$REPO_ROOT/$f" ]; then r="$REPO_ROOT/$f"
else echo "[$SELF] file not found: $f" >&2; exit 2; fi else echo "[$SELF] file not found: $f" >&2; exit 2; fi
resolved_files+=("$r")
list+="- $(winpath "$r") list+="- $(winpath "$r")
" "
done done
@@ -211,6 +259,23 @@ case "$MODE" in
printf 'Use your read_file tool to read EACH of these files (absolute paths), then perform the task across ALL of them and stop. Do not modify anything.\n\nFiles:\n%s\nTask: %s' "$list" "$instr" > "$PF" printf 'Use your read_file tool to read EACH of these files (absolute paths), then perform the task across ALL of them and stop. Do not modify anything.\n\nFiles:\n%s\nTask: %s' "$list" "$instr" > "$PF"
run_grok 300 --max-turns 24 run_grok 300 --max-turns 24
txt="$(jfield text)" txt="$(jfield text)"
if [ -z "$txt" ]; then
# read_file path empty -> retry ONCE with all file contents embedded inline,
# if the combined size is under the inline threshold.
sz="$(bytes_of_files "${resolved_files[@]}")"
if [ "$sz" -le "$EMBED_FALLBACK_MAX_BYTES" ]; then
echo "[$SELF] empty result; retrying with ${#resolved_files[@]} file(s) embedded inline (${sz}B)" >&2
{
printf 'Review the following files together as a unit. Answer in text only; do not use tools. Do not modify anything.\n\nTask: %s\n' "$instr"
for r in "${resolved_files[@]}"; do
printf '\n=== BEGIN FILE: %s ===\n' "$r"; cat "$r"; printf '\n=== END FILE: %s ===\n' "$r"
done
} > "$PF"
txt="$(embed_fallback_run)"
else
echo "[$SELF] embed-fallback skipped: combined files are ${sz}B (> ${EMBED_FALLBACK_MAX_BYTES}B threshold)" >&2
fi
fi
if [ -n "$txt" ]; then printf '%s\n' "$txt"; else if [ -n "$txt" ]; then printf '%s\n' "$txt"; else
echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; exit 1; fi echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; exit 1; fi
;; ;;
@@ -243,6 +308,19 @@ case "$MODE" in
{ printf 'Review the following unified git diff. %s\nYou may use read_file on any changed file (paths in the diff are relative to your current directory; strip the a/ b/ prefixes) for full context. Do not modify anything.\n\n=== BEGIN DIFF ===\n' "$instr"; cat "$TMP/diff.txt"; printf '\n=== END DIFF ===\n'; } > "$PF" { printf 'Review the following unified git diff. %s\nYou may use read_file on any changed file (paths in the diff are relative to your current directory; strip the a/ b/ prefixes) for full context. Do not modify anything.\n\n=== BEGIN DIFF ===\n' "$instr"; cat "$TMP/diff.txt"; printf '\n=== END DIFF ===\n'; } > "$PF"
run_grok 300 --max-turns 20 run_grok 300 --max-turns 20
txt="$(jfield text)" txt="$(jfield text)"
if [ -z "$txt" ]; then
# If even the diff review (which already embeds the diff but invites read_file
# for context) came back empty, retry ONCE in the strict no-tools text path
# with just the diff inline, provided the diff is under the inline threshold.
sz="$(bytes_of_files "$TMP/diff.txt")"
if [ "$sz" -le "$EMBED_FALLBACK_MAX_BYTES" ]; then
echo "[$SELF] empty result; retrying with diff embedded inline, no tools (${sz}B)" >&2
{ printf 'Review the following unified git diff. %s\nAnswer in text only; do not use tools. Do not modify anything.\n\n=== BEGIN DIFF ===\n' "$instr"; cat "$TMP/diff.txt"; printf '\n=== END DIFF ===\n'; } > "$PF"
txt="$(embed_fallback_run)"
else
echo "[$SELF] embed-fallback skipped: diff is ${sz}B (> ${EMBED_FALLBACK_MAX_BYTES}B threshold)" >&2
fi
fi
if [ -n "$txt" ]; then printf '%s\n' "$txt"; else if [ -n "$txt" ]; then printf '%s\n' "$txt"; else
echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; exit 1; fi echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; exit 1; fi
;; ;;