hkblockchaintechnology commited on
Commit
598cca6
·
verified ·
1 Parent(s): 783bfb0

Publish README.md from marimo

Browse files
Files changed (1) hide show
  1. README.md +152 -16
README.md CHANGED
@@ -74,6 +74,69 @@ The click landed on the button, the app changed its own window to "Saved", and t
74
  verifier confirmed it before the episode was called a success. **Pixels in, a real click
75
  out, and evidence that it worked.**
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  ### On a replayed screenshot
78
 
79
  ```
@@ -89,6 +152,23 @@ named the right target:
89
  step 0 | click label='Save' reason="the reply names 'Save'" -> pixel (295, 284)
90
  ```
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  ### What did *not* work, and what caught it
93
 
94
  - **The 256M VLM echoes the prompt on a busy live screen.** Asked to click Save on the
@@ -103,16 +183,42 @@ named the right target:
103
  `warning: no text was found on screen, so the index is 96 numbered grid cells and the
104
  agent is choosing blind` — instead of silently guessing.
105
 
106
- **123 tests pass**, including real OCR over a real image and (opt-in) live-desktop tests
107
  that click a real button.
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  ## Install
110
 
111
  ```bash
112
  pip install -e ".[ocr]" # labels from pixels (RapidOCR: no system binary)
113
  pip install -e ".[desktop,ocr]" # + real capture and real input
114
  pip install -e ".[vision,ocr]" # + the tiny model brains
115
- pytest # 123 tests, no display or network needed
116
  ```
117
 
118
  ## Run it on your machine
@@ -152,20 +258,50 @@ That test starts its own Tk window, asserts OCR finds the button at the coordina
152
  was actually drawn at, clicks it for real, and checks the app reacted. It is opt-in
153
  because it moves your mouse — run it on a throwaway desktop.
154
 
155
- ### Testing on Windows (or macOS)
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
- This repo's live test was run on Linux/X11, because that is what the build container
158
- had. For real Windows coverage, mirror the repo to GitHub: `.github/workflows/live-desktop.yml`
159
- runs the unit suite **and** the live desktop test on `windows-latest` — a real Windows
160
- desktop session, free for public repositories — plus the same test under Xvfb on Linux,
161
- and a preflight on macOS. Trigger it from the Actions tab.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
- Nothing in the harness is Linux-specific: pyautogui uses `SendInput` on Windows, and
164
- `GrabScreen` already falls back to Pillow's `ImageGrab` there. Two things can only fail
165
- on a real Windows desktop, which is exactly why the job exists: **DPI scaling** (that is
166
- what `--scale` is for) and the native input backend. At 125% or 150% display scaling,
167
- expect the coordinate assertion in `test_live_desktop.py` to be the first thing that
168
- fails — that is the signal, not a nuisance.
169
 
170
  ## How it works
171
 
@@ -213,7 +349,7 @@ success.
213
 
214
  **Works:** real capture, a real OCR index with coordinates that land on the right pixel,
215
  a real click that an app reacts to, verified success, the closed vocabulary, the policy
216
- gates, the no-progress guard, echo detection, the doctor, the CLI, 123 tests — and a
217
  256M VLM that reads a button label from pixels on a clean screenshot.
218
 
219
  **Does not work yet:** reliability on a *live* screen. The 256M VLM echoed the prompt
@@ -227,7 +363,7 @@ when no verifier is given.
227
  - [x] A real click on a real window, with a verified outcome
228
  - [x] Blind-grid-click guard, echo detection, no-progress guard
229
  - [ ] Make the VLM reliable on a live screen (it echoes the prompt instead of choosing)
230
- - [ ] Windows run of the live test (workflow included; needs a GitHub mirror)
231
  - [ ] Accessibility-tree detector (AT-SPI on Linux, UI Automation on Windows)
232
  - [ ] Score episodes: replay a trace and count how often the choice was right
233
  - [ ] marimo console: live screen preview, action log, pause / resume / step
 
74
  verifier confirmed it before the episode was called a success. **Pixels in, a real click
