Environment
- OS: Ubuntu 24.04 (Linux 7.0.0-28-generic), GNOME on X11 (not Wayland)
- Python: 3.12.3 (system),
gi GObject Introspection with Atspi 2.0 (gi.repository.Atspi)
- open-computer-use: v0.3.1 (npm,
dist/linux/amd64/open-computer-use — a Go binary embedding apps/OpenComputerUseLinux/runtime.py)
- Node: v18.19.1 (system)
Problem 1 (critical): every tool crashes with 'Accessible' object has no attribute 'is_text'
On this system, all tools that read the accessibility tree crash:
open-computer-use call get_app_state --args '{"app":"qqmusic"}'
>>> 'Accessible' object has no attribute 'is_text'
type_text crashes the same way with a sibling attribute:
open-computer-use call type_text --args '{"app":"qqmusic","text":"hi"}'
>>> 'Accessible' object has no attribute 'is_editable_text'
Because every action tool is gated behind app state ("No app state is available for X. Run get_app_state before action tools."), one AttributeError makes the entire server unusable on Linux.
Root cause
The embedded runtime.py treats is_text / is_editable_text as attributes of the Atspi.Accessible object:
runtime.py:220 — if not bool(safe(node.is_text, False)):
runtime.py:410 — if focused is None or not bool(safe(focused.is_text, False)):
runtime.py:693 — return bool(safe(node.is_editable_text, False)) and ...
runtime.py:720 — if node is not None and bool(safe(node.is_editable_text, False)):
In the gi bindings (gi.repository.Atspi), Atspi.Accessible has no is_text/is_editable_text attribute. Interface presence is queried via node.get_interfaces() (returns e.g. ['Accessible', 'Action', 'Collection', 'Component', 'Hyperlink', 'Text']). Because the attribute is evaluated eagerly at call time, the AttributeError fires before safe() can catch it — so safe(node.is_text, False) never protects anything.
Suggested fix
Replace the attribute accesses with interface checks:
def is_text_node(node):
try:
return "Text" in node.get_interfaces()
except Exception:
return False
def is_editable_text_node(node):
try:
return "EditableText" in node.get_interfaces()
except Exception:
return False
and use those in the four call sites above.
Workaround used
I worked around it locally (without touching the Go binary) by monkeypatching the missing properties onto Atspi.Accessible from a .pth-loaded Python module:
# ocu_fix.py (loaded via ocu_fix.pth in a site-packages dir)
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
if not hasattr(Atspi.Accessible, "is_text"):
Atspi.Accessible.is_text = property(lambda self: "Text" in self.get_interfaces())
if not hasattr(Atspi.Accessible, "is_editable_text"):
Atspi.Accessible.is_editable_text = property(lambda self: "EditableText" in self.get_interfaces())
Note: a sitecustomize.py in the user site-packages does not work — Ubuntu ships /usr/lib/python3.12/sitecustomize.py, and Python only loads the first sitecustomize on sys.path. The .pth import ocu_fix mechanism is what reliably runs.
Problem 2: type_text cannot type CJK on Chromium/Electron apps
type_text first tries insert_text(), which requires the target node to expose the EditableText interface. On Chromium/Electron apps the search <input> is exposed with Text but no EditableText, so insert_text returns False and it falls back to send_text() (Atspi.generate_keyboard_event(..., KeySynthType.STRING)), which synthesizes keysyms and cannot produce CJK characters. On Chinese-language apps, type_text therefore cannot enter text; the only reliable route is pasting from the X clipboard into a focused field.
This would be worth documenting (or handling) if CJK input is expected to work.
Problem 3: Chromium/Electron apps expose an empty web-content tree to AT-SPI
Against QQ Music (an Electron app), get_app_state returns only empty document web nodes until the app is launched with --force-renderer-accessibility. Without that flag, no widgets (search box, buttons, song rows) are exposed at all, so element-indexed click/type_text cannot target anything. Worth a note in the README for Electron/Chromium targets.
Happy to provide more logs or test a patch if useful.
Environment
giGObject Introspection with Atspi 2.0 (gi.repository.Atspi)dist/linux/amd64/open-computer-use— a Go binary embeddingapps/OpenComputerUseLinux/runtime.py)Problem 1 (critical): every tool crashes with
'Accessible' object has no attribute 'is_text'On this system, all tools that read the accessibility tree crash:
type_textcrashes the same way with a sibling attribute:Because every action tool is gated behind app state ("No app state is available for
X. Run get_app_state before action tools."), one AttributeError makes the entire server unusable on Linux.Root cause
The embedded
runtime.pytreatsis_text/is_editable_textas attributes of theAtspi.Accessibleobject:runtime.py:220—if not bool(safe(node.is_text, False)):runtime.py:410—if focused is None or not bool(safe(focused.is_text, False)):runtime.py:693—return bool(safe(node.is_editable_text, False)) and ...runtime.py:720—if node is not None and bool(safe(node.is_editable_text, False)):In the
gibindings (gi.repository.Atspi),Atspi.Accessiblehas nois_text/is_editable_textattribute. Interface presence is queried vianode.get_interfaces()(returns e.g.['Accessible', 'Action', 'Collection', 'Component', 'Hyperlink', 'Text']). Because the attribute is evaluated eagerly at call time, theAttributeErrorfires beforesafe()can catch it — sosafe(node.is_text, False)never protects anything.Suggested fix
Replace the attribute accesses with interface checks:
and use those in the four call sites above.
Workaround used
I worked around it locally (without touching the Go binary) by monkeypatching the missing properties onto
Atspi.Accessiblefrom a.pth-loaded Python module:Note: a
sitecustomize.pyin the user site-packages does not work — Ubuntu ships/usr/lib/python3.12/sitecustomize.py, and Python only loads the firstsitecustomizeonsys.path. The.pthimport ocu_fixmechanism is what reliably runs.Problem 2:
type_textcannot type CJK on Chromium/Electron appstype_textfirst triesinsert_text(), which requires the target node to expose theEditableTextinterface. On Chromium/Electron apps the search<input>is exposed withTextbut noEditableText, soinsert_textreturnsFalseand it falls back tosend_text()(Atspi.generate_keyboard_event(..., KeySynthType.STRING)), which synthesizes keysyms and cannot produce CJK characters. On Chinese-language apps,type_texttherefore cannot enter text; the only reliable route is pasting from the X clipboard into a focused field.This would be worth documenting (or handling) if CJK input is expected to work.
Problem 3: Chromium/Electron apps expose an empty web-content tree to AT-SPI
Against QQ Music (an Electron app),
get_app_statereturns only emptydocument webnodes until the app is launched with--force-renderer-accessibility. Without that flag, no widgets (search box, buttons, song rows) are exposed at all, so element-indexedclick/type_textcannot target anything. Worth a note in the README for Electron/Chromium targets.Happy to provide more logs or test a patch if useful.