provider-gateway.test.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import { AISDK } from "@opencode-ai/core/aisdk"
  2. import { describe, expect, mock } from "bun:test"
  3. import { Effect } from "effect"
  4. import { ModelV2 } from "@opencode-ai/core/model"
  5. import { PluginV2 } from "@opencode-ai/core/plugin"
  6. import { PluginHost } from "@opencode-ai/core/plugin/host"
  7. import { GatewayPlugin } from "@opencode-ai/core/plugin/provider/gateway"
  8. import { ProviderV2 } from "@opencode-ai/core/provider"
  9. import { testEffect } from "../lib/effect"
  10. import { PluginTestLayer } from "./fixture"
  11. const gatewayCalls: Record<string, unknown>[] = []
  12. const vercelGatewayModels = ["anthropic/claude-sonnet-4", "openai/gpt-5", "google/gemini-2.5-pro"]
  13. const it = testEffect(PluginTestLayer)
  14. const addPlugin = Effect.fn(function* () {
  15. const plugin = yield* PluginV2.Service
  16. const aisdk = yield* AISDK.Service
  17. const host = yield* PluginHost.make(plugin)
  18. yield* GatewayPlugin.effect(host)
  19. })
  20. mock.module("@ai-sdk/gateway", () => ({
  21. createGateway(options: Record<string, unknown>) {
  22. gatewayCalls.push({ ...options })
  23. return {
  24. languageModel(modelID: string) {
  25. return {
  26. modelId: modelID,
  27. provider: options.name,
  28. specificationVersion: "v3",
  29. }
  30. },
  31. }
  32. },
  33. }))
  34. describe("GatewayPlugin", () => {
  35. it.effect("creates a Gateway SDK for @ai-sdk/gateway", () =>
  36. Effect.gen(function* () {
  37. gatewayCalls.length = 0
  38. const plugin = yield* PluginV2.Service
  39. const aisdk = yield* AISDK.Service
  40. yield* addPlugin()
  41. const result = yield* aisdk.runSDK({
  42. model: ModelV2.Info.make({
  43. ...ModelV2.Info.empty(ProviderV2.ID.make("gateway"), ModelV2.ID.make("model")),
  44. modelID: ModelV2.ID.make("model"),
  45. package: "aisdk:test-provider",
  46. }),
  47. package: "@ai-sdk/gateway",
  48. options: { name: "gateway" },
  49. })
  50. expect(result.sdk).toBeDefined()
  51. expect(gatewayCalls).toHaveLength(1)
  52. }),
  53. )
  54. it.effect("passes the model providerID as the Gateway SDK name", () =>
  55. Effect.gen(function* () {
  56. gatewayCalls.length = 0
  57. const plugin = yield* PluginV2.Service
  58. const aisdk = yield* AISDK.Service
  59. yield* addPlugin()
  60. const result = yield* aisdk.runSDK({
  61. model: ModelV2.Info.make({
  62. ...ModelV2.Info.empty(ProviderV2.ID.make("vercel"), ModelV2.ID.make("anthropic/claude-sonnet-4")),
  63. modelID: ModelV2.ID.make("anthropic/claude-sonnet-4"),
  64. package: "aisdk:test-provider",
  65. }),
  66. package: "@ai-sdk/gateway",
  67. options: { name: "vercel", apiKey: "test-key" },
  68. })
  69. expect(gatewayCalls).toEqual([{ name: "vercel", apiKey: "test-key" }])
  70. expect(result.sdk.languageModel("anthropic/claude-sonnet-4").provider).toBe("vercel")
  71. }),
  72. )
  73. it.effect("matches Vercel AI Gateway models by their @ai-sdk/gateway package", () =>
  74. Effect.gen(function* () {
  75. gatewayCalls.length = 0
  76. const plugin = yield* PluginV2.Service
  77. const aisdk = yield* AISDK.Service
  78. yield* addPlugin()
  79. for (const modelID of vercelGatewayModels) {
  80. const ignored = yield* aisdk.runSDK({
  81. model: ModelV2.Info.make({
  82. ...ModelV2.Info.empty(ProviderV2.ID.make("vercel"), ModelV2.ID.make(modelID)),
  83. modelID: ModelV2.ID.make(modelID),
  84. package: "aisdk:test-provider",
  85. }),
  86. package: "@ai-sdk/vercel",
  87. options: { name: "vercel" },
  88. })
  89. expect(ignored.sdk).toBeUndefined()
  90. const result = yield* aisdk.runSDK({
  91. model: ModelV2.Info.make({
  92. ...ModelV2.Info.empty(ProviderV2.ID.make("vercel"), ModelV2.ID.make(modelID)),
  93. modelID: ModelV2.ID.make(modelID),
  94. package: "aisdk:test-provider",
  95. }),
  96. package: "@ai-sdk/gateway",
  97. options: { name: "vercel" },
  98. })
  99. expect(result.sdk).toBeDefined()
  100. }
  101. expect(gatewayCalls).toHaveLength(3)
  102. }),
  103. )
  104. })