p3: no Tavily daily cap for restricted callers
Restricted searches skip the cap check. Credits land on tavily:restricted so they never raise the fleet row. Fleet at cap still falls through.
This commit is contained in:
+4
-1
@@ -241,7 +241,10 @@ Digest/question-embedding keys are partitioned the same way in P2.6.
|
|||||||
**Daily cap** (paid vendors, currently Tavily): calendar UTC day, in-process counter
|
**Daily cap** (paid vendors, currently Tavily): calendar UTC day, in-process counter
|
||||||
plus a `search_cap` row in SQLite so a restart does not reset it. Hitting the cap
|
plus a `search_cap` row in SQLite so a restart does not reset it. Hitting the cap
|
||||||
skips that source for the rest of the day (`warnings: tavily: daily cap`) and does
|
skips that source for the rest of the day (`warnings: tavily: daily cap`) and does
|
||||||
not fail the search. Brave LLM Context gets a cap too if the key is billed; default
|
not fail the search. **`permit_restricted` callers skip the cap check.** Their
|
||||||
|
credits are stored on a separate row (`tavily:restricted`) so they never raise the
|
||||||
|
fleet row, and the fleet cap never throttles them. Per-caller `search_credits`
|
||||||
|
still counts both. Brave LLM Context gets a cap too if the key is billed; default
|
||||||
off until the bake-off shows a rate.
|
off until the bake-off shows a rate.
|
||||||
|
|
||||||
Logs: one INFO line `search caller=… q_len=… sources=… n=… cache=hit|miss rerank_ms=…`.
|
Logs: one INFO line `search caller=… q_len=… sources=… n=… cache=hit|miss rerank_ms=…`.
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ func (e *Engine) Run(ctx context.Context, query string, k int, doRerank bool, ca
|
|||||||
class = dcache.ClassFleet
|
class = dcache.ClassFleet
|
||||||
}
|
}
|
||||||
|
|
||||||
attempted := e.attemptedNames()
|
attempted := e.attemptedNames(class)
|
||||||
key := dcache.SearchKey(query, attempted, k, e.now(), class)
|
key := dcache.SearchKey(query, attempted, k, e.now(), class)
|
||||||
if b, ok := e.Cache.GetSearch(key); ok {
|
if b, ok := e.Cache.GetSearch(key); ok {
|
||||||
var hits []Hit
|
var hits []Hit
|
||||||
@@ -123,7 +123,7 @@ func (e *Engine) Run(ctx context.Context, query string, k int, doRerank bool, ca
|
|||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
for i, src := range e.Sources {
|
for i, src := range e.Sources {
|
||||||
name := src.Name()
|
name := src.Name()
|
||||||
if name == NameTavily && e.tavilyCapped() {
|
if name == NameTavily && e.tavilyCapped(class) {
|
||||||
outs[i] = one{name: name, out: SourceOut{Warn: "tavily: daily cap"}, skip: true}
|
outs[i] = one{name: name, out: SourceOut{Warn: "tavily: daily cap"}, skip: true}
|
||||||
e.addCapped(NameTavily)
|
e.addCapped(NameTavily)
|
||||||
continue
|
continue
|
||||||
@@ -164,7 +164,7 @@ func (e *Engine) Run(ctx context.Context, query string, k int, doRerank bool, ca
|
|||||||
if o.out.Credits > 0 {
|
if o.out.Credits > 0 {
|
||||||
e.addCredits(caller, o.name, o.out.Credits)
|
e.addCredits(caller, o.name, o.out.Credits)
|
||||||
if o.name == NameTavily && e.Cache != nil {
|
if o.name == NameTavily && e.Cache != nil {
|
||||||
e.Cache.AddSearchCredits(NameTavily, e.now().UTC().Format("2006-01-02"), o.out.Credits)
|
e.Cache.AddSearchCredits(tavilyCapSource(class), e.now().UTC().Format("2006-01-02"), o.out.Credits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,10 +190,10 @@ func (e *Engine) Run(ctx context.Context, query string, k int, doRerank bool, ca
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) attemptedNames() []string {
|
func (e *Engine) attemptedNames(class string) []string {
|
||||||
var n []string
|
var n []string
|
||||||
for _, s := range e.Sources {
|
for _, s := range e.Sources {
|
||||||
if s.Name() == NameTavily && e.tavilyCapped() {
|
if s.Name() == NameTavily && e.tavilyCapped(class) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
n = append(n, s.Name())
|
n = append(n, s.Name())
|
||||||
@@ -202,10 +202,20 @@ func (e *Engine) attemptedNames() []string {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) tavilyCapped() bool {
|
func tavilyCapSource(class string) string {
|
||||||
|
if class == dcache.ClassRestricted {
|
||||||
|
return NameTavily + ":restricted"
|
||||||
|
}
|
||||||
|
return NameTavily
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) tavilyCapped(class string) bool {
|
||||||
if e == nil || e.TavilyCap <= 0 {
|
if e == nil || e.TavilyCap <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if class == dcache.ClassRestricted {
|
||||||
|
return false
|
||||||
|
}
|
||||||
n := 0
|
n := 0
|
||||||
if e.Cache != nil {
|
if e.Cache != nil {
|
||||||
n = e.Cache.GetSearchCredits(NameTavily, e.now().UTC().Format("2006-01-02"))
|
n = e.Cache.GetSearchCredits(NameTavily, e.now().UTC().Format("2006-01-02"))
|
||||||
|
|||||||
@@ -195,6 +195,46 @@ func TestDailyCapSkipsTavily(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRestrictedSkipsTavilyCap(t *testing.T) {
|
||||||
|
db, err := dcache.Open(filepath.Join(t.TempDir(), "c.db"), 1<<20, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
tav := fakeSrc{name: NameTavily, hits: []Hit{{URL: "https://t.example/a", Source: NameTavily}}, credits: 1}
|
||||||
|
e := &Engine{Sources: []Source{tav}, DefaultK: 8, Cache: db, TavilyCap: 1, RerankOn: false}
|
||||||
|
e.Run(context.Background(), "q1", 8, false, "titan", dcache.ClassFleet)
|
||||||
|
day := e.now().UTC().Format("2006-01-02")
|
||||||
|
if db.GetSearchCredits(NameTavily, day) != 1 {
|
||||||
|
t.Fatalf("fleet row %d", db.GetSearchCredits(NameTavily, day))
|
||||||
|
}
|
||||||
|
r := e.Run(context.Background(), "q-gs", 8, false, "straylight-gs", dcache.ClassRestricted)
|
||||||
|
if len(r.Hits) != 1 || r.Hits[0].URL != "https://t.example/a" {
|
||||||
|
t.Fatalf("restricted should still get Tavily: %+v %v", r.Hits, r.Warnings)
|
||||||
|
}
|
||||||
|
for _, w := range r.Warnings {
|
||||||
|
if strings.Contains(w, "daily cap") {
|
||||||
|
t.Fatalf("restricted capped: %v", r.Warnings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if db.GetSearchCredits(NameTavily, day) != 1 {
|
||||||
|
t.Fatalf("restricted must not raise fleet row, got %d", db.GetSearchCredits(NameTavily, day))
|
||||||
|
}
|
||||||
|
if db.GetSearchCredits(NameTavily+":restricted", day) != 1 {
|
||||||
|
t.Fatalf("restricted row %d", db.GetSearchCredits(NameTavily+":restricted", day))
|
||||||
|
}
|
||||||
|
fleet := e.Run(context.Background(), "q2", 8, false, "titan", dcache.ClassFleet)
|
||||||
|
n := 0
|
||||||
|
for _, w := range fleet.Warnings {
|
||||||
|
if strings.Contains(w, "daily cap") {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n != 1 {
|
||||||
|
t.Fatalf("fleet still capped: %v", fleet.Warnings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDedupeLongerSnippet(t *testing.T) {
|
func TestDedupeLongerSnippet(t *testing.T) {
|
||||||
in := []Hit{
|
in := []Hit{
|
||||||
{URL: "https://Ex.com/a#x", Snippet: "aa", Source: NameSearxNG},
|
{URL: "https://Ex.com/a#x", Snippet: "aa", Source: NameSearxNG},
|
||||||
|
|||||||
Reference in New Issue
Block a user