agentvision 0.3.0__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. {agentvision-0.3.0 → agentvision-0.3.2}/CHANGELOG.md +46 -0
  2. {agentvision-0.3.0 → agentvision-0.3.2}/PKG-INFO +30 -1
  3. {agentvision-0.3.0 → agentvision-0.3.2}/README.md +29 -0
  4. agentvision-0.3.2/docs/field-report-rhtrader.md +180 -0
  5. agentvision-0.3.2/docs/unified-architecture.png +0 -0
  6. agentvision-0.3.2/docs/unified-architecture.svg +143 -0
  7. {agentvision-0.3.0 → agentvision-0.3.2}/pyproject.toml +1 -1
  8. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/__init__.py +1 -1
  9. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/adapters/cli.py +105 -23
  10. agentvision-0.3.2/src/agentvision/backends/_image.py +37 -0
  11. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/backends/anthropic_backend.py +3 -2
  12. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/backends/gemini_backend.py +3 -2
  13. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/backends/ollama_backend.py +3 -2
  14. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/backends/openai_backend.py +3 -2
  15. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/config.py +10 -2
  16. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/analyze.py +16 -1
  17. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/intent.py +55 -2
  18. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/render.py +4 -0
  19. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/renderers/base.py +6 -0
  20. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/renderers/playwright_renderer.py +96 -9
  21. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/sources.py +2 -1
  22. agentvision-0.3.2/tests/unit/test_field_report_fixes.py +105 -0
  23. agentvision-0.3.0/src/agentvision/backends/_image.py +0 -21
  24. {agentvision-0.3.0 → agentvision-0.3.2}/.github/workflows/ci.yml +0 -0
  25. {agentvision-0.3.0 → agentvision-0.3.2}/.gitignore +0 -0
  26. {agentvision-0.3.0 → agentvision-0.3.2}/Dockerfile +0 -0
  27. {agentvision-0.3.0 → agentvision-0.3.2}/LICENSE +0 -0
  28. {agentvision-0.3.0 → agentvision-0.3.2}/docs/VISION.md +0 -0
  29. {agentvision-0.3.0 → agentvision-0.3.2}/docs/adapters.md +0 -0
  30. {agentvision-0.3.0 → agentvision-0.3.2}/docs/backends.md +0 -0
  31. {agentvision-0.3.0 → agentvision-0.3.2}/docs/banner.png +0 -0
  32. {agentvision-0.3.0 → agentvision-0.3.2}/docs/conformance.md +0 -0
  33. {agentvision-0.3.0 → agentvision-0.3.2}/docs/handoff.md +0 -0
  34. {agentvision-0.3.0 → agentvision-0.3.2}/docs/integrations.md +0 -0
  35. {agentvision-0.3.0 → agentvision-0.3.2}/docs/quickstart.md +0 -0
  36. {agentvision-0.3.0 → agentvision-0.3.2}/docs/the-loop.md +0 -0
  37. {agentvision-0.3.0 → agentvision-0.3.2}/examples/broken_layout.fixed.html +0 -0
  38. {agentvision-0.3.0 → agentvision-0.3.2}/examples/broken_layout.html +0 -0
  39. {agentvision-0.3.0 → agentvision-0.3.2}/examples/contact_sheet.py +0 -0
  40. {agentvision-0.3.0 → agentvision-0.3.2}/examples/fix_loop.py +0 -0
  41. {agentvision-0.3.0 → agentvision-0.3.2}/integrations/agent-contract.md +0 -0
  42. {agentvision-0.3.0 → agentvision-0.3.2}/integrations/aider.md +0 -0
  43. {agentvision-0.3.0 → agentvision-0.3.2}/integrations/cursor.rules.md +0 -0
  44. {agentvision-0.3.0 → agentvision-0.3.2}/skill/SKILL.md +0 -0
  45. {agentvision-0.3.0 → agentvision-0.3.2}/skill/scripts/see.sh +0 -0
  46. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/adapters/__init__.py +0 -0
  47. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/adapters/_demo_assets.py +0 -0
  48. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/adapters/doctor.py +0 -0
  49. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/adapters/mcp_server.py +0 -0
  50. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/adapters/rest.py +0 -0
  51. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/backends/__init__.py +0 -0
  52. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/backends/base.py +0 -0
  53. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/backends/local_backend.py +0 -0
  54. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/backends/prompt.py +0 -0
  55. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/backends/registry.py +0 -0
  56. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/backends/schema_adapters.py +0 -0
  57. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/__init__.py +0 -0
  58. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/baseline.py +0 -0
  59. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/capture.py +0 -0
  60. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/checks/__init__.py +0 -0
  61. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/checks/contrast.py +0 -0
  62. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/checks/layout.py +0 -0
  63. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/checks/spelling.py +0 -0
  64. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/diff.py +0 -0
  65. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/generate.py +0 -0
  66. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/core/loop.py +0 -0
  67. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/errors.py +0 -0
  68. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/logging.py +0 -0
  69. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/models/__init__.py +0 -0
  70. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/models/diff.py +0 -0
  71. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/models/geometry.py +0 -0
  72. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/models/handoff.py +0 -0
  73. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/models/intent.py +0 -0
  74. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/models/report.py +0 -0
  75. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/ocr/__init__.py +0 -0
  76. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/ocr/base.py +0 -0
  77. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/ocr/tesseract.py +0 -0
  78. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/renderers/__init__.py +0 -0
  79. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/renderers/_extract_js.py +0 -0
  80. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/renderers/image_renderer.py +0 -0
  81. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/renderers/pdf_renderer.py +0 -0
  82. {agentvision-0.3.0 → agentvision-0.3.2}/src/agentvision/workspace.py +0 -0
  83. {agentvision-0.3.0 → agentvision-0.3.2}/tests/integration/test_render_loop.py +0 -0
  84. {agentvision-0.3.0 → agentvision-0.3.2}/tests/unit/test_generate.py +0 -0
  85. {agentvision-0.3.0 → agentvision-0.3.2}/tests/unit/test_handoff.py +0 -0
  86. {agentvision-0.3.0 → agentvision-0.3.2}/tests/unit/test_intent.py +0 -0
  87. {agentvision-0.3.0 → agentvision-0.3.2}/tests/unit/test_local_backend.py +0 -0
  88. {agentvision-0.3.0 → agentvision-0.3.2}/tests/unit/test_models.py +0 -0
  89. {agentvision-0.3.0 → agentvision-0.3.2}/tests/unit/test_schema_adapters.py +0 -0
  90. {agentvision-0.3.0 → agentvision-0.3.2}/tests/unit/test_sources.py +0 -0
  91. {agentvision-0.3.0 → agentvision-0.3.2}/tests/unit/test_spelling.py +0 -0
  92. {agentvision-0.3.0 → agentvision-0.3.2}/tests/unit/test_workspace.py +0 -0
