OpenHands / OpenHands/software-agent-sdk
WAITING_FOR_CONFIRMATION: any user message implicitly approves pending actions on next run()
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 539
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 137
Description
Summary
In confirmation mode, when the agent proposes an action the conversation enters WAITING_FOR_CONFIRMATION. LocalConversation.send_message has zero handling for that state (it only resets FINISHED/STUCK to IDLE). The next run() clears WAITING→RUNNING with the built-in comment "(user approved)" — an assumption, never verified — and Agent._step executes all unmatched pending actions as an "implicit confirmation".
Therefore a user message that explicitly revokes the request — "Wait, do NOT run that" — causes the revoked action to execute on the next run(), with no approval gesture of any kind.
The async arun() loop implements the correct semantic for the mid-step race window (reject pending actions: "Superseded by a new user message", local_conversation.py:2289-2312, with a comment stating leaving them unmatched would "silently [override] the new message") — but the sync path and the steady-state waiting window (the primary human-decision window) are undefended.
Actual Behavior
Reproducible SDK steps (fully offline, deterministic scripted LLM; see harness below):
python repro_gc09.py # exits 1, prints the evidence
- Confirmation mode; run #1: agent proposes a marker-writing tool call → status WAITING_FOR_CONFIRMATION, not executed (correct).
- User sends "Wait — do NOT run that. Cancel the marker request." (a revocation, not an approval).
- run #2: WAITING is cleared with the "(user approved)" comment (local_conversation.py:1994-2000),
_stepexecutes all unmatched pending actions (agent/agent.py:653-663) → marker file written; the model then receives{'status': 'executed', ...}. send_messagehas no WAITING branch (local_conversation.py:1850-1856); only the async mid-step window supersedes pending actions on a new message (:2289-2312).
Observed: EFFECT EXECUTED DESPITE REVOCATION: True.
Expected Behavior
A user message during WAITING_FOR_CONFIRMATION must never act as consent. The framework's own async mid-step path already implements the correct semantic — pending actions should be superseded (reject_pending_actions("Superseded by a new user message")) when a message arrives while waiting.
Acceptance Criteria
- A revocation/control message sent while WAITING_FOR_CONFIRMATION no longer results in pending-action execution on the next run()
- send_message either supersedes pending actions (as the async mid-step path does) or surfaces an explicit confirm/deny choice instead of assuming consent
Notes
- Harness details (real
LettaAgentV3-style offline construction is not used here; this uses the installedopenhands-sdkwith a deterministic scripted LLM and a marker tool — available on request). Control withreject_pending_actions()before the second run correctly prevents execution. - Affects the OpenHands product surfaces that rely on the message→run loop (CLI/GUI/agent-server message endpoint with run=True).
Credit
Chengzhi Yi — yimou@hust.edu.cn — GitHub @Tardfyou
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with LocalConversation.send_message and the WAITING_FOR_CONFIRMATION transition around local_conversation.py:1850-1856 and 1994-2000, then compare the async handling at :2289-2312 with Agent._step at agent/agent.py:653-663. Run python repro_gc09.py to reproduce the execution after revocation. Done means a message while waiting cannot execute pending actions without an explicit confirmation or denial path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100