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  }