@@ -55,6 +55,52 @@ clean, provider-agnostic handoff — it perceives and hands off, it does not dec
55
55
  brain's sense adapter can keep it for provenance yet exclude it from gating (this honors the
56
56
  contract Verel's `verel.senses.sight` already documents and tests).
57
57
 
58
+ ## [0.3.2] — 2026-06-19
59
+
60
+ ### Fixed — v0.3.1 retest residuals (canvas/WebGL visual path)
61
+ Two residual findings from re-grading the live WebGL dashboard, both on the vision path for
62
+ **visual (non-text) elements**:
63
+
64
+ - **Freeze no longer blanks canvas/WebGL scenes that build inside `requestAnimationFrame`.**
65
+ Freeze is now *canvas-aware*: CSS animations/transitions are still paused, but when a
66
+ `<canvas>` is present rAF is left running and the renderer waits `canvas_settle_ms`
67
+ (default 1500) so the scene draws before capture ("settle-then-freeze"). Heavy scenes can
68
+ still raise `--settle-ms`. (Static pages keep the full rAF freeze.)
69
+ - **Vision "missing" claims about visual elements are overruled by the DOM.** The renderer
70
+ reports sizable `canvas`/`svg`/`img`/`video` elements (`RenderResult.visual_tags`); a vision
71
+ `missing_element`/`intent_mismatch` that names a visual (canvas, chart, 3D scene, image…)
72
+ is suppressed when the matching element is actually present — so a downscaled/blurry full
73
+ page no longer false-fails a chart or canvas that demonstrably exists.
74
+
75
+ ## [0.3.1] — 2026-06-19
76
+
77
+ ### Fixed / changed — live-dashboard field report (rhtrader)
78
+ Hardening from grading a live, continuously-polling WebGL dashboard. The biggest wins:
79
+ don't default to `networkidle`, settle/freeze before capture, and never let a vision
80
+ "missing" claim survive when DOM/OCR proves the element is present.
81
+
82
+ - **`nav_wait` default is now `load`** (was `networkidle`). Polling/websocket pages never
83
+ go idle and used to hang to `RenderTimeout`. When `networkidle` *is* requested it is now
84
+ **bounded** (≤5s) and falls through instead of blocking. `--nav-wait` is a CLI flag.
85
+ - **Settle + freeze before capture.** A short post-load settle (`settle_ms`, default 400)
86
+ lets client-rendered data populate (fixes false "blank/missing" on the shell-then-fill
87
+ frame); `freeze_animations` (default on) pauses CSS animations + the `requestAnimationFrame`
88
+ loop and the screenshot uses `animations="disabled"`, so canvas/WebGL/animation-heavy pages
89
+ (incl. **`--full-page`**) capture deterministically instead of timing out. `--settle-ms`,
90
+ `--freeze/--no-freeze`, and `--wait-for <selector>` are CLI flags.
91
+ - **Vision claims cross-checked against DOM/OCR ground truth.** An advisory vision
92
+ `missing_element` / `intent_mismatch` finding is suppressed when the quoted element text is
93
+ actually present in the DOM/OCR — killing the false-fail class entirely.
94
+ - **Intent text claims grade against DOM *and* OCR**, so `--expect 'must: "…"'` is
95
+ deterministic even with no OCR/no key (the text is read from the DOM).
96
+ - **Oversized screenshots are downscaled** before the vision LLM (`vision_max_edge_px`,
97
+ default 2000) — large/dense images made models return lazy/generic critiques.
98
+ - **`--allow-local`** CLI flag for localhost / LAN dev servers (clearer than the env var),
99
+ and the `UnsafeSourceError` now names it.
100
+ - **`--quiet` machine mode**: only the JSON object on stdout (logs on stderr), errors as a
101
+ JSON `{"error": …}`, stable exit codes (0 pass/warn, 2 fail, 3 error).
102
+ - **Default `render_timeout_s` raised to 60s** and exposed as `--render-timeout`.
103
+
58
104
  ## [0.2.0] — 2026-06-18
