返回 DeepSeek-Reasonix
tool_search.go
根目录 / internal / provider / tool_search.go
1 package provider
2
3 import (
4 "net/url"
5 "strings"
6 "sync/atomic"
7 )
8
9 // ToolSearch is a request-level native tool-search experiment. Unsupported
10 // adapters must not serialize it.
11 type ToolSearch struct {
12 Enabled bool
13 }
14
15 // nativeToolSearchPreview is compiled off for 1.33.0. First-party OpenAI
16 // Responses and Anthropic may enable it later after the preview experiment.
17 var nativeToolSearchPreview atomic.Bool
18
19 func NativeToolSearchPreviewEnabled() bool { return nativeToolSearchPreview.Load() }
20
21 func SetNativeToolSearchPreviewForTest(enabled bool) func() {
22 prev := nativeToolSearchPreview.Swap(enabled)
23 return func() { nativeToolSearchPreview.Store(prev) }
24 }
25
26 type nativeToolSearchProvider interface {
27 NativeToolSearchAvailable() bool
28 }
29
30 // NativeToolSearchSupported reports explicit adapter capability. The first
31 // preview supports first-party OpenAI Responses only; Anthropic stays on the
32 // fixed proxy until its server-side tool-search result blocks can be replayed.
33 func NativeToolSearchSupported(p Provider) bool {
34 if p == nil {
35 return false
36 }
37 capable, ok := p.(nativeToolSearchProvider)
38 return ok && capable.NativeToolSearchAvailable()
39 }
40
41 func NativeToolSearchEnabled(p Provider) bool {
42 return nativeToolSearchPreview.Load() && NativeToolSearchSupported(p)
43 }
44
45 // ApplyNativeToolSearch marks extra MCP schemas deferred when the preview is
46 // active. When disabled it returns visible unchanged so the cache prefix is
47 // byte-identical to 1.33.0.
48 func ApplyNativeToolSearch(visible, extra []ToolSchema, p Provider) []ToolSchema {
49 if !NativeToolSearchEnabled(p) || len(extra) == 0 {
50 return visible
51 }
52 out := append([]ToolSchema(nil), visible...)
53 seen := map[string]bool{}
54 for _, schema := range visible {
55 seen[schema.Name] = true
56 }
57 for _, schema := range extra {
58 if seen[schema.Name] {
59 continue
60 }
61 schema.Deferred = true
62 out = append(out, schema)
63 seen[schema.Name] = true
64 }
65 return out
66 }
67
68 func IsFirstPartyOpenAI(baseURL string) bool {
69 u, err := url.Parse(baseURL)
70 if err != nil {
71 return false
72 }
73 host := strings.ToLower(u.Hostname())
74 return host == "api.openai.com" || strings.HasSuffix(host, ".openai.com")
75 }
76
77 func IsFirstPartyAnthropic(baseURL string) bool {
78 u, err := url.Parse(baseURL)
79 if err != nil {
80 return false
81 }
82 host := strings.ToLower(u.Hostname())
83 return host == "api.anthropic.com" || strings.HasSuffix(host, ".anthropic.com")
84 }
85
85 lines GO