provider-openrouter.test.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import { AISDK } from "@opencode-ai/core/aisdk"
  2. import { describe, expect } from "bun:test"
  3. import { Effect } from "effect"
  4. import { Catalog } from "@opencode-ai/core/catalog"
  5. import { ModelV2 } from "@opencode-ai/core/model"
  6. import { PluginV2 } from "@opencode-ai/core/plugin"
  7. import { PluginHost } from "@opencode-ai/core/plugin/host"
  8. import { ProviderPlugins } from "@opencode-ai/core/plugin/provider"
  9. import { OpenRouterPlugin } from "@opencode-ai/core/plugin/provider/openrouter"
  10. import { ProviderV2 } from "@opencode-ai/core/provider"
  11. import { testEffect } from "../lib/effect"
  12. import { PluginTestLayer } from "./fixture"
  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* OpenRouterPlugin.effect(host)
  19. })
  20. describe("OpenRouterPlugin", () => {
  21. it.effect("is registered so legacy OpenRouter behavior can be applied", () =>
  22. Effect.sync(() => expect(ProviderPlugins.map((item) => item.id)).toContain("opencode.provider.openrouter")),
  23. )
  24. it.effect("applies legacy referer headers only to openrouter", () =>
  25. Effect.gen(function* () {
  26. const catalog = yield* Catalog.Service
  27. yield* catalog.transform((catalog) => {
  28. catalog.provider.update(ProviderV2.ID.openrouter, (provider) => {
  29. provider.package = ProviderV2.aisdk("@openrouter/ai-sdk-provider")
  30. provider.headers = { Existing: "value" }
  31. })
  32. catalog.provider.update(ProviderV2.ID.make("nvidia"), () => {})
  33. })
  34. yield* addPlugin()
  35. expect((yield* catalog.provider.get(ProviderV2.ID.openrouter))?.headers).toEqual({
  36. Existing: "value",
  37. "HTTP-Referer": "https://opencode.ai/",
  38. "X-Title": "opencode",
  39. })
  40. expect((yield* catalog.provider.get(ProviderV2.ID.make("nvidia")))?.headers).toBeUndefined()
  41. }),
  42. )
  43. it.effect("creates an SDK only for the OpenRouter package", () =>
  44. Effect.gen(function* () {
  45. const plugin = yield* PluginV2.Service
  46. const aisdk = yield* AISDK.Service
  47. yield* addPlugin()
  48. const ignored = yield* aisdk.runSDK({
  49. model: ModelV2.Info.make({
  50. ...ModelV2.Info.empty(ProviderV2.ID.openrouter, ModelV2.ID.make("openai/gpt-5")),
  51. modelID: ModelV2.ID.make("openai/gpt-5"),
  52. package: ProviderV2.aisdk("test-provider"),
  53. }),
  54. package: "@ai-sdk/openai-compatible",
  55. options: { name: "openrouter" },
  56. })
  57. expect(ignored.sdk).toBeUndefined()
  58. const result = yield* aisdk.runSDK({
  59. model: ModelV2.Info.make({
  60. ...ModelV2.Info.empty(ProviderV2.ID.make("custom"), ModelV2.ID.make("openai/gpt-5")),
  61. modelID: ModelV2.ID.make("openai/gpt-5"),
  62. package: ProviderV2.aisdk("test-provider"),
  63. }),
  64. package: "@openrouter/ai-sdk-provider",
  65. options: { name: "custom" },
  66. })
  67. expect(result.sdk).toBeDefined()
  68. }),
  69. )
  70. it.effect("filters OpenRouter's gpt-5 chat alias", () =>
  71. Effect.gen(function* () {
  72. const catalog = yield* Catalog.Service
  73. yield* catalog.transform((catalog) => {
  74. catalog.provider.update(ProviderV2.ID.openrouter, (provider) => {
  75. provider.package = ProviderV2.aisdk("@openrouter/ai-sdk-provider")
  76. })
  77. catalog.provider.update(ProviderV2.ID.openai, () => {})
  78. catalog.model.update(ProviderV2.ID.openrouter, ModelV2.ID.make("openai/gpt-5-chat"), () => {})
  79. catalog.model.update(ProviderV2.ID.openrouter, ModelV2.ID.make("openai/gpt-5"), () => {})
  80. catalog.model.update(ProviderV2.ID.openai, ModelV2.ID.make("openai/gpt-5-chat"), () => {})
  81. })
  82. yield* addPlugin()
  83. expect((yield* catalog.model.get(ProviderV2.ID.openrouter, ModelV2.ID.make("openai/gpt-5-chat")))?.enabled).toBe(
  84. false,
  85. )
  86. expect((yield* catalog.model.get(ProviderV2.ID.openrouter, ModelV2.ID.make("openai/gpt-5")))?.enabled).toBe(true)
  87. expect((yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("openai/gpt-5-chat")))?.enabled).toBe(true)
  88. }),
  89. )
  90. it.effect("does not disable gpt-5-chat-latest for non-OpenRouter providers", () =>
  91. Effect.gen(function* () {
  92. const catalog = yield* Catalog.Service
  93. yield* catalog.transform((catalog) => {
  94. catalog.provider.update(ProviderV2.ID.make("custom-openrouter"), () => {})
  95. catalog.model.update(ProviderV2.ID.make("custom-openrouter"), ModelV2.ID.make("gpt-5-chat-latest"), () => {})
  96. })
  97. yield* addPlugin()
  98. expect(
  99. (yield* catalog.model.get(ProviderV2.ID.make("custom-openrouter"), ModelV2.ID.make("gpt-5-chat-latest")))
  100. ?.enabled,
  101. ).toBe(true)
  102. }),
  103. )
  104. })