『保存』を押す前に、同じボタンか確かめる――agent-desktopの強さと代償
AIが画面上の「保存」ボタンを見つけた直後、同じ窓にもう一つ「保存」ボタンが現れたとする。最初に覚えた位置や番号をそのまま使えば、違う対象を押すかもしれない。これはデスクトップ自動化の機能数より、観察から操作までの間に画面が変わったとき、何を根拠に同じ対象だと言えるかという問題だ。
2026年10月30日、デスクトップ操作用のオープンソースソフト agent-desktop はバージョン1.0.2を公開した。10月27日の1.0.0でmacOS、Windows、Linux向けのCLIとC向けライブラリーを統合し、その後は導入時の案内やmacOSの権限設定を修正している。これはAIモデルそのものではない。AIが既存のアプリを「観察し、操作し、確かめる」ための道具だ。開発元の変更履歴が示す公開日と修正内容
既存のOSSと比べて、どこが違うのか
デスクトップ操作を可能にするOSSは既にある。PyAutoGUIは3つのOSでマウスとキーボードを動かし、スクリーンショット上の画像を探せる。pywinautoはWindowsのWin32とUI Automationを利用して画面要素を操作する。agent-browserもアクセシビリティ情報と参照IDを使うが、対象はブラウザーだ。PyAutoGUIの操作例、pywinautoの対応方式、agent-browserの操作例
| OSS | 主に何を手掛かりにするか | 得意な範囲 | agent-desktopと比べると |
|---|---|---|---|
| PyAutoGUI | 座標、画像、キーボード | 画面に見えるものを広く操作する | ボタンの役割や名前を共通のJSONで受ける設計ではない |
| pywinauto | Win32・UI Automationの要素 | Windowsアプリの細かな操作 | Windowsに絞る代わりに、そのOS固有の操作を使い分けられる |
| agent-browser | ブラウザー内の要素と参照ID | Webページとブラウザー操作 | デスクトップ全体のアプリやOSの画面を対象にしない |
| agent-desktop | OSのアクセシビリティ情報と参照ID | 3つのOS上のアプリを同じCLI形式で扱う | 要素がOSへ意味を公開していることに依存する |
比較は各プロジェクトのPyAutoGUI文書、pywinauto文書、agent-browser README、agent-desktop READMEから整理したもの。性能や成功率の比較試験ではない。
したがって、agent-desktopの強みを「アクセシビリティ情報を使う初めての道具」と言うのは誤りだ。OSをまたぐデスクトップアプリの構造を、AIが呼びやすいCLIとJSONにそろえ、古い参照や曖昧な操作の扱いまで契約にしたことが注目点になる。AIに計画や判断をさせる部分は別に必要で、agent-desktop自体は推論モデルを含まない。CLIとJSONの契約を説明する公式資料
ブラウザー内だけで完結する仕事なら、ページやタブを直接扱えるagent-browserが候補になる。Windowsの一つの業務アプリを細かく制御するならpywinautoが候補になる。agent-desktopが光るのは、アプリをまたぎ、しかも画面要素の意味をOSが公開している場合だ。これは各ツールの公開機能に基づく選択の指針であり、どれが必ず速い・正確という主張ではない。
画素より、ボタンの意味を読む
仕組みの中心はアクセシビリティツリーだ。これは、画面にある要素をOSが「ボタン」「入力欄」「名前」「状態」などの形で外部へ伝える情報である。agent-desktopはその情報を読み、操作できる要素ごとに参照IDを付けたJSONのスナップショットを返す。たとえばAIは「Documentsという項目」を見つけ、その参照IDを指定してクリックし、新しいスナップショットで結果を確かめる。公式READMEが示す観察→操作→再観察の例
参照IDを配る対象も限定される。実装は、入力欄など操作用の役割を持つ要素、または主要な操作を提供する要素を選ぶ。多くのWeb系画面でほぼ全要素に付く「フォーカスできる」「右クリックできる」「見える位置へスクロールできる」だけでは、参照IDを配る理由にしない。無意味な容器まで番号を付けて結果を膨らませないためだ。参照IDを割り当てる条件
ここで参照IDは「永遠に同じボタンを指す番号」ではない。スナップショットに結び付いており、画面が変わって対象を確かめられなければ、古い参照としてエラーを返す。窓の識別も、OSの窓番号だけでなく、所有するプロセスの起動時点などで確かめる設計だ。開発元が説明する参照IDと窓の再同定
大きなアプリでは、まず浅い構造を読み、必要な領域だけ掘り下げられる。通常の参照IDによる操作は、マウスポインターを動かさずアクセシビリティ機能を通す。一方、スクリーンショットやマウス入力も別の機能として用意されている。「画像を一切扱えない製品」という理解は正しくない。公式READMEが示す領域の掘り下げと入力方法
実装はどこで分かれるのか
公開されているRustの構成には、共通コア、macOS・Windows・Linux別の実装、CLI、Cから呼び出すためのライブラリーが並ぶ。OSごとに異なる画面情報を取り、共通の役割や状態に変換してからAIへ返す形だ。macOSはAccessibility API、WindowsはUI Automation、LinuxはAT-SPIという各OS側の仕組みを使う。Cargoの構成、OSごとの役割の対応を説明する文書
共通コアが「クリック」を決めても、OSへ届ける方法は同じではない。macOSにはAXPressなどの操作、WindowsにはUI AutomationのInvokePattern、LinuxにはAT-SPIのDoActionを使う経路がある。これらは各OSで利用可能な場合の例で、すべてのボタンが必ずその経路を通るという意味ではない。macOSの操作呼び出し、Windowsの操作候補、LinuxのAT-SPI呼び出し
通常の参照ID操作では、前面のアプリを奪ったりマウスを動かしたりしない方針が基本になる。物理的なポインター操作が必要な場合は、別の許可を明示する。したがって「画面を触る」製品でも、意味のある要素への操作と、人間のマウスを代わりに動かす操作は、実装上分けられている。操作方針のコード
スナップショットは「表示する木」と「証明に使う観察」を分ける
コードを追うと、snapshotコマンドは対象アプリ・窓・深さなどを受け取り、OS別実装から画面要素の木を取得する。--skeletonでは表示する深さを最大3段に抑える。深いアプリの全情報を一度にAIへ渡さず、必要な枝へ進むためだ。返すJSONには要素の木だけでなく、snapshot_id、参照IDの数、観察が完了したかを示すcompleteが入る。snapshotコマンドが表示深さと出力を決める箇所
ここに意外な費用がある。AIへ見せる木が浅くても、参照IDの安全性を判定するために窓全体を読む場合がある。OS側に後から同じ要素を特定できる識別子が残らない場合、浅い観察だけでは「同じ名前のボタンが窓の下のほうにもう一つあるか」を確かめられない。実装は必要に応じて窓全体を観察し、その結果から浅い表示を作る。全体の観察が時間切れなどで不完全なら、参照の一意性を証明できなかったと記録する。浅い表示と窓全体の観察を分ける実装
この設計から、出力が短いこととOSからの読み取りが軽いことは同義ではない、と分かる。密な画面で遅さを評価するなら、AIへ渡した文字数だけでなく、OS側の観察時間も測る必要がある。これはコードから導いた性能上の見方であり、速度の実測値ではない。
参照IDを使う前に、何を確かめるのか
参照IDは@スナップショットID:e番号という形で、対応する情報をローカルの保存領域から読み出す。そこには対象の役割、名前などの識別材料、取得元のアプリや窓が含まれる。保存されたスナップショットは無制限に積み上げず、コード上は128件を上限として古いものを整理する。参照IDの保存と読み出しの実装
識別の鍵は「名前が同じなら同じ対象」ではない。取得時には、窓全体を漏れなく観察でき、記録した条件に合う要素が一つだけで、判定に必要な情報が読めたときに、一意性の証拠を付ける。後の操作では、保存された窓を探し、同じ条件に合う生きた要素を再検索する。二つ見つかれば曖昧な対象、見つからなければ古い参照、情報が読み切れなければ不明として止める。位置を手掛かりに到達した後も、到達先が本当に記録された要素か再確認する。取得時の一意性判定、操作時の再検索と到達先の確認
| 取得後に起きたこと | 参照IDを使う際の扱い |
|---|---|
| 同じ窓の同じ要素を確認できる | 操作へ進む |
| 要素が消えた | 古い参照として、新しい観察を求める |
| 同じ条件の要素が二つある | どちらかを推測せず、曖昧な対象として止める |
| 観察が不完全 | 一致を証明できず、操作を保留する |
表は取得時と操作時の実装を読者向けに要約したもの。すべての失敗が同じエラー名で返るという意味ではない。
冒頭の「保存」で考える。OS側に元の要素を継続特定できる識別子が残らず、取得時には一つだけだったボタンと同じ条件を満たすものが、操作時に同じ窓の中で二つになった場合、保存済みの参照からはどちらが元のボタンか決められない。実装は窓内の一致数を調べ、AMBIGUOUS_TARGETとして止める。元の条件に合う要素がなくなればSTALE_REFになる。参照IDはクリックを確約する券ではなく、再確認するための手掛かりだ。一致が複数またはゼロの場合の分岐
画面要素の「名前」を読む段階にも慎重さがある。複数の候補から名前を決める際、優先度の高い情報が読み取り失敗なら、優先度の低い候補をそのまま正式な名前として採用せず「不明」にする。情報が存在しないことと、読み取れなかったことを分ける実装だ。要素名の決定処理
操作の成功は、どこまで検証されるのか
CLIは一回の命令に一つのJSON結果を返す。結果には成功・失敗だけでなく、操作が届いたと確認できたか、再試行して安全かを表す区分がある。たとえば操作が届いたか不明なとき、同じクリックを機械的に繰り返すと二重実行の恐れがある。開発元の仕様も、再試行可否を確かめるよう求めている。「命令を送れた」と「目的の状態になった」は別の判定だ。JSON出力仕様にある操作の到達状態と再試行の扱い
実装では、値の設定、文字入力、チェックの切り替え、展開など、状態を読み返せる操作について、原則として一度送った後に要素の状態を再取得する。期待した値と矛盾すればエラーにし、読み返す証拠が足りなければ「届いたが未検証」として返す。パスワード欄のように値が隠される場合も、読めないことを成功の証明にはしない。さらに、要素の状態が一致しても、アプリの保存処理やサーバーへの反映まで証明したとは扱わない。操作後の状態確認を行う実装
not_deliveredなら再試行は安全、delivery_uncertainやdelivered_unverifiedなら安全とは判定しない、という対応もコードにある。たとえば送信ボタンの操作が時間切れになった場合、同じ命令を直ちに再送するより、まず送信済みかを画面や記録で調べるべきだ。後半はこの区分を利用する側への編集上の提案である。到達状態と再試行可否を対応付ける実装
--rootで領域を掘り下げるときは、既存の参照一覧の一部を更新する。そのため、観察が途中で切れた場合は、部分的な新しい結果で古い参照を置き換えず失敗させる。一方、窓全体の新しいスナップショットなら、complete: falseと切れた位置を付けて、読めた部分を返せる。ここでも「読めた範囲を利用すること」と「古い参照を書き換えること」を別の危険度で扱っている。領域を掘り下げる際の更新条件、部分的な観察のJSON仕様
どんな仕事で役立つか
もっとも使い道が見えやすいのは、アプリに直接使えるAPIがなく、操作対象が画面の要素として提供されている仕事だ。たとえばmacOS、Windows、Linux向けに同じデスクトップアプリを出す開発チームが、「設定画面を開き、項目を変更し、表示が変わったかを確かめる」テストをAIに依頼する場面である。OS別の取得部分は製品が吸収し、AIには同じ形式のJSONを返せる。ただし、3つのOSで同じ要素名や動作が得られることまで保証するものではない。これは機能から考えた仮想例であり、実測した導入事例ではない。各OSの実装構成、役割や名前の差を説明する文書
この仕事でAI側が組むべき手順は、①対象のアプリと窓を絞って観察、②completeと操作対象を確認、③参照IDで操作、④到達状態と更新後の値を確認、⑤アプリとして保存されたかを別に調べる、となる。agent-desktopが直接担当するのは観察、操作、要素状態の読み直しまでで、最後の業務上の判定は呼び出し側が設計する。公式READMEの基本手順、操作後の検証範囲
| 作業の条件 | 向き・不向きの目安 |
|---|---|
| 入力欄やボタンに意味のある名前が付く | 参照IDで対象を選びやすい |
| 対象が図形や独自描画だけで示される | ツリーから対象を読めない可能性がある |
| 結果を画面の状態で再確認できる | 操作後の確認手順を組みやすい |
| 送信・購入など取り消しにくい操作を含む | 到達状態の確認と人間の判断が要る |
表は開発元の仕組みと操作結果の仕様から導いた編集上の判断基準であり、互換性の測定結果ではない。
賛否を編集上の筆名による応酬で表す。以下は実際の討論や取材の記録ではない。
早瀬 ユウ(自動化の活用を考える編集上の推進役):ブラウザーの外まで、同じJSONの契約で扱えるのは強い。別のボタンを押すくらいなら曖昧な参照を拒む設計なら、AI側で「観察し直す」という回復手順も書きやすい。
氷室 さや(操作の確実性を吟味する編集上の慎重派):その厳格さは、窓全体の観察という費用も生む。OSに公開されない要素は読めないし、要素の値が変わっても保存されたとは限らない。既にAPIやブラウザー専用の操作口がある仕事へ、常にこの方式を使う理由はない。
この対立への答えは、対象アプリで小さな作業を試し、読める要素・操作の到達状態・結果の確認方法・観察にかかる時間を別々に評価することだ。アクセシビリティ情報が豊かな画面では利点が出やすく、独自描画の多い画面や見た目そのものを評価する仕事では、画像による確認などを併用する余地がある。これは製品資料からの推論であり、全アプリの実測結果ではない。
現時点の評価
2026年11月3日時点で、公式READMEはnpmからの導入、3つのOSへの対応、CLIとC向けライブラリーを案内している。ただし機能差はある。たとえばLinuxのマウス入力はX11を前提とし、スクリーンショットや窓操作も表示環境で条件が変わる。macOSではアクセシビリティ権限が必要だ。公式READMEの対応表と導入条件
画面の内容を読む道具には、プライバシー上の扱いも伴う。スナップショット、窓のタイトル、クリップボード、スクリーンショット、操作履歴には私的な情報が入りうる。基本のCLIに遠隔のAIサービスは必須ではないが、別途用意された任意の補助機能は設定したモデル提供者へ画面の説明を送る。開発元FAQが説明するデータの扱い
agent-desktopが足すものは、クリック命令の種類より、「押してよい根拠がない」「押したが結果は未確認」をAIへ返せる共通の約束だ。ブラウザー内の仕事には専用ツール、Windows固有の精密な操作にはそのOS向けの道具、見た目だけに現れる対象には画像の手掛かりがある。複数OSのデスクトップアプリを意味に沿って操作したいなら、この参照IDと再確認の設計が試す理由になる。では自分のアプリは、間違った対象を押さないための情報をOSへ十分に公開しているだろうか。
キーワード:#agent-desktop
出典
- 公式README:操作の基本手順、対応OS、インストール方法と機能一覧
- 開発元のCargo設定:共通コア、OS別実装、CLI、C向けライブラリーの構成とバージョン
- 開発元の概念説明:アクセシビリティ情報、スナップショット、参照IDと再同定の設計
- 開発元の変更履歴:1.0.0から1.0.2までの公開日と修正内容
- 開発元のJSON仕様:操作結果、古い参照、再試行可否と検証状態
- 開発元のFAQ:構成、用途、画面内容の扱いと任意の外部モデル連携
- 2026年11月3日に確認したRust実装:snapshotコマンドの引数、浅い観察と出力項目
- 同実装:参照IDの対象が取得時に窓内で一意だったかを証明する条件
- 同実装:保存した参照IDを操作時に窓内で再同定する処理
- 同実装:浅い表示と一意性判定用の窓全体の観察を分ける処理
- 同実装:領域を掘り下げる際に既存参照を更新する条件
- 同実装:操作を一度送った後の状態読み直しと検証
- 同実装:操作の到達状態と再試行可否の対応
- 同実装:スナップショット参照のローカル保存と件数制限
- 同実装:要素名を複数の候補から決める際に読み取り失敗を扱う方法
- 同実装:操作できる要素へ参照IDを割り当てる条件
- 同実装:背後での操作と前面の物理入力を分ける許可条件
- 同実装:macOSのアクセシビリティ操作の呼び出し
- 同実装:WindowsのUI Automationによる操作候補と失敗時の扱い
- 同実装:LinuxのAT-SPI操作を呼ぶ経路
- PyAutoGUI公式文書:3つのOSでのマウス・キーボード操作と画像検索
- pywinauto公式文書:WindowsのWin32・UI Automationを使う要素操作と対応範囲
- agent-browser公式README:ブラウザーのアクセシビリティ情報から参照IDを得る操作
コメント
まだコメントはありません。