From c10b269b52593f50c5dee850069e42a748ac9e7b Mon Sep 17 00:00:00 2001 From: damaozi <1811866786@qq.com> Date: Wed, 4 Feb 2026 01:31:01 +0800 Subject: [PATCH] fix(provider): apply config headers to fetch requests Fixes #11789 The custom fetch function in getSDK was not merging options["headers"] (which contains provider/model headers from config) into the actual fetch request headers. Solution: Merge options["headers"] into opts.headers before calling fetch. Changes: - packages/opencode/src/provider/provider.ts: merge headers in custom fetch - packages/opencode/test/provider/provider.test.ts: add tests for header config --- packages/opencode/src/provider/provider.ts | 5 ++ .../opencode/test/provider/provider.test.ts | 75 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index e01c583ff348..a011c9a7bcba 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -1020,6 +1020,11 @@ export namespace Provider { } } + opts.headers = { + ...(typeof opts.headers === "object" ? opts.headers : {}), + ...options["headers"], + } + return fetchFn(input, { ...opts, // @ts-ignore see here: https://github.com/oven-sh/bun/issues/16682 diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts index 482587d8ac50..1cbfa3a19e18 100644 --- a/packages/opencode/test/provider/provider.test.ts +++ b/packages/opencode/test/provider/provider.test.ts @@ -2148,3 +2148,78 @@ test("custom model with variants enabled and disabled", async () => { }, }) }) + +test("provider headers from config are applied to fetch requests", async () => { + let capturedHeaders: Record | undefined + + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + provider: { + anthropic: { + options: { + headers: { + "X-Custom-Header": "custom-value", + "User-Agent": "MyCustomAgent/1.0", + }, + }, + }, + }, + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("ANTHROPIC_API_KEY", "test-api-key") + }, + fn: async () => { + const providers = await Provider.list() + expect(providers["anthropic"]).toBeDefined() + // Verify headers are in provider options + expect(providers["anthropic"].options.headers).toBeDefined() + expect(providers["anthropic"].options.headers["X-Custom-Header"]).toBe("custom-value") + expect(providers["anthropic"].options.headers["User-Agent"]).toBe("MyCustomAgent/1.0") + }, + }) +}) + +test("model headers from config are merged with provider headers", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + provider: { + anthropic: { + models: { + "claude-sonnet-4-20250514": { + headers: { + "X-Model-Header": "model-value", + }, + }, + }, + }, + }, + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("ANTHROPIC_API_KEY", "test-api-key") + }, + fn: async () => { + const providers = await Provider.list() + const model = providers["anthropic"].models["claude-sonnet-4-20250514"] + expect(model.headers).toBeDefined() + expect(model.headers["X-Model-Header"]).toBe("model-value") + }, + }) +})