Skip to content

Commit d6d1e1e

Browse files
authored
feat: add extra headers support to responses endpoint (#154)
1 parent 96099fd commit d6d1e1e

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

intercept/responses/base.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ type responsesInterceptionBase struct {
5252
func (i *responsesInterceptionBase) newResponsesService() responses.ResponseService {
5353
opts := []option.RequestOption{option.WithBaseURL(i.cfg.BaseURL), option.WithAPIKey(i.cfg.Key)}
5454

55+
// Add extra headers if configured.
56+
// Some providers require additional headers that are not added by the SDK.
57+
for key, value := range i.cfg.ExtraHeaders {
58+
opts = append(opts, option.WithHeader(key, value))
59+
}
60+
5561
// Add API dump middleware if configured
5662
if mw := apidump.NewMiddleware(i.cfg.APIDumpDir, config.ProviderOpenAI, i.Model(), i.id, i.logger, quartz.NewReal()); mw != nil {
5763
opts = append(opts, option.WithMiddleware(mw))

provider/copilot_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,53 @@ func TestCopilot_CreateInterceptor(t *testing.T) {
221221
assert.Contains(t, err.Error(), "unmarshal responses request body")
222222
})
223223

224+
t.Run("Responses_ForwardsHeadersToUpstream", func(t *testing.T) {
225+
t.Parallel()
226+
227+
var receivedHeaders http.Header
228+
229+
// Mock upstream that captures headers
230+
mockUpstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
231+
receivedHeaders = r.Header.Clone()
232+
w.Header().Set("Content-Type", "application/json")
233+
w.WriteHeader(http.StatusOK)
234+
_, _ = w.Write([]byte(`{"id":"resp-123","object":"responses.response","created":1677652288,"model":"gpt-5-mini","output":[],"usage":{"input_tokens":5,"output_tokens":10,"total_tokens":15}}`))
235+
}))
236+
t.Cleanup(mockUpstream.Close)
237+
238+
// Create provider with mock upstream URL
239+
provider := NewCopilot(config.Copilot{
240+
BaseURL: mockUpstream.URL,
241+
})
242+
243+
body := `{"model": "gpt-5-mini", "input": "hello", "stream": false}`
244+
req := httptest.NewRequest(http.MethodPost, routeCopilotResponses, bytes.NewBufferString(body))
245+
req.Header.Set("Authorization", "Bearer test-token")
246+
req.Header.Set("Editor-Version", "vscode/1.85.0")
247+
req.Header.Set("Copilot-Integration-Id", "test-integration")
248+
req.Header.Set("X-Custom-Header", "should-not-forward")
249+
w := httptest.NewRecorder()
250+
251+
interceptor, err := provider.CreateInterceptor(w, req, testTracer)
252+
require.NoError(t, err)
253+
require.NotNil(t, interceptor)
254+
255+
// Setup and process request
256+
logger := slog.Make()
257+
interceptor.Setup(logger, &testutil.MockRecorder{}, nil)
258+
259+
processReq := httptest.NewRequest(http.MethodPost, routeCopilotResponses, nil)
260+
err = interceptor.ProcessRequest(w, processReq)
261+
require.NoError(t, err)
262+
263+
// Verify headers were forwarded
264+
assert.Equal(t, "vscode/1.85.0", receivedHeaders.Get("Editor-Version"))
265+
assert.Equal(t, "test-integration", receivedHeaders.Get("Copilot-Integration-Id"))
266+
267+
// Verify non-Copilot headers are not forwarded
268+
assert.Empty(t, receivedHeaders.Get("X-Custom-Header"), "non-Copilot headers should not be forwarded")
269+
})
270+
224271
t.Run("UnknownRoute", func(t *testing.T) {
225272
t.Parallel()
226273

0 commit comments

Comments
 (0)