Repository navigation
fix: resolve leaked extract() element IDs on z.string() URL fields - #2784
antonvishal wants to merge 8 commits into
Conversation
|
|
This PR is from an external contributor and must be approved by a stagehand team member with write access before CI can run. |
# Conflicts: # packages/extension/services/extractService.ts
# Conflicts: # packages/sdk-go/internal/extensionassets/stagehand-extension.zip
# Conflicts: # packages/sdk-go/internal/extensionassets/stagehand-extension.zip
Summary
extract()leaked accessibility-tree IDs ([0-74],0-74) when the schema used plainz.string()for URL fields.injectUrlsonly ran forz.url()/format: uri.{ stories: z.string() }or{ rank1_url: z.string(), ... }on a page like Hacker News) got raw element IDs back.z.url()fields already resolved correctly.frameId-backendIdonly for URL values, thenreplaceElementIdsWithUrlsmaps leaked IDs throughcombinedUrlMap. Bracketed IDs rewrite in any string; bare IDs only on URL-ish field names.Before
{ "stories": "[0-74]\n[0-112]\n[0-150]\n[0-188]\n[0-226]" }
{
"rank1_title": "GrapheneOS in 2027 available on high-end Motorola phones",
"rank1_url": "0-74",
"rank2_url": "0-112",
"rank3_url": "0-150",
"rank4_url": "0-188",
"rank5_url": "0-226"
}
After (this fix)
{
"stories": "https://grapheneos.social/@GrapheneOS/117078064184215730\nhttps://yassa9.github.io/osint/gralhix-004/\nhttps://www.raphaelbauer.com/posts/postgresql-everything/\nhttps://sprocketfox.io/xssfox/2026/08/19/sondehub-and-war/\nhttps://openlogi.org/en"
}
{
"rank1_title": "GrapheneOS in 2027 available on high-end Motorola phones",
"rank1_url": "https://grapheneos.social/@GrapheneOS/117078064184215730",
"rank2_url": "https://yassa9.github.io/osint/gralhix-004/",
"rank3_url": "https://www.raphaelbauer.com/posts/postgresql-everything/",
"rank4_url": "https://sprocketfox.io/xssfox/2026/08/19/sondehub-and-war/",
"rank5_url": "https://openlogi.org/en"
}
Test plan
pnpm exec vitest run --root . packages/extension/tests/extract.test.tsextract()on a page with links usingz.object({ title: z.string(), url: z.url() })still returns real hrefsz.object({ title: z.string(), url: z.string() })returns real hrefs, not element IDsextract("Extract the first 5 story URLs", z.object({ urls: z.string() }))returns real URLs, not[0-74]/0-74score: "0-74") are left unchangedSummary by cubic
Fixes
extract()leaking accessibility-tree element IDs when URL fields usez.string(). Onlyz.url()fields resolved to hrefs before; now plain string URL fields also return real URLs, and non-URL fields never return element IDs.frameId-backendId(no brackets) and all other fields return only visible text.replaceElementIdsWithUrlsto map leaked IDs to hrefs via the snapshotcombinedUrlMap: bracketed IDs are replaced anywhere, bare IDs only on URL-like field names, and unknown IDs are left as-is.transformSchemato treaturl,uri, anduri-referenceas URL formats, preserving thez.url()path.Migration
Written for commit 6c77b7e. Summary will update on new commits.