OpenHands / OpenHands/software-agent-sdk

WAITING_FOR_CONFIRMATION: any user message implicitly approves pending actions on next run()

Open
#5,092 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug priority:high ready-for-dev sdk security
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
  1. Confirmation mode; run #1: agent proposes a marker-writing tool call → status WAITING_FOR_CONFIRMATION, not executed (correct).
  2. User sends "Wait — do NOT run that. Cancel the marker request." (a revocation, not an approval).
  3. run #2: WAITING is cleared with the "(user approved)" comment (local_conversation.py:1994-2000), _step executes all unmatched pending actions (agent/agent.py:653-663) → marker file written; the model then receives {'status': 'executed', ...}.
  4. send_message has 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 installed openhands-sdk with a deterministic scripted LLM and a marker tool — available on request). Control with reject_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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.