59
105
 
60
106
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentvision
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Eyes for AI Agents — a machine-graded visual feedback loop coding agents consume to self-correct before claiming done.
5
5
  Project-URL: Homepage, https://github.com/amitpatole/agent-vision
6
6
  Project-URL: Repository, https://github.com/amitpatole/agent-vision
@@ -161,6 +161,23 @@ agentvision analyze ./page.html --handoff
161
161
  `report.to_handoff()`, the MCP `perceive_handoff` tool, `POST /handoff`, and a `handoff.json`
162
162
  per loop iteration — provider- and brain-agnostic. See [docs/handoff.md](docs/handoff.md).
163
163
 
164
+ ## Eyes & Brain — AgentVision × Verel
165
+
166
+ AgentVision is the **eyes**. It pairs with **[Verel](https://github.com/amitpatole/verel)**,
167
+ the **brain** — an agent framework where *nothing is "done" until a grader returns a verdict.*
168
+ The eyes perceive and grade intent; the brain decides with attestation and **compounds only
169
+ verified work** into memory; then the eyes look again.
170
+
171
+ <p align="center">
172
+ <img src="docs/unified-architecture.png" alt="Eyes & Brain — AgentVision perceives and grades intent; Verel decides and compounds verified work into memory" width="100%">
173
+ </p>
174
+
175
+ They ship and version independently (`pip install agentvision`, `pip install verel`) yet work
176
+ in sync: AgentVision plugs into Verel as its `verel.senses` perception organ — mapped onto a
177
+ unified verdict bus (vision *alongside* tests, lint and types), with intent conformance
178
+ recorded in the brain's memory each iteration. AgentVision stays brain-agnostic; Verel is the
179
+ reference brain. See [docs/handoff.md](docs/handoff.md).
180
+
164
181
  ## Many faces, one core
165
182
 
166
183
  | Surface | Who it's for |
@@ -221,6 +238,18 @@ agentvision baseline ./index.html --name home
221
238
  agentvision regress ./index.html --name home
222
239
  ```
223
240
 
241
+ **Live pages, SPAs & dashboards** (polling, websockets, canvas/WebGL):
242
+
243
+ ```bash
244
+ # localhost dev server, wait for the data to render, freeze animation, machine output
245
+ agentvision analyze http://localhost:5173 --allow-local \
246
+ --wait-for "#dashboard" --settle-ms 800 --quiet
247
+ ```
248
+
249
+ `--nav-wait` defaults to `load` (polling pages never go idle); `--freeze` (default on) pauses
250
+ animations + `requestAnimationFrame` so canvas/WebGL pages capture without hanging; `--quiet`
251
+ prints only JSON (logs to stderr, exit codes 0 pass/warn · 2 fail · 3 error).
252
+
224
253
  Library:
225
254
 
226
255
  ```python
@@ -97,6 +97,23 @@ agentvision analyze ./page.html --handoff
97
97
  `report.to_handoff()`, the MCP `perceive_handoff` tool, `POST /handoff`, and a `handoff.json`
98
98
  per loop iteration — provider- and brain-agnostic. See [docs/handoff.md](docs/handoff.md).
99
99
 
100
+ ## Eyes & Brain — AgentVision × Verel
101
+
102
+ AgentVision is the **eyes**. It pairs with **[Verel](https://github.com/amitpatole/verel)**,
103
+ the **brain** — an agent framework where *nothing is "done" until a grader returns a verdict.*
104
+ The eyes perceive and grade intent; the brain decides with attestation and **compounds only
105
+ verified work** into memory; then the eyes look again.
106
+
107
+ <p align="center">
108
+ <img src="docs/unified-architecture.png" alt="Eyes & Brain — AgentVision perceives and grades intent; Verel decides and compounds verified work into memory" width="100%">
109
+ </p>
110
+
111
+ They ship and version independently (`pip install agentvision`, `pip install verel`) yet work
112
+ in sync: AgentVision plugs into Verel as its `verel.senses` perception organ — mapped onto a
113
+ unified verdict bus (vision *alongside* tests, lint and types), with intent conformance
114
+ recorded in the brain's memory each iteration. AgentVision stays brain-agnostic; Verel is the
115
+ reference brain. See [docs/handoff.md](docs/handoff.md).
116
+
100
117
  ## Many faces, one core
101
118
 
102
119
  | Surface | Who it's for |
@@ -157,6 +174,18 @@ agentvision baseline ./index.html --name home
157
174
  agentvision regress ./index.html --name home
158
175
  ```
159
176
 
177
+ **Live pages, SPAs & dashboards** (polling, websockets, canvas/WebGL):
178
+
179
+ ```bash
180
+ # localhost dev server, wait for the data to render, freeze animation, machine output
181
+ agentvision analyze http://localhost:5173 --allow-local \
182
+ --wait-for "#dashboard" --settle-ms 800 --quiet
183
+ ```
184
+
185
+ `--nav-wait` defaults to `load` (polling pages never go idle); `--freeze` (default on) pauses
186
+ animations + `requestAnimationFrame` so canvas/WebGL pages capture without hanging; `--quiet`
187
+ prints only JSON (logs to stderr, exit codes 0 pass/warn · 2 fail · 3 error).
188
+
160
189
  Library:
161
190
 
162
191
  ```python
@@ -0,0 +1,180 @@
1
+ # Field report: AgentVision on a live trading dashboard (rhtrader)
2
+
3
+ > **Status: all 8 addressed in v0.3.1.** Summary of fixes:
4
+ > 1. `nav_wait` defaults to `load`; `networkidle` is now bounded (≤5s) — no more hangs.
5
+ > 2. Freeze (pause CSS animations + rAF) + `screenshot(animations="disabled")` → full-page
6
+ > capture works on canvas/WebGL/animation-heavy pages (`--freeze`, default on).
7
+ > 3. Post-load settle (`settle_ms`, default 400) + discoverable `--wait-for <selector>` →
8
+ > no false "blank/missing" on the shell-then-fill frame.
9
+ > 4. Oversized screenshots downscaled before the vision LLM (`--vision_max_edge_px`/2000);
10
+ > **vision `missing_element` claims cross-checked against DOM/OCR and suppressed if the
11
+ > element is provably present.**
12
+ > 5. Text claims grade against DOM **and** OCR — deterministic even with no OCR/no key.
13
+ > 6. `--allow-local` CLI flag (and the error message names it).
14
+ > 7. `--quiet` machine mode: JSON-only stdout, logs to stderr, stable exit codes (0/2/3).
15
+ > 8. Default `render_timeout_s` raised to 60s; exposed as `--render-timeout`.
16
+
17
+
18
+ Real drawbacks hit while using AgentVision (`agentvision analyze`, `local` + `openai`
19
+ backends) to grade and fix a live, continuously-polling, WebGL dashboard
20
+ (`http://localhost:8910/` — a stdlib HTTP server rendering a cockpit that polls
21
+ `/state.json` every 3s and runs a three.js scene with a perpetual `requestAnimationFrame`
22
+ loop). Dated 2026-06-19. Ordered by impact. Each item: **what happened → impact →
23
+ suggested enhancement.**
24
+
25
+ ## 1. `networkidle` (the default `nav_wait`) hangs forever on polling pages
26
+ - **What:** the dashboard polls `/state.json` every 3s, so the network is never idle.
27
+ `analyze <url>` hit `RenderTimeout: Render exceeded 30.0s (hanging page?)`. Only
28
+ `AGENTVISION_NAV_WAIT=load` unblocked it.
29
+ - **Impact:** out-of-the-box failure on *any* live dashboard / SPA with polling or
30
+ websockets — arguably the most common "real" target.
31
+ - **Suggestion:** don't default to `networkidle`; default to `load` + a short fixed
32
+ settle, OR cap the networkidle wait (e.g. 3–5s of quiet) and fall back to `load`
33
+ automatically. At minimum, when `RenderTimeout` fires, the message should suggest
34
+ `nav_wait=load`.
35
+
36
+ ## 2. Continuously-animating pages never "settle" → full-page capture times out
37
+ - **What:** `--full-page` timed out even with `nav_wait=load` and
38
+ `AGENTVISION_RENDER_TIMEOUT_S=75`. Root cause: the three.js scene animates forever
39
+ (rAF), and full-page scroll-and-stitch waits for stability that never comes.
40
+ Viewport-only worked; full-page did not.
41
+ - **Impact:** can't grade the whole page on any canvas/WebGL/animation-heavy app.
42
+ - **Suggestion:** a "freeze before capture" mode — pause rAF (override
43
+ `requestAnimationFrame`), set `* { animation-play-state: paused !important;
44
+ transition: none !important }`, and/or `prefers-reduced-motion` — then snapshot.
45
+ Or a hard `--settle-ms N` that snapshots regardless of stability.
46
+
47
+ ## 3. Captures at `load` BEFORE client-rendered data populates → false "blank/missing"
48
+ - **What:** the page renders its shell at `load`, then JS fills the metric cards/data a
49
+ beat later. AgentVision captured the in-between frame; the vision backend then
50
+ reported plainly-present elements ("TODAY'S NET", regime, equity curve…) as **missing**
51
+ (`matches_intent: false`, 10+ false `[intent/must]` items). The actual screenshot
52
+ (artifact) showed a fully-populated page — the capture was just early.
53
+ - **Impact:** systematically wrong verdicts on client-rendered UIs; erodes trust.
54
+ - **Suggestion:** make `--wait-for <selector>` / `--settle-ms` first-class in
55
+ `analyze --help` (the selector path exists in the renderer but isn't discoverable);
56
+ consider a default small post-`load` settle (e.g. 800ms); or wait for DOM mutations
57
+ to quiesce.
58
+
59
+ ## 4. Vision-LLM gives lazy/hallucinated output on large/dense images
60
+ - **What:** with `--backend openai` on a `1440x1600` screenshot, the model returned a
61
+ generic checklist-echo ("everything missing"), clearly not reading the image. The
62
+ **same** model on a focused `1280x720` viewport produced a genuinely useful, specific
63
+ critique (low-contrast amber, icon crowding, "booting…" confusion, missing section
64
+ grouping). The failure correlated with image size/density.
65
+ - **Impact:** large pages silently get garbage critiques.
66
+ - **Suggestion:** (a) downscale/tile oversized screenshots before sending and/or warn
67
+ when an image exceeds a model-friendly size; (b) **cross-check vision
68
+ `missing_element` claims against DOM/OCR ground truth and suppress contradicted
69
+ ones** — if the DOM/OCR clearly contains the element, don't emit a vision "missing"
70
+ finding. This single guard would have prevented the entire false-fail above.
71
+
72
+ ## 5. Intent-conformance wasn't actually deterministic in practice
73
+ - **What:** docs say text claims grade deterministically via OCR, but with the `openai`
74
+ backend, `--expect 'must: shows "TODAY'S NET"'` came back failed even though that exact
75
+ text is large and OCR-able and present.
76
+ - **Impact:** `--expect`/`--brief` conformance can't be trusted when a vision backend is
77
+ selected.
78
+ - **Suggestion:** grade `--expect` text claims via OCR **independently** of the vision
79
+ model's holistic judgment, and report per-claim which grader decided it (ocr vs
80
+ vision) so the user can tell deterministic from advisory.
81
+
82
+ ## 6. SSRF guard blocks localhost/LAN with only an env-var escape hatch
83
+ - **What:** `analyze http://localhost:8910/` →
84
+ `UnsafeSourceError: Refusing to render 'localhost' … (SSRF protection)`. Fixed only via
85
+ `AGENTVISION_BLOCK_PRIVATE_NETWORKS=false`.
86
+ - **Impact:** the most common dev target (a localhost dev server) is blocked by default
87
+ with no obvious CLI flag.
88
+ - **Suggestion:** a `--allow-local` / `--lan` CLI flag (clearer than the env var), and
89
+ let the `UnsafeSourceError` message name that flag.
90
+
91
+ ## 7. Machine-readable output is hard to capture reliably
92
+ - **What:** `--handoff` / `--json` output was intermittently empty on stdout, sometimes
93
+ appeared mixed with Rich/console formatting, and some runs exited non-zero with no
94
+ parseable body. We had to regex-extract the JSON object (`{…}`) from mixed output and
95
+ retry.
96
+ - **Impact:** brittle to script around (and scripting is the whole point for agents/CI).
97
+ - **Suggestion:** a strict `--quiet`/`--machine` mode that writes **only** the JSON
98
+ object to stdout (all logs/Rich to stderr), with documented, stable exit codes.
99
+
100
+ ## 8. Default `render_timeout_s` (30s) is low for heavy SPA/WebGL
101
+ - **What:** 30s wasn't enough once the page was non-trivial; bumping via
102
+ `AGENTVISION_RENDER_TIMEOUT_S` was necessary (though for full-page the real fix is #2,
103
+ not a bigger timeout).
104
+ - **Suggestion:** raise the default a bit and/or expose `--render-timeout` as a CLI flag
105
+ (currently env-only).
106
+
107
+ ---
108
+
109
+ ### What worked well (keep)
110
+ - The **`local` backend** (DOM geometry + WCAG contrast + OCR/typo) was reliable and
111
+ trustworthy throughout — it correctly found **106 real WCAG-AA contrast violations** on
112
+ first run and a clean **PASS / 0 issues** after the fix. The deterministic path is the
113
+ star; the advisory vision path needs the guardrails above.
114
+ - The **handoff shape** (`perceived` / `next_action` / `todo` / `open_questions`) mapped
115
+ cleanly into a Verel verdict-bus gate.
116
+
117
+ ### One-line meta-takeaway
118
+ The biggest wins are **(a) don't default to `networkidle`, (b) settle/freeze before
119
+ capture, and (c) never let a vision "missing_element" claim survive when DOM/OCR proves
120
+ the element is present.** Those three remove ~all the false fails we hit.
121
+
122
+ ---
123
+
124
+ ## v0.3.1 retest (2026-06-19) — confirmed fixes + TWO residual findings
125
+
126
+ Re-ran against the same dashboard on **v0.3.1**. Confirmed working: full-page no longer
127
+ times out (freeze), `--allow-local`, `--settle-ms`, `--quiet` (JSON-only, exit 0/2/3),
128
+ console-error capture (it caught our WebGL GPU-stall warnings), and — the big one —
129
+ **OCR-literal `--expect` claims (`"TODAY'S NET"`, `"EQUITY CURVE"`, `"OPEN POSITIONS"`)
130
+ are now correctly recognized as present** (previously all false-missing). Two new things
131
+ surfaced:
132
+
133
+ ### 9. `--freeze` (default ON) pauses rAF → WebGL/canvas scenes that *build* via rAF never render
134
+ - **What:** our three.js scene builds its first frame *inside* the `requestAnimationFrame`
135
+ loop. With `--freeze` (default), rAF is paused before that first build, so the canvas
136
+ stays empty and the vision backend reports **"no 3D scene"** — a false negative. With
137
+ `--no-freeze` + `--settle-ms 6000`, the full scene rendered correctly (verified: floor,
138
+ figures, ticker ring, bins all present).
139
+ - **Impact:** freeze (great for CSS-animation determinism) silently breaks grading of any
140
+ WebGL/canvas/game UI that lazy-builds in rAF.
141
+ - **Suggestion:** freeze CSS animations/transitions by default but **let rAF run for N ms
142
+ (or until the canvas has drawn a non-blank frame) BEFORE pausing it** — i.e.
143
+ "settle-then-freeze," not "freeze-then-settle." Or auto-detect a `<canvas>` and switch
144
+ to no-freeze. At minimum, document that WebGL targets need `--no-freeze`.
145
+
146
+ ### 10. Full-page downscale makes small-but-present *visual* elements read as "missing"
147
+ - **What:** the full page is ~3350px tall; downscaled to the vision max edge (~2000px),
148
+ the 3D-scene region becomes small/blurry, and the model reported the (clearly present)
149
+ scene as missing. The DOM/OCR cross-check (fix #4) saves **text** claims but not
150
+ **visual-only** regions like a `<canvas>`.
151
+ - **Impact:** intent claims about non-text visuals (charts, canvases, images) still
152
+ false-fail on tall pages.
153
+ - **Suggestion:** for a visual intent claim, resolve the relevant DOM node's bbox and send
154
+ the model a **focused, full-res crop** of that region instead of (or in addition to) the
155
+ downscaled whole page. And extend the cross-check: if a `<canvas>`/`<img>` of meaningful
156
+ size exists where the claim expects a visual, suppress the vision "missing" finding (or
157
+ drop it to `warn`/advisory) just like the text path.
158
+
159
+ ### Net for v0.3.1
160
+ Infra drawbacks (#1–#8) are resolved — full-page works, localhost works, output is
161
+ clean/scriptable, and text-conformance is trustworthy. The remaining gaps are both about
162
+ the **vision-LLM path on visual (non-OCR) elements**: don't freeze rAF before a canvas
163
+ draws, and crop-to-bbox for visual intent claims rather than judging a downscaled whole
164
+ page.
165
+
166
+ ---
167
+
168
+ ## v0.3.2 — residuals #9 & #10 addressed
169
+
170
+ - **#9 (rAF-built canvas blanked by freeze):** freeze is now *canvas-aware*. CSS animations
171
+ are still paused, but when a `<canvas>` is present rAF is left running and the renderer
172
+ waits `canvas_settle_ms` (default 1500) so the scene builds before capture
173
+ ("settle-then-freeze"). Verified: a canvas that draws only inside rAF now renders non-blank
174
+ with `--freeze` on (default). Heavy scenes can still bump `--settle-ms`.
175
+ - **#10 (visual element read as "missing" on a downscaled full page):** the renderer now
176
+ reports present `canvas`/`svg`/`img`/`video` (`RenderResult.visual_tags`), and a vision
177
+ "missing" claim naming a visual (canvas, chart, 3D scene, image…) is **suppressed when the
178
+ matching element is actually in the DOM** — extending the text cross-check to the visual
179
+ path. (A focused full-res crop-to-bbox per visual claim remains a future quality
180
+ enhancement; the false-fail itself is now prevented.)
@@ -0,0 +1,143 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1600" height="1060" viewBox="0 0 1600 1060" font-family="Inter, Segoe UI, Helvetica, Arial, sans-serif">
2
+ <defs>
3
+ <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
4
+ <stop offset="0" stop-color="#0c0f17"/>
5
+ <stop offset="1" stop-color="#0f1320"/>
6
+ </linearGradient>
7
+ <linearGradient id="eyeGlow" x1="0" y1="0" x2="1" y2="1">
8
+ <stop offset="0" stop-color="#5ad1e6"/>
9
+ <stop offset="1" stop-color="#3a9fd6"/>
10
+ </linearGradient>
11
+ <linearGradient id="brainGlow" x1="0" y1="0" x2="1" y2="1">
12
+ <stop offset="0" stop-color="#8b7cff"/>
13
+ <stop offset="1" stop-color="#b06cff"/>
14
+ </linearGradient>
15
+ <linearGradient id="nerve" x1="0" y1="0" x2="1" y2="0">
16
+ <stop offset="0" stop-color="#5ad1e6"/>
17
+ <stop offset="1" stop-color="#8b7cff"/>
18
+ </linearGradient>
19
+ <marker id="ah" markerWidth="12" markerHeight="12" refX="8" refY="4" orient="auto">
20
+ <path d="M0,0 L8,4 L0,8 Z" fill="#8b7cff"/>
21
+ </marker>
22
+ <marker id="ahb" markerWidth="14" markerHeight="14" refX="9" refY="5" orient="auto">
23
+ <path d="M0,0 L10,5 L0,10 Z" fill="#46d39a"/>
24
+ </marker>
25
+ </defs>
26
+
27
+ <rect width="1600" height="1060" fill="url(#bg)"/>
28
+
29
+ <!-- Title -->
30
+ <text x="800" y="66" text-anchor="middle" font-size="48" font-weight="800" fill="#eef2fb">Eyes &amp; Brain</text>
31
+ <text x="800" y="104" text-anchor="middle" font-size="22" fill="#9aa4b8">AgentVision <tspan fill="#5ad1e6">sees</tspan> · Verel <tspan fill="#8b7cff">decides</tspan> · only <tspan fill="#46d39a">verified</tspan> work ships</text>
32
+
33
+ <!-- ================= EYES PANEL ================= -->
34
+ <rect x="56" y="150" width="610" height="700" rx="22" fill="#12161f" stroke="#274050" stroke-width="1.5"/>
35
+ <text x="92" y="200" font-size="15" letter-spacing="3" fill="#5ad1e6" font-weight="700">THE EYES · PERCEPTION</text>
36
+ <text x="92" y="246" font-size="38" font-weight="800" fill="#eef2fb">AgentVision</text>
37
+ <!-- eye glyph -->
38
+ <g transform="translate(566,210)">
39
+ <ellipse cx="0" cy="0" rx="44" ry="26" fill="none" stroke="url(#eyeGlow)" stroke-width="4"/>
40
+ <circle cx="0" cy="0" r="13" fill="#5ad1e6"/>
41
+ <circle cx="5" cy="-5" r="4" fill="#0c0f17"/>
42
+ </g>
43
+ <text x="92" y="282" font-size="17" fill="#9aa4b8">It writes a UI, chart, SVG, PDF or image — and actually looks at the result.</text>
44
+
45
+ <!-- pipeline -->
46
+ <g font-size="16" font-weight="700" text-anchor="middle">
47
+ <rect x="92" y="312" width="118" height="46" rx="10" fill="#14202a" stroke="#2f5163"/>
48
+ <text x="151" y="341" fill="#cfe9f2">RENDER</text>
49
+ <rect x="232" y="312" width="118" height="46" rx="10" fill="#14202a" stroke="#2f5163"/>
50
+ <text x="291" y="341" fill="#cfe9f2">PERCEIVE</text>
51
+ <rect x="372" y="312" width="118" height="46" rx="10" fill="#14202a" stroke="#2f5163"/>
52
+ <text x="431" y="341" fill="#cfe9f2">REPORT</text>
53
+ <rect x="512" y="312" width="118" height="46" rx="10" fill="#14202a" stroke="#2f5163"/>
54
+ <text x="571" y="341" fill="#cfe9f2">DIFF</text>
55
+ <text x="221" y="341" fill="#5ad1e6">›</text>
56
+ <text x="361" y="341" fill="#5ad1e6">›</text>
57
+ <text x="501" y="341" fill="#5ad1e6">›</text>
58
+ </g>
59
+
60
+ <!-- trust card -->
61
+ <rect x="92" y="386" width="538" height="146" rx="14" fill="#101a22" stroke="#23323d"/>
62
+ <text x="112" y="416" font-size="18" font-weight="700" fill="#eef2fb">Grounded truth, not vibes</text>
63
+ <text x="112" y="446" font-size="16" fill="#bfe7f0">▪ DOM geometry + computed-style WCAG contrast — <tspan fill="#46d39a">precise</tspan></text>
64
+ <text x="112" y="474" font-size="16" fill="#bfe7f0">▪ OCR word boxes + spelling/typo check — <tspan fill="#46d39a">precise</tspan></text>
65
+ <text x="112" y="502" font-size="16" fill="#bfe7f0">▪ Vision-LLM critique (Claude/GPT/Gemini/Ollama) — <tspan fill="#f5b14c">advisory</tspan></text>
66
+
67
+ <!-- conformance card -->
68
+ <rect x="92" y="548" width="538" height="150" rx="14" fill="#101a22" stroke="#23323d"/>
69
+ <text x="112" y="578" font-size="18" font-weight="700" fill="#eef2fb">Matches intent, not just defects</text>
70
+ <text x="112" y="608" font-size="16" fill="#bfe7f0">brief / checklist / reference → a render is graded per requirement</text>
71
+ <text x="112" y="636" font-size="16" fill="#bfe7f0">must · should · nice → <tspan fill="#46d39a">satisfied</tspan> · <tspan fill="#ff7a7a">violated</tspan> · <tspan fill="#f5b14c">uncertain</tspan></text>
72
+ <text x="112" y="664" font-size="16" fill="#9aa4b8">PASS means “it’s what we set out to build,” not “nothing’s broken.”</text>
73
+
74
+ <!-- handoff output pill -->
75
+ <rect x="92" y="716" width="538" height="104" rx="14" fill="#0e2230" stroke="#2f6f7e"/>
76
+ <text x="112" y="752" font-size="18" font-weight="800" fill="#5ad1e6">The handoff →</text>
77
+ <text x="112" y="782" font-size="15" fill="#cfe9f2">verdict · next_action · matches_intent · todo[] · open_questions[]</text>
78
+ <text x="112" y="806" font-size="14" fill="#9aa4b8">a clean afferent signal — the eyes report, they don’t decide</text>
79
+
80
+ <!-- ================= OPTIC NERVE ================= -->
81
+ <text x="800" y="430" text-anchor="middle" font-size="14" letter-spacing="2" fill="#9aa4b8">THE OPTIC NERVE</text>
82
+ <line x1="676" y1="470" x2="924" y2="470" stroke="url(#nerve)" stroke-width="7" marker-end="url(#ah)"/>
83
+ <g text-anchor="middle" font-size="14" font-weight="700">
84
+ <rect x="690" y="492" width="220" height="34" rx="17" fill="#13202b" stroke="#2f5163"/>
85
+ <text x="800" y="514" fill="#bfe7f0">perception → decision</text>
86
+ </g>
87
+ <text x="800" y="560" text-anchor="middle" font-size="14" fill="#9aa4b8">grounded observations + a verdict,</text>
88
+ <text x="800" y="580" text-anchor="middle" font-size="14" fill="#9aa4b8">mapped onto one bus the brain trusts</text>
89
+
90
+ <!-- ================= BRAIN PANEL ================= -->
91
+ <rect x="934" y="150" width="610" height="700" rx="22" fill="#15131f" stroke="#3a2f5e" stroke-width="1.5"/>
92
+ <text x="970" y="200" font-size="15" letter-spacing="3" fill="#b6a6ff" font-weight="700">THE BRAIN · DECISION + MEMORY</text>
93
+ <text x="970" y="246" font-size="38" font-weight="800" fill="#eef2fb">Verel</text>
94
+ <!-- brain glyph -->
95
+ <g transform="translate(1444,212)">
96
+ <circle cx="0" cy="0" r="30" fill="none" stroke="url(#brainGlow)" stroke-width="4"/>
97
+ <circle cx="-12" cy="-6" r="4" fill="#8b7cff"/><circle cx="8" cy="-12" r="4" fill="#8b7cff"/>
98
+ <circle cx="12" cy="8" r="4" fill="#8b7cff"/><circle cx="-8" cy="10" r="4" fill="#8b7cff"/>
99
+ <path d="M-12,-6 L8,-12 M8,-12 L12,8 M12,8 L-8,10 M-8,10 L-12,-6" stroke="#6a5acf" stroke-width="1.5" fill="none"/>
100
+ </g>
101
+ <text x="970" y="282" font-size="17" fill="#9aa4b8">Nothing is “done” until a grader returns a verdict.</text>
102
+
103
+ <!-- five organs -->
104
+ <g font-size="16">
105
+ <rect x="970" y="312" width="258" height="76" rx="12" fill="#1a1730" stroke="#3a2f5e"/>
106
+ <text x="986" y="340" font-weight="700" fill="#eef2fb">⚖ Verdict bus</text>
107
+ <text x="986" y="366" font-size="13" fill="#b6a6ff">vision + tests + lint + types → one pass/warn/fail</text>
108
+
109
+ <rect x="1250" y="312" width="258" height="76" rx="12" fill="#1a1730" stroke="#3a2f5e"/>
110
+ <text x="1266" y="340" font-weight="700" fill="#eef2fb">Memory that compounds</text>
111
+ <text x="1266" y="366" font-size="13" fill="#b6a6ff">only verified facts/skills graduate</text>
112
+
113
+ <rect x="970" y="402" width="258" height="76" rx="12" fill="#16202a" stroke="#2f5163"/>
114
+ <text x="986" y="430" font-weight="700" fill="#cfe9f2">Eyes = AgentVision</text>
115
+ <text x="986" y="456" font-size="13" fill="#7fd3e6">perception as one sense among many</text>
116
+
117
+ <rect x="1250" y="402" width="258" height="76" rx="12" fill="#1a1730" stroke="#3a2f5e"/>
118
+ <text x="1266" y="430" font-weight="700" fill="#eef2fb">Fleet</text>
119
+ <text x="1266" y="456" font-size="13" fill="#b6a6ff">agents managing agents, gated by the bus</text>
120
+
121
+ <rect x="970" y="492" width="538" height="76" rx="12" fill="#1a1730" stroke="#3a2f5e"/>
122
+ <text x="986" y="520" font-weight="700" fill="#eef2fb">Tool-smith</text>
123
+ <text x="986" y="546" font-size="13" fill="#b6a6ff">agents build, test &amp; register their own tools — sandboxed, admitted only on a passing eval</text>
124
+ </g>
125
+
126
+ <!-- compounds pill -->
127
+ <rect x="970" y="588" width="538" height="110" rx="14" fill="#10231b" stroke="#2f6f55"/>
128
+ <text x="990" y="624" font-size="18" font-weight="800" fill="#46d39a">Only verified work compounds</text>
129
+ <text x="990" y="654" font-size="15" fill="#c8e9da">the brain decides with grader attestation — a hollow check can’t mint green</text>
130
+ <text x="990" y="680" font-size="14" fill="#9aa4b8">records “did it match what we set out to build?” across every iteration</text>
131
+
132
+ <!-- brain decision output -->
133
+ <rect x="970" y="716" width="538" height="104" rx="14" fill="#1a1730" stroke="#4a3f7e"/>
134
+ <text x="990" y="752" font-size="18" font-weight="800" fill="#b6a6ff">The decision →</text>
135
+ <text x="990" y="782" font-size="15" fill="#d7ccff">done · revise (act on the to-do) · review</text>
136
+ <text x="990" y="806" font-size="14" fill="#9aa4b8">a full brain runs its own gate; a simpler brain can use the handoff verbatim</text>
137
+
138
+ <!-- ================= EFFERENT LOOP ================= -->
139
+ <path d="M1230,866 C 1100,948 520,948 372,894" fill="none" stroke="#46d39a" stroke-width="4" stroke-dasharray="2 0" marker-end="url(#ahb)"/>
140
+ <rect x="612" y="906" width="376" height="44" rx="22" fill="#10231b" stroke="#2f6f55"/>
141
+ <text x="800" y="934" text-anchor="middle" font-size="16" font-weight="700" fill="#c8e9da">decide → act (edit code / refine prompt) → look again</text>
142
+ <text x="800" y="1000" text-anchor="middle" font-size="18" fill="#9aa4b8">render → perceive → gate → fix → re-render → <tspan fill="#46d39a" font-weight="700">pass</tspan> — the loop where “done” becomes a verdict, not an opinion</text>
143
+ </svg>
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "agentvision"
7
- version = "0.3.0"
7
+ version = "0.3.2"
8
8
  description = "Eyes for AI Agents — a machine-graded visual feedback loop coding agents consume to self-correct before claiming done."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -42,7 +42,7 @@ from .models import (
42
42
  Viewport,
43
43
  )
44
44
 
45
- __version__ = "0.3.0"
45
+ __version__ = "0.3.2"
46
46
 
47
47
  __all__ = [
48
48
  "__version__",