History

fix(claude): preserve legacy user agent overrides

tpob committed 7 months ago

Commit c7b59071 parent f36a5792 files · +40 −4Browse files

Unified · Split

2 files
  1. internal/runtime/executor/claude_device_profile.go +8 −4
  2. internal/runtime/executor/claude_executor_test.go +32 −0
internal/runtime/executor/claude_device_profile.go+8−4
@@ -308,15 +308,19 @@ func applyClaudeLegacyDeviceHeaders(r *http.Request, ginHeaders http.Header, cfg · 307 unmodified lines
308308 miscEnsure("X-Stainless-Os", mapStainlessOS())
309309 miscEnsure("X-Stainless-Arch", mapStainlessArch())
310310
311+ // Legacy mode preserves per-auth custom header overrides. By the time we get
312+ // here, ApplyCustomHeadersFromAttrs has already populated r.Header.
313+ if strings.TrimSpace(r.Header.Get("User-Agent")) != "" {
314+ return
315+ }
316+
311317 clientUA := ""
312318 if ginHeaders != nil {
313− clientUA = ginHeaders.Get("User-Agent")
319+ clientUA = strings.TrimSpace(ginHeaders.Get("User-Agent"))
314320 }
315321 if isClaudeCodeClient(clientUA) {
316322 r.Header.Set("User-Agent", clientUA)
317323 return
318324 }
319− if strings.TrimSpace(r.Header.Get("User-Agent")) == "" {
320− r.Header.Set("User-Agent", profile.UserAgent)
321− }
325+ r.Header.Set("User-Agent", profile.UserAgent)
322326 }
internal/runtime/executor/claude_executor_test.go+32−0
@@ -216,6 +216,38 @@ func TestApplyClaudeHeaders_DisableDeviceProfileStabilization(t *testing.T) { · 215 unmodified lines
216216 assertClaudeFingerprint(t, lowerReq.Header, "claude-cli/2.1.61 (external, cli)", "0.73.0", "v24.2.0", "Windows", "x64")
217217 }
218218
219+func TestApplyClaudeHeaders_LegacyModePreservesConfiguredUserAgentOverrideForClaudeClients(t *testing.T) {
220+ resetClaudeDeviceProfileCache()
221+
222+ stabilize := false
223+ cfg := &config.Config{
224+ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{
225+ UserAgent: "claude-cli/2.1.60 (external, cli)",
226+ PackageVersion: "0.70.0",
227+ RuntimeVersion: "v22.0.0",
228+ StabilizeDeviceProfile: &stabilize,
229+ },
230+ }
231+ auth := &cliproxyauth.Auth{
232+ ID: "auth-legacy-ua-override",
233+ Attributes: map[string]string{
234+ "api_key": "key-legacy-ua-override",
235+ "header:User-Agent": "config-ua/1.0",
236+ },
237+ }
238+
239+ req := newClaudeHeaderTestRequest(t, http.Header{
240+ "User-Agent": []string{"claude-cli/2.1.62 (external, cli)"},
241+ "X-Stainless-Package-Version": []string{"0.74.0"},
242+ "X-Stainless-Runtime-Version": []string{"v24.3.0"},
243+ "X-Stainless-Os": []string{"Linux"},
244+ "X-Stainless-Arch": []string{"x64"},
245+ })
246+ applyClaudeHeaders(req, auth, "key-legacy-ua-override", false, nil, cfg)
247+
248+ assertClaudeFingerprint(t, req.Header, "config-ua/1.0", "0.74.0", "v24.3.0", "Linux", "x64")
249+}
250+
219251 func TestApplyClaudeHeaders_LegacyModeFallsBackToRuntimeOSArchWhenMissing(t *testing.T) {
220252 resetClaudeDeviceProfileCache()
221253