75
  out, and evidence that it worked.**
76
 
77
+ ### Re-confirmed end to end on a headless Linux box
78
+
79
+ The whole path above was re-run from scratch on a headless Debian container (gVisor
80
+ sandbox, 20 vCPU, no GPU, no physical display, no network at run time) behind a virtual
81
+ X server. First the suite, headless:
82
+
83
+ ```bash
84
+ python -m pip install -e ".[desktop,ocr,dev]"
85
+ pytest tests -q
86
+ # 123 passed, 2 skipped in 18.6s
87
+ ```
88
+
89
+ The two skips are the live-desktop tests. Give them a display and they run for real:
90
+
91
+ ```bash
92
+ Xvfb :99 -screen 0 1280x800x24 &
93
+ export DISPLAY=:99
94
+ TINY_COMPUTER_AGENT_LIVE_TEST=1 python -m pytest tests/test_live_desktop.py -q
95
+ # tests/test_live_desktop.py::test_ocr_finds_a_real_button_at_the_right_pixels PASSED
96
+ # tests/test_live_desktop.py::test_a_real_click_lands_on_the_button PASSED
97
+ # 2 passed
98
+ ```
99
+
100
+ Then the same desktop, driven through the CLI with the mouse actually live:
101
+
102
+ ```bash
103
+ export TINY_COMPUTER_AGENT_ALLOW_REAL_INPUT=1
104
+ python -m tiny_computer_agent --live --real-input --verify-text Saved "click 'Save' to save the document"
105
+ ```
106
+
107
+ ```
108
+ goal: click 'Save' to save the document
109
+ mode: REAL INPUT (mouse and keyboard live) | screen: real desktop (monitor 1) | brain: planner | kill switch: create /tmp/tiny-computer-agent.STOP to stop
110
+ index: auto - OCR when it finds text, grid otherwise (rapidocr-onnxruntime ready (CPU, offline))
111
+
112
+ step 0 | click label='Save' reason="matched 'Save' in the element index" | ok: clicked (194, 296)
113
+
114
+ result: success - verified after 1 action(s)
115
+ ```
116
+
117
+ The window was drawn at `+120+120` with its Save button at `x=20, y=155, 110x40`, so the
118
+ button centre is `(195, 295)`. The click at `(194, 296)` is *on the button*, not near it —
119
+ and the app wrote `Save` back to its own marker file. Pixels in, a real click out, and the
120
+ app's own side effect as the proof.
121
+
122
+ `--doctor` on that box, with the virtual display attached:
123
+
124
+ ```
125
+ tiny-computer-agent preflight (Linux x86_64, python 3.13.11)
126
+
127
+ [ok ] display server: DISPLAY=:99
128
+ [ok ] pillow: installed
129
+ [ok ] screen capture: mss (fast, multi-monitor)
130
+ [ok ] input backend (pyautogui): installed
131
+ [ok ] element detector (auto): OCR when it finds text, grid otherwise (rapidocr-onnxruntime ready (CPU, offline))
132
+ [ok ] model runtime: not needed: the planner is rule-based (no weights, no download)
133
+ [ok ] execution mode: dry run (nothing is clicked)
134
+ [ok ] kill switch: create /tmp/tiny-computer-agent.STOP to abort the next action
135
+
136
+ READY: the harness can drive this desktop.
137
+ ```
138
+
139
+
140
  ### On a replayed screenshot
141
 
142
  ```
 
152
  step 0 | click label='Save' reason="the reply names 'Save'" -> pixel (295, 284)
153
  ```
154
 
