Buckets:
| import fs from "fs/promises" | |
| import path from "path" | |
| import { describe, expect } from "bun:test" | |
| import { Effect, Schema } from "effect" | |
| import { AbsolutePath, Location, Model, OpenCode, Session, Tool } from "@opencode-ai/core/public" | |
| import { tmpdir } from "./fixture/tmpdir" | |
| import { testEffect } from "./lib/effect" | |
| const it = testEffect(OpenCode.layer) | |
| describe("public native OpenCode API", () => { | |
| it.effect("exposes only the intentional Session capabilities", () => | |
| Effect.gen(function* () { | |
| const opencode = yield* OpenCode.Service | |
| expect(Object.keys(opencode).sort()).toEqual(["sessions", "tools"]) | |
| expect(Object.keys(opencode.sessions).sort()).toEqual([ | |
| "context", | |
| "create", | |
| "events", | |
| "get", | |
| "interrupt", | |
| "list", | |
| "message", | |
| "messages", | |
| "prompt", | |
| "switchModel", | |
| ]) | |
| expect(Session.ID.create()).toStartWith("ses_") | |
| expect(Session.MessageID.create()).toStartWith("msg_") | |
| expect(yield* opencode.sessions.list()).toBeArray() | |
| yield* opencode.tools.register({ | |
| public_tool: Tool.make({ | |
| description: "Public tool", | |
| input: Schema.Struct({}), | |
| output: Schema.Struct({ ok: Schema.Boolean }), | |
| execute: () => Effect.succeed({ ok: true }), | |
| }), | |
| }) | |
| }), | |
| ) | |
| it.effect("switches to an available model and variant", () => | |
| Effect.acquireRelease( | |
| Effect.promise(() => tmpdir()), | |
| (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), | |
| ).pipe( | |
| Effect.flatMap((tmp) => | |
| Effect.gen(function* () { | |
| yield* writeProvider(tmp.path) | |
| const opencode = yield* OpenCode.Service | |
| const sessionID = Session.ID.make("ses_public_switch_available") | |
| const model = ref({ variant: "fast" }) | |
| yield* opencode.sessions.create({ | |
| id: sessionID, | |
| location: Location.Ref.make({ directory: AbsolutePath.make(tmp.path) }), | |
| }) | |
| yield* opencode.sessions.switchModel({ sessionID, model }) | |
| expect((yield* opencode.sessions.get(sessionID)).model).toEqual(model) | |
| }), | |
| ), | |
| ), | |
| ) | |
| it.effect("rejects missing and Location-disabled models without changing the Session", () => | |
| Effect.acquireRelease( | |
| Effect.promise(() => Promise.all([tmpdir(), tmpdir()])), | |
| (dirs) => Effect.promise(() => Promise.all(dirs.map((dir) => dir[Symbol.asyncDispose]())).then(() => undefined)), | |
| ).pipe( | |
| Effect.flatMap(([available, disabled]) => | |
| Effect.gen(function* () { | |
| yield* writeProvider(available.path) | |
| yield* writeProvider(disabled.path, true) | |
| const opencode = yield* OpenCode.Service | |
| const availableID = Session.ID.make("ses_public_switch_exact_available") | |
| const disabledID = Session.ID.make("ses_public_switch_exact_disabled") | |
| yield* opencode.sessions.create({ | |
| id: availableID, | |
| location: Location.Ref.make({ directory: AbsolutePath.make(available.path) }), | |
| }) | |
| yield* opencode.sessions.create({ | |
| id: disabledID, | |
| location: Location.Ref.make({ directory: AbsolutePath.make(disabled.path) }), | |
| }) | |
| yield* opencode.sessions.switchModel({ sessionID: availableID, model: ref({ variant: "default" }) }) | |
| const disabledError = yield* opencode.sessions | |
| .switchModel({ sessionID: disabledID, model: ref() }) | |
| .pipe(Effect.flip) | |
| const missingError = yield* opencode.sessions | |
| .switchModel({ sessionID: disabledID, model: ref({ id: "missing" }) }) | |
| .pipe(Effect.flip) | |
| expect(disabledError).toBeInstanceOf(Session.ModelUnavailableError) | |
| expect(missingError).toBeInstanceOf(Session.ModelUnavailableError) | |
| expect((yield* opencode.sessions.get(availableID)).model).toEqual(ref({ variant: "default" })) | |
| expect((yield* opencode.sessions.get(disabledID)).model).toBeUndefined() | |
| }), | |
| ), | |
| ), | |
| ) | |
| it.effect("rejects an unavailable variant without changing the Session", () => | |
| Effect.acquireRelease( | |
| Effect.promise(() => tmpdir()), | |
| (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), | |
| ).pipe( | |
| Effect.flatMap((tmp) => | |
| Effect.gen(function* () { | |
| yield* writeProvider(tmp.path) | |
| const opencode = yield* OpenCode.Service | |
| const sessionID = Session.ID.make("ses_public_switch_variant") | |
| const selected = ref({ variant: "fast" }) | |
| yield* opencode.sessions.create({ | |
| id: sessionID, | |
| location: Location.Ref.make({ directory: AbsolutePath.make(tmp.path) }), | |
| }) | |
| yield* opencode.sessions.switchModel({ sessionID, model: selected }) | |
| const error = yield* opencode.sessions | |
| .switchModel({ sessionID, model: ref({ variant: "unknown" }) }) | |
| .pipe(Effect.flip) | |
| expect(error).toBeInstanceOf(Session.VariantUnavailableError) | |
| expect((yield* opencode.sessions.get(sessionID)).model).toEqual(selected) | |
| }), | |
| ), | |
| ), | |
| ) | |
| it.effect("preserves the typed not-found error for a missing Session", () => | |
| Effect.gen(function* () { | |
| const opencode = yield* OpenCode.Service | |
| const sessionID = Session.ID.make("ses_public_switch_missing") | |
| const error = yield* opencode.sessions | |
| .switchModel({ | |
| sessionID, | |
| model: Schema.decodeUnknownSync(Model.Ref)({ id: "claude-sonnet-4-5", providerID: "anthropic" }), | |
| }) | |
| .pipe(Effect.flip) | |
| expect(error).toBeInstanceOf(Session.NotFoundError) | |
| if (error instanceof Session.NotFoundError) expect(error.sessionID).toBe(sessionID) | |
| }), | |
| ) | |
| }) | |
| const ref = (input: { id?: string; variant?: string } = {}) => | |
| Schema.decodeUnknownSync(Model.Ref)({ | |
| id: input.id ?? "chat", | |
| providerID: "public-test", | |
| variant: input.variant, | |
| }) | |
| const writeProvider = (directory: string, disabled = false) => | |
| Effect.promise(() => | |
| fs.writeFile( | |
| path.join(directory, "opencode.json"), | |
| JSON.stringify({ | |
| providers: { | |
| "public-test": { | |
| name: "Public test", | |
| api: { type: "native", settings: {} }, | |
| models: { | |
| chat: { | |
| disabled, | |
| variants: [{ id: "fast" }], | |
| }, | |
| }, | |
| }, | |
| }, | |
| }), | |
| ), | |
| ) | |
Xet Storage Details
- Size:
- 6.49 kB
- Xet hash:
- aa46e924a95ec92bb5301c47092d8dad696bd6e9537479ddbc55fe85826124c5
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.