model.test.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import fs from "node:fs/promises"
  2. import path from "node:path"
  3. import { expect } from "bun:test"
  4. import { Effect } from "effect"
  5. import { HttpServer } from "effect/unstable/http"
  6. import { tmpdir } from "../../core/test/fixture/tmpdir"
  7. import { it } from "../../core/test/lib/effect"
  8. import { ServerProcess } from "../src/process"
  9. it.live("waits for plugin initialization before listing models", () =>
  10. Effect.acquireUseRelease(
  11. Effect.promise(() => tmpdir("opencode-model-endpoint-")),
  12. (tmp) =>
  13. Effect.gen(function* () {
  14. yield* Effect.promise(() =>
  15. fs.writeFile(
  16. path.join(tmp.path, "opencode.json"),
  17. JSON.stringify({
  18. providers: {
  19. custom: {
  20. package: "aisdk:@ai-sdk/openai-compatible",
  21. settings: { apiKey: "secret" },
  22. models: { chat: {} },
  23. },
  24. },
  25. }),
  26. ),
  27. )
  28. const server = yield* ServerProcess.start<never, never>({
  29. hostname: "127.0.0.1",
  30. port: 0,
  31. password: "secret",
  32. app: { version: "test-version" },
  33. database: { path: ":memory:" },
  34. config: { directory: tmp.path },
  35. fs: { filewatcher: false },
  36. })
  37. const url = new URL("/api/model", HttpServer.formatAddress(server.address))
  38. url.searchParams.set("location[directory]", tmp.path)
  39. const response = yield* Effect.promise(() =>
  40. fetch(url, { headers: { authorization: `Basic ${btoa("opencode:secret")}` } }),
  41. )
  42. expect(response.status).toBe(200)
  43. const body: unknown = yield* Effect.promise(() => response.json())
  44. if (!isRecord(body) || !Array.isArray(body["data"])) throw new Error("Expected a model list response")
  45. expect(
  46. body["data"].some((model) => isRecord(model) && model["providerID"] === "custom" && model["id"] === "chat"),
  47. ).toBeTrue()
  48. }),
  49. (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
  50. ),
  51. )
  52. function isRecord(value: unknown): value is Record<string, unknown> {
  53. return typeof value === "object" && value !== null && !Array.isArray(value)
  54. }