public-opencode.test.ts 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  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.register({
  27. public_tool: Tool.make({
  28. description: "Public tool",
  29. input: Schema.Struct({}),
  30. output: Schema.Struct({ ok: Schema.Boolean }),
  31. execute: () => Effect.succeed({ ok: true }),
  32. }),
  33. })
  34. }),
  35. )
  36. it.effect("records model selection without resolving the Location catalog", () =>
  37. Effect.gen(function* () {
  38. const opencode = yield* OpenCode.Service
  39. const sessionID = Session.ID.make("ses_public_switch_deferred")
  40. const model = Schema.decodeUnknownSync(Model.Ref)({
  41. id: "missing",
  42. providerID: "missing",
  43. variant: "unknown",
  44. })
  45. yield* opencode.sessions.create({
  46. id: sessionID,
  47. location: Location.Ref.make({ directory: AbsolutePath.make("/public-session-switch-model") }),
  48. })
  49. yield* opencode.sessions.switchModel({ sessionID, model })
  50. expect((yield* opencode.sessions.get(sessionID)).model).toEqual(model)
  51. }),
  52. )
  53. it.effect("preserves the typed not-found error for a missing Session", () =>
  54. Effect.gen(function* () {
  55. const opencode = yield* OpenCode.Service
  56. const sessionID = Session.ID.make("ses_public_switch_missing")
  57. const error = yield* opencode.sessions
  58. .switchModel({
  59. sessionID,
  60. model: Schema.decodeUnknownSync(Model.Ref)({ id: "claude-sonnet-4-5", providerID: "anthropic" }),
  61. })
  62. .pipe(Effect.flip)
  63. expect(error).toBeInstanceOf(Session.NotFoundError)
  64. if (error instanceof Session.NotFoundError) expect(error.sessionID).toBe(sessionID)
  65. }),
  66. )
  67. })