155
+ ### Which brain drove which run
156
+
157
+ The harness and the brain are separable, and it matters which one a result came from.
158
+ None of the runs below used a cloud API; the two model brains run on CPU:
159
+
160
+ | Run | Brain | Weights | Outcome |
161
+ |---|---|---|---|
162
+ | Live Linux desktop, real click | `PlannerBrain` (rule-based) | none | **success, verified** |
163
+ | `/tmp/saveapp.py` window live | `PlannerBrain` | none | clicked `Save` at `(194, 296)` |
164
+ | `--image example` | `PlannerBrain` | none | picked `Save`, pixel `(295, 284)` |
165
+ | `--image example` | `VLMBrain` (SmolVLM-256M-Instruct) | 256M, CPU | picked `Save` |
166
+ | Live Linux desktop | `VLMBrain` (SmolVLM-256M-Instruct) | 256M, CPU | echoed the prompt; **refused** by echo detection |
167
+ | Live Linux desktop | `TextPlannerBrain` (Qwen2.5-0.5B) | 0.5B, CPU | clicked Cancel, then garbled JSON; budget exhausted |
168
+
169
+ The rule-based planner is what carries the verified end-to-end runs. The tiny model is the
170
+ open problem: it is reliable on a clean screenshot and unreliable on a busy live screen.
171
+
172
  ### What did *not* work, and what caught it
173
 
174
  - **The 256M VLM echoes the prompt on a busy live screen.** Asked to click Save on the
 
183
  `warning: no text was found on screen, so the index is 96 numbered grid cells and the
184
  agent is choosing blind` — instead of silently guessing.
185
 
186
+ **125 tests pass**, including real OCR over a real image and (opt-in) live-desktop tests
187
  that click a real button.
188
 
189
+ ## The test suite, in full
190
+
191
+ `pytest tests` collects **125 tests**. 123 run headless — no display, no network, no
192
+ weights. The last 2 are the opt-in live-desktop tests, skipped unless
193
+ `TINY_COMPUTER_AGENT_LIVE_TEST=1`.
194
+
195
+ | File | Tests | What it proves |
196
+ |---|---:|---|
197
+ | `tests/test_actions.py` | 13 | the closed vocabulary — every action is validated before anything executes |
198
+ | `tests/test_act.py` | 8 | `DryRunExecutor` is inert; the real executor refuses until explicitly armed |
199
+ | `tests/test_observe.py` | 8 | element/observation geometry, `FakeScreen`, `ImageScreen`, the capture fallback |
200
+ | `tests/test_perception.py` | 13 | OCR labels a real image with real coordinates; the grid fallback; `AutoDetector` |
201
+ | `tests/test_brain.py` | 18 | the numbered `DecisionMenu`, lenient parsing, echo detection, `MockBrain`, `PlannerBrain` |
202
+ | `tests/test_loop.py` | 14 | `AgentLoop` / `Episode` / `Step`, the no-progress guard, the step budget |
203
+ | `tests/test_verify.py` | 7 | success is only claimed when a verifier can actually see it |
204
+ | `tests/test_safety.py` | 11 | deny lists, the kill switch, the blind-grid-click guard |
205
+ | `tests/test_grid_fallback.py` | 11 | the fallback index announces itself instead of guessing |
206
+ | `tests/test_desktop.py` | 10 | display detection, the preflight checks, `doctor` |
207
+ | `tests/test_cli.py` | 10 | the command line: `--doctor`, `--image`, `--live`, argument handling |
208
+ | `tests/test_live_desktop.py` | 2 | **needs a display, opt-in**: OCR finds a real button at the pixels it was drawn at, and a real click makes the app react |
209
+
210
+ ```bash
211
+ pytest tests -q # 123 passed, 2 skipped
212
+ TINY_COMPUTER_AGENT_LIVE_TEST=1 pytest tests -q # 125 passed, on a desktop
213
+ ```
214
+
215
  ## Install
216
 
217
  ```bash
218
  pip install -e ".[ocr]" # labels from pixels (RapidOCR: no system binary)
219
  pip install -e ".[desktop,ocr]" # + real capture and real input
220
  pip install -e ".[vision,ocr]" # + the tiny model brains
221
+ pytest # 125 tests, no display or network needed
222
  ```
223
 
224
  ## Run it on your machine
 
258
  was actually drawn at, clicks it for real, and checks the app reacted. It is opt-in
259
  because it moves your mouse — run it on a throwaway desktop.
260
 
