fix(extension): resolve link element IDs in plain string fields
Closes #3234
Problem
extract() can return accessibility-tree element IDs instead of URLs when a
schema uses a plain z.string() field for a link.
The extract system prompt (packages/extension/prompt.ts) asks the model to
return link element IDs rather than hrefs, but injectUrls in utils.ts only
resolves IDs for schema paths that are marked as URL fields
(z.string().url()). A plain z.string() field carrying a link therefore
leaks the raw ID ("0-74", or "[0-74]\n[0-112]" for multi-link strings) to
the caller.
Change
After the existing .url() resolution, walk the extracted value with a new
resolveUrlIds helper and replace any bare or bracketed element ID that is
actually present in the snapshot's URL map (idToUrlMapping). IDs that are not
real links are left untouched, so a value like a score of "3-2" is preserved
exactly as requested in the issue.
Verification
- Added a mock unit test in
extract.test.tscovering plain-string resolution,
.url()fields, bracketed multi-ID strings, and the"3-2"non-link case. - The
resolveUrlIdshelper was exercised in an isolated vitest run (8 cases
pass) plus a stricttsc --noEmitbefore submission. - Note on scope: the repo-wide
extract.test.tscould not be executed in this
environment (no full monorepo checkout is possible here), but it is a
pure-mock test (vi.fnstubs forcaptureSnapshot/generate, no real
browser) and is covered by CI's unit-test job.
Known trade-off
If a plain string field legitimately contains a value that happens to equal a
real link element ID from the page's accessibility tree, it will be resolved to
that link's href. This is the intended behaviour described in the issue (the
discriminator is "the ID is present in the snapshot's URL map"), but it is a
semantic edge case worth surfacing to maintainers.
AI use
Drafted with an AI coding agent; the isolated helper test and strict typecheck
were run locally before submission.
Summary by cubic
Fixes extract() returning raw accessibility-tree element IDs like "0-74" instead of URLs when a link lands in a plain z.string() field. Link IDs are now resolved to hrefs via the snapshot's URL map, while non-link values like a score of "3-2" stay unchanged.
Details
- The extract prompt asks the model to return link IDs for plain string fields, but only
z.string().url()paths were resolved beforehand. - A new
resolveUrlIdshelper recursively walks the extracted value and replaces bare or bracketed IDs present in the URL map. - Adds a mock test covering plain strings,
.url()fields, bracketed multi-ID strings, and the"3-2"non-link case.