examples/openai-chat-example/useragent-comparison.md
Implementation Details:
debug.ReadBuildInfo(){program}@{version} langchaingo/{version} ({arch} {os}) Go/{goversion} or langchaingo/{version} ({arch} {os}) Go/{goversion}Transport struct that wraps http.RoundTripperhttputil.DefaultClient used by all providersExample Output:
github.com/user/[email protected] langchaingo/v0.1.8 (arm64 darwin) Go/go1.21.5
Implementation Details:
version = "0.41.0")go-cloud/{api}/{version}ClientOption(), GRPCDialOption(), etc.Example Output:
existing-user-agent go-cloud/storage/0.41.0
Change from replacing to appending the User-Agent header. This is more polite and preserves valuable debugging information from upstream clients.
// Instead of:
newReq.Header.Set("User-Agent", UserAgent())
// Use:
existing := req.Header.Get("User-Agent")
if existing != "" {
newReq.Header.Set("User-Agent", existing + " " + UserAgent())
} else {
newReq.Header.Set("User-Agent", UserAgent())
}
Allow different providers to identify themselves in the User-Agent:
func UserAgent(component string) string {
base := fmt.Sprintf("langchaingo/%s", getLangChainVersion())
if component != "" {
base = fmt.Sprintf("langchaingo/%s/%s", component, getLangChainVersion())
}
// ... rest of the formatting
}
This would enable:
langchaingo/openai/v0.1.8 for OpenAI providerlangchaingo/anthropic/v0.1.8 for Anthropic providerThe dynamic version detection is good for most cases. Consider:
Consider offering a simplified format similar to go-cloud for cases where full system info isn't needed:
func SimpleUserAgent(component string) string {
if component != "" {
return fmt.Sprintf("langchaingo/%s/%s", component, getLangChainVersion())
}
return fmt.Sprintf("langchaingo/%s", getLangChainVersion())
}
Here's a suggested enhanced implementation that incorporates the best of both approaches:
type Transport struct {
Transport http.RoundTripper
Component string // Optional component identifier
Append bool // Whether to append or replace
}
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
transport := t.Transport
if transport == nil {
transport = http.DefaultTransport
}
newReq := req.Clone(req.Context())
userAgent := UserAgent(t.Component)
if t.Append {
existing := req.Header.Get("User-Agent")
if existing != "" {
userAgent = existing + " " + userAgent
}
}
newReq.Header.Set("User-Agent", userAgent)
return transport.RoundTrip(newReq)
}
// Default to appending for better compatibility
var DefaultTransport http.RoundTripper = &Transport{Append: true}
This approach would: