Narrow forced edit retry nudges
ober
de5517d10ed5c03e3f563b056ca5d68626ee983a
--- a/src/jcode/core/workflow-runner.ss +++ b/src/jcode/core/workflow-runner.ss @@ -413,6 +413,23 @@ (and (string? content) (string-prefix? forced-first-edit-retry-marker content))) +(def (forced-first-edit-retry-tool-names content fallback-tool-names) + (cond + ((not (string? content)) + fallback-tool-names) + ((or (string-contains content "required edit") + (string-contains content "required write")) + '("edit" "write")) + ((string-contains content "required balance") + '("balance")) + ((string-contains content "required replace_range") + '("replace_range")) + ((string-contains content "required replace_def") + '("replace_def")) + ((string-contains content "required line_edit") + '("line_edit")) + (else fallback-tool-names))) + (def (suppress-verified-text-history? workflow retry-text-responses? content) (and retry-text-responses? (verified-workflow? workflow) @@ -644,7 +661,10 @@ (emit! (make-user-message (if forced-first-edit-retry (forced-first-edit-retry-message - (tool-spec-name-list visible-tool-specs)) + (forced-first-edit-retry-tool-names + content + (tool-spec-name-list + visible-tool-specs))) (text-retry-message workflow enforcer messages content (error-tracker-consecutive-retries --- a/test/run.ss +++ b/test/run.ss @@ -1598,6 +1598,36 @@ #t] [else (loop (cdr ys))]))))) +(let* ([w (mk-research-wf)] + [msgs '()] + [resp (scripted-responder + (list (make-text-response + "JCODE_INTERNAL_FORCE_FIRST_EDIT_RETRY provider streamed 513 text/reasoning characters without calling a tool while this turn required edit.") + (list (make-wtool-call "search" '() #f)) + (list (make-wtool-call "answer" '() #f))))] + [result (run-workflow w "go" resp + (list (cons 'max-iterations 6) + (cons 'retry-text-responses? #t) + (cons 'on-message + (lambda (m) (set! msgs (cons m msgs))))))]) + (check! "forced first-edit detailed retry workflow still reaches terminal" + result "ANSWER delivered") + (check-pred! "forced first-edit detailed retry narrows nudge to edit tools" + (reverse msgs) + (lambda (xs) + (let loop ([ys xs]) + (cond + [(null? ys) #f] + [(and (equal? (message-role (car ys)) "user") + (str-contains? (message-content (car ys)) + "Currently available structured tools: edit, write") + (str-contains? (message-content (car ys)) + "Next response should be one structured edit(...) or write(...) tool call.") + (not (str-contains? (message-content (car ys)) + "search, lookup, answer"))) + #t] + [else (loop (cdr ys))]))))) + ;; Opt-in text retries fail through ToolCallError instead of burning every ;; workflow iteration. (let* ([w (mk-research-wf)]