public-opencode.test.ts 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import { describe, expect } from "bun:test"
  2. import { Effect, Schema } from "effect"
  3. import { AbsolutePath, Location, Model, OpenCode, Session, Tool } from "@opencode-ai/core/public"
  4. import { testEffect } from "./lib/effect"
  5. const it = testEffect(OpenCode.layer)
  6. describe("public native OpenCode API", () => {
  7. it.effect("exposes only the intentional Session capabilities", () =>
  8. Effect.gen(function* () {
  9. const opencode = yield* OpenCode.Service
  10. expect(Object.keys(opencode).sort()).toEqual(["sessions", "tools"])
  11. expect(Object.keys(opencode.sessions).sort()).toEqual([
  12. "context",
  13. "create",
  14. "events",
  15. "get",
  16. "interrupt",
  17. "list",
  18. "message",
  19. "messages",
  20. "prompt",
  21. "switchModel",
  22. ])
  23. expect(Session.ID.create()).toStartWith("ses_")
  24. expect(Session.MessageID.create()).toStartWith("msg_")
  25. expect(yield* opencode.sessions.list()).toBeArray()
  26. yield* opencode.tools.attach({
  27. public_tool: Tool.make({
  28. description: "Public tool",
  29. parameters: Schema.Struct({}),
  30. success: Schema.Struct({ ok: Schema.Boolean }),
  31. execute: () => Effect.succeed({ ok: true }),
  32. }),
  33. })
  34. }),
  35. )
  36. it.effect("switches the exact Session to the exact model through the durable facade", () =>
  37. Effect.gen(function* () {
  38. const opencode = yield* OpenCode.Service
  39. const targetID = Session.ID.make("ses_public_switch_target")
  40. const otherID = Session.ID.make("ses_public_switch_other")
  41. const model = Schema.decodeUnknownSync(Model.Ref)({
  42. id: "claude-sonnet-4-5",
  43. providerID: "anthropic",
  44. variant: "high",
  45. })
  46. const location = Location.Ref.make({ directory: AbsolutePath.make("/public-session-switch-model") })
  47. yield* opencode.sessions.create({ id: targetID, location })
  48. yield* opencode.sessions.create({ id: otherID, location })
  49. yield* opencode.sessions.switchModel({ sessionID: targetID, model })
  50. expect((yield* opencode.sessions.get(targetID)).model).toEqual(model)
  51. expect((yield* opencode.sessions.get(otherID)).model).toBeUndefined()
  52. }),
  53. )
  54. it.effect("preserves the typed not-found error for a missing Session", () =>
  55. Effect.gen(function* () {
  56. const opencode = yield* OpenCode.Service
  57. const sessionID = Session.ID.make("ses_public_switch_missing")
  58. const error = yield* opencode.sessions
  59. .switchModel({
  60. sessionID,
  61. model: Schema.decodeUnknownSync(Model.Ref)({ id: "claude-sonnet-4-5", providerID: "anthropic" }),
  62. })
  63. .pipe(Effect.flip)
  64. expect(error).toBeInstanceOf(Session.NotFoundError)
  65. expect(error.sessionID).toBe(sessionID)
  66. }),
  67. )
  68. })