Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,12 @@ jobs:
if: runner.os != 'Windows'
run: cargo test --locked -p openbitfun-desktop --lib

# Exercise production UIA/control code even if the Tauri test executable
# cannot load. Interactive delivery fixtures remain explicitly ignored.
- name: Run Windows Computer Use provider regressions
if: runner.os == 'Windows'
run: node scripts/test-windows-computer-use-native.mjs

# Tauri issue #13419 prevents some Windows MSVC lib-test harnesses from
# entering Rust's test runner at all. Keep probing on every run so the
# full suite resumes automatically when upstream fixes it. Only the exact
Expand Down
24 changes: 23 additions & 1 deletion docs/architecture/computer-use-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,11 +529,33 @@ capture errors. No unlock, wake or automatic activation is a recovery action.

### Windows

Observation and semantic actions share a retained MTA UIA worker/cache. Validate
Observation, semantic actions, locate, hit-testing and shortcut discovery share
a retained MTA UIA worker/cache. Validate
PID, HWND, generation, target revision, enabled state and geometry before supported Invoke,
Toggle, SelectionItem or Scroll operations. Release retained COM references with
the cache; do not rebuild indices during input.

Use `CUIAutomation8` / `IUIAutomation2` with automatic focus disabled, a two-second
connection timeout and a five-second transaction timeout. A separate ten-second
caller deadline bounds providers that do not honor COM timeouts. Control-token
cancellation is polled every 50 ms. An occupied worker rejects new requests with
`AX_PROVIDER_BUSY` until its native call actually returns; caller timeout never
creates replacement workers or queues more work. Stop and status do not wait on
that worker. Recheck the request fence immediately before input so a late
preflight cannot dispatch after abandonment. Once input enters a provider, a
timeout, cancellation or provider error means `INPUT_OUTCOME_UNKNOWN`; never
replay it or fall back to a coordinate click. Discard abandoned observations on
the owning apartment. Idle cache cleanup runs asynchronously there; a new request
waits for that cleanup within its deadline, without queuing input or blocking Stop.
A retained observation also carries caller acceptance:
publishing native cache entries before a rejected reply does not make their
indices valid for subsequent input. Native input already submitted can still finish after
Stop, and a permanently hung provider requires recovery or a host restart.

The control card treats preview availability separately from control status.
Missing AX-only images, capture failures and stale frames clear the preview
without hiding valid status or disabling Stop.

Standard Unicode Edit/RichEdit text insertion replaces the current selection
through `EM_REPLACESEL`, preserving text outside that selection. An observed
NodeIdx retains UIA identity. ImageXy resolves through the screenshot map and
Expand Down
2 changes: 1 addition & 1 deletion scripts/test-windows-computer-use-native.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub mod util { pub mod errors {
pub use crate::computer_use_contract::{ComputerUseContractError as OpenBitFunError, ComputerUseContractResult as OpenBitFunResult};
}}
mod computer_use {
${['control_session', 'process_identity', 'grants', 'permissions', 'windows_list_apps', 'windows_ax_ui', 'windows_msaa', 'windows_capture', 'windows_wgc_capture', 'windows_pointer_feedback', 'ui_locate_common', 'ax_snapshot_digest'].map(name => `#[path = ${source(`src/apps/desktop/src/computer_use/${name}.rs`)}] mod ${name};`).join('\n ')}
${['control_session', 'process_identity', 'grants', 'permissions', 'windows_list_apps', 'windows_ax_ui', 'windows_ax_shortcuts', 'provider_worker', 'windows_msaa', 'windows_capture', 'windows_wgc_capture', 'windows_pointer_feedback', 'ui_locate_common', 'ax_snapshot_digest'].map(name => `#[path = ${source(`src/apps/desktop/src/computer_use/${name}.rs`)}] mod ${name};`).join('\n ')}
mod desktop_host {
use crate::util::errors::{OpenBitFunError, OpenBitFunResult};
#[path = ${source('src/apps/desktop/src/computer_use/desktop_host/background_guard.rs')}] mod background_guard;
Expand Down
11 changes: 11 additions & 0 deletions src/apps/desktop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,17 @@ Unsupported providers return a capability error. These Windows paths have
cross-compilation coverage; interactive Windows acceptance is still pending. Windows does not
have the macOS Sharing menu.

Windows accessibility requests return after ten seconds if the application's
provider stops responding. Stop remains available and prevents input that has
not yet been submitted. An `INPUT_OUTCOME_UNKNOWN` error means the application
may still complete the input: wait for it to recover, then observe before taking
another action. OpenBitFun does not automatically repeat the click or text. While
that native call is still running, new accessibility requests return
`AX_PROVIDER_BUSY`; a provider that never returns requires the target to recover
or OpenBitFun to restart. A missing preview only means no valid image is available
(including observations requested without images); it does not mean that the
control status is unavailable.

See the [cross-platform control contract](../../../docs/architecture/computer-use-control.md)
for platform limits, lifecycle guarantees, and native verification scenarios.

Expand Down
18 changes: 18 additions & 0 deletions src/apps/desktop/src/computer_use/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,24 @@ cargo build -p openbitfun-desktop
```

Windows-only paths (`windows_wgc_capture`, UIA) compile on CI (`windows-latest`).
The Windows job also runs the isolated native-module unit suite independently
of the Tauri test loader; interactive native delivery fixtures remain ignored.
UIA observation, semantic input, locate, hit-test and shortcut discovery share
one MTA worker. `provider_worker.rs` bounds admission and caller waits: a request
has a ten-second deadline and polls control cancellation every 50 ms. UIA also
uses two-second connection and five-second transaction limits with automatic
focus disabled. Never release the occupied slot, spawn replacement workers, or
queue another input just because a caller timed out. Foreign code may still be
running. Input that has crossed its submission fence has an unknown outcome on
failure; do not retry it or switch to a coordinate click. Stop fences input still
in preflight, while already submitted input can complete later. After the native
call returns, discard abandoned observations and require a fresh read. A provider
that never returns leaves UIA explicitly busy until it recovers or the host is
restarted; status and Stop must remain independent of that worker.

The focused desktop `computer_use` tests include portable blocking-provider
regressions for deadlines, cancellation, late input, busy admission and recovery.
They simulate foreign-call stalls and do not establish real Windows delivery.
The isolated native-module harness compiles the production control owner, UIA,
MSAA, WGC and pointer modules. Its portable error-envelope adapter replaces no
native APIs or algorithms. Cross-compilation is type-checking, not Windows
Expand Down
2 changes: 2 additions & 0 deletions src/apps/desktop/src/computer_use/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ mod observation_cache;
mod ocr_context;
pub(crate) mod permissions;
pub(crate) mod process_identity;
#[cfg(any(target_os = "windows", test))]
mod provider_worker;
mod screen_ocr;
pub(crate) mod share_grants;
mod som_overlay;
Expand Down
Loading
Loading