Edit pacing — a loop implementer writes before its round budget runs out
A key-only loop implementer (loop-deepseek-build and the other loop-*-build workers) used to spend every tool round reading and never call a write tool. When the budget ran out, the loop asked for a final answer with no tools, so the model could only describe the fix it had worked out (k7mvc, measured on deepseek-flash direct: 0 of 2 runs changed a file on a two-file task). LoopAgentAdapter now paces a run that is expected to change files. Three things happen, and only while no write tool (write_file / edit_file / multi_edit) has been called yet:
- At run start, a system message states the round budget, says a described change is never applied, and names the round to start editing by.
- After 40% of
LOOP_MAX_TOOL_ROUNDS(round 10 of the default 25), a one-time user message says how many rounds are left and asks the model to stop surveying and start writing. - After 60% (round 15 of 25), reading tools are switched off: only the write tools are offered until one is called, and then every tool comes back so the model can check and correct its change.
After the change, the same task on the same model landed a typecheck-clean diff in 3 of 3 runs, and the one-line control task still passed.
Pacing applies only when the dispatcher sets Task.expectsEdits and the worker holds a write tool. The engine sets that flag wherever a worker runs in its own worktree and its diff is captured: isolate: true steps (the implement step of cyberine run with a build fleet, swarm chunks), kanban cards, beam-search candidates, swarm lanes, and the self-heal and integration-fix agents. Planning and review steps that reuse a build worker, judges, and the loop-*-direct compare workers are unchanged.
export LOOP_EDIT_PACING_PERCENT=40 # default: nudge at 40% of the round budget, write tools only from 60%
export LOOP_EDIT_PACING_PERCENT=0 # turn edit pacing offThe write-only point is always a third of the way from the nudge to the end of the budget. A budget too small to fit both steps gets only the nudge, or no pacing at all.
Known Limitations and Deferred Work (src/adapters/LoopAgentAdapter.ts).
- Measured on one two-file task with one model (
deepseek-flashover DeepSeek direct), 3 runs after the change. Other models and larger tasks are not measured. - A landed diff is not a complete one: in 1 of the 3 runs the first adapter edit failed on a non-unique
old_string, and the run ended with only the parser half written. Pacing gets a write onto disk; it does not judge completeness. - The first write in a write-only round has to come from code the model already read. A failed write call still counts as a write and brings reading back.
- The architect-editor editor task, a
delegate_subtasksubagent and any directLoopAgentAdaptercaller get no pacing unless they setTask.expectsEdits. - A write-only round sends a smaller tool list, which can miss a provider's prompt cache for that round.
- A write through
run_pipelineis detected by a plain substring match on its arguments.
Malformed tool calls — validate-then-repair on the loop tool-input path (kmk7x)
Open models on OpenAI-compatible endpoints (DeepSeek, MiniMax, GLM, Qwen) emit a small set of recurring tool-call shape errors. Before this change a loop worker parsed the arguments with...
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...