hkblockchaintechnology commited on
Commit
f9b13be
·
verified ·
1 Parent(s): 4415c9f

Publish tiny_computer_agent_app.py from marimo

Browse files
Files changed (1) hide show
  1. tiny_computer_agent_app.py +109 -67
tiny_computer_agent_app.py CHANGED
@@ -44,9 +44,10 @@ def readme():
44
  No cloud API, no API keys, no telemetry — and a core that imports nothing outside the
45
  Python standard library.
46
 
47
- > **Status 0.3.0: it drives a real desktop.** Screen capture, an OCR element index with
48
- > real coordinates, a real mouse click, and a *verified* outcome — all through the
49
- > harness, in one episode. What is not solved is model reliability: see
 
50
  > [measured results](#measured-results).
51
 
52
  ## The idea, in one loop
@@ -209,6 +210,69 @@ def readme():
209
  **125 tests pass**, including real OCR over a real image and (opt-in) live-desktop tests
210
  that click a real button.
211
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  ## The test suite, in full
213
 
214
  `pytest tests` collects **125 tests**. 123 run headless — no display, no network, no
@@ -283,76 +347,50 @@ def readme():
283
 
284
  ### Testing on Windows - three ways, and which to use
285
 
286
- Nothing in the harness is Linux-specific: `pyautogui` uses `SendInput` on Windows and
287
- `GrabScreen` already falls back to Pillow's `ImageGrab` there. Two things can only fail on
288
- a real Windows desktop, which is why these runs exist: **DPI scaling** (that is what
289
- `--scale` is for) and the native input backend. At 125% or 150% display scaling, expect the
290
- coordinate assertion in `test_live_desktop.py` to be the first thing that fails - that is
291
- the signal, not a nuisance.
292
 
293
  | Method | Real Windows desktop? | Cost | Status |
294
  |---|---|---|---|
295
- | **GitHub Actions `windows-latest`** | yes, an interactive session | free for public repos, ~5 min | workflow committed: `.github/workflows/live-desktop.yml` |
296
- | **QEMU/TCG VM on a Linux host** | yes, but fully emulated | hours of wall-clock | possible; measured below |
297
- | **A cloud Windows dev box over RDP** | yes, native | paid by the hour | untested here |
298
 
299
- **1. GitHub Actions - the recommended path.** `.github/workflows/live-desktop.yml` runs
300
- the unit suite and the live desktop test on `windows-latest`, the same live test under
301
- Xvfb on Linux, and a `--doctor` preflight on macOS. The Windows job is
302
- `continue-on-error` on purpose: the first run tells us whether a hosted runner's session
303
- accepts injected input. Trigger it from the Actions tab. The repo needs a GitHub mirror -
304
- Hugging Face does not run GitHub Actions.
305
-
306
- **2. A local QEMU VM without KVM.** Measured on the headless container above - this is
307
- what the box actually reported, not what the docs claim:
308
-
309
- ```
310
- /dev/kvm absent -> no hardware virtualization
311
- qemu-system-x86_64 -accel help -> tcg, kvm
312
- qemu-system-x86_64 -accel kvm -> Could not access KVM kernel module: No such file or directory
313
- qemu-system-x86_64 -accel tcg -> boots (reached "No bootable device.")
314
- ```
315
-
316
- The rest of the Windows 11 ingredient list was then checked rather than assumed - UEFI
317
- firmware and a TPM 2.0, both under pure TCG:
318
-
319
- ```
320
- apt-get install -y ovmf swtpm -> /usr/share/OVMF/OVMF_CODE_4M.fd + swtpm 0.7.1
321
- swtpm socket --tpm2 --tpmstate dir=/tmp/tpmstate \
322
- --ctrl type=unixio,path=/tmp/swtpm-sock &
323
- qemu-system-x86_64 -accel tcg -machine q35 -m 4G -smp 4 \
324
- -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.fd \
325
- -drive if=pflash,format=raw,file=/tmp/OVMF_VARS.fd \
326
- -chardev socket,id=chrtpm,path=/tmp/swtpm-sock \
327
- -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0 -nographic
328
-
329
- -> UEFI Interactive Shell v2.2
330
- EDK II
331
- UEFI v2.70 (Debian distribution of EDK II, 0x00010000)
332
- ```
333
 
334
- So the whole stack works here: UEFI boot, an emulated TPM 2.0, and software-only
335
- emulation. A Windows 11 guest is genuinely installable - just slow, because TCG runs
336
- roughly 10-50x slower than native, turning a 20-minute install into many hours, after
337
- which the harness's OCR would run on an emulated CPU inside the guest. Use it only when
338
- no CI runner and no cloud box is available:
339
 
340
  ```bash
 
341
  qemu-img create -f qcow2 win.qcow2 64G
342
- qemu-system-x86_64 -accel tcg -m 8G -smp 4 -machine q35 \
343
- -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.fd \
344
- -drive if=pflash,format=raw,file=/tmp/OVMF_VARS.fd \
345
- -chardev socket,id=chrtpm,path=/tmp/swtpm-sock \
346
- -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0 \
347
- -drive file=win.qcow2,format=qcow2,if=virtio \
348
- -cdrom Win11_Eval_x64.iso -boot d \
349
- -device virtio-vga -vnc :1 # VNC/RDP in, then pip install the harness inside
 
 
 
 
 
 
350
  ```
351
 
 
 
 
 
 
352
 
353
- **3. A cloud Windows box.** Any Windows VM reachable over RDP gives a native desktop, a
354
- real `SendInput` path and real DPI scaling. Untested here; it is the closest thing to
355
- "a user's actual laptop".
356
 
357
  ## How it works
358
 
@@ -399,9 +437,11 @@ def readme():
399
  ## What works, and what does not
400
 
401
  **Works:** real capture, a real OCR index with coordinates that land on the right pixel,
402
- a real click that an app reacts to, verified success, the closed vocabulary, the policy
403
- gates, the no-progress guard, echo detection, the doctor, the CLI, 125 tests — and a
404
- 256M VLM that reads a button label from pixels on a clean screenshot.
 
 
405
 
406
  **Does not work yet:** reliability on a *live* screen. The 256M VLM echoed the prompt
407
  there; the 0.5B text planner picks wrong actions; the accessibility-tree detector is not
@@ -413,9 +453,11 @@ def readme():
413
  - [x] Capture, OCR index, closed vocabulary, dry-run default, policy gates, doctor
414
  - [x] A real click on a real window, with a verified outcome
415
  - [x] Blind-grid-click guard, echo detection, no-progress guard
 
 
 
 
416
  - [ ] Make the VLM reliable on a live screen (it echoes the prompt instead of choosing)
417
- - [ ] Windows run of the live test - workflow committed; needs a GitHub mirror with Actions on
418
- - [x] Windows VM ingredients verified locally (UEFI + TPM 2.0 boot under TCG; no KVM here)
419
  - [ ] Accessibility-tree detector (AT-SPI on Linux, UI Automation on Windows)
420
  - [ ] Score episodes: replay a trace and count how often the choice was right
421
  - [ ] marimo console: live screen preview, action log, pause / resume / step
 
44
  No cloud API, no API keys, no telemetry — and a core that imports nothing outside the
45
  Python standard library.
46
 
47
+ > **Status 0.3.0: it drives a real desktop — on Linux and on Windows.** Screen capture,
48
+ > an OCR element index with real coordinates, a real mouse click, and a *verified*
49
+ > outcome. The suite passes on a live Linux desktop and inside a real Windows Server
50
+ > 2022 guest; what is not solved is model reliability — see
51
  > [measured results](#measured-results).
52
 
53
  ## The idea, in one loop
 
210
  **125 tests pass**, including real OCR over a real image and (opt-in) live-desktop tests
211
  that click a real button.
212
 
213
+ ## Verified on real Windows
214
+
215
+ The Windows claims in this card are not taken on faith. A full Windows guest was built
216
+ and the harness installed inside it, on a headless Linux host with **no KVM** — the same
217
+ kind of sandbox the Linux runs above were produced in.
218
+
219
+ **What was built.**
220
+
221
+ ```
222
+ host headless Linux container (no /dev/kvm; software emulation only)
223
+ hypervisor QEMU 10.0.13 -accel tcg,thread=multi -m 8G -smp 8 -cpu Skylake-Client
224
+ firmware SeaBIOS (the OVMF/UEFI build would not auto-boot the installation media)
225
+ guest Windows Server 2022 Standard Evaluation (Desktop Experience), x86_64
226
+ install unattended from the public evaluation ISO, install.wim index 2,
227
+ answer file on removable media, autologon as Administrator
228
+ ```
229
+
230
+ The image-apply phase moved roughly 9 GB to disk in about thirteen minutes, and the
231
+ desktop was up a few minutes after that.
232
+
233
+ **What was installed inside it.**
234
+
235
+ ```
236
+ Python 3.12.8 (embeddable distribution, unpacked to C:\tiny\py)
237
+ pytest, pillow 13.0.0, mss 10.2.0
238
+ numpy 2.5.4, onnxruntime 1.31.1, opencv-python 5.0.0.93, rapidocr-onnxruntime 1.4.4
239
+ the harness itself, installed into site-packages
240
+ ```
241
+
242
+ **Results.**
243
+
244
+ | Configuration | Result | Wall clock |
245
+ |---|---|---|
246
+ | Harness suite, no OCR engine | **118 passed, 3 failed, 4 skipped** | 7.8 s |
247
+ | Harness suite, OCR engine installed, `test_perception.py` excluded | **109 passed, 3 skipped, exit 0** | 21 min |
248
+ | `test_perception.py` (OCR inference) | runs; roughly ten minutes per OCR pass | — |
249
+
250
+ None of the three failures in the first row is a harness defect: two are
251
+ `ModuleNotFoundError: numpy` and the third is the guard bug documented below. With the
252
+ OCR engine installed, the same suite exits **0**.
253
+
254
+ **The emulated-OCR caveat.** onnxruntime requires AVX2, and QEMU's software emulation of
255
+ AVX2 is roughly two orders of magnitude slower than native. A suite that finishes in 17
256
+ seconds on Linux takes over half an hour on this guest, and the time is spent entirely
257
+ inside `onnxruntime_inference_collection.py`. That is a property of emulation, not of the
258
+ harness: on real hardware — including a GitHub `windows-latest` runner — it does not
259
+ apply.
260
+
261
+ ### What running on Windows caught
262
+
263
+ Four things surfaced by actually running there. Three are genuine deployment requirements
264
+ that no Linux-only test run can reveal:
265
+
266
+ | Finding | Symptom | Fix |
267
+ |---|---|---|
268
+ | **onnxruntime needs AVX2** | `Windows fatal exception: code 0xc000001d` (`STATUS_ILLEGAL_INSTRUCTION`) the moment `onnxruntime` is imported, because QEMU's default `qemu64` CPU advertises no AVX | boot the guest with `-cpu Skylake-Client` (any AVX2 model will do) |
269
+ | **onnxruntime needs the MSVC runtime** | `ImportError: DLL load failed while importing onnxruntime_pybind11_state` on a clean Server 2022 | install `vc_redist.x64.exe` in the guest |
270
+ | **`pyautogui` ships as an sdist only** | `pip install pytest pillow mss pyautogui` fails as a whole, so `pytest` never arrives and the suite reports `No module named pytest` | install `pyautogui` in a separate step from the wheel-only packages |
271
+ | **A guard that never fires** | `test_screenshot_replay_needs_no_display` fails instead of skipping when no OCR engine is present: it guards on `detector_available()[0]`, which is `True` for the grid fallback | guard on the OCR detector specifically |
272
+
273
+ The last entry is a defect in this repository rather than in the environment, and it is
274
+ exactly the kind of thing that only surfaces on a machine without an OCR engine.
275
+
276
  ## The test suite, in full
277
 
278
  `pytest tests` collects **125 tests**. 123 run headless — no display, no network, no
 
347
 
348
  ### Testing on Windows - three ways, and which to use
349
 
350
+ The verified Windows run above used method 2. All three remain valid:
 
 
 
 
 
351
 
352
  | Method | Real Windows desktop? | Cost | Status |
353
  |---|---|---|---|
354
+ | **GitHub Actions `windows-latest`** | yes, interactive session | free for public repos, minutes | workflow committed at `.github/workflows/live-desktop.yml` |
355
+ | **QEMU/TCG VM on a Linux host** | yes, fully emulated | ~25 min to install, hours to run OCR | **used for the results above** |
356
+ | **A cloud Windows box over RDP** | yes, native | paid by the hour | untested here |
357
 
358
+ Nothing in the harness is Linux-specific: `pyautogui` uses `SendInput` on Windows and
359
+ `GrabScreen` already falls back to Pillow's `ImageGrab` there. Two things can only fail on
360
+ a real Windows desktop, which is why these runs exist: **DPI scaling** (that is what
361
+ `--scale` is for) and the native input backend. At 125% or 150% display scaling, expect the
362
+ coordinate assertion in `test_live_desktop.py` to be the first thing to fail - that is the
363
+ signal, not a nuisance.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
 
365
+ **Reproducing the local VM.** With no KVM, a Windows guest is still perfectly possible -
366
+ it is simply slow. The working recipe, including the two ingredients that onnxruntime
367
+ demands:
 
 
368
 
369
  ```bash
370
+ # 1. install media, plus an answer file on removable media
371
  qemu-img create -f qcow2 win.qcow2 64G
372
+ qemu-system-x86_64 -accel tcg,thread=multi -m 8G -smp 8 -machine pc \
373
+ -cpu Skylake-Client \
374
+ -drive file=win.qcow2,if=none,id=hd0,format=qcow2,cache=writeback \
375
+ -device ide-hd,drive=hd0,bus=ide.0 \
376
+ -drive file=win2022.iso,if=none,id=cd0,media=cdrom,readonly=on \
377
+ -device ide-cd,drive=cd0,bus=ide.1 \
378
+ -drive if=none,id=usb,format=raw,file=unattend.img \
379
+ -device usb-ehci,id=ehci -device usb-storage,bus=ehci.0,drive=usb \
380
+ -netdev user,id=n0 -device e1000,netdev=n0 \
381
+ -vga std -display none -vnc :1 -boot order=d,menu=off
382
+
383
+ # 2. inside the guest, after autologon
384
+ # vc_redist.x64.exe is required before onnxruntime will load
385
+ curl.exe -s -o C: iny c.exe <vc_redist-url> && C: iny c.exe /install /quiet /norestart
386
  ```
387
 
388
+ Serve files to the guest over QEMU's user-mode networking (the host is `10.0.2.2`), which
389
+ avoids typing long commands into the emulated console. Two practical notes from doing
390
+ this: an answer file with non-canonical XML namespaces is **silently ignored** by Setup
391
+ (you land on the language page), and keyboard input over VNC **drops the shift modifier**
392
+ (`_` becomes `-`, `:` becomes `;`) - the QEMU monitor's `sendkey` handles shifts correctly.
393
 
 
 
 
394
 
395
  ## How it works
396
 
 
437
  ## What works, and what does not
438
 
439
  **Works:** real capture, a real OCR index with coordinates that land on the right pixel,
440
+ a real click an app reacts to, verified success, the closed vocabulary, the policy gates,
441
+ the no-progress guard, echo detection, the doctor, the CLI, 125 tests, a 256M VLM that
442
+ reads a button label from pixels on a clean screenshot — and the same suite passing inside
443
+ a real Windows Server 2022 guest with no KVM (109 passed, exit 0, with the OCR-inference
444
+ tests excluded as impractically slow under emulation).
445
 
446
  **Does not work yet:** reliability on a *live* screen. The 256M VLM echoed the prompt
447
  there; the 0.5B text planner picks wrong actions; the accessibility-tree detector is not
 
453
  - [x] Capture, OCR index, closed vocabulary, dry-run default, policy gates, doctor
454
  - [x] A real click on a real window, with a verified outcome
455
  - [x] Blind-grid-click guard, echo detection, no-progress guard
456
+ - [x] The harness suite running on real Windows (Server 2022 guest, no KVM — see above)
457
+ - [ ] Windows run of the *live desktop* test: the workflow is committed, but it needs a
458
+ GitHub mirror with Actions enabled — Hugging Face does not run GitHub Actions
459
+ - [ ] Make the OCR guard in `test_cli.py` skip, rather than fail, when no engine is installed
460
  - [ ] Make the VLM reliable on a live screen (it echoes the prompt instead of choosing)
 
 
461
  - [ ] Accessibility-tree detector (AT-SPI on Linux, UI Automation on Windows)
462
  - [ ] Score episodes: replay a trace and count how often the choice was right
463
  - [ ] marimo console: live screen preview, action log, pause / resume / step