返回 DeepSeek-Reasonix
cache_policy.go
根目录 / internal / config / cache_policy.go
1 package config
2
3 import (
4 "strings"
5 "time"
6 )
7
8 // DefaultCacheTTL returns the vendor's known prefix-cache retention based on
9 // the provider's base_url. Used by cold-resume prune to decide whether the
10 // provider cache is still warm after a session idle period.
11 //
12 // The legacy main-v2 default (24h) is deliberately preserved for DeepSeek and
13 // unknown vendors: DeepSeek's Context Caching on Disk retains prefixes for
14 // "several hours to days", so the long-standing 24h threshold is correct for
15 // it and must not regress. Only vendors with a documented, much shorter
16 // cache TTL (DashScope 5m, Anthropic 5m) override it.
17 //
18 // Values are deliberately conservative: too small burns a live cache (the user
19 // pays full price for a prefix that was still cached server-side), too large
20 // only forgoes a prune opportunity. Tighten from measured retention data.
21 func DefaultCacheTTL(baseURL string) time.Duration {
22 switch detectCacheVendor(baseURL) {
23 case "dashscope":
24 // DashScope Session cache TTL is 5 minutes (documented).
25 return 5 * time.Minute
26 case "anthropic":
27 // Anthropic ephemeral cache TTL is 5 minutes.
28 return 5 * time.Minute
29 default:
30 // DeepSeek and unknown vendors keep the legacy 24h default.
31 // DeepSeek Context Caching on Disk retains prefixes for hours to
32 // days; shrinking this would prune still-warm caches and burn
33 // the user's live cache (measured ~4x miss cost).
34 return 24 * time.Hour
35 }
36 }
37
38 // EffectiveCacheTTL resolves the provider's cache TTL: an explicit
39 // cache_ttl_minutes config wins; otherwise the vendor default applies.
40 func (e *ProviderEntry) EffectiveCacheTTL() time.Duration {
41 if e.CacheTTLMinutes > 0 {
42 return time.Duration(e.CacheTTLMinutes) * time.Minute
43 }
44 return DefaultCacheTTL(e.BaseURL)
45 }
46
47 // detectCacheVendor identifies the provider vendor from its base_url for
48 // cache policy purposes. Mirrors provider/responses.DetectVendor but lives in
49 // the config layer to avoid an import cycle (control → config, not control →
50 // provider). Host-based exact/suffix matching (not full-URL substring) so
51 // unrelated or attacker-controlled URLs can't be misdetected.
52 func detectCacheVendor(baseURL string) string {
53 host := officialProviderHost(baseURL)
54 switch {
55 case host == "dashscope.aliyuncs.com", strings.HasSuffix(host, ".dashscope.aliyuncs.com"), strings.HasSuffix(host, ".maas.aliyuncs.com"):
56 return "dashscope"
57 case host == "api.deepseek.com", strings.HasSuffix(host, ".deepseek.com"):
58 return "deepseek"
59 case host == "api.anthropic.com", strings.HasSuffix(host, ".anthropic.com"):
60 return "anthropic"
61 default:
62 return ""
63 }
64 }
65
65 lines GO