embedded.test.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import { expect, test } from "bun:test"
  2. import { mkdtemp, rm } from "node:fs/promises"
  3. import { tmpdir } from "node:os"
  4. import { join } from "node:path"
  5. import { Flag } from "@opencode-ai/core/flag/flag"
  6. import { Effect, Schema } from "effect"
  7. test("embedded client uses the real router and handlers", async () => {
  8. const directory = await mkdtemp(join(tmpdir(), "opencode-embedded-"))
  9. const database = Flag.OPENCODE_DB
  10. Flag.OPENCODE_DB = join(directory, "opencode.sqlite")
  11. const { AbsolutePath, Agent, Location, Model, OpenCode, Prompt, Provider, Session, Tool } = await import("../src")
  12. const sessionID = Session.ID.make(`ses_embedded_${crypto.randomUUID()}`)
  13. const model = Model.Ref.make({ id: Model.ID.make("embedded"), providerID: Provider.ID.make("test") })
  14. try {
  15. const program = Effect.gen(function* () {
  16. const opencode = yield* OpenCode.create()
  17. yield* opencode.tools.register({
  18. embedded_tool: Tool.make({
  19. description: "Embedded test tool",
  20. input: Schema.Struct({}),
  21. output: Schema.Struct({ ok: Schema.Boolean }),
  22. execute: () => Effect.succeed({ ok: true }),
  23. }),
  24. })
  25. const created = yield* opencode.sessions.create({
  26. id: sessionID,
  27. agent: Agent.ID.make("build"),
  28. location: Location.Ref.make({ directory: AbsolutePath.make(directory) }),
  29. })
  30. yield* opencode.sessions.switchModel({ sessionID, model })
  31. const selected = yield* opencode.sessions.get({ sessionID })
  32. const page = yield* opencode.sessions.list({ directory: AbsolutePath.make(directory) })
  33. const admitted = yield* opencode.sessions.prompt({
  34. sessionID,
  35. prompt: Prompt.make({ text: "Do not run" }),
  36. resume: false,
  37. })
  38. const context = yield* opencode.sessions.context({ sessionID })
  39. const missing = yield* Effect.flip(
  40. opencode.sessions.get({ sessionID: Session.ID.make(`ses_missing_${crypto.randomUUID()}`) }),
  41. )
  42. expect(created.id).toBe(sessionID)
  43. expect(selected.model?.id).toBe(model.id)
  44. expect(selected.model?.providerID).toBe(model.providerID)
  45. expect(page.data.some((session) => session.id === sessionID)).toBe(true)
  46. expect(admitted.sessionID).toBe(sessionID)
  47. expect(context.some((message) => message.type === "model-switched")).toBe(true)
  48. expect(missing._tag).toBe("SessionNotFoundError")
  49. })
  50. await Effect.runPromise(Effect.scoped(program))
  51. } finally {
  52. Flag.OPENCODE_DB = database
  53. await rm(directory, { recursive: true, force: true })
  54. }
  55. })
  56. test("embedded client is available as a Layer service", async () => {
  57. const directory = await mkdtemp(join(tmpdir(), "opencode-embedded-layer-"))
  58. const database = Flag.OPENCODE_DB
  59. Flag.OPENCODE_DB = join(directory, "opencode.sqlite")
  60. const { AbsolutePath, Location, OpenCode, Session } = await import("../src")
  61. const sessionID = Session.ID.make(`ses_embedded_${crypto.randomUUID()}`)
  62. try {
  63. const created = await Effect.runPromise(
  64. Effect.gen(function* () {
  65. const opencode = yield* OpenCode.Service
  66. return yield* opencode.sessions.create({
  67. id: sessionID,
  68. location: Location.Ref.make({ directory: AbsolutePath.make(directory) }),
  69. })
  70. }).pipe(Effect.provide(OpenCode.layer), Effect.scoped),
  71. )
  72. expect(created.id).toBe(sessionID)
  73. } finally {
  74. Flag.OPENCODE_DB = database
  75. await rm(directory, { recursive: true, force: true })
  76. }
  77. })