provider-options.test.ts 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import { describe, expect, test } from "bun:test"
  2. import { ConfigProviderOptionsV1 } from "@opencode-ai/core/v1/config/provider-options"
  3. describe("ConfigProviderOptionsV1", () => {
  4. test("keeps raw provider and request options unchanged", () => {
  5. const lowerer = ConfigProviderOptionsV1.get("custom-provider")
  6. expect(lowerer.provider({ apiKey: "secret", headers: { "x-test": "1" }, nested: { camelCase: true } })).toEqual({
  7. body: { apiKey: "secret", headers: { "x-test": "1" }, nested: { camelCase: true } },
  8. })
  9. expect(lowerer.request({ nested: { camelCase: true } })).toEqual({ nested: { camelCase: true } })
  10. })
  11. test("falls back to raw lowering for prototype property package names", () => {
  12. expect(ConfigProviderOptionsV1.get("toString").provider({ enabled: true })).toEqual({ body: { enabled: true } })
  13. })
  14. test("lowers OpenAI provider and request options", () => {
  15. const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/openai")
  16. expect(
  17. lowerer.provider({
  18. apiKey: "secret",
  19. baseURL: "https://openai.example/v1",
  20. organization: "org",
  21. project: "project",
  22. headers: { "x-test": "1" },
  23. body: { store: true },
  24. timeout: 1000,
  25. }),
  26. ).toEqual({
  27. url: "https://openai.example/v1",
  28. headers: {
  29. Authorization: "Bearer secret",
  30. "OpenAI-Organization": "org",
  31. "OpenAI-Project": "project",
  32. "x-test": "1",
  33. },
  34. body: { store: true },
  35. settings: { timeout: 1000 },
  36. })
  37. expect(lowerer.request({ reasoningEffort: "high", nestedValue: { camelCase: true } })).toEqual({
  38. reasoning_effort: "high",
  39. nested_value: { camel_case: true },
  40. })
  41. })
  42. test("lowers Anthropic provider and request options", () => {
  43. const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/anthropic")
  44. expect(
  45. lowerer.provider({
  46. apiKey: "secret",
  47. authToken: "token",
  48. baseURL: "https://anthropic.example",
  49. headers: { "x-test": "1" },
  50. body: { beta: true },
  51. generateId: "custom",
  52. }),
  53. ).toEqual({
  54. url: "https://anthropic.example",
  55. headers: { "x-api-key": "secret", Authorization: "Bearer token", "x-test": "1" },
  56. body: { beta: true },
  57. settings: { generateId: "custom" },
  58. })
  59. expect(
  60. lowerer.request({
  61. effort: "high",
  62. taskBudget: 1024,
  63. metadata: { userId: "user", traceId: "trace" },
  64. nestedValue: { camelCase: true },
  65. }),
  66. ).toEqual({
  67. output_config: { effort: "high", task_budget: 1024 },
  68. metadata: { user_id: "user", trace_id: "trace" },
  69. nested_value: { camel_case: true },
  70. })
  71. })
  72. test("lowers Google provider and request options", () => {
  73. const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/google")
  74. expect(
  75. lowerer.provider({
  76. apiKey: "secret",
  77. baseURL: "https://google.example",
  78. headers: { "x-test": "1" },
  79. body: { trace: true },
  80. project: "project",
  81. }),
  82. ).toEqual({
  83. url: "https://google.example",
  84. headers: { "x-goog-api-key": "secret", "x-test": "1" },
  85. body: { trace: true },
  86. settings: { project: "project" },
  87. })
  88. expect(
  89. lowerer.request({
  90. thinkingConfig: { thinkingBudget: 1024 },
  91. responseModalities: ["TEXT"],
  92. mediaResolution: "high",
  93. imageConfig: { aspectRatio: "16:9" },
  94. safetySettings: ["safe"],
  95. }),
  96. ).toEqual({
  97. safetySettings: ["safe"],
  98. generationConfig: {
  99. thinkingConfig: { thinkingBudget: 1024 },
  100. responseModalities: ["TEXT"],
  101. mediaResolution: "high",
  102. imageConfig: { aspectRatio: "16:9" },
  103. },
  104. })
  105. })
  106. test("lowers Azure provider options and uses OpenAI request lowering", () => {
  107. const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/azure")
  108. expect(
  109. lowerer.provider({
  110. apiKey: "secret",
  111. baseURL: "https://azure.example",
  112. headers: { "x-test": "1" },
  113. body: { trace: true },
  114. resourceName: "resource",
  115. }),
  116. ).toEqual({
  117. url: "https://azure.example",
  118. headers: { "api-key": "secret", "x-test": "1" },
  119. body: { trace: true },
  120. settings: { resourceName: "resource" },
  121. })
  122. expect(lowerer.request({ reasoningEffort: "high" })).toEqual({ reasoning_effort: "high" })
  123. })
  124. test("lowers Amazon Bedrock provider and request options", () => {
  125. const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/amazon-bedrock")
  126. expect(
  127. lowerer.provider({
  128. headers: { "x-test": "1" },
  129. body: { trace: true },
  130. region: "us-east-1",
  131. profile: "dev",
  132. }),
  133. ).toEqual({
  134. headers: { "x-test": "1" },
  135. body: { trace: true },
  136. settings: { region: "us-east-1", profile: "dev" },
  137. })
  138. expect(lowerer.request({ temperature: 0.2 })).toEqual({
  139. additionalModelRequestFields: { temperature: 0.2 },
  140. })
  141. })
  142. test("lowers OpenAI-compatible provider and request options", () => {
  143. const lowerer = ConfigProviderOptionsV1.get("@ai-sdk/openai-compatible")
  144. expect(
  145. lowerer.provider({
  146. baseURL: "https://compatible.example/v1",
  147. headers: { "x-test": "1" },
  148. body: { trace: true },
  149. apiKey: "secret",
  150. }),
  151. ).toEqual({
  152. url: "https://compatible.example/v1",
  153. headers: { "x-test": "1" },
  154. body: { trace: true },
  155. settings: { apiKey: "secret" },
  156. })
  157. expect(lowerer.request({ reasoningEffort: "high", serviceTier: "priority" })).toEqual({
  158. reasoning_effort: "high",
  159. serviceTier: "priority",
  160. })
  161. })
  162. test.each([
  163. "@ai-sdk/cerebras",
  164. "@ai-sdk/deepinfra",
  165. "@ai-sdk/groq",
  166. "@ai-sdk/mistral",
  167. "@ai-sdk/togetherai",
  168. "@ai-sdk/xai",
  169. "@openrouter/ai-sdk-provider",
  170. "ai-gateway-provider",
  171. "venice-ai-sdk-provider",
  172. ])("uses OpenAI-compatible lowering for %s", (packageName) => {
  173. const lowerer = ConfigProviderOptionsV1.get(packageName)
  174. expect(lowerer.provider({ baseURL: "https://example.test", apiKey: "secret" })).toEqual({
  175. url: "https://example.test",
  176. headers: undefined,
  177. body: undefined,
  178. settings: { apiKey: "secret" },
  179. })
  180. expect(lowerer.request({ reasoningEffort: "high" })).toEqual({ reasoning_effort: "high" })
  181. })
  182. test.each(["@ai-sdk/google-vertex", "@ai-sdk/google-vertex/anthropic"])(
  183. "uses provider family lowering for %s",
  184. (packageName) => {
  185. const lowerer = ConfigProviderOptionsV1.get(packageName)
  186. expect(lowerer.provider({ baseURL: "https://example.test", profile: "dev" })).toMatchObject({
  187. url: "https://example.test",
  188. settings: { profile: "dev" },
  189. })
  190. },
  191. )
  192. })