provider-gateway.test.ts 4.1 KB

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