docs(search): don't threshold JSON score as Tavily

S1: skill recipe now says result score is merged rank. Also send
non-zero --min-score to the server (N1), sort include_domains (N2),
and note that search_queries counts each sub-query (N3).
This commit is contained in:
2026-09-29 15:33:57 -07:00
parent 8b26776cdd
commit 682b9b8044
5 changed files with 20 additions and 4 deletions
+2 -1
View File
@@ -45,7 +45,8 @@ sift extract <file.pdf> [--pages a-b] [--grep re] [--question q] [--mode clean|d
the key file must be mode 0600. `sift extract` uploads a local PDF to `/v1/extract` and prints the the key file must be mode 0600. `sift extract` uploads a local PDF to `/v1/extract` and prints the
answer exactly as `sift fetch` does for a PDF URL — `--pages`, `--grep` and `--question` behave the answer exactly as `sift fetch` does for a PDF URL — `--pages`, `--grep` and `--question` behave the
same, and a file over 100 MiB is refused before the upload. The agent-facing guide is same, and a file over 100 MiB is refused before the upload. The agent-facing guide is
[`skill/SKILL.md`](skill/SKILL.md). [`skill/SKILL.md`](skill/SKILL.md). JSON `search_queries` (and `sift_search_queries_*`) counts
each sub-query as its own upstream call, so a 4-query search is 4× one `query`.
## Batch ## Batch
+1 -1
View File
@@ -96,7 +96,7 @@ func searchMain() {
if *exact { if *exact {
body["exact_match"] = true body["exact_match"] = true
} }
if *minScore > 0 { if *minScore != 0 {
body["min_score"] = *minScore body["min_score"] = *minScore
} }
base, key, err := loadClient() base, key, err := loadClient()
+2
View File
@@ -1,6 +1,7 @@
package search package search
import ( import (
"sort"
"strings" "strings"
"time" "time"
"unicode/utf8" "unicode/utf8"
@@ -170,6 +171,7 @@ func normalizeDomains(in []string, hint string) ([]string, string) {
if len(out) == 0 { if len(out) == 0 {
return nil, "" return nil, ""
} }
sort.Strings(out)
if len(out) > maxDomainList { if len(out) > maxDomainList {
return nil, hint return nil, hint
} }
+12
View File
@@ -150,6 +150,18 @@ func TestNormalizeDomainOR(t *testing.T) {
if msg != "" || hint != "" || len(out.IncludeDomains) != 1 || out.IncludeDomains[0] != "oracle.com" { if msg != "" || hint != "" || len(out.IncludeDomains) != 1 || out.IncludeDomains[0] != "oracle.com" {
t.Fatalf("%q %q %+v", msg, hint, out) t.Fatalf("%q %q %+v", msg, hint, out)
} }
_, out, msg, _ = NormalizeSearch("q", nil, Filter{IncludeDomains: []string{"z.com", "a.com", "m.com"}})
if msg != "" || strings.Join(out.IncludeDomains, ",") != "a.com,m.com,z.com" {
t.Fatalf("sorted domains %+v", out.IncludeDomains)
}
_, four, _, _ := NormalizeSearch("q", nil, Filter{IncludeDomains: []string{"d.com", "c.com", "b.com", "a.com"}})
q, notes := searxQueryAndNotes("q", four)
if !strings.HasPrefix(q, "site:a.com OR site:b.com OR site:c.com ") {
t.Fatalf("site subset %q", q)
}
if !strings.Contains(strings.Join(notes, " "), "extra include_domains dropped") {
t.Fatalf("notes %v", notes)
}
} }
func TestMultiQueryRRF(t *testing.T) { func TestMultiQueryRRF(t *testing.T) {
+3 -2
View File
@@ -80,8 +80,9 @@ sift search "product launch" --include-domain openai.com --topic news --time-ran
**Recipe:** after `sift search --json`, do not `sift fetch` every URL. Drop hits below a **Recipe:** after `sift search --json`, do not `sift fetch` every URL. Drop hits below a
Tavily score you care about (`--min-score`, Tavily's 0–1 scale) or take top N, then Tavily score you care about (`--min-score`, Tavily's 0–1 scale) or take top N, then
`sift batch submit`. `web_search` is only the fallback when sift is unreachable, and it `sift batch submit`. The `score` field is sift's merged rank, not comparable across
still hits `/v2/search` with no filters. sources: use `--min-score` for Tavily's threshold, or take the top N. `web_search` is
only the fallback when sift is unreachable, and it still hits `/v2/search` with no filters.
## Batch ## Batch