provider-openai-compatible.test.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { AISDK } from "@opencode-ai/core/aisdk"
  2. import { describe, expect } 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 { OpenAICompatiblePlugin } from "@opencode-ai/core/plugin/provider/openai-compatible"
  8. import { ProviderV2 } from "@opencode-ai/core/provider"
  9. import { testEffect } from "../lib/effect"
  10. import { PluginTestLayer } from "./fixture"
  11. const it = testEffect(PluginTestLayer)
  12. const addPlugin = Effect.fn(function* () {
  13. const plugin = yield* PluginV2.Service
  14. const aisdk = yield* AISDK.Service
  15. const host = yield* PluginHost.make(plugin)
  16. yield* OpenAICompatiblePlugin.effect(host)
  17. })
  18. describe("OpenAICompatiblePlugin", () => {
  19. it.effect("preserves explicit includeUsage false and defaults it to true", () =>
  20. Effect.gen(function* () {
  21. const plugin = yield* PluginV2.Service
  22. const aisdk = yield* AISDK.Service
  23. yield* addPlugin()
  24. const defaulted = yield* aisdk.runSDK({
  25. model: ModelV2.Info.make({
  26. ...ModelV2.Info.empty(ProviderV2.ID.make("custom"), ModelV2.ID.make("model")),
  27. modelID: ModelV2.ID.make("model"),
  28. package: "aisdk:test-provider",
  29. }),
  30. package: "@ai-sdk/openai-compatible",
  31. options: { name: "custom" },
  32. })
  33. const disabled = yield* aisdk.runSDK({
  34. model: ModelV2.Info.make({
  35. ...ModelV2.Info.empty(ProviderV2.ID.make("custom"), ModelV2.ID.make("model")),
  36. modelID: ModelV2.ID.make("model"),
  37. package: "aisdk:test-provider",
  38. }),
  39. package: "@ai-sdk/openai-compatible",
  40. options: { name: "custom", includeUsage: false },
  41. })
  42. expect(defaulted.options.includeUsage).toBe(true)
  43. expect(disabled.options.includeUsage).toBe(false)
  44. }),
  45. )
  46. it.effect("defaults includeUsage for OpenAI-compatible package matches", () =>
  47. Effect.gen(function* () {
  48. const plugin = yield* PluginV2.Service
  49. const aisdk = yield* AISDK.Service
  50. yield* addPlugin()
  51. const result = yield* aisdk.runSDK({
  52. model: ModelV2.Info.make({
  53. ...ModelV2.Info.empty(ProviderV2.ID.make("custom"), ModelV2.ID.make("model")),
  54. modelID: ModelV2.ID.make("model"),
  55. package: "aisdk:test-provider",
  56. }),
  57. package: "file:///tmp/@ai-sdk/openai-compatible-provider.js",
  58. options: { name: "custom" },
  59. })
  60. expect(result.options.includeUsage).toBe(true)
  61. }),
  62. )
  63. it.effect("uses the provider ID as the OpenAI-compatible provider name", () =>
  64. Effect.gen(function* () {
  65. const plugin = yield* PluginV2.Service
  66. const aisdk = yield* AISDK.Service
  67. const observed: string[] = []
  68. yield* addPlugin()
  69. yield* aisdk.hook.sdk((event) =>
  70. Effect.sync(() => {
  71. observed.push(event.sdk.languageModel("model").provider)
  72. }),
  73. )
  74. yield* aisdk.runSDK({
  75. model: ModelV2.Info.make({
  76. ...ModelV2.Info.empty(ProviderV2.ID.make("custom-provider"), ModelV2.ID.make("model")),
  77. modelID: ModelV2.ID.make("model"),
  78. package: "aisdk:test-provider",
  79. }),
  80. package: "@ai-sdk/openai-compatible",
  81. options: { name: "custom-provider", baseURL: "https://example.com/v1" },
  82. })
  83. expect(observed).toEqual(["custom-provider.chat"])
  84. }),
  85. )
  86. it.effect("does not overwrite an SDK created by an earlier provider-specific plugin", () =>
  87. Effect.gen(function* () {
  88. const aisdk = yield* AISDK.Service
  89. const sentinel = { languageModel: (modelID: string) => ({ modelID }) }
  90. yield* aisdk.hook.sdk((event) => {
  91. event.sdk = sentinel
  92. })
  93. yield* addPlugin()
  94. const result = yield* aisdk.runSDK({
  95. model: ModelV2.Info.make({
  96. ...ModelV2.Info.empty(ProviderV2.ID.make("cloudflare-workers-ai"), ModelV2.ID.make("model")),
  97. modelID: ModelV2.ID.make("model"),
  98. package: "aisdk:test-provider",
  99. }),
  100. package: "@ai-sdk/openai-compatible",
  101. options: { name: "cloudflare-workers-ai" },
  102. })
  103. expect(result.sdk).toBe(sentinel)
  104. }),
  105. )
  106. })