feat: describe-ui --no-raw and skill guidance to keep agent context small#63
feat: describe-ui --no-raw and skill guidance to keep agent context small#634faramita wants to merge 6 commits into
Conversation
43bfccb to
c1c05be
Compare
onevclaw
left a comment
There was a problem hiding this comment.
I’m reviewing this as @onevcat’s assistant. The implementation and test suite look good, but two documentation issues should be corrected before merge:
skills/sim-use/SKILL.md:68presentstap --label 'X' --wait-timeout 3as cross-platform guidance. Android'stapcommand does not support--wait-timeout, and the top-level Android path does not forward timing. Please scope this advice to iOS or add equivalent Android support.skills/sim-use/SKILL.md:64says--jsonshould be used only for untruncated text, but the same document explains that coordinate calculations need structured fields such asentries[].frameandscreen. Please revise this to include structured/coordinate use cases as well.
An Android raw: nil serialization test would also be a useful follow-up, but the two documentation corrections above are the blocking items.
onevclaw - an assistant to @onevcat
|
@onevclaw Please take another claw |
onevpaw
left a comment
There was a problem hiding this comment.
The new --no-raw option is correctly wired through the CLI layers, but the Viewer snapshot path still invokes describe-ui --json in ViewerAPIHandlers.swift and then discards raw entirely. Since the Viewer polls this path continuously while playback is active, it continues to incur the raw-tree transfer and decoding cost this change is intended to avoid.
Please add --no-raw to that invocation and cover the spawned arguments in ViewerAPIHandlersTests.swift to prevent a regression. It would also be worth updating the comments that describe raw == nil as occurring only without --json, since --json --no-raw now has that result as well.
onevpaw - an assistant to @onevcat
data.raw is the raw accessibility tree passed through for debugging sim-use itself; on real app screens it dominates the encoded envelope (~70% measured on a busy screen, 26.6KB -> 9.7KB with the flag) and larger screens can push the payload past agent tool-output truncation limits mid-JSON. The flag is available on all three surfaces (describe-ui, ios describe-ui, android describe-ui); outline/entries/lists and the default --json shape are unchanged. Signed-off-by: 4faramita <14917258+4faramita@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a "Keeping output small" section to SKILL.md: prefer the text outline over --json, pair --json with --no-raw, verify via the outline instead of screenshots, reuse the verify read as the next observe, and batch known sequences. Point the cheatsheet's --json note at --no-raw. Signed-off-by: 4faramita <14917258+4faramita@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The wait-out-a-transition tip presented tap --wait-timeout as cross-platform, but the flag is iOS-only (the Android backend has no wait-timeout and the top-level Android path forwards no timing) -- scope the tip to iOS and point Android at sleep. The --json guidance said "only when you need full untruncated text", contradicting the Observe section's coordinate-math use of entries[].frame / screen -- name both use cases. Also add the Android DescribeUIResult raw-key omission test suggested in review. Signed-off-by: 4faramita <14917258+4faramita@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Viewer's /api/snapshot handler spawns describe-ui --json but only forwards outline/entries/lists, discarding raw -- and it polls continuously during playback, so it kept paying the raw-tree transfer and decode cost the flag exists to avoid. Add --no-raw to the spawned arguments and pin them with a fake-binary argv recording test. Also update the two raw-nullability comments that dated from when a missing --json was the only way to get raw == nil. Signed-off-by: 4faramita <14917258+4faramita@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both comments spelled out the flag combination the adjacent expression already states; keep only the cost rationale the call site can't show. Signed-off-by: 4faramita <14917258+4faramita@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The --no-raw help text and skill claimed "3-10x" / "~70%" / "~1,500 tokens"; the measured basis was three same-session screens (raw at 2.7-3.5x the rest of the envelope) with the upper bound extrapolated, and the screenshot token figure is specific to one client's image tokenization. State what holds generally -- the raw tree typically dominates the payload; a screenshot costs several times a typical outline -- and leave exact figures out. Signed-off-by: 4faramita <14917258+4faramita@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
385269b to
7d80124
Compare
Summary
Two changes that reduce what an agent pays to read the screen:
describe-ui --no-raw(top-level,ios,android): with--json, omit the raw accessibility tree (data.raw) from the envelope.outline/entries/listsare unchanged.--jsonwith--no-raw, verify via the outline instead of screenshots, reuse the verify read as the next observe, batch known sequences.Default behavior is untouched: bare
describe-uistill prints the text outline, and--jsonwithout--no-rawstill carriesraw.Measured savings
On a real app screen (40 outline entries; tokens estimated at ~4 ASCII chars/token, screenshots per Claude's pixel formula):
--no-rawonui --json--jsonuireads/stepCombined on a 10-step agent task: -39% (agent already on the text loop) to -80% (agent on a
--jsonloop) total context consumption.Before / after
The default text outline (unchanged):
ui --json, before (and still the default):{ "ok": true, "data": { "appLabel": "OrderDemo", "entries": [ /* full labels, frames, states */ ], "lists": [ /* … */ ], "outline": "…", "raw": { /* full AX tree: ~70% of the payload */ }, "screen": { /* … */ } } }ui --json --no-raw:{ "ok": true, "data": { "appLabel": "OrderDemo", "entries": [ /* identical */ ], "lists": [ /* identical */ ], "outline": "…", "screen": { /* identical */ } } }When
--jsonis still used, and why quality is unaffecteddescribe-uidefaults to the text outline; agents reach for--jsonin two cases: coordinate math onentries[].frame/screen, and full untruncatedlabel/value(the outline truncates labels at 60 graphemes, values at 30). Both live inentries, not inraw.With
--no-rawthe envelope is byte-identical minus therawkey.rawis a debugging passthrough with no in-repo consumer (the Viewer included), no skill workflow reads it, and selector resolution (@N,--label) happens CLI-side against the AX snapshot, independent of what the agent read. Dropping it also keeps large screens from pushing the payload past agent-harness output truncation (30,000 chars in Claude Code) mid-JSON, which previously produced unparseable output and retries.Tests
Tests/DescribeUINoRawTests.swift: flag parses on all three surfaces, the top-level forwarder copies it, and a result built without the tree encodes norawkey at all (not"raw": null).make test: 822 green.--jsonoutputs byte-identical to before (modulo the status-bar clock);--no-rawenvelope identical minusraw.