cyberine
UsageRun recipes

Repeat-tool nudge — advisory reminder when a worker repeats the exact same call

safetyRails.checkPreCallCaps (iteration + token caps) runs once PER DISPATCH; a worker grepping the same pattern forty times inside ONE dispatch is invisible to it, and the only thing that eventually stops it is the blunt LOOP_MAX_TOOL_ROUNDS round cap ending the task rather than redirecting it. src/tools/repeatToolNudge.ts closes that gap with a targeted, purely advisory signal: when a worker calls the SAME tool with canonicalised-identical arguments 3, 5, then 8 times in a row (ascending, escalating in tone), it appends a reminder to that call's own result asking the model to re-read the last result and either change approach or conclude the repeat is intentional. It never blocks, never rewrites the underlying result, and never appears in any tool's list — it is a post-execute stage (src/core/toolDispatch.ts), not a Tool. Canonicalisation sorts argument object keys before comparing, so reordered JSON keys still count as the same call; any intervening DIFFERENT call resets the streak to zero. todo_write / todo_read are excluded (a todo list is legitimately re-read/re-written with identical arguments across many correct turns).

Thresholds are configurable, read at call time (same convention as the other safety-rails caps):

export CYBERINE_REPEAT_TOOL_THRESHOLDS="3,5,8"   # default; ascending, any count
export CYBERINE_REPEAT_TOOL_THRESHOLDS=""        # disable the nudge entirely

Known Limitations and Deferred Work (src/tools/repeatToolNudge.ts). State is scoped by ToolContext.cwd (the same practical per-worker unit src/tools/jobRegistry.ts's background jobs already use) — two non-isolated workers that happen to share one cwd (no worktree isolation) share one repeat-count bucket rather than being tracked independently; isolated (isolate: true) build steps, which each get their own worktree cwd, are unaffected. State lives in an in-process Map with a crude 500-worker eviction (clear-everything, not per-entry LRU) — acceptable for an advisory signal, not for anything correctness-sensitive. Injecting the reminder appends to the tool-result message's own content, which — like any change to that message's bytes — can invalidate a provider's prompt cache for the rest of that step; firing only at the three configured thresholds (never on every repeated call) is the mitigation, not a cache-aware exemption.