provider-mistral.test.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import { AISDK } from "@opencode-ai/core/aisdk"
  2. import type { LanguageModelV3 } from "@ai-sdk/provider"
  3. import { describe, expect } from "bun:test"
  4. import { Effect } from "effect"
  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 { MistralPlugin } from "@opencode-ai/core/plugin/provider/mistral"
  9. import { ProviderV2 } from "@opencode-ai/core/provider"
  10. import { testEffect } from "../lib/effect"
  11. import { PluginTestLayer } from "./fixture"
  12. const it = testEffect(PluginTestLayer)
  13. const addPlugin = Effect.fn(function* () {
  14. const plugin = yield* PluginV2.Service
  15. const aisdk = yield* AISDK.Service
  16. const host = yield* PluginHost.make(plugin)
  17. yield* MistralPlugin.effect(host)
  18. })
  19. describe("MistralPlugin", () => {
  20. it.effect("creates a Mistral SDK for @ai-sdk/mistral", () =>
  21. Effect.gen(function* () {
  22. const plugin = yield* PluginV2.Service
  23. const aisdk = yield* AISDK.Service
  24. yield* addPlugin()
  25. const result = yield* aisdk.runSDK({
  26. model: ModelV2.Info.make({
  27. ...ModelV2.Info.empty(ProviderV2.ID.make("mistral"), ModelV2.ID.make("mistral-large")),
  28. modelID: ModelV2.ID.make("mistral-large"),
  29. package: "aisdk:test-provider",
  30. }),
  31. package: "@ai-sdk/mistral",
  32. options: { name: "mistral" },
  33. })
  34. expect(result.sdk).toBeDefined()
  35. }),
  36. )
  37. it.effect("ignores non-Mistral SDK packages", () =>
  38. Effect.gen(function* () {
  39. const plugin = yield* PluginV2.Service
  40. const aisdk = yield* AISDK.Service
  41. yield* addPlugin()
  42. const result = yield* aisdk.runSDK({
  43. model: ModelV2.Info.make({
  44. ...ModelV2.Info.empty(ProviderV2.ID.make("mistral"), ModelV2.ID.make("mistral-large")),
  45. modelID: ModelV2.ID.make("mistral-large"),
  46. package: "aisdk:test-provider",
  47. }),
  48. package: "@ai-sdk/openai-compatible",
  49. options: { name: "mistral" },
  50. })
  51. expect(result.sdk).toBeUndefined()
  52. }),
  53. )
  54. it.effect("matches the old bundled Mistral SDK provider name for the bundled provider ID", () =>
  55. Effect.gen(function* () {
  56. const plugin = yield* PluginV2.Service
  57. const aisdk = yield* AISDK.Service
  58. const providers: string[] = []
  59. yield* addPlugin()
  60. yield* aisdk.hook.sdk((event) =>
  61. Effect.sync(() => {
  62. providers.push(event.sdk.languageModel("mistral-large").provider)
  63. }),
  64. )
  65. const result = yield* aisdk.runSDK({
  66. model: ModelV2.Info.make({
  67. ...ModelV2.Info.empty(ProviderV2.ID.make("mistral"), ModelV2.ID.make("mistral-large")),
  68. modelID: ModelV2.ID.make("mistral-large"),
  69. package: "aisdk:test-provider",
  70. }),
  71. package: "@ai-sdk/mistral",
  72. options: { name: "mistral" },
  73. })
  74. expect(result.sdk).toBeDefined()
  75. expect(providers).toEqual(["mistral.chat"])
  76. }),
  77. )
  78. it.effect("matches the old bundled Mistral SDK provider name for custom provider IDs", () =>
  79. Effect.gen(function* () {
  80. const plugin = yield* PluginV2.Service
  81. const aisdk = yield* AISDK.Service
  82. const providers: string[] = []
  83. yield* addPlugin()
  84. yield* aisdk.hook.sdk((event) =>
  85. Effect.sync(() => {
  86. providers.push(event.sdk.languageModel("mistral-large").provider)
  87. }),
  88. )
  89. yield* aisdk.runSDK({
  90. model: ModelV2.Info.make({
  91. ...ModelV2.Info.empty(ProviderV2.ID.make("custom-mistral"), ModelV2.ID.make("mistral-large")),
  92. modelID: ModelV2.ID.make("mistral-large"),
  93. package: "aisdk:test-provider",
  94. }),
  95. package: "@ai-sdk/mistral",
  96. options: { name: "custom-mistral" },
  97. })
  98. expect(providers).toEqual(["mistral.chat"])
  99. }),
  100. )
  101. it.effect("leaves Mistral language selection on the default sdk.languageModel(modelID) path", () =>
  102. Effect.gen(function* () {
  103. const plugin = yield* PluginV2.Service
  104. const aisdk = yield* AISDK.Service
  105. const calls: string[] = []
  106. const sdk = {
  107. languageModel: (id: string) => {
  108. calls.push(`languageModel:${id}`)
  109. return { modelId: id, provider: "languageModel", specificationVersion: "v3" } as unknown as LanguageModelV3
  110. },
  111. }
  112. yield* addPlugin()
  113. const result = yield* aisdk.runLanguage({
  114. model: ModelV2.Info.make({
  115. ...ModelV2.Info.empty(ProviderV2.ID.make("mistral"), ModelV2.ID.make("alias")),
  116. modelID: ModelV2.ID.make("mistral-large"),
  117. package: "aisdk:test-provider",
  118. }),
  119. sdk,
  120. options: {},
  121. })
  122. const language = result.language ?? sdk.languageModel(result.model.modelID ?? result.model.id)
  123. expect(calls).toEqual(["languageModel:mistral-large"])
  124. expect(language).toBeDefined()
  125. }),
  126. )
  127. })