provider-xai.test.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import type { LanguageModelV3 } from "@ai-sdk/provider"
  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 { XAIPlugin } from "@opencode-ai/core/plugin/provider/xai"
  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 host = yield* PluginHost.make()
  15. yield* plugin.add({ id: XAIPlugin.id, effect: XAIPlugin.effect(host) })
  16. })
  17. function fakeSelectorSdk(calls: string[]) {
  18. const make = (method: string) => (id: string) => {
  19. calls.push(`${method}:${id}`)
  20. return { modelId: id, provider: method, specificationVersion: "v3" } as unknown as LanguageModelV3
  21. }
  22. return {
  23. responses: make("responses"),
  24. messages: make("messages"),
  25. chat: make("chat"),
  26. languageModel: make("languageModel"),
  27. }
  28. }
  29. describe("XAIPlugin", () => {
  30. it.effect("creates an xAI SDK only for @ai-sdk/xai", () =>
  31. Effect.gen(function* () {
  32. const plugin = yield* PluginV2.Service
  33. yield* addPlugin()
  34. const ignored = yield* plugin.trigger(
  35. "aisdk.sdk",
  36. {
  37. model: new ModelV2.Info({
  38. ...ModelV2.Info.empty(ProviderV2.ID.make("xai"), ModelV2.ID.make("grok-4")),
  39. api: { id: ModelV2.ID.make("grok-4"), type: "aisdk", package: "@ai-sdk/xai" },
  40. }),
  41. package: "@ai-sdk/openai-compatible",
  42. options: {},
  43. },
  44. {},
  45. )
  46. const result = yield* plugin.trigger(
  47. "aisdk.sdk",
  48. {
  49. model: new ModelV2.Info({
  50. ...ModelV2.Info.empty(ProviderV2.ID.make("xai"), ModelV2.ID.make("grok-4")),
  51. api: { id: ModelV2.ID.make("grok-4"), type: "aisdk", package: "@ai-sdk/xai" },
  52. }),
  53. package: "@ai-sdk/xai",
  54. options: {},
  55. },
  56. {},
  57. )
  58. expect(ignored.sdk).toBeUndefined()
  59. expect(typeof result.sdk?.responses).toBe("function")
  60. }),
  61. )
  62. it.effect("creates xAI SDKs for custom provider IDs", () =>
  63. Effect.gen(function* () {
  64. const plugin = yield* PluginV2.Service
  65. yield* addPlugin()
  66. const result = yield* plugin.trigger(
  67. "aisdk.sdk",
  68. {
  69. model: new ModelV2.Info({
  70. ...ModelV2.Info.empty(ProviderV2.ID.make("custom-xai"), ModelV2.ID.make("grok-4")),
  71. api: { id: ModelV2.ID.make("grok-4"), type: "aisdk", package: "@ai-sdk/xai" },
  72. }),
  73. package: "@ai-sdk/xai",
  74. options: {},
  75. },
  76. {},
  77. )
  78. expect(result.sdk.responses("grok-4").provider).toBe("xai.responses")
  79. }),
  80. )
  81. it.effect("uses responses with the model api.id for xAI language models", () =>
  82. Effect.gen(function* () {
  83. const plugin = yield* PluginV2.Service
  84. const calls: string[] = []
  85. yield* addPlugin()
  86. const result = yield* plugin.trigger(
  87. "aisdk.language",
  88. {
  89. model: new ModelV2.Info({
  90. ...ModelV2.Info.empty(ProviderV2.ID.make("xai"), ModelV2.ID.make("alias")),
  91. api: { id: ModelV2.ID.make("grok-4"), type: "aisdk", package: "@ai-sdk/xai" },
  92. }),
  93. sdk: fakeSelectorSdk(calls),
  94. options: {},
  95. },
  96. {},
  97. )
  98. expect(calls).toEqual(["responses:grok-4"])
  99. expect(result.language).toBeDefined()
  100. }),
  101. )
  102. it.effect("ignores non-xAI providers", () =>
  103. Effect.gen(function* () {
  104. const plugin = yield* PluginV2.Service
  105. const calls: string[] = []
  106. yield* addPlugin()
  107. const result = yield* plugin.trigger(
  108. "aisdk.language",
  109. {
  110. model: new ModelV2.Info({
  111. ...ModelV2.Info.empty(ProviderV2.ID.openai, ModelV2.ID.make("grok-4")),
  112. api: { id: ModelV2.ID.make("grok-4"), type: "aisdk", package: "@ai-sdk/xai" },
  113. }),
  114. sdk: fakeSelectorSdk(calls),
  115. options: {},
  116. },
  117. {},
  118. )
  119. expect(calls).toEqual([])
  120. expect(result.language).toBeUndefined()
  121. }),
  122. )
  123. })