github.com/anthropics/anthropic-sdk-go@v1.70.1/internal/stainlessheader/stainlessheader.go (about) 1 // Package stainlessheader is the single source of truth for the 2 // x-stainless-helper telemetry header — the key, the closed set of tag 3 // values shared across SDKs, and the append-don't-clobber request option. 4 package stainlessheader 5 6 import ( 7 "net/http" 8 "strings" 9 10 "github.com/anthropics/anthropic-sdk-go/internal/requestconfig" 11 ) 12 13 // Header is the helper-telemetry header key. Always this lowercase form; 14 // http.Header is case-insensitive but a single canonical casing keeps every 15 // call site greppable. 16 const Header = "x-stainless-helper" 17 18 // Value is the closed set of helper-telemetry tags, shared verbatim across 19 // SDKs. A typo at a call site is caught by the unused-const check rather than 20 // silently mistagged. Existing values keep their original spellings — telemetry 21 // consumers match on them, so renames lose history. New tags are hyphenated 22 // lowercase; add them here (and to the matching set in every other SDK) before 23 // using them. 24 type Value string 25 26 const ( 27 BetaToolRunner Value = "BetaToolRunner" 28 Compaction Value = "compaction" 29 EnvironmentsWorkPoller Value = "environments-work-poller" 30 EnvironmentsWorker Value = "environments-worker" 31 FallbackRefusalMiddleware Value = "fallback-refusal-middleware" 32 SessionToolRunner Value = "session-tool-runner" 33 ) 34 35 // With returns a request option (assignable to [option.RequestOption]) that 36 // appends value to the x-stainless-helper header rather than replacing it — 37 // the backend logs the header as one opaque string, so a second header line or 38 // a clobbered value loses data. Existing tags keep their position; the new tag 39 // appends at the end; duplicates are dropped. 40 func With(value Value) requestconfig.RequestOption { 41 return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { 42 AppendHeaderValue(r.Request.Header, value) 43 return nil 44 }) 45 } 46 47 // AppendHeaderValue appends value to h's x-stainless-helper entry in place, 48 // collapsing any existing values (under any casing, across multiple lines) 49 // into one comma-joined deduplicated string. Exposed for code paths that hold 50 // a [*http.Request] rather than a request option chain (e.g. middleware). 51 func AppendHeaderValue(h http.Header, value Value) { 52 var tokens []string 53 seen := map[string]struct{}{} 54 add := func(tok string) { 55 if tok == "" { 56 return 57 } 58 if _, ok := seen[tok]; ok { 59 return 60 } 61 seen[tok] = struct{}{} 62 tokens = append(tokens, tok) 63 } 64 for _, existing := range h.Values(Header) { 65 for _, tok := range strings.Split(existing, ",") { 66 add(strings.TrimSpace(tok)) 67 } 68 } 69 add(string(value)) 70 h.Set(Header, strings.Join(tokens, ", ")) 71 }