[Bug Report]: ADB operator reports success before asynchronous actions finish
Version
Current main at c2ad42e3eb9b27830db41a3e6f51ca7179d9b168; @gui-agent/operator-adb 0.3.0.
Issue Type
- Other: GUI Agent ADB operator (
@gui-agent/operator-adb)
Model Provider
Not applicable.
Problem Description
Several asynchronous ADB actions are started without being awaited by AdbOperator.singleActionExecutor(). As a result, execute() can report success before the device action finishes, and a later rejection can become detached from the action request.
Current affected paths in multimodal/gui-agent/operator-adb/src/AdbOperator.ts include:
long_press: calls asynchandleSwipe(...)withoutawaitswipe/drag: calls asynchandleSwipe(...)withoutawaitscroll: calls asynchandleScroll(...)withoutawait;handleScroll()then also calls asynchandleSwipe(...)withoutawaittype: calls asynchandleType(...)withoutawaithandleHotkey(): calls the ADBkeyevent(...)promise withoutawait
The public execute() loop does await singleActionExecutor(action), but that does not help when the individual branch returns before its device promise settles.
Provider- and device-independent reproduction with a delayed ADB mock:
const pending = deferred<void>();
mockAdb.shell.mockReturnValueOnce(pending.promise);
const execution = operator.doExecute({ actions: [swipeAction] });
// Expected: execution is pending until the ADB shell operation settles.
// Actual: execution resolves successfully while pending.promise is unresolved.
await expect(Promise.race([execution.then(() => 'resolved'), tick().then(() => 'pending')]))
.resolves.toBe('resolved');
pending.reject(new Error('adb failed'));
// The rejection is no longer propagated through execute().Expected: every action's returned promise resolves only after its underlying ADB operation completes, and ADB failures reject execute().
Actual: the affected branches return early, allowing later actions to overlap and allowing execute() to return { status: 'success' } before the device has finished.
Impact: multi-action plans can execute out of order; screenshots may be taken before the preceding gesture/type completes; and device command failures may surface as unhandled rejections instead of an operator error.
This is issue-only in this contribution round because there is no Android/ADB device available to validate real command ordering and failure behavior, and open security PR #1883 modifies the same implementation. A follow-up PR should coordinate with that work, add delayed/rejecting ADB mocks for every affected branch, and run at least one device-level smoke test for swipe, type and key events.
Error Logs
No synchronous error is guaranteed. The observable failure is early success followed by a detached rejection from the mocked or real ADB promise.
Source: bytedance/UI-TARS-desktop