feat: screenshot digest response-view — Phase 4#945
Conversation
Add a `screenshot` entry to the Phase 4 RESPONSE_VIEWS registry. At
responseLevel `digest`, the view keeps the cheap result fields — the
captured `path` and the `artifacts` retrieval handle — and collapses the
token-heavy `overlayRefs` array (each carrying ref + label + three
geometry rects) to a total `overlayCount` plus the first 12 refs leveled
down to `{ ref, label }`. `default`/`full` return today's shape unchanged,
so unregistered and default-level responses stay byte-identical.
Size Report
Startup median (7 runs, lower is better):
Top changed chunks:
|
|
Blocking this one because the screenshot digest does not survive the shipped client/CLI path. The daemon view returns a digest shape with Please add a shipped-path test through |
The daemon screenshot view returns a leveled digest (path, overlayCount, leveled
overlayRefs, artifacts), but client.capture.screenshot() always ran the data
through readScreenshotResultData, which keeps only path + full-geometry overlay
refs and drops overlayCount/artifacts — so the digest never reached SDK/CLI
callers. Make the capture method level-aware: when the effective responseLevel
(request override or client config) is non-default, return the leveled payload
verbatim instead of normalizing it. Default-level behavior is unchanged.
Adds shipped-path client tests: capture.screenshot({ responseLevel: 'digest' })
returns the raw digest (overlayCount/artifacts preserved, no normalizer
identifiers); the default path still normalizes. Kept the return type as
CaptureScreenshotResult (the union variant cascaded into many default-path
consumers); the caller opted into the level, so the runtime value is leveled.
|
Fixed (pushed). You're right that the digest died at the client boundary. Added the requested shipped-path tests through On typing: I kept the return type as |
|
Thanks, the There is still one shipped-path gap from the original blocker: the CLI screenshot command re-normalizes the client result into a new object with only const data = {
path: result.path,
...(result.overlayRefs ? { overlayRefs: result.overlayRefs } : {}),
};So |
agent-device screenshot --level digest --json still dropped overlayCount and
artifacts: the CLI command rebuilt the default { path, overlayRefs } shape from
the (now leveled) client result. Make screenshotCommand level-aware — for a
non-default responseLevel it emits the leveled payload verbatim (JSON / JSON
text). Adds a CLI shipped-path test (--level digest --json preserves the digest;
the default level still emits the normalized shape). Factors the predicate into
a shared isNonDefaultResponseLevel in contracts.ts, reused by the client helper.
|
Fixed (pushed). |
client.capture.snapshot() always ran the daemon data through
normalizeSnapshotResult, which expects the full `nodes` tree — so a non-default
responseLevel digest ({ nodeCount, refs }) collapsed to an empty snapshot, the
same gap #945 fixed for screenshot. Make it level-aware: when the effective
responseLevel is non-default, return the leveled payload verbatim. Default-level
behavior is unchanged. Adds a shipped-path client test asserting the digest
survives (nodeCount/refs preserved, no normalizer identifiers).
|
Re-reviewed the latest fix at The previous CLI blocker is addressed now: All 21 checks are green. I do not see an actionable blocker now. |
… 4 (#949) * fix: preserve the snapshot digest through the client capture path client.capture.snapshot() always ran the daemon data through normalizeSnapshotResult, which expects the full `nodes` tree — so a non-default responseLevel digest ({ nodeCount, refs }) collapsed to an empty snapshot, the same gap #945 fixed for screenshot. Make it level-aware: when the effective responseLevel is non-default, return the leveled payload verbatim. Default-level behavior is unchanged. Adds a shipped-path client test asserting the digest survives (nodeCount/refs preserved, no normalizer identifiers). * fix: preserve leveled digests through the generic CLI path agent-device snapshot --level digest --json dropped nodeCount/refs: snapshot goes through the generic CLI path (runCliCommandWithOutput -> formatCliOutput), whose snapshot formatter serializes the default CaptureSnapshotResult shape and discards digest-only fields. Make runGenericClientBackedCommand level-aware: for a non-default responseLevel it emits the raw leveled payload verbatim (JSON / JSON text), bypassing the default-shape formatter. This generalizes to any generic-path command. Adds a snapshot CLI shipped-path test.
|
What
Adds a
screenshotentry to the Phase 4 leveledRESPONSE_VIEWSregistry (src/daemon/response-views.ts), extending the pattern introduced forsnapshotin #942 (now merged to main; this PR is the next Phase 4 slice).Digest shape
At responseLevel
digest, thescreenshotview:path(the primary result) andartifacts(the client's image-retrieval handle, grafted on by request finalization), preserved only when present;overlayRefsarray — each entry carriesref+ optionallabel+ three geometry rects (rect,overlayRect,center) — to a totaloverlayCountplus the first 12 refs leveled down to{ ref, label }. The per-overlay geometry is the token sink that--overlay-refsemits when many nodes are annotated.defaultandfullreturn today's data unchanged (same reference). The router only calls a view atdigest/fullfor a registered command, sodefaultand every unregistered command stay byte-identical.Grounding
The shape is grounded in the real handler return — not invented:
ScreenshotResultData = { path?: string; overlayRefs?: ScreenshotOverlayRef[] }—src/utils/screenshot-result.ts:4ScreenshotOverlayRef = { ref; label?; rect; overlayRect; center }—src/kernel/snapshot.ts:125overlayRefsattached to the daemon response data —src/daemon/request-generic-dispatch.ts:328(data.overlayRefs = overlayRefs)artifactsgrafted onto screenshot responses by finalization —src/daemon/request-finalization.ts:82Invariant
The view is a pure read of the default
data; it never mutates its input, and only restructures atdigest.Tests
src/daemon/__tests__/response-views.test.ts— mirrors the snapshot view test: digest collapses overlay geometry tooverlayCount+ leveled{ ref, label }refs while keepingpath/artifacts, caps the list at 12 (counting all),default/fullpassthrough by reference, and tolerates a path-only result with no overlay refs.Verification
tsc --noEmit→ 0oxfmt --check+oxlint --deny-warnings→ cleanfallow audit --base origin/main→ no issuesvitest run src/daemon/__tests__/response-views.test.ts→ 9/9vitest run daemon→ 938/938 (98 files)