provider-openai-compatible.test.ts 3.3 KB

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