diff --git a/README.md b/README.md index 63ccc7a..09ddb73 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,8 @@ sift extract [--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 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 -[`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 diff --git a/cmd/sift/searchcmd.go b/cmd/sift/searchcmd.go index 797dbc9..4acab81 100644 --- a/cmd/sift/searchcmd.go +++ b/cmd/sift/searchcmd.go @@ -96,7 +96,7 @@ func searchMain() { if *exact { body["exact_match"] = true } - if *minScore > 0 { + if *minScore != 0 { body["min_score"] = *minScore } base, key, err := loadClient() diff --git a/internal/search/filter.go b/internal/search/filter.go index 67b6b48..e33c756 100644 --- a/internal/search/filter.go +++ b/internal/search/filter.go @@ -1,6 +1,7 @@ package search import ( + "sort" "strings" "time" "unicode/utf8" @@ -170,6 +171,7 @@ func normalizeDomains(in []string, hint string) ([]string, string) { if len(out) == 0 { return nil, "" } + sort.Strings(out) if len(out) > maxDomainList { return nil, hint } diff --git a/internal/search/p31_test.go b/internal/search/p31_test.go index d355822..b823eb1 100644 --- a/internal/search/p31_test.go +++ b/internal/search/p31_test.go @@ -150,6 +150,18 @@ func TestNormalizeDomainOR(t *testing.T) { if msg != "" || hint != "" || len(out.IncludeDomains) != 1 || out.IncludeDomains[0] != "oracle.com" { 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) { diff --git a/skill/SKILL.md b/skill/SKILL.md index 17acd9e..e1379a8 100644 --- a/skill/SKILL.md +++ b/skill/SKILL.md @@ -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 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 -still hits `/v2/search` with no filters. +`sift batch submit`. The `score` field is sift's merged rank, not comparable across +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