[Bug] RLM agent still holds the turn open with polling despite the #1188 nonblocking rule #2049
israellot
started this conversation in
Bug reports
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Summary
The RLM system prompt (merged in #1188) forbids keeping the turn open by polling with
time.sleep()or shellsleep, and forbids replacing polling with a long blockingawait. In practice the model still does exactly this withawait asyncio.sleep(N), which the prompt does not name. The model treats the asyncio variant as allowed, so the turn stays open for minutes while nothing productive happens.Environment
0.9.1bash()handle from Async bash() tool for the kernel runtime #1684Reproduction
dh = bash("jadx -d /tmp/out app.apk > /tmp/jadx.log 2>&1").Observed behavior
Repeated cells of this shape, each keeping the turn open for the full fixed interval:
Expected behavior
Per the #1188 contract: start the job, record the handle, end the turn, and inspect
dh.poll()/dh.tail()on a later turn or on a heartbeat wake-up.Why the prompt rule does not catch it
Current text in
packages/coding-agent/src/core/prompts/rlm.ts:asyncio.sleepis not named. The model reads "long blockingawait" as "await on the job", not as "await on a timer", and picksasyncio.sleepprecisely because it is the "non-blocking" sleep in asyncio terms.rlm_heartbeatskill (rlm_heartbeat.create(..., delivery_mode="follow_up")) is the natural replacement, but nothing in the control-loop text routes the model to it, so the model invents a timer instead.Suggestions
asyncio.sleep(andawait asyncio.sleep) explicitly in the rule, alongsidetime.sleep()and shellsleep.asyncio.sleep(n)/time.sleep(n)above a few seconds, in the same spirit as the other fail-closed guards. This removes the dependence on the model reading the prompt correctly.Note the opposite failure in #2016 / discussion #1598: when the model does end the turn correctly, goal mode hot-loops. Both point at the same gap: there is no first-class "wake me when this handle finishes" primitive, so the model either sleeps (this report) or gets re-prompted every few seconds (#2016).
Related
time.sleep()variant of the rulebash()handleAll reactions