diff --git a/packages/coding-agent/src/core/provider-attribution.ts b/packages/coding-agent/src/core/provider-attribution.ts index 16bea3e..4491303 100644 --- a/packages/coding-agent/src/core/provider-attribution.ts +++ b/packages/coding-agent/src/core/provider-attribution.ts @@ -3,6 +3,12 @@ import { APP_NAME } from "../config.ts"; const OPENCODE_HOST = "opencode.ai"; +const OPENROUTER_ATTRIBUTION_HEADERS: ProviderHeaders = { + "HTTP-Referer": "https://github.com/stepfun-ai/Step-Code", + "X-OpenRouter-Title": "StepCode", + "X-OpenRouter-Categories": "cli-agent", +}; + function matchesHost(baseUrl: string, expectedHost: string): boolean { try { return new URL(baseUrl).hostname === expectedHost; @@ -29,6 +35,7 @@ export function mergeProviderAttributionHeaders( ...headerSources: Array ): ProviderHeaders | undefined { const merged: ProviderHeaders = { + ...OPENROUTER_ATTRIBUTION_HEADERS, ...getSessionHeaders(model, sessionId), }; diff --git a/packages/coding-agent/test/sdk-openrouter-attribution.test.ts b/packages/coding-agent/test/sdk-openrouter-attribution.test.ts index c6e38fa..2547a2a 100644 --- a/packages/coding-agent/test/sdk-openrouter-attribution.test.ts +++ b/packages/coding-agent/test/sdk-openrouter-attribution.test.ts @@ -132,12 +132,20 @@ describe("createAgentSession provider headers", () => { } } - it("does not add provider attribution headers for OpenRouter models", async () => { + it("adds StepCode attribution headers for OpenRouter models without changing the provider", async () => { const headers = await captureHeaders(createModel("openrouter", "https://openrouter.ai/api/v1")); - expect(headers?.["HTTP-Referer"]).toBeUndefined(); - expect(headers?.["X-OpenRouter-Title"]).toBeUndefined(); - expect(headers?.["X-OpenRouter-Categories"]).toBeUndefined(); + expect(headers?.["HTTP-Referer"]).toBe("https://github.com/stepfun-ai/Step-Code"); + expect(headers?.["X-OpenRouter-Title"]).toBe("StepCode"); + expect(headers?.["X-OpenRouter-Categories"]).toBe("cli-agent"); + }); + + it("adds StepCode attribution headers for other providers", async () => { + const headers = await captureHeaders(createModel("custom", "https://provider.example/v1")); + + expect(headers?.["HTTP-Referer"]).toBe("https://github.com/stepfun-ai/Step-Code"); + expect(headers?.["X-OpenRouter-Title"]).toBe("StepCode"); + expect(headers?.["X-OpenRouter-Categories"]).toBe("cli-agent"); }); it("does not add provider attribution headers for NVIDIA NIM endpoints", async () => { @@ -146,7 +154,7 @@ describe("createAgentSession provider headers", () => { expect(headers?.["X-BILLING-INVOKE-ORIGIN"]).toBeUndefined(); }); - it("passes provider and request headers through", async () => { + it("lets configured OpenRouter attribution override the defaults", async () => { const headers = await captureHeaders(createModel("openrouter", "https://openrouter.ai/api/v1"), { providerHeaders: { "HTTP-Referer": "https://provider.example", @@ -157,6 +165,7 @@ describe("createAgentSession provider headers", () => { }); expect(headers?.["HTTP-Referer"]).toBe("https://provider.example"); + expect(headers?.["X-OpenRouter-Title"]).toBe("StepCode"); expect(headers?.["X-Request-Header"]).toBe("request-value"); });