Each instance below enhances a plain search input with on-device AI
Suggestions: plain rewordings (typo fixes, finished-out phrases,
broader related terms) mixed freely with fielded/boolean
reformulations wherever Fields are configured, never labeled or
capped by which kind of improvement a given one is. Type a
natural-language query, wait a moment for Suggestions to appear, then
accept one to see that instance's configured Action run. Requires
Chrome with the on-device LanguageModel available. Expand
the <query-shaper> line under any search box below
to see exactly how it's configured.
Fields declared as an inline JSON schema; Format lucene;
Action opensearch against a hand-built template (no
published OpenSearch document for archive.org). examples
cover a range with an open ("before"/wildcard) bound, a grouped OR
combined with negation, a typo, and a vague input deliberately given
five varied Suggestions.
<query-shaper for="ia-search" ... /><query-shaper
for="ia-search"
fields='[{"name":"mediatype"},{"name":"year","type":"number"},{"name":"creator"},{"name":"subject"},{"name":"language"}]'
examples='[
{"input":"climate change documentaries from 2020","suggestions":["mediatype:movies AND subject:\"climate change\" AND year:2020"]},
{"input":"documentaries from before 2015","suggestions":["mediatype:movies AND year:[* TO 2015]"]},
{"input":"audio recordings or texts about jazz, not from 2020","suggestions":["(mediatype:audio OR mediatype:texts) AND subject:jazz AND -year:2020"]},
{"input":"documentries about space","suggestions":["mediatype:movies AND subject:space","documentaries about space"]},
{"input":"vintage sci-fi films","suggestions":["mediatype:movies AND subject:\"science fiction\"","vintage science fiction movies","classic sci-fi films","mediatype:movies AND subject:vintage","old science fiction movies"]}
]'
format="lucene"
action="opensearch"
template="https://archive.org/search?query={searchTerms}"
></query-shaper>
Format lucene; Action opensearch, with the
template sourced directly from Open Library's real
OpenSearch description document.
examples cover a bounded range, a wildcard open range, a
combined field + negation, a grouped OR, a typo, and a vague input
given five varied Suggestions. notes directly targets a
real bug seen live: the model once assigned "Harry Potter" to
author instead of title.
<query-shaper for="ol-search" ... /><query-shaper
for="ol-search"
fields='[{"name":"author"},{"name":"title"},{"name":"language","description":"ISO 639 code"},{"name":"first_publish_year","type":"number"}]'
examples='[
{"input":"harry potter books published before 2000","suggestions":["title:\"harry potter\" AND first_publish_year:[1000 TO 2000]"]},
{"input":"books by cory doctorow in english","suggestions":["author:\"cory doctorow\" AND language:en"]},
{"input":"books published up to 2005","suggestions":["first_publish_year:[* TO 2005]"]},
{"input":"books by asimov but not in french","suggestions":["author:\"isaac asimov\" AND -language:fr"]},
{"input":"tolkien books in english or spanish","suggestions":["author:\"j.r.r. tolkien\" AND (language:en OR language:es)"]},
{"input":"harry poter books","suggestions":["title:\"harry potter\"","harry potter books"]},
{"input":"classic fantasy novels","suggestions":["title:fantasy","fantasy novels","classic fantasy books","title:\"lord of the rings\"","fantasy literature classics"]}
]'
notes="A book or series title (e.g. "Harry Potter", "Lord of the Rings") always belongs in the title field, never author: only a real person's name belongs in author."
format="lucene"
action="opensearch"
template="https://openlibrary.org/search?q={searchTerms}&mode=everything"
></query-shaper>
gov collection search
The gov collection itself is fixed configuration baked
into the template, never a Field the model varies.
Format lucene; the {searchTerms} placeholder
sits in a path segment, not a query string. examples
cover a bare term mixed with fielded conditions (since "climate
policy" isn't itself a declared Field), negation, a wildcard open
range in each direction, a typo, and a vague input given five varied
Suggestions.
<query-shaper for="wb-search" ... /><query-shaper
for="wb-search"
fields='[{"name":"language"},{"name":"site"},{"name":"year","type":"number"},{"name":"pubdate","type":"date"}]'
examples='[
{"input":"government sites about climate policy after 2015","suggestions":["site:gov AND year:[2015 TO *] climate policy"]},
{"input":"English language government sites","suggestions":["language:en AND site:gov"]},
{"input":"sites excluding .com domains from 2020","suggestions":["-site:com AND year:2020"]},
{"input":"old government pages up to 2010","suggestions":["site:gov AND year:[* TO 2010]"]},
{"input":"goverment sites","suggestions":["site:gov","government sites"]},
{"input":"climate change resources","suggestions":["climate change","site:gov climate change","climate policy resources","environmental policy sites","site:org climate change"]}
]'
format="lucene"
action="opensearch"
template="https://web.archive.org/collection-search/gov/{searchTerms}"
></query-shaper>
No fields attribute at all: the model is never told
about any backend fields, so Suggestions stay plain rewordings
(typo fixes, finished-out phrases, broader related terms) and never
attempt a fielded reformulation, since there's nothing declared to
reformulate against.
<query-shaper for="generic-none" /><query-shaper for="generic-none"></query-shaper>
A loosely specified, human-written Fields description still produces
sensible Expression Suggestions, helped along here by
examples, since a harder-to-parse prose Fields
declaration measurably needed more encouragement to attempt a
fielded Suggestion at all, covering a range, negation, and grouping.
<query-shaper for="generic-freeform" ... /><query-shaper
for="generic-freeform"
fields="title, author, language:iso-639-1, date (allowed patterns YYYY[-MM[-DD]]), categories (comma-separated list)"
examples='[
{"input":"French novels from the 1920s","suggestions":["language:fr AND date:[1920 TO 1929]","french novels 1920s"]},
{"input":"books by Verne in French","suggestions":["author:\"jules verne\" AND language:fr"]},
{"input":"novels not in english, from before 1950","suggestions":["-language:en AND date:[* TO 1950]"]},
{"input":"adventure or mystery novels in french","suggestions":["(categories:adventure OR categories:mystery) AND language:fr"]},
{"input":"vernes novels","suggestions":["author:\"jules verne\"","verne's novels"]}
]'
></query-shaper>
The more precise, structured declaration path. examples
cover a range, the boolean field, negation, a grouped OR, a typo,
and a vague input deliberately given five varied Suggestions mixing
fielded and plain-rewording styles.
<query-shaper for="generic-json" ... /><query-shaper
for="generic-json"
fields='[{"name":"category"},{"name":"price","type":"number"},{"name":"in_stock","type":"boolean"}]'
examples='[
{"input":"electronics under $50","suggestions":["category:electronics AND price:[0 TO 50]","cheap electronics"]},
{"input":"laptops in stock","suggestions":["category:laptop AND in_stock:true"]},
{"input":"cheap electronics, not laptops","suggestions":["category:electronics AND -category:laptop AND price:[0 TO 50]"]},
{"input":"electronics or gadgets under $50","suggestions":["(category:electronics OR category:gadgets) AND price:[0 TO 50]"]},
{"input":"electroncis under $50","suggestions":["category:electronics AND price:[0 TO 50]","electronics under $50"]},
{"input":"cheap stuff","suggestions":["price:[0 TO 20]","category:electronics AND price:[0 TO 20]","affordable items","budget electronics","discounted electronics"]}
]'
></query-shaper>
.format render function
The escape hatch for backends neither built-in preset covers. A
render function can't be expressed as an attribute, so it's set
imperatively on the .format property once the element
is defined. This one renders field=value pairs joined
by ; instead of lucene or
url-params syntax.
<query-shaper for="generic-custom" ... /><query-shaper
id="generic-custom-shaper"
for="generic-custom"
fields='[{"name":"category"},{"name":"price","type":"number"}]'
></query-shaper>
<script type="module">
customElements.whenDefined('query-shaper').then(() => {
document.querySelector('#generic-custom-shaper').format = (fields) =>
fields.map((f) => `${f.field ?? 'q'}=${f.value}`).join(';')
})
</script>