From 7c0db58919f204ec5ee47e1093d563515109a542 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 3 Jun 2026 13:35:15 -0400 Subject: [PATCH] test(core): cover v1 provider option lowering --- .../core/src/v1/config/provider-options.ts | 3 +- .../core/test/config/provider-options.test.ts | 208 ++++++++++++++++++ 2 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 packages/core/test/config/provider-options.test.ts diff --git a/packages/core/src/v1/config/provider-options.ts b/packages/core/src/v1/config/provider-options.ts index 6caeaacb49f5..a441a1a211d0 100644 --- a/packages/core/src/v1/config/provider-options.ts +++ b/packages/core/src/v1/config/provider-options.ts @@ -64,8 +64,7 @@ const anthropic: Lowerer = { delete result.task_budget } if (isRecord(options.metadata) && options.metadata.userId !== undefined) { - result.metadata = { ...options.metadata, user_id: options.metadata.userId } - delete (result.metadata as Record).userId + result.metadata = { ...(isRecord(result.metadata) ? result.metadata : {}), user_id: options.metadata.userId } } return result }, diff --git a/packages/core/test/config/provider-options.test.ts b/packages/core/test/config/provider-options.test.ts new file mode 100644 index 000000000000..c38f0eeee7e3 --- /dev/null +++ b/packages/core/test/config/provider-options.test.ts @@ -0,0 +1,208 @@ +import { describe, expect, test } from "bun:test" +import { ConfigProviderOptionsV1 } from "@opencode-ai/core/v1/config/provider-options" + +describe("ConfigProviderOptionsV1", () => { + test("keeps raw provider and request options unchanged", () => { + const lowerer = ConfigProviderOptionsV1.get("custom-provider") + + expect(lowerer.provider({ apiKey: "secret", headers: { "x-test": "1" }, nested: { camelCase: true } })).toEqual({ + body: { apiKey: "secret", headers: { "x-test": "1" }, nested: { camelCase: true } }, + }) + expect(lowerer.request({ nested: { camelCase: true } })).toEqual({ nested: { camelCase: true } }) + }) + + test("falls back to raw lowering for prototype property package names", () => { + expect(ConfigProviderOptionsV1.get("toString").provider({ enabled: true })).toEqual({ body: { enabled: true } }) + }) + + test("lowers OpenAI provider and request options", () => { + const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/openai") + + expect( + lowerer.provider({ + apiKey: "secret", + baseURL: "https://openai.example/v1", + organization: "org", + project: "project", + headers: { "x-test": "1" }, + body: { store: true }, + timeout: 1000, + }), + ).toEqual({ + url: "https://openai.example/v1", + headers: { + Authorization: "Bearer secret", + "OpenAI-Organization": "org", + "OpenAI-Project": "project", + "x-test": "1", + }, + body: { store: true }, + settings: { timeout: 1000 }, + }) + expect(lowerer.request({ reasoningEffort: "high", nestedValue: { camelCase: true } })).toEqual({ + reasoning_effort: "high", + nested_value: { camel_case: true }, + }) + }) + + test("lowers Anthropic provider and request options", () => { + const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/anthropic") + + expect( + lowerer.provider({ + apiKey: "secret", + authToken: "token", + baseURL: "https://anthropic.example", + headers: { "x-test": "1" }, + body: { beta: true }, + generateId: "custom", + }), + ).toEqual({ + url: "https://anthropic.example", + headers: { "x-api-key": "secret", Authorization: "Bearer token", "x-test": "1" }, + body: { beta: true }, + settings: { generateId: "custom" }, + }) + expect( + lowerer.request({ + effort: "high", + taskBudget: 1024, + metadata: { userId: "user", traceId: "trace" }, + nestedValue: { camelCase: true }, + }), + ).toEqual({ + output_config: { effort: "high", task_budget: 1024 }, + metadata: { user_id: "user", trace_id: "trace" }, + nested_value: { camel_case: true }, + }) + }) + + test("lowers Google provider and request options", () => { + const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/google") + + expect( + lowerer.provider({ + apiKey: "secret", + baseURL: "https://google.example", + headers: { "x-test": "1" }, + body: { trace: true }, + project: "project", + }), + ).toEqual({ + url: "https://google.example", + headers: { "x-goog-api-key": "secret", "x-test": "1" }, + body: { trace: true }, + settings: { project: "project" }, + }) + expect( + lowerer.request({ + thinkingConfig: { thinkingBudget: 1024 }, + responseModalities: ["TEXT"], + mediaResolution: "high", + imageConfig: { aspectRatio: "16:9" }, + safetySettings: ["safe"], + }), + ).toEqual({ + safetySettings: ["safe"], + generationConfig: { + thinkingConfig: { thinkingBudget: 1024 }, + responseModalities: ["TEXT"], + mediaResolution: "high", + imageConfig: { aspectRatio: "16:9" }, + }, + }) + }) + + test("lowers Azure provider options and uses OpenAI request lowering", () => { + const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/azure") + + expect( + lowerer.provider({ + apiKey: "secret", + baseURL: "https://azure.example", + headers: { "x-test": "1" }, + body: { trace: true }, + resourceName: "resource", + }), + ).toEqual({ + url: "https://azure.example", + headers: { "api-key": "secret", "x-test": "1" }, + body: { trace: true }, + settings: { resourceName: "resource" }, + }) + expect(lowerer.request({ reasoningEffort: "high" })).toEqual({ reasoning_effort: "high" }) + }) + + test("lowers Amazon Bedrock provider and request options", () => { + const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/amazon-bedrock") + + expect( + lowerer.provider({ + headers: { "x-test": "1" }, + body: { trace: true }, + region: "us-east-1", + profile: "dev", + }), + ).toEqual({ + headers: { "x-test": "1" }, + body: { trace: true }, + settings: { region: "us-east-1", profile: "dev" }, + }) + expect(lowerer.request({ temperature: 0.2 })).toEqual({ + additionalModelRequestFields: { temperature: 0.2 }, + }) + }) + + test("lowers OpenAI-compatible provider and request options", () => { + const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/openai-compatible") + + expect( + lowerer.provider({ + baseURL: "https://compatible.example/v1", + headers: { "x-test": "1" }, + body: { trace: true }, + apiKey: "secret", + }), + ).toEqual({ + url: "https://compatible.example/v1", + headers: { "x-test": "1" }, + body: { trace: true }, + settings: { apiKey: "secret" }, + }) + expect(lowerer.request({ reasoningEffort: "high", serviceTier: "priority" })).toEqual({ + reasoning_effort: "high", + serviceTier: "priority", + }) + }) + + test.each([ + "@ai-sdk/cerebras", + "@ai-sdk/deepinfra", + "@ai-sdk/groq", + "@ai-sdk/mistral", + "@ai-sdk/togetherai", + "@ai-sdk/xai", + "@openrouter/ai-sdk-provider", + "ai-gateway-provider", + "venice-ai-sdk-provider", + ])("uses OpenAI-compatible lowering for %s", (packageName) => { + const lowerer = ConfigProviderOptionsV1.get(packageName) + + expect(lowerer.provider({ baseURL: "https://example.test", apiKey: "secret" })).toEqual({ + url: "https://example.test", + headers: undefined, + body: undefined, + settings: { apiKey: "secret" }, + }) + expect(lowerer.request({ reasoningEffort: "high" })).toEqual({ reasoning_effort: "high" }) + }) + + test.each(["@ai-sdk/google-vertex", "@ai-sdk/google-vertex/anthropic"])("uses provider family lowering for %s", (packageName) => { + const lowerer = ConfigProviderOptionsV1.get(packageName) + + expect(lowerer.provider({ baseURL: "https://example.test", profile: "dev" })).toMatchObject({ + url: "https://example.test", + settings: { profile: "dev" }, + }) + }) +})