261
+ ### Testing on Windows - three ways, and which to use
262
+
263
+ Nothing in the harness is Linux-specific: `pyautogui` uses `SendInput` on Windows and
264
+ `GrabScreen` already falls back to Pillow's `ImageGrab` there. Two things can only fail on
265
+ a real Windows desktop, which is why these runs exist: **DPI scaling** (that is what
266
+ `--scale` is for) and the native input backend. At 125% or 150% display scaling, expect the
267
+ coordinate assertion in `test_live_desktop.py` to be the first thing that fails - that is
268
+ the signal, not a nuisance.
269
+
270
+ | Method | Real Windows desktop? | Cost | Status |
271
+ |---|---|---|---|
272
+ | **GitHub Actions `windows-latest`** | yes, an interactive session | free for public repos, ~5 min | workflow committed: `.github/workflows/live-desktop.yml` |
273
+ | **QEMU/TCG VM on a Linux host** | yes, but fully emulated | hours of wall-clock | possible; measured below |
274
+ | **A cloud Windows dev box over RDP** | yes, native | paid by the hour | untested here |
275
 
276
+ **1. GitHub Actions - the recommended path.** `.github/workflows/live-desktop.yml` runs
277
+ the unit suite and the live desktop test on `windows-latest`, the same live test under
278
+ Xvfb on Linux, and a `--doctor` preflight on macOS. The Windows job is
279
+ `continue-on-error` on purpose: the first run tells us whether a hosted runner's session
280
+ accepts injected input. Trigger it from the Actions tab. The repo needs a GitHub mirror -
281
+ Hugging Face does not run GitHub Actions.
282
+
283
+ **2. A local QEMU VM without KVM.** Measured on the headless container above:
284
+
285
+ ```
286
+ /dev/kvm absent -> no hardware virtualization
287
+ qemu-system-x86_64 -accel help -> tcg, kvm
288
+ qemu-system-x86_64 -accel kvm -> Could not access KVM kernel module: No such file or directory
289
+ qemu-system-x86_64 -accel tcg -> boots (reached "No bootable device.")
290
+ ```
291
+
292
+ So a Windows guest is *possible* with no KVM at all, but entirely under software
293
+ emulation. TCG runs roughly 10-50x slower than native, which turns a 20-minute Windows
294
+ install into many hours - and the harness's OCR would then run on an emulated CPU inside
295
+ the guest. Use this only when no CI runner and no cloud box is available:
296
+
297
+ ```bash
298
+ qemu-img create -f qcow2 win.qcow2 64G
299
+ qemu-system-x86_64 -accel tcg -m 8G -smp 4 -drive file=win.qcow2,format=qcow2,if=virtio -cdrom Win11_Eval_x64.iso -boot d -device virtio-vga -vnc :1 # then RDP/VNC in, pip install the harness inside
300
+ ```
301
 
302
+ **3. A cloud Windows box.** Any Windows VM reachable over RDP gives a native desktop, a
303
+ real `SendInput` path and real DPI scaling. Untested here; it is the closest thing to
304
+ "a user's actual laptop".
 
 
 
305
 
306
  ## How it works
307
 
 
349
 
350
  **Works:** real capture, a real OCR index with coordinates that land on the right pixel,
351
  a real click that an app reacts to, verified success, the closed vocabulary, the policy
352
+ gates, the no-progress guard, echo detection, the doctor, the CLI, 125 tests — and a
353
  256M VLM that reads a button label from pixels on a clean screenshot.
354
 
355
  **Does not work yet:** reliability on a *live* screen. The 256M VLM echoed the prompt
 
363
  - [x] A real click on a real window, with a verified outcome
364
  - [x] Blind-grid-click guard, echo detection, no-progress guard
365
  - [ ] Make the VLM reliable on a live screen (it echoes the prompt instead of choosing)
366
+ - [ ] Windows run of the live test - workflow committed; needs a GitHub mirror with Actions on
367
  - [ ] Accessibility-tree detector (AT-SPI on Linux, UI Automation on Windows)
368
  - [ ] Score episodes: replay a trace and count how often the choice was right
369
  - [ ] marimo console: live screen preview, action log, pause / resume / step