fix(extension): resolve link element IDs in plain string fields

LH
9h ago
+123-1

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.ts covering plain-string resolution,
    .url() fields, bracketed multi-ID strings, and the "3-2" non-link case.
  • The resolveUrlIds helper was exercised in an isolated vitest run (8 cases
    pass) plus a strict tsc --noEmit before submission.
  • Note on scope: the repo-wide extract.test.ts could not be executed in this
    environment (no full monorepo checkout is possible here), but it is a
    pure-mock test (vi.fn stubs for captureSnapshot/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 resolveUrlIds helper 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.