返回 DeepSeek-Reasonix
opencode_headers.go
根目录 / internal / provider / opencode_headers.go
1 package provider
2
3 import (
4 "context"
5 "crypto/rand"
6 "crypto/sha256"
7 "encoding/hex"
8 "net/http"
9 )
10
11 type cacheSessionContextKey struct{}
12
13 // WithCacheSession scopes transport cache routing to a conversation. The hash
14 // prevents local session paths or user-provided identifiers entering headers.
15 // It deliberately replaces inherited identities when a child Agent starts.
16 func WithCacheSession(ctx context.Context, identity string) context.Context {
17 sum := sha256.Sum256([]byte(identity))
18 return context.WithValue(ctx, cacheSessionContextKey{}, "reasonix-"+hex.EncodeToString(sum[:16]))
19 }
20
21 // NewCacheSessionID provides a stable per-client fallback for standalone calls.
22 func NewCacheSessionID() string { return "reasonix-" + rand.Text() }
23
24 // NewClientIdentityHeaders groups immutable transport identity by client lifetime.
25 func NewClientIdentityHeaders() http.Header {
26 return http.Header{"User-Agent": []string{"Reasonix"}, "X-Opencode-Session": []string{NewCacheSessionID()}}
27 }
28
29 // ApplyOpenCodeGoHeaders implements Go's client identification/cache contract
30 // for all three wire adapters. It never changes model input or other vendors.
31 func ApplyOpenCodeGoHeaders(req *http.Request, _ string, fallback http.Header) {
32 path, ok := officialOpenCodeGoPath(req.URL.String())
33 if !ok || (path != "/zen/go/v1/chat/completions" && path != "/zen/go/v1/messages" && path != "/zen/go/v1/responses" && path != "/zen/go/v1/models") {
34 return
35 }
36 if req.Header.Get("User-Agent") == "" {
37 req.Header.Set("User-Agent", fallback.Get("User-Agent"))
38 }
39 if req.Header.Get("x-opencode-session") != "" {
40 return
41 }
42 id, _ := req.Context().Value(cacheSessionContextKey{}).(string)
43 if id == "" {
44 id = fallback.Get("x-opencode-session")
45 }
46 if id != "" {
47 req.Header.Set("x-opencode-session", id)
48 }
49 }
50
50